From b7cc05ba8564ca22a17fef25f1fbd7338e09ab9f Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Tue, 24 Oct 2023 18:54:57 -0400 Subject: [PATCH 001/327] (test): Add Functions test harnesses & additional foundry unit tests (#11011) * (test): Add Functions test harnesses & additional unit tests * (test): Add transmitter balance helpers * Update gas snapshot from helper functions --- contracts/foundry.toml | 6 +- .../gas-snapshots/functions.gas-snapshot | 318 +++++++++--------- .../tests/v1_X/FunctionsBilling.t.sol | 242 ++++++++++--- .../tests/v1_X/FunctionsClient.t.sol | 44 ++- .../tests/v1_X/FunctionsCoordinator.t.sol | 216 ++++++++++-- .../tests/v1_X/FunctionsRouter.t.sol | 4 +- .../tests/v1_X/FunctionsSubscriptions.t.sol | 60 +--- .../src/v0.8/functions/tests/v1_X/README.md | 15 +- .../src/v0.8/functions/tests/v1_X/Setup.t.sol | 49 ++- .../testhelpers/FunctionsClientHarness.sol | 24 ++ .../testhelpers/FunctionsClientTestHelper.sol | 2 +- .../FunctionsClientWithEmptyCallback.sol | 2 +- .../FunctionsCoordinatorHarness.sol | 119 +++++++ .../FunctionsCoordinatorTestHelper.sol | 2 +- .../testhelpers/FunctionsRouterHarness.sol | 30 ++ .../FunctionsSubscriptionsHarness.sol | 54 +++ .../v1_X/testhelpers/FunctionsTestHelper.sol | 2 +- 17 files changed, 884 insertions(+), 305 deletions(-) create mode 100644 contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol create mode 100644 contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol create mode 100644 contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsRouterHarness.sol create mode 100644 contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsSubscriptionsHarness.sol diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 1228ce3ec0..cf27c0f2a8 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -18,9 +18,9 @@ block_number = 12345 [profile.functions] solc_version = '0.8.19' -src = 'src/v0.8/functions' -test = 'src/v0.8/functions/tests' -gas_price = 3000000000 +src = 'src/v0.8/functions/dev/v1_X' +test = 'src/v0.8/functions/tests/v1_X' +gas_price = 3_000_000_000 # 3 gwei [profile.vrf] optimizer_runs = 1000 diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index b629835060..d575c8ca19 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,177 +1,195 @@ -FunctionsBilling_EstimateCost:test_EstimateCost_RevertsIfGasPriceAboveCeiling() (gas: 32391) -FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 53182) -FunctionsBilling_EstimateCost:test_EstimateCost_SuccessLowGasPrice() (gas: 53285) +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_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_OracleWithdrawAll:test_OracleWithdrawAll_RevertIfNotOwner() (gas: 13296) -FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 146657) -FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 498113) -FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 199261) -FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 54991) -FunctionsCoordinator_Constructor:test_Constructor_Success() (gas: 11933) -FunctionsOracle_sendRequest:testEmptyRequestDataReverts() (gas: 13452) -FunctionsOracle_setDONPublicKey:testEmptyPublicKeyReverts() (gas: 10974) -FunctionsOracle_setDONPublicKey:testOnlyOwnerReverts() (gas: 11255) -FunctionsOracle_setDONPublicKey:testSetDONPublicKeySuccess() (gas: 126453) -FunctionsOracle_setDONPublicKey:testSetDONPublicKey_gas() (gas: 97580) -FunctionsOracle_setRegistry:testEmptyPublicKeyReverts() (gas: 10635) -FunctionsOracle_setRegistry:testOnlyOwnerReverts() (gas: 10927) -FunctionsOracle_setRegistry:testSetRegistrySuccess() (gas: 35791) -FunctionsOracle_setRegistry:testSetRegistry_gas() (gas: 31987) -FunctionsOracle_typeAndVersion:testTypeAndVersionSuccess() (gas: 6905) +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) +FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) +FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 498114) +FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 199285) +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_GetDONPublicKey:test_GetDONPublicKey_RevertIfEmpty() (gas: 15334) +FunctionsCoordinator_GetDONPublicKey:test_GetDONPublicKey_Success() (gas: 106496) +FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_RevertIfEmpty() (gas: 15313) +FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_Success() (gas: 656556) +FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_RevertNotOwner() (gas: 20364) +FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_Success() (gas: 101275) +FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_RevertNotOwner() (gas: 13892) +FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_Success() (gas: 651248) +FunctionsCoordinator_StartRequest:test_StartRequest_RevertIfNotRouter() (gas: 22703) +FunctionsCoordinator_StartRequest:test_StartRequest_Success() (gas: 107681) +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: 12073) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 169899) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 160226) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38092) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35224) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 178394) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28063) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 153900) -FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 296711) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 310303) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2484943) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 515428) -FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 18005) -FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12926) -FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37136) -FunctionsRouter_GetContractById:test_GetContractById_RevertIfRouteDoesNotExist() (gas: 13871) -FunctionsRouter_GetContractById:test_GetContractById_SuccessIfRouteExists() (gas: 17395) -FunctionsRouter_GetProposedContractById:test_GetProposedContractById_RevertIfRouteDoesNotExist() (gas: 16382) -FunctionsRouter_GetProposedContractById:test_GetProposedContractById_SuccessIfRouteExists() (gas: 23934) -FunctionsRouter_GetProposedContractSet:test_GetProposedContractSet_Success() (gas: 25958) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertGasLimitTooBig() (gas: 28034) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertInvalidConfig() (gas: 41004) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_Success() (gas: 24551) -FunctionsRouter_Pause:test_Pause_RevertIfNotOwner() (gas: 13315) -FunctionsRouter_Pause:test_Pause_Success() (gas: 20298) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfEmptyAddress() (gas: 14768) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfExceedsMaxProposal() (gas: 21670) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengthMismatch() (gas: 14647) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19025) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23369) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118456) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59304) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 192796) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29405) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57926) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186209) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50902) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25061) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29111) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34247) -FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 284999) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65800) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 35991) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29897) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57488) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidDonId() (gas: 27482) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35696) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40766) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 291551) -FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 192728) -FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30687) -FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13380) -FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13337) -FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77421) +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_RequestNotProcessedInvalidCommitment() (gas: 38115) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 178373) +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_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) +FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) +FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159) +FunctionsRouter_GetContractById:test_GetContractById_RevertIfRouteDoesNotExist() (gas: 13849) +FunctionsRouter_GetContractById:test_GetContractById_SuccessIfRouteExists() (gas: 17373) +FunctionsRouter_GetProposedContractById:test_GetProposedContractById_RevertIfRouteDoesNotExist() (gas: 16383) +FunctionsRouter_GetProposedContractById:test_GetProposedContractById_SuccessIfRouteExists() (gas: 23935) +FunctionsRouter_GetProposedContractSet:test_GetProposedContractSet_Success() (gas: 25936) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertGasLimitTooBig() (gas: 28103) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertInvalidConfig() (gas: 41093) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_Success() (gas: 24626) +FunctionsRouter_Pause:test_Pause_RevertIfNotOwner() (gas: 13338) +FunctionsRouter_Pause:test_Pause_Success() (gas: 20344) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfEmptyAddress() (gas: 14791) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfExceedsMaxProposal() (gas: 21693) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengthMismatch() (gas: 14670) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19048) +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_RevertIfEmptyData() (gas: 29426) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57925) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186299) +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_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65843) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 36012) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29896) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57533) +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_SetAllowListId:test_SetAllowListId_Success() (gas: 30688) +FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13403) +FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13293) +FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77400) FunctionsRouter_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 24437) -FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 60653) -FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13293) -FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38716) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60324) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60962) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94675) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62691) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 214576) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137833) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164777) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12926) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 57789) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87142) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18051) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95481) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15085) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57929) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89316) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20191) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193763) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114636) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125891) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessRecieveDeposit() (gas: 311486) +FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 60676) +FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13336) +FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38732) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60326) +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_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137893) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164837) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12946) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 57809) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87162) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18094) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95480) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15041) +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_SuccessForfeitAllBalanceAsDeposit() (gas: 114506) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125832) +FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 74973) FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28637) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17948) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351723) -FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16225) -FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessInvalidSubscription() (gas: 13100) -FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessValidSubscription() (gas: 40858) -FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30959) -FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 12967) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 16523) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13436) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59568) -FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15032) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 28401, ~: 28401) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 30913, ~: 30913) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14248, ~: 14248) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 35870, ~: 35870) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 59685, ~: 59685) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28660) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17994) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351726) +FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16226) +FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessInvalidSubscription() (gas: 13101) +FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessValidSubscription() (gas: 40903) +FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30937) +FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 12968) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 16547) +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, μ: 28446, ~: 28446) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 30958, ~: 30958) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14293, ~: 14293) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 35938, ~: 35938) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 59686, ~: 59686) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfPaused() (gas: 20833) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfPaused() (gas: 20856) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessPaysRecipient() (gas: 59732) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZero() (gas: 57701) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNoSubscription() (gas: 12818) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15549) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 54867) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 49624) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 49607) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 50896) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 164300) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 164303) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17924) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfBalanceInvariant() (gas: 210) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15533) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15555) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfNoAmount() (gas: 37396) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfRecipientAddressZero() (gas: 52130) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 54413) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37790) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 15025) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175897) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27610) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57707) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15000) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75130) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17959) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20104) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68217) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82791) -FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15532) -FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success(uint64) (runs: 256, μ: 41699, ~: 41704) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30238) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 14997) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57778) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87186) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18004) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191195) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 14981) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175857) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27611) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57709) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15001) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75131) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17960) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20128) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68196) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82749) +FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15554) +FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success(uint64) (runs: 256, μ: 41717, ~: 41721) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30260) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 15019) +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_Success() (gas: 41979) -FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12847) -FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15640) -FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35549) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (gas: 25910) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25239) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28220) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57752) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26368) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15714) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152510) +FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12891) +FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15684) +FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35594) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (gas: 25955) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25261) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28242) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57754) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26390) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15759) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152576) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94815) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25837) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 44348) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23597) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1866530) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26003) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946591) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946547) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 104851) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 51794) @@ -188,8 +206,8 @@ FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13727) FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22073) Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84675) -Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79067) -Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73353) -Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38501) -Gas_SendRequest:test_SendRequest_MaximumGas() (gas: 964209) -Gas_SendRequest:test_SendRequest_MinimumGas() (gas: 156929) \ No newline at end of file +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 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 14188fdc04..82dea8672c 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,12 +4,17 @@ 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 {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; +import {Routable} from "../../dev/v1_X/Routable.sol"; -import {FunctionsRouterSetup, FunctionsSubscriptionSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; +import {FunctionsRouterSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; /// @notice #constructor -contract FunctionsBilling_Constructor { - +contract FunctionsBilling_Constructor is FunctionsSubscriptionSetup { + function test_Constructor_Success() public { + assertEq(address(s_functionsRouter), s_functionsCoordinator.getRouter_HARNESS()); + assertEq(address(s_linkEthFeed), s_functionsCoordinator.getLinkToNativeFeed_HARNESS()); + } } /// @notice #getConfig @@ -32,28 +37,94 @@ contract FunctionsBilling_GetConfig is FunctionsRouterSetup { } /// @notice #updateConfig -contract FunctionsBilling_UpdateConfig { +contract FunctionsBilling_UpdateConfig is FunctionsRouterSetup { + FunctionsBilling.Config internal configToSet; + + function setUp() public virtual override { + FunctionsRouterSetup.setUp(); + + configToSet = FunctionsBilling.Config({ + feedStalenessSeconds: getCoordinatorConfig().feedStalenessSeconds * 2, + gasOverheadAfterCallback: getCoordinatorConfig().gasOverheadAfterCallback * 2, + gasOverheadBeforeCallback: getCoordinatorConfig().gasOverheadBeforeCallback * 2, + requestTimeoutSeconds: getCoordinatorConfig().requestTimeoutSeconds * 2, + donFee: getCoordinatorConfig().donFee * 2, + maxSupportedRequestDataVersion: getCoordinatorConfig().maxSupportedRequestDataVersion * 2, + fulfillmentGasPriceOverEstimationBP: getCoordinatorConfig().fulfillmentGasPriceOverEstimationBP * 2, + fallbackNativePerUnitLink: getCoordinatorConfig().fallbackNativePerUnitLink * 2, + minimumEstimateGasPriceWei: getCoordinatorConfig().minimumEstimateGasPriceWei * 2 + }); + } + function test_UpdateConfig_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsCoordinator.updateConfig(configToSet); + } + + event ConfigUpdated(FunctionsBilling.Config config); + + function test_UpdateConfig_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit ConfigUpdated(configToSet); + + s_functionsCoordinator.updateConfig(configToSet); + + FunctionsBilling.Config memory config = s_functionsCoordinator.getConfig(); + assertEq(config.feedStalenessSeconds, configToSet.feedStalenessSeconds); + assertEq(config.gasOverheadAfterCallback, configToSet.gasOverheadAfterCallback); + assertEq(config.gasOverheadBeforeCallback, configToSet.gasOverheadBeforeCallback); + assertEq(config.requestTimeoutSeconds, configToSet.requestTimeoutSeconds); + assertEq(config.donFee, configToSet.donFee); + assertEq(config.maxSupportedRequestDataVersion, configToSet.maxSupportedRequestDataVersion); + assertEq(config.fulfillmentGasPriceOverEstimationBP, configToSet.fulfillmentGasPriceOverEstimationBP); + assertEq(config.fallbackNativePerUnitLink, configToSet.fallbackNativePerUnitLink); + assertEq(config.minimumEstimateGasPriceWei, configToSet.minimumEstimateGasPriceWei); + } } /// @notice #getDONFee -contract FunctionsBilling_GetDONFee { +contract FunctionsBilling_GetDONFee is FunctionsRouterSetup { + function test_GetDONFee_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + uint72 donFee = s_functionsCoordinator.getDONFee(new bytes(0)); + assertEq(donFee, s_donFee); + } } /// @notice #getAdminFee -contract FunctionsBilling_GetAdminFee { +contract FunctionsBilling_GetAdminFee is FunctionsRouterSetup { + function test_GetAdminFee_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + uint72 adminFee = s_functionsCoordinator.getAdminFee(); + assertEq(adminFee, s_adminFee); + } } /// @notice #getWeiPerUnitLink -contract FunctionsBilling_GetWeiPerUnitLink { - -} +contract FunctionsBilling_GetWeiPerUnitLink is FunctionsRouterSetup { + function test_GetWeiPerUnitLink_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); -/// @notice #_getJuelsPerGas -contract FunctionsBilling__GetJuelsPerGas { - // TODO: make contract internal function helper + uint256 weiPerUnitLink = s_functionsCoordinator.getWeiPerUnitLink(); + assertEq(weiPerUnitLink, uint256(LINK_ETH_RATE)); + } } /// @notice #estimateCost @@ -109,7 +180,7 @@ contract FunctionsBilling_EstimateCost is FunctionsSubscriptionSetup { callbackGasLimit, gasPriceWei ); - uint96 expectedCostEstimate = 16375000000000200; + uint96 expectedCostEstimate = 51110500000000200; assertEq(costEstimate, expectedCostEstimate); } @@ -134,7 +205,7 @@ contract FunctionsBilling_EstimateCost is FunctionsSubscriptionSetup { callbackGasLimit, gasPriceWei ); - uint96 expectedCostEstimate = 81875000000000200; + uint96 expectedCostEstimate = 255552500000000200; assertEq(costEstimate, expectedCostEstimate); } } @@ -149,24 +220,115 @@ contract FunctionsBilling__StartBilling { // TODO: make contract internal function helper } -/// @notice #_computeRequestId -contract FunctionsBilling__ComputeRequestId { - // TODO: make contract internal function helper -} - /// @notice #_fulfillAndBill contract FunctionsBilling__FulfillAndBill { // TODO: make contract internal function helper } /// @notice #deleteCommitment -contract FunctionsBilling_DeleteCommitment { +contract FunctionsBilling_DeleteCommitment is FunctionsClientRequestSetup { + function test_DeleteCommitment_RevertIfNotRouter() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(Routable.OnlyCallableByRouter.selector); + s_functionsCoordinator.deleteCommitment(s_requests[1].requestId); + } + + event CommitmentDeleted(bytes32 requestId); + + function test_DeleteCommitment_Success() public { + // Send as Router + vm.stopPrank(); + vm.startPrank(address(s_functionsRouter)); + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit CommitmentDeleted(s_requests[1].requestId); + s_functionsCoordinator.deleteCommitment(s_requests[1].requestId); + } } /// @notice #oracleWithdraw -contract FunctionsBilling_OracleWithdraw { +contract FunctionsBilling_OracleWithdraw is FunctionsMultipleFulfillmentsSetup { + function test_OracleWithdraw_RevertWithNoBalance() public { + uint256[4] memory transmitterBalancesBefore = _getTransmitterBalances(); + _assertTransmittersAllHaveBalance(transmitterBalancesBefore, 0); + // Send as stranger, which has no balance + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + + // Attempt to withdraw with no amount, which would withdraw the full balance + s_functionsCoordinator.oracleWithdraw(STRANGER_ADDRESS, 0); + + uint256[4] memory transmitterBalancesAfter = _getTransmitterBalances(); + _assertTransmittersAllHaveBalance(transmitterBalancesAfter, 0); + } + + function test_OracleWithdraw_RevertIfInsufficientBalance() public { + // Send as transmitter 1, which has transmitted 1 report + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); + + vm.expectRevert(FunctionsBilling.InsufficientBalance.selector); + + // Attempt to withdraw more than the Coordinator has assigned + s_functionsCoordinator.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, s_fulfillmentCoordinatorBalance + 1); + } + + function test_OracleWithdraw_SuccessTransmitterWithBalanceValidAmountGiven() public { + uint256[4] memory transmitterBalancesBefore = _getTransmitterBalances(); + _assertTransmittersAllHaveBalance(transmitterBalancesBefore, 0); + + // Send as transmitter 1, which has transmitted 1 report + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); + + uint96 expectedTransmitterBalance = s_fulfillmentCoordinatorBalance / 3; + + // Attempt to withdraw half of balance + uint96 halfBalance = expectedTransmitterBalance / 2; + s_functionsCoordinator.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, halfBalance); + + uint256[4] memory transmitterBalancesAfter = _getTransmitterBalances(); + assertEq(transmitterBalancesAfter[0], halfBalance); + assertEq(transmitterBalancesAfter[1], 0); + assertEq(transmitterBalancesAfter[2], 0); + assertEq(transmitterBalancesAfter[3], 0); + } + + function test_OracleWithdraw_SuccessTransmitterWithBalanceNoAmountGiven() public { + uint256[4] memory transmitterBalancesBefore = _getTransmitterBalances(); + _assertTransmittersAllHaveBalance(transmitterBalancesBefore, 0); + + // Send as transmitter 1, which has transmitted 1 report + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); + + // Attempt to withdraw with no amount, which will withdraw the full balance + s_functionsCoordinator.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, 0); + + // 3 report transmissions have been made + uint96 totalDonFees = s_donFee * 3; + // 4 transmitters will share the DON fees + uint96 donFeeShare = totalDonFees / 4; + uint96 expectedTransmitterBalance = ((s_fulfillmentCoordinatorBalance - totalDonFees) / 3) + donFeeShare; + + uint256[4] memory transmitterBalancesAfter = _getTransmitterBalances(); + assertEq(transmitterBalancesAfter[0], expectedTransmitterBalance); + assertEq(transmitterBalancesAfter[1], 0); + assertEq(transmitterBalancesAfter[2], 0); + assertEq(transmitterBalancesAfter[3], 0); + } } /// @notice #oracleWithdrawAll @@ -188,37 +350,29 @@ contract FunctionsBilling_OracleWithdrawAll is FunctionsMultipleFulfillmentsSetu } function test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() public { - uint256 transmitter1BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); - assertEq(transmitter1BalanceBefore, 0); - uint256 transmitter2BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_2); - assertEq(transmitter2BalanceBefore, 0); - uint256 transmitter3BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_3); - assertEq(transmitter3BalanceBefore, 0); - uint256 transmitter4BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_4); - assertEq(transmitter4BalanceBefore, 0); + uint256[4] memory transmitterBalancesBefore = _getTransmitterBalances(); + _assertTransmittersAllHaveBalance(transmitterBalancesBefore, 0); s_functionsCoordinator.oracleWithdrawAll(); uint96 expectedTransmitterBalance = s_fulfillmentCoordinatorBalance / 3; - uint256 transmitter1BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); - assertEq(transmitter1BalanceAfter, expectedTransmitterBalance); - uint256 transmitter2BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_2); - assertEq(transmitter2BalanceAfter, expectedTransmitterBalance); - uint256 transmitter3BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_3); - assertEq(transmitter3BalanceAfter, expectedTransmitterBalance); + uint256[4] memory transmitterBalancesAfter = _getTransmitterBalances(); + assertEq(transmitterBalancesAfter[0], expectedTransmitterBalance); + assertEq(transmitterBalancesAfter[1], expectedTransmitterBalance); + assertEq(transmitterBalancesAfter[2], expectedTransmitterBalance); // Transmitter 4 has no balance - uint256 transmitter4BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_4); - assertEq(transmitter4BalanceAfter, 0); + assertEq(transmitterBalancesAfter[3], 0); } } -/// @notice #_getTransmitters -contract FunctionsBilling__GetTransmitters { - // TODO: make contract internal function helper -} - /// @notice #_disperseFeePool -contract FunctionsBilling__DisperseFeePool { - // TODO: make contract internal function helper +contract FunctionsBilling__DisperseFeePool is FunctionsRouterSetup { + function test__DisperseFeePool_RevertIfNotSet() public { + // Manually set s_feePool (at slot 11) to 1 to get past first check in _disperseFeePool + vm.store(address(s_functionsCoordinator), bytes32(uint256(11)), bytes32(uint256(1))); + + vm.expectRevert(FunctionsBilling.NoTransmittersSet.selector); + s_functionsCoordinator.disperseFeePool_HARNESS(); + } } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsClient.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsClient.t.sol index d6a3be1684..363827645c 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsClient.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsClient.t.sol @@ -2,22 +2,23 @@ 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 {FunctionsSubscriptionSetup} from "./Setup.t.sol"; +import {FunctionsClientSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup} from "./Setup.t.sol"; /// @notice #constructor -contract FunctionsClient_Constructor { - +contract FunctionsClient_Constructor is FunctionsClientSetup { + function test_Constructor_Success() public { + assertEq(address(s_functionsRouter), s_functionsClient.getRouter_HARNESS()); + } } /// @notice #_sendRequest contract FunctionsClient__SendRequest is FunctionsSubscriptionSetup { - // TODO: make contract internal function helper - function test__SendRequest_RevertIfInvalidCallbackGasLimit() public { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; @@ -43,12 +44,35 @@ contract FunctionsClient__SendRequest is FunctionsSubscriptionSetup { } } -/// @notice #fulfillRequest -contract FunctionsClient_FulfillRequest { +/// @notice #handleOracleFulfillment +contract FunctionsClient_HandleOracleFulfillment is FunctionsClientRequestSetup { + function test_HandleOracleFulfillment_RevertIfNotRouter() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); -} + vm.expectRevert(FunctionsClient.OnlyRouterCanFulfill.selector); + s_functionsClient.handleOracleFulfillment(s_requests[1].requestId, new bytes(0), new bytes(0)); + } -/// @notice #handleOracleFulfillment -contract FunctionsClient_HandleOracleFulfillment { + event RequestFulfilled(bytes32 indexed id); + event ResponseReceived(bytes32 indexed requestId, bytes result, bytes err); + + function test_HandleOracleFulfillment_Success() public { + // Send as Router + vm.stopPrank(); + vm.startPrank(address(s_functionsRouter)); + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit ResponseReceived(s_requests[1].requestId, new bytes(0), new bytes(0)); + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestFulfilled(s_requests[1].requestId); + + s_functionsClient.handleOracleFulfillment(s_requests[1].requestId, new bytes(0), new bytes(0)); + } } 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 893aa6408b..7166add19f 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 @@ -4,9 +4,13 @@ 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 {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; +import {Routable} from "../../dev/v1_X/Routable.sol"; -import {FunctionsRouterSetup} from "./Setup.t.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 { @@ -17,48 +21,220 @@ contract FunctionsCoordinator_Constructor is FunctionsRouterSetup { } /// @notice #getThresholdPublicKey -contract FunctionsCoordinator_GetThresholdPublicKey { +contract FunctionsCoordinator_GetThresholdPublicKey is FunctionsDONSetup { + function test_GetThresholdPublicKey_RevertIfEmpty() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + // Reverts when empty + vm.expectRevert(FunctionsCoordinator.EmptyPublicKey.selector); + s_functionsCoordinator.getThresholdPublicKey(); + } + + function test_GetThresholdPublicKey_Success() public { + s_functionsCoordinator.setThresholdPublicKey(s_thresholdKey); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes memory thresholdKey = s_functionsCoordinator.getThresholdPublicKey(); + assertEq(thresholdKey, s_thresholdKey); + } } /// @notice #setThresholdPublicKey -contract FunctionsCoordinator_SetThresholdPublicKey { +contract FunctionsCoordinator_SetThresholdPublicKey is FunctionsDONSetup { + function test_SetThresholdPublicKey_RevertNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + bytes memory newThresholdKey = new bytes(0); + s_functionsCoordinator.setThresholdPublicKey(newThresholdKey); + } + + function test_SetThresholdPublicKey_Success() public { + s_functionsCoordinator.setThresholdPublicKey(s_thresholdKey); + + bytes memory thresholdKey = s_functionsCoordinator.getThresholdPublicKey(); + assertEq(thresholdKey, s_thresholdKey); + } } /// @notice #getDONPublicKey -contract FunctionsCoordinator_GetDONPublicKey { +contract FunctionsCoordinator_GetDONPublicKey is FunctionsDONSetup { + function test_GetDONPublicKey_RevertIfEmpty() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + // Reverts when empty + vm.expectRevert(FunctionsCoordinator.EmptyPublicKey.selector); + s_functionsCoordinator.getDONPublicKey(); + } + + function test_GetDONPublicKey_Success() public { + s_functionsCoordinator.setDONPublicKey(s_donKey); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + bytes memory donKey = s_functionsCoordinator.getDONPublicKey(); + assertEq(donKey, s_donKey); + } } /// @notice #setDONPublicKey -contract FunctionsCoordinator__SetDONPublicKey { +contract FunctionsCoordinator_SetDONPublicKey is FunctionsDONSetup { + function test_SetDONPublicKey_RevertNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsCoordinator.setDONPublicKey(s_donKey); + } + + function test_SetDONPublicKey_Success() public { + s_functionsCoordinator.setDONPublicKey(s_donKey); + bytes memory donKey = s_functionsCoordinator.getDONPublicKey(); + assertEq(donKey, s_donKey); + } } /// @notice #_isTransmitter -contract FunctionsCoordinator_IsTransmitter { - // TODO: make contract internal function helper +contract FunctionsCoordinator__IsTransmitter is FunctionsDONSetup { + function test__IsTransmitter_SuccessFound() public { + bool isTransmitter = s_functionsCoordinator.isTransmitter_HARNESS(NOP_TRANSMITTER_ADDRESS_1); + assertEq(isTransmitter, true); + } + + function test__IsTransmitter_SuccessNotFound() public { + bool isTransmitter = s_functionsCoordinator.isTransmitter_HARNESS(STRANGER_ADDRESS); + assertEq(isTransmitter, false); + } } -/// @notice #setNodePublicKey -contract FunctionsCoordinator_SetNodePublicKey { +/// @notice #startRequest +contract FunctionsCoordinator_StartRequest is FunctionsSubscriptionSetup { + function test_StartRequest_RevertIfNotRouter() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); -} + vm.expectRevert(Routable.OnlyCallableByRouter.selector); -/// @notice #deleteNodePublicKey -contract FunctionsCoordinator_DeleteNodePublicKey { + s_functionsCoordinator.startRequest( + FunctionsResponse.RequestMeta({ + requestingContract: address(s_functionsClient), + data: new bytes(0), + subscriptionId: s_subscriptionId, + dataVersion: FunctionsRequest.REQUEST_DATA_VERSION, + flags: bytes32(0), + callbackGasLimit: 5_500, + adminFee: s_adminFee, + initiatedRequests: 0, + completedRequests: 0, + availableBalance: s_subscriptionInitialFunding, + subscriptionOwner: OWNER_ADDRESS + }) + ); + } -} + event OracleRequest( + bytes32 indexed requestId, + address indexed requestingContract, + address requestInitiator, + uint64 subscriptionId, + address subscriptionOwner, + bytes data, + uint16 dataVersion, + bytes32 flags, + uint64 callbackGasLimit, + FunctionsResponse.Commitment commitment + ); -/// @notice #getAllNodePublicKeys -contract FunctionsCoordinator_GetAllNodePublicKeys { + function test_StartRequest_Success() public { + // Send as Router + vm.stopPrank(); + vm.startPrank(address(s_functionsRouter)); + (, , address txOrigin) = vm.readCallers(); -} + bytes memory _requestData = new bytes(0); + uint32 _callbackGasLimit = 5_500; + uint96 costEstimate = s_functionsCoordinator.estimateCost( + s_subscriptionId, + _requestData, + _callbackGasLimit, + tx.gasprice + ); + uint32 timeoutTimestamp = uint32(block.timestamp + getCoordinatorConfig().requestTimeoutSeconds); + bytes32 expectedRequestId = keccak256( + abi.encode( + address(s_functionsCoordinator), + address(s_functionsClient), + s_subscriptionId, + 1, + keccak256(_requestData), + FunctionsRequest.REQUEST_DATA_VERSION, + _callbackGasLimit, + costEstimate, + timeoutTimestamp, + txOrigin + ) + ); -/// @notice #startRequest -contract FunctionsCoordinator_StartRequest { + FunctionsResponse.Commitment memory expectedComittment = FunctionsResponse.Commitment({ + adminFee: s_adminFee, + coordinator: address(s_functionsCoordinator), + client: address(s_functionsClient), + subscriptionId: s_subscriptionId, + callbackGasLimit: _callbackGasLimit, + estimatedTotalCostJuels: costEstimate, + timeoutTimestamp: timeoutTimestamp, + requestId: expectedRequestId, + donFee: s_donFee, + gasOverheadBeforeCallback: getCoordinatorConfig().gasOverheadBeforeCallback, + gasOverheadAfterCallback: getCoordinatorConfig().gasOverheadAfterCallback + }); + // topic0 (function signature, always checked), topic1 (true), topic2 (true), NOT topic3 (false), and data (true). + vm.expectEmit(true, true, false, true); + emit OracleRequest({ + requestId: expectedRequestId, + requestingContract: address(s_functionsClient), + requestInitiator: txOrigin, + subscriptionId: s_subscriptionId, + subscriptionOwner: OWNER_ADDRESS, + data: _requestData, + dataVersion: FunctionsRequest.REQUEST_DATA_VERSION, + flags: bytes32(0), + callbackGasLimit: _callbackGasLimit, + commitment: expectedComittment + }); + + s_functionsCoordinator.startRequest( + FunctionsResponse.RequestMeta({ + requestingContract: address(s_functionsClient), + data: _requestData, + subscriptionId: s_subscriptionId, + dataVersion: FunctionsRequest.REQUEST_DATA_VERSION, + flags: bytes32(0), + callbackGasLimit: 5_500, + adminFee: s_adminFee, + initiatedRequests: 0, + completedRequests: 0, + availableBalance: s_subscriptionInitialFunding, + subscriptionOwner: OWNER_ADDRESS + }) + ); + } } /// @notice #_beforeSetConfig @@ -73,10 +249,10 @@ contract FunctionsCoordinator__GetTransmitters { /// @notice #_report contract FunctionsCoordinator__Report { - + // TODO: make contract internal function helper } /// @notice #_onlyOwner contract FunctionsCoordinator__OnlyOwner { - + // TODO: make contract internal function helper } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol index b9b6e1d574..081fe2f664 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol @@ -938,7 +938,7 @@ contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { uint32 callbackGasLimit = s_requests[requestToFulfill].requestData.callbackGasLimit; // Coordinator sends enough gas that would get through callback and payment, but fail after - uint256 gasToUse = getCoordinatorConfig().gasOverheadBeforeCallback + callbackGasLimit + 100000; + uint256 gasToUse = getCoordinatorConfig().gasOverheadBeforeCallback + callbackGasLimit + 10_000; // topic0 (function signature, always checked), topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true). bool checkTopic1RequestId = true; @@ -1221,7 +1221,7 @@ contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { emit RequestProcessed({ requestId: s_requests[requestToFulfill].requestId, subscriptionId: s_subscriptionId, - totalCostJuels: _getExpectedCost(5393), // gasUsed is manually taken + totalCostJuels: _getExpectedCost(5416), // gasUsed is manually taken transmitter: NOP_TRANSMITTER_ADDRESS_1, resultCode: FunctionsResponse.FulfillResult.FULFILLED, response: bytes(response), diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol index 8046bf7d93..df905fb8be 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol @@ -1122,62 +1122,14 @@ contract FunctionsSubscriptions_CancelSubscription is FunctionsSubscriptionSetup uint256 balanceAfterWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); assertEq(balanceBeforeWithdraw + expectedDepositWithheld, balanceAfterWithdraw); } +} - function test_CancelSubscription_SuccessRecieveDeposit() public { - // Complete 1 request = subscriptionDepositMinimumRequests - vm.recordLogs(); - bytes32 requestId = s_functionsClient.sendRequest( - s_donId, - "return 'hello world';", - new bytes(0), - new string[](0), - new bytes[](0), - s_subscriptionId, - 5500 - ); - - // Get commitment data from OracleRequest event log - Vm.Log[] memory entries = vm.getRecordedLogs(); - (, , , , , , , FunctionsResponse.Commitment memory commitment) = abi.decode( - entries[0].data, - (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) - ); - - // Send as transmitter 1 - vm.stopPrank(); - vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); - - // Build report - bytes32[] memory requestIds = new bytes32[](1); - requestIds[0] = requestId; - bytes[] memory results = new bytes[](1); - results[0] = bytes("hello world!"); - bytes[] memory errors = new bytes[](1); - // No error - bytes[] memory onchainMetadata = new bytes[](1); - onchainMetadata[0] = abi.encode(commitment); - bytes[] memory offchainMetadata = new bytes[](1); - // No offchain metadata - bytes memory report = abi.encode(requestIds, results, errors, onchainMetadata, offchainMetadata); - - // Build signers - address[31] memory signers; - signers[0] = NOP_SIGNER_ADDRESS_1; - - // Send report - vm.recordLogs(); - s_functionsCoordinator.callReportWithSigners(report, signers); - - // Get actual cost from RequestProcessed event log - Vm.Log[] memory entries2 = vm.getRecordedLogs(); - (uint96 totalCostJuels, , , , , ) = abi.decode( - entries2[2].data, - (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) - ); +/// @notice #cancelSubscription +contract FunctionsSubscriptions_CancelSubscription_ReceiveDeposit is FunctionsFulfillmentSetup { + event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); - // Return to sending as owner - vm.stopPrank(); - vm.startPrank(OWNER_ADDRESS); + function test_CancelSubscription_SuccessRecieveDeposit() public { + uint96 totalCostJuels = s_fulfillmentRouterOwnerBalance + s_fulfillmentCoordinatorBalance; uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); diff --git a/contracts/src/v0.8/functions/tests/v1_X/README.md b/contracts/src/v0.8/functions/tests/v1_X/README.md index 6400a28dc7..5f96532fb4 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/README.md +++ b/contracts/src/v0.8/functions/tests/v1_X/README.md @@ -5,18 +5,21 @@ First set the foundry profile to Functions: export FOUNDRY_PROFILE=functions ``` -To run all test files use: +**To run tests use**: + +All Functions test files: ``` -forge test -vv +forge test -vvv ``` To run a specific file use: ``` -forge test -vv --mp src/v0.8/functions/tests/v1_X/[File Name].t.sol +forge test -vvv --mp src/v0.8/functions/tests/v1_X/[File Name].t.sol ``` -To see coverage: -First ensure that the correct files are being evaluated. For example, if only v1 contracts are, then temporarily change the Functions profile in `./foundry.toml`. +**To see coverage**: +First ensure that the correct files are being evaluated. For example, if only v0 contracts are, then temporarily change the Functions profile in `./foundry.toml`. + ``` -forge coverage +forge coverage --ir-minimum ``` \ No newline at end of file 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 f603e83281..0c08fd20cd 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 @@ -2,21 +2,21 @@ pragma solidity ^0.8.19; import {BaseTest} from "./BaseTest.t.sol"; -import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; -import {FunctionsCoordinatorTestHelper} from "./testhelpers/FunctionsCoordinatorTestHelper.sol"; +import {FunctionsClientHarness} from "./testhelpers/FunctionsClientHarness.sol"; +import {FunctionsRouterHarness, FunctionsRouter} from "./testhelpers/FunctionsRouterHarness.sol"; +import {FunctionsCoordinatorHarness} from "./testhelpers/FunctionsCoordinatorHarness.sol"; import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; import {TermsOfServiceAllowList} from "../../dev/v1_X/accessControl/TermsOfServiceAllowList.sol"; -import {FunctionsClientUpgradeHelper} from "./testhelpers/FunctionsClientUpgradeHelper.sol"; import {MockLinkToken} from "../../../mocks/MockLinkToken.sol"; import "forge-std/Vm.sol"; /// @notice Set up to deploy the following contracts: FunctionsRouter, FunctionsCoordinator, LINK/ETH Feed, ToS Allow List, and LINK token contract FunctionsRouterSetup is BaseTest { - FunctionsRouter internal s_functionsRouter; - FunctionsCoordinatorTestHelper internal s_functionsCoordinator; // TODO: use actual FunctionsCoordinator instead of helper + FunctionsRouterHarness internal s_functionsRouter; + FunctionsCoordinatorHarness internal s_functionsCoordinator; MockV3Aggregator internal s_linkEthFeed; TermsOfServiceAllowList internal s_termsOfServiceAllowList; MockLinkToken internal s_linkToken; @@ -36,9 +36,9 @@ contract FunctionsRouterSetup is BaseTest { function setUp() public virtual override { BaseTest.setUp(); s_linkToken = new MockLinkToken(); - s_functionsRouter = new FunctionsRouter(address(s_linkToken), getRouterConfig()); + s_functionsRouter = new FunctionsRouterHarness(address(s_linkToken), getRouterConfig()); s_linkEthFeed = new MockV3Aggregator(0, LINK_ETH_RATE); - s_functionsCoordinator = new FunctionsCoordinatorTestHelper( + s_functionsCoordinator = new FunctionsCoordinatorHarness( address(s_functionsRouter), getCoordinatorConfig(), address(s_linkEthFeed) @@ -68,8 +68,8 @@ contract FunctionsRouterSetup is BaseTest { return FunctionsBilling.Config({ feedStalenessSeconds: 24 * 60 * 60, // 1 day - gasOverheadAfterCallback: 50_000, // TODO: update - gasOverheadBeforeCallback: 100_00, // TODO: update + gasOverheadAfterCallback: 93_942, + gasOverheadBeforeCallback: 105_000, requestTimeoutSeconds: 60 * 5, // 5 minutes donFee: s_donFee, maxSupportedRequestDataVersion: 1, @@ -111,6 +111,15 @@ contract FunctionsDONSetup is FunctionsRouterSetup { uint64 internal s_offchainConfigVersion = 1; bytes internal s_offchainConfig = new bytes(0); + bytes s_thresholdKey = + vm.parseBytes( + "0x7b2247726f7570223a2250323536222c22475f626172223a22424f2f344358424575792f64547a436a612b614e774d666c2b645a77346d325036533246536b4966472f6633527547327337392b494e79642b4639326a346f586e67433657427561556a752b4a637a32377834484251343d222c2248223a224250532f72485065377941467232416c447a79395549466258776d46384666756632596d514177666e3342373844336f474845643247474536466e616f34552b4c6a4d4d5756792b464f7075686e77554f6a75427a64773d222c22484172726179223a5b22424d75546862414473337768316e67764e56792f6e3841316d42674b5a4b4c475259385937796a39695769337242502f316a32347571695869534531437554384c6f51446a386248466d384345477667517158494e62383d222c224248687974716d6e34314373322f4658416f43737548687151486236382f597930524b2b41354c6647654f645a78466f4e386c442b45656e4b587a544943784f6d3231636d535447364864484a6e336342645663714c673d222c22424d794e7a4534616e596258474d72694f52664c52634e7239766c347878654279316432452f4464335a744630546372386267567435582b2b42355967552b4b7875726e512f4d656b6857335845782b79506e4e4f584d3d222c22424d6a753272375a657a4a45545539413938746a6b6d547966796a79493735345742555835505174724a6578346d6766366130787373426d50325a7472412b55576d504e592b6d4664526b46674f7944694c53614e59453d225d7d" + ); + bytes s_donKey = + vm.parseBytes( + "0xf2f9c47363202d89aa9fa70baf783d70006fe493471ac8cfa82f1426fd09f16a5f6b32b7c4b5d5165cd147a6e513ba4c0efd39d969d6b20a8a21126f0411b9c6" + ); + function setUp() public virtual override { FunctionsRouterSetup.setUp(); @@ -136,6 +145,22 @@ contract FunctionsDONSetup is FunctionsRouterSetup { s_offchainConfig ); } + + function _getTransmitterBalances() internal view returns (uint256[4] memory balances) { + return [ + s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1), + s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_2), + s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_3), + s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_4) + ]; + } + + function _assertTransmittersAllHaveBalance(uint256[4] memory balances, uint256 expectedBalance) internal { + assertEq(balances[0], expectedBalance); + assertEq(balances[1], expectedBalance); + assertEq(balances[2], expectedBalance); + assertEq(balances[3], expectedBalance); + } } /// @notice Set up to add the Coordinator and ToS Allow Contract as routes on the Router contract @@ -172,12 +197,12 @@ contract FunctionsOwnerAcceptTermsOfServiceSetup is FunctionsRoutesSetup { /// @notice Set up to deploy a consumer contract contract FunctionsClientSetup is FunctionsOwnerAcceptTermsOfServiceSetup { - FunctionsClientUpgradeHelper internal s_functionsClient; + FunctionsClientHarness internal s_functionsClient; function setUp() public virtual override { FunctionsOwnerAcceptTermsOfServiceSetup.setUp(); - s_functionsClient = new FunctionsClientUpgradeHelper(address(s_functionsRouter)); + s_functionsClient = new FunctionsClientHarness(address(s_functionsRouter)); } } @@ -261,7 +286,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { vm.recordLogs(); - bytes32 requestId = FunctionsClientUpgradeHelper(client).sendRequest( + bytes32 requestId = FunctionsClientHarness(client).sendRequest( s_donId, sourceCode, secrets, diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol new file mode 100644 index 0000000000..ec3b5a65fe --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsClientUpgradeHelper} from "./FunctionsClientUpgradeHelper.sol"; +import {FunctionsResponse} from "../../../dev/v1_X/libraries/FunctionsResponse.sol"; + +/// @title Functions Client Test Harness +/// @notice Contract to expose internal functions for testing purposes +contract FunctionsClientHarness is FunctionsClientUpgradeHelper { + constructor(address router) FunctionsClientUpgradeHelper(router) {} + + function getRouter_HARNESS() external view returns (address) { + return address(i_router); + } + + function sendRequest_HARNESS( + bytes memory data, + uint64 subscriptionId, + uint32 callbackGasLimit, + bytes32 donId + ) external returns (bytes32) { + return super._sendRequest(data, subscriptionId, callbackGasLimit, donId); + } +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol index bca0f0a3fa..bc73544205 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; +pragma solidity ^0.8.19; import {ITermsOfServiceAllowList} from "../../../dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol"; import {IFunctionsSubscriptions} from "../../../dev/v1_X/interfaces/IFunctionsSubscriptions.sol"; diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol index 362b21d89b..e567471773 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; +pragma solidity ^0.8.19; import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; import {FunctionsClient} from "../../../dev/v1_X/FunctionsClient.sol"; 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 new file mode 100644 index 0000000000..bc103fc356 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsCoordinator} from "../../../dev/v1_X/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../../dev/v1_X/FunctionsBilling.sol"; +import {FunctionsResponse} from "../../../dev/v1_X/libraries/FunctionsResponse.sol"; + +/// @title Functions Coordinator Test Harness +/// @notice Contract to expose internal functions for testing purposes +contract FunctionsCoordinatorHarness is FunctionsCoordinator { + address s_linkToNativeFeed_HARNESS; + address s_router_HARNESS; + + constructor( + address router, + FunctionsBilling.Config memory config, + address linkToNativeFeed + ) FunctionsCoordinator(router, config, linkToNativeFeed) { + s_linkToNativeFeed_HARNESS = linkToNativeFeed; + s_router_HARNESS = router; + } + + function isTransmitter_HARNESS(address node) external view returns (bool) { + return super._isTransmitter(node); + } + + function beforeSetConfig_HARNESS(uint8 _f, bytes memory _onchainConfig) external { + return super._beforeSetConfig(_f, _onchainConfig); + } + + /// @dev Used by FunctionsBilling.sol + function getTransmitters_HARNESS() external view returns (address[] memory) { + return super._getTransmitters(); + } + + function report_HARNESS( + uint256 initialGas, + address transmitter, + uint8 signerCount, + address[MAX_NUM_ORACLES] memory signers, + bytes calldata report + ) external { + return super._report(initialGas, transmitter, signerCount, signers, report); + } + + function onlyOwner_HARNESS() external view { + return super._onlyOwner(); + } + + // ================================================================ + // | Functions Billing | + // ================================================================ + + function getLinkToNativeFeed_HARNESS() external view returns (address) { + return s_linkToNativeFeed_HARNESS; + } + + function getRouter_HARNESS() external view returns (address) { + return s_router_HARNESS; + } + + function calculateCostEstimate_HARNESS( + uint32 callbackGasLimit, + uint256 gasPriceWei, + uint72 donFee, + uint72 adminFee + ) external view returns (uint96) { + return super._calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee); + } + + function startBilling_HARNESS( + FunctionsResponse.RequestMeta memory request + ) external returns (FunctionsResponse.Commitment memory commitment) { + return super._startBilling(request); + } + + function fulfillAndBill_HARNESS( + bytes32 requestId, + bytes memory response, + bytes memory err, + bytes memory onchainMetadata, + bytes memory offchainMetadata + ) external returns (FunctionsResponse.FulfillResult) { + return super._fulfillAndBill(requestId, response, err, onchainMetadata, offchainMetadata); + } + + function disperseFeePool_HARNESS() external { + return super._disperseFeePool(); + } + + // ================================================================ + // | OCR2 | + // ================================================================ + + function configDigestFromConfigData_HARNESS( + uint256 _chainId, + address _contractAddress, + uint64 _configCount, + address[] memory _signers, + address[] memory _transmitters, + uint8 _f, + bytes memory _onchainConfig, + uint64 _encodedConfigVersion, + bytes memory _encodedConfig + ) internal pure returns (bytes32) { + return + super._configDigestFromConfigData( + _chainId, + _contractAddress, + _configCount, + _signers, + _transmitters, + _f, + _onchainConfig, + _encodedConfigVersion, + _encodedConfig + ); + } +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol index 1d883b3b29..5e57e62e59 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; +pragma solidity ^0.8.19; import {FunctionsCoordinator} from "../../../dev/v1_X/FunctionsCoordinator.sol"; import {FunctionsBilling} from "../../../dev/v1_X/FunctionsBilling.sol"; diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsRouterHarness.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsRouterHarness.sol new file mode 100644 index 0000000000..7caeff498a --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsRouterHarness.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsRouter} from "../../../dev/v1_X/FunctionsRouter.sol"; + +/// @title Functions Router Test Harness +/// @notice Contract to expose internal functions for testing purposes +contract FunctionsRouterHarness is FunctionsRouter { + constructor(address linkToken, Config memory config) FunctionsRouter(linkToken, config) {} + + function getMaxConsumers_HARNESS() external view returns (uint16) { + return super._getMaxConsumers(); + } + + function getSubscriptionDepositDetails_HARNESS() external view returns (uint16, uint72) { + return super._getSubscriptionDepositDetails(); + } + + function whenNotPaused_HARNESS() external view { + return super._whenNotPaused(); + } + + function onlyRouterOwner_HARNESS() external view { + return super._onlyRouterOwner(); + } + + function onlySenderThatAcceptedToS_HARNESS() external view { + return super._onlySenderThatAcceptedToS(); + } +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsSubscriptionsHarness.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsSubscriptionsHarness.sol new file mode 100644 index 0000000000..2e2427f6e1 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsSubscriptionsHarness.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsSubscriptions} from "../../../dev/v1_X/FunctionsSubscriptions.sol"; + +/// @title Functions Subscriptions Test Harness +/// @notice Contract to expose internal functions for testing purposes +contract FunctionsSubscriptionsHarness is FunctionsSubscriptions { + constructor(address link) FunctionsSubscriptions(link) {} + + function markRequestInFlight_HARNESS(address client, uint64 subscriptionId, uint96 estimatedTotalCostJuels) external { + return super._markRequestInFlight(client, subscriptionId, estimatedTotalCostJuels); + } + + function pay_HARNESS( + uint64 subscriptionId, + uint96 estimatedTotalCostJuels, + address client, + uint96 adminFee, + uint96 juelsPerGas, + uint96 gasUsed, + uint96 costWithoutCallbackJuels + ) external returns (Receipt memory) { + return + super._pay( + subscriptionId, + estimatedTotalCostJuels, + client, + adminFee, + juelsPerGas, + gasUsed, + costWithoutCallbackJuels + ); + } + + function isExistingSubscription_HARNESS(uint64 subscriptionId) external view { + return super._isExistingSubscription(subscriptionId); + } + + function isAllowedConsumer_HARNESS(address client, uint64 subscriptionId) external view { + return super._isAllowedConsumer(client, subscriptionId); + } + + // Overrides + function _getMaxConsumers() internal view override returns (uint16) {} + + function _getSubscriptionDepositDetails() internal override returns (uint16, uint72) {} + + function _onlySenderThatAcceptedToS() internal override {} + + function _onlyRouterOwner() internal override {} + + function _whenNotPaused() internal override {} +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol index e8e74e3ed7..50e90c4495 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; +pragma solidity ^0.8.19; import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; From e9c820632bfd2cf7da0c40ce547af13cd53748de Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Wed, 25 Oct 2023 02:47:50 -0400 Subject: [PATCH 002/327] (chore): Reduce contracts solhint warnings by ignoring Functions v1.0.0 production code (#11069) --- contracts/.solhintignore | 4 ++-- contracts/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/.solhintignore b/contracts/.solhintignore index 1a308af94b..53d52657ec 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1,8 +1,8 @@ # 351 warnings #./src/v0.8/automation -# 27 warnings -#./src/v0.8/functions +# Ignore Functions v1.0.0 code that was frozen after audit +./src/v0.8/functions/v1_0_0 # Ignore tests, this should not be the long term plan but is OK in the short term ./src/v0.8/**/*.t.sol diff --git a/contracts/package.json b/contracts/package.json index 6c902926c2..75b1ddfa97 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 442 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 351 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", From 5e75873305b79b6a313813a29e604678953c291f Mon Sep 17 00:00:00 2001 From: Mohamed Mehany <7327188+mohamed-mehany@users.noreply.github.com> Date: Wed, 25 Oct 2023 10:57:56 +0200 Subject: [PATCH 003/327] Fix redundant "replacing abandoned tx" logs (#11019) This fixes the issue of incorrectly logging the "replacing abandoned tx" log. The DELETE query doesn't return a sql.ErrNoRows on failing to find rows to be deleted. Instead we are checking on the count of RowsAffected. Another minor fix is continuing to execute the function if no attempts were deleted, instead of throwing an error, since at this point there is no need to break the execution flow. Co-authored-by: Simson --- core/chains/evm/txmgr/evm_tx_store.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 7b1ef8948c..96963e78d7 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -1486,14 +1486,20 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, // Note: the record of the original abandoned transaction will remain in evm.txes, only the attempt is replaced. (Any receipt // associated with the abandoned attempt would also be lost, although this shouldn't happen since only unconfirmed transactions // can be abandoned.) - _, err := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t + result, err := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t WHERE t.id = a.eth_tx_id AND a.hash = $1 AND t.state = $2 AND t.error = 'abandoned'`, attempt.Hash, txmgr.TxFatalError, ) if err == nil { - o.logger.Debugf("Replacing abandoned tx with tx hash %s with tx_id=%d with identical tx hash", attempt.Hash, attempt.TxID) - } else if errors.Is(err, sql.ErrNoRows) { - return err + count, err := result.RowsAffected() + if err != nil { + return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to get rows affected") + } + if count > 0 { + o.logger.Debugf("Replacing abandoned tx with tx hash %s with tx_id=%d with identical tx hash", attempt.Hash, attempt.TxID) + } + } else { + return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to delete abandoned transactions") } var dbAttempt DbEthTxAttempt From 8743742d827a4717d78ee5c0276b2cf3d88d356e Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Wed, 25 Oct 2023 12:17:04 +0200 Subject: [PATCH 004/327] Bump breaking NPM deps (#11003) * bump typechain/hardhat * bump typechain/hardhat * bump nomiclabs/hardhat-etherscan * Pin cbor v5.2.0 dependency * bump hardhat-abi-exporter * bump hardhat-contract-sizer * bump typechain/ethers-v5 * Revert "bump typechain/ethers-v5" This reverts commit ea695e7138115c61ddfd7aa2f6030614e7b16a61. * solhint wrong issue number --------- Co-authored-by: Justin Kaseman --- contracts/.solhintignore | 2 +- contracts/package.json | 11 ++-- contracts/pnpm-lock.yaml | 105 +++++++++++++++++++++++---------------- 3 files changed, 69 insertions(+), 49 deletions(-) diff --git a/contracts/.solhintignore b/contracts/.solhintignore index 53d52657ec..bc7be4fbfe 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1,4 +1,4 @@ -# 351 warnings +# 377 warnings #./src/v0.8/automation # Ignore Functions v1.0.0 code that was frozen after audit diff --git a/contracts/package.json b/contracts/package.json index 75b1ddfa97..46b47440a6 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 351 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 377 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", @@ -40,12 +40,12 @@ "@ethersproject/random": "~5.7.0", "@nomicfoundation/hardhat-network-helpers": "^1.0.9", "@nomiclabs/hardhat-ethers": "^2.2.3", - "@nomiclabs/hardhat-etherscan": "^3.1.0", + "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "2.0.6", "@openzeppelin/hardhat-upgrades": "1.28.0", "@openzeppelin/test-helpers": "^0.5.16", "@typechain/ethers-v5": "^7.2.0", - "@typechain/hardhat": "^5.0.0", + "@typechain/hardhat": "^7.0.0", "@types/cbor": "5.0.1", "@types/chai": "^4.3.9", "@types/debug": "^4.1.10", @@ -55,6 +55,7 @@ "@typescript-eslint/eslint-plugin": "^6.8.0", "@typescript-eslint/parser": "^6.8.0", "abi-to-sol": "^0.6.6", + "cbor": "^5.2.0", "chai": "^4.3.10", "debug": "^4.3.4", "eslint": "^8.51.0", @@ -64,8 +65,8 @@ "ethereum-waffle": "^3.4.4", "ethers": "~5.7.2", "hardhat": "~2.18.1", - "hardhat-abi-exporter": "^2.2.1", - "hardhat-contract-sizer": "^2.5.1", + "hardhat-abi-exporter": "^2.10.1", + "hardhat-contract-sizer": "^2.10.0", "hardhat-gas-reporter": "^1.0.9", "hardhat-ignore-warnings": "^0.2.6", "istanbul": "^0.4.5", diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index 9d54cfa774..65865f2adf 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -44,14 +44,14 @@ devDependencies: specifier: ^2.2.3 version: 2.2.3(ethers@5.7.2)(hardhat@2.18.1) '@nomiclabs/hardhat-etherscan': - specifier: ^3.1.0 - version: 3.1.0(hardhat@2.18.1) + specifier: ^3.1.7 + version: 3.1.7(hardhat@2.18.1) '@nomiclabs/hardhat-waffle': specifier: 2.0.6 version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.18.1) '@openzeppelin/hardhat-upgrades': specifier: 1.28.0 - version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.0)(ethers@5.7.2)(hardhat@2.18.1) + version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.18.1) '@openzeppelin/test-helpers': specifier: ^0.5.16 version: 0.5.16(bn.js@4.12.0) @@ -59,8 +59,8 @@ devDependencies: specifier: ^7.2.0 version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.2.2) '@typechain/hardhat': - specifier: ^5.0.0 - version: 5.0.0(hardhat@2.18.1)(lodash@4.17.21)(typechain@8.2.0) + specifier: ^7.0.0 + version: 7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.18.1)(typechain@8.2.0) '@types/cbor': specifier: 5.0.1 version: 5.0.1 @@ -88,6 +88,9 @@ devDependencies: abi-to-sol: specifier: ^0.6.6 version: 0.6.6 + cbor: + specifier: ^5.2.0 + version: 5.2.0 chai: specifier: ^4.3.10 version: 4.3.10 @@ -116,11 +119,11 @@ devDependencies: specifier: ~2.18.1 version: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) hardhat-abi-exporter: - specifier: ^2.2.1 - version: 2.2.1(hardhat@2.18.1) + specifier: ^2.10.1 + version: 2.10.1(hardhat@2.18.1) hardhat-contract-sizer: - specifier: ^2.5.1 - version: 2.5.1(hardhat@2.18.1) + specifier: ^2.10.0 + version: 2.10.0(hardhat@2.18.1) hardhat-gas-reporter: specifier: ^1.0.9 version: 1.0.9(hardhat@2.18.1) @@ -1159,22 +1162,22 @@ packages: hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) dev: true - /@nomiclabs/hardhat-etherscan@3.1.0(hardhat@2.18.1): - resolution: {integrity: sha512-JroYgfN1AlYFkQTQ3nRwFi4o8NtZF7K/qFR2dxDUgHbCtIagkUseca9L4E/D2ScUm4XT40+8PbCdqZi+XmHyQA==} + /@nomiclabs/hardhat-etherscan@3.1.7(hardhat@2.18.1): + resolution: {integrity: sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ==} peerDependencies: hardhat: ^2.0.4 dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/address': 5.7.0 - cbor: 5.2.0 + cbor: 8.1.0 chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 7.0.1 hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) lodash: 4.17.21 semver: 6.3.0 - table: 6.8.0 - undici: 5.10.0 + table: 6.8.1 + undici: 5.19.1 transitivePeerDependencies: - supports-color dev: true @@ -1223,7 +1226,7 @@ packages: - encoding dev: true - /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.0)(ethers@5.7.2)(hardhat@2.18.1): + /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.18.1): resolution: {integrity: sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ==} hasBin: true peerDependencies: @@ -1237,7 +1240,7 @@ packages: optional: true dependencies: '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.18.1) - '@nomiclabs/hardhat-etherscan': 3.1.0(hardhat@2.18.1) + '@nomiclabs/hardhat-etherscan': 3.1.7(hardhat@2.18.1) '@openzeppelin/defender-base-client': 1.49.0(debug@4.3.4) '@openzeppelin/platform-deploy-client': 0.8.0(debug@4.3.4) '@openzeppelin/upgrades-core': 1.30.1 @@ -1645,16 +1648,22 @@ packages: typescript: 5.2.2 dev: true - /@typechain/hardhat@5.0.0(hardhat@2.18.1)(lodash@4.17.21)(typechain@8.2.0): - resolution: {integrity: sha512-Pqk+KdREbU6Uk3en1Z5caQpWt2bKU+KTOi+6dZwcIXJpF1wKoAwF1cbaYSQEzrG4BSUTM1rHQhW5JHSfeqpsAg==} + /@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.18.1)(typechain@8.2.0): + resolution: {integrity: sha512-XB79i5ewg9Met7gMVGfgVkmypicbnI25T5clJBEooMoW2161p4zvKFpoS2O+lBppQyMrPIZkdvl2M3LMDayVcA==} peerDependencies: - hardhat: ^2.0.10 - lodash: ^4.17.15 - typechain: ^7.0.0 + '@ethersproject/abi': ^5.4.7 + '@ethersproject/providers': ^5.4.7 + '@typechain/ethers-v5': ^11.0.0 + ethers: ^5.4.7 + hardhat: ^2.9.9 + typechain: ^8.2.0 dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/providers': 5.7.2 + '@typechain/ethers-v5': 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.2.2) + ethers: 5.7.2 fs-extra: 9.1.0 hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) - lodash: 4.17.21 typechain: 8.2.0(typescript@5.2.2) dev: true @@ -3487,6 +3496,13 @@ packages: nofilter: 1.0.4 dev: true + /cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + dependencies: + nofilter: 3.1.0 + dev: true + /cbor@9.0.1: resolution: {integrity: sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==} engines: {node: '>=16'} @@ -4324,6 +4340,17 @@ packages: engines: {node: '>=0.4.0'} dev: true + /delete-empty@3.0.0: + resolution: {integrity: sha512-ZUyiwo76W+DYnKsL3Kim6M/UOavPdBJgDYWOmuQhYaZvJH0AXAHbUNyEDtRbBra8wqqr686+63/0azfEk1ebUQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + ansi-colors: 4.1.3 + minimist: 1.2.8 + path-starts-with: 2.0.1 + rimraf: 2.7.1 + dev: true + /depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} @@ -6273,23 +6300,26 @@ packages: har-schema: 2.0.0 dev: true - /hardhat-abi-exporter@2.2.1(hardhat@2.18.1): - resolution: {integrity: sha512-Um7+RPvJEj+OqWjPoPKlTTkO1Akr10pqpgMk8Pw2jz2wrGv5XQBGNW5aQgGVDUosYktUIWDaEhcwwFKbFsir9A==} - engines: {node: '>=12.10.0'} + /hardhat-abi-exporter@2.10.1(hardhat@2.18.1): + resolution: {integrity: sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==} + engines: {node: '>=14.14.0'} peerDependencies: hardhat: ^2.0.0 dependencies: + '@ethersproject/abi': 5.7.0 + delete-empty: 3.0.0 hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) dev: true - /hardhat-contract-sizer@2.5.1(hardhat@2.18.1): - resolution: {integrity: sha512-28yRb73e30aBVaZOOHTlHZFIdIasA/iFunIehrUviIJTubvdQjtSiQUo2wexHFtt71mQeMPP8qjw2sdbgatDnQ==} + /hardhat-contract-sizer@2.10.0(hardhat@2.18.1): + resolution: {integrity: sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==} peerDependencies: hardhat: ^2.0.0 dependencies: chalk: 4.1.2 cli-table3: 0.6.3 hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + strip-ansi: 6.0.1 dev: true /hardhat-gas-reporter@1.0.9(hardhat@2.18.1): @@ -8916,6 +8946,11 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /path-starts-with@2.0.1: + resolution: {integrity: sha512-wZ3AeiRBRlNwkdUxvBANh0+esnt38DLffHDujZyRHkqkaKHTglnY2EP5UX3b8rdeiSutgO4y9NEJwXezNP5vHg==} + engines: {node: '>=8'} + dev: true + /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} requiresBuild: true @@ -10730,17 +10765,6 @@ packages: wordwrapjs: 4.0.1 dev: true - /table@6.8.0: - resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==} - engines: {node: '>=10.0.0'} - dependencies: - ajv: 8.11.0 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - /table@6.8.1: resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} engines: {node: '>=10.0.0'} @@ -11244,11 +11268,6 @@ packages: dev: true optional: true - /undici@5.10.0: - resolution: {integrity: sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==} - engines: {node: '>=12.18'} - dev: true - /undici@5.19.1: resolution: {integrity: sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==} engines: {node: '>=12.18'} From 8dd240f7f69804c5103dbdfc8d5008d86139868b Mon Sep 17 00:00:00 2001 From: Cedric Date: Wed, 25 Oct 2023 12:52:03 +0100 Subject: [PATCH 005/327] [BCF-2725] Add the repository name to the flakey test runner output (#11078) * [BCF-2725] Surface the repo in flakeytestrunner * Use back-quoted strings --- .github/workflows/ci-core.yml | 4 ++++ tools/flakeytests/cmd/runner/main.go | 4 +++- tools/flakeytests/reporter.go | 4 +++- tools/flakeytests/reporter_test.go | 14 +++++++------- tools/flakeytests/utils.go | 24 ++++++++++++++---------- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index d6991bb4e6..74ca1dae9a 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -156,12 +156,16 @@ jobs: GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} GITHUB_EVENT_PATH: ${{ github.event_path }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + GITHUB_REPO: ${{ github.repository }} run: | ./runner \ -grafana_auth=$GRAFANA_CLOUD_BASIC_AUTH \ -grafana_host=$GRAFANA_CLOUD_HOST \ -gh_sha=$GITHUB_SHA \ -gh_event_path=$GITHUB_EVENT_PATH \ + -gh_event_name=$GITHUB_EVENT_NAME \ + -gh_repo=$GITHUB_REPO \ -command=./tools/bin/go_core_tests \ `ls -R ./artifacts/go_core_tests*/output.txt` - name: Store logs artifacts diff --git a/tools/flakeytests/cmd/runner/main.go b/tools/flakeytests/cmd/runner/main.go index aea69a134b..601832a837 100644 --- a/tools/flakeytests/cmd/runner/main.go +++ b/tools/flakeytests/cmd/runner/main.go @@ -18,6 +18,8 @@ func main() { command := flag.String("command", "", "test command being rerun; used to tag metrics") ghSHA := flag.String("gh_sha", "", "commit sha for which we're rerunning tests") ghEventPath := flag.String("gh_event_path", "", "path to associated gh event") + ghEventName := flag.String("gh_event_name", "", "type of associated gh event") + ghRepo := flag.String("gh_repo", "", "name of gh repository") flag.Parse() if *grafanaHost == "" { @@ -45,7 +47,7 @@ func main() { readers = append(readers, r) } - ctx := flakeytests.GetGithubMetadata(*ghSHA, *ghEventPath) + ctx := flakeytests.GetGithubMetadata(*ghRepo, *ghEventName, *ghSHA, *ghEventPath) rep := flakeytests.NewLokiReporter(*grafanaHost, *grafanaAuth, *command, ctx) r := flakeytests.NewRunner(readers, rep, numReruns) err := r.Run() diff --git a/tools/flakeytests/reporter.go b/tools/flakeytests/reporter.go index beecd8b3e4..db3890b5c7 100644 --- a/tools/flakeytests/reporter.go +++ b/tools/flakeytests/reporter.go @@ -33,8 +33,10 @@ type numFlakes struct { } type Context struct { - CommitSHA string `json:"commit_sha,omitempty"` + CommitSHA string `json:"commit_sha"` PullRequestURL string `json:"pull_request_url,omitempty"` + Repository string `json:"repository"` + Type string `json:"event_type"` } type LokiReporter struct { diff --git a/tools/flakeytests/reporter_test.go b/tools/flakeytests/reporter_test.go index f63b89273c..9cb2c8e9f7 100644 --- a/tools/flakeytests/reporter_test.go +++ b/tools/flakeytests/reporter_test.go @@ -23,8 +23,8 @@ func TestMakeRequest_SingleTest(t *testing.T) { assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, "{\"package\":\"core/assets\",\"test_name\":\"TestLink\",\"fq_test_name\":\"core/assets:TestLink\"}"}, - {ts, "{\"num_flakes\":1}"}, + {ts, `{"package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink","commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"num_flakes":1,"commit_sha":"","repository":"","event_type":""}`}, }) } @@ -44,9 +44,9 @@ func TestMakeRequest_MultipleTests(t *testing.T) { assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, "{\"package\":\"core/assets\",\"test_name\":\"TestLink\",\"fq_test_name\":\"core/assets:TestLink\"}"}, - {ts, "{\"package\":\"core/assets\",\"test_name\":\"TestCore\",\"fq_test_name\":\"core/assets:TestCore\"}"}, - {ts, "{\"num_flakes\":2}"}, + {ts, `{"package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink","commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"package":"core/assets","test_name":"TestCore","fq_test_name":"core/assets:TestCore","commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"num_flakes":2,"commit_sha":"","repository":"","event_type":""}`}, }) } @@ -60,7 +60,7 @@ func TestMakeRequest_NoTests(t *testing.T) { assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, "{\"num_flakes\":0}"}, + {ts, `{"num_flakes":0,"commit_sha":"","repository":"","event_type":""}`}, }) } @@ -74,6 +74,6 @@ func TestMakeRequest_WithContext(t *testing.T) { assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, "{\"num_flakes\":0,\"commit_sha\":\"42\"}"}, + {ts, `{"num_flakes":0,"commit_sha":"42","repository":"","event_type":""}`}, }) } diff --git a/tools/flakeytests/utils.go b/tools/flakeytests/utils.go index 0b95193b2b..18ab43980b 100644 --- a/tools/flakeytests/utils.go +++ b/tools/flakeytests/utils.go @@ -29,7 +29,7 @@ func DigString(mp map[string]interface{}, path []string) (string, error) { return vs, nil } -func GetGithubMetadata(sha string, path string) Context { +func GetGithubMetadata(repo string, eventName string, sha string, path string) Context { event := map[string]interface{}{} if path != "" { r, err := os.Open(path) @@ -48,14 +48,18 @@ func GetGithubMetadata(sha string, path string) Context { } } - prURL := "" - url, err := DigString(event, []string{"pull_request", "_links", "html", "href"}) - if err == nil { - prURL = url - } - ctx := Context{ - CommitSHA: sha, - PullRequestURL: prURL, + basicCtx := &Context{Repository: repo, CommitSHA: sha, Type: eventName} + switch eventName { + case "pull_request": + prURL := "" + url, err := DigString(event, []string{"pull_request", "_links", "html", "href"}) + if err == nil { + prURL = url + } + + basicCtx.PullRequestURL = prURL + return *basicCtx + default: + return *basicCtx } - return ctx } From d8463be40baaf4f75113c51d883b355c8541accf Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 25 Oct 2023 08:07:31 -0500 Subject: [PATCH 006/327] core/internal/testutils/configtest: consolidate v2 and toml packages in to configtest (#11081) --- core/bridges/orm_test.go | 5 +- core/chains/evm/chain_test.go | 5 +- core/chains/evm/config/config_test.go | 2 +- .../evm/forwarders/forwarder_manager_test.go | 2 +- .../evm/headtracker/head_broadcaster_test.go | 2 +- .../evm/headtracker/head_listener_test.go | 2 +- .../chains/evm/headtracker/head_saver_test.go | 2 +- .../evm/headtracker/head_tracker_test.go | 2 +- core/chains/evm/headtracker/orm_test.go | 2 +- core/chains/evm/log/helpers_test.go | 2 +- core/chains/evm/log/orm_test.go | 2 +- core/chains/evm/monitor/balance_test.go | 2 +- core/chains/evm/txmgr/attempts_test.go | 2 +- core/chains/evm/txmgr/broadcaster_test.go | 2 +- core/chains/evm/txmgr/confirmer_test.go | 2 +- core/chains/evm/txmgr/evm_tx_store_test.go | 2 +- core/chains/evm/txmgr/nonce_syncer_test.go | 2 +- core/chains/evm/txmgr/reaper_test.go | 2 +- core/chains/evm/txmgr/resender_test.go | 2 +- core/chains/evm/txmgr/strategies_test.go | 2 +- core/chains/evm/txmgr/txmgr_test.go | 2 +- core/chains/evm/types/models_test.go | 2 +- core/cmd/app_test.go | 26 ++-- core/cmd/p2p_keys_commands_test.go | 3 +- core/cmd/shell_local_test.go | 2 +- core/cmd/shell_remote_test.go | 4 +- core/cmd/shell_test.go | 2 +- core/internal/cltest/cltest.go | 11 +- core/internal/cltest/factories.go | 2 +- core/internal/cltest/heavyweight/orm.go | 9 +- core/internal/cltest/job_factories.go | 5 +- core/internal/features/features_test.go | 10 +- .../testutils/configtest/general_config.go | 122 +++++++++++++++++- .../configtest/{v2/toml => }/toml.go | 2 +- .../testutils/configtest/v2/general_config.go | 120 ----------------- core/internal/testutils/evmtest/v2/evmtest.go | 2 +- core/services/blockhashstore/bhs_test.go | 2 +- core/services/blockhashstore/delegate_test.go | 2 +- .../relayer_chain_interoperators_test.go | 2 +- core/services/cron/cron_test.go | 2 +- core/services/directrequest/delegate_test.go | 2 +- core/services/feeds/orm_test.go | 2 +- core/services/feeds/service_test.go | 2 +- .../fluxmonitorv2/flux_monitor_test.go | 2 +- core/services/fluxmonitorv2/orm_test.go | 2 +- core/services/functions/listener_test.go | 2 +- core/services/job/job_orm_test.go | 2 +- .../job/job_pipeline_orm_integration_test.go | 9 +- core/services/job/orm_test.go | 5 +- core/services/job/runner_integration_test.go | 39 +++--- core/services/job/spawner_test.go | 6 +- core/services/keeper/orm_test.go | 5 +- .../keeper/registry1_1_synchronizer_test.go | 2 +- .../keeper/registry1_2_synchronizer_test.go | 2 +- .../keeper/registry1_3_synchronizer_test.go | 2 +- .../registry_synchronizer_helper_test.go | 2 +- core/services/keeper/upkeep_executer_test.go | 5 +- core/services/keystore/cosmos_test.go | 2 +- core/services/keystore/csa_test.go | 2 +- core/services/keystore/dkgencrypt_test.go | 2 +- core/services/keystore/dkgsign_test.go | 2 +- core/services/keystore/eth_test.go | 2 +- core/services/keystore/master_test.go | 2 +- core/services/keystore/ocr2_test.go | 2 +- core/services/keystore/ocr_test.go | 2 +- core/services/keystore/p2p_test.go | 2 +- core/services/keystore/solana_test.go | 2 +- core/services/keystore/starknet_test.go | 2 +- core/services/keystore/vrf_test.go | 2 +- core/services/ocr/contract_tracker_test.go | 2 +- core/services/ocr/database_test.go | 7 +- core/services/ocr/validate_test.go | 4 +- core/services/ocr2/database_test.go | 7 +- core/services/ocr2/delegate_test.go | 2 +- .../ocr2/plugins/dkg/config/config_test.go | 2 +- core/services/ocr2/validate/validate_test.go | 4 +- core/services/ocrcommon/peer_wrapper_test.go | 4 +- core/services/ocrcommon/peerstore_test.go | 6 +- .../ocrcommon/transmitter_pipeline_test.go | 2 +- core/services/ocrcommon/transmitter_test.go | 2 +- core/services/pg/locked_db_test.go | 2 +- core/services/pipeline/common_test.go | 4 +- core/services/pipeline/orm_test.go | 11 +- core/services/pipeline/runner_test.go | 2 +- core/services/pipeline/task.bridge_test.go | 9 +- core/services/pipeline/task.eth_call_test.go | 2 +- core/services/pipeline/task.eth_tx_test.go | 2 +- core/services/pipeline/task.http_test.go | 2 +- .../promreporter/prom_reporter_test.go | 2 +- core/services/relay/evm/evm_test.go | 5 +- .../relay/evm/relayer_extender_test.go | 2 +- .../relay/evm/request_round_tracker_test.go | 7 +- core/services/vrf/delegate_test.go | 2 +- .../services/vrf/proof/proof_response_test.go | 2 +- .../vrf/v2/integration_v2_plus_test.go | 2 +- core/services/vrf/v2/integration_v2_test.go | 2 +- core/store/migrate/migrate_test.go | 2 +- core/web/cors_test.go | 2 +- core/web/cosmos_chains_controller_test.go | 2 +- core/web/eth_keys_controller_test.go | 2 +- core/web/evm_chains_controller_test.go | 2 +- core/web/evm_forwarders_controller_test.go | 2 +- core/web/evm_transfer_controller_test.go | 6 +- .../external_initiators_controller_test.go | 14 +- core/web/features_controller_test.go | 2 +- core/web/gui_assets_test.go | 2 +- core/web/jobs_controller_test.go | 4 +- core/web/log_controller_test.go | 2 +- core/web/loop_registry_test.go | 2 +- core/web/pipeline_runs_controller_test.go | 2 +- core/web/resolver/eth_key_test.go | 2 +- core/web/resolver/features_test.go | 4 +- core/web/solana_chains_controller_test.go | 2 +- 113 files changed, 327 insertions(+), 320 deletions(-) rename core/internal/testutils/configtest/{v2/toml => }/toml.go (95%) delete mode 100644 core/internal/testutils/configtest/v2/general_config.go diff --git a/core/bridges/orm_test.go b/core/bridges/orm_test.go index db04339335..b110b4f519 100644 --- a/core/bridges/orm_test.go +++ b/core/bridges/orm_test.go @@ -5,15 +5,16 @@ import ( "time" "github.com/google/uuid" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/chains/evm/chain_test.go b/core/chains/evm/chain_test.go index 09395ff4c9..ba24598ef7 100644 --- a/core/chains/evm/chain_test.go +++ b/core/chains/evm/chain_test.go @@ -4,12 +4,13 @@ import ( "math/big" "testing" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index 10984d45d1..d0f9e846e3 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/chains/evm/forwarders/forwarder_manager_test.go b/core/chains/evm/forwarders/forwarder_manager_test.go index 0117c2f2c0..082d329e38 100644 --- a/core/chains/evm/forwarders/forwarder_manager_test.go +++ b/core/chains/evm/forwarders/forwarder_manager_test.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index c478920e00..5c2423f328 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -17,7 +17,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go index 63d2223383..dff97f5843 100644 --- a/core/chains/evm/headtracker/head_listener_test.go +++ b/core/chains/evm/headtracker/head_listener_test.go @@ -17,7 +17,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/chains/evm/headtracker/head_saver_test.go b/core/chains/evm/headtracker/head_saver_test.go index 5ab43679f4..5ed85adc59 100644 --- a/core/chains/evm/headtracker/head_saver_test.go +++ b/core/chains/evm/headtracker/head_saver_test.go @@ -10,7 +10,7 @@ import ( httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index d30571f331..502aa4ae6d 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -29,7 +29,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/headtracker/orm_test.go b/core/chains/evm/headtracker/orm_test.go index 5b106ac101..123478ff90 100644 --- a/core/chains/evm/headtracker/orm_test.go +++ b/core/chains/evm/headtracker/orm_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/ethereum/go-ethereum/common" diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index 58e81132b0..688757a3e9 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -31,7 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/log/orm_test.go b/core/chains/evm/log/orm_test.go index 365bb35433..48524896cf 100644 --- a/core/chains/evm/log/orm_test.go +++ b/core/chains/evm/log/orm_test.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index dbb2003b69..c80d64e7ef 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -18,7 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index 099143f0ce..863eae4723 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 6f9308548b..3901da59ee 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -37,7 +37,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 32246b06ce..8fbdb7696d 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -33,7 +33,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index e5b47c457b..ba02f118cf 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -15,7 +15,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/txmgr/nonce_syncer_test.go b/core/chains/evm/txmgr/nonce_syncer_test.go index 13e5fd02e8..f6480b4c30 100644 --- a/core/chains/evm/txmgr/nonce_syncer_test.go +++ b/core/chains/evm/txmgr/nonce_syncer_test.go @@ -7,7 +7,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 830ed1ac17..20cc27a675 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -12,7 +12,7 @@ import ( txmgrmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index d17156f452..cc94511e3b 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/txmgr/strategies_test.go b/core/chains/evm/txmgr/strategies_test.go index 9c5a1be37f..765b43e78f 100644 --- a/core/chains/evm/txmgr/strategies_test.go +++ b/core/chains/evm/txmgr/strategies_test.go @@ -11,7 +11,7 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" ) func Test_SendEveryStrategy(t *testing.T) { diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index de8c6ff4ef..6cb43b2771 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -30,7 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index 683a49692b..2f9dc7dd7c 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -22,7 +22,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/cmd/app_test.go b/core/cmd/app_test.go index 78331bf706..bbb00bff3e 100644 --- a/core/cmd/app_test.go +++ b/core/cmd/app_test.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - testtomlutils "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2/toml" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -88,7 +88,7 @@ func Test_initServerConfig(t *testing.T) { name: "files only", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, }, wantCfg: withDefaults(t, testConfigFileContents, chainlink.Secrets{}), }, @@ -104,7 +104,7 @@ func Test_initServerConfig(t *testing.T) { name: "env overlay of file", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, envVar: testEnvContents, }, wantCfg: withDefaults(t, chainlink.Config{ @@ -124,7 +124,7 @@ func Test_initServerConfig(t *testing.T) { name: "failed to read secrets", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{"/doesnt-exist"}, }, wantErr: true, @@ -133,8 +133,8 @@ func Test_initServerConfig(t *testing.T) { name: "reading secrets", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, - secretsFiles: []string{testtomlutils.WriteTOMLFile(t, testSecretsFileContents, "test_secrets.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + secretsFiles: []string{configtest.WriteTOMLFile(t, testSecretsFileContents, "test_secrets.toml")}, }, wantCfg: withDefaults(t, testConfigFileContents, testSecretsRedactedContents), }, @@ -142,7 +142,7 @@ func Test_initServerConfig(t *testing.T) { name: "reading multiple secrets", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../services/chainlink/testdata/mergingsecretsdata/secrets-database.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-password.toml", @@ -159,7 +159,7 @@ func Test_initServerConfig(t *testing.T) { name: "reading multiple secrets with overrides: Database", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../testdata/mergingsecretsdata/secrets-database.toml", "../testdata/mergingsecretsdata/secrets-database.toml", @@ -171,7 +171,7 @@ func Test_initServerConfig(t *testing.T) { name: "reading multiple secrets with overrides: Password", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../testdata/mergingsecretsdata/secrets-password.toml", "../testdata/mergingsecretsdata/secrets-password.toml", @@ -183,7 +183,7 @@ func Test_initServerConfig(t *testing.T) { name: "reading multiple secrets with overrides: Pyroscope", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../testdata/mergingsecretsdata/secrets-pyroscope.toml", "../testdata/mergingsecretsdata/secrets-pyroscope.toml", @@ -195,7 +195,7 @@ func Test_initServerConfig(t *testing.T) { name: "reading multiple secrets with overrides: Prometheus", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../testdata/mergingsecretsdata/secrets-prometheus.toml", "../testdata/mergingsecretsdata/secrets-prometheus.toml", @@ -207,7 +207,7 @@ func Test_initServerConfig(t *testing.T) { name: "reading multiple secrets with overrides: Mercury", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../testdata/mergingsecretsdata/secrets-mercury-split-one.toml", "../testdata/mergingsecretsdata/secrets-mercury-split-one.toml", @@ -219,7 +219,7 @@ func Test_initServerConfig(t *testing.T) { name: "reading multiple secrets with overrides: Threshold", args: args{ opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, + fileNames: []string{configtest.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../testdata/mergingsecretsdata/secrets-threshold.toml", "../testdata/mergingsecretsdata/secrets-threshold.toml", diff --git a/core/cmd/p2p_keys_commands_test.go b/core/cmd/p2p_keys_commands_test.go index cf107ba507..0407c92457 100644 --- a/core/cmd/p2p_keys_commands_test.go +++ b/core/cmd/p2p_keys_commands_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -24,7 +25,7 @@ func TestP2PKeyPresenter_RenderTable(t *testing.T) { var ( id = "1" - peerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" + peerID = configtest.DefaultPeerID pubKey = "somepubkey" buffer = bytes.NewBufferString("") r = cmd.RendererTable{Writer: buffer} diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index be8d5c9405..d70b06f5a9 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index c1d15df9ec..7f998225f6 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -25,7 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -58,7 +58,7 @@ func startNewApplicationV2(t *testing.T, overrideFn func(c *chainlink.Config, s fn(sopts) } - config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(30 * time.Millisecond) f := false c.EVM[0].Enabled = &f diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index 74768a2192..9b87e8fb1d 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index a9ff8144b3..3fa0090177 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -61,7 +61,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/keystest" @@ -108,7 +107,7 @@ const ( // SessionSecret is the hardcoded secret solely used for test SessionSecret = "clsession_test_secret" // DefaultPeerID is the peer ID of the default p2p key - DefaultPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" + DefaultPeerID = configtest.DefaultPeerID // DefaultOCRKeyBundleID is the ID of the default ocr key bundle DefaultOCRKeyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5" // DefaultOCR2KeyBundleID is the ID of the fixture ocr2 key bundle @@ -240,7 +239,7 @@ func NewWSServer(t *testing.T, chainID *big.Int, callback testutils.JSONRPCHandl func NewApplicationEVMDisabled(t *testing.T) *TestApplication { t.Helper() - c := configtest2.NewGeneralConfig(t, nil) + c := configtest.NewGeneralConfig(t, nil) return NewApplicationWithConfig(t, c) } @@ -250,7 +249,7 @@ func NewApplicationEVMDisabled(t *testing.T) *TestApplication { func NewApplication(t testing.TB, flagsAndDeps ...interface{}) *TestApplication { t.Helper() - c := configtest2.NewGeneralConfig(t, nil) + c := configtest.NewGeneralConfig(t, nil) return NewApplicationWithConfig(t, c, flagsAndDeps...) } @@ -260,7 +259,7 @@ func NewApplication(t testing.TB, flagsAndDeps ...interface{}) *TestApplication func NewApplicationWithKey(t *testing.T, flagsAndDeps ...interface{}) *TestApplication { t.Helper() - config := configtest2.NewGeneralConfig(t, nil) + config := configtest.NewGeneralConfig(t, nil) return NewApplicationWithConfigAndKey(t, config, flagsAndDeps...) } @@ -1617,7 +1616,7 @@ func AssertPipelineTaskRunsErrored(t testing.TB, runs []pipeline.TaskRun) { } func NewTestChainScopedConfig(t testing.TB) evmconfig.ChainScopedConfig { - cfg := configtest2.NewGeneralConfig(t, nil) + cfg := configtest.NewGeneralConfig(t, nil) return evmtest.NewChainScopedConfig(t, cfg) } diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index a1a5d9db6b..85ffc6b02b 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -34,7 +34,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" diff --git a/core/internal/cltest/heavyweight/orm.go b/core/internal/cltest/heavyweight/orm.go index 841901c25a..2f9370f35a 100644 --- a/core/internal/cltest/heavyweight/orm.go +++ b/core/internal/cltest/heavyweight/orm.go @@ -14,13 +14,14 @@ import ( "runtime" "testing" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" @@ -50,7 +51,7 @@ func prepareFullTestDBV2(t testing.TB, name string, empty bool, loadFixtures boo t.Fatal("could not load fixtures into an empty DB") } - gcfg := configtest2.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { + gcfg := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres if overrideFn != nil { overrideFn(c, s) @@ -68,7 +69,7 @@ func prepareFullTestDBV2(t testing.TB, name string, empty bool, loadFixtures boo os.RemoveAll(gcfg.RootDir()) }) - gcfg = configtest2.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { + gcfg = configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres s.Database.URL = models.MustSecretURL(migrationTestDBURL) if overrideFn != nil { diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index 910ffe79e3..77fee125e2 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -5,11 +5,12 @@ import ( "testing" "github.com/google/uuid" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/bridges" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index c5d16590d5..058c8325b9 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -56,7 +56,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -83,7 +83,7 @@ func TestIntegration_ExternalInitiatorV2(t *testing.T) { ethClient := cltest.NewEthMocksWithStartupAssertions(t) - cfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) }) @@ -362,7 +362,7 @@ func TestIntegration_DirectRequest(t *testing.T) { t.Run(test.name, func(t *testing.T) { // Simulate a consumer contract calling to obtain ETH quotes in 3 different currencies // in a single callback. - config := configtest2.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { + config := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) }) @@ -467,7 +467,7 @@ func setupAppForEthTx(t *testing.T, operatorContracts OperatorContracts) (app *c b := operatorContracts.sim lggr, o := logger.TestLoggerObserved(t, zapcore.DebugLevel) - cfg := configtest2.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) }) app = cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, b, lggr) @@ -1320,7 +1320,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { var initialDefaultGasPrice int64 = 5_000_000_000 maxGasPrice := assets.NewWeiI(10 * initialDefaultGasPrice) - cfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].BalanceMonitor.Enabled = ptr(false) c.EVM[0].GasEstimator.BlockHistory.CheckInclusionBlocks = ptr[uint16](0) c.EVM[0].GasEstimator.PriceDefault = assets.NewWeiI(initialDefaultGasPrice) diff --git a/core/internal/testutils/configtest/general_config.go b/core/internal/testutils/configtest/general_config.go index 1b652eeecd..93d388b2d3 100644 --- a/core/internal/testutils/configtest/general_config.go +++ b/core/internal/testutils/configtest/general_config.go @@ -1,6 +1,122 @@ package configtest -// TODO move? -const ( - DefaultPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" +import ( + "net" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/store/dialects" + "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) + +const DefaultPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" + +// NewTestGeneralConfig returns a new chainlink.GeneralConfig with default test overrides and one chain with evmclient.NullClientChainID. +func NewTestGeneralConfig(t testing.TB) chainlink.GeneralConfig { return NewGeneralConfig(t, nil) } + +// NewGeneralConfig returns a new chainlink.GeneralConfig with overrides. +// The default test overrides are applied before overrideFn, and include one chain with evmclient.NullClientChainID. +func NewGeneralConfig(t testing.TB, overrideFn func(*chainlink.Config, *chainlink.Secrets)) chainlink.GeneralConfig { + tempDir := t.TempDir() + g, err := chainlink.GeneralConfigOpts{ + OverrideFn: func(c *chainlink.Config, s *chainlink.Secrets) { + overrides(c, s) + c.RootDir = &tempDir + if fn := overrideFn; fn != nil { + fn(c, s) + } + }, + }.New() + require.NoError(t, err) + return g +} + +// overrides applies some test config settings and adds a default chain with evmclient.NullClientChainID. +func overrides(c *chainlink.Config, s *chainlink.Secrets) { + s.Password.Keystore = models.NewSecret("dummy-to-pass-validation") + + c.Insecure.OCRDevelopmentMode = ptr(true) + c.InsecureFastScrypt = ptr(true) + c.ShutdownGracePeriod = models.MustNewDuration(testutils.DefaultWaitTimeout) + + c.Database.Dialect = dialects.TransactionWrappedPostgres + c.Database.Lock.Enabled = ptr(false) + c.Database.MaxIdleConns = ptr[int64](20) + c.Database.MaxOpenConns = ptr[int64](20) + c.Database.MigrateOnStartup = ptr(false) + c.Database.DefaultLockTimeout = models.MustNewDuration(1 * time.Minute) + + c.JobPipeline.ReaperInterval = models.MustNewDuration(0) + + c.P2P.V1.Enabled = ptr(false) + c.P2P.V2.Enabled = ptr(false) + + c.WebServer.SessionTimeout = models.MustNewDuration(2 * time.Minute) + c.WebServer.BridgeResponseURL = models.MustParseURL("http://localhost:6688") + testIP := net.ParseIP("127.0.0.1") + c.WebServer.ListenIP = &testIP + c.WebServer.TLS.ListenIP = &testIP + + chainID := utils.NewBigI(evmclient.NullClientChainID) + c.EVM = append(c.EVM, &evmcfg.EVMConfig{ + ChainID: chainID, + Chain: evmcfg.Defaults(chainID), + Nodes: evmcfg.EVMNodes{ + &evmcfg.Node{ + Name: ptr("test"), + WSURL: &models.URL{}, + HTTPURL: &models.URL{}, + SendOnly: new(bool), + Order: ptr[int32](100), + }, + }, + }) +} + +// NewGeneralConfigSimulated returns a new chainlink.GeneralConfig with overrides, including the simulated EVM chain. +// The default test overrides are applied before overrideFn. +// The simulated chain (testutils.SimulatedChainID) replaces the null chain (evmclient.NullClientChainID). +func NewGeneralConfigSimulated(t testing.TB, overrideFn func(*chainlink.Config, *chainlink.Secrets)) chainlink.GeneralConfig { + return NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + simulated(c, s) + if fn := overrideFn; fn != nil { + fn(c, s) + } + }) +} + +// simulated is a config override func that appends the simulated EVM chain (testutils.SimulatedChainID), +// or replaces the null chain (client.NullClientChainID) if that is the only entry. +func simulated(c *chainlink.Config, s *chainlink.Secrets) { + chainID := utils.NewBig(testutils.SimulatedChainID) + enabled := true + cfg := evmcfg.EVMConfig{ + ChainID: chainID, + Chain: evmcfg.Defaults(chainID), + Enabled: &enabled, + Nodes: evmcfg.EVMNodes{&validTestNode}, + } + if len(c.EVM) == 1 && c.EVM[0].ChainID.Cmp(utils.NewBigI(client.NullClientChainID)) == 0 { + c.EVM[0] = &cfg // replace null, if only entry + } else { + c.EVM = append(c.EVM, &cfg) + } +} + +var validTestNode = evmcfg.Node{ + Name: ptr("simulated-node"), + WSURL: models.MustParseURL("WSS://simulated-wss.com/ws"), + HTTPURL: models.MustParseURL("http://simulated.com"), + SendOnly: nil, + Order: ptr(int32(1)), +} + +func ptr[T any](v T) *T { return &v } diff --git a/core/internal/testutils/configtest/v2/toml/toml.go b/core/internal/testutils/configtest/toml.go similarity index 95% rename from core/internal/testutils/configtest/v2/toml/toml.go rename to core/internal/testutils/configtest/toml.go index 0cb89010f2..78db05f9c3 100644 --- a/core/internal/testutils/configtest/v2/toml/toml.go +++ b/core/internal/testutils/configtest/toml.go @@ -1,4 +1,4 @@ -package testtomlutils +package configtest import ( "os" diff --git a/core/internal/testutils/configtest/v2/general_config.go b/core/internal/testutils/configtest/v2/general_config.go deleted file mode 100644 index febbb367bd..0000000000 --- a/core/internal/testutils/configtest/v2/general_config.go +++ /dev/null @@ -1,120 +0,0 @@ -package v2 - -import ( - "net" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/dialects" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -// NewTestGeneralConfig returns a new chainlink.GeneralConfig with default test overrides and one chain with evmclient.NullClientChainID. -func NewTestGeneralConfig(t testing.TB) chainlink.GeneralConfig { return NewGeneralConfig(t, nil) } - -// NewGeneralConfig returns a new chainlink.GeneralConfig with overrides. -// The default test overrides are applied before overrideFn, and include one chain with evmclient.NullClientChainID. -func NewGeneralConfig(t testing.TB, overrideFn func(*chainlink.Config, *chainlink.Secrets)) chainlink.GeneralConfig { - tempDir := t.TempDir() - g, err := chainlink.GeneralConfigOpts{ - OverrideFn: func(c *chainlink.Config, s *chainlink.Secrets) { - overrides(c, s) - c.RootDir = &tempDir - if fn := overrideFn; fn != nil { - fn(c, s) - } - }, - }.New() - require.NoError(t, err) - return g -} - -// overrides applies some test config settings and adds a default chain with evmclient.NullClientChainID. -func overrides(c *chainlink.Config, s *chainlink.Secrets) { - s.Password.Keystore = models.NewSecret("dummy-to-pass-validation") - - c.Insecure.OCRDevelopmentMode = ptr(true) - c.InsecureFastScrypt = ptr(true) - c.ShutdownGracePeriod = models.MustNewDuration(testutils.DefaultWaitTimeout) - - c.Database.Dialect = dialects.TransactionWrappedPostgres - c.Database.Lock.Enabled = ptr(false) - c.Database.MaxIdleConns = ptr[int64](20) - c.Database.MaxOpenConns = ptr[int64](20) - c.Database.MigrateOnStartup = ptr(false) - c.Database.DefaultLockTimeout = models.MustNewDuration(1 * time.Minute) - - c.JobPipeline.ReaperInterval = models.MustNewDuration(0) - - c.P2P.V1.Enabled = ptr(false) - c.P2P.V2.Enabled = ptr(false) - - c.WebServer.SessionTimeout = models.MustNewDuration(2 * time.Minute) - c.WebServer.BridgeResponseURL = models.MustParseURL("http://localhost:6688") - testIP := net.ParseIP("127.0.0.1") - c.WebServer.ListenIP = &testIP - c.WebServer.TLS.ListenIP = &testIP - - chainID := utils.NewBigI(evmclient.NullClientChainID) - c.EVM = append(c.EVM, &evmcfg.EVMConfig{ - ChainID: chainID, - Chain: evmcfg.Defaults(chainID), - Nodes: evmcfg.EVMNodes{ - &evmcfg.Node{ - Name: ptr("test"), - WSURL: &models.URL{}, - HTTPURL: &models.URL{}, - SendOnly: new(bool), - Order: ptr[int32](100), - }, - }, - }) -} - -// NewGeneralConfigSimulated returns a new chainlink.GeneralConfig with overrides, including the simulated EVM chain. -// The default test overrides are applied before overrideFn. -// The simulated chain (testutils.SimulatedChainID) replaces the null chain (evmclient.NullClientChainID). -func NewGeneralConfigSimulated(t testing.TB, overrideFn func(*chainlink.Config, *chainlink.Secrets)) chainlink.GeneralConfig { - return NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - simulated(c, s) - if fn := overrideFn; fn != nil { - fn(c, s) - } - }) -} - -// simulated is a config override func that appends the simulated EVM chain (testutils.SimulatedChainID), -// or replaces the null chain (client.NullClientChainID) if that is the only entry. -func simulated(c *chainlink.Config, s *chainlink.Secrets) { - chainID := utils.NewBig(testutils.SimulatedChainID) - enabled := true - cfg := evmcfg.EVMConfig{ - ChainID: chainID, - Chain: evmcfg.Defaults(chainID), - Enabled: &enabled, - Nodes: evmcfg.EVMNodes{&validTestNode}, - } - if len(c.EVM) == 1 && c.EVM[0].ChainID.Cmp(utils.NewBigI(client.NullClientChainID)) == 0 { - c.EVM[0] = &cfg // replace null, if only entry - } else { - c.EVM = append(c.EVM, &cfg) - } -} - -var validTestNode = evmcfg.Node{ - Name: ptr("simulated-node"), - WSURL: models.MustParseURL("WSS://simulated-wss.com/ws"), - HTTPURL: models.MustParseURL("http://simulated.com"), - SendOnly: nil, - Order: ptr(int32(1)), -} - -func ptr[T any](v T) *T { return &v } diff --git a/core/internal/testutils/evmtest/v2/evmtest.go b/core/internal/testutils/evmtest/v2/evmtest.go index 400690480d..fa22588c8f 100644 --- a/core/internal/testutils/evmtest/v2/evmtest.go +++ b/core/internal/testutils/evmtest/v2/evmtest.go @@ -5,7 +5,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index ed32b3ab49..5c501a62ac 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -12,7 +12,7 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 582492105e..089e9544af 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -15,7 +15,7 @@ import ( mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 5b17e2e423..b7291e7dc7 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -29,7 +29,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/plugins" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/cron/cron_test.go b/core/services/cron/cron_test.go index 174f80586a..19a51a3065 100644 --- a/core/services/cron/cron_test.go +++ b/core/services/cron/cron_test.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index ffd78443cc..e58dbaeb50 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -20,7 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index fab9d39a26..746956bbfc 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 744c5d1470..c94a75b3dd 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index 83ffee8ac5..0d1eb085a8 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -32,7 +32,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" corenull "github.com/smartcontractkit/chainlink/v2/core/null" diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index 3bebc150c8..0bb0803261 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -16,7 +16,7 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 6f0badd6e1..007a2a9168 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -21,7 +21,7 @@ import ( log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 20f569a893..74416e68dc 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -23,7 +23,7 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index a5d3ee984d..1158fc4626 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -4,14 +4,15 @@ import ( "testing" "time" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -44,7 +45,7 @@ func TestPipelineORM_Integration(t *testing.T) { answer2 [type=bridge name=election_winner index=1]; ` - config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(30 * time.Millisecond) }) db := pgtest.NewSqlxDB(t) @@ -147,7 +148,7 @@ func TestPipelineORM_Integration(t *testing.T) { t.Run("creates runs", func(t *testing.T) { lggr := logger.TestLogger(t) - cfg := configtest2.NewTestGeneralConfig(t) + cfg := configtest.NewTestGeneralConfig(t) clearJobsDb(t, db) orm := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, logger.TestLogger(t), cfg.Database()) diff --git a/core/services/job/orm_test.go b/core/services/job/orm_test.go index 15a2432f9e..a6986d7fb3 100644 --- a/core/services/job/orm_test.go +++ b/core/services/job/orm_test.go @@ -3,13 +3,14 @@ package job_test import ( "testing" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" clnull "github.com/smartcontractkit/chainlink/v2/core/null" diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 05782f95ce..c0fff1e560 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -13,39 +13,38 @@ import ( "testing" "time" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/google/uuid" + "github.com/pelletier/go-toml" + "github.com/pkg/errors" + "github.com/shopspring/decimal" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" - - "github.com/google/uuid" - "github.com/pelletier/go-toml" - "github.com/pkg/errors" - "github.com/shopspring/decimal" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" ) var monitoringEndpoint = telemetry.MonitoringEndpointGenerator(&telemetry.NoopAgent{}) @@ -58,7 +57,7 @@ func TestRunner(t *testing.T) { _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V1.Enabled = ptr(true) c.P2P.V1.DefaultBootstrapPeers = &[]string{ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", @@ -759,7 +758,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { ethClient := cltest.NewEthMocksWithStartupAssertions(t) - cfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { t := true c.JobPipeline.ExternalInitiatorsEnabled = &t c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) @@ -941,7 +940,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { ethClient := cltest.NewEthMocksWithStartupAssertions(t) - cfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { t := true c.JobPipeline.ExternalInitiatorsEnabled = &t c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 4e28dcdf06..be4a480a6c 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -18,7 +18,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -73,7 +73,7 @@ func (g *relayGetter) Get(id relay.ID) (loop.Relayer, error) { func TestSpawner_CreateJobDeleteJob(t *testing.T) { t.Parallel() - config := configtest2.NewTestGeneralConfig(t) + config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, config.Database()) ethKeyStore := keyStore.Eth() @@ -264,7 +264,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { }) t.Run("Unregisters filters on 'DeleteJob()'", func(t *testing.T) { - config = configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + config = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = func(b bool) *bool { return &b }(true) }) lp := &mocklp.LogPoller{} diff --git a/core/services/keeper/orm_test.go b/core/services/keeper/orm_test.go index 972437eda1..d990effa10 100644 --- a/core/services/keeper/orm_test.go +++ b/core/services/keeper/orm_test.go @@ -9,13 +9,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/keeper/registry1_1_synchronizer_test.go b/core/services/keeper/registry1_1_synchronizer_test.go index 8444aa50dd..031b7a5907 100644 --- a/core/services/keeper/registry1_1_synchronizer_test.go +++ b/core/services/keeper/registry1_1_synchronizer_test.go @@ -18,7 +18,7 @@ import ( registry1_1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/keeper/registry1_2_synchronizer_test.go b/core/services/keeper/registry1_2_synchronizer_test.go index f593a638f9..e7d8d6a48a 100644 --- a/core/services/keeper/registry1_2_synchronizer_test.go +++ b/core/services/keeper/registry1_2_synchronizer_test.go @@ -18,7 +18,7 @@ import ( registry1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/keeper/registry1_3_synchronizer_test.go b/core/services/keeper/registry1_3_synchronizer_test.go index 53b5cbf983..a0522fd717 100644 --- a/core/services/keeper/registry1_3_synchronizer_test.go +++ b/core/services/keeper/registry1_3_synchronizer_test.go @@ -14,7 +14,7 @@ import ( evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/utils" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index 99fb54eba4..63dc634353 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 39f85aedcd..7f9698435f 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -9,11 +9,12 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -24,7 +25,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/keystore/cosmos_test.go b/core/services/keystore/cosmos_test.go index ada7c25a2c..3c33f16282 100644 --- a/core/services/keystore/cosmos_test.go +++ b/core/services/keystore/cosmos_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" diff --git a/core/services/keystore/csa_test.go b/core/services/keystore/csa_test.go index ef2dd1f689..b6dfb00959 100644 --- a/core/services/keystore/csa_test.go +++ b/core/services/keystore/csa_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" diff --git a/core/services/keystore/dkgencrypt_test.go b/core/services/keystore/dkgencrypt_test.go index 1edbc2120f..36f48f9c2b 100644 --- a/core/services/keystore/dkgencrypt_test.go +++ b/core/services/keystore/dkgencrypt_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" diff --git a/core/services/keystore/dkgsign_test.go b/core/services/keystore/dkgsign_test.go index d699800b50..5ea23a516b 100644 --- a/core/services/keystore/dkgsign_test.go +++ b/core/services/keystore/dkgsign_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 0fec509a32..4165350300 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -16,7 +16,7 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/services/keystore/master_test.go b/core/services/keystore/master_test.go index 7a280cc675..73f636c662 100644 --- a/core/services/keystore/master_test.go +++ b/core/services/keystore/master_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) diff --git a/core/services/keystore/ocr2_test.go b/core/services/keystore/ocr2_test.go index b4feb33b5f..9223538a76 100644 --- a/core/services/keystore/ocr2_test.go +++ b/core/services/keystore/ocr2_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" diff --git a/core/services/keystore/ocr_test.go b/core/services/keystore/ocr_test.go index 5698352ec3..200d62415e 100644 --- a/core/services/keystore/ocr_test.go +++ b/core/services/keystore/ocr_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" diff --git a/core/services/keystore/p2p_test.go b/core/services/keystore/p2p_test.go index 63654786fd..89cab3e162 100644 --- a/core/services/keystore/p2p_test.go +++ b/core/services/keystore/p2p_test.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" diff --git a/core/services/keystore/solana_test.go b/core/services/keystore/solana_test.go index 8d7d90a9da..6e895a5611 100644 --- a/core/services/keystore/solana_test.go +++ b/core/services/keystore/solana_test.go @@ -8,7 +8,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" diff --git a/core/services/keystore/starknet_test.go b/core/services/keystore/starknet_test.go index 571a809a55..df9516f871 100644 --- a/core/services/keystore/starknet_test.go +++ b/core/services/keystore/starknet_test.go @@ -13,7 +13,7 @@ import ( "github.com/smartcontractkit/caigo" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" diff --git a/core/services/keystore/vrf_test.go b/core/services/keystore/vrf_test.go index f0c6949bbe..7a2e91ffec 100644 --- a/core/services/keystore/vrf_test.go +++ b/core/services/keystore/vrf_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" diff --git a/core/services/ocr/contract_tracker_test.go b/core/services/ocr/contract_tracker_test.go index d8fe45e8b3..5684219cf1 100644 --- a/core/services/ocr/contract_tracker_test.go +++ b/core/services/ocr/contract_tracker_test.go @@ -23,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr/database_test.go b/core/services/ocr/database_test.go index 8b345df859..6a72c27aa6 100644 --- a/core/services/ocr/database_test.go +++ b/core/services/ocr/database_test.go @@ -7,14 +7,15 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/services/ocr/validate_test.go b/core/services/ocr/validate_test.go index 3efd2d8381..0164fd82c5 100644 --- a/core/services/ocr/validate_test.go +++ b/core/services/ocr/validate_test.go @@ -12,7 +12,7 @@ import ( "gopkg.in/guregu/null.v4" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -399,7 +399,7 @@ answer1 [type=median index=0]; for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { - c := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = null.BoolFrom(false).Ptr() if tc.overrides != nil { tc.overrides(c, s) diff --git a/core/services/ocr2/database_test.go b/core/services/ocr2/database_test.go index 18c0ec8519..aabb2b33a7 100644 --- a/core/services/ocr2/database_test.go +++ b/core/services/ocr2/database_test.go @@ -7,14 +7,15 @@ import ( medianconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median/config" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index 3973774c56..daffac3f96 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -13,7 +13,7 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/dkg/config/config_test.go b/core/services/ocr2/plugins/dkg/config/config_test.go index b49a5277d9..fe796a9ad6 100644 --- a/core/services/ocr2/plugins/dkg/config/config_test.go +++ b/core/services/ocr2/plugins/dkg/config/config_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" ) diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index 98a13ebf8a..4685ed745d 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" medianconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median/config" @@ -584,7 +584,7 @@ KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { - c := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = testutils.Ptr(false) // tests run with OCRDevelopmentMode by default. if tc.overrides != nil { tc.overrides(c, s) diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index 45edc64e9d..209bc6b969 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -25,7 +25,7 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) - peerID, err := p2ppeer.Decode("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") + peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) require.NoError(t, err) t.Run("with no p2p keys returns error", func(t *testing.T) { diff --git a/core/services/ocrcommon/peerstore_test.go b/core/services/ocrcommon/peerstore_test.go index ba55e0767a..6e69215356 100644 --- a/core/services/ocrcommon/peerstore_test.go +++ b/core/services/ocrcommon/peerstore_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -21,7 +21,7 @@ import ( func Test_Peerstore_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) - peerID, err := p2ppeer.Decode("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") + peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) require.NoError(t, err) nonExistentP2PPeerID, err := p2ppeer.Decode("12D3KooWAdCzaesXyezatDzgGvCngqsBqoUqnV9PnVc46jsVt2i9") @@ -72,7 +72,7 @@ func Test_Peerstore_Start(t *testing.T) { func Test_Peerstore_WriteToDB(t *testing.T) { db := pgtest.NewSqlxDB(t) - peerID, err := p2ppeer.Decode("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") + peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) require.NoError(t, err) cfg := configtest.NewTestGeneralConfig(t) diff --git a/core/services/ocrcommon/transmitter_pipeline_test.go b/core/services/ocrcommon/transmitter_pipeline_test.go index 8a1f2f2a92..e0114d0aa0 100644 --- a/core/services/ocrcommon/transmitter_pipeline_test.go +++ b/core/services/ocrcommon/transmitter_pipeline_test.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/services/ocrcommon/transmitter_test.go b/core/services/ocrcommon/transmitter_test.go index ac5d120eb0..d954da869b 100644 --- a/core/services/ocrcommon/transmitter_test.go +++ b/core/services/ocrcommon/transmitter_test.go @@ -13,7 +13,7 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" ) diff --git a/core/services/pg/locked_db_test.go b/core/services/pg/locked_db_test.go index aaf7ebf32c..a2aebcd57f 100644 --- a/core/services/pg/locked_db_test.go +++ b/core/services/pg/locked_db_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/pipeline/common_test.go b/core/services/pipeline/common_test.go index 37cc60f27e..7da80d3af4 100644 --- a/core/services/pipeline/common_test.go +++ b/core/services/pipeline/common_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -323,7 +323,7 @@ func TestTaskRunResult_IsPending(t *testing.T) { func TestSelectGasLimit(t *testing.T) { t.Parallel() - gcfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(999)) c.EVM[0].GasEstimator.LimitJobType = toml.GasLimitJobType{ DR: ptr(uint32(100)), diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index 4c03ce16ef..a487c231fb 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -5,17 +5,18 @@ import ( "time" "github.com/google/uuid" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -514,7 +515,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { // The test configures single Keeper job with two running tasks. // GetUnfinishedRuns() expects to catch both running tasks. - config := configtest2.NewTestGeneralConfig(t) + config := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, config.Database()) @@ -616,7 +617,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { // The test configures single DR job with two task runs: one is running and one is suspended. // GetUnfinishedRuns() expects to catch the one that is running. - config := configtest2.NewTestGeneralConfig(t) + config := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, config.Database()) @@ -709,7 +710,7 @@ func Test_Prune(t *testing.T) { n := uint64(2) - cfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.MaxSuccessfulRuns = &n }) lggr, observed := logger.TestLoggerObserved(t, zapcore.DebugLevel) diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index 22b70829ba..3abcdbe0ab 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -26,7 +26,7 @@ import ( bridgesMocks "github.com/smartcontractkit/chainlink/v2/core/bridges/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" diff --git a/core/services/pipeline/task.bridge_test.go b/core/services/pipeline/task.bridge_test.go index 6f542d485e..03a804c9c1 100644 --- a/core/services/pipeline/task.bridge_test.go +++ b/core/services/pipeline/task.bridge_test.go @@ -24,8 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -208,7 +207,7 @@ func TestBridgeTask_HandlesIntermittentFailure(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {}) + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {}) s1 := httptest.NewServer(fakeIntermittentlyFailingPriceResponder(t, utils.MustUnmarshalToMap(btcUSDPairing), decimal.NewFromInt(9700), "", nil)) defer s1.Close() @@ -270,7 +269,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.WebServer.BridgeCacheTTL = models.MustNewDuration(30 * time.Second) }) queryer := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) @@ -336,7 +335,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { require.NoError(t, result2.Error) require.Equal(t, string(big.NewInt(9700).Bytes()), result2.Value) - cfg2 := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg2 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.WebServer.BridgeCacheTTL = models.MustNewDuration(0 * time.Second) }) task.HelperSetDependencies(cfg2.JobPipeline(), cfg2.WebServer(), orm, specID, uuid.UUID{}, c) diff --git a/core/services/pipeline/task.eth_call_test.go b/core/services/pipeline/task.eth_call_test.go index 77a10681fb..8fe8bec16c 100644 --- a/core/services/pipeline/task.eth_call_test.go +++ b/core/services/pipeline/task.eth_call_test.go @@ -17,7 +17,7 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index af09d79385..e5f50bc29e 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/pipeline/task.http_test.go b/core/services/pipeline/task.http_test.go index eee3a9aa78..c0dd93df43 100644 --- a/core/services/pipeline/task.http_test.go +++ b/core/services/pipeline/task.http_test.go @@ -20,7 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index f57cf8f45a..1f15d94418 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" diff --git a/core/services/relay/evm/evm_test.go b/core/services/relay/evm/evm_test.go index df7cd8eb81..4e9c44a7b9 100644 --- a/core/services/relay/evm/evm_test.go +++ b/core/services/relay/evm/evm_test.go @@ -3,10 +3,11 @@ package evm_test import ( "testing" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go index 361a7468f3..3f4a3749ac 100644 --- a/core/services/relay/evm/relayer_extender_test.go +++ b/core/services/relay/evm/relayer_extender_test.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/services/relay/evm/request_round_tracker_test.go b/core/services/relay/evm/request_round_tracker_test.go index b9f38d54ba..cb2ee2a8d7 100644 --- a/core/services/relay/evm/request_round_tracker_test.go +++ b/core/services/relay/evm/request_round_tracker_test.go @@ -7,12 +7,13 @@ import ( gethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -21,7 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 8c522520fa..38b361716b 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -21,7 +21,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/vrf/proof/proof_response_test.go b/core/services/vrf/proof/proof_response_test.go index 191c18b60d..24df77d4b3 100644 --- a/core/services/vrf/proof/proof_response_test.go +++ b/core/services/vrf/proof/proof_response_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_verifier_wrapper" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" proof2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 33eb9f7483..9adf47f256 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -40,7 +40,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 6dad317307..093adc8eaa 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -57,7 +57,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 7a1e38fb03..fe218589d2 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/web/cors_test.go b/core/web/cors_test.go index cfd82dd8b7..fcd5d9b387 100644 --- a/core/web/cors_test.go +++ b/core/web/cors_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) diff --git a/core/web/cosmos_chains_controller_test.go b/core/web/cosmos_chains_controller_test.go index f3f5909940..475ef41352 100644 --- a/core/web/cosmos_chains_controller_test.go +++ b/core/web/cosmos_chains_controller_test.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/web" diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index 9864172173..e3a39d541a 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/web/evm_chains_controller_test.go b/core/web/evm_chains_controller_test.go index 4ebf06f2b6..3d5a4e3eed 100644 --- a/core/web/evm_chains_controller_test.go +++ b/core/web/evm_chains_controller_test.go @@ -14,7 +14,7 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/web/evm_forwarders_controller_test.go b/core/web/evm_forwarders_controller_test.go index 46820b4233..31e49f20ec 100644 --- a/core/web/evm_forwarders_controller_test.go +++ b/core/web/evm_forwarders_controller_test.go @@ -13,7 +13,7 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index 0f3cdc8bb6..14259637b4 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -15,7 +15,7 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -125,7 +125,7 @@ func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testin ethClient.On("PendingNonceAt", mock.Anything, key.Address).Return(uint64(1), nil) ethClient.On("BalanceAt", mock.Anything, key.Address, (*big.Int)(nil)).Return(balance.ToInt(), nil) - config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) @@ -285,7 +285,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, key.Address, (*big.Int)(nil)).Return(balance.ToInt(), nil) ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(0), nil).Maybe() - config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") c.EVM[0].ChainID = (*utils.Big)(testutils.FixtureChainID) diff --git a/core/web/external_initiators_controller_test.go b/core/web/external_initiators_controller_test.go index 2229b40b7e..6a1b715b72 100644 --- a/core/web/external_initiators_controller_test.go +++ b/core/web/external_initiators_controller_test.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -69,7 +69,7 @@ func TestExternalInitiatorsController_Index(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithConfig(t, - configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) })) require.NoError(t, app.Start(testutils.Context(t))) @@ -135,7 +135,7 @@ func TestExternalInitiatorsController_Create_success(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithConfig(t, - configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) })) require.NoError(t, app.Start(testutils.Context(t))) @@ -163,7 +163,7 @@ func TestExternalInitiatorsController_Create_without_URL(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithConfig(t, - configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) })) require.NoError(t, app.Start(testutils.Context(t))) @@ -191,7 +191,7 @@ func TestExternalInitiatorsController_Create_invalid(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithConfig(t, - configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) })) require.NoError(t, app.Start(testutils.Context(t))) @@ -209,7 +209,7 @@ func TestExternalInitiatorsController_Delete(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithConfig(t, - configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) })) require.NoError(t, app.Start(testutils.Context(t))) @@ -231,7 +231,7 @@ func TestExternalInitiatorsController_DeleteNotFound(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithConfig(t, - configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) })) require.NoError(t, app.Start(testutils.Context(t))) diff --git a/core/web/features_controller_test.go b/core/web/features_controller_test.go index 8ef2e08d39..727d7db547 100644 --- a/core/web/features_controller_test.go +++ b/core/web/features_controller_test.go @@ -6,7 +6,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/gui_assets_test.go b/core/web/gui_assets_test.go index 784b0958f5..137b123198 100644 --- a/core/web/gui_assets_test.go +++ b/core/web/gui_assets_test.go @@ -8,7 +8,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/web" diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 345662909a..fc2e8d7a30 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -25,7 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -44,7 +44,7 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin contractAddress = cltest.NewEIP55Address() ) - peerID, err := p2ppeer.Decode("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") + peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) require.NoError(t, err) randomBytes := testutils.Random32Byte() diff --git a/core/web/log_controller_test.go b/core/web/log_controller_test.go index e4cd1768ce..dbb95361b9 100644 --- a/core/web/log_controller_test.go +++ b/core/web/log_controller_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/loop_registry_test.go b/core/web/loop_registry_test.go index 59a4d0df68..ea76672564 100644 --- a/core/web/loop_registry_test.go +++ b/core/web/loop_registry_test.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) diff --git a/core/web/pipeline_runs_controller_test.go b/core/web/pipeline_runs_controller_test.go index 5b17fcb007..c44ee9ae8d 100644 --- a/core/web/pipeline_runs_controller_test.go +++ b/core/web/pipeline_runs_controller_test.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index 26e061b164..6cac2f4ac4 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" diff --git a/core/web/resolver/features_test.go b/core/web/resolver/features_test.go index 1d3f5b8dda..f14f71abc9 100644 --- a/core/web/resolver/features_test.go +++ b/core/web/resolver/features_test.go @@ -3,7 +3,7 @@ package resolver import ( "testing" - configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) @@ -24,7 +24,7 @@ func Test_ToFeatures(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.App.On("GetConfig").Return(configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + f.App.On("GetConfig").Return(configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { t, f := true, false c.Feature.UICSAKeys = &f c.Feature.FeedsManager = &t diff --git a/core/web/solana_chains_controller_test.go b/core/web/solana_chains_controller_test.go index 5d6dc7424a..724d5cd2c3 100644 --- a/core/web/solana_chains_controller_test.go +++ b/core/web/solana_chains_controller_test.go @@ -18,7 +18,7 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/solana" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" From a3817b5d5a9a3686dfcfca54d4859ac926bef680 Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:10:22 +0200 Subject: [PATCH 007/327] Pass docker image and version to ClNode in E2E tests (#11082) * Pass docker image and version to ClNode * Update logging * Fix --- integration-tests/docker/test_env/cl_node.go | 46 +++++++++---------- integration-tests/docker/test_env/test_env.go | 2 +- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index bf4d3285dc..4c40e64121 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -49,6 +49,8 @@ type ClNode struct { NodeConfig *chainlink.Config `json:"-"` NodeSecretsConfigTOML string `json:"-"` PostgresDb *test_env.PostgresDb `json:"postgresDb"` + UserEmail string `json:"userEmail"` + UserPassword string `json:"userPassword"` t *testing.T l zerolog.Logger lw *logwatch.LogWatch @@ -86,18 +88,22 @@ func WithLogWatch(lw *logwatch.LogWatch) ClNodeOption { } } -func NewClNode(networks []string, nodeConfig *chainlink.Config, opts ...ClNodeOption) *ClNode { +func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *chainlink.Config, opts ...ClNodeOption) *ClNode { nodeDefaultCName := fmt.Sprintf("%s-%s", "cl-node", uuid.NewString()[0:8]) pgDefaultCName := fmt.Sprintf("pg-%s", nodeDefaultCName) pgDb := test_env.NewPostgresDb(networks, test_env.WithPostgresDbContainerName(pgDefaultCName)) n := &ClNode{ EnvComponent: test_env.EnvComponent{ - ContainerName: nodeDefaultCName, - Networks: networks, + ContainerName: nodeDefaultCName, + ContainerImage: imageName, + ContainerVersion: imageVersion, + Networks: networks, }, - NodeConfig: nodeConfig, - PostgresDb: pgDb, - l: log.Logger, + UserEmail: "local@local.com", + UserPassword: "localdevpassword", + NodeConfig: nodeConfig, + PostgresDb: pgDb, + l: log.Logger, } for _, opt := range opts { opt(n) @@ -126,7 +132,7 @@ func (n *ClNode) UpgradeVersion(cfg *chainlink.Config, newImage, newVersion stri return fmt.Errorf("new version is empty") } if newImage == "" { - newImage = os.Getenv("CHAINLINK_IMAGE") + return fmt.Errorf("new image name is empty") } n.ContainerImage = newImage n.ContainerVersion = newVersion @@ -291,14 +297,19 @@ func (n *ClNode) StartContainer() error { if err != nil { return err } - n.l.Info().Str("containerName", n.ContainerName). + n.l.Info(). + Str("containerName", n.ContainerName). + Str("containerImage", n.ContainerImage). + Str("containerVersion", n.ContainerVersion). Str("clEndpoint", clEndpoint). Str("clInternalIP", ip). + Str("userEmail", n.UserEmail). + Str("userPassword", n.UserPassword). Msg("Started Chainlink Node container") clClient, err := client.NewChainlinkClient(&client.ChainlinkConfig{ URL: clEndpoint, - Email: "local@local.com", - Password: "localdevpassword", + Email: n.UserEmail, + Password: n.UserPassword, InternalIP: ip, }, n.l) @@ -360,21 +371,6 @@ func (n *ClNode) getContainerRequest(secrets string) ( adminCredsPath := "/home/admin-credentials.txt" apiCredsPath := "/home/api-credentials.txt" - if n.ContainerImage == "" { - image, ok := os.LookupEnv("CHAINLINK_IMAGE") - if !ok { - return nil, errors.New("CHAINLINK_IMAGE env must be set") - } - n.ContainerImage = image - } - if n.ContainerVersion == "" { - version, ok := os.LookupEnv("CHAINLINK_VERSION") - if !ok { - return nil, errors.New("CHAINLINK_VERSION env must be set") - } - n.ContainerVersion = version - } - return &tc.ContainerRequest{ Name: n.ContainerName, Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 9eb9ed9f39..07b193f102 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -142,7 +142,7 @@ func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count i } else { te.ClCluster = &ClCluster{} for i := 0; i < count; i++ { - ocrNode := NewClNode([]string{te.Network.Name}, nodeConfig, + ocrNode := NewClNode([]string{te.Network.Name}, os.Getenv("CHAINLINK_IMAGE"), os.Getenv("CHAINLINK_VERSION"), nodeConfig, WithSecrets(secretsConfig), ) te.ClCluster.Nodes = append(te.ClCluster.Nodes, ocrNode) From 93a4ef9de2046510cb634513e3e97074c89a8386 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Wed, 25 Oct 2023 16:08:53 +0200 Subject: [PATCH 008/327] fix several npm audit issues (#11080) * fix: json-schema * bump eth-gas-reporter * fix shelljs * fix minimatch & lodash * run hh on lockfile changes --- .github/workflows/solidity-hardhat.yml | 1 + contracts/pnpm-lock.yaml | 457 ++----------------------- 2 files changed, 32 insertions(+), 426 deletions(-) diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index 2e25e52753..334ce4d1ba 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -28,6 +28,7 @@ jobs: - 'contracts/src/!(v0.8/(llo-feeds|ccip)/**)/**/*' - 'contracts/test/**/*' - 'contracts/package.json' + - 'contracts/pnpm-lock.yaml' - 'contracts/hardhat.config.ts' - 'contracts/ci.json' - '.github/workflows/solidity-hardhat.yml' diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index 65865f2adf..2b6082d656 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -126,7 +126,7 @@ devDependencies: version: 2.10.0(hardhat@2.18.1) hardhat-gas-reporter: specifier: ^1.0.9 - version: 1.0.9(hardhat@2.18.1) + version: 1.0.9(debug@4.3.4)(hardhat@2.18.1) hardhat-ignore-warnings: specifier: ^0.2.6 version: 0.2.9 @@ -2156,11 +2156,6 @@ packages: dev: true optional: true - /ansi-colors@3.2.3: - resolution: {integrity: sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==} - engines: {node: '>=6'} - dev: true - /ansi-colors@3.2.4: resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==} engines: {node: '>=6'} @@ -2193,11 +2188,6 @@ packages: engines: {node: '>=4'} dev: true - /ansi-regex@4.1.1: - resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} - engines: {node: '>=6'} - dev: true - /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2330,17 +2320,6 @@ packages: get-intrinsic: 1.2.1 dev: true - /array.prototype.reduce@1.0.4: - resolution: {integrity: sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - es-array-method-boxes-properly: 1.0.0 - is-string: 1.0.7 - dev: true - /array.prototype.reduce@1.0.6: resolution: {integrity: sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==} engines: {node: '>= 0.4'} @@ -3460,11 +3439,6 @@ packages: engines: {node: '>=4'} dev: true - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - dev: true - /camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -3622,21 +3596,6 @@ packages: parse5-htmlparser2-tree-adapter: 7.0.0 dev: true - /chokidar@3.3.0: - resolution: {integrity: sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.2 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.2.0 - optionalDependencies: - fsevents: 2.1.3 - dev: true - /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -3740,14 +3699,6 @@ packages: wrap-ansi: 2.1.0 dev: true - /cliui@5.0.0: - resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} - dependencies: - string-width: 3.1.0 - strip-ansi: 5.2.0 - wrap-ansi: 5.1.0 - dev: true - /cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: @@ -4136,7 +4087,7 @@ packages: ms: 2.0.0 dev: true - /debug@3.2.6(supports-color@6.0.0): + /debug@3.2.6: resolution: {integrity: sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==} deprecated: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797) peerDependencies: @@ -4146,7 +4097,6 @@ packages: optional: true dependencies: ms: 2.1.3 - supports-color: 6.0.0 dev: true /debug@3.2.7: @@ -4398,11 +4348,6 @@ packages: - supports-color dev: true - /diff@3.5.0: - resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} - engines: {node: '>=0.3.1'} - dev: true - /diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -4518,10 +4463,6 @@ packages: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - /emoji-regex@7.0.3: - resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} - dev: true - /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true @@ -4585,36 +4526,6 @@ packages: is-arrayish: 0.2.1 dev: true - /es-abstract@1.20.3: - resolution: {integrity: sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - es-to-primitive: 1.2.1 - function-bind: 1.1.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.1.3 - get-symbol-description: 1.0.0 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-symbols: 1.0.3 - internal-slot: 1.0.3 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-weakref: 1.0.2 - object-inspect: 1.12.2 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.4.3 - safe-regex-test: 1.0.0 - string.prototype.trimend: 1.0.5 - string.prototype.trimstart: 1.0.5 - unbox-primitive: 1.0.2 - dev: true - /es-abstract@1.22.2: resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==} engines: {node: '>= 0.4'} @@ -4916,29 +4827,31 @@ packages: js-sha3: 0.5.7 dev: true - /eth-gas-reporter@0.2.25: - resolution: {integrity: sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==} + /eth-gas-reporter@0.2.27(debug@4.3.4): + resolution: {integrity: sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==} peerDependencies: '@codechecks/client': ^0.1.0 peerDependenciesMeta: '@codechecks/client': optional: true dependencies: - '@ethersproject/abi': 5.7.0 '@solidity-parser/parser': 0.14.3 + axios: 1.5.1(debug@4.3.4) cli-table3: 0.5.1 colors: 1.4.0 ethereum-cryptography: 1.1.2 - ethers: 4.0.49 + ethers: 5.7.2 fs-readdir-recursive: 1.1.0 lodash: 4.17.21 markdown-table: 1.1.3 - mocha: 7.2.0 + mocha: 10.2.0 req-cwd: 2.0.0 - request: 2.88.2 - request-promise-native: 1.0.9(request@2.88.2) sha1: 1.1.1 sync-request: 6.1.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate dev: true /eth-json-rpc-infura@3.2.1: @@ -5654,13 +5567,6 @@ packages: locate-path: 2.0.0 dev: true - /find-up@3.0.0: - resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} - engines: {node: '>=6'} - dependencies: - locate-path: 3.0.0 - dev: true - /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5700,13 +5606,6 @@ packages: rimraf: 3.0.2 dev: true - /flat@4.1.1: - resolution: {integrity: sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==} - hasBin: true - dependencies: - is-buffer: 2.0.5 - dev: true - /flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true @@ -5862,15 +5761,6 @@ packages: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /fsevents@2.1.3: - resolution: {integrity: sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - deprecated: '"Please update to latest v2.3 or v2.2"' - requiresBuild: true - dev: true - optional: true - /fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -5883,16 +5773,6 @@ packages: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - functions-have-names: 1.2.3 - dev: true - /function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} @@ -5921,7 +5801,7 @@ packages: bip39: 2.5.0 cachedown: 1.0.0 clone: 2.1.2 - debug: 3.2.6(supports-color@6.0.0) + debug: 3.2.6 encoding-down: 5.0.4 eth-sig-util: 3.0.0 ethereumjs-abi: 0.6.8 @@ -5934,7 +5814,7 @@ packages: heap: 0.2.6 level-sublevel: 6.6.4 levelup: 3.1.1 - lodash: 4.17.20 + lodash: 4.17.21 lru-cache: 5.1.1 merkle-patricia-tree: 3.0.0 patch-package: 6.2.2 @@ -6066,17 +5946,6 @@ packages: path-is-absolute: 1.0.1 dev: true - /glob@7.1.3: - resolution: {integrity: sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - /glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} dependencies: @@ -6268,11 +6137,6 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true - /growl@1.10.5: - resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} - engines: {node: '>=4.x'} - dev: true - /handlebars@4.7.7: resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} engines: {node: '>=0.4.7'} @@ -6322,17 +6186,20 @@ packages: strip-ansi: 6.0.1 dev: true - /hardhat-gas-reporter@1.0.9(hardhat@2.18.1): + /hardhat-gas-reporter@1.0.9(debug@4.3.4)(hardhat@2.18.1): resolution: {integrity: sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==} peerDependencies: hardhat: ^2.0.2 dependencies: array-uniq: 1.0.3 - eth-gas-reporter: 0.2.25 + eth-gas-reporter: 0.2.27(debug@4.3.4) hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' + - bufferutil + - debug + - utf-8-validate dev: true /hardhat-ignore-warnings@0.2.9: @@ -6648,7 +6515,7 @@ packages: engines: {node: '>=0.8', npm: '>=1.3.7'} dependencies: assert-plus: 1.0.0 - jsprim: 1.4.1 + jsprim: 1.4.2 sshpk: 1.16.1 dev: true @@ -6759,15 +6626,6 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true - /internal-slot@1.0.3: - resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.1.3 - has: 1.0.3 - side-channel: 1.0.4 - dev: true - /internal-slot@1.0.5: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} @@ -6878,12 +6736,6 @@ packages: ci-info: 2.0.0 dev: true - /is-core-module@2.10.0: - resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} - dependencies: - has: 1.0.3 - dev: true - /is-core-module@2.13.0: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: @@ -7268,14 +7120,6 @@ packages: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true - /js-yaml@3.13.1: - resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -7349,8 +7193,8 @@ packages: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} dev: true - /json-schema@0.2.3: - resolution: {integrity: sha512-a3xHnILGMtk+hDOqNwHzF6e2fNbiMrXZvxKQiEv2MlgQP+pjIOzqAmKYD2mDpXYE/44M7g+n9p2bKkYWDUcXCQ==} + /json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} dev: true /json-stable-stringify-without-jsonify@1.0.1: @@ -7413,13 +7257,13 @@ packages: resolution: {integrity: sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==} dev: true - /jsprim@1.4.1: - resolution: {integrity: sha512-4Dj8Rf+fQ+/Pn7C5qeEX02op1WfOss3PKTE9Nsop3Dx+6UPxlm1dr/og7o2cRa5hNN07CACr4NFzRLtj/rjWog==} - engines: {'0': node >=0.6.0} + /jsprim@1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} dependencies: assert-plus: 1.0.0 extsprintf: 1.3.0 - json-schema: 0.2.3 + json-schema: 0.4.0 verror: 1.10.0 dev: true @@ -7680,14 +7524,6 @@ packages: path-exists: 3.0.0 dev: true - /locate-path@3.0.0: - resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} - engines: {node: '>=6'} - dependencies: - p-locate: 3.0.0 - path-exists: 3.0.0 - dev: true - /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -7734,13 +7570,6 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - /log-symbols@3.0.0: - resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==} - engines: {node: '>=8'} - dependencies: - chalk: 2.4.2 - dev: true - /log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -8036,12 +7865,6 @@ packages: /minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - /minimatch@3.0.4: - resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} - dependencies: - brace-expansion: 1.1.11 - dev: true - /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -8102,13 +7925,6 @@ packages: mkdirp: 1.0.4 dev: true - /mkdirp@0.5.5: - resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==} - hasBin: true - dependencies: - minimist: 1.2.6 - dev: true - /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -8156,37 +7972,6 @@ packages: yargs-unparser: 2.0.0 dev: true - /mocha@7.2.0: - resolution: {integrity: sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==} - engines: {node: '>= 8.10.0'} - hasBin: true - dependencies: - ansi-colors: 3.2.3 - browser-stdout: 1.3.1 - chokidar: 3.3.0 - debug: 3.2.6(supports-color@6.0.0) - diff: 3.5.0 - escape-string-regexp: 1.0.5 - find-up: 3.0.0 - glob: 7.1.3 - growl: 1.10.5 - he: 1.2.0 - js-yaml: 3.13.1 - log-symbols: 3.0.0 - minimatch: 3.0.4 - mkdirp: 0.5.5 - ms: 2.1.1 - node-environment-flags: 1.0.6 - object.assign: 4.1.0 - strip-json-comments: 2.0.1 - supports-color: 6.0.0 - which: 1.3.1 - wide-align: 1.1.3 - yargs: 13.3.2 - yargs-parser: 13.1.2 - yargs-unparser: 1.6.0 - dev: true - /mock-fs@4.12.0: resolution: {integrity: sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ==} requiresBuild: true @@ -8355,13 +8140,6 @@ packages: lodash: 4.17.21 dev: true - /node-environment-flags@1.0.6: - resolution: {integrity: sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==} - dependencies: - object.getownpropertydescriptors: 2.1.4 - semver: 5.7.1 - dev: true - /node-fetch@1.7.3: resolution: {integrity: sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==} dependencies: @@ -8414,7 +8192,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.1 + resolve: 1.22.8 semver: 5.7.1 validate-npm-package-license: 3.0.4 dev: true @@ -8522,16 +8300,6 @@ packages: isobject: 3.0.1 dev: true - /object.assign@4.1.0: - resolution: {integrity: sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.1.4 - function-bind: 1.1.1 - has-symbols: 1.0.3 - object-keys: 1.1.1 - dev: true - /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} @@ -8542,16 +8310,6 @@ packages: object-keys: 1.1.1 dev: true - /object.getownpropertydescriptors@2.1.4: - resolution: {integrity: sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==} - engines: {node: '>= 0.8'} - dependencies: - array.prototype.reduce: 1.0.4 - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - /object.getownpropertydescriptors@2.1.7: resolution: {integrity: sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==} engines: {node: '>= 0.8'} @@ -8726,13 +8484,6 @@ packages: p-limit: 1.3.0 dev: true - /p-locate@3.0.0: - resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} - engines: {node: '>=6'} - dependencies: - p-limit: 2.3.0 - dev: true - /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -9385,13 +9136,6 @@ packages: util-deprecate: 1.0.2 dev: true - /readdirp@3.2.0: - resolution: {integrity: sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==} - engines: {node: '>= 8'} - dependencies: - picomatch: 2.3.1 - dev: true - /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -9410,7 +9154,7 @@ packages: resolution: {integrity: sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==} engines: {node: '>=0.10.0'} dependencies: - minimatch: 3.0.4 + minimatch: 3.1.2 dev: true /reduce-flatten@2.0.0: @@ -9514,29 +9258,6 @@ packages: resolve-from: 3.0.0 dev: true - /request-promise-core@1.1.4(request@2.88.2): - resolution: {integrity: sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==} - engines: {node: '>=0.10.0'} - peerDependencies: - request: ^2.34 - dependencies: - lodash: 4.17.21 - request: 2.88.2 - dev: true - - /request-promise-native@1.0.9(request@2.88.2): - resolution: {integrity: sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==} - engines: {node: '>=0.12.0'} - deprecated: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142 - peerDependencies: - request: ^2.34 - dependencies: - request: 2.88.2 - request-promise-core: 1.1.4(request@2.88.2) - stealthy-require: 1.1.1 - tough-cookie: 2.5.0 - dev: true - /request@2.88.2: resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} engines: {node: '>= 6'} @@ -9583,10 +9304,6 @@ packages: resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} dev: true - /require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - dev: true - /resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} dev: true @@ -9616,15 +9333,6 @@ packages: path-parse: 1.0.7 dev: true - /resolve@1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true - dependencies: - is-core-module: 2.10.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -10013,8 +9721,8 @@ packages: engines: {node: '>=8'} dev: true - /shelljs@0.8.3: - resolution: {integrity: sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==} + /shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} engines: {node: '>=4'} hasBin: true dependencies: @@ -10332,7 +10040,7 @@ packages: recursive-readdir: 2.2.2 sc-istanbul: 0.4.6 semver: 7.5.4 - shelljs: 0.8.3 + shelljs: 0.8.5 web3-utils: 1.8.0 transitivePeerDependencies: - supports-color @@ -10474,11 +10182,6 @@ packages: engines: {node: '>= 0.8'} dev: true - /stealthy-require@1.1.1: - resolution: {integrity: sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==} - engines: {node: '>=0.10.0'} - dev: true - /stream-to-pull-stream@1.7.3: resolution: {integrity: sha512-6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg==} dependencies: @@ -10518,15 +10221,6 @@ packages: strip-ansi: 4.0.0 dev: true - /string-width@3.1.0: - resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} - engines: {node: '>=6'} - dependencies: - emoji-regex: 7.0.3 - is-fullwidth-code-point: 2.0.0 - strip-ansi: 5.2.0 - dev: true - /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -10545,14 +10239,6 @@ packages: es-abstract: 1.22.2 dev: true - /string.prototype.trimend@1.0.5: - resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - /string.prototype.trimend@1.0.7: resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} dependencies: @@ -10561,14 +10247,6 @@ packages: es-abstract: 1.22.2 dev: true - /string.prototype.trimstart@1.0.5: - resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - /string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} dependencies: @@ -10607,13 +10285,6 @@ packages: ansi-regex: 3.0.1 dev: true - /strip-ansi@5.2.0: - resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} - engines: {node: '>=6'} - dependencies: - ansi-regex: 4.1.1 - dev: true - /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -10650,11 +10321,6 @@ packages: engines: {node: '>=4'} dev: true - /strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - dev: true - /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -10679,13 +10345,6 @@ packages: has-flag: 3.0.0 dev: true - /supports-color@6.0.0: - resolution: {integrity: sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==} - engines: {node: '>=6'} - dependencies: - has-flag: 3.0.0 - dev: true - /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -11006,7 +10665,7 @@ packages: glob: 7.2.3 mkdirp: 0.5.6 prettier: 2.8.8 - resolve: 1.22.1 + resolve: 1.22.8 ts-essentials: 1.0.4 dev: true @@ -12408,10 +12067,6 @@ packages: resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} dev: true - /which-module@2.0.0: - resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} - dev: true - /which-typed-array@1.1.11: resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} engines: {node: '>= 0.4'} @@ -12438,12 +12093,6 @@ packages: isexe: 2.0.0 dev: true - /wide-align@1.1.3: - resolution: {integrity: sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==} - dependencies: - string-width: 2.1.1 - dev: true - /window-size@0.2.0: resolution: {integrity: sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==} engines: {node: '>= 0.10.0'} @@ -12479,15 +12128,6 @@ packages: strip-ansi: 3.0.1 dev: true - /wrap-ansi@5.1.0: - resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} - engines: {node: '>=6'} - dependencies: - ansi-styles: 3.2.1 - string-width: 3.1.0 - strip-ansi: 5.2.0 - dev: true - /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -12613,10 +12253,6 @@ packages: resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} dev: true - /y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - dev: true - /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -12640,13 +12276,6 @@ packages: engines: {node: '>= 6'} dev: true - /yargs-parser@13.1.2: - resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - dev: true - /yargs-parser@2.4.1: resolution: {integrity: sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==} dependencies: @@ -12659,15 +12288,6 @@ packages: engines: {node: '>=10'} dev: true - /yargs-unparser@1.6.0: - resolution: {integrity: sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==} - engines: {node: '>=6'} - dependencies: - flat: 4.1.1 - lodash: 4.17.21 - yargs: 13.3.2 - dev: true - /yargs-unparser@2.0.0: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} @@ -12678,21 +12298,6 @@ packages: is-plain-obj: 2.1.0 dev: true - /yargs@13.3.2: - resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==} - dependencies: - cliui: 5.0.0 - find-up: 3.0.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 3.1.0 - which-module: 2.0.0 - y18n: 4.0.3 - yargs-parser: 13.1.2 - dev: true - /yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} From d31223c6f9767ef775932d7622dd709f3b7fafdb Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Wed, 25 Oct 2023 17:34:02 +0300 Subject: [PATCH 009/327] VRF-664:add Slack notification for VRF v2 Plus WASP test (#11063) * VRF-664:add Slack notification for VRF v2 Plus WASP test * VRF-664:fixing import cycle * VRF-664:cleanup * VRF-664:adding slack channel secret --- ... on-demand-vrfv2plus-performance-test.yml} | 23 ++-- .../vrfv2plus/vrfv2plus_config/config.go | 2 + integration-tests/load/vrfv2plus/config.go | 23 ++-- integration-tests/load/vrfv2plus/config.toml | 8 +- .../load/vrfv2plus/onchain_monitoring.go | 22 ++-- .../load/vrfv2plus/vrfv2plus_test.go | 117 +++++++++++++----- integration-tests/testreporters/vrfv2plus.go | 91 ++++++++++++++ 7 files changed, 228 insertions(+), 58 deletions(-) rename .github/workflows/{on-demand-vrfv2plus-load-test.yml => on-demand-vrfv2plus-performance-test.yml} (84%) create mode 100644 integration-tests/testreporters/vrfv2plus.go diff --git a/.github/workflows/on-demand-vrfv2plus-load-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml similarity index 84% rename from .github/workflows/on-demand-vrfv2plus-load-test.yml rename to .github/workflows/on-demand-vrfv2plus-performance-test.yml index f4ca096d5c..b33c6f8313 100644 --- a/.github/workflows/on-demand-vrfv2plus-load-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -1,4 +1,4 @@ -name: On Demand VRFV2 Plus Load Test +name: On Demand VRFV2 Plus Performance Test on: workflow_dispatch: inputs: @@ -49,8 +49,8 @@ on: - "Spike" testDuration: description: Duration of the test (time string) - required: false - default: 1m + required: true + default: 5m useExistingEnv: description: Set `true` to use existing environment or `false` to deploy CL node and all contracts required: false @@ -59,8 +59,8 @@ on: description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) required: false jobs: - vrfv2plus_load_test: - name: ${{ inputs.network }} VRFV2 Plus Load Test + vrfv2plus_performance_test: + name: ${{ inputs.network }} VRFV2 Plus Performance Test environment: integration runs-on: ubuntu20.04-8cores-32GB permissions: @@ -80,6 +80,8 @@ jobs: REF_NAME: ${{ github.head_ref || github.ref_name }} CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} + SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} WASP_LOG_LEVEL: info steps: - name: Collect Metrics @@ -88,8 +90,15 @@ jobs: with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ${{ inputs.network }} VRFV2 Plus Load Test + this-job-name: ${{ inputs.network }} VRFV2 Plus Performance Test continue-on-error: true + - name: Setup Push Tag + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - name: Get Inputs run: | EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) @@ -111,7 +120,7 @@ jobs: - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: - test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 6h -run TestVRFV2PlusLoad/vrfv2plus_soak_test ./load/vrfv2plus + test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 6h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./load/vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ inputs.chainlinkImage }} cl_image_tag: ${{ inputs.chainlinkVersion }} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go index 7a1221eaf8..caee353294 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -18,6 +18,8 @@ type VRFV2PlusConfig struct { FulfillmentFlatFeeLinkPPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM" default:"500"` // Flat fee in ppm for LINK for the VRF Coordinator config FulfillmentFlatFeeNativePPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_NATIVE_PPM" default:"500"` // Flat fee in ppm for native currency for the VRF Coordinator config + NumberOfSubToCreate int `envconfig:"NUMBER_OF_SUB_TO_CREATE" default:"1"` // Number of subscriptions to create + RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request RandomnessRequestCountPerRequestDeviation uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST_DEVIATION" default:"0"` // How many randomness requests to send per request diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index 5f3babfeab..329e4abf13 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -12,6 +12,10 @@ import ( const ( DefaultConfigFilename = "config.toml" + SoakTestType = "Soak" + LoadTestType = "Load" + StressTestType = "Stress" + SpikeTestType = "Spike" ErrReadPerfConfig = "failed to read TOML config for performance tests" ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" @@ -38,7 +42,6 @@ type ExistingEnvConfig struct { type NewEnvConfig struct { Funding - NumberOfSubToCreate int `toml:"number_of_sub_to_create"` } type Common struct { @@ -68,6 +71,8 @@ type Spike struct { } type PerformanceTestConfig struct { + NumberOfSubToCreate int `toml:"number_of_sub_to_create"` + RPS int64 `toml:"rps"` //Duration *models.Duration `toml:"duration"` RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` @@ -101,24 +106,28 @@ func ReadConfig() (*PerformanceConfig, error) { return cfg, nil } -func SetPerformanceTestConfig(vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, cfg *PerformanceConfig) { - switch os.Getenv("TEST_TYPE") { - case "Soak": +func SetPerformanceTestConfig(testType string, vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, cfg *PerformanceConfig) { + switch testType { + case SoakTestType: + vrfv2PlusConfig.NumberOfSubToCreate = cfg.Soak.NumberOfSubToCreate vrfv2PlusConfig.RPS = cfg.Soak.RPS vrfv2PlusConfig.RateLimitUnitDuration = cfg.Soak.RateLimitUnitDuration.Duration() vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Soak.RandomnessRequestCountPerRequest vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Soak.RandomnessRequestCountPerRequestDeviation - case "Load": + case LoadTestType: + vrfv2PlusConfig.NumberOfSubToCreate = cfg.Load.NumberOfSubToCreate vrfv2PlusConfig.RPS = cfg.Load.RPS vrfv2PlusConfig.RateLimitUnitDuration = cfg.Load.RateLimitUnitDuration.Duration() vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Load.RandomnessRequestCountPerRequest vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Load.RandomnessRequestCountPerRequestDeviation - case "Stress": + case StressTestType: + vrfv2PlusConfig.NumberOfSubToCreate = cfg.Stress.NumberOfSubToCreate vrfv2PlusConfig.RPS = cfg.Stress.RPS vrfv2PlusConfig.RateLimitUnitDuration = cfg.Stress.RateLimitUnitDuration.Duration() vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Stress.RandomnessRequestCountPerRequest vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Stress.RandomnessRequestCountPerRequestDeviation - case "Spike": + case SpikeTestType: + vrfv2PlusConfig.NumberOfSubToCreate = cfg.Spike.NumberOfSubToCreate vrfv2PlusConfig.RPS = cfg.Spike.RPS vrfv2PlusConfig.RateLimitUnitDuration = cfg.Spike.RateLimitUnitDuration.Duration() vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Spike.RandomnessRequestCountPerRequest diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml index 1208423dc0..31a0bf5665 100644 --- a/integration-tests/load/vrfv2plus/config.toml +++ b/integration-tests/load/vrfv2plus/config.toml @@ -6,7 +6,7 @@ minimum_confirmations = 3 sub_funds_link = 1000 sub_funds_native = 1000 node_funds = 10 -number_of_sub_to_create = 10 + [ExistingEnvConfig] coordinator_address = "0x4931Ce2e341398c8eD8A5D0F6ADb920476D6DaBb" @@ -21,6 +21,7 @@ rate_limit_unit_duration = "6s" rps = 1 randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 # approx 60 RPM - 1 tx request with 4 rand requests in each tx every 3 seconds [Load] @@ -28,13 +29,15 @@ rate_limit_unit_duration = "3s" rps = 1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 10 # approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx [Stress] -rate_limit_unit_duration = "0" +rate_limit_unit_duration = "1s" rps = 3 randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 20 # approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds [Spike] @@ -42,3 +45,4 @@ rate_limit_unit_duration = "1m" rps = 1 randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 \ No newline at end of file diff --git a/integration-tests/load/vrfv2plus/onchain_monitoring.go b/integration-tests/load/vrfv2plus/onchain_monitoring.go index 0ae27fe6be..c56d835234 100644 --- a/integration-tests/load/vrfv2plus/onchain_monitoring.go +++ b/integration-tests/load/vrfv2plus/onchain_monitoring.go @@ -3,7 +3,7 @@ package loadvrfv2plus import ( "context" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/wasp" "testing" "time" @@ -18,11 +18,12 @@ const ( ErrLokiPush = "failed to push monitoring metrics to Loki" ) -func MonitorLoadStats(lc *wasp.LokiClient, vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts, labels map[string]string) { +func MonitorLoadStats(lc *wasp.LokiClient, consumer contracts.VRFv2PlusLoadTestConsumer, labels map[string]string) { go func() { for { time.Sleep(1 * time.Second) - SendLoadTestMetricsToLoki(vrfv2PlusContracts, lc, labels) + metrics := GetLoadTestMetrics(consumer) + SendMetricsToLoki(metrics, lc, labels) } }() } @@ -38,13 +39,16 @@ func UpdateLabels(labels map[string]string, t *testing.T) map[string]string { return updatedLabels } -func SendLoadTestMetricsToLoki(vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts, lc *wasp.LokiClient, updatedLabels map[string]string) { - //todo - should work with multiple consumers and consumers having different keyhashes and wallets - metrics, err := vrfv2PlusContracts.LoadTestConsumers[0].GetLoadTestMetrics(context.Background()) - if err != nil { - log.Error().Err(err).Msg(ErrMetrics) - } +func SendMetricsToLoki(metrics *contracts.VRFLoadTestMetrics, lc *wasp.LokiClient, updatedLabels map[string]string) { if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), metrics); err != nil { log.Error().Err(err).Msg(ErrLokiPush) } } + +func GetLoadTestMetrics(consumer contracts.VRFv2PlusLoadTestConsumer) *contracts.VRFLoadTestMetrics { + metrics, err := consumer.GetLoadTestMetrics(context.Background()) + if err != nil { + log.Error().Err(err).Msg(ErrMetrics) + } + return metrics +} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 5c3ea6e8c6..a3cb4d4b7f 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -4,7 +4,9 @@ import ( "context" "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" + "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" "math/big" @@ -20,21 +22,46 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) -func TestVRFV2PlusLoad(t *testing.T) { +var ( + env *test_env.CLClusterTestEnv + vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts + vrfv2PlusData *vrfv2plus.VRFV2PlusData + subIDs []*big.Int + + labels = map[string]string{ + "branch": "vrfv2Plus_healthcheck", + "commit": "vrfv2Plus_healthcheck", + } + + testType = os.Getenv("TEST_TYPE") +) + +func TestVRFV2PlusPerformance(t *testing.T) { cfg, err := ReadConfig() require.NoError(t, err) var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) require.NoError(t, err) - SetPerformanceTestConfig(&vrfv2PlusConfig, cfg) + testReporter := &testreporters.VRFV2PlusTestReporter{} + + SetPerformanceTestConfig(testType, &vrfv2PlusConfig, cfg) l := logging.GetTestLogger(t) //todo: temporary solution with envconfig and toml config until VRF-662 is implemented vrfv2PlusConfig.MinimumConfirmations = cfg.Common.MinimumConfirmations + lokiConfig := wasp.NewEnvLokiConfig() + lc, err := wasp.NewLokiClient(lokiConfig) + if err != nil { + l.Error().Err(err).Msg(ErrLokiClient) + return + } + + updatedLabels := UpdateLabels(labels, t) + l.Info(). - Str("Test Type", os.Getenv("TEST_TYPE")). + Str("Test Type", testType). Str("Test Duration", vrfv2PlusConfig.TestDuration.Truncate(time.Second).String()). Int64("RPS", vrfv2PlusConfig.RPS). Str("RateLimitUnitDuration", vrfv2PlusConfig.RateLimitUnitDuration.String()). @@ -43,11 +70,6 @@ func TestVRFV2PlusLoad(t *testing.T) { Bool("UseExistingEnv", vrfv2PlusConfig.UseExistingEnv). Msg("Performance Test Configuration") - var env *test_env.CLClusterTestEnv - var vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts - var vrfv2PlusData *vrfv2plus.VRFV2PlusData - var subIDs []*big.Int - if vrfv2PlusConfig.UseExistingEnv { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented vrfv2PlusConfig.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress @@ -57,7 +79,10 @@ func TestVRFV2PlusLoad(t *testing.T) { env, err = test_env.NewCLTestEnvBuilder(). WithTestLogger(t). - WithoutCleanup(). + WithCustomCleanup( + func() { + teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + }). Build() require.NoError(t, err, "error creating test env") @@ -93,13 +118,18 @@ func TestVRFV2PlusLoad(t *testing.T) { vrfv2PlusConfig.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeFunds vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.NewEnvConfig.Funding.SubFundsNative - numberOfSubToCreate := cfg.NewEnvConfig.NumberOfSubToCreate env, err = test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). - WithStandardCleanup(). + WithCustomCleanup( + func() { + teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + }). WithLogWatcher(). Build() @@ -113,29 +143,24 @@ func TestVRFV2PlusLoad(t *testing.T) { linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1, numberOfSubToCreate) + vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment( + env, + &vrfv2PlusConfig, + linkToken, + mockETHLinkFeed, + 1, + vrfv2PlusConfig.NumberOfSubToCreate, + ) require.NoError(t, err, "error setting up VRF v2_5 env") } - l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs Involved in Load Test") + l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) } - labels := map[string]string{ - "branch": "vrfv2Plus_healthcheck", - "commit": "vrfv2Plus_healthcheck", - } - - lokiConfig := wasp.NewEnvLokiConfig() - lc, err := wasp.NewLokiClient(lokiConfig) - if err != nil { - l.Error().Err(err).Msg(ErrLokiClient) - return - } - singleFeedConfig := &wasp.Config{ T: t, LoadType: wasp.RPS, @@ -156,11 +181,10 @@ func TestVRFV2PlusLoad(t *testing.T) { consumer := vrfv2PlusContracts.LoadTestConsumers[0] err = consumer.ResetMetrics() require.NoError(t, err) - updatedLabels := UpdateLabels(labels, t) - MonitorLoadStats(lc, vrfv2PlusContracts, updatedLabels) + MonitorLoadStats(lc, consumer, updatedLabels) // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? - t.Run("vrfv2plus soak test", func(t *testing.T) { + t.Run("vrfv2plus performance test", func(t *testing.T) { singleFeedConfig.Schedule = wasp.Plain( vrfv2PlusConfig.RPS, @@ -172,17 +196,44 @@ func TestVRFV2PlusLoad(t *testing.T) { require.NoError(t, err) var wg sync.WaitGroup - wg.Add(1) + //todo - timeout should be configurable depending on the perf test type requestCount, fulfilmentCount, err := vrfv2plus.WaitForRequestCountEqualToFulfilmentCount(consumer, 30*time.Second, &wg) + require.NoError(t, err) + wg.Wait() + l.Info(). Interface("Request Count", requestCount). Interface("Fulfilment Count", fulfilmentCount). Msg("Final Request/Fulfilment Stats") - require.NoError(t, err) - wg.Wait() - //send final results - SendLoadTestMetricsToLoki(vrfv2PlusContracts, lc, updatedLabels) }) +} +func teardown( + t *testing.T, + consumer contracts.VRFv2PlusLoadTestConsumer, + lc *wasp.LokiClient, updatedLabels map[string]string, + testReporter *testreporters.VRFV2PlusTestReporter, + testType string, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, +) { + //send final results to Loki + metrics := GetLoadTestMetrics(consumer) + SendMetricsToLoki(metrics, lc, updatedLabels) + //set report data for Slack notification + testReporter.SetReportData( + testType, + metrics.RequestCount, + metrics.FulfilmentCount, + metrics.AverageFulfillmentInMillions, + metrics.SlowestFulfillment, + metrics.FastestFulfillment, + vrfv2PlusConfig, + ) + + // send Slack notification + err := testReporter.SendSlackNotification(t, nil) + if err != nil { + log.Warn().Err(err).Msg("Error sending Slack notification") + } } diff --git a/integration-tests/testreporters/vrfv2plus.go b/integration-tests/testreporters/vrfv2plus.go new file mode 100644 index 0000000000..83d4678dfd --- /dev/null +++ b/integration-tests/testreporters/vrfv2plus.go @@ -0,0 +1,91 @@ +package testreporters + +import ( + "fmt" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "math/big" + "os" + "testing" + "time" + + "github.com/slack-go/slack" + + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" +) + +type VRFV2PlusTestReporter struct { + TestType string + RequestCount *big.Int + FulfilmentCount *big.Int + AverageFulfillmentInMillions *big.Int + SlowestFulfillment *big.Int + FastestFulfillment *big.Int + Vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig +} + +func (o *VRFV2PlusTestReporter) SetReportData( + testType string, + RequestCount *big.Int, + FulfilmentCount *big.Int, + AverageFulfillmentInMillions *big.Int, + SlowestFulfillment *big.Int, + FastestFulfillment *big.Int, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, +) { + o.TestType = testType + o.RequestCount = RequestCount + o.FulfilmentCount = FulfilmentCount + o.AverageFulfillmentInMillions = AverageFulfillmentInMillions + o.SlowestFulfillment = SlowestFulfillment + o.FastestFulfillment = FastestFulfillment + o.Vrfv2PlusConfig = &vrfv2PlusConfig +} + +// SendSlackNotification sends a slack message to a slack webhook +func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { + if slackClient == nil { + slackClient = slack.New(testreporters.SlackAPIKey) + } + + testFailed := t.Failed() + headerText := fmt.Sprintf(":white_check_mark: VRF %s Test PASSED :white_check_mark:", o.TestType) + if testFailed { + headerText = fmt.Sprintf(":x: VRF %s Test FAILED :x:", o.TestType) + } + + messageBlocks := testreporters.SlackNotifyBlocks(headerText, fmt.Sprintf("%s", os.Getenv("SELECTED_NETWORKS")), []string{ + fmt.Sprintf( + "Summary\n"+ + "Perf Test Type: %s\n"+ + "Test Duration set in parameters: %s\n"+ + "Use Existing Env: %t\n"+ + "Request Count: %s\n"+ + "Fulfilment Count: %s\n"+ + "AverageFulfillmentInMillions: %s\n"+ + "Slowest Fulfillment: %s\n"+ + "Fastest Fulfillment: %s \n"+ + "RPS: %d\n"+ + "RateLimitUnitDuration: %s\n"+ + "RandomnessRequestCountPerRequest: %d\n"+ + "RandomnessRequestCountPerRequestDeviation: %d\n", + o.TestType, + o.Vrfv2PlusConfig.TestDuration.Truncate(time.Second).String(), + o.Vrfv2PlusConfig.UseExistingEnv, + o.RequestCount.String(), + o.FulfilmentCount.String(), + o.AverageFulfillmentInMillions.String(), + o.SlowestFulfillment.String(), + o.FastestFulfillment.String(), + o.Vrfv2PlusConfig.RPS, + o.Vrfv2PlusConfig.RateLimitUnitDuration.String(), + o.Vrfv2PlusConfig.RandomnessRequestCountPerRequest, + o.Vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation, + ), + }) + + _, err := testreporters.SendSlackMessage(slackClient, slack.MsgOptionBlocks(messageBlocks...)) + if err != nil { + return err + } + return nil +} From 3e75b262f11603383609e2a5757d5170adb07e88 Mon Sep 17 00:00:00 2001 From: Sneha Agnihotri <180277+snehaagni@users.noreply.github.com> Date: Wed, 25 Oct 2023 08:20:04 -0700 Subject: [PATCH 010/327] Bump version and update CHANGELOG for core v2.7.0 (#11072) --- VERSION | 2 +- docs/CHANGELOG.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e70b4523ae..24ba9a38de 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.6.0 +2.7.0 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 469cd0d168..44d018769e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] +... + +## 2.7.0 - UNRELEASED + ### Added - Added new configuration field named `LeaseDuration` for `EVM.NodePool` that will periodically check if internal subscriptions are connected to the "best" (as defined by the `SelectionMode`) node and switch to it if necessary. Setting this value to `0s` will disable this feature. From 4464dffc90686c05868f26f52d669ae8192aa18e Mon Sep 17 00:00:00 2001 From: Erik Burton Date: Wed, 25 Oct 2023 11:05:09 -0700 Subject: [PATCH 011/327] [RE-2009] Bump action references (#11067) * Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...3df4ab11eba7bda6032a0b82a6bb43b11571feac) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * manual: Bump actions/checkout from 3 to 4 * manual: Bump actions/setup-node from 3 to 4 * manual: Bump aws-actions/amazon-ecr-login from 1 to 2 * manual: Bump aws-actions/configure-aws-credentials from 2 to 4 * fix: Solana Build Artifacts job --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../build-sign-publish-chainlink/action.yml | 2 +- .github/actions/delete-deployments/action.yml | 4 +-- .github/actions/golangci-lint/action.yml | 2 +- .../goreleaser-build-sign-publish/README.md | 4 +-- .github/actions/setup-nodejs/action.yaml | 4 +-- .github/actions/split-tests/action.yaml | 2 +- .../workflows/automation-benchmark-tests.yml | 2 +- .../workflows/automation-ondemand-tests.yml | 6 ++-- .github/workflows/build-publish-develop.yml | 2 +- .github/workflows/build-publish.yml | 4 +-- .github/workflows/build.yml | 2 +- .github/workflows/ci-chaincli.yml | 2 +- .github/workflows/ci-core.yml | 14 ++++---- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/delete-deployments.yml | 2 +- .github/workflows/dependency-check.yml | 4 +-- .../goreleaser-build-publish-develop.yml | 8 ++--- .github/workflows/helm-publish.yml | 2 +- .github/workflows/integration-chaos-tests.yml | 6 ++-- .../workflows/integration-staging-tests.yml | 2 +- .../workflows/integration-tests-publish.yml | 2 +- .github/workflows/integration-tests.yml | 32 ++++++++++--------- .github/workflows/lint-gh-workflows.yml | 2 +- .github/workflows/on-demand-ocr-soak-test.yml | 2 +- .../on-demand-vrfv2plus-performance-test.yml | 2 +- .github/workflows/operator-ui-cd.yml | 4 +-- .github/workflows/operator-ui-ci.yml | 2 +- .github/workflows/performance-tests.yml | 8 ++--- .github/workflows/solidity-foundry.yml | 4 +-- .github/workflows/solidity-hardhat.yml | 10 +++--- .github/workflows/solidity.yml | 12 +++---- ...evelop-from-smartcontractkit-chainlink.yml | 2 +- 32 files changed, 80 insertions(+), 78 deletions(-) diff --git a/.github/actions/build-sign-publish-chainlink/action.yml b/.github/actions/build-sign-publish-chainlink/action.yml index 853702045e..bd633bced7 100644 --- a/.github/actions/build-sign-publish-chainlink/action.yml +++ b/.github/actions/build-sign-publish-chainlink/action.yml @@ -99,7 +99,7 @@ runs: - if: inputs.publish == 'true' # Log in to AWS for publish to ECR name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ inputs.aws-role-to-assume }} role-duration-seconds: ${{ inputs.aws-role-duration-seconds }} diff --git a/.github/actions/delete-deployments/action.yml b/.github/actions/delete-deployments/action.yml index 20b7d0eefe..5fc7ef0287 100644 --- a/.github/actions/delete-deployments/action.yml +++ b/.github/actions/delete-deployments/action.yml @@ -29,11 +29,11 @@ inputs: runs: using: composite steps: - - uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd #v2.2.4 + - uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd # v2.2.4 with: version: ^8.0.0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version: "18" cache: "pnpm" diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index 5c4882e268..c0aeb529c1 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -30,7 +30,7 @@ inputs: runs: using: composite steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Go uses: ./.github/actions/setup-go with: diff --git a/.github/actions/goreleaser-build-sign-publish/README.md b/.github/actions/goreleaser-build-sign-publish/README.md index 49edfb25d5..d6bf7e6fd4 100644 --- a/.github/actions/goreleaser-build-sign-publish/README.md +++ b/.github/actions/goreleaser-build-sign-publish/README.md @@ -25,9 +25,9 @@ jobs: MACOS_SDK_VERSION: 12.3 steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.aws-role-arn }} role-duration-seconds: ${{ secrets.aws-role-dur-sec }} diff --git a/.github/actions/setup-nodejs/action.yaml b/.github/actions/setup-nodejs/action.yaml index 4e1740032b..1bb529b421 100644 --- a/.github/actions/setup-nodejs/action.yaml +++ b/.github/actions/setup-nodejs/action.yaml @@ -7,11 +7,11 @@ description: Setup pnpm for contracts runs: using: composite steps: - - uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd #v2.2.4 + - uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd # v2.2.4 with: version: ^7.0.0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version: "16" cache: "pnpm" diff --git a/.github/actions/split-tests/action.yaml b/.github/actions/split-tests/action.yaml index fc96c4da25..684fd6a2bd 100644 --- a/.github/actions/split-tests/action.yaml +++ b/.github/actions/split-tests/action.yaml @@ -15,7 +15,7 @@ runs: with: version: ^7.0.0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version: "16" cache: "pnpm" diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index 3d7466faed..45491af026 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -97,7 +97,7 @@ jobs: done done <<< "$EVM_HTTP_URLS" - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ env.REF_NAME }} - name: Build Test Image diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 032670c39a..20415b599e 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -53,7 +53,7 @@ jobs: this-job-name: Build Chainlink Image ${{ matrix.image.name }} continue-on-error: true - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.head_ref || github.ref_name }} - name: Check if image exists @@ -98,7 +98,7 @@ jobs: this-job-name: Build Test Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.head_ref || github.ref_name }} - name: Build Test Image @@ -149,7 +149,7 @@ jobs: name: Automation On Demand ${{ matrix.tests.name }} Test steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.head_ref || github.ref_name }} - name: Determine build to use diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index cba8edba3e..54ccaad581 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -31,7 +31,7 @@ jobs: name: push-chainlink-develop ${{ matrix.image.name }} steps: - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ env.GIT_REF }} # When this is ran from manual workflow_dispatch, the github.sha may be diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 9aa7b9accc..5db70576b3 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Check for VERSION file bump on tags if: ${{ startsWith(github.ref, 'refs/tags/v') }} uses: ./.github/actions/version-file-bump @@ -32,7 +32,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Build, sign and publish chainlink image uses: ./.github/actions/build-sign-publish-chainlink diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9931137d63..7cdf5e46b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Build chainlink image uses: ./.github/actions/build-sign-publish-chainlink diff --git a/.github/workflows/ci-chaincli.yml b/.github/workflows/ci-chaincli.yml index 97225e4655..fd58d08005 100644 --- a/.github/workflows/ci-chaincli.yml +++ b/.github/workflows/ci-chaincli.yml @@ -14,7 +14,7 @@ jobs: name: chaincli-lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Golang Lint uses: ./.github/actions/golangci-lint with: diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 74ca1dae9a..7bc91da3ab 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -22,7 +22,7 @@ jobs: name: lint runs-on: ubuntu20.04-8cores-32GB steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Golang Lint uses: ./.github/actions/golangci-lint with: @@ -40,9 +40,9 @@ jobs: CL_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainlink_test?sslmode=disable steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: @@ -126,9 +126,9 @@ jobs: CL_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainlink_test?sslmode=disable steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: @@ -183,7 +183,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 # fetches all history for all tags and branches to provide more metadata for sonar reports - name: Download all workflow run artifacts @@ -227,7 +227,7 @@ jobs: run: | echo "## \`skip-smoke-tests\` label is active, skipping E2E smoke tests" >>$GITHUB_STEP_SUMMARY exit 0 - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 - name: Setup Go diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 86f2515e26..822bf259f9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Go if: ${{ matrix.language == 'go' }} diff --git a/.github/workflows/delete-deployments.yml b/.github/workflows/delete-deployments.yml index a3d3100516..3ec5fb35c9 100644 --- a/.github/workflows/delete-deployments.yml +++ b/.github/workflows/delete-deployments.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Clean up integration environment uses: ./.github/actions/delete-deployments diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index ebfe1b947a..42729a8cf1 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -11,7 +11,7 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 id: changes with: @@ -25,7 +25,7 @@ jobs: needs: [changes] steps: - name: Check out code - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Go if: needs.changes.outputs.src == 'true' diff --git a/.github/workflows/goreleaser-build-publish-develop.yml b/.github/workflows/goreleaser-build-publish-develop.yml index 9e9b088033..1edfdedd70 100644 --- a/.github/workflows/goreleaser-build-publish-develop.yml +++ b/.github/workflows/goreleaser-build-publish-develop.yml @@ -18,9 +18,9 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }} role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} @@ -55,9 +55,9 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_GATI }} role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} diff --git a/.github/workflows/helm-publish.yml b/.github/workflows/helm-publish.yml index e80d758d81..48a7060fc7 100644 --- a/.github/workflows/helm-publish.yml +++ b/.github/workflows/helm-publish.yml @@ -12,7 +12,7 @@ jobs: contents: read steps: - name: Checkout repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials uses: aws-actions/configure-aws-credentials@50ac8dd1e1b10d09dac7b8727528b91bed831ac0 # v3.0.2 diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index a9aa2c35df..503e5ec58a 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Check if image exists id: check-image uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 @@ -69,7 +69,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Build Test Image uses: ./.github/actions/build-test-image with: @@ -107,7 +107,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml index a6fda178d5..2abb9a3cfa 100644 --- a/.github/workflows/integration-staging-tests.yml +++ b/.github/workflows/integration-staging-tests.yml @@ -50,7 +50,7 @@ jobs: WASP_LOG_LEVEL: info steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 - name: Run E2E soak tests diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index c71b83d1c4..06f7bb1b81 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -27,7 +27,7 @@ jobs: this-job-name: Publish Integration Test Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha }} - name: Build Image diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index aadb14f128..edd7755e8b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 id: changes with: @@ -81,7 +81,7 @@ jobs: this-job-name: Build Chainlink Image ${{ matrix.image.name }} continue-on-error: true - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Check if image exists @@ -129,7 +129,7 @@ jobs: this-job-name: Build Test Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Test Image @@ -153,7 +153,7 @@ jobs: echo "## \`skip-smoke-tests\` label is active, skipping E2E smoke tests" >>$GITHUB_STEP_SUMMARY exit 0 - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Compare Test Lists run: | cd ./integration-tests @@ -190,7 +190,7 @@ jobs: name: ETH Smoke Tests ${{ matrix.product.name }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Go Test Command @@ -303,7 +303,7 @@ jobs: name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Go Test Command @@ -484,7 +484,7 @@ jobs: steps: - name: Checkout repo if: ${{ github.event_name == 'pull_request' }} - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: 🧼 Clean up Environment if: ${{ github.event_name == 'pull_request' }} @@ -513,7 +513,7 @@ jobs: continue-on-error: true steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Setup @@ -552,7 +552,7 @@ jobs: TEST_SUITE: migration steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Get Latest Version @@ -608,7 +608,7 @@ jobs: sha: ${{ steps.getsha.outputs.sha }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Get the sha from go mod @@ -619,7 +619,7 @@ jobs: echo "short sha is: ${short_sha}" echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" - name: Checkout solana - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: smartcontractkit/chainlink-solana ref: develop @@ -642,7 +642,7 @@ jobs: projectserum_version: ${{ steps.psversion.outputs.projectserum_version }} steps: - name: Checkout the solana repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -704,6 +704,8 @@ jobs: this-job-name: Solana Build Artifacts continue-on-error: true - name: Checkout the solana repo + # Use v3.6.0 because the custom runner (container configured above) + # doesn't have node20 installed which is required for versions >=4 uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: repository: smartcontractkit/chainlink-solana @@ -744,7 +746,7 @@ jobs: continue-on-error: true - name: Checkout the repo if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: smartcontractkit/chainlink-solana ref: 23816fcf7d380a30c87b6d87e4fb0ca94419b259 # swtich back to this after the next solana release${{ needs.get_solana_sha.outputs.sha }} @@ -802,7 +804,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -915,7 +917,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} ## Only run OCR smoke test for now diff --git a/.github/workflows/lint-gh-workflows.yml b/.github/workflows/lint-gh-workflows.yml index 1220f3a745..8facdc038c 100644 --- a/.github/workflows/lint-gh-workflows.yml +++ b/.github/workflows/lint-gh-workflows.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out Code - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run actionlint uses: reviewdog/action-actionlint@82693e9e3b239f213108d6e412506f8b54003586 # v1.39.1 - name: Collect Metrics diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index cd14114226..7dc144264d 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -110,7 +110,7 @@ jobs: echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ env.REF_NAME }} - name: Setup Push Tag diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index b33c6f8313..41b6618ba6 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -114,7 +114,7 @@ jobs: echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 - name: Run Tests diff --git a/.github/workflows/operator-ui-cd.yml b/.github/workflows/operator-ui-cd.yml index 4f6e82e07b..36a9d8b715 100644 --- a/.github/workflows/operator-ui-cd.yml +++ b/.github/workflows/operator-ui-cd.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Update version id: update @@ -25,7 +25,7 @@ jobs: run: ./operator_ui/check.sh - name: Assume role capable of dispatching action - uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.AWS_OIDC_CHAINLINK_CI_AUTO_PR_TOKEN_ISSUER_ROLE_ARN }} role-duration-seconds: ${{ secrets.aws-role-duration-seconds }} diff --git a/.github/workflows/operator-ui-ci.yml b/.github/workflows/operator-ui-ci.yml index 8ced3b222c..2ce85bc132 100644 --- a/.github/workflows/operator-ui-ci.yml +++ b/.github/workflows/operator-ui-ci.yml @@ -23,7 +23,7 @@ jobs: continue-on-error: true - name: Assume role capable of dispatching action - uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.AWS_OIDC_CHAINLINK_CI_OPERATOR_UI_ACCESS_TOKEN_ISSUER_ROLE_ARN }} role-duration-seconds: 3600 diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index b79d8dfea2..43ed80cb3f 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -18,16 +18,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: aws-region: ${{ secrets.QA_AWS_REGION }} role-to-assume: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} role-duration-seconds: 3600 - name: Login to Amazon ECR id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 + uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # v2.7.0 - name: Build and Push @@ -55,7 +55,7 @@ jobs: needs: build-chainlink steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 590165c8e7..f6c515b5b8 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -12,7 +12,7 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 id: changes with: @@ -41,7 +41,7 @@ jobs: steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: recursive diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index 334ce4d1ba..6e7de2eba1 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -19,7 +19,7 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 id: changes with: @@ -40,7 +40,7 @@ jobs: splits: ${{ steps.split.outputs.splits }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Generate splits id: split uses: ./.github/actions/split-tests @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu20.04-4cores-16GB steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs - name: Setup Hardhat @@ -104,7 +104,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs - name: Make coverage directory @@ -131,7 +131,7 @@ jobs: runs-on: ubuntu20.04-4cores-16GB steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs - name: Setup Hardhat diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index b2537a5c9a..f46b13191d 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -16,7 +16,7 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 id: changes with: @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs - name: Run Prepublish test @@ -54,9 +54,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Checkout diff-so-fancy - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: so-fancy/diff-so-fancy ref: a673cb4d2707f64d92b86498a2f5f71c8e2643d5 # v1.4.3 @@ -101,7 +101,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs - name: Run pnpm lint @@ -126,7 +126,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup NodeJS if: needs.changes.outputs.changes == 'true' uses: ./.github/actions/setup-nodejs diff --git a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml index 9703765203..7fe9ffd526 100644 --- a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml +++ b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml @@ -10,7 +10,7 @@ jobs: name: Sync runs-on: ubuntu-latest steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: develop if: env.GITHUB_REPOSITORY != 'smartcontractkit/chainlink' From 45b59578f369f221465dea339d368bd3beec175c Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 26 Oct 2023 06:11:53 -0500 Subject: [PATCH 012/327] .github/workflows: add slack notification to nightly golangci-lint (#11088) --- .github/workflows/ci-core.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 7bc91da3ab..4037dc0cd9 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -28,6 +28,14 @@ jobs: with: gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} + - name: Notify Slack + if: ${{ failure() && github.event.schedule != '' }} + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + with: + channel-id: "#team-core" + slack-message: "golangci-lint failed: ${{ job.html_url }}\n${{ format('https://github.com/smartcontractkit/chainlink/actions/runs/{0}', github.run_id) }}" core: strategy: From b31284ba5a12c7b675bd942cc8f4b2598232f5a7 Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Thu, 26 Oct 2023 15:26:50 +0200 Subject: [PATCH 013/327] make maxCheck and maxPerform configurable (#11083) * Make maxCheck and maxPerform configurable - maxCheck and maxPerform can be configured. - Values for these have to be provided in the constructor. - Adhere to Solidity Style Guide in imports, varnames, etc. * add tests * add custom errors on require methods * add proposed fixes * make LINK_TOKEN private --- .../upkeeps/LinkAvailableBalanceMonitor.sol | 240 ++++---- .../contracts/utils/structs/EnumerableMap.sol | 530 ++++++++++++++++++ .../LinkAvailableBalanceMonitor.test.ts | 15 +- 3 files changed, 659 insertions(+), 126 deletions(-) create mode 100644 contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index cff09aaebb..028579397a 100644 --- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.6; -import "../../shared/access/ConfirmedOwner.sol"; -import "../interfaces/KeeperCompatibleInterface.sol"; -import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; -import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableMap.sol"; +import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; interface IAggregatorProxy { function aggregator() external view returns (address); @@ -16,60 +16,63 @@ interface ILinkAvailable { function linkAvailableForPayment() external view returns (int256 availableBalance); } -/** - * @title The LinkAvailableBalanceMonitor contract. - * @notice A keeper-compatible contract that monitors target contracts for balance from a custom - * function linkAvailableForPayment() and funds them with LINK if it falls below a defined - * threshold. Also supports aggregator proxy contracts monitoring which require fetching the actual - * target contract through a predefined interface. - * @dev with 30 addresses as the MAX_PERFORM, the measured max gas usage of performUpkeep is around 2M - * therefore, we recommend an upkeep gas limit of 3M (this has a 33% margin of safety). Although, nothing - * prevents us from using 5M gas and increasing MAX_PERFORM, 30 seems like a reasonable batch size that - * is probably plenty for most needs. - * @dev with 130 addresses as the MAX_CHECK, the measured max gas usage of checkUpkeep is around 3.5M, - * which is 30% below the 5M limit. - * Note that testing conditions DO NOT match live chain gas usage, hence the margins. Change - * at your own risk!!! - * @dev some areas for improvement / acknowledgement of limitations: - * * validate that all addresses conform to interface when adding them to the watchlist - * * this is a "trusless" upkeep, meaning it does not trust the caller of performUpkeep; - we could save a fair amount of gas and re-write this upkeep for use with Automation v2.0+, - which has significantly different trust assumptions - */ -contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatibleInterface { +/// @title The LinkAvailableBalanceMonitor contract. +/// @notice A keeper-compatible contract that monitors target contracts for balance from a custom +/// function linkAvailableForPayment() and funds them with LINK if it falls below a defined +/// threshold. Also supports aggregator proxy contracts monitoring which require fetching the actual +/// target contract through a predefined interface. +/// @dev with 30 addresses as the s_maxPerform, the measured max gas usage of performUpkeep is around 2M +/// therefore, we recommend an upkeep gas limit of 3M (this has a 33% margin of safety). Although, nothing +/// prevents us from using 5M gas and increasing s_maxPerform, 30 seems like a reasonable batch size that +/// is probably plenty for most needs. +/// @dev with 130 addresses as the s_maxCheck, the measured max gas usage of checkUpkeep is around 3.5M, +/// which is 30% below the 5M limit. +/// Note that testing conditions DO NOT match live chain gas usage, hence the margins. Change +/// at your own risk!!! +/// @dev some areas for improvement / acknowledgement of limitations: +/// validate that all addresses conform to interface when adding them to the watchlist +/// this is a "trusless" upkeep, meaning it does not trust the caller of performUpkeep; +/// we could save a fair amount of gas and re-write this upkeep for use with Automation v2.0+, +/// which has significantly different trust assumptions +contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationCompatibleInterface { using EnumerableMap for EnumerableMap.AddressToUintMap; event FundsWithdrawn(uint256 amountWithdrawn, address payee); event TopUpSucceeded(address indexed topUpAddress); event TopUpBlocked(address indexed topUpAddress); event WatchlistUpdated(); + event MaxPerformUpdated(uint256 oldMaxPerform, uint256 newMaxPerform); + event MaxCheckUpdated(uint256 oldMaxCheck, uint256 newMaxCheck); error InvalidWatchList(); error DuplicateAddress(address duplicate); - uint256 public constant MAX_PERFORM = 5; // max number to addresses to top up in a single batch - uint256 public constant MAX_CHECK = 20; // max number of upkeeps to check (need to fit in 5M gas limit) - IERC20 public immutable LINK_TOKEN; - + IERC20 private immutable LINK_TOKEN; EnumerableMap.AddressToUintMap private s_watchList; uint256 private s_topUpAmount; + uint32 private s_minWaitPeriodSeconds; + uint16 private s_maxPerform; + uint16 private s_maxCheck; - /** - * @param linkTokenAddress the LINK token address - * @param topUpAmount the amount of LINK to top up an aggregator with at once - */ - constructor(address linkTokenAddress, uint256 topUpAmount) ConfirmedOwner(msg.sender) { - require(linkTokenAddress != address(0)); - require(topUpAmount > 0); + /// @param linkTokenAddress the LINK token address + /// @param topUpAmount the amount of LINK to top up an aggregator with at once + constructor( + address linkTokenAddress, + uint256 topUpAmount, + uint16 maxPerform, + uint16 maxCheck + ) ConfirmedOwner(msg.sender) { + require(linkTokenAddress != address(0), "LinkAvailableBalanceMonitor: invalid linkTokenAddress"); + require(topUpAmount > 0, "LinkAvailableBalanceMonitor: invalid topUpAmount"); LINK_TOKEN = IERC20(linkTokenAddress); s_topUpAmount = topUpAmount; + s_maxPerform = maxPerform; + s_maxCheck = maxCheck; } - /** - * @notice Sets the list of subscriptions to watch and their funding parameters - * @param addresses the list of target addresses to watch (could be direct target or IAggregatorProxy) - * @param minBalances the list of corresponding minBalance for the target address - */ + /// @notice Sets the list of subscriptions to watch and their funding parameters + /// @param addresses the list of target addresses to watch (could be direct target or IAggregatorProxy) + /// @param minBalances the list of corresponding minBalance for the target address function setWatchList(address[] calldata addresses, uint256[] calldata minBalances) external onlyOwner { if (addresses.length != minBalances.length) { revert InvalidWatchList(); @@ -77,7 +80,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib // first, remove all existing addresses from list for (uint256 idx = s_watchList.length(); idx > 0; idx--) { (address target, ) = s_watchList.at(idx - 1); - require(s_watchList.remove(target)); + require(s_watchList.remove(target), "LinkAvailableBalanceMonitor: unable to setWatchlist"); } // then set new addresses for (uint256 idx = 0; idx < addresses.length; idx++) { @@ -92,11 +95,9 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib emit WatchlistUpdated(); } - /** - * @notice Adds addresses to the watchlist without overwriting existing members - * @param addresses the list of target addresses to watch (could be direct target or IAggregatorProxy) - * @param minBalances the list of corresponding minBalance for the target address - */ + /// @notice Adds addresses to the watchlist without overwriting existing members + /// @param addresses the list of target addresses to watch (could be direct target or IAggregatorProxy) + /// @param minBalances the list of corresponding minBalance for the target address function addToWatchList(address[] calldata addresses, uint256[] calldata minBalances) external onlyOwner { if (addresses.length != minBalances.length) { revert InvalidWatchList(); @@ -113,10 +114,8 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib emit WatchlistUpdated(); } - /** - * @notice Removes addresses from the watchlist - * @param addresses the list of target addresses to remove from the watchlist - */ + /// @notice Removes addresses from the watchlist + /// @param addresses the list of target addresses to remove from the watchlist function removeFromWatchlist(address[] calldata addresses) external onlyOwner { for (uint256 idx = 0; idx < addresses.length; idx++) { if (!s_watchList.contains(addresses[idx])) { @@ -127,33 +126,36 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib emit WatchlistUpdated(); } - /** - * @notice Gets a list of proxies that are underfunded, up to the MAX_PERFORM size - * @dev the function starts at a random index in the list to avoid biasing the first - * addresses in the list over latter ones. - * @dev the function will check at most MAX_CHECK proxies in a single call - * @dev the function returns a list with a max length of MAX_PERFORM - * @return list of target addresses which are underfunded - */ + /// @notice Gets a list of proxies that are underfunded, up to the s_maxPerform size + /// @dev the function starts at a random index in the list to avoid biasing the first + /// addresses in the list over latter ones. + /// @dev the function will check at most s_maxCheck proxies in a single call + /// @dev the function returns a list with a max length of s_maxPerform + /// @return list of target addresses which are underfunded function sampleUnderfundedAddresses() public view returns (address[] memory) { + uint16 maxPerform = s_maxPerform; + uint16 maxCheck = s_maxCheck; uint256 numTargets = s_watchList.length(); - uint256 numChecked = 0; uint256 idx = uint256(blockhash(block.number - 1)) % numTargets; // start at random index, to distribute load - uint256 numToCheck = numTargets < MAX_CHECK ? numTargets : MAX_CHECK; + uint256 numToCheck = numTargets < maxCheck ? numTargets : maxCheck; uint256 numFound = 0; - address[] memory targetsToFund = new address[](MAX_PERFORM); - for (; numChecked < numToCheck; (idx, numChecked) = ((idx + 1) % numTargets, numChecked + 1)) { + address[] memory targetsToFund = new address[](maxPerform); + for ( + uint256 numChecked = 0; + numChecked < numToCheck; + (idx, numChecked) = ((idx + 1) % numTargets, numChecked + 1) + ) { (address target, uint256 minBalance) = s_watchList.at(idx); (bool needsFunding, ) = _needsFunding(target, minBalance); if (needsFunding) { targetsToFund[numFound] = target; numFound++; - if (numFound == MAX_PERFORM) { + if (numFound == maxPerform) { break; // max number of addresses in batch reached } } } - if (numFound != MAX_PERFORM) { + if (numFound != maxPerform) { assembly { mstore(targetsToFund, numFound) // resize array to number of valid targets } @@ -161,10 +163,8 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib return targetsToFund; } - /** - * @notice Send funds to the targets provided. - * @param targetAddresses the list of targets to fund - */ + /// @notice Send funds to the targets provided. + /// @param targetAddresses the list of targets to fund function topUp(address[] memory targetAddresses) public whenNotPaused { uint256 topUpAmount = s_topUpAmount; uint256 stopIdx = targetAddresses.length; @@ -186,11 +186,9 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib } } - /** - * @notice Gets list of subscription ids that are underfunded and returns a keeper-compatible payload. - * @return upkeepNeeded signals if upkeep is needed - * @return performData is an abi encoded list of subscription ids that need funds - */ + /// @notice Gets list of subscription ids that are underfunded and returns a keeper-compatible payload. + /// @return upkeepNeeded signals if upkeep is needed + /// @return performData is an abi encoded list of subscription ids that need funds function checkUpkeep( bytes calldata ) external view override whenNotPaused returns (bool upkeepNeeded, bytes memory performData) { @@ -206,39 +204,31 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib return (upkeepNeeded, performData); } - /** - * @notice Called by the keeper to send funds to underfunded addresses. - * @param performData the abi encoded list of addresses to fund - */ + /// @notice Called by the keeper to send funds to underfunded addresses. + /// @param performData the abi encoded list of addresses to fund function performUpkeep(bytes calldata performData) external override { address[] memory needsFunding = abi.decode(performData, (address[])); topUp(needsFunding); } - /** - * @notice Withdraws the contract balance in the LINK token. - * @param amount the amount of the LINK to withdraw - * @param payee the address to pay - */ + /// @notice Withdraws the contract balance in the LINK token. + /// @param amount the amount of the LINK to withdraw + /// @param payee the address to pay function withdraw(uint256 amount, address payable payee) external onlyOwner { - require(payee != address(0)); + require(payee != address(0), "LinkAvailableBalanceMonitor: invalid payee address"); LINK_TOKEN.transfer(payee, amount); emit FundsWithdrawn(amount, payee); } - /** - * @notice Sets the top up amount - */ + /// @notice Sets the top up amount function setTopUpAmount(uint256 topUpAmount) external onlyOwner returns (uint256) { - require(topUpAmount > 0); + require(topUpAmount > 0, "LinkAvailableBalanceMonitor: invalid linkTokenAddress"); return s_topUpAmount = topUpAmount; } - /** - * @notice Sets the minimum balance for the given target address - */ + /// @notice Sets the minimum balance for the given target address function setMinBalance(address target, uint256 minBalance) external onlyOwner returns (uint256) { - require(minBalance > 0); + require(minBalance > 0, "LinkAvailableBalanceMonitor: invalid minBalance"); (bool exists, uint256 prevMinBalance) = s_watchList.tryGet(target); if (!exists) { revert InvalidWatchList(); @@ -247,23 +237,29 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib return prevMinBalance; } - /** - * @notice Pause the contract, which prevents executing performUpkeep - */ - function pause() external onlyOwner { - _pause(); + /// @notice Update s_maxPerform + function setMaxPerform(uint16 maxPerform) external onlyOwner { + emit MaxPerformUpdated(s_maxPerform, maxPerform); + s_maxPerform = maxPerform; } - /** - * @notice Unpause the contract - */ - function unpause() external onlyOwner { - _unpause(); + /// @notice Update s_maxCheck + function setMaxCheck(uint16 maxCheck) external onlyOwner { + emit MaxCheckUpdated(s_maxCheck, maxCheck); + s_maxCheck = maxCheck; + } + + /// @notice Gets maxPerform + function getMaxPerform() external view returns (uint16) { + return s_maxPerform; + } + + /// @notice Gets maxCheck + function getMaxCheck() external view returns (uint16) { + return s_maxCheck; } - /** - * @notice Gets the list of subscription ids being watched - */ + /// @notice Gets the list of subscription ids being watched function getWatchList() external view returns (address[] memory, uint256[] memory) { uint256 len = s_watchList.length(); address[] memory targets = new address[](len); @@ -276,16 +272,12 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib return (targets, minBalances); } - /** - * @notice Gets the configured top up amount - */ + /// @notice Gets the configured top up amount function getTopUpAmount() external view returns (uint256) { return s_topUpAmount; } - /** - * @notice Gets the configured minimum balance for the given target - */ + /// @notice Gets the configured minimum balance for the given target function getMinBalance(address target) external view returns (uint256) { (bool exists, uint256 minBalance) = s_watchList.tryGet(target); if (!exists) { @@ -294,14 +286,22 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompatib return minBalance; } - /** - * @notice checks the target (could be direct target or IAggregatorProxy), and determines - * if it is elligible for funding - * @param targetAddress the target to check - * @param minBalance minimum balance required for the target - * @return bool whether the target needs funding or not - * @return address the address of the contract needing funding - */ + /// @notice Pause the contract, which prevents executing performUpkeep + function pause() external onlyOwner { + _pause(); + } + + /// @notice Unpause the contract + function unpause() external onlyOwner { + _unpause(); + } + + /// @notice checks the target (could be direct target or IAggregatorProxy), and determines + /// if it is elligible for funding + /// @param targetAddress the target to check + /// @param minBalance minimum balance required for the target + /// @return bool whether the target needs funding or not + /// @return address the address of the contract needing funding function _needsFunding(address targetAddress, uint256 minBalance) private view returns (bool, address) { ILinkAvailable target; IAggregatorProxy proxy = IAggregatorProxy(targetAddress); diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol new file mode 100644 index 0000000000..7f4e9115b1 --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableMap.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. + +pragma solidity ^0.8.0; + +import "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (O(1)). + * - Entries are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableMap for EnumerableMap.UintToAddressMap; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * The following map types are supported: + * + * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 + * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 + * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 + * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 + * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +library EnumerableMap { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Map type with + // bytes32 keys and values. + // The Map implementation uses private functions, and user-facing + // implementations (such as Uint256ToAddressMap) are just wrappers around + // the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit + // in bytes32. + + struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 => bytes32) _values; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set( + Bytes32ToBytes32Map storage map, + bytes32 key, + bytes32 value + ) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); + return value; + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + Bytes32ToBytes32Map storage map, + bytes32 key, + string memory errorMessage + ) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), errorMessage); + return value; + } + + // UintToUintMap + + struct UintToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set( + UintToUintMap storage map, + uint256 key, + uint256 value + ) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the set. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + UintToUintMap storage map, + uint256 key, + string memory errorMessage + ) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key), errorMessage)); + } + + // UintToAddressMap + + struct UintToAddressMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set( + UintToAddressMap storage map, + uint256 key, + address value + ) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the set. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), address(uint160(uint256(value)))); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(value)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + UintToAddressMap storage map, + uint256 key, + string memory errorMessage + ) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage)))); + } + + // AddressToUintMap + + struct AddressToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set( + AddressToUintMap storage map, + address key, + uint256 value + ) internal returns (bool) { + return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(AddressToUintMap storage map, address key) internal returns (bool) { + return remove(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(AddressToUintMap storage map, address key) internal view returns (bool) { + return contains(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(AddressToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the set. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (address(uint160(uint256(key))), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(AddressToUintMap storage map, address key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + AddressToUintMap storage map, + address key, + string memory errorMessage + ) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage)); + } + + // Bytes32ToUintMap + + struct Bytes32ToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set( + Bytes32ToUintMap storage map, + bytes32 key, + uint256 value + ) internal returns (bool) { + return set(map._inner, key, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { + return remove(map._inner, key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { + return contains(map._inner, key); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(Bytes32ToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the set. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (key, uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, key); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { + return uint256(get(map._inner, key)); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + Bytes32ToUintMap storage map, + bytes32 key, + string memory errorMessage + ) internal view returns (uint256) { + return uint256(get(map._inner, key, errorMessage)); + } +} \ No newline at end of file diff --git a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts index 4efd98039f..af0063fb50 100644 --- a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts @@ -35,7 +35,6 @@ const zeroLINK = ethers.utils.parseEther('0') const oneLINK = ethers.utils.parseEther('1') const twoLINK = ethers.utils.parseEther('2') const fiveLINK = ethers.utils.parseEther('5') -const sixLINK = ethers.utils.parseEther('6') const tenLINK = ethers.utils.parseEther('10') const oneHundredLINK = ethers.utils.parseEther('100') @@ -142,8 +141,12 @@ const setup = async () => { owner, ) - lt = await ltFactory.deploy() - labm = await labmFactory.deploy(lt.address, twoLINK) + // New parameters needed by the constructor + const maxPerform = 5 + const maxCheck = 20 + + lt = (await ltFactory.deploy()) as LinkToken + labm = await labmFactory.deploy(lt.address, twoLINK, maxPerform, maxCheck) await labm.deployed() for (let i = 1; i <= 4; i++) { @@ -471,8 +474,8 @@ describe('LinkAvailableBalanceMonitor', () => { let aggregators: MockContract[] beforeEach(async () => { - MAX_PERFORM = (await labm.MAX_PERFORM()).toNumber() - MAX_CHECK = (await labm.MAX_CHECK()).toNumber() + MAX_PERFORM = await labm.getMaxPerform() + MAX_CHECK = await labm.getMaxCheck() proxyAddresses = [] minBalances = [] aggregators = [] @@ -577,7 +580,7 @@ describe('LinkAvailableBalanceMonitor', () => { it('Can handle MAX_PERFORM proxies within gas limit', async () => { // add MAX_PERFORM number of proxies - const MAX_PERFORM = (await labm.MAX_PERFORM()).toNumber() + const MAX_PERFORM = await labm.getMaxPerform() const proxyAddresses = [] const minBalances = [] for (let idx = 0; idx < MAX_PERFORM; idx++) { From 09f0afdef4ec46909d6d3cdc2f3a12f4fcec9ca8 Mon Sep 17 00:00:00 2001 From: Jean Arnaud Date: Thu, 26 Oct 2023 15:58:27 +0200 Subject: [PATCH 014/327] Add missing fields to generated Deploy methods (#11061) * Add missing fields to generated Deploy methods * Regenerate wrappers * Abigen test * Error handling * Test Address method returning the proper address * Update generated wrappers * Refactor method and check type assertion * Format --- core/gethwrappers/abigen.go | 61 ++++++++++++++++--- core/gethwrappers/abigen_test.go | 29 +++++++++ .../generated/functions/functions.go | 2 +- .../functions_allow_list.go | 2 +- .../functions_client_example.go | 2 +- .../functions_coordinator.go | 2 +- .../functions_load_test_client.go | 2 +- .../functions_router/functions_router.go | 2 +- .../functions_v1_events_mock.go | 2 +- .../functions/generated/ocr2dr/ocr2dr.go | 2 +- .../ocr2dr_client_example.go | 2 +- .../generated/ocr2dr_oracle/ocr2dr_oracle.go | 2 +- .../ocr2dr_registry/ocr2dr_registry.go | 2 +- .../authorized_forwarder.go | 2 +- .../automation_consumer_benchmark.go | 2 +- .../automation_forwarder_logic.go | 2 +- .../automation_registrar_wrapper2_1.go | 2 +- .../automation_utils_2_1.go | 2 +- .../batch_blockhash_store.go | 2 +- .../batch_vrf_coordinator_v2.go | 2 +- .../batch_vrf_coordinator_v2plus.go | 2 +- .../blockhash_store/blockhash_store.go | 2 +- .../chain_specific_util_helper.go | 2 +- .../consumer_wrapper/consumer_wrapper.go | 2 +- .../dummy_protocol_wrapper.go | 2 +- .../generated/flags_wrapper/flags_wrapper.go | 2 +- .../flux_aggregator_wrapper.go | 2 +- .../functions_billing_registry_events_mock.go | 2 +- .../functions_oracle_events_mock.go | 2 +- .../generated/gas_wrapper/gas_wrapper.go | 2 +- .../gas_wrapper_mock/gas_wrapper_mock.go | 2 +- .../keeper_consumer_performance_wrapper.go | 2 +- .../keeper_consumer_wrapper.go | 2 +- .../keeper_registrar_wrapper1_2.go | 2 +- .../keeper_registrar_wrapper1_2_mock.go | 2 +- .../keeper_registrar_wrapper2_0.go | 2 +- .../keeper_registry_logic1_3.go | 2 +- .../keeper_registry_logic2_0.go | 2 +- .../keeper_registry_logic_a_wrapper_2_1.go | 2 +- .../keeper_registry_logic_b_wrapper_2_1.go | 2 +- .../keeper_registry_wrapper1_1.go | 2 +- .../keeper_registry_wrapper1_1_mock.go | 2 +- .../keeper_registry_wrapper1_2.go | 2 +- .../keeper_registry_wrapper1_3.go | 2 +- .../keeper_registry_wrapper2_0.go | 2 +- .../keeper_registry_wrapper_2_1.go | 2 +- .../keepers_vrf_consumer.go | 2 +- .../link_token_interface.go | 2 +- .../generated/log_emitter/log_emitter.go | 2 +- .../log_triggered_streams_lookup_wrapper.go | 2 +- .../log_upkeep_counter_wrapper.go | 2 +- .../mock_aggregator_proxy.go | 2 +- .../mock_ethlink_aggregator_wrapper.go | 2 +- .../mock_gas_aggregator_wrapper.go | 2 +- .../multiwordconsumer_wrapper.go | 2 +- .../operator_factory/operator_factory.go | 2 +- .../operator_wrapper/operator_wrapper.go | 2 +- .../oracle_wrapper/oracle_wrapper.go | 2 +- .../perform_data_checker_wrapper.go | 2 +- .../solidity_vrf_consumer_interface.go | 2 +- .../solidity_vrf_consumer_interface_v08.go | 2 +- .../solidity_vrf_coordinator_interface.go | 2 +- .../solidity_vrf_request_id.go | 2 +- .../solidity_vrf_request_id_v08.go | 2 +- .../solidity_vrf_v08_verifier_wrapper.go | 2 +- .../solidity_vrf_verifier_wrapper.go | 2 +- .../solidity_vrf_wrapper.go | 2 +- .../streams_lookup_upkeep_wrapper.go | 2 +- .../test_api_consumer_wrapper.go | 2 +- .../trusted_blockhash_store.go | 2 +- .../upkeep_counter_wrapper.go | 2 +- ...eep_perform_counter_restrictive_wrapper.go | 2 +- .../upkeep_transcoder/upkeep_transcoder.go | 2 +- ...ifiable_load_log_trigger_upkeep_wrapper.go | 2 +- ...able_load_streams_lookup_upkeep_wrapper.go | 2 +- .../verifiable_load_upkeep_wrapper.go | 2 +- .../vrf_consumer_v2/vrf_consumer_v2.go | 2 +- ...rf_consumer_v2_plus_upgradeable_example.go | 2 +- .../vrf_consumer_v2_upgradeable_example.go | 2 +- .../vrf_coordinator_mock.go | 2 +- .../vrf_coordinator_v2/vrf_coordinator_v2.go | 2 +- .../vrf_coordinator_v2_5.go | 2 +- .../vrf_coordinator_v2_plus_v2_example.go | 2 +- .../vrf_external_sub_owner_example.go | 2 +- .../vrf_load_test_external_sub_owner.go | 2 +- .../vrf_load_test_ownerless_consumer.go | 2 +- .../vrf_load_test_with_metrics.go | 2 +- .../vrf_malicious_consumer_v2.go | 2 +- .../vrf_malicious_consumer_v2_plus.go | 2 +- .../generated/vrf_owner/vrf_owner.go | 2 +- .../vrf_owner_test_consumer.go | 2 +- .../vrf_ownerless_consumer_example.go | 2 +- .../vrf_single_consumer_example.go | 2 +- .../vrf_v2_consumer_wrapper.go | 2 +- .../vrf_v2plus_load_test_with_metrics.go | 2 +- .../vrf_v2plus_single_consumer.go | 2 +- .../vrf_v2plus_sub_owner.go | 2 +- .../vrf_v2plus_upgraded_version.go | 2 +- .../vrfv2_proxy_admin/vrfv2_proxy_admin.go | 2 +- .../vrfv2_reverting_example.go | 2 +- .../vrfv2_transparent_upgradeable_proxy.go | 2 +- .../generated/vrfv2_wrapper/vrfv2_wrapper.go | 2 +- .../vrfv2_wrapper_consumer_example.go | 2 +- .../vrfv2plus_client/vrfv2plus_client.go | 2 +- .../vrfv2plus_consumer_example.go | 2 +- .../vrfv2plus_malicious_migrator.go | 2 +- .../vrfv2plus_reverting_example.go | 2 +- .../vrfv2plus_wrapper/vrfv2plus_wrapper.go | 2 +- .../vrfv2plus_wrapper_consumer_example.go | 2 +- .../vrfv2plus_wrapper_load_test_consumer.go | 2 +- core/gethwrappers/go_generate.go | 2 +- .../errored_verifier/errored_verifier.go | 2 +- .../exposed_verifier/exposed_verifier.go | 2 +- .../generated/fee_manager/fee_manager.go | 2 +- .../reward_manager/reward_manager.go | 2 +- .../llo-feeds/generated/verifier/verifier.go | 2 +- .../verifier_proxy/verifier_proxy.go | 2 +- .../burn_mint_erc677/burn_mint_erc677.go | 2 +- .../shared/generated/erc20/erc20.go | 2 +- .../shared/generated/link_token/link_token.go | 2 +- .../generated/werc20_mock/werc20_mock.go | 2 +- .../generated/entry_point/entry_point.go | 2 +- .../greeter_wrapper/greeter_wrapper.go | 2 +- .../paymaster_wrapper/paymaster_wrapper.go | 2 +- .../generated/sca_wrapper/sca_wrapper.go | 2 +- .../smart_contract_account_factory.go | 2 +- .../smart_contract_account_helper.go | 2 +- 127 files changed, 207 insertions(+), 133 deletions(-) create mode 100644 core/gethwrappers/abigen_test.go diff --git a/core/gethwrappers/abigen.go b/core/gethwrappers/abigen.go index 5affe54657..d96d9f8c30 100644 --- a/core/gethwrappers/abigen.go +++ b/core/gethwrappers/abigen.go @@ -159,9 +159,17 @@ func getContractName(fileNode *ast.File) string { return contractName } +// Add the `.address` and `.abi` fields to the contract struct. func addContractStructFields(contractName string, fileNode *ast.File) *ast.File { - // Add the `.address` and `.abi` fields to the contract struct - fileNode = astutil.Apply(fileNode, func(cursor *astutil.Cursor) bool { + fileNode = addContractStructFieldsToStruct(contractName, fileNode) + fileNode = addContractStructFieldsToConstructor(contractName, fileNode) + fileNode = addContractStructFieldsToDeployMethod(contractName, fileNode) + return fileNode +} + +// Add the fields to the contract struct. +func addContractStructFieldsToStruct(contractName string, fileNode *ast.File) *ast.File { + return astutil.Apply(fileNode, func(cursor *astutil.Cursor) bool { x, is := cursor.Node().(*ast.StructType) if !is { return true @@ -188,14 +196,14 @@ func addContractStructFields(contractName string, fileNode *ast.File) *ast.File Sel: ast.NewIdent("ABI"), }, } - x.Fields.List = append([]*ast.Field{addrField, abiField}, x.Fields.List...) - return false }, nil).(*ast.File) +} - // Add the fields to the return value of the constructor - fileNode = astutil.Apply(fileNode, func(cursor *astutil.Cursor) bool { +// Add the fields to the return value of the constructor. +func addContractStructFieldsToConstructor(contractName string, fileNode *ast.File) *ast.File { + return astutil.Apply(fileNode, func(cursor *astutil.Cursor) bool { x, is := cursor.Node().(*ast.FuncDecl) if !is { return true @@ -260,11 +268,48 @@ func addContractStructFields(contractName string, fileNode *ast.File) *ast.File } x.Body.List = append([]ast.Stmt{parseABIStmt, checkParseABIErrStmt}, x.Body.List...) - return false }, nil).(*ast.File) +} - return fileNode +// Add the fields to the returned struct in the 'Deploy' method. +func addContractStructFieldsToDeployMethod(contractName string, fileNode *ast.File) *ast.File { + return astutil.Apply(fileNode, func(cursor *astutil.Cursor) bool { + x, is := cursor.Node().(*ast.FuncDecl) + if !is { + return true + } else if x.Name.Name != "Deploy"+contractName { + return false + } + + for _, stmt := range x.Body.List { + returnStmt, is := stmt.(*ast.ReturnStmt) + if !is { + continue + } + if len(returnStmt.Results) < 3 { + continue + } + rs, is := returnStmt.Results[2].(*ast.UnaryExpr) + if !is { + return true + } + lit, is := rs.X.(*ast.CompositeLit) + if !is { + continue + } + addressExpr := &ast.KeyValueExpr{ + Key: ast.NewIdent("address"), + Value: ast.NewIdent("address"), + } + abiExpr := &ast.KeyValueExpr{ + Key: ast.NewIdent("abi"), + Value: ast.NewIdent("*parsed"), + } + lit.Elts = append([]ast.Expr{addressExpr, abiExpr}, lit.Elts...) + } + return false + }, nil).(*ast.File) } func getLogNames(fileNode *ast.File) []string { diff --git a/core/gethwrappers/abigen_test.go b/core/gethwrappers/abigen_test.go new file mode 100644 index 0000000000..7c206f59dc --- /dev/null +++ b/core/gethwrappers/abigen_test.go @@ -0,0 +1,29 @@ +package gethwrappers + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" +) + +// Test that the generated Deploy method fill all the required fields and returns the correct address. +// We perform this test using the generated LogEmitter wrapper. +func TestGeneratedDeployMethodAddressField(t *testing.T) { + owner := testutils.MustNewSimTransactor(t) + ec := backends.NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), map[common.Address]core.GenesisAccount{ + owner.From: { + Balance: big.NewInt(0).Mul(big.NewInt(10), big.NewInt(1e18)), + }, + }, 10e6) + emitterAddr, _, emitter, err := log_emitter.DeployLogEmitter(owner, ec) + require.NoError(t, err) + require.Equal(t, emitterAddr, emitter.Address()) +} diff --git a/core/gethwrappers/functions/generated/functions/functions.go b/core/gethwrappers/functions/generated/functions/functions.go index 419c21ca05..0c35806b66 100644 --- a/core/gethwrappers/functions/generated/functions/functions.go +++ b/core/gethwrappers/functions/generated/functions/functions.go @@ -50,7 +50,7 @@ func DeployFunctions(auth *bind.TransactOpts, backend bind.ContractBackend) (com if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Functions{FunctionsCaller: FunctionsCaller{contract: contract}, FunctionsTransactor: FunctionsTransactor{contract: contract}, FunctionsFilterer: FunctionsFilterer{contract: contract}}, nil + return address, tx, &Functions{address: address, abi: *parsed, FunctionsCaller: FunctionsCaller{contract: contract}, FunctionsTransactor: FunctionsTransactor{contract: contract}, FunctionsFilterer: FunctionsFilterer{contract: contract}}, nil } type Functions struct { diff --git a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go index d86c07f170..0ccb08cdaa 100644 --- a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go +++ b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go @@ -57,7 +57,7 @@ func DeployTermsOfServiceAllowList(auth *bind.TransactOpts, backend bind.Contrac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &TermsOfServiceAllowList{TermsOfServiceAllowListCaller: TermsOfServiceAllowListCaller{contract: contract}, TermsOfServiceAllowListTransactor: TermsOfServiceAllowListTransactor{contract: contract}, TermsOfServiceAllowListFilterer: TermsOfServiceAllowListFilterer{contract: contract}}, nil + return address, tx, &TermsOfServiceAllowList{address: address, abi: *parsed, TermsOfServiceAllowListCaller: TermsOfServiceAllowListCaller{contract: contract}, TermsOfServiceAllowListTransactor: TermsOfServiceAllowListTransactor{contract: contract}, TermsOfServiceAllowListFilterer: TermsOfServiceAllowListFilterer{contract: contract}}, nil } type TermsOfServiceAllowList struct { diff --git a/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go b/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go index 6ae90b45ed..00bf6a438f 100644 --- a/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go +++ b/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go @@ -52,7 +52,7 @@ func DeployFunctionsClientExample(auth *bind.TransactOpts, backend bind.Contract if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FunctionsClientExample{FunctionsClientExampleCaller: FunctionsClientExampleCaller{contract: contract}, FunctionsClientExampleTransactor: FunctionsClientExampleTransactor{contract: contract}, FunctionsClientExampleFilterer: FunctionsClientExampleFilterer{contract: contract}}, nil + return address, tx, &FunctionsClientExample{address: address, abi: *parsed, FunctionsClientExampleCaller: FunctionsClientExampleCaller{contract: contract}, FunctionsClientExampleTransactor: FunctionsClientExampleTransactor{contract: contract}, FunctionsClientExampleFilterer: FunctionsClientExampleFilterer{contract: contract}}, nil } type FunctionsClientExample struct { diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 32db52a029..ffe072fc65 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -92,7 +92,7 @@ func DeployFunctionsCoordinator(auth *bind.TransactOpts, backend bind.ContractBa if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FunctionsCoordinator{FunctionsCoordinatorCaller: FunctionsCoordinatorCaller{contract: contract}, FunctionsCoordinatorTransactor: FunctionsCoordinatorTransactor{contract: contract}, FunctionsCoordinatorFilterer: FunctionsCoordinatorFilterer{contract: contract}}, nil + return address, tx, &FunctionsCoordinator{address: address, abi: *parsed, FunctionsCoordinatorCaller: FunctionsCoordinatorCaller{contract: contract}, FunctionsCoordinatorTransactor: FunctionsCoordinatorTransactor{contract: contract}, FunctionsCoordinatorFilterer: FunctionsCoordinatorFilterer{contract: contract}}, nil } type FunctionsCoordinator struct { diff --git a/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go b/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go index 37a895fe8c..a03d6a5b14 100644 --- a/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go +++ b/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go @@ -52,7 +52,7 @@ func DeployFunctionsLoadTestClient(auth *bind.TransactOpts, backend bind.Contrac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FunctionsLoadTestClient{FunctionsLoadTestClientCaller: FunctionsLoadTestClientCaller{contract: contract}, FunctionsLoadTestClientTransactor: FunctionsLoadTestClientTransactor{contract: contract}, FunctionsLoadTestClientFilterer: FunctionsLoadTestClientFilterer{contract: contract}}, nil + return address, tx, &FunctionsLoadTestClient{address: address, abi: *parsed, FunctionsLoadTestClientCaller: FunctionsLoadTestClientCaller{contract: contract}, FunctionsLoadTestClientTransactor: FunctionsLoadTestClientTransactor{contract: contract}, FunctionsLoadTestClientFilterer: FunctionsLoadTestClientFilterer{contract: contract}}, nil } type FunctionsLoadTestClient struct { diff --git a/core/gethwrappers/functions/generated/functions_router/functions_router.go b/core/gethwrappers/functions/generated/functions_router/functions_router.go index 2c482048c4..592f95b568 100644 --- a/core/gethwrappers/functions/generated/functions_router/functions_router.go +++ b/core/gethwrappers/functions/generated/functions_router/functions_router.go @@ -91,7 +91,7 @@ func DeployFunctionsRouter(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FunctionsRouter{FunctionsRouterCaller: FunctionsRouterCaller{contract: contract}, FunctionsRouterTransactor: FunctionsRouterTransactor{contract: contract}, FunctionsRouterFilterer: FunctionsRouterFilterer{contract: contract}}, nil + return address, tx, &FunctionsRouter{address: address, abi: *parsed, FunctionsRouterCaller: FunctionsRouterCaller{contract: contract}, FunctionsRouterTransactor: FunctionsRouterTransactor{contract: contract}, FunctionsRouterFilterer: FunctionsRouterFilterer{contract: contract}}, nil } type FunctionsRouter struct { diff --git a/core/gethwrappers/functions/generated/functions_v1_events_mock/functions_v1_events_mock.go b/core/gethwrappers/functions/generated/functions_v1_events_mock/functions_v1_events_mock.go index ae1fe20401..422d2e8b2a 100644 --- a/core/gethwrappers/functions/generated/functions_v1_events_mock/functions_v1_events_mock.go +++ b/core/gethwrappers/functions/generated/functions_v1_events_mock/functions_v1_events_mock.go @@ -60,7 +60,7 @@ func DeployFunctionsV1EventsMock(auth *bind.TransactOpts, backend bind.ContractB if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FunctionsV1EventsMock{FunctionsV1EventsMockCaller: FunctionsV1EventsMockCaller{contract: contract}, FunctionsV1EventsMockTransactor: FunctionsV1EventsMockTransactor{contract: contract}, FunctionsV1EventsMockFilterer: FunctionsV1EventsMockFilterer{contract: contract}}, nil + return address, tx, &FunctionsV1EventsMock{address: address, abi: *parsed, FunctionsV1EventsMockCaller: FunctionsV1EventsMockCaller{contract: contract}, FunctionsV1EventsMockTransactor: FunctionsV1EventsMockTransactor{contract: contract}, FunctionsV1EventsMockFilterer: FunctionsV1EventsMockFilterer{contract: contract}}, nil } type FunctionsV1EventsMock struct { diff --git a/core/gethwrappers/functions/generated/ocr2dr/ocr2dr.go b/core/gethwrappers/functions/generated/ocr2dr/ocr2dr.go index 8cc6594216..c2b3c3a5e9 100644 --- a/core/gethwrappers/functions/generated/ocr2dr/ocr2dr.go +++ b/core/gethwrappers/functions/generated/ocr2dr/ocr2dr.go @@ -50,7 +50,7 @@ func DeployOCR2DR(auth *bind.TransactOpts, backend bind.ContractBackend) (common if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &OCR2DR{OCR2DRCaller: OCR2DRCaller{contract: contract}, OCR2DRTransactor: OCR2DRTransactor{contract: contract}, OCR2DRFilterer: OCR2DRFilterer{contract: contract}}, nil + return address, tx, &OCR2DR{address: address, abi: *parsed, OCR2DRCaller: OCR2DRCaller{contract: contract}, OCR2DRTransactor: OCR2DRTransactor{contract: contract}, OCR2DRFilterer: OCR2DRFilterer{contract: contract}}, nil } type OCR2DR struct { diff --git a/core/gethwrappers/functions/generated/ocr2dr_client_example/ocr2dr_client_example.go b/core/gethwrappers/functions/generated/ocr2dr_client_example/ocr2dr_client_example.go index a4b94f7e92..c37ba64b8d 100644 --- a/core/gethwrappers/functions/generated/ocr2dr_client_example/ocr2dr_client_example.go +++ b/core/gethwrappers/functions/generated/ocr2dr_client_example/ocr2dr_client_example.go @@ -61,7 +61,7 @@ func DeployOCR2DRClientExample(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &OCR2DRClientExample{OCR2DRClientExampleCaller: OCR2DRClientExampleCaller{contract: contract}, OCR2DRClientExampleTransactor: OCR2DRClientExampleTransactor{contract: contract}, OCR2DRClientExampleFilterer: OCR2DRClientExampleFilterer{contract: contract}}, nil + return address, tx, &OCR2DRClientExample{address: address, abi: *parsed, OCR2DRClientExampleCaller: OCR2DRClientExampleCaller{contract: contract}, OCR2DRClientExampleTransactor: OCR2DRClientExampleTransactor{contract: contract}, OCR2DRClientExampleFilterer: OCR2DRClientExampleFilterer{contract: contract}}, nil } type OCR2DRClientExample struct { diff --git a/core/gethwrappers/functions/generated/ocr2dr_oracle/ocr2dr_oracle.go b/core/gethwrappers/functions/generated/ocr2dr_oracle/ocr2dr_oracle.go index 509a3c8388..a2f81cfb30 100644 --- a/core/gethwrappers/functions/generated/ocr2dr_oracle/ocr2dr_oracle.go +++ b/core/gethwrappers/functions/generated/ocr2dr_oracle/ocr2dr_oracle.go @@ -59,7 +59,7 @@ func DeployOCR2DROracle(auth *bind.TransactOpts, backend bind.ContractBackend) ( if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &OCR2DROracle{OCR2DROracleCaller: OCR2DROracleCaller{contract: contract}, OCR2DROracleTransactor: OCR2DROracleTransactor{contract: contract}, OCR2DROracleFilterer: OCR2DROracleFilterer{contract: contract}}, nil + return address, tx, &OCR2DROracle{address: address, abi: *parsed, OCR2DROracleCaller: OCR2DROracleCaller{contract: contract}, OCR2DROracleTransactor: OCR2DROracleTransactor{contract: contract}, OCR2DROracleFilterer: OCR2DROracleFilterer{contract: contract}}, nil } type OCR2DROracle struct { diff --git a/core/gethwrappers/functions/generated/ocr2dr_registry/ocr2dr_registry.go b/core/gethwrappers/functions/generated/ocr2dr_registry/ocr2dr_registry.go index eb825b5eaa..f81a431620 100644 --- a/core/gethwrappers/functions/generated/ocr2dr_registry/ocr2dr_registry.go +++ b/core/gethwrappers/functions/generated/ocr2dr_registry/ocr2dr_registry.go @@ -71,7 +71,7 @@ func DeployOCR2DRRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &OCR2DRRegistry{OCR2DRRegistryCaller: OCR2DRRegistryCaller{contract: contract}, OCR2DRRegistryTransactor: OCR2DRRegistryTransactor{contract: contract}, OCR2DRRegistryFilterer: OCR2DRRegistryFilterer{contract: contract}}, nil + return address, tx, &OCR2DRRegistry{address: address, abi: *parsed, OCR2DRRegistryCaller: OCR2DRRegistryCaller{contract: contract}, OCR2DRRegistryTransactor: OCR2DRRegistryTransactor{contract: contract}, OCR2DRRegistryFilterer: OCR2DRRegistryFilterer{contract: contract}}, nil } type OCR2DRRegistry struct { diff --git a/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go b/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go index 6417a9c678..03643c9154 100644 --- a/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go +++ b/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go @@ -52,7 +52,7 @@ func DeployAuthorizedForwarder(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &AuthorizedForwarder{AuthorizedForwarderCaller: AuthorizedForwarderCaller{contract: contract}, AuthorizedForwarderTransactor: AuthorizedForwarderTransactor{contract: contract}, AuthorizedForwarderFilterer: AuthorizedForwarderFilterer{contract: contract}}, nil + return address, tx, &AuthorizedForwarder{address: address, abi: *parsed, AuthorizedForwarderCaller: AuthorizedForwarderCaller{contract: contract}, AuthorizedForwarderTransactor: AuthorizedForwarderTransactor{contract: contract}, AuthorizedForwarderFilterer: AuthorizedForwarderFilterer{contract: contract}}, nil } type AuthorizedForwarder struct { diff --git a/core/gethwrappers/generated/automation_consumer_benchmark/automation_consumer_benchmark.go b/core/gethwrappers/generated/automation_consumer_benchmark/automation_consumer_benchmark.go index f4d59e7e7d..3dafe68921 100644 --- a/core/gethwrappers/generated/automation_consumer_benchmark/automation_consumer_benchmark.go +++ b/core/gethwrappers/generated/automation_consumer_benchmark/automation_consumer_benchmark.go @@ -52,7 +52,7 @@ func DeployAutomationConsumerBenchmark(auth *bind.TransactOpts, backend bind.Con if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &AutomationConsumerBenchmark{AutomationConsumerBenchmarkCaller: AutomationConsumerBenchmarkCaller{contract: contract}, AutomationConsumerBenchmarkTransactor: AutomationConsumerBenchmarkTransactor{contract: contract}, AutomationConsumerBenchmarkFilterer: AutomationConsumerBenchmarkFilterer{contract: contract}}, nil + return address, tx, &AutomationConsumerBenchmark{address: address, abi: *parsed, AutomationConsumerBenchmarkCaller: AutomationConsumerBenchmarkCaller{contract: contract}, AutomationConsumerBenchmarkTransactor: AutomationConsumerBenchmarkTransactor{contract: contract}, AutomationConsumerBenchmarkFilterer: AutomationConsumerBenchmarkFilterer{contract: contract}}, nil } type AutomationConsumerBenchmark struct { diff --git a/core/gethwrappers/generated/automation_forwarder_logic/automation_forwarder_logic.go b/core/gethwrappers/generated/automation_forwarder_logic/automation_forwarder_logic.go index b26f5e5692..8b35a68c82 100644 --- a/core/gethwrappers/generated/automation_forwarder_logic/automation_forwarder_logic.go +++ b/core/gethwrappers/generated/automation_forwarder_logic/automation_forwarder_logic.go @@ -50,7 +50,7 @@ func DeployAutomationForwarderLogic(auth *bind.TransactOpts, backend bind.Contra if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &AutomationForwarderLogic{AutomationForwarderLogicCaller: AutomationForwarderLogicCaller{contract: contract}, AutomationForwarderLogicTransactor: AutomationForwarderLogicTransactor{contract: contract}, AutomationForwarderLogicFilterer: AutomationForwarderLogicFilterer{contract: contract}}, nil + return address, tx, &AutomationForwarderLogic{address: address, abi: *parsed, AutomationForwarderLogicCaller: AutomationForwarderLogicCaller{contract: contract}, AutomationForwarderLogicTransactor: AutomationForwarderLogicTransactor{contract: contract}, AutomationForwarderLogicFilterer: AutomationForwarderLogicFilterer{contract: contract}}, nil } type AutomationForwarderLogic struct { diff --git a/core/gethwrappers/generated/automation_registrar_wrapper2_1/automation_registrar_wrapper2_1.go b/core/gethwrappers/generated/automation_registrar_wrapper2_1/automation_registrar_wrapper2_1.go index d2b8054436..311ce75c10 100644 --- a/core/gethwrappers/generated/automation_registrar_wrapper2_1/automation_registrar_wrapper2_1.go +++ b/core/gethwrappers/generated/automation_registrar_wrapper2_1/automation_registrar_wrapper2_1.go @@ -77,7 +77,7 @@ func DeployAutomationRegistrar(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &AutomationRegistrar{AutomationRegistrarCaller: AutomationRegistrarCaller{contract: contract}, AutomationRegistrarTransactor: AutomationRegistrarTransactor{contract: contract}, AutomationRegistrarFilterer: AutomationRegistrarFilterer{contract: contract}}, nil + return address, tx, &AutomationRegistrar{address: address, abi: *parsed, AutomationRegistrarCaller: AutomationRegistrarCaller{contract: contract}, AutomationRegistrarTransactor: AutomationRegistrarTransactor{contract: contract}, AutomationRegistrarFilterer: AutomationRegistrarFilterer{contract: contract}}, nil } type AutomationRegistrar struct { diff --git a/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go b/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go index 1eaa4ea03f..5d6dc1e41c 100644 --- a/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go +++ b/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go @@ -110,7 +110,7 @@ func DeployAutomationUtils(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &AutomationUtils{AutomationUtilsCaller: AutomationUtilsCaller{contract: contract}, AutomationUtilsTransactor: AutomationUtilsTransactor{contract: contract}, AutomationUtilsFilterer: AutomationUtilsFilterer{contract: contract}}, nil + return address, tx, &AutomationUtils{address: address, abi: *parsed, AutomationUtilsCaller: AutomationUtilsCaller{contract: contract}, AutomationUtilsTransactor: AutomationUtilsTransactor{contract: contract}, AutomationUtilsFilterer: AutomationUtilsFilterer{contract: contract}}, nil } type AutomationUtils struct { diff --git a/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go b/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go index 426c5a2c79..1a43287d74 100644 --- a/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go +++ b/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go @@ -50,7 +50,7 @@ func DeployBatchBlockhashStore(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BatchBlockhashStore{BatchBlockhashStoreCaller: BatchBlockhashStoreCaller{contract: contract}, BatchBlockhashStoreTransactor: BatchBlockhashStoreTransactor{contract: contract}, BatchBlockhashStoreFilterer: BatchBlockhashStoreFilterer{contract: contract}}, nil + return address, tx, &BatchBlockhashStore{address: address, abi: *parsed, BatchBlockhashStoreCaller: BatchBlockhashStoreCaller{contract: contract}, BatchBlockhashStoreTransactor: BatchBlockhashStoreTransactor{contract: contract}, BatchBlockhashStoreFilterer: BatchBlockhashStoreFilterer{contract: contract}}, nil } type BatchBlockhashStore struct { diff --git a/core/gethwrappers/generated/batch_vrf_coordinator_v2/batch_vrf_coordinator_v2.go b/core/gethwrappers/generated/batch_vrf_coordinator_v2/batch_vrf_coordinator_v2.go index 4cb6e76b96..3a1ec957b9 100644 --- a/core/gethwrappers/generated/batch_vrf_coordinator_v2/batch_vrf_coordinator_v2.go +++ b/core/gethwrappers/generated/batch_vrf_coordinator_v2/batch_vrf_coordinator_v2.go @@ -72,7 +72,7 @@ func DeployBatchVRFCoordinatorV2(auth *bind.TransactOpts, backend bind.ContractB if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BatchVRFCoordinatorV2{BatchVRFCoordinatorV2Caller: BatchVRFCoordinatorV2Caller{contract: contract}, BatchVRFCoordinatorV2Transactor: BatchVRFCoordinatorV2Transactor{contract: contract}, BatchVRFCoordinatorV2Filterer: BatchVRFCoordinatorV2Filterer{contract: contract}}, nil + return address, tx, &BatchVRFCoordinatorV2{address: address, abi: *parsed, BatchVRFCoordinatorV2Caller: BatchVRFCoordinatorV2Caller{contract: contract}, BatchVRFCoordinatorV2Transactor: BatchVRFCoordinatorV2Transactor{contract: contract}, BatchVRFCoordinatorV2Filterer: BatchVRFCoordinatorV2Filterer{contract: contract}}, nil } type BatchVRFCoordinatorV2 struct { diff --git a/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go b/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go index 610f3a2700..58f134fe2a 100644 --- a/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go +++ b/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go @@ -73,7 +73,7 @@ func DeployBatchVRFCoordinatorV2Plus(auth *bind.TransactOpts, backend bind.Contr if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BatchVRFCoordinatorV2Plus{BatchVRFCoordinatorV2PlusCaller: BatchVRFCoordinatorV2PlusCaller{contract: contract}, BatchVRFCoordinatorV2PlusTransactor: BatchVRFCoordinatorV2PlusTransactor{contract: contract}, BatchVRFCoordinatorV2PlusFilterer: BatchVRFCoordinatorV2PlusFilterer{contract: contract}}, nil + return address, tx, &BatchVRFCoordinatorV2Plus{address: address, abi: *parsed, BatchVRFCoordinatorV2PlusCaller: BatchVRFCoordinatorV2PlusCaller{contract: contract}, BatchVRFCoordinatorV2PlusTransactor: BatchVRFCoordinatorV2PlusTransactor{contract: contract}, BatchVRFCoordinatorV2PlusFilterer: BatchVRFCoordinatorV2PlusFilterer{contract: contract}}, nil } type BatchVRFCoordinatorV2Plus struct { diff --git a/core/gethwrappers/generated/blockhash_store/blockhash_store.go b/core/gethwrappers/generated/blockhash_store/blockhash_store.go index 8711f13b2d..e43f9f450e 100644 --- a/core/gethwrappers/generated/blockhash_store/blockhash_store.go +++ b/core/gethwrappers/generated/blockhash_store/blockhash_store.go @@ -50,7 +50,7 @@ func DeployBlockhashStore(auth *bind.TransactOpts, backend bind.ContractBackend) if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BlockhashStore{BlockhashStoreCaller: BlockhashStoreCaller{contract: contract}, BlockhashStoreTransactor: BlockhashStoreTransactor{contract: contract}, BlockhashStoreFilterer: BlockhashStoreFilterer{contract: contract}}, nil + return address, tx, &BlockhashStore{address: address, abi: *parsed, BlockhashStoreCaller: BlockhashStoreCaller{contract: contract}, BlockhashStoreTransactor: BlockhashStoreTransactor{contract: contract}, BlockhashStoreFilterer: BlockhashStoreFilterer{contract: contract}}, nil } type BlockhashStore struct { diff --git a/core/gethwrappers/generated/chain_specific_util_helper/chain_specific_util_helper.go b/core/gethwrappers/generated/chain_specific_util_helper/chain_specific_util_helper.go index aa4dc0f88d..b32c3d18d5 100644 --- a/core/gethwrappers/generated/chain_specific_util_helper/chain_specific_util_helper.go +++ b/core/gethwrappers/generated/chain_specific_util_helper/chain_specific_util_helper.go @@ -50,7 +50,7 @@ func DeployChainSpecificUtilHelper(auth *bind.TransactOpts, backend bind.Contrac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &ChainSpecificUtilHelper{ChainSpecificUtilHelperCaller: ChainSpecificUtilHelperCaller{contract: contract}, ChainSpecificUtilHelperTransactor: ChainSpecificUtilHelperTransactor{contract: contract}, ChainSpecificUtilHelperFilterer: ChainSpecificUtilHelperFilterer{contract: contract}}, nil + return address, tx, &ChainSpecificUtilHelper{address: address, abi: *parsed, ChainSpecificUtilHelperCaller: ChainSpecificUtilHelperCaller{contract: contract}, ChainSpecificUtilHelperTransactor: ChainSpecificUtilHelperTransactor{contract: contract}, ChainSpecificUtilHelperFilterer: ChainSpecificUtilHelperFilterer{contract: contract}}, nil } type ChainSpecificUtilHelper struct { diff --git a/core/gethwrappers/generated/consumer_wrapper/consumer_wrapper.go b/core/gethwrappers/generated/consumer_wrapper/consumer_wrapper.go index 954f66a08e..0c0386b085 100644 --- a/core/gethwrappers/generated/consumer_wrapper/consumer_wrapper.go +++ b/core/gethwrappers/generated/consumer_wrapper/consumer_wrapper.go @@ -52,7 +52,7 @@ func DeployConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _link if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Consumer{ConsumerCaller: ConsumerCaller{contract: contract}, ConsumerTransactor: ConsumerTransactor{contract: contract}, ConsumerFilterer: ConsumerFilterer{contract: contract}}, nil + return address, tx, &Consumer{address: address, abi: *parsed, ConsumerCaller: ConsumerCaller{contract: contract}, ConsumerTransactor: ConsumerTransactor{contract: contract}, ConsumerFilterer: ConsumerFilterer{contract: contract}}, nil } type Consumer struct { diff --git a/core/gethwrappers/generated/dummy_protocol_wrapper/dummy_protocol_wrapper.go b/core/gethwrappers/generated/dummy_protocol_wrapper/dummy_protocol_wrapper.go index e7a88fdd06..e2838b3f6f 100644 --- a/core/gethwrappers/generated/dummy_protocol_wrapper/dummy_protocol_wrapper.go +++ b/core/gethwrappers/generated/dummy_protocol_wrapper/dummy_protocol_wrapper.go @@ -52,7 +52,7 @@ func DeployDummyProtocol(auth *bind.TransactOpts, backend bind.ContractBackend) if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &DummyProtocol{DummyProtocolCaller: DummyProtocolCaller{contract: contract}, DummyProtocolTransactor: DummyProtocolTransactor{contract: contract}, DummyProtocolFilterer: DummyProtocolFilterer{contract: contract}}, nil + return address, tx, &DummyProtocol{address: address, abi: *parsed, DummyProtocolCaller: DummyProtocolCaller{contract: contract}, DummyProtocolTransactor: DummyProtocolTransactor{contract: contract}, DummyProtocolFilterer: DummyProtocolFilterer{contract: contract}}, nil } type DummyProtocol struct { diff --git a/core/gethwrappers/generated/flags_wrapper/flags_wrapper.go b/core/gethwrappers/generated/flags_wrapper/flags_wrapper.go index f8d3c21b54..590f9e2af9 100644 --- a/core/gethwrappers/generated/flags_wrapper/flags_wrapper.go +++ b/core/gethwrappers/generated/flags_wrapper/flags_wrapper.go @@ -52,7 +52,7 @@ func DeployFlags(auth *bind.TransactOpts, backend bind.ContractBackend, racAddre if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Flags{FlagsCaller: FlagsCaller{contract: contract}, FlagsTransactor: FlagsTransactor{contract: contract}, FlagsFilterer: FlagsFilterer{contract: contract}}, nil + return address, tx, &Flags{address: address, abi: *parsed, FlagsCaller: FlagsCaller{contract: contract}, FlagsTransactor: FlagsTransactor{contract: contract}, FlagsFilterer: FlagsFilterer{contract: contract}}, nil } type Flags struct { diff --git a/core/gethwrappers/generated/flux_aggregator_wrapper/flux_aggregator_wrapper.go b/core/gethwrappers/generated/flux_aggregator_wrapper/flux_aggregator_wrapper.go index 6c4cb73af7..876ef73487 100644 --- a/core/gethwrappers/generated/flux_aggregator_wrapper/flux_aggregator_wrapper.go +++ b/core/gethwrappers/generated/flux_aggregator_wrapper/flux_aggregator_wrapper.go @@ -52,7 +52,7 @@ func DeployFluxAggregator(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FluxAggregator{FluxAggregatorCaller: FluxAggregatorCaller{contract: contract}, FluxAggregatorTransactor: FluxAggregatorTransactor{contract: contract}, FluxAggregatorFilterer: FluxAggregatorFilterer{contract: contract}}, nil + return address, tx, &FluxAggregator{address: address, abi: *parsed, FluxAggregatorCaller: FluxAggregatorCaller{contract: contract}, FluxAggregatorTransactor: FluxAggregatorTransactor{contract: contract}, FluxAggregatorFilterer: FluxAggregatorFilterer{contract: contract}}, nil } type FluxAggregator struct { diff --git a/core/gethwrappers/generated/functions_billing_registry_events_mock/functions_billing_registry_events_mock.go b/core/gethwrappers/generated/functions_billing_registry_events_mock/functions_billing_registry_events_mock.go index ec87fb9e74..c86c4feaa4 100644 --- a/core/gethwrappers/generated/functions_billing_registry_events_mock/functions_billing_registry_events_mock.go +++ b/core/gethwrappers/generated/functions_billing_registry_events_mock/functions_billing_registry_events_mock.go @@ -64,7 +64,7 @@ func DeployFunctionsBillingRegistryEventsMock(auth *bind.TransactOpts, backend b if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FunctionsBillingRegistryEventsMock{FunctionsBillingRegistryEventsMockCaller: FunctionsBillingRegistryEventsMockCaller{contract: contract}, FunctionsBillingRegistryEventsMockTransactor: FunctionsBillingRegistryEventsMockTransactor{contract: contract}, FunctionsBillingRegistryEventsMockFilterer: FunctionsBillingRegistryEventsMockFilterer{contract: contract}}, nil + return address, tx, &FunctionsBillingRegistryEventsMock{address: address, abi: *parsed, FunctionsBillingRegistryEventsMockCaller: FunctionsBillingRegistryEventsMockCaller{contract: contract}, FunctionsBillingRegistryEventsMockTransactor: FunctionsBillingRegistryEventsMockTransactor{contract: contract}, FunctionsBillingRegistryEventsMockFilterer: FunctionsBillingRegistryEventsMockFilterer{contract: contract}}, nil } type FunctionsBillingRegistryEventsMock struct { diff --git a/core/gethwrappers/generated/functions_oracle_events_mock/functions_oracle_events_mock.go b/core/gethwrappers/generated/functions_oracle_events_mock/functions_oracle_events_mock.go index 3b8238c00e..4e97e08239 100644 --- a/core/gethwrappers/generated/functions_oracle_events_mock/functions_oracle_events_mock.go +++ b/core/gethwrappers/generated/functions_oracle_events_mock/functions_oracle_events_mock.go @@ -52,7 +52,7 @@ func DeployFunctionsOracleEventsMock(auth *bind.TransactOpts, backend bind.Contr if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FunctionsOracleEventsMock{FunctionsOracleEventsMockCaller: FunctionsOracleEventsMockCaller{contract: contract}, FunctionsOracleEventsMockTransactor: FunctionsOracleEventsMockTransactor{contract: contract}, FunctionsOracleEventsMockFilterer: FunctionsOracleEventsMockFilterer{contract: contract}}, nil + return address, tx, &FunctionsOracleEventsMock{address: address, abi: *parsed, FunctionsOracleEventsMockCaller: FunctionsOracleEventsMockCaller{contract: contract}, FunctionsOracleEventsMockTransactor: FunctionsOracleEventsMockTransactor{contract: contract}, FunctionsOracleEventsMockFilterer: FunctionsOracleEventsMockFilterer{contract: contract}}, nil } type FunctionsOracleEventsMock struct { diff --git a/core/gethwrappers/generated/gas_wrapper/gas_wrapper.go b/core/gethwrappers/generated/gas_wrapper/gas_wrapper.go index f2e25e36a7..eec0cf855f 100644 --- a/core/gethwrappers/generated/gas_wrapper/gas_wrapper.go +++ b/core/gethwrappers/generated/gas_wrapper/gas_wrapper.go @@ -52,7 +52,7 @@ func DeployKeeperRegistryCheckUpkeepGasUsageWrapper(auth *bind.TransactOpts, bac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistryCheckUpkeepGasUsageWrapper{KeeperRegistryCheckUpkeepGasUsageWrapperCaller: KeeperRegistryCheckUpkeepGasUsageWrapperCaller{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperTransactor: KeeperRegistryCheckUpkeepGasUsageWrapperTransactor{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperFilterer: KeeperRegistryCheckUpkeepGasUsageWrapperFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistryCheckUpkeepGasUsageWrapper{address: address, abi: *parsed, KeeperRegistryCheckUpkeepGasUsageWrapperCaller: KeeperRegistryCheckUpkeepGasUsageWrapperCaller{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperTransactor: KeeperRegistryCheckUpkeepGasUsageWrapperTransactor{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperFilterer: KeeperRegistryCheckUpkeepGasUsageWrapperFilterer{contract: contract}}, nil } type KeeperRegistryCheckUpkeepGasUsageWrapper struct { diff --git a/core/gethwrappers/generated/gas_wrapper_mock/gas_wrapper_mock.go b/core/gethwrappers/generated/gas_wrapper_mock/gas_wrapper_mock.go index b0420097b4..93803ce993 100644 --- a/core/gethwrappers/generated/gas_wrapper_mock/gas_wrapper_mock.go +++ b/core/gethwrappers/generated/gas_wrapper_mock/gas_wrapper_mock.go @@ -52,7 +52,7 @@ func DeployKeeperRegistryCheckUpkeepGasUsageWrapperMock(auth *bind.TransactOpts, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistryCheckUpkeepGasUsageWrapperMock{KeeperRegistryCheckUpkeepGasUsageWrapperMockCaller: KeeperRegistryCheckUpkeepGasUsageWrapperMockCaller{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperMockTransactor: KeeperRegistryCheckUpkeepGasUsageWrapperMockTransactor{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperMockFilterer: KeeperRegistryCheckUpkeepGasUsageWrapperMockFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistryCheckUpkeepGasUsageWrapperMock{address: address, abi: *parsed, KeeperRegistryCheckUpkeepGasUsageWrapperMockCaller: KeeperRegistryCheckUpkeepGasUsageWrapperMockCaller{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperMockTransactor: KeeperRegistryCheckUpkeepGasUsageWrapperMockTransactor{contract: contract}, KeeperRegistryCheckUpkeepGasUsageWrapperMockFilterer: KeeperRegistryCheckUpkeepGasUsageWrapperMockFilterer{contract: contract}}, nil } type KeeperRegistryCheckUpkeepGasUsageWrapperMock struct { diff --git a/core/gethwrappers/generated/keeper_consumer_performance_wrapper/keeper_consumer_performance_wrapper.go b/core/gethwrappers/generated/keeper_consumer_performance_wrapper/keeper_consumer_performance_wrapper.go index 0e1876ce0a..08178c9882 100644 --- a/core/gethwrappers/generated/keeper_consumer_performance_wrapper/keeper_consumer_performance_wrapper.go +++ b/core/gethwrappers/generated/keeper_consumer_performance_wrapper/keeper_consumer_performance_wrapper.go @@ -52,7 +52,7 @@ func DeployKeeperConsumerPerformance(auth *bind.TransactOpts, backend bind.Contr if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperConsumerPerformance{KeeperConsumerPerformanceCaller: KeeperConsumerPerformanceCaller{contract: contract}, KeeperConsumerPerformanceTransactor: KeeperConsumerPerformanceTransactor{contract: contract}, KeeperConsumerPerformanceFilterer: KeeperConsumerPerformanceFilterer{contract: contract}}, nil + return address, tx, &KeeperConsumerPerformance{address: address, abi: *parsed, KeeperConsumerPerformanceCaller: KeeperConsumerPerformanceCaller{contract: contract}, KeeperConsumerPerformanceTransactor: KeeperConsumerPerformanceTransactor{contract: contract}, KeeperConsumerPerformanceFilterer: KeeperConsumerPerformanceFilterer{contract: contract}}, nil } type KeeperConsumerPerformance struct { diff --git a/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go b/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go index 896927f9e6..8a4ee2c4de 100644 --- a/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go +++ b/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go @@ -50,7 +50,7 @@ func DeployKeeperConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperConsumer{KeeperConsumerCaller: KeeperConsumerCaller{contract: contract}, KeeperConsumerTransactor: KeeperConsumerTransactor{contract: contract}, KeeperConsumerFilterer: KeeperConsumerFilterer{contract: contract}}, nil + return address, tx, &KeeperConsumer{address: address, abi: *parsed, KeeperConsumerCaller: KeeperConsumerCaller{contract: contract}, KeeperConsumerTransactor: KeeperConsumerTransactor{contract: contract}, KeeperConsumerFilterer: KeeperConsumerFilterer{contract: contract}}, nil } type KeeperConsumer struct { diff --git a/core/gethwrappers/generated/keeper_registrar_wrapper1_2/keeper_registrar_wrapper1_2.go b/core/gethwrappers/generated/keeper_registrar_wrapper1_2/keeper_registrar_wrapper1_2.go index 3721238f67..45564b662d 100644 --- a/core/gethwrappers/generated/keeper_registrar_wrapper1_2/keeper_registrar_wrapper1_2.go +++ b/core/gethwrappers/generated/keeper_registrar_wrapper1_2/keeper_registrar_wrapper1_2.go @@ -52,7 +52,7 @@ func DeployKeeperRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistrar{KeeperRegistrarCaller: KeeperRegistrarCaller{contract: contract}, KeeperRegistrarTransactor: KeeperRegistrarTransactor{contract: contract}, KeeperRegistrarFilterer: KeeperRegistrarFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistrar{address: address, abi: *parsed, KeeperRegistrarCaller: KeeperRegistrarCaller{contract: contract}, KeeperRegistrarTransactor: KeeperRegistrarTransactor{contract: contract}, KeeperRegistrarFilterer: KeeperRegistrarFilterer{contract: contract}}, nil } type KeeperRegistrar struct { diff --git a/core/gethwrappers/generated/keeper_registrar_wrapper1_2_mock/keeper_registrar_wrapper1_2_mock.go b/core/gethwrappers/generated/keeper_registrar_wrapper1_2_mock/keeper_registrar_wrapper1_2_mock.go index ea4c49f7c8..d83fd9a431 100644 --- a/core/gethwrappers/generated/keeper_registrar_wrapper1_2_mock/keeper_registrar_wrapper1_2_mock.go +++ b/core/gethwrappers/generated/keeper_registrar_wrapper1_2_mock/keeper_registrar_wrapper1_2_mock.go @@ -52,7 +52,7 @@ func DeployKeeperRegistrarMock(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistrarMock{KeeperRegistrarMockCaller: KeeperRegistrarMockCaller{contract: contract}, KeeperRegistrarMockTransactor: KeeperRegistrarMockTransactor{contract: contract}, KeeperRegistrarMockFilterer: KeeperRegistrarMockFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistrarMock{address: address, abi: *parsed, KeeperRegistrarMockCaller: KeeperRegistrarMockCaller{contract: contract}, KeeperRegistrarMockTransactor: KeeperRegistrarMockTransactor{contract: contract}, KeeperRegistrarMockFilterer: KeeperRegistrarMockFilterer{contract: contract}}, nil } type KeeperRegistrarMock struct { diff --git a/core/gethwrappers/generated/keeper_registrar_wrapper2_0/keeper_registrar_wrapper2_0.go b/core/gethwrappers/generated/keeper_registrar_wrapper2_0/keeper_registrar_wrapper2_0.go index c8a7016df4..56d78f9f0d 100644 --- a/core/gethwrappers/generated/keeper_registrar_wrapper2_0/keeper_registrar_wrapper2_0.go +++ b/core/gethwrappers/generated/keeper_registrar_wrapper2_0/keeper_registrar_wrapper2_0.go @@ -63,7 +63,7 @@ func DeployKeeperRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistrar{KeeperRegistrarCaller: KeeperRegistrarCaller{contract: contract}, KeeperRegistrarTransactor: KeeperRegistrarTransactor{contract: contract}, KeeperRegistrarFilterer: KeeperRegistrarFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistrar{address: address, abi: *parsed, KeeperRegistrarCaller: KeeperRegistrarCaller{contract: contract}, KeeperRegistrarTransactor: KeeperRegistrarTransactor{contract: contract}, KeeperRegistrarFilterer: KeeperRegistrarFilterer{contract: contract}}, nil } type KeeperRegistrar struct { diff --git a/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go b/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go index 6049536df6..11856a0c8f 100644 --- a/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go +++ b/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go @@ -67,7 +67,7 @@ func DeployKeeperRegistryLogic(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistryLogic{KeeperRegistryLogicCaller: KeeperRegistryLogicCaller{contract: contract}, KeeperRegistryLogicTransactor: KeeperRegistryLogicTransactor{contract: contract}, KeeperRegistryLogicFilterer: KeeperRegistryLogicFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistryLogic{address: address, abi: *parsed, KeeperRegistryLogicCaller: KeeperRegistryLogicCaller{contract: contract}, KeeperRegistryLogicTransactor: KeeperRegistryLogicTransactor{contract: contract}, KeeperRegistryLogicFilterer: KeeperRegistryLogicFilterer{contract: contract}}, nil } type KeeperRegistryLogic struct { diff --git a/core/gethwrappers/generated/keeper_registry_logic2_0/keeper_registry_logic2_0.go b/core/gethwrappers/generated/keeper_registry_logic2_0/keeper_registry_logic2_0.go index e4e24a0463..819e7e094b 100644 --- a/core/gethwrappers/generated/keeper_registry_logic2_0/keeper_registry_logic2_0.go +++ b/core/gethwrappers/generated/keeper_registry_logic2_0/keeper_registry_logic2_0.go @@ -52,7 +52,7 @@ func DeployKeeperRegistryLogic(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistryLogic{KeeperRegistryLogicCaller: KeeperRegistryLogicCaller{contract: contract}, KeeperRegistryLogicTransactor: KeeperRegistryLogicTransactor{contract: contract}, KeeperRegistryLogicFilterer: KeeperRegistryLogicFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistryLogic{address: address, abi: *parsed, KeeperRegistryLogicCaller: KeeperRegistryLogicCaller{contract: contract}, KeeperRegistryLogicTransactor: KeeperRegistryLogicTransactor{contract: contract}, KeeperRegistryLogicFilterer: KeeperRegistryLogicFilterer{contract: contract}}, nil } type KeeperRegistryLogic struct { diff --git a/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go index 48c4d75e8b..69d9adbc68 100644 --- a/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go +++ b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go @@ -52,7 +52,7 @@ func DeployKeeperRegistryLogicA(auth *bind.TransactOpts, backend bind.ContractBa if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistryLogicA{KeeperRegistryLogicACaller: KeeperRegistryLogicACaller{contract: contract}, KeeperRegistryLogicATransactor: KeeperRegistryLogicATransactor{contract: contract}, KeeperRegistryLogicAFilterer: KeeperRegistryLogicAFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistryLogicA{address: address, abi: *parsed, KeeperRegistryLogicACaller: KeeperRegistryLogicACaller{contract: contract}, KeeperRegistryLogicATransactor: KeeperRegistryLogicATransactor{contract: contract}, KeeperRegistryLogicAFilterer: KeeperRegistryLogicAFilterer{contract: contract}}, nil } type KeeperRegistryLogicA struct { diff --git a/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_1/keeper_registry_logic_b_wrapper_2_1.go b/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_1/keeper_registry_logic_b_wrapper_2_1.go index 15330fb821..984d9221eb 100644 --- a/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_1/keeper_registry_logic_b_wrapper_2_1.go +++ b/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_1/keeper_registry_logic_b_wrapper_2_1.go @@ -96,7 +96,7 @@ func DeployKeeperRegistryLogicB(auth *bind.TransactOpts, backend bind.ContractBa if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistryLogicB{KeeperRegistryLogicBCaller: KeeperRegistryLogicBCaller{contract: contract}, KeeperRegistryLogicBTransactor: KeeperRegistryLogicBTransactor{contract: contract}, KeeperRegistryLogicBFilterer: KeeperRegistryLogicBFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistryLogicB{address: address, abi: *parsed, KeeperRegistryLogicBCaller: KeeperRegistryLogicBCaller{contract: contract}, KeeperRegistryLogicBTransactor: KeeperRegistryLogicBTransactor{contract: contract}, KeeperRegistryLogicBFilterer: KeeperRegistryLogicBFilterer{contract: contract}}, nil } type KeeperRegistryLogicB struct { diff --git a/core/gethwrappers/generated/keeper_registry_wrapper1_1/keeper_registry_wrapper1_1.go b/core/gethwrappers/generated/keeper_registry_wrapper1_1/keeper_registry_wrapper1_1.go index 896de7f088..196b2f36f5 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper1_1/keeper_registry_wrapper1_1.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper1_1/keeper_registry_wrapper1_1.go @@ -52,7 +52,7 @@ func DeployKeeperRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistry{KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistry{address: address, abi: *parsed, KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil } type KeeperRegistry struct { diff --git a/core/gethwrappers/generated/keeper_registry_wrapper1_1_mock/keeper_registry_wrapper1_1_mock.go b/core/gethwrappers/generated/keeper_registry_wrapper1_1_mock/keeper_registry_wrapper1_1_mock.go index d7bfc132eb..14457f91ef 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper1_1_mock/keeper_registry_wrapper1_1_mock.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper1_1_mock/keeper_registry_wrapper1_1_mock.go @@ -52,7 +52,7 @@ func DeployKeeperRegistryMock(auth *bind.TransactOpts, backend bind.ContractBack if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistryMock{KeeperRegistryMockCaller: KeeperRegistryMockCaller{contract: contract}, KeeperRegistryMockTransactor: KeeperRegistryMockTransactor{contract: contract}, KeeperRegistryMockFilterer: KeeperRegistryMockFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistryMock{address: address, abi: *parsed, KeeperRegistryMockCaller: KeeperRegistryMockCaller{contract: contract}, KeeperRegistryMockTransactor: KeeperRegistryMockTransactor{contract: contract}, KeeperRegistryMockFilterer: KeeperRegistryMockFilterer{contract: contract}}, nil } type KeeperRegistryMock struct { diff --git a/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go b/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go index cbfd589abf..6fa0d55b78 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go @@ -74,7 +74,7 @@ func DeployKeeperRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistry{KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistry{address: address, abi: *parsed, KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil } type KeeperRegistry struct { diff --git a/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go b/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go index 73ff800e12..bea6e458a0 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go @@ -74,7 +74,7 @@ func DeployKeeperRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistry{KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistry{address: address, abi: *parsed, KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil } type KeeperRegistry struct { diff --git a/core/gethwrappers/generated/keeper_registry_wrapper2_0/keeper_registry_wrapper2_0.go b/core/gethwrappers/generated/keeper_registry_wrapper2_0/keeper_registry_wrapper2_0.go index 2aaf8085aa..bd000995e3 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper2_0/keeper_registry_wrapper2_0.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper2_0/keeper_registry_wrapper2_0.go @@ -94,7 +94,7 @@ func DeployKeeperRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistry{KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistry{address: address, abi: *parsed, KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil } type KeeperRegistry struct { diff --git a/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go b/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go index 1db34ca395..fc9d120c5e 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go @@ -70,7 +70,7 @@ func DeployKeeperRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeeperRegistry{KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil + return address, tx, &KeeperRegistry{address: address, abi: *parsed, KeeperRegistryCaller: KeeperRegistryCaller{contract: contract}, KeeperRegistryTransactor: KeeperRegistryTransactor{contract: contract}, KeeperRegistryFilterer: KeeperRegistryFilterer{contract: contract}}, nil } type KeeperRegistry struct { diff --git a/core/gethwrappers/generated/keepers_vrf_consumer/keepers_vrf_consumer.go b/core/gethwrappers/generated/keepers_vrf_consumer/keepers_vrf_consumer.go index 99e0fece52..57e0aced8a 100644 --- a/core/gethwrappers/generated/keepers_vrf_consumer/keepers_vrf_consumer.go +++ b/core/gethwrappers/generated/keepers_vrf_consumer/keepers_vrf_consumer.go @@ -50,7 +50,7 @@ func DeployKeepersVRFConsumer(auth *bind.TransactOpts, backend bind.ContractBack if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &KeepersVRFConsumer{KeepersVRFConsumerCaller: KeepersVRFConsumerCaller{contract: contract}, KeepersVRFConsumerTransactor: KeepersVRFConsumerTransactor{contract: contract}, KeepersVRFConsumerFilterer: KeepersVRFConsumerFilterer{contract: contract}}, nil + return address, tx, &KeepersVRFConsumer{address: address, abi: *parsed, KeepersVRFConsumerCaller: KeepersVRFConsumerCaller{contract: contract}, KeepersVRFConsumerTransactor: KeepersVRFConsumerTransactor{contract: contract}, KeepersVRFConsumerFilterer: KeepersVRFConsumerFilterer{contract: contract}}, nil } type KeepersVRFConsumer struct { diff --git a/core/gethwrappers/generated/link_token_interface/link_token_interface.go b/core/gethwrappers/generated/link_token_interface/link_token_interface.go index d0a6b92c1e..53fbb56dce 100644 --- a/core/gethwrappers/generated/link_token_interface/link_token_interface.go +++ b/core/gethwrappers/generated/link_token_interface/link_token_interface.go @@ -52,7 +52,7 @@ func DeployLinkToken(auth *bind.TransactOpts, backend bind.ContractBackend) (com if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &LinkToken{LinkTokenCaller: LinkTokenCaller{contract: contract}, LinkTokenTransactor: LinkTokenTransactor{contract: contract}, LinkTokenFilterer: LinkTokenFilterer{contract: contract}}, nil + return address, tx, &LinkToken{address: address, abi: *parsed, LinkTokenCaller: LinkTokenCaller{contract: contract}, LinkTokenTransactor: LinkTokenTransactor{contract: contract}, LinkTokenFilterer: LinkTokenFilterer{contract: contract}}, nil } type LinkToken struct { diff --git a/core/gethwrappers/generated/log_emitter/log_emitter.go b/core/gethwrappers/generated/log_emitter/log_emitter.go index 4f0189dfde..3cb11da512 100644 --- a/core/gethwrappers/generated/log_emitter/log_emitter.go +++ b/core/gethwrappers/generated/log_emitter/log_emitter.go @@ -52,7 +52,7 @@ func DeployLogEmitter(auth *bind.TransactOpts, backend bind.ContractBackend) (co if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &LogEmitter{LogEmitterCaller: LogEmitterCaller{contract: contract}, LogEmitterTransactor: LogEmitterTransactor{contract: contract}, LogEmitterFilterer: LogEmitterFilterer{contract: contract}}, nil + return address, tx, &LogEmitter{address: address, abi: *parsed, LogEmitterCaller: LogEmitterCaller{contract: contract}, LogEmitterTransactor: LogEmitterTransactor{contract: contract}, LogEmitterFilterer: LogEmitterFilterer{contract: contract}}, nil } type LogEmitter struct { diff --git a/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go b/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go index 18b61baed7..ccd5aea2c3 100644 --- a/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go +++ b/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go @@ -63,7 +63,7 @@ func DeployLogTriggeredStreamsLookup(auth *bind.TransactOpts, backend bind.Contr if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &LogTriggeredStreamsLookup{LogTriggeredStreamsLookupCaller: LogTriggeredStreamsLookupCaller{contract: contract}, LogTriggeredStreamsLookupTransactor: LogTriggeredStreamsLookupTransactor{contract: contract}, LogTriggeredStreamsLookupFilterer: LogTriggeredStreamsLookupFilterer{contract: contract}}, nil + return address, tx, &LogTriggeredStreamsLookup{address: address, abi: *parsed, LogTriggeredStreamsLookupCaller: LogTriggeredStreamsLookupCaller{contract: contract}, LogTriggeredStreamsLookupTransactor: LogTriggeredStreamsLookupTransactor{contract: contract}, LogTriggeredStreamsLookupFilterer: LogTriggeredStreamsLookupFilterer{contract: contract}}, nil } type LogTriggeredStreamsLookup struct { diff --git a/core/gethwrappers/generated/log_upkeep_counter_wrapper/log_upkeep_counter_wrapper.go b/core/gethwrappers/generated/log_upkeep_counter_wrapper/log_upkeep_counter_wrapper.go index fd55349b12..51b7b753cc 100644 --- a/core/gethwrappers/generated/log_upkeep_counter_wrapper/log_upkeep_counter_wrapper.go +++ b/core/gethwrappers/generated/log_upkeep_counter_wrapper/log_upkeep_counter_wrapper.go @@ -63,7 +63,7 @@ func DeployLogUpkeepCounter(auth *bind.TransactOpts, backend bind.ContractBacken if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &LogUpkeepCounter{LogUpkeepCounterCaller: LogUpkeepCounterCaller{contract: contract}, LogUpkeepCounterTransactor: LogUpkeepCounterTransactor{contract: contract}, LogUpkeepCounterFilterer: LogUpkeepCounterFilterer{contract: contract}}, nil + return address, tx, &LogUpkeepCounter{address: address, abi: *parsed, LogUpkeepCounterCaller: LogUpkeepCounterCaller{contract: contract}, LogUpkeepCounterTransactor: LogUpkeepCounterTransactor{contract: contract}, LogUpkeepCounterFilterer: LogUpkeepCounterFilterer{contract: contract}}, nil } type LogUpkeepCounter struct { diff --git a/core/gethwrappers/generated/mock_aggregator_proxy/mock_aggregator_proxy.go b/core/gethwrappers/generated/mock_aggregator_proxy/mock_aggregator_proxy.go index 1694ebd11f..a9c972e8be 100644 --- a/core/gethwrappers/generated/mock_aggregator_proxy/mock_aggregator_proxy.go +++ b/core/gethwrappers/generated/mock_aggregator_proxy/mock_aggregator_proxy.go @@ -50,7 +50,7 @@ func DeployMockAggregatorProxy(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &MockAggregatorProxy{MockAggregatorProxyCaller: MockAggregatorProxyCaller{contract: contract}, MockAggregatorProxyTransactor: MockAggregatorProxyTransactor{contract: contract}, MockAggregatorProxyFilterer: MockAggregatorProxyFilterer{contract: contract}}, nil + return address, tx, &MockAggregatorProxy{address: address, abi: *parsed, MockAggregatorProxyCaller: MockAggregatorProxyCaller{contract: contract}, MockAggregatorProxyTransactor: MockAggregatorProxyTransactor{contract: contract}, MockAggregatorProxyFilterer: MockAggregatorProxyFilterer{contract: contract}}, nil } type MockAggregatorProxy struct { diff --git a/core/gethwrappers/generated/mock_ethlink_aggregator_wrapper/mock_ethlink_aggregator_wrapper.go b/core/gethwrappers/generated/mock_ethlink_aggregator_wrapper/mock_ethlink_aggregator_wrapper.go index bcf34a0c47..bc92e3f32b 100644 --- a/core/gethwrappers/generated/mock_ethlink_aggregator_wrapper/mock_ethlink_aggregator_wrapper.go +++ b/core/gethwrappers/generated/mock_ethlink_aggregator_wrapper/mock_ethlink_aggregator_wrapper.go @@ -50,7 +50,7 @@ func DeployMockETHLINKAggregator(auth *bind.TransactOpts, backend bind.ContractB if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &MockETHLINKAggregator{MockETHLINKAggregatorCaller: MockETHLINKAggregatorCaller{contract: contract}, MockETHLINKAggregatorTransactor: MockETHLINKAggregatorTransactor{contract: contract}, MockETHLINKAggregatorFilterer: MockETHLINKAggregatorFilterer{contract: contract}}, nil + return address, tx, &MockETHLINKAggregator{address: address, abi: *parsed, MockETHLINKAggregatorCaller: MockETHLINKAggregatorCaller{contract: contract}, MockETHLINKAggregatorTransactor: MockETHLINKAggregatorTransactor{contract: contract}, MockETHLINKAggregatorFilterer: MockETHLINKAggregatorFilterer{contract: contract}}, nil } type MockETHLINKAggregator struct { diff --git a/core/gethwrappers/generated/mock_gas_aggregator_wrapper/mock_gas_aggregator_wrapper.go b/core/gethwrappers/generated/mock_gas_aggregator_wrapper/mock_gas_aggregator_wrapper.go index edc0adc5b7..148417f3fc 100644 --- a/core/gethwrappers/generated/mock_gas_aggregator_wrapper/mock_gas_aggregator_wrapper.go +++ b/core/gethwrappers/generated/mock_gas_aggregator_wrapper/mock_gas_aggregator_wrapper.go @@ -50,7 +50,7 @@ func DeployMockGASAggregator(auth *bind.TransactOpts, backend bind.ContractBacke if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &MockGASAggregator{MockGASAggregatorCaller: MockGASAggregatorCaller{contract: contract}, MockGASAggregatorTransactor: MockGASAggregatorTransactor{contract: contract}, MockGASAggregatorFilterer: MockGASAggregatorFilterer{contract: contract}}, nil + return address, tx, &MockGASAggregator{address: address, abi: *parsed, MockGASAggregatorCaller: MockGASAggregatorCaller{contract: contract}, MockGASAggregatorTransactor: MockGASAggregatorTransactor{contract: contract}, MockGASAggregatorFilterer: MockGASAggregatorFilterer{contract: contract}}, nil } type MockGASAggregator struct { diff --git a/core/gethwrappers/generated/multiwordconsumer_wrapper/multiwordconsumer_wrapper.go b/core/gethwrappers/generated/multiwordconsumer_wrapper/multiwordconsumer_wrapper.go index c939418e57..9a1fc55b6c 100644 --- a/core/gethwrappers/generated/multiwordconsumer_wrapper/multiwordconsumer_wrapper.go +++ b/core/gethwrappers/generated/multiwordconsumer_wrapper/multiwordconsumer_wrapper.go @@ -52,7 +52,7 @@ func DeployMultiWordConsumer(auth *bind.TransactOpts, backend bind.ContractBacke if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &MultiWordConsumer{MultiWordConsumerCaller: MultiWordConsumerCaller{contract: contract}, MultiWordConsumerTransactor: MultiWordConsumerTransactor{contract: contract}, MultiWordConsumerFilterer: MultiWordConsumerFilterer{contract: contract}}, nil + return address, tx, &MultiWordConsumer{address: address, abi: *parsed, MultiWordConsumerCaller: MultiWordConsumerCaller{contract: contract}, MultiWordConsumerTransactor: MultiWordConsumerTransactor{contract: contract}, MultiWordConsumerFilterer: MultiWordConsumerFilterer{contract: contract}}, nil } type MultiWordConsumer struct { diff --git a/core/gethwrappers/generated/operator_factory/operator_factory.go b/core/gethwrappers/generated/operator_factory/operator_factory.go index b062f6b01a..c9a6c57ce2 100644 --- a/core/gethwrappers/generated/operator_factory/operator_factory.go +++ b/core/gethwrappers/generated/operator_factory/operator_factory.go @@ -52,7 +52,7 @@ func DeployOperatorFactory(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &OperatorFactory{OperatorFactoryCaller: OperatorFactoryCaller{contract: contract}, OperatorFactoryTransactor: OperatorFactoryTransactor{contract: contract}, OperatorFactoryFilterer: OperatorFactoryFilterer{contract: contract}}, nil + return address, tx, &OperatorFactory{address: address, abi: *parsed, OperatorFactoryCaller: OperatorFactoryCaller{contract: contract}, OperatorFactoryTransactor: OperatorFactoryTransactor{contract: contract}, OperatorFactoryFilterer: OperatorFactoryFilterer{contract: contract}}, nil } type OperatorFactory struct { diff --git a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go index 69541858f3..4b7f634763 100644 --- a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go +++ b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go @@ -52,7 +52,7 @@ func DeployOperator(auth *bind.TransactOpts, backend bind.ContractBackend, link if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Operator{OperatorCaller: OperatorCaller{contract: contract}, OperatorTransactor: OperatorTransactor{contract: contract}, OperatorFilterer: OperatorFilterer{contract: contract}}, nil + return address, tx, &Operator{address: address, abi: *parsed, OperatorCaller: OperatorCaller{contract: contract}, OperatorTransactor: OperatorTransactor{contract: contract}, OperatorFilterer: OperatorFilterer{contract: contract}}, nil } type Operator struct { diff --git a/core/gethwrappers/generated/oracle_wrapper/oracle_wrapper.go b/core/gethwrappers/generated/oracle_wrapper/oracle_wrapper.go index 98c7b37338..e22e6cd303 100644 --- a/core/gethwrappers/generated/oracle_wrapper/oracle_wrapper.go +++ b/core/gethwrappers/generated/oracle_wrapper/oracle_wrapper.go @@ -52,7 +52,7 @@ func DeployOracle(auth *bind.TransactOpts, backend bind.ContractBackend, _link c if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Oracle{OracleCaller: OracleCaller{contract: contract}, OracleTransactor: OracleTransactor{contract: contract}, OracleFilterer: OracleFilterer{contract: contract}}, nil + return address, tx, &Oracle{address: address, abi: *parsed, OracleCaller: OracleCaller{contract: contract}, OracleTransactor: OracleTransactor{contract: contract}, OracleFilterer: OracleFilterer{contract: contract}}, nil } type Oracle struct { diff --git a/core/gethwrappers/generated/perform_data_checker_wrapper/perform_data_checker_wrapper.go b/core/gethwrappers/generated/perform_data_checker_wrapper/perform_data_checker_wrapper.go index aa639deb9c..a678ad0a8d 100644 --- a/core/gethwrappers/generated/perform_data_checker_wrapper/perform_data_checker_wrapper.go +++ b/core/gethwrappers/generated/perform_data_checker_wrapper/perform_data_checker_wrapper.go @@ -50,7 +50,7 @@ func DeployPerformDataChecker(auth *bind.TransactOpts, backend bind.ContractBack if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &PerformDataChecker{PerformDataCheckerCaller: PerformDataCheckerCaller{contract: contract}, PerformDataCheckerTransactor: PerformDataCheckerTransactor{contract: contract}, PerformDataCheckerFilterer: PerformDataCheckerFilterer{contract: contract}}, nil + return address, tx, &PerformDataChecker{address: address, abi: *parsed, PerformDataCheckerCaller: PerformDataCheckerCaller{contract: contract}, PerformDataCheckerTransactor: PerformDataCheckerTransactor{contract: contract}, PerformDataCheckerFilterer: PerformDataCheckerFilterer{contract: contract}}, nil } type PerformDataChecker struct { diff --git a/core/gethwrappers/generated/solidity_vrf_consumer_interface/solidity_vrf_consumer_interface.go b/core/gethwrappers/generated/solidity_vrf_consumer_interface/solidity_vrf_consumer_interface.go index de123d5ec7..8c815be3a5 100644 --- a/core/gethwrappers/generated/solidity_vrf_consumer_interface/solidity_vrf_consumer_interface.go +++ b/core/gethwrappers/generated/solidity_vrf_consumer_interface/solidity_vrf_consumer_interface.go @@ -50,7 +50,7 @@ func DeployVRFConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _v if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFConsumer{VRFConsumerCaller: VRFConsumerCaller{contract: contract}, VRFConsumerTransactor: VRFConsumerTransactor{contract: contract}, VRFConsumerFilterer: VRFConsumerFilterer{contract: contract}}, nil + return address, tx, &VRFConsumer{address: address, abi: *parsed, VRFConsumerCaller: VRFConsumerCaller{contract: contract}, VRFConsumerTransactor: VRFConsumerTransactor{contract: contract}, VRFConsumerFilterer: VRFConsumerFilterer{contract: contract}}, nil } type VRFConsumer struct { diff --git a/core/gethwrappers/generated/solidity_vrf_consumer_interface_v08/solidity_vrf_consumer_interface_v08.go b/core/gethwrappers/generated/solidity_vrf_consumer_interface_v08/solidity_vrf_consumer_interface_v08.go index e122d3e07f..b3267a17ce 100644 --- a/core/gethwrappers/generated/solidity_vrf_consumer_interface_v08/solidity_vrf_consumer_interface_v08.go +++ b/core/gethwrappers/generated/solidity_vrf_consumer_interface_v08/solidity_vrf_consumer_interface_v08.go @@ -50,7 +50,7 @@ func DeployVRFConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, vr if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFConsumer{VRFConsumerCaller: VRFConsumerCaller{contract: contract}, VRFConsumerTransactor: VRFConsumerTransactor{contract: contract}, VRFConsumerFilterer: VRFConsumerFilterer{contract: contract}}, nil + return address, tx, &VRFConsumer{address: address, abi: *parsed, VRFConsumerCaller: VRFConsumerCaller{contract: contract}, VRFConsumerTransactor: VRFConsumerTransactor{contract: contract}, VRFConsumerFilterer: VRFConsumerFilterer{contract: contract}}, nil } type VRFConsumer struct { diff --git a/core/gethwrappers/generated/solidity_vrf_coordinator_interface/solidity_vrf_coordinator_interface.go b/core/gethwrappers/generated/solidity_vrf_coordinator_interface/solidity_vrf_coordinator_interface.go index 36c715a2c0..7ac2210dc7 100644 --- a/core/gethwrappers/generated/solidity_vrf_coordinator_interface/solidity_vrf_coordinator_interface.go +++ b/core/gethwrappers/generated/solidity_vrf_coordinator_interface/solidity_vrf_coordinator_interface.go @@ -52,7 +52,7 @@ func DeployVRFCoordinator(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFCoordinator{VRFCoordinatorCaller: VRFCoordinatorCaller{contract: contract}, VRFCoordinatorTransactor: VRFCoordinatorTransactor{contract: contract}, VRFCoordinatorFilterer: VRFCoordinatorFilterer{contract: contract}}, nil + return address, tx, &VRFCoordinator{address: address, abi: *parsed, VRFCoordinatorCaller: VRFCoordinatorCaller{contract: contract}, VRFCoordinatorTransactor: VRFCoordinatorTransactor{contract: contract}, VRFCoordinatorFilterer: VRFCoordinatorFilterer{contract: contract}}, nil } type VRFCoordinator struct { diff --git a/core/gethwrappers/generated/solidity_vrf_request_id/solidity_vrf_request_id.go b/core/gethwrappers/generated/solidity_vrf_request_id/solidity_vrf_request_id.go index fd35e245e4..b0d101a96c 100644 --- a/core/gethwrappers/generated/solidity_vrf_request_id/solidity_vrf_request_id.go +++ b/core/gethwrappers/generated/solidity_vrf_request_id/solidity_vrf_request_id.go @@ -50,7 +50,7 @@ func DeployVRFRequestIDBaseTestHelper(auth *bind.TransactOpts, backend bind.Cont if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFRequestIDBaseTestHelper{VRFRequestIDBaseTestHelperCaller: VRFRequestIDBaseTestHelperCaller{contract: contract}, VRFRequestIDBaseTestHelperTransactor: VRFRequestIDBaseTestHelperTransactor{contract: contract}, VRFRequestIDBaseTestHelperFilterer: VRFRequestIDBaseTestHelperFilterer{contract: contract}}, nil + return address, tx, &VRFRequestIDBaseTestHelper{address: address, abi: *parsed, VRFRequestIDBaseTestHelperCaller: VRFRequestIDBaseTestHelperCaller{contract: contract}, VRFRequestIDBaseTestHelperTransactor: VRFRequestIDBaseTestHelperTransactor{contract: contract}, VRFRequestIDBaseTestHelperFilterer: VRFRequestIDBaseTestHelperFilterer{contract: contract}}, nil } type VRFRequestIDBaseTestHelper struct { diff --git a/core/gethwrappers/generated/solidity_vrf_request_id_v08/solidity_vrf_request_id_v08.go b/core/gethwrappers/generated/solidity_vrf_request_id_v08/solidity_vrf_request_id_v08.go index 181226bfa3..5d931e3d90 100644 --- a/core/gethwrappers/generated/solidity_vrf_request_id_v08/solidity_vrf_request_id_v08.go +++ b/core/gethwrappers/generated/solidity_vrf_request_id_v08/solidity_vrf_request_id_v08.go @@ -50,7 +50,7 @@ func DeployVRFRequestIDBaseTestHelper(auth *bind.TransactOpts, backend bind.Cont if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFRequestIDBaseTestHelper{VRFRequestIDBaseTestHelperCaller: VRFRequestIDBaseTestHelperCaller{contract: contract}, VRFRequestIDBaseTestHelperTransactor: VRFRequestIDBaseTestHelperTransactor{contract: contract}, VRFRequestIDBaseTestHelperFilterer: VRFRequestIDBaseTestHelperFilterer{contract: contract}}, nil + return address, tx, &VRFRequestIDBaseTestHelper{address: address, abi: *parsed, VRFRequestIDBaseTestHelperCaller: VRFRequestIDBaseTestHelperCaller{contract: contract}, VRFRequestIDBaseTestHelperTransactor: VRFRequestIDBaseTestHelperTransactor{contract: contract}, VRFRequestIDBaseTestHelperFilterer: VRFRequestIDBaseTestHelperFilterer{contract: contract}}, nil } type VRFRequestIDBaseTestHelper struct { diff --git a/core/gethwrappers/generated/solidity_vrf_v08_verifier_wrapper/solidity_vrf_v08_verifier_wrapper.go b/core/gethwrappers/generated/solidity_vrf_v08_verifier_wrapper/solidity_vrf_v08_verifier_wrapper.go index 045c30e935..6eaf2b996f 100644 --- a/core/gethwrappers/generated/solidity_vrf_v08_verifier_wrapper/solidity_vrf_v08_verifier_wrapper.go +++ b/core/gethwrappers/generated/solidity_vrf_v08_verifier_wrapper/solidity_vrf_v08_verifier_wrapper.go @@ -62,7 +62,7 @@ func DeployVRFV08TestHelper(auth *bind.TransactOpts, backend bind.ContractBacken if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV08TestHelper{VRFV08TestHelperCaller: VRFV08TestHelperCaller{contract: contract}, VRFV08TestHelperTransactor: VRFV08TestHelperTransactor{contract: contract}, VRFV08TestHelperFilterer: VRFV08TestHelperFilterer{contract: contract}}, nil + return address, tx, &VRFV08TestHelper{address: address, abi: *parsed, VRFV08TestHelperCaller: VRFV08TestHelperCaller{contract: contract}, VRFV08TestHelperTransactor: VRFV08TestHelperTransactor{contract: contract}, VRFV08TestHelperFilterer: VRFV08TestHelperFilterer{contract: contract}}, nil } type VRFV08TestHelper struct { diff --git a/core/gethwrappers/generated/solidity_vrf_verifier_wrapper/solidity_vrf_verifier_wrapper.go b/core/gethwrappers/generated/solidity_vrf_verifier_wrapper/solidity_vrf_verifier_wrapper.go index a00768ee1b..b46cc3de08 100644 --- a/core/gethwrappers/generated/solidity_vrf_verifier_wrapper/solidity_vrf_verifier_wrapper.go +++ b/core/gethwrappers/generated/solidity_vrf_verifier_wrapper/solidity_vrf_verifier_wrapper.go @@ -50,7 +50,7 @@ func DeployVRFTestHelper(auth *bind.TransactOpts, backend bind.ContractBackend) if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFTestHelper{VRFTestHelperCaller: VRFTestHelperCaller{contract: contract}, VRFTestHelperTransactor: VRFTestHelperTransactor{contract: contract}, VRFTestHelperFilterer: VRFTestHelperFilterer{contract: contract}}, nil + return address, tx, &VRFTestHelper{address: address, abi: *parsed, VRFTestHelperCaller: VRFTestHelperCaller{contract: contract}, VRFTestHelperTransactor: VRFTestHelperTransactor{contract: contract}, VRFTestHelperFilterer: VRFTestHelperFilterer{contract: contract}}, nil } type VRFTestHelper struct { diff --git a/core/gethwrappers/generated/solidity_vrf_wrapper/solidity_vrf_wrapper.go b/core/gethwrappers/generated/solidity_vrf_wrapper/solidity_vrf_wrapper.go index fb16ff3a8b..82199d4538 100644 --- a/core/gethwrappers/generated/solidity_vrf_wrapper/solidity_vrf_wrapper.go +++ b/core/gethwrappers/generated/solidity_vrf_wrapper/solidity_vrf_wrapper.go @@ -50,7 +50,7 @@ func DeployVRF(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Ad if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRF{VRFCaller: VRFCaller{contract: contract}, VRFTransactor: VRFTransactor{contract: contract}, VRFFilterer: VRFFilterer{contract: contract}}, nil + return address, tx, &VRF{address: address, abi: *parsed, VRFCaller: VRFCaller{contract: contract}, VRFTransactor: VRFTransactor{contract: contract}, VRFFilterer: VRFFilterer{contract: contract}}, nil } type VRF struct { diff --git a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go index 3332ac8215..d54ee36f8f 100644 --- a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go @@ -52,7 +52,7 @@ func DeployStreamsLookupUpkeep(auth *bind.TransactOpts, backend bind.ContractBac if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &StreamsLookupUpkeep{StreamsLookupUpkeepCaller: StreamsLookupUpkeepCaller{contract: contract}, StreamsLookupUpkeepTransactor: StreamsLookupUpkeepTransactor{contract: contract}, StreamsLookupUpkeepFilterer: StreamsLookupUpkeepFilterer{contract: contract}}, nil + return address, tx, &StreamsLookupUpkeep{address: address, abi: *parsed, StreamsLookupUpkeepCaller: StreamsLookupUpkeepCaller{contract: contract}, StreamsLookupUpkeepTransactor: StreamsLookupUpkeepTransactor{contract: contract}, StreamsLookupUpkeepFilterer: StreamsLookupUpkeepFilterer{contract: contract}}, nil } type StreamsLookupUpkeep struct { diff --git a/core/gethwrappers/generated/test_api_consumer_wrapper/test_api_consumer_wrapper.go b/core/gethwrappers/generated/test_api_consumer_wrapper/test_api_consumer_wrapper.go index 8503d6f75e..71b26af95d 100644 --- a/core/gethwrappers/generated/test_api_consumer_wrapper/test_api_consumer_wrapper.go +++ b/core/gethwrappers/generated/test_api_consumer_wrapper/test_api_consumer_wrapper.go @@ -52,7 +52,7 @@ func DeployTestAPIConsumer(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &TestAPIConsumer{TestAPIConsumerCaller: TestAPIConsumerCaller{contract: contract}, TestAPIConsumerTransactor: TestAPIConsumerTransactor{contract: contract}, TestAPIConsumerFilterer: TestAPIConsumerFilterer{contract: contract}}, nil + return address, tx, &TestAPIConsumer{address: address, abi: *parsed, TestAPIConsumerCaller: TestAPIConsumerCaller{contract: contract}, TestAPIConsumerTransactor: TestAPIConsumerTransactor{contract: contract}, TestAPIConsumerFilterer: TestAPIConsumerFilterer{contract: contract}}, nil } type TestAPIConsumer struct { diff --git a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go index 43ae1a3f5b..c571b0a700 100644 --- a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go +++ b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go @@ -52,7 +52,7 @@ func DeployTrustedBlockhashStore(auth *bind.TransactOpts, backend bind.ContractB if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &TrustedBlockhashStore{TrustedBlockhashStoreCaller: TrustedBlockhashStoreCaller{contract: contract}, TrustedBlockhashStoreTransactor: TrustedBlockhashStoreTransactor{contract: contract}, TrustedBlockhashStoreFilterer: TrustedBlockhashStoreFilterer{contract: contract}}, nil + return address, tx, &TrustedBlockhashStore{address: address, abi: *parsed, TrustedBlockhashStoreCaller: TrustedBlockhashStoreCaller{contract: contract}, TrustedBlockhashStoreTransactor: TrustedBlockhashStoreTransactor{contract: contract}, TrustedBlockhashStoreFilterer: TrustedBlockhashStoreFilterer{contract: contract}}, nil } type TrustedBlockhashStore struct { diff --git a/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go b/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go index 4f9fe79d77..13db591730 100644 --- a/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go +++ b/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go @@ -52,7 +52,7 @@ func DeployUpkeepCounter(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &UpkeepCounter{UpkeepCounterCaller: UpkeepCounterCaller{contract: contract}, UpkeepCounterTransactor: UpkeepCounterTransactor{contract: contract}, UpkeepCounterFilterer: UpkeepCounterFilterer{contract: contract}}, nil + return address, tx, &UpkeepCounter{address: address, abi: *parsed, UpkeepCounterCaller: UpkeepCounterCaller{contract: contract}, UpkeepCounterTransactor: UpkeepCounterTransactor{contract: contract}, UpkeepCounterFilterer: UpkeepCounterFilterer{contract: contract}}, nil } type UpkeepCounter struct { diff --git a/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go b/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go index e6770fd074..e004ab6143 100644 --- a/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go +++ b/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go @@ -52,7 +52,7 @@ func DeployUpkeepPerformCounterRestrictive(auth *bind.TransactOpts, backend bind if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &UpkeepPerformCounterRestrictive{UpkeepPerformCounterRestrictiveCaller: UpkeepPerformCounterRestrictiveCaller{contract: contract}, UpkeepPerformCounterRestrictiveTransactor: UpkeepPerformCounterRestrictiveTransactor{contract: contract}, UpkeepPerformCounterRestrictiveFilterer: UpkeepPerformCounterRestrictiveFilterer{contract: contract}}, nil + return address, tx, &UpkeepPerformCounterRestrictive{address: address, abi: *parsed, UpkeepPerformCounterRestrictiveCaller: UpkeepPerformCounterRestrictiveCaller{contract: contract}, UpkeepPerformCounterRestrictiveTransactor: UpkeepPerformCounterRestrictiveTransactor{contract: contract}, UpkeepPerformCounterRestrictiveFilterer: UpkeepPerformCounterRestrictiveFilterer{contract: contract}}, nil } type UpkeepPerformCounterRestrictive struct { diff --git a/core/gethwrappers/generated/upkeep_transcoder/upkeep_transcoder.go b/core/gethwrappers/generated/upkeep_transcoder/upkeep_transcoder.go index a439dddd40..53d557d79a 100644 --- a/core/gethwrappers/generated/upkeep_transcoder/upkeep_transcoder.go +++ b/core/gethwrappers/generated/upkeep_transcoder/upkeep_transcoder.go @@ -50,7 +50,7 @@ func DeployUpkeepTranscoder(auth *bind.TransactOpts, backend bind.ContractBacken if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &UpkeepTranscoder{UpkeepTranscoderCaller: UpkeepTranscoderCaller{contract: contract}, UpkeepTranscoderTransactor: UpkeepTranscoderTransactor{contract: contract}, UpkeepTranscoderFilterer: UpkeepTranscoderFilterer{contract: contract}}, nil + return address, tx, &UpkeepTranscoder{address: address, abi: *parsed, UpkeepTranscoderCaller: UpkeepTranscoderCaller{contract: contract}, UpkeepTranscoderTransactor: UpkeepTranscoderTransactor{contract: contract}, UpkeepTranscoderFilterer: UpkeepTranscoderFilterer{contract: contract}}, nil } type UpkeepTranscoder struct { diff --git a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go index 52e241965f..9648c4bd71 100644 --- a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go @@ -76,7 +76,7 @@ func DeployVerifiableLoadLogTriggerUpkeep(auth *bind.TransactOpts, backend bind. if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VerifiableLoadLogTriggerUpkeep{VerifiableLoadLogTriggerUpkeepCaller: VerifiableLoadLogTriggerUpkeepCaller{contract: contract}, VerifiableLoadLogTriggerUpkeepTransactor: VerifiableLoadLogTriggerUpkeepTransactor{contract: contract}, VerifiableLoadLogTriggerUpkeepFilterer: VerifiableLoadLogTriggerUpkeepFilterer{contract: contract}}, nil + return address, tx, &VerifiableLoadLogTriggerUpkeep{address: address, abi: *parsed, VerifiableLoadLogTriggerUpkeepCaller: VerifiableLoadLogTriggerUpkeepCaller{contract: contract}, VerifiableLoadLogTriggerUpkeepTransactor: VerifiableLoadLogTriggerUpkeepTransactor{contract: contract}, VerifiableLoadLogTriggerUpkeepFilterer: VerifiableLoadLogTriggerUpkeepFilterer{contract: contract}}, nil } type VerifiableLoadLogTriggerUpkeep struct { diff --git a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go index e8a10d85dd..fc39ffb366 100644 --- a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go @@ -65,7 +65,7 @@ func DeployVerifiableLoadStreamsLookupUpkeep(auth *bind.TransactOpts, backend bi if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VerifiableLoadStreamsLookupUpkeep{VerifiableLoadStreamsLookupUpkeepCaller: VerifiableLoadStreamsLookupUpkeepCaller{contract: contract}, VerifiableLoadStreamsLookupUpkeepTransactor: VerifiableLoadStreamsLookupUpkeepTransactor{contract: contract}, VerifiableLoadStreamsLookupUpkeepFilterer: VerifiableLoadStreamsLookupUpkeepFilterer{contract: contract}}, nil + return address, tx, &VerifiableLoadStreamsLookupUpkeep{address: address, abi: *parsed, VerifiableLoadStreamsLookupUpkeepCaller: VerifiableLoadStreamsLookupUpkeepCaller{contract: contract}, VerifiableLoadStreamsLookupUpkeepTransactor: VerifiableLoadStreamsLookupUpkeepTransactor{contract: contract}, VerifiableLoadStreamsLookupUpkeepFilterer: VerifiableLoadStreamsLookupUpkeepFilterer{contract: contract}}, nil } type VerifiableLoadStreamsLookupUpkeep struct { diff --git a/core/gethwrappers/generated/verifiable_load_upkeep_wrapper/verifiable_load_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_upkeep_wrapper/verifiable_load_upkeep_wrapper.go index 6dc8e73f1f..b95f311f1c 100644 --- a/core/gethwrappers/generated/verifiable_load_upkeep_wrapper/verifiable_load_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_upkeep_wrapper/verifiable_load_upkeep_wrapper.go @@ -65,7 +65,7 @@ func DeployVerifiableLoadUpkeep(auth *bind.TransactOpts, backend bind.ContractBa if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VerifiableLoadUpkeep{VerifiableLoadUpkeepCaller: VerifiableLoadUpkeepCaller{contract: contract}, VerifiableLoadUpkeepTransactor: VerifiableLoadUpkeepTransactor{contract: contract}, VerifiableLoadUpkeepFilterer: VerifiableLoadUpkeepFilterer{contract: contract}}, nil + return address, tx, &VerifiableLoadUpkeep{address: address, abi: *parsed, VerifiableLoadUpkeepCaller: VerifiableLoadUpkeepCaller{contract: contract}, VerifiableLoadUpkeepTransactor: VerifiableLoadUpkeepTransactor{contract: contract}, VerifiableLoadUpkeepFilterer: VerifiableLoadUpkeepFilterer{contract: contract}}, nil } type VerifiableLoadUpkeep struct { diff --git a/core/gethwrappers/generated/vrf_consumer_v2/vrf_consumer_v2.go b/core/gethwrappers/generated/vrf_consumer_v2/vrf_consumer_v2.go index 8317e4c5b3..16090150fc 100644 --- a/core/gethwrappers/generated/vrf_consumer_v2/vrf_consumer_v2.go +++ b/core/gethwrappers/generated/vrf_consumer_v2/vrf_consumer_v2.go @@ -50,7 +50,7 @@ func DeployVRFConsumerV2(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFConsumerV2{VRFConsumerV2Caller: VRFConsumerV2Caller{contract: contract}, VRFConsumerV2Transactor: VRFConsumerV2Transactor{contract: contract}, VRFConsumerV2Filterer: VRFConsumerV2Filterer{contract: contract}}, nil + return address, tx, &VRFConsumerV2{address: address, abi: *parsed, VRFConsumerV2Caller: VRFConsumerV2Caller{contract: contract}, VRFConsumerV2Transactor: VRFConsumerV2Transactor{contract: contract}, VRFConsumerV2Filterer: VRFConsumerV2Filterer{contract: contract}}, nil } type VRFConsumerV2 struct { diff --git a/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go b/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go index fce0876ba3..deb678c4eb 100644 --- a/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go +++ b/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go @@ -52,7 +52,7 @@ func DeployVRFConsumerV2PlusUpgradeableExample(auth *bind.TransactOpts, backend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFConsumerV2PlusUpgradeableExample{VRFConsumerV2PlusUpgradeableExampleCaller: VRFConsumerV2PlusUpgradeableExampleCaller{contract: contract}, VRFConsumerV2PlusUpgradeableExampleTransactor: VRFConsumerV2PlusUpgradeableExampleTransactor{contract: contract}, VRFConsumerV2PlusUpgradeableExampleFilterer: VRFConsumerV2PlusUpgradeableExampleFilterer{contract: contract}}, nil + return address, tx, &VRFConsumerV2PlusUpgradeableExample{address: address, abi: *parsed, VRFConsumerV2PlusUpgradeableExampleCaller: VRFConsumerV2PlusUpgradeableExampleCaller{contract: contract}, VRFConsumerV2PlusUpgradeableExampleTransactor: VRFConsumerV2PlusUpgradeableExampleTransactor{contract: contract}, VRFConsumerV2PlusUpgradeableExampleFilterer: VRFConsumerV2PlusUpgradeableExampleFilterer{contract: contract}}, nil } type VRFConsumerV2PlusUpgradeableExample struct { diff --git a/core/gethwrappers/generated/vrf_consumer_v2_upgradeable_example/vrf_consumer_v2_upgradeable_example.go b/core/gethwrappers/generated/vrf_consumer_v2_upgradeable_example/vrf_consumer_v2_upgradeable_example.go index 72bdbce58a..5499868e32 100644 --- a/core/gethwrappers/generated/vrf_consumer_v2_upgradeable_example/vrf_consumer_v2_upgradeable_example.go +++ b/core/gethwrappers/generated/vrf_consumer_v2_upgradeable_example/vrf_consumer_v2_upgradeable_example.go @@ -52,7 +52,7 @@ func DeployVRFConsumerV2UpgradeableExample(auth *bind.TransactOpts, backend bind if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFConsumerV2UpgradeableExample{VRFConsumerV2UpgradeableExampleCaller: VRFConsumerV2UpgradeableExampleCaller{contract: contract}, VRFConsumerV2UpgradeableExampleTransactor: VRFConsumerV2UpgradeableExampleTransactor{contract: contract}, VRFConsumerV2UpgradeableExampleFilterer: VRFConsumerV2UpgradeableExampleFilterer{contract: contract}}, nil + return address, tx, &VRFConsumerV2UpgradeableExample{address: address, abi: *parsed, VRFConsumerV2UpgradeableExampleCaller: VRFConsumerV2UpgradeableExampleCaller{contract: contract}, VRFConsumerV2UpgradeableExampleTransactor: VRFConsumerV2UpgradeableExampleTransactor{contract: contract}, VRFConsumerV2UpgradeableExampleFilterer: VRFConsumerV2UpgradeableExampleFilterer{contract: contract}}, nil } type VRFConsumerV2UpgradeableExample struct { diff --git a/core/gethwrappers/generated/vrf_coordinator_mock/vrf_coordinator_mock.go b/core/gethwrappers/generated/vrf_coordinator_mock/vrf_coordinator_mock.go index 35fbabc8e2..961aa7b30c 100644 --- a/core/gethwrappers/generated/vrf_coordinator_mock/vrf_coordinator_mock.go +++ b/core/gethwrappers/generated/vrf_coordinator_mock/vrf_coordinator_mock.go @@ -52,7 +52,7 @@ func DeployVRFCoordinatorMock(auth *bind.TransactOpts, backend bind.ContractBack if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFCoordinatorMock{VRFCoordinatorMockCaller: VRFCoordinatorMockCaller{contract: contract}, VRFCoordinatorMockTransactor: VRFCoordinatorMockTransactor{contract: contract}, VRFCoordinatorMockFilterer: VRFCoordinatorMockFilterer{contract: contract}}, nil + return address, tx, &VRFCoordinatorMock{address: address, abi: *parsed, VRFCoordinatorMockCaller: VRFCoordinatorMockCaller{contract: contract}, VRFCoordinatorMockTransactor: VRFCoordinatorMockTransactor{contract: contract}, VRFCoordinatorMockFilterer: VRFCoordinatorMockFilterer{contract: contract}}, nil } type VRFCoordinatorMock struct { diff --git a/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go b/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go index 1f9ef1eda2..ffe32f7810 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go @@ -84,7 +84,7 @@ func DeployVRFCoordinatorV2(auth *bind.TransactOpts, backend bind.ContractBacken if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFCoordinatorV2{VRFCoordinatorV2Caller: VRFCoordinatorV2Caller{contract: contract}, VRFCoordinatorV2Transactor: VRFCoordinatorV2Transactor{contract: contract}, VRFCoordinatorV2Filterer: VRFCoordinatorV2Filterer{contract: contract}}, nil + return address, tx, &VRFCoordinatorV2{address: address, abi: *parsed, VRFCoordinatorV2Caller: VRFCoordinatorV2Caller{contract: contract}, VRFCoordinatorV2Transactor: VRFCoordinatorV2Transactor{contract: contract}, VRFCoordinatorV2Filterer: VRFCoordinatorV2Filterer{contract: contract}}, nil } type VRFCoordinatorV2 struct { diff --git a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go index e09c7c46e2..62e8b9f0de 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go @@ -87,7 +87,7 @@ func DeployVRFCoordinatorV25(auth *bind.TransactOpts, backend bind.ContractBacke if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFCoordinatorV25{VRFCoordinatorV25Caller: VRFCoordinatorV25Caller{contract: contract}, VRFCoordinatorV25Transactor: VRFCoordinatorV25Transactor{contract: contract}, VRFCoordinatorV25Filterer: VRFCoordinatorV25Filterer{contract: contract}}, nil + return address, tx, &VRFCoordinatorV25{address: address, abi: *parsed, VRFCoordinatorV25Caller: VRFCoordinatorV25Caller{contract: contract}, VRFCoordinatorV25Transactor: VRFCoordinatorV25Transactor{contract: contract}, VRFCoordinatorV25Filterer: VRFCoordinatorV25Filterer{contract: contract}}, nil } type VRFCoordinatorV25 struct { diff --git a/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go b/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go index dd7865fe8a..3d9efea9f7 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go @@ -59,7 +59,7 @@ func DeployVRFCoordinatorV2PlusV2Example(auth *bind.TransactOpts, backend bind.C if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFCoordinatorV2PlusV2Example{VRFCoordinatorV2PlusV2ExampleCaller: VRFCoordinatorV2PlusV2ExampleCaller{contract: contract}, VRFCoordinatorV2PlusV2ExampleTransactor: VRFCoordinatorV2PlusV2ExampleTransactor{contract: contract}, VRFCoordinatorV2PlusV2ExampleFilterer: VRFCoordinatorV2PlusV2ExampleFilterer{contract: contract}}, nil + return address, tx, &VRFCoordinatorV2PlusV2Example{address: address, abi: *parsed, VRFCoordinatorV2PlusV2ExampleCaller: VRFCoordinatorV2PlusV2ExampleCaller{contract: contract}, VRFCoordinatorV2PlusV2ExampleTransactor: VRFCoordinatorV2PlusV2ExampleTransactor{contract: contract}, VRFCoordinatorV2PlusV2ExampleFilterer: VRFCoordinatorV2PlusV2ExampleFilterer{contract: contract}}, nil } type VRFCoordinatorV2PlusV2Example struct { diff --git a/core/gethwrappers/generated/vrf_external_sub_owner_example/vrf_external_sub_owner_example.go b/core/gethwrappers/generated/vrf_external_sub_owner_example/vrf_external_sub_owner_example.go index 8752e2f39c..4ab3cdf591 100644 --- a/core/gethwrappers/generated/vrf_external_sub_owner_example/vrf_external_sub_owner_example.go +++ b/core/gethwrappers/generated/vrf_external_sub_owner_example/vrf_external_sub_owner_example.go @@ -50,7 +50,7 @@ func DeployVRFExternalSubOwnerExample(auth *bind.TransactOpts, backend bind.Cont if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFExternalSubOwnerExample{VRFExternalSubOwnerExampleCaller: VRFExternalSubOwnerExampleCaller{contract: contract}, VRFExternalSubOwnerExampleTransactor: VRFExternalSubOwnerExampleTransactor{contract: contract}, VRFExternalSubOwnerExampleFilterer: VRFExternalSubOwnerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFExternalSubOwnerExample{address: address, abi: *parsed, VRFExternalSubOwnerExampleCaller: VRFExternalSubOwnerExampleCaller{contract: contract}, VRFExternalSubOwnerExampleTransactor: VRFExternalSubOwnerExampleTransactor{contract: contract}, VRFExternalSubOwnerExampleFilterer: VRFExternalSubOwnerExampleFilterer{contract: contract}}, nil } type VRFExternalSubOwnerExample struct { diff --git a/core/gethwrappers/generated/vrf_load_test_external_sub_owner/vrf_load_test_external_sub_owner.go b/core/gethwrappers/generated/vrf_load_test_external_sub_owner/vrf_load_test_external_sub_owner.go index ea3302d2e7..e98239eb4e 100644 --- a/core/gethwrappers/generated/vrf_load_test_external_sub_owner/vrf_load_test_external_sub_owner.go +++ b/core/gethwrappers/generated/vrf_load_test_external_sub_owner/vrf_load_test_external_sub_owner.go @@ -52,7 +52,7 @@ func DeployVRFLoadTestExternalSubOwner(auth *bind.TransactOpts, backend bind.Con if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFLoadTestExternalSubOwner{VRFLoadTestExternalSubOwnerCaller: VRFLoadTestExternalSubOwnerCaller{contract: contract}, VRFLoadTestExternalSubOwnerTransactor: VRFLoadTestExternalSubOwnerTransactor{contract: contract}, VRFLoadTestExternalSubOwnerFilterer: VRFLoadTestExternalSubOwnerFilterer{contract: contract}}, nil + return address, tx, &VRFLoadTestExternalSubOwner{address: address, abi: *parsed, VRFLoadTestExternalSubOwnerCaller: VRFLoadTestExternalSubOwnerCaller{contract: contract}, VRFLoadTestExternalSubOwnerTransactor: VRFLoadTestExternalSubOwnerTransactor{contract: contract}, VRFLoadTestExternalSubOwnerFilterer: VRFLoadTestExternalSubOwnerFilterer{contract: contract}}, nil } type VRFLoadTestExternalSubOwner struct { diff --git a/core/gethwrappers/generated/vrf_load_test_ownerless_consumer/vrf_load_test_ownerless_consumer.go b/core/gethwrappers/generated/vrf_load_test_ownerless_consumer/vrf_load_test_ownerless_consumer.go index 6beadf5ad5..fea4360e50 100644 --- a/core/gethwrappers/generated/vrf_load_test_ownerless_consumer/vrf_load_test_ownerless_consumer.go +++ b/core/gethwrappers/generated/vrf_load_test_ownerless_consumer/vrf_load_test_ownerless_consumer.go @@ -50,7 +50,7 @@ func DeployVRFLoadTestOwnerlessConsumer(auth *bind.TransactOpts, backend bind.Co if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFLoadTestOwnerlessConsumer{VRFLoadTestOwnerlessConsumerCaller: VRFLoadTestOwnerlessConsumerCaller{contract: contract}, VRFLoadTestOwnerlessConsumerTransactor: VRFLoadTestOwnerlessConsumerTransactor{contract: contract}, VRFLoadTestOwnerlessConsumerFilterer: VRFLoadTestOwnerlessConsumerFilterer{contract: contract}}, nil + return address, tx, &VRFLoadTestOwnerlessConsumer{address: address, abi: *parsed, VRFLoadTestOwnerlessConsumerCaller: VRFLoadTestOwnerlessConsumerCaller{contract: contract}, VRFLoadTestOwnerlessConsumerTransactor: VRFLoadTestOwnerlessConsumerTransactor{contract: contract}, VRFLoadTestOwnerlessConsumerFilterer: VRFLoadTestOwnerlessConsumerFilterer{contract: contract}}, nil } type VRFLoadTestOwnerlessConsumer struct { diff --git a/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go b/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go index 93d50b72dd..76b5e267d3 100644 --- a/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go +++ b/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go @@ -52,7 +52,7 @@ func DeployVRFV2LoadTestWithMetrics(auth *bind.TransactOpts, backend bind.Contra if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2LoadTestWithMetrics{VRFV2LoadTestWithMetricsCaller: VRFV2LoadTestWithMetricsCaller{contract: contract}, VRFV2LoadTestWithMetricsTransactor: VRFV2LoadTestWithMetricsTransactor{contract: contract}, VRFV2LoadTestWithMetricsFilterer: VRFV2LoadTestWithMetricsFilterer{contract: contract}}, nil + return address, tx, &VRFV2LoadTestWithMetrics{address: address, abi: *parsed, VRFV2LoadTestWithMetricsCaller: VRFV2LoadTestWithMetricsCaller{contract: contract}, VRFV2LoadTestWithMetricsTransactor: VRFV2LoadTestWithMetricsTransactor{contract: contract}, VRFV2LoadTestWithMetricsFilterer: VRFV2LoadTestWithMetricsFilterer{contract: contract}}, nil } type VRFV2LoadTestWithMetrics struct { diff --git a/core/gethwrappers/generated/vrf_malicious_consumer_v2/vrf_malicious_consumer_v2.go b/core/gethwrappers/generated/vrf_malicious_consumer_v2/vrf_malicious_consumer_v2.go index 5fb16e00e8..1fe5e61f3a 100644 --- a/core/gethwrappers/generated/vrf_malicious_consumer_v2/vrf_malicious_consumer_v2.go +++ b/core/gethwrappers/generated/vrf_malicious_consumer_v2/vrf_malicious_consumer_v2.go @@ -50,7 +50,7 @@ func DeployVRFMaliciousConsumerV2(auth *bind.TransactOpts, backend bind.Contract if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFMaliciousConsumerV2{VRFMaliciousConsumerV2Caller: VRFMaliciousConsumerV2Caller{contract: contract}, VRFMaliciousConsumerV2Transactor: VRFMaliciousConsumerV2Transactor{contract: contract}, VRFMaliciousConsumerV2Filterer: VRFMaliciousConsumerV2Filterer{contract: contract}}, nil + return address, tx, &VRFMaliciousConsumerV2{address: address, abi: *parsed, VRFMaliciousConsumerV2Caller: VRFMaliciousConsumerV2Caller{contract: contract}, VRFMaliciousConsumerV2Transactor: VRFMaliciousConsumerV2Transactor{contract: contract}, VRFMaliciousConsumerV2Filterer: VRFMaliciousConsumerV2Filterer{contract: contract}}, nil } type VRFMaliciousConsumerV2 struct { diff --git a/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go b/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go index 64a5cace7f..df5a49a8de 100644 --- a/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go +++ b/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go @@ -52,7 +52,7 @@ func DeployVRFMaliciousConsumerV2Plus(auth *bind.TransactOpts, backend bind.Cont if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFMaliciousConsumerV2Plus{VRFMaliciousConsumerV2PlusCaller: VRFMaliciousConsumerV2PlusCaller{contract: contract}, VRFMaliciousConsumerV2PlusTransactor: VRFMaliciousConsumerV2PlusTransactor{contract: contract}, VRFMaliciousConsumerV2PlusFilterer: VRFMaliciousConsumerV2PlusFilterer{contract: contract}}, nil + return address, tx, &VRFMaliciousConsumerV2Plus{address: address, abi: *parsed, VRFMaliciousConsumerV2PlusCaller: VRFMaliciousConsumerV2PlusCaller{contract: contract}, VRFMaliciousConsumerV2PlusTransactor: VRFMaliciousConsumerV2PlusTransactor{contract: contract}, VRFMaliciousConsumerV2PlusFilterer: VRFMaliciousConsumerV2PlusFilterer{contract: contract}}, nil } type VRFMaliciousConsumerV2Plus struct { diff --git a/core/gethwrappers/generated/vrf_owner/vrf_owner.go b/core/gethwrappers/generated/vrf_owner/vrf_owner.go index 8a97fcf5aa..b029bd393f 100644 --- a/core/gethwrappers/generated/vrf_owner/vrf_owner.go +++ b/core/gethwrappers/generated/vrf_owner/vrf_owner.go @@ -84,7 +84,7 @@ func DeployVRFOwner(auth *bind.TransactOpts, backend bind.ContractBackend, _vrfC if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFOwner{VRFOwnerCaller: VRFOwnerCaller{contract: contract}, VRFOwnerTransactor: VRFOwnerTransactor{contract: contract}, VRFOwnerFilterer: VRFOwnerFilterer{contract: contract}}, nil + return address, tx, &VRFOwner{address: address, abi: *parsed, VRFOwnerCaller: VRFOwnerCaller{contract: contract}, VRFOwnerTransactor: VRFOwnerTransactor{contract: contract}, VRFOwnerFilterer: VRFOwnerFilterer{contract: contract}}, nil } type VRFOwner struct { diff --git a/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go b/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go index ce42ddb7d6..8a17b64378 100644 --- a/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go +++ b/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go @@ -52,7 +52,7 @@ func DeployVRFV2OwnerTestConsumer(auth *bind.TransactOpts, backend bind.Contract if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2OwnerTestConsumer{VRFV2OwnerTestConsumerCaller: VRFV2OwnerTestConsumerCaller{contract: contract}, VRFV2OwnerTestConsumerTransactor: VRFV2OwnerTestConsumerTransactor{contract: contract}, VRFV2OwnerTestConsumerFilterer: VRFV2OwnerTestConsumerFilterer{contract: contract}}, nil + return address, tx, &VRFV2OwnerTestConsumer{address: address, abi: *parsed, VRFV2OwnerTestConsumerCaller: VRFV2OwnerTestConsumerCaller{contract: contract}, VRFV2OwnerTestConsumerTransactor: VRFV2OwnerTestConsumerTransactor{contract: contract}, VRFV2OwnerTestConsumerFilterer: VRFV2OwnerTestConsumerFilterer{contract: contract}}, nil } type VRFV2OwnerTestConsumer struct { diff --git a/core/gethwrappers/generated/vrf_ownerless_consumer_example/vrf_ownerless_consumer_example.go b/core/gethwrappers/generated/vrf_ownerless_consumer_example/vrf_ownerless_consumer_example.go index c71553ac81..697a862533 100644 --- a/core/gethwrappers/generated/vrf_ownerless_consumer_example/vrf_ownerless_consumer_example.go +++ b/core/gethwrappers/generated/vrf_ownerless_consumer_example/vrf_ownerless_consumer_example.go @@ -50,7 +50,7 @@ func DeployVRFOwnerlessConsumerExample(auth *bind.TransactOpts, backend bind.Con if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFOwnerlessConsumerExample{VRFOwnerlessConsumerExampleCaller: VRFOwnerlessConsumerExampleCaller{contract: contract}, VRFOwnerlessConsumerExampleTransactor: VRFOwnerlessConsumerExampleTransactor{contract: contract}, VRFOwnerlessConsumerExampleFilterer: VRFOwnerlessConsumerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFOwnerlessConsumerExample{address: address, abi: *parsed, VRFOwnerlessConsumerExampleCaller: VRFOwnerlessConsumerExampleCaller{contract: contract}, VRFOwnerlessConsumerExampleTransactor: VRFOwnerlessConsumerExampleTransactor{contract: contract}, VRFOwnerlessConsumerExampleFilterer: VRFOwnerlessConsumerExampleFilterer{contract: contract}}, nil } type VRFOwnerlessConsumerExample struct { diff --git a/core/gethwrappers/generated/vrf_single_consumer_example/vrf_single_consumer_example.go b/core/gethwrappers/generated/vrf_single_consumer_example/vrf_single_consumer_example.go index affc8c5371..ac5c081ab3 100644 --- a/core/gethwrappers/generated/vrf_single_consumer_example/vrf_single_consumer_example.go +++ b/core/gethwrappers/generated/vrf_single_consumer_example/vrf_single_consumer_example.go @@ -50,7 +50,7 @@ func DeployVRFSingleConsumerExample(auth *bind.TransactOpts, backend bind.Contra if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFSingleConsumerExample{VRFSingleConsumerExampleCaller: VRFSingleConsumerExampleCaller{contract: contract}, VRFSingleConsumerExampleTransactor: VRFSingleConsumerExampleTransactor{contract: contract}, VRFSingleConsumerExampleFilterer: VRFSingleConsumerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFSingleConsumerExample{address: address, abi: *parsed, VRFSingleConsumerExampleCaller: VRFSingleConsumerExampleCaller{contract: contract}, VRFSingleConsumerExampleTransactor: VRFSingleConsumerExampleTransactor{contract: contract}, VRFSingleConsumerExampleFilterer: VRFSingleConsumerExampleFilterer{contract: contract}}, nil } type VRFSingleConsumerExample struct { diff --git a/core/gethwrappers/generated/vrf_v2_consumer_wrapper/vrf_v2_consumer_wrapper.go b/core/gethwrappers/generated/vrf_v2_consumer_wrapper/vrf_v2_consumer_wrapper.go index a5d5794580..e35efc9ec8 100644 --- a/core/gethwrappers/generated/vrf_v2_consumer_wrapper/vrf_v2_consumer_wrapper.go +++ b/core/gethwrappers/generated/vrf_v2_consumer_wrapper/vrf_v2_consumer_wrapper.go @@ -52,7 +52,7 @@ func DeployVRFv2Consumer(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFv2Consumer{VRFv2ConsumerCaller: VRFv2ConsumerCaller{contract: contract}, VRFv2ConsumerTransactor: VRFv2ConsumerTransactor{contract: contract}, VRFv2ConsumerFilterer: VRFv2ConsumerFilterer{contract: contract}}, nil + return address, tx, &VRFv2Consumer{address: address, abi: *parsed, VRFv2ConsumerCaller: VRFv2ConsumerCaller{contract: contract}, VRFv2ConsumerTransactor: VRFv2ConsumerTransactor{contract: contract}, VRFv2ConsumerFilterer: VRFv2ConsumerFilterer{contract: contract}}, nil } type VRFv2Consumer struct { diff --git a/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go b/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go index c8971595c5..017423772f 100644 --- a/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go +++ b/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusLoadTestWithMetrics(auth *bind.TransactOpts, backend bind.Co if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusLoadTestWithMetrics{VRFV2PlusLoadTestWithMetricsCaller: VRFV2PlusLoadTestWithMetricsCaller{contract: contract}, VRFV2PlusLoadTestWithMetricsTransactor: VRFV2PlusLoadTestWithMetricsTransactor{contract: contract}, VRFV2PlusLoadTestWithMetricsFilterer: VRFV2PlusLoadTestWithMetricsFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusLoadTestWithMetrics{address: address, abi: *parsed, VRFV2PlusLoadTestWithMetricsCaller: VRFV2PlusLoadTestWithMetricsCaller{contract: contract}, VRFV2PlusLoadTestWithMetricsTransactor: VRFV2PlusLoadTestWithMetricsTransactor{contract: contract}, VRFV2PlusLoadTestWithMetricsFilterer: VRFV2PlusLoadTestWithMetricsFilterer{contract: contract}}, nil } type VRFV2PlusLoadTestWithMetrics struct { diff --git a/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go b/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go index afa659269d..b9de348b10 100644 --- a/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go +++ b/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusSingleConsumerExample(auth *bind.TransactOpts, backend bind. if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusSingleConsumerExample{VRFV2PlusSingleConsumerExampleCaller: VRFV2PlusSingleConsumerExampleCaller{contract: contract}, VRFV2PlusSingleConsumerExampleTransactor: VRFV2PlusSingleConsumerExampleTransactor{contract: contract}, VRFV2PlusSingleConsumerExampleFilterer: VRFV2PlusSingleConsumerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusSingleConsumerExample{address: address, abi: *parsed, VRFV2PlusSingleConsumerExampleCaller: VRFV2PlusSingleConsumerExampleCaller{contract: contract}, VRFV2PlusSingleConsumerExampleTransactor: VRFV2PlusSingleConsumerExampleTransactor{contract: contract}, VRFV2PlusSingleConsumerExampleFilterer: VRFV2PlusSingleConsumerExampleFilterer{contract: contract}}, nil } type VRFV2PlusSingleConsumerExample struct { diff --git a/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go b/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go index da32a6a202..8cc57fce6c 100644 --- a/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go +++ b/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusExternalSubOwnerExample(auth *bind.TransactOpts, backend bin if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusExternalSubOwnerExample{VRFV2PlusExternalSubOwnerExampleCaller: VRFV2PlusExternalSubOwnerExampleCaller{contract: contract}, VRFV2PlusExternalSubOwnerExampleTransactor: VRFV2PlusExternalSubOwnerExampleTransactor{contract: contract}, VRFV2PlusExternalSubOwnerExampleFilterer: VRFV2PlusExternalSubOwnerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusExternalSubOwnerExample{address: address, abi: *parsed, VRFV2PlusExternalSubOwnerExampleCaller: VRFV2PlusExternalSubOwnerExampleCaller{contract: contract}, VRFV2PlusExternalSubOwnerExampleTransactor: VRFV2PlusExternalSubOwnerExampleTransactor{contract: contract}, VRFV2PlusExternalSubOwnerExampleFilterer: VRFV2PlusExternalSubOwnerExampleFilterer{contract: contract}}, nil } type VRFV2PlusExternalSubOwnerExample struct { diff --git a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go index 852501d09e..7aae3d3777 100644 --- a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go +++ b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go @@ -87,7 +87,7 @@ func DeployVRFCoordinatorV2PlusUpgradedVersion(auth *bind.TransactOpts, backend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFCoordinatorV2PlusUpgradedVersion{VRFCoordinatorV2PlusUpgradedVersionCaller: VRFCoordinatorV2PlusUpgradedVersionCaller{contract: contract}, VRFCoordinatorV2PlusUpgradedVersionTransactor: VRFCoordinatorV2PlusUpgradedVersionTransactor{contract: contract}, VRFCoordinatorV2PlusUpgradedVersionFilterer: VRFCoordinatorV2PlusUpgradedVersionFilterer{contract: contract}}, nil + return address, tx, &VRFCoordinatorV2PlusUpgradedVersion{address: address, abi: *parsed, VRFCoordinatorV2PlusUpgradedVersionCaller: VRFCoordinatorV2PlusUpgradedVersionCaller{contract: contract}, VRFCoordinatorV2PlusUpgradedVersionTransactor: VRFCoordinatorV2PlusUpgradedVersionTransactor{contract: contract}, VRFCoordinatorV2PlusUpgradedVersionFilterer: VRFCoordinatorV2PlusUpgradedVersionFilterer{contract: contract}}, nil } type VRFCoordinatorV2PlusUpgradedVersion struct { diff --git a/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go b/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go index 2cb4edd208..d92679f4ad 100644 --- a/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go +++ b/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go @@ -52,7 +52,7 @@ func DeployVRFV2ProxyAdmin(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2ProxyAdmin{VRFV2ProxyAdminCaller: VRFV2ProxyAdminCaller{contract: contract}, VRFV2ProxyAdminTransactor: VRFV2ProxyAdminTransactor{contract: contract}, VRFV2ProxyAdminFilterer: VRFV2ProxyAdminFilterer{contract: contract}}, nil + return address, tx, &VRFV2ProxyAdmin{address: address, abi: *parsed, VRFV2ProxyAdminCaller: VRFV2ProxyAdminCaller{contract: contract}, VRFV2ProxyAdminTransactor: VRFV2ProxyAdminTransactor{contract: contract}, VRFV2ProxyAdminFilterer: VRFV2ProxyAdminFilterer{contract: contract}}, nil } type VRFV2ProxyAdmin struct { diff --git a/core/gethwrappers/generated/vrfv2_reverting_example/vrfv2_reverting_example.go b/core/gethwrappers/generated/vrfv2_reverting_example/vrfv2_reverting_example.go index 9f8a4eb0fa..facfc931c9 100644 --- a/core/gethwrappers/generated/vrfv2_reverting_example/vrfv2_reverting_example.go +++ b/core/gethwrappers/generated/vrfv2_reverting_example/vrfv2_reverting_example.go @@ -50,7 +50,7 @@ func DeployVRFV2RevertingExample(auth *bind.TransactOpts, backend bind.ContractB if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2RevertingExample{VRFV2RevertingExampleCaller: VRFV2RevertingExampleCaller{contract: contract}, VRFV2RevertingExampleTransactor: VRFV2RevertingExampleTransactor{contract: contract}, VRFV2RevertingExampleFilterer: VRFV2RevertingExampleFilterer{contract: contract}}, nil + return address, tx, &VRFV2RevertingExample{address: address, abi: *parsed, VRFV2RevertingExampleCaller: VRFV2RevertingExampleCaller{contract: contract}, VRFV2RevertingExampleTransactor: VRFV2RevertingExampleTransactor{contract: contract}, VRFV2RevertingExampleFilterer: VRFV2RevertingExampleFilterer{contract: contract}}, nil } type VRFV2RevertingExample struct { diff --git a/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go b/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go index 657cc1894f..c808650a08 100644 --- a/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go +++ b/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go @@ -52,7 +52,7 @@ func DeployVRFV2TransparentUpgradeableProxy(auth *bind.TransactOpts, backend bin if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2TransparentUpgradeableProxy{VRFV2TransparentUpgradeableProxyCaller: VRFV2TransparentUpgradeableProxyCaller{contract: contract}, VRFV2TransparentUpgradeableProxyTransactor: VRFV2TransparentUpgradeableProxyTransactor{contract: contract}, VRFV2TransparentUpgradeableProxyFilterer: VRFV2TransparentUpgradeableProxyFilterer{contract: contract}}, nil + return address, tx, &VRFV2TransparentUpgradeableProxy{address: address, abi: *parsed, VRFV2TransparentUpgradeableProxyCaller: VRFV2TransparentUpgradeableProxyCaller{contract: contract}, VRFV2TransparentUpgradeableProxyTransactor: VRFV2TransparentUpgradeableProxyTransactor{contract: contract}, VRFV2TransparentUpgradeableProxyFilterer: VRFV2TransparentUpgradeableProxyFilterer{contract: contract}}, nil } type VRFV2TransparentUpgradeableProxy struct { diff --git a/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go b/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go index 61cb52e117..9e7e25229e 100644 --- a/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go +++ b/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go @@ -52,7 +52,7 @@ func DeployVRFV2Wrapper(auth *bind.TransactOpts, backend bind.ContractBackend, _ if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2Wrapper{VRFV2WrapperCaller: VRFV2WrapperCaller{contract: contract}, VRFV2WrapperTransactor: VRFV2WrapperTransactor{contract: contract}, VRFV2WrapperFilterer: VRFV2WrapperFilterer{contract: contract}}, nil + return address, tx, &VRFV2Wrapper{address: address, abi: *parsed, VRFV2WrapperCaller: VRFV2WrapperCaller{contract: contract}, VRFV2WrapperTransactor: VRFV2WrapperTransactor{contract: contract}, VRFV2WrapperFilterer: VRFV2WrapperFilterer{contract: contract}}, nil } type VRFV2Wrapper struct { diff --git a/core/gethwrappers/generated/vrfv2_wrapper_consumer_example/vrfv2_wrapper_consumer_example.go b/core/gethwrappers/generated/vrfv2_wrapper_consumer_example/vrfv2_wrapper_consumer_example.go index ba38ddf436..dbf5d97f9c 100644 --- a/core/gethwrappers/generated/vrfv2_wrapper_consumer_example/vrfv2_wrapper_consumer_example.go +++ b/core/gethwrappers/generated/vrfv2_wrapper_consumer_example/vrfv2_wrapper_consumer_example.go @@ -52,7 +52,7 @@ func DeployVRFV2WrapperConsumerExample(auth *bind.TransactOpts, backend bind.Con if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2WrapperConsumerExample{VRFV2WrapperConsumerExampleCaller: VRFV2WrapperConsumerExampleCaller{contract: contract}, VRFV2WrapperConsumerExampleTransactor: VRFV2WrapperConsumerExampleTransactor{contract: contract}, VRFV2WrapperConsumerExampleFilterer: VRFV2WrapperConsumerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFV2WrapperConsumerExample{address: address, abi: *parsed, VRFV2WrapperConsumerExampleCaller: VRFV2WrapperConsumerExampleCaller{contract: contract}, VRFV2WrapperConsumerExampleTransactor: VRFV2WrapperConsumerExampleTransactor{contract: contract}, VRFV2WrapperConsumerExampleFilterer: VRFV2WrapperConsumerExampleFilterer{contract: contract}}, nil } type VRFV2WrapperConsumerExample struct { diff --git a/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go b/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go index 91112ff856..f6a65a63f2 100644 --- a/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go +++ b/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go @@ -50,7 +50,7 @@ func DeployVRFV2PlusClient(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusClient{VRFV2PlusClientCaller: VRFV2PlusClientCaller{contract: contract}, VRFV2PlusClientTransactor: VRFV2PlusClientTransactor{contract: contract}, VRFV2PlusClientFilterer: VRFV2PlusClientFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusClient{address: address, abi: *parsed, VRFV2PlusClientCaller: VRFV2PlusClientCaller{contract: contract}, VRFV2PlusClientTransactor: VRFV2PlusClientTransactor{contract: contract}, VRFV2PlusClientFilterer: VRFV2PlusClientFilterer{contract: contract}}, nil } type VRFV2PlusClient struct { diff --git a/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go b/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go index 2ad412a122..20f3d4422b 100644 --- a/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go +++ b/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusConsumerExample(auth *bind.TransactOpts, backend bind.Contra if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusConsumerExample{VRFV2PlusConsumerExampleCaller: VRFV2PlusConsumerExampleCaller{contract: contract}, VRFV2PlusConsumerExampleTransactor: VRFV2PlusConsumerExampleTransactor{contract: contract}, VRFV2PlusConsumerExampleFilterer: VRFV2PlusConsumerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusConsumerExample{address: address, abi: *parsed, VRFV2PlusConsumerExampleCaller: VRFV2PlusConsumerExampleCaller{contract: contract}, VRFV2PlusConsumerExampleTransactor: VRFV2PlusConsumerExampleTransactor{contract: contract}, VRFV2PlusConsumerExampleFilterer: VRFV2PlusConsumerExampleFilterer{contract: contract}}, nil } type VRFV2PlusConsumerExample struct { diff --git a/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go b/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go index c0c19a1134..03c5ffd8cc 100644 --- a/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go +++ b/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go @@ -50,7 +50,7 @@ func DeployVRFV2PlusMaliciousMigrator(auth *bind.TransactOpts, backend bind.Cont if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusMaliciousMigrator{VRFV2PlusMaliciousMigratorCaller: VRFV2PlusMaliciousMigratorCaller{contract: contract}, VRFV2PlusMaliciousMigratorTransactor: VRFV2PlusMaliciousMigratorTransactor{contract: contract}, VRFV2PlusMaliciousMigratorFilterer: VRFV2PlusMaliciousMigratorFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusMaliciousMigrator{address: address, abi: *parsed, VRFV2PlusMaliciousMigratorCaller: VRFV2PlusMaliciousMigratorCaller{contract: contract}, VRFV2PlusMaliciousMigratorTransactor: VRFV2PlusMaliciousMigratorTransactor{contract: contract}, VRFV2PlusMaliciousMigratorFilterer: VRFV2PlusMaliciousMigratorFilterer{contract: contract}}, nil } type VRFV2PlusMaliciousMigrator struct { diff --git a/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go b/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go index 7236470139..5e66eb2474 100644 --- a/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go +++ b/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusRevertingExample(auth *bind.TransactOpts, backend bind.Contr if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusRevertingExample{VRFV2PlusRevertingExampleCaller: VRFV2PlusRevertingExampleCaller{contract: contract}, VRFV2PlusRevertingExampleTransactor: VRFV2PlusRevertingExampleTransactor{contract: contract}, VRFV2PlusRevertingExampleFilterer: VRFV2PlusRevertingExampleFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusRevertingExample{address: address, abi: *parsed, VRFV2PlusRevertingExampleCaller: VRFV2PlusRevertingExampleCaller{contract: contract}, VRFV2PlusRevertingExampleTransactor: VRFV2PlusRevertingExampleTransactor{contract: contract}, VRFV2PlusRevertingExampleFilterer: VRFV2PlusRevertingExampleFilterer{contract: contract}}, nil } type VRFV2PlusRevertingExample struct { diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go index d7894c576e..5a5ccb34f1 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusWrapper(auth *bind.TransactOpts, backend bind.ContractBacken if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusWrapper{VRFV2PlusWrapperCaller: VRFV2PlusWrapperCaller{contract: contract}, VRFV2PlusWrapperTransactor: VRFV2PlusWrapperTransactor{contract: contract}, VRFV2PlusWrapperFilterer: VRFV2PlusWrapperFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusWrapper{address: address, abi: *parsed, VRFV2PlusWrapperCaller: VRFV2PlusWrapperCaller{contract: contract}, VRFV2PlusWrapperTransactor: VRFV2PlusWrapperTransactor{contract: contract}, VRFV2PlusWrapperFilterer: VRFV2PlusWrapperFilterer{contract: contract}}, nil } type VRFV2PlusWrapper struct { diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go b/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go index 9cbd5ef964..ee2f1e360b 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusWrapperConsumerExample(auth *bind.TransactOpts, backend bind if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusWrapperConsumerExample{VRFV2PlusWrapperConsumerExampleCaller: VRFV2PlusWrapperConsumerExampleCaller{contract: contract}, VRFV2PlusWrapperConsumerExampleTransactor: VRFV2PlusWrapperConsumerExampleTransactor{contract: contract}, VRFV2PlusWrapperConsumerExampleFilterer: VRFV2PlusWrapperConsumerExampleFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusWrapperConsumerExample{address: address, abi: *parsed, VRFV2PlusWrapperConsumerExampleCaller: VRFV2PlusWrapperConsumerExampleCaller{contract: contract}, VRFV2PlusWrapperConsumerExampleTransactor: VRFV2PlusWrapperConsumerExampleTransactor{contract: contract}, VRFV2PlusWrapperConsumerExampleFilterer: VRFV2PlusWrapperConsumerExampleFilterer{contract: contract}}, nil } type VRFV2PlusWrapperConsumerExample struct { diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go b/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go index 231945c9b7..8da1419620 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go @@ -52,7 +52,7 @@ func DeployVRFV2PlusWrapperLoadTestConsumer(auth *bind.TransactOpts, backend bin if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VRFV2PlusWrapperLoadTestConsumer{VRFV2PlusWrapperLoadTestConsumerCaller: VRFV2PlusWrapperLoadTestConsumerCaller{contract: contract}, VRFV2PlusWrapperLoadTestConsumerTransactor: VRFV2PlusWrapperLoadTestConsumerTransactor{contract: contract}, VRFV2PlusWrapperLoadTestConsumerFilterer: VRFV2PlusWrapperLoadTestConsumerFilterer{contract: contract}}, nil + return address, tx, &VRFV2PlusWrapperLoadTestConsumer{address: address, abi: *parsed, VRFV2PlusWrapperLoadTestConsumerCaller: VRFV2PlusWrapperLoadTestConsumerCaller{contract: contract}, VRFV2PlusWrapperLoadTestConsumerTransactor: VRFV2PlusWrapperLoadTestConsumerTransactor{contract: contract}, VRFV2PlusWrapperLoadTestConsumerFilterer: VRFV2PlusWrapperLoadTestConsumerFilterer{contract: contract}}, nil } type VRFV2PlusWrapperLoadTestConsumer struct { diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index ce553dc818..67090d16c6 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -2,7 +2,7 @@ // golang packages, using abigen. package gethwrappers -// Make sure solidity compiler artifacts are up to date. Only output stdout on failure. +// Make sure solidity compiler artifacts are up-to-date. Only output stdout on failure. //go:generate ./generation/compile_contracts.sh //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator.bin FluxAggregator flux_aggregator_wrapper diff --git a/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go b/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go index 846ebb197b..ad0ff29478 100644 --- a/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go +++ b/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go @@ -55,7 +55,7 @@ func DeployErroredVerifier(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &ErroredVerifier{ErroredVerifierCaller: ErroredVerifierCaller{contract: contract}, ErroredVerifierTransactor: ErroredVerifierTransactor{contract: contract}, ErroredVerifierFilterer: ErroredVerifierFilterer{contract: contract}}, nil + return address, tx, &ErroredVerifier{address: address, abi: *parsed, ErroredVerifierCaller: ErroredVerifierCaller{contract: contract}, ErroredVerifierTransactor: ErroredVerifierTransactor{contract: contract}, ErroredVerifierFilterer: ErroredVerifierFilterer{contract: contract}}, nil } type ErroredVerifier struct { diff --git a/core/gethwrappers/llo-feeds/generated/exposed_verifier/exposed_verifier.go b/core/gethwrappers/llo-feeds/generated/exposed_verifier/exposed_verifier.go index 2ca74b7cf3..e27cb58d15 100644 --- a/core/gethwrappers/llo-feeds/generated/exposed_verifier/exposed_verifier.go +++ b/core/gethwrappers/llo-feeds/generated/exposed_verifier/exposed_verifier.go @@ -50,7 +50,7 @@ func DeployExposedVerifier(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &ExposedVerifier{ExposedVerifierCaller: ExposedVerifierCaller{contract: contract}, ExposedVerifierTransactor: ExposedVerifierTransactor{contract: contract}, ExposedVerifierFilterer: ExposedVerifierFilterer{contract: contract}}, nil + return address, tx, &ExposedVerifier{address: address, abi: *parsed, ExposedVerifierCaller: ExposedVerifierCaller{contract: contract}, ExposedVerifierTransactor: ExposedVerifierTransactor{contract: contract}, ExposedVerifierFilterer: ExposedVerifierFilterer{contract: contract}}, nil } type ExposedVerifier struct { diff --git a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go index 666edd3385..742ec91bf9 100644 --- a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go +++ b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go @@ -67,7 +67,7 @@ func DeployFeeManager(auth *bind.TransactOpts, backend bind.ContractBackend, _li if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &FeeManager{FeeManagerCaller: FeeManagerCaller{contract: contract}, FeeManagerTransactor: FeeManagerTransactor{contract: contract}, FeeManagerFilterer: FeeManagerFilterer{contract: contract}}, nil + return address, tx, &FeeManager{address: address, abi: *parsed, FeeManagerCaller: FeeManagerCaller{contract: contract}, FeeManagerTransactor: FeeManagerTransactor{contract: contract}, FeeManagerFilterer: FeeManagerFilterer{contract: contract}}, nil } type FeeManager struct { diff --git a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go index 224fb37ef6..c870a40301 100644 --- a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go +++ b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go @@ -62,7 +62,7 @@ func DeployRewardManager(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &RewardManager{RewardManagerCaller: RewardManagerCaller{contract: contract}, RewardManagerTransactor: RewardManagerTransactor{contract: contract}, RewardManagerFilterer: RewardManagerFilterer{contract: contract}}, nil + return address, tx, &RewardManager{address: address, abi: *parsed, RewardManagerCaller: RewardManagerCaller{contract: contract}, RewardManagerTransactor: RewardManagerTransactor{contract: contract}, RewardManagerFilterer: RewardManagerFilterer{contract: contract}}, nil } type RewardManager struct { diff --git a/core/gethwrappers/llo-feeds/generated/verifier/verifier.go b/core/gethwrappers/llo-feeds/generated/verifier/verifier.go index 993de18eb5..09bf78b23b 100644 --- a/core/gethwrappers/llo-feeds/generated/verifier/verifier.go +++ b/core/gethwrappers/llo-feeds/generated/verifier/verifier.go @@ -57,7 +57,7 @@ func DeployVerifier(auth *bind.TransactOpts, backend bind.ContractBackend, verif if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Verifier{VerifierCaller: VerifierCaller{contract: contract}, VerifierTransactor: VerifierTransactor{contract: contract}, VerifierFilterer: VerifierFilterer{contract: contract}}, nil + return address, tx, &Verifier{address: address, abi: *parsed, VerifierCaller: VerifierCaller{contract: contract}, VerifierTransactor: VerifierTransactor{contract: contract}, VerifierFilterer: VerifierFilterer{contract: contract}}, nil } type Verifier struct { diff --git a/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go b/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go index 5ed70fef20..fc7f10b641 100644 --- a/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go +++ b/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go @@ -57,7 +57,7 @@ func DeployVerifierProxy(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &VerifierProxy{VerifierProxyCaller: VerifierProxyCaller{contract: contract}, VerifierProxyTransactor: VerifierProxyTransactor{contract: contract}, VerifierProxyFilterer: VerifierProxyFilterer{contract: contract}}, nil + return address, tx, &VerifierProxy{address: address, abi: *parsed, VerifierProxyCaller: VerifierProxyCaller{contract: contract}, VerifierProxyTransactor: VerifierProxyTransactor{contract: contract}, VerifierProxyFilterer: VerifierProxyFilterer{contract: contract}}, nil } type VerifierProxy struct { diff --git a/core/gethwrappers/shared/generated/burn_mint_erc677/burn_mint_erc677.go b/core/gethwrappers/shared/generated/burn_mint_erc677/burn_mint_erc677.go index f138b3b1f0..1d5b1c4ab1 100644 --- a/core/gethwrappers/shared/generated/burn_mint_erc677/burn_mint_erc677.go +++ b/core/gethwrappers/shared/generated/burn_mint_erc677/burn_mint_erc677.go @@ -52,7 +52,7 @@ func DeployBurnMintERC677(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BurnMintERC677{BurnMintERC677Caller: BurnMintERC677Caller{contract: contract}, BurnMintERC677Transactor: BurnMintERC677Transactor{contract: contract}, BurnMintERC677Filterer: BurnMintERC677Filterer{contract: contract}}, nil + return address, tx, &BurnMintERC677{address: address, abi: *parsed, BurnMintERC677Caller: BurnMintERC677Caller{contract: contract}, BurnMintERC677Transactor: BurnMintERC677Transactor{contract: contract}, BurnMintERC677Filterer: BurnMintERC677Filterer{contract: contract}}, nil } type BurnMintERC677 struct { diff --git a/core/gethwrappers/shared/generated/erc20/erc20.go b/core/gethwrappers/shared/generated/erc20/erc20.go index f5b1d9b7bf..9fd43134b6 100644 --- a/core/gethwrappers/shared/generated/erc20/erc20.go +++ b/core/gethwrappers/shared/generated/erc20/erc20.go @@ -52,7 +52,7 @@ func DeployERC20(auth *bind.TransactOpts, backend bind.ContractBackend, name_ st if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &ERC20{ERC20Caller: ERC20Caller{contract: contract}, ERC20Transactor: ERC20Transactor{contract: contract}, ERC20Filterer: ERC20Filterer{contract: contract}}, nil + return address, tx, &ERC20{address: address, abi: *parsed, ERC20Caller: ERC20Caller{contract: contract}, ERC20Transactor: ERC20Transactor{contract: contract}, ERC20Filterer: ERC20Filterer{contract: contract}}, nil } type ERC20 struct { diff --git a/core/gethwrappers/shared/generated/link_token/link_token.go b/core/gethwrappers/shared/generated/link_token/link_token.go index 98de7de66a..1467680626 100644 --- a/core/gethwrappers/shared/generated/link_token/link_token.go +++ b/core/gethwrappers/shared/generated/link_token/link_token.go @@ -52,7 +52,7 @@ func DeployLinkToken(auth *bind.TransactOpts, backend bind.ContractBackend) (com if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &LinkToken{LinkTokenCaller: LinkTokenCaller{contract: contract}, LinkTokenTransactor: LinkTokenTransactor{contract: contract}, LinkTokenFilterer: LinkTokenFilterer{contract: contract}}, nil + return address, tx, &LinkToken{address: address, abi: *parsed, LinkTokenCaller: LinkTokenCaller{contract: contract}, LinkTokenTransactor: LinkTokenTransactor{contract: contract}, LinkTokenFilterer: LinkTokenFilterer{contract: contract}}, nil } type LinkToken struct { diff --git a/core/gethwrappers/shared/generated/werc20_mock/werc20_mock.go b/core/gethwrappers/shared/generated/werc20_mock/werc20_mock.go index 3d8660c701..c8ff372275 100644 --- a/core/gethwrappers/shared/generated/werc20_mock/werc20_mock.go +++ b/core/gethwrappers/shared/generated/werc20_mock/werc20_mock.go @@ -52,7 +52,7 @@ func DeployWERC20Mock(auth *bind.TransactOpts, backend bind.ContractBackend) (co if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &WERC20Mock{WERC20MockCaller: WERC20MockCaller{contract: contract}, WERC20MockTransactor: WERC20MockTransactor{contract: contract}, WERC20MockFilterer: WERC20MockFilterer{contract: contract}}, nil + return address, tx, &WERC20Mock{address: address, abi: *parsed, WERC20MockCaller: WERC20MockCaller{contract: contract}, WERC20MockTransactor: WERC20MockTransactor{contract: contract}, WERC20MockFilterer: WERC20MockFilterer{contract: contract}}, nil } type WERC20Mock struct { diff --git a/core/gethwrappers/transmission/generated/entry_point/entry_point.go b/core/gethwrappers/transmission/generated/entry_point/entry_point.go index 9177186f4d..09a3a94a7f 100644 --- a/core/gethwrappers/transmission/generated/entry_point/entry_point.go +++ b/core/gethwrappers/transmission/generated/entry_point/entry_point.go @@ -99,7 +99,7 @@ func DeployEntryPoint(auth *bind.TransactOpts, backend bind.ContractBackend) (co if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &EntryPoint{EntryPointCaller: EntryPointCaller{contract: contract}, EntryPointTransactor: EntryPointTransactor{contract: contract}, EntryPointFilterer: EntryPointFilterer{contract: contract}}, nil + return address, tx, &EntryPoint{address: address, abi: *parsed, EntryPointCaller: EntryPointCaller{contract: contract}, EntryPointTransactor: EntryPointTransactor{contract: contract}, EntryPointFilterer: EntryPointFilterer{contract: contract}}, nil } type EntryPoint struct { diff --git a/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go b/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go index 857472422f..9814c6a12c 100644 --- a/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go +++ b/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go @@ -50,7 +50,7 @@ func DeployGreeter(auth *bind.TransactOpts, backend bind.ContractBackend) (commo if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Greeter{GreeterCaller: GreeterCaller{contract: contract}, GreeterTransactor: GreeterTransactor{contract: contract}, GreeterFilterer: GreeterFilterer{contract: contract}}, nil + return address, tx, &Greeter{address: address, abi: *parsed, GreeterCaller: GreeterCaller{contract: contract}, GreeterTransactor: GreeterTransactor{contract: contract}, GreeterFilterer: GreeterFilterer{contract: contract}}, nil } type Greeter struct { diff --git a/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go b/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go index 84283b28bb..4910d2b4bb 100644 --- a/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go +++ b/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go @@ -66,7 +66,7 @@ func DeployPaymaster(auth *bind.TransactOpts, backend bind.ContractBackend, link if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Paymaster{PaymasterCaller: PaymasterCaller{contract: contract}, PaymasterTransactor: PaymasterTransactor{contract: contract}, PaymasterFilterer: PaymasterFilterer{contract: contract}}, nil + return address, tx, &Paymaster{address: address, abi: *parsed, PaymasterCaller: PaymasterCaller{contract: contract}, PaymasterTransactor: PaymasterTransactor{contract: contract}, PaymasterFilterer: PaymasterFilterer{contract: contract}}, nil } type Paymaster struct { diff --git a/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go b/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go index 36838fc1b0..55a3107710 100644 --- a/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go +++ b/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go @@ -64,7 +64,7 @@ func DeploySCA(auth *bind.TransactOpts, backend bind.ContractBackend, owner comm if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &SCA{SCACaller: SCACaller{contract: contract}, SCATransactor: SCATransactor{contract: contract}, SCAFilterer: SCAFilterer{contract: contract}}, nil + return address, tx, &SCA{address: address, abi: *parsed, SCACaller: SCACaller{contract: contract}, SCATransactor: SCATransactor{contract: contract}, SCAFilterer: SCAFilterer{contract: contract}}, nil } type SCA struct { diff --git a/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go b/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go index 1e7761bffe..0b4daf3fa8 100644 --- a/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go +++ b/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go @@ -52,7 +52,7 @@ func DeploySmartContractAccountFactory(auth *bind.TransactOpts, backend bind.Con if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &SmartContractAccountFactory{SmartContractAccountFactoryCaller: SmartContractAccountFactoryCaller{contract: contract}, SmartContractAccountFactoryTransactor: SmartContractAccountFactoryTransactor{contract: contract}, SmartContractAccountFactoryFilterer: SmartContractAccountFactoryFilterer{contract: contract}}, nil + return address, tx, &SmartContractAccountFactory{address: address, abi: *parsed, SmartContractAccountFactoryCaller: SmartContractAccountFactoryCaller{contract: contract}, SmartContractAccountFactoryTransactor: SmartContractAccountFactoryTransactor{contract: contract}, SmartContractAccountFactoryFilterer: SmartContractAccountFactoryFilterer{contract: contract}}, nil } type SmartContractAccountFactory struct { diff --git a/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go b/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go index add1d2ce51..d951227c3a 100644 --- a/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go +++ b/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go @@ -50,7 +50,7 @@ func DeploySmartContractAccountHelper(auth *bind.TransactOpts, backend bind.Cont if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &SmartContractAccountHelper{SmartContractAccountHelperCaller: SmartContractAccountHelperCaller{contract: contract}, SmartContractAccountHelperTransactor: SmartContractAccountHelperTransactor{contract: contract}, SmartContractAccountHelperFilterer: SmartContractAccountHelperFilterer{contract: contract}}, nil + return address, tx, &SmartContractAccountHelper{address: address, abi: *parsed, SmartContractAccountHelperCaller: SmartContractAccountHelperCaller{contract: contract}, SmartContractAccountHelperTransactor: SmartContractAccountHelperTransactor{contract: contract}, SmartContractAccountHelperFilterer: SmartContractAccountHelperFilterer{contract: contract}}, nil } type SmartContractAccountHelper struct { From 78c658e04539db27c0c6322fa1e80744f1f7cfb0 Mon Sep 17 00:00:00 2001 From: Kashif Date: Thu, 26 Oct 2023 23:21:53 +0900 Subject: [PATCH 015/327] [FTM] Enable suggested gas fee on Fantom (#10963) * Enable suggested gas fee on Fantom * update docs * Add contract deployer * Add config change reasoning --------- Co-authored-by: davidcauchi --- .github/workflows/on-demand-ocr-soak-test.yml | 2 ++ core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml | 5 +++-- core/chains/evm/config/toml/defaults/Fantom_Testnet.toml | 3 +-- docs/CONFIG.md | 8 ++++---- integration-tests/contracts/contract_deployer.go | 6 ++++++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 7dc144264d..15f259e7e8 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -24,6 +24,8 @@ on: - "POLYGON_MAINNET" - "LINEA_GOERLI" - "LINEA_MAINNET" + - "FANTOM_TESTNET" + - "FANTOM_MAINNET" fundingPrivateKey: description: Private funding key (Skip for Simulated) required: false diff --git a/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml b/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml index f7678c37eb..7046642bb9 100644 --- a/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml @@ -9,8 +9,9 @@ RPCBlockQueryDelay = 2 Enabled = true [GasEstimator] -PriceDefault = '15 gwei' -PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +# Fantom network has been slow to include txs at times when using the BlockHistory estimator, and the recommendation is to use L2Suggested mode. +# There is work under way to improve L2Suggested mode's name so that its use on non-L2 chains will be less confusing in the future. +Mode = 'L2Suggested' [OCR2.Automation] GasLimit = 3800000 \ No newline at end of file diff --git a/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml b/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml index c7a6f72f9a..0292ed5b74 100644 --- a/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml +++ b/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml @@ -7,8 +7,7 @@ NoNewHeadsThreshold = '0' RPCBlockQueryDelay = 2 [GasEstimator] -PriceDefault = '15 gwei' -PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +Mode = 'L2Suggested' [OCR2.Automation] GasLimit = 3800000 \ No newline at end of file diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 9582a940c3..1fc7d9b632 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -2724,8 +2724,8 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'BlockHistory' -PriceDefault = '15 gwei' +Mode = 'L2Suggested' +PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '1 gwei' LimitDefault = 500000 @@ -3197,8 +3197,8 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'BlockHistory' -PriceDefault = '15 gwei' +Mode = 'L2Suggested' +PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '1 gwei' LimitDefault = 500000 diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index bdf63d1919..710422891c 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -169,6 +169,8 @@ func NewContractDeployer(bcClient blockchain.EVMClient, logger zerolog.Logger) ( return &PolygonZkEvmContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.LineaClient: return &LineaContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil + case *blockchain.FantomClient: + return &FantomContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract deployer, register blockchain client in NewContractDeployer") } @@ -232,6 +234,10 @@ type LineaContractDeployer struct { *EthereumContractDeployer } +type FantomContractDeployer struct { + *EthereumContractDeployer +} + // NewEthereumContractDeployer returns an instantiated instance of the ETH contract deployer func NewEthereumContractDeployer(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractDeployer { return &EthereumContractDeployer{ From 7fef66dc1fb82a865120601f38a1bd8f3c507b01 Mon Sep 17 00:00:00 2001 From: Lei Date: Thu, 26 Oct 2023 13:27:35 -0700 Subject: [PATCH 016/327] tune debugging script (#11070) --- core/scripts/chaincli/handler/debug.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index bdbce79926..7cf801d332 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -70,7 +70,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { // verify contract is correct typeAndVersion, err := keeperRegistry21.TypeAndVersion(latestCallOpts) if err != nil { - failCheckConfig("failed to get typeAndVersion: are you sure you have the correct contract address?", err) + failCheckConfig("failed to get typeAndVersion: make sure your registry contract address and archive node are valid", err) } if typeAndVersion != expectedTypeAndVersion { failCheckConfig(fmt.Sprintf("invalid registry contract: this command can only debug %s, got: %s", expectedTypeAndVersion, typeAndVersion), nil) @@ -148,10 +148,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failCheckArgs("unable to parse log index", err) } - // find transaciton receipt + // find transaction receipt _, isPending, err := k.client.TransactionByHash(ctx, txHash) if err != nil { - log.Fatal("failed to fetch tx receipt", err) + log.Fatal("failed to get tx by hash", err) } if isPending { resolveIneligible(fmt.Sprintf("tx %s is still pending confirmation", txHash)) @@ -256,6 +256,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { message("using mercury lookup v0.3") } streamsLookup := &StreamsLookup{streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time, streamsLookupErr.ExtraData, upkeepID, blockNum} + + if k.cfg.MercuryLegacyURL == "" || k.cfg.MercuryURL == "" || k.cfg.MercuryID == "" || k.cfg.MercuryKey == "" { + failCheckConfig("Mercury configs not set properly, check your MERCURY_LEGACY_URL, MERCURY_URL, MERCURY_ID and MERCURY_KEY", nil) + } handler := NewMercuryLookupHandler(&MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey}, k.rpcClient) state, failureReason, values, _, err := handler.doMercuryRequest(ctx, streamsLookup) if failureReason == UpkeepFailureReasonInvalidRevertDataInput { From e062e38b82aa1b3f150d463b96aedd44bab9f74c Mon Sep 17 00:00:00 2001 From: Tate Date: Thu, 26 Oct 2023 15:29:38 -0600 Subject: [PATCH 017/327] [TT-647] Bump Metrics For More Go Package + Test Name Preprocessing (#11095) --- .github/actions/golangci-lint/action.yml | 2 +- .../workflows/automation-benchmark-tests.yml | 2 +- .../workflows/automation-ondemand-tests.yml | 6 ++--- .github/workflows/build-publish-develop.yml | 2 +- .github/workflows/build-publish.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/changelog.yml | 2 +- .github/workflows/ci-core.yml | 6 ++--- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/delete-deployments.yml | 2 +- .github/workflows/dependency-check.yml | 2 +- .../goreleaser-build-publish-develop.yml | 2 +- .github/workflows/integration-chaos-tests.yml | 6 ++--- .../workflows/integration-tests-publish.yml | 2 +- .github/workflows/integration-tests.yml | 26 +++++++++---------- .github/workflows/lint-gh-workflows.yml | 2 +- .github/workflows/on-demand-ocr-soak-test.yml | 2 +- .../on-demand-vrfv2plus-performance-test.yml | 2 +- .github/workflows/operator-ui-cd.yml | 2 +- .github/workflows/performance-tests.yml | 4 +-- .github/workflows/readme.yml | 2 +- .github/workflows/sigscanner.yml | 2 +- .github/workflows/solidity-foundry.yml | 2 +- .github/workflows/solidity-hardhat.yml | 8 +++--- .github/workflows/solidity.yml | 8 +++--- ...evelop-from-smartcontractkit-chainlink.yml | 2 +- 26 files changed, 51 insertions(+), 51 deletions(-) diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index c0aeb529c1..c9ea735d1f 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -69,7 +69,7 @@ runs: path: ${{ inputs.go-directory }}/golangci-lint-report.xml - name: Collect Metrics if: always() - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ inputs.gc-basic-auth }} hostname: ${{ inputs.gc-host }} diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index 45491af026..f23102f1ee 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -128,7 +128,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 20415b599e..ac0e34e083 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -46,7 +46,7 @@ jobs: - name: Collect Metrics if: inputs.chainlinkImage == '' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -91,7 +91,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -205,7 +205,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index 54ccaad581..076fdf817d 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -56,7 +56,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 5db70576b3..4d5a42a369 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -50,7 +50,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7cdf5e46b9..0f9a8ea8b3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index a8e6e266a9..c7ca0b880c 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -31,7 +31,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 4037dc0cd9..4053585590 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -117,7 +117,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -215,7 +215,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -253,7 +253,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 822bf259f9..8bc066f408 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -45,7 +45,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/delete-deployments.yml b/.github/workflows/delete-deployments.yml index 3ec5fb35c9..dc3c17852b 100644 --- a/.github/workflows/delete-deployments.yml +++ b/.github/workflows/delete-deployments.yml @@ -24,7 +24,7 @@ jobs: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index 42729a8cf1..dbf0889575 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -47,7 +47,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/goreleaser-build-publish-develop.yml b/.github/workflows/goreleaser-build-publish-develop.yml index 1edfdedd70..514067fd85 100644 --- a/.github/workflows/goreleaser-build-publish-develop.yml +++ b/.github/workflows/goreleaser-build-publish-develop.yml @@ -39,7 +39,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 503e5ec58a..648d5f9daa 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -53,7 +53,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -79,7 +79,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -99,7 +99,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index 06f7bb1b81..60f67f0357 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index edd7755e8b..98e59ce8d4 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -45,7 +45,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -74,7 +74,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -122,7 +122,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -228,7 +228,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -440,7 +440,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -468,7 +468,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -496,7 +496,7 @@ jobs: - name: Collect Metrics if: ${{ github.event_name == 'pull_request' }} id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -591,7 +591,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -697,7 +697,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -738,7 +738,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -796,7 +796,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -874,7 +874,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -946,7 +946,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/lint-gh-workflows.yml b/.github/workflows/lint-gh-workflows.yml index 8facdc038c..f1a3cc2080 100644 --- a/.github/workflows/lint-gh-workflows.yml +++ b/.github/workflows/lint-gh-workflows.yml @@ -13,7 +13,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 15f259e7e8..1fb79d8ccd 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -89,7 +89,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 41b6618ba6..deb977e43f 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -86,7 +86,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/operator-ui-cd.yml b/.github/workflows/operator-ui-cd.yml index 36a9d8b715..54f423e6dc 100644 --- a/.github/workflows/operator-ui-cd.yml +++ b/.github/workflows/operator-ui-cd.yml @@ -50,7 +50,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index 43ed80cb3f..277940dc2d 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -42,7 +42,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -79,7 +79,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml index e847216eb0..585bed41c6 100644 --- a/.github/workflows/readme.yml +++ b/.github/workflows/readme.yml @@ -31,7 +31,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/sigscanner.yml b/.github/workflows/sigscanner.yml index 285a63cacb..de34766d2c 100644 --- a/.github/workflows/sigscanner.yml +++ b/.github/workflows/sigscanner.yml @@ -26,7 +26,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index f6c515b5b8..19c879b09e 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -86,7 +86,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index 6e7de2eba1..129f37c0de 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -48,7 +48,7 @@ jobs: config: ./contracts/ci.json - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -90,7 +90,7 @@ jobs: path: ./contracts/coverage-${{ matrix.split.idx }}.json - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -145,7 +145,7 @@ jobs: run: pnpm test -- $SPLIT - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -170,7 +170,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index f46b13191d..782dc93a0f 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -40,7 +40,7 @@ jobs: run: pnpm prepublishOnly - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -84,7 +84,7 @@ jobs: run: gh pr comment -b 'Go solidity wrappers are out-of-date, regenerate them via the `make wrappers-all` command' - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -110,7 +110,7 @@ jobs: run: pnpm solhint - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -136,7 +136,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.changes == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml index 7fe9ffd526..d27acceca6 100644 --- a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml +++ b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml @@ -30,7 +30,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} From eabdba0c76de266554cc33db3cbdb2e123afac4b Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 26 Oct 2023 16:56:02 -0500 Subject: [PATCH 018/327] core/chains/cosmos/types: rm unused (#11099) --- core/chains/cosmos/types/types.go | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 core/chains/cosmos/types/types.go diff --git a/core/chains/cosmos/types/types.go b/core/chains/cosmos/types/types.go deleted file mode 100644 index 69b086a970..0000000000 --- a/core/chains/cosmos/types/types.go +++ /dev/null @@ -1,8 +0,0 @@ -package types - -// NewNode defines a new node to create. -type NewNode struct { - Name string `json:"name"` - CosmosChainID string `json:"cosmosChainId"` - TendermintURL string `json:"tendermintURL" db:"tendermint_url"` -} From 01200f8ef8d3fab71d130dd8cd80855bf27bc5bb Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Fri, 27 Oct 2023 13:01:05 +0300 Subject: [PATCH 019/327] =?UTF-8?q?VRF-678:create=20sub,=20fund=20it,=20de?= =?UTF-8?q?ploy=20consumer=20and=20add=20to=20sub=20when=20usin=E2=80=A6?= =?UTF-8?q?=20(#11086)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-678:create sub, fund it, deploy consumer and add to sub when using VRFV2 Plus WASP load test with existing env * VRF-678: cleanup * VRF-678: fixing smoke test; adding additional logging --- .../vrfv2plus/vrfv2plus_config/config.go | 1 + .../actions/vrfv2plus/vrfv2plus_steps.go | 96 ++++++++++++------- .../contracts/contract_vrf_models.go | 4 +- .../contracts/ethereum_vrfv2plus_contracts.go | 12 +-- integration-tests/load/vrfv2plus/config.go | 13 ++- integration-tests/load/vrfv2plus/config.toml | 18 ++-- .../load/vrfv2plus/vrfv2plus_test.go | 35 +++++-- integration-tests/smoke/vrfv2plus_test.go | 4 +- 8 files changed, 119 insertions(+), 64 deletions(-) diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go index caee353294..10d4f19c24 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -39,6 +39,7 @@ type VRFV2PlusConfig struct { UseExistingEnv bool `envconfig:"USE_EXISTING_ENV" default:"false"` // Whether to use an existing environment or create a new one CoordinatorAddress string `envconfig:"COORDINATOR_ADDRESS" default:""` // Coordinator address ConsumerAddress string `envconfig:"CONSUMER_ADDRESS" default:""` // Consumer address + LinkAddress string `envconfig:"LINK_ADDRESS" default:""` // Link address SubID string `envconfig:"SUB_ID" default:""` // Subscription ID KeyHash string `envconfig:"KEY_HASH" default:""` } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 3bfa5d4f41..46f0ca58e6 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -241,13 +241,16 @@ func SetupVRFV2_5Environment( mockNativeLINKFeed contracts.MockETHLINKFeed, numberOfConsumers int, numberOfSubToCreate int, + l zerolog.Logger, ) (*VRFV2_5Contracts, []*big.Int, *VRFV2PlusData, error) { - + l.Info().Msg("Starting VRFV2 Plus environment setup") + l.Info().Msg("Deploying VRFV2 Plus contracts") vrfv2_5Contracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, env.EVMClient, numberOfConsumers) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrDeployVRFV2_5Contracts) } + l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") err = vrfv2_5Contracts.Coordinator.SetConfig( vrfv2PlusConfig.MinimumConfirmations, vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, @@ -263,6 +266,7 @@ func SetupVRFV2_5Environment( return nil, nil, nil, errors.Wrap(err, ErrSetVRFCoordinatorConfig) } + l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Link and ETH/LINK feed") err = vrfv2_5Contracts.Coordinator.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrSetLinkNativeLinkFeed) @@ -271,32 +275,12 @@ func SetupVRFV2_5Environment( if err != nil { return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - - subIDs, err := CreateSubsAndFund(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts, numberOfSubToCreate) - if err != nil { - return nil, nil, nil, err - } - - subToConsumersMap := map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer{} - - //each subscription will have the same consumers - for _, subID := range subIDs { - subToConsumersMap[subID] = vrfv2_5Contracts.LoadTestConsumers - } - - err = AddConsumersToSubs( - subToConsumersMap, - vrfv2_5Contracts.Coordinator, - ) + l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Creating and funding subscriptions, adding consumers") + subIDs, err := CreateFundSubsAndAddConsumers(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, numberOfSubToCreate) if err != nil { return nil, nil, nil, err } - - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) - } - + l.Info().Str("Node URL", env.ClCluster.NodeAPIs()[0].URL()).Msg("Creating VRF Key on the Node") vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() if err != nil { return nil, nil, nil, errors.Wrap(err, ErrCreatingVRFv2PlusKey) @@ -307,6 +291,7 @@ func SetupVRFV2_5Environment( if err != nil { return nil, nil, nil, errors.Wrap(err, ErrNodePrimaryKey) } + l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Registering Proving Key") provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, nativeTokenPrimaryKeyAddress, vrfv2_5Contracts.Coordinator) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrRegisteringProvingKey) @@ -318,6 +303,7 @@ func SetupVRFV2_5Environment( chainID := env.EVMClient.GetChainID() + l.Info().Msg("Creating VRFV2 Plus Job") job, err := CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], vrfv2_5Contracts.Coordinator.Address(), @@ -340,6 +326,7 @@ func SetupVRFV2_5Environment( nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, node.WithVRFv2EVMEstimator(addr), ) + l.Info().Msg("Restarting Node with new sending key PriceMax configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrRestartCLNode) @@ -358,17 +345,52 @@ func SetupVRFV2_5Environment( chainID, } + l.Info().Msg("VRFV2 Plus environment setup is finished") return vrfv2_5Contracts, subIDs, &data, nil } +func CreateFundSubsAndAddConsumers( + env *test_env.CLClusterTestEnv, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + consumers []contracts.VRFv2PlusLoadTestConsumer, + numberOfSubToCreate int, +) ([]*big.Int, error) { + subIDs, err := CreateSubsAndFund(env, vrfv2PlusConfig, linkToken, coordinator, numberOfSubToCreate) + if err != nil { + return nil, err + } + subToConsumersMap := map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer{} + + //each subscription will have the same consumers + for _, subID := range subIDs { + subToConsumersMap[subID] = consumers + } + + err = AddConsumersToSubs( + subToConsumersMap, + coordinator, + ) + if err != nil { + return nil, err + } + + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, errors.Wrap(err, ErrWaitTXsComplete) + } + return subIDs, nil +} + func CreateSubsAndFund( env *test_env.CLClusterTestEnv, vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, - vrfv2_5Contracts *VRFV2_5Contracts, + coordinator contracts.VRFCoordinatorV2_5, subAmountToCreate int, ) ([]*big.Int, error) { - subs, err := CreateSubs(env, vrfv2_5Contracts.Coordinator, subAmountToCreate) + subs, err := CreateSubs(env, coordinator, subAmountToCreate) if err != nil { return nil, err } @@ -376,7 +398,7 @@ func CreateSubsAndFund( if err != nil { return nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts.Coordinator, subs) + err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, subs) if err != nil { return nil, err } @@ -503,21 +525,27 @@ func SetupVRFV2PlusWrapperEnvironment( return wrapperContracts, wrapperSubID, nil } func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { - err := coordinator.CreateSubscription() + tx, err := coordinator.CreateSubscription() if err != nil { return nil, errors.Wrap(err, ErrCreateVRFSubscription) } - - sub, err := coordinator.WaitForSubscriptionCreatedEvent(time.Second * 10) + err = env.EVMClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrFindSubID) + return nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = env.EVMClient.WaitForEvents() + receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + + //SubscriptionsCreated Log should be emitted with the subscription ID + subID := receipt.Logs[0].Topics[1].Big() + + //verify that the subscription was created + _, err = coordinator.FindSubscriptionID(subID) if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, errors.Wrap(err, ErrFindSubID) } - return sub.SubId, nil + + return subID, nil } func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 656cabb92e..f0f57f58e7 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -73,7 +73,7 @@ type VRFCoordinatorV2_5 interface { publicProvingKey [2]*big.Int, ) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) - CreateSubscription() error + CreateSubscription() (*types.Transaction, error) GetActiveSubscriptionIds(ctx context.Context, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) Migrate(subId *big.Int, coordinatorAddress string) error RegisterMigratableCoordinator(migratableCoordinatorAddress string) error @@ -83,7 +83,7 @@ type VRFCoordinatorV2_5 interface { GetSubscription(ctx context.Context, subID *big.Int) (vrf_coordinator_v2_5.GetSubscription, error) GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) - FindSubscriptionID() (*big.Int, error) + FindSubscriptionID(subID *big.Int) (*big.Int, error) WaitForSubscriptionCreatedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated, error) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index df7cca54b2..1488f97131 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -182,16 +182,16 @@ func (v *EthereumVRFCoordinatorV2_5) RegisterProvingKey( return v.client.ProcessTransaction(tx) } -func (v *EthereumVRFCoordinatorV2_5) CreateSubscription() error { +func (v *EthereumVRFCoordinatorV2_5) CreateSubscription() (*types.Transaction, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { - return err + return nil, err } tx, err := v.coordinator.CreateSubscription(opts) if err != nil { - return err + return nil, err } - return v.client.ProcessTransaction(tx) + return tx, v.client.ProcessTransaction(tx) } func (v *EthereumVRFCoordinatorV2_5) Migrate(subId *big.Int, coordinatorAddress string) error { @@ -250,11 +250,11 @@ func (v *EthereumVRFCoordinatorV2_5) FundSubscriptionWithNative(subId *big.Int, return v.client.ProcessTransaction(tx) } -func (v *EthereumVRFCoordinatorV2_5) FindSubscriptionID() (*big.Int, error) { +func (v *EthereumVRFCoordinatorV2_5) FindSubscriptionID(subID *big.Int) (*big.Int, error) { owner := v.client.GetDefaultWallet().Address() subscriptionIterator, err := v.coordinator.FilterSubscriptionCreated( nil, - nil, + []*big.Int{subID}, ) if err != nil { return nil, err diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index 329e4abf13..50003c8286 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -36,8 +36,11 @@ type PerformanceConfig struct { type ExistingEnvConfig struct { CoordinatorAddress string `toml:"coordinator_address"` ConsumerAddress string `toml:"consumer_address"` + LinkAddress string `toml:"link_address"` SubID string `toml:"sub_id"` KeyHash string `toml:"key_hash"` + SubFunding + CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` } type NewEnvConfig struct { @@ -49,9 +52,13 @@ type Common struct { } type Funding struct { - NodeFunds float64 `toml:"node_funds"` - SubFundsLink int64 `toml:"sub_funds_link"` - SubFundsNative int64 `toml:"sub_funds_native"` + NodeFunds float64 `toml:"node_funds"` + SubFunding +} + +type SubFunding struct { + SubFundsLink int64 `toml:"sub_funds_link"` + SubFundsNative int64 `toml:"sub_funds_native"` } type Soak struct { diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml index 31a0bf5665..05e22bd51e 100644 --- a/integration-tests/load/vrfv2plus/config.toml +++ b/integration-tests/load/vrfv2plus/config.toml @@ -3,17 +3,19 @@ minimum_confirmations = 3 [NewEnvConfig] -sub_funds_link = 1000 -sub_funds_native = 1000 +sub_funds_link = 1 +sub_funds_native = 1 node_funds = 10 - [ExistingEnvConfig] -coordinator_address = "0x4931Ce2e341398c8eD8A5D0F6ADb920476D6DaBb" +coordinator_address = "0x27b61f155F772b291D1d9B478BeAd37B2Ae447b0" consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" -key_hash = "0x4c422465ed6a06cfc84575a5437fef7b9dc6263133f648afbe6ae7b2c694d3b3" - +key_hash = "0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae" +create_fund_subs_and_add_consumers = true +link_address = "0x779877A7B0D9E8603169DdbD7836e478b4624789" +sub_funds_link = 3 +sub_funds_native = 1 # 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds [Soak] @@ -29,7 +31,7 @@ rate_limit_unit_duration = "3s" rps = 1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 10 +number_of_sub_to_create = 5 # approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx [Stress] @@ -37,7 +39,7 @@ rate_limit_unit_duration = "1s" rps = 3 randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 20 +number_of_sub_to_create = 5 # approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds [Spike] diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index a3cb4d4b7f..e619cf78fd 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -74,6 +74,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented vrfv2PlusConfig.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress vrfv2PlusConfig.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress + vrfv2PlusConfig.LinkAddress = cfg.ExistingEnvConfig.LinkAddress + vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink + vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.ExistingEnvConfig.SubFunding.SubFundsNative vrfv2PlusConfig.SubID = cfg.ExistingEnvConfig.SubID vrfv2PlusConfig.KeyHash = cfg.ExistingEnvConfig.KeyHash @@ -90,17 +93,29 @@ func TestVRFV2PlusPerformance(t *testing.T) { coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(vrfv2PlusConfig.CoordinatorAddress) require.NoError(t, err) - consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) - require.NoError(t, err) + var consumers []contracts.VRFv2PlusLoadTestConsumer + if cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { + linkToken, err := env.ContractLoader.LoadLINKToken(vrfv2PlusConfig.LinkAddress) + require.NoError(t, err) + consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) + require.NoError(t, err) + subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers(env, &vrfv2PlusConfig, linkToken, coordinator, consumers, vrfv2PlusConfig.NumberOfSubToCreate) + require.NoError(t, err) + } else { + consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) + require.NoError(t, err) + consumers = append(consumers, consumer) + var ok bool + subID, ok := new(big.Int).SetString(vrfv2PlusConfig.SubID, 10) + require.True(t, ok) + subIDs = append(subIDs, subID) + } vrfv2PlusContracts = &vrfv2plus.VRFV2_5Contracts{ Coordinator: coordinator, - LoadTestConsumers: []contracts.VRFv2PlusLoadTestConsumer{consumer}, + LoadTestConsumers: consumers, BHS: nil, } - var ok bool - subID, ok := new(big.Int).SetString(vrfv2PlusConfig.SubID, 10) - require.True(t, ok) vrfv2PlusData = &vrfv2plus.VRFV2PlusData{ VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{ @@ -112,7 +127,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { PrimaryEthAddress: "", ChainID: nil, } - subIDs = append(subIDs, subID) + } else { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented vrfv2PlusConfig.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeFunds @@ -150,6 +165,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { mockETHLinkFeed, 1, vrfv2PlusConfig.NumberOfSubToCreate, + l, ) require.NoError(t, err, "error setting up VRF v2_5 env") } @@ -198,7 +214,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { var wg sync.WaitGroup wg.Add(1) //todo - timeout should be configurable depending on the perf test type - requestCount, fulfilmentCount, err := vrfv2plus.WaitForRequestCountEqualToFulfilmentCount(consumer, 30*time.Second, &wg) + requestCount, fulfilmentCount, err := vrfv2plus.WaitForRequestCountEqualToFulfilmentCount(consumer, 2*time.Minute, &wg) require.NoError(t, err) wg.Wait() @@ -212,7 +228,8 @@ func TestVRFV2PlusPerformance(t *testing.T) { func teardown( t *testing.T, consumer contracts.VRFv2PlusLoadTestConsumer, - lc *wasp.LokiClient, updatedLabels map[string]string, + lc *wasp.LokiClient, + updatedLabels map[string]string, testReporter *testreporters.VRFV2PlusTestReporter, testType string, vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index c2cc0878b6..408e5a95ed 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -46,7 +46,7 @@ func TestVRFv2Plus(t *testing.T) { linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1, 1) + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1, 1, l) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] @@ -271,7 +271,7 @@ func TestVRFv2PlusMigration(t *testing.T) { linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, 2, 1) + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, 2, 1, l) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] From d8414631ddf1464eb4b06056cbfa21cbf991bcfa Mon Sep 17 00:00:00 2001 From: "app-token-issuer-infra-releng[bot]" <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:56:54 +0300 Subject: [PATCH 020/327] Update Operator UI from v0.8.0-06f745d to v0.8.0-e10948a (#11094) * Update Operator UI from v0.8.0-06f745d to v0.8.0-e10948a * Sig scanner check --------- Co-authored-by: github-merge-queue[bot] Co-authored-by: george-dorin --- operator_ui/TAG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator_ui/TAG b/operator_ui/TAG index 023fd8732c..e08ca07267 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1 +1 @@ -v0.8.0-06f745d +v0.8.0-e10948a From e6118da8b89033d857efa1aef6d7f4ba9bdd9d91 Mon Sep 17 00:00:00 2001 From: george-dorin <120329946+george-dorin@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:09:24 +0300 Subject: [PATCH 021/327] Add string equivalent for observation price, bid, ask (#11077) * Add string equivalent for observation price, bid, ask * Update logging --- core/services/ocrcommon/telemetry.go | 64 ++-- core/services/ocrcommon/telemetry_test.go | 57 ++-- .../telem/telem_enhanced_ea_mercury.pb.go | 280 ++++++++++-------- .../telem/telem_enhanced_ea_mercury.proto | 3 + 4 files changed, 227 insertions(+), 177 deletions(-) diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index 54a5002093..5277143c8b 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "math/big" "github.com/ethereum/go-ethereum/common" @@ -230,7 +231,7 @@ func (e *EnhancedTelemetryService[T]) collectAndSend(trrs *pipeline.TaskRunResul } eaTelem, err := parseEATelemetry([]byte(bridgeRawResponse)) if err != nil { - e.lggr.Warnf("cannot parse EA telemetry, job %d, id %s", e.job.ID, trr.Task.DotID()) + e.lggr.Warnw(fmt.Sprintf("cannot parse EA telemetry, job %d, id %s", e.job.ID, trr.Task.DotID()), "err", err) } value := e.getParsedValue(trrs, trr) @@ -278,39 +279,42 @@ func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(obs relaym bridgeRawResponse, ok := trr.Result.Value.(string) if !ok { - e.lggr.Warnf("cannot get bridge response from bridge task, job %d, id %s", e.job.ID, trr.Task.DotID()) + e.lggr.Warnf("cannot get bridge response from bridge task, job %d, id %s, expected string got %T", e.job.ID, trr.Task.DotID(), trr.Result.Value) continue } eaTelem, err := parseEATelemetry([]byte(bridgeRawResponse)) if err != nil { - e.lggr.Warnf("cannot parse EA telemetry, job %d, id %s", e.job.ID, trr.Task.DotID()) + e.lggr.Warnw(fmt.Sprintf("cannot parse EA telemetry, job %d, id %s", e.job.ID, trr.Task.DotID()), "err", err) } assetSymbol := e.getAssetSymbolFromRequestData(bridgeTask.RequestData) benchmarkPrice, bidPrice, askPrice := e.getPricesFromResults(trr, &trrs) t := &telem.EnhancedEAMercury{ - DataSource: eaTelem.DataSource, - DpBenchmarkPrice: benchmarkPrice, - DpBid: bidPrice, - DpAsk: askPrice, - CurrentBlockNumber: obsBlockNum, - CurrentBlockHash: common.BytesToHash(obsBlockHash).String(), - CurrentBlockTimestamp: obsBlockTimestamp, - BridgeTaskRunStartedTimestamp: trr.CreatedAt.UnixMilli(), - BridgeTaskRunEndedTimestamp: trr.FinishedAt.Time.UnixMilli(), - ProviderRequestedTimestamp: eaTelem.ProviderRequestedTimestamp, - ProviderReceivedTimestamp: eaTelem.ProviderReceivedTimestamp, - ProviderDataStreamEstablished: eaTelem.ProviderDataStreamEstablished, - ProviderIndicatedTime: eaTelem.ProviderIndicatedTime, - Feed: e.job.OCR2OracleSpec.FeedID.Hex(), - ObservationBenchmarkPrice: obsBenchmarkPrice, - ObservationBid: obsBid, - ObservationAsk: obsAsk, - ConfigDigest: repts.ConfigDigest.Hex(), - Round: int64(repts.Round), - Epoch: int64(repts.Epoch), - AssetSymbol: assetSymbol, + DataSource: eaTelem.DataSource, + DpBenchmarkPrice: benchmarkPrice, + DpBid: bidPrice, + DpAsk: askPrice, + CurrentBlockNumber: obsBlockNum, + CurrentBlockHash: common.BytesToHash(obsBlockHash).String(), + CurrentBlockTimestamp: obsBlockTimestamp, + BridgeTaskRunStartedTimestamp: trr.CreatedAt.UnixMilli(), + BridgeTaskRunEndedTimestamp: trr.FinishedAt.Time.UnixMilli(), + ProviderRequestedTimestamp: eaTelem.ProviderRequestedTimestamp, + ProviderReceivedTimestamp: eaTelem.ProviderReceivedTimestamp, + ProviderDataStreamEstablished: eaTelem.ProviderDataStreamEstablished, + ProviderIndicatedTime: eaTelem.ProviderIndicatedTime, + Feed: e.job.OCR2OracleSpec.FeedID.Hex(), + ObservationBenchmarkPrice: obsBenchmarkPrice.Int64(), //Deprecated: observation value will not fit in int64, we will use the string equivalent field ObservationBenchmarkPriceString + ObservationBid: obsBid.Int64(), //Deprecated: observation value will not fit in int64, we will use the string equivalent field ObservationBidString + ObservationAsk: obsAsk.Int64(), //Deprecated: observation value will not fit in int64, we will use the string equivalent field ObservationAskString + ConfigDigest: repts.ConfigDigest.Hex(), + Round: int64(repts.Round), + Epoch: int64(repts.Epoch), + AssetSymbol: assetSymbol, + ObservationBenchmarkPriceString: obsBenchmarkPrice.String(), + ObservationBidString: obsBid.String(), + ObservationAskString: obsAsk.String(), } bytes, err := proto.Marshal(t) @@ -408,17 +412,19 @@ func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.Ta } // getFinalValues runs a parse on the pipeline.TaskRunResults and returns the values -func (e *EnhancedTelemetryService[T]) getFinalValues(obs relaymercuryv1.Observation) (int64, int64, int64, int64, []byte, uint64) { - var benchmarkPrice, bid, ask int64 +func (e *EnhancedTelemetryService[T]) getFinalValues(obs relaymercuryv1.Observation) (*big.Int, *big.Int, *big.Int, int64, []byte, uint64) { + benchmarkPrice := big.NewInt(0) + bid := big.NewInt(0) + ask := big.NewInt(0) if obs.BenchmarkPrice.Val != nil { - benchmarkPrice = obs.BenchmarkPrice.Val.Int64() + benchmarkPrice = obs.BenchmarkPrice.Val } if obs.Bid.Val != nil { - bid = obs.Bid.Val.Int64() + bid = obs.Bid.Val } if obs.Ask.Val != nil { - ask = obs.Ask.Val.Int64() + ask = obs.Ask.Val } return benchmarkPrice, bid, ask, obs.CurrentBlockNum.Val, obs.CurrentBlockHash.Val, obs.CurrentBlockTimestamp.Val diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index 88fb7de3e3..5d1494a038 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -433,17 +433,17 @@ func TestGetFinalValues(t *testing.T) { } benchmarkPrice, bid, ask, blockNr, blockHash, blockTimestamp := e.getFinalValues(o) - require.Equal(t, benchmarkPrice, int64(111111)) - require.Equal(t, bid, int64(222222)) - require.Equal(t, ask, int64(333333)) + require.Equal(t, benchmarkPrice, big.NewInt(111111)) + require.Equal(t, bid, big.NewInt(222222)) + require.Equal(t, ask, big.NewInt(333333)) require.Equal(t, blockNr, int64(123456789)) require.Equal(t, blockHash, common.HexToHash("0x123321").Bytes()) require.Equal(t, blockTimestamp, uint64(987654321)) benchmarkPrice, bid, ask, blockNr, blockHash, blockTimestamp = e.getFinalValues(mercuryv1.Observation{}) - require.Equal(t, benchmarkPrice, int64(0)) - require.Equal(t, bid, int64(0)) - require.Equal(t, ask, int64(0)) + require.Equal(t, benchmarkPrice, big.NewInt(0)) + require.Equal(t, bid, big.NewInt(0)) + require.Equal(t, ask, big.NewInt(0)) require.Equal(t, blockNr, int64(0)) require.Nil(t, blockHash) require.Equal(t, blockTimestamp, uint64(0)) @@ -598,27 +598,30 @@ func TestCollectMercuryEnhancedTelemetry(t *testing.T) { } expectedTelemetry := telem.EnhancedEAMercury{ - DataSource: "data-source-name", - DpBenchmarkPrice: 123456.123456, - DpBid: 1234567.1234567, - DpAsk: 321123, - CurrentBlockNumber: 123456789, - CurrentBlockHash: common.HexToHash("0x123321").String(), - CurrentBlockTimestamp: 987654321, - BridgeTaskRunStartedTimestamp: trrsMercury[0].CreatedAt.UnixMilli(), - BridgeTaskRunEndedTimestamp: trrsMercury[0].FinishedAt.Time.UnixMilli(), - ProviderRequestedTimestamp: 92233720368547760, - ProviderReceivedTimestamp: -92233720368547760, - ProviderDataStreamEstablished: 1, - ProviderIndicatedTime: -123456789, - Feed: common.HexToHash("0x111").String(), - ObservationBenchmarkPrice: 111111, - ObservationBid: 222222, - ObservationAsk: 333333, - ConfigDigest: "0200000000000000000000000000000000000000000000000000000000000000", - Round: 22, - Epoch: 11, - AssetSymbol: "USD/LINK", + DataSource: "data-source-name", + DpBenchmarkPrice: 123456.123456, + DpBid: 1234567.1234567, + DpAsk: 321123, + CurrentBlockNumber: 123456789, + CurrentBlockHash: common.HexToHash("0x123321").String(), + CurrentBlockTimestamp: 987654321, + BridgeTaskRunStartedTimestamp: trrsMercury[0].CreatedAt.UnixMilli(), + BridgeTaskRunEndedTimestamp: trrsMercury[0].FinishedAt.Time.UnixMilli(), + ProviderRequestedTimestamp: 92233720368547760, + ProviderReceivedTimestamp: -92233720368547760, + ProviderDataStreamEstablished: 1, + ProviderIndicatedTime: -123456789, + Feed: common.HexToHash("0x111").String(), + ObservationBenchmarkPrice: 111111, + ObservationBid: 222222, + ObservationAsk: 333333, + ConfigDigest: "0200000000000000000000000000000000000000000000000000000000000000", + Round: 22, + Epoch: 11, + AssetSymbol: "USD/LINK", + ObservationBenchmarkPriceString: "111111", + ObservationBidString: "222222", + ObservationAskString: "333333", } expectedMessage, _ := proto.Marshal(&expectedTelemetry) diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go index 571a725b88..32c3061cc4 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go @@ -1,8 +1,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 -// protoc v3.21.12 -// source: telem_enhanced_ea_mercury.proto +// protoc-gen-go v1.31.0 +// protoc v4.24.3 +// source: core/services/synchronization/telem/telem_enhanced_ea_mercury.proto package telem @@ -25,33 +25,36 @@ type EnhancedEAMercury struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DataSource string `protobuf:"bytes,1,opt,name=data_source,json=dataSource,proto3" json:"data_source,omitempty"` - DpBenchmarkPrice float64 `protobuf:"fixed64,2,opt,name=dp_benchmark_price,json=dpBenchmarkPrice,proto3" json:"dp_benchmark_price,omitempty"` - DpBid float64 `protobuf:"fixed64,3,opt,name=dp_bid,json=dpBid,proto3" json:"dp_bid,omitempty"` - DpAsk float64 `protobuf:"fixed64,4,opt,name=dp_ask,json=dpAsk,proto3" json:"dp_ask,omitempty"` - CurrentBlockNumber int64 `protobuf:"varint,5,opt,name=current_block_number,json=currentBlockNumber,proto3" json:"current_block_number,omitempty"` - CurrentBlockHash string `protobuf:"bytes,6,opt,name=current_block_hash,json=currentBlockHash,proto3" json:"current_block_hash,omitempty"` - CurrentBlockTimestamp uint64 `protobuf:"varint,7,opt,name=current_block_timestamp,json=currentBlockTimestamp,proto3" json:"current_block_timestamp,omitempty"` - BridgeTaskRunStartedTimestamp int64 `protobuf:"varint,8,opt,name=bridge_task_run_started_timestamp,json=bridgeTaskRunStartedTimestamp,proto3" json:"bridge_task_run_started_timestamp,omitempty"` - BridgeTaskRunEndedTimestamp int64 `protobuf:"varint,9,opt,name=bridge_task_run_ended_timestamp,json=bridgeTaskRunEndedTimestamp,proto3" json:"bridge_task_run_ended_timestamp,omitempty"` - ProviderRequestedTimestamp int64 `protobuf:"varint,10,opt,name=provider_requested_timestamp,json=providerRequestedTimestamp,proto3" json:"provider_requested_timestamp,omitempty"` - ProviderReceivedTimestamp int64 `protobuf:"varint,11,opt,name=provider_received_timestamp,json=providerReceivedTimestamp,proto3" json:"provider_received_timestamp,omitempty"` - ProviderDataStreamEstablished int64 `protobuf:"varint,12,opt,name=provider_data_stream_established,json=providerDataStreamEstablished,proto3" json:"provider_data_stream_established,omitempty"` - ProviderIndicatedTime int64 `protobuf:"varint,13,opt,name=provider_indicated_time,json=providerIndicatedTime,proto3" json:"provider_indicated_time,omitempty"` - Feed string `protobuf:"bytes,14,opt,name=feed,proto3" json:"feed,omitempty"` - ObservationBenchmarkPrice int64 `protobuf:"varint,15,opt,name=observation_benchmark_price,json=observationBenchmarkPrice,proto3" json:"observation_benchmark_price,omitempty"` - ObservationBid int64 `protobuf:"varint,16,opt,name=observation_bid,json=observationBid,proto3" json:"observation_bid,omitempty"` - ObservationAsk int64 `protobuf:"varint,17,opt,name=observation_ask,json=observationAsk,proto3" json:"observation_ask,omitempty"` - ConfigDigest string `protobuf:"bytes,18,opt,name=config_digest,json=configDigest,proto3" json:"config_digest,omitempty"` - Round int64 `protobuf:"varint,19,opt,name=round,proto3" json:"round,omitempty"` - Epoch int64 `protobuf:"varint,20,opt,name=epoch,proto3" json:"epoch,omitempty"` - AssetSymbol string `protobuf:"bytes,21,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"` + DataSource string `protobuf:"bytes,1,opt,name=data_source,json=dataSource,proto3" json:"data_source,omitempty"` + DpBenchmarkPrice float64 `protobuf:"fixed64,2,opt,name=dp_benchmark_price,json=dpBenchmarkPrice,proto3" json:"dp_benchmark_price,omitempty"` + DpBid float64 `protobuf:"fixed64,3,opt,name=dp_bid,json=dpBid,proto3" json:"dp_bid,omitempty"` + DpAsk float64 `protobuf:"fixed64,4,opt,name=dp_ask,json=dpAsk,proto3" json:"dp_ask,omitempty"` + CurrentBlockNumber int64 `protobuf:"varint,5,opt,name=current_block_number,json=currentBlockNumber,proto3" json:"current_block_number,omitempty"` + CurrentBlockHash string `protobuf:"bytes,6,opt,name=current_block_hash,json=currentBlockHash,proto3" json:"current_block_hash,omitempty"` + CurrentBlockTimestamp uint64 `protobuf:"varint,7,opt,name=current_block_timestamp,json=currentBlockTimestamp,proto3" json:"current_block_timestamp,omitempty"` + BridgeTaskRunStartedTimestamp int64 `protobuf:"varint,8,opt,name=bridge_task_run_started_timestamp,json=bridgeTaskRunStartedTimestamp,proto3" json:"bridge_task_run_started_timestamp,omitempty"` + BridgeTaskRunEndedTimestamp int64 `protobuf:"varint,9,opt,name=bridge_task_run_ended_timestamp,json=bridgeTaskRunEndedTimestamp,proto3" json:"bridge_task_run_ended_timestamp,omitempty"` + ProviderRequestedTimestamp int64 `protobuf:"varint,10,opt,name=provider_requested_timestamp,json=providerRequestedTimestamp,proto3" json:"provider_requested_timestamp,omitempty"` + ProviderReceivedTimestamp int64 `protobuf:"varint,11,opt,name=provider_received_timestamp,json=providerReceivedTimestamp,proto3" json:"provider_received_timestamp,omitempty"` + ProviderDataStreamEstablished int64 `protobuf:"varint,12,opt,name=provider_data_stream_established,json=providerDataStreamEstablished,proto3" json:"provider_data_stream_established,omitempty"` + ProviderIndicatedTime int64 `protobuf:"varint,13,opt,name=provider_indicated_time,json=providerIndicatedTime,proto3" json:"provider_indicated_time,omitempty"` + Feed string `protobuf:"bytes,14,opt,name=feed,proto3" json:"feed,omitempty"` + ObservationBenchmarkPrice int64 `protobuf:"varint,15,opt,name=observation_benchmark_price,json=observationBenchmarkPrice,proto3" json:"observation_benchmark_price,omitempty"` + ObservationBid int64 `protobuf:"varint,16,opt,name=observation_bid,json=observationBid,proto3" json:"observation_bid,omitempty"` + ObservationAsk int64 `protobuf:"varint,17,opt,name=observation_ask,json=observationAsk,proto3" json:"observation_ask,omitempty"` + ConfigDigest string `protobuf:"bytes,18,opt,name=config_digest,json=configDigest,proto3" json:"config_digest,omitempty"` + Round int64 `protobuf:"varint,19,opt,name=round,proto3" json:"round,omitempty"` + Epoch int64 `protobuf:"varint,20,opt,name=epoch,proto3" json:"epoch,omitempty"` + AssetSymbol string `protobuf:"bytes,21,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"` + ObservationBenchmarkPriceString string `protobuf:"bytes,22,opt,name=observation_benchmark_price_string,json=observationBenchmarkPriceString,proto3" json:"observation_benchmark_price_string,omitempty"` + ObservationBidString string `protobuf:"bytes,23,opt,name=observation_bid_string,json=observationBidString,proto3" json:"observation_bid_string,omitempty"` + ObservationAskString string `protobuf:"bytes,24,opt,name=observation_ask_string,json=observationAskString,proto3" json:"observation_ask_string,omitempty"` } func (x *EnhancedEAMercury) Reset() { *x = EnhancedEAMercury{} if protoimpl.UnsafeEnabled { - mi := &file_telem_enhanced_ea_mercury_proto_msgTypes[0] + mi := &file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -64,7 +67,7 @@ func (x *EnhancedEAMercury) String() string { func (*EnhancedEAMercury) ProtoMessage() {} func (x *EnhancedEAMercury) ProtoReflect() protoreflect.Message { - mi := &file_telem_enhanced_ea_mercury_proto_msgTypes[0] + mi := &file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -77,7 +80,7 @@ func (x *EnhancedEAMercury) ProtoReflect() protoreflect.Message { // Deprecated: Use EnhancedEAMercury.ProtoReflect.Descriptor instead. func (*EnhancedEAMercury) Descriptor() ([]byte, []int) { - return file_telem_enhanced_ea_mercury_proto_rawDescGZIP(), []int{0} + return file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescGZIP(), []int{0} } func (x *EnhancedEAMercury) GetDataSource() string { @@ -227,98 +230,133 @@ func (x *EnhancedEAMercury) GetAssetSymbol() string { return "" } -var File_telem_enhanced_ea_mercury_proto protoreflect.FileDescriptor - -var file_telem_enhanced_ea_mercury_proto_rawDesc = []byte{ - 0x0a, 0x1f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x65, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x64, - 0x5f, 0x65, 0x61, 0x5f, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0xd5, 0x07, 0x0a, 0x11, 0x45, 0x6e, 0x68, - 0x61, 0x6e, 0x63, 0x65, 0x64, 0x45, 0x41, 0x4d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x79, 0x12, 0x1f, - 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x2c, 0x0a, 0x12, 0x64, 0x70, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, - 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x10, 0x64, 0x70, 0x42, - 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x15, 0x0a, - 0x06, 0x64, 0x70, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x64, - 0x70, 0x42, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x70, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x64, 0x70, 0x41, 0x73, 0x6b, 0x12, 0x30, 0x0a, 0x14, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2c, 0x0a, - 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x36, 0x0a, 0x17, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x48, 0x0a, 0x21, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x74, 0x61, - 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1d, - 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x44, 0x0a, - 0x1f, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, - 0x5f, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1b, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x54, 0x61, - 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x40, 0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1a, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3e, 0x0a, 0x1b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x47, 0x0a, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x65, 0x73, - 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x1d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x36, - 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x64, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x65, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x1b, 0x6f, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, - 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x19, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x6e, 0x63, - 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x42, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, 0x6b, 0x12, 0x23, 0x0a, 0x0d, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, - 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x21, 0x0a, - 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x15, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, - 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, - 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, - 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x72, - 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x68, - 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +func (x *EnhancedEAMercury) GetObservationBenchmarkPriceString() string { + if x != nil { + return x.ObservationBenchmarkPriceString + } + return "" +} + +func (x *EnhancedEAMercury) GetObservationBidString() string { + if x != nil { + return x.ObservationBidString + } + return "" +} + +func (x *EnhancedEAMercury) GetObservationAskString() string { + if x != nil { + return x.ObservationAskString + } + return "" +} + +var File_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto protoreflect.FileDescriptor + +var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDesc = []byte{ + 0x0a, 0x43, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, + 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x65, 0x6e, 0x68, 0x61, + 0x6e, 0x63, 0x65, 0x64, 0x5f, 0x65, 0x61, 0x5f, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0x8e, 0x09, 0x0a, + 0x11, 0x45, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x45, 0x41, 0x4d, 0x65, 0x72, 0x63, 0x75, + 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x70, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, + 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x10, 0x64, 0x70, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, + 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x70, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x05, 0x64, 0x70, 0x42, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x70, 0x5f, 0x61, + 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x64, 0x70, 0x41, 0x73, 0x6b, 0x12, + 0x30, 0x0a, 0x14, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x36, 0x0a, 0x17, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x15, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x48, 0x0a, 0x21, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x1d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, + 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x44, 0x0a, 0x1f, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, + 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1b, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x40, 0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1a, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3e, 0x0a, 0x1b, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x47, 0x0a, 0x20, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x5f, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x1d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x44, 0x61, 0x74, + 0x61, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x65, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, + 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x65, + 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x65, 0x65, 0x64, 0x12, 0x3e, + 0x0a, 0x1b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x65, + 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0f, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x19, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x27, + 0x0a, 0x0f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, + 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x62, 0x73, 0x65, 0x72, + 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, 0x6b, + 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x13, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x70, 0x6f, 0x63, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, + 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, + 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x79, + 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x4b, 0x0a, 0x22, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x1f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x6e, + 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x12, 0x34, 0x0a, 0x16, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x17, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x14, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, + 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x16, 0x6f, 0x62, 0x73, 0x65, 0x72, + 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x6b, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x4e, 0x5a, + 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, + 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_telem_enhanced_ea_mercury_proto_rawDescOnce sync.Once - file_telem_enhanced_ea_mercury_proto_rawDescData = file_telem_enhanced_ea_mercury_proto_rawDesc + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescOnce sync.Once + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescData = file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDesc ) -func file_telem_enhanced_ea_mercury_proto_rawDescGZIP() []byte { - file_telem_enhanced_ea_mercury_proto_rawDescOnce.Do(func() { - file_telem_enhanced_ea_mercury_proto_rawDescData = protoimpl.X.CompressGZIP(file_telem_enhanced_ea_mercury_proto_rawDescData) +func file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescGZIP() []byte { + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescOnce.Do(func() { + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescData) }) - return file_telem_enhanced_ea_mercury_proto_rawDescData + return file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescData } -var file_telem_enhanced_ea_mercury_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_telem_enhanced_ea_mercury_proto_goTypes = []interface{}{ +var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_goTypes = []interface{}{ (*EnhancedEAMercury)(nil), // 0: telem.EnhancedEAMercury } -var file_telem_enhanced_ea_mercury_proto_depIdxs = []int32{ +var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name @@ -326,13 +364,13 @@ var file_telem_enhanced_ea_mercury_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for field type_name } -func init() { file_telem_enhanced_ea_mercury_proto_init() } -func file_telem_enhanced_ea_mercury_proto_init() { - if File_telem_enhanced_ea_mercury_proto != nil { +func init() { file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_init() } +func file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_init() { + if File_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_telem_enhanced_ea_mercury_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EnhancedEAMercury); i { case 0: return &v.state @@ -349,18 +387,18 @@ func file_telem_enhanced_ea_mercury_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_telem_enhanced_ea_mercury_proto_rawDesc, + RawDescriptor: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, - GoTypes: file_telem_enhanced_ea_mercury_proto_goTypes, - DependencyIndexes: file_telem_enhanced_ea_mercury_proto_depIdxs, - MessageInfos: file_telem_enhanced_ea_mercury_proto_msgTypes, + GoTypes: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_goTypes, + DependencyIndexes: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_depIdxs, + MessageInfos: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes, }.Build() - File_telem_enhanced_ea_mercury_proto = out.File - file_telem_enhanced_ea_mercury_proto_rawDesc = nil - file_telem_enhanced_ea_mercury_proto_goTypes = nil - file_telem_enhanced_ea_mercury_proto_depIdxs = nil + File_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto = out.File + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDesc = nil + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_goTypes = nil + file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_depIdxs = nil } diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto index 805d976d2d..92242fd2a1 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto @@ -26,4 +26,7 @@ message EnhancedEAMercury { int64 round=19; int64 epoch=20; string asset_symbol=21; + string observation_benchmark_price_string = 22; + string observation_bid_string = 23; + string observation_ask_string = 24; } From 12ff0e6dabfd52333bf4ebdc3f1725f5c4172ba7 Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:42:05 +0200 Subject: [PATCH 022/327] Update CTF and SELECTED_NETWORKS env in E2E tests (#11103) * Update CTF and SELECTED_NETWORKS env * Update go mod --- integration-tests/benchmark/keeper_test.go | 2 +- integration-tests/chaos/automation_chaos_test.go | 11 ++++++----- integration-tests/chaos/ocr2vrf_chaos_test.go | 4 ++-- integration-tests/chaos/ocr_chaos_test.go | 2 +- integration-tests/docker/test_env/test_env_builder.go | 2 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/functions/setup.go | 2 +- integration-tests/performance/cron_test.go | 2 +- integration-tests/performance/directrequest_test.go | 2 +- integration-tests/performance/flux_test.go | 2 +- integration-tests/performance/keeper_test.go | 2 +- integration-tests/performance/ocr_test.go | 2 +- integration-tests/performance/vrf_test.go | 2 +- integration-tests/reorg/automation_reorg_test.go | 4 ++-- integration-tests/smoke/automation_test.go | 8 ++++---- integration-tests/smoke/ocr2_test.go | 2 +- integration-tests/smoke/ocr2vrf_test.go | 2 +- integration-tests/testsetups/ocr.go | 8 ++++---- 19 files changed, 33 insertions(+), 32 deletions(-) diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 7178ab854e..ed26caf470 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -299,7 +299,7 @@ func getEnv(key, fallback string) string { func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockchain.EVMNetwork) { l := logging.GetTestLogger(t) - testNetwork := networks.SelectedNetwork // Environment currently being used to run benchmark test on + testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] // Environment currently being used to run benchmark test on blockTime := "1" networkDetailTOML := `MinIncomingConfirmations = 1` diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 244f6c36ea..62f85d3256 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -43,7 +43,7 @@ ListenAddresses = ["0.0.0.0:6690"]` defaultAutomationSettings = map[string]interface{}{ "replicas": 6, - "toml": client.AddNetworksConfig(baseTOML, networks.SelectedNetwork), + "toml": client.AddNetworksConfig(baseTOML, networks.MustGetSelectedNetworksFromEnv()[0]), "db": map[string]interface{}{ "stateful": true, "capacity": "1Gi", @@ -61,9 +61,10 @@ ListenAddresses = ["0.0.0.0:6690"]` } defaultEthereumSettings = ðereum.Props{ - NetworkName: networks.SelectedNetwork.Name, - Simulated: networks.SelectedNetwork.Simulated, - WsURLs: networks.SelectedNetwork.URLs, + // utils.MustGetSelectedNetworksFromEnv() + NetworkName: networks.MustGetSelectedNetworksFromEnv()[0].Name, + Simulated: networks.MustGetSelectedNetworksFromEnv()[0].Simulated, + WsURLs: networks.MustGetSelectedNetworksFromEnv()[0].URLs, Values: map[string]interface{}{ "resources": map[string]interface{}{ "requests": map[string]interface{}{ @@ -182,7 +183,7 @@ func TestAutomationChaos(t *testing.T) { testCase := tst t.Run(fmt.Sprintf("Automation_%s", name), func(t *testing.T) { t.Parallel() - network := networks.SelectedNetwork // Need a new copy of the network for each test + network := networks.MustGetSelectedNetworksFromEnv()[0] // Need a new copy of the network for each test testEnvironment := environment. New(&environment.Config{ diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 1d7f61f783..cbab1bf9e7 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -31,7 +31,7 @@ import ( func TestOCR2VRFChaos(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - loadedNetwork := networks.SelectedNetwork + loadedNetwork := networks.MustGetSelectedNetworksFromEnv()[0] defaultOCR2VRFSettings := map[string]interface{}{ "replicas": 6, @@ -119,7 +119,7 @@ func TestOCR2VRFChaos(t *testing.T) { testCase := tc t.Run(fmt.Sprintf("OCR2VRF_%s", testCaseName), func(t *testing.T) { t.Parallel() - testNetwork := networks.SelectedNetwork // Need a new copy of the network for each test + testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] // Need a new copy of the network for each test testEnvironment := environment. New(&environment.Config{ NamespacePrefix: fmt.Sprintf( diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index f3ee12046f..0d72e3932e 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -53,7 +53,7 @@ var ( ) func TestMain(m *testing.M) { - defaultOCRSettings["toml"] = client.AddNetworksConfig(config.BaseOCRP2PV1Config, networks.SelectedNetwork) + defaultOCRSettings["toml"] = client.AddNetworksConfig(config.BaseOCRP2PV1Config, networks.MustGetSelectedNetworksFromEnv()[0]) os.Exit(m.Run()) } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 072728321b..d155024050 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -238,7 +238,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } return b.te, nil } - networkConfig := networks.SelectedNetwork + networkConfig := networks.MustGetSelectedNetworksFromEnv()[0] var internalDockerUrls test_env.InternalDockerUrls if b.hasGeth && networkConfig.Simulated { networkConfig, internalDockerUrls, err = b.te.StartGeth() diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 7dd2d01778..7683a96692 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -21,7 +21,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-env v0.38.3 - github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231018101901-23824db88d36 + github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231027132403-4898f11e80b6 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 3be7407727..d280310b9f 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2370,8 +2370,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231018101901-23824db88d36 h1:ow84QG8vEHMvfjGg0RF8HNYh80WcHci6PIenXyY6K8Y= -github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231018101901-23824db88d36/go.mod h1:RWlmjwnjIGbQAnRfKwe02Ife82nNI3rZmdI0zgkfbyk= +github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231027132403-4898f11e80b6 h1:f1nUQ/1eUTMwNbOZK0P7P6OHvTDGQSn2KE+LtwY0rXA= +github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231027132403-4898f11e80b6/go.mod h1:RWlmjwnjIGbQAnRfKwe02Ife82nNI3rZmdI0zgkfbyk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index 5d44cbc698..5253c531ee 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -50,7 +50,7 @@ type S4SecretsCfg struct { } func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { - bc, err := blockchain.NewEVMClientFromNetwork(networks.SelectedNetwork, log.Logger) + bc, err := blockchain.NewEVMClientFromNetwork(networks.MustGetSelectedNetworksFromEnv()[0], log.Logger) if err != nil { return nil, err } diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index 959cb0fa3e..84a4964647 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -109,7 +109,7 @@ func TestCronPerformance(t *testing.T) { func setupCronTest(t *testing.T) (testEnvironment *environment.Environment) { logging.Init() - network := networks.SelectedNetwork + network := networks.MustGetSelectedNetworksFromEnv()[0] evmConfig := ethereum.New(nil) if !network.Simulated { evmConfig = ethereum.New(ðereum.Props{ diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index 4ff2b85619..faaac5910d 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -129,7 +129,7 @@ func TestDirectRequestPerformance(t *testing.T) { } func setupDirectRequestTest(t *testing.T) (testEnvironment *environment.Environment) { - network := networks.SelectedNetwork + network := networks.MustGetSelectedNetworksFromEnv()[0] evmConfig := ethereum.New(nil) if !network.Simulated { evmConfig = ethereum.New(ðereum.Props{ diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index 3f9db27c10..df3022003e 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -173,7 +173,7 @@ func TestFluxPerformance(t *testing.T) { } func setupFluxTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.SelectedNetwork + testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] evmConf := ethereum.New(nil) if !testNetwork.Simulated { evmConf = ethereum.New(ðereum.Props{ diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index 08ea95b434..7a2cc933de 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -134,7 +134,7 @@ func setupKeeperTest( contracts.ContractDeployer, contracts.LinkToken, ) { - network := networks.SelectedNetwork + network := networks.MustGetSelectedNetworksFromEnv()[0] evmConfig := eth.New(nil) if !network.Simulated { evmConfig = eth.New(ð.Props{ diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index b18d7f1f79..1db030f1cc 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -90,7 +90,7 @@ func TestOCRBasic(t *testing.T) { } func setupOCRTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.SelectedNetwork + testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] evmConfig := ethereum.New(nil) if !testNetwork.Simulated { evmConfig = ethereum.New(ðereum.Props{ diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index 510e378eb8..c715641692 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -135,7 +135,7 @@ func TestVRFBasic(t *testing.T) { } func setupVRFTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.SelectedNetwork + testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] evmConfig := ethereum.New(nil) if !testNetwork.Simulated { evmConfig = ethereum.New(ðereum.Props{ diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index e94e5c2853..a1260cc37a 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -48,7 +48,7 @@ HistoryDepth = 400 [EVM.GasEstimator] Mode = 'FixedPrice' LimitDefault = 5_000_000` - activeEVMNetwork = networks.SelectedNetwork + activeEVMNetwork = networks.MustGetSelectedNetworksFromEnv()[0] defaultAutomationSettings = map[string]interface{}{ "toml": client.AddNetworkDetailedConfig(baseTOML, networkTOML, activeEVMNetwork), "db": map[string]interface{}{ @@ -135,7 +135,7 @@ func TestAutomationReorg(t *testing.T) { for name, registryVersion := range registryVersions { t.Run(name, func(t *testing.T) { t.Parallel() - network := networks.SelectedNetwork + network := networks.MustGetSelectedNetworksFromEnv()[0] defaultAutomationSettings["replicas"] = numberOfNodes cd := chainlink.New(0, defaultAutomationSettings) diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 834de5ce48..3addac1b9d 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -79,9 +79,9 @@ var ( func TestMain(m *testing.M) { logging.Init() - fmt.Printf("Running Smoke Test on %s\n", networks.SelectedNetwork.Name) // Print to get around disabled logging - fmt.Printf("Chainlink Image %s\n", os.Getenv("CHAINLINK_IMAGE")) // Print to get around disabled logging - fmt.Printf("Chainlink Version %s\n", os.Getenv("CHAINLINK_VERSION")) // Print to get around disabled logging + fmt.Printf("Running Smoke Test on %s\n", networks.MustGetSelectedNetworksFromEnv()[0].Name) // Print to get around disabled logging + fmt.Printf("Chainlink Image %s\n", os.Getenv("CHAINLINK_IMAGE")) // Print to get around disabled logging + fmt.Printf("Chainlink Version %s\n", os.Getenv("CHAINLINK_VERSION")) // Print to get around disabled logging os.Exit(m.Run()) } @@ -1028,7 +1028,7 @@ func setupAutomationTestDocker( l := logging.GetTestLogger(t) // Add registry version to config registryConfig.RegistryVersion = registryVersion - network := networks.SelectedNetwork + network := networks.MustGetSelectedNetworksFromEnv()[0] // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index d82d84a207..582ca17f7b 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -107,7 +107,7 @@ func setupOCR2Test(t *testing.T, forwardersEnabled bool) ( testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork, ) { - testNetwork = networks.SelectedNetwork + testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] evmConfig := ethereum.New(nil) if !testNetwork.Simulated { evmConfig = ethereum.New(ðereum.Props{ diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 8148863918..8c102f6fd2 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -149,7 +149,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { } func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.SelectedNetwork + testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] evmConfig := eth.New(nil) if !testNetwork.Simulated { evmConfig = eth.New(ð.Props{ diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 048f3124ad..c4b1fc7ab1 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -126,7 +126,7 @@ func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { // DeployEnvironment deploys the test environment, starting all Chainlink nodes and other components for the test func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { - network := networks.SelectedNetwork // Environment currently being used to soak test on + network := networks.MustGetSelectedNetworksFromEnv()[0] // Environment currently being used to soak test on nsPre := "soak-ocr-" if o.OperatorForwarderFlow { nsPre = fmt.Sprintf("%sforwarder-", nsPre) @@ -165,7 +165,7 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { // LoadEnvironment loads an existing test environment using the provided URLs func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, chainURL, mockServerURL string) { var ( - network = networks.SelectedNetwork + network = networks.MustGetSelectedNetworksFromEnv()[0] err error ) o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) @@ -185,7 +185,7 @@ func (o *OCRSoakTest) Environment() *environment.Environment { func (o *OCRSoakTest) Setup() { var ( err error - network = networks.SelectedNetwork + network = networks.MustGetSelectedNetworksFromEnv()[0] ) // Environment currently being used to soak test on @@ -387,7 +387,7 @@ func (o *OCRSoakTest) LoadState() error { o.startTime = testState.StartTime o.startingBlockNum = testState.StartingBlockNum - network := networks.SelectedNetwork + network := networks.MustGetSelectedNetworksFromEnv()[0] o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) if err != nil { return err From 5808e734cf024a5e8c5450e939e1f2d5b3cba546 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 27 Oct 2023 08:52:16 -0500 Subject: [PATCH 023/327] core: log a warning when deprecated P2P.V1 config is set in TOML (#11073) * core: log a warning when deprecated P2P.V1 config is set in TOML * change default P2P from V1 to V2 * bump operator ui --- .../evm/config/mocks/chain_scoped_config.go | 6 +- core/cmd/shell_local.go | 5 +- core/config/app_config.go | 2 +- core/config/docs/core.toml | 7 +- core/scripts/chaincli/handler/handler.go | 4 +- .../common/vrf/docker/toml-config/base.toml | 1 - core/scripts/ocr2vrf/util.go | 13 +- core/services/chainlink/config.go | 44 +++ core/services/chainlink/config_general.go | 14 +- core/services/chainlink/config_p2p_test.go | 7 +- core/services/chainlink/config_test.go | 39 ++- .../chainlink/mocks/general_config.go | 6 +- .../testdata/config-empty-effective.toml | 4 +- .../chainlink/testdata/config-full.toml | 4 +- .../config-multi-chain-effective.toml | 4 +- .../ocr2/plugins/mercury/helpers_test.go | 4 - core/utils/config/validate.go | 14 + .../testdata/config-empty-effective.toml | 4 +- core/web/resolver/testdata/config-full.toml | 4 +- .../config-multi-chain-effective.toml | 4 +- docs/CHANGELOG.md | 10 +- docs/CONFIG.md | 12 +- integration-tests/benchmark/keeper_test.go | 1 - .../chaos/automation_chaos_test.go | 1 - integration-tests/config/config.go | 6 +- integration-tests/performance/ocr_test.go | 4 + .../reorg/automation_reorg_test.go | 6 +- integration-tests/smoke/automation_test.go | 1 - integration-tests/smoke/keeper_test.go | 2 +- integration-tests/types/config/node/core.go | 11 +- .../types/config/node/defaults/sample.toml | 1 - testdata/scripts/node/validate/default.txtar | 4 +- .../disk-based-logging-disabled.txtar | 4 +- .../validate/disk-based-logging-no-dir.txtar | 4 +- .../node/validate/disk-based-logging.txtar | 4 +- testdata/scripts/node/validate/invalid.txtar | 4 +- testdata/scripts/node/validate/valid.txtar | 4 +- testdata/scripts/node/validate/warnings.txtar | 279 ++++++++++++++++++ 38 files changed, 463 insertions(+), 85 deletions(-) create mode 100644 testdata/scripts/node/validate/warnings.txtar diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index 0854b82165..cb18282f49 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -252,9 +252,9 @@ func (_m *ChainScopedConfig) Log() coreconfig.Log { return r0 } -// LogConfiguration provides a mock function with given fields: log -func (_m *ChainScopedConfig) LogConfiguration(log coreconfig.LogfFn) { - _m.Called(log) +// LogConfiguration provides a mock function with given fields: log, warn +func (_m *ChainScopedConfig) LogConfiguration(log coreconfig.LogfFn, warn coreconfig.LogfFn) { + _m.Called(log, warn) } // Mercury provides a mock function with given fields: diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index f578604db3..401375238d 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -290,7 +290,7 @@ func (s *Shell) runNode(c *cli.Context) error { s.Config.SetPasswords(pwd, vrfpwd) - s.Config.LogConfiguration(lggr.Debugf) + s.Config.LogConfiguration(lggr.Debugf, lggr.Warnf) if err := s.Config.Validate(); err != nil { return errors.Wrap(err, "config validation failed") @@ -689,7 +689,8 @@ var errDBURLMissing = errors.New("You must set CL_DATABASE_URL env variable or p // ConfigValidate validate the client configuration and pretty-prints results func (s *Shell) ConfigFileValidate(_ *cli.Context) error { - s.Config.LogConfiguration(func(f string, params ...any) { fmt.Printf(f, params...) }) + fn := func(f string, params ...any) { fmt.Printf(f, params...) } + s.Config.LogConfiguration(fn, fn) if err := s.configExitErr(s.Config.Validate); err != nil { return err } diff --git a/core/config/app_config.go b/core/config/app_config.go index ab8d955967..648939b871 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -28,7 +28,7 @@ type AppConfig interface { Validate() error ValidateDB() error - LogConfiguration(log LogfFn) + LogConfiguration(log, warn LogfFn) SetLogLevel(lvl zapcore.Level) error SetLogSQL(logSQL bool) SetPasswords(keystore, vrf *string) diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 18f5810adc..1ca4c656a7 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -359,6 +359,8 @@ TraceLogging = false # Default # automatically fall back to V1. If V2 starts working again later, it will automatically be preferred again. This is useful # for migrating networks without downtime. Note that the two networking stacks _must not_ be configured to bind to the same IP/port. # +# Note: P2P.V1 is deprecated will be removed in the future. +# # All nodes in the OCR network should share the same networking stack. [P2P] # IncomingMessageBufferSize is the per-remote number of incoming @@ -377,9 +379,10 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example # TraceLogging enables trace level logging. TraceLogging = false # Default +# P2P.V1 is deprecated and will be removed in a future version. [P2P.V1] # Enabled enables P2P V1. -Enabled = true # Default +Enabled = false # Default # AnnounceIP should be set as the externally reachable IP address of the Chainlink node. AnnounceIP = '1.2.3.4' # Example # AnnouncePort should be set as the externally reachable port of the Chainlink node. @@ -423,7 +426,7 @@ PeerstoreWriteInterval = '5m' # Default [P2P.V2] # Enabled enables P2P V2. # Note: V1.Enabled is true by default, so it must be set false in order to run V2 only. -Enabled = false # Default +Enabled = true # Default # AnnounceAddresses is the addresses the peer will advertise on the network in `host:port` form as accepted by the TCP version of Go’s `net.Dial`. # The addresses should be reachable by other nodes on the network. When attempting to connect to another node, # a node will attempt to dial all of the other node’s AnnounceAddresses in round-robin fashion. diff --git a/core/scripts/chaincli/handler/handler.go b/core/scripts/chaincli/handler/handler.go index c51792f9ad..f72e94605d 100644 --- a/core/scripts/chaincli/handler/handler.go +++ b/core/scripts/chaincli/handler/handler.go @@ -64,9 +64,7 @@ HTTPSPort = 0 LogPoller = true [OCR2] Enabled = true -[P2P] -[P2P.V2] -Enabled = true + [Keeper] TurnLookBack = 0 [[EVM]] diff --git a/core/scripts/common/vrf/docker/toml-config/base.toml b/core/scripts/common/vrf/docker/toml-config/base.toml index 0bb83beb94..39aab2e63a 100644 --- a/core/scripts/common/vrf/docker/toml-config/base.toml +++ b/core/scripts/common/vrf/docker/toml-config/base.toml @@ -26,6 +26,5 @@ HTTPSPort = 0 [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ['0.0.0.0:6690'] ListenAddresses = ['0.0.0.0:6690'] diff --git a/core/scripts/ocr2vrf/util.go b/core/scripts/ocr2vrf/util.go index f8d104a5f3..a2ff55524d 100644 --- a/core/scripts/ocr2vrf/util.go +++ b/core/scripts/ocr2vrf/util.go @@ -14,16 +14,17 @@ import ( "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" + "github.com/urfave/cli" + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/group/edwards25519" + "go.dedis.ch/kyber/v3/pairing" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/ocr2vrf/altbn_128" "github.com/smartcontractkit/ocr2vrf/dkg" "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - "github.com/urfave/cli" - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/group/edwards25519" - "go.dedis.ch/kyber/v3/pairing" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" @@ -43,11 +44,7 @@ var ( g1 = suite.G1() g2 = suite.G2() tomlConfigTemplate = ` - [P2P.V1] - Enabled = false - [P2P.V2] - Enabled = true ListenAddresses = ["127.0.0.1:8000"] [Feature] diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 62be789f85..26e2d539ba 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -52,6 +52,50 @@ func (c *Config) TOMLString() (string, error) { return string(b), nil } +// deprecationWarnings returns an error if the Config contains deprecated fields. +// This is typically used before defaults have been applied, with input from the user. +func (c *Config) deprecationWarnings() (err error) { + if c.P2P.V1 != (toml.P2PV1{}) { + err = multierr.Append(err, config.ErrDeprecated{Name: "P2P.V1"}) + var err2 error + if c.P2P.V1.AnnounceIP != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnounceIP"}) + } + if c.P2P.V1.AnnouncePort != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnouncePort"}) + } + if c.P2P.V1.BootstrapCheckInterval != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "BootstrapCheckInterval"}) + } + if c.P2P.V1.DefaultBootstrapPeers != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DefaultBootstrapPeers"}) + } + if c.P2P.V1.DHTAnnouncementCounterUserPrefix != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTAnnouncementCounterUserPrefix"}) + } + if c.P2P.V1.DHTLookupInterval != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTLookupInterval"}) + } + if c.P2P.V1.ListenIP != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenIP"}) + } + if c.P2P.V1.ListenPort != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenPort"}) + } + if c.P2P.V1.NewStreamTimeout != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "NewStreamTimeout"}) + } + if c.P2P.V1.PeerstoreWriteInterval != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "PeerstoreWriteInterval"}) + } + err2 = config.NamedMultiErrorList(err2, "P2P.V1") + err = multierr.Append(err, err2) + } + return +} + +// Validate returns an error if the Config is not valid for use, as-is. +// This is typically used after defaults have been applied. func (c *Config) Validate() error { if err := config.Validate(c); err != nil { return fmt.Errorf("invalid configuration: %w", err) diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 8e3dc100a4..6243146e91 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -35,11 +35,13 @@ import ( type generalConfig struct { inputTOML string // user input, normalized via de/re-serialization effectiveTOML string // with default values included - secretsTOML string // with env overdies includes, redacted + secretsTOML string // with env overrides includes, redacted c *Config // all fields non-nil (unless the legacy method signature return a pointer) secrets *Secrets + warning error // warnings about inputTOML, e.g. deprecated fields + logLevelDefault zapcore.Level appIDOnce sync.Once @@ -123,7 +125,7 @@ func (o *GeneralConfigOpts) parseSecrets(secrets string) error { return nil } -// New returns a coreconfig.GeneralConfig for the given options. +// New returns a GeneralConfig for the given options. func (o GeneralConfigOpts) New() (GeneralConfig, error) { err := o.parse() if err != nil { @@ -135,6 +137,8 @@ func (o GeneralConfigOpts) New() (GeneralConfig, error) { return nil, err } + _, warning := utils.MultiErrorList(o.Config.deprecationWarnings()) + o.Config.setDefaults() if !o.SkipEnv { err = o.Secrets.setEnv() @@ -163,6 +167,7 @@ func (o GeneralConfigOpts) New() (GeneralConfig, error) { secretsTOML: secrets, c: &o.Config, secrets: &o.Secrets, + warning: warning, } if lvl := o.Config.Log.Level; lvl != nil { cfg.logLevelDefault = zapcore.Level(*lvl) @@ -253,10 +258,13 @@ func validateEnv() (err error) { return } -func (g *generalConfig) LogConfiguration(log coreconfig.LogfFn) { +func (g *generalConfig) LogConfiguration(log, warn coreconfig.LogfFn) { log("# Secrets:\n%s\n", g.secretsTOML) log("# Input Configuration:\n%s\n", g.inputTOML) log("# Effective Configuration, with defaults applied:\n%s\n", g.effectiveTOML) + if g.warning != nil { + warn("# Configuration warning:\n%s\n", g.warning) + } } // ConfigTOML implements chainlink.ConfigV2 diff --git a/core/services/chainlink/config_p2p_test.go b/core/services/chainlink/config_p2p_test.go index d6adfe7051..21ce8f17e4 100644 --- a/core/services/chainlink/config_p2p_test.go +++ b/core/services/chainlink/config_p2p_test.go @@ -4,9 +4,10 @@ import ( "testing" "time" - "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/libocr/commontypes" ) func TestP2PConfig(t *testing.T) { @@ -23,7 +24,7 @@ func TestP2PConfig(t *testing.T) { assert.True(t, p2p.TraceLogging()) v1 := p2p.V1() - assert.False(t, v1.Enabled()) + assert.True(t, v1.Enabled()) assert.Equal(t, "1.2.3.4", v1.AnnounceIP().String()) assert.Equal(t, uint16(1234), v1.AnnouncePort()) assert.Equal(t, time.Minute, v1.BootstrapCheckInterval()) @@ -38,7 +39,7 @@ func TestP2PConfig(t *testing.T) { assert.Equal(t, time.Minute, v1.PeerstoreWriteInterval()) v2 := p2p.V2() - assert.True(t, v2.Enabled()) + assert.False(t, v2.Enabled()) assert.Equal(t, []string{"a", "b", "c"}, v2.AnnounceAddresses()) assert.ElementsMatch( t, diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index d811dd8209..597dab6ba1 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -389,7 +389,7 @@ func TestConfig_Marshal(t *testing.T) { PeerID: mustPeerID("12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw"), TraceLogging: ptr(true), V1: toml.P2PV1{ - Enabled: ptr(false), + Enabled: ptr(true), AnnounceIP: mustIP("1.2.3.4"), AnnouncePort: ptr[uint16](1234), BootstrapCheckInterval: models.MustNewDuration(time.Minute), @@ -402,7 +402,7 @@ func TestConfig_Marshal(t *testing.T) { PeerstoreWriteInterval: models.MustNewDuration(time.Minute), }, V2: toml.P2PV2{ - Enabled: ptr(true), + Enabled: ptr(false), AnnounceAddresses: &[]string{"a", "b", "c"}, DefaultBootstrappers: &[]ocrcommontypes.BootstrapperLocator{ {PeerID: "12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw", Addrs: []string{"foo:42", "bar:10"}}, @@ -820,7 +820,7 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true [P2P.V1] -Enabled = false +Enabled = true AnnounceIP = '1.2.3.4' AnnouncePort = 1234 BootstrapCheckInterval = '1m0s' @@ -833,7 +833,7 @@ NewStreamTimeout = '1s' PeerstoreWriteInterval = '1m0s' [P2P.V2] -Enabled = true +Enabled = false AnnounceAddresses = ['a', 'b', 'c'] DefaultBootstrappers = ['12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@foo:42/bar:10', '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@test:99'] DeltaDial = '1m0s' @@ -1248,6 +1248,21 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { secrets = "# Secrets:\n" input = "# Input Configuration:\n" effective = "# Effective Configuration, with defaults applied:\n" + warning = "# Configuration warning:\n" + + deprecated = `2 errors: + - P2P.V1: is deprecated and will be removed in a future version + - P2P.V1: 10 errors: + - AnnounceIP: is deprecated and will be removed in a future version + - AnnouncePort: is deprecated and will be removed in a future version + - BootstrapCheckInterval: is deprecated and will be removed in a future version + - DefaultBootstrapPeers: is deprecated and will be removed in a future version + - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version + - DHTLookupInterval: is deprecated and will be removed in a future version + - ListenIP: is deprecated and will be removed in a future version + - ListenPort: is deprecated and will be removed in a future version + - NewStreamTimeout: is deprecated and will be removed in a future version + - PeerstoreWriteInterval: is deprecated and will be removed in a future version` ) tests := []struct { name string @@ -1257,10 +1272,11 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { wantConfig string wantEffective string wantSecrets string + wantWarning string }{ {name: "empty", wantEffective: emptyEffectiveTOML, wantSecrets: emptyEffectiveSecretsTOML}, {name: "full", inputSecrets: secretsFullTOML, inputConfig: fullTOML, - wantConfig: fullTOML, wantEffective: fullTOML, wantSecrets: secretsFullRedactedTOML}, + wantConfig: fullTOML, wantEffective: fullTOML, wantSecrets: secretsFullRedactedTOML, wantWarning: deprecated}, {name: "multi-chain", inputSecrets: secretsMultiTOML, inputConfig: multiChainTOML, wantConfig: multiChainTOML, wantEffective: multiChainEffectiveTOML, wantSecrets: secretsMultiRedactedTOML}, } @@ -1274,10 +1290,11 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { } c, err := opts.New() require.NoError(t, err) - c.LogConfiguration(lggr.Infof) + c.LogConfiguration(lggr.Infof, lggr.Warnf) inputLogs := observed.FilterMessageSnippet(secrets).All() if assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.InfoLevel, inputLogs[0].Level) got := strings.TrimPrefix(inputLogs[0].Message, secrets) got = strings.TrimSuffix(got, "\n") assert.Equal(t, tt.wantSecrets, got) @@ -1285,6 +1302,7 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { inputLogs = observed.FilterMessageSnippet(input).All() if assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.InfoLevel, inputLogs[0].Level) got := strings.TrimPrefix(inputLogs[0].Message, input) got = strings.TrimSuffix(got, "\n") assert.Equal(t, tt.wantConfig, got) @@ -1292,10 +1310,19 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { inputLogs = observed.FilterMessageSnippet(effective).All() if assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.InfoLevel, inputLogs[0].Level) got := strings.TrimPrefix(inputLogs[0].Message, effective) got = strings.TrimSuffix(got, "\n") assert.Equal(t, tt.wantEffective, got) } + + inputLogs = observed.FilterMessageSnippet(warning).All() + if tt.wantWarning != "" && assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.WarnLevel, inputLogs[0].Level) + got := strings.TrimPrefix(inputLogs[0].Message, warning) + got = strings.TrimSuffix(got, "\n") + assert.Equal(t, tt.wantWarning, got) + } }) } } diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 8098b9634f..0bc51ea431 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -298,9 +298,9 @@ func (_m *GeneralConfig) Log() config.Log { return r0 } -// LogConfiguration provides a mock function with given fields: log -func (_m *GeneralConfig) LogConfiguration(log config.LogfFn) { - _m.Called(log) +// LogConfiguration provides a mock function with given fields: log, warn +func (_m *GeneralConfig) LogConfiguration(log config.LogfFn, warn config.LogfFn) { + _m.Called(log, warn) } // Mercury provides a mock function with given fields: diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index e746d66777..48d432138a 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 3bd422f892..1534a411dc 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -148,7 +148,7 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true [P2P.V1] -Enabled = false +Enabled = true AnnounceIP = '1.2.3.4' AnnouncePort = 1234 BootstrapCheckInterval = '1m0s' @@ -161,7 +161,7 @@ NewStreamTimeout = '1s' PeerstoreWriteInterval = '1m0s' [P2P.V2] -Enabled = true +Enabled = false AnnounceAddresses = ['a', 'b', 'c'] DefaultBootstrappers = ['12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@foo:42/bar:10', '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@test:99'] DeltaDial = '1m0s' diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 89b034169c..1dcbfe3a83 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index ce4e089516..60904b5813 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -190,10 +190,6 @@ func setupNode( c.P2P.PeerID = ptr(p2pKey.PeerID()) c.P2P.TraceLogging = ptr(true) - // [P2P.V1] - // Enabled = false - c.P2P.V1.Enabled = ptr(false) - // [P2P.V2] // Enabled = true // AnnounceAddresses = ['$EXT_IP:17775'] diff --git a/core/utils/config/validate.go b/core/utils/config/validate.go index 3ed0ffbabb..32cb94b520 100644 --- a/core/utils/config/validate.go +++ b/core/utils/config/validate.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "github.com/Masterminds/semver/v3" "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-relay/pkg/config" @@ -146,3 +147,16 @@ type ErrOverride struct { func (e ErrOverride) Error() string { return fmt.Sprintf("%s: overrides (duplicate keys or list elements) are not allowed for multiple secrets files", e.Name) } + +type ErrDeprecated struct { + Name string + Version semver.Version +} + +func (e ErrDeprecated) Error() string { + when := "a future version" + if e.Version != (semver.Version{}) { + when = fmt.Sprintf("version %s", e.Version) + } + return fmt.Sprintf("%s: is deprecated and will be removed in %s", e.Name, when) +} diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index e746d66777..48d432138a 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 5a815b2e01..4b53396b94 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -148,7 +148,7 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true [P2P.V1] -Enabled = false +Enabled = true AnnounceIP = '1.2.3.4' AnnouncePort = 1234 BootstrapCheckInterval = '1m0s' @@ -161,7 +161,7 @@ NewStreamTimeout = '1s' PeerstoreWriteInterval = '1m0s' [P2P.V2] -Enabled = true +Enabled = false AnnounceAddresses = ['a', 'b', 'c'] DefaultBootstrappers = ['12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@foo:42/bar:10', '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@test:99'] DeltaDial = '1m0s' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 89b034169c..1dcbfe3a83 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 44d018769e..daeddf2ce6 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -29,9 +29,15 @@ These will eventually replace `TelemetryIngress.URL` and `TelemetryIngress.Serve - LogPoller will now use finality tags to dynamically determine finality on evm chains if `UseFinalityTags=true`, rather than the fixed `FinalityDepth` specified in toml config -### Upcoming Required Configuration Change +### Changed + +- `P2P.V1` is now disabled (`Enabled = false`) by default. It must be explicitly enabled with `true` to be used. However, it is deprecated and will be removed in the future. +- `P2P.V2` is now enabled (`Enabled = true`) by default. -- Starting in 2.9.0, chainlink nodes will no longer allow `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey`. Any TOML configuration that sets this fields will prevent the node from booting. These fields will be replaced by `[[TelemetryIngress.Endpoints]]` +### Upcoming Required Configuration Changes +Starting in `v2.9.0`: +- `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey` will no longer be allowed. Any TOML configuration that sets this fields will prevent the node from booting. These fields will be replaced by `[[TelemetryIngress.Endpoints]]` +- `P2P.V1` will no longer be supported and must not be set in TOML configuration in order to boot. Use `P2P.V2` instead. If you are using both, `V1` can simply be removed. ### Removed diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 1fc7d9b632..da986e0500 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -981,6 +981,8 @@ If both are configured, then for each link with another peer, V2 networking will automatically fall back to V1. If V2 starts working again later, it will automatically be preferred again. This is useful for migrating networks without downtime. Note that the two networking stacks _must not_ be configured to bind to the same IP/port. +Note: P2P.V1 is deprecated will be removed in the future. + All nodes in the OCR network should share the same networking stack. ### IncomingMessageBufferSize @@ -1017,7 +1019,7 @@ TraceLogging enables trace level logging. ## P2P.V1 ```toml [P2P.V1] -Enabled = true # Default +Enabled = false # Default AnnounceIP = '1.2.3.4' # Example AnnouncePort = 1337 # Example BootstrapCheckInterval = '20s' # Default @@ -1029,11 +1031,11 @@ ListenPort = 1337 # Example NewStreamTimeout = '10s' # Default PeerstoreWriteInterval = '5m' # Default ``` - +P2P.V1 is deprecated and will be removed in a future version. ### Enabled ```toml -Enabled = true # Default +Enabled = false # Default ``` Enabled enables P2P V1. @@ -1119,7 +1121,7 @@ PeerstoreWriteInterval controls how often the peerstore for the OCR V1 networkin ## P2P.V2 ```toml [P2P.V2] -Enabled = false # Default +Enabled = true # Default AnnounceAddresses = ['1.2.3.4:9999', '[a52d:0:a88:1274::abcd]:1337'] # Example DefaultBootstrappers = ['12D3KooWMHMRLQkgPbFSYHwD3NBuwtS1AmxhvKVUrcfyaGDASR4U@1.2.3.4:9999', '12D3KooWM55u5Swtpw9r8aFLQHEtw7HR4t44GdNs654ej5gRs2Dh@example.com:1234'] # Example DeltaDial = '15s' # Default @@ -1130,7 +1132,7 @@ ListenAddresses = ['1.2.3.4:9999', '[a52d:0:a88:1274::abcd]:1337'] # Example ### Enabled ```toml -Enabled = false # Default +Enabled = true # Default ``` Enabled enables P2P V2. Note: V1.Enabled is true by default, so it must be set false in order to run V2 only. diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index ed26caf470..7f484fc69f 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -37,7 +37,6 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"] [Keeper] diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 62f85d3256..8697044aa7 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -37,7 +37,6 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"]` diff --git a/integration-tests/config/config.go b/integration-tests/config/config.go index cd3f5983a2..44c108b0d7 100644 --- a/integration-tests/config/config.go +++ b/integration-tests/config/config.go @@ -4,6 +4,10 @@ var ( BaseOCRP2PV1Config = `[OCR] Enabled = true +[P2P] +[P2P.V2] +Enabled = false + [P2P] [P2P.V1] Enabled = true @@ -18,7 +22,6 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"]` @@ -67,7 +70,6 @@ CaptureEATelemetry = true [P2P] [P2P.V2] -Enabled = true ListenAddresses = ['0.0.0.0:6690']` TelemetryIngressConfig = `[TelemetryIngress] diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index 1db030f1cc..4d875022ed 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -102,6 +102,10 @@ func setupOCRTest(t *testing.T) (testEnvironment *environment.Environment, testN baseTOML := `[OCR] Enabled = true +[P2P] +[P2P.V2] +Enabled = false + [P2P] [P2P.V1] Enabled = true diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index a1260cc37a..608144eafd 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -9,6 +9,9 @@ import ( "time" "github.com/onsi/gomega" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-env/pkg/cdk8s/blockscout" "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" @@ -17,8 +20,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -35,7 +36,6 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"]` networkTOML = `Enabled = true diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 3addac1b9d..17373e6a95 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -1038,7 +1038,6 @@ func setupAutomationTestDocker( clNodeConfig.Keeper.TurnLookBack = it_utils.Ptr[int64](int64(0)) clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval clNodeConfig.Keeper.Registry.PerformGasOverhead = it_utils.Ptr[uint32](uint32(150000)) - clNodeConfig.P2P.V2.Enabled = it_utils.Ptr[bool](true) clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 21dbeb8753..d42944fd55 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1098,7 +1098,7 @@ func setupKeeperTest(t *testing.T) ( contracts.LinkToken, *test_env.CLClusterTestEnv, ) { - clNodeConfig := node.NewConfig(node.NewBaseConfig()) + clNodeConfig := node.NewConfig(node.NewBaseConfig(), node.WithP2Pv1()) turnLookBack := int64(0) syncInterval := models.MustMakeDuration(5 * time.Second) performGasOverhead := uint32(150000) diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 966e270e51..37047cdb66 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -115,13 +115,14 @@ func WithP2Pv1() NodeConfigOpt { ListenIP: utils2.MustIP("0.0.0.0"), ListenPort: utils2.Ptr[uint16](6690), } + // disabled default + c.P2P.V2 = toml.P2PV2{Enabled: utils2.Ptr(false)} } } func WithP2Pv2() NodeConfigOpt { return func(c *chainlink.Config) { c.P2P.V2 = toml.P2PV2{ - Enabled: utils2.Ptr(true), ListenAddresses: &[]string{"0.0.0.0:6690"}, } } @@ -130,14 +131,14 @@ func WithP2Pv2() NodeConfigOpt { func WithTracing() NodeConfigOpt { return func(c *chainlink.Config) { c.Tracing = toml.Tracing{ - Enabled: utils2.Ptr(true), + Enabled: utils2.Ptr(true), CollectorTarget: utils2.Ptr("otel-collector:4317"), // ksortable unique id - NodeID: utils2.Ptr(ksuid.New().String()), - Attributes: map[string]string{ + NodeID: utils2.Ptr(ksuid.New().String()), + Attributes: map[string]string{ "env": "smoke", }, - SamplingRatio: utils2.Ptr(1.0), + SamplingRatio: utils2.Ptr(1.0), } } } diff --git a/integration-tests/types/config/node/defaults/sample.toml b/integration-tests/types/config/node/defaults/sample.toml index 3663998003..b0e1bc2a07 100644 --- a/integration-tests/types/config/node/defaults/sample.toml +++ b/integration-tests/types/config/node/defaults/sample.toml @@ -15,7 +15,6 @@ DefaultTransactionQueueDepth = 0 [P2P] [P2P.V2] -Enabled = true ListenAddresses = ['0.0.0.0:6690'] AnnounceAddresses = ['0.0.0.0:6690'] DeltaDial = '500ms' diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 06a623c9ca..189476bfa8 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -154,7 +154,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -167,7 +167,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 1c0956b10d..593aa0b21d 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -198,7 +198,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -211,7 +211,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 19e180e0cf..7b8aa5e383 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -198,7 +198,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -211,7 +211,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 062a21b196..ef6548619e 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -198,7 +198,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -211,7 +211,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 0fa1647381..87b877bc88 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -188,7 +188,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -201,7 +201,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 002c249fb7..c607da1064 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -195,7 +195,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -208,7 +208,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar new file mode 100644 index 0000000000..ee7926f8f5 --- /dev/null +++ b/testdata/scripts/node/validate/warnings.txtar @@ -0,0 +1,279 @@ +exec chainlink node -c config.toml -s secrets.toml validate +cmp stdout out.txt + +-- config.toml -- +[P2P.V1] +Enabled = true +AnnounceIP = '' +AnnouncePort = 0 +BootstrapCheckInterval = '20s' +DefaultBootstrapPeers = [] +DHTAnnouncementCounterUserPrefix = 0 +DHTLookupInterval = 10 +ListenIP = '0.0.0.0' +ListenPort = 0 +NewStreamTimeout = '10s' +PeerstoreWriteInterval = '5m0s' + +-- secrets.toml -- +[Database] +URL = 'postgresql://user:pass1234567890abcd@localhost:5432/dbname?sslmode=disable' + +[Password] +Keystore = 'keystore_pass' + +-- out.txt -- +# Secrets: +[Database] +URL = 'xxxxx' +AllowSimplePasswords = false + +[Password] +Keystore = 'xxxxx' + +# Input Configuration: +[P2P] +[P2P.V1] +Enabled = true +AnnounceIP = '' +AnnouncePort = 0 +BootstrapCheckInterval = '20s' +DefaultBootstrapPeers = [] +DHTAnnouncementCounterUserPrefix = 0 +DHTLookupInterval = 10 +ListenIP = '0.0.0.0' +ListenPort = 0 +NewStreamTimeout = '10s' +PeerstoreWriteInterval = '5m0s' + +# Effective Configuration, with defaults applied: +InsecureFastScrypt = false +RootDir = '~/.chainlink' +ShutdownGracePeriod = '5s' + +[Feature] +FeedsManager = true +LogPoller = false +UICSAKeys = false + +[Database] +DefaultIdleInTxSessionTimeout = '1h0m0s' +DefaultLockTimeout = '15s' +DefaultQueryTimeout = '10s' +LogQueries = false +MaxIdleConns = 10 +MaxOpenConns = 20 +MigrateOnStartup = true + +[Database.Backup] +Dir = '' +Frequency = '1h0m0s' +Mode = 'none' +OnVersionUpgrade = true + +[Database.Listener] +MaxReconnectDuration = '10m0s' +MinReconnectInterval = '1m0s' +FallbackPollInterval = '30s' + +[Database.Lock] +Enabled = true +LeaseDuration = '10s' +LeaseRefreshInterval = '1s' + +[TelemetryIngress] +UniConn = true +Logging = false +BufferSize = 100 +MaxBatchSize = 50 +SendInterval = '500ms' +SendTimeout = '10s' +UseBatchSend = true +URL = '' +ServerPubKey = '' + +[AuditLogger] +Enabled = false +ForwardToUrl = '' +JsonWrapperKey = '' +Headers = [] + +[Log] +Level = 'info' +JSONConsole = false +UnixTS = false + +[Log.File] +Dir = '' +MaxSize = '5.12gb' +MaxAgeDays = 0 +MaxBackups = 1 + +[WebServer] +AllowOrigins = 'http://localhost:3000,http://localhost:6688' +BridgeResponseURL = '' +BridgeCacheTTL = '0s' +HTTPWriteTimeout = '10s' +HTTPPort = 6688 +SecureCookies = true +SessionTimeout = '15m0s' +SessionReaperExpiration = '240h0m0s' +HTTPMaxSize = '32.77kb' +StartTimeout = '15s' +ListenIP = '0.0.0.0' + +[WebServer.MFA] +RPID = '' +RPOrigin = '' + +[WebServer.RateLimit] +Authenticated = 1000 +AuthenticatedPeriod = '1m0s' +Unauthenticated = 5 +UnauthenticatedPeriod = '20s' + +[WebServer.TLS] +CertPath = '' +ForceRedirect = false +Host = '' +HTTPSPort = 6689 +KeyPath = '' +ListenIP = '0.0.0.0' + +[JobPipeline] +ExternalInitiatorsEnabled = false +MaxRunDuration = '10m0s' +MaxSuccessfulRuns = 10000 +ReaperInterval = '1h0m0s' +ReaperThreshold = '24h0m0s' +ResultWriteQueueDepth = 100 + +[JobPipeline.HTTPRequest] +DefaultTimeout = '15s' +MaxSize = '32.77kb' + +[FluxMonitor] +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false + +[OCR2] +Enabled = false +ContractConfirmations = 3 +BlockchainTimeout = '20s' +ContractPollInterval = '1m0s' +ContractSubscribeInterval = '2m0s' +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' +CaptureEATelemetry = false +CaptureAutomationCustomTelemetry = false +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false +TraceLogging = false + +[OCR] +Enabled = false +ObservationTimeout = '5s' +BlockchainTimeout = '20s' +ContractPollInterval = '1m0s' +ContractSubscribeInterval = '2m0s' +DefaultTransactionQueueDepth = 1 +KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' +SimulateTransactions = false +TransmitterAddress = '' +CaptureEATelemetry = false +TraceLogging = false + +[P2P] +IncomingMessageBufferSize = 10 +OutgoingMessageBufferSize = 10 +PeerID = '' +TraceLogging = false + +[P2P.V1] +Enabled = true +AnnounceIP = '' +AnnouncePort = 0 +BootstrapCheckInterval = '20s' +DefaultBootstrapPeers = [] +DHTAnnouncementCounterUserPrefix = 0 +DHTLookupInterval = 10 +ListenIP = '0.0.0.0' +ListenPort = 0 +NewStreamTimeout = '10s' +PeerstoreWriteInterval = '5m0s' + +[P2P.V2] +Enabled = true +AnnounceAddresses = [] +DefaultBootstrappers = [] +DeltaDial = '15s' +DeltaReconcile = '1m0s' +ListenAddresses = [] + +[Keeper] +DefaultTransactionQueueDepth = 1 +GasPriceBufferPercent = 20 +GasTipCapBufferPercent = 20 +BaseFeeBufferPercent = 20 +MaxGracePeriod = 100 +TurnLookBack = 1000 + +[Keeper.Registry] +CheckGasOverhead = 200000 +PerformGasOverhead = 300000 +MaxPerformDataSize = 5000 +SyncInterval = '30m0s' +SyncUpkeepQueueSize = 10 + +[AutoPprof] +Enabled = false +ProfileRoot = '' +PollInterval = '10s' +GatherDuration = '10s' +GatherTraceDuration = '5s' +MaxProfileSize = '100.00mb' +CPUProfileRate = 1 +MemProfileRate = 1 +BlockProfileRate = 1 +MutexProfileFraction = 1 +MemThreshold = '4.00gb' +GoroutineThreshold = 5000 + +[Pyroscope] +ServerAddress = '' +Environment = 'mainnet' + +[Sentry] +Debug = false +DSN = '' +Environment = '' +Release = '' + +[Insecure] +DevWebServer = false +OCRDevelopmentMode = false +InfiniteDepthQueries = false +DisableRateLimiting = false + +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + +# Configuration warning: +2 errors: + - P2P.V1: is deprecated and will be removed in a future version + - P2P.V1: 10 errors: + - AnnounceIP: is deprecated and will be removed in a future version + - AnnouncePort: is deprecated and will be removed in a future version + - BootstrapCheckInterval: is deprecated and will be removed in a future version + - DefaultBootstrapPeers: is deprecated and will be removed in a future version + - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version + - DHTLookupInterval: is deprecated and will be removed in a future version + - ListenIP: is deprecated and will be removed in a future version + - ListenPort: is deprecated and will be removed in a future version + - NewStreamTimeout: is deprecated and will be removed in a future version + - PeerstoreWriteInterval: is deprecated and will be removed in a future version +Valid configuration. From 7206a62a49f098c816172a1d4c1f51af04f24e15 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 27 Oct 2023 09:32:43 -0500 Subject: [PATCH 024/327] tools/docker: use longer password (#11098) --- tools/docker/.env | 2 +- tools/docker/dev-secrets.toml | 4 ---- tools/docker/develop.Dockerfile | 2 +- tools/docker/docker-compose.yaml | 8 ++------ 4 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 tools/docker/dev-secrets.toml diff --git a/tools/docker/.env b/tools/docker/.env index 32de93edb4..05f4314ff2 100644 --- a/tools/docker/.env +++ b/tools/docker/.env @@ -4,7 +4,7 @@ # Chainlink env vars CHAINLINK_DB_NAME=node_dev CL_DEV=true -CHAINLINK_PGPASSWORD=node +CHAINLINK_PGPASSWORD=thispasswordislongenough # Explorer env vars EXPLORER_DB_NAME=explorer_dev diff --git a/tools/docker/dev-secrets.toml b/tools/docker/dev-secrets.toml deleted file mode 100644 index b27b8a8a8e..0000000000 --- a/tools/docker/dev-secrets.toml +++ /dev/null @@ -1,4 +0,0 @@ -# dev only credentials - -[Database] -AllowSimplePasswords = true diff --git a/tools/docker/develop.Dockerfile b/tools/docker/develop.Dockerfile index 46fad445d6..f663eaf1cf 100644 --- a/tools/docker/develop.Dockerfile +++ b/tools/docker/develop.Dockerfile @@ -54,7 +54,7 @@ EXPOSE 8546 # Default env setup for testing ENV CHAINLINK_DB_NAME chainlink_test -ENV CHAINLINK_PGPASSWORD=node +ENV CHAINLINK_PGPASSWORD=thispasswordislongenough ENV CL_DATABASE_URL=postgresql://postgres:$CHAINLINK_PGPASSWORD@localhost:5432/$CHAINLINK_DB_NAME?sslmode=disable ENV TYPEORM_USERNAME=postgres ENV TYPEORM_PASSWORD=node diff --git a/tools/docker/docker-compose.yaml b/tools/docker/docker-compose.yaml index 4d3ef7def2..c01d357935 100644 --- a/tools/docker/docker-compose.yaml +++ b/tools/docker/docker-compose.yaml @@ -10,7 +10,7 @@ services: # Note that the keystore import allows us to submit transactions # immediately because addresses are specified when starting the # parity/geth node to be prefunded with eth. - entrypoint: /bin/sh -c "chainlink -c /run/secrets/config -s /run/secrets/secrets node start -d -p /run/secrets/node_password -a /run/secrets/apicredentials" + entrypoint: /bin/sh -c "chainlink -c /run/secrets/config node start -d -p /run/secrets/node_password -a /run/secrets/apicredentials" restart: always environment: - CL_DATABASE_URL @@ -23,7 +23,6 @@ services: - apicredentials - keystore - config - - secrets node-2: container_name: chainlink-node-2 @@ -31,7 +30,7 @@ services: build: context: ../../ dockerfile: core/chainlink.Dockerfile - entrypoint: /bin/sh -c "chainlink -c /run/secrets/config -s /run/secrets/secrets node start -d -p /run/secrets/node_password -a /run/secrets/apicredentials" + entrypoint: /bin/sh -c "chainlink -c /run/secrets/config node start -d -p /run/secrets/node_password -a /run/secrets/apicredentials" restart: always environment: - CL_DATABASE_URL @@ -44,7 +43,6 @@ services: - apicredentials - keystore - config - - secrets # TODO # - replace clroot with secrets @@ -59,6 +57,4 @@ secrets: file: ../secrets/0xb90c7E3F7815F59EAD74e7543eB6D9E8538455D6.json config: file: config.toml - secrets: - file: dev-secrets.toml From c95d8f80832d7867daf98dd73ae2f4ad670b970c Mon Sep 17 00:00:00 2001 From: Lei Date: Fri, 27 Oct 2023 09:41:34 -0700 Subject: [PATCH 025/327] fix solhint issues under src/v0.8/automation (#11065) --- contracts/package.json | 2 +- contracts/src/v0.8/automation/AutomationBase.sol | 5 +++-- contracts/src/v0.8/automation/AutomationCompatible.sol | 4 ++-- contracts/src/v0.8/automation/Chainable.sol | 10 ++++++---- contracts/src/v0.8/automation/ExecutionPrevention.sol | 5 +++-- contracts/src/v0.8/automation/HeartbeatRequester.sol | 6 ++++-- contracts/src/v0.8/automation/UpkeepTranscoder.sol | 6 ++++-- 7 files changed, 23 insertions(+), 15 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 46b47440a6..935c7901b6 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 377 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 350 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", diff --git a/contracts/src/v0.8/automation/AutomationBase.sol b/contracts/src/v0.8/automation/AutomationBase.sol index d91780a79f..8267fbc6a4 100644 --- a/contracts/src/v0.8/automation/AutomationBase.sol +++ b/contracts/src/v0.8/automation/AutomationBase.sol @@ -8,7 +8,8 @@ contract AutomationBase { * @notice method that allows it to be simulated via eth_call by checking that * the sender is the zero address. */ - function preventExecution() internal view { + function _preventExecution() internal view { + // solhint-disable-next-line avoid-tx-origin if (tx.origin != address(0)) { revert OnlySimulatedBackend(); } @@ -19,7 +20,7 @@ contract AutomationBase { * that the sender is the zero address. */ modifier cannotExecute() { - preventExecution(); + _preventExecution(); _; } } diff --git a/contracts/src/v0.8/automation/AutomationCompatible.sol b/contracts/src/v0.8/automation/AutomationCompatible.sol index 5634956ea7..6533243684 100644 --- a/contracts/src/v0.8/automation/AutomationCompatible.sol +++ b/contracts/src/v0.8/automation/AutomationCompatible.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./AutomationBase.sol"; -import "./interfaces/AutomationCompatibleInterface.sol"; +import {AutomationBase} from "./AutomationBase.sol"; +import {AutomationCompatibleInterface} from "./interfaces/AutomationCompatibleInterface.sol"; abstract contract AutomationCompatible is AutomationBase, AutomationCompatibleInterface {} diff --git a/contracts/src/v0.8/automation/Chainable.sol b/contracts/src/v0.8/automation/Chainable.sol index 1b446f013a..29ac7796c4 100644 --- a/contracts/src/v0.8/automation/Chainable.sol +++ b/contracts/src/v0.8/automation/Chainable.sol @@ -10,29 +10,31 @@ contract Chainable { /** * @dev addresses of the next contract in the chain **have to be immutable/constant** or the system won't work */ - address private immutable FALLBACK_ADDRESS; + address private immutable i_FALLBACK_ADDRESS; /** * @param fallbackAddress the address of the next contract in the chain */ constructor(address fallbackAddress) { - FALLBACK_ADDRESS = fallbackAddress; + i_FALLBACK_ADDRESS = fallbackAddress; } /** * @notice returns the address of the next contract in the chain */ function fallbackTo() external view returns (address) { - return FALLBACK_ADDRESS; + return i_FALLBACK_ADDRESS; } /** * @notice the fallback function routes the call to the next contract in the chain * @dev most of the implementation is copied directly from OZ's Proxy contract */ + // solhint-disable payable-fallback + // solhint-disable-next-line no-complex-fallback fallback() external { // copy to memory for assembly access - address next = FALLBACK_ADDRESS; + address next = i_FALLBACK_ADDRESS; // copied directly from OZ's Proxy contract assembly { // Copy msg.data. We take full control of memory in this inline assembly diff --git a/contracts/src/v0.8/automation/ExecutionPrevention.sol b/contracts/src/v0.8/automation/ExecutionPrevention.sol index a8baf55fd2..30a823c4b8 100644 --- a/contracts/src/v0.8/automation/ExecutionPrevention.sol +++ b/contracts/src/v0.8/automation/ExecutionPrevention.sol @@ -8,7 +8,8 @@ abstract contract ExecutionPrevention { * @notice method that allows it to be simulated via eth_call by checking that * the sender is the zero address. */ - function preventExecution() internal view { + function _preventExecution() internal view { + // solhint-disable-next-line avoid-tx-origin if (tx.origin != address(0)) { revert OnlySimulatedBackend(); } @@ -19,7 +20,7 @@ abstract contract ExecutionPrevention { * that the sender is the zero address. */ modifier cannotExecute() { - preventExecution(); + _preventExecution(); _; } } diff --git a/contracts/src/v0.8/automation/HeartbeatRequester.sol b/contracts/src/v0.8/automation/HeartbeatRequester.sol index d5802a7958..aa39073800 100644 --- a/contracts/src/v0.8/automation/HeartbeatRequester.sol +++ b/contracts/src/v0.8/automation/HeartbeatRequester.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT +// solhint-disable-next-line one-contract-per-file pragma solidity 0.8.6; -import "./../interfaces/TypeAndVersionInterface.sol"; -import "../shared/access/ConfirmedOwner.sol"; +import {TypeAndVersionInterface} from "./../interfaces/TypeAndVersionInterface.sol"; +import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; // defines some interfaces for type safety and reduces encoding/decoding // does not use the full interfaces intentionally because the requester only uses a fraction of them @@ -32,6 +33,7 @@ contract HeartbeatRequester is TypeAndVersionInterface, ConfirmedOwner { * - HeartbeatRequester 1.0.0: The requester fetches the latest aggregator address from proxy, and request a new round * using the aggregator address. */ + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "HeartbeatRequester 1.0.0"; constructor() ConfirmedOwner(msg.sender) {} diff --git a/contracts/src/v0.8/automation/UpkeepTranscoder.sol b/contracts/src/v0.8/automation/UpkeepTranscoder.sol index 450da8c14a..144a96c7e7 100644 --- a/contracts/src/v0.8/automation/UpkeepTranscoder.sol +++ b/contracts/src/v0.8/automation/UpkeepTranscoder.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.0; -import "./interfaces/UpkeepTranscoderInterface.sol"; -import "../interfaces/TypeAndVersionInterface.sol"; +import {UpkeepTranscoderInterface} from "./interfaces/UpkeepTranscoderInterface.sol"; +import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; +import {UpkeepFormat} from "./UpkeepFormat.sol"; /** * @notice Transcoder for converting upkeep data from one keeper @@ -16,6 +17,7 @@ contract UpkeepTranscoder is UpkeepTranscoderInterface, TypeAndVersionInterface * @notice versions: * - UpkeepTranscoder 1.0.0: placeholder to allow new formats in the future */ + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "UpkeepTranscoder 1.0.0"; /** From 2df49da68def10542e9f885aa8e8435f807ba2b8 Mon Sep 17 00:00:00 2001 From: Erik Burton Date: Sat, 28 Oct 2023 04:01:16 -0700 Subject: [PATCH 026/327] [RE-2009] Bump action references (#11115) * Bump docker/setup-buildx-action from 2.7.0 to 3.0.0 * Bump docker/build-push-action from 3.2.0 to 5.0.0 * Bump aws-actions/configure-aws-credentials from 3.0.2 to 4.0.1 --- .github/actions/build-sign-publish-chainlink/action.yml | 6 +++--- .github/actions/goreleaser-build-sign-publish/action.yml | 2 +- .github/workflows/helm-publish.yml | 2 +- .github/workflows/performance-tests.yml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/actions/build-sign-publish-chainlink/action.yml b/.github/actions/build-sign-publish-chainlink/action.yml index bd633bced7..55c682bc8d 100644 --- a/.github/actions/build-sign-publish-chainlink/action.yml +++ b/.github/actions/build-sign-publish-chainlink/action.yml @@ -112,7 +112,7 @@ runs: registry: ${{ inputs.ecr-hostname }} - name: Setup Docker Buildx - uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - name: Generate docker metadata for root image id: meta-root @@ -128,7 +128,7 @@ runs: - name: Build and push root docker image id: buildpush-root - uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 # v3.2.0 + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 with: push: ${{ inputs.publish }} context: . @@ -161,7 +161,7 @@ runs: - name: Build and push non-root docker image id: buildpush-nonroot - uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 # v3.2.0 + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 with: push: ${{ inputs.publish }} context: . diff --git a/.github/actions/goreleaser-build-sign-publish/action.yml b/.github/actions/goreleaser-build-sign-publish/action.yml index 0cc144564c..845d2443fc 100644 --- a/.github/actions/goreleaser-build-sign-publish/action.yml +++ b/.github/actions/goreleaser-build-sign-publish/action.yml @@ -65,7 +65,7 @@ runs: using: composite steps: - name: Setup docker buildx - uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - name: Set up qemu uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0 - name: Setup go diff --git a/.github/workflows/helm-publish.yml b/.github/workflows/helm-publish.yml index 48a7060fc7..6ea46e6a52 100644 --- a/.github/workflows/helm-publish.yml +++ b/.github/workflows/helm-publish.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@50ac8dd1e1b10d09dac7b8727528b91bed831ac0 # v3.0.2 + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_GATI }} role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index 277940dc2d..87fb75beca 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -29,9 +29,9 @@ jobs: id: login-ecr uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # v2.7.0 + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - name: Build and Push - uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 # v3.2.0 + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 with: context: . file: core/chainlink.Dockerfile From b6550805131cf86361250eb986e869348b3a490d Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 30 Oct 2023 07:48:36 -0500 Subject: [PATCH 027/327] skipped test cleanup (#11026) --- core/internal/testutils/testutils.go | 4 ++++ .../evm21/logprovider/integration_test.go | 20 +++++++++---------- .../internal/ocr2vrf_integration_test.go | 4 ++-- .../uni_client_integration_test.go | 5 +++-- .../vrf/v2/integration_v2_plus_test.go | 4 +--- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 938d814b9e..79c86f0c5f 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -451,3 +451,7 @@ func MustDecodeBase64(s string) (b []byte) { } return } + +func SkipFlakey(t *testing.T, ticketURL string) { + t.Skip("Flakey", ticketURL) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index 506dcb9ea3..811468746e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -455,9 +455,7 @@ func TestIntegration_LogEventProvider_RateLimit(t *testing.T) { } func TestIntegration_LogRecoverer_Backfill(t *testing.T) { - t.Skip() // TODO: remove skip after removing constant timeouts - ctx, cancel := context.WithTimeout(testutils.Context(t), time.Second*60) - defer cancel() + ctx := testutils.Context(t) backend, stopMining, accounts := setupBackend(t) defer stopMining() @@ -515,21 +513,21 @@ func TestIntegration_LogRecoverer_Backfill(t *testing.T) { }() defer recoverer.Close() - lctx, lcancel := context.WithTimeout(ctx, time.Second*15) - defer lcancel() var allProposals []ocr2keepers.UpkeepPayload - for lctx.Err() == nil { + for { poll(backend.Commit()) proposals, err := recoverer.GetRecoveryProposals(ctx) require.NoError(t, err) allProposals = append(allProposals, proposals...) - if len(allProposals) < n { - time.Sleep(100 * time.Millisecond) - continue + if len(allProposals) >= n { + break // success + } + select { + case <-ctx.Done(): + t.Fatalf("could not recover logs before timeout: %s", ctx.Err()) + case <-time.After(100 * time.Millisecond): } - break } - require.NoError(t, lctx.Err(), "could not recover logs before timeout") } func collectPayloads(ctx context.Context, t *testing.T, logProvider logprovider.LogEventProvider, n, rounds int) []ocr2keepers.UpkeepPayload { diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index b9a4d50002..cf7a408725 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -326,12 +326,12 @@ func setupNodeOCR2( } func TestIntegration_OCR2VRF_ForwarderFlow(t *testing.T) { - t.Skip() + testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/VRF-688") runOCR2VRFTest(t, true) } func TestIntegration_OCR2VRF(t *testing.T) { - t.Skip() + testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/VRF-688") runOCR2VRFTest(t, false) } diff --git a/core/services/synchronization/uni_client_integration_test.go b/core/services/synchronization/uni_client_integration_test.go index 1ad2865669..fcc0dc2371 100644 --- a/core/services/synchronization/uni_client_integration_test.go +++ b/core/services/synchronization/uni_client_integration_test.go @@ -6,16 +6,17 @@ import ( "testing" "time" - "github.com/smartcontractkit/wsrpc" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/wsrpc" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" ) func TestUniClient(t *testing.T) { - t.Skip() + t.Skip("Incomplete", "https://smartcontract-it.atlassian.net/browse/BCF-2729") privKey, err := hex.DecodeString("TODO") require.NoError(t, err) pubKey, err := hex.DecodeString("TODO") diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 9adf47f256..f08c10c200 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -486,9 +486,7 @@ func TestVRFV2PlusIntegration_SingleConsumer_EOA_Request_Batching_Enabled(t *tes } func TestVRFV2PlusIntegration_SingleConsumer_EIP150_HappyPath(t *testing.T) { - // See: https://smartcontract-it.atlassian.net/browse/VRF-589 - // Temporarily skipping to figure out issue with test - t.Skip() + testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/VRF-589") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) From db64df96ba3ab987a27d684b8161c35fcaa569b8 Mon Sep 17 00:00:00 2001 From: Cedric Date: Mon, 30 Oct 2023 14:05:31 +0000 Subject: [PATCH 028/327] [BCF-2630] Add pipeline runner wrapper (#11091) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../generic/pipeline_runner_adapter.go | 94 ++++++++++++ .../generic/pipeline_runner_adapter_test.go | 144 ++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 8 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 core/services/ocr2/plugins/generic/pipeline_runner_adapter.go create mode 100644 core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c8b616a4b6..f097ea89be 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -302,7 +302,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.20230913032705-f924d753cc47 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 // 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 c4d0575bb2..0461daa25e 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1458,8 +1458,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.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 h1:QFMxPq7AqU4qXeW7UBv0eP/mpLt2pG2QkASUyFjKoIE= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04/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/ocr2/plugins/generic/pipeline_runner_adapter.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go new file mode 100644 index 0000000000..5c58522f40 --- /dev/null +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go @@ -0,0 +1,94 @@ +package generic + +import ( + "context" + "time" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/store/models" +) + +var _ types.PipelineRunnerService = (*PipelineRunnerAdapter)(nil) + +type pipelineRunner interface { + ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) +} + +type PipelineRunnerAdapter struct { + runner pipelineRunner + job job.Job + logger logger.Logger +} + +func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, vars types.Vars, options types.Options) ([]types.TaskResult, error) { + s := pipeline.Spec{ + DotDagSource: spec, + CreatedAt: time.Now(), + MaxTaskDuration: models.Interval(options.MaxTaskDuration), + JobID: p.job.ID, + JobName: p.job.Name.ValueOrZero(), + JobType: string(p.job.Type), + } + + defaultVars := map[string]interface{}{ + "jb": map[string]interface{}{ + "databaseID": p.job.ID, + "externalJobID": p.job.ExternalJobID, + "name": p.job.Name.ValueOrZero(), + }, + } + + err := merge(defaultVars, vars.Vars) + if err != nil { + return nil, err + } + + finalVars := pipeline.NewVarsFrom(defaultVars) + _, trrs, err := p.runner.ExecuteRun(ctx, s, finalVars, p.logger) + if err != nil { + return nil, err + } + + taskResults := make([]types.TaskResult, len(trrs)) + for i, trr := range trrs { + taskResults[i] = types.TaskResult{ + ID: trr.ID.String(), + Type: string(trr.Task.Type()), + Value: trr.Result.Value, + Error: trr.Result.Error, + Index: int(trr.TaskRun.Index), + } + } + return taskResults, nil +} + +func NewPipelineRunnerAdapter(logger logger.Logger, job job.Job, runner pipelineRunner) *PipelineRunnerAdapter { + return &PipelineRunnerAdapter{ + logger: logger, + job: job, + runner: runner, + } +} + +// merge merges mapTwo into mapOne, modifying mapOne in the process. +func merge(mapOne, mapTwo map[string]interface{}) error { + for k, v := range mapTwo { + // if `mapOne` doesn't have `k`, then nothing to do, just assign v to `mapOne`. + if _, ok := mapOne[k]; !ok { + mapOne[k] = v + } else { + vAsMap, vOK := v.(map[string]interface{}) + mapOneVAsMap, moOK := mapOne[k].(map[string]interface{}) + if vOK && moOK { + merge(mapOneVAsMap, vAsMap) + } else { + mapOne[k] = v + } + } + } + + return nil +} diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go new file mode 100644 index 0000000000..d1f06d8766 --- /dev/null +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go @@ -0,0 +1,144 @@ +package generic + +import ( + "context" + "net/http" + "reflect" + "testing" + "time" + + "github.com/google/uuid" + "github.com/shopspring/decimal" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + _ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +const spec = ` +answer [type=sum values=<[ $(val), 2 ]>] +answer; +` + +func TestAdapter_Integration(t *testing.T) { + logger := logger.TestLogger(t) + cfg := configtest.NewTestGeneralConfig(t) + url := cfg.Database().URL() + db, err := pg.NewConnection(url.String(), cfg.Database().Dialect(), cfg.Database()) + require.NoError(t, err) + + keystore := keystore.NewInMemory(db, utils.FastScryptParams, logger, cfg.Database()) + pipelineORM := pipeline.NewORM(db, logger, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + bridgesORM := bridges.NewORM(db, logger, cfg.Database()) + pr := pipeline.NewRunner( + pipelineORM, + bridgesORM, + cfg.JobPipeline(), + cfg.WebServer(), + nil, + keystore.Eth(), + keystore.VRF(), + logger, + http.DefaultClient, + http.DefaultClient, + ) + pra := NewPipelineRunnerAdapter(logger, job.Job{}, pr) + results, err := pra.ExecuteRun(context.Background(), spec, types.Vars{Vars: map[string]interface{}{"val": 1}}, types.Options{}) + require.NoError(t, err) + + finalResult := results[0].Value.(decimal.Decimal) + + assert.True(t, decimal.NewFromInt(3).Equal(finalResult)) +} + +func newMockPipelineRunner() *mockPipelineRunner { + return &mockPipelineRunner{} +} + +type mockPipelineRunner struct { + results pipeline.TaskRunResults + err error + run *pipeline.Run + spec pipeline.Spec + vars pipeline.Vars +} + +func (m *mockPipelineRunner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (*pipeline.Run, pipeline.TaskRunResults, error) { + m.spec = spec + m.vars = vars + return m.run, m.results, m.err +} + +func TestAdapter_AddsDefaultVars(t *testing.T) { + logger := logger.TestLogger(t) + mpr := newMockPipelineRunner() + jobID, externalJobID, name := int32(100), uuid.New(), null.StringFrom("job-name") + pra := NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name}, mpr) + + _, err := pra.ExecuteRun(context.Background(), spec, types.Vars{}, types.Options{}) + require.NoError(t, err) + + gotName, err := mpr.vars.Get("jb.name") + require.NoError(t, err) + assert.Equal(t, name.String, gotName) + + gotID, err := mpr.vars.Get("jb.databaseID") + require.NoError(t, err) + assert.Equal(t, jobID, gotID) + + gotExternalID, err := mpr.vars.Get("jb.externalJobID") + require.NoError(t, err) + assert.Equal(t, externalJobID, gotExternalID) +} + +func TestPipelineRunnerAdapter_SetsVarsOnSpec(t *testing.T) { + logger := logger.TestLogger(t) + mpr := newMockPipelineRunner() + jobID, externalJobID, name, jobType := int32(100), uuid.New(), null.StringFrom("job-name"), job.Type("generic") + pra := NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name, Type: jobType}, mpr) + + maxDuration := time.Duration(100 * time.Second) + _, err := pra.ExecuteRun(context.Background(), spec, types.Vars{}, types.Options{MaxTaskDuration: maxDuration}) + require.NoError(t, err) + + assert.Equal(t, jobID, mpr.spec.JobID) + assert.Equal(t, name.ValueOrZero(), mpr.spec.JobName) + assert.Equal(t, string(jobType), mpr.spec.JobType) + assert.Equal(t, maxDuration, mpr.spec.MaxTaskDuration.Duration()) + +} + +func TestMerge(t *testing.T) { + vars := map[string]interface{}{ + "jb": map[string]interface{}{ + "databaseID": "some-job-id", + }, + } + addedVars := map[string]interface{}{ + "jb": map[string]interface{}{ + "some-other-var": "foo", + }, + "val": 0, + } + + err := merge(vars, addedVars) + require.NoError(t, err) + + assert.True(t, reflect.DeepEqual(vars, map[string]interface{}{ + "jb": map[string]interface{}{ + "databaseID": "some-job-id", + "some-other-var": "foo", + }, + "val": 0, + }), vars) +} diff --git a/go.mod b/go.mod index df970160ac..3679c79ed0 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,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.20230913032705-f924d753cc47 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 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-20231020123319-d255366a6545 diff --git a/go.sum b/go.sum index 59286787c2..e2bc661048 100644 --- a/go.sum +++ b/go.sum @@ -1459,8 +1459,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.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 h1:QFMxPq7AqU4qXeW7UBv0eP/mpLt2pG2QkASUyFjKoIE= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04/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 7683a96692..d3e09d94d7 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -385,7 +385,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.20230913032705-f924d753cc47 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 // 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/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index d280310b9f..725e05914c 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2364,8 +2364,8 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc4 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= github.com/smartcontractkit/chainlink-env v0.38.3 h1:ZtOnwkG622R0VCTxL5V09AnT/QXhlFwkGTjd0Lsfpfg= github.com/smartcontractkit/chainlink-env v0.38.3/go.mod h1:7z4sw/hN8TxioQCLwFqQdhK3vaOV0a22Qe99z4bRUcg= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 h1:QFMxPq7AqU4qXeW7UBv0eP/mpLt2pG2QkASUyFjKoIE= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04/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= From e242dfb9ae44a36ef05bb7b09f75fce0f415e308 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 30 Oct 2023 10:17:18 -0400 Subject: [PATCH 029/327] Every instance of mercury transmitter should not load reports for all feeds on startup (#10829) * Every instance of mercury transmitter should not load reports for all feeds on startup * Fix a few persistence manager bugs * Bump Migration version --- core/services/relay/evm/mercury/orm.go | 38 +++++---- core/services/relay/evm/mercury/orm_test.go | 48 +++++++----- .../relay/evm/mercury/persistence_manager.go | 4 +- .../evm/mercury/persistence_manager_test.go | 78 ++++++++++++++----- .../services/relay/evm/mercury/transmitter.go | 2 +- .../relay/evm/mercury/transmitter_test.go | 4 + ...d_feed_id_to_mercury_transmit_requests.sql | 14 ++++ 7 files changed, 130 insertions(+), 58 deletions(-) create mode 100644 core/store/migrate/migrations/0205_add_feed_id_to_mercury_transmit_requests.sql diff --git a/core/services/relay/evm/mercury/orm.go b/core/services/relay/evm/mercury/orm.go index dd7d7b33e7..7273519f6b 100644 --- a/core/services/relay/evm/mercury/orm.go +++ b/core/services/relay/evm/mercury/orm.go @@ -23,8 +23,8 @@ import ( type ORM interface { InsertTransmitRequest(req *pb.TransmitRequest, jobID int32, reportCtx ocrtypes.ReportContext, qopts ...pg.QOpt) error DeleteTransmitRequests(reqs []*pb.TransmitRequest, qopts ...pg.QOpt) error - GetTransmitRequests(qopts ...pg.QOpt) ([]*Transmission, error) - PruneTransmitRequests(maxSize int, qopts ...pg.QOpt) error + GetTransmitRequests(jobID int32, qopts ...pg.QOpt) ([]*Transmission, error) + PruneTransmitRequests(jobID int32, maxSize int, qopts ...pg.QOpt) error LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg.QOpt) (report []byte, err error) } @@ -49,6 +49,11 @@ func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) ORM { // InsertTransmitRequest inserts one transmit request if the payload does not exist already. func (o *orm) InsertTransmitRequest(req *pb.TransmitRequest, jobID int32, reportCtx ocrtypes.ReportContext, qopts ...pg.QOpt) error { + feedID, err := FeedIDFromReport(req.Payload) + if err != nil { + return err + } + q := o.q.WithOpts(qopts...) var wg sync.WaitGroup wg.Add(2) @@ -57,16 +62,12 @@ func (o *orm) InsertTransmitRequest(req *pb.TransmitRequest, jobID int32, report go func() { defer wg.Done() err1 = q.ExecQ(` - INSERT INTO mercury_transmit_requests (payload, payload_hash, config_digest, epoch, round, extra_hash, job_id) - VALUES ($1, $2, $3, $4, $5, $6, $7) + INSERT INTO mercury_transmit_requests (payload, payload_hash, config_digest, epoch, round, extra_hash, job_id, feed_id) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (payload_hash) DO NOTHING - `, req.Payload, hashPayload(req.Payload), reportCtx.ConfigDigest[:], reportCtx.Epoch, reportCtx.Round, reportCtx.ExtraHash[:], jobID) + `, req.Payload, hashPayload(req.Payload), reportCtx.ConfigDigest[:], reportCtx.Epoch, reportCtx.Round, reportCtx.ExtraHash[:], jobID, feedID[:]) }() - feedID, err := FeedIDFromReport(req.Payload) - if err != nil { - return err - } go func() { defer wg.Done() err2 = q.ExecQ(` @@ -101,15 +102,16 @@ func (o *orm) DeleteTransmitRequests(reqs []*pb.TransmitRequest, qopts ...pg.QOp } // GetTransmitRequests returns all transmit requests in chronologically descending order. -func (o *orm) GetTransmitRequests(qopts ...pg.QOpt) ([]*Transmission, error) { +func (o *orm) GetTransmitRequests(jobID int32, qopts ...pg.QOpt) ([]*Transmission, error) { q := o.q.WithOpts(qopts...) // The priority queue uses epoch and round to sort transmissions so order by // the same fields here for optimal insertion into the pq. rows, err := q.QueryContext(q.ParentCtx, ` SELECT payload, config_digest, epoch, round, extra_hash FROM mercury_transmit_requests + WHERE job_id = $1 ORDER BY epoch DESC, round DESC - `) + `, jobID) if err != nil { return nil, err } @@ -142,20 +144,22 @@ func (o *orm) GetTransmitRequests(qopts ...pg.QOpt) ([]*Transmission, error) { return transmissions, nil } -// PruneTransmitRequests keeps at most maxSize rows in the table, deleting the -// oldest transactions. -func (o *orm) PruneTransmitRequests(maxSize int, qopts ...pg.QOpt) error { +// PruneTransmitRequests keeps at most maxSize rows for the given job ID, +// deleting the oldest transactions. +func (o *orm) PruneTransmitRequests(jobID int32, maxSize int, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) // Prune the oldest requests by epoch and round. return q.ExecQ(` DELETE FROM mercury_transmit_requests - WHERE payload_hash NOT IN ( + WHERE job_id = $1 AND + payload_hash NOT IN ( SELECT payload_hash FROM mercury_transmit_requests + WHERE job_id = $1 ORDER BY epoch DESC, round DESC - LIMIT $1 + LIMIT $2 ) - `, maxSize) + `, jobID, maxSize) } func (o *orm) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg.QOpt) (report []byte, err error) { diff --git a/core/services/relay/evm/mercury/orm_test.go b/core/services/relay/evm/mercury/orm_test.go index a6a7232767..56dea70417 100644 --- a/core/services/relay/evm/mercury/orm_test.go +++ b/core/services/relay/evm/mercury/orm_test.go @@ -3,6 +3,7 @@ package mercury import ( "testing" + "github.com/cometbft/cometbft/libs/rand" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -16,7 +17,7 @@ import ( func TestORM(t *testing.T) { db := pgtest.NewSqlxDB(t) - var jobID int32 // foreign key constraints disabled so can leave as 0 + jobID := rand.Int32() // foreign key constraints disabled so value doesn't matter pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) lggr := logger.TestLogger(t) @@ -48,7 +49,7 @@ func TestORM(t *testing.T) { err = orm.InsertTransmitRequest(&pb.TransmitRequest{Payload: reports[2]}, jobID, reportContexts[2]) require.NoError(t, err) - transmissions, err := orm.GetTransmitRequests() + transmissions, err := orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Equal(t, transmissions, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[2]}, ReportCtx: reportContexts[2]}, @@ -65,7 +66,7 @@ func TestORM(t *testing.T) { err = orm.DeleteTransmitRequests([]*pb.TransmitRequest{{Payload: reports[1]}}) require.NoError(t, err) - transmissions, err = orm.GetTransmitRequests() + transmissions, err = orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Equal(t, transmissions, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[2]}, ReportCtx: reportContexts[2]}, @@ -80,7 +81,7 @@ func TestORM(t *testing.T) { err = orm.DeleteTransmitRequests([]*pb.TransmitRequest{{Payload: []byte("does-not-exist")}}) require.NoError(t, err) - transmissions, err = orm.GetTransmitRequests() + transmissions, err = orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Equal(t, transmissions, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[2]}, ReportCtx: reportContexts[2]}, @@ -98,7 +99,7 @@ func TestORM(t *testing.T) { require.NoError(t, err) assert.Equal(t, reports[2], l) - transmissions, err = orm.GetTransmitRequests() + transmissions, err = orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Empty(t, transmissions) @@ -106,7 +107,7 @@ func TestORM(t *testing.T) { err = orm.InsertTransmitRequest(&pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) require.NoError(t, err) - transmissions, err = orm.GetTransmitRequests() + transmissions, err = orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Equal(t, transmissions, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[3]}, ReportCtx: reportContexts[3]}, @@ -118,7 +119,7 @@ func TestORM(t *testing.T) { err = orm.InsertTransmitRequest(&pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) require.NoError(t, err) - transmissions, err = orm.GetTransmitRequests() + transmissions, err = orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Equal(t, transmissions, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[3]}, ReportCtx: reportContexts[3]}, @@ -131,7 +132,7 @@ func TestORM(t *testing.T) { func TestORM_PruneTransmitRequests(t *testing.T) { db := pgtest.NewSqlxDB(t) - var jobID int32 // foreign key constraints disabled so can leave as 0 + jobID := rand.Int32() // foreign key constraints disabled so value doesn't matter pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) @@ -157,10 +158,10 @@ func TestORM_PruneTransmitRequests(t *testing.T) { require.NoError(t, err) // Max size greater than table size, expect no-op - err = orm.PruneTransmitRequests(5) + err = orm.PruneTransmitRequests(jobID, 5) require.NoError(t, err) - transmissions, err := orm.GetTransmitRequests() + transmissions, err := orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Equal(t, transmissions, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[1]}, ReportCtx: makeReportContext(1, 2)}, @@ -168,37 +169,48 @@ func TestORM_PruneTransmitRequests(t *testing.T) { }) // Max size equal to table size, expect no-op - err = orm.PruneTransmitRequests(2) + err = orm.PruneTransmitRequests(jobID, 2) require.NoError(t, err) - transmissions, err = orm.GetTransmitRequests() + transmissions, err = orm.GetTransmitRequests(jobID) require.NoError(t, err) require.Equal(t, transmissions, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[1]}, ReportCtx: makeReportContext(1, 2)}, {Req: &pb.TransmitRequest{Payload: reports[0]}, ReportCtx: makeReportContext(1, 1)}, }) + // Max size is table size + 1, but jobID differs, expect no-op + err = orm.PruneTransmitRequests(-1, 2) + require.NoError(t, err) + + transmissions, err = orm.GetTransmitRequests(jobID) + require.NoError(t, err) + require.Equal(t, []*Transmission{ + {Req: &pb.TransmitRequest{Payload: reports[1]}, ReportCtx: makeReportContext(1, 2)}, + {Req: &pb.TransmitRequest{Payload: reports[0]}, ReportCtx: makeReportContext(1, 1)}, + }, transmissions) + err = orm.InsertTransmitRequest(&pb.TransmitRequest{Payload: reports[2]}, jobID, makeReportContext(2, 1)) require.NoError(t, err) err = orm.InsertTransmitRequest(&pb.TransmitRequest{Payload: reports[3]}, jobID, makeReportContext(2, 2)) require.NoError(t, err) - // Max size is table size + 1, expect the oldest row to be pruned. - err = orm.PruneTransmitRequests(3) + // Max size is table size - 1, expect the oldest row to be pruned. + err = orm.PruneTransmitRequests(jobID, 3) require.NoError(t, err) - transmissions, err = orm.GetTransmitRequests() + transmissions, err = orm.GetTransmitRequests(jobID) require.NoError(t, err) - require.Equal(t, transmissions, []*Transmission{ + require.Equal(t, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[3]}, ReportCtx: makeReportContext(2, 2)}, {Req: &pb.TransmitRequest{Payload: reports[2]}, ReportCtx: makeReportContext(2, 1)}, {Req: &pb.TransmitRequest{Payload: reports[1]}, ReportCtx: makeReportContext(1, 2)}, - }) + }, transmissions) } func TestORM_InsertTransmitRequest_LatestReport(t *testing.T) { db := pgtest.NewSqlxDB(t) - var jobID int32 // foreign key constraints disabled so can leave as 0 + jobID := rand.Int32() // foreign key constraints disabled so value doesn't matter pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index 9e8df72a15..1c8dad4530 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -78,7 +78,7 @@ func (pm *PersistenceManager) AsyncDelete(req *pb.TransmitRequest) { } func (pm *PersistenceManager) Load(ctx context.Context) ([]*Transmission, error) { - return pm.orm.GetTransmitRequests(pg.WithParentCtx(ctx)) + return pm.orm.GetTransmitRequests(pm.jobID, pg.WithParentCtx(ctx)) } func (pm *PersistenceManager) runFlushDeletesLoop() { @@ -118,7 +118,7 @@ func (pm *PersistenceManager) runPruneLoop() { ticker.Stop() return case <-ticker.C: - if err := pm.orm.PruneTransmitRequests(pm.maxTransmitQueueSize, pg.WithParentCtx(ctx), pg.WithLongQueryTimeout()); err != nil { + if err := pm.orm.PruneTransmitRequests(pm.jobID, pm.maxTransmitQueueSize, pg.WithParentCtx(ctx), pg.WithLongQueryTimeout()); err != nil { pm.lggr.Errorw("Failed to prune transmit requests table", "err", err) } else { pm.lggr.Debugw("Pruned transmit requests table") diff --git a/core/services/relay/evm/mercury/persistence_manager_test.go b/core/services/relay/evm/mercury/persistence_manager_test.go index 97628ed9c2..d185a64a8f 100644 --- a/core/services/relay/evm/mercury/persistence_manager_test.go +++ b/core/services/relay/evm/mercury/persistence_manager_test.go @@ -5,7 +5,10 @@ import ( "testing" "time" + "github.com/cometbft/cometbft/libs/rand" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/sqlx" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" @@ -16,19 +19,22 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) -func bootstrapPersistenceManager(t *testing.T) (*PersistenceManager, *observer.ObservedLogs) { +func bootstrapPersistenceManager(t *testing.T, jobID int32, db *sqlx.DB) (*PersistenceManager, *observer.ObservedLogs) { t.Helper() - db := pgtest.NewSqlxDB(t) - pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) - pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.DebugLevel) orm := NewORM(db, lggr, pgtest.NewQConfig(true)) - return NewPersistenceManager(lggr, orm, 0, 2, 5*time.Millisecond, 5*time.Millisecond), observedLogs + return NewPersistenceManager(lggr, orm, jobID, 2, 5*time.Millisecond, 5*time.Millisecond), observedLogs } func TestPersistenceManager(t *testing.T) { + jobID1 := rand.Int32() + jobID2 := jobID1 + 1 + ctx := context.Background() - pm, _ := bootstrapPersistenceManager(t) + db := pgtest.NewSqlxDB(t) + pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) + pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) + pm, _ := bootstrapPersistenceManager(t, jobID1, db) reports := sampleReports @@ -52,11 +58,23 @@ func TestPersistenceManager(t *testing.T) { require.Equal(t, []*Transmission{ {Req: &pb.TransmitRequest{Payload: reports[1]}}, }, transmissions) + + t.Run("scopes load to only transmissions with matching job ID", func(t *testing.T) { + pm2, _ := bootstrapPersistenceManager(t, jobID2, db) + transmissions, err = pm2.Load(ctx) + require.NoError(t, err) + + assert.Len(t, transmissions, 0) + }) } func TestPersistenceManagerAsyncDelete(t *testing.T) { ctx := context.Background() - pm, observedLogs := bootstrapPersistenceManager(t) + jobID := rand.Int32() + db := pgtest.NewSqlxDB(t) + pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) + pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) + pm, observedLogs := bootstrapPersistenceManager(t, jobID, db) reports := sampleReports @@ -96,16 +114,32 @@ func TestPersistenceManagerAsyncDelete(t *testing.T) { } func TestPersistenceManagerPrune(t *testing.T) { + jobID1 := rand.Int32() + jobID2 := jobID1 + 1 + db := pgtest.NewSqlxDB(t) + pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) + pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) + ctx := context.Background() - pm, observedLogs := bootstrapPersistenceManager(t) - reports := sampleReports + reports := make([][]byte, 25) + for i := 0; i < 25; i++ { + reports[i] = buildSampleV1Report(int64(i)) + } - err := pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[0]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 1}}) + pm2, _ := bootstrapPersistenceManager(t, jobID2, db) + for i := 0; i < 20; i++ { + err := pm2.Insert(ctx, &pb.TransmitRequest{Payload: reports[i]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: uint32(i)}}) + require.NoError(t, err) + } + + pm, observedLogs := bootstrapPersistenceManager(t, jobID1, db) + + err := pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[21]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 21}}) require.NoError(t, err) - err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[1]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 2}}) + err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[22]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 22}}) require.NoError(t, err) - err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[2]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 3}}) + err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[23]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 23}}) require.NoError(t, err) err = pm.Start(ctx) @@ -118,24 +152,28 @@ func TestPersistenceManagerPrune(t *testing.T) { transmissions, err := pm.Load(ctx) require.NoError(t, err) require.Equal(t, []*Transmission{ - {Req: &pb.TransmitRequest{Payload: reports[2]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 3}}}, - {Req: &pb.TransmitRequest{Payload: reports[1]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 2}}}, + {Req: &pb.TransmitRequest{Payload: reports[23]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 23}}}, + {Req: &pb.TransmitRequest{Payload: reports[22]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 22}}}, }, transmissions) // Test pruning stops after Close. err = pm.Close() require.NoError(t, err) - err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[3]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 4}}) + err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[24]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 24}}) require.NoError(t, err) - time.Sleep(15 * time.Millisecond) - transmissions, err = pm.Load(ctx) require.NoError(t, err) require.Equal(t, []*Transmission{ - {Req: &pb.TransmitRequest{Payload: reports[3]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 4}}}, - {Req: &pb.TransmitRequest{Payload: reports[2]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 3}}}, - {Req: &pb.TransmitRequest{Payload: reports[1]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 2}}}, + {Req: &pb.TransmitRequest{Payload: reports[24]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 24}}}, + {Req: &pb.TransmitRequest{Payload: reports[23]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 23}}}, + {Req: &pb.TransmitRequest{Payload: reports[22]}, ReportCtx: ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 22}}}, }, transmissions) + + t.Run("prune was scoped to job ID", func(t *testing.T) { + transmissions, err = pm2.Load(ctx) + require.NoError(t, err) + assert.Len(t, transmissions, 20) + }) } diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 0c701e3b4b..0c2721442b 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -137,7 +137,7 @@ func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrp jobID, fmt.Sprintf("%x", fromAccount), make(chan (struct{})), - NewTransmitQueue(lggr, feedIDHex, maxTransmitQueueSize, nil, persistenceManager), + nil, sync.WaitGroup{}, transmitSuccessCount.WithLabelValues(feedIDHex), transmitDuplicateCount.WithLabelValues(feedIDHex), diff --git a/core/services/relay/evm/mercury/transmitter_test.go b/core/services/relay/evm/mercury/transmitter_test.go index 6723ffcbca..c8a68d41a1 100644 --- a/core/services/relay/evm/mercury/transmitter_test.go +++ b/core/services/relay/evm/mercury/transmitter_test.go @@ -26,6 +26,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { var jobID int32 pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) + q := NewTransmitQueue(lggr, "", 0, nil, nil) t.Run("v1 report transmission successfully enqueued", func(t *testing.T) { report := sampleV1Report @@ -40,6 +41,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { }, } mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) + mt.queue = q err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -57,6 +59,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { }, } mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) + mt.queue = q err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -74,6 +77,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { }, } mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) + mt.queue = q err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) diff --git a/core/store/migrate/migrations/0205_add_feed_id_to_mercury_transmit_requests.sql b/core/store/migrate/migrations/0205_add_feed_id_to_mercury_transmit_requests.sql new file mode 100644 index 0000000000..04cf5a2571 --- /dev/null +++ b/core/store/migrate/migrations/0205_add_feed_id_to_mercury_transmit_requests.sql @@ -0,0 +1,14 @@ +-- +goose Up +ALTER TABLE mercury_transmit_requests ADD COLUMN feed_id BYTEA CHECK (feed_id IS NULL OR octet_length(feed_id) = 32); +DROP INDEX idx_mercury_transmission_requests_epoch_round; +CREATE INDEX idx_mercury_transmission_requests_job_id_epoch_round ON mercury_transmit_requests (job_id, epoch DESC, round DESC); +CREATE INDEX idx_mercury_transmit_requests_job_id ON mercury_transmit_requests (job_id); +CREATE INDEX idx_mercury_transmit_requests_feed_id ON mercury_transmit_requests (feed_id); +CREATE INDEX idx_mercury_feed_latest_reports_job_id ON feed_latest_reports (job_id); + +-- +goose Down +ALTER TABLE mercury_transmit_requests DROP COLUMN feed_id; +DROP INDEX idx_mercury_transmit_requests_job_id; +DROP INDEX idx_mercury_feed_latest_reports_job_id; +CREATE INDEX idx_mercury_transmission_requests_epoch_round ON mercury_transmit_requests (epoch DESC, round DESC); +DROP INDEX idx_mercury_transmission_requests_job_id_epoch_round; From 5e1c3a3f2ddf35ac6e86f9640ba33f71173efadc Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Mon, 30 Oct 2023 16:22:07 +0100 Subject: [PATCH 030/327] Use CTF instead of chainlink-env in E2E tests (#11120) --- integration-tests/actions/actions.go | 2 +- integration-tests/benchmark/keeper_test.go | 12 ++++++------ integration-tests/chaos/automation_chaos_test.go | 12 ++++++------ integration-tests/chaos/ocr2vrf_chaos_test.go | 10 +++++----- integration-tests/chaos/ocr_chaos_test.go | 16 ++++++++-------- .../client/chainlink_config_builder.go | 2 +- integration-tests/client/chainlink_k8s.go | 2 +- integration-tests/go.mod | 3 +-- integration-tests/go.sum | 6 ++---- integration-tests/performance/cron_test.go | 12 ++++++------ .../performance/directrequest_test.go | 10 +++++----- integration-tests/performance/flux_test.go | 10 +++++----- integration-tests/performance/keeper_test.go | 10 +++++----- integration-tests/performance/ocr_test.go | 10 +++++----- integration-tests/performance/vrf_test.go | 6 +++--- integration-tests/reorg/automation_reorg_test.go | 8 ++++---- integration-tests/reorg/reorg_confirmer.go | 8 ++++---- integration-tests/reorg/reorg_test.go | 14 +++++++------- integration-tests/smoke/ocr2_test.go | 10 +++++----- integration-tests/smoke/ocr2vrf_test.go | 6 +++--- integration-tests/testsetups/don_evm_chain.go | 10 +++++----- integration-tests/testsetups/keeper_benchmark.go | 2 +- integration-tests/testsetups/ocr.go | 10 +++++----- integration-tests/testsetups/profile.go | 2 +- integration-tests/testsetups/vrfv2.go | 2 +- 25 files changed, 96 insertions(+), 99 deletions(-) diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index dcdca91cc7..010b431b56 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -16,9 +16,9 @@ import ( "github.com/rs/zerolog/log" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils" diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 7f484fc69f..6fbf929e47 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -11,13 +11,13 @@ import ( "github.com/stretchr/testify/require" - env_client "github.com/smartcontractkit/chainlink-env/client" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/cdk8s/blockscout" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + env_client "github.com/smartcontractkit/chainlink-testing-framework/k8s/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 8697044aa7..a3d4e37406 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -11,13 +11,13 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/chaos" - "github.com/smartcontractkit/chainlink-env/environment" - a "github.com/smartcontractkit/chainlink-env/pkg/alias" - "github.com/smartcontractkit/chainlink-env/pkg/cdk8s/blockscout" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index cbab1bf9e7..0beccadddd 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -10,12 +10,12 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/chaos" - "github.com/smartcontractkit/chainlink-env/environment" - a "github.com/smartcontractkit/chainlink-env/pkg/alias" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 0d72e3932e..b65f8bb74f 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -11,15 +11,15 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/chaos" - "github.com/smartcontractkit/chainlink-env/environment" - a "github.com/smartcontractkit/chainlink-env/pkg/alias" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" @@ -75,7 +75,7 @@ func TestOCRChaos(t *testing.T) { // and chaos.NewNetworkPartition method (https://chaos-mesh.org/docs/simulate-network-chaos-on-kubernetes/) // in order to regenerate Go bindings if k8s version will be updated // you can pull new CRD spec from your current cluster and check README here - // https://github.com/smartcontractkit/chainlink-env/blob/master/README.md + // https://github.com/smartcontractkit/chainlink-testing-framework/k8s/blob/master/README.md NetworkChaosFailMajorityNetwork: { ethereum.New(nil), chainlink.New(0, defaultOCRSettings), diff --git a/integration-tests/client/chainlink_config_builder.go b/integration-tests/client/chainlink_config_builder.go index 9c1050300b..13cc1e7fe9 100644 --- a/integration-tests/client/chainlink_config_builder.go +++ b/integration-tests/client/chainlink_config_builder.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "github.com/smartcontractkit/chainlink-env/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" ) const ( diff --git a/integration-tests/client/chainlink_k8s.go b/integration-tests/client/chainlink_k8s.go index 4aa7c6d0fe..3fbf9eaf73 100644 --- a/integration-tests/client/chainlink_k8s.go +++ b/integration-tests/client/chainlink_k8s.go @@ -8,7 +8,7 @@ import ( "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-env/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" ) type ChainlinkK8sClient struct { diff --git a/integration-tests/go.mod b/integration-tests/go.mod index d3e09d94d7..c1a8cdb61c 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -20,8 +20,7 @@ require ( github.com/rs/zerolog v1.30.0 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-env v0.38.3 - github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231027132403-4898f11e80b6 + github.com/smartcontractkit/chainlink-testing-framework v1.18.0 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 725e05914c..77778de9d2 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2362,16 +2362,14 @@ 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.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-env v0.38.3 h1:ZtOnwkG622R0VCTxL5V09AnT/QXhlFwkGTjd0Lsfpfg= -github.com/smartcontractkit/chainlink-env v0.38.3/go.mod h1:7z4sw/hN8TxioQCLwFqQdhK3vaOV0a22Qe99z4bRUcg= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 h1:QFMxPq7AqU4qXeW7UBv0eP/mpLt2pG2QkASUyFjKoIE= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04/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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231027132403-4898f11e80b6 h1:f1nUQ/1eUTMwNbOZK0P7P6OHvTDGQSn2KE+LtwY0rXA= -github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231027132403-4898f11e80b6/go.mod h1:RWlmjwnjIGbQAnRfKwe02Ife82nNI3rZmdI0zgkfbyk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.0 h1:Ru7odxF0tq0FixJXM58rNZw0PvyQnRroqAInBAM83gs= +github.com/smartcontractkit/chainlink-testing-framework v1.18.0/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index 84a4964647..e700a66e1f 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -12,14 +12,14 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/logging" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index faaac5910d..d229f9fb3e 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -11,13 +11,13 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index df3022003e..be536450a7 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -12,13 +12,13 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index 7a2cc933de..cd9818f99d 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -12,12 +12,12 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - eth "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index 4d875022ed..e81cc91cf7 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -10,13 +10,13 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index c715641692..eeaceffaaf 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -12,10 +12,10 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index 608144eafd..697ae28ce3 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -12,11 +12,11 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/cdk8s/blockscout" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" diff --git a/integration-tests/reorg/reorg_confirmer.go b/integration-tests/reorg/reorg_confirmer.go index 6647816c97..be535d2a6d 100644 --- a/integration-tests/reorg/reorg_confirmer.go +++ b/integration-tests/reorg/reorg_confirmer.go @@ -11,11 +11,11 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-env/chaos" - "github.com/smartcontractkit/chainlink-env/environment" - a "github.com/smartcontractkit/chainlink-env/pkg/alias" - "github.com/smartcontractkit/chainlink-env/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" ) // The steps are: diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go index 74468b9253..f92becfa50 100644 --- a/integration-tests/reorg/reorg_test.go +++ b/integration-tests/reorg/reorg_test.go @@ -13,15 +13,15 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/logging" - "github.com/smartcontractkit/chainlink-env/pkg/cdk8s/blockscout" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-env/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/onsi/gomega" diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 582ca17f7b..1b33cdce76 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -11,12 +11,12 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 8c102f6fd2..0d6a77a115 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - eth "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" diff --git a/integration-tests/testsetups/don_evm_chain.go b/integration-tests/testsetups/don_evm_chain.go index 545d951580..3ade7f0d69 100644 --- a/integration-tests/testsetups/don_evm_chain.go +++ b/integration-tests/testsetups/don_evm_chain.go @@ -6,13 +6,13 @@ import ( "github.com/rs/zerolog" "github.com/stretchr/testify/require" - e "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + e "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index 466eb97fdd..f786cca9bb 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -21,8 +21,8 @@ import ( "github.com/slack-go/slack" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index c4b1fc7ab1..ee8116f3f9 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -26,13 +26,13 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - "github.com/smartcontractkit/chainlink-env/environment" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" + mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" diff --git a/integration-tests/testsetups/profile.go b/integration-tests/testsetups/profile.go index 6f978cdebe..14fe3d29ae 100644 --- a/integration-tests/testsetups/profile.go +++ b/integration-tests/testsetups/profile.go @@ -7,8 +7,8 @@ import ( . "github.com/onsi/gomega" "golang.org/x/sync/errgroup" - "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/client" diff --git a/integration-tests/testsetups/vrfv2.go b/integration-tests/testsetups/vrfv2.go index cfa26e8f27..194c7ff4e6 100644 --- a/integration-tests/testsetups/vrfv2.go +++ b/integration-tests/testsetups/vrfv2.go @@ -14,8 +14,8 @@ import ( "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" From c94240344024998e32969b24783430d8b42ab0c9 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 30 Oct 2023 12:36:30 -0400 Subject: [PATCH 031/327] MERC 1388 update telemetry module to address the multi report structure (#10827) * w * Don't warn uselessly on bid/ask missing * - Update enhancedEAmercury proto file - Fix tests * Genereate * fix foundry deps --------- Co-authored-by: george-dorin Co-authored-by: Rens Rooimans --- core/services/ocr2/delegate.go | 2 +- core/services/ocrcommon/telemetry.go | 189 +++++++--- core/services/ocrcommon/telemetry_test.go | 211 ++++++++--- .../relay/evm/mercury/v1/data_source.go | 37 +- .../relay/evm/mercury/v2/data_source.go | 46 +-- .../relay/evm/mercury/v3/data_source.go | 47 +-- .../telem/telem_enhanced_ea_mercury.pb.go | 327 +++++++++++------- .../telem/telem_enhanced_ea_mercury.proto | 33 +- tools/flakeytests/coverage.txt | 93 +++++ 9 files changed, 698 insertions(+), 287 deletions(-) create mode 100644 tools/flakeytests/coverage.txt diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index ef1ae7c588..efb6f04fd3 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -551,7 +551,7 @@ func (d *Delegate) newServicesMercury( mercuryServices, err2 := mercury.NewServices(jb, mercuryProvider, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, d.cfg.JobPipeline(), chEnhancedTelem, chain, d.mercuryORM, (mercuryutils.FeedID)(*spec.FeedID)) - if ocrcommon.ShouldCollectEnhancedTelemetryMercury(&jb) { + if ocrcommon.ShouldCollectEnhancedTelemetryMercury(jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(spec.FeedID.String(), synchronization.EnhancedEAMercury, rid.Network, rid.ChainID), lggr.Named("EnhancedTelemetryMercury")) mercuryServices = append(mercuryServices, enhancedTelemService) } diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index 5277143c8b..29d1ad92e4 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -7,7 +7,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/libocr/commontypes" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "google.golang.org/protobuf/proto" @@ -15,10 +14,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/utils" relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" ) type eaTelemetry struct { @@ -36,9 +38,15 @@ type EnhancedTelemetryData struct { } type EnhancedTelemetryMercuryData struct { - TaskRunResults pipeline.TaskRunResults - Observation relaymercuryv1.Observation - RepTimestamp ocrtypes.ReportTimestamp + V1Observation *relaymercuryv1.Observation + V2Observation *relaymercuryv2.Observation + V3Observation *relaymercuryv3.Observation + TaskRunResults pipeline.TaskRunResults + RepTimestamp ocrtypes.ReportTimestamp + FeedVersion mercuryutils.FeedVersion + FetchMaxFinalizedTimestamp bool + IsLinkFeed bool + IsNativeFeed bool } type EnhancedTelemetryService[T EnhancedTelemetryData | EnhancedTelemetryMercuryData] struct { @@ -69,13 +77,13 @@ func (e *EnhancedTelemetryService[T]) Start(context.Context) error { for { select { case t := <-e.chTelem: - switch any(t).(type) { + switch v := any(t).(type) { case EnhancedTelemetryData: - s := any(t).(EnhancedTelemetryData) - e.collectEATelemetry(s.TaskRunResults, s.FinalResults, s.RepTimestamp) + e.collectEATelemetry(v.TaskRunResults, v.FinalResults, v.RepTimestamp) case EnhancedTelemetryMercuryData: - s := any(t).(EnhancedTelemetryMercuryData) - e.collectMercuryEnhancedTelemetry(s.Observation, s.TaskRunResults, s.RepTimestamp) + e.collectMercuryEnhancedTelemetry(v) + default: + e.lggr.Errorf("unrecognised telemetry data type: %T", t) } case <-e.chDone: return @@ -224,14 +232,19 @@ func (e *EnhancedTelemetryService[T]) collectAndSend(trrs *pipeline.TaskRunResul continue } + if trr.Result.Error != nil { + e.lggr.Warnw(fmt.Sprintf("cannot get bridge response from bridge task, job %d, id %s", e.job.ID, trr.Task.DotID()), "err", trr.Result.Error) + continue + } bridgeRawResponse, ok := trr.Result.Value.(string) if !ok { - e.lggr.Warnf("cannot get bridge response from bridge task, job %d, id %s", e.job.ID, trr.Task.DotID()) + e.lggr.Warnf("cannot parse bridge response from bridge task, job %d, id %s: expected string, got: %v (type %T)", e.job.ID, trr.Task.DotID(), trr.Result.Value, trr.Result.Value) continue } eaTelem, err := parseEATelemetry([]byte(bridgeRawResponse)) if err != nil { e.lggr.Warnw(fmt.Sprintf("cannot parse EA telemetry, job %d, id %s", e.job.ID, trr.Task.DotID()), "err", err) + continue } value := e.getParsedValue(trrs, trr) @@ -254,7 +267,7 @@ func (e *EnhancedTelemetryService[T]) collectAndSend(trrs *pipeline.TaskRunResul bytes, err := proto.Marshal(t) if err != nil { - e.lggr.Warnf("protobuf marshal failed %v", err.Error()) + e.lggr.Warnw("protobuf marshal failed", "err", err) continue } @@ -264,14 +277,81 @@ func (e *EnhancedTelemetryService[T]) collectAndSend(trrs *pipeline.TaskRunResul // collectMercuryEnhancedTelemetry checks if enhanced telemetry should be collected, fetches the information needed and // sends the telemetry -func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(obs relaymercuryv1.Observation, trrs pipeline.TaskRunResults, repts ocrtypes.ReportTimestamp) { +func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(d EnhancedTelemetryMercuryData) { if e.monitoringEndpoint == nil { return } - obsBenchmarkPrice, obsBid, obsAsk, obsBlockNum, obsBlockHash, obsBlockTimestamp := e.getFinalValues(obs) + // v1 fields + var bn int64 + var bh string + var bt uint64 + // v1+v2+v3 fields + bp := big.NewInt(0) + //v1+v3 fields + bid := big.NewInt(0) + ask := big.NewInt(0) + // v2+v3 fields + var mfts, lp, np int64 + + switch { + case d.V1Observation != nil: + obs := *d.V1Observation + if obs.CurrentBlockNum.Err == nil { + bn = obs.CurrentBlockNum.Val + } + if obs.CurrentBlockHash.Err == nil { + bh = common.BytesToHash(obs.CurrentBlockHash.Val).Hex() + } + if obs.CurrentBlockTimestamp.Err == nil { + bt = obs.CurrentBlockTimestamp.Val + } + if obs.BenchmarkPrice.Err == nil && obs.BenchmarkPrice.Val != nil { + bp = obs.BenchmarkPrice.Val + } + if obs.Bid.Err == nil && obs.Bid.Val != nil { + bid = obs.Bid.Val + } + if obs.Ask.Err == nil && obs.Ask.Val != nil { + ask = obs.Ask.Val + } + case d.V2Observation != nil: + obs := *d.V2Observation + if obs.MaxFinalizedTimestamp.Err == nil { + mfts = obs.MaxFinalizedTimestamp.Val + } + if obs.LinkPrice.Err == nil && obs.LinkPrice.Val != nil { + lp = obs.LinkPrice.Val.Int64() + } + if obs.NativePrice.Err == nil && obs.NativePrice.Val != nil { + np = obs.NativePrice.Val.Int64() + } + if obs.BenchmarkPrice.Err == nil && obs.BenchmarkPrice.Val != nil { + bp = obs.BenchmarkPrice.Val + } + case d.V3Observation != nil: + obs := *d.V3Observation + if obs.MaxFinalizedTimestamp.Err == nil { + mfts = obs.MaxFinalizedTimestamp.Val + } + if obs.LinkPrice.Err == nil && obs.LinkPrice.Val != nil { + lp = obs.LinkPrice.Val.Int64() + } + if obs.NativePrice.Err == nil && obs.NativePrice.Val != nil { + np = obs.NativePrice.Val.Int64() + } + if obs.BenchmarkPrice.Err == nil && obs.BenchmarkPrice.Val != nil { + bp = obs.BenchmarkPrice.Val + } + if obs.Bid.Err == nil && obs.Bid.Val != nil { + bid = obs.Bid.Val + } + if obs.Ask.Err == nil && obs.Ask.Val != nil { + ask = obs.Ask.Val + } + } - for _, trr := range trrs { + for _, trr := range d.TaskRunResults { if trr.Task.Type() != pipeline.TaskTypeBridge { continue } @@ -288,16 +368,19 @@ func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(obs relaym } assetSymbol := e.getAssetSymbolFromRequestData(bridgeTask.RequestData) - benchmarkPrice, bidPrice, askPrice := e.getPricesFromResults(trr, &trrs) + + benchmarkPrice, bidPrice, askPrice := e.getPricesFromResults(trr, d.TaskRunResults, d.FeedVersion) t := &telem.EnhancedEAMercury{ DataSource: eaTelem.DataSource, DpBenchmarkPrice: benchmarkPrice, DpBid: bidPrice, DpAsk: askPrice, - CurrentBlockNumber: obsBlockNum, - CurrentBlockHash: common.BytesToHash(obsBlockHash).String(), - CurrentBlockTimestamp: obsBlockTimestamp, + CurrentBlockNumber: bn, + CurrentBlockHash: bh, + CurrentBlockTimestamp: bt, + FetchMaxFinalizedTimestamp: d.FetchMaxFinalizedTimestamp, + MaxFinalizedTimestamp: mfts, BridgeTaskRunStartedTimestamp: trr.CreatedAt.UnixMilli(), BridgeTaskRunEndedTimestamp: trr.FinishedAt.Time.UnixMilli(), ProviderRequestedTimestamp: eaTelem.ProviderRequestedTimestamp, @@ -305,16 +388,21 @@ func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(obs relaym ProviderDataStreamEstablished: eaTelem.ProviderDataStreamEstablished, ProviderIndicatedTime: eaTelem.ProviderIndicatedTime, Feed: e.job.OCR2OracleSpec.FeedID.Hex(), - ObservationBenchmarkPrice: obsBenchmarkPrice.Int64(), //Deprecated: observation value will not fit in int64, we will use the string equivalent field ObservationBenchmarkPriceString - ObservationBid: obsBid.Int64(), //Deprecated: observation value will not fit in int64, we will use the string equivalent field ObservationBidString - ObservationAsk: obsAsk.Int64(), //Deprecated: observation value will not fit in int64, we will use the string equivalent field ObservationAskString - ConfigDigest: repts.ConfigDigest.Hex(), - Round: int64(repts.Round), - Epoch: int64(repts.Epoch), + ObservationBenchmarkPrice: bp.Int64(), + ObservationBid: bid.Int64(), + ObservationAsk: ask.Int64(), + ObservationBenchmarkPriceString: stringOrEmpty(bp), + ObservationBidString: stringOrEmpty(bid), + ObservationAskString: stringOrEmpty(ask), + IsLinkFeed: d.IsLinkFeed, + LinkPrice: lp, + IsNativeFeed: d.IsNativeFeed, + NativePrice: np, + ConfigDigest: d.RepTimestamp.ConfigDigest.Hex(), + Round: int64(d.RepTimestamp.Round), + Epoch: int64(d.RepTimestamp.Epoch), AssetSymbol: assetSymbol, - ObservationBenchmarkPriceString: obsBenchmarkPrice.String(), - ObservationBidString: obsBid.String(), - ObservationAskString: obsAsk.String(), + Version: uint32(d.FeedVersion), } bytes, err := proto.Marshal(t) @@ -347,19 +435,19 @@ func (e *EnhancedTelemetryService[T]) getAssetSymbolFromRequestData(requestData } // ShouldCollectEnhancedTelemetryMercury checks if enhanced telemetry should be collected and sent -func ShouldCollectEnhancedTelemetryMercury(job *job.Job) bool { - if job.Type.String() == pipeline.OffchainReporting2JobType && job.OCR2OracleSpec != nil { - return job.OCR2OracleSpec.CaptureEATelemetry +func ShouldCollectEnhancedTelemetryMercury(jb job.Job) bool { + if jb.Type.String() == pipeline.OffchainReporting2JobType && jb.OCR2OracleSpec != nil { + return jb.OCR2OracleSpec.CaptureEATelemetry } return false } // getPricesFromResults parses the pipeline.TaskRunResults for pipeline.TaskTypeJSONParse and gets the benchmarkPrice, // bid and ask. This functions expects the pipeline.TaskRunResults to be correctly ordered -func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.TaskRunResult, allTasks *pipeline.TaskRunResults) (float64, float64, float64) { +func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.TaskRunResult, allTasks pipeline.TaskRunResults, mercuryVersion mercuryutils.FeedVersion) (float64, float64, float64) { var benchmarkPrice, askPrice, bidPrice float64 var err error - //We rely on task results to be sorted in the correct order + // We rely on task results to be sorted in the correct order benchmarkPriceTask := allTasks.GetNextTaskOf(startTask) if benchmarkPriceTask == nil { e.lggr.Warnf("cannot parse enhanced EA telemetry benchmark price, task is nil, job %d, id %s", e.job.ID) @@ -376,12 +464,18 @@ func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.Ta } } + // mercury version 2 only supports benchmarkPrice + if mercuryVersion == 2 { + return benchmarkPrice, 0, 0 + } + bidTask := allTasks.GetNextTaskOf(*benchmarkPriceTask) if bidTask == nil { e.lggr.Warnf("cannot parse enhanced EA telemetry bid price, task is nil, job %d, id %s", e.job.ID) return benchmarkPrice, 0, 0 } - if bidTask.Task.Type() == pipeline.TaskTypeJSONParse { + + if bidTask != nil && bidTask.Task.Type() == pipeline.TaskTypeJSONParse { if bidTask.Result.Error != nil { e.lggr.Warnw(fmt.Sprintf("got error for enhanced EA telemetry bid price, job %d, id %s: %s", e.job.ID, bidTask.Task.DotID(), bidTask.Result.Error), "err", bidTask.Result.Error) } else { @@ -397,7 +491,7 @@ func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.Ta e.lggr.Warnf("cannot parse enhanced EA telemetry ask price, task is nil, job %d, id %s", e.job.ID) return benchmarkPrice, bidPrice, 0 } - if askTask.Task.Type() == pipeline.TaskTypeJSONParse { + if askTask != nil && askTask.Task.Type() == pipeline.TaskTypeJSONParse { if bidTask.Result.Error != nil { e.lggr.Warnw(fmt.Sprintf("got error for enhanced EA telemetry ask price, job %d, id %s: %s", e.job.ID, askTask.Task.DotID(), askTask.Result.Error), "err", askTask.Result.Error) } else { @@ -411,23 +505,11 @@ func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.Ta return benchmarkPrice, bidPrice, askPrice } -// getFinalValues runs a parse on the pipeline.TaskRunResults and returns the values -func (e *EnhancedTelemetryService[T]) getFinalValues(obs relaymercuryv1.Observation) (*big.Int, *big.Int, *big.Int, int64, []byte, uint64) { - benchmarkPrice := big.NewInt(0) - bid := big.NewInt(0) - ask := big.NewInt(0) - - if obs.BenchmarkPrice.Val != nil { - benchmarkPrice = obs.BenchmarkPrice.Val - } - if obs.Bid.Val != nil { - bid = obs.Bid.Val - } - if obs.Ask.Val != nil { - ask = obs.Ask.Val +// MaybeEnqueueEnhancedTelem sends data to the telemetry channel for processing +func MaybeEnqueueEnhancedTelem(jb job.Job, ch chan<- EnhancedTelemetryMercuryData, data EnhancedTelemetryMercuryData) { + if ShouldCollectEnhancedTelemetryMercury(jb) { + EnqueueEnhancedTelem[EnhancedTelemetryMercuryData](ch, data) } - - return benchmarkPrice, bid, ask, obs.CurrentBlockNum.Val, obs.CurrentBlockHash.Val, obs.CurrentBlockTimestamp.Val } // EnqueueEnhancedTelem sends data to the telemetry channel for processing @@ -447,3 +529,10 @@ func getResultFloat64(task *pipeline.TaskRunResult) (float64, error) { resultFloat64, _ := result.Float64() return resultFloat64, nil } + +func stringOrEmpty(n *big.Int) string { + if n.Cmp(big.NewInt(0)) == 0 { + return "" + } + return n.String() +} diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index 5d1494a038..e6a798780b 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" mercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + mercury_v2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -361,7 +362,7 @@ func TestCollectAndSend(t *testing.T) { wg.Wait() assert.Equal(t, logs.Len(), 2) - assert.Contains(t, logs.All()[0].Message, "cannot get bridge response from bridge task") + assert.Contains(t, logs.All()[0].Message, "cannot parse bridge response from bridge task") badTrrs = &pipeline.TaskRunResults{ pipeline.TaskRunResult{ @@ -372,20 +373,19 @@ func TestCollectAndSend(t *testing.T) { Value: "[]", }, }} - wg.Add(1) enhancedTelemChan <- EnhancedTelemetryData{ TaskRunResults: *badTrrs, FinalResults: *finalResult, RepTimestamp: observationTimestamp, } wg.Wait() - assert.Equal(t, logs.Len(), 4) - assert.Contains(t, logs.All()[2].Message, "cannot parse EA telemetry") - assert.Contains(t, logs.All()[3].Message, "cannot get json parse value") + assert.Equal(t, 2, logs.Len()) + assert.Contains(t, logs.All()[0].Message, "cannot parse bridge response from bridge task") + assert.Contains(t, logs.All()[1].Message, "cannot get json parse value") doneCh <- struct{}{} } -var trrsMercury = pipeline.TaskRunResults{ +var trrsMercuryV1 = pipeline.TaskRunResults{ pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), @@ -421,32 +421,24 @@ var trrsMercury = pipeline.TaskRunResults{ }, } -func TestGetFinalValues(t *testing.T) { - e := EnhancedTelemetryService[EnhancedTelemetryMercuryData]{} - o := mercuryv1.Observation{ - BenchmarkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(111111)}, - Bid: mercury.ObsResult[*big.Int]{Val: big.NewInt(222222)}, - Ask: mercury.ObsResult[*big.Int]{Val: big.NewInt(333333)}, - CurrentBlockNum: mercury.ObsResult[int64]{Val: 123456789}, - CurrentBlockHash: mercury.ObsResult[[]byte]{Val: common.HexToHash("0x123321").Bytes()}, - CurrentBlockTimestamp: mercury.ObsResult[uint64]{Val: 987654321}, - } - - benchmarkPrice, bid, ask, blockNr, blockHash, blockTimestamp := e.getFinalValues(o) - require.Equal(t, benchmarkPrice, big.NewInt(111111)) - require.Equal(t, bid, big.NewInt(222222)) - require.Equal(t, ask, big.NewInt(333333)) - require.Equal(t, blockNr, int64(123456789)) - require.Equal(t, blockHash, common.HexToHash("0x123321").Bytes()) - require.Equal(t, blockTimestamp, uint64(987654321)) - - benchmarkPrice, bid, ask, blockNr, blockHash, blockTimestamp = e.getFinalValues(mercuryv1.Observation{}) - require.Equal(t, benchmarkPrice, big.NewInt(0)) - require.Equal(t, bid, big.NewInt(0)) - require.Equal(t, ask, big.NewInt(0)) - require.Equal(t, blockNr, int64(0)) - require.Nil(t, blockHash) - require.Equal(t, blockTimestamp, uint64(0)) +var trrsMercuryV2 = pipeline.TaskRunResults{ + pipeline.TaskRunResult{ + Task: &pipeline.BridgeTask{ + BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), + RequestData: `{"data":{"to":"LINK","from":"USD"}}`, + }, + Result: pipeline.Result{ + Value: bridgeResponse, + }, + }, + pipeline.TaskRunResult{ + Task: &pipeline.JSONParseTask{ + BaseTask: pipeline.NewBaseTask(1, "ds1_benchmark", nil, nil, 1), + }, + Result: pipeline.Result{ + Value: float64(123456.123456), + }, + }, } func TestGetPricesFromResults(t *testing.T) { @@ -458,25 +450,25 @@ func TestGetPricesFromResults(t *testing.T) { }, } - benchmarkPrice, bid, ask := e.getPricesFromResults(trrsMercury[0], &trrsMercury) + benchmarkPrice, bid, ask := e.getPricesFromResults(trrsMercuryV1[0], trrsMercuryV1, 1) require.Equal(t, 123456.123456, benchmarkPrice) require.Equal(t, 1234567.1234567, bid) require.Equal(t, float64(321123), ask) - benchmarkPrice, bid, ask = e.getPricesFromResults(trrsMercury[0], &pipeline.TaskRunResults{}) + benchmarkPrice, bid, ask = e.getPricesFromResults(trrsMercuryV1[0], pipeline.TaskRunResults{}, 1) require.Equal(t, float64(0), benchmarkPrice) require.Equal(t, float64(0), bid) require.Equal(t, float64(0), ask) require.Equal(t, 1, logs.Len()) require.Contains(t, logs.All()[0].Message, "cannot parse enhanced EA telemetry") - tt := trrsMercury[:2] - e.getPricesFromResults(trrsMercury[0], &tt) + tt := trrsMercuryV1[:2] + e.getPricesFromResults(trrsMercuryV1[0], tt, 1) require.Equal(t, 2, logs.Len()) require.Contains(t, logs.All()[1].Message, "cannot parse enhanced EA telemetry bid price, task is nil") - tt = trrsMercury[:3] - e.getPricesFromResults(trrsMercury[0], &tt) + tt = trrsMercuryV1[:3] + e.getPricesFromResults(trrsMercuryV1[0], tt, 1) require.Equal(t, 3, logs.Len()) require.Contains(t, logs.All()[2].Message, "cannot parse enhanced EA telemetry ask price, task is nil") @@ -513,7 +505,7 @@ func TestGetPricesFromResults(t *testing.T) { Value: nil, }, }} - benchmarkPrice, bid, ask = e.getPricesFromResults(trrsMercury[0], &trrs2) + benchmarkPrice, bid, ask = e.getPricesFromResults(trrsMercuryV1[0], trrs2, 3) require.Equal(t, benchmarkPrice, float64(0)) require.Equal(t, bid, float64(0)) require.Equal(t, ask, float64(0)) @@ -521,11 +513,16 @@ func TestGetPricesFromResults(t *testing.T) { require.Contains(t, logs.All()[3].Message, "cannot parse enhanced EA telemetry benchmark price") require.Contains(t, logs.All()[4].Message, "cannot parse enhanced EA telemetry bid price") require.Contains(t, logs.All()[5].Message, "cannot parse enhanced EA telemetry ask price") + + benchmarkPrice, bid, ask = e.getPricesFromResults(trrsMercuryV1[0], trrsMercuryV2, 2) + require.Equal(t, 123456.123456, benchmarkPrice) + require.Equal(t, float64(0), bid) + require.Equal(t, float64(0), ask) } func TestShouldCollectEnhancedTelemetryMercury(t *testing.T) { - j := &job.Job{ + j := job.Job{ Type: job.Type(pipeline.OffchainReporting2JobType), OCR2OracleSpec: &job.OCR2OracleSpec{ CaptureEATelemetry: true, @@ -547,7 +544,7 @@ func TestGetAssetSymbolFromRequestData(t *testing.T) { require.Equal(t, e.getAssetSymbolFromRequestData(reqData), "USD/LINK") } -func TestCollectMercuryEnhancedTelemetry(t *testing.T) { +func TestCollectMercuryEnhancedTelemetryV1(t *testing.T) { wg := sync.WaitGroup{} ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) @@ -581,8 +578,8 @@ func TestCollectMercuryEnhancedTelemetry(t *testing.T) { wg.Add(1) chTelem <- EnhancedTelemetryMercuryData{ - TaskRunResults: trrsMercury, - Observation: mercuryv1.Observation{ + TaskRunResults: trrsMercuryV1, + V1Observation: &mercuryv1.Observation{ BenchmarkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(111111)}, Bid: mercury.ObsResult[*big.Int]{Val: big.NewInt(222222)}, Ask: mercury.ObsResult[*big.Int]{Val: big.NewInt(333333)}, @@ -605,8 +602,8 @@ func TestCollectMercuryEnhancedTelemetry(t *testing.T) { CurrentBlockNumber: 123456789, CurrentBlockHash: common.HexToHash("0x123321").String(), CurrentBlockTimestamp: 987654321, - BridgeTaskRunStartedTimestamp: trrsMercury[0].CreatedAt.UnixMilli(), - BridgeTaskRunEndedTimestamp: trrsMercury[0].FinishedAt.Time.UnixMilli(), + BridgeTaskRunStartedTimestamp: trrsMercuryV1[0].CreatedAt.UnixMilli(), + BridgeTaskRunEndedTimestamp: trrsMercuryV1[0].FinishedAt.Time.UnixMilli(), ProviderRequestedTimestamp: 92233720368547760, ProviderReceivedTimestamp: -92233720368547760, ProviderDataStreamEstablished: 1, @@ -637,7 +634,7 @@ func TestCollectMercuryEnhancedTelemetry(t *testing.T) { Value: nil, }}, }, - Observation: mercuryv1.Observation{}, + V1Observation: &mercuryv1.Observation{}, RepTimestamp: types.ReportTimestamp{ ConfigDigest: types.ConfigDigest{2}, Epoch: 11, @@ -645,10 +642,10 @@ func TestCollectMercuryEnhancedTelemetry(t *testing.T) { }, } wg.Add(1) - trrsMercury[0].Result.Value = "" + trrsMercuryV1[0].Result.Value = "" chTelem <- EnhancedTelemetryMercuryData{ - TaskRunResults: trrsMercury, - Observation: mercuryv1.Observation{}, + TaskRunResults: trrsMercuryV1, + V1Observation: &mercuryv1.Observation{}, RepTimestamp: types.ReportTimestamp{ ConfigDigest: types.ConfigDigest{2}, Epoch: 11, @@ -662,3 +659,119 @@ func TestCollectMercuryEnhancedTelemetry(t *testing.T) { require.Contains(t, logs.All()[1].Message, "cannot parse EA telemetry") chDone <- struct{}{} } + +func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { + wg := sync.WaitGroup{} + ingressClient := mocks.NewTelemetryService(t) + ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEAMercury, "test-network", "test-chainID") + + var sentMessage []byte + ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + sentMessage = args[1].([]byte) + wg.Done() + }) + + lggr, logs := logger.TestLoggerObserved(t, zap.WarnLevel) + chTelem := make(chan EnhancedTelemetryMercuryData, 100) + chDone := make(chan struct{}) + feedID := common.HexToHash("0x111") + e := EnhancedTelemetryService[EnhancedTelemetryMercuryData]{ + chDone: chDone, + chTelem: chTelem, + job: &job.Job{ + Type: job.Type(pipeline.OffchainReporting2JobType), + OCR2OracleSpec: &job.OCR2OracleSpec{ + CaptureEATelemetry: true, + FeedID: &feedID, + }, + }, + lggr: lggr, + monitoringEndpoint: monitoringEndpoint, + } + require.NoError(t, e.Start(testutils.Context(t))) + + wg.Add(1) + + chTelem <- EnhancedTelemetryMercuryData{ + TaskRunResults: trrsMercuryV2, + V2Observation: &mercury_v2.Observation{ + BenchmarkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(111111)}, + MaxFinalizedTimestamp: mercury.ObsResult[int64]{Val: 321}, + LinkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(4321)}, + NativePrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(54321)}, + }, + RepTimestamp: types.ReportTimestamp{ + ConfigDigest: types.ConfigDigest{2}, + Epoch: 11, + Round: 22, + }, + } + + expectedTelemetry := telem.EnhancedEAMercury{ + DataSource: "data-source-name", + DpBenchmarkPrice: 123456.123456, + CurrentBlockNumber: 0, + CurrentBlockHash: "", + CurrentBlockTimestamp: 0, + BridgeTaskRunStartedTimestamp: trrsMercuryV1[0].CreatedAt.UnixMilli(), + BridgeTaskRunEndedTimestamp: trrsMercuryV1[0].FinishedAt.Time.UnixMilli(), + ProviderRequestedTimestamp: 92233720368547760, + ProviderReceivedTimestamp: -92233720368547760, + ProviderDataStreamEstablished: 1, + ProviderIndicatedTime: -123456789, + Feed: common.HexToHash("0x111").String(), + ObservationBenchmarkPrice: 111111, + ObservationBid: 0, + ObservationAsk: 0, + ConfigDigest: "0200000000000000000000000000000000000000000000000000000000000000", + Round: 22, + Epoch: 11, + AssetSymbol: "USD/LINK", + ObservationBenchmarkPriceString: "111111", + MaxFinalizedTimestamp: 321, + LinkPrice: 4321, + NativePrice: 54321, + } + + expectedMessage, _ := proto.Marshal(&expectedTelemetry) + wg.Wait() + + require.Equal(t, expectedMessage, sentMessage) + + chTelem <- EnhancedTelemetryMercuryData{ + TaskRunResults: pipeline.TaskRunResults{ + pipeline.TaskRunResult{Task: &pipeline.BridgeTask{ + BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), + }, + Result: pipeline.Result{ + Value: nil, + }}, + }, + V2Observation: &mercury_v2.Observation{}, + RepTimestamp: types.ReportTimestamp{ + ConfigDigest: types.ConfigDigest{2}, + Epoch: 11, + Round: 22, + }, + } + wg.Add(1) + trrsMercuryV2[0].Result.Value = "" + chTelem <- EnhancedTelemetryMercuryData{ + TaskRunResults: trrsMercuryV2, + V2Observation: &mercury_v2.Observation{}, + RepTimestamp: types.ReportTimestamp{ + ConfigDigest: types.ConfigDigest{2}, + Epoch: 11, + Round: 22, + }, + } + + wg.Wait() + require.Equal(t, 4, logs.Len()) + require.Contains(t, logs.All()[0].Message, "cannot parse enhanced EA telemetry bid price") + require.Contains(t, logs.All()[1].Message, "cannot get bridge response from bridge task") + require.Contains(t, logs.All()[2].Message, "cannot parse EA telemetry") + require.Contains(t, logs.All()[3].Message, "cannot parse enhanced EA telemetry bid price") + chDone <- struct{}{} +} diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index 5c1f55ddab..d225dbee68 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -13,14 +13,14 @@ import ( relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -59,7 +59,7 @@ func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec return &datasource{pr, jb, spec, lggr, rr, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainHeadTracker, fetcher, initialBlockNumber} } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs relaymercuryv1.Observation, err error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs relaymercuryv1.Observation, pipelineExecutionErr error) { // setCurrentBlock must come first, along with observationTimestamp, to // avoid front-running ds.setCurrentBlock(ctx, &obs) @@ -116,9 +116,9 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam go func() { defer wg.Done() var run *pipeline.Run - run, trrs, err = ds.executeRun(ctx) - if err != nil { - err = fmt.Errorf("Observe failed while executing run: %w", err) + run, trrs, pipelineExecutionErr = ds.executeRun(ctx) + if pipelineExecutionErr != nil { + pipelineExecutionErr = fmt.Errorf("Observe failed while executing run: %w", pipelineExecutionErr) return } select { @@ -137,27 +137,30 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam } var parsed parseOutput - parsed, err = ds.parse(finaltrrs) - if err != nil { - err = fmt.Errorf("Observe failed while parsing run results: %w", err) + parsed, pipelineExecutionErr = ds.parse(finaltrrs) + if pipelineExecutionErr != nil { + pipelineExecutionErr = fmt.Errorf("Observe failed while parsing run results: %w", pipelineExecutionErr) return } obs.BenchmarkPrice = parsed.benchmarkPrice obs.Bid = parsed.bid obs.Ask = parsed.ask }() - wg.Wait() - if ocrcommon.ShouldCollectEnhancedTelemetryMercury(&ds.jb) { - ocrcommon.EnqueueEnhancedTelem(ds.chEnhancedTelem, ocrcommon.EnhancedTelemetryMercuryData{ - TaskRunResults: trrs, - Observation: obs, - RepTimestamp: repts, - }) + wg.Wait() + if pipelineExecutionErr != nil { + return } - return obs, err + ocrcommon.MaybeEnqueueEnhancedTelem(ds.jb, ds.chEnhancedTelem, ocrcommon.EnhancedTelemetryMercuryData{ + V1Observation: &obs, + TaskRunResults: trrs, + RepTimestamp: repts, + FeedVersion: mercuryutils.REPORT_V1, + }) + + return obs, nil } func toBigInt(val interface{}) (*big.Int, error) { diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index 10c8839a3c..17bc4a6670 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -58,7 +58,7 @@ func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec return &datasource{pr, jb, spec, feedID, lggr, rr, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv2.Observation, err error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv2.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup ctx, cancel := context.WithCancel(ctx) @@ -80,15 +80,15 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() } + var trrs pipeline.TaskRunResults wg.Add(1) go func() { defer wg.Done() - var trrs pipeline.TaskRunResults var run *pipeline.Run - run, trrs, err = ds.executeRun(ctx) - if err != nil { + run, trrs, pipelineExecutionErr = ds.executeRun(ctx) + if pipelineExecutionErr != nil { cancel() - err = fmt.Errorf("Observe failed while executing run: %w", err) + pipelineExecutionErr = fmt.Errorf("Observe failed while executing run: %w", pipelineExecutionErr) return } select { @@ -98,12 +98,12 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam } var parsed parseOutput - parsed, err = ds.parse(trrs) - if err != nil { + parsed, pipelineExecutionErr = ds.parse(trrs) + if pipelineExecutionErr != nil { cancel() // This is not expected under normal circumstances - ds.lggr.Errorw("Observe failed while parsing run results", "err", err) - err = fmt.Errorf("Observe failed while parsing run results: %w", err) + ds.lggr.Errorw("Observe failed while parsing run results", "err", pipelineExecutionErr) + pipelineExecutionErr = fmt.Errorf("Observe failed while parsing run results: %w", pipelineExecutionErr) return } obs.BenchmarkPrice = parsed.benchmarkPrice @@ -149,11 +149,12 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam wg.Wait() cancel() + if pipelineExecutionErr != nil { + return + } + if isLink || isNative { - // run has now completed so it is safe to use err or benchmark price - if err != nil { - return - } + // run has now completed so it is safe to use benchmark price if isLink { // This IS the LINK feed, use our observed price obs.LinkPrice.Val, obs.LinkPrice.Err = obs.BenchmarkPrice.Val, obs.BenchmarkPrice.Err @@ -164,16 +165,17 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam } } - // todo: implement telemetry - https://smartcontract-it.atlassian.net/browse/MERC-1388 - // if ocrcommon.ShouldCollectEnhancedTelemetryMercury(&ds.jb) { - // ocrcommon.EnqueueEnhancedTelem(ds.chEnhancedTelem, ocrcommon.EnhancedTelemetryMercuryData{ - // TaskRunResults: trrs, - // Observation: obs, - // RepTimestamp: repts, - // }) - // } + ocrcommon.MaybeEnqueueEnhancedTelem(ds.jb, ds.chEnhancedTelem, ocrcommon.EnhancedTelemetryMercuryData{ + V2Observation: &obs, + TaskRunResults: trrs, + RepTimestamp: repts, + FeedVersion: mercuryutils.REPORT_V2, + FetchMaxFinalizedTimestamp: fetchMaxFinalizedTimestamp, + IsLinkFeed: isLink, + IsNativeFeed: isNative, + }) - return obs, err + return obs, nil } func toBigInt(val interface{}) (*big.Int, error) { diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index 4eadfc35c2..6f2b2eb6bd 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -59,7 +59,7 @@ func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec return &datasource{pr, jb, spec, feedID, lggr, rr, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv3.Observation, err error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv3.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup ctx, cancel := context.WithCancel(ctx) @@ -81,15 +81,15 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() } + var trrs pipeline.TaskRunResults wg.Add(1) go func() { defer wg.Done() - var trrs pipeline.TaskRunResults var run *pipeline.Run - run, trrs, err = ds.executeRun(ctx) - if err != nil { + run, trrs, pipelineExecutionErr = ds.executeRun(ctx) + if pipelineExecutionErr != nil { cancel() - err = fmt.Errorf("Observe failed while executing run: %w", err) + pipelineExecutionErr = fmt.Errorf("Observe failed while executing run: %w", pipelineExecutionErr) return } select { @@ -99,12 +99,12 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam } var parsed parseOutput - parsed, err = ds.parse(trrs) - if err != nil { + parsed, pipelineExecutionErr = ds.parse(trrs) + if pipelineExecutionErr != nil { cancel() // This is not expected under normal circumstances - ds.lggr.Errorw("Observe failed while parsing run results", "err", err) - err = fmt.Errorf("Observe failed while parsing run results: %w", err) + ds.lggr.Errorw("Observe failed while parsing run results", "err", pipelineExecutionErr) + pipelineExecutionErr = fmt.Errorf("Observe failed while parsing run results: %w", pipelineExecutionErr) return } obs.BenchmarkPrice = parsed.benchmarkPrice @@ -152,11 +152,12 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam wg.Wait() cancel() + if pipelineExecutionErr != nil { + return + } + if isLink || isNative { - // run has now completed so it is safe to use err or benchmark price - if err != nil { - return - } + // run has now completed so it is safe to use benchmark price if isLink { // This IS the LINK feed, use our observed price obs.LinkPrice.Val, obs.LinkPrice.Err = obs.BenchmarkPrice.Val, obs.BenchmarkPrice.Err @@ -167,17 +168,17 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam } } - // todo: implement telemetry https://smartcontract-it.atlassian.net/browse/MERC-1388 - // if ocrcommon.ShouldCollectEnhancedTelemetryMercury(&ds.jb) { - // ocrcommon.EnqueueEnhancedTelem(ds.chEnhancedTelem, ocrcommon.EnhancedTelemetryMercuryData{ - // TaskRunResults: trrs, - // Observation: obs, - // RepTimestamp: repts, - // }) - // } + ocrcommon.MaybeEnqueueEnhancedTelem(ds.jb, ds.chEnhancedTelem, ocrcommon.EnhancedTelemetryMercuryData{ + V3Observation: &obs, + TaskRunResults: trrs, + RepTimestamp: repts, + FeedVersion: mercuryutils.REPORT_V3, + FetchMaxFinalizedTimestamp: fetchMaxFinalizedTimestamp, + IsLinkFeed: isLink, + IsNativeFeed: isNative, + }) - cancel() - return obs, err + return obs, nil } func toBigInt(val interface{}) (*big.Int, error) { diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go index 32c3061cc4..9cda6ef99a 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go @@ -25,30 +25,42 @@ type EnhancedEAMercury struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DataSource string `protobuf:"bytes,1,opt,name=data_source,json=dataSource,proto3" json:"data_source,omitempty"` - DpBenchmarkPrice float64 `protobuf:"fixed64,2,opt,name=dp_benchmark_price,json=dpBenchmarkPrice,proto3" json:"dp_benchmark_price,omitempty"` - DpBid float64 `protobuf:"fixed64,3,opt,name=dp_bid,json=dpBid,proto3" json:"dp_bid,omitempty"` - DpAsk float64 `protobuf:"fixed64,4,opt,name=dp_ask,json=dpAsk,proto3" json:"dp_ask,omitempty"` - CurrentBlockNumber int64 `protobuf:"varint,5,opt,name=current_block_number,json=currentBlockNumber,proto3" json:"current_block_number,omitempty"` - CurrentBlockHash string `protobuf:"bytes,6,opt,name=current_block_hash,json=currentBlockHash,proto3" json:"current_block_hash,omitempty"` - CurrentBlockTimestamp uint64 `protobuf:"varint,7,opt,name=current_block_timestamp,json=currentBlockTimestamp,proto3" json:"current_block_timestamp,omitempty"` - BridgeTaskRunStartedTimestamp int64 `protobuf:"varint,8,opt,name=bridge_task_run_started_timestamp,json=bridgeTaskRunStartedTimestamp,proto3" json:"bridge_task_run_started_timestamp,omitempty"` - BridgeTaskRunEndedTimestamp int64 `protobuf:"varint,9,opt,name=bridge_task_run_ended_timestamp,json=bridgeTaskRunEndedTimestamp,proto3" json:"bridge_task_run_ended_timestamp,omitempty"` - ProviderRequestedTimestamp int64 `protobuf:"varint,10,opt,name=provider_requested_timestamp,json=providerRequestedTimestamp,proto3" json:"provider_requested_timestamp,omitempty"` - ProviderReceivedTimestamp int64 `protobuf:"varint,11,opt,name=provider_received_timestamp,json=providerReceivedTimestamp,proto3" json:"provider_received_timestamp,omitempty"` - ProviderDataStreamEstablished int64 `protobuf:"varint,12,opt,name=provider_data_stream_established,json=providerDataStreamEstablished,proto3" json:"provider_data_stream_established,omitempty"` - ProviderIndicatedTime int64 `protobuf:"varint,13,opt,name=provider_indicated_time,json=providerIndicatedTime,proto3" json:"provider_indicated_time,omitempty"` - Feed string `protobuf:"bytes,14,opt,name=feed,proto3" json:"feed,omitempty"` - ObservationBenchmarkPrice int64 `protobuf:"varint,15,opt,name=observation_benchmark_price,json=observationBenchmarkPrice,proto3" json:"observation_benchmark_price,omitempty"` - ObservationBid int64 `protobuf:"varint,16,opt,name=observation_bid,json=observationBid,proto3" json:"observation_bid,omitempty"` - ObservationAsk int64 `protobuf:"varint,17,opt,name=observation_ask,json=observationAsk,proto3" json:"observation_ask,omitempty"` - ConfigDigest string `protobuf:"bytes,18,opt,name=config_digest,json=configDigest,proto3" json:"config_digest,omitempty"` - Round int64 `protobuf:"varint,19,opt,name=round,proto3" json:"round,omitempty"` - Epoch int64 `protobuf:"varint,20,opt,name=epoch,proto3" json:"epoch,omitempty"` - AssetSymbol string `protobuf:"bytes,21,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"` - ObservationBenchmarkPriceString string `protobuf:"bytes,22,opt,name=observation_benchmark_price_string,json=observationBenchmarkPriceString,proto3" json:"observation_benchmark_price_string,omitempty"` - ObservationBidString string `protobuf:"bytes,23,opt,name=observation_bid_string,json=observationBidString,proto3" json:"observation_bid_string,omitempty"` - ObservationAskString string `protobuf:"bytes,24,opt,name=observation_ask_string,json=observationAskString,proto3" json:"observation_ask_string,omitempty"` + Version uint32 `protobuf:"varint,32,opt,name=version,proto3" json:"version,omitempty"` + DataSource string `protobuf:"bytes,1,opt,name=data_source,json=dataSource,proto3" json:"data_source,omitempty"` + DpBenchmarkPrice float64 `protobuf:"fixed64,2,opt,name=dp_benchmark_price,json=dpBenchmarkPrice,proto3" json:"dp_benchmark_price,omitempty"` + DpBid float64 `protobuf:"fixed64,3,opt,name=dp_bid,json=dpBid,proto3" json:"dp_bid,omitempty"` + DpAsk float64 `protobuf:"fixed64,4,opt,name=dp_ask,json=dpAsk,proto3" json:"dp_ask,omitempty"` + // v1 fields (block range) + CurrentBlockNumber int64 `protobuf:"varint,5,opt,name=current_block_number,json=currentBlockNumber,proto3" json:"current_block_number,omitempty"` + CurrentBlockHash string `protobuf:"bytes,6,opt,name=current_block_hash,json=currentBlockHash,proto3" json:"current_block_hash,omitempty"` + CurrentBlockTimestamp uint64 `protobuf:"varint,7,opt,name=current_block_timestamp,json=currentBlockTimestamp,proto3" json:"current_block_timestamp,omitempty"` + // v2+v3 fields (timestamp range) + FetchMaxFinalizedTimestamp bool `protobuf:"varint,25,opt,name=fetch_max_finalized_timestamp,json=fetchMaxFinalizedTimestamp,proto3" json:"fetch_max_finalized_timestamp,omitempty"` + MaxFinalizedTimestamp int64 `protobuf:"varint,26,opt,name=max_finalized_timestamp,json=maxFinalizedTimestamp,proto3" json:"max_finalized_timestamp,omitempty"` + ObservationTimestamp uint32 `protobuf:"varint,27,opt,name=observation_timestamp,json=observationTimestamp,proto3" json:"observation_timestamp,omitempty"` + IsLinkFeed bool `protobuf:"varint,28,opt,name=is_link_feed,json=isLinkFeed,proto3" json:"is_link_feed,omitempty"` + LinkPrice int64 `protobuf:"varint,29,opt,name=link_price,json=linkPrice,proto3" json:"link_price,omitempty"` + IsNativeFeed bool `protobuf:"varint,30,opt,name=is_native_feed,json=isNativeFeed,proto3" json:"is_native_feed,omitempty"` + NativePrice int64 `protobuf:"varint,31,opt,name=native_price,json=nativePrice,proto3" json:"native_price,omitempty"` + BridgeTaskRunStartedTimestamp int64 `protobuf:"varint,8,opt,name=bridge_task_run_started_timestamp,json=bridgeTaskRunStartedTimestamp,proto3" json:"bridge_task_run_started_timestamp,omitempty"` + BridgeTaskRunEndedTimestamp int64 `protobuf:"varint,9,opt,name=bridge_task_run_ended_timestamp,json=bridgeTaskRunEndedTimestamp,proto3" json:"bridge_task_run_ended_timestamp,omitempty"` + ProviderRequestedTimestamp int64 `protobuf:"varint,10,opt,name=provider_requested_timestamp,json=providerRequestedTimestamp,proto3" json:"provider_requested_timestamp,omitempty"` + ProviderReceivedTimestamp int64 `protobuf:"varint,11,opt,name=provider_received_timestamp,json=providerReceivedTimestamp,proto3" json:"provider_received_timestamp,omitempty"` + ProviderDataStreamEstablished int64 `protobuf:"varint,12,opt,name=provider_data_stream_established,json=providerDataStreamEstablished,proto3" json:"provider_data_stream_established,omitempty"` + ProviderIndicatedTime int64 `protobuf:"varint,13,opt,name=provider_indicated_time,json=providerIndicatedTime,proto3" json:"provider_indicated_time,omitempty"` + Feed string `protobuf:"bytes,14,opt,name=feed,proto3" json:"feed,omitempty"` + // v1+v2+v3 + ObservationBenchmarkPrice int64 `protobuf:"varint,15,opt,name=observation_benchmark_price,json=observationBenchmarkPrice,proto3" json:"observation_benchmark_price,omitempty"` // This value overflows, will be reserved and removed in future versions + ObservationBenchmarkPriceString string `protobuf:"bytes,22,opt,name=observation_benchmark_price_string,json=observationBenchmarkPriceString,proto3" json:"observation_benchmark_price_string,omitempty"` + // v1+v3 + ObservationBid int64 `protobuf:"varint,16,opt,name=observation_bid,json=observationBid,proto3" json:"observation_bid,omitempty"` // This value overflows, will be reserved and removed in future versions + ObservationAsk int64 `protobuf:"varint,17,opt,name=observation_ask,json=observationAsk,proto3" json:"observation_ask,omitempty"` // This value overflows, will be reserved and removed in future versions + ObservationBidString string `protobuf:"bytes,23,opt,name=observation_bid_string,json=observationBidString,proto3" json:"observation_bid_string,omitempty"` + ObservationAskString string `protobuf:"bytes,24,opt,name=observation_ask_string,json=observationAskString,proto3" json:"observation_ask_string,omitempty"` + ConfigDigest string `protobuf:"bytes,18,opt,name=config_digest,json=configDigest,proto3" json:"config_digest,omitempty"` + Round int64 `protobuf:"varint,19,opt,name=round,proto3" json:"round,omitempty"` + Epoch int64 `protobuf:"varint,20,opt,name=epoch,proto3" json:"epoch,omitempty"` + AssetSymbol string `protobuf:"bytes,21,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"` } func (x *EnhancedEAMercury) Reset() { @@ -83,6 +95,13 @@ func (*EnhancedEAMercury) Descriptor() ([]byte, []int) { return file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescGZIP(), []int{0} } +func (x *EnhancedEAMercury) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + func (x *EnhancedEAMercury) GetDataSource() string { if x != nil { return x.DataSource @@ -132,6 +151,55 @@ func (x *EnhancedEAMercury) GetCurrentBlockTimestamp() uint64 { return 0 } +func (x *EnhancedEAMercury) GetFetchMaxFinalizedTimestamp() bool { + if x != nil { + return x.FetchMaxFinalizedTimestamp + } + return false +} + +func (x *EnhancedEAMercury) GetMaxFinalizedTimestamp() int64 { + if x != nil { + return x.MaxFinalizedTimestamp + } + return 0 +} + +func (x *EnhancedEAMercury) GetObservationTimestamp() uint32 { + if x != nil { + return x.ObservationTimestamp + } + return 0 +} + +func (x *EnhancedEAMercury) GetIsLinkFeed() bool { + if x != nil { + return x.IsLinkFeed + } + return false +} + +func (x *EnhancedEAMercury) GetLinkPrice() int64 { + if x != nil { + return x.LinkPrice + } + return 0 +} + +func (x *EnhancedEAMercury) GetIsNativeFeed() bool { + if x != nil { + return x.IsNativeFeed + } + return false +} + +func (x *EnhancedEAMercury) GetNativePrice() int64 { + if x != nil { + return x.NativePrice + } + return 0 +} + func (x *EnhancedEAMercury) GetBridgeTaskRunStartedTimestamp() int64 { if x != nil { return x.BridgeTaskRunStartedTimestamp @@ -188,6 +256,13 @@ func (x *EnhancedEAMercury) GetObservationBenchmarkPrice() int64 { return 0 } +func (x *EnhancedEAMercury) GetObservationBenchmarkPriceString() string { + if x != nil { + return x.ObservationBenchmarkPriceString + } + return "" +} + func (x *EnhancedEAMercury) GetObservationBid() int64 { if x != nil { return x.ObservationBid @@ -202,6 +277,20 @@ func (x *EnhancedEAMercury) GetObservationAsk() int64 { return 0 } +func (x *EnhancedEAMercury) GetObservationBidString() string { + if x != nil { + return x.ObservationBidString + } + return "" +} + +func (x *EnhancedEAMercury) GetObservationAskString() string { + if x != nil { + return x.ObservationAskString + } + return "" +} + func (x *EnhancedEAMercury) GetConfigDigest() string { if x != nil { return x.ConfigDigest @@ -230,27 +319,6 @@ func (x *EnhancedEAMercury) GetAssetSymbol() string { return "" } -func (x *EnhancedEAMercury) GetObservationBenchmarkPriceString() string { - if x != nil { - return x.ObservationBenchmarkPriceString - } - return "" -} - -func (x *EnhancedEAMercury) GetObservationBidString() string { - if x != nil { - return x.ObservationBidString - } - return "" -} - -func (x *EnhancedEAMercury) GetObservationAskString() string { - if x != nil { - return x.ObservationAskString - } - return "" -} - var File_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto protoreflect.FileDescriptor var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDesc = []byte{ @@ -258,86 +326,107 @@ var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_raw 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x65, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x5f, 0x65, 0x61, 0x5f, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0x8e, 0x09, 0x0a, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0xe2, 0x0b, 0x0a, 0x11, 0x45, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x45, 0x41, 0x4d, 0x65, 0x72, 0x63, 0x75, - 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x70, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, - 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x10, 0x64, 0x70, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, - 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x70, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x05, 0x64, 0x70, 0x42, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x70, 0x5f, 0x61, - 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x64, 0x70, 0x41, 0x73, 0x6b, 0x12, - 0x30, 0x0a, 0x14, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x36, 0x0a, 0x17, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x15, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x48, 0x0a, 0x21, 0x62, 0x72, 0x69, 0x64, 0x67, - 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x1d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, - 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x44, 0x0a, 0x1f, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, - 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1b, 0x62, 0x72, 0x69, 0x64, - 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x40, 0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1a, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3e, 0x0a, 0x1b, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x47, 0x0a, 0x20, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x5f, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x1d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x44, 0x61, 0x74, - 0x61, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x65, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, - 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x65, - 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x65, 0x65, 0x64, 0x12, 0x3e, - 0x0a, 0x1b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x65, - 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0f, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x19, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x27, - 0x0a, 0x0f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, - 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x62, 0x73, 0x65, 0x72, - 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, 0x6b, - 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, - 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x13, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, - 0x70, 0x6f, 0x63, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, - 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, - 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x79, - 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x4b, 0x0a, 0x22, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, - 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x1f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x6e, - 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x12, 0x34, 0x0a, 0x16, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x20, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2c, 0x0a, + 0x12, 0x64, 0x70, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x10, 0x64, 0x70, 0x42, 0x65, 0x6e, + 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, + 0x70, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x64, 0x70, 0x42, + 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x70, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x01, 0x52, 0x05, 0x64, 0x70, 0x41, 0x73, 0x6b, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x41, 0x0a, 0x1d, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x66, + 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x66, 0x65, 0x74, 0x63, 0x68, 0x4d, + 0x61, 0x78, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x36, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x1a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x6d, 0x61, 0x78, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x33, 0x0a, 0x15, + 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x6f, 0x62, 0x73, + 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x66, 0x65, 0x65, + 0x64, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x46, + 0x65, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x69, + 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x73, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, + 0x66, 0x65, 0x65, 0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x4e, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x46, 0x65, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x21, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x44, 0x0a, 0x1f, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, + 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1b, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x45, 0x6e, 0x64, + 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x40, 0x0a, 0x1c, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x1a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3e, 0x0a, + 0x1b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x19, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x63, 0x65, + 0x69, 0x76, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x47, 0x0a, + 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x44, 0x61, 0x74, 0x61, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x73, 0x74, 0x61, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x66, 0x65, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x65, + 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x1b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, + 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x22, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1f, + 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x6e, 0x63, 0x68, + 0x6d, 0x61, 0x72, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, + 0x27, 0x0a, 0x0f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, + 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, + 0x6b, 0x12, 0x34, 0x0a, 0x16, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x16, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x6b, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x4e, 0x5a, - 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, - 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x23, 0x0a, + 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x12, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, + 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x21, + 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x15, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x79, 0x6d, 0x62, 0x6f, + 0x6c, 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, + 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, + 0x72, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, + 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, + 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto index 92242fd2a1..a527552bb6 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto @@ -5,28 +5,49 @@ option go_package = "github.com/smartcontractkit/chainlink/v2/core/services/sync package telem; message EnhancedEAMercury { + uint32 version = 32; + string data_source=1; double dp_benchmark_price=2; double dp_bid=3; double dp_ask=4; + + // v1 fields (block range) int64 current_block_number=5; string current_block_hash=6; uint64 current_block_timestamp=7; + + // v2+v3 fields (timestamp range) + bool fetch_max_finalized_timestamp = 25; + int64 max_finalized_timestamp=26; + uint32 observation_timestamp=27; + bool is_link_feed=28; + int64 link_price=29; + bool is_native_feed=30; + int64 native_price=31; + int64 bridge_task_run_started_timestamp=8; int64 bridge_task_run_ended_timestamp=9; int64 provider_requested_timestamp=10; int64 provider_received_timestamp=11; int64 provider_data_stream_established=12; int64 provider_indicated_time=13; + string feed=14; - int64 observation_benchmark_price=15; - int64 observation_bid=16; - int64 observation_ask=17; + + // v1+v2+v3 + int64 observation_benchmark_price=15; // This value overflows, will be reserved and removed in future versions + string observation_benchmark_price_string = 22; + // v1+v3 + int64 observation_bid=16; // This value overflows, will be reserved and removed in future versions + int64 observation_ask=17; // This value overflows, will be reserved and removed in future versions + string observation_bid_string = 23; + string observation_ask_string = 24; + string config_digest = 18; int64 round=19; int64 epoch=20; string asset_symbol=21; - string observation_benchmark_price_string = 22; - string observation_bid_string = 23; - string observation_ask_string = 24; + + } diff --git a/tools/flakeytests/coverage.txt b/tools/flakeytests/coverage.txt new file mode 100644 index 0000000000..91640016fe --- /dev/null +++ b/tools/flakeytests/coverage.txt @@ -0,0 +1,93 @@ +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 67a79f134e516b51ebf597e2eda0ff587c14d37d Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 30 Oct 2023 12:40:19 -0500 Subject: [PATCH 032/327] core/utils: deprecate StartStopOnce in favor of services.StateMachine (#11117) --- common/headtracker/head_broadcaster.go | 26 ++- common/headtracker/head_tracker.go | 4 +- common/txmgr/broadcaster.go | 3 +- common/txmgr/confirmer.go | 3 +- common/txmgr/txmgr.go | 2 +- core/chains/cosmos/chain.go | 5 +- core/chains/cosmos/cosmostxm/txm.go | 23 +-- core/chains/evm/chain.go | 4 +- core/chains/evm/client/node.go | 3 +- core/chains/evm/client/pool.go | 6 +- core/chains/evm/client/send_only_node.go | 3 +- .../evm/forwarders/forwarder_manager.go | 7 +- core/chains/evm/gas/arbitrum_estimator.go | 5 +- .../chains/evm/gas/block_history_estimator.go | 3 +- core/chains/evm/gas/l2_suggested_estimator.go | 3 +- core/chains/evm/gas/models.go | 3 +- .../evm/gas/rollups/l1_gas_price_oracle.go | 3 +- core/chains/evm/log/broadcaster.go | 7 +- core/chains/evm/logpoller/log_poller.go | 7 +- core/chains/evm/monitor/balance.go | 9 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/blockhashstore/delegate.go | 3 +- core/services/blockheaderfeeder/delegate.go | 3 +- core/services/directrequest/delegate.go | 5 +- core/services/feeds/service.go | 3 +- core/services/fluxmonitorv2/flux_monitor.go | 4 +- core/services/functions/connector_handler.go | 9 +- core/services/functions/listener.go | 8 +- core/services/gateway/connectionmanager.go | 2 +- core/services/gateway/connector/connector.go | 2 +- core/services/gateway/gateway.go | 3 +- .../gateway/handlers/functions/allowlist.go | 3 +- .../handlers/functions/handler.functions.go | 3 +- .../handlers/functions/subscriptions.go | 3 +- core/services/gateway/network/httpserver.go | 4 +- core/services/gateway/network/wsconnection.go | 3 +- core/services/gateway/network/wsserver.go | 4 +- core/services/job/spawner.go | 2 +- .../keeper/registry_synchronizer_core.go | 3 +- core/services/keeper/upkeep_executer.go | 3 +- core/services/nurse.go | 3 +- core/services/ocr/config_overrider.go | 6 +- core/services/ocr/contract_tracker.go | 3 +- core/services/ocr2/plugins/median/plugin.go | 3 +- .../plugins/ocr2keeper/evm20/log_provider.go | 5 +- .../ocr2/plugins/ocr2keeper/evm20/registry.go | 7 +- .../ocr2keeper/evm21/block_subscriber.go | 4 +- .../ocr2keeper/evm21/logprovider/provider.go | 4 +- .../ocr2keeper/evm21/logprovider/recoverer.go | 4 +- .../ocr2/plugins/ocr2keeper/evm21/registry.go | 3 +- .../evm21/transmit/event_provider.go | 5 +- .../ocr2keeper/evm21/upkeepstate/store.go | 3 +- core/services/ocrcommon/peer_wrapper.go | 11 +- core/services/ocrcommon/peerstore.go | 6 +- core/services/ocrcommon/run_saver.go | 4 +- core/services/ocrcommon/telemetry.go | 7 +- core/services/periodicbackup/backup.go | 12 +- core/services/pg/event_broadcaster.go | 7 +- core/services/pipeline/orm.go | 14 +- core/services/pipeline/runner.go | 10 +- core/services/promreporter/prom_reporter.go | 6 +- core/services/relay/evm/config_poller.go | 5 +- core/services/relay/evm/evm.go | 7 +- core/services/relay/evm/functions.go | 8 +- .../relay/evm/functions/logpoller_wrapper.go | 3 +- .../relay/evm/mercury/persistence_manager.go | 3 +- core/services/relay/evm/mercury/queue.go | 9 +- .../services/relay/evm/mercury/transmitter.go | 4 +- .../relay/evm/mercury/wsrpc/client.go | 10 +- .../relay/evm/request_round_tracker.go | 5 +- .../telemetry_ingress_batch_client.go | 4 +- .../telemetry_ingress_client.go | 3 +- core/services/telemetry/manager.go | 11 +- core/services/telemetry/manager_test.go | 10 +- core/services/vrf/v1/listener_v1.go | 3 +- core/services/vrf/v2/listener_v2.go | 3 +- core/utils/helpers_test.go | 5 - core/utils/mailbox_prom.go | 4 +- core/utils/sleeper_task.go | 15 +- core/utils/utils.go | 181 +----------------- core/utils/utils_test.go | 105 ---------- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 86 files changed, 254 insertions(+), 488 deletions(-) delete mode 100644 core/utils/helpers_test.go diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index 17d50ef562..e9ae93419b 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -25,13 +26,13 @@ func (set callbackSet[H, BLOCK_HASH]) values() []types.HeadTrackable[H, BLOCK_HA } type HeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct { - logger logger.Logger - callbacks callbackSet[H, BLOCK_HASH] - mailbox *utils.Mailbox[H] - mutex *sync.Mutex - chClose utils.StopChan - wgDone sync.WaitGroup - utils.StartStopOnce + services.StateMachine + logger logger.Logger + callbacks callbackSet[H, BLOCK_HASH] + mailbox *utils.Mailbox[H] + mutex sync.Mutex + chClose utils.StopChan + wgDone sync.WaitGroup latest H lastCallbackID int } @@ -44,13 +45,10 @@ func NewHeadBroadcaster[ lggr logger.Logger, ) *HeadBroadcaster[H, BLOCK_HASH] { return &HeadBroadcaster[H, BLOCK_HASH]{ - logger: lggr.Named("HeadBroadcaster"), - callbacks: make(callbackSet[H, BLOCK_HASH]), - mailbox: utils.NewSingleMailbox[H](), - mutex: &sync.Mutex{}, - chClose: make(chan struct{}), - wgDone: sync.WaitGroup{}, - StartStopOnce: utils.StartStopOnce{}, + logger: lggr.Named("HeadBroadcaster"), + callbacks: make(callbackSet[H, BLOCK_HASH]), + mailbox: utils.NewSingleMailbox[H](), + chClose: make(chan struct{}), } } diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 1978b281d4..c24dde595c 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -40,6 +40,7 @@ type HeadTracker[ ID types.ID, BLOCK_HASH types.Hashable, ] struct { + services.StateMachine log logger.Logger headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH] headSaver types.HeadSaver[HTH, BLOCK_HASH] @@ -54,8 +55,7 @@ type HeadTracker[ headListener types.HeadListener[HTH, BLOCK_HASH] chStop utils.StopChan wgDone sync.WaitGroup - utils.StartStopOnce - getNilHead func() HTH + getNilHead func() HTH } // NewHeadTracker instantiates a new HeadTracker using HeadSaver to persist new block numbers. diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 6512f67fe0..011866bf39 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -14,6 +14,7 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/services" clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -105,6 +106,7 @@ type Broadcaster[ SEQ types.Sequence, FEE feetypes.Fee, ] struct { + services.StateMachine logger logger.Logger txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] @@ -140,7 +142,6 @@ type Broadcaster[ initSync sync.Mutex isStarted bool - utils.StartStopOnce parseAddr func(string) (ADDR, error) diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index 31bba77141..c22a159457 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -14,6 +14,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/services" clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" @@ -112,7 +113,7 @@ type Confirmer[ SEQ types.Sequence, FEE feetypes.Fee, ] struct { - utils.StartStopOnce + services.StateMachine txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] lggr logger.Logger client txmgrtypes.TxmClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 980067b5fb..0c7117afab 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -69,7 +69,7 @@ type Txm[ SEQ types.Sequence, FEE feetypes.Fee, ] struct { - utils.StartStopOnce + services.StateMachine logger logger.Logger txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] config txmgrtypes.TransactionManagerChainConfig diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go index 43ba5a4e79..bb44c4bee6 100644 --- a/core/chains/cosmos/chain.go +++ b/core/chains/cosmos/chain.go @@ -27,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // DefaultRequestTimeout is the default Cosmos client timeout. @@ -93,7 +92,7 @@ func NewChain(cfg *CosmosConfig, opts ChainOpts) (adapters.Chain, error) { var _ adapters.Chain = (*chain)(nil) type chain struct { - utils.StartStopOnce + services.StateMachine id string cfg *CosmosConfig txm *cosmostxm.Txm @@ -197,7 +196,7 @@ func (c *chain) Close() error { func (c *chain) Ready() error { return multierr.Combine( - c.StartStopOnce.Ready(), + c.StateMachine.Ready(), c.txm.Ready(), ) } diff --git a/core/chains/cosmos/cosmostxm/txm.go b/core/chains/cosmos/cosmostxm/txm.go index e9fb2f6aca..8806d97a9f 100644 --- a/core/chains/cosmos/cosmostxm/txm.go +++ b/core/chains/cosmos/cosmostxm/txm.go @@ -28,20 +28,20 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( - _ services.ServiceCtx = (*Txm)(nil) - _ adapters.TxManager = (*Txm)(nil) + _ services.Service = (*Txm)(nil) + _ adapters.TxManager = (*Txm)(nil) ) // Txm manages transactions for the cosmos blockchain. type Txm struct { - starter utils.StartStopOnce + services.StateMachine eb pg.EventBroadcaster sub pg.Subscription orm *ORM @@ -58,7 +58,6 @@ func NewTxm(db *sqlx.DB, tc func() (cosmosclient.ReaderWriter, error), gpe cosmo lggr = logger.Named(lggr, "Txm") keystoreAdapter := NewKeystoreAdapter(ks, cfg.Bech32Prefix()) return &Txm{ - starter: utils.StartStopOnce{}, eb: eb, orm: NewORM(chainID, db, lggr, logCfg), lggr: lggr, @@ -73,7 +72,7 @@ func NewTxm(db *sqlx.DB, tc func() (cosmosclient.ReaderWriter, error), gpe cosmo // Start subscribes to pg notifications about cosmos msg inserts and processes them. func (txm *Txm) Start(context.Context) error { - return txm.starter.StartOnce("cosmostxm", func() error { + return txm.StartOnce("Txm", func() error { sub, err := txm.eb.Subscribe(pg.ChannelInsertOnCosmosMsg, "") if err != nil { return err @@ -520,13 +519,15 @@ func (txm *Txm) GasPrice() (sdk.DecCoin, error) { // Close close service func (txm *Txm) Close() error { - txm.sub.Close() - close(txm.stop) - <-txm.done - return nil + return txm.StopOnce("Txm", func() error { + txm.sub.Close() + close(txm.stop) + <-txm.done + return nil + }) } -func (txm *Txm) Name() string { return "cosmostxm" } +func (txm *Txm) Name() string { return txm.lggr.Name() } // Healthy service is healthy func (txm *Txm) Healthy() error { diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index 2646d25867..6eed13271e 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -108,7 +108,7 @@ func (c *LegacyChains) Get(id string) (Chain, error) { } type chain struct { - utils.StartStopOnce + services.StateMachine id *big.Int cfg *evmconfig.ChainScoped client evmclient.Client @@ -366,7 +366,7 @@ func (c *chain) Close() error { func (c *chain) Ready() (merr error) { merr = multierr.Combine( - c.StartStopOnce.Ready(), + c.StateMachine.Ready(), c.txm.Ready(), c.headBroadcaster.Ready(), c.headTracker.Ready(), diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index 4f7132a6cc..80bac25448 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -19,6 +19,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -132,7 +133,7 @@ type rawclient struct { // Node represents one ethereum node. // It must have a ws url and may have a http url type node struct { - utils.StartStopOnce + services.StateMachine lfcLog logger.Logger rpcLog logger.Logger name string diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 7e4667623d..2d679ab3d7 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -15,11 +15,11 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -57,7 +57,7 @@ type PoolConfig interface { // Pool represents an abstraction over one or more primary nodes // It is responsible for liveness checking and balancing queries across live nodes type Pool struct { - utils.StartStopOnce + services.StateMachine nodes []Node sendonlys []SendOnlyNode chainID *big.Int diff --git a/core/chains/evm/client/send_only_node.go b/core/chains/evm/client/send_only_node.go index a085ec4753..3f2481c189 100644 --- a/core/chains/evm/client/send_only_node.go +++ b/core/chains/evm/client/send_only_node.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -56,7 +57,7 @@ var _ SendOnlyNode = &sendOnlyNode{} // It only supports sending transactions // It must a http(s) url type sendOnlyNode struct { - utils.StartStopOnce + services.StateMachine stateMu sync.RWMutex // protects state* fields state NodeState diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 0c470e76d8..46bca95ba3 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -9,8 +9,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmlogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -30,7 +32,7 @@ type Config interface { } type FwdMgr struct { - utils.StartStopOnce + services.StateMachine ORM ORM evmClient evmclient.Client cfg Config @@ -61,9 +63,6 @@ func NewFwdMgr(db *sqlx.DB, client evmclient.Client, logpoller evmlogpoller.LogP ORM: NewORM(db, lggr, dbConfig), logpoller: logpoller, sendersCache: make(map[common.Address][]common.Address), - cacheMu: sync.RWMutex{}, - wg: sync.WaitGroup{}, - latestBlock: 0, } fwdMgr.ctx, fwdMgr.cancel = context.WithCancel(context.Background()) return &fwdMgr diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 6c2b5e8b87..17934bfa07 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -33,6 +33,7 @@ type ethClient interface { // arbitrumEstimator is an Estimator which extends l2SuggestedPriceEstimator to use getPricesInArbGas() for gas limit estimation. type arbitrumEstimator struct { + services.StateMachine cfg ArbConfig EvmEstimator // *l2SuggestedPriceEstimator @@ -49,8 +50,6 @@ type arbitrumEstimator struct { chInitialised chan struct{} chStop utils.StopChan chDone chan struct{} - - utils.StartStopOnce } func NewArbitrumEstimator(lggr logger.Logger, cfg ArbConfig, rpcClient rpcClient, ethClient ethClient) EvmEstimator { @@ -91,7 +90,7 @@ func (a *arbitrumEstimator) Close() error { }) } -func (a *arbitrumEstimator) Ready() error { return a.StartStopOnce.Ready() } +func (a *arbitrumEstimator) Ready() error { return a.StateMachine.Ready() } func (a *arbitrumEstimator) HealthReport() map[string]error { hp := map[string]error{a.Name(): a.Healthy()} diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 14b18ad66b..42c8f05153 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -15,6 +15,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-relay/pkg/services" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -96,7 +97,7 @@ type estimatorGasEstimatorConfig interface { //go:generate mockery --quiet --name Config --output ./mocks/ --case=underscore type ( BlockHistoryEstimator struct { - utils.StartStopOnce + services.StateMachine ethClient evmclient.Client chainID big.Int config chainConfig diff --git a/core/chains/evm/gas/l2_suggested_estimator.go b/core/chains/evm/gas/l2_suggested_estimator.go index 1782e34930..8e6c06a128 100644 --- a/core/chains/evm/gas/l2_suggested_estimator.go +++ b/core/chains/evm/gas/l2_suggested_estimator.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -28,7 +29,7 @@ type rpcClient interface { // l2SuggestedPriceEstimator is an Estimator which uses the L2 suggested gas price from eth_gasPrice. type l2SuggestedPriceEstimator struct { - utils.StartStopOnce + services.StateMachine client rpcClient pollPeriod time.Duration diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index bd3106c2ad..7bd88d7543 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -22,7 +22,6 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) @@ -150,10 +149,10 @@ func (fee EvmFee) ValidDynamic() bool { // WrappedEvmEstimator provides a struct that wraps the EVM specific dynamic and legacy estimators into one estimator that conforms to the generic FeeEstimator type WrappedEvmEstimator struct { + services.StateMachine EvmEstimator EIP1559Enabled bool l1Oracle rollups.L1Oracle - utils.StartStopOnce } var _ EvmFeeEstimator = (*WrappedEvmEstimator)(nil) diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index 8cf10325d4..c15aa23c79 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/config" @@ -26,6 +27,7 @@ type ethClient interface { // Reads L2-specific precompiles and caches the l1GasPrice set by the L2. type l1GasPriceOracle struct { + services.StateMachine client ethClient pollPeriod time.Duration logger logger.Logger @@ -38,7 +40,6 @@ type l1GasPriceOracle struct { chInitialised chan struct{} chStop utils.StopChan chDone chan struct{} - utils.StartStopOnce } const ( diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index bc9ba1cf6c..9c4050fd79 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -12,13 +12,14 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -44,7 +45,7 @@ type ( // Of course, these backfilled logs + any new logs will only be sent after the NumConfirmations for given subscriber. Broadcaster interface { utils.DependentAwaiter - services.ServiceCtx + services.Service httypes.HeadTrackable // ReplayFromBlock enqueues a replay from the provided block number. If forceBroadcast is @@ -88,6 +89,7 @@ type ( } broadcaster struct { + services.StateMachine orm ORM config Config connected atomic.Bool @@ -106,7 +108,6 @@ type ( changeSubscriberStatus *utils.Mailbox[changeSubscriberStatus] newHeads *utils.Mailbox[*evmtypes.Head] - utils.StartStopOnce utils.DependentAwaiter chStop utils.StopChan diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 54999cbdfb..6cda8f5b46 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -20,10 +20,11 @@ import ( "github.com/pkg/errors" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" @@ -31,7 +32,7 @@ import ( //go:generate mockery --quiet --name LogPoller --output ./mocks/ --case=underscore --structname LogPoller --filename log_poller.go type LogPoller interface { - services.ServiceCtx + services.Service Replay(ctx context.Context, fromBlock int64) error ReplayAsync(fromBlock int64) RegisterFilter(filter Filter, qopts ...pg.QOpt) error @@ -92,7 +93,7 @@ var ( ) type logPoller struct { - utils.StartStopOnce + services.StateMachine ec Client orm ORM lggr logger.Logger diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index 94434b733e..5f5b8a243b 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -13,12 +13,13 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -29,11 +30,11 @@ type ( BalanceMonitor interface { httypes.HeadTrackable GetEthBalance(gethCommon.Address) *assets.Eth - services.ServiceCtx + services.Service } balanceMonitor struct { - utils.StartStopOnce + services.StateMachine logger logger.Logger ethClient evmclient.Client chainID *big.Int @@ -53,7 +54,7 @@ var _ BalanceMonitor = (*balanceMonitor)(nil) func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keystore.Eth, logger logger.Logger) *balanceMonitor { chainId := ethClient.ConfiguredChainID() bm := &balanceMonitor{ - utils.StartStopOnce{}, + services.StateMachine{}, logger.Named("BalanceMonitor"), ethClient, chainId, diff --git a/core/scripts/go.mod b/core/scripts/go.mod index f097ea89be..7c0161a066 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -302,7 +302,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.20230913032705-f924d753cc47 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 // 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 0461daa25e..e0e5e07ecf 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1458,8 +1458,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.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 h1:QFMxPq7AqU4qXeW7UBv0eP/mpLt2pG2QkASUyFjKoIE= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/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/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index 90819f27a1..123052550b 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -197,7 +198,7 @@ func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // service is a job.Service that runs the BHS feeder every pollPeriod. type service struct { - utils.StartStopOnce + services.StateMachine feeder *Feeder wg sync.WaitGroup pollPeriod time.Duration diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 02ab34821f..971a691d77 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -211,7 +212,7 @@ func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // service is a job.Service that runs the BHS feeder every pollPeriod. type service struct { - utils.StartStopOnce + services.StateMachine feeder *BlockHeaderFeeder done chan struct{} pollPeriod time.Duration diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 75cebb7a74..174dca062a 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -9,13 +9,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -119,6 +120,7 @@ var ( ) type listener struct { + services.StateMachine logger logger.Logger config Config logBroadcaster log.Broadcaster @@ -135,7 +137,6 @@ type listener struct { requesters models.AddressCollection minContractPayment *assets.Link chStop chan struct{} - utils.StartStopOnce } func (l *listener) HealthReport() map[string]error { diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index 4c3647fde4..20919606fa 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" pb "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto" @@ -98,7 +99,7 @@ type Service interface { } type service struct { - utils.StartStopOnce + services.StateMachine orm ORM jobORM job.ORM diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index fe8a22d417..99d33c4239 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -55,6 +56,7 @@ const DefaultHibernationPollPeriod = 24 * time.Hour // FluxMonitor polls external price adapters via HTTP to check for price swings. type FluxMonitor struct { + services.StateMachine contractAddress common.Address oracleAddress common.Address jobSpec job.Job @@ -80,7 +82,6 @@ type FluxMonitor struct { backlog *utils.BoundedPriorityQueue[log.Broadcast] chProcessLogs chan struct{} - utils.StartStopOnce chStop chan struct{} waitOnStop chan struct{} } @@ -134,7 +135,6 @@ func NewFluxMonitor( PriorityAnswerUpdatedLog: 1, PriorityFlagChangedLog: 2, }), - StartStopOnce: utils.StartStopOnce{}, chProcessLogs: make(chan struct{}, 1), chStop: make(chan struct{}), waitOnStop: make(chan struct{}), diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index c32bf56f0c..a018157a37 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -8,6 +8,10 @@ import ( "go.uber.org/multierr" + ethCommon "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" @@ -16,13 +20,10 @@ import ( hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - ethCommon "github.com/ethereum/go-ethereum/common" ) type functionsConnectorHandler struct { - utils.StartStopOnce + services.StateMachine connector connector.GatewayConnector signerKey *ecdsa.PrivateKey diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index b76eb0a1c0..773ae61040 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -13,6 +13,9 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/libocr/commontypes" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/cbor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -23,9 +26,6 @@ import ( evmrelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/s4" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/smartcontractkit/libocr/commontypes" ) var ( @@ -116,7 +116,7 @@ const ( ) type FunctionsListener struct { - utils.StartStopOnce + services.StateMachine client client.Client contractAddressHex string job job.Job diff --git a/core/services/gateway/connectionmanager.go b/core/services/gateway/connectionmanager.go index ae2ade6511..278c4beaaa 100644 --- a/core/services/gateway/connectionmanager.go +++ b/core/services/gateway/connectionmanager.go @@ -42,7 +42,7 @@ type ConnectionManager interface { } type connectionManager struct { - utils.StartStopOnce + services.StateMachine config *config.ConnectionManagerConfig dons map[string]*donConnectionManager diff --git a/core/services/gateway/connector/connector.go b/core/services/gateway/connector/connector.go index dd8dce473b..5578681944 100644 --- a/core/services/gateway/connector/connector.go +++ b/core/services/gateway/connector/connector.go @@ -46,7 +46,7 @@ type GatewayConnectorHandler interface { } type gatewayConnector struct { - utils.StartStopOnce + services.StateMachine config *ConnectorConfig codec api.Codec diff --git a/core/services/gateway/gateway.go b/core/services/gateway/gateway.go index fb38ae10de..42e03107f3 100644 --- a/core/services/gateway/gateway.go +++ b/core/services/gateway/gateway.go @@ -13,6 +13,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" @@ -42,7 +43,7 @@ type HandlerFactory interface { } type gateway struct { - utils.StartStopOnce + services.StateMachine codec api.Codec httpServer gw_net.HttpServer diff --git a/core/services/gateway/handlers/functions/allowlist.go b/core/services/gateway/handlers/functions/allowlist.go index d3619d9071..914a933eb1 100644 --- a/core/services/gateway/handlers/functions/allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_allow_list" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" @@ -45,7 +46,7 @@ type OnchainAllowlist interface { } type onchainAllowlist struct { - utils.StartStopOnce + services.StateMachine config OnchainAllowlistConfig allowlist atomic.Pointer[map[common.Address]struct{}] diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index 7eb15ef6ff..01f450a4ea 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -68,7 +69,7 @@ type FunctionsHandlerConfig struct { } type functionsHandler struct { - utils.StartStopOnce + services.StateMachine handlerConfig FunctionsHandlerConfig donConfig *config.DONConfig diff --git a/core/services/gateway/handlers/functions/subscriptions.go b/core/services/gateway/handlers/functions/subscriptions.go index 181a98009f..79233b1031 100644 --- a/core/services/gateway/handlers/functions/subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -38,7 +39,7 @@ type OnchainSubscriptions interface { } type onchainSubscriptions struct { - utils.StartStopOnce + services.StateMachine config OnchainSubscriptionsConfig subscriptions UserSubscriptions diff --git a/core/services/gateway/network/httpserver.go b/core/services/gateway/network/httpserver.go index d9d3e5ee7e..3cae8dc276 100644 --- a/core/services/gateway/network/httpserver.go +++ b/core/services/gateway/network/httpserver.go @@ -8,9 +8,9 @@ import ( "net/http" "time" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name HttpServer --output ./mocks/ --case=underscore @@ -44,7 +44,7 @@ type HTTPServerConfig struct { } type httpServer struct { - utils.StartStopOnce + services.StateMachine config *HTTPServerConfig listener net.Listener server *http.Server diff --git a/core/services/gateway/network/wsconnection.go b/core/services/gateway/network/wsconnection.go index 345d951ed4..9215d183d1 100644 --- a/core/services/gateway/network/wsconnection.go +++ b/core/services/gateway/network/wsconnection.go @@ -11,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // WSConnectionWrapper is a websocket connection abstraction that supports re-connects. @@ -42,7 +41,7 @@ type WSConnectionWrapper interface { } type wsConnectionWrapper struct { - utils.StartStopOnce + services.StateMachine lggr logger.Logger conn atomic.Pointer[websocket.Conn] diff --git a/core/services/gateway/network/wsserver.go b/core/services/gateway/network/wsserver.go index 2fed4a9df4..86812a313e 100644 --- a/core/services/gateway/network/wsserver.go +++ b/core/services/gateway/network/wsserver.go @@ -10,9 +10,9 @@ import ( "github.com/gorilla/websocket" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name WebSocketServer --output ./mocks/ --case=underscore @@ -29,7 +29,7 @@ type WebSocketServerConfig struct { } type webSocketServer struct { - utils.StartStopOnce + services.StateMachine config *WebSocketServerConfig listener net.Listener server *http.Server diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index 200c25deb3..b2a8dad68f 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -43,6 +43,7 @@ type ( } spawner struct { + relayservices.StateMachine orm ORM config Config checker services.Checker @@ -52,7 +53,6 @@ type ( q pg.Q lggr logger.Logger - utils.StartStopOnce chStop utils.StopChan lbDependentAwaiters []utils.DependentAwaiter } diff --git a/core/services/keeper/registry_synchronizer_core.go b/core/services/keeper/registry_synchronizer_core.go index dea24f1a3b..761958ce19 100644 --- a/core/services/keeper/registry_synchronizer_core.go +++ b/core/services/keeper/registry_synchronizer_core.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -36,7 +37,7 @@ type RegistrySynchronizerOptions struct { } type RegistrySynchronizer struct { - utils.StartStopOnce + services.StateMachine chStop chan struct{} registryWrapper RegistryWrapper interval time.Duration diff --git a/core/services/keeper/upkeep_executer.go b/core/services/keeper/upkeep_executer.go index 435b245792..33ad8b7d77 100644 --- a/core/services/keeper/upkeep_executer.go +++ b/core/services/keeper/upkeep_executer.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -53,6 +54,7 @@ type UpkeepExecuterConfig interface { // UpkeepExecuter implements the logic to communicate with KeeperRegistry type UpkeepExecuter struct { + services.StateMachine chStop utils.StopChan ethClient evmclient.Client config UpkeepExecuterConfig @@ -66,7 +68,6 @@ type UpkeepExecuter struct { logger logger.Logger wgDone sync.WaitGroup effectiveKeeperAddress common.Address - utils.StartStopOnce } // NewUpkeepExecuter is the constructor of UpkeepExecuter diff --git a/core/services/nurse.go b/core/services/nurse.go index 33230ddae0..e414ca280e 100644 --- a/core/services/nurse.go +++ b/core/services/nurse.go @@ -17,13 +17,14 @@ import ( "github.com/google/pprof/profile" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type Nurse struct { - utils.StartStopOnce + services.StateMachine cfg Config log logger.Logger diff --git a/core/services/ocr/config_overrider.go b/core/services/ocr/config_overrider.go index 35d8e2a4c8..5b2ac20c00 100644 --- a/core/services/ocr/config_overrider.go +++ b/core/services/ocr/config_overrider.go @@ -9,15 +9,17 @@ import ( "time" "github.com/pkg/errors" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ConfigOverriderImpl struct { - utils.StartStopOnce + services.StateMachine logger logger.Logger flags *ContractFlags contractAddress ethkey.EIP55Address @@ -56,7 +58,7 @@ func NewConfigOverriderImpl( ctx, cancel := context.WithCancel(context.Background()) co := ConfigOverriderImpl{ - utils.StartStopOnce{}, + services.StateMachine{}, logger, flags, contractAddress, diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index a7df28e1c7..c5f3e431e4 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -52,7 +53,7 @@ type ( // OCRContractTracker complies with ContractConfigTracker interface and // handles log events related to the contract more generally OCRContractTracker struct { - utils.StartStopOnce + services.StateMachine ethClient evmclient.Client contract *offchain_aggregator_wrapper.OffchainAggregator diff --git a/core/services/ocr2/plugins/median/plugin.go b/core/services/ocr2/plugins/median/plugin.go index b78b75cbfc..f8517386b3 100644 --- a/core/services/ocr2/plugins/median/plugin.go +++ b/core/services/ocr2/plugins/median/plugin.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -48,7 +49,7 @@ func (p *Plugin) NewMedianFactory(ctx context.Context, provider types.MedianProv } type reportingPluginFactoryService struct { - utils.StartStopOnce + services.StateMachine lggr logger.Logger ocrtypes.ReportingPluginFactory } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go index e32c4a0662..856e508fc5 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go @@ -10,16 +10,17 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" + pluginutils "github.com/smartcontractkit/ocr2keepers/pkg/util" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" "github.com/smartcontractkit/ocr2keepers/pkg/v2/encoding" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type TransmitUnpacker interface { @@ -27,7 +28,7 @@ type TransmitUnpacker interface { } type LogProvider struct { - sync utils.StartStopOnce + sync services.StateMachine mu sync.RWMutex runState int runError error diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go index 7d1de17a5b..49cab7b5a4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go @@ -15,9 +15,11 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" "go.uber.org/multierr" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -25,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -135,7 +136,7 @@ type activeUpkeep struct { type EvmRegistry struct { HeadProvider - sync utils.StartStopOnce + sync services.StateMachine lggr logger.Logger poller logpoller.LogPoller addr common.Address diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go index 9766d98876..2d524e6f6c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go @@ -8,8 +8,10 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -34,7 +36,7 @@ var ( ) type BlockSubscriber struct { - utils.StartStopOnce + services.StateMachine threadCtrl utils.ThreadControl mu sync.RWMutex diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go index b62fb37084..729bf4ade5 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go @@ -15,8 +15,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -81,7 +83,7 @@ var _ LogEventProviderTest = &logEventProvider{} // logEventProvider manages log filters for upkeeps and enables to read the log events. type logEventProvider struct { - utils.StartStopOnce + services.StateMachine threadCtrl utils.ThreadControl lggr logger.Logger diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index 3994f1d841..b74160ae91 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -15,9 +15,11 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -63,7 +65,7 @@ type visitedRecord struct { } type logRecoverer struct { - utils.StartStopOnce + services.StateMachine threadCtrl utils.ThreadControl lggr logger.Logger diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 1cad587e63..5d180c05b8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -19,6 +19,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -128,7 +129,7 @@ type MercuryConfig struct { } type EvmRegistry struct { - utils.StartStopOnce + services.StateMachine threadCtrl utils.ThreadControl lggr logger.Logger poller logpoller.LogPoller diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go index b0ae2a7bf6..5fd320df8e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go @@ -7,15 +7,16 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ ocr2keepers.TransmitEventProvider = &EventProvider{} @@ -23,7 +24,7 @@ var _ ocr2keepers.TransmitEventProvider = &EventProvider{} type logParser func(registry *iregistry21.IKeeperRegistryMaster, log logpoller.Log) (transmitEventLog, error) type EventProvider struct { - sync utils.StartStopOnce + sync services.StateMachine mu sync.RWMutex runState int runError error diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go index 34bd6822d6..6c5f767bd3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go @@ -10,6 +10,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -59,7 +60,7 @@ type upkeepStateRecord struct { // It stores the state of ineligible upkeeps in a local, in-memory cache. // In addition, performed events are fetched by the scanner on demand. type upkeepStateStore struct { - utils.StartStopOnce + services.StateMachine threadCtrl utils.ThreadControl orm ORM diff --git a/core/services/ocrcommon/peer_wrapper.go b/core/services/ocrcommon/peer_wrapper.go index 1d2eca4666..0781303275 100644 --- a/core/services/ocrcommon/peer_wrapper.go +++ b/core/services/ocrcommon/peer_wrapper.go @@ -9,21 +9,22 @@ import ( p2ppeer "github.com/libp2p/go-libp2p-core/peer" p2ppeerstore "github.com/libp2p/go-libp2p-core/peerstore" "github.com/pkg/errors" + "go.uber.org/multierr" + ocrnetworking "github.com/smartcontractkit/libocr/networking" ocrnetworkingtypes "github.com/smartcontractkit/libocr/networking/types" ocr1types "github.com/smartcontractkit/libocr/offchainreporting/types" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/sqlx" - "go.uber.org/multierr" relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type PeerWrapperOCRConfig interface { @@ -43,7 +44,7 @@ type ( // SingletonPeerWrapper manages all libocr peers for the application SingletonPeerWrapper struct { - utils.StartStopOnce + services.StateMachine keyStore keystore.Master p2pCfg config.P2P ocrCfg PeerWrapperOCRConfig @@ -97,9 +98,7 @@ func NewSingletonPeerWrapper(keyStore keystore.Master, p2pCfg config.P2P, ocrCfg } } -func (p *SingletonPeerWrapper) IsStarted() bool { - return p.State() == utils.StartStopOnce_Started -} +func (p *SingletonPeerWrapper) IsStarted() bool { return p.Ready() == nil } // Start starts SingletonPeerWrapper. func (p *SingletonPeerWrapper) Start(context.Context) error { diff --git a/core/services/ocrcommon/peerstore.go b/core/services/ocrcommon/peerstore.go index 6bad2db4ee..f1c318a3bf 100644 --- a/core/services/ocrcommon/peerstore.go +++ b/core/services/ocrcommon/peerstore.go @@ -11,8 +11,10 @@ import ( "github.com/libp2p/go-libp2p-peerstore/pstoremem" ma "github.com/multiformats/go-multiaddr" "github.com/pkg/errors" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -30,7 +32,7 @@ type ( } Pstorewrapper struct { - utils.StartStopOnce + services.StateMachine Peerstore p2ppeerstore.Peerstore peerID string q pg.Q @@ -50,7 +52,7 @@ func NewPeerstoreWrapper(db *sqlx.DB, writeInterval time.Duration, peerID p2pkey q := pg.NewQ(db, namedLogger, cfg) return &Pstorewrapper{ - utils.StartStopOnce{}, + services.StateMachine{}, pstoremem.NewPeerstore(), peerID.Raw(), q, diff --git a/core/services/ocrcommon/run_saver.go b/core/services/ocrcommon/run_saver.go index 3aa3aff876..d8dcc34358 100644 --- a/core/services/ocrcommon/run_saver.go +++ b/core/services/ocrcommon/run_saver.go @@ -3,13 +3,13 @@ package ocrcommon import ( "context" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type RunResultSaver struct { - utils.StartStopOnce + services.StateMachine maxSuccessfulRuns uint64 runResults <-chan *pipeline.Run diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index 29d1ad92e4..be139723ef 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -7,10 +7,13 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + + "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/libocr/commontypes" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -50,7 +53,7 @@ type EnhancedTelemetryMercuryData struct { } type EnhancedTelemetryService[T EnhancedTelemetryData | EnhancedTelemetryMercuryData] struct { - utils.StartStopOnce + services.StateMachine chTelem <-chan T chDone chan struct{} diff --git a/core/services/periodicbackup/backup.go b/core/services/periodicbackup/backup.go index 8b9ff89cf4..f43698bbdb 100644 --- a/core/services/periodicbackup/backup.go +++ b/core/services/periodicbackup/backup.go @@ -11,11 +11,11 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -37,18 +37,18 @@ type backupResult struct { type ( DatabaseBackup interface { - services.ServiceCtx + services.Service RunBackup(version string) error } databaseBackup struct { + services.StateMachine logger logger.Logger databaseURL url.URL mode config.DatabaseBackupMode frequency time.Duration outputParentDir string done chan bool - utils.StartStopOnce } BackupConfig interface { @@ -77,13 +77,13 @@ func NewDatabaseBackup(dbUrl url.URL, rootDir string, backupConfig BackupConfig, } return &databaseBackup{ + services.StateMachine{}, lggr, dbUrl, backupConfig.Mode(), backupConfig.Frequency(), outputParentDir, make(chan bool), - utils.StartStopOnce{}, }, nil } @@ -129,7 +129,7 @@ func (backup *databaseBackup) Name() string { } func (backup *databaseBackup) HealthReport() map[string]error { - return map[string]error{backup.Name(): backup.StartStopOnce.Healthy()} + return map[string]error{backup.Name(): backup.Healthy()} } func (backup *databaseBackup) frequencyIsTooSmall() bool { diff --git a/core/services/pg/event_broadcaster.go b/core/services/pg/event_broadcaster.go index 3c74df6d74..f18ac3251a 100644 --- a/core/services/pg/event_broadcaster.go +++ b/core/services/pg/event_broadcaster.go @@ -11,8 +11,9 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -23,12 +24,13 @@ import ( // EventBroadcaster opaquely manages a collection of Postgres event listeners // and broadcasts events to subscribers (with an optional payload filter). type EventBroadcaster interface { - services.ServiceCtx + services.Service Subscribe(channel, payloadFilter string) (Subscription, error) Notify(channel string, payload string) error } type eventBroadcaster struct { + services.StateMachine uri string minReconnectInterval time.Duration maxReconnectDuration time.Duration @@ -39,7 +41,6 @@ type eventBroadcaster struct { chStop chan struct{} chDone chan struct{} lggr logger.Logger - utils.StartStopOnce } var _ EventBroadcaster = (*eventBroadcaster)(nil) diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index f4e69df1ec..148901bb36 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -11,13 +11,13 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/smartcontractkit/sqlx" ) // KeepersObservationSource is the same for all keeper jobs and it is not persisted in DB @@ -74,7 +74,7 @@ const KeepersObservationSource = ` //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore type ORM interface { - services.ServiceCtx + services.Service CreateSpec(pipeline Pipeline, maxTaskTimeout models.Interval, qopts ...pg.QOpt) (int32, error) CreateRun(run *Run, qopts ...pg.QOpt) (err error) InsertRun(run *Run, qopts ...pg.QOpt) error @@ -95,7 +95,7 @@ type ORM interface { } type orm struct { - utils.StartStopOnce + services.StateMachine q pg.Q lggr logger.Logger maxSuccessfulRuns uint64 @@ -111,7 +111,7 @@ var _ ORM = (*orm)(nil) func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, jobPipelineMaxSuccessfulRuns uint64) *orm { ctx, cancel := context.WithCancel(context.Background()) return &orm{ - utils.StartStopOnce{}, + services.StateMachine{}, pg.NewQ(db, lggr, cfg), lggr.Named("PipelineORM"), jobPipelineMaxSuccessfulRuns, diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 20319682ef..3dbe94747e 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -14,13 +14,13 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -28,7 +28,7 @@ import ( //go:generate mockery --quiet --name Runner --output ./mocks/ --case=underscore type Runner interface { - services.ServiceCtx + services.Service // Run is a blocking call that will execute the run until no further progress can be made. // If `incomplete` is true, the run is only partially complete and is suspended, awaiting to be resumed when more data comes in. @@ -52,6 +52,7 @@ type Runner interface { } type runner struct { + services.StateMachine orm ORM btORM bridges.ORM config Config @@ -67,7 +68,6 @@ type runner struct { // test helper runFinished func(*Run) - utils.StartStopOnce chStop utils.StopChan wgDone sync.WaitGroup } @@ -150,7 +150,7 @@ func (r *runner) Name() string { } func (r *runner) HealthReport() map[string]error { - return map[string]error{r.Name(): r.StartStopOnce.Healthy()} + return map[string]error{r.Name(): r.Healthy()} } func (r *runner) destroy() { diff --git a/core/services/promreporter/prom_reporter.go b/core/services/promreporter/prom_reporter.go index c0b48b46e3..fd6afeeb8e 100644 --- a/core/services/promreporter/prom_reporter.go +++ b/core/services/promreporter/prom_reporter.go @@ -13,6 +13,7 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -21,6 +22,7 @@ import ( //go:generate mockery --quiet --name PrometheusBackend --output ../../internal/mocks/ --case=underscore type ( promReporter struct { + services.StateMachine db *sql.DB lggr logger.Logger backend PrometheusBackend @@ -28,8 +30,6 @@ type ( chStop utils.StopChan wgDone sync.WaitGroup reportPeriod time.Duration - - utils.StartStopOnce } PrometheusBackend interface { @@ -130,7 +130,7 @@ func (pr *promReporter) Name() string { } func (pr *promReporter) HealthReport() map[string]error { - return map[string]error{pr.Name(): pr.StartStopOnce.Healthy()} + return map[string]error{pr.Name(): pr.Healthy()} } func (pr *promReporter) OnNewLongestChain(ctx context.Context, head *evmtypes.Head) { diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index 504155bf1e..1cf2318b29 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -11,16 +11,17 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -89,7 +90,7 @@ func configFromLog(logData []byte) (ocrtypes.ContractConfig, error) { } type configPoller struct { - utils.StartStopOnce + services.StateMachine lggr logger.Logger filterName string diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index e7a2bca344..3f45b41f46 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -42,7 +42,6 @@ import ( reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ relaytypes.Relayer = &Relayer{} //nolint:staticcheck @@ -238,7 +237,7 @@ func FilterNamesFromRelayArgs(args relaytypes.RelayArgs) (filterNames []string, } type configWatcher struct { - utils.StartStopOnce + services.StateMachine lggr logger.Logger contractAddress common.Address contractABI abi.ABI @@ -263,7 +262,6 @@ func newConfigWatcher(lggr logger.Logger, ) *configWatcher { replayCtx, replayCancel := context.WithCancel(context.Background()) return &configWatcher{ - StartStopOnce: utils.StartStopOnce{}, lggr: lggr.Named("ConfigWatcher").Named(contractAddress.String()), contractAddress: contractAddress, contractABI: contractABI, @@ -274,7 +272,6 @@ func newConfigWatcher(lggr logger.Logger, fromBlock: fromBlock, replayCtx: replayCtx, replayCancel: replayCancel, - wg: sync.WaitGroup{}, } } @@ -312,7 +309,7 @@ func (c *configWatcher) Close() error { } func (c *configWatcher) HealthReport() map[string]error { - return map[string]error{c.Name(): c.StartStopOnce.Healthy()} + return map[string]error{c.Name(): c.Healthy()} } func (c *configWatcher) OffchainConfigDigester() ocrtypes.OffchainConfigDigester { diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index 43a3d2ff86..fdd6201c69 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -9,11 +9,14 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "go.uber.org/multierr" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -24,11 +27,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type functionsProvider struct { - utils.StartStopOnce + services.StateMachine configWatcher *configWatcher contractTransmitter ContractTransmitter logPollerWrapper evmRelayTypes.LogPollerWrapper diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go index db2c7fd68c..777717d01c 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper.go +++ b/core/services/relay/evm/functions/logpoller_wrapper.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" @@ -21,7 +22,7 @@ import ( ) type logPollerWrapper struct { - utils.StartStopOnce + services.StateMachine routerContract *functions_router.FunctionsRouter pluginConfig config.PluginConfig diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index 1c8dad4530..9de1f80c6b 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -7,6 +7,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" @@ -22,7 +23,7 @@ type PersistenceManager struct { lggr logger.Logger orm ORM - once utils.StartStopOnce + once services.StateMachine stopCh utils.StopChan wg sync.WaitGroup diff --git a/core/services/relay/evm/mercury/queue.go b/core/services/relay/evm/mercury/queue.go index 44042c5772..3d20b3f2b0 100644 --- a/core/services/relay/evm/mercury/queue.go +++ b/core/services/relay/evm/mercury/queue.go @@ -13,8 +13,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -24,7 +25,7 @@ type asyncDeleter interface { AsyncDelete(req *pb.TransmitRequest) } -var _ services.ServiceCtx = (*TransmitQueue)(nil) +var _ services.Service = (*TransmitQueue)(nil) var transmitQueueLoad = promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "mercury_transmit_queue_load", @@ -40,7 +41,7 @@ const promInterval = 6500 * time.Millisecond // TransmitQueue is the high-level package that everything outside of this file should be using // It stores pending transmissions, yielding the latest (highest priority) first to the caller type TransmitQueue struct { - utils.StartStopOnce + services.StateMachine cond sync.Cond lggr logger.Logger @@ -68,7 +69,7 @@ func NewTransmitQueue(lggr logger.Logger, feedID string, maxlen int, transmissio heap.Init(&pq) // ensure the heap is ordered mu := new(sync.RWMutex) return &TransmitQueue{ - utils.StartStopOnce{}, + services.StateMachine{}, sync.Cond{L: mu}, lggr.Named("TransmitQueue"), asyncDeleter, diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 0c2721442b..88c3113abc 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -84,7 +84,7 @@ type TransmitterReportDecoder interface { var _ Transmitter = (*mercuryTransmitter)(nil) type mercuryTransmitter struct { - utils.StartStopOnce + services.StateMachine lggr logger.Logger rpcClient wsrpc.Client cfgTracker ConfigTracker @@ -127,7 +127,7 @@ func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrp feedIDHex := fmt.Sprintf("0x%x", feedID[:]) persistenceManager := NewPersistenceManager(lggr, NewORM(db, lggr, cfg), jobID, maxTransmitQueueSize, flushDeletesFrequency, pruneFrequency) return &mercuryTransmitter{ - utils.StartStopOnce{}, + services.StateMachine{}, lggr.Named("MercuryTransmitter").With("feedID", feedIDHex), rpcClient, cfgTracker, diff --git a/core/services/relay/evm/mercury/wsrpc/client.go b/core/services/relay/evm/mercury/wsrpc/client.go index fb9a57d9a2..f6ed1d0db8 100644 --- a/core/services/relay/evm/mercury/wsrpc/client.go +++ b/core/services/relay/evm/mercury/wsrpc/client.go @@ -11,11 +11,13 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/wsrpc" "github.com/smartcontractkit/wsrpc/connectivity" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -59,7 +61,7 @@ var ( ) type Client interface { - services.ServiceCtx + services.Service pb.MercuryClient } @@ -70,7 +72,7 @@ type Conn interface { } type client struct { - utils.StartStopOnce + services.StateMachine csaKey csakey.KeyV2 serverPubKey []byte @@ -211,7 +213,7 @@ func (w *client) HealthReport() map[string]error { // Healthy if connected func (w *client) Healthy() (err error) { - if err = w.StartStopOnce.Healthy(); err != nil { + if err = w.StateMachine.Healthy(); err != nil { return err } state := w.conn.GetState() diff --git a/core/services/relay/evm/request_round_tracker.go b/core/services/relay/evm/request_round_tracker.go index 3507f1dfa8..4e065f2dfd 100644 --- a/core/services/relay/evm/request_round_tracker.go +++ b/core/services/relay/evm/request_round_tracker.go @@ -8,22 +8,23 @@ import ( gethCommon "github.com/ethereum/go-ethereum/common" gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // RequestRoundTracker subscribes to new request round logs. type RequestRoundTracker struct { - utils.StartStopOnce + services.StateMachine ethClient evmclient.Client contract *offchain_aggregator_wrapper.OffchainAggregator diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go index 4924bb2cd5..26abda65d3 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client.go +++ b/core/services/synchronization/telemetry_ingress_batch_client.go @@ -12,10 +12,10 @@ import ( "github.com/smartcontractkit/wsrpc" "github.com/smartcontractkit/wsrpc/examples/simple/keys" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // NoopTelemetryIngressBatchClient is a no-op interface for TelemetryIngressBatchClient @@ -37,7 +37,7 @@ func (NoopTelemetryIngressBatchClient) Name() string { return func (NoopTelemetryIngressBatchClient) Ready() error { return nil } type telemetryIngressBatchClient struct { - utils.StartStopOnce + services.StateMachine url *url.URL ks keystore.CSA serverPubKeyHex string diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go index 1db4f69afd..9458b7627c 100644 --- a/core/services/synchronization/telemetry_ingress_client.go +++ b/core/services/synchronization/telemetry_ingress_client.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/wsrpc" "github.com/smartcontractkit/wsrpc/examples/simple/keys" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" @@ -35,7 +36,7 @@ func (NoopTelemetryIngressClient) Name() string { return "Noop func (NoopTelemetryIngressClient) Ready() error { return nil } type telemetryIngressClient struct { - utils.StartStopOnce + services.StateMachine url *url.URL ks keystore.CSA serverPubKeyHex string diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go index 3818341f5b..2931ec71a1 100644 --- a/core/services/telemetry/manager.go +++ b/core/services/telemetry/manager.go @@ -8,14 +8,15 @@ import ( "time" "github.com/pkg/errors" - "github.com/smartcontractkit/libocr/commontypes" "go.uber.org/multierr" + "github.com/smartcontractkit/libocr/commontypes" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //// Client encapsulates all the functionality needed to @@ -26,7 +27,7 @@ import ( //} type Manager struct { - utils.StartStopOnce + services.StateMachine bufferSize uint endpoints []*telemetryEndpoint ks keystore.CSA @@ -67,7 +68,7 @@ func (l *legacyEndpointConfig) URL() *url.URL { } type telemetryEndpoint struct { - utils.StartStopOnce + services.StateMachine ChainID string Network string URL *url.URL @@ -143,7 +144,7 @@ func (m *Manager) HealthReport() map[string]error { hr[m.lggr.Name()] = m.Healthy() for _, e := range m.endpoints { name := fmt.Sprintf("%s.%s.%s", m.lggr.Name(), e.Network, e.ChainID) - hr[name] = e.StartStopOnce.Healthy() + hr[name] = e.Healthy() } return hr } diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 4aaf328015..69746625dd 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -24,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" mocks2 "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func setupMockConfig(t *testing.T, useBatchSend bool) *mocks.TelemetryIngress { @@ -246,10 +246,10 @@ func TestCorrectEndpointRouting(t *testing.T) { }) tm.endpoints[i] = &telemetryEndpoint{ - StartStopOnce: utils.StartStopOnce{}, - ChainID: e.chainID, - Network: e.network, - client: clientMock, + StateMachine: services.StateMachine{}, + ChainID: e.chainID, + Network: e.network, + client: clientMock, } } diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 03b92bc15c..613c0d124d 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -13,6 +13,7 @@ import ( heaps "github.com/theodesp/go-heaps" "github.com/theodesp/go-heaps/pairing" + "github.com/smartcontractkit/chainlink-relay/pkg/services" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -43,7 +44,7 @@ type request struct { } type Listener struct { - utils.StartStopOnce + services.StateMachine Cfg vrfcommon.Config FeeCfg vrfcommon.FeeConfig diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 31e76b48fd..7560baad3a 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -23,6 +23,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/services" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -191,7 +192,7 @@ type vrfPipelineResult struct { } type listenerV2 struct { - utils.StartStopOnce + services.StateMachine cfg vrfcommon.Config feeCfg vrfcommon.FeeConfig l logger.SugaredLogger diff --git a/core/utils/helpers_test.go b/core/utils/helpers_test.go deleted file mode 100644 index d317994cde..0000000000 --- a/core/utils/helpers_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package utils - -func (once *StartStopOnce) LoadState() StartStopOnceState { - return StartStopOnceState(once.state.Load()) -} diff --git a/core/utils/mailbox_prom.go b/core/utils/mailbox_prom.go index 0291a51d2c..dc20db84d9 100644 --- a/core/utils/mailbox_prom.go +++ b/core/utils/mailbox_prom.go @@ -9,6 +9,8 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" ) var mailboxLoad = promauto.NewGaugeVec(prometheus.GaugeOpts{ @@ -21,7 +23,7 @@ var mailboxLoad = promauto.NewGaugeVec(prometheus.GaugeOpts{ const mailboxPromInterval = 5 * time.Second type MailboxMonitor struct { - StartStopOnce + services.StateMachine appID string mailboxes sync.Map diff --git a/core/utils/sleeper_task.go b/core/utils/sleeper_task.go index 0b45507a82..fcec254249 100644 --- a/core/utils/sleeper_task.go +++ b/core/utils/sleeper_task.go @@ -3,6 +3,8 @@ package utils import ( "fmt" "time" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" ) // SleeperTask represents a task that waits in the background to process some work. @@ -19,12 +21,12 @@ type Worker interface { } type sleeperTask struct { + services.StateMachine worker Worker chQueue chan struct{} chStop chan struct{} chDone chan struct{} chWorkDone chan struct{} - StartStopOnce } // NewSleeperTask takes a worker and returns a SleeperTask. @@ -76,13 +78,14 @@ func (s *sleeperTask) WakeUpIfStarted() { // WakeUp wakes up the sleeper task, asking it to execute its Worker. func (s *sleeperTask) WakeUp() { - if s.StartStopOnce.State() == StartStopOnce_Stopped { + if !s.IfStarted(func() { + select { + case s.chQueue <- struct{}{}: + default: + } + }) { panic("cannot wake up stopped sleeper task") } - select { - case s.chQueue <- struct{}{}: - default: - } } func (s *sleeperTask) workDone() { diff --git a/core/utils/utils.go b/core/utils/utils.go index d96546b3e1..b8515f3362 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -31,6 +31,8 @@ import ( "github.com/robfig/cron/v3" "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/sha3" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" ) const ( @@ -819,14 +821,6 @@ func EVMBytesToUint64(buf []byte) uint64 { return result } -type errNotStarted struct { - state StartStopOnceState -} - -func (e *errNotStarted) Error() string { - return fmt.Sprintf("service is %q, not started", e.state) -} - var ( ErrAlreadyStopped = errors.New("already stopped") ErrCannotStopUnstarted = errors.New("cannot stop unstarted service") @@ -834,176 +828,7 @@ var ( // StartStopOnce contains a StartStopOnceState integer // Deprecated: use services.StateMachine -type StartStopOnce struct { - state atomic.Int32 - sync.RWMutex // lock is held during startup/shutdown, RLock is held while executing functions dependent on a particular state - - // SvcErrBuffer is an ErrorBuffer that let service owners track critical errors happening in the service. - // - // SvcErrBuffer.SetCap(int) Overrides buffer limit from defaultErrorBufferCap - // SvcErrBuffer.Append(error) Appends an error to the buffer - // SvcErrBuffer.Flush() error returns all tracked errors as a single joined error - SvcErrBuffer ErrorBuffer -} - -// StartStopOnceState holds the state for StartStopOnce -type StartStopOnceState int32 - -// nolint -const ( - StartStopOnce_Unstarted StartStopOnceState = iota - StartStopOnce_Started - StartStopOnce_Starting - StartStopOnce_StartFailed - StartStopOnce_Stopping - StartStopOnce_Stopped - StartStopOnce_StopFailed -) - -func (s StartStopOnceState) String() string { - switch s { - case StartStopOnce_Unstarted: - return "Unstarted" - case StartStopOnce_Started: - return "Started" - case StartStopOnce_Starting: - return "Starting" - case StartStopOnce_StartFailed: - return "StartFailed" - case StartStopOnce_Stopping: - return "Stopping" - case StartStopOnce_Stopped: - return "Stopped" - case StartStopOnce_StopFailed: - return "StopFailed" - default: - return fmt.Sprintf("unrecognized state: %d", s) - } -} - -// StartOnce sets the state to Started -func (once *StartStopOnce) StartOnce(name string, fn func() error) error { - // SAFETY: We do this compare-and-swap outside of the lock so that - // concurrent StartOnce() calls return immediately. - success := once.state.CompareAndSwap(int32(StartStopOnce_Unstarted), int32(StartStopOnce_Starting)) - - if !success { - return pkgerrors.Errorf("%v has already been started once; state=%v", name, StartStopOnceState(once.state.Load())) - } - - once.Lock() - defer once.Unlock() - - // Setting cap before calling startup fn in case of crits in startup - once.SvcErrBuffer.SetCap(defaultErrorBufferCap) - err := fn() - - if err == nil { - success = once.state.CompareAndSwap(int32(StartStopOnce_Starting), int32(StartStopOnce_Started)) - } else { - success = once.state.CompareAndSwap(int32(StartStopOnce_Starting), int32(StartStopOnce_StartFailed)) - } - - if !success { - // SAFETY: If this is reached, something must be very wrong: once.state - // was tampered with outside of the lock. - panic(fmt.Sprintf("%v entered unreachable state, unable to set state to started", name)) - } - - return err -} - -// StopOnce sets the state to Stopped -func (once *StartStopOnce) StopOnce(name string, fn func() error) error { - // SAFETY: We hold the lock here so that Stop blocks until StartOnce - // executes. This ensures that a very fast call to Stop will wait for the - // code to finish starting up before teardown. - once.Lock() - defer once.Unlock() - - success := once.state.CompareAndSwap(int32(StartStopOnce_Started), int32(StartStopOnce_Stopping)) - - if !success { - state := once.state.Load() - switch state { - case int32(StartStopOnce_Stopped): - return pkgerrors.Wrapf(ErrAlreadyStopped, "%s has already been stopped", name) - case int32(StartStopOnce_Unstarted): - return pkgerrors.Wrapf(ErrCannotStopUnstarted, "%s has not been started", name) - default: - return pkgerrors.Errorf("%v cannot be stopped from this state; state=%v", name, StartStopOnceState(state)) - } - } - - err := fn() - - if err == nil { - success = once.state.CompareAndSwap(int32(StartStopOnce_Stopping), int32(StartStopOnce_Stopped)) - } else { - success = once.state.CompareAndSwap(int32(StartStopOnce_Stopping), int32(StartStopOnce_StopFailed)) - } - - if !success { - // SAFETY: If this is reached, something must be very wrong: once.state - // was tampered with outside of the lock. - panic(fmt.Sprintf("%v entered unreachable state, unable to set state to stopped", name)) - } - - return err -} - -// State retrieves the current state -func (once *StartStopOnce) State() StartStopOnceState { - state := once.state.Load() - return StartStopOnceState(state) -} - -// IfStarted runs the func and returns true only if started, otherwise returns false -func (once *StartStopOnce) IfStarted(f func()) (ok bool) { - once.RLock() - defer once.RUnlock() - - state := once.state.Load() - - if StartStopOnceState(state) == StartStopOnce_Started { - f() - return true - } - return false -} - -// IfNotStopped runs the func and returns true if in any state other than Stopped -func (once *StartStopOnce) IfNotStopped(f func()) (ok bool) { - once.RLock() - defer once.RUnlock() - - state := once.state.Load() - - if StartStopOnceState(state) == StartStopOnce_Stopped { - return false - } - f() - return true -} - -// Ready returns ErrNotStarted if the state is not started. -func (once *StartStopOnce) Ready() error { - state := once.State() - if state == StartStopOnce_Started { - return nil - } - return &errNotStarted{state: state} -} - -// Healthy returns ErrNotStarted if the state is not started. -// Override this per-service with more specific implementations. -func (once *StartStopOnce) Healthy() error { - state := once.State() - if state == StartStopOnce_Started { - return once.SvcErrBuffer.Flush() - } - return &errNotStarted{state: state} -} +type StartStopOnce = services.StateMachine // EnsureClosed closes the io.Closer, returning nil if it was already // closed or not started yet diff --git a/core/utils/utils_test.go b/core/utils/utils_test.go index 5d728d14f4..04802feb3a 100644 --- a/core/utils/utils_test.go +++ b/core/utils/utils_test.go @@ -724,111 +724,6 @@ func TestContextFromChanWithTimeout(t *testing.T) { }) } -func TestStartStopOnceState_String(t *testing.T) { - t.Parallel() - - assert.Equal(t, "Unstarted", utils.StartStopOnce_Unstarted.String()) - assert.Equal(t, "Started", utils.StartStopOnce_Started.String()) - assert.Equal(t, "Starting", utils.StartStopOnce_Starting.String()) - assert.Equal(t, "Stopping", utils.StartStopOnce_Stopping.String()) - assert.Equal(t, "Stopped", utils.StartStopOnce_Stopped.String()) - assert.Equal(t, "unrecognized state: 123", utils.StartStopOnceState(123).String()) -} - -func TestStartStopOnce(t *testing.T) { - t.Parallel() - - var callsCount atomic.Int32 - incCount := func() { - callsCount.Add(1) - } - - var s utils.StartStopOnce - ok := s.IfStarted(incCount) - assert.False(t, ok) - ok = s.IfNotStopped(incCount) - assert.True(t, ok) - assert.Equal(t, int32(1), callsCount.Load()) - - err := s.StartOnce("foo", func() error { return nil }) - assert.NoError(t, err) - - assert.True(t, s.IfStarted(incCount)) - assert.Equal(t, int32(2), callsCount.Load()) - - err = s.StopOnce("foo", func() error { return nil }) - assert.NoError(t, err) - ok = s.IfNotStopped(incCount) - assert.False(t, ok) - assert.Equal(t, int32(2), callsCount.Load()) -} - -func TestStartStopOnce_StartErrors(t *testing.T) { - var s utils.StartStopOnce - - err := s.StartOnce("foo", func() error { return errors.New("foo") }) - assert.Error(t, err) - - var callsCount atomic.Int32 - incCount := func() { - callsCount.Add(1) - } - - assert.False(t, s.IfStarted(incCount)) - assert.Equal(t, int32(0), callsCount.Load()) - - err = s.StartOnce("foo", func() error { return nil }) - require.Error(t, err) - assert.Contains(t, err.Error(), "foo has already been started once") - err = s.StopOnce("foo", func() error { return nil }) - require.Error(t, err) - assert.Contains(t, err.Error(), "foo cannot be stopped from this state; state=StartFailed") - - assert.Equal(t, utils.StartStopOnce_StartFailed, s.LoadState()) -} - -func TestStartStopOnce_StopErrors(t *testing.T) { - var s utils.StartStopOnce - - err := s.StartOnce("foo", func() error { return nil }) - require.NoError(t, err) - - var callsCount atomic.Int32 - incCount := func() { - callsCount.Add(1) - } - - err = s.StopOnce("foo", func() error { return errors.New("explodey mcsplode") }) - assert.Error(t, err) - - assert.False(t, s.IfStarted(incCount)) - assert.Equal(t, int32(0), callsCount.Load()) - assert.True(t, s.IfNotStopped(incCount)) - assert.Equal(t, int32(1), callsCount.Load()) - - err = s.StartOnce("foo", func() error { return nil }) - require.Error(t, err) - assert.Contains(t, err.Error(), "foo has already been started once") - err = s.StopOnce("foo", func() error { return nil }) - require.Error(t, err) - assert.Contains(t, err.Error(), "foo cannot be stopped from this state; state=StopFailed") - - assert.Equal(t, utils.StartStopOnce_StopFailed, s.LoadState()) -} - -func TestStartStopOnce_Ready_Healthy(t *testing.T) { - t.Parallel() - - var s utils.StartStopOnce - assert.Error(t, s.Ready()) - assert.Error(t, s.Healthy()) - - err := s.StartOnce("foo", func() error { return nil }) - assert.NoError(t, err) - assert.NoError(t, s.Ready()) - assert.NoError(t, s.Healthy()) -} - func TestLeftPadBitString(t *testing.T) { t.Parallel() diff --git a/go.mod b/go.mod index 3679c79ed0..14f195d495 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,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.20230913032705-f924d753cc47 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 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-20231020123319-d255366a6545 diff --git a/go.sum b/go.sum index e2bc661048..c9700330fa 100644 --- a/go.sum +++ b/go.sum @@ -1459,8 +1459,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.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 h1:QFMxPq7AqU4qXeW7UBv0eP/mpLt2pG2QkASUyFjKoIE= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/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 c1a8cdb61c..21ce192126 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -384,7 +384,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.20230913032705-f924d753cc47 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 // 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/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 77778de9d2..64305ddc24 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2362,8 +2362,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.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04 h1:QFMxPq7AqU4qXeW7UBv0eP/mpLt2pG2QkASUyFjKoIE= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231027131428-7dc07d302a04/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/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= From e3caf761e9f036b351d5f4ab686892c4f7d7da42 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 30 Oct 2023 13:15:35 -0500 Subject: [PATCH 033/327] core/chains/cosmos/cosmostxm: simplifications (#11101) --- core/chains/cosmos/chain.go | 102 +++++-- core/chains/cosmos/config.go | 272 ------------------ core/chains/cosmos/config_test.go | 96 ------- core/chains/cosmos/cosmostxm/helpers_test.go | 32 +-- core/chains/cosmos/cosmostxm/key_wrapper.go | 6 +- .../cosmos/cosmostxm/keystore_adapter.go | 16 +- core/chains/cosmos/cosmostxm/orm_test.go | 5 +- core/chains/cosmos/cosmostxm/txm.go | 4 +- .../cosmos/cosmostxm/txm_internal_test.go | 122 ++++---- core/chains/cosmos/cosmostxm/txm_test.go | 265 ++++++++--------- core/cmd/cosmos_chains_commands_test.go | 4 +- core/cmd/cosmos_node_commands_test.go | 13 +- core/cmd/cosmos_transaction_commands_test.go | 61 +--- core/cmd/shell.go | 2 +- core/config/docs/docs_test.go | 4 +- core/internal/cltest/cltest.go | 2 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/chainlink/config.go | 6 +- core/services/chainlink/config_general.go | 4 +- core/services/chainlink/config_test.go | 7 +- .../chainlink/mocks/general_config.go | 10 +- .../relayer_chain_interoperators_test.go | 15 +- core/services/chainlink/relayer_factory.go | 7 +- core/services/chainlink/types.go | 4 +- core/web/cosmos_chains_controller_test.go | 9 +- core/web/cosmos_transfer_controller.go | 108 +++---- core/web/presenters/cosmos_msg.go | 4 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 32 files changed, 377 insertions(+), 821 deletions(-) delete mode 100644 core/chains/cosmos/config.go delete mode 100644 core/chains/cosmos/config_test.go diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go index bb44c4bee6..e11f95d356 100644 --- a/core/chains/cosmos/chain.go +++ b/core/chains/cosmos/chain.go @@ -7,35 +7,38 @@ import ( "math/big" "time" + "github.com/pelletier/go-toml/v2" "github.com/pkg/errors" "go.uber.org/multierr" sdk "github.com/cosmos/cosmos-sdk/types" + bank "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/smartcontractkit/sqlx" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" relaychains "github.com/smartcontractkit/chainlink-relay/pkg/chains" "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-relay/pkg/services" + + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) -// DefaultRequestTimeout is the default Cosmos client timeout. +// defaultRequestTimeout is the default Cosmos client timeout. // Note that while the cosmos node is processing a heavy block, // requests can be delayed significantly (https://github.com/tendermint/tendermint/issues/6899), // however there's nothing we can do but wait until the block is processed. // So we set a fairly high timeout here. // TODO(BCI-979): Remove this, or make this configurable with the updated client. -const DefaultRequestTimeout = 30 * time.Second +const defaultRequestTimeout = 30 * time.Second var ( // ErrChainIDEmpty is returned when chain is required but was empty. @@ -78,7 +81,7 @@ func (o *ChainOpts) Validate() (err error) { return } -func NewChain(cfg *CosmosConfig, opts ChainOpts) (adapters.Chain, error) { +func NewChain(cfg *coscfg.TOMLConfig, opts ChainOpts) (adapters.Chain, error) { if !cfg.IsEnabled() { return nil, fmt.Errorf("cannot create new chain with ID %s, the chain is disabled", *cfg.ChainID) } @@ -94,23 +97,23 @@ var _ adapters.Chain = (*chain)(nil) type chain struct { services.StateMachine id string - cfg *CosmosConfig + cfg *coscfg.TOMLConfig txm *cosmostxm.Txm lggr logger.Logger } -func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *coscfg.TOMLConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "cosmosChainID", id) var ch = chain{ id: id, cfg: cfg, lggr: logger.Named(lggr, "Chain"), } - tc := func() (cosmosclient.ReaderWriter, error) { + tc := func() (client.ReaderWriter, error) { return ch.getClient("") } - gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ - cosmosclient.NewClosureGasPriceEstimator(func() (map[string]sdk.DecCoin, error) { + gpe := client.NewMustGasPriceEstimator([]client.GasPricesEstimator{ + client.NewClosureGasPriceEstimator(func() (map[string]sdk.DecCoin, error) { return map[string]sdk.DecCoin{ cfg.GasToken(): sdk.NewDecCoinFromDec(cfg.GasToken(), cfg.FallbackGasPrice()), }, nil @@ -141,12 +144,12 @@ func (c *chain) TxManager() adapters.TxManager { return c.txm } -func (c *chain) Reader(name string) (cosmosclient.Reader, error) { +func (c *chain) Reader(name string) (client.Reader, error) { return c.getClient(name) } // getClient returns a client, optionally requiring a specific node by name. -func (c *chain) getClient(name string) (cosmosclient.ReaderWriter, error) { +func (c *chain) getClient(name string) (client.ReaderWriter, error) { var node db.Node if name == "" { // Any node nodes, err := c.cfg.ListNodes() @@ -171,7 +174,7 @@ func (c *chain) getClient(name string) (cosmosclient.ReaderWriter, error) { return nil, fmt.Errorf("failed to create client for chain %s with node %s: wrong chain id %s", c.id, name, node.CosmosChainID) } } - client, err := cosmosclient.NewClient(c.id, node.TendermintURL, DefaultRequestTimeout, logger.Named(c.lggr, "Client."+name)) + client, err := client.NewClient(c.id, node.TendermintURL, defaultRequestTimeout, logger.Named(c.lggr, "Client."+name)) if err != nil { return nil, fmt.Errorf("failed to create client: %w", err) } @@ -224,7 +227,41 @@ func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken } func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return chains.ErrLOOPPUnsupported + fromAcc, err := sdk.AccAddressFromBech32(from) + if err != nil { + return fmt.Errorf("failed to parse from account: %s", fromAcc) + } + toAcc, err := sdk.AccAddressFromBech32(to) + if err != nil { + return fmt.Errorf("failed to parse from account: %s", toAcc) + } + coin := sdk.Coin{Amount: sdk.NewIntFromBigInt(amount), Denom: c.Config().GasToken()} + + txm := c.TxManager() + + if balanceCheck { + var reader client.Reader + reader, err = c.Reader("") + if err != nil { + return fmt.Errorf("chain unreachable: %v", err) + } + gasPrice, err2 := txm.GasPrice() + if err2 != nil { + return fmt.Errorf("gas price unavailable: %v", err2) + } + + err = validateBalance(reader, gasPrice, fromAcc, coin) + if err != nil { + return fmt.Errorf("failed to validate balance: %v", err) + } + } + + sendMsg := bank.NewMsgSend(fromAcc, toAcc, sdk.Coins{coin}) + _, err = txm.Enqueue("", sendMsg) + if err != nil { + return fmt.Errorf("failed to enqueue tx: %w", err) + } + return nil } // TODO BCF-2602 statuses are static for non-evm chain and should be dynamic @@ -247,3 +284,34 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, } return stats, total, nil } + +func nodeStatus(n *coscfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { + var s relaytypes.NodeStatus + s.ChainID = id + s.Name = *n.Name + b, err := toml.Marshal(n) + if err != nil { + return relaytypes.NodeStatus{}, err + } + s.Config = string(b) + return s, nil +} + +// maxGasUsedTransfer is an upper bound on how much gas we expect a MsgSend for a single coin to use. +const maxGasUsedTransfer = 100_000 + +// validateBalance validates that fromAddr's balance can cover coin, including fees at gasPrice. +func validateBalance(reader client.Reader, gasPrice sdk.DecCoin, fromAddr sdk.AccAddress, coin sdk.Coin) error { + balance, err := reader.Balance(fromAddr, coin.GetDenom()) + if err != nil { + return err + } + + fee := gasPrice.Amount.MulInt64(maxGasUsedTransfer).RoundInt() + need := coin.Amount.Add(fee) + + if balance.Amount.LT(need) { + return errors.Errorf("balance %q is too low for this transaction to be executed: need %s total, including %s fee", balance, need, fee) + } + return nil +} diff --git a/core/chains/cosmos/config.go b/core/chains/cosmos/config.go deleted file mode 100644 index 8b4c8c13f3..0000000000 --- a/core/chains/cosmos/config.go +++ /dev/null @@ -1,272 +0,0 @@ -package cosmos - -import ( - "fmt" - "net/url" - "slices" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/pelletier/go-toml/v2" - "github.com/shopspring/decimal" - "go.uber.org/multierr" - - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" -) - -type CosmosConfigs []*CosmosConfig - -func (cs CosmosConfigs) validateKeys() (err error) { - // Unique chain IDs - chainIDs := config.UniqueStrings{} - for i, c := range cs { - if chainIDs.IsDupe(c.ChainID) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.ChainID", i), *c.ChainID)) - } - } - - // Unique node names - names := config.UniqueStrings{} - for i, c := range cs { - for j, n := range c.Nodes { - if names.IsDupe(n.Name) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.Name", i, j), *n.Name)) - } - } - } - - // Unique TendermintURLs - urls := config.UniqueStrings{} - for i, c := range cs { - for j, n := range c.Nodes { - u := (*url.URL)(n.TendermintURL) - if urls.IsDupeFmt(u) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.TendermintURL", i, j), u.String())) - } - } - } - return - -} - -func (cs CosmosConfigs) ValidateConfig() (err error) { - return cs.validateKeys() -} - -func (cs *CosmosConfigs) SetFrom(fs *CosmosConfigs) (err error) { - if err1 := fs.validateKeys(); err1 != nil { - return err1 - } - for _, f := range *fs { - if f.ChainID == nil { - *cs = append(*cs, f) - } else if i := slices.IndexFunc(*cs, func(c *CosmosConfig) bool { - return c.ChainID != nil && *c.ChainID == *f.ChainID - }); i == -1 { - *cs = append(*cs, f) - } else { - (*cs)[i].SetFrom(f) - } - } - return -} - -func nodeStatus(n *coscfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { - var s relaytypes.NodeStatus - s.ChainID = id - s.Name = *n.Name - b, err := toml.Marshal(n) - if err != nil { - return relaytypes.NodeStatus{}, err - } - s.Config = string(b) - return s, nil -} - -type CosmosNodes []*coscfg.Node - -func (ns *CosmosNodes) SetFrom(fs *CosmosNodes) { - for _, f := range *fs { - if f.Name == nil { - *ns = append(*ns, f) - } else if i := slices.IndexFunc(*ns, func(n *coscfg.Node) bool { - return n.Name != nil && *n.Name == *f.Name - }); i == -1 { - *ns = append(*ns, f) - } else { - setFromNode((*ns)[i], f) - } - } -} - -func setFromNode(n, f *coscfg.Node) { - if f.Name != nil { - n.Name = f.Name - } - if f.TendermintURL != nil { - n.TendermintURL = f.TendermintURL - } -} - -func legacyNode(n *coscfg.Node, id string) db.Node { - return db.Node{ - Name: *n.Name, - CosmosChainID: id, - TendermintURL: (*url.URL)(n.TendermintURL).String(), - } -} - -type CosmosConfig struct { - ChainID *string - // Do not access directly. Use [IsEnabled] - Enabled *bool - coscfg.Chain - Nodes CosmosNodes -} - -func (c *CosmosConfig) IsEnabled() bool { - return c.Enabled == nil || *c.Enabled -} - -func (c *CosmosConfig) SetFrom(f *CosmosConfig) { - if f.ChainID != nil { - c.ChainID = f.ChainID - } - if f.Enabled != nil { - c.Enabled = f.Enabled - } - setFromChain(&c.Chain, &f.Chain) - c.Nodes.SetFrom(&f.Nodes) -} - -func setFromChain(c, f *coscfg.Chain) { - if f.Bech32Prefix != nil { - c.Bech32Prefix = f.Bech32Prefix - } - if f.BlockRate != nil { - c.BlockRate = f.BlockRate - } - if f.BlocksUntilTxTimeout != nil { - c.BlocksUntilTxTimeout = f.BlocksUntilTxTimeout - } - if f.ConfirmPollPeriod != nil { - c.ConfirmPollPeriod = f.ConfirmPollPeriod - } - if f.FallbackGasPrice != nil { - c.FallbackGasPrice = f.FallbackGasPrice - } - if f.GasToken != nil { - c.GasToken = f.GasToken - } - if f.GasLimitMultiplier != nil { - c.GasLimitMultiplier = f.GasLimitMultiplier - } - if f.MaxMsgsPerBatch != nil { - c.MaxMsgsPerBatch = f.MaxMsgsPerBatch - } - if f.OCR2CachePollPeriod != nil { - c.OCR2CachePollPeriod = f.OCR2CachePollPeriod - } - if f.OCR2CacheTTL != nil { - c.OCR2CacheTTL = f.OCR2CacheTTL - } - if f.TxMsgTimeout != nil { - c.TxMsgTimeout = f.TxMsgTimeout - } -} - -func (c *CosmosConfig) ValidateConfig() (err error) { - if c.ChainID == nil { - err = multierr.Append(err, config.ErrMissing{Name: "ChainID", Msg: "required for all chains"}) - } else if *c.ChainID == "" { - err = multierr.Append(err, config.ErrEmpty{Name: "ChainID", Msg: "required for all chains"}) - } - - if len(c.Nodes) == 0 { - err = multierr.Append(err, config.ErrMissing{Name: "Nodes", Msg: "must have at least one node"}) - } - - return -} - -func (c *CosmosConfig) TOMLString() (string, error) { - b, err := toml.Marshal(c) - if err != nil { - return "", err - } - return string(b), nil -} - -var _ coscfg.Config = &CosmosConfig{} - -func (c *CosmosConfig) Bech32Prefix() string { - return *c.Chain.Bech32Prefix -} - -func (c *CosmosConfig) BlockRate() time.Duration { - return c.Chain.BlockRate.Duration() -} - -func (c *CosmosConfig) BlocksUntilTxTimeout() int64 { - return *c.Chain.BlocksUntilTxTimeout -} - -func (c *CosmosConfig) ConfirmPollPeriod() time.Duration { - return c.Chain.ConfirmPollPeriod.Duration() -} - -func (c *CosmosConfig) FallbackGasPrice() sdk.Dec { - return sdkDecFromDecimal(c.Chain.FallbackGasPrice) -} - -func (c *CosmosConfig) GasToken() string { - return *c.Chain.GasToken -} - -func (c *CosmosConfig) GasLimitMultiplier() float64 { - return c.Chain.GasLimitMultiplier.InexactFloat64() -} - -func (c *CosmosConfig) MaxMsgsPerBatch() int64 { - return *c.Chain.MaxMsgsPerBatch -} - -func (c *CosmosConfig) OCR2CachePollPeriod() time.Duration { - return c.Chain.OCR2CachePollPeriod.Duration() -} - -func (c *CosmosConfig) OCR2CacheTTL() time.Duration { - return c.Chain.OCR2CacheTTL.Duration() -} - -func (c *CosmosConfig) TxMsgTimeout() time.Duration { - return c.Chain.TxMsgTimeout.Duration() -} - -func sdkDecFromDecimal(d *decimal.Decimal) sdk.Dec { - i := d.Shift(sdk.Precision) - return sdk.NewDecFromBigIntWithPrec(i.BigInt(), sdk.Precision) -} - -func (c *CosmosConfig) GetNode(name string) (db.Node, error) { - for _, n := range c.Nodes { - if *n.Name == name { - return legacyNode(n, *c.ChainID), nil - } - } - return db.Node{}, fmt.Errorf("%w: node %q", chains.ErrNotFound, name) -} - -func (c *CosmosConfig) ListNodes() ([]db.Node, error) { - var allNodes []db.Node - for _, n := range c.Nodes { - allNodes = append(allNodes, legacyNode(n, *c.ChainID)) - } - return allNodes, nil -} diff --git a/core/chains/cosmos/config_test.go b/core/chains/cosmos/config_test.go deleted file mode 100644 index 54f91a1362..0000000000 --- a/core/chains/cosmos/config_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package cosmos - -import ( - "reflect" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/shopspring/decimal" - "github.com/stretchr/testify/assert" - - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" -) - -func Test_sdkDecFromDecimal(t *testing.T) { - tests := []string{ - "0.0", - "0.1", - "1.0", - "0.000000000000000001", - } - for _, tt := range tests { - t.Run(tt, func(t *testing.T) { - val := decimal.RequireFromString(tt) - exp := sdk.MustNewDecFromStr(tt) - assert.Equal(t, exp, sdkDecFromDecimal(&val)) - }) - } -} - -func TestCosmosConfig_GetNode(t *testing.T) { - type fields struct { - ChainID *string - Nodes CosmosNodes - } - type args struct { - name string - } - tests := []struct { - name string - fields fields - args args - want db.Node - wantErr bool - }{ - { - name: "not found", - args: args{ - name: "not a node", - }, - fields: fields{Nodes: CosmosNodes{}}, - want: db.Node{}, - wantErr: true, - }, - { - name: "success", - args: args{ - name: "node", - }, - fields: fields{ - ChainID: ptr("chainID"), - Nodes: []*coscfg.Node{ - &coscfg.Node{ - Name: ptr("node"), - TendermintURL: &utils.URL{}, - }, - }}, - want: db.Node{ - CosmosChainID: "chainID", - Name: "node", - TendermintURL: "", - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := &CosmosConfig{ - Nodes: tt.fields.Nodes, - ChainID: tt.fields.ChainID, - } - got, err := c.GetNode(tt.args.name) - if (err != nil) != tt.wantErr { - t.Errorf("CosmosConfig.GetNode() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("CosmosConfig.GetNode() = %v, want %v", got, tt.want) - } - }) - } -} - -func ptr[T any](t T) *T { - return &t -} diff --git a/core/chains/cosmos/cosmostxm/helpers_test.go b/core/chains/cosmos/cosmostxm/helpers_test.go index ad93189082..a2dfbbeed8 100644 --- a/core/chains/cosmos/cosmostxm/helpers_test.go +++ b/core/chains/cosmos/cosmostxm/helpers_test.go @@ -1,36 +1,8 @@ package cosmostxm -import ( - "context" - "time" +import "golang.org/x/exp/maps" - sdk "github.com/cosmos/cosmos-sdk/types" - "golang.org/x/exp/maps" - - cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" -) - -func (txm *Txm) ORM() *ORM { - return txm.orm -} - -func (txm *Txm) ConfirmTx(ctx context.Context, tc cosmosclient.Reader, txHash string, broadcasted []int64, maxPolls int, pollPeriod time.Duration) error { - return txm.confirmTx(ctx, tc, txHash, broadcasted, maxPolls, pollPeriod) -} - -func (txm *Txm) ConfirmAnyUnconfirmed(ctx context.Context) { - txm.confirmAnyUnconfirmed(ctx) -} - -func (txm *Txm) MarshalMsg(msg sdk.Msg) (string, []byte, error) { - return txm.marshalMsg(msg) -} - -func (txm *Txm) SendMsgBatch(ctx context.Context) { - txm.sendMsgBatch(ctx) -} - -func (ka *KeystoreAdapter) Accounts(ctx context.Context) ([]string, error) { +func (ka *keystoreAdapter) Accounts() ([]string, error) { ka.mutex.Lock() defer ka.mutex.Unlock() err := ka.updateMappingLocked() diff --git a/core/chains/cosmos/cosmostxm/key_wrapper.go b/core/chains/cosmos/cosmostxm/key_wrapper.go index 1d2d686c8c..e03dfd89b8 100644 --- a/core/chains/cosmos/cosmostxm/key_wrapper.go +++ b/core/chains/cosmos/cosmostxm/key_wrapper.go @@ -8,15 +8,15 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) -// KeyWrapper uses a KeystoreAdapter to implement the cosmos-sdk PrivKey interface for a specific key. +// KeyWrapper uses a keystoreAdapter to implement the cosmos-sdk PrivKey interface for a specific key. type KeyWrapper struct { - adapter *KeystoreAdapter + adapter *keystoreAdapter account string } var _ cryptotypes.PrivKey = &KeyWrapper{} -func NewKeyWrapper(adapter *KeystoreAdapter, account string) *KeyWrapper { +func NewKeyWrapper(adapter *keystoreAdapter, account string) *KeyWrapper { return &KeyWrapper{ adapter: adapter, account: account, diff --git a/core/chains/cosmos/cosmostxm/keystore_adapter.go b/core/chains/cosmos/cosmostxm/keystore_adapter.go index c8556015c6..6b360dde98 100644 --- a/core/chains/cosmos/cosmostxm/keystore_adapter.go +++ b/core/chains/cosmos/cosmostxm/keystore_adapter.go @@ -21,23 +21,23 @@ type accountInfo struct { PubKey *secp256k1.PubKey } -// An adapter for a Cosmos loop.Keystore to translate public keys into bech32-prefixed account addresses. -type KeystoreAdapter struct { +// keystoreAdapter adapts a Cosmos loop.Keystore to translate public keys into bech32-prefixed account addresses. +type keystoreAdapter struct { keystore loop.Keystore accountPrefix string mutex sync.RWMutex addressToPubKey map[string]*accountInfo } -func NewKeystoreAdapter(keystore loop.Keystore, accountPrefix string) *KeystoreAdapter { - return &KeystoreAdapter{ +func newKeystoreAdapter(keystore loop.Keystore, accountPrefix string) *keystoreAdapter { + return &keystoreAdapter{ keystore: keystore, accountPrefix: accountPrefix, addressToPubKey: make(map[string]*accountInfo), } } -func (ka *KeystoreAdapter) updateMappingLocked() error { +func (ka *keystoreAdapter) updateMappingLocked() error { accounts, err := ka.keystore.Accounts(context.Background()) if err != nil { return err @@ -90,7 +90,7 @@ func (ka *KeystoreAdapter) updateMappingLocked() error { return nil } -func (ka *KeystoreAdapter) lookup(id string) (*accountInfo, error) { +func (ka *keystoreAdapter) lookup(id string) (*accountInfo, error) { ka.mutex.RLock() ai, ok := ka.addressToPubKey[id] ka.mutex.RUnlock() @@ -111,7 +111,7 @@ func (ka *KeystoreAdapter) lookup(id string) (*accountInfo, error) { return ai, nil } -func (ka *KeystoreAdapter) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { +func (ka *keystoreAdapter) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { accountInfo, err := ka.lookup(id) if err != nil { return nil, err @@ -120,7 +120,7 @@ func (ka *KeystoreAdapter) Sign(ctx context.Context, id string, hash []byte) ([] } // Returns the cosmos PubKey associated with the prefixed address. -func (ka *KeystoreAdapter) PubKey(address string) (cryptotypes.PubKey, error) { +func (ka *keystoreAdapter) PubKey(address string) (cryptotypes.PubKey, error) { accountInfo, err := ka.lookup(address) if err != nil { return nil, err diff --git a/core/chains/cosmos/cosmostxm/orm_test.go b/core/chains/cosmos/cosmostxm/orm_test.go index c741874936..3cee25bac1 100644 --- a/core/chains/cosmos/cosmostxm/orm_test.go +++ b/core/chains/cosmos/cosmostxm/orm_test.go @@ -1,4 +1,4 @@ -package cosmostxm_test +package cosmostxm import ( "testing" @@ -8,7 +8,6 @@ import ( cosmosdb "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -19,7 +18,7 @@ func TestORM(t *testing.T) { lggr := logger.TestLogger(t) logCfg := pgtest.NewQConfig(true) chainID := cosmostest.RandomChainID() - o := cosmostxm.NewORM(chainID, db, lggr, logCfg) + o := NewORM(chainID, db, lggr, logCfg) // Create mid, err := o.InsertMsg("0x123", "", []byte("hello")) diff --git a/core/chains/cosmos/cosmostxm/txm.go b/core/chains/cosmos/cosmostxm/txm.go index 8806d97a9f..712e1b8fc7 100644 --- a/core/chains/cosmos/cosmostxm/txm.go +++ b/core/chains/cosmos/cosmostxm/txm.go @@ -47,7 +47,7 @@ type Txm struct { orm *ORM lggr logger.Logger tc func() (cosmosclient.ReaderWriter, error) - keystoreAdapter *KeystoreAdapter + keystoreAdapter *keystoreAdapter stop, done chan struct{} cfg coscfg.Config gpe cosmosclient.ComposedGasPriceEstimator @@ -56,7 +56,7 @@ type Txm struct { // NewTxm creates a txm. Uses simulation so should only be used to send txes to trusted contracts i.e. OCR. func NewTxm(db *sqlx.DB, tc func() (cosmosclient.ReaderWriter, error), gpe cosmosclient.ComposedGasPriceEstimator, chainID string, cfg coscfg.Config, ks loop.Keystore, lggr logger.Logger, logCfg pg.QConfig, eb pg.EventBroadcaster) *Txm { lggr = logger.Named(lggr, "Txm") - keystoreAdapter := NewKeystoreAdapter(ks, cfg.Bech32Prefix()) + keystoreAdapter := newKeystoreAdapter(ks, cfg.Bech32Prefix()) return &Txm{ eb: eb, orm: NewORM(chainID, db, lggr, logCfg), diff --git a/core/chains/cosmos/cosmostxm/txm_internal_test.go b/core/chains/cosmos/cosmostxm/txm_internal_test.go index 66a8c98b63..f29f130cae 100644 --- a/core/chains/cosmos/cosmostxm/txm_internal_test.go +++ b/core/chains/cosmos/cosmostxm/txm_internal_test.go @@ -1,4 +1,4 @@ -package cosmostxm_test +package cosmostxm import ( "fmt" @@ -21,8 +21,6 @@ import ( cosmosdb "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" relayutils "github.com/smartcontractkit/chainlink-relay/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -31,7 +29,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func generateExecuteMsg(t *testing.T, msg []byte, from, to cosmostypes.AccAddress) cosmostypes.Msg { +func generateExecuteMsg(msg []byte, from, to cosmostypes.AccAddress) cosmostypes.Msg { return &wasmtypes.MsgExecuteContract{ Sender: from.String(), Contract: to.String(), @@ -59,8 +57,8 @@ func TestTxm(t *testing.T) { } loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - adapter := cosmostxm.NewKeystoreAdapter(loopKs, "wasm") - accounts, err := adapter.Accounts(testutils.Context(t)) + adapter := newKeystoreAdapter(loopKs, "wasm") + accounts, err := adapter.Accounts() require.NoError(t, err) require.Equal(t, len(accounts), 4) @@ -77,7 +75,7 @@ func TestTxm(t *testing.T) { chainID := cosmostest.RandomChainID() two := int64(2) gasToken := "ucosm" - cfg := &cosmos.CosmosConfig{Chain: coscfg.Chain{ + cfg := &coscfg.TOMLConfig{Chain: coscfg.Chain{ MaxMsgsPerBatch: &two, GasToken: &gasToken, }} @@ -94,10 +92,10 @@ func TestTxm(t *testing.T) { tc := newReaderWriterMock(t) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, logCfg, nil) + txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, logCfg, nil) // Enqueue a single msg, then send it in a batch - id1, err := txm.Enqueue(contract.String(), generateExecuteMsg(t, []byte(`1`), sender1, contract)) + id1, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`1`), sender1, contract)) require.NoError(t, err) tc.On("Account", mock.Anything).Return(uint64(0), uint64(0), nil) tc.On("BatchSimulateUnsigned", mock.Anything, mock.Anything).Return(&cosmosclient.BatchSimResults{ @@ -118,10 +116,10 @@ func TestTxm(t *testing.T) { txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} tc.On("Broadcast", mock.Anything, mock.Anything).Return(&txtypes.BroadcastTxResponse{TxResponse: txResp}, nil) tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil) - txm.SendMsgBatch(testutils.Context(t)) + txm.sendMsgBatch(testutils.Context(t)) // Should be in completed state - completed, err := txm.ORM().GetMsgs(id1) + completed, err := txm.orm.GetMsgs(id1) require.NoError(t, err) require.Equal(t, 1, len(completed)) assert.Equal(t, completed[0].State, cosmosdb.Confirmed) @@ -131,11 +129,11 @@ func TestTxm(t *testing.T) { tc := newReaderWriterMock(t) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) + txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) - id1, err := txm.Enqueue(contract.String(), generateExecuteMsg(t, []byte(`0`), sender1, contract)) + id1, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`0`), sender1, contract)) require.NoError(t, err) - id2, err := txm.Enqueue(contract.String(), generateExecuteMsg(t, []byte(`1`), sender2, contract)) + id2, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`1`), sender2, contract)) require.NoError(t, err) tc.On("Account", mock.Anything).Return(uint64(0), uint64(0), nil).Once() @@ -173,10 +171,10 @@ func TestTxm(t *testing.T) { txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} tc.On("Broadcast", mock.Anything, mock.Anything).Return(&txtypes.BroadcastTxResponse{TxResponse: txResp}, nil).Once() tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil).Once() - txm.SendMsgBatch(testutils.Context(t)) + txm.sendMsgBatch(testutils.Context(t)) // Should be in completed state - completed, err := txm.ORM().GetMsgs(id1, id2) + completed, err := txm.orm.GetMsgs(id1, id2) require.NoError(t, err) require.Equal(t, 2, len(completed)) assert.Equal(t, cosmosdb.Errored, completed[0].State) // cancelled @@ -187,11 +185,11 @@ func TestTxm(t *testing.T) { tc := newReaderWriterMock(t) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) + txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) - id1, err := txm.Enqueue(contract.String(), generateExecuteMsg(t, []byte(`0`), sender1, contract)) + id1, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`0`), sender1, contract)) require.NoError(t, err) - id2, err := txm.Enqueue(contract2.String(), generateExecuteMsg(t, []byte(`1`), sender2, contract2)) + id2, err := txm.Enqueue(contract2.String(), generateExecuteMsg([]byte(`1`), sender2, contract2)) require.NoError(t, err) ids := []int64{id1, id2} senders := []string{sender1.String(), sender2.String()} @@ -233,10 +231,10 @@ func TestTxm(t *testing.T) { txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} tc.On("Broadcast", mock.Anything, mock.Anything).Return(&txtypes.BroadcastTxResponse{TxResponse: txResp}, nil).Twice() tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil).Twice() - txm.SendMsgBatch(testutils.Context(t)) + txm.sendMsgBatch(testutils.Context(t)) // Should be in completed state - completed, err := txm.ORM().GetMsgs(id1, id2) + completed, err := txm.orm.GetMsgs(id1, id2) require.NoError(t, err) require.Equal(t, 2, len(completed)) assert.Equal(t, cosmosdb.Confirmed, completed[0].State) @@ -251,15 +249,15 @@ func TestTxm(t *testing.T) { }, errors.New("not found")).Twice() tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) - i, err := txm.ORM().InsertMsg("blah", "", []byte{0x01}) + txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) + i, err := txm.orm.InsertMsg("blah", "", []byte{0x01}) require.NoError(t, err) txh := "0x123" - require.NoError(t, txm.ORM().UpdateMsgs([]int64{i}, cosmosdb.Started, &txh)) - require.NoError(t, txm.ORM().UpdateMsgs([]int64{i}, cosmosdb.Broadcasted, &txh)) - err = txm.ConfirmTx(testutils.Context(t), tc, txh, []int64{i}, 2, 1*time.Millisecond) + require.NoError(t, txm.orm.UpdateMsgs([]int64{i}, cosmosdb.Started, &txh)) + require.NoError(t, txm.orm.UpdateMsgs([]int64{i}, cosmosdb.Broadcasted, &txh)) + err = txm.confirmTx(testutils.Context(t), tc, txh, []int64{i}, 2, 1*time.Millisecond) require.NoError(t, err) - m, err := txm.ORM().GetMsgs(i) + m, err := txm.orm.GetMsgs(i) require.NoError(t, err) require.Equal(t, 1, len(m)) assert.Equal(t, cosmosdb.Errored, m[0].State) @@ -282,31 +280,31 @@ func TestTxm(t *testing.T) { }, nil).Once() tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) + txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) // Insert and broadcast 3 msgs with different txhashes. - id1, err := txm.ORM().InsertMsg("blah", "", []byte{0x01}) + id1, err := txm.orm.InsertMsg("blah", "", []byte{0x01}) require.NoError(t, err) - id2, err := txm.ORM().InsertMsg("blah", "", []byte{0x02}) + id2, err := txm.orm.InsertMsg("blah", "", []byte{0x02}) require.NoError(t, err) - id3, err := txm.ORM().InsertMsg("blah", "", []byte{0x03}) + id3, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id1}, cosmosdb.Started, &txHash1) + err = txm.orm.UpdateMsgs([]int64{id1}, cosmosdb.Started, &txHash1) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id2}, cosmosdb.Started, &txHash2) + err = txm.orm.UpdateMsgs([]int64{id2}, cosmosdb.Started, &txHash2) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id3}, cosmosdb.Started, &txHash3) + err = txm.orm.UpdateMsgs([]int64{id3}, cosmosdb.Started, &txHash3) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id1}, cosmosdb.Broadcasted, &txHash1) + err = txm.orm.UpdateMsgs([]int64{id1}, cosmosdb.Broadcasted, &txHash1) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id2}, cosmosdb.Broadcasted, &txHash2) + err = txm.orm.UpdateMsgs([]int64{id2}, cosmosdb.Broadcasted, &txHash2) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id3}, cosmosdb.Broadcasted, &txHash3) + err = txm.orm.UpdateMsgs([]int64{id3}, cosmosdb.Broadcasted, &txHash3) require.NoError(t, err) // Confirm them as in a restart while confirming scenario - txm.ConfirmAnyUnconfirmed(testutils.Context(t)) - msgs, err := txm.ORM().GetMsgs(id1, id2, id3) + txm.confirmAnyUnconfirmed(testutils.Context(t)) + msgs, err := txm.orm.GetMsgs(id1, id2, id3) require.NoError(t, err) require.Equal(t, 3, len(msgs)) assert.Equal(t, cosmosdb.Confirmed, msgs[0].State) @@ -320,33 +318,33 @@ func TestTxm(t *testing.T) { require.NoError(t, err) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } two := int64(2) - cfgShortExpiry := &cosmos.CosmosConfig{Chain: coscfg.Chain{ + cfgShortExpiry := &coscfg.TOMLConfig{Chain: coscfg.Chain{ MaxMsgsPerBatch: &two, TxMsgTimeout: &timeout, }} cfgShortExpiry.SetDefaults() loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfgShortExpiry, loopKs, lggr, pgtest.NewQConfig(true), nil) + txm := NewTxm(db, tcFn, *gpe, chainID, cfgShortExpiry, loopKs, lggr, pgtest.NewQConfig(true), nil) // Send a single one expired - id1, err := txm.ORM().InsertMsg("blah", "", []byte{0x03}) + id1, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) require.NoError(t, err) time.Sleep(1 * time.Millisecond) - txm.SendMsgBatch(testutils.Context(t)) + txm.sendMsgBatch(testutils.Context(t)) // Should be marked errored - m, err := txm.ORM().GetMsgs(id1) + m, err := txm.orm.GetMsgs(id1) require.NoError(t, err) assert.Equal(t, cosmosdb.Errored, m[0].State) // Send a batch which is all expired - id2, err := txm.ORM().InsertMsg("blah", "", []byte{0x03}) + id2, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) require.NoError(t, err) - id3, err := txm.ORM().InsertMsg("blah", "", []byte{0x03}) + id3, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) require.NoError(t, err) time.Sleep(1 * time.Millisecond) - txm.SendMsgBatch(testutils.Context(t)) + txm.sendMsgBatch(testutils.Context(t)) require.NoError(t, err) - ms, err := txm.ORM().GetMsgs(id2, id3) + ms, err := txm.orm.GetMsgs(id2, id3) require.NoError(t, err) assert.Equal(t, cosmosdb.Errored, ms[0].State) assert.Equal(t, cosmosdb.Errored, ms[1].State) @@ -367,17 +365,17 @@ func TestTxm(t *testing.T) { tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } two := int64(2) - cfgMaxMsgs := &cosmos.CosmosConfig{Chain: coscfg.Chain{ + cfgMaxMsgs := &coscfg.TOMLConfig{Chain: coscfg.Chain{ MaxMsgsPerBatch: &two, }} cfgMaxMsgs.SetDefaults() loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfgMaxMsgs, loopKs, lggr, pgtest.NewQConfig(true), nil) + txm := NewTxm(db, tcFn, *gpe, chainID, cfgMaxMsgs, loopKs, lggr, pgtest.NewQConfig(true), nil) // Leftover started is processed - msg1 := generateExecuteMsg(t, []byte{0x03}, sender1, contract) + msg1 := generateExecuteMsg([]byte{0x03}, sender1, contract) id1 := mustInsertMsg(t, txm, contract.String(), msg1) - require.NoError(t, txm.ORM().UpdateMsgs([]int64{id1}, cosmosdb.Started, nil)) + require.NoError(t, txm.orm.UpdateMsgs([]int64{id1}, cosmosdb.Started, nil)) msgs := cosmosclient.SimMsgs{{ID: id1, Msg: &wasmtypes.MsgExecuteContract{ Sender: sender1.String(), Msg: []byte{0x03}, @@ -386,16 +384,16 @@ func TestTxm(t *testing.T) { tc.On("BatchSimulateUnsigned", msgs, mock.Anything). Return(&cosmosclient.BatchSimResults{Failed: nil, Succeeded: msgs}, nil).Once() time.Sleep(1 * time.Millisecond) - txm.SendMsgBatch(testutils.Context(t)) - m, err := txm.ORM().GetMsgs(id1) + txm.sendMsgBatch(testutils.Context(t)) + m, err := txm.orm.GetMsgs(id1) require.NoError(t, err) assert.Equal(t, cosmosdb.Confirmed, m[0].State) // Leftover started is not cancelled - msg2 := generateExecuteMsg(t, []byte{0x04}, sender1, contract) - msg3 := generateExecuteMsg(t, []byte{0x05}, sender1, contract) + msg2 := generateExecuteMsg([]byte{0x04}, sender1, contract) + msg3 := generateExecuteMsg([]byte{0x05}, sender1, contract) id2 := mustInsertMsg(t, txm, contract.String(), msg2) - require.NoError(t, txm.ORM().UpdateMsgs([]int64{id2}, cosmosdb.Started, nil)) + require.NoError(t, txm.orm.UpdateMsgs([]int64{id2}, cosmosdb.Started, nil)) time.Sleep(time.Millisecond) // ensure != CreatedAt id3 := mustInsertMsg(t, txm, contract.String(), msg3) msgs = cosmosclient.SimMsgs{{ID: id2, Msg: &wasmtypes.MsgExecuteContract{ @@ -410,19 +408,19 @@ func TestTxm(t *testing.T) { tc.On("BatchSimulateUnsigned", msgs, mock.Anything). Return(&cosmosclient.BatchSimResults{Failed: nil, Succeeded: msgs}, nil).Once() time.Sleep(1 * time.Millisecond) - txm.SendMsgBatch(testutils.Context(t)) + txm.sendMsgBatch(testutils.Context(t)) require.NoError(t, err) - ms, err := txm.ORM().GetMsgs(id2, id3) + ms, err := txm.orm.GetMsgs(id2, id3) require.NoError(t, err) assert.Equal(t, cosmosdb.Confirmed, ms[0].State) assert.Equal(t, cosmosdb.Confirmed, ms[1].State) }) } -func mustInsertMsg(t *testing.T, txm *cosmostxm.Txm, contractID string, msg cosmostypes.Msg) int64 { - typeURL, raw, err := txm.MarshalMsg(msg) +func mustInsertMsg(t *testing.T, txm *Txm, contractID string, msg cosmostypes.Msg) int64 { + typeURL, raw, err := txm.marshalMsg(msg) require.NoError(t, err) - id, err := txm.ORM().InsertMsg(contractID, typeURL, raw) + id, err := txm.orm.InsertMsg(contractID, typeURL, raw) require.NoError(t, err) return id } diff --git a/core/chains/cosmos/cosmostxm/txm_test.go b/core/chains/cosmos/cosmostxm/txm_test.go index a7a8d0280c..25ac9e8d9e 100644 --- a/core/chains/cosmos/cosmostxm/txm_test.go +++ b/core/chains/cosmos/cosmostxm/txm_test.go @@ -2,151 +2,120 @@ package cosmostxm_test -import ( - "fmt" - "testing" - "time" - - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/cometbft/cometbft/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" - txtypes "github.com/cosmos/cosmos-sdk/types/tx" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - . "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" -) - -func TestTxm_Integration(t *testing.T) { - chainID := cosmostest.RandomChainID() - cosmosChain := coscfg.Chain{} - cosmosChain.SetDefaults() - fallbackGasPrice := sdk.NewDecCoinFromDec(*cosmosChain.GasToken, sdk.MustNewDecFromStr("0.01")) - chainConfig := cosmos.CosmosConfig{ChainID: &chainID, Enabled: ptr(true), Chain: cosmosChain} - cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "cosmos_txm", func(c *chainlink.Config, s *chainlink.Secrets) { - c.Cosmos = cosmos.CosmosConfigs{&chainConfig} - }) - lggr := logger.TestLogger(t) - logCfg := pgtest.NewQConfig(true) - gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ - cosmosclient.NewFixedGasPriceEstimator(map[string]sdk.DecCoin{ - *cosmosChain.GasToken: fallbackGasPrice, - }, - lggr.(logger.SugaredLogger), - ), - }, lggr) - orm := cosmostxm.NewORM(chainID, db, lggr, logCfg) - eb := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, lggr, uuid.New()) - require.NoError(t, eb.Start(testutils.Context(t))) - t.Cleanup(func() { require.NoError(t, eb.Close()) }) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) - zeConfig := sdk.GetConfig() - fmt.Println(zeConfig) - accounts, testdir, tendermintURL := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.GasToken) - tc, err := cosmosclient.NewClient(chainID, tendermintURL, cosmos.DefaultRequestTimeout, lggr) - require.NoError(t, err) - - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - keystoreAdapter := cosmostxm.NewKeystoreAdapter(loopKs, *cosmosChain.Bech32Prefix) - - // First create a transmitter key and fund it with 1k native tokens - require.NoError(t, ks.Unlock("blah")) - err = ks.Cosmos().EnsureKey() - require.NoError(t, err) - ksAccounts, err := keystoreAdapter.Accounts(testutils.Context(t)) - require.NoError(t, err) - transmitterAddress := ksAccounts[0] - transmitterID, err := sdk.AccAddressFromBech32(transmitterAddress) - require.NoError(t, err) - an, sn, err := tc.Account(accounts[0].Address) - require.NoError(t, err) - resp, err := tc.SignAndBroadcast([]sdk.Msg{banktypes.NewMsgSend(accounts[0].Address, transmitterID, sdk.NewCoins(sdk.NewInt64Coin(*cosmosChain.GasToken, 100000)))}, - an, sn, gpe.GasPrices()[*cosmosChain.GasToken], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) - tx, success := cosmosclient.AwaitTxCommitted(t, tc, resp.TxResponse.TxHash) - require.True(t, success) - require.Equal(t, types.CodeTypeOK, tx.TxResponse.Code) - require.NoError(t, err) - - // TODO: find a way to pull this test artifact from - // the chainlink-cosmos repo instead of copying it to cores testdata - contractID := cosmosclient.DeployTestContract(t, tendermintURL, chainID, *cosmosChain.GasToken, accounts[0], cosmosclient.Account{ - Name: "transmitter", - PrivateKey: cosmostxm.NewKeyWrapper(keystoreAdapter, transmitterAddress), - Address: transmitterID, - }, tc, testdir, "../../../testdata/cosmos/my_first_contract.wasm") - - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - // Start txm - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, &chainConfig, loopKs, lggr, pgtest.NewQConfig(true), eb) - require.NoError(t, txm.Start(testutils.Context(t))) - - // Change the contract state - setMsg := &wasmtypes.MsgExecuteContract{ - Sender: transmitterID.String(), - Contract: contractID.String(), - Msg: []byte(`{"reset":{"count":5}}`), - Funds: sdk.Coins{}, - } - _, err = txm.Enqueue(contractID.String(), setMsg) - require.NoError(t, err) - - // Observe the counter gets set eventually - gomega.NewWithT(t).Eventually(func() bool { - d, err := tc.ContractState(contractID, []byte(`{"get_count":{}}`)) - require.NoError(t, err) - t.Log("contract value", string(d)) - return string(d) == `{"count":5}` - }, 20*time.Second, time.Second).Should(gomega.BeTrue()) - // Ensure messages are completed - gomega.NewWithT(t).Eventually(func() bool { - msgs, err := orm.GetMsgsState(Confirmed, 5) - require.NoError(t, err) - return 1 == len(msgs) - }, 5*time.Second, time.Second).Should(gomega.BeTrue()) - - // Ensure invalid msgs are marked as errored - invalidMsg := &wasmtypes.MsgExecuteContract{ - Sender: transmitterID.String(), - Contract: contractID.String(), - Msg: []byte(`{"blah":{"blah":5}}`), - Funds: sdk.Coins{}, - } - _, err = txm.Enqueue(contractID.String(), invalidMsg) - require.NoError(t, err) - _, err = txm.Enqueue(contractID.String(), invalidMsg) - require.NoError(t, err) - _, err = txm.Enqueue(contractID.String(), setMsg) - require.NoError(t, err) - - // Ensure messages are completed - gomega.NewWithT(t).Eventually(func() bool { - succeeded, err := orm.GetMsgsState(Confirmed, 5) - require.NoError(t, err) - errored, err := orm.GetMsgsState(Errored, 5) - require.NoError(t, err) - t.Log("errored", len(errored), "succeeded", len(succeeded)) - return 2 == len(succeeded) && 2 == len(errored) - }, 20*time.Second, time.Second).Should(gomega.BeTrue()) - - // Observe the messages have been marked as completed - require.NoError(t, txm.Close()) -} - -func ptr[T any](t T) *T { return &t } +// TestTxm_Integration is disabled in order to be moved to chainlink-cosmos before DB testing is available +//func TestTxm_Integration(t *testing.T) { +// chainID := cosmostest.RandomChainID() +// cosmosChain := coscfg.Chain{} +// cosmosChain.SetDefaults() +// fallbackGasPrice := sdk.NewDecCoinFromDec(*cosmosChain.GasToken, sdk.MustNewDecFromStr("0.01")) +// chainConfig := cosmos.CosmosConfig{ChainID: &chainID, Enabled: ptr(true), Chain: cosmosChain} +// cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "cosmos_txm", func(c *chainlink.Config, s *chainlink.Secrets) { +// c.Cosmos = cosmos.CosmosConfigs{&chainConfig} +// }) +// lggr := logger.TestLogger(t) +// logCfg := pgtest.NewQConfig(true) +// gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ +// cosmosclient.NewFixedGasPriceEstimator(map[string]sdk.DecCoin{ +// *cosmosChain.GasToken: fallbackGasPrice, +// }, +// lggr.(logger.SugaredLogger), +// ), +// }, lggr) +// orm := cosmostxm.NewORM(chainID, db, lggr, logCfg) +// eb := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, lggr, uuid.New()) +// require.NoError(t, eb.Start(testutils.Context(t))) +// t.Cleanup(func() { require.NoError(t, eb.Close()) }) +// ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) +// zeConfig := sdk.GetConfig() +// fmt.Println(zeConfig) +// accounts, testdir, tendermintURL := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.GasToken) +// tc, err := cosmosclient.NewClient(chainID, tendermintURL, 0, lggr) +// require.NoError(t, err) +// +// loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} +// keystoreAdapter := cosmostxm.NewKeystoreAdapter(loopKs, *cosmosChain.Bech32Prefix) +// +// // First create a transmitter key and fund it with 1k native tokens +// require.NoError(t, ks.Unlock("blah")) +// err = ks.Cosmos().EnsureKey() +// require.NoError(t, err) +// ksAccounts, err := keystoreAdapter.Accounts() +// require.NoError(t, err) +// transmitterAddress := ksAccounts[0] +// transmitterID, err := sdk.AccAddressFromBech32(transmitterAddress) +// require.NoError(t, err) +// an, sn, err := tc.Account(accounts[0].Address) +// require.NoError(t, err) +// resp, err := tc.SignAndBroadcast([]sdk.Msg{banktypes.NewMsgSend(accounts[0].Address, transmitterID, sdk.NewCoins(sdk.NewInt64Coin(*cosmosChain.GasToken, 100000)))}, +// an, sn, gpe.GasPrices()[*cosmosChain.GasToken], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) +// tx, success := cosmosclient.AwaitTxCommitted(t, tc, resp.TxResponse.TxHash) +// require.True(t, success) +// require.Equal(t, types.CodeTypeOK, tx.TxResponse.Code) +// require.NoError(t, err) +// +// // TODO: find a way to pull this test artifact from +// // the chainlink-cosmos repo instead of copying it to cores testdata +// contractID := cosmosclient.DeployTestContract(t, tendermintURL, chainID, *cosmosChain.GasToken, accounts[0], cosmosclient.Account{ +// Name: "transmitter", +// PrivateKey: cosmostxm.NewKeyWrapper(keystoreAdapter, transmitterAddress), +// Address: transmitterID, +// }, tc, testdir, "../../../testdata/cosmos/my_first_contract.wasm") +// +// tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } +// // Start txm +// txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, &chainConfig, loopKs, lggr, pgtest.NewQConfig(true), eb) +// require.NoError(t, txm.Start(testutils.Context(t))) +// +// // Change the contract state +// setMsg := &wasmtypes.MsgExecuteContract{ +// Sender: transmitterID.String(), +// Contract: contractID.String(), +// Msg: []byte(`{"reset":{"count":5}}`), +// Funds: sdk.Coins{}, +// } +// _, err = txm.Enqueue(contractID.String(), setMsg) +// require.NoError(t, err) +// +// // Observe the counter gets set eventually +// gomega.NewWithT(t).Eventually(func() bool { +// d, err := tc.ContractState(contractID, []byte(`{"get_count":{}}`)) +// require.NoError(t, err) +// t.Log("contract value", string(d)) +// return string(d) == `{"count":5}` +// }, 20*time.Second, time.Second).Should(gomega.BeTrue()) +// // Ensure messages are completed +// gomega.NewWithT(t).Eventually(func() bool { +// msgs, err := orm.GetMsgsState(Confirmed, 5) +// require.NoError(t, err) +// return 1 == len(msgs) +// }, 5*time.Second, time.Second).Should(gomega.BeTrue()) +// +// // Ensure invalid msgs are marked as errored +// invalidMsg := &wasmtypes.MsgExecuteContract{ +// Sender: transmitterID.String(), +// Contract: contractID.String(), +// Msg: []byte(`{"blah":{"blah":5}}`), +// Funds: sdk.Coins{}, +// } +// _, err = txm.Enqueue(contractID.String(), invalidMsg) +// require.NoError(t, err) +// _, err = txm.Enqueue(contractID.String(), invalidMsg) +// require.NoError(t, err) +// _, err = txm.Enqueue(contractID.String(), setMsg) +// require.NoError(t, err) +// +// // Ensure messages are completed +// gomega.NewWithT(t).Eventually(func() bool { +// succeeded, err := orm.GetMsgsState(Confirmed, 5) +// require.NoError(t, err) +// errored, err := orm.GetMsgsState(Errored, 5) +// require.NoError(t, err) +// t.Log("errored", len(errored), "succeeded", len(succeeded)) +// return 2 == len(succeeded) && 2 == len(errored) +// }, 20*time.Second, time.Second).Should(gomega.BeTrue()) +// +// // Observe the messages have been marked as completed +// require.NoError(t, txm.Close()) +//} +// +//func ptr[T any](t T) *T { return &t } diff --git a/core/cmd/cosmos_chains_commands_test.go b/core/cmd/cosmos_chains_commands_test.go index 55e6a60d1c..a0d2052d83 100644 --- a/core/cmd/cosmos_chains_commands_test.go +++ b/core/cmd/cosmos_chains_commands_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -17,7 +17,7 @@ func TestShell_IndexCosmosChains(t *testing.T) { t.Parallel() chainID := cosmostest.RandomChainID() - chain := cosmos.CosmosConfig{ + chain := coscfg.TOMLConfig{ ChainID: ptr(chainID), Enabled: ptr(true), } diff --git a/core/cmd/cosmos_node_commands_test.go b/core/cmd/cosmos_node_commands_test.go index c19749ecd1..9ac7dfb2ba 100644 --- a/core/cmd/cosmos_node_commands_test.go +++ b/core/cmd/cosmos_node_commands_test.go @@ -9,18 +9,17 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-relay/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) -func cosmosStartNewApplication(t *testing.T, cfgs ...*cosmos.CosmosConfig) *cltest.TestApplication { +func cosmosStartNewApplication(t *testing.T, cfgs ...*coscfg.TOMLConfig) *cltest.TestApplication { for i := range cfgs { cfgs[i].SetDefaults() } @@ -34,14 +33,14 @@ func TestShell_IndexCosmosNodes(t *testing.T) { t.Parallel() chainID := cosmostest.RandomChainID() - node := coscfg.Node{ + node := config.Node{ Name: ptr("second"), TendermintURL: utils.MustParseURL("http://tender.mint.test/bombay-12"), } - chain := cosmos.CosmosConfig{ + chain := config.TOMLConfig{ ChainID: ptr(chainID), Enabled: ptr(true), - Nodes: cosmos.CosmosNodes{&node}, + Nodes: config.Nodes{&node}, } app := cosmosStartNewApplication(t, &chain) client, r := app.NewShellAndRenderer() diff --git a/core/cmd/cosmos_transaction_commands_test.go b/core/cmd/cosmos_transaction_commands_test.go index 04858d2956..67b014af2c 100644 --- a/core/cmd/cosmos_transaction_commands_test.go +++ b/core/cmd/cosmos_transaction_commands_test.go @@ -5,7 +5,6 @@ package cmd_test import ( "flag" "os" - "strconv" "testing" "time" @@ -20,15 +19,11 @@ import ( "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/denom" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/params" "github.com/smartcontractkit/chainlink-relay/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" ) @@ -52,13 +47,13 @@ func TestShell_SendCosmosCoins(t *testing.T) { cosmosChain.SetDefaults() accounts, _, url := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.GasToken) require.Greater(t, len(accounts), 1) - nodes := cosmos.CosmosNodes{ + nodes := coscfg.Nodes{ &coscfg.Node{ Name: ptr("random"), TendermintURL: utils.MustParseURL(url), }, } - chainConfig := cosmos.CosmosConfig{ChainID: &chainID, Enabled: ptr(true), Chain: cosmosChain, Nodes: nodes} + chainConfig := coscfg.TOMLConfig{ChainID: &chainID, Enabled: ptr(true), Chain: cosmosChain, Nodes: nodes} app := cosmosStartNewApplication(t, &chainConfig) from := accounts[0] @@ -78,9 +73,6 @@ func TestShell_SendCosmosCoins(t *testing.T) { return coin.IsPositive() }, time.Minute, 5*time.Second) - db := app.GetSqlxDB() - orm := cosmostxm.NewORM(chainID, db, logger.TestLogger(t), pgtest.NewQConfig(true)) - client, r := app.NewShellAndRenderer() cliapp := cli.NewApp() @@ -123,49 +115,18 @@ func TestShell_SendCosmosCoins(t *testing.T) { require.NotEmpty(t, renderedMsg.ID) assert.Equal(t, string(cosmosdb.Unstarted), renderedMsg.State) assert.Nil(t, renderedMsg.TxHash) - id, err := strconv.ParseInt(renderedMsg.ID, 10, 64) - require.NoError(t, err) - msgs, err := orm.GetMsgs(id) - require.NoError(t, err) - require.Equal(t, 1, len(msgs)) - msg := msgs[0] - assert.Equal(t, strconv.FormatInt(msg.ID, 10), renderedMsg.ID) - assert.Equal(t, msg.ChainID, renderedMsg.ChainID) - assert.Equal(t, msg.ContractID, renderedMsg.ContractID) - require.NotEqual(t, cosmosdb.Errored, msg.State) - switch msg.State { - case cosmosdb.Unstarted: - assert.Nil(t, msg.TxHash) - case cosmosdb.Broadcasted, cosmosdb.Confirmed: - assert.NotNil(t, msg.TxHash) - } - - // Maybe wait for confirmation - if msg.State != cosmosdb.Confirmed { - require.Eventually(t, func() bool { - msgs, err := orm.GetMsgs(id) - if assert.NoError(t, err) && assert.NotEmpty(t, msgs) { - if msg = msgs[0]; assert.Equal(t, msg.ID, id) { - t.Log("State:", msg.State) - return msg.State == cosmosdb.Confirmed - } - } - return false - }, testutils.WaitTimeout(t), time.Second) - require.NotNil(t, msg.TxHash) - } // Check balance - endBal, err := reader.Balance(from.Address, *cosmosChain.GasToken) + sent, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(nativeToken, sdk.MustNewDecFromStr(tt.amount)), *cosmosChain.GasToken) require.NoError(t, err) - if assert.NotNil(t, startBal) && assert.NotNil(t, endBal) { - diff := startBal.Sub(*endBal).Amount - sent, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(nativeToken, sdk.MustNewDecFromStr(tt.amount)), *cosmosChain.GasToken) + expBal := startBal.Sub(sent) + + testutils.AssertEventually(t, func() bool { + endBal, err := reader.Balance(from.Address, *cosmosChain.GasToken) require.NoError(t, err) - if assert.True(t, diff.IsInt64()) && assert.True(t, sent.Amount.IsInt64()) { - require.Greater(t, diff.Int64(), sent.Amount.Int64()) - } - } + t.Logf("%s <= %s", endBal, expBal) + return endBal.IsLTE(expBal) + }) }) } } diff --git a/core/cmd/shell.go b/core/cmd/shell.go index fbbce4becb..1ef99992a6 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -174,7 +174,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G if cfg.CosmosEnabled() { cosmosCfg := chainlink.CosmosFactoryConfig{ Keystore: keyStore.Cosmos(), - CosmosConfigs: cfg.CosmosConfigs(), + TOMLConfigs: cfg.CosmosConfigs(), EventBroadcaster: eventBroadcaster, } initOps = append(initOps, chainlink.InitCosmos(ctx, relayerFactory, cosmosCfg)) diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index 276d023994..927592e448 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -10,11 +10,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink/v2/core/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -92,7 +92,7 @@ func TestDoc(t *testing.T) { }) t.Run("Cosmos", func(t *testing.T) { - var fallbackDefaults cosmos.CosmosConfig + var fallbackDefaults coscfg.TOMLConfig fallbackDefaults.SetDefaults() assertTOML(t, fallbackDefaults.Chain, defaults.Cosmos[0].Chain) diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 3fa0090177..d47e6243b8 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -415,7 +415,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn if cfg.CosmosEnabled() { cosmosCfg := chainlink.CosmosFactoryConfig{ Keystore: keyStore.Cosmos(), - CosmosConfigs: cfg.CosmosConfigs(), + TOMLConfigs: cfg.CosmosConfigs(), EventBroadcaster: eventBroadcaster, DB: db, QConfig: cfg.Database(), diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 7c0161a066..14e29a6740 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -301,7 +301,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 // indirect 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.20230913032705-f924d753cc47 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 // indirect github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 // 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 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index e0e5e07ecf..08356fe076 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1456,8 +1456,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 26e2d539ba..3f55a2dc00 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -8,10 +8,10 @@ import ( gotoml "github.com/pelletier/go-toml/v2" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/config/env" @@ -36,7 +36,7 @@ type Config struct { EVM evmcfg.EVMConfigs `toml:",omitempty"` - Cosmos cosmos.CosmosConfigs `toml:",omitempty"` + Cosmos coscfg.TOMLConfigs `toml:",omitempty"` Solana solana.TOMLConfigs `toml:",omitempty"` @@ -119,7 +119,7 @@ func (c *Config) setDefaults() { for i := range c.Cosmos { if c.Cosmos[i] == nil { - c.Cosmos[i] = new(cosmos.CosmosConfig) + c.Cosmos[i] = new(coscfg.TOMLConfig) } c.Cosmos[i].Chain.SetDefaults() } diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 6243146e91..81e3883335 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -15,10 +15,10 @@ import ( ocrnetworking "github.com/smartcontractkit/libocr/networking" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" starknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" @@ -199,7 +199,7 @@ func (g *generalConfig) EVMConfigs() evmcfg.EVMConfigs { return g.c.EVM } -func (g *generalConfig) CosmosConfigs() cosmos.CosmosConfigs { +func (g *generalConfig) CosmosConfigs() coscfg.TOMLConfigs { return g.c.Cosmos } diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 597dab6ba1..48fb8272ac 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -23,7 +23,6 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink/v2/core/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" legacy "github.com/smartcontractkit/chainlink/v2/core/config" @@ -138,7 +137,7 @@ var ( }, }}, }, - Cosmos: []*cosmos.CosmosConfig{ + Cosmos: []*coscfg.TOMLConfig{ { ChainID: ptr("Ibiza-808"), Chain: coscfg.Chain{ @@ -622,7 +621,7 @@ func TestConfig_Marshal(t *testing.T) { }, }, } - full.Cosmos = []*cosmos.CosmosConfig{ + full.Cosmos = []*coscfg.TOMLConfig{ { ChainID: ptr("Malaga-420"), Enabled: ptr(true), @@ -1435,7 +1434,7 @@ func assertValidationError(t *testing.T, invalid interface{ Validate() error }, func TestConfig_setDefaults(t *testing.T) { var c Config c.EVM = evmcfg.EVMConfigs{{ChainID: utils.NewBigI(99999133712345)}} - c.Cosmos = cosmos.CosmosConfigs{{ChainID: ptr("unknown cosmos chain")}} + c.Cosmos = coscfg.TOMLConfigs{{ChainID: ptr("unknown cosmos chain")}} c.Solana = solana.TOMLConfigs{{ChainID: ptr("unknown solana chain")}} c.Starknet = stkcfg.TOMLConfigs{{ChainID: ptr("unknown starknet chain")}} c.setDefaults() diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 0bc51ea431..98796e9005 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -6,7 +6,7 @@ import ( chainlinkconfig "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" config "github.com/smartcontractkit/chainlink/v2/core/config" - cosmos "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" + cosmosconfig "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" mock "github.com/stretchr/testify/mock" @@ -99,15 +99,15 @@ func (_m *GeneralConfig) ConfigTOML() (string, string) { } // CosmosConfigs provides a mock function with given fields: -func (_m *GeneralConfig) CosmosConfigs() cosmos.CosmosConfigs { +func (_m *GeneralConfig) CosmosConfigs() cosmosconfig.TOMLConfigs { ret := _m.Called() - var r0 cosmos.CosmosConfigs - if rf, ok := ret.Get(0).(func() cosmos.CosmosConfigs); ok { + var r0 cosmosconfig.TOMLConfigs + if rf, ok := ret.Get(0).(func() cosmosconfig.TOMLConfigs); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(cosmos.CosmosConfigs) + r0 = ret.Get(0).(cosmosconfig.TOMLConfigs) } } diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index b7291e7dc7..cfc7dbadc1 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -16,7 +16,6 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -132,8 +131,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, } - c.Cosmos = cosmos.CosmosConfigs{ - &cosmos.CosmosConfig{ + c.Cosmos = coscfg.TOMLConfigs{ + &coscfg.TOMLConfig{ ChainID: &cosmosChainID1, Enabled: ptr(true), Chain: coscfg.Chain{ @@ -141,14 +140,14 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Bech32Prefix: ptr("wasm"), GasToken: ptr("cosm"), }, - Nodes: cosmos.CosmosNodes{ + Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 1 node 1"), TendermintURL: (*relayutils.URL)(models.MustParseURL("http://localhost:9548").URL()), }, }, }, - &cosmos.CosmosConfig{ + &coscfg.TOMLConfig{ ChainID: &cosmosChainID2, Enabled: ptr(true), Chain: coscfg.Chain{ @@ -156,7 +155,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Bech32Prefix: ptr("wasm"), GasToken: ptr("cosm"), }, - Nodes: cosmos.CosmosNodes{ + Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 2 node 1"), TendermintURL: (*relayutils.URL)(models.MustParseURL("http://localhost:9598").URL()), @@ -259,7 +258,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitCosmos(testctx, factory, chainlink.CosmosFactoryConfig{ Keystore: keyStore.Cosmos(), - CosmosConfigs: cfg.CosmosConfigs(), + TOMLConfigs: cfg.CosmosConfigs(), EventBroadcaster: pg.NewNullEventBroadcaster(), DB: db, QConfig: cfg.Database()}), @@ -292,7 +291,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { TOMLConfigs: cfg.StarknetConfigs()}), chainlink.InitCosmos(testctx, factory, chainlink.CosmosFactoryConfig{ Keystore: keyStore.Cosmos(), - CosmosConfigs: cfg.CosmosConfigs(), + TOMLConfigs: cfg.CosmosConfigs(), EventBroadcaster: pg.NewNullEventBroadcaster(), DB: db, QConfig: cfg.Database(), diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 31251069df..a159ee7cd0 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/sqlx" pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-solana/pkg/solana" pkgsolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" @@ -223,7 +224,7 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML type CosmosFactoryConfig struct { Keystore keystore.Cosmos - cosmos.CosmosConfigs + coscfg.TOMLConfigs EventBroadcaster pg.EventBroadcaster *sqlx.DB pg.QConfig @@ -234,7 +235,7 @@ func (c CosmosFactoryConfig) Validate() error { if c.Keystore == nil { err = errors.Join(err, fmt.Errorf("nil Keystore")) } - if len(c.CosmosConfigs) == 0 { + if len(c.TOMLConfigs) == 0 { err = errors.Join(err, fmt.Errorf("no CosmosConfigs provided")) } if c.EventBroadcaster == nil { @@ -266,7 +267,7 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf ) // create one relayer per chain id - for _, chainCfg := range config.CosmosConfigs { + for _, chainCfg := range config.TOMLConfigs { relayID := relay.ID{Network: relay.Cosmos, ChainID: *chainCfg.ChainID} lggr := cosmosLggr.Named(relayID.ChainID) diff --git a/core/services/chainlink/types.go b/core/services/chainlink/types.go index 1233a17961..72cad69416 100644 --- a/core/services/chainlink/types.go +++ b/core/services/chainlink/types.go @@ -1,10 +1,10 @@ package chainlink import ( + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config" ) @@ -14,7 +14,7 @@ import ( type GeneralConfig interface { config.AppConfig toml.HasEVMConfigs - CosmosConfigs() cosmos.CosmosConfigs + CosmosConfigs() coscfg.TOMLConfigs SolanaConfigs() solana.TOMLConfigs StarknetConfigs() stkcfg.TOMLConfigs // ConfigTOML returns both the user provided and effective configuration as TOML. diff --git a/core/web/cosmos_chains_controller_test.go b/core/web/cosmos_chains_controller_test.go index 475ef41352..f8dbe4614f 100644 --- a/core/web/cosmos_chains_controller_test.go +++ b/core/web/cosmos_chains_controller_test.go @@ -13,7 +13,6 @@ import ( coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -76,7 +75,7 @@ Nodes = [] t.Run(tc.name, func(t *testing.T) { t.Parallel() - controller := setupCosmosChainsControllerTestV2(t, &cosmos.CosmosConfig{ + controller := setupCosmosChainsControllerTestV2(t, &coscfg.TOMLConfig{ ChainID: ptr(validId), Enabled: ptr(true), Chain: coscfg.Chain{ @@ -106,7 +105,7 @@ Nodes = [] func Test_CosmosChainsController_Index(t *testing.T) { t.Parallel() - chainA := &cosmos.CosmosConfig{ + chainA := &coscfg.TOMLConfig{ ChainID: ptr("a" + cosmostest.RandomChainID()), Enabled: ptr(true), Chain: coscfg.Chain{ @@ -114,7 +113,7 @@ func Test_CosmosChainsController_Index(t *testing.T) { }, } - chainB := &cosmos.CosmosConfig{ + chainB := &coscfg.TOMLConfig{ ChainID: ptr("b" + cosmostest.RandomChainID()), Enabled: ptr(true), Chain: coscfg.Chain{ @@ -174,7 +173,7 @@ type TestCosmosChainsController struct { client cltest.HTTPClientCleaner } -func setupCosmosChainsControllerTestV2(t *testing.T, cfgs ...*cosmos.CosmosConfig) *TestCosmosChainsController { +func setupCosmosChainsControllerTestV2(t *testing.T, cfgs ...*coscfg.TOMLConfig) *TestCosmosChainsController { for i := range cfgs { cfgs[i].SetDefaults() } diff --git a/core/web/cosmos_transfer_controller.go b/core/web/cosmos_transfer_controller.go index afe0fe16d1..965f694fc1 100644 --- a/core/web/cosmos_transfer_controller.go +++ b/core/web/cosmos_transfer_controller.go @@ -1,26 +1,26 @@ package web import ( + "fmt" "net/http" + "slices" sdk "github.com/cosmos/cosmos-sdk/types" - bank "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/gin-gonic/gin" + "github.com/google/uuid" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/denom" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" cosmosmodels "github.com/smartcontractkit/chainlink/v2/core/store/models/cosmos" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) -// maxGasUsedTransfer is an upper bound on how much gas we expect a MsgSend for a single coin to use. -const maxGasUsedTransfer = 100_000 - // CosmosTransfersController can send LINK tokens to another address type CosmosTransfersController struct { App chainlink.Application @@ -28,9 +28,9 @@ type CosmosTransfersController struct { // Create sends native coins from the Chainlink's account to a specified address. func (tc *CosmosTransfersController) Create(c *gin.Context) { - cosmosChains := tc.App.GetRelayers().LegacyCosmosChains() - if cosmosChains == nil { - jsonAPIError(c, http.StatusBadRequest, ErrCosmosNotEnabled) + relayers := tc.App.GetRelayers().List(chainlink.FilterRelayersByType(relay.Cosmos)) + if relayers == nil { + jsonAPIError(c, http.StatusBadRequest, ErrSolanaNotEnabled) return } @@ -43,91 +43,51 @@ func (tc *CosmosTransfersController) Create(c *gin.Context) { jsonAPIError(c, http.StatusBadRequest, errors.New("missing cosmosChainID")) return } - // TODO what about ctx in Get? ctx was used here but not in ETH calls. maybe better to make the interface require ctx and - // put in TODOs in ETH... - chain, err := cosmosChains.Get(tr.CosmosChainID) //cosmosChains.Chain(c.Request.Context(), tr.CosmosChainID) - if errors.Is(err, cosmos.ErrChainIDInvalid) || errors.Is(err, cosmos.ErrChainIDEmpty) { - jsonAPIError(c, http.StatusBadRequest, err) + if tr.FromAddress.Empty() { + jsonAPIError(c, http.StatusUnprocessableEntity, errors.Errorf("withdrawal source address is missing: %v", tr.FromAddress)) return - } else if err != nil { + } + + relayerID := relay.ID{Network: relay.Cosmos, ChainID: tr.CosmosChainID} + relayer, err := relayers.Get(relayerID) + if err != nil { + if errors.Is(err, chainlink.ErrNoSuchRelayer) { + jsonAPIError(c, http.StatusBadRequest, err) + return + } jsonAPIError(c, http.StatusInternalServerError, err) return } - - if tr.FromAddress.Empty() { - jsonAPIError(c, http.StatusUnprocessableEntity, errors.Errorf("withdrawal source address is missing: %v", tr.FromAddress)) + var gasToken string + cfgs := tc.App.GetConfig().CosmosConfigs() + if i := slices.IndexFunc(cfgs, func(config *coscfg.TOMLConfig) bool { return *config.ChainID == tr.CosmosChainID }); i != -1 { + gasToken = cfgs[i].GasToken() + } else { + jsonAPIError(c, http.StatusInternalServerError, fmt.Errorf("no config for chain id: %s", tr.CosmosChainID)) return } - coin, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(tr.Token, tr.Amount), chain.Config().GasToken()) + + //TODO move this inside? + coin, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(tr.Token, tr.Amount), gasToken) if err != nil { - jsonAPIError(c, http.StatusBadRequest, errors.Errorf("unable to convert %s to %s: %v", tr.Token, chain.Config().GasToken(), err)) + jsonAPIError(c, http.StatusBadRequest, errors.Errorf("unable to convert %s to %s: %v", tr.Token, gasToken, err)) return } else if !coin.Amount.IsPositive() { jsonAPIError(c, http.StatusBadRequest, errors.Errorf("amount must be greater than zero: %s", coin.Amount)) return } - txm := chain.TxManager() - - if !tr.AllowHigherAmounts { - var reader client.Reader - reader, err = chain.Reader("") - if err != nil { - jsonAPIError(c, http.StatusInternalServerError, errors.Errorf("chain unreachable: %v", err)) - return - } - gasPrice, err2 := txm.GasPrice() - if err2 != nil { - jsonAPIError(c, http.StatusInternalServerError, errors.Errorf("gas price unavailable: %v", err2)) - return - } - - err = cosmosValidateBalance(reader, gasPrice, tr.FromAddress, coin) - if err != nil { - jsonAPIError(c, http.StatusUnprocessableEntity, errors.Errorf("failed to validate balance: %v", err)) - return - } - } - - sendMsg := bank.NewMsgSend(tr.FromAddress, tr.DestinationAddress, sdk.Coins{coin}) - msgID, err := txm.Enqueue("", sendMsg) + err = relayer.Transact(c, tr.FromAddress.String(), tr.DestinationAddress.String(), coin.Amount.BigInt(), !tr.AllowHigherAmounts) if err != nil { - jsonAPIError(c, http.StatusInternalServerError, errors.Errorf("transaction failed: %v", err)) + jsonAPIError(c, http.StatusInternalServerError, errors.Errorf("failed to send transaction: %v", err)) return } - resource := presenters.NewCosmosMsgResource(msgID, tr.CosmosChainID, "") - msgs, err := txm.GetMsgs(msgID) - if err != nil { - jsonAPIError(c, http.StatusInternalServerError, errors.Errorf("failed to get message %d: %v", msgID, err)) - return - } - if len(msgs) != 1 { - jsonAPIError(c, http.StatusInternalServerError, errors.Errorf("failed to get message %d: %v", msgID, err)) - return - } - msg := msgs[0] - resource.TxHash = msg.TxHash - resource.State = string(msg.State) + resource := presenters.NewCosmosMsgResource("cosmos_transfer_"+uuid.New().String(), tr.CosmosChainID, "") + resource.State = string(db.Unstarted) tc.App.GetAuditLogger().Audit(audit.CosmosTransactionCreated, map[string]interface{}{ "cosmosTransactionResource": resource, }) jsonAPIResponse(c, resource, "cosmos_msg") } - -// cosmosValidateBalance validates that fromAddr's balance can cover coin, including fees at gasPrice. -func cosmosValidateBalance(reader client.Reader, gasPrice sdk.DecCoin, fromAddr sdk.AccAddress, coin sdk.Coin) error { - balance, err := reader.Balance(fromAddr, coin.GetDenom()) - if err != nil { - return err - } - - fee := gasPrice.Amount.MulInt64(maxGasUsedTransfer).RoundInt() - need := coin.Amount.Add(fee) - - if balance.Amount.LT(need) { - return errors.Errorf("balance %q is too low for this transaction to be executed: need %s total, including %s fee", balance, need, fee) - } - return nil -} diff --git a/core/web/presenters/cosmos_msg.go b/core/web/presenters/cosmos_msg.go index d4fbc905bd..5bf0bb9b4f 100644 --- a/core/web/presenters/cosmos_msg.go +++ b/core/web/presenters/cosmos_msg.go @@ -15,9 +15,9 @@ func (CosmosMsgResource) GetName() string { } // NewCosmosMsgResource returns a new partial CosmosMsgResource. -func NewCosmosMsgResource(id int64, chainID string, contractID string) CosmosMsgResource { +func NewCosmosMsgResource(id string, chainID string, contractID string) CosmosMsgResource { return CosmosMsgResource{ - JAID: NewJAIDInt64(id), + JAID: NewJAID(id), ChainID: chainID, ContractID: contractID, } diff --git a/go.mod b/go.mod index 14f195d495..9c14fe8c14 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 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.20230913032705-f924d753cc47 + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 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 diff --git a/go.sum b/go.sum index c9700330fa..372e705c71 100644 --- a/go.sum +++ b/go.sum @@ -1457,8 +1457,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 21ce192126..a0be1dbd8c 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -383,7 +383,7 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect 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.20230913032705-f924d753cc47 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 // indirect github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 // 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 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 64305ddc24..9cc918229f 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2360,8 +2360,8 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= From ef59cf4a36e75ca747ac2f4f1ac973bb04c9c072 Mon Sep 17 00:00:00 2001 From: Domino Valdano <2644901+reductionista@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:36:25 -0700 Subject: [PATCH 034/327] Avoid risky early abort before attempting to send a tx in tx mgr (#11016) * Warn instead of error if anything goes wrong with tx hash conflict detection Ignore any other errors from the DELETE, since we're only looking for an edge case--usually there will be no txhash conflict, and if there is we'll abort anyway on the INSERT. In some cases aborting before we even try to send the tx could be hurtful (risking tx mgr to get stuck) and in others it won't matter either way, but in no case would it ever be helpful. * Document error handling * Raise Warn level to Error, so a persistent error in DELETE query doesn't go unnoticed --- core/chains/evm/txmgr/evm_tx_store.go | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 96963e78d7..cc28c71d78 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -1486,20 +1486,23 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, // Note: the record of the original abandoned transaction will remain in evm.txes, only the attempt is replaced. (Any receipt // associated with the abandoned attempt would also be lost, although this shouldn't happen since only unconfirmed transactions // can be abandoned.) - result, err := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t + res, err := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t WHERE t.id = a.eth_tx_id AND a.hash = $1 AND t.state = $2 AND t.error = 'abandoned'`, attempt.Hash, txmgr.TxFatalError, ) - if err == nil { - count, err := result.RowsAffected() - if err != nil { - return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to get rows affected") - } - if count > 0 { - o.logger.Debugf("Replacing abandoned tx with tx hash %s with tx_id=%d with identical tx hash", attempt.Hash, attempt.TxID) - } - } else { - return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to delete abandoned transactions") + + if err != nil { + // If the DELETE fails, we don't want to abort before at least attempting the INSERT. tx hash conflicts with + // abandoned transactions can only happen after a nonce reset. If the node is operating normally but there is + // some unexpected issue with the DELETE query, blocking the txmgr from sending transactions would be risky + // and could potentially get the node stuck. If the INSERT is going to succeed then we definitely want to continue. + // And even if the INSERT fails, an error message showing the txmgr is having trouble inserting tx's in the db may be + // easier to understand quickly if there is a problem with the node. + o.logger.Errorw("Ignoring unexpected db error while checking for txhash conflict", "err", err) + } else if rows, err := res.RowsAffected(); err != nil { + o.logger.Errorw("Ignoring unexpected db error reading rows affected while checking for txhash conflict", "err", err) + } else if rows > 0 { + o.logger.Debugf("Replacing abandoned tx with tx hash %s with tx_id=%d with identical tx hash", attempt.Hash, attempt.TxID) } var dbAttempt DbEthTxAttempt From 612409932c1fd92d13de7322981639cbc1263df9 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Mon, 30 Oct 2023 15:58:03 -0400 Subject: [PATCH 035/327] Updates to use default keys when available (#11128) --- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a0be1dbd8c..1263c406aa 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -20,7 +20,7 @@ require ( github.com/rs/zerolog v1.30.0 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.0 + github.com/smartcontractkit/chainlink-testing-framework v1.18.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 9cc918229f..08c037dd0c 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2368,8 +2368,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.0 h1:Ru7odxF0tq0FixJXM58rNZw0PvyQnRroqAInBAM83gs= -github.com/smartcontractkit/chainlink-testing-framework v1.18.0/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.1 h1:YznR7isiPYbywuUma5eVSyuZYwbUHIGJ2lpcJazOZgo= +github.com/smartcontractkit/chainlink-testing-framework v1.18.1/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= From 44bf841b393c12d4d62339e21fa3233919beb750 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Mon, 30 Oct 2023 16:03:23 -0400 Subject: [PATCH 036/327] Manually Trigger Integration Tests (#11129) * First attempt * Enable dispatch --- .github/workflows/integration-tests.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 98e59ce8d4..5074fc35b9 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -8,6 +8,13 @@ on: push: tags: - "*" + workflow_dispatch: + inputs: + liveNetwork: + description: "Run Live Testnet Tests" + required: false + type: boolean + # Only run 1 of this workflow at a time per PR concurrency: @@ -886,7 +893,7 @@ jobs: ### Start Live Testnet Section testnet-smoke-tests-matrix: - if: ${{ github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) }} ## Only run live tests on new tags and nightly + if: ${{ github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || (github.event_name == 'workflow_dispatch' && inputs.liveNetwork) }} ## Only run live tests on new tags, schedule, or on manual request environment: integration permissions: checks: write From 2534e1a6055b9e409b2a9f0710cc860f0518ec24 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Tue, 31 Oct 2023 10:40:05 +0100 Subject: [PATCH 037/327] CCIP-1230 Exposing entire LogPollerBlock from LatestBlock in LogPoller (#11105) * Exposing entire LogPollerBlock from LatestBlock function in the LogPoller's interface * Exposing entire LogPollerBlock from LatestBlock function in the LogPoller's interface --- core/chains/evm/logpoller/disabled.go | 4 +- core/chains/evm/logpoller/helper_test.go | 2 +- core/chains/evm/logpoller/log_poller.go | 8 ++-- .../evm/logpoller/log_poller_internal_test.go | 2 +- core/chains/evm/logpoller/log_poller_test.go | 39 ++++++++++++------- core/chains/evm/logpoller/mocks/log_poller.go | 10 ++--- core/services/blockhashstore/coordinators.go | 6 +-- core/services/blockhashstore/delegate.go | 2 +- core/services/blockhashstore/delegate_test.go | 3 +- core/services/blockhashstore/feeder_test.go | 6 +-- .../plugins/ocr2keeper/evm20/log_provider.go | 24 ++++++------ .../ocr2/plugins/ocr2keeper/evm20/registry.go | 10 ++--- .../plugins/ocr2keeper/evm20/registry_test.go | 2 +- .../ocr2keeper/evm21/block_subscriber.go | 7 ++-- .../ocr2keeper/evm21/block_subscriber_test.go | 4 +- .../evm21/logprovider/block_time.go | 5 ++- .../evm21/logprovider/block_time_test.go | 2 +- .../evm21/logprovider/integration_test.go | 4 +- .../ocr2keeper/evm21/logprovider/provider.go | 10 ++--- .../evm21/logprovider/provider_life_cycle.go | 2 +- .../logprovider/provider_life_cycle_test.go | 5 ++- .../evm21/logprovider/provider_test.go | 2 +- .../ocr2keeper/evm21/logprovider/recoverer.go | 8 ++-- .../evm21/logprovider/recoverer_test.go | 11 +++--- .../ocr2/plugins/ocr2keeper/evm21/registry.go | 10 ++--- .../plugins/ocr2keeper/evm21/registry_test.go | 2 +- .../evm21/transmit/event_provider.go | 6 +-- .../evm21/transmit/event_provider_test.go | 2 +- .../ocr2vrf/coordinator/coordinator.go | 2 +- .../ocr2vrf/coordinator/coordinator_test.go | 4 +- core/services/relay/evm/config_poller.go | 2 +- .../relay/evm/functions/config_poller.go | 2 +- .../relay/evm/functions/logpoller_wrapper.go | 15 +++---- .../evm/functions/logpoller_wrapper_test.go | 2 +- .../relay/evm/mercury/config_poller.go | 2 +- 35 files changed, 123 insertions(+), 104 deletions(-) diff --git a/core/chains/evm/logpoller/disabled.go b/core/chains/evm/logpoller/disabled.go index 4bcf1c5086..b54d4e6fc8 100644 --- a/core/chains/evm/logpoller/disabled.go +++ b/core/chains/evm/logpoller/disabled.go @@ -39,7 +39,9 @@ func (disabled) UnregisterFilter(name string, qopts ...pg.QOpt) error { return E func (disabled) HasFilter(name string) bool { return false } -func (disabled) LatestBlock(qopts ...pg.QOpt) (int64, error) { return -1, ErrDisabled } +func (disabled) LatestBlock(qopts ...pg.QOpt) (LogPollerBlock, error) { + return LogPollerBlock{}, ErrDisabled +} func (disabled) GetBlocksRange(ctx context.Context, numbers []uint64, qopts ...pg.QOpt) ([]LogPollerBlock, error) { return nil, ErrDisabled diff --git a/core/chains/evm/logpoller/helper_test.go b/core/chains/evm/logpoller/helper_test.go index 8415641c40..c61d3d5fad 100644 --- a/core/chains/evm/logpoller/helper_test.go +++ b/core/chains/evm/logpoller/helper_test.go @@ -92,7 +92,7 @@ func SetupTH(t testing.TB, useFinalityTag bool, finalityDepth, backfillBatchSize func (th *TestHarness) PollAndSaveLogs(ctx context.Context, currentBlockNumber int64) int64 { th.LogPoller.PollAndSaveLogs(ctx, currentBlockNumber) latest, _ := th.LogPoller.LatestBlock(pg.WithParentCtx(ctx)) - return latest + 1 + return latest.BlockNumber + 1 } func (th *TestHarness) assertDontHave(t *testing.T, start, end int) { diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 6cda8f5b46..4cd2804d9f 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -38,7 +38,7 @@ type LogPoller interface { RegisterFilter(filter Filter, qopts ...pg.QOpt) error UnregisterFilter(name string, qopts ...pg.QOpt) error HasFilter(name string) bool - LatestBlock(qopts ...pg.QOpt) (int64, error) + LatestBlock(qopts ...pg.QOpt) (LogPollerBlock, error) GetBlocksRange(ctx context.Context, numbers []uint64, qopts ...pg.QOpt) ([]LogPollerBlock, error) // General querying @@ -1019,13 +1019,13 @@ func (lp *logPoller) IndexedLogsTopicRange(eventSig common.Hash, address common. // LatestBlock returns the latest block the log poller is on. It tracks blocks to be able // to detect reorgs. -func (lp *logPoller) LatestBlock(qopts ...pg.QOpt) (int64, error) { +func (lp *logPoller) LatestBlock(qopts ...pg.QOpt) (LogPollerBlock, error) { b, err := lp.orm.SelectLatestBlock(qopts...) if err != nil { - return 0, err + return LogPollerBlock{}, err } - return b.BlockNumber, nil + return *b, nil } func (lp *logPoller) BlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, error) { diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index b9474158a6..c0d081582f 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -262,7 +262,7 @@ func TestLogPoller_Replay(t *testing.T) { lp.PollAndSaveLogs(tctx, 4) latest, err := lp.LatestBlock() require.NoError(t, err) - require.Equal(t, int64(4), latest) + require.Equal(t, int64(4), latest.BlockNumber) t.Run("abort before replayStart received", func(t *testing.T) { // Replay() should abort immediately if caller's context is cancelled before request signal is read diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 1ee8f4dcb7..471c728cdd 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -311,8 +311,8 @@ func Test_BackupLogPoller(t *testing.T) { body.Transactions = types.Transactions{} // number of tx's must match # of logs for GetLogs() to succeed rawdb.WriteBody(th.EthDB, h.Hash(), h.Number.Uint64(), body) - currentBlock := th.PollAndSaveLogs(ctx, 1) - assert.Equal(t, int64(35), currentBlock) + currentBlockNumber := th.PollAndSaveLogs(ctx, 1) + assert.Equal(t, int64(35), currentBlockNumber) // simulate logs becoming available rawdb.WriteReceipts(th.EthDB, h.Hash(), h.Number.Uint64(), receipts) @@ -342,12 +342,12 @@ func Test_BackupLogPoller(t *testing.T) { markBlockAsFinalized(t, th, 34) // Run ordinary poller + backup poller at least once - currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) - th.LogPoller.PollAndSaveLogs(ctx, currentBlock+1) + currentBlock, _ := th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) + th.LogPoller.PollAndSaveLogs(ctx, currentBlock.BlockNumber+1) th.LogPoller.BackupPollAndSaveLogs(ctx, 100) currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) - require.Equal(t, int64(37), currentBlock+1) + require.Equal(t, int64(37), currentBlock.BlockNumber+1) // logs still shouldn't show up, because we don't want to backfill the last finalized log // to help with reorg detection @@ -359,11 +359,11 @@ func Test_BackupLogPoller(t *testing.T) { markBlockAsFinalized(t, th, 35) // Run ordinary poller + backup poller at least once more - th.LogPoller.PollAndSaveLogs(ctx, currentBlock+1) + th.LogPoller.PollAndSaveLogs(ctx, currentBlockNumber+1) th.LogPoller.BackupPollAndSaveLogs(ctx, 100) currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) - require.Equal(t, int64(38), currentBlock+1) + require.Equal(t, int64(38), currentBlock.BlockNumber+1) // all 3 logs in block 34 should show up now, thanks to backup logger logs, err = th.LogPoller.Logs(30, 37, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, @@ -471,6 +471,13 @@ func TestLogPoller_BackupPollAndSaveLogsWithDeepBlockDelay(t *testing.T) { // 1 -> 2 -> ... th.PollAndSaveLogs(ctx, 1) + // Check that latest block has the same properties as the head + latestBlock, err := th.LogPoller.LatestBlock() + require.NoError(t, err) + assert.Equal(t, latestBlock.BlockNumber, header.Number.Int64()) + assert.Equal(t, latestBlock.FinalizedBlockNumber, header.Number.Int64()) + assert.Equal(t, latestBlock.BlockHash, header.Hash()) + // Register filter err = th.LogPoller.RegisterFilter(logpoller.Filter{ Name: "Test Emitter", @@ -619,7 +626,7 @@ func TestLogPoller_BlockTimestamps(t *testing.T) { require.Len(t, gethLogs, 2) lb, _ := th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) - th.PollAndSaveLogs(context.Background(), lb+1) + th.PollAndSaveLogs(context.Background(), lb.BlockNumber+1) lg1, err := th.LogPoller.Logs(0, 20, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, pg.WithParentCtx(testutils.Context(t))) require.NoError(t, err) @@ -667,9 +674,9 @@ func TestLogPoller_SynchronizedWithGeth(t *testing.T) { for i := 0; i < finalityDepth; i++ { // Have enough blocks that we could reorg the full finalityDepth-1. ec.Commit() } - currentBlock := int64(1) - lp.PollAndSaveLogs(testutils.Context(t), currentBlock) - currentBlock, err = lp.LatestBlock(pg.WithParentCtx(testutils.Context(t))) + currentBlockNumber := int64(1) + lp.PollAndSaveLogs(testutils.Context(t), currentBlockNumber) + currentBlock, err := lp.LatestBlock(pg.WithParentCtx(testutils.Context(t))) require.NoError(t, err) matchesGeth := func() bool { // Check every block is identical @@ -719,7 +726,7 @@ func TestLogPoller_SynchronizedWithGeth(t *testing.T) { require.NoError(t, err1) t.Logf("New latest (%v, %x), latest parent %x)\n", latest.NumberU64(), latest.Hash(), latest.ParentHash()) } - lp.PollAndSaveLogs(testutils.Context(t), currentBlock) + lp.PollAndSaveLogs(testutils.Context(t), currentBlock.BlockNumber) currentBlock, err = lp.LatestBlock(pg.WithParentCtx(testutils.Context(t))) require.NoError(t, err) } @@ -1245,7 +1252,7 @@ func TestGetReplayFromBlock(t *testing.T) { require.NoError(t, err) latest, err := th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) require.NoError(t, err) - assert.Equal(t, latest, fromBlock) + assert.Equal(t, latest.BlockNumber, fromBlock) // Should take min(latest, requested) in this case requested. requested = int64(7) @@ -1551,6 +1558,10 @@ func Test_PollAndSavePersistsFinalityInBlocks(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { th := SetupTH(t, tt.useFinalityTag, tt.finalityDepth, 3, 2, 1000) + // Should return error before the first poll and save + _, err := th.LogPoller.LatestBlock() + require.Error(t, err) + // Mark first block as finalized h := th.Client.Blockchain().CurrentHeader() th.Client.Blockchain().SetFinalized(h) @@ -1562,7 +1573,7 @@ func Test_PollAndSavePersistsFinalityInBlocks(t *testing.T) { th.PollAndSaveLogs(ctx, 1) - latestBlock, err := th.ORM.SelectLatestBlock() + latestBlock, err := th.LogPoller.LatestBlock() require.NoError(t, err) require.Equal(t, int64(numberOfBlocks), latestBlock.BlockNumber) require.Equal(t, tt.expectedFinalizedBlock, latestBlock.FinalizedBlockNumber) diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index f435734164..01be5f7ba5 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -330,7 +330,7 @@ func (_m *LogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventS } // LatestBlock provides a mock function with given fields: qopts -func (_m *LogPoller) LatestBlock(qopts ...pg.QOpt) (int64, error) { +func (_m *LogPoller) LatestBlock(qopts ...pg.QOpt) (logpoller.LogPollerBlock, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -339,15 +339,15 @@ func (_m *LogPoller) LatestBlock(qopts ...pg.QOpt) (int64, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) - var r0 int64 + var r0 logpoller.LogPollerBlock var r1 error - if rf, ok := ret.Get(0).(func(...pg.QOpt) (int64, error)); ok { + if rf, ok := ret.Get(0).(func(...pg.QOpt) (logpoller.LogPollerBlock, error)); ok { return rf(qopts...) } - if rf, ok := ret.Get(0).(func(...pg.QOpt) int64); ok { + if rf, ok := ret.Get(0).(func(...pg.QOpt) logpoller.LogPollerBlock); ok { r0 = rf(qopts...) } else { - r0 = ret.Get(0).(int64) + r0 = ret.Get(0).(logpoller.LogPollerBlock) } if rf, ok := ret.Get(1).(func(...pg.QOpt) error); ok { diff --git a/core/services/blockhashstore/coordinators.go b/core/services/blockhashstore/coordinators.go index ff5aff1f5e..4cb58bab6f 100644 --- a/core/services/blockhashstore/coordinators.go +++ b/core/services/blockhashstore/coordinators.go @@ -128,7 +128,7 @@ func (v *V1Coordinator) Fulfillments(ctx context.Context, fromBlock uint64) ([]E logs, err := v.lp.LogsWithSigs( int64(fromBlock), - int64(toBlock), + toBlock.BlockNumber, []common.Hash{ v1.VRFCoordinatorRandomnessRequestFulfilled{}.Topic(), }, @@ -219,7 +219,7 @@ func (v *V2Coordinator) Fulfillments(ctx context.Context, fromBlock uint64) ([]E logs, err := v.lp.LogsWithSigs( int64(fromBlock), - int64(toBlock), + toBlock.BlockNumber, []common.Hash{ v2.VRFCoordinatorV2RandomWordsFulfilled{}.Topic(), }, @@ -310,7 +310,7 @@ func (v *V2PlusCoordinator) Fulfillments(ctx context.Context, fromBlock uint64) logs, err := v.lp.LogsWithSigs( int64(fromBlock), - int64(toBlock), + toBlock.BlockNumber, []common.Hash{ v2plus.IVRFCoordinatorV2PlusInternalRandomWordsFulfilled{}.Topic(), }, diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index 123052550b..c8e55e47c3 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -173,7 +173,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if err != nil { return 0, errors.Wrap(err, "getting chain head") } - return uint64(head), nil + return uint64(head.BlockNumber), nil }) return []job.ServiceCtx{&service{ diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 089e9544af..011ab87ad6 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -58,7 +59,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { sendingKey, _ := cltest.MustInsertRandomKey(t, kst) lp := &mocklp.LogPoller{} lp.On("RegisterFilter", mock.Anything).Return(nil) - lp.On("LatestBlock", mock.Anything, mock.Anything).Return(int64(0), nil) + lp.On("LatestBlock", mock.Anything, mock.Anything).Return(logpoller.LogPollerBlock{}, nil) relayExtenders := evmtest.NewChainRelayExtenders( t, diff --git a/core/services/blockhashstore/feeder_test.go b/core/services/blockhashstore/feeder_test.go index 3145a9fd76..8d9ed48c4b 100644 --- a/core/services/blockhashstore/feeder_test.go +++ b/core/services/blockhashstore/feeder_test.go @@ -445,7 +445,7 @@ func (test testCase) testFeederWithLogPollerVRFv1(t *testing.T) { // Mock log poller. lp.On("LatestBlock", mock.Anything). - Return(latest, nil) + Return(logpoller.LogPollerBlock{BlockNumber: latest}, nil) lp.On( "LogsWithSigs", fromBlock, @@ -543,7 +543,7 @@ func (test testCase) testFeederWithLogPollerVRFv2(t *testing.T) { // Mock log poller. lp.On("LatestBlock", mock.Anything). - Return(latest, nil) + Return(logpoller.LogPollerBlock{BlockNumber: latest}, nil) lp.On( "LogsWithSigs", fromBlock, @@ -641,7 +641,7 @@ func (test testCase) testFeederWithLogPollerVRFv2Plus(t *testing.T) { // Mock log poller. lp.On("LatestBlock", mock.Anything). - Return(latest, nil) + Return(logpoller.LogPollerBlock{BlockNumber: latest}, nil) lp.On( "LogsWithSigs", fromBlock, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go index 856e508fc5..4044bb5f2a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go @@ -151,8 +151,8 @@ func (c *LogProvider) PerformLogs(ctx context.Context) ([]ocr2keepers.PerformLog // always check the last lookback number of blocks and rebroadcast // this allows the plugin to make decisions based on event confirmations logs, err := c.logPoller.LogsWithSigs( - end-c.lookbackBlocks, - end, + end.BlockNumber-c.lookbackBlocks, + end.BlockNumber, []common.Hash{ registry.KeeperRegistryUpkeepPerformed{}.Topic(), }, @@ -175,7 +175,7 @@ func (c *LogProvider) PerformLogs(ctx context.Context) ([]ocr2keepers.PerformLog Key: UpkeepKeyHelper[uint32]{}.MakeUpkeepKey(p.CheckBlockNumber, p.Id), TransmitBlock: BlockKeyHelper[int64]{}.MakeBlockKey(p.BlockNumber), TransactionHash: p.TxHash.Hex(), - Confirmations: end - p.BlockNumber, + Confirmations: end.BlockNumber - p.BlockNumber, } vals = append(vals, l) } @@ -194,8 +194,8 @@ func (c *LogProvider) StaleReportLogs(ctx context.Context) ([]ocr2keepers.StaleR // ReorgedUpkeepReportLogs logs, err := c.logPoller.LogsWithSigs( - end-c.lookbackBlocks, - end, + end.BlockNumber-c.lookbackBlocks, + end.BlockNumber, []common.Hash{ registry.KeeperRegistryReorgedUpkeepReport{}.Topic(), }, @@ -212,8 +212,8 @@ func (c *LogProvider) StaleReportLogs(ctx context.Context) ([]ocr2keepers.StaleR // StaleUpkeepReportLogs logs, err = c.logPoller.LogsWithSigs( - end-c.lookbackBlocks, - end, + end.BlockNumber-c.lookbackBlocks, + end.BlockNumber, []common.Hash{ registry.KeeperRegistryStaleUpkeepReport{}.Topic(), }, @@ -230,8 +230,8 @@ func (c *LogProvider) StaleReportLogs(ctx context.Context) ([]ocr2keepers.StaleR // InsufficientFundsUpkeepReportLogs logs, err = c.logPoller.LogsWithSigs( - end-c.lookbackBlocks, - end, + end.BlockNumber-c.lookbackBlocks, + end.BlockNumber, []common.Hash{ registry.KeeperRegistryInsufficientFundsUpkeepReport{}.Topic(), }, @@ -258,7 +258,7 @@ func (c *LogProvider) StaleReportLogs(ctx context.Context) ([]ocr2keepers.StaleR Key: encoding.BasicEncoder{}.MakeUpkeepKey(checkBlockNumber, upkeepId), TransmitBlock: BlockKeyHelper[int64]{}.MakeBlockKey(r.BlockNumber), TransactionHash: r.TxHash.Hex(), - Confirmations: end - r.BlockNumber, + Confirmations: end.BlockNumber - r.BlockNumber, } vals = append(vals, l) } @@ -273,7 +273,7 @@ func (c *LogProvider) StaleReportLogs(ctx context.Context) ([]ocr2keepers.StaleR Key: encoding.BasicEncoder{}.MakeUpkeepKey(checkBlockNumber, upkeepId), TransmitBlock: BlockKeyHelper[int64]{}.MakeBlockKey(r.BlockNumber), TransactionHash: r.TxHash.Hex(), - Confirmations: end - r.BlockNumber, + Confirmations: end.BlockNumber - r.BlockNumber, } vals = append(vals, l) } @@ -288,7 +288,7 @@ func (c *LogProvider) StaleReportLogs(ctx context.Context) ([]ocr2keepers.StaleR Key: encoding.BasicEncoder{}.MakeUpkeepKey(checkBlockNumber, upkeepId), TransmitBlock: BlockKeyHelper[int64]{}.MakeBlockKey(r.BlockNumber), TransactionHash: r.TxHash.Hex(), - Confirmations: end - r.BlockNumber, + Confirmations: end.BlockNumber - r.BlockNumber, } vals = append(vals, l) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go index 49cab7b5a4..2d49a91e98 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go @@ -347,7 +347,7 @@ func (r *EvmRegistry) initialize() error { func (r *EvmRegistry) pollLogs() error { var latest int64 - var end int64 + var end logpoller.LogPollerBlock var err error if end, err = r.poller.LatestBlock(pg.WithParentCtx(r.ctx)); err != nil { @@ -356,11 +356,11 @@ func (r *EvmRegistry) pollLogs() error { r.mu.Lock() latest = r.lastPollBlock - r.lastPollBlock = end + r.lastPollBlock = end.BlockNumber r.mu.Unlock() // if start and end are the same, no polling needs to be done - if latest == 0 || latest == end { + if latest == 0 || latest == end.BlockNumber { return nil } @@ -368,8 +368,8 @@ func (r *EvmRegistry) pollLogs() error { var logs []logpoller.Log if logs, err = r.poller.LogsWithSigs( - end-logEventLookback, - end, + end.BlockNumber-logEventLookback, + end.BlockNumber, upkeepStateEvents, r.addr, pg.WithParentCtx(r.ctx), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go index 348b5a47c0..8662bfd047 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go @@ -189,7 +189,7 @@ func TestPollLogs(t *testing.T) { if test.LatestBlock != nil { mp.On("LatestBlock", mock.Anything). - Return(test.LatestBlock.OutputBlock, test.LatestBlock.OutputErr) + Return(logpoller.LogPollerBlock{BlockNumber: test.LatestBlock.OutputBlock}, test.LatestBlock.OutputErr) } if test.LogsWithSigs != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go index 2d524e6f6c..d97156ed18 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go @@ -79,12 +79,13 @@ func (bs *BlockSubscriber) getBlockRange(ctx context.Context) ([]uint64, error) if err != nil { return nil, err } - bs.lggr.Infof("latest block from log poller is %d", h) + latestBlockNumber := h.BlockNumber + bs.lggr.Infof("latest block from log poller is %d", latestBlockNumber) var blocks []uint64 for i := bs.blockSize - 1; i >= 0; i-- { - if h-i > 0 { - blocks = append(blocks, uint64(h-i)) + if latestBlockNumber-i > 0 { + blocks = append(blocks, uint64(latestBlockNumber-i)) } } return blocks, nil diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go index 618ea83d4e..004b5fac6c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go @@ -97,7 +97,7 @@ func TestBlockSubscriber_GetBlockRange(t *testing.T) { for _, tc := range tests { t.Run(tc.Name, func(t *testing.T) { lp := new(mocks.LogPoller) - lp.On("LatestBlock", mock.Anything).Return(tc.LatestBlock, tc.LatestBlockErr) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: tc.LatestBlock}, tc.LatestBlockErr) bs := NewBlockSubscriber(hb, lp, finality, lggr) bs.blockHistorySize = historySize bs.blockSize = blockSize @@ -278,7 +278,7 @@ func TestBlockSubscriber_Start(t *testing.T) { hb := commonmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) hb.On("Subscribe", mock.Anything).Return(&evmtypes.Head{Number: 42}, func() {}) lp := new(mocks.LogPoller) - lp.On("LatestBlock", mock.Anything).Return(int64(100), nil) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: 100}, nil) blocks := []uint64{97, 98, 99, 100} pollerBlocks := []logpoller.LogPollerBlock{ { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go index 9fc35dd84b..814ed29d90 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go @@ -34,10 +34,11 @@ func (r *blockTimeResolver) BlockTime(ctx context.Context, blockSampleSize int64 if err != nil { return 0, fmt.Errorf("failed to get latest block from poller: %w", err) } - if latest <= blockSampleSize { + latestBlockNumber := latest.BlockNumber + if latestBlockNumber <= blockSampleSize { return defaultBlockTime, nil } - start, end := latest-blockSampleSize, latest + start, end := latestBlockNumber-blockSampleSize, latestBlockNumber startTime, endTime, err := r.getSampleTimestamps(ctx, uint64(start), uint64(end)) if err != nil { return 0, err diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go index 0ad9990e18..7009cfaa9b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go @@ -69,7 +69,7 @@ func TestBlockTimeResolver_BlockTime(t *testing.T) { lp := new(lpmocks.LogPoller) resolver := newBlockTimeResolver(lp) - lp.On("LatestBlock", mock.Anything).Return(tc.latestBlock, tc.latestBlockErr) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: tc.latestBlock}, tc.latestBlockErr) lp.On("GetBlocksRange", mock.Anything, mock.Anything).Return(tc.blocksRange, tc.blocksRangeErr) blockTime, err := resolver.BlockTime(ctx, tc.blockSampleSize) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index 811468746e..dad3542039 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -317,7 +317,7 @@ func TestIntegration_LogEventProvider_RateLimit(t *testing.T) { var minimumBlockCount int64 = 500 latestBlock, _ := lp.LatestBlock() - assert.GreaterOrEqual(t, latestBlock, minimumBlockCount, "to ensure the integrety of the test, the minimum block count before the test should be %d but got %d", minimumBlockCount, latestBlock) + assert.GreaterOrEqual(t, latestBlock.BlockNumber, minimumBlockCount, "to ensure the integrety of the test, the minimum block count before the test should be %d but got %d", minimumBlockCount, latestBlock) } require.NoError(t, logProvider.ReadLogs(ctx, ids...)) @@ -564,7 +564,7 @@ func waitLogPoller(ctx context.Context, t *testing.T, backend *backends.Simulate for { latestPolled, lberr := lp.LatestBlock(pg.WithParentCtx(ctx)) require.NoError(t, lberr) - if latestPolled >= latestBlock { + if latestPolled.BlockNumber >= latestBlock { break } lp.PollAndSaveLogs(ctx, latestBlock) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go index 729bf4ade5..349db2902b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go @@ -161,11 +161,11 @@ func (p *logEventProvider) GetLatestPayloads(ctx context.Context) ([]ocr2keepers if err != nil { return nil, fmt.Errorf("%w: %s", ErrHeadNotAvailable, err) } - start := latest - p.opts.LookbackBlocks + start := latest.BlockNumber - p.opts.LookbackBlocks if start <= 0 { start = 1 } - logs := p.buffer.dequeueRange(start, latest, AllowedLogsPerUpkeep, MaxPayloads) + logs := p.buffer.dequeueRange(start, latest.BlockNumber, AllowedLogsPerUpkeep, MaxPayloads) // p.lggr.Debugw("got latest logs from buffer", "latest", latest, "diff", diff, "logs", len(logs)) @@ -199,12 +199,12 @@ func (p *logEventProvider) ReadLogs(pctx context.Context, ids ...*big.Int) error if err != nil { return fmt.Errorf("%w: %s", ErrHeadNotAvailable, err) } - if latest == 0 { + if latest.BlockNumber == 0 { return fmt.Errorf("%w: %s", ErrHeadNotAvailable, "latest block is 0") } - filters := p.getFilters(latest, ids...) + filters := p.getFilters(latest.BlockNumber, ids...) - err = p.readLogs(ctx, latest, filters) + err = p.readLogs(ctx, latest.BlockNumber, filters) p.updateFiltersLastPoll(filters) // p.lggr.Debugw("read logs for entries", "latestBlock", latest, "entries", len(entries), "err", err) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go index ab816adb1b..69a4872351 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go @@ -128,7 +128,7 @@ func (p *logEventProvider) register(ctx context.Context, lpFilter logpoller.Filt // already registered in DB before, no need to backfill return nil } - backfillBlock := latest - int64(LogBackfillBuffer) + backfillBlock := latest.BlockNumber - int64(LogBackfillBuffer) if backfillBlock < 1 { // New chain, backfill from start backfillBlock = 1 diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go index 4b1ff06f31..03395cb5b5 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" @@ -109,7 +110,7 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { lp := new(mocks.LogPoller) lp.On("RegisterFilter", mock.Anything).Return(nil) lp.On("UnregisterFilter", mock.Anything).Return(nil) - lp.On("LatestBlock", mock.Anything).Return(int64(0), nil) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{}, nil) hasFitlerTimes := 1 if tc.unregister { hasFitlerTimes = 2 @@ -149,7 +150,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { mp.On("RegisterFilter", mock.Anything).Return(nil) mp.On("UnregisterFilter", mock.Anything).Return(nil) mp.On("HasFilter", mock.Anything).Return(false) - mp.On("LatestBlock", mock.Anything).Return(int64(0), nil) + mp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{}, nil) mp.On("ReplayAsync", mock.Anything).Return(nil) p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go index db22886cbb..a8e33ba23b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go @@ -248,7 +248,7 @@ func TestLogEventProvider_ReadLogs(t *testing.T) { mp.On("ReplayAsync", mock.Anything).Return() mp.On("HasFilter", mock.Anything).Return(false) mp.On("UnregisterFilter", mock.Anything, mock.Anything).Return(nil) - mp.On("LatestBlock", mock.Anything).Return(int64(1), nil) + mp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: int64(1)}, nil) mp.On("LogsWithSigs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{ { BlockNumber: 1, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index b74160ae91..d6e7ad51d1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -208,7 +208,7 @@ func (r *logRecoverer) getLogTriggerCheckData(ctx context.Context, proposal ocr2 return nil, err } - start, offsetBlock := r.getRecoveryWindow(latest) + start, offsetBlock := r.getRecoveryWindow(latest.BlockNumber) if proposal.Trigger.LogTriggerExtension == nil { return nil, errors.New("missing log trigger extension") } @@ -297,7 +297,7 @@ func (r *logRecoverer) GetRecoveryProposals(ctx context.Context) ([]ocr2keepers. allLogsCounter := 0 logsCount := map[string]int{} - r.sortPending(uint64(latestBlock)) + r.sortPending(uint64(latestBlock.BlockNumber)) var results, pending []ocr2keepers.UpkeepPayload for _, payload := range r.pending { @@ -330,7 +330,7 @@ func (r *logRecoverer) recover(ctx context.Context) error { return fmt.Errorf("%w: %s", ErrHeadNotAvailable, err) } - start, offsetBlock := r.getRecoveryWindow(latest) + start, offsetBlock := r.getRecoveryWindow(latest.BlockNumber) if offsetBlock < 0 { // too soon to recover, we don't have enough blocks return nil @@ -611,7 +611,7 @@ func (r *logRecoverer) tryExpire(ctx context.Context, ids ...string) error { return fmt.Errorf("failed to get states: %w", err) } lggr := r.lggr.With("where", "clean") - start, _ := r.getRecoveryWindow(latestBlock) + start, _ := r.getRecoveryWindow(latestBlock.BlockNumber) r.lock.Lock() defer r.lock.Unlock() var removed int diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go index 2fdf04f76c..c882a22bc1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go @@ -32,7 +32,7 @@ func TestLogRecoverer_GetRecoverables(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() lp := &lpmocks.LogPoller{} - lp.On("LatestBlock", mock.Anything).Return(int64(100), nil) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: 100}, nil) r := NewLogRecoverer(logger.TestLogger(t), lp, nil, nil, nil, nil, NewOptions(200)) tests := []struct { @@ -182,7 +182,7 @@ func TestLogRecoverer_Clean(t *testing.T) { start, _ := r.getRecoveryWindow(0) block24h := int64(math.Abs(float64(start))) - lp.On("LatestBlock", mock.Anything).Return(block24h+oldLogsOffset, nil) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: block24h + oldLogsOffset}, nil) statesReader.On("SelectByWorkIDs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.states, nil) r.lock.Lock() @@ -423,7 +423,7 @@ func TestLogRecoverer_Recover(t *testing.T) { recoverer, filterStore, lp, statesReader := setupTestRecoverer(t, time.Millisecond*50, lookbackBlocks) filterStore.AddActiveUpkeeps(tc.active...) - lp.On("LatestBlock", mock.Anything).Return(tc.latestBlock, tc.latestBlockErr) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: tc.latestBlock}, tc.latestBlockErr) lp.On("LogsWithSigs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.logs, tc.logsErr) statesReader.On("SelectByWorkIDs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.states, tc.statesErr) @@ -1206,8 +1206,9 @@ type mockLogPoller struct { func (p *mockLogPoller) LogsWithSigs(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return p.LogsWithSigsFn(start, end, eventSigs, address, qopts...) } -func (p *mockLogPoller) LatestBlock(qopts ...pg.QOpt) (int64, error) { - return p.LatestBlockFn(qopts...) +func (p *mockLogPoller) LatestBlock(qopts ...pg.QOpt) (logpoller.LogPollerBlock, error) { + block, err := p.LatestBlockFn(qopts...) + return logpoller.LogPollerBlock{BlockNumber: block}, err } type mockClient struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 5d180c05b8..0ca20477f2 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -362,7 +362,7 @@ func (r *EvmRegistry) refreshLogTriggerUpkeepsBatch(logTriggerIDs []*big.Int) er func (r *EvmRegistry) pollUpkeepStateLogs() error { var latest int64 - var end int64 + var end logpoller.LogPollerBlock var err error if end, err = r.poller.LatestBlock(pg.WithParentCtx(r.ctx)); err != nil { @@ -371,18 +371,18 @@ func (r *EvmRegistry) pollUpkeepStateLogs() error { r.mu.Lock() latest = r.lastPollBlock - r.lastPollBlock = end + r.lastPollBlock = end.BlockNumber r.mu.Unlock() // if start and end are the same, no polling needs to be done - if latest == 0 || latest == end { + if latest == 0 || latest == end.BlockNumber { return nil } var logs []logpoller.Log if logs, err = r.poller.LogsWithSigs( - end-logEventLookback, - end, + end.BlockNumber-logEventLookback, + end.BlockNumber, upkeepStateEvents, r.addr, pg.WithParentCtx(r.ctx), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go index 0cd5ecd259..4be0ccce4e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go @@ -145,7 +145,7 @@ func TestPollLogs(t *testing.T) { if test.LatestBlock != nil { mp.On("LatestBlock", mock.Anything). - Return(test.LatestBlock.OutputBlock, test.LatestBlock.OutputErr) + Return(logpoller.LogPollerBlock{BlockNumber: test.LatestBlock.OutputBlock}, test.LatestBlock.OutputErr) } if test.LogsWithSigs != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go index 5fd320df8e..8f84ca1495 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go @@ -141,8 +141,8 @@ func (c *EventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keepers.Tran // always check the last lookback number of blocks and rebroadcast // this allows the plugin to make decisions based on event confirmations logs, err := c.logPoller.LogsWithSigs( - end-c.lookbackBlocks, - end, + end.BlockNumber-c.lookbackBlocks, + end.BlockNumber, []common.Hash{ iregistry21.IKeeperRegistryMasterUpkeepPerformed{}.Topic(), iregistry21.IKeeperRegistryMasterStaleUpkeepReport{}.Topic(), @@ -156,7 +156,7 @@ func (c *EventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keepers.Tran return nil, fmt.Errorf("%w: failed to collect logs from log poller", err) } - return c.processLogs(end, logs...) + return c.processLogs(end.BlockNumber, logs...) } // processLogs will parse the unseen logs and return the corresponding transmit events. diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go index 72f3b63088..58e95bc423 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go @@ -89,7 +89,7 @@ func TestTransmitEventProvider_Sanity(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - lp.On("LatestBlock", mock.Anything).Return(tc.latestBlock, nil) + lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: tc.latestBlock}, nil) lp.On("LogsWithSigs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.logs, nil) res, err := provider.GetLatestEvents(ctx) diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go index e51b68f415..1b58a01732 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go @@ -227,7 +227,7 @@ func (c *coordinator) CurrentChainHeight(ctx context.Context) (uint64, error) { if err != nil { return 0, err } - return uint64(head), nil + return uint64(head.BlockNumber), nil } // ReportIsOnchain returns true iff a report for the given OCR epoch/round is diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index 26d0f2996a..dc489b4958 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -1032,7 +1032,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { requestedBlocks := []uint64{195, 196} lp := lp_mocks.NewLogPoller(t) lp.On("LatestBlock", mock.Anything). - Return(int64(latestHeadNumber), nil) + Return(logpoller.LogPollerBlock{BlockNumber: int64(latestHeadNumber)}, nil) lp.On("GetBlocksRange", mock.Anything, append(requestedBlocks, uint64(latestHeadNumber-lookbackBlocks+1), uint64(latestHeadNumber)), mock.Anything). Return(nil, errors.New("GetBlocks error")) @@ -1720,7 +1720,7 @@ func getLogPoller( lp := lp_mocks.NewLogPoller(t) if needsLatestBlock { lp.On("LatestBlock", mock.Anything). - Return(int64(latestHeadNumber), nil) + Return(logpoller.LogPollerBlock{BlockNumber: int64(latestHeadNumber)}, nil) } var logPollerBlocks []logpoller.LogPollerBlock diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index 1cf2318b29..daccf400ea 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -212,7 +212,7 @@ func (cp *configPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint } return 0, err } - return uint64(latest), nil + return uint64(latest.BlockNumber), nil } func (cp *configPoller) isConfigStoreAvailable() bool { diff --git a/core/services/relay/evm/functions/config_poller.go b/core/services/relay/evm/functions/config_poller.go index f068f13cc7..7a59d49989 100644 --- a/core/services/relay/evm/functions/config_poller.go +++ b/core/services/relay/evm/functions/config_poller.go @@ -181,7 +181,7 @@ func (cp *configPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint } return 0, err } - return uint64(latest), nil + return uint64(latest.BlockNumber), nil } // called from LogPollerWrapper in a separate goroutine diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go index 777717d01c..d355bd6569 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper.go +++ b/core/services/relay/evm/functions/logpoller_wrapper.go @@ -77,7 +77,7 @@ func (l *logPollerWrapper) Start(context.Context) error { l.lggr.Errorw("LogPollerWrapper: LatestBlock() failed, starting from 0", "error", err) } else { l.lggr.Debugw("LogPollerWrapper: LatestBlock() got starting block", "block", nextBlock) - l.nextBlock = nextBlock - l.blockOffset + l.nextBlock = nextBlock.BlockNumber - l.blockOffset } l.closeWait.Add(1) go l.checkForRouteUpdates() @@ -123,9 +123,10 @@ func (l *logPollerWrapper) LatestEvents() ([]evmRelayTypes.OracleRequest, []evmR l.mu.Unlock() return nil, nil, err } - latest -= l.blockOffset - if latest >= nextBlock { - l.nextBlock = latest + 1 + latestBlockNumber := latest.BlockNumber + latestBlockNumber -= l.blockOffset + if latestBlockNumber >= nextBlock { + l.nextBlock = latestBlockNumber + 1 } l.mu.Unlock() @@ -136,18 +137,18 @@ func (l *logPollerWrapper) LatestEvents() ([]evmRelayTypes.OracleRequest, []evmR l.lggr.Debug("LatestEvents: no non-zero coordinators to check") return resultsReq, resultsResp, errors.New("no non-zero coordinators to check") } - if latest < nextBlock { + if latestBlockNumber < nextBlock { l.lggr.Debugw("LatestEvents: no new blocks to check", "latest", latest, "nextBlock", nextBlock) return resultsReq, resultsResp, nil } for _, coordinator := range coordinators { - requestLogs, err := l.logPoller.Logs(nextBlock, latest, functions_coordinator.FunctionsCoordinatorOracleRequest{}.Topic(), coordinator) + requestLogs, err := l.logPoller.Logs(nextBlock, latestBlockNumber, functions_coordinator.FunctionsCoordinatorOracleRequest{}.Topic(), coordinator) if err != nil { l.lggr.Errorw("LatestEvents: fetching request logs from LogPoller failed", "latest", latest, "nextBlock", nextBlock) return nil, nil, err } - responseLogs, err := l.logPoller.Logs(nextBlock, latest, functions_coordinator.FunctionsCoordinatorOracleResponse{}.Topic(), coordinator) + responseLogs, err := l.logPoller.Logs(nextBlock, latestBlockNumber, functions_coordinator.FunctionsCoordinatorOracleResponse{}.Topic(), coordinator) if err != nil { l.lggr.Errorw("LatestEvents: fetching response logs from LogPoller failed", "latest", latest, "nextBlock", nextBlock) return nil, nil, err diff --git a/core/services/relay/evm/functions/logpoller_wrapper_test.go b/core/services/relay/evm/functions/logpoller_wrapper_test.go index 224aa51a5d..c91c3c49aa 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper_test.go +++ b/core/services/relay/evm/functions/logpoller_wrapper_test.go @@ -60,7 +60,7 @@ func setUp(t *testing.T, updateFrequencySec uint32) (*lpmocks.LogPoller, types.L lpWrapper, err := functions.NewLogPollerWrapper(gethcommon.Address{}, config, client, lp, lggr) require.NoError(t, err) - lp.On("LatestBlock").Return(int64(100), nil) + lp.On("LatestBlock").Return(logpoller.LogPollerBlock{BlockNumber: int64(100)}, nil) return lp, lpWrapper, client } diff --git a/core/services/relay/evm/mercury/config_poller.go b/core/services/relay/evm/mercury/config_poller.go index 2f16157bfa..8964a28304 100644 --- a/core/services/relay/evm/mercury/config_poller.go +++ b/core/services/relay/evm/mercury/config_poller.go @@ -188,7 +188,7 @@ func (cp *ConfigPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint } return 0, err } - return uint64(latest), nil + return uint64(latest.BlockNumber), nil } func (cp *ConfigPoller) startLogSubscription() { From 943a1ade98bcc6cc134aa332074228257c72b141 Mon Sep 17 00:00:00 2001 From: Patrick Date: Tue, 31 Oct 2023 07:07:10 -0400 Subject: [PATCH 038/327] fix/lint (#11131) --- core/chains/evm/txmgr/evm_tx_store.go | 8 ++++---- core/utils/utils.go | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index cc28c71d78..86a06b6025 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -1486,19 +1486,19 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, // Note: the record of the original abandoned transaction will remain in evm.txes, only the attempt is replaced. (Any receipt // associated with the abandoned attempt would also be lost, although this shouldn't happen since only unconfirmed transactions // can be abandoned.) - res, err := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t + res, err2 := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t WHERE t.id = a.eth_tx_id AND a.hash = $1 AND t.state = $2 AND t.error = 'abandoned'`, attempt.Hash, txmgr.TxFatalError, ) - if err != nil { + if err2 != nil { // If the DELETE fails, we don't want to abort before at least attempting the INSERT. tx hash conflicts with // abandoned transactions can only happen after a nonce reset. If the node is operating normally but there is // some unexpected issue with the DELETE query, blocking the txmgr from sending transactions would be risky // and could potentially get the node stuck. If the INSERT is going to succeed then we definitely want to continue. // And even if the INSERT fails, an error message showing the txmgr is having trouble inserting tx's in the db may be // easier to understand quickly if there is a problem with the node. - o.logger.Errorw("Ignoring unexpected db error while checking for txhash conflict", "err", err) + o.logger.Errorw("Ignoring unexpected db error while checking for txhash conflict", "err", err2) } else if rows, err := res.RowsAffected(); err != nil { o.logger.Errorw("Ignoring unexpected db error reading rows affected while checking for txhash conflict", "err", err) } else if rows > 0 { @@ -1511,7 +1511,7 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, if e != nil { return pkgerrors.Wrap(e, "failed to BindNamed") } - err = tx.Get(&dbAttempt, query, args...) + err := tx.Get(&dbAttempt, query, args...) if err != nil { var pqErr *pgconn.PgError if isPqErr := errors.As(err, &pqErr); isPqErr && diff --git a/core/utils/utils.go b/core/utils/utils.go index b8515f3362..e5541ecf55 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -40,9 +40,6 @@ const ( DefaultSecretSize = 48 // EVMWordByteLen the length of an EVM Word Byte EVMWordByteLen = 32 - - // defaultErrorBufferCap is the default cap on the errors an error buffer can store at any time - defaultErrorBufferCap = 50 ) // ZeroAddress is an address of all zeroes, otherwise in Ethereum as From 14804a959975cf53aa52ab95f5f0438046a9cc42 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Tue, 31 Oct 2023 12:45:34 +0100 Subject: [PATCH 039/327] bump version without changes (#11118) --- contracts/scripts/native_solc_compile_all_shared | 2 +- .../src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol | 4 ++-- .../automation/upkeeps/LinkAvailableBalanceMonitor.sol | 6 +++--- .../src/v0.8/functions/dev/v1_X/FunctionsBilling.sol | 2 +- contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol | 4 ++-- .../v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol | 4 ++-- .../dev/v1_X/accessControl/TermsOfServiceAllowList.sol | 4 ++-- .../functions/tests/v1_X/FunctionsSubscriptions.t.sol | 2 +- contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol | 2 +- contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol | 4 ++-- .../src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol | 4 ++-- .../v1_0_0/accessControl/TermsOfServiceAllowList.sol | 4 ++-- contracts/src/v0.8/llo-feeds/FeeManager.sol | 8 ++++---- contracts/src/v0.8/llo-feeds/RewardManager.sol | 4 ++-- contracts/src/v0.8/llo-feeds/Verifier.sol | 2 +- contracts/src/v0.8/llo-feeds/VerifierProxy.sol | 2 +- contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol | 2 +- .../src/v0.8/llo-feeds/interfaces/IRewardManager.sol | 2 +- contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol | 2 +- .../src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol | 2 +- .../v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol | 2 +- .../llo-feeds/test/reward-manager/BaseRewardManager.t.sol | 2 +- .../test/reward-manager/RewardManager.general.t.sol | 2 +- .../v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol | 4 ++-- .../test/verifier/VerifierProxySetVerifierTest.t.sol | 2 +- contracts/src/v0.8/operatorforwarder/dev/Operator.sol | 2 +- contracts/src/v0.8/shared/mocks/WERC20Mock.sol | 2 +- .../v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol | 4 ++-- .../shared/test/token/ERC677/OpStackBurnMintERC677.t.sol | 2 +- contracts/src/v0.8/shared/token/ERC20/IBurnMintERC20.sol | 2 +- .../v0.8/shared/token/ERC20/IOptimismMintableERC20.sol | 2 +- contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol | 8 ++++---- contracts/src/v0.8/shared/token/ERC677/ERC677.sol | 4 ++-- .../v0.8/shared/token/ERC677/OpStackBurnMintERC677.sol | 2 +- contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol | 2 +- .../{v4.8.0 => v4.8.3}/contracts/interfaces/IERC165.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/interfaces/IERC20.sol | 0 .../contracts/interfaces/draft-IERC20Permit.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/mocks/ERC20Mock.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/security/Pausable.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/token/ERC20/ERC20.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/token/ERC20/IERC20.sol | 0 .../contracts/token/ERC20/extensions/ERC20Burnable.sol | 0 .../contracts/token/ERC20/extensions/IERC20Metadata.sol | 0 .../token/ERC20/extensions/draft-ERC20Permit.sol | 0 .../token/ERC20/extensions/draft-IERC20Permit.sol | 0 .../contracts/token/ERC20/utils/SafeERC20.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/utils/Address.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/utils/Context.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/utils/Counters.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/utils/StorageSlot.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/utils/Strings.sol | 0 .../contracts/utils/cryptography/ECDSA.sol | 0 .../contracts/utils/cryptography/EIP712.sol | 0 .../contracts/utils/introspection/IERC165.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/utils/math/Math.sol | 0 .../{v4.8.0 => v4.8.3}/contracts/utils/math/SafeCast.sol | 0 .../contracts/utils/math/SignedMath.sol | 0 .../contracts/utils/structs/EnumerableMap.sol | 0 .../contracts/utils/structs/EnumerableSet.sol | 0 60 files changed, 54 insertions(+), 54 deletions(-) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/interfaces/IERC165.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/interfaces/IERC20.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/interfaces/draft-IERC20Permit.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/mocks/ERC20Mock.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/security/Pausable.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/token/ERC20/ERC20.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/token/ERC20/IERC20.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/token/ERC20/extensions/ERC20Burnable.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/token/ERC20/extensions/IERC20Metadata.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/token/ERC20/extensions/draft-ERC20Permit.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/token/ERC20/extensions/draft-IERC20Permit.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/token/ERC20/utils/SafeERC20.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/Address.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/Context.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/Counters.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/StorageSlot.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/Strings.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/cryptography/ECDSA.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/cryptography/EIP712.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/introspection/IERC165.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/math/Math.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/math/SafeCast.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/math/SignedMath.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/structs/EnumerableMap.sol (100%) rename contracts/src/v0.8/vendor/openzeppelin-solidity/{v4.8.0 => v4.8.3}/contracts/utils/structs/EnumerableSet.sol (100%) diff --git a/contracts/scripts/native_solc_compile_all_shared b/contracts/scripts/native_solc_compile_all_shared index 705cedce7a..db421f45e0 100755 --- a/contracts/scripts/native_solc_compile_all_shared +++ b/contracts/scripts/native_solc_compile_all_shared @@ -28,4 +28,4 @@ compileContract () { compileContract shared/token/ERC677/BurnMintERC677.sol compileContract shared/token/ERC677/LinkToken.sol compileContract shared/mocks/WERC20Mock.sol -compileContract vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/ERC20.sol +compileContract vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol diff --git a/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol index 61a6e882d8..d2a7adc67a 100644 --- a/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.4; import "../../shared/access/ConfirmedOwner.sol"; import "../interfaces/KeeperCompatibleInterface.sol"; -import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; -import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; +import "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title The ERC20BalanceMonitor contract. diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index 028579397a..e2d42bc066 100644 --- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -4,9 +4,9 @@ pragma solidity 0.8.6; import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; +import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; interface IAggregatorProxy { function aggregator() external view returns (address); 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 e7958a7bca..ed67d48543 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -8,7 +8,7 @@ import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; -import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; /// @title Functions Billing contract /// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol index 8daa821bb5..2e12a75679 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol @@ -10,8 +10,8 @@ import {FunctionsSubscriptions} from "./FunctionsSubscriptions.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; -import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -import {Pausable} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; +import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; +import {Pausable} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, ITypeAndVersion, ConfirmedOwner { using FunctionsResponse for FunctionsResponse.RequestMeta; diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol index 86e762e39c..bcd01c1f0c 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol @@ -7,8 +7,8 @@ import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title Functions Subscriptions contract /// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol index fbeef3c298..b36d063ad7 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol @@ -7,8 +7,8 @@ import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; -import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; -import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; +import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; /// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, ITypeAndVersion, ConfirmedOwner { diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol index df905fb8be..8f08a6c1e8 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol @@ -6,7 +6,7 @@ import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {FunctionsRouterSetup, FunctionsOwnerAcceptTermsOfServiceSetup, FunctionsClientSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsFulfillmentSetup} from "./Setup.t.sol"; diff --git a/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol index 1f99903c5a..5168bdc01e 100644 --- a/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol @@ -8,7 +8,7 @@ import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; -import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; /// @title Functions Billing contract /// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). diff --git a/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol index dad50b042b..9f35c4dfe5 100644 --- a/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol @@ -10,8 +10,8 @@ import {FunctionsSubscriptions} from "./FunctionsSubscriptions.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; +import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, ITypeAndVersion, ConfirmedOwner { using FunctionsResponse for FunctionsResponse.RequestMeta; diff --git a/contracts/src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol index 7fa2368c46..b93d217473 100644 --- a/contracts/src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol @@ -7,8 +7,8 @@ import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title Functions Subscriptions contract /// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). diff --git a/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol index a7b1357784..8a42e34cb8 100644 --- a/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol @@ -7,8 +7,8 @@ import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; -import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; -import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; /// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, ITypeAndVersion, ConfirmedOwner { diff --git a/contracts/src/v0.8/llo-feeds/FeeManager.sol b/contracts/src/v0.8/llo-feeds/FeeManager.sol index 0cc8273442..397605d9b2 100644 --- a/contracts/src/v0.8/llo-feeds/FeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/FeeManager.sol @@ -4,13 +4,13 @@ pragma solidity 0.8.16; import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {IFeeManager} from "./interfaces/IFeeManager.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; -import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {Common} from "../libraries/Common.sol"; import {IRewardManager} from "./interfaces/IRewardManager.sol"; import {IWERC20} from "../shared/interfaces/IWERC20.sol"; -import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol"; -import {Math} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/Math.sol"; -import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol"; +import {Math} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol"; +import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol"; /** diff --git a/contracts/src/v0.8/llo-feeds/RewardManager.sol b/contracts/src/v0.8/llo-feeds/RewardManager.sol index e064bff8b6..3777b432fc 100644 --- a/contracts/src/v0.8/llo-feeds/RewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/RewardManager.sol @@ -3,10 +3,10 @@ pragma solidity 0.8.16; import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {IRewardManager} from "./interfaces/IRewardManager.sol"; -import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol"; +import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {Common} from "../libraries/Common.sol"; -import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title RewardManager diff --git a/contracts/src/v0.8/llo-feeds/Verifier.sol b/contracts/src/v0.8/llo-feeds/Verifier.sol index cd7e3d2bad..f7ce156a60 100644 --- a/contracts/src/v0.8/llo-feeds/Verifier.sol +++ b/contracts/src/v0.8/llo-feeds/Verifier.sol @@ -5,7 +5,7 @@ import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {IVerifier} from "./interfaces/IVerifier.sol"; import {IVerifierProxy} from "./interfaces/IVerifierProxy.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; -import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {Common} from "../libraries/Common.sol"; // OCR2 standard diff --git a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol index 989c5c6b81..6abb2b78e9 100644 --- a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol +++ b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol @@ -6,7 +6,7 @@ import {IVerifierProxy} from "./interfaces/IVerifierProxy.sol"; import {IVerifier} from "./interfaces/IVerifier.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {AccessControllerInterface} from "../shared/interfaces/AccessControllerInterface.sol"; -import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol"; import {Common} from "../libraries/Common.sol"; diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol b/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol index ed7213870e..08373a6a5b 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {Common} from "../../libraries/Common.sol"; import {IVerifierFeeManager} from "./IVerifierFeeManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol b/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol index 68cecc4f97..a76366a3eb 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {Common} from "../../libraries/Common.sol"; interface IRewardManager is IERC165 { diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol b/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol index 7617d9a5c3..9b9ba2e657 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {Common} from "../../libraries/Common.sol"; interface IVerifier is IERC165 { diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol index 8e490d39d1..e5a73e612c 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {Common} from "../../libraries/Common.sol"; interface IVerifierFeeManager is IERC165 { diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol index c446150406..ec2611f9e4 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol @@ -5,7 +5,7 @@ import {Test} from "forge-std/Test.sol"; import {FeeManager} from "../../FeeManager.sol"; import {RewardManager} from "../../RewardManager.sol"; import {Common} from "../../../libraries/Common.sol"; -import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol"; +import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {WERC20Mock} from "../../../shared/mocks/WERC20Mock.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; import {FeeManagerProxy} from "../mocks/FeeManagerProxy.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol index 4a70109316..3e50adef95 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {Test} from "forge-std/Test.sol"; -import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol"; +import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {RewardManager} from "../../RewardManager.sol"; import {Common} from "../../../libraries/Common.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol index 9cee5b05c5..e7bc43dc81 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; import {RewardManager} from "../../RewardManager.sol"; -import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol"; +import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; /** diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol index 3faa65fb52..91e0f9da90 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.16; import {Test} from "forge-std/Test.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {IVerifier} from "../../interfaces/IVerifier.sol"; import {ErroredVerifier} from "../mocks/ErroredVerifier.sol"; import {Verifier} from "../../Verifier.sol"; @@ -11,7 +11,7 @@ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; import {FeeManager} from "../../FeeManager.sol"; import {Common} from "../../../libraries/Common.sol"; -import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol"; +import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {WERC20Mock} from "../../../shared/mocks/WERC20Mock.sol"; import {FeeManager} from "../../FeeManager.sol"; import {RewardManager} from "../../RewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol index 3699aaf420..a6b23d7e8b 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.16; import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol"; import {IVerifier} from "../../interfaces/IVerifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {Common} from "../../../libraries/Common.sol"; contract VerifierProxyInitializeVerifierTest is BaseTestWithConfiguredVerifierAndFeeManager { diff --git a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol index b68e283730..b83996a9ed 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol @@ -11,7 +11,7 @@ import {IOwnable} from "../../shared/interfaces/IOwnable.sol"; import {WithdrawalInterface} from "./interfaces/WithdrawalInterface.sol"; import {OracleInterface} from "../../interfaces/OracleInterface.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; -import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; // @title The Chainlink Operator contract // @notice Node operators can deploy this contract to fulfill requests sent to them diff --git a/contracts/src/v0.8/shared/mocks/WERC20Mock.sol b/contracts/src/v0.8/shared/mocks/WERC20Mock.sol index 02c13be993..cee7fa7ff8 100644 --- a/contracts/src/v0.8/shared/mocks/WERC20Mock.sol +++ b/contracts/src/v0.8/shared/mocks/WERC20Mock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {ERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol"; contract WERC20Mock is ERC20 { constructor() ERC20("WERC20Mock", "WERC") {} diff --git a/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol b/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol index 6b13f39000..de9067a569 100644 --- a/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol +++ b/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol @@ -7,8 +7,8 @@ import {IERC677} from "../../../token/ERC677/IERC677.sol"; import {BaseTest} from "../../BaseTest.t.sol"; import {BurnMintERC677} from "../../../token/ERC677/BurnMintERC677.sol"; -import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; contract BurnMintERC677Setup is BaseTest { event Transfer(address indexed from, address indexed to, uint256 value); diff --git a/contracts/src/v0.8/shared/test/token/ERC677/OpStackBurnMintERC677.t.sol b/contracts/src/v0.8/shared/test/token/ERC677/OpStackBurnMintERC677.t.sol index f22a92a425..7987fefec4 100644 --- a/contracts/src/v0.8/shared/test/token/ERC677/OpStackBurnMintERC677.t.sol +++ b/contracts/src/v0.8/shared/test/token/ERC677/OpStackBurnMintERC677.t.sol @@ -9,7 +9,7 @@ import {BurnMintERC677} from "../../../token/ERC677/BurnMintERC677.sol"; import {BaseTest} from "../../BaseTest.t.sol"; import {OpStackBurnMintERC677} from "../../../token/ERC677/OpStackBurnMintERC677.sol"; -import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; contract OpStackBurnMintERC677Setup is BaseTest { address internal s_l1Token = address(897352983527); diff --git a/contracts/src/v0.8/shared/token/ERC20/IBurnMintERC20.sol b/contracts/src/v0.8/shared/token/ERC20/IBurnMintERC20.sol index 2b2f3fd378..b9b3b54bf7 100644 --- a/contracts/src/v0.8/shared/token/ERC20/IBurnMintERC20.sol +++ b/contracts/src/v0.8/shared/token/ERC20/IBurnMintERC20.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; interface IBurnMintERC20 is IERC20 { /// @notice Mints new tokens for a given address. diff --git a/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol b/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol index 6362d9e78a..4e9d3a2494 100644 --- a/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol +++ b/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol @@ -2,7 +2,7 @@ // solhint-disable one-contract-per-file pragma solidity ^0.8.0; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; /// @title IOptimismMintableERC20Minimal /// @dev This interface is a subset of the Optimism ERC20 interface that is defined diff --git a/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol b/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol index 775d5fb3d9..556914da12 100644 --- a/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol +++ b/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol @@ -7,10 +7,10 @@ import {IERC677} from "./IERC677.sol"; import {ERC677} from "./ERC677.sol"; import {OwnerIsCreator} from "../../access/OwnerIsCreator.sol"; -import {ERC20Burnable} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/ERC20Burnable.sol"; -import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {ERC20Burnable} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; /// @notice A basic ERC677 compatible token contract with burn and minting roles. /// @dev The total supply can be limited during deployment. diff --git a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol index c9a2996e8e..9a68bac3a1 100644 --- a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol +++ b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.0; import {IERC677} from "./IERC677.sol"; import {IERC677Receiver} from "./IERC677Receiver.sol"; -import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; -import {ERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/ERC20.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; +import {ERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol"; contract ERC677 is IERC677, ERC20 { using Address for address; diff --git a/contracts/src/v0.8/shared/token/ERC677/OpStackBurnMintERC677.sol b/contracts/src/v0.8/shared/token/ERC677/OpStackBurnMintERC677.sol index 714a4a11ba..95c64c9cd2 100644 --- a/contracts/src/v0.8/shared/token/ERC677/OpStackBurnMintERC677.sol +++ b/contracts/src/v0.8/shared/token/ERC677/OpStackBurnMintERC677.sol @@ -5,7 +5,7 @@ import {IOptimismMintableERC20Minimal, IOptimismMintableERC20} from "../ERC20/IO import {BurnMintERC677} from "./BurnMintERC677.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; /// @notice A basic ERC677 compatible token contract with burn and minting roles that supports /// the native L2 bridging requirements of the Optimism Stack. diff --git a/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol b/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol index 1947379929..ae8b6af1cc 100644 --- a/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol +++ b/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.6 <0.9.0; -import "./openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; +import "./openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; /** * @title iOVM_CrossDomainMessenger diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/draft-IERC20Permit.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/draft-IERC20Permit.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/draft-IERC20Permit.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/draft-IERC20Permit.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/ERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/ERC20.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/ERC20Burnable.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/ERC20Burnable.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/ERC20Burnable.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/ERC20Burnable.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/IERC20Metadata.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/IERC20Metadata.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/draft-ERC20Permit.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/draft-ERC20Permit.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/draft-ERC20Permit.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/draft-ERC20Permit.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/draft-IERC20Permit.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/draft-IERC20Permit.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/draft-IERC20Permit.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/draft-IERC20Permit.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Context.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Context.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Context.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Context.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Counters.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Counters.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Counters.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Counters.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/StorageSlot.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/StorageSlot.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/StorageSlot.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/StorageSlot.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Strings.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Strings.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Strings.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Strings.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/cryptography/ECDSA.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/cryptography/ECDSA.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/cryptography/ECDSA.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/cryptography/ECDSA.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/cryptography/EIP712.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/cryptography/EIP712.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/cryptography/EIP712.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/cryptography/EIP712.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/Math.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/Math.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SignedMath.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SignedMath.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SignedMath.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SignedMath.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol similarity index 100% rename from contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol rename to contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol From 7cadec057ebc180b131deeed49bbb4a8b78aadcc Mon Sep 17 00:00:00 2001 From: Andrei Smirnov Date: Tue, 31 Oct 2023 15:00:50 +0300 Subject: [PATCH 040/327] Contracts: running hardhat tests in parallel (#11090) Co-authored-by: Rens Rooimans --- contracts/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/package.json b/contracts/package.json index 935c7901b6..05a5293e48 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -6,7 +6,7 @@ "license": "MIT", "private": false, "scripts": { - "test": "hardhat test", + "test": "hardhat test --parallel", "lint": "eslint --ext js,ts .", "prettier:check": "prettier '**/*' --check --ignore-unknown", "prettier:write": "prettier '**/*' --write --ignore-unknown", From 8fba9c8a4217356cf51a8ddda1daa62fbdb9e150 Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 31 Oct 2023 12:29:17 +0000 Subject: [PATCH 041/327] [BCF-2727] Add telemetry adapter service (#11125) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../ocr2/plugins/generic/telemetry_adapter.go | 56 +++++++++ .../plugins/generic/telemetry_adapter_test.go | 108 ++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 8 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 core/services/ocr2/plugins/generic/telemetry_adapter.go create mode 100644 core/services/ocr2/plugins/generic/telemetry_adapter_test.go diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 14e29a6740..690a8d189c 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -302,7 +302,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.20231030134738-81a5a89699a0 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 // 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 08356fe076..5cbdb37427 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1458,8 +1458,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.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/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/ocr2/plugins/generic/telemetry_adapter.go b/core/services/ocr2/plugins/generic/telemetry_adapter.go new file mode 100644 index 0000000000..a81befa985 --- /dev/null +++ b/core/services/ocr2/plugins/generic/telemetry_adapter.go @@ -0,0 +1,56 @@ +package generic + +import ( + "context" + "errors" + + "github.com/smartcontractkit/libocr/commontypes" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" +) + +var _ types.TelemetryService = (*TelemetryAdapter)(nil) + +type TelemetryAdapter struct { + endpointGenerator types.MonitoringEndpointGenerator + endpoints map[[4]string]commontypes.MonitoringEndpoint +} + +func NewTelemetryAdapter(endpointGen types.MonitoringEndpointGenerator) *TelemetryAdapter { + return &TelemetryAdapter{ + endpoints: make(map[[4]string]commontypes.MonitoringEndpoint), + endpointGenerator: endpointGen, + } +} + +func (t *TelemetryAdapter) Send(ctx context.Context, network string, chainID string, contractID string, telemetryType string, payload []byte) error { + e, err := t.getOrCreateEndpoint(contractID, telemetryType, network, chainID) + if err != nil { + return err + } + e.SendLog(payload) + return nil +} + +func (t *TelemetryAdapter) getOrCreateEndpoint(contractID string, telemetryType string, network string, chainID string) (commontypes.MonitoringEndpoint, error) { + if contractID == "" { + return nil, errors.New("contractID cannot be empty") + } + if telemetryType == "" { + return nil, errors.New("telemetryType cannot be empty") + } + if network == "" { + return nil, errors.New("network cannot be empty") + } + if chainID == "" { + return nil, errors.New("chainID cannot be empty") + } + + key := [4]string{network, chainID, contractID, telemetryType} + e, ok := t.endpoints[key] + if !ok { + e = t.endpointGenerator.GenMonitoringEndpoint(network, chainID, contractID, telemetryType) + t.endpoints[key] = e + } + return e, nil +} diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter_test.go b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go new file mode 100644 index 0000000000..d430b889a4 --- /dev/null +++ b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go @@ -0,0 +1,108 @@ +package generic + +import ( + "context" + "fmt" + "testing" + + "github.com/smartcontractkit/libocr/commontypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type mockEndpoint struct { + network string + chainID string + contractID string + telemetryType string + payload []byte +} + +func (m *mockEndpoint) SendLog(payload []byte) { m.payload = payload } + +type mockGenerator struct{} + +func (m *mockGenerator) GenMonitoringEndpoint(network, chainID, contractID, telemetryType string) commontypes.MonitoringEndpoint { + return &mockEndpoint{ + network: network, + chainID: chainID, + contractID: contractID, + telemetryType: telemetryType, + } +} + +func TestTelemetryAdapter(t *testing.T) { + ta := NewTelemetryAdapter(&mockGenerator{}) + + tests := []struct { + name string + contractID string + telemetryType string + networkID string + chainID string + payload []byte + errorMsg string + }{ + { + name: "valid request", + contractID: "contract", + telemetryType: "mercury", + networkID: "solana", + chainID: "1337", + payload: []byte("uh oh"), + }, + { + name: "no valid contractID", + telemetryType: "mercury", + networkID: "solana", + chainID: "1337", + payload: []byte("uh oh"), + errorMsg: "contractID cannot be empty", + }, + { + name: "no valid chainID", + contractID: "contract", + telemetryType: "mercury", + networkID: "solana", + payload: []byte("uh oh"), + errorMsg: "chainID cannot be empty", + }, + { + name: "no valid telemetryType", + contractID: "contract", + networkID: "solana", + chainID: "1337", + payload: []byte("uh oh"), + errorMsg: "telemetryType cannot be empty", + }, + { + name: "no valid network", + contractID: "contract", + telemetryType: "mercury", + chainID: "1337", + payload: []byte("uh oh"), + errorMsg: "network cannot be empty", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := ta.Send(context.Background(), test.networkID, test.chainID, test.contractID, test.telemetryType, test.payload) + if test.errorMsg != "" { + assert.ErrorContains(t, err, test.errorMsg) + } else { + require.NoError(t, err) + key := [4]string{test.networkID, test.chainID, test.contractID, test.telemetryType} + fmt.Printf("%+v", ta.endpoints) + endpoint, ok := ta.endpoints[key] + require.True(t, ok) + + me := endpoint.(*mockEndpoint) + assert.Equal(t, test.networkID, me.network) + assert.Equal(t, test.chainID, me.chainID) + assert.Equal(t, test.contractID, me.contractID) + assert.Equal(t, test.telemetryType, me.telemetryType) + assert.Equal(t, test.payload, me.payload) + } + }) + } +} diff --git a/go.mod b/go.mod index 9c14fe8c14..ad3cb5f78e 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,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.20231030134738-81a5a89699a0 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 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-20231020123319-d255366a6545 diff --git a/go.sum b/go.sum index 372e705c71..f879f16272 100644 --- a/go.sum +++ b/go.sum @@ -1459,8 +1459,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.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/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 1263c406aa..3affd79919 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -384,7 +384,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.20231030134738-81a5a89699a0 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 // 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/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 08c037dd0c..98685fdf88 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2362,8 +2362,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.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436 h1:XJuWThPInOZ9Bz0zM8xmACO+Ly/cY9+0JOILkHlN/2o= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231030111206-48c9bf5d5436/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/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= From 9fd1d5d0e28dd631ac879035f56bee7e03e78713 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 31 Oct 2023 09:45:26 -0500 Subject: [PATCH 042/327] golangci-lint fix issue & disable only-new-issues (#11133) * core/services/ocr/plugins/generic: rm unused error return * .github/actions/golangci-lint: disable only-new-issues --- .github/actions/golangci-lint/action.yml | 2 +- .../ocr2/plugins/generic/pipeline_runner_adapter.go | 9 ++------- .../ocr2/plugins/generic/pipeline_runner_adapter_test.go | 3 +-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index c9ea735d1f..97755fa46e 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -58,7 +58,7 @@ runs: skip-pkg-cache: true skip-build-cache: true # only-new-issues is only applicable to PRs, otherwise it is always set to false - only-new-issues: true + only-new-issues: false # disabled for PRs due to unreliability args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml working-directory: ${{ inputs.go-directory }} - name: Store lint report artifact diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go index 5c58522f40..6afb35ca75 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go @@ -41,10 +41,7 @@ func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, var }, } - err := merge(defaultVars, vars.Vars) - if err != nil { - return nil, err - } + merge(defaultVars, vars.Vars) finalVars := pipeline.NewVarsFrom(defaultVars) _, trrs, err := p.runner.ExecuteRun(ctx, s, finalVars, p.logger) @@ -74,7 +71,7 @@ func NewPipelineRunnerAdapter(logger logger.Logger, job job.Job, runner pipeline } // merge merges mapTwo into mapOne, modifying mapOne in the process. -func merge(mapOne, mapTwo map[string]interface{}) error { +func merge(mapOne, mapTwo map[string]interface{}) { for k, v := range mapTwo { // if `mapOne` doesn't have `k`, then nothing to do, just assign v to `mapOne`. if _, ok := mapOne[k]; !ok { @@ -89,6 +86,4 @@ func merge(mapOne, mapTwo map[string]interface{}) error { } } } - - return nil } diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go index d1f06d8766..ee0038232d 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go @@ -131,8 +131,7 @@ func TestMerge(t *testing.T) { "val": 0, } - err := merge(vars, addedVars) - require.NoError(t, err) + merge(vars, addedVars) assert.True(t, reflect.DeepEqual(vars, map[string]interface{}{ "jb": map[string]interface{}{ From 921a89ca6243d274062b2090458e6b40421242e9 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Tue, 31 Oct 2023 20:14:02 +0100 Subject: [PATCH 043/327] BCF-2672 cleanup legacy job orm env var loading (#11119) * Remove unused DRSpecConfig param in LoadEnvConfigVarsVRF * Remove unused DirectRequestSpec MinIncomingConfirmationsEnv field * Remove unnecessary DRSpecConfig wrapper interface from job orm * Remove DirectRequestSpec MinIncomingConfirmations override from job orm MinIncomingConfirmations for DirectRequestSpec already gets overridden in delegate before its only usage * Remove DirectRequestSpec MinIncomingConfirmationsENV from graphql spec * Revert removal of DirectRequestSpec MinIncomingConfirmationsENV * Remove legacy chains from job orm - Remove LoadEnvConfigVarsOCR for ocr spec, because it gets called in delegate anyway - Remove legacy chains as it is no longer used in orm * Remove unused legacyChains from job_orm_test.go * Revert "Remove unused legacyChains from job_orm_test.go" This reverts commit dce7e3f5dc67fb924a204ecb5f1491a970786286. * Revert "Remove legacy chains from job orm" This reverts commit a41a48f74b11235a4e9519e691eab31e6bb6088d. * Rename legacy env var loading funcs in job orm and cleanup unused stuff * Remove unused legacy tramsnimtter address env * minor func rename * Update func signature in calls to LoadDefaultVRFPollPeriod * Remove EncryptedOCRKeyBundleIDEnv and ConfirmationsEnv --- core/services/directrequest/delegate.go | 2 +- core/services/job/models.go | 74 +++++++-------- core/services/job/orm.go | 62 ++++--------- core/services/job/orm_test.go | 32 +++---- core/services/ocr/config.go | 2 +- core/services/ocr/delegate.go | 2 +- core/services/vrf/v1/listener_v1.go | 2 +- core/services/vrf/v2/listener_v2.go | 2 +- core/web/presenters/job.go | 114 ++++++++++-------------- core/web/resolver/spec.go | 58 ------------ core/web/resolver/spec_test.go | 72 +++++---------- core/web/schema/type/spec.graphql | 10 --- 12 files changed, 140 insertions(+), 292 deletions(-) diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 174dca062a..920f94b4d6 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -77,7 +77,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if err != nil { return nil, err } - concreteSpec := job.LoadEnvConfigVarsDR(chain.Config().EVM(), *jb.DirectRequestSpec) + concreteSpec := job.SetDRMinIncomingConfirmations(chain.Config().EVM().MinIncomingConfirmations(), *jb.DirectRequestSpec) oracle, err := operator_wrapper.NewOperator(concreteSpec.ContractAddress.Address(), chain.Client()) if err != nil { diff --git a/core/services/job/models.go b/core/services/job/models.go index a3dfce5999..a474040dd4 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -15,6 +15,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -233,35 +234,25 @@ func (pr *PipelineRun) SetID(value string) error { // OCROracleSpec defines the job spec for OCR jobs. type OCROracleSpec struct { - ID int32 `toml:"-"` - ContractAddress ethkey.EIP55Address `toml:"contractAddress"` - P2PBootstrapPeers pq.StringArray `toml:"p2pBootstrapPeers" db:"p2p_bootstrap_peers"` - P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers" db:"p2pv2_bootstrappers"` - IsBootstrapPeer bool `toml:"isBootstrapPeer"` - EncryptedOCRKeyBundleID *models.Sha256Hash `toml:"keyBundleID"` - EncryptedOCRKeyBundleIDEnv bool - TransmitterAddress *ethkey.EIP55Address `toml:"transmitterAddress"` - TransmitterAddressEnv bool - ObservationTimeout models.Interval `toml:"observationTimeout"` - ObservationTimeoutEnv bool - BlockchainTimeout models.Interval `toml:"blockchainTimeout"` - BlockchainTimeoutEnv bool - ContractConfigTrackerSubscribeInterval models.Interval `toml:"contractConfigTrackerSubscribeInterval"` - ContractConfigTrackerSubscribeIntervalEnv bool - ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` - ContractConfigTrackerPollIntervalEnv bool - ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` - ContractConfigConfirmationsEnv bool - EVMChainID *utils.Big `toml:"evmChainID" db:"evm_chain_id"` - DatabaseTimeout *models.Interval `toml:"databaseTimeout"` - DatabaseTimeoutEnv bool - ObservationGracePeriod *models.Interval `toml:"observationGracePeriod"` - ObservationGracePeriodEnv bool - ContractTransmitterTransmitTimeout *models.Interval `toml:"contractTransmitterTransmitTimeout"` - ContractTransmitterTransmitTimeoutEnv bool - CaptureEATelemetry bool `toml:"captureEATelemetry"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` + ID int32 `toml:"-"` + ContractAddress ethkey.EIP55Address `toml:"contractAddress"` + P2PBootstrapPeers pq.StringArray `toml:"p2pBootstrapPeers" db:"p2p_bootstrap_peers"` + P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers" db:"p2pv2_bootstrappers"` + IsBootstrapPeer bool `toml:"isBootstrapPeer"` + EncryptedOCRKeyBundleID *models.Sha256Hash `toml:"keyBundleID"` + TransmitterAddress *ethkey.EIP55Address `toml:"transmitterAddress"` + ObservationTimeout models.Interval `toml:"observationTimeout"` + BlockchainTimeout models.Interval `toml:"blockchainTimeout"` + ContractConfigTrackerSubscribeInterval models.Interval `toml:"contractConfigTrackerSubscribeInterval"` + ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` + ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` + EVMChainID *utils.Big `toml:"evmChainID" db:"evm_chain_id"` + DatabaseTimeout *models.Interval `toml:"databaseTimeout"` + ObservationGracePeriod *models.Interval `toml:"observationGracePeriod"` + ContractTransmitterTransmitTimeout *models.Interval `toml:"contractTransmitterTransmitTimeout"` + CaptureEATelemetry bool `toml:"captureEATelemetry"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` } // GetID is a getter function that returns the ID of the spec. @@ -438,15 +429,14 @@ func (w *WebhookSpec) SetID(value string) error { } type DirectRequestSpec struct { - ID int32 `toml:"-"` - ContractAddress ethkey.EIP55Address `toml:"contractAddress"` - MinIncomingConfirmations clnull.Uint32 `toml:"minIncomingConfirmations"` - MinIncomingConfirmationsEnv bool `toml:"minIncomingConfirmationsEnv"` - Requesters models.AddressCollection `toml:"requesters"` - MinContractPayment *assets.Link `toml:"minContractPaymentLinkJuels"` - EVMChainID *utils.Big `toml:"evmChainID"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` + ID int32 `toml:"-"` + ContractAddress ethkey.EIP55Address `toml:"contractAddress"` + MinIncomingConfirmations clnull.Uint32 `toml:"minIncomingConfirmations"` + Requesters models.AddressCollection `toml:"requesters"` + MinContractPayment *assets.Link `toml:"minContractPaymentLinkJuels"` + EVMChainID *utils.Big `toml:"evmChainID"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` } type CronSpec struct { @@ -522,13 +512,11 @@ type VRFSpec struct { CoordinatorAddress ethkey.EIP55Address `toml:"coordinatorAddress"` PublicKey secp256k1.PublicKey `toml:"publicKey"` MinIncomingConfirmations uint32 `toml:"minIncomingConfirmations"` - ConfirmationsEnv bool `toml:"-"` EVMChainID *utils.Big `toml:"evmChainID"` FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` - PollPeriod time.Duration `toml:"pollPeriod"` // For v2 jobs - PollPeriodEnv bool - RequestedConfsDelay int64 `toml:"requestedConfsDelay"` // For v2 jobs. Optional, defaults to 0 if not provided. - RequestTimeout time.Duration `toml:"requestTimeout"` // Optional, defaults to 24hr if not provided. + PollPeriod time.Duration `toml:"pollPeriod"` // For v2 jobs + RequestedConfsDelay int64 `toml:"requestedConfsDelay"` // For v2 jobs. Optional, defaults to 0 if not provided. + RequestTimeout time.Duration `toml:"requestTimeout"` // Optional, defaults to 24hr if not provided. // GasLanePrice specifies the gas lane price for this VRF job. // If the specified keys in FromAddresses do not have the provided gas price the job diff --git a/core/services/job/orm.go b/core/services/job/orm.go index cbdd7ebfae..372b2fe74a 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -705,61 +705,41 @@ func (o *orm) FindJobs(offset, limit int) (jobs []Job, count int, err error) { return err } for i := range jobs { - err = multierr.Combine(err, o.LoadEnvConfigVars(&jobs[i])) + err = multierr.Combine(err, o.LoadConfigVars(&jobs[i])) } return nil }) return jobs, int(count), err } -func (o *orm) LoadEnvConfigVars(jb *Job) error { +func (o *orm) LoadConfigVars(jb *Job) error { if jb.OCROracleSpec != nil { ch, err := o.legacyChains.Get(jb.OCROracleSpec.EVMChainID.String()) if err != nil { return err } - newSpec, err := LoadEnvConfigVarsOCR(ch.Config().EVM().OCR(), ch.Config().OCR(), *jb.OCROracleSpec) + newSpec, err := LoadConfigVarsOCR(ch.Config().EVM().OCR(), ch.Config().OCR(), *jb.OCROracleSpec) if err != nil { return err } jb.OCROracleSpec = newSpec - } else if jb.VRFSpec != nil { - ch, err := o.legacyChains.Get(jb.VRFSpec.EVMChainID.String()) - if err != nil { - return err - } - jb.VRFSpec = LoadEnvConfigVarsVRF(ch.Config().EVM(), *jb.VRFSpec) - } else if jb.DirectRequestSpec != nil { - ch, err := o.legacyChains.Get(jb.DirectRequestSpec.EVMChainID.String()) - if err != nil { - return err - } - jb.DirectRequestSpec = LoadEnvConfigVarsDR(ch.Config().EVM(), *jb.DirectRequestSpec) } return nil } -type DRSpecConfig interface { - MinIncomingConfirmations() uint32 -} - -func LoadEnvConfigVarsVRF(cfg DRSpecConfig, vrfs VRFSpec) *VRFSpec { +func LoadDefaultVRFPollPeriod(vrfs VRFSpec) *VRFSpec { if vrfs.PollPeriod == 0 { - vrfs.PollPeriodEnv = true vrfs.PollPeriod = 5 * time.Second } return &vrfs } -func LoadEnvConfigVarsDR(cfg DRSpecConfig, drs DirectRequestSpec) *DirectRequestSpec { - // Take the largest of the global vs specific. - minIncomingConfirmations := cfg.MinIncomingConfirmations() - if !drs.MinIncomingConfirmations.Valid || drs.MinIncomingConfirmations.Uint32 < minIncomingConfirmations { - drs.MinIncomingConfirmationsEnv = true - drs.MinIncomingConfirmations = null.Uint32From(minIncomingConfirmations) +// SetDRMinIncomingConfirmations takes the largest of the global vs specific. +func SetDRMinIncomingConfirmations(defaultMinIncomingConfirmations uint32, drs DirectRequestSpec) *DirectRequestSpec { + if !drs.MinIncomingConfirmations.Valid || drs.MinIncomingConfirmations.Uint32 < defaultMinIncomingConfirmations { + drs.MinIncomingConfirmations = null.Uint32From(defaultMinIncomingConfirmations) } - return &drs } @@ -773,38 +753,30 @@ type OCRConfig interface { TransmitterAddress() (ethkey.EIP55Address, error) } -// LoadEnvConfigVarsLocalOCR loads local OCR env vars into the OCROracleSpec. -func LoadEnvConfigVarsLocalOCR(evmOcrCfg evmconfig.OCR, os OCROracleSpec, ocrCfg OCRConfig) *OCROracleSpec { +// LoadConfigVarsLocalOCR loads local OCR vars into the OCROracleSpec. +func LoadConfigVarsLocalOCR(evmOcrCfg evmconfig.OCR, os OCROracleSpec, ocrCfg OCRConfig) *OCROracleSpec { if os.ObservationTimeout == 0 { - os.ObservationTimeoutEnv = true os.ObservationTimeout = models.Interval(ocrCfg.ObservationTimeout()) } if os.BlockchainTimeout == 0 { - os.BlockchainTimeoutEnv = true os.BlockchainTimeout = models.Interval(ocrCfg.BlockchainTimeout()) } if os.ContractConfigTrackerSubscribeInterval == 0 { - os.ContractConfigTrackerSubscribeIntervalEnv = true os.ContractConfigTrackerSubscribeInterval = models.Interval(ocrCfg.ContractSubscribeInterval()) } if os.ContractConfigTrackerPollInterval == 0 { - os.ContractConfigTrackerPollIntervalEnv = true os.ContractConfigTrackerPollInterval = models.Interval(ocrCfg.ContractPollInterval()) } if os.ContractConfigConfirmations == 0 { - os.ContractConfigConfirmationsEnv = true os.ContractConfigConfirmations = evmOcrCfg.ContractConfirmations() } if os.DatabaseTimeout == nil { - os.DatabaseTimeoutEnv = true os.DatabaseTimeout = models.NewInterval(evmOcrCfg.DatabaseTimeout()) } if os.ObservationGracePeriod == nil { - os.ObservationGracePeriodEnv = true os.ObservationGracePeriod = models.NewInterval(evmOcrCfg.ObservationGracePeriod()) } if os.ContractTransmitterTransmitTimeout == nil { - os.ContractTransmitterTransmitTimeoutEnv = true os.ContractTransmitterTransmitTimeout = models.NewInterval(evmOcrCfg.ContractTransmitterTransmitTimeout()) } os.CaptureEATelemetry = ocrCfg.CaptureEATelemetry() @@ -812,15 +784,14 @@ func LoadEnvConfigVarsLocalOCR(evmOcrCfg evmconfig.OCR, os OCROracleSpec, ocrCfg return &os } -// LoadEnvConfigVarsOCR loads OCR env vars into the OCROracleSpec. -func LoadEnvConfigVarsOCR(evmOcrCfg evmconfig.OCR, ocrCfg OCRConfig, os OCROracleSpec) (*OCROracleSpec, error) { +// LoadConfigVarsOCR loads OCR config vars into the OCROracleSpec. +func LoadConfigVarsOCR(evmOcrCfg evmconfig.OCR, ocrCfg OCRConfig, os OCROracleSpec) (*OCROracleSpec, error) { if os.TransmitterAddress == nil { ta, err := ocrCfg.TransmitterAddress() if !errors.Is(errors.Cause(err), config.ErrEnvUnset) { if err != nil { return nil, err } - os.TransmitterAddressEnv = true os.TransmitterAddress = &ta } } @@ -834,11 +805,10 @@ func LoadEnvConfigVarsOCR(evmOcrCfg evmconfig.OCR, ocrCfg OCRConfig, os OCROracl if err != nil { return nil, err } - os.EncryptedOCRKeyBundleIDEnv = true os.EncryptedOCRKeyBundleID = &encryptedOCRKeyBundleID } - return LoadEnvConfigVarsLocalOCR(evmOcrCfg, os, ocrCfg), nil + return LoadConfigVarsLocalOCR(evmOcrCfg, os, ocrCfg), nil } func (o *orm) FindJobTx(id int32) (Job, error) { @@ -872,7 +842,7 @@ func (o *orm) FindJobWithoutSpecErrors(id int32) (jb Job, err error) { return jb, errors.Wrap(err, "FindJobWithoutSpecErrors failed") } - return jb, o.LoadEnvConfigVars(&jb) + return jb, o.LoadConfigVars(&jb) } // FindSpecErrorsByJobIDs returns all jobs spec errors by jobs IDs @@ -961,7 +931,7 @@ func (o *orm) findJob(jb *Job, col string, arg interface{}, qopts ...pg.QOpt) er if err != nil { return errors.Wrap(err, "findJob failed") } - return o.LoadEnvConfigVars(jb) + return o.LoadConfigVars(jb) } func (o *orm) FindJobIDsWithBridge(name string) (jids []int32, err error) { @@ -1205,7 +1175,7 @@ func (o *orm) FindJobsByPipelineSpecIDs(ids []int32) ([]Job, error) { return err } for i := range jbs { - err = o.LoadEnvConfigVars(&jbs[i]) + err = o.LoadConfigVars(&jbs[i]) //We must return the jobs even if the chainID is disabled if err != nil && !errors.Is(err, chains.ErrNoSuchChainID) { return err diff --git a/core/services/job/orm_test.go b/core/services/job/orm_test.go index a6986d7fb3..cd437147b4 100644 --- a/core/services/job/orm_test.go +++ b/core/services/job/orm_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func NewTestORM(t *testing.T, db *sqlx.DB, legacyChains evm.LegacyChainContainer, pipelineORM pipeline.ORM, bridgeORM bridges.ORM, keyStore keystore.Master, cfg pg.QConfig) job.ORM { @@ -27,26 +28,28 @@ func NewTestORM(t *testing.T, db *sqlx.DB, legacyChains evm.LegacyChainContainer return o } -func TestLoadEnvConfigVarsLocalOCR(t *testing.T) { +func TestLoadConfigVarsLocalOCR(t *testing.T) { t.Parallel() config := configtest.NewTestGeneralConfig(t) chainConfig := evmtest.NewChainScopedConfig(t, config) jobSpec := &job.OCROracleSpec{} - jobSpec = job.LoadEnvConfigVarsLocalOCR(chainConfig.EVM().OCR(), *jobSpec, chainConfig.OCR()) + jobSpec = job.LoadConfigVarsLocalOCR(chainConfig.EVM().OCR(), *jobSpec, chainConfig.OCR()) - require.True(t, jobSpec.ObservationTimeoutEnv) - require.True(t, jobSpec.BlockchainTimeoutEnv) - require.True(t, jobSpec.ContractConfigTrackerSubscribeIntervalEnv) - require.True(t, jobSpec.ContractConfigTrackerPollIntervalEnv) - require.True(t, jobSpec.ContractConfigConfirmationsEnv) - require.True(t, jobSpec.DatabaseTimeoutEnv) - require.True(t, jobSpec.ObservationGracePeriodEnv) - require.True(t, jobSpec.ContractTransmitterTransmitTimeoutEnv) + require.Equal(t, models.Interval(chainConfig.OCR().ObservationTimeout()), jobSpec.ObservationTimeout) + require.Equal(t, models.Interval(chainConfig.OCR().BlockchainTimeout()), jobSpec.BlockchainTimeout) + require.Equal(t, models.Interval(chainConfig.OCR().ContractSubscribeInterval()), jobSpec.ContractConfigTrackerSubscribeInterval) + require.Equal(t, models.Interval(chainConfig.OCR().ContractPollInterval()), jobSpec.ContractConfigTrackerPollInterval) + require.Equal(t, chainConfig.OCR().CaptureEATelemetry(), jobSpec.CaptureEATelemetry) + + require.Equal(t, chainConfig.EVM().OCR().ContractConfirmations(), jobSpec.ContractConfigConfirmations) + require.Equal(t, models.Interval(chainConfig.EVM().OCR().DatabaseTimeout()), *jobSpec.DatabaseTimeout) + require.Equal(t, models.Interval(chainConfig.EVM().OCR().ObservationGracePeriod()), *jobSpec.ObservationGracePeriod) + require.Equal(t, models.Interval(chainConfig.EVM().OCR().ContractTransmitterTransmitTimeout()), *jobSpec.ContractTransmitterTransmitTimeout) } -func TestLoadEnvConfigVarsDR(t *testing.T) { +func TestSetDRMinIncomingConfirmations(t *testing.T) { t.Parallel() config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -59,15 +62,14 @@ func TestLoadEnvConfigVarsDR(t *testing.T) { MinIncomingConfirmations: clnull.Uint32From(10), } - drs10 := job.LoadEnvConfigVarsDR(chainConfig.EVM(), jobSpec10) - assert.True(t, drs10.MinIncomingConfirmationsEnv) + drs10 := job.SetDRMinIncomingConfirmations(chainConfig.EVM().MinIncomingConfirmations(), jobSpec10) + assert.Equal(t, uint32(100), drs10.MinIncomingConfirmations.Uint32) jobSpec200 := job.DirectRequestSpec{ MinIncomingConfirmations: clnull.Uint32From(200), } - drs200 := job.LoadEnvConfigVarsDR(chainConfig.EVM(), jobSpec200) - assert.False(t, drs200.MinIncomingConfirmationsEnv) + drs200 := job.SetDRMinIncomingConfirmations(chainConfig.EVM().MinIncomingConfirmations(), jobSpec200) assert.True(t, drs200.MinIncomingConfirmations.Valid) assert.Equal(t, uint32(200), drs200.MinIncomingConfirmations.Uint32) } diff --git a/core/services/ocr/config.go b/core/services/ocr/config.go index e1bc997f26..53ec9f9cea 100644 --- a/core/services/ocr/config.go +++ b/core/services/ocr/config.go @@ -14,7 +14,7 @@ type Config interface { } func toLocalConfig(cfg ValidationConfig, evmOcrConfig evmconfig.OCR, insecureCfg insecureConfig, spec job.OCROracleSpec, ocrConfig job.OCRConfig) ocrtypes.LocalConfig { - concreteSpec := job.LoadEnvConfigVarsLocalOCR(evmOcrConfig, spec, ocrConfig) + concreteSpec := job.LoadConfigVarsLocalOCR(evmOcrConfig, spec, ocrConfig) lc := ocrtypes.LocalConfig{ BlockchainTimeout: concreteSpec.BlockchainTimeout.Duration(), ContractConfigConfirmations: concreteSpec.ContractConfigConfirmations, diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index dee349a9a0..b761690485 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -95,7 +95,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e if err != nil { return nil, err } - concreteSpec, err := job.LoadEnvConfigVarsOCR(chain.Config().EVM().OCR(), chain.Config().OCR(), *jb.OCROracleSpec) + concreteSpec, err := job.LoadConfigVarsOCR(chain.Config().EVM().OCR(), chain.Config().OCR(), *jb.OCROracleSpec) if err != nil { return nil, err } diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 613c0d124d..92e697f229 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -112,7 +112,7 @@ func (lsn *Listener) getLatestHead() uint64 { // Start complies with job.Service func (lsn *Listener) Start(context.Context) error { return lsn.StartOnce("VRFListener", func() error { - spec := job.LoadEnvConfigVarsVRF(lsn.Cfg, *lsn.Job.VRFSpec) + spec := job.LoadDefaultVRFPollPeriod(*lsn.Job.VRFSpec) unsubscribeLogs := lsn.LogBroadcaster.Register(lsn, log.ListenerOpts{ Contract: lsn.Coordinator.Address(), diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 7560baad3a..8bac485d65 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -271,7 +271,7 @@ func (lsn *listenerV2) Start(ctx context.Context) error { "proofVerificationGas", GasProofVerification) } - spec := job.LoadEnvConfigVarsVRF(lsn.cfg, *lsn.job.VRFSpec) + spec := job.LoadDefaultVRFPollPeriod(*lsn.job.VRFSpec) unsubscribeLogs := lsn.logBroadcaster.Register(lsn, log.ListenerOpts{ Contract: lsn.coordinator.Address(), diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index 2aa9773088..06b9950755 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -41,26 +41,24 @@ const ( // DirectRequestSpec defines the spec details of a DirectRequest Job type DirectRequestSpec struct { - ContractAddress ethkey.EIP55Address `json:"contractAddress"` - MinIncomingConfirmations clnull.Uint32 `json:"minIncomingConfirmations"` - MinIncomingConfirmationsEnv bool `json:"minIncomingConfirmationsEnv,omitempty"` - MinContractPayment *assets.Link `json:"minContractPaymentLinkJuels"` - Requesters models.AddressCollection `json:"requesters"` - Initiator string `json:"initiator"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + ContractAddress ethkey.EIP55Address `json:"contractAddress"` + MinIncomingConfirmations clnull.Uint32 `json:"minIncomingConfirmations"` + MinContractPayment *assets.Link `json:"minContractPaymentLinkJuels"` + Requesters models.AddressCollection `json:"requesters"` + Initiator string `json:"initiator"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + EVMChainID *utils.Big `json:"evmChainID"` } // NewDirectRequestSpec initializes a new DirectRequestSpec from a // job.DirectRequestSpec func NewDirectRequestSpec(spec *job.DirectRequestSpec) *DirectRequestSpec { return &DirectRequestSpec{ - ContractAddress: spec.ContractAddress, - MinIncomingConfirmations: spec.MinIncomingConfirmations, - MinIncomingConfirmationsEnv: spec.MinIncomingConfirmationsEnv, - MinContractPayment: spec.MinContractPayment, - Requesters: spec.Requesters, + ContractAddress: spec.ContractAddress, + MinIncomingConfirmations: spec.MinIncomingConfirmations, + MinContractPayment: spec.MinContractPayment, + Requesters: spec.Requesters, // This is hardcoded to runlog. When we support other initiators, we need // to change this Initiator: "runlog", @@ -120,64 +118,48 @@ func NewFluxMonitorSpec(spec *job.FluxMonitorSpec) *FluxMonitorSpec { // OffChainReportingSpec defines the spec details of a OffChainReporting Job type OffChainReportingSpec struct { - ContractAddress ethkey.EIP55Address `json:"contractAddress"` - P2PBootstrapPeers pq.StringArray `json:"p2pBootstrapPeers"` - P2PV2Bootstrappers pq.StringArray `json:"p2pv2Bootstrappers"` - IsBootstrapPeer bool `json:"isBootstrapPeer"` - EncryptedOCRKeyBundleID *models.Sha256Hash `json:"keyBundleID"` - TransmitterAddress *ethkey.EIP55Address `json:"transmitterAddress"` - ObservationTimeout models.Interval `json:"observationTimeout"` - ObservationTimeoutEnv bool `json:"observationTimeoutEnv,omitempty"` - BlockchainTimeout models.Interval `json:"blockchainTimeout"` - BlockchainTimeoutEnv bool `json:"blockchainTimeoutEnv,omitempty"` - ContractConfigTrackerSubscribeInterval models.Interval `json:"contractConfigTrackerSubscribeInterval"` - ContractConfigTrackerSubscribeIntervalEnv bool `json:"contractConfigTrackerSubscribeIntervalEnv,omitempty"` - ContractConfigTrackerPollInterval models.Interval `json:"contractConfigTrackerPollInterval"` - ContractConfigTrackerPollIntervalEnv bool `json:"contractConfigTrackerPollIntervalEnv,omitempty"` - ContractConfigConfirmations uint16 `json:"contractConfigConfirmations"` - ContractConfigConfirmationsEnv bool `json:"contractConfigConfirmationsEnv,omitempty"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` - DatabaseTimeout *models.Interval `json:"databaseTimeout"` - DatabaseTimeoutEnv bool `json:"databaseTimeoutEnv,omitempty"` - ObservationGracePeriod *models.Interval `json:"observationGracePeriod"` - ObservationGracePeriodEnv bool `json:"observationGracePeriodEnv,omitempty"` - ContractTransmitterTransmitTimeout *models.Interval `json:"contractTransmitterTransmitTimeout"` - ContractTransmitterTransmitTimeoutEnv bool `json:"contractTransmitterTransmitTimeoutEnv,omitempty"` - CollectTelemetry bool `json:"collectTelemetry,omitempty"` + ContractAddress ethkey.EIP55Address `json:"contractAddress"` + P2PBootstrapPeers pq.StringArray `json:"p2pBootstrapPeers"` + P2PV2Bootstrappers pq.StringArray `json:"p2pv2Bootstrappers"` + IsBootstrapPeer bool `json:"isBootstrapPeer"` + EncryptedOCRKeyBundleID *models.Sha256Hash `json:"keyBundleID"` + TransmitterAddress *ethkey.EIP55Address `json:"transmitterAddress"` + ObservationTimeout models.Interval `json:"observationTimeout"` + BlockchainTimeout models.Interval `json:"blockchainTimeout"` + ContractConfigTrackerSubscribeInterval models.Interval `json:"contractConfigTrackerSubscribeInterval"` + ContractConfigTrackerPollInterval models.Interval `json:"contractConfigTrackerPollInterval"` + ContractConfigConfirmations uint16 `json:"contractConfigConfirmations"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + EVMChainID *utils.Big `json:"evmChainID"` + DatabaseTimeout *models.Interval `json:"databaseTimeout"` + ObservationGracePeriod *models.Interval `json:"observationGracePeriod"` + ContractTransmitterTransmitTimeout *models.Interval `json:"contractTransmitterTransmitTimeout"` + CollectTelemetry bool `json:"collectTelemetry,omitempty"` } // NewOffChainReportingSpec initializes a new OffChainReportingSpec from a // job.OCROracleSpec func NewOffChainReportingSpec(spec *job.OCROracleSpec) *OffChainReportingSpec { return &OffChainReportingSpec{ - ContractAddress: spec.ContractAddress, - P2PBootstrapPeers: spec.P2PBootstrapPeers, - P2PV2Bootstrappers: spec.P2PV2Bootstrappers, - IsBootstrapPeer: spec.IsBootstrapPeer, - EncryptedOCRKeyBundleID: spec.EncryptedOCRKeyBundleID, - TransmitterAddress: spec.TransmitterAddress, - ObservationTimeout: spec.ObservationTimeout, - ObservationTimeoutEnv: spec.ObservationTimeoutEnv, - BlockchainTimeout: spec.BlockchainTimeout, - BlockchainTimeoutEnv: spec.BlockchainTimeoutEnv, - ContractConfigTrackerSubscribeInterval: spec.ContractConfigTrackerSubscribeInterval, - ContractConfigTrackerSubscribeIntervalEnv: spec.ContractConfigTrackerSubscribeIntervalEnv, - ContractConfigTrackerPollInterval: spec.ContractConfigTrackerPollInterval, - ContractConfigTrackerPollIntervalEnv: spec.ContractConfigTrackerPollIntervalEnv, - ContractConfigConfirmations: spec.ContractConfigConfirmations, - ContractConfigConfirmationsEnv: spec.ContractConfigConfirmationsEnv, - CreatedAt: spec.CreatedAt, - UpdatedAt: spec.UpdatedAt, - EVMChainID: spec.EVMChainID, - DatabaseTimeout: spec.DatabaseTimeout, - DatabaseTimeoutEnv: spec.DatabaseTimeoutEnv, - ObservationGracePeriod: spec.ObservationGracePeriod, - ObservationGracePeriodEnv: spec.ObservationGracePeriodEnv, - ContractTransmitterTransmitTimeout: spec.ContractTransmitterTransmitTimeout, - ContractTransmitterTransmitTimeoutEnv: spec.ContractTransmitterTransmitTimeoutEnv, - CollectTelemetry: spec.CaptureEATelemetry, + ContractAddress: spec.ContractAddress, + P2PBootstrapPeers: spec.P2PBootstrapPeers, + P2PV2Bootstrappers: spec.P2PV2Bootstrappers, + IsBootstrapPeer: spec.IsBootstrapPeer, + EncryptedOCRKeyBundleID: spec.EncryptedOCRKeyBundleID, + TransmitterAddress: spec.TransmitterAddress, + ObservationTimeout: spec.ObservationTimeout, + BlockchainTimeout: spec.BlockchainTimeout, + ContractConfigTrackerSubscribeInterval: spec.ContractConfigTrackerSubscribeInterval, + ContractConfigTrackerPollInterval: spec.ContractConfigTrackerPollInterval, + ContractConfigConfirmations: spec.ContractConfigConfirmations, + CreatedAt: spec.CreatedAt, + UpdatedAt: spec.UpdatedAt, + EVMChainID: spec.EVMChainID, + DatabaseTimeout: spec.DatabaseTimeout, + ObservationGracePeriod: spec.ObservationGracePeriod, + ContractTransmitterTransmitTimeout: spec.ContractTransmitterTransmitTimeout, + CollectTelemetry: spec.CaptureEATelemetry, } } diff --git a/core/web/resolver/spec.go b/core/web/resolver/spec.go index 48040d118a..c9ee519922 100644 --- a/core/web/resolver/spec.go +++ b/core/web/resolver/spec.go @@ -164,11 +164,6 @@ func (r *DirectRequestSpecResolver) MinIncomingConfirmations() int32 { return 0 } -// EVMChainID resolves the spec's evm chain id. -func (r *DirectRequestSpecResolver) MinIncomingConfirmationsEnv() bool { - return r.spec.MinIncomingConfirmationsEnv -} - // MinContractPaymentLinkJuels resolves the spec's min contract payment link. func (r *DirectRequestSpecResolver) MinContractPaymentLinkJuels() string { return r.spec.MinContractPayment.String() @@ -328,12 +323,6 @@ func (r *OCRSpecResolver) BlockchainTimeout() *string { return &timeout } -// BlockchainTimeoutEnv resolves whether the spec's blockchain timeout comes -// from an env var. -func (r *OCRSpecResolver) BlockchainTimeoutEnv() bool { - return r.spec.BlockchainTimeoutEnv -} - // ContractAddress resolves the spec's contract address. func (r *OCRSpecResolver) ContractAddress() string { return r.spec.ContractAddress.String() @@ -350,12 +339,6 @@ func (r *OCRSpecResolver) ContractConfigConfirmations() *int32 { return &confirmations } -// ContractConfigConfirmationsEnv resolves whether spec's confirmations -// config comes from an env var. -func (r *OCRSpecResolver) ContractConfigConfirmationsEnv() bool { - return r.spec.ContractConfigConfirmationsEnv -} - // ContractConfigTrackerPollInterval resolves the spec's contract tracker poll // interval config. func (r *OCRSpecResolver) ContractConfigTrackerPollInterval() *string { @@ -368,12 +351,6 @@ func (r *OCRSpecResolver) ContractConfigTrackerPollInterval() *string { return &interval } -// ContractConfigTrackerPollIntervalEnv resolves the whether spec's tracker poll -// config comes from an env var. -func (r *OCRSpecResolver) ContractConfigTrackerPollIntervalEnv() bool { - return r.spec.ContractConfigTrackerPollIntervalEnv -} - // ContractConfigTrackerSubscribeInterval resolves the spec's tracker subscribe // interval config. func (r *OCRSpecResolver) ContractConfigTrackerSubscribeInterval() *string { @@ -386,12 +363,6 @@ func (r *OCRSpecResolver) ContractConfigTrackerSubscribeInterval() *string { return &interval } -// ContractConfigTrackerSubscribeIntervalEnv resolves whether spec's tracker -// subscribe interval config comes from an env var. -func (r *OCRSpecResolver) ContractConfigTrackerSubscribeIntervalEnv() bool { - return r.spec.ContractConfigTrackerSubscribeIntervalEnv -} - // CreatedAt resolves the spec's created at timestamp. func (r *OCRSpecResolver) CreatedAt() graphql.Time { return graphql.Time{Time: r.spec.CreatedAt} @@ -413,34 +384,16 @@ func (r *OCRSpecResolver) DatabaseTimeout() string { return r.spec.DatabaseTimeout.Duration().String() } -// DatabaseTimeoutEnv resolves the whether spec's database timeout -// config comes from an env var. -func (r *OCRSpecResolver) DatabaseTimeoutEnv() bool { - return r.spec.DatabaseTimeoutEnv -} - // ObservationGracePeriod resolves the spec's observation grace period. func (r *OCRSpecResolver) ObservationGracePeriod() string { return r.spec.ObservationGracePeriod.Duration().String() } -// ObservationGracePeriodEnv resolves the whether spec's observation grace period -// config comes from an env var. -func (r *OCRSpecResolver) ObservationGracePeriodEnv() bool { - return r.spec.ObservationGracePeriodEnv -} - // ContractTransmitterTransmitTimeout resolves the spec's contract transmitter transmit timeout. func (r *OCRSpecResolver) ContractTransmitterTransmitTimeout() string { return r.spec.ContractTransmitterTransmitTimeout.Duration().String() } -// ContractTransmitterTransmitTimeoutEnv resolves the whether spec's -// contract transmitter transmit timeout config comes from an env var. -func (r *OCRSpecResolver) ContractTransmitterTransmitTimeoutEnv() bool { - return r.spec.ContractTransmitterTransmitTimeoutEnv -} - // IsBootstrapPeer resolves whether spec is a bootstrap peer. func (r *OCRSpecResolver) IsBootstrapPeer() bool { return r.spec.IsBootstrapPeer @@ -468,12 +421,6 @@ func (r *OCRSpecResolver) ObservationTimeout() *string { return &timeout } -// ObservationTimeoutEnv resolves whether spec's observation timeout comes -// from an env var. -func (r *OCRSpecResolver) ObservationTimeoutEnv() bool { - return r.spec.ObservationTimeoutEnv -} - // P2PBootstrapPeers resolves the spec's p2p bootstrap peers func (r *OCRSpecResolver) P2PBootstrapPeers() *[]string { if len(r.spec.P2PBootstrapPeers) == 0 { @@ -631,11 +578,6 @@ func (r *VRFSpecResolver) MinIncomingConfirmations() int32 { return int32(r.spec.MinIncomingConfirmations) } -// MinIncomingConfirmations resolves the spec's min incoming confirmations. -func (r *VRFSpecResolver) MinIncomingConfirmationsEnv() bool { - return r.spec.ConfirmationsEnv -} - // CoordinatorAddress resolves the spec's coordinator address. func (r *VRFSpecResolver) CoordinatorAddress() string { return r.spec.CoordinatorAddress.String() diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 04bfffbe05..8e4095e171 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -10,6 +10,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -91,13 +92,12 @@ func TestResolver_DirectRequestSpec(t *testing.T) { f.Mocks.jobORM.On("FindJobWithoutSpecErrors", id).Return(job.Job{ Type: job.DirectRequest, DirectRequestSpec: &job.DirectRequestSpec{ - ContractAddress: contractAddress, - CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), - MinIncomingConfirmations: clnull.NewUint32(1, true), - MinIncomingConfirmationsEnv: true, - MinContractPayment: assets.NewLinkFromJuels(1000), - Requesters: models.AddressCollection{requesterAddress}, + ContractAddress: contractAddress, + CreatedAt: f.Timestamp(), + EVMChainID: utils.NewBigI(42), + MinIncomingConfirmations: clnull.NewUint32(1, true), + MinContractPayment: assets.NewLinkFromJuels(1000), + Requesters: models.AddressCollection{requesterAddress}, }, }, nil) }, @@ -112,7 +112,6 @@ func TestResolver_DirectRequestSpec(t *testing.T) { createdAt evmChainID minIncomingConfirmations - minIncomingConfirmationsEnv minContractPaymentLinkJuels requesters } @@ -130,7 +129,6 @@ func TestResolver_DirectRequestSpec(t *testing.T) { "createdAt": "2021-01-01T00:00:00Z", "evmChainID": "42", "minIncomingConfirmations": 1, - "minIncomingConfirmationsEnv": true, "minContractPaymentLinkJuels": "1000", "requesters": ["0x3cCad4715152693fE3BC4460591e3D3Fbd071b42"] } @@ -373,30 +371,22 @@ func TestResolver_OCRSpec(t *testing.T) { f.Mocks.jobORM.On("FindJobWithoutSpecErrors", id).Return(job.Job{ Type: job.OffchainReporting, OCROracleSpec: &job.OCROracleSpec{ - BlockchainTimeout: models.Interval(1 * time.Minute), - BlockchainTimeoutEnv: false, - ContractAddress: contractAddress, - ContractConfigConfirmations: 1, - ContractConfigConfirmationsEnv: true, - ContractConfigTrackerPollInterval: models.Interval(1 * time.Minute), - ContractConfigTrackerPollIntervalEnv: false, - ContractConfigTrackerSubscribeInterval: models.Interval(2 * time.Minute), - ContractConfigTrackerSubscribeIntervalEnv: true, - DatabaseTimeout: models.NewInterval(3 * time.Second), - DatabaseTimeoutEnv: true, - ObservationGracePeriod: models.NewInterval(4 * time.Second), - ObservationGracePeriodEnv: true, - ContractTransmitterTransmitTimeout: models.NewInterval(555 * time.Millisecond), - ContractTransmitterTransmitTimeoutEnv: true, - CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), - IsBootstrapPeer: false, - EncryptedOCRKeyBundleID: &keyBundleID, - ObservationTimeout: models.Interval(2 * time.Minute), - ObservationTimeoutEnv: false, - P2PBootstrapPeers: pq.StringArray{"/dns4/test.com/tcp/2001/p2pkey"}, - P2PV2Bootstrappers: pq.StringArray{"12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw@localhost:5001"}, - TransmitterAddress: &transmitterAddress, + BlockchainTimeout: models.Interval(1 * time.Minute), + ContractAddress: contractAddress, + ContractConfigConfirmations: 1, + ContractConfigTrackerPollInterval: models.Interval(1 * time.Minute), + ContractConfigTrackerSubscribeInterval: models.Interval(2 * time.Minute), + DatabaseTimeout: models.NewInterval(3 * time.Second), + ObservationGracePeriod: models.NewInterval(4 * time.Second), + ContractTransmitterTransmitTimeout: models.NewInterval(555 * time.Millisecond), + CreatedAt: f.Timestamp(), + EVMChainID: utils.NewBigI(42), + IsBootstrapPeer: false, + EncryptedOCRKeyBundleID: &keyBundleID, + ObservationTimeout: models.Interval(2 * time.Minute), + P2PBootstrapPeers: pq.StringArray{"/dns4/test.com/tcp/2001/p2pkey"}, + P2PV2Bootstrappers: pq.StringArray{"12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw@localhost:5001"}, + TransmitterAddress: &transmitterAddress, }, }, nil) }, @@ -408,26 +398,18 @@ func TestResolver_OCRSpec(t *testing.T) { __typename ... on OCRSpec { blockchainTimeout - blockchainTimeoutEnv contractAddress contractConfigConfirmations - contractConfigConfirmationsEnv contractConfigTrackerPollInterval - contractConfigTrackerPollIntervalEnv contractConfigTrackerSubscribeInterval - contractConfigTrackerSubscribeIntervalEnv databaseTimeout - databaseTimeoutEnv observationGracePeriod - observationGracePeriodEnv contractTransmitterTransmitTimeout - contractTransmitterTransmitTimeoutEnv createdAt evmChainID isBootstrapPeer keyBundleID observationTimeout - observationTimeoutEnv p2pBootstrapPeers p2pv2Bootstrappers transmitterAddress @@ -443,26 +425,18 @@ func TestResolver_OCRSpec(t *testing.T) { "spec": { "__typename": "OCRSpec", "blockchainTimeout": "1m0s", - "blockchainTimeoutEnv": false, "contractAddress": "0x613a38AC1659769640aaE063C651F48E0250454C", "contractConfigConfirmations": 1, - "contractConfigConfirmationsEnv": true, "contractConfigTrackerPollInterval": "1m0s", - "contractConfigTrackerPollIntervalEnv": false, "contractConfigTrackerSubscribeInterval": "2m0s", - "contractConfigTrackerSubscribeIntervalEnv": true, "databaseTimeout": "3s", - "databaseTimeoutEnv": true, "observationGracePeriod": "4s", - "observationGracePeriodEnv": true, "contractTransmitterTransmitTimeout": "555ms", - "contractTransmitterTransmitTimeoutEnv": true, "createdAt": "2021-01-01T00:00:00Z", "evmChainID": "42", "isBootstrapPeer": false, "keyBundleID": "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5", "observationTimeout": "2m0s", - "observationTimeoutEnv": false, "p2pBootstrapPeers": ["/dns4/test.com/tcp/2001/p2pkey"], "p2pv2Bootstrappers": ["12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw@localhost:5001"], "transmitterAddress": "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" diff --git a/core/web/schema/type/spec.graphql b/core/web/schema/type/spec.graphql index cdcbabf9ef..98203a1870 100644 --- a/core/web/schema/type/spec.graphql +++ b/core/web/schema/type/spec.graphql @@ -22,7 +22,6 @@ type DirectRequestSpec { createdAt: Time! evmChainID: String minIncomingConfirmations: Int! - minIncomingConfirmationsEnv: Boolean! minContractPaymentLinkJuels: String! requesters: [String!] } @@ -52,29 +51,21 @@ type KeeperSpec { type OCRSpec { blockchainTimeout: String - blockchainTimeoutEnv: Boolean! contractAddress: String! contractConfigConfirmations: Int - contractConfigConfirmationsEnv: Boolean! contractConfigTrackerPollInterval: String - contractConfigTrackerPollIntervalEnv: Boolean! contractConfigTrackerSubscribeInterval: String - contractConfigTrackerSubscribeIntervalEnv: Boolean! createdAt: Time! evmChainID: String isBootstrapPeer: Boolean! keyBundleID: String observationTimeout: String - observationTimeoutEnv: Boolean! p2pBootstrapPeers: [String!] p2pv2Bootstrappers: [String!] transmitterAddress: String databaseTimeout: String! - databaseTimeoutEnv: Boolean! observationGracePeriod: String! - observationGracePeriodEnv: Boolean! contractTransmitterTransmitTimeout: String! - contractTransmitterTransmitTimeoutEnv: Boolean! } type OCR2Spec { @@ -100,7 +91,6 @@ type VRFSpec { evmChainID: String fromAddresses: [String!] minIncomingConfirmations: Int! - minIncomingConfirmationsEnv: Boolean! pollPeriod: String! publicKey: String! requestedConfsDelay: Int! From 8c96682617ad90b57b759a95f1555c51b842ee00 Mon Sep 17 00:00:00 2001 From: Jim W Date: Tue, 31 Oct 2023 16:53:02 -0400 Subject: [PATCH 044/327] remove dependency of postgres trigger for broadcaster (#11109) * remove dependency of postgres trigger for broadcaster * remove extra argument in NewBroadcaster call * fixes for extra args * fix some failing tests and remove some error wraps * remove pkgerrors from txm * remove parseAddr which is now dead code * fix error handling * remove trigger from postgres via migration; use error wrapping in txmgr * fix naming of new migration --- common/txmgr/broadcaster.go | 40 ------------- common/txmgr/txmgr.go | 50 ++++++++++------ core/chains/evm/evm_txm.go | 1 - core/chains/evm/txmgr/broadcaster_test.go | 60 ++----------------- core/chains/evm/txmgr/builder.go | 7 +-- core/chains/evm/txmgr/common.go | 7 --- core/chains/evm/txmgr/txmgr_test.go | 28 +++------ core/services/pg/channels.go | 1 - .../0206_remove_tx_insert_trigger.sql | 18 ++++++ 9 files changed, 67 insertions(+), 145 deletions(-) create mode 100644 core/store/migrate/migrations/0206_remove_tx_insert_trigger.sql diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 011866bf39..4f6ffae2ad 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -123,8 +122,6 @@ type Broadcaster[ // when Start is called autoSyncSequence bool - txInsertListener pg.Subscription - eventBroadcaster pg.EventBroadcaster processUnstartedTxsImpl ProcessUnstartedTxs[ADDR] ks txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ] @@ -143,8 +140,6 @@ type Broadcaster[ initSync sync.Mutex isStarted bool - parseAddr func(string) (ADDR, error) - sequenceLock sync.RWMutex nextSequenceMap map[ADDR]SEQ generateNextSequence types.GenerateNextSequenceFunc[SEQ] @@ -166,13 +161,11 @@ func NewBroadcaster[ txConfig txmgrtypes.BroadcasterTransactionsConfig, listenerConfig txmgrtypes.BroadcasterListenerConfig, keystore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ], - eventBroadcaster pg.EventBroadcaster, txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], logger logger.Logger, checkerFactory TransmitCheckerFactory[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], autoSyncSequence bool, - parseAddress func(string) (ADDR, error), generateNextSequence types.GenerateNextSequenceFunc[SEQ], ) *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { logger = logger.Named("Broadcaster") @@ -187,11 +180,9 @@ func NewBroadcaster[ feeConfig: feeConfig, txConfig: txConfig, listenerConfig: listenerConfig, - eventBroadcaster: eventBroadcaster, ks: keystore, checkerFactory: checkerFactory, autoSyncSequence: autoSyncSequence, - parseAddr: parseAddress, } b.processUnstartedTxsImpl = b.processUnstartedTxs @@ -215,10 +206,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star return errors.New("Broadcaster is already started") } var err error - eb.txInsertListener, err = eb.eventBroadcaster.Subscribe(pg.ChannelInsertOnTx, "") - if err != nil { - return errors.Wrap(err, "Broadcaster could not start") - } eb.enabledAddresses, err = eb.ks.EnabledAddressesForChain(eb.chainID) if err != nil { return errors.Wrap(err, "Broadcaster: failed to load EnabledAddressesForChain") @@ -239,9 +226,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star go eb.monitorTxs(addr, triggerCh) } - eb.wg.Add(1) - go eb.txInsertTriggerer() - eb.sequenceLock.Lock() defer eb.sequenceLock.Unlock() eb.nextSequenceMap, err = eb.loadNextSequenceMap(eb.enabledAddresses) @@ -266,9 +250,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) clos if !eb.isStarted { return errors.Wrap(utils.ErrAlreadyStopped, "Broadcaster is not started") } - if eb.txInsertListener != nil { - eb.txInsertListener.Close() - } close(eb.chStop) eb.wg.Wait() eb.isStarted = false @@ -305,27 +286,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trig } } -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) txInsertTriggerer() { - defer eb.wg.Done() - for { - select { - case ev, ok := <-eb.txInsertListener.Events(): - if !ok { - eb.logger.Debug("txInsertListener channel closed, exiting trigger loop") - return - } - addr, err := eb.parseAddr(ev.Payload) - if err != nil { - eb.logger.Errorw("failed to parse address in trigger", "err", err) - continue - } - eb.Trigger(addr) - case <-eb.chStop: - return - } - } -} - // Load the next sequence map using the tx table or on-chain (if not found in tx table) func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(addresses []ADDR) (map[ADDR]SEQ, error) { ctx, cancel := eb.chStop.NewCtx() diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 0c7117afab..d80f534ad2 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -10,7 +10,6 @@ import ( "time" "github.com/google/uuid" - pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-relay/pkg/services" @@ -166,14 +165,14 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx return b.StartOnce("Txm", func() error { var ms services.MultiStart if err := ms.Start(ctx, b.broadcaster); err != nil { - return pkgerrors.Wrap(err, "Txm: Broadcaster failed to start") + return fmt.Errorf("Txm: Broadcaster failed to start: %w", err) } if err := ms.Start(ctx, b.confirmer); err != nil { - return pkgerrors.Wrap(err, "Txm: Confirmer failed to start") + return fmt.Errorf("Txm: Confirmer failed to start: %w", err) } if err := ms.Start(ctx, b.txAttemptBuilder); err != nil { - return pkgerrors.Wrap(err, "Txm: Estimator failed to start") + return fmt.Errorf("Txm: Estimator failed to start: %w", err) } b.wg.Add(1) @@ -190,7 +189,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx if b.fwdMgr != nil { if err := ms.Start(ctx, b.fwdMgr); err != nil { - return pkgerrors.Wrap(err, "Txm: ForwarderManager failed to start") + return fmt.Errorf("Txm: ForwarderManager failed to start: %w", err) } } @@ -223,8 +222,10 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(addr func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) abandon(addr ADDR) (err error) { ctx, cancel := utils.StopChan(b.chStop).NewCtx() defer cancel() - err = b.txStore.Abandon(ctx, b.chainID, addr) - return pkgerrors.Wrapf(err, "abandon failed to update txes for key %s", addr.String()) + if err = b.txStore.Abandon(ctx, b.chainID, addr); err != nil { + return fmt.Errorf("abandon failed to update txes for key %s: %w", addr.String(), err) + } + return nil } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() (merr error) { @@ -241,14 +242,14 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() (m } if b.fwdMgr != nil { if err := b.fwdMgr.Close(); err != nil { - merr = errors.Join(merr, pkgerrors.Wrap(err, "Txm: failed to stop ForwarderManager")) + merr = errors.Join(merr, fmt.Errorf("Txm: failed to stop ForwarderManager: %w", err)) } } b.wg.Wait() if err := b.txAttemptBuilder.Close(); err != nil { - merr = errors.Join(merr, pkgerrors.Wrap(err, "Txm: failed to close TxAttemptBuilder")) + merr = errors.Join(merr, fmt.Errorf("Txm: failed to close TxAttemptBuilder: %w", err)) } return nil @@ -444,7 +445,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTran var existingTx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] existingTx, err = b.txStore.FindTxWithIdempotencyKey(ctx, *txRequest.IdempotencyKey, b.chainID) if err != nil && !errors.Is(err, sql.ErrNoRows) { - return tx, pkgerrors.Wrap(err, "Failed to search for transaction with IdempotencyKey") + return tx, fmt.Errorf("Failed to search for transaction with IdempotencyKey: %w", err) } if existingTx != nil { b.logger.Infow("Found a Tx with IdempotencyKey. Returning existing Tx without creating a new one.", "IdempotencyKey", *txRequest.IdempotencyKey) @@ -470,31 +471,40 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTran txRequest.ToAddress = txRequest.ForwarderAddress txRequest.EncodedPayload = fwdPayload } else { - b.logger.Errorf("Failed to use forwarder set upstream: %s", fwdErr.Error()) + b.logger.Errorf("Failed to use forwarder set upstream: %w", fwdErr.Error()) } } err = b.txStore.CheckTxQueueCapacity(ctx, txRequest.FromAddress, b.txConfig.MaxQueued(), b.chainID) if err != nil { - return tx, pkgerrors.Wrap(err, "Txm#CreateTransaction") + return tx, fmt.Errorf("Txm#CreateTransaction: %w", err) } tx, err = b.txStore.CreateTransaction(ctx, txRequest, b.chainID) - return + if err != nil { + return tx, err + } + + // Trigger the Broadcaster to check for new transaction + b.broadcaster.Trigger(txRequest.FromAddress) + + return tx, nil } // Calls forwarderMgr to get a proper forwarder for a given EOA. func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetForwarderForEOA(eoa ADDR) (forwarder ADDR, err error) { if !b.txConfig.ForwardersEnabled() { - return forwarder, pkgerrors.Errorf("Forwarding is not enabled, to enable set Transactions.ForwardersEnabled =true") + return forwarder, fmt.Errorf("forwarding is not enabled, to enable set Transactions.ForwardersEnabled =true") } forwarder, err = b.fwdMgr.ForwarderFor(eoa) return } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) checkEnabled(addr ADDR) error { - err := b.keyStore.CheckEnabled(addr, b.chainID) - return pkgerrors.Wrapf(err, "cannot send transaction from %s on chain ID %s", addr, b.chainID.String()) + if err := b.keyStore.CheckEnabled(addr, b.chainID); err != nil { + return fmt.Errorf("cannot send transaction from %s on chain ID %s: %w", addr, b.chainID.String(), err) + } + return nil } // SendNativeToken creates a transaction that transfers the given value of native tokens @@ -511,7 +521,13 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNative Strategy: NewSendEveryStrategy(), } etx, err = b.txStore.CreateTransaction(ctx, txRequest, chainID) - return etx, pkgerrors.Wrap(err, "SendNativeToken failed to insert tx") + if err != nil { + return etx, fmt.Errorf("SendNativeToken failed to insert tx: %w", err) + } + + // Trigger the Broadcaster to check for new transaction + b.broadcaster.Trigger(from) + return etx, nil } type NullTxManager[ diff --git a/core/chains/evm/evm_txm.go b/core/chains/evm/evm_txm.go index d2f4178c7d..a8673e954a 100644 --- a/core/chains/evm/evm_txm.go +++ b/core/chains/evm/evm_txm.go @@ -61,7 +61,6 @@ func newEvmTxm( lggr, logPoller, opts.KeyStore, - opts.EventBroadcaster, estimator) } else { txm = opts.GenTxManager(chainID) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 3901da59ee..61a230c21b 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" - "github.com/onsi/gomega" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -44,9 +43,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" - pgmocks "github.com/smartcontractkit/chainlink/v2/core/services/pg/mocks" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -61,17 +58,14 @@ func NewTestEthBroadcaster( nonceAutoSync bool, ) *txmgr.Broadcaster { t.Helper() - eb := cltest.NewEventBroadcaster(t, config.Database().URL()) ctx := testutils.Context(t) - require.NoError(t, eb.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, eb.Close()) }) lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) - ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, eb, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) + ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) // Mark instance as test ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing() @@ -82,10 +76,6 @@ func NewTestEthBroadcaster( func TestEthBroadcaster_Lifecycle(t *testing.T) { cfg, db := heavyweight.FullTestDBV2(t, "eth_broadcaster_optimistic_locking", nil) - eventBroadcaster := cltest.NewEventBroadcaster(t, cfg.Database().URL()) - err := eventBroadcaster.Start(testutils.Context(t)) - require.NoError(t, err) - t.Cleanup(func() { assert.NoError(t, eventBroadcaster.Close()) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -102,7 +92,6 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, - eventBroadcaster, txBuilder, nil, logger.TestLogger(t), @@ -111,7 +100,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { ) // Can't close an unstarted instance - err = eb.Close() + err := eb.Close() require.Error(t, err) ctx := testutils.Context(t) @@ -577,9 +566,6 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testing.T) { // non-transactional DB needed because we deliberately test for FK violation cfg, db := heavyweight.FullTestDBV2(t, "eth_broadcaster_optimistic_locking", nil) - eventBroadcaster := cltest.NewEventBroadcaster(t, cfg.Database().URL()) - require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, eventBroadcaster.Close()) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ccfg := evmtest.NewChainScopedConfig(t, cfg) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) @@ -605,7 +591,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ccfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, - eventBroadcaster, txBuilder, nil, logger.TestLogger(t), @@ -1113,17 +1098,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // same as the parent test, but callback is set by ctor t.Run("callback set by ctor", func(t *testing.T) { - eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - err := eventBroadcaster.Start(testutils.Context(t)) - require.NoError(t, err) - t.Cleanup(func() { assert.NoError(t, eventBroadcaster.Close()) }) lggr := logger.TestLogger(t) estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) localNextNonce = getLocalNextNonce(t, eb, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() - eb2 := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, eventBroadcaster, txBuilder, nil, lggr, &testCheckerFactory{}, false) - require.NoError(t, err) + eb2 := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, nil, lggr, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1724,29 +1704,6 @@ func TestEthBroadcaster_Trigger(t *testing.T) { eb.Trigger(testutils.NewAddress()) } -func TestEthBroadcaster_EthTxInsertEventCausesTriggerToFire(t *testing.T) { - // NOTE: Testing triggers requires committing transactions and does not work with transactional tests - cfg, db := heavyweight.FullTestDBV2(t, "eth_tx_triggers", nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - eventBroadcaster := cltest.NewEventBroadcaster(t, evmcfg.Database().URL()) - require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) - t.Cleanup(func() { require.NoError(t, eventBroadcaster.Close()) }) - - ethTxInsertListener, err := eventBroadcaster.Subscribe(pg.ChannelInsertOnTx, "") - require.NoError(t, err) - - // Give it some time to start listening - time.Sleep(100 * time.Millisecond) - - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) - gomega.NewWithT(t).Eventually(ethTxInsertListener.Events()).Should(gomega.Receive()) -} - func TestEthBroadcaster_SyncNonce(t *testing.T) { db := pgtest.NewSqlxDB(t) ctx := testutils.Context(t) @@ -1765,11 +1722,6 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethNodeNonce := uint64(22) - eventBroadcaster := pgmocks.NewEventBroadcaster(t) - sub := pgmocks.NewSubscription(t) - sub.On("Events").Return(make(<-chan pg.Event)) - sub.On("Close") - eventBroadcaster.On("Subscribe", "evm.insert_on_txes", "").Return(sub, nil) estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) checkerFactory := &testCheckerFactory{} @@ -1783,7 +1735,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, nil, lggr, checkerFactory, false) + eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, nil, lggr, checkerFactory, false) err := eb.Start(testutils.Context(t)) assert.NoError(t, err) @@ -1801,7 +1753,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) + eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(ethNodeNonce), nil).Once() require.NoError(t, eb.Start(ctx)) @@ -1832,7 +1784,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) + eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) eb.XXXTestDisableUnstartedTxAutoProcessing() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("something exploded")).Once() diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 39781e83f4..9123d1dfc0 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -16,7 +16,6 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // NewTxm constructs the necessary dependencies for the EvmTxm (broadcaster, confirmer, etc) and returns a new EvmTxManager @@ -31,7 +30,6 @@ func NewTxm( lggr logger.Logger, logPoller logpoller.LogPoller, keyStore keystore.Eth, - eventBroadcaster pg.EventBroadcaster, estimator gas.EvmFeeEstimator, ) (txm TxManager, err error, @@ -52,7 +50,7 @@ func NewTxm( txmCfg := NewEvmTxmConfig(chainConfig) // wrap Evm specific config feeCfg := NewEvmTxmFeeConfig(fCfg) // wrap Evm specific config txmClient := NewEvmTxmClient(client) // wrap Evm specific client - ethBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, eventBroadcaster, txAttemptBuilder, txNonceSyncer, lggr, checker, chainConfig.NonceAutoSync()) + ethBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, txNonceSyncer, lggr, checker, chainConfig.NonceAutoSync()) ethConfirmer := NewEvmConfirmer(txStore, txmClient, txmCfg, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr) var ethResender *Resender if txConfig.ResendAfterThreshold() > 0 { @@ -123,12 +121,11 @@ func NewEvmBroadcaster( txConfig txmgrtypes.BroadcasterTransactionsConfig, listenerConfig txmgrtypes.BroadcasterListenerConfig, keystore KeyStore, - eventBroadcaster pg.EventBroadcaster, txAttemptBuilder TxAttemptBuilder, nonceSyncer NonceSyncer, logger logger.Logger, checkerFactory TransmitCheckerFactory, autoSyncNonce bool, ) *Broadcaster { - return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, eventBroadcaster, txAttemptBuilder, nonceSyncer, logger, checkerFactory, autoSyncNonce, stringToGethAddress, evmtypes.GenerateNextNonce) + return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, txAttemptBuilder, nonceSyncer, logger, checkerFactory, autoSyncNonce, evmtypes.GenerateNextNonce) } diff --git a/core/chains/evm/txmgr/common.go b/core/chains/evm/txmgr/common.go index 5dbb2ef961..37cc89dd7a 100644 --- a/core/chains/evm/txmgr/common.go +++ b/core/chains/evm/txmgr/common.go @@ -69,10 +69,3 @@ func batchSendTransactions( } return reqs, now, successfulBroadcast, nil } - -func stringToGethAddress(s string) (common.Address, error) { - if !common.IsHexAddress(s) { - return common.Address{}, fmt.Errorf("invalid hex address: %s", s) - } - return common.HexToAddress(s), nil -} diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 6cb43b2771..e9823ee021 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -37,12 +37,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - pgmocks "github.com/smartcontractkit/chainlink/v2/core/services/pg/mocks" "github.com/smartcontractkit/chainlink/v2/core/utils" ) func makeTestEvmTxm( - t *testing.T, db *sqlx.DB, ethClient evmclient.Client, estimator gas.EvmFeeEstimator, ccfg txmgr.ChainConfig, fcfg txmgr.FeeConfig, txConfig evmconfig.Transactions, dbConfig txmgr.DatabaseConfig, listenerConfig txmgr.ListenerConfig, keyStore keystore.Eth, eventBroadcaster pg.EventBroadcaster) (txmgr.TxManager, error) { + t *testing.T, db *sqlx.DB, ethClient evmclient.Client, estimator gas.EvmFeeEstimator, ccfg txmgr.ChainConfig, fcfg txmgr.FeeConfig, txConfig evmconfig.Transactions, dbConfig txmgr.DatabaseConfig, listenerConfig txmgr.ListenerConfig, keyStore keystore.Eth) (txmgr.TxManager, error) { lggr := logger.TestLogger(t) lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), ethClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) @@ -66,7 +65,6 @@ func makeTestEvmTxm( lggr, lp, keyStore, - eventBroadcaster, estimator) } @@ -83,7 +81,7 @@ func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) { keyStore := cltest.NewKeyStore(t, db, dbConfig).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keyStore, nil) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keyStore) require.NoError(t, err) _, err = txm.SendNativeToken(testutils.Context(t), big.NewInt(0), from, to, *value, 21000) @@ -109,7 +107,7 @@ func TestTxm_CreateTransaction(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth(), nil) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth()) require.NoError(t, err) t.Run("with queue under capacity inserts eth_tx", func(t *testing.T) { @@ -523,7 +521,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), etKeyStore, nil) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), etKeyStore) require.NoError(t, err) t.Run("if another key has any transactions with insufficient eth errors, transmits as normal", func(t *testing.T) { @@ -567,7 +565,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { Meta: nil, Strategy: strategy, }) - assert.NoError(t, err) + require.NoError(t, err) require.Equal(t, payload, etx.EncodedPayload) }) @@ -589,7 +587,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { Meta: nil, Strategy: strategy, }) - assert.NoError(t, err) + require.NoError(t, err) require.Equal(t, payload, etx.EncodedPayload) }) } @@ -599,7 +597,6 @@ func TestTxm_Lifecycle(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) kst := ksmocks.NewEth(t) - eventBroadcaster := pgmocks.NewEventBroadcaster(t) config, dbConfig, evmConfig := makeConfigs(t) config.finalityDepth = uint32(42) @@ -615,16 +612,13 @@ func TestTxm_Lifecycle(t *testing.T) { unsub := cltest.NewAwaiter() kst.On("SubscribeToKeyChanges").Return(keyChangeCh, unsub.ItHappened) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst, eventBroadcaster) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst) require.NoError(t, err) head := cltest.Head(42) // It should not hang or panic txm.OnNewLongestChain(testutils.Context(t), head) - sub := pgmocks.NewSubscription(t) - sub.On("Events").Return(make(<-chan pg.Event)) - eventBroadcaster.On("Subscribe", "evm.insert_on_txes", "").Return(sub, nil) evmConfig.bumpThreshold = uint64(1) require.NoError(t, txm.Start(testutils.Context(t))) @@ -638,7 +632,6 @@ func TestTxm_Lifecycle(t *testing.T) { addr := []gethcommon.Address{keyState.Address.Address()} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addr, nil) - sub.On("Close").Return() ethClient.On("PendingNonceAt", mock.AnythingOfType("*context.cancelCtx"), gethcommon.Address{}).Return(uint64(0), nil).Maybe() keyChangeCh <- struct{}{} @@ -670,14 +663,9 @@ func TestTxm_Reset(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil) ethClient.On("BatchCallContextAll", mock.Anything, mock.Anything).Return(nil).Maybe() - eventBroadcaster := pgmocks.NewEventBroadcaster(t) - sub := pgmocks.NewSubscription(t) - sub.On("Events").Return(make(<-chan pg.Event)) - sub.On("Close") - eventBroadcaster.On("Subscribe", "evm.insert_on_txes", "").Return(sub, nil) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), cfg.Database(), cfg.Database().Listener(), kst.Eth(), eventBroadcaster) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), cfg.Database(), cfg.Database().Listener(), kst.Eth()) require.NoError(t, err) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, addr2) diff --git a/core/services/pg/channels.go b/core/services/pg/channels.go index 736cd40796..1d67dabe52 100644 --- a/core/services/pg/channels.go +++ b/core/services/pg/channels.go @@ -2,7 +2,6 @@ package pg // Postgres channel to listen for new evm.txes const ( - ChannelInsertOnTx = "evm.insert_on_txes" ChannelInsertOnCosmosMsg = "insert_on_cosmos_msg" ChannelInsertOnEVMLogs = "evm.insert_on_logs" ) diff --git a/core/store/migrate/migrations/0206_remove_tx_insert_trigger.sql b/core/store/migrate/migrations/0206_remove_tx_insert_trigger.sql new file mode 100644 index 0000000000..94b2e4aa8a --- /dev/null +++ b/core/store/migrate/migrations/0206_remove_tx_insert_trigger.sql @@ -0,0 +1,18 @@ +-- +goose Up +DROP TRIGGER IF EXISTS notify_tx_insertion on evm.txes; +DROP FUNCTION IF EXISTS evm.notifyethtxinsertion(); + + +-- +goose Down +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION evm.notifytxinsertion() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('evm.insert_on_txes'::text, encode(NEW.from_address, 'hex')); + RETURN NULL; + END + $$; + +CREATE TRIGGER notify_tx_insertion AFTER INSERT ON evm.txes FOR EACH ROW EXECUTE PROCEDURE evm.notifytxinsertion(); +-- +goose StatementEnd \ No newline at end of file From 24de8afe09954c45c16d2143186e042bcb300788 Mon Sep 17 00:00:00 2001 From: Morgan Kuphal <87319522+KuphJr@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:55:58 -0500 Subject: [PATCH 045/327] Get request logs from past n blocks (#11052) * Get request logs from past n blocks * Separate confirmations setting for reqs & resps * Filter already detected reqs & resps * validate pastBlocksToPoll * Fixed bugs which appeared during tests * Addressed feedback * Added test * Added comment to config * Fixed log & removed const * Used const values for defaults * Address feedback * Fixed types for logPoller * Added tests for FilterPreviouslyDetectedEvents * Added additional test assertions * Fixed lint errors --- core/scripts/functions/templates/oracle.toml | 1 + .../ocr2/plugins/functions/config/config.go | 4 + .../relay/evm/functions/logpoller_wrapper.go | 174 +++++++++++++----- .../evm/functions/logpoller_wrapper_test.go | 127 ++++++++++++- 4 files changed, 250 insertions(+), 56 deletions(-) diff --git a/core/scripts/functions/templates/oracle.toml b/core/scripts/functions/templates/oracle.toml index 4739252d68..d21fe4a5e8 100644 --- a/core/scripts/functions/templates/oracle.toml +++ b/core/scripts/functions/templates/oracle.toml @@ -36,6 +36,7 @@ requestTimeoutSec = 300 maxRequestSizesList = [30_720, 51_200, 102_400, 204_800, 512_000, 1_048_576, 2_097_152, 3_145_728, 5_242_880, 10_485_760] maxSecretsSizesList = [10_240, 20_480, 51_200, 102_400, 307_200, 512_000, 1_048_576, 2_097_152] minimumSubscriptionBalance = "2 link" +pastBlocksToPoll = 25 [pluginConfig.OnchainAllowlist] diff --git a/core/services/ocr2/plugins/functions/config/config.go b/core/services/ocr2/plugins/functions/config/config.go index 3f35d1dba9..0978500deb 100644 --- a/core/services/ocr2/plugins/functions/config/config.go +++ b/core/services/ocr2/plugins/functions/config/config.go @@ -23,7 +23,11 @@ type PluginConfig struct { EnableRequestSignatureCheck bool `json:"enableRequestSignatureCheck"` DONID string `json:"donID"` ContractVersion uint32 `json:"contractVersion"` + MinRequestConfirmations uint32 `json:"minRequestConfirmations"` + MinResponseConfirmations uint32 `json:"minResponseConfirmations"` MinIncomingConfirmations uint32 `json:"minIncomingConfirmations"` + PastBlocksToPoll uint32 `json:"pastBlocksToPoll"` + LogPollerCacheDurationSec uint32 `json:"logPollerCacheDurationSec"` // Duration to cache previously detected request or response logs such that they can be filtered when calling logpoller_wrapper.LatestEvents() RequestTimeoutSec uint32 `json:"requestTimeoutSec"` RequestTimeoutCheckFrequencySec uint32 `json:"requestTimeoutCheckFrequencySec"` RequestTimeoutBatchLookupSize uint32 `json:"requestTimeoutBatchLookupSize"` diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go index d355bd6569..6193f4ba86 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper.go +++ b/core/services/relay/evm/functions/logpoller_wrapper.go @@ -24,21 +24,39 @@ import ( type logPollerWrapper struct { services.StateMachine - routerContract *functions_router.FunctionsRouter - pluginConfig config.PluginConfig - client client.Client - logPoller logpoller.LogPoller - subscribers map[string]evmRelayTypes.RouteUpdateSubscriber - activeCoordinator common.Address - proposedCoordinator common.Address - blockOffset int64 - nextBlock int64 - mu sync.Mutex - closeWait sync.WaitGroup - stopCh utils.StopChan - lggr logger.Logger + routerContract *functions_router.FunctionsRouter + pluginConfig config.PluginConfig + client client.Client + logPoller logpoller.LogPoller + subscribers map[string]evmRelayTypes.RouteUpdateSubscriber + activeCoordinator common.Address + proposedCoordinator common.Address + requestBlockOffset int64 + responseBlockOffset int64 + pastBlocksToPoll int64 + logPollerCacheDurationSec int64 + detectedRequests detectedEvents + detectedResponses detectedEvents + mu sync.Mutex + closeWait sync.WaitGroup + stopCh utils.StopChan + lggr logger.Logger } +type detectedEvent struct { + requestId [32]byte + timeDetected time.Time +} + +type detectedEvents struct { + isPreviouslyDetected map[[32]byte]struct{} + detectedEventsOrdered []detectedEvent +} + +const logPollerCacheDurationSecDefault = 300 +const pastBlocksToPollDefault = 50 +const maxLogsToProcess = 1000 + var _ evmRelayTypes.LogPollerWrapper = &logPollerWrapper{} func NewLogPollerWrapper(routerContractAddress common.Address, pluginConfig config.PluginConfig, client client.Client, logPoller logpoller.LogPoller, lggr logger.Logger) (evmRelayTypes.LogPollerWrapper, error) { @@ -48,18 +66,48 @@ func NewLogPollerWrapper(routerContractAddress common.Address, pluginConfig conf } blockOffset := int64(pluginConfig.MinIncomingConfirmations) - 1 if blockOffset < 0 { + lggr.Warnw("invalid minIncomingConfirmations, using 1 instead", "minIncomingConfirmations", pluginConfig.MinIncomingConfirmations) blockOffset = 0 } + requestBlockOffset := int64(pluginConfig.MinRequestConfirmations) - 1 + if requestBlockOffset < 0 { + lggr.Warnw("invalid minRequestConfirmations, using minIncomingConfirmations instead", "minRequestConfirmations", pluginConfig.MinRequestConfirmations) + requestBlockOffset = blockOffset + } + responseBlockOffset := int64(pluginConfig.MinResponseConfirmations) - 1 + if responseBlockOffset < 0 { + lggr.Warnw("invalid minResponseConfirmations, using minIncomingConfirmations instead", "minResponseConfirmations", pluginConfig.MinResponseConfirmations) + responseBlockOffset = blockOffset + } + logPollerCacheDurationSec := int64(pluginConfig.LogPollerCacheDurationSec) + if logPollerCacheDurationSec <= 0 { + lggr.Warnw("invalid logPollerCacheDuration, using 300 instead", "logPollerCacheDurationSec", logPollerCacheDurationSec) + logPollerCacheDurationSec = logPollerCacheDurationSecDefault + } + pastBlocksToPoll := int64(pluginConfig.PastBlocksToPoll) + if pastBlocksToPoll <= 0 { + lggr.Warnw("invalid pastBlocksToPoll, using 50 instead", "pastBlocksToPoll", pastBlocksToPoll) + pastBlocksToPoll = pastBlocksToPollDefault + } + if blockOffset >= pastBlocksToPoll || requestBlockOffset >= pastBlocksToPoll || responseBlockOffset >= pastBlocksToPoll { + lggr.Errorw("invalid config: number of required confirmation blocks >= pastBlocksToPoll", "pastBlocksToPoll", pastBlocksToPoll, "minIncomingConfirmations", pluginConfig.MinIncomingConfirmations, "minRequestConfirmations", pluginConfig.MinRequestConfirmations, "minResponseConfirmations", pluginConfig.MinResponseConfirmations) + return nil, errors.Errorf("invalid config: number of required confirmation blocks >= pastBlocksToPoll") + } return &logPollerWrapper{ - routerContract: routerContract, - pluginConfig: pluginConfig, - blockOffset: blockOffset, - logPoller: logPoller, - client: client, - subscribers: make(map[string]evmRelayTypes.RouteUpdateSubscriber), - stopCh: make(utils.StopChan), - lggr: lggr, + routerContract: routerContract, + pluginConfig: pluginConfig, + requestBlockOffset: requestBlockOffset, + responseBlockOffset: responseBlockOffset, + pastBlocksToPoll: pastBlocksToPoll, + logPollerCacheDurationSec: logPollerCacheDurationSec, + detectedRequests: detectedEvents{isPreviouslyDetected: make(map[[32]byte]struct{})}, + detectedResponses: detectedEvents{isPreviouslyDetected: make(map[[32]byte]struct{})}, + logPoller: logPoller, + client: client, + subscribers: make(map[string]evmRelayTypes.RouteUpdateSubscriber), + stopCh: make(utils.StopChan), + lggr: lggr, }, nil } @@ -68,20 +116,11 @@ func (l *logPollerWrapper) Start(context.Context) error { l.lggr.Infow("starting LogPollerWrapper", "routerContract", l.routerContract.Address().Hex(), "contractVersion", l.pluginConfig.ContractVersion) l.mu.Lock() defer l.mu.Unlock() - if l.pluginConfig.ContractVersion == 0 { - l.activeCoordinator = l.routerContract.Address() - l.proposedCoordinator = l.routerContract.Address() - } else if l.pluginConfig.ContractVersion == 1 { - nextBlock, err := l.logPoller.LatestBlock() - if err != nil { - l.lggr.Errorw("LogPollerWrapper: LatestBlock() failed, starting from 0", "error", err) - } else { - l.lggr.Debugw("LogPollerWrapper: LatestBlock() got starting block", "block", nextBlock) - l.nextBlock = nextBlock.BlockNumber - l.blockOffset - } - l.closeWait.Add(1) - go l.checkForRouteUpdates() + if l.pluginConfig.ContractVersion != 1 { + return errors.New("only contract version 1 is supported") } + l.closeWait.Add(1) + go l.checkForRouteUpdates() return nil }) } @@ -117,16 +156,15 @@ func (l *logPollerWrapper) LatestEvents() ([]evmRelayTypes.OracleRequest, []evmR if l.proposedCoordinator != (common.Address{}) && l.activeCoordinator != l.proposedCoordinator { coordinators = append(coordinators, l.proposedCoordinator) } - nextBlock := l.nextBlock latest, err := l.logPoller.LatestBlock() if err != nil { l.mu.Unlock() return nil, nil, err } - latestBlockNumber := latest.BlockNumber - latestBlockNumber -= l.blockOffset - if latestBlockNumber >= nextBlock { - l.nextBlock = latestBlockNumber + 1 + latestBlockNum := latest.BlockNumber + startBlockNum := latestBlockNum - l.pastBlocksToPoll + if startBlockNum < 0 { + startBlockNum = 0 } l.mu.Unlock() @@ -137,22 +175,24 @@ func (l *logPollerWrapper) LatestEvents() ([]evmRelayTypes.OracleRequest, []evmR l.lggr.Debug("LatestEvents: no non-zero coordinators to check") return resultsReq, resultsResp, errors.New("no non-zero coordinators to check") } - if latestBlockNumber < nextBlock { - l.lggr.Debugw("LatestEvents: no new blocks to check", "latest", latest, "nextBlock", nextBlock) - return resultsReq, resultsResp, nil - } for _, coordinator := range coordinators { - requestLogs, err := l.logPoller.Logs(nextBlock, latestBlockNumber, functions_coordinator.FunctionsCoordinatorOracleRequest{}.Topic(), coordinator) + requestEndBlock := latestBlockNum - l.requestBlockOffset + requestLogs, err := l.logPoller.Logs(startBlockNum, requestEndBlock, functions_coordinator.FunctionsCoordinatorOracleRequest{}.Topic(), coordinator) if err != nil { - l.lggr.Errorw("LatestEvents: fetching request logs from LogPoller failed", "latest", latest, "nextBlock", nextBlock) + l.lggr.Errorw("LatestEvents: fetching request logs from LogPoller failed", "startBlock", startBlockNum, "endBlock", requestEndBlock) return nil, nil, err } - responseLogs, err := l.logPoller.Logs(nextBlock, latestBlockNumber, functions_coordinator.FunctionsCoordinatorOracleResponse{}.Topic(), coordinator) + l.lggr.Debugw("LatestEvents: fetched request logs", "nRequestLogs", len(requestLogs), "latestBlock", latest, "startBlock", startBlockNum, "endBlock", requestEndBlock) + requestLogs = l.filterPreviouslyDetectedEvents(requestLogs, &l.detectedRequests, "requests") + responseEndBlock := latestBlockNum - l.responseBlockOffset + responseLogs, err := l.logPoller.Logs(startBlockNum, responseEndBlock, functions_coordinator.FunctionsCoordinatorOracleResponse{}.Topic(), coordinator) if err != nil { - l.lggr.Errorw("LatestEvents: fetching response logs from LogPoller failed", "latest", latest, "nextBlock", nextBlock) + l.lggr.Errorw("LatestEvents: fetching response logs from LogPoller failed", "startBlock", startBlockNum, "endBlock", responseEndBlock) return nil, nil, err } + l.lggr.Debugw("LatestEvents: fetched request logs", "nResponseLogs", len(responseLogs), "latestBlock", latest, "startBlock", startBlockNum, "endBlock", responseEndBlock) + responseLogs = l.filterPreviouslyDetectedEvents(responseLogs, &l.detectedResponses, "responses") parsingContract, err := functions_coordinator.NewFunctionsCoordinator(coordinator, l.client) if err != nil { @@ -165,7 +205,7 @@ func (l *logPollerWrapper) LatestEvents() ([]evmRelayTypes.OracleRequest, []evmR gethLog := log.ToGethLog() oracleRequest, err := parsingContract.ParseOracleRequest(gethLog) if err != nil { - l.lggr.Errorw("LatestEvents: failed to parse a request log, skipping") + l.lggr.Errorw("LatestEvents: failed to parse a request log, skipping", "err", err) continue } @@ -241,10 +281,46 @@ func (l *logPollerWrapper) LatestEvents() ([]evmRelayTypes.OracleRequest, []evmR } } - l.lggr.Debugw("LatestEvents: done", "nRequestLogs", len(resultsReq), "nResponseLogs", len(resultsResp), "nextBlock", nextBlock, "latest", latest) + l.lggr.Debugw("LatestEvents: done", "nRequestLogs", len(resultsReq), "nResponseLogs", len(resultsResp), "startBlock", startBlockNum, "endBlock", latestBlockNum) return resultsReq, resultsResp, nil } +func (l *logPollerWrapper) filterPreviouslyDetectedEvents(logs []logpoller.Log, detectedEvents *detectedEvents, filterType string) []logpoller.Log { + if len(logs) > maxLogsToProcess { + l.lggr.Errorw("filterPreviouslyDetectedEvents: too many logs to process, only processing latest maxLogsToProcess logs", "filterType", filterType, "nLogs", len(logs), "maxLogsToProcess", maxLogsToProcess) + logs = logs[len(logs)-maxLogsToProcess:] + } + l.mu.Lock() + defer l.mu.Unlock() + filteredLogs := []logpoller.Log{} + for _, log := range logs { + var requestId [32]byte + if len(log.Topics) < 2 || len(log.Topics[1]) != 32 { + l.lggr.Errorw("filterPreviouslyDetectedEvents: invalid log, skipping", "filterType", filterType, "log", log) + continue + } + copy(requestId[:], log.Topics[1]) // requestId is the second topic (1st topic is the event signature) + if _, ok := detectedEvents.isPreviouslyDetected[requestId]; !ok { + filteredLogs = append(filteredLogs, log) + detectedEvents.isPreviouslyDetected[requestId] = struct{}{} + detectedEvents.detectedEventsOrdered = append(detectedEvents.detectedEventsOrdered, detectedEvent{requestId: requestId, timeDetected: time.Now()}) + } + } + expiredRequests := 0 + for _, detectedEvent := range detectedEvents.detectedEventsOrdered { + expirationTime := time.Now().Add(-time.Second * time.Duration(l.logPollerCacheDurationSec)) + if detectedEvent.timeDetected.Before(expirationTime) { + delete(detectedEvents.isPreviouslyDetected, detectedEvent.requestId) + expiredRequests++ + } else { + break + } + } + detectedEvents.detectedEventsOrdered = detectedEvents.detectedEventsOrdered[expiredRequests:] + l.lggr.Debugw("filterPreviouslyDetectedEvents: done", "filterType", filterType, "nLogs", len(logs), "nFilteredLogs", len(filteredLogs), "nExpiredRequests", expiredRequests, "previouslyDetectedCacheSize", len(detectedEvents.detectedEventsOrdered)) + return filteredLogs +} + // "internal" method called only by EVM relayer components func (l *logPollerWrapper) SubscribeToUpdates(subscriberName string, subscriber evmRelayTypes.RouteUpdateSubscriber) { if l.pluginConfig.ContractVersion == 0 { diff --git a/core/services/relay/evm/functions/logpoller_wrapper_test.go b/core/services/relay/evm/functions/logpoller_wrapper_test.go index c91c3c49aa..2108e822d5 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper_test.go +++ b/core/services/relay/evm/functions/logpoller_wrapper_test.go @@ -1,22 +1,24 @@ -package functions_test +package functions import ( + "crypto/rand" "encoding/hex" "sync" "testing" + "time" "github.com/ethereum/go-ethereum/common" - gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -57,17 +59,34 @@ func setUp(t *testing.T, updateFrequencySec uint32) (*lpmocks.LogPoller, types.L ContractUpdateCheckFrequencySec: updateFrequencySec, ContractVersion: 1, } - lpWrapper, err := functions.NewLogPollerWrapper(gethcommon.Address{}, config, client, lp, lggr) + lpWrapper, err := NewLogPollerWrapper(common.Address{}, config, client, lp, lggr) require.NoError(t, err) - lp.On("LatestBlock").Return(logpoller.LogPollerBlock{BlockNumber: int64(100)}, nil) - return lp, lpWrapper, client } +func getMockedRequestLog(t *testing.T) logpoller.Log { + // NOTE: Change this to be a more readable log generation + data, err := hex.DecodeString("000000000000000000000000c113ba31b0080f940ca5812bbccc1e038ea9efb40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c113ba31b0080f940ca5812bbccc1e038ea9efb4000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001117082cd81744eb9504dc37f53a86db7e3fb24929b8e7507b097d501ab5b315fb20e0000000000000000000000001b4f2b0e6363097f413c249910d5bc632993ed08000000000000000000000000000000000000000000000000015bcf880382c000000000000000000000000000665785a800593e8fa915208c1ce62f6e57fd75ba0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000001117000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f588000000000000000000000000000000000000000000000000000000000000c350000000000000000000000000000000000000000000000000000000000000021c00000000000000000000000000000000000000000000000000000000000008866c636f64654c6f636174696f6ec258200000000000000000000000000000000000000000000000000000000000000000686c616e6775616765c25820000000000000000000000000000000000000000000000000000000000000000066736f757263657907d0633836366665643238326533313137636466303836633934396662613133643834666331376131656335353934656361643034353133646632326137623538356333363763633132326236373138306334383737303435616235383033373463353066313862346564386132346131323437383532363731623030633035663237373163663036363632333663333236393939323139363866323833346438626462616266306661643165313237613837643237363936323831643965656539326134646263316337356137316136656333613135356438633230616661643064623432383362613433353736303734653035633433633561653061656466643332323838346536613231386466323430323630316436356437316131303061633065376563643037663565646364633535643562373932646130626632353665623038363139336463376431333965613764373965653531653831356465333834386565643363366330353837393265366461333434363738626436373239346636643639656564356132663836323835343965616530323235323835346232666361333635646265623032383433386537326234383465383864316136646563373933633739656265353834666465363465663831383363313365386231623735663037636532303963393138633532643637613735343862653236366433663964316439656132613162303166633838376231316162383739663164333861373833303563373031316533643938346130393863663634383931316536653065383038396365306130363230393136663134323935343036336630376239343931326435666331393366303138633764616135363136323562313966376463323036663930353365623234643036323234616164326338623430646162663631656166666635326234653831373239353837333830313561643730663739316663643864333739343035353737393563383937363164636665333639373938373437353439633234643530646464303563623337613465613863353162306530313032363738643433653766306563353039653434633564343764353335626261363831303936383264643864653439326532363633646336653133653532383539663664336565306533633430336236366362653338643236366137356163373639363863613465653331396166363965373431333137393162653630376537353832373430366164653038306335623239653665343262386563386137373761663865383166336234616337626263666531643066616633393338613664353061316561633835643933643234343066313863333037356237306433626134663930323836396439383937663266636562626262366263646439333436633336633663643838626434336265306562333134323562343665613765386338336638386230363933343836383666366134313839623535666132666431396634326264333730313634616339356530303635656461663130373761633131366632393930303833616631333839636661666336613433323439376531363437393762633738616633366335613435366136646661326636626430626639326136613930366130653930313130626266323265613066333163663364353132663466303331653236343330633831663935656431323362323938356266623830623161396432646337306232356264613961386261303839323833666166663634383661316231646235613938353564346237363966623835663531353063393935306462303964373536326537353133633234653531636163366634366634633231636234373561613937363166666466626434656138613531626465613432383037313466363538393630656336643139656539373237626339316635313665346466306665346264613762623035343161393462326334396636323938616132396337656130646662653635346632306437663164323239633066303262356535326137363031376237306439383232643533383166623966613166393361353861376338383632326631326462643363623937323363626132313639633337643538303939336333663666393065323039336331336130363132323334303064393731363031656262313631343332613966666333373033396562663537326364326566666635636562323539346236346462336261616431633734663532653938343938353964383363313238353465376263393764363432363464653931343735386333386438383739343132333937653263643534653431366234373962363331623830626633306266653062366239353564393066356362303435346361373531303963393938366330636536316165356566376534653433353036313432633633646235363862383634353139623463306636366137633161376661336538666431323231376666336665383164663830643138386232646334343833356132663332323733666133353139633531343764643233353763326161346336326461386238353232306535386130333565373662633133316634623734376632663731643263663933376431303832356138316533623963323136663962316134646431663239383463656635656363656265353530363662363061373263363063323864303336653766386635323131343735386638326366323330646636363930636364617267739f64617267316461726732ff6f736563726574734c6f636174696f6ec2582000000000000000000000000000000000000000000000000000000000000000016773656372657473430102030000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + topic0, err := hex.DecodeString("bf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff") + require.NoError(t, err) + // Create a random requestID + topic1 := make([]byte, 32) + _, err = rand.Read(topic1) + require.NoError(t, err) + topic2, err := hex.DecodeString("000000000000000000000000665785a800593e8fa915208c1ce62f6e57fd75ba") + require.NoError(t, err) + return logpoller.Log{ + Topics: [][]byte{topic0, topic1, topic2}, + Data: data, + } +} + func TestLogPollerWrapper_SingleSubscriberEmptyEvents(t *testing.T) { t.Parallel() lp, lpWrapper, client := setUp(t, 100_000) // check only once + lp.On("LatestBlock").Return(logpoller.LogPollerBlock{BlockNumber: int64(100)}, nil) lp.On("Logs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{}, nil) client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(addr(t, "01"), nil) @@ -87,7 +106,8 @@ func TestLogPollerWrapper_SingleSubscriberEmptyEvents(t *testing.T) { func TestLogPollerWrapper_ErrorOnZeroAddresses(t *testing.T) { t.Parallel() - _, lpWrapper, client := setUp(t, 100_000) // check only once + lp, lpWrapper, client := setUp(t, 100_000) // check only once + lp.On("LatestBlock").Return(logpoller.LogPollerBlock{BlockNumber: int64(100)}, nil) client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(addr(t, "00"), nil) @@ -96,3 +116,96 @@ func TestLogPollerWrapper_ErrorOnZeroAddresses(t *testing.T) { require.Error(t, err) lpWrapper.Close() } + +func TestLogPollerWrapper_LatestEvents_ReorgHandling(t *testing.T) { + t.Parallel() + lp, lpWrapper, client := setUp(t, 100_000) + lp.On("LatestBlock").Return(logpoller.LogPollerBlock{BlockNumber: int64(100)}, nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(addr(t, "01"), nil) + lp.On("RegisterFilter", mock.Anything).Return(nil) + subscriber := newSubscriber(1) + lpWrapper.SubscribeToUpdates("mock_subscriber", subscriber) + mockedLog := getMockedRequestLog(t) + // All logPoller queries for responses return none + lp.On("Logs", mock.Anything, mock.Anything, functions_coordinator.FunctionsCoordinatorOracleResponse{}.Topic(), mock.Anything).Return([]logpoller.Log{}, nil) + // On the first logPoller query for requests, the request log appears + lp.On("Logs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{mockedLog}, nil).Once() + // On the 2nd query, the request log disappears + lp.On("Logs", mock.Anything, mock.Anything, functions_coordinator.FunctionsCoordinatorOracleRequest{}.Topic(), mock.Anything).Return([]logpoller.Log{}, nil).Once() + // On the 3rd query, the original request log appears again + lp.On("Logs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{mockedLog}, nil).Once() + + require.NoError(t, lpWrapper.Start(testutils.Context(t))) + subscriber.updates.Wait() + + oracleRequests, _, err := lpWrapper.LatestEvents() + require.NoError(t, err) + assert.Equal(t, 1, len(oracleRequests)) + oracleRequests, _, err = lpWrapper.LatestEvents() + require.NoError(t, err) + assert.Equal(t, 0, len(oracleRequests)) + require.NoError(t, err) + oracleRequests, _, err = lpWrapper.LatestEvents() + require.NoError(t, err) + assert.Equal(t, 0, len(oracleRequests)) +} + +func TestLogPollerWrapper_FilterPreviouslyDetectedEvents_TruncatesLogs(t *testing.T) { + t.Parallel() + _, lpWrapper, _ := setUp(t, 100_000) + + inputLogs := make([]logpoller.Log, maxLogsToProcess+100) + for i := 0; i < 1100; i++ { + inputLogs[i] = getMockedRequestLog(t) + } + + functionsLpWrapper := lpWrapper.(*logPollerWrapper) + mockedDetectedEvents := detectedEvents{isPreviouslyDetected: make(map[[32]byte]struct{})} + outputLogs := functionsLpWrapper.filterPreviouslyDetectedEvents(inputLogs, &mockedDetectedEvents, "request") + + assert.Equal(t, maxLogsToProcess, len(outputLogs)) + assert.Equal(t, 1000, len(mockedDetectedEvents.detectedEventsOrdered)) + assert.Equal(t, 1000, len(mockedDetectedEvents.isPreviouslyDetected)) +} + +func TestLogPollerWrapper_FilterPreviouslyDetectedEvents_SkipsInvalidLog(t *testing.T) { + t.Parallel() + _, lpWrapper, _ := setUp(t, 100_000) + inputLogs := []logpoller.Log{getMockedRequestLog(t)} + inputLogs[0].Topics = [][]byte{[]byte("invalid topic")} + mockedDetectedEvents := detectedEvents{isPreviouslyDetected: make(map[[32]byte]struct{})} + + functionsLpWrapper := lpWrapper.(*logPollerWrapper) + outputLogs := functionsLpWrapper.filterPreviouslyDetectedEvents(inputLogs, &mockedDetectedEvents, "request") + + assert.Equal(t, 0, len(outputLogs)) + assert.Equal(t, 0, len(mockedDetectedEvents.detectedEventsOrdered)) + assert.Equal(t, 0, len(mockedDetectedEvents.isPreviouslyDetected)) +} + +func TestLogPollerWrapper_FilterPreviouslyDetectedEvents_FiltersPreviouslyDetectedEvent(t *testing.T) { + t.Parallel() + _, lpWrapper, _ := setUp(t, 100_000) + mockedRequestLog := getMockedRequestLog(t) + inputLogs := []logpoller.Log{mockedRequestLog} + var mockedRequestId [32]byte + copy(mockedRequestId[:], mockedRequestLog.Topics[1]) + + mockedDetectedEvents := detectedEvents{ + isPreviouslyDetected: make(map[[32]byte]struct{}), + detectedEventsOrdered: make([]detectedEvent, 1), + } + mockedDetectedEvents.isPreviouslyDetected[mockedRequestId] = struct{}{} + mockedDetectedEvents.detectedEventsOrdered[0] = detectedEvent{ + requestId: mockedRequestId, + timeDetected: time.Now().Add(-time.Second * time.Duration(logPollerCacheDurationSecDefault+1)), + } + + functionsLpWrapper := lpWrapper.(*logPollerWrapper) + outputLogs := functionsLpWrapper.filterPreviouslyDetectedEvents(inputLogs, &mockedDetectedEvents, "request") + + assert.Equal(t, 0, len(outputLogs)) + // Ensure that expired events are removed from the cache + assert.Equal(t, 0, len(mockedDetectedEvents.detectedEventsOrdered)) + assert.Equal(t, 0, len(mockedDetectedEvents.isPreviouslyDetected)) +} From 45844de10fcc4a31436cf8f9f84ab555e2a0f044 Mon Sep 17 00:00:00 2001 From: David Cauchi <13139524+davidcauchi@users.noreply.github.com> Date: Wed, 1 Nov 2023 15:06:12 +0100 Subject: [PATCH 046/327] Add base goerli benchmark option (#11089) * Add base goerli benchmark option * Add config * Add to op stack deployer * Add FlatFeeMicroLink --- .github/workflows/automation-benchmark-tests.yml | 1 + integration-tests/benchmark/keeper_test.go | 7 +++++++ integration-tests/contracts/contract_deployer.go | 2 ++ 3 files changed, 10 insertions(+) diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index f23102f1ee..5c4dced934 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -24,6 +24,7 @@ on: - OPTIMISM_GOERLI - MUMBAI - SEPOLIA + - BASE_GOERLI TestInputs: description: TestInputs required: false diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 6fbf929e47..55f769e73b 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -161,6 +161,7 @@ func TestAutomationBenchmark(t *testing.T) { RegistryVersions: registryVersions, KeeperRegistrySettings: &contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(0), + FlatFeeMicroLINK: uint32(40000), BlockCountPerTurn: big.NewInt(100), CheckGasLimit: uint32(45_000_000), //45M StalenessSeconds: big.NewInt(90_000), @@ -282,6 +283,12 @@ var networkConfig = map[string]NetworkConfig{ deltaStage: time.Duration(0), funding: big.NewFloat(ChainlinkNodeFunding), }, + "BaseGoerli": { + upkeepSLA: int64(60), + blockTime: 2 * time.Second, + deltaStage: 20 * time.Second, + funding: big.NewFloat(ChainlinkNodeFunding), + }, } func getEnv(key, fallback string) string { diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 710422891c..94f6c73386 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -883,6 +883,8 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( //Optimism payment model case big.NewInt(420): mode = uint8(2) + case big.NewInt(84531): + mode = uint8(2) default: mode = uint8(0) } From fda43935a2582cbe75d38088ef523bcf6091841f Mon Sep 17 00:00:00 2001 From: Lei Date: Wed, 1 Nov 2023 12:40:55 -0700 Subject: [PATCH 047/327] add an empty index.html under core/web/assets to avoid running make commands (#11114) --- .github/workflows/automation-ondemand-tests.yml | 2 +- .github/workflows/integration-chaos-tests.yml | 2 +- .github/workflows/integration-tests.yml | 8 ++++---- GNUmakefile | 4 ---- core/web/assets/index.html | 0 integration-tests/Makefile | 2 +- 6 files changed, 7 insertions(+), 11 deletions(-) create mode 100644 core/web/assets/index.html diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index ac0e34e083..fb8adcfdb6 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -182,7 +182,7 @@ jobs: UPGRADE_VERSION: ${{ steps.determine-build.outputs.upgrade_version }} UPGRADE_IMAGE: ${{ steps.determine-build.outputs.upgrade_image }} with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ steps.determine-build.outputs.image }} cl_image_tag: ${{ steps.determine-build.outputs.version }} diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 648d5f9daa..4ad985e915 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -111,7 +111,7 @@ jobs: - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: - test_command_to_run: make test_need_operator_assets && cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 11 ./chaos 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 11 ./chaos 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 5074fc35b9..b66ab58d55 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -218,7 +218,7 @@ jobs: PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} @@ -417,7 +417,7 @@ jobs: PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }}${{ matrix.product.tag_suffix }} @@ -574,7 +574,7 @@ jobs: - name: Run Migration Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ steps.get_latest_version.outputs.latest_version }} @@ -935,7 +935,7 @@ jobs: PYROSCOPE_ENVIRONMENT: ci-smoke-ocr-evm-${{ matrix.testnet }} # TODO: Only for OCR for now PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/ocr_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/ocr_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} diff --git a/GNUmakefile b/GNUmakefile index 957df96ce4..32f74e285e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -127,10 +127,6 @@ telemetry-protobuf: $(telemetry-protobuf) ## Generate telemetry protocol buffers --go-wsrpc_opt=paths=source_relative \ ./core/services/synchronization/telem/*.proto -.PHONY: test_need_operator_assets -test_need_operator_assets: ## Add blank file in web assets if operator ui has not been built - [ -f "./core/web/assets/index.html" ] || mkdir ./core/web/assets && touch ./core/web/assets/index.html - .PHONY: config-docs config-docs: ## Generate core node configuration documentation go run ./core/config/docs/cmd/generate -o ./docs/ diff --git a/core/web/assets/index.html b/core/web/assets/index.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integration-tests/Makefile b/integration-tests/Makefile index f26518c007..257331afcf 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -118,7 +118,7 @@ test_chaos_verbose: ## Run all smoke tests with verbose logging # Performance .PHONY: test_perf -test_perf: test_need_operator_assets ## Run core node performance tests. +test_perf: ## Run core node performance tests. TEST_LOG_LEVEL="disabled" \ SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ go test -timeout 1h -count=1 -json $(args) ./performance 2>&1 | tee /tmp/gotest.log | gotestfmt From 08c9f89bcabbde28d40349e010f629ea840bfd9a Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Wed, 1 Nov 2023 22:41:45 +0200 Subject: [PATCH 048/327] Introduce generalized multi node client (#10907) * Introduce generalized multi node client * Export EVM RPC client * Unexport clientAPI interface * Add BlockDifficulty to mocks * Unexport node state * Rename error parsing * Nit fixes * Rename error classification functions * Update NodeSelection names * Deprecate StartStopOnce --- common/chains/client/models.go | 22 + common/client/multi_node.go | 669 +++++++++++ common/client/node.go | 282 +++++ common/client/node_fsm.go | 266 +++++ common/client/node_lifecycle.go | 431 +++++++ common/client/node_selector_highest_head.go | 41 + common/client/node_selector_priority_level.go | 129 ++ common/client/node_selector_round_robin.go | 50 + .../client/node_selector_total_difficulty.go | 54 + common/client/send_only_node.go | 183 +++ common/client/send_only_node_lifecycle.go | 66 ++ common/client/types.go | 133 +++ common/headtracker/types/mocks/head.go | 17 + common/types/head.go | 6 + common/types/mocks/head.go | 17 + common/types/receipt.go | 14 + core/chains/evm/chain.go | 18 + core/chains/evm/client/chain_client.go | 274 +++++ core/chains/evm/client/client.go | 2 +- core/chains/evm/client/client_test.go | 442 ++++--- core/chains/evm/client/errors.go | 14 +- core/chains/evm/client/helpers_test.go | 65 + core/chains/evm/client/rpc_client.go | 1046 +++++++++++++++++ core/chains/evm/txmgr/client.go | 2 +- core/chains/evm/types/models.go | 4 + 25 files changed, 4110 insertions(+), 137 deletions(-) create mode 100644 common/client/multi_node.go create mode 100644 common/client/node.go create mode 100644 common/client/node_fsm.go create mode 100644 common/client/node_lifecycle.go create mode 100644 common/client/node_selector_highest_head.go create mode 100644 common/client/node_selector_priority_level.go create mode 100644 common/client/node_selector_round_robin.go create mode 100644 common/client/node_selector_total_difficulty.go create mode 100644 common/client/send_only_node.go create mode 100644 common/client/send_only_node_lifecycle.go create mode 100644 common/client/types.go create mode 100644 common/types/receipt.go create mode 100644 core/chains/evm/client/chain_client.go create mode 100644 core/chains/evm/client/rpc_client.go diff --git a/common/chains/client/models.go b/common/chains/client/models.go index ebe7bb7576..bd974f901f 100644 --- a/common/chains/client/models.go +++ b/common/chains/client/models.go @@ -1,5 +1,9 @@ package client +import ( + "fmt" +) + type SendTxReturnCode int // SendTxReturnCode is a generalized client error that dictates what should be the next action, depending on the RPC error response. @@ -15,3 +19,21 @@ const ( ExceedsMaxFee // Attempt's fee was higher than the node's limit and got rejected. FeeOutOfValidRange // This error is returned when we use a fee price suggested from an RPC, but the network rejects the attempt due to an invalid range(mostly used by L2 chains). Retry by requesting a new suggested fee price. ) + +type NodeTier int + +const ( + Primary = NodeTier(iota) + Secondary +) + +func (n NodeTier) String() string { + switch n { + case Primary: + return "primary" + case Secondary: + return "secondary" + default: + return fmt.Sprintf("NodeTier(%d)", n) + } +} diff --git a/common/client/multi_node.go b/common/client/multi_node.go new file mode 100644 index 0000000000..0da3b89076 --- /dev/null +++ b/common/client/multi_node.go @@ -0,0 +1,669 @@ +package client + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" + + "github.com/smartcontractkit/chainlink/v2/common/chains/client" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +var ( + // PromMultiNodeRPCNodeStates reports current RPC node state + PromMultiNodeRPCNodeStates = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "multi_node_states", + Help: "The number of RPC nodes currently in the given state for the given chain", + }, []string{"network", "chainId", "state"}) + 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[ + CHAIN_ID types.ID, + SEQ types.Sequence, + ADDR types.Hashable, + BLOCK_HASH types.Hashable, + TX any, + TX_HASH types.Hashable, + EVENT any, + EVENT_OPS any, + TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], + FEE feetypes.Fee, + HEAD types.Head[BLOCK_HASH], + RPC_CLIENT RPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD], +] interface { + clientAPI[ + CHAIN_ID, + SEQ, + ADDR, + BLOCK_HASH, + TX, + TX_HASH, + EVENT, + EVENT_OPS, + TX_RECEIPT, + FEE, + HEAD, + ] + Close() error + NodeStates() map[string]string + SelectNodeRPC() (RPC_CLIENT, error) + + BatchCallContextAll(ctx context.Context, b []any) error + ConfiguredChainID() CHAIN_ID + IsL2() bool +} + +type multiNode[ + CHAIN_ID types.ID, + SEQ types.Sequence, + ADDR types.Hashable, + BLOCK_HASH types.Hashable, + TX any, + TX_HASH types.Hashable, + EVENT any, + EVENT_OPS any, + TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], + FEE feetypes.Fee, + HEAD types.Head[BLOCK_HASH], + RPC_CLIENT RPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD], +] struct { + services.StateMachine + nodes []Node[CHAIN_ID, HEAD, RPC_CLIENT] + sendonlys []SendOnlyNode[CHAIN_ID, RPC_CLIENT] + chainID CHAIN_ID + chainType config.ChainType + logger logger.Logger + selectionMode string + noNewHeadsThreshold time.Duration + nodeSelector NodeSelector[CHAIN_ID, HEAD, RPC_CLIENT] + leaseDuration time.Duration + leaseTicker *time.Ticker + chainFamily string + + activeMu sync.RWMutex + activeNode Node[CHAIN_ID, HEAD, RPC_CLIENT] + + chStop utils.StopChan + wg sync.WaitGroup + + sendOnlyErrorParser func(err error) client.SendTxReturnCode +} + +func NewMultiNode[ + CHAIN_ID types.ID, + SEQ types.Sequence, + ADDR types.Hashable, + BLOCK_HASH types.Hashable, + TX any, + TX_HASH types.Hashable, + EVENT any, + EVENT_OPS any, + TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], + FEE feetypes.Fee, + HEAD types.Head[BLOCK_HASH], + RPC_CLIENT RPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD], +]( + logger logger.Logger, + selectionMode string, + leaseDuration time.Duration, + noNewHeadsThreshold time.Duration, + nodes []Node[CHAIN_ID, HEAD, RPC_CLIENT], + sendonlys []SendOnlyNode[CHAIN_ID, RPC_CLIENT], + chainID CHAIN_ID, + chainType config.ChainType, + chainFamily string, + sendOnlyErrorParser func(err error) client.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)) + } + }() + + lggr := logger.Named("MultiNode").With("chainID", chainID.String()) + + c := &multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]{ + nodes: nodes, + sendonlys: sendonlys, + chainID: chainID, + chainType: chainType, + logger: lggr, + selectionMode: selectionMode, + noNewHeadsThreshold: noNewHeadsThreshold, + nodeSelector: nodeSelector, + chStop: make(chan struct{}), + leaseDuration: leaseDuration, + chainFamily: chainFamily, + sendOnlyErrorParser: sendOnlyErrorParser, + } + + c.logger.Debugf("The MultiNode is configured to use NodeSelectionMode: %s", selectionMode) + + return c +} + +// Dial starts every node in the pool +// +// Nodes handle their own redialing and runloops, so this function does not +// return any error if the nodes aren't available +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) Dial(ctx context.Context) error { + return c.StartOnce("MultiNode", func() (merr error) { + if len(c.nodes) == 0 { + return errors.Errorf("no available nodes for chain %s", c.chainID.String()) + } + var ms services.MultiStart + for _, n := range c.nodes { + if n.ConfiguredChainID().String() != c.chainID.String() { + return ms.CloseBecause(errors.Errorf("node %s has configured chain ID %s which does not match multinode configured chain ID of %s", n.String(), n.ConfiguredChainID().String(), c.chainID.String())) + } + rawNode, ok := n.(*node[CHAIN_ID, HEAD, RPC_CLIENT]) + if ok { + // This is a bit hacky but it allows the node to be aware of + // pool state and prevent certain state transitions that might + // otherwise leave no nodes available. It is better to have one + // node in a degraded state than no nodes at all. + rawNode.nLiveNodes = c.nLiveNodes + } + // node will handle its own redialing and automatic recovery + if err := ms.Start(ctx, n); err != nil { + return err + } + } + for _, s := range c.sendonlys { + if s.ConfiguredChainID().String() != c.chainID.String() { + return ms.CloseBecause(errors.Errorf("sendonly node %s has configured chain ID %s which does not match multinode configured chain ID of %s", s.String(), s.ConfiguredChainID().String(), c.chainID.String())) + } + if err := ms.Start(ctx, s); err != nil { + return err + } + } + c.wg.Add(1) + go c.runLoop() + + if c.leaseDuration.Seconds() > 0 && c.selectionMode != NodeSelectionModeRoundRobin { + c.logger.Infof("The MultiNode will switch to best node every %s", c.leaseDuration.String()) + c.wg.Add(1) + go c.checkLeaseLoop() + } else { + c.logger.Info("Best node switching is disabled") + } + + return nil + }) +} + +// Close tears down the MultiNode and closes all nodes +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) Close() error { + return c.StopOnce("MultiNode", func() error { + close(c.chStop) + c.wg.Wait() + + return services.CloseAll(services.MultiCloser(c.nodes), services.MultiCloser(c.sendonlys)) + }) +} + +// SelectNodeRPC returns an RPC of an active node. If there are no active nodes it returns an error. +// Call this method from your chain-specific client implementation to access any chain-specific rpc calls. +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) SelectNodeRPC() (rpc RPC_CLIENT, err error) { + n, err := c.selectNode() + if err != nil { + return rpc, err + } + return n.RPC(), nil + +} + +// selectNode returns the active Node, if it is still nodeStateAlive, otherwise it selects a new one from the NodeSelector. +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) selectNode() (node Node[CHAIN_ID, HEAD, RPC_CLIENT], err error) { + c.activeMu.RLock() + node = c.activeNode + c.activeMu.RUnlock() + if node != nil && node.State() == nodeStateAlive { + return // still alive + } + + // select a new one + c.activeMu.Lock() + defer c.activeMu.Unlock() + node = c.activeNode + if node != nil && node.State() == nodeStateAlive { + return // another goroutine beat us here + } + + c.activeNode = c.nodeSelector.Select() + + if c.activeNode == nil { + c.logger.Criticalw("No live RPC nodes available", "NodeSelectionMode", c.nodeSelector.Name()) + errmsg := fmt.Errorf("no live nodes available for chain %s", c.chainID.String()) + c.SvcErrBuffer.Append(errmsg) + err = ErroringNodeError + } + + return c.activeNode, err +} + +// nLiveNodes returns the number of currently alive nodes, as well as the highest block number and greatest total difficulty. +// totalDifficulty will be 0 if all nodes return nil. +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) nLiveNodes() (nLiveNodes int, blockNumber int64, totalDifficulty *utils.Big) { + totalDifficulty = utils.NewBigI(0) + for _, n := range c.nodes { + if s, num, td := n.StateAndLatest(); s == nodeStateAlive { + nLiveNodes++ + if num > blockNumber { + blockNumber = num + } + if td != nil && td.Cmp(totalDifficulty) > 0 { + totalDifficulty = td + } + } + } + return +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) checkLease() { + bestNode := c.nodeSelector.Select() + for _, n := range c.nodes { + // Terminate client subscriptions. Services are responsible for reconnecting, which will be routed to the new + // best node. Only terminate connections with more than 1 subscription to account for the aliveLoop subscription + if n.State() == nodeStateAlive && n != bestNode && n.SubscribersCount() > 1 { + c.logger.Infof("Switching to best node from %q to %q", n.String(), bestNode.String()) + n.UnsubscribeAllExceptAliveLoop() + } + } + + c.activeMu.Lock() + if bestNode != c.activeNode { + c.activeNode = bestNode + } + c.activeMu.Unlock() +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) checkLeaseLoop() { + defer c.wg.Done() + c.leaseTicker = time.NewTicker(c.leaseDuration) + defer c.leaseTicker.Stop() + + for { + select { + case <-c.leaseTicker.C: + c.checkLease() + case <-c.chStop: + return + } + } +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) runLoop() { + defer c.wg.Done() + + 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)) + defer monitor.Stop() + + for { + select { + case <-monitor.C: + c.report() + case <-c.chStop: + return + } + } +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) report() { + type nodeWithState struct { + Node string + State string + } + + var total, dead int + counts := make(map[nodeState]int) + nodeStates := make([]nodeWithState, len(c.nodes)) + for i, n := range c.nodes { + state := n.State() + nodeStates[i] = nodeWithState{n.String(), state.String()} + total++ + if state != nodeStateAlive { + dead++ + } + counts[state]++ + } + for _, state := range allNodeStates { + count := counts[state] + PromMultiNodeRPCNodeStates.WithLabelValues(c.chainFamily, c.chainID.String(), state.String()).Set(float64(count)) + } + + live := total - dead + c.logger.Tracew(fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + if total == dead { + rerr := fmt.Errorf("no primary nodes available: 0/%d nodes are alive", total) + c.logger.Criticalw(rerr.Error(), "nodeStates", nodeStates) + c.SvcErrBuffer.Append(rerr) + } else if dead > 0 { + c.logger.Errorw(fmt.Sprintf("At least one primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + } +} + +// ClientAPI methods +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) BalanceAt(ctx context.Context, account ADDR, blockNumber *big.Int) (*big.Int, error) { + n, err := c.selectNode() + if err != nil { + return nil, err + } + return n.RPC().BalanceAt(ctx, account, blockNumber) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) BatchCallContext(ctx context.Context, b []any) error { + n, err := c.selectNode() + if err != nil { + return err + } + return n.RPC().BatchCallContext(ctx, b) +} + +// BatchCallContextAll calls BatchCallContext for every single node including +// sendonlys. +// CAUTION: This should only be used for mass re-transmitting transactions, it +// might have unexpected effects to use it for anything else. +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) BatchCallContextAll(ctx context.Context, b []any) error { + var wg sync.WaitGroup + defer wg.Wait() + + main, selectionErr := c.selectNode() + var all []SendOnlyNode[CHAIN_ID, RPC_CLIENT] + for _, n := range c.nodes { + all = append(all, n) + } + all = append(all, c.sendonlys...) + for _, n := range all { + if n == main { + // main node is used at the end for the return value + continue + } + // Parallel call made to all other nodes with ignored return value + wg.Add(1) + go func(n SendOnlyNode[CHAIN_ID, RPC_CLIENT]) { + defer wg.Done() + err := n.RPC().BatchCallContext(ctx, b) + if err != nil { + c.logger.Debugw("Secondary node BatchCallContext failed", "err", err) + } else { + c.logger.Trace("Secondary node BatchCallContext success") + } + }(n) + } + + if selectionErr != nil { + return selectionErr + } + return main.RPC().BatchCallContext(ctx, b) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) BlockByHash(ctx context.Context, hash BLOCK_HASH) (h HEAD, err error) { + n, err := c.selectNode() + if err != nil { + return h, err + } + return n.RPC().BlockByHash(ctx, hash) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) BlockByNumber(ctx context.Context, number *big.Int) (h HEAD, err error) { + n, err := c.selectNode() + if err != nil { + return h, err + } + return n.RPC().BlockByNumber(ctx, number) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + n, err := c.selectNode() + if err != nil { + return err + } + return n.RPC().CallContext(ctx, result, method, args...) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) CallContract( + ctx context.Context, + attempt interface{}, + blockNumber *big.Int, +) (rpcErr []byte, extractErr error) { + n, err := c.selectNode() + if err != nil { + return rpcErr, err + } + return n.RPC().CallContract(ctx, attempt, blockNumber) +} + +// ChainID makes a direct RPC call. In most cases it should be better to use the configured chain id instead by +// calling ConfiguredChainID. +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) ChainID(ctx context.Context) (id CHAIN_ID, err error) { + n, err := c.selectNode() + if err != nil { + return id, err + } + return n.RPC().ChainID(ctx) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) ChainType() config.ChainType { + return c.chainType +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) CodeAt(ctx context.Context, account ADDR, blockNumber *big.Int) (code []byte, err error) { + n, err := c.selectNode() + if err != nil { + return code, err + } + return n.RPC().CodeAt(ctx, account, blockNumber) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) ConfiguredChainID() CHAIN_ID { + return c.chainID +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) EstimateGas(ctx context.Context, call any) (gas uint64, err error) { + n, err := c.selectNode() + if err != nil { + return gas, err + } + return n.RPC().EstimateGas(ctx, call) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) FilterEvents(ctx context.Context, query EVENT_OPS) (e []EVENT, err error) { + n, err := c.selectNode() + if err != nil { + return e, err + } + return n.RPC().FilterEvents(ctx, query) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) IsL2() bool { + return c.ChainType().IsL2() +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) LatestBlockHeight(ctx context.Context) (h *big.Int, err error) { + n, err := c.selectNode() + if err != nil { + return h, err + } + return n.RPC().LatestBlockHeight(ctx) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) LINKBalance(ctx context.Context, accountAddress ADDR, linkAddress ADDR) (b *assets.Link, err error) { + n, err := c.selectNode() + if err != nil { + return b, err + } + return n.RPC().LINKBalance(ctx, accountAddress, linkAddress) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) NodeStates() (states map[string]string) { + states = make(map[string]string) + for _, n := range c.nodes { + states[n.Name()] = n.State().String() + } + for _, s := range c.sendonlys { + states[s.Name()] = s.State().String() + } + return +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) PendingSequenceAt(ctx context.Context, addr ADDR) (s SEQ, err error) { + n, err := c.selectNode() + if err != nil { + return s, err + } + return n.RPC().PendingSequenceAt(ctx, addr) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) SendEmptyTransaction( + ctx context.Context, + newTxAttempt func(seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (attempt any, err error), + seq SEQ, + gasLimit uint32, + fee FEE, + fromAddress ADDR, +) (txhash string, err error) { + n, err := c.selectNode() + if err != nil { + return txhash, err + } + return n.RPC().SendEmptyTransaction(ctx, newTxAttempt, seq, gasLimit, fee, fromAddress) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) SendTransaction(ctx context.Context, tx TX) error { + main, nodeError := c.selectNode() + var all []SendOnlyNode[CHAIN_ID, RPC_CLIENT] + for _, n := range c.nodes { + all = append(all, n) + } + all = append(all, c.sendonlys...) + for _, n := range all { + if n == main { + // main node is used at the end for the return value + continue + } + // Parallel send to all other nodes with ignored return value + // Async - we do not want to block the main thread with secondary nodes + // in case they are unreliable/slow. + // It is purely a "best effort" send. + // Resource is not unbounded because the default context has a timeout. + ok := c.IfNotStopped(func() { + // Must wrap inside IfNotStopped to avoid waitgroup racing with Close + c.wg.Add(1) + go func(n SendOnlyNode[CHAIN_ID, RPC_CLIENT]) { + defer c.wg.Done() + + txErr := n.RPC().SendTransaction(ctx, tx) + c.logger.Debugw("Sendonly node sent transaction", "name", n.String(), "tx", tx, "err", txErr) + sendOnlyError := c.sendOnlyErrorParser(txErr) + if sendOnlyError != client.Successful { + c.logger.Warnw("RPC returned error", "name", n.String(), "tx", tx, "err", txErr) + } + }(n) + }) + if !ok { + c.logger.Debug("Cannot send transaction on sendonly node; MultiNode is stopped", "node", n.String()) + } + } + if nodeError != nil { + return nodeError + } + return main.RPC().SendTransaction(ctx, tx) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) SequenceAt(ctx context.Context, account ADDR, blockNumber *big.Int) (s SEQ, err error) { + n, err := c.selectNode() + if err != nil { + return s, err + } + return n.RPC().SequenceAt(ctx, account, blockNumber) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) SimulateTransaction(ctx context.Context, tx TX) error { + n, err := c.selectNode() + if err != nil { + return err + } + return n.RPC().SimulateTransaction(ctx, tx) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (s types.Subscription, err error) { + n, err := c.selectNode() + if err != nil { + return s, err + } + return n.RPC().Subscribe(ctx, channel, args...) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) TokenBalance(ctx context.Context, account ADDR, tokenAddr ADDR) (b *big.Int, err error) { + n, err := c.selectNode() + if err != nil { + return b, err + } + return n.RPC().TokenBalance(ctx, account, tokenAddr) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) TransactionByHash(ctx context.Context, txHash TX_HASH) (tx TX, err error) { + n, err := c.selectNode() + if err != nil { + return tx, err + } + return n.RPC().TransactionByHash(ctx, txHash) +} + +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) TransactionReceipt(ctx context.Context, txHash TX_HASH) (txr TX_RECEIPT, err error) { + n, err := c.selectNode() + if err != nil { + return txr, err + } + return n.RPC().TransactionReceipt(ctx, txHash) +} diff --git a/common/client/node.go b/common/client/node.go new file mode 100644 index 0000000000..71b34452f0 --- /dev/null +++ b/common/client/node.go @@ -0,0 +1,282 @@ +package client + +import ( + "context" + "fmt" + "net/url" + "sync" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" + + "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +const QueryTimeout = 10 * time.Second + +var errInvalidChainID = errors.New("invalid chain id") + +var ( + promPoolRPCNodeVerifies = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_verifies", + Help: "The total number of chain ID verifications for the given RPC node", + }, []string{"network", "chainID", "nodeName"}) + promPoolRPCNodeVerifiesFailed = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_verifies_failed", + Help: "The total number of failed chain ID verifications for the given RPC node", + }, []string{"network", "chainID", "nodeName"}) + promPoolRPCNodeVerifiesSuccess = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_verifies_success", + Help: "The total number of successful chain ID verifications for the given RPC node", + }, []string{"network", "chainID", "nodeName"}) +) + +type NodeConfig interface { + PollFailureThreshold() uint32 + PollInterval() time.Duration + SelectionMode() string + SyncThreshold() uint32 +} + +type Node[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] interface { + // State returns nodeState + State() nodeState + // StateAndLatest returns nodeState with the latest received block number & total difficulty. + StateAndLatest() (nodeState, int64, *utils.Big) + // Name is a unique identifier for this node. + Name() string + String() string + RPC() RPC + SubscribersCount() int32 + UnsubscribeAllExceptAliveLoop() + ConfiguredChainID() CHAIN_ID + Order() int32 + Start(context.Context) error + Close() error +} + +type node[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] struct { + services.StateMachine + lfcLog logger.Logger + name string + id int32 + chainID CHAIN_ID + nodePoolCfg NodeConfig + noNewHeadsThreshold time.Duration + order int32 + chainFamily string + + ws url.URL + http *url.URL + + rpc RPC + + stateMu sync.RWMutex // protects state* fields + state nodeState + // Each node is tracking the last received head number and total difficulty + stateLatestBlockNumber int64 + stateLatestTotalDifficulty *utils.Big + + // nodeCtx is the node lifetime's context + nodeCtx context.Context + // cancelNodeCtx cancels nodeCtx when stopping the node + cancelNodeCtx context.CancelFunc + // wg waits for subsidiary goroutines + wg sync.WaitGroup + + // nLiveNodes is a passed in function that allows this node to: + // 1. see how many live nodes there are in total, so we can prevent the last alive node in a pool from being + // moved to out-of-sync state. It is better to have one out-of-sync node than no nodes at all. + // 2. compare against the highest head (by number or difficulty) to ensure we don't fall behind too far. + nLiveNodes func() (count int, blockNumber int64, totalDifficulty *utils.Big) +} + +func NewNode[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +]( + nodeCfg NodeConfig, + noNewHeadsThreshold time.Duration, + lggr logger.Logger, + wsuri url.URL, + httpuri *url.URL, + name string, + id int32, + chainID CHAIN_ID, + nodeOrder int32, + rpc RPC, + chainFamily string, +) Node[CHAIN_ID, HEAD, RPC] { + n := new(node[CHAIN_ID, HEAD, RPC]) + n.name = name + n.id = id + n.chainID = chainID + n.nodePoolCfg = nodeCfg + n.noNewHeadsThreshold = noNewHeadsThreshold + n.ws = wsuri + n.order = nodeOrder + if httpuri != nil { + n.http = httpuri + } + n.nodeCtx, n.cancelNodeCtx = context.WithCancel(context.Background()) + lggr = lggr.Named("Node").With( + "nodeTier", client.Primary.String(), + "nodeName", name, + "node", n.String(), + "chainID", chainID, + "nodeOrder", n.order, + ) + n.lfcLog = lggr.Named("Lifecycle") + n.stateLatestBlockNumber = -1 + n.rpc = rpc + n.chainFamily = chainFamily + return n +} + +func (n *node[CHAIN_ID, HEAD, RPC]) String() string { + s := fmt.Sprintf("(%s)%s:%s", client.Primary.String(), n.name, n.ws.String()) + if n.http != nil { + s = s + fmt.Sprintf(":%s", n.http.String()) + } + return s +} + +func (n *node[CHAIN_ID, HEAD, RPC]) ConfiguredChainID() (chainID CHAIN_ID) { + return n.chainID +} + +func (n *node[CHAIN_ID, HEAD, RPC]) Name() string { + return n.name +} + +func (n *node[CHAIN_ID, HEAD, RPC]) RPC() RPC { + return n.rpc +} + +func (n *node[CHAIN_ID, HEAD, RPC]) SubscribersCount() int32 { + return n.rpc.SubscribersCount() +} + +func (n *node[CHAIN_ID, HEAD, RPC]) UnsubscribeAllExceptAliveLoop() { + n.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() + }() + + n.stateMu.Lock() + defer n.stateMu.Unlock() + + n.cancelNodeCtx() + n.state = nodeStateClosed + return nil + }) +} + +// Start dials and verifies the node +// Should only be called once in a node's lifecycle +// Return value is necessary to conform to interface but this will never +// actually return an error. +func (n *node[CHAIN_ID, HEAD, RPC]) Start(startCtx context.Context) error { + return n.StartOnce(n.name, func() error { + n.start(startCtx) + return nil + }) +} + +// start initially dials the node and verifies chain ID +// This spins off lifecycle goroutines. +// Not thread-safe. +// Node lifecycle is synchronous: only one goroutine should be running at a +// time. +func (n *node[CHAIN_ID, HEAD, RPC]) start(startCtx context.Context) { + if n.state != nodeStateUndialed { + panic(fmt.Sprintf("cannot dial node with state %v", n.state)) + } + + if err := n.rpc.Dial(startCtx); err != nil { + n.lfcLog.Errorw("Dial failed: Node is unreachable", "err", err) + n.declareUnreachable() + return + } + n.setState(nodeStateDialed) + + if err := n.verify(startCtx); errors.Is(err, errInvalidChainID) { + n.lfcLog.Errorw("Verify failed: Node has the wrong chain ID", "err", err) + n.declareInvalidChainID() + return + } else if err != nil { + n.lfcLog.Errorw(fmt.Sprintf("Verify failed: %v", err), "err", err) + n.declareUnreachable() + return + } + + n.declareAlive() +} + +// verify checks that all connections to eth nodes match the given chain ID +// Not thread-safe +// Pure verify: does not mutate node "state" field. +func (n *node[CHAIN_ID, HEAD, RPC]) verify(callerCtx context.Context) (err error) { + promPoolRPCNodeVerifies.WithLabelValues(n.chainFamily, n.chainID.String(), n.name).Inc() + promFailed := func() { + promPoolRPCNodeVerifiesFailed.WithLabelValues(n.chainFamily, n.chainID.String(), n.name).Inc() + } + + st := n.State() + switch st { + case nodeStateDialed, nodeStateOutOfSync, nodeStateInvalidChainID: + default: + panic(fmt.Sprintf("cannot verify node in state %v", st)) + } + + var chainID CHAIN_ID + if chainID, err = n.rpc.ChainID(callerCtx); err != nil { + promFailed() + return errors.Wrapf(err, "failed to verify chain ID for node %s", n.name) + } else if chainID.String() != n.chainID.String() { + promFailed() + return errors.Wrapf( + errInvalidChainID, + "rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s", + chainID.String(), + n.chainID.String(), + n.name, + ) + } + + promPoolRPCNodeVerifiesSuccess.WithLabelValues(n.chainFamily, n.chainID.String(), n.name).Inc() + + return nil +} + +// disconnectAll disconnects all clients connected to the node +// WARNING: NOT THREAD-SAFE +// This must be called from within the n.stateMu lock +func (n *node[CHAIN_ID, HEAD, RPC]) disconnectAll() { + n.rpc.DisconnectAll() +} + +func (n *node[CHAIN_ID, HEAD, RPC]) Order() int32 { + return n.order +} diff --git a/common/client/node_fsm.go b/common/client/node_fsm.go new file mode 100644 index 0000000000..d4fc19140e --- /dev/null +++ b/common/client/node_fsm.go @@ -0,0 +1,266 @@ +package client + +import ( + "fmt" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +var ( + promPoolRPCNodeTransitionsToAlive = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_transitions_to_alive", + Help: transitionString(nodeStateAlive), + }, []string{"chainID", "nodeName"}) + promPoolRPCNodeTransitionsToInSync = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_transitions_to_in_sync", + Help: fmt.Sprintf("%s to %s", transitionString(nodeStateOutOfSync), nodeStateAlive), + }, []string{"chainID", "nodeName"}) + promPoolRPCNodeTransitionsToOutOfSync = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_transitions_to_out_of_sync", + Help: transitionString(nodeStateOutOfSync), + }, []string{"chainID", "nodeName"}) + promPoolRPCNodeTransitionsToUnreachable = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_transitions_to_unreachable", + Help: transitionString(nodeStateUnreachable), + }, []string{"chainID", "nodeName"}) + promPoolRPCNodeTransitionsToInvalidChainID = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_transitions_to_invalid_chain_id", + Help: transitionString(nodeStateInvalidChainID), + }, []string{"chainID", "nodeName"}) + promPoolRPCNodeTransitionsToUnusable = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_transitions_to_unusable", + Help: transitionString(nodeStateUnusable), + }, []string{"chainID", "nodeName"}) +) + +// nodeState represents the current state of the node +// Node is a FSM (finite state machine) +type nodeState int + +func (n nodeState) String() string { + switch n { + case nodeStateUndialed: + return "Undialed" + case nodeStateDialed: + return "Dialed" + case nodeStateInvalidChainID: + return "InvalidChainID" + case nodeStateAlive: + return "Alive" + case nodeStateUnreachable: + return "Unreachable" + case nodeStateUnusable: + return "Unusable" + case nodeStateOutOfSync: + return "OutOfSync" + case nodeStateClosed: + return "Closed" + default: + return fmt.Sprintf("nodeState(%d)", n) + } +} + +// GoString prints a prettier state +func (n nodeState) GoString() string { + return fmt.Sprintf("nodeState%s(%d)", n.String(), n) +} + +const ( + // nodeStateUndialed is the first state of a virgin node + nodeStateUndialed = nodeState(iota) + // nodeStateDialed is after a node has successfully dialed but before it has verified the correct chain ID + nodeStateDialed + // nodeStateInvalidChainID is after chain ID verification failed + nodeStateInvalidChainID + // nodeStateAlive is a healthy node after chain ID verification succeeded + nodeStateAlive + // nodeStateUnreachable is a node that cannot be dialed or has disconnected + nodeStateUnreachable + // nodeStateOutOfSync is a node that is accepting connections but exceeded + // the failure threshold without sending any new heads. It will be + // disconnected, then put into a revive loop and re-awakened after redial + // if a new head arrives + nodeStateOutOfSync + // nodeStateUnusable is a sendonly node that has an invalid URL that can never be reached + nodeStateUnusable + // nodeStateClosed is after the connection has been closed and the node is at the end of its lifecycle + nodeStateClosed + // nodeStateLen tracks the number of states + nodeStateLen +) + +// allNodeStates represents all possible states a node can be in +var allNodeStates []nodeState + +func init() { + for s := nodeState(0); s < nodeStateLen; s++ { + allNodeStates = append(allNodeStates, s) + } +} + +// FSM methods + +// State allows reading the current state of the node. +func (n *node[CHAIN_ID, HEAD, RPC]) State() nodeState { + n.stateMu.RLock() + defer n.stateMu.RUnlock() + return n.state +} + +func (n *node[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *utils.Big) { + n.stateMu.RLock() + defer n.stateMu.RUnlock() + return n.state, n.stateLatestBlockNumber, n.stateLatestTotalDifficulty +} + +// setState is only used by internal state management methods. +// This is low-level; care should be taken by the caller to ensure the new state is a valid transition. +// State changes should always be synchronous: only one goroutine at a time should change state. +// n.stateMu should not be locked for long periods of time because external clients expect a timely response from n.State() +func (n *node[CHAIN_ID, HEAD, RPC]) setState(s nodeState) { + n.stateMu.Lock() + defer n.stateMu.Unlock() + n.state = s +} + +// declareXXX methods change the state and pass conrol off the new state +// management goroutine + +func (n *node[CHAIN_ID, HEAD, RPC]) declareAlive() { + n.transitionToAlive(func() { + n.lfcLog.Infow("RPC Node is online", "nodeState", n.state) + n.wg.Add(1) + go n.aliveLoop() + }) +} + +func (n *node[CHAIN_ID, HEAD, RPC]) transitionToAlive(fn func()) { + promPoolRPCNodeTransitionsToAlive.WithLabelValues(n.chainID.String(), n.name).Inc() + n.stateMu.Lock() + defer n.stateMu.Unlock() + if n.state == nodeStateClosed { + return + } + switch n.state { + case nodeStateDialed, nodeStateInvalidChainID: + n.state = nodeStateAlive + default: + panic(transitionFail(n.state, nodeStateAlive)) + } + fn() +} + +// declareInSync puts a node back into Alive state, allowing it to be used by +// pool consumers again +func (n *node[CHAIN_ID, HEAD, RPC]) declareInSync() { + n.transitionToInSync(func() { + n.lfcLog.Infow("RPC Node is back in sync", "nodeState", n.state) + n.wg.Add(1) + go n.aliveLoop() + }) +} + +func (n *node[CHAIN_ID, HEAD, RPC]) transitionToInSync(fn func()) { + promPoolRPCNodeTransitionsToAlive.WithLabelValues(n.chainID.String(), n.name).Inc() + promPoolRPCNodeTransitionsToInSync.WithLabelValues(n.chainID.String(), n.name).Inc() + n.stateMu.Lock() + defer n.stateMu.Unlock() + if n.state == nodeStateClosed { + return + } + switch n.state { + case nodeStateOutOfSync: + n.state = nodeStateAlive + default: + panic(transitionFail(n.state, nodeStateAlive)) + } + fn() +} + +// declareOutOfSync puts a node into OutOfSync state, disconnecting all current +// clients and making it unavailable for use until back in-sync. +func (n *node[CHAIN_ID, HEAD, RPC]) declareOutOfSync(isOutOfSync func(num int64, td *utils.Big) bool) { + n.transitionToOutOfSync(func() { + n.lfcLog.Errorw("RPC Node is out of sync", "nodeState", n.state) + n.wg.Add(1) + go n.outOfSyncLoop(isOutOfSync) + }) +} + +func (n *node[CHAIN_ID, HEAD, RPC]) transitionToOutOfSync(fn func()) { + promPoolRPCNodeTransitionsToOutOfSync.WithLabelValues(n.chainID.String(), n.name).Inc() + n.stateMu.Lock() + defer n.stateMu.Unlock() + if n.state == nodeStateClosed { + return + } + switch n.state { + case nodeStateAlive: + n.disconnectAll() + n.state = nodeStateOutOfSync + default: + panic(transitionFail(n.state, nodeStateOutOfSync)) + } + fn() +} + +func (n *node[CHAIN_ID, HEAD, RPC]) declareUnreachable() { + n.transitionToUnreachable(func() { + n.lfcLog.Errorw("RPC Node is unreachable", "nodeState", n.state) + n.wg.Add(1) + go n.unreachableLoop() + }) +} + +func (n *node[CHAIN_ID, HEAD, RPC]) transitionToUnreachable(fn func()) { + promPoolRPCNodeTransitionsToUnreachable.WithLabelValues(n.chainID.String(), n.name).Inc() + n.stateMu.Lock() + defer n.stateMu.Unlock() + if n.state == nodeStateClosed { + return + } + switch n.state { + case nodeStateUndialed, nodeStateDialed, nodeStateAlive, nodeStateOutOfSync, nodeStateInvalidChainID: + n.disconnectAll() + n.state = nodeStateUnreachable + default: + panic(transitionFail(n.state, nodeStateUnreachable)) + } + fn() +} + +func (n *node[CHAIN_ID, HEAD, RPC]) declareInvalidChainID() { + n.transitionToInvalidChainID(func() { + n.lfcLog.Errorw("RPC Node has the wrong chain ID", "nodeState", n.state) + n.wg.Add(1) + go n.invalidChainIDLoop() + }) +} + +func (n *node[CHAIN_ID, HEAD, RPC]) transitionToInvalidChainID(fn func()) { + promPoolRPCNodeTransitionsToInvalidChainID.WithLabelValues(n.chainID.String(), n.name).Inc() + n.stateMu.Lock() + defer n.stateMu.Unlock() + if n.state == nodeStateClosed { + return + } + switch n.state { + case nodeStateDialed, nodeStateOutOfSync: + n.disconnectAll() + n.state = nodeStateInvalidChainID + default: + panic(transitionFail(n.state, nodeStateInvalidChainID)) + } + fn() +} + +func transitionString(state nodeState) string { + return fmt.Sprintf("Total number of times node has transitioned to %s", state) +} + +func transitionFail(from nodeState, to nodeState) string { + return fmt.Sprintf("cannot transition from %#v to %#v", from, to) +} diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go new file mode 100644 index 0000000000..149c5f01a6 --- /dev/null +++ b/common/client/node_lifecycle.go @@ -0,0 +1,431 @@ +package client + +import ( + "context" + "fmt" + "math" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +var ( + promPoolRPCNodeHighestSeenBlock = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pool_rpc_node_highest_seen_block", + Help: "The highest seen block for the given RPC node", + }, []string{"chainID", "nodeName"}) + promPoolRPCNodeNumSeenBlocks = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_seen_blocks", + Help: "The total number of new blocks seen by the given RPC node", + }, []string{"chainID", "nodeName"}) + promPoolRPCNodePolls = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_polls_total", + Help: "The total number of poll checks for the given RPC node", + }, []string{"chainID", "nodeName"}) + promPoolRPCNodePollsFailed = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_polls_failed", + Help: "The total number of failed poll checks for the given RPC node", + }, []string{"chainID", "nodeName"}) + promPoolRPCNodePollsSuccess = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_polls_success", + Help: "The total number of successful poll checks for the given RPC node", + }, []string{"chainID", "nodeName"}) +) + +// zombieNodeCheckInterval controls how often to re-check to see if we need to +// state change in case we have to force a state transition due to no available +// nodes. +// NOTE: This only applies to out-of-sync nodes if they are the last available node +func zombieNodeCheckInterval(noNewHeadsThreshold time.Duration) time.Duration { + interval := noNewHeadsThreshold + if interval <= 0 || interval > QueryTimeout { + interval = QueryTimeout + } + return utils.WithJitter(interval) +} + +func (n *node[CHAIN_ID, HEAD, RPC]) setLatestReceived(blockNumber int64, totalDifficulty *utils.Big) { + n.stateMu.Lock() + defer n.stateMu.Unlock() + n.stateLatestBlockNumber = blockNumber + n.stateLatestTotalDifficulty = totalDifficulty +} + +const ( + msgCannotDisable = "but cannot disable this connection because there are no other RPC endpoints, or all other RPC endpoints are dead." + msgDegradedState = "Chainlink is now operating in a degraded state and urgent action is required to resolve the issue" +) + +// 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. +// Each loop passes control onto the next loop as it exits, except when the node is Closed which terminates the loop permanently. + +// This handles node lifecycle for the ALIVE state +// Should only be run ONCE per node, after a successful Dial +func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { + defer n.wg.Done() + + { + // sanity check + state := n.State() + switch state { + case nodeStateAlive: + case nodeStateClosed: + return + default: + panic(fmt.Sprintf("aliveLoop can only run for node in Alive state, got: %s", state)) + } + } + + noNewHeadsTimeoutThreshold := n.noNewHeadsThreshold + pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() + pollInterval := n.nodePoolCfg.PollInterval() + + lggr := n.lfcLog.Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) + lggr.Tracew("Alive loop starting", "nodeState", n.State()) + + headsC := make(chan HEAD) + sub, err := n.rpc.Subscribe(n.nodeCtx, headsC, "newHeads") + if err != nil { + lggr.Errorw("Initial subscribe for heads failed", "nodeState", n.State()) + n.declareUnreachable() + return + } + n.rpc.SetAliveLoopSub(sub) + defer sub.Unsubscribe() + + var outOfSyncT *time.Ticker + var outOfSyncTC <-chan time.Time + if noNewHeadsTimeoutThreshold > 0 { + lggr.Debugw("Head liveness checking enabled", "nodeState", n.State()) + outOfSyncT = time.NewTicker(noNewHeadsTimeoutThreshold) + defer outOfSyncT.Stop() + outOfSyncTC = outOfSyncT.C + } else { + lggr.Debug("Head liveness checking disabled") + } + + var pollCh <-chan time.Time + if pollInterval > 0 { + lggr.Debug("Polling enabled") + pollT := time.NewTicker(pollInterval) + defer pollT.Stop() + pollCh = pollT.C + if pollFailureThreshold > 0 { + // polling can be enabled with no threshold to enable polling but + // the node will not be marked offline regardless of the number of + // poll failures + lggr.Debug("Polling liveness checking enabled") + } + } else { + lggr.Debug("Polling disabled") + } + + _, highestReceivedBlockNumber, _ := n.StateAndLatest() + var pollFailures uint32 + + for { + select { + case <-n.nodeCtx.Done(): + return + case <-pollCh: + var version string + promPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() + lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + ctx, cancel := context.WithTimeout(n.nodeCtx, pollInterval) + version, err := n.RPC().ClientVersion(ctx) + cancel() + if err != nil { + // prevent overflow + if pollFailures < math.MaxUint32 { + promPoolRPCNodePollsFailed.WithLabelValues(n.chainID.String(), n.name).Inc() + pollFailures++ + } + lggr.Warnw(fmt.Sprintf("Poll failure, RPC endpoint %s failed to respond properly", n.String()), "err", err, "pollFailures", pollFailures, "nodeState", n.State()) + } else { + lggr.Debugw("Version poll successful", "nodeState", n.State(), "clientVersion", version) + promPoolRPCNodePollsSuccess.WithLabelValues(n.chainID.String(), n.name).Inc() + pollFailures = 0 + } + if pollFailureThreshold > 0 && pollFailures >= pollFailureThreshold { + lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) + if n.nLiveNodes != nil { + if l, _, _ := n.nLiveNodes(); l < 2 { + lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) + continue + } + } + n.declareUnreachable() + return + } + _, num, td := n.StateAndLatest() + if outOfSync, liveNodes := n.syncStatus(num, td); outOfSync { + // note: there must be another live node for us to be out of sync + lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) + if liveNodes < 2 { + lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) + continue + } + n.declareOutOfSync(n.isOutOfSync) + return + } + case bh, open := <-headsC: + if !open { + lggr.Errorw("Subscription channel unexpectedly closed", "nodeState", n.State()) + n.declareUnreachable() + return + } + promPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() + lggr.Tracew("Got head", "head", bh) + if bh.BlockNumber() > highestReceivedBlockNumber { + promPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.BlockNumber())) + lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + highestReceivedBlockNumber = bh.BlockNumber() + } else { + lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + } + if outOfSyncT != nil { + outOfSyncT.Reset(noNewHeadsTimeoutThreshold) + } + n.setLatestReceived(bh.BlockNumber(), bh.BlockDifficulty()) + case err := <-sub.Err(): + lggr.Errorw("Subscription was terminated", "err", err, "nodeState", n.State()) + n.declareUnreachable() + return + case <-outOfSyncTC: + // We haven't received a head on the channel for at least the + // threshold amount of time, mark it broken + lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) + if n.nLiveNodes != nil { + if l, _, _ := n.nLiveNodes(); l < 2 { + lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) + // We don't necessarily want to wait the full timeout to check again, we should + // check regularly and log noisily in this state + outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) + continue + } + } + n.declareOutOfSync(func(num int64, td *utils.Big) bool { return num < highestReceivedBlockNumber }) + return + } + } +} + +func (n *node[CHAIN_ID, HEAD, RPC]) isOutOfSync(num int64, td *utils.Big) (outOfSync bool) { + outOfSync, _ = n.syncStatus(num, td) + return +} + +// syncStatus returns outOfSync true if num or td is more than SyncThresold behind the best node. +// Always returns outOfSync false for SyncThreshold 0. +// liveNodes is only included when outOfSync is true. +func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *utils.Big) (outOfSync bool, liveNodes int) { + if n.nLiveNodes == nil { + return // skip for tests + } + threshold := n.nodePoolCfg.SyncThreshold() + if threshold == 0 { + return // disabled + } + // Check against best node + ln, highest, greatest := n.nLiveNodes() + mode := n.nodePoolCfg.SelectionMode() + switch mode { + case NodeSelectionModeHighestHead, NodeSelectionModeRoundRobin, NodeSelectionModePriorityLevel: + return num < highest-int64(threshold), ln + case NodeSelectionModeTotalDifficulty: + bigThreshold := utils.NewBigI(int64(threshold)) + return td.Cmp(greatest.Sub(bigThreshold)) < 0, ln + default: + panic("unrecognized NodeSelectionMode: " + mode) + } +} + +const ( + msgReceivedBlock = "Received block for RPC node, waiting until back in-sync to mark as live again" + msgInSync = "RPC node back in sync" +) + +// outOfSyncLoop takes an OutOfSync node and waits until isOutOfSync returns false to go back to live status +func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td *utils.Big) bool) { + defer n.wg.Done() + + { + // sanity check + state := n.State() + switch state { + case nodeStateOutOfSync: + case nodeStateClosed: + return + default: + panic(fmt.Sprintf("outOfSyncLoop can only run for node in OutOfSync state, got: %s", state)) + } + } + + outOfSyncAt := time.Now() + + lggr := n.lfcLog.Named("OutOfSync") + lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) + + // Need to redial since out-of-sync nodes are automatically disconnected + if err := n.rpc.Dial(n.nodeCtx); err != nil { + lggr.Errorw("Failed to dial out-of-sync RPC node", "nodeState", n.State()) + n.declareUnreachable() + return + } + + // Manually re-verify since out-of-sync nodes are automatically disconnected + if err := n.verify(n.nodeCtx); err != nil { + lggr.Errorw(fmt.Sprintf("Failed to verify out-of-sync RPC node: %v", err), "err", err) + n.declareInvalidChainID() + return + } + + 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") + if err != nil { + lggr.Errorw("Failed to subscribe heads on out-of-sync RPC node", "nodeState", n.State(), "err", err) + n.declareUnreachable() + return + } + defer sub.Unsubscribe() + + for { + select { + case <-n.nodeCtx.Done(): + return + case head, open := <-ch: + if !open { + lggr.Error("Subscription channel unexpectedly closed", "nodeState", n.State()) + n.declareUnreachable() + return + } + 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()) + n.declareInSync() + return + } + lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "totalDifficulty", "nodeState", n.State()) + case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): + if n.nLiveNodes != nil { + if l, _, _ := n.nLiveNodes(); l < 1 { + lggr.Critical("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") + n.declareInSync() + return + } + } + case err := <-sub.Err(): + lggr.Errorw("Subscription was terminated", "nodeState", n.State(), "err", err) + n.declareUnreachable() + return + } + } +} + +func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { + defer n.wg.Done() + + { + // sanity check + state := n.State() + switch state { + case nodeStateUnreachable: + case nodeStateClosed: + return + default: + panic(fmt.Sprintf("unreachableLoop can only run for node in Unreachable state, got: %s", state)) + } + } + + unreachableAt := time.Now() + + lggr := n.lfcLog.Named("Unreachable") + lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) + + dialRetryBackoff := utils.NewRedialBackoff() + + for { + select { + case <-n.nodeCtx.Done(): + return + case <-time.After(dialRetryBackoff.Duration()): + lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) + + err := n.rpc.Dial(n.nodeCtx) + if err != nil { + lggr.Errorw(fmt.Sprintf("Failed to redial RPC node; still unreachable: %v", err), "err", err, "nodeState", n.State()) + continue + } + + n.setState(nodeStateDialed) + + err = n.verify(n.nodeCtx) + + if errors.Is(err, errInvalidChainID) { + lggr.Errorw("Failed to redial RPC node; remote endpoint returned the wrong chain ID", "err", err) + n.declareInvalidChainID() + return + } else if err != nil { + lggr.Errorw(fmt.Sprintf("Failed to redial RPC node; verify failed: %v", err), "err", err) + n.declareUnreachable() + return + } + + lggr.Infow(fmt.Sprintf("Successfully redialled and verified RPC node %s. Node was offline for %s", n.String(), time.Since(unreachableAt)), "nodeState", n.State()) + n.declareAlive() + return + } + } +} + +func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { + defer n.wg.Done() + + { + // sanity check + state := n.State() + switch state { + case nodeStateInvalidChainID: + case nodeStateClosed: + return + default: + panic(fmt.Sprintf("invalidChainIDLoop can only run for node in InvalidChainID state, got: %s", state)) + } + } + + invalidAt := time.Now() + + lggr := n.lfcLog.Named("InvalidChainID") + lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.State()) + + chainIDRecheckBackoff := utils.NewRedialBackoff() + + for { + select { + case <-n.nodeCtx.Done(): + return + case <-time.After(chainIDRecheckBackoff.Duration()): + err := n.verify(n.nodeCtx) + if errors.Is(err, errInvalidChainID) { + lggr.Errorw("Failed to verify RPC node; remote endpoint returned the wrong chain ID", "err", err) + continue + } else if err != nil { + lggr.Errorw(fmt.Sprintf("Unexpected error while verifying RPC node chain ID; %v", err), "err", err) + n.declareUnreachable() + return + } + lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was offline for %s", time.Since(invalidAt)), "nodeState", n.State()) + n.declareAlive() + return + } + } +} diff --git a/common/client/node_selector_highest_head.go b/common/client/node_selector_highest_head.go new file mode 100644 index 0000000000..99a130004a --- /dev/null +++ b/common/client/node_selector_highest_head.go @@ -0,0 +1,41 @@ +package client + +import ( + "math" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +type highestHeadNodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] []Node[CHAIN_ID, HEAD, RPC] + +func NewHighestHeadNodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](nodes []Node[CHAIN_ID, HEAD, RPC]) NodeSelector[CHAIN_ID, HEAD, RPC] { + return highestHeadNodeSelector[CHAIN_ID, HEAD, RPC](nodes) +} + +func (s highestHeadNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { + var highestHeadNumber int64 = math.MinInt64 + var highestHeadNodes []Node[CHAIN_ID, HEAD, RPC] + for _, n := range s { + state, currentHeadNumber, _ := n.StateAndLatest() + if state == nodeStateAlive && currentHeadNumber >= highestHeadNumber { + if highestHeadNumber < currentHeadNumber { + highestHeadNumber = currentHeadNumber + highestHeadNodes = nil + } + highestHeadNodes = append(highestHeadNodes, n) + } + } + return firstOrHighestPriority(highestHeadNodes) +} + +func (s highestHeadNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { + return NodeSelectionModeHighestHead +} diff --git a/common/client/node_selector_priority_level.go b/common/client/node_selector_priority_level.go new file mode 100644 index 0000000000..45cc62de07 --- /dev/null +++ b/common/client/node_selector_priority_level.go @@ -0,0 +1,129 @@ +package client + +import ( + "math" + "sort" + "sync/atomic" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +type priorityLevelNodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] struct { + nodes []Node[CHAIN_ID, HEAD, RPC] + roundRobinCount []atomic.Uint32 +} + +type nodeWithPriority[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] struct { + node Node[CHAIN_ID, HEAD, RPC] + priority int32 +} + +func NewPriorityLevelNodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](nodes []Node[CHAIN_ID, HEAD, RPC]) NodeSelector[CHAIN_ID, HEAD, RPC] { + return &priorityLevelNodeSelector[CHAIN_ID, HEAD, RPC]{ + nodes: nodes, + roundRobinCount: make([]atomic.Uint32, nrOfPriorityTiers(nodes)), + } +} + +func (s priorityLevelNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { + nodes := s.getHighestPriorityAliveTier() + + if len(nodes) == 0 { + return nil + } + priorityLevel := nodes[len(nodes)-1].priority + + // NOTE: Inc returns the number after addition, so we must -1 to get the "current" counter + count := s.roundRobinCount[priorityLevel].Add(1) - 1 + idx := int(count % uint32(len(nodes))) + + return nodes[idx].node +} + +func (s priorityLevelNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { + return NodeSelectionModePriorityLevel +} + +// getHighestPriorityAliveTier filters nodes that are not in state nodeStateAlive and +// returns only the highest tier of alive nodes +func (s priorityLevelNodeSelector[CHAIN_ID, HEAD, RPC]) getHighestPriorityAliveTier() []nodeWithPriority[CHAIN_ID, HEAD, RPC] { + var nodes []nodeWithPriority[CHAIN_ID, HEAD, RPC] + for _, n := range s.nodes { + if n.State() == nodeStateAlive { + nodes = append(nodes, nodeWithPriority[CHAIN_ID, HEAD, RPC]{n, n.Order()}) + } + } + + if len(nodes) == 0 { + return nil + } + + return removeLowerTiers(nodes) +} + +// removeLowerTiers take a slice of nodeWithPriority[CHAIN_ID, BLOCK_HASH, HEAD, RPC] and keeps only the highest tier +func removeLowerTiers[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](nodes []nodeWithPriority[CHAIN_ID, HEAD, RPC]) []nodeWithPriority[CHAIN_ID, HEAD, RPC] { + sort.SliceStable(nodes, func(i, j int) bool { + return nodes[i].priority > nodes[j].priority + }) + + var nodes2 []nodeWithPriority[CHAIN_ID, HEAD, RPC] + currentPriority := nodes[len(nodes)-1].priority + + for _, n := range nodes { + if n.priority == currentPriority { + nodes2 = append(nodes2, n) + } + } + + return nodes2 +} + +// nrOfPriorityTiers calculates the total number of priority tiers +func nrOfPriorityTiers[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](nodes []Node[CHAIN_ID, HEAD, RPC]) int32 { + highestPriority := int32(0) + for _, n := range nodes { + priority := n.Order() + if highestPriority < priority { + highestPriority = priority + } + } + return highestPriority + 1 +} + +// firstOrHighestPriority takes a list of nodes and returns the first one with the highest priority +func firstOrHighestPriority[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](nodes []Node[CHAIN_ID, HEAD, RPC]) Node[CHAIN_ID, HEAD, RPC] { + hp := int32(math.MaxInt32) + var node Node[CHAIN_ID, HEAD, RPC] + for _, n := range nodes { + if n.Order() < hp { + hp = n.Order() + node = n + } + } + return node +} diff --git a/common/client/node_selector_round_robin.go b/common/client/node_selector_round_robin.go new file mode 100644 index 0000000000..5cdad7f52e --- /dev/null +++ b/common/client/node_selector_round_robin.go @@ -0,0 +1,50 @@ +package client + +import ( + "sync/atomic" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +type roundRobinSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] struct { + nodes []Node[CHAIN_ID, HEAD, RPC] + roundRobinCount atomic.Uint32 +} + +func NewRoundRobinSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](nodes []Node[CHAIN_ID, HEAD, RPC]) NodeSelector[CHAIN_ID, HEAD, RPC] { + return &roundRobinSelector[CHAIN_ID, HEAD, RPC]{ + nodes: nodes, + } +} + +func (s *roundRobinSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { + var liveNodes []Node[CHAIN_ID, HEAD, RPC] + for _, n := range s.nodes { + if n.State() == nodeStateAlive { + liveNodes = append(liveNodes, n) + } + } + + nNodes := len(liveNodes) + if nNodes == 0 { + return nil + } + + // NOTE: Inc returns the number after addition, so we must -1 to get the "current" counter + count := s.roundRobinCount.Add(1) - 1 + idx := int(count % uint32(nNodes)) + + return liveNodes[idx] +} + +func (s *roundRobinSelector[CHAIN_ID, HEAD, RPC]) Name() string { + return NodeSelectionModeRoundRobin +} diff --git a/common/client/node_selector_total_difficulty.go b/common/client/node_selector_total_difficulty.go new file mode 100644 index 0000000000..9b29642d03 --- /dev/null +++ b/common/client/node_selector_total_difficulty.go @@ -0,0 +1,54 @@ +package client + +import ( + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +type totalDifficultyNodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] []Node[CHAIN_ID, HEAD, RPC] + +func NewTotalDifficultyNodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](nodes []Node[CHAIN_ID, HEAD, RPC]) NodeSelector[CHAIN_ID, HEAD, RPC] { + return totalDifficultyNodeSelector[CHAIN_ID, HEAD, RPC](nodes) +} + +func (s totalDifficultyNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { + // NodeNoNewHeadsThreshold may not be enabled, in this case all nodes have td == nil + var highestTD *utils.Big + var nodes []Node[CHAIN_ID, HEAD, RPC] + var aliveNodes []Node[CHAIN_ID, HEAD, RPC] + + for _, n := range s { + state, _, currentTD := n.StateAndLatest() + if state != nodeStateAlive { + continue + } + + aliveNodes = append(aliveNodes, n) + if currentTD != nil && (highestTD == nil || currentTD.Cmp(highestTD) >= 0) { + if highestTD == nil || currentTD.Cmp(highestTD) > 0 { + highestTD = currentTD + nodes = nil + } + nodes = append(nodes, n) + } + } + + //If all nodes have td == nil pick one from the nodes that are alive + if len(nodes) == 0 { + return firstOrHighestPriority(aliveNodes) + } + return firstOrHighestPriority(nodes) +} + +func (s totalDifficultyNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { + return NodeSelectionModeTotalDifficulty +} diff --git a/common/client/send_only_node.go b/common/client/send_only_node.go new file mode 100644 index 0000000000..3b382b2dcb --- /dev/null +++ b/common/client/send_only_node.go @@ -0,0 +1,183 @@ +package client + +import ( + "context" + "fmt" + "net/url" + "sync" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" + + "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type sendOnlyClient[ + CHAIN_ID types.ID, +] interface { + Close() + ChainID(context.Context) (CHAIN_ID, error) + DialHTTP() error +} + +// SendOnlyNode represents one node used as a sendonly +type SendOnlyNode[ + CHAIN_ID types.ID, + RPC sendOnlyClient[CHAIN_ID], +] interface { + // Start may attempt to connect to the node, but should only return error for misconfiguration - never for temporary errors. + Start(context.Context) error + Close() error + + ConfiguredChainID() CHAIN_ID + RPC() RPC + + String() string + // State returns nodeState + State() nodeState + // Name is a unique identifier for this node. + Name() string +} + +// It only supports sending transactions +// It must use an http(s) url +type sendOnlyNode[ + CHAIN_ID types.ID, + RPC sendOnlyClient[CHAIN_ID], +] struct { + services.StateMachine + + stateMu sync.RWMutex // protects state* fields + state nodeState + + rpc RPC + uri url.URL + log logger.Logger + name string + chainID CHAIN_ID + chStop utils.StopChan + wg sync.WaitGroup +} + +// NewSendOnlyNode returns a new sendonly node +func NewSendOnlyNode[ + CHAIN_ID types.ID, + RPC sendOnlyClient[CHAIN_ID], +]( + lggr logger.Logger, + httpuri url.URL, + name string, + chainID CHAIN_ID, + rpc RPC, +) SendOnlyNode[CHAIN_ID, RPC] { + s := new(sendOnlyNode[CHAIN_ID, RPC]) + s.name = name + s.log = lggr.Named("SendOnlyNode").Named(name).With( + "nodeTier", "sendonly", + ) + s.rpc = rpc + s.uri = httpuri + s.chainID = chainID + s.chStop = make(chan struct{}) + return s +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) Start(ctx context.Context) error { + return s.StartOnce(s.name, func() error { + s.start(ctx) + return nil + }) +} + +// Start setups up and verifies the sendonly node +// Should only be called once in a node's lifecycle +func (s *sendOnlyNode[CHAIN_ID, RPC]) start(startCtx context.Context) { + if s.State() != nodeStateUndialed { + panic(fmt.Sprintf("cannot dial node with state %v", s.state)) + } + + err := s.rpc.DialHTTP() + if err != nil { + promPoolRPCNodeTransitionsToUnusable.WithLabelValues(s.chainID.String(), s.name).Inc() + s.log.Errorw("Dial failed: SendOnly Node is unusable", "err", err) + s.setState(nodeStateUnusable) + return + } + s.setState(nodeStateDialed) + + if s.chainID.String() == "0" { + // Skip verification if chainID is zero + s.log.Warn("sendonly rpc ChainID verification skipped") + } else { + chainID, err := s.rpc.ChainID(startCtx) + if err != nil || chainID.String() != s.chainID.String() { + promPoolRPCNodeTransitionsToUnreachable.WithLabelValues(s.chainID.String(), s.name).Inc() + if err != nil { + promPoolRPCNodeTransitionsToUnreachable.WithLabelValues(s.chainID.String(), s.name).Inc() + s.log.Errorw(fmt.Sprintf("Verify failed: %v", err), "err", err) + s.setState(nodeStateUnreachable) + } else { + promPoolRPCNodeTransitionsToInvalidChainID.WithLabelValues(s.chainID.String(), s.name).Inc() + s.log.Errorf( + "sendonly rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s", + chainID.String(), + s.chainID.String(), + s.name, + ) + s.setState(nodeStateInvalidChainID) + } + // Since it has failed, spin up the verifyLoop that will keep + // retrying until success + s.wg.Add(1) + go s.verifyLoop() + return + } + } + + promPoolRPCNodeTransitionsToAlive.WithLabelValues(s.chainID.String(), s.name).Inc() + s.setState(nodeStateAlive) + s.log.Infow("Sendonly RPC Node is online", "nodeState", s.state) +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) Close() error { + return s.StopOnce(s.name, func() error { + s.rpc.Close() + s.wg.Wait() + s.setState(nodeStateClosed) + return nil + }) +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) ConfiguredChainID() CHAIN_ID { + return s.chainID +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) RPC() RPC { + return s.rpc +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) String() string { + return fmt.Sprintf("(%s)%s:%s", client.Secondary.String(), s.name, s.uri.Redacted()) +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) setState(state nodeState) (changed bool) { + s.stateMu.Lock() + defer s.stateMu.Unlock() + if s.state == state { + return false + } + s.state = state + return true +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) State() nodeState { + s.stateMu.RLock() + defer s.stateMu.RUnlock() + return s.state +} + +func (s *sendOnlyNode[CHAIN_ID, RPC]) Name() string { + return s.name +} diff --git a/common/client/send_only_node_lifecycle.go b/common/client/send_only_node_lifecycle.go new file mode 100644 index 0000000000..0f663eab30 --- /dev/null +++ b/common/client/send_only_node_lifecycle.go @@ -0,0 +1,66 @@ +package client + +import ( + "context" + "fmt" + "time" + + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +// verifyLoop may only be triggered once, on Start, if initial chain ID check +// fails. +// +// It will continue checking until success and then exit permanently. +func (s *sendOnlyNode[CHAIN_ID, RPC]) verifyLoop() { + defer s.wg.Done() + + backoff := utils.NewRedialBackoff() + for { + select { + case <-s.chStop: + return + case <-time.After(backoff.Duration()): + } + chainID, err := s.rpc.ChainID(context.Background()) + if err != nil { + ok := s.IfStarted(func() { + if changed := s.setState(nodeStateUnreachable); changed { + promPoolRPCNodeTransitionsToUnreachable.WithLabelValues(s.chainID.String(), s.name).Inc() + } + }) + if !ok { + return + } + s.log.Errorw(fmt.Sprintf("Verify failed: %v", err), "err", err) + continue + } else if chainID.String() != s.chainID.String() { + ok := s.IfStarted(func() { + if changed := s.setState(nodeStateInvalidChainID); changed { + promPoolRPCNodeTransitionsToInvalidChainID.WithLabelValues(s.chainID.String(), s.name).Inc() + } + }) + if !ok { + return + } + s.log.Errorf( + "sendonly rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s", + chainID.String(), + s.chainID.String(), + s.name, + ) + + continue + } + ok := s.IfStarted(func() { + if changed := s.setState(nodeStateAlive); changed { + promPoolRPCNodeTransitionsToAlive.WithLabelValues(s.chainID.String(), s.name).Inc() + } + }) + if !ok { + return + } + s.log.Infow("Sendonly RPC Node is online", "nodeState", s.state) + return + } +} diff --git a/common/client/types.go b/common/client/types.go new file mode 100644 index 0000000000..f3a6029a9e --- /dev/null +++ b/common/client/types.go @@ -0,0 +1,133 @@ +package client + +import ( + "context" + "math/big" + + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +// RPC includes all the necessary methods for a multi-node client to interact directly with any RPC endpoint. +type RPC[ + CHAIN_ID types.ID, + SEQ types.Sequence, + ADDR types.Hashable, + BLOCK_HASH types.Hashable, + TX any, + TX_HASH types.Hashable, + EVENT any, + EVENT_OPS any, + TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], + FEE feetypes.Fee, + HEAD types.Head[BLOCK_HASH], + +] interface { + NodeClient[ + CHAIN_ID, + HEAD, + ] + clientAPI[ + CHAIN_ID, + SEQ, + ADDR, + BLOCK_HASH, + TX, + TX_HASH, + EVENT, + EVENT_OPS, + TX_RECEIPT, + FEE, + HEAD, + ] +} + +// Head is the interface required by the NodeClient +type Head interface { + BlockNumber() int64 + BlockDifficulty() *utils.Big +} + +// NodeClient includes all the necessary RPC methods required by a node. +type NodeClient[ + CHAIN_ID types.ID, + HEAD Head, +] interface { + connection[CHAIN_ID, HEAD] + + DialHTTP() error + DisconnectAll() + Close() + ClientVersion(context.Context) (string, error) + SubscribersCount() int32 + SetAliveLoopSub(types.Subscription) + UnsubscribeAllExceptAliveLoop() +} + +// clientAPI includes all the direct RPC methods required by the generalized common client to implement its own. +type clientAPI[ + CHAIN_ID types.ID, + SEQ types.Sequence, + ADDR types.Hashable, + BLOCK_HASH types.Hashable, + TX any, + TX_HASH types.Hashable, + EVENT any, + EVENT_OPS any, // event filter query options + TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], + FEE feetypes.Fee, + HEAD types.Head[BLOCK_HASH], +] interface { + connection[CHAIN_ID, HEAD] + + // Account + BalanceAt(ctx context.Context, accountAddress ADDR, blockNumber *big.Int) (*big.Int, error) + TokenBalance(ctx context.Context, accountAddress ADDR, tokenAddress ADDR) (*big.Int, error) + SequenceAt(ctx context.Context, accountAddress ADDR, blockNumber *big.Int) (SEQ, error) + LINKBalance(ctx context.Context, accountAddress ADDR, linkAddress ADDR) (*assets.Link, error) + PendingSequenceAt(ctx context.Context, addr ADDR) (SEQ, error) + EstimateGas(ctx context.Context, call any) (gas uint64, err error) + + // Transactions + SendTransaction(ctx context.Context, tx TX) error + SimulateTransaction(ctx context.Context, tx TX) error + TransactionByHash(ctx context.Context, txHash TX_HASH) (TX, error) + TransactionReceipt(ctx context.Context, txHash TX_HASH) (TX_RECEIPT, error) + SendEmptyTransaction( + ctx context.Context, + newTxAttempt func(seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (attempt any, err error), + seq SEQ, + gasLimit uint32, + fee FEE, + fromAddress ADDR, + ) (txhash string, err error) + + // Blocks + BlockByNumber(ctx context.Context, number *big.Int) (HEAD, error) + BlockByHash(ctx context.Context, hash BLOCK_HASH) (HEAD, error) + LatestBlockHeight(context.Context) (*big.Int, error) + + // Events + FilterEvents(ctx context.Context, query EVENT_OPS) ([]EVENT, error) + + // Misc + BatchCallContext(ctx context.Context, b []any) error + CallContract( + ctx context.Context, + msg interface{}, + blockNumber *big.Int, + ) (rpcErr []byte, extractErr error) + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error + CodeAt(ctx context.Context, account ADDR, blockNumber *big.Int) ([]byte, error) +} + +type connection[ + CHAIN_ID types.ID, + HEAD Head, +] interface { + ChainID(ctx context.Context) (CHAIN_ID, error) + Dial(ctx context.Context) error + Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (types.Subscription, error) +} diff --git a/common/headtracker/types/mocks/head.go b/common/headtracker/types/mocks/head.go index edda18d57e..a56590b6ef 100644 --- a/common/headtracker/types/mocks/head.go +++ b/common/headtracker/types/mocks/head.go @@ -4,6 +4,7 @@ package mocks import ( types "github.com/smartcontractkit/chainlink/v2/common/types" + utils "github.com/smartcontractkit/chainlink/v2/core/utils" mock "github.com/stretchr/testify/mock" ) @@ -12,6 +13,22 @@ type Head[BLOCK_HASH types.Hashable, CHAIN_ID types.ID] struct { mock.Mock } +// BlockDifficulty provides a mock function with given fields: +func (_m *Head[BLOCK_HASH, CHAIN_ID]) 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 +} + // BlockHash provides a mock function with given fields: func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockHash() BLOCK_HASH { ret := _m.Called() diff --git a/common/types/head.go b/common/types/head.go index 4d339b1cdd..bef9c30d9e 100644 --- a/common/types/head.go +++ b/common/types/head.go @@ -1,5 +1,7 @@ package types +import "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. // @@ -24,4 +26,8 @@ type Head[BLOCK_HASH Hashable] interface { // HashAtHeight returns the hash of the block at the given height, if it is in the chain. // If not in chain, returns the zero hash HashAtHeight(blockNum int64) BLOCK_HASH + + // Returns the total difficulty of the block. For chains who do not have a concept of block + // difficulty, return 0. + BlockDifficulty() *utils.Big } diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index 3cb303ef26..816a9234a3 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -4,6 +4,7 @@ package mocks import ( types "github.com/smartcontractkit/chainlink/v2/common/types" + utils "github.com/smartcontractkit/chainlink/v2/core/utils" mock "github.com/stretchr/testify/mock" ) @@ -12,6 +13,22 @@ type Head[BLOCK_HASH types.Hashable] struct { mock.Mock } +// BlockDifficulty provides a mock function with given fields: +func (_m *Head[BLOCK_HASH]) 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 +} + // BlockHash provides a mock function with given fields: func (_m *Head[BLOCK_HASH]) BlockHash() BLOCK_HASH { ret := _m.Called() diff --git a/common/types/receipt.go b/common/types/receipt.go new file mode 100644 index 0000000000..01d5a72def --- /dev/null +++ b/common/types/receipt.go @@ -0,0 +1,14 @@ +package types + +import "math/big" + +type Receipt[TX_HASH Hashable, BLOCK_HASH Hashable] interface { + GetStatus() uint64 + GetTxHash() TX_HASH + GetBlockNumber() *big.Int + IsZero() bool + IsUnmined() bool + GetFeeUsed() uint64 + GetTransactionIndex() uint + GetBlockHash() BLOCK_HASH +} diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index 6eed13271e..936abc6216 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -498,3 +498,21 @@ func newPrimary(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr return evmclient.NewNode(cfg, noNewHeadsThreshold, lggr, (url.URL)(*n.WSURL), (*url.URL)(n.HTTPURL), *n.Name, id, chainID, *n.Order), nil } + +// TODO-1663: replace newEthClientFromChain with the function below once client.go is deprecated. +//func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType config.ChainType, nodes []*toml.Node) evmclient.Client { +// var empty url.URL +// var primaries []commonclient.Node[*big.Int, *evmtypes.Head, evmclient.RPCCLient] +// var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient] +// for i, node := range nodes { +// if node.SendOnly != nil && *node.SendOnly { +// rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), fmt.Sprintf("eth-sendonly-rpc-%d", i), int32(i), chainID, commontypes.Primary) +// sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCCLient](lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID, rpc) +// sendonlys = append(sendonlys, sendonly) +// } else { +// rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), fmt.Sprintf("eth-sendonly-rpc-%d", i), int32(i), chainID, commontypes.Primary) +// primaries = append(primaries, commonclient.NewNode[*big.Int, *evmtypes.Head, evmclient.RPCCLient](cfg, noNewHeadsThreshold, lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order, rpc, "EVM")) +// } +// } +// return evmclient.NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) +//} diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go new file mode 100644 index 0000000000..bda028cbf3 --- /dev/null +++ b/core/chains/evm/client/chain_client.go @@ -0,0 +1,274 @@ +package client + +import ( + "context" + "math/big" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" + + commontypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + "github.com/smartcontractkit/chainlink/v2/core/assets" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +var _ Client = (*chainClient)(nil) + +// TODO-1663: rename this to client, once the client.go file is deprecated. +type chainClient struct { + multiNode commonclient.MultiNode[ + *big.Int, + evmtypes.Nonce, + common.Address, + common.Hash, + *types.Transaction, + common.Hash, + types.Log, + ethereum.FilterQuery, + *evmtypes.Receipt, + *assets.Wei, + *evmtypes.Head, + RPCCLient, + ] + logger logger.Logger +} + +func NewChainClient( + logger logger.Logger, + selectionMode string, + leaseDuration time.Duration, + noNewHeadsThreshold time.Duration, + nodes []commonclient.Node[*big.Int, *evmtypes.Head, RPCCLient], + sendonlys []commonclient.SendOnlyNode[*big.Int, RPCCLient], + chainID *big.Int, + chainType config.ChainType, +) Client { + multiNode := commonclient.NewMultiNode[ + *big.Int, + evmtypes.Nonce, + common.Address, + common.Hash, + *types.Transaction, + common.Hash, + types.Log, + ethereum.FilterQuery, + *evmtypes.Receipt, + *assets.Wei, + *evmtypes.Head, + RPCCLient, + ]( + logger, + selectionMode, + leaseDuration, + noNewHeadsThreshold, + nodes, + sendonlys, + chainID, + chainType, + "EVM", + ClassifySendOnlyError, + ) + return &chainClient{ + multiNode: multiNode, + logger: logger, + } +} + +func (c *chainClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { + return c.multiNode.BalanceAt(ctx, account, blockNumber) +} + +func (c *chainClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { + batch := make([]any, len(b)) + for i, arg := range b { + batch[i] = any(arg) + } + return c.multiNode.BatchCallContext(ctx, batch) +} + +func (c *chainClient) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) error { + batch := make([]any, len(b)) + for i, arg := range b { + batch[i] = any(arg) + } + return c.multiNode.BatchCallContextAll(ctx, batch) +} + +// TODO-1663: return custom Block type instead of geth's once client.go is deprecated. +func (c *chainClient) BlockByHash(ctx context.Context, hash common.Hash) (b *types.Block, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return b, err + } + return rpc.BlockByHashGeth(ctx, hash) +} + +// TODO-1663: return custom Block type instead of geth's once client.go is deprecated. +func (c *chainClient) BlockByNumber(ctx context.Context, number *big.Int) (b *types.Block, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return b, err + } + return rpc.BlockByNumberGeth(ctx, number) +} + +func (c *chainClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + return c.multiNode.CallContext(ctx, result, method) +} + +func (c *chainClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + return c.multiNode.CallContract(ctx, msg, blockNumber) +} + +// TODO-1663: change this to actual ChainID() call once client.go is deprecated. +func (c *chainClient) ChainID() (*big.Int, error) { + //return c.multiNode.ChainID(ctx), nil + return c.multiNode.ConfiguredChainID(), nil +} + +func (c *chainClient) Close() { + c.multiNode.Close() +} + +func (c *chainClient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { + return c.multiNode.CodeAt(ctx, account, blockNumber) +} + +func (c *chainClient) ConfiguredChainID() *big.Int { + return c.multiNode.ConfiguredChainID() +} + +func (c *chainClient) Dial(ctx context.Context) error { + return c.multiNode.Dial(ctx) +} + +func (c *chainClient) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { + return c.multiNode.EstimateGas(ctx, call) +} +func (c *chainClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + return c.multiNode.FilterEvents(ctx, q) +} + +func (c *chainClient) HeaderByHash(ctx context.Context, h common.Hash) (head *types.Header, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return head, err + } + return rpc.HeaderByHash(ctx, h) +} + +func (c *chainClient) HeaderByNumber(ctx context.Context, n *big.Int) (head *types.Header, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return head, err + } + return rpc.HeaderByNumber(ctx, n) +} + +func (c *chainClient) HeadByHash(ctx context.Context, h common.Hash) (*evmtypes.Head, error) { + return c.multiNode.BlockByHash(ctx, h) +} + +func (c *chainClient) HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, error) { + return c.multiNode.BlockByNumber(ctx, n) +} + +func (c *chainClient) IsL2() bool { + return c.multiNode.IsL2() +} + +func (c *chainClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*assets.Link, error) { + return c.multiNode.LINKBalance(ctx, address, linkAddress) +} + +func (c *chainClient) LatestBlockHeight(ctx context.Context) (*big.Int, error) { + return c.multiNode.LatestBlockHeight(ctx) +} + +func (c *chainClient) NodeStates() map[string]string { + return c.multiNode.NodeStates() +} + +func (c *chainClient) PendingCodeAt(ctx context.Context, account common.Address) (b []byte, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return b, err + } + return rpc.PendingCodeAt(ctx, account) +} + +// TODO-1663: change this to evmtypes.Nonce(int64) once client.go is deprecated. +func (c *chainClient) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { + n, err := c.multiNode.PendingSequenceAt(ctx, account) + return uint64(n), err +} + +func (c *chainClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { + return c.multiNode.SendTransaction(ctx, tx) +} + +func (c *chainClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commontypes.SendTxReturnCode, error) { + err := c.SendTransaction(ctx, tx) + return ClassifySendError(err, c.logger, tx, fromAddress, c.IsL2()) +} + +func (c *chainClient) SequenceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (evmtypes.Nonce, error) { + return c.multiNode.SequenceAt(ctx, account, blockNumber) +} + +func (c *chainClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (s ethereum.Subscription, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return s, err + } + return rpc.SubscribeFilterLogs(ctx, q, ch) +} + +func (c *chainClient) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head) (ethereum.Subscription, error) { + csf := newChainIDSubForwarder(c.ConfiguredChainID(), ch) + err := csf.start(c.multiNode.Subscribe(ctx, csf.srcCh, "newHeads")) + if err != nil { + return nil, err + } + return csf, nil +} + +func (c *chainClient) SuggestGasPrice(ctx context.Context) (p *big.Int, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return p, err + } + return rpc.SuggestGasPrice(ctx) +} + +func (c *chainClient) SuggestGasTipCap(ctx context.Context) (t *big.Int, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return t, err + } + return rpc.SuggestGasTipCap(ctx) +} + +func (c *chainClient) TokenBalance(ctx context.Context, address common.Address, contractAddress common.Address) (*big.Int, error) { + return c.multiNode.TokenBalance(ctx, address, contractAddress) +} + +func (c *chainClient) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) { + return c.multiNode.TransactionByHash(ctx, txHash) +} + +// TODO-1663: return custom Receipt type instead of geth's once client.go is deprecated. +func (c *chainClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (r *types.Receipt, err error) { + rpc, err := c.multiNode.SelectNodeRPC() + if err != nil { + return r, err + } + //return rpc.TransactionReceipt(ctx, txHash) + return rpc.TransactionReceiptGeth(ctx, txHash) +} diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index 3a3b8b23a9..af03720ced 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -213,7 +213,7 @@ func (client *client) HeaderByHash(ctx context.Context, h common.Hash) (*types.H func (client *client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (clienttypes.SendTxReturnCode, error) { err := client.SendTransaction(ctx, tx) - return NewSendErrorReturnCode(err, client.logger, tx, fromAddress, client.pool.ChainType().IsL2()) + return ClassifySendError(err, client.logger, tx, fromAddress, client.pool.ChainType().IsL2()) } // SendTransaction also uses the sendonly HTTP RPC URLs if set diff --git a/core/chains/evm/client/client_test.go b/core/chains/evm/client/client_test.go index 88bc37411c..81a82d20fa 100644 --- a/core/chains/evm/client/client_test.go +++ b/core/chains/evm/client/client_test.go @@ -22,7 +22,9 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + + commontypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -43,6 +45,33 @@ func mustNewClientWithChainID(t *testing.T, wsURL string, chainID *big.Int, send return c } +func mustNewChainClient(t *testing.T, wsURL string, sendonlys ...url.URL) evmclient.Client { + return mustNewChainClientWithChainID(t, wsURL, testutils.FixtureChainID, sendonlys...) +} + +func mustNewChainClientWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) evmclient.Client { + cfg := evmclient.TestNodePoolConfig{ + NodeSelectionMode: evmclient.NodeSelectionMode_RoundRobin, + } + c, err := evmclient.NewChainClientWithTestNode(t, cfg, time.Second*0, cfg.NodeLeaseDuration, wsURL, nil, sendonlys, 42, chainID) + require.NoError(t, err) + return c +} + +func mustNewClients(t *testing.T, wsURL string, sendonlys ...url.URL) []evmclient.Client { + var clients []evmclient.Client + clients = append(clients, mustNewClient(t, wsURL, sendonlys...)) + clients = append(clients, mustNewChainClient(t, wsURL, sendonlys...)) + return clients +} + +func mustNewClientsWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) []evmclient.Client { + var clients []evmclient.Client + clients = append(clients, mustNewClientWithChainID(t, wsURL, chainID, sendonlys...)) + clients = append(clients, mustNewChainClientWithChainID(t, wsURL, chainID, sendonlys...)) + return clients +} + func TestEthClient_TransactionReceipt(t *testing.T) { t.Parallel() @@ -78,15 +107,17 @@ func TestEthClient_TransactionReceipt(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - hash := common.HexToHash(txHash) - receipt, err := ethClient.TransactionReceipt(testutils.Context(t), hash) - require.NoError(t, err) - assert.Equal(t, hash, receipt.TxHash) - assert.Equal(t, big.NewInt(11), receipt.BlockNumber) + hash := common.HexToHash(txHash) + receipt, err := ethClient.TransactionReceipt(testutils.Context(t), hash) + require.NoError(t, err) + assert.Equal(t, hash, receipt.TxHash) + assert.Equal(t, big.NewInt(11), receipt.BlockNumber) + } }) t.Run("no tx hash, returns ethereum.NotFound", func(t *testing.T) { @@ -108,13 +139,15 @@ func TestEthClient_TransactionReceipt(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - hash := common.HexToHash(txHash) - _, err = ethClient.TransactionReceipt(testutils.Context(t), hash) - require.Equal(t, ethereum.NotFound, errors.Cause(err)) + hash := common.HexToHash(txHash) + _, err = ethClient.TransactionReceipt(testutils.Context(t), hash) + require.Equal(t, ethereum.NotFound, errors.Cause(err)) + } }) } @@ -144,15 +177,17 @@ func TestEthClient_PendingNonceAt(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - result, err := ethClient.PendingNonceAt(testutils.Context(t), address) - require.NoError(t, err) + result, err := ethClient.PendingNonceAt(testutils.Context(t), address) + require.NoError(t, err) - var expected uint64 = 256 - require.Equal(t, result, expected) + var expected uint64 = 256 + require.Equal(t, result, expected) + } } func TestEthClient_BalanceAt(t *testing.T) { @@ -189,13 +224,15 @@ func TestEthClient_BalanceAt(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - result, err := ethClient.BalanceAt(testutils.Context(t), address, nil) - require.NoError(t, err) - assert.Equal(t, test.balance, result) + result, err := ethClient.BalanceAt(testutils.Context(t), address, nil) + require.NoError(t, err) + assert.Equal(t, test.balance, result) + } }) } } @@ -220,13 +257,15 @@ func TestEthClient_LatestBlockHeight(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - result, err := ethClient.LatestBlockHeight(testutils.Context(t)) - require.NoError(t, err) - require.Equal(t, big.NewInt(256), result) + result, err := ethClient.LatestBlockHeight(testutils.Context(t)) + require.NoError(t, err) + require.Equal(t, big.NewInt(256), result) + } } func TestEthClient_GetERC20Balance(t *testing.T) { @@ -277,13 +316,15 @@ func TestEthClient_GetERC20Balance(t *testing.T) { }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - result, err := ethClient.TokenBalance(ctx, userAddress, contractAddress) - require.NoError(t, err) - assert.Equal(t, test.balance, result) + result, err := ethClient.TokenBalance(ctx, userAddress, contractAddress) + require.NoError(t, err) + assert.Equal(t, test.balance, result) + } }) } } @@ -354,20 +395,22 @@ func TestEthClient_HeaderByNumber(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) - - ctx, cancel := context.WithTimeout(testutils.Context(t), 5*time.Second) - defer cancel() - result, err := ethClient.HeadByNumber(ctx, expectedBlockNum) - if test.error != nil { - require.Error(t, err, test.error) - } else { + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) require.NoError(t, err) - require.Equal(t, expectedBlockHash, result.Hash.Hex()) - require.Equal(t, test.expectedResponseBlock, result.Number) - require.Zero(t, cltest.FixtureChainID.Cmp(result.EVMChainID.ToInt())) + + ctx, cancel := context.WithTimeout(testutils.Context(t), 5*time.Second) + result, err := ethClient.HeadByNumber(ctx, expectedBlockNum) + if test.error != nil { + require.Error(t, err, test.error) + } else { + require.NoError(t, err) + require.Equal(t, expectedBlockHash, result.Hash.Hex()) + require.Equal(t, test.expectedResponseBlock, result.Number) + require.Zero(t, cltest.FixtureChainID.Cmp(result.EVMChainID.ToInt())) + } + cancel() } }) } @@ -395,12 +438,14 @@ func TestEthClient_SendTransaction_NoSecondaryURL(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - err = ethClient.SendTransaction(testutils.Context(t), tx) - assert.NoError(t, err) + err = ethClient.SendTransaction(testutils.Context(t), tx) + assert.NoError(t, err) + } } func TestEthClient_SendTransaction_WithSecondaryURLs(t *testing.T) { @@ -432,16 +477,19 @@ func TestEthClient_SendTransaction_WithSecondaryURLs(t *testing.T) { t.Cleanup(ts.Close) sendonlyURL := *cltest.MustParseURL(t, ts.URL) - ethClient := mustNewClient(t, wsURL, sendonlyURL, sendonlyURL) - err = ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) - err = ethClient.SendTransaction(testutils.Context(t), tx) - require.NoError(t, err) + clients := mustNewClients(t, wsURL, sendonlyURL, sendonlyURL) + for _, ethClient := range clients { + err = ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) + + err = ethClient.SendTransaction(testutils.Context(t), tx) + require.NoError(t, err) + } // Unfortunately it's a bit tricky to test this, since there is no // synchronization. We have to rely on timing instead. - require.Eventually(t, func() bool { return service.sentCount.Load() == int32(2) }, testutils.WaitTimeout(t), 500*time.Millisecond) + require.Eventually(t, func() bool { return service.sentCount.Load() == int32(len(clients)*2) }, testutils.WaitTimeout(t), 500*time.Millisecond) } func TestEthClient_SendTransactionReturnCode(t *testing.T) { @@ -467,13 +515,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.Fatal) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.Fatal) + } }) t.Run("returns TransactionAlreadyKnown error type when error message is nonce too low", func(t *testing.T) { @@ -493,13 +543,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.TransactionAlreadyKnown) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.TransactionAlreadyKnown) + } }) t.Run("returns Successful error type when there is no error message", func(t *testing.T) { @@ -518,13 +570,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.NoError(t, err) - assert.Equal(t, errType, clienttypes.Successful) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.NoError(t, err) + assert.Equal(t, errType, commontypes.Successful) + } }) t.Run("returns Underpriced error type when transaction is terminally underpriced", func(t *testing.T) { @@ -544,13 +598,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.Underpriced) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.Underpriced) + } }) t.Run("returns Unsupported error type when error message is queue full", func(t *testing.T) { @@ -570,13 +626,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.Unsupported) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.Unsupported) + } }) t.Run("returns Retryable error type when there is a transaction gap", func(t *testing.T) { @@ -596,13 +654,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.Retryable) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.Retryable) + } }) t.Run("returns InsufficientFunds error type when the sender address doesn't have enough funds", func(t *testing.T) { @@ -622,13 +682,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.InsufficientFunds) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.InsufficientFunds) + } }) t.Run("returns ExceedsFeeCap error type when gas price is too high for the node", func(t *testing.T) { @@ -648,13 +710,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.ExceedsMaxFee) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.ExceedsMaxFee) + } }) t.Run("returns Unknown error type when the error can't be categorized", func(t *testing.T) { @@ -674,13 +738,15 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { return }) - ethClient := mustNewClient(t, wsURL) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClients(t, wsURL) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) - assert.Error(t, err) - assert.Equal(t, errType, clienttypes.Unknown) + errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) + assert.Error(t, err) + assert.Equal(t, errType, commontypes.Unknown) + } }) } @@ -718,24 +784,132 @@ func TestEthClient_SubscribeNewHead(t *testing.T) { return }) - ethClient := mustNewClientWithChainID(t, wsURL, chainId) - err := ethClient.Dial(testutils.Context(t)) - require.NoError(t, err) + clients := mustNewClientsWithChainID(t, wsURL, chainId) + for _, ethClient := range clients { + err := ethClient.Dial(testutils.Context(t)) + require.NoError(t, err) - headCh := make(chan *evmtypes.Head) - sub, err := ethClient.SubscribeNewHead(ctx, headCh) - require.NoError(t, err) - defer sub.Unsubscribe() - - select { - case err := <-sub.Err(): - t.Fatal(err) - case <-ctx.Done(): - t.Fatal(ctx.Err()) - case h := <-headCh: - require.NotNil(t, h.EVMChainID) - require.Zero(t, chainId.Cmp(h.EVMChainID.ToInt())) + headCh := make(chan *evmtypes.Head) + sub, err := ethClient.SubscribeNewHead(ctx, headCh) + require.NoError(t, err) + + select { + case err := <-sub.Err(): + t.Fatal(err) + case <-ctx.Done(): + t.Fatal(ctx.Err()) + case h := <-headCh: + require.NotNil(t, h.EVMChainID) + require.Zero(t, chainId.Cmp(h.EVMChainID.ToInt())) + } + sub.Unsubscribe() } } +func TestEthClient_ErroringClient(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + + // Empty node means there are no active nodes to select from, causing client to always return error. + erroringClient := evmclient.NewChainClientWithEmptyNode(t, commonclient.NodeSelectionModeRoundRobin, time.Second*0, time.Second*0, testutils.FixtureChainID) + + _, err := erroringClient.BalanceAt(ctx, common.Address{}, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + err = erroringClient.BatchCallContext(ctx, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + err = erroringClient.BatchCallContextAll(ctx, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.BlockByHash(ctx, common.Hash{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.BlockByNumber(ctx, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + err = erroringClient.CallContext(ctx, nil, "") + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.CallContract(ctx, ethereum.CallMsg{}, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + // TODO-1663: test actual ChainID() call once client.go is deprecated. + id, err := erroringClient.ChainID() + require.Equal(t, id, testutils.FixtureChainID) + //require.Equal(t, err, commonclient.ErroringNodeError) + require.Equal(t, err, nil) + + _, err = erroringClient.CodeAt(ctx, common.Address{}, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + id = erroringClient.ConfiguredChainID() + require.Equal(t, id, testutils.FixtureChainID) + + err = erroringClient.Dial(ctx) + require.ErrorContains(t, err, "no available nodes for chain") + + _, err = erroringClient.EstimateGas(ctx, ethereum.CallMsg{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.FilterLogs(ctx, ethereum.FilterQuery{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.HeaderByHash(ctx, common.Hash{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.HeaderByNumber(ctx, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.HeadByHash(ctx, common.Hash{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.HeadByNumber(ctx, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.LINKBalance(ctx, common.Address{}, common.Address{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.LatestBlockHeight(ctx) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.PendingCodeAt(ctx, common.Address{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.PendingNonceAt(ctx, common.Address{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + err = erroringClient.SendTransaction(ctx, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + code, err := erroringClient.SendTransactionReturnCode(ctx, nil, common.Address{}) + require.Equal(t, code, commontypes.Unknown) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.SequenceAt(ctx, common.Address{}, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.SubscribeFilterLogs(ctx, ethereum.FilterQuery{}, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.SubscribeNewHead(ctx, nil) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.SuggestGasPrice(ctx) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.SuggestGasTipCap(ctx) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.TokenBalance(ctx, common.Address{}, common.Address{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.TransactionByHash(ctx, common.Hash{}) + require.Equal(t, err, commonclient.ErroringNodeError) + + _, err = erroringClient.TransactionReceipt(ctx, common.Hash{}) + require.Equal(t, err, commonclient.ErroringNodeError) + +} + const headResult = evmclient.HeadResult diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 7b89e7b92d..7197d77b3d 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -397,7 +397,7 @@ func ExtractRPCError(baseErr error) (*JsonError, error) { return &jErr, nil } -func NewSendErrorReturnCode(err error, lggr logger.Logger, tx *types.Transaction, fromAddress common.Address, isL2 bool) (clienttypes.SendTxReturnCode, error) { +func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fromAddress common.Address, isL2 bool) (clienttypes.SendTxReturnCode, error) { sendError := NewSendError(err) if sendError == nil { return clienttypes.Successful, err @@ -465,3 +465,15 @@ func NewSendErrorReturnCode(err error, lggr logger.Logger, tx *types.Transaction } return clienttypes.Unknown, err } + +// ClassifySendOnlyError handles SendOnly nodes error codes. In that case, we don't assume there is another transaction that will be correctly +// priced. +func ClassifySendOnlyError(err error) clienttypes.SendTxReturnCode { + sendError := NewSendError(err) + if sendError == nil || sendError.IsNonceTooLowError() || sendError.IsTransactionAlreadyMined() || sendError.IsTransactionAlreadyInMempool() { + // Nonce too low or transaction known errors are expected since + // the primary SendTransaction may well have succeeded already + return clienttypes.Successful + } + return clienttypes.Fatal +} diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 342a914343..8552b2c0a0 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -9,7 +9,11 @@ import ( "github.com/pkg/errors" + clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + commonconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -64,6 +68,67 @@ func Wrap(err error, s string) error { return wrap(err, s) } +func NewChainClientWithTestNode( + t *testing.T, + nodeCfg commonclient.NodeConfig, + noNewHeadsThreshold time.Duration, + leaseDuration time.Duration, + rpcUrl string, + rpcHTTPURL *url.URL, + sendonlyRPCURLs []url.URL, + id int32, + chainID *big.Int, +) (Client, error) { + parsed, err := url.ParseRequestURI(rpcUrl) + if err != nil { + return nil, err + } + + if parsed.Scheme != "ws" && parsed.Scheme != "wss" { + return nil, errors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) + } + + lggr := logger.TestLogger(t) + rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, clienttypes.Primary) + + n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCCLient]( + nodeCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-node-0", id, chainID, 1, rpc, "EVM") + primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCCLient]{n} + + var sendonlys []commonclient.SendOnlyNode[*big.Int, RPCCLient] + for i, u := range sendonlyRPCURLs { + if u.Scheme != "http" && u.Scheme != "https" { + return nil, errors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", u.String()) + } + var empty url.URL + rpc := NewRPCClient(lggr, empty, &sendonlyRPCURLs[i], fmt.Sprintf("eth-sendonly-rpc-%d", i), id, chainID, clienttypes.Secondary) + s := commonclient.NewSendOnlyNode[*big.Int, RPCCLient]( + lggr, u, fmt.Sprintf("eth-sendonly-%d", i), chainID, rpc) + sendonlys = append(sendonlys, s) + } + + var chainType commonconfig.ChainType + c := NewChainClient(lggr, nodeCfg.SelectionMode(), leaseDuration, noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) + t.Cleanup(c.Close) + return c, nil +} + +func NewChainClientWithEmptyNode( + t *testing.T, + selectionMode string, + leaseDuration time.Duration, + noNewHeadsThreshold time.Duration, + chainID *big.Int, +) Client { + + lggr := logger.TestLogger(t) + + var chainType commonconfig.ChainType + c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, nil, nil, chainID, chainType) + t.Cleanup(c.Close) + return c +} + type TestableSendOnlyNode interface { SendOnlyNode SetEthClient(newBatchSender BatchSender, newSender TxSender) diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go new file mode 100644 index 0000000000..b6ed84eee4 --- /dev/null +++ b/core/chains/evm/client/rpc_client.go @@ -0,0 +1,1046 @@ +package client + +import ( + "context" + "fmt" + "math/big" + "net/url" + "strconv" + "sync" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + "github.com/google/uuid" + "github.com/pkg/errors" + + clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + commontypes "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/assets" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +// RPCCLient includes all the necessary generalized RPC methods along with any additional chain-specific methods. +type RPCCLient interface { + commonclient.RPC[ + *big.Int, + evmtypes.Nonce, + common.Address, + common.Hash, + *types.Transaction, + common.Hash, + types.Log, + ethereum.FilterQuery, + *evmtypes.Receipt, + *assets.Wei, + *evmtypes.Head, + ] + BlockByHashGeth(ctx context.Context, hash common.Hash) (b *types.Block, err error) + BlockByNumberGeth(ctx context.Context, number *big.Int) (b *types.Block, err error) + HeaderByHash(ctx context.Context, h common.Hash) (head *types.Header, err error) + HeaderByNumber(ctx context.Context, n *big.Int) (head *types.Header, err error) + PendingCodeAt(ctx context.Context, account common.Address) (b []byte, err error) + SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (s ethereum.Subscription, err error) + SuggestGasPrice(ctx context.Context) (p *big.Int, err error) + SuggestGasTipCap(ctx context.Context) (t *big.Int, err error) + TransactionReceiptGeth(ctx context.Context, txHash common.Hash) (r *types.Receipt, err error) +} + +type rpcClient struct { + rpcLog logger.Logger + name string + id int32 + chainID *big.Int + tier clienttypes.NodeTier + + ws rawclient + http *rawclient + + stateMu sync.RWMutex // protects state* fields + + // Need to track subscriptions because closing the RPC does not (always?) + // close the underlying subscription + subs []ethereum.Subscription + + // Need to track the aliveLoop subscription, so we do not cancel it when checking lease on the MultiNode + aliveLoopSub ethereum.Subscription + + // chStopInFlight can be closed to immediately cancel all in-flight requests on + // this rpcClient. Closing and replacing should be serialized through + // stateMu since it can happen on state transitions as well as rpcClient Close. + chStopInFlight chan struct{} +} + +// NewRPCCLient returns a new *rpcClient as commonclient.RPC +func NewRPCClient( + lggr logger.Logger, + wsuri url.URL, + httpuri *url.URL, + name string, + id int32, + chainID *big.Int, + tier clienttypes.NodeTier, +) RPCCLient { + r := new(rpcClient) + r.name = name + r.id = id + r.chainID = chainID + r.tier = tier + r.ws.uri = wsuri + if httpuri != nil { + r.http = &rawclient{uri: *httpuri} + } + r.chStopInFlight = make(chan struct{}) + lggr = lggr.Named("Client").With( + "clientTier", tier.String(), + "clientName", name, + "client", r.String(), + "evmChainID", chainID, + ) + r.rpcLog = lggr.Named("RPC") + + return r +} + +// Not thread-safe, pure dial. +func (r *rpcClient) Dial(callerCtx context.Context) error { + ctx, cancel := r.makeQueryCtx(callerCtx) + defer cancel() + + promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() + lggr := r.rpcLog.With("wsuri", r.ws.uri.Redacted()) + if r.http != nil { + lggr = lggr.With("httpuri", r.http.uri.Redacted()) + } + lggr.Debugw("RPC dial: evmclient.Client#dial") + + wsrpc, err := rpc.DialWebsocket(ctx, r.ws.uri.String(), "") + if err != nil { + promEVMPoolRPCNodeDialsFailed.WithLabelValues(r.chainID.String(), r.name).Inc() + return errors.Wrapf(err, "error while dialing websocket: %v", r.ws.uri.Redacted()) + } + + r.ws.rpc = wsrpc + r.ws.geth = ethclient.NewClient(wsrpc) + + if r.http != nil { + if err := r.DialHTTP(); err != nil { + return err + } + } + + promEVMPoolRPCNodeDialsSuccess.WithLabelValues(r.chainID.String(), r.name).Inc() + + return nil +} + +// Not thread-safe, pure dial. +// DialHTTP doesn't actually make any external HTTP calls +// It can only return error if the URL is malformed. +func (r *rpcClient) DialHTTP() error { + promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() + lggr := r.rpcLog.With("httpuri", r.ws.uri.Redacted()) + lggr.Debugw("RPC dial: evmclient.Client#dial") + + var httprpc *rpc.Client + httprpc, err := rpc.DialHTTP(r.http.uri.String()) + if err != nil { + promEVMPoolRPCNodeDialsFailed.WithLabelValues(r.chainID.String(), r.name).Inc() + return errors.Wrapf(err, "error while dialing HTTP: %v", r.http.uri.Redacted()) + } + + r.http.rpc = httprpc + r.http.geth = ethclient.NewClient(httprpc) + + promEVMPoolRPCNodeDialsSuccess.WithLabelValues(r.chainID.String(), r.name).Inc() + + return nil +} + +func (r *rpcClient) Close() { + defer func() { + if r.ws.rpc != nil { + r.ws.rpc.Close() + } + }() + + r.stateMu.Lock() + defer r.stateMu.Unlock() + r.cancelInflightRequests() +} + +// cancelInflightRequests closes and replaces the chStopInFlight +// WARNING: NOT THREAD-SAFE +// This must be called from within the r.stateMu lock +func (r *rpcClient) cancelInflightRequests() { + close(r.chStopInFlight) + r.chStopInFlight = make(chan struct{}) +} + +func (r *rpcClient) String() string { + s := fmt.Sprintf("(%s)%s:%s", r.tier.String(), r.name, r.ws.uri.Redacted()) + if r.http != nil { + s = s + fmt.Sprintf(":%s", r.http.uri.Redacted()) + } + return s +} + +func (r *rpcClient) logResult( + lggr logger.Logger, + err error, + callDuration time.Duration, + rpcDomain, + callName string, + results ...interface{}, +) { + lggr = lggr.With("duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) + promEVMPoolRPCNodeCalls.WithLabelValues(r.chainID.String(), r.name).Inc() + if err == nil { + promEVMPoolRPCNodeCallsSuccess.WithLabelValues(r.chainID.String(), r.name).Inc() + lggr.Tracew( + fmt.Sprintf("evmclient.Client#%s RPC call success", callName), + results..., + ) + } else { + promEVMPoolRPCNodeCallsFailed.WithLabelValues(r.chainID.String(), r.name).Inc() + lggr.Debugw( + fmt.Sprintf("evmclient.Client#%s RPC call failure", callName), + append(results, "err", err)..., + ) + } + promEVMPoolRPCCallTiming. + WithLabelValues( + r.chainID.String(), // chain id + r.name, // rpcClient name + rpcDomain, // rpc domain + "false", // is send only + strconv.FormatBool(err == nil), // is successful + callName, // rpc call name + ). + Observe(float64(callDuration)) +} + +func (r *rpcClient) getRPCDomain() string { + if r.http != nil { + return r.http.uri.Host + } + return r.ws.uri.Host +} + +// registerSub adds the sub to the rpcClient list +func (r *rpcClient) registerSub(sub ethereum.Subscription) { + r.stateMu.Lock() + defer r.stateMu.Unlock() + r.subs = append(r.subs, sub) +} + +// disconnectAll disconnects all clients connected to the rpcClient +// WARNING: NOT THREAD-SAFE +// This must be called from within the r.stateMu lock +func (r *rpcClient) DisconnectAll() { + if r.ws.rpc != nil { + r.ws.rpc.Close() + } + r.cancelInflightRequests() + r.unsubscribeAll() +} + +// unsubscribeAll unsubscribes all subscriptions +// WARNING: NOT THREAD-SAFE +// This must be called from within the r.stateMu lock +func (r *rpcClient) unsubscribeAll() { + for _, sub := range r.subs { + sub.Unsubscribe() + } + r.subs = nil +} +func (r *rpcClient) SetAliveLoopSub(sub commontypes.Subscription) { + r.stateMu.Lock() + defer r.stateMu.Unlock() + + r.aliveLoopSub = sub +} + +// SubscribersCount returns the number of client subscribed to the node +func (r *rpcClient) SubscribersCount() int32 { + r.stateMu.RLock() + defer r.stateMu.RUnlock() + return int32(len(r.subs)) +} + +// UnsubscribeAllExceptAliveLoop disconnects all subscriptions to the node except the alive loop subscription +// while holding the n.stateMu lock +func (r *rpcClient) UnsubscribeAllExceptAliveLoop() { + r.stateMu.Lock() + defer r.stateMu.Unlock() + + for _, s := range r.subs { + if s != r.aliveLoopSub { + s.Unsubscribe() + } + } +} + +// RPC wrappers + +// CallContext implementation +func (r *rpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return err + } + defer cancel() + lggr := r.newRqLggr().With( + "method", method, + "args", args, + ) + + lggr.Debug("RPC call: evmclient.Client#CallContext") + start := time.Now() + if http != nil { + err = r.wrapHTTP(http.rpc.CallContext(ctx, result, method, args...)) + } else { + err = r.wrapWS(ws.rpc.CallContext(ctx, result, method, args...)) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "CallContext") + + return err +} + +func (r *rpcClient) BatchCallContext(ctx context.Context, b []any) error { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return err + } + batch := make([]rpc.BatchElem, len(b)) + for i, arg := range b { + batch[i] = arg.(rpc.BatchElem) + } + defer cancel() + lggr := r.newRqLggr().With("nBatchElems", len(b), "batchElems", b) + + lggr.Trace("RPC call: evmclient.Client#BatchCallContext") + start := time.Now() + if http != nil { + err = r.wrapHTTP(http.rpc.BatchCallContext(ctx, batch)) + } else { + err = r.wrapWS(ws.rpc.BatchCallContext(ctx, batch)) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "BatchCallContext") + + return err +} + +func (r *rpcClient) Subscribe(ctx context.Context, channel chan<- *evmtypes.Head, args ...interface{}) (commontypes.Subscription, error) { + ctx, cancel, ws, _, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("args", args) + + lggr.Debug("RPC call: evmclient.Client#EthSubscribe") + start := time.Now() + sub, err := ws.rpc.EthSubscribe(ctx, channel, args...) + if err == nil { + r.registerSub(sub) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "EthSubscribe") + + return sub, err +} + +// GethClient wrappers + +func (r *rpcClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (receipt *evmtypes.Receipt, err error) { + err = r.CallContext(ctx, &receipt, "eth_getTransactionReceipt", txHash, false) + if err != nil { + return nil, err + } + if receipt == nil { + err = ethereum.NotFound + return + } + return +} + +func (r *rpcClient) TransactionReceiptGeth(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("txHash", txHash) + + lggr.Debug("RPC call: evmclient.Client#TransactionReceipt") + + start := time.Now() + if http != nil { + receipt, err = http.geth.TransactionReceipt(ctx, txHash) + err = r.wrapHTTP(err) + } else { + receipt, err = ws.geth.TransactionReceipt(ctx, txHash) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "TransactionReceipt", + "receipt", receipt, + ) + + return +} +func (r *rpcClient) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("txHash", txHash) + + lggr.Debug("RPC call: evmclient.Client#TransactionByHash") + + start := time.Now() + if http != nil { + tx, _, err = http.geth.TransactionByHash(ctx, txHash) + err = r.wrapHTTP(err) + } else { + tx, _, err = ws.geth.TransactionByHash(ctx, txHash) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "TransactionByHash", + "receipt", tx, + ) + + return +} + +func (r *rpcClient) HeaderByNumber(ctx context.Context, number *big.Int) (header *types.Header, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("number", number) + + lggr.Debug("RPC call: evmclient.Client#HeaderByNumber") + start := time.Now() + if http != nil { + header, err = http.geth.HeaderByNumber(ctx, number) + err = r.wrapHTTP(err) + } else { + header, err = ws.geth.HeaderByNumber(ctx, number) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "HeaderByNumber", "header", header) + + return +} + +func (r *rpcClient) HeaderByHash(ctx context.Context, hash common.Hash) (header *types.Header, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("hash", hash) + + lggr.Debug("RPC call: evmclient.Client#HeaderByHash") + start := time.Now() + if http != nil { + header, err = http.geth.HeaderByHash(ctx, hash) + err = r.wrapHTTP(err) + } else { + header, err = ws.geth.HeaderByHash(ctx, hash) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "HeaderByHash", + "header", header, + ) + + return +} + +func (r *rpcClient) BlockByNumber(ctx context.Context, number *big.Int) (head *evmtypes.Head, err error) { + hex := ToBlockNumArg(number) + err = r.CallContext(ctx, &head, "eth_getBlockByNumber", hex, false) + if err != nil { + return nil, err + } + if head == nil { + err = ethereum.NotFound + return + } + head.EVMChainID = utils.NewBig(r.chainID) + return +} + +func (r *rpcClient) BlockByHash(ctx context.Context, hash common.Hash) (head *evmtypes.Head, err error) { + err = r.CallContext(ctx, &head, "eth_getBlockByHash", hash.Hex(), false) + if err != nil { + return nil, err + } + if head == nil { + err = ethereum.NotFound + return + } + head.EVMChainID = utils.NewBig(r.chainID) + return +} + +func (r *rpcClient) BlockByHashGeth(ctx context.Context, hash common.Hash) (block *types.Block, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("hash", hash) + + lggr.Debug("RPC call: evmclient.Client#BlockByHash") + start := time.Now() + if http != nil { + block, err = http.geth.BlockByHash(ctx, hash) + err = r.wrapHTTP(err) + } else { + block, err = ws.geth.BlockByHash(ctx, hash) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "BlockByHash", + "block", block, + ) + + return +} + +func (r *rpcClient) BlockByNumberGeth(ctx context.Context, number *big.Int) (block *types.Block, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("number", number) + + lggr.Debug("RPC call: evmclient.Client#BlockByNumber") + start := time.Now() + if http != nil { + block, err = http.geth.BlockByNumber(ctx, number) + err = r.wrapHTTP(err) + } else { + block, err = ws.geth.BlockByNumber(ctx, number) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "BlockByNumber", + "block", block, + ) + + return +} + +func (r *rpcClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return err + } + defer cancel() + lggr := r.newRqLggr().With("tx", tx) + + lggr.Debug("RPC call: evmclient.Client#SendTransaction") + start := time.Now() + if http != nil { + err = r.wrapHTTP(http.geth.SendTransaction(ctx, tx)) + } else { + err = r.wrapWS(ws.geth.SendTransaction(ctx, tx)) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "SendTransaction") + + return err +} + +func (r *rpcClient) SimulateTransaction(ctx context.Context, tx *types.Transaction) error { + // Not Implemented + return errors.New("SimulateTransaction not implemented") +} + +func (r *rpcClient) SendEmptyTransaction( + ctx context.Context, + newTxAttempt func(nonce evmtypes.Nonce, feeLimit uint32, fee *assets.Wei, fromAddress common.Address) (attempt any, err error), + nonce evmtypes.Nonce, + gasLimit uint32, + fee *assets.Wei, + fromAddress common.Address, +) (txhash string, err error) { + // Not Implemented + return "", errors.New("SendEmptyTransaction not implemented") +} + +// PendingSequenceAt returns one higher than the highest nonce from both mempool and mined transactions +func (r *rpcClient) PendingSequenceAt(ctx context.Context, account common.Address) (nonce evmtypes.Nonce, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return 0, err + } + defer cancel() + lggr := r.newRqLggr().With("account", account) + + lggr.Debug("RPC call: evmclient.Client#PendingNonceAt") + start := time.Now() + var n uint64 + if http != nil { + n, err = http.geth.PendingNonceAt(ctx, account) + nonce = evmtypes.Nonce(int64(n)) + err = r.wrapHTTP(err) + } else { + n, err = ws.geth.PendingNonceAt(ctx, account) + nonce = evmtypes.Nonce(int64(n)) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "PendingNonceAt", + "nonce", nonce, + ) + + return +} + +// SequenceAt is a bit of a misnomer. You might expect it to return the highest +// mined nonce at the given block number, but it actually returns the total +// transaction count which is the highest mined nonce + 1 +func (r *rpcClient) SequenceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (nonce evmtypes.Nonce, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return 0, err + } + defer cancel() + lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) + + lggr.Debug("RPC call: evmclient.Client#NonceAt") + start := time.Now() + var n uint64 + if http != nil { + n, err = http.geth.NonceAt(ctx, account, blockNumber) + nonce = evmtypes.Nonce(int64(n)) + err = r.wrapHTTP(err) + } else { + n, err = ws.geth.NonceAt(ctx, account, blockNumber) + nonce = evmtypes.Nonce(int64(n)) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "NonceAt", + "nonce", nonce, + ) + + return +} + +func (r *rpcClient) PendingCodeAt(ctx context.Context, account common.Address) (code []byte, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("account", account) + + lggr.Debug("RPC call: evmclient.Client#PendingCodeAt") + start := time.Now() + if http != nil { + code, err = http.geth.PendingCodeAt(ctx, account) + err = r.wrapHTTP(err) + } else { + code, err = ws.geth.PendingCodeAt(ctx, account) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "PendingCodeAt", + "code", code, + ) + + return +} + +func (r *rpcClient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) (code []byte, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) + + lggr.Debug("RPC call: evmclient.Client#CodeAt") + start := time.Now() + if http != nil { + code, err = http.geth.CodeAt(ctx, account, blockNumber) + err = r.wrapHTTP(err) + } else { + code, err = ws.geth.CodeAt(ctx, account, blockNumber) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "CodeAt", + "code", code, + ) + + return +} + +func (r *rpcClient) EstimateGas(ctx context.Context, c interface{}) (gas uint64, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return 0, err + } + defer cancel() + call := c.(ethereum.CallMsg) + lggr := r.newRqLggr().With("call", call) + + lggr.Debug("RPC call: evmclient.Client#EstimateGas") + start := time.Now() + if http != nil { + gas, err = http.geth.EstimateGas(ctx, call) + err = r.wrapHTTP(err) + } else { + gas, err = ws.geth.EstimateGas(ctx, call) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "EstimateGas", + "gas", gas, + ) + + return +} + +func (r *rpcClient) SuggestGasPrice(ctx context.Context) (price *big.Int, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr() + + lggr.Debug("RPC call: evmclient.Client#SuggestGasPrice") + start := time.Now() + if http != nil { + price, err = http.geth.SuggestGasPrice(ctx) + err = r.wrapHTTP(err) + } else { + price, err = ws.geth.SuggestGasPrice(ctx) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "SuggestGasPrice", + "price", price, + ) + + return +} + +func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumber *big.Int) (val []byte, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber) + message := msg.(ethereum.CallMsg) + + lggr.Debug("RPC call: evmclient.Client#CallContract") + start := time.Now() + if http != nil { + val, err = http.geth.CallContract(ctx, message, blockNumber) + err = r.wrapHTTP(err) + } else { + val, err = ws.geth.CallContract(ctx, message, blockNumber) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "CallContract", + "val", val, + ) + + return + +} + +func (r *rpcClient) LatestBlockHeight(ctx context.Context) (*big.Int, error) { + var height big.Int + h, err := r.BlockNumber(ctx) + return height.SetUint64(h), err +} + +func (r *rpcClient) BlockNumber(ctx context.Context) (height uint64, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return 0, err + } + defer cancel() + lggr := r.newRqLggr() + + lggr.Debug("RPC call: evmclient.Client#BlockNumber") + start := time.Now() + if http != nil { + height, err = http.geth.BlockNumber(ctx) + err = r.wrapHTTP(err) + } else { + height, err = ws.geth.BlockNumber(ctx) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "BlockNumber", + "height", height, + ) + + return +} + +func (r *rpcClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (balance *big.Int, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber) + + lggr.Debug("RPC call: evmclient.Client#BalanceAt") + start := time.Now() + if http != nil { + balance, err = http.geth.BalanceAt(ctx, account, blockNumber) + err = r.wrapHTTP(err) + } else { + balance, err = ws.geth.BalanceAt(ctx, account, blockNumber) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "BalanceAt", + "balance", balance, + ) + + return +} + +// TokenBalance returns the balance of the given address for the token contract address. +func (r *rpcClient) TokenBalance(ctx context.Context, address common.Address, contractAddress common.Address) (*big.Int, error) { + result := "" + numLinkBigInt := new(big.Int) + functionSelector := evmtypes.HexToFunctionSelector(BALANCE_OF_ADDRESS_FUNCTION_SELECTOR) // balanceOf(address) + data := utils.ConcatBytes(functionSelector.Bytes(), common.LeftPadBytes(address.Bytes(), utils.EVMWordByteLen)) + args := CallArgs{ + To: contractAddress, + Data: data, + } + err := r.CallContext(ctx, &result, "eth_call", args, "latest") + if err != nil { + return numLinkBigInt, err + } + numLinkBigInt.SetString(result, 0) + return numLinkBigInt, nil +} + +// LINKBalance returns the balance of LINK at the given address +func (r *rpcClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*assets.Link, error) { + balance, err := r.TokenBalance(ctx, address, linkAddress) + if err != nil { + return assets.NewLinkFromJuels(0), err + } + return (*assets.Link)(balance), nil +} + +func (r *rpcClient) FilterEvents(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + return r.FilterLogs(ctx, q) +} + +func (r *rpcClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l []types.Log, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("q", q) + + lggr.Debug("RPC call: evmclient.Client#FilterLogs") + start := time.Now() + if http != nil { + l, err = http.geth.FilterLogs(ctx, q) + err = r.wrapHTTP(err) + } else { + l, err = ws.geth.FilterLogs(ctx, q) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "FilterLogs", + "log", l, + ) + + return +} + +func (r *rpcClient) ClientVersion(ctx context.Context) (version string, err error) { + err = r.CallContext(ctx, &version, "web3_clientVersion") + return +} + +func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (sub ethereum.Subscription, err error) { + ctx, cancel, ws, _, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("q", q) + + lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") + start := time.Now() + sub, err = ws.geth.SubscribeFilterLogs(ctx, q, ch) + if err == nil { + r.registerSub(sub) + } + err = r.wrapWS(err) + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "SubscribeFilterLogs") + + return +} + +func (r *rpcClient) SuggestGasTipCap(ctx context.Context) (tipCap *big.Int, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr() + + lggr.Debug("RPC call: evmclient.Client#SuggestGasTipCap") + start := time.Now() + if http != nil { + tipCap, err = http.geth.SuggestGasTipCap(ctx) + err = r.wrapHTTP(err) + } else { + tipCap, err = ws.geth.SuggestGasTipCap(ctx) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "SuggestGasTipCap", + "tipCap", tipCap, + ) + + return +} + +// Returns the ChainID according to the geth client. This is useful for functions like verify() +// the common node. +func (r *rpcClient) ChainID(ctx context.Context) (chainID *big.Int, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + + defer cancel() + + if http != nil { + chainID, err = http.geth.ChainID(ctx) + err = r.wrapHTTP(err) + } else { + chainID, err = ws.geth.ChainID(ctx) + err = r.wrapWS(err) + } + return +} + +// newRqLggr generates a new logger with a unique request ID +func (r *rpcClient) newRqLggr() logger.Logger { + return r.rpcLog.With( + "requestID", uuid.New(), + ) +} + +func wrapCallError(err error, tp string) error { + if err == nil { + return nil + } + if errors.Cause(err).Error() == "context deadline exceeded" { + err = errors.Wrap(err, "remote node timed out") + } + return errors.Wrapf(err, "%s call failed", tp) +} + +func (r *rpcClient) wrapWS(err error) error { + err = wrapCallError(err, fmt.Sprintf("%s websocket (%s)", r.tier.String(), r.ws.uri.Redacted())) + return err +} + +func (r *rpcClient) wrapHTTP(err error) error { + err = wrapCallError(err, fmt.Sprintf("%s http (%s)", r.tier.String(), r.http.uri.Redacted())) + if err != nil { + r.rpcLog.Debugw("Call failed", "err", err) + } else { + r.rpcLog.Trace("Call succeeded") + } + return err +} + +// makeLiveQueryCtxAndSafeGetClients wraps makeQueryCtx +func (r *rpcClient) makeLiveQueryCtxAndSafeGetClients(parentCtx context.Context) (ctx context.Context, cancel context.CancelFunc, ws rawclient, http *rawclient, err error) { + // Need to wrap in mutex because state transition can cancel and replace the + // context + r.stateMu.RLock() + cancelCh := r.chStopInFlight + ws = r.ws + if r.http != nil { + cp := *r.http + http = &cp + } + r.stateMu.RUnlock() + ctx, cancel = makeQueryCtx(parentCtx, cancelCh) + return +} + +func (r *rpcClient) makeQueryCtx(ctx context.Context) (context.Context, context.CancelFunc) { + return makeQueryCtx(ctx, r.getChStopInflight()) +} + +// getChStopInflight provides a convenience helper that mutex wraps a +// read to the chStopInFlight +func (r *rpcClient) getChStopInflight() chan struct{} { + r.stateMu.RLock() + defer r.stateMu.RUnlock() + return r.chStopInFlight +} + +func (r *rpcClient) Name() string { + return r.name +} + +func Name(r *rpcClient) string { + return r.name +} diff --git a/core/chains/evm/txmgr/client.go b/core/chains/evm/txmgr/client.go index 150ee27757..e1b1257774 100644 --- a/core/chains/evm/txmgr/client.go +++ b/core/chains/evm/txmgr/client.go @@ -80,7 +80,7 @@ func (c *evmTxmClient) BatchSendTransactions( processingErr[i] = fmt.Errorf("failed to process tx (index %d): %w", i, signedErr) return } - codes[i], txErrs[i] = evmclient.NewSendErrorReturnCode(reqs[i].Error, lggr, tx, attempts[i].Tx.FromAddress, c.client.IsL2()) + codes[i], txErrs[i] = evmclient.ClassifySendError(reqs[i].Error, lggr, tx, attempts[i].Tx.FromAddress, c.client.IsL2()) }(index) } wg.Wait() diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 6210226120..a71c9e8716 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) BlockDifficulty() *utils.Big { + return h.Difficulty +} + // EarliestInChain recurses through parents until it finds the earliest one func (h *Head) EarliestInChain() *Head { for h.Parent != nil { From 1a69590dc766a1e7b405fe03cf2e2c6e1ddee64b Mon Sep 17 00:00:00 2001 From: Dylan Tinianov Date: Wed, 1 Nov 2023 17:12:11 -0400 Subject: [PATCH 049/327] [BCI-2313] Rename L2Suggested to SuggestedPrice (#11093) * Rename L2Suggested to SuggestedPrice * Rename L2Suggested to SuggestedPrice * update test error string * update comment * update docs * generate docs * L2Suggested backwards compatibility * L2Suggested backwards compatibility * Update CHANGELOG * Update comments * Update docs/CHANGELOG.md Co-authored-by: amit-momin <108959691+amit-momin@users.noreply.github.com> * Fix error message * Move import * deprecate L2Suggested * Update CONFIG.md --------- Co-authored-by: amit-momin <108959691+amit-momin@users.noreply.github.com> Co-authored-by: Prashant Yadav <34992934+prashantkumar1982@users.noreply.github.com> --- core/chains/evm/config/config_test.go | 2 +- .../config/toml/defaults/Fantom_Mainnet.toml | 5 +- .../config/toml/defaults/Fantom_Testnet.toml | 2 +- .../config/toml/defaults/Klaytn_Mainnet.toml | 2 +- .../config/toml/defaults/Klaytn_Testnet.toml | 2 +- .../config/toml/defaults/Metis_Mainnet.toml | 4 +- .../config/toml/defaults/Metis_Rinkeby.toml | 2 +- .../config/toml/defaults/Scroll_Mainnet.toml | 4 +- .../config/toml/defaults/Scroll_Sepolia.toml | 4 +- core/chains/evm/gas/arbitrum_estimator.go | 8 +-- .../chains/evm/gas/arbitrum_estimator_test.go | 4 +- core/chains/evm/gas/models.go | 4 +- ...imator.go => suggested_price_estimator.go} | 58 +++++++++---------- ...t.go => suggested_price_estimator_test.go} | 18 +++--- core/config/docs/chains-evm.toml | 3 +- core/services/chainlink/config_test.go | 4 +- .../chainlink/testdata/config-full.toml | 2 +- core/web/resolver/testdata/config-full.toml | 2 +- docs/CHANGELOG.md | 8 +++ docs/CONFIG.md | 19 +++--- 20 files changed, 83 insertions(+), 74 deletions(-) rename core/chains/evm/gas/{l2_suggested_estimator.go => suggested_price_estimator.go} (60%) rename core/chains/evm/gas/{l2_suggested_estimator_test.go => suggested_price_estimator_test.go} (87%) diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index d0f9e846e3..0a3fc5f41e 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -423,7 +423,7 @@ func Test_chainScopedConfig_Validate(t *testing.T) { t.Run("testnet", func(t *testing.T) { cfg := configWithChains(t, 421611, &toml.Chain{ GasEstimator: toml.GasEstimator{ - Mode: ptr("L2Suggested"), + Mode: ptr("SuggestedPrice"), }, }) assert.NoError(t, cfg.Validate()) diff --git a/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml b/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml index 7046642bb9..c7fb6ba473 100644 --- a/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Fantom_Mainnet.toml @@ -9,9 +9,8 @@ RPCBlockQueryDelay = 2 Enabled = true [GasEstimator] -# Fantom network has been slow to include txs at times when using the BlockHistory estimator, and the recommendation is to use L2Suggested mode. -# There is work under way to improve L2Suggested mode's name so that its use on non-L2 chains will be less confusing in the future. -Mode = 'L2Suggested' +# Fantom network has been slow to include txs at times when using the BlockHistory estimator, and the recommendation is to use SuggestedPrice mode. +Mode = 'SuggestedPrice' [OCR2.Automation] GasLimit = 3800000 \ No newline at end of file diff --git a/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml b/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml index 0292ed5b74..1e1aab1468 100644 --- a/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml +++ b/core/chains/evm/config/toml/defaults/Fantom_Testnet.toml @@ -7,7 +7,7 @@ NoNewHeadsThreshold = '0' RPCBlockQueryDelay = 2 [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' [OCR2.Automation] GasLimit = 3800000 \ No newline at end of file diff --git a/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml b/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml index 36dc04ae96..c68f03b044 100644 --- a/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml @@ -5,6 +5,6 @@ NoNewHeadsThreshold = '30s' OCR.ContractConfirmations = 1 [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '750 gwei' # gwei = ston BumpThreshold = 0 diff --git a/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml b/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml index 34b15ca74b..864aa0fa72 100644 --- a/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml +++ b/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml @@ -5,6 +5,6 @@ NoNewHeadsThreshold = '30s' OCR.ContractConfirmations = 1 [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '750 gwei' # gwei = ston BumpThreshold = 0 diff --git a/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml b/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml index 855fef55a7..3e8efa531c 100644 --- a/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml @@ -8,8 +8,8 @@ NoNewHeadsThreshold = '0' OCR.ContractConfirmations = 1 [GasEstimator] -Mode = 'L2Suggested' -# Metis uses the L2Suggested estimator; we don't want to place any limits on the minimum gas price +Mode = 'SuggestedPrice' +# Metis uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price PriceMin = '0' # Never bump gas on metis BumpThreshold = 0 diff --git a/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml b/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml index 487cc22485..7d9fec9076 100644 --- a/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml +++ b/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml @@ -9,7 +9,7 @@ OCR.ContractConfirmations = 1 Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceMin = '0' BumpThreshold = 0 diff --git a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml index 63c0855901..56ed84c7f3 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml @@ -7,8 +7,8 @@ NoNewHeadsThreshold = '0' OCR.ContractConfirmations = 1 [GasEstimator] -Mode = 'L2Suggested' -# Scroll uses the L2Suggested estimator; we don't want to place any limits on the minimum gas price +Mode = 'SuggestedPrice' +# Scroll uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price PriceMin = '0' # Never bump gas on Scroll BumpThreshold = 0 diff --git a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml index 5a1a0f9ba7..af17c4d485 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml @@ -7,8 +7,8 @@ NoNewHeadsThreshold = '0' OCR.ContractConfirmations = 1 [GasEstimator] -Mode = 'L2Suggested' -# Scroll uses the L2Suggested estimator; we don't want to place any limits on the minimum gas price +Mode = 'SuggestedPrice' +# Scroll uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price PriceMin = '0' # Never bump gas on Scroll BumpThreshold = 0 diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 17934bfa07..78d93243bb 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -31,12 +31,12 @@ type ethClient interface { CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) } -// arbitrumEstimator is an Estimator which extends l2SuggestedPriceEstimator to use getPricesInArbGas() for gas limit estimation. +// arbitrumEstimator is an Estimator which extends SuggestedPriceEstimator to use getPricesInArbGas() for gas limit estimation. type arbitrumEstimator struct { services.StateMachine cfg ArbConfig - EvmEstimator // *l2SuggestedPriceEstimator + EvmEstimator // *SuggestedPriceEstimator client ethClient pollPeriod time.Duration @@ -56,7 +56,7 @@ func NewArbitrumEstimator(lggr logger.Logger, cfg ArbConfig, rpcClient rpcClient lggr = lggr.Named("ArbitrumEstimator") return &arbitrumEstimator{ cfg: cfg, - EvmEstimator: NewL2SuggestedPriceEstimator(lggr, rpcClient), + EvmEstimator: NewSuggestedPriceEstimator(lggr, rpcClient), client: ethClient, pollPeriod: 10 * time.Second, logger: lggr, @@ -99,7 +99,7 @@ func (a *arbitrumEstimator) HealthReport() map[string]error { } // GetLegacyGas estimates both the gas price and the gas limit. -// - Price is delegated to the embedded l2SuggestedPriceEstimator. +// - Price is delegated to the embedded SuggestedPriceEstimator. // - Limit is computed from the dynamic values perL2Tx and perL1CalldataUnit, provided by the getPricesInArbGas() method // of the precompilie contract at ArbGasInfoAddress. perL2Tx is a constant amount of gas, and perL1CalldataUnit is // multiplied by the length of the tx calldata. The sum of these two values plus the original l2GasLimit is returned. diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index b6e299190c..a226368edf 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -131,7 +131,7 @@ func TestArbitrumEstimator(t *testing.T) { ethClient := mocks.NewETHClient(t) o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{}, rpcClient, ethClient) _, _, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), gasLimit, assets.NewWeiI(10), nil) - assert.EqualError(t, err, "bump gas is not supported for this l2") + assert.EqualError(t, err, "bump gas is not supported for this chain") }) t.Run("calling GetLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { @@ -152,7 +152,7 @@ func TestArbitrumEstimator(t *testing.T) { t.Cleanup(func() { assert.NoError(t, o.Close()) }) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) - assert.EqualError(t, err, "failed to estimate l2 gas; gas price not set") + assert.EqualError(t, err, "failed to estimate gas; gas price not set") }) t.Run("limit computes", func(t *testing.T) { diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index 7bd88d7543..299d7d5473 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -78,8 +78,8 @@ func NewEstimator(lggr logger.Logger, ethClient evmclient.Client, cfg Config, ge return NewWrappedEvmEstimator(NewBlockHistoryEstimator(lggr, ethClient, cfg, geCfg, bh, *ethClient.ConfiguredChainID()), df, l1Oracle) case "FixedPrice": return NewWrappedEvmEstimator(NewFixedPriceEstimator(geCfg, bh, lggr), df, l1Oracle) - case "Optimism2", "L2Suggested": - return NewWrappedEvmEstimator(NewL2SuggestedPriceEstimator(lggr, ethClient), df, l1Oracle) + case "L2Suggested", "SuggestedPrice": + return NewWrappedEvmEstimator(NewSuggestedPriceEstimator(lggr, ethClient), df, l1Oracle) default: lggr.Warnf("GasEstimator: unrecognised mode '%s', falling back to FixedPriceEstimator", s) return NewWrappedEvmEstimator(NewFixedPriceEstimator(geCfg, bh, lggr), df, l1Oracle) diff --git a/core/chains/evm/gas/l2_suggested_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go similarity index 60% rename from core/chains/evm/gas/l2_suggested_estimator.go rename to core/chains/evm/gas/suggested_price_estimator.go index 8e6c06a128..a4ffb80997 100644 --- a/core/chains/evm/gas/l2_suggested_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -19,7 +19,7 @@ import ( ) var ( - _ EvmEstimator = &l2SuggestedPriceEstimator{} + _ EvmEstimator = &SuggestedPriceEstimator{} ) //go:generate mockery --quiet --name rpcClient --output ./mocks/ --case=underscore --structname RPCClient @@ -27,8 +27,8 @@ type rpcClient interface { CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error } -// l2SuggestedPriceEstimator is an Estimator which uses the L2 suggested gas price from eth_gasPrice. -type l2SuggestedPriceEstimator struct { +// SuggestedPriceEstimator is an Estimator which uses the suggested gas price from eth_gasPrice. +type SuggestedPriceEstimator struct { services.StateMachine client rpcClient @@ -36,7 +36,7 @@ type l2SuggestedPriceEstimator struct { logger logger.Logger gasPriceMu sync.RWMutex - l2GasPrice *assets.Wei + GasPrice *assets.Wei chForceRefetch chan (chan struct{}) chInitialised chan struct{} @@ -44,12 +44,12 @@ type l2SuggestedPriceEstimator struct { chDone chan struct{} } -// NewL2SuggestedPriceEstimator returns a new Estimator which uses the L2 suggested gas price. -func NewL2SuggestedPriceEstimator(lggr logger.Logger, client rpcClient) EvmEstimator { - return &l2SuggestedPriceEstimator{ +// NewSuggestedPriceEstimator returns a new Estimator which uses the suggested gas price. +func NewSuggestedPriceEstimator(lggr logger.Logger, client rpcClient) EvmEstimator { + return &SuggestedPriceEstimator{ client: client, pollPeriod: 10 * time.Second, - logger: lggr.Named("L2SuggestedEstimator"), + logger: lggr.Named("SuggestedPriceEstimator"), chForceRefetch: make(chan (chan struct{})), chInitialised: make(chan struct{}), chStop: make(chan struct{}), @@ -57,30 +57,30 @@ func NewL2SuggestedPriceEstimator(lggr logger.Logger, client rpcClient) EvmEstim } } -func (o *l2SuggestedPriceEstimator) Name() string { +func (o *SuggestedPriceEstimator) Name() string { return o.logger.Name() } -func (o *l2SuggestedPriceEstimator) Start(context.Context) error { - return o.StartOnce("L2SuggestedEstimator", func() error { +func (o *SuggestedPriceEstimator) Start(context.Context) error { + return o.StartOnce("SuggestedPriceEstimator", func() error { go o.run() <-o.chInitialised return nil }) } -func (o *l2SuggestedPriceEstimator) Close() error { - return o.StopOnce("L2SuggestedEstimator", func() error { +func (o *SuggestedPriceEstimator) Close() error { + return o.StopOnce("SuggestedPriceEstimator", func() error { close(o.chStop) <-o.chDone return nil }) } -func (o *l2SuggestedPriceEstimator) HealthReport() map[string]error { +func (o *SuggestedPriceEstimator) HealthReport() map[string]error { return map[string]error{o.Name(): o.Healthy()} } -func (o *l2SuggestedPriceEstimator) run() { +func (o *SuggestedPriceEstimator) run() { defer close(o.chDone) t := o.refreshPrice() @@ -100,7 +100,7 @@ func (o *l2SuggestedPriceEstimator) run() { } } -func (o *l2SuggestedPriceEstimator) refreshPrice() (t *time.Timer) { +func (o *SuggestedPriceEstimator) refreshPrice() (t *time.Timer) { t = time.NewTimer(utils.WithJitter(o.pollPeriod)) var res hexutil.Big @@ -113,28 +113,28 @@ func (o *l2SuggestedPriceEstimator) refreshPrice() (t *time.Timer) { } bi := (*assets.Wei)(&res) - o.logger.Debugw("refreshPrice", "l2GasPrice", bi) + o.logger.Debugw("refreshPrice", "GasPrice", bi) o.gasPriceMu.Lock() defer o.gasPriceMu.Unlock() - o.l2GasPrice = bi + o.GasPrice = bi return } -func (o *l2SuggestedPriceEstimator) OnNewLongestChain(context.Context, *evmtypes.Head) {} +func (o *SuggestedPriceEstimator) OnNewLongestChain(context.Context, *evmtypes.Head) {} -func (*l2SuggestedPriceEstimator) GetDynamicFee(_ context.Context, _ uint32, _ *assets.Wei) (fee DynamicFee, chainSpecificGasLimit uint32, err error) { +func (*SuggestedPriceEstimator) GetDynamicFee(_ context.Context, _ uint32, _ *assets.Wei) (fee DynamicFee, chainSpecificGasLimit uint32, err error) { err = errors.New("dynamic fees are not implemented for this layer 2") return } -func (*l2SuggestedPriceEstimator) BumpDynamicFee(_ context.Context, _ DynamicFee, _ uint32, _ *assets.Wei, _ []EvmPriorAttempt) (bumped DynamicFee, chainSpecificGasLimit uint32, err error) { +func (*SuggestedPriceEstimator) BumpDynamicFee(_ context.Context, _ DynamicFee, _ uint32, _ *assets.Wei, _ []EvmPriorAttempt) (bumped DynamicFee, chainSpecificGasLimit uint32, err error) { err = errors.New("dynamic fees are not implemented for this layer 2") return } -func (o *l2SuggestedPriceEstimator) GetLegacyGas(ctx context.Context, _ []byte, l2GasLimit uint32, maxGasPriceWei *assets.Wei, opts ...feetypes.Opt) (gasPrice *assets.Wei, chainSpecificGasLimit uint32, err error) { - chainSpecificGasLimit = l2GasLimit +func (o *SuggestedPriceEstimator) GetLegacyGas(ctx context.Context, _ []byte, GasLimit uint32, maxGasPriceWei *assets.Wei, opts ...feetypes.Opt) (gasPrice *assets.Wei, chainSpecificGasLimit uint32, err error) { + chainSpecificGasLimit = GasLimit ok := o.IfStarted(func() { if slices.Contains(opts, feetypes.OptForceRefetch) { @@ -159,10 +159,10 @@ func (o *l2SuggestedPriceEstimator) GetLegacyGas(ctx context.Context, _ []byte, } } if gasPrice = o.getGasPrice(); gasPrice == nil { - err = errors.New("failed to estimate l2 gas; gas price not set") + err = errors.New("failed to estimate gas; gas price not set") return } - o.logger.Debugw("GetLegacyGas", "l2GasPrice", gasPrice, "l2GasLimit", l2GasLimit) + o.logger.Debugw("GetLegacyGas", "GasPrice", gasPrice, "GasLimit", GasLimit) }) if !ok { return nil, 0, errors.New("estimator is not started") @@ -176,12 +176,12 @@ func (o *l2SuggestedPriceEstimator) GetLegacyGas(ctx context.Context, _ []byte, return } -func (o *l2SuggestedPriceEstimator) BumpLegacyGas(_ context.Context, _ *assets.Wei, _ uint32, _ *assets.Wei, _ []EvmPriorAttempt) (bumpedGasPrice *assets.Wei, chainSpecificGasLimit uint32, err error) { - return nil, 0, errors.New("bump gas is not supported for this l2") +func (o *SuggestedPriceEstimator) BumpLegacyGas(_ context.Context, _ *assets.Wei, _ uint32, _ *assets.Wei, _ []EvmPriorAttempt) (bumpedGasPrice *assets.Wei, chainSpecificGasLimit uint32, err error) { + return nil, 0, errors.New("bump gas is not supported for this chain") } -func (o *l2SuggestedPriceEstimator) getGasPrice() (l2GasPrice *assets.Wei) { +func (o *SuggestedPriceEstimator) getGasPrice() (GasPrice *assets.Wei) { o.gasPriceMu.RLock() defer o.gasPriceMu.RUnlock() - return o.l2GasPrice + return o.GasPrice } diff --git a/core/chains/evm/gas/l2_suggested_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go similarity index 87% rename from core/chains/evm/gas/l2_suggested_estimator_test.go rename to core/chains/evm/gas/suggested_price_estimator_test.go index 69b3603302..808b28a3a6 100644 --- a/core/chains/evm/gas/l2_suggested_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" ) -func TestL2SuggestedEstimator(t *testing.T) { +func TestSuggestedPriceEstimator(t *testing.T) { t.Parallel() maxGasPrice := assets.NewWeiI(100) @@ -27,7 +27,7 @@ func TestL2SuggestedEstimator(t *testing.T) { t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewL2SuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "estimator is not started") }) @@ -39,7 +39,7 @@ func TestL2SuggestedEstimator(t *testing.T) { (*big.Int)(res).SetInt64(42) }) - o := gas.NewL2SuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) require.NoError(t, o.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, o.Close()) }) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) @@ -50,7 +50,7 @@ func TestL2SuggestedEstimator(t *testing.T) { t.Run("gas price is lower than user specified max gas price", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewL2SuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -68,7 +68,7 @@ func TestL2SuggestedEstimator(t *testing.T) { t.Run("gas price is lower than global max gas price", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewL2SuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -85,14 +85,14 @@ func TestL2SuggestedEstimator(t *testing.T) { t.Run("calling BumpLegacyGas always returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewL2SuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) _, _, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), gasLimit, assets.NewWeiI(10), nil) - assert.EqualError(t, err, "bump gas is not supported for this l2") + assert.EqualError(t, err, "bump gas is not supported for this chain") }) t.Run("calling GetLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewL2SuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) @@ -100,6 +100,6 @@ func TestL2SuggestedEstimator(t *testing.T) { t.Cleanup(func() { assert.NoError(t, o.Close()) }) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) - assert.EqualError(t, err, "failed to estimate l2 gas; gas price not set") + assert.EqualError(t, err, "failed to estimate gas; gas price not set") }) } diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index c8b5395d6d..0e0d0d0bd8 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -112,7 +112,8 @@ Enabled = true # Default # # - `FixedPrice` uses static configured values for gas price (can be set via API call). # - `BlockHistory` dynamically adjusts default gas price based on heuristics from mined blocks. -# - `L2Suggested` is a special mode only for use with L2 blockchains. This mode will use the gas price suggested by the rpc endpoint via `eth_gasPrice`. +# - `L2Suggested` mode is deprecated and replaced with `SuggestedPrice`. +# - `SuggestedPrice` is a mode which uses the gas price suggested by the rpc endpoint via `eth_gasPrice`. # - `Arbitrum` is a special mode only for use with Arbitrum blockchains. It uses the suggested gas price (up to `ETH_MAX_GAS_PRICE_WEI`, with `1000 gwei` default) as well as an estimated gas limit (up to `ETH_GAS_LIMIT_MAX`, with `1,000,000,000` default). # # Chainlink nodes decide what gas price to use using an `Estimator`. It ships with several simple and battle-hardened built-in estimators that should work well for almost all use-cases. Note that estimators will change their behaviour slightly depending on if you are in EIP-1559 mode or not. diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 48fb8272ac..986b98d936 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -468,7 +468,7 @@ func TestConfig_Marshal(t *testing.T) { FlagsContractAddress: mustAddress("0xae4E781a6218A8031764928E88d457937A954fC3"), GasEstimator: evmcfg.GasEstimator{ - Mode: ptr("L2Suggested"), + Mode: ptr("SuggestedPrice"), EIP1559DynamicFees: ptr(true), BumpPercent: ptr[uint16](10), BumpThreshold: ptr[uint32](6), @@ -912,7 +912,7 @@ ResendAfterThreshold = '1h0m0s' Enabled = true [EVM.GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '9.223372036854775807 ether' PriceMax = '281.474976710655 micro' PriceMin = '13 wei' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 1534a411dc..7ce0d185b1 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -257,7 +257,7 @@ ResendAfterThreshold = '1h0m0s' Enabled = true [EVM.GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '9.223372036854775807 ether' PriceMax = '281.474976710655 micro' PriceMin = '13 wei' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 4b53396b94..f44f119075 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -257,7 +257,7 @@ ResendAfterThreshold = '1h0m0s' Enabled = true [EVM.GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '9.223372036854775807 ether' PriceMax = '281.474976710655 micro' PriceMin = '13 wei' diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index daeddf2ce6..8f3b16c132 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] +### Changed + +- `L2Suggested` mode is now called `SuggestedPrice` + +### Removed + +- Removed `Optimism2` as a supported gas estimator mode + ... ## 2.7.0 - UNRELEASED diff --git a/docs/CONFIG.md b/docs/CONFIG.md index da986e0500..313e7b46aa 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -2726,7 +2726,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '1 gwei' @@ -2885,7 +2885,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '0' @@ -2963,7 +2963,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '750 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '1 gwei' @@ -3042,7 +3042,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '0' @@ -3199,7 +3199,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '1 gwei' @@ -3277,7 +3277,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '750 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '1 gwei' @@ -4383,7 +4383,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '0' @@ -4461,7 +4461,7 @@ ResendAfterThreshold = '1m0s' Enabled = true [GasEstimator] -Mode = 'L2Suggested' +Mode = 'SuggestedPrice' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '0' @@ -5004,7 +5004,8 @@ Mode controls what type of gas estimator is used. - `FixedPrice` uses static configured values for gas price (can be set via API call). - `BlockHistory` dynamically adjusts default gas price based on heuristics from mined blocks. -- `L2Suggested` is a special mode only for use with L2 blockchains. This mode will use the gas price suggested by the rpc endpoint via `eth_gasPrice`. +- `L2Suggested` mode is deprecated and replaced with `SuggestedPrice`. +- `SuggestedPrice` is a mode which uses the gas price suggested by the rpc endpoint via `eth_gasPrice`. - `Arbitrum` is a special mode only for use with Arbitrum blockchains. It uses the suggested gas price (up to `ETH_MAX_GAS_PRICE_WEI`, with `1000 gwei` default) as well as an estimated gas limit (up to `ETH_GAS_LIMIT_MAX`, with `1,000,000,000` default). Chainlink nodes decide what gas price to use using an `Estimator`. It ships with several simple and battle-hardened built-in estimators that should work well for almost all use-cases. Note that estimators will change their behaviour slightly depending on if you are in EIP-1559 mode or not. From 836ab9048781ef40b1098e9324dddfcd71f3ee5b Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Wed, 1 Nov 2023 17:18:06 -0400 Subject: [PATCH 050/327] Utilizes Lazier Fund Return for Tests (#11144) --- .gitignore | 1 + integration-tests/docker/test_env/cl_node_cluster.go | 3 ++- integration-tests/docker/test_env/test_env.go | 2 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/smoke/ocr_test.go | 2 +- integration-tests/smoke/vrfv2plus_test.go | 5 ++--- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index decea4a68a..bfd66e2a39 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ tools/clroot/db.sqlite3-wal .idea .vscode/ *.iml +debug.env # codeship *.aes diff --git a/integration-tests/docker/test_env/cl_node_cluster.go b/integration-tests/docker/test_env/cl_node_cluster.go index a717a19264..5ae90bb982 100644 --- a/integration-tests/docker/test_env/cl_node_cluster.go +++ b/integration-tests/docker/test_env/cl_node_cluster.go @@ -3,8 +3,9 @@ package test_env import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/integration-tests/client" "golang.org/x/sync/errgroup" + + "github.com/smartcontractkit/chainlink/integration-tests/client" ) var ( diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 07b193f102..40ed0d4d53 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -23,11 +23,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) var ( diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 3affd79919..aa670da1c9 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -20,7 +20,7 @@ require ( github.com/rs/zerolog v1.30.0 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.1 + github.com/smartcontractkit/chainlink-testing-framework v1.18.2 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 98685fdf88..f7b55b259f 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2368,8 +2368,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.1 h1:YznR7isiPYbywuUma5eVSyuZYwbUHIGJ2lpcJazOZgo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.1/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.2 h1:Ac/wdRDF4L479wpFT3yqn6ujb6kFTn7aq8gj9giyFHM= +github.com/smartcontractkit/chainlink-testing-framework v1.18.2/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 8d71c5d08f..8952f00d76 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -22,7 +22,7 @@ func TestOCRBasic(t *testing.T) { WithGeth(). WithMockAdapter(). WithCLNodes(6). - WithFunding(big.NewFloat(.1)). + WithFunding(big.NewFloat(.01)). WithStandardCleanup(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 408e5a95ed..d7381c9cd3 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -6,14 +6,13 @@ import ( "testing" "time" - "github.com/kelseyhightower/envconfig" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" - "github.com/ethereum/go-ethereum/common" + "github.com/kelseyhightower/envconfig" "github.com/pkg/errors" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" From ac9e6185c1008a8702d525829d8e0ed3047aff86 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 2 Nov 2023 04:35:47 -0500 Subject: [PATCH 051/327] core/chains/cosmos: remove; import from chainlink-comsos (#11136) --- core/chains/cosmos/chain.go | 317 ---------- core/chains/cosmos/cosmostxm/helpers_test.go | 15 - core/chains/cosmos/cosmostxm/key_wrapper.go | 62 -- .../cosmos/cosmostxm/keystore_adapter.go | 129 ----- core/chains/cosmos/cosmostxm/main_test.go | 17 - core/chains/cosmos/cosmostxm/orm.go | 104 ---- core/chains/cosmos/cosmostxm/orm_test.go | 76 --- core/chains/cosmos/cosmostxm/txm.go | 542 ------------------ .../cosmos/cosmostxm/txm_internal_test.go | 426 -------------- core/chains/cosmos/cosmostxm/txm_test.go | 121 ---- core/chains/cosmos/relayer_adapter.go | 50 -- core/cmd/shell.go | 5 +- core/cmd/shell_local_test.go | 9 +- core/internal/cltest/cltest.go | 9 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../mocks/relayer_chain_interoperators.go | 251 ++------ .../chainlink/relayer_chain_interoperators.go | 54 +- .../relayer_chain_interoperators_test.go | 18 +- core/services/chainlink/relayer_factory.go | 22 +- core/services/pg/channels.go | 5 +- .../0207_drop_insert_on_terra_msg.sql | 20 + core/web/loader/loader_test.go | 10 +- core/web/resolver/eth_key_test.go | 10 +- core/web/resolver/node_test.go | 11 +- core/web/resolver/resolver_test.go | 4 +- go.mod | 6 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 30 files changed, 148 insertions(+), 2161 deletions(-) delete mode 100644 core/chains/cosmos/chain.go delete mode 100644 core/chains/cosmos/cosmostxm/helpers_test.go delete mode 100644 core/chains/cosmos/cosmostxm/key_wrapper.go delete mode 100644 core/chains/cosmos/cosmostxm/keystore_adapter.go delete mode 100644 core/chains/cosmos/cosmostxm/main_test.go delete mode 100644 core/chains/cosmos/cosmostxm/orm.go delete mode 100644 core/chains/cosmos/cosmostxm/orm_test.go delete mode 100644 core/chains/cosmos/cosmostxm/txm.go delete mode 100644 core/chains/cosmos/cosmostxm/txm_internal_test.go delete mode 100644 core/chains/cosmos/cosmostxm/txm_test.go delete mode 100644 core/chains/cosmos/relayer_adapter.go create mode 100644 core/store/migrate/migrations/0207_drop_insert_on_terra_msg.sql diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go deleted file mode 100644 index e11f95d356..0000000000 --- a/core/chains/cosmos/chain.go +++ /dev/null @@ -1,317 +0,0 @@ -package cosmos - -import ( - "context" - "crypto/rand" - "fmt" - "math/big" - "time" - - "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" - "go.uber.org/multierr" - - sdk "github.com/cosmos/cosmos-sdk/types" - bank "github.com/cosmos/cosmos-sdk/x/bank/types" - - "github.com/smartcontractkit/sqlx" - - relaychains "github.com/smartcontractkit/chainlink-relay/pkg/chains" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// defaultRequestTimeout is the default Cosmos client timeout. -// Note that while the cosmos node is processing a heavy block, -// requests can be delayed significantly (https://github.com/tendermint/tendermint/issues/6899), -// however there's nothing we can do but wait until the block is processed. -// So we set a fairly high timeout here. -// TODO(BCI-979): Remove this, or make this configurable with the updated client. -const defaultRequestTimeout = 30 * time.Second - -var ( - // ErrChainIDEmpty is returned when chain is required but was empty. - ErrChainIDEmpty = errors.New("chain id empty") - // ErrChainIDInvalid is returned when a chain id does not match any configured chains. - ErrChainIDInvalid = errors.New("chain id does not match any local chains") -) - -// Chain is a wrap for easy use in other places in the core node -type Chain = adapters.Chain - -// ChainOpts holds options for configuring a Chain. -type ChainOpts struct { - QueryConfig pg.QConfig - Logger logger.Logger - DB *sqlx.DB - KeyStore loop.Keystore - EventBroadcaster pg.EventBroadcaster -} - -func (o *ChainOpts) Validate() (err error) { - required := func(s string) error { - return fmt.Errorf("%s is required", s) - } - if o.QueryConfig == nil { - err = multierr.Append(err, required("Config")) - } - if o.Logger == nil { - err = multierr.Append(err, required("Logger'")) - } - if o.DB == nil { - err = multierr.Append(err, required("DB")) - } - if o.KeyStore == nil { - err = multierr.Append(err, required("KeyStore")) - } - if o.EventBroadcaster == nil { - err = multierr.Append(err, required("EventBroadcaster")) - } - return -} - -func NewChain(cfg *coscfg.TOMLConfig, opts ChainOpts) (adapters.Chain, error) { - if !cfg.IsEnabled() { - return nil, fmt.Errorf("cannot create new chain with ID %s, the chain is disabled", *cfg.ChainID) - } - c, err := newChain(*cfg.ChainID, cfg, opts.DB, opts.KeyStore, opts.QueryConfig, opts.EventBroadcaster, opts.Logger) - if err != nil { - return nil, err - } - return c, nil -} - -var _ adapters.Chain = (*chain)(nil) - -type chain struct { - services.StateMachine - id string - cfg *coscfg.TOMLConfig - txm *cosmostxm.Txm - lggr logger.Logger -} - -func newChain(id string, cfg *coscfg.TOMLConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, lggr logger.Logger) (*chain, error) { - lggr = logger.With(lggr, "cosmosChainID", id) - var ch = chain{ - id: id, - cfg: cfg, - lggr: logger.Named(lggr, "Chain"), - } - tc := func() (client.ReaderWriter, error) { - return ch.getClient("") - } - gpe := client.NewMustGasPriceEstimator([]client.GasPricesEstimator{ - client.NewClosureGasPriceEstimator(func() (map[string]sdk.DecCoin, error) { - return map[string]sdk.DecCoin{ - cfg.GasToken(): sdk.NewDecCoinFromDec(cfg.GasToken(), cfg.FallbackGasPrice()), - }, nil - }), - }, lggr) - ch.txm = cosmostxm.NewTxm(db, tc, *gpe, ch.id, cfg, ks, lggr, logCfg, eb) - - return &ch, nil -} - -func (c *chain) Name() string { - return c.lggr.Name() -} - -func (c *chain) ID() string { - return c.id -} - -func (c *chain) ChainID() string { - return c.id -} - -func (c *chain) Config() coscfg.Config { - return c.cfg -} - -func (c *chain) TxManager() adapters.TxManager { - return c.txm -} - -func (c *chain) Reader(name string) (client.Reader, error) { - return c.getClient(name) -} - -// getClient returns a client, optionally requiring a specific node by name. -func (c *chain) getClient(name string) (client.ReaderWriter, error) { - var node db.Node - if name == "" { // Any node - nodes, err := c.cfg.ListNodes() - if err != nil { - return nil, fmt.Errorf("failed to list nodes: %w", err) - } - if len(nodes) == 0 { - return nil, errors.New("no nodes available") - } - nodeIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(nodes)))) - if err != nil { - return nil, fmt.Errorf("could not generate a random node index: %w", err) - } - node = nodes[nodeIndex.Int64()] - } else { // Named node - var err error - node, err = c.cfg.GetNode(name) - if err != nil { - return nil, fmt.Errorf("failed to get node named %s: %w", name, err) - } - if node.CosmosChainID != c.id { - return nil, fmt.Errorf("failed to create client for chain %s with node %s: wrong chain id %s", c.id, name, node.CosmosChainID) - } - } - client, err := client.NewClient(c.id, node.TendermintURL, defaultRequestTimeout, logger.Named(c.lggr, "Client."+name)) - if err != nil { - return nil, fmt.Errorf("failed to create client: %w", err) - } - c.lggr.Debugw("Created client", "name", node.Name, "tendermint-url", node.TendermintURL) - return client, nil -} - -// Start starts cosmos chain. -func (c *chain) Start(ctx context.Context) error { - return c.StartOnce("Chain", func() error { - c.lggr.Debug("Starting") - return c.txm.Start(ctx) - }) -} - -func (c *chain) Close() error { - return c.StopOnce("Chain", func() error { - c.lggr.Debug("Stopping") - return c.txm.Close() - }) -} - -func (c *chain) Ready() error { - return multierr.Combine( - c.StateMachine.Ready(), - c.txm.Ready(), - ) -} - -func (c *chain) HealthReport() map[string]error { - m := map[string]error{c.Name(): c.Healthy()} - services.CopyHealth(m, c.txm.HealthReport()) - return m -} - -// ChainService interface -func (c *chain) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - toml, err := c.cfg.TOMLString() - if err != nil { - return relaytypes.ChainStatus{}, err - } - return relaytypes.ChainStatus{ - ID: c.id, - Enabled: *c.cfg.Enabled, - Config: toml, - }, nil -} -func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return relaychains.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) -} - -func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - fromAcc, err := sdk.AccAddressFromBech32(from) - if err != nil { - return fmt.Errorf("failed to parse from account: %s", fromAcc) - } - toAcc, err := sdk.AccAddressFromBech32(to) - if err != nil { - return fmt.Errorf("failed to parse from account: %s", toAcc) - } - coin := sdk.Coin{Amount: sdk.NewIntFromBigInt(amount), Denom: c.Config().GasToken()} - - txm := c.TxManager() - - if balanceCheck { - var reader client.Reader - reader, err = c.Reader("") - if err != nil { - return fmt.Errorf("chain unreachable: %v", err) - } - gasPrice, err2 := txm.GasPrice() - if err2 != nil { - return fmt.Errorf("gas price unavailable: %v", err2) - } - - err = validateBalance(reader, gasPrice, fromAcc, coin) - if err != nil { - return fmt.Errorf("failed to validate balance: %v", err) - } - } - - sendMsg := bank.NewMsgSend(fromAcc, toAcc, sdk.Coins{coin}) - _, err = txm.Enqueue("", sendMsg) - if err != nil { - return fmt.Errorf("failed to enqueue tx: %w", err) - } - return nil -} - -// TODO BCF-2602 statuses are static for non-evm chain and should be dynamic -func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, error) { - stats := make([]relaytypes.NodeStatus, 0) - total := len(c.cfg.Nodes) - if start >= total { - return stats, total, relaychains.ErrOutOfRange - } - if end > total { - end = total - } - nodes := c.cfg.Nodes[start:end] - for _, node := range nodes { - stat, err := nodeStatus(node, c.ChainID()) - if err != nil { - return stats, total, err - } - stats = append(stats, stat) - } - return stats, total, nil -} - -func nodeStatus(n *coscfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { - var s relaytypes.NodeStatus - s.ChainID = id - s.Name = *n.Name - b, err := toml.Marshal(n) - if err != nil { - return relaytypes.NodeStatus{}, err - } - s.Config = string(b) - return s, nil -} - -// maxGasUsedTransfer is an upper bound on how much gas we expect a MsgSend for a single coin to use. -const maxGasUsedTransfer = 100_000 - -// validateBalance validates that fromAddr's balance can cover coin, including fees at gasPrice. -func validateBalance(reader client.Reader, gasPrice sdk.DecCoin, fromAddr sdk.AccAddress, coin sdk.Coin) error { - balance, err := reader.Balance(fromAddr, coin.GetDenom()) - if err != nil { - return err - } - - fee := gasPrice.Amount.MulInt64(maxGasUsedTransfer).RoundInt() - need := coin.Amount.Add(fee) - - if balance.Amount.LT(need) { - return errors.Errorf("balance %q is too low for this transaction to be executed: need %s total, including %s fee", balance, need, fee) - } - return nil -} diff --git a/core/chains/cosmos/cosmostxm/helpers_test.go b/core/chains/cosmos/cosmostxm/helpers_test.go deleted file mode 100644 index a2dfbbeed8..0000000000 --- a/core/chains/cosmos/cosmostxm/helpers_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package cosmostxm - -import "golang.org/x/exp/maps" - -func (ka *keystoreAdapter) Accounts() ([]string, error) { - ka.mutex.Lock() - defer ka.mutex.Unlock() - err := ka.updateMappingLocked() - if err != nil { - return nil, err - } - addresses := maps.Keys(ka.addressToPubKey) - - return addresses, nil -} diff --git a/core/chains/cosmos/cosmostxm/key_wrapper.go b/core/chains/cosmos/cosmostxm/key_wrapper.go deleted file mode 100644 index e03dfd89b8..0000000000 --- a/core/chains/cosmos/cosmostxm/key_wrapper.go +++ /dev/null @@ -1,62 +0,0 @@ -package cosmostxm - -import ( - "bytes" - "context" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" -) - -// KeyWrapper uses a keystoreAdapter to implement the cosmos-sdk PrivKey interface for a specific key. -type KeyWrapper struct { - adapter *keystoreAdapter - account string -} - -var _ cryptotypes.PrivKey = &KeyWrapper{} - -func NewKeyWrapper(adapter *keystoreAdapter, account string) *KeyWrapper { - return &KeyWrapper{ - adapter: adapter, - account: account, - } -} - -func (a *KeyWrapper) Bytes() []byte { - // don't expose the private key. - return nil -} - -func (a *KeyWrapper) Sign(msg []byte) ([]byte, error) { - return a.adapter.Sign(context.Background(), a.account, msg) -} - -func (a *KeyWrapper) PubKey() cryptotypes.PubKey { - pubKey, err := a.adapter.PubKey(a.account) - if err != nil { - // return an empty pubkey if it's not found. - return &secp256k1.PubKey{Key: []byte{}} - } - return pubKey -} - -func (a *KeyWrapper) Equals(other cryptotypes.LedgerPrivKey) bool { - return bytes.Equal(a.PubKey().Bytes(), other.PubKey().Bytes()) -} - -func (a *KeyWrapper) Type() string { - return "secp256k1" -} - -func (a *KeyWrapper) Reset() { - // no-op -} - -func (a *KeyWrapper) String() string { - return "" -} - -func (a *KeyWrapper) ProtoMessage() { - // no-op -} diff --git a/core/chains/cosmos/cosmostxm/keystore_adapter.go b/core/chains/cosmos/cosmostxm/keystore_adapter.go deleted file mode 100644 index 6b360dde98..0000000000 --- a/core/chains/cosmos/cosmostxm/keystore_adapter.go +++ /dev/null @@ -1,129 +0,0 @@ -package cosmostxm - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "sync" - - "github.com/cometbft/cometbft/crypto" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/types/bech32" - "github.com/pkg/errors" - "golang.org/x/crypto/ripemd160" //nolint: staticcheck - - "github.com/smartcontractkit/chainlink-relay/pkg/loop" -) - -type accountInfo struct { - Account string - PubKey *secp256k1.PubKey -} - -// keystoreAdapter adapts a Cosmos loop.Keystore to translate public keys into bech32-prefixed account addresses. -type keystoreAdapter struct { - keystore loop.Keystore - accountPrefix string - mutex sync.RWMutex - addressToPubKey map[string]*accountInfo -} - -func newKeystoreAdapter(keystore loop.Keystore, accountPrefix string) *keystoreAdapter { - return &keystoreAdapter{ - keystore: keystore, - accountPrefix: accountPrefix, - addressToPubKey: make(map[string]*accountInfo), - } -} - -func (ka *keystoreAdapter) updateMappingLocked() error { - accounts, err := ka.keystore.Accounts(context.Background()) - if err != nil { - return err - } - - // similar to cosmos-sdk, cache and re-use calculated bech32 addresses to prevent duplicated work. - // ref: https://github.com/cosmos/cosmos-sdk/blob/3b509c187e1643757f5ef8a0b5ae3decca0c7719/types/address.go#L705 - - type cacheEntry struct { - bech32Addr string - accountInfo *accountInfo - } - accountCache := make(map[string]cacheEntry, len(ka.addressToPubKey)) - for bech32Addr, accountInfo := range ka.addressToPubKey { - accountCache[accountInfo.Account] = cacheEntry{bech32Addr: bech32Addr, accountInfo: accountInfo} - } - - addressToPubKey := make(map[string]*accountInfo, len(accounts)) - for _, account := range accounts { - if prevEntry, ok := accountCache[account]; ok { - addressToPubKey[prevEntry.bech32Addr] = prevEntry.accountInfo - continue - } - pubKeyBytes, err := hex.DecodeString(account) - if err != nil { - return err - } - - if len(pubKeyBytes) != secp256k1.PubKeySize { - return errors.New("length of pubkey is incorrect") - } - - sha := sha256.Sum256(pubKeyBytes) - hasherRIPEMD160 := ripemd160.New() - _, _ = hasherRIPEMD160.Write(sha[:]) - address := crypto.Address(hasherRIPEMD160.Sum(nil)) - - bech32Addr, err := bech32.ConvertAndEncode(ka.accountPrefix, address) - if err != nil { - return err - } - - addressToPubKey[bech32Addr] = &accountInfo{ - Account: account, - PubKey: &secp256k1.PubKey{Key: pubKeyBytes}, - } - } - - ka.addressToPubKey = addressToPubKey - return nil -} - -func (ka *keystoreAdapter) lookup(id string) (*accountInfo, error) { - ka.mutex.RLock() - ai, ok := ka.addressToPubKey[id] - ka.mutex.RUnlock() - if !ok { - // try updating the mapping once, incase there was an update on the keystore. - ka.mutex.Lock() - err := ka.updateMappingLocked() - if err != nil { - ka.mutex.Unlock() - return nil, err - } - ai, ok = ka.addressToPubKey[id] - ka.mutex.Unlock() - if !ok { - return nil, errors.New("No such id") - } - } - return ai, nil -} - -func (ka *keystoreAdapter) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { - accountInfo, err := ka.lookup(id) - if err != nil { - return nil, err - } - return ka.keystore.Sign(ctx, accountInfo.Account, hash) -} - -// Returns the cosmos PubKey associated with the prefixed address. -func (ka *keystoreAdapter) PubKey(address string) (cryptotypes.PubKey, error) { - accountInfo, err := ka.lookup(address) - if err != nil { - return nil, err - } - return accountInfo.PubKey, nil -} diff --git a/core/chains/cosmos/cosmostxm/main_test.go b/core/chains/cosmos/cosmostxm/main_test.go deleted file mode 100644 index bc340afa43..0000000000 --- a/core/chains/cosmos/cosmostxm/main_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package cosmostxm - -import ( - "os" - "testing" - - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/params" -) - -func TestMain(m *testing.M) { - params.InitCosmosSdk( - /* bech32Prefix= */ "wasm", - /* token= */ "cosm", - ) - code := m.Run() - os.Exit(code) -} diff --git a/core/chains/cosmos/cosmostxm/orm.go b/core/chains/cosmos/cosmostxm/orm.go deleted file mode 100644 index cc9b179cce..0000000000 --- a/core/chains/cosmos/cosmostxm/orm.go +++ /dev/null @@ -1,104 +0,0 @@ -package cosmostxm - -import ( - "database/sql" - - "github.com/pkg/errors" - - "github.com/smartcontractkit/sqlx" - - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - - "github.com/smartcontractkit/chainlink/v2/core/services/pg" -) - -// ORM manages the data model for cosmos tx management. -type ORM struct { - chainID string - q pg.Q -} - -// NewORM creates an ORM scoped to chainID. -func NewORM(chainID string, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *ORM { - namedLogger := logger.Named(lggr, "Configs") - q := pg.NewQ(db, namedLogger, cfg) - return &ORM{ - chainID: chainID, - q: q, - } -} - -// InsertMsg inserts a cosmos msg, assumed to be a serialized cosmos ExecuteContractMsg. -func (o *ORM) InsertMsg(contractID, typeURL string, msg []byte, qopts ...pg.QOpt) (int64, error) { - var tm adapters.Msg - q := o.q.WithOpts(qopts...) - err := q.Get(&tm, `INSERT INTO cosmos_msgs (contract_id, type, raw, state, cosmos_chain_id, created_at, updated_at) - VALUES ($1, $2, $3, $4, $5, NOW(), NOW()) RETURNING *`, contractID, typeURL, msg, db.Unstarted, o.chainID) - if err != nil { - return 0, err - } - return tm.ID, nil -} - -// UpdateMsgsContract updates messages for the given contract. -func (o *ORM) UpdateMsgsContract(contractID string, from, to db.State, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - _, err := q.Exec(`UPDATE cosmos_msgs SET state = $1, updated_at = NOW() - WHERE cosmos_chain_id = $2 AND contract_id = $3 AND state = $4`, to, o.chainID, contractID, from) - if err != nil { - return err - } - return nil -} - -// GetMsgsState returns the oldest messages with a given state up to limit. -func (o *ORM) GetMsgsState(state db.State, limit int64, qopts ...pg.QOpt) (adapters.Msgs, error) { - if limit < 1 { - return adapters.Msgs{}, errors.New("limit must be greater than 0") - } - q := o.q.WithOpts(qopts...) - var msgs adapters.Msgs - if err := q.Select(&msgs, `SELECT * FROM cosmos_msgs WHERE state = $1 AND cosmos_chain_id = $2 ORDER BY id ASC LIMIT $3`, state, o.chainID, limit); err != nil { - return nil, err - } - return msgs, nil -} - -// GetMsgs returns any messages matching ids. -func (o *ORM) GetMsgs(ids ...int64) (adapters.Msgs, error) { - var msgs adapters.Msgs - if err := o.q.Select(&msgs, `SELECT * FROM cosmos_msgs WHERE id = ANY($1)`, ids); err != nil { - return nil, err - } - return msgs, nil -} - -// UpdateMsgs updates msgs with the given ids. -// Note state transitions are validated at the db level. -func (o *ORM) UpdateMsgs(ids []int64, state db.State, txHash *string, qopts ...pg.QOpt) error { - if state == db.Broadcasted && txHash == nil { - return errors.New("txHash is required when updating to broadcasted") - } - q := o.q.WithOpts(qopts...) - var res sql.Result - var err error - if state == db.Broadcasted { - res, err = q.Exec(`UPDATE cosmos_msgs SET state = $1, updated_at = NOW(), tx_hash = $2 WHERE id = ANY($3)`, state, *txHash, ids) - } else { - res, err = q.Exec(`UPDATE cosmos_msgs SET state = $1, updated_at = NOW() WHERE id = ANY($2)`, state, ids) - } - if err != nil { - return err - } - count, err := res.RowsAffected() - if err != nil { - return err - } - if int(count) != len(ids) { - return errors.Errorf("expected %d records updated, got %d", len(ids), count) - } - return nil -} diff --git a/core/chains/cosmos/cosmostxm/orm_test.go b/core/chains/cosmos/cosmostxm/orm_test.go deleted file mode 100644 index 3cee25bac1..0000000000 --- a/core/chains/cosmos/cosmostxm/orm_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package cosmostxm - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - cosmosdb "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -func TestORM(t *testing.T) { - db := pgtest.NewSqlxDB(t) - lggr := logger.TestLogger(t) - logCfg := pgtest.NewQConfig(true) - chainID := cosmostest.RandomChainID() - o := NewORM(chainID, db, lggr, logCfg) - - // Create - mid, err := o.InsertMsg("0x123", "", []byte("hello")) - require.NoError(t, err) - assert.NotEqual(t, 0, int(mid)) - - // Read - unstarted, err := o.GetMsgsState(cosmosdb.Unstarted, 5) - require.NoError(t, err) - require.Equal(t, 1, len(unstarted)) - assert.Equal(t, "hello", string(unstarted[0].Raw)) - assert.Equal(t, chainID, unstarted[0].ChainID) - t.Log(unstarted[0].UpdatedAt, unstarted[0].CreatedAt) - - // Limit - unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, 0) - assert.Error(t, err) - assert.Empty(t, unstarted) - unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, -1) - assert.Error(t, err) - assert.Empty(t, unstarted) - mid2, err := o.InsertMsg("0xabc", "", []byte("test")) - require.NoError(t, err) - assert.NotEqual(t, 0, int(mid2)) - unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, 1) - require.NoError(t, err) - require.Equal(t, 1, len(unstarted)) - assert.Equal(t, "hello", string(unstarted[0].Raw)) - assert.Equal(t, chainID, unstarted[0].ChainID) - unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, 2) - require.NoError(t, err) - require.Equal(t, 2, len(unstarted)) - assert.Equal(t, "test", string(unstarted[1].Raw)) - assert.Equal(t, chainID, unstarted[1].ChainID) - - // Update - txHash := "123" - err = o.UpdateMsgs([]int64{mid}, cosmosdb.Started, &txHash) - require.NoError(t, err) - err = o.UpdateMsgs([]int64{mid}, cosmosdb.Broadcasted, &txHash) - require.NoError(t, err) - broadcasted, err := o.GetMsgsState(cosmosdb.Broadcasted, 5) - require.NoError(t, err) - require.Equal(t, 1, len(broadcasted)) - assert.Equal(t, broadcasted[0].Raw, unstarted[0].Raw) - require.NotNil(t, broadcasted[0].TxHash) - assert.Equal(t, *broadcasted[0].TxHash, txHash) - assert.Equal(t, chainID, broadcasted[0].ChainID) - - err = o.UpdateMsgs([]int64{mid}, cosmosdb.Confirmed, nil) - require.NoError(t, err) - confirmed, err := o.GetMsgsState(cosmosdb.Confirmed, 5) - require.NoError(t, err) - require.Equal(t, 1, len(confirmed)) -} diff --git a/core/chains/cosmos/cosmostxm/txm.go b/core/chains/cosmos/cosmostxm/txm.go deleted file mode 100644 index 712e1b8fc7..0000000000 --- a/core/chains/cosmos/cosmostxm/txm.go +++ /dev/null @@ -1,542 +0,0 @@ -package cosmostxm - -import ( - "cmp" - "context" - "encoding/hex" - "fmt" - "slices" - "strings" - "time" - - "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" - - "github.com/smartcontractkit/sqlx" - - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/cometbft/cometbft/crypto/tmhash" - sdk "github.com/cosmos/cosmos-sdk/types" - txtypes "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/x/bank/types" - - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -var ( - _ services.Service = (*Txm)(nil) - _ adapters.TxManager = (*Txm)(nil) -) - -// Txm manages transactions for the cosmos blockchain. -type Txm struct { - services.StateMachine - eb pg.EventBroadcaster - sub pg.Subscription - orm *ORM - lggr logger.Logger - tc func() (cosmosclient.ReaderWriter, error) - keystoreAdapter *keystoreAdapter - stop, done chan struct{} - cfg coscfg.Config - gpe cosmosclient.ComposedGasPriceEstimator -} - -// NewTxm creates a txm. Uses simulation so should only be used to send txes to trusted contracts i.e. OCR. -func NewTxm(db *sqlx.DB, tc func() (cosmosclient.ReaderWriter, error), gpe cosmosclient.ComposedGasPriceEstimator, chainID string, cfg coscfg.Config, ks loop.Keystore, lggr logger.Logger, logCfg pg.QConfig, eb pg.EventBroadcaster) *Txm { - lggr = logger.Named(lggr, "Txm") - keystoreAdapter := newKeystoreAdapter(ks, cfg.Bech32Prefix()) - return &Txm{ - eb: eb, - orm: NewORM(chainID, db, lggr, logCfg), - lggr: lggr, - tc: tc, - keystoreAdapter: keystoreAdapter, - stop: make(chan struct{}), - done: make(chan struct{}), - cfg: cfg, - gpe: gpe, - } -} - -// Start subscribes to pg notifications about cosmos msg inserts and processes them. -func (txm *Txm) Start(context.Context) error { - return txm.StartOnce("Txm", func() error { - sub, err := txm.eb.Subscribe(pg.ChannelInsertOnCosmosMsg, "") - if err != nil { - return err - } - txm.sub = sub - go txm.run() - return nil - }) -} - -func (txm *Txm) confirmAnyUnconfirmed(ctx context.Context) { - // Confirm any broadcasted but not confirmed txes. - // This is an edge case if we crash after having broadcasted but before we confirm. - for { - broadcasted, err := txm.orm.GetMsgsState(db.Broadcasted, txm.cfg.MaxMsgsPerBatch()) - if err != nil { - // Should never happen but if so, theoretically can retry with a reboot - logger.Criticalw(txm.lggr, "unable to look for broadcasted but unconfirmed txes", "err", err) - return - } - if len(broadcasted) == 0 { - return - } - tc, err := txm.tc() - if err != nil { - logger.Criticalw(txm.lggr, "unable to get client for handling broadcasted but unconfirmed txes", "count", len(broadcasted), "err", err) - return - } - msgsByTxHash := make(map[string]adapters.Msgs) - for _, msg := range broadcasted { - msgsByTxHash[*msg.TxHash] = append(msgsByTxHash[*msg.TxHash], msg) - } - for txHash, msgs := range msgsByTxHash { - maxPolls, pollPeriod := txm.confirmPollConfig() - err := txm.confirmTx(ctx, tc, txHash, msgs.GetIDs(), maxPolls, pollPeriod) - if err != nil { - txm.lggr.Errorw("unable to confirm broadcasted but unconfirmed txes", "err", err, "txhash", txHash) - if ctx.Err() != nil { - return - } - } - } - } -} - -func (txm *Txm) run() { - defer close(txm.done) - ctx, cancel := utils.StopChan(txm.stop).NewCtx() - defer cancel() - txm.confirmAnyUnconfirmed(ctx) - // Jitter in case we have multiple cosmos chains each with their own client. - tick := time.After(utils.WithJitter(txm.cfg.BlockRate())) - for { - select { - case <-txm.sub.Events(): - txm.sendMsgBatch(ctx) - case <-tick: - txm.sendMsgBatch(ctx) - tick = time.After(utils.WithJitter(txm.cfg.BlockRate())) - case <-txm.stop: - return - } - } -} - -var ( - typeMsgSend = sdk.MsgTypeURL(&types.MsgSend{}) - typeMsgExecuteContract = sdk.MsgTypeURL(&wasmtypes.MsgExecuteContract{}) -) - -func unmarshalMsg(msgType string, raw []byte) (sdk.Msg, string, error) { - switch msgType { - case typeMsgSend: - var ms types.MsgSend - err := ms.Unmarshal(raw) - if err != nil { - return nil, "", err - } - return &ms, ms.FromAddress, nil - case typeMsgExecuteContract: - var ms wasmtypes.MsgExecuteContract - err := ms.Unmarshal(raw) - if err != nil { - return nil, "", err - } - return &ms, ms.Sender, nil - } - return nil, "", errors.Errorf("unrecognized message type: %s", msgType) -} - -type msgValidator struct { - cutoff time.Time - expired, valid adapters.Msgs -} - -func (e *msgValidator) add(msg adapters.Msg) { - if msg.CreatedAt.Before(e.cutoff) { - e.expired = append(e.expired, msg) - } else { - e.valid = append(e.valid, msg) - } -} - -func (e *msgValidator) sortValid() { - slices.SortFunc(e.valid, func(a, b adapters.Msg) int { - ac, bc := a.CreatedAt, b.CreatedAt - if ac.Equal(bc) { - return cmp.Compare(a.ID, b.ID) - } - if ac.After(bc) { - return 1 - } - return -1 // ac.Before(bc) - }) -} - -func (txm *Txm) sendMsgBatch(ctx context.Context) { - msgs := msgValidator{cutoff: time.Now().Add(-txm.cfg.TxMsgTimeout())} - err := txm.orm.q.Transaction(func(tx pg.Queryer) error { - // There may be leftover Started messages after a crash or failed send attempt. - started, err := txm.orm.GetMsgsState(db.Started, txm.cfg.MaxMsgsPerBatch(), pg.WithQueryer(tx)) - if err != nil { - txm.lggr.Errorw("unable to read unstarted msgs", "err", err) - return err - } - if limit := txm.cfg.MaxMsgsPerBatch() - int64(len(started)); limit > 0 { - // Use the remaining batch budget for Unstarted - unstarted, err := txm.orm.GetMsgsState(db.Unstarted, limit, pg.WithQueryer(tx)) //nolint - if err != nil { - txm.lggr.Errorw("unable to read unstarted msgs", "err", err) - return err - } - for _, msg := range unstarted { - msgs.add(msg) - } - // Update valid, Unstarted messages to Started - err = txm.orm.UpdateMsgs(msgs.valid.GetIDs(), db.Started, nil, pg.WithQueryer(tx)) - if err != nil { - // Assume transient db error retry - txm.lggr.Errorw("unable to mark unstarted txes as started", "err", err) - return err - } - } - for _, msg := range started { - msgs.add(msg) - } - // Update expired messages (Unstarted or Started) to Errored - err = txm.orm.UpdateMsgs(msgs.expired.GetIDs(), db.Errored, nil, pg.WithQueryer(tx)) - if err != nil { - // Assume transient db error retry - txm.lggr.Errorw("unable to mark expired txes as errored", "err", err) - return err - } - return nil - }) - if err != nil { - return - } - if len(msgs.valid) == 0 { - return - } - msgs.sortValid() - txm.lggr.Debugw("building a batch", "not expired", msgs.valid, "marked expired", msgs.expired) - var msgsByFrom = make(map[string]adapters.Msgs) - for _, m := range msgs.valid { - msg, sender, err2 := unmarshalMsg(m.Type, m.Raw) - if err2 != nil { - // Should be impossible given the check in Enqueue - logger.Criticalw(txm.lggr, "Failed to unmarshal msg, skipping", "err", err2, "msg", m) - continue - } - m.DecodedMsg = msg - _, err2 = sdk.AccAddressFromBech32(sender) - if err2 != nil { - // Should never happen, we parse sender on Enqueue - logger.Criticalw(txm.lggr, "Unable to parse sender", "err", err2, "sender", sender) - continue - } - msgsByFrom[sender] = append(msgsByFrom[sender], m) - } - - txm.lggr.Debugw("msgsByFrom", "msgsByFrom", msgsByFrom) - gasPrice, err := txm.GasPrice() - if err != nil { - // Should be impossible - logger.Criticalw(txm.lggr, "Failed to get gas price", "err", err) - return - } - for s, msgs := range msgsByFrom { - sender, _ := sdk.AccAddressFromBech32(s) // Already checked validity above - err := txm.sendMsgBatchFromAddress(ctx, gasPrice, sender, msgs) - if err != nil { - txm.lggr.Errorw("Could not send message batch", "err", err, "from", sender.String()) - continue - } - if ctx.Err() != nil { - return - } - } - -} - -func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoin, sender sdk.AccAddress, msgs adapters.Msgs) error { - tc, err := txm.tc() - if err != nil { - logger.Criticalw(txm.lggr, "unable to get client", "err", err) - return err - } - an, sn, err := tc.Account(sender) - if err != nil { - txm.lggr.Warnw("unable to read account", "err", err, "from", sender.String()) - // If we can't read the account, assume transient api issues and leave msgs unstarted - // to retry on next poll. - return err - } - - txm.lggr.Debugw("simulating batch", "from", sender, "msgs", msgs, "seqnum", sn) - simResults, err := tc.BatchSimulateUnsigned(msgs.GetSimMsgs(), sn) - if err != nil { - txm.lggr.Warnw("unable to simulate", "err", err, "from", sender.String()) - // If we can't simulate assume transient api issue and retry on next poll. - // Note one rare scenario in which this can happen: the cosmos node misbehaves - // in that it confirms a txhash is present but still gives an old seq num. - // This is benign as the next retry will succeeds. - return err - } - txm.lggr.Debugw("simulation results", "from", sender, "succeeded", simResults.Succeeded, "failed", simResults.Failed) - err = txm.orm.UpdateMsgs(simResults.Failed.GetSimMsgsIDs(), db.Errored, nil) - if err != nil { - txm.lggr.Errorw("unable to mark failed sim txes as errored", "err", err, "from", sender.String()) - // If we can't mark them as failed retry on next poll. Presumably same ones will fail. - return err - } - - // Continue if there are no successful txes - if len(simResults.Succeeded) == 0 { - txm.lggr.Warnw("all sim msgs errored, not sending tx", "from", sender.String()) - return errors.New("all sim msgs errored") - } - // Get the gas limit for the successful batch - s, err := tc.SimulateUnsigned(simResults.Succeeded.GetMsgs(), sn) - if err != nil { - // In the OCR context this should only happen upon stale report - txm.lggr.Warnw("unexpected failure after successful simulation", "err", err) - return err - } - gasLimit := s.GasInfo.GasUsed - - lb, err := tc.LatestBlock() - if err != nil { - txm.lggr.Warnw("unable to get latest block", "err", err, "from", sender.String()) - // Assume transient api issue and retry. - return err - } - header, timeout := lb.SdkBlock.Header.Height, txm.cfg.BlocksUntilTxTimeout() - if header < 0 { - return fmt.Errorf("invalid negative header height: %d", header) - } else if timeout < 0 { - return fmt.Errorf("invalid negative blocks until tx timeout: %d", timeout) - } - timeoutHeight := uint64(header) + uint64(timeout) - signedTx, err := tc.CreateAndSign(simResults.Succeeded.GetMsgs(), an, sn, gasLimit, txm.cfg.GasLimitMultiplier(), - gasPrice, NewKeyWrapper(txm.keystoreAdapter, sender.String()), timeoutHeight) - if err != nil { - txm.lggr.Errorw("unable to sign tx", "err", err, "from", sender.String()) - return err - } - - // We need to ensure that we either broadcast successfully and mark the tx as - // broadcasted OR we do not broadcast successfully and we do not mark it as broadcasted. - // We do this by first marking it broadcasted then rolling back if the broadcast api call fails. - // There is still a small chance of network failure or node/db crash after broadcasting but before committing the tx, - // in which case the msgs would be picked up again and re-broadcast, ensuring at-least once delivery. - var resp *txtypes.BroadcastTxResponse - err = txm.orm.q.Transaction(func(tx pg.Queryer) error { - txHash := strings.ToUpper(hex.EncodeToString(tmhash.Sum(signedTx))) - err = txm.orm.UpdateMsgs(simResults.Succeeded.GetSimMsgsIDs(), db.Broadcasted, &txHash, pg.WithQueryer(tx)) - if err != nil { - return err - } - - txm.lggr.Infow("broadcasting tx", "from", sender, "msgs", simResults.Succeeded, "gasLimit", gasLimit, "gasPrice", gasPrice.String(), "timeoutHeight", timeoutHeight, "hash", txHash) - resp, err = tc.Broadcast(signedTx, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) - if err != nil { - // Rollback marking as broadcasted - // Note can happen if the node's mempool is full, where we expect errCode 20. - return err - } - if resp.TxResponse == nil { - // Rollback marking as broadcasted - return errors.New("unexpected nil tx response") - } - if resp.TxResponse.TxHash != txHash { - // Should never happen - logger.Criticalw(txm.lggr, "txhash mismatch", "got", resp.TxResponse.TxHash, "want", txHash) - } - return nil - }) - if err != nil { - txm.lggr.Errorw("error broadcasting tx", "err", err, "from", sender.String()) - // Was unable to broadcast, retry on next poll - return err - } - - maxPolls, pollPeriod := txm.confirmPollConfig() - if err := txm.confirmTx(ctx, tc, resp.TxResponse.TxHash, simResults.Succeeded.GetSimMsgsIDs(), maxPolls, pollPeriod); err != nil { - txm.lggr.Errorw("error confirming tx", "err", err, "hash", resp.TxResponse.TxHash) - return err - } - - return nil -} - -func (txm *Txm) confirmPollConfig() (maxPolls int, pollPeriod time.Duration) { - blocks := txm.cfg.BlocksUntilTxTimeout() - blockPeriod := txm.cfg.BlockRate() - pollPeriod = txm.cfg.ConfirmPollPeriod() - if pollPeriod == 0 { - // don't divide by zero - maxPolls = 1 - } else { - maxPolls = int((time.Duration(blocks) * blockPeriod) / pollPeriod) - } - return -} - -func (txm *Txm) confirmTx(ctx context.Context, tc cosmosclient.Reader, txHash string, broadcasted []int64, maxPolls int, pollPeriod time.Duration) error { - // We either mark these broadcasted txes as confirmed or errored. - // Confirmed: we see the txhash onchain. There are no reorgs in cosmos chains. - // Errored: we do not see the txhash onchain after waiting for N blocks worth - // of time (plus a small buffer to account for block time variance) where N - // is TimeoutHeight - HeightAtBroadcast. In other words, if we wait for that long - // and the tx is not confirmed, we know it has timed out. - for tries := 0; tries < maxPolls; tries++ { - // Jitter in-case we're confirming multiple txes in parallel for different keys - select { - case <-ctx.Done(): - return ctx.Err() - case <-time.After(utils.WithJitter(pollPeriod)): - } - // Confirm that this tx is onchain, ensuring the sequence number has incremented - // so we can build a new batch - tx, err := tc.Tx(txHash) - if err != nil { - if strings.Contains(err.Error(), "not found") { - txm.lggr.Infow("txhash not found yet, still confirming", "hash", txHash) - } else { - txm.lggr.Errorw("error looking for hash of tx", "err", err, "hash", txHash) - } - continue - } - // Sanity check - if tx.TxResponse == nil || tx.TxResponse.TxHash != txHash { - txm.lggr.Errorw("error looking for hash of tx, unexpected response", "tx", tx, "hash", txHash) - continue - } - - txm.lggr.Infow("successfully sent batch", "hash", txHash, "msgs", broadcasted) - // If confirmed mark these as completed. - err = txm.orm.UpdateMsgs(broadcasted, db.Confirmed, nil) - if err != nil { - return err - } - return nil - } - txm.lggr.Errorw("unable to confirm tx after timeout period, marking errored", "hash", txHash) - // If we are unable to confirm the tx after the timeout period - // mark these msgs as errored - err := txm.orm.UpdateMsgs(broadcasted, db.Errored, nil) - if err != nil { - txm.lggr.Errorw("unable to mark timed out txes as errored", "err", err, "txes", broadcasted, "num", len(broadcasted)) - return err - } - return nil -} - -// Enqueue enqueue a msg destined for the cosmos chain. -func (txm *Txm) Enqueue(contractID string, msg sdk.Msg) (int64, error) { - typeURL, raw, err := txm.marshalMsg(msg) - if err != nil { - return 0, err - } - - // We could consider simulating here too, but that would - // introduce another network call and essentially double - // the enqueue time. Enqueue is used in the context of OCRs Transmit - // and must be fast, so we do the minimum. - - var id int64 - err = txm.orm.q.Transaction(func(tx pg.Queryer) (err error) { - // cancel any unstarted msgs (normally just one) - err = txm.orm.UpdateMsgsContract(contractID, db.Unstarted, db.Errored, pg.WithQueryer(tx)) - if err != nil { - return err - } - id, err = txm.orm.InsertMsg(contractID, typeURL, raw, pg.WithQueryer(tx)) - return err - }) - return id, err -} - -func (txm *Txm) marshalMsg(msg sdk.Msg) (string, []byte, error) { - switch ms := msg.(type) { - case *wasmtypes.MsgExecuteContract: - _, err := sdk.AccAddressFromBech32(ms.Sender) - if err != nil { - txm.lggr.Errorw("failed to parse sender, skipping", "err", err, "sender", ms.Sender) - return "", nil, err - } - - case *types.MsgSend: - _, err := sdk.AccAddressFromBech32(ms.FromAddress) - if err != nil { - txm.lggr.Errorw("failed to parse sender, skipping", "err", err, "sender", ms.FromAddress) - return "", nil, err - } - - default: - return "", nil, &cosmos.ErrMsgUnsupported{Msg: msg} - } - typeURL := sdk.MsgTypeURL(msg) - raw, err := proto.Marshal(msg) - if err != nil { - txm.lggr.Errorw("failed to marshal msg, skipping", "err", err, "msg", msg) - return "", nil, err - } - return typeURL, raw, nil -} - -// GetMsgs returns any messages matching ids. -func (txm *Txm) GetMsgs(ids ...int64) (adapters.Msgs, error) { - return txm.orm.GetMsgs(ids...) -} - -// GasPrice returns the gas price from the estimator in the configured fee token. -func (txm *Txm) GasPrice() (sdk.DecCoin, error) { - prices := txm.gpe.GasPrices() - gasPrice, ok := prices[txm.cfg.GasToken()] - if !ok { - return sdk.DecCoin{}, errors.New("unexpected empty gas price") - } - return gasPrice, nil -} - -// Close close service -func (txm *Txm) Close() error { - return txm.StopOnce("Txm", func() error { - txm.sub.Close() - close(txm.stop) - <-txm.done - return nil - }) -} - -func (txm *Txm) Name() string { return txm.lggr.Name() } - -// Healthy service is healthy -func (txm *Txm) Healthy() error { - return nil -} - -// Ready service is ready -func (txm *Txm) Ready() error { - return nil -} - -func (txm *Txm) HealthReport() map[string]error { return map[string]error{txm.Name(): txm.Healthy()} } diff --git a/core/chains/cosmos/cosmostxm/txm_internal_test.go b/core/chains/cosmos/cosmostxm/txm_internal_test.go deleted file mode 100644 index f29f130cae..0000000000 --- a/core/chains/cosmos/cosmostxm/txm_internal_test.go +++ /dev/null @@ -1,426 +0,0 @@ -package cosmostxm - -import ( - "fmt" - "testing" - "time" - - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - tmservicetypes "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" - cosmostypes "github.com/cosmos/cosmos-sdk/types" - txtypes "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" - tcmocks "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client/mocks" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - cosmosdb "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - relayutils "github.com/smartcontractkit/chainlink-relay/pkg/utils" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func generateExecuteMsg(msg []byte, from, to cosmostypes.AccAddress) cosmostypes.Msg { - return &wasmtypes.MsgExecuteContract{ - Sender: from.String(), - Contract: to.String(), - Msg: msg, - Funds: cosmostypes.Coins{}, - } -} - -func newReaderWriterMock(t *testing.T) *tcmocks.ReaderWriter { - tc := new(tcmocks.ReaderWriter) - tc.Test(t) - t.Cleanup(func() { tc.AssertExpectations(t) }) - return tc -} - -func TestTxm(t *testing.T) { - db := pgtest.NewSqlxDB(t) - lggr := testutils.LoggerAssertMaxLevel(t, zapcore.ErrorLevel) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) - require.NoError(t, ks.Unlock("blah")) - - for i := 0; i < 4; i++ { - _, err := ks.Cosmos().Create() - require.NoError(t, err) - } - - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - adapter := newKeystoreAdapter(loopKs, "wasm") - accounts, err := adapter.Accounts() - require.NoError(t, err) - require.Equal(t, len(accounts), 4) - - sender1, err := cosmostypes.AccAddressFromBech32(accounts[0]) - require.NoError(t, err) - sender2, err := cosmostypes.AccAddressFromBech32(accounts[1]) - require.NoError(t, err) - contract, err := cosmostypes.AccAddressFromBech32(accounts[2]) - require.NoError(t, err) - contract2, err := cosmostypes.AccAddressFromBech32(accounts[3]) - require.NoError(t, err) - - logCfg := pgtest.NewQConfig(true) - chainID := cosmostest.RandomChainID() - two := int64(2) - gasToken := "ucosm" - cfg := &coscfg.TOMLConfig{Chain: coscfg.Chain{ - MaxMsgsPerBatch: &two, - GasToken: &gasToken, - }} - cfg.SetDefaults() - gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ - cosmosclient.NewFixedGasPriceEstimator(map[string]cosmostypes.DecCoin{ - cfg.GasToken(): cosmostypes.NewDecCoinFromDec(cfg.GasToken(), cosmostypes.MustNewDecFromStr("0.01")), - }, - lggr.(logger.SugaredLogger), - ), - }, lggr) - - t.Run("single msg", func(t *testing.T) { - tc := newReaderWriterMock(t) - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, logCfg, nil) - - // Enqueue a single msg, then send it in a batch - id1, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`1`), sender1, contract)) - require.NoError(t, err) - tc.On("Account", mock.Anything).Return(uint64(0), uint64(0), nil) - tc.On("BatchSimulateUnsigned", mock.Anything, mock.Anything).Return(&cosmosclient.BatchSimResults{ - Failed: nil, - Succeeded: cosmosclient.SimMsgs{{ID: id1, Msg: &wasmtypes.MsgExecuteContract{ - Sender: sender1.String(), - Msg: []byte(`1`), - }}}, - }, nil) - tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ - GasUsed: 1_000_000, - }}, nil) - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ - Header: tmservicetypes.Header{Height: 1}, - }}, nil) - tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil) - - txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} - tc.On("Broadcast", mock.Anything, mock.Anything).Return(&txtypes.BroadcastTxResponse{TxResponse: txResp}, nil) - tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil) - txm.sendMsgBatch(testutils.Context(t)) - - // Should be in completed state - completed, err := txm.orm.GetMsgs(id1) - require.NoError(t, err) - require.Equal(t, 1, len(completed)) - assert.Equal(t, completed[0].State, cosmosdb.Confirmed) - }) - - t.Run("two msgs different accounts", func(t *testing.T) { - tc := newReaderWriterMock(t) - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) - - id1, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`0`), sender1, contract)) - require.NoError(t, err) - id2, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`1`), sender2, contract)) - require.NoError(t, err) - - tc.On("Account", mock.Anything).Return(uint64(0), uint64(0), nil).Once() - // Note this must be arg dependent, we don't know which order - // the procesing will happen in (map iteration by from address). - tc.On("BatchSimulateUnsigned", cosmosclient.SimMsgs{ - { - ID: id2, - Msg: &wasmtypes.MsgExecuteContract{ - Sender: sender2.String(), - Msg: []byte(`1`), - Contract: contract.String(), - }, - }, - }, mock.Anything).Return(&cosmosclient.BatchSimResults{ - Failed: nil, - Succeeded: cosmosclient.SimMsgs{ - { - ID: id2, - Msg: &wasmtypes.MsgExecuteContract{ - Sender: sender2.String(), - Msg: []byte(`1`), - Contract: contract.String(), - }, - }, - }, - }, nil).Once() - tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ - GasUsed: 1_000_000, - }}, nil).Once() - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ - Header: tmservicetypes.Header{Height: 1}, - }}, nil).Once() - tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil).Once() - txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} - tc.On("Broadcast", mock.Anything, mock.Anything).Return(&txtypes.BroadcastTxResponse{TxResponse: txResp}, nil).Once() - tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil).Once() - txm.sendMsgBatch(testutils.Context(t)) - - // Should be in completed state - completed, err := txm.orm.GetMsgs(id1, id2) - require.NoError(t, err) - require.Equal(t, 2, len(completed)) - assert.Equal(t, cosmosdb.Errored, completed[0].State) // cancelled - assert.Equal(t, cosmosdb.Confirmed, completed[1].State) - }) - - t.Run("two msgs different contracts", func(t *testing.T) { - tc := newReaderWriterMock(t) - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) - - id1, err := txm.Enqueue(contract.String(), generateExecuteMsg([]byte(`0`), sender1, contract)) - require.NoError(t, err) - id2, err := txm.Enqueue(contract2.String(), generateExecuteMsg([]byte(`1`), sender2, contract2)) - require.NoError(t, err) - ids := []int64{id1, id2} - senders := []string{sender1.String(), sender2.String()} - contracts := []string{contract.String(), contract2.String()} - for i := 0; i < 2; i++ { - tc.On("Account", mock.Anything).Return(uint64(0), uint64(0), nil).Once() - // Note this must be arg dependent, we don't know which order - // the procesing will happen in (map iteration by from address). - tc.On("BatchSimulateUnsigned", cosmosclient.SimMsgs{ - { - ID: ids[i], - Msg: &wasmtypes.MsgExecuteContract{ - Sender: senders[i], - Msg: []byte(fmt.Sprintf(`%d`, i)), - Contract: contracts[i], - }, - }, - }, mock.Anything).Return(&cosmosclient.BatchSimResults{ - Failed: nil, - Succeeded: cosmosclient.SimMsgs{ - { - ID: ids[i], - Msg: &wasmtypes.MsgExecuteContract{ - Sender: senders[i], - Msg: []byte(fmt.Sprintf(`%d`, i)), - Contract: contracts[i], - }, - }, - }, - }, nil).Once() - tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ - GasUsed: 1_000_000, - }}, nil).Once() - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ - Header: tmservicetypes.Header{Height: 1}, - }}, nil).Once() - tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil).Once() - } - txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} - tc.On("Broadcast", mock.Anything, mock.Anything).Return(&txtypes.BroadcastTxResponse{TxResponse: txResp}, nil).Twice() - tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil).Twice() - txm.sendMsgBatch(testutils.Context(t)) - - // Should be in completed state - completed, err := txm.orm.GetMsgs(id1, id2) - require.NoError(t, err) - require.Equal(t, 2, len(completed)) - assert.Equal(t, cosmosdb.Confirmed, completed[0].State) - assert.Equal(t, cosmosdb.Confirmed, completed[1].State) - }) - - t.Run("failed to confirm", func(t *testing.T) { - tc := newReaderWriterMock(t) - tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{ - Tx: &txtypes.Tx{}, - TxResponse: &cosmostypes.TxResponse{TxHash: "0x123"}, - }, errors.New("not found")).Twice() - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) - i, err := txm.orm.InsertMsg("blah", "", []byte{0x01}) - require.NoError(t, err) - txh := "0x123" - require.NoError(t, txm.orm.UpdateMsgs([]int64{i}, cosmosdb.Started, &txh)) - require.NoError(t, txm.orm.UpdateMsgs([]int64{i}, cosmosdb.Broadcasted, &txh)) - err = txm.confirmTx(testutils.Context(t), tc, txh, []int64{i}, 2, 1*time.Millisecond) - require.NoError(t, err) - m, err := txm.orm.GetMsgs(i) - require.NoError(t, err) - require.Equal(t, 1, len(m)) - assert.Equal(t, cosmosdb.Errored, m[0].State) - }) - - t.Run("confirm any unconfirmed", func(t *testing.T) { - require.Equal(t, int64(2), cfg.MaxMsgsPerBatch()) - txHash1 := "0x1234" - txHash2 := "0x1235" - txHash3 := "0xabcd" - tc := newReaderWriterMock(t) - tc.On("Tx", txHash1).Return(&txtypes.GetTxResponse{ - TxResponse: &cosmostypes.TxResponse{TxHash: txHash1}, - }, nil).Once() - tc.On("Tx", txHash2).Return(&txtypes.GetTxResponse{ - TxResponse: &cosmostypes.TxResponse{TxHash: txHash2}, - }, nil).Once() - tc.On("Tx", txHash3).Return(&txtypes.GetTxResponse{ - TxResponse: &cosmostypes.TxResponse{TxHash: txHash3}, - }, nil).Once() - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) - - // Insert and broadcast 3 msgs with different txhashes. - id1, err := txm.orm.InsertMsg("blah", "", []byte{0x01}) - require.NoError(t, err) - id2, err := txm.orm.InsertMsg("blah", "", []byte{0x02}) - require.NoError(t, err) - id3, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) - require.NoError(t, err) - err = txm.orm.UpdateMsgs([]int64{id1}, cosmosdb.Started, &txHash1) - require.NoError(t, err) - err = txm.orm.UpdateMsgs([]int64{id2}, cosmosdb.Started, &txHash2) - require.NoError(t, err) - err = txm.orm.UpdateMsgs([]int64{id3}, cosmosdb.Started, &txHash3) - require.NoError(t, err) - err = txm.orm.UpdateMsgs([]int64{id1}, cosmosdb.Broadcasted, &txHash1) - require.NoError(t, err) - err = txm.orm.UpdateMsgs([]int64{id2}, cosmosdb.Broadcasted, &txHash2) - require.NoError(t, err) - err = txm.orm.UpdateMsgs([]int64{id3}, cosmosdb.Broadcasted, &txHash3) - require.NoError(t, err) - - // Confirm them as in a restart while confirming scenario - txm.confirmAnyUnconfirmed(testutils.Context(t)) - msgs, err := txm.orm.GetMsgs(id1, id2, id3) - require.NoError(t, err) - require.Equal(t, 3, len(msgs)) - assert.Equal(t, cosmosdb.Confirmed, msgs[0].State) - assert.Equal(t, cosmosdb.Confirmed, msgs[1].State) - assert.Equal(t, cosmosdb.Confirmed, msgs[2].State) - }) - - t.Run("expired msgs", func(t *testing.T) { - tc := new(tcmocks.ReaderWriter) - timeout, err := relayutils.NewDuration(1 * time.Millisecond) - require.NoError(t, err) - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - two := int64(2) - cfgShortExpiry := &coscfg.TOMLConfig{Chain: coscfg.Chain{ - MaxMsgsPerBatch: &two, - TxMsgTimeout: &timeout, - }} - cfgShortExpiry.SetDefaults() - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := NewTxm(db, tcFn, *gpe, chainID, cfgShortExpiry, loopKs, lggr, pgtest.NewQConfig(true), nil) - - // Send a single one expired - id1, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) - require.NoError(t, err) - time.Sleep(1 * time.Millisecond) - txm.sendMsgBatch(testutils.Context(t)) - // Should be marked errored - m, err := txm.orm.GetMsgs(id1) - require.NoError(t, err) - assert.Equal(t, cosmosdb.Errored, m[0].State) - - // Send a batch which is all expired - id2, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) - require.NoError(t, err) - id3, err := txm.orm.InsertMsg("blah", "", []byte{0x03}) - require.NoError(t, err) - time.Sleep(1 * time.Millisecond) - txm.sendMsgBatch(testutils.Context(t)) - require.NoError(t, err) - ms, err := txm.orm.GetMsgs(id2, id3) - require.NoError(t, err) - assert.Equal(t, cosmosdb.Errored, ms[0].State) - assert.Equal(t, cosmosdb.Errored, ms[1].State) - }) - - t.Run("started msgs", func(t *testing.T) { - tc := new(tcmocks.ReaderWriter) - tc.On("Account", mock.Anything).Return(uint64(0), uint64(0), nil) - tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ - GasUsed: 1_000_000, - }}, nil) - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ - Header: tmservicetypes.Header{Height: 1}, - }}, nil) - tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil) - txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} - tc.On("Broadcast", mock.Anything, mock.Anything).Return(&txtypes.BroadcastTxResponse{TxResponse: txResp}, nil) - tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{Tx: &txtypes.Tx{}, TxResponse: txResp}, nil) - tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - two := int64(2) - cfgMaxMsgs := &coscfg.TOMLConfig{Chain: coscfg.Chain{ - MaxMsgsPerBatch: &two, - }} - cfgMaxMsgs.SetDefaults() - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} - txm := NewTxm(db, tcFn, *gpe, chainID, cfgMaxMsgs, loopKs, lggr, pgtest.NewQConfig(true), nil) - - // Leftover started is processed - msg1 := generateExecuteMsg([]byte{0x03}, sender1, contract) - id1 := mustInsertMsg(t, txm, contract.String(), msg1) - require.NoError(t, txm.orm.UpdateMsgs([]int64{id1}, cosmosdb.Started, nil)) - msgs := cosmosclient.SimMsgs{{ID: id1, Msg: &wasmtypes.MsgExecuteContract{ - Sender: sender1.String(), - Msg: []byte{0x03}, - Contract: contract.String(), - }}} - tc.On("BatchSimulateUnsigned", msgs, mock.Anything). - Return(&cosmosclient.BatchSimResults{Failed: nil, Succeeded: msgs}, nil).Once() - time.Sleep(1 * time.Millisecond) - txm.sendMsgBatch(testutils.Context(t)) - m, err := txm.orm.GetMsgs(id1) - require.NoError(t, err) - assert.Equal(t, cosmosdb.Confirmed, m[0].State) - - // Leftover started is not cancelled - msg2 := generateExecuteMsg([]byte{0x04}, sender1, contract) - msg3 := generateExecuteMsg([]byte{0x05}, sender1, contract) - id2 := mustInsertMsg(t, txm, contract.String(), msg2) - require.NoError(t, txm.orm.UpdateMsgs([]int64{id2}, cosmosdb.Started, nil)) - time.Sleep(time.Millisecond) // ensure != CreatedAt - id3 := mustInsertMsg(t, txm, contract.String(), msg3) - msgs = cosmosclient.SimMsgs{{ID: id2, Msg: &wasmtypes.MsgExecuteContract{ - Sender: sender1.String(), - Msg: []byte{0x04}, - Contract: contract.String(), - }}, {ID: id3, Msg: &wasmtypes.MsgExecuteContract{ - Sender: sender1.String(), - Msg: []byte{0x05}, - Contract: contract.String(), - }}} - tc.On("BatchSimulateUnsigned", msgs, mock.Anything). - Return(&cosmosclient.BatchSimResults{Failed: nil, Succeeded: msgs}, nil).Once() - time.Sleep(1 * time.Millisecond) - txm.sendMsgBatch(testutils.Context(t)) - require.NoError(t, err) - ms, err := txm.orm.GetMsgs(id2, id3) - require.NoError(t, err) - assert.Equal(t, cosmosdb.Confirmed, ms[0].State) - assert.Equal(t, cosmosdb.Confirmed, ms[1].State) - }) -} - -func mustInsertMsg(t *testing.T, txm *Txm, contractID string, msg cosmostypes.Msg) int64 { - typeURL, raw, err := txm.marshalMsg(msg) - require.NoError(t, err) - id, err := txm.orm.InsertMsg(contractID, typeURL, raw) - require.NoError(t, err) - return id -} diff --git a/core/chains/cosmos/cosmostxm/txm_test.go b/core/chains/cosmos/cosmostxm/txm_test.go deleted file mode 100644 index 25ac9e8d9e..0000000000 --- a/core/chains/cosmos/cosmostxm/txm_test.go +++ /dev/null @@ -1,121 +0,0 @@ -//go:build integration - -package cosmostxm_test - -// TestTxm_Integration is disabled in order to be moved to chainlink-cosmos before DB testing is available -//func TestTxm_Integration(t *testing.T) { -// chainID := cosmostest.RandomChainID() -// cosmosChain := coscfg.Chain{} -// cosmosChain.SetDefaults() -// fallbackGasPrice := sdk.NewDecCoinFromDec(*cosmosChain.GasToken, sdk.MustNewDecFromStr("0.01")) -// chainConfig := cosmos.CosmosConfig{ChainID: &chainID, Enabled: ptr(true), Chain: cosmosChain} -// cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "cosmos_txm", func(c *chainlink.Config, s *chainlink.Secrets) { -// c.Cosmos = cosmos.CosmosConfigs{&chainConfig} -// }) -// lggr := logger.TestLogger(t) -// logCfg := pgtest.NewQConfig(true) -// gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ -// cosmosclient.NewFixedGasPriceEstimator(map[string]sdk.DecCoin{ -// *cosmosChain.GasToken: fallbackGasPrice, -// }, -// lggr.(logger.SugaredLogger), -// ), -// }, lggr) -// orm := cosmostxm.NewORM(chainID, db, lggr, logCfg) -// eb := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, lggr, uuid.New()) -// require.NoError(t, eb.Start(testutils.Context(t))) -// t.Cleanup(func() { require.NoError(t, eb.Close()) }) -// ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) -// zeConfig := sdk.GetConfig() -// fmt.Println(zeConfig) -// accounts, testdir, tendermintURL := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.GasToken) -// tc, err := cosmosclient.NewClient(chainID, tendermintURL, 0, lggr) -// require.NoError(t, err) -// -// loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} -// keystoreAdapter := cosmostxm.NewKeystoreAdapter(loopKs, *cosmosChain.Bech32Prefix) -// -// // First create a transmitter key and fund it with 1k native tokens -// require.NoError(t, ks.Unlock("blah")) -// err = ks.Cosmos().EnsureKey() -// require.NoError(t, err) -// ksAccounts, err := keystoreAdapter.Accounts() -// require.NoError(t, err) -// transmitterAddress := ksAccounts[0] -// transmitterID, err := sdk.AccAddressFromBech32(transmitterAddress) -// require.NoError(t, err) -// an, sn, err := tc.Account(accounts[0].Address) -// require.NoError(t, err) -// resp, err := tc.SignAndBroadcast([]sdk.Msg{banktypes.NewMsgSend(accounts[0].Address, transmitterID, sdk.NewCoins(sdk.NewInt64Coin(*cosmosChain.GasToken, 100000)))}, -// an, sn, gpe.GasPrices()[*cosmosChain.GasToken], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) -// tx, success := cosmosclient.AwaitTxCommitted(t, tc, resp.TxResponse.TxHash) -// require.True(t, success) -// require.Equal(t, types.CodeTypeOK, tx.TxResponse.Code) -// require.NoError(t, err) -// -// // TODO: find a way to pull this test artifact from -// // the chainlink-cosmos repo instead of copying it to cores testdata -// contractID := cosmosclient.DeployTestContract(t, tendermintURL, chainID, *cosmosChain.GasToken, accounts[0], cosmosclient.Account{ -// Name: "transmitter", -// PrivateKey: cosmostxm.NewKeyWrapper(keystoreAdapter, transmitterAddress), -// Address: transmitterID, -// }, tc, testdir, "../../../testdata/cosmos/my_first_contract.wasm") -// -// tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } -// // Start txm -// txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, &chainConfig, loopKs, lggr, pgtest.NewQConfig(true), eb) -// require.NoError(t, txm.Start(testutils.Context(t))) -// -// // Change the contract state -// setMsg := &wasmtypes.MsgExecuteContract{ -// Sender: transmitterID.String(), -// Contract: contractID.String(), -// Msg: []byte(`{"reset":{"count":5}}`), -// Funds: sdk.Coins{}, -// } -// _, err = txm.Enqueue(contractID.String(), setMsg) -// require.NoError(t, err) -// -// // Observe the counter gets set eventually -// gomega.NewWithT(t).Eventually(func() bool { -// d, err := tc.ContractState(contractID, []byte(`{"get_count":{}}`)) -// require.NoError(t, err) -// t.Log("contract value", string(d)) -// return string(d) == `{"count":5}` -// }, 20*time.Second, time.Second).Should(gomega.BeTrue()) -// // Ensure messages are completed -// gomega.NewWithT(t).Eventually(func() bool { -// msgs, err := orm.GetMsgsState(Confirmed, 5) -// require.NoError(t, err) -// return 1 == len(msgs) -// }, 5*time.Second, time.Second).Should(gomega.BeTrue()) -// -// // Ensure invalid msgs are marked as errored -// invalidMsg := &wasmtypes.MsgExecuteContract{ -// Sender: transmitterID.String(), -// Contract: contractID.String(), -// Msg: []byte(`{"blah":{"blah":5}}`), -// Funds: sdk.Coins{}, -// } -// _, err = txm.Enqueue(contractID.String(), invalidMsg) -// require.NoError(t, err) -// _, err = txm.Enqueue(contractID.String(), invalidMsg) -// require.NoError(t, err) -// _, err = txm.Enqueue(contractID.String(), setMsg) -// require.NoError(t, err) -// -// // Ensure messages are completed -// gomega.NewWithT(t).Eventually(func() bool { -// succeeded, err := orm.GetMsgsState(Confirmed, 5) -// require.NoError(t, err) -// errored, err := orm.GetMsgsState(Errored, 5) -// require.NoError(t, err) -// t.Log("errored", len(errored), "succeeded", len(succeeded)) -// return 2 == len(succeeded) && 2 == len(errored) -// }, 20*time.Second, time.Second).Should(gomega.BeTrue()) -// -// // Observe the messages have been marked as completed -// require.NoError(t, txm.Close()) -//} -// -//func ptr[T any](t T) *T { return &t } diff --git a/core/chains/cosmos/relayer_adapter.go b/core/chains/cosmos/relayer_adapter.go deleted file mode 100644 index ace441c2bb..0000000000 --- a/core/chains/cosmos/relayer_adapter.go +++ /dev/null @@ -1,50 +0,0 @@ -package cosmos - -import ( - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - - pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// LegacyChainContainer is container interface for Cosmos chains -type LegacyChainContainer interface { - Get(id string) (adapters.Chain, error) - Len() int - List(ids ...string) ([]adapters.Chain, error) - Slice() []adapters.Chain -} - -type LegacyChains = chains.ChainsKV[adapters.Chain] - -var _ LegacyChainContainer = &LegacyChains{} - -func NewLegacyChains(m map[string]adapters.Chain) *LegacyChains { - return chains.NewChainsKV[adapters.Chain](m) -} - -type LoopRelayerChainer interface { - loop.Relayer - Chain() adapters.Chain -} - -type LoopRelayerChain struct { - loop.Relayer - chain adapters.Chain -} - -func NewLoopRelayerChain(r *pkgcosmos.Relayer, s adapters.Chain) *LoopRelayerChain { - ra := relay.NewServerAdapter(r, s) - return &LoopRelayerChain{ - Relayer: ra, - chain: s, - } -} -func (r *LoopRelayerChain) Chain() adapters.Chain { - return r.chain -} - -var _ LoopRelayerChainer = &LoopRelayerChain{} diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 1ef99992a6..308ebf8da8 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -173,9 +173,8 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G if cfg.CosmosEnabled() { cosmosCfg := chainlink.CosmosFactoryConfig{ - Keystore: keyStore.Cosmos(), - TOMLConfigs: cfg.CosmosConfigs(), - EventBroadcaster: eventBroadcaster, + Keystore: keyStore.Cosmos(), + TOMLConfigs: cfg.CosmosConfigs(), } initOps = append(initOps, chainlink.InitCosmos(ctx, relayerFactory, cosmosCfg)) } diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index d70b06f5a9..89b8704f87 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -302,8 +302,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) - mockRelayerChainInteroperators := chainlinkmocks.NewRelayerChainInteroperators(t) - mockRelayerChainInteroperators.On("LegacyEVMChains").Return(legacy, nil) + mockRelayerChainInteroperators := &chainlinkmocks.FakeRelayerChainInteroperators{EVMChains: legacy} app.On("GetRelayers").Return(mockRelayerChainInteroperators).Maybe() ethClient.On("Dial", mock.Anything).Return(nil) @@ -385,8 +384,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { ethClient.On("Dial", mock.Anything).Return(nil) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) - mockRelayerChainInteroperators := chainlinkmocks.NewRelayerChainInteroperators(t) - mockRelayerChainInteroperators.On("LegacyEVMChains").Return(legacy, nil) + mockRelayerChainInteroperators := &chainlinkmocks.FakeRelayerChainInteroperators{EVMChains: legacy} app.On("GetRelayers").Return(mockRelayerChainInteroperators).Maybe() client := cmd.Shell{ @@ -465,8 +463,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { ethClient.On("Dial", mock.Anything).Return(nil) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) - mockRelayerChainInteroperators := chainlinkmocks.NewRelayerChainInteroperators(t) - mockRelayerChainInteroperators.On("LegacyEVMChains").Return(legacy, nil) + mockRelayerChainInteroperators := &chainlinkmocks.FakeRelayerChainInteroperators{EVMChains: legacy} app.On("GetRelayers").Return(mockRelayerChainInteroperators).Maybe() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(clienttypes.Successful, nil) diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index d47e6243b8..4cb9808fe2 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -414,11 +414,10 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn if cfg.CosmosEnabled() { cosmosCfg := chainlink.CosmosFactoryConfig{ - Keystore: keyStore.Cosmos(), - TOMLConfigs: cfg.CosmosConfigs(), - EventBroadcaster: eventBroadcaster, - DB: db, - QConfig: cfg.Database(), + Keystore: keyStore.Cosmos(), + TOMLConfigs: cfg.CosmosConfigs(), + DB: db, + QConfig: cfg.Database(), } initOps = append(initOps, chainlink.InitCosmos(testCtx, relayerFactory, cosmosCfg)) } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 690a8d189c..f2b1f9a4c9 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -301,7 +301,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 // indirect 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.20231030134738-81a5a89699a0 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 // indirect github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 // 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 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 5cbdb37427..683cc1ea06 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1456,8 +1456,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= diff --git a/core/services/chainlink/mocks/relayer_chain_interoperators.go b/core/services/chainlink/mocks/relayer_chain_interoperators.go index 0a8758f6d4..81f112f766 100644 --- a/core/services/chainlink/mocks/relayer_chain_interoperators.go +++ b/core/services/chainlink/mocks/relayer_chain_interoperators.go @@ -1,248 +1,61 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. - package mocks import ( - context "context" - - chainlink "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - - cosmos "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" + "context" + "slices" - evm "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + services2 "github.com/smartcontractkit/chainlink/v2/core/services" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - // Manually edited. mockery generates the wrong dependency. edited to use `loop` rather than `loop/internal` - // seems to caused by incorrect alias resolution of the relayer dep - internal "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - mock "github.com/stretchr/testify/mock" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relay "github.com/smartcontractkit/chainlink/v2/core/services/relay" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" - services "github.com/smartcontractkit/chainlink/v2/core/services" - - types "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-relay/pkg/types" ) -// RelayerChainInteroperators is an autogenerated mock type for the RelayerChainInteroperators type -type RelayerChainInteroperators struct { - mock.Mock -} - -// ChainStatus provides a mock function with given fields: ctx, id -func (_m *RelayerChainInteroperators) ChainStatus(ctx context.Context, id relay.ID) (types.ChainStatus, error) { - ret := _m.Called(ctx, id) - - var r0 types.ChainStatus - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, relay.ID) (types.ChainStatus, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, relay.ID) types.ChainStatus); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(types.ChainStatus) - } - - if rf, ok := ret.Get(1).(func(context.Context, relay.ID) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ChainStatuses provides a mock function with given fields: ctx, offset, limit -func (_m *RelayerChainInteroperators) ChainStatuses(ctx context.Context, offset int, limit int) ([]types.ChainStatus, int, error) { - ret := _m.Called(ctx, offset, limit) - - var r0 []types.ChainStatus - var r1 int - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, int, int) ([]types.ChainStatus, int, error)); ok { - return rf(ctx, offset, limit) - } - if rf, ok := ret.Get(0).(func(context.Context, int, int) []types.ChainStatus); ok { - r0 = rf(ctx, offset, limit) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.ChainStatus) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int, int) int); ok { - r1 = rf(ctx, offset, limit) - } else { - r1 = ret.Get(1).(int) - } - - if rf, ok := ret.Get(2).(func(context.Context, int, int) error); ok { - r2 = rf(ctx, offset, limit) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 +// FakeRelayerChainInteroperators is a fake chainlink.RelayerChainInteroperators. +// This exists because mockery generation doesn't understand how to produce an alias instead of the underlying type (which is not exported in this case). +type FakeRelayerChainInteroperators struct { + EVMChains evm.LegacyChainContainer + Nodes []types.NodeStatus + NodesErr error } -// Get provides a mock function with given fields: id -func (_m *RelayerChainInteroperators) Get(id relay.ID) (internal.Relayer, error) { - ret := _m.Called(id) - - var r0 internal.Relayer - var r1 error - if rf, ok := ret.Get(0).(func(relay.ID) (internal.Relayer, error)); ok { - return rf(id) - } - if rf, ok := ret.Get(0).(func(relay.ID) internal.Relayer); ok { - r0 = rf(id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(internal.Relayer) - } - } - - if rf, ok := ret.Get(1).(func(relay.ID) error); ok { - r1 = rf(id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 +func (f *FakeRelayerChainInteroperators) LegacyEVMChains() evm.LegacyChainContainer { + return f.EVMChains } -// LegacyCosmosChains provides a mock function with given fields: -func (_m *RelayerChainInteroperators) LegacyCosmosChains() cosmos.LegacyChainContainer { - ret := _m.Called() - - var r0 cosmos.LegacyChainContainer - if rf, ok := ret.Get(0).(func() cosmos.LegacyChainContainer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(cosmos.LegacyChainContainer) - } - } - - return r0 +func (f *FakeRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) { + return slices.Clone(f.Nodes), len(f.Nodes), f.NodesErr } -// LegacyEVMChains provides a mock function with given fields: -func (_m *RelayerChainInteroperators) LegacyEVMChains() evm.LegacyChainContainer { - ret := _m.Called() - - var r0 evm.LegacyChainContainer - if rf, ok := ret.Get(0).(func() evm.LegacyChainContainer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(evm.LegacyChainContainer) - } - } - - return r0 +func (f *FakeRelayerChainInteroperators) Services() []services2.ServiceCtx { + panic("unimplemented") } -// List provides a mock function with given fields: filter -func (_m *RelayerChainInteroperators) List(filter chainlink.FilterFn) chainlink.RelayerChainInteroperators { - ret := _m.Called(filter) - - var r0 chainlink.RelayerChainInteroperators - if rf, ok := ret.Get(0).(func(chainlink.FilterFn) chainlink.RelayerChainInteroperators); ok { - r0 = rf(filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(chainlink.RelayerChainInteroperators) - } - } - - return r0 +func (f *FakeRelayerChainInteroperators) List(filter chainlink.FilterFn) chainlink.RelayerChainInteroperators { + panic("unimplemented") } -// NodeStatuses provides a mock function with given fields: ctx, offset, limit, relayIDs -func (_m *RelayerChainInteroperators) NodeStatuses(ctx context.Context, offset int, limit int, relayIDs ...relay.ID) ([]types.NodeStatus, int, error) { - _va := make([]interface{}, len(relayIDs)) - for _i := range relayIDs { - _va[_i] = relayIDs[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, offset, limit) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 []types.NodeStatus - var r1 int - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...relay.ID) ([]types.NodeStatus, int, error)); ok { - return rf(ctx, offset, limit, relayIDs...) - } - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...relay.ID) []types.NodeStatus); ok { - r0 = rf(ctx, offset, limit, relayIDs...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.NodeStatus) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int, int, ...relay.ID) int); ok { - r1 = rf(ctx, offset, limit, relayIDs...) - } else { - r1 = ret.Get(1).(int) - } - - if rf, ok := ret.Get(2).(func(context.Context, int, int, ...relay.ID) error); ok { - r2 = rf(ctx, offset, limit, relayIDs...) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 +func (f *FakeRelayerChainInteroperators) Get(id relay.ID) (loop.Relayer, error) { + panic("unimplemented") } -// Services provides a mock function with given fields: -func (_m *RelayerChainInteroperators) Services() []services.ServiceCtx { - ret := _m.Called() - - var r0 []services.ServiceCtx - if rf, ok := ret.Get(0).(func() []services.ServiceCtx); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]services.ServiceCtx) - } - } - - return r0 +func (f *FakeRelayerChainInteroperators) Slice() []loop.Relayer { + panic("unimplemented") } -// Slice provides a mock function with given fields: -func (_m *RelayerChainInteroperators) Slice() []internal.Relayer { - ret := _m.Called() - - var r0 []internal.Relayer - if rf, ok := ret.Get(0).(func() []internal.Relayer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]internal.Relayer) - } - } - - return r0 +func (f *FakeRelayerChainInteroperators) LegacyCosmosChains() chainlink.LegacyCosmosContainer { + panic("unimplemented") } -type mockConstructorTestingTNewRelayerChainInteroperators interface { - mock.TestingT - Cleanup(func()) +func (f *FakeRelayerChainInteroperators) ChainStatus(ctx context.Context, id relay.ID) (types.ChainStatus, error) { + panic("unimplemented") } -// NewRelayerChainInteroperators creates a new instance of RelayerChainInteroperators. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewRelayerChainInteroperators(t mockConstructorTestingTNewRelayerChainInteroperators) *RelayerChainInteroperators { - mock := &RelayerChainInteroperators{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock +func (f *FakeRelayerChainInteroperators) ChainStatuses(ctx context.Context, offset, limit int) ([]types.ChainStatus, int, error) { + panic("unimplemented") } diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index e039afbfc9..b2ec0822d4 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -7,11 +7,12 @@ import ( "sort" "sync" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" @@ -24,10 +25,6 @@ var ErrNoSuchRelayer = errors.New("relayer does not exist") // encapsulates relayers and chains and is the primary entry point for // the node to access relayers, get legacy chains associated to a relayer // and get status about the chains and nodes -// -// note the generated mockery code incorrectly resolves dependencies and needs to be manually edited -// therefore this interface is not auto-generated. for reference use and edit the result: -// `go:generate mockery --quiet --name RelayerChainInteroperators --output ./mocks/ --case=underscore“` type RelayerChainInteroperators interface { Services() []services.ServiceCtx @@ -50,7 +47,7 @@ type LoopRelayerStorer interface { // on the relayer interface. type LegacyChainer interface { LegacyEVMChains() evm.LegacyChainContainer - LegacyCosmosChains() cosmos.LegacyChainContainer + LegacyCosmosChains() LegacyCosmosContainer } type ChainStatuser interface { @@ -135,7 +132,7 @@ func InitCosmos(ctx context.Context, factory RelayerFactory, config CosmosFactor op.loopRelayers[id] = a legacyMap[id.ChainID] = a.Chain() } - op.legacyChains.CosmosChains = cosmos.NewLegacyChains(legacyMap) + op.legacyChains.CosmosChains = NewLegacyCosmos(legacyMap) return nil } @@ -196,7 +193,7 @@ func (rs *CoreRelayerChainInteroperators) LegacyEVMChains() evm.LegacyChainConta // LegacyCosmosChains returns a container with all the cosmos chains // TODO BCF-2511 -func (rs *CoreRelayerChainInteroperators) LegacyCosmosChains() cosmos.LegacyChainContainer { +func (rs *CoreRelayerChainInteroperators) LegacyCosmosChains() LegacyCosmosContainer { rs.mu.Lock() defer rs.mu.Unlock() return rs.legacyChains.CosmosChains @@ -355,5 +352,44 @@ func (rs *CoreRelayerChainInteroperators) Services() (s []services.ServiceCtx) { // deprecated when chain-specific logic is removed from products. type legacyChains struct { EVMChains evm.LegacyChainContainer - CosmosChains cosmos.LegacyChainContainer + CosmosChains LegacyCosmosContainer } + +// LegacyCosmosContainer is container interface for Cosmos chains +type LegacyCosmosContainer interface { + Get(id string) (adapters.Chain, error) + Len() int + List(ids ...string) ([]adapters.Chain, error) + Slice() []adapters.Chain +} + +type LegacyCosmos = chains.ChainsKV[adapters.Chain] + +var _ LegacyCosmosContainer = &LegacyCosmos{} + +func NewLegacyCosmos(m map[string]adapters.Chain) *LegacyCosmos { + return chains.NewChainsKV[adapters.Chain](m) +} + +type CosmosLoopRelayerChainer interface { + loop.Relayer + Chain() adapters.Chain +} + +type CosmosLoopRelayerChain struct { + loop.Relayer + chain adapters.Chain +} + +func NewCosmosLoopRelayerChain(r *cosmos.Relayer, s adapters.Chain) *CosmosLoopRelayerChain { + ra := relay.NewServerAdapter(r, s) + return &CosmosLoopRelayerChain{ + Relayer: ra, + chain: s, + } +} +func (r *CosmosLoopRelayerChain) Chain() adapters.Chain { + return r.chain +} + +var _ CosmosLoopRelayerChainer = &CosmosLoopRelayerChain{} diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index cfc7dbadc1..8729306964 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -257,11 +257,10 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { name: "2 cosmos chains with 2 nodes", initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitCosmos(testctx, factory, chainlink.CosmosFactoryConfig{ - Keystore: keyStore.Cosmos(), - TOMLConfigs: cfg.CosmosConfigs(), - EventBroadcaster: pg.NewNullEventBroadcaster(), - DB: db, - QConfig: cfg.Database()}), + Keystore: keyStore.Cosmos(), + TOMLConfigs: cfg.CosmosConfigs(), + DB: db, + QConfig: cfg.Database()}), }, expectedCosmosChainCnt: 2, expectedCosmosNodeCnt: 2, @@ -290,11 +289,10 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Keystore: keyStore.StarkNet(), TOMLConfigs: cfg.StarknetConfigs()}), chainlink.InitCosmos(testctx, factory, chainlink.CosmosFactoryConfig{ - Keystore: keyStore.Cosmos(), - TOMLConfigs: cfg.CosmosConfigs(), - EventBroadcaster: pg.NewNullEventBroadcaster(), - DB: db, - QConfig: cfg.Database(), + Keystore: keyStore.Cosmos(), + TOMLConfigs: cfg.CosmosConfigs(), + DB: db, + QConfig: cfg.Database(), }), }, expectedEVMChainCnt: 2, diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index a159ee7cd0..76bfcd1641 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/sqlx" - pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-solana/pkg/solana" @@ -17,7 +17,7 @@ import ( pkgstarknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink" starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -225,7 +225,6 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML type CosmosFactoryConfig struct { Keystore keystore.Cosmos coscfg.TOMLConfigs - EventBroadcaster pg.EventBroadcaster *sqlx.DB pg.QConfig } @@ -238,9 +237,6 @@ func (c CosmosFactoryConfig) Validate() error { if len(c.TOMLConfigs) == 0 { err = errors.Join(err, fmt.Errorf("no CosmosConfigs provided")) } - if c.EventBroadcaster == nil { - err = errors.Join(err, fmt.Errorf("nil EventBroadcaster")) - } if c.DB == nil { err = errors.Join(err, fmt.Errorf("nil DB")) } @@ -254,12 +250,12 @@ func (c CosmosFactoryConfig) Validate() error { return err } -func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConfig) (map[relay.ID]cosmos.LoopRelayerChainer, error) { +func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConfig) (map[relay.ID]CosmosLoopRelayerChainer, error) { err := config.Validate() if err != nil { return nil, fmt.Errorf("cannot create Cosmos relayer: %w", err) } - relayers := make(map[relay.ID]cosmos.LoopRelayerChainer) + relayers := make(map[relay.ID]CosmosLoopRelayerChainer) var ( cosmosLggr = r.Logger.Named("Cosmos") @@ -273,11 +269,9 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf lggr := cosmosLggr.Named(relayID.ChainID) opts := cosmos.ChainOpts{ - QueryConfig: config.QConfig, - Logger: lggr, - DB: config.DB, - KeyStore: loopKs, - EventBroadcaster: config.EventBroadcaster, + Logger: lggr, + DB: config.DB, + KeyStore: loopKs, } chain, err := cosmos.NewChain(chainCfg, opts) @@ -285,7 +279,7 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf return nil, fmt.Errorf("failed to load Cosmos chain %q: %w", relayID, err) } - relayers[relayID] = cosmos.NewLoopRelayerChain(pkgcosmos.NewRelayer(lggr, chain), chain) + relayers[relayID] = NewCosmosLoopRelayerChain(cosmos.NewRelayer(lggr, chain), chain) } return relayers, nil diff --git a/core/services/pg/channels.go b/core/services/pg/channels.go index 1d67dabe52..aed132a7f2 100644 --- a/core/services/pg/channels.go +++ b/core/services/pg/channels.go @@ -1,7 +1,4 @@ package pg // Postgres channel to listen for new evm.txes -const ( - ChannelInsertOnCosmosMsg = "insert_on_cosmos_msg" - ChannelInsertOnEVMLogs = "evm.insert_on_logs" -) +const ChannelInsertOnEVMLogs = "evm.insert_on_logs" diff --git a/core/store/migrate/migrations/0207_drop_insert_on_terra_msg.sql b/core/store/migrate/migrations/0207_drop_insert_on_terra_msg.sql new file mode 100644 index 0000000000..f4ae4b98e2 --- /dev/null +++ b/core/store/migrate/migrations/0207_drop_insert_on_terra_msg.sql @@ -0,0 +1,20 @@ +-- +goose Up + +-- +goose StatementBegin +DROP TRIGGER IF EXISTS insert_on_terra_msg ON PUBLIC.cosmos_msgs; +DROP FUNCTION IF EXISTS PUBLIC.notify_terra_msg_insert; +-- +goose StatementEnd + +-- +goose Down + +-- +goose StatementBegin +CREATE FUNCTION notify_terra_msg_insert() RETURNS trigger + LANGUAGE plpgsql +AS $$ +BEGIN + PERFORM pg_notify('insert_on_terra_msg'::text, NOW()::text); + RETURN NULL; +END +$$; +CREATE TRIGGER notify_terra_msg_insertion AFTER INSERT ON cosmos_msgs FOR EACH STATEMENT EXECUTE PROCEDURE notify_terra_msg_insert(); +-- +goose StatementEnd diff --git a/core/web/loader/loader_test.go b/core/web/loader/loader_test.go index 0dd45a1735..984aa9f618 100644 --- a/core/web/loader/loader_test.go +++ b/core/web/loader/loader_test.go @@ -26,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" jobORMMocks "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -69,9 +68,6 @@ func TestLoader_Nodes(t *testing.T) { ctx := InjectDataloader(testutils.Context(t), app) chainID1, chainID2, notAnID := big.NewInt(1), big.NewInt(2), big.NewInt(3) - relayID1 := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(chainID1.String())} - relayID2 := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(chainID2.String())} - notARelayID := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(notAnID.String())} genNodeStat := func(id string) relaytypes.NodeStatus { return relaytypes.NodeStatus{ @@ -79,11 +75,9 @@ func TestLoader_Nodes(t *testing.T) { ChainID: id, } } - rcInterops := chainlinkmocks.NewRelayerChainInteroperators(t) - rcInterops.On("NodeStatuses", mock.Anything, 0, -1, - relayID2, relayID1, notARelayID).Return([]relaytypes.NodeStatus{ + rcInterops := &chainlinkmocks.FakeRelayerChainInteroperators{Nodes: []relaytypes.NodeStatus{ genNodeStat(chainID2.String()), genNodeStat(chainID1.String()), - }, 2, nil) + }} app.On("GetRelayers").Return(rcInterops) batcher := nodeBatcher{app} diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index 6cac2f4ac4..a7f8ce56d9 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -100,7 +100,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.balM.On("GetEthBalance", address).Return(assets.NewEth(1)) f.Mocks.chain.On("BalanceMonitor").Return(f.Mocks.balM) f.Mocks.chain.On("Config").Return(f.Mocks.scfg) - f.Mocks.relayerChainInterops.On("LegacyEVMChains").Return(legacyEVMChains) + f.Mocks.relayerChainInterops.EVMChains = legacyEVMChains f.Mocks.evmORM.PutChains(toml.EVMConfig{ChainID: &chainID}) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.App.On("GetKeyStore").Return(f.Mocks.keystore) @@ -149,7 +149,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) f.Mocks.ethKs.On("GetAll").Return(keys, nil) - f.Mocks.relayerChainInterops.On("LegacyEVMChains").Return(f.Mocks.legacyEVMChains) + f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains f.Mocks.evmORM.PutChains(toml.EVMConfig{ChainID: &chainID}) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.App.On("GetKeyStore").Return(f.Mocks.keystore) @@ -268,7 +268,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("GetAll").Return(keys, nil) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(f.Mocks.chain, gError) - f.Mocks.relayerChainInterops.On("LegacyEVMChains").Return(f.Mocks.legacyEVMChains) + f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains f.App.On("GetRelayers").Return(f.Mocks.relayerChainInterops) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -302,7 +302,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(assets.NewLinkFromJuels(12), gError) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(f.Mocks.chain, nil) - f.Mocks.relayerChainInterops.On("LegacyEVMChains").Return(f.Mocks.legacyEVMChains) + f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) f.Mocks.balM.On("GetEthBalance", address).Return(assets.NewEth(1)) f.Mocks.chain.On("BalanceMonitor").Return(f.Mocks.balM) @@ -358,7 +358,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.chain.On("BalanceMonitor").Return(nil) f.Mocks.chain.On("Config").Return(f.Mocks.scfg) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(f.Mocks.chain, nil) - f.Mocks.relayerChainInterops.On("LegacyEVMChains").Return(f.Mocks.legacyEVMChains) + f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains f.Mocks.evmORM.PutChains(toml.EVMConfig{ChainID: &chainID}) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.App.On("GetKeyStore").Return(f.Mocks.keystore) diff --git a/core/web/resolver/node_test.go b/core/web/resolver/node_test.go index e949a67a85..9f34b27420 100644 --- a/core/web/resolver/node_test.go +++ b/core/web/resolver/node_test.go @@ -5,10 +5,10 @@ import ( gqlerrors "github.com/graph-gophers/graphql-go/errors" "github.com/pkg/errors" - "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -43,17 +43,16 @@ func TestResolver_Nodes(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.App.On("GetRelayers").Return(f.Mocks.relayerChainInterops) - f.Mocks.relayerChainInterops.On("NodeStatuses", mock.Anything, PageDefaultOffset, PageDefaultLimit).Return([]types.NodeStatus{ + f.App.On("GetRelayers").Return(chainlink.RelayerChainInteroperators(f.Mocks.relayerChainInterops)) + f.Mocks.relayerChainInterops.Nodes = []types.NodeStatus{ { Name: "node-name", ChainID: chainID.String(), Config: `Name = 'node-name'`, }, - }, 1, nil) + } f.App.On("EVMORM").Return(f.Mocks.evmORM) f.Mocks.evmORM.PutChains(toml.EVMConfig{ChainID: &chainID}) - }, query: query, result: ` @@ -76,7 +75,7 @@ func TestResolver_Nodes(t *testing.T) { name: "generic error", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.relayerChainInterops.On("NodeStatuses", mock.Anything, PageDefaultOffset, PageDefaultLimit).Return([]types.NodeStatus{}, 0, gError) + f.Mocks.relayerChainInterops.NodesErr = gError f.App.On("GetRelayers").Return(f.Mocks.relayerChainInterops) }, query: query, diff --git a/core/web/resolver/resolver_test.go b/core/web/resolver/resolver_test.go index d0523d6b96..fa8471c5e2 100644 --- a/core/web/resolver/resolver_test.go +++ b/core/web/resolver/resolver_test.go @@ -52,7 +52,7 @@ type mocks struct { solana *keystoreMocks.Solana chain *evmORMMocks.Chain legacyEVMChains *evmORMMocks.LegacyChainContainer - relayerChainInterops *chainlinkMocks.RelayerChainInteroperators + relayerChainInterops *chainlinkMocks.FakeRelayerChainInteroperators ethClient *evmClientMocks.Client eIMgr *webhookmocks.ExternalInitiatorManager balM *evmORMMocks.BalanceMonitor @@ -111,7 +111,7 @@ func setupFramework(t *testing.T) *gqlTestFramework { solana: keystoreMocks.NewSolana(t), chain: evmORMMocks.NewChain(t), legacyEVMChains: evmORMMocks.NewLegacyChainContainer(t), - relayerChainInterops: chainlinkMocks.NewRelayerChainInteroperators(t), + relayerChainInterops: &chainlinkMocks.FakeRelayerChainInteroperators{}, ethClient: evmClientMocks.NewClient(t), eIMgr: webhookmocks.NewExternalInitiatorManager(t), balM: evmORMMocks.NewBalanceMonitor(t), diff --git a/go.mod b/go.mod index ad3cb5f78e..2df4b05c74 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/smartcontractkit/chainlink/v2 go 1.21 require ( - github.com/CosmWasm/wasmd v0.40.1 github.com/Depado/ginprom v1.7.11 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 @@ -24,7 +23,6 @@ require ( github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 github.com/gin-gonic/gin v1.9.1 github.com/go-webauthn/webauthn v0.8.2 - github.com/gogo/protobuf v1.3.3 github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 github.com/google/uuid v1.3.1 github.com/gorilla/securecookie v1.1.1 @@ -67,7 +65,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 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.20231030134738-81a5a89699a0 + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 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 @@ -116,6 +114,7 @@ require ( github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect + github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -184,6 +183,7 @@ require ( github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect + github.com/gogo/protobuf v1.3.3 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect diff --git a/go.sum b/go.sum index f879f16272..f13b00d6db 100644 --- a/go.sum +++ b/go.sum @@ -1457,8 +1457,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index aa670da1c9..be9285c6d4 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -383,7 +383,7 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect 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.20231030134738-81a5a89699a0 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 // indirect github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 // 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 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f7b55b259f..7c5542bfa6 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2360,8 +2360,8 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0 h1:YrJ3moRDu2kgdv4o3Hym/FWVF4MS5cIZ7o7wk+43pvk= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231030134738-81a5a89699a0/go.mod h1:fxtwgVZzTgoU1CpdSxNvFXecIY2r8DhH2JCzPO4e9G0= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= From 463f938e1fb9f4d3782c6f147331d22bc0dc59c4 Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 2 Nov 2023 11:30:54 +0000 Subject: [PATCH 052/327] [chore] Skip Mercury/VRF flakey tests (#11141) --- core/services/relay/evm/mercury/config_poller_test.go | 1 + core/services/vrf/v2/integration_v2_plus_test.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/core/services/relay/evm/mercury/config_poller_test.go b/core/services/relay/evm/mercury/config_poller_test.go index 6a692b0eac..1b3ba72128 100644 --- a/core/services/relay/evm/mercury/config_poller_test.go +++ b/core/services/relay/evm/mercury/config_poller_test.go @@ -115,6 +115,7 @@ func TestMercuryConfigPoller(t *testing.T) { } func TestNotify(t *testing.T) { + testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/BCF-2746") feedIDStr := "8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1" feedIDBytes, err := hexutil.Decode("0x" + feedIDStr) require.NoError(t, err) diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index f08c10c200..6d2b77acb7 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -304,6 +304,7 @@ func newVRFCoordinatorV2PlusUniverse(t *testing.T, key ethkey.KeyV2, numConsumer } func TestVRFV2PlusIntegration_SingleConsumer_HappyPath_BatchFulfillment(t *testing.T) { + testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/BCF-2745") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) @@ -456,6 +457,7 @@ func TestVRFV2PlusIntegration_SingleConsumer_HappyPath(t *testing.T) { } func TestVRFV2PlusIntegration_SingleConsumer_EOA_Request(t *testing.T) { + testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/BCF-2744") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) From 627d698401b4b19321b7db603d4dbba4d1c8ca4e Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 2 Nov 2023 09:52:49 -0400 Subject: [PATCH 053/327] Bump Chainlink-relay to c686b4d48672d0eb818beafcff90ad4e33ea5db3 (#11145) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index f2b1f9a4c9..65dcec563e 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -302,7 +302,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 // 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 683cc1ea06..781eed46ce 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1458,8 +1458,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 h1:59vz5H52EpwWE/64ZQpNCs7Gtnyi7/ytjyoGjlbKhBA= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672/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/go.mod b/go.mod index 2df4b05c74..569912ed1b 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.20231101160906-7acebcc1b353 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 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-20231020123319-d255366a6545 diff --git a/go.sum b/go.sum index f13b00d6db..155e54646d 100644 --- a/go.sum +++ b/go.sum @@ -1459,8 +1459,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 h1:59vz5H52EpwWE/64ZQpNCs7Gtnyi7/ytjyoGjlbKhBA= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672/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 be9285c6d4..33beae119a 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -384,7 +384,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 // 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/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 7c5542bfa6..7969e82144 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2362,8 +2362,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111 h1:CElKhWq0WIa9Rmg5Ssajs5Hp3m3u/nYIQdXtpj2gbcc= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231031114820-e9826d481111/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 h1:59vz5H52EpwWE/64ZQpNCs7Gtnyi7/ytjyoGjlbKhBA= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672/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= From f7e868e171c0fc2ee656cd575c0912ead5b3fe2d Mon Sep 17 00:00:00 2001 From: Makram Date: Thu, 2 Nov 2023 16:16:04 +0100 Subject: [PATCH 054/327] fix: v2 superscript (#11146) * dereference only after parsing args * fix sending key parsing * fix public key parsing --- .../vrfv2/testnet/v2scripts/super_scripts.go | 101 +++++++++++------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index f5e3700569..23ad8e1374 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -5,10 +5,6 @@ import ( "encoding/hex" "flag" "fmt" - "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" - "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/jobs" - "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" - "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" "math/big" "os" "strings" @@ -18,6 +14,11 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/shopspring/decimal" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/jobs" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" + helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" @@ -37,12 +38,12 @@ func DeployUniverseViaCLI(e helpers.Environment) { deployCmd := flag.NewFlagSet("deploy-universe", flag.ExitOnError) // required flags - linkAddress := *deployCmd.String("link-address", "", "address of link token") - linkEthAddress := *deployCmd.String("link-eth-feed", "", "address of link eth feed") - bhsContractAddressString := *deployCmd.String("bhs-address", "", "address of BHS contract") - batchBHSAddressString := *deployCmd.String("batch-bhs-address", "", "address of Batch BHS contract") - coordinatorAddressString := *deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") - batchCoordinatorAddressString := *deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") + linkAddress := deployCmd.String("link-address", "", "address of link token") + linkEthAddress := deployCmd.String("link-eth-feed", "", "address of link eth feed") + bhsContractAddressString := deployCmd.String("bhs-address", "", "address of BHS contract") + batchBHSAddressString := deployCmd.String("batch-bhs-address", "", "address of Batch BHS contract") + coordinatorAddressString := deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") + batchCoordinatorAddressString := deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", constants.SubscriptionBalanceJuels, "amount to fund subscription") nodeSendingKeyFundingAmount := deployCmd.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "CL node sending key funding amount") @@ -87,7 +88,10 @@ func DeployUniverseViaCLI(e helpers.Environment) { ReqsForTier5: big.NewInt(*reqsForTier5), } - vrfPrimaryNodeSendingKeys := strings.Split(*vrfPrimaryNodeSendingKeysString, ",") + var vrfPrimaryNodeSendingKeys []string + if len(*vrfPrimaryNodeSendingKeysString) > 0 { + vrfPrimaryNodeSendingKeys = strings.Split(*vrfPrimaryNodeSendingKeysString, ",") + } nodesMap := make(map[string]model.Node) @@ -100,14 +104,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { SendingKeyFundingAmount: fundingAmount, } - bhsContractAddress := common.HexToAddress(bhsContractAddressString) - batchBHSAddress := common.HexToAddress(batchBHSAddressString) - coordinatorAddress := common.HexToAddress(coordinatorAddressString) - batchCoordinatorAddress := common.HexToAddress(batchCoordinatorAddressString) + bhsContractAddress := common.HexToAddress(*bhsContractAddressString) + batchBHSAddress := common.HexToAddress(*batchBHSAddressString) + coordinatorAddress := common.HexToAddress(*coordinatorAddressString) + batchCoordinatorAddress := common.HexToAddress(*batchCoordinatorAddressString) contractAddresses := model.ContractAddresses{ - LinkAddress: linkAddress, - LinkEthAddress: linkEthAddress, + LinkAddress: *linkAddress, + LinkEthAddress: *linkEthAddress, BhsContractAddress: bhsContractAddress, BatchBHSAddress: batchBHSAddress, CoordinatorAddress: coordinatorAddress, @@ -149,29 +153,32 @@ func VRFV2DeployUniverse( batchFulfillmentEnabled bool, nodesMap map[string]model.Node, ) model.JobSpecs { - - // Put key in ECDSA format - if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { - *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) - } - - // Generate compressed public key and key hash - pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) - helpers.PanicErr(err) - pk, err := crypto.UnmarshalPubkey(pubBytes) - helpers.PanicErr(err) - var pkBytes []byte - if big.NewInt(0).Mod(pk.Y, big.NewInt(2)).Uint64() != 0 { - pkBytes = append(pk.X.Bytes(), 1) - } else { - pkBytes = append(pk.X.Bytes(), 0) + var compressedPkHex string + var keyHash common.Hash + if len(*registerKeyUncompressedPubKey) > 0 { + // Put key in ECDSA format + if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { + *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) + } + + // Generate compressed public key and key hash + pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) + helpers.PanicErr(err) + pk, err := crypto.UnmarshalPubkey(pubBytes) + helpers.PanicErr(err) + var pkBytes []byte + if big.NewInt(0).Mod(pk.Y, big.NewInt(2)).Uint64() != 0 { + pkBytes = append(pk.X.Bytes(), 1) + } else { + pkBytes = append(pk.X.Bytes(), 0) + } + var newPK secp256k1.PublicKey + copy(newPK[:], pkBytes) + + compressedPkHex = hexutil.Encode(pkBytes) + keyHash, err = newPK.Hash() + helpers.PanicErr(err) } - var newPK secp256k1.PublicKey - copy(newPK[:], pkBytes) - - compressedPkHex := hexutil.Encode(pkBytes) - keyHash, err := newPK.Hash() - helpers.PanicErr(err) if len(contractAddresses.LinkAddress) == 0 { fmt.Println("\nDeploying LINK Token...") @@ -268,7 +275,13 @@ func VRFV2DeployUniverse( e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[model.VRFPrimaryNodeName].SendingKeys[0].Address, + func() string { + if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { + return keys[0].Address + } else { + return common.HexToAddress("0x0").String() + } + }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) @@ -283,7 +296,13 @@ func VRFV2DeployUniverse( e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[model.VRFPrimaryNodeName].SendingKeys[0], + func() string { + if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { + return keys[0].Address + } else { + return common.HexToAddress("0x0").String() + } + }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) From a08b7054e9384c597112496dbe23683983c84a00 Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 2 Nov 2023 15:57:41 +0000 Subject: [PATCH 055/327] [BCF-2463] Add generic job type for lightweight OCR plugins (#10665) * [BCF-2463] Add generic job type for lightweight OCR plugins * [chore] Refactor ErrJobSpecNoRelayer; add ErrRelayerNotEnabled * [feedback] Move validation of PluginConfig to ocr2/validate/validate.go * Add tests for pluginConfig * Sensible defaults for command --- core/services/ocr2/delegate.go | 169 ++++++++++++++++-- .../ocr2/plugins/generic/helpers_test.go | 7 + .../ocr2/plugins/generic/merge_test.go | 32 ++++ .../generic/pipeline_runner_adapter_test.go | 35 +--- .../ocr2/plugins/generic/telemetry_adapter.go | 13 +- .../plugins/generic/telemetry_adapter_test.go | 15 +- core/services/ocr2/validate/validate.go | 33 ++++ core/services/ocr2/validate/validate_test.go | 83 +++++++++ go.mod | 2 +- 9 files changed, 334 insertions(+), 55 deletions(-) create mode 100644 core/services/ocr2/plugins/generic/helpers_test.go create mode 100644 core/services/ocr2/plugins/generic/merge_test.go diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index efb6f04fd3..e822fd5d8f 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -8,6 +8,7 @@ import ( "log" "time" + "google.golang.org/grpc" "gopkg.in/guregu/null.v4" "github.com/ethereum/go-ethereum/common" @@ -30,6 +31,7 @@ import ( relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-relay/pkg/loop/reportingplugins" "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -43,6 +45,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/persistence" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/generic" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" @@ -70,7 +73,28 @@ import ( "github.com/smartcontractkit/chainlink/v2/plugins" ) -var ErrJobSpecNoRelayer = errors.New("OCR2 job spec could not get relayer id") +type ErrJobSpecNoRelayer struct { + PluginName string + Err error +} + +func (e ErrJobSpecNoRelayer) Unwrap() error { return e.Err } + +func (e ErrJobSpecNoRelayer) Error() string { + return fmt.Sprintf("%s services: OCR2 job spec could not get relayer ID: %s", e.PluginName, e.Err) +} + +type ErrRelayNotEnabled struct { + PluginName string + Relay string + Err error +} + +func (e ErrRelayNotEnabled) Unwrap() error { return e.Err } + +func (e ErrRelayNotEnabled) Error() string { + return fmt.Sprintf("%s services: failed to get relay %s, is it enabled? %s", e.PluginName, e.Relay, e.Err) +} type RelayGetter interface { Get(id relay.ID) (loop.Relayer, error) @@ -245,7 +269,7 @@ func (d *Delegate) OnDeleteJob(jb job.Job, q pg.Queryer) error { rid, err := spec.RelayID() if err != nil { - d.lggr.Errorw("DeleteJob: "+ErrJobSpecNoRelayer.Error(), "err", err) + d.lggr.Errorw("DeleteJob", "err", ErrJobSpecNoRelayer{Err: err, PluginName: string(spec.PluginType)}) return nil } // we only have clean to do for the EVM @@ -337,7 +361,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("ServicesForSpec: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: string(spec.PluginType)} } if rid.Network == relay.EVM { @@ -428,6 +452,9 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { s4PluginDB := NewDB(d.db, spec.ID, s4PluginId, lggr, d.cfg.Database()) return d.newServicesOCR2Functions(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, thresholdPluginDB, s4PluginDB, lc, ocrLogger) + case types.GenericPlugin: + return d.newServicesGenericPlugin(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) + default: return nil, errors.Errorf("plugin type %s not supported", spec.PluginType) } @@ -473,6 +500,124 @@ func GetEVMEffectiveTransmitterID(jb *job.Job, chain evm.Chain, lggr logger.Suga return spec.TransmitterID.String, nil } +type connProvider interface { + ClientConn() grpc.ClientConnInterface +} + +func defaultPathFromPluginName(pluginName string) string { + // By default we install the command on the system path, in the + // form: `chainlink-` + return fmt.Sprintf("chainlink-%s", pluginName) +} + +func (d *Delegate) newServicesGenericPlugin( + ctx context.Context, + lggr logger.SugaredLogger, + jb job.Job, + bootstrapPeers []commontypes.BootstrapperLocator, + kb ocr2key.KeyBundle, + ocrDB *db, + lc ocrtypes.LocalConfig, + ocrLogger commontypes.Logger, +) (srvs []job.ServiceCtx, err error) { + spec := jb.OCR2OracleSpec + + p := validate.OCR2GenericPluginConfig{} + err = json.Unmarshal(spec.PluginConfig.Bytes(), &p) + if err != nil { + return nil, err + } + cconf := p.CoreConfig + + command := cconf.Command + if command == "" { + command = defaultPathFromPluginName(cconf.PluginName) + } + + // NOTE: we don't need to validate this config, since that happens as part of creating the job. + // See: validate/validate.go's `validateSpec`. + + rid, err := spec.RelayID() + if err != nil { + return nil, ErrJobSpecNoRelayer{PluginName: cconf.PluginName, Err: err} + } + + relayer, err := d.RelayGetter.Get(rid) + if err != nil { + return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: p.CoreConfig.PluginName} + } + + provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{ + ExternalJobID: jb.ExternalJobID, + JobID: spec.ID, + ContractID: spec.ContractID, + New: d.isNewlyCreatedJob, + RelayConfig: spec.RelayConfig.Bytes(), + ProviderType: cconf.ProviderType, + }, types.PluginArgs{ + TransmitterID: spec.TransmitterID.String, + PluginConfig: spec.PluginConfig.Bytes(), + }) + if err != nil { + return nil, err + } + srvs = append(srvs, provider) + + oracleEndpoint := d.monitoringEndpointGen.GenMonitoringEndpoint( + spec.ContractID, + synchronization.TelemetryType(cconf.TelemetryType), + rid.Network, + rid.ChainID, + ) + oracleArgs := libocr2.OCR2OracleArgs{ + BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, + V2Bootstrappers: bootstrapPeers, + Database: ocrDB, + LocalConfig: lc, + Logger: ocrLogger, + MonitoringEndpoint: oracleEndpoint, + OffchainKeyring: kb, + OnchainKeyring: kb, + ContractTransmitter: provider.ContractTransmitter(), + ContractConfigTracker: provider.ContractConfigTracker(), + OffchainConfigDigester: provider.OffchainConfigDigester(), + } + + pluginLggr := lggr.Named(cconf.PluginName).Named(spec.ContractID).Named(spec.GetID()) + cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(fmt.Sprintf("%s-%s-%s", cconf.PluginName, spec.ContractID, spec.GetID()), command) + if err != nil { + return nil, fmt.Errorf("failed to register loop: %w", err) + } + + errorLog := &errorLog{jobID: jb.ID, recordError: d.jobORM.RecordError} + providerConn, ok := provider.(connProvider) + if !ok { + return nil, errors.New("provider not supported: the provider is not a LOOPP provider") + } + + pluginConfig := types.ReportingPluginServiceConfig{ + PluginName: cconf.PluginName, + Command: command, + ProviderType: cconf.ProviderType, + PluginConfig: string(p.PluginConfig), + } + + pr := generic.NewPipelineRunnerAdapter(pluginLggr, jb, d.pipelineRunner) + ta := generic.NewTelemetryAdapter(d.monitoringEndpointGen) + + plugin := reportingplugins.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerConn.ClientConn(), pr, ta, errorLog) + oracleArgs.ReportingPluginFactory = plugin + srvs = append(srvs, plugin) + + oracle, err := libocr2.NewOracle(oracleArgs) + if err != nil { + return nil, err + } + + srvs = append(srvs, job.NewServiceAdapter(oracle)) + return srvs, nil +} + func (d *Delegate) newServicesMercury( ctx context.Context, lggr logger.SugaredLogger, @@ -498,14 +643,14 @@ func (d *Delegate) newServicesMercury( rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("mercury services: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "mercury"} } if rid.Network != relay.EVM { return nil, fmt.Errorf("mercury services: expected EVM relayer got %s", rid.Network) } relayer, err := d.RelayGetter.Get(rid) if err != nil { - return nil, fmt.Errorf("failed to get relay %s is it enabled?: %w", spec.Relay, err) + return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: "mercury"} } chain, err := d.legacyChains.Get(rid.ChainID) if err != nil { @@ -574,7 +719,7 @@ func (d *Delegate) newServicesMedian( rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("median services: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "median"} } oracleArgsNoPlugin := libocr2.OCR2OracleArgs{ @@ -593,7 +738,7 @@ func (d *Delegate) newServicesMedian( relayer, err := d.RelayGetter.Get(rid) if err != nil { - return nil, fmt.Errorf("median services; failed to get relay %s is it enabled?: %w", spec.Relay, err) + return nil, ErrRelayNotEnabled{Err: err, PluginName: "median", Relay: spec.Relay} } medianServices, err2 := median.NewMedianServices(ctx, jb, d.isNewlyCreatedJob, relayer, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, mConfig, enhancedTelemChan, errorLog) @@ -618,7 +763,7 @@ func (d *Delegate) newServicesDKG( spec := jb.OCR2OracleSpec rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("DKG services: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "DKG"} } if rid.Network != relay.EVM { return nil, fmt.Errorf("DKG services: expected EVM relayer got %s", rid.Network) @@ -687,7 +832,7 @@ func (d *Delegate) newServicesOCR2VRF( rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("VRF services: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "VRF"} } if rid.Network != relay.EVM { return nil, fmt.Errorf("VRF services: expected EVM relayer got %s", rid.Network) @@ -912,7 +1057,7 @@ func (d *Delegate) newServicesOCR2Keepers21( mc := d.cfg.Mercury().Credentials(credName) rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("keeper2 services: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "keeper2"} } if rid.Network != relay.EVM { return nil, fmt.Errorf("keeper2 services: expected EVM relayer got %s", rid.Network) @@ -1026,7 +1171,7 @@ func (d *Delegate) newServicesOCR2Keepers20( rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("keepers2.0 services: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "keepers2.0"} } if rid.Network != relay.EVM { return nil, fmt.Errorf("keepers2.0 services: expected EVM relayer got %s", rid.Network) @@ -1161,7 +1306,7 @@ func (d *Delegate) newServicesOCR2Functions( rid, err := spec.RelayID() if err != nil { - return nil, fmt.Errorf("functions services: %w: %w", ErrJobSpecNoRelayer, err) + return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "functions"} } if rid.Network != relay.EVM { return nil, fmt.Errorf("functions services: expected EVM relayer got %s", rid.Network) diff --git a/core/services/ocr2/plugins/generic/helpers_test.go b/core/services/ocr2/plugins/generic/helpers_test.go new file mode 100644 index 0000000000..e23e8e4642 --- /dev/null +++ b/core/services/ocr2/plugins/generic/helpers_test.go @@ -0,0 +1,7 @@ +package generic + +import "github.com/smartcontractkit/libocr/commontypes" + +func (t *TelemetryAdapter) Endpoints() map[[4]string]commontypes.MonitoringEndpoint { + return t.endpoints +} diff --git a/core/services/ocr2/plugins/generic/merge_test.go b/core/services/ocr2/plugins/generic/merge_test.go new file mode 100644 index 0000000000..9618c62357 --- /dev/null +++ b/core/services/ocr2/plugins/generic/merge_test.go @@ -0,0 +1,32 @@ +package generic + +import ( + "reflect" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMerge(t *testing.T) { + vars := map[string]interface{}{ + "jb": map[string]interface{}{ + "databaseID": "some-job-id", + }, + } + addedVars := map[string]interface{}{ + "jb": map[string]interface{}{ + "some-other-var": "foo", + }, + "val": 0, + } + + merge(vars, addedVars) + + assert.True(t, reflect.DeepEqual(vars, map[string]interface{}{ + "jb": map[string]interface{}{ + "databaseID": "some-job-id", + "some-other-var": "foo", + }, + "val": 0, + }), vars) +} diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go index ee0038232d..ef0e7421b5 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go @@ -1,9 +1,8 @@ -package generic +package generic_test import ( "context" "net/http" - "reflect" "testing" "time" @@ -20,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/generic" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -52,7 +52,7 @@ func TestAdapter_Integration(t *testing.T) { http.DefaultClient, http.DefaultClient, ) - pra := NewPipelineRunnerAdapter(logger, job.Job{}, pr) + pra := generic.NewPipelineRunnerAdapter(logger, job.Job{}, pr) results, err := pra.ExecuteRun(context.Background(), spec, types.Vars{Vars: map[string]interface{}{"val": 1}}, types.Options{}) require.NoError(t, err) @@ -83,7 +83,7 @@ func TestAdapter_AddsDefaultVars(t *testing.T) { logger := logger.TestLogger(t) mpr := newMockPipelineRunner() jobID, externalJobID, name := int32(100), uuid.New(), null.StringFrom("job-name") - pra := NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name}, mpr) + pra := generic.NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name}, mpr) _, err := pra.ExecuteRun(context.Background(), spec, types.Vars{}, types.Options{}) require.NoError(t, err) @@ -105,7 +105,7 @@ func TestPipelineRunnerAdapter_SetsVarsOnSpec(t *testing.T) { logger := logger.TestLogger(t) mpr := newMockPipelineRunner() jobID, externalJobID, name, jobType := int32(100), uuid.New(), null.StringFrom("job-name"), job.Type("generic") - pra := NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name, Type: jobType}, mpr) + pra := generic.NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name, Type: jobType}, mpr) maxDuration := time.Duration(100 * time.Second) _, err := pra.ExecuteRun(context.Background(), spec, types.Vars{}, types.Options{MaxTaskDuration: maxDuration}) @@ -115,29 +115,4 @@ func TestPipelineRunnerAdapter_SetsVarsOnSpec(t *testing.T) { assert.Equal(t, name.ValueOrZero(), mpr.spec.JobName) assert.Equal(t, string(jobType), mpr.spec.JobType) assert.Equal(t, maxDuration, mpr.spec.MaxTaskDuration.Duration()) - -} - -func TestMerge(t *testing.T) { - vars := map[string]interface{}{ - "jb": map[string]interface{}{ - "databaseID": "some-job-id", - }, - } - addedVars := map[string]interface{}{ - "jb": map[string]interface{}{ - "some-other-var": "foo", - }, - "val": 0, - } - - merge(vars, addedVars) - - assert.True(t, reflect.DeepEqual(vars, map[string]interface{}{ - "jb": map[string]interface{}{ - "databaseID": "some-job-id", - "some-other-var": "foo", - }, - "val": 0, - }), vars) } diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter.go b/core/services/ocr2/plugins/generic/telemetry_adapter.go index a81befa985..e7f87dcd46 100644 --- a/core/services/ocr2/plugins/generic/telemetry_adapter.go +++ b/core/services/ocr2/plugins/generic/telemetry_adapter.go @@ -6,17 +6,20 @@ import ( "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" + "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" + "github.com/smartcontractkit/chainlink-relay/pkg/types" ) var _ types.TelemetryService = (*TelemetryAdapter)(nil) type TelemetryAdapter struct { - endpointGenerator types.MonitoringEndpointGenerator + endpointGenerator telemetry.MonitoringEndpointGenerator endpoints map[[4]string]commontypes.MonitoringEndpoint } -func NewTelemetryAdapter(endpointGen types.MonitoringEndpointGenerator) *TelemetryAdapter { +func NewTelemetryAdapter(endpointGen telemetry.MonitoringEndpointGenerator) *TelemetryAdapter { return &TelemetryAdapter{ endpoints: make(map[[4]string]commontypes.MonitoringEndpoint), endpointGenerator: endpointGen, @@ -24,7 +27,7 @@ func NewTelemetryAdapter(endpointGen types.MonitoringEndpointGenerator) *Telemet } func (t *TelemetryAdapter) Send(ctx context.Context, network string, chainID string, contractID string, telemetryType string, payload []byte) error { - e, err := t.getOrCreateEndpoint(contractID, telemetryType, network, chainID) + e, err := t.getOrCreateEndpoint(network, chainID, contractID, telemetryType) if err != nil { return err } @@ -32,7 +35,7 @@ func (t *TelemetryAdapter) Send(ctx context.Context, network string, chainID str return nil } -func (t *TelemetryAdapter) getOrCreateEndpoint(contractID string, telemetryType string, network string, chainID string) (commontypes.MonitoringEndpoint, error) { +func (t *TelemetryAdapter) getOrCreateEndpoint(network string, chainID string, contractID string, telemetryType string) (commontypes.MonitoringEndpoint, error) { if contractID == "" { return nil, errors.New("contractID cannot be empty") } @@ -49,7 +52,7 @@ func (t *TelemetryAdapter) getOrCreateEndpoint(contractID string, telemetryType key := [4]string{network, chainID, contractID, telemetryType} e, ok := t.endpoints[key] if !ok { - e = t.endpointGenerator.GenMonitoringEndpoint(network, chainID, contractID, telemetryType) + e = t.endpointGenerator.GenMonitoringEndpoint(contractID, synchronization.TelemetryType(telemetryType), network, chainID) t.endpoints[key] = e } return e, nil diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter_test.go b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go index d430b889a4..9c42b0f85d 100644 --- a/core/services/ocr2/plugins/generic/telemetry_adapter_test.go +++ b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go @@ -1,13 +1,15 @@ -package generic +package generic_test import ( "context" - "fmt" "testing" "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/generic" + "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" ) type mockEndpoint struct { @@ -22,17 +24,17 @@ func (m *mockEndpoint) SendLog(payload []byte) { m.payload = payload } type mockGenerator struct{} -func (m *mockGenerator) GenMonitoringEndpoint(network, chainID, contractID, telemetryType string) commontypes.MonitoringEndpoint { +func (m *mockGenerator) GenMonitoringEndpoint(contractID string, telemetryType synchronization.TelemetryType, network string, chainID string) commontypes.MonitoringEndpoint { return &mockEndpoint{ network: network, chainID: chainID, contractID: contractID, - telemetryType: telemetryType, + telemetryType: string(telemetryType), } } func TestTelemetryAdapter(t *testing.T) { - ta := NewTelemetryAdapter(&mockGenerator{}) + ta := generic.NewTelemetryAdapter(&mockGenerator{}) tests := []struct { name string @@ -92,8 +94,7 @@ func TestTelemetryAdapter(t *testing.T) { } else { require.NoError(t, err) key := [4]string{test.networkID, test.chainID, test.contractID, test.telemetryType} - fmt.Printf("%+v", ta.endpoints) - endpoint, ok := ta.endpoints[key] + endpoint, ok := ta.Endpoints()[key] require.True(t, ok) me := endpoint.(*mockEndpoint) diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index cde1a1f927..78802f6559 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -114,6 +114,8 @@ func validateSpec(tree *toml.Tree, spec job.Job) error { return nil case types.Mercury: return validateOCR2MercurySpec(spec.OCR2OracleSpec.PluginConfig, *spec.OCR2OracleSpec.FeedID) + case types.GenericPlugin: + return validateOCR2GenericPluginSpec(spec.OCR2OracleSpec.PluginConfig) case "": return errors.New("no plugin specified") default: @@ -123,6 +125,37 @@ func validateSpec(tree *toml.Tree, spec job.Job) error { return nil } +type coreConfig struct { + Command string `json:"command"` + ProviderType string `json:"providerType"` + PluginName string `json:"pluginName"` + TelemetryType string `json:"telemetryType"` +} + +type OCR2GenericPluginConfig struct { + CoreConfig coreConfig `json:"coreConfig"` + PluginConfig json.RawMessage +} + +func validateOCR2GenericPluginSpec(jsonConfig job.JSONConfig) error { + p := OCR2GenericPluginConfig{} + err := json.Unmarshal(jsonConfig.Bytes(), &p) + if err != nil { + return err + } + + cc := p.CoreConfig + if cc.PluginName == "" { + return errors.New("generic config invalid: must provide plugin name") + } + + if cc.TelemetryType == "" { + return errors.New("generic config invalid: must provide telemetry type") + } + + return nil +} + func validateDKGSpec(jsonConfig job.JSONConfig) error { if jsonConfig == nil { return errors.New("pluginConfig is empty") diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index 4685ed745d..5b40224a4b 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -580,6 +580,89 @@ KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c require.Contains(t, err.Error(), "validation error for keyID") }, }, + { + name: "Generic plugin config validation - nothing provided", + toml: ` +type = "offchainreporting2" +schemaVersion = 1 +name = "dkg" +externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" +maxTaskDuration = "1s" +contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" +ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" +p2pv2Bootstrappers = [ + "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" +] +relay = "evm" +pluginType = "plugin" +transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" + +[relayConfig] +chainID = 4 + +[pluginConfig.coreConfig] +`, + assertion: func(t *testing.T, os job.Job, err error) { + require.Error(t, err) + require.ErrorContains(t, err, "must provide plugin name") + }, + }, + { + name: "Generic plugin config validation - plugin name provided", + toml: ` +type = "offchainreporting2" +schemaVersion = 1 +name = "dkg" +externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" +maxTaskDuration = "1s" +contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" +ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" +p2pv2Bootstrappers = [ + "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" +] +relay = "evm" +pluginType = "plugin" +transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" + +[relayConfig] +chainID = 4 + +[pluginConfig.coreConfig] +pluginName = "median" +`, + assertion: func(t *testing.T, os job.Job, err error) { + require.Error(t, err) + require.ErrorContains(t, err, "must provide telemetry type") + }, + }, + { + name: "Generic plugin config validation - all provided", + toml: ` +type = "offchainreporting2" +schemaVersion = 1 +name = "dkg" +externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" +maxTaskDuration = "1s" +contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" +ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" +p2pv2Bootstrappers = [ + "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" +] +relay = "evm" +pluginType = "plugin" +transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" + +[relayConfig] +chainID = 4 + +[pluginConfig.coreConfig] +pluginName = "median" +telemetryType = "median" +`, + assertion: func(t *testing.T, os job.Job, err error) { + require.NoError(t, err) + }, + }, } for _, tc := range tt { diff --git a/go.mod b/go.mod index 569912ed1b..820e42c330 100644 --- a/go.mod +++ b/go.mod @@ -97,6 +97,7 @@ require ( golang.org/x/time v0.3.0 golang.org/x/tools v0.14.0 gonum.org/v1/gonum v0.13.0 + google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 gopkg.in/guregu/null.v4 v4.0.0 @@ -364,7 +365,6 @@ require ( google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/grpc v1.58.3 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect From 2c295a7756fa41b83039a721598514bdaa522297 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Thu, 2 Nov 2023 17:16:20 +0100 Subject: [PATCH 056/327] BCF-2749 remove legacy chains job orm (#11140) * Remove legacy chains from job orm - This removes evm cfg loading into jobs str8 from db * Remove legacy chains from tests that used it for job orm * Remove legacy env var test from TestRunner integration tests * minor fix for test runner * minor err handling change in vrf delegate_test.go --- core/internal/cltest/cltest.go | 2 +- core/internal/cltest/factories.go | 4 +- core/internal/cltest/job_factories.go | 6 +- core/internal/features/features_test.go | 3 +- core/services/chainlink/application.go | 2 +- core/services/cron/cron_test.go | 6 +- core/services/directrequest/delegate_test.go | 2 +- core/services/feeds/orm_test.go | 4 +- core/services/fluxmonitorv2/orm_test.go | 6 +- core/services/job/job_orm_test.go | 96 ++++++----------- .../job/job_pipeline_orm_integration_test.go | 2 +- core/services/job/orm.go | 68 +++--------- core/services/job/orm_test.go | 5 +- core/services/job/runner_integration_test.go | 100 +----------------- core/services/job/spawner_test.go | 11 +- core/services/pipeline/orm_test.go | 10 +- core/services/vrf/delegate_test.go | 4 +- 17 files changed, 75 insertions(+), 256 deletions(-) diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 4cb9808fe2..fb4a69cf30 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -191,7 +191,7 @@ func NewJobPipelineV2(t testing.TB, cfg pipeline.BridgeConfig, jpcfg JobPipeline lggr := logger.TestLogger(t) prm := pipeline.NewORM(db, lggr, dbCfg, jpcfg.MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, dbCfg) - jrm := job.NewORM(db, legacyChains, prm, btORM, keyStore, lggr, dbCfg) + jrm := job.NewORM(db, prm, btORM, keyStore, lggr, dbCfg) pr := pipeline.NewRunner(prm, btORM, jpcfg, cfg, legacyChains, keyStore.Eth(), keyStore.VRF(), lggr, restrictedHTTPClient, unrestrictedHTTPClient) return JobPipelineV2TestHelper{ prm, diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 85ffc6b02b..82235baf6b 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -563,7 +563,7 @@ func MustInsertV2JobSpec(t *testing.T, db *sqlx.DB, transmitterAddress common.Ad PipelineSpecID: pipelineSpec.ID, } - jorm := job.NewORM(db, nil, nil, nil, nil, logger.TestLogger(t), configtest.NewTestGeneralConfig(t).Database()) + jorm := job.NewORM(db, nil, nil, nil, logger.TestLogger(t), configtest.NewTestGeneralConfig(t).Database()) err = jorm.InsertJob(&jb) require.NoError(t, err) return jb @@ -619,7 +619,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey tlg := logger.TestLogger(t) prm := pipeline.NewORM(db, tlg, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, tlg, cfg.Database()) - jrm := job.NewORM(db, nil, prm, btORM, nil, tlg, cfg.Database()) + jrm := job.NewORM(db, prm, btORM, nil, tlg, cfg.Database()) err = jrm.InsertJob(&jb) require.NoError(t, err) return jb diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index 77fee125e2..b76d6c7ec2 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -11,13 +11,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) const ( @@ -66,9 +64,7 @@ func getORMs(t *testing.T, db *sqlx.DB) (jobORM job.ORM, pipelineORM pipeline.OR lggr := logger.TestLogger(t) pipelineORM = pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db, lggr, config.Database()) - cc := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) - jobORM = job.NewORM(db, legacyChains, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) + jobORM = job.NewORM(db, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) t.Cleanup(func() { jobORM.Close() }) return } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 058c8325b9..3293066191 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -237,8 +237,7 @@ observationSource = """ pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database()) - legacyChains := app.GetRelayers().LegacyEVMChains() - jobORM := job.NewORM(app.GetSqlxDB(), legacyChains, pipelineORM, bridgeORM, app.KeyStore, logger.TestLogger(t), cfg.Database()) + jobORM := job.NewORM(app.GetSqlxDB(), pipelineORM, bridgeORM, app.KeyStore, logger.TestLogger(t), cfg.Database()) runs := cltest.WaitForPipelineComplete(t, 0, jobID, 1, 2, jobORM, 5*time.Second, 300*time.Millisecond) require.Len(t, runs, 1) diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 354f047904..63a9b2696c 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -251,7 +251,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { sessionORM = sessions.NewORM(db, cfg.WebServer().SessionTimeout().Duration(), globalLogger, cfg.Database(), auditLogger) mercuryORM = mercury.NewORM(db, globalLogger, cfg.Database()) pipelineRunner = pipeline.NewRunner(pipelineORM, bridgeORM, cfg.JobPipeline(), cfg.WebServer(), legacyEVMChains, keyStore.Eth(), keyStore.VRF(), globalLogger, restrictedHTTPClient, unrestrictedHTTPClient) - jobORM = job.NewORM(db, legacyEVMChains, pipelineORM, bridgeORM, keyStore, globalLogger, cfg.Database()) + jobORM = job.NewORM(db, pipelineORM, bridgeORM, keyStore, globalLogger, cfg.Database()) txmORM = txmgr.NewTxStore(db, globalLogger, cfg.Database()) ) diff --git a/core/services/cron/cron_test.go b/core/services/cron/cron_test.go index 19a51a3065..b561248edd 100644 --- a/core/services/cron/cron_test.go +++ b/core/services/cron/cron_test.go @@ -12,14 +12,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/cron" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) func TestCronV2Pipeline(t *testing.T) { @@ -28,12 +26,10 @@ func TestCronV2Pipeline(t *testing.T) { db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - relayerExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: evmtest.NewEthClientMockWithDefaultChain(t), KeyStore: keyStore.Eth()}) lggr := logger.TestLogger(t) orm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, cfg.Database()) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayerExtenders) - jobORM := job.NewORM(db, legacyChains, orm, btORM, keyStore, lggr, cfg.Database()) + jobORM := job.NewORM(db, orm, btORM, keyStore, lggr, cfg.Database()) jb := &job.Job{ Type: job.Cron, diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index e58dbaeb50..34c79a0afb 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -88,8 +88,8 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi lggr := logger.TestLogger(t) orm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, cfg.Database()) + jobORM := job.NewORM(db, orm, btORM, keyStore, lggr, cfg.Database()) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := job.NewORM(db, legacyChains, orm, btORM, keyStore, lggr, cfg.Database()) delegate := directrequest.NewDelegate(lggr, runner, orm, legacyChains, mailMon) jb := cltest.MakeDirectRequestJobSpec(t) diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 746956bbfc..3d51ad45ff 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -1656,8 +1656,7 @@ func createJob(t *testing.T, db *sqlx.DB, externalJobID uuid.UUID) *job.Job { bridgeORM = bridges.NewORM(db, lggr, config.Database()) relayExtenders = evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) ) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := job.NewORM(db, legacyChains, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) + orm := job.NewORM(db, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) @@ -1667,6 +1666,7 @@ func createJob(t *testing.T, db *sqlx.DB, externalJobID uuid.UUID) *job.Job { _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jb, err := ocr.ValidatedOracleSpecToml(legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index 0bb0803261..6e06a1e65b 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -17,13 +17,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -96,11 +94,9 @@ func TestORM_UpdateFluxMonitorRoundStats(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db, lggr, cfg.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{GeneralConfig: cfg, DB: db, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) // Instantiate a real job ORM because we need to create a job to satisfy // a check in pipeline.CreateRun - jobORM := job.NewORM(db, legacyChains, pipelineORM, bridgeORM, keyStore, lggr, cfg.Database()) + jobORM := job.NewORM(db, pipelineORM, bridgeORM, keyStore, lggr, cfg.Database()) orm := newORM(t, db, cfg.Database(), nil) address := testutils.NewAddress() diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 74416e68dc..6306dedcef 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -83,9 +83,7 @@ func TestORM(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: ethKeyStore}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) borm := bridges.NewORM(db, logger.TestLogger(t), config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -331,9 +329,7 @@ func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { lggr := logger.TestLogger(t) pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) scopedConfig := evmtest.NewChainScopedConfig(t, config) korm := keeper.NewORM(db, logger.TestLogger(t), scopedConfig.Database()) @@ -342,6 +338,8 @@ func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jb, err := ocr.ValidatedOracleSpecToml(legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ TransmitterAddress: address.Hex(), DS1BridgeName: bridge.Name.String(), @@ -431,10 +429,8 @@ func TestORM_CreateJob_VRFV2(t *testing.T) { lggr := logger.TestLogger(t) pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) fromAddresses := []string{cltest.NewEIP55Address().String(), cltest.NewEIP55Address().String()} jb, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec( @@ -514,9 +510,7 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { lggr := logger.TestLogger(t) pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - cc := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) fromAddresses := []string{cltest.NewEIP55Address().String(), cltest.NewEIP55Address().String()} jb, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec( @@ -599,9 +593,7 @@ func TestORM_CreateJob_OCRBootstrap(t *testing.T) { lggr := logger.TestLogger(t) pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := ocrbootstrap.ValidatedBootstrapSpecToml(testspecs.GetOCRBootstrapSpec()) require.NoError(t, err) @@ -628,9 +620,7 @@ func TestORM_CreateJob_EVMChainID_Validation(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) t.Run("evm chain id validation for ocr works", func(t *testing.T) { jb := job.Job{ @@ -725,9 +715,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) // defaultChainID is deprecated defaultChainID := customChainID @@ -745,6 +733,8 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { TransmitterAddress: address.Hex(), JobID: externalJobID.UUID.String(), }) + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jb, err := ocr.ValidatedOracleSpecToml(legacyChains, spec.Toml()) require.NoError(t, err) @@ -794,9 +784,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -857,10 +845,7 @@ func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - require.True(t, relayExtenders.Len() > 0) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) @@ -974,14 +959,15 @@ func Test_FindJobs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jb1, err := ocr.ValidatedOracleSpecToml(legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: uuid.New().String(), @@ -1054,9 +1040,8 @@ func Test_FindJob(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1065,6 +1050,8 @@ func Test_FindJob(t *testing.T) { // Must uniquely name the OCR Specs to properly insert a new job in the job table. externalJobID := uuid.New() _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) job, err := ocr.ValidatedOracleSpecToml(legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), @@ -1232,9 +1219,7 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) @@ -1263,20 +1248,7 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { }) t.Run("with chainID disabled", func(t *testing.T) { - newCfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0] = &evmcfg.EVMConfig{ - ChainID: utils.NewBigI(0), - Enabled: ptr(false), - } - c.EVM = append(c.EVM, &evmcfg.EVMConfig{ - ChainID: utils.NewBigI(123123123), - Enabled: ptr(true), - }) - }) - relayExtenders2 := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: newCfg, KeyStore: keyStore.Eth()}) - legacyChains2 := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders2) - - orm2 := NewTestORM(t, db, legacyChains2, pipelineORM, bridgesORM, keyStore, config.Database()) + orm2 := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) jbs, err2 := orm2.FindJobsByPipelineSpecIDs([]int32{jb.PipelineSpecID}) require.NoError(t, err2) @@ -1297,7 +1269,7 @@ func Test_FindPipelineRuns(t *testing.T) { bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1358,7 +1330,7 @@ func Test_PipelineRunsByJobID(t *testing.T) { bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1419,7 +1391,7 @@ func Test_FindPipelineRunIDsByJobID(t *testing.T) { bridgesORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -1527,7 +1499,7 @@ func Test_FindPipelineRunsByIDs(t *testing.T) { bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1583,9 +1555,7 @@ func Test_FindPipelineRunByID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) @@ -1628,9 +1598,7 @@ func Test_FindJobWithoutSpecErrors(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) @@ -1667,9 +1635,7 @@ func Test_FindSpecErrorsByJobIDs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) @@ -1705,7 +1671,7 @@ func Test_CountPipelineRunsByJobID(t *testing.T) { bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index 1158fc4626..a2b6cc4618 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -156,7 +156,7 @@ func TestPipelineORM_Integration(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) runner := pipeline.NewRunner(orm, btORM, config.JobPipeline(), cfg.WebServer(), legacyChains, nil, nil, lggr, nil, nil) - jobORM := NewTestORM(t, db, legacyChains, orm, btORM, keyStore, cfg.Database()) + jobORM := NewTestORM(t, db, orm, btORM, keyStore, cfg.Database()) dbSpec := makeVoterTurnoutOCRJobSpec(t, transmitterAddress, bridge.Name.String(), bridge2.Name.String()) diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 372b2fe74a..c6ec4ed5c8 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -21,8 +21,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -85,35 +83,25 @@ type ORMConfig interface { } type orm struct { - q pg.Q - legacyChains evm.LegacyChainContainer - keyStore keystore.Master - pipelineORM pipeline.ORM - lggr logger.SugaredLogger - cfg pg.QConfig - bridgeORM bridges.ORM + q pg.Q + keyStore keystore.Master + pipelineORM pipeline.ORM + lggr logger.SugaredLogger + cfg pg.QConfig + bridgeORM bridges.ORM } var _ ORM = (*orm)(nil) -func NewORM( - db *sqlx.DB, - legacyChains evm.LegacyChainContainer, - pipelineORM pipeline.ORM, - bridgeORM bridges.ORM, - keyStore keystore.Master, // needed to validation key properties on new job creation - lggr logger.Logger, - cfg pg.QConfig, -) *orm { +func NewORM(db *sqlx.DB, pipelineORM pipeline.ORM, bridgeORM bridges.ORM, keyStore keystore.Master, lggr logger.Logger, cfg pg.QConfig) *orm { namedLogger := logger.Sugared(lggr.Named("JobORM")) return &orm{ - q: pg.NewQ(db, namedLogger, cfg), - legacyChains: legacyChains, - keyStore: keyStore, - pipelineORM: pipelineORM, - bridgeORM: bridgeORM, - lggr: namedLogger, - cfg: cfg, + q: pg.NewQ(db, namedLogger, cfg), + keyStore: keyStore, + pipelineORM: pipelineORM, + bridgeORM: bridgeORM, + lggr: namedLogger, + cfg: cfg, } } func (o *orm) Close() error { @@ -704,29 +692,12 @@ func (o *orm) FindJobs(offset, limit int) (jobs []Job, count int, err error) { if err != nil { return err } - for i := range jobs { - err = multierr.Combine(err, o.LoadConfigVars(&jobs[i])) - } + return nil }) return jobs, int(count), err } -func (o *orm) LoadConfigVars(jb *Job) error { - if jb.OCROracleSpec != nil { - ch, err := o.legacyChains.Get(jb.OCROracleSpec.EVMChainID.String()) - if err != nil { - return err - } - newSpec, err := LoadConfigVarsOCR(ch.Config().EVM().OCR(), ch.Config().OCR(), *jb.OCROracleSpec) - if err != nil { - return err - } - jb.OCROracleSpec = newSpec - } - return nil -} - func LoadDefaultVRFPollPeriod(vrfs VRFSpec) *VRFSpec { if vrfs.PollPeriod == 0 { vrfs.PollPeriod = 5 * time.Second @@ -842,7 +813,7 @@ func (o *orm) FindJobWithoutSpecErrors(id int32) (jb Job, err error) { return jb, errors.Wrap(err, "FindJobWithoutSpecErrors failed") } - return jb, o.LoadConfigVars(&jb) + return jb, nil } // FindSpecErrorsByJobIDs returns all jobs spec errors by jobs IDs @@ -931,7 +902,7 @@ func (o *orm) findJob(jb *Job, col string, arg interface{}, qopts ...pg.QOpt) er if err != nil { return errors.Wrap(err, "findJob failed") } - return o.LoadConfigVars(jb) + return nil } func (o *orm) FindJobIDsWithBridge(name string) (jids []int32, err error) { @@ -1174,13 +1145,6 @@ func (o *orm) FindJobsByPipelineSpecIDs(ids []int32) ([]Job, error) { if err != nil { return err } - for i := range jbs { - err = o.LoadConfigVars(&jbs[i]) - //We must return the jobs even if the chainID is disabled - if err != nil && !errors.Is(err, chains.ErrNoSuchChainID) { - return err - } - } return nil }) diff --git a/core/services/job/orm_test.go b/core/services/job/orm_test.go index cd437147b4..48805388a3 100644 --- a/core/services/job/orm_test.go +++ b/core/services/job/orm_test.go @@ -9,7 +9,6 @@ import ( "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -22,8 +21,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" ) -func NewTestORM(t *testing.T, db *sqlx.DB, legacyChains evm.LegacyChainContainer, pipelineORM pipeline.ORM, bridgeORM bridges.ORM, keyStore keystore.Master, cfg pg.QConfig) job.ORM { - o := job.NewORM(db, legacyChains, pipelineORM, bridgeORM, keyStore, logger.TestLogger(t), cfg) +func NewTestORM(t *testing.T, db *sqlx.DB, pipelineORM pipeline.ORM, bridgeORM bridges.ORM, keyStore keystore.Master, cfg pg.QConfig) job.ORM { + o := job.NewORM(db, pipelineORM, bridgeORM, keyStore, logger.TestLogger(t), cfg) t.Cleanup(func() { o.Close() }) return o } diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index c0fff1e560..7e8ed5e87f 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -85,7 +85,7 @@ func TestRunner(t *testing.T) { c := clhttptest.NewTestLocalOnlyHTTPClient() runner := pipeline.NewRunner(pipelineORM, btORM, config.JobPipeline(), config.WebServer(), legacyChains, nil, nil, logger.TestLogger(t), c, c) - jobORM := NewTestORM(t, db, legacyChains, pipelineORM, btORM, keyStore, config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, btORM, keyStore, config.Database()) _, placeHolderAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -428,45 +428,7 @@ answer1 [type=median index=0]; } }) - t.Run("missing required env vars", func(t *testing.T) { - s := ` - type = "offchainreporting" - schemaVersion = 1 - contractAddress = "%s" - isBootstrapPeer = false - evmChainID = "0" - observationSource = """ -ds1 [type=http method=GET url="%s" allowunrestrictednetworkaccess="true" %s]; -ds1_parse [type=jsonparse path="USD" lax=true]; -ds1 -> ds1_parse; -""" -` - s = fmt.Sprintf(s, cltest.NewEIP55Address(), "http://blah.com", "") - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) - require.NoError(t, err) - err = toml.Unmarshal([]byte(s), &jb) - require.NoError(t, err) - jb.MaxTaskDuration = models.Interval(cltest.MustParseDuration(t, "1s")) - err = jobORM.CreateJob(&jb) - require.NoError(t, err) - sd := ocr.NewDelegate( - db, - jobORM, - keyStore, - nil, - nil, - nil, - legacyChains, - logger.TestLogger(t), - config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), - ) - _, err = sd.ServicesForSpec(jb) - // We expect this to fail as neither the required vars are not set either via the env nor the job itself. - require.Error(t, err) - }) - - t.Run("use env for minimal bootstrap", func(t *testing.T) { + t.Run("minimal bootstrap", func(t *testing.T) { s := ` type = "offchainreporting" schemaVersion = 1 @@ -504,53 +466,6 @@ ds1 -> ds1_parse; require.NoError(t, err) }) - t.Run("use env for minimal non-bootstrap", func(t *testing.T) { - s := ` - type = "offchainreporting" - schemaVersion = 1 - contractAddress = "%s" - isBootstrapPeer = false - observationTimeout = "15s" - evmChainID = "0" - observationSource = """ -ds1 [type=http method=GET url="%s" allowunrestrictednetworkaccess="true" %s]; -ds1_parse [type=jsonparse path="USD" lax=true]; -ds1 -> ds1_parse; -""" -` - s = fmt.Sprintf(s, cltest.NewEIP55Address(), "http://blah.com", "") - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) - require.NoError(t, err) - err = toml.Unmarshal([]byte(s), &jb) - require.NoError(t, err) - jb.MaxTaskDuration = models.Interval(cltest.MustParseDuration(t, "1s")) - err = jobORM.CreateJob(&jb) - require.NoError(t, err) - // Assert the override - assert.Equal(t, jb.OCROracleSpec.ObservationTimeout, models.Interval(cltest.MustParseDuration(t, "15s"))) - // Assert that this is default - assert.Equal(t, models.Interval(20000000000), jb.OCROracleSpec.BlockchainTimeout) - assert.Equal(t, models.Interval(cltest.MustParseDuration(t, "1s")), jb.MaxTaskDuration) - - lggr := logger.TestLogger(t) - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - sd := ocr.NewDelegate( - db, - jobORM, - keyStore, - nil, - pw, - monitoringEndpoint, - legacyChains, - lggr, - config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), - ) - _, err = sd.ServicesForSpec(jb) - require.NoError(t, err) - }) - t.Run("test min non-bootstrap", func(t *testing.T) { kb, err := keyStore.OCR().Create() require.NoError(t, err) @@ -765,9 +680,6 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) - keyStore := cltest.NewKeyStore(t, app.GetSqlxDB(), pgtest.NewQConfig(true)) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: app.GetSqlxDB(), Client: ethClient, GeneralConfig: cfg, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) require.NoError(t, app.Start(testutils.Context(t))) var ( @@ -898,7 +810,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database()) - jobORM := NewTestORM(t, app.GetSqlxDB(), legacyChains, pipelineORM, bridgesORM, app.KeyStore, cfg.Database()) + jobORM := NewTestORM(t, app.GetSqlxDB(), pipelineORM, bridgesORM, app.KeyStore, cfg.Database()) // Trigger v2/resume select { @@ -947,10 +859,6 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) - keyStore := cltest.NewKeyStore(t, app.GetSqlxDB(), pgtest.NewQConfig(true)) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: app.GetSqlxDB(), Client: ethClient, GeneralConfig: cfg, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, app.Start(testutils.Context(t))) var ( @@ -1079,7 +987,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database()) - jobORM := NewTestORM(t, app.GetSqlxDB(), legacyChains, pipelineORM, bridgesORM, app.KeyStore, cfg.Database()) + jobORM := NewTestORM(t, app.GetSqlxDB(), pipelineORM, bridgesORM, app.KeyStore, cfg.Database()) // Trigger v2/resume select { diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index be4a480a6c..1f10a86e9c 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -97,7 +98,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) t.Run("should respect its dependents", func(t *testing.T) { lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, legacyChains, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) a := utils.NewDependentAwaiter() a.AddDependents(1) spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{}, db, lggr, []utils.DependentAwaiter{a}) @@ -120,7 +121,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { jobB := makeOCRJobSpec(t, address, bridge.Name.String(), bridge2.Name.String()) lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, legacyChains, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) eventuallyA := cltest.NewAwaiter() serviceA1 := mocks.NewServiceCtx(t) @@ -185,7 +186,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventually.ItHappened() }) lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, legacyChains, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} @@ -219,7 +220,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyStart.ItHappened() }) lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, legacyChains, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} @@ -297,7 +298,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { jobOCR2VRF := makeOCR2VRFJobSpec(t, keyStore, config, address, chain.ID(), 2) - orm := NewTestORM(t, db, legacyChains, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }) diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index a487c231fb..f916c24f0a 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -17,14 +17,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -522,9 +520,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { porm := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jorm := job.NewORM(db, legacyChains, porm, bridgeORM, keyStore, lggr, config.Database()) + jorm := job.NewORM(db, porm, bridgeORM, keyStore, lggr, config.Database()) defer func() { assert.NoError(t, jorm.Close()) }() timestamp := time.Now() @@ -624,9 +620,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { porm := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db, lggr, config.Database()) - relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jorm := job.NewORM(db, legacyChains, porm, bridgeORM, keyStore, lggr, config.Database()) + jorm := job.NewORM(db, porm, bridgeORM, keyStore, lggr, config.Database()) defer func() { assert.NoError(t, jorm.Close()) }() timestamp := time.Now() diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 38b361716b..91ae4400e3 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -78,10 +78,10 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv btORM := bridges.NewORM(db, lggr, cfg.Database()) txm := txmmocks.NewMockEvmTxManager(t) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) + jrm := job.NewORM(db, prm, btORM, ks, lggr, cfg.Database()) + t.Cleanup(func() { assert.NoError(t, jrm.Close()) }) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{LogBroadcaster: lb, KeyStore: ks.Eth(), Client: ec, DB: db, GeneralConfig: cfg, TxManager: txm}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jrm := job.NewORM(db, legacyChains, prm, btORM, ks, lggr, cfg.Database()) - t.Cleanup(func() { jrm.Close() }) pr := pipeline.NewRunner(prm, btORM, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ks.Eth(), ks.VRF(), lggr, nil, nil) require.NoError(t, ks.Unlock(testutils.Password)) k, err := ks.Eth().Create(testutils.FixtureChainID) From 96567e127d72f3f58c7a3e75dfdd1a69a6c316d4 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Thu, 2 Nov 2023 20:35:04 +0400 Subject: [PATCH 057/327] add sepolia-arbitrum to automation benchmark test (#11149) * add sepolia-arbitrum to automation benchmark test * add back P2P.V2 Enabled * fix switch case in DeployKeeperRegistry --- .github/workflows/automation-benchmark-tests.yml | 1 + integration-tests/benchmark/keeper_test.go | 11 +++++++++-- integration-tests/contracts/contract_deployer.go | 14 ++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index 5c4dced934..d78e5e76ac 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -25,6 +25,7 @@ on: - MUMBAI - SEPOLIA - BASE_GOERLI + - ARBITRUM_SEPOLIA TestInputs: description: TestInputs required: false diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 55f769e73b..25a147fbf0 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -37,6 +37,7 @@ Enabled = true [P2P] [P2P.V2] +Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"] [Keeper] @@ -242,13 +243,13 @@ func repeatRegistries(registryVersion eth_contracts.KeeperRegistryVersion, numbe var networkConfig = map[string]NetworkConfig{ "SimulatedGeth": { - upkeepSLA: int64(20), + upkeepSLA: int64(120), //2 minutes blockTime: time.Second, deltaStage: 30 * time.Second, funding: big.NewFloat(100_000), }, "geth": { - upkeepSLA: int64(20), + upkeepSLA: int64(120), //2 minutes blockTime: time.Second, deltaStage: 30 * time.Second, funding: big.NewFloat(100_000), @@ -289,6 +290,12 @@ var networkConfig = map[string]NetworkConfig{ deltaStage: 20 * time.Second, funding: big.NewFloat(ChainlinkNodeFunding), }, + "ArbitrumSepolia": { + upkeepSLA: int64(120), + blockTime: time.Second, + deltaStage: 20 * time.Second, + funding: big.NewFloat(ChainlinkNodeFunding), + }, } func getEnv(key, fallback string) string { diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 94f6c73386..e203d8318f 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -876,14 +876,20 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( opts *KeeperRegistryOpts, ) (KeeperRegistry, error) { var mode uint8 - switch e.client.GetChainID() { + switch e.client.GetChainID().Int64() { //Arbitrum payment model - case big.NewInt(421613): + //Goerli Arbitrum + case 421613: + mode = uint8(1) + //Sepolia Arbitrum + case 421614: mode = uint8(1) //Optimism payment model - case big.NewInt(420): + //Goerli Optimism + case 420: mode = uint8(2) - case big.NewInt(84531): + //Goerli Base + case 84531: mode = uint8(2) default: mode = uint8(0) From 388b267e1776262008a3488b656620f1f776742c Mon Sep 17 00:00:00 2001 From: Ryan Hall Date: Thu, 2 Nov 2023 13:20:09 -0400 Subject: [PATCH 058/327] debug script improvements (#11152) --- core/scripts/chaincli/handler/debug.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 7cf801d332..daf012ee16 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -275,13 +275,21 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failUnknown("failed to execute mercury callback ", err) } + if callbackResult.UpkeepFailureReason != 0 { + message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) + } upkeepNeeded, performData = callbackResult.UpkeepNeeded, callbackResult.PerformData - // do tenderly simulation + // do tenderly simulations rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.extraData) if err != nil { - failUnknown("failed to pack raw checkUpkeep call", err) + failUnknown("failed to pack raw checkCallback call", err) } addLink("checkCallback simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.extraData) + if err != nil { + failUnknown("failed to pack raw checkCallback (direct) call", err) + } + addLink("checkCallback (direct) simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) } else { message("did not revert with StreamsLookup error") } From 206fb8b3ab4dc96bb55788bc111abd54939ea040 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:36:28 -0400 Subject: [PATCH 059/327] Avoid rate limiting when pulling public docker hub images (#11153) --- .../build-sign-publish-chainlink/action.yml | 22 +++++++++++++++++++ .github/workflows/build-publish-develop.yml | 2 ++ .github/workflows/build-publish.yml | 12 +++++----- .github/workflows/build.yml | 5 +++-- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/.github/actions/build-sign-publish-chainlink/action.yml b/.github/actions/build-sign-publish-chainlink/action.yml index 55c682bc8d..fe4ef858f5 100644 --- a/.github/actions/build-sign-publish-chainlink/action.yml +++ b/.github/actions/build-sign-publish-chainlink/action.yml @@ -13,6 +13,12 @@ inputs: description: Path to the Dockerfile (relative to the repo root) default: core/chainlink.Dockerfile required: false + dockerhub_username: + description: Username for Docker Hub to avoid rate limits when pulling public images + required: false + dockerhub_password: + description: Password for Docker Hub to avoid rate limits when pulling public images + required: false ecr-hostname: description: The ECR registry scope default: public.ecr.aws @@ -126,6 +132,14 @@ runs: type=semver,pattern={{version}},suffix=${{ inputs.ecr-tag-suffix }}-root type=sha,format=short,suffix=${{ inputs.ecr-tag-suffix }}-root + # To avoid rate limiting from Docker Hub, we login with a paid user account. + - name: Login to Docker Hub + if: inputs.dockerhub_username && inputs.dockerhub_password + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + username: ${{ inputs.dockerhub_username }} + password: ${{ inputs.dockerhub_password }} + - name: Build and push root docker image id: buildpush-root uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 @@ -159,6 +173,14 @@ runs: images: ${{ env.shared-images }} tags: ${{ env.shared-tag-list }} + # To avoid rate limiting from Docker Hub, we login with a paid user account. + - name: Login to Docker Hub + if: inputs.dockerhub_username && inputs.dockerhub_password + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + username: ${{ inputs.dockerhub_username }} + password: ${{ inputs.dockerhub_password }} + - name: Build and push non-root docker image id: buildpush-nonroot uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index 076fdf817d..b885972237 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -52,6 +52,8 @@ jobs: ecr-image-name: chainlink ecr-tag-suffix: ${{ matrix.image.tag-suffix }} dockerfile: ${{ matrix.image.dockerfile }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} git-commit-sha: ${{ steps.git-ref.outputs.checked-out || github.sha }} - name: Collect Metrics if: always() diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 4d5a42a369..1bda6957a2 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -1,17 +1,17 @@ -name: 'Build Chainlink and Publish' +name: "Build Chainlink and Publish" on: # Mimics old circleci behaviour push: tags: - - 'v*' + - "v*" branches: - master - - 'release/**' + - "release/**" jobs: checks: - name: 'Checks' + name: "Checks" runs-on: ubuntu-20.04 steps: - name: Checkout repository @@ -42,10 +42,12 @@ jobs: aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} aws-region: ${{ secrets.AWS_REGION }} sign-images: true - sign-method: 'keypair' + sign-method: "keypair" cosign-private-key: ${{ secrets.COSIGN_PRIVATE_KEY }} cosign-public-key: ${{ secrets.COSIGN_PUBLIC_KEY }} cosign-password: ${{ secrets.COSIGN_PASSWORD }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} verify-signature: true - name: Collect Metrics if: always() diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f9a8ea8b3..6282e2168d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: 'Build Chainlink' +name: "Build Chainlink" on: pull_request: @@ -7,7 +7,6 @@ on: - master jobs: - build-chainlink: runs-on: ubuntu-20.04 steps: @@ -17,6 +16,8 @@ jobs: - name: Build chainlink image uses: ./.github/actions/build-sign-publish-chainlink with: + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} publish: false sign-images: false - name: Collect Metrics From a9d27aa2ccdebcb8b79af9ddf4d42d7f1fab6d9e Mon Sep 17 00:00:00 2001 From: David Cauchi <13139524+davidcauchi@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:40:47 +0100 Subject: [PATCH 060/327] Remove duplicate table (#11151) --- integration-tests/config/config.go | 1 - 1 file changed, 1 deletion(-) diff --git a/integration-tests/config/config.go b/integration-tests/config/config.go index 44c108b0d7..1da8254e0e 100644 --- a/integration-tests/config/config.go +++ b/integration-tests/config/config.go @@ -8,7 +8,6 @@ Enabled = true [P2P.V2] Enabled = false -[P2P] [P2P.V1] Enabled = true ListenIP = '0.0.0.0' From 618d06b3adf412ad5e3eea2fab39177ed8505c15 Mon Sep 17 00:00:00 2001 From: Tate Date: Thu, 2 Nov 2023 13:42:06 -0600 Subject: [PATCH 061/327] [TT-668] E2E Dockerhub Login Rate Limit Issue Fix (#11155) --- .../workflows/automation-benchmark-tests.yml | 2 +- .../workflows/automation-ondemand-tests.yml | 2 +- .github/workflows/integration-chaos-tests.yml | 2 +- .github/workflows/integration-tests.yml | 28 ++++++++++++------- .github/workflows/on-demand-ocr-soak-test.yml | 2 +- .../on-demand-vrfv2plus-performance-test.yml | 2 +- .github/workflows/performance-tests.yml | 2 +- 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index d78e5e76ac..7bdb66c919 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -109,7 +109,7 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 env: DETACH_RUNNER: true TEST_SUITE: benchmark diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index fb8adcfdb6..88c2c126dc 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -172,7 +172,7 @@ jobs: echo "version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT fi - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 env: PYROSCOPE_SERVER: ${{ matrix.tests.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }} diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 4ad985e915..892a43e76f 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -109,7 +109,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 11 ./chaos 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index b66ab58d55..445a027731 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -212,7 +212,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 env: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} @@ -223,6 +223,8 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} @@ -231,7 +233,7 @@ jobs: cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + QA_KUBECONFIG: "" - name: Collect Metrics if: always() id: collect-gha-metrics @@ -411,7 +413,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 env: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} @@ -422,6 +424,8 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }}${{ matrix.product.tag_suffix }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} artifacts_name: ${{ matrix.product.name }}-test-logs artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} @@ -431,11 +435,11 @@ jobs: cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + QA_KUBECONFIG: "" ## Run this step when changes that do not need the test to run are made - name: Run Setup if: needs.changes.outputs.src == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod @@ -572,7 +576,7 @@ jobs: run: | echo "Running migration tests from version '${{ steps.get_latest_version.outputs.latest_version }}' to: '${{ github.sha }}'" - name: Run Migration Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -817,12 +821,14 @@ jobs: ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Run Setup if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: go_mod_path: ./integration-tests/go.mod cache_restore_only: true cache_key_id: core-solana-e2e-${{ env.MOD_CACHE_VERSION }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} @@ -844,7 +850,7 @@ jobs: docker rm "$CONTAINER_ID" - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: export ENV_JOB_IMAGE=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} && make test_smoke cl_repo: ${{ env.CHAINLINK_IMAGE }} @@ -857,7 +863,7 @@ jobs: aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + QA_KUBECONFIG: "" run_setup: false - name: Upload test log uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 @@ -929,7 +935,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} ## Only run OCR smoke test for now - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 env: PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} PYROSCOPE_ENVIRONMENT: ci-smoke-ocr-evm-${{ matrix.testnet }} # TODO: Only for OCR for now @@ -940,6 +946,8 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} artifacts_location: ./integration-tests/smoke/logs publish_check_name: ${{ matrix.testnet }} OCR Smoke Test Results token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 1fb79d8ccd..4a18aabf22 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -129,7 +129,7 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 env: DETACH_RUNNER: true TEST_SUITE: soak diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index deb977e43f..c51f7f5a2f 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -118,7 +118,7 @@ jobs: with: fetch-depth: 0 - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 6h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./load/vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index 87fb75beca..57907fe6c2 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -57,7 +57,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 10 ./performance 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: make gomod From 1208fb3d3dec36876dfd74a9a05db437840ce9fc Mon Sep 17 00:00:00 2001 From: amit-momin <108959691+amit-momin@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:05:10 -0500 Subject: [PATCH 062/327] Remove direct TXM DB reads from VRF (#10987) * Removed direct TXM DB reads from VRF * Addressed PR feedback * Added tx deduping to vrf respCount method * Fixed linting * Fixed failing test --------- Co-authored-by: Prashant Yadav <34992934+prashantkumar1982@users.noreply.github.com> --- common/txmgr/mocks/tx_manager.go | 104 ++++++ common/txmgr/txmgr.go | 40 +++ common/txmgr/types/mocks/tx_store.go | 105 ++++++ common/txmgr/types/tx_store.go | 8 + .../evm/client/simulated_backend_client.go | 3 +- core/chains/evm/txmgr/evm_tx_store.go | 79 ++++- core/chains/evm/txmgr/mocks/evm_tx_store.go | 104 ++++++ core/chains/evm/txmgr/test_helpers.go | 151 ++++++++ core/chains/evm/txmgr/txmgr_test.go | 177 ++-------- core/services/vrf/delegate.go | 137 +------- core/services/vrf/delegate_test.go | 36 +- core/services/vrf/v1/listener_v1.go | 103 ++++-- .../vrf/v2/integration_helpers_test.go | 28 +- .../vrf/v2/integration_v2_plus_test.go | 2 +- core/services/vrf/v2/integration_v2_test.go | 169 ++++----- core/services/vrf/v2/listener_v2.go | 222 +++++++----- .../vrf/v2/listener_v2_helpers_test.go | 22 ++ core/services/vrf/v2/listener_v2_test.go | 329 +++++++++++------- core/services/vrf/v2/listener_v2_types.go | 6 +- core/services/vrf/vrfcommon/utils.go | 78 +++++ core/web/jobs_controller_test.go | 14 +- 21 files changed, 1265 insertions(+), 652 deletions(-) create mode 100644 core/chains/evm/txmgr/test_helpers.go create mode 100644 core/services/vrf/vrfcommon/utils.go diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index c01f182c9b..89abf1dea5 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -59,6 +59,110 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Create return r0, r1 } +// FindTxesByMetaFieldAndStates provides a mock function with given fields: ctx, metaField, metaValue, states, chainID +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, metaField, metaValue, states, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, metaField, metaValue, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, metaField, metaValue, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) error); ok { + r1 = rf(ctx, metaField, metaValue, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, ids, states, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, ids, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, ids, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) error); ok { + r1 = rf(ctx, ids, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithMetaFieldByReceiptBlockNum provides a mock function with given fields: ctx, metaField, blockNum, chainID +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, metaField, blockNum, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, metaField, blockNum, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, metaField, blockNum, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, int64, *big.Int) error); ok { + r1 = rf(ctx, metaField, blockNum, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithMetaFieldByStates provides a mock function with given fields: ctx, metaField, states, chainID +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, metaField, states, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, metaField, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, metaField, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) error); ok { + r1 = rf(ctx, metaField, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetForwarderForEOA provides a mock function with given fields: eoa func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetForwarderForEOA(eoa ADDR) (ADDR, error) { ret := _m.Called(eoa) diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index d80f534ad2..5b7afd3224 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -47,6 +47,14 @@ type TxManager[ RegisterResumeCallback(fn ResumeCallback) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) Reset(addr ADDR, abandon bool) error + // Find transactions by a field in the TxMeta blob and transaction states + FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + // Find transactions with a non-null TxMeta field that was provided by transaction states + FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + // Find transactions with a non-null TxMeta field that was provided and a receipt block number greater than or equal to the one provided + FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + // Find transactions loaded with transaction attempts and receipts by transaction IDs and states + FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) } type reset struct { @@ -530,6 +538,26 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNative return etx, nil } +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + txes, err = b.txStore.FindTxesByMetaFieldAndStates(ctx, metaField, metaValue, states, chainID) + return +} + +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + txes, err = b.txStore.FindTxesWithMetaFieldByStates(ctx, metaField, states, chainID) + return +} + +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + txes, err = b.txStore.FindTxesWithMetaFieldByReceiptBlockNum(ctx, metaField, blockNum, chainID) + return +} + +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + txes, err = b.txStore.FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx, ids, states, chainID) + return +} + type NullTxManager[ CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], @@ -584,3 +612,15 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Hea } func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) RegisterResumeCallback(fn ResumeCallback) { } +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + return txes, errors.New(n.ErrMsg) +} +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + return txes, errors.New(n.ErrMsg) +} +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + return txes, errors.New(n.ErrMsg) +} +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { + return txes, errors.New(n.ErrMsg) +} diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index 02388e40f4..7da51de606 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -4,6 +4,7 @@ package mocks import ( context "context" + big "math/big" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" mock "github.com/stretchr/testify/mock" @@ -361,6 +362,110 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithS return r0, r1 } +// FindTxesByMetaFieldAndStates provides a mock function with given fields: ctx, metaField, metaValue, states, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, metaField, metaValue, states, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, metaField, metaValue, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, metaField, metaValue, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) error); ok { + r1 = rf(ctx, metaField, metaValue, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, ids, states, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, ids, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, ids, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) error); ok { + r1 = rf(ctx, ids, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithMetaFieldByReceiptBlockNum provides a mock function with given fields: ctx, metaField, blockNum, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, metaField, blockNum, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, metaField, blockNum, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, metaField, blockNum, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, int64, *big.Int) error); ok { + r1 = rf(ctx, metaField, blockNum, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithMetaFieldByStates provides a mock function with given fields: ctx, metaField, states, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, metaField, states, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, metaField, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, metaField, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) error); ok { + r1 = rf(ctx, metaField, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindTxsRequiringGasBump provides a mock function with given fields: ctx, address, blockNum, gasBumpThreshold, depth, chainID func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringGasBump(ctx context.Context, address ADDR, blockNum int64, gasBumpThreshold int64, depth int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, address, blockNum, gasBumpThreshold, depth, chainID) diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index 059a87d7ab..83cb4b85ee 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -43,6 +43,14 @@ type TxStore[ CheckTxQueueCapacity(ctx context.Context, fromAddress ADDR, maxQueuedTransactions uint64, chainID CHAIN_ID) (err error) Close() Abandon(ctx context.Context, id CHAIN_ID, addr ADDR) error + // Find transactions by a field in the TxMeta blob and transaction states + FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []TxState, chainID *big.Int) (tx []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + // Find transactions with a non-null TxMeta field that was provided by transaction states + FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []TxState, chainID *big.Int) (tx []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + // Find transactions with a non-null TxMeta field that was provided and a receipt block number greater than or equal to the one provided + FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (tx []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + // Find transactions loaded with transaction attempts and receipts by transaction IDs and states + FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []TxState, chainID *big.Int) (tx []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) } // TransactionStore contains the persistence layer methods needed to manage Txs and TxAttempts diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index abab204662..cde536bc7b 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -318,7 +318,8 @@ func (c *SimulatedBackendClient) BlockByHash(ctx context.Context, hash common.Ha } func (c *SimulatedBackendClient) LatestBlockHeight(ctx context.Context) (*big.Int, error) { - panic("not implemented") + header, err := c.b.HeaderByNumber(ctx, nil) + return header.Number, err } // ChainID returns the ethereum ChainID. diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 86a06b6025..971103bdfd 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -184,6 +184,7 @@ type DbEthTx struct { func (db *DbEthTx) FromTx(tx *Tx) { db.ID = tx.ID + db.IdempotencyKey = tx.IdempotencyKey db.FromAddress = tx.FromAddress db.ToAddress = tx.ToAddress db.EncodedPayload = tx.EncodedPayload @@ -511,8 +512,8 @@ func (o *evmTxStore) InsertTx(etx *Tx) error { if etx.CreatedAt == (time.Time{}) { etx.CreatedAt = time.Now() } - const insertEthTxSQL = `INSERT INTO evm.txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, error, broadcast_at, initial_broadcast_at, created_at, state, meta, subject, pipeline_task_run_id, min_confirmations, evm_chain_id, transmit_checker) VALUES ( -:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit, :error, :broadcast_at, :initial_broadcast_at, :created_at, :state, :meta, :subject, :pipeline_task_run_id, :min_confirmations, :evm_chain_id, :transmit_checker + const insertEthTxSQL = `INSERT INTO evm.txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, error, broadcast_at, initial_broadcast_at, created_at, state, meta, subject, pipeline_task_run_id, min_confirmations, evm_chain_id, transmit_checker, idempotency_key) VALUES ( +:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit, :error, :broadcast_at, :initial_broadcast_at, :created_at, :state, :meta, :subject, :pipeline_task_run_id, :min_confirmations, :evm_chain_id, :transmit_checker, :idempotency_key ) RETURNING *` var dbTx DbEthTx dbTx.FromTx(etx) @@ -548,14 +549,14 @@ func (o *evmTxStore) FindTxWithAttempts(etxID int64) (etx Tx, err error) { err = o.q.Transaction(func(tx pg.Queryer) error { var dbEtx DbEthTx if err = tx.Get(&dbEtx, `SELECT * FROM evm.txes WHERE id = $1 ORDER BY created_at ASC, id ASC`, etxID); err != nil { - return pkgerrors.Wrapf(err, "failed to find eth_tx with id %d", etxID) + return pkgerrors.Wrapf(err, "failed to find evm.tx with id %d", etxID) } dbEtx.ToTx(&etx) if err = o.loadTxAttemptsAtomic(&etx, pg.WithQueryer(tx)); err != nil { - return pkgerrors.Wrapf(err, "failed to load evm.tx_attempts for eth_tx with id %d", etxID) + return pkgerrors.Wrapf(err, "failed to load evm.tx_attempts for evm.tx with id %d", etxID) } if err = loadEthTxAttemptsReceipts(tx, &etx); err != nil { - return pkgerrors.Wrapf(err, "failed to load evm.receipts for eth_tx with id %d", etxID) + return pkgerrors.Wrapf(err, "failed to load evm.receipts for evm.tx with id %d", etxID) } return nil }, pg.OptReadOnlyTx()) @@ -637,6 +638,8 @@ func loadEthTxesAttemptsReceipts(q pg.Queryer, etxs []*Tx) (err error) { for _, receipt := range receipts { attempt := attemptHashM[receipt.TxHash] + // Although the attempts struct supports multiple receipts, the expectation for EVM is that there is only one receipt + // per tx and therefore attempt too. attempt.Receipts = append(attempt.Receipts, receipt) } return nil @@ -1776,6 +1779,72 @@ func (o *evmTxStore) Abandon(ctx context.Context, chainID *big.Int, addr common. return err } +// Find transactions by a field in the TxMeta blob and transaction states +func (o *evmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*Tx, error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + var dbEtxs []DbEthTx + sql := fmt.Sprintf("SELECT * FROM evm.txes WHERE evm_chain_id = $1 AND meta->>'%s' = $2 AND state = ANY($3)", metaField) + err := qq.Select(&dbEtxs, sql, chainID.String(), metaValue, pq.Array(states)) + txes := make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + return txes, pkgerrors.Wrap(err, "failed to FindTxesByMetaFieldAndStates") +} + +// Find transactions with a non-null TxMeta field that was provided by transaction states +func (o *evmTxStore) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + var dbEtxs []DbEthTx + sql := fmt.Sprintf("SELECT * FROM evm.txes WHERE meta->'%s' IS NOT NULL AND state = ANY($1) AND evm_chain_id = $2", metaField) + err = qq.Select(&dbEtxs, sql, pq.Array(states), chainID.String()) + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + return txes, pkgerrors.Wrap(err, "failed to FindTxesWithMetaFieldByStates") +} + +// Find transactions with a non-null TxMeta field that was provided and a receipt block number greater than or equal to the one provided +func (o *evmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (txes []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + var dbEtxs []DbEthTx + sql := fmt.Sprintf("SELECT et.* FROM evm.txes et JOIN evm.tx_attempts eta on et.id = eta.eth_tx_id JOIN evm.receipts er on eta.hash = er.tx_hash WHERE et.meta->'%s' IS NOT NULL AND er.block_number >= $1 AND et.evm_chain_id = $2", metaField) + err = qq.Select(&dbEtxs, sql, blockNum, chainID.String()) + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + return txes, pkgerrors.Wrap(err, "failed to FindTxesWithMetaFieldByReceiptBlockNum") +} + +// Find transactions loaded with transaction attempts and receipts by transaction IDs and states +func (o *evmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Transaction(func(tx pg.Queryer) error { + var dbEtxs []DbEthTx + if err = tx.Select(&dbEtxs, `SELECT * FROM evm.txes WHERE id = ANY($1) AND state = ANY($2) AND evm_chain_id = $3`, pq.Array(ids), pq.Array(states), chainID.String()); err != nil { + return pkgerrors.Wrapf(err, "failed to find evm.txes") + } + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + if err = o.LoadTxesAttempts(txes, pg.WithQueryer(tx)); err != nil { + return pkgerrors.Wrapf(err, "failed to load evm.tx_attempts for evm.tx") + } + if err = loadEthTxesAttemptsReceipts(tx, txes); err != nil { + return pkgerrors.Wrapf(err, "failed to load evm.receipts for evm.tx") + } + return nil + }) + return txes, pkgerrors.Wrap(err, "FindTxesWithAttemptsAndReceiptsByIdsAndState failed") +} + // Returns a context that contains the values of the provided context, // and which is canceled when either the provided contextg or TxStore parent context is canceled. func (o *evmTxStore) mergeContexts(ctx context.Context) (context.Context, context.CancelFunc) { diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 69a0d257f7..4632a8ae34 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -467,6 +467,110 @@ func (_m *EvmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common return r0, r1 } +// FindTxesByMetaFieldAndStates provides a mock function with given fields: ctx, metaField, metaValue, states, chainID +func (_m *EvmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, metaField, metaValue, states, chainID) + + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, metaField, metaValue, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, []types.TxState, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, metaField, metaValue, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, []types.TxState, *big.Int) error); ok { + r1 = rf(ctx, metaField, metaValue, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID +func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, ids, states, chainID) + + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, ids, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []types.TxState, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, ids, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []big.Int, []types.TxState, *big.Int) error); ok { + r1 = rf(ctx, ids, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithMetaFieldByReceiptBlockNum provides a mock function with given fields: ctx, metaField, blockNum, chainID +func (_m *EvmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, metaField, blockNum, chainID) + + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, metaField, blockNum, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, metaField, blockNum, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, int64, *big.Int) error); ok { + r1 = rf(ctx, metaField, blockNum, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindTxesWithMetaFieldByStates provides a mock function with given fields: ctx, metaField, states, chainID +func (_m *EvmTxStore) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, metaField, states, chainID) + + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, metaField, states, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, []types.TxState, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, metaField, states, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, []types.TxState, *big.Int) error); ok { + r1 = rf(ctx, metaField, states, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindTxsRequiringGasBump provides a mock function with given fields: ctx, address, blockNum, gasBumpThreshold, depth, chainID func (_m *EvmTxStore) FindTxsRequiringGasBump(ctx context.Context, address common.Address, blockNum int64, gasBumpThreshold int64, depth int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, address, blockNum, gasBumpThreshold, depth, chainID) diff --git a/core/chains/evm/txmgr/test_helpers.go b/core/chains/evm/txmgr/test_helpers.go new file mode 100644 index 0000000000..f9c0423a62 --- /dev/null +++ b/core/chains/evm/txmgr/test_helpers.go @@ -0,0 +1,151 @@ +package txmgr + +import ( + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + + evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" +) + +func ptr[T any](t T) *T { return &t } + +type TestDatabaseConfig struct { + config.Database + defaultQueryTimeout time.Duration +} + +func (d *TestDatabaseConfig) DefaultQueryTimeout() time.Duration { + return d.defaultQueryTimeout +} + +func (d *TestDatabaseConfig) LogSQL() bool { + return false +} + +type TestListenerConfig struct { + config.Listener +} + +func (l *TestListenerConfig) FallbackPollInterval() time.Duration { + return 1 * time.Minute +} + +func (d *TestDatabaseConfig) Listener() config.Listener { + return &TestListenerConfig{} +} + +type TestEvmConfig struct { + evmconfig.EVM + MaxInFlight uint32 + ReaperInterval time.Duration + ReaperThreshold time.Duration + ResendAfterThreshold time.Duration + BumpThreshold uint64 + MaxQueued uint64 +} + +func (e *TestEvmConfig) Transactions() evmconfig.Transactions { + return &transactionsConfig{e: e} +} + +func (e *TestEvmConfig) NonceAutoSync() bool { return true } + +func (e *TestEvmConfig) FinalityDepth() uint32 { return 42 } + +type TestGasEstimatorConfig struct { + bumpThreshold uint64 +} + +func (g *TestGasEstimatorConfig) BlockHistory() evmconfig.BlockHistory { + return &TestBlockHistoryConfig{} +} + +func (g *TestGasEstimatorConfig) EIP1559DynamicFees() bool { return false } +func (g *TestGasEstimatorConfig) LimitDefault() uint32 { return 42 } +func (g *TestGasEstimatorConfig) BumpPercent() uint16 { return 42 } +func (g *TestGasEstimatorConfig) BumpThreshold() uint64 { return g.bumpThreshold } +func (g *TestGasEstimatorConfig) BumpMin() *assets.Wei { return assets.NewWeiI(42) } +func (g *TestGasEstimatorConfig) FeeCapDefault() *assets.Wei { return assets.NewWeiI(42) } +func (g *TestGasEstimatorConfig) PriceDefault() *assets.Wei { return assets.NewWeiI(42) } +func (g *TestGasEstimatorConfig) TipCapDefault() *assets.Wei { return assets.NewWeiI(42) } +func (g *TestGasEstimatorConfig) TipCapMin() *assets.Wei { return assets.NewWeiI(42) } +func (g *TestGasEstimatorConfig) LimitMax() uint32 { return 0 } +func (g *TestGasEstimatorConfig) LimitMultiplier() float32 { return 0 } +func (g *TestGasEstimatorConfig) BumpTxDepth() uint32 { return 42 } +func (g *TestGasEstimatorConfig) LimitTransfer() uint32 { return 42 } +func (g *TestGasEstimatorConfig) PriceMax() *assets.Wei { return assets.NewWeiI(42) } +func (g *TestGasEstimatorConfig) PriceMin() *assets.Wei { return assets.NewWeiI(42) } +func (g *TestGasEstimatorConfig) Mode() string { return "FixedPrice" } +func (g *TestGasEstimatorConfig) LimitJobType() evmconfig.LimitJobType { + return &TestLimitJobTypeConfig{} +} +func (g *TestGasEstimatorConfig) PriceMaxKey(addr common.Address) *assets.Wei { + return assets.NewWeiI(42) +} + +func (e *TestEvmConfig) GasEstimator() evmconfig.GasEstimator { + return &TestGasEstimatorConfig{bumpThreshold: e.BumpThreshold} +} + +type TestLimitJobTypeConfig struct { +} + +func (l *TestLimitJobTypeConfig) OCR() *uint32 { return ptr(uint32(0)) } +func (l *TestLimitJobTypeConfig) OCR2() *uint32 { return ptr(uint32(0)) } +func (l *TestLimitJobTypeConfig) DR() *uint32 { return ptr(uint32(0)) } +func (l *TestLimitJobTypeConfig) FM() *uint32 { return ptr(uint32(0)) } +func (l *TestLimitJobTypeConfig) Keeper() *uint32 { return ptr(uint32(0)) } +func (l *TestLimitJobTypeConfig) VRF() *uint32 { return ptr(uint32(0)) } + +type TestBlockHistoryConfig struct { + evmconfig.BlockHistory +} + +func (b *TestBlockHistoryConfig) BatchSize() uint32 { return 42 } +func (b *TestBlockHistoryConfig) BlockDelay() uint16 { return 42 } +func (b *TestBlockHistoryConfig) BlockHistorySize() uint16 { return 42 } +func (b *TestBlockHistoryConfig) EIP1559FeeCapBufferBlocks() uint16 { return 42 } +func (b *TestBlockHistoryConfig) TransactionPercentile() uint16 { return 42 } + +type transactionsConfig struct { + evmconfig.Transactions + e *TestEvmConfig +} + +func (*transactionsConfig) ForwardersEnabled() bool { return true } +func (t *transactionsConfig) MaxInFlight() uint32 { return t.e.MaxInFlight } +func (t *transactionsConfig) MaxQueued() uint64 { return t.e.MaxQueued } +func (t *transactionsConfig) ReaperInterval() time.Duration { return t.e.ReaperInterval } +func (t *transactionsConfig) ReaperThreshold() time.Duration { return t.e.ReaperThreshold } +func (t *transactionsConfig) ResendAfterThreshold() time.Duration { return t.e.ResendAfterThreshold } + +type MockConfig struct { + EvmConfig *TestEvmConfig + RpcDefaultBatchSize uint32 + finalityDepth uint32 + finalityTagEnabled bool +} + +func (c *MockConfig) EVM() evmconfig.EVM { + return c.EvmConfig +} + +func (c *MockConfig) NonceAutoSync() bool { return true } +func (c *MockConfig) ChainType() config.ChainType { return "" } +func (c *MockConfig) FinalityDepth() uint32 { return c.finalityDepth } +func (c *MockConfig) SetFinalityDepth(fd uint32) { c.finalityDepth = fd } +func (c *MockConfig) FinalityTagEnabled() bool { return c.finalityTagEnabled } +func (c *MockConfig) RPCDefaultBatchSize() uint32 { return c.RpcDefaultBatchSize } + +func MakeTestConfigs(t *testing.T) (*MockConfig, *TestDatabaseConfig, *TestEvmConfig) { + db := &TestDatabaseConfig{defaultQueryTimeout: pg.DefaultQueryTimeout} + ec := &TestEvmConfig{BumpThreshold: 42, MaxInFlight: uint32(42), MaxQueued: uint64(0), ReaperInterval: time.Duration(0), ReaperThreshold: time.Duration(0)} + config := &MockConfig{EvmConfig: ec} + return config, db, ec +} diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index e9823ee021..4aa54bc52a 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" @@ -27,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -36,7 +34,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -76,7 +73,7 @@ func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) { to := utils.ZeroAddress value := assets.NewEth(1).ToInt() - config, dbConfig, evmConfig := makeConfigs(t) + config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) keyStore := cltest.NewKeyStore(t, db, dbConfig).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -102,7 +99,7 @@ func TestTxm_CreateTransaction(t *testing.T) { gasLimit := uint32(1000) payload := []byte{1, 2, 3} - config, dbConfig, evmConfig := makeConfigs(t) + config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -115,7 +112,7 @@ func TestTxm_CreateTransaction(t *testing.T) { strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{UUID: subject, Valid: true}) strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, @@ -151,7 +148,7 @@ func TestTxm_CreateTransaction(t *testing.T) { cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, fromAddress) t.Run("with queue at capacity does not insert eth_tx", func(t *testing.T) { - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) _, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: testutils.NewAddress(), @@ -165,7 +162,7 @@ func TestTxm_CreateTransaction(t *testing.T) { }) t.Run("doesn't insert eth_tx if a matching tx already exists for that pipeline_task_run_id", func(t *testing.T) { - evmConfig.maxQueued = uint64(3) + evmConfig.MaxQueued = uint64(3) id := uuid.New() tx1, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, @@ -221,7 +218,7 @@ func TestTxm_CreateTransaction(t *testing.T) { checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeSimulate, } - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, @@ -260,7 +257,7 @@ func TestTxm_CreateTransaction(t *testing.T) { SubID: &testDefaultSubID, GlobalSubID: &testDefaultGlobalSubID, } - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeVRFV2, VRFCoordinatorAddress: testutils.NewAddressPtr(), @@ -292,7 +289,7 @@ func TestTxm_CreateTransaction(t *testing.T) { t.Run("forwards tx when a proper forwarder is set up", func(t *testing.T) { pgtest.MustExec(t, db, `DELETE FROM evm.txes`) pgtest.MustExec(t, db, `DELETE FROM evm.forwarders`) - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) // Create mock forwarder, mock authorizedsenders call. form := forwarders.NewORM(db, logger.TestLogger(t), cfg.Database()) @@ -322,7 +319,7 @@ func TestTxm_CreateTransaction(t *testing.T) { }) t.Run("insert Tx successfully with a IdempotencyKey", func(t *testing.T) { - evmConfig.maxQueued = uint64(3) + evmConfig.MaxQueued = uint64(3) id := uuid.New() idempotencyKey := "1" _, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ @@ -338,7 +335,7 @@ func TestTxm_CreateTransaction(t *testing.T) { }) t.Run("doesn't insert eth_tx if a matching tx already exists for that IdempotencyKey", func(t *testing.T) { - evmConfig.maxQueued = uint64(3) + evmConfig.MaxQueued = uint64(3) id := uuid.New() idempotencyKey := "2" tx1, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ @@ -371,138 +368,6 @@ func newMockTxStrategy(t *testing.T) *commontxmmocks.TxStrategy { return commontxmmocks.NewTxStrategy(t) } -type databaseConfig struct { - config.Database - defaultQueryTimeout time.Duration -} - -func (d *databaseConfig) DefaultQueryTimeout() time.Duration { - return d.defaultQueryTimeout -} - -func (d *databaseConfig) LogSQL() bool { - return false -} - -type listenerConfig struct { - config.Listener -} - -func (l *listenerConfig) FallbackPollInterval() time.Duration { - return 1 * time.Minute -} - -func (d *databaseConfig) Listener() config.Listener { - return &listenerConfig{} -} - -type evmConfig struct { - evmconfig.EVM - maxInFlight uint32 - reaperInterval time.Duration - reaperThreshold time.Duration - resendAfterThreshold time.Duration - bumpThreshold uint64 - maxQueued uint64 -} - -func (e *evmConfig) Transactions() evmconfig.Transactions { - return &transactionsConfig{e: e} -} - -func (e *evmConfig) GasEstimator() evmconfig.GasEstimator { - return &gasEstimatorConfig{bumpThreshold: e.bumpThreshold} -} - -func (e *evmConfig) NonceAutoSync() bool { return true } - -func (e *evmConfig) FinalityDepth() uint32 { return 42 } - -type gasEstimatorConfig struct { - bumpThreshold uint64 -} - -func (g *gasEstimatorConfig) BlockHistory() evmconfig.BlockHistory { - return &blockHistoryConfig{} -} - -func (g *gasEstimatorConfig) EIP1559DynamicFees() bool { return false } -func (g *gasEstimatorConfig) LimitDefault() uint32 { return 42 } -func (g *gasEstimatorConfig) BumpPercent() uint16 { return 42 } -func (g *gasEstimatorConfig) BumpThreshold() uint64 { return g.bumpThreshold } -func (g *gasEstimatorConfig) BumpMin() *assets.Wei { return assets.NewWeiI(42) } -func (g *gasEstimatorConfig) FeeCapDefault() *assets.Wei { return assets.NewWeiI(42) } -func (g *gasEstimatorConfig) PriceDefault() *assets.Wei { return assets.NewWeiI(42) } -func (g *gasEstimatorConfig) TipCapDefault() *assets.Wei { return assets.NewWeiI(42) } -func (g *gasEstimatorConfig) TipCapMin() *assets.Wei { return assets.NewWeiI(42) } -func (g *gasEstimatorConfig) LimitMax() uint32 { return 0 } -func (g *gasEstimatorConfig) LimitMultiplier() float32 { return 0 } -func (g *gasEstimatorConfig) BumpTxDepth() uint32 { return 42 } -func (g *gasEstimatorConfig) LimitTransfer() uint32 { return 42 } -func (g *gasEstimatorConfig) PriceMax() *assets.Wei { return assets.NewWeiI(42) } -func (g *gasEstimatorConfig) PriceMin() *assets.Wei { return assets.NewWeiI(42) } -func (g *gasEstimatorConfig) Mode() string { return "FixedPrice" } -func (g *gasEstimatorConfig) LimitJobType() evmconfig.LimitJobType { return &limitJobTypeConfig{} } -func (g *gasEstimatorConfig) PriceMaxKey(addr common.Address) *assets.Wei { - return assets.NewWeiI(42) -} - -type limitJobTypeConfig struct { -} - -func (l *limitJobTypeConfig) OCR() *uint32 { return ptr(uint32(0)) } -func (l *limitJobTypeConfig) OCR2() *uint32 { return ptr(uint32(0)) } -func (l *limitJobTypeConfig) DR() *uint32 { return ptr(uint32(0)) } -func (l *limitJobTypeConfig) FM() *uint32 { return ptr(uint32(0)) } -func (l *limitJobTypeConfig) Keeper() *uint32 { return ptr(uint32(0)) } -func (l *limitJobTypeConfig) VRF() *uint32 { return ptr(uint32(0)) } - -type blockHistoryConfig struct { - evmconfig.BlockHistory -} - -func (b *blockHistoryConfig) BatchSize() uint32 { return 42 } -func (b *blockHistoryConfig) BlockDelay() uint16 { return 42 } -func (b *blockHistoryConfig) BlockHistorySize() uint16 { return 42 } -func (b *blockHistoryConfig) EIP1559FeeCapBufferBlocks() uint16 { return 42 } -func (b *blockHistoryConfig) TransactionPercentile() uint16 { return 42 } - -type transactionsConfig struct { - evmconfig.Transactions - e *evmConfig -} - -func (*transactionsConfig) ForwardersEnabled() bool { return true } -func (t *transactionsConfig) MaxInFlight() uint32 { return t.e.maxInFlight } -func (t *transactionsConfig) MaxQueued() uint64 { return t.e.maxQueued } -func (t *transactionsConfig) ReaperInterval() time.Duration { return t.e.reaperInterval } -func (t *transactionsConfig) ReaperThreshold() time.Duration { return t.e.reaperThreshold } -func (t *transactionsConfig) ResendAfterThreshold() time.Duration { return t.e.resendAfterThreshold } - -type mockConfig struct { - evmConfig *evmConfig - rpcDefaultBatchSize uint32 - finalityDepth uint32 - finalityTagEnabled bool -} - -func (c *mockConfig) EVM() evmconfig.EVM { - return c.evmConfig -} - -func (c *mockConfig) NonceAutoSync() bool { return true } -func (c *mockConfig) ChainType() config.ChainType { return "" } -func (c *mockConfig) FinalityDepth() uint32 { return c.finalityDepth } -func (c *mockConfig) FinalityTagEnabled() bool { return c.finalityTagEnabled } -func (c *mockConfig) RPCDefaultBatchSize() uint32 { return c.rpcDefaultBatchSize } - -func makeConfigs(t *testing.T) (*mockConfig, *databaseConfig, *evmConfig) { - db := &databaseConfig{defaultQueryTimeout: pg.DefaultQueryTimeout} - ec := &evmConfig{bumpThreshold: 42, maxInFlight: uint32(42), maxQueued: uint64(0), reaperInterval: time.Duration(0), reaperThreshold: time.Duration(0)} - config := &mockConfig{evmConfig: ec} - return config, db, ec -} - func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) @@ -517,7 +382,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { gasLimit := uint32(1000) toAddress := testutils.NewAddress() - config, dbConfig, evmConfig := makeConfigs(t) + config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) @@ -527,7 +392,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { t.Run("if another key has any transactions with insufficient eth errors, transmits as normal", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherKey.Address) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) @@ -550,7 +415,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { t.Run("if this key has any transactions with insufficient eth errors, inserts it anyway", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, thisKey.Address) strategy := newMockTxStrategy(t) @@ -578,7 +443,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { strategy.On("Subject").Return(uuid.NullUUID{}) strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) - evmConfig.maxQueued = uint64(1) + evmConfig.MaxQueued = uint64(1) etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: evmFromAddress, ToAddress: toAddress, @@ -598,13 +463,13 @@ func TestTxm_Lifecycle(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) kst := ksmocks.NewEth(t) - config, dbConfig, evmConfig := makeConfigs(t) - config.finalityDepth = uint32(42) - config.rpcDefaultBatchSize = uint32(4) + config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) + config.SetFinalityDepth(uint32(42)) + config.RpcDefaultBatchSize = uint32(4) - evmConfig.resendAfterThreshold = 1 * time.Hour - evmConfig.reaperThreshold = 1 * time.Hour - evmConfig.reaperInterval = 1 * time.Hour + evmConfig.ResendAfterThreshold = 1 * time.Hour + evmConfig.ReaperThreshold = 1 * time.Hour + evmConfig.ReaperInterval = 1 * time.Hour kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return([]gethcommon.Address{}, nil) @@ -619,7 +484,7 @@ func TestTxm_Lifecycle(t *testing.T) { // It should not hang or panic txm.OnNewLongestChain(testutils.Context(t), head) - evmConfig.bumpThreshold = uint64(1) + evmConfig.BumpThreshold = uint64(1) require.NoError(t, txm.Start(testutils.Context(t))) diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index f6b6a460b8..558d48752d 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -1,10 +1,7 @@ package vrf import ( - "encoding/hex" "fmt" - "math/big" - "strings" "time" "github.com/avast/retry-go/v4" @@ -87,7 +84,6 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if err != nil { return nil, err } - chainId := chain.Client().ConfiguredChainID() coordinator, err := solidity_vrf_coordinator_interface.NewVRFCoordinator(jb.VRFSpec.CoordinatorAddress.Address(), chain.Client()) if err != nil { return nil, err @@ -168,23 +164,19 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { chain.Config().EVM(), chain.Config().EVM().GasEstimator(), lV2Plus, - chain.Client(), + chain, chain.ID(), - chain.LogBroadcaster(), d.q, v2.NewCoordinatorV2_5(coordinatorV2Plus), batchCoordinatorV2, vrfOwner, aggregator, - chain.TxManager(), d.pr, d.ks.Eth(), jb, d.mailMon, utils.NewHighCapacityMailbox[log.Broadcast](), func() {}, - GetStartingResponseCountsV2(d.q, lV2Plus, chainId.Uint64(), chain.Config().EVM().FinalityDepth()), - chain.HeadBroadcaster(), vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())))}, nil } if _, ok := task.(*pipeline.VRFTaskV2); ok { @@ -223,49 +215,42 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { chain.Config().EVM(), chain.Config().EVM().GasEstimator(), lV2, - chain.Client(), + chain, chain.ID(), - chain.LogBroadcaster(), d.q, v2.NewCoordinatorV2(coordinatorV2), batchCoordinatorV2, vrfOwner, aggregator, - chain.TxManager(), d.pr, d.ks.Eth(), jb, d.mailMon, utils.NewHighCapacityMailbox[log.Broadcast](), func() {}, - GetStartingResponseCountsV2(d.q, lV2, chainId.Uint64(), chain.Config().EVM().FinalityDepth()), - chain.HeadBroadcaster(), vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())))}, nil } if _, ok := task.(*pipeline.VRFTask); ok { return []job.ServiceCtx{&v1.Listener{ - Cfg: chain.Config().EVM(), - FeeCfg: chain.Config().EVM().GasEstimator(), - L: logger.Sugared(lV1), - HeadBroadcaster: chain.HeadBroadcaster(), - LogBroadcaster: chain.LogBroadcaster(), - Q: d.q, - Txm: chain.TxManager(), - Coordinator: coordinator, - PipelineRunner: d.pr, - GethKs: d.ks.Eth(), - Job: jb, - MailMon: d.mailMon, + Cfg: chain.Config().EVM(), + FeeCfg: chain.Config().EVM().GasEstimator(), + L: logger.Sugared(lV1), + Q: d.q, + Coordinator: coordinator, + PipelineRunner: d.pr, + GethKs: d.ks.Eth(), + Job: jb, + MailMon: d.mailMon, // Note the mailbox size effectively sets a limit on how many logs we can replay // in the event of a VRF outage. ReqLogs: utils.NewHighCapacityMailbox[log.Broadcast](), ChStop: make(chan struct{}), WaitOnStop: make(chan struct{}), NewHead: make(chan struct{}, 1), - ResponseCount: GetStartingResponseCountsV1(d.q, lV1, chainId.Uint64(), chain.Config().EVM().FinalityDepth()), BlockNumberToReqID: pairing.New(), ReqAdded: func() {}, Deduper: vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())), + Chain: chain, }}, nil } } @@ -314,101 +299,3 @@ func FromAddressMaxGasPricesAllEqual(jb job.Job, keySpecificMaxGasPriceWei keySp } return } - -func GetStartingResponseCountsV1(q pg.Q, l logger.Logger, chainID uint64, evmFinalityDepth uint32) map[[32]byte]uint64 { - respCounts := map[[32]byte]uint64{} - - // Only check as far back as the evm finality depth for completed transactions. - counts, err := getRespCounts(q, chainID, evmFinalityDepth) - if err != nil { - // Continue with an empty map, do not block job on this. - l.Errorw("Unable to read previous confirmed fulfillments", "err", err) - return respCounts - } - - for _, c := range counts { - // Remove the quotes from the json - req := strings.Replace(c.RequestID, `"`, ``, 2) - // Remove the 0x prefix - b, err := hex.DecodeString(req[2:]) - if err != nil { - l.Errorw("Unable to read fulfillment", "err", err, "reqID", c.RequestID) - continue - } - var reqID [32]byte - copy(reqID[:], b) - respCounts[reqID] = uint64(c.Count) - } - - return respCounts -} - -func GetStartingResponseCountsV2( - q pg.Q, - l logger.Logger, - chainID uint64, - evmFinalityDepth uint32, -) map[string]uint64 { - respCounts := map[string]uint64{} - - // Only check as far back as the evm finality depth for completed transactions. - counts, err := getRespCounts(q, chainID, evmFinalityDepth) - if err != nil { - // Continue with an empty map, do not block job on this. - l.Errorw("Unable to read previous confirmed fulfillments", "err", err) - return respCounts - } - - for _, c := range counts { - // Remove the quotes from the json - req := strings.Replace(c.RequestID, `"`, ``, 2) - // Remove the 0x prefix - b, err := hex.DecodeString(req[2:]) - if err != nil { - l.Errorw("Unable to read fulfillment", "err", err, "reqID", c.RequestID) - continue - } - bi := new(big.Int).SetBytes(b) - respCounts[bi.String()] = uint64(c.Count) - } - return respCounts -} - -func getRespCounts(q pg.Q, chainID uint64, evmFinalityDepth uint32) ( - []struct { - RequestID string - Count int - }, - error, -) { - counts := []struct { - RequestID string - Count int - }{} - // This query should use the idx_evm.txes_state_from_address_evm_chain_id - // index, since the quantity of unconfirmed/unstarted/in_progress transactions _should_ be small - // relative to the rest of the data. - unconfirmedQuery := ` -SELECT meta->'RequestID' AS request_id, count(meta->'RequestID') AS count -FROM evm.txes et -WHERE et.meta->'RequestID' IS NOT NULL -AND et.state IN ('unconfirmed', 'unstarted', 'in_progress') -GROUP BY meta->'RequestID' - ` - // Fetch completed transactions only as far back as the given cutoffBlockNumber. This avoids - // a table scan of the evm.txes table, which could be large if it is unpruned. - confirmedQuery := ` -SELECT meta->'RequestID' AS request_id, count(meta->'RequestID') AS count -FROM evm.txes et JOIN evm.tx_attempts eta on et.id = eta.eth_tx_id - join evm.receipts er on eta.hash = er.tx_hash -WHERE et.meta->'RequestID' is not null -AND er.block_number >= (SELECT number FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC LIMIT 1) - $2 -GROUP BY meta->'RequestID' - ` - query := unconfirmedQuery + "\nUNION ALL\n" + confirmedQuery - err := q.Select(&counts, query, chainID, evmFinalityDepth) - if err != nil { - return nil, err - } - return counts, nil -} diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 91ae4400e3..927e2ae682 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -17,9 +17,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -58,7 +58,7 @@ type vrfUniverse struct { ks keystore.Master vrfkey vrfkey.KeyV2 submitter common.Address - txm *txmmocks.MockEvmTxManager + txm *txmgr.TxManager hb httypes.HeadBroadcaster legacyChains evm.LegacyChainContainer cid big.Int @@ -68,28 +68,33 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv // Mock all chain interactions lb := log_mocks.NewBroadcaster(t) lb.On("AddDependents", 1).Maybe() + lb.On("Register", mock.Anything, mock.Anything).Return(func() {}).Maybe() ec := evmclimocks.NewClient(t) ec.On("ConfiguredChainID").Return(testutils.FixtureChainID) + ec.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(51), nil).Maybe() lggr := logger.TestLogger(t) hb := headtracker.NewHeadBroadcaster(lggr) // Don't mock db interactions prm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, cfg.Database()) - txm := txmmocks.NewMockEvmTxManager(t) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) + _, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) + txm, err := txmgr.NewTxm(db, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), ec, logger.TestLogger(t), nil, ks.Eth(), nil) + orm := headtracker.NewORM(db, lggr, cfg.Database(), *testutils.FixtureChainID) + require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), cltest.Head(51))) jrm := job.NewORM(db, prm, btORM, ks, lggr, cfg.Database()) t.Cleanup(func() { assert.NoError(t, jrm.Close()) }) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{LogBroadcaster: lb, KeyStore: ks.Eth(), Client: ec, DB: db, GeneralConfig: cfg, TxManager: txm}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) pr := pipeline.NewRunner(prm, btORM, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ks.Eth(), ks.VRF(), lggr, nil, nil) require.NoError(t, ks.Unlock(testutils.Password)) - k, err := ks.Eth().Create(testutils.FixtureChainID) - require.NoError(t, err) + k, err2 := ks.Eth().Create(testutils.FixtureChainID) + require.NoError(t, err2) submitter := k.Address require.NoError(t, err) - vrfkey, err := ks.VRF().Create() - require.NoError(t, err) + vrfkey, err3 := ks.VRF().Create() + require.NoError(t, err3) return vrfUniverse{ jrm: jrm, @@ -100,7 +105,7 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv ks: ks, vrfkey: vrfkey, submitter: submitter, - txm: txm, + txm: &txm, hb: hb, legacyChains: legacyChains, cid: *ec.ConfiguredChainID(), @@ -172,6 +177,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { listener.RunHeadListener(func() {}) }() t.Cleanup(func() { listener.Stop(t) }) + require.NoError(t, listener.Start(testutils.Context(t))) return vuni, listener, jb } @@ -302,20 +308,6 @@ func TestDelegate_ValidLog(t *testing.T) { // Expect a call to check if the req is already fulfilled. vuni.ec.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(generateCallbackReturnValues(t, false), nil) - // Ensure we queue up a valid eth transaction - // Linked to requestID - vuni.txm.On("CreateTransaction", - mock.Anything, - mock.MatchedBy(func(txRequest txmgr.TxRequest) bool { - meta := txRequest.Meta - return txRequest.FromAddress == vuni.submitter && - txRequest.ToAddress == common.HexToAddress(jb.VRFSpec.CoordinatorAddress.String()) && - txRequest.FeeLimit == uint32(500000) && - meta.JobID != nil && meta.RequestID != nil && meta.RequestTxHash != nil && - (*meta.JobID > 0 && *meta.RequestID == tc.reqID && *meta.RequestTxHash == txHash) - }), - ).Once().Return(txmgr.Tx{}, nil) - listener.HandleLog(log.NewLogBroadcast(tc.log, vuni.cid, nil)) // Wait until the log is present waitForChannel(t, added, time.Second, "request not added to the queue") diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 92e697f229..b1f9bbb503 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -3,20 +3,22 @@ package v1 import ( "context" "encoding/hex" + "errors" "fmt" "math/big" + "strings" "sync" "time" + "github.com/avast/retry-go/v4" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" heaps "github.com/theodesp/go-heaps" "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-relay/pkg/services" - httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -46,24 +48,22 @@ type request struct { type Listener struct { services.StateMachine - Cfg vrfcommon.Config - FeeCfg vrfcommon.FeeConfig - L logger.SugaredLogger - LogBroadcaster log.Broadcaster - Coordinator *solidity_vrf_coordinator_interface.VRFCoordinator - PipelineRunner pipeline.Runner - Job job.Job - Q pg.Q - HeadBroadcaster httypes.HeadBroadcasterRegistry - Txm txmgr.TxManager - GethKs vrfcommon.GethKeyStore - MailMon *utils.MailboxMonitor - ReqLogs *utils.Mailbox[log.Broadcast] - ChStop utils.StopChan - WaitOnStop chan struct{} - NewHead chan struct{} - LatestHead uint64 - LatestHeadMu sync.RWMutex + Cfg vrfcommon.Config + FeeCfg vrfcommon.FeeConfig + L logger.SugaredLogger + Coordinator *solidity_vrf_coordinator_interface.VRFCoordinator + PipelineRunner pipeline.Runner + Job job.Job + Q pg.Q + GethKs vrfcommon.GethKeyStore + MailMon *utils.MailboxMonitor + ReqLogs *utils.Mailbox[log.Broadcast] + ChStop utils.StopChan + WaitOnStop chan struct{} + NewHead chan struct{} + LatestHead uint64 + LatestHeadMu sync.RWMutex + Chain evm.Chain // We can keep these pending logs in memory because we // only mark them confirmed once we send a corresponding fulfillment transaction. @@ -110,11 +110,11 @@ func (lsn *Listener) getLatestHead() uint64 { } // Start complies with job.Service -func (lsn *Listener) Start(context.Context) error { +func (lsn *Listener) Start(ctx context.Context) error { return lsn.StartOnce("VRFListener", func() error { spec := job.LoadDefaultVRFPollPeriod(*lsn.Job.VRFSpec) - unsubscribeLogs := lsn.LogBroadcaster.Register(lsn, log.ListenerOpts{ + unsubscribeLogs := lsn.Chain.LogBroadcaster().Register(lsn, log.ListenerOpts{ Contract: lsn.Coordinator.Address(), ParseLog: lsn.Coordinator.ParseLog, LogsWithTopics: map[common.Hash][][]log.Topic{ @@ -136,10 +136,19 @@ func (lsn *Listener) Start(context.Context) error { }) // Subscribe to the head broadcaster for handling // per request conf requirements. - latestHead, unsubscribeHeadBroadcaster := lsn.HeadBroadcaster.Subscribe(lsn) + latestHead, unsubscribeHeadBroadcaster := lsn.Chain.HeadBroadcaster().Subscribe(lsn) if latestHead != nil { lsn.setLatestHead(latestHead) } + + // Populate the response count map + lsn.RespCountMu.Lock() + defer lsn.RespCountMu.Unlock() + respCount, err := lsn.GetStartingResponseCountsV1(ctx) + if err != nil { + return err + } + lsn.ResponseCount = respCount go lsn.RunLogListener([]func(){unsubscribeLogs}, spec.MinIncomingConfirmations) go lsn.RunHeadListener(unsubscribeHeadBroadcaster) @@ -148,6 +157,48 @@ func (lsn *Listener) Start(context.Context) error { }) } +func (lsn *Listener) GetStartingResponseCountsV1(ctx context.Context) (respCount map[[32]byte]uint64, err error) { + respCounts := make(map[[32]byte]uint64) + var latestBlockNum *big.Int + // Retry client call for LatestBlockHeight if fails + // Want to avoid failing startup due to potential faulty RPC call + err = retry.Do(func() error { + latestBlockNum, err = lsn.Chain.Client().LatestBlockHeight(ctx) + return err + }, retry.Attempts(10), retry.Delay(500*time.Millisecond)) + if err != nil { + return nil, err + } + if latestBlockNum == nil { + return nil, errors.New("LatestBlockHeight return nil block num") + } + confirmedBlockNum := latestBlockNum.Int64() - int64(lsn.Chain.Config().EVM().FinalityDepth()) + // Only check as far back as the evm finality depth for completed transactions. + var counts []vrfcommon.RespCountEntry + counts, err = vrfcommon.GetRespCounts(ctx, lsn.Chain.TxManager(), lsn.Chain.Client().ConfiguredChainID(), confirmedBlockNum) + if err != nil { + // Continue with an empty map, do not block job on this. + lsn.L.Errorw("Unable to read previous confirmed fulfillments", "err", err) + return respCounts, nil + } + + for _, c := range counts { + // Remove the quotes from the json + req := strings.Replace(c.RequestID, `"`, ``, 2) + // Remove the 0x prefix + b, err := hex.DecodeString(req[2:]) + if err != nil { + lsn.L.Errorw("Unable to read fulfillment", "err", err, "reqID", c.RequestID) + continue + } + var reqID [32]byte + copy(reqID[:], b) + respCounts[reqID] = uint64(c.Count) + } + + return respCounts, nil +} + // Removes and returns all the confirmed logs from // the pending queue. func (lsn *Listener) extractConfirmedLogs() []request { @@ -314,7 +365,7 @@ func (lsn *Listener) handleLog(lb log.Broadcast, minConfs uint32) { } func (lsn *Listener) shouldProcessLog(lb log.Broadcast) bool { - consumed, err := lsn.LogBroadcaster.WasAlreadyConsumed(lb) + consumed, err := lsn.Chain.LogBroadcaster().WasAlreadyConsumed(lb) if err != nil { lsn.L.Errorw("Could not determine if log was already consumed", "error", err, "txHash", lb.RawLog().TxHash) // Do not process, let lb resend it as a retry mechanism. @@ -324,7 +375,7 @@ func (lsn *Listener) shouldProcessLog(lb log.Broadcast) bool { } func (lsn *Listener) markLogAsConsumed(lb log.Broadcast) { - err := lsn.LogBroadcaster.MarkConsumed(lb) + err := lsn.Chain.LogBroadcaster().MarkConsumed(lb) lsn.L.ErrorIf(err, fmt.Sprintf("Unable to mark log %v as consumed", lb.String())) } @@ -432,7 +483,7 @@ func (lsn *Listener) ProcessRequest(ctx context.Context, req request) bool { // The VRF pipeline has no async tasks, so we don't need to check for `incomplete` if _, err = lsn.PipelineRunner.Run(ctx, run, lggr, true, func(tx pg.Queryer) error { // Always mark consumed regardless of whether the proof failed or not. - if err = lsn.LogBroadcaster.MarkConsumed(req.lb, pg.WithQueryer(tx)); err != nil { + if err = lsn.Chain.LogBroadcaster().MarkConsumed(req.lb, pg.WithQueryer(tx)); err != nil { lggr.Errorw("Failed mark consumed", "err", err) } return nil diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index 09c9a0ed43..60a7cd18d2 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -113,7 +113,7 @@ func testSingleConsumerHappyPath( }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, requestID1, subID, uni.backend, db, vrfVersion) + mine(t, requestID1, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. // In particular: @@ -133,7 +133,7 @@ func testSingleConsumerHappyPath( t.Log("runs", len(runs)) return len(runs) == 2 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) - mine(t, requestID2, subID, uni.backend, db, vrfVersion) + mine(t, requestID2, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. // In particular: @@ -285,7 +285,7 @@ func testMultipleConsumersNeedBHS( return len(runs) == 1 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) - mine(t, requestID, subID, uni.backend, db, vrfVersion) + mine(t, requestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) rwfe := assertRandomWordsFulfilled(t, requestID, true, coordinator, nativePayment) if len(assertions) > 0 { @@ -446,7 +446,7 @@ func testMultipleConsumersNeedTrustedBHS( return len(runs) == 1 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) - mine(t, requestID, subID, uni.backend, db, vrfVersion) + mine(t, requestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) rwfe := assertRandomWordsFulfilled(t, requestID, true, coordinator, nativePayment) if len(assertions) > 0 { @@ -592,7 +592,7 @@ func testSingleConsumerHappyPathBatchFulfillment( return len(runs) == numRequests }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) - mineBatch(t, reqIDs, subID, uni.backend, db, vrfVersion) + mineBatch(t, reqIDs, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) for i, requestID := range reqIDs { // Assert correct state of RandomWordsFulfilled event. @@ -694,7 +694,7 @@ func testSingleConsumerNeedsTopUp( // Mine the fulfillment. Need to wait for Txm to mark the tx as confirmed // so that we can actually see the event on the simulated chain. - mine(t, requestID, subID, uni.backend, db, vrfVersion) + mine(t, requestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert the state of the RandomWordsFulfilled event. rwfe := assertRandomWordsFulfilled(t, requestID, true, coordinator, nativePayment) @@ -818,7 +818,7 @@ func testBlockHeaderFeeder( return len(runs) == 1 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) - mine(t, requestID, subID, uni.backend, db, vrfVersion) + mine(t, requestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) rwfe := assertRandomWordsFulfilled(t, requestID, true, coordinator, nativePayment) if len(assertions) > 0 { @@ -1021,7 +1021,7 @@ func testSingleConsumerForcedFulfillment( }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, requestID, subID, uni.backend, db, vrfVersion) + mine(t, requestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. // In this particular case: @@ -1264,7 +1264,7 @@ func testSingleConsumerBigGasCallbackSandwich( }, 3*time.Second, 1*time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, reqIDs[1], subID, uni.backend, db, vrfVersion) + mine(t, reqIDs[1], subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert the random word was fulfilled assertRandomWordsFulfilled(t, reqIDs[1], false, uni.rootContract, nativePayment) @@ -1365,7 +1365,7 @@ func testSingleConsumerMultipleGasLanes( }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, cheapRequestID, subID, uni.backend, db, vrfVersion) + mine(t, cheapRequestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. assertRandomWordsFulfilled(t, cheapRequestID, true, uni.rootContract, nativePayment) @@ -1397,7 +1397,7 @@ func testSingleConsumerMultipleGasLanes( }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, expensiveRequestID, subID, uni.backend, db, vrfVersion) + mine(t, expensiveRequestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. assertRandomWordsFulfilled(t, expensiveRequestID, true, uni.rootContract, nativePayment) @@ -1477,7 +1477,7 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, requestID, subID, uni.backend, db, vrfVersion) + mine(t, requestID, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. assertRandomWordsFulfilled(t, requestID, false, uni.rootContract, nativePayment) @@ -1552,7 +1552,7 @@ func testConsumerProxyHappyPath( }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, requestID1, subID, uni.backend, db, vrfVersion) + mine(t, requestID1, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. assertRandomWordsFulfilled(t, requestID1, true, uni.rootContract, nativePayment) @@ -1576,7 +1576,7 @@ func testConsumerProxyHappyPath( t.Log("runs", len(runs)) return len(runs) == 2 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) - mine(t, requestID2, subID, uni.backend, db, vrfVersion) + mine(t, requestID2, subID, uni.backend, db, vrfVersion, testutils.SimulatedChainID) assertRandomWordsFulfilled(t, requestID2, true, uni.rootContract, nativePayment) // Assert correct number of random words sent by coordinator. diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 6d2b77acb7..094d7d060e 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -1200,7 +1200,7 @@ func TestVRFV2PlusIntegration_Migration(t *testing.T) { return len(runs) == 1 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) - mine(t, requestID, subID, uni.backend, db, vrfcommon.V2Plus) + mine(t, requestID, subID, uni.backend, db, vrfcommon.V2Plus, testutils.SimulatedChainID) assertRandomWordsFulfilled(t, requestID, true, uni.rootContract, false) // Assert correct number of random words sent by coordinator. diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 093adc8eaa..3a691ec2e2 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -24,6 +24,7 @@ import ( "github.com/onsi/gomega" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" @@ -32,6 +33,8 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmlogger "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -58,6 +61,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -67,9 +72,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/services/vrf" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" + v1 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v1" v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" @@ -127,24 +133,14 @@ type coordinatorV2Universe struct { batchCoordinatorContractAddress common.Address } -const ( - ConfirmedEthTxesV2Query = `SELECT * FROM evm.txes - WHERE evm.txes.state = 'confirmed' - AND evm.txes.meta->>'RequestID' = $1 - AND CAST(evm.txes.meta->>'SubId' AS NUMERIC) = $2 LIMIT 1` - ConfirmedEthTxesV2PlusQuery = `SELECT * FROM evm.txes - WHERE evm.txes.state = 'confirmed' - AND evm.txes.meta->>'RequestID' = $1 - AND CAST(evm.txes.meta->>'GlobalSubId' AS NUMERIC) = $2 LIMIT 1` - ConfirmedEthTxesV2BatchQuery = ` - SELECT * FROM evm.txes - WHERE evm.txes.state = 'confirmed' - AND CAST(evm.txes.meta->>'SubId' AS NUMERIC) = $1` - ConfirmedEthTxesV2PlusBatchQuery = ` - SELECT * FROM evm.txes - WHERE evm.txes.state = 'confirmed' - AND CAST(evm.txes.meta->>'GlobalSubId' AS NUMERIC) = $1` -) +func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.Master, ec *evmclimocks.Client) txmgrcommon.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] { + _, _, evmConfig := txmgr.MakeTestConfigs(t) + txmConfig := txmgr.NewEvmTxmConfig(evmConfig) + txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, + nil, txStore, nil, nil, nil, nil) + + return txm +} func newVRFCoordinatorV2Universe(t *testing.T, key ethkey.KeyV2, numConsumers int) coordinatorV2Universe { testutils.SkipShort(t, "VRFCoordinatorV2Universe") @@ -454,7 +450,7 @@ func sendEth(t *testing.T, key ethkey.KeyV2, ec *backends.SimulatedBackend, to c nonce, err := ec.PendingNonceAt(testutils.Context(t), key.Address) require.NoError(t, err) tx := gethtypes.NewTx(&gethtypes.DynamicFeeTx{ - ChainID: big.NewInt(1337), + ChainID: testutils.SimulatedChainID, Nonce: nonce, GasTipCap: big.NewInt(1), GasFeeCap: assets.GWei(10).ToInt(), // block base fee in sim @@ -463,7 +459,7 @@ func sendEth(t *testing.T, key ethkey.KeyV2, ec *backends.SimulatedBackend, to c Value: big.NewInt(0).Mul(big.NewInt(int64(eth)), big.NewInt(1e18)), Data: nil, }) - signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(big.NewInt(1337)), key.ToEcdsaPrivKey()) + signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(testutils.SimulatedChainID), key.ToEcdsaPrivKey()) require.NoError(t, err) err = ec.SendTransaction(testutils.Context(t), signedTx) require.NoError(t, err) @@ -762,32 +758,42 @@ func assertNumRandomWords( } } -func mine(t *testing.T, requestID, subID *big.Int, backend *backends.SimulatedBackend, db *sqlx.DB, vrfVersion vrfcommon.Version) bool { - var query string +func mine(t *testing.T, requestID, subID *big.Int, backend *backends.SimulatedBackend, db *sqlx.DB, vrfVersion vrfcommon.Version, chainId *big.Int) bool { + cfg := pgtest.NewQConfig(false) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + var metaField string if vrfVersion == vrfcommon.V2Plus { - query = ConfirmedEthTxesV2PlusQuery + metaField = "GlobalSubId" } else if vrfVersion == vrfcommon.V2 { - query = ConfirmedEthTxesV2Query + metaField = "SubId" } else { t.Errorf("unsupported vrf version %s", vrfVersion) } + return gomega.NewWithT(t).Eventually(func() bool { backend.Commit() - var txs []txmgr.DbEthTx - err := db.Select(&txs, query, common.BytesToHash(requestID.Bytes()).String(), subID.String()) + txes, err := txstore.FindTxesByMetaFieldAndStates(testutils.Context(t), metaField, subID.String(), []txmgrtypes.TxState{txmgrcommon.TxConfirmed}, chainId) require.NoError(t, err) - t.Log("num txs", len(txs)) - return len(txs) == 1 + for _, tx := range txes { + meta, err := tx.GetMeta() + require.NoError(t, err) + if meta.RequestID.String() == common.BytesToHash(requestID.Bytes()).String() { + return true + } + } + return false }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) } -func mineBatch(t *testing.T, requestIDs []*big.Int, subID *big.Int, backend *backends.SimulatedBackend, db *sqlx.DB, vrfVersion vrfcommon.Version) bool { +func mineBatch(t *testing.T, requestIDs []*big.Int, subID *big.Int, backend *backends.SimulatedBackend, db *sqlx.DB, vrfVersion vrfcommon.Version, chainId *big.Int) bool { requestIDMap := map[string]bool{} - var query string + cfg := pgtest.NewQConfig(false) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + var metaField string if vrfVersion == vrfcommon.V2Plus { - query = ConfirmedEthTxesV2PlusBatchQuery + metaField = "GlobalSubId" } else if vrfVersion == vrfcommon.V2 { - query = ConfirmedEthTxesV2BatchQuery + metaField = "SubId" } else { t.Errorf("unsupported vrf version %s", vrfVersion) } @@ -796,12 +802,10 @@ func mineBatch(t *testing.T, requestIDs []*big.Int, subID *big.Int, backend *bac } return gomega.NewWithT(t).Eventually(func() bool { backend.Commit() - var txs []txmgr.DbEthTx - require.NoError(t, db.Select(&txs, query, subID.String())) - for _, tx := range txs { - var evmTx txmgr.Tx - tx.ToTx(&evmTx) - meta, err := evmTx.GetMeta() + txes, err := txstore.FindTxesByMetaFieldAndStates(testutils.Context(t), metaField, subID.String(), []txmgrtypes.TxState{txmgrcommon.TxConfirmed}, chainId) + require.NoError(t, err) + for _, tx := range txes { + meta, err := tx.GetMeta() require.NoError(t, err) for _, requestID := range meta.RequestIDs { if _, ok := requestIDMap[requestID.String()]; ok { @@ -1188,7 +1192,7 @@ func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, requestID, new(big.Int).SetUint64(wrapperSubID), uni.backend, db, vrfcommon.V2) + mine(t, requestID, new(big.Int).SetUint64(wrapperSubID), uni.backend, db, vrfcommon.V2, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. assertRandomWordsFulfilled(t, requestID, true, uni.rootContract, false) @@ -1268,7 +1272,7 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) // Mine the fulfillment that was queued. - mine(t, requestID, new(big.Int).SetUint64(wrapperSubID), uni.backend, db, vrfcommon.V2) + mine(t, requestID, new(big.Int).SetUint64(wrapperSubID), uni.backend, db, vrfcommon.V2, testutils.SimulatedChainID) // Assert correct state of RandomWordsFulfilled event. assertRandomWordsFulfilled(t, requestID, true, uni.rootContract, false) @@ -1599,6 +1603,10 @@ func TestIntegrationVRFV2(t *testing.T) { require.Zero(t, key.Cmp(keys[0])) require.NoError(t, app.Start(testutils.Context(t))) + var chain evm.Chain + chain, err = app.GetRelayers().LegacyEVMChains().Get(testutils.SimulatedChainID.String()) + require.NoError(t, err) + listenerV2 := v22.MakeTestListenerV2(chain) jbs := createVRFJobs( t, @@ -1751,11 +1759,10 @@ func TestIntegrationVRFV2(t *testing.T) { }) // We should see the response count present - chain, err := app.GetRelayers().LegacyEVMChains().Get(big.NewInt(1337).String()) require.NoError(t, err) - - q := pg.NewQ(app.GetSqlxDB(), app.Logger, app.Config.Database()) - counts := vrf.GetStartingResponseCountsV2(q, app.Logger, chain.Client().ConfiguredChainID().Uint64(), chain.Config().EVM().FinalityDepth()) + var counts map[string]uint64 + counts, err = listenerV2.GetStartingResponseCountsV2(testutils.Context(t)) + require.NoError(t, err) t.Log(counts, rf[0].RequestID().String()) assert.Equal(t, uint64(1), counts[rf[0].RequestID().String()]) } @@ -1997,19 +2004,30 @@ func TestFulfillmentCost(t *testing.T) { func TestStartingCountsV1(t *testing.T) { cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "vrf_test_starting_counts", nil) - _, err := db.Exec(`INSERT INTO evm.heads (hash, number, parent_hash, created_at, timestamp, evm_chain_id) - VALUES ($1, 4, $2, NOW(), NOW(), 1337)`, utils.NewHash(), utils.NewHash()) - require.NoError(t, err) lggr := logger.TestLogger(t) - q := pg.NewQ(db, lggr, cfg.Database()) - finalityDepth := 3 - counts := vrf.GetStartingResponseCountsV1(q, lggr, 1337, uint32(finalityDepth)) - assert.Equal(t, 0, len(counts)) + qCfg := pgtest.NewQConfig(false) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t), qCfg) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) + ec := evmclimocks.NewClient(t) + ec.On("ConfiguredChainID").Return(testutils.SimulatedChainID) + ec.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(2), nil).Maybe() + txm := makeTestTxm(t, txStore, ks, ec) + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{KeyStore: ks.Eth(), Client: ec, DB: db, GeneralConfig: cfg, TxManager: txm}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) + chain, err := legacyChains.Get(testutils.SimulatedChainID.String()) + require.NoError(t, err) + listenerV1 := &v1.Listener{ + Chain: chain, + } + listenerV2 := v22.MakeTestListenerV2(chain) + var counts map[[32]byte]uint64 + counts, err = listenerV1.GetStartingResponseCountsV1(testutils.Context(t)) + require.NoError(t, err) + assert.Equal(t, 0, len(counts)) err = ks.Unlock(testutils.Password) require.NoError(t, err) - k, err := ks.Eth().Create(big.NewInt(1337)) + k, err := ks.Eth().Create(testutils.SimulatedChainID) require.NoError(t, err) b := time.Now() n1, n2, n3, n4 := evmtypes.Nonce(0), evmtypes.Nonce(1), evmtypes.Nonce(2), evmtypes.Nonce(3) @@ -2027,7 +2045,7 @@ func TestStartingCountsV1(t *testing.T) { md2, err := json.Marshal(&m2) md2_ := datatypes.JSON(md2) require.NoError(t, err) - chainID := utils.NewBig(big.NewInt(1337)) + chainID := utils.NewBig(testutils.SimulatedChainID) confirmedTxes := []txmgr.Tx{ { Sequence: &n1, @@ -2100,16 +2118,13 @@ func TestStartingCountsV1(t *testing.T) { ChainID: chainID.ToInt(), }) } - sql := `INSERT INTO evm.txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, state, created_at, broadcast_at, initial_broadcast_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) -VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit, :state, :created_at, :broadcast_at, :initial_broadcast_at, :meta, :subject, :evm_chain_id, :min_confirmations, :pipeline_task_run_id);` - for _, tx := range append(confirmedTxes, unconfirmedTxes...) { - var dbEtx txmgr.DbEthTx - dbEtx.FromTx(&tx) //nolint:gosec // just copying fields - _, err = db.NamedExec(sql, &dbEtx) + txList := append(confirmedTxes, unconfirmedTxes...) + for i := range txList { + err = txStore.InsertTx(&txList[i]) require.NoError(t, err) } - // add evm.tx_attempts for confirmed + // add tx attempt for confirmed broadcastBlock := int64(1) var txAttempts []txmgr.TxAttempt for i := range confirmedTxes { @@ -2124,7 +2139,7 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit ChainSpecificFeeLimit: uint32(100), }) } - // add evm.tx_attempts for unconfirmed + // add tx attempt for unconfirmed for i := range unconfirmedTxes { txAttempts = append(txAttempts, txmgr.TxAttempt{ TxID: int64(i + 1 + len(confirmedTxes)), @@ -2139,41 +2154,35 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit for _, txAttempt := range txAttempts { t.Log("tx attempt eth tx id: ", txAttempt.TxID) } - sql = `INSERT INTO evm.tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, state, created_at, chain_specific_gas_limit) - VALUES (:eth_tx_id, :gas_price, :signed_raw_tx, :hash, :state, :created_at, :chain_specific_gas_limit)` - for _, attempt := range txAttempts { - var dbAttempt txmgr.DbEthTxAttempt - dbAttempt.FromTxAttempt(&attempt) //nolint:gosec // just copying fields - _, err = db.NamedExec(sql, &dbAttempt) + for i := range txAttempts { + err = txStore.InsertTxAttempt(&txAttempts[i]) require.NoError(t, err) } // add evm.receipts - receipts := []txmgr.Receipt{} + receipts := []evmtypes.Receipt{} for i := 0; i < 4; i++ { - receipts = append(receipts, txmgr.Receipt{ + receipts = append(receipts, evmtypes.Receipt{ BlockHash: utils.NewHash(), TxHash: txAttempts[i].Hash, - BlockNumber: broadcastBlock, + BlockNumber: big.NewInt(broadcastBlock), TransactionIndex: 1, - Receipt: evmtypes.Receipt{}, - CreatedAt: time.Now(), }) } - sql = `INSERT INTO evm.receipts (block_hash, tx_hash, block_number, transaction_index, receipt, created_at) - VALUES (:block_hash, :tx_hash, :block_number, :transaction_index, :receipt, :created_at)` - for _, r := range receipts { - _, err2 := db.NamedExec(sql, r) - require.NoError(t, err2) + for i := range receipts { + _, err = txStore.InsertReceipt(&receipts[i]) + require.NoError(t, err) } - counts = vrf.GetStartingResponseCountsV1(q, lggr, 1337, uint32(finalityDepth)) + counts, err = listenerV1.GetStartingResponseCountsV1(testutils.Context(t)) + require.NoError(t, err) assert.Equal(t, 3, len(counts)) assert.Equal(t, uint64(1), counts[utils.PadByteToHash(0x10)]) assert.Equal(t, uint64(2), counts[utils.PadByteToHash(0x11)]) assert.Equal(t, uint64(2), counts[utils.PadByteToHash(0x12)]) - countsV2 := vrf.GetStartingResponseCountsV2(q, lggr, 1337, uint32(finalityDepth)) + countsV2, err := listenerV2.GetStartingResponseCountsV2(testutils.Context(t)) + require.NoError(t, err) t.Log(countsV2) assert.Equal(t, 3, len(countsV2)) assert.Equal(t, uint64(1), countsV2[big.NewInt(0x10).String()]) diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 8bac485d65..17cb9ec96e 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -4,6 +4,7 @@ import ( "cmp" "context" "database/sql" + "encoding/hex" "fmt" "math" "math/big" @@ -12,6 +13,7 @@ import ( "sync" "time" + "github.com/avast/retry-go/v4" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -27,8 +29,7 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -56,6 +57,8 @@ var ( batchCoordinatorV2ABI = evmtypes.MustGetABI(batch_vrf_coordinator_v2.BatchVRFCoordinatorV2ABI) batchCoordinatorV2PlusABI = evmtypes.MustGetABI(batch_vrf_coordinator_v2plus.BatchVRFCoordinatorV2PlusABI) vrfOwnerABI = evmtypes.MustGetABI(vrf_owner.VRFOwnerMetaData.ABI) + // These are the transaction states used when summing up already reserved subscription funds that are about to be used in in-flight transactions + reserveEthLinkQueryStates = []txmgrtypes.TxState{txmgrcommon.TxUnconfirmed, txmgrcommon.TxUnstarted, txmgrcommon.TxInProgress} ) const ( @@ -73,29 +76,8 @@ const ( // backoffFactor is the factor by which to increase the delay each time a request fails. backoffFactor = 1.3 - V2ReservedLinkQuery = `SELECT SUM(CAST(meta->>'MaxLink' AS NUMERIC(78, 0))) - FROM evm.txes - WHERE meta->>'MaxLink' IS NOT NULL - AND evm_chain_id = $1 - AND CAST(meta->>'SubId' AS NUMERIC) = $2 - AND state IN ('unconfirmed', 'unstarted', 'in_progress') - GROUP BY meta->>'SubId'` - - V2PlusReservedLinkQuery = `SELECT SUM(CAST(meta->>'MaxLink' AS NUMERIC(78, 0))) - FROM evm.txes - WHERE meta->>'MaxLink' IS NOT NULL - AND evm_chain_id = $1 - AND CAST(meta->>'GlobalSubId' AS NUMERIC) = $2 - AND state IN ('unconfirmed', 'unstarted', 'in_progress') - GROUP BY meta->>'GlobalSubId'` - - V2PlusReservedEthQuery = `SELECT SUM(CAST(meta->>'MaxEth' AS NUMERIC(78, 0))) - FROM evm.txes - WHERE meta->>'MaxEth' IS NOT NULL - AND evm_chain_id = $1 - AND CAST(meta->>'GlobalSubId' AS NUMERIC) = $2 - AND state IN ('unconfirmed', 'unstarted', 'in_progress') - GROUP BY meta->>'GlobalSubId'` + txMetaFieldSubId = "SubId" + txMetaGlobalSubId = "GlobalSubId" CouldNotDetermineIfLogConsumedMsg = "Could not determine if log was already consumed" ) @@ -116,33 +98,27 @@ func New( cfg vrfcommon.Config, feeCfg vrfcommon.FeeConfig, l logger.Logger, - ethClient evmclient.Client, + chain evm.Chain, chainID *big.Int, - logBroadcaster log.Broadcaster, q pg.Q, coordinator CoordinatorV2_X, batchCoordinator batch_vrf_coordinator_v2.BatchVRFCoordinatorV2Interface, vrfOwner vrf_owner.VRFOwnerInterface, aggregator *aggregator_v3_interface.AggregatorV3Interface, - txm txmgr.TxManager, pipelineRunner pipeline.Runner, gethks keystore.Eth, job job.Job, mailMon *utils.MailboxMonitor, reqLogs *utils.Mailbox[log.Broadcast], reqAdded func(), - respCount map[string]uint64, - headBroadcaster httypes.HeadBroadcasterRegistry, deduper *vrfcommon.LogDeduper, ) job.ServiceCtx { return &listenerV2{ cfg: cfg, feeCfg: feeCfg, l: logger.Sugared(l), - ethClient: ethClient, + chain: chain, chainID: chainID, - logBroadcaster: logBroadcaster, - txm: txm, mailMon: mailMon, coordinator: coordinator, batchCoordinator: batchCoordinator, @@ -154,9 +130,7 @@ func New( reqLogs: reqLogs, chStop: make(chan struct{}), reqAdded: reqAdded, - respCount: respCount, blockNumberToReqID: pairing.New(), - headBroadcaster: headBroadcaster, latestHeadMu: sync.RWMutex{}, wg: &sync.WaitGroup{}, aggregator: aggregator, @@ -193,14 +167,12 @@ type vrfPipelineResult struct { type listenerV2 struct { services.StateMachine - cfg vrfcommon.Config - feeCfg vrfcommon.FeeConfig - l logger.SugaredLogger - ethClient evmclient.Client - chainID *big.Int - logBroadcaster log.Broadcaster - txm txmgr.TxManager - mailMon *utils.MailboxMonitor + cfg vrfcommon.Config + feeCfg vrfcommon.FeeConfig + l logger.SugaredLogger + chain evm.Chain + chainID *big.Int + mailMon *utils.MailboxMonitor coordinator CoordinatorV2_X batchCoordinator batch_vrf_coordinator_v2.BatchVRFCoordinatorV2Interface @@ -229,7 +201,6 @@ type listenerV2 struct { blockNumberToReqID *pairing.PairHeap // head tracking data structures - headBroadcaster httypes.HeadBroadcasterRegistry latestHeadMu sync.RWMutex latestHeadNumber uint64 @@ -273,7 +244,7 @@ func (lsn *listenerV2) Start(ctx context.Context) error { spec := job.LoadDefaultVRFPollPeriod(*lsn.job.VRFSpec) - unsubscribeLogs := lsn.logBroadcaster.Register(lsn, log.ListenerOpts{ + unsubscribeLogs := lsn.chain.LogBroadcaster().Register(lsn, log.ListenerOpts{ Contract: lsn.coordinator.Address(), ParseLog: lsn.coordinator.ParseLog, LogsWithTopics: lsn.coordinator.LogsWithTopics(spec.PublicKey.MustHash()), @@ -284,11 +255,20 @@ func (lsn *listenerV2) Start(ctx context.Context) error { ReplayStartedCallback: lsn.ReplayStartedCallback, }) - latestHead, unsubscribeHeadBroadcaster := lsn.headBroadcaster.Subscribe(lsn) + latestHead, unsubscribeHeadBroadcaster := lsn.chain.HeadBroadcaster().Subscribe(lsn) if latestHead != nil { lsn.setLatestHead(latestHead) } + lsn.respCountMu.Lock() + defer lsn.respCountMu.Unlock() + var respCount map[string]uint64 + respCount, err = lsn.GetStartingResponseCountsV2(ctx) + if err != nil { + return err + } + lsn.respCount = respCount + // Log listener gathers request logs lsn.wg.Add(1) go func() { @@ -306,6 +286,46 @@ func (lsn *listenerV2) Start(ctx context.Context) error { }) } +func (lsn *listenerV2) GetStartingResponseCountsV2(ctx context.Context) (respCount map[string]uint64, err error) { + respCounts := map[string]uint64{} + var latestBlockNum *big.Int + // Retry client call for LatestBlockHeight if fails + // Want to avoid failing startup due to potential faulty RPC call + err = retry.Do(func() error { + latestBlockNum, err = lsn.chain.Client().LatestBlockHeight(ctx) + return err + }, retry.Attempts(10), retry.Delay(500*time.Millisecond)) + if err != nil { + return nil, err + } + if latestBlockNum == nil { + return nil, errors.New("LatestBlockHeight return nil block num") + } + confirmedBlockNum := latestBlockNum.Int64() - int64(lsn.chain.Config().EVM().FinalityDepth()) + // Only check as far back as the evm finality depth for completed transactions. + var counts []vrfcommon.RespCountEntry + counts, err = vrfcommon.GetRespCounts(ctx, lsn.chain.TxManager(), lsn.chainID, confirmedBlockNum) + if err != nil { + // Continue with an empty map, do not block job on this. + lsn.l.Errorw("Unable to read previous confirmed fulfillments", "err", err) + return respCounts, nil + } + + for _, c := range counts { + // Remove the quotes from the json + req := strings.Replace(c.RequestID, `"`, ``, 2) + // Remove the 0x prefix + b, err := hex.DecodeString(req[2:]) + if err != nil { + lsn.l.Errorw("Unable to read fulfillment", "err", err, "reqID", c.RequestID) + continue + } + bi := new(big.Int).SetBytes(b) + respCounts[bi.String()] = uint64(c.Count) + } + return respCounts, nil +} + func (lsn *listenerV2) setLatestHead(head *evmtypes.Head) { lsn.latestHeadMu.Lock() defer lsn.latestHeadMu.Unlock() @@ -520,68 +540,80 @@ func (lsn *listenerV2) processPendingVRFRequests(ctx context.Context) { // MaybeSubtractReservedLink figures out how much LINK is reserved for other VRF requests that // have not been fully confirmed yet on-chain, and subtracts that from the given startBalance, // and returns that value if there are no errors. -func MaybeSubtractReservedLink(q pg.Q, startBalance *big.Int, chainID uint64, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { - var ( - reservedLink string - query string - ) +func (lsn *listenerV2) MaybeSubtractReservedLink(ctx context.Context, startBalance *big.Int, chainID *big.Int, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { + var metaField string if vrfVersion == vrfcommon.V2Plus { - query = V2PlusReservedLinkQuery + metaField = txMetaGlobalSubId } else if vrfVersion == vrfcommon.V2 { - query = V2ReservedLinkQuery + metaField = txMetaFieldSubId } else { return nil, errors.Errorf("unsupported vrf version %s", vrfVersion) } - err := q.Get(&reservedLink, query, chainID, subID.String()) + txes, err := lsn.chain.TxManager().FindTxesByMetaFieldAndStates(ctx, metaField, subID.String(), reserveEthLinkQueryStates, chainID) if err != nil && !errors.Is(err, sql.ErrNoRows) { - return nil, errors.Wrap(err, "getting reserved LINK") + return nil, errors.Wrap(err, "TXM FindTxesByMetaFieldAndStates failed") } - if reservedLink != "" { - reservedLinkInt, success := big.NewInt(0).SetString(reservedLink, 10) - if !success { - return nil, fmt.Errorf("converting reserved LINK %s", reservedLink) + reservedLinkSum := big.NewInt(0) + // Aggregate non-null MaxLink from all txes returned + for _, tx := range txes { + var meta *txmgrtypes.TxMeta[common.Address, common.Hash] + meta, err = tx.GetMeta() + if err != nil { + return nil, errors.Wrap(err, "GetMeta for Tx failed") } + if meta != nil && meta.MaxLink != nil { + txMaxLink, success := new(big.Int).SetString(*meta.MaxLink, 10) + if !success { + return nil, fmt.Errorf("converting reserved LINK %s", *meta.MaxLink) + } - return new(big.Int).Sub(startBalance, reservedLinkInt), nil + reservedLinkSum.Add(reservedLinkSum, txMaxLink) + } } - return new(big.Int).Set(startBalance), nil + return new(big.Int).Sub(startBalance, reservedLinkSum), nil } // MaybeSubtractReservedEth figures out how much ether is reserved for other VRF requests that // have not been fully confirmed yet on-chain, and subtracts that from the given startBalance, // and returns that value if there are no errors. -func MaybeSubtractReservedEth(q pg.Q, startBalance *big.Int, chainID uint64, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { - var ( - reservedEther string - query string - ) +func (lsn *listenerV2) MaybeSubtractReservedEth(ctx context.Context, startBalance *big.Int, chainID *big.Int, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { + var metaField string if vrfVersion == vrfcommon.V2Plus { - query = V2PlusReservedEthQuery + metaField = txMetaGlobalSubId } else if vrfVersion == vrfcommon.V2 { // native payment is not supported for v2, so returning 0 reserved ETH return big.NewInt(0), nil } else { return nil, errors.Errorf("unsupported vrf version %s", vrfVersion) } - err := q.Get(&reservedEther, query, chainID, subID.String()) + txes, err := lsn.chain.TxManager().FindTxesByMetaFieldAndStates(ctx, metaField, subID.String(), reserveEthLinkQueryStates, chainID) if err != nil && !errors.Is(err, sql.ErrNoRows) { - return nil, errors.Wrap(err, "getting reserved ether") + return nil, errors.Wrap(err, "TXM FindTxesByMetaFieldAndStates failed") } - if reservedEther != "" { - reservedEtherInt, success := big.NewInt(0).SetString(reservedEther, 10) - if !success { - return nil, fmt.Errorf("converting reserved ether %s", reservedEther) + reservedEthSum := big.NewInt(0) + // Aggregate non-null MaxEth from all txes returned + for _, tx := range txes { + var meta *txmgrtypes.TxMeta[common.Address, common.Hash] + meta, err = tx.GetMeta() + if err != nil { + return nil, errors.Wrap(err, "GetMeta for Tx failed") } + if meta != nil && meta.MaxEth != nil { + txMaxEth, success := new(big.Int).SetString(*meta.MaxEth, 10) + if !success { + return nil, fmt.Errorf("converting reserved ETH %s", *meta.MaxEth) + } - return new(big.Int).Sub(startBalance, reservedEtherInt), nil + reservedEthSum.Add(reservedEthSum, txMaxEth) + } } if startBalance != nil { - return new(big.Int).Set(startBalance), nil + return new(big.Int).Sub(startBalance, reservedEthSum), nil } return big.NewInt(0), nil } @@ -812,14 +844,14 @@ func (lsn *listenerV2) processRequestsPerSubBatch( subIsActive bool, ) map[string]struct{} { var processed = make(map[string]struct{}) - startBalanceNoReserveLink, err := MaybeSubtractReservedLink( - lsn.q, startLinkBalance, lsn.chainID.Uint64(), subID, lsn.coordinator.Version()) + startBalanceNoReserveLink, err := lsn.MaybeSubtractReservedLink( + ctx, startLinkBalance, lsn.chainID, subID, lsn.coordinator.Version()) if err != nil { lsn.l.Errorw("Couldn't get reserved LINK for subscription", "sub", reqs[0].req.SubID(), "err", err) return processed } - startBalanceNoReserveEth, err := MaybeSubtractReservedEth( - lsn.q, startEthBalance, lsn.chainID.Uint64(), subID, lsn.coordinator.Version()) + startBalanceNoReserveEth, err := lsn.MaybeSubtractReservedEth( + ctx, startEthBalance, lsn.chainID, subID, lsn.coordinator.Version()) if err != nil { lsn.l.Errorw("Couldn't get reserved ether for subscription", "sub", reqs[0].req.SubID(), "err", err) return processed @@ -883,7 +915,7 @@ func (lsn *listenerV2) enqueueForceFulfillment( // fulfill the request through the VRF owner err = lsn.q.Transaction(func(tx pg.Queryer) error { - if err = lsn.logBroadcaster.MarkConsumed(p.req.lb, pg.WithQueryer(tx)); err != nil { + if err = lsn.chain.LogBroadcaster().MarkConsumed(p.req.lb, pg.WithQueryer(tx)); err != nil { return err } @@ -901,7 +933,7 @@ func (lsn *listenerV2) enqueueForceFulfillment( if err != nil { return errors.Wrap(err, "abi pack VRFOwner.fulfillRandomWords") } - estimateGasLimit, err := lsn.ethClient.EstimateGas(ctx, ethereum.CallMsg{ + estimateGasLimit, err := lsn.chain.Client().EstimateGas(ctx, ethereum.CallMsg{ From: fromAddress, To: &vrfOwnerAddressSpec, Data: txData, @@ -919,7 +951,7 @@ func (lsn *listenerV2) enqueueForceFulfillment( requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) subID := p.req.req.SubID() requestTxHash := p.req.req.Raw().TxHash - etx, err = lsn.txm.CreateTransaction(ctx, txmgr.TxRequest{ + etx, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: lsn.vrfOwner.Address(), EncodedPayload: txData, @@ -943,7 +975,7 @@ func (lsn *listenerV2) enqueueForceFulfillment( func (lsn *listenerV2) isConsumerValidAfterFinalityDepthElapsed(ctx context.Context, req pendingRequest) bool { latestHead := lsn.getLatestHead() if latestHead-req.req.Raw().BlockNumber > uint64(lsn.cfg.FinalityDepth()) { - code, err := lsn.ethClient.CodeAt(ctx, req.req.Sender(), big.NewInt(int64(latestHead))) + code, err := lsn.chain.Client().CodeAt(ctx, req.req.Sender(), big.NewInt(int64(latestHead))) if err != nil { lsn.l.Warnw("Failed to fetch contract code", "err", err) return true // error fetching code, give the benefit of doubt to the consumer @@ -1103,7 +1135,7 @@ func (lsn *listenerV2) processRequestsPerSubHelper( if err = lsn.pipelineRunner.InsertFinishedRun(p.run, true, pg.WithQueryer(tx)); err != nil { return err } - if err = lsn.logBroadcaster.MarkConsumed(p.req.lb, pg.WithQueryer(tx)); err != nil { + if err = lsn.chain.LogBroadcaster().MarkConsumed(p.req.lb, pg.WithQueryer(tx)); err != nil { return err } @@ -1126,7 +1158,7 @@ func (lsn *listenerV2) processRequestsPerSubHelper( requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) coordinatorAddress := lsn.coordinator.Address() requestTxHash := p.req.req.Raw().TxHash - transaction, err = lsn.txm.CreateTransaction(ctx, txmgr.TxRequest{ + transaction, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: lsn.coordinator.Address(), EncodedPayload: hexutil.MustDecode(p.payload), @@ -1185,15 +1217,15 @@ func (lsn *listenerV2) processRequestsPerSub( } var processed = make(map[string]struct{}) - chainId := lsn.ethClient.ConfiguredChainID() - startBalanceNoReserveLink, err := MaybeSubtractReservedLink( - lsn.q, startLinkBalance, chainId.Uint64(), subID, lsn.coordinator.Version()) + chainId := lsn.chain.Client().ConfiguredChainID() + startBalanceNoReserveLink, err := lsn.MaybeSubtractReservedLink( + ctx, startLinkBalance, chainId, subID, lsn.coordinator.Version()) if err != nil { lsn.l.Errorw("Couldn't get reserved LINK for subscription", "sub", reqs[0].req.SubID(), "err", err) return processed } - startBalanceNoReserveEth, err := MaybeSubtractReservedEth( - lsn.q, startEthBalance, lsn.chainID.Uint64(), subID, lsn.coordinator.Version()) + startBalanceNoReserveEth, err := lsn.MaybeSubtractReservedEth( + ctx, startEthBalance, lsn.chainID, subID, lsn.coordinator.Version()) if err != nil { lsn.l.Errorw("Couldn't get reserved ETH for subscription", "sub", reqs[0].req.SubID(), "err", err) return processed @@ -1299,7 +1331,7 @@ func (lsn *listenerV2) checkReqsFulfilled(ctx context.Context, l logger.Logger, } } - err := lsn.ethClient.BatchCallContext(ctx, calls) + err := lsn.chain.Client().BatchCallContext(ctx, calls) if err != nil { return fulfilled, errors.Wrap(err, "making batch call") } @@ -1582,7 +1614,7 @@ func (lsn *listenerV2) getConfirmedAt(req RandomWordsRequested, nodeMinConfs uin func (lsn *listenerV2) handleLog(lb log.Broadcast, minConfs uint32) { if v, ok := lb.DecodedLog().(*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled); ok { lsn.l.Debugw("Received fulfilled log", "reqID", v.RequestId, "success", v.Success) - consumed, err := lsn.logBroadcaster.WasAlreadyConsumed(lb) + consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(lb) if err != nil { lsn.l.Errorw(CouldNotDetermineIfLogConsumedMsg, "err", err, "txHash", lb.RawLog().TxHash) return @@ -1602,7 +1634,7 @@ func (lsn *listenerV2) handleLog(lb log.Broadcast, minConfs uint32) { if v, ok := lb.DecodedLog().(*vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalRandomWordsFulfilled); ok { lsn.l.Debugw("Received fulfilled log", "reqID", v.RequestId, "success", v.Success) - consumed, err := lsn.logBroadcaster.WasAlreadyConsumed(lb) + consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(lb) if err != nil { lsn.l.Errorw(CouldNotDetermineIfLogConsumedMsg, "err", err, "txHash", lb.RawLog().TxHash) return @@ -1623,7 +1655,7 @@ func (lsn *listenerV2) handleLog(lb log.Broadcast, minConfs uint32) { req, err := lsn.coordinator.ParseRandomWordsRequested(lb.RawLog()) if err != nil { lsn.l.Errorw("Failed to parse log", "err", err, "txHash", lb.RawLog().TxHash) - consumed, err := lsn.logBroadcaster.WasAlreadyConsumed(lb) + consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(lb) if err != nil { lsn.l.Errorw(CouldNotDetermineIfLogConsumedMsg, "err", err, "txHash", lb.RawLog().TxHash) return @@ -1648,7 +1680,7 @@ func (lsn *listenerV2) handleLog(lb log.Broadcast, minConfs uint32) { } func (lsn *listenerV2) markLogAsConsumed(lb log.Broadcast) { - err := lsn.logBroadcaster.MarkConsumed(lb) + err := lsn.chain.LogBroadcaster().MarkConsumed(lb) lsn.l.ErrorIf(err, fmt.Sprintf("Unable to mark log %v as consumed", lb.String())) } diff --git a/core/services/vrf/v2/listener_v2_helpers_test.go b/core/services/vrf/v2/listener_v2_helpers_test.go index 8ba900bdc3..fc34a115b1 100644 --- a/core/services/vrf/v2/listener_v2_helpers_test.go +++ b/core/services/vrf/v2/listener_v2_helpers_test.go @@ -7,7 +7,9 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" v2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" + "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" ) func TestListener_EstimateFeeJuels(t *testing.T) { @@ -29,3 +31,23 @@ func TestListener_EstimateFeeJuels(t *testing.T) { require.Nil(t, actual) require.Error(t, err) } + +func Test_TxListDeduper(t *testing.T) { + tx1 := &txmgr.Tx{ + ID: 1, + Value: *big.NewInt(0), + ChainID: big.NewInt(0), + } + tx2 := &txmgr.Tx{ + ID: 1, + Value: *big.NewInt(1), + ChainID: big.NewInt(0), + } + tx3 := &txmgr.Tx{ + ID: 2, + Value: *big.NewInt(1), + ChainID: big.NewInt(0), + } + txList := vrfcommon.DedupeTxList([]*txmgr.Tx{tx1, tx2, tx3}) + require.Equal(t, len(txList), 2) +} diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 70d5b8154e..17615feb63 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -1,6 +1,7 @@ package v2 import ( + "encoding/json" "math/big" "sync" "testing" @@ -13,39 +14,44 @@ import ( "github.com/stretchr/testify/require" "github.com/theodesp/go-heaps/pairing" - "github.com/smartcontractkit/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" + evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" ) -const ( - addEthTxQuery = `INSERT INTO evm.txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) - VALUES ( - $1, $2, $3, $4, $5, $6, NOW(), $7, $8, $9, $10, $11 - ) - RETURNING "txes".*` - - addConfirmedEthTxQuery = `INSERT INTO evm.txes (nonce, broadcast_at, initial_broadcast_at, error, from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) - VALUES ( - $1, NOW(), NOW(), NULL, $2, $3, $4, $5, $6, 'confirmed', NOW(), $7, $8, $9, $10, $11 - ) - RETURNING "txes".*` -) +func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.Master) txmgrcommon.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] { + _, _, evmConfig := txmgr.MakeTestConfigs(t) + ec := evmtest.NewEthClientMockWithDefaultChain(t) + txmConfig := txmgr.NewEvmTxmConfig(evmConfig) + txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, + nil, txStore, nil, nil, nil, nil) + + return txm +} + +func MakeTestListenerV2(chain evm.Chain) *listenerV2 { + return &listenerV2{chainID: chain.Client().ConfiguredChainID(), chain: chain} +} func txMetaSubIDs(t *testing.T, vrfVersion vrfcommon.Version, subID *big.Int) (*uint64, *string) { var ( @@ -62,89 +68,118 @@ func txMetaSubIDs(t *testing.T, vrfVersion vrfcommon.Version, subID *big.Int) (* return txMetaSubID, txMetaGlobalSubID } -func addEthTx(t *testing.T, db *sqlx.DB, from common.Address, state txmgrtypes.TxState, maxLink string, subID *big.Int, reqTxHash common.Hash, vrfVersion vrfcommon.Version) { +func addEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, from common.Address, state txmgrtypes.TxState, maxLink string, subID *big.Int, reqTxHash common.Hash, vrfVersion vrfcommon.Version) { txMetaSubID, txMetaGlobalSubID := txMetaSubIDs(t, vrfVersion, subID) - _, err := db.Exec(addEthTxQuery, - from, // from - from, // to - []byte(`blah`), // payload - 0, // value - 0, // limit - state, - txmgr.TxMeta{ - MaxLink: &maxLink, - SubID: txMetaSubID, - GlobalSubID: txMetaGlobalSubID, - RequestTxHash: &reqTxHash, - }, - uuid.NullUUID{}, - 1337, - 0, // confs - nil) + b, err := json.Marshal(txmgr.TxMeta{ + MaxLink: &maxLink, + SubID: txMetaSubID, + GlobalSubID: txMetaGlobalSubID, + RequestTxHash: &reqTxHash, + }) + require.NoError(t, err) + meta := datatypes.JSON(b) + tx := &txmgr.Tx{ + FromAddress: from, + ToAddress: from, + EncodedPayload: []byte(`blah`), + Value: *big.NewInt(0), + FeeLimit: 0, + State: state, + Meta: &meta, + Subject: uuid.NullUUID{}, + ChainID: testutils.SimulatedChainID, + MinConfirmations: clnull.Uint32{Uint32: 0}, + PipelineTaskRunID: uuid.NullUUID{}, + } + err = txStore.InsertTx(tx) require.NoError(t, err) } -func addConfirmedEthTx(t *testing.T, db *sqlx.DB, from common.Address, maxLink string, subID *big.Int, nonce uint64, vrfVersion vrfcommon.Version) { +func addConfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, from common.Address, maxLink string, subID *big.Int, nonce evmtypes.Nonce, vrfVersion vrfcommon.Version) { txMetaSubID, txMetaGlobalSubID := txMetaSubIDs(t, vrfVersion, subID) - _, err := db.Exec(addConfirmedEthTxQuery, - nonce, // nonce - from, // from - from, // to - []byte(`blah`), // payload - 0, // value - 0, // limit - txmgr.TxMeta{ - MaxLink: &maxLink, - SubID: txMetaSubID, - GlobalSubID: txMetaGlobalSubID, - }, - uuid.NullUUID{}, - 1337, - 0, // confs - nil) + b, err := json.Marshal(txmgr.TxMeta{ + MaxLink: &maxLink, + SubID: txMetaSubID, + GlobalSubID: txMetaGlobalSubID, + }) + require.NoError(t, err) + meta := datatypes.JSON(b) + now := time.Now() + + tx := &txmgr.Tx{ + Sequence: &nonce, + FromAddress: from, + ToAddress: from, + EncodedPayload: []byte(`blah`), + Value: *big.NewInt(0), + FeeLimit: 0, + State: txmgrcommon.TxConfirmed, + Meta: &meta, + Subject: uuid.NullUUID{}, + ChainID: testutils.SimulatedChainID, + MinConfirmations: clnull.Uint32{Uint32: 0}, + PipelineTaskRunID: uuid.NullUUID{}, + BroadcastAt: &now, + InitialBroadcastAt: &now, + } + err = txStore.InsertTx(tx) require.NoError(t, err) } -func addEthTxNativePayment(t *testing.T, db *sqlx.DB, from common.Address, state txmgrtypes.TxState, maxNative string, subID *big.Int, reqTxHash common.Hash, vrfVersion vrfcommon.Version) { +func addEthTxNativePayment(t *testing.T, txStore txmgr.TestEvmTxStore, from common.Address, state txmgrtypes.TxState, maxNative string, subID *big.Int, reqTxHash common.Hash, vrfVersion vrfcommon.Version) { txMetaSubID, txMetaGlobalSubID := txMetaSubIDs(t, vrfVersion, subID) - _, err := db.Exec(addEthTxQuery, - from, // from - from, // to - []byte(`blah`), // payload - 0, // value - 0, // limit - state, - txmgr.TxMeta{ - MaxEth: &maxNative, - SubID: txMetaSubID, - GlobalSubID: txMetaGlobalSubID, - RequestTxHash: &reqTxHash, - }, - uuid.NullUUID{}, - 1337, - 0, // confs - nil) + b, err := json.Marshal(txmgr.TxMeta{ + MaxEth: &maxNative, + SubID: txMetaSubID, + GlobalSubID: txMetaGlobalSubID, + RequestTxHash: &reqTxHash, + }) + require.NoError(t, err) + meta := datatypes.JSON(b) + tx := &txmgr.Tx{ + FromAddress: from, + ToAddress: from, + EncodedPayload: []byte(`blah`), + Value: *big.NewInt(0), + FeeLimit: 0, + State: state, + Meta: &meta, + Subject: uuid.NullUUID{}, + ChainID: testutils.SimulatedChainID, + MinConfirmations: clnull.Uint32{Uint32: 0}, + PipelineTaskRunID: uuid.NullUUID{}, + } + err = txStore.InsertTx(tx) require.NoError(t, err) } -func addConfirmedEthTxNativePayment(t *testing.T, db *sqlx.DB, from common.Address, maxNative string, subID *big.Int, nonce uint64, vrfVersion vrfcommon.Version) { +func addConfirmedEthTxNativePayment(t *testing.T, txStore txmgr.TestEvmTxStore, from common.Address, maxNative string, subID *big.Int, nonce evmtypes.Nonce, vrfVersion vrfcommon.Version) { txMetaSubID, txMetaGlobalSubID := txMetaSubIDs(t, vrfVersion, subID) - _, err := db.Exec(addConfirmedEthTxQuery, - nonce, // nonce - from, // from - from, // to - []byte(`blah`), // payload - 0, // value - 0, // limit - txmgr.TxMeta{ - MaxEth: &maxNative, - SubID: txMetaSubID, - GlobalSubID: txMetaGlobalSubID, - }, - uuid.NullUUID{}, - 1337, - 0, // confs - nil) + b, err := json.Marshal(txmgr.TxMeta{ + MaxEth: &maxNative, + SubID: txMetaSubID, + GlobalSubID: txMetaGlobalSubID, + }) + require.NoError(t, err) + meta := datatypes.JSON(b) + now := time.Now() + tx := &txmgr.Tx{ + Sequence: &nonce, + FromAddress: from, + ToAddress: from, + EncodedPayload: []byte(`blah`), + Value: *big.NewInt(0), + FeeLimit: 0, + State: txmgrcommon.TxConfirmed, + Meta: &meta, + Subject: uuid.NullUUID{}, + ChainID: testutils.SimulatedChainID, + MinConfirmations: clnull.Uint32{Uint32: 0}, + PipelineTaskRunID: uuid.NullUUID{}, + BroadcastAt: &now, + InitialBroadcastAt: &now, + } + err = txStore.InsertTx(tx) require.NoError(t, err) } @@ -152,57 +187,72 @@ func testMaybeSubtractReservedLink(t *testing.T, vrfVersion vrfcommon.Version) { db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) cfg := pgtest.NewQConfig(false) - q := pg.NewQ(db, lggr, cfg) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) - chainID := uint64(1337) - k, err := ks.Eth().Create(big.NewInt(int64(chainID))) + chainID := testutils.SimulatedChainID + k, err := ks.Eth().Create(chainID) require.NoError(t, err) subID := new(big.Int).SetUint64(1) reqTxHash := common.HexToHash("0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8") + j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ + RequestedConfsDelay: 10, + }).Toml()) + require.NoError(t, err) + txstore := txmgr.NewTxStore(db, lggr, cfg) + txm := makeTestTxm(t, txstore, ks) + chain := evmmocks.NewChain(t) + chain.On("TxManager").Return(txm) + listener := &listenerV2{ + respCount: map[string]uint64{}, + job: j, + chain: chain, + } + + ctx := testutils.Context(t) + // Insert an unstarted eth tx with link metadata - addEthTx(t, db, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) - start, err := MaybeSubtractReservedLink(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTx(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) + start, err := listener.MaybeSubtractReservedLink(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) assert.Equal(t, "90000", start.String()) // A confirmed tx should not affect the starting balance - addConfirmedEthTx(t, db, k.Address, "10000", subID, 1, vrfVersion) - start, err = MaybeSubtractReservedLink(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addConfirmedEthTx(t, txstore, k.Address, "10000", subID, 1, vrfVersion) + start, err = listener.MaybeSubtractReservedLink(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) assert.Equal(t, "90000", start.String()) // An unconfirmed tx _should_ affect the starting balance. - addEthTx(t, db, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedLink(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTx(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedLink(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) assert.Equal(t, "80000", start.String()) // One subscriber's reserved link should not affect other subscribers prospective balance. otherSubID := new(big.Int).SetUint64(2) require.NoError(t, err) - addEthTx(t, db, k.Address, txmgrcommon.TxUnstarted, "10000", otherSubID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedLink(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTx(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", otherSubID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedLink(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) require.Equal(t, "80000", start.String()) // One key's data should not affect other keys' data in the case of different subscribers. - k2, err := ks.Eth().Create(big.NewInt(1337)) + k2, err := ks.Eth().Create(testutils.SimulatedChainID) require.NoError(t, err) anotherSubID := new(big.Int).SetUint64(3) - addEthTx(t, db, k2.Address, txmgrcommon.TxUnstarted, "10000", anotherSubID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedLink(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTx(t, txstore, k2.Address, txmgrcommon.TxUnstarted, "10000", anotherSubID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedLink(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) require.Equal(t, "80000", start.String()) // A subscriber's balance is deducted with the link reserved across multiple keys, // i.e, gas lanes. - addEthTx(t, db, k2.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedLink(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTx(t, txstore, k2.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedLink(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) require.Equal(t, "70000", start.String()) } @@ -219,57 +269,73 @@ func testMaybeSubtractReservedNative(t *testing.T, vrfVersion vrfcommon.Version) db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) cfg := pgtest.NewQConfig(false) - q := pg.NewQ(db, lggr, cfg) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) - chainID := uint64(1337) - k, err := ks.Eth().Create(big.NewInt(int64(chainID))) + chainID := testutils.SimulatedChainID + k, err := ks.Eth().Create(chainID) require.NoError(t, err) subID := new(big.Int).SetUint64(1) reqTxHash := common.HexToHash("0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8") + j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ + RequestedConfsDelay: 10, + }).Toml()) + require.NoError(t, err) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txm := makeTestTxm(t, txstore, ks) + require.NoError(t, err) + chain := evmmocks.NewChain(t) + chain.On("TxManager").Return(txm) + listener := &listenerV2{ + respCount: map[string]uint64{}, + job: j, + chain: chain, + } + + ctx := testutils.Context(t) + // Insert an unstarted eth tx with native metadata - addEthTxNativePayment(t, db, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) - start, err := MaybeSubtractReservedEth(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTxNativePayment(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) + start, err := listener.MaybeSubtractReservedEth(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) assert.Equal(t, "90000", start.String()) // A confirmed tx should not affect the starting balance - addConfirmedEthTxNativePayment(t, db, k.Address, "10000", subID, 1, vrfVersion) - start, err = MaybeSubtractReservedEth(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addConfirmedEthTxNativePayment(t, txstore, k.Address, "10000", subID, 1, vrfVersion) + start, err = listener.MaybeSubtractReservedEth(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) assert.Equal(t, "90000", start.String()) // An unconfirmed tx _should_ affect the starting balance. - addEthTxNativePayment(t, db, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedEth(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTxNativePayment(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedEth(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) assert.Equal(t, "80000", start.String()) // One subscriber's reserved native should not affect other subscribers prospective balance. otherSubID := new(big.Int).SetUint64(2) require.NoError(t, err) - addEthTxNativePayment(t, db, k.Address, txmgrcommon.TxUnstarted, "10000", otherSubID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedEth(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTxNativePayment(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", otherSubID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedEth(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) require.Equal(t, "80000", start.String()) // One key's data should not affect other keys' data in the case of different subscribers. - k2, err := ks.Eth().Create(big.NewInt(1337)) + k2, err := ks.Eth().Create(testutils.SimulatedChainID) require.NoError(t, err) anotherSubID := new(big.Int).SetUint64(3) - addEthTxNativePayment(t, db, k2.Address, txmgrcommon.TxUnstarted, "10000", anotherSubID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedEth(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTxNativePayment(t, txstore, k2.Address, txmgrcommon.TxUnstarted, "10000", anotherSubID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedEth(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) require.Equal(t, "80000", start.String()) // A subscriber's balance is deducted with the native reserved across multiple keys, // i.e, gas lanes. - addEthTxNativePayment(t, db, k2.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) - start, err = MaybeSubtractReservedEth(q, big.NewInt(100_000), chainID, subID, vrfVersion) + addEthTxNativePayment(t, txstore, k2.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) + start, err = listener.MaybeSubtractReservedEth(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) require.NoError(t, err) require.Equal(t, "70000", start.String()) } @@ -282,13 +348,26 @@ func TestMaybeSubtractReservedNativeV2(t *testing.T) { db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) cfg := pgtest.NewQConfig(false) - q := pg.NewQ(db, lggr, cfg) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) - chainID := uint64(1337) + chainID := testutils.SimulatedChainID subID := new(big.Int).SetUint64(1) + + j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ + RequestedConfsDelay: 10, + }).Toml()) + require.NoError(t, err) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txm := makeTestTxm(t, txstore, ks) + chain := evmmocks.NewChain(t) + chain.On("TxManager").Return(txm).Maybe() + listener := &listenerV2{ + respCount: map[string]uint64{}, + job: j, + chain: chain, + } // returns error because native payment is not supported for V2 - start, err := MaybeSubtractReservedEth(q, big.NewInt(100_000), chainID, subID, vrfcommon.V2) + start, err := listener.MaybeSubtractReservedEth(testutils.Context(t), big.NewInt(100_000), chainID, subID, vrfcommon.V2) require.NoError(t, err) assert.Equal(t, big.NewInt(0), start) } @@ -445,12 +524,14 @@ func TestListener_handleLog(tt *testing.T) { lb.On("WasAlreadyConsumed", log).Return(false, nil).Once() lb.On("MarkConsumed", log).Return(nil).Once() defer lb.AssertExpectations(t) + chain := evmmocks.NewChain(t) + chain.On("LogBroadcaster").Return(lb) listener := &listenerV2{ respCount: map[string]uint64{}, job: j, blockNumberToReqID: pairing.New(), latestHeadMu: sync.RWMutex{}, - logBroadcaster: lb, + chain: chain, l: logger.TestLogger(t), } listener.handleLog(log, minConfs) @@ -476,12 +557,14 @@ func TestListener_handleLog(tt *testing.T) { lb.On("WasAlreadyConsumed", log).Return(false, nil).Once() lb.On("MarkConsumed", log).Return(nil).Once() defer lb.AssertExpectations(t) + chain := evmmocks.NewChain(t) + chain.On("LogBroadcaster").Return(lb) listener := &listenerV2{ respCount: map[string]uint64{}, job: j, blockNumberToReqID: pairing.New(), latestHeadMu: sync.RWMutex{}, - logBroadcaster: lb, + chain: chain, l: logger.TestLogger(t), } listener.handleLog(log, minConfs) diff --git a/core/services/vrf/v2/listener_v2_types.go b/core/services/vrf/v2/listener_v2_types.go index e0596abcd1..5ad44c31a8 100644 --- a/core/services/vrf/v2/listener_v2_types.go +++ b/core/services/vrf/v2/listener_v2_types.go @@ -170,7 +170,7 @@ func (lsn *listenerV2) processBatch( return errors.Wrap(err, "inserting finished pipeline runs") } - if err = lsn.logBroadcaster.MarkManyConsumed(batch.lbs, pg.WithQueryer(tx)); err != nil { + if err = lsn.chain.LogBroadcaster().MarkManyConsumed(batch.lbs, pg.WithQueryer(tx)); err != nil { return errors.Wrap(err, "mark logs consumed") } @@ -181,7 +181,7 @@ func (lsn *listenerV2) processBatch( for _, reqID := range batch.reqIDs { reqIDHashes = append(reqIDHashes, common.BytesToHash(reqID.Bytes())) } - ethTX, err = lsn.txm.CreateTransaction(ctx, txmgr.TxRequest{ + ethTX, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: lsn.batchCoordinator.Address(), EncodedPayload: payload, @@ -234,7 +234,7 @@ func (lsn *listenerV2) getUnconsumed(l logger.Logger, reqs []pendingRequest) (un // This check to see if the log was consumed needs to be in the same // goroutine as the mark consumed to avoid processing duplicates. - consumed, err := lsn.logBroadcaster.WasAlreadyConsumed(req.lb) + consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(req.lb) if err != nil { // Do not process for now, retry on next iteration. l.Errorw("Could not determine if log was already consumed", diff --git a/core/services/vrf/vrfcommon/utils.go b/core/services/vrf/vrfcommon/utils.go new file mode 100644 index 0000000000..f9cc012d8f --- /dev/null +++ b/core/services/vrf/vrfcommon/utils.go @@ -0,0 +1,78 @@ +package vrfcommon + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" + txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" +) + +type RespCountEntry struct { + RequestID string + Count int +} + +func GetRespCounts(ctx context.Context, txm txmgr.TxManager, chainID *big.Int, confirmedBlockNum int64) ( + []RespCountEntry, + error, +) { + counts := []RespCountEntry{} + metaField := "RequestID" + states := []txmgrtypes.TxState{txmgrcommon.TxUnconfirmed, txmgrcommon.TxUnstarted, txmgrcommon.TxInProgress} + // Search for txes with a non-null meta field in the provided states + unconfirmedTxes, err := txm.FindTxesWithMetaFieldByStates(ctx, metaField, states, chainID) + if err != nil { + return nil, errors.Wrap(err, "getRespCounts failed due to error in FindTxesWithMetaFieldByStates") + } + // Fetch completed transactions only as far back as the given confirmedBlockNum. This avoids + // a table scan of the whole table, which could be large if it is unpruned. + var confirmedTxes []*txmgr.Tx + confirmedTxes, err = txm.FindTxesWithMetaFieldByReceiptBlockNum(ctx, metaField, confirmedBlockNum, chainID) + if err != nil { + return nil, errors.Wrap(err, "getRespCounts failed due to error in FindTxesWithMetaFieldByReceiptBlockNum") + } + txes := DedupeTxList(append(unconfirmedTxes, confirmedTxes...)) + respCountMap := make(map[string]int) + // Consolidate the number of txes for each meta RequestID + for _, tx := range txes { + var meta *txmgrtypes.TxMeta[common.Address, common.Hash] + meta, err = tx.GetMeta() + if err != nil { + return nil, errors.Wrap(err, "getRespCounts failed parsing tx meta field") + } + if meta != nil && meta.RequestID != nil { + requestId := meta.RequestID.String() + if _, exists := respCountMap[requestId]; !exists { + respCountMap[requestId] = 0 + } + respCountMap[requestId]++ + } + } + + // Parse response count map into output + for key, value := range respCountMap { + respCountEntry := RespCountEntry{ + RequestID: key, + Count: value, + } + counts = append(counts, respCountEntry) + } + return counts, nil +} + +func DedupeTxList(txes []*txmgr.Tx) []*txmgr.Tx { + txIdMap := make(map[string]bool) + dedupedTxes := []*txmgr.Tx{} + for _, tx := range txes { + if _, found := txIdMap[tx.GetID()]; !found { + txIdMap[tx.GetID()] = true + dedupedTxes = append(dedupedTxes, tx) + } + } + return dedupedTxes +} diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index fc2e8d7a30..0bd947bbce 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "io" + "math/big" "net/http" "net/url" "strconv" @@ -19,10 +20,12 @@ import ( p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/sqlx" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -658,7 +661,8 @@ func setupJobsControllerTests(t *testing.T) (ta *cltest.TestApplication, cc clte c.P2P.V1.Enabled = ptr(true) c.P2P.PeerID = &cltest.DefaultP2PPeerID }) - app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) + ec := setupEthClientForControllerTests(t) + app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey, ec) require.NoError(t, app.Start(testutils.Context(t))) client := app.NewHTTPClient(nil) @@ -668,6 +672,14 @@ func setupJobsControllerTests(t *testing.T) (ta *cltest.TestApplication, cc clte return app, client } +func setupEthClientForControllerTests(t *testing.T) *evmclimocks.Client { + ec := cltest.NewEthMocksWithStartupAssertions(t) + ec.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil).Maybe() + ec.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(100), nil).Maybe() + ec.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Once().Return(big.NewInt(0), nil).Maybe() + return ec +} + func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication, cltest.HTTPClientCleaner, job.Job, int32, job.Job, int32) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) From 8b6f4899ef0a981b869d7deeed45e40de3193aa2 Mon Sep 17 00:00:00 2001 From: Tate Date: Thu, 2 Nov 2023 15:40:18 -0600 Subject: [PATCH 063/327] E2E Metrics Missing Tag Suffix (#11163) --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 445a027731..785c48da40 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -455,7 +455,7 @@ jobs: with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ETH Smoke Tests ${{ matrix.product.name }} + this-job-name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Keep action running to view traces From 5cc88a82ec77b1d4f3f37b0255af778a056e7e5c Mon Sep 17 00:00:00 2001 From: HenryNguyen5 <6404866+HenryNguyen5@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:43:54 -0400 Subject: [PATCH 064/327] Handle PR bodies correctly (#11165) --- .github/workflows/operator-ui-cd.yml | 2 +- operator_ui/check.sh | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/operator-ui-cd.yml b/.github/workflows/operator-ui-cd.yml index 54f423e6dc..bd589da728 100644 --- a/.github/workflows/operator-ui-cd.yml +++ b/.github/workflows/operator-ui-cd.yml @@ -39,7 +39,7 @@ jobs: url: ${{ secrets.AWS_INFRA_RELENG_TOKEN_ISSUER_LAMBDA_URL }} - name: Open PR - uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v4.2.4 + uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2 with: title: Update Operator UI from ${{ steps.update.outputs.current_tag }} to ${{ steps.update.outputs.latest_tag }} token: ${{ steps.get-gh-token.outputs.access-token }} diff --git a/operator_ui/check.sh b/operator_ui/check.sh index 614afd4b07..9e73821808 100755 --- a/operator_ui/check.sh +++ b/operator_ui/check.sh @@ -26,12 +26,13 @@ else echo "$latest_tag" >"$tag_file" echo "Tag updated $current_tag -> $latest_tag" if [ "$CI" ]; then - echo "current_tag=$current_tag" >> $GITHUB_OUTPUT - echo "latest_tag=$latest_tag" >> $GITHUB_OUTPUT - # See https://github.com/peter-evans/create-pull-request/blob/main/docs/examples.md#setting-the-pull-request-body-from-a-file - body="${body//'%'/'%25'}" - body="${body//$'\n'/'%0A'}" - body="${body//$'\r'/'%0D'}" - echo "body=$body" >> $GITHUB_OUTPUT + echo "current_tag=$current_tag" >>$GITHUB_OUTPUT + echo "latest_tag=$latest_tag" >>$GITHUB_OUTPUT + + # See https://github.com/orgs/community/discussions/26288#discussioncomment-3876281 + delimiter="$(openssl rand -hex 8)" + echo "body<<${delimiter}" >>"${GITHUB_OUTPUT}" + echo "$body" >>"${GITHUB_OUTPUT}" + echo "${delimiter}" >>"${GITHUB_OUTPUT}" fi fi From ed9dc15b98c2f0cbf105d0f1b5fd40cf7571998c Mon Sep 17 00:00:00 2001 From: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> Date: Fri, 3 Nov 2023 10:39:34 +0000 Subject: [PATCH 065/327] fix: v2plus superscript (#11156) --- .../testnet/v2plusscripts/super_scripts.go | 91 +++++++++++-------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index f805e7b74f..752e06bbb2 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -6,15 +6,16 @@ import ( "encoding/hex" "flag" "fmt" + "math/big" + "os" + "strings" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/jobs" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" - "math/big" - "os" - "strings" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -467,12 +468,12 @@ func DeployUniverseViaCLI(e helpers.Environment) { deployCmd := flag.NewFlagSet("deploy-universe", flag.ExitOnError) // required flags - linkAddress := *deployCmd.String("link-address", "", "address of link token") - linkEthAddress := *deployCmd.String("link-eth-feed", "", "address of link eth feed") - bhsContractAddressString := *deployCmd.String("bhs-address", "", "address of BHS contract") - batchBHSAddressString := *deployCmd.String("batch-bhs-address", "", "address of Batch BHS contract") - coordinatorAddressString := *deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") - batchCoordinatorAddressString := *deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") + linkAddress := deployCmd.String("link-address", "", "address of link token") + linkEthAddress := deployCmd.String("link-eth-feed", "", "address of link eth feed") + bhsContractAddressString := deployCmd.String("bhs-address", "", "address of BHS contract") + batchBHSAddressString := deployCmd.String("batch-bhs-address", "", "address of Batch BHS contract") + coordinatorAddressString := deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") + batchCoordinatorAddressString := deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", "1e19", "amount to fund subscription with Link token (Juels)") subscriptionBalanceNativeWeiString := deployCmd.String("subscription-balance-native", "1e18", "amount to fund subscription with native token (Wei)") @@ -513,14 +514,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { SendingKeyFundingAmount: fundingAmount, } - bhsContractAddress := common.HexToAddress(bhsContractAddressString) - batchBHSAddress := common.HexToAddress(batchBHSAddressString) - coordinatorAddress := common.HexToAddress(coordinatorAddressString) - batchCoordinatorAddress := common.HexToAddress(batchCoordinatorAddressString) + bhsContractAddress := common.HexToAddress(*bhsContractAddressString) + batchBHSAddress := common.HexToAddress(*batchBHSAddressString) + coordinatorAddress := common.HexToAddress(*coordinatorAddressString) + batchCoordinatorAddress := common.HexToAddress(*batchCoordinatorAddressString) contractAddresses := model.ContractAddresses{ - LinkAddress: linkAddress, - LinkEthAddress: linkEthAddress, + LinkAddress: *linkAddress, + LinkEthAddress: *linkEthAddress, BhsContractAddress: bhsContractAddress, BatchBHSAddress: batchBHSAddress, CoordinatorAddress: coordinatorAddress, @@ -563,28 +564,32 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, batchFulfillmentEnabled bool, nodesMap map[string]model.Node, ) model.JobSpecs { - // Put key in ECDSA format - if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { - *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) - } + var compressedPkHex string + var keyHash common.Hash + if len(*registerKeyUncompressedPubKey) > 0 { + // Put key in ECDSA format + if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { + *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) + } - // Generate compressed public key and key hash - pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) - helpers.PanicErr(err) - pk, err := crypto.UnmarshalPubkey(pubBytes) - helpers.PanicErr(err) - var pkBytes []byte - if big.NewInt(0).Mod(pk.Y, big.NewInt(2)).Uint64() != 0 { - pkBytes = append(pk.X.Bytes(), 1) - } else { - pkBytes = append(pk.X.Bytes(), 0) - } - var newPK secp256k1.PublicKey - copy(newPK[:], pkBytes) + // Generate compressed public key and key hash + pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) + helpers.PanicErr(err) + pk, err := crypto.UnmarshalPubkey(pubBytes) + helpers.PanicErr(err) + var pkBytes []byte + if big.NewInt(0).Mod(pk.Y, big.NewInt(2)).Uint64() != 0 { + pkBytes = append(pk.X.Bytes(), 1) + } else { + pkBytes = append(pk.X.Bytes(), 0) + } + var newPK secp256k1.PublicKey + copy(newPK[:], pkBytes) - compressedPkHex := hexutil.Encode(pkBytes) - keyHash, err := newPK.Hash() - helpers.PanicErr(err) + compressedPkHex = hexutil.Encode(pkBytes) + keyHash, err = newPK.Hash() + helpers.PanicErr(err) + } if len(contractAddresses.LinkAddress) == 0 { fmt.Println("\nDeploying LINK Token...") @@ -689,7 +694,13 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[model.VRFPrimaryNodeName].SendingKeys[0].Address, + func() string { + if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { + return keys[0].Address + } else { + return common.HexToAddress("0x0").String() + } + }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) @@ -704,7 +715,13 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[model.VRFPrimaryNodeName].SendingKeys[0], + func() string { + if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { + return keys[0].Address + } else { + return common.HexToAddress("0x0").String() + } + }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) From 4ea52f902f2ff1a0bef53e90c19ee46a3e01cf6c Mon Sep 17 00:00:00 2001 From: "app-token-issuer-infra-releng[bot]" <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 11:17:17 +0000 Subject: [PATCH 066/327] Update Operator UI from v0.8.0-e10948a to v0.8.0-2f868c3 (#11135) Co-authored-by: github-merge-queue[bot] --- operator_ui/TAG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator_ui/TAG b/operator_ui/TAG index e08ca07267..3b63cc3add 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1 +1 @@ -v0.8.0-e10948a +v0.8.0-2f868c3 From 4174f36b2727fbba5da81af591c24a16d396c802 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Fri, 3 Nov 2023 12:23:13 +0100 Subject: [PATCH 067/327] added smoke test & load test for log poller (#11110) * added smoke test & load test for log poller * read CL nodes logs in parallel and compare them in parallel with EVM node logs (has a big impact on execution, when we emit 100k+ logs) * add simple config validation * add smoke tests for backup process and replay * run replay test for 15m instead of 5m (for debuggin) * do not use hardcoded postgres values * added support for chaos experiments (pausing containers) + a smoke test that uses them * streamline log poller tests * remove backup poller test -- way to test it reliably in e2e tests * don't skip replay test * add go.work* to .gitignore * add tests that can easier run in CI + some changes after testing with live testnets * wait for LP to finalise endblock + on demand workflow in GH * rename on demand workflow * fix typo in workflow name --- .github/log_poller_on_demand.yml | 66 + .gitignore | 3 +- core/chains/evm/logpoller/log_poller.go | 4 +- integration-tests/client/chainlink.go | 20 + integration-tests/client/chainlink_models.go | 14 + .../contracts/contract_deployer.go | 20 + .../contracts/contract_models.go | 10 + integration-tests/contracts/test_contracts.go | 79 ++ integration-tests/docker/cmd/test_env.go | 1 + integration-tests/docker/test_env/test_env.go | 1 + .../docker/test_env/test_env_builder.go | 67 +- integration-tests/go.mod | 8 +- integration-tests/go.sum | 4 +- integration-tests/load/log_poller/config.toml | 22 + .../load/log_poller/log_poller_test.go | 24 + .../reorg/log_poller_maybe_reorg_test.go | 42 + integration-tests/smoke/automation_test.go | 3 +- integration-tests/smoke/log_poller_test.go | 140 ++ .../universal/log_poller/config.go | 247 ++++ integration-tests/universal/log_poller/gun.go | 78 ++ .../universal/log_poller/helpers.go | 1136 +++++++++++++++++ .../universal/log_poller/scenarios.go | 498 ++++++++ 22 files changed, 2460 insertions(+), 27 deletions(-) create mode 100644 .github/log_poller_on_demand.yml create mode 100644 integration-tests/contracts/test_contracts.go create mode 100644 integration-tests/load/log_poller/config.toml create mode 100644 integration-tests/load/log_poller/log_poller_test.go create mode 100644 integration-tests/reorg/log_poller_maybe_reorg_test.go create mode 100644 integration-tests/smoke/log_poller_test.go create mode 100644 integration-tests/universal/log_poller/config.go create mode 100644 integration-tests/universal/log_poller/gun.go create mode 100644 integration-tests/universal/log_poller/helpers.go create mode 100644 integration-tests/universal/log_poller/scenarios.go diff --git a/.github/log_poller_on_demand.yml b/.github/log_poller_on_demand.yml new file mode 100644 index 0000000000..856d1e0234 --- /dev/null +++ b/.github/log_poller_on_demand.yml @@ -0,0 +1,66 @@ +name: On Demand Log Poller Consistency Test +on: + workflow_dispatch: + inputs: + contracts: + description: Number of test contracts + default: "2" + required: true + eventsPerTx: + description: Number of events to emit per transaction + default: "10" + required: true + useFinalityTag: + description: Use finality tag + default: "false" + required: true + loadDuration: + description: Load duration (e.g. 10s, 10m, 1h) + default: "10m" + required: true + chainlinkImage: + description: Chainlink image to use + default: "public.ecr.aws/chainlink/chainlink" + required: true + chainlinkVersion: + description: Chainlink version to use + default: "v2.7.0-beta0" + required: true + selectedNetworks: + description: Network to use (only Sepolia or Mumbai) + default: "Sepolia" + required: true + fundingKey: + description: Private key used to fund the contracts + required: true + rpcURL: + description: RPC URL to use + required: true + wsURL: + description: WS URL to use + required: true + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version-file: "integration-tests/go.mod" + cache: true + - name: Show overrides + env: + CONTRACTS: ${{ inputs.contracts }} + EVENTS_PER_TX: ${{ inputs.eventsPerTx }} + LOAD_DURATION: ${{ inputs.loadDuration }} + USE_FINALITY_TAG: ${{ inputs.useFinalityTag }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} + EVM_KEYS: ${{ inputs.fundingKey }} + EVM_HTTP_URLS: ${{ inputs.rpcURL }} + EVM_URLS: ${{ inputs.wsURL }} + run: | + go test -v -timeout 5h -run=TestLogPollerFromEnv integration-tests/reorg/log_poller_maybe_reorg_test.go \ No newline at end of file diff --git a/.gitignore b/.gitignore index bfd66e2a39..61ebfab0e9 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,7 @@ tests-*.xml tmp-manifest-*.yaml ztarrepo.tar.gz **/test-ledger/* -__debug_bin +__debug_bin* # goreleaser builds cosign.* @@ -82,3 +82,4 @@ contracts/yarn.lock # Ignore DevSpace cache and log folder .devspace/ +go.work* \ No newline at end of file diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 4cd2804d9f..01d6a2aad4 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -466,6 +466,7 @@ func (lp *logPoller) run() { // Serially process replay requests. lp.lggr.Infow("Executing replay", "fromBlock", fromBlock, "requested", fromBlockReq) lp.PollAndSaveLogs(lp.ctx, fromBlock) + lp.lggr.Infow("Executing replay finished", "fromBlock", fromBlock, "requested", fromBlockReq) } } else { lp.lggr.Errorw("Error executing replay, could not get fromBlock", "err", err) @@ -574,13 +575,14 @@ func (lp *logPoller) BackupPollAndSaveLogs(ctx context.Context, backupPollerBloc lastSafeBackfillBlock := latestFinalizedBlockNumber - 1 if lastSafeBackfillBlock >= lp.backupPollerNextBlock { - lp.lggr.Infow("Backup poller backfilling logs", "start", lp.backupPollerNextBlock, "end", lastSafeBackfillBlock) + lp.lggr.Infow("Backup poller started backfilling logs", "start", lp.backupPollerNextBlock, "end", lastSafeBackfillBlock) if err = lp.backfill(ctx, lp.backupPollerNextBlock, lastSafeBackfillBlock); err != nil { // If there's an error backfilling, we can just return and retry from the last block saved // since we don't save any blocks on backfilling. We may re-insert the same logs but thats ok. lp.lggr.Warnw("Backup poller failed", "err", err) return } + lp.lggr.Infow("Backup poller finished backfilling", "start", lp.backupPollerNextBlock, "end", lastSafeBackfillBlock) lp.backupPollerNextBlock = lastSafeBackfillBlock + 1 } } diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 8a79cb3ec9..3638fa11c7 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -1213,3 +1213,23 @@ func (c *ChainlinkClient) GetForwarders() (*Forwarders, *http.Response, error) { } return response, resp.RawResponse, err } + +// Replays log poller from block number +func (c *ChainlinkClient) ReplayLogPollerFromBlock(fromBlock, evmChainID int64) (*ReplayResponse, *http.Response, error) { + specObj := &ReplayResponse{} + c.l.Info().Str(NodeURL, c.Config.URL).Int64("From block", fromBlock).Int64("EVM chain ID", evmChainID).Msg("Replaying Log Poller from block") + resp, err := c.APIClient.R(). + SetResult(&specObj). + SetQueryParams(map[string]string{ + "evmChainID": fmt.Sprint(evmChainID), + }). + SetPathParams(map[string]string{ + "fromBlock": fmt.Sprint(fromBlock), + }). + Post("/v2/replay_from_block/{fromBlock}") + if err != nil { + return nil, nil, err + } + + return specObj, resp.RawResponse, err +} diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index 6013e13e0f..c6d1209d2e 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -9,6 +9,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) // EIServiceConfig represents External Initiator service config @@ -1407,3 +1408,16 @@ type ForwarderAttributes struct { CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } + +type ReplayResponse struct { + Data ReplayResponseData `json:"data"` +} + +type ReplayResponseData struct { + Attributes ReplayResponseAttributes `json:"attributes"` +} + +type ReplayResponseAttributes struct { + Message string `json:"message"` + EVMChainID *utils.Big `json:"evmChainID"` +} diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index e203d8318f..5a3fad256e 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -45,6 +45,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" registry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" + le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_aggregator_proxy" @@ -138,6 +139,7 @@ type ContractDeployer interface { DeployMercuryVerifierProxyContract(accessControllerAddr common.Address) (MercuryVerifierProxy, error) DeployMercuryFeeManager(linkAddress common.Address, nativeAddress common.Address, proxyAddress common.Address, rewardManagerAddress common.Address) (MercuryFeeManager, error) DeployMercuryRewardManager(linkAddress common.Address) (MercuryRewardManager, error) + DeployLogEmitterContract() (LogEmitter, error) } // NewContractDeployer returns an instance of a contract deployer based on the client type @@ -1613,3 +1615,21 @@ func (e *EthereumContractDeployer) DeployWERC20Mock() (WERC20Mock, error) { l: e.l, }, err } + +func (e *EthereumContractDeployer) DeployLogEmitterContract() (LogEmitter, error) { + address, _, instance, err := e.client.DeployContract("Log Emitter", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return le.DeployLogEmitter(auth, backend) + }) + if err != nil { + return nil, err + } + return &LogEmitterContract{ + client: e.client, + instance: instance.(*le.LogEmitter), + address: *address, + l: e.l, + }, err +} diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 51fce7cb12..4c8d610fa1 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -400,3 +400,13 @@ type WERC20Mock interface { Transfer(to string, amount *big.Int) error Mint(account common.Address, amount *big.Int) (*types.Transaction, error) } + +type LogEmitter interface { + Address() common.Address + EmitLogInts(ints []int) (*types.Transaction, error) + EmitLogIntsIndexed(ints []int) (*types.Transaction, error) + EmitLogStrings(strings []string) (*types.Transaction, error) + EmitLogInt(payload int) (*types.Transaction, error) + EmitLogIntIndexed(payload int) (*types.Transaction, error) + EmitLogString(strings string) (*types.Transaction, error) +} diff --git a/integration-tests/contracts/test_contracts.go b/integration-tests/contracts/test_contracts.go new file mode 100644 index 0000000000..ccdd2989e4 --- /dev/null +++ b/integration-tests/contracts/test_contracts.go @@ -0,0 +1,79 @@ +package contracts + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + + le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" +) + +type LogEmitterContract struct { + address common.Address + client blockchain.EVMClient + instance *le.LogEmitter + l zerolog.Logger +} + +func (e *LogEmitterContract) Address() common.Address { + return e.address +} + +func (e *LogEmitterContract) EmitLogInts(ints []int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + bigInts := make([]*big.Int, len(ints)) + for i, v := range ints { + bigInts[i] = big.NewInt(int64(v)) + } + tx, err := e.instance.EmitLog1(opts, bigInts) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +func (e *LogEmitterContract) EmitLogIntsIndexed(ints []int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + bigInts := make([]*big.Int, len(ints)) + for i, v := range ints { + bigInts[i] = big.NewInt(int64(v)) + } + tx, err := e.instance.EmitLog2(opts, bigInts) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +func (e *LogEmitterContract) EmitLogStrings(strings []string) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := e.instance.EmitLog3(opts, strings) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +func (e *LogEmitterContract) EmitLogInt(payload int) (*types.Transaction, error) { + return e.EmitLogInts([]int{payload}) +} + +func (e *LogEmitterContract) EmitLogIntIndexed(payload int) (*types.Transaction, error) { + return e.EmitLogIntsIndexed([]int{payload}) +} + +func (e *LogEmitterContract) EmitLogString(strings string) (*types.Transaction, error) { + return e.EmitLogStrings([]string{strings}) +} diff --git a/integration-tests/docker/cmd/test_env.go b/integration-tests/docker/cmd/test_env.go index 31b7de5dcd..f760f45f8d 100644 --- a/integration-tests/docker/cmd/test_env.go +++ b/integration-tests/docker/cmd/test_env.go @@ -50,6 +50,7 @@ func main() { return nil }, } + startEnvCmd.AddCommand(startFullEnvCmd) // Set default log level for non-testcontainer code diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 40ed0d4d53..e067e46090 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -166,6 +166,7 @@ func (te *CLClusterTestEnv) FundChainlinkNodes(amount *big.Float) error { if err := cl.Fund(te.EVMClient, amount); err != nil { return errors.Wrap(err, ErrFundCLNode) } + time.Sleep(5 * time.Second) } return te.EVMClient.WaitForEvents() } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index d155024050..c07ea76262 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" ) type CleanUpType string @@ -30,22 +31,24 @@ const ( ) type CLTestEnvBuilder struct { - hasLogWatch bool - hasGeth bool - hasKillgrave bool - hasForwarders bool - clNodeConfig *chainlink.Config - secretsConfig string - nonDevGethNetworks []blockchain.EVMNetwork - clNodesCount int - customNodeCsaKeys []string - defaultNodeCsaKeys []string - l zerolog.Logger - t *testing.T - te *CLClusterTestEnv - isNonEVM bool - cleanUpType CleanUpType - cleanUpCustomFn func() + hasLogWatch bool + hasGeth bool + hasKillgrave bool + hasForwarders bool + clNodeConfig *chainlink.Config + secretsConfig string + nonDevGethNetworks []blockchain.EVMNetwork + clNodesCount int + customNodeCsaKeys []string + defaultNodeCsaKeys []string + l zerolog.Logger + t *testing.T + te *CLClusterTestEnv + isNonEVM bool + cleanUpType CleanUpType + cleanUpCustomFn func() + chainOptionsFn []ChainOption + evmClientNetworkOption []EVMClientNetworkOption /* funding */ ETHFunds *big.Float @@ -162,6 +165,24 @@ func (b *CLTestEnvBuilder) WithCustomCleanup(customFn func()) *CLTestEnvBuilder return b } +type ChainOption = func(*evmcfg.Chain) *evmcfg.Chain + +func (b *CLTestEnvBuilder) WithChainOptions(opts ...ChainOption) *CLTestEnvBuilder { + b.chainOptionsFn = make([]ChainOption, 0, 0) + b.chainOptionsFn = append(b.chainOptionsFn, opts...) + + return b +} + +type EVMClientNetworkOption = func(*blockchain.EVMNetwork) *blockchain.EVMNetwork + +func (b *CLTestEnvBuilder) EVMClientNetworkOptions(opts ...EVMClientNetworkOption) *CLTestEnvBuilder { + b.evmClientNetworkOption = make([]EVMClientNetworkOption, 0, 0) + b.evmClientNetworkOption = append(b.evmClientNetworkOption, opts...) + + return b +} + func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { if b.te == nil { var err error @@ -245,10 +266,14 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { if err != nil { return nil, err } - } if !b.isNonEVM { + if b.evmClientNetworkOption != nil && len(b.evmClientNetworkOption) > 0 { + for _, fn := range b.evmClientNetworkOption { + fn(&networkConfig) + } + } bc, err := blockchain.NewEVMClientFromNetwork(networkConfig, b.l) if err != nil { return nil, err @@ -294,6 +319,14 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } node.SetChainConfig(cfg, wsUrls, httpUrls, networkConfig, b.hasForwarders) + + if b.chainOptionsFn != nil && len(b.chainOptionsFn) > 0 { + for _, fn := range b.chainOptionsFn { + for _, evmCfg := range cfg.EVM { + fn(&evmCfg.Chain) + } + } + } } err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 33beae119a..127980a2cb 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -6,6 +6,7 @@ go 1.21 replace github.com/smartcontractkit/chainlink/v2 => ../ require ( + cosmossdk.io/errors v1.0.0 github.com/K-Phoen/grabana v0.21.17 github.com/cli/go-gh/v2 v2.0.0 github.com/ethereum/go-ethereum v1.12.0 @@ -18,13 +19,15 @@ require ( github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.30.0 + github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.2 + github.com/smartcontractkit/chainlink-testing-framework v1.18.2-0.20231030212542-5fb562e774a5 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 + github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.3.0 github.com/spf13/cobra v1.6.1 @@ -49,7 +52,6 @@ require ( cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.3 // indirect - cosmossdk.io/errors v1.0.0 // indirect cosmossdk.io/math v1.0.1 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.0.0 // indirect @@ -375,7 +377,6 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday v1.6.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sercand/kuberesolver v2.4.0+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -387,7 +388,6 @@ require ( github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 // 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/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 7969e82144..24da946717 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2368,8 +2368,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.2 h1:Ac/wdRDF4L479wpFT3yqn6ujb6kFTn7aq8gj9giyFHM= -github.com/smartcontractkit/chainlink-testing-framework v1.18.2/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.2-0.20231030212542-5fb562e774a5 h1:4hTf8pvtdtwoaeKFSEYjBZPvDbZ05WgiHsb0TPL6HqQ= +github.com/smartcontractkit/chainlink-testing-framework v1.18.2-0.20231030212542-5fb562e774a5/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/load/log_poller/config.toml b/integration-tests/load/log_poller/config.toml new file mode 100644 index 0000000000..2e32800194 --- /dev/null +++ b/integration-tests/load/log_poller/config.toml @@ -0,0 +1,22 @@ +[general] +generator = "looped" +contracts = 10 +events_per_tx = 10 + +[chaos] +experiment_count = 10 + +[looped] +[looped.contract] +execution_count = 300 + +[looped.fuzz] +min_emit_wait_time_ms = 100 +max_emit_wait_time_ms = 500 + +[wasp] +[wasp.load] +call_timeout = "3m" +rate_limit_unit_duration = "2s" +LPS = 30 +duration = "1m" \ No newline at end of file diff --git a/integration-tests/load/log_poller/log_poller_test.go b/integration-tests/load/log_poller/log_poller_test.go new file mode 100644 index 0000000000..ec67815832 --- /dev/null +++ b/integration-tests/load/log_poller/log_poller_test.go @@ -0,0 +1,24 @@ +package logpoller + +import ( + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + + lp_helpers "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" + "github.com/stretchr/testify/require" +) + +func TestLoadTestLogPoller(t *testing.T) { + cfg, err := lp_helpers.ReadConfig(lp_helpers.DefaultConfigFilename) + require.NoError(t, err) + + eventsToEmit := []abi.Event{} + for _, event := range lp_helpers.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + + lp_helpers.ExecuteBasicLogPollerTest(t, cfg) +} diff --git a/integration-tests/reorg/log_poller_maybe_reorg_test.go b/integration-tests/reorg/log_poller_maybe_reorg_test.go new file mode 100644 index 0000000000..4e802bdb09 --- /dev/null +++ b/integration-tests/reorg/log_poller_maybe_reorg_test.go @@ -0,0 +1,42 @@ +package reorg + +import ( + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" +) + +func TestLogPollerFromEnv(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 100, + UseFinalityTag: true, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 800, + MaxEmitWaitTimeMs: 1200, + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + err := cfg.OverrideFromEnv() + if err != nil { + t.Errorf("failed to override config from env: %v", err) + t.FailNow() + } + + logpoller.ExecuteCILogPollerTest(t, &cfg) +} diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 17373e6a95..9e35b24df1 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -11,9 +11,8 @@ import ( "testing" "time" - "github.com/kelseyhightower/envconfig" - "github.com/ethereum/go-ethereum/common" + "github.com/kelseyhightower/envconfig" "github.com/onsi/gomega" "github.com/stretchr/testify/require" diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go new file mode 100644 index 0000000000..0df7817f1e --- /dev/null +++ b/integration-tests/smoke/log_poller_test.go @@ -0,0 +1,140 @@ +package smoke + +import ( + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" +) + +// consistency test with no network disruptions with approximate emission of 1500-1600 logs per second for ~110-120 seconds +// 6 filters are registered +func TestLogPollerFewFilters(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 4, + UseFinalityTag: false, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + + logpoller.ExecuteBasicLogPollerTest(t, &cfg) +} + +// consistency test with no network disruptions with approximate emission of 1000-1100 logs per second for ~110-120 seconds +// 900 filters are registered +func TestLogManyFiltersPoller(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 300, + EventsPerTx: 3, + UseFinalityTag: false, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 30, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + + logpoller.ExecuteBasicLogPollerTest(t, &cfg) +} + +// consistency test that introduces random distruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds +// with approximate emission of 520-550 logs per second for ~110 seconds +// 6 filters are registered +func TestLogPollerWithChaos(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 100, + UseFinalityTag: false, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + ChaosConfig: &logpoller.ChaosConfig{ + ExperimentCount: 10, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + + logpoller.ExecuteBasicLogPollerTest(t, &cfg) +} + +// consistency test that registers filters after events were emitted and then triggers replay via API +// unfortunately there is no way to make sure that logs that are indexed are only picked up by replay +// and not by backup poller +// with approximate emission of 24 logs per second for ~110 seconds +// 6 filters are registered +func TestLogPollerReplay(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 4, + UseFinalityTag: false, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + consistencyTimeout := "5m" + + logpoller.ExecuteLogPollerReplay(t, &cfg, consistencyTimeout) +} diff --git a/integration-tests/universal/log_poller/config.go b/integration-tests/universal/log_poller/config.go new file mode 100644 index 0000000000..623fa6606e --- /dev/null +++ b/integration-tests/universal/log_poller/config.go @@ -0,0 +1,247 @@ +package logpoller + +import ( + "fmt" + "os" + "strconv" + + "cosmossdk.io/errors" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/pelletier/go-toml/v2" + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/v2/core/store/models" +) + +const ( + DefaultConfigFilename = "config.toml" + + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" +) + +type GeneratorType = string + +const ( + GeneratorType_WASP = "wasp" + GeneratorType_Looped = "looped" +) + +type Config struct { + General *General `toml:"general"` + ChaosConfig *ChaosConfig `toml:"chaos"` + Wasp *WaspConfig `toml:"wasp"` + LoopedConfig *LoopedConfig `toml:"looped"` +} + +type LoopedConfig struct { + ContractConfig `toml:"contract"` + FuzzConfig `toml:"fuzz"` +} + +type ContractConfig struct { + ExecutionCount int `toml:"execution_count"` +} + +type FuzzConfig struct { + MinEmitWaitTimeMs int `toml:"min_emit_wait_time_ms"` + MaxEmitWaitTimeMs int `toml:"max_emit_wait_time_ms"` +} + +type General struct { + Generator string `toml:"generator"` + EventsToEmit []abi.Event `toml:"-"` + Contracts int `toml:"contracts"` + EventsPerTx int `toml:"events_per_tx"` + UseFinalityTag bool `toml:"use_finality_tag"` +} + +type ChaosConfig struct { + ExperimentCount int `toml:"experiment_count"` +} + +type WaspConfig struct { + Load *Load `toml:"load"` +} + +type Load struct { + RPS int64 `toml:"rps"` + LPS int64 `toml:"lps"` + RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` + Duration *models.Duration `toml:"duration"` + CallTimeout *models.Duration `toml:"call_timeout"` +} + +func ReadConfig(configName string) (*Config, error) { + var cfg *Config + d, err := os.ReadFile(configName) + if err != nil { + return nil, errors.Wrap(err, ErrReadPerfConfig) + } + err = toml.Unmarshal(d, &cfg) + if err != nil { + return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) + } + + if err := cfg.validate(); err != nil { + return nil, err + } + + log.Debug().Interface("Config", cfg).Msg("Parsed config") + return cfg, nil +} + +func (c *Config) OverrideFromEnv() error { + if contr := os.Getenv("CONTRACTS"); contr != "" { + c.General.Contracts = mustParseInt(contr) + } + + if eventsPerTx := os.Getenv("EVENTS_PER_TX"); eventsPerTx != "" { + c.General.EventsPerTx = mustParseInt(eventsPerTx) + } + + if useFinalityTag := os.Getenv("USE_FINALITY_TAG"); useFinalityTag != "" { + c.General.UseFinalityTag = mustParseBool(useFinalityTag) + } + + if duration := os.Getenv("LOAD_DURATION"); duration != "" { + d, err := models.ParseDuration(duration) + if err != nil { + return err + } + + if c.General.Generator == GeneratorType_WASP { + c.Wasp.Load.Duration = &d + } else { + // make the looped generator approximately run for desired duration + // on average we will emit 1 event per second + c.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs = 900 + c.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs = 1100 + c.LoopedConfig.ContractConfig.ExecutionCount = int(d.Duration().Seconds()) + } + } + + return nil +} + +func (c *Config) validate() error { + if c.General == nil { + return fmt.Errorf("General config is nil") + } + + err := c.General.validate() + if err != nil { + return fmt.Errorf("General config validation failed: %v", err) + } + + switch c.General.Generator { + case GeneratorType_WASP: + if c.Wasp == nil { + return fmt.Errorf("Wasp config is nil") + } + if c.Wasp.Load == nil { + return fmt.Errorf("Wasp load config is nil") + } + + err = c.Wasp.validate() + if err != nil { + return fmt.Errorf("Wasp config validation failed: %v", err) + } + case GeneratorType_Looped: + if c.LoopedConfig == nil { + return fmt.Errorf("Looped config is nil") + } + + err = c.LoopedConfig.validate() + if err != nil { + return fmt.Errorf("Looped config validation failed: %v", err) + } + default: + return fmt.Errorf("Unknown generator type: %s", c.General.Generator) + } + + return nil +} + +func (g *General) validate() error { + if g.Generator == "" { + return fmt.Errorf("Generator is empty") + } + + if g.Contracts == 0 { + return fmt.Errorf("Contracts is 0, but must be > 0") + } + + if g.EventsPerTx == 0 { + return fmt.Errorf("Events_per_tx is 0, but must be > 0") + } + + return nil +} + +func (w *WaspConfig) validate() error { + if w.Load == nil { + return fmt.Errorf("Load config is nil") + } + + err := w.Load.validate() + if err != nil { + return fmt.Errorf("Load config validation failed: %v", err) + } + + return nil +} + +func (l *Load) validate() error { + if l.RPS == 0 && l.LPS == 0 { + return fmt.Errorf("Either RPS or LPS needs to be set") + } + + if l.RPS != 0 && l.LPS != 0 { + return fmt.Errorf("Only one of RPS or LPS can be set") + } + + if l.Duration == nil { + return fmt.Errorf("duration is nil") + } + + if l.CallTimeout == nil { + return fmt.Errorf("call_timeout is nil") + } + if l.RateLimitUnitDuration == nil { + return fmt.Errorf("rate_limit_unit_duration is nil") + } + + return nil +} + +func (l *LoopedConfig) validate() error { + if l.ExecutionCount == 0 { + return fmt.Errorf("execution_count is 0, but must be > 0") + } + + if l.MinEmitWaitTimeMs == 0 { + return fmt.Errorf("min_emit_wait_time_ms is 0, but must be > 0") + } + + if l.MaxEmitWaitTimeMs == 0 { + return fmt.Errorf("max_emit_wait_time_ms is 0, but must be > 0") + } + + return nil +} + +func mustParseInt(s string) int { + i, err := strconv.Atoi(s) + if err != nil { + panic(err) + } + return i +} + +func mustParseBool(s string) bool { + b, err := strconv.ParseBool(s) + if err != nil { + panic(err) + } + return b +} diff --git a/integration-tests/universal/log_poller/gun.go b/integration-tests/universal/log_poller/gun.go new file mode 100644 index 0000000000..11932330a3 --- /dev/null +++ b/integration-tests/universal/log_poller/gun.go @@ -0,0 +1,78 @@ +package logpoller + +import ( + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/rs/zerolog" + + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/wasp" +) + +/* LogEmitterGun is a gun that constantly emits logs from a contract */ +type LogEmitterGun struct { + contract *contracts.LogEmitter + eventsToEmit []abi.Event + logger zerolog.Logger + eventsPerTx int +} + +type Counter struct { + mu *sync.Mutex + value int +} + +func NewLogEmitterGun( + contract *contracts.LogEmitter, + eventsToEmit []abi.Event, + eventsPerTx int, + logger zerolog.Logger, +) *LogEmitterGun { + return &LogEmitterGun{ + contract: contract, + eventsToEmit: eventsToEmit, + eventsPerTx: eventsPerTx, + logger: logger, + } +} + +func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { + localCounter := 0 + logEmitter := (*m.contract) + address := logEmitter.Address() + for _, event := range m.eventsToEmit { + m.logger.Debug().Str("Emitter address", address.String()).Str("Event type", event.Name).Msg("Emitting log from emitter") + var err error + switch event.Name { + case "Log1": + _, err = logEmitter.EmitLogInts(getIntSlice(m.eventsPerTx)) + case "Log2": + _, err = logEmitter.EmitLogIntsIndexed(getIntSlice(m.eventsPerTx)) + case "Log3": + _, err = logEmitter.EmitLogStrings(getStringSlice(m.eventsPerTx)) + default: + err = fmt.Errorf("Unknown event name: %s", event.Name) + } + + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + localCounter += 1 + } + + // I don't think that will work as expected, I should atomically read the value and save it, so maybe just a mutex? + if counter, ok := l.InputSharedData().(*Counter); ok { + counter.mu.Lock() + defer counter.mu.Unlock() + counter.value += localCounter + } else { + return &wasp.CallResult{ + Error: "SharedData did not contain a Counter", + Failed: true, + } + } + + return &wasp.CallResult{} +} diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go new file mode 100644 index 0000000000..aa488eb1be --- /dev/null +++ b/integration-tests/universal/log_poller/helpers.go @@ -0,0 +1,1136 @@ +package logpoller + +import ( + "bytes" + "context" + "errors" + "fmt" + "math/big" + "math/rand" + "sort" + "strings" + "sync" + "testing" + "time" + + geth "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + geth_types "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_blockchain "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/store/models" + + ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/stretchr/testify/require" + + "github.com/scylladb/go-reflectx" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" + utils2 "github.com/smartcontractkit/chainlink/integration-tests/utils" + evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + lpEvm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/sqlx" +) + +var ( + EmitterABI, _ = abi.JSON(strings.NewReader(le.LogEmitterABI)) + automationUtilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) + bytes0 = [32]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + } // bytes representation of 0x0000000000000000000000000000000000000000000000000000000000000000 + +) + +var registerSingleTopicFilter = func(registry contracts.KeeperRegistry, upkeepID *big.Int, emitterAddress common.Address, topic common.Hash) error { + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: emitterAddress, + FilterSelector: 0, + Topic0: topic, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := automationUtilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return err + } + + err = registry.SetUpkeepTriggerConfig(upkeepID, encodedLogTriggerConfig) + if err != nil { + return err + } + + return nil +} + +// this is not really possible, log trigger doesn't support multiple topics, even if log poller does +var registerMultipleTopicsFilter = func(registry contracts.KeeperRegistry, upkeepID *big.Int, emitterAddress common.Address, topics []abi.Event) error { + if len(topics) > 4 { + return errors.New("Cannot register more than 4 topics") + } + + var getTopic = func(topics []abi.Event, i int) common.Hash { + if i > len(topics)-1 { + return bytes0 + } + + return topics[i].ID + } + + var getFilterSelector = func(topics []abi.Event) (uint8, error) { + switch len(topics) { + case 0: + return 0, errors.New("Cannot register filter with 0 topics") + case 1: + return 0, nil + case 2: + return 1, nil + case 3: + return 3, nil + case 4: + return 7, nil + default: + return 0, errors.New("Cannot register filter with more than 4 topics") + } + } + + filterSelector, err := getFilterSelector(topics) + if err != nil { + return err + } + + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: emitterAddress, + FilterSelector: filterSelector, + Topic0: getTopic(topics, 0), + Topic1: getTopic(topics, 1), + Topic2: getTopic(topics, 2), + Topic3: getTopic(topics, 3), + } + encodedLogTriggerConfig, err := automationUtilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return err + } + + err = registry.SetUpkeepTriggerConfig(upkeepID, encodedLogTriggerConfig) + if err != nil { + return err + } + + return nil +} + +func NewOrm(logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (*lpEvm.DbORM, *sqlx.DB, error) { + dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", "127.0.0.1", postgresDb.ExternalPort, postgresDb.User, postgresDb.Password, postgresDb.DbName) + db, err := sqlx.Open("postgres", dsn) + if err != nil { + return nil, db, err + } + + db.MapperFunc(reflectx.CamelToSnakeASCII) + return lpEvm.NewORM(chainID, db, logger, pg.NewQConfig(false)), db, nil +} + +type ExpectedFilter struct { + emitterAddress common.Address + topic common.Hash +} + +func getExpectedFilters(logEmitters []*contracts.LogEmitter, cfg *Config) []ExpectedFilter { + expectedFilters := make([]ExpectedFilter, 0) + for _, emitter := range logEmitters { + for _, event := range cfg.General.EventsToEmit { + expectedFilters = append(expectedFilters, ExpectedFilter{ + emitterAddress: (*emitter).Address(), + topic: event.ID, + }) + } + } + + return expectedFilters +} + +var nodeHasExpectedFilters = func(expectedFilters []ExpectedFilter, logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (bool, error) { + orm, db, err := NewOrm(logger, chainID, postgresDb) + if err != nil { + return false, err + } + + defer db.Close() + knownFilters, err := orm.LoadFilters() + if err != nil { + return false, err + } + + for _, expectedFilter := range expectedFilters { + filterFound := false + for _, knownFilter := range knownFilters { + if bytes.Equal(expectedFilter.emitterAddress.Bytes(), knownFilter.Addresses[0].Bytes()) && bytes.Equal(expectedFilter.topic.Bytes(), knownFilter.EventSigs[0].Bytes()) { + filterFound = true + break + } + } + + if !filterFound { + return false, fmt.Errorf("No filter found for emitter %s and topic %s", expectedFilter.emitterAddress.String(), expectedFilter.topic.Hex()) + } + } + + return true, nil +} + +var randomWait = func(minMilliseconds, maxMilliseconds int) { + rand.New(rand.NewSource(time.Now().UnixNano())) + randomMilliseconds := rand.Intn(maxMilliseconds-minMilliseconds+1) + minMilliseconds + time.Sleep(time.Duration(randomMilliseconds) * time.Millisecond) +} + +type LogEmitterChannel struct { + logsEmitted int + err error + currentIndex int +} + +func getIntSlice(length int) []int { + result := make([]int, length) + for i := 0; i < length; i++ { + result[i] = i + } + + return result +} + +func getStringSlice(length int) []string { + result := make([]string, length) + for i := 0; i < length; i++ { + result[i] = "amazing event" + } + + return result +} + +var emitEvents = func(ctx context.Context, l zerolog.Logger, logEmitter *contracts.LogEmitter, cfg *Config, wg *sync.WaitGroup, results chan LogEmitterChannel) { + address := (*logEmitter).Address().String() + localCounter := 0 + select { + case <-ctx.Done(): + l.Warn().Str("Emitter address", address).Msg("Context cancelled, not emitting events") + return + default: + defer wg.Done() + for i := 0; i < cfg.LoopedConfig.ExecutionCount; i++ { + for _, event := range cfg.General.EventsToEmit { + l.Debug().Str("Emitter address", address).Str("Event type", event.Name).Str("index", fmt.Sprintf("%d/%d", (i+1), cfg.LoopedConfig.ExecutionCount)).Msg("Emitting log from emitter") + var err error + switch event.Name { + case "Log1": + _, err = (*logEmitter).EmitLogInts(getIntSlice(cfg.General.EventsPerTx)) + case "Log2": + _, err = (*logEmitter).EmitLogIntsIndexed(getIntSlice(cfg.General.EventsPerTx)) + case "Log3": + _, err = (*logEmitter).EmitLogStrings(getStringSlice(cfg.General.EventsPerTx)) + default: + err = fmt.Errorf("Unknown event name: %s", event.Name) + } + + if err != nil { + results <- LogEmitterChannel{ + logsEmitted: 0, + err: err, + } + return + } + localCounter += cfg.General.EventsPerTx + + randomWait(cfg.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs, cfg.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs) + } + + if (i+1)%10 == 0 { + l.Info().Str("Emitter address", address).Str("Index", fmt.Sprintf("%d/%d", i+1, cfg.LoopedConfig.ExecutionCount)).Msg("Emitted all three events") + } + } + + l.Info().Str("Emitter address", address).Int("Total logs emitted", localCounter).Msg("Finished emitting events") + + results <- LogEmitterChannel{ + logsEmitted: localCounter, + err: nil, + } + } +} + +var waitForEndBlockInLogPoller = func(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { + for i := 1; i < len(nodes.Nodes); i++ { + clNode := nodes.Nodes[i] + orm, db, err := NewOrm(coreLogger, chainID, clNode.PostgresDb) + if err != nil { + return false, err + } + + defer db.Close() + block, err := orm.SelectBlockByNumber(endBlock) + if err != nil { + return false, err + } + + if block == nil { + return false, nil + } + } + + return true, nil +} + +var chainHasFinalisedEndBlock = func(l zerolog.Logger, evmClient ctf_blockchain.EVMClient, endBlock int64) (bool, error) { + effectiveEndBlock := endBlock + 1 + lastFinalisedBlockHeader, err := evmClient.GetLatestFinalizedBlockHeader(context.Background()) + if err != nil { + return false, err + } + + l.Info().Int64("Last finalised block header", lastFinalisedBlockHeader.Number.Int64()).Int64("End block", effectiveEndBlock).Int64("Blocks left till end block", effectiveEndBlock-lastFinalisedBlockHeader.Number.Int64()).Msg("Waiting for the finalized block to move beyond end block") + + return lastFinalisedBlockHeader.Number.Int64() > effectiveEndBlock, nil +} + +var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { + wg := &sync.WaitGroup{} + + type boolQueryResult struct { + nodeName string + hasFinalised bool + err error + } + + endBlockCh := make(chan boolQueryResult, len(nodes.Nodes)-1) + ctx, cancelFn := context.WithCancel(context.Background()) + + for i := 1; i < len(nodes.Nodes); i++ { + wg.Add(1) + + go func(clNode *test_env.ClNode, r chan boolQueryResult) { + defer wg.Done() + select { + case <-ctx.Done(): + return + default: + orm, db, err := NewOrm(coreLogger, chainID, clNode.PostgresDb) + if err != nil { + r <- boolQueryResult{ + nodeName: clNode.ContainerName, + hasFinalised: false, + err: err, + } + } + + defer db.Close() + + latestBlock, err := orm.SelectLatestBlock() + if err != nil { + r <- boolQueryResult{ + nodeName: clNode.ContainerName, + hasFinalised: false, + err: err, + } + } + + r <- boolQueryResult{ + nodeName: clNode.ContainerName, + hasFinalised: latestBlock.FinalizedBlockNumber > endBlock, + err: nil, + } + + } + }(nodes.Nodes[i], endBlockCh) + } + + var err error + allFinalisedCh := make(chan bool, 1) + + go func() { + foundMap := make(map[string]bool, 0) + for r := range endBlockCh { + if r.err != nil { + err = r.err + cancelFn() + return + } + + foundMap[r.nodeName] = r.hasFinalised + if r.hasFinalised { + l.Info().Str("Node name", r.nodeName).Msg("CL node has finalised end block") + } else { + l.Warn().Str("Node name", r.nodeName).Msg("CL node has not finalised end block yet") + } + + if len(foundMap) == len(nodes.Nodes)-1 { + allFinalised := true + for _, v := range foundMap { + if !v { + allFinalised = false + break + } + } + + allFinalisedCh <- allFinalised + return + } + } + }() + + wg.Wait() + close(endBlockCh) + + return <-allFinalisedCh, err +} + +var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big.Int, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { + wg := &sync.WaitGroup{} + + type logQueryResult struct { + nodeName string + logCount int + hasExpectedCount bool + err error + } + + queryCh := make(chan logQueryResult, len(nodes.Nodes)-1) + ctx, cancelFn := context.WithCancel(context.Background()) + + for i := 1; i < len(nodes.Nodes); i++ { + wg.Add(1) + + go func(clNode *test_env.ClNode, r chan logQueryResult) { + defer wg.Done() + select { + case <-ctx.Done(): + return + default: + orm, db, err := NewOrm(coreLogger, chainID, clNode.PostgresDb) + if err != nil { + r <- logQueryResult{ + nodeName: clNode.ContainerName, + logCount: 0, + hasExpectedCount: false, + err: err, + } + } + + defer db.Close() + foundLogsCount := 0 + + for _, filter := range expectedFilters { + logs, err := orm.SelectLogs(startBlock, endBlock, filter.emitterAddress, filter.topic) + if err != nil { + r <- logQueryResult{ + nodeName: clNode.ContainerName, + logCount: 0, + hasExpectedCount: false, + err: err, + } + } + + foundLogsCount += len(logs) + } + + r <- logQueryResult{ + nodeName: clNode.ContainerName, + logCount: foundLogsCount, + hasExpectedCount: foundLogsCount >= expectedLogCount, + err: err, + } + } + }(nodes.Nodes[i], queryCh) + } + + var err error + allFoundCh := make(chan bool, 1) + + go func() { + foundMap := make(map[string]bool, 0) + for r := range queryCh { + if r.err != nil { + err = r.err + cancelFn() + return + } + + foundMap[r.nodeName] = r.hasExpectedCount + if r.hasExpectedCount { + l.Info().Str("Node name", r.nodeName).Int("Logs count", r.logCount).Msg("Expected log count found in CL node") + } else { + l.Warn().Str("Node name", r.nodeName).Str("Found/Expected logs", fmt.Sprintf("%d/%d", r.logCount, expectedLogCount)).Int("Missing logs", expectedLogCount-r.logCount).Msg("Too low log count found in CL node") + } + + if len(foundMap) == len(nodes.Nodes)-1 { + allFound := true + for _, v := range foundMap { + if !v { + allFound = false + break + } + } + + allFoundCh <- allFound + return + } + } + }() + + wg.Wait() + close(queryCh) + + return <-allFoundCh, err +} + +type MissingLogs map[string][]geth_types.Log + +func (m *MissingLogs) IsEmpty() bool { + for _, v := range *m { + if len(v) > 0 { + return false + } + } + + return true +} + +var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient ctf_blockchain.EVMClient, clnodeCluster *test_env.ClCluster, l zerolog.Logger, coreLogger core_logger.SugaredLogger, cfg *Config) (MissingLogs, error) { + wg := &sync.WaitGroup{} + + type dbQueryResult struct { + err error + nodeName string + logs []logpoller.Log + } + + ctx, cancelFn := context.WithCancel(context.Background()) + resultCh := make(chan dbQueryResult, len(clnodeCluster.Nodes)-1) + + for i := 1; i < len(clnodeCluster.Nodes); i++ { + wg.Add(1) + + go func(ctx context.Context, i int, r chan dbQueryResult) { + defer wg.Done() + select { + case <-ctx.Done(): + l.Warn().Msg("Context cancelled. Terminating fetching logs from log poller's DB") + return + default: + nodeName := clnodeCluster.Nodes[i].ContainerName + + l.Info().Str("Node name", nodeName).Msg("Fetching log poller logs") + orm, db, err := NewOrm(coreLogger, evmClient.GetChainID(), clnodeCluster.Nodes[i].PostgresDb) + if err != nil { + r <- dbQueryResult{ + err: err, + nodeName: nodeName, + logs: []logpoller.Log{}, + } + } + + defer db.Close() + logs := make([]logpoller.Log, 0) + + for j := 0; j < len(logEmitters); j++ { + address := (*logEmitters[j]).Address() + + for _, event := range cfg.General.EventsToEmit { + l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Msg("Fetching single emitter's logs") + result, err := orm.SelectLogs(startBlock, endBlock, address, event.ID) + if err != nil { + r <- dbQueryResult{ + err: err, + nodeName: nodeName, + logs: []logpoller.Log{}, + } + } + + sort.Slice(result, func(i, j int) bool { + return result[i].BlockNumber < result[j].BlockNumber + }) + + logs = append(logs, result...) + + l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Int("Log count", len(result)).Msg("Logs found per node") + } + } + + l.Warn().Int("Count", len(logs)).Str("Node name", nodeName).Msg("Fetched log poller logs") + + r <- dbQueryResult{ + err: nil, + nodeName: nodeName, + logs: logs, + } + } + }(ctx, i, resultCh) + } + + allLogPollerLogs := make(map[string][]logpoller.Log, 0) + missingLogs := map[string][]geth_types.Log{} + var dbError error + + go func() { + for r := range resultCh { + if r.err != nil { + l.Err(r.err).Str("Node name", r.nodeName).Msg("Error fetching logs from log poller's DB") + dbError = r.err + cancelFn() + return + } + // use channel for aggregation and then for := range over it after closing resultCh? + allLogPollerLogs[r.nodeName] = r.logs + } + }() + + wg.Wait() + close(resultCh) + + if dbError != nil { + return nil, dbError + } + + allLogsInEVMNode, err := getEVMLogs(startBlock, endBlock, logEmitters, evmClient, l, cfg) + if err != nil { + return nil, err + } + + wg = &sync.WaitGroup{} + + type missingLogResult struct { + nodeName string + logs []geth_types.Log + } + + l.Info().Msg("Started comparison of logs from EVM node and CL nodes. This may take a while if there's a lot of logs") + missingCh := make(chan missingLogResult, len(clnodeCluster.Nodes)-1) + evmLogCount := len(allLogsInEVMNode) + for i := 1; i < len(clnodeCluster.Nodes); i++ { + wg.Add(1) + + go func(i int, result chan missingLogResult) { + defer wg.Done() + nodeName := clnodeCluster.Nodes[i].ContainerName + l.Info().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("0/%d", evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") + + missingLogs := make([]geth_types.Log, 0) + for i, evmLog := range allLogsInEVMNode { + logFound := false + for _, logPollerLog := range allLogPollerLogs[nodeName] { + if logPollerLog.BlockNumber == int64(evmLog.BlockNumber) && logPollerLog.TxHash == evmLog.TxHash && bytes.Equal(logPollerLog.Data, evmLog.Data) && logPollerLog.LogIndex == int64(evmLog.Index) && + logPollerLog.Address == evmLog.Address && logPollerLog.BlockHash == evmLog.BlockHash && bytes.Equal(logPollerLog.Topics[0][:], evmLog.Topics[0].Bytes()) { + logFound = true + continue + } + } + + if i%10000 == 0 && i != 0 { + l.Info().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("%d/%d", i, evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") + } + + if !logFound { + missingLogs = append(missingLogs, evmLog) + } + } + + if len(missingLogs) > 0 { + l.Warn().Int("Count", len(missingLogs)).Str("Node name", nodeName).Msg("Some EMV logs were missing from CL node") + } else { + l.Info().Str("Node name", nodeName).Msg("All EVM logs were found in CL node") + } + + result <- missingLogResult{ + nodeName: nodeName, + logs: missingLogs, + } + }(i, missingCh) + } + + wg.Wait() + close(missingCh) + + for v := range missingCh { + if len(v.logs) > 0 { + missingLogs[v.nodeName] = v.logs + } + } + + expectedTotalLogsEmitted := getExpectedLogCount(cfg) + if int64(len(allLogsInEVMNode)) != expectedTotalLogsEmitted { + l.Warn().Str("Actual/Expected", fmt.Sprintf("%d/%d", expectedTotalLogsEmitted, len(allLogsInEVMNode))).Msg("Some of the test logs were not found in EVM node. This is a bug in the test") + } + + return missingLogs, nil +} + +var printMissingLogsByType = func(missingLogs map[string][]geth_types.Log, l zerolog.Logger, cfg *Config) { + var findHumanName = func(topic common.Hash) string { + for _, event := range cfg.General.EventsToEmit { + if event.ID == topic { + return event.Name + } + } + + return "Unknown event" + } + + missingByType := make(map[string]int) + for _, logs := range missingLogs { + for _, v := range logs { + humanName := findHumanName(v.Topics[0]) + if _, ok := missingByType[humanName]; ok { + missingByType[humanName] += 1 + } else { + missingByType[humanName] = 1 + } + } + } + + for k, v := range missingByType { + l.Warn().Str("Event name", k).Int("Missing count", v).Msg("Missing logs by type") + } +} + +var getEVMLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient ctf_blockchain.EVMClient, l zerolog.Logger, cfg *Config) ([]geth_types.Log, error) { + allLogsInEVMNode := make([]geth_types.Log, 0) + for j := 0; j < len(logEmitters); j++ { + address := (*logEmitters[j]).Address() + for _, event := range cfg.General.EventsToEmit { + l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Msg("Fetching logs from EVM node") + logsInEVMNode, err := evmClient.FilterLogs(context.Background(), geth.FilterQuery{ + Addresses: []common.Address{(address)}, + Topics: [][]common.Hash{{event.ID}}, + FromBlock: big.NewInt(startBlock), + ToBlock: big.NewInt(endBlock), + }) + if err != nil { + return nil, err + } + + sort.Slice(logsInEVMNode, func(i, j int) bool { + return logsInEVMNode[i].BlockNumber < logsInEVMNode[j].BlockNumber + }) + + allLogsInEVMNode = append(allLogsInEVMNode, logsInEVMNode...) + l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Int("Log count", len(logsInEVMNode)).Msg("Logs found in EVM node") + } + } + + l.Warn().Int("Count", len(allLogsInEVMNode)).Msg("Logs in EVM node") + + return allLogsInEVMNode, nil +} + +func executeGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { + if cfg.General.Generator == GeneratorType_WASP { + return runWaspGenerator(t, cfg, logEmitters) + } + + return runLoopedGenerator(t, cfg, logEmitters) +} + +func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { + l := logging.GetTestLogger(t) + + var RPSprime int64 + + // if LPS is set, we need to calculate based on countract count and events per transaction + if cfg.Wasp.Load.LPS > 0 { + RPSprime = cfg.Wasp.Load.LPS / int64(cfg.General.Contracts) / int64(cfg.General.EventsPerTx) / int64(len(cfg.General.EventsToEmit)) + + if RPSprime < 1 { + return 0, fmt.Errorf("Invalid load configuration, effective RPS would have been zero. Adjust LPS, contracts count, events per tx or events to emit") + } + } + + // if RPS is set simply split it between contracts + if cfg.Wasp.Load.RPS > 0 { + RPSprime = cfg.Wasp.Load.RPS / int64(cfg.General.Contracts) + } + + counter := &Counter{ + mu: &sync.Mutex{}, + value: 0, + } + + p := wasp.NewProfile() + + for _, logEmitter := range logEmitters { + g, err := wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: fmt.Sprintf("log_poller_gen_%s", (*logEmitter).Address().String()), + RateLimitUnitDuration: cfg.Wasp.Load.RateLimitUnitDuration.Duration(), + CallTimeout: cfg.Wasp.Load.CallTimeout.Duration(), + Schedule: wasp.Plain( + RPSprime, + cfg.Wasp.Load.Duration.Duration(), + ), + Gun: NewLogEmitterGun( + logEmitter, + cfg.General.EventsToEmit, + cfg.General.EventsPerTx, + l, + ), + SharedData: counter, + }) + p.Add(g, err) + } + + _, err := p.Run(true) + + if err != nil { + return 0, err + } + + return counter.value, nil +} + +func runLoopedGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { + l := logging.GetTestLogger(t) + + // Start emitting events in parallel, each contract is emitting events in a separate goroutine + // We will stop as soon as we encounter an error + wg := &sync.WaitGroup{} + emitterCh := make(chan LogEmitterChannel, len(logEmitters)) + + ctx, cancelFn := context.WithCancel(context.Background()) + defer cancelFn() + + for i := 0; i < len(logEmitters); i++ { + wg.Add(1) + go emitEvents(ctx, l, logEmitters[i], cfg, wg, emitterCh) + } + + var emitErr error + total := 0 + + aggrChan := make(chan int, len(logEmitters)) + + go func() { + for emitter := range emitterCh { + if emitter.err != nil { + emitErr = emitter.err + cancelFn() + return + } + aggrChan <- emitter.logsEmitted + } + }() + + wg.Wait() + close(emitterCh) + + for i := 0; i < len(logEmitters); i++ { + total += <-aggrChan + } + + if emitErr != nil { + return 0, emitErr + } + + return int(total), nil +} + +func getExpectedLogCount(cfg *Config) int64 { + if cfg.General.Generator == GeneratorType_WASP { + if cfg.Wasp.Load.RPS != 0 { + return cfg.Wasp.Load.RPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) * int64(cfg.General.EventsPerTx) + } else { + return cfg.Wasp.Load.LPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) + } + } + + return int64(len(cfg.General.EventsToEmit) * cfg.LoopedConfig.ExecutionCount * cfg.General.Contracts * cfg.General.EventsPerTx) +} + +var chaosPauseSyncFn = func(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv) error { + rand.New(rand.NewSource(time.Now().UnixNano())) + randomBool := rand.Intn(2) == 0 + + randomNode := testEnv.ClCluster.Nodes[rand.Intn(len(testEnv.ClCluster.Nodes)-1)+1] + var component ctf_test_env.EnvComponent + + if randomBool { + component = randomNode.EnvComponent + } else { + component = randomNode.PostgresDb.EnvComponent + } + + pauseTimeSec := rand.Intn(20-5) + 5 + l.Info().Str("Container", component.ContainerName).Int("Pause time", pauseTimeSec).Msg("Pausing component") + pauseTimeDur := time.Duration(pauseTimeSec) * time.Second + err := component.ChaosPause(l, pauseTimeDur) + l.Info().Str("Container", component.ContainerName).Msg("Component unpaused") + + if err != nil { + return err + } + + return nil +} + +var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, cfg *Config, errorCh chan error) { + if cfg.ChaosConfig == nil || cfg.ChaosConfig.ExperimentCount == 0 { + errorCh <- nil + return + } + + chaosChan := make(chan error, cfg.ChaosConfig.ExperimentCount) + + wg := &sync.WaitGroup{} + + go func() { + // if we wanted to have more than 1 container paused, we'd need to make sure we aren't trying to pause an already paused one + guardChan := make(chan struct{}, 1) + + for i := 0; i < cfg.ChaosConfig.ExperimentCount; i++ { + wg.Add(1) + guardChan <- struct{}{} + go func() { + defer func() { + <-guardChan + wg.Done() + l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", i, cfg.ChaosConfig.ExperimentCount)).Msg("Done with experiment") + }() + chaosChan <- chaosPauseSyncFn(l, testEnv) + }() + } + + wg.Wait() + + close(chaosChan) + }() + + go func() { + for { + select { + case err, ok := <-chaosChan: + if !ok { + l.Info().Msg("All chaos experiments finished") + errorCh <- nil + return + } else { + if err != nil { + l.Err(err).Msg("Error encountered during chaos experiment") + errorCh <- err + return + } + } + } + } + }() +} + +var GetFinalityDepth = func(chainId int64) (int64, error) { + var finalityDepth int64 + switch chainId { + // Ethereum Sepolia + case 11155111: + finalityDepth = 50 + // Polygon Mumbai + case 80001: + finalityDepth = 500 + // Simulated network + case 1337: + finalityDepth = 10 + default: + return 0, fmt.Errorf("No known finality depth for chain %d", chainId) + } + + return finalityDepth, nil +} + +var GetEndBlockToWaitFor = func(endBlock, chainId int64, cfg *Config) (int64, error) { + if cfg.General.UseFinalityTag { + return endBlock + 1, nil + } + + finalityDepth, err := GetFinalityDepth(chainId) + if err != nil { + return 0, err + } + + return endBlock + finalityDepth, nil +} + +const ( + automationDefaultUpkeepGasLimit = uint32(2500000) + automationDefaultLinkFunds = int64(9e18) + automationDefaultUpkeepsToDeploy = 10 + automationExpectedData = "abcdef" + defaultAmountOfUpkeeps = 2 +) + +var ( + defaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ + PaymentPremiumPPB: uint32(200000000), + FlatFeeMicroLINK: uint32(0), + BlockCountPerTurn: big.NewInt(10), + CheckGasLimit: uint32(2500000), + StalenessSeconds: big.NewInt(90000), + GasCeilingMultiplier: uint16(1), + MinUpkeepSpend: big.NewInt(0), + MaxPerformGas: uint32(5000000), + FallbackGasPrice: big.NewInt(2e11), + FallbackLinkPrice: big.NewInt(2e18), + MaxCheckDataSize: uint32(5000), + MaxPerformDataSize: uint32(5000), + } + + automationDefaultRegistryConfig = contracts.KeeperRegistrySettings{ + PaymentPremiumPPB: uint32(200000000), + FlatFeeMicroLINK: uint32(0), + BlockCountPerTurn: big.NewInt(10), + CheckGasLimit: uint32(2500000), + StalenessSeconds: big.NewInt(90000), + GasCeilingMultiplier: uint16(1), + MinUpkeepSpend: big.NewInt(0), + MaxPerformGas: uint32(5000000), + FallbackGasPrice: big.NewInt(2e11), + FallbackLinkPrice: big.NewInt(2e18), + MaxCheckDataSize: uint32(5000), + MaxPerformDataSize: uint32(5000), + } +) + +func setupLogPollerTestDocker( + t *testing.T, + testName string, + registryVersion ethereum.KeeperRegistryVersion, + registryConfig contracts.KeeperRegistrySettings, + upkeepsNeeded int, + lpPollingInterval time.Duration, + finalityTagEnabled bool, +) ( + blockchain.EVMClient, + []*client.ChainlinkClient, + contracts.ContractDeployer, + contracts.LinkToken, + contracts.KeeperRegistry, + contracts.KeeperRegistrar, + *test_env.CLClusterTestEnv, +) { + l := logging.GetTestLogger(t) + // Add registry version to config + registryConfig.RegistryVersion = registryVersion + network := networks.MustGetSelectedNetworksFromEnv()[0] + + finalityDepth, err := GetFinalityDepth(network.ChainID) + require.NoError(t, err, "Error getting finality depth") + + // build the node config + clNodeConfig := node.NewConfig(node.NewBaseConfig()) + syncInterval := models.MustMakeDuration(5 * time.Minute) + clNodeConfig.Feature.LogPoller = it_utils.Ptr[bool](true) + clNodeConfig.OCR2.Enabled = it_utils.Ptr[bool](true) + clNodeConfig.Keeper.TurnLookBack = it_utils.Ptr[int64](int64(0)) + clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval + clNodeConfig.Keeper.Registry.PerformGasOverhead = it_utils.Ptr[uint32](uint32(150000)) + clNodeConfig.P2P.V2.Enabled = it_utils.Ptr[bool](true) + clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} + clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} + + //launch the environment + var env *test_env.CLClusterTestEnv + chainlinkNodeFunding := 0.5 + l.Debug().Msgf("Funding amount: %f", chainlinkNodeFunding) + clNodesCount := 5 + + var logPolllerSettingsFn = func(chain *evmcfg.Chain) *evmcfg.Chain { + chain.LogPollInterval = models.MustNewDuration(lpPollingInterval) + chain.FinalityDepth = utils2.Ptr[uint32](uint32(finalityDepth)) + chain.FinalityTagEnabled = utils2.Ptr[bool](finalityTagEnabled) + return chain + } + + var evmClientSettingsFn = func(network *blockchain.EVMNetwork) *blockchain.EVMNetwork { + network.FinalityDepth = uint64(finalityDepth) + network.FinalityTag = finalityTagEnabled + return network + } + + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithCLNodes(clNodesCount). + WithCLNodeConfig(clNodeConfig). + WithFunding(big.NewFloat(chainlinkNodeFunding)). + WithChainOptions(logPolllerSettingsFn). + EVMClientNetworkOptions(evmClientSettingsFn). + WithStandardCleanup(). + Build() + require.NoError(t, err, "Error deploying test environment") + + env.ParallelTransactions(true) + nodeClients := env.ClCluster.NodeAPIs() + workerNodes := nodeClients[1:] + + var linkToken contracts.LinkToken + + switch network.ChainID { + // Simulated + case 1337: + linkToken, err = env.ContractDeployer.DeployLinkTokenContract() + // Ethereum Sepolia + case 11155111: + linkToken, err = env.ContractLoader.LoadLINKToken("0x779877A7B0D9E8603169DdbD7836e478b4624789") + // Polygon Mumbai + case 80001: + linkToken, err = env.ContractLoader.LoadLINKToken("0x326C977E6efc84E512bB9C30f76E30c160eD06FB") + default: + panic("Not implemented") + } + require.NoError(t, err, "Error loading/deploying LINK token") + + linkBalance, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(linkToken.Address())) + require.NoError(t, err, "Error getting LINK balance") + + l.Info().Str("Balance", big.NewInt(0).Div(linkBalance, big.NewInt(1e18)).String()).Msg("LINK balance") + minLinkBalanceSingleNode := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(9)) + minLinkBalance := big.NewInt(0).Mul(minLinkBalanceSingleNode, big.NewInt(int64(upkeepsNeeded))) + if minLinkBalance.Cmp(linkBalance) < 0 { + require.FailNowf(t, "Not enough LINK", "Not enough LINK to run the test. Need at least %s", big.NewInt(0).Div(minLinkBalance, big.NewInt(1e18)).String()) + } + + registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( + t, + registryVersion, + registryConfig, + linkToken, + env.ContractDeployer, + env.EVMClient, + ) + + // Fund the registry with LINK + err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(defaultAmountOfUpkeeps)))) + require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + + err = actions.CreateOCRKeeperJobsLocal(l, nodeClients, registry.Address(), network.ChainID, 0, registryVersion) + require.NoError(t, err, "Error creating OCR Keeper Jobs") + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, workerNodes, registryConfig, registrar.Address(), 30*time.Second, registry.RegistryOwnerAddress()) + require.NoError(t, err, "Error building OCR config vars") + err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) + require.NoError(t, err, "Registry config should be set successfully") + require.NoError(t, env.EVMClient.WaitForEvents(), "Waiting for config to be set") + + return env.EVMClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env +} diff --git a/integration-tests/universal/log_poller/scenarios.go b/integration-tests/universal/log_poller/scenarios.go new file mode 100644 index 0000000000..d14a3bcb2a --- /dev/null +++ b/integration-tests/universal/log_poller/scenarios.go @@ -0,0 +1,498 @@ +package logpoller + +import ( + "context" + "fmt" + "math/big" + "testing" + "time" + + "github.com/onsi/gomega" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/stretchr/testify/require" +) + +func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { + l := logging.GetTestLogger(t) + coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ + + if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { + l.Warn().Msg("No events to emit specified, using all events from log emitter contract") + for _, event := range EmitterABI.Events { + cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) + } + } + + l.Info().Msg("Starting basic log poller test") + + var ( + err error + testName = "basic-log-poller" + upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) + ) + + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( + t, testName, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(500*time.Millisecond), cfg.General.UseFinalityTag, + ) + + _, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + upKeepsNeeded, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + true, + false, + ) + + // Deploy Log Emitter contracts + logEmitters := make([]*contracts.LogEmitter, 0) + for i := 0; i < cfg.General.Contracts; i++ { + logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() + logEmitters = append(logEmitters, &logEmitter) + require.NoError(t, err, "Error deploying log emitter contract") + l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") + time.Sleep(200 * time.Millisecond) + } + + // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) + // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) + for i := 0; i < len(upkeepIDs); i++ { + emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() + upkeepID := upkeepIDs[i] + topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID + + l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") + err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) + randomWait(50, 200) + require.NoError(t, err, "Error registering log trigger for log emitter") + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + // Make sure that all nodes have expected filters registered before starting to emit events + expectedFilters := getExpectedFilters(logEmitters, cfg) + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") + + hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) + if err != nil { + l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") + return + } + + g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") + } + }, "30s", "1s").Should(gomega.Succeed()) + l.Info().Msg("All nodes have expected filters registered") + l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") + + // Save block number before starting to emit events, so that we can later use it when querying logs + sb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + startBlock := int64(sb) + + l.Info().Msg("STARTING EVENT EMISSION") + startTime := time.Now() + + // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) + chaosDoneCh := make(chan error, 1) + go func() { + executeChaosExperiment(l, testEnv, cfg, chaosDoneCh) + }() + + totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) + endTime := time.Now() + require.NoError(t, err, "Error executing event generator") + + expectedLogsEmitted := getExpectedLogCount(cfg) + duration := int(endTime.Sub(startTime).Seconds()) + l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") + + // Save block number after finishing to emit events, so that we can later use it when querying logs + eb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + + endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) + require.NoError(t, err, "Error getting end block to wait for") + + l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") + chaosError := <-chaosDoneCh + require.NoError(t, chaosError, "Error encountered during chaos experiment") + + // Wait until last block in which events were emitted has been finalised + // how long should we wait here until all logs are processed? wait for block X to be processed by all nodes? + waitDuration := "15m" + l.Warn().Str("Duration", waitDuration).Msg("Waiting for logs to be processed by all nodes and for chain to advance beyond finality") + + gom.Eventually(func(g gomega.Gomega) { + hasAdvanced, err := chainHasFinalisedEndBlock(l, testEnv.EVMClient, endBlock) + if err != nil { + l.Warn().Err(err).Msg("Error checking if chain has advanced beyond finality. Retrying...") + } + g.Expect(hasAdvanced).To(gomega.BeTrue(), "Chain has not advanced beyond finality") + }, waitDuration, "30s").Should(gomega.Succeed()) + + l.Warn().Str("Duration", "1m").Msg("Waiting for all CL nodes to have end block finalised") + gom.Eventually(func(g gomega.Gomega) { + hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") + } + g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") + }, "1m", "30s").Should(gomega.Succeed()) + + gom.Eventually(func(g gomega.Gomega) { + logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if CL nodes have expected log count. Retrying...") + } + g.Expect(logCountMatches).To(gomega.BeTrue(), "Not all CL nodes have expected log count") + }, waitDuration, "5s").Should(gomega.Succeed()) + + // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has + logConsistencyWaitDuration := "1m" + l.Warn().Str("Duration", logConsistencyWaitDuration).Msg("Waiting for CL nodes to have all the logs that EVM node has") + + gom.Eventually(func(g gomega.Gomega) { + missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) + if err != nil { + l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") + } + + if !missingLogs.IsEmpty() { + printMissingLogsByType(missingLogs, l, cfg) + } + g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") + }, logConsistencyWaitDuration, "5s").Should(gomega.Succeed()) +} + +func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string) { + l := logging.GetTestLogger(t) + coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ + + if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { + l.Warn().Msg("No events to emit specified, using all events from log emitter contract") + for _, event := range EmitterABI.Events { + cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) + } + } + + l.Info().Msg("Starting replay log poller test") + + var ( + err error + testName = "replay-log-poller" + upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) + ) + + // we set blockBackfillDepth to 0, to make sure nothing will be backfilled and won't interfere with our test + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( + t, testName, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag) + + _, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + upKeepsNeeded, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + true, + false, + ) + + // Deploy Log Emitter contracts + logEmitters := make([]*contracts.LogEmitter, 0) + for i := 0; i < cfg.General.Contracts; i++ { + logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() + logEmitters = append(logEmitters, &logEmitter) + require.NoError(t, err, "Error deploying log emitter contract") + l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") + time.Sleep(200 * time.Millisecond) + } + + //wait for contracts to be uploaded to chain, TODO: could make this wait fluent + time.Sleep(5 * time.Second) + + // Save block number before starting to emit events, so that we can later use it when querying logs + sb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + startBlock := int64(sb) + + l.Info().Msg("STARTING EVENT EMISSION") + startTime := time.Now() + totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) + endTime := time.Now() + require.NoError(t, err, "Error executing event generator") + expectedLogsEmitted := getExpectedLogCount(cfg) + duration := int(endTime.Sub(startTime).Seconds()) + l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") + + // Save block number after finishing to emit events, so that we can later use it when querying logs + eb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + + endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) + require.NoError(t, err, "Error getting end block to wait for") + + // Lets make sure no logs are in DB yet + expectedFilters := getExpectedFilters(logEmitters, cfg) + logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), 0, expectedFilters, l, coreLogger, testEnv.ClCluster) + require.NoError(t, err, "Error checking if CL nodes have expected log count") + require.True(t, logCountMatches, "Some CL nodes already had logs in DB") + l.Info().Msg("No logs were saved by CL nodes yet, as expected. Proceeding.") + + // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) + // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) + for i := 0; i < len(upkeepIDs); i++ { + emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() + upkeepID := upkeepIDs[i] + topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID + + l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") + err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) + require.NoError(t, err, "Error registering log trigger for log emitter") + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + // Make sure that all nodes have expected filters registered before starting to emit events + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") + + hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) + if err != nil { + l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") + return + } + + g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") + } + }, "30s", "1s").Should(gomega.Succeed()) + l.Info().Msg("All nodes have expected filters registered") + l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") + + l.Warn().Str("Duration", "1m").Msg("Waiting for all CL nodes to have end block finalised") + gom.Eventually(func(g gomega.Gomega) { + hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") + } + g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") + }, "1m", "30s").Should(gomega.Succeed()) + + // Trigger replay + l.Info().Msg("Triggering log poller's replay") + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + response, _, err := testEnv.ClCluster.Nodes[i].API.ReplayLogPollerFromBlock(startBlock, testEnv.EVMClient.GetChainID().Int64()) + require.NoError(t, err, "Error triggering log poller's replay on node %s", nodeName) + require.Equal(t, "Replay started", response.Data.Attributes.Message, "Unexpected response message from log poller's replay") + } + + l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for logs to be processed by all nodes and for chain to advance beyond finality") + + gom.Eventually(func(g gomega.Gomega) { + logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if CL nodes have expected log count. Retrying...") + } + g.Expect(logCountMatches).To(gomega.BeTrue(), "Not all CL nodes have expected log count") + }, consistencyTimeout, "30s").Should(gomega.Succeed()) + + // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has + l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for CL nodes to have all the logs that EVM node has") + + gom.Eventually(func(g gomega.Gomega) { + missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) + if err != nil { + l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") + } + + if !missingLogs.IsEmpty() { + printMissingLogsByType(missingLogs, l, cfg) + } + g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") + }, consistencyTimeout, "10s").Should(gomega.Succeed()) +} + +type FinalityBlockFn = func(chainId int64, endBlock int64) (int64, error) + +func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { + l := logging.GetTestLogger(t) + coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ + + if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { + l.Warn().Msg("No events to emit specified, using all events from log emitter contract") + for _, event := range EmitterABI.Events { + cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) + } + } + + l.Info().Msg("Starting CI log poller test") + + var ( + err error + testName = "ci-log-poller" + upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) + ) + + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( + t, testName, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag, + ) + + _, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + upKeepsNeeded, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + true, + false, + ) + + // Deploy Log Emitter contracts + logEmitters := make([]*contracts.LogEmitter, 0) + for i := 0; i < cfg.General.Contracts; i++ { + logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() + logEmitters = append(logEmitters, &logEmitter) + require.NoError(t, err, "Error deploying log emitter contract") + l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") + time.Sleep(200 * time.Millisecond) + } + + // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) + // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) + for i := 0; i < len(upkeepIDs); i++ { + emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() + upkeepID := upkeepIDs[i] + topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID + + l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") + err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) + randomWait(50, 200) + require.NoError(t, err, "Error registering log trigger for log emitter") + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + // Make sure that all nodes have expected filters registered before starting to emit events + expectedFilters := getExpectedFilters(logEmitters, cfg) + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") + + hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) + if err != nil { + l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") + return + } + + g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") + } + }, "1m", "1s").Should(gomega.Succeed()) + l.Info().Msg("All nodes have expected filters registered") + l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") + + // Save block number before starting to emit events, so that we can later use it when querying logs + sb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + startBlock := int64(sb) + + l.Info().Msg("STARTING EVENT EMISSION") + startTime := time.Now() + + // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) + chaosDoneCh := make(chan error, 1) + go func() { + executeChaosExperiment(l, testEnv, cfg, chaosDoneCh) + }() + + totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) + endTime := time.Now() + require.NoError(t, err, "Error executing event generator") + + expectedLogsEmitted := getExpectedLogCount(cfg) + duration := int(endTime.Sub(startTime).Seconds()) + l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") + + // Save block number after finishing to emit events, so that we can later use it when querying logs + eb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + + endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) + require.NoError(t, err, "Error getting end block to wait for") + + l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") + chaosError := <-chaosDoneCh + require.NoError(t, chaosError, "Error encountered during chaos experiment") + + // Wait until last block in which events were emitted has been finalised (with buffer) + waitDuration := "45m" + l.Warn().Str("Duration", waitDuration).Msg("Waiting for chain to advance beyond finality") + + gom.Eventually(func(g gomega.Gomega) { + hasAdvanced, err := chainHasFinalisedEndBlock(l, testEnv.EVMClient, endBlock) + if err != nil { + l.Warn().Err(err).Msg("Error checking if chain has advanced beyond finality. Retrying...") + } + g.Expect(hasAdvanced).To(gomega.BeTrue(), "Chain has not advanced beyond finality") + }, waitDuration, "30s").Should(gomega.Succeed()) + + l.Warn().Str("Duration", waitDuration).Msg("Waiting for all CL nodes to have end block finalised") + gom.Eventually(func(g gomega.Gomega) { + hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") + } + g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") + }, waitDuration, "30s").Should(gomega.Succeed()) + + // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has + logConsistencyWaitDuration := "10m" + l.Warn().Str("Duration", logConsistencyWaitDuration).Msg("Waiting for CL nodes to have all the logs that EVM node has") + + gom.Eventually(func(g gomega.Gomega) { + missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) + if err != nil { + l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") + } + + if !missingLogs.IsEmpty() { + printMissingLogsByType(missingLogs, l, cfg) + } + g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") + }, logConsistencyWaitDuration, "20s").Should(gomega.Succeed()) + + evmLogs, _ := getEVMLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, l, cfg) + + if totalLogsEmitted != len(evmLogs) { + l.Warn().Int("Total logs emitted", totalLogsEmitted).Int("Total logs in EVM", len(evmLogs)).Msg("Test passed, but total logs emitted does not match total logs in EVM") + } +} From 305356206be809671fd497345d3851028ab60d9f Mon Sep 17 00:00:00 2001 From: Cedric Date: Fri, 3 Nov 2023 12:27:54 +0000 Subject: [PATCH 068/327] [BCF-2750] Reorder telemetry params (#11147) --- core/services/functions/listener_test.go | 2 +- core/services/ocr/delegate.go | 4 ++-- core/services/ocr2/delegate.go | 22 +++++++++---------- .../ocr2/plugins/generic/telemetry_adapter.go | 2 +- .../plugins/generic/telemetry_adapter_test.go | 2 +- core/services/ocrcommon/telemetry_test.go | 8 +++---- core/services/telemetry/common.go | 2 +- core/services/telemetry/ingress.go | 14 ++++++------ core/services/telemetry/ingress_batch.go | 14 ++++++------ core/services/telemetry/ingress_batch_test.go | 2 +- core/services/telemetry/ingress_test.go | 2 +- core/services/telemetry/manager.go | 6 ++--- core/services/telemetry/manager_test.go | 18 +++++++-------- core/services/telemetry/noop.go | 2 +- 14 files changed, 50 insertions(+), 50 deletions(-) diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 007a2a9168..3b7ed46988 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -125,7 +125,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe ingressClient := sync_mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monEndpoint := ingressAgent.GenMonitoringEndpoint(contractAddress, synchronization.FunctionsRequests, "test-network", "test-chainID") + monEndpoint := ingressAgent.GenMonitoringEndpoint("test-network", "test-chainID", contractAddress, synchronization.FunctionsRequests) s4Storage := s4_mocks.NewStorage(t) client := chain.Client() diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index b761690485..bbed43c151 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -297,7 +297,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e enhancedTelemChan := make(chan ocrcommon.EnhancedTelemetryData, 100) if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { - enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(concreteSpec.ContractAddress.String(), synchronization.EnhancedEA, "EVM", chain.ID().String()), lggr.Named("EnhancedTelemetry")) + enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint("EVM", chain.ID().String(), concreteSpec.ContractAddress.String(), synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) services = append(services, enhancedTelemService) } @@ -319,7 +319,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e Logger: ocrLogger, V1Bootstrappers: v1BootstrapPeers, V2Bootstrappers: v2Bootstrappers, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(concreteSpec.ContractAddress.String(), synchronization.OCR, "EVM", chain.ID().String()), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint("EVM", chain.ID().String(), concreteSpec.ContractAddress.String(), synchronization.OCR), ConfigOverrider: configOverrider, }) if err != nil { diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index e822fd5d8f..39a8c84d6b 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -564,10 +564,10 @@ func (d *Delegate) newServicesGenericPlugin( srvs = append(srvs, provider) oracleEndpoint := d.monitoringEndpointGen.GenMonitoringEndpoint( - spec.ContractID, - synchronization.TelemetryType(cconf.TelemetryType), rid.Network, rid.ChainID, + spec.ContractID, + synchronization.TelemetryType(cconf.TelemetryType), ) oracleArgs := libocr2.OCR2OracleArgs{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, @@ -686,7 +686,7 @@ func (d *Delegate) newServicesMercury( Database: ocrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.FeedID.String(), synchronization.OCR3Mercury, rid.Network, rid.ChainID), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.FeedID.String(), synchronization.OCR3Mercury), OffchainConfigDigester: mercuryProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: kb, @@ -697,7 +697,7 @@ func (d *Delegate) newServicesMercury( mercuryServices, err2 := mercury.NewServices(jb, mercuryProvider, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, d.cfg.JobPipeline(), chEnhancedTelem, chain, d.mercuryORM, (mercuryutils.FeedID)(*spec.FeedID)) if ocrcommon.ShouldCollectEnhancedTelemetryMercury(jb) { - enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(spec.FeedID.String(), synchronization.EnhancedEAMercury, rid.Network, rid.ChainID), lggr.Named("EnhancedTelemetryMercury")) + enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.FeedID.String(), synchronization.EnhancedEAMercury), lggr.Named("EnhancedTelemetryMercury")) mercuryServices = append(mercuryServices, enhancedTelemService) } @@ -728,7 +728,7 @@ func (d *Delegate) newServicesMedian( Database: ocrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Median, rid.Network, rid.ChainID), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR2Median), OffchainKeyring: kb, OnchainKeyring: kb, } @@ -744,7 +744,7 @@ func (d *Delegate) newServicesMedian( medianServices, err2 := median.NewMedianServices(ctx, jb, d.isNewlyCreatedJob, relayer, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, mConfig, enhancedTelemChan, errorLog) if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { - enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.EnhancedEA, rid.Network, rid.ChainID), lggr.Named("EnhancedTelemetry")) + enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) medianServices = append(medianServices, enhancedTelemService) } @@ -965,7 +965,7 @@ func (d *Delegate) newServicesOCR2VRF( VRFContractTransmitter: vrfProvider.ContractTransmitter(), VRFDatabase: ocrDB, VRFLocalConfig: lc, - VRFMonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2VRF, rid.Network, rid.ChainID), + VRFMonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR2VRF), DKGContractConfigTracker: dkgProvider.ContractConfigTracker(), DKGOffchainConfigDigester: dkgProvider.OffchainConfigDigester(), DKGContract: dkgpkg.NewOnchainContract(dkgContract, &altbn_128.G2{}), @@ -1104,7 +1104,7 @@ func (d *Delegate) newServicesOCR2Keepers21( ContractConfigTracker: keeperProvider.ContractConfigTracker(), KeepersDatabase: ocrDB, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Automation, rid.Network, rid.ChainID), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR2Automation), OffchainConfigDigester: keeperProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: services.Keyring(), @@ -1249,7 +1249,7 @@ func (d *Delegate) newServicesOCR2Keepers20( KeepersDatabase: ocrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Automation, rid.Network, rid.ChainID), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR2Automation), OffchainConfigDigester: keeperProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: kb, @@ -1358,7 +1358,7 @@ func (d *Delegate) newServicesOCR2Functions( Database: functionsOcrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Functions, rid.Network, rid.ChainID), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR2Functions), OffchainConfigDigester: functionsProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: kb, @@ -1422,7 +1422,7 @@ func (d *Delegate) newServicesOCR2Functions( ContractID: spec.ContractID, Logger: lggr, MailMon: d.mailMon, - URLsMonEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.FunctionsRequests, rid.Network, rid.ChainID), + URLsMonEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.FunctionsRequests), EthKeystore: d.ethKs, ThresholdKeyShare: thresholdKeyShare, LogPollerWrapper: functionsProvider.LogPollerWrapper(), diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter.go b/core/services/ocr2/plugins/generic/telemetry_adapter.go index e7f87dcd46..51d94f5cfe 100644 --- a/core/services/ocr2/plugins/generic/telemetry_adapter.go +++ b/core/services/ocr2/plugins/generic/telemetry_adapter.go @@ -52,7 +52,7 @@ func (t *TelemetryAdapter) getOrCreateEndpoint(network string, chainID string, c key := [4]string{network, chainID, contractID, telemetryType} e, ok := t.endpoints[key] if !ok { - e = t.endpointGenerator.GenMonitoringEndpoint(contractID, synchronization.TelemetryType(telemetryType), network, chainID) + e = t.endpointGenerator.GenMonitoringEndpoint(network, chainID, contractID, synchronization.TelemetryType(telemetryType)) t.endpoints[key] = e } return e, nil diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter_test.go b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go index 9c42b0f85d..e137343f2b 100644 --- a/core/services/ocr2/plugins/generic/telemetry_adapter_test.go +++ b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go @@ -24,7 +24,7 @@ func (m *mockEndpoint) SendLog(payload []byte) { m.payload = payload } type mockGenerator struct{} -func (m *mockGenerator) GenMonitoringEndpoint(contractID string, telemetryType synchronization.TelemetryType, network string, chainID string) commontypes.MonitoringEndpoint { +func (m *mockGenerator) GenMonitoringEndpoint(network string, chainID string, contractID string, telemetryType synchronization.TelemetryType) commontypes.MonitoringEndpoint { return &mockEndpoint{ network: network, chainID: chainID, diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index e6a798780b..9e3dedce8a 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -189,7 +189,7 @@ func TestSendEATelemetry(t *testing.T) { wg := sync.WaitGroup{} ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEA, "test-network", "test-chainID") + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("test-network", "test-chainID", "0xa", synchronization.EnhancedEA) var sentMessage []byte ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { @@ -305,7 +305,7 @@ func TestCollectAndSend(t *testing.T) { wg := sync.WaitGroup{} ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEA, "test-network", "test-chainID") + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("test-network", "test-chainID", "0xa", synchronization.EnhancedEA) ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { wg.Done() }) @@ -548,7 +548,7 @@ func TestCollectMercuryEnhancedTelemetryV1(t *testing.T) { wg := sync.WaitGroup{} ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEAMercury, "test-network", "test-chainID") + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("test-network", "test-chainID", "0xa", synchronization.EnhancedEAMercury) var sentMessage []byte ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { @@ -664,7 +664,7 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { wg := sync.WaitGroup{} ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEAMercury, "test-network", "test-chainID") + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("test-network", "test-chainID", "0xa", synchronization.EnhancedEAMercury) var sentMessage []byte ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { diff --git a/core/services/telemetry/common.go b/core/services/telemetry/common.go index 5a3f6706f7..37a92f16c6 100644 --- a/core/services/telemetry/common.go +++ b/core/services/telemetry/common.go @@ -7,5 +7,5 @@ import ( ) type MonitoringEndpointGenerator interface { - GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint + GenMonitoringEndpoint(network string, chainID string, contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint } diff --git a/core/services/telemetry/ingress.go b/core/services/telemetry/ingress.go index 637fa0dd3b..266155095b 100644 --- a/core/services/telemetry/ingress.go +++ b/core/services/telemetry/ingress.go @@ -18,25 +18,25 @@ func NewIngressAgentWrapper(telemetryIngressClient synchronization.TelemetryServ return &IngressAgentWrapper{telemetryIngressClient} } -func (t *IngressAgentWrapper) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint { - return NewIngressAgent(t.telemetryIngressClient, contractID, telemType, network, chainID) +func (t *IngressAgentWrapper) GenMonitoringEndpoint(network, chainID string, contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { + return NewIngressAgent(t.telemetryIngressClient, network, chainID, contractID, telemType) } type IngressAgent struct { telemetryIngressClient synchronization.TelemetryService - contractID string - telemType synchronization.TelemetryType network string chainID string + contractID string + telemType synchronization.TelemetryType } -func NewIngressAgent(telemetryIngressClient synchronization.TelemetryService, contractID string, telemType synchronization.TelemetryType, network string, chainID string) *IngressAgent { +func NewIngressAgent(telemetryIngressClient synchronization.TelemetryService, network string, chainID string, contractID string, telemType synchronization.TelemetryType) *IngressAgent { return &IngressAgent{ telemetryIngressClient, - contractID, - telemType, network, chainID, + contractID, + telemType, } } diff --git a/core/services/telemetry/ingress_batch.go b/core/services/telemetry/ingress_batch.go index df86085359..bb08c76d7e 100644 --- a/core/services/telemetry/ingress_batch.go +++ b/core/services/telemetry/ingress_batch.go @@ -21,27 +21,27 @@ func NewIngressAgentBatchWrapper(telemetryIngressBatchClient synchronization.Tel } // GenMonitoringEndpoint returns a new ingress batch agent instantiated with the batch client and a contractID -func (t *IngressAgentBatchWrapper) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint { - return NewIngressAgentBatch(t.telemetryIngressBatchClient, contractID, telemType, network, chainID) +func (t *IngressAgentBatchWrapper) GenMonitoringEndpoint(network string, chainID string, contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { + return NewIngressAgentBatch(t.telemetryIngressBatchClient, network, chainID, contractID, telemType) } // IngressAgentBatch allows for sending batch telemetry for a given contractID type IngressAgentBatch struct { telemetryIngressBatchClient synchronization.TelemetryService - contractID string - telemType synchronization.TelemetryType network string chainID string + contractID string + telemType synchronization.TelemetryType } // NewIngressAgentBatch creates a new IngressAgentBatch with the given batch client and contractID -func NewIngressAgentBatch(telemetryIngressBatchClient synchronization.TelemetryService, contractID string, telemType synchronization.TelemetryType, network string, chainID string) *IngressAgentBatch { +func NewIngressAgentBatch(telemetryIngressBatchClient synchronization.TelemetryService, network string, chainID string, contractID string, telemType synchronization.TelemetryType) *IngressAgentBatch { return &IngressAgentBatch{ telemetryIngressBatchClient, - contractID, - telemType, network, chainID, + contractID, + telemType, } } diff --git a/core/services/telemetry/ingress_batch_test.go b/core/services/telemetry/ingress_batch_test.go index 3923b569fe..91e6a07ad7 100644 --- a/core/services/telemetry/ingress_batch_test.go +++ b/core/services/telemetry/ingress_batch_test.go @@ -14,7 +14,7 @@ import ( func TestIngressAgentBatch(t *testing.T) { telemetryBatchClient := mocks.NewTelemetryService(t) ingressAgentBatch := telemetry.NewIngressAgentWrapper(telemetryBatchClient) - monitoringEndpoint := ingressAgentBatch.GenMonitoringEndpoint("0xa", synchronization.OCR, "test-network", "test-chainID") + monitoringEndpoint := ingressAgentBatch.GenMonitoringEndpoint("test-network", "test-chainID", "0xa", synchronization.OCR) // Handle the Send call and store the telem var telemPayload synchronization.TelemPayload diff --git a/core/services/telemetry/ingress_test.go b/core/services/telemetry/ingress_test.go index 31028f2f60..7e83384dc6 100644 --- a/core/services/telemetry/ingress_test.go +++ b/core/services/telemetry/ingress_test.go @@ -14,7 +14,7 @@ import ( func TestIngressAgent(t *testing.T) { telemetryClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(telemetryClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.OCR, "test-network", "test-chainID") + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("test-network", "test-chainID", "0xa", synchronization.OCR) // Handle the Send call and store the telem var telemPayload synchronization.TelemPayload diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go index 2931ec71a1..cc14a956c1 100644 --- a/core/services/telemetry/manager.go +++ b/core/services/telemetry/manager.go @@ -150,7 +150,7 @@ func (m *Manager) HealthReport() map[string]error { } // GenMonitoringEndpoint creates a new monitoring endpoints based on the existing available endpoints defined in the core config TOML, if no endpoint for the network and chainID exists, a NOOP agent will be used and the telemetry will not be sent -func (m *Manager) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) commontypes.MonitoringEndpoint { +func (m *Manager) GenMonitoringEndpoint(network string, chainID string, contractID string, telemType synchronization.TelemetryType) commontypes.MonitoringEndpoint { e, found := m.getEndpoint(network, chainID) @@ -160,10 +160,10 @@ func (m *Manager) GenMonitoringEndpoint(contractID string, telemType synchroniza } if m.useBatchSend { - return NewIngressAgentBatch(e.client, contractID, telemType, network, chainID) + return NewIngressAgentBatch(e.client, network, chainID, contractID, telemType) } - return NewIngressAgent(e.client, contractID, telemType, network, chainID) + return NewIngressAgent(e.client, network, chainID, contractID, telemType) } diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 69746625dd..2d51d9f449 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -56,14 +56,14 @@ func TestManagerAgents(t *testing.T) { tm := NewManager(tic, ks, lggr) require.Equal(t, "*synchronization.telemetryIngressBatchClient", reflect.TypeOf(tm.endpoints[0].client).String()) - me := tm.GenMonitoringEndpoint("", "", "network-1", "network-1-chainID-1") + me := tm.GenMonitoringEndpoint("network-1", "network-1-chainID-1", "", "") require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(me).String()) tic = setupMockConfig(t, false) tic.On("Endpoints").Return([]config.TelemetryIngressEndpoint{te}) tm = NewManager(tic, ks, lggr) require.Equal(t, "*synchronization.telemetryIngressClient", reflect.TypeOf(tm.endpoints[0].client).String()) - me = tm.GenMonitoringEndpoint("", "", "network-1", "network-1-chainID-1") + me = tm.GenMonitoringEndpoint("network-1", "network-1-chainID-1", "", "") require.Equal(t, "*telemetry.IngressAgent", reflect.TypeOf(me).String()) } @@ -254,17 +254,17 @@ func TestCorrectEndpointRouting(t *testing.T) { } //Unknown networks or chainID - noopEndpoint := tm.GenMonitoringEndpoint("some-contractID", "some-type", "unknown-network", "unknown-chainID") + noopEndpoint := tm.GenMonitoringEndpoint("unknown-network", "unknown-chainID", "some-contractID", "some-type") require.Equal(t, "*telemetry.NoopAgent", reflect.TypeOf(noopEndpoint).String()) require.Equal(t, 1, obsLogs.Len()) require.Contains(t, obsLogs.TakeAll()[0].Message, "no telemetry endpoint found") - noopEndpoint = tm.GenMonitoringEndpoint("some-contractID", "some-type", "network-1", "unknown-chainID") + noopEndpoint = tm.GenMonitoringEndpoint("network-1", "unknown-chainID", "some-contractID", "some-type") require.Equal(t, "*telemetry.NoopAgent", reflect.TypeOf(noopEndpoint).String()) require.Equal(t, 1, obsLogs.Len()) require.Contains(t, obsLogs.TakeAll()[0].Message, "no telemetry endpoint found") - noopEndpoint = tm.GenMonitoringEndpoint("some-contractID", "some-type", "network-2", "network-1-chainID-1") + noopEndpoint = tm.GenMonitoringEndpoint("network-2", "network-1-chainID-1", "some-contractID", "some-type") require.Equal(t, "*telemetry.NoopAgent", reflect.TypeOf(noopEndpoint).String()) require.Equal(t, 1, obsLogs.Len()) require.Contains(t, obsLogs.TakeAll()[0].Message, "no telemetry endpoint found") @@ -274,10 +274,10 @@ func TestCorrectEndpointRouting(t *testing.T) { telemType := fmt.Sprintf("TelemType_%s", e.chainID) contractID := fmt.Sprintf("contractID_%s", e.chainID) me := tm.GenMonitoringEndpoint( - contractID, - synchronization.TelemetryType(telemType), e.network, e.chainID, + contractID, + synchronization.TelemetryType(telemType), ) me.SendLog([]byte(e.chainID)) require.Equal(t, 0, obsLogs.Len()) @@ -316,7 +316,7 @@ func TestLegacyMode(t *testing.T) { }) tm.endpoints[0].client = clientMock - e := tm.GenMonitoringEndpoint("some-contractID", "some-type", "unknown-network", "unknown-chainID") + e := tm.GenMonitoringEndpoint("unknown-network", "unknown-chainID", "some-contractID", "some-type") require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(e).String()) e.SendLog([]byte("endpoint-1-message-1")) @@ -324,7 +324,7 @@ func TestLegacyMode(t *testing.T) { e.SendLog([]byte("endpoint-1-message-3")) require.Len(t, clientSent, 3) - e2 := tm.GenMonitoringEndpoint("another-contractID", "another-type", "another-unknown-network", "another-unknown-chainID") + e2 := tm.GenMonitoringEndpoint("another-unknown-network", "another-unknown-chainID", "another-contractID", "another-type") require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(e).String()) e2.SendLog([]byte("endpoint-2-message-1")) diff --git a/core/services/telemetry/noop.go b/core/services/telemetry/noop.go index cbeb038708..4da8868c8f 100644 --- a/core/services/telemetry/noop.go +++ b/core/services/telemetry/noop.go @@ -16,6 +16,6 @@ func (t *NoopAgent) SendLog(log []byte) { } // GenMonitoringEndpoint creates a monitoring endpoint for telemetry -func (t *NoopAgent) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint { +func (t *NoopAgent) GenMonitoringEndpoint(network string, chainID string, contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { return t } From 04ba364831eee6541c976cf8ea60c8eac09a0e5a Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Fri, 3 Nov 2023 09:07:11 -0400 Subject: [PATCH 069/327] Toggle Simulated Test Runs (#11157) * Toggle Simulated Test Runs * Debug inputs * Figured it out * Skip notify --- .github/workflows/integration-tests.yml | 15 ++++++++++----- integration-tests/soak/ocr_test.go | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 785c48da40..0456c5f9d4 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -10,12 +10,16 @@ on: - "*" workflow_dispatch: inputs: + simulatedNetwork: + description: "Run Simulated Network Tests" + required: false + type: boolean + default: true liveNetwork: - description: "Run Live Testnet Tests" + description: "Run Live Network Tests" required: false type: boolean - # Only run 1 of this workflow at a time per PR concurrency: group: integration-tests-chainlink-${{ github.ref }} @@ -58,6 +62,7 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: Check Paths That Require Tests To Run continue-on-error: true + outputs: src: ${{ steps.changes.outputs.src }} build-chainlink: @@ -176,7 +181,7 @@ jobs: echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV eth-smoke-tests-matrix-automation: - if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} + if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || (github.event_name == 'workflow_dispatch' && !inputs.simulatedNetwork)) }} environment: integration permissions: checks: write @@ -246,7 +251,7 @@ jobs: continue-on-error: true eth-smoke-tests-matrix: - if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} + if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || (github.event_name == 'workflow_dispatch' && !inputs.simulatedNetwork)) }} environment: integration permissions: checks: write @@ -971,7 +976,7 @@ jobs: testnet-smoke-tests-notify: name: Live Testnet Start Slack Thread - if: ${{ always() && needs.testnet-smoke-tests-matrix.result != 'skipped' && needs.testnet-smoke-tests-matrix.result != 'cancelled' }} + if: ${{ always() && needs.testnet-smoke-tests-matrix.result != 'skipped' && needs.testnet-smoke-tests-matrix.result != 'cancelled' && github.event_name != 'workflow_dispatch' }} environment: integration outputs: thread_ts: ${{ steps.slack.outputs.thread_ts }} diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index b2375f13ac..9973c23808 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -16,6 +16,7 @@ func TestOCRSoak(t *testing.T) { // Use this variable to pass in any custom EVM specific TOML values to your Chainlink nodes customNetworkTOML := `` // Uncomment below for debugging TOML issues on the node + // network := networks.MustGetSelectedNetworksFromEnv()[0] // fmt.Println("Using Chainlink TOML\n---------------------") // fmt.Println(client.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) // fmt.Println("---------------------") From 2b8ba05471a4c0f8fa1d30b7f47579f86a95efcf Mon Sep 17 00:00:00 2001 From: Chunkai Yang Date: Fri, 3 Nov 2023 09:35:15 -0400 Subject: [PATCH 070/327] Make solc output folder per contract (#11126) * update generation output path to be folder per contract * lint bash script * mass update go generate wrapper path * regen wrappers and db * fix not-updated wrappers * fix more wrappers --- contracts/scripts/native_solc_compile_all_6 | 11 +- contracts/scripts/native_solc_compile_all_7 | 11 +- .../native_solc_compile_all_automation | 13 +- .../native_solc_compile_all_events_mock | 11 +- .../scripts/native_solc_compile_all_feeds | 11 +- .../scripts/native_solc_compile_all_llo-feeds | 11 +- .../scripts/native_solc_compile_all_logpoller | 11 +- .../scripts/native_solc_compile_all_ocr2vrf | 13 +- .../native_solc_compile_all_operatorforwarder | 13 +- .../scripts/native_solc_compile_all_shared | 11 +- .../native_solc_compile_all_transmission | 11 +- contracts/scripts/native_solc_compile_all_vrf | 25 +- ...rapper-dependency-versions-do-not-edit.txt | 226 +++++++++--------- core/gethwrappers/go_generate.go | 218 ++++++++--------- ...rapper-dependency-versions-do-not-edit.txt | 12 +- core/gethwrappers/llo-feeds/go_generate.go | 12 +- ...rapper-dependency-versions-do-not-edit.txt | 8 +- core/gethwrappers/shared/go_generate.go | 8 +- ...rapper-dependency-versions-do-not-edit.txt | 12 +- core/gethwrappers/transmission/go_generate.go | 12 +- 20 files changed, 350 insertions(+), 310 deletions(-) diff --git a/contracts/scripts/native_solc_compile_all_6 b/contracts/scripts/native_solc_compile_all_6 index 7f8f4fa695..f7bd60d678 100755 --- a/contracts/scripts/native_solc_compile_all_6 +++ b/contracts/scripts/native_solc_compile_all_6 @@ -12,7 +12,7 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION @@ -20,10 +20,13 @@ export SOLC_VERSION=$SOLC_VERSION compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v0.6 \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.6 \ - $ROOT/contracts/src/v0.6/$1 + -o "$ROOT"/contracts/solc/v0.6/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.6 \ + "$ROOT"/contracts/src/v0.6/"$1" } compileContract Flags.sol diff --git a/contracts/scripts/native_solc_compile_all_7 b/contracts/scripts/native_solc_compile_all_7 index b2d76b3cb5..fd64d9ffce 100755 --- a/contracts/scripts/native_solc_compile_all_7 +++ b/contracts/scripts/native_solc_compile_all_7 @@ -12,7 +12,7 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION @@ -20,10 +20,13 @@ export SOLC_VERSION=$SOLC_VERSION compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v0.7 \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.7 \ - $ROOT/contracts/src/v0.7/$1 + -o "$ROOT"/contracts/solc/v0.7/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.7 \ + "$ROOT"/contracts/src/v0.7/"$1" } compileContract tests/MultiWordConsumer.sol diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index 414453c848..beb557de12 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -12,7 +12,7 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION @@ -20,10 +20,13 @@ export SOLC_VERSION=$SOLC_VERSION compileContract () { - solc @openzeppelin/=$ROOT/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8,$ROOT/contracts/node_modules\ - $ROOT/contracts/src/v0.8/$1 + local contract + contract=$(basename "$1" ".sol") + + solc @openzeppelin/="$ROOT"/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8,"$ROOT"/contracts/node_modules\ + "$ROOT"/contracts/src/v0.8/"$1" } compileContract automation/upkeeps/CronUpkeepFactory.sol diff --git a/contracts/scripts/native_solc_compile_all_events_mock b/contracts/scripts/native_solc_compile_all_events_mock index 993530e2fa..68e8bdfa6a 100755 --- a/contracts/scripts/native_solc_compile_all_events_mock +++ b/contracts/scripts/native_solc_compile_all_events_mock @@ -12,17 +12,20 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8\ - $ROOT/contracts/src/v0.8/$1 + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8\ + "$ROOT"/contracts/src/v0.8/"$1" } # This script is used to compile the contracts for the Events Mocks used in the tests. diff --git a/contracts/scripts/native_solc_compile_all_feeds b/contracts/scripts/native_solc_compile_all_feeds index 2bbd9fe869..eac5a6b70c 100755 --- a/contracts/scripts/native_solc_compile_all_feeds +++ b/contracts/scripts/native_solc_compile_all_feeds @@ -12,7 +12,7 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION @@ -20,10 +20,13 @@ export SOLC_VERSION=$SOLC_VERSION compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8\ - $ROOT/contracts/src/v0.8/$1 + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8\ + "$ROOT"/contracts/src/v0.8/"$1" } # Aggregators diff --git a/contracts/scripts/native_solc_compile_all_llo-feeds b/contracts/scripts/native_solc_compile_all_llo-feeds index 27ef714ec1..2caa6fb98d 100755 --- a/contracts/scripts/native_solc_compile_all_llo-feeds +++ b/contracts/scripts/native_solc_compile_all_llo-feeds @@ -11,7 +11,7 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION @@ -19,10 +19,13 @@ export SOLC_VERSION=$SOLC_VERSION ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8\ - $ROOT/contracts/src/v0.8/$1 + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8\ + "$ROOT"/contracts/src/v0.8/"$1" } compileContract llo-feeds/Verifier.sol diff --git a/contracts/scripts/native_solc_compile_all_logpoller b/contracts/scripts/native_solc_compile_all_logpoller index 91a0606dba..b6ac51eced 100755 --- a/contracts/scripts/native_solc_compile_all_logpoller +++ b/contracts/scripts/native_solc_compile_all_logpoller @@ -11,7 +11,7 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION @@ -19,10 +19,13 @@ export SOLC_VERSION=$SOLC_VERSION ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8\ - $ROOT/contracts/src/v0.8/$1 + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8\ + "$ROOT"/contracts/src/v0.8/"$1" } diff --git a/contracts/scripts/native_solc_compile_all_ocr2vrf b/contracts/scripts/native_solc_compile_all_ocr2vrf index 42478d7ebc..755edd34f5 100755 --- a/contracts/scripts/native_solc_compile_all_ocr2vrf +++ b/contracts/scripts/native_solc_compile_all_ocr2vrf @@ -16,7 +16,7 @@ echo "Compiling OCR2VRF contracts..." SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION @@ -24,11 +24,14 @@ export SOLC_VERSION=$SOLC_VERSION compileContract () { - solc --overwrite --optimize --optimize-runs $2 --metadata-hash none \ - -o $ROOT/contracts/solc/v0.8.19 \ + local contract + contract=$(basename "$1" ".sol") + + solc --overwrite --optimize --optimize-runs "$2" --metadata-hash none \ + -o "$ROOT"/contracts/solc/v0.8.19/"$contract" \ --abi --bin \ - --allow-paths $ROOT/../$FOLDER/contracts \ - $ROOT/$1 + --allow-paths "$ROOT"/../$FOLDER/contracts \ + "$ROOT"/"$1" } # OCR2VRF diff --git a/contracts/scripts/native_solc_compile_all_operatorforwarder b/contracts/scripts/native_solc_compile_all_operatorforwarder index 3bc5cb9249..2d45599481 100755 --- a/contracts/scripts/native_solc_compile_all_operatorforwarder +++ b/contracts/scripts/native_solc_compile_all_operatorforwarder @@ -11,17 +11,20 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION compileContract () { - solc @openzeppelin/=$ROOT/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8,$ROOT/contracts/node_modules\ - $ROOT/contracts/src/v0.8/$1 + local contract + contract=$(basename "$1" ".sol") + + solc @openzeppelin/="$ROOT"/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8,"$ROOT"/contracts/node_modules\ + "$ROOT"/contracts/src/v0.8/"$1" } # Contracts diff --git a/contracts/scripts/native_solc_compile_all_shared b/contracts/scripts/native_solc_compile_all_shared index db421f45e0..9178237b8a 100755 --- a/contracts/scripts/native_solc_compile_all_shared +++ b/contracts/scripts/native_solc_compile_all_shared @@ -11,7 +11,7 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION @@ -19,10 +19,13 @@ export SOLC_VERSION=$SOLC_VERSION ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8\ - $ROOT/contracts/src/v0.8/$1 + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8\ + "$ROOT"/contracts/src/v0.8/"$1" } compileContract shared/token/ERC677/BurnMintERC677.sol diff --git a/contracts/scripts/native_solc_compile_all_transmission b/contracts/scripts/native_solc_compile_all_transmission index e08f38e2ba..281fa7aea7 100755 --- a/contracts/scripts/native_solc_compile_all_transmission +++ b/contracts/scripts/native_solc_compile_all_transmission @@ -11,17 +11,20 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION compileContract () { + local contract + contract=$(basename "$1" ".sol") + solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8\ - $ROOT/contracts/src/v0.8/$1 + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8\ + "$ROOT"/contracts/src/v0.8/"$1" } # Contracts diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 80adba8e6f..4eed35cf5b 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -11,24 +11,30 @@ OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION compileContract () { - solc @openzeppelin/=$ROOT/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8,$ROOT/contracts/node_modules\ - $ROOT/contracts/src/v0.8/$1 + local contract + contract=$(basename "$1" ".sol") + + solc @openzeppelin/="$ROOT"/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8,"$ROOT"/contracts/node_modules\ + "$ROOT"/contracts/src/v0.8/"$1" } compileContractAltOpts () { - solc @openzeppelin/=$ROOT/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $2 --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION \ - --abi --bin --allow-paths $ROOT/contracts/src/v0.8,$ROOT/contracts/node_modules\ - $ROOT/contracts/src/v0.8/$1 + local contract + contract=$(basename "$1" ".sol") + + solc @openzeppelin/="$ROOT"/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs "$2" --metadata-hash none \ + -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \ + --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8,"$ROOT"/contracts/node_modules\ + "$ROOT"/contracts/src/v0.8/"$1" } # VRF @@ -73,6 +79,7 @@ compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol compileContract vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol compileContract vrf/dev/libraries/VRFV2PlusClient.sol compileContract vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol +compileContract vrf/dev/BlockhashStore.sol compileContract vrf/dev/TrustedBlockhashStore.sol compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol compileContractAltOpts vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 0d0bb388f2..a14b461fa7 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,116 +1,116 @@ GETH_VERSION: 1.12.0 -KeeperConsumer: ../../contracts/solc/v0.8.16/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 -KeeperConsumerPerformance: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 -PerformDataChecker: ../../contracts/solc/v0.8.16/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 -UpkeepCounter: ../../contracts/solc/v0.8.16/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 -UpkeepPerformCounterRestrictive: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c -VRFv2Consumer: ../../contracts/solc/v0.8.6/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 -aggregator_v2v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.bin 95e8814b408bb05bf21742ef580d98698b7db6a9bac6a35c3de12b23aec4ee28 -aggregator_v3_interface: ../../contracts/solc/v0.8.6/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV3Interface.bin 351b55d3b0f04af67db6dfb5c92f1c64479400ca1fec77afc20bc0ce65cb49ab -authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10 -authorized_receiver: ../../contracts/solc/v0.8.19/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver.bin 18e8969ba3234b027e1b16c11a783aca58d0ea5c2361010ec597f134b7bf1c4f -automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e -automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 -automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 -automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1.bin 331bfa79685aee6ddf63b64c0747abee556c454cae3fb8175edff425b615d8aa -batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore.bin 14356c48ef70f66ef74f22f644450dbf3b2a147c1b68deaa7e7d1eb8ffab15db -batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 -batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.bin 7bb76ae241cf1b37b41920830b836cb99f1ad33efd7435ca2398ff6cd2fe5d48 -blockhash_store: ../../contracts/solc/v0.8.6/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore.bin 12b0662f1636a341c8863bdec7a20f2ddd97c3a4fd1a7ae353fe316609face4e -chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.bin 5f10664e31abc768f4a37901cae7a3bef90146180f97303e5a1bde5a08d84595 -consumer_wrapper: ../../contracts/solc/v0.7/Consumer.abi ../../contracts/solc/v0.7/Consumer.bin 894d1cbd920dccbd36d92918c1037c6ded34f66f417ccb18ec3f33c64ef83ec5 -cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7 -cron_upkeep_wrapper: ../../contracts/solc/v0.8.6/CronUpkeep.abi - 362fcfcf30a6ab3acff83095ea4b2b9056dd5e9dcb94bc5411aae58995d22709 -dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol.bin 583a448170b13abf7ed64e406e8177d78c9e55ab44efd141eee60de23a71ee3b -flags_wrapper: ../../contracts/solc/v0.6/Flags.abi ../../contracts/solc/v0.6/Flags.bin 2034d1b562ca37a63068851915e3703980276e8d5f7db6db8a3351a49d69fc4a -flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator.bin a3b0a6396c4aa3b5ee39b3c4bd45efc89789d4859379a8a92caca3a0496c5794 -functions_billing_registry_events_mock: ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 -functions_oracle_events_mock: ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c -gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 -gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 -i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.bin 6501bb9bcf5048bab2737b00685c6984a24867e234ddf5b60a65904eee9a4ebc -i_log_automation: ../../contracts/solc/v0.8.16/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation.bin 296beccb6af655d6fc3a6e676b244831cce2da6688d3afc4f21f8738ae59e03e -keeper_consumer_performance_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 -keeper_consumer_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 -keeper_registrar_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistrar.abi ../../contracts/solc/v0.8.6/KeeperRegistrar.bin e49b2f8b23da17af1ed2209b8ae0968cc04350554d636711e6c24a3ad3118692 -keeper_registrar_wrapper1_2_mock: ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock.bin 5b155a7cb3def309fd7525de1d7cd364ebf8491bdc3060eac08ea0ff55ab29bc -keeper_registrar_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistrar2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistrar2_0.bin 647f125c2f0dafabcdc545cb77b15dc2ec3ea9429357806813179b1fd555c2d2 -keeper_registry_logic1_3: ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.bin 903f8b9c8e25425ca6d0b81b89e339d695a83630bfbfa24a6f3b38869676bc5a -keeper_registry_logic2_0: ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0.bin d69d2bc8e4844293dbc2d45abcddc50b84c88554ecccfa4fa77c0ca45ec80871 -keeper_registry_logic_a_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1.bin 77481ab75c9aa86a62a7b2a708599b5ea1a6346ed1c0def6d4826e7ae523f1ee -keeper_registry_logic_b_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1.bin 467d10741a04601b136553a2b1c6ab37f2a65d809366faf03180a22ff26be215 -keeper_registry_wrapper1_1: ../../contracts/solc/v0.7/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1.bin 6ce079f2738f015f7374673a2816e8e9787143d00b780ea7652c8aa9ad9e1e20 -keeper_registry_wrapper1_1_mock: ../../contracts/solc/v0.7/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock.bin 98ddb3680e86359de3b5d17e648253ba29a84703f087a1b52237824003a8c6df -keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2.bin a40ff877dd7c280f984cbbb2b428e160662b0c295e881d5f778f941c0088ca22 -keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3.bin d4dc760b767ae274ee25c4a604ea371e1fa603a7b6421b69efb2088ad9e8abb3 -keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0.bin c32dea7d5ef66b7c58ddc84ddf69aa44df1b3ae8601fbc271c95be4ff5853056 -keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1.bin 604e4a0cd980c713929b523b999462a3aa0ed06f96ff563a4c8566cf59c8445b -keepers_vrf_consumer: ../../contracts/solc/v0.8.6/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer.bin fa75572e689c9e84705c63e8dbe1b7b8aa1a8fe82d66356c4873d024bb9166e8 -log_emitter: ../../contracts/solc/v0.8.19/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter.bin 244ba13730c036de0b02beef4e3d9c9a96946ce353c27f366baecc7f5be5a6fd -log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.bin f8da43a927c1a66238a9f4fd5d5dd7e280e361daa0444da1f7f79498ace901e1 -log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter.bin 42426bbb83f96dfbe55fc576d6c65020eaeed690e2289cf99b0c4aa810a5f4ec -mock_aggregator_proxy: ../../contracts/solc/v0.8.6/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy.bin b16c108f3dd384c342ddff5e94da7c0a8d39d1be5e3d8f2cf61ecc7f0e50ff42 -mock_ethlink_aggregator_wrapper: ../../contracts/solc/v0.6/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator.bin 1c52c24f797b8482aa12b8251dcea1c072827bd5b3426b822621261944b99ca0 -mock_gas_aggregator_wrapper: ../../contracts/solc/v0.6/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator.bin bacbb1ea4dc6beac0db8a13ca5c75e2fd61b903d70feea9b3b1c8b10fe8df4f3 -multiwordconsumer_wrapper: ../../contracts/solc/v0.7/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer.bin 6e68abdf614e3ed0f5066c1b5f9d7c1199f1e7c5c5251fe8a471344a59afc6ba +KeeperConsumer: ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 +KeeperConsumerPerformance: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 +PerformDataChecker: ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 +UpkeepCounter: ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 +UpkeepPerformCounterRestrictive: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c +VRFv2Consumer: ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 +aggregator_v2v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.bin 95e8814b408bb05bf21742ef580d98698b7db6a9bac6a35c3de12b23aec4ee28 +aggregator_v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.bin 351b55d3b0f04af67db6dfb5c92f1c64479400ca1fec77afc20bc0ce65cb49ab +authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10 +authorized_receiver: ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.bin 18e8969ba3234b027e1b16c11a783aca58d0ea5c2361010ec597f134b7bf1c4f +automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e +automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 +automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 +automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 331bfa79685aee6ddf63b64c0747abee556c454cae3fb8175edff425b615d8aa +batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.bin 14356c48ef70f66ef74f22f644450dbf3b2a147c1b68deaa7e7d1eb8ffab15db +batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 +batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin 7bb76ae241cf1b37b41920830b836cb99f1ad33efd7435ca2398ff6cd2fe5d48 +blockhash_store: ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.bin 12b0662f1636a341c8863bdec7a20f2ddd97c3a4fd1a7ae353fe316609face4e +chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin 5f10664e31abc768f4a37901cae7a3bef90146180f97303e5a1bde5a08d84595 +consumer_wrapper: ../../contracts/solc/v0.7/Consumer/Consumer.abi ../../contracts/solc/v0.7/Consumer/Consumer.bin 894d1cbd920dccbd36d92918c1037c6ded34f66f417ccb18ec3f33c64ef83ec5 +cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7 +cron_upkeep_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeep.abi - 362fcfcf30a6ab3acff83095ea4b2b9056dd5e9dcb94bc5411aae58995d22709 +dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.bin 583a448170b13abf7ed64e406e8177d78c9e55ab44efd141eee60de23a71ee3b +flags_wrapper: ../../contracts/solc/v0.6/Flags/Flags.abi ../../contracts/solc/v0.6/Flags/Flags.bin 2034d1b562ca37a63068851915e3703980276e8d5f7db6db8a3351a49d69fc4a +flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.bin a3b0a6396c4aa3b5ee39b3c4bd45efc89789d4859379a8a92caca3a0496c5794 +functions_billing_registry_events_mock: ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock/FunctionsBillingRegistryEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 +functions_oracle_events_mock: ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock/FunctionsOracleEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c +gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 +gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 +i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin 6501bb9bcf5048bab2737b00685c6984a24867e234ddf5b60a65904eee9a4ebc +i_log_automation: ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin 296beccb6af655d6fc3a6e676b244831cce2da6688d3afc4f21f8738ae59e03e +keeper_consumer_performance_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 +keeper_consumer_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 +keeper_registrar_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.bin e49b2f8b23da17af1ed2209b8ae0968cc04350554d636711e6c24a3ad3118692 +keeper_registrar_wrapper1_2_mock: ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock/KeeperRegistrar1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock/KeeperRegistrar1_2Mock.bin 5b155a7cb3def309fd7525de1d7cd364ebf8491bdc3060eac08ea0ff55ab29bc +keeper_registrar_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.bin 647f125c2f0dafabcdc545cb77b15dc2ec3ea9429357806813179b1fd555c2d2 +keeper_registry_logic1_3: ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.bin 903f8b9c8e25425ca6d0b81b89e339d695a83630bfbfa24a6f3b38869676bc5a +keeper_registry_logic2_0: ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.bin d69d2bc8e4844293dbc2d45abcddc50b84c88554ecccfa4fa77c0ca45ec80871 +keeper_registry_logic_a_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin 77481ab75c9aa86a62a7b2a708599b5ea1a6346ed1c0def6d4826e7ae523f1ee +keeper_registry_logic_b_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.bin 467d10741a04601b136553a2b1c6ab37f2a65d809366faf03180a22ff26be215 +keeper_registry_wrapper1_1: ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.bin 6ce079f2738f015f7374673a2816e8e9787143d00b780ea7652c8aa9ad9e1e20 +keeper_registry_wrapper1_1_mock: ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.bin 98ddb3680e86359de3b5d17e648253ba29a84703f087a1b52237824003a8c6df +keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.bin a40ff877dd7c280f984cbbb2b428e160662b0c295e881d5f778f941c0088ca22 +keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.bin d4dc760b767ae274ee25c4a604ea371e1fa603a7b6421b69efb2088ad9e8abb3 +keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.bin c32dea7d5ef66b7c58ddc84ddf69aa44df1b3ae8601fbc271c95be4ff5853056 +keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.bin 604e4a0cd980c713929b523b999462a3aa0ed06f96ff563a4c8566cf59c8445b +keepers_vrf_consumer: ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin fa75572e689c9e84705c63e8dbe1b7b8aa1a8fe82d66356c4873d024bb9166e8 +log_emitter: ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin 244ba13730c036de0b02beef4e3d9c9a96946ce353c27f366baecc7f5be5a6fd +log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin f8da43a927c1a66238a9f4fd5d5dd7e280e361daa0444da1f7f79498ace901e1 +log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.bin 42426bbb83f96dfbe55fc576d6c65020eaeed690e2289cf99b0c4aa810a5f4ec +mock_aggregator_proxy: ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.bin b16c108f3dd384c342ddff5e94da7c0a8d39d1be5e3d8f2cf61ecc7f0e50ff42 +mock_ethlink_aggregator_wrapper: ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.bin 1c52c24f797b8482aa12b8251dcea1c072827bd5b3426b822621261944b99ca0 +mock_gas_aggregator_wrapper: ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.bin bacbb1ea4dc6beac0db8a13ca5c75e2fd61b903d70feea9b3b1c8b10fe8df4f3 +multiwordconsumer_wrapper: ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.bin 6e68abdf614e3ed0f5066c1b5f9d7c1199f1e7c5c5251fe8a471344a59afc6ba offchain_aggregator_wrapper: OffchainAggregator/OffchainAggregator.abi - 5c8d6562e94166d4790f1ee6e4321d359d9f7262e6c5452a712b1f1c896f45cf -operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory.bin 0fdfacf8879537b854875608dfca41c6221c342174417112acaa67dfcadafddc -operator_wrapper: ../../contracts/solc/v0.8.19/Operator.abi ../../contracts/solc/v0.8.19/Operator.bin d7abd0e67f30a3a4c9c04c896124391306fa364fcf579fa6df04dbf912b48568 -oracle_wrapper: ../../contracts/solc/v0.6/Oracle.abi ../../contracts/solc/v0.6/Oracle.bin 7af2fbac22a6e8c2847e8e685a5400cac5101d72ddf5365213beb79e4dede43a -perform_data_checker_wrapper: ../../contracts/solc/v0.8.16/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 -solidity_vrf_consumer_interface: ../../contracts/solc/v0.6/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer.bin ecc99378aa798014de9db42b2eb81320778b0663dbe208008dad75ccdc1d4366 -solidity_vrf_consumer_interface_v08: ../../contracts/solc/v0.8.6/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer.bin b14f9136b15e3dc9d6154d5700f3ed4cf88ddc4f70f20c3bb57fc46050904c8f -solidity_vrf_coordinator_interface: ../../contracts/solc/v0.6/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator.bin a23d3c395156804788c7f6fbda2994e8f7184304c0f0c9f2c4ddeaf073d346d2 -solidity_vrf_request_id: ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper.bin 383b59e861732c1911ddb7b002c6158608496ce889979296527215fd0366b318 -solidity_vrf_request_id_v08: ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper.bin f2559015d6f3e5d285c57b011be9b2300632e93dd6c4524e58202d6200f09edc -solidity_vrf_v08_verifier_wrapper: ../../contracts/solc/v0.8.6/VRFTestHelper.abi ../../contracts/solc/v0.8.6/VRFTestHelper.bin f37f8b21a81c113085c6137835a2246db6ebda07da455c4f2b5c7ec60c725c3b -solidity_vrf_verifier_wrapper: ../../contracts/solc/v0.6/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper.bin 44c2b67d8d2990ab580453deb29d63508c6147a3dc49908a1db563bef06e6474 -solidity_vrf_wrapper: ../../contracts/solc/v0.6/VRF.abi ../../contracts/solc/v0.6/VRF.bin 04ede5b83c06ba5b76ef99c081c72928007d8a7aaefcf21449a46a07cbd4bfc2 -streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.bin feb92cc666df21ea04ab9d7a588a513847b01b2f66fc167d06ab28ef2b17e015 -streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.bin b1a598963cacac51ed4706538d0f142bdc0d94b9a4b13e2d402131cdf05c9bcf -test_api_consumer_wrapper: ../../contracts/solc/v0.6/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer.bin ed10893cb18894c18e275302329c955f14ea2de37ee044f84aa1e067ac5ea71e -trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin 98cb0dc06c15af5dcd3b53bdfc98e7ed2489edc96a42203294ac2fc0efdda02b -type_and_version_interface_wrapper: ../../contracts/solc/v0.8.6/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/TypeAndVersionInterface.bin bc9c3a6e73e3ebd5b58754df0deeb3b33f4bb404d5709bb904aed51d32f4b45e -upkeep_counter_wrapper: ../../contracts/solc/v0.8.16/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 -upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c -upkeep_transcoder: ../../contracts/solc/v0.8.6/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder.bin 336c92a981597be26508455f81a908a0784a817b129a59686c5b2c4afcba730a -verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.bin fb674ba44c0e8f3b385cd10b2f7dea5cd07b5f38df08066747e8b1542e152557 -verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.bin 785f68c44bfff070505eaa65e38a1af94046e5f9afc1189bcf2c8cfcd1102d66 -verifiable_load_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.bin a3e02c43756ea91e7ce4b81e48c11648f1d12f6663c236780147e41dfa36ebee -vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2.bin 9ef258bf8e9f8d880fd229ceb145593d91e24fc89366baa0bf19169c5787d15f -vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b -vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.bin f1790a9a2f2a04c730593e483459709cb89e897f8a19d7a3ac0cfe6a97265e6e -vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 -vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin 295f35ce282060317dfd01f45959f5a2b05ba26913e422fbd4fb6bf90b107006 -vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.bin b0e7c42a30b36d9d31fa9a3f26bad7937152e3dddee5bd8dd3d121390c879ab6 -vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.bin 4a5b86701983b1b65f0a8dfa116b3f6d75f8f706fa274004b57bdf5992e4cec3 +operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin 0fdfacf8879537b854875608dfca41c6221c342174417112acaa67dfcadafddc +operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin d7abd0e67f30a3a4c9c04c896124391306fa364fcf579fa6df04dbf912b48568 +oracle_wrapper: ../../contracts/solc/v0.6/Oracle/Oracle.abi ../../contracts/solc/v0.6/Oracle/Oracle.bin 7af2fbac22a6e8c2847e8e685a5400cac5101d72ddf5365213beb79e4dede43a +perform_data_checker_wrapper: ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 +solidity_vrf_consumer_interface: ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.bin ecc99378aa798014de9db42b2eb81320778b0663dbe208008dad75ccdc1d4366 +solidity_vrf_consumer_interface_v08: ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.bin b14f9136b15e3dc9d6154d5700f3ed4cf88ddc4f70f20c3bb57fc46050904c8f +solidity_vrf_coordinator_interface: ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.bin a23d3c395156804788c7f6fbda2994e8f7184304c0f0c9f2c4ddeaf073d346d2 +solidity_vrf_request_id: ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin 383b59e861732c1911ddb7b002c6158608496ce889979296527215fd0366b318 +solidity_vrf_request_id_v08: ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin f2559015d6f3e5d285c57b011be9b2300632e93dd6c4524e58202d6200f09edc +solidity_vrf_v08_verifier_wrapper: ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.bin f37f8b21a81c113085c6137835a2246db6ebda07da455c4f2b5c7ec60c725c3b +solidity_vrf_verifier_wrapper: ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.bin 44c2b67d8d2990ab580453deb29d63508c6147a3dc49908a1db563bef06e6474 +solidity_vrf_wrapper: ../../contracts/solc/v0.6/VRF/VRF.abi ../../contracts/solc/v0.6/VRF/VRF.bin 04ede5b83c06ba5b76ef99c081c72928007d8a7aaefcf21449a46a07cbd4bfc2 +streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.bin feb92cc666df21ea04ab9d7a588a513847b01b2f66fc167d06ab28ef2b17e015 +streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.bin b1a598963cacac51ed4706538d0f142bdc0d94b9a4b13e2d402131cdf05c9bcf +test_api_consumer_wrapper: ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.bin ed10893cb18894c18e275302329c955f14ea2de37ee044f84aa1e067ac5ea71e +trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.bin 98cb0dc06c15af5dcd3b53bdfc98e7ed2489edc96a42203294ac2fc0efdda02b +type_and_version_interface_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.bin bc9c3a6e73e3ebd5b58754df0deeb3b33f4bb404d5709bb904aed51d32f4b45e +upkeep_counter_wrapper: ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 +upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c +upkeep_transcoder: ../../contracts/solc/v0.8.6/UpkeepTranscoder/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder/UpkeepTranscoder.bin 336c92a981597be26508455f81a908a0784a817b129a59686c5b2c4afcba730a +verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.bin fb674ba44c0e8f3b385cd10b2f7dea5cd07b5f38df08066747e8b1542e152557 +verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.bin 785f68c44bfff070505eaa65e38a1af94046e5f9afc1189bcf2c8cfcd1102d66 +verifiable_load_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.bin a3e02c43756ea91e7ce4b81e48c11648f1d12f6663c236780147e41dfa36ebee +vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.bin 9ef258bf8e9f8d880fd229ceb145593d91e24fc89366baa0bf19169c5787d15f +vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b +vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.bin f1790a9a2f2a04c730593e483459709cb89e897f8a19d7a3ac0cfe6a97265e6e +vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 +vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.bin 295f35ce282060317dfd01f45959f5a2b05ba26913e422fbd4fb6bf90b107006 +vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin b0e7c42a30b36d9d31fa9a3f26bad7937152e3dddee5bd8dd3d121390c879ab6 +vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin 4a5b86701983b1b65f0a8dfa116b3f6d75f8f706fa274004b57bdf5992e4cec3 vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin e4409bbe361258273458a5c99408b3d7f0cc57a2560dee91c0596cc6d6f738be -vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal.bin 834a2ce0e83276372a0e1446593fd89798f4cf6dc95d4be0113e99fadf61558b -vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 -vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d -vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c -vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.bin 8ab9de5816fbdf93a2865e2711b85a39a6fc9c413a4b336578c485be1158d430 -vrf_malicious_consumer_v2: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2.bin 9755fa8ffc7f5f0b337d5d413d77b0c9f6cd6f68c31727d49acdf9d4a51bc522 -vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.bin e2a72638e11da807b6533d037e7e5aaeed695efd5035777b8e20d2f8973a574c -vrf_owner: ../../contracts/solc/v0.8.6/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner.bin eccfae5ee295b5850e22f61240c469f79752b8d9a3bac5d64aec7ac8def2f6cb -vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.bin 0537bbe96c5a8bbd44d0a65fbb7e51f6a9f9e75f4673225845ac1ba33f4e7974 -vrf_ownerless_consumer_example: ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample.bin 9893b3805863273917fb282eed32274e32aa3d5c2a67a911510133e1218132be -vrf_single_consumer_example: ../../contracts/solc/v0.8.6/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample.bin 892a5ed35da2e933f7fd7835cd6f7f70ef3aa63a9c03a22c5b1fd026711b0ece -vrf_v2_consumer_wrapper: ../../contracts/solc/v0.8.6/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 -vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.bin 0a89cb7ed9dfb42f91e559b03dc351ccdbe14d281a7ab71c63bd3f47eeed7711 -vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.bin 6226d05afa1664033b182bfbdde11d5dfb1d4c8e3eb0bd0448c8bfb76f5b96e4 -vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.bin 7541f986571b8a5671a256edc27ae9b8df9bcdff45ac3b96e5609bbfcc320e4e -vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.bin c0793d86fb6e45342c4424184fe241c16da960c0b4de76816364b933344d0756 -vrfv2_proxy_admin: ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.bin 402b1103087ffe1aa598854a8f8b38f8cd3de2e3aaa86369e28017a9157f4980 -vrfv2_reverting_example: ../../contracts/solc/v0.8.6/VRFV2RevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2RevertingExample.bin 1ae46f80351d428bd85ba58b9041b2a608a1845300d79a8fed83edf96606de87 -vrfv2_transparent_upgradeable_proxy: ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.bin fe1a8e6852fbd06d91f64315c5cede86d340891f5b5cc981fb5b86563f7eac3f -vrfv2_wrapper: ../../contracts/solc/v0.8.6/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper.bin d5e9a982325d2d4f517c4f2bc818795f61555408ef4b38fb59b923d144970e38 -vrfv2_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample.bin 3c5c9f1c501e697a7e77e959b48767e2a0bb1372393fd7686f7aaef3eb794231 -vrfv2_wrapper_interface: ../../contracts/solc/v0.8.6/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface.bin ff8560169de171a68b360b7438d13863682d07040d984fd0fb096b2379421003 -vrfv2plus_client: ../../contracts/solc/v0.8.6/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient.bin 3ffbfa4971a7e5f46051a26b1722613f265d89ea1867547ecec58500953a9501 -vrfv2plus_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.bin 2c480a6d7955d33a00690fdd943486d95802e48a03f3cc243df314448e4ddb2c -vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.bin 80dbc98be5e42246960c889d29488f978d3db0127e95e9b295352c481d8c9b07 -vrfv2plus_reverting_example: ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.bin 6c9053a94f90b8151964d3311310478b57744fbbd153e8ee742ed570e1e49798 -vrfv2plus_wrapper: ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.bin 934bafba386b934f491827e535306726069f4cafef9125079ea88abf0d808877 -vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.bin a14c4c6e2299cd963a8f0ed069e61dd135af5aad4c13a94f6ea7e086eced7191 -vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.bin 55e3bd534045125fb6579a201ab766185e9b0fac5737b4f37897bb69c9f599fa +vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin 834a2ce0e83276372a0e1446593fd89798f4cf6dc95d4be0113e99fadf61558b +vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 +vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d +vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c +vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin 8ab9de5816fbdf93a2865e2711b85a39a6fc9c413a4b336578c485be1158d430 +vrf_malicious_consumer_v2: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.bin 9755fa8ffc7f5f0b337d5d413d77b0c9f6cd6f68c31727d49acdf9d4a51bc522 +vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin e2a72638e11da807b6533d037e7e5aaeed695efd5035777b8e20d2f8973a574c +vrf_owner: ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.bin eccfae5ee295b5850e22f61240c469f79752b8d9a3bac5d64aec7ac8def2f6cb +vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.bin 0537bbe96c5a8bbd44d0a65fbb7e51f6a9f9e75f4673225845ac1ba33f4e7974 +vrf_ownerless_consumer_example: ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.bin 9893b3805863273917fb282eed32274e32aa3d5c2a67a911510133e1218132be +vrf_single_consumer_example: ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.bin 892a5ed35da2e933f7fd7835cd6f7f70ef3aa63a9c03a22c5b1fd026711b0ece +vrf_v2_consumer_wrapper: ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 +vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin 0a89cb7ed9dfb42f91e559b03dc351ccdbe14d281a7ab71c63bd3f47eeed7711 +vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin 6226d05afa1664033b182bfbdde11d5dfb1d4c8e3eb0bd0448c8bfb76f5b96e4 +vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin 7541f986571b8a5671a256edc27ae9b8df9bcdff45ac3b96e5609bbfcc320e4e +vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin c0793d86fb6e45342c4424184fe241c16da960c0b4de76816364b933344d0756 +vrfv2_proxy_admin: ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.bin 402b1103087ffe1aa598854a8f8b38f8cd3de2e3aaa86369e28017a9157f4980 +vrfv2_reverting_example: ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.bin 1ae46f80351d428bd85ba58b9041b2a608a1845300d79a8fed83edf96606de87 +vrfv2_transparent_upgradeable_proxy: ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.bin fe1a8e6852fbd06d91f64315c5cede86d340891f5b5cc981fb5b86563f7eac3f +vrfv2_wrapper: ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.bin d5e9a982325d2d4f517c4f2bc818795f61555408ef4b38fb59b923d144970e38 +vrfv2_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.bin 3c5c9f1c501e697a7e77e959b48767e2a0bb1372393fd7686f7aaef3eb794231 +vrfv2_wrapper_interface: ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.bin ff8560169de171a68b360b7438d13863682d07040d984fd0fb096b2379421003 +vrfv2plus_client: ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.bin 3ffbfa4971a7e5f46051a26b1722613f265d89ea1867547ecec58500953a9501 +vrfv2plus_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin 2c480a6d7955d33a00690fdd943486d95802e48a03f3cc243df314448e4ddb2c +vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin 80dbc98be5e42246960c889d29488f978d3db0127e95e9b295352c481d8c9b07 +vrfv2plus_reverting_example: ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin 6c9053a94f90b8151964d3311310478b57744fbbd153e8ee742ed570e1e49798 +vrfv2plus_wrapper: ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.bin 934bafba386b934f491827e535306726069f4cafef9125079ea88abf0d808877 +vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin a14c4c6e2299cd963a8f0ed069e61dd135af5aad4c13a94f6ea7e086eced7191 +vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin 55e3bd534045125fb6579a201ab766185e9b0fac5737b4f37897bb69c9f599fa diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 67090d16c6..3965c15908 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -5,139 +5,139 @@ package gethwrappers // Make sure solidity compiler artifacts are up-to-date. Only output stdout on failure. //go:generate ./generation/compile_contracts.sh -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator.bin FluxAggregator flux_aggregator_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRF.abi ../../contracts/solc/v0.6/VRF.bin VRF solidity_vrf_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper.bin VRFTestHelper solidity_vrf_verifier_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator.bin VRFCoordinator solidity_vrf_coordinator_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer.bin VRFConsumer solidity_vrf_consumer_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper.bin VRFRequestIDBaseTestHelper solidity_vrf_request_id -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Flags.abi ../../contracts/solc/v0.6/Flags.bin Flags flags_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Oracle.abi ../../contracts/solc/v0.6/Oracle.bin Oracle oracle_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer.bin TestAPIConsumer test_api_consumer_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator.bin MockETHLINKAggregator mock_ethlink_aggregator_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator.bin MockGASAggregator mock_gas_aggregator_wrapper - -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/Consumer.abi ../../contracts/solc/v0.7/Consumer.bin Consumer consumer_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer.bin MultiWordConsumer multiwordconsumer_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/Operator.abi ../../contracts/solc/v0.8.19/Operator.bin Operator operator_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory.bin OperatorFactory operator_factory -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder.bin AuthorizedForwarder authorized_forwarder -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver.bin AuthorizedReceiver authorized_receiver +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.bin FluxAggregator flux_aggregator_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRF/VRF.abi ../../contracts/solc/v0.6/VRF/VRF.bin VRF solidity_vrf_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.bin VRFTestHelper solidity_vrf_verifier_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.bin VRFCoordinator solidity_vrf_coordinator_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.bin VRFConsumer solidity_vrf_consumer_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin VRFRequestIDBaseTestHelper solidity_vrf_request_id +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Flags/Flags.abi ../../contracts/solc/v0.6/Flags/Flags.bin Flags flags_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Oracle/Oracle.abi ../../contracts/solc/v0.6/Oracle/Oracle.bin Oracle oracle_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.bin TestAPIConsumer test_api_consumer_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.bin MockETHLINKAggregator mock_ethlink_aggregator_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.bin MockGASAggregator mock_gas_aggregator_wrapper + +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/Consumer/Consumer.abi ../../contracts/solc/v0.7/Consumer/Consumer.bin Consumer consumer_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.bin MultiWordConsumer multiwordconsumer_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin Operator operator_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin OperatorFactory operator_factory +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin AuthorizedForwarder authorized_forwarder +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.bin AuthorizedReceiver authorized_receiver //go:generate go run ./generation/generate/wrap.go OffchainAggregator/OffchainAggregator.abi - OffchainAggregator offchain_aggregator_wrapper // Automation -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1.bin KeeperRegistry keeper_registry_wrapper1_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock.bin KeeperRegistryMock keeper_registry_wrapper1_1_mock -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.bin UpkeepPerformCounterRestrictive upkeep_perform_counter_restrictive_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/UpkeepCounter.abi ../../contracts/solc/v0.7/UpkeepCounter.bin UpkeepCounter upkeep_counter_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/CronUpkeepFactory.abi - CronUpkeepFactory cron_upkeep_factory_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/CronUpkeep.abi - CronUpkeep cron_upkeep_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistrar.abi ../../contracts/solc/v0.8.6/KeeperRegistrar.bin KeeperRegistrar keeper_registrar_wrapper1_2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock.bin KeeperRegistrarMock keeper_registrar_wrapper1_2_mock -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2.bin KeeperRegistry keeper_registry_wrapper1_2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/TypeAndVersionInterface.bin TypeAndVersionInterface type_and_version_interface_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin KeeperRegistryCheckUpkeepGasUsageWrapper gas_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin KeeperRegistryCheckUpkeepGasUsageWrapperMock gas_wrapper_mock -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3.bin KeeperRegistry keeper_registry_wrapper1_3 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.bin KeeperRegistryLogic keeper_registry_logic1_3 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistrar2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistrar2_0.bin KeeperRegistrar keeper_registrar_wrapper2_0 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0.bin KeeperRegistry keeper_registry_wrapper2_0 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0.bin KeeperRegistryLogic keeper_registry_logic2_0 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder.bin UpkeepTranscoder upkeep_transcoder -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.bin VerifiableLoadUpkeep verifiable_load_upkeep_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.bin VerifiableLoadStreamsLookupUpkeep verifiable_load_streams_lookup_upkeep_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.bin VerifiableLoadLogTriggerUpkeep verifiable_load_log_trigger_upkeep_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.bin StreamsLookupUpkeep streams_lookup_upkeep_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.bin StreamsLookupCompatibleInterface streams_lookup_compatible_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.bin AutomationConsumerBenchmark automation_consumer_benchmark -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.bin AutomationRegistrar automation_registrar_wrapper2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1.bin KeeperRegistry keeper_registry_wrapper_2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1.bin KeeperRegistryLogicA keeper_registry_logic_a_wrapper_2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1.bin KeeperRegistryLogicB keeper_registry_logic_b_wrapper_2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.bin IKeeperRegistryMaster i_keeper_registry_master_wrapper_2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation.bin ILogAutomation i_log_automation -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1.bin AutomationUtils automation_utils_2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic.bin AutomationForwarderLogic automation_forwarder_logic -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter.bin LogUpkeepCounter log_upkeep_counter_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.bin LogTriggeredStreamsLookup log_triggered_streams_lookup_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol.bin DummyProtocol dummy_protocol_wrapper - -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer.bin KeeperConsumer keeper_consumer_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.bin KeeperConsumerPerformance keeper_consumer_performance_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker.bin PerformDataChecker perform_data_checker_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter.bin UpkeepCounter upkeep_counter_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.bin UpkeepPerformCounterRestrictive upkeep_perform_counter_restrictive_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.bin KeeperRegistry keeper_registry_wrapper1_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.bin KeeperRegistryMock keeper_registry_wrapper1_1_mock +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin UpkeepPerformCounterRestrictive upkeep_perform_counter_restrictive_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.7/UpkeepCounter/UpkeepCounter.bin UpkeepCounter upkeep_counter_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - CronUpkeepFactory cron_upkeep_factory_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeep.abi - CronUpkeep cron_upkeep_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.bin KeeperRegistrar keeper_registrar_wrapper1_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock/KeeperRegistrar1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock/KeeperRegistrar1_2Mock.bin KeeperRegistrarMock keeper_registrar_wrapper1_2_mock +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.bin KeeperRegistry keeper_registry_wrapper1_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.bin TypeAndVersionInterface type_and_version_interface_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin KeeperRegistryCheckUpkeepGasUsageWrapper gas_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin KeeperRegistryCheckUpkeepGasUsageWrapperMock gas_wrapper_mock +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.bin KeeperRegistry keeper_registry_wrapper1_3 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.bin KeeperRegistryLogic keeper_registry_logic1_3 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.bin KeeperRegistrar keeper_registrar_wrapper2_0 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.bin KeeperRegistry keeper_registry_wrapper2_0 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.bin KeeperRegistryLogic keeper_registry_logic2_0 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/UpkeepTranscoder/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder/UpkeepTranscoder.bin UpkeepTranscoder upkeep_transcoder +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.bin VerifiableLoadUpkeep verifiable_load_upkeep_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.bin VerifiableLoadStreamsLookupUpkeep verifiable_load_streams_lookup_upkeep_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.bin VerifiableLoadLogTriggerUpkeep verifiable_load_log_trigger_upkeep_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.bin StreamsLookupUpkeep streams_lookup_upkeep_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.bin StreamsLookupCompatibleInterface streams_lookup_compatible_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.bin AutomationConsumerBenchmark automation_consumer_benchmark +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.bin AutomationRegistrar automation_registrar_wrapper2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.bin KeeperRegistry keeper_registry_wrapper_2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin KeeperRegistryLogicA keeper_registry_logic_a_wrapper_2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.bin KeeperRegistryLogicB keeper_registry_logic_b_wrapper_2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin IKeeperRegistryMaster i_keeper_registry_master_wrapper_2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin ILogAutomation i_log_automation +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin AutomationUtils automation_utils_2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin AutomationForwarderLogic automation_forwarder_logic +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.bin LogUpkeepCounter log_upkeep_counter_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin LogTriggeredStreamsLookup log_triggered_streams_lookup_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.bin DummyProtocol dummy_protocol_wrapper + +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin KeeperConsumer keeper_consumer_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin KeeperConsumerPerformance keeper_consumer_performance_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin PerformDataChecker perform_data_checker_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.bin UpkeepCounter upkeep_counter_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin UpkeepPerformCounterRestrictive upkeep_perform_counter_restrictive_wrapper // v0.8.6 VRFConsumer -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock.bin VRFCoordinatorMock vrf_coordinator_mock -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer.bin VRFConsumer solidity_vrf_consumer_interface_v08 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper.bin VRFRequestIDBaseTestHelper solidity_vrf_request_id_v08 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample.bin VRFOwnerlessConsumerExample vrf_ownerless_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.bin VRFLoadTestOwnerlessConsumer vrf_load_test_ownerless_consumer -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.bin VRFLoadTestExternalSubOwner vrf_load_test_external_sub_owner -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.bin VRFV2LoadTestWithMetrics vrf_load_test_with_metrics -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.bin VRFV2OwnerTestConsumer vrf_owner_test_consumer -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer.bin VRFv2Consumer vrf_v2_consumer_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.bin VRFCoordinatorMock vrf_coordinator_mock +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.bin VRFConsumer solidity_vrf_consumer_interface_v08 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin VRFRequestIDBaseTestHelper solidity_vrf_request_id_v08 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.bin VRFOwnerlessConsumerExample vrf_ownerless_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.bin VRFLoadTestOwnerlessConsumer vrf_load_test_ownerless_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.bin VRFLoadTestExternalSubOwner vrf_load_test_external_sub_owner +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin VRFV2LoadTestWithMetrics vrf_load_test_with_metrics +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.bin VRFV2OwnerTestConsumer vrf_owner_test_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.bin VRFv2Consumer vrf_v2_consumer_wrapper //go:generate go run ./generation/generate_link/wrap_link.go // VRF V2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore.bin BlockhashStore blockhash_store -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore.bin BatchBlockhashStore batch_blockhash_store -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.bin BatchVRFCoordinatorV2 batch_vrf_coordinator_v2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner.bin VRFOwner vrf_owner -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin VRFCoordinatorV2 vrf_coordinator_v2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2.bin VRFConsumerV2 vrf_consumer_v2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2.bin VRFMaliciousConsumerV2 vrf_malicious_consumer_v2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.bin BlockhashStore blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.bin BatchBlockhashStore batch_blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin BatchVRFCoordinatorV2 batch_vrf_coordinator_v2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.bin VRFOwner vrf_owner +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.bin VRFCoordinatorV2 vrf_coordinator_v2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.bin VRFConsumerV2 vrf_consumer_v2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.bin VRFMaliciousConsumerV2 vrf_malicious_consumer_v2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFTestHelper.abi ../../contracts/solc/v0.8.6/VRFTestHelper.bin VRFV08TestHelper solidity_vrf_v08_verifier_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample.bin VRFSingleConsumerExample vrf_single_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.bin VRFV08TestHelper solidity_vrf_v08_verifier_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.bin VRFSingleConsumerExample vrf_single_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.bin VRFExternalSubOwnerExample vrf_external_sub_owner_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.bin VRFExternalSubOwnerExample vrf_external_sub_owner_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2RevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2RevertingExample.bin VRFV2RevertingExample vrfv2_reverting_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.bin VRFV2RevertingExample vrfv2_reverting_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.bin VRFConsumerV2UpgradeableExample vrf_consumer_v2_upgradeable_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.bin VRFConsumerV2UpgradeableExample vrf_consumer_v2_upgradeable_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.bin VRFV2TransparentUpgradeableProxy vrfv2_transparent_upgradeable_proxy -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.bin VRFV2ProxyAdmin vrfv2_proxy_admin -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.bin ChainSpecificUtilHelper chain_specific_util_helper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.bin VRFV2TransparentUpgradeableProxy vrfv2_transparent_upgradeable_proxy +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.bin VRFV2ProxyAdmin vrfv2_proxy_admin +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin ChainSpecificUtilHelper chain_specific_util_helper // VRF V2 Wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper.bin VRFV2Wrapper vrfv2_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface.bin VRFV2WrapperInterface vrfv2_wrapper_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample.bin VRFV2WrapperConsumerExample vrfv2_wrapper_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.bin VRFV2Wrapper vrfv2_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.bin VRFV2WrapperInterface vrfv2_wrapper_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.bin VRFV2WrapperConsumerExample vrfv2_wrapper_consumer_example // Keepers X VRF v2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer.bin KeepersVRFConsumer keepers_vrf_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin KeepersVRFConsumer keepers_vrf_consumer // VRF V2Plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal.bin IVRFCoordinatorV2PlusInternal vrf_coordinator_v2plus_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.bin BatchVRFCoordinatorV2Plus batch_vrf_coordinator_v2plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin TrustedBlockhashStore trusted_blockhash_store -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.bin VRFV2PlusConsumerExample vrfv2plus_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.bin VRFCoordinatorV2_5 vrf_coordinator_v2_5 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.bin VRFV2PlusWrapper vrfv2plus_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.bin VRFV2PlusWrapperConsumerExample vrfv2plus_wrapper_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.bin VRFMaliciousConsumerV2Plus vrf_malicious_consumer_v2_plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.bin VRFV2PlusSingleConsumerExample vrf_v2plus_single_consumer -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.bin VRFV2PlusExternalSubOwnerExample vrf_v2plus_sub_owner -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.bin VRFV2PlusRevertingExample vrfv2plus_reverting_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.bin VRFConsumerV2PlusUpgradeableExample vrf_consumer_v2_plus_upgradeable_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient.bin VRFV2PlusClient vrfv2plus_client -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.bin VRFCoordinatorV2Plus_V2Example vrf_coordinator_v2_plus_v2_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.bin VRFV2PlusMaliciousMigrator vrfv2plus_malicious_migrator -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.bin VRFV2PlusLoadTestWithMetrics vrf_v2plus_load_test_with_metrics -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.bin VRFCoordinatorV2PlusUpgradedVersion vrf_v2plus_upgraded_version -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.bin VRFV2PlusWrapperLoadTestConsumer vrfv2plus_wrapper_load_test_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin IVRFCoordinatorV2PlusInternal vrf_coordinator_v2plus_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin BatchVRFCoordinatorV2Plus batch_vrf_coordinator_v2plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.bin TrustedBlockhashStore trusted_blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin VRFV2PlusConsumerExample vrfv2plus_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin VRFCoordinatorV2_5 vrf_coordinator_v2_5 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.bin VRFV2PlusWrapper vrfv2plus_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin VRFV2PlusWrapperConsumerExample vrfv2plus_wrapper_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin VRFMaliciousConsumerV2Plus vrf_malicious_consumer_v2_plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin VRFV2PlusSingleConsumerExample vrf_v2plus_single_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin VRFV2PlusExternalSubOwnerExample vrf_v2plus_sub_owner +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin VRFV2PlusRevertingExample vrfv2plus_reverting_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin VRFConsumerV2PlusUpgradeableExample vrf_consumer_v2_plus_upgradeable_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.bin VRFV2PlusClient vrfv2plus_client +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin VRFCoordinatorV2Plus_V2Example vrf_coordinator_v2_plus_v2_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin VRFV2PlusMaliciousMigrator vrfv2plus_malicious_migrator +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin VRFV2PlusLoadTestWithMetrics vrf_v2plus_load_test_with_metrics +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin VRFCoordinatorV2PlusUpgradedVersion vrf_v2plus_upgraded_version +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin VRFV2PlusWrapperLoadTestConsumer vrfv2plus_wrapper_load_test_consumer // Aggregators -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.bin AggregatorV2V3Interface aggregator_v2v3_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV3Interface.bin AggregatorV3Interface aggregator_v3_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy.bin MockAggregatorProxy mock_aggregator_proxy +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.bin AggregatorV2V3Interface aggregator_v2v3_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.bin AggregatorV3Interface aggregator_v3_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.bin MockAggregatorProxy mock_aggregator_proxy // Log tester -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter.bin LogEmitter log_emitter +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin LogEmitter log_emitter // Chainlink Functions //go:generate go generate ./functions diff --git a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt index abc3b47db2..293defcfbe 100644 --- a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,10 +1,10 @@ GETH_VERSION: 1.12.0 -errored_verifier: ../../../contracts/solc/v0.8.16/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier.bin 510d18a58bfda646be35e46491baf73041eb333a349615465b20e2b5b41c5f73 -exposed_verifier: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -fee_manager: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin 1b852df75bfabcc2b57539e84309cd57f9e693a2bb6b25a50e4a6101ccf32c49 +errored_verifier: ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.bin 510d18a58bfda646be35e46491baf73041eb333a349615465b20e2b5b41c5f73 +exposed_verifier: ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 +fee_manager: ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.bin 1b852df75bfabcc2b57539e84309cd57f9e693a2bb6b25a50e4a6101ccf32c49 llo_feeds: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin cb71e018f67e49d7bc0e194c822204dfd59f79ff42e4fc8fd8ab63f3acd71361 llo_feeds_test: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin db73e9062b17a1d5aa14c06881fe2be49bd95b00b7f1a8943910c5e4ded5b221 -verifier: ../../../contracts/solc/v0.8.16/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier.bin df12786bbeccf3a8f3389479cf93c055b4efd5904b9f99a4835f81af43fe62bf -verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin 6393443d0a323f2dbe9687dc30fd77f8dfa918944b61c651759746ff2d76e4e5 +reward_manager: ../../../contracts/solc/v0.8.16/RewardManager/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager/RewardManager.bin db73e9062b17a1d5aa14c06881fe2be49bd95b00b7f1a8943910c5e4ded5b221 +verifier: ../../../contracts/solc/v0.8.16/Verifier/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier/Verifier.bin df12786bbeccf3a8f3389479cf93c055b4efd5904b9f99a4835f81af43fe62bf +verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy/VerifierProxy.bin 6393443d0a323f2dbe9687dc30fd77f8dfa918944b61c651759746ff2d76e4e5 werc20_mock: ../../../contracts/solc/v0.8.19/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock.bin ff2ca3928b2aa9c412c892cb8226c4d754c73eeb291bb7481c32c48791b2aa94 diff --git a/core/gethwrappers/llo-feeds/go_generate.go b/core/gethwrappers/llo-feeds/go_generate.go index 8d9e3be049..5b2088f43a 100644 --- a/core/gethwrappers/llo-feeds/go_generate.go +++ b/core/gethwrappers/llo-feeds/go_generate.go @@ -3,9 +3,9 @@ package gethwrappers // Chainlink LLO -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier.bin Verifier verifier -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin VerifierProxy verifier_proxy -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier.bin ErroredVerifier errored_verifier -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin ExposedVerifier exposed_verifier -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin RewardManager reward_manager -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin FeeManager fee_manager +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/Verifier/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier/Verifier.bin Verifier verifier +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/VerifierProxy/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy/VerifierProxy.bin VerifierProxy verifier_proxy +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.bin ErroredVerifier errored_verifier +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.bin ExposedVerifier exposed_verifier +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/RewardManager/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager/RewardManager.bin RewardManager reward_manager +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.bin FeeManager fee_manager diff --git a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 7ac7e77a4b..af907ce85e 100644 --- a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,5 +1,5 @@ GETH_VERSION: 1.12.0 -burn_mint_erc677: ../../../contracts/solc/v0.8.19/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677.bin 405c9016171e614b17e10588653ef8d33dcea21dd569c3fddc596a46fcff68a3 -erc20: ../../../contracts/solc/v0.8.19/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20.bin 5b1a93d9b24f250e49a730c96335a8113c3f7010365cba578f313b483001d4fc -link_token: ../../../contracts/solc/v0.8.19/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken.bin c0ef9b507103aae541ebc31d87d051c2764ba9d843076b30ec505d37cdfffaba -werc20_mock: ../../../contracts/solc/v0.8.19/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock.bin ff2ca3928b2aa9c412c892cb8226c4d754c73eeb291bb7481c32c48791b2aa94 +burn_mint_erc677: ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.bin 405c9016171e614b17e10588653ef8d33dcea21dd569c3fddc596a46fcff68a3 +erc20: ../../../contracts/solc/v0.8.19/ERC20/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20/ERC20.bin 5b1a93d9b24f250e49a730c96335a8113c3f7010365cba578f313b483001d4fc +link_token: ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.bin c0ef9b507103aae541ebc31d87d051c2764ba9d843076b30ec505d37cdfffaba +werc20_mock: ../../../contracts/solc/v0.8.19/WERC20Mock/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock/WERC20Mock.bin ff2ca3928b2aa9c412c892cb8226c4d754c73eeb291bb7481c32c48791b2aa94 diff --git a/core/gethwrappers/shared/go_generate.go b/core/gethwrappers/shared/go_generate.go index 85a01670c9..6f3bead7d6 100644 --- a/core/gethwrappers/shared/go_generate.go +++ b/core/gethwrappers/shared/go_generate.go @@ -2,7 +2,7 @@ // golang packages, using abigen. package gethwrappers -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677.bin BurnMintERC677 burn_mint_erc677 -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken.bin LinkToken link_token -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20.bin ERC20 erc20 -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock.bin WERC20Mock werc20_mock +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.bin BurnMintERC677 burn_mint_erc677 +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.bin LinkToken link_token +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/ERC20/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20/ERC20.bin ERC20 erc20 +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/WERC20Mock/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock/WERC20Mock.bin WERC20Mock werc20_mock diff --git a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 8ea0492fa4..a6d32bf0a8 100644 --- a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,9 +1,9 @@ GETH_VERSION: 1.12.0 -entry_point: ../../../contracts/solc/v0.8.15/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint.bin 2cb4bb2ba3efa8df3dfb0a57eb3727d17b68fe202682024fa7cfb4faf026833e +entry_point: ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.bin 2cb4bb2ba3efa8df3dfb0a57eb3727d17b68fe202682024fa7cfb4faf026833e greeter: ../../../contracts/solc/v0.8.15/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c -greeter_wrapper: ../../../contracts/solc/v0.8.15/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c -paymaster_wrapper: ../../../contracts/solc/v0.8.15/Paymaster.abi ../../../contracts/solc/v0.8.15/Paymaster.bin 189ef817a5b7a6ff53ddf35b1988465b8aec479c47b77236fe20bf7e67d48100 +greeter_wrapper: ../../../contracts/solc/v0.8.15/Greeter/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c +paymaster_wrapper: ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.abi ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.bin 189ef817a5b7a6ff53ddf35b1988465b8aec479c47b77236fe20bf7e67d48100 sca: ../../../contracts/solc/v0.8.15/SCA.abi ../../../contracts/solc/v0.8.15/SCA.bin ae0f860cdac87d4ac505edbd228bd3ea1108550453aba67aebcb61f09cf70d0b -sca_wrapper: ../../../contracts/solc/v0.8.15/SCA.abi ../../../contracts/solc/v0.8.15/SCA.bin 2a8100fbdb41e6ce917ed333a624eaa4a8984b07e2d8d8ca6bba9bc9f74b05d7 -smart_contract_account_factory: ../../../contracts/solc/v0.8.15/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.15/SmartContractAccountFactory.bin a44d6fa2dbf9cb3441d6d637d89e1cd656f28b6bf4146f58d508067474bf845b -smart_contract_account_helper: ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.bin 22f960a74bd1581a12aa4f8f438a3f265f32f43682f5c1897ca50707b9982d56 +sca_wrapper: ../../../contracts/solc/v0.8.15/SCA/SCA.abi ../../../contracts/solc/v0.8.15/SCA/SCA.bin 2a8100fbdb41e6ce917ed333a624eaa4a8984b07e2d8d8ca6bba9bc9f74b05d7 +smart_contract_account_factory: ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.bin a44d6fa2dbf9cb3441d6d637d89e1cd656f28b6bf4146f58d508067474bf845b +smart_contract_account_helper: ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.bin 22f960a74bd1581a12aa4f8f438a3f265f32f43682f5c1897ca50707b9982d56 diff --git a/core/gethwrappers/transmission/go_generate.go b/core/gethwrappers/transmission/go_generate.go index 52182a1150..54c6ecf94e 100644 --- a/core/gethwrappers/transmission/go_generate.go +++ b/core/gethwrappers/transmission/go_generate.go @@ -3,9 +3,9 @@ package gethwrappers // Transmission -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter.bin Greeter greeter_wrapper -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.15/SmartContractAccountFactory.bin SmartContractAccountFactory smart_contract_account_factory -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint.bin EntryPoint entry_point -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.bin SmartContractAccountHelper smart_contract_account_helper -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SCA.abi ../../../contracts/solc/v0.8.15/SCA.bin SCA sca_wrapper -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/Paymaster.abi ../../../contracts/solc/v0.8.15/Paymaster.bin Paymaster paymaster_wrapper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/Greeter/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter/Greeter.bin Greeter greeter_wrapper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.bin SmartContractAccountFactory smart_contract_account_factory +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.bin EntryPoint entry_point +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.bin SmartContractAccountHelper smart_contract_account_helper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SCA/SCA.abi ../../../contracts/solc/v0.8.15/SCA/SCA.bin SCA sca_wrapper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.abi ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.bin Paymaster paymaster_wrapper From 41eac0a47137b65a70caa824cdb7f2c3b7c749c6 Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Fri, 3 Nov 2023 16:31:51 +0100 Subject: [PATCH 071/327] DEVEX-1046: add functionalities to LinkMon (#11097) * DEVEX-1046: add functionalities to LinkMon * add timestamp checks * adding suggestions and remove duplicated checks * add changes and tests * polishing last details * add custom errors * rebase develop * rebase develop --- .../upkeeps/LinkAvailableBalanceMonitor.sol | 311 ++++++++-------- .../LinkAvailableBalanceMonitor.test.ts | 352 +++++++++--------- 2 files changed, 339 insertions(+), 324 deletions(-) diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index e2d42bc066..9b9dc2d6b7 100644 --- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -1,10 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.6; +pragma solidity 0.8.19; import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; @@ -35,94 +34,87 @@ interface ILinkAvailable { /// we could save a fair amount of gas and re-write this upkeep for use with Automation v2.0+, /// which has significantly different trust assumptions contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationCompatibleInterface { - using EnumerableMap for EnumerableMap.AddressToUintMap; - + event BalanceUpdated(address indexed addr, uint256 oldBalance, uint256 newBalance); event FundsWithdrawn(uint256 amountWithdrawn, address payee); - event TopUpSucceeded(address indexed topUpAddress); + event UpkeepIntervalSet(uint256 oldUpkeepInterval, uint256 newUpkeepInterval); + event MaxCheckSet(uint256 oldMaxCheck, uint256 newMaxCheck); + event MaxPerformSet(uint256 oldMaxPerform, uint256 newMaxPerform); + event MinWaitPeriodSet(uint256 s_minWaitPeriodSeconds, uint256 minWaitPeriodSeconds); event TopUpBlocked(address indexed topUpAddress); + event TopUpFailed(address indexed recipient); + event TopUpSucceeded(address indexed topUpAddress); + event TopUpUpdated(address indexed addr, uint256 oldTopUpAmount, uint256 newTopUpAmount); event WatchlistUpdated(); - event MaxPerformUpdated(uint256 oldMaxPerform, uint256 newMaxPerform); - event MaxCheckUpdated(uint256 oldMaxCheck, uint256 newMaxCheck); + error InvalidAddress(address target); + error InvalidMaxCheck(uint16 maxCheck); + error InvalixMaxPerform(uint16 maxPerform); + error InvalidMinBalance(uint96 minBalance); + error InvalidTopUpAmount(uint96 topUpAmount); + error InvalidUpkeepInterval(uint8 upkeepInterval); + error InvalidLinkTokenAddress(address lt); error InvalidWatchList(); error DuplicateAddress(address duplicate); + struct MonitoredAddress { + uint96 minBalance; + uint96 topUpAmount; + uint56 lastTopUpTimestamp; + bool isActive; + } + IERC20 private immutable LINK_TOKEN; - EnumerableMap.AddressToUintMap private s_watchList; - uint256 private s_topUpAmount; - uint32 private s_minWaitPeriodSeconds; + uint256 private s_minWaitPeriodSeconds; uint16 private s_maxPerform; uint16 private s_maxCheck; + uint8 private s_upkeepInterval; + address[] private s_watchList; + mapping(address targetAddress => MonitoredAddress targetProperties) internal s_targets; /// @param linkTokenAddress the LINK token address - /// @param topUpAmount the amount of LINK to top up an aggregator with at once constructor( address linkTokenAddress, - uint256 topUpAmount, + uint256 minWaitPeriodSeconds, uint16 maxPerform, - uint16 maxCheck + uint16 maxCheck, + uint8 upkeepInterval ) ConfirmedOwner(msg.sender) { - require(linkTokenAddress != address(0), "LinkAvailableBalanceMonitor: invalid linkTokenAddress"); - require(topUpAmount > 0, "LinkAvailableBalanceMonitor: invalid topUpAmount"); + if (linkTokenAddress == address(0)) revert InvalidLinkTokenAddress(linkTokenAddress); LINK_TOKEN = IERC20(linkTokenAddress); - s_topUpAmount = topUpAmount; - s_maxPerform = maxPerform; - s_maxCheck = maxCheck; + setMinWaitPeriodSeconds(minWaitPeriodSeconds); + setMaxPerform(maxPerform); + setMaxCheck(maxCheck); + setUpkeepInterval(upkeepInterval); } /// @notice Sets the list of subscriptions to watch and their funding parameters /// @param addresses the list of target addresses to watch (could be direct target or IAggregatorProxy) /// @param minBalances the list of corresponding minBalance for the target address - function setWatchList(address[] calldata addresses, uint256[] calldata minBalances) external onlyOwner { - if (addresses.length != minBalances.length) { - revert InvalidWatchList(); - } - // first, remove all existing addresses from list - for (uint256 idx = s_watchList.length(); idx > 0; idx--) { - (address target, ) = s_watchList.at(idx - 1); - require(s_watchList.remove(target), "LinkAvailableBalanceMonitor: unable to setWatchlist"); - } - // then set new addresses - for (uint256 idx = 0; idx < addresses.length; idx++) { - if (s_watchList.contains(addresses[idx])) { - revert DuplicateAddress(addresses[idx]); - } - if (addresses[idx] == address(0)) { - revert InvalidWatchList(); - } - s_watchList.set(addresses[idx], minBalances[idx]); - } - emit WatchlistUpdated(); - } - - /// @notice Adds addresses to the watchlist without overwriting existing members - /// @param addresses the list of target addresses to watch (could be direct target or IAggregatorProxy) - /// @param minBalances the list of corresponding minBalance for the target address - function addToWatchList(address[] calldata addresses, uint256[] calldata minBalances) external onlyOwner { - if (addresses.length != minBalances.length) { + /// @param topUpAmounts the list of corresponding minTopUp for the target address + function setWatchList( + address[] calldata addresses, + uint96[] calldata minBalances, + uint96[] calldata topUpAmounts + ) external onlyOwner { + if (addresses.length != minBalances.length || addresses.length != topUpAmounts.length) { revert InvalidWatchList(); } - for (uint256 idx = 0; idx < addresses.length; idx++) { - if (s_watchList.contains(addresses[idx])) { - revert DuplicateAddress(addresses[idx]); - } - if (addresses[idx] == address(0)) { - revert InvalidWatchList(); - } - s_watchList.set(addresses[idx], minBalances[idx]); + for (uint256 idx = 0; idx < s_watchList.length; idx++) { + delete s_targets[s_watchList[idx]]; } - emit WatchlistUpdated(); - } - - /// @notice Removes addresses from the watchlist - /// @param addresses the list of target addresses to remove from the watchlist - function removeFromWatchlist(address[] calldata addresses) external onlyOwner { for (uint256 idx = 0; idx < addresses.length; idx++) { - if (!s_watchList.contains(addresses[idx])) { - revert InvalidWatchList(); - } - s_watchList.remove(addresses[idx]); + address targetAddress = addresses[idx]; + if (s_targets[targetAddress].isActive) revert DuplicateAddress(addresses[idx]); + if (addresses[idx] == address(0)) revert InvalidWatchList(); + if (topUpAmounts[idx] == 0) revert InvalidWatchList(); + s_targets[targetAddress] = MonitoredAddress({ + isActive: true, + minBalance: minBalances[idx], + topUpAmount: topUpAmounts[idx], + lastTopUpTimestamp: 0 + }); } + s_watchList = addresses; emit WatchlistUpdated(); } @@ -135,20 +127,21 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp function sampleUnderfundedAddresses() public view returns (address[] memory) { uint16 maxPerform = s_maxPerform; uint16 maxCheck = s_maxCheck; - uint256 numTargets = s_watchList.length(); - uint256 idx = uint256(blockhash(block.number - 1)) % numTargets; // start at random index, to distribute load + uint256 numTargets = s_watchList.length; + uint256 idx = uint256(blockhash(block.number - (block.number % s_upkeepInterval) - 1)) % numTargets; uint256 numToCheck = numTargets < maxCheck ? numTargets : maxCheck; uint256 numFound = 0; address[] memory targetsToFund = new address[](maxPerform); + MonitoredAddress memory target; for ( uint256 numChecked = 0; numChecked < numToCheck; (idx, numChecked) = ((idx + 1) % numTargets, numChecked + 1) ) { - (address target, uint256 minBalance) = s_watchList.at(idx); - (bool needsFunding, ) = _needsFunding(target, minBalance); - if (needsFunding) { - targetsToFund[numFound] = target; + address targetAddress = s_watchList[idx]; + target = s_targets[targetAddress]; + if (_needsFunding(targetAddress, target.minBalance)) { + targetsToFund[numFound] = targetAddress; numFound++; if (numFound == maxPerform) { break; // max number of addresses in batch reached @@ -163,29 +156,59 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp return targetsToFund; } - /// @notice Send funds to the targets provided. - /// @param targetAddresses the list of targets to fund function topUp(address[] memory targetAddresses) public whenNotPaused { - uint256 topUpAmount = s_topUpAmount; - uint256 stopIdx = targetAddresses.length; - uint256 numCanFund = LINK_TOKEN.balanceOf(address(this)) / topUpAmount; - stopIdx = numCanFund < stopIdx ? numCanFund : stopIdx; - for (uint256 idx = 0; idx < stopIdx; idx++) { - (bool exists, uint256 minBalance) = s_watchList.tryGet(targetAddresses[idx]); - if (!exists) { - emit TopUpBlocked(targetAddresses[idx]); - continue; - } - (bool needsFunding, address target) = _needsFunding(targetAddresses[idx], minBalance); - if (!needsFunding) { - emit TopUpBlocked(targetAddresses[idx]); - continue; + MonitoredAddress memory target; + uint256 localBalance = LINK_TOKEN.balanceOf(address(this)); + for (uint256 idx = 0; idx < targetAddresses.length; idx++) { + address targetAddress = targetAddresses[idx]; + target = s_targets[targetAddress]; + if (localBalance >= target.topUpAmount && _needsFunding(targetAddress, target.minBalance)) { + bool success = LINK_TOKEN.transfer(targetAddress, target.topUpAmount); + if (success) { + localBalance -= target.topUpAmount; + target.lastTopUpTimestamp = uint56(block.timestamp); + emit TopUpSucceeded(targetAddress); + } else { + emit TopUpFailed(targetAddress); + } + } else { + emit TopUpBlocked(targetAddress); } - LINK_TOKEN.transfer(target, topUpAmount); - emit TopUpSucceeded(targetAddresses[idx]); } } + /// @notice checks the target (could be direct target or IAggregatorProxy), and determines + /// if it is elligible for funding + /// @param targetAddress the target to check + /// @param minBalance minimum balance required for the target + /// @return bool whether the target needs funding or not + function _needsFunding(address targetAddress, uint256 minBalance) private view returns (bool) { + // Explicitly check if the targetAddress is the zero address + // or if it's not a contract. In both cases return with false, + // to prevent target.linkAvailableForPayment from running, + // which would revert the operation. + if (targetAddress == address(0) || targetAddress.code.length == 0) { + return false; + } + MonitoredAddress memory addressToCheck = s_targets[targetAddress]; + ILinkAvailable target; + IAggregatorProxy proxy = IAggregatorProxy(targetAddress); + try proxy.aggregator() returns (address aggregatorAddress) { + if (aggregatorAddress == address(0)) return false; + target = ILinkAvailable(aggregatorAddress); + } catch { + target = ILinkAvailable(targetAddress); + } + try target.linkAvailableForPayment() returns (int256 balance) { + if ( + balance < int256(minBalance) && addressToCheck.lastTopUpTimestamp + s_minWaitPeriodSeconds <= block.timestamp + ) { + return true; + } + } catch {} + return false; + } + /// @notice Gets list of subscription ids that are underfunded and returns a keeper-compatible payload. /// @return upkeepNeeded signals if upkeep is needed /// @return performData is an abi encoded list of subscription ids that need funds @@ -193,12 +216,6 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp bytes calldata ) external view override whenNotPaused returns (bool upkeepNeeded, bytes memory performData) { address[] memory needsFunding = sampleUnderfundedAddresses(); - uint256 numCanFund = LINK_TOKEN.balanceOf(address(this)) / s_topUpAmount; - if (numCanFund < needsFunding.length) { - assembly { - mstore(needsFunding, numCanFund) // resize - } - } upkeepNeeded = needsFunding.length > 0; performData = abi.encode(needsFunding); return (upkeepNeeded, performData); @@ -215,38 +232,54 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp /// @param amount the amount of the LINK to withdraw /// @param payee the address to pay function withdraw(uint256 amount, address payable payee) external onlyOwner { - require(payee != address(0), "LinkAvailableBalanceMonitor: invalid payee address"); + if (payee == address(0)) revert InvalidAddress(payee); LINK_TOKEN.transfer(payee, amount); emit FundsWithdrawn(amount, payee); } - /// @notice Sets the top up amount - function setTopUpAmount(uint256 topUpAmount) external onlyOwner returns (uint256) { - require(topUpAmount > 0, "LinkAvailableBalanceMonitor: invalid linkTokenAddress"); - return s_topUpAmount = topUpAmount; + /// @notice Sets the minimum balance for the given target address + function setMinBalance(address target, uint96 minBalance) external onlyOwner { + if (target == address(0)) revert InvalidAddress(target); + if (minBalance == 0) revert InvalidMinBalance(minBalance); + if (!s_targets[target].isActive) revert InvalidWatchList(); + uint256 oldBalance = s_targets[target].minBalance; + s_targets[target].minBalance = minBalance; + emit BalanceUpdated(target, oldBalance, minBalance); } /// @notice Sets the minimum balance for the given target address - function setMinBalance(address target, uint256 minBalance) external onlyOwner returns (uint256) { - require(minBalance > 0, "LinkAvailableBalanceMonitor: invalid minBalance"); - (bool exists, uint256 prevMinBalance) = s_watchList.tryGet(target); - if (!exists) { - revert InvalidWatchList(); - } - s_watchList.set(target, minBalance); - return prevMinBalance; + function setTopUpAmount(address target, uint96 topUpAmount) external onlyOwner { + if (target == address(0)) revert InvalidAddress(target); + if (topUpAmount == 0) revert InvalidTopUpAmount(topUpAmount); + if (!s_targets[target].isActive) revert InvalidWatchList(); + uint256 oldTopUpAmount = s_targets[target].topUpAmount; + s_targets[target].topUpAmount = topUpAmount; + emit BalanceUpdated(target, oldTopUpAmount, topUpAmount); } /// @notice Update s_maxPerform - function setMaxPerform(uint16 maxPerform) external onlyOwner { - emit MaxPerformUpdated(s_maxPerform, maxPerform); + function setMaxPerform(uint16 maxPerform) public onlyOwner { s_maxPerform = maxPerform; + emit MaxPerformSet(s_maxPerform, maxPerform); } /// @notice Update s_maxCheck - function setMaxCheck(uint16 maxCheck) external onlyOwner { - emit MaxCheckUpdated(s_maxCheck, maxCheck); + function setMaxCheck(uint16 maxCheck) public onlyOwner { s_maxCheck = maxCheck; + emit MaxCheckSet(s_maxCheck, maxCheck); + } + + /// @notice Sets the minimum wait period (in seconds) for addresses between funding + function setMinWaitPeriodSeconds(uint256 minWaitPeriodSeconds) public onlyOwner { + s_minWaitPeriodSeconds = minWaitPeriodSeconds; + emit MinWaitPeriodSet(s_minWaitPeriodSeconds, minWaitPeriodSeconds); + } + + /// @notice Update s_upkeepInterval + function setUpkeepInterval(uint8 upkeepInterval) public onlyOwner { + if (upkeepInterval > 255) revert InvalidUpkeepInterval(upkeepInterval); + s_upkeepInterval = upkeepInterval; + emit UpkeepIntervalSet(s_upkeepInterval, upkeepInterval); } /// @notice Gets maxPerform @@ -259,31 +292,27 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp return s_maxCheck; } - /// @notice Gets the list of subscription ids being watched - function getWatchList() external view returns (address[] memory, uint256[] memory) { - uint256 len = s_watchList.length(); - address[] memory targets = new address[](len); - uint256[] memory minBalances = new uint256[](len); - - for (uint256 idx = 0; idx < len; idx++) { - (targets[idx], minBalances[idx]) = s_watchList.at(idx); - } + /// @notice Gets the minimum wait period + function getMinWaitPeriodSeconds() external view returns (uint256) { + return s_minWaitPeriodSeconds; + } - return (targets, minBalances); + /// @notice Gets upkeepInterval + function getUpkeepInterval() external view returns (uint8) { + return s_upkeepInterval; } - /// @notice Gets the configured top up amount - function getTopUpAmount() external view returns (uint256) { - return s_topUpAmount; + /// @notice Gets the list of subscription ids being watched + function getWatchList() external view returns (address[] memory) { + return s_watchList; } - /// @notice Gets the configured minimum balance for the given target - function getMinBalance(address target) external view returns (uint256) { - (bool exists, uint256 minBalance) = s_watchList.tryGet(target); - if (!exists) { - revert InvalidWatchList(); - } - return minBalance; + /// @notice Gets configuration information for an address on the watchlist + function getAccountInfo( + address targetAddress + ) external view returns (bool isActive, uint256 minBalance, uint256 topUpAmount) { + MonitoredAddress memory target = s_targets[targetAddress]; + return (target.isActive, target.minBalance, target.topUpAmount); } /// @notice Pause the contract, which prevents executing performUpkeep @@ -295,26 +324,4 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp function unpause() external onlyOwner { _unpause(); } - - /// @notice checks the target (could be direct target or IAggregatorProxy), and determines - /// if it is elligible for funding - /// @param targetAddress the target to check - /// @param minBalance minimum balance required for the target - /// @return bool whether the target needs funding or not - /// @return address the address of the contract needing funding - function _needsFunding(address targetAddress, uint256 minBalance) private view returns (bool, address) { - ILinkAvailable target; - IAggregatorProxy proxy = IAggregatorProxy(targetAddress); - try proxy.aggregator() returns (address aggregatorAddress) { - target = ILinkAvailable(aggregatorAddress); - } catch { - target = ILinkAvailable(targetAddress); - } - try target.linkAvailableForPayment() returns (int256 balance) { - if (balance < 0 || uint256(balance) < minBalance) { - return (true, address(target)); - } - } catch {} - return (false, address(0)); - } } diff --git a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts index af0063fb50..76a3dcfff1 100644 --- a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts @@ -34,6 +34,7 @@ const PAUSED_ERR = 'Pausable: paused' const zeroLINK = ethers.utils.parseEther('0') const oneLINK = ethers.utils.parseEther('1') const twoLINK = ethers.utils.parseEther('2') +const fourLINK = ethers.utils.parseEther('4') const fiveLINK = ethers.utils.parseEther('5') const tenLINK = ethers.utils.parseEther('10') const oneHundredLINK = ethers.utils.parseEther('100') @@ -59,6 +60,7 @@ let directTarget2: MockContract let watchListAddresses: string[] let watchListMinBalances: BigNumber[] +let watchListTopUpAmounts: BigNumber[] async function assertContractLinkBalances( balance1: BigNumber, @@ -120,6 +122,7 @@ const setup = async () => { directTarget2.address, ] watchListMinBalances = [oneLINK, oneLINK, oneLINK, twoLINK, twoLINK] + watchListTopUpAmounts = [twoLINK, twoLINK, twoLINK, twoLINK, twoLINK] await proxy1.mock.aggregator.returns(aggregator1.address) await proxy2.mock.aggregator.returns(aggregator2.address) @@ -144,9 +147,17 @@ const setup = async () => { // New parameters needed by the constructor const maxPerform = 5 const maxCheck = 20 + const minWaitPeriodSeconds = 0 + const upkeepInterval = 10 lt = (await ltFactory.deploy()) as LinkToken - labm = await labmFactory.deploy(lt.address, twoLINK, maxPerform, maxCheck) + labm = await labmFactory.deploy( + lt.address, + minWaitPeriodSeconds, + maxPerform, + maxCheck, + upkeepInterval, + ) await labm.deployed() for (let i = 1; i <= 4; i++) { @@ -156,7 +167,11 @@ const setup = async () => { const setTx = await labm .connect(owner) - .setWatchList(watchListAddresses, watchListMinBalances) + .setWatchList( + watchListAddresses, + watchListMinBalances, + watchListTopUpAmounts, + ) await setTx.wait() } @@ -174,19 +189,27 @@ describe('LinkAvailableBalanceMonitor', () => { describe('setTopUpAmount()', () => { it('configures the top-up amount', async () => { - await labm.connect(owner).setTopUpAmount(100) - assert.equal((await labm.getTopUpAmount()).toNumber(), 100) + await labm + .connect(owner) + .setTopUpAmount(directTarget1.address, BigNumber.from(100)) + const report = await labm.getAccountInfo(directTarget1.address) + assert.equal(report.topUpAmount.toString(), '100') }) it('configuresis only callable by the owner', async () => { - await expect(labm.connect(stranger).setTopUpAmount(100)).to.be.reverted + await expect( + labm.connect(stranger).setTopUpAmount(directTarget1.address, 100), + ).to.be.reverted }) }) describe('setMinBalance()', () => { it('configures the min balance', async () => { - await labm.connect(owner).setMinBalance(proxy1.address, 100) - assert.equal((await labm.getMinBalance(proxy1.address)).toNumber(), 100) + await labm + .connect(owner) + .setMinBalance(proxy1.address, BigNumber.from(100)) + const report = await labm.getAccountInfo(proxy1.address) + assert.equal(report.minBalance.toString(), '100') }) it('reverts if address is not in the watchlist', async () => { @@ -266,66 +289,29 @@ describe('LinkAvailableBalanceMonitor', () => { beforeEach(async () => { // reset watchlist to empty before running these tests - await labm.connect(owner).setWatchList([], []) - let watchList = await labm.getWatchList() - assert.deepEqual(watchList, [[], []]) + await labm.connect(owner).setWatchList([], [], []) + const watchList = await labm.getWatchList() + assert.deepEqual(watchList, []) }) it('Should allow owner to adjust the watchlist', async () => { // add first watchlist let tx = await labm .connect(owner) - .setWatchList([watchAddress1], [oneLINK]) + .setWatchList([watchAddress1], [oneLINK], [oneLINK]) let watchList = await labm.getWatchList() - assert.deepEqual(watchList[0], [watchAddress1]) - assert.deepEqual( - watchList[1].map((x) => x.toString()), - [oneLINK].map((x) => x.toString()), - ) + assert.deepEqual(watchList[0], watchAddress1) // add more to watchlist tx = await labm .connect(owner) .setWatchList( [watchAddress1, watchAddress2, watchAddress3], [oneLINK, oneLINK, oneLINK], + [oneLINK, oneLINK, oneLINK], ) await tx.wait() watchList = await labm.getWatchList() - assert.deepEqual(watchList[0], [ - watchAddress1, - watchAddress2, - watchAddress3, - ]) - assert.deepEqual( - watchList[1].map((x) => x.toString()), - [oneLINK, oneLINK, oneLINK].map((x) => x.toString()), - ) - // remove some from watchlist - tx = await labm - .connect(owner) - .removeFromWatchlist([watchAddress3, watchAddress1]) - await tx.wait() - watchList = await labm.getWatchList() - assert.deepEqual(watchList[0], [watchAddress2]) - assert.deepEqual( - watchList[1].map((x) => x.toString()), - [oneLINK].map((x) => x.toString()), - ) - // add some to watchlist - tx = await labm - .connect(owner) - .addToWatchList([watchAddress1, watchAddress3], [twoLINK, twoLINK]) - await tx.wait() - watchList = await labm.getWatchList() - assert.deepEqual(watchList[0], [ - watchAddress2, - watchAddress1, - watchAddress3, - ]) - assert.deepEqual( - watchList[1].map((x) => x.toString()), - [oneLINK, twoLINK, twoLINK].map((x) => x.toString()), - ) + assert.deepEqual(watchList, [watchAddress1, watchAddress2, watchAddress3]) }) it('Should not allow different length arrays in the watchlist', async () => { @@ -335,6 +321,7 @@ describe('LinkAvailableBalanceMonitor', () => { .setWatchList( [watchAddress1, watchAddress2, watchAddress1], [oneLINK, oneLINK], + [oneLINK, oneLINK], ) await expect(tx).to.be.revertedWith(errMsg) }) @@ -346,12 +333,6 @@ describe('LinkAvailableBalanceMonitor', () => { .setWatchList( [watchAddress1, watchAddress2, watchAddress1], [oneLINK, oneLINK, oneLINK], - ) - await expect(tx).to.be.revertedWith(errMsg) - tx = labm - .connect(owner) - .addToWatchList( - [watchAddress1, watchAddress2, watchAddress1], [oneLINK, oneLINK, oneLINK], ) await expect(tx).to.be.revertedWith(errMsg) @@ -360,14 +341,8 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should not allow strangers to set the watchlist', async () => { const setTxStranger = labm .connect(stranger) - .setWatchList([watchAddress1], [oneLINK]) + .setWatchList([watchAddress1], [oneLINK], [oneLINK]) await expect(setTxStranger).to.be.revertedWith(OWNABLE_ERR) - const addTxStranger = labm - .connect(stranger) - .addToWatchList([watchAddress1], [oneLINK]) - await expect(addTxStranger).to.be.revertedWith(OWNABLE_ERR) - const removeTxStranger = labm.connect(stranger).removeFromWatchlist([]) - await expect(removeTxStranger).to.be.revertedWith(OWNABLE_ERR) }) it('Should revert if any of the addresses are empty', async () => { @@ -376,12 +351,6 @@ describe('LinkAvailableBalanceMonitor', () => { .setWatchList( [watchAddress1, ethers.constants.AddressZero], [oneLINK, oneLINK], - ) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) - tx = labm - .connect(owner) - .addToWatchList( - [watchAddress1, ethers.constants.AddressZero], [oneLINK, oneLINK], ) await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) @@ -390,69 +359,68 @@ describe('LinkAvailableBalanceMonitor', () => { describe('checkUpkeep() / sampleUnderfundedAddresses() [ @skip-coverage ]', () => { it('Should return list of address that are underfunded', async () => { - const fundTx = await lt.connect(owner).transfer( - labm.address, - tenLINK, // needs 10 total - ) + const fundTx = await lt + .connect(owner) + .transfer(labm.address, oneHundredLINK) await fundTx.wait() + + await labm.setWatchList( + watchListAddresses, + watchListMinBalances, + watchListTopUpAmounts, + ) + const [should, payload] = await labm.checkUpkeep('0x') assert.isTrue(should) let [addresses] = ethers.utils.defaultAbiCoder.decode( ['address[]'], payload, ) + expect(addresses).to.deep.equalInAnyOrder(watchListAddresses) - // checkUpkeep payload should match sampleUnderfundedAddresses() addresses = await labm.sampleUnderfundedAddresses() expect(addresses).to.deep.equalInAnyOrder(watchListAddresses) }) - it('Should return some results even if contract cannot fund all eligible targets', async () => { + it('Should omit aggregators that have sufficient funding', async () => { const fundTx = await lt.connect(owner).transfer( labm.address, - fiveLINK, // needs 2Link per contract, so can fund 2 max + oneHundredLINK, // enough for anything that needs funding ) await fundTx.wait() - const [should, payload] = await labm.checkUpkeep('0x') - assert.isTrue(should) - let [addresses] = ethers.utils.defaultAbiCoder.decode( - ['address[]'], - payload, + + await labm.setWatchList( + [aggregator2.address, directTarget1.address, directTarget2.address], + [oneLINK, twoLINK, twoLINK], + [oneLINK, oneLINK, oneLINK], ) - assert.equal(addresses.length, 2) - assert.notEqual(addresses[0], addresses[1]) - assert(watchListAddresses.includes(addresses[0])) - assert(watchListAddresses.includes(addresses[1])) - // underfunded sample should still match list - addresses = await labm.sampleUnderfundedAddresses() - expect(addresses).to.deep.equalInAnyOrder(watchListAddresses) - }) - it('Should omit aggregators that have sufficient funding', async () => { + // all of them are underfunded, return 3 + await aggregator2.mock.linkAvailableForPayment.returns(zeroLINK) + await directTarget1.mock.linkAvailableForPayment.returns(zeroLINK) + await directTarget2.mock.linkAvailableForPayment.returns(zeroLINK) + let addresses = await labm.sampleUnderfundedAddresses() - expect(addresses).to.deep.equalInAnyOrder(watchListAddresses) - await aggregator2.mock.linkAvailableForPayment.returns(oneLINK) // aggregator2 is enough funded - await directTarget1.mock.linkAvailableForPayment.returns(oneLINK) // directTarget1 is NOT enough funded - await directTarget2.mock.linkAvailableForPayment.returns(twoLINK) // directTarget2 is enough funded - addresses = await labm.sampleUnderfundedAddresses() expect(addresses).to.deep.equalInAnyOrder([ - proxy1.address, - proxy3.address, + aggregator2.address, directTarget1.address, + directTarget2.address, ]) - await aggregator1.mock.linkAvailableForPayment.returns(tenLINK) + await aggregator2.mock.linkAvailableForPayment.returns(oneLINK) // aggregator2 is enough funded + await directTarget1.mock.linkAvailableForPayment.returns(oneLINK) // directTarget1 is NOT enough funded + await directTarget2.mock.linkAvailableForPayment.returns(oneLINK) // directTarget2 is NOT funded addresses = await labm.sampleUnderfundedAddresses() expect(addresses).to.deep.equalInAnyOrder([ - proxy3.address, directTarget1.address, + directTarget2.address, ]) - await aggregator3.mock.linkAvailableForPayment.returns(tenLINK) + await directTarget1.mock.linkAvailableForPayment.returns(tenLINK) addresses = await labm.sampleUnderfundedAddresses() - expect(addresses).to.deep.equalInAnyOrder([directTarget1.address]) + expect(addresses).to.deep.equalInAnyOrder([directTarget2.address]) - await directTarget1.mock.linkAvailableForPayment.returns(tenLINK) + await directTarget2.mock.linkAvailableForPayment.returns(tenLINK) addresses = await labm.sampleUnderfundedAddresses() expect(addresses).to.deep.equalInAnyOrder([]) }) @@ -471,6 +439,7 @@ describe('LinkAvailableBalanceMonitor', () => { let MAX_CHECK: number let proxyAddresses: string[] let minBalances: BigNumber[] + let topUpAmount: BigNumber[] let aggregators: MockContract[] beforeEach(async () => { @@ -478,6 +447,7 @@ describe('LinkAvailableBalanceMonitor', () => { MAX_CHECK = await labm.getMaxCheck() proxyAddresses = [] minBalances = [] + topUpAmount = [] aggregators = [] const numAggregators = MAX_CHECK + 50 for (let idx = 0; idx < numAggregators; idx++) { @@ -493,18 +463,18 @@ describe('LinkAvailableBalanceMonitor', () => { await aggregator.mock.linkAvailableForPayment.returns(0) proxyAddresses.push(proxy.address) minBalances.push(oneLINK) + topUpAmount.push(oneLINK) aggregators.push(aggregator) } - await labm.setWatchList(proxyAddresses, minBalances) - expect(await labm.getWatchList()).to.deep.equalInAnyOrder([ - proxyAddresses, - minBalances, - ]) + await labm.setWatchList(proxyAddresses, minBalances, topUpAmount) + let watchlist = await labm.getWatchList() + expect(watchlist).to.deep.equalInAnyOrder(proxyAddresses) + assert.equal(watchlist.length, minBalances.length) }) it('Should not include more than MAX_PERFORM addresses', async () => { const addresses = await labm.sampleUnderfundedAddresses() - assert.equal(addresses.length, MAX_PERFORM) + expect(addresses.length).to.be.lessThanOrEqual(MAX_PERFORM) }) it('Should sample from the list of addresses pseudorandomly', async () => { @@ -547,7 +517,11 @@ describe('LinkAvailableBalanceMonitor', () => { ) await labm .connect(owner) - .setWatchList(watchListAddresses, watchListMinBalances) + .setWatchList( + watchListAddresses, + watchListMinBalances, + watchListTopUpAmounts, + ) }) it('Should revert when paused', async () => { @@ -557,32 +531,38 @@ describe('LinkAvailableBalanceMonitor', () => { }) it('Should fund the appropriate addresses', async () => { - await lt.connect(owner).transfer(labm.address, tenLINK) - await assertContractLinkBalances( - zeroLINK, - zeroLINK, - zeroLINK, - zeroLINK, - zeroLINK, - ) + await aggregator1.mock.linkAvailableForPayment.returns(zeroLINK) + await aggregator2.mock.linkAvailableForPayment.returns(zeroLINK) + await aggregator3.mock.linkAvailableForPayment.returns(zeroLINK) + await directTarget1.mock.linkAvailableForPayment.returns(zeroLINK) + await directTarget2.mock.linkAvailableForPayment.returns(zeroLINK) + + const fundTx = await lt.connect(owner).transfer(labm.address, tenLINK) + await fundTx.wait() + + h.assertLinkTokenBalance(lt, aggregator1.address, zeroLINK) + h.assertLinkTokenBalance(lt, aggregator2.address, zeroLINK) + h.assertLinkTokenBalance(lt, aggregator3.address, zeroLINK) + h.assertLinkTokenBalance(lt, directTarget1.address, zeroLINK) + h.assertLinkTokenBalance(lt, directTarget2.address, zeroLINK) + const performTx = await labm .connect(keeperRegistry) - .performUpkeep(validPayload, { gasLimit: 2_500_000 }) + .performUpkeep(validPayload, { gasLimit: 1_500_000 }) await performTx.wait() - await assertContractLinkBalances( - twoLINK, - twoLINK, - twoLINK, - twoLINK, - twoLINK, - ) + + h.assertLinkTokenBalance(lt, aggregator1.address, twoLINK) + h.assertLinkTokenBalance(lt, aggregator2.address, twoLINK) + h.assertLinkTokenBalance(lt, aggregator3.address, twoLINK) + h.assertLinkTokenBalance(lt, directTarget1.address, twoLINK) + h.assertLinkTokenBalance(lt, directTarget2.address, twoLINK) }) it('Can handle MAX_PERFORM proxies within gas limit', async () => { - // add MAX_PERFORM number of proxies const MAX_PERFORM = await labm.getMaxPerform() const proxyAddresses = [] const minBalances = [] + const topUpAmount = [] for (let idx = 0; idx < MAX_PERFORM; idx++) { const proxy = await deployMockContract( owner, @@ -596,20 +576,29 @@ describe('LinkAvailableBalanceMonitor', () => { await aggregator.mock.linkAvailableForPayment.returns(0) proxyAddresses.push(proxy.address) minBalances.push(oneLINK) + topUpAmount.push(oneLINK) } - await labm.setWatchList(proxyAddresses, minBalances) - expect(await labm.getWatchList()).to.deep.equalInAnyOrder([ - proxyAddresses, - minBalances, - ]) + await labm.setWatchList(proxyAddresses, minBalances, topUpAmount) + let watchlist = await labm.getWatchList() + expect(watchlist).to.deep.equalInAnyOrder(proxyAddresses) + assert.equal(watchlist.length, minBalances.length) + // add funds - const fundsNeeded = (await labm.getTopUpAmount()).mul(MAX_PERFORM) + const wl = await labm.getWatchList() + let fundsNeeded = BigNumber.from(0) + for (let idx = 0; idx < wl.length; idx++) { + const targetInfo = await labm.getAccountInfo(wl[idx]) + const targetTopUpAmount = targetInfo.topUpAmount + fundsNeeded.add(targetTopUpAmount) + } await lt.connect(owner).transfer(labm.address, fundsNeeded) + // encode payload const payload = ethers.utils.defaultAbiCoder.encode( ['address[]'], [proxyAddresses], ) + // do the thing await labm .connect(keeperRegistry) @@ -618,6 +607,11 @@ describe('LinkAvailableBalanceMonitor', () => { }) describe('topUp()', () => { + it('Should revert topUp address(0)', async () => { + const tx = await labm.connect(owner).topUp([ethers.constants.AddressZero]) + await expect(tx).to.emit(labm, 'TopUpBlocked') + }) + context('when not paused', () => { it('Should be callable by anyone', async () => { const users = [owner, keeperRegistry, stranger] @@ -654,13 +648,13 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should fund the appropriate addresses', async () => { const tx = await labm.connect(keeperRegistry).topUp(watchListAddresses) - await assertContractLinkBalances( - twoLINK, - twoLINK, - twoLINK, - twoLINK, - twoLINK, - ) + + await aggregator1.mock.linkAvailableForPayment.returns(twoLINK) + await aggregator2.mock.linkAvailableForPayment.returns(twoLINK) + await aggregator3.mock.linkAvailableForPayment.returns(twoLINK) + await directTarget1.mock.linkAvailableForPayment.returns(twoLINK) + await directTarget2.mock.linkAvailableForPayment.returns(twoLINK) + await expect(tx) .to.emit(labm, 'TopUpSucceeded') .withArgs(proxy1.address) @@ -682,13 +676,12 @@ describe('LinkAvailableBalanceMonitor', () => { await labm .connect(keeperRegistry) .topUp([proxy1.address, directTarget1.address]) - await assertContractLinkBalances( - twoLINK, - zeroLINK, - zeroLINK, - twoLINK, - zeroLINK, - ) + + await aggregator1.mock.linkAvailableForPayment.returns(twoLINK) + await aggregator2.mock.linkAvailableForPayment.returns(zeroLINK) + await aggregator3.mock.linkAvailableForPayment.returns(zeroLINK) + await directTarget1.mock.linkAvailableForPayment.returns(twoLINK) + await directTarget2.mock.linkAvailableForPayment.returns(zeroLINK) }) it('Should skip un-approved addresses', async () => { @@ -697,6 +690,7 @@ describe('LinkAvailableBalanceMonitor', () => { .setWatchList( [proxy1.address, directTarget1.address], [oneLINK, oneLINK], + [oneLINK, oneLINK], ) const tx = await labm .connect(keeperRegistry) @@ -707,13 +701,13 @@ describe('LinkAvailableBalanceMonitor', () => { directTarget1.address, directTarget2.address, ]) - await assertContractLinkBalances( - twoLINK, - zeroLINK, - zeroLINK, - twoLINK, - zeroLINK, - ) + + h.assertLinkTokenBalance(lt, aggregator1.address, twoLINK) + h.assertLinkTokenBalance(lt, aggregator2.address, zeroLINK) + h.assertLinkTokenBalance(lt, aggregator3.address, zeroLINK) + h.assertLinkTokenBalance(lt, directTarget1.address, twoLINK) + h.assertLinkTokenBalance(lt, directTarget2.address, zeroLINK) + await expect(tx) .to.emit(labm, 'TopUpSucceeded') .withArgs(proxy1.address) @@ -730,7 +724,11 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should skip an address if the proxy is invalid and it is not a direct target', async () => { await labm .connect(owner) - .setWatchList([proxy1.address, proxy4.address], [oneLINK, oneLINK]) + .setWatchList( + [proxy1.address, proxy4.address], + [oneLINK, oneLINK], + [oneLINK, oneLINK], + ) const tx = await labm .connect(keeperRegistry) .topUp([proxy1.address, proxy4.address]) @@ -744,7 +742,11 @@ describe('LinkAvailableBalanceMonitor', () => { await proxy4.mock.aggregator.returns(aggregator4.address) await labm .connect(owner) - .setWatchList([proxy1.address, proxy4.address], [oneLINK, oneLINK]) + .setWatchList( + [proxy1.address, proxy4.address], + [oneLINK, oneLINK], + [oneLINK, oneLINK], + ) const tx = await labm .connect(keeperRegistry) .topUp([proxy1.address, proxy4.address]) @@ -759,7 +761,11 @@ describe('LinkAvailableBalanceMonitor', () => { await aggregator4.mock.linkAvailableForPayment.returns(tenLINK) await labm .connect(owner) - .setWatchList([proxy1.address, proxy4.address], [oneLINK, oneLINK]) + .setWatchList( + [proxy1.address, proxy4.address], + [oneLINK, oneLINK], + [oneLINK, oneLINK], + ) const tx = await labm .connect(keeperRegistry) .topUp([proxy1.address, proxy4.address]) @@ -776,6 +782,7 @@ describe('LinkAvailableBalanceMonitor', () => { .setWatchList( [proxy1.address, directTarget1.address], [oneLINK, oneLINK], + [oneLINK, oneLINK], ) const tx = await labm .connect(keeperRegistry) @@ -790,25 +797,26 @@ describe('LinkAvailableBalanceMonitor', () => { }) context('when partially funded', () => { - it('Should fund as many addresses as possible', async () => { + it('Should fund as many addresses as possible T', async () => { await lt.connect(owner).transfer( labm.address, - fiveLINK, // only enough LINK to fund 2 addresses + fourLINK, // only enough LINK to fund 2 addresses ) + + await aggregator1.mock.linkAvailableForPayment.returns(twoLINK) + await aggregator2.mock.linkAvailableForPayment.returns(twoLINK) + await aggregator3.mock.linkAvailableForPayment.returns(zeroLINK) + await directTarget1.mock.linkAvailableForPayment.returns(zeroLINK) + await directTarget2.mock.linkAvailableForPayment.returns(zeroLINK) + + h.assertLinkTokenBalance(lt, aggregator1.address, twoLINK) + h.assertLinkTokenBalance(lt, aggregator2.address, twoLINK) + h.assertLinkTokenBalance(lt, aggregator3.address, zeroLINK) + h.assertLinkTokenBalance(lt, directTarget1.address, zeroLINK) + h.assertLinkTokenBalance(lt, directTarget2.address, zeroLINK) + const tx = await labm.connect(keeperRegistry).topUp(watchListAddresses) - await assertContractLinkBalances( - twoLINK, - twoLINK, - zeroLINK, - zeroLINK, - zeroLINK, - ) - await expect(tx) - .to.emit(labm, 'TopUpSucceeded') - .withArgs(proxy1.address) - await expect(tx) - .to.emit(labm, 'TopUpSucceeded') - .withArgs(proxy2.address) + await expect(tx).to.emit(labm, 'TopUpSucceeded') }) }) }) From cea3e6e037d77291ba392a69ba0dc7c6c9cc67c2 Mon Sep 17 00:00:00 2001 From: CL-Andrew <96407253+CL-Andrew@users.noreply.github.com> Date: Fri, 3 Nov 2023 15:15:10 -0700 Subject: [PATCH 072/327] Optional and Configurable LDAP User/Session Management Support and Reworked Pluggable Auth Driver Interface (#9750) * Initial commit of LDAP Auth driver support with toml config docs and parser driver, pluggable auth interface defined and localauth (default) moved to scoped module * 'orm sessions.UserManager' to 'um sessions.UserManager' * Add missing checks for the UserApiTokenEnabled config field for token related calls, rename ServerTls to ServerTLS * Update docs toml LDAP section to clarify how the fields are used and specify LDAP terminology * Clarify LDAP 'cn' in toml docs for LDAP * Fix WebServer TOML and config definitions, split types for WebServerLDAPSecrets to following config and secret toml convention, improved error handling on startup for missing WebServer and LDAP fields * Error application startup if authentication method is not one of the valid options, instead of defaulting to local * Don't export unneeded ldapGroupMembersListToUser in ldap module * Bugfixes for LDAP find user when no results of passed email, address the two ways local CLI can attempt auth using local client for LDAP implementation of createSession, moved ErrNotSupported up to authentication types level so router can expose to API response when type message * Rework LDAP function to check if list of provided query emails possess the 'active' attribute/group in a single query. Now returns list of bools one to one for the passed in emails array and correctly handles the case for querying more than one email at a time, changing function return signature from just error * Update LDAP field naming for Cn, Dn to Go convention CN, DN in toml and types, tidy god mod, fix path imports for test files, fix toml comments * Post merge toml module rename LDAP model fixes Populate test config and test secrets toml file with new LDAP config fields, use secrets parse type for LDAPSecrets interface * Update top level application struct to accomodate new sibling AuthProvider field to preserve always available local admin auth This commit splits the newly added UserManager interface (now renamed) into two interfaces where the existing local user ORM auth provider covers the implementation for the required always available Admin commands. These are used when configuring the node initially (creating the admin user) or assuming the admin role from the command line, which should work locally as well regardless of the configured Authentication Provider. Renamed new UserManager interface to AuthenticationProvider, which no longer has the boilerplate Admin prefix functions. * Update all err comparison checks for ErrNotSupported to errors.Is * go generate mocks * Tidy unecessary string cast, bump ldap library to latest and use v3, test forward compatibility, mod tidy * Clean up auth provider config switch statement * Update checked in test txtar output * Update gql test and mocks with new authprovider mock, updated in mock struct. Add missing TestPassword call * Update remaining test config toml files with new WebServer LDAP fields, populated where test case makes sense, add toml config validation checks on parse for LDAP fields non empty, update LDAP Server field to Models Secret URL, add parsing test for secrets * Update LDAP module with missing API token implementation - creation, use, and deletion Bugfixes and logic improvements for LDAP session reaper/upstream sync. Reaper now correctly syncs roles and users from upstream via sleeper task tied to LDAP auth actions. User sessions and API tokens are correctly removed when the expire TTL is met, the local LDAP sessions and API tokens role is updated and synced with the state of the upstream LDAP server as part of the logic of this sleeper task, and if a user is no longer present in any of the defined groups they are automatically removed from the LDAP sessions and API tokens tables (checked on cadence of sleeper task Work call) Update LDAP webconfigToken duration to match wrapped models.Duration type Add const for LDAPUniqueMemberAttribute/uniqueMember in ldapauth module Add info logger connection attempt message in case of hang on node startup Fix expired LDAP api tokens purge issue Nicer error for session missing / expired on attempt of sesion token use (remove error within stdout) * Add missing support for local CLI user and auth when using LDAP Authentication module Fixed edge cases for FindUser, check local users table as well, local user API Token creation and support Add localauth_user flag for ldap specific tables to support node usage by the initial required local admin user, add logic in CreateSession * Update config UpstreamSyncInterval and UpstreamSyncRateLimit functionality for LDAP Sync daemon Implement .Work call on timer for LDAP sync in the background, independent of Auth related calls. The implementation of SleeperTask calls Work when hooked into Auth events, being called on login or logout. Now if UpstreamSyncInterval is defined as non 0, a background timer call will call the sync function, respecting the new UpstreamSyncRateLimit field * LDAP Fix for checks of optional isactive property on group query, find user functionality, and admin functions Bug fix for ldap driver not supporting local admin users case of change password and list users, FindUser functionality can now return matches of local admin users List Users now includes local users and works as expected for upstream LDAP users who have any of the defined groups required for node access. Bugfix for group search query in both the sync and ldap providers modules. Factored out group query functionality for both call sites Set Password support for only local admin users as functionality is still supported and required when using LDAP auth, upstream user modification remains unsupported Bugfix for shell local initialization not using local admin auth ORM, causing issue with initial assume user step in ListUsers * bump migration file index * remove incorrect rebased merge resolution for Explorer removal * Change default config definitions for LDAP 'Is Active' attribute checks to empty, as not all LDAP providers will use 'ActiveAttribute', or retain group member access when inactive. Fix error handling in find users for case when NoRows, dont log error automatically with Transaction middleware * Simplify sessions purge sql exec using pq.Array instead of manually generating placeholders, and Regenerate mocks * Merge go mod require groups, gotidy * Rename changed authentication provider session ORM in test files, fix config test reordering, add missing mock, update const err strings * Add mock value for one test case of config ldap is active attribute, revert purge sessions api token test file, migrate to new errors module and update how errors are wrapped, lowercase all error messages * Factor out unsupported action error message in user controller with new errUnsupportedForAuth type * Rebase, update migration index * Update config_test full case, error case for missing fields * Fix tests with missing Mocks for cmd shell, config resolver, and sessions localauth Missing mocks for LocalAdminUsersORM Revert change unrelated to LDAP feature in AuthorizedUserWithSession (refactored) Fix leaked internal error over HTTP response + test case for delete user Fix mocks and missing TestPassword call cases for graphql mutation tests, update incorrect password test case Add expected LDAP config fields for config resolver tests * Bump migration file index for ldap tables * Linter fixes - application.go localAdminUsersORM in initialized one line Fix config sesion timeout interface naming (r -> l) Typos fix in ldap.go docstring Rework logic in checkErr for FindUser logic of testing admin table query before failing (rework to avoid error shadowing) Invert logic for err != nil in case for local admin user found Fix missing errors.Is comparison for sessions.ErrUserSessionExpired in ldap module Run docs generate Fix typo in txtar test LDAP config * Add missing ldap fields to warnings.txtar, fix err shadowing linter errors in ldap.go and sync.go Run go mod tidy * Fix linter import order and groupings * More import ordering lint * Rebase, bump sql migraiton index * use correct guregu/null.v4 version * Implement test cases for ldap module, create LDAP client and LDAPConn wrapper interfaces and mocks New LDAPClient and LDAPConn interfaces allow test mocks to handle Bind and Search functionality. the ldap implementation has been updated to store the ldapClient (still ephemeral single use, like a factory) in the struct such that the test harness can swap the implementation with the mocks. Create helpers_test.go following codebase convention to allow a Setter method to be defined for the ldapClient field, but separated from the production build. This allows the ldap struct and field properties to remain unexported. Test helper contains test mock configand helper constructor function New ldap_test.go module with cases for ldap query functionality and local admin support assertions ldap.go module improvements, return struct in constructor instead of interface type for authentication provider, define user facing error consts (test assertion), store ldapClient in struct, nicer error handling for user not found in FindUser, fix err shadowing reuse error in token expired case, fix typos in ListUsers LDAP Sync rework for new ldapclient field, use new interface to support mocking Remove dangling commited localauth orm.mock, which was being imported by a missed test. Test now imports the correct mock (new authentication provider mocks) * Updated CHANGELOG.md * Update go.mod * Linter fixes UserNoLDAPGroups -> ErrUserNoLDAPGroups, shadowing * module -> package, format package docstring properly for ldapauth to support godoc render Remove redundant LDAP prefix for UniqueMemberAttribute * Remove rebased gomod line * define const NodeAdmins* for mocked tests in helpers_test, reference [WebServer].AuthenticationMethod in changelog * Add missing returns in sync Work call when failed to establish LDAP connection as it is required for the sync functionality, flip return flow in TestPassword for admin fallback * Updating naming and address nits LocalAdminUsersORM -> BasicAdminUsersORM, regenerate mocks Save indent in WebServer ValidateConfig when ldapauth Update comments and rename CreateEphemeralClient -> CreateEphemeralConnection * Add missed go generate Application change for BasicAdminUsersORM rename --- core/cmd/admin_commands_test.go | 6 +- core/cmd/app_test.go | 1 + core/cmd/shell.go | 12 +- core/cmd/shell_local.go | 7 +- core/cmd/shell_local_test.go | 11 +- core/cmd/shell_remote_test.go | 16 +- core/cmd/shell_test.go | 13 +- core/config/docs/core.toml | 40 + core/config/docs/secrets.toml | 9 + core/config/toml/types.go | 146 +++ core/config/web_config.go | 25 + core/internal/cltest/cltest.go | 2 +- core/internal/cltest/mocks.go | 4 +- core/internal/features/features_test.go | 2 +- core/internal/mocks/application.go | 48 +- core/scripts/go.mod | 3 + core/scripts/go.sum | 15 + core/services/chainlink/application.go | 49 +- core/services/chainlink/config.go | 24 +- core/services/chainlink/config_general.go | 2 +- .../services/chainlink/config_general_test.go | 10 + core/services/chainlink/config_test.go | 51 +- core/services/chainlink/config_web_server.go | 145 +++ .../testdata/config-empty-effective.toml | 20 + .../chainlink/testdata/config-full.toml | 20 + .../chainlink/testdata/config-invalid.toml | 22 + .../config-multi-chain-effective.toml | 20 + .../secrets-webserver-ldap.toml | 4 + .../testdata/secrets-full-redacted.toml | 6 + .../chainlink/testdata/secrets-full.toml | 6 + core/sessions/authentication.go | 66 ++ core/sessions/ldapauth/client.go | 47 + core/sessions/ldapauth/helpers_test.go | 131 +++ core/sessions/ldapauth/ldap.go | 858 ++++++++++++++++++ core/sessions/ldapauth/ldap_test.go | 639 +++++++++++++ core/sessions/ldapauth/mocks/ldap_client.go | 53 ++ core/sessions/ldapauth/mocks/ldap_conn.go | 82 ++ core/sessions/ldapauth/sync.go | 343 +++++++ core/sessions/{ => localauth}/orm.go | 111 +-- core/sessions/{ => localauth}/orm_test.go | 10 +- core/sessions/{ => localauth}/reaper.go | 2 +- core/sessions/{ => localauth}/reaper_test.go | 40 +- .../{orm.go => authentication_provider.go} | 62 +- core/sessions/mocks/basic_admin_users_orm.go | 91 ++ core/sessions/session.go | 74 ++ core/sessions/user.go | 64 -- core/sessions/webauthn.go | 4 +- .../0208_create_ldap_sessions_table.sql | 22 + core/web/auth/auth.go | 5 +- core/web/auth/auth_test.go | 4 +- core/web/auth/gql_test.go | 4 +- core/web/resolver/api_token_test.go | 64 +- core/web/resolver/mutation.go | 20 +- core/web/resolver/resolver_test.go | 6 +- .../testdata/config-empty-effective.toml | 20 + core/web/resolver/testdata/config-full.toml | 20 + .../config-multi-chain-effective.toml | 20 + core/web/resolver/user_test.go | 26 +- core/web/router.go | 12 +- core/web/sessions_controller.go | 6 +- core/web/sessions_controller_test.go | 18 +- core/web/user_controller.go | 76 +- core/web/user_controller_test.go | 4 +- core/web/webauthn_controller.go | 6 +- docs/CHANGELOG.md | 5 + docs/CONFIG.md | 133 +++ docs/SECRETS.md | 27 + go.mod | 3 + go.sum | 15 + integration-tests/go.mod | 3 + integration-tests/go.sum | 9 + testdata/scripts/node/validate/default.txtar | 20 + .../disk-based-logging-disabled.txtar | 20 + .../validate/disk-based-logging-no-dir.txtar | 20 + .../node/validate/disk-based-logging.txtar | 20 + testdata/scripts/node/validate/invalid.txtar | 20 + testdata/scripts/node/validate/valid.txtar | 20 + testdata/scripts/node/validate/warnings.txtar | 20 + 78 files changed, 3743 insertions(+), 341 deletions(-) create mode 100644 core/services/chainlink/testdata/mergingsecretsdata/secrets-webserver-ldap.toml create mode 100644 core/sessions/authentication.go create mode 100644 core/sessions/ldapauth/client.go create mode 100644 core/sessions/ldapauth/helpers_test.go create mode 100644 core/sessions/ldapauth/ldap.go create mode 100644 core/sessions/ldapauth/ldap_test.go create mode 100644 core/sessions/ldapauth/mocks/ldap_client.go create mode 100644 core/sessions/ldapauth/mocks/ldap_conn.go create mode 100644 core/sessions/ldapauth/sync.go rename core/sessions/{ => localauth}/orm.go (80%) rename core/sessions/{ => localauth}/orm_test.go (95%) rename core/sessions/{ => localauth}/reaper.go (98%) rename core/sessions/{ => localauth}/reaper_test.go (69%) rename core/sessions/mocks/{orm.go => authentication_provider.go} (75%) create mode 100644 core/sessions/mocks/basic_admin_users_orm.go create mode 100644 core/sessions/session.go create mode 100644 core/store/migrate/migrations/0208_create_ldap_sessions_table.sql diff --git a/core/cmd/admin_commands_test.go b/core/cmd/admin_commands_test.go index a5512fddda..954e3577d3 100644 --- a/core/cmd/admin_commands_test.go +++ b/core/cmd/admin_commands_test.go @@ -62,7 +62,7 @@ func TestShell_ChangeRole(t *testing.T) { app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) tests := []struct { name string @@ -101,7 +101,7 @@ func TestShell_DeleteUser(t *testing.T) { app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.BasicAdminUsersORM().CreateUser(&user)) tests := []struct { name string @@ -135,7 +135,7 @@ func TestShell_ListUsers(t *testing.T) { app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) set := flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.ListUsers, set, "") diff --git a/core/cmd/app_test.go b/core/cmd/app_test.go index bbb00bff3e..e5e2940642 100644 --- a/core/cmd/app_test.go +++ b/core/cmd/app_test.go @@ -151,6 +151,7 @@ func Test_initServerConfig(t *testing.T) { "../services/chainlink/testdata/mergingsecretsdata/secrets-mercury-split-one.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-mercury-split-two.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-threshold.toml", + "../services/chainlink/testdata/mergingsecretsdata/secrets-webserver-ldap.toml", }, }, wantErr: false, diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 308ebf8da8..80ecd2590b 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -776,8 +776,8 @@ func (f *fileSessionRequestBuilder) Build(file string) (sessions.SessionRequest, // APIInitializer is the interface used to create the API User credentials // needed to access the API. Does nothing if API user already exists. type APIInitializer interface { - // Initialize creates a new user for API access, or does nothing if one exists. - Initialize(orm sessions.ORM, lggr logger.Logger) (sessions.User, error) + // Initialize creates a new local Admin user for API access, or does nothing if one exists. + Initialize(orm sessions.BasicAdminUsersORM, lggr logger.Logger) (sessions.User, error) } type promptingAPIInitializer struct { @@ -791,11 +791,11 @@ func NewPromptingAPIInitializer(prompter Prompter) APIInitializer { } // Initialize uses the terminal to get credentials that it then saves in the store. -func (t *promptingAPIInitializer) Initialize(orm sessions.ORM, lggr logger.Logger) (sessions.User, error) { +func (t *promptingAPIInitializer) Initialize(orm sessions.BasicAdminUsersORM, lggr logger.Logger) (sessions.User, error) { // Load list of users to determine which to assume, or if a user needs to be created dbUsers, err := orm.ListUsers() if err != nil { - return sessions.User{}, err + return sessions.User{}, errors.Wrap(err, "Unable to List users for initialization") } // If there are no users in the database, prompt for initial admin user creation @@ -845,7 +845,7 @@ func NewFileAPIInitializer(file string) APIInitializer { return fileAPIInitializer{file: file} } -func (f fileAPIInitializer) Initialize(orm sessions.ORM, lggr logger.Logger) (sessions.User, error) { +func (f fileAPIInitializer) Initialize(orm sessions.BasicAdminUsersORM, lggr logger.Logger) (sessions.User, error) { request, err := credentialsFromFile(f.file, lggr) if err != nil { return sessions.User{}, err @@ -854,7 +854,7 @@ func (f fileAPIInitializer) Initialize(orm sessions.ORM, lggr logger.Logger) (se // Load list of users to determine which to assume, or if a user needs to be created dbUsers, err := orm.ListUsers() if err != nil { - return sessions.User{}, err + return sessions.User{}, errors.Wrap(err, "Unable to List users for initialization") } // If there are no users in the database, create initial admin user from session request from file creds diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 401375238d..dea9a29359 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -362,7 +362,8 @@ func (s *Shell) runNode(c *cli.Context) error { return s.errorOut(errors.Wrap(err, "fatal error instantiating application")) } - sessionORM := app.SessionORM() + // Local shell initialization always uses local auth users table for admin auth + authProviderORM := app.BasicAdminUsersORM() keyStore := app.GetKeyStore() err = s.KeyStoreAuthenticator.authenticate(keyStore, s.Config.Password()) if err != nil { @@ -449,11 +450,11 @@ func (s *Shell) runNode(c *cli.Context) error { } var user sessions.User - if user, err = NewFileAPIInitializer(c.String("api")).Initialize(sessionORM, lggr); err != nil { + if user, err = NewFileAPIInitializer(c.String("api")).Initialize(authProviderORM, lggr); err != nil { if !errors.Is(err, ErrNoCredentialFile) { return errors.Wrap(err, "error creating api initializer") } - if user, err = s.FallbackAPIInitializer.Initialize(sessionORM, lggr); err != nil { + if user, err = s.FallbackAPIInitializer.Initialize(authProviderORM, lggr); err != nil { if errors.Is(err, ErrorNoAPICredentialsAvailable) { return errors.WithStack(err) } diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 89b8704f87..df60e16423 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -25,7 +25,7 @@ import ( chainlinkmocks "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -79,7 +79,7 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { }) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - sessionORM := sessions.NewORM(db, time.Minute, logger.TestLogger(t), cfg.Database(), audit.NoopLogger) + authProviderORM := localauth.NewORM(db, time.Minute, logger.TestLogger(t), cfg.Database(), audit.NoopLogger) lggr := logger.TestLogger(t) @@ -100,7 +100,8 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { pgtest.MustExec(t, db, "DELETE FROM users;") app := mocks.NewApplication(t) - app.On("SessionORM").Return(sessionORM).Maybe() + app.On("AuthenticationProvider").Return(authProviderORM).Maybe() + app.On("BasicAdminUsersORM").Return(authProviderORM).Maybe() app.On("GetKeyStore").Return(keyStore).Maybe() app.On("GetRelayers").Return(testRelayers).Maybe() app.On("Start", mock.Anything).Maybe().Return(nil) @@ -171,7 +172,7 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { c.Insecure.OCRDevelopmentMode = nil }) db := pgtest.NewSqlxDB(t) - sessionORM := sessions.NewORM(db, time.Minute, logger.TestLogger(t), cfg.Database(), audit.NoopLogger) + authProviderORM := localauth.NewORM(db, time.Minute, logger.TestLogger(t), cfg.Database(), audit.NoopLogger) // Clear out fixture users/users created from the other test cases // This asserts that on initial run with an empty users table that the credentials file will instantiate and @@ -199,7 +200,7 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { } testRelayers := genTestEVMRelayers(t, opts, keyStore) app := mocks.NewApplication(t) - app.On("SessionORM").Return(sessionORM) + app.On("BasicAdminUsersORM").Return(authProviderORM) app.On("GetKeyStore").Return(keyStore) app.On("GetRelayers").Return(testRelayers).Maybe() app.On("Start", mock.Anything).Maybe().Return(nil) diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 7f998225f6..91b56ee53a 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -258,7 +258,7 @@ func TestShell_DestroyExternalInitiator_NotFound(t *testing.T) { func TestShell_RemoteLogin(t *testing.T) { app := startNewApplicationV2(t, nil) - orm := app.SessionORM() + orm := app.AuthenticationProvider() u := cltest.NewUserWithSession(t, orm) @@ -301,7 +301,7 @@ func TestShell_RemoteBuildCompatibility(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - u := cltest.NewUserWithSession(t, app.SessionORM()) + u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: append(enteredStrings, enteredStrings...)} client := app.NewAuthenticatingShell(prompter) @@ -340,7 +340,7 @@ func TestShell_CheckRemoteBuildCompatibility(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - u := cltest.NewUserWithSession(t, app.SessionORM()) + u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) tests := []struct { name string remoteVersion, remoteSha string @@ -416,7 +416,7 @@ func TestShell_ChangePassword(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - u := cltest.NewUserWithSession(t, app.SessionORM()) + u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: enteredStrings} @@ -466,7 +466,7 @@ func TestShell_Profile_InvalidSecondsParam(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - u := cltest.NewUserWithSession(t, app.SessionORM()) + u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: enteredStrings} @@ -497,7 +497,7 @@ func TestShell_Profile(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - u := cltest.NewUserWithSession(t, app.SessionORM()) + u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: enteredStrings} @@ -648,7 +648,7 @@ func TestShell_AutoLogin(t *testing.T) { app := startNewApplicationV2(t, nil) user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.BasicAdminUsersORM().CreateUser(&user)) sr := sessions.SessionRequest{ Email: user.Email, @@ -676,7 +676,7 @@ func TestShell_AutoLogin_AuthFails(t *testing.T) { app := startNewApplicationV2(t, nil) user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.BasicAdminUsersORM().CreateUser(&user)) sr := sessions.SessionRequest{ Email: user.Email, diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index 9b87e8fb1d..2a8c2c5586 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -26,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -33,7 +34,7 @@ func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { t.Parallel() app := cltest.NewApplicationEVMDisabled(t) - u := cltest.NewUserWithSession(t, app.SessionORM()) + u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) tests := []struct { name, email, pwd string @@ -65,7 +66,7 @@ func TestTerminalCookieAuthenticator_AuthenticateWithSession(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - u := cltest.NewUserWithSession(t, app.SessionORM()) + u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) tests := []struct { name, email, pwd string @@ -155,7 +156,7 @@ func TestTerminalAPIInitializer_InitializeWithoutAPIUser(t *testing.T) { t.Run(test.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) - orm := sessions.NewORM(db, time.Minute, lggr, pgtest.NewQConfig(true), audit.NoopLogger) + orm := localauth.NewORM(db, time.Minute, lggr, pgtest.NewQConfig(true), audit.NoopLogger) mock := &cltest.MockCountingPrompter{T: t, EnteredStrings: test.enteredStrings, NotTerminal: !test.isTerminal} tai := cmd.NewPromptingAPIInitializer(mock) @@ -186,7 +187,7 @@ func TestTerminalAPIInitializer_InitializeWithExistingAPIUser(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) lggr := logger.TestLogger(t) - orm := sessions.NewORM(db, time.Minute, lggr, cfg.Database(), audit.NoopLogger) + orm := localauth.NewORM(db, time.Minute, lggr, cfg.Database(), audit.NoopLogger) // Clear out fixture users/users created from the other test cases // This asserts that on initial run with an empty users table that the credentials file will instantiate and @@ -223,7 +224,7 @@ func TestFileAPIInitializer_InitializeWithoutAPIUser(t *testing.T) { t.Run(test.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) - orm := sessions.NewORM(db, time.Minute, lggr, pgtest.NewQConfig(true), audit.NoopLogger) + orm := localauth.NewORM(db, time.Minute, lggr, pgtest.NewQConfig(true), audit.NoopLogger) // Clear out fixture users/users created from the other test cases // This asserts that on initial run with an empty users table that the credentials file will instantiate and @@ -248,7 +249,7 @@ func TestFileAPIInitializer_InitializeWithoutAPIUser(t *testing.T) { func TestFileAPIInitializer_InitializeWithExistingAPIUser(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - orm := sessions.NewORM(db, time.Minute, logger.TestLogger(t), cfg.Database(), audit.NoopLogger) + orm := localauth.NewORM(db, time.Minute, logger.TestLogger(t), cfg.Database(), audit.NoopLogger) tests := []struct { name string diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 1ca4c656a7..0a8e6aba3b 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -161,6 +161,8 @@ MaxAgeDays = 0 # Default MaxBackups = 1 # Default [WebServer] +# AuthenticationMethod defines which pluggable auth interface to use for user login and role assumption. Options include 'local' and 'ldap'. See docs for more details +AuthenticationMethod = 'local' # Default # AllowOrigins controls the URLs Chainlink nodes emit in the `Allow-Origins` header of its API responses. The setting can be a comma-separated list with no spaces. You might experience CORS issues if this is not set correctly. # # You should set this to the external URL that you use to access the Chainlink UI. @@ -191,6 +193,44 @@ StartTimeout = '15s' # Default # ListenIP specifies the IP to bind the HTTP server to ListenIP = '0.0.0.0' # Default +# Optional LDAP config if WebServer.AuthenticationMethod is set to 'ldap' +# LDAP queries are all parameterized to support custom LDAP 'dn', 'cn', and attributes +[WebServer.LDAP] +# ServerTLS defines the option to require the secure ldaps +ServerTLS = true # Default +# SessionTimeout determines the amount of idle time to elapse before session cookies expire. This signs out GUI users from their sessions. +SessionTimeout = '15m0s' # Default +# QueryTimeout defines how long queries should wait before timing out, defined in seconds +QueryTimeout = '2m0s' # Default +# BaseUserAttr defines the base attribute used to populate LDAP queries such as "uid=$", default is example +BaseUserAttr = 'uid' # Default +# BaseDN defines the base LDAP 'dn' search filter to apply to every LDAP query, replace example,com with the appropriate LDAP server's structure +BaseDN = 'dc=custom,dc=example,dc=com' # Example +# UsersDN defines the 'dn' query to use when querying for the 'users' 'ou' group +UsersDN = 'ou=users' # Default +# GroupsDN defines the 'dn' query to use when querying for the 'groups' 'ou' group +GroupsDN = 'ou=groups' # Default +# ActiveAttribute is an optional user field to check truthiness for if a user is valid/active. This is only required if the LDAP provider lists inactive users as members of groups +ActiveAttribute = '' # Default +# ActiveAttributeAllowedValue is the value to check against for the above optional user attribute +ActiveAttributeAllowedValue = '' # Default +# AdminUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Admin' role +AdminUserGroupCN = 'NodeAdmins' # Default +# EditUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Edit' role +EditUserGroupCN = 'NodeEditors' # Default +# RunUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Run' role +RunUserGroupCN = 'NodeRunners' # Default +# ReadUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Read' role +ReadUserGroupCN = 'NodeReadOnly' # Default +# UserApiTokenEnabled enables the users to issue API tokens with the same access of their role +UserApiTokenEnabled = false # Default +# UserAPITokenDuration is the duration of time an API token is active for before expiring +UserAPITokenDuration = '240h0m0s' # Default +# UpstreamSyncInterval is the interval at which the background LDAP sync task will be called. A '0s' value disables the background sync being run on an interval. This check is already performed during login/logout actions, all sessions and API tokens stored in the local ldap tables are updated to match the remote server +UpstreamSyncInterval = '0s' # Default +# UpstreamSyncRateLimit defines a duration to limit the number of query/API calls to the upstream LDAP provider. It prevents the sync functionality from being called multiple times within the defined duration +UpstreamSyncRateLimit = '2m0s' # Default + [WebServer.RateLimit] # Authenticated defines the threshold to which authenticated requests get limited. More than this many authenticated requests per `AuthenticatedRateLimitPeriod` will be rejected. Authenticated = 1000 # Default diff --git a/core/config/docs/secrets.toml b/core/config/docs/secrets.toml index 2b491a7749..4ed2325dfb 100644 --- a/core/config/docs/secrets.toml +++ b/core/config/docs/secrets.toml @@ -14,6 +14,15 @@ BackupURL = "postgresql://user:pass@read-replica.example.com:5432/dbname?sslmode # Environment variable: `CL_DATABASE_ALLOW_SIMPLE_PASSWORDS` AllowSimplePasswords = false # Default +# Optional LDAP config +[WebServer.LDAP] +# ServerAddress is the full ldaps:// address of the ldap server to authenticate with and query +ServerAddress = 'ldaps://127.0.0.1' # Example +# ReadOnlyUserLogin is the username of the read only root user used to authenticate the requested LDAP queries +ReadOnlyUserLogin = 'viewer@example.com' # Example +# ReadOnlyUserPass is the password for the above account +ReadOnlyUserPass = 'password' # Example + [Password] # Keystore is the password for the node's account. # diff --git a/core/config/toml/types.go b/core/config/toml/types.go index b7c8cfbc47..61962d43e5 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config/parse" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" + "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -101,6 +102,7 @@ func (c *Core) ValidateConfig() (err error) { type Secrets struct { Database DatabaseSecrets `toml:",omitempty"` Password Passwords `toml:",omitempty"` + WebServer WebServerSecrets `toml:",omitempty"` Pyroscope PyroscopeSecrets `toml:",omitempty"` Prometheus PrometheusSecrets `toml:",omitempty"` Mercury MercurySecrets `toml:",omitempty"` @@ -592,6 +594,7 @@ func (l *LogFile) setFrom(f *LogFile) { } type WebServer struct { + AuthenticationMethod *string AllowOrigins *string BridgeResponseURL *models.URL BridgeCacheTTL *models.Duration @@ -604,12 +607,16 @@ type WebServer struct { StartTimeout *models.Duration ListenIP *net.IP + LDAP WebServerLDAP `toml:",omitempty"` MFA WebServerMFA `toml:",omitempty"` RateLimit WebServerRateLimit `toml:",omitempty"` TLS WebServerTLS `toml:",omitempty"` } func (w *WebServer) setFrom(f *WebServer) { + if v := f.AuthenticationMethod; v != nil { + w.AuthenticationMethod = v + } if v := f.AllowOrigins; v != nil { w.AllowOrigins = v } @@ -644,11 +651,46 @@ func (w *WebServer) setFrom(f *WebServer) { w.HTTPMaxSize = v } + w.LDAP.setFrom(&f.LDAP) w.MFA.setFrom(&f.MFA) w.RateLimit.setFrom(&f.RateLimit) w.TLS.setFrom(&f.TLS) } +func (w *WebServer) ValidateConfig() (err error) { + // Validate LDAP fields when authentication method is LDAPAuth + if *w.AuthenticationMethod != string(sessions.LDAPAuth) { + return + } + + // Assert LDAP fields when AuthMethod set to LDAP + if *w.LDAP.BaseDN == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.BaseDN", Msg: "LDAP BaseDN can not be empty"}) + } + if *w.LDAP.BaseUserAttr == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.BaseUserAttr", Msg: "LDAP BaseUserAttr can not be empty"}) + } + if *w.LDAP.UsersDN == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.UsersDN", Msg: "LDAP UsersDN can not be empty"}) + } + if *w.LDAP.GroupsDN == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.GroupsDN", Msg: "LDAP GroupsDN can not be empty"}) + } + if *w.LDAP.AdminUserGroupCN == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.AdminUserGroupCN", Msg: "LDAP AdminUserGroupCN can not be empty"}) + } + if *w.LDAP.EditUserGroupCN == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.RunUserGroupCN", Msg: "LDAP ReadUserGroupCN can not be empty"}) + } + if *w.LDAP.RunUserGroupCN == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.RunUserGroupCN", Msg: "LDAP RunUserGroupCN can not be empty"}) + } + if *w.LDAP.ReadUserGroupCN == "" { + err = multierr.Append(err, configutils.ErrInvalid{Name: "LDAP.ReadUserGroupCN", Msg: "LDAP ReadUserGroupCN can not be empty"}) + } + return err +} + type WebServerMFA struct { RPID *string RPOrigin *string @@ -715,6 +757,110 @@ func (w *WebServerTLS) setFrom(f *WebServerTLS) { } } +type WebServerLDAP struct { + ServerTLS *bool + SessionTimeout *models.Duration + QueryTimeout *models.Duration + BaseUserAttr *string + BaseDN *string + UsersDN *string + GroupsDN *string + ActiveAttribute *string + ActiveAttributeAllowedValue *string + AdminUserGroupCN *string + EditUserGroupCN *string + RunUserGroupCN *string + ReadUserGroupCN *string + UserApiTokenEnabled *bool + UserAPITokenDuration *models.Duration + UpstreamSyncInterval *models.Duration + UpstreamSyncRateLimit *models.Duration +} + +func (w *WebServerLDAP) setFrom(f *WebServerLDAP) { + if v := f.ServerTLS; v != nil { + w.ServerTLS = v + } + if v := f.SessionTimeout; v != nil { + w.SessionTimeout = v + } + if v := f.SessionTimeout; v != nil { + w.SessionTimeout = v + } + if v := f.QueryTimeout; v != nil { + w.QueryTimeout = v + } + if v := f.BaseUserAttr; v != nil { + w.BaseUserAttr = v + } + if v := f.BaseDN; v != nil { + w.BaseDN = v + } + if v := f.UsersDN; v != nil { + w.UsersDN = v + } + if v := f.GroupsDN; v != nil { + w.GroupsDN = v + } + if v := f.ActiveAttribute; v != nil { + w.ActiveAttribute = v + } + if v := f.ActiveAttributeAllowedValue; v != nil { + w.ActiveAttributeAllowedValue = v + } + if v := f.AdminUserGroupCN; v != nil { + w.AdminUserGroupCN = v + } + if v := f.EditUserGroupCN; v != nil { + w.EditUserGroupCN = v + } + if v := f.RunUserGroupCN; v != nil { + w.RunUserGroupCN = v + } + if v := f.ReadUserGroupCN; v != nil { + w.ReadUserGroupCN = v + } + if v := f.UserApiTokenEnabled; v != nil { + w.UserApiTokenEnabled = v + } + if v := f.UserAPITokenDuration; v != nil { + w.UserAPITokenDuration = v + } + if v := f.UpstreamSyncInterval; v != nil { + w.UpstreamSyncInterval = v + } + if v := f.UpstreamSyncRateLimit; v != nil { + w.UpstreamSyncRateLimit = v + } +} + +type WebServerLDAPSecrets struct { + ServerAddress *models.SecretURL + ReadOnlyUserLogin *models.Secret + ReadOnlyUserPass *models.Secret +} + +func (w *WebServerLDAPSecrets) setFrom(f *WebServerLDAPSecrets) { + if v := f.ServerAddress; v != nil { + w.ServerAddress = v + } + if v := f.ReadOnlyUserLogin; v != nil { + w.ReadOnlyUserLogin = v + } + if v := f.ReadOnlyUserPass; v != nil { + w.ReadOnlyUserPass = v + } +} + +type WebServerSecrets struct { + LDAP WebServerLDAPSecrets `toml:",omitempty"` +} + +func (w *WebServerSecrets) SetFrom(f *WebServerSecrets) error { + w.LDAP.setFrom(&f.LDAP) + return nil +} + type JobPipeline struct { ExternalInitiatorsEnabled *bool MaxRunDuration *models.Duration diff --git a/core/config/web_config.go b/core/config/web_config.go index 12209a0267..429a31e7e8 100644 --- a/core/config/web_config.go +++ b/core/config/web_config.go @@ -32,7 +32,31 @@ type MFA interface { RPOrigin() string } +type LDAP interface { + ServerAddress() string + ReadOnlyUserLogin() string + ReadOnlyUserPass() string + ServerTLS() bool + SessionTimeout() models.Duration + QueryTimeout() time.Duration + BaseUserAttr() string + BaseDN() string + UsersDN() string + GroupsDN() string + ActiveAttribute() string + ActiveAttributeAllowedValue() string + AdminUserGroupCN() string + EditUserGroupCN() string + RunUserGroupCN() string + ReadUserGroupCN() string + UserApiTokenEnabled() bool + UserAPITokenDuration() models.Duration + UpstreamSyncInterval() models.Duration + UpstreamSyncRateLimit() models.Duration +} + type WebServer interface { + AuthenticationMethod() string AllowOrigins() string BridgeCacheTTL() time.Duration BridgeResponseURL() *url.URL @@ -49,4 +73,5 @@ type WebServer interface { TLS() TLS RateLimit() RateLimit MFA() MFA + LDAP() LDAP } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index fb4a69cf30..66162aef10 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -628,7 +628,7 @@ func (ta *TestApplication) NewHTTPClient(user *User) HTTPClientCleaner { u, err := clsessions.NewUser(user.Email, Password, user.Role) require.NoError(ta.t, err) - err = ta.SessionORM().CreateUser(&u) + err = ta.BasicAdminUsersORM().CreateUser(&u) require.NoError(ta.t, err) sessionID := ta.MustSeedNewSession(user.Email) diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 9fdbcbb373..00f72199dd 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -309,7 +309,7 @@ func MustRandomUser(t testing.TB) sessions.User { return r } -func NewUserWithSession(t testing.TB, orm sessions.ORM) sessions.User { +func NewUserWithSession(t testing.TB, orm sessions.AuthenticationProvider) sessions.User { u := MustRandomUser(t) require.NoError(t, orm.CreateUser(&u)) @@ -330,7 +330,7 @@ func NewMockAPIInitializer(t testing.TB) *MockAPIInitializer { return &MockAPIInitializer{t: t} } -func (m *MockAPIInitializer) Initialize(orm sessions.ORM, lggr logger.Logger) (sessions.User, error) { +func (m *MockAPIInitializer) Initialize(orm sessions.BasicAdminUsersORM, lggr logger.Logger) (sessions.User, error) { if user, err := orm.FindUser(APIEmailAdmin); err == nil { return user, err } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 3293066191..23451bf29f 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -266,7 +266,7 @@ func TestIntegration_AuthToken(t *testing.T) { mockUser := cltest.MustRandomUser(t) key, secret := uuid.New().String(), uuid.New().String() apiToken := auth.Token{AccessKey: key, Secret: secret} - orm := app.SessionORM() + orm := app.AuthenticationProvider() require.NoError(t, orm.CreateUser(&mockUser)) require.NoError(t, orm.SetAuthToken(&mockUser, &apiToken)) diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index ec656509af..7853361db9 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -63,6 +63,38 @@ func (_m *Application) AddJobV2(ctx context.Context, _a1 *job.Job) error { return r0 } +// AuthenticationProvider provides a mock function with given fields: +func (_m *Application) AuthenticationProvider() sessions.AuthenticationProvider { + ret := _m.Called() + + var r0 sessions.AuthenticationProvider + if rf, ok := ret.Get(0).(func() sessions.AuthenticationProvider); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(sessions.AuthenticationProvider) + } + } + + return r0 +} + +// BasicAdminUsersORM provides a mock function with given fields: +func (_m *Application) BasicAdminUsersORM() sessions.BasicAdminUsersORM { + ret := _m.Called() + + var r0 sessions.BasicAdminUsersORM + if rf, ok := ret.Get(0).(func() sessions.BasicAdminUsersORM); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(sessions.BasicAdminUsersORM) + } + } + + return r0 +} + // BridgeORM provides a mock function with given fields: func (_m *Application) BridgeORM() bridges.ORM { ret := _m.Called() @@ -439,22 +471,6 @@ func (_m *Application) SecretGenerator() chainlink.SecretGenerator { return r0 } -// SessionORM provides a mock function with given fields: -func (_m *Application) SessionORM() sessions.ORM { - ret := _m.Called() - - var r0 sessions.ORM - if rf, ok := ret.Get(0).(func() sessions.ORM); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(sessions.ORM) - } - } - - return r0 -} - // SetLogLevel provides a mock function with given fields: lvl func (_m *Application) SetLogLevel(lvl zapcore.Level) error { ret := _m.Called(lvl) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 65dcec563e..17c2cff103 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -44,6 +44,7 @@ require ( filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect @@ -119,8 +120,10 @@ require ( github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect + github.com/go-ldap/ldap/v3 v3.4.5 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 781eed46ce..ae1f924c0f 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -79,6 +79,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -124,6 +126,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -424,6 +428,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -438,6 +444,8 @@ github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEai github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= +github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -1745,6 +1753,7 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1785,6 +1794,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1846,6 +1856,7 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1872,6 +1883,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1975,6 +1987,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1987,6 +2000,7 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2063,6 +2077,7 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 63a9b2696c..3285acdc07 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -52,6 +52,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/sessions/ldapauth" + "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -82,7 +84,8 @@ type Application interface { EVMORM() evmtypes.Configs PipelineORM() pipeline.ORM BridgeORM() bridges.ORM - SessionORM() sessions.ORM + BasicAdminUsersORM() sessions.BasicAdminUsersORM + AuthenticationProvider() sessions.AuthenticationProvider TxmStorageService() txmgr.EvmTxStore AddJobV2(ctx context.Context, job *job.Job) error DeleteJob(ctx context.Context, jobID int32) error @@ -115,7 +118,8 @@ type ChainlinkApplication struct { pipelineORM pipeline.ORM pipelineRunner pipeline.Runner bridgeORM bridges.ORM - sessionORM sessions.ORM + localAdminUsersORM sessions.BasicAdminUsersORM + authenticationProvider sessions.AuthenticationProvider txmStorageService txmgr.EvmTxStore FeedsService feeds.Service webhookJobRunner webhook.JobRunner @@ -245,10 +249,36 @@ func NewApplication(opts ApplicationOpts) (Application, error) { return nil, fmt.Errorf("no evm chains found") } + // Initialize Local Users ORM and Authentication Provider specified in config + // BasicAdminUsersORM is initialized and required regardless of separate Authentication Provider + localAdminUsersORM := localauth.NewORM(db, cfg.WebServer().SessionTimeout().Duration(), globalLogger, cfg.Database(), auditLogger) + + // Initialize Sessions ORM based on environment configured authenticator + // localDB auth or remote LDAP auth + authMethod := cfg.WebServer().AuthenticationMethod() + var authenticationProvider sessions.AuthenticationProvider + var sessionReaper utils.SleeperTask + + switch sessions.AuthenticationProviderName(authMethod) { + case sessions.LDAPAuth: + var err error + authenticationProvider, err = ldapauth.NewLDAPAuthenticator( + db, cfg.Database(), cfg.WebServer().LDAP(), cfg.Insecure().DevWebServer(), globalLogger, auditLogger, + ) + if err != nil { + return nil, errors.Wrap(err, "NewApplication: failed to initialize LDAP Authentication module") + } + sessionReaper = ldapauth.NewLDAPServerStateSync(db, cfg.Database(), cfg.WebServer().LDAP(), globalLogger) + case sessions.LocalAuth: + authenticationProvider = localauth.NewORM(db, cfg.WebServer().SessionTimeout().Duration(), globalLogger, cfg.Database(), auditLogger) + sessionReaper = localauth.NewSessionReaper(db.DB, cfg.WebServer(), globalLogger) + default: + return nil, errors.Errorf("NewApplication: Unexpected 'AuthenticationMethod': %s supported values: %s, %s", authMethod, sessions.LocalAuth, sessions.LDAPAuth) + } + var ( pipelineORM = pipeline.NewORM(db, globalLogger, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) bridgeORM = bridges.NewORM(db, globalLogger, cfg.Database()) - sessionORM = sessions.NewORM(db, cfg.WebServer().SessionTimeout().Duration(), globalLogger, cfg.Database(), auditLogger) mercuryORM = mercury.NewORM(db, globalLogger, cfg.Database()) pipelineRunner = pipeline.NewRunner(pipelineORM, bridgeORM, cfg.JobPipeline(), cfg.WebServer(), legacyEVMChains, keyStore.Eth(), keyStore.VRF(), globalLogger, restrictedHTTPClient, unrestrictedHTTPClient) jobORM = job.NewORM(db, pipelineORM, bridgeORM, keyStore, globalLogger, cfg.Database()) @@ -440,13 +470,14 @@ func NewApplication(opts ApplicationOpts) (Application, error) { pipelineRunner: pipelineRunner, pipelineORM: pipelineORM, bridgeORM: bridgeORM, - sessionORM: sessionORM, + localAdminUsersORM: localAdminUsersORM, + authenticationProvider: authenticationProvider, txmStorageService: txmORM, FeedsService: feedsService, Config: cfg, webhookJobRunner: webhookJobRunner, KeyStore: keyStore, - SessionReaper: sessions.NewSessionReaper(db.DB, cfg.WebServer(), globalLogger), + SessionReaper: sessionReaper, ExternalInitiatorManager: externalInitiatorManager, HealthChecker: healthChecker, Nurse: nurse, @@ -612,8 +643,12 @@ func (app *ChainlinkApplication) BridgeORM() bridges.ORM { return app.bridgeORM } -func (app *ChainlinkApplication) SessionORM() sessions.ORM { - return app.sessionORM +func (app *ChainlinkApplication) BasicAdminUsersORM() sessions.BasicAdminUsersORM { + return app.localAdminUsersORM +} + +func (app *ChainlinkApplication) AuthenticationProvider() sessions.AuthenticationProvider { + return app.authenticationProvider } // TODO BCF-2516 remove this all together remove EVM specifics diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 3f55a2dc00..10598718f9 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -168,28 +168,32 @@ type Secrets struct { } func (s *Secrets) SetFrom(f *Secrets) (err error) { - if err1 := s.Database.SetFrom(&f.Database); err1 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err1, "Database")) + if err2 := s.Database.SetFrom(&f.Database); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "Database")) } if err2 := s.Password.SetFrom(&f.Password); err2 != nil { err = multierr.Append(err, config.NamedMultiErrorList(err2, "Password")) } - if err3 := s.Pyroscope.SetFrom(&f.Pyroscope); err3 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err3, "Pyroscope")) + if err2 := s.WebServer.SetFrom(&f.WebServer); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "WebServer")) } - if err4 := s.Prometheus.SetFrom(&f.Prometheus); err4 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err4, "Prometheus")) + if err2 := s.Pyroscope.SetFrom(&f.Pyroscope); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "Pyroscope")) } - if err5 := s.Mercury.SetFrom(&f.Mercury); err5 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err5, "Mercury")) + if err2 := s.Prometheus.SetFrom(&f.Prometheus); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "Prometheus")) } - if err6 := s.Threshold.SetFrom(&f.Threshold); err6 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err6, "Threshold")) + if err2 := s.Mercury.SetFrom(&f.Mercury); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "Mercury")) + } + + if err2 := s.Threshold.SetFrom(&f.Threshold); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "Threshold")) } _, err = utils.MultiErrorList(err) diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 81e3883335..6a835e09c8 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -348,7 +348,7 @@ func (g *generalConfig) StarkNetEnabled() bool { } func (g *generalConfig) WebServer() config.WebServer { - return &webServerConfig{c: g.c.WebServer, rootDir: g.RootDir} + return &webServerConfig{c: g.c.WebServer, s: g.secrets.WebServer, rootDir: g.RootDir} } func (g *generalConfig) AutoPprofBlockProfileRate() int { diff --git a/core/services/chainlink/config_general_test.go b/core/services/chainlink/config_general_test.go index 46931e53e2..c122f8f968 100644 --- a/core/services/chainlink/config_general_test.go +++ b/core/services/chainlink/config_general_test.go @@ -149,6 +149,9 @@ var mercurySecretsTOMLSplitTwo string //go:embed testdata/mergingsecretsdata/secrets-threshold.toml var thresholdSecretsTOML string +//go:embed testdata/mergingsecretsdata/secrets-webserver-ldap.toml +var WebServerLDAPSecretsTOML string + func TestConfig_SecretsMerging(t *testing.T) { t.Run("verify secrets merging in GeneralConfigOpts.New()", func(t *testing.T) { databaseSecrets, err := parseSecrets(databaseSecretsTOML) @@ -165,6 +168,8 @@ func TestConfig_SecretsMerging(t *testing.T) { require.NoErrorf(t, err6, "error: %s", err6) thresholdSecrets, err7 := parseSecrets(thresholdSecretsTOML) require.NoErrorf(t, err7, "error: %s", err7) + webserverLDAPSecrets, err8 := parseSecrets(WebServerLDAPSecretsTOML) + require.NoErrorf(t, err8, "error: %s", err8) opts := new(GeneralConfigOpts) configFiles := []string{ @@ -178,6 +183,7 @@ func TestConfig_SecretsMerging(t *testing.T) { "testdata/mergingsecretsdata/secrets-mercury-split-one.toml", "testdata/mergingsecretsdata/secrets-mercury-split-two.toml", "testdata/mergingsecretsdata/secrets-threshold.toml", + "testdata/mergingsecretsdata/secrets-webserver-ldap.toml", } err = opts.Setup(configFiles, secretsFiles) require.NoErrorf(t, err, "error: %s", err) @@ -194,6 +200,10 @@ func TestConfig_SecretsMerging(t *testing.T) { assert.Equal(t, (string)(*prometheusSecrets.Prometheus.AuthToken), (string)(*opts.Secrets.Prometheus.AuthToken)) assert.Equal(t, (string)(*thresholdSecrets.Threshold.ThresholdKeyShare), (string)(*opts.Secrets.Threshold.ThresholdKeyShare)) + assert.Equal(t, webserverLDAPSecrets.WebServer.LDAP.ServerAddress.URL().String(), opts.Secrets.WebServer.LDAP.ServerAddress.URL().String()) + assert.Equal(t, webserverLDAPSecrets.WebServer.LDAP.ReadOnlyUserLogin, opts.Secrets.WebServer.LDAP.ReadOnlyUserLogin) + assert.Equal(t, webserverLDAPSecrets.WebServer.LDAP.ReadOnlyUserPass, opts.Secrets.WebServer.LDAP.ReadOnlyUserPass) + err = assertDeepEqualityMercurySecrets(*merge(mercurySecrets_a.Mercury, mercurySecrets_b.Mercury), opts.Secrets.Mercury) require.NoErrorf(t, err, "merged mercury secrets unequal") }) diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 986b98d936..96e6db42c8 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -308,6 +308,7 @@ func TestConfig_Marshal(t *testing.T) { }, } full.WebServer = toml.WebServer{ + AuthenticationMethod: ptr("local"), AllowOrigins: ptr("*"), BridgeResponseURL: mustURL("https://bridge.response"), BridgeCacheTTL: models.MustNewDuration(10 * time.Second), @@ -323,6 +324,25 @@ func TestConfig_Marshal(t *testing.T) { RPID: ptr("test-rpid"), RPOrigin: ptr("test-rp-origin"), }, + LDAP: toml.WebServerLDAP{ + ServerTLS: ptr(true), + SessionTimeout: models.MustNewDuration(15 * time.Minute), + QueryTimeout: models.MustNewDuration(2 * time.Minute), + BaseUserAttr: ptr("uid"), + BaseDN: ptr("dc=custom,dc=example,dc=com"), + UsersDN: ptr("ou=users"), + GroupsDN: ptr("ou=groups"), + ActiveAttribute: ptr("organizationalStatus"), + ActiveAttributeAllowedValue: ptr("ACTIVE"), + AdminUserGroupCN: ptr("NodeAdmins"), + EditUserGroupCN: ptr("NodeEditors"), + RunUserGroupCN: ptr("NodeRunners"), + ReadUserGroupCN: ptr("NodeReadOnly"), + UserApiTokenEnabled: ptr(false), + UserAPITokenDuration: models.MustNewDuration(240 * time.Hour), + UpstreamSyncInterval: models.MustNewDuration(0 * time.Second), + UpstreamSyncRateLimit: models.MustNewDuration(2 * time.Minute), + }, RateLimit: toml.WebServerRateLimit{ Authenticated: ptr[int64](42), AuthenticatedPeriod: models.MustNewDuration(time.Second), @@ -738,6 +758,7 @@ MaxAgeDays = 17 MaxBackups = 9 `}, {"WebServer", Config{Core: toml.Core{WebServer: full.WebServer}}, `[WebServer] +AuthenticationMethod = 'local' AllowOrigins = '*' BridgeResponseURL = 'https://bridge.response' BridgeCacheTTL = '10s' @@ -750,6 +771,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '192.158.1.37' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = 'dc=custom,dc=example,dc=com' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = 'organizationalStatus' +ActiveAttributeAllowedValue = 'ACTIVE' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = 'test-rpid' RPOrigin = 'test-rp-origin' @@ -1118,8 +1158,17 @@ func TestConfig_Validate(t *testing.T) { toml string exp string }{ - {name: "invalid", toml: invalidTOML, exp: `invalid configuration: 5 errors: + {name: "invalid", toml: invalidTOML, exp: `invalid configuration: 6 errors: - Database.Lock.LeaseRefreshInterval: invalid value (6s): must be less than or equal to half of LeaseDuration (10s) + - WebServer: 8 errors: + - LDAP.BaseDN: invalid value (): LDAP BaseDN can not be empty + - LDAP.BaseUserAttr: invalid value (): LDAP BaseUserAttr can not be empty + - LDAP.UsersDN: invalid value (): LDAP UsersDN can not be empty + - LDAP.GroupsDN: invalid value (): LDAP GroupsDN can not be empty + - LDAP.AdminUserGroupCN: invalid value (): LDAP AdminUserGroupCN can not be empty + - LDAP.RunUserGroupCN: invalid value (): LDAP ReadUserGroupCN can not be empty + - LDAP.RunUserGroupCN: invalid value (): LDAP RunUserGroupCN can not be empty + - LDAP.ReadUserGroupCN: invalid value (): LDAP ReadUserGroupCN can not be empty - EVM: 8 errors: - 1.ChainID: invalid value (1): duplicate - must be unique - 0.Nodes.1.Name: invalid value (foo): duplicate - must be unique diff --git a/core/services/chainlink/config_web_server.go b/core/services/chainlink/config_web_server.go index a931d67f38..06db398e2e 100644 --- a/core/services/chainlink/config_web_server.go +++ b/core/services/chainlink/config_web_server.go @@ -98,6 +98,7 @@ func (m *mfaConfig) RPOrigin() string { type webServerConfig struct { c toml.WebServer + s toml.WebServerSecrets rootDir func() string } @@ -113,6 +114,14 @@ func (w *webServerConfig) MFA() config.MFA { return &mfaConfig{c: w.c.MFA} } +func (w *webServerConfig) LDAP() config.LDAP { + return &ldapConfig{c: w.c.LDAP, s: w.s.LDAP} +} + +func (w *webServerConfig) AuthenticationMethod() string { + return *w.c.AuthenticationMethod +} + func (w *webServerConfig) AllowOrigins() string { return *w.c.AllowOrigins } @@ -168,3 +177,139 @@ func (w *webServerConfig) SessionTimeout() models.Duration { func (w *webServerConfig) ListenIP() net.IP { return *w.c.ListenIP } + +type ldapConfig struct { + c toml.WebServerLDAP + s toml.WebServerLDAPSecrets +} + +func (l *ldapConfig) ServerAddress() string { + if l.s.ServerAddress == nil { + return "" + } + return l.s.ServerAddress.URL().String() +} + +func (l *ldapConfig) ReadOnlyUserLogin() string { + if l.s.ReadOnlyUserLogin == nil { + return "" + } + return string(*l.s.ReadOnlyUserLogin) +} + +func (l *ldapConfig) ReadOnlyUserPass() string { + if l.s.ReadOnlyUserPass == nil { + return "" + } + return string(*l.s.ReadOnlyUserPass) +} + +func (l *ldapConfig) ServerTLS() bool { + if l.c.ServerTLS == nil { + return false + } + return *l.c.ServerTLS +} + +func (l *ldapConfig) SessionTimeout() models.Duration { + return *l.c.SessionTimeout +} + +func (l *ldapConfig) QueryTimeout() time.Duration { + return l.c.QueryTimeout.Duration() +} + +func (l *ldapConfig) UserAPITokenDuration() models.Duration { + return *l.c.UserAPITokenDuration +} + +func (l *ldapConfig) BaseUserAttr() string { + if l.c.BaseUserAttr == nil { + return "" + } + return *l.c.BaseUserAttr +} + +func (l *ldapConfig) BaseDN() string { + if l.c.BaseDN == nil { + return "" + } + return *l.c.BaseDN +} + +func (l *ldapConfig) UsersDN() string { + if l.c.UsersDN == nil { + return "" + } + return *l.c.UsersDN +} + +func (l *ldapConfig) GroupsDN() string { + if l.c.GroupsDN == nil { + return "" + } + return *l.c.GroupsDN +} + +func (l *ldapConfig) ActiveAttribute() string { + if l.c.ActiveAttribute == nil { + return "" + } + return *l.c.ActiveAttribute +} + +func (l *ldapConfig) ActiveAttributeAllowedValue() string { + if l.c.ActiveAttributeAllowedValue == nil { + return "" + } + return *l.c.ActiveAttributeAllowedValue +} + +func (l *ldapConfig) AdminUserGroupCN() string { + if l.c.AdminUserGroupCN == nil { + return "" + } + return *l.c.AdminUserGroupCN +} + +func (l *ldapConfig) EditUserGroupCN() string { + if l.c.EditUserGroupCN == nil { + return "" + } + return *l.c.EditUserGroupCN +} + +func (l *ldapConfig) RunUserGroupCN() string { + if l.c.RunUserGroupCN == nil { + return "" + } + return *l.c.RunUserGroupCN +} + +func (l *ldapConfig) ReadUserGroupCN() string { + if l.c.ReadUserGroupCN == nil { + return "" + } + return *l.c.ReadUserGroupCN +} + +func (l *ldapConfig) UserApiTokenEnabled() bool { + if l.c.UserApiTokenEnabled == nil { + return false + } + return *l.c.UserApiTokenEnabled +} + +func (l *ldapConfig) UpstreamSyncInterval() models.Duration { + if l.c.UpstreamSyncInterval == nil { + return models.Duration{} + } + return *l.c.UpstreamSyncInterval +} + +func (l *ldapConfig) UpstreamSyncRateLimit() models.Duration { + if l.c.UpstreamSyncRateLimit == nil { + return models.Duration{} + } + return *l.c.UpstreamSyncRateLimit +} diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 48d432138a..f5d775fe74 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -61,6 +61,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -73,6 +74,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 7ce0d185b1..5ede10ef69 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -67,6 +67,7 @@ MaxAgeDays = 17 MaxBackups = 9 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = '*' BridgeResponseURL = 'https://bridge.response' BridgeCacheTTL = '10s' @@ -79,6 +80,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '192.158.1.37' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = 'dc=custom,dc=example,dc=com' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = 'organizationalStatus' +ActiveAttributeAllowedValue = 'ACTIVE' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = 'test-rpid' RPOrigin = 'test-rp-origin' diff --git a/core/services/chainlink/testdata/config-invalid.toml b/core/services/chainlink/testdata/config-invalid.toml index 3b7e89299f..4d8c9bc29a 100644 --- a/core/services/chainlink/testdata/config-invalid.toml +++ b/core/services/chainlink/testdata/config-invalid.toml @@ -2,6 +2,28 @@ LeaseRefreshInterval='6s' LeaseDuration='10s' +[WebServer] +AuthenticationMethod = 'ldap' + +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = '' +BaseDN = '' +UsersDN = '' +GroupsDN = '' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = '' +EditUserGroupCN = '' +RunUserGroupCN = '' +ReadUserGroupCN = '' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [[EVM]] ChainID = '1' Transactions.MaxInFlight= 10 diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 1dcbfe3a83..9dd0be8f5d 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -61,6 +61,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -73,6 +74,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/core/services/chainlink/testdata/mergingsecretsdata/secrets-webserver-ldap.toml b/core/services/chainlink/testdata/mergingsecretsdata/secrets-webserver-ldap.toml new file mode 100644 index 0000000000..f73efcff0c --- /dev/null +++ b/core/services/chainlink/testdata/mergingsecretsdata/secrets-webserver-ldap.toml @@ -0,0 +1,4 @@ +[WebServer.LDAP] +ServerAddress = 'ldaps://127.0.0.1' +ReadOnlyUserLogin = 'viewer@example.com' +ReadOnlyUserPass = 'password' \ No newline at end of file diff --git a/core/services/chainlink/testdata/secrets-full-redacted.toml b/core/services/chainlink/testdata/secrets-full-redacted.toml index 740c3250ed..9d91d79cb5 100644 --- a/core/services/chainlink/testdata/secrets-full-redacted.toml +++ b/core/services/chainlink/testdata/secrets-full-redacted.toml @@ -7,6 +7,12 @@ AllowSimplePasswords = false Keystore = 'xxxxx' VRF = 'xxxxx' +[WebServer] +[WebServer.LDAP] +ServerAddress = 'xxxxx' +ReadOnlyUserLogin = 'xxxxx' +ReadOnlyUserPass = 'xxxxx' + [Pyroscope] AuthToken = 'xxxxx' diff --git a/core/services/chainlink/testdata/secrets-full.toml b/core/services/chainlink/testdata/secrets-full.toml index 37e5dafc7d..37a3e2e7dc 100644 --- a/core/services/chainlink/testdata/secrets-full.toml +++ b/core/services/chainlink/testdata/secrets-full.toml @@ -6,6 +6,12 @@ BackupURL = "postgresql://user:pass@localhost:5432/backupdbname?sslmode=disable" Keystore = "keystore_pass" VRF = "VRF_pass" +[WebServer] +[WebServer.LDAP] +ServerAddress = 'ldaps://127.0.0.1' +ReadOnlyUserLogin = 'viewer@example.com' +ReadOnlyUserPass = 'password' + [Pyroscope] AuthToken = "pyroscope-token" diff --git a/core/sessions/authentication.go b/core/sessions/authentication.go new file mode 100644 index 0000000000..0f0dda3bf3 --- /dev/null +++ b/core/sessions/authentication.go @@ -0,0 +1,66 @@ +package sessions + +import ( + "errors" + "fmt" + + "github.com/smartcontractkit/chainlink/v2/core/auth" + "github.com/smartcontractkit/chainlink/v2/core/bridges" +) + +// Application config constant options +type AuthenticationProviderName string + +const ( + LocalAuth AuthenticationProviderName = "local" + LDAPAuth AuthenticationProviderName = "ldap" +) + +// ErrUserSessionExpired defines the error triggered when the user session has expired +var ErrUserSessionExpired = errors.New("session missing or expired, please login again") + +// ErrNotSupported defines the error where interface functionality doesn't align with the underlying Auth Provider +var ErrNotSupported = fmt.Errorf("functionality not supported with current authentication provider: %w", errors.ErrUnsupported) + +// ErrEmptySessionID captures the empty case error message +var ErrEmptySessionID = errors.New("session ID cannot be empty") + +//go:generate mockery --quiet --name BasicAdminUsersORM --output ./mocks/ --case=underscore + +// BasicAdminUsersORM is the interface that defines the functionality required for supporting basic admin functionality +// adjacent to the identity provider authentication provider implementation. It is currently implemented by the local +// users/sessions ORM containing local admin CLI actions. This is separate from the AuthenticationProvider, +// as local admin management (ie initial core node setup, initial admin user creation), is always +// required no matter what the pluggable AuthenticationProvider implementation is. +type BasicAdminUsersORM interface { + ListUsers() ([]User, error) + CreateUser(user *User) error + FindUser(email string) (User, error) +} + +//go:generate mockery --quiet --name AuthenticationProvider --output ./mocks/ --case=underscore + +// AuthenticationProvider is an interface that abstracts the required application calls to a user management backend +// Currently localauth (users table DB) or LDAP server (readonly) +type AuthenticationProvider interface { + FindUser(email string) (User, error) + FindUserByAPIToken(apiToken string) (User, error) + ListUsers() ([]User, error) + AuthorizedUserWithSession(sessionID string) (User, error) + DeleteUser(email string) error + DeleteUserSession(sessionID string) error + CreateSession(sr SessionRequest) (string, error) + ClearNonCurrentSessions(sessionID string) error + CreateUser(user *User) error + UpdateRole(email, newRole string) (User, error) + SetAuthToken(user *User, token *auth.Token) error + CreateAndSetAuthToken(user *User) (*auth.Token, error) + DeleteAuthToken(user *User) error + SetPassword(user *User, newPassword string) error + TestPassword(email, password string) error + Sessions(offset, limit int) ([]Session, error) + GetUserWebAuthn(email string) ([]WebAuthn, error) + SaveWebAuthn(token *WebAuthn) error + + FindExternalInitiator(eia *auth.Token) (initiator *bridges.ExternalInitiator, err error) +} diff --git a/core/sessions/ldapauth/client.go b/core/sessions/ldapauth/client.go new file mode 100644 index 0000000000..bb259f8c9a --- /dev/null +++ b/core/sessions/ldapauth/client.go @@ -0,0 +1,47 @@ +package ldapauth + +import ( + "fmt" + + "github.com/go-ldap/ldap/v3" + + "github.com/smartcontractkit/chainlink/v2/core/config" +) + +type ldapClient struct { + config config.LDAP +} + +//go:generate mockery --quiet --name LDAPClient --output ./mocks/ --case=underscore + +// Wrapper for creating a handle to a *ldap.Conn/LDAPConn interface +type LDAPClient interface { + CreateEphemeralConnection() (LDAPConn, error) +} + +//go:generate mockery --quiet --name LDAPConn --output ./mocks/ --case=underscore + +// Wrapper for ldap connection and mock testing, implemented by *ldap.Conn +type LDAPConn interface { + Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) + Bind(username string, password string) error + Close() (err error) +} + +func newLDAPClient(config config.LDAP) LDAPClient { + return &ldapClient{config} +} + +// CreateEphemeralConnection returns a valid, active LDAP connection for upstream Search and Bind queries +func (l *ldapClient) CreateEphemeralConnection() (LDAPConn, error) { + conn, err := ldap.DialURL(l.config.ServerAddress()) + if err != nil { + return nil, fmt.Errorf("failed to Dial LDAP Server: %w", err) + } + // Root level root user auth with credentials provided from config + bindStr := l.config.BaseUserAttr() + "=" + l.config.ReadOnlyUserLogin() + "," + l.config.BaseDN() + if err := conn.Bind(bindStr, l.config.ReadOnlyUserPass()); err != nil { + return nil, fmt.Errorf("unable to login as initial root LDAP user: %w", err) + } + return conn, nil +} diff --git a/core/sessions/ldapauth/helpers_test.go b/core/sessions/ldapauth/helpers_test.go new file mode 100644 index 0000000000..c554d5436e --- /dev/null +++ b/core/sessions/ldapauth/helpers_test.go @@ -0,0 +1,131 @@ +package ldapauth + +import ( + "time" + + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/logger/audit" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/store/models" +) + +// Returns an instantiated ldapAuthenticator struct without validation for testing +func NewTestLDAPAuthenticator( + db *sqlx.DB, + pgCfg pg.QConfig, + ldapCfg config.LDAP, + dev bool, + lggr logger.Logger, + auditLogger audit.AuditLogger, +) (*ldapAuthenticator, error) { + namedLogger := lggr.Named("LDAPAuthenticationProvider") + ldapAuth := ldapAuthenticator{ + q: pg.NewQ(db, namedLogger, pgCfg), + ldapClient: newLDAPClient(ldapCfg), + config: ldapCfg, + lggr: lggr.Named("LDAPAuthenticationProvider"), + auditLogger: auditLogger, + } + + return &ldapAuth, nil +} + +// Default server group name mappings for test config and mocked ldap search results +const ( + NodeAdminsGroupCN = "NodeAdmins" + NodeEditorsGroupCN = "NodeEditors" + NodeRunnersGroupCN = "NodeRunners" + NodeReadOnlyGroupCN = "NodeReadOnly" +) + +// Implement a setter function within the _test file so that the ldapauth_test module can set the unexported field with a mock +func (l *ldapAuthenticator) SetLDAPClient(newClient LDAPClient) { + l.ldapClient = newClient +} + +// Implements config.LDAP +type TestConfig struct { +} + +func (t *TestConfig) ServerAddress() string { + return "ldaps://MOCK" +} + +func (t *TestConfig) ReadOnlyUserLogin() string { + return "mock-readonly" +} + +func (t *TestConfig) ReadOnlyUserPass() string { + return "mock-password" +} + +func (t *TestConfig) ServerTLS() bool { + return false +} + +func (t *TestConfig) SessionTimeout() models.Duration { + return models.MustMakeDuration(time.Duration(0)) +} + +func (t *TestConfig) QueryTimeout() time.Duration { + return time.Duration(0) +} + +func (t *TestConfig) UserAPITokenDuration() models.Duration { + return models.MustMakeDuration(time.Duration(0)) +} + +func (t *TestConfig) BaseUserAttr() string { + return "uid" +} + +func (t *TestConfig) BaseDN() string { + return "dc=custom,dc=example,dc=com" +} + +func (t *TestConfig) UsersDN() string { + return "ou=users" +} + +func (t *TestConfig) GroupsDN() string { + return "ou=groups" +} + +func (t *TestConfig) ActiveAttribute() string { + return "organizationalStatus" +} + +func (t *TestConfig) ActiveAttributeAllowedValue() string { + return "ACTIVE" +} + +func (t *TestConfig) AdminUserGroupCN() string { + return NodeAdminsGroupCN +} + +func (t *TestConfig) EditUserGroupCN() string { + return NodeEditorsGroupCN +} + +func (t *TestConfig) RunUserGroupCN() string { + return NodeRunnersGroupCN +} + +func (t *TestConfig) ReadUserGroupCN() string { + return NodeReadOnlyGroupCN +} + +func (t *TestConfig) UserApiTokenEnabled() bool { + return true +} + +func (t *TestConfig) UpstreamSyncInterval() models.Duration { + return models.MustMakeDuration(time.Duration(0)) +} + +func (t *TestConfig) UpstreamSyncRateLimit() models.Duration { + return models.MustMakeDuration(time.Duration(0)) +} diff --git a/core/sessions/ldapauth/ldap.go b/core/sessions/ldapauth/ldap.go new file mode 100644 index 0000000000..188f2684e7 --- /dev/null +++ b/core/sessions/ldapauth/ldap.go @@ -0,0 +1,858 @@ +/* +The LDAP authentication package forwards the credentials in the user session request +for authentication with a configured upstream LDAP server + +This package relies on the two following local database tables: + + ldap_sessions: Upon successful LDAP response, creates a keyed local copy of the user email + ldap_user_api_tokens: User created API tokens, tied to the node, storing user email. + +Note: user can have only one API token at a time, and token expiration is enforced + +User session and roles are cached and revalidated with the upstream service at the interval defined in +the local LDAP config through the Application.sessionReaper implementation in reaper.go. + +Changes to the upstream identity server will propagate through and update local tables (web sessions, API tokens) +by either removing the entries or updating the roles. This sync happens for every auth endpoint hit, and +via the defined sync interval. One goroutine is created to coordinate the sync timing in the New function + +This implementation is read only; user mutation actions such as Delete are not supported. + +MFA is supported via the remote LDAP server implementation. Sufficient request time out should accommodate +for a blocking auth call while the user responds to a potential push notification callback. +*/ +package ldapauth + +import ( + "crypto/subtle" + "database/sql" + "errors" + "fmt" + "strings" + "time" + + "github.com/go-ldap/ldap/v3" + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/auth" + "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/logger/audit" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" +) + +const ( + UniqueMemberAttribute = "uniqueMember" +) + +var ErrUserNotInUpstream = errors.New("LDAP query returned no matching users") +var ErrUserNoLDAPGroups = errors.New("user present in directory, but matching no role groups assigned") + +type ldapAuthenticator struct { + q pg.Q + ldapClient LDAPClient + config config.LDAP + lggr logger.Logger + auditLogger audit.AuditLogger +} + +// ldapAuthenticator implements sessions.AuthenticationProvider interface +var _ sessions.AuthenticationProvider = (*ldapAuthenticator)(nil) + +func NewLDAPAuthenticator( + db *sqlx.DB, + pgCfg pg.QConfig, + ldapCfg config.LDAP, + dev bool, + lggr logger.Logger, + auditLogger audit.AuditLogger, +) (*ldapAuthenticator, error) { + namedLogger := lggr.Named("LDAPAuthenticationProvider") + + // If not chainlink dev and not tls, error + if !dev && !ldapCfg.ServerTLS() { + return nil, errors.New("LDAP Authentication driver requires TLS when running in Production mode") + } + + // Ensure all RBAC role mappings to LDAP Groups are defined, and required fields populated, or error on startup + if ldapCfg.AdminUserGroupCN() == "" || ldapCfg.EditUserGroupCN() == "" || + ldapCfg.RunUserGroupCN() == "" || ldapCfg.ReadUserGroupCN() == "" { + return nil, errors.New("LDAP Group mapping from server group name for all local RBAC role required. Set group names for `_UserGroupCN` fields") + } + if ldapCfg.ServerAddress() == "" { + return nil, errors.New("LDAP ServerAddress config required") + } + if ldapCfg.ReadOnlyUserLogin() == "" { + return nil, errors.New("LDAP ReadOnlyUserLogin config required") + } + + ldapAuth := ldapAuthenticator{ + q: pg.NewQ(db, namedLogger, pgCfg), + ldapClient: newLDAPClient(ldapCfg), + config: ldapCfg, + lggr: lggr.Named("LDAPAuthenticationProvider"), + auditLogger: auditLogger, + } + + // Single override of library defined global + ldap.DefaultTimeout = ldapCfg.QueryTimeout() + + // Test initial connection and credentials + lggr.Infof("Attempting initial connection to configured LDAP server with bind as API user") + conn, err := ldapAuth.ldapClient.CreateEphemeralConnection() + if err != nil { + return nil, fmt.Errorf("unable to establish connection to LDAP server with provided URL and credentials: %w", err) + } + conn.Close() + + // Store LDAP connection config for auth/new connection per request instead of persisted connection with reconnect + return &ldapAuth, nil +} + +// FindUser will attempt to return an LDAP user with mapped role by email. +func (l *ldapAuthenticator) FindUser(email string) (sessions.User, error) { + email = strings.ToLower(email) + foundUser := sessions.User{} + + // First check for the supported local admin users table + var foundLocalAdminUser sessions.User + checkErr := l.q.Transaction(func(tx pg.Queryer) error { + sql := "SELECT * FROM users WHERE lower(email) = lower($1)" + return tx.Get(&foundLocalAdminUser, sql, email) + }) + if checkErr != nil { + // If error is not nil, there was either an issue or no local users found + if !errors.Is(checkErr, sql.ErrNoRows) { + // If the error is not that no local user was found, log and exit + l.lggr.Errorf("error searching users table: %v", checkErr) + return sessions.User{}, errors.New("error Finding user") + } + } else { + // Error was nil, local user found. Return + return foundLocalAdminUser, nil + } + + // First query for user "is active" property if defined + usersActive, err := l.validateUsersActive([]string{email}) + if err != nil { + if errors.Is(err, ErrUserNotInUpstream) { + return foundUser, ErrUserNotInUpstream + } + l.lggr.Errorf("error in validateUsers call: %v", err) + return foundUser, errors.New("error running query to validate user active") + } + if !usersActive[0] { + return foundUser, errors.New("user not active") + } + + conn, err := l.ldapClient.CreateEphemeralConnection() + if err != nil { + l.lggr.Errorf("error in LDAP dial: ", err) + return foundUser, errors.New("unable to establish connection to LDAP server with provided URL and credentials") + } + defer conn.Close() + + // User email and role are the only upstream data that needs queried for. + // List query user groups using the provided email, on success is a list of group the uniquemember belongs to + // data is readily available + escapedEmail := ldap.EscapeFilter(email) + searchBaseDN := fmt.Sprintf("%s, %s", l.config.GroupsDN(), l.config.BaseDN()) + filterQuery := fmt.Sprintf("(&(uniquemember=%s=%s,%s,%s))", l.config.BaseUserAttr(), escapedEmail, l.config.UsersDN(), l.config.BaseDN()) + searchRequest := ldap.NewSearchRequest( + searchBaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, int(l.config.QueryTimeout().Seconds()), false, + filterQuery, + []string{"cn"}, + nil, + ) + + // Query the server + result, err := conn.Search(searchRequest) + if err != nil { + l.lggr.Errorf("error searching users in LDAP query: %v", err) + return foundUser, errors.New("error searching users in LDAP directory") + } + + if len(result.Entries) == 0 { + // Provided email is not present in upstream LDAP server, local admin CLI auth is supported + // So query and check the users table as well before failing + if err = l.q.Transaction(func(tx pg.Queryer) error { + var localUserRole sessions.UserRole + if err = tx.Get(&localUserRole, "SELECT role FROM users WHERE email = $1", email); err != nil { + return err + } + foundUser = sessions.User{ + Email: email, + Role: localUserRole, + } + return nil + }); err != nil { + // Above query for local user unsuccessful, return error + l.lggr.Warnf("No local users table user found with email %s", email) + return foundUser, errors.New("no users found with provided email") + } + + // If the above query to the local users table was successful, return that local user's role + return foundUser, nil + } + + // Populate found user by email and role based on matched group names + userRole, err := l.groupSearchResultsToUserRole(result.Entries) + if err != nil { + l.lggr.Warnf("User '%s' found but no matching assigned groups in LDAP to assume role", email) + return sessions.User{}, err + } + + // Convert search result to sessions.User type with required fields + foundUser = sessions.User{ + Email: email, + Role: userRole, + } + + return foundUser, nil +} + +// FindUserByAPIToken retrieves a possible stored user and role from the ldap_user_api_tokens table store +func (l *ldapAuthenticator) FindUserByAPIToken(apiToken string) (sessions.User, error) { + if !l.config.UserApiTokenEnabled() { + return sessions.User{}, errors.New("API token is not enabled ") + } + + var foundUser sessions.User + err := l.q.Transaction(func(tx pg.Queryer) error { + // Query the ldap user API token table for given token, user role and email are cached so + // no further upstream LDAP query is performed, sessions and tokens are synced against the upstream server + // via the UpstreamSyncInterval config and reaper.go sync implementation + var foundUserToken struct { + UserEmail string + UserRole sessions.UserRole + Valid bool + } + if err := tx.Get(&foundUserToken, + "SELECT user_email, user_role, created_at + $2 >= now() as valid FROM ldap_user_api_tokens WHERE token_key = $1", + apiToken, l.config.UserAPITokenDuration().Duration(), + ); err != nil { + return err + } + if !foundUserToken.Valid { + return sessions.ErrUserSessionExpired + } + foundUser = sessions.User{ + Email: foundUserToken.UserEmail, + Role: foundUserToken.UserRole, + } + return nil + }) + if err != nil { + if errors.Is(err, sessions.ErrUserSessionExpired) { + // API Token expired, purge + if _, execErr := l.q.Exec("DELETE FROM ldap_user_api_tokens WHERE token_key = $1", apiToken); err != nil { + l.lggr.Errorf("error purging stale ldap API token session: %v", execErr) + } + } + return sessions.User{}, err + } + return foundUser, nil +} + +// ListUsers will load and return all active users in applicable LDAP groups, extended with local admin users as well +func (l *ldapAuthenticator) ListUsers() ([]sessions.User, error) { + // For each defined role/group, query for the list of group members to gather the full list of possible users + users := []sessions.User{} + var err error + + conn, err := l.ldapClient.CreateEphemeralConnection() + if err != nil { + l.lggr.Errorf("error in LDAP dial: ", err) + return users, errors.New("unable to establish connection to LDAP server with provided URL and credentials") + } + defer conn.Close() + + // Query for list of uniqueMember IDs present in Admin group + adminUsers, err := l.ldapGroupMembersListToUser(conn, l.config.AdminUserGroupCN(), sessions.UserRoleAdmin) + if err != nil { + l.lggr.Errorf("error in ldapGroupMembersListToUser: ", err) + return users, errors.New("unable to list group users") + } + // Query for list of uniqueMember IDs present in Edit group + editUsers, err := l.ldapGroupMembersListToUser(conn, l.config.EditUserGroupCN(), sessions.UserRoleEdit) + if err != nil { + l.lggr.Errorf("error in ldapGroupMembersListToUser: ", err) + return users, errors.New("unable to list group users") + } + // Query for list of uniqueMember IDs present in Run group + runUsers, err := l.ldapGroupMembersListToUser(conn, l.config.RunUserGroupCN(), sessions.UserRoleRun) + if err != nil { + l.lggr.Errorf("error in ldapGroupMembersListToUser: ", err) + return users, errors.New("unable to list group users") + } + // Query for list of uniqueMember IDs present in Read group + readUsers, err := l.ldapGroupMembersListToUser(conn, l.config.ReadUserGroupCN(), sessions.UserRoleView) + if err != nil { + l.lggr.Errorf("error in ldapGroupMembersListToUser: ", err) + return users, errors.New("unable to list group users") + } + + // Aggregate full list + users = append(users, adminUsers...) + users = append(users, editUsers...) + users = append(users, runUsers...) + users = append(users, readUsers...) + + // Dedupe preserving order of highest role + uniqueRef := make(map[string]struct{}) + dedupedUsers := []sessions.User{} + for _, user := range users { + if _, ok := uniqueRef[user.Email]; !ok { + uniqueRef[user.Email] = struct{}{} + dedupedUsers = append(dedupedUsers, user) + } + } + + // If no active attribute to check is defined, user simple being assigned the group is enough, return full list + if l.config.ActiveAttribute() == "" { + return dedupedUsers, nil + } + + // Now optionally validate that all uniqueMembers are active in the org/LDAP server + emails := []string{} + for _, user := range dedupedUsers { + emails = append(emails, user.Email) + } + activeUsers, err := l.validateUsersActive(emails) + if err != nil { + l.lggr.Errorf("error validating supplied user list: ", err) + return users, errors.New("error validating supplied user list") + } + + // Filter non active users + returnUsers := []sessions.User{} + for i, active := range activeUsers { + if active { + returnUsers = append(returnUsers, dedupedUsers[i]) + } + } + + // Extend with local admin users + var localAdminUsers []sessions.User + if err := l.q.Transaction(func(tx pg.Queryer) error { + sql := "SELECT * FROM users ORDER BY email ASC;" + return tx.Select(&localAdminUsers, sql) + }); err != nil { + l.lggr.Errorf("error extending upstream LDAP users with local admin users in users table: ", err) + } else { + returnUsers = append(returnUsers, localAdminUsers...) + } + + return returnUsers, nil +} + +// ldapGroupMembersListToUser queries the LDAP server given a conn for a list of uniqueMember who are part of the parameterized group +func (l *ldapAuthenticator) ldapGroupMembersListToUser(conn LDAPConn, groupNameCN string, roleToAssign sessions.UserRole) ([]sessions.User, error) { + users, err := ldapGroupMembersListToUser( + conn, groupNameCN, roleToAssign, l.config.GroupsDN(), + l.config.BaseDN(), l.config.QueryTimeout(), + l.lggr, + ) + if err != nil { + l.lggr.Errorf("error listing members of group (%s): %v", groupNameCN, err) + return users, errors.New("error searching group members in LDAP directory") + } + return users, nil +} + +// AuthorizedUserWithSession will return the API user associated with the Session ID if it +// exists and hasn't expired, and update session's LastUsed field. The state of the upstream LDAP server +// is polled and synced at the defined interval via a SleeperTask +func (l *ldapAuthenticator) AuthorizedUserWithSession(sessionID string) (sessions.User, error) { + if len(sessionID) == 0 { + return sessions.User{}, errors.New("session ID cannot be empty") + } + var foundUser sessions.User + err := l.q.Transaction(func(tx pg.Queryer) error { + // Query the ldap_sessions table for given session ID, user role and email are cached so + // no further upstream LDAP query is performed + var foundSession struct { + UserEmail string + UserRole sessions.UserRole + Valid bool + } + if err := tx.Get(&foundSession, + "SELECT user_email, user_role, created_at + $2 >= now() as valid FROM ldap_sessions WHERE id = $1", + sessionID, l.config.SessionTimeout().Duration(), + ); err != nil { + return sessions.ErrUserSessionExpired + } + if !foundSession.Valid { + // Sessions expired, purge + return sessions.ErrUserSessionExpired + } + foundUser = sessions.User{ + Email: foundSession.UserEmail, + Role: foundSession.UserRole, + } + return nil + }) + if err != nil { + if errors.Is(err, sessions.ErrUserSessionExpired) { + if _, execErr := l.q.Exec("DELETE FROM ldap_sessions WHERE id = $1", sessionID); err != nil { + l.lggr.Errorf("error purging stale ldap session: %v", execErr) + } + } + return sessions.User{}, err + } + return foundUser, nil +} + +// DeleteUser is not supported for read only LDAP +func (l *ldapAuthenticator) DeleteUser(email string) error { + return sessions.ErrNotSupported +} + +// DeleteUserSession removes an ldapSession table entry by ID +func (l *ldapAuthenticator) DeleteUserSession(sessionID string) error { + _, err := l.q.Exec("DELETE FROM ldap_sessions WHERE id = $1", sessionID) + return err +} + +// GetUserWebAuthn returns an empty stub, MFA token prompt is handled either by the upstream +// server blocking callback, or an error code to pass a OTP +func (l *ldapAuthenticator) GetUserWebAuthn(email string) ([]sessions.WebAuthn, error) { + return []sessions.WebAuthn{}, nil +} + +// CreateSession will forward the session request credentials to the +// LDAP server, querying for a user + role response if username and +// password match. The API call is blocking with timeout, so a sufficient timeout +// should allow the user to respond to potential MFA push notifications +func (l *ldapAuthenticator) CreateSession(sr sessions.SessionRequest) (string, error) { + conn, err := l.ldapClient.CreateEphemeralConnection() + if err != nil { + return "", errors.New("unable to establish connection to LDAP server with provided URL and credentials") + } + defer conn.Close() + + var returnErr error + + // Attempt to LDAP Bind with user provided credentials + escapedEmail := ldap.EscapeFilter(strings.ToLower(sr.Email)) + searchBaseDN := fmt.Sprintf("%s=%s,%s,%s", l.config.BaseUserAttr(), escapedEmail, l.config.UsersDN(), l.config.BaseDN()) + if err = conn.Bind(searchBaseDN, sr.Password); err != nil { + l.lggr.Infof("Error binding user authentication request in LDAP Bind: %v", err) + returnErr = errors.New("unable to log in with LDAP server. Check credentials") + } + + // Bind was successful meaning user and credentials are present in LDAP directory + // Reuse FindUser functionality to fetch user roles used to create ldap_session entry + // with cached user email and role + foundUser, err := l.FindUser(escapedEmail) + if err != nil { + l.lggr.Infof("Successful user login, but error querying for user groups: user: %s, error %v", escapedEmail, err) + returnErr = errors.New("log in successful, but no assigned groups to assume role") + } + + isLocalUser := false + if returnErr != nil { + // Unable to log in against LDAP server, attempt fallback local auth with credentials, case of local CLI Admin account + // Successful local user sessions can not be managed by the upstream server and have expiration handled by the reaper sync module + foundUser, returnErr = l.localLoginFallback(sr) + isLocalUser = true + } + + // If err is still populated, return + if returnErr != nil { + return "", returnErr + } + + l.lggr.Infof("Successful LDAP login request for user %s - %s", sr.Email, foundUser.Role) + + // Save session, user, and role to database. Given a session ID for future queries, the LDAP server will not be queried + // Sessions are set to expire after the duration + creation date elapsed, and are synced on an interval against the upstream + // LDAP server + session := sessions.NewSession() + _, err = l.q.Exec( + "INSERT INTO ldap_sessions (id, user_email, user_role, localauth_user, created_at) VALUES ($1, $2, $3, $4, now())", + session.ID, + strings.ToLower(sr.Email), + foundUser.Role, + isLocalUser, + ) + if err != nil { + l.lggr.Errorf("unable to create new session in ldap_sessions table %v", err) + return "", fmt.Errorf("error creating local LDAP session: %w", err) + } + + l.auditLogger.Audit(audit.AuthLoginSuccessNo2FA, map[string]interface{}{"email": sr.Email}) + + return session.ID, nil +} + +// ClearNonCurrentSessions removes all ldap_sessions but the id passed in. +func (l *ldapAuthenticator) ClearNonCurrentSessions(sessionID string) error { + _, err := l.q.Exec("DELETE FROM ldap_sessions where id != $1", sessionID) + return err +} + +// CreateUser is not supported for read only LDAP +func (l *ldapAuthenticator) CreateUser(user *sessions.User) error { + return sessions.ErrNotSupported +} + +// UpdateRole is not supported for read only LDAP +func (l *ldapAuthenticator) UpdateRole(email, newRole string) (sessions.User, error) { + return sessions.User{}, sessions.ErrNotSupported +} + +// SetPassword for remote users is not supported via the read only LDAP implementation, however change password +// in the context of updating a local admin user's password is required +func (l *ldapAuthenticator) SetPassword(user *sessions.User, newPassword string) error { + // Ensure specified user is part of the local admins user table + var localAdminUser sessions.User + if err := l.q.Transaction(func(tx pg.Queryer) error { + sql := "SELECT * FROM users WHERE lower(email) = lower($1)" + return tx.Get(&localAdminUser, sql, user.Email) + }); err != nil { + l.lggr.Infof("Can not change password, local user with email not found in users table: %s, err: %v", user.Email, err) + return sessions.ErrNotSupported + } + + // User is local admin, save new password + hashedPassword, err := utils.HashPassword(newPassword) + if err != nil { + return err + } + if err := l.q.Transaction(func(tx pg.Queryer) error { + sql := "UPDATE users SET hashed_password = $1, updated_at = now() WHERE email = $2 RETURNING *" + return tx.Get(user, sql, hashedPassword, user.Email) + }); err != nil { + l.lggr.Errorf("unable to set password for user: %s, err: %v", user.Email, err) + return errors.New("unable to save password") + } + return nil +} + +// TestPassword tests if an LDAP login bind can be performed with provided credentials, returns nil if success +func (l *ldapAuthenticator) TestPassword(email string, password string) error { + conn, err := l.ldapClient.CreateEphemeralConnection() + if err != nil { + return errors.New("unable to establish connection to LDAP server with provided URL and credentials") + } + defer conn.Close() + + // Attempt to LDAP Bind with user provided credentials + escapedEmail := ldap.EscapeFilter(strings.ToLower(email)) + searchBaseDN := fmt.Sprintf("%s=%s,%s,%s", l.config.BaseUserAttr(), escapedEmail, l.config.UsersDN(), l.config.BaseDN()) + err = conn.Bind(searchBaseDN, password) + if err == nil { + return nil + } + l.lggr.Infof("Error binding user authentication request in TestPassword call LDAP Bind: %v", err) + + // Fall back to test local users table in case of supported local CLI users as well + var hashedPassword string + if err := l.q.Get(&hashedPassword, "SELECT hashed_password FROM users WHERE lower(email) = lower($1)", email); err != nil { + return errors.New("invalid credentials") + } + if !utils.CheckPasswordHash(password, hashedPassword) { + return errors.New("invalid credentials") + } + + return nil +} + +// CreateAndSetAuthToken generates a new credential token with the user role +func (l *ldapAuthenticator) CreateAndSetAuthToken(user *sessions.User) (*auth.Token, error) { + newToken := auth.NewToken() + + err := l.SetAuthToken(user, newToken) + if err != nil { + return nil, err + } + + return newToken, nil +} + +// SetAuthToken updates the user to use the given Authentication Token. +func (l *ldapAuthenticator) SetAuthToken(user *sessions.User, token *auth.Token) error { + if !l.config.UserApiTokenEnabled() { + return errors.New("API token is not enabled ") + } + + salt := utils.NewSecret(utils.DefaultSecretSize) + hashedSecret, err := auth.HashedSecret(token, salt) + if err != nil { + return fmt.Errorf("LDAPAuth SetAuthToken hashed secret error: %w", err) + } + + err = l.q.Transaction(func(tx pg.Queryer) error { + // Is this user a local CLI Admin or upstream LDAP user? + // Check presence in local users table. Set localauth_user column true if present. + // This flag omits the session/token from being purged by the sync daemon/reaper.go + isLocalCLIAdmin := false + err = l.q.QueryRow("SELECT EXISTS (SELECT 1 FROM users WHERE email = $1)", user.Email).Scan(&isLocalCLIAdmin) + if err != nil { + return fmt.Errorf("error checking user presence in users table: %w", err) + } + + // Remove any existing API tokens + if _, err = l.q.Exec("DELETE FROM ldap_user_api_tokens WHERE user_email = $1", user.Email); err != nil { + return fmt.Errorf("error executing DELETE FROM ldap_user_api_tokens: %w", err) + } + // Create new API token for user + _, err = l.q.Exec( + "INSERT INTO ldap_user_api_tokens (user_email, user_role, localauth_user, token_key, token_salt, token_hashed_secret, created_at) VALUES ($1, $2, $3, $4, $5, $6, now())", + user.Email, + user.Role, + isLocalCLIAdmin, + token.AccessKey, + salt, + hashedSecret, + ) + if err != nil { + return fmt.Errorf("failed insert into ldap_user_api_tokens: %w", err) + } + return nil + }) + if err != nil { + return errors.New("error creating API token") + } + + l.auditLogger.Audit(audit.APITokenCreated, map[string]interface{}{"user": user.Email}) + return nil +} + +// DeleteAuthToken clears and disables the users Authentication Token. +func (l *ldapAuthenticator) DeleteAuthToken(user *sessions.User) error { + _, err := l.q.Exec("DELETE FROM ldap_user_api_tokens WHERE email = $1") + return err +} + +// SaveWebAuthn is not supported for read only LDAP +func (l *ldapAuthenticator) SaveWebAuthn(token *sessions.WebAuthn) error { + return sessions.ErrNotSupported +} + +// Sessions returns all sessions limited by the parameters. +func (l *ldapAuthenticator) Sessions(offset, limit int) ([]sessions.Session, error) { + var sessions []sessions.Session + sql := `SELECT * FROM ldap_sessions ORDER BY created_at, id LIMIT $1 OFFSET $2;` + if err := l.q.Select(&sessions, sql, limit, offset); err != nil { + return sessions, nil + } + return sessions, nil +} + +// FindExternalInitiator supports the 'Run' role external intiator header auth functionality +func (l *ldapAuthenticator) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiator, error) { + exi := &bridges.ExternalInitiator{} + err := l.q.Get(exi, `SELECT * FROM external_initiators WHERE access_key = $1`, eia.AccessKey) + return exi, err +} + +// localLoginFallback tests the credentials provided against the 'local' authentication method +// This covers the case of local CLI API calls requiring local login separate from the LDAP server +func (l *ldapAuthenticator) localLoginFallback(sr sessions.SessionRequest) (sessions.User, error) { + var user sessions.User + sql := "SELECT * FROM users WHERE lower(email) = lower($1)" + err := l.q.Get(&user, sql, sr.Email) + if err != nil { + return user, err + } + if !constantTimeEmailCompare(strings.ToLower(sr.Email), strings.ToLower(user.Email)) { + l.auditLogger.Audit(audit.AuthLoginFailedEmail, map[string]interface{}{"email": sr.Email}) + return user, errors.New("invalid email") + } + + if !utils.CheckPasswordHash(sr.Password, user.HashedPassword) { + l.auditLogger.Audit(audit.AuthLoginFailedPassword, map[string]interface{}{"email": sr.Email}) + return user, errors.New("invalid password") + } + + return user, nil +} + +// validateUsersActive performs an additional LDAP server query for the supplied emails, checking the +// returned user data for an 'active' property defined optionally in the config. +// Returns same length bool 'valid' array, indexed by sorted email +func (l *ldapAuthenticator) validateUsersActive(emails []string) ([]bool, error) { + validUsers := make([]bool, len(emails)) + // If active attribute to check is not defined in config, skip + if l.config.ActiveAttribute() == "" { + // fill with valids + for i := range emails { + validUsers[i] = true + } + return validUsers, nil + } + + conn, err := l.ldapClient.CreateEphemeralConnection() + if err != nil { + l.lggr.Errorf("error in LDAP dial: ", err) + return validUsers, errors.New("unable to establish connection to LDAP server with provided URL and credentials") + } + defer conn.Close() + + // Build the full email list query to pull all 'isActive' information for each user specified in one query + filterQuery := "(|" + for _, email := range emails { + escapedEmail := ldap.EscapeFilter(email) + filterQuery = fmt.Sprintf("%s(%s=%s)", filterQuery, l.config.BaseUserAttr(), escapedEmail) + } + filterQuery = fmt.Sprintf("(&%s))", filterQuery) + searchBaseDN := fmt.Sprintf("%s,%s", l.config.UsersDN(), l.config.BaseDN()) + searchRequest := ldap.NewSearchRequest( + searchBaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, int(l.config.QueryTimeout().Seconds()), false, + filterQuery, + []string{l.config.BaseUserAttr(), l.config.ActiveAttribute()}, + nil, + ) + // Query LDAP server for the ActiveAttribute property of each specified user + results, err := conn.Search(searchRequest) + if err != nil { + l.lggr.Errorf("error searching user in LDAP query: %v", err) + return validUsers, errors.New("error searching users in LDAP directory") + } + + // Ensure user response entries + if len(results.Entries) == 0 { + return validUsers, ErrUserNotInUpstream + } + + // Pull expected ActiveAttribute value from list of string possible values + // keyed on email for final step to return flag bool list where order is preserved + emailToActiveMap := make(map[string]bool) + for _, result := range results.Entries { + isActiveAttribute := result.GetAttributeValue(l.config.ActiveAttribute()) + uidAttribute := result.GetAttributeValue(l.config.BaseUserAttr()) + emailToActiveMap[uidAttribute] = isActiveAttribute == l.config.ActiveAttributeAllowedValue() + } + for i, email := range emails { + active, ok := emailToActiveMap[email] + if ok && active { + validUsers[i] = true + } + } + + return validUsers, nil +} + +// ldapGroupMembersListToUser queries the LDAP server given a conn for a list of uniqueMember who are part of the parameterized group. Reused by sync.go +func ldapGroupMembersListToUser( + conn LDAPConn, + groupNameCN string, + roleToAssign sessions.UserRole, + groupsDN string, + baseDN string, + queryTimeout time.Duration, + lggr logger.Logger, +) ([]sessions.User, error) { + users := []sessions.User{} + // Prepare and query the GroupsDN for the specified group name + searchBaseDN := fmt.Sprintf("%s, %s", groupsDN, baseDN) + filterQuery := fmt.Sprintf("(&(cn=%s))", groupNameCN) + searchRequest := ldap.NewSearchRequest( + searchBaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, int(queryTimeout.Seconds()), false, + filterQuery, + []string{UniqueMemberAttribute}, + nil, + ) + result, err := conn.Search(searchRequest) + if err != nil { + lggr.Errorf("error searching group members in LDAP query: %v", err) + return users, errors.New("error searching group members in LDAP directory") + } + + // The result.Entry query response here is for the 'group' type of LDAP resource. The result should be a single entry, containing + // a single Attribute named 'uniqueMember' containing a list of string Values. These Values are strings that should be returned in + // the format "uid=test.user@example.com,ou=users,dc=example,dc=com". The 'uid' is then manually parsed here as the library does + // not expose the functionality + if len(result.Entries) != 1 { + lggr.Errorf("unexpected length of query results for group user members, expected one got %d", len(result.Entries)) + return users, errors.New("error searching group members in LDAP directory") + } + + // Get string list of members from 'uniqueMember' attribute + uniqueMemberValues := result.Entries[0].GetAttributeValues(UniqueMemberAttribute) + for _, uniqueMemberEntry := range uniqueMemberValues { + parts := strings.Split(uniqueMemberEntry, ",") // Split attribute value on comma (uid, ou, dc parts) + uidComponent := "" + for _, part := range parts { // Iterate parts for "uid=" + if strings.HasPrefix(part, "uid=") { + uidComponent = part + break + } + } + if uidComponent == "" { + lggr.Errorf("unexpected LDAP group query response for unique members - expected list of LDAP Values for uniqueMember containing LDAP strings in format uid=test.user@example.com,ou=users,dc=example,dc=com. Got %s", uniqueMemberEntry) + continue + } + // Map each user email to the sessions.User struct + userEmail := strings.TrimPrefix(uidComponent, "uid=") + users = append(users, sessions.User{ + Email: userEmail, + Role: roleToAssign, + }) + } + return users, nil +} + +// groupSearchResultsToUserRole takes a list of LDAP group search result entries and returns the associated +// internal user role based on the group name mappings defined in the configuration +func (l *ldapAuthenticator) groupSearchResultsToUserRole(ldapGroups []*ldap.Entry) (sessions.UserRole, error) { + return GroupSearchResultsToUserRole( + ldapGroups, + l.config.AdminUserGroupCN(), + l.config.EditUserGroupCN(), + l.config.RunUserGroupCN(), + l.config.ReadUserGroupCN(), + ) +} + +func GroupSearchResultsToUserRole(ldapGroups []*ldap.Entry, adminCN string, editCN string, runCN string, readCN string) (sessions.UserRole, error) { + // If defined Admin group name is present in groups search result, return UserRoleAdmin + for _, group := range ldapGroups { + if group.GetAttributeValue("cn") == adminCN { + return sessions.UserRoleAdmin, nil + } + } + // Check edit role + for _, group := range ldapGroups { + if group.GetAttributeValue("cn") == editCN { + return sessions.UserRoleEdit, nil + } + } + // Check run role + for _, group := range ldapGroups { + if group.GetAttributeValue("cn") == runCN { + return sessions.UserRoleRun, nil + } + } + // Check view role + for _, group := range ldapGroups { + if group.GetAttributeValue("cn") == readCN { + return sessions.UserRoleView, nil + } + } + // No role group found, error + return sessions.UserRoleView, ErrUserNoLDAPGroups +} + +const constantTimeEmailLength = 256 + +func constantTimeEmailCompare(left, right string) bool { + length := mathutil.Max(constantTimeEmailLength, len(left), len(right)) + leftBytes := make([]byte, length) + rightBytes := make([]byte, length) + copy(leftBytes, left) + copy(rightBytes, right) + return subtle.ConstantTimeCompare(leftBytes, rightBytes) == 1 +} diff --git a/core/sessions/ldapauth/ldap_test.go b/core/sessions/ldapauth/ldap_test.go new file mode 100644 index 0000000000..261141d66e --- /dev/null +++ b/core/sessions/ldapauth/ldap_test.go @@ -0,0 +1,639 @@ +package ldapauth_test + +import ( + "errors" + "fmt" + "testing" + "time" + + "github.com/go-ldap/ldap/v3" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/logger/audit" + "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/sessions/ldapauth" + "github.com/smartcontractkit/chainlink/v2/core/sessions/ldapauth/mocks" +) + +// Setup LDAP Auth authenticator +func setupAuthenticationProvider(t *testing.T, ldapClient ldapauth.LDAPClient) (*sqlx.DB, sessions.AuthenticationProvider) { + t.Helper() + + cfg := ldapauth.TestConfig{} + db := pgtest.NewSqlxDB(t) + ldapAuthProvider, err := ldapauth.NewTestLDAPAuthenticator(db, pgtest.NewQConfig(true), &cfg, true, logger.TestLogger(t), &audit.AuditLoggerService{}) + if err != nil { + t.Fatalf("Error constructing NewTestLDAPAuthenticator: %v\n", err) + } + + // Override the LDAPClient responsible for returning the *ldap.Conn struct with Mock + ldapAuthProvider.SetLDAPClient(ldapClient) + return db, ldapAuthProvider +} + +func TestORM_FindUser_Empty(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // User not in upstream, return no entry + expectedResults := ldap.SearchResult{} + + // On search performed for validateUsersActive + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&expectedResults, nil) + + // Not in upstream, no local admin users, expect error + _, err := ldapAuthProvider.FindUser("unknown-user") + require.ErrorContains(t, err, "LDAP query returned no matching users") +} + +func TestORM_FindUser_NoGroups(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // User present in Upstream but no groups assigned + user1 := cltest.MustRandomUser(t) + expectedResults := ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "cn=User One,ou=Users,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "organizationalStatus", + Values: []string{"ACTIVE"}, + }, + { + Name: "uid", + Values: []string{user1.Email}, + }, + }, + }, + }, + } + + // On search performed for validateUsersActive + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&expectedResults, nil) + + // No Groups, expect error + _, err := ldapAuthProvider.FindUser(user1.Email) + require.ErrorContains(t, err, "user present in directory, but matching no role groups assigned") +} + +func TestORM_FindUser_NotActive(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // User present in Upstream but not active + user1 := cltest.MustRandomUser(t) + expectedResults := ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "cn=User One,ou=Users,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "organizationalStatus", + Values: []string{"INACTIVE"}, + }, + { + Name: "uid", + Values: []string{user1.Email}, + }, + }, + }, + }, + } + + // On search performed for validateUsersActive + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&expectedResults, nil) + + // User not active, expect error + _, err := ldapAuthProvider.FindUser(user1.Email) + require.ErrorContains(t, err, "user not active") +} + +func TestORM_FindUser_Single(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // User present and valid + user1 := cltest.MustRandomUser(t) + expectedResults := ldap.SearchResult{ // Users query + Entries: []*ldap.Entry{ + { + DN: "cn=User One,ou=Users,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "organizationalStatus", + Values: []string{"ACTIVE"}, + }, + { + Name: "uid", + Values: []string{user1.Email}, + }, + }, + }, + }, + } + expectedGroupResults := ldap.SearchResult{ // Groups query + Entries: []*ldap.Entry{ + { + DN: "cn=NodeEditors,ou=Users,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{"NodeEditors"}, + }, + }, + }, + }, + } + + // On search performed for validateUsersActive + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&expectedResults, nil).Once() + + // Second call on user groups search + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&expectedGroupResults, nil).Once() + + // User active, and has editor group. Expect success + user, err := ldapAuthProvider.FindUser(user1.Email) + require.NoError(t, err) + require.Equal(t, user1.Email, user.Email) + require.Equal(t, sessions.UserRoleEdit, user.Role) +} + +func TestORM_FindUser_FallbackMatchLocalAdmin(t *testing.T) { + t.Parallel() + + // Initilaize LDAP Authentication Provider with mock client + mockLdapClient := mocks.NewLDAPClient(t) + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // Not in upstream, but utilize text fixture admin user presence in test DB. Succeed + user, err := ldapAuthProvider.FindUser(cltest.APIEmailAdmin) + require.NoError(t, err) + require.Equal(t, cltest.APIEmailAdmin, user.Email) + require.Equal(t, sessions.UserRoleAdmin, user.Role) +} + +func TestORM_FindUserByAPIToken_Success(t *testing.T) { + // Initilaize LDAP Authentication Provider with mock client + mockLdapClient := mocks.NewLDAPClient(t) + db, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // Ensure valid tokens return a user with role + testEmail := "test@test.com" + apiToken := "example" + _, err := db.Exec("INSERT INTO ldap_user_api_tokens values ($1, 'edit', false, $2, '', '', now())", testEmail, apiToken) + require.NoError(t, err) + + // Found user by API token in specific ldap_user_api_tokens table + user, err := ldapAuthProvider.FindUserByAPIToken(apiToken) + require.NoError(t, err) + require.Equal(t, testEmail, user.Email) + require.Equal(t, sessions.UserRoleEdit, user.Role) +} + +func TestORM_FindUserByAPIToken_Expired(t *testing.T) { + cfg := ldapauth.TestConfig{} + + // Initilaize LDAP Authentication Provider with mock client + mockLdapClient := mocks.NewLDAPClient(t) + db, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // Ensure valid tokens return a user with role + testEmail := "test@test.com" + apiToken := "example" + expiredTime := time.Now().Add(-cfg.UserAPITokenDuration().Duration()) + _, err := db.Exec("INSERT INTO ldap_user_api_tokens values ($1, 'edit', false, $2, '', '', $3)", testEmail, apiToken, expiredTime) + require.NoError(t, err) + + // Token found, but expired. Expect error + _, err = ldapAuthProvider.FindUserByAPIToken(apiToken) + require.Equal(t, sessions.ErrUserSessionExpired, err) +} + +func TestORM_ListUsers_Full(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + user1 := cltest.MustRandomUser(t) + user2 := cltest.MustRandomUser(t) + user3 := cltest.MustRandomUser(t) + user4 := cltest.MustRandomUser(t) + user5 := cltest.MustRandomUser(t) + user6 := cltest.MustRandomUser(t) + + // LDAP Group queries per role - admin + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeAdminsGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: ldapauth.UniqueMemberAttribute, + Values: []string{ + fmt.Sprintf("uid=%s,ou=users,dc=example,dc=com", user1.Email), + fmt.Sprintf("uid=%s,ou=users,dc=example,dc=com", user2.Email), + }, + }, + }, + }, + }, + }, nil).Once() + // LDAP Group queries per role - edit + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeEditorsGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: ldapauth.UniqueMemberAttribute, + Values: []string{ + fmt.Sprintf("uid=%s,ou=users,dc=example,dc=com", user3.Email), + }, + }, + }, + }, + }, + }, nil).Once() + // LDAP Group queries per role - run + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "cn=NodeRunners,ou=Groups,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: ldapauth.UniqueMemberAttribute, + Values: []string{ + fmt.Sprintf("uid=%s,ou=users,dc=example,dc=com", user4.Email), + fmt.Sprintf("uid=%s,ou=users,dc=example,dc=com", user4.Email), // Test deduped + fmt.Sprintf("uid=%s,ou=users,dc=example,dc=com", user5.Email), + }, + }, + }, + }, + }, + }, nil).Once() + // LDAP Group queries per role - view + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "cn=NodeReadOnly,ou=Groups,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: ldapauth.UniqueMemberAttribute, + Values: []string{ + fmt.Sprintf("uid=%s,ou=users,dc=example,dc=com", user6.Email), + }, + }, + }, + }, + }, + }, nil).Once() + // Lastly followed by IsActive lookup + type userActivePair struct { + email string + active string + } + emailsActive := []userActivePair{ + {user1.Email, "ACTIVE"}, + {user2.Email, "INACTIVE"}, + {user3.Email, "ACTIVE"}, + {user4.Email, "ACTIVE"}, + {user5.Email, "INACTIVE"}, + {user6.Email, "ACTIVE"}, + } + listUpstreamUsersQuery := ldap.SearchResult{} + for _, upstreamUser := range emailsActive { + listUpstreamUsersQuery.Entries = append(listUpstreamUsersQuery.Entries, &ldap.Entry{ + DN: "cn=User,ou=Users,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "organizationalStatus", + Values: []string{upstreamUser.active}, + }, + { + Name: "uid", + Values: []string{upstreamUser.email}, + }, + }, + }, + ) + } + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&listUpstreamUsersQuery, nil).Once() + + // Asserts 'uid=' parsing log in ldapGroupMembersListToUser + // Expected full list of users above, including local admin user, excluding 'inactive' and duplicate users + users, err := ldapAuthProvider.ListUsers() + require.NoError(t, err) + require.Equal(t, users[0].Email, user1.Email) + require.Equal(t, users[0].Role, sessions.UserRoleAdmin) + require.Equal(t, users[1].Email, user3.Email) // User 2 inactive + require.Equal(t, users[1].Role, sessions.UserRoleEdit) + require.Equal(t, users[2].Email, user4.Email) + require.Equal(t, users[2].Role, sessions.UserRoleRun) + require.Equal(t, users[3].Email, user6.Email) // User 5 inactive + require.Equal(t, users[3].Role, sessions.UserRoleView) + require.Equal(t, users[4].Email, cltest.APIEmailAdmin) // Text fixture user is local admin included as well + require.Equal(t, users[4].Role, sessions.UserRoleAdmin) +} + +func TestORM_CreateSession_UpstreamBind(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // Upsream user present + user1 := cltest.MustRandomUser(t) + expectedResults := ldap.SearchResult{ // Users query + Entries: []*ldap.Entry{ + { + DN: "cn=User One,ou=Users,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "organizationalStatus", + Values: []string{"ACTIVE"}, + }, + { + Name: "uid", + Values: []string{user1.Email}, + }, + }, + }, + }, + } + expectedGroupResults := ldap.SearchResult{ // Groups query + Entries: []*ldap.Entry{ + { + DN: "cn=NodeEditors,ou=Users,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{"NodeEditors"}, + }, + }, + }, + }, + } + + // On search performed for validateUsersActive + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&expectedResults, nil).Once() + + // Second call on user groups search + mockLdapConnProvider.On("Search", mock.AnythingOfType("*ldap.SearchRequest")).Return(&expectedGroupResults, nil).Once() + + // User active, and has editor group. Expect success + mockLdapConnProvider.On("Bind", mock.Anything, cltest.Password).Return(nil) + sessionRequest := sessions.SessionRequest{ + Email: user1.Email, + Password: cltest.Password, + } + + _, err := ldapAuthProvider.CreateSession(sessionRequest) + require.NoError(t, err) +} + +func TestORM_CreateSession_LocalAdminFallbackLogin(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // Fail the bind to trigger 'localLoginFallback' - local admin users should still be able to login + // regardless of whether the authentication provider is remote or not + mockLdapConnProvider.On("Bind", mock.Anything, cltest.Password).Return(errors.New("unable to login via LDAP server")).Once() + + // User active, and has editor group. Expect success + sessionRequest := sessions.SessionRequest{ + Email: cltest.APIEmailAdmin, + Password: cltest.Password, + } + + _, err := ldapAuthProvider.CreateSession(sessionRequest) + require.NoError(t, err) + + // Finally, assert login failing altogether + // User active, and has editor group. Expect success + mockLdapConnProvider.On("Bind", mock.Anything, "incorrect-password").Return(errors.New("unable to login via LDAP server")).Once() + sessionRequest = sessions.SessionRequest{ + Email: cltest.APIEmailAdmin, + Password: "incorrect-password", + } + + _, err = ldapAuthProvider.CreateSession(sessionRequest) + require.ErrorContains(t, err, "invalid password") +} + +func TestORM_SetPassword_LocalAdminFallbackLogin(t *testing.T) { + t.Parallel() + + mockLdapClient := mocks.NewLDAPClient(t) + mockLdapConnProvider := mocks.NewLDAPConn(t) + mockLdapClient.On("CreateEphemeralConnection").Return(mockLdapConnProvider, nil) + mockLdapConnProvider.On("Close").Return(nil) + + // Initilaize LDAP Authentication Provider with mock client + _, ldapAuthProvider := setupAuthenticationProvider(t, mockLdapClient) + + // Fail the bind to trigger 'localLoginFallback' - local admin users should still be able to login + // regardless of whether the authentication provider is remote or not + mockLdapConnProvider.On("Bind", mock.Anything, cltest.Password).Return(errors.New("unable to login via LDAP server")).Once() + + // User active, and has editor group. Expect success + sessionRequest := sessions.SessionRequest{ + Email: cltest.APIEmailAdmin, + Password: cltest.Password, + } + + _, err := ldapAuthProvider.CreateSession(sessionRequest) + require.NoError(t, err) + + // Finally, assert login failing altogether + // User active, and has editor group. Expect success + mockLdapConnProvider.On("Bind", mock.Anything, "incorrect-password").Return(errors.New("unable to login via LDAP server")).Once() + sessionRequest = sessions.SessionRequest{ + Email: cltest.APIEmailAdmin, + Password: "incorrect-password", + } + + _, err = ldapAuthProvider.CreateSession(sessionRequest) + require.ErrorContains(t, err, "invalid password") +} + +func TestORM_MapSearchGroups(t *testing.T) { + t.Parallel() + + cfg := ldapauth.TestConfig{} + + tests := []struct { + name string + groupsQuerySearchResult []*ldap.Entry + wantMappedRole sessions.UserRole + wantErr error + }{ + { + "user in admin group only", + []*ldap.Entry{ + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeAdminsGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{ldapauth.NodeAdminsGroupCN}, + }, + }, + }, + }, + sessions.UserRoleAdmin, + nil, + }, + { + "user in edit group", + []*ldap.Entry{ + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeEditorsGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{ldapauth.NodeEditorsGroupCN}, + }, + }, + }, + }, + sessions.UserRoleEdit, + nil, + }, + { + "user in run group", + []*ldap.Entry{ + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeRunnersGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{ldapauth.NodeRunnersGroupCN}, + }, + }, + }, + }, + sessions.UserRoleRun, + nil, + }, + { + "user in view role", + []*ldap.Entry{ + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeReadOnlyGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{ldapauth.NodeReadOnlyGroupCN}, + }, + }, + }, + }, + sessions.UserRoleView, + nil, + }, + { + "user in none", + []*ldap.Entry{}, + sessions.UserRole(""), // ignored, error case + ldapauth.ErrUserNoLDAPGroups, + }, + { + "user in run and view", + []*ldap.Entry{ + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeRunnersGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{ldapauth.NodeRunnersGroupCN}, + }, + }, + }, + { + DN: fmt.Sprintf("cn=%s,ou=Groups,dc=example,dc=com", ldapauth.NodeReadOnlyGroupCN), + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{ldapauth.NodeReadOnlyGroupCN}, + }, + }, + }, + }, + sessions.UserRoleRun, // Take highest role + nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + role, err := ldapauth.GroupSearchResultsToUserRole( + test.groupsQuerySearchResult, + cfg.AdminUserGroupCN(), + cfg.EditUserGroupCN(), + cfg.RunUserGroupCN(), + cfg.ReadUserGroupCN(), + ) + if test.wantErr != nil { + assert.Equal(t, test.wantErr, err) + } else { + assert.Equal(t, test.wantMappedRole, role) + } + }) + } +} diff --git a/core/sessions/ldapauth/mocks/ldap_client.go b/core/sessions/ldapauth/mocks/ldap_client.go new file mode 100644 index 0000000000..7a44778dca --- /dev/null +++ b/core/sessions/ldapauth/mocks/ldap_client.go @@ -0,0 +1,53 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package mocks + +import ( + ldapauth "github.com/smartcontractkit/chainlink/v2/core/sessions/ldapauth" + mock "github.com/stretchr/testify/mock" +) + +// LDAPClient is an autogenerated mock type for the LDAPClient type +type LDAPClient struct { + mock.Mock +} + +// CreateEphemeralConnection provides a mock function with given fields: +func (_m *LDAPClient) CreateEphemeralConnection() (ldapauth.LDAPConn, error) { + ret := _m.Called() + + var r0 ldapauth.LDAPConn + var r1 error + if rf, ok := ret.Get(0).(func() (ldapauth.LDAPConn, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() ldapauth.LDAPConn); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ldapauth.LDAPConn) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewLDAPClient creates a new instance of LDAPClient. 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 NewLDAPClient(t interface { + mock.TestingT + Cleanup(func()) +}) *LDAPClient { + mock := &LDAPClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/sessions/ldapauth/mocks/ldap_conn.go b/core/sessions/ldapauth/mocks/ldap_conn.go new file mode 100644 index 0000000000..c05fb6c4fa --- /dev/null +++ b/core/sessions/ldapauth/mocks/ldap_conn.go @@ -0,0 +1,82 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package mocks + +import ( + ldap "github.com/go-ldap/ldap/v3" + + mock "github.com/stretchr/testify/mock" +) + +// LDAPConn is an autogenerated mock type for the LDAPConn type +type LDAPConn struct { + mock.Mock +} + +// Bind provides a mock function with given fields: username, password +func (_m *LDAPConn) Bind(username string, password string) error { + ret := _m.Called(username, password) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(username, password) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Close provides a mock function with given fields: +func (_m *LDAPConn) 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 +} + +// Search provides a mock function with given fields: searchRequest +func (_m *LDAPConn) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) { + ret := _m.Called(searchRequest) + + var r0 *ldap.SearchResult + var r1 error + if rf, ok := ret.Get(0).(func(*ldap.SearchRequest) (*ldap.SearchResult, error)); ok { + return rf(searchRequest) + } + if rf, ok := ret.Get(0).(func(*ldap.SearchRequest) *ldap.SearchResult); ok { + r0 = rf(searchRequest) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*ldap.SearchResult) + } + } + + if rf, ok := ret.Get(1).(func(*ldap.SearchRequest) error); ok { + r1 = rf(searchRequest) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewLDAPConn creates a new instance of LDAPConn. 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 NewLDAPConn(t interface { + mock.TestingT + Cleanup(func()) +}) *LDAPConn { + mock := &LDAPConn{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/sessions/ldapauth/sync.go b/core/sessions/ldapauth/sync.go new file mode 100644 index 0000000000..ce7a338f40 --- /dev/null +++ b/core/sessions/ldapauth/sync.go @@ -0,0 +1,343 @@ +package ldapauth + +import ( + "errors" + "fmt" + "time" + + "github.com/go-ldap/ldap/v3" + "github.com/lib/pq" + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type LDAPServerStateSyncer struct { + q pg.Q + ldapClient LDAPClient + config config.LDAP + lggr logger.Logger + nextSyncTime time.Time +} + +// NewLDAPServerStateSync creates a reaper that cleans stale sessions from the store. +func NewLDAPServerStateSync( + db *sqlx.DB, + pgCfg pg.QConfig, + config config.LDAP, + lggr logger.Logger, +) utils.SleeperTask { + namedLogger := lggr.Named("LDAPServerStateSync") + serverSync := LDAPServerStateSyncer{ + q: pg.NewQ(db, namedLogger, pgCfg), + ldapClient: newLDAPClient(config), + config: config, + lggr: namedLogger, + nextSyncTime: time.Time{}, + } + // If enabled, start a background task that calls the Sync/Work function on an + // interval without needing an auth event to trigger it + // Use IsInstant to check 0 value to omit functionality. + if !config.UpstreamSyncInterval().IsInstant() { + lggr.Info("LDAP Config UpstreamSyncInterval is non-zero, sync functionality will be called on a timer, respecting the UpstreamSyncRateLimit value") + serverSync.StartWorkOnTimer() + } else { + // Ensure upstream server state is synced on startup manually if interval check not set + serverSync.Work() + } + + // Start background Sync call task reactive to auth related events + serverSyncSleeperTask := utils.NewSleeperTask(&serverSync) + return serverSyncSleeperTask +} + +func (ldSync *LDAPServerStateSyncer) Name() string { + return "LDAPServerStateSync" +} + +func (ldSync *LDAPServerStateSyncer) StartWorkOnTimer() { + time.AfterFunc(ldSync.config.UpstreamSyncInterval().Duration(), ldSync.StartWorkOnTimer) + ldSync.Work() +} + +func (ldSync *LDAPServerStateSyncer) Work() { + // Purge expired ldap_sessions and ldap_user_api_tokens + recordCreationStaleThreshold := ldSync.config.SessionTimeout().Before(time.Now()) + err := ldSync.deleteStaleSessions(recordCreationStaleThreshold) + if err != nil { + ldSync.lggr.Error("unable to expire local LDAP sessions: ", err) + } + recordCreationStaleThreshold = ldSync.config.UserAPITokenDuration().Before(time.Now()) + err = ldSync.deleteStaleAPITokens(recordCreationStaleThreshold) + if err != nil { + ldSync.lggr.Error("unable to expire user API tokens: ", err) + } + + // Optional rate limiting check to limit the amount of upstream LDAP server queries performed + if !ldSync.config.UpstreamSyncRateLimit().IsInstant() { + if !time.Now().After(ldSync.nextSyncTime) { + return + } + + // Enough time has elapsed to sync again, store the time for when next sync is allowed and begin sync + ldSync.nextSyncTime = time.Now().Add(ldSync.config.UpstreamSyncRateLimit().Duration()) + } + + ldSync.lggr.Info("Begin Upstream LDAP provider state sync after checking time against config UpstreamSyncInterval and UpstreamSyncRateLimit") + + // For each defined role/group, query for the list of group members to gather the full list of possible users + users := []sessions.User{} + + conn, err := ldSync.ldapClient.CreateEphemeralConnection() + if err != nil { + ldSync.lggr.Errorf("Failed to Dial LDAP Server", err) + return + } + // Root level root user auth with credentials provided from config + bindStr := ldSync.config.BaseUserAttr() + "=" + ldSync.config.ReadOnlyUserLogin() + "," + ldSync.config.BaseDN() + if err = conn.Bind(bindStr, ldSync.config.ReadOnlyUserPass()); err != nil { + ldSync.lggr.Errorf("Unable to login as initial root LDAP user", err) + } + defer conn.Close() + + // Query for list of uniqueMember IDs present in Admin group + adminUsers, err := ldSync.ldapGroupMembersListToUser(conn, ldSync.config.AdminUserGroupCN(), sessions.UserRoleAdmin) + if err != nil { + ldSync.lggr.Errorf("Error in ldapGroupMembersListToUser: ", err) + return + } + // Query for list of uniqueMember IDs present in Edit group + editUsers, err := ldSync.ldapGroupMembersListToUser(conn, ldSync.config.EditUserGroupCN(), sessions.UserRoleEdit) + if err != nil { + ldSync.lggr.Errorf("Error in ldapGroupMembersListToUser: ", err) + return + } + // Query for list of uniqueMember IDs present in Edit group + runUsers, err := ldSync.ldapGroupMembersListToUser(conn, ldSync.config.RunUserGroupCN(), sessions.UserRoleRun) + if err != nil { + ldSync.lggr.Errorf("Error in ldapGroupMembersListToUser: ", err) + return + } + // Query for list of uniqueMember IDs present in Edit group + readUsers, err := ldSync.ldapGroupMembersListToUser(conn, ldSync.config.ReadUserGroupCN(), sessions.UserRoleView) + if err != nil { + ldSync.lggr.Errorf("Error in ldapGroupMembersListToUser: ", err) + return + } + + users = append(users, adminUsers...) + users = append(users, editUsers...) + users = append(users, runUsers...) + users = append(users, readUsers...) + + // Dedupe preserving order of highest role (sorted) + // Preserve members as a map for future lookup + upstreamUserStateMap := make(map[string]sessions.User) + dedupedEmails := []string{} + for _, user := range users { + if _, ok := upstreamUserStateMap[user.Email]; !ok { + upstreamUserStateMap[user.Email] = user + dedupedEmails = append(dedupedEmails, user.Email) + } + } + + // For each unique user in list of active sessions, check for 'Is Active' propery if defined in the config. Some LDAP providers + // list group members that are no longer marked as active + usersActiveFlags, err := ldSync.validateUsersActive(dedupedEmails, conn) + if err != nil { + ldSync.lggr.Errorf("Error validating supplied user list: ", err) + } + // Remove users in the upstreamUserStateMap source of truth who are part of groups but marked as deactivated/no-active + for i, active := range usersActiveFlags { + if !active { + delete(upstreamUserStateMap, dedupedEmails[i]) + } + } + + // upstreamUserStateMap is now the most up to date source of truth + // Now sync database sessions and roles with new data + err = ldSync.q.Transaction(func(tx pg.Queryer) error { + // First, purge users present in the local ldap_sessions table but not in the upstream server + type LDAPSession struct { + UserEmail string + UserRole sessions.UserRole + } + var existingSessions []LDAPSession + if err = tx.Select(&existingSessions, "SELECT user_email, user_role FROM ldap_sessions WHERE localauth_user = false"); err != nil { + return fmt.Errorf("unable to query ldap_sessions table: %w", err) + } + var existingAPITokens []LDAPSession + if err = tx.Select(&existingAPITokens, "SELECT user_email, user_role FROM ldap_user_api_tokens WHERE localauth_user = false"); err != nil { + return fmt.Errorf("unable to query ldap_user_api_tokens table: %w", err) + } + + // Create existing sessions and API tokens lookup map for later + existingSessionsMap := make(map[string]LDAPSession) + for _, sess := range existingSessions { + existingSessionsMap[sess.UserEmail] = sess + } + existingAPITokensMap := make(map[string]LDAPSession) + for _, sess := range existingAPITokens { + existingAPITokensMap[sess.UserEmail] = sess + } + + // Populate list of session emails present in the local session table but not in the upstream state + emailsToPurge := []interface{}{} + for _, ldapSession := range existingSessions { + if _, ok := upstreamUserStateMap[ldapSession.UserEmail]; !ok { + emailsToPurge = append(emailsToPurge, ldapSession.UserEmail) + } + } + // Likewise for API Tokens table + apiTokenEmailsToPurge := []interface{}{} + for _, ldapSession := range existingAPITokens { + if _, ok := upstreamUserStateMap[ldapSession.UserEmail]; !ok { + apiTokenEmailsToPurge = append(apiTokenEmailsToPurge, ldapSession.UserEmail) + } + } + + // Remove any active sessions this user may have + if len(emailsToPurge) > 0 { + _, err = ldSync.q.Exec("DELETE FROM ldap_sessions WHERE user_email = ANY($1)", pq.Array(emailsToPurge)) + if err != nil { + return err + } + } + + // Remove any active API tokens this user may have + if len(apiTokenEmailsToPurge) > 0 { + _, err = ldSync.q.Exec("DELETE FROM ldap_user_api_tokens WHERE user_email = ANY($1)", pq.Array(apiTokenEmailsToPurge)) + if err != nil { + return err + } + } + + // For each user session row, update role to match state of user map from upstream source + queryWhenClause := "" + emailValues := []interface{}{} + // Prepare CASE WHEN query statement with parameterized argument $n placeholders and matching role based on index + for email, user := range upstreamUserStateMap { + // Only build on SET CASE statement per local session and API token role, not for each upstream user value + _, sessionOk := existingSessionsMap[email] + _, tokenOk := existingAPITokensMap[email] + if !sessionOk && !tokenOk { + continue + } + emailValues = append(emailValues, email) + queryWhenClause += fmt.Sprintf("WHEN user_email = $%d THEN '%s' ", len(emailValues), user.Role) + } + + // If there are remaining user entries to update + if len(emailValues) != 0 { + // Set new role state for all rows in single Exec + query := fmt.Sprintf("UPDATE ldap_sessions SET user_role = CASE %s ELSE user_role END", queryWhenClause) + _, err = ldSync.q.Exec(query, emailValues...) + if err != nil { + return err + } + + // Update role of API tokens as well + query = fmt.Sprintf("UPDATE ldap_user_api_tokens SET user_role = CASE %s ELSE user_role END", queryWhenClause) + _, err = ldSync.q.Exec(query, emailValues...) + if err != nil { + return err + } + } + + ldSync.lggr.Info("local ldap_sessions and ldap_user_api_tokens table successfully synced with upstream LDAP state") + return nil + }) + if err != nil { + ldSync.lggr.Errorf("Error syncing local database state: ", err) + } + ldSync.lggr.Info("Upstream LDAP sync complete") +} + +// deleteStaleSessions deletes all ldap_sessions before the passed time. +func (ldSync *LDAPServerStateSyncer) deleteStaleSessions(before time.Time) error { + _, err := ldSync.q.Exec("DELETE FROM ldap_sessions WHERE created_at < $1", before) + return err +} + +// deleteStaleAPITokens deletes all ldap_user_api_tokens before the passed time. +func (ldSync *LDAPServerStateSyncer) deleteStaleAPITokens(before time.Time) error { + _, err := ldSync.q.Exec("DELETE FROM ldap_user_api_tokens WHERE created_at < $1", before) + return err +} + +// ldapGroupMembersListToUser queries the LDAP server given a conn for a list of uniqueMember who are part of the parameterized group +func (ldSync *LDAPServerStateSyncer) ldapGroupMembersListToUser(conn LDAPConn, groupNameCN string, roleToAssign sessions.UserRole) ([]sessions.User, error) { + users, err := ldapGroupMembersListToUser( + conn, groupNameCN, roleToAssign, ldSync.config.GroupsDN(), + ldSync.config.BaseDN(), ldSync.config.QueryTimeout(), + ldSync.lggr, + ) + if err != nil { + ldSync.lggr.Errorf("Error listing members of group (%s): %v", groupNameCN, err) + return users, errors.New("error searching group members in LDAP directory") + } + return users, nil +} + +// validateUsersActive performs an additional LDAP server query for the supplied emails, checking the +// returned user data for an 'active' property defined optionally in the config. +// Returns same length bool 'valid' array, order preserved +func (ldSync *LDAPServerStateSyncer) validateUsersActive(emails []string, conn LDAPConn) ([]bool, error) { + validUsers := make([]bool, len(emails)) + // If active attribute to check is not defined in config, skip + if ldSync.config.ActiveAttribute() == "" { + // pre fill with valids + for i := range emails { + validUsers[i] = true + } + return validUsers, nil + } + + // Build the full email list query to pull all 'isActive' information for each user specified in one query + filterQuery := "(|" + for _, email := range emails { + escapedEmail := ldap.EscapeFilter(email) + filterQuery = fmt.Sprintf("%s(%s=%s)", filterQuery, ldSync.config.BaseUserAttr(), escapedEmail) + } + filterQuery = fmt.Sprintf("(&%s))", filterQuery) + searchBaseDN := fmt.Sprintf("%s,%s", ldSync.config.UsersDN(), ldSync.config.BaseDN()) + searchRequest := ldap.NewSearchRequest( + searchBaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, int(ldSync.config.QueryTimeout().Seconds()), false, + filterQuery, + []string{ldSync.config.BaseUserAttr(), ldSync.config.ActiveAttribute()}, + nil, + ) + // Query LDAP server for the ActiveAttribute property of each specified user + results, err := conn.Search(searchRequest) + if err != nil { + ldSync.lggr.Errorf("Error searching user in LDAP query: %v", err) + return validUsers, errors.New("error searching users in LDAP directory") + } + // Ensure user response entries + if len(results.Entries) == 0 { + return validUsers, errors.New("no users matching email query") + } + + // Pull expected ActiveAttribute value from list of string possible values + // keyed on email for final step to return flag bool list where order is preserved + emailToActiveMap := make(map[string]bool) + for _, result := range results.Entries { + isActiveAttribute := result.GetAttributeValue(ldSync.config.ActiveAttribute()) + uidAttribute := result.GetAttributeValue(ldSync.config.BaseUserAttr()) + emailToActiveMap[uidAttribute] = isActiveAttribute == ldSync.config.ActiveAttributeAllowedValue() + } + for i, email := range emails { + active, ok := emailToActiveMap[email] + if ok && active { + validUsers[i] = true + } + } + + return validUsers, nil +} diff --git a/core/sessions/orm.go b/core/sessions/localauth/orm.go similarity index 80% rename from core/sessions/orm.go rename to core/sessions/localauth/orm.go index eaac211f24..d6fb8cd578 100644 --- a/core/sessions/orm.go +++ b/core/sessions/localauth/orm.go @@ -1,4 +1,4 @@ -package sessions +package localauth import ( "crypto/subtle" @@ -14,34 +14,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) -//go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore - -type ORM interface { - FindUser(email string) (User, error) - FindUserByAPIToken(apiToken string) (User, error) - ListUsers() ([]User, error) - AuthorizedUserWithSession(sessionID string) (User, error) - DeleteUser(email string) error - DeleteUserSession(sessionID string) error - CreateSession(sr SessionRequest) (string, error) - ClearNonCurrentSessions(sessionID string) error - CreateUser(user *User) error - UpdateRole(email, newRole string) (User, error) - SetAuthToken(user *User, token *auth.Token) error - CreateAndSetAuthToken(user *User) (*auth.Token, error) - DeleteAuthToken(user *User) error - SetPassword(user *User, newPassword string) error - Sessions(offset, limit int) ([]Session, error) - GetUserWebAuthn(email string) ([]WebAuthn, error) - SaveWebAuthn(token *WebAuthn) error - - FindExternalInitiator(eia *auth.Token) (initiator *bridges.ExternalInitiator, err error) -} - type orm struct { q pg.Q sessionDuration time.Duration @@ -49,38 +26,40 @@ type orm struct { auditLogger audit.AuditLogger } -var _ ORM = (*orm)(nil) +// orm implements sessions.AuthenticationProvider and sessions.BasicAdminUsersORM interfaces +var _ sessions.AuthenticationProvider = (*orm)(nil) +var _ sessions.BasicAdminUsersORM = (*orm)(nil) -func NewORM(db *sqlx.DB, sd time.Duration, lggr logger.Logger, cfg pg.QConfig, auditLogger audit.AuditLogger) ORM { - lggr = lggr.Named("SessionsORM") +func NewORM(db *sqlx.DB, sd time.Duration, lggr logger.Logger, cfg pg.QConfig, auditLogger audit.AuditLogger) sessions.AuthenticationProvider { + namedLogger := lggr.Named("LocalAuthAuthenticationProviderORM") return &orm{ - q: pg.NewQ(db, lggr, cfg), + q: pg.NewQ(db, namedLogger, cfg), sessionDuration: sd, - lggr: lggr, + lggr: lggr.Named("LocalAuthAuthenticationProviderORM"), auditLogger: auditLogger, } } // FindUser will attempt to return an API user by email. -func (o *orm) FindUser(email string) (User, error) { +func (o *orm) FindUser(email string) (sessions.User, error) { return o.findUser(email) } // FindUserByAPIToken will attempt to return an API user via the user's table token_key column. -func (o *orm) FindUserByAPIToken(apiToken string) (user User, err error) { +func (o *orm) FindUserByAPIToken(apiToken string) (user sessions.User, err error) { sql := "SELECT * FROM users WHERE token_key = $1" err = o.q.Get(&user, sql, apiToken) return } -func (o *orm) findUser(email string) (user User, err error) { +func (o *orm) findUser(email string) (user sessions.User, err error) { sql := "SELECT * FROM users WHERE lower(email) = lower($1)" err = o.q.Get(&user, sql, email) return } // ListUsers will load and return all user rows from the db. -func (o *orm) ListUsers() (users []User, err error) { +func (o *orm) ListUsers() (users []sessions.User, err error) { sql := "SELECT * FROM users ORDER BY email ASC;" err = o.q.Select(&users, sql) return @@ -100,31 +79,27 @@ func (o *orm) updateSessionLastUsed(sessionID string) error { return o.q.ExecQ("UPDATE sessions SET last_used = now() WHERE id = $1", sessionID) } -// ErrUserSessionExpired defines the error triggered when the user session has expired -var ( - ErrUserSessionExpired = errors.New("user session missing or expired, please login again") - ErrEmptySessionID = errors.New("session ID cannot be empty") -) - // AuthorizedUserWithSession will return the API user associated with the Session ID if it // exists and hasn't expired, and update session's LastUsed field. -func (o *orm) AuthorizedUserWithSession(sessionID string) (user User, err error) { +// AuthorizedUserWithSession will return the API user associated with the Session ID if it +// exists and hasn't expired, and update session's LastUsed field. +func (o *orm) AuthorizedUserWithSession(sessionID string) (user sessions.User, err error) { if len(sessionID) == 0 { - return User{}, ErrEmptySessionID + return sessions.User{}, sessions.ErrEmptySessionID } email, err := o.findValidSession(sessionID) if err != nil { - return User{}, ErrUserSessionExpired + return sessions.User{}, sessions.ErrUserSessionExpired } user, err = o.findUser(email) if err != nil { - return User{}, ErrUserSessionExpired + return sessions.User{}, sessions.ErrUserSessionExpired } if err := o.updateSessionLastUsed(sessionID); err != nil { - return User{}, err + return sessions.User{}, err } return user, nil @@ -151,8 +126,8 @@ func (o *orm) DeleteUserSession(sessionID string) error { // tokens for the user. This list must be used when logging in (for obvious reasons) but // must also be used for registration to prevent the user from enrolling the same hardware // token multiple times. -func (o *orm) GetUserWebAuthn(email string) ([]WebAuthn, error) { - var uwas []WebAuthn +func (o *orm) GetUserWebAuthn(email string) ([]sessions.WebAuthn, error) { + var uwas []sessions.WebAuthn err := o.q.Select(&uwas, "SELECT email, public_key_data FROM web_authns WHERE LOWER(email) = $1", strings.ToLower(email)) if err != nil { return uwas, err @@ -165,7 +140,7 @@ func (o *orm) GetUserWebAuthn(email string) ([]WebAuthn, error) { // CreateSession will check the password in the SessionRequest against // the hashed API User password in the db. Also will check WebAuthn if it's // enabled for that user. -func (o *orm) CreateSession(sr SessionRequest) (string, error) { +func (o *orm) CreateSession(sr sessions.SessionRequest) (string, error) { user, err := o.FindUser(sr.Email) if err != nil { return "", err @@ -196,7 +171,7 @@ func (o *orm) CreateSession(sr SessionRequest) (string, error) { // No webauthn tokens registered for the current user, so normal authentication is now complete if len(uwas) == 0 { lggr.Infof("No MFA for user. Creating Session") - session := NewSession() + session := sessions.NewSession() _, err = o.q.Exec("INSERT INTO sessions (id, email, last_used, created_at) VALUES ($1, $2, now(), now())", session.ID, user.Email) o.auditLogger.Audit(audit.AuthLoginSuccessNo2FA, map[string]interface{}{"email": sr.Email}) return session.ID, err @@ -207,7 +182,7 @@ func (o *orm) CreateSession(sr SessionRequest) (string, error) { // data in the next round trip request (tap key to include webauthn data on the login page) if sr.WebAuthnData == "" { lggr.Warnf("Attempted login to MFA user. Generating challenge for user.") - options, webauthnError := BeginWebAuthnLogin(user, uwas, sr) + options, webauthnError := sessions.BeginWebAuthnLogin(user, uwas, sr) if webauthnError != nil { lggr.Errorf("Could not begin WebAuthn verification: %v", webauthnError) return "", errors.New("MFA Error") @@ -225,7 +200,7 @@ func (o *orm) CreateSession(sr SessionRequest) (string, error) { // The user is at the final stage of logging in with MFA. We have an // attestation back from the user, we now need to verify that it is // correct. - err = FinishWebAuthnLogin(user, uwas, sr) + err = sessions.FinishWebAuthnLogin(user, uwas, sr) if err != nil { // The user does have WebAuthn enabled but failed the check @@ -236,7 +211,7 @@ func (o *orm) CreateSession(sr SessionRequest) (string, error) { lggr.Infof("User passed MFA authentication and login will proceed") // This is a success so we can create the sessions - session := NewSession() + session := sessions.NewSession() _, err = o.q.Exec("INSERT INTO sessions (id, email, last_used, created_at) VALUES ($1, $2, now(), now())", session.ID, user.Email) if err != nil { return "", err @@ -271,14 +246,14 @@ func (o *orm) ClearNonCurrentSessions(sessionID string) error { } // CreateUser creates a new API user -func (o *orm) CreateUser(user *User) error { +func (o *orm) CreateUser(user *sessions.User) error { sql := "INSERT INTO users (email, hashed_password, role, created_at, updated_at) VALUES ($1, $2, $3, now(), now()) RETURNING *" return o.q.Get(user, sql, strings.ToLower(user.Email), user.HashedPassword, user.Role) } // UpdateRole overwrites role field of the user specified by email. -func (o *orm) UpdateRole(email, newRole string) (User, error) { - var userToEdit User +func (o *orm) UpdateRole(email, newRole string) (sessions.User, error) { + var userToEdit sessions.User if newRole == "" { return userToEdit, errors.New("user role must be specified") @@ -291,7 +266,7 @@ func (o *orm) UpdateRole(email, newRole string) (User, error) { } // Patch validated role - userRole, err := GetUserRole(newRole) + userRole, err := sessions.GetUserRole(newRole) if err != nil { return err } @@ -316,7 +291,7 @@ func (o *orm) UpdateRole(email, newRole string) (User, error) { } // SetAuthToken updates the user to use the given Authentication Token. -func (o *orm) SetPassword(user *User, newPassword string) error { +func (o *orm) SetPassword(user *sessions.User, newPassword string) error { hashedPassword, err := utils.HashPassword(newPassword) if err != nil { return err @@ -325,7 +300,19 @@ func (o *orm) SetPassword(user *User, newPassword string) error { return o.q.Get(user, sql, hashedPassword, user.Email) } -func (o *orm) CreateAndSetAuthToken(user *User) (*auth.Token, error) { +// TestPassword checks plaintext user provided password with hashed database password, returns nil if matched +func (o *orm) TestPassword(email string, password string) error { + var hashedPassword string + if err := o.q.Get(&hashedPassword, "SELECT hashed_password FROM users WHERE lower(email) = lower($1)", email); err != nil { + return errors.New("no matching user for provided email") + } + if !utils.CheckPasswordHash(password, hashedPassword) { + return errors.New("passwords don't match") + } + return nil +} + +func (o *orm) CreateAndSetAuthToken(user *sessions.User) (*auth.Token, error) { newToken := auth.NewToken() err := o.SetAuthToken(user, newToken) @@ -337,7 +324,7 @@ func (o *orm) CreateAndSetAuthToken(user *User) (*auth.Token, error) { } // SetAuthToken updates the user to use the given Authentication Token. -func (o *orm) SetAuthToken(user *User, token *auth.Token) error { +func (o *orm) SetAuthToken(user *sessions.User, token *auth.Token) error { salt := utils.NewSecret(utils.DefaultSecretSize) hashedSecret, err := auth.HashedSecret(token, salt) if err != nil { @@ -348,20 +335,20 @@ func (o *orm) SetAuthToken(user *User, token *auth.Token) error { } // DeleteAuthToken clears and disables the users Authentication Token. -func (o *orm) DeleteAuthToken(user *User) error { +func (o *orm) DeleteAuthToken(user *sessions.User) error { sql := "UPDATE users SET token_salt = '', token_key = '', token_hashed_secret = '', updated_at = now() WHERE email = $1 RETURNING *" return o.q.Get(user, sql, user.Email) } // SaveWebAuthn saves new WebAuthn token information. -func (o *orm) SaveWebAuthn(token *WebAuthn) error { +func (o *orm) SaveWebAuthn(token *sessions.WebAuthn) error { sql := "INSERT INTO web_authns (email, public_key_data) VALUES ($1, $2)" _, err := o.q.Exec(sql, token.Email, token.PublicKeyData) return err } // Sessions returns all sessions limited by the parameters. -func (o *orm) Sessions(offset, limit int) (sessions []Session, err error) { +func (o *orm) Sessions(offset, limit int) (sessions []sessions.Session, err error) { sql := `SELECT * FROM sessions ORDER BY created_at, id LIMIT $1 OFFSET $2;` if err = o.q.Select(&sessions, sql, limit, offset); err != nil { return diff --git a/core/sessions/orm_test.go b/core/sessions/localauth/orm_test.go similarity index 95% rename from core/sessions/orm_test.go rename to core/sessions/localauth/orm_test.go index 5decb82308..7868937ad0 100644 --- a/core/sessions/orm_test.go +++ b/core/sessions/localauth/orm_test.go @@ -1,4 +1,4 @@ -package sessions_test +package localauth_test import ( "encoding/json" @@ -7,6 +7,7 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -18,14 +19,15 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func setupORM(t *testing.T) (*sqlx.DB, sessions.ORM) { +func setupORM(t *testing.T) (*sqlx.DB, sessions.AuthenticationProvider) { t.Helper() db := pgtest.NewSqlxDB(t) - orm := sessions.NewORM(db, time.Minute, logger.TestLogger(t), pgtest.NewQConfig(true), &audit.AuditLoggerService{}) + orm := localauth.NewORM(db, time.Minute, logger.TestLogger(t), pgtest.NewQConfig(true), &audit.AuditLoggerService{}) return db, orm } @@ -66,7 +68,7 @@ func TestORM_AuthorizedUserWithSession(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) - orm := sessions.NewORM(db, test.sessionDuration, logger.TestLogger(t), pgtest.NewQConfig(true), &audit.AuditLoggerService{}) + orm := localauth.NewORM(db, test.sessionDuration, logger.TestLogger(t), pgtest.NewQConfig(true), &audit.AuditLoggerService{}) user := cltest.MustRandomUser(t) require.NoError(t, orm.CreateUser(&user)) diff --git a/core/sessions/reaper.go b/core/sessions/localauth/reaper.go similarity index 98% rename from core/sessions/reaper.go rename to core/sessions/localauth/reaper.go index c4f0ed6796..77d1b1abef 100644 --- a/core/sessions/reaper.go +++ b/core/sessions/localauth/reaper.go @@ -1,4 +1,4 @@ -package sessions +package localauth import ( "database/sql" diff --git a/core/sessions/reaper_test.go b/core/sessions/localauth/reaper_test.go similarity index 69% rename from core/sessions/reaper_test.go rename to core/sessions/localauth/reaper_test.go index a96c3822ef..43a263d032 100644 --- a/core/sessions/reaper_test.go +++ b/core/sessions/localauth/reaper_test.go @@ -1,4 +1,4 @@ -package sessions_test +package localauth_test import ( "testing" @@ -9,8 +9,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/sessions" + "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -31,10 +33,9 @@ func TestSessionReaper_ReapSessions(t *testing.T) { db := pgtest.NewSqlxDB(t) config := sessionReaperConfig{} lggr := logger.TestLogger(t) - orm := sessions.NewORM(db, config.SessionTimeout().Duration(), lggr, pgtest.NewQConfig(true), audit.NoopLogger) - - r := sessions.NewSessionReaper(db.DB, config, lggr) + orm := localauth.NewORM(db, config.SessionTimeout().Duration(), lggr, pgtest.NewQConfig(true), audit.NoopLogger) + r := localauth.NewSessionReaper(db.DB, config, lggr) t.Cleanup(func() { assert.NoError(t, r.Stop()) }) @@ -53,31 +54,28 @@ func TestSessionReaper_ReapSessions(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - user := cltest.MustRandomUser(t) - require.NoError(t, orm.CreateUser(&user)) - - session := sessions.NewSession() - session.Email = user.Email - - _, err := db.Exec("INSERT INTO sessions (last_used, email, id, created_at) VALUES ($1, $2, $3, now())", test.lastUsed, user.Email, test.name) - require.NoError(t, err) - t.Cleanup(func() { - _, err2 := db.Exec("DELETE FROM sessions where email = $1", user.Email) + _, err2 := db.Exec("DELETE FROM sessions where email = $1", cltest.APIEmailAdmin) require.NoError(t, err2) }) + _, err := db.Exec("INSERT INTO sessions (last_used, email, id, created_at) VALUES ($1, $2, $3, now())", test.lastUsed, cltest.APIEmailAdmin, test.name) + require.NoError(t, err) + r.WakeUp() - <-r.(interface { - WorkDone() <-chan struct{} - }).WorkDone() - sessions, err := orm.Sessions(0, 10) - assert.NoError(t, err) if test.wantReap { - assert.Len(t, sessions, 0) + gomega.NewWithT(t).Eventually(func() []sessions.Session { + sessions, err := orm.Sessions(0, 10) + assert.NoError(t, err) + return sessions + }).Should(gomega.HaveLen(0)) } else { - assert.Len(t, sessions, 1) + gomega.NewWithT(t).Consistently(func() []sessions.Session { + sessions, err := orm.Sessions(0, 10) + assert.NoError(t, err) + return sessions + }).Should(gomega.HaveLen(1)) } }) } diff --git a/core/sessions/mocks/orm.go b/core/sessions/mocks/authentication_provider.go similarity index 75% rename from core/sessions/mocks/orm.go rename to core/sessions/mocks/authentication_provider.go index 5699b9f889..d6e33d11e4 100644 --- a/core/sessions/mocks/orm.go +++ b/core/sessions/mocks/authentication_provider.go @@ -11,13 +11,13 @@ import ( sessions "github.com/smartcontractkit/chainlink/v2/core/sessions" ) -// ORM is an autogenerated mock type for the ORM type -type ORM struct { +// AuthenticationProvider is an autogenerated mock type for the AuthenticationProvider type +type AuthenticationProvider struct { mock.Mock } // AuthorizedUserWithSession provides a mock function with given fields: sessionID -func (_m *ORM) AuthorizedUserWithSession(sessionID string) (sessions.User, error) { +func (_m *AuthenticationProvider) AuthorizedUserWithSession(sessionID string) (sessions.User, error) { ret := _m.Called(sessionID) var r0 sessions.User @@ -41,7 +41,7 @@ func (_m *ORM) AuthorizedUserWithSession(sessionID string) (sessions.User, error } // ClearNonCurrentSessions provides a mock function with given fields: sessionID -func (_m *ORM) ClearNonCurrentSessions(sessionID string) error { +func (_m *AuthenticationProvider) ClearNonCurrentSessions(sessionID string) error { ret := _m.Called(sessionID) var r0 error @@ -55,7 +55,7 @@ func (_m *ORM) ClearNonCurrentSessions(sessionID string) error { } // CreateAndSetAuthToken provides a mock function with given fields: user -func (_m *ORM) CreateAndSetAuthToken(user *sessions.User) (*auth.Token, error) { +func (_m *AuthenticationProvider) CreateAndSetAuthToken(user *sessions.User) (*auth.Token, error) { ret := _m.Called(user) var r0 *auth.Token @@ -81,7 +81,7 @@ func (_m *ORM) CreateAndSetAuthToken(user *sessions.User) (*auth.Token, error) { } // CreateSession provides a mock function with given fields: sr -func (_m *ORM) CreateSession(sr sessions.SessionRequest) (string, error) { +func (_m *AuthenticationProvider) CreateSession(sr sessions.SessionRequest) (string, error) { ret := _m.Called(sr) var r0 string @@ -105,7 +105,7 @@ func (_m *ORM) CreateSession(sr sessions.SessionRequest) (string, error) { } // CreateUser provides a mock function with given fields: user -func (_m *ORM) CreateUser(user *sessions.User) error { +func (_m *AuthenticationProvider) CreateUser(user *sessions.User) error { ret := _m.Called(user) var r0 error @@ -119,7 +119,7 @@ func (_m *ORM) CreateUser(user *sessions.User) error { } // DeleteAuthToken provides a mock function with given fields: user -func (_m *ORM) DeleteAuthToken(user *sessions.User) error { +func (_m *AuthenticationProvider) DeleteAuthToken(user *sessions.User) error { ret := _m.Called(user) var r0 error @@ -133,7 +133,7 @@ func (_m *ORM) DeleteAuthToken(user *sessions.User) error { } // DeleteUser provides a mock function with given fields: email -func (_m *ORM) DeleteUser(email string) error { +func (_m *AuthenticationProvider) DeleteUser(email string) error { ret := _m.Called(email) var r0 error @@ -147,7 +147,7 @@ func (_m *ORM) DeleteUser(email string) error { } // DeleteUserSession provides a mock function with given fields: sessionID -func (_m *ORM) DeleteUserSession(sessionID string) error { +func (_m *AuthenticationProvider) DeleteUserSession(sessionID string) error { ret := _m.Called(sessionID) var r0 error @@ -161,7 +161,7 @@ func (_m *ORM) DeleteUserSession(sessionID string) error { } // FindExternalInitiator provides a mock function with given fields: eia -func (_m *ORM) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiator, error) { +func (_m *AuthenticationProvider) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiator, error) { ret := _m.Called(eia) var r0 *bridges.ExternalInitiator @@ -187,7 +187,7 @@ func (_m *ORM) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiato } // FindUser provides a mock function with given fields: email -func (_m *ORM) FindUser(email string) (sessions.User, error) { +func (_m *AuthenticationProvider) FindUser(email string) (sessions.User, error) { ret := _m.Called(email) var r0 sessions.User @@ -211,7 +211,7 @@ func (_m *ORM) FindUser(email string) (sessions.User, error) { } // FindUserByAPIToken provides a mock function with given fields: apiToken -func (_m *ORM) FindUserByAPIToken(apiToken string) (sessions.User, error) { +func (_m *AuthenticationProvider) FindUserByAPIToken(apiToken string) (sessions.User, error) { ret := _m.Called(apiToken) var r0 sessions.User @@ -235,7 +235,7 @@ func (_m *ORM) FindUserByAPIToken(apiToken string) (sessions.User, error) { } // GetUserWebAuthn provides a mock function with given fields: email -func (_m *ORM) GetUserWebAuthn(email string) ([]sessions.WebAuthn, error) { +func (_m *AuthenticationProvider) GetUserWebAuthn(email string) ([]sessions.WebAuthn, error) { ret := _m.Called(email) var r0 []sessions.WebAuthn @@ -261,7 +261,7 @@ func (_m *ORM) GetUserWebAuthn(email string) ([]sessions.WebAuthn, error) { } // ListUsers provides a mock function with given fields: -func (_m *ORM) ListUsers() ([]sessions.User, error) { +func (_m *AuthenticationProvider) ListUsers() ([]sessions.User, error) { ret := _m.Called() var r0 []sessions.User @@ -287,7 +287,7 @@ func (_m *ORM) ListUsers() ([]sessions.User, error) { } // SaveWebAuthn provides a mock function with given fields: token -func (_m *ORM) SaveWebAuthn(token *sessions.WebAuthn) error { +func (_m *AuthenticationProvider) SaveWebAuthn(token *sessions.WebAuthn) error { ret := _m.Called(token) var r0 error @@ -301,7 +301,7 @@ func (_m *ORM) SaveWebAuthn(token *sessions.WebAuthn) error { } // Sessions provides a mock function with given fields: offset, limit -func (_m *ORM) Sessions(offset int, limit int) ([]sessions.Session, error) { +func (_m *AuthenticationProvider) Sessions(offset int, limit int) ([]sessions.Session, error) { ret := _m.Called(offset, limit) var r0 []sessions.Session @@ -327,7 +327,7 @@ func (_m *ORM) Sessions(offset int, limit int) ([]sessions.Session, error) { } // SetAuthToken provides a mock function with given fields: user, token -func (_m *ORM) SetAuthToken(user *sessions.User, token *auth.Token) error { +func (_m *AuthenticationProvider) SetAuthToken(user *sessions.User, token *auth.Token) error { ret := _m.Called(user, token) var r0 error @@ -341,7 +341,7 @@ func (_m *ORM) SetAuthToken(user *sessions.User, token *auth.Token) error { } // SetPassword provides a mock function with given fields: user, newPassword -func (_m *ORM) SetPassword(user *sessions.User, newPassword string) error { +func (_m *AuthenticationProvider) SetPassword(user *sessions.User, newPassword string) error { ret := _m.Called(user, newPassword) var r0 error @@ -354,8 +354,22 @@ func (_m *ORM) SetPassword(user *sessions.User, newPassword string) error { return r0 } +// TestPassword provides a mock function with given fields: email, password +func (_m *AuthenticationProvider) TestPassword(email string, password string) error { + ret := _m.Called(email, password) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(email, password) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // UpdateRole provides a mock function with given fields: email, newRole -func (_m *ORM) UpdateRole(email string, newRole string) (sessions.User, error) { +func (_m *AuthenticationProvider) UpdateRole(email string, newRole string) (sessions.User, error) { ret := _m.Called(email, newRole) var r0 sessions.User @@ -378,13 +392,13 @@ func (_m *ORM) UpdateRole(email string, newRole string) (sessions.User, error) { return r0, r1 } -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewAuthenticationProvider creates a new instance of AuthenticationProvider. 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 NewORM(t interface { +func NewAuthenticationProvider(t interface { mock.TestingT Cleanup(func()) -}) *ORM { - mock := &ORM{} +}) *AuthenticationProvider { + mock := &AuthenticationProvider{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/sessions/mocks/basic_admin_users_orm.go b/core/sessions/mocks/basic_admin_users_orm.go new file mode 100644 index 0000000000..845e2d8880 --- /dev/null +++ b/core/sessions/mocks/basic_admin_users_orm.go @@ -0,0 +1,91 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package mocks + +import ( + sessions "github.com/smartcontractkit/chainlink/v2/core/sessions" + mock "github.com/stretchr/testify/mock" +) + +// BasicAdminUsersORM is an autogenerated mock type for the BasicAdminUsersORM type +type BasicAdminUsersORM struct { + mock.Mock +} + +// CreateUser provides a mock function with given fields: user +func (_m *BasicAdminUsersORM) CreateUser(user *sessions.User) error { + ret := _m.Called(user) + + var r0 error + if rf, ok := ret.Get(0).(func(*sessions.User) error); ok { + r0 = rf(user) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// FindUser provides a mock function with given fields: email +func (_m *BasicAdminUsersORM) FindUser(email string) (sessions.User, error) { + ret := _m.Called(email) + + var r0 sessions.User + var r1 error + if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { + return rf(email) + } + if rf, ok := ret.Get(0).(func(string) sessions.User); ok { + r0 = rf(email) + } else { + r0 = ret.Get(0).(sessions.User) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(email) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListUsers provides a mock function with given fields: +func (_m *BasicAdminUsersORM) ListUsers() ([]sessions.User, error) { + ret := _m.Called() + + var r0 []sessions.User + var r1 error + if rf, ok := ret.Get(0).(func() ([]sessions.User, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []sessions.User); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]sessions.User) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewBasicAdminUsersORM creates a new instance of BasicAdminUsersORM. 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 NewBasicAdminUsersORM(t interface { + mock.TestingT + Cleanup(func()) +}) *BasicAdminUsersORM { + mock := &BasicAdminUsersORM{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/sessions/session.go b/core/sessions/session.go new file mode 100644 index 0000000000..90964596e9 --- /dev/null +++ b/core/sessions/session.go @@ -0,0 +1,74 @@ +package sessions + +import ( + "crypto/subtle" + "time" + + "github.com/pkg/errors" + "gopkg.in/guregu/null.v4" + + "github.com/smartcontractkit/chainlink/v2/core/auth" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +// SessionRequest encapsulates the fields needed to generate a new SessionID, +// including the hashed password. +type SessionRequest struct { + Email string `json:"email"` + Password string `json:"password"` + WebAuthnData string `json:"webauthndata"` + WebAuthnConfig WebAuthnConfiguration + SessionStore *WebAuthnSessionStore +} + +// Session holds the unique id for the authenticated session. +type Session struct { + ID string `json:"id"` + Email string `json:"email"` + LastUsed time.Time `json:"lastUsed"` + CreatedAt time.Time `json:"createdAt"` +} + +// NewSession returns a session instance with ID set to a random ID and +// LastUsed to now. +func NewSession() Session { + return Session{ + ID: utils.NewBytes32ID(), + LastUsed: time.Now(), + } +} + +// Changeauth.TokenRequest is sent when updating a User's authentication token. +type ChangeAuthTokenRequest struct { + Password string `json:"password"` +} + +// GenerateAuthToken randomly generates and sets the users Authentication +// Token. +func (u *User) GenerateAuthToken() (*auth.Token, error) { + token := auth.NewToken() + return token, u.SetAuthToken(token) +} + +// SetAuthToken updates the user to use the given Authentication Token. +func (u *User) SetAuthToken(token *auth.Token) error { + salt := utils.NewSecret(utils.DefaultSecretSize) + hashedSecret, err := auth.HashedSecret(token, salt) + if err != nil { + return errors.Wrap(err, "user") + } + u.TokenSalt = null.StringFrom(salt) + u.TokenKey = null.StringFrom(token.AccessKey) + u.TokenHashedSecret = null.StringFrom(hashedSecret) + return nil +} + +// AuthenticateUserByToken returns true on successful authentication of the +// user against the given Authentication Token. +func AuthenticateUserByToken(token *auth.Token, user *User) (bool, error) { + hashedSecret, err := auth.HashedSecret(token, user.TokenSalt.ValueOrZero()) + if err != nil { + return false, err + } + return subtle.ConstantTimeCompare([]byte(hashedSecret), []byte(user.TokenHashedSecret.ValueOrZero())) == 1, nil +} diff --git a/core/sessions/user.go b/core/sessions/user.go index a120874432..f2e4827b92 100644 --- a/core/sessions/user.go +++ b/core/sessions/user.go @@ -1,7 +1,6 @@ package sessions import ( - "crypto/subtle" "fmt" "net/mail" "time" @@ -9,7 +8,6 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -108,65 +106,3 @@ func GetUserRole(role string) (UserRole, error) { ) return UserRole(""), errors.New(errStr) } - -// SessionRequest encapsulates the fields needed to generate a new SessionID, -// including the hashed password. -type SessionRequest struct { - Email string `json:"email"` - Password string `json:"password"` - WebAuthnData string `json:"webauthndata"` - WebAuthnConfig WebAuthnConfiguration - SessionStore *WebAuthnSessionStore -} - -// Session holds the unique id for the authenticated session. -type Session struct { - ID string `json:"id"` - Email string `json:"email"` - LastUsed time.Time `json:"lastUsed"` - CreatedAt time.Time `json:"createdAt"` -} - -// NewSession returns a session instance with ID set to a random ID and -// LastUsed to now. -func NewSession() Session { - return Session{ - ID: utils.NewBytes32ID(), - LastUsed: time.Now(), - } -} - -// Changeauth.TokenRequest is sent when updating a User's authentication token. -type ChangeAuthTokenRequest struct { - Password string `json:"password"` -} - -// GenerateAuthToken randomly generates and sets the users Authentication -// Token. -func (u *User) GenerateAuthToken() (*auth.Token, error) { - token := auth.NewToken() - return token, u.SetAuthToken(token) -} - -// SetAuthToken updates the user to use the given Authentication Token. -func (u *User) SetAuthToken(token *auth.Token) error { - salt := utils.NewSecret(utils.DefaultSecretSize) - hashedSecret, err := auth.HashedSecret(token, salt) - if err != nil { - return errors.Wrap(err, "user") - } - u.TokenSalt = null.StringFrom(salt) - u.TokenKey = null.StringFrom(token.AccessKey) - u.TokenHashedSecret = null.StringFrom(hashedSecret) - return nil -} - -// AuthenticateUserByToken returns true on successful authentication of the -// user against the given Authentication Token. -func AuthenticateUserByToken(token *auth.Token, user *User) (bool, error) { - hashedSecret, err := auth.HashedSecret(token, user.TokenSalt.ValueOrZero()) - if err != nil { - return false, err - } - return subtle.ConstantTimeCompare([]byte(hashedSecret), []byte(user.TokenHashedSecret.ValueOrZero())) == 1, nil -} diff --git a/core/sessions/webauthn.go b/core/sessions/webauthn.go index 0dd8242dc8..41e31d7aaa 100644 --- a/core/sessions/webauthn.go +++ b/core/sessions/webauthn.go @@ -279,7 +279,7 @@ func (store *WebAuthnSessionStore) GetWebauthnSession(key string) (data webauthn return } -func AddCredentialToUser(o ORM, email string, credential *webauthn.Credential) error { +func AddCredentialToUser(ap AuthenticationProvider, email string, credential *webauthn.Credential) error { credj, err := json.Marshal(credential) if err != nil { return err @@ -289,5 +289,5 @@ func AddCredentialToUser(o ORM, email string, credential *webauthn.Credential) e Email: email, PublicKeyData: sqlxTypes.JSONText(credj), } - return o.SaveWebAuthn(&token) + return ap.SaveWebAuthn(&token) } diff --git a/core/store/migrate/migrations/0208_create_ldap_sessions_table.sql b/core/store/migrate/migrations/0208_create_ldap_sessions_table.sql new file mode 100644 index 0000000000..f788cdab07 --- /dev/null +++ b/core/store/migrate/migrations/0208_create_ldap_sessions_table.sql @@ -0,0 +1,22 @@ +-- +goose Up +CREATE TABLE IF NOT EXISTS ldap_sessions ( + id text PRIMARY KEY, + user_email text NOT NULL, + user_role user_roles, + localauth_user BOOLEAN, + created_at timestamp with time zone NOT NULL +); + +CREATE TABLE IF NOT EXISTS ldap_user_api_tokens ( + user_email text PRIMARY KEY, + user_role user_roles, + localauth_user BOOLEAN, + token_key text UNIQUE NOT NULL, + token_salt text NOT NULL, + token_hashed_secret text NOT NULL, + created_at timestamp with time zone NOT NULL +); + +-- +goose Down +DROP TABLE ldap_sessions; +DROP TABLE ldap_user_api_tokens; diff --git a/core/web/auth/auth.go b/core/web/auth/auth.go index a0a9df58c7..c2458f5262 100644 --- a/core/web/auth/auth.go +++ b/core/web/auth/auth.go @@ -78,6 +78,9 @@ func AuthenticateByToken(c *gin.Context, authr Authenticator) error { AccessKey: c.GetHeader(APIKey), Secret: c.GetHeader(APISecret), } + if token.AccessKey == "" { + return auth.ErrorAuthFailed + } if token.AccessKey == "" { return auth.ErrorAuthFailed @@ -86,7 +89,7 @@ func AuthenticateByToken(c *gin.Context, authr Authenticator) error { // We need to first load the user row so we can compare tokens using the stored salt user, err := authr.FindUserByAPIToken(token.AccessKey) if err != nil { - if errors.Is(err, sql.ErrNoRows) { + if errors.Is(err, sql.ErrNoRows) || errors.Is(err, clsessions.ErrUserSessionExpired) { return auth.ErrorAuthFailed } return err diff --git a/core/web/auth/auth_test.go b/core/web/auth/auth_test.go index 896542915a..f0b4e5068f 100644 --- a/core/web/auth/auth_test.go +++ b/core/web/auth/auth_test.go @@ -33,7 +33,7 @@ func authSuccess(*gin.Context, webauth.Authenticator) error { } type userFindFailer struct { - sessions.ORM + sessions.AuthenticationProvider err error } @@ -46,7 +46,7 @@ func (u userFindFailer) FindUserByAPIToken(token string) (sessions.User, error) } type userFindSuccesser struct { - sessions.ORM + sessions.AuthenticationProvider user sessions.User } diff --git a/core/web/auth/gql_test.go b/core/web/auth/gql_test.go index 4688f62a33..4f3f8e27ba 100644 --- a/core/web/auth/gql_test.go +++ b/core/web/auth/gql_test.go @@ -21,7 +21,7 @@ import ( func Test_AuthenticateGQL_Unauthenticated(t *testing.T) { t.Parallel() - sessionORM := mocks.NewORM(t) + sessionORM := mocks.NewAuthenticationProvider(t) sessionStore := cookie.NewStore([]byte("secret")) r := gin.Default() @@ -44,7 +44,7 @@ func Test_AuthenticateGQL_Unauthenticated(t *testing.T) { func Test_AuthenticateGQL_Authenticated(t *testing.T) { t.Parallel() - sessionORM := mocks.NewORM(t) + sessionORM := mocks.NewAuthenticationProvider(t) sessionStore := cookie.NewStore([]byte(cltest.SessionSecret)) sessionID := "sessionID" diff --git a/core/web/resolver/api_token_test.go b/core/web/resolver/api_token_test.go index b5ed52be3c..fae0204caf 100644 --- a/core/web/resolver/api_token_test.go +++ b/core/web/resolver/api_token_test.go @@ -39,6 +39,11 @@ func TestResolver_CreateAPIToken(t *testing.T) { "password": defaultPassword, }, } + variablesIncorrect := map[string]interface{}{ + "input": map[string]interface{}{ + "password": "wrong-password", + }, + } gError := errors.New("error") testCases := []GQLTestCase{ @@ -56,12 +61,13 @@ func TestResolver_CreateAPIToken(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.Mocks.sessionsORM.On("CreateAndSetAuthToken", session.User).Return(&auth.Token{ + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("TestPassword", session.User.Email, defaultPassword).Return(nil) + f.Mocks.authProvider.On("CreateAndSetAuthToken", session.User).Return(&auth.Token{ Secret: "new-secret", AccessKey: "new-access-key", }, nil) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -83,13 +89,12 @@ func TestResolver_CreateAPIToken(t *testing.T) { require.True(t, ok) require.NotNil(t, session) - session.User.HashedPassword = "wrong-password" - - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("TestPassword", session.User.Email, "wrong-password").Return(gError) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, - variables: variables, + variables: variablesIncorrect, result: ` { "createAPIToken": { @@ -114,8 +119,8 @@ func TestResolver_CreateAPIToken(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, gError) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, gError) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -142,9 +147,10 @@ func TestResolver_CreateAPIToken(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.Mocks.sessionsORM.On("CreateAndSetAuthToken", session.User).Return(nil, gError) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("TestPassword", session.User.Email, defaultPassword).Return(nil) + f.Mocks.authProvider.On("CreateAndSetAuthToken", session.User).Return(nil, gError) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -189,6 +195,11 @@ func TestResolver_DeleteAPIToken(t *testing.T) { "password": defaultPassword, }, } + variablesIncorrect := map[string]interface{}{ + "input": map[string]interface{}{ + "password": "wrong-password", + }, + } gError := errors.New("error") testCases := []GQLTestCase{ @@ -208,9 +219,10 @@ func TestResolver_DeleteAPIToken(t *testing.T) { err = session.User.TokenKey.UnmarshalText([]byte("new-access-key")) require.NoError(t, err) - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.Mocks.sessionsORM.On("DeleteAuthToken", session.User).Return(nil) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("TestPassword", session.User.Email, defaultPassword).Return(nil) + f.Mocks.authProvider.On("DeleteAuthToken", session.User).Return(nil) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -231,13 +243,12 @@ func TestResolver_DeleteAPIToken(t *testing.T) { require.True(t, ok) require.NotNil(t, session) - session.User.HashedPassword = "wrong-password" - - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("TestPassword", session.User.Email, "wrong-password").Return(gError) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, - variables: variables, + variables: variablesIncorrect, result: ` { "deleteAPIToken": { @@ -262,8 +273,8 @@ func TestResolver_DeleteAPIToken(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, gError) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, gError) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -290,9 +301,10 @@ func TestResolver_DeleteAPIToken(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.Mocks.sessionsORM.On("DeleteAuthToken", session.User).Return(gError) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("TestPassword", session.User.Email, defaultPassword).Return(nil) + f.Mocks.authProvider.On("DeleteAuthToken", session.User).Return(gError) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index 68cbb0b789..f9eee0734a 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -882,7 +882,7 @@ func (r *Resolver) UpdateUserPassword(ctx context.Context, args struct { return nil, errors.New("couldn't retrieve user session") } - dbUser, err := r.App.SessionORM().FindUser(session.User.Email) + dbUser, err := r.App.AuthenticationProvider().FindUser(session.User.Email) if err != nil { return nil, err } @@ -895,11 +895,11 @@ func (r *Resolver) UpdateUserPassword(ctx context.Context, args struct { }), nil } - if err = r.App.SessionORM().ClearNonCurrentSessions(session.SessionID); err != nil { + if err = r.App.AuthenticationProvider().ClearNonCurrentSessions(session.SessionID); err != nil { return nil, clearSessionsError{} } - err = r.App.SessionORM().SetPassword(&dbUser, args.Input.NewPassword) + err = r.App.AuthenticationProvider().SetPassword(&dbUser, args.Input.NewPassword) if err != nil { return nil, failedPasswordUpdateError{} } @@ -937,12 +937,13 @@ func (r *Resolver) CreateAPIToken(ctx context.Context, args struct { if !ok { return nil, errors.New("Failed to obtain current user from context") } - dbUser, err := r.App.SessionORM().FindUser(session.User.Email) + dbUser, err := r.App.AuthenticationProvider().FindUser(session.User.Email) if err != nil { return nil, err } - if !utils.CheckPasswordHash(args.Input.Password, dbUser.HashedPassword) { + err = r.App.AuthenticationProvider().TestPassword(dbUser.Email, args.Input.Password) + if err != nil { r.App.GetAuditLogger().Audit(audit.APITokenCreateAttemptPasswordMismatch, map[string]interface{}{"user": dbUser.Email}) return NewCreateAPITokenPayload(nil, map[string]string{ @@ -950,7 +951,7 @@ func (r *Resolver) CreateAPIToken(ctx context.Context, args struct { }), nil } - newToken, err := r.App.SessionORM().CreateAndSetAuthToken(&dbUser) + newToken, err := r.App.AuthenticationProvider().CreateAndSetAuthToken(&dbUser) if err != nil { return nil, err } @@ -970,12 +971,13 @@ func (r *Resolver) DeleteAPIToken(ctx context.Context, args struct { if !ok { return nil, errors.New("Failed to obtain current user from context") } - dbUser, err := r.App.SessionORM().FindUser(session.User.Email) + dbUser, err := r.App.AuthenticationProvider().FindUser(session.User.Email) if err != nil { return nil, err } - if !utils.CheckPasswordHash(args.Input.Password, dbUser.HashedPassword) { + err = r.App.AuthenticationProvider().TestPassword(dbUser.Email, args.Input.Password) + if err != nil { r.App.GetAuditLogger().Audit(audit.APITokenDeleteAttemptPasswordMismatch, map[string]interface{}{"user": dbUser.Email}) return NewDeleteAPITokenPayload(nil, map[string]string{ @@ -983,7 +985,7 @@ func (r *Resolver) DeleteAPIToken(ctx context.Context, args struct { }), nil } - err = r.App.SessionORM().DeleteAuthToken(&dbUser) + err = r.App.AuthenticationProvider().DeleteAuthToken(&dbUser) if err != nil { return nil, err } diff --git a/core/web/resolver/resolver_test.go b/core/web/resolver/resolver_test.go index fa8471c5e2..85c495faaa 100644 --- a/core/web/resolver/resolver_test.go +++ b/core/web/resolver/resolver_test.go @@ -27,7 +27,7 @@ import ( pipelineMocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" webhookmocks "github.com/smartcontractkit/chainlink/v2/core/services/webhook/mocks" clsessions "github.com/smartcontractkit/chainlink/v2/core/sessions" - sessionsMocks "github.com/smartcontractkit/chainlink/v2/core/sessions/mocks" + authProviderMocks "github.com/smartcontractkit/chainlink/v2/core/sessions/mocks" "github.com/smartcontractkit/chainlink/v2/core/web/auth" "github.com/smartcontractkit/chainlink/v2/core/web/loader" "github.com/smartcontractkit/chainlink/v2/core/web/schema" @@ -37,7 +37,7 @@ type mocks struct { bridgeORM *bridgeORMMocks.ORM evmORM *evmtest.TestConfigs jobORM *jobORMMocks.ORM - sessionsORM *sessionsMocks.ORM + authProvider *authProviderMocks.AuthenticationProvider pipelineORM *pipelineMocks.ORM feedsSvc *feedsMocks.Service cfg *chainlinkMocks.GeneralConfig @@ -97,7 +97,7 @@ func setupFramework(t *testing.T) *gqlTestFramework { evmORM: evmtest.NewTestConfigs(), jobORM: jobORMMocks.NewORM(t), feedsSvc: feedsMocks.NewService(t), - sessionsORM: sessionsMocks.NewORM(t), + authProvider: authProviderMocks.NewAuthenticationProvider(t), pipelineORM: pipelineMocks.NewORM(t), cfg: chainlinkMocks.NewGeneralConfig(t), scfg: evmConfigMocks.NewChainScopedConfig(t), diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 48d432138a..f5d775fe74 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -61,6 +61,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -73,6 +74,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index f44f119075..95d898c353 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -67,6 +67,7 @@ MaxAgeDays = 17 MaxBackups = 9 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = '*' BridgeResponseURL = 'https://bridge.response' BridgeCacheTTL = '10s' @@ -79,6 +80,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '192.158.1.37' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = 'test-rpid' RPOrigin = 'test-rp-origin' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 1dcbfe3a83..9dd0be8f5d 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -61,6 +61,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -73,6 +74,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/core/web/resolver/user_test.go b/core/web/resolver/user_test.go index e3808eebcb..bc64beeb45 100644 --- a/core/web/resolver/user_test.go +++ b/core/web/resolver/user_test.go @@ -53,10 +53,10 @@ func TestResolver_UpdateUserPassword(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.Mocks.sessionsORM.On("SetPassword", session.User, "new").Return(nil) - f.Mocks.sessionsORM.On("ClearNonCurrentSessions", session.SessionID).Return(nil) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("SetPassword", session.User, "new").Return(nil) + f.Mocks.authProvider.On("ClearNonCurrentSessions", session.SessionID).Return(nil) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -79,8 +79,8 @@ func TestResolver_UpdateUserPassword(t *testing.T) { session.User.HashedPassword = "random-string" - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -108,11 +108,11 @@ func TestResolver_UpdateUserPassword(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.Mocks.sessionsORM.On("ClearNonCurrentSessions", session.SessionID).Return( + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("ClearNonCurrentSessions", session.SessionID).Return( clearSessionsError{}, ) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, @@ -139,10 +139,10 @@ func TestResolver_UpdateUserPassword(t *testing.T) { session.User.HashedPassword = pwd - f.Mocks.sessionsORM.On("FindUser", session.User.Email).Return(*session.User, nil) - f.Mocks.sessionsORM.On("ClearNonCurrentSessions", session.SessionID).Return(nil) - f.Mocks.sessionsORM.On("SetPassword", session.User, "new").Return(failedPasswordUpdateError{}) - f.App.On("SessionORM").Return(f.Mocks.sessionsORM) + f.Mocks.authProvider.On("FindUser", session.User.Email).Return(*session.User, nil) + f.Mocks.authProvider.On("ClearNonCurrentSessions", session.SessionID).Return(nil) + f.Mocks.authProvider.On("SetPassword", session.User, "new").Return(failedPasswordUpdateError{}) + f.App.On("AuthenticationProvider").Return(f.Mocks.authProvider) }, query: mutation, variables: variables, diff --git a/core/web/router.go b/core/web/router.go index a873f14b70..28bd4f2170 100644 --- a/core/web/router.go +++ b/core/web/router.go @@ -90,7 +90,7 @@ func NewRouter(app chainlink.Application, prometheus *ginprom.Prometheus) (*gin. guiAssetRoutes(engine, config.Insecure().DisableRateLimiting(), app.GetLogger()) api.POST("/query", - auth.AuthenticateGQL(app.SessionORM(), app.GetLogger().Named("GQLHandler")), + auth.AuthenticateGQL(app.AuthenticationProvider(), app.GetLogger().Named("GQLHandler")), loader.Middleware(app), graphqlHandler(app), ) @@ -170,7 +170,7 @@ func secureMiddleware(tlsRedirect bool, tlsHost string, devWebServer bool) gin.H } func debugRoutes(app chainlink.Application, r *gin.RouterGroup) { - group := r.Group("/debug", auth.Authenticate(app.SessionORM(), auth.AuthenticateBySession)) + group := r.Group("/debug", auth.Authenticate(app.AuthenticationProvider(), auth.AuthenticateBySession)) group.GET("/vars", expvar.Handler()) } @@ -207,7 +207,7 @@ func sessionRoutes(app chainlink.Application, r *gin.RouterGroup) { )) sc := NewSessionsController(app) unauth.POST("/sessions", sc.Create) - auth := r.Group("/", auth.Authenticate(app.SessionORM(), auth.AuthenticateBySession)) + auth := r.Group("/", auth.Authenticate(app.AuthenticationProvider(), auth.AuthenticateBySession)) auth.DELETE("/sessions", sc.Destroy) } @@ -231,7 +231,7 @@ func v2Routes(app chainlink.Application, r *gin.RouterGroup) { psec := PipelineJobSpecErrorsController{app} unauthedv2.PATCH("/resume/:runID", prc.Resume) - authv2 := r.Group("/v2", auth.Authenticate(app.SessionORM(), + authv2 := r.Group("/v2", auth.Authenticate(app.AuthenticationProvider(), auth.AuthenticateByToken, auth.AuthenticateBySession, )) @@ -301,7 +301,7 @@ func v2Routes(app chainlink.Application, r *gin.RouterGroup) { // duplicated from above, with `evm` instead of `eth` // legacy ones remain for backwards compatibility - ethKeysGroup := authv2.Group("", auth.Authenticate(app.SessionORM(), + ethKeysGroup := authv2.Group("", auth.Authenticate(app.AuthenticationProvider(), auth.AuthenticateByToken, auth.AuthenticateBySession, )) @@ -427,7 +427,7 @@ func v2Routes(app chainlink.Application, r *gin.RouterGroup) { } ping := PingController{app} - userOrEI := r.Group("/v2", auth.Authenticate(app.SessionORM(), + userOrEI := r.Group("/v2", auth.Authenticate(app.AuthenticationProvider(), auth.AuthenticateExternalInitiator, auth.AuthenticateByToken, auth.AuthenticateBySession, diff --git a/core/web/sessions_controller.go b/core/web/sessions_controller.go index 6f029456bd..23ecfd3b79 100644 --- a/core/web/sessions_controller.go +++ b/core/web/sessions_controller.go @@ -39,7 +39,7 @@ func (sc *SessionsController) Create(c *gin.Context) { } // Does this user have 2FA enabled? - userWebAuthnTokens, err := sc.App.SessionORM().GetUserWebAuthn(sr.Email) + userWebAuthnTokens, err := sc.App.AuthenticationProvider().GetUserWebAuthn(sr.Email) if err != nil { sc.App.GetLogger().Errorf("Error loading user WebAuthn data: %s", err) jsonAPIError(c, http.StatusInternalServerError, errors.New("internal Server Error")) @@ -53,7 +53,7 @@ func (sc *SessionsController) Create(c *gin.Context) { sr.WebAuthnConfig = sc.App.GetWebAuthnConfiguration() } - sid, err := sc.App.SessionORM().CreateSession(sr) + sid, err := sc.App.AuthenticationProvider().CreateSession(sr) if err != nil { jsonAPIError(c, http.StatusUnauthorized, err) return @@ -78,7 +78,7 @@ func (sc *SessionsController) Destroy(c *gin.Context) { jsonAPIResponse(c, Session{Authenticated: false}, "session") return } - if err := sc.App.SessionORM().DeleteUserSession(sessionID); err != nil { + if err := sc.App.AuthenticationProvider().DeleteUserSession(sessionID); err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return } diff --git a/core/web/sessions_controller_test.go b/core/web/sessions_controller_test.go index 7184e3f95b..c2950caf3d 100644 --- a/core/web/sessions_controller_test.go +++ b/core/web/sessions_controller_test.go @@ -27,7 +27,7 @@ func TestSessionsController_Create(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) client := clhttptest.NewTestLocalOnlyHTTPClient() tests := []struct { @@ -59,7 +59,7 @@ func TestSessionsController_Create(t *testing.T) { decrypted, err := cltest.DecodeSessionCookie(sessionCookie.Value) require.NoError(t, err) - user, err := app.SessionORM().AuthorizedUserWithSession(decrypted) + user, err := app.AuthenticationProvider().AuthorizedUserWithSession(decrypted) assert.NoError(t, err) assert.Equal(t, test.email, user.Email) @@ -69,7 +69,7 @@ func TestSessionsController_Create(t *testing.T) { } else { require.True(t, resp.StatusCode >= 400, "Should not be able to create session") // Ignore fixture session - sessions, err := app.SessionORM().Sessions(1, 2) + sessions, err := app.AuthenticationProvider().Sessions(1, 2) assert.NoError(t, err) assert.Empty(t, sessions) } @@ -90,7 +90,7 @@ func TestSessionsController_Create_ReapSessions(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) staleSession := cltest.NewSession() staleSession.LastUsed = time.Now().Add(-cltest.MustParseDuration(t, "241h")) @@ -107,7 +107,7 @@ func TestSessionsController_Create_ReapSessions(t *testing.T) { var s []sessions.Session gomega.NewWithT(t).Eventually(func() []sessions.Session { - s, err = app.SessionORM().Sessions(0, 10) + s, err = app.AuthenticationProvider().Sessions(0, 10) assert.NoError(t, err) return s }).Should(gomega.HaveLen(1)) @@ -124,7 +124,7 @@ func TestSessionsController_Destroy(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) correctSession := sessions.NewSession() correctSession.Email = user.Email @@ -150,7 +150,7 @@ func TestSessionsController_Destroy(t *testing.T) { resp, err := client.Do(request) assert.NoError(t, err) - _, err = app.SessionORM().AuthorizedUserWithSession(test.sessionID) + _, err = app.AuthenticationProvider().AuthorizedUserWithSession(test.sessionID) assert.Error(t, err) if test.success { assert.Equal(t, http.StatusOK, resp.StatusCode) @@ -170,7 +170,7 @@ func TestSessionsController_Destroy_ReapSessions(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) user := cltest.MustRandomUser(t) - require.NoError(t, app.SessionORM().CreateUser(&user)) + require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) correctSession := sessions.NewSession() correctSession.Email = user.Email @@ -192,7 +192,7 @@ func TestSessionsController_Destroy_ReapSessions(t *testing.T) { assert.Equal(t, http.StatusOK, resp.StatusCode) gomega.NewWithT(t).Eventually(func() []sessions.Session { - sessions, err := app.SessionORM().Sessions(0, 10) + sessions, err := app.AuthenticationProvider().Sessions(0, 10) assert.NoError(t, err) return sessions }).Should(gomega.HaveLen(0)) diff --git a/core/web/user_controller.go b/core/web/user_controller.go index 115971eafc..857fff7b37 100644 --- a/core/web/user_controller.go +++ b/core/web/user_controller.go @@ -30,10 +30,16 @@ type UpdatePasswordRequest struct { NewPassword string `json:"newPassword"` } +var errUnsupportedForAuth = errors.New("action is unsupported with configured authentication provider") + // Index lists all API users func (c *UserController) Index(ctx *gin.Context) { - users, err := c.App.SessionORM().ListUsers() + users, err := c.App.AuthenticationProvider().ListUsers() if err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } c.App.GetLogger().Errorf("Unable to list users", "err", err) jsonAPIError(ctx, http.StatusInternalServerError, err) return @@ -76,7 +82,7 @@ func (c *UserController) Create(ctx *gin.Context) { jsonAPIError(ctx, http.StatusBadRequest, errors.Errorf("error creating API user: %s", err)) return } - if err = c.App.SessionORM().CreateUser(&user); err != nil { + if err = c.App.AuthenticationProvider().CreateUser(&user); err != nil { // If this is a duplicate key error (code 23505), return a nicer error message var pgErr *pgconn.PgError if ok := errors.As(err, &pgErr); ok { @@ -85,6 +91,10 @@ func (c *UserController) Create(ctx *gin.Context) { return } } + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } c.App.GetLogger().Errorf("Error creating new API user", "err", err) jsonAPIError(ctx, http.StatusInternalServerError, errors.New("error creating API user")) return @@ -132,8 +142,12 @@ func (c *UserController) UpdateRole(ctx *gin.Context) { return } - user, err := c.App.SessionORM().UpdateRole(request.Email, request.NewRole) + user, err := c.App.AuthenticationProvider().UpdateRole(request.Email, request.NewRole) if err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } jsonAPIError(ctx, http.StatusInternalServerError, errors.Wrap(err, "error updating API user")) return } @@ -146,8 +160,12 @@ func (c *UserController) Delete(ctx *gin.Context) { email := ctx.Param("email") // Attempt find user by email - user, err := c.App.SessionORM().FindUser(email) + user, err := c.App.AuthenticationProvider().FindUser(email) if err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } jsonAPIError(ctx, http.StatusBadRequest, errors.Errorf("specified user not found: %s", email)) return } @@ -163,7 +181,11 @@ func (c *UserController) Delete(ctx *gin.Context) { return } - if err = c.App.SessionORM().DeleteUser(email); err != nil { + if err = c.App.AuthenticationProvider().DeleteUser(email); err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } c.App.GetLogger().Errorf("Error deleting API user", "err", err) jsonAPIError(ctx, http.StatusInternalServerError, errors.New("error deleting API user")) return @@ -185,8 +207,12 @@ func (c *UserController) UpdatePassword(ctx *gin.Context) { jsonAPIError(ctx, http.StatusInternalServerError, errors.New("failed to obtain current user from context")) return } - user, err := c.App.SessionORM().FindUser(sessionUser.Email) + user, err := c.App.AuthenticationProvider().FindUser(sessionUser.Email) if err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } c.App.GetLogger().Errorf("failed to obtain current user record: %s", err) jsonAPIError(ctx, http.StatusInternalServerError, errors.New("unable to update password")) return @@ -222,19 +248,29 @@ func (c *UserController) NewAPIToken(ctx *gin.Context) { jsonAPIError(ctx, http.StatusInternalServerError, errors.New("failed to obtain current user from context")) return } - user, err := c.App.SessionORM().FindUser(sessionUser.Email) + user, err := c.App.AuthenticationProvider().FindUser(sessionUser.Email) if err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } c.App.GetLogger().Errorf("failed to obtain current user record: %s", err) - jsonAPIError(ctx, http.StatusInternalServerError, errors.New("unable to creatae API token")) + jsonAPIError(ctx, http.StatusInternalServerError, errors.New("unable to create API token")) return } - if !utils.CheckPasswordHash(request.Password, user.HashedPassword) { + // In order to create an API token, login validation with provided password must succeed + err = c.App.AuthenticationProvider().TestPassword(sessionUser.Email, request.Password) + if err != nil { c.App.GetAuditLogger().Audit(audit.APITokenCreateAttemptPasswordMismatch, map[string]interface{}{"user": user.Email}) jsonAPIError(ctx, http.StatusUnauthorized, errors.New("incorrect password")) return } newToken := auth.NewToken() - if err := c.App.SessionORM().SetAuthToken(&user, newToken); err != nil { + if err := c.App.AuthenticationProvider().SetAuthToken(&user, newToken); err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } jsonAPIError(ctx, http.StatusInternalServerError, err) return } @@ -256,18 +292,27 @@ func (c *UserController) DeleteAPIToken(ctx *gin.Context) { jsonAPIError(ctx, http.StatusInternalServerError, errors.New("failed to obtain current user from context")) return } - user, err := c.App.SessionORM().FindUser(sessionUser.Email) + user, err := c.App.AuthenticationProvider().FindUser(sessionUser.Email) if err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } c.App.GetLogger().Errorf("failed to obtain current user record: %s", err) jsonAPIError(ctx, http.StatusInternalServerError, errors.New("unable to delete API token")) return } - if !utils.CheckPasswordHash(request.Password, user.HashedPassword) { + err = c.App.AuthenticationProvider().TestPassword(sessionUser.Email, request.Password) + if err != nil { c.App.GetAuditLogger().Audit(audit.APITokenDeleteAttemptPasswordMismatch, map[string]interface{}{"user": user.Email}) jsonAPIError(ctx, http.StatusUnauthorized, errors.New("incorrect password")) return } - if err := c.App.SessionORM().DeleteAuthToken(&user); err != nil { + if err := c.App.AuthenticationProvider().DeleteAuthToken(&user); err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + jsonAPIError(ctx, http.StatusBadRequest, errUnsupportedForAuth) + return + } jsonAPIError(ctx, http.StatusInternalServerError, err) return } @@ -291,12 +336,15 @@ func (c *UserController) updateUserPassword(ctx *gin.Context, user *clsession.Us if err != nil { return err } - orm := c.App.SessionORM() + orm := c.App.AuthenticationProvider() if err := orm.ClearNonCurrentSessions(sessionID); err != nil { c.App.GetLogger().Errorf("failed to clear non current user sessions: %s", err) return errors.New("unable to update password") } if err := orm.SetPassword(user, newPassword); err != nil { + if errors.Is(err, clsession.ErrNotSupported) { + return errUnsupportedForAuth + } c.App.GetLogger().Errorf("failed to update current user password: %s", err) return errors.New("unable to update password") } diff --git a/core/web/user_controller_test.go b/core/web/user_controller_test.go index a11082ff6a..6baab1c396 100644 --- a/core/web/user_controller_test.go +++ b/core/web/user_controller_test.go @@ -188,7 +188,7 @@ func TestUserController_UpdateRole(t *testing.T) { client := app.NewHTTPClient(nil) user := cltest.MustRandomUser(t) - err := app.SessionORM().CreateUser(&user) + err := app.AuthenticationProvider().CreateUser(&user) require.NoError(t, err) testCases := []struct { @@ -235,7 +235,7 @@ func TestUserController_DeleteUser(t *testing.T) { client := app.NewHTTPClient(nil) user := cltest.MustRandomUser(t) - err := app.SessionORM().CreateUser(&user) + err := app.AuthenticationProvider().CreateUser(&user) require.NoError(t, err) resp, cleanup := client.Delete(fmt.Sprintf("/v2/users/%s", url.QueryEscape(user.Email))) diff --git a/core/web/webauthn_controller.go b/core/web/webauthn_controller.go index 0509001323..41c8f268ad 100644 --- a/core/web/webauthn_controller.go +++ b/core/web/webauthn_controller.go @@ -36,7 +36,7 @@ func (c *WebAuthnController) BeginRegistration(ctx *gin.Context) { return } - orm := c.App.SessionORM() + orm := c.App.AuthenticationProvider() uwas, err := orm.GetUserWebAuthn(user.Email) if err != nil { c.App.GetLogger().Errorf("failed to obtain current user MFA tokens: error in GetUserWebAuthn: %+v", err) @@ -66,7 +66,7 @@ func (c *WebAuthnController) FinishRegistration(ctx *gin.Context) { return } - orm := c.App.SessionORM() + orm := c.App.AuthenticationProvider() uwas, err := orm.GetUserWebAuthn(user.Email) if err != nil { c.App.GetLogger().Errorf("failed to obtain current user MFA tokens: error in GetUserWebAuthn: %s", err) @@ -83,7 +83,7 @@ func (c *WebAuthnController) FinishRegistration(ctx *gin.Context) { return } - if sessions.AddCredentialToUser(c.App.SessionORM(), user.Email, credential) != nil { + if sessions.AddCredentialToUser(c.App.AuthenticationProvider(), user.Email, credential) != nil { c.App.GetLogger().Errorf("Could not save WebAuthn credential to DB for user: %s", user.Email) jsonAPIError(ctx, http.StatusInternalServerError, errors.New("internal Server Error")) return diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8f3b16c132..b5b393542b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] +### Added + +- Added a new, optional WebServer authentication option that supports LDAP as a user identity provider. This enables user login access and user roles to be managed and provisioned via a centralized remote server that supports the LDAP protocol, which can be helpful when running multiple nodes. See the documentation for more information and config setup instructions. There is a new `[WebServer].AuthenticationMethod` config option, when set to `ldap` requires the new `[WebServer.LDAP]` config section to be defined, see the reference `docs/core.toml`. + + ### Changed - `L2Suggested` mode is now called `SuggestedPrice` diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 313e7b46aa..23508df172 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -459,6 +459,7 @@ MaxBackups determines the maximum number of old log files to retain. Keeping thi ## WebServer ```toml [WebServer] +AuthenticationMethod = 'local' # Default AllowOrigins = 'http://localhost:3000,http://localhost:6688' # Default BridgeCacheTTL = '0s' # Default BridgeResponseURL = 'https://my-chainlink-node.example.com:6688' # Example @@ -473,6 +474,12 @@ ListenIP = '0.0.0.0' # Default ``` +### AuthenticationMethod +```toml +AuthenticationMethod = 'local' # Default +``` +AuthenticationMethod defines which pluggable auth interface to use for user login and role assumption. Options include 'local' and 'ldap'. See docs for more details + ### AllowOrigins ```toml AllowOrigins = 'http://localhost:3000,http://localhost:6688' # Default @@ -546,6 +553,132 @@ ListenIP = '0.0.0.0' # Default ``` ListenIP specifies the IP to bind the HTTP server to +## WebServer.LDAP +```toml +[WebServer.LDAP] +ServerTLS = true # Default +SessionTimeout = '15m0s' # Default +QueryTimeout = '2m0s' # Default +BaseUserAttr = 'uid' # Default +BaseDN = 'dc=custom,dc=example,dc=com' # Example +UsersDN = 'ou=users' # Default +GroupsDN = 'ou=groups' # Default +ActiveAttribute = '' # Default +ActiveAttributeAllowedValue = '' # Default +AdminUserGroupCN = 'NodeAdmins' # Default +EditUserGroupCN = 'NodeEditors' # Default +RunUserGroupCN = 'NodeRunners' # Default +ReadUserGroupCN = 'NodeReadOnly' # Default +UserApiTokenEnabled = false # Default +UserAPITokenDuration = '240h0m0s' # Default +UpstreamSyncInterval = '0s' # Default +UpstreamSyncRateLimit = '2m0s' # Default +``` +Optional LDAP config if WebServer.AuthenticationMethod is set to 'ldap' +LDAP queries are all parameterized to support custom LDAP 'dn', 'cn', and attributes + +### ServerTLS +```toml +ServerTLS = true # Default +``` +ServerTLS defines the option to require the secure ldaps + +### SessionTimeout +```toml +SessionTimeout = '15m0s' # Default +``` +SessionTimeout determines the amount of idle time to elapse before session cookies expire. This signs out GUI users from their sessions. + +### QueryTimeout +```toml +QueryTimeout = '2m0s' # Default +``` +QueryTimeout defines how long queries should wait before timing out, defined in seconds + +### BaseUserAttr +```toml +BaseUserAttr = 'uid' # Default +``` +BaseUserAttr defines the base attribute used to populate LDAP queries such as "uid=$", default is example + +### BaseDN +```toml +BaseDN = 'dc=custom,dc=example,dc=com' # Example +``` +BaseDN defines the base LDAP 'dn' search filter to apply to every LDAP query, replace example,com with the appropriate LDAP server's structure + +### UsersDN +```toml +UsersDN = 'ou=users' # Default +``` +UsersDN defines the 'dn' query to use when querying for the 'users' 'ou' group + +### GroupsDN +```toml +GroupsDN = 'ou=groups' # Default +``` +GroupsDN defines the 'dn' query to use when querying for the 'groups' 'ou' group + +### ActiveAttribute +```toml +ActiveAttribute = '' # Default +``` +ActiveAttribute is an optional user field to check truthiness for if a user is valid/active. This is only required if the LDAP provider lists inactive users as members of groups + +### ActiveAttributeAllowedValue +```toml +ActiveAttributeAllowedValue = '' # Default +``` +ActiveAttributeAllowedValue is the value to check against for the above optional user attribute + +### AdminUserGroupCN +```toml +AdminUserGroupCN = 'NodeAdmins' # Default +``` +AdminUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Admin' role + +### EditUserGroupCN +```toml +EditUserGroupCN = 'NodeEditors' # Default +``` +EditUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Edit' role + +### RunUserGroupCN +```toml +RunUserGroupCN = 'NodeRunners' # Default +``` +RunUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Run' role + +### ReadUserGroupCN +```toml +ReadUserGroupCN = 'NodeReadOnly' # Default +``` +ReadUserGroupCN is the LDAP 'cn' of the LDAP group that maps the core node's 'Read' role + +### UserApiTokenEnabled +```toml +UserApiTokenEnabled = false # Default +``` +UserApiTokenEnabled enables the users to issue API tokens with the same access of their role + +### UserAPITokenDuration +```toml +UserAPITokenDuration = '240h0m0s' # Default +``` +UserAPITokenDuration is the duration of time an API token is active for before expiring + +### UpstreamSyncInterval +```toml +UpstreamSyncInterval = '0s' # Default +``` +UpstreamSyncInterval is the interval at which the background LDAP sync task will be called. A '0s' value disables the background sync being run on an interval. This check is already performed during login/logout actions, all sessions and API tokens stored in the local ldap tables are updated to match the remote server + +### UpstreamSyncRateLimit +```toml +UpstreamSyncRateLimit = '2m0s' # Default +``` +UpstreamSyncRateLimit defines a duration to limit the number of query/API calls to the upstream LDAP provider. It prevents the sync functionality from being called multiple times within the defined duration + ## WebServer.RateLimit ```toml [WebServer.RateLimit] diff --git a/docs/SECRETS.md b/docs/SECRETS.md index af316cab14..fa7ba76df4 100644 --- a/docs/SECRETS.md +++ b/docs/SECRETS.md @@ -51,6 +51,33 @@ AllowSimplePasswords skips the password complexity check normally enforced on UR Environment variable: `CL_DATABASE_ALLOW_SIMPLE_PASSWORDS` +## WebServer.LDAP +```toml +[WebServer.LDAP] +ServerAddress = 'ldaps://127.0.0.1' # Example +ReadOnlyUserLogin = 'viewer@example.com' # Example +ReadOnlyUserPass = 'password' # Example +``` +Optional LDAP config + +### ServerAddress +```toml +ServerAddress = 'ldaps://127.0.0.1' # Example +``` +ServerAddress is the full ldaps:// address of the ldap server to authenticate with and query + +### ReadOnlyUserLogin +```toml +ReadOnlyUserLogin = 'viewer@example.com' # Example +``` +ReadOnlyUserLogin is the username of the read only root user used to authenticate the requested LDAP queries + +### ReadOnlyUserPass +```toml +ReadOnlyUserPass = 'password' # Example +``` +ReadOnlyUserPass is the password for the above account + ## Password ```toml [Password] diff --git a/go.mod b/go.mod index 820e42c330..999c1b0402 100644 --- a/go.mod +++ b/go.mod @@ -114,6 +114,7 @@ require ( filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect @@ -169,8 +170,10 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect + github.com/go-ldap/ldap/v3 v3.4.5 github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/go.sum b/go.sum index 155e54646d..ee06cc9b75 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -129,6 +131,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -419,6 +423,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -433,6 +439,8 @@ github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEai github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= +github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -1748,6 +1756,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1788,6 +1797,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1850,6 +1860,7 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1876,6 +1887,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1980,6 +1992,7 @@ golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1993,6 +2006,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2068,6 +2082,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 127980a2cb..93820c6ebf 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -58,6 +58,7 @@ require ( github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect @@ -152,9 +153,11 @@ require ( github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect + github.com/go-ldap/ldap/v3 v3.4.5 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 24da946717..60805eae82 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -575,6 +575,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -641,6 +643,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -1027,6 +1031,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -1047,6 +1053,8 @@ github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= +github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= @@ -2713,6 +2721,7 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 189476bfa8..8a3b1af96f 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -73,6 +73,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -85,6 +86,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 593aa0b21d..31fded1b42 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -117,6 +117,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -129,6 +130,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 7b8aa5e383..78fc976912 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -117,6 +117,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -129,6 +130,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index ef6548619e..226a7bbb3b 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -117,6 +117,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -129,6 +130,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 87b877bc88..5cd3d56746 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -107,6 +107,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -119,6 +120,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index c607da1064..fd24150b58 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -114,6 +114,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -126,6 +127,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index ee7926f8f5..828d953da9 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -110,6 +110,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] +AuthenticationMethod = 'local' AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -122,6 +123,25 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + [WebServer.MFA] RPID = '' RPOrigin = '' From 59bf37c5f8ebfb368e93ef7b6f2ccad4b50b246d Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Mon, 6 Nov 2023 11:03:45 +0200 Subject: [PATCH 073/327] =?UTF-8?q?VRF-669:=20adding=20CTF=20tests=20for?= =?UTF-8?q?=20VRF=20v2.5=20cancel=20subscription,=20oracle=20wi=E2=80=A6?= =?UTF-8?q?=20(#11159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-669: adding CTF tests for VRF v2.5 cancel subscription, oracle withdraw; added fund return as a teardown for the WASP load test * VRF-669: updating tests to have better balance calculation * VRF-669: small update * VRF-669: enabling tests; making use of big.Int Cmp() method * VRF-669: adding sub cancellation test for the coordinator owner; code refactoring; fixing load test --- .github/workflows/integration-tests.yml | 2 +- integration-tests/actions/actions.go | 16 + .../vrfv2plus/vrfv2plus_config/config.go | 6 +- .../actions/vrfv2plus/vrfv2plus_steps.go | 118 +++- .../contracts/contract_vrf_models.go | 6 + .../contracts/ethereum_vrfv2plus_contracts.go | 101 ++++ integration-tests/load/vrfv2plus/config.go | 4 +- integration-tests/load/vrfv2plus/config.toml | 8 +- integration-tests/load/vrfv2plus/gun.go | 5 +- .../load/vrfv2plus/vrfv2plus_test.go | 62 +- integration-tests/smoke/vrfv2plus_test.go | 530 ++++++++++++++---- integration-tests/utils/common.go | 10 + 12 files changed, 737 insertions(+), 131 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 0456c5f9d4..928c716dd1 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -303,7 +303,7 @@ jobs: pyroscope_env: ci-smoke-vrf2-evm-simulated - name: vrfv2plus nodes: 1 - os: ubuntu-latest + os: ubuntu20.04-8cores-32GB pyroscope_env: ci-smoke-vrf2plus-evm-simulated - name: forwarder_ocr nodes: 1 diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 010b431b56..b45b8e83b9 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -2,8 +2,10 @@ package actions import ( + "crypto/ecdsa" "encoding/json" "fmt" + "github.com/ethereum/go-ethereum/crypto" "math/big" "strings" "testing" @@ -443,3 +445,17 @@ func DeployMockETHLinkFeed(cd contracts.ContractDeployer, answer *big.Int) (cont } return mockETHLINKFeed, err } + +// todo - move to CTF +func GenerateWallet() (common.Address, error) { + privateKey, err := crypto.GenerateKey() + if err != nil { + return common.Address{}, err + } + publicKey := privateKey.Public() + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return common.Address{}, errors.New("cannot assert type: publicKey is not of type *ecdsa.PublicKey") + } + return crypto.PubkeyToAddress(*publicKeyECDSA), nil +} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go index 10d4f19c24..a47103a8a1 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -7,8 +7,8 @@ type VRFV2PlusConfig struct { IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator - SubscriptionFundingAmountLink int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"10"` // Amount of LINK to fund the subscription with - SubscriptionFundingAmountNative int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_NATIVE" default:"1"` // Amount of native currency to fund the subscription with + SubscriptionFundingAmountLink float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"5"` // Amount of LINK to fund the subscription with + SubscriptionFundingAmountNative float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_NATIVE" default:"1"` // Amount of native currency to fund the subscription with NumberOfWords uint32 `envconfig:"NUMBER_OF_WORDS" default:"3"` // Number of words to request CallbackGasLimit uint32 `envconfig:"CALLBACK_GAS_LIMIT" default:"1000000"` // Gas limit for the callback MaxGasLimitCoordinatorConfig uint32 `envconfig:"MAX_GAS_LIMIT_COORDINATOR_CONFIG" default:"2500000"` // Max gas limit for the VRF Coordinator config @@ -23,6 +23,8 @@ type VRFV2PlusConfig struct { RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request RandomnessRequestCountPerRequestDeviation uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST_DEVIATION" default:"0"` // How many randomness requests to send per request + RandomWordsFulfilledEventTimeout time.Duration `envconfig:"RANDOM_WORDS_FULFILLED_EVENT_TIMEOUT" default:"2m"` // How long to wait for the RandomWordsFulfilled event to be emitted + //Wrapper Config WrapperGasOverhead uint32 `envconfig:"WRAPPER_GAS_OVERHEAD" default:"50000"` CoordinatorGasOverhead uint32 `envconfig:"COORDINATOR_GAS_OVERHEAD" default:"52000"` diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 46f0ca58e6..e720116c21 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -3,6 +3,7 @@ package vrfv2plus import ( "context" "fmt" + "github.com/smartcontractkit/chainlink-testing-framework/utils" "math/big" "sync" "time" @@ -221,12 +222,18 @@ func VRFV2PlusUpgradedVersionRegisterProvingKey( return provingKey, nil } -func FundVRFCoordinatorV2_5Subscription(linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, chainClient blockchain.EVMClient, subscriptionID *big.Int, linkFundingAmount *big.Int) error { +func FundVRFCoordinatorV2_5Subscription( + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + chainClient blockchain.EVMClient, + subscriptionID *big.Int, + linkFundingAmountJuels *big.Int, +) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) if err != nil { return errors.Wrap(err, ErrABIEncodingFunding) } - _, err = linkToken.TransferAndCall(coordinator.Address(), big.NewInt(0).Mul(linkFundingAmount, big.NewInt(1e18)), encodedSubId) + _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) if err != nil { return errors.Wrap(err, ErrSendingLinkToken) } @@ -236,9 +243,10 @@ func FundVRFCoordinatorV2_5Subscription(linkToken contracts.LinkToken, coordinat // SetupVRFV2_5Environment will create specified number of subscriptions and add the same conumer/s to each of them func SetupVRFV2_5Environment( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, + registerProvingKeyAgainstAddress string, numberOfConsumers int, numberOfSubToCreate int, l zerolog.Logger, @@ -275,8 +283,12 @@ func SetupVRFV2_5Environment( if err != nil { return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Creating and funding subscriptions, adding consumers") - subIDs, err := CreateFundSubsAndAddConsumers(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, numberOfSubToCreate) + l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Int("Number of Subs to create", numberOfSubToCreate).Msg("Creating and funding subscriptions, adding consumers") + subIDs, err := CreateFundSubsAndAddConsumers( + env, + vrfv2PlusConfig, + linkToken, + vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, numberOfSubToCreate) if err != nil { return nil, nil, nil, err } @@ -287,12 +299,8 @@ func SetupVRFV2_5Environment( } pubKeyCompressed := vrfKey.Data.ID - nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() - if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrNodePrimaryKey) - } l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, nativeTokenPrimaryKeyAddress, vrfv2_5Contracts.Coordinator) + provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2_5Contracts.Coordinator) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrRegisteringProvingKey) } @@ -303,6 +311,11 @@ func SetupVRFV2_5Environment( chainID := env.EVMClient.GetChainID() + nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() + if err != nil { + return nil, nil, nil, errors.Wrap(err, ErrNodePrimaryKey) + } + l.Info().Msg("Creating VRFV2 Plus Job") job, err := CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], @@ -351,7 +364,7 @@ func SetupVRFV2_5Environment( func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, consumers []contracts.VRFv2PlusLoadTestConsumer, @@ -385,7 +398,7 @@ func CreateFundSubsAndAddConsumers( func CreateSubsAndFund( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subAmountToCreate int, @@ -439,7 +452,7 @@ func AddConsumersToSubs( func SetupVRFV2PlusWrapperEnvironment( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, coordinator contracts.VRFCoordinatorV2_5, @@ -574,19 +587,24 @@ func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkT func FundSubscriptions( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subIDs []*big.Int, ) error { for _, subID := range subIDs { //Native Billing - err := coordinator.FundSubscriptionWithNative(subID, big.NewInt(0).Mul(big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountNative), big.NewInt(1e18))) + amountWei := utils.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountNative)) + err := coordinator.FundSubscriptionWithNative( + subID, + amountWei, + ) if err != nil { return errors.Wrap(err, ErrFundSubWithNativeToken) } //Link Billing - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountLink)) + amountJuels := utils.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountLink)) + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { return errors.Wrap(err, ErrFundSubWithLinkToken) } @@ -605,7 +623,8 @@ func RequestRandomnessAndWaitForFulfillment( subID *big.Int, isNativeBilling bool, randomnessRequestCountPerRequest uint16, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) @@ -622,7 +641,15 @@ func RequestRandomnessAndWaitForFulfillment( return nil, errors.Wrap(err, ErrRequestRandomness) } - return WaitForRequestAndFulfillmentEvents(consumer.Address(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) + return WaitForRequestAndFulfillmentEvents( + consumer.Address(), + coordinator, + vrfv2PlusData, + subID, + isNativeBilling, + randomWordsFulfilledEventTimeout, + l, + ) } func RequestRandomnessAndWaitForFulfillmentUpgraded( @@ -631,7 +658,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) @@ -679,7 +706,8 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) @@ -708,7 +736,15 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( if err != nil { return nil, errors.Wrap(err, "error getting wrapper address") } - return WaitForRequestAndFulfillmentEvents(wrapperAddress.String(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) + return WaitForRequestAndFulfillmentEvents( + wrapperAddress.String(), + coordinator, + vrfv2PlusData, + subID, + isNativeBilling, + randomWordsFulfilledEventTimeout, + l, + ) } func WaitForRequestAndFulfillmentEvents( @@ -717,6 +753,7 @@ func WaitForRequestAndFulfillmentEvents( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( @@ -734,7 +771,7 @@ func WaitForRequestAndFulfillmentEvents( randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{subID}, []*big.Int{randomWordsRequestedEvent.RequestId}, - time.Minute*2, + randomWordsFulfilledEventTimeout, ) if err != nil { return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) @@ -777,6 +814,41 @@ func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadT } } +func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator contracts.VRFCoordinatorV2_5, l zerolog.Logger) error { + linkTotalBalance, err := coordinator.GetLinkTotalBalance(context.Background()) + if err != nil { + return errors.Wrap(err, "Error getting LINK total balance") + } + defaultWallet := client.GetDefaultWallet().Address() + l.Info(). + Str("LINK amount", linkTotalBalance.String()). + Str("Returning to", defaultWallet). + Msg("Returning LINK for fulfilled requests") + err = coordinator.OracleWithdraw( + common.HexToAddress(defaultWallet), + linkTotalBalance, + ) + if err != nil { + return errors.Wrap(err, "Error withdrawing LINK from coordinator to default wallet") + } + nativeTotalBalance, err := coordinator.GetNativeTokenTotalBalance(context.Background()) + if err != nil { + return errors.Wrap(err, "Error getting NATIVE total balance") + } + l.Info(). + Str("Native Token amount", linkTotalBalance.String()). + Str("Returning to", defaultWallet). + Msg("Returning Native Token for fulfilled requests") + err = coordinator.OracleWithdrawNative( + common.HexToAddress(defaultWallet), + nativeTotalBalance, + ) + if err != nil { + return errors.Wrap(err, "Error withdrawing NATIVE from coordinator to default wallet") + } + return nil +} + func getLoadTestMetrics( consumer contracts.VRFv2PlusLoadTestConsumer, metricsChannel chan *contracts.VRFLoadTestMetrics, @@ -934,7 +1006,7 @@ func logRandRequest( coordinator string, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger) { l.Debug(). Str("Consumer", consumer). diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index f0f57f58e7..c82924143b 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -80,11 +80,17 @@ type VRFCoordinatorV2_5 interface { AddConsumer(subId *big.Int, consumerAddress string) error FundSubscriptionWithNative(subId *big.Int, nativeTokenAmount *big.Int) error Address() string + PendingRequestsExist(ctx context.Context, subID *big.Int) (bool, error) GetSubscription(ctx context.Context, subID *big.Int) (vrf_coordinator_v2_5.GetSubscription, error) + OwnerCancelSubscription(subID *big.Int) (*types.Transaction, error) + CancelSubscription(subID *big.Int, to common.Address) (*types.Transaction, error) + OracleWithdraw(recipient common.Address, amount *big.Int) error + OracleWithdrawNative(recipient common.Address, amount *big.Int) error GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) FindSubscriptionID(subID *big.Int) (*big.Int, error) WaitForSubscriptionCreatedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated, error) + WaitForSubscriptionCanceledEvent(subID *big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 1488f97131..330166dc79 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -96,6 +96,18 @@ func (v *EthereumVRFCoordinatorV2_5) GetActiveSubscriptionIds(ctx context.Contex return activeSubscriptionIds, nil } +func (v *EthereumVRFCoordinatorV2_5) PendingRequestsExist(ctx context.Context, subID *big.Int) (bool, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + pendingRequestExists, err := v.coordinator.PendingRequestExists(opts, subID) + if err != nil { + return false, err + } + return pendingRequestExists, nil +} + func (v *EthereumVRFCoordinatorV2_5) GetSubscription(ctx context.Context, subID *big.Int) (vrf_coordinator_v2_5.GetSubscription, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), @@ -131,6 +143,75 @@ func (v *EthereumVRFCoordinatorV2_5) GetNativeTokenTotalBalance(ctx context.Cont return totalBalance, nil } +// OwnerCancelSubscription cancels subscription by Coordinator owner +// return funds to sub owner, +// does not check if pending requests for a sub exist +func (v *EthereumVRFCoordinatorV2_5) OwnerCancelSubscription(subID *big.Int) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.coordinator.OwnerCancelSubscription( + opts, + subID, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + +// CancelSubscription cancels subscription by Sub owner, +// return funds to specified address, +// checks if pending requests for a sub exist +func (v *EthereumVRFCoordinatorV2_5) CancelSubscription(subID *big.Int, to common.Address) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.coordinator.CancelSubscription( + opts, + subID, + to, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFCoordinatorV2_5) OracleWithdraw(recipient common.Address, amount *big.Int) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.coordinator.OracleWithdraw( + opts, + recipient, + amount, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFCoordinatorV2_5) OracleWithdrawNative(recipient common.Address, amount *big.Int) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.coordinator.OracleWithdrawNative( + opts, + recipient, + amount, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFCoordinatorV2_5) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -287,6 +368,26 @@ func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCreatedEvent(timeout tim } } +func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCanceledEvent(subID *big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) { + eventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled) + subscription, err := v.coordinator.WatchSubscriptionCanceled(nil, eventsChannel, []*big.Int{subID}) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionCanceled event") + case sub := <-eventsChannel: + return sub, nil + } + } +} + func (v *EthereumVRFCoordinatorV2_5) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled) subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, requestID, subID) diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index 50003c8286..a5439210c2 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -57,8 +57,8 @@ type Funding struct { } type SubFunding struct { - SubFundsLink int64 `toml:"sub_funds_link"` - SubFundsNative int64 `toml:"sub_funds_native"` + SubFundsLink float64 `toml:"sub_funds_link"` + SubFundsNative float64 `toml:"sub_funds_native"` } type Soak struct { diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml index 05e22bd51e..e3200fafe2 100644 --- a/integration-tests/load/vrfv2plus/config.toml +++ b/integration-tests/load/vrfv2plus/config.toml @@ -9,8 +9,8 @@ node_funds = 10 [ExistingEnvConfig] coordinator_address = "0x27b61f155F772b291D1d9B478BeAd37B2Ae447b0" -consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" -sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" +#consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" +#sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" key_hash = "0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae" create_fund_subs_and_add_consumers = true link_address = "0x779877A7B0D9E8603169DdbD7836e478b4624789" @@ -31,7 +31,7 @@ rate_limit_unit_duration = "3s" rps = 1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 5 +number_of_sub_to_create = 1 # approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx [Stress] @@ -39,7 +39,7 @@ rate_limit_unit_duration = "1s" rps = 3 randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 5 +number_of_sub_to_create = 1 # approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds [Spike] diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index c9947fa32f..21be1c74ca 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -15,7 +15,7 @@ type SingleHashGun struct { contracts *vrfv2plus.VRFV2_5Contracts keyHash [32]byte subIDs []*big.Int - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig logger zerolog.Logger } @@ -23,7 +23,7 @@ func NewSingleHashGun( contracts *vrfv2plus.VRFV2_5Contracts, keyHash [32]byte, subIDs []*big.Int, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ @@ -52,6 +52,7 @@ func (m *SingleHashGun) Call(l *wasp.Generator) *wasp.CallResult { randBool(), randomnessRequestCountPerRequest, m.vrfv2PlusConfig, + m.vrfv2PlusConfig.RandomWordsFulfilledEventTimeout, m.logger, ) if err != nil { diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index e619cf78fd..4d3de014bc 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -27,6 +27,7 @@ var ( vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts vrfv2PlusData *vrfv2plus.VRFV2PlusData subIDs []*big.Int + eoaWalletAddress string labels = map[string]string{ "branch": "vrfv2Plus_healthcheck", @@ -85,6 +86,32 @@ func TestVRFV2PlusPerformance(t *testing.T) { WithCustomCleanup( func() { teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + if env.EVMClient.NetworkSimulated() { + l.Info(). + Str("Network Name", env.EVMClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + //cancel subs and return funds to sub owner + for _, subID := range subIDs { + l.Info(). + Str("Returning funds from SubID", subID.String()). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subID) + if err != nil { + l.Error().Err(err).Msg("Error checking if pending requests exist") + } + if !pendingRequestsExist { + _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } else { + l.Error().Str("Sub ID", subID.String()).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") + } + + } + } }). Build() @@ -99,7 +126,14 @@ func TestVRFV2PlusPerformance(t *testing.T) { require.NoError(t, err) consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) require.NoError(t, err) - subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers(env, &vrfv2PlusConfig, linkToken, coordinator, consumers, vrfv2PlusConfig.NumberOfSubToCreate) + subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers( + env, + vrfv2PlusConfig, + linkToken, + coordinator, + consumers, + vrfv2PlusConfig.NumberOfSubToCreate, + ) require.NoError(t, err) } else { consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) @@ -141,6 +175,25 @@ func TestVRFV2PlusPerformance(t *testing.T) { WithCustomCleanup( func() { teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + + if env.EVMClient.NetworkSimulated() { + l.Info(). + Str("Network Name", env.EVMClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + for _, subID := range subIDs { + l.Info(). + Str("Returning funds from SubID", subID.String()). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } + //err = vrfv2plus.ReturnFundsForFulfilledRequests(env.EVMClient, vrfv2PlusContracts.Coordinator, l) + //l.Error().Err(err).Msg("Error returning funds for fulfilled requests") + } if err := env.Cleanup(); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } @@ -160,15 +213,18 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment( env, - &vrfv2PlusConfig, + vrfv2PlusConfig, linkToken, mockETHLinkFeed, + //register proving key against EOA address in order to return funds to this address + env.EVMClient.GetDefaultWallet().Address(), 1, vrfv2PlusConfig.NumberOfSubToCreate, l, ) require.NoError(t, err, "error setting up VRF v2_5 env") } + eoaWalletAddress = env.EVMClient.GetDefaultWallet().Address() l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { @@ -186,7 +242,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusContracts, vrfv2PlusData.KeyHash, subIDs, - &vrfv2PlusConfig, + vrfv2PlusConfig, l, ), Labels: labels, diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index d7381c9cd3..acd548c88e 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -2,6 +2,8 @@ package smoke import ( "context" + "fmt" + "github.com/smartcontractkit/chainlink/integration-tests/utils" "math/big" "testing" "time" @@ -45,7 +47,10 @@ func TestVRFv2Plus(t *testing.T) { linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1, 1, l) + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkToken, mockETHLinkFeed, defaultWalletAddress, 1, 1, l) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] @@ -55,7 +60,8 @@ func TestVRFv2Plus(t *testing.T) { vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) - t.Run("VRFV2 Plus With Link Billing", func(t *testing.T) { + t.Run("Link Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig var isNativeBilling = false subBalanceBeforeRequest := subscription.Balance @@ -69,8 +75,9 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, - &vrfv2PlusConfig, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -90,14 +97,14 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) - - t.Run("VRFV2 Plus With Native Billing", func(t *testing.T) { + t.Run("Native Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig var isNativeBilling = true subNativeTokenBalanceBeforeRequest := subscription.NativeBalance @@ -111,8 +118,9 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, - &vrfv2PlusConfig, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -131,120 +139,451 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) + t.Run("Direct Funding (VRFV2PlusWrapper)", func(t *testing.T) { + testConfig := vrfv2PlusConfig + wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( + env, + testConfig, + linkToken, + mockETHLinkFeed, + vrfv2PlusContracts.Coordinator, + vrfv2PlusData.KeyHash, + 1, + ) + require.NoError(t, err) - wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( - env, - &vrfv2PlusConfig, - linkToken, - mockETHLinkFeed, - vrfv2PlusContracts.Coordinator, - vrfv2PlusData.KeyHash, - 1, - ) - require.NoError(t, err) + t.Run("Link Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig + var isNativeBilling = false + + wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) + require.NoError(t, err, "error getting wrapper consumer balance") + + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceBeforeRequest := wrapperSubscription.Balance + + randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( + wrapperContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + wrapperSubID, + isNativeBilling, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceAfterRequest := wrapperSubscription.Balance + require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) + + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, consumerStatus.Fulfilled) + + expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) + + wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) + require.NoError(t, err, "error getting wrapper consumer balance") + require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) + + //todo: uncomment when VRF-651 will be fixed + //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") + vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) + + require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + for _, w := range consumerStatus.RandomWords { + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") + } + }) + t.Run("Native Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig + var isNativeBilling = true + + wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + require.NoError(t, err, "error getting wrapper consumer balance") + + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceBeforeRequest := wrapperSubscription.NativeBalance + + randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( + wrapperContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + wrapperSubID, + isNativeBilling, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceAfterRequest := wrapperSubscription.NativeBalance + require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) + + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, consumerStatus.Fulfilled) + + expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) + + wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + require.NoError(t, err, "error getting wrapper consumer balance") + require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) + + //todo: uncomment when VRF-651 will be fixed + //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") + vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) + + require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + for _, w := range consumerStatus.RandomWords { + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") + } + }) + }) + t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { + testConfig := vrfv2PlusConfig + subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( + env, + testConfig, + linkToken, + vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.LoadTestConsumers, + 1, + ) + require.NoError(t, err) + subIDForCancelling := subIDsForCancelling[0] - t.Run("VRFV2 Plus With Direct Funding (VRFV2PlusWrapper) - Link Billing", func(t *testing.T) { - var isNativeBilling = false + testWalletAddress, err := actions.GenerateWallet() - wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) - require.NoError(t, err, "error getting wrapper consumer balance") + testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), testWalletAddress) + require.NoError(t, err) + + testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(context.Background(), testWalletAddress.String()) + require.NoError(t, err) - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - subBalanceBeforeRequest := wrapperSubscription.Balance - randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( - wrapperContracts.LoadTestConsumers[0], + subBalanceLink := subscriptionForCancelling.Balance + subBalanceNative := subscriptionForCancelling.NativeBalance + l.Info(). + Str("Subscription Amount Native", subBalanceNative.String()). + Str("Subscription Amount Link", subBalanceLink.String()). + Str("Returning funds from SubID", subIDForCancelling.String()). + Str("Returning funds to", testWalletAddress.String()). + Msg("Canceling subscription and returning funds to subscription owner") + tx, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subIDForCancelling, testWalletAddress) + require.NoError(t, err, "Error canceling subscription") + + subscriptionCanceledEvent, err := vrfv2PlusContracts.Coordinator.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + require.NoError(t, err, "error waiting for subscription canceled event") + + cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + require.NoError(t, err, "error getting tx cancellation Tx Receipt") + + txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + + l.Info(). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Msg("Cancellation TX Receipt") + + l.Info(). + Str("Returned Subscription Amount Native", subscriptionCanceledEvent.AmountNative.String()). + Str("Returned Subscription Amount Link", subscriptionCanceledEvent.AmountLink.String()). + Str("SubID", subscriptionCanceledEvent.SubId.String()). + Str("Returned to", subscriptionCanceledEvent.To.String()). + Msg("Subscription Canceled Event") + + require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + + testWalletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), testWalletAddress) + require.NoError(t, err) + + testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(context.Background(), testWalletAddress.String()) + require.NoError(t, err) + + //Verify that sub was deleted from Coordinator + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") + + subFundsReturnedNativeActual := new(big.Int).Sub(testWalletBalanceNativeAfterSubCancelling, testWalletBalanceNativeBeforeSubCancelling) + subFundsReturnedLinkActual := new(big.Int).Sub(testWalletBalanceLinkAfterSubCancelling, testWalletBalanceLinkBeforeSubCancelling) + + subFundsReturnedNativeExpected := new(big.Int).Sub(subBalanceNative, cancellationTxFeeWei) + deltaSpentOnCancellationTxFee := new(big.Int).Sub(subBalanceNative, subFundsReturnedNativeActual) + l.Info(). + Str("Sub Balance - Native", subBalanceNative.String()). + Str("Delta Spent On Cancellation Tx Fee - `NativeBalance - subFundsReturnedNativeActual`", deltaSpentOnCancellationTxFee.String()). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Sub Funds Returned Actual - Native", subFundsReturnedNativeActual.String()). + Str("Sub Funds Returned Expected - `NativeBalance - cancellationTxFeeWei`", subFundsReturnedNativeExpected.String()). + Str("Sub Funds Returned Actual - Link", subFundsReturnedLinkActual.String()). + Str("Sub Balance - Link", subBalanceLink.String()). + Msg("Sub funds returned") + + //todo - this fails on SIMULATED env as tx cost is calculated different as for testnets and it's not receipt.EffectiveGasPrice*receipt.GasUsed + //require.Equal(t, subFundsReturnedNativeExpected, subFundsReturnedNativeActual, "Returned funds are not equal to sub balance that was cancelled") + require.Equal(t, 1, testWalletBalanceNativeAfterSubCancelling.Cmp(testWalletBalanceNativeBeforeSubCancelling), "Native funds were not returned after sub cancellation") + require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") + + }) + t.Run("Owner Canceling Sub And Returning Funds While Having Pending Requests", func(t *testing.T) { + testConfig := vrfv2PlusConfig + //underfund subs in order rand fulfillments to fail + testConfig.SubscriptionFundingAmountNative = float64(0.000000000000000001) //1 Wei + testConfig.SubscriptionFundingAmountLink = float64(0.000000000000000001) //1 Juels + + subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( + env, + testConfig, + linkToken, vrfv2PlusContracts.Coordinator, - vrfv2PlusData, - wrapperSubID, - isNativeBilling, - &vrfv2PlusConfig, - l, + vrfv2PlusContracts.LoadTestConsumers, + 1, ) - require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + require.NoError(t, err) - expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + subIDForCancelling := subIDsForCancelling[0] + + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - subBalanceAfterRequest := wrapperSubscription.Balance - require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) - require.NoError(t, err, "error getting rand request status") - require.True(t, consumerStatus.Fulfilled) + vrfv2plus.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2PlusContracts.Coordinator) - expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) + activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + require.NoError(t, err) - wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) - require.NoError(t, err, "error getting wrapper consumer balance") - require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) + require.True(t, utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subIDForCancelling)) - //todo: uncomment when VRF-651 will be fixed - //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subIDForCancelling) + require.NoError(t, err) + require.False(t, pendingRequestsExist, "Pending requests should not exist") - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) - for _, w := range consumerStatus.RandomWords { - l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") - require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") - } - }) + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + subIDForCancelling, + false, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + 5*time.Second, + l, + ) - t.Run("VRFV2 Plus With Direct Funding (VRFV2PlusWrapper) - Native Billing", func(t *testing.T) { - var isNativeBilling = true + require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") - wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) - require.NoError(t, err, "error getting wrapper consumer balance") + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + subIDForCancelling, + true, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") + + pendingRequestsExist, err = vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subIDForCancelling) + require.NoError(t, err) + require.True(t, pendingRequestsExist, "Pending requests should exist after unfulfilled rand requests due to low sub balance") + + walletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) + + walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) + + subscriptionForCancelling, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - subBalanceBeforeRequest := wrapperSubscription.NativeBalance - randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( - wrapperContracts.LoadTestConsumers[0], + subBalanceLink := subscriptionForCancelling.Balance + subBalanceNative := subscriptionForCancelling.NativeBalance + l.Info(). + Str("Subscription Amount Native", subBalanceNative.String()). + Str("Subscription Amount Link", subBalanceLink.String()). + Str("Returning funds from SubID", subIDForCancelling.String()). + Str("Returning funds to", defaultWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + tx, err := vrfv2PlusContracts.Coordinator.OwnerCancelSubscription(subIDForCancelling) + require.NoError(t, err, "Error canceling subscription") + + subscriptionCanceledEvent, err := vrfv2PlusContracts.Coordinator.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + require.NoError(t, err, "error waiting for subscription canceled event") + + cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + require.NoError(t, err, "error getting tx cancellation Tx Receipt") + + txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + + l.Info(). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Msg("Cancellation TX Receipt") + + l.Info(). + Str("Returned Subscription Amount Native", subscriptionCanceledEvent.AmountNative.String()). + Str("Returned Subscription Amount Link", subscriptionCanceledEvent.AmountLink.String()). + Str("SubID", subscriptionCanceledEvent.SubId.String()). + Str("Returned to", subscriptionCanceledEvent.To.String()). + Msg("Subscription Canceled Event") + + require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + + walletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) + + walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) + + //Verify that sub was deleted from Coordinator + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + fmt.Println("err", err) + require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") + + subFundsReturnedNativeActual := new(big.Int).Sub(walletBalanceNativeAfterSubCancelling, walletBalanceNativeBeforeSubCancelling) + subFundsReturnedLinkActual := new(big.Int).Sub(walletBalanceLinkAfterSubCancelling, walletBalanceLinkBeforeSubCancelling) + + subFundsReturnedNativeExpected := new(big.Int).Sub(subBalanceNative, cancellationTxFeeWei) + deltaSpentOnCancellationTxFee := new(big.Int).Sub(subBalanceNative, subFundsReturnedNativeActual) + l.Info(). + Str("Sub Balance - Native", subBalanceNative.String()). + Str("Delta Spent On Cancellation Tx Fee - `NativeBalance - subFundsReturnedNativeActual`", deltaSpentOnCancellationTxFee.String()). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Sub Funds Returned Actual - Native", subFundsReturnedNativeActual.String()). + Str("Sub Funds Returned Expected - `NativeBalance - cancellationTxFeeWei`", subFundsReturnedNativeExpected.String()). + Str("Sub Funds Returned Actual - Link", subFundsReturnedLinkActual.String()). + Str("Sub Balance - Link", subBalanceLink.String()). + Str("walletBalanceNativeBeforeSubCancelling", walletBalanceNativeBeforeSubCancelling.String()). + Str("walletBalanceNativeAfterSubCancelling", walletBalanceNativeAfterSubCancelling.String()). + Msg("Sub funds returned") + + //todo - need to use different wallet for each test to verify exact amount of Native/LINK returned + //todo - as defaultWallet is used in other tests in parallel which might affect the balance + //require.Equal(t, 1, walletBalanceNativeAfterSubCancelling.Cmp(walletBalanceNativeBeforeSubCancelling), "Native funds were not returned after sub cancellation") + + //todo - this fails on SIMULATED env as tx cost is calculated different as for testnets and it's not receipt.EffectiveGasPrice*receipt.GasUsed + //require.Equal(t, subFundsReturnedNativeExpected, subFundsReturnedNativeActual, "Returned funds are not equal to sub balance that was cancelled") + require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") + + activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + require.NoError(t, err, "error getting active subscription ids") + + require.False( + t, + utils.BigIntSliceContains(activeSubscriptionIdsAfterSubCancellation, subIDForCancelling), + "Active subscription ids should not contain sub id after sub cancellation", + ) + }) + t.Run("Oracle Withdraw", func(t *testing.T) { + testConfig := vrfv2PlusConfig + subIDsForOracleWithDraw, err := vrfv2plus.CreateFundSubsAndAddConsumers( + env, + testConfig, + linkToken, + vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.LoadTestConsumers, + 1, + ) + require.NoError(t, err) + subIDForOracleWithdraw := subIDsForOracleWithDraw[0] + + fulfilledEventLink, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], vrfv2PlusContracts.Coordinator, vrfv2PlusData, - wrapperSubID, - isNativeBilling, - &vrfv2PlusConfig, + subIDForOracleWithdraw, + false, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, l, ) - require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + require.NoError(t, err) - expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) - require.NoError(t, err, "error getting subscription information") - subBalanceAfterRequest := wrapperSubscription.NativeBalance - require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) + fulfilledEventNative, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + subIDForOracleWithdraw, + true, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err) + amountToWithdrawLink := fulfilledEventLink.Payment - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) - require.NoError(t, err, "error getting rand request status") - require.True(t, consumerStatus.Fulfilled) + defaultWalletBalanceNativeBeforeOracleWithdraw, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) - expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) + defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) - wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) - require.NoError(t, err, "error getting wrapper consumer balance") - require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) + l.Info(). + Str("Returning to", defaultWalletAddress). + Str("Amount", amountToWithdrawLink.String()). + Msg("Invoking Oracle Withdraw for LINK") - //todo: uncomment when VRF-651 will be fixed - //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) + err = vrfv2PlusContracts.Coordinator.OracleWithdraw( + common.HexToAddress(defaultWalletAddress), + amountToWithdrawLink, + ) + require.NoError(t, err, "error withdrawing LINK from coordinator to default wallet") + amountToWithdrawNative := fulfilledEventNative.Payment - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) - for _, w := range consumerStatus.RandomWords { - l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") - require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") - } - }) + l.Info(). + Str("Returning to", defaultWalletAddress). + Str("Amount", amountToWithdrawNative.String()). + Msg("Invoking Oracle Withdraw for Native") + + err = vrfv2PlusContracts.Coordinator.OracleWithdrawNative( + common.HexToAddress(defaultWalletAddress), + amountToWithdrawNative, + ) + require.NoError(t, err, "error withdrawing Native tokens from coordinator to default wallet") + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + defaultWalletBalanceNativeAfterOracleWithdraw, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) + + defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) + + //not possible to verify exact amount of Native/LINK returned as defaultWallet is used in other tests in parallel which might affect the balance + require.Equal(t, 1, defaultWalletBalanceNativeAfterOracleWithdraw.Cmp(defaultWalletBalanceNativeBeforeOracleWithdraw), "Native funds were not returned after oracle withdraw native") + require.Equal(t, 1, defaultWalletBalanceLinkAfterOracleWithdraw.Cmp(defaultWalletBalanceLinkBeforeOracleWithdraw), "LINK funds were not returned after oracle withdraw") + }) } func TestVRFv2PlusMigration(t *testing.T) { @@ -270,7 +609,10 @@ func TestVRFv2PlusMigration(t *testing.T) { linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, 2, 1, l) + nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() + require.NoError(t, err, "error getting primary eth address") + + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, nativeTokenPrimaryKeyAddress, 2, 1, l) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] @@ -395,10 +737,10 @@ func TestVRFv2PlusMigration(t *testing.T) { expectedLinkTotalBalanceForOldCoordinator := new(big.Int).Sub(oldCoordinatorLinkTotalBalanceBeforeMigration, oldSubscriptionBeforeMigration.Balance) expectedEthTotalBalanceForOldCoordinator := new(big.Int).Sub(oldCoordinatorEthTotalBalanceBeforeMigration, oldSubscriptionBeforeMigration.NativeBalance) - require.Equal(t, expectedLinkTotalBalanceForMigratedCoordinator, migratedCoordinatorLinkTotalBalanceAfterMigration) - require.Equal(t, expectedEthTotalBalanceForMigratedCoordinator, migratedCoordinatorEthTotalBalanceAfterMigration) - require.Equal(t, expectedLinkTotalBalanceForOldCoordinator, oldCoordinatorLinkTotalBalanceAfterMigration) - require.Equal(t, expectedEthTotalBalanceForOldCoordinator, oldCoordinatorEthTotalBalanceAfterMigration) + require.Equal(t, 0, expectedLinkTotalBalanceForMigratedCoordinator.Cmp(migratedCoordinatorLinkTotalBalanceAfterMigration)) + require.Equal(t, 0, expectedEthTotalBalanceForMigratedCoordinator.Cmp(migratedCoordinatorEthTotalBalanceAfterMigration)) + require.Equal(t, 0, expectedLinkTotalBalanceForOldCoordinator.Cmp(oldCoordinatorLinkTotalBalanceAfterMigration)) + require.Equal(t, 0, expectedEthTotalBalanceForOldCoordinator.Cmp(oldCoordinatorEthTotalBalanceAfterMigration)) //Verify rand requests fulfills with Link Token billing _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( @@ -407,7 +749,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, false, - &vrfv2PlusConfig, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -419,7 +761,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, true, - &vrfv2PlusConfig, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go index c8243097a7..9aacaeed41 100644 --- a/integration-tests/utils/common.go +++ b/integration-tests/utils/common.go @@ -1,6 +1,7 @@ package utils import ( + "math/big" "net" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -23,3 +24,12 @@ func MustIP(s string) *net.IP { } return &ip } + +func BigIntSliceContains(slice []*big.Int, b *big.Int) bool { + for _, a := range slice { + if b.Cmp(a) == 0 { + return true + } + } + return false +} From e623afd8079d0875301df33acf74f75e989abcde Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Mon, 6 Nov 2023 11:22:13 +0100 Subject: [PATCH 074/327] move workflow to correct directory (#11168) --- .../on-demand-log-poller.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/{log_poller_on_demand.yml => workflows/on-demand-log-poller.yml} (95%) diff --git a/.github/log_poller_on_demand.yml b/.github/workflows/on-demand-log-poller.yml similarity index 95% rename from .github/log_poller_on_demand.yml rename to .github/workflows/on-demand-log-poller.yml index 856d1e0234..c5470a5a3d 100644 --- a/.github/log_poller_on_demand.yml +++ b/.github/workflows/on-demand-log-poller.yml @@ -31,7 +31,7 @@ on: default: "Sepolia" required: true fundingKey: - description: Private key used to fund the contracts + description: Private key used to fund the contracts (must have sufficient ETH and LINK!) required: true rpcURL: description: RPC URL to use From 28e959668484eeaac3e48ccb44a85b6e35ef21f8 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 6 Nov 2023 10:03:10 -0500 Subject: [PATCH 075/327] Include multiple blocks in observation (#11142) * Include multiple blocks in observation * Bump chainlink-relay * Take the trash out * Add prom metrics * Bump chainlink-relay => c28841d7cd41b14fa1207586a905c44f735e9517 * Address PR comments * Update core/services/relay/evm/mercury/v1/data_source.go Co-authored-by: martin-cll <121895364+martin-cll@users.noreply.github.com> * Address PR feedback * Fix test --------- Co-authored-by: martin-cll <121895364+martin-cll@users.noreply.github.com> --- core/chains/evm/types/models.go | 15 ++ core/chains/evm/types/models_test.go | 23 +++ core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../evm/mercury/mocks/chain_head_tracker.go | 30 +-- .../services/relay/evm/mercury/types/types.go | 2 - .../relay/evm/mercury/v1/data_source.go | 90 ++++++--- .../relay/evm/mercury/v1/data_source_test.go | 183 ++++++++++-------- docs/CHANGELOG.md | 7 + go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 13 files changed, 221 insertions(+), 147 deletions(-) diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index a71c9e8716..6db5d49575 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -227,6 +227,21 @@ func (h *Head) NextInt() *big.Int { return new(big.Int).Add(h.ToInt(), big.NewInt(1)) } +// AsSlice returns a slice of heads up to length k +// len(heads) may be less than k if the available chain is not long enough +func (h *Head) AsSlice(k int) (heads []*Head) { + if k < 1 || h == nil { + return + } + heads = make([]*Head, 1) + heads[0] = h + for len(heads) < k && h.Parent != nil { + h = h.Parent + heads = append(heads, h) + } + return +} + func (h *Head) UnmarshalJSON(bs []byte) error { type head struct { Hash common.Hash `json:"hash"` diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index 2f9dc7dd7c..2911e426e8 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -129,6 +129,29 @@ func TestHead_ChainLength(t *testing.T) { assert.Equal(t, uint32(0), head2.ChainLength()) } +func TestHead_AsSlice(t *testing.T) { + h1 := &evmtypes.Head{ + Number: 1, + } + h2 := &evmtypes.Head{ + Number: 2, + Parent: h1, + } + h3 := &evmtypes.Head{ + Number: 3, + Parent: h2, + } + + assert.Len(t, (*evmtypes.Head)(nil).AsSlice(0), 0) + assert.Len(t, (*evmtypes.Head)(nil).AsSlice(1), 0) + + assert.Len(t, h3.AsSlice(0), 0) + assert.Equal(t, []*evmtypes.Head{h3}, h3.AsSlice(1)) + assert.Equal(t, []*evmtypes.Head{h3, h2}, h3.AsSlice(2)) + assert.Equal(t, []*evmtypes.Head{h3, h2, h1}, h3.AsSlice(3)) + assert.Equal(t, []*evmtypes.Head{h3, h2, h1}, h3.AsSlice(4)) +} + func TestModels_HexToFunctionSelector(t *testing.T) { t.Parallel() fid := evmtypes.HexToFunctionSelector("0xb3f98adc") diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 17c2cff103..6b0a33451e 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -305,7 +305,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de // 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 ae1f924c0f..2cb0eb2582 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1466,8 +1466,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 h1:59vz5H52EpwWE/64ZQpNCs7Gtnyi7/ytjyoGjlbKhBA= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de h1:CeVpn5xEdmuEsYE8ss2b7bSq9h3BY4OPvpqXeYIPnHw= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de/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/mocks/chain_head_tracker.go b/core/services/relay/evm/mercury/mocks/chain_head_tracker.go index 1a5a7e47c5..b6f2981cf0 100644 --- a/core/services/relay/evm/mercury/mocks/chain_head_tracker.go +++ b/core/services/relay/evm/mercury/mocks/chain_head_tracker.go @@ -4,13 +4,11 @@ package mocks import ( common "github.com/ethereum/go-ethereum/common" - client "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" mock "github.com/stretchr/testify/mock" + + types "github.com/smartcontractkit/chainlink/v2/common/types" ) // ChainHeadTracker is an autogenerated mock type for the ChainHeadTracker type @@ -18,32 +16,16 @@ type ChainHeadTracker struct { mock.Mock } -// Client provides a mock function with given fields: -func (_m *ChainHeadTracker) Client() client.Client { - ret := _m.Called() - - var r0 client.Client - if rf, ok := ret.Get(0).(func() client.Client); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(client.Client) - } - } - - return r0 -} - // HeadTracker provides a mock function with given fields: -func (_m *ChainHeadTracker) HeadTracker() commontypes.HeadTracker[*evmtypes.Head, common.Hash] { +func (_m *ChainHeadTracker) HeadTracker() types.HeadTracker[*evmtypes.Head, common.Hash] { ret := _m.Called() - var r0 commontypes.HeadTracker[*evmtypes.Head, common.Hash] - if rf, ok := ret.Get(0).(func() commontypes.HeadTracker[*evmtypes.Head, common.Hash]); ok { + var r0 types.HeadTracker[*evmtypes.Head, common.Hash] + if rf, ok := ret.Get(0).(func() types.HeadTracker[*evmtypes.Head, common.Hash]); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(commontypes.HeadTracker[*evmtypes.Head, common.Hash]) + r0 = ret.Get(0).(types.HeadTracker[*evmtypes.Head, common.Hash]) } } diff --git a/core/services/relay/evm/mercury/types/types.go b/core/services/relay/evm/mercury/types/types.go index ca266ca8cc..7059689939 100644 --- a/core/services/relay/evm/mercury/types/types.go +++ b/core/services/relay/evm/mercury/types/types.go @@ -8,14 +8,12 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) //go:generate mockery --quiet --name ChainHeadTracker --output ../mocks/ --case=underscore type ChainHeadTracker interface { - Client() evmclient.Client HeadTracker() httypes.HeadTracker } diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index d225dbee68..1b16dc76f9 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -8,6 +8,8 @@ import ( "sync" pkgerrors "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -25,6 +27,24 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) +var ( + insufficientBlocksCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_insufficient_blocks_count", + Help: fmt.Sprintf("Count of times that there were not enough blocks in the chain during observation (need: %d)", nBlocksObservation), + }, + []string{"feedID"}, + ) + zeroBlocksCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_zero_blocks_count", + Help: "Count of times that there were zero blocks in the chain during observation", + }, + []string{"feedID"}, + ) +) + +// nBlocksObservation controls how many blocks are included in the LatestBlocks observation +const nBlocksObservation int = 5 + type Runner interface { ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) } @@ -51,18 +71,31 @@ type datasource struct { chainHeadTracker types.ChainHeadTracker fetcher Fetcher initialBlockNumber *int64 + + insufficientBlocksCounter prometheus.Counter + zeroBlocksCounter prometheus.Counter } var _ relaymercuryv1.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, rr chan *pipeline.Run, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainHeadTracker types.ChainHeadTracker, fetcher Fetcher, initialBlockNumber *int64, feedID [32]byte) *datasource { - return &datasource{pr, jb, spec, lggr, rr, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainHeadTracker, fetcher, initialBlockNumber} +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, rr chan *pipeline.Run, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainHeadTracker types.ChainHeadTracker, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { + return &datasource{pr, jb, spec, lggr, rr, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainHeadTracker, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} +} + +type ErrEmptyLatestReport struct { + Err error +} + +func (e ErrEmptyLatestReport) Unwrap() error { return e.Err } + +func (e ErrEmptyLatestReport) Error() string { + return fmt.Sprintf("FetchInitialMaxFinalizedBlockNumber returned empty LatestReport; this is a new feed. No initialBlockNumber was set, tried to use current block number to determine maxFinalizedBlockNumber but got error: %v", e.Err) } func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs relaymercuryv1.Observation, pipelineExecutionErr error) { - // setCurrentBlock must come first, along with observationTimestamp, to - // avoid front-running - ds.setCurrentBlock(ctx, &obs) + // setLatestBlocks must come chronologically before observations, along + // with observationTimestamp, to avoid front-running + ds.setLatestBlocks(ctx, &obs) var wg sync.WaitGroup if fetchMaxFinalizedBlockNum { @@ -89,7 +122,7 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam } if ds.initialBlockNumber == nil { if obs.CurrentBlockNum.Err != nil { - obs.MaxFinalizedBlockNumber.Err = fmt.Errorf("FetchInitialMaxFinalizedBlockNumber returned empty LatestReport; this is a new feed. No initialBlockNumber was set, tried to use current block number to determine maxFinalizedBlockNumber but got error: %w", obs.CurrentBlockNum.Err) + obs.MaxFinalizedBlockNumber.Err = ErrEmptyLatestReport{Err: obs.CurrentBlockNum.Err} } else { // Subract 1 here because we will later add 1 to the // maxFinalizedBlockNumber to get the first validFromBlockNum, which @@ -258,37 +291,40 @@ func (ds *datasource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.T return run, trrs, err } -func (ds *datasource) setCurrentBlock(ctx context.Context, obs *relaymercuryv1.Observation) { - latestHead, err := ds.getCurrentBlock(ctx) - if err != nil { +func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.Observation) { + latestBlocks := ds.getLatestBlocks(ctx, nBlocksObservation) + if len(latestBlocks) < nBlocksObservation { + ds.insufficientBlocksCounter.Inc() + ds.lggr.Warnw("Insufficient blocks", "latestBlocks", latestBlocks, "lenLatestBlocks", len(latestBlocks), "nBlocksObservation", nBlocksObservation) + } + + // TODO: remove with https://smartcontract-it.atlassian.net/browse/BCF-2209 + if len(latestBlocks) == 0 { + ds.zeroBlocksCounter.Inc() + err := errors.New("no blocks available") obs.CurrentBlockNum.Err = err obs.CurrentBlockHash.Err = err obs.CurrentBlockTimestamp.Err = err - return + } else { + obs.CurrentBlockNum.Val = latestBlocks[0].Number + obs.CurrentBlockHash.Val = latestBlocks[0].Hash.Bytes() + if latestBlocks[0].Timestamp.IsZero() { + obs.CurrentBlockTimestamp.Val = 0 + } else { + obs.CurrentBlockTimestamp.Val = uint64(latestBlocks[0].Timestamp.Unix()) + } } - obs.CurrentBlockNum.Val = latestHead.Number - obs.CurrentBlockHash.Val = latestHead.Hash.Bytes() - if latestHead.Timestamp.IsZero() { - obs.CurrentBlockTimestamp.Val = 0 - } else { - obs.CurrentBlockTimestamp.Val = uint64(latestHead.Timestamp.Unix()) + for _, block := range latestBlocks { + obs.LatestBlocks = append(obs.LatestBlocks, relaymercuryv1.NewBlock(block.Number, block.Hash.Bytes(), uint64(block.Timestamp.Unix()))) } } -func (ds *datasource) getCurrentBlock(ctx context.Context) (*evmtypes.Head, error) { - // Use the headtracker's view of the latest block, this is very fast since +func (ds *datasource) getLatestBlocks(ctx context.Context, k int) (blocks []*evmtypes.Head) { + // Use the headtracker's view of the chain, this is very fast since // it doesn't make any external network requests, and it is the // headtracker's job to ensure it has an up-to-date view of the chain based // on responses from all available RPC nodes latestHead := ds.chainHeadTracker.HeadTracker().LatestChain() - if latestHead == nil { - logger.Sugared(ds.lggr).AssumptionViolation("HeadTracker unexpectedly returned nil head, falling back to RPC call") - var err error - latestHead, err = ds.chainHeadTracker.Client().HeadByNumber(ctx, nil) - if err != nil { - return nil, err - } - } - return latestHead, nil + return latestHead.AsSlice(k) } diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 6e46095130..42983fa002 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -19,17 +18,17 @@ import ( relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" mercurymocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -56,11 +55,9 @@ func (m *mockFetcher) LatestTimestamp(context.Context) (int64, error) { var _ types.ChainHeadTracker = &mockHeadTracker{} type mockHeadTracker struct { - c evmclient.Client h httypes.HeadTracker } -func (m *mockHeadTracker) Client() evmclient.Client { return m.c } func (m *mockHeadTracker) HeadTracker() httypes.HeadTracker { return m.h } type mockORM struct { @@ -74,7 +71,8 @@ func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg func TestMercury_Observe(t *testing.T) { orm := &mockORM{} - ds := &datasource{lggr: logger.TestLogger(t), orm: orm, codec: (reportcodecv1.ReportCodec{})} + lggr := logger.TestLogger(t) + ds := NewDataSource(orm, nil, job.Job{}, pipeline.Spec{}, lggr, nil, nil, nil, nil, nil, mercuryutils.FeedID{}) ctx := testutils.Context(t) repts := ocrtypes.ReportTimestamp{} @@ -108,9 +106,7 @@ func TestMercury_Observe(t *testing.T) { ds.spec = spec h := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - c := evmclimocks.NewClient(t) ht := &mockHeadTracker{ - c: c, h: h, } ds.chainHeadTracker = ht @@ -202,25 +198,21 @@ func TestMercury_Observe(t *testing.T) { assert.NoError(t, obs.MaxFinalizedBlockNumber.Err) assert.Equal(t, head.Number-1, obs.MaxFinalizedBlockNumber.Val) }) - t.Run("if current block num errored", func(t *testing.T) { + t.Run("if no current block available", func(t *testing.T) { h2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) h2.On("LatestChain").Return((*evmtypes.Head)(nil)) ht.h = h2 - c2 := evmclimocks.NewClient(t) - c2.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, errors.New("head retrieval failed")) - ht.c = c2 obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) - assert.EqualError(t, obs.MaxFinalizedBlockNumber.Err, "FetchInitialMaxFinalizedBlockNumber returned empty LatestReport; this is a new feed. No initialBlockNumber was set, tried to use current block number to determine maxFinalizedBlockNumber but got error: head retrieval failed") + assert.EqualError(t, obs.MaxFinalizedBlockNumber.Err, "FetchInitialMaxFinalizedBlockNumber returned empty LatestReport; this is a new feed. No initialBlockNumber was set, tried to use current block number to determine maxFinalizedBlockNumber but got error: no blocks available") }) }) }) }) ht.h = h - ht.c = c t.Run("when fetchMaxFinalizedBlockNum=false", func(t *testing.T) { t.Run("when run execution fails, returns error", func(t *testing.T) { @@ -322,52 +314,96 @@ func TestMercury_Observe(t *testing.T) { t.Fatal("expected run on channel") } }) - t.Run("if head tracker returns nil, falls back to RPC method", func(t *testing.T) { - t.Run("if call succeeds", func(t *testing.T) { - h = commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - h.On("LatestChain").Return((*evmtypes.Head)(nil)) - ht.h = h - c.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(head, nil).Once() - - obs, err := ds.Observe(ctx, repts, false) - assert.NoError(t, err) + }) - assert.Equal(t, head.Number, obs.CurrentBlockNum.Val) - assert.NoError(t, obs.CurrentBlockNum.Err) - assert.Equal(t, fmt.Sprintf("%x", head.Hash), fmt.Sprintf("%x", obs.CurrentBlockHash.Val)) - assert.NoError(t, obs.CurrentBlockHash.Err) - assert.Equal(t, uint64(head.Timestamp.Unix()), obs.CurrentBlockTimestamp.Val) - assert.NoError(t, obs.CurrentBlockTimestamp.Err) + t.Run("LatestBlocks is populated correctly", func(t *testing.T) { + t.Run("when chain length is zero", func(t *testing.T) { + ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + ht2.On("LatestChain").Return((*evmtypes.Head)(nil)) + ht.h = ht2 - h.AssertExpectations(t) - c.AssertExpectations(t) - }) - t.Run("if call fails, returns error for that observation", func(t *testing.T) { - c = evmclimocks.NewClient(t) - ht.c = c - c.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, errors.New("client call failed")).Once() + obs, err := ds.Observe(ctx, repts, true) + assert.NoError(t, err) - obs, err := ds.Observe(ctx, repts, false) - assert.NoError(t, err) + assert.Len(t, obs.LatestBlocks, 0) - assert.Zero(t, obs.CurrentBlockNum.Val) - assert.EqualError(t, obs.CurrentBlockNum.Err, "client call failed") - assert.Zero(t, obs.CurrentBlockHash.Val) - assert.EqualError(t, obs.CurrentBlockHash.Err, "client call failed") - assert.Zero(t, obs.CurrentBlockTimestamp.Val) - assert.EqualError(t, obs.CurrentBlockTimestamp.Err, "client call failed") + ht2.AssertExpectations(t) + }) + t.Run("when chain is too short", func(t *testing.T) { + h4 := &evmtypes.Head{ + Number: 4, + Parent: nil, + } + h5 := &evmtypes.Head{ + Number: 5, + Parent: h4, + } + h6 := &evmtypes.Head{ + Number: 6, + Parent: h5, + } - c.AssertExpectations(t) - }) + ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + ht2.On("LatestChain").Return(h6) + ht.h = ht2 + + obs, err := ds.Observe(ctx, repts, true) + assert.NoError(t, err) + + assert.Len(t, obs.LatestBlocks, 3) + assert.Equal(t, 6, int(obs.LatestBlocks[0].Num)) + assert.Equal(t, 5, int(obs.LatestBlocks[1].Num)) + assert.Equal(t, 4, int(obs.LatestBlocks[2].Num)) + + ht2.AssertExpectations(t) + }) + t.Run("when chain is long enough", func(t *testing.T) { + h1 := &evmtypes.Head{ + Number: 1, + } + h2 := &evmtypes.Head{ + Number: 2, + Parent: h1, + } + h3 := &evmtypes.Head{ + Number: 3, + Parent: h2, + } + h4 := &evmtypes.Head{ + Number: 4, + Parent: h3, + } + h5 := &evmtypes.Head{ + Number: 5, + Parent: h4, + } + h6 := &evmtypes.Head{ + Number: 6, + Parent: h5, + } + + ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + ht2.On("LatestChain").Return(h6) + ht.h = ht2 + + obs, err := ds.Observe(ctx, repts, true) + assert.NoError(t, err) + + assert.Len(t, obs.LatestBlocks, 5) + assert.Equal(t, 6, int(obs.LatestBlocks[0].Num)) + assert.Equal(t, 5, int(obs.LatestBlocks[1].Num)) + assert.Equal(t, 4, int(obs.LatestBlocks[2].Num)) + assert.Equal(t, 3, int(obs.LatestBlocks[3].Num)) + assert.Equal(t, 2, int(obs.LatestBlocks[4].Num)) + + ht2.AssertExpectations(t) }) }) } -func TestMercury_SetCurrentBlock(t *testing.T) { +func TestMercury_SetLatestBlocks(t *testing.T) { lggr := logger.TestLogger(t) - ds := datasource{ - lggr: lggr, - } + ds := NewDataSource(nil, nil, job.Job{}, pipeline.Spec{}, lggr, nil, nil, nil, nil, nil, mercuryutils.FeedID{}) h := evmtypes.Head{ Number: testutils.NewRandomPositiveInt64(), @@ -390,64 +426,41 @@ func TestMercury_SetCurrentBlock(t *testing.T) { ds.chainHeadTracker = chainHeadTracker obs := relaymercuryv1.Observation{} - ds.setCurrentBlock(context.Background(), &obs) + ds.setLatestBlocks(context.Background(), &obs) assert.Equal(t, h.Number, obs.CurrentBlockNum.Val) assert.Equal(t, h.Hash.Bytes(), obs.CurrentBlockHash.Val) assert.Equal(t, uint64(h.Timestamp.Unix()), obs.CurrentBlockTimestamp.Val) - chainHeadTracker.AssertExpectations(t) - headTracker.AssertExpectations(t) - }) - - t.Run("if headtracker returns nil head and eth call succeeds", func(t *testing.T) { - ethClient := evmclimocks.NewClient(t) - headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - chainHeadTracker := mercurymocks.NewChainHeadTracker(t) - - chainHeadTracker.On("Client").Return(ethClient) - chainHeadTracker.On("HeadTracker").Return(headTracker) - // This can happen in some cases e.g. RPC node is offline - headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) - ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(&h, nil) - - ds.chainHeadTracker = chainHeadTracker - - obs := relaymercuryv1.Observation{} - ds.setCurrentBlock(context.Background(), &obs) - - assert.Equal(t, h.Number, obs.CurrentBlockNum.Val) - assert.Equal(t, h.Hash.Bytes(), obs.CurrentBlockHash.Val) - assert.Equal(t, uint64(h.Timestamp.Unix()), obs.CurrentBlockTimestamp.Val) + assert.Len(t, obs.LatestBlocks, 1) chainHeadTracker.AssertExpectations(t) - ethClient.AssertExpectations(t) headTracker.AssertExpectations(t) }) - t.Run("if headtracker returns nil head and eth call fails", func(t *testing.T) { - ethClient := evmclimocks.NewClient(t) + t.Run("if headtracker returns nil head", func(t *testing.T) { headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) chainHeadTracker := mercurymocks.NewChainHeadTracker(t) - chainHeadTracker.On("Client").Return(ethClient) chainHeadTracker.On("HeadTracker").Return(headTracker) // This can happen in some cases e.g. RPC node is offline headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) - err := errors.New("foo") - ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, err) ds.chainHeadTracker = chainHeadTracker obs := relaymercuryv1.Observation{} - ds.setCurrentBlock(context.Background(), &obs) + ds.setLatestBlocks(context.Background(), &obs) + + assert.Zero(t, obs.CurrentBlockNum.Val) + assert.Zero(t, obs.CurrentBlockHash.Val) + assert.Zero(t, obs.CurrentBlockTimestamp.Val) + assert.EqualError(t, obs.CurrentBlockNum.Err, "no blocks available") + assert.EqualError(t, obs.CurrentBlockHash.Err, "no blocks available") + assert.EqualError(t, obs.CurrentBlockTimestamp.Err, "no blocks available") - assert.Equal(t, err, obs.CurrentBlockNum.Err) - assert.Equal(t, err, obs.CurrentBlockHash.Err) - assert.Equal(t, err, obs.CurrentBlockTimestamp.Err) + assert.Len(t, obs.LatestBlocks, 0) chainHeadTracker.AssertExpectations(t) - ethClient.AssertExpectations(t) headTracker.AssertExpectations(t) }) } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b5b393542b..a9f9d080f4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -22,6 +22,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `Optimism2` as a supported gas estimator mode +### Added + +- Mercury v0.2 has improved consensus around current block that uses the most recent 5 blocks instead of only the latest one +- Two new prom metrics for mercury, nops should consider adding alerting on these: + - `mercury_insufficient_blocks_count` + - `mercury_zero_blocks_count` + ... ## 2.7.0 - UNRELEASED diff --git a/go.mod b/go.mod index 999c1b0402..f271bf421f 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.20231101160906-7acebcc1b353 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de 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-20231020123319-d255366a6545 diff --git a/go.sum b/go.sum index ee06cc9b75..8426876e23 100644 --- a/go.sum +++ b/go.sum @@ -1467,8 +1467,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 h1:59vz5H52EpwWE/64ZQpNCs7Gtnyi7/ytjyoGjlbKhBA= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de h1:CeVpn5xEdmuEsYE8ss2b7bSq9h3BY4OPvpqXeYIPnHw= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de/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 93820c6ebf..c4e6fd3848 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -388,7 +388,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de // 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 60805eae82..4744fc086a 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2370,8 +2370,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672 h1:59vz5H52EpwWE/64ZQpNCs7Gtnyi7/ytjyoGjlbKhBA= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231101203911-c686b4d48672/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de h1:CeVpn5xEdmuEsYE8ss2b7bSq9h3BY4OPvpqXeYIPnHw= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de/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= From b24af1367e5af984db6ebf8523e9949bad736516 Mon Sep 17 00:00:00 2001 From: Andrei Smirnov Date: Mon, 6 Nov 2023 18:13:43 +0300 Subject: [PATCH 076/327] Functions: fixed subscriptions tracking logic (#11167) * Functions: fixed subscriptions tracking logic * Addressed PR feedback * Addressed PR feedback * Addressed PR feedback --- .../handlers/functions/handler.functions.go | 12 ++++- .../handlers/functions/subscriptions.go | 22 ++++---- .../handlers/functions/subscriptions_test.go | 52 +++++++++++++++++-- 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index 01f450a4ea..d0011145d4 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "math/big" "time" "github.com/ethereum/go-ethereum/common" @@ -178,8 +179,15 @@ func (h *functionsHandler) HandleUserMessage(ctx context.Context, msg *api.Messa return ErrRateLimited } if h.subscriptions != nil && h.minimumBalance != nil { - if balance, err := h.subscriptions.GetMaxUserBalance(sender); err != nil || balance.Cmp(h.minimumBalance.ToInt()) < 0 { - h.lggr.Debug("received a message from a user having insufficient balance", "sender", msg.Body.Sender, "balance", balance.String()) + balance, err := h.subscriptions.GetMaxUserBalance(sender) + if err != nil { + h.lggr.Debugw("error getting max user balance", "sender", msg.Body.Sender, "err", err) + } + if balance == nil { + balance = big.NewInt(0) + } + if err != nil || balance.Cmp(h.minimumBalance.ToInt()) < 0 { + h.lggr.Debugw("received a message from a user having insufficient balance", "sender", msg.Body.Sender, "balance", balance.String()) return fmt.Errorf("sender has insufficient balance: %v juels", balance.String()) } } diff --git a/core/services/gateway/handlers/functions/subscriptions.go b/core/services/gateway/handlers/functions/subscriptions.go index 79233b1031..c7a6519e69 100644 --- a/core/services/gateway/handlers/functions/subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions.go @@ -130,19 +130,16 @@ func (s *onchainSubscriptions) queryLoop() { blockNumber := big.NewInt(0).Sub(latestBlockHeight, s.blockConfirmations) - updateLastKnownCount := func() { + if lastKnownCount == 0 || start > lastKnownCount { count, err := s.getSubscriptionsCount(ctx, blockNumber) if err != nil { - s.lggr.Errorw("Error getting subscriptions count", "err", err) - return + s.lggr.Errorw("Error getting new subscriptions count", "err", err) + } else { + s.lggr.Infow("Updated subscriptions count", "count", count, "blockNumber", blockNumber.Int64()) + lastKnownCount = count } - s.lggr.Infow("Updated subscriptions count", "err", err, "count", count, "blockNumber", blockNumber.Int64()) - lastKnownCount = count } - if lastKnownCount == 0 { - updateLastKnownCount() - } if lastKnownCount == 0 { s.lggr.Info("Router has no subscriptions yet") return @@ -152,12 +149,9 @@ func (s *onchainSubscriptions) queryLoop() { start = 1 } - end := start + uint64(s.config.UpdateRangeSize) + end := start + uint64(s.config.UpdateRangeSize) - 1 if end > lastKnownCount { - updateLastKnownCount() - if end > lastKnownCount { - end = lastKnownCount - } + end = lastKnownCount } if err := s.querySubscriptionsRange(ctx, blockNumber, start, end); err != nil { s.lggr.Errorw("Error querying subscriptions", "err", err, "start", start, "end", end) @@ -180,6 +174,8 @@ func (s *onchainSubscriptions) queryLoop() { } func (s *onchainSubscriptions) querySubscriptionsRange(ctx context.Context, blockNumber *big.Int, start, end uint64) error { + s.lggr.Debugw("Querying subscriptions", "blockNumber", blockNumber, "start", start, "end", end) + subscriptions, err := s.router.GetSubscriptionsInRange(&bind.CallOpts{ Pending: false, BlockNumber: blockNumber, diff --git a/core/services/gateway/handlers/functions/subscriptions_test.go b/core/services/gateway/handlers/functions/subscriptions_test.go index 1e46bff5c0..adbf637ad7 100644 --- a/core/services/gateway/handlers/functions/subscriptions_test.go +++ b/core/services/gateway/handlers/functions/subscriptions_test.go @@ -2,6 +2,7 @@ package functions_test import ( "math/big" + "sync/atomic" "testing" "time" @@ -24,9 +25,7 @@ const ( invalidUser = "0x6E2dc0F9DB014aE19888F539E59285D2Ea04244C" ) -func TestSubscriptions(t *testing.T) { - t.Parallel() - +func TestSubscriptions_OnePass(t *testing.T) { getSubscriptionCount := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000003") getSubscriptionsInRange := hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000109e6e1b12098cc8f3a1e9719a817ec53ab9b35c000000000000000000000000000000000000000000000000000034e23f515cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f5340f0968ee8b7dfd97e3327a6139273cc2c4fa000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc14b92364c75e20000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005439e5881a529f3ccbffc0e82d49f9db3950aefe") @@ -46,7 +45,7 @@ func TestSubscriptions(t *testing.T) { BlockConfirmations: 1, UpdateFrequencySec: 1, UpdateTimeoutSec: 1, - UpdateRangeSize: 10, + UpdateRangeSize: 3, } subscriptions, err := functions.NewOnchainSubscriptions(client, config, logger.TestLogger(t)) require.NoError(t, err) @@ -57,6 +56,7 @@ func TestSubscriptions(t *testing.T) { assert.NoError(t, subscriptions.Close()) }) + // initially we have 3 subs and range is 3, which needs one pass gomega.NewGomegaWithT(t).Eventually(func() bool { expectedBalance := big.NewInt(0).SetBytes(hexutil.MustDecode("0x01158e460913d00000")) balance, err1 := subscriptions.GetMaxUserBalance(common.HexToAddress(validUser)) @@ -64,3 +64,47 @@ func TestSubscriptions(t *testing.T) { return err1 == nil && err2 != nil && balance.Cmp(expectedBalance) == 0 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) } + +func TestSubscriptions_MultiPass(t *testing.T) { + const ncycles int32 = 5 + var currentCycle atomic.Int32 + getSubscriptionCount := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000006") + getSubscriptionsInRange := hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000109e6e1b12098cc8f3a1e9719a817ec53ab9b35c000000000000000000000000000000000000000000000000000034e23f515cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f5340f0968ee8b7dfd97e3327a6139273cc2c4fa000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc14b92364c75e20000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005439e5881a529f3ccbffc0e82d49f9db3950aefe") + + ctx := testutils.Context(t) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, ethereum.CallMsg{ // getSubscriptionCount + To: &common.Address{}, + Data: hexutil.MustDecode("0x66419970"), + }, mock.Anything).Run(func(args mock.Arguments) { + currentCycle.Add(1) + }).Return(getSubscriptionCount, nil) + client.On("CallContract", mock.Anything, ethereum.CallMsg{ // GetSubscriptionsInRange(1,3) + To: &common.Address{}, + Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003"), + }, mock.Anything).Return(getSubscriptionsInRange, nil) + client.On("CallContract", mock.Anything, ethereum.CallMsg{ // GetSubscriptionsInRange(4,6) + To: &common.Address{}, + Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006"), + }, mock.Anything).Return(getSubscriptionsInRange, nil) + config := functions.OnchainSubscriptionsConfig{ + ContractAddress: common.Address{}, + BlockConfirmations: 1, + UpdateFrequencySec: 1, + UpdateTimeoutSec: 1, + UpdateRangeSize: 3, + } + subscriptions, err := functions.NewOnchainSubscriptions(client, config, logger.TestLogger(t)) + require.NoError(t, err) + + err = subscriptions.Start(ctx) + require.NoError(t, err) + t.Cleanup(func() { + assert.NoError(t, subscriptions.Close()) + }) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + return currentCycle.Load() == ncycles + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) +} From a7572683ba10864d98fd1d7cffd27889908d8e22 Mon Sep 17 00:00:00 2001 From: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> Date: Mon, 6 Nov 2023 17:56:59 +0000 Subject: [PATCH 077/327] Update hardhat config for ArbSepolia and V2_5 (#11177) * Update hardhat config for ArbSepolia and V2_5 * Prettier fix * Minor fix --- contracts/hardhat.config.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index 521345ffc9..5306827b8e 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -105,6 +105,18 @@ let config = { }, }, }, + 'src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol': { + version: '0.8.6', + settings: { + optimizer: { + enabled: true, + runs: 50, // see native_solc_compile_all_vrf + }, + metadata: { + bytecodeHash: 'none', + }, + }, + }, }, }, contractSizer: { From bda4d5aba0cada85b4dceca88415718d3afd70a8 Mon Sep 17 00:00:00 2001 From: Kashif Date: Tue, 7 Nov 2023 03:13:11 +0900 Subject: [PATCH 078/327] Add kroma support (#11179) * Add kroma support * Bump ctf for kroma client support * add kroma l1 gas test --- .github/workflows/on-demand-ocr-soak-test.yml | 2 + .../config/toml/defaults/Kroma_Mainnet.toml | 26 +++ .../config/toml/defaults/Kroma_Sepolia.toml | 26 +++ core/chains/evm/gas/chain_specific.go | 2 +- .../evm/gas/rollups/l1_gas_price_oracle.go | 12 +- .../gas/rollups/l1_gas_price_oracle_test.go | 22 +++ core/config/chaintype.go | 4 +- core/config/docs/chains-evm.toml | 2 +- core/services/chainlink/config_test.go | 4 +- core/services/ocr/contract_tracker.go | 2 +- docs/CONFIG.md | 160 +++++++++++++++++- .../contracts/contract_deployer.go | 6 + integration-tests/go.mod | 4 +- integration-tests/go.sum | 6 +- 14 files changed, 263 insertions(+), 15 deletions(-) create mode 100644 core/chains/evm/config/toml/defaults/Kroma_Mainnet.toml create mode 100644 core/chains/evm/config/toml/defaults/Kroma_Sepolia.toml diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 4a18aabf22..1e510c23be 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -26,6 +26,8 @@ on: - "LINEA_MAINNET" - "FANTOM_TESTNET" - "FANTOM_MAINNET" + - "KROMA_MAINNET" + - "KROMA_SEPOLIA" fundingPrivateKey: description: Private funding key (Skip for Simulated) required: false diff --git a/core/chains/evm/config/toml/defaults/Kroma_Mainnet.toml b/core/chains/evm/config/toml/defaults/Kroma_Mainnet.toml new file mode 100644 index 0000000000..55154bf766 --- /dev/null +++ b/core/chains/evm/config/toml/defaults/Kroma_Mainnet.toml @@ -0,0 +1,26 @@ +ChainID = '255' +ChainType = 'kroma' # Kroma is based on the Optimism Bedrock architechture +FinalityDepth = 400 +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 400 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 diff --git a/core/chains/evm/config/toml/defaults/Kroma_Sepolia.toml b/core/chains/evm/config/toml/defaults/Kroma_Sepolia.toml new file mode 100644 index 0000000000..643b0556b3 --- /dev/null +++ b/core/chains/evm/config/toml/defaults/Kroma_Sepolia.toml @@ -0,0 +1,26 @@ +ChainID = '2358' +ChainType = 'kroma' # Kroma is based on the Optimism Bedrock architechture +FinalityDepth = 400 +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 400 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 diff --git a/core/chains/evm/gas/chain_specific.go b/core/chains/evm/gas/chain_specific.go index cd38f49ee0..4d87b8b454 100644 --- a/core/chains/evm/gas/chain_specific.go +++ b/core/chains/evm/gas/chain_specific.go @@ -19,7 +19,7 @@ func chainSpecificIsUsable(tx evmtypes.Transaction, baseFee *assets.Wei, chainTy return false } } - if chainType == config.ChainOptimismBedrock { + if chainType == config.ChainOptimismBedrock || chainType == config.ChainKroma { // This is a special deposit transaction type introduced in Bedrock upgrade. // This is a system transaction that it will occur at least one time per block. // We should discard this type before even processing it to avoid flooding the diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index c15aa23c79..d990017bd0 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -57,11 +57,18 @@ const ( // `function l1BaseFee() external view returns (uint256);` OPGasOracle_l1BaseFee = "519b4bd3" + // GasOracleAddress is the address of the precompiled contract that exists on Kroma chain. + // This is the case for Kroma. + KromaGasOracleAddress = "0x4200000000000000000000000000000000000005" + // GasOracle_l1BaseFee is the a hex encoded call to: + // `function l1BaseFee() external view returns (uint256);` + KromaGasOracle_l1BaseFee = "519b4bd3" + // Interval at which to poll for L1BaseFee. A good starting point is the L1 block time. PollPeriod = 12 * time.Second ) -var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock} +var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock, config.ChainKroma} func IsRollupWithL1Support(chainType config.ChainType) bool { return slices.Contains(supportedChainTypes, chainType) @@ -76,6 +83,9 @@ func NewL1GasPriceOracle(lggr logger.Logger, ethClient ethClient, chainType conf case config.ChainOptimismBedrock: address = OPGasOracleAddress callArgs = OPGasOracle_l1BaseFee + case config.ChainKroma: + address = KromaGasOracleAddress + callArgs = KromaGasOracle_l1BaseFee default: panic(fmt.Sprintf("Received unspported chaintype %s", chainType)) } diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go index 9fd2a66201..320c9cb71d 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go @@ -59,6 +59,28 @@ func TestL1GasPriceOracle(t *testing.T) { assert.Equal(t, assets.NewWei(l1BaseFee), gasPrice) }) + t.Run("Calling GasPrice on started Kroma L1Oracle returns Kroma l1GasPrice", func(t *testing.T) { + l1BaseFee := big.NewInt(200) + + ethClient := mocks.NewETHClient(t) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + assert.Equal(t, KromaGasOracleAddress, callMsg.To.String()) + assert.Equal(t, KromaGasOracle_l1BaseFee, fmt.Sprintf("%x", callMsg.Data)) + assert.Nil(t, blockNumber) + }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) + + oracle := NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainKroma) + require.NoError(t, oracle.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + + gasPrice, err := oracle.GasPrice(testutils.Context(t)) + require.NoError(t, err) + + assert.Equal(t, assets.NewWei(l1BaseFee), gasPrice) + }) + t.Run("Calling GasPrice on started OPStack L1Oracle returns OPStack l1GasPrice", func(t *testing.T) { l1BaseFee := big.NewInt(200) diff --git a/core/config/chaintype.go b/core/config/chaintype.go index fe67b0925a..c99099ee61 100644 --- a/core/config/chaintype.go +++ b/core/config/chaintype.go @@ -15,16 +15,18 @@ const ( ChainOptimismBedrock ChainType = "optimismBedrock" ChainXDai ChainType = "xdai" ChainCelo ChainType = "celo" + ChainKroma ChainType = "kroma" ) var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{ string(ChainArbitrum), string(ChainMetis), string(ChainXDai), string(ChainOptimismBedrock), string(ChainCelo), + string(ChainKroma), }, ", ")) // IsValid returns true if the ChainType value is known or empty. func (c ChainType) IsValid() bool { switch c { - case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo: + case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma: return true } return false diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index 0e0d0d0bd8..082bbd6cd1 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -14,7 +14,7 @@ BlockBackfillDepth = 10 # Default # BlockBackfillSkip enables skipping of very long backfills. BlockBackfillSkip = false # Default # ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -# Available types: arbitrum, metis, optimismBedrock, xdai +# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma ChainType = 'arbitrum' # Example # FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID so it should not be necessary to change this under normal operation. # BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 96e6db42c8..59a02f1dcf 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -1190,7 +1190,7 @@ func TestConfig_Validate(t *testing.T) { - 1: 6 errors: - ChainType: invalid value (Foo): must not be set with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo or omitted + - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma or omitted - HeadTracker.HistoryDepth: invalid value (30): must be equal to or greater than FinalityDepth - GasEstimator: 2 errors: - FeeCapDefault: invalid value (101 wei): must be equal to PriceMax (99 wei) since you are using FixedPrice estimation with gas bumping disabled in EIP1559 mode - PriceMax will be used as the FeeCap for transactions instead of FeeCapDefault @@ -1199,7 +1199,7 @@ func TestConfig_Validate(t *testing.T) { - 2: 5 errors: - ChainType: invalid value (Arbitrum): only "optimismBedrock" can be used with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo or omitted + - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma or omitted - FinalityDepth: invalid value (0): must be greater than or equal to 1 - MinIncomingConfirmations: invalid value (0): must be greater than or equal to 1 - 3.Nodes: 5 errors: diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index c5f3e431e4..3a216e025f 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -401,7 +401,7 @@ func (t *OCRContractTracker) LatestBlockHeight(ctx context.Context) (blockheight // care about the block height; we have no way of getting the L1 block // height anyway return 0, nil - case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai: + case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma: // continue } latestBlockHeight := t.getLatestBlockHeight() diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 23508df172..4b55c804a3 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -2907,6 +2907,85 @@ GasLimit = 3800000

+
Kroma Mainnet (255)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'kroma' +FinalityDepth = 400 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '2s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '40s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '30s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '1 wei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '100 wei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = true +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 24 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 400 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 10 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 1 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+
Optimism Goerli (420)

```toml @@ -3301,6 +3380,85 @@ GasLimit = 5300000

+
Kroma Sepolia (2358)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'kroma' +FinalityDepth = 400 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '2s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '40s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '30s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '1 wei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '100 wei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = true +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 24 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 400 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 10 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 1 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+
Fantom Testnet (4002)

```toml @@ -4916,7 +5074,7 @@ BlockBackfillSkip enables skipping of very long backfills. ChainType = 'arbitrum' # Example ``` ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -Available types: arbitrum, metis, optimismBedrock, xdai +Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma ### FinalityDepth ```toml diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 5a3fad256e..0c36a26081 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -173,6 +173,8 @@ func NewContractDeployer(bcClient blockchain.EVMClient, logger zerolog.Logger) ( return &LineaContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.FantomClient: return &FantomContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil + case *blockchain.KromaClient: + return &KromaContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract deployer, register blockchain client in NewContractDeployer") } @@ -240,6 +242,10 @@ type FantomContractDeployer struct { *EthereumContractDeployer } +type KromaContractDeployer struct { + *EthereumContractDeployer +} + // NewEthereumContractDeployer returns an instantiated instance of the ETH contract deployer func NewEthereumContractDeployer(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractDeployer { return &EthereumContractDeployer{ diff --git a/integration-tests/go.mod b/integration-tests/go.mod index c4e6fd3848..f73838f1ab 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,7 +22,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.2-0.20231030212542-5fb562e774a5 + github.com/smartcontractkit/chainlink-testing-framework v1.18.4-0.20231106173929-20fe04d6ad66 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 @@ -427,7 +427,6 @@ require ( github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.1.0 // indirect - github.com/yuin/goldmark v1.4.13 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect @@ -455,7 +454,6 @@ require ( golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 4744fc086a..843cef2690 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2376,8 +2376,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.2-0.20231030212542-5fb562e774a5 h1:4hTf8pvtdtwoaeKFSEYjBZPvDbZ05WgiHsb0TPL6HqQ= -github.com/smartcontractkit/chainlink-testing-framework v1.18.2-0.20231030212542-5fb562e774a5/go.mod h1:lMdEUTdSmzldCwqf+todFEyebE9Vlb23+5rvIHJBPOk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.4-0.20231106173929-20fe04d6ad66 h1:AOqcHiAppMoIvM2WSJNIZzJDnOQNXyElbLFK3ZqoJeM= +github.com/smartcontractkit/chainlink-testing-framework v1.18.4-0.20231106173929-20fe04d6ad66/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= @@ -2578,7 +2578,6 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -2765,7 +2764,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= From 0f66f7fd324fb0b8ecef07989eee7dd55bdcdf32 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Mon, 6 Nov 2023 20:28:52 +0200 Subject: [PATCH 079/327] Move common client models to correct path (#11169) * Move common client models to correct path * Drop unnecessary aliases --- common/{chains => }/client/models.go | 0 common/client/multi_node.go | 7 +- common/client/node.go | 5 +- common/client/send_only_node.go | 3 +- common/txmgr/broadcaster.go | 24 +++--- common/txmgr/confirmer.go | 20 ++--- common/txmgr/resender.go | 8 +- common/txmgr/types/client.go | 6 +- core/chains/evm/client/chain_client.go | 3 +- core/chains/evm/client/client.go | 6 +- core/chains/evm/client/client_test.go | 57 +++++++------ core/chains/evm/client/errors.go | 38 ++++----- core/chains/evm/client/helpers_test.go | 5 +- core/chains/evm/client/mocks/client.go | 14 ++-- core/chains/evm/client/null_client.go | 6 +- core/chains/evm/client/rpc_client.go | 5 +- .../evm/client/simulated_backend_client.go | 10 +-- core/chains/evm/txmgr/broadcaster_test.go | 82 +++++++++--------- core/chains/evm/txmgr/client.go | 20 ++--- core/chains/evm/txmgr/confirmer_test.go | 84 +++++++++---------- core/cmd/shell_local_test.go | 24 +++--- core/internal/cltest/cltest.go | 4 +- 22 files changed, 212 insertions(+), 219 deletions(-) rename common/{chains => }/client/models.go (100%) diff --git a/common/chains/client/models.go b/common/client/models.go similarity index 100% rename from common/chains/client/models.go rename to common/client/models.go diff --git a/common/client/multi_node.go b/common/client/multi_node.go index 0da3b89076..f54e3115d9 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/common/chains/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -121,7 +120,7 @@ type multiNode[ chStop utils.StopChan wg sync.WaitGroup - sendOnlyErrorParser func(err error) client.SendTxReturnCode + sendOnlyErrorParser func(err error) SendTxReturnCode } func NewMultiNode[ @@ -147,7 +146,7 @@ func NewMultiNode[ chainID CHAIN_ID, chainType config.ChainType, chainFamily string, - sendOnlyErrorParser func(err error) client.SendTxReturnCode, + 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 { @@ -605,7 +604,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP txErr := n.RPC().SendTransaction(ctx, tx) c.logger.Debugw("Sendonly node sent transaction", "name", n.String(), "tx", tx, "err", txErr) sendOnlyError := c.sendOnlyErrorParser(txErr) - if sendOnlyError != client.Successful { + if sendOnlyError != Successful { c.logger.Warnw("RPC returned error", "name", n.String(), "tx", tx, "err", txErr) } }(n) diff --git a/common/client/node.go b/common/client/node.go index 71b34452f0..20d098e03f 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/common/chains/client" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -136,7 +135,7 @@ func NewNode[ } n.nodeCtx, n.cancelNodeCtx = context.WithCancel(context.Background()) lggr = lggr.Named("Node").With( - "nodeTier", client.Primary.String(), + "nodeTier", Primary.String(), "nodeName", name, "node", n.String(), "chainID", chainID, @@ -150,7 +149,7 @@ func NewNode[ } func (n *node[CHAIN_ID, HEAD, RPC]) String() string { - s := fmt.Sprintf("(%s)%s:%s", client.Primary.String(), n.name, n.ws.String()) + s := fmt.Sprintf("(%s)%s:%s", Primary.String(), n.name, n.ws.String()) if n.http != nil { s = s + fmt.Sprintf(":%s", n.http.String()) } diff --git a/common/client/send_only_node.go b/common/client/send_only_node.go index 3b382b2dcb..0051fb014d 100644 --- a/common/client/send_only_node.go +++ b/common/client/send_only_node.go @@ -8,7 +8,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/common/chains/client" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -159,7 +158,7 @@ func (s *sendOnlyNode[CHAIN_ID, RPC]) RPC() RPC { } func (s *sendOnlyNode[CHAIN_ID, RPC]) String() string { - return fmt.Sprintf("(%s)%s:%s", client.Secondary.String(), s.name, s.uri.Redacted()) + return fmt.Sprintf("(%s)%s:%s", Secondary.String(), s.name, s.uri.Redacted()) } func (s *sendOnlyNode[CHAIN_ID, RPC]) setState(state nodeState) (changed bool) { diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 4f6ffae2ad..80c7adbfc1 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -15,7 +15,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-relay/pkg/services" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" @@ -553,19 +553,19 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand lgr.Infow("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "err", err, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt, "etx", etx) errType, err := eb.client.SendTransactionReturnCode(ctx, etx, attempt, lgr) - if errType != clienttypes.Fatal { + if errType != client.Fatal { etx.InitialBroadcastAt = &initialBroadcastAt etx.BroadcastAt = &initialBroadcastAt } switch errType { - case clienttypes.Fatal: + case client.Fatal: eb.SvcErrBuffer.Append(err) etx.Error = null.StringFrom(err.Error()) return eb.saveFatallyErroredTransaction(lgr, &etx), true - case clienttypes.TransactionAlreadyKnown: + case client.TransactionAlreadyKnown: fallthrough - case clienttypes.Successful: + case client.Successful: // Either the transaction was successful or one of the following four scenarios happened: // // SCENARIO 1 @@ -618,9 +618,9 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // Increment sequence if successfully broadcasted eb.IncrementNextSequence(etx.FromAddress, sequence) return err, true - case clienttypes.Underpriced: + case client.Underpriced: return eb.tryAgainBumpingGas(ctx, lgr, err, etx, attempt, initialBroadcastAt) - case clienttypes.InsufficientFunds: + case client.InsufficientFunds: // NOTE: This bails out of the entire cycle and essentially "blocks" on // any transaction that gets insufficient_funds. This is OK if a // transaction with a large VALUE blocks because this always comes last @@ -630,13 +630,13 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // theoretically be sent, but will instead be blocked. eb.SvcErrBuffer.Append(err) fallthrough - case clienttypes.Retryable: + case client.Retryable: return err, true - case clienttypes.FeeOutOfValidRange: + case client.FeeOutOfValidRange: return eb.tryAgainWithNewEstimation(ctx, lgr, err, etx, attempt, initialBroadcastAt) - case clienttypes.Unsupported: + case client.Unsupported: return err, false - case clienttypes.ExceedsMaxFee: + case client.ExceedsMaxFee: // Broadcaster: Note that we may have broadcast to multiple nodes and had it // accepted by one of them! It is not guaranteed that all nodes share // the same tx fee cap. That is why we must treat this as an unknown @@ -649,7 +649,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand default: // Every error that doesn't fall under one of the above categories will be treated as Unknown. fallthrough - case clienttypes.Unknown: + case client.Unknown: eb.SvcErrBuffer.Append(err) lgr.Criticalw(`Unknown error occurred while handling tx queue in ProcessUnstartedTxs. This chain/RPC client may not be supported. `+ `Urgent resolution required, Chainlink is currently operating in a degraded state and may miss transactions`, "err", err, "etx", etx, "attempt", attempt) diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index c22a159457..1d92149094 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -15,7 +15,7 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-relay/pkg/services" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -362,7 +362,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che for idx, txErr := range txErrs { // Add to Unconfirm array, all tx where error wasn't TransactionAlreadyKnown. if txErr != nil { - if txCodes[idx] == clienttypes.TransactionAlreadyKnown { + if txCodes[idx] == client.TransactionAlreadyKnown { continue } } @@ -819,7 +819,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han errType, sendError := ec.client.SendTransactionReturnCode(ctx, etx, attempt, lggr) switch errType { - case clienttypes.Underpriced: + case client.Underpriced: // This should really not ever happen in normal operation since we // already bumped above the required minimum in broadcaster. ec.lggr.Warnw("Got terminally underpriced error for gas bump, this should never happen unless the remote RPC node changed its configuration on the fly, or you are using multiple RPC nodes with different minimum gas price requirements. This is not recommended", "err", sendError, "attempt", attempt) @@ -854,12 +854,12 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han return errors.Wrap(err, "saveReplacementInProgressAttempt failed") } return ec.handleInProgressAttempt(ctx, lggr, etx, replacementAttempt, blockHeight) - case clienttypes.ExceedsMaxFee: + case client.ExceedsMaxFee: // Confirmer: The gas price was bumped too high. This transaction attempt cannot be accepted. // Best thing we can do is to re-send the previous attempt at the old // price and discard this bumped version. fallthrough - case clienttypes.Fatal: + case client.Fatal: // WARNING: This should never happen! // Should NEVER be fatal this is an invariant violation. The // Broadcaster can never create a TxAttempt that will @@ -874,20 +874,20 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han ec.SvcErrBuffer.Append(sendError) // This will loop continuously on every new head so it must be handled manually by the node operator! return ec.txStore.DeleteInProgressAttempt(ctx, attempt) - case clienttypes.TransactionAlreadyKnown: + case client.TransactionAlreadyKnown: // Sequence too low indicated that a transaction at this sequence was confirmed already. // Mark confirmed_missing_receipt and wait for the next cycle to try to get a receipt lggr.Debugw("Sequence already used", "txAttemptID", attempt.ID, "txHash", attempt.Hash.String(), "err", sendError) timeout := ec.dbConfig.DefaultQueryTimeout() return ec.txStore.SaveConfirmedMissingReceiptAttempt(ctx, timeout, &attempt, now) - case clienttypes.InsufficientFunds: + case client.InsufficientFunds: timeout := ec.dbConfig.DefaultQueryTimeout() return ec.txStore.SaveInsufficientFundsAttempt(ctx, timeout, &attempt, now) - case clienttypes.Successful: + case client.Successful: lggr.Debugw("Successfully broadcast transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash.String()) timeout := ec.dbConfig.DefaultQueryTimeout() return ec.txStore.SaveSentAttempt(ctx, timeout, &attempt, now) - case clienttypes.Unknown: + case client.Unknown: // Every error that doesn't fall under one of the above categories will be treated as Unknown. fallthrough default: @@ -1058,7 +1058,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For } attempt.Tx = *etx // for logging ec.lggr.Debugw("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "err", err, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt) - if errCode, err := ec.client.SendTransactionReturnCode(context.TODO(), *etx, attempt, ec.lggr); errCode != clienttypes.Successful && err != nil { + if errCode, err := ec.client.SendTransactionReturnCode(context.TODO(), *etx, attempt, ec.lggr); errCode != client.Successful && err != nil { ec.lggr.Errorw(fmt.Sprintf("ForceRebroadcast: failed to rebroadcast tx %v with sequence %v and gas limit %v: %s", etx.ID, *etx.Sequence, etx.FeeLimit, err.Error()), "err", err, "fee", attempt.TxFee) continue } diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 655de0f113..d788b82773 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" @@ -175,13 +175,13 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) resendUnconfi return nil } -func logResendResult(lggr logger.Logger, codes []clienttypes.SendTxReturnCode) { +func logResendResult(lggr logger.Logger, codes []client.SendTxReturnCode) { var nNew int var nFatal int for _, c := range codes { - if c == clienttypes.Successful { + if c == client.Successful { nNew++ - } else if c == clienttypes.Fatal { + } else if c == client.Fatal { nFatal++ } } diff --git a/common/txmgr/types/client.go b/common/txmgr/types/client.go index 6d7f1c5555..58c1b6f6ad 100644 --- a/common/txmgr/types/client.go +++ b/common/txmgr/types/client.go @@ -6,7 +6,7 @@ import ( "math/big" "time" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -49,7 +49,7 @@ type TransactionClient[ bathSize int, lggr logger.Logger, ) ( - txCodes []clienttypes.SendTxReturnCode, + txCodes []client.SendTxReturnCode, txErrs []error, broadcastTime time.Time, successfulTxIDs []int64, @@ -59,7 +59,7 @@ type TransactionClient[ tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], lggr logger.Logger, - ) (clienttypes.SendTxReturnCode, error) + ) (client.SendTxReturnCode, error) SendEmptyTransaction( ctx context.Context, newTxAttempt func(seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error), diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index bda028cbf3..4c5108745c 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - commontypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -213,7 +212,7 @@ func (c *chainClient) SendTransaction(ctx context.Context, tx *types.Transaction return c.multiNode.SendTransaction(ctx, tx) } -func (c *chainClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commontypes.SendTxReturnCode, error) { +func (c *chainClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { err := c.SendTransaction(ctx, tx) return ClassifySendError(err, c.logger, tx, fromAddress, c.IsL2()) } diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index af03720ced..fb8a39f379 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -6,7 +6,7 @@ import ( "strings" "time" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -61,7 +61,7 @@ type Client interface { HeadByHash(ctx context.Context, n common.Hash) (*evmtypes.Head, error) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head) (ethereum.Subscription, error) - SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (clienttypes.SendTxReturnCode, error) + SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) // Wrapped Geth client methods // blockNumber can be specified as `nil` to imply latest block @@ -211,7 +211,7 @@ func (client *client) HeaderByHash(ctx context.Context, h common.Hash) (*types.H return client.pool.HeaderByHash(ctx, h) } -func (client *client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (clienttypes.SendTxReturnCode, error) { +func (client *client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { err := client.SendTransaction(ctx, tx) return ClassifySendError(err, client.logger, tx, fromAddress, client.pool.ChainType().IsL2()) } diff --git a/core/chains/evm/client/client_test.go b/core/chains/evm/client/client_test.go index 81a82d20fa..673fe044af 100644 --- a/core/chains/evm/client/client_test.go +++ b/core/chains/evm/client/client_test.go @@ -24,49 +24,48 @@ import ( commonclient "github.com/smartcontractkit/chainlink/v2/common/client" - commontypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func mustNewClient(t *testing.T, wsURL string, sendonlys ...url.URL) evmclient.Client { +func mustNewClient(t *testing.T, wsURL string, sendonlys ...url.URL) client.Client { return mustNewClientWithChainID(t, wsURL, testutils.FixtureChainID, sendonlys...) } -func mustNewClientWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) evmclient.Client { - cfg := evmclient.TestNodePoolConfig{ - NodeSelectionMode: evmclient.NodeSelectionMode_RoundRobin, +func mustNewClientWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) client.Client { + cfg := client.TestNodePoolConfig{ + NodeSelectionMode: client.NodeSelectionMode_RoundRobin, } - c, err := evmclient.NewClientWithTestNode(t, cfg, time.Second*0, wsURL, nil, sendonlys, 42, chainID) + c, err := client.NewClientWithTestNode(t, cfg, time.Second*0, wsURL, nil, sendonlys, 42, chainID) require.NoError(t, err) return c } -func mustNewChainClient(t *testing.T, wsURL string, sendonlys ...url.URL) evmclient.Client { +func mustNewChainClient(t *testing.T, wsURL string, sendonlys ...url.URL) client.Client { return mustNewChainClientWithChainID(t, wsURL, testutils.FixtureChainID, sendonlys...) } -func mustNewChainClientWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) evmclient.Client { - cfg := evmclient.TestNodePoolConfig{ - NodeSelectionMode: evmclient.NodeSelectionMode_RoundRobin, +func mustNewChainClientWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) client.Client { + cfg := client.TestNodePoolConfig{ + NodeSelectionMode: client.NodeSelectionMode_RoundRobin, } - c, err := evmclient.NewChainClientWithTestNode(t, cfg, time.Second*0, cfg.NodeLeaseDuration, wsURL, nil, sendonlys, 42, chainID) + c, err := client.NewChainClientWithTestNode(t, cfg, time.Second*0, cfg.NodeLeaseDuration, wsURL, nil, sendonlys, 42, chainID) require.NoError(t, err) return c } -func mustNewClients(t *testing.T, wsURL string, sendonlys ...url.URL) []evmclient.Client { - var clients []evmclient.Client +func mustNewClients(t *testing.T, wsURL string, sendonlys ...url.URL) []client.Client { + var clients []client.Client clients = append(clients, mustNewClient(t, wsURL, sendonlys...)) clients = append(clients, mustNewChainClient(t, wsURL, sendonlys...)) return clients } -func mustNewClientsWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) []evmclient.Client { - var clients []evmclient.Client +func mustNewClientsWithChainID(t *testing.T, wsURL string, chainID *big.Int, sendonlys ...url.URL) []client.Client { + var clients []client.Client clients = append(clients, mustNewClientWithChainID(t, wsURL, chainID, sendonlys...)) clients = append(clients, mustNewChainClientWithChainID(t, wsURL, chainID, sendonlys...)) return clients @@ -287,7 +286,7 @@ func TestEthClient_GetERC20Balance(t *testing.T) { t.Run(test.name, func(t *testing.T) { contractAddress := testutils.NewAddress() userAddress := testutils.NewAddress() - functionSelector := evmtypes.HexToFunctionSelector(evmclient.BALANCE_OF_ADDRESS_FUNCTION_SELECTOR) // balanceOf(address) + functionSelector := evmtypes.HexToFunctionSelector(client.BALANCE_OF_ADDRESS_FUNCTION_SELECTOR) // balanceOf(address) txData := utils.ConcatBytes(functionSelector.Bytes(), common.LeftPadBytes(userAddress.Bytes(), utils.EVMWordByteLen)) wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { @@ -522,7 +521,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.Fatal) + assert.Equal(t, errType, commonclient.Fatal) } }) @@ -550,7 +549,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.TransactionAlreadyKnown) + assert.Equal(t, errType, commonclient.TransactionAlreadyKnown) } }) @@ -577,7 +576,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.NoError(t, err) - assert.Equal(t, errType, commontypes.Successful) + assert.Equal(t, errType, commonclient.Successful) } }) @@ -605,7 +604,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.Underpriced) + assert.Equal(t, errType, commonclient.Underpriced) } }) @@ -633,7 +632,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.Unsupported) + assert.Equal(t, errType, commonclient.Unsupported) } }) @@ -661,7 +660,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.Retryable) + assert.Equal(t, errType, commonclient.Retryable) } }) @@ -689,7 +688,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.InsufficientFunds) + assert.Equal(t, errType, commonclient.InsufficientFunds) } }) @@ -717,7 +716,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.ExceedsMaxFee) + assert.Equal(t, errType, commonclient.ExceedsMaxFee) } }) @@ -745,7 +744,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { errType, err := ethClient.SendTransactionReturnCode(testutils.Context(t), tx, fromAddress) assert.Error(t, err) - assert.Equal(t, errType, commontypes.Unknown) + assert.Equal(t, errType, commonclient.Unknown) } }) } @@ -811,7 +810,7 @@ func TestEthClient_ErroringClient(t *testing.T) { ctx := testutils.Context(t) // Empty node means there are no active nodes to select from, causing client to always return error. - erroringClient := evmclient.NewChainClientWithEmptyNode(t, commonclient.NodeSelectionModeRoundRobin, time.Second*0, time.Second*0, testutils.FixtureChainID) + erroringClient := client.NewChainClientWithEmptyNode(t, commonclient.NodeSelectionModeRoundRobin, time.Second*0, time.Second*0, testutils.FixtureChainID) _, err := erroringClient.BalanceAt(ctx, common.Address{}, nil) require.Equal(t, err, commonclient.ErroringNodeError) @@ -883,7 +882,7 @@ func TestEthClient_ErroringClient(t *testing.T) { require.Equal(t, err, commonclient.ErroringNodeError) code, err := erroringClient.SendTransactionReturnCode(ctx, nil, common.Address{}) - require.Equal(t, code, commontypes.Unknown) + require.Equal(t, code, commonclient.Unknown) require.Equal(t, err, commonclient.ErroringNodeError) _, err = erroringClient.SequenceAt(ctx, common.Address{}, nil) @@ -912,4 +911,4 @@ func TestEthClient_ErroringClient(t *testing.T) { } -const headResult = evmclient.HeadResult +const headResult = client.HeadResult diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 7197d77b3d..0d177455e3 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -397,20 +397,20 @@ func ExtractRPCError(baseErr error) (*JsonError, error) { return &jErr, nil } -func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fromAddress common.Address, isL2 bool) (clienttypes.SendTxReturnCode, error) { +func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fromAddress common.Address, isL2 bool) (commonclient.SendTxReturnCode, error) { sendError := NewSendError(err) if sendError == nil { - return clienttypes.Successful, err + return commonclient.Successful, err } if sendError.Fatal() { lggr.Criticalw("Fatal error sending transaction", "err", sendError, "etx", tx) // Attempt is thrown away in this case; we don't need it since it never got accepted by a node - return clienttypes.Fatal, err + return commonclient.Fatal, err } if sendError.IsNonceTooLowError() || sendError.IsTransactionAlreadyMined() { // Nonce too low indicated that a transaction at this nonce was confirmed already. // Mark it as TransactionAlreadyKnown. - return clienttypes.TransactionAlreadyKnown, err + return commonclient.TransactionAlreadyKnown, err } if sendError.IsReplacementUnderpriced() { lggr.Errorw(fmt.Sprintf("Replacement transaction underpriced for eth_tx %x. "+ @@ -419,41 +419,41 @@ func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fro tx.Hash(), err), "gasPrice", tx.GasPrice, "gasTipCap", tx.GasTipCap, "gasFeeCap", tx.GasFeeCap) // Assume success and hand off to the next cycle. - return clienttypes.Successful, err + return commonclient.Successful, err } if sendError.IsTransactionAlreadyInMempool() { lggr.Debugw("Transaction already in mempool", "txHash", tx.Hash, "nodeErr", sendError.Error()) - return clienttypes.Successful, err + return commonclient.Successful, err } if sendError.IsTemporarilyUnderpriced() { lggr.Infow("Transaction temporarily underpriced", "err", sendError.Error()) - return clienttypes.Successful, err + return commonclient.Successful, err } if sendError.IsTerminallyUnderpriced() { - return clienttypes.Underpriced, err + return commonclient.Underpriced, err } if sendError.L2FeeTooLow() || sendError.IsL2FeeTooHigh() || sendError.IsL2Full() { if isL2 { - return clienttypes.FeeOutOfValidRange, err + return commonclient.FeeOutOfValidRange, err } - return clienttypes.Unsupported, errors.Wrap(sendError, "this error type only handled for L2s") + return commonclient.Unsupported, errors.Wrap(sendError, "this error type only handled for L2s") } if sendError.IsNonceTooHighError() { // This error occurs when the tx nonce is greater than current_nonce + tx_count_in_mempool, // instead of keeping the tx in mempool. This can happen if previous transactions haven't // reached the client yet. The correct thing to do is to mark it as retryable. lggr.Warnw("Transaction has a nonce gap.", "err", err) - return clienttypes.Retryable, err + return commonclient.Retryable, err } if sendError.IsInsufficientEth() { lggr.Criticalw(fmt.Sprintf("Tx %x with type 0x%d was rejected due to insufficient eth: %s\n"+ "ACTION REQUIRED: Chainlink wallet with address 0x%x is OUT OF FUNDS", tx.Hash(), tx.Type(), sendError.Error(), fromAddress, ), "err", sendError) - return clienttypes.InsufficientFunds, err + return commonclient.InsufficientFunds, err } if sendError.IsTimeout() { - return clienttypes.Retryable, errors.Wrapf(sendError, "timeout while sending transaction %s", tx.Hash().Hex()) + return commonclient.Retryable, errors.Wrapf(sendError, "timeout while sending transaction %s", tx.Hash().Hex()) } if sendError.IsTxFeeExceedsCap() { lggr.Criticalw(fmt.Sprintf("Sending transaction failed: %s", label.RPCTxFeeCapConfiguredIncorrectlyWarning), @@ -461,19 +461,19 @@ func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fro "err", sendError, "id", "RPCTxFeeCapExceeded", ) - return clienttypes.ExceedsMaxFee, err + return commonclient.ExceedsMaxFee, err } - return clienttypes.Unknown, err + return commonclient.Unknown, err } // ClassifySendOnlyError handles SendOnly nodes error codes. In that case, we don't assume there is another transaction that will be correctly // priced. -func ClassifySendOnlyError(err error) clienttypes.SendTxReturnCode { +func ClassifySendOnlyError(err error) commonclient.SendTxReturnCode { sendError := NewSendError(err) if sendError == nil || sendError.IsNonceTooLowError() || sendError.IsTransactionAlreadyMined() || sendError.IsTransactionAlreadyInMempool() { // Nonce too low or transaction known errors are expected since // the primary SendTransaction may well have succeeded already - return clienttypes.Successful + return commonclient.Successful } - return clienttypes.Fatal + return commonclient.Fatal } diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 8552b2c0a0..2820ba992c 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -9,7 +9,6 @@ import ( "github.com/pkg/errors" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -89,7 +88,7 @@ func NewChainClientWithTestNode( } lggr := logger.TestLogger(t) - rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, clienttypes.Primary) + rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, commonclient.Primary) n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCCLient]( nodeCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-node-0", id, chainID, 1, rpc, "EVM") @@ -101,7 +100,7 @@ func NewChainClientWithTestNode( return nil, errors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", u.String()) } var empty url.URL - rpc := NewRPCClient(lggr, empty, &sendonlyRPCURLs[i], fmt.Sprintf("eth-sendonly-rpc-%d", i), id, chainID, clienttypes.Secondary) + rpc := NewRPCClient(lggr, empty, &sendonlyRPCURLs[i], fmt.Sprintf("eth-sendonly-rpc-%d", i), id, chainID, commonclient.Secondary) s := commonclient.NewSendOnlyNode[*big.Int, RPCCLient]( lggr, u, fmt.Sprintf("eth-sendonly-%d", i), chainID, rpc) sendonlys = append(sendonlys, s) diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index fdcb15d6a6..7617a7c05f 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -7,10 +7,10 @@ import ( assets "github.com/smartcontractkit/chainlink/v2/core/assets" - chainsclient "github.com/smartcontractkit/chainlink/v2/common/chains/client" - common "github.com/ethereum/go-ethereum/common" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + context "context" ethereum "github.com/ethereum/go-ethereum" @@ -566,18 +566,18 @@ func (_m *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er } // SendTransactionReturnCode provides a mock function with given fields: ctx, tx, fromAddress -func (_m *Client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (chainsclient.SendTxReturnCode, error) { +func (_m *Client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { ret := _m.Called(ctx, tx, fromAddress) - var r0 chainsclient.SendTxReturnCode + var r0 commonclient.SendTxReturnCode var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction, common.Address) (chainsclient.SendTxReturnCode, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction, common.Address) (commonclient.SendTxReturnCode, error)); ok { return rf(ctx, tx, fromAddress) } - if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction, common.Address) chainsclient.SendTxReturnCode); ok { + if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction, common.Address) commonclient.SendTxReturnCode); ok { r0 = rf(ctx, tx, fromAddress) } else { - r0 = ret.Get(0).(chainsclient.SendTxReturnCode) + r0 = ret.Get(0).(commonclient.SendTxReturnCode) } if rf, ok := ret.Get(1).(func(context.Context, *types.Transaction, common.Address) error); ok { diff --git a/core/chains/evm/client/null_client.go b/core/chains/evm/client/null_client.go index 8e271aea1e..286f62b3b8 100644 --- a/core/chains/evm/client/null_client.go +++ b/core/chains/evm/client/null_client.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -121,9 +121,9 @@ func (nc *NullClient) HeaderByHash(ctx context.Context, h common.Hash) (*types.H return nil, nil } -func (nc *NullClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, sender common.Address) (clienttypes.SendTxReturnCode, error) { +func (nc *NullClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, sender common.Address) (commonclient.SendTxReturnCode, error) { nc.lggr.Debug("SendTransactionReturnCode") - return clienttypes.Successful, nil + return commonclient.Successful, nil } func (nc *NullClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index b6ed84eee4..04b9fad1fc 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -17,7 +17,6 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -57,7 +56,7 @@ type rpcClient struct { name string id int32 chainID *big.Int - tier clienttypes.NodeTier + tier commonclient.NodeTier ws rawclient http *rawclient @@ -85,7 +84,7 @@ func NewRPCClient( name string, id int32, chainID *big.Int, - tier clienttypes.NodeTier, + tier commonclient.NodeTier, ) RPCCLient { r := new(rpcClient) r.name = name diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index cde536bc7b..7823908967 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -18,7 +18,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -417,16 +417,16 @@ func (c *SimulatedBackendClient) HeaderByHash(ctx context.Context, h common.Hash return c.b.HeaderByHash(ctx, h) } -func (c *SimulatedBackendClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (clienttypes.SendTxReturnCode, error) { +func (c *SimulatedBackendClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { err := c.SendTransaction(ctx, tx) if err == nil { - return clienttypes.Successful, nil + return commonclient.Successful, nil } if strings.Contains(err.Error(), "could not fetch parent") || strings.Contains(err.Error(), "invalid transaction") { - return clienttypes.Fatal, err + return commonclient.Fatal, err } // All remaining error messages returned from SendTransaction are considered Unknown. - return clienttypes.Unknown, err + return commonclient.Unknown, err } // SendTransaction sends a transaction. diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 61a230c21b..ca2697ca99 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -22,11 +22,11 @@ import ( "go.uber.org/zap/zapcore" "gopkg.in/guregu/null.v4" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" @@ -51,7 +51,7 @@ import ( func NewTestEthBroadcaster( t testing.TB, txStore txmgr.TestEvmTxStore, - ethClient evmclient.Client, + ethClient client.Client, keyStore keystore.Eth, config evmconfig.ChainScopedConfig, checkerFactory txmgr.TransmitCheckerFactory, @@ -217,7 +217,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { } ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(2) && tx.Value().Cmp(big.NewInt(242)) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Earlier tr := int32(99) @@ -245,7 +245,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { require.Equal(t, value.String(), tx.Value().String()) require.Equal(t, earlierEthTx.EncodedPayload, tx.Data()) return true - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Later laterEthTx := txmgr.Tx{ @@ -268,7 +268,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { require.Equal(t, value.String(), tx.Value().String()) require.Equal(t, laterEthTx.EncodedPayload, tx.Data()) return true - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Insertion order deliberately reversed to test ordering require.NoError(t, txStore.InsertTx(&expensiveEthTx)) @@ -349,7 +349,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(343) && tx.Value().Cmp(big.NewInt(242)) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, []byte{42, 42, 0}, gasLimit, big.Int(assets.NewEthValue(242)), &cltest.FixtureChainID) // Do the thing @@ -400,7 +400,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { } ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(344) && tx.Value().Cmp(big.NewInt(442)) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() ethClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { if fmt.Sprintf("%s", callarg["value"]) == "0x1ba" { // 442 assert.Equal(t, txRequest.FromAddress, callarg["from"]) @@ -433,7 +433,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { t.Run("with unknown error, sends tx as normal", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(345) && tx.Value().Cmp(big.NewInt(542)) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() ethClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { return fmt.Sprintf("%s", callarg["value"]) == "0x21e" // 542 }), "latest").Return(errors.New("this is not a revert, something unexpected went wrong")).Once() @@ -454,7 +454,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }) t.Run("on revert, marks tx as fatally errored and does not send", func(t *testing.T) { - jerr := evmclient.JsonError{ + jerr := client.JsonError{ Code: 42, Message: "oh no, it reverted", Data: []byte{42, 166, 34}, @@ -503,7 +503,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == 0 && tx.Value().Cmp(big.NewInt(442)) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() ethTx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, cltest.EvmTxRequestWithValue(big.Int(assets.NewEthValue(442))), @@ -526,7 +526,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == 1 && tx.Value().Cmp(big.NewInt(442)) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() ethTx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, cltest.EvmTxRequestWithValue(big.Int(assets.NewEthValue(442))), @@ -646,7 +646,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { assert.Equal(t, int(1600), int(tx.Gas())) return true - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() txRequest := txmgr.TxRequest{ FromAddress: fromAddress, @@ -730,7 +730,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Do the thing { @@ -766,7 +766,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) - }), fromAddress).Return(clienttypes.Fatal, errors.New("exceeds block gas limit")).Once() + }), fromAddress).Return(commonclient.Fatal, errors.New("exceeds block gas limit")).Once() // Do the thing { @@ -802,7 +802,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) - }), fromAddress).Return(clienttypes.Successful, errors.New("known transaction: a1313bd99a81fb4d8ad1d2e90b67c6b3fa77545c990d6251444b83b70b6f8980")).Once() + }), fromAddress).Return(commonclient.Successful, errors.New("known transaction: a1313bd99a81fb4d8ad1d2e90b67c6b3fa77545c990d6251444b83b70b6f8980")).Once() // Do the thing { @@ -837,7 +837,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) - }), fromAddress).Return(clienttypes.TransactionAlreadyKnown, errors.New("nonce too low")).Once() + }), fromAddress).Return(commonclient.TransactionAlreadyKnown, errors.New("nonce too low")).Once() // Do the thing { @@ -874,7 +874,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) - }), fromAddress).Return(clienttypes.Retryable, failedToReachNodeError).Once() + }), fromAddress).Return(commonclient.Retryable, failedToReachNodeError).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -920,7 +920,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { s, e := txmgr.GetGethSignedTx(attempt.SignedRawTx) require.NoError(t, e) return tx.Nonce() == uint64(firstNonce) && tx.GasPrice().Int64() == s.GasPrice().Int64() - }), fromAddress).Return(clienttypes.Successful, errors.New("known transaction: a1313bd99a81fb4d8ad1d2e90b67c6b3fa77545c990d6251444b83b70b6f8980")).Once() + }), fromAddress).Return(commonclient.Successful, errors.New("known transaction: a1313bd99a81fb4d8ad1d2e90b67c6b3fa77545c990d6251444b83b70b6f8980")).Once() // Do the thing { @@ -980,7 +980,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // First send, replacement underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(0) - }), fromAddress).Return(clienttypes.Successful, errors.New("replacement transaction underpriced")).Once() + }), fromAddress).Return(commonclient.Successful, errors.New("replacement transaction underpriced")).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1017,7 +1017,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Fatal, errors.New(fatalErrorExample)).Once() + }), fromAddress).Return(commonclient.Fatal, errors.New(fatalErrorExample)).Once() retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -1067,7 +1067,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Fatal, errors.New(fatalErrorExample)).Once() + }), fromAddress).Return(commonclient.Fatal, errors.New(fatalErrorExample)).Once() retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) require.Error(t, err) @@ -1088,7 +1088,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Fatal, errors.New(fatalErrorExample)).Once() + }), fromAddress).Return(commonclient.Fatal, errors.New(fatalErrorExample)).Once() { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1120,7 +1120,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.ExceedsMaxFee, errors.New(TxFeeExceedsCapError)).Twice() + }), fromAddress).Return(commonclient.ExceedsMaxFee, errors.New(TxFeeExceedsCapError)).Twice() // In the first case, the tx was NOT accepted into the mempool. In the case // of multiple RPC nodes, it is possible that it can be accepted by // another node even if the primary one returns "exceeds the configured @@ -1178,7 +1178,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(localNextNonce) - }), fromAddress).Return(clienttypes.Unknown, errors.New(retryableErrorExample)).Once() + }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is the same as localNextNonce, implying that this sent transaction has not been accepted ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() @@ -1204,7 +1204,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Now on the second run, it is successful ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -1230,7 +1230,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(localNextNonce) - }), fromAddress).Return(clienttypes.Unknown, errors.New(retryableErrorExample)).Once() + }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("pending nonce fetch failed")).Once() // Do the thing @@ -1256,7 +1256,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Now on the second run, it is successful ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -1282,7 +1282,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Unknown, errors.New(retryableErrorExample)).Once() + }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is one higher than localNextNonce, implying that despite the error, this sent transaction has been accepted into the mempool ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() @@ -1316,17 +1316,17 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // First was underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasPrice().Cmp(evmcfg.EVM().GasEstimator().PriceDefault().ToInt()) == 0 - }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() + }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Second with gas bump was still underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasPrice().Cmp(big.NewInt(25000000000)) == 0 - }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() + }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Third succeeded ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasPrice().Cmp(big.NewInt(30000000000)) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1362,7 +1362,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Retryable, failedToReachNodeError).Once() + }), fromAddress).Return(commonclient.Retryable, failedToReachNodeError).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1393,7 +1393,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Successful, errors.New(temporarilyUnderpricedError)).Once() + }), fromAddress).Return(commonclient.Successful, errors.New(temporarilyUnderpricedError)).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1433,7 +1433,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // First was underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasPrice().Cmp(evmcfg2.EVM().GasEstimator().PriceDefault().ToInt()) == 0 - }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() + }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Do the thing retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1451,7 +1451,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.InsufficientFunds, errors.New(insufficientEthError)).Once() + }), fromAddress).Return(commonclient.InsufficientFunds, errors.New(insufficientEthError)).Once() retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) require.Error(t, err) @@ -1481,7 +1481,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce - }), fromAddress).Return(clienttypes.Retryable, errors.New(nonceGapError)).Once() + }), fromAddress).Return(commonclient.Retryable, errors.New(nonceGapError)).Once() retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) require.Error(t, err) @@ -1525,7 +1525,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce = getLocalNextNonce(t, eb, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(1)) == 0 - }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() + }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Check gas tip cap verification retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1569,15 +1569,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Second was underpriced but above minimum ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(gasTipCapDefault.ToInt()) == 0 - }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() + }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Resend at the bumped price ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), evmcfg2.EVM().GasEstimator().BumpMin().ToInt())) == 0 - }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() + }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Final bump succeeds ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), big.NewInt(0).Mul(evmcfg2.EVM().GasEstimator().BumpMin().ToInt(), big.NewInt(2)))) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() retryable, err = eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) require.NoError(t, err) diff --git a/core/chains/evm/txmgr/client.go b/core/chains/evm/txmgr/client.go index e1b1257774..8789f5f173 100644 --- a/core/chains/evm/txmgr/client.go +++ b/core/chains/evm/txmgr/client.go @@ -13,8 +13,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -24,10 +24,10 @@ import ( var _ TxmClient = (*evmTxmClient)(nil) type evmTxmClient struct { - client evmclient.Client + client client.Client } -func NewEvmTxmClient(c evmclient.Client) *evmTxmClient { +func NewEvmTxmClient(c client.Client) *evmTxmClient { return &evmTxmClient{client: c} } @@ -45,14 +45,14 @@ func (c *evmTxmClient) BatchSendTransactions( batchSize int, lggr logger.Logger, ) ( - codes []clienttypes.SendTxReturnCode, + codes []commonclient.SendTxReturnCode, txErrs []error, broadcastTime time.Time, successfulTxIDs []int64, err error, ) { // preallocate - codes = make([]clienttypes.SendTxReturnCode, len(attempts)) + codes = make([]commonclient.SendTxReturnCode, len(attempts)) txErrs = make([]error, len(attempts)) reqs, broadcastTime, successfulTxIDs, batchErr := batchSendTransactions(ctx, attempts, batchSize, lggr, c.client) @@ -80,7 +80,7 @@ func (c *evmTxmClient) BatchSendTransactions( processingErr[i] = fmt.Errorf("failed to process tx (index %d): %w", i, signedErr) return } - codes[i], txErrs[i] = evmclient.ClassifySendError(reqs[i].Error, lggr, tx, attempts[i].Tx.FromAddress, c.client.IsL2()) + codes[i], txErrs[i] = client.ClassifySendError(reqs[i].Error, lggr, tx, attempts[i].Tx.FromAddress, c.client.IsL2()) }(index) } wg.Wait() @@ -88,11 +88,11 @@ func (c *evmTxmClient) BatchSendTransactions( return } -func (c *evmTxmClient) SendTransactionReturnCode(ctx context.Context, etx Tx, attempt TxAttempt, lggr logger.Logger) (clienttypes.SendTxReturnCode, error) { +func (c *evmTxmClient) SendTransactionReturnCode(ctx context.Context, etx Tx, attempt TxAttempt, lggr logger.Logger) (commonclient.SendTxReturnCode, error) { signedTx, err := GetGethSignedTx(attempt.SignedRawTx) if err != nil { lggr.Criticalw("Fatal error signing transaction", "err", err, "etx", etx) - return clienttypes.Fatal, err + return commonclient.Fatal, err } return c.client.SendTransactionReturnCode(ctx, signedTx, etx.FromAddress) } @@ -174,5 +174,5 @@ func (c *evmTxmClient) CallContract(ctx context.Context, a TxAttempt, blockNumbe Data: a.Tx.EncodedPayload, AccessList: nil, }, blockNumber) - return evmclient.ExtractRPCError(errCall) + return client.ExtractRPCError(errCall) } diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 8fbdb7696d..1385250a20 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -20,12 +20,12 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" @@ -564,7 +564,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { data, err := utils.ABIEncode(`[{"type":"uint256"}]`, big.NewInt(10)) require.NoError(t, err) sig := utils.Keccak256Fixed([]byte(`MyError(uint256)`)) - ethClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(nil, &evmclient.JsonError{ + ethClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(nil, &client.JsonError{ Code: 1, Message: "reverted", Data: utils.ConcatBytes(sig[:4], data), @@ -1658,7 +1658,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1.ID)) // Send transaction and assume success. - ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return(clienttypes.Successful, nil).Once() + ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return(commonclient.Successful, nil).Once() err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.NoError(t, err) @@ -1703,7 +1703,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1.ID)) // Send transaction and assume success. - ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return(clienttypes.Successful, nil).Once() + ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return(commonclient.Successful, nil).Once() err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.NoError(t, err) @@ -1787,7 +1787,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { })).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) - }), fromAddress).Return(clienttypes.Fatal, errors.New("exceeds block gas limit")).Once() + }), fromAddress).Return(commonclient.Fatal, errors.New("exceeds block gas limit")).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -1819,7 +1819,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Once for the bumped attempt which exceeds limit ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) && tx.GasPrice().Int64() == int64(20000000000) - }), fromAddress).Return(clienttypes.ExceedsMaxFee, errors.New("tx fee (1.10 ether) exceeds the configured cap (1.00 ether)")).Once() + }), fromAddress).Return(commonclient.ExceedsMaxFee, errors.New("tx fee (1.10 ether) exceeds the configured cap (1.00 ether)")).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -1858,7 +1858,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { })).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -1904,7 +1904,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, fmt.Errorf("known transaction: %s", ethTx.Hash().Hex())).Once() + }), fromAddress).Return(commonclient.Successful, fmt.Errorf("known transaction: %s", ethTx.Hash().Hex())).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -1944,7 +1944,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.TransactionAlreadyKnown, errors.New("nonce too low")).Once() + }), fromAddress).Return(commonclient.TransactionAlreadyKnown, errors.New("nonce too low")).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -1996,7 +1996,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == n && expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Unknown, errors.New("some network error")).Once() + }), fromAddress).Return(commonclient.Unknown, errors.New("some network error")).Once() // Do the thing err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) @@ -2024,7 +2024,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { n = *etx2.Sequence ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == n && expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2063,7 +2063,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == n && expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.TransactionAlreadyKnown, errors.New("nonce too low")).Once() + }), fromAddress).Return(commonclient.TransactionAlreadyKnown, errors.New("nonce too low")).Once() // Creates new attempt as normal if currentHead is not high enough require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2104,7 +2104,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, errors.New("replacement transaction underpriced")).Once() + }), fromAddress).Return(commonclient.Successful, errors.New("replacement transaction underpriced")).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2141,7 +2141,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, fmt.Errorf("known transaction: %s", ethTx.Hash().Hex())).Once() + }), fromAddress).Return(commonclient.Successful, fmt.Errorf("known transaction: %s", ethTx.Hash().Hex())).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2180,7 +2180,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, errors.New(temporarilyUnderpricedError)).Once() + }), fromAddress).Return(commonclient.Successful, errors.New(temporarilyUnderpricedError)).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2209,7 +2209,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, errors.New("already known")).Once() // we already submitted at this price, now it's time to bump and submit again but since we simply resubmitted rather than increasing gas price, geth already knows about this tx + }), fromAddress).Return(commonclient.Successful, errors.New("already known")).Once() // we already submitted at this price, now it's time to bump and submit again but since we simply resubmitted rather than increasing gas price, geth already knows about this tx // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2239,7 +2239,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, errors.New("already known")).Once() // we already submitted at this price, now it's time to bump and submit again but since we simply resubmitted rather than increasing gas price, geth already knows about this tx + }), fromAddress).Return(commonclient.Successful, errors.New("already known")).Once() // we already submitted at this price, now it's time to bump and submit again but since we simply resubmitted rather than increasing gas price, geth already knows about this tx // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2278,7 +2278,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { gasTipCap := assets.GWei(42) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx4.Sequence && gasTipCap.ToInt().Cmp(tx.GasTipCap()) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error etx4, err = txStore.FindTxWithAttempts(etx4.ID) @@ -2308,7 +2308,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Third attempt failed to bump, resubmits old one instead ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx4.Sequence && attempt4_2.Hash.String() == tx.Hash().String() - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error @@ -2344,7 +2344,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(ðTx, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx4.Sequence && expectedBumpedTipCap.ToInt().Cmp(tx.GasTipCap()) == 0 - }), fromAddress).Return(clienttypes.Successful, errors.New("replacement transaction underpriced")).Once() + }), fromAddress).Return(commonclient.Successful, errors.New("replacement transaction underpriced")).Once() // Do it require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2401,10 +2401,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Fail the first time with terminally underpriced. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( - clienttypes.Underpriced, errors.New("Transaction gas price is too low. It does not satisfy your node's minimal gas price")).Once() + commonclient.Underpriced, errors.New("Transaction gas price is too low. It does not satisfy your node's minimal gas price")).Once() // Succeed the second time after bumping gas. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( - clienttypes.Successful, nil).Once() + commonclient.Successful, nil).Once() kst.On("SignTx", mock.Anything, mock.Anything, mock.Anything).Return( signedTx, nil, ).Once() @@ -2424,10 +2424,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Fail a few times with terminally underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( - clienttypes.Underpriced, errors.New("Transaction gas price is too low. It does not satisfy your node's minimal gas price")).Times(3) + commonclient.Underpriced, errors.New("Transaction gas price is too low. It does not satisfy your node's minimal gas price")).Times(3) // Succeed the second time after bumping gas. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( - clienttypes.Successful, nil).Once() + commonclient.Successful, nil).Once() signedLegacyTx := new(types.Transaction) kst.On("SignTx", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Type() == 0x0 && tx.Nonce() == uint64(*etx.Sequence) @@ -2456,10 +2456,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Fail a few times with terminally underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( - clienttypes.Underpriced, errors.New("transaction underpriced")).Times(3) + commonclient.Underpriced, errors.New("transaction underpriced")).Times(3) // Succeed the second time after bumping gas. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( - clienttypes.Successful, nil).Once() + commonclient.Successful, nil).Once() signedDxFeeTx := new(types.Transaction) kst.On("SignTx", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Type() == 0x2 && tx.Nonce() == uint64(*etx.Sequence) @@ -2517,7 +2517,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.InsufficientFunds, insufficientEthError).Once() + }), fromAddress).Return(commonclient.InsufficientFunds, insufficientEthError).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2543,7 +2543,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.InsufficientFunds, insufficientEthError).Once() + }), fromAddress).Return(commonclient.InsufficientFunds, insufficientEthError).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2568,7 +2568,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return expectedBumpedGasPrice.Cmp(tx.GasPrice()) == 0 - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2600,7 +2600,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(n) - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() nonce++ } @@ -2695,7 +2695,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { require.NoError(t, err) // Keeps gas price and nonce the same return atx.GasPrice().Cmp(tx.GasPrice()) == 0 && atx.Nonce() == tx.Nonce() - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) @@ -2718,7 +2718,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { cltest.MustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attemptHash) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( - clienttypes.Successful, nil).Once() + commonclient.Successful, nil).Once() // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) @@ -2753,7 +2753,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { s, err := txmgr.GetGethSignedTx(attempt3.SignedRawTx) require.NoError(t, err) return tx.Hash() == s.Hash() - }), fromAddress).Return(clienttypes.Successful, nil).Once() + }), fromAddress).Return(commonclient.Successful, nil).Once() // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) @@ -2817,7 +2817,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { tx.Gas() == uint64(overrideGasLimit) && reflect.DeepEqual(tx.Data(), etx1.EncodedPayload) && tx.To().String() == etx1.ToAddress.String() - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{1}, gasPriceWei, fromAddress, overrideGasLimit)) }) @@ -2832,7 +2832,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { tx.Gas() == uint64(etx1.FeeLimit) && reflect.DeepEqual(tx.Data(), etx1.EncodedPayload) && tx.To().String() == etx1.ToAddress.String() - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{(1)}, gasPriceWei, fromAddress, 0)) }) @@ -2843,10 +2843,10 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == uint64(overrideGasLimit) - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx2.Sequence) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == uint64(overrideGasLimit) - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{(1), (2)}, gasPriceWei, fromAddress, overrideGasLimit)) }) @@ -2857,10 +2857,10 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(1) - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(2) - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() for i := 3; i <= 5; i++ { nonce := i ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { @@ -2870,7 +2870,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { *tx.To() == fromAddress && tx.Value().Cmp(big.NewInt(0)) == 0 && len(tx.Data()) == 0 - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() } nonces := []evmtypes.Nonce{(1), (2), (3), (4), (5)} @@ -2883,7 +2883,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(0) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && uint32(tx.Gas()) == config.EVM().GasEstimator().LimitDefault() - }), mock.Anything).Return(clienttypes.Successful, nil).Once() + }), mock.Anything).Return(commonclient.Successful, nil).Once() require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{(0)}, gasPriceWei, fromAddress, 0)) }) diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index df60e16423..a73e98a935 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/cmd" cmdMocks "github.com/smartcontractkit/chainlink/v2/core/cmd/mocks" @@ -307,7 +307,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { app.On("GetRelayers").Return(mockRelayerChainInteroperators).Maybe() ethClient.On("Dial", mock.Anything).Return(nil) - client := cmd.Shell{ + c := cmd.Shell{ Config: config, AppFactory: cltest.InstanceAppFactory{App: app}, FallbackAPIInitializer: cltest.NewMockAPIInitializer(t), @@ -318,7 +318,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { beginningNonce := uint64(7) endingNonce := uint64(10) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RebroadcastTransactions, set, "") + cltest.FlagSetApplyFromAction(c.RebroadcastTransactions, set, "") require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("beginningNonce", strconv.FormatUint(beginningNonce, 10))) @@ -328,16 +328,16 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { require.NoError(t, set.Set("address", fromAddress.Hex())) require.NoError(t, set.Set("password", "../internal/fixtures/correct_password.txt")) - c := cli.NewContext(nil, set, nil) + ctx := cli.NewContext(nil, set, nil) for i := beginningNonce; i <= endingNonce; i++ { n := i ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == n - }), mock.Anything).Once().Return(clienttypes.Successful, nil) + }), mock.Anything).Once().Return(client.Successful, nil) } - assert.NoError(t, client.RebroadcastTransactions(c)) + assert.NoError(t, c.RebroadcastTransactions(ctx)) } func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { @@ -388,7 +388,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { mockRelayerChainInteroperators := &chainlinkmocks.FakeRelayerChainInteroperators{EVMChains: legacy} app.On("GetRelayers").Return(mockRelayerChainInteroperators).Maybe() - client := cmd.Shell{ + c := cmd.Shell{ Config: config, AppFactory: cltest.InstanceAppFactory{App: app}, FallbackAPIInitializer: cltest.NewMockAPIInitializer(t), @@ -397,7 +397,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { } set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RebroadcastTransactions, set, "") + cltest.FlagSetApplyFromAction(c.RebroadcastTransactions, set, "") require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("beginningNonce", strconv.FormatUint(uint64(beginningNonce), 10))) @@ -407,16 +407,16 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { require.NoError(t, set.Set("address", fromAddress.Hex())) require.NoError(t, set.Set("password", "../internal/fixtures/correct_password.txt")) - c := cli.NewContext(nil, set, nil) + ctx := cli.NewContext(nil, set, nil) for i := beginningNonce; i <= endingNonce; i++ { n := i ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return uint(tx.Nonce()) == n - }), mock.Anything).Once().Return(clienttypes.Successful, nil) + }), mock.Anything).Once().Return(client.Successful, nil) } - assert.NoError(t, client.RebroadcastTransactions(c)) + assert.NoError(t, c.RebroadcastTransactions(ctx)) cltest.AssertEthTxAttemptCountStays(t, app.GetSqlxDB(), 1) }) @@ -466,7 +466,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { mockRelayerChainInteroperators := &chainlinkmocks.FakeRelayerChainInteroperators{EVMChains: legacy} app.On("GetRelayers").Return(mockRelayerChainInteroperators).Maybe() - ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(clienttypes.Successful, nil) + ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(client.Successful, nil) client := cmd.Shell{ Config: config, diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 66162aef10..e5c2ca031a 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -44,7 +44,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/loop" - clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" + "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -518,7 +518,7 @@ func NewEthMocksWithTransactionsOnBlocksAssertions(t testing.TB) *evmclimocks.Cl c.On("Dial", mock.Anything).Maybe().Return(nil) c.On("SubscribeNewHead", mock.Anything, mock.Anything).Maybe().Return(EmptyMockSubscription(t), nil) c.On("SendTransaction", mock.Anything, mock.Anything).Maybe().Return(nil) - c.On("SendTransactionReturnCode", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(clienttypes.Successful, nil) + c.On("SendTransactionReturnCode", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(client.Successful, nil) // Construct chain h2 := Head(2) h1 := HeadWithHash(1, h2.ParentHash) From 84bbe2af6ac8889e40f0210414375c956df65275 Mon Sep 17 00:00:00 2001 From: FelixFan1992 Date: Mon, 6 Nov 2023 14:42:47 -0500 Subject: [PATCH 080/327] populate retry interval for mercury requests [DO NOT MERGE] (#11150) * populate retry interval for mercury requests * fix go mod * populate retry interval based on the work ID counter * add tests * use const value * include check block number in plugin retry key * address comments * refactor * test for plugin retry counter * Bump ocr2keepers to 0.7.28 (#11181) * handles 206 response code * reduce mercury permission cache period * address comments * remove special logging for 206 --------- Co-authored-by: Akshay Aggarwal --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../ocr2/plugins/ocr2keeper/evm21/registry.go | 19 +- .../ocr2keeper/evm21/streams_lookup.go | 88 ++++++-- .../ocr2keeper/evm21/streams_lookup_test.go | 205 ++++++++++++++---- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 9 files changed, 248 insertions(+), 82 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 6b0a33451e..8d731f3f41 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -22,7 +22,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 - github.com/smartcontractkit/ocr2keepers v0.7.27 + github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/spf13/cobra v1.6.1 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 2cb0eb2582..ebab8c990d 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1478,8 +1478,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= -github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= +github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= +github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 0ca20477f2..73e2bc0a9c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -20,6 +20,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -35,11 +36,14 @@ import ( ) const ( + defaultPluginRetryExpiration = 30 * time.Minute // defaultAllowListExpiration decides how long an upkeep's allow list info will be valid for. - defaultAllowListExpiration = 20 * time.Minute - // allowListCleanupInterval decides when the expired items in allowList cache will be deleted. - allowListCleanupInterval = 5 * time.Minute + defaultAllowListExpiration = 10 * time.Minute + // cleanupInterval decides when the expired items in cache will be deleted. + cleanupInterval = 5 * time.Minute logTriggerRefreshBatchSize = 32 + totalFastPluginRetries = 5 + totalMediumPluginRetries = 10 ) var ( @@ -100,9 +104,10 @@ func NewEvmRegistry( headFunc: func(ocr2keepers.BlockKey) {}, chLog: make(chan logpoller.Log, 1000), mercury: &MercuryConfig{ - cred: mc, - abi: core.StreamsCompatibleABI, - allowListCache: cache.New(defaultAllowListExpiration, allowListCleanupInterval), + cred: mc, + abi: core.StreamsCompatibleABI, + allowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), + pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), }, hc: http.DefaultClient, logEventProvider: logEventProvider, @@ -126,6 +131,8 @@ type MercuryConfig struct { abi abi.ABI // allowListCache stores the upkeeps privileges. In 2.1, this only includes a JSON bytes for allowed to use mercury allowListCache *cache.Cache + + pluginRetryCache *cache.Cache } type EvmRegistry struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go index 6f2594b6c3..f183e1f6bb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go @@ -162,10 +162,11 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *StreamsLookup, i int, checkResults []ocr2keepers.CheckResult, lggr logger.Logger) { defer wg.Done() - state, reason, values, retryable, err := r.doMercuryRequest(ctx, lookup, lggr) + state, reason, values, retryable, ri, err := r.doMercuryRequest(ctx, lookup, generatePluginRetryKey(checkResults[i].WorkID, lookup.block), lggr) if err != nil { - lggr.Errorf("upkeep %s retryable %v doMercuryRequest: %s", lookup.upkeepId, retryable, err.Error()) + lggr.Errorf("upkeep %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.upkeepId, retryable, ri, err.Error()) checkResults[i].Retryable = retryable + checkResults[i].RetryInterval = ri checkResults[i].PipelineExecutionState = uint8(state) checkResults[i].IneligibilityReason = uint8(reason) return @@ -278,12 +279,12 @@ func (r *EvmRegistry) checkCallback(ctx context.Context, values [][]byte, lookup } // doMercuryRequest sends requests to Mercury API to retrieve mercury data. -func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, lggr logger.Logger) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, error) { +func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, prk string, lggr logger.Logger) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, time.Duration, error) { var isMercuryV03 bool resultLen := len(sl.Feeds) ch := make(chan MercuryData, resultLen) if len(sl.Feeds) == 0 { - return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) + return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) } if sl.FeedParamKey == feedIdHex && sl.TimeParamKey == blockNumber { // only mercury v0.2 @@ -297,10 +298,11 @@ func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, l ch = make(chan MercuryData, resultLen) go r.multiFeedsRequest(ctx, ch, sl, lggr) } else { - return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) + return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) } var reqErr error + var ri time.Duration results := make([][]byte, len(sl.Feeds)) retryable := true allSuccess := true @@ -323,8 +325,11 @@ func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, l results[m.Index] = m.Bytes[0] } } + if retryable && !allSuccess { + ri = r.calculateRetryConfig(prk) + } // only retry when not all successful AND none are not retryable - return state, encoding.UpkeepFailureReasonNone, results, retryable && !allSuccess, reqErr + return state, encoding.UpkeepFailureReasonNone, results, retryable && !allSuccess, ri, reqErr } // singleFeedRequest sends a v0.2 Mercury request for a single feed report. @@ -378,7 +383,7 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa return err1 } - if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { + if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError || resp.StatusCode == http.StatusBadGateway || resp.StatusCode == http.StatusServiceUnavailable || resp.StatusCode == http.StatusGatewayTimeout { lggr.Warnf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, sl.Feeds[index]) retryable = true state = encoding.MercuryFlakyFailure @@ -415,9 +420,9 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa sent = true return nil }, - // only retry when the error is 404 Not Found or 500 Internal Server Error + // only retry when the error is 404 Not Found, 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) + return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) || err.Error() == fmt.Sprintf("%d", http.StatusBadGateway) || err.Error() == fmt.Sprintf("%d", http.StatusServiceUnavailable) || err.Error() == fmt.Sprintf("%d", http.StatusGatewayTimeout) }), retry.Context(ctx), retry.Delay(retryDelay), @@ -504,15 +509,29 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa retryable = false state = encoding.InvalidMercuryRequest return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3 with message: %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, string(body)) - } else if resp.StatusCode == http.StatusInternalServerError { + } else if resp.StatusCode == http.StatusInternalServerError || resp.StatusCode == http.StatusBadGateway || resp.StatusCode == http.StatusServiceUnavailable || resp.StatusCode == http.StatusGatewayTimeout { retryable = true state = encoding.MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusInternalServerError) - } else if resp.StatusCode == 420 { - // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds - retryable = false - state = encoding.InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) + return fmt.Errorf("%d", resp.StatusCode) + } else if resp.StatusCode == http.StatusPartialContent { + //var response MercuryV03Response + //err1 = json.Unmarshal(body, &response) + //if err1 != nil { + // lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.Time.String(), sl.upkeepId.String(), err1) + // retryable = false + // state = encoding.MercuryUnmarshalError + // return err1 + //} + // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract + // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated + //var receivedFeeds []string + //for _, f := range response.Reports { + // receivedFeeds = append(receivedFeeds, f.FeedID) + //} + lggr.Warnf("at timestamp %s upkeep %s requested [%s] feeds but mercury v0.3 server returned 206 status, treating it as 404 and retrying", sl.Time.String(), sl.upkeepId.String(), sl.Feeds) + retryable = true + state = encoding.MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusPartialContent) } else if resp.StatusCode != http.StatusOK { retryable = false state = encoding.InvalidMercuryRequest @@ -532,8 +551,11 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated if len(response.Reports) != len(sl.Feeds) { - // TODO: AUTO-5044: calculate what reports are missing and log a warning - lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server retruned 200 status with %d reports while we requested %d feeds, treating as 404 (not found) and retrying", sl.Time.String(), sl.upkeepId.String(), len(response.Reports), len(sl.Feeds)) + var receivedFeeds []string + for _, f := range response.Reports { + receivedFeeds = append(receivedFeeds, f.FeedID) + } + lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server returned 206 status with [%s] reports while we requested [%s] feeds, retrying", sl.Time.String(), sl.upkeepId.String(), receivedFeeds, sl.Feeds) retryable = true state = encoding.MercuryFlakyFailure return fmt.Errorf("%d", http.StatusNotFound) @@ -558,9 +580,9 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa sent = true return nil }, - // only retry when the error is 404 Not Found or 500 Internal Server Error + // only retry when the error is 206 Partial Content, 404 Not Found, 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) + return err.Error() == fmt.Sprintf("%d", http.StatusPartialContent) || err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) || err.Error() == fmt.Sprintf("%d", http.StatusBadGateway) || err.Error() == fmt.Sprintf("%d", http.StatusServiceUnavailable) || err.Error() == fmt.Sprintf("%d", http.StatusGatewayTimeout) }), retry.Context(ctx), retry.Delay(retryDelay), @@ -593,3 +615,29 @@ func (r *EvmRegistry) generateHMAC(method string, path string, body []byte, clie userHmac := hex.EncodeToString(signedMessage.Sum(nil)) return userHmac } + +// calculateRetryConfig returns plugin retry interval based on how many times plugin has retried this work +func (r *EvmRegistry) calculateRetryConfig(prk string) time.Duration { + var ri time.Duration + var retries int + totalAttempts, ok := r.mercury.pluginRetryCache.Get(prk) + if ok { + retries = totalAttempts.(int) + if retries < totalFastPluginRetries { + ri = 1 * time.Second + } else if retries < totalMediumPluginRetries { + ri = 5 * time.Second + } + // if the core node has retried totalMediumPluginRetries times, do not set retry interval and plugin will use + // the default interval + } else { + ri = 1 * time.Second + } + r.mercury.pluginRetryCache.Set(prk, retries+1, cache.DefaultExpiration) + return ri +} + +// generatePluginRetryKey returns a plugin retry cache key +func generatePluginRetryKey(workID string, block uint64) string { + return workID + "|" + fmt.Sprintf("%d", block) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go index 6f7065ef87..8d7c67d80c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go @@ -10,6 +10,7 @@ import ( "net/http" "strings" "testing" + "time" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -65,8 +66,9 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { Username: "FakeClientID", Password: "FakeClientKey", }, - abi: streamsLookupCompatibleABI, - allowListCache: cache.New(defaultAllowListExpiration, allowListCleanupInterval), + abi: streamsLookupCompatibleABI, + allowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), + pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), }, hc: mockHttpClient, } @@ -427,15 +429,18 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) tests := []struct { - name string - lookup *StreamsLookup - mockHttpStatusCode int - mockChainlinkBlobs []string - expectedValues [][]byte - expectedRetryable bool - expectedError error - state encoding.PipelineExecutionState - reason encoding.UpkeepFailureReason + name string + lookup *StreamsLookup + mockHttpStatusCode int + mockChainlinkBlobs []string + pluginRetries int + pluginRetryKey string + expectedValues [][]byte + expectedRetryable bool + expectedRetryInterval time.Duration + expectedError error + state encoding.PipelineExecutionState + reason encoding.UpkeepFailureReason }{ { name: "success", @@ -456,7 +461,7 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { expectedError: nil, }, { - name: "failure - retryable", + name: "failure - retryable and interval is 1s", lookup: &StreamsLookup{ StreamsLookupError: &encoding.StreamsLookupError{ FeedParamKey: feedIdHex, @@ -467,6 +472,49 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { }, upkeepId: upkeepId, }, + mockHttpStatusCode: http.StatusInternalServerError, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{nil}, + expectedRetryable: true, + pluginRetries: 0, + expectedRetryInterval: 1 * time.Second, + expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), + state: encoding.MercuryFlakyFailure, + }, + { + name: "failure - retryable and interval is 5s", + lookup: &StreamsLookup{ + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, + }, + pluginRetries: 5, + mockHttpStatusCode: http.StatusInternalServerError, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{nil}, + expectedRetryable: true, + expectedRetryInterval: 5 * time.Second, + expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), + state: encoding.MercuryFlakyFailure, + }, + { + name: "failure - not retryable because there are many plugin retries already", + lookup: &StreamsLookup{ + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, + }, + pluginRetries: 10, mockHttpStatusCode: http.StatusInternalServerError, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, expectedValues: [][]byte{nil}, @@ -486,11 +534,11 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { }, upkeepId: upkeepId, }, - mockHttpStatusCode: http.StatusBadGateway, + mockHttpStatusCode: http.StatusTooManyRequests, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, expectedValues: [][]byte{nil}, expectedRetryable: false, - expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 25880526 upkeep 88786950015966611018675766524283132478093844178961698330929478019253453382042 received status code 502 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 25880526 upkeep 88786950015966611018675766524283132478093844178961698330929478019253453382042 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), state: encoding.InvalidMercuryRequest, }, { @@ -528,6 +576,9 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + if tt.pluginRetries != 0 { + r.mercury.pluginRetryCache.Set(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) + } hc := mocks.NewHttpClient(t) for _, blob := range tt.mockChainlinkBlobs { @@ -539,7 +590,7 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { StatusCode: tt.mockHttpStatusCode, Body: io.NopCloser(bytes.NewReader(b)), } - if tt.expectedError != nil && tt.expectedRetryable { + if tt.expectedError != nil && tt.expectedRetryable || tt.pluginRetries > 0 { hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) } else { hc.On("Do", mock.Anything).Return(resp, nil).Once() @@ -547,13 +598,18 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { } r.hc = hc - state, reason, values, retryable, reqErr := r.doMercuryRequest(context.Background(), tt.lookup, r.lggr) + state, reason, values, retryable, ri, reqErr := r.doMercuryRequest(context.Background(), tt.lookup, tt.pluginRetryKey, r.lggr) assert.Equal(t, tt.expectedValues, values) assert.Equal(t, tt.expectedRetryable, retryable) + if retryable { + newRetries, _ := r.mercury.pluginRetryCache.Get(tt.pluginRetryKey) + assert.Equal(t, tt.pluginRetries+1, newRetries.(int)) + } + assert.Equal(t, tt.expectedRetryInterval, ri) assert.Equal(t, tt.state, state) assert.Equal(t, tt.reason, reason) if tt.expectedError != nil { - assert.Equal(t, tt.expectedError.Error(), reqErr.Error()) + assert.True(t, strings.HasPrefix(reqErr.Error(), "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000")) } }) } @@ -563,15 +619,17 @@ func TestEvmRegistry_DoMercuryRequestV03(t *testing.T) { upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) tests := []struct { - name string - lookup *StreamsLookup - mockHttpStatusCode int - mockChainlinkBlobs []string - expectedValues [][]byte - expectedRetryable bool - expectedError error - state encoding.PipelineExecutionState - reason encoding.UpkeepFailureReason + name string + lookup *StreamsLookup + mockHttpStatusCode int + mockChainlinkBlobs []string + pluginRetryKey string + expectedValues [][]byte + expectedRetryable bool + expectedRetryInterval time.Duration + expectedError error + state encoding.PipelineExecutionState + reason encoding.UpkeepFailureReason }{ { name: "success v0.3", @@ -622,9 +680,10 @@ func TestEvmRegistry_DoMercuryRequestV03(t *testing.T) { } r.hc = hc - state, reason, values, retryable, reqErr := r.doMercuryRequest(context.Background(), tt.lookup, r.lggr) + state, reason, values, retryable, ri, reqErr := r.doMercuryRequest(context.Background(), tt.lookup, tt.pluginRetryKey, r.lggr) assert.Equal(t, tt.expectedValues, values) assert.Equal(t, tt.expectedRetryable, retryable) + assert.Equal(t, tt.expectedRetryInterval, ri) assert.Equal(t, tt.state, state) assert.Equal(t, tt.reason, reason) if tt.expectedError != nil { @@ -640,6 +699,7 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { name string index int lookup *StreamsLookup + pluginRetryKey string blob string statusCode int lastStatusCode int @@ -728,8 +788,8 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { blob: "0xab2123dc", retryNumber: 1, statusCode: http.StatusNotFound, - lastStatusCode: http.StatusBadGateway, - errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: at block 123456 upkeep 123456789 received status code 502 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + lastStatusCode: http.StatusTooManyRequests, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: at block 123456 upkeep 123456789 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", }, { name: "failure - returns not retryable", @@ -744,8 +804,8 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { upkeepId: upkeepId, }, blob: "0xab2123dc", - statusCode: http.StatusBadGateway, - errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 502 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + statusCode: http.StatusConflict, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 409 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", }, } @@ -819,6 +879,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { lookup *StreamsLookup statusCode int lastStatusCode int + pluginRetries int + pluginRetryKey string retryNumber int retryable bool errorMessage string @@ -883,6 +945,47 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { }, statusCode: http.StatusOK, }, + { + name: "success - retry 206", + lookup: &StreamsLookup{ + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, + }, + firstResponse: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000019", + }, + }, + }, + retryNumber: 1, + statusCode: http.StatusPartialContent, + lastStatusCode: http.StatusOK, + }, { name: "success - retry for 500", lookup: &StreamsLookup{ @@ -946,7 +1049,7 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { errorMessage: "All attempts fail:\n#1: hex string without 0x prefix", }, { - name: "failure - returns retryable", + name: "failure - returns retryable with 1s plugin retry interval", lookup: &StreamsLookup{ StreamsLookupError: &encoding.StreamsLookupError{ FeedParamKey: feedIDs, @@ -962,7 +1065,7 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", }, { - name: "failure - returns retryable and then non-retryable", + name: "failure - returns retryable with 5s plugin retry interval", lookup: &StreamsLookup{ StreamsLookupError: &encoding.StreamsLookupError{ FeedParamKey: feedIDs, @@ -972,27 +1075,30 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { }, upkeepId: upkeepId, }, - retryNumber: 1, - statusCode: http.StatusInternalServerError, - lastStatusCode: http.StatusUnauthorized, - errorMessage: "All attempts fail:\n#1: 500\n#2: at timestamp 123456 upkeep 123456789 received status code 401 from mercury v0.3, most likely this is caused by unauthorized upkeep", + pluginRetries: 6, + retryNumber: totalAttempt, + statusCode: http.StatusInternalServerError, + retryable: true, + errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", }, { - name: "failure - returns status code 420 not retryable", + name: "failure - returns retryable and then non-retryable", lookup: &StreamsLookup{ StreamsLookupError: &encoding.StreamsLookupError{ FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, TimeParamKey: timestamp, Time: big.NewInt(123456), }, upkeepId: upkeepId, }, - statusCode: 420, - errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 420 from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", + retryNumber: 1, + statusCode: http.StatusInternalServerError, + lastStatusCode: http.StatusUnauthorized, + errorMessage: "All attempts fail:\n#1: 500\n#2: at timestamp 123456 upkeep 123456789 received status code 401 from mercury v0.3, most likely this is caused by unauthorized upkeep", }, { - name: "failure - returns status code 502 not retryable", + name: "failure - returns status code 422 not retryable", lookup: &StreamsLookup{ StreamsLookupError: &encoding.StreamsLookupError{ FeedParamKey: feedIDs, @@ -1002,8 +1108,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { }, upkeepId: upkeepId, }, - statusCode: http.StatusBadGateway, - errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 502 from mercury v0.3", + statusCode: http.StatusUnprocessableEntity, + errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 422 from mercury v0.3", }, { name: "success - retry when reports length does not match feeds length", @@ -1042,14 +1148,19 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { }, }, }, - retryNumber: 1, - statusCode: http.StatusOK, + retryNumber: 1, + statusCode: http.StatusOK, + lastStatusCode: http.StatusOK, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + if tt.pluginRetries != 0 { + r.mercury.pluginRetryCache.Set(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) + } + hc := mocks.NewHttpClient(t) b, err := json.Marshal(tt.response) assert.Nil(t, err) @@ -1071,7 +1182,7 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { b1, err := json.Marshal(tt.response) assert.Nil(t, err) resp1 := &http.Response{ - StatusCode: tt.statusCode, + StatusCode: tt.lastStatusCode, Body: io.NopCloser(bytes.NewReader(b1)), } hc.On("Do", mock.Anything).Return(resp0, nil).Once().On("Do", mock.Anything).Return(resp1, nil).Once() diff --git a/go.mod b/go.mod index f271bf421f..4d8a929402 100644 --- a/go.mod +++ b/go.mod @@ -70,7 +70,7 @@ require ( 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-20231020123319-d255366a6545 - github.com/smartcontractkit/ocr2keepers v0.7.27 + github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 diff --git a/go.sum b/go.sum index 8426876e23..acd966e8aa 100644 --- a/go.sum +++ b/go.sum @@ -1479,8 +1479,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= -github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= +github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= +github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index f73838f1ab..936729944f 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -25,7 +25,7 @@ require ( github.com/smartcontractkit/chainlink-testing-framework v1.18.4-0.20231106173929-20fe04d6ad66 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 - github.com/smartcontractkit/ocr2keepers v0.7.27 + github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 843cef2690..7bd733023c 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2384,8 +2384,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= -github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= +github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= +github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= From 7b5e6a5ea6c4a450af73acd67a322553d033a16a Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Mon, 6 Nov 2023 14:56:22 -0500 Subject: [PATCH 081/327] Fixes old pointer aliases (#11187) --- .../chaos/automation_chaos_test.go | 17 ++++++++--------- integration-tests/chaos/ocr2vrf_chaos_test.go | 17 ++++++++--------- integration-tests/chaos/ocr_chaos_test.go | 17 ++++++++--------- integration-tests/reorg/reorg_confirmer.go | 7 ++++--- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index a3d4e37406..22c9e742f3 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -14,7 +14,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" @@ -132,7 +131,7 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -141,7 +140,7 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -150,9 +149,9 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, DurationStr: "1m", - ContainerNames: &[]*string{a.Str("chainlink-db")}, + ContainerNames: &[]*string{utils.Ptr("chainlink-db")}, }, }, NetworkChaosFailMajorityNetwork: { @@ -160,8 +159,8 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{ChaosGroupMajority: a.Str("1")}, - ToLabels: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + FromLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + ToLabels: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -170,8 +169,8 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{"app": a.Str("geth")}, - ToLabels: &map[string]*string{ChaosGroupMajorityPlus: a.Str("1")}, + FromLabels: &map[string]*string{"app": utils.Ptr("geth")}, + ToLabels: &map[string]*string{ChaosGroupMajorityPlus: utils.Ptr("1")}, DurationStr: "1m", }, }, diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 0beccadddd..ba75974f01 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" @@ -68,7 +67,7 @@ func TestOCR2VRFChaos(t *testing.T) { chainlink.New(0, defaultOCR2VRFSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -78,7 +77,7 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewFailPods, // &chaos.Props{ - // LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + // LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, // DurationStr: "1m", // }, //}, @@ -88,9 +87,9 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewFailPods, // &chaos.Props{ - // LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + // LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, // DurationStr: "1m", - // ContainerNames: &[]*string{a.Str("chainlink-db")}, + // ContainerNames: &[]*string{utils.Ptr("chainlink-db")}, // }, //}, //NetworkChaosFailMajorityNetwork: { @@ -98,8 +97,8 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewNetworkPartition, // &chaos.Props{ - // FromLabels: &map[string]*string{ChaosGroupMajority: a.Str("1")}, - // ToLabels: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + // FromLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + // ToLabels: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, // DurationStr: "1m", // }, //}, @@ -108,8 +107,8 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewNetworkPartition, // &chaos.Props{ - // FromLabels: &map[string]*string{"app": a.Str("geth")}, - // ToLabels: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + // FromLabels: &map[string]*string{"app": utils.Ptr("geth")}, + // ToLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, // DurationStr: "1m", // }, //}, diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index b65f8bb74f..599fad8ddc 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -15,7 +15,6 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" @@ -81,8 +80,8 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{ChaosGroupMajority: a.Str("1")}, - ToLabels: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + FromLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + ToLabels: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -91,8 +90,8 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{"app": a.Str("geth")}, - ToLabels: &map[string]*string{ChaosGroupMajorityPlus: a.Str("1")}, + FromLabels: &map[string]*string{"app": utils.Ptr("geth")}, + ToLabels: &map[string]*string{ChaosGroupMajorityPlus: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -101,7 +100,7 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -110,7 +109,7 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, DurationStr: "1m", }, }, @@ -119,9 +118,9 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, DurationStr: "1m", - ContainerNames: &[]*string{a.Str("chainlink-db")}, + ContainerNames: &[]*string{utils.Ptr("chainlink-db")}, }, }, } diff --git a/integration-tests/reorg/reorg_confirmer.go b/integration-tests/reorg/reorg_confirmer.go index be535d2a6d..885bed2ad4 100644 --- a/integration-tests/reorg/reorg_confirmer.go +++ b/integration-tests/reorg/reorg_confirmer.go @@ -14,8 +14,9 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - a "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/alias" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" + + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) // The steps are: @@ -231,8 +232,8 @@ func (rc *ReorgController) forkNetwork(header blockchain.NodeHeader) error { rc.cfg.Env.Cfg.Namespace, &chaos.Props{ DurationStr: "999h", - FromLabels: &map[string]*string{"app": a.Str(reorg.TXNodesAppLabel)}, - ToLabels: &map[string]*string{"app": a.Str(reorg.MinerNodesAppLabel)}, + FromLabels: &map[string]*string{"app": utils.Ptr(reorg.TXNodesAppLabel)}, + ToLabels: &map[string]*string{"app": utils.Ptr(reorg.MinerNodesAppLabel)}, }, )) rc.chaosExperimentName = expName From 2b3806209238ebe3b2d8199639bf5c864fe4ba3c Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:01:26 -0800 Subject: [PATCH 082/327] [Functions] Respond with an error on insufficient balance (#11183) Co-authored-by: Morgan Kuphal <87319522+KuphJr@users.noreply.github.com> --- core/services/functions/connector_handler.go | 7 ++++++ .../functions/connector_handler_test.go | 24 ++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index a018157a37..8a8710e6ea 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -78,6 +78,13 @@ func (h *functionsConnectorHandler) HandleGatewayMessage(ctx context.Context, ga } if balance, err := h.subscriptions.GetMaxUserBalance(fromAddr); err != nil || balance.Cmp(h.minimumBalance.ToInt()) < 0 { h.lggr.Errorw("user subscription has insufficient balance", "id", gatewayId, "address", fromAddr, "balance", balance, "minBalance", h.minimumBalance) + response := functions.SecretsResponseBase{ + Success: false, + ErrorMessage: "user subscription has insufficient balance", + } + if err := h.sendResponse(ctx, gatewayId, body, response); err != nil { + h.lggr.Errorw("failed to send response to gateway", "id", gatewayId, "error", err) + } return } diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index bb3e2acbab..7bf98d7501 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -39,7 +39,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { allowlist.On("Close", mock.Anything).Return(nil) subscriptions.On("Start", mock.Anything).Return(nil) subscriptions.On("Close", mock.Anything).Return(nil) - handler, err := functions.NewFunctionsConnectorHandler(addr.Hex(), privateKey, storage, allowlist, rateLimiter, subscriptions, *assets.NewLinkFromJuels(0), logger) + handler, err := functions.NewFunctionsConnectorHandler(addr.Hex(), privateKey, storage, allowlist, rateLimiter, subscriptions, *assets.NewLinkFromJuels(100), logger) require.NoError(t, err) handler.SetConnector(connector) @@ -78,7 +78,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { } storage.On("List", ctx, addr).Return(snapshot, nil).Once() allowlist.On("Allow", addr).Return(true).Once() - subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil) + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -91,6 +91,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("orm error", func(t *testing.T) { storage.On("List", ctx, addr).Return(nil, errors.New("boom")).Once() allowlist.On("Allow", addr).Return(true).Once() + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -135,7 +136,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { storage.On("Put", ctx, &key, &record, signature).Return(nil).Once() allowlist.On("Allow", addr).Return(true).Once() - subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil) + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -148,6 +149,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("orm error", func(t *testing.T) { storage.On("Put", ctx, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("boom")).Once() allowlist.On("Allow", addr).Return(true).Once() + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -163,6 +165,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { require.NoError(t, msg.Sign(privateKey)) storage.On("Put", ctx, mock.Anything, mock.Anything, mock.Anything).Return(s4.ErrWrongSignature).Once() allowlist.On("Allow", addr).Return(true).Once() + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -177,6 +180,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { msg.Body.Payload = json.RawMessage(`{sdfgdfgoscsicosd:sdf:::sdf ::; xx}`) require.NoError(t, msg.Sign(privateKey)) allowlist.On("Allow", addr).Return(true).Once() + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -186,6 +190,19 @@ func TestFunctionsConnectorHandler(t *testing.T) { handler.HandleGatewayMessage(ctx, "gw1", &msg) }) + + t.Run("insufficient balance", func(t *testing.T) { + allowlist.On("Allow", addr).Return(true).Once() + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(0), nil).Once() + connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { + msg, ok := args[2].(*api.Message) + require.True(t, ok) + require.Equal(t, `{"success":false,"error_message":"user subscription has insufficient balance"}`, string(msg.Body.Payload)) + + }).Return(nil).Once() + + handler.HandleGatewayMessage(ctx, "gw1", &msg) + }) }) t.Run("unsupported method", func(t *testing.T) { @@ -201,6 +218,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { require.NoError(t, msg.Sign(privateKey)) allowlist.On("Allow", addr).Return(true).Once() + subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() handler.HandleGatewayMessage(testutils.Context(t), "gw1", &msg) }) }) From 0ae0b691466687ac7be2b49d9d4a1bd3136d6424 Mon Sep 17 00:00:00 2001 From: Erik Burton Date: Mon, 6 Nov 2023 13:24:15 -0800 Subject: [PATCH 083/327] chore: bump sigstore/cosign-installer from 2.1.0 to 3.1.2 (#11192) --- .github/actions/build-sign-publish-chainlink/action.yml | 2 +- .github/actions/goreleaser-build-sign-publish/action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-sign-publish-chainlink/action.yml b/.github/actions/build-sign-publish-chainlink/action.yml index fe4ef858f5..62add53092 100644 --- a/.github/actions/build-sign-publish-chainlink/action.yml +++ b/.github/actions/build-sign-publish-chainlink/action.yml @@ -223,7 +223,7 @@ runs: - if: inputs.sign-images == 'true' name: Install cosign - uses: sigstore/cosign-installer@581838fbedd492d2350a9ecd427a95d6de1e5d01 # v2.1.0 + uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 with: cosign-release: "v1.6.0" diff --git a/.github/actions/goreleaser-build-sign-publish/action.yml b/.github/actions/goreleaser-build-sign-publish/action.yml index 845d2443fc..b2d42c1234 100644 --- a/.github/actions/goreleaser-build-sign-publish/action.yml +++ b/.github/actions/goreleaser-build-sign-publish/action.yml @@ -84,7 +84,7 @@ runs: version: ${{ inputs.zig-version }} - name: Setup cosign if: inputs.enable-cosign == 'true' - uses: sigstore/cosign-installer@581838fbedd492d2350a9ecd427a95d6de1e5d01 # v2.1.0 + uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 with: cosign-release: ${{ inputs.cosign-version }} - name: Login to docker registry From c71ead762d71e8952698b1be303c158cbd6f74e0 Mon Sep 17 00:00:00 2001 From: Tate Date: Mon, 6 Nov 2023 17:00:15 -0700 Subject: [PATCH 084/327] [TT-668] Use Internal Mirror for docker images used in e2e tests (#11189) Part of the effor to remove the e2e flakes caused by dockerhub rate limit issues --- .github/workflows/integration-tests.yml | 4 ---- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 928c716dd1..125ddb3f4f 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -228,8 +228,6 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} @@ -429,8 +427,6 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }}${{ matrix.product.tag_suffix }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} artifacts_name: ${{ matrix.product.name }}-test-logs artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 936729944f..8daa5a29e5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,7 +22,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.4-0.20231106173929-20fe04d6ad66 + github.com/smartcontractkit/chainlink-testing-framework v1.18.4 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.28 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 7bd733023c..696e06b6c9 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2376,8 +2376,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.4-0.20231106173929-20fe04d6ad66 h1:AOqcHiAppMoIvM2WSJNIZzJDnOQNXyElbLFK3ZqoJeM= -github.com/smartcontractkit/chainlink-testing-framework v1.18.4-0.20231106173929-20fe04d6ad66/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.4 h1:IAalKSqRDSGj10zE/JvFrngKGp7mEIVTPh5jTnsaCec= +github.com/smartcontractkit/chainlink-testing-framework v1.18.4/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= From 0e5b5232e378263964f202ff4bb1712c4ad77813 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Tue, 7 Nov 2023 11:00:37 +0400 Subject: [PATCH 085/327] Fix Automation benchmark test (#11191) * fix benchmark test * bump runner --- .github/workflows/automation-benchmark-tests.yml | 2 +- integration-tests/benchmark/keeper_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index 7bdb66c919..a4338d642b 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -57,7 +57,7 @@ jobs: id-token: write contents: read name: ${{ inputs.network }} Automation Benchmark Test - runs-on: ubuntu-latest + runs-on: ubuntu20.04-16cores-64GB env: SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 25a147fbf0..9342f3629b 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -227,7 +227,7 @@ func addRegistry(registryToTest string) []eth_contracts.KeeperRegistryVersion { case "2_0-Multiple": return repeatRegistries(eth_contracts.RegistryVersion_2_0, NumberOfRegistries) case "2_1-Multiple": - return repeatRegistries(eth_contracts.RegistryVersion_1_0, NumberOfRegistries) + return repeatRegistries(eth_contracts.RegistryVersion_2_1, NumberOfRegistries) default: return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_0} } From fcaf226947ceece466df04e0524428f132ecc267 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Tue, 7 Nov 2023 10:12:36 +0100 Subject: [PATCH 086/327] Add to delegate job spec CaptureEATelemetry override from evm ocr cfg (#11197) * Add to delegate job spec CaptureEATelemetry override from evm ocr cfg * Add logs for when Ea telemetry is disabled * Update core/services/ocr/delegate.go Co-authored-by: Jordan Krage * Update core/services/ocr2/delegate.go * Update core/services/ocrcommon/data_source.go --------- Co-authored-by: Patrick Co-authored-by: Jordan Krage Co-authored-by: Gheorghe Strimtu --- core/services/ocr/delegate.go | 3 +++ core/services/ocr2/delegate.go | 2 ++ core/services/ocrcommon/data_source.go | 2 ++ 3 files changed, 7 insertions(+) diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index bbed43c151..6eb6714a47 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -295,10 +295,13 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e configOverrider = configOverriderService } + jb.OCROracleSpec.CaptureEATelemetry = chain.Config().OCR().CaptureEATelemetry() enhancedTelemChan := make(chan ocrcommon.EnhancedTelemetryData, 100) if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint("EVM", chain.ID().String(), concreteSpec.ContractAddress.String(), synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) services = append(services, enhancedTelemService) + } else { + lggr.Infow("Enhanced telemetry is disabled for job", "job", jb.Name) } oracle, err := ocr.NewOracle(ocr.OracleArgs{ diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 39a8c84d6b..99aa492bc7 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -746,6 +746,8 @@ func (d *Delegate) newServicesMedian( if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) medianServices = append(medianServices, enhancedTelemService) + } else { + lggr.Infow("Enhanced telemetry is disabled for job", "job", jb.Name) } return medianServices, err2 diff --git a/core/services/ocrcommon/data_source.go b/core/services/ocrcommon/data_source.go index ed832e45fc..0363a7124b 100644 --- a/core/services/ocrcommon/data_source.go +++ b/core/services/ocrcommon/data_source.go @@ -144,6 +144,8 @@ func (ds *inMemoryDataSource) executeRun(ctx context.Context, timestamp Observat FinalResults: finalResult, RepTimestamp: timestamp, }) + } else { + ds.lggr.Infow("Enhanced telemetry is disabled for job", "job", ds.jb.Name) } return run, finalResult, err From 48b9902f5dc931c6a2d06699ea26f660b65630f1 Mon Sep 17 00:00:00 2001 From: Mohamed Mehany <7327188+mohamed-mehany@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:11:36 +0100 Subject: [PATCH 087/327] Adds WeMix chain config (#10793) * Adds WeMix testnet config * Extending NoNewHeads threshold to 3s * Adds WeMix contract loader * Downgrading to go 1.20.5 bullseye * Revert "Downgrading to go 1.20.5 bullseye" This reverts commit 7eab839819456513dcf7f83ca8f08c97bdeb3835. * Update testing branch * Excludes fee delegation transactions for Wemix * Update testing branch * Linting * Fix typo * Update CTF --------- Co-authored-by: davidcauchi --- .github/workflows/on-demand-ocr-soak-test.yml | 2 + .../config/toml/defaults/WeMix_Mainnet.toml | 14 ++ .../config/toml/defaults/WeMix_Testnet.toml | 14 ++ .../evm/gas/block_history_estimator_test.go | 6 + core/chains/evm/gas/chain_specific.go | 7 + core/config/chaintype.go | 6 +- core/config/docs/chains-evm.toml | 2 +- core/services/chainlink/config_test.go | 4 +- core/services/ocr/contract_tracker.go | 2 +- docs/CONFIG.md | 160 +++++++++++++++++- .../contracts/contract_deployer.go | 6 + .../contracts/contract_loader.go | 7 + integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 14 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml create mode 100644 core/chains/evm/config/toml/defaults/WeMix_Testnet.toml diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 1e510c23be..b6ccad2246 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -28,6 +28,8 @@ on: - "FANTOM_MAINNET" - "KROMA_MAINNET" - "KROMA_SEPOLIA" + - "WEMIX_TESTNET" + - "WEMIX_MAINNET" fundingPrivateKey: description: Private funding key (Skip for Simulated) required: false diff --git a/core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml b/core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml new file mode 100644 index 0000000000..ee50a9844a --- /dev/null +++ b/core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml @@ -0,0 +1,14 @@ +ChainID = '1111' +ChainType = 'wemix' +FinalityDepth = 1 +MinIncomingConfirmations = 1 +# WeMix emits a block every 1 second, regardless of transactions +LogPollInterval = '3s' +NoNewHeadsThreshold = '30s' + +[OCR] +ContractConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +TipCapDefault = '100 gwei' diff --git a/core/chains/evm/config/toml/defaults/WeMix_Testnet.toml b/core/chains/evm/config/toml/defaults/WeMix_Testnet.toml new file mode 100644 index 0000000000..6cdb451eb1 --- /dev/null +++ b/core/chains/evm/config/toml/defaults/WeMix_Testnet.toml @@ -0,0 +1,14 @@ +ChainID = '1112' +ChainType = 'wemix' +FinalityDepth = 1 +MinIncomingConfirmations = 1 +# WeMix emits a block every 1 second, regardless of transactions +LogPollInterval = '3s' +NoNewHeadsThreshold = '30s' + +[OCR] +ContractConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +TipCapDefault = '100 gwei' diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index 7f4d157e37..decb68dbe9 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -1329,6 +1329,12 @@ func TestBlockHistoryEstimator_IsUsable(t *testing.T) { assert.Equal(t, true, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) }) + t.Run("returns false if transaction is of type 0x16 only on WeMix", func(t *testing.T) { + cfg.ChainTypeF = "wemix" + tx := evmtypes.Transaction{Type: 0x16, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + }) + t.Run("returns false if transaction has base fee higher than the gas price only on Celo", func(t *testing.T) { cfg.ChainTypeF = "celo" tx := evmtypes.Transaction{Type: 0x0, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} diff --git a/core/chains/evm/gas/chain_specific.go b/core/chains/evm/gas/chain_specific.go index 4d87b8b454..5c0b256bd3 100644 --- a/core/chains/evm/gas/chain_specific.go +++ b/core/chains/evm/gas/chain_specific.go @@ -42,5 +42,12 @@ func chainSpecificIsUsable(tx evmtypes.Transaction, baseFee *assets.Wei, chainTy return false } } + if chainType == config.ChainWeMix { + // WeMix specific transaction types that enables fee delegation. + // https://docs.wemix.com/v/en/design/fee-delegation + if tx.Type == 0x16 { + return false + } + } return true } diff --git a/core/config/chaintype.go b/core/config/chaintype.go index c99099ee61..0110f247b7 100644 --- a/core/config/chaintype.go +++ b/core/config/chaintype.go @@ -15,18 +15,18 @@ const ( ChainOptimismBedrock ChainType = "optimismBedrock" ChainXDai ChainType = "xdai" ChainCelo ChainType = "celo" + ChainWeMix ChainType = "wemix" ChainKroma ChainType = "kroma" ) var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{ string(ChainArbitrum), string(ChainMetis), string(ChainXDai), string(ChainOptimismBedrock), string(ChainCelo), - string(ChainKroma), -}, ", ")) + string(ChainKroma), string(ChainWeMix)}, ", ")) // IsValid returns true if the ChainType value is known or empty. func (c ChainType) IsValid() bool { switch c { - case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma: + case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma, ChainWeMix: return true } return false diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index 082bbd6cd1..c0cdfc7a31 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -14,7 +14,7 @@ BlockBackfillDepth = 10 # Default # BlockBackfillSkip enables skipping of very long backfills. BlockBackfillSkip = false # Default # ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma +# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix ChainType = 'arbitrum' # Example # FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID so it should not be necessary to change this under normal operation. # BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 59a02f1dcf..cc3fda167d 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -1190,7 +1190,7 @@ func TestConfig_Validate(t *testing.T) { - 1: 6 errors: - ChainType: invalid value (Foo): must not be set with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma or omitted + - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix or omitted - HeadTracker.HistoryDepth: invalid value (30): must be equal to or greater than FinalityDepth - GasEstimator: 2 errors: - FeeCapDefault: invalid value (101 wei): must be equal to PriceMax (99 wei) since you are using FixedPrice estimation with gas bumping disabled in EIP1559 mode - PriceMax will be used as the FeeCap for transactions instead of FeeCapDefault @@ -1199,7 +1199,7 @@ func TestConfig_Validate(t *testing.T) { - 2: 5 errors: - ChainType: invalid value (Arbitrum): only "optimismBedrock" can be used with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma or omitted + - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix or omitted - FinalityDepth: invalid value (0): must be greater than or equal to 1 - MinIncomingConfirmations: invalid value (0): must be greater than or equal to 1 - 3.Nodes: 5 errors: diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 3a216e025f..2308fa3035 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -401,7 +401,7 @@ func (t *OCRContractTracker) LatestBlockHeight(ctx context.Context) (blockheight // care about the block height; we have no way of getting the L1 block // height anyway return 0, nil - case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma: + case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma, config.ChainWeMix: // continue } latestBlockHeight := t.getLatestBlockHeight() diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 4b55c804a3..fd8822c162 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -3302,6 +3302,164 @@ GasLimit = 5300000

+
WeMix Mainnet (1111)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'wemix' +FinalityDepth = 1 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '3s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '30s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '1m0s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '1 gwei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '5 gwei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = true +FeeCapDefault = '100 gwei' +TipCapDefault = '100 gwei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 1 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+ +
WeMix Testnet (1112)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'wemix' +FinalityDepth = 1 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '3s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '30s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '1m0s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '1 gwei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '5 gwei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = true +FeeCapDefault = '100 gwei' +TipCapDefault = '100 gwei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 1 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+
Simulated (1337)

```toml @@ -5074,7 +5232,7 @@ BlockBackfillSkip enables skipping of very long backfills. ChainType = 'arbitrum' # Example ``` ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma +Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix ### FinalityDepth ```toml diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 0c36a26081..916971f82d 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -175,6 +175,8 @@ func NewContractDeployer(bcClient blockchain.EVMClient, logger zerolog.Logger) ( return &FantomContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.KromaClient: return &KromaContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil + case *blockchain.WeMixClient: + return &WeMixContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract deployer, register blockchain client in NewContractDeployer") } @@ -246,6 +248,10 @@ type KromaContractDeployer struct { *EthereumContractDeployer } +type WeMixContractDeployer struct { + *EthereumContractDeployer +} + // NewEthereumContractDeployer returns an instantiated instance of the ETH contract deployer func NewEthereumContractDeployer(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractDeployer { return &EthereumContractDeployer{ diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 4dda2d3f0c..cfe7a35467 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -64,6 +64,8 @@ func NewContractLoader(bcClient blockchain.EVMClient, logger zerolog.Logger) (Co return &OptimismContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.PolygonZkEvmClient: return &PolygonZkEvmContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.WeMixClient: + return &WeMixContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract Loader, register blockchain client in NewContractLoader") } @@ -107,6 +109,11 @@ type PolygonZKEVMContractLoader struct { *EthereumContractLoader } +// WeMixContractLoader wraps for WeMix +type WeMixContractLoader struct { + *EthereumContractLoader +} + // NewEthereumContractLoader returns an instantiated instance of the ETH contract Loader func NewEthereumContractLoader(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractLoader { return &EthereumContractLoader{ diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 8daa5a29e5..dab3cfa64b 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,7 +22,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.4 + github.com/smartcontractkit/chainlink-testing-framework v1.18.5-0.20231107092923-3aa655167f65 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.28 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 696e06b6c9..e8ee06ff49 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2376,8 +2376,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.4 h1:IAalKSqRDSGj10zE/JvFrngKGp7mEIVTPh5jTnsaCec= -github.com/smartcontractkit/chainlink-testing-framework v1.18.4/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.5-0.20231107092923-3aa655167f65 h1:/iRhwYy5KFsaS9Zo1T64QxAd11HGZB5p/LHI5oVc4BU= +github.com/smartcontractkit/chainlink-testing-framework v1.18.5-0.20231107092923-3aa655167f65/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= From cc308a14d879478933de95c3a153e3cb7cf1a3b2 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Tue, 7 Nov 2023 13:22:56 +0100 Subject: [PATCH 088/327] fix mockery version (#11199) --- contracts/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index b477164a49..e41d6422c2 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -34,7 +34,7 @@ abigen: ## Build & install abigen. .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.28.1 + go install github.com/vektra/mockery/v2@v2.35.4 .PHONY: foundry foundry: ## Install foundry. From 302eb05d592132309b264e316f443f1ceb81b6c3 Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 7 Nov 2023 13:57:26 +0000 Subject: [PATCH 089/327] [BCF-2632] Adapt median to POC (#11178) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/ocr2/delegate.go | 9 +- .../generic/pipeline_runner_adapter.go | 12 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- plugins/cmd/chainlink-medianpoc/main.go | 42 ++++++ plugins/medianpoc/data_source.go | 79 +++++++++++ plugins/medianpoc/data_source_test.go | 115 ++++++++++++++++ plugins/medianpoc/plugin.go | 126 ++++++++++++++++++ plugins/medianpoc/plugin_test.go | 105 +++++++++++++++ 13 files changed, 489 insertions(+), 17 deletions(-) create mode 100644 plugins/cmd/chainlink-medianpoc/main.go create mode 100644 plugins/medianpoc/data_source.go create mode 100644 plugins/medianpoc/data_source_test.go create mode 100644 plugins/medianpoc/plugin.go create mode 100644 plugins/medianpoc/plugin_test.go diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 8d731f3f41..7766697c60 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -305,7 +305,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 // 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 ebab8c990d..5149148d03 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1466,8 +1466,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de h1:CeVpn5xEdmuEsYE8ss2b7bSq9h3BY4OPvpqXeYIPnHw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 h1:nhhEtc7+u/92CGVE36/mpQCVB8MhrC3ZE3pAFbOvhd4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41/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/ocr2/delegate.go b/core/services/ocr2/delegate.go index 99aa492bc7..75147ca233 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -596,10 +596,11 @@ func (d *Delegate) newServicesGenericPlugin( } pluginConfig := types.ReportingPluginServiceConfig{ - PluginName: cconf.PluginName, - Command: command, - ProviderType: cconf.ProviderType, - PluginConfig: string(p.PluginConfig), + PluginName: cconf.PluginName, + Command: command, + ProviderType: cconf.ProviderType, + TelemetryType: cconf.TelemetryType, + PluginConfig: string(p.PluginConfig), } pr := generic.NewPipelineRunnerAdapter(pluginLggr, jb, d.pipelineRunner) diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go index 6afb35ca75..def33114e8 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go @@ -23,7 +23,7 @@ type PipelineRunnerAdapter struct { logger logger.Logger } -func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, vars types.Vars, options types.Options) ([]types.TaskResult, error) { +func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, vars types.Vars, options types.Options) (types.TaskResults, error) { s := pipeline.Spec{ DotDagSource: spec, CreatedAt: time.Now(), @@ -54,9 +54,13 @@ func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, var taskResults[i] = types.TaskResult{ ID: trr.ID.String(), Type: string(trr.Task.Type()), - Value: trr.Result.Value, - Error: trr.Result.Error, - Index: int(trr.TaskRun.Index), + Index: int(trr.Task.OutputIndex()), + + TaskValue: types.TaskValue{ + Value: trr.Result.Value, + Error: trr.Result.Error, + IsTerminal: len(trr.Task.Outputs()) == 0, + }, } } return taskResults, nil diff --git a/go.mod b/go.mod index 4d8a929402..a5628eb4b8 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.20231101160906-7acebcc1b353 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 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-20231020123319-d255366a6545 diff --git a/go.sum b/go.sum index acd966e8aa..a35e0f32bd 100644 --- a/go.sum +++ b/go.sum @@ -1467,8 +1467,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de h1:CeVpn5xEdmuEsYE8ss2b7bSq9h3BY4OPvpqXeYIPnHw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 h1:nhhEtc7+u/92CGVE36/mpQCVB8MhrC3ZE3pAFbOvhd4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41/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 dab3cfa64b..3c5a5e1f2e 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -388,7 +388,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 // 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 e8ee06ff49..cd5cb84a68 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2370,8 +2370,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de h1:CeVpn5xEdmuEsYE8ss2b7bSq9h3BY4OPvpqXeYIPnHw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231102162027-5fdce33763de/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 h1:nhhEtc7+u/92CGVE36/mpQCVB8MhrC3ZE3pAFbOvhd4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41/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/plugins/cmd/chainlink-medianpoc/main.go b/plugins/cmd/chainlink-medianpoc/main.go new file mode 100644 index 0000000000..325de6538f --- /dev/null +++ b/plugins/cmd/chainlink-medianpoc/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "github.com/hashicorp/go-plugin" + + "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-relay/pkg/loop/reportingplugins" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/plugins/medianpoc" +) + +const ( + loggerName = "PluginMedianPoc" +) + +func main() { + s := loop.MustNewStartedServer(loggerName) + defer s.Stop() + + p := medianpoc.NewPlugin(s.Logger) + defer s.Logger.ErrorIfFn(p.Close, "Failed to close") + + s.MustRegister(p) + + stop := make(chan struct{}) + defer close(stop) + + plugin.Serve(&plugin.ServeConfig{ + HandshakeConfig: reportingplugins.ReportingPluginHandshakeConfig(), + Plugins: map[string]plugin.Plugin{ + reportingplugins.PluginServiceName: &reportingplugins.GRPCService[types.MedianProvider]{ + PluginServer: p, + BrokerConfig: loop.BrokerConfig{ + Logger: s.Logger, + StopCh: stop, + GRPCOpts: s.GRPCOpts, + }, + }, + }, + GRPCServer: s.GRPCOpts.NewServer, + }) +} diff --git a/plugins/medianpoc/data_source.go b/plugins/medianpoc/data_source.go new file mode 100644 index 0000000000..7b20f1e5eb --- /dev/null +++ b/plugins/medianpoc/data_source.go @@ -0,0 +1,79 @@ +package medianpoc + +import ( + "context" + "errors" + "fmt" + "math/big" + "sync" + "time" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type DataSource struct { + pipelineRunner types.PipelineRunnerService + spec string + lggr logger.Logger + + current bridges.BridgeMetaData + mu sync.RWMutex +} + +func (d *DataSource) Observe(ctx context.Context, reportTimestamp ocrtypes.ReportTimestamp) (*big.Int, error) { + md, err := bridges.MarshalBridgeMetaData(d.currentAnswer()) + if err != nil { + d.lggr.Warnw("unable to attach metadata for run", "err", err) + } + + // NOTE: job metadata is automatically attached by the pipeline runner service + vars := types.Vars{ + Vars: map[string]interface{}{ + "jobRun": md, + }, + } + + results, err := d.pipelineRunner.ExecuteRun(ctx, d.spec, vars, types.Options{}) + if err != nil { + return nil, err + } + + finalResults := results.FinalResults() + if len(finalResults) == 0 { + return nil, errors.New("pipeline execution failed: not enough results") + } + + finalResult := finalResults[0] + if finalResult.Error != nil { + return nil, fmt.Errorf("pipeline execution failed: %w", finalResult.Error) + } + + asDecimal, err := utils.ToDecimal(finalResult.Value) + if err != nil { + return nil, errors.New("cannot convert observation to decimal") + } + + resultAsBigInt := asDecimal.BigInt() + d.updateAnswer(resultAsBigInt) + return resultAsBigInt, nil +} + +func (d *DataSource) currentAnswer() (*big.Int, *big.Int) { + d.mu.RLock() + defer d.mu.RUnlock() + return d.current.LatestAnswer, d.current.UpdatedAt +} + +func (d *DataSource) updateAnswer(latestAnswer *big.Int) { + d.mu.Lock() + defer d.mu.Unlock() + d.current = bridges.BridgeMetaData{ + LatestAnswer: latestAnswer, + UpdatedAt: big.NewInt(time.Now().Unix()), + } +} diff --git a/plugins/medianpoc/data_source_test.go b/plugins/medianpoc/data_source_test.go new file mode 100644 index 0000000000..e9a7945cee --- /dev/null +++ b/plugins/medianpoc/data_source_test.go @@ -0,0 +1,115 @@ +package medianpoc + +import ( + "context" + "errors" + "math/big" + "testing" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" +) + +type mockPipelineRunner struct { + results types.TaskResults + err error + spec string + vars types.Vars + options types.Options +} + +func (m *mockPipelineRunner) ExecuteRun(ctx context.Context, spec string, vars types.Vars, options types.Options) (types.TaskResults, error) { + m.spec = spec + m.vars = vars + m.options = options + return m.results, m.err +} + +func TestDataSource(t *testing.T) { + lggr := logger.TestLogger(t) + expect := int64(3) + pr := &mockPipelineRunner{ + results: types.TaskResults{ + { + TaskValue: types.TaskValue{ + Value: expect, + Error: nil, + IsTerminal: true, + }, + Index: 2, + }, + { + TaskValue: types.TaskValue{ + Value: int(4), + Error: nil, + IsTerminal: false, + }, + Index: 1, + }, + }, + } + spec := "SPEC" + ds := &DataSource{ + pipelineRunner: pr, + spec: spec, + lggr: lggr, + } + res, err := ds.Observe(context.Background(), ocrtypes.ReportTimestamp{}) + require.NoError(t, err) + assert.Equal(t, big.NewInt(expect), res) + assert.Equal(t, spec, pr.spec) + assert.Equal(t, big.NewInt(expect), ds.current.LatestAnswer) +} + +func TestDataSource_ResultErrors(t *testing.T) { + lggr := logger.TestLogger(t) + pr := &mockPipelineRunner{ + results: types.TaskResults{ + { + TaskValue: types.TaskValue{ + Error: errors.New("something went wrong"), + IsTerminal: true, + }, + Index: 0, + }, + }, + } + spec := "SPEC" + ds := &DataSource{ + pipelineRunner: pr, + spec: spec, + lggr: lggr, + } + _, err := ds.Observe(context.Background(), ocrtypes.ReportTimestamp{}) + assert.ErrorContains(t, err, "something went wrong") +} + +func TestDataSource_ResultNotAnInt(t *testing.T) { + lggr := logger.TestLogger(t) + + expect := "string-result" + pr := &mockPipelineRunner{ + results: types.TaskResults{ + { + TaskValue: types.TaskValue{ + Value: expect, + IsTerminal: true, + }, + Index: 0, + }, + }, + } + spec := "SPEC" + ds := &DataSource{ + pipelineRunner: pr, + spec: spec, + lggr: lggr, + } + _, err := ds.Observe(context.Background(), ocrtypes.ReportTimestamp{}) + assert.ErrorContains(t, err, "cannot convert observation to decimal") +} diff --git a/plugins/medianpoc/plugin.go b/plugins/medianpoc/plugin.go new file mode 100644 index 0000000000..ceea1eb84f --- /dev/null +++ b/plugins/medianpoc/plugin.go @@ -0,0 +1,126 @@ +package medianpoc + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-relay/pkg/loop/reportingplugins" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +func NewPlugin(lggr logger.Logger) *Plugin { + return &Plugin{ + Plugin: loop.Plugin{Logger: lggr}, + MedianProviderServer: reportingplugins.MedianProviderServer{}, + stop: make(utils.StopChan), + } +} + +type Plugin struct { + loop.Plugin + stop utils.StopChan + reportingplugins.MedianProviderServer +} + +type jsonConfig struct { + Pipelines map[string]string `json:"pipelines"` +} + +func (j jsonConfig) defaultPipeline() (string, error) { + return j.getPipeline("__DEFAULT_PIPELINE__") +} + +func (j jsonConfig) getPipeline(key string) (string, error) { + v, ok := j.Pipelines[key] + if ok { + return v, nil + } + return "", fmt.Errorf("no pipeline found for %s", key) +} + +func (p *Plugin) NewReportingPluginFactory( + ctx context.Context, + config types.ReportingPluginServiceConfig, + provider types.MedianProvider, + pipelineRunner types.PipelineRunnerService, + telemetry types.TelemetryClient, + errorLog types.ErrorLog, +) (types.ReportingPluginFactory, error) { + f, err := p.newFactory(ctx, config, provider, pipelineRunner, telemetry, errorLog) + if err != nil { + return nil, err + } + s := &reportingPluginFactoryService{lggr: p.Logger, ReportingPluginFactory: f} + p.SubService(s) + return s, nil +} + +func (p *Plugin) newFactory(ctx context.Context, config types.ReportingPluginServiceConfig, provider types.MedianProvider, pipelineRunner types.PipelineRunnerService, telemetry types.TelemetryClient, errorLog types.ErrorLog) (*median.NumericalMedianFactory, error) { + jc := &jsonConfig{} + err := json.Unmarshal([]byte(config.PluginConfig), jc) + if err != nil { + return nil, err + } + + dp, err := jc.defaultPipeline() + if err != nil { + return nil, err + } + ds := &DataSource{ + pipelineRunner: pipelineRunner, + spec: dp, + lggr: p.Logger, + } + + jfp, err := jc.getPipeline("juelsPerFeeCoinPipeline") + if err != nil { + return nil, err + } + jds := &DataSource{ + pipelineRunner: pipelineRunner, + spec: jfp, + lggr: p.Logger, + } + factory := &median.NumericalMedianFactory{ + ContractTransmitter: provider.MedianContract(), + DataSource: ds, + JuelsPerFeeCoinDataSource: jds, + Logger: logger.NewOCRWrapper( + p.Logger, + true, + func(msg string) {}, + ), + OnchainConfigCodec: provider.OnchainConfigCodec(), + ReportCodec: provider.ReportCodec(), + } + return factory, nil +} + +type reportingPluginFactoryService struct { + services.StateMachine + lggr logger.Logger + ocrtypes.ReportingPluginFactory +} + +func (r *reportingPluginFactoryService) Name() string { return r.lggr.Name() } + +func (r *reportingPluginFactoryService) Start(ctx context.Context) error { + return r.StartOnce("ReportingPluginFactory", func() error { return nil }) +} + +func (r *reportingPluginFactoryService) Close() error { + return r.StopOnce("ReportingPluginFactory", func() error { return nil }) +} + +func (r *reportingPluginFactoryService) HealthReport() map[string]error { + return map[string]error{r.Name(): r.Healthy()} +} diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go new file mode 100644 index 0000000000..74a0695c6c --- /dev/null +++ b/plugins/medianpoc/plugin_test.go @@ -0,0 +1,105 @@ +package medianpoc + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +type mockErrorLog struct { + types.ErrorLog +} + +type mockOffchainConfigDigester struct { + ocrtypes.OffchainConfigDigester +} + +type mockContractTransmitter struct { + ocrtypes.ContractTransmitter +} + +type mockContractConfigTracker struct { + ocrtypes.ContractConfigTracker +} + +type mockReportCodec struct { + median.ReportCodec +} + +type mockMedianContract struct { + median.MedianContract +} + +type mockOnchainConfigCodec struct { + median.OnchainConfigCodec +} + +type provider struct { + types.Service +} + +func (p provider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester { + return mockOffchainConfigDigester{} +} + +func (p provider) ContractTransmitter() ocrtypes.ContractTransmitter { + return mockContractTransmitter{} +} + +func (p provider) ContractConfigTracker() ocrtypes.ContractConfigTracker { + return mockContractConfigTracker{} +} + +func (p provider) ReportCodec() median.ReportCodec { + return mockReportCodec{} +} + +func (p provider) MedianContract() median.MedianContract { + return mockMedianContract{} +} + +func (p provider) OnchainConfigCodec() median.OnchainConfigCodec { + return mockOnchainConfigCodec{} +} + +func TestNewPlugin(t *testing.T) { + lggr := logger.TestLogger(t) + p := NewPlugin(lggr) + + defaultSpec := "default-spec" + juelsPerFeeCoinSpec := "jpfc-spec" + config := types.ReportingPluginServiceConfig{ + PluginConfig: fmt.Sprintf( + `{"pipelines": {"__DEFAULT_PIPELINE__": "%s", "juelsPerFeeCoinPipeline": "%s"}}`, + defaultSpec, + juelsPerFeeCoinSpec, + ), + } + pr := &mockPipelineRunner{} + prov := provider{} + + f, err := p.newFactory( + context.Background(), + config, + prov, + pr, + nil, + mockErrorLog{}, + ) + require.NoError(t, err) + + ds := f.DataSource.(*DataSource) + assert.Equal(t, defaultSpec, ds.spec) + jpfcDs := f.JuelsPerFeeCoinDataSource.(*DataSource) + assert.Equal(t, juelsPerFeeCoinSpec, jpfcDs.spec) +} From b1c5a856d71f560883d2cb61d633c47660d41365 Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 7 Nov 2023 14:59:44 +0000 Subject: [PATCH 090/327] [fix] Pull in correct commit sha for pull request events (#11202) --- tools/flakeytests/utils.go | 44 +++++++++++++++++++++------------ tools/flakeytests/utils_test.go | 29 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/tools/flakeytests/utils.go b/tools/flakeytests/utils.go index 18ab43980b..7ead45c858 100644 --- a/tools/flakeytests/utils.go +++ b/tools/flakeytests/utils.go @@ -29,23 +29,16 @@ func DigString(mp map[string]interface{}, path []string) (string, error) { return vs, nil } -func GetGithubMetadata(repo string, eventName string, sha string, path string) Context { - event := map[string]interface{}{} - if path != "" { - r, err := os.Open(path) - if err != nil { - log.Fatalf("Error reading gh event at path: %s", path) - } - - d, err := io.ReadAll(r) - if err != nil { - log.Fatal("Error reading gh event into string") - } +func getGithubMetadata(repo string, eventName string, sha string, e io.Reader) Context { + d, err := io.ReadAll(e) + if err != nil { + log.Fatal("Error reading gh event into string") + } - err = json.Unmarshal(d, &event) - if err != nil { - log.Fatalf("Error unmarshaling gh event at path: %s", path) - } + event := map[string]interface{}{} + err = json.Unmarshal(d, &event) + if err != nil { + log.Fatalf("Error unmarshaling gh event at path") } basicCtx := &Context{Repository: repo, CommitSHA: sha, Type: eventName} @@ -58,8 +51,27 @@ func GetGithubMetadata(repo string, eventName string, sha string, path string) C } basicCtx.PullRequestURL = prURL + + // For pull request events, the $GITHUB_SHA variable doesn't actually + // contain the sha for the latest commit, as documented here: + // https://stackoverflow.com/a/68068674 + var newSha string + s, err := DigString(event, []string{"pull_request", "head", "sha"}) + if err == nil { + newSha = s + } + + basicCtx.CommitSHA = newSha return *basicCtx default: return *basicCtx } } + +func GetGithubMetadata(repo string, eventName string, sha string, path string) Context { + event, err := os.Open(path) + if err != nil { + log.Fatalf("Error reading gh event at path: %s", path) + } + return getGithubMetadata(repo, eventName, sha, event) +} diff --git a/tools/flakeytests/utils_test.go b/tools/flakeytests/utils_test.go index d3ef8eb602..17d597c3c0 100644 --- a/tools/flakeytests/utils_test.go +++ b/tools/flakeytests/utils_test.go @@ -1,6 +1,8 @@ package flakeytests import ( + "fmt" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -17,3 +19,30 @@ func TestDigString(t *testing.T) { require.NoError(t, err) assert.Equal(t, "some-url", out) } + +var prEventTemplate = ` +{ + "pull_request": { + "head": { + "sha": "%s" + }, + "_links": { + "html": { + "href": "%s" + } + } + } +} +` + +func TestGetGithubMetadata(t *testing.T) { + repo, eventName, sha, event := "chainlink", "merge_group", "a-sha", `{}` + ctx := getGithubMetadata(repo, eventName, sha, strings.NewReader(event)) + assert.Equal(t, Context{Repository: repo, CommitSHA: sha, Type: eventName}, 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)) + assert.Equal(t, Context{Repository: repo, CommitSHA: anotherSha, Type: eventName, PullRequestURL: url}, ctx) +} From 031d9d26c32171152dd29bcad10ccc2e93478a6d Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 7 Nov 2023 15:23:43 +0000 Subject: [PATCH 091/327] [chore] Pin to chainlink-relay@main (#11203) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 7766697c60..9dbe132346 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -305,7 +305,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 // 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 5149148d03..7025d38c20 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1466,8 +1466,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 h1:nhhEtc7+u/92CGVE36/mpQCVB8MhrC3ZE3pAFbOvhd4= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +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-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/go.mod b/go.mod index a5628eb4b8..d61b7b6f61 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.20231101160906-7acebcc1b353 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 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-20231020123319-d255366a6545 diff --git a/go.sum b/go.sum index a35e0f32bd..f2737ab3ae 100644 --- a/go.sum +++ b/go.sum @@ -1467,8 +1467,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 h1:nhhEtc7+u/92CGVE36/mpQCVB8MhrC3ZE3pAFbOvhd4= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +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-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 3c5a5e1f2e..6f2809df8c 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -388,7 +388,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.20231101160906-7acebcc1b353 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 // 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 cd5cb84a68..9e1be8b814 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2370,8 +2370,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.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41 h1:nhhEtc7+u/92CGVE36/mpQCVB8MhrC3ZE3pAFbOvhd4= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231106145532-206ff03d1d41/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +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-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= From f6f3cfefec2d2a44e23a000c1a6dbd64f40edd2f Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 7 Nov 2023 10:25:51 -0500 Subject: [PATCH 092/327] Simple delete queue for mercury transmitter (#11182) --- .../services/relay/evm/mercury/transmitter.go | 85 +++++++++++++++++-- docs/CHANGELOG.md | 5 ++ 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 88c3113abc..557210e58a 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -33,6 +33,7 @@ import ( var ( maxTransmitQueueSize = 10_000 + maxDeleteQueueSize = 10_000 transmitTimeout = 5 * time.Second ) @@ -60,6 +61,24 @@ var ( }, []string{"feedID"}, ) + transmitQueueDeleteErrorCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_transmit_queue_delete_error_count", + Help: "Running count of DB errors when trying to delete an item from the queue DB", + }, + []string{"feedID"}, + ) + transmitQueueInsertErrorCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_transmit_queue_insert_error_count", + Help: "Running count of DB errors when trying to insert an item into the queue DB", + }, + []string{"feedID"}, + ) + transmitQueuePushErrorCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_transmit_queue_push_error_count", + Help: "Running count of DB errors when trying to push an item onto the queue", + }, + []string{"feedID"}, + ) transmitServerErrorCount = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "mercury_transmit_server_error_count", Help: "Number of errored transmissions that failed due to an error returned by the mercury server", @@ -99,9 +118,14 @@ type mercuryTransmitter struct { queue *TransmitQueue wg sync.WaitGroup - transmitSuccessCount prometheus.Counter - transmitDuplicateCount prometheus.Counter - transmitConnectionErrorCount prometheus.Counter + deleteQueue chan *pb.TransmitRequest + + transmitSuccessCount prometheus.Counter + transmitDuplicateCount prometheus.Counter + transmitConnectionErrorCount prometheus.Counter + transmitQueueDeleteErrorCount prometheus.Counter + transmitQueueInsertErrorCount prometheus.Counter + transmitQueuePushErrorCount prometheus.Counter } var PayloadTypes = getPayloadTypes() @@ -139,9 +163,13 @@ func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrp make(chan (struct{})), nil, sync.WaitGroup{}, + make(chan *pb.TransmitRequest, maxDeleteQueueSize), transmitSuccessCount.WithLabelValues(feedIDHex), transmitDuplicateCount.WithLabelValues(feedIDHex), transmitConnectionErrorCount.WithLabelValues(feedIDHex), + transmitQueueDeleteErrorCount.WithLabelValues(feedIDHex), + transmitQueueInsertErrorCount.WithLabelValues(feedIDHex), + transmitQueuePushErrorCount.WithLabelValues(feedIDHex), } } @@ -164,6 +192,8 @@ func (mt *mercuryTransmitter) Start(ctx context.Context) (err error) { return err } mt.wg.Add(1) + go mt.runDeleteQueueLoop() + mt.wg.Add(1) go mt.runQueueLoop() return nil }) @@ -192,6 +222,46 @@ func (mt *mercuryTransmitter) HealthReport() map[string]error { return report } +func (mt *mercuryTransmitter) runDeleteQueueLoop() { + defer mt.wg.Done() + runloopCtx, cancel := mt.stopCh.Ctx(context.Background()) + defer cancel() + + // Exponential backoff for very rarely occurring errors (DB disconnect etc) + b := backoff.Backoff{ + Min: 1 * time.Second, + Max: 120 * time.Second, + Factor: 2, + Jitter: true, + } + + for { + select { + case req := <-mt.deleteQueue: + for { + if err := mt.persistenceManager.Delete(runloopCtx, req); err != nil { + mt.lggr.Errorw("Failed to delete transmit request record", "error", err, "req", req) + mt.transmitQueueDeleteErrorCount.Inc() + select { + case <-time.After(b.Duration()): + // Wait a backoff duration before trying to delete again + continue + case <-mt.stopCh: + // abort and return immediately on stop even if items remain in queue + return + } + } + break + } + // success + b.Reset() + case <-mt.stopCh: + // abort and return immediately on stop even if items remain in queue + return + } + } +} + func (mt *mercuryTransmitter) runQueueLoop() { defer mt.wg.Done() // Exponential backoff with very short retry interval (since latency is a priority) @@ -253,9 +323,10 @@ func (mt *mercuryTransmitter) runQueueLoop() { } } - if err := mt.persistenceManager.Delete(runloopCtx, t.Req); err != nil { - mt.lggr.Errorw("Failed to delete transmit request record", "error", err, "reportCtx", t.ReportCtx) - return + select { + case mt.deleteQueue <- t.Req: + default: + mt.lggr.Criticalw("Delete queue is full", "reportCtx", t.ReportCtx) } } } @@ -288,9 +359,11 @@ func (mt *mercuryTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes.R mt.lggr.Tracew("Transmit enqueue", "req", req, "report", report, "reportCtx", reportCtx, "signatures", signatures) if err := mt.persistenceManager.Insert(ctx, req, reportCtx); err != nil { + mt.transmitQueueInsertErrorCount.Inc() return err } if ok := mt.queue.Push(req, reportCtx); !ok { + mt.transmitQueuePushErrorCount.Inc() return errors.New("transmit queue is closed") } return nil diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a9f9d080f4..a10f9dd1c6 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added a new, optional WebServer authentication option that supports LDAP as a user identity provider. This enables user login access and user roles to be managed and provisioned via a centralized remote server that supports the LDAP protocol, which can be helpful when running multiple nodes. See the documentation for more information and config setup instructions. There is a new `[WebServer].AuthenticationMethod` config option, when set to `ldap` requires the new `[WebServer.LDAP]` config section to be defined, see the reference `docs/core.toml`. +- New prom metrics for mercury: + `mercury_transmit_queue_delete_error_count` + `mercury_transmit_queue_insert_error_count` + `mercury_transmit_queue_push_error_count` + Nops should consider alerting on these. ### Changed From 8b4e0f8db32502f928860b928e6102a96db78b07 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 7 Nov 2023 12:00:25 -0500 Subject: [PATCH 093/327] Update SimulatedBackendClient CallContext (#11164) * Update SimulatedBackendClient CallContext The function `CallContext` has different supported contract function calls than `BatchCallContext` even though the latter is simply a batch version of the former. This commit makes the two functions match both in the supported calls, but also in the validation and execution of those calls. * Update core/chains/evm/client/simulated_backend_client.go Use suggestion on default address returned on error. Co-authored-by: Jordan Krage * replace errors with panics * align parameters to documentation, real-world RPCs, and the simulated backend client * allow different receipt types * comment on strong typing on result * remove logic for handling incomplete transaction receipt handling on simulated backend client * reduce panics in favor of errors * remove commented code --------- Co-authored-by: Jordan Krage --- .../evm/client/simulated_backend_client.go | 503 ++++++++---------- core/chains/evm/txmgr/transmitchecker.go | 2 +- .../plugins/ocr2keeper/evm21/core/utils.go | 17 +- 3 files changed, 235 insertions(+), 287 deletions(-) diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 7823908967..d542e98e6e 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -25,6 +25,41 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) +func init() { + var err error + + balanceOfABI, err = abi.JSON(strings.NewReader(balanceOfABIString)) + if err != nil { + panic(fmt.Errorf("%w: while parsing erc20ABI", err)) + } +} + +var ( + balanceOfABIString = `[ + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +]` + + balanceOfABI abi.ABI +) + // SimulatedBackendClient is an Client implementation using a simulated // blockchain backend. Note that not all RPC methods are implemented here. type SimulatedBackendClient struct { @@ -51,69 +86,6 @@ func (c *SimulatedBackendClient) Dial(context.Context) error { // other simulated clients might still be using it func (c *SimulatedBackendClient) Close() {} -// checkEthCallArgs extracts and verifies the arguments for an eth_call RPC -func (c *SimulatedBackendClient) checkEthCallArgs( - args []interface{}) (*CallArgs, *big.Int, error) { - if len(args) != 2 { - return nil, nil, fmt.Errorf( - "should have two arguments after \"eth_call\", got %d", len(args)) - } - callArgs, ok := args[0].(map[string]interface{}) - if !ok { - return nil, nil, fmt.Errorf("third arg to SimulatedBackendClient.Call "+ - "must be an eth.CallArgs, got %+#v", args[0]) - } - blockNumber, err := c.blockNumber(args[1]) - if err != nil { - return nil, nil, fmt.Errorf("fourth arg to SimulatedBackendClient.Call "+ - "must be the string \"latest\", or a *big.Int, got %#+v", args[1]) - } - - // to and from need to map to a common.Address but could come in as a string - var ( - toAddr common.Address - frmAddr common.Address - ) - - toAddr, err = interfaceToAddress(callArgs["to"]) - if err != nil { - return nil, nil, err - } - - // from is optional in the standard client; default to 0x when missing - if value, ok := callArgs["from"]; ok { - addr, err := interfaceToAddress(value) - if err != nil { - return nil, nil, err - } - - frmAddr = addr - } else { - frmAddr = common.HexToAddress("0x") - } - - ca := CallArgs{ - To: toAddr, - From: frmAddr, - Data: callArgs["data"].(hexutil.Bytes), - } - - return &ca, blockNumber, nil -} - -func interfaceToAddress(value interface{}) (common.Address, error) { - switch v := value.(type) { - case common.Address: - return v, nil - case string: - return common.HexToAddress(v), nil - case *big.Int: - return common.BigToAddress(v), nil - default: - return common.HexToAddress("0x"), fmt.Errorf("unrecognized value type for converting value to common.Address; try string, *big.Int, or common.Address") - } -} - // CallContext mocks the ethereum client RPC calls used by chainlink, copying the // return value into result. // The simulated client avoids the old block error from the simulated backend by @@ -121,41 +93,16 @@ func interfaceToAddress(value interface{}) (common.Address, error) { // and will not return an error when an old block is used. func (c *SimulatedBackendClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { switch method { + case "eth_getTransactionReceipt": + return c.ethGetTransactionReceipt(ctx, result, args...) + case "eth_getBlockByNumber": + return c.ethGetBlockByNumber(ctx, result, args...) case "eth_call": - var ( - callArgs *CallArgs - b []byte - err error - ) - - if callArgs, _, err = c.checkEthCallArgs(args); err != nil { - return err - } - - callMsg := ethereum.CallMsg{From: callArgs.From, To: &callArgs.To, Data: callArgs.Data} - - if b, err = c.b.CallContract(ctx, callMsg, nil /* always latest block */); err != nil { - return fmt.Errorf("%w: while calling contract at address %x with "+ - "data %x", err, callArgs.To, callArgs.Data) - } - - switch r := result.(type) { - case *hexutil.Bytes: - *r = append(*r, b...) - - if !bytes.Equal(*r, b) { - return fmt.Errorf("was passed a non-empty array, or failed to copy "+ - "answer. Expected %x = %x", *r, b) - } - return nil - default: - return fmt.Errorf("first arg to SimulatedBackendClient.Call is an "+ - "unrecognized type: %T; add processing logic for it here", result) - } + return c.ethCall(ctx, result, args...) + case "eth_getHeaderByNumber": + return c.ethGetHeaderByNumber(ctx, result, args...) default: - return fmt.Errorf("second arg to SimulatedBackendClient.Call is an RPC "+ - "API method which has not yet been implemented: %s. Add processing for "+ - "it here", method) + return fmt.Errorf("second arg to SimulatedBackendClient.Call is an RPC API method which has not yet been implemented: %s. Add processing for it here", method) } } @@ -175,38 +122,6 @@ func (c *SimulatedBackendClient) currentBlockNumber() *big.Int { return c.b.Blockchain().CurrentBlock().Number } -var balanceOfABIString = `[ - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "balance", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - } -]` - -var balanceOfABI abi.ABI - -func init() { - var err error - balanceOfABI, err = abi.JSON(strings.NewReader(balanceOfABIString)) - if err != nil { - panic(fmt.Errorf("%w: while parsing erc20ABI", err)) - } -} - func (c *SimulatedBackendClient) TokenBalance(ctx context.Context, address common.Address, contractAddress common.Address) (balance *big.Int, err error) { callData, err := balanceOfABI.Pack("balanceOf", address) if err != nil { @@ -251,13 +166,12 @@ func (c *SimulatedBackendClient) blockNumber(number interface{}) (blockNumber *b case "earliest": return big.NewInt(0), nil case "pending": - panic("not implemented") // I don't understand the semantics of this. + panic("pending block not supported by simulated backend client") // I don't understand the semantics of this. // return big.NewInt(0).Add(c.currentBlockNumber(), big.NewInt(1)), nil default: - blockNumber, err = utils.HexToUint256(n) + blockNumber, err := hexutil.DecodeBig(n) if err != nil { - return nil, fmt.Errorf("%w: while parsing '%s' as hex-encoded"+ - "block number", err, n) + return nil, fmt.Errorf("%w: while parsing '%s' as hex-encoded block number", err, n) } return blockNumber, nil } @@ -521,114 +435,18 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B for i, elem := range b { switch elem.Method { case "eth_getTransactionReceipt": - if _, ok := elem.Result.(*evmtypes.Receipt); !ok { - return fmt.Errorf("SimulatedBackendClient expected return type of *evmtypes.Receipt for eth_getTransactionReceipt, got type %T", elem.Result) - } - if len(elem.Args) != 1 { - return fmt.Errorf("SimulatedBackendClient expected 1 arg, got %d for eth_getTransactionReceipt", len(elem.Args)) - } - hash, is := elem.Args[0].(common.Hash) - if !is { - return fmt.Errorf("SimulatedBackendClient expected arg to be a hash, got: %T", elem.Args[0]) - } - receipt, err := c.b.TransactionReceipt(ctx, hash) - if receipt != nil { - *(b[i].Result.(*evmtypes.Receipt)) = *evmtypes.FromGethReceipt(receipt) - } - b[i].Error = err + b[i].Error = c.ethGetTransactionReceipt(ctx, b[i].Result, b[i].Args...) case "eth_getBlockByNumber": - switch v := elem.Result.(type) { - case *evmtypes.Head: - case *evmtypes.Block: - default: - return fmt.Errorf("SimulatedBackendClient expected return type of [*evmtypes.Head] or [*evmtypes.Block] for eth_getBlockByNumber, got type %T", v) - } - if len(elem.Args) != 2 { - return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getBlockByNumber", len(elem.Args)) - } - blockNumOrTag, is := elem.Args[0].(string) - if !is { - return fmt.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getBlockByNumber, got: %T", elem.Args[0]) - } - _, is = elem.Args[1].(bool) - if !is { - return fmt.Errorf("SimulatedBackendClient expected second arg to be a boolean for eth_getBlockByNumber, got: %T", elem.Args[1]) - } - header, err := c.fetchHeader(ctx, blockNumOrTag) - if err != nil { - return err - } - switch res := elem.Result.(type) { - case *evmtypes.Head: - res.Number = header.Number.Int64() - res.Hash = header.Hash() - res.ParentHash = header.ParentHash - res.Timestamp = time.Unix(int64(header.Time), 0).UTC() - case *evmtypes.Block: - res.Number = header.Number.Int64() - res.Hash = header.Hash() - res.ParentHash = header.ParentHash - res.Timestamp = time.Unix(int64(header.Time), 0).UTC() - default: - return fmt.Errorf("SimulatedBackendClient Unexpected Type %T", elem.Result) - } - b[i].Error = err + b[i].Error = c.ethGetBlockByNumber(ctx, b[i].Result, b[i].Args...) case "eth_call": - if len(elem.Args) != 2 { - return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_call", len(elem.Args)) - } - - _, ok := elem.Result.(*string) - if !ok { - return fmt.Errorf("SimulatedBackendClient expected result to be *string for eth_call, got: %T", elem.Result) - } - - params, ok := elem.Args[0].(map[string]interface{}) - if !ok { - return fmt.Errorf("SimulatedBackendClient expected first arg to be map[string]interface{} for eth_call, got: %T", elem.Args[0]) - } - - blockNum, ok := elem.Args[1].(string) - if !ok { - return fmt.Errorf("SimulatedBackendClient expected second arg to be a string for eth_call, got: %T", elem.Args[1]) - } - - if blockNum != "" { - if _, ok = new(big.Int).SetString(blockNum, 0); !ok { - return fmt.Errorf("error while converting block number string: %s to big.Int ", blockNum) - } - } - - callMsg := toCallMsg(params) - resp, err := c.b.CallContract(ctx, callMsg, nil) - *(b[i].Result.(*string)) = hexutil.Encode(resp) - b[i].Error = err + b[i].Error = c.ethCall(ctx, b[i].Result, b[i].Args...) case "eth_getHeaderByNumber": - if len(elem.Args) != 1 { - return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getHeaderByNumber", len(elem.Args)) - } - blockNum, is := elem.Args[0].(string) - if !is { - return fmt.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getHeaderByNumber, got: %T", elem.Args[0]) - } - n, err := hexutil.DecodeBig(blockNum) - if err != nil { - return fmt.Errorf("error while converting hex block number %s to big.Int ", blockNum) - } - header, err := c.b.HeaderByNumber(ctx, n) - if err != nil { - return err - } - switch v := elem.Result.(type) { - case *types.Header: - b[i].Result = header - default: - return fmt.Errorf("SimulatedBackendClient Unexpected Type %T", v) - } + b[i].Error = c.ethGetHeaderByNumber(ctx, b[i].Result, b[i].Args...) default: return fmt.Errorf("SimulatedBackendClient got unsupported method %s", elem.Method) } } + return nil } @@ -655,32 +473,175 @@ func (c *SimulatedBackendClient) Commit() common.Hash { return c.b.Commit() } -func toCallMsg(params map[string]interface{}) ethereum.CallMsg { - var callMsg ethereum.CallMsg +func (c *SimulatedBackendClient) IsL2() bool { + return false +} - switch to := params["to"].(type) { - case string: - toAddr := common.HexToAddress(to) - callMsg.To = &toAddr - case common.Address: - callMsg.To = &to - case *common.Address: - callMsg.To = to +func (c *SimulatedBackendClient) fetchHeader(ctx context.Context, blockNumOrTag string) (*types.Header, error) { + switch blockNumOrTag { + case rpc.SafeBlockNumber.String(): + return c.b.Blockchain().CurrentSafeBlock(), nil + case rpc.LatestBlockNumber.String(): + return c.b.Blockchain().CurrentHeader(), nil + case rpc.FinalizedBlockNumber.String(): + return c.b.Blockchain().CurrentFinalBlock(), nil default: - panic("unexpected type of 'to' parameter") + blockNum, ok := new(big.Int).SetString(blockNumOrTag, 0) + if !ok { + return nil, fmt.Errorf("error while converting block number string: %s to big.Int ", blockNumOrTag) + } + return c.b.HeaderByNumber(ctx, blockNum) } +} - switch from := params["from"].(type) { - case nil: - // This parameter is not required so nil is acceptable - case string: - callMsg.From = common.HexToAddress(from) - case common.Address: - callMsg.From = from - case *common.Address: - callMsg.From = *from +func (c *SimulatedBackendClient) ethGetTransactionReceipt(ctx context.Context, result interface{}, args ...interface{}) error { + if len(args) != 1 { + return fmt.Errorf("SimulatedBackendClient expected 1 arg, got %d for eth_getTransactionReceipt", len(args)) + } + + hash, is := args[0].(common.Hash) + if !is { + return fmt.Errorf("SimulatedBackendClient expected arg to be a hash, got: %T", args[0]) + } + + receipt, err := c.b.TransactionReceipt(ctx, hash) + if err != nil { + return err + } + + // strongly typing the result here has the consequence of not being flexible in + // custom types where a real-world RPC client would allow for custom types with + // custom marshalling. + switch typed := result.(type) { + case *types.Receipt: + *typed = *receipt + case *evmtypes.Receipt: + *typed = *evmtypes.FromGethReceipt(receipt) + default: + return fmt.Errorf("SimulatedBackendClient expected return type of *evmtypes.Receipt for eth_getTransactionReceipt, got type %T", result) + } + + return nil +} + +func (c *SimulatedBackendClient) ethGetBlockByNumber(ctx context.Context, result interface{}, args ...interface{}) error { + if len(args) != 2 { + return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getBlockByNumber", len(args)) + } + + blockNumOrTag, is := args[0].(string) + if !is { + return fmt.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getBlockByNumber, got: %T", args[0]) + } + + _, is = args[1].(bool) + if !is { + return fmt.Errorf("SimulatedBackendClient expected second arg to be a boolean for eth_getBlockByNumber, got: %T", args[1]) + } + + header, err := c.fetchHeader(ctx, blockNumOrTag) + if err != nil { + return err + } + + switch res := result.(type) { + case *evmtypes.Head: + res.Number = header.Number.Int64() + res.Hash = header.Hash() + res.ParentHash = header.ParentHash + res.Timestamp = time.Unix(int64(header.Time), 0).UTC() + case *evmtypes.Block: + res.Number = header.Number.Int64() + res.Hash = header.Hash() + res.ParentHash = header.ParentHash + res.Timestamp = time.Unix(int64(header.Time), 0).UTC() + default: + return fmt.Errorf("SimulatedBackendClient Unexpected Type %T", res) + } + + return nil +} + +func (c *SimulatedBackendClient) ethCall(ctx context.Context, result interface{}, args ...interface{}) error { + if len(args) != 2 { + return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_call", len(args)) + } + + params, ok := args[0].(map[string]interface{}) + if !ok { + return fmt.Errorf("SimulatedBackendClient expected first arg to be map[string]interface{} for eth_call, got: %T", args[0]) + } + + if _, err := c.blockNumber(args[1]); err != nil { + return fmt.Errorf("SimulatedBackendClient expected second arg to be the string 'latest' or a *big.Int for eth_call, got: %T", args[1]) + } + + resp, err := c.b.CallContract(ctx, toCallMsg(params), nil /* always latest block on simulated backend */) + if err != nil { + return err + } + + switch typedResult := result.(type) { + case *hexutil.Bytes: + *typedResult = append(*typedResult, resp...) + + if !bytes.Equal(*typedResult, resp) { + return fmt.Errorf("SimulatedBackendClient was passed a non-empty array, or failed to copy answer. Expected %x = %x", *typedResult, resp) + } + case *string: + *typedResult = hexutil.Encode(resp) default: - panic("unexpected type of 'from' parameter") + return fmt.Errorf("SimulatedBackendClient unexpected type %T", result) + } + + return nil +} + +func (c *SimulatedBackendClient) ethGetHeaderByNumber(ctx context.Context, result interface{}, args ...interface{}) error { + if len(args) != 1 { + return fmt.Errorf("SimulatedBackendClient expected 1 arg, got %d for eth_getHeaderByNumber", len(args)) + } + + blockNumber, err := c.blockNumber(args[0]) + if err != nil { + return fmt.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getHeaderByNumber: %w", err) + } + + header, err := c.b.HeaderByNumber(ctx, blockNumber) + if err != nil { + return err + } + + switch typedResult := result.(type) { + case *types.Header: + *typedResult = *header + default: + return fmt.Errorf("SimulatedBackendClient unexpected Type %T", typedResult) + } + + return nil +} + +func toCallMsg(params map[string]interface{}) ethereum.CallMsg { + var callMsg ethereum.CallMsg + + toAddr, err := interfaceToAddress(params["to"]) + if err != nil { + panic(fmt.Errorf("unexpected 'to' parameter: %s", err)) + } + + callMsg.To = &toAddr + + // from is optional in the standard client; default to 0x when missing + if value, ok := params["from"]; ok { + addr, err := interfaceToAddress(value) + if err != nil { + panic(fmt.Errorf("unexpected 'from' parameter: %s", err)) + } + + callMsg.From = addr + } else { + callMsg.From = common.HexToAddress("0x") } switch data := params["data"].(type) { @@ -691,7 +652,7 @@ func toCallMsg(params map[string]interface{}) ethereum.CallMsg { case []byte: callMsg.Data = data default: - panic("unexpected type of 'data' parameter") + panic("unexpected type of 'data' parameter; try hexutil.Bytes, []byte, or nil") } if value, ok := params["value"].(*big.Int); ok { @@ -709,23 +670,23 @@ func toCallMsg(params map[string]interface{}) ethereum.CallMsg { return callMsg } -func (c *SimulatedBackendClient) IsL2() bool { - return false -} +func interfaceToAddress(value interface{}) (common.Address, error) { + switch v := value.(type) { + case common.Address: + return v, nil + case string: + if ok := common.IsHexAddress(v); !ok { + return common.Address{}, fmt.Errorf("string not formatted as a hex encoded evm address") + } -func (c *SimulatedBackendClient) fetchHeader(ctx context.Context, blockNumOrTag string) (*types.Header, error) { - switch blockNumOrTag { - case rpc.SafeBlockNumber.String(): - return c.b.Blockchain().CurrentSafeBlock(), nil - case rpc.LatestBlockNumber.String(): - return c.b.Blockchain().CurrentHeader(), nil - case rpc.FinalizedBlockNumber.String(): - return c.b.Blockchain().CurrentFinalBlock(), nil - default: - blockNum, ok := new(big.Int).SetString(blockNumOrTag, 0) - if !ok { - return nil, fmt.Errorf("error while converting block number string: %s to big.Int ", blockNumOrTag) + return common.HexToAddress(v), nil + case *big.Int: + if v.Uint64() > 0 || len(v.Bytes()) > 20 { + return common.Address{}, fmt.Errorf("invalid *big.Int; value must be larger than 0 with a byte length <= 20") } - return c.b.HeaderByNumber(ctx, blockNum) + + return common.BigToAddress(v), nil + default: + return common.Address{}, fmt.Errorf("unrecognized value type for converting value to common.Address; use hex encoded string, *big.Int, or common.Address") } } diff --git a/core/chains/evm/txmgr/transmitchecker.go b/core/chains/evm/txmgr/transmitchecker.go index 4636b70848..eb6edd3f58 100644 --- a/core/chains/evm/txmgr/transmitchecker.go +++ b/core/chains/evm/txmgr/transmitchecker.go @@ -217,7 +217,7 @@ func (v *VRFV1Checker) Check( requestTransactionReceipt := &gethtypes.Receipt{} batch := []rpc.BatchElem{{ Method: "eth_getBlockByNumber", - Args: []interface{}{nil}, + Args: []interface{}{"latest", false}, Result: mostRecentHead, }, { Method: "eth_getTransactionReceipt", diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go index 6a31b938fc..1da28c1ad0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go @@ -3,7 +3,6 @@ package core import ( "context" "math/big" - "strings" "github.com/ethereum/go-ethereum/common" @@ -14,20 +13,8 @@ import ( // GetTxBlock calls eth_getTransactionReceipt on the eth client to obtain a tx receipt func GetTxBlock(ctx context.Context, client client.Client, txHash common.Hash) (*big.Int, common.Hash, error) { receipt := types.Receipt{} - err := client.CallContext(ctx, &receipt, "eth_getTransactionReceipt", txHash) - if err != nil { - if strings.Contains(err.Error(), "not yet been implemented") { - // workaround for simulated chains - // Exploratory: fix this properly (e.g. in the simulated backend) - r, err1 := client.TransactionReceipt(ctx, txHash) - if err1 != nil { - return nil, common.Hash{}, err1 - } - if r.Status != 1 { - return nil, common.Hash{}, nil - } - return r.BlockNumber, r.BlockHash, nil - } + + if err := client.CallContext(ctx, &receipt, "eth_getTransactionReceipt", txHash); err != nil { return nil, common.Hash{}, err } From 38de9a61c0233b412e9cf8a32011909022da6320 Mon Sep 17 00:00:00 2001 From: FelixFan1992 Date: Tue, 7 Nov 2023 12:08:01 -0500 Subject: [PATCH 094/327] add a TODO for 206 response parsing (#11188) --- .../plugins/ocr2keeper/evm21/streams_lookup.go | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go index f183e1f6bb..660550afe9 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go @@ -514,20 +514,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa state = encoding.MercuryFlakyFailure return fmt.Errorf("%d", resp.StatusCode) } else if resp.StatusCode == http.StatusPartialContent { - //var response MercuryV03Response - //err1 = json.Unmarshal(body, &response) - //if err1 != nil { - // lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.Time.String(), sl.upkeepId.String(), err1) - // retryable = false - // state = encoding.MercuryUnmarshalError - // return err1 - //} - // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract - // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated - //var receivedFeeds []string - //for _, f := range response.Reports { - // receivedFeeds = append(receivedFeeds, f.FeedID) - //} + // TODO (AUTO-5044): handle response code 206 entirely with errors field parsing lggr.Warnf("at timestamp %s upkeep %s requested [%s] feeds but mercury v0.3 server returned 206 status, treating it as 404 and retrying", sl.Time.String(), sl.upkeepId.String(), sl.Feeds) retryable = true state = encoding.MercuryFlakyFailure From 4e45a2ac05849703f34a4f5ce4ae539e9cfdcbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedemann=20F=C3=BCrst?= <59653747+friedemannf@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:43:02 +0100 Subject: [PATCH 095/327] Add zkSync support (#11162) * feat(zksync): add custom error messages * feat(zksync): add custom chain type to ignore 0x71 transaction type and commit default node config * fix: add exhaustive case stmt for zkSync ChainType * docs: regenerate CONFIG.md * test: add zksync ChainType to expected output * test: add test for custom zkSync tx type * fix: reduce HistoryDepth setting to 5 * ci: trigger pipelines * fix(zksync): also ignore tx type 0xff * docs(zksync): regenerate CONFIG.md --- core/chains/evm/client/errors.go | 18 +- core/chains/evm/client/errors_test.go | 16 ++ .../config/toml/defaults/zkSync_Goerli.toml | 14 ++ .../config/toml/defaults/zkSync_Mainnet.toml | 14 ++ .../evm/gas/block_history_estimator_test.go | 16 ++ core/chains/evm/gas/chain_specific.go | 7 + core/config/chaintype.go | 5 +- core/config/docs/chains-evm.toml | 2 +- core/scripts/common/helpers.go | 5 + core/services/chainlink/config_test.go | 4 +- core/services/ocr/contract_tracker.go | 2 +- docs/CONFIG.md | 160 +++++++++++++++++- 12 files changed, 255 insertions(+), 8 deletions(-) create mode 100644 core/chains/evm/config/toml/defaults/zkSync_Goerli.toml create mode 100644 core/chains/evm/config/toml/defaults/zkSync_Mainnet.toml diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 0d177455e3..4cb505dc9e 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -207,7 +207,23 @@ var harmony = ClientErrors{ Fatal: harmonyFatal, } -var clients = []ClientErrors{parity, geth, arbitrum, metis, substrate, avalanche, nethermind, harmony, besu, erigon, klaytn, celo} +var zkSync = ClientErrors{ + NonceTooLow: regexp.MustCompile(`(?:: |^)nonce too low\..+actual: \d*$`), + NonceTooHigh: regexp.MustCompile(`(?:: |^)nonce too high\..+actual: \d*$`), + TerminallyUnderpriced: regexp.MustCompile(`(?:: |^)max fee per gas less than block base fee$`), + InsufficientEth: regexp.MustCompile(`(?:: |^)(?:insufficient balance for transfer$|insufficient funds for gas + value)`), + TxFeeExceedsCap: regexp.MustCompile(`(?:: |^)max priority fee per gas higher than max fee per gas$`), + // intrinsic gas too low - gas limit less than 14700 + // Not enough gas for transaction validation - gas limit less than L2 fee + // Failed to pay the fee to the operator - gas limit less than L2+L1 fee + // Error function_selector = 0x, data = 0x - contract call with gas limit of 0 + // can't start a transaction from a non-account - trying to send from an invalid address, e.g. estimating a contract -> contract tx + // max fee per gas higher than 2^64-1 - uint64 overflow + // oversized data - data too large + Fatal: regexp.MustCompile(`(?:: |^)(?:exceeds block gas limit|intrinsic gas too low|Not enough gas for transaction validation|Failed to pay the fee to the operator|Error function_selector = 0x, data = 0x|invalid sender. can't start a transaction from a non-account|max(?: priority)? fee per (?:gas|pubdata byte) higher than 2\^64-1|oversized data. max: \d+; actual: \d+)$`), +} + +var clients = []ClientErrors{parity, geth, arbitrum, metis, substrate, avalanche, nethermind, harmony, besu, erigon, klaytn, celo, zkSync} func (s *SendError) is(errorType int) bool { if s == nil || s.err == nil { diff --git a/core/chains/evm/client/errors_test.go b/core/chains/evm/client/errors_test.go index a5a3cc15eb..ad8079824a 100644 --- a/core/chains/evm/client/errors_test.go +++ b/core/chains/evm/client/errors_test.go @@ -40,6 +40,7 @@ func Test_Eth_Errors(t *testing.T) { {"call failed: nonce too low: address 0x0499BEA33347cb62D79A9C0b1EDA01d8d329894c current nonce (5833) > tx nonce (5511)", true, "Avalanche"}, {"call failed: OldNonce", true, "Nethermind"}, {"call failed: OldNonce, Current nonce: 22, nonce of rejected tx: 17", true, "Nethermind"}, + {"nonce too low. allowed nonce range: 427 - 447, actual: 426", true, "zkSync"}, } for _, test := range tests { @@ -60,6 +61,7 @@ func Test_Eth_Errors(t *testing.T) { {"nonce too high: address 0x336394A3219e71D9d9bd18201d34E95C1Bb7122C, tx: 8089 state: 8090", true, "Arbitrum"}, {"nonce too high", true, "Geth"}, {"nonce too high", true, "Erigon"}, + {"nonce too high. allowed nonce range: 427 - 477, actual: 527", true, "zkSync"}, } for _, test := range tests { @@ -152,6 +154,7 @@ func Test_Eth_Errors(t *testing.T) { {"FeeTooLowToCompete", true, "Nethermind"}, {"transaction underpriced", true, "Klaytn"}, {"intrinsic gas too low", true, "Klaytn"}, + {"max fee per gas less than block base fee", true, "zkSync"}, } for _, test := range tests { @@ -194,6 +197,8 @@ func Test_Eth_Errors(t *testing.T) { {"call failed: InsufficientFunds, Account balance: 4740799397601480913, cumulative cost: 22019342038993800000", true, "Nethermind"}, {"insufficient funds", true, "Klaytn"}, {"insufficient funds for gas * price + value + gatewayFee", true, "celo"}, + {"insufficient balance for transfer", true, "zkSync"}, + {"insufficient funds for gas + value. balance: 42719769622667482000, fee: 48098250000000, value: 42719769622667482000", true, "celo"}, } for _, test := range tests { err = evmclient.NewSendErrorS(test.message) @@ -213,6 +218,7 @@ func Test_Eth_Errors(t *testing.T) { {"invalid gas fee cap", true, "Klaytn"}, {"max fee per gas higher than max priority fee per gas", true, "Klaytn"}, {"tx fee (1.10 of currency celo) exceeds the configured cap (1.00 celo)", true, "celo"}, + {"max priority fee per gas higher than max fee per gas", true, "zkSync"}, } for _, test := range tests { err = evmclient.NewSendErrorS(test.message) @@ -329,6 +335,16 @@ func Test_Eth_Errors_Fatal(t *testing.T) { {"`to` address of transaction in blacklist", true, "Harmony"}, {"`from` address of transaction in blacklist", true, "Harmony"}, {"staking message does not match directive message", true, "Harmony"}, + + {"intrinsic gas too low", true, "zkSync"}, + {"failed to validate the transaction. reason: Validation revert: Account validation error: Not enough gas for transaction validation", true, "zkSync"}, + {"failed to validate the transaction. reason: Validation revert: Failed to pay for the transaction: Failed to pay the fee to the operator", true, "zkSync"}, + {"failed to validate the transaction. reason: Validation revert: Account validation error: Error function_selector = 0x, data = 0x", true, "zkSync"}, + {"invalid sender. can't start a transaction from a non-account", true, "zkSync"}, + {"Failed to serialize transaction: max fee per gas higher than 2^64-1", true, "zkSync"}, + {"Failed to serialize transaction: max fee per pubdata byte higher than 2^64-1", true, "zkSync"}, + {"Failed to serialize transaction: max priority fee per gas higher than 2^64-1", true, "zkSync"}, + {"Failed to serialize transaction: oversized data. max: 1000000; actual: 1000000", true, "zkSync"}, } for _, test := range tests { diff --git a/core/chains/evm/config/toml/defaults/zkSync_Goerli.toml b/core/chains/evm/config/toml/defaults/zkSync_Goerli.toml new file mode 100644 index 0000000000..04529a41b8 --- /dev/null +++ b/core/chains/evm/config/toml/defaults/zkSync_Goerli.toml @@ -0,0 +1,14 @@ +ChainID = '280' +ChainType = 'zksync' +FinalityDepth = 1 +LogPollInterval = '5s' +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '1m' + +[GasEstimator] +LimitDefault = 3_500_000 +PriceMax = 18446744073709551615 +PriceMin = 0 + +[HeadTracker] +HistoryDepth = 5 diff --git a/core/chains/evm/config/toml/defaults/zkSync_Mainnet.toml b/core/chains/evm/config/toml/defaults/zkSync_Mainnet.toml new file mode 100644 index 0000000000..d7808edd15 --- /dev/null +++ b/core/chains/evm/config/toml/defaults/zkSync_Mainnet.toml @@ -0,0 +1,14 @@ +ChainID = '324' +ChainType = 'zksync' +FinalityDepth = 1 +LogPollInterval = '5s' +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '1m' + +[GasEstimator] +LimitDefault = 3_500_000 +PriceMax = 18446744073709551615 +PriceMin = 0 + +[HeadTracker] +HistoryDepth = 5 diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index decb68dbe9..c8b193c443 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -23,6 +23,7 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -1348,6 +1349,21 @@ func TestBlockHistoryEstimator_IsUsable(t *testing.T) { assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) assert.Equal(t, true, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) }) + + t.Run("returns false if transaction is of type 0x71 or 0xff only on zkSync", func(t *testing.T) { + cfg.ChainTypeF = string(config.ChainZkSync) + tx := evmtypes.Transaction{Type: 0x71, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + + tx.Type = 0x02 + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + + tx.Type = 0xff + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + + cfg.ChainTypeF = "" + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + }) } func TestBlockHistoryEstimator_EffectiveTipCap(t *testing.T) { diff --git a/core/chains/evm/gas/chain_specific.go b/core/chains/evm/gas/chain_specific.go index 5c0b256bd3..4f0d2e6b2f 100644 --- a/core/chains/evm/gas/chain_specific.go +++ b/core/chains/evm/gas/chain_specific.go @@ -49,5 +49,12 @@ func chainSpecificIsUsable(tx evmtypes.Transaction, baseFee *assets.Wei, chainTy return false } } + if chainType == config.ChainZkSync { + // zKSync specific type for contract deployment & priority transactions + // https://era.zksync.io/docs/reference/concepts/transactions.html#eip-712-0x71 + if tx.Type == 0x71 || tx.Type == 0xff { + return false + } + } return true } diff --git a/core/config/chaintype.go b/core/config/chaintype.go index 0110f247b7..21fb8cd297 100644 --- a/core/config/chaintype.go +++ b/core/config/chaintype.go @@ -17,16 +17,17 @@ const ( ChainCelo ChainType = "celo" ChainWeMix ChainType = "wemix" ChainKroma ChainType = "kroma" + ChainZkSync ChainType = "zksync" ) var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{ string(ChainArbitrum), string(ChainMetis), string(ChainXDai), string(ChainOptimismBedrock), string(ChainCelo), - string(ChainKroma), string(ChainWeMix)}, ", ")) + string(ChainKroma), string(ChainWeMix), string(ChainZkSync)}, ", ")) // IsValid returns true if the ChainType value is known or empty. func (c ChainType) IsValid() bool { switch c { - case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma, ChainWeMix: + case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma, ChainWeMix, ChainZkSync: return true } return false diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index c0cdfc7a31..381ab794d6 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -14,7 +14,7 @@ BlockBackfillDepth = 10 # Default # BlockBackfillSkip enables skipping of very long backfills. BlockBackfillSkip = false # Default # ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix +# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync ChainType = 'arbitrum' # Example # FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID so it should not be necessary to change this under normal operation. # BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain diff --git a/core/scripts/common/helpers.go b/core/scripts/common/helpers.go index d03dcec097..c141e8a29c 100644 --- a/core/scripts/common/helpers.go +++ b/core/scripts/common/helpers.go @@ -219,6 +219,11 @@ func explorerLinkPrefix(chainID int64) (prefix string) { case 8453: prefix = "https://basescan.org" + case 280: // zkSync Goerli testnet + prefix = "https://goerli.explorer.zksync.io" + case 324: // zkSync mainnet + prefix = "https://explorer.zksync.io" + default: // Unknown chain, return prefix as-is prefix = "" } diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index cc3fda167d..34fcc4bbe9 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -1190,7 +1190,7 @@ func TestConfig_Validate(t *testing.T) { - 1: 6 errors: - ChainType: invalid value (Foo): must not be set with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix or omitted + - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync or omitted - HeadTracker.HistoryDepth: invalid value (30): must be equal to or greater than FinalityDepth - GasEstimator: 2 errors: - FeeCapDefault: invalid value (101 wei): must be equal to PriceMax (99 wei) since you are using FixedPrice estimation with gas bumping disabled in EIP1559 mode - PriceMax will be used as the FeeCap for transactions instead of FeeCapDefault @@ -1199,7 +1199,7 @@ func TestConfig_Validate(t *testing.T) { - 2: 5 errors: - ChainType: invalid value (Arbitrum): only "optimismBedrock" can be used with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix or omitted + - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync or omitted - FinalityDepth: invalid value (0): must be greater than or equal to 1 - MinIncomingConfirmations: invalid value (0): must be greater than or equal to 1 - 3.Nodes: 5 errors: diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 2308fa3035..f49e556d4e 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -401,7 +401,7 @@ func (t *OCRContractTracker) LatestBlockHeight(ctx context.Context) (blockheight // care about the block height; we have no way of getting the L1 block // height anyway return 0, nil - case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma, config.ChainWeMix: + case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma, config.ChainWeMix, config.ChainZkSync: // continue } latestBlockHeight := t.getLatestBlockHeight() diff --git a/docs/CONFIG.md b/docs/CONFIG.md index fd8822c162..1eb9cd5023 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -2986,6 +2986,164 @@ GasLimit = 5300000

+
zkSync Goerli (280)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'zksync' +FinalityDepth = 1 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '5s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '1m0s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '1m0s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '18.446744073709551615 ether' +PriceMin = '0' +LimitDefault = 3500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '5 gwei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = false +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 5 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+ +
zkSync Mainnet (324)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'zksync' +FinalityDepth = 1 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '5s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '1m0s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '1m0s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '18.446744073709551615 ether' +PriceMin = '0' +LimitDefault = 3500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '5 gwei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = false +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 5 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+
Optimism Goerli (420)

```toml @@ -5232,7 +5390,7 @@ BlockBackfillSkip enables skipping of very long backfills. ChainType = 'arbitrum' # Example ``` ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix +Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync ### FinalityDepth ```toml From e4b50ff0516e172782d96ea96fcefd876742c5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedemann=20F=C3=BCrst?= <59653747+friedemannf@users.noreply.github.com> Date: Tue, 7 Nov 2023 19:45:37 +0100 Subject: [PATCH 096/327] Bump libocr => 13e0202ae8d7e38245422aa93af82010390f9e9b (#11212) * Bump libocr to 13e0202ae8d7e38245422aa93af82010390f9e9b * go mod tidy --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 9dbe132346..b72d07978f 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -21,7 +21,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 + github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7025d38c20..b1e62010ab 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1476,8 +1476,8 @@ github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88 github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= +github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= diff --git a/go.mod b/go.mod index d61b7b6f61..cd0fb0fab4 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 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-20231020123319-d255366a6545 + github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb diff --git a/go.sum b/go.sum index f2737ab3ae..fb97398f84 100644 --- a/go.sum +++ b/go.sum @@ -1477,8 +1477,8 @@ github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88 github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= +github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 6f2809df8c..eb542651b5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-testing-framework v1.18.5-0.20231107092923-3aa655167f65 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 + github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 9e1be8b814..ecafa2706e 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2382,8 +2382,8 @@ github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88 github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= +github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= From f5d6797e4f0af7a7d8e634b31daaecc098548c8c Mon Sep 17 00:00:00 2001 From: Tate Date: Tue, 7 Nov 2023 12:21:32 -0700 Subject: [PATCH 097/327] [TT-681] Remove usages of github.com/pkg/errors (#11213) --- integration-tests/actions/actions.go | 18 +-- integration-tests/actions/actions_local.go | 5 +- .../actions/automation_ocr_helpers_local.go | 3 +- .../actions/ocr_helpers_local.go | 9 +- integration-tests/actions/vrfv1/actions.go | 9 +- .../actions/vrfv2_actions/vrfv2_steps.go | 27 ++-- .../actions/vrfv2plus/vrfv2plus_steps.go | 127 +++++++++--------- .../contracts/ethereum_contracts.go | 5 +- .../contracts/ethereum_ocr2vrf_contracts.go | 23 ++-- integration-tests/docker/test_env/cl_node.go | 5 +- .../docker/test_env/cl_node_cluster.go | 5 +- integration-tests/docker/test_env/test_env.go | 12 +- .../docker/test_env/test_env_builder.go | 8 +- integration-tests/go.mod | 4 +- integration-tests/go.sum | 4 +- integration-tests/load/functions/config.go | 13 +- integration-tests/load/functions/gateway.go | 20 +-- integration-tests/load/functions/setup.go | 24 ++-- integration-tests/load/vrfv2/config.go | 11 +- integration-tests/load/vrfv2/vu.go | 7 +- integration-tests/load/vrfv2plus/config.go | 11 +- integration-tests/reorg/reorg_confirmer.go | 8 +- integration-tests/smoke/ocr2_test.go | 49 ------- integration-tests/smoke/ocr2vrf_test.go | 5 +- integration-tests/smoke/vrfv2plus_test.go | 8 +- 25 files changed, 189 insertions(+), 231 deletions(-) diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index b45b8e83b9..bacf5a9dbf 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -5,16 +5,16 @@ import ( "crypto/ecdsa" "encoding/json" "fmt" - "github.com/ethereum/go-ethereum/crypto" "math/big" "strings" "testing" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "go.uber.org/zap/zapcore" @@ -262,7 +262,7 @@ func TeardownSuite( ) error { l := logging.GetTestLogger(t) if err := testreporters.WriteTeardownLogs(t, env, optionalTestReporter, failingLogLevel); err != nil { - return errors.Wrap(err, "Error dumping environment logs, leaving environment running for manual retrieval") + return fmt.Errorf("Error dumping environment logs, leaving environment running for manual retrieval, err: %w", err) } // Delete all jobs to stop depleting the funds err := DeleteAllJobs(chainlinkNodes) @@ -330,16 +330,16 @@ func DeleteAllJobs(chainlinkNodes []*client.ChainlinkK8sClient) error { } jobs, _, err := node.ReadJobs() if err != nil { - return errors.Wrap(err, "error reading jobs from chainlink node") + return fmt.Errorf("error reading jobs from chainlink node, err: %w", err) } for _, maps := range jobs.Data { if _, ok := maps["id"]; !ok { - return errors.Errorf("error reading job id from chainlink node's jobs %+v", jobs.Data) + return fmt.Errorf("error reading job id from chainlink node's jobs %+v", jobs.Data) } id := maps["id"].(string) _, err := node.DeleteJob(id) if err != nil { - return errors.Wrap(err, "error deleting job from chainlink node") + return fmt.Errorf("error deleting job from chainlink node, err: %w", err) } } } @@ -350,7 +350,7 @@ func DeleteAllJobs(chainlinkNodes []*client.ChainlinkK8sClient) error { // all from a remote, k8s style environment func ReturnFunds(chainlinkNodes []*client.ChainlinkK8sClient, blockchainClient blockchain.EVMClient) error { if blockchainClient == nil { - return errors.New("blockchain client is nil, unable to return funds from chainlink nodes") + return fmt.Errorf("blockchain client is nil, unable to return funds from chainlink nodes") } log.Info().Msg("Attempting to return Chainlink node funds to default network wallets") if blockchainClient.NetworkSimulated() { @@ -416,7 +416,7 @@ func UpgradeChainlinkNodeVersions( nodes ...*client.ChainlinkK8sClient, ) error { if newImage == "" && newVersion == "" { - return errors.New("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") + return fmt.Errorf("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") } for _, node := range nodes { if err := node.UpgradeVersion(testEnvironment, newImage, newVersion); err != nil { @@ -455,7 +455,7 @@ func GenerateWallet() (common.Address, error) { publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { - return common.Address{}, errors.New("cannot assert type: publicKey is not of type *ecdsa.PublicKey") + return common.Address{}, fmt.Errorf("cannot assert type: publicKey is not of type *ecdsa.PublicKey") } return crypto.PubkeyToAddress(*publicKeyECDSA), nil } diff --git a/integration-tests/actions/actions_local.go b/integration-tests/actions/actions_local.go index b65bac43bb..f5d2a9035f 100644 --- a/integration-tests/actions/actions_local.go +++ b/integration-tests/actions/actions_local.go @@ -2,7 +2,8 @@ package actions import ( - "github.com/pkg/errors" + "fmt" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) @@ -13,7 +14,7 @@ func UpgradeChainlinkNodeVersionsLocal( nodes ...*test_env.ClNode, ) error { if newImage == "" && newVersion == "" { - return errors.New("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") + return fmt.Errorf("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") } for _, node := range nodes { if err := node.UpgradeVersion(node.NodeConfig, newImage, newVersion); err != nil { diff --git a/integration-tests/actions/automation_ocr_helpers_local.go b/integration-tests/actions/automation_ocr_helpers_local.go index ccc2eea99d..f541594c4d 100644 --- a/integration-tests/actions/automation_ocr_helpers_local.go +++ b/integration-tests/actions/automation_ocr_helpers_local.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" - "github.com/pkg/errors" "github.com/rs/zerolog" ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" @@ -187,7 +186,7 @@ func CreateOCRKeeperJobsLocal( } else if registryVersion == ethereum.RegistryVersion_2_0 { contractVersion = "v2.0" } else { - return errors.New("v2.0 and v2.1 are the only supported versions") + return fmt.Errorf("v2.0 and v2.1 are the only supported versions") } bootstrapSpec := &client.OCR2TaskJobSpec{ diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index 8bb4e83479..5836ee7945 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" @@ -280,7 +279,7 @@ func TrackForwarderLocal( chainID := chainClient.GetChainID() _, _, err := node.TrackForwarder(chainID, authorizedForwarder) if err != nil { - return errors.Wrap(err, "failed to track forwarder") + return fmt.Errorf("failed to track forwarder, err: %w", err) } logger.Info().Str("NodeURL", node.Config.URL). Str("ForwarderAddress", authorizedForwarder.Hex()). @@ -305,7 +304,7 @@ func DeployOCRContractsForwarderFlowLocal( contracts.DefaultOffChainAggregatorOptions(), ) if err != nil { - return nil, errors.Wrap(err, "failed to deploy offchain aggregator") + return nil, fmt.Errorf("failed to deploy offchain aggregator, err: %w", err) } ocrInstances = append(ocrInstances, ocrInstance) err = client.WaitForEvents() @@ -329,7 +328,7 @@ func DeployOCRContractsForwarderFlowLocal( for _, ocrInstance := range ocrInstances { err := ocrInstance.SetPayees(transmitters, payees) if err != nil { - return nil, errors.Wrap(err, "failed to set OCR payees") + return nil, fmt.Errorf("failed to set OCR payees, err: %w", err) } if err := client.WaitForEvents(); err != nil { return nil, err @@ -348,7 +347,7 @@ func DeployOCRContractsForwarderFlowLocal( forwarderAddresses, ) if err != nil { - return nil, errors.Wrap(err, "failed to set on-chain config") + return nil, fmt.Errorf("failed to set on-chain config, err: %w", err) } if err = client.WaitForEvents(); err != nil { return nil, err diff --git a/integration-tests/actions/vrfv1/actions.go b/integration-tests/actions/vrfv1/actions.go index 68d3e584ce..f8d7190709 100644 --- a/integration-tests/actions/vrfv1/actions.go +++ b/integration-tests/actions/vrfv1/actions.go @@ -1,7 +1,8 @@ package vrfv1 import ( - "github.com/pkg/errors" + "fmt" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) @@ -21,15 +22,15 @@ type Contracts struct { func DeployVRFContracts(cd contracts.ContractDeployer, bc blockchain.EVMClient, lt contracts.LinkToken) (*Contracts, error) { bhs, err := cd.DeployBlockhashStore() if err != nil { - return nil, errors.Wrap(err, ErrDeployBHSV1) + return nil, fmt.Errorf("%s, err %w", ErrDeployBHSV1, err) } coordinator, err := cd.DeployVRFCoordinator(lt.Address(), bhs.Address()) if err != nil { - return nil, errors.Wrap(err, ErrDeployVRFCootrinatorV1) + return nil, fmt.Errorf("%s, err %w", ErrDeployVRFCootrinatorV1, err) } consumer, err := cd.DeployVRFConsumer(lt.Address(), coordinator.Address()) if err != nil { - return nil, errors.Wrap(err, ErrDeployVRFConsumerV1) + return nil, fmt.Errorf("%s, err %w", ErrDeployVRFConsumerV1, err) } if err := bc.WaitForEvents(); err != nil { return nil, err diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go index 24ac217a33..a832d020b0 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go @@ -6,7 +6,6 @@ import ( "math/big" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -43,15 +42,15 @@ func DeployVRFV2Contracts( ) (*VRFV2Contracts, error) { bhs, err := contractDeployer.DeployBlockhashStore() if err != nil { - return nil, errors.Wrap(err, ErrDeployBlockHashStore) + return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) } coordinator, err := contractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) if err != nil { - return nil, errors.Wrap(err, ErrDeployCoordinator) + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) } loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinator.Address()) if err != nil { - return nil, errors.Wrap(err, ErrAdvancedConsumer) + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) } err = chainClient.WaitForEvents() if err != nil { @@ -70,7 +69,7 @@ func CreateVRFV2Jobs( for _, chainlinkNode := range chainlinkNodes { vrfKey, err := chainlinkNode.MustCreateVRFKey() if err != nil { - return nil, errors.Wrap(err, ErrCreatingVRFv2Key) + return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Key, err) } pubKeyCompressed := vrfKey.Data.ID jobUUID := uuid.New() @@ -79,11 +78,11 @@ func CreateVRFV2Jobs( } ost, err := os.String() if err != nil { - return nil, errors.Wrap(err, ErrParseJob) + return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) } nativeTokenPrimaryKeyAddress, err := chainlinkNode.PrimaryEthAddress() if err != nil { - return nil, errors.Wrap(err, ErrNodePrimaryKey) + return nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) } job, err := chainlinkNode.MustCreateJob(&client.VRFV2JobSpec{ Name: fmt.Sprintf("vrf-%s", jobUUID), @@ -97,15 +96,15 @@ func CreateVRFV2Jobs( BatchFulfillmentEnabled: false, }) if err != nil { - return nil, errors.Wrap(err, ErrCreatingVRFv2Job) + return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) } provingKey, err := VRFV2RegisterProvingKey(vrfKey, nativeTokenPrimaryKeyAddress, coordinator) if err != nil { - return nil, errors.Wrap(err, ErrCreatingProvingKey) + return nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKey, err) } keyHash, err := coordinator.HashOfKey(context.Background(), provingKey) if err != nil { - return nil, errors.Wrap(err, ErrCreatingProvingKeyHash) + return nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) } ji := VRFV2JobInfo{ Job: job, @@ -125,14 +124,14 @@ func VRFV2RegisterProvingKey( ) (VRFV2EncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return VRFV2EncodedProvingKey{}, errors.Wrap(err, ErrEncodingProvingKey) + return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( oracleAddress, provingKey, ) if err != nil { - return VRFV2EncodedProvingKey{}, errors.Wrap(err, ErrRegisterProvingKey) + return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) } return provingKey, nil } @@ -140,11 +139,11 @@ func VRFV2RegisterProvingKey( func FundVRFCoordinatorV2Subscription(linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, chainClient blockchain.EVMClient, subscriptionID uint64, linkFundingAmount *big.Int) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) if err != nil { - return errors.Wrap(err, ErrABIEncodingFunding) + return fmt.Errorf("%s, err %w", ErrABIEncodingFunding, err) } _, err = linkToken.TransferAndCall(coordinator.Address(), big.NewInt(0).Mul(linkFundingAmount, big.NewInt(1e18)), encodedSubId) if err != nil { - return errors.Wrap(err, ErrSendingLinkToken) + return fmt.Errorf("%s, err %w", ErrSendingLinkToken, err) } return chainClient.WaitForEvents() } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index e720116c21..e964623fb2 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -3,17 +3,17 @@ package vrfv2plus import ( "context" "fmt" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "math/big" "sync" "time" + "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -71,19 +71,19 @@ func DeployVRFV2_5Contracts( ) (*VRFV2_5Contracts, error) { bhs, err := contractDeployer.DeployBlockhashStore() if err != nil { - return nil, errors.Wrap(err, ErrDeployBlockHashStore) + return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } coordinator, err := contractDeployer.DeployVRFCoordinatorV2_5(bhs.Address()) if err != nil { - return nil, errors.Wrap(err, ErrDeployCoordinator) + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } consumers, err := DeployVRFV2PlusConsumers(contractDeployer, coordinator, consumerContractsAmount) if err != nil { @@ -91,7 +91,7 @@ func DeployVRFV2_5Contracts( } err = chainClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } return &VRFV2_5Contracts{coordinator, bhs, consumers}, nil } @@ -107,11 +107,11 @@ func DeployVRFV2PlusDirectFundingContracts( vrfv2PlusWrapper, err := contractDeployer.DeployVRFV2PlusWrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) if err != nil { - return nil, errors.Wrap(err, ErrDeployWrapper) + return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, linkTokenAddress, vrfv2PlusWrapper, consumerContractsAmount) @@ -120,7 +120,7 @@ func DeployVRFV2PlusDirectFundingContracts( } err = chainClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil } @@ -130,7 +130,7 @@ func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coord for i := 1; i <= consumerContractsAmount; i++ { loadTestConsumer, err := contractDeployer.DeployVRFv2PlusLoadTestConsumer(coordinator.Address()) if err != nil { - return nil, errors.Wrap(err, ErrAdvancedConsumer) + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) } consumers = append(consumers, loadTestConsumer) } @@ -142,7 +142,7 @@ func DeployVRFV2PlusWrapperConsumers(contractDeployer contracts.ContractDeployer for i := 1; i <= consumerContractsAmount; i++ { loadTestConsumer, err := contractDeployer.DeployVRFV2PlusWrapperLoadTestConsumer(linkTokenAddress, vrfV2PlusWrapper.Address()) if err != nil { - return nil, errors.Wrap(err, ErrAdvancedConsumer) + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) } consumers = append(consumers, loadTestConsumer) } @@ -163,7 +163,7 @@ func CreateVRFV2PlusJob( } ost, err := os.String() if err != nil { - return nil, errors.Wrap(err, ErrParseJob) + return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) } job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ @@ -178,7 +178,7 @@ func CreateVRFV2PlusJob( BatchFulfillmentEnabled: false, }) if err != nil { - return nil, errors.Wrap(err, ErrCreatingVRFv2PlusJob) + return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusJob, err) } return job, nil @@ -191,14 +191,14 @@ func VRFV2_5RegisterProvingKey( ) (VRFV2PlusEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return VRFV2PlusEncodedProvingKey{}, errors.Wrap(err, ErrEncodingProvingKey) + return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( oracleAddress, provingKey, ) if err != nil { - return VRFV2PlusEncodedProvingKey{}, errors.Wrap(err, ErrRegisterProvingKey) + return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) } return provingKey, nil } @@ -210,14 +210,14 @@ func VRFV2PlusUpgradedVersionRegisterProvingKey( ) (VRFV2PlusEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return VRFV2PlusEncodedProvingKey{}, errors.Wrap(err, ErrEncodingProvingKey) + return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( oracleAddress, provingKey, ) if err != nil { - return VRFV2PlusEncodedProvingKey{}, errors.Wrap(err, ErrRegisterProvingKey) + return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) } return provingKey, nil } @@ -231,11 +231,11 @@ func FundVRFCoordinatorV2_5Subscription( ) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) if err != nil { - return errors.Wrap(err, ErrABIEncodingFunding) + return fmt.Errorf("%s, err %w", ErrABIEncodingFunding, err) } _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) if err != nil { - return errors.Wrap(err, ErrSendingLinkToken) + return fmt.Errorf("%s, err %w", ErrSendingLinkToken, err) } return chainClient.WaitForEvents() } @@ -255,7 +255,7 @@ func SetupVRFV2_5Environment( l.Info().Msg("Deploying VRFV2 Plus contracts") vrfv2_5Contracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, env.EVMClient, numberOfConsumers) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrDeployVRFV2_5Contracts) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2_5Contracts, err) } l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") @@ -271,17 +271,17 @@ func SetupVRFV2_5Environment( }, ) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrSetVRFCoordinatorConfig) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetVRFCoordinatorConfig, err) } l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Link and ETH/LINK feed") err = vrfv2_5Contracts.Coordinator.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrSetLinkNativeLinkFeed) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetLinkNativeLinkFeed, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Int("Number of Subs to create", numberOfSubToCreate).Msg("Creating and funding subscriptions, adding consumers") subIDs, err := CreateFundSubsAndAddConsumers( @@ -295,25 +295,25 @@ func SetupVRFV2_5Environment( l.Info().Str("Node URL", env.ClCluster.NodeAPIs()[0].URL()).Msg("Creating VRF Key on the Node") vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrCreatingVRFv2PlusKey) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusKey, err) } pubKeyCompressed := vrfKey.Data.ID l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Registering Proving Key") provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2_5Contracts.Coordinator) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrRegisteringProvingKey) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRegisteringProvingKey, err) } keyHash, err := vrfv2_5Contracts.Coordinator.HashOfKey(context.Background(), provingKey) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrCreatingProvingKeyHash) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) } chainID := env.EVMClient.GetChainID() nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrNodePrimaryKey) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) } l.Info().Msg("Creating VRFV2 Plus Job") @@ -326,7 +326,7 @@ func SetupVRFV2_5Environment( vrfv2PlusConfig.MinimumConfirmations, ) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrCreateVRFV2PlusJobs) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) } // this part is here because VRFv2 can work with only a specific key @@ -334,7 +334,7 @@ func SetupVRFV2_5Environment( // Key = '...' addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrGetPrimaryKey) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrGetPrimaryKey, err) } nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, node.WithVRFv2EVMEstimator(addr), @@ -342,7 +342,7 @@ func SetupVRFV2_5Environment( l.Info().Msg("Restarting Node with new sending key PriceMax configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrRestartCLNode) + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRestartCLNode, err) } vrfv2PlusKeyData := VRFV2PlusKeyData{ @@ -391,7 +391,7 @@ func CreateFundSubsAndAddConsumers( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } return subIDs, nil } @@ -409,7 +409,7 @@ func CreateSubsAndFund( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, subs) if err != nil { @@ -443,7 +443,7 @@ func AddConsumersToSubs( for _, consumer := range consumers { err := coordinator.AddConsumer(subID, consumer.Address()) if err != nil { - return errors.Wrap(err, ErrAddConsumerToSub) + return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) } } } @@ -475,7 +475,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } err = wrapperContracts.VRFV2PlusWrapper.SetConfig( vrfv2PlusConfig.WrapperGasOverhead, @@ -494,7 +494,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } //fund sub @@ -505,7 +505,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, []*big.Int{wrapperSubID}) @@ -523,7 +523,7 @@ func SetupVRFV2PlusWrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } //fund consumer with Eth @@ -533,21 +533,24 @@ func SetupVRFV2PlusWrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } return wrapperContracts, wrapperSubID, nil } func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { tx, err := coordinator.CreateSubscription() if err != nil { - return nil, errors.Wrap(err, ErrCreateVRFSubscription) + return nil, fmt.Errorf("%s, err %w", ErrCreateVRFSubscription, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } //SubscriptionsCreated Log should be emitted with the subscription ID subID := receipt.Logs[0].Topics[1].Big() @@ -555,7 +558,7 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts //verify that the subscription was created _, err = coordinator.FindSubscriptionID(subID) if err != nil { - return nil, errors.Wrap(err, ErrFindSubID) + return nil, fmt.Errorf("%s, err %w", ErrFindSubID, err) } return subID, nil @@ -564,11 +567,11 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) if err != nil { - return nil, nil, errors.Wrap(err, ErrLinkTotalBalance) + return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) } nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) if err != nil { - return nil, nil, errors.Wrap(err, ErrNativeTokenBalance) + return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) } return } @@ -576,11 +579,11 @@ func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2Pl func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) if err != nil { - return nil, nil, errors.Wrap(err, ErrLinkTotalBalance) + return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) } nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) if err != nil { - return nil, nil, errors.Wrap(err, ErrNativeTokenBalance) + return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) } return } @@ -600,18 +603,18 @@ func FundSubscriptions( amountWei, ) if err != nil { - return errors.Wrap(err, ErrFundSubWithNativeToken) + return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) } //Link Billing amountJuels := utils.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountLink)) err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { - return errors.Wrap(err, ErrFundSubWithLinkToken) + return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) } } err := env.EVMClient.WaitForEvents() if err != nil { - return errors.Wrap(err, ErrWaitTXsComplete) + return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } return nil } @@ -638,7 +641,7 @@ func RequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest, ) if err != nil { - return nil, errors.Wrap(err, ErrRequestRandomness) + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) } return WaitForRequestAndFulfillmentEvents( @@ -672,7 +675,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { - return nil, errors.Wrap(err, ErrRequestRandomness) + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) } randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( @@ -682,7 +685,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( time.Minute*1, ) if err != nil { - return nil, errors.Wrap(err, ErrWaitRandomWordsRequestedEvent) + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) } LogRandomnessRequestedEventUpgraded(l, coordinator, randomWordsRequestedEvent) @@ -693,7 +696,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( time.Minute*2, ) if err != nil { - return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) } LogRandomWordsFulfilledEventUpgraded(l, coordinator, randomWordsFulfilledEvent) @@ -719,7 +722,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { - return nil, errors.Wrap(err, ErrRequestRandomnessDirectFundingNativePayment) + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingNativePayment, err) } } else { _, err := consumer.RequestRandomness( @@ -729,12 +732,12 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { - return nil, errors.Wrap(err, ErrRequestRandomnessDirectFundingLinkPayment) + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingLinkPayment, err) } } wrapperAddress, err := consumer.GetWrapper(context.Background()) if err != nil { - return nil, errors.Wrap(err, "error getting wrapper address") + return nil, fmt.Errorf("error getting wrapper address, err: %w", err) } return WaitForRequestAndFulfillmentEvents( wrapperAddress.String(), @@ -763,7 +766,7 @@ func WaitForRequestAndFulfillmentEvents( time.Minute*1, ) if err != nil { - return nil, errors.Wrap(err, ErrWaitRandomWordsRequestedEvent) + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) } LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) @@ -774,7 +777,7 @@ func WaitForRequestAndFulfillmentEvents( randomWordsFulfilledEventTimeout, ) if err != nil { - return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) } LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) @@ -817,7 +820,7 @@ func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadT func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator contracts.VRFCoordinatorV2_5, l zerolog.Logger) error { linkTotalBalance, err := coordinator.GetLinkTotalBalance(context.Background()) if err != nil { - return errors.Wrap(err, "Error getting LINK total balance") + return fmt.Errorf("Error getting LINK total balance, err: %w", err) } defaultWallet := client.GetDefaultWallet().Address() l.Info(). @@ -829,11 +832,11 @@ func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator co linkTotalBalance, ) if err != nil { - return errors.Wrap(err, "Error withdrawing LINK from coordinator to default wallet") + return fmt.Errorf("Error withdrawing LINK from coordinator to default wallet, err: %w", err) } nativeTotalBalance, err := coordinator.GetNativeTokenTotalBalance(context.Background()) if err != nil { - return errors.Wrap(err, "Error getting NATIVE total balance") + return fmt.Errorf("Error getting NATIVE total balance, err: %w", err) } l.Info(). Str("Native Token amount", linkTotalBalance.String()). @@ -844,7 +847,7 @@ func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator co nativeTotalBalance, ) if err != nil { - return errors.Wrap(err, "Error withdrawing NATIVE from coordinator to default wallet") + return fmt.Errorf("Error withdrawing NATIVE from coordinator to default wallet, err: %w", err) } return nil } diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index 5b3a93fe0c..cde6e325f2 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -13,7 +13,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -2162,11 +2161,11 @@ func (e *EthereumFunctionsRouter) CreateSubscriptionWithConsumer(consumer string topicOneInputs := abi.Arguments{fabi.Events["SubscriptionCreated"].Inputs[0]} topicOneHash := []common.Hash{r.Logs[0].Topics[1:][0]} if err := abi.ParseTopicsIntoMap(topicsMap, topicOneInputs, topicOneHash); err != nil { - return 0, errors.Wrap(err, "failed to decode topic value") + return 0, fmt.Errorf("failed to decode topic value, err: %w", err) } e.l.Info().Interface("NewTopicsDecoded", topicsMap).Send() if topicsMap["subscriptionId"] == 0 { - return 0, errors.New("failed to decode subscription ID after creation") + return 0, fmt.Errorf("failed to decode subscription ID after creation") } return topicsMap["subscriptionId"].(uint64), nil } diff --git a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go index e8149b2125..cb52d1941a 100644 --- a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go +++ b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" @@ -230,7 +229,7 @@ func (dkgContract *EthereumDKG) WaitForTransmittedEvent(timeout time.Duration) ( case err = <-subscription.Err(): return nil, err case <-time.After(timeout): - return nil, errors.New("timeout waiting for DKGTransmitted event") + return nil, fmt.Errorf("timeout waiting for DKGTransmitted event") case transmittedEvent := <-transmittedEventsChannel: return transmittedEvent, nil } @@ -250,7 +249,7 @@ func (dkgContract *EthereumDKG) WaitForConfigSetEvent(timeout time.Duration) (*d case err = <-subscription.Err(): return nil, err case <-time.After(timeout): - return nil, errors.New("timeout waiting for DKGConfigSet event") + return nil, fmt.Errorf("timeout waiting for DKGConfigSet event") case configSetEvent := <-configSetEventsChannel: return configSetEvent, nil } @@ -451,7 +450,7 @@ func (consumer *EthereumVRFBeaconConsumer) RequestRandomness( ) (*types.Receipt, error) { opts, err := consumer.client.TransactionOpts(consumer.client.GetDefaultWallet()) if err != nil { - return nil, errors.Wrap(err, "TransactionOpts failed") + return nil, fmt.Errorf("TransactionOpts failed, err: %w", err) } tx, err := consumer.vrfBeaconConsumer.TestRequestRandomness( opts, @@ -460,20 +459,20 @@ func (consumer *EthereumVRFBeaconConsumer) RequestRandomness( confirmationDelayArg, ) if err != nil { - return nil, errors.Wrap(err, "TestRequestRandomness failed") + return nil, fmt.Errorf("TestRequestRandomness failed, err: %w", err) } err = consumer.client.ProcessTransaction(tx) if err != nil { - return nil, errors.Wrap(err, "ProcessTransaction failed") + return nil, fmt.Errorf("ProcessTransaction failed, err: %w", err) } err = consumer.client.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, "WaitForEvents failed") + return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) } receipt, err := consumer.client.GetTxReceipt(tx.Hash()) if err != nil { - return nil, errors.Wrap(err, "GetTxReceipt failed") + return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) } log.Info().Interface("Sub ID", subID). Interface("Number of Words", numWords). @@ -526,20 +525,20 @@ func (consumer *EthereumVRFBeaconConsumer) RequestRandomnessFulfillment( arguments, ) if err != nil { - return nil, errors.Wrap(err, "TestRequestRandomnessFulfillment failed") + return nil, fmt.Errorf("TestRequestRandomnessFulfillment failed, err: %w", err) } err = consumer.client.ProcessTransaction(tx) if err != nil { - return nil, errors.Wrap(err, "ProcessTransaction failed") + return nil, fmt.Errorf("ProcessTransaction failed, err: %w", err) } err = consumer.client.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, "WaitForEvents failed") + return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) } receipt, err := consumer.client.GetTxReceipt(tx.Hash()) if err != nil { - return nil, errors.Wrap(err, "GetTxReceipt failed") + return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) } log.Info().Interface("Sub ID", subID). Interface("Number of Words", numWords). diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 4c40e64121..4de3d27d75 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -17,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" @@ -282,7 +281,7 @@ func (n *ClNode) StartContainer() error { Logger: l, }) if err != nil { - return errors.Wrap(err, ErrStartCLNodeContainer) + return fmt.Errorf("%s err: %w", ErrStartCLNodeContainer, err) } if n.lw != nil { if err := n.lw.ConnectContainer(context.Background(), container, "cl-node", true); err != nil { @@ -314,7 +313,7 @@ func (n *ClNode) StartContainer() error { }, n.l) if err != nil { - return errors.Wrap(err, ErrConnectNodeClient) + return fmt.Errorf("%s err: %w", ErrConnectNodeClient, err) } clClient.Config.InternalIP = n.ContainerName n.Container = container diff --git a/integration-tests/docker/test_env/cl_node_cluster.go b/integration-tests/docker/test_env/cl_node_cluster.go index 5ae90bb982..08122b5744 100644 --- a/integration-tests/docker/test_env/cl_node_cluster.go +++ b/integration-tests/docker/test_env/cl_node_cluster.go @@ -1,8 +1,9 @@ package test_env import ( + "fmt" + "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -61,7 +62,7 @@ func (c *ClCluster) NodeCSAKeys() ([]string, error) { for _, n := range c.Nodes { csaKeys, err := n.GetNodeCSAKeys() if err != nil { - return nil, errors.Wrap(err, ErrGetNodeCSAKeys) + return nil, fmt.Errorf("%s, err: %w", ErrGetNodeCSAKeys, err) } keys = append(keys, csaKeys.Data[0].ID) } diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index e067e46090..a6495bed54 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -8,11 +8,11 @@ import ( "math/big" "os" "path/filepath" + "runtime/debug" "testing" "time" "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" @@ -114,7 +114,7 @@ func (te *CLClusterTestEnv) StartPrivateChain() error { for _, chain := range te.PrivateChain { primaryNode := chain.GetPrimaryNode() if primaryNode == nil { - return errors.WithStack(fmt.Errorf("primary node is nil in PrivateChain interface")) + return fmt.Errorf("primary node is nil in PrivateChain interface, stack: %s", string(debug.Stack())) } err := primaryNode.Start() if err != nil { @@ -164,7 +164,7 @@ func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count i func (te *CLClusterTestEnv) FundChainlinkNodes(amount *big.Float) error { for _, cl := range te.ClCluster.Nodes { if err := cl.Fund(te.EVMClient, amount); err != nil { - return errors.Wrap(err, ErrFundCLNode) + return fmt.Errorf("%s, err: %w", ErrFundCLNode, err) } time.Sleep(5 * time.Second) } @@ -181,10 +181,10 @@ func (te *CLClusterTestEnv) Terminate() error { func (te *CLClusterTestEnv) Cleanup() error { te.l.Info().Msg("Cleaning up test environment") if te.t == nil { - return errors.New("cannot cleanup test environment without a testing.T") + return fmt.Errorf("cannot cleanup test environment without a testing.T") } if te.ClCluster == nil || len(te.ClCluster.Nodes) == 0 { - return errors.New("chainlink nodes are nil, unable cleanup chainlink nodes") + return fmt.Errorf("chainlink nodes are nil, unable cleanup chainlink nodes") } // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution @@ -196,7 +196,7 @@ func (te *CLClusterTestEnv) Cleanup() error { } if te.EVMClient == nil { - return errors.New("evm client is nil, unable to return funds from chainlink nodes during cleanup") + return fmt.Errorf("evm client is nil, unable to return funds from chainlink nodes during cleanup") } else if te.EVMClient.NetworkSimulated() { te.l.Info(). Str("Network Name", te.EVMClient.GetNetworkName()). diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index c07ea76262..9f64ab64c9 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -4,9 +4,9 @@ import ( "fmt" "math/big" "os" + "runtime/debug" "testing" - "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -230,7 +230,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { case CleanUpTypeNone: b.l.Warn().Msg("test environment won't be cleaned up") case "": - return b.te, errors.WithMessage(errors.New("explicit cleanup type must be set when building test environment"), "test environment builder failed") + return b.te, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("explicit cleanup type must be set when building test environment")) } if b.nonDevGethNetworks != nil { @@ -243,14 +243,14 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { for i, n := range b.te.PrivateChain { primaryNode := n.GetPrimaryNode() if primaryNode == nil { - return b.te, errors.WithStack(fmt.Errorf("primary node is nil in PrivateChain interface")) + return b.te, fmt.Errorf("primary node is nil in PrivateChain interface, stack: %s", string(debug.Stack())) } nonDevNetworks = append(nonDevNetworks, *n.GetNetworkConfig()) nonDevNetworks[i].URLs = []string{primaryNode.GetInternalWsUrl()} nonDevNetworks[i].HTTPURLs = []string{primaryNode.GetInternalHttpUrl()} } if nonDevNetworks == nil { - return nil, errors.New("cannot create nodes with custom config without nonDevNetworks") + return nil, fmt.Errorf("cannot create nodes with custom config without nonDevNetworks") } err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index eb542651b5..2ac3c38a71 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -17,12 +17,11 @@ require ( github.com/manifoldco/promptui v0.9.0 github.com/onsi/gomega v1.27.8 github.com/pelletier/go-toml/v2 v2.1.0 - github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.30.0 github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.5-0.20231107092923-3aa655167f65 + github.com/smartcontractkit/chainlink-testing-framework v1.18.5 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 @@ -364,6 +363,7 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/alertmanager v0.25.1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index ecafa2706e..ce5e51a568 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2376,8 +2376,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.5-0.20231107092923-3aa655167f65 h1:/iRhwYy5KFsaS9Zo1T64QxAd11HGZB5p/LHI5oVc4BU= -github.com/smartcontractkit/chainlink-testing-framework v1.18.5-0.20231107092923-3aa655167f65/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.5 h1:R0f13AUbon1ltHE/vudkyUnLRGaoeocIDVv+FsHZjno= +github.com/smartcontractkit/chainlink-testing-framework v1.18.5/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go index 5c622401ab..451d01a6c8 100644 --- a/integration-tests/load/functions/config.go +++ b/integration-tests/load/functions/config.go @@ -1,12 +1,13 @@ package loadfunctions import ( + "fmt" + "math/big" + "os" + "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "math/big" - "os" ) const ( @@ -103,18 +104,18 @@ func ReadConfig() (*PerformanceConfig, error) { var cfg *PerformanceConfig d, err := os.ReadFile(DefaultConfigFilename) if err != nil { - return nil, errors.Wrap(err, ErrReadPerfConfig) + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) } err = toml.Unmarshal(d, &cfg) if err != nil { - return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) + return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) } log.Debug().Interface("PerformanceConfig", cfg).Msg("Parsed performance config") mpk := os.Getenv("MUMBAI_KEYS") murls := os.Getenv("MUMBAI_URLS") snet := os.Getenv("SELECTED_NETWORKS") if mpk == "" || murls == "" || snet == "" { - return nil, errors.New( + return nil, fmt.Errorf( "ensure variables are set:\nMUMBAI_KEYS variable, private keys, comma separated\nSELECTED_NETWORKS=MUMBAI\nMUMBAI_URLS variable, websocket urls, comma separated", ) } else { diff --git a/integration-tests/load/functions/gateway.go b/integration-tests/load/functions/gateway.go index aefe4fbedc..78b0f14cf1 100644 --- a/integration-tests/load/functions/gateway.go +++ b/integration-tests/load/functions/gateway.go @@ -8,16 +8,16 @@ import ( "encoding/hex" "encoding/json" "fmt" + "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/go-resty/resty/v2" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" "github.com/smartcontractkit/chainlink/v2/core/services/s4" "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" - "time" ) type RPCResponse struct { @@ -182,12 +182,12 @@ func EncryptS4Secrets(deployerPk *ecdsa.PrivateKey, tdh2Pk *tdh2easy.PublicKey, donKey = bytes.Join([][]byte{b, donKey}, nil) donPubKey, err := crypto.UnmarshalPubkey(donKey) if err != nil { - return "", errors.Wrap(err, "failed to unmarshal DON key") + return "", fmt.Errorf("failed to unmarshal DON key: %w", err) } eciesDONPubKey := ecies.ImportECDSAPublic(donPubKey) signature, err := deployerPk.Sign(rand.Reader, []byte(msgJSON), nil) if err != nil { - return "", errors.Wrap(err, "failed to sign the msg with Ethereum key") + return "", fmt.Errorf("failed to sign the msg with Ethereum key: %w", err) } signedSecrets, err := json.Marshal(struct { Signature []byte `json:"signature"` @@ -197,29 +197,29 @@ func EncryptS4Secrets(deployerPk *ecdsa.PrivateKey, tdh2Pk *tdh2easy.PublicKey, Message: msgJSON, }) if err != nil { - return "", errors.Wrap(err, "failed to marshal signed secrets") + return "", fmt.Errorf("failed to marshal signed secrets: %w", err) } ct, err := ecies.Encrypt(rand.Reader, eciesDONPubKey, signedSecrets, nil, nil) if err != nil { - return "", errors.Wrap(err, "failed to encrypt with DON key") + return "", fmt.Errorf("failed to encrypt with DON key: %w", err) } ct0xFormat, err := json.Marshal(map[string]interface{}{"0x0": base64.StdEncoding.EncodeToString(ct)}) if err != nil { - return "", errors.Wrap(err, "failed to marshal DON key encrypted format") + return "", fmt.Errorf("failed to marshal DON key encrypted format: %w", err) } ctTDH2Format, err := tdh2easy.Encrypt(tdh2Pk, ct0xFormat) if err != nil { - return "", errors.Wrap(err, "failed to encrypt with TDH2 public key") + return "", fmt.Errorf("failed to encrypt with TDH2 public key: %w", err) } tdh2Message, err := ctTDH2Format.Marshal() if err != nil { - return "", errors.Wrap(err, "failed to marshal TDH2 encrypted msg") + return "", fmt.Errorf("failed to marshal TDH2 encrypted msg: %w", err) } finalMsg, err := json.Marshal(map[string]interface{}{ "encryptedSecrets": "0x" + hex.EncodeToString(tdh2Message), }) if err != nil { - return "", errors.Wrap(err, "failed to marshal secrets msg") + return "", fmt.Errorf("failed to marshal secrets msg: %w", err) } return string(finalMsg), nil } diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index 5253c531ee..81bc660b35 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -2,6 +2,7 @@ package loadfunctions import ( "crypto/ecdsa" + "fmt" "math/big" mrand "math/rand" "os" @@ -10,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/go-resty/resty/v2" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/networks" @@ -91,41 +91,41 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { log.Info().Msg("Creating new subscription") subID, err := router.CreateSubscriptionWithConsumer(loadTestClient.Address()) if err != nil { - return nil, errors.Wrap(err, "failed to create a new subscription") + return nil, fmt.Errorf("failed to create a new subscription: %w", err) } encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subID) if err != nil { - return nil, errors.Wrap(err, "failed to encode subscription ID for funding") + return nil, fmt.Errorf("failed to encode subscription ID for funding: %w", err) } _, err = lt.TransferAndCall(router.Address(), big.NewInt(0).Mul(cfg.Common.Funding.SubFunds, big.NewInt(1e18)), encodedSubId) if err != nil { - return nil, errors.Wrap(err, "failed to transferAndCall router, LINK funding") + return nil, fmt.Errorf("failed to transferAndCall router, LINK funding: %w", err) } cfg.Common.SubscriptionID = subID } pKey, pubKey, err := parseEthereumPrivateKey(os.Getenv("MUMBAI_KEYS")) if err != nil { - return nil, errors.Wrap(err, "failed to load Ethereum private key") + return nil, fmt.Errorf("failed to load Ethereum private key: %w", err) } tpk, err := coord.GetThresholdPublicKey() if err != nil { - return nil, errors.Wrap(err, "failed to get Threshold public key") + return nil, fmt.Errorf("failed to get Threshold public key: %w", err) } log.Info().Hex("ThresholdPublicKeyBytesHex", tpk).Msg("Loaded coordinator keys") donPubKey, err := coord.GetDONPublicKey() if err != nil { - return nil, errors.Wrap(err, "failed to get DON public key") + return nil, fmt.Errorf("failed to get DON public key: %w", err) } log.Info().Hex("DONPublicKeyHex", donPubKey).Msg("Loaded DON key") tdh2pk, err := ParseTDH2Key(tpk) if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal tdh2 public key") + return nil, fmt.Errorf("failed to unmarshal tdh2 public key: %w", err) } var encryptedSecrets string if cfg.Common.Secrets != "" { encryptedSecrets, err = EncryptS4Secrets(pKey, tdh2pk, donPubKey, cfg.Common.Secrets) if err != nil { - return nil, errors.Wrap(err, "failed to generate tdh2 secrets") + return nil, fmt.Errorf("failed to generate tdh2 secrets: %w", err) } slotID, slotVersion, err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ GatewayURL: cfg.Common.GatewayURL, @@ -139,7 +139,7 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { S4SetPayload: encryptedSecrets, }) if err != nil { - return nil, errors.Wrap(err, "failed to upload secrets to S4") + return nil, fmt.Errorf("failed to upload secrets to S4: %w", err) } cfg.Common.SecretsSlotID = slotID cfg.Common.SecretsVersionID = slotVersion @@ -168,13 +168,13 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { func parseEthereumPrivateKey(pk string) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) { pKey, err := crypto.HexToECDSA(pk) if err != nil { - return nil, nil, errors.Wrap(err, "failed to convert Ethereum key from hex") + return nil, nil, fmt.Errorf("failed to convert Ethereum key from hex: %w", err) } publicKey := pKey.Public() pubKey, ok := publicKey.(*ecdsa.PublicKey) if !ok { - return nil, nil, errors.Wrap(err, "failed to get public key from Ethereum private key") + return nil, nil, fmt.Errorf("failed to get public key from Ethereum private key: %w", err) } log.Info().Str("Address", crypto.PubkeyToAddress(*pubKey).Hex()).Msg("Parsed private key for address") return pKey, pubKey, nil diff --git a/integration-tests/load/vrfv2/config.go b/integration-tests/load/vrfv2/config.go index ee5f3ff80d..0c62cc351b 100644 --- a/integration-tests/load/vrfv2/config.go +++ b/integration-tests/load/vrfv2/config.go @@ -1,12 +1,13 @@ package loadvrfv2 import ( + "fmt" + "math/big" + "os" + "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "math/big" - "os" ) const ( @@ -63,11 +64,11 @@ func ReadConfig() (*PerformanceConfig, error) { var cfg *PerformanceConfig d, err := os.ReadFile(DefaultConfigFilename) if err != nil { - return nil, errors.Wrap(err, ErrReadPerfConfig) + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) } err = toml.Unmarshal(d, &cfg) if err != nil { - return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) + return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) } log.Debug().Interface("PerformanceConfig", cfg).Msg("Parsed performance config") return cfg, nil diff --git a/integration-tests/load/vrfv2/vu.go b/integration-tests/load/vrfv2/vu.go index df05a9168e..4658388d40 100644 --- a/integration-tests/load/vrfv2/vu.go +++ b/integration-tests/load/vrfv2/vu.go @@ -1,13 +1,14 @@ package loadvrfv2 import ( - "github.com/pkg/errors" + "fmt" + "time" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/wasp" - "time" ) /* JobVolumeVU is a "virtual user" that creates a VRFv2 job and constantly requesting new randomness only for this job instance */ @@ -54,7 +55,7 @@ func (m *JobVolumeVU) Clone(_ *wasp.Generator) wasp.VirtualUser { func (m *JobVolumeVU) Setup(_ *wasp.Generator) error { jobs, err := vrfv2_actions.CreateVRFV2Jobs(m.nodes, m.contracts.Coordinator, m.bc, m.minIncomingConfirmations) if err != nil { - return errors.Wrap(err, "failed to create VRFv2 jobs in setup") + return fmt.Errorf("failed to create VRFv2 jobs in setup: %w", err) } m.jobs = jobs m.keyHash = jobs[0].KeyHash diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index a5439210c2..cba3fdcde5 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -2,12 +2,13 @@ package loadvrfv2plus import ( "encoding/base64" + "fmt" + "os" + "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "os" ) const ( @@ -95,18 +96,18 @@ func ReadConfig() (*PerformanceConfig, error) { if rawConfig == "" { d, err = os.ReadFile(DefaultConfigFilename) if err != nil { - return nil, errors.Wrap(err, ErrReadPerfConfig) + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) } } else { d, err = base64.StdEncoding.DecodeString(rawConfig) } err = toml.Unmarshal(d, &cfg) if err != nil { - return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) + return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) } if cfg.Soak.RandomnessRequestCountPerRequest <= cfg.Soak.RandomnessRequestCountPerRequestDeviation { - return nil, errors.Wrap(err, ErrDeviationShouldBeLessThanOriginal) + return nil, fmt.Errorf("%s, err: %w", ErrDeviationShouldBeLessThanOriginal, err) } log.Debug().Interface("Config", cfg).Msg("Parsed config") diff --git a/integration-tests/reorg/reorg_confirmer.go b/integration-tests/reorg/reorg_confirmer.go index 885bed2ad4..2193131680 100644 --- a/integration-tests/reorg/reorg_confirmer.go +++ b/integration-tests/reorg/reorg_confirmer.go @@ -2,13 +2,13 @@ package reorg import ( "context" + "fmt" "math/big" "sync" "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" @@ -70,7 +70,7 @@ type ReorgController struct { // NewReorgController creates a type that can create reorg chaos and confirm reorg has happened func NewReorgController(cfg *ReorgConfig) (*ReorgController, error) { if len(cfg.Network.GetClients()) == 1 { - return nil, errors.New("need at least 3 nodes to re-org") + return nil, fmt.Errorf("need at least 3 nodes to re-org") } ctx, ctxCancel := context.WithTimeout(context.Background(), cfg.Timeout) rc := &ReorgController{ @@ -165,7 +165,7 @@ func (rc *ReorgController) VerifyReorgComplete() error { } } if rc.currentVerifiedBlocks+1 < rc.ReorgDepth { - return errors.New("Reorg depth has not met") + return fmt.Errorf("Reorg depth has not met") } return nil } @@ -217,7 +217,7 @@ func (rc *ReorgController) Wait() error { if rc.complete { return nil } - return errors.New("timeout waiting for reorg to complete") + return fmt.Errorf("timeout waiting for reorg to complete") } // forkNetwork stomp the network between target reorged node and the rest diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 1b33cdce76..a6dcdcd139 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -5,24 +5,14 @@ import ( "fmt" "math/big" "net/http" - "strings" "testing" "time" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" @@ -102,42 +92,3 @@ func TestOCRv2Basic(t *testing.T) { roundData.Answer.Int64(), ) } - -func setupOCR2Test(t *testing.T, forwardersEnabled bool) ( - testEnvironment *environment.Environment, - testNetwork blockchain.EVMNetwork, -) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !testNetwork.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - - var toml string - if forwardersEnabled { - toml = client.AddNetworkDetailedConfig(config.BaseOCR2Config, config.ForwarderNetworkDetailConfig, testNetwork) - } else { - toml = client.AddNetworksConfig(config.BaseOCR2Config, testNetwork) - } - - chainlinkChart := chainlink.New(0, map[string]interface{}{ - "replicas": 6, - "toml": toml, - }) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("smoke-ocr2-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, - }). - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddHelm(evmConfig). - AddHelm(chainlinkChart) - err := testEnvironment.Run() - require.NoError(t, err, "Error running test environment") - return testEnvironment, testNetwork -} diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 0d6a77a115..912c121d07 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -1,6 +1,7 @@ package smoke import ( + "context" "fmt" "math/big" "strings" @@ -80,7 +81,7 @@ func TestOCR2VRFRedeemModel(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(nil, requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(context.Background(), requestID, big.NewInt(int64(i))) require.NoError(t, err) l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") @@ -141,7 +142,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(nil, requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(context.Background(), requestID, big.NewInt(int64(i))) require.NoError(t, err, "Error getting Randomness result from Consumer Contract") l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness Fulfillment retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness Fulfillment retrieved from Consumer contract give an answer other than 0") diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index acd548c88e..3510a1505a 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -3,14 +3,14 @@ package smoke import ( "context" "fmt" - "github.com/smartcontractkit/chainlink/integration-tests/utils" "math/big" "testing" "time" + "github.com/smartcontractkit/chainlink/integration-tests/utils" + "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" - "github.com/pkg/errors" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" @@ -271,6 +271,7 @@ func TestVRFv2Plus(t *testing.T) { subIDForCancelling := subIDsForCancelling[0] testWalletAddress, err := actions.GenerateWallet() + require.NoError(t, err) testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), testWalletAddress) require.NoError(t, err) @@ -638,7 +639,7 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfv2PlusData.VRFKey, vrfv2PlusData.PrimaryEthAddress, newCoordinator) - require.NoError(t, err, errors.Wrap(err, vrfv2plus.ErrRegisteringProvingKey)) + require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfv2plus.ErrRegisteringProvingKey, err)) err = newCoordinator.SetConfig( vrfv2PlusConfig.MinimumConfirmations, @@ -651,6 +652,7 @@ func TestVRFv2PlusMigration(t *testing.T) { FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, }, ) + require.NoError(t, err) err = newCoordinator.SetLINKAndLINKNativeFeed(linkAddress.Address(), mockETHLinkFeedAddress.Address()) require.NoError(t, err, vrfv2plus.ErrSetLinkNativeLinkFeed) From 8c81f61f36fa9aeddde43b1c139a20c6915a3121 Mon Sep 17 00:00:00 2001 From: Tate Date: Tue, 7 Nov 2023 12:23:45 -0700 Subject: [PATCH 098/327] [TT-685] Enforce CTF version to be tag in the form v1.2.3 (#11209) --- .github/actions/build-test-image/action.yml | 9 ++++++++- .github/workflows/integration-tests.yml | 14 +++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index c4b39b4d7a..683ce912ec 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -30,6 +30,13 @@ inputs: runs: using: composite steps: + - name: Get CTF Version + id: version + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + with: + go-project-path: ./integration-tests + module-name: github.com/smartcontractkit/chainlink-testing-framework + enforce-semantic-tag: "true" # it has to be in the form of v1.2.3 or the image won't exist - name: Check if image exists id: check-image uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 @@ -48,7 +55,7 @@ runs: file: ./integration-tests/test.Dockerfile build-args: | BASE_IMAGE=${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image - IMAGE_VERSION=v0.38.2 + IMAGE_VERSION=${{ steps.version.output.version }} SUITES="${{ inputs.suites }}" AWS_REGION: ${{ inputs.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 125ddb3f4f..382e9cbbcf 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -35,6 +35,18 @@ env: MOD_CACHE_VERSION: 2 jobs: + enforce-ctf-version: + name: Enforce CTF Version + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Enforce CTF Version + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + with: + go-project-path: ./integration-tests + module-name: github.com/smartcontractkit/chainlink-testing-framework + enforce-semantic-tag: "true" changes: environment: integration name: Check Paths That Require Tests To Run @@ -81,7 +93,7 @@ jobs: tag-suffix: -plugins name: Build Chainlink Image ${{ matrix.image.name }} runs-on: ubuntu20.04-16cores-64GB - needs: [changes] + needs: [changes, enforce-ctf-version] steps: - name: Collect Metrics if: needs.changes.outputs.src == 'true' From 5af9bca45861bc61a1375cf0770570341c9a7a88 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Tue, 7 Nov 2023 14:38:42 -0500 Subject: [PATCH 099/327] [TT-524] Separate Live Testnet Tests (#11196) * Separate Live Testnet Tests * \n * Remove typo * Extrapolates building Chainlink image --- .../actions/build-chainlink-image/action.yml | 48 +++ .github/workflows/integration-tests.yml | 243 +------------ .github/workflows/live-testnet-tests.yml | 342 ++++++++++++++++++ 3 files changed, 399 insertions(+), 234 deletions(-) create mode 100644 .github/actions/build-chainlink-image/action.yml create mode 100644 .github/workflows/live-testnet-tests.yml diff --git a/.github/actions/build-chainlink-image/action.yml b/.github/actions/build-chainlink-image/action.yml new file mode 100644 index 0000000000..5041d9d1db --- /dev/null +++ b/.github/actions/build-chainlink-image/action.yml @@ -0,0 +1,48 @@ +name: Build Chainlink Image +description: A composite action that allows building and publishing the Chainlink image for integration testing + +inputs: + tag_suffix: + description: The suffix to append to the image tag (usually blank or "-plugins") + default: "" + dockerfile: + description: The path to the Dockerfile to use (usually core/chainlink.Dockerfile or plugins/chainlink.Dockerfile) + default: core/chainlink.Dockerfile + git_commit_sha: + description: The git commit sha to use for the image tag + default: ${{ github.sha }} + GRAFANA_CLOUD_BASIC_AUTH: + description: "grafana cloud basic auth" + GRAFANA_CLOUD_HOST: + description: "grafana cloud hostname" + AWS_REGION: + description: "AWS region to use for ECR" + AWS_ROLE_TO_ASSUME: + description: "AWS role to assume for ECR" + +runs: + using: composite + steps: + - name: Check if image exists + id: check-image + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + with: + repository: chainlink + tag: ${{ inputs.git_commit_sha }}${{ inputs.tag_suffix }} + AWS_REGION: ${{ inputs.AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ inputs.AWS_ROLE_TO_ASSUME }} + - name: Build Image + if: steps.check-image.outputs.exists == 'false' && needs.changes.outputs.src == 'true' + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + with: + cl_repo: smartcontractkit/chainlink + cl_ref: ${{ inputs.git_commit_sha }} + cl_dockerfile: ${{ inputs.dockerfile }} + push_tag: ${{ env.CHAINLINK_IMAGE }}:${{ inputs.git_commit_sha }}${{ inputs.tag_suffix }} + QA_AWS_REGION: ${{ inputs.AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ inputs.AWS_ROLE_TO_ASSUME }} + - name: Print Chainlink Image Built + shell: sh + run: | + echo "### Chainlink node image tag used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 382e9cbbcf..4c617a00c4 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -2,23 +2,10 @@ name: Integration Tests on: merge_group: pull_request: - schedule: - - cron: "0 0 * * *" - # - cron: "0 * * * *" # DEBUG: Run every hour to nail down flakes push: tags: - "*" workflow_dispatch: - inputs: - simulatedNetwork: - description: "Run Simulated Network Tests" - required: false - type: boolean - default: true - liveNetwork: - description: "Run Live Network Tests" - required: false - type: boolean # Only run 1 of this workflow at a time per PR concurrency: @@ -74,9 +61,9 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: Check Paths That Require Tests To Run continue-on-error: true - outputs: src: ${{ steps.changes.outputs.src }} + build-chainlink: environment: integration permissions: @@ -108,30 +95,16 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Check if image exists - if: needs.changes.outputs.src == 'true' - id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 - with: - repository: chainlink - tag: ${{ github.sha }}${{ matrix.image.tag-suffix }} + - name: Build Chainlink Image + uses: ./.github/actions/build-chainlink-image + with: + tag_suffix: ${{ matrix.image.tag-suffix }} + dockerfile: ${{ matrix.image.dockerfile }} + git_commit_sha: ${{ github.sha }} + GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - name: Build Image - if: steps.check-image.outputs.exists == 'false' && needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 - with: - cl_repo: smartcontractkit/chainlink - cl_ref: ${{ github.sha }} - cl_dockerfile: ${{ matrix.image.dockerfile }} - push_tag: ${{ env.CHAINLINK_IMAGE }}:${{ github.sha }}${{ matrix.image.tag-suffix }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - name: Print Chainlink Image Built - if: needs.changes.outputs.src == 'true' - run: | - echo "### Chainlink node image tag used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY build-test-image: if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') @@ -908,201 +881,3 @@ jobs: matrix-aggregator-status: ${{ needs.solana-smoke-tests-matrix.result }} continue-on-error: true ### End Solana Section - - ### Start Live Testnet Section - - testnet-smoke-tests-matrix: - if: ${{ github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || (github.event_name == 'workflow_dispatch' && inputs.liveNetwork) }} ## Only run live tests on new tags, schedule, or on manual request - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink] - env: - SELECTED_NETWORKS: ${{ matrix.testnet }} - CHAINLINK_COMMIT_SHA: ${{ github.sha }} - CHAINLINK_ENV_USER: ${{ github.actor }} - TEST_LOG_LEVEL: debug - EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} - - OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} - OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} - - ARBITRUM_GOERLI_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_URLS }} - ARBITRUM_GOERLI_HTTP_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_HTTP_URLS }} - strategy: - fail-fast: false - matrix: - # NOTE: If changing this matrix, make sure to update the matrix in the testnet-smoke-tests-notify job to be the same - # otherwise reporting will be broken. Getting a single matrix for multiple jobs is a pain - # https://github.com/orgs/community/discussions/26284#discussioncomment-3251198 - testnet: [OPTIMISM_GOERLI, ARBITRUM_GOERLI] - name: Live Testnet Smoke Tests ${{ matrix.testnet }} - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - ## Only run OCR smoke test for now - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-ocr-evm-${{ matrix.testnet }} # TODO: Only for OCR for now - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/ocr_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt - test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./integration-tests/smoke/logs - publish_check_name: ${{ matrix.testnet }} OCR Smoke Test Results - token: ${{ secrets.GITHUB_TOKEN }} - go_mod_path: ./integration-tests/go.mod - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Live Testnet Smoke Tests ${{ matrix.testnet }} - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - continue-on-error: true - - testnet-smoke-tests-notify: - name: Live Testnet Start Slack Thread - if: ${{ always() && needs.testnet-smoke-tests-matrix.result != 'skipped' && needs.testnet-smoke-tests-matrix.result != 'cancelled' && github.event_name != 'workflow_dispatch' }} - environment: integration - outputs: - thread_ts: ${{ steps.slack.outputs.thread_ts }} - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - runs-on: ubuntu-latest - needs: testnet-smoke-tests-matrix - steps: - - name: Debug Result - run: echo ${{needs.testnet-smoke-tests-matrix.result}} - - name: Main Slack Notification - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 - id: slack - with: - channel-id: ${{ secrets.QA_SLACK_CHANNEL }} - payload: | - { - "attachments": [ - { - "color": "${{ needs.testnet-smoke-tests-matrix.result == 'success' && '#2E7D32' || '#C62828' }}", - "blocks": [ - { - "type": "header", - "text": { - "type": "plain_text", - "text": "Live Smoke Test Results ${{ needs.testnet-smoke-tests-matrix.result == 'success' && ':white_check_mark:' || ':x:'}}", - "emoji": true - } - }, - { - "type": "divider" - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "<${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}|${{ github.ref_name }}> | <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> | <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Run>" - } - } - ] - } - ] - } - env: - SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} - - testnet-smoke-tests-results: - name: Post Live Testnet Smoke Test Results - if: ${{ always() && needs.testnet-smoke-tests-matrix.result != 'skipped' && needs.testnet-smoke-tests-matrix.result != 'cancelled' }} - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - runs-on: ubuntu-latest - needs: testnet-smoke-tests-notify - strategy: - fail-fast: false - matrix: - # NOTE: If changing this matrix, make sure to update the matrix in the testnet-smoke-tests-matrix job to be the same - # otherwise reporting will be broken. Getting a single matrix for multiple jobs is a pain - # https://github.com/orgs/community/discussions/26284#discussioncomment-3251198 - testnet: [OPTIMISM_GOERLI, ARBITRUM_GOERLI] - steps: - - name: Get Results - id: test-results - run: | - echo "Querying test results" - - echo "status=$(curl \ - -H "Authorization: Bearer ${{ github.token }}" \ - 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ - | jq -r '.jobs[] | select(.name == "Live Testnet Smoke Tests ${{ matrix.testnet}}").steps[] | select(.name == "Run Tests").conclusion')" >> $GITHUB_OUTPUT - - echo "status=$(curl \ - -H "Authorization: Bearer ${{ github.token }}" \ - 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ - | jq -r '.jobs[] | select(.name == "Live Testnet Smoke Tests ${{ matrix.testnet}}").steps[] | select(.name == "Run Tests").conclusion')" - echo "thread_ts=${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}" - - - name: Test Details - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 - with: - channel-id: ${{ secrets.QA_SLACK_CHANNEL }} - payload: | - { - "thread_ts": "${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}", - "attachments": [ - { - "color": "${{ steps.test-results.outputs.status == 'success' && '#2E7D32' || '#C62828' }}", - "blocks": [ - { - "type": "header", - "text": { - "type": "plain_text", - "text": "${{ matrix.testnet }} Smoke Test Results ${{ steps.test-results.outputs.status == 'success' && ':white_check_mark:' || ':x:'}}", - "emoji": true - } - }, - { - "type": "divider" - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "OCR ${{ steps.test-results.outputs.status == 'success' && ':white_check_mark:' || ':x:'}}" - } - } - ] - } - ] - } - env: - SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} - - ### End Live Testnet Section diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml new file mode 100644 index 0000000000..23e9b3c04c --- /dev/null +++ b/.github/workflows/live-testnet-tests.yml @@ -0,0 +1,342 @@ +name: Live Testnet Tests +on: + schedule: + - cron: "0 0 * * *" # Run nightly + push: + tags: + - "*" + workflow_dispatch: + +env: + CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com + MOD_CACHE_VERSION: 2 + + CHAINLINK_COMMIT_SHA: ${{ github.sha }} + CHAINLINK_ENV_USER: ${{ github.actor }} + TEST_LOG_LEVEL: debug + EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} + + OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} + OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} + + ARBITRUM_GOERLI_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_URLS }} + ARBITRUM_GOERLI_HTTP_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_HTTP_URLS }} + +jobs: + build-chainlink: + environment: integration + permissions: + id-token: write + contents: read + name: Build Chainlink Image + runs-on: ubuntu20.04-16cores-64GB + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Build Chainlink Image + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Chainlink Image + uses: ./.github/actions/build-chainlink-image + with: + tag_suffix: "" + dockerfile: core/chainlink.Dockerfile + git_commit_sha: ${{ github.sha }} + GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} + AWS_REGION: ${{ secrets.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + + + sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink] + env: + SELECTED_NETWORKS: SEPOLIA + strategy: + fail-fast: false + matrix: + product: [ocr, automation] + name: Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/${{ matrix.product }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./integration-tests/smoke/logs + publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Sepolia ${{ matrix.product }} Tests + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true + + optimism-goerli-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink] + env: + SELECTED_NETWORKS: OPTIMISM_GOERLI + strategy: + fail-fast: false + matrix: + product: [ocr, automation] + name: Optimism Goerli ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-goerli + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/${{ matrix.product }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./integration-tests/smoke/logs + publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Optimism Goerli ${{ matrix.product }} Tests + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true + + arbitrum-goerli-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink] + env: + SELECTED_NETWORKS: ARBITRUM_GOERLI + strategy: + fail-fast: false + matrix: + product: [ocr, automation] + name: Arbitrum Goerli ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-arbitrum-goerli + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/${{ matrix.product }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./integration-tests/smoke/logs + publish_check_name: Arbitrum Goerli ${{ matrix.product }} Smoke Test Results + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Arbitrum Goerli ${{ matrix.product }} Tests + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true + + testnet-smoke-tests-notify: + name: Start Slack Thread + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + outputs: + thread_ts: ${{ steps.slack.outputs.thread_ts }} + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: [sepolia-smoke-tests, optimism-goerli-smoke-tests, arbitrum-goerli-smoke-tests] + steps: + - name: Debug Result + run: echo ${{needs.*.result}} + - name: Main Slack Notification + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + id: slack + with: + channel-id: ${{ secrets.QA_SLACK_CHANNEL }} + payload: | + { + "attachments": [ + { + "color": "${{ needs.*.result == 'success' && '#2E7D32' || '#C62828' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "Live Smoke Test Results ${{ needs.*.result == 'success' && ':white_check_mark:' || ':x:'}}", + "emoji": true + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "<${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}|${{ github.ref_name }}> | <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> | <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Run>" + } + } + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + + testnet-smoke-tests-results: + name: Post Test Results + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: testnet-smoke-tests-notify + strategy: + fail-fast: false + matrix: + testnet: [sepolia, optimism-goerli, arbitrum-goerli] + steps: + - name: Get Results + id: test-results + run: | + echo "Querying test results" + + echo "status=$(curl \ + -H "Authorization: Bearer ${{ github.token }}" \ + 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ + | jq -r '.jobs[] | select(.name == "Live Testnet Smoke Tests ${{ matrix.testnet }}-smoke-tests").steps[] | select(.name == "Run Tests").conclusion')" >> $GITHUB_OUTPUT + + echo "status=$(curl \ + -H "Authorization: Bearer ${{ github.token }}" \ + 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ + | jq -r '.jobs[] | select(.name == "Live Testnet Smoke Tests ${{ matrix.testnet }}-smoke-tests"").steps[] | select(.name == "Run Tests").conclusion')" + echo "thread_ts=${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}" + + - name: Test Details + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + with: + channel-id: ${{ secrets.QA_SLACK_CHANNEL }} + payload: | + { + "thread_ts": "${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}", + "attachments": [ + { + "color": "${{ steps.test-results.outputs.status == 'success' && '#2E7D32' || '#C62828' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "${{ matrix.testnet }} Smoke Test Results ${{ steps.test-results.outputs.status == 'success' && ':white_check_mark:' || ':x:'}}", + "emoji": true + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "OCR ${{ steps.test-results.outputs.status == 'success' && ':white_check_mark:' || ':x:'}}" + } + } + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} From 647ce13cfac9c3bdd7a8f86636dde775f321a22b Mon Sep 17 00:00:00 2001 From: frank zhu Date: Tue, 7 Nov 2023 13:40:22 -0600 Subject: [PATCH 100/327] add lint and update tests for solidity foundry gha (#11184) * add lint and update tests for solidity foundry gha * fix typo * fix typo * refactor conditional into individual steps * remove if statement for checkout repo and add comment --- .github/workflows/solidity-foundry.yml | 13 +++++++++---- .github/workflows/solidity.yml | 8 +++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 19c879b09e..7c9df79617 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -34,11 +34,12 @@ jobs: matrix: product: [vrf, automation, llo-feeds, functions, shared] needs: [changes] - if: needs.changes.outputs.changes == 'true' - name: Tests + name: Foundry Tests ${{ matrix.product }} ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} # See https://github.com/foundry-rs/foundry/issues/3827 runs-on: ubuntu-22.04 + # The if statements for steps after checkout repo is workaround for + # passing required check for PRs that don't have filtered changes. steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -49,15 +50,18 @@ jobs: # and not native Foundry. This is to make sure the dependencies # stay in sync. - name: Setup NodeJS + if: needs.changes.outputs.changes == 'true' uses: ./.github/actions/setup-nodejs - name: Install Foundry + if: needs.changes.outputs.changes == 'true' uses: foundry-rs/foundry-toolchain@v1 with: # Has to match the `make foundry` version. version: nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b - name: Run Forge build + if: needs.changes.outputs.changes == 'true' run: | forge --version forge build @@ -67,6 +71,7 @@ jobs: FOUNDRY_PROFILE: ${{ matrix.product }} - name: Run Forge tests + if: needs.changes.outputs.changes == 'true' run: | forge test -vvv id: test @@ -75,7 +80,7 @@ jobs: FOUNDRY_PROFILE: ${{ matrix.product }} - name: Run Forge snapshot - if: ${{ !contains(fromJson('["vrf"]'), matrix.product) && !contains(fromJson('["automation"]'), matrix.product) }} + if: ${{ !contains(fromJson('["vrf"]'), matrix.product) && !contains(fromJson('["automation"]'), matrix.product) && needs.changes.outputs.changes == 'true' }} run: | forge snapshot --nmt "testFuzz_\w{1,}?" --check gas-snapshots/${{ matrix.product }}.gas-snapshot id: snapshot @@ -84,7 +89,7 @@ jobs: FOUNDRY_PROFILE: ${{ matrix.product }} - name: Collect Metrics - if: always() + if: needs.changes.outputs.changes == 'true' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index 782dc93a0f..069d9de45a 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -24,6 +24,7 @@ jobs: src: - 'contracts/**/*' - '.github/workflows/solidity.yml' + - '.github/workflows/solidity-foundry.yml' prepublish-test: needs: [changes] @@ -91,24 +92,29 @@ jobs: this-job-name: Native Compilation continue-on-error: true + # The if statements for steps after checkout repo is a workaround for + # passing required check for PRs that don't have filtered changes. lint: defaults: run: working-directory: contracts needs: [changes] - if: needs.changes.outputs.changes == 'true' name: Lint ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} runs-on: ubuntu-latest steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup NodeJS + if: needs.changes.outputs.changes == 'true' uses: ./.github/actions/setup-nodejs - name: Run pnpm lint + if: needs.changes.outputs.changes == 'true' run: pnpm lint - name: Run solhint + if: needs.changes.outputs.changes == 'true' run: pnpm solhint - name: Collect Metrics + if: needs.changes.outputs.changes == 'true' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: From 44f6d388d2c85cbb199f9550c7814528a6fa412b Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Tue, 7 Nov 2023 16:37:50 -0500 Subject: [PATCH 101/327] Removes Old Needs Check (#11220) * Removes old Needs Check * Properly gate action --- .github/actions/build-chainlink-image/action.yml | 2 +- .github/workflows/integration-tests.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/actions/build-chainlink-image/action.yml b/.github/actions/build-chainlink-image/action.yml index 5041d9d1db..ac29a3d7b8 100644 --- a/.github/actions/build-chainlink-image/action.yml +++ b/.github/actions/build-chainlink-image/action.yml @@ -32,7 +32,7 @@ runs: AWS_REGION: ${{ inputs.AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ inputs.AWS_ROLE_TO_ASSUME }} - name: Build Image - if: steps.check-image.outputs.exists == 'false' && needs.changes.outputs.src == 'true' + if: steps.check-image.outputs.exists == 'false' uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: cl_repo: smartcontractkit/chainlink diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 4c617a00c4..ba66a53ab6 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -96,6 +96,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image + if: needs.changes.outputs.src == 'true' uses: ./.github/actions/build-chainlink-image with: tag_suffix: ${{ matrix.image.tag-suffix }} From 33b9d2a2e30087dea3fdb05d46c45be817ac6679 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Wed, 8 Nov 2023 13:12:38 +0400 Subject: [PATCH 102/327] fix build-test-image action (#11225) --- .github/actions/build-test-image/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index 683ce912ec..a241f51d92 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -55,7 +55,7 @@ runs: file: ./integration-tests/test.Dockerfile build-args: | BASE_IMAGE=${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image - IMAGE_VERSION=${{ steps.version.output.version }} + IMAGE_VERSION=${{ steps.version.outputs.version }} SUITES="${{ inputs.suites }}" AWS_REGION: ${{ inputs.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} From ea27753bc31b7454915337984773d52528c6bd55 Mon Sep 17 00:00:00 2001 From: David Cauchi <13139524+davidcauchi@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:55:38 +0100 Subject: [PATCH 103/327] Add baseFeeWei to logs (#11204) --- .github/workflows/on-demand-ocr-soak-test.yml | 2 +- core/chains/evm/gas/block_history_estimator.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index b6ccad2246..4ea10cd482 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -20,7 +20,7 @@ on: - "BSC_TESTNET" - "SCROLL_SEPOLIA" - "SCROLL_MAINNET" - - "MUMBAI" + - "POLYGON_MUMBAI" - "POLYGON_MAINNET" - "LINEA_GOERLI" - "LINEA_MAINNET" diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 42c8f05153..80ae19f109 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -163,7 +163,7 @@ func (b *BlockHistoryEstimator) setLatest(head *evmtypes.Head) { if baseFee := head.BaseFeePerGas; baseFee != nil { promBlockHistoryEstimatorCurrentBaseFee.WithLabelValues(b.chainID.String()).Set(float64(baseFee.Int64())) } - b.logger.Debugw("Set latest block", "blockNum", head.Number, "blockHash", head.Hash, "baseFee", head.BaseFeePerGas) + b.logger.Debugw("Set latest block", "blockNum", head.Number, "blockHash", head.Hash, "baseFee", head.BaseFeePerGas, "baseFeeWei", head.BaseFeePerGas.ToInt()) b.latestMu.Lock() defer b.latestMu.Unlock() b.latest = head From b5191f1a8cf391e80a2960b65170177e439beed9 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:23:41 +0100 Subject: [PATCH 104/327] BCF-2749 add tests for ocr enhancedTelemetry service creation (#11206) * Add Enhanced telemetry is disabled log to newServicesMercury delegate * Add test to check if eaTelemetry service was created in ocr servicseForSpec based on ocr spec flag --- core/services/job/runner_integration_test.go | 68 ++++++++++++++++++++ core/services/ocr2/delegate.go | 2 + 2 files changed, 70 insertions(+) diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 7e8ed5e87f..deb4bff6b0 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -528,6 +528,74 @@ answer1 [type=median index=0]; require.NoError(t, err) }) + t.Run("test enhanced telemetry service creation", func(t *testing.T) { + testCases := []struct { + jbCaptureEATelemetry bool + specCaptureEATelemetry bool + expected bool + }{{false, false, false}, + {true, false, false}, + {false, true, true}, + {true, true, true}, + } + + for _, tc := range testCases { + + config = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.P2P.V1.Enabled = ptr(true) + c.OCR.CaptureEATelemetry = ptr(tc.specCaptureEATelemetry) + }) + + relayExtenders = evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: ethClient, GeneralConfig: config, KeyStore: ethKeyStore}) + legacyChains = evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) + + kb, err := keyStore.OCR().Create() + require.NoError(t, err) + + s := fmt.Sprintf(minimalNonBootstrapTemplate, cltest.NewEIP55Address(), transmitterAddress.Hex(), kb.ID(), "http://blah.com", "") + jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) + require.NoError(t, err) + err = toml.Unmarshal([]byte(s), &jb) + require.NoError(t, err) + + jb.MaxTaskDuration = models.Interval(cltest.MustParseDuration(t, "1s")) + err = jobORM.CreateJob(&jb) + require.NoError(t, err) + assert.Equal(t, jb.MaxTaskDuration, models.Interval(cltest.MustParseDuration(t, "1s"))) + + lggr := logger.TestLogger(t) + pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) + require.NoError(t, pw.Start(testutils.Context(t))) + sd := ocr.NewDelegate( + db, + jobORM, + keyStore, + nil, + pw, + monitoringEndpoint, + legacyChains, + lggr, + config.Database(), + srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + ) + + jb.OCROracleSpec.CaptureEATelemetry = tc.jbCaptureEATelemetry + services, err := sd.ServicesForSpec(jb) + require.NoError(t, err) + + enhancedTelemetryServiceCreated := false + for _, service := range services { + _, ok := service.(*ocrcommon.EnhancedTelemetryService[ocrcommon.EnhancedTelemetryData]) + enhancedTelemetryServiceCreated = ok + if enhancedTelemetryServiceCreated { + break + } + } + + require.Equal(t, tc.expected, enhancedTelemetryServiceCreated) + } + }) + t.Run("test job spec error is created", func(t *testing.T) { // Create a keystore with an ocr key bundle and p2p key. kb, err := keyStore.OCR().Create() diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 75147ca233..1e87915bd1 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -700,6 +700,8 @@ func (d *Delegate) newServicesMercury( if ocrcommon.ShouldCollectEnhancedTelemetryMercury(jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.FeedID.String(), synchronization.EnhancedEAMercury), lggr.Named("EnhancedTelemetryMercury")) mercuryServices = append(mercuryServices, enhancedTelemService) + } else { + lggr.Infow("Enhanced telemetry is disabled for mercury job", "job", jb.Name) } return mercuryServices, err2 From c3e889f1456d052ec0e96af383669bb7685d3a05 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Wed, 8 Nov 2023 17:00:30 +0100 Subject: [PATCH 105/327] Log poller on demand streamlining (#11231) * move workflow to correct directory * streamline on-demand values a bit * get RPC urls and private keys from secrets * download and run from inside the test folder * checkout repo before running tests * get inputs and mask them * fix step ordering in workflow * fix default image tag * use latest pumba@CTF * run one test * fix directory name * run on powerful runner * add guide explaining how to use log poller tests * update LP readme --- .github/workflows/on-demand-log-poller.yml | 71 +++++--- integration-tests/LOG_POLLER.md | 163 ++++++++++++++++++ integration-tests/docker/test_env/test_env.go | 17 ++ .../reorg/log_poller_maybe_reorg_test.go | 4 +- .../universal/log_poller/config.go | 11 +- .../universal/log_poller/scenarios.go | 2 +- 6 files changed, 235 insertions(+), 33 deletions(-) create mode 100644 integration-tests/LOG_POLLER.md diff --git a/.github/workflows/on-demand-log-poller.yml b/.github/workflows/on-demand-log-poller.yml index c5470a5a3d..42f901ec30 100644 --- a/.github/workflows/on-demand-log-poller.yml +++ b/.github/workflows/on-demand-log-poller.yml @@ -24,43 +24,64 @@ on: required: true chainlinkVersion: description: Chainlink version to use - default: "v2.7.0-beta0" + default: "2.7.0-beta1" required: true selectedNetworks: - description: Network to use (only Sepolia or Mumbai) - default: "Sepolia" - required: true - fundingKey: - description: Private key used to fund the contracts (must have sufficient ETH and LINK!) - required: true - rpcURL: - description: RPC URL to use + type: choice + options: + - "SIMULATED" + - "SEPOLIA" + - "MUMBAI" + fundingPrivateKey: + description: Private funding key (Skip for Simulated) required: true + type: string wsURL: - description: WS URL to use + description: WS URL for the network (Skip for Simulated) required: true + type: string + httpURL: + description: HTTP URL for the network (Skip for Simulated) + required: true + type: string jobs: test: - runs-on: ubuntu-latest + env: + CONTRACTS: ${{ inputs.contracts }} + EVENTS_PER_TX: ${{ inputs.eventsPerTx }} + LOAD_DURATION: ${{ inputs.loadDuration }} + USE_FINALITY_TAG: ${{ inputs.useFinalityTag }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} + REF_NAME: ${{ github.head_ref || github.ref_name }} + runs-on: ubuntu20.04-8cores-32GB steps: - - uses: actions/checkout@v3 + - name: Get Inputs + run: | + EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) + EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) + EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) + + echo ::add-mask::$EVM_URLS + echo ::add-mask::$EVM_HTTP_URLS + echo ::add-mask::$EVM_KEYS + + echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV + echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV + echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} - name: Setup Go uses: actions/setup-go@v3 with: go-version-file: "integration-tests/go.mod" cache: true - - name: Show overrides - env: - CONTRACTS: ${{ inputs.contracts }} - EVENTS_PER_TX: ${{ inputs.eventsPerTx }} - LOAD_DURATION: ${{ inputs.loadDuration }} - USE_FINALITY_TAG: ${{ inputs.useFinalityTag }} - CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} - CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} - SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} - EVM_KEYS: ${{ inputs.fundingKey }} - EVM_HTTP_URLS: ${{ inputs.rpcURL }} - EVM_URLS: ${{ inputs.wsURL }} + - name: Run tests run: | - go test -v -timeout 5h -run=TestLogPollerFromEnv integration-tests/reorg/log_poller_maybe_reorg_test.go \ No newline at end of file + cd integration-tests + go mod download + go test -v -timeout 5h -v -count=1 -run ^TestLogPollerFromEnv$ ./reorg/log_poller_maybe_reorg_test.go diff --git a/integration-tests/LOG_POLLER.md b/integration-tests/LOG_POLLER.md new file mode 100644 index 0000000000..6e98fba552 --- /dev/null +++ b/integration-tests/LOG_POLLER.md @@ -0,0 +1,163 @@ +# How to run Log Poller's tests + +## Limitations +* currently they can only be run in Docker, not in Kubernetes +* when using `looped` runner it's not possible to directly control execution time +* WASP's `gun` implementation is imperfect in terms of generated load + +## Configuration +Due to unfinished migration to TOML config tests use a mixed configuration approach: +* network, RPC endpoints, funding keys, etc need to be provided by env vars +* test-specific configuration can be provided by TOML file or via a `Config` struct (to which TOML is parsed anyway) additionally some of it can be overridden by env vars (for ease of use in CI) +** smoke tests use the programmatical approach +** load test uses the TOML approach + +## Approximated test scenario +Different tests might have slightly modified scenarios, but generally they follow this pattern: +* start CL nodes +* setup OCR +* upload Automation Registry 2.1 +* deploy UpKeep Consumers +* deploy test contracts +* register filters for test contracts +* make sure all CL nodes have filters registered +* emit test logs +* wait for log poller to finalise last block in which logs were emitted +** block number is determined either by finality tag or fixed finality depth depending on network configuration +* wait for all CL nodes to have expected log count +* compare logs that present in the EVM node with logs in CL nodes + +All of the checks use fluent waits. + +### Required env vars +* `CHAINLINK_IMAGE` +* `CHAINLINK_VERSION` +* `SELECTED_NETWORKS` + +### Env vars required for live testnet tests +* `EVM_WS_URL` -- RPC websocket +* `EVM_HTTP_URL` -- RPC HTTP +* `EVM_KEYS` -- private keys used for funding + +Since on live testnets we are using existing and canonical LINK contracts funding keys need to contain enough LINK to pay for the test. There's an automated check that fails during setup if there's not enough LINK. Approximately `9 LINK` is required for each UpKeep contract test uses to register a `LogTrigger`. Test contract emits 3 types of events and unless configured otherwise (programmatically!) all of them will be used, which means that due to Automation's limitation we need to register a separate `LogTrigger` for each event type for each contract. So if you want to test with 100 contracts, then you'd need to register 300 UpKeep contracts and thus your funding address needs to have at least 2700 LINK. + +### Programmatical config +There are two load generators available: +* `looped` -- it's a simple generator that just loops over all contracts and emits events at random intervals +* `wasp` -- based on WASP load testing tool, it's more sophisticated and allows to control execution time + +#### Looped config +``` + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, # number of test contracts to deploy + EventsPerTx: 4, # number of events to emit in a single transaction + UseFinalityTag: false, # if set to true then Log Poller will use finality tag returned by chain, when determining last finalised block (won't work on a simulated network, it requires eth2) + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, # number of times each contract will be called + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, # minimum number of milliseconds to wait before emitting events + MaxEmitWaitTimeMs: 500, # maximum number of milliseconds to wait before emitting events + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { # modify that function to emit only logs you want + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit +``` + +Remember that final number of events emitted will be `Contracts * EventsPerTx * ExecutionCount * len(eventToEmit)`. And that that last number by default is equal to `3` (that's because we want to emit different event types, not just one). You can change that by overriding `EventsToEmit` field. + +#### WASP config +``` + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 4, + UseFinalityTag: false, + }, + Wasp: &logpoller.WaspConfig{ + Load: &logpoller.Load{ + RPS: 10, # requests per second + LPS: 0, # logs per second + RateLimitUnitDuration: models.MustNewDuration(5 * time.Minutes), # for how long the load should be limited (ramp-up period) + Duration: models.MustNewDuration(5 * time.Minutes), # how long to generate the load for + CallTimeout: models.MustNewDuration(5 * time.Minutes), # how long to wait for a single call to finish + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit +``` + +Remember that you cannot specify both `RPS` and `LPS`. If you want to use `LPS` then omit `RPS` field. Also remember that depending on the events you decide to emit RPS might mean 1 request or might mean 3 requests (if you go with the default `EventsToEmit`). + +For other nuances do check [gun.go][integration-tests/universal/log_poller/gun.go]. + +### TOML config +That config follows the same structure as programmatical config shown above. + +Sample config: [config.toml](integration-tests/load/log_poller/config.toml) + +Use this snippet instead of creating the `Config` struct programmatically: +``` + cfg, err := lp_helpers.ReadConfig(lp_helpers.DefaultConfigFilename) + require.NoError(t, err) +``` + +And remember to add events you want emit: +``` + eventsToEmit := []abi.Event{} + for _, event := range lp_helpers.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit +``` + +### Timeouts +Various checks inside the tests have hardcoded timeouts, which might not be suitable for your execution parameters, for example if you decided to emit 1M logs, then waiting for all of them to be indexed for `1m` might not be enough. Remember to adjust them accordingly. + +Sample snippet: +``` + gom.Eventually(func(g gomega.Gomega) { + logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if CL nodes have expected log count. Retrying...") + } + g.Expect(logCountMatches).To(gomega.BeTrue(), "Not all CL nodes have expected log count") + }, "1m", "30s").Should(gomega.Succeed()) # 1m is the timeout for all nodes to have expected log count +``` + +## Tests +* [Load](integration-tests/load/log_poller/log_poller_test.go) +* [Smoke](integration-tests/smoke/log_poller/log_poller_test.go) + +## Running tests +After setting all the environment variables you can run the test with: +``` +# run in the root folder of chainlink repo +go test -v -test.timeout=2700s -run TestLogPollerReplay integration-tests/smoke/log_poller_test.go +``` + +Remember to adjust test timeout accordingly to match expected duration. + + +## Github Actions +If all of that seems too complicated use this [on-demand workflow](https://github.com/smartcontractkit/chainlink/actions/workflows/on-demand-log-poller.yml). + +Execution time here is an approximation, so depending on network conditions it might be slightly longer or shorter. \ No newline at end of file diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index a6495bed54..b3fc1c0cf6 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -187,6 +187,8 @@ func (te *CLClusterTestEnv) Cleanup() error { return fmt.Errorf("chainlink nodes are nil, unable cleanup chainlink nodes") } + te.logWhetherAllContainersAreRunning() + // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution // Collect logs if the test fails, or if we just want them if te.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { @@ -216,6 +218,21 @@ func (te *CLClusterTestEnv) Cleanup() error { return nil } +func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { + for _, node := range te.ClCluster.Nodes { + isCLRunning := node.Container.IsRunning() + isDBRunning := node.PostgresDb.Container.IsRunning() + + if !isCLRunning { + te.l.Warn().Str("Node", node.ContainerName).Msg("Chainlink node was not running, when test ended") + } + + if !isDBRunning { + te.l.Warn().Str("Node", node.ContainerName).Msg("Postgres DB is not running, when test ended") + } + } +} + // collectTestLogs collects the logs from all the Chainlink nodes in the test environment and writes them to local files func (te *CLClusterTestEnv) collectTestLogs() error { te.l.Info().Msg("Collecting test logs") diff --git a/integration-tests/reorg/log_poller_maybe_reorg_test.go b/integration-tests/reorg/log_poller_maybe_reorg_test.go index 4e802bdb09..0176fdbbdd 100644 --- a/integration-tests/reorg/log_poller_maybe_reorg_test.go +++ b/integration-tests/reorg/log_poller_maybe_reorg_test.go @@ -20,8 +20,8 @@ func TestLogPollerFromEnv(t *testing.T) { ExecutionCount: 100, }, FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 800, - MaxEmitWaitTimeMs: 1200, + MinEmitWaitTimeMs: 400, + MaxEmitWaitTimeMs: 600, }, }, } diff --git a/integration-tests/universal/log_poller/config.go b/integration-tests/universal/log_poller/config.go index 623fa6606e..7297e81124 100644 --- a/integration-tests/universal/log_poller/config.go +++ b/integration-tests/universal/log_poller/config.go @@ -112,11 +112,12 @@ func (c *Config) OverrideFromEnv() error { if c.General.Generator == GeneratorType_WASP { c.Wasp.Load.Duration = &d } else { - // make the looped generator approximately run for desired duration - // on average we will emit 1 event per second - c.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs = 900 - c.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs = 1100 - c.LoopedConfig.ContractConfig.ExecutionCount = int(d.Duration().Seconds()) + // this is completely arbitrary and practice shows that even with this values + // test executes much longer than specified, probably due to network latency + c.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs = 400 + c.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs = 600 + // divide by 4 based on past runs, but we should do it in a better way + c.LoopedConfig.ContractConfig.ExecutionCount = int(d.Duration().Seconds() / 4) } } diff --git a/integration-tests/universal/log_poller/scenarios.go b/integration-tests/universal/log_poller/scenarios.go index d14a3bcb2a..1110a2f8ca 100644 --- a/integration-tests/universal/log_poller/scenarios.go +++ b/integration-tests/universal/log_poller/scenarios.go @@ -309,7 +309,7 @@ func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string require.Equal(t, "Replay started", response.Data.Attributes.Message, "Unexpected response message from log poller's replay") } - l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for logs to be processed by all nodes and for chain to advance beyond finality") + l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for replay logs to be processed by all nodes") gom.Eventually(func(g gomega.Gomega) { logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) From 7be2d6516addfaaab435d34dfac0039cfa63479b Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Wed, 8 Nov 2023 18:40:17 +0200 Subject: [PATCH 106/327] chore/VRF-722-externalise-oracleWithdraw-address (#11216) * VRF-722: made eoa address configurable which is used for VRF Key registration in VRF super scripts * VRF-722: PR comments --- core/scripts/common/vrf/model/model.go | 5 ++ core/scripts/common/vrf/setup-envs/README.md | 4 +- core/scripts/common/vrf/setup-envs/main.go | 27 +++++--- core/scripts/vrfv2/testnet/README.md | 16 +++-- .../vrfv2/testnet/v2scripts/super_scripts.go | 54 +++++++++------- core/scripts/vrfv2plus/testnet/README.md | 11 +++- .../testnet/v2plusscripts/super_scripts.go | 63 ++++++++++++------- 7 files changed, 117 insertions(+), 63 deletions(-) diff --git a/core/scripts/common/vrf/model/model.go b/core/scripts/common/vrf/model/model.go index bd0e3bbe36..42deb42453 100644 --- a/core/scripts/common/vrf/model/model.go +++ b/core/scripts/common/vrf/model/model.go @@ -44,3 +44,8 @@ type ContractAddresses struct { CoordinatorAddress common.Address BatchCoordinatorAddress common.Address } + +type VRFKeyRegistrationConfig struct { + VRFKeyUncompressedPubKey string + RegisterAgainstAddress string +} diff --git a/core/scripts/common/vrf/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md index 33515338a2..f3b391f0ee 100644 --- a/core/scripts/common/vrf/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -35,7 +35,9 @@ go run . \ --min-confs=3 \ --num-eth-keys=1 \ --num-vrf-keys=1 \ ---sending-key-funding-amount="1e17" +--sending-key-funding-amount="1e17" \ +--register-vrf-key-against-address= ``` Optional parameters - will not be deployed if specified (NOT WORKING YET) diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index 6748408f47..7c2530ffd4 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -85,6 +85,8 @@ func main() { batchBHSAddressString := flag.String("batch-bhs-address", "", "address of Batch BHS contract") coordinatorAddressString := flag.String("coordinator-address", "", "address of VRF Coordinator contract") batchCoordinatorAddressString := flag.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") + registerVRFKeyAgainstAddress := flag.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ + "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") e := helpers.SetupEnv(false) flag.Parse() @@ -171,6 +173,11 @@ func main() { BatchCoordinatorAddress: common.HexToAddress(*batchCoordinatorAddressString), } + vrfKeyRegistrationConfig := model.VRFKeyRegistrationConfig{ + VRFKeyUncompressedPubKey: nodesMap[model.VRFPrimaryNodeName].VrfKeys[0], + RegisterAgainstAddress: *registerVRFKeyAgainstAddress, + } + var jobSpecs model.JobSpecs switch *vrfVersion { @@ -188,10 +195,10 @@ func main() { } coordinatorConfigV2 := v2scripts.CoordinatorConfigV2{ - MinConfs: minConfs, - MaxGasLimit: &constants.MaxGasLimit, - StalenessSeconds: &constants.StalenessSeconds, - GasAfterPayment: &constants.GasAfterPayment, + MinConfs: *minConfs, + MaxGasLimit: constants.MaxGasLimit, + StalenessSeconds: constants.StalenessSeconds, + GasAfterPayment: constants.GasAfterPayment, FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, FeeConfig: feeConfigV2, } @@ -199,7 +206,7 @@ func main() { jobSpecs = v2scripts.VRFV2DeployUniverse( e, subscriptionBalanceJuels, - &nodesMap[model.VRFPrimaryNodeName].VrfKeys[0], + vrfKeyRegistrationConfig, contractAddresses, coordinatorConfigV2, *batchFulfillmentEnabled, @@ -211,10 +218,10 @@ func main() { FulfillmentFlatFeeNativePPM: uint32(constants.FlatFeeNativePPM), } coordinatorConfigV2Plus := v2plusscripts.CoordinatorConfigV2Plus{ - MinConfs: minConfs, - MaxGasLimit: &constants.MaxGasLimit, - StalenessSeconds: &constants.StalenessSeconds, - GasAfterPayment: &constants.GasAfterPayment, + MinConfs: *minConfs, + MaxGasLimit: constants.MaxGasLimit, + StalenessSeconds: constants.StalenessSeconds, + GasAfterPayment: constants.GasAfterPayment, FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, FeeConfig: feeConfigV2Plus, } @@ -223,7 +230,7 @@ func main() { e, subscriptionBalanceJuels, subscriptionBalanceNativeWei, - &nodesMap[model.VRFPrimaryNodeName].VrfKeys[0], + vrfKeyRegistrationConfig, contractAddresses, coordinatorConfigV2Plus, *batchFulfillmentEnabled, diff --git a/core/scripts/vrfv2/testnet/README.md b/core/scripts/vrfv2/testnet/README.md index 1b2d986f55..b527c576fd 100644 --- a/core/scripts/vrfv2/testnet/README.md +++ b/core/scripts/vrfv2/testnet/README.md @@ -57,11 +57,19 @@ To deploy a full VRF environment on-chain, run: ```shell go run . deploy-universe \ ---sending-key-funding-amount 100000000000000000 \ ---subscription-balance=10000000000000000000 \ +--subscription-balance=5000000000000000000 \ #5 LINK --uncompressed-pub-key= \ ---vrf-primary-node-sending-keys="" \ ---batch-fulfillment-enabled false +--vrf-primary-node-sending-keys="" \ #used to fund the keys and for sample VRF Job Spec generation +--sending-key-funding-amount 100000000000000000 \ #0.1 ETH, fund addresses specified in vrf-primary-node-sending-keys +--batch-fulfillment-enabled false \ #only used for sample VRF Job Spec generation +--register-vrf-key-against-address=<"from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments> +``` +```shell +go run . deploy-universe \ +--subscription-balance=5000000000000000000 \ +--uncompressed-pub-key="0xf3706e247a7b205c8a8bd25a6e8c4650474da496151371085d45beeead27e568c1a5e8330c7fa718f8a31226efbff6632ed6f8ed470b637aa9be2b948e9dcef6" \ +--batch-fulfillment-enabled false \ +--register-vrf-key-against-address="0x23b5613fc04949F4A53d1cc8d6BCCD21ffc38C11" ``` ## Deploying the Consumer Contract diff --git a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index 23ad8e1374..b623ae6308 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -26,10 +26,10 @@ import ( ) type CoordinatorConfigV2 struct { - MinConfs *int - MaxGasLimit *int64 - StalenessSeconds *int64 - GasAfterPayment *int64 + MinConfs int + MaxGasLimit int64 + StalenessSeconds int64 + GasAfterPayment int64 FallbackWeiPerUnitLink *big.Int FeeConfig vrf_coordinator_v2.VRFCoordinatorV2FeeConfig } @@ -52,7 +52,10 @@ func DeployUniverseViaCLI(e helpers.Environment) { // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", constants.FallbackWeiPerUnitLink.String(), "fallback wei/link ratio") - registerKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") + registerVRFKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") + registerVRFKeyAgainstAddress := deployCmd.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ + "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") + vrfPrimaryNodeSendingKeysString := deployCmd.String("vrf-primary-node-sending-keys", "", "VRF Primary Node sending keys") minConfs := deployCmd.Int("min-confs", constants.MinConfs, "min confs") @@ -119,18 +122,23 @@ func DeployUniverseViaCLI(e helpers.Environment) { } coordinatorConfig := CoordinatorConfigV2{ - MinConfs: minConfs, - MaxGasLimit: maxGasLimit, - StalenessSeconds: stalenessSeconds, - GasAfterPayment: gasAfterPayment, + MinConfs: *minConfs, + MaxGasLimit: *maxGasLimit, + StalenessSeconds: *stalenessSeconds, + GasAfterPayment: *gasAfterPayment, FallbackWeiPerUnitLink: fallbackWeiPerUnitLink, FeeConfig: feeConfig, } + vrfKeyRegistrationConfig := model.VRFKeyRegistrationConfig{ + VRFKeyUncompressedPubKey: *registerVRFKeyUncompressedPubKey, + RegisterAgainstAddress: *registerVRFKeyAgainstAddress, + } + VRFV2DeployUniverse( e, subscriptionBalanceJuels, - registerKeyUncompressedPubKey, + vrfKeyRegistrationConfig, contractAddresses, coordinatorConfig, *batchFulfillmentEnabled, @@ -147,7 +155,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { func VRFV2DeployUniverse( e helpers.Environment, subscriptionBalanceJuels *big.Int, - registerKeyUncompressedPubKey *string, + vrfKeyRegistrationConfig model.VRFKeyRegistrationConfig, contractAddresses model.ContractAddresses, coordinatorConfig CoordinatorConfigV2, batchFulfillmentEnabled bool, @@ -155,14 +163,14 @@ func VRFV2DeployUniverse( ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash - if len(*registerKeyUncompressedPubKey) > 0 { + if len(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) > 0 { // Put key in ECDSA format - if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { - *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) + if strings.HasPrefix(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, "0x") { + vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey = strings.Replace(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, "0x", "04", 1) } // Generate compressed public key and key hash - pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) + pubBytes, err := hex.DecodeString(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) helpers.PanicErr(err) pk, err := crypto.UnmarshalPubkey(pubBytes) helpers.PanicErr(err) @@ -217,10 +225,10 @@ func VRFV2DeployUniverse( SetCoordinatorConfig( e, *coordinator, - uint16(*coordinatorConfig.MinConfs), - uint32(*coordinatorConfig.MaxGasLimit), - uint32(*coordinatorConfig.StalenessSeconds), - uint32(*coordinatorConfig.GasAfterPayment), + uint16(coordinatorConfig.MinConfs), + uint32(coordinatorConfig.MaxGasLimit), + uint32(coordinatorConfig.StalenessSeconds), + uint32(coordinatorConfig.GasAfterPayment), coordinatorConfig.FallbackWeiPerUnitLink, coordinatorConfig.FeeConfig, ) @@ -228,12 +236,12 @@ func VRFV2DeployUniverse( fmt.Println("\nConfig set, getting current config from deployed contract...") PrintCoordinatorConfig(coordinator) - if len(*registerKeyUncompressedPubKey) > 0 { + if len(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) > 0 { fmt.Println("\nRegistering proving key...") //NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able // easily withdraw funds from Coordinator contract back to EOA account - RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, e.Owner.From.String()) + RegisterCoordinatorProvingKey(e, *coordinator, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, vrfKeyRegistrationConfig.RegisterAgainstAddress) fmt.Println("\nProving key registered, getting proving key hashes from deployed contract...") _, _, provingKeyHashes, configErr := coordinator.GetRequestConfig(nil) @@ -271,7 +279,7 @@ func VRFV2DeployUniverse( contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress batchFulfillmentEnabled, //batchFulfillmentEnabled compressedPkHex, //publicKey - *coordinatorConfig.MinConfs, //minIncomingConfirmations + coordinatorConfig.MinConfs, //minIncomingConfirmations e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, @@ -348,7 +356,7 @@ func VRFV2DeployUniverse( "\nVRF Subscription Id:", subID, "\nVRF Subscription Balance:", *subscriptionBalanceJuels, "\nPossible VRF Request command: ", - fmt.Sprintf("go run . eoa-load-test-request-with-metrics --consumer-address=%s --sub-id=%d --key-hash=%s --request-confirmations %d --requests 1 --runs 1 --cb-gas-limit 1_000_000", consumerAddress, subID, keyHash, *coordinatorConfig.MinConfs), + fmt.Sprintf("go run . eoa-load-test-request-with-metrics --consumer-address=%s --sub-id=%d --key-hash=%s --request-confirmations %d --requests 1 --runs 1 --cb-gas-limit 1_000_000", consumerAddress, subID, keyHash, coordinatorConfig.MinConfs), "\nRetrieve Request Status: ", fmt.Sprintf("go run . eoa-load-test-read-metrics --consumer-address=%s", consumerAddress), "\nA node can now be configured to run a VRF job with the below job spec :\n", diff --git a/core/scripts/vrfv2plus/testnet/README.md b/core/scripts/vrfv2plus/testnet/README.md index b95ec99d5f..6402569c56 100644 --- a/core/scripts/vrfv2plus/testnet/README.md +++ b/core/scripts/vrfv2plus/testnet/README.md @@ -58,7 +58,16 @@ cd /core/scripts/vrfv2/testnet - Not specifying `--link-eth-feed` would make the super script deploy a new LINK-ETH feed contract and use it for funding VRF V2+ subscription ```shell -go run . deploy-universe --link-address=$LINK --link-eth-feed=$LINK_ETH_FEED --subscription-balance= --uncompressed-pub-key=$PUB_KEY --oracle-address=$ORACLE_ADDRESS +go run . deploy-universe \ +--link-address=$LINK \ +--link-eth-feed=$LINK_ETH_FEED \ +--subscription-balance=5000000000000000000 \ #5 LINK +--subscription-balance-native=1000000000000000000 \ #1 ETH +--uncompressed-pub-key= \ +--vrf-primary-node-sending-keys="" \ #used to fund the keys and for sample VRF Job Spec generation +--sending-key-funding-amount 100000000000000000 \ #0.1 ETH, fund addresses specified in vrf-primary-node-sending-keys +--batch-fulfillment-enabled false \ #only used for sample VRF Job Spec generation +--register-vrf-key-against-address="" # from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments ``` ## Deploying the Consumer Contract diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index 752e06bbb2..50584d885a 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -39,10 +39,10 @@ import ( var coordinatorV2PlusABI = evmtypes.MustGetABI(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalABI) type CoordinatorConfigV2Plus struct { - MinConfs *int - MaxGasLimit *int64 - StalenessSeconds *int64 - GasAfterPayment *int64 + MinConfs int + MaxGasLimit int64 + StalenessSeconds int64 + GasAfterPayment int64 FallbackWeiPerUnitLink *big.Int FeeConfig vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig } @@ -481,7 +481,10 @@ func DeployUniverseViaCLI(e helpers.Environment) { // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", "6e16", "fallback wei/link ratio") - registerKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") + registerVRFKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") + registerVRFKeyAgainstAddress := deployCmd.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ + "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") + vrfPrimaryNodeSendingKeysString := deployCmd.String("vrf-primary-node-sending-keys", "", "VRF Primary Node sending keys") minConfs := deployCmd.Int("min-confs", constants.MinConfs, "min confs") nodeSendingKeyFundingAmount := deployCmd.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "CL node sending key funding amount") @@ -505,10 +508,17 @@ func DeployUniverseViaCLI(e helpers.Environment) { FulfillmentFlatFeeNativePPM: uint32(*flatFeeEthPPM), } - vrfPrimaryNodeSendingKeys := strings.Split(*vrfPrimaryNodeSendingKeysString, ",") + var vrfPrimaryNodeSendingKeys []string + if len(*vrfPrimaryNodeSendingKeysString) > 0 { + vrfPrimaryNodeSendingKeys = strings.Split(*vrfPrimaryNodeSendingKeysString, ",") + } nodesMap := make(map[string]model.Node) + fundingAmount, ok := new(big.Int).SetString(*nodeSendingKeyFundingAmount, 10) + if !ok { + panic(fmt.Sprintf("failed to parse node sending key funding amount '%s'", *nodeSendingKeyFundingAmount)) + } nodesMap[model.VRFPrimaryNodeName] = model.Node{ SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), SendingKeyFundingAmount: fundingAmount, @@ -529,19 +539,24 @@ func DeployUniverseViaCLI(e helpers.Environment) { } coordinatorConfig := CoordinatorConfigV2Plus{ - MinConfs: minConfs, - MaxGasLimit: maxGasLimit, - StalenessSeconds: stalenessSeconds, - GasAfterPayment: gasAfterPayment, + MinConfs: *minConfs, + MaxGasLimit: *maxGasLimit, + StalenessSeconds: *stalenessSeconds, + GasAfterPayment: *gasAfterPayment, FallbackWeiPerUnitLink: fallbackWeiPerUnitLink, FeeConfig: feeConfig, } + vrfKeyRegistrationConfig := model.VRFKeyRegistrationConfig{ + VRFKeyUncompressedPubKey: *registerVRFKeyUncompressedPubKey, + RegisterAgainstAddress: *registerVRFKeyAgainstAddress, + } + VRFV2PlusDeployUniverse( e, subscriptionBalanceJuels, subscriptionBalanceNativeWei, - registerKeyUncompressedPubKey, + vrfKeyRegistrationConfig, contractAddresses, coordinatorConfig, *batchFulfillmentEnabled, @@ -558,7 +573,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { func VRFV2PlusDeployUniverse(e helpers.Environment, subscriptionBalanceJuels *big.Int, subscriptionBalanceNativeWei *big.Int, - registerKeyUncompressedPubKey *string, + vrfKeyRegistrationConfig model.VRFKeyRegistrationConfig, contractAddresses model.ContractAddresses, coordinatorConfig CoordinatorConfigV2Plus, batchFulfillmentEnabled bool, @@ -566,14 +581,14 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash - if len(*registerKeyUncompressedPubKey) > 0 { + if len(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) > 0 { // Put key in ECDSA format - if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { - *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) + if strings.HasPrefix(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, "0x") { + vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey = strings.Replace(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, "0x", "04", 1) } // Generate compressed public key and key hash - pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) + pubBytes, err := hex.DecodeString(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) helpers.PanicErr(err) pk, err := crypto.UnmarshalPubkey(pubBytes) helpers.PanicErr(err) @@ -628,10 +643,10 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, SetCoordinatorConfig( e, *coordinator, - uint16(*coordinatorConfig.MinConfs), - uint32(*coordinatorConfig.MaxGasLimit), - uint32(*coordinatorConfig.StalenessSeconds), - uint32(*coordinatorConfig.GasAfterPayment), + uint16(coordinatorConfig.MinConfs), + uint32(coordinatorConfig.MaxGasLimit), + uint32(coordinatorConfig.StalenessSeconds), + uint32(coordinatorConfig.GasAfterPayment), coordinatorConfig.FallbackWeiPerUnitLink, coordinatorConfig.FeeConfig, ) @@ -639,12 +654,12 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, fmt.Println("\nConfig set, getting current config from deployed contract...") PrintCoordinatorConfig(coordinator) - if len(*registerKeyUncompressedPubKey) > 0 { + if len(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) > 0 { fmt.Println("\nRegistering proving key...") //NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able // easily withdraw funds from Coordinator contract back to EOA account - RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, e.Owner.From.String()) + RegisterCoordinatorProvingKey(e, *coordinator, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, vrfKeyRegistrationConfig.RegisterAgainstAddress) fmt.Println("\nProving key registered, getting proving key hashes from deployed contract...") _, _, provingKeyHashes, configErr := coordinator.GetRequestConfig(nil) @@ -690,7 +705,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress batchFulfillmentEnabled, //batchFulfillmentEnabled compressedPkHex, //publicKey - *coordinatorConfig.MinConfs, //minIncomingConfirmations + coordinatorConfig.MinConfs, //minIncomingConfirmations e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, @@ -768,7 +783,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, "\nVRF Subscription LINK Balance:", *subscriptionBalanceJuels, "\nVRF Subscription Native Balance:", *subscriptionBalanceNativeWei, "\nPossible VRF Request command: ", - fmt.Sprintf("go run . eoa-load-test-request-with-metrics --consumer-address=%s --sub-id=%d --key-hash=%s --request-confirmations %d --requests 1 --runs 1 --cb-gas-limit 1_000_000", consumerAddress, subID, keyHash, *coordinatorConfig.MinConfs), + fmt.Sprintf("go run . eoa-load-test-request-with-metrics --consumer-address=%s --sub-id=%d --key-hash=%s --request-confirmations %d --requests 1 --runs 1 --cb-gas-limit 1_000_000", consumerAddress, subID, keyHash, coordinatorConfig.MinConfs), "\nRetrieve Request Status: ", fmt.Sprintf("go run . eoa-load-test-read-metrics --consumer-address=%s", consumerAddress), "\nA node can now be configured to run a VRF job with the below job spec :\n", From c80fb93bc127b0021d4d2f98ff64001154661c54 Mon Sep 17 00:00:00 2001 From: Lei Date: Wed, 8 Nov 2023 08:52:15 -0800 Subject: [PATCH 107/327] remove duplicate contracts (#11127) --- .../native_solc_compile_all_automation | 2 - .../automation/testhelpers/KeeperBase.sol | 21 ---------- .../testhelpers/KeeperCompatibleInterface.sol | 42 ------------------- .../automation/testhelpers/KeeperConsumer.sol | 4 +- .../testhelpers/PerformDataChecker.sol | 2 +- .../keeper_consumer_wrapper.go | 4 +- ...rapper-dependency-versions-do-not-edit.txt | 11 +---- 7 files changed, 6 insertions(+), 80 deletions(-) delete mode 100644 contracts/src/v0.8/automation/testhelpers/KeeperBase.sol delete mode 100644 contracts/src/v0.8/automation/testhelpers/KeeperCompatibleInterface.sol diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index beb557de12..1c54d67713 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -63,8 +63,6 @@ compileContract automation/v2_1/AutomationForwarderLogic.sol compileContract automation/testhelpers/LogTriggeredStreamsLookup.sol compileContract automation/testhelpers/DummyProtocol.sol -compileContract automation/testhelpers/KeeperBase.sol -compileContract automation/testhelpers/KeeperCompatibleInterface.sol compileContract automation/testhelpers/KeeperConsumer.sol compileContract automation/testhelpers/KeeperConsumerPerformance.sol compileContract automation/testhelpers/PerformDataChecker.sol diff --git a/contracts/src/v0.8/automation/testhelpers/KeeperBase.sol b/contracts/src/v0.8/automation/testhelpers/KeeperBase.sol deleted file mode 100644 index 6fe41607f7..0000000000 --- a/contracts/src/v0.8/automation/testhelpers/KeeperBase.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.16; - -contract KeeperBase { - /** - * @notice method that allows it to be simulated via eth_call by checking that - * the sender is the zero address. - */ - function preventExecution() internal view { - require(tx.origin == address(0), "only for simulated backend"); - } - - /** - * @notice modifier that allows it to be simulated via eth_call by checking - * that the sender is the zero address. - */ - modifier cannotExecute() { - preventExecution(); - _; - } -} diff --git a/contracts/src/v0.8/automation/testhelpers/KeeperCompatibleInterface.sol b/contracts/src/v0.8/automation/testhelpers/KeeperCompatibleInterface.sol deleted file mode 100644 index 113f5ef6a5..0000000000 --- a/contracts/src/v0.8/automation/testhelpers/KeeperCompatibleInterface.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.16; - -interface KeeperCompatibleInterface { - /** - * @notice method that is simulated by the keepers to see if any work actually - * needs to be performed. This method does does not actually need to be - * executable, and since it is only ever simulated it can consume lots of gas. - * @dev To ensure that it is never called, you may want to add the - * cannotExecute modifier from KeeperBase to your implementation of this - * method. - * @param checkData specified in the upkeep registration so it is always the - * same for a registered upkeep. This can easily be broken down into specific - * arguments using `abi.decode`, so multiple upkeeps can be registered on the - * same contract and easily differentiated by the contract. - * @return upkeepNeeded boolean to indicate whether the keeper should call - * performUpkeep or not. - * @return performData bytes that the keeper should call performUpkeep with, if - * upkeep is needed. If you would like to encode data to decode later, try - * `abi.encode`. - */ - function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData); - - /** - * @notice method that is actually executed by the keepers, via the registry. - * The data returned by the checkUpkeep simulation will be passed into - * this method to actually be executed. - * @dev The input to this method should not be trusted, and the caller of the - * method should not even be restricted to any single registry. Anyone should - * be able call it, and the input should be validated, there is no guarantee - * that the data passed in is the performData returned from checkUpkeep. This - * could happen due to malicious keepers, racing keepers, or simply a state - * change while the performUpkeep transaction is waiting for confirmation. - * Always validate the data passed in. - * @param performData is the data which was passed back from the checkData - * simulation. If it is encoded, it can easily be decoded into other types by - * calling `abi.decode`. This data should not be trusted, and should be - * validated against the contract's current state. - */ - function performUpkeep(bytes calldata performData) external; -} diff --git a/contracts/src/v0.8/automation/testhelpers/KeeperConsumer.sol b/contracts/src/v0.8/automation/testhelpers/KeeperConsumer.sol index ba4694234a..fb492f376c 100644 --- a/contracts/src/v0.8/automation/testhelpers/KeeperConsumer.sol +++ b/contracts/src/v0.8/automation/testhelpers/KeeperConsumer.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.16; -import "./KeeperCompatibleInterface.sol"; -import "./KeeperBase.sol"; +import "../interfaces/KeeperCompatibleInterface.sol"; +import "../KeeperBase.sol"; contract KeeperConsumer is KeeperCompatibleInterface, KeeperBase { uint public counter; diff --git a/contracts/src/v0.8/automation/testhelpers/PerformDataChecker.sol b/contracts/src/v0.8/automation/testhelpers/PerformDataChecker.sol index 03c57ea8e4..268942f931 100644 --- a/contracts/src/v0.8/automation/testhelpers/PerformDataChecker.sol +++ b/contracts/src/v0.8/automation/testhelpers/PerformDataChecker.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import "./KeeperCompatibleInterface.sol"; +import "../interfaces/KeeperCompatibleInterface.sol"; contract PerformDataChecker is KeeperCompatibleInterface { uint256 public counter; diff --git a/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go b/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go index 8a4ee2c4de..feb614aa83 100644 --- a/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go +++ b/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go @@ -29,8 +29,8 @@ var ( ) var KeeperConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"updateInterval\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastTimeStamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b5060405161036c38038061036c83398101604081905261002f9161003f565b6080524260015560008055610058565b60006020828403121561005157600080fd5b5051919050565b6080516102fa610072600039600060cc01526102fa6000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806361bc221a1161005057806361bc221a1461009d5780636e04ff0d146100a6578063947a36fb146100c757600080fd5b80633f3b3b271461006c5780634585e33b14610088575b600080fd5b61007560015481565b6040519081526020015b60405180910390f35b61009b6100963660046101c5565b6100ee565b005b61007560005481565b6100b96100b43660046101c5565b610103565b60405161007f929190610237565b6100757f000000000000000000000000000000000000000000000000000000000000000081565b6000546100fc9060016102ad565b6000555050565b6000606061010f610157565b6001848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b32156101c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920666f722073696d756c61746564206261636b656e64000000000000604482015260640160405180910390fd5b565b600080602083850312156101d857600080fd5b823567ffffffffffffffff808211156101f057600080fd5b818501915085601f83011261020457600080fd5b81358181111561021357600080fd5b86602082850101111561022557600080fd5b60209290920196919550909350505050565b821515815260006020604081840152835180604085015260005b8181101561026d57858101830151858201606001528201610251565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509392505050565b808201808211156102e7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"updateInterval\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastTimeStamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a060405234801561001057600080fd5b5060405161033838038061033883398101604081905261002f9161003f565b6080524260015560008055610058565b60006020828403121561005157600080fd5b5051919050565b6080516102c6610072600039600060cc01526102c66000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806361bc221a1161005057806361bc221a1461009d5780636e04ff0d146100a6578063947a36fb146100c757600080fd5b80633f3b3b271461006c5780634585e33b14610088575b600080fd5b61007560015481565b6040519081526020015b60405180910390f35b61009b610096366004610191565b6100ee565b005b61007560005481565b6100b96100b4366004610191565b610103565b60405161007f929190610203565b6100757f000000000000000000000000000000000000000000000000000000000000000081565b6000546100fc906001610279565b6000555050565b6000606061010f610157565b6001848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b321561018f576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600080602083850312156101a457600080fd5b823567ffffffffffffffff808211156101bc57600080fd5b818501915085601f8301126101d057600080fd5b8135818111156101df57600080fd5b8660208285010111156101f157600080fd5b60209290920196919550909350505050565b821515815260006020604081840152835180604085015260005b818110156102395785810183015185820160600152820161021d565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509392505050565b808201808211156102b3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000810000a", } var KeeperConsumerABI = KeeperConsumerMetaData.ABI diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index a14b461fa7..6482c01cf8 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,10 +1,4 @@ GETH_VERSION: 1.12.0 -KeeperConsumer: ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 -KeeperConsumerPerformance: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 -PerformDataChecker: ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 -UpkeepCounter: ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 -UpkeepPerformCounterRestrictive: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c -VRFv2Consumer: ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 aggregator_v2v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.bin 95e8814b408bb05bf21742ef580d98698b7db6a9bac6a35c3de12b23aec4ee28 aggregator_v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.bin 351b55d3b0f04af67db6dfb5c92f1c64479400ca1fec77afc20bc0ce65cb49ab authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10 @@ -24,14 +18,12 @@ cron_upkeep_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeep.ab dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.bin 583a448170b13abf7ed64e406e8177d78c9e55ab44efd141eee60de23a71ee3b flags_wrapper: ../../contracts/solc/v0.6/Flags/Flags.abi ../../contracts/solc/v0.6/Flags/Flags.bin 2034d1b562ca37a63068851915e3703980276e8d5f7db6db8a3351a49d69fc4a flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.bin a3b0a6396c4aa3b5ee39b3c4bd45efc89789d4859379a8a92caca3a0496c5794 -functions_billing_registry_events_mock: ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock/FunctionsBillingRegistryEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 -functions_oracle_events_mock: ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock/FunctionsOracleEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin 6501bb9bcf5048bab2737b00685c6984a24867e234ddf5b60a65904eee9a4ebc i_log_automation: ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin 296beccb6af655d6fc3a6e676b244831cce2da6688d3afc4f21f8738ae59e03e keeper_consumer_performance_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 -keeper_consumer_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 +keeper_consumer_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin 2c6163b145082fbab74b7343577a9cec8fda8b0da9daccf2a82581b1f5a84b83 keeper_registrar_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.bin e49b2f8b23da17af1ed2209b8ae0968cc04350554d636711e6c24a3ad3118692 keeper_registrar_wrapper1_2_mock: ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock/KeeperRegistrar1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock/KeeperRegistrar1_2Mock.bin 5b155a7cb3def309fd7525de1d7cd364ebf8491bdc3060eac08ea0ff55ab29bc keeper_registrar_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.bin 647f125c2f0dafabcdc545cb77b15dc2ec3ea9429357806813179b1fd555c2d2 @@ -84,7 +76,6 @@ vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordina vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.bin 295f35ce282060317dfd01f45959f5a2b05ba26913e422fbd4fb6bf90b107006 vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin b0e7c42a30b36d9d31fa9a3f26bad7937152e3dddee5bd8dd3d121390c879ab6 vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin 4a5b86701983b1b65f0a8dfa116b3f6d75f8f706fa274004b57bdf5992e4cec3 -vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin e4409bbe361258273458a5c99408b3d7f0cc57a2560dee91c0596cc6d6f738be vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin 834a2ce0e83276372a0e1446593fd89798f4cf6dc95d4be0113e99fadf61558b vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d From 027068e06365716c615dcbbd7bdcf462e9a228c1 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 8 Nov 2023 11:33:29 -0600 Subject: [PATCH 108/327] bump deps (#11148) * bump deps - github.com/go-webauthn/webauthn v0.8.6 - github.com/prometheus/common v0.45.0 - github.com/prometheus/prometheus v0.47.2 - github.com/tidwall/gjson v1.17.0 - gonum.org/v1/gonum v0.14.0 * Use UnmarshalFirst to maintain compatibility --------- Co-authored-by: Ryan Tinianov --- core/cbor/cbor.go | 7 +++--- core/scripts/go.mod | 20 +++++++-------- core/scripts/go.sum | 53 +++++++++++++++++----------------------- go.mod | 20 +++++++-------- go.sum | 53 +++++++++++++++++----------------------- integration-tests/go.mod | 22 ++++++++--------- integration-tests/go.sum | 48 ++++++++++++++++-------------------- 7 files changed, 102 insertions(+), 121 deletions(-) diff --git a/core/cbor/cbor.go b/core/cbor/cbor.go index 754e572934..cc3f74e423 100644 --- a/core/cbor/cbor.go +++ b/core/cbor/cbor.go @@ -17,7 +17,7 @@ func ParseDietCBOR(b []byte) (map[string]interface{}, error) { b = autoAddMapDelimiters(b) var m map[interface{}]interface{} - if err := cbor.Unmarshal(b, &m); err != nil { + if _, err := cbor.UnmarshalFirst(b, &m); err != nil { return nil, err } @@ -38,7 +38,8 @@ func ParseDietCBOR(b []byte) (map[string]interface{}, error) { // "top-level map" requirement of "diet" CBOR. func ParseDietCBORToStruct(b []byte, v interface{}) error { b = autoAddMapDelimiters(b) - return cbor.Unmarshal(b, v) + _, err := cbor.UnmarshalFirst(b, v) + return err } // ParseStandardCBOR parses CBOR in "standards compliant" mode. @@ -49,7 +50,7 @@ func ParseStandardCBOR(b []byte) (a interface{}, err error) { if len(b) == 0 { return nil, nil } - if err = cbor.Unmarshal(b, &a); err != nil { + if _, err = cbor.UnmarshalFirst(b, &a); err != nil { return nil, err } return diff --git a/core/scripts/go.mod b/core/scripts/go.mod index b72d07978f..aada3850db 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -106,7 +106,7 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gagliardetto/binary v0.7.1 // indirect github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect @@ -132,13 +132,13 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/revoke v0.1.9 // indirect - github.com/go-webauthn/webauthn v0.8.2 // indirect + github.com/go-webauthn/webauthn v0.8.6 // indirect + github.com/go-webauthn/x v0.1.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect @@ -146,7 +146,7 @@ require ( github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/go-tpm v0.3.3 // indirect + github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect @@ -254,7 +254,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/minio/sha256-simd v0.1.1 // indirect @@ -289,9 +289,9 @@ require ( github.com/pressly/goose/v3 v3.15.1 // indirect github.com/prometheus/client_golang v1.17.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.46.0 // indirect + github.com/prometheus/prometheus v0.47.2 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rjeczalik/notify v0.9.3 // indirect @@ -325,7 +325,7 @@ require ( github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a // indirect github.com/tidwall/btree v1.6.0 // indirect - github.com/tidwall/gjson v1.16.0 // indirect + github.com/tidwall/gjson v1.17.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect @@ -367,7 +367,7 @@ require ( golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect - gonum.org/v1/gonum v0.13.0 // indirect + gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index b1e62010ab..4f42c84d4e 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -391,8 +391,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= -github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= +github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= @@ -478,10 +478,10 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-webauthn/revoke v0.1.9 h1:gSJ1ckA9VaKA2GN4Ukp+kiGTk1/EXtaDb1YE8RknbS0= -github.com/go-webauthn/revoke v0.1.9/go.mod h1:j6WKPnv0HovtEs++paan9g3ar46gm1NarktkXBaPR+w= -github.com/go-webauthn/webauthn v0.8.2 h1:8KLIbpldjz9KVGHfqEgJNbkhd7bbRXhNw4QWFJE15oA= -github.com/go-webauthn/webauthn v0.8.2/go.mod h1:d+ezx/jMCNDiqSMzOchuynKb9CVU1NM9BumOnokfcVQ= +github.com/go-webauthn/webauthn v0.8.6 h1:bKMtL1qzd2WTFkf1mFTVbreYrwn7dsYmEPjTq6QN90E= +github.com/go-webauthn/webauthn v0.8.6/go.mod h1:emwVLMCI5yx9evTTvr0r+aOZCdWJqMfbRhF0MufyUog= +github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= +github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -499,9 +499,12 @@ github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q8 github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= @@ -567,12 +570,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI= -github.com/google/go-tpm v0.3.0/go.mod h1:iVLWvrPp/bHeEkxTFi9WG6K9w0iy2yIszHwZGHPbzAw= -github.com/google/go-tpm v0.3.3 h1:P/ZFNBZYXRxc+z7i5uyd8VP7MaDteuLZInzrH2idRGo= -github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51BeghL4= -github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845/go.mod h1:AVfHadzbdzHo54inR2x1v640jdi1YSi3NauM2DUsxk0= -github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4= +github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -626,7 +625,6 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -1180,8 +1178,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= @@ -1388,16 +1386,16 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw= -github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4= +github.com/prometheus/prometheus v0.47.2 h1:jWcnuQHz1o1Wu3MZ6nMJDuTI0kU5yJp9pkxh8XEkNvI= +github.com/prometheus/prometheus v0.47.2/go.mod h1:J/bmOSjgH7lFxz2gZhrWEZs2i64vMS+HIuZfmYNhJ/M= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= @@ -1507,7 +1505,6 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= @@ -1518,7 +1515,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= @@ -1565,8 +1561,8 @@ github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a/go.mod h1:/sfW47 github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= -github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -1814,7 +1810,6 @@ golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1869,8 +1864,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1957,7 +1952,6 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2089,8 +2083,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= -gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= +gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= +gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -2176,7 +2170,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go. google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= diff --git a/go.mod b/go.mod index cd0fb0fab4..e6af9533dc 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/esote/minmaxheap v1.0.0 github.com/ethereum/go-ethereum v1.12.0 github.com/fatih/color v1.15.0 - github.com/fxamacker/cbor/v2 v2.4.0 + github.com/fxamacker/cbor/v2 v2.5.0 github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 github.com/getsentry/sentry-go v0.19.0 github.com/gin-contrib/cors v1.4.0 @@ -22,7 +22,7 @@ require ( github.com/gin-contrib/sessions v0.0.5 github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 github.com/gin-gonic/gin v1.9.1 - github.com/go-webauthn/webauthn v0.8.2 + github.com/go-webauthn/webauthn v0.8.6 github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 github.com/google/uuid v1.3.1 github.com/gorilla/securecookie v1.1.1 @@ -57,8 +57,8 @@ require ( github.com/pressly/goose/v3 v3.15.1 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 - github.com/prometheus/common v0.44.0 - github.com/prometheus/prometheus v0.46.0 + github.com/prometheus/common v0.45.0 + github.com/prometheus/prometheus v0.47.2 github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 @@ -79,7 +79,7 @@ require ( github.com/spf13/cast v1.5.1 github.com/stretchr/testify v1.8.4 github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a - github.com/tidwall/gjson v1.16.0 + github.com/tidwall/gjson v1.17.0 github.com/ugorji/go/codec v1.2.11 github.com/ulule/limiter/v3 v3.11.2 github.com/umbracle/ethgo v0.1.3 @@ -96,7 +96,7 @@ require ( golang.org/x/text v0.13.0 golang.org/x/time v0.3.0 golang.org/x/tools v0.14.0 - gonum.org/v1/gonum v0.13.0 + gonum.org/v1/gonum v0.14.0 google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 @@ -182,13 +182,13 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/revoke v0.1.9 // indirect + github.com/go-webauthn/x v0.1.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -196,7 +196,7 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/go-tpm v0.3.3 // indirect + github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/gorilla/context v1.1.1 // indirect @@ -287,7 +287,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/minio/sha256-simd v0.1.1 // indirect diff --git a/go.sum b/go.sum index fb97398f84..5c70c22a75 100644 --- a/go.sum +++ b/go.sum @@ -386,8 +386,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= -github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= +github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= @@ -475,10 +475,10 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-webauthn/revoke v0.1.9 h1:gSJ1ckA9VaKA2GN4Ukp+kiGTk1/EXtaDb1YE8RknbS0= -github.com/go-webauthn/revoke v0.1.9/go.mod h1:j6WKPnv0HovtEs++paan9g3ar46gm1NarktkXBaPR+w= -github.com/go-webauthn/webauthn v0.8.2 h1:8KLIbpldjz9KVGHfqEgJNbkhd7bbRXhNw4QWFJE15oA= -github.com/go-webauthn/webauthn v0.8.2/go.mod h1:d+ezx/jMCNDiqSMzOchuynKb9CVU1NM9BumOnokfcVQ= +github.com/go-webauthn/webauthn v0.8.6 h1:bKMtL1qzd2WTFkf1mFTVbreYrwn7dsYmEPjTq6QN90E= +github.com/go-webauthn/webauthn v0.8.6/go.mod h1:emwVLMCI5yx9evTTvr0r+aOZCdWJqMfbRhF0MufyUog= +github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= +github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -496,9 +496,12 @@ github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q8 github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= @@ -564,12 +567,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI= -github.com/google/go-tpm v0.3.0/go.mod h1:iVLWvrPp/bHeEkxTFi9WG6K9w0iy2yIszHwZGHPbzAw= -github.com/google/go-tpm v0.3.3 h1:P/ZFNBZYXRxc+z7i5uyd8VP7MaDteuLZInzrH2idRGo= -github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51BeghL4= -github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845/go.mod h1:AVfHadzbdzHo54inR2x1v640jdi1YSi3NauM2DUsxk0= -github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4= +github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -623,7 +622,6 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -1181,8 +1179,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= @@ -1391,16 +1389,16 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw= -github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4= +github.com/prometheus/prometheus v0.47.2 h1:jWcnuQHz1o1Wu3MZ6nMJDuTI0kU5yJp9pkxh8XEkNvI= +github.com/prometheus/prometheus v0.47.2/go.mod h1:J/bmOSjgH7lFxz2gZhrWEZs2i64vMS+HIuZfmYNhJ/M= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= @@ -1509,7 +1507,6 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= @@ -1520,7 +1517,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= @@ -1567,8 +1563,8 @@ github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a/go.mod h1:/sfW47 github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= -github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -1817,7 +1813,6 @@ golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1873,8 +1868,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1960,7 +1955,6 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2094,8 +2088,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= -gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= +gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= +gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -2181,7 +2175,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go. google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 2ac3c38a71..8fe63a46d2 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -142,7 +142,7 @@ require ( github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fvbommel/sortorder v1.0.2 // indirect - github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gagliardetto/binary v0.7.1 // indirect github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect @@ -174,15 +174,15 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/revoke v0.1.9 // indirect - github.com/go-webauthn/webauthn v0.8.2 // indirect + github.com/go-webauthn/webauthn v0.8.6 // indirect + github.com/go-webauthn/x v0.1.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect github.com/gogo/status v1.1.1 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -191,7 +191,7 @@ require ( github.com/google/gnostic v0.6.9 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/go-tpm v0.3.3 // indirect + github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect @@ -316,7 +316,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/miekg/dns v1.1.55 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect @@ -369,11 +369,11 @@ require ( github.com/prometheus/alertmanager v0.25.1 // indirect github.com/prometheus/client_golang v1.17.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.10.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.46.0 // indirect + github.com/prometheus/prometheus v0.47.2 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect @@ -409,7 +409,7 @@ require ( github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a // indirect github.com/tidwall/btree v1.6.0 // indirect - github.com/tidwall/gjson v1.16.0 // indirect + github.com/tidwall/gjson v1.17.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect @@ -456,14 +456,14 @@ require ( golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect - gonum.org/v1/gonum v0.13.0 // indirect + gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index ce5e51a568..b8e8b205c8 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -994,8 +994,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= -github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= -github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= +github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= @@ -1134,10 +1134,10 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-webauthn/revoke v0.1.9 h1:gSJ1ckA9VaKA2GN4Ukp+kiGTk1/EXtaDb1YE8RknbS0= -github.com/go-webauthn/revoke v0.1.9/go.mod h1:j6WKPnv0HovtEs++paan9g3ar46gm1NarktkXBaPR+w= -github.com/go-webauthn/webauthn v0.8.2 h1:8KLIbpldjz9KVGHfqEgJNbkhd7bbRXhNw4QWFJE15oA= -github.com/go-webauthn/webauthn v0.8.2/go.mod h1:d+ezx/jMCNDiqSMzOchuynKb9CVU1NM9BumOnokfcVQ= +github.com/go-webauthn/webauthn v0.8.6 h1:bKMtL1qzd2WTFkf1mFTVbreYrwn7dsYmEPjTq6QN90E= +github.com/go-webauthn/webauthn v0.8.6/go.mod h1:emwVLMCI5yx9evTTvr0r+aOZCdWJqMfbRhF0MufyUog= +github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= +github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= @@ -1189,9 +1189,12 @@ github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRs github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -1266,12 +1269,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI= -github.com/google/go-tpm v0.3.0/go.mod h1:iVLWvrPp/bHeEkxTFi9WG6K9w0iy2yIszHwZGHPbzAw= -github.com/google/go-tpm v0.3.3 h1:P/ZFNBZYXRxc+z7i5uyd8VP7MaDteuLZInzrH2idRGo= -github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51BeghL4= -github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845/go.mod h1:AVfHadzbdzHo54inR2x1v640jdi1YSi3NauM2DUsxk0= -github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4= +github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -1351,7 +1350,6 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -1987,8 +1985,9 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= @@ -2262,8 +2261,8 @@ github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+ github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= @@ -2419,7 +2418,6 @@ github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= @@ -2430,7 +2428,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= @@ -2482,8 +2479,8 @@ github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e/go.mod h1: github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= -github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -2801,7 +2798,6 @@ golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -2900,8 +2896,8 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -3007,7 +3003,6 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -3192,8 +3187,8 @@ gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJ gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= -gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= +gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= +gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= @@ -3407,7 +3402,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go. google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= From 4ccd1c5e63a398ae17b0ede50e3785630277a20d Mon Sep 17 00:00:00 2001 From: Cedric Date: Wed, 8 Nov 2023 17:35:58 +0000 Subject: [PATCH 109/327] Randomize database names when using heavyweight ORM (#11233) --- core/chains/evm/logpoller/log_poller_test.go | 6 ++-- core/chains/evm/txmgr/broadcaster_test.go | 4 +-- core/cmd/shell_local_test.go | 6 ++-- core/internal/cltest/heavyweight/orm.go | 24 ++++++++------- core/internal/features/features_test.go | 15 +++++----- .../features/ocr2/features_ocr2_test.go | 11 ++++--- .../fluxmonitorv2/flux_monitor_test.go | 18 ++---------- .../fluxmonitorv2/integrations_test.go | 2 +- core/services/keeper/integration_test.go | 6 ++-- .../v1/internal/testutils.go | 7 ++--- .../ocr2/plugins/mercury/helpers_test.go | 2 +- .../evm21/logprovider/integration_test.go | 3 +- .../plugins/ocr2keeper/integration_21_test.go | 4 +-- .../plugins/ocr2keeper/integration_test.go | 11 ++++--- .../internal/ocr2vrf_integration_test.go | 2 +- core/services/pg/event_broadcaster_test.go | 2 +- core/services/pg/lease_lock_test.go | 4 +-- core/services/pipeline/orm_test.go | 14 ++++----- core/services/vrf/v1/integration_test.go | 5 ++-- core/services/vrf/v2/bhs_feeder_test.go | 2 +- .../vrf/v2/integration_helpers_test.go | 29 +++++++++---------- .../vrf/v2/integration_v2_plus_test.go | 2 +- core/services/vrf/v2/integration_v2_test.go | 10 +++---- core/store/migrate/migrate_test.go | 10 +++---- 24 files changed, 92 insertions(+), 107 deletions(-) diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 471c728cdd..5f013ca914 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -85,7 +85,7 @@ func populateDatabase(t testing.TB, o *logpoller.DbORM, chainID *big.Int) (commo func BenchmarkSelectLogsCreatedAfter(b *testing.B) { chainId := big.NewInt(137) - _, db := heavyweight.FullTestDBV2(b, "logs_scale", nil) + _, db := heavyweight.FullTestDBV2(b, nil) o := logpoller.NewORM(chainId, db, logger.TestLogger(b), pgtest.NewQConfig(false)) event, address, _ := populateDatabase(b, o, chainId) @@ -103,7 +103,7 @@ func BenchmarkSelectLogsCreatedAfter(b *testing.B) { func TestPopulateLoadedDB(t *testing.T) { t.Skip("Only for local load testing and query analysis") - _, db := heavyweight.FullTestDBV2(t, "logs_scale", nil) + _, db := heavyweight.FullTestDBV2(t, nil) chainID := big.NewInt(137) o := logpoller.NewORM(big.NewInt(137), db, logger.TestLogger(t), pgtest.NewQConfig(true)) @@ -1328,7 +1328,7 @@ func TestNotifyAfterInsert(t *testing.T) { // Use a non-transactional db for this test because notify events // are not delivered until the transaction is committed. var dbURL string - _, sqlxDB := heavyweight.FullTestDBV2(t, "notify_after_insert_log", func(c *chainlink.Config, s *chainlink.Secrets) { + _, sqlxDB := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { dbURL = s.Database.URL.URL().String() }) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index ca2697ca99..fcbc7a1f4c 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -75,7 +75,7 @@ func NewTestEthBroadcaster( } func TestEthBroadcaster_Lifecycle(t *testing.T) { - cfg, db := heavyweight.FullTestDBV2(t, "eth_broadcaster_optimistic_locking", nil) + cfg, db := heavyweight.FullTestDBV2(t, nil) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -565,7 +565,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testing.T) { // non-transactional DB needed because we deliberately test for FK violation - cfg, db := heavyweight.FullTestDBV2(t, "eth_broadcaster_optimistic_locking", nil) + cfg, db := heavyweight.FullTestDBV2(t, nil) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ccfg := evmtest.NewChainScopedConfig(t, cfg) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index a73e98a935..4d906214ef 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -280,7 +280,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { // Use a non-transactional db for this test because we need to // test multiple connections to the database, and changes made within // the transaction cannot be seen from another connection. - config, sqlxDB := heavyweight.FullTestDBV2(t, "rebroadcasttransactions", func(c *chainlink.Config, s *chainlink.Secrets) { + config, sqlxDB := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres // evm config is used in this test. but if set, it must be pass config validation. // simplest to make it nil @@ -359,7 +359,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { // Use the non-transactional db for this test because we need to // test multiple connections to the database, and changes made within // the transaction cannot be seen from another connection. - config, sqlxDB := heavyweight.FullTestDBV2(t, "rebroadcasttransactions_outsiderange", func(c *chainlink.Config, s *chainlink.Secrets) { + config, sqlxDB := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres // evm config is used in this test. but if set, it must be pass config validation. // simplest to make it nil @@ -437,7 +437,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - config, sqlxDB := heavyweight.FullTestDBV2(t, "rebroadcasttransactions_outsiderange", func(c *chainlink.Config, s *chainlink.Secrets) { + config, sqlxDB := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres c.EVM = nil diff --git a/core/internal/cltest/heavyweight/orm.go b/core/internal/cltest/heavyweight/orm.go index 2f9370f35a..b46e7114cf 100644 --- a/core/internal/cltest/heavyweight/orm.go +++ b/core/internal/cltest/heavyweight/orm.go @@ -7,13 +7,14 @@ import ( "database/sql" "errors" "fmt" - "math/rand" "net/url" "os" "path" "runtime" + "strings" "testing" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -30,21 +31,25 @@ import ( // FullTestDBV2 creates a pristine DB which runs in a separate database than the normal // unit tests, so you can do things like use other Postgres connection types with it. -func FullTestDBV2(t testing.TB, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return prepareFullTestDBV2(t, name, false, true, overrideFn) +func FullTestDBV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { + return prepareFullTestDBV2(t, false, true, overrideFn) } // FullTestDBNoFixturesV2 is the same as FullTestDB, but it does not load fixtures. -func FullTestDBNoFixturesV2(t testing.TB, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return prepareFullTestDBV2(t, name, false, false, overrideFn) +func FullTestDBNoFixturesV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { + return prepareFullTestDBV2(t, false, false, overrideFn) } // FullTestDBEmptyV2 creates an empty DB (without migrations). -func FullTestDBEmptyV2(t testing.TB, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return prepareFullTestDBV2(t, name, true, false, overrideFn) +func FullTestDBEmptyV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { + return prepareFullTestDBV2(t, true, false, overrideFn) } -func prepareFullTestDBV2(t testing.TB, name string, empty bool, loadFixtures bool, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { +func generateName() string { + return strings.ReplaceAll(uuid.New().String(), "-", "") +} + +func prepareFullTestDBV2(t testing.TB, empty bool, loadFixtures bool, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { testutils.SkipShort(t, "FullTestDB") if empty && loadFixtures { @@ -59,8 +64,7 @@ func prepareFullTestDBV2(t testing.TB, name string, empty bool, loadFixtures boo }) require.NoError(t, os.MkdirAll(gcfg.RootDir(), 0700)) - name = fmt.Sprintf("%s_%x", name, rand.Intn(0xFFF)) // to avoid name collisions - migrationTestDBURL, err := dropAndCreateThrowawayTestDB(gcfg.Database().URL(), name, empty) + migrationTestDBURL, err := dropAndCreateThrowawayTestDB(gcfg.Database().URL(), generateName(), empty) require.NoError(t, err) db, err := pg.NewConnection(migrationTestDBURL, dialects.Postgres, gcfg.Database()) require.NoError(t, err) diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 23451bf29f..b5f42d8bf3 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -675,11 +675,11 @@ func setupOCRContracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBac return owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress } -func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, dbName string, +func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, b *backends.SimulatedBackend, ns ocrnetworking.NetworkingStack, overrides func(c *chainlink.Config, s *chainlink.Secrets), ) (*cltest.TestApplication, string, common.Address, ocrkey.KeyV2) { p2pKey := keystest.NewP2PKeyV2(t) - config, _ := heavyweight.FullTestDBV2(t, dbName, func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. c.OCR.Enabled = ptr(true) @@ -748,7 +748,6 @@ func setupForwarderEnabledNode( owner *bind.TransactOpts, portV1, portV2 int, - dbName string, b *backends.SimulatedBackend, ns ocrnetworking.NetworkingStack, overrides func(c *chainlink.Config, s *chainlink.Secrets), @@ -760,7 +759,7 @@ func setupForwarderEnabledNode( ocrkey.KeyV2, ) { p2pKey := keystest.NewP2PKeyV2(t) - config, _ := heavyweight.FullTestDBV2(t, dbName, func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. c.OCR.Enabled = ptr(true) @@ -867,7 +866,7 @@ func TestIntegration_OCR(t *testing.T) { // Note it's plausible these ports could be occupied on a CI machine. // May need a port randomize + retry approach if we observe collisions. - appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, fmt.Sprintf("b_%d", test.id), b, test.ns, nil) + appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, b, test.ns, nil) var ( oracles []confighelper.OracleIdentityExtra transmitters []common.Address @@ -878,7 +877,7 @@ func TestIntegration_OCR(t *testing.T) { for i := 0; i < numOracles; i++ { portV1 := ports[2*i] portV2 := ports[2*i+1] - app, peerID, transmitter, key := setupNode(t, owner, portV1, portV2, fmt.Sprintf("o%d_%d", i, test.id), b, test.ns, func(c *chainlink.Config, s *chainlink.Secrets) { + app, peerID, transmitter, key := setupNode(t, owner, portV1, portV2, b, test.ns, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(test.eip1559) if test.ns != ocrnetworking.NetworkingStackV1 { @@ -1092,7 +1091,7 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { // Note it's plausible these ports could be occupied on a CI machine. // May need a port randomize + retry approach if we observe collisions. - appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, fmt.Sprintf("b_%d", 1), b, ocrnetworking.NetworkingStackV2, nil) + appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, b, ocrnetworking.NetworkingStackV2, nil) var ( oracles []confighelper.OracleIdentityExtra @@ -1105,7 +1104,7 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { for i := 0; i < numOracles; i++ { portV1 := ports[2*i] portV2 := ports[2*i+1] - app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, portV1, portV2, fmt.Sprintf("o%d_%d", i, 1), b, ocrnetworking.NetworkingStackV2, func(c *chainlink.Config, s *chainlink.Secrets) { + app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, portV1, portV2, b, ocrnetworking.NetworkingStackV2, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 25b6781c4e..3e22093568 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -105,13 +105,12 @@ func setupNodeOCR2( t *testing.T, owner *bind.TransactOpts, port int, - dbName string, useForwarder bool, b *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, ) *ocr2Node { p2pKey := keystest.NewP2PKeyV2(t) - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. c.Feature.LogPoller = ptr(true) @@ -193,7 +192,7 @@ func TestIntegration_OCR2(t *testing.T) { lggr := logger.TestLogger(t) bootstrapNodePort := freeport.GetOne(t) - bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, "bootstrap", false /* useForwarders */, b, nil) + bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, false /* useForwarders */, b, nil) var ( oracles []confighelper2.OracleIdentityExtra @@ -203,7 +202,7 @@ func TestIntegration_OCR2(t *testing.T) { ) ports := freeport.GetN(t, 4) for i := 0; i < 4; i++ { - node := setupNodeOCR2(t, owner, ports[i], fmt.Sprintf("oracle%d", i), false /* useForwarders */, b, []commontypes.BootstrapperLocator{ + node := setupNodeOCR2(t, owner, ports[i], false /* useForwarders */, b, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }) @@ -477,7 +476,7 @@ func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { lggr := logger.TestLogger(t) bootstrapNodePort := freeport.GetOne(t) - bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, "bootstrap", true /* useForwarders */, b, nil) + bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, true /* useForwarders */, b, nil) var ( oracles []confighelper2.OracleIdentityExtra @@ -488,7 +487,7 @@ func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { ) ports := freeport.GetN(t, 4) for i := uint16(0); i < 4; i++ { - node := setupNodeOCR2(t, owner, ports[i], fmt.Sprintf("oracle%d", i), true /* useForwarders */, b, []commontypes.BootstrapperLocator{ + node := setupNodeOCR2(t, owner, ports[i], true /* useForwarders */, b, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }) diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index 0d1eb085a8..26ec520e7c 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -3,7 +3,6 @@ package fluxmonitorv2_test import ( "fmt" "math/big" - "strings" "testing" "time" @@ -26,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -284,8 +282,8 @@ func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { } // setupStoreWithKey setups a new store and adds a key to the keystore -func setupFullDBWithKey(t *testing.T, name string) (*sqlx.DB, common.Address) { - cfg, db := heavyweight.FullTestDBV2(t, name, nil) +func setupFullDBWithKey(t *testing.T) (*sqlx.DB, common.Address) { + cfg, db := heavyweight.FullTestDBV2(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -906,18 +904,8 @@ func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { g.Eventually(func() int { return len(pollOccured) }, testutils.WaitTimeout(t)).Should(gomega.Equal(3)) } -// chainlink_test_TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped -// 63 bytes is max and chainlink_test_ takes up 15, plus 4 for a random hex suffix. -func dbName(s string) string { - diff := len(cmd.TestDBNamePrefix) + len("_FFF") - if len(s) <= diff { - return strings.ReplaceAll(strings.ToLower(s), "/", "") - } - return strings.ReplaceAll(strings.ToLower(s[len(s)-diff:]), "/", "") -} - func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { - db, nodeAddr := setupFullDBWithKey(t, "hibernation") + db, nodeAddr := setupFullDBWithKey(t) oracles := []common.Address{nodeAddr, testutils.NewAddress()} const ( diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index 2c45ed5ad8..b2f24e08d5 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -206,7 +206,7 @@ func startApplication( fa fluxAggregatorUniverse, overrides func(c *chainlink.Config, s *chainlink.Secrets), ) *cltest.TestApplication { - config, _ := heavyweight.FullTestDBV2(t, dbName(t.Name()), overrides) + config, _ := heavyweight.FullTestDBV2(t, overrides) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, fa.backend, fa.key) require.NoError(t, app.Start(testutils.Context(t))) return app diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index 39431063bc..f76ef93574 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -236,7 +236,7 @@ func TestKeeperEthIntegration(t *testing.T) { backend.Commit() // setup app - config, db := heavyweight.FullTestDBV2(t, fmt.Sprintf("keeper_eth_integration_%s", test.name), func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test @@ -393,7 +393,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { backend.Commit() // setup app - config, db := heavyweight.FullTestDBV2(t, "keeper_forwarder_flow", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps @@ -540,7 +540,7 @@ func TestMaxPerformDataSize(t *testing.T) { backend.Commit() // setup app - config, db := heavyweight.FullTestDBV2(t, "keeper_max_perform_data_test", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test c.Keeper.Registry.MaxPerformDataSize = ptr(uint32(maxPerformDataSize)) // set the max perform data size diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index 5c824323eb..9f63d60eef 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -302,7 +302,6 @@ func StartNewNode( t *testing.T, owner *bind.TransactOpts, port int, - dbName string, b *backends.SimulatedBackend, maxGas uint32, p2pV2Bootstrappers []commontypes.BootstrapperLocator, @@ -310,7 +309,7 @@ func StartNewNode( thresholdKeyShare string, ) *Node { p2pKey := keystest.NewP2PKeyV2(t) - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) c.Feature.LogPoller = ptr(true) @@ -550,7 +549,7 @@ func CreateFunctionsNodes( } bootstrapPort := freeport.GetOne(t) - bootstrapNode = StartNewNode(t, owner, bootstrapPort, "bootstrap", b, uint32(maxGas), nil, nil, "") + bootstrapNode = StartNewNode(t, owner, bootstrapPort, b, uint32(maxGas), nil, nil, "") AddBootstrapJob(t, bootstrapNode.App, routerAddress) // oracle nodes with jobs, bridges and mock EAs @@ -568,7 +567,7 @@ func CreateFunctionsNodes( } else { ocr2Keystore = ocr2Keystores[i] } - oracleNode := StartNewNode(t, owner, ports[i], fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ + oracleNode := StartNewNode(t, owner, ports[i], b, uint32(maxGas), []commontypes.BootstrapperLocator{ {PeerID: bootstrapNode.PeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapPort)}}, }, ocr2Keystore, thresholdKeyShare) oracleNodes = append(oracleNodes, oracleNode.App) diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index 60904b5813..588f772120 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -163,7 +163,7 @@ func setupNode( p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { // [JobPipeline] // MaxSuccessfulRuns = 0 c.JobPipeline.MaxSuccessfulRuns = ptr(uint64(0)) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index dad3542039..63ed4114b8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -3,7 +3,6 @@ package logprovider_test import ( "context" "errors" - "fmt" "math/big" "testing" "time" @@ -693,7 +692,7 @@ func setupBackend(t *testing.T) (*backends.SimulatedBackend, func(), []*bind.Tra func ptr[T any](v T) *T { return &v } func setupDB(t *testing.T) *sqlx.DB { - _, db := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", "chainlink_test", 5432), func(c *chainlink.Config, s *chainlink.Secrets) { + _, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.OCR.Enabled = ptr(false) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 15280de73c..562f972bc4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -479,7 +479,7 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK // Setup bootstrap + oracle nodes bootstrapNodePort := freeport.GetOne(t) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, mServer) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, mServer) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, } @@ -490,7 +490,7 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK // Set up the minimum 4 oracles all funded ports := freeport.GetN(t, 4) for i := 0; i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + app, peerID, transmitter, kb := setupNode(t, ports[i], nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, mServer) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 7c881a18eb..f50321631c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -111,7 +111,6 @@ func deployKeeper20Registry( func setupNode( t *testing.T, port int, - dbName string, nodeKey ethkey.KeyV2, backend *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, @@ -119,7 +118,7 @@ func setupNode( ) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) { p2pKey := keystest.NewP2PKeyV2(t) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} - cfg, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { + cfg, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.OCR.Enabled = ptr(false) @@ -240,7 +239,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { // Setup bootstrap + oracle nodes bootstrapNodePort := freeport.GetOne(t) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, } @@ -251,7 +250,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { // Set up the minimum 4 oracles all funded ports := freeport.GetN(t, 4) for i := 0; i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + app, peerID, transmitter, kb := setupNode(t, ports[i], nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, NewSimulatedMercuryServer()) @@ -501,7 +500,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { effectiveTransmitters := make([]common.Address, 0) // Setup bootstrap + oracle nodes bootstrapNodePort := freeport.GetOne(t) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -513,7 +512,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { // Set up the minimum 4 oracles all funded ports := freeport.GetN(t, 4) for i := 0; i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + app, peerID, transmitter, kb := setupNode(t, ports[i], nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, NewSimulatedMercuryServer()) diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index cf7a408725..0dbb6a5915 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -226,7 +226,7 @@ func setupNodeOCR2( p2pV2Bootstrappers []commontypes.BootstrapperLocator, ) *ocr2Node { p2pKey := keystest.NewP2PKeyV2(t) - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. c.Feature.LogPoller = ptr(true) diff --git a/core/services/pg/event_broadcaster_test.go b/core/services/pg/event_broadcaster_test.go index bea7dfb5a8..a82e26e058 100644 --- a/core/services/pg/event_broadcaster_test.go +++ b/core/services/pg/event_broadcaster_test.go @@ -16,7 +16,7 @@ import ( ) func TestEventBroadcaster(t *testing.T) { - config, _ := heavyweight.FullTestDBNoFixturesV2(t, "event_broadcaster", nil) + config, _ := heavyweight.FullTestDBNoFixturesV2(t, nil) eventBroadcaster := cltest.NewEventBroadcaster(t, config.Database().URL()) require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) diff --git a/core/services/pg/lease_lock_test.go b/core/services/pg/lease_lock_test.go index 9f857ffa20..483e03e003 100644 --- a/core/services/pg/lease_lock_test.go +++ b/core/services/pg/lease_lock_test.go @@ -24,7 +24,7 @@ func newLeaseLock(t *testing.T, db *sqlx.DB, cfg pg.LeaseLockConfig) pg.LeaseLoc } func Test_LeaseLock(t *testing.T) { - cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "leaselock", func(c *chainlink.Config, s *chainlink.Secrets) { + cfg, db := heavyweight.FullTestDBNoFixturesV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { t := true c.Database.Lock.Enabled = &t }) @@ -207,7 +207,7 @@ func Test_LeaseLock(t *testing.T) { require.NoError(t, db.Close()) t.Run("on virgin database", func(t *testing.T) { - _, db := heavyweight.FullTestDBEmptyV2(t, "leaselock", nil) + _, db := heavyweight.FullTestDBEmptyV2(t, nil) cfg := pg.LeaseLockConfig{ DefaultQueryTimeout: cfg.Database().DefaultQueryTimeout(), LeaseDuration: 15 * time.Second, diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index f916c24f0a..295ad20a00 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -33,11 +33,11 @@ type ormconfig struct { func (ormconfig) JobPipelineMaxSuccessfulRuns() uint64 { return 123456 } -func setupORM(t *testing.T, name string) (db *sqlx.DB, orm pipeline.ORM) { +func setupORM(t *testing.T, heavy bool) (db *sqlx.DB, orm pipeline.ORM) { t.Helper() - if name != "" { - _, db = heavyweight.FullTestDBV2(t, name, nil) + if heavy { + _, db = heavyweight.FullTestDBV2(t, nil) } else { db = pgtest.NewSqlxDB(t) } @@ -47,12 +47,12 @@ func setupORM(t *testing.T, name string) (db *sqlx.DB, orm pipeline.ORM) { return } -func setupHeavyORM(t *testing.T, name string) (db *sqlx.DB, orm pipeline.ORM) { - return setupORM(t, name) +func setupHeavyORM(t *testing.T) (db *sqlx.DB, orm pipeline.ORM) { + return setupORM(t, true) } func setupLiteORM(t *testing.T) (db *sqlx.DB, orm pipeline.ORM) { - return setupORM(t, "") + return setupORM(t, false) } func Test_PipelineORM_CreateSpec(t *testing.T) { @@ -464,7 +464,7 @@ func Test_PipelineORM_DeleteRun(t *testing.T) { } func Test_PipelineORM_DeleteRunsOlderThan(t *testing.T) { - _, orm := setupHeavyORM(t, "pipeline_runs_reaper") + _, orm := setupHeavyORM(t) var runsIds []int64 diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index b7e6be4318..a7dca56776 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -2,7 +2,6 @@ package v1_test import ( "encoding/hex" - "fmt" "math/big" "strings" "testing" @@ -46,7 +45,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { for _, tt := range tests { test := tt t.Run(test.name, func(t *testing.T) { - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("vrf_jpv2_%v", test.eip1559), func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) }) @@ -129,7 +128,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { func TestIntegration_VRF_WithBHS(t *testing.T) { t.Parallel() - config, _ := heavyweight.FullTestDBV2(t, "vrf_with_bhs", func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].BlockBackfillDepth = ptr[uint32](500) c.Feature.LogPoller = ptr(true) diff --git a/core/services/vrf/v2/bhs_feeder_test.go b/core/services/vrf/v2/bhs_feeder_test.go index 0da28378d0..219fe1c8fd 100644 --- a/core/services/vrf/v2/bhs_feeder_test.go +++ b/core/services/vrf/v2/bhs_feeder_test.go @@ -51,7 +51,7 @@ func TestStartHeartbeats(t *testing.T) { keys = append(keys, ownerKey, vrfKey) - config, _ := heavyweight.FullTestDBV2(t, "vrfv2_needs_blockhash_store", func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, gasLanePriceWei, keySpecificOverrides...)(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index 60a7cd18d2..a086cbbb09 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -1,7 +1,6 @@ package v2_test import ( - "fmt" "math/big" "strings" "testing" @@ -62,7 +61,7 @@ func testSingleConsumerHappyPath( key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_happypath", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -202,7 +201,7 @@ func testMultipleConsumersNeedBHS( GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, }) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_needs_blockhash_store", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), keySpecificOverrides...)(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) @@ -349,7 +348,7 @@ func testMultipleConsumersNeedTrustedBHS( uni.backend.Commit() } - config, db := heavyweight.FullTestDBV2(t, "vrfv2_needs_trusted_blockhash_store", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), keySpecificOverrides...)(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(5_000_000)) @@ -531,7 +530,7 @@ func testSingleConsumerHappyPathBatchFulfillment( ) { key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_batch_happypath", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -635,7 +634,7 @@ func testSingleConsumerNeedsTopUp( ) { key := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(1000) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_needstopup", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(1000), toml.KeySpecific{ // Gas lane. Key: ptr(key.EIP55Address), @@ -739,7 +738,7 @@ func testBlockHeaderFeeder( gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_test_block_header_feeder", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, gasLanePriceWei, toml.KeySpecific{ // Gas lane. Key: ptr(vrfKey.EIP55Address), @@ -894,7 +893,7 @@ func testSingleConsumerForcedFulfillment( key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, fmt.Sprintf("vrfv2_singleconsumer_forcefulfill_%v", batchEnabled), func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1061,7 +1060,7 @@ func testSingleConsumerEIP150( key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, _ := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_eip150_happypath", func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), v2.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1129,7 +1128,7 @@ func testSingleConsumerEIP150Revert( key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, _ := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_eip150_revert", func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), v2.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1192,7 +1191,7 @@ func testSingleConsumerBigGasCallbackSandwich( ) { key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(100) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_bigcallback_sandwich", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(100), v2.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1308,7 +1307,7 @@ func testSingleConsumerMultipleGasLanes( expensiveKey := cltest.MustGenerateRandomKey(t) cheapGasLane := assets.GWei(10) expensiveGasLane := assets.GWei(1000) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_multiplegaslanes", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), v2.KeySpecific{ // Cheap gas lane. Key: ptr(cheapKey.EIP55Address), @@ -1428,7 +1427,7 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( ) { key := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_alwaysrevertingcallback", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), v2.KeySpecific{ // Gas lane. Key: ptr(key.EIP55Address), @@ -1496,7 +1495,7 @@ func testConsumerProxyHappyPath( key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_consumerproxy_happypath", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), v2.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1624,7 +1623,7 @@ func testMaliciousConsumer( batchEnabled bool, vrfVersion vrfcommon.Version, ) { - config, _ := heavyweight.FullTestDBV2(t, "vrf_v2plus_integration_malicious", func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](2_000_000) c.EVM[0].GasEstimator.PriceMax = assets.GWei(1) c.EVM[0].GasEstimator.PriceDefault = assets.GWei(1) diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 094d7d060e..75026423f4 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -1141,7 +1141,7 @@ func TestVRFV2PlusIntegration_Migration(t *testing.T) { uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2plus_migration", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 3a691ec2e2..e50ed91491 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -967,7 +967,7 @@ func testEoa( key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, _ := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_eoa_request", func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1128,7 +1128,7 @@ func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { callBackGasLimit := int64(100_000) // base callback gas. key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_singleconsumer_wrapper", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1208,7 +1208,7 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { key1 := cltest.MustGenerateRandomKey(t) callBackGasLimit := int64(2_000_000) // base callback gas. gasLanePriceWei := assets.GWei(10) - config, db := heavyweight.FullTestDBV2(t, "vrfv2_wrapper_high_gas_revert", func(c *chainlink.Config, s *chainlink.Secrets) { + config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. Key: ptr(key1.EIP55Address), @@ -1585,7 +1585,7 @@ func TestIntegrationVRFV2(t *testing.T) { gasPrice := assets.GWei(1) key := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) - config, _ := heavyweight.FullTestDBV2(t, "vrf_v2_integration", func(c *chainlink.Config, s *chainlink.Secrets) { + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, gasPrice, toml.KeySpecific{ Key: &key.EIP55Address, GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, @@ -2003,7 +2003,7 @@ func TestFulfillmentCost(t *testing.T) { } func TestStartingCountsV1(t *testing.T) { - cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "vrf_test_starting_counts", nil) + cfg, db := heavyweight.FullTestDBNoFixturesV2(t, nil) lggr := logger.TestLogger(t) qCfg := pgtest.NewQConfig(false) diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index fe218589d2..ef105c75ff 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -73,7 +73,7 @@ func getOCR2Spec100() OffchainReporting2OracleSpec100 { } func TestMigrate_0100_BootstrapConfigs(t *testing.T) { - cfg, db := heavyweight.FullTestDBEmptyV2(t, migrationDir, nil) + cfg, db := heavyweight.FullTestDBEmptyV2(t, nil) lggr := logger.TestLogger(t) err := goose.UpTo(db.DB, migrationDir, 99) require.NoError(t, err) @@ -342,7 +342,7 @@ ON jobs.offchainreporting2_oracle_spec_id = ocr2.id` } func TestMigrate_101_GenericOCR2(t *testing.T) { - _, db := heavyweight.FullTestDBEmptyV2(t, migrationDir, nil) + _, db := heavyweight.FullTestDBEmptyV2(t, nil) err := goose.UpTo(db.DB, migrationDir, 100) require.NoError(t, err) @@ -392,7 +392,7 @@ func TestMigrate_101_GenericOCR2(t *testing.T) { func TestMigrate(t *testing.T) { lggr := logger.TestLogger(t) - _, db := heavyweight.FullTestDBEmptyV2(t, migrationDir, nil) + _, db := heavyweight.FullTestDBEmptyV2(t, nil) err := goose.UpTo(db.DB, migrationDir, 100) require.NoError(t, err) @@ -443,7 +443,7 @@ func TestSetMigrationENVVars(t *testing.T) { } func TestDatabaseBackFillWithMigration202(t *testing.T) { - _, db := heavyweight.FullTestDBEmptyV2(t, migrationDir, nil) + _, db := heavyweight.FullTestDBEmptyV2(t, nil) err := goose.UpTo(db.DB, migrationDir, 201) require.NoError(t, err) @@ -523,7 +523,7 @@ func BenchmarkBackfillingRecordsWithMigration202(b *testing.B) { maxLogsSize := 100_000 // Disable Goose logging for benchmarking goose.SetLogger(goose.NopLogger()) - _, db := heavyweight.FullTestDBEmptyV2(b, migrationDir, nil) + _, db := heavyweight.FullTestDBEmptyV2(b, nil) err := goose.UpTo(db.DB, migrationDir, previousMigration) require.NoError(b, err) From 5d4961b70ec804589ea66bb33e087f1da41a9e33 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 8 Nov 2023 12:10:56 -0600 Subject: [PATCH 110/327] core/store/migration/migrations: rm last sqlx.NewTx use (#11230) --- core/store/migrate/migrations/0036_external_job_id.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/store/migrate/migrations/0036_external_job_id.go b/core/store/migrate/migrations/0036_external_job_id.go index 82f26206d8..8637bd38f5 100644 --- a/core/store/migrate/migrations/0036_external_job_id.go +++ b/core/store/migrate/migrations/0036_external_job_id.go @@ -45,7 +45,7 @@ func Up36(ctx context.Context, tx *sql.Tx) error { // Update all jobs to have an external_job_id. // We do this to avoid using the uuid postgres extension. var jobIDs []int32 - txx := sqlx.NewTx(tx, "postgres") + txx := sqlx.Tx{Tx: tx} if err := txx.SelectContext(ctx, &jobIDs, "SELECT id FROM jobs"); err != nil { return err } From b8caeda1aee8b7127bb2d0a208630ce42beee46d Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Wed, 8 Nov 2023 16:13:59 -0500 Subject: [PATCH 111/327] (test): Amend Functions onTokenTransferTest to be able to fuzz with full LINK supply (#11234) --- .../gas-snapshots/functions.gas-snapshot | 10 ++--- .../tests/v1_X/FunctionsSubscriptions.t.sol | 42 ++++++++++++------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index d575c8ca19..e742be2754 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -130,11 +130,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, μ: 28446, ~: 28446) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 30958, ~: 30958) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14293, ~: 14293) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 35938, ~: 35938) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 59686, ~: 59686) +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_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/tests/v1_X/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol index 8f08a6c1e8..5a54bcc84c 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol @@ -309,11 +309,22 @@ contract FunctionsSubscriptions_OwnerWithdraw is FunctionsFulfillmentSetup { } /// @notice #onTokenTransfer -contract FunctionsSubscriptions_OnTokenTransfer is FunctionsSubscriptionSetup { +contract FunctionsSubscriptions_OnTokenTransfer is FunctionsClientSetup { + uint64 s_subscriptionId; + + function setUp() public virtual override { + FunctionsClientSetup.setUp(); + + // Create subscription, but do not fund it + s_subscriptionId = s_functionsRouter.createSubscription(); + s_functionsRouter.addConsumer(s_subscriptionId, address(s_functionsClient)); + } + function test_OnTokenTransfer_RevertIfPaused(uint96 fundingAmount) public { // Funding amount must be less than LINK total supply - vm.assume(fundingAmount < 1_000_000_000 * 1e18); - vm.assume(fundingAmount > 0); + uint256 totalSupplyJuels = 1_000_000_000 * 1e18; + vm.assume(fundingAmount <= totalSupplyJuels); + vm.assume(fundingAmount >= 0); s_functionsRouter.pause(); vm.expectRevert("Pausable: paused"); @@ -322,8 +333,9 @@ contract FunctionsSubscriptions_OnTokenTransfer is FunctionsSubscriptionSetup { function test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96 fundingAmount) public { // Funding amount must be less than LINK total supply - vm.assume(fundingAmount < 1_000_000_000 * 1e18); - vm.assume(fundingAmount > 0); + uint256 totalSupplyJuels = 1_000_000_000 * 1e18; + vm.assume(fundingAmount <= totalSupplyJuels); + vm.assume(fundingAmount >= 0); vm.expectRevert(FunctionsSubscriptions.OnlyCallableFromLink.selector); s_functionsRouter.onTokenTransfer(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); @@ -331,8 +343,9 @@ contract FunctionsSubscriptions_OnTokenTransfer is FunctionsSubscriptionSetup { function test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96 fundingAmount) public { // Funding amount must be less than LINK total supply - vm.assume(fundingAmount < 1_000_000_000 * 1e18); - vm.assume(fundingAmount > 0); + uint256 totalSupplyJuels = 1_000_000_000 * 1e18; + vm.assume(fundingAmount <= totalSupplyJuels); + vm.assume(fundingAmount >= 0); vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, new bytes(0)); @@ -340,8 +353,9 @@ contract FunctionsSubscriptions_OnTokenTransfer is FunctionsSubscriptionSetup { function test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96 fundingAmount) public { // Funding amount must be less than LINK total supply - vm.assume(fundingAmount < 1_000_000_000 * 1e18); - vm.assume(fundingAmount > 0); + uint256 totalSupplyJuels = 1_000_000_000 * 1e18; + vm.assume(fundingAmount <= totalSupplyJuels); + vm.assume(fundingAmount >= 0); vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); uint64 invalidSubscriptionId = 123456789; @@ -349,17 +363,15 @@ contract FunctionsSubscriptions_OnTokenTransfer is FunctionsSubscriptionSetup { } function test_OnTokenTransfer_Success(uint96 fundingAmount) public { - uint96 subscriptionBalanceBefore = s_functionsRouter.getSubscription(s_subscriptionId).balance; - // Funding amount must be less than LINK total supply - uint96 TOTAL_LINK = 1_000_000_000 * 1e18; + uint256 totalSupplyJuels = 1_000_000_000 * 1e18; // Some of the total supply is already in the subscription account - vm.assume(fundingAmount < TOTAL_LINK - subscriptionBalanceBefore); - vm.assume(fundingAmount > 0); + vm.assume(fundingAmount <= totalSupplyJuels); + vm.assume(fundingAmount >= 0); s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); uint96 subscriptionBalanceAfter = s_functionsRouter.getSubscription(s_subscriptionId).balance; - assertEq(subscriptionBalanceBefore + fundingAmount, subscriptionBalanceAfter); + assertEq(fundingAmount, subscriptionBalanceAfter); } } From 6481bed281200e17ca09508b839dc90223fe3ffb Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:42:50 +0100 Subject: [PATCH 112/327] Add GetAPIClient to ClNode E2E docker wrapper (#11240) --- integration-tests/docker/test_env/cl_node.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 4de3d27d75..6e74e54a4f 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -203,6 +203,10 @@ func (n *ClNode) GetContainerName() string { return strings.Replace(name, "/", "", -1) } +func (n *ClNode) GetAPIClient() *client.ChainlinkClient { + return n.API +} + func (n *ClNode) GetPeerUrl() (string, error) { p2pKeys, err := n.API.MustReadP2PKeys() if err != nil { From dd2c5ef1a71d821d97f199573b04df71dcab6172 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Thu, 9 Nov 2023 12:58:22 +0100 Subject: [PATCH 113/327] Move Sol files from top level to project dirs (#11227) * mv agg interfaces * rm unused ownable interface * mv AuthorizedReceiverInterface * mv libs to llo-feeds * fix interfaces/AggregatorV2V3Interface ref * rm dup interface --- .../gas-snapshots/llo-feeds.gas-snapshot | 20 +++++++++++++++++++ .../scripts/native_solc_compile_all_feeds | 2 +- contracts/src/v0.8/ValidatorProxy.sol | 2 +- .../automation/v1_2/KeeperRegistry1_2.sol | 2 +- .../automation/v1_3/KeeperRegistryBase1_3.sol | 2 +- .../automation/v2_0/KeeperRegistryBase2_0.sol | 2 +- .../automation/v2_1/KeeperRegistryBase2_1.sol | 2 +- .../shared/interfaces/OwnableInterface.sol | 10 ---------- .../functions/dev/v1_X/FunctionsBilling.sol | 2 +- .../functions/v1_0_0/FunctionsBilling.sol | 2 +- .../v0.8/interfaces/FeedRegistryInterface.sol | 2 +- .../arbitrum/ArbitrumSequencerUptimeFeed.sol | 6 +++--- .../l2ep/dev/arbitrum/ArbitrumValidator.sol | 2 +- .../optimism/OptimismSequencerUptimeFeed.sol | 6 +++--- .../l2ep/dev/optimism/OptimismValidator.sol | 2 +- contracts/src/v0.8/llo-feeds/FeeManager.sol | 2 +- .../src/v0.8/llo-feeds/RewardManager.sol | 2 +- contracts/src/v0.8/llo-feeds/Verifier.sol | 2 +- .../src/v0.8/llo-feeds/VerifierProxy.sol | 2 +- .../v0.8/llo-feeds/interfaces/IFeeManager.sol | 2 +- .../llo-feeds/interfaces/IRewardManager.sol | 2 +- .../v0.8/llo-feeds/interfaces/IVerifier.sol | 2 +- .../interfaces/IVerifierFeeManager.sol | 2 +- .../llo-feeds/interfaces/IVerifierProxy.sol | 2 +- .../{ => llo-feeds}/libraries/ByteUtil.sol | 0 .../v0.8/{ => llo-feeds}/libraries/Common.sol | 0 .../test/ByteUtilTest.t.sol | 2 +- .../test/fee-manager/BaseFeeManager.t.sol | 2 +- .../FeeManager.getFeeAndReward.t.sol | 2 +- .../fee-manager/FeeManager.processFee.t.sol | 2 +- .../llo-feeds/test/gas/Gas_VerifierTest.t.sol | 2 +- .../llo-feeds/test/mocks/ErroredVerifier.sol | 2 +- .../reward-manager/BaseRewardManager.t.sol | 2 +- .../reward-manager/RewardManager.claim.t.sol | 2 +- .../RewardManager.setRecipients.t.sol | 2 +- ...RewardManager.updateRewardRecipients.t.sol | 2 +- .../test/verifier/BaseVerifierTest.t.sol | 2 +- .../VerifierProxySetVerifierTest.t.sol | 2 +- .../VerifierSetConfigFromSourceTest.t.sol | 2 +- .../test/verifier/VerifierSetConfigTest.t.sol | 2 +- .../test/verifier/VerifierVerifyTest.t.sol | 2 +- .../v0.8/mocks/MockAggregatorValidator.sol | 2 +- .../dev/AuthorizedReceiver.sol | 2 +- .../v0.8/operatorforwarder/dev/Operator.sol | 2 +- .../AuthorizedReceiverInterface.sol | 0 .../interfaces/AggregatorInterface.sol | 0 .../interfaces/AggregatorV2V3Interface.sol | 0 .../interfaces/AggregatorV3Interface.sol | 0 .../AggregatorValidatorInterface.sol | 0 .../src/v0.8/shared/token/ERC677/ERC677.sol | 2 +- .../shared/token/ERC677/IERC677Receiver.sol | 6 ------ contracts/src/v0.8/tests/FeedConsumer.sol | 2 +- .../src/v0.8/tests/MockETHLINKAggregator.sol | 2 +- contracts/src/v0.8/tests/MockV3Aggregator.sol | 2 +- .../transmission/dev/ERC-4337/Paymaster.sol | 2 +- contracts/src/v0.8/vrf/VRFCoordinatorV2.sol | 2 +- contracts/src/v0.8/vrf/VRFV2Wrapper.sol | 2 +- .../src/v0.8/vrf/dev/SubscriptionAPI.sol | 2 +- .../src/v0.8/vrf/dev/VRFV2PlusWrapper.sol | 2 +- .../VRFCoordinatorV2TestHelper.sol | 2 +- .../test/v0.8/dev/ArbitrumValidator.test.ts | 2 +- .../test/v0.8/dev/OptimismValidator.test.ts | 2 +- 62 files changed, 76 insertions(+), 72 deletions(-) delete mode 100644 contracts/src/v0.8/dev/shared/interfaces/OwnableInterface.sol rename contracts/src/v0.8/{ => llo-feeds}/libraries/ByteUtil.sol (100%) rename contracts/src/v0.8/{ => llo-feeds}/libraries/Common.sol (100%) rename contracts/src/v0.8/{libraries => llo-feeds}/test/ByteUtilTest.t.sol (99%) rename contracts/src/v0.8/{ => operatorforwarder/dev}/interfaces/AuthorizedReceiverInterface.sol (100%) rename contracts/src/v0.8/{ => shared}/interfaces/AggregatorInterface.sol (100%) rename contracts/src/v0.8/{ => shared}/interfaces/AggregatorV2V3Interface.sol (100%) rename contracts/src/v0.8/{ => shared}/interfaces/AggregatorV3Interface.sol (100%) rename contracts/src/v0.8/{ => shared}/interfaces/AggregatorValidatorInterface.sol (100%) delete mode 100644 contracts/src/v0.8/shared/token/ERC677/IERC677Receiver.sol diff --git a/contracts/gas-snapshots/llo-feeds.gas-snapshot b/contracts/gas-snapshots/llo-feeds.gas-snapshot index a9877fbe33..ad9339a341 100644 --- a/contracts/gas-snapshots/llo-feeds.gas-snapshot +++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot @@ -1,3 +1,23 @@ +ByteUtilTest:test_readAddress() (gas: 542) +ByteUtilTest:test_readAddressMultiWord() (gas: 540) +ByteUtilTest:test_readAddressWithEmptyArray() (gas: 3274) +ByteUtilTest:test_readAddressWithNotEnoughBytes() (gas: 3314) +ByteUtilTest:test_readUint192Max() (gas: 485) +ByteUtilTest:test_readUint192Min() (gas: 508) +ByteUtilTest:test_readUint192MultiWord() (gas: 486) +ByteUtilTest:test_readUint192WithEmptyArray() (gas: 3274) +ByteUtilTest:test_readUint192WithNotEnoughBytes() (gas: 3314) +ByteUtilTest:test_readUint256Max() (gas: 502) +ByteUtilTest:test_readUint256Min() (gas: 546) +ByteUtilTest:test_readUint256MultiWord() (gas: 500) +ByteUtilTest:test_readUint256WithEmptyArray() (gas: 3296) +ByteUtilTest:test_readUint256WithNotEnoughBytes() (gas: 3293) +ByteUtilTest:test_readUint32Max() (gas: 507) +ByteUtilTest:test_readUint32Min() (gas: 487) +ByteUtilTest:test_readUint32MultiWord() (gas: 552) +ByteUtilTest:test_readUint32WithEmptyArray() (gas: 3253) +ByteUtilTest:test_readUint32WithNotEnoughBytes() (gas: 3272) +ByteUtilTest:test_readZeroAddress() (gas: 519) FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52282) FeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52235) FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78440) diff --git a/contracts/scripts/native_solc_compile_all_feeds b/contracts/scripts/native_solc_compile_all_feeds index eac5a6b70c..2c5808d466 100755 --- a/contracts/scripts/native_solc_compile_all_feeds +++ b/contracts/scripts/native_solc_compile_all_feeds @@ -30,6 +30,6 @@ compileContract () { } # Aggregators -compileContract interfaces/AggregatorV2V3Interface.sol +compileContract shared/interfaces/AggregatorV2V3Interface.sol compileContract Chainlink.sol compileContract ChainlinkClient.sol diff --git a/contracts/src/v0.8/ValidatorProxy.sol b/contracts/src/v0.8/ValidatorProxy.sol index 35909ad87d..627af73b39 100644 --- a/contracts/src/v0.8/ValidatorProxy.sol +++ b/contracts/src/v0.8/ValidatorProxy.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {ConfirmedOwner} from "./shared/access/ConfirmedOwner.sol"; -import {AggregatorValidatorInterface} from "./interfaces/AggregatorValidatorInterface.sol"; +import {AggregatorValidatorInterface} from "./shared/interfaces/AggregatorValidatorInterface.sol"; import {TypeAndVersionInterface} from "./interfaces/TypeAndVersionInterface.sol"; // solhint-disable custom-errors diff --git a/contracts/src/v0.8/automation/v1_2/KeeperRegistry1_2.sol b/contracts/src/v0.8/automation/v1_2/KeeperRegistry1_2.sol index 262b8357f7..2fa1ee6188 100644 --- a/contracts/src/v0.8/automation/v1_2/KeeperRegistry1_2.sol +++ b/contracts/src/v0.8/automation/v1_2/KeeperRegistry1_2.sol @@ -7,7 +7,7 @@ import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../KeeperBase.sol"; import "../../interfaces/TypeAndVersionInterface.sol"; -import "../../interfaces/AggregatorV3Interface.sol"; +import "../../shared/interfaces/AggregatorV3Interface.sol"; import "../interfaces/KeeperCompatibleInterface.sol"; import "../interfaces/v1_2/KeeperRegistryInterface1_2.sol"; import "../interfaces/MigratableKeeperRegistryInterface.sol"; diff --git a/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol b/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol index 6328b65167..c21f3a7391 100644 --- a/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol +++ b/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol @@ -8,7 +8,7 @@ import "../../vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_ import "../ExecutionPrevention.sol"; import {Config, Upkeep} from "../interfaces/v1_3/AutomationRegistryInterface1_3.sol"; import "../../shared/access/ConfirmedOwner.sol"; -import "../../interfaces/AggregatorV3Interface.sol"; +import "../../shared/interfaces/AggregatorV3Interface.sol"; import "../../shared/interfaces/LinkTokenInterface.sol"; import "../interfaces/KeeperCompatibleInterface.sol"; import "../interfaces/UpkeepTranscoderInterface.sol"; diff --git a/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol b/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol index 14e9b20447..9b78e5806f 100644 --- a/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol +++ b/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol @@ -7,7 +7,7 @@ import "../../vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_ import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; import "../ExecutionPrevention.sol"; import "../../shared/access/ConfirmedOwner.sol"; -import "../../interfaces/AggregatorV3Interface.sol"; +import "../../shared/interfaces/AggregatorV3Interface.sol"; import "../../shared/interfaces/LinkTokenInterface.sol"; import "../interfaces/KeeperCompatibleInterface.sol"; import "../interfaces/UpkeepTranscoderInterface.sol"; diff --git a/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol b/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol index f5d89de546..f81fcef636 100644 --- a/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol +++ b/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol @@ -11,7 +11,7 @@ import {StreamsLookupCompatibleInterface} from "../interfaces/StreamsLookupCompa import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {KeeperCompatibleInterface} from "../interfaces/KeeperCompatibleInterface.sol"; import {UpkeepFormat} from "../interfaces/UpkeepTranscoderInterface.sol"; diff --git a/contracts/src/v0.8/dev/shared/interfaces/OwnableInterface.sol b/contracts/src/v0.8/dev/shared/interfaces/OwnableInterface.sol deleted file mode 100644 index a24cbee504..0000000000 --- a/contracts/src/v0.8/dev/shared/interfaces/OwnableInterface.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface OwnableInterface { - function owner() external returns (address); - - function transferOwnership(address recipient) external; - - function acceptOwnership() external; -} 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 ed67d48543..adc6218733 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; -import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; diff --git a/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol index 5168bdc01e..8de53dd9c0 100644 --- a/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; -import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; diff --git a/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol b/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol index 1d2367d82a..f3272174ae 100644 --- a/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol +++ b/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; pragma abicoder v2; -import {AggregatorV2V3Interface} from "./AggregatorV2V3Interface.sol"; +import {AggregatorV2V3Interface} from "../shared/interfaces/AggregatorV2V3Interface.sol"; interface FeedRegistryInterface { struct Phase { diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol index 6d8d31a808..5250fbda27 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.4; import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import {AggregatorInterface} from "../../../interfaces/AggregatorInterface.sol"; -import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; -import {AggregatorV2V3Interface} from "../../../interfaces/AggregatorV2V3Interface.sol"; +import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; import {FlagsInterface} from "../interfaces/FlagsInterface.sol"; import {ArbitrumSequencerUptimeFeedInterface} from "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol index 3b5fd277e5..2043ffa628 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {AggregatorValidatorInterface} from "../../../interfaces/AggregatorValidatorInterface.sol"; +import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol index b522a600ba..fcf6093e3c 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {AggregatorInterface} from "../../../interfaces/AggregatorInterface.sol"; -import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; -import {AggregatorV2V3Interface} from "../../../interfaces/AggregatorV2V3Interface.sol"; +import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; import {OptimismSequencerUptimeFeedInterface} from "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol index a955b7e92c..e41c61a453 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {AggregatorValidatorInterface} from "../../../interfaces/AggregatorValidatorInterface.sol"; +import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; import {OptimismSequencerUptimeFeedInterface} from "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; diff --git a/contracts/src/v0.8/llo-feeds/FeeManager.sol b/contracts/src/v0.8/llo-feeds/FeeManager.sol index 397605d9b2..c9981045a4 100644 --- a/contracts/src/v0.8/llo-feeds/FeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/FeeManager.sol @@ -5,7 +5,7 @@ import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {IFeeManager} from "./interfaces/IFeeManager.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; -import {Common} from "../libraries/Common.sol"; +import {Common} from "./libraries/Common.sol"; import {IRewardManager} from "./interfaces/IRewardManager.sol"; import {IWERC20} from "../shared/interfaces/IWERC20.sol"; import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol"; diff --git a/contracts/src/v0.8/llo-feeds/RewardManager.sol b/contracts/src/v0.8/llo-feeds/RewardManager.sol index 3777b432fc..596755142e 100644 --- a/contracts/src/v0.8/llo-feeds/RewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/RewardManager.sol @@ -5,7 +5,7 @@ import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {IRewardManager} from "./interfaces/IRewardManager.sol"; import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; -import {Common} from "../libraries/Common.sol"; +import {Common} from "./libraries/Common.sol"; import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /** diff --git a/contracts/src/v0.8/llo-feeds/Verifier.sol b/contracts/src/v0.8/llo-feeds/Verifier.sol index f7ce156a60..3e668c09ff 100644 --- a/contracts/src/v0.8/llo-feeds/Verifier.sol +++ b/contracts/src/v0.8/llo-feeds/Verifier.sol @@ -6,7 +6,7 @@ import {IVerifier} from "./interfaces/IVerifier.sol"; import {IVerifierProxy} from "./interfaces/IVerifierProxy.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; -import {Common} from "../libraries/Common.sol"; +import {Common} from "./libraries/Common.sol"; // OCR2 standard uint256 constant MAX_NUM_ORACLES = 31; diff --git a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol index 6abb2b78e9..a35c54573c 100644 --- a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol +++ b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol @@ -8,7 +8,7 @@ import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol import {AccessControllerInterface} from "../shared/interfaces/AccessControllerInterface.sol"; import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol"; -import {Common} from "../libraries/Common.sol"; +import {Common} from "./libraries/Common.sol"; /** * The verifier proxy contract is the gateway for all report verification requests diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol b/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol index 08373a6a5b..e006f0254e 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; -import {Common} from "../../libraries/Common.sol"; +import {Common} from "../libraries/Common.sol"; import {IVerifierFeeManager} from "./IVerifierFeeManager.sol"; interface IFeeManager is IERC165, IVerifierFeeManager { diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol b/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol index a76366a3eb..7a4d421671 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; -import {Common} from "../../libraries/Common.sol"; +import {Common} from "../libraries/Common.sol"; interface IRewardManager is IERC165 { /** diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol b/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol index 9b9ba2e657..9e1e6d314c 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; -import {Common} from "../../libraries/Common.sol"; +import {Common} from "../libraries/Common.sol"; interface IVerifier is IERC165 { /** diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol index e5a73e612c..323b8a2cf0 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; -import {Common} from "../../libraries/Common.sol"; +import {Common} from "../libraries/Common.sol"; interface IVerifierFeeManager is IERC165 { /** diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol index c2665261e9..d86bb46dd9 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {Common} from "../../libraries/Common.sol"; +import {Common} from "../libraries/Common.sol"; import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol"; import {IVerifierFeeManager} from "./IVerifierFeeManager.sol"; diff --git a/contracts/src/v0.8/libraries/ByteUtil.sol b/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol similarity index 100% rename from contracts/src/v0.8/libraries/ByteUtil.sol rename to contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol diff --git a/contracts/src/v0.8/libraries/Common.sol b/contracts/src/v0.8/llo-feeds/libraries/Common.sol similarity index 100% rename from contracts/src/v0.8/libraries/Common.sol rename to contracts/src/v0.8/llo-feeds/libraries/Common.sol diff --git a/contracts/src/v0.8/libraries/test/ByteUtilTest.t.sol b/contracts/src/v0.8/llo-feeds/test/ByteUtilTest.t.sol similarity index 99% rename from contracts/src/v0.8/libraries/test/ByteUtilTest.t.sol rename to contracts/src/v0.8/llo-feeds/test/ByteUtilTest.t.sol index 0629d0235e..b4e87364ac 100644 --- a/contracts/src/v0.8/libraries/test/ByteUtilTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/ByteUtilTest.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {Test} from "forge-std/Test.sol"; -import {ByteUtil} from "../ByteUtil.sol"; +import {ByteUtil} from "../libraries/ByteUtil.sol"; contract ByteUtilTest is Test { using ByteUtil for bytes; diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol index ec2611f9e4..db0b3d8b3d 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.16; import {Test} from "forge-std/Test.sol"; import {FeeManager} from "../../FeeManager.sol"; import {RewardManager} from "../../RewardManager.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {WERC20Mock} from "../../../shared/mocks/WERC20Mock.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol index 801a1e3992..6a24806353 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.16; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; import "./BaseFeeManager.t.sol"; /** diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol index 9c2bd711ed..e0093b88a4 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.16; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; import "./BaseFeeManager.t.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol index 3198576e8a..6938437b01 100644 --- a/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.16; import {BaseTest, BaseTestWithConfiguredVerifierAndFeeManager} from "../verifier/BaseVerifierTest.t.sol"; import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; contract Verifier_setConfig is BaseTest { diff --git a/contracts/src/v0.8/llo-feeds/test/mocks/ErroredVerifier.sol b/contracts/src/v0.8/llo-feeds/test/mocks/ErroredVerifier.sol index a0a404d88d..770b7b809d 100644 --- a/contracts/src/v0.8/llo-feeds/test/mocks/ErroredVerifier.sol +++ b/contracts/src/v0.8/llo-feeds/test/mocks/ErroredVerifier.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {IVerifier} from "../../interfaces/IVerifier.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; contract ErroredVerifier is IVerifier { function supportsInterface(bytes4 interfaceId) public pure override returns (bool) { diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol index 3e50adef95..a9953d73c7 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.16; import {Test} from "forge-std/Test.sol"; import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {RewardManager} from "../../RewardManager.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; /** diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol index 9a3749d1dd..a6c98c0303 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; /** * @title BaseRewardManagerTest diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol index 0e45ba00da..a8cf6260f5 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; /** * @title BaseRewardManagerTest diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol index 4b3063ac01..b1836e0fb9 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; /** * @title BaseRewardManagerTest diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol index 91e0f9da90..34e2090115 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol @@ -10,7 +10,7 @@ import {Verifier} from "../../Verifier.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; import {FeeManager} from "../../FeeManager.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {WERC20Mock} from "../../../shared/mocks/WERC20Mock.sol"; import {FeeManager} from "../../FeeManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol index a6b23d7e8b..17fc49979e 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol @@ -5,7 +5,7 @@ import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t. import {IVerifier} from "../../interfaces/IVerifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; contract VerifierProxyInitializeVerifierTest is BaseTestWithConfiguredVerifierAndFeeManager { function test_revertsIfNotCorrectVerifier() public { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol index 6c5eac9b6d..ba3acce0ee 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {BaseTest, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; contract VerifierSetConfigFromSourceTest is BaseTest { function setUp() public virtual override { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol index f0b045e7f3..374a976786 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.16; import {BaseTest, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; import {Verifier} from "../../Verifier.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; contract VerifierSetConfigTest is BaseTest { function setUp() public virtual override { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierVerifyTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierVerifyTest.t.sol index b4fcac75d3..34e02bcfb9 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierVerifyTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierVerifyTest.t.sol @@ -5,7 +5,7 @@ import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t. import {Verifier} from "../../Verifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; -import {Common} from "../../../libraries/Common.sol"; +import {Common} from "../../libraries/Common.sol"; contract VerifierVerifyTest is BaseTestWithConfiguredVerifierAndFeeManager { bytes32[3] internal s_reportContext; diff --git a/contracts/src/v0.8/mocks/MockAggregatorValidator.sol b/contracts/src/v0.8/mocks/MockAggregatorValidator.sol index a43236de9f..bdc935cd23 100644 --- a/contracts/src/v0.8/mocks/MockAggregatorValidator.sol +++ b/contracts/src/v0.8/mocks/MockAggregatorValidator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/AggregatorValidatorInterface.sol"; +import "../shared/interfaces/AggregatorValidatorInterface.sol"; contract MockAggregatorValidator is AggregatorValidatorInterface { uint8 immutable id; diff --git a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol index 04d2635d58..bc5f1c0e7e 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.19; -import {AuthorizedReceiverInterface} from "../../interfaces/AuthorizedReceiverInterface.sol"; +import {AuthorizedReceiverInterface} from "./interfaces/AuthorizedReceiverInterface.sol"; // solhint-disable custom-errors abstract contract AuthorizedReceiver is AuthorizedReceiverInterface { diff --git a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol index b83996a9ed..c8451bf03c 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol @@ -5,7 +5,7 @@ import {AuthorizedReceiver} from "./AuthorizedReceiver.sol"; import {LinkTokenReceiver} from "./LinkTokenReceiver.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; -import {AuthorizedReceiverInterface} from "../../interfaces/AuthorizedReceiverInterface.sol"; +import {AuthorizedReceiverInterface} from "./interfaces/AuthorizedReceiverInterface.sol"; import {OperatorInterface} from "../../interfaces/OperatorInterface.sol"; import {IOwnable} from "../../shared/interfaces/IOwnable.sol"; import {WithdrawalInterface} from "./interfaces/WithdrawalInterface.sol"; diff --git a/contracts/src/v0.8/interfaces/AuthorizedReceiverInterface.sol b/contracts/src/v0.8/operatorforwarder/dev/interfaces/AuthorizedReceiverInterface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/AuthorizedReceiverInterface.sol rename to contracts/src/v0.8/operatorforwarder/dev/interfaces/AuthorizedReceiverInterface.sol diff --git a/contracts/src/v0.8/interfaces/AggregatorInterface.sol b/contracts/src/v0.8/shared/interfaces/AggregatorInterface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/AggregatorInterface.sol rename to contracts/src/v0.8/shared/interfaces/AggregatorInterface.sol diff --git a/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol b/contracts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol rename to contracts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol diff --git a/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol b/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/AggregatorV3Interface.sol rename to contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol diff --git a/contracts/src/v0.8/interfaces/AggregatorValidatorInterface.sol b/contracts/src/v0.8/shared/interfaces/AggregatorValidatorInterface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/AggregatorValidatorInterface.sol rename to contracts/src/v0.8/shared/interfaces/AggregatorValidatorInterface.sol diff --git a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol index 9a68bac3a1..aa75a1170c 100644 --- a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol +++ b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {IERC677} from "./IERC677.sol"; -import {IERC677Receiver} from "./IERC677Receiver.sol"; +import {IERC677Receiver} from "../../interfaces/IERC677Receiver.sol"; import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; import {ERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol"; diff --git a/contracts/src/v0.8/shared/token/ERC677/IERC677Receiver.sol b/contracts/src/v0.8/shared/token/ERC677/IERC677Receiver.sol deleted file mode 100644 index 2e44d860a8..0000000000 --- a/contracts/src/v0.8/shared/token/ERC677/IERC677Receiver.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IERC677Receiver { - function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external; -} diff --git a/contracts/src/v0.8/tests/FeedConsumer.sol b/contracts/src/v0.8/tests/FeedConsumer.sol index 3c9462b0ac..c9fc62357a 100644 --- a/contracts/src/v0.8/tests/FeedConsumer.sol +++ b/contracts/src/v0.8/tests/FeedConsumer.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {AggregatorV2V3Interface} from "../interfaces/AggregatorV2V3Interface.sol"; +import {AggregatorV2V3Interface} from "../shared/interfaces/AggregatorV2V3Interface.sol"; contract FeedConsumer { AggregatorV2V3Interface public immutable AGGREGATOR; diff --git a/contracts/src/v0.8/tests/MockETHLINKAggregator.sol b/contracts/src/v0.8/tests/MockETHLINKAggregator.sol index 98dd775a11..d685aac731 100644 --- a/contracts/src/v0.8/tests/MockETHLINKAggregator.sol +++ b/contracts/src/v0.8/tests/MockETHLINKAggregator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/AggregatorV3Interface.sol"; +import "../shared/interfaces/AggregatorV3Interface.sol"; contract MockETHLINKAggregator is AggregatorV3Interface { int256 public answer; diff --git a/contracts/src/v0.8/tests/MockV3Aggregator.sol b/contracts/src/v0.8/tests/MockV3Aggregator.sol index d261b2c4b1..9822d23e85 100644 --- a/contracts/src/v0.8/tests/MockV3Aggregator.sol +++ b/contracts/src/v0.8/tests/MockV3Aggregator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/AggregatorV2V3Interface.sol"; +import "../shared/interfaces/AggregatorV2V3Interface.sol"; /** * @title MockV3Aggregator diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol index cd84bb6a0e..970ddf6b7e 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.15; import {IPaymaster} from "../../../vendor/entrypoint/interfaces/IPaymaster.sol"; import {SCALibrary} from "./SCALibrary.sol"; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {UserOperation} from "../../../vendor/entrypoint/interfaces/UserOperation.sol"; import {_packValidationData} from "../../../vendor/entrypoint/core/Helpers.sol"; diff --git a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol index 5150d263a8..5acd3e7435 100644 --- a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.4; import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; import {BlockhashStoreInterface} from "./interfaces/BlockhashStoreInterface.sol"; -import {AggregatorV3Interface} from "../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../shared/interfaces/AggregatorV3Interface.sol"; import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {IERC677Receiver} from "../shared/interfaces/IERC677Receiver.sol"; diff --git a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol index 805c8d76cb..abe479cb20 100644 --- a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol +++ b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol @@ -6,7 +6,7 @@ import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {VRFConsumerBaseV2} from "./VRFConsumerBaseV2.sol"; import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; -import {AggregatorV3Interface} from "../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../shared/interfaces/AggregatorV3Interface.sol"; import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; import {VRFV2WrapperInterface} from "./interfaces/VRFV2WrapperInterface.sol"; import {VRFV2WrapperConsumerBase} from "./VRFV2WrapperConsumerBase.sol"; diff --git a/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol index e4708bb1fc..d7cc5b86c5 100644 --- a/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol +++ b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; import {IVRFSubscriptionV2Plus} from "./interfaces/IVRFSubscriptionV2Plus.sol"; diff --git a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol index 9c3b983e30..a724b70a3d 100644 --- a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol @@ -6,7 +6,7 @@ import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface. import {IVRFV2PlusMigrate} from "./interfaces/IVRFV2PlusMigrate.sol"; import {VRFConsumerBaseV2Plus} from "./VRFConsumerBaseV2Plus.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; -import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; import {VRFV2PlusClient} from "./libraries/VRFV2PlusClient.sol"; import {IVRFV2PlusWrapper} from "./interfaces/IVRFV2PlusWrapper.sol"; import {VRFV2PlusWrapperConsumerBase} from "./VRFV2PlusWrapperConsumerBase.sol"; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol index f938532968..c5d1d90c12 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; // Ideally this contract should inherit from VRFCoordinatorV2 and delegate calls to VRFCoordinatorV2 // However, due to exceeding contract size limit, the logic from VRFCoordinatorV2 is ported over to this contract diff --git a/contracts/test/v0.8/dev/ArbitrumValidator.test.ts b/contracts/test/v0.8/dev/ArbitrumValidator.test.ts index 2f95a6f6fb..232eea9583 100644 --- a/contracts/test/v0.8/dev/ArbitrumValidator.test.ts +++ b/contracts/test/v0.8/dev/ArbitrumValidator.test.ts @@ -12,7 +12,7 @@ import { abi as arbitrumSequencerStatusRecorderAbi } from '../../../artifacts/sr // @ts-ignore import { abi as arbitrumInboxAbi } from '../../../artifacts/src/v0.8/vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol/IInbox.json' // @ts-ignore -import { abi as aggregatorAbi } from '../../../artifacts/src/v0.8/interfaces/AggregatorV2V3Interface.sol/AggregatorV2V3Interface.json' +import { abi as aggregatorAbi } from '../../../artifacts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol/AggregatorV2V3Interface.json' const truncateBigNumToAddress = (num: BigNumberish) => { // Pad, then slice off '0x' prefix diff --git a/contracts/test/v0.8/dev/OptimismValidator.test.ts b/contracts/test/v0.8/dev/OptimismValidator.test.ts index 120b1057d1..ee69211f56 100644 --- a/contracts/test/v0.8/dev/OptimismValidator.test.ts +++ b/contracts/test/v0.8/dev/OptimismValidator.test.ts @@ -8,7 +8,7 @@ import { abi as optimismSequencerStatusRecorderAbi } from '../../../artifacts/sr // @ts-ignore import { abi as optimismL1CrossDomainMessengerAbi } from '@eth-optimism/contracts/artifacts/contracts/L1/messaging/L1CrossDomainMessenger.sol' // @ts-ignore -import { abi as aggregatorAbi } from '../../../artifacts/src/v0.8/interfaces/AggregatorV2V3Interface.sol/AggregatorV2V3Interface.json' +import { abi as aggregatorAbi } from '../../../artifacts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol/AggregatorV2V3Interface.json' describe('OptimismValidator', () => { const GAS_LIMIT = BigNumber.from(1_900_000) From cc05bfd1cf693f57dd5d7075fbc571523212b596 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Thu, 9 Nov 2023 14:49:26 +0200 Subject: [PATCH 114/327] Remove core label dependency from common (#11241) --- common/txmgr/broadcaster.go | 2 +- common/txmgr/confirmer.go | 2 +- common/txmgr/resender.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 80c7adbfc1..d68b509101 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -14,12 +14,12 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/chains/label" "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index 1d92149094..1d7446d9d2 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -14,13 +14,13 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/chains/label" "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index d788b82773..75781c0840 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -6,11 +6,11 @@ import ( "fmt" "time" + "github.com/smartcontractkit/chainlink-relay/pkg/chains/label" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) From b9bd82ade13007862b3820cdbc8f4a82ab8c1f1c Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 9 Nov 2023 13:05:31 +0000 Subject: [PATCH 115/327] [chore] Add run id to flakey test logs (#11243) --- .github/workflows/ci-core.yml | 2 ++ tools/flakeytests/cmd/runner/main.go | 3 ++- tools/flakeytests/reporter.go | 1 + tools/flakeytests/utils.go | 10 ++++++---- tools/flakeytests/utils_test.go | 10 +++++----- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 4053585590..d0bae66480 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -166,6 +166,7 @@ jobs: GITHUB_EVENT_PATH: ${{ github.event_path }} GITHUB_EVENT_NAME: ${{ github.event_name }} GITHUB_REPO: ${{ github.repository }} + GITHUB_RUN_ID: ${{ github.run_id }} run: | ./runner \ -grafana_auth=$GRAFANA_CLOUD_BASIC_AUTH \ @@ -173,6 +174,7 @@ jobs: -gh_sha=$GITHUB_SHA \ -gh_event_path=$GITHUB_EVENT_PATH \ -gh_event_name=$GITHUB_EVENT_NAME \ + -gh_run_id=$GITHUB_RUN_ID \ -gh_repo=$GITHUB_REPO \ -command=./tools/bin/go_core_tests \ `ls -R ./artifacts/go_core_tests*/output.txt` diff --git a/tools/flakeytests/cmd/runner/main.go b/tools/flakeytests/cmd/runner/main.go index 601832a837..f38179f502 100644 --- a/tools/flakeytests/cmd/runner/main.go +++ b/tools/flakeytests/cmd/runner/main.go @@ -20,6 +20,7 @@ func main() { ghEventPath := flag.String("gh_event_path", "", "path to associated gh event") ghEventName := flag.String("gh_event_name", "", "type of associated gh event") ghRepo := flag.String("gh_repo", "", "name of gh repository") + ghRunID := flag.String("gh_run_id", "", "run id of the gh workflow") flag.Parse() if *grafanaHost == "" { @@ -47,7 +48,7 @@ func main() { readers = append(readers, r) } - ctx := flakeytests.GetGithubMetadata(*ghRepo, *ghEventName, *ghSHA, *ghEventPath) + ctx := flakeytests.GetGithubMetadata(*ghRepo, *ghEventName, *ghSHA, *ghEventPath, *ghRunID) rep := flakeytests.NewLokiReporter(*grafanaHost, *grafanaAuth, *command, ctx) r := flakeytests.NewRunner(readers, rep, numReruns) err := r.Run() diff --git a/tools/flakeytests/reporter.go b/tools/flakeytests/reporter.go index db3890b5c7..6696ec29a4 100644 --- a/tools/flakeytests/reporter.go +++ b/tools/flakeytests/reporter.go @@ -37,6 +37,7 @@ type Context struct { PullRequestURL string `json:"pull_request_url,omitempty"` Repository string `json:"repository"` Type string `json:"event_type"` + RunURL string `json:"run_url,omitempty"` } type LokiReporter struct { diff --git a/tools/flakeytests/utils.go b/tools/flakeytests/utils.go index 7ead45c858..698a9b49c9 100644 --- a/tools/flakeytests/utils.go +++ b/tools/flakeytests/utils.go @@ -2,6 +2,7 @@ package flakeytests import ( "encoding/json" + "fmt" "io" "log" "os" @@ -29,7 +30,7 @@ func DigString(mp map[string]interface{}, path []string) (string, error) { return vs, nil } -func getGithubMetadata(repo string, eventName string, sha string, e io.Reader) Context { +func getGithubMetadata(repo string, eventName string, sha string, e io.Reader, runID string) Context { d, err := io.ReadAll(e) if err != nil { log.Fatal("Error reading gh event into string") @@ -41,7 +42,8 @@ func getGithubMetadata(repo string, eventName string, sha string, e io.Reader) C log.Fatalf("Error unmarshaling gh event at path") } - basicCtx := &Context{Repository: repo, CommitSHA: sha, Type: eventName} + runURL := fmt.Sprintf("%s/actions/%s", repo, runID) + basicCtx := &Context{Repository: repo, CommitSHA: sha, Type: eventName, RunURL: runURL} switch eventName { case "pull_request": prURL := "" @@ -68,10 +70,10 @@ func getGithubMetadata(repo string, eventName string, sha string, e io.Reader) C } } -func GetGithubMetadata(repo string, eventName string, sha string, path string) Context { +func GetGithubMetadata(repo string, eventName string, sha string, path string, runID string) Context { event, err := os.Open(path) if err != nil { log.Fatalf("Error reading gh event at path: %s", path) } - return getGithubMetadata(repo, eventName, sha, event) + return getGithubMetadata(repo, eventName, sha, event, runID) } diff --git a/tools/flakeytests/utils_test.go b/tools/flakeytests/utils_test.go index 17d597c3c0..761d9cd255 100644 --- a/tools/flakeytests/utils_test.go +++ b/tools/flakeytests/utils_test.go @@ -36,13 +36,13 @@ var prEventTemplate = ` ` func TestGetGithubMetadata(t *testing.T) { - repo, eventName, sha, event := "chainlink", "merge_group", "a-sha", `{}` - ctx := getGithubMetadata(repo, eventName, sha, strings.NewReader(event)) - assert.Equal(t, Context{Repository: repo, CommitSHA: sha, Type: eventName}, ctx) + repo, eventName, sha, event, runID := "chainlink", "merge_group", "a-sha", `{}`, "1234" + 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) 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)) - assert.Equal(t, Context{Repository: repo, CommitSHA: anotherSha, Type: eventName, PullRequestURL: url}, ctx) + 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) } From bc4ff537590279a124b96ef28002acfc5579179f Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Thu, 9 Nov 2023 15:31:27 +0100 Subject: [PATCH 116/327] bump solhint & prettier deps (#11228) * bump solhint deps * bump cl solhint chainlink-solidity/explicit-returns * bump solhint * bump prettier-plugin-solidity --- contracts/.solhint.json | 3 +- contracts/.solhintignore | 2 +- contracts/package.json | 10 +- contracts/pnpm-lock.yaml | 145 +++++++++++++++--- .../interfaces/IOwnableFunctionsRouter.sol | 4 +- .../tests/v1_X/FunctionsRequest.t.sol | 24 +-- .../src/v0.8/functions/tests/v1_X/OCR2.t.sol | 36 ++--- .../interfaces/IOwnableFunctionsRouter.sol | 4 +- .../l2ep/dev/CrossDomainDelegateForwarder.sol | 4 +- .../v0.8/l2ep/dev/CrossDomainForwarder.sol | 4 +- 10 files changed, 148 insertions(+), 88 deletions(-) diff --git a/contracts/.solhint.json b/contracts/.solhint.json index 3b69ca6a7f..e66b915d67 100644 --- a/contracts/.solhint.json +++ b/contracts/.solhint.json @@ -37,6 +37,7 @@ "chainlink-solidity/prefix-immutable-variables-with-i": "warn", "chainlink-solidity/all-caps-constant-storage-variables": "warn", "chainlink-solidity/no-hardhat-imports": "warn", - "chainlink-solidity/inherited-constructor-args-not-in-contract-definition": "warn" + "chainlink-solidity/inherited-constructor-args-not-in-contract-definition": "warn", + "chainlink-solidity/explicit-returns": "warn" } } diff --git a/contracts/.solhintignore b/contracts/.solhintignore index bc7be4fbfe..ba2aac1fb3 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1,4 +1,4 @@ -# 377 warnings +# 344 warnings #./src/v0.8/automation # Ignore Functions v1.0.0 code that was frozen after audit diff --git a/contracts/package.json b/contracts/package.json index 05a5293e48..6d0b7af6cc 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 350 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 371 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", @@ -72,11 +72,11 @@ "istanbul": "^0.4.5", "moment": "^2.29.4", "prettier": "^3.0.3", - "prettier-plugin-solidity": "1.1.3", + "prettier-plugin-solidity": "1.1.4-dev", "rlp": "^2.2.7", - "solhint": "^3.6.2", - "solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git", - "solhint-plugin-prettier": "^0.0.5", + "solhint": "^4.0.0", + "solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.0", + "solhint-plugin-prettier": "^0.1.0", "solidity-coverage": "^0.8.5", "ts-node": "^10.9.1", "tslib": "^2.6.2", diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index 2b6082d656..ac4efd5f59 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -140,20 +140,20 @@ devDependencies: specifier: ^3.0.3 version: 3.0.3 prettier-plugin-solidity: - specifier: 1.1.3 - version: 1.1.3(prettier@3.0.3) + specifier: 1.1.4-dev + version: 1.1.4-dev(prettier@3.0.3) rlp: specifier: ^2.2.7 version: 2.2.7 solhint: - specifier: ^3.6.2 - version: 3.6.2 + specifier: ^4.0.0 + version: 4.0.0 solhint-plugin-chainlink-solidity: - specifier: git+https://github.com/smartcontractkit/chainlink-solhint-rules.git - version: github.com/smartcontractkit/chainlink-solhint-rules/6229ce5d3cc3e4a2454411bebc887c5ca240dcf2 + specifier: git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.0 + version: github.com/smartcontractkit/chainlink-solhint-rules/cfc50b32f95b730304a50deb2e27e88d87115874 solhint-plugin-prettier: - specifier: ^0.0.5 - version: 0.0.5(prettier-plugin-solidity@1.1.3)(prettier@3.0.3) + specifier: ^0.1.0 + version: 0.1.0(prettier-plugin-solidity@1.1.4-dev)(prettier@3.0.3) solidity-coverage: specifier: ^0.8.5 version: 0.8.5(hardhat@2.18.1) @@ -1317,6 +1317,35 @@ packages: tslib: 2.6.2 dev: true + /@pnpm/config.env-replace@1.1.0: + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + dev: true + + /@pnpm/network.ca-file@1.0.2: + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + dependencies: + graceful-fs: 4.2.10 + dev: true + + /@pnpm/npm-conf@2.2.2: + resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==} + engines: {node: '>=12'} + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + dev: true + + /@prettier/sync@0.3.0(prettier@3.0.3): + resolution: {integrity: sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==} + peerDependencies: + prettier: ^3.0.0 + dependencies: + prettier: 3.0.3 + dev: true + /@resolver-engine/core@0.3.3: resolution: {integrity: sha512-eB8nEbKDJJBi5p5SrvrvILn4a0h42bKtbCTri3ZxCGt6UvoQyp7HnGOfki944bUjBSHKK3RvgfViHn+kqdXtnQ==} dependencies: @@ -1477,6 +1506,12 @@ packages: antlr4ts: 0.5.0-alpha.4 dev: true + /@solidity-parser/parser@0.16.1: + resolution: {integrity: sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==} + dependencies: + antlr4ts: 0.5.0-alpha.4 + dev: true + /@szmarczak/http-timer@1.1.2: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} engines: {node: '>=6'} @@ -3833,6 +3868,13 @@ packages: typedarray: 0.0.6 dev: true + /config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: true + /constant-case@2.0.0: resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} dependencies: @@ -7326,6 +7368,13 @@ packages: graceful-fs: 4.2.10 dev: true + /latest-version@7.0.0: + resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} + engines: {node: '>=14.16'} + dependencies: + package-json: 8.1.1 + dev: true + /lcid@1.0.0: resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} engines: {node: '>=0.10.0'} @@ -8523,6 +8572,16 @@ packages: engines: {node: '>=6'} dev: true + /package-json@8.1.1: + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} + dependencies: + got: 12.1.0 + registry-auth-token: 5.0.2 + registry-url: 6.0.1 + semver: 7.5.4 + dev: true + /param-case@2.1.1: resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} dependencies: @@ -8822,6 +8881,7 @@ packages: /prettier-plugin-solidity@1.1.3(prettier@2.8.8): resolution: {integrity: sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==} engines: {node: '>=12'} + requiresBuild: true peerDependencies: prettier: '>=2.3.0 || >=3.0.0-alpha.0' dependencies: @@ -8832,15 +8892,15 @@ packages: dev: true optional: true - /prettier-plugin-solidity@1.1.3(prettier@3.0.3): - resolution: {integrity: sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==} - engines: {node: '>=12'} + /prettier-plugin-solidity@1.1.4-dev(prettier@3.0.3): + resolution: {integrity: sha512-SIDnHIPLN/Pod/dZoyJL07ViEcDxrXoT47ROQshpA/WFgyq/rRzLIc3oWkKfWiicHOD493Y/L1n9ds1GbwPoKQ==} + engines: {node: '>=16'} peerDependencies: - prettier: '>=2.3.0 || >=3.0.0-alpha.0' + prettier: '>=2.3.0' dependencies: - '@solidity-parser/parser': 0.16.0 + '@solidity-parser/parser': 0.16.1 prettier: 3.0.3 - semver: 7.5.0 + semver: 7.5.4 solidity-comments-extractor: 0.0.7 dev: true @@ -8892,6 +8952,10 @@ packages: signal-exit: 3.0.7 dev: true + /proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: true + /proxy-addr@2.0.5: resolution: {integrity: sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==} engines: {node: '>= 0.10'} @@ -9080,6 +9144,16 @@ packages: unpipe: 1.0.0 dev: true + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: true + /read-pkg-up@1.0.1: resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} engines: {node: '>=0.10.0'} @@ -9216,6 +9290,20 @@ packages: regjsparser: 0.1.5 dev: true + /registry-auth-token@5.0.2: + resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + engines: {node: '>=14'} + dependencies: + '@pnpm/npm-conf': 2.2.2 + dev: true + + /registry-url@6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + dependencies: + rc: 1.2.8 + dev: true + /regjsgen@0.2.0: resolution: {integrity: sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g==} dev: true @@ -9553,9 +9641,11 @@ packages: resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} engines: {node: '>=10'} hasBin: true + requiresBuild: true dependencies: lru-cache: 6.0.0 dev: true + optional: true /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} @@ -9863,19 +9953,20 @@ packages: - debug dev: true - /solhint-plugin-prettier@0.0.5(prettier-plugin-solidity@1.1.3)(prettier@3.0.3): - resolution: {integrity: sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==} + /solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.1.4-dev)(prettier@3.0.3): + resolution: {integrity: sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==} peerDependencies: - prettier: ^1.15.0 || ^2.0.0 - prettier-plugin-solidity: ^1.0.0-alpha.14 + prettier: ^3.0.0 + prettier-plugin-solidity: ^1.0.0 dependencies: + '@prettier/sync': 0.3.0(prettier@3.0.3) prettier: 3.0.3 prettier-linter-helpers: 1.0.0 - prettier-plugin-solidity: 1.1.3(prettier@3.0.3) + prettier-plugin-solidity: 1.1.4-dev(prettier@3.0.3) dev: true - /solhint@3.6.2: - resolution: {integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==} + /solhint@4.0.0: + resolution: {integrity: sha512-bFViMcFvhqVd/HK3Roo7xZXX5nbujS7Bxeg5vnZc9QvH0yCWCrQ38Yrn1pbAY9tlKROc6wFr+rK1mxYgYrjZgA==} hasBin: true dependencies: '@solidity-parser/parser': 0.16.0 @@ -9889,6 +9980,7 @@ packages: glob: 8.1.0 ignore: 5.2.4 js-yaml: 4.1.0 + latest-version: 7.0.0 lodash: 4.17.21 pluralize: 8.0.0 semver: 7.5.4 @@ -10321,6 +10413,11 @@ packages: engines: {node: '>=4'} dev: true + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: true + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -12349,8 +12446,8 @@ packages: ethereumjs-util: 6.2.1 dev: true - github.com/smartcontractkit/chainlink-solhint-rules/6229ce5d3cc3e4a2454411bebc887c5ca240dcf2: - resolution: {tarball: https://codeload.github.com/smartcontractkit/chainlink-solhint-rules/tar.gz/6229ce5d3cc3e4a2454411bebc887c5ca240dcf2} + github.com/smartcontractkit/chainlink-solhint-rules/cfc50b32f95b730304a50deb2e27e88d87115874: + resolution: {tarball: https://codeload.github.com/smartcontractkit/chainlink-solhint-rules/tar.gz/cfc50b32f95b730304a50deb2e27e88d87115874} name: '@chainlink/solhint-plugin-chainlink-solidity' - version: 1.0.1 + version: 1.2.0 dev: true diff --git a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IOwnableFunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IOwnableFunctionsRouter.sol index 39b84a930a..f6d7880da3 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IOwnableFunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IOwnableFunctionsRouter.sol @@ -5,6 +5,4 @@ import {IFunctionsRouter} from "./IFunctionsRouter.sol"; import {IOwnable} from "../../../../shared/interfaces/IOwnable.sol"; /// @title Chainlink Functions Router interface with Ownability. -interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter { - -} +interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter {} diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRequest.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRequest.t.sol index 5457a221b6..e9684d9f5b 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRequest.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRequest.t.sol @@ -30,31 +30,19 @@ contract FunctionsRequest_EncodeCBOR is Test { } /// @notice #initializeRequest -contract FunctionsRequest_InitializeRequest is Test { - -} +contract FunctionsRequest_InitializeRequest is Test {} /// @notice #initializeRequestForInlineJavaScript -contract FunctionsRequest_InitializeRequestForInlineJavaScript is Test { - -} +contract FunctionsRequest_InitializeRequestForInlineJavaScript is Test {} /// @notice #addSecretsReference -contract FunctionsRequest_AddSecretsReference is Test { - -} +contract FunctionsRequest_AddSecretsReference is Test {} /// @notice #addDONHostedSecrets -contract FunctionsRequest_AddDONHostedSecrets is Test { - -} +contract FunctionsRequest_AddDONHostedSecrets is Test {} /// @notice #setArgs -contract FunctionsRequest_SetArgs is Test { - -} +contract FunctionsRequest_SetArgs is Test {} /// @notice #setBytesArgs -contract FunctionsRequest_SetBytesArgs is Test { - -} +contract FunctionsRequest_SetBytesArgs is Test {} diff --git a/contracts/src/v0.8/functions/tests/v1_X/OCR2.t.sol b/contracts/src/v0.8/functions/tests/v1_X/OCR2.t.sol index 745ad4f0ae..3dc0db85a4 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/OCR2.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/OCR2.t.sol @@ -6,39 +6,25 @@ pragma solidity ^0.8.19; // ================================================================ /// @notice #constructor -contract OCR2Base_Constructor { - -} +contract OCR2Base_Constructor {} /// @notice #checkConfigValid -contract OCR2Base_CheckConfigValid { - -} +contract OCR2Base_CheckConfigValid {} /// @notice #latestConfigDigestAndEpoch -contract OCR2Base_LatestConfigDigestAndEpoch { - -} +contract OCR2Base_LatestConfigDigestAndEpoch {} /// @notice #setConfig -contract OCR2Base_SetConfig { - -} +contract OCR2Base_SetConfig {} /// @notice #configDigestFromConfigData -contract OCR2Base_ConfigDigestFromConfigData { - -} +contract OCR2Base_ConfigDigestFromConfigData {} /// @notice #latestConfigDetails -contract OCR2Base_LatestConfigDetails { - -} +contract OCR2Base_LatestConfigDetails {} /// @notice #transmitters -contract OCR2Base_Transmitters { - -} +contract OCR2Base_Transmitters {} /// @notice #_report contract OCR2Base__Report { @@ -46,11 +32,7 @@ contract OCR2Base__Report { } /// @notice #requireExpectedMsgDataLength -contract OCR2Base_RequireExpectedMsgDataLength { - -} +contract OCR2Base_RequireExpectedMsgDataLength {} /// @notice #transmit -contract OCR2Base_Transmit { - -} +contract OCR2Base_Transmit {} diff --git a/contracts/src/v0.8/functions/v1_0_0/interfaces/IOwnableFunctionsRouter.sol b/contracts/src/v0.8/functions/v1_0_0/interfaces/IOwnableFunctionsRouter.sol index 89eb48022b..c5f3d82677 100644 --- a/contracts/src/v0.8/functions/v1_0_0/interfaces/IOwnableFunctionsRouter.sol +++ b/contracts/src/v0.8/functions/v1_0_0/interfaces/IOwnableFunctionsRouter.sol @@ -5,6 +5,4 @@ import {IFunctionsRouter} from "./IFunctionsRouter.sol"; import {IOwnable} from "../../../shared/interfaces/IOwnable.sol"; /// @title Chainlink Functions Router interface with Ownability. -interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter { - -} +interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter {} diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol index 1eb6cba932..5dc73619af 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol @@ -10,6 +10,4 @@ import {DelegateForwarderInterface} from "./interfaces/DelegateForwarderInterfac * @dev Any other L2 contract which uses this contract's address as a privileged position, * can consider that position to be held by the `l1Owner` */ -abstract contract CrossDomainDelegateForwarder is DelegateForwarderInterface, CrossDomainOwnable { - -} +abstract contract CrossDomainDelegateForwarder is DelegateForwarderInterface, CrossDomainOwnable {} diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol index 1f9066c505..8f218f66b8 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol @@ -10,6 +10,4 @@ import {ForwarderInterface} from "./interfaces/ForwarderInterface.sol"; * @dev Any other L2 contract which uses this contract's address as a privileged position, * can consider that position to be held by the `l1Owner` */ -abstract contract CrossDomainForwarder is ForwarderInterface, CrossDomainOwnable { - -} +abstract contract CrossDomainForwarder is ForwarderInterface, CrossDomainOwnable {} From 606e5f2b113bca494199a8385819132d6625403d Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 9 Nov 2023 09:24:14 -0600 Subject: [PATCH 117/327] switch sqlx from smartcontractkit to jmoiron (#11238) --- core/bridges/orm.go | 2 +- core/bridges/orm_test.go | 2 +- core/chains/evm/chain.go | 2 +- core/chains/evm/chain_test.go | 2 +- core/chains/evm/evm_txm.go | 2 +- .../evm/forwarders/forwarder_manager.go | 3 +- core/chains/evm/forwarders/orm.go | 2 +- core/chains/evm/forwarders/orm_test.go | 2 +- .../evm/headtracker/head_tracker_test.go | 2 +- core/chains/evm/headtracker/orm.go | 2 +- core/chains/evm/log/helpers_test.go | 2 +- core/chains/evm/log/orm.go | 2 +- core/chains/evm/logpoller/observability.go | 2 +- core/chains/evm/logpoller/orm.go | 2 +- core/chains/evm/txmgr/builder.go | 2 +- core/chains/evm/txmgr/evm_tx_store.go | 2 +- core/chains/evm/txmgr/txmgr_test.go | 2 +- core/cmd/ocr2vrf_configure_commands.go | 2 +- core/cmd/shell.go | 2 +- core/cmd/shell_local.go | 2 +- core/internal/cltest/cltest.go | 2 +- core/internal/cltest/factories.go | 2 +- core/internal/cltest/heavyweight/orm.go | 2 +- core/internal/cltest/job_factories.go | 2 +- core/internal/cltest/mocks.go | 2 +- core/internal/mocks/application.go | 2 +- core/internal/testutils/evmtest/evmtest.go | 2 +- core/internal/testutils/pgtest/pgtest.go | 2 +- core/internal/testutils/pgtest/txdb.go | 2 +- core/internal/testutils/pgtest/txdb_test.go | 2 +- core/internal/testutils/testutils.go | 2 +- core/scripts/go.mod | 5 ++-- core/scripts/go.sum | 6 ++-- core/scripts/vrfv2/testnet/main.go | 2 +- core/scripts/vrfv2plus/testnet/main.go | 5 ++-- core/services/chainlink/application.go | 2 +- core/services/chainlink/relayer_factory.go | 2 +- core/services/feeds/orm.go | 2 +- core/services/feeds/orm_test.go | 2 +- core/services/feeds/service.go | 3 +- core/services/fluxmonitorv2/delegate.go | 2 +- core/services/fluxmonitorv2/flux_monitor.go | 3 +- .../fluxmonitorv2/flux_monitor_test.go | 2 +- .../fluxmonitorv2/integrations_test.go | 2 +- core/services/fluxmonitorv2/orm.go | 2 +- core/services/functions/orm.go | 2 +- core/services/job/helpers_test.go | 2 +- core/services/job/job_orm_test.go | 3 +- .../job/job_pipeline_orm_integration_test.go | 2 +- core/services/job/orm.go | 6 ++-- core/services/job/orm_test.go | 2 +- core/services/job/spawner.go | 2 +- core/services/job/spawner_test.go | 2 +- core/services/keeper/delegate.go | 2 +- core/services/keeper/orm.go | 2 +- core/services/keeper/orm_test.go | 2 +- .../registry_synchronizer_helper_test.go | 2 +- core/services/keeper/upkeep_executer_test.go | 2 +- core/services/keystore/helpers_test.go | 2 +- core/services/keystore/keystoretest.go | 2 +- core/services/keystore/master.go | 2 +- core/services/keystore/orm.go | 2 +- core/services/ocr/contract_tracker.go | 3 +- core/services/ocr/database.go | 2 +- core/services/ocr/delegate.go | 2 +- core/services/ocr/helpers_internal_test.go | 2 +- core/services/ocr2/database.go | 2 +- core/services/ocr2/database_test.go | 2 +- core/services/ocr2/delegate.go | 2 +- .../ocr2/plugins/dkg/persistence/db.go | 2 +- .../ocr2/plugins/dkg/persistence/db_test.go | 2 +- core/services/ocr2/plugins/dkg/plugin.go | 2 +- .../services/ocr2/plugins/functions/plugin.go | 2 +- .../evm21/logprovider/integration_test.go | 2 +- .../ocr2/plugins/ocr2keeper/evm21/services.go | 2 +- .../ocr2keeper/evm21/upkeepstate/orm.go | 2 +- core/services/ocr2/plugins/ocr2keeper/util.go | 2 +- core/services/ocrbootstrap/database_test.go | 2 +- core/services/ocrbootstrap/delegate.go | 2 +- core/services/ocrcommon/peer_wrapper.go | 2 +- core/services/ocrcommon/peerstore.go | 3 +- core/services/pg/connection.go | 2 +- core/services/pg/connection_test.go | 2 +- core/services/pg/helpers_test.go | 2 +- core/services/pg/lease_lock.go | 2 +- core/services/pg/lease_lock_test.go | 2 +- core/services/pg/locked_db.go | 2 +- core/services/pg/q.go | 2 +- core/services/pg/sqlx.go | 2 +- core/services/pg/transaction.go | 2 +- core/services/pipeline/orm.go | 2 +- core/services/pipeline/orm_test.go | 2 +- core/services/pipeline/runner_test.go | 2 +- core/services/pipeline/test_helpers_test.go | 2 +- core/services/relay/evm/evm.go | 2 +- core/services/relay/evm/evm_test.go | 2 +- core/services/relay/evm/median.go | 2 +- core/services/relay/evm/mercury/orm.go | 2 +- .../evm/mercury/persistence_manager_test.go | 2 +- .../services/relay/evm/mercury/transmitter.go | 2 +- core/services/relay/evm/ocr2keeper.go | 2 +- core/services/relay/evm/ocr2vrf.go | 2 +- .../relay/evm/request_round_tracker.go | 3 +- core/services/s4/postgres_orm.go | 2 +- core/services/versioning/orm.go | 2 +- core/services/vrf/delegate.go | 2 +- core/services/vrf/delegate_test.go | 2 +- core/services/vrf/v2/integration_v2_test.go | 2 +- core/services/webhook/authorizer_test.go | 2 +- .../webhook/external_initiator_manager.go | 2 +- core/sessions/ldapauth/helpers_test.go | 2 +- core/sessions/ldapauth/ldap.go | 2 +- core/sessions/ldapauth/ldap_test.go | 2 +- core/sessions/ldapauth/sync.go | 2 +- core/sessions/localauth/orm.go | 2 +- core/sessions/localauth/orm_test.go | 2 +- core/sessions/webauthn.go | 2 +- core/sessions/webauthn_test.go | 2 +- core/store/migrate/migrate.go | 2 +- .../migrations/0036_external_job_id.go | 2 +- core/web/jobs_controller_test.go | 2 +- go.mod | 5 ++-- go.sum | 6 ++-- integration-tests/go.mod | 5 ++-- integration-tests/go.sum | 6 ++-- .../universal/log_poller/helpers.go | 28 +++++++++---------- 126 files changed, 156 insertions(+), 157 deletions(-) diff --git a/core/bridges/orm.go b/core/bridges/orm.go index 96801f4484..cfad1da836 100644 --- a/core/bridges/orm.go +++ b/core/bridges/orm.go @@ -6,8 +6,8 @@ import ( "sync" "time" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/bridges/orm_test.go b/core/bridges/orm_test.go index b110b4f519..0b485764c8 100644 --- a/core/bridges/orm_test.go +++ b/core/bridges/orm_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index 936abc6216..b5896393d3 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -11,7 +11,7 @@ import ( gotoml "github.com/pelletier/go-toml/v2" "go.uber.org/multierr" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" relaychains "github.com/smartcontractkit/chainlink-relay/pkg/chains" "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/chains/evm/chain_test.go b/core/chains/evm/chain_test.go index ba24598ef7..f25af87a35 100644 --- a/core/chains/evm/chain_test.go +++ b/core/chains/evm/chain_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" diff --git a/core/chains/evm/evm_txm.go b/core/chains/evm/evm_txm.go index a8673e954a..bfc0f6378b 100644 --- a/core/chains/evm/evm_txm.go +++ b/core/chains/evm/evm_txm.go @@ -3,7 +3,7 @@ package evm import ( "fmt" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 46bca95ba3..934da487fd 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -10,9 +10,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmlogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/chains/evm/forwarders/orm.go b/core/chains/evm/forwarders/orm.go index 287698d22f..df89dbe29e 100644 --- a/core/chains/evm/forwarders/orm.go +++ b/core/chains/evm/forwarders/orm.go @@ -4,8 +4,8 @@ import ( "database/sql" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/chains/evm/forwarders/orm_test.go b/core/chains/evm/forwarders/orm_test.go index a3d5c2831f..f6d63dc574 100644 --- a/core/chains/evm/forwarders/orm_test.go +++ b/core/chains/evm/forwarders/orm_test.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" ) type TestORM struct { diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index 502aa4ae6d..8af344098f 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/exp/maps" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/chains/evm/headtracker/orm.go b/core/chains/evm/headtracker/orm.go index 426df68b30..34f46ce44d 100644 --- a/core/chains/evm/headtracker/orm.go +++ b/core/chains/evm/headtracker/orm.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index 688757a3e9..f787002578 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" diff --git a/core/chains/evm/log/orm.go b/core/chains/evm/log/orm.go index 4e51940f34..d383419d72 100644 --- a/core/chains/evm/log/orm.go +++ b/core/chains/evm/log/orm.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/chains/evm/logpoller/observability.go b/core/chains/evm/logpoller/observability.go index 7f54fa9f09..c4b58b42a2 100644 --- a/core/chains/evm/logpoller/observability.go +++ b/core/chains/evm/logpoller/observability.go @@ -5,9 +5,9 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index 06f4acbb4f..e044be2e0c 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -8,8 +8,8 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 9123d1dfc0..5e3d61301c 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -4,7 +4,7 @@ import ( "math/big" "time" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 971103bdfd..4db7989b46 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -13,9 +13,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/jackc/pgconn" + "github.com/jmoiron/sqlx" "github.com/lib/pq" pkgerrors "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" nullv4 "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/common/txmgr" diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 4aa54bc52a..4e201b9c6f 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index a3feddd611..bb4cef4708 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -14,7 +14,7 @@ import ( "github.com/pkg/errors" "github.com/urfave/cli" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 80ecd2590b..595c42b9fe 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -29,7 +29,7 @@ import ( "go.uber.org/zap/zapcore" "golang.org/x/sync/errgroup" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/loop" diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index dea9a29359..954cead5c3 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -29,7 +29,7 @@ import ( "golang.org/x/sync/errgroup" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/build" diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index e5c2ca031a..778ccbdb15 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -39,8 +39,8 @@ import ( "github.com/tidwall/gjson" "github.com/urfave/cli" + "github.com/jmoiron/sqlx" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/loop" diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 82235baf6b..a52b9a5d06 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -21,7 +21,7 @@ import ( "github.com/urfave/cli" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" diff --git a/core/internal/cltest/heavyweight/orm.go b/core/internal/cltest/heavyweight/orm.go index b46e7114cf..5df28a4977 100644 --- a/core/internal/cltest/heavyweight/orm.go +++ b/core/internal/cltest/heavyweight/orm.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index b76d6c7ec2..a9e403fb60 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -7,7 +7,7 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 00f72199dd..540924d7f0 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index 7853361db9..48f8e12dac 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -31,7 +31,7 @@ import ( sessions "github.com/smartcontractkit/chainlink/v2/core/sessions" - sqlx "github.com/smartcontractkit/sqlx" + sqlx "github.com/jmoiron/sqlx" txmgr "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 3a08c81516..80237d218d 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -9,8 +9,8 @@ import ( "testing" "github.com/ethereum/go-ethereum" + "github.com/jmoiron/sqlx" "github.com/pelletier/go-toml/v2" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" diff --git a/core/internal/testutils/pgtest/pgtest.go b/core/internal/testutils/pgtest/pgtest.go index 283326de85..1900fcc62b 100644 --- a/core/internal/testutils/pgtest/pgtest.go +++ b/core/internal/testutils/pgtest/pgtest.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/google/uuid" + "github.com/jmoiron/sqlx" "github.com/scylladb/go-reflectx" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/core/internal/testutils/pgtest/txdb.go b/core/internal/testutils/pgtest/txdb.go index 598a5dddc5..da9fd6cb2d 100644 --- a/core/internal/testutils/pgtest/txdb.go +++ b/core/internal/testutils/pgtest/txdb.go @@ -12,7 +12,7 @@ import ( "sync" "testing" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "go.uber.org/multierr" "github.com/smartcontractkit/chainlink/v2/core/config/env" diff --git a/core/internal/testutils/pgtest/txdb_test.go b/core/internal/testutils/pgtest/txdb_test.go index 71960c6150..c1aeef4b8c 100644 --- a/core/internal/testutils/pgtest/txdb_test.go +++ b/core/internal/testutils/pgtest/txdb_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/google/uuid" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" ) diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 79c86f0c5f..6ffd873d09 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -27,7 +27,7 @@ import ( "github.com/tidwall/gjson" "go.uber.org/zap/zaptest/observer" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/core/scripts/go.mod b/core/scripts/go.mod index aada3850db..3adcc130bc 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -13,6 +13,7 @@ require ( github.com/ethereum/go-ethereum v1.12.0 github.com/google/go-cmp v0.5.9 github.com/google/uuid v1.3.1 + github.com/jmoiron/sqlx v1.3.5 github.com/joho/godotenv v1.4.0 github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f github.com/montanaflynn/stats v0.7.1 @@ -24,7 +25,6 @@ require ( github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 - github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.4 @@ -199,7 +199,6 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.0 // indirect @@ -304,7 +303,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 // indirect 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.20231101160906-7acebcc1b353 // 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-solana v1.0.3-0.20231023133638-72f4e799ab05 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 4f42c84d4e..7f5d0e227d 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1462,8 +1462,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= +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-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= @@ -1480,8 +1480,6 @@ github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGuj github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index 5b216776bd..677c0b105e 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -21,7 +21,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/shopspring/decimal" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/assets" diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index 0d1bf9a948..b7940d6fda 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -6,12 +6,13 @@ import ( "encoding/hex" "flag" "fmt" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2plus/testnet/v2plusscripts" "log" "math/big" "os" "strings" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2plus/testnet/v2plusscripts" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_specific_util_helper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" @@ -25,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/shopspring/decimal" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/assets" diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 3285acdc07..0d479b1f1a 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -16,7 +16,7 @@ import ( "go.uber.org/multierr" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/loop" relayservices "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 76bfcd1641..d452decda1 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -7,7 +7,7 @@ import ( "github.com/pelletier/go-toml/v2" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" diff --git a/core/services/feeds/orm.go b/core/services/feeds/orm.go index 30b6ad632a..24ed7b8b36 100644 --- a/core/services/feeds/orm.go +++ b/core/services/feeds/orm.go @@ -9,7 +9,7 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 3d51ad45ff..02b9e24739 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index 20919606fa..f6e8952d6b 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -15,9 +15,10 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" pb "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto" diff --git a/core/services/fluxmonitorv2/delegate.go b/core/services/fluxmonitorv2/delegate.go index d380122f71..e63f355672 100644 --- a/core/services/fluxmonitorv2/delegate.go +++ b/core/services/fluxmonitorv2/delegate.go @@ -3,7 +3,7 @@ package fluxmonitorv2 import ( "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index 99d33c4239..5dbeaeafc3 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -13,9 +13,10 @@ import ( "github.com/pkg/errors" "github.com/shopspring/decimal" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/bridges" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index 26ec520e7c..e81e1ba9e6 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/assets" diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index b2f24e08d5..38c73d3ad7 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -24,7 +24,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" diff --git a/core/services/fluxmonitorv2/orm.go b/core/services/fluxmonitorv2/orm.go index 61395e8708..f85ab146c7 100644 --- a/core/services/fluxmonitorv2/orm.go +++ b/core/services/fluxmonitorv2/orm.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/services/functions/orm.go b/core/services/functions/orm.go index b6f692019a..7838c70085 100644 --- a/core/services/functions/orm.go +++ b/core/services/functions/orm.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/job/helpers_test.go b/core/services/job/helpers_test.go index 167ed5297c..4151ed401c 100644 --- a/core/services/job/helpers_test.go +++ b/core/services/job/helpers_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 6306dedcef..f4471e75c6 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -16,8 +16,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -38,6 +36,7 @@ import ( ocr2validate "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index a2b6cc4618..f1307753d2 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/services/job/orm.go b/core/services/job/orm.go index c6ec4ed5c8..fb897bc928 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -16,7 +16,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/types" @@ -992,11 +992,13 @@ func (o *orm) loadPipelineRunIDs(jobID *int32, offset, limit int, tx pg.Queryer) // range minID <-> maxID. for n := int64(1000); maxID > 0 && len(ids) < limit; n *= 2 { + var batch []int64 minID := maxID - n - if err = tx.Select(&ids, stmt, offset, limit-len(ids), minID, maxID); err != nil { + if err = tx.Select(&batch, stmt, offset, limit-len(ids), minID, maxID); err != nil { err = errors.Wrap(err, "error loading runs") return } + ids = append(ids, batch...) if offset > 0 { if len(ids) > 0 { // If we're already receiving rows back, then we no longer need an offset diff --git a/core/services/job/orm_test.go b/core/services/job/orm_test.go index 48805388a3..41d02dba06 100644 --- a/core/services/job/orm_test.go +++ b/core/services/job/orm_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index b2a8dad68f..03ee8cee13 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -9,7 +9,7 @@ import ( pkgerrors "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" relayservices "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 1f10a86e9c..cfe646d866 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index 6c68203f84..6d41362496 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -3,7 +3,7 @@ package keeper import ( "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/keeper/orm.go b/core/services/keeper/orm.go index e281d61064..91883f8056 100644 --- a/core/services/keeper/orm.go +++ b/core/services/keeper/orm.go @@ -3,9 +3,9 @@ package keeper import ( "math/rand" + "github.com/jmoiron/sqlx" "github.com/lib/pq" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/services/keeper/orm_test.go b/core/services/keeper/orm_test.go index d990effa10..d67baa09a0 100644 --- a/core/services/keeper/orm_test.go +++ b/core/services/keeper/orm_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index 63dc634353..966366b106 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 7f9698435f..32b1d2c191 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/services/keystore/helpers_test.go b/core/services/keystore/helpers_test.go index 13627dd023..d0b2a21ab3 100644 --- a/core/services/keystore/helpers_test.go +++ b/core/services/keystore/helpers_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/services/keystore/keystoretest.go b/core/services/keystore/keystoretest.go index 0b5ce4e005..6efc8e76bc 100644 --- a/core/services/keystore/keystoretest.go +++ b/core/services/keystore/keystoretest.go @@ -4,7 +4,7 @@ import ( "errors" "sync" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/keystore/master.go b/core/services/keystore/master.go index fb28202b52..05f19495f9 100644 --- a/core/services/keystore/master.go +++ b/core/services/keystore/master.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" diff --git a/core/services/keystore/orm.go b/core/services/keystore/orm.go index 6f612105ea..3d75d6f236 100644 --- a/core/services/keystore/orm.go +++ b/core/services/keystore/orm.go @@ -7,8 +7,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" ) func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) ksORM { diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index f49e556d4e..db19bdd4f0 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -14,13 +14,14 @@ import ( gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-relay/pkg/services" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" diff --git a/core/services/ocr/database.go b/core/services/ocr/database.go index cd8e584e39..524dfa0e7b 100644 --- a/core/services/ocr/database.go +++ b/core/services/ocr/database.go @@ -11,9 +11,9 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index 6eb6714a47..0559469abb 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" diff --git a/core/services/ocr/helpers_internal_test.go b/core/services/ocr/helpers_internal_test.go index 9a1f887986..57b669ef40 100644 --- a/core/services/ocr/helpers_internal_test.go +++ b/core/services/ocr/helpers_internal_test.go @@ -3,7 +3,7 @@ package ocr import ( "testing" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/database.go b/core/services/ocr2/database.go index 7061ad0452..5591f33fd4 100644 --- a/core/services/ocr2/database.go +++ b/core/services/ocr2/database.go @@ -6,11 +6,11 @@ import ( "encoding/binary" "time" + "github.com/jmoiron/sqlx" "github.com/lib/pq" "github.com/pkg/errors" ocrcommon "github.com/smartcontractkit/libocr/commontypes" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/ocr2/database_test.go b/core/services/ocr2/database_test.go index aabb2b33a7..b70ac629da 100644 --- a/core/services/ocr2/database_test.go +++ b/core/services/ocr2/database_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/jmoiron/sqlx" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 1e87915bd1..95ec146915 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -27,7 +28,6 @@ import ( "github.com/smartcontractkit/ocr2vrf/altbn_128" dkgpkg "github.com/smartcontractkit/ocr2vrf/dkg" "github.com/smartcontractkit/ocr2vrf/ocr2vrf" - "github.com/smartcontractkit/sqlx" relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/loop" diff --git a/core/services/ocr2/plugins/dkg/persistence/db.go b/core/services/ocr2/plugins/dkg/persistence/db.go index 75fb3b391f..c020a68cbe 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db.go +++ b/core/services/ocr2/plugins/dkg/persistence/db.go @@ -9,13 +9,13 @@ import ( "time" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" "github.com/smartcontractkit/ocr2vrf/types/hash" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/ocr2/plugins/dkg/persistence/db_test.go b/core/services/ocr2/plugins/dkg/persistence/db_test.go index b830a8db3b..4e029c1cb2 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db_test.go +++ b/core/services/ocr2/plugins/dkg/persistence/db_test.go @@ -7,9 +7,9 @@ import ( "testing" "github.com/ethereum/go-ethereum/crypto" + "github.com/jmoiron/sqlx" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" "github.com/smartcontractkit/ocr2vrf/types/hash" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/core/services/ocr2/plugins/dkg/plugin.go b/core/services/ocr2/plugins/dkg/plugin.go index 540518b553..92910ff7bb 100644 --- a/core/services/ocr2/plugins/dkg/plugin.go +++ b/core/services/ocr2/plugins/dkg/plugin.go @@ -6,12 +6,12 @@ import ( "fmt" "math/big" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" "github.com/smartcontractkit/ocr2vrf/altbn_128" "github.com/smartcontractkit/ocr2vrf/dkg" - "github.com/smartcontractkit/sqlx" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 10f780371b..26cffac5ab 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -7,8 +7,8 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index 63ed4114b8..9a1e99610c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -17,7 +17,7 @@ import ( "go.uber.org/zap/zapcore" "golang.org/x/time/rate" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go index f9d3dd9259..d178a9af57 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go @@ -4,11 +4,11 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go index 5db2f8bd0f..c918ad595f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go @@ -4,8 +4,8 @@ import ( "math/big" "time" + "github.com/jmoiron/sqlx" "github.com/lib/pq" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 132afd0d29..fca98d8700 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -3,12 +3,12 @@ package ocr2keeper import ( "fmt" + "github.com/jmoiron/sqlx" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocr2keepers20 "github.com/smartcontractkit/ocr2keepers/pkg/v2" ocr2keepers20coordinator "github.com/smartcontractkit/ocr2keepers/pkg/v2/coordinator" ocr2keepers20polling "github.com/smartcontractkit/ocr2keepers/pkg/v2/observer/polling" ocr2keepers20runner "github.com/smartcontractkit/ocr2keepers/pkg/v2/runner" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/types" diff --git a/core/services/ocrbootstrap/database_test.go b/core/services/ocrbootstrap/database_test.go index 2f160eff58..e00e318c69 100644 --- a/core/services/ocrbootstrap/database_test.go +++ b/core/services/ocrbootstrap/database_test.go @@ -3,7 +3,7 @@ package ocrbootstrap_test import ( "testing" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/stretchr/testify/require" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" diff --git a/core/services/ocrbootstrap/delegate.go b/core/services/ocrbootstrap/delegate.go index 3910ca05d3..34e3ee0a71 100644 --- a/core/services/ocrbootstrap/delegate.go +++ b/core/services/ocrbootstrap/delegate.go @@ -7,8 +7,8 @@ import ( "github.com/pkg/errors" + "github.com/jmoiron/sqlx" ocr "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/sqlx" relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/loop" diff --git a/core/services/ocrcommon/peer_wrapper.go b/core/services/ocrcommon/peer_wrapper.go index 0781303275..1daa84b721 100644 --- a/core/services/ocrcommon/peer_wrapper.go +++ b/core/services/ocrcommon/peer_wrapper.go @@ -11,11 +11,11 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/jmoiron/sqlx" ocrnetworking "github.com/smartcontractkit/libocr/networking" ocrnetworkingtypes "github.com/smartcontractkit/libocr/networking/types" ocr1types "github.com/smartcontractkit/libocr/offchainreporting/types" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/services/ocrcommon/peerstore.go b/core/services/ocrcommon/peerstore.go index f1c318a3bf..02a4d90f57 100644 --- a/core/services/ocrcommon/peerstore.go +++ b/core/services/ocrcommon/peerstore.go @@ -12,9 +12,10 @@ import ( ma "github.com/multiformats/go-multiaddr" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" diff --git a/core/services/pg/connection.go b/core/services/pg/connection.go index 19c48a118b..0bafd5dcd0 100644 --- a/core/services/pg/connection.go +++ b/core/services/pg/connection.go @@ -6,8 +6,8 @@ import ( "github.com/google/uuid" _ "github.com/jackc/pgx/v4/stdlib" // need to make sure pgx driver is registered before opening connection + "github.com/jmoiron/sqlx" "github.com/scylladb/go-reflectx" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" ) diff --git a/core/services/pg/connection_test.go b/core/services/pg/connection_test.go index 92781343c6..651bf9d2d9 100644 --- a/core/services/pg/connection_test.go +++ b/core/services/pg/connection_test.go @@ -5,7 +5,7 @@ import ( "github.com/google/uuid" _ "github.com/jackc/pgx/v4/stdlib" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/pg/helpers_test.go b/core/services/pg/helpers_test.go index c5ccda6bd9..52158535a2 100644 --- a/core/services/pg/helpers_test.go +++ b/core/services/pg/helpers_test.go @@ -1,6 +1,6 @@ package pg -import "github.com/smartcontractkit/sqlx" +import "github.com/jmoiron/sqlx" func SetConn(lock interface{}, conn *sqlx.Conn) { switch v := lock.(type) { diff --git a/core/services/pg/lease_lock.go b/core/services/pg/lease_lock.go index 656005016e..e21cec44bd 100644 --- a/core/services/pg/lease_lock.go +++ b/core/services/pg/lease_lock.go @@ -8,8 +8,8 @@ import ( "time" "github.com/google/uuid" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "go.uber.org/multierr" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/pg/lease_lock_test.go b/core/services/pg/lease_lock_test.go index 483e03e003..1b4116b5bf 100644 --- a/core/services/pg/lease_lock_test.go +++ b/core/services/pg/lease_lock_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" diff --git a/core/services/pg/locked_db.go b/core/services/pg/locked_db.go index af4481285c..a9157fe1ae 100644 --- a/core/services/pg/locked_db.go +++ b/core/services/pg/locked_db.go @@ -8,7 +8,7 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/pg/q.go b/core/services/pg/q.go index 9c70d813ab..470d39c825 100644 --- a/core/services/pg/q.go +++ b/core/services/pg/q.go @@ -15,7 +15,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/logger" ) diff --git a/core/services/pg/sqlx.go b/core/services/pg/sqlx.go index cd5427463d..820cd51712 100644 --- a/core/services/pg/sqlx.go +++ b/core/services/pg/sqlx.go @@ -7,7 +7,7 @@ import ( "github.com/pkg/errors" mapper "github.com/scylladb/go-reflectx" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/logger" ) diff --git a/core/services/pg/transaction.go b/core/services/pg/transaction.go index 932b112085..d237c20d4c 100644 --- a/core/services/pg/transaction.go +++ b/core/services/pg/transaction.go @@ -10,7 +10,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/logger" diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index 148901bb36..d60050700f 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -11,7 +11,7 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index 295ad20a00..dcbbfd9c97 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -10,7 +10,7 @@ import ( "go.uber.org/zap/zapcore" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index 3abcdbe0ab..695590e7bd 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -37,7 +37,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" ) func newRunner(t testing.TB, db *sqlx.DB, bridgeORM bridges.ORM, cfg chainlink.GeneralConfig) (pipeline.Runner, *mocks.ORM) { diff --git a/core/services/pipeline/test_helpers_test.go b/core/services/pipeline/test_helpers_test.go index 8353f5fb5b..3b72a1625b 100644 --- a/core/services/pipeline/test_helpers_test.go +++ b/core/services/pipeline/test_helpers_test.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" ) func fakeExternalAdapter(t *testing.T, expectedRequest, response interface{}) http.Handler { diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 3f45b41f46..111e3622b1 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -13,12 +13,12 @@ import ( pkgerrors "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median/evmreportcodec" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" diff --git a/core/services/relay/evm/evm_test.go b/core/services/relay/evm/evm_test.go index 4e9c44a7b9..8f49128ff2 100644 --- a/core/services/relay/evm/evm_test.go +++ b/core/services/relay/evm/evm_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/relay/evm/median.go b/core/services/relay/evm/median.go index b7d751e01e..5184326cf2 100644 --- a/core/services/relay/evm/median.go +++ b/core/services/relay/evm/median.go @@ -7,12 +7,12 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator" diff --git a/core/services/relay/evm/mercury/orm.go b/core/services/relay/evm/mercury/orm.go index 7273519f6b..f8d4c8cb1e 100644 --- a/core/services/relay/evm/mercury/orm.go +++ b/core/services/relay/evm/mercury/orm.go @@ -8,9 +8,9 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/lib/pq" pkgerrors "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" diff --git a/core/services/relay/evm/mercury/persistence_manager_test.go b/core/services/relay/evm/mercury/persistence_manager_test.go index d185a64a8f..dbdb977725 100644 --- a/core/services/relay/evm/mercury/persistence_manager_test.go +++ b/core/services/relay/evm/mercury/persistence_manager_test.go @@ -6,8 +6,8 @@ import ( "time" "github.com/cometbft/cometbft/libs/rand" + "github.com/jmoiron/sqlx" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 557210e58a..269f28b122 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -16,9 +16,9 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" "github.com/smartcontractkit/chainlink-relay/pkg/services" diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index baf98b9b00..a284d677eb 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -8,12 +8,12 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" - "github.com/smartcontractkit/sqlx" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index 14004d0b1a..0c9414068e 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -7,11 +7,11 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" diff --git a/core/services/relay/evm/request_round_tracker.go b/core/services/relay/evm/request_round_tracker.go index 4e065f2dfd..c1c3a49e0e 100644 --- a/core/services/relay/evm/request_round_tracker.go +++ b/core/services/relay/evm/request_round_tracker.go @@ -9,11 +9,12 @@ import ( gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/services" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator" diff --git a/core/services/s4/postgres_orm.go b/core/services/s4/postgres_orm.go index d0a79dba95..1f91270fd0 100644 --- a/core/services/s4/postgres_orm.go +++ b/core/services/s4/postgres_orm.go @@ -9,8 +9,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" ) const ( diff --git a/core/services/versioning/orm.go b/core/services/versioning/orm.go index 03bd64fdd2..8ed745955d 100644 --- a/core/services/versioning/orm.go +++ b/core/services/versioning/orm.go @@ -7,8 +7,8 @@ import ( "github.com/Masterminds/semver/v3" "github.com/jackc/pgconn" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index 558d48752d..e976d01b99 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -10,7 +10,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "go.uber.org/multierr" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 927e2ae682..389e1159be 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index e50ed91491..1f607da2f2 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -28,7 +28,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" diff --git a/core/services/webhook/authorizer_test.go b/core/services/webhook/authorizer_test.go index 19dbf38140..b6eb2feacc 100644 --- a/core/services/webhook/authorizer_test.go +++ b/core/services/webhook/authorizer_test.go @@ -3,7 +3,7 @@ package webhook_test import ( "testing" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/webhook/external_initiator_manager.go b/core/services/webhook/external_initiator_manager.go index 2e881ec42d..01edf82b11 100644 --- a/core/services/webhook/external_initiator_manager.go +++ b/core/services/webhook/external_initiator_manager.go @@ -10,7 +10,7 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/sessions/ldapauth/helpers_test.go b/core/sessions/ldapauth/helpers_test.go index c554d5436e..3566ea8438 100644 --- a/core/sessions/ldapauth/helpers_test.go +++ b/core/sessions/ldapauth/helpers_test.go @@ -3,7 +3,7 @@ package ldapauth import ( "time" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/sessions/ldapauth/ldap.go b/core/sessions/ldapauth/ldap.go index 188f2684e7..04f6fbfbbb 100644 --- a/core/sessions/ldapauth/ldap.go +++ b/core/sessions/ldapauth/ldap.go @@ -32,7 +32,7 @@ import ( "time" "github.com/go-ldap/ldap/v3" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" diff --git a/core/sessions/ldapauth/ldap_test.go b/core/sessions/ldapauth/ldap_test.go index 261141d66e..c85e0db831 100644 --- a/core/sessions/ldapauth/ldap_test.go +++ b/core/sessions/ldapauth/ldap_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" diff --git a/core/sessions/ldapauth/sync.go b/core/sessions/ldapauth/sync.go index ce7a338f40..67f101b62a 100644 --- a/core/sessions/ldapauth/sync.go +++ b/core/sessions/ldapauth/sync.go @@ -6,8 +6,8 @@ import ( "time" "github.com/go-ldap/ldap/v3" + "github.com/jmoiron/sqlx" "github.com/lib/pq" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/sessions/localauth/orm.go b/core/sessions/localauth/orm.go index d6fb8cd578..090dc468a6 100644 --- a/core/sessions/localauth/orm.go +++ b/core/sessions/localauth/orm.go @@ -6,8 +6,8 @@ import ( "strings" "time" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" diff --git a/core/sessions/localauth/orm_test.go b/core/sessions/localauth/orm_test.go index 7868937ad0..c2e155de28 100644 --- a/core/sessions/localauth/orm_test.go +++ b/core/sessions/localauth/orm_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/sessions/webauthn.go b/core/sessions/webauthn.go index 41e31d7aaa..89e7758bc5 100644 --- a/core/sessions/webauthn.go +++ b/core/sessions/webauthn.go @@ -9,8 +9,8 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" + sqlxTypes "github.com/jmoiron/sqlx/types" "github.com/pkg/errors" - sqlxTypes "github.com/smartcontractkit/sqlx/types" ) // WebAuthn holds the credentials for API user. diff --git a/core/sessions/webauthn_test.go b/core/sessions/webauthn_test.go index b3c1ecf789..9c055d9c79 100644 --- a/core/sessions/webauthn_test.go +++ b/core/sessions/webauthn_test.go @@ -7,7 +7,7 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" - sqlxTypes "github.com/smartcontractkit/sqlx/types" + sqlxTypes "github.com/jmoiron/sqlx/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/core/store/migrate/migrate.go b/core/store/migrate/migrate.go index 69cf9a7824..1e58d7a0b0 100644 --- a/core/store/migrate/migrate.go +++ b/core/store/migrate/migrate.go @@ -9,9 +9,9 @@ import ( "strconv" "strings" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" "github.com/pressly/goose/v3" - "github.com/smartcontractkit/sqlx" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/config/env" diff --git a/core/store/migrate/migrations/0036_external_job_id.go b/core/store/migrate/migrations/0036_external_job_id.go index 8637bd38f5..fc9ec08ec6 100644 --- a/core/store/migrate/migrations/0036_external_job_id.go +++ b/core/store/migrate/migrations/0036_external_job_id.go @@ -6,8 +6,8 @@ import ( "fmt" "github.com/google/uuid" + "github.com/jmoiron/sqlx" "github.com/pressly/goose/v3" - "github.com/smartcontractkit/sqlx" ) func init() { diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 0bd947bbce..2e3f3a8369 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -23,7 +23,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/sqlx" + "github.com/jmoiron/sqlx" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/go.mod b/go.mod index e6af9533dc..67896860e0 100644 --- a/go.mod +++ b/go.mod @@ -65,14 +65,13 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 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.20231101160906-7acebcc1b353 + 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-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 github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 - github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 @@ -238,7 +237,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/jmoiron/sqlx v1.3.5 github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect diff --git a/go.sum b/go.sum index 5c70c22a75..89e9aee85f 100644 --- a/go.sum +++ b/go.sum @@ -1463,8 +1463,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= +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-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= @@ -1481,8 +1481,6 @@ github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGuj github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 8fe63a46d2..c51bd3c4f6 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -12,6 +12,7 @@ require ( github.com/ethereum/go-ethereum v1.12.0 github.com/go-resty/resty/v2 v2.7.0 github.com/google/uuid v1.3.1 + github.com/jmoiron/sqlx v1.3.5 github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.9 github.com/manifoldco/promptui v0.9.0 @@ -26,7 +27,6 @@ require ( github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 - github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.3.0 github.com/spf13/cobra v1.6.1 @@ -259,7 +259,6 @@ require ( github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -387,7 +386,7 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect 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.20231101160906-7acebcc1b353 // 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-solana v1.0.3-0.20231023133638-72f4e799ab05 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index b8e8b205c8..4afa0de1d3 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2367,8 +2367,8 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353 h1:4iO3Ei1b/Lb0yprzclk93e1aQnYF92sIe+EJzMG87y4= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231101160906-7acebcc1b353/go.mod h1:hMhGr9ok3p4442keFtK6u6Ei9yWfG66fmDwsFi3aHcw= +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-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= @@ -2387,8 +2387,6 @@ github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGuj github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index aa488eb1be..ab7a221955 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -17,36 +17,36 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" geth_types "github.com/ethereum/go-ethereum/core/types" + "github.com/jmoiron/sqlx" "github.com/rs/zerolog" + "github.com/scylladb/go-reflectx" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctf_blockchain "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" "github.com/smartcontractkit/wasp" + evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + lpEvm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/store/models" - ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/stretchr/testify/require" - - "github.com/scylladb/go-reflectx" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" utils2 "github.com/smartcontractkit/chainlink/integration-tests/utils" - evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - lpEvm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" - core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/sqlx" ) var ( From c2a1b26ed24f50a30cac95bd25a8f517f3367c8c Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 9 Nov 2023 11:42:44 -0500 Subject: [PATCH 118/327] 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 61ebfab0e9..48e228eb83 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 c24dde595c..54262dd93f 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 a56590b6ef..1de1f78de8 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 bef9c30d9e..000bad2390 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 816a9234a3..82fd910a08 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 d542e98e6e..f4ad6a65a1 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 6db5d49575..c2d61e0070 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 3adcc130bc..5f881f354e 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 7f5d0e227d..1d455305a9 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 1b16dc76f9..0f8f56f46e 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 67896860e0..f35077e923 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 89e9aee85f..2c9d9e5371 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 c51bd3c4f6..83657baa01 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 4afa0de1d3..a873f9b7c1 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 91640016fe..0000000000 --- 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 119/327] 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 e742be2754..4e891535b7 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 0000000000..f0eec19db2 --- /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 adc6218733..bf43ead8d7 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 eb0d954ae0..2caab41c74 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 0000000000..5384a66d91 --- /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 7166add19f..f6d3d41e63 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 55ab3810b4..f2d7af54e4 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 0c08fd20cd..97418958bc 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 bc103fc356..c1b6d5d0b1 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 ffe072fc65..b2e5ec4b09 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 cff49cd07c..3543116d21 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 120/327] [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 698a9b49c9..d2326c4726 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 761d9cd255..6ea912d11d 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 121/327] 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 0000000000..d9f1670c07 --- /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 0000000000..b9cf0a5866 --- /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 0000000000..7c8eb69171 --- /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 0000000000..e7b8d9ecb8 --- /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 0000000000..bd704cd2c6 --- /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 0000000000..c378b9384e --- /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 0000000000..481b2602ea --- /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 0000000000..524d7d8a6c --- /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 f54e3115d9..c268cfb23c 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 0000000000..1fddbc3be3 --- /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 20d098e03f..f28a171a55 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 0000000000..87e9084669 --- /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 149c5f01a6..4193560e29 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 0000000000..564c08bbdc --- /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 0000000000..45604ebe8d --- /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 0000000000..6e47bbedca --- /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 0000000000..ac84645e91 --- /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 0000000000..e5078d858f --- /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 0000000000..226cb67168 --- /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 0000000000..4eecb859db --- /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 0000000000..0438e11e61 --- /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 0051fb014d..fa793a826a 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 0000000000..bfe5515365 --- /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 f3a6029a9e..0e52f1db72 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 0000000000..40560f7866 --- /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 122/327] [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 4e891535b7..af95b75df1 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 bf43ead8d7..bd13a3a5a1 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 82dea8672c..6e94e4fc5f 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 b2e5ec4b09..397ea3d18b 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 3543116d21..41524c3a82 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 123/327] 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 af95b75df1..d15666f885 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 bd13a3a5a1..e4b6fe7d90 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 2caab41c74..3ee4931e97 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 397ea3d18b..917107524b 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 41524c3a82..534e5543e8 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 124/327] 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 d15666f885..521b3bffac 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 3ee4931e97..15949a497e 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 dd9ea84a51..375159bf4c 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 917107524b..3e3fac16d1 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 534e5543e8..93c4e64a3a 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 From 75d0743eae6f419756f5de12ddd922a711809c35 Mon Sep 17 00:00:00 2001 From: Cedric Date: Fri, 10 Nov 2023 11:07:07 +0000 Subject: [PATCH 125/327] Add medianpoc to plugins dockerfile (#11247) --- GNUmakefile | 4 ++++ plugins/chainlink.Dockerfile | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/GNUmakefile b/GNUmakefile index 32f74e285e..69d82da6c8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -61,6 +61,10 @@ chainlink-local-start: install-median: ## Build & install the chainlink-median binary. go install $(GOFLAGS) ./plugins/cmd/chainlink-median +.PHONY: install-medianpoc +install-medianpoc: ## Build & install the chainlink-medianpoc binary. + go install $(GOFLAGS) ./plugins/cmd/chainlink-medianpoc + .PHONY: docker ## Build the chainlink docker image docker: docker buildx build \ diff --git a/plugins/chainlink.Dockerfile b/plugins/chainlink.Dockerfile index 001ee30bf7..f07fab4812 100644 --- a/plugins/chainlink.Dockerfile +++ b/plugins/chainlink.Dockerfile @@ -19,6 +19,9 @@ RUN make install-chainlink # Build LOOP Plugins RUN make install-median +# Install medianpoc binary +RUN make install-medianpoc + RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana | xargs -I % ln -s % /chainlink-solana RUN mkdir /chainlink-starknet RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-starknet/relayer | xargs -I % ln -s % /chainlink-starknet/relayer @@ -49,6 +52,7 @@ RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && apt-get clean all COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ +COPY --from=buildgo /go/bin/chainlink-medianpoc /usr/local/bin/ COPY --from=buildgo /go/bin/chainlink-median /usr/local/bin/ ENV CL_MEDIAN_CMD chainlink-median From 0918b37d4e27c465a2e360167ad6e1ca594fe6e5 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Fri, 10 Nov 2023 15:52:08 +0100 Subject: [PATCH 126/327] solidity style guide 2.0 (#10995) * solidity style guide 2.0 * split into rules and guidelines * improve layout --- contracts/STYLE.md | 234 ----------------------- contracts/STYLE_GUIDE.md | 391 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 391 insertions(+), 234 deletions(-) delete mode 100644 contracts/STYLE.md create mode 100644 contracts/STYLE_GUIDE.md diff --git a/contracts/STYLE.md b/contracts/STYLE.md deleted file mode 100644 index d9692a6521..0000000000 --- a/contracts/STYLE.md +++ /dev/null @@ -1,234 +0,0 @@ -# Solidity Style Guide - -## Background - -Our starting point is the [official Solidity Style Guide](https://solidity.readthedocs.io/en/v0.8.0/style-guide.html) and [ConsenSys's Secure Development practices](https://consensys.github.io/smart-contract-best-practices/), but we deviate in some ways. We lean heavily on [Prettier](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/.prettierrc) for formatting, and if you have to set up a new Solidity project we recommend starting with [our prettier config](https://github.com/smartcontractkit/chainlink/blob/develop/.prettierrc.js). We are trying to automate as much of this styleguide with Solhint as possible. - -### Code Organization - -- Group functionality together. E.g. Declare structs, events, and helper functions near the functions that use them. This is helpful when reading code because the related pieces are localized. It is also consistent with inheritance and libraries, which are separate pieces of code designed for a specific goal. - - Why not follow the Solidity recommendation of grouping by visibility? Visibility is clearly defined next to the method signature, making it trivial to check. However, searching can be deceiving because of inherited methods. Given this inconsistency in grouping, we find it easier to read and more consistent to organize code around functionality. Additionally, we recommend testing the public interface for any Solidity contract to ensure it only exposes expected methods. - -### Delineate Unaudited Code - -- In a large repo it is worthwhile to keep code that has not yet been audited separate from the code that has been audited. This allows you to easily keep track of which files need to be reviewed. - - E.g. we keep unaudited code in a directory named `dev`. Only once it has been audited we move the audited files out of `dev` and only then is it considered safe to deploy. - -## Variables - -### Visibility - -- All contract variables should be private. Getters should be explicitly written and documented when you want to expose a variable publicly. Whether a getter function reads from storage, a constant, or calculates a value from somewhere else, that’s all implementation details that should not be exposed to the consumer by casing or other conventions. - -Examples: - -Good: - -```javascript -uint256 private s_myVar; - -function getMyVar() external view returns(uint256){ - return s_myVar; -} -``` - -Bad: - -```javascript -uint256 public s_myVar; -``` - -### Naming and Casing - -- Function arguments are named like this: `argumentName`. No leading or trailing underscores necessary. -- Storage variables prefixed with an `s_` to make it clear that they live in storage and are expensive to read and write: `s_variableName`. They should always be private, and you should write explicit getters if you want to expose a storage variable. -- Immutable variables should be prefixed with an `i_` to make it clear that they are immutable. E.g. `i_decimalPlaces`. They should always be private, and you should write explicit getters if you want to expose an immutable variable. -- Internal/private constants should be all caps with underscores: `FOO_BAR`. Like other contract variables, constants should not be public. Create getter methods if you want to publicly expose constants. -- Explicitly declare variable size: `uint256` not just `uint`. In addition to being explicit, it matches the naming used to calculate function selectors. - -Examples: - -Good: - -```javascript -uint256 private s_myVar; -uint256 private immutable i_myImmutVar; -uint256 private constant MY_CONST_VAR; - -function multiplyMyVar(uint256 multiplier) external view returns(uint256){ - return multiplier * s_myVar; -} -``` - -Bad: - -```javascript -uint private s_myVar; -uint256 private immutable myImmutVar; -uint256 private constant s_myConstVar; - -function multiplyMyVar_(uint _multiplier) external view returns(uint256){ - return _mutliplier * s_myVar; -} -``` - -### Types - -- If you are storing an address and know/expect it to be of a type(or interface), make the variable that type. This more clearly documents the behavior of this variable than the `address` type and often leads to less casting code whenever the address is used. - -Examples: - -Good: - -```javascript -import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; -// . -// . -// . -AggregatorV3Interface private s_priceFeed; - -constructor(address priceFeed) { - s_priceFeed = AggregatorV3Interface(priceFeed); -} -``` - -Bad: - -```javascript -import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; -// . -// . -// . -address private s_priceFeed; - -constructor(address priceFeed) { - s_priceFeed = priceFeed; -} -``` - -## Functions - -### Visibility - -- Method visibility should always be explicitly declared. Contract’s [public interfaces should be tested](https://github.com/smartcontractkit/chainlink/blob/master/contracts/test/test-helpers/helpers.ts#L221) to enforce this and make sure that internal logic is not accidentally exposed. - -### Naming - -- Function names should start with imperative verbs, not nouns or other tenses. - - `requestData` not `dataRequest` - - `approve` not `approved` -- Prefix private and internal methods with an underscore. There should never be a publicly callable method starting with an underscore. - - E.g. `_setOwner(address)` -- Prefix your public getters with `get` and your public setters with `set`. - - `getConfig` and `setConfig`. - -## Modifiers - -- Only extract a modifier once a check is duplicated in multiple places. Modifiers arguably hurt readability, so we have found that they are not worth extracting until there is duplication. -- Modifiers should be treated as if they are view functions. They should not change state, only read it. While it is possible to change state in a modifier, it is unconventional and surprising. - -### Naming - -There are two common classes of modifiers, and their name should be prefixed accordingly to quickly represent their behavior: - -- Control flow modifiers: Prefix the modifier name with `if` in the case that a modifier only enables or disables the subsequent code in the modified method, but does not revert. -- Reverting modifiers: Prefix the modifier name with `validate` in the case that a modifier reverts if a condition is not met. - -### Return Values - -- If an address is cast as a contract type, return the type, do not cast back to the address type. This prevents the consumer of the method signature from having to cast again, but presents an equivalent API for off-chain APIs. Additionally it is a more declarative API, providing more context if we return a type. - -## Events - -- Events should only be triggered on state changes. If the value is set but not changed, we prefer avoiding a log emission indicating a change. (e.g. Either do not emit a log, or name the event `ConfigSet` instead of `ConfigUpdated`.) - -### Naming - -- When possible event names should correspond to the method they are in or the action that is being taken. Events preferably follow the format , where the action performed is the past tense of the imperative verb in the method name. e.g. calling `setConfig` should emit an event called `ConfigSet`, not `ConfigUpdated` in a method named `setConfig`. - -## Errors - -### Use Custom Errors - -Whenever possible (Solidity v0.8+) use [custom errors](https://blog.soliditylang.org/2021/04/21/custom-errors/) instead of emitting strings. This saves contract code size and simultaneously provides more informative error messages. - -### Expose Errors - -It is common to call a contract and then check the call succeeded: - -```javascript -(bool success, ) = to.call(data); -require(success, "Contract call failed"); -``` - -While this may look descriptive it swallows the error. Instead bubble up the error: - -```javascript -error YourError(bytes response); - -(bool success, bytes memory response) = to.call(data); -if (!success) { revert YourError(response); } -``` - -This will cost slightly more gas to copy the response into memory, but will ultimately make contract usage more understandable and easier to debug. Whether it is worth the extra gas is a judgement call you’ll have to make based on your needs. - -The original error will not be human readable in an off-chain explorer because it is RLP hex encoded but is easily decoded with standard Solidity ABI decoding tools, or a hex to UTF-8 converter and some basic ABI knowledge. - -## Control Flow - -### `if` Statements - -Always wrap the result statement of your `if` conditions in a closure, even if it is only one line. - -Bad: - -```javascript - if (condition) statement; -``` - -Good: - -```javascript - if (condition) { statement; } -``` - -## Interfaces - -### Scope - -- Interfaces should be as concise as reasonably possible. Break it up into smaller composable interfaces when that is sensible. - -### Naming - -- Up through Solidity version 0.8: Interfaces should be named `FooInterface`, this follows our historical naming pattern. -- Starting in Solidity v0.9: Interfaces should be named `IFoo` instead of `FooInterface`. This follows the patterns of popular [libraries like OpenZeppelin’s](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L9). - -## Vendor Dependencies - -- That’s it, vendor your Solidity dependencies. Supply chain attacks are all the rage these days. There is not yet a silver bullet for best way to vendor, it depends on the size of your project and your needs. You should be as explicit as possible about where the code comes from and make sure that this is enforced in some way; e.g. reference a hash. Some options: - - NPM packages work for repos already in the JavaScript ecosystem. If you go this route you should lock to a hash of the repo or use a proxy registry like GitHub Packages. - - Git submodules are great if you don’t mind git submodules. - - Copy and paste the code into a `vendor` directory. Record attribution of the code and license in the repo along with the commit or version that you pulled the code from. - -## Common Behaviors - -### Transferring Ownership - -- When transferring control, whether it is of a token or a role in a contract, prefer "safe ownership" transfer patterns where the recipient must accept ownership. This avoids accidentally burning the control. This is also inline with the secure pattern of [prefer pull over push](https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls). - -### Use Factories - -- If you expect multiple instances of a contract to be deployed, it is probably best to [build a factory](https://www.quicknode.com/guides/solidity/how-to-create-a-smart-contract-factory-in-solidity-using-hardhat) as this allows for simpler deployments later. Additionally it reduces the burden of verifying the correctness of the contract deployment. If many people have to deploy an instance of a contract then doing so with a contract makes it much easier for verification because instead of checking the code hash and/or the compiler and maybe the source code, you only have to check that the contract was deployed through a factory. -- Factories can add some pain when deploying with immutable variables. In general it is difficult to parse those out immutable variables from internal transactions. There is nothing inherently wrong with contracts deployed in this manner but at the time of writing they may not easily verify on Etherscan. - -### Call with Exact Gas - -- `call` accepts a gas parameter, but that parameter is a ceiling on gas usage. If a transaction does not have enough gas, `call` will simply provide as much gas as it safely can. This is unintuitive and can lead to transactions failing for unexpected reasons. We have [an implementation of `callWithExactGas`](https://github.com/smartcontractkit/chainlink/blob/075f3e2caf61b8685d2dc78714f1ee39764fda17/contracts/src/v0.8/KeeperRegistry.sol#L792) to ensure the precise gas amount requested is provided. - -## Picking a Pragma - -- If a contract or library is expected to be imported by outside parties then the pragma should be kept as loose as possible without sacrificing safety. We publish versions for every minor semver version of Solidity, and maintain a corresponding set of tests for each published version. - - Examples: libraries, interfaces, abstract contracts, and contracts expected to be inherited from -- Otherwise, Solidity contracts should have a pragma which is locked to a specific version. - - Example: Most concrete contracts. -- Avoid changing pragmas after audit. Unless there is a bug that has affects your contract, then you should try to stick to a known good pragma. In practice this means we typically only support one (occasionally two) pragma for any “major”(minor by semver naming) Solidity version. diff --git a/contracts/STYLE_GUIDE.md b/contracts/STYLE_GUIDE.md new file mode 100644 index 0000000000..3868117d4b --- /dev/null +++ b/contracts/STYLE_GUIDE.md @@ -0,0 +1,391 @@ +# Structure + +This guide is split into two sections: [Guidelines](#guidelines) and [Rules](#rules). +Guidelines are recommendations that should be followed but are hard to enforce in an automated way. +Rules are all enforced through CI, this can be through Solhint rules or other tools. + +## Background + +Our starting point is the [official Solidity Style Guide](https://docs.soliditylang.org/en/v0.8.21/style-guide.html) and [ConsenSys's Secure Development practices](https://consensys.github.io/smart-contract-best-practices/), but we deviate in some ways. We lean heavily on [Prettier](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/.prettierrc) for formatting, and if you have to set up a new Solidity project we recommend starting with [our prettier config](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/.prettierrc). We are trying to automate as much of this styleguide with Solhint as possible. + +This guide is not meant to be applied retroactively. There is no need to rewrite existing code to adhere to this guide, and when making (small) changes in existing files, it is not required to do so in accordance to this guide if it would conflict with other practices in that existing file. Consistency is preferred. + +We will be looking into `forge fmt`, but for now we still use `prettier`. + + +# Guidelines + +## Code Organization +- Group functionality together. E.g. Declare structs, events, and helper functions near the functions that use them. This is helpful when reading code because the related pieces are localized. It is also consistent with inheritance and libraries, which are separate pieces of code designed for a specific goal. +- 🤔Why not follow the Solidity recommendation of grouping by visibility? Visibility is clearly defined next to the method signature, making it trivial to check. However, searching can be deceiving because of inherited methods. Given this inconsistency in grouping, we find it easier to read and more consistent to organize code around functionality. Additionally, we recommend testing the public interface for any Solidity contract to ensure it only exposes expected methods. +- Follow the [Solidity folder structure CLIP](https://github.com/smartcontractkit/CLIPs/tree/main/clips/2023-04-13-solidity-folder-structure) + +### Delineate Unaudited Code + +- In a large repo it is worthwhile to keep code that has not yet been audited separate from the code that has been audited. This allows you to easily keep track of which files need to be reviewed. + - E.g. we keep unaudited code in a directory named `dev` that exists within each projects folder. Only once it has been audited we move the audited files out of `dev` and only then is it considered safe to deploy. + - This `dev` folder also has implications for when code is valid for bug bounties, so be extra careful to move functionality out of a `dev` folder. + + +## comments +- Besides comment above functions/structs, comments should live everywhere a reader might be confused. + Don’t overestimate the reader of your contract, expect confusion in many places and document accordingly. + This will help massively during audits and onboarding new team members. +- Headers should be used to group functionality, the following header style and length is recommended. + - Don’t use headers for a single function, or to say “getters”. Group by functionality e.g. the `Tokens and pools` , or `fees` logic within the CCIP OnRamp. + +```solidity + // ================================================================ + // │ Tokens and pools │ + // ================================================================ + +.... + + // ================================================================ + // │ Fees │ + // ================================================================ +``` + +## Variables + +- Function arguments are named like this: `argumentName`. No leading or trailing underscores necessary. +- Names should be explicit on the unit it contains, e.g. a network fee that is charged in USD cents + +```solidity +uint256 fee; // bad +uint256 networkFee; // bad +uint256 networkFeeUSD; // bad +uint256 networkFeeUSDCents; // good +``` + +### Types + +- If you are storing an address and know/expect it to be of a type(or interface), make the variable that type. This more clearly documents the behavior of this variable than the `address` type and often leads to less casting code whenever the address is used. + +### Structs + +- All structs should be packed to have the lowest memory footprint to reduce gas usage. Even structs that will never be written to storage should be packed. + - A contract can be considered a struct; it should also be packed to reduce gas cost. +- Structs should contain struct packing comments to clearly indicate the storage slot layout + - Using the exact characters from the example below will ensure visually appealing struct packing comments. + - Notice there is no line on the unpacked last `fee` item. +- Struct should contain comments, clearly indicating the denomination of values e.g. 0.01 USD if the variable name doesn’t already do that (which it should). + - Simple tool that could help packing structs and adding comments: https://github.com/RensR/Spack + +```solidity +/// @dev Struct to hold the fee configuration for a fee token, same as the FeeTokenConfig but with +/// token included so that an array of these can be passed in to setFeeTokenConfig to set the mapping +struct FeeTokenConfigArgs { + address token; // ────────────╮ Token address + uint32 networkFeeUSD; // │ Flat network fee to charge for messages, multiples of 0.01 USD + // │ multiline comments should work like this. More fee info + uint64 gasMultiplier; // ─────╯ Price multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost + uint64 premiumMultiplier; // ─╮ Multiplier for fee-token-specific premiums + bool enabled; // ─────────────╯ Whether this fee token is enabled + uint256 fee; // The flat fee the user pays in juels +} +``` +## Functions + +### Naming + +- Function names should start with imperative verbs, not nouns or other tenses. + - `requestData` not `dataRequest` + - `approve` not `approved` + - `getFeeParameters` not `feeParameters` + +- Prefix your public getters with `get` and your public setters with `set`. + - `getConfig` and `setConfig`. + +### Return Values + +- If an address is cast as a contract type, return the type, do not cast back to the address type. + This prevents the consumer of the method signature from having to cast again, but presents an equivalent API for off-chain APIs. + Additionally, it is a more declarative API, providing more context if we return a type. + +## Modifiers + +- Only extract a modifier once a check is duplicated in multiple places. Modifiers arguably hurt readability, so we have found that they are not worth extracting until there is duplication. +- Modifiers should be treated as if they are view functions. They should not change state, only read it. While it is possible to change state in a modifier, it is unconventional and surprising. +- Modifiers tend to bloat contract size because the code is duplicated wherever the modifier is used. + +## Events + +- Events should only be triggered on state changes. If the value is set but not changed, we prefer avoiding a log emission indicating a change. (e.g. Either do not emit a log, or name the event `ConfigSet` instead of `ConfigUpdated`.) +- Events should be emitted for all state changes, not emitting should be an exception +- When possible event names should correspond to the method they are in or the action that is being taken. Events preferably follow the format , where the action performed is the past tense of the imperative verb in the method name. e.g. calling `setConfig` should emit an event called `ConfigSet`, not `ConfigUpdated` in a method named `setConfig`. + + +### Expose Errors + +It is common to call a contract and then check the call succeeded: + +```solidity +(bool success, ) = to.call(data); +require(success, "Contract call failed"); +``` + +While this may look descriptive it swallows the error. Instead, bubble up the error: + +```solidity +bool success; +retData = new bytes(maxReturnBytes); +assembly { + // call and return whether we succeeded. ignore return data + // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) + success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0, 0) + + // limit our copy to maxReturnBytes bytes + let toCopy := returndatasize() + if gt(toCopy, maxReturnBytes) { + toCopy := maxReturnBytes + } + // Store the length of the copied bytes + mstore(retData, toCopy) + // copy the bytes from retData[0:_toCopy] + returndatacopy(add(retData, 0x20), 0, toCopy) +} +return (success, retData); +``` + +This will cost slightly more gas to copy the response into memory, but will ultimately make contract usage more understandable and easier to debug. Whether it is worth the extra gas is a judgement call you’ll have to make based on your needs. + +The original error will not be human-readable in an off-chain explorer because it is RLP hex encoded but is easily decoded with standard Solidity ABI decoding tools, or a hex to UTF-8 converter and some basic ABI knowledge. + + +## Interfaces + +- Interfaces should be as concise as reasonably possible. Break it up into smaller composable interfaces when that is sensible. + +## Dependencies + +- Prefer not reinventing the wheel, especially if there is an Openzeppelin wheel. +- The `shared` folder can be treated as a first party dependency and it is recommend to check if some functionality might already be in there before either writing it yourself or adding a third party dependency. +- When we have reinvented the wheel already (like with ownership), it is OK to keep using these contracts. If there are clear benefits of using another standard like OZ, we can deprecate the custom implementation and start using the new standard in all new projects. Migration will not be required unless there are serious issues with the old implementation. +- When the decision is made to use a new standard, it is no longer allowed to use the old standard for new projects. + +### Vendor dependencies + +- That’s it, vendor your Solidity dependencies. Supply chain attacks are all the rage these days. There is not yet a silver bullet for best way to vendor, it depends on the size of your project and your needs. You should be as explicit as possible about where the code comes from and make sure that this is enforced in some way; e.g. reference a hash. Some options: + - NPM packages work for repos already in the JavaScript ecosystem. If you go this route you should lock to a hash of the repo or use a proxy registry like GitHub Packages. + - Copy and paste the code into a `vendor` directory. Record attribution of the code and license in the repo along with the commit or version that you pulled the code from. + - Foundry uses git submodules for its dependencies. We only use the `forge-std` lib through submodules, we don’t import any non-Foundry-testing code through this method. + + +## Common Behaviors + +### Transferring Ownership + +- When transferring control, whether it is of a token or a role in a contract, prefer "safe ownership" transfer patterns where the recipient must accept ownership. This avoids accidentally burning the control. This is also inline with the secure pattern of [prefer pull over push](https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls). + +### Call with Exact Gas + +- `call` accepts a gas parameter, but that parameter is a ceiling on gas usage. If a transaction does not have enough gas, `call` will simply provide as much gas as it safely can. This is unintuitive and can lead to transactions failing for unexpected reasons. We have [an implementation of `callWithExactGas`](https://github.com/smartcontractkit/chainlink/blob/075f3e2caf61b8685d2dc78714f1ee39764fda17/contracts/src/v0.8/KeeperRegistry.sol#L792) to ensure the precise gas amount requested is provided. + +### Sending tokens + +- Prefer [ERC20.safeTransfer](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#SafeERC20) over ERC20.transfer + +### Gas golfing + +- Golf your code. Make it cheap, within reason. + - Focus on the hot path +- Most of the cost of executing Solidity is related to reading/writing storage +- Calling other contracts will also be costly +- Common types to safely use are + - uint40 for timestamps (or uint32 if you really need the space) + - uint96 for link, as there are only 1b link tokens +- prefer `++i` over `i++` +- If you’re unsure about golfing, ask in the #tech-solidity channel + +## Testing + +- Test using Foundry. +- Aim for at least 90% *useful* coverage as a baseline, but (near) 100% is achievable in Solidity. Always 100% test the critical path. + - Make sure to test for each event emitted + - Test each reverting path +- Consider fuzzing, start with stateless (very easy in Foundry) and if that works, try stateful fuzzing. +- Consider fork testing if applicable + +### Foundry + +- Create a Foundry profile for each project folder in `foundry.toml` +- Foundry tests live in the project folder in `src`, not in the `contracts/test/` folder +- Set the block number and timestamp. It is preferred to set these values to some reasonable value close to reality. +- There should be no code between `vm.expectEmit`/`vm.expectRevert` and the function call + +## Picking a Pragma + +- If a contract or library is expected to be imported by outside parties then the pragma should be kept as loose as possible without sacrificing safety. We publish versions for every minor semver version of Solidity, and maintain a corresponding set of tests for each published version. + - Examples: libraries, interfaces, abstract contracts, and contracts expected to be inherited from +- Otherwise, Solidity contracts should have a pragma which is locked to a specific version. + - Example: Most concrete contracts. +- Avoid changing pragmas after audit. Unless there is a bug that has affects your contract, then you should try to stick to a known good pragma. In practice this means we typically only support one (occasionally two) pragma for any “major”(minor by semver naming) Solidity version. +- The current advised pragma is `0.8.19` or higher, lower versions should be avoided when starting a new project. Newer versions can be considered. +- All contracts should have a SPDX license identifier. If unsure about which one to pick, please consult with legal. Most older contracts have been MIT, but some of the newer products have been using BUSL-1.1 + + +## Versioning + +Contracts should implement the following interface + +```solidity +interface ITypeAndVersion { + function typeAndVersion() external pure returns (string memory); +} +``` + +Here are some examples of what this should look like: + +```solidity +contract AccessControlledFoo is Foo { + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "AccessControlledFoo 1.0.0"; +} + +contract OffchainAggregator is ITypeAndVersion { + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "OffchainAggregator 1.0.0"; + + function getData() public returns(uint256) { + return 4; + } +} + +// Next version of Aggregator contract +contract SuperDuperAggregator is ITypeAndVersion { + /// This is a new contract that has not been released yet, so we + /// add a `-dev` suffix to the typeAndVersion. + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "SuperDuperAggregator 1.1.0-dev"; + + function getData() public returns(uint256) { + return 5; + } +} +``` + +All contracts will expose a `typeAndVersion` constant. +The string has the following format: `-` with the `-dev` part only being applicable to contracts that have not been fully released. +Try to fit it into 32 bytes to keep impact on contract sizes minimal. +Solhint will complain about a public constant variable that isn’t FULL_CAPS without the solhint-disable comment. + + + + + + + + + + +# Rules + +All rules have a `rule` tag which indicated how the rule is enforced. + + +## Comments + +- Comments should be in the `//` (default) or `///` (natspec) format, not the `/* */` format. + - rule: `tbd` +- Comments should follow [NatSpec](https://docs.soliditylang.org/en/latest/natspec-format.html) + - rule: `tbd` + +## Imports + +- Imports should always be explicit + - rule: `no-global-import` +- Imports have follow the following format: + - rule: `tbd` + +```solidity +import {IInterface} from "../interfaces/IInterface.sol"; + +import {AnythingElse} from "../code/AnythingElse.sol"; + +import {ThirdPartyCode} from "../../vendor/ThirdPartyCode.sol"; +``` + +- An example would be + +```solidity +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; +import {IPool} from "../interfaces/pools/IPool.sol"; + +import {AggregateRateLimiter} from "../AggregateRateLimiter.sol"; +import {Client} from "../libraries/Client.sol"; + +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +``` + +## Variables + +### Visibility + +All contract variables should be private by default. Getters should be explicitly written and documented when you want to expose a variable publicly. +Whether a getter function reads from storage, a constant, or calculates a value from somewhere else, that’s all implementation details that should not be exposed to the consumer by casing or other conventions. + +rule: tbd + +### Naming and Casing + +- Storage variables prefixed with an `s_` to make it clear that they live in storage and are expensive to read and write: `s_variableName`. They should always be private, and you should write explicit getters if you want to expose a storage variable. + - rule: `chainlink-solidity/prefix-storage-variables-with-s-underscore` +- Immutable variables should be prefixed with an `i_` to make it clear that they are immutable. E.g. `i_decimalPlaces`. They should always be private, and you should write explicit getters if you want to expose an immutable variable. + - rule: `chainlink-solidity/prefix-immutable-variables-with-i` +- Internal/private constants should be all caps with underscores: `FOO_BAR`. Like other contract variables, constants should not be public. Create getter methods if you want to publicly expose constants. + - rule: `chainlink-solidity/all-caps-constant-storage-variables` +- Explicitly declare variable size: `uint256` not just `uint`. In addition to being explicit, it matches the naming used to calculate function selectors. + - rule: `explicit-types` +- Mapping should always be named if Solidity allows it (≥0.8.18) + - rule: `tbd` + + +## Functions + +### Visibility + +- Method visibility should always be explicitly declared. + - rule: `state-visibility` + +- Prefix private and internal methods with an underscore. There should never be a publicly callable method starting with an underscore. + - E.g. `_setOwner(address)` + - rule: `chainlink-solidity/prefix-internal-functions-with-underscore` + +### Return values + +- Returned values should always be explicit. Using named return values and then returning with an empty return should be avoided + - rule: `chainlink-solidity/explicit-returns` + +```solidity +// Bad +function getNum() external view returns (uint64 num) { + num = 4; + return; +} + +// Good +function getNum() external view returns (uint64 num) { + num = 4; + return num; +} + +// Good +function getNum() external view returns (uint64 num) { + return 4; +} +``` + +## Errors + +Use [custom errors](https://blog.soliditylang.org/2021/04/21/custom-errors/) instead of emitting strings. This saves contract code size and simultaneously provides more informative error messages. + +rule: `custom-errors` + +## Interfaces + +Interfaces should be named `IFoo` instead of `FooInterface`. This follows the patterns of popular [libraries like OpenZeppelin’s](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L9). + +rule: `tbd` \ No newline at end of file From 41025f45fcf3c5e7135d03f0e77dfb66ee770163 Mon Sep 17 00:00:00 2001 From: Tate Date: Fri, 10 Nov 2023 08:37:12 -0700 Subject: [PATCH 127/327] [TT-689] Send slack notification on test base image build/publish failure (#11248) --- .github/workflows/integration-tests-publish.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index 60f67f0357..a66ea61228 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -37,3 +37,11 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + - name: Notify Slack + if: failure() + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + with: + channel-id: "#team-test-tooling-internal" + slack-message: ":x: :mild-panic-intensifies: Publish Integration Test Image failed: ${{ job.html_url }}\n${{ format('https://github.com/smartcontractkit/chainlink/actions/runs/{0}', github.run_id) }}" From 4a6f2fe749e19d92be013b9b8f59cefe829b07eb Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Fri, 10 Nov 2023 19:52:39 +0100 Subject: [PATCH 128/327] turn off 0.6 & 0.7 tests (#11132) * turn off 0.6 tests * reduce splits and mark other tests as sow * add modification protection * rm 0.7 tests --- .github/workflows/solidity.yml | 18 + contracts/ci.json | 22 +- contracts/test/v0.6/AggregatorFacade.test.ts | 167 - contracts/test/v0.6/BasicConsumer.test.ts | 243 -- contracts/test/v0.6/BlockhashStore.test.ts | 285 -- contracts/test/v0.6/Chainlink.test.ts | 186 - contracts/test/v0.6/ChainlinkClient.test.ts | 376 -- contracts/test/v0.6/CheckedMath.test.ts | 183 - .../v0.6/DeviationFlaggingValidator.test.ts | 296 -- contracts/test/v0.6/Flags.test.ts | 405 -- contracts/test/v0.6/FluxAggregator.test.ts | 3252 -------------- contracts/test/v0.6/Median.test.ts | 237 - contracts/test/v0.6/Owned.test.ts | 84 - contracts/test/v0.6/SignedSafeMath.test.ts | 187 - .../v0.6/SimpleReadAccessController.test.ts | 250 -- .../v0.6/SimpleWriteAccessController.test.ts | 214 - contracts/test/v0.6/VRFD20.test.ts | 303 -- contracts/test/v0.7/AggregatorProxy.test.ts | 743 ---- .../test/v0.7/AuthorizedForwarder.test.ts | 444 -- contracts/test/v0.7/Chainlink.test.ts | 186 - contracts/test/v0.7/ChainlinkClient.test.ts | 454 -- .../CompoundPriceFlaggingValidator.test.ts | 471 -- contracts/test/v0.7/ConfirmedOwner.test.ts | 136 - contracts/test/v0.7/KeeperRegistry1_1.test.ts | 1725 -------- contracts/test/v0.7/Operator.test.ts | 3819 ----------------- contracts/test/v0.7/OperatorFactory.test.ts | 293 -- .../v0.7/StalenessFlaggingValidator.test.ts | 632 --- .../v0.7/UpkeepRegistrationRequests.test.ts | 603 --- contracts/test/v0.7/VRFD20.test.ts | 303 -- contracts/test/v0.7/gasUsage.test.ts | 178 - 30 files changed, 27 insertions(+), 16668 deletions(-) delete mode 100644 contracts/test/v0.6/AggregatorFacade.test.ts delete mode 100644 contracts/test/v0.6/BasicConsumer.test.ts delete mode 100644 contracts/test/v0.6/BlockhashStore.test.ts delete mode 100644 contracts/test/v0.6/Chainlink.test.ts delete mode 100644 contracts/test/v0.6/ChainlinkClient.test.ts delete mode 100644 contracts/test/v0.6/CheckedMath.test.ts delete mode 100644 contracts/test/v0.6/DeviationFlaggingValidator.test.ts delete mode 100644 contracts/test/v0.6/Flags.test.ts delete mode 100644 contracts/test/v0.6/FluxAggregator.test.ts delete mode 100644 contracts/test/v0.6/Median.test.ts delete mode 100644 contracts/test/v0.6/Owned.test.ts delete mode 100644 contracts/test/v0.6/SignedSafeMath.test.ts delete mode 100644 contracts/test/v0.6/SimpleReadAccessController.test.ts delete mode 100644 contracts/test/v0.6/SimpleWriteAccessController.test.ts delete mode 100644 contracts/test/v0.6/VRFD20.test.ts delete mode 100644 contracts/test/v0.7/AggregatorProxy.test.ts delete mode 100644 contracts/test/v0.7/AuthorizedForwarder.test.ts delete mode 100644 contracts/test/v0.7/Chainlink.test.ts delete mode 100644 contracts/test/v0.7/ChainlinkClient.test.ts delete mode 100644 contracts/test/v0.7/CompoundPriceFlaggingValidator.test.ts delete mode 100644 contracts/test/v0.7/ConfirmedOwner.test.ts delete mode 100644 contracts/test/v0.7/KeeperRegistry1_1.test.ts delete mode 100644 contracts/test/v0.7/Operator.test.ts delete mode 100644 contracts/test/v0.7/OperatorFactory.test.ts delete mode 100644 contracts/test/v0.7/StalenessFlaggingValidator.test.ts delete mode 100644 contracts/test/v0.7/UpkeepRegistrationRequests.test.ts delete mode 100644 contracts/test/v0.7/VRFD20.test.ts delete mode 100644 contracts/test/v0.7/gasUsage.test.ts diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index 069d9de45a..5699657fa5 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -20,11 +20,29 @@ jobs: - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 id: changes with: + list-files: "csv" filters: | src: - 'contracts/**/*' - '.github/workflows/solidity.yml' - '.github/workflows/solidity-foundry.yml' + old_sol: + - 'contracts/src/v0.4/**/*' + - 'contracts/src/v0.5/**/*' + - 'contracts/src/v0.6/**/*' + - 'contracts/src/v0.7/**/*' + + + - name: Fail if read-only files have changed + if: ${{ steps.changes.outputs.old_sol == 'true' }} + run: | + echo "One or more read-only Solidity file(s) has changed." + for file in ${{ steps.changes.outputs.old_sol_files }}; do + echo "$file was changed" + done + exit 1 + + prepublish-test: needs: [changes] diff --git a/contracts/ci.json b/contracts/ci.json index dd1fbb0a88..f1eff76513 100644 --- a/contracts/ci.json +++ b/contracts/ci.json @@ -6,23 +6,19 @@ "dir": "cross-version", "numOfSplits": 1 }, - { - "dir": "v0.6", - "numOfSplits": 1 - }, - { - "dir": "v0.7", - "numOfSplits": 1 - }, { "dir": "v0.8", - "numOfSplits": 8, + "numOfSplits": 6, "slowTests": [ - "Keeper", - "Cron.test", - "CronUpkeep.test", + "Cron", + "CronUpkeep", + "VRFSubscriptionBalanceMonitor", "EthBalanceMonitor", - "CanaryUpkeep" + "KeeperRegistrar", + "KeeperRegistry1_2", + "KeeperRegistry1_3", + "KeeperRegistry2_0", + "KeeperRegistry2_1" ] } ] diff --git a/contracts/test/v0.6/AggregatorFacade.test.ts b/contracts/test/v0.6/AggregatorFacade.test.ts deleted file mode 100644 index f85c24ae6c..0000000000 --- a/contracts/test/v0.6/AggregatorFacade.test.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { ethers } from 'hardhat' -import { numToBytes32, publicAbi } from '../test-helpers/helpers' -import { assert } from 'chai' -import { Contract, ContractFactory, Signer } from 'ethers' -import { getUsers } from '../test-helpers/setup' -import { convertFufillParams, decodeRunRequest } from '../test-helpers/oracle' -import { bigNumEquals, evmRevert } from '../test-helpers/matchers' - -let defaultAccount: Signer - -let linkTokenFactory: ContractFactory -let aggregatorFactory: ContractFactory -let oracleFactory: ContractFactory -let aggregatorFacadeFactory: ContractFactory - -before(async () => { - const users = await getUsers() - - defaultAccount = users.roles.defaultAccount - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - defaultAccount, - ) - aggregatorFactory = await ethers.getContractFactory( - 'src/v0.4/Aggregator.sol:Aggregator', - defaultAccount, - ) - oracleFactory = await ethers.getContractFactory( - 'src/v0.6/Oracle.sol:Oracle', - defaultAccount, - ) - aggregatorFacadeFactory = await ethers.getContractFactory( - 'src/v0.6/AggregatorFacade.sol:AggregatorFacade', - defaultAccount, - ) -}) - -describe('AggregatorFacade', () => { - const jobId1 = - '0x4c7b7ffb66b344fbaa64995af81e355a00000000000000000000000000000001' - const previousResponse = numToBytes32(54321) - const response = numToBytes32(67890) - const decimals = 18 - const description = 'LINK / USD: Historic Aggregator Facade' - - let link: Contract - let aggregator: Contract - let oc1: Contract - let facade: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(defaultAccount).deploy() - oc1 = await oracleFactory.connect(defaultAccount).deploy(link.address) - aggregator = await aggregatorFactory - .connect(defaultAccount) - .deploy(link.address, 0, 1, [oc1.address], [jobId1]) - facade = await aggregatorFacadeFactory - .connect(defaultAccount) - .deploy(aggregator.address, decimals, description) - - let requestTx = await aggregator.requestRateUpdate() - let receipt = await requestTx.wait() - let request = decodeRunRequest(receipt.logs?.[3]) - await oc1.fulfillOracleRequest( - ...convertFufillParams(request, previousResponse), - ) - requestTx = await aggregator.requestRateUpdate() - receipt = await requestTx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - await oc1.fulfillOracleRequest(...convertFufillParams(request, response)) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(facade, [ - 'aggregator', - 'decimals', - 'description', - 'getAnswer', - 'getRoundData', - 'getTimestamp', - 'latestAnswer', - 'latestRound', - 'latestRoundData', - 'latestTimestamp', - 'version', - ]) - }) - - describe('#constructor', () => { - it('uses the decimals set in the constructor', async () => { - bigNumEquals(decimals, await facade.decimals()) - }) - - it('uses the description set in the constructor', async () => { - assert.equal(description, await facade.description()) - }) - - it('sets the version to 2', async () => { - bigNumEquals(2, await facade.version()) - }) - }) - - describe('#getAnswer/latestAnswer', () => { - it('pulls the rate from the aggregator', async () => { - bigNumEquals(response, await facade.latestAnswer()) - const latestRound = await facade.latestRound() - bigNumEquals(response, await facade.getAnswer(latestRound)) - }) - }) - - describe('#getTimestamp/latestTimestamp', () => { - it('pulls the timestamp from the aggregator', async () => { - const height = await aggregator.latestTimestamp() - assert.notEqual('0', height.toString()) - bigNumEquals(height, await facade.latestTimestamp()) - const latestRound = await facade.latestRound() - bigNumEquals( - await aggregator.latestTimestamp(), - await facade.getTimestamp(latestRound), - ) - }) - }) - - describe('#getRoundData', () => { - it('assembles the requested round data', async () => { - const previousId = (await facade.latestRound()).sub(1) - const round = await facade.getRoundData(previousId) - bigNumEquals(previousId, round.roundId) - bigNumEquals(previousResponse, round.answer) - bigNumEquals(await facade.getTimestamp(previousId), round.startedAt) - bigNumEquals(await facade.getTimestamp(previousId), round.updatedAt) - bigNumEquals(previousId, round.answeredInRound) - }) - - it('returns zero data for non-existing rounds', async () => { - const roundId = 13371337 - await evmRevert(facade.getRoundData(roundId), 'No data present') - }) - }) - - describe('#latestRoundData', () => { - it('assembles the requested round data', async () => { - const latestId = await facade.latestRound() - const round = await facade.latestRoundData() - bigNumEquals(latestId, round.roundId) - bigNumEquals(response, round.answer) - bigNumEquals(await facade.getTimestamp(latestId), round.startedAt) - bigNumEquals(await facade.getTimestamp(latestId), round.updatedAt) - bigNumEquals(latestId, round.answeredInRound) - }) - - describe('when there is no latest round', () => { - beforeEach(async () => { - aggregator = await aggregatorFactory - .connect(defaultAccount) - .deploy(link.address, 0, 1, [oc1.address], [jobId1]) - facade = await aggregatorFacadeFactory - .connect(defaultAccount) - .deploy(aggregator.address, decimals, description) - }) - - it('assembles the requested round data', async () => { - await evmRevert(facade.latestRoundData(), 'No data present') - }) - }) - }) -}) diff --git a/contracts/test/v0.6/BasicConsumer.test.ts b/contracts/test/v0.6/BasicConsumer.test.ts deleted file mode 100644 index ce0b7c643e..0000000000 --- a/contracts/test/v0.6/BasicConsumer.test.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { ethers } from 'hardhat' -import { toWei, increaseTime5Minutes, toHex } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { BigNumber, constants, Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../test-helpers/setup' -import { bigNumEquals, evmRevert } from '../test-helpers/matchers' -import { - convertFufillParams, - decodeRunRequest, - encodeOracleRequest, - RunRequest, -} from '../test-helpers/oracle' -import cbor from 'cbor' -import { makeDebug } from '../test-helpers/debug' - -const d = makeDebug('BasicConsumer') -let basicConsumerFactory: ContractFactory -let oracleFactory: ContractFactory -let linkTokenFactory: ContractFactory - -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - basicConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/BasicConsumer.sol:BasicConsumer', - roles.defaultAccount, - ) - oracleFactory = await ethers.getContractFactory( - 'src/v0.6/Oracle.sol:Oracle', - roles.oracleNode, - ) - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) -}) - -describe('BasicConsumer', () => { - const specId = '0x4c7b7ffb66b344fbaa64995af81e355a'.padEnd(66, '0') - const currency = 'USD' - const payment = toWei('1') - let link: Contract - let oc: Contract - let cc: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - oc = await oracleFactory.connect(roles.oracleNode).deploy(link.address) - cc = await basicConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, oc.address, specId) - }) - - it('has a predictable gas price [ @skip-coverage ]', async () => { - const rec = await ethers.provider.getTransactionReceipt( - cc.deployTransaction.hash ?? '', - ) - assert.isBelow(rec.gasUsed?.toNumber() ?? -1, 1750000) - }) - - describe('#requestEthereumPrice', () => { - describe('without LINK', () => { - it('reverts', async () => - await expect(cc.requestEthereumPrice(currency, payment)).to.be.reverted) - }) - - describe('with LINK', () => { - beforeEach(async () => { - await link.transfer(cc.address, toWei('1')) - }) - - it('triggers a log event in the Oracle contract', async () => { - const tx = await cc.requestEthereumPrice(currency, payment) - const receipt = await tx.wait() - - const log = receipt?.logs?.[3] - assert.equal(log?.address.toLowerCase(), oc.address.toLowerCase()) - - const request = decodeRunRequest(log) - const expected = { - path: ['USD'], - get: 'https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY', - } - - assert.equal(toHex(specId), request.specId) - bigNumEquals(toWei('1'), request.payment) - assert.equal(cc.address.toLowerCase(), request.requester.toLowerCase()) - assert.equal(1, request.dataVersion) - assert.deepEqual(expected, cbor.decodeFirstSync(request.data)) - }) - - it('has a reasonable gas cost [ @skip-coverage ]', async () => { - const tx = await cc.requestEthereumPrice(currency, payment) - const receipt = await tx.wait() - - assert.isBelow(receipt?.gasUsed?.toNumber() ?? -1, 140000) - }) - }) - }) - - describe('#fulfillOracleRequest', () => { - const response = ethers.utils.formatBytes32String('1,000,000.00') - let request: RunRequest - - beforeEach(async () => { - await link.transfer(cc.address, toWei('1')) - const tx = await cc.requestEthereumPrice(currency, payment) - const receipt = await tx.wait() - - request = decodeRunRequest(receipt?.logs?.[3]) - }) - - it('records the data given to it by the oracle', async () => { - await oc - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - const currentPrice = await cc.currentPrice() - assert.equal(currentPrice, response) - }) - - it('logs the data given to it by the oracle', async () => { - const tx = await oc - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - const receipt = await tx.wait() - - assert.equal(2, receipt?.logs?.length) - const log = receipt?.logs?.[1] - - assert.equal(log?.topics[2], response) - }) - - describe('when the consumer does not recognize the request ID', () => { - let otherRequest: RunRequest - - beforeEach(async () => { - // Create a request directly via the oracle, rather than through the - // chainlink client (consumer). The client should not respond to - // fulfillment of this request, even though the oracle will faithfully - // forward the fulfillment to it. - const args = encodeOracleRequest( - toHex(specId), - cc.address, - basicConsumerFactory.interface.getSighash('fulfill'), - 43, - constants.HashZero, - ) - const tx = await link.transferAndCall(oc.address, 0, args) - const receipt = await tx.wait() - - otherRequest = decodeRunRequest(receipt?.logs?.[2]) - }) - - it('does not accept the data provided', async () => { - d('otherRequest %s', otherRequest) - await oc - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(otherRequest, response)) - - const received = await cc.currentPrice() - - assert.equal(ethers.utils.parseBytes32String(received), '') - }) - }) - - describe('when called by anyone other than the oracle contract', () => { - it('does not accept the data provided', async () => { - await evmRevert( - cc.connect(roles.oracleNode).fulfill(request.requestId, response), - ) - - const received = await cc.currentPrice() - assert.equal(ethers.utils.parseBytes32String(received), '') - }) - }) - }) - - describe('#cancelRequest', () => { - const depositAmount = toWei('1') - let request: RunRequest - - beforeEach(async () => { - await link.transfer(cc.address, depositAmount) - const tx = await cc.requestEthereumPrice(currency, payment) - const receipt = await tx.wait() - - request = decodeRunRequest(receipt.logs?.[3]) - }) - - describe('before 5 minutes', () => { - it('cant cancel the request', () => - evmRevert( - cc - .connect(roles.consumer) - .cancelRequest( - oc.address, - request.requestId, - request.payment, - request.callbackFunc, - request.expiration, - ), - )) - }) - - describe('after 5 minutes', () => { - it('can cancel the request', async () => { - await increaseTime5Minutes(ethers.provider) - - await cc - .connect(roles.consumer) - .cancelRequest( - oc.address, - request.requestId, - request.payment, - request.callbackFunc, - request.expiration, - ) - }) - }) - }) - - describe('#withdrawLink', () => { - const depositAmount = toWei('1') - - beforeEach(async () => { - await link.transfer(cc.address, depositAmount) - const balance = await link.balanceOf(cc.address) - bigNumEquals(balance, depositAmount) - }) - - it('transfers LINK out of the contract', async () => { - await cc.connect(roles.consumer).withdrawLink() - const ccBalance = await link.balanceOf(cc.address) - const consumerBalance = BigNumber.from( - await link.balanceOf(await roles.consumer.getAddress()), - ) - bigNumEquals(ccBalance, 0) - bigNumEquals(consumerBalance, depositAmount) - }) - }) -}) diff --git a/contracts/test/v0.6/BlockhashStore.test.ts b/contracts/test/v0.6/BlockhashStore.test.ts deleted file mode 100644 index 453b2eca3b..0000000000 --- a/contracts/test/v0.6/BlockhashStore.test.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { Contract, ContractFactory } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' - -let personas: Personas -let blockhashStoreTestHelperFactory: ContractFactory - -type TestBlocks = { - num: number - rlpHeader: Uint8Array - hash: string -} - -const mainnetBlocks: TestBlocks[] = [ - { - num: 10000467, - rlpHeader: ethers.utils.arrayify( - '0xf90215a058ee3c05e880cb25a3db92b9f1479c5453690ca97f9bcbb18d21965d3213578ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea674fdde714fd979de3edf0f56aa9716b898ec8a0a448355652812a7d518b5c979a15bba02cfe4576d8eb61e8b5731ecc37f2bec6a0049f25ed97f9ed9a9c8521ab39cd2c48438d1d18c84dcab5bf494c19595bd462a0b1169f28bdbe5dd61ebc20b7a459be9d7fa898f5a3ba5fed6d502d94b9a8101bb901001000008180000210000080010001080310e004800c3040000060484000010804088050044302a500240041040010012120840002400005092000808000640012081000880010008040200208000004050800400002244044006041040040010890040504020040008004222502000800220000021800006400802036500000000400014640d00020002110000001440000001509543802080004210004100de04744a2810000000032250080810000502210c04289480800000423080800004000a020220030203000020001000000042c00420090000008003308459020e010a01000200190900040e81000040040000020000a8044001000202010000600c087086c49cadb1b57839898538398909483984b9e845eb02fbf94505059452d65746865726d696e652d6575312d34a06d0287c21536fac432714bd3f3712ff1a7e409faf1b10edac9b9547da1d4f7b188930531280477460c', - ), - hash: '0x4a65bcdf3466a16740b74849cc10fc57d4acb24cce148665482812699a400464', - }, - { - num: 10000468, - rlpHeader: ethers.utils.arrayify( - '0xf9020da04a65bcdf3466a16740b74849cc10fc57d4acb24cce148665482812699a400464a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479404668ec2f57cc15c381b461b9fedab5d451c8f7fa0bcd4ddbb7125a5c06df96d862921dc0bba8664b3f759a233fe565a615c0ab3eaa0087ab379852c83e4b660de1668fc93333201ad0d233167ea6cef8bacaf5cba2aa0d81855037b2a6b56eba0c2ed129fb4102fb831b0baa187a0f6e0c155400f7855b9010080040040200000000010102081000000500040010408040800010110000000008000005808020000902021818000210000000000081100401000400014400001041008000020448800180128800008000200000420e01200000000000000011000001000020000208000b42200a0008000510200080200008c002018108010014030200000080000000002000010008000011008004003081000400080100803040080040300000002044080480000000000008080101000000050000000000840000002200040000a0080000442008006005502800000040008000890201002022402208002900020900000000080000100100201080000000003400000004887086d57541477ba839898548398968083989147845eb02fc28c73706964657230380b03ac53a076c676a0ab090b373b6242851a4beab7b8cdc9d3ebe211747a255b78c0278c42880ea13d40042dd1e6', - ), - hash: '0x00fd2589a272b85ffaf63223641571bf95891c936b7514ee4e87a593e52de7c9', - }, - { - num: 10000469, - rlpHeader: ethers.utils.arrayify( - '0xf90211a000fd2589a272b85ffaf63223641571bf95891c936b7514ee4e87a593e52de7c9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347945a0b54d5dc17e0aadc383d2db43b0a0d3e029c4ca01b28d3b4e4d3442a9e6caed9f80b6a639bce6f3a283d4e004e6bb44e483ceeeba067c00d9067bc023b8fab8e3afd1bc0f2470f08003bdf9f167fbfeede2422ac4ea09d8b344d9ab1b7288f8c5e644c53b1a5288da6d6ee0e388ec76f291def48da15b90100c462095870a26a0804132e208110329710d459054558159c103208d44820002016108136199200061063699d8400254a22828c11b5512e3303c98ec7747cc02d00161880c2f2c580e806bccc04805190265f096601342058020a8324c277735d8202220412f03303201252a3000038883a4bb0010e6b004408306232150a84d110100d0c4b9d228022812602c05c801d20500d4ed10010ce2400428a96950a98050c00e603292a806c4983b25814880000440a23821191121996410c5110c949616c2066a4a0488087d4c226c14208042c00d609b5cc44051400219d93626818728612a9b18690e03c902014a900e0018828011494b80d4708799b0d8a83cace87086e64fefefb48839898558398968083986664845eb02fc7906574682d70726f2d687a662d74303032a09f1918a362b55ebd072cc9548fb74f89301d41c2a1feb13c08a1c2c3cb0606d88810dfa530069367fb', - ), - hash: '0x325fde74e261fc483a16506bbc711b645b043ad24c7db0136845a1be262cf0c9', - }, - { - num: 10000470, - rlpHeader: ethers.utils.arrayify( - '0xf90215a0325fde74e261fc483a16506bbc711b645b043ad24c7db0136845a1be262cf0c9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea674fdde714fd979de3edf0f56aa9716b898ec8a020647cfa35563093442a12d80bf2bacb83da1de8340366677f3822591a334ccea066ad7285f6c5b6407f62c6b65a83aeaaa71ad9a97c2bb15139140f2dbb60f7e0a0c0e633851d0b5ce661ecc054517425e82425fcc6170db9693e5b5a6dd5ef6d6bb90100c0c000c1520708182080c8e461891c2402800a80d44a00034259414012012a5006a1416331181504902044960808f1129018800311621e920886804693749b10542400142e984580ccba634881c4156962200ecfb004000005468db44842781c59923110262660802315006106388b028412c42c000820c508e66b7851fa68002008144cd7860cd884280802915163399c168d5a11b0649486084110149469a1e61c31134204b903206566885180bc0426c0c6c0a4d408e182242f08180d204c624a040248425041ac028010d088820402ba4bd38c2d1215829300543465603822110500811290490148049300040e000c280086a09e8100089818ce480a887e87086c4965bf3c8a839898568398705c839847d2845eb02fe994505059452d65746865726d696e652d6575312d35a09d8ae288d0eede524f3ef5e6cfcc5ba07f380bc695bb71578a7b91cfa517071b8859d0976006378e52', - ), - hash: '0x5cf096dfd1fc2d2947a96fdec5377ab7beaa0eb00c80728a3b96f0864cec506a', - }, -] - -const maticBlocks: TestBlocks[] = [ - { - num: 10000467, - rlpHeader: ethers.utils.arrayify( - '0xf9025da0212093b89337e6741aca0c6c1cbfc64b56155bdcc3623fa9bcbfa0498fa135aba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0ac0ec242516093308f7a2cc6965f38835eb3db69cba93401daef672666a3aefea0d06985e9ae671d22fb4b3d73ef4e074a448f66b4769ad8d59c3b8aef1ede15e2a00076d4897a88e08c25ca12c558f622d03d532d8b674e8c6b9847000b98dbe480b90100040000000200000000000000000000000000000000000000100000000000400000000000000000000000002800000000100080000000000000000001000000400000000000000000000000080002008000000000000000000021000000000000000000000200000000001000000008000000000008000001800800100000000000010000000010100000800000000000001000000200100000000000000000002000000004000000000000000080010000000000000000200000000000000040000000420000000000010000000000000004040004000000001000001000200100100080000000000400000000100000100000000000000000000000021000000e839898538401312d008302e54b84600df884b861d78301091883626f7288676f312e31352e35856c696e7578000000000000000003eb49c29f5facd767206f64b8a5c9b325bced5c9156f489c6281c68eddc9e5f2ef1177c02a99d8ab6216dcf2879eefddfc27c75ffa9ef6a2185ce9983d1434901a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0x6c3b869ca26fece236545f7914d8249651d729852dc1445f53a94d5a59cdc9da', - }, - { - num: 10000468, - rlpHeader: ethers.utils.arrayify( - '0xf9025da06c3b869ca26fece236545f7914d8249651d729852dc1445f53a94d5a59cdc9daa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fa236c78bbe5939cc62985e32582c2158468a5b2b4dd02d514edb0bea95f0fd3a0e05ccfb09764e5cd6811ef2c2616d4a57f187be84235e2569c9b8d70489f1a44a0aea27aed2ad1d553e30501e6fe47fee0842c3b7ce5867e579b29975f02ec4282b90100008000100000000000000400080800000009000000010020000000000800000000000000080000000000000000000000000080000080000820400000000000000000200000000000000000080000008000200000200000000003009000020000000200000010000000001000000000000000000000000000800040100000000000000000000010000000100100000000000000000102004000000040000000002000000008000000000000000000000000000000200000000000000000000041000000020000080001010000000000000008000000110000001001800020000000100000000001400000040000000000000010010000000001000000001000000e839898548401312d00830494ed84600df886b861d78301091883626f7288676f312e31352e35856c696e75780000000000000000aa8ed86143b48b6aa7170d2083c3a7be31cbdfdc40f39badb8747f4c2198279a71c0d3eb5d25f3b7da5a48b887f61e22fe0baa692aa03807ad12f6fe25af087e00a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0x258aa48bde013579fbfef2e222bcc222b1f57bf898a71c623f9024229c9f6111', - }, - { - num: 10000469, - rlpHeader: ethers.utils.arrayify( - '0xf9025aa0258aa48bde013579fbfef2e222bcc222b1f57bf898a71c623f9024229c9f6111a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fa236c78bbe5939cc62985e32582c2158468a5b2b4dd02d514edb0bea95f0fd3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e839898558401312d008084600df888b861d78301091883626f7288676f312e31352e35856c696e75780000000000000000bd8668cc5d89583a7cc26fb96650e61f045ffe5248ae80c667ba7648df41e3d552060998ac151f2d15bd1b98f0a2a50c4281729a4c0aae4758a3bad280207c2901a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0x611779767f1deb5a17723ec71d1b397b18a0fc9a40d282810a33bd6a0a5f46f9', - }, - { - num: 10000470, - rlpHeader: ethers.utils.arrayify( - '0xf9025aa0611779767f1deb5a17723ec71d1b397b18a0fc9a40d282810a33bd6a0a5f46f9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fa236c78bbe5939cc62985e32582c2158468a5b2b4dd02d514edb0bea95f0fd3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e839898568401312d008084600df88ab861d78301091883626f7288676f312e31352e35856c696e75780000000000000000b617675c3b01e98319508130e1a583d57ce6b3a8a97fa2fbdaa33673cc6c609d6f7c361c833838f54b724d3a83cdd73e2398bb147970cd0b057865386cb08e1300a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0x2edf2f5c5faa5046b2304f76c92096a25e7c4343a7b75c36b29e8e9755d93397', - }, -] - -// The following headers from Binance Smart Chain were retrieved using `go run -// binance.go`, where binance.go contains -// -// package main -// -// import ( -// "context" -// "fmt" -// "log" -// "math/big" -// "math/rand" -// "strings" -// -// "github.com/ethereum/go-ethereum/ethclient" -// "github.com/ethereum/go-ethereum/rlp" -// ) -// -// var tsBlockTemplate = ` -// { -// num: %d, -// rlpHeader: ethers.utils.arrayify( -// '0x%x', -// ), -// hash: '0x%x', -// }, -// ` -// -// func main() { -// client, err := ethclient.Dial("https://bsc-dataseed.binance.org/") -// if err != nil { -// log.Fatal(err) -// } -// -// header, err := client.HeaderByNumber(context.Background(), nil) -// if err != nil { -// log.Fatal(err) -// } -// topBlockNum := header.Number.Int64() -// numBlocks := int64(4) -// if topBlockNum < numBlocks { -// log.Fatalf("need at least %d consecutive blocks", numBlocks) -// } -// targetBlock := int64(rand.Intn(int(topBlockNum - numBlocks))) -// simulatedHeadBlock := targetBlock + numBlocks - 1 -// for blockNum := targetBlock; blockNum <= simulatedHeadBlock; blockNum++ { -// header, err := client.HeaderByNumber(context.Background(), big.NewInt(blockNum)) -// if err != nil { -// log.Fatal(err) -// } -// s, err := rlp.EncodeToBytes(header) -// if err != nil { -// log.Fatalf("could not encode header: got error %s from %v", err, header) -// } -// // fmt.Printf("header for block number %d: 0x%x\n", blockNum, s) -// fmt.Printf(strings.TrimLeft(tsBlockTemplate, "\n"), blockNum, s, header.Hash()) -// } -// } -const binanceBlocks: TestBlocks[] = [ - { - num: 1875651, - rlpHeader: ethers.utils.arrayify( - '0xf9025da029c26248bebbe0d0acb209d13ac9337c4b5c313696c031dd63b3cd16cbdc0c21a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b8f7166496996a7da21cf1f1b04d9b3e26a3d077a03f962867b5e86191c3280bd52c4249587e08ddfa9851cea981fb7a5721c9157aa05924ae05d17347687ba81d093aee159ccc65cefc8314b0515ef921e553df05a2a089af99a7afa586e7d67062d051df4255304bb730f6d62fdd3bdb207f1513b23bb901000100000000000000000800000000000000000000000200000000000000800000000000000200100000000000000800000000000000000000000000000000000000000000000000800000140800000008201000001000000202000000001200000000002002020000000000000000080000000000000002000000001000000000000002000000008010000000000000000002040080008400280000c00000081000400000004000000010000000020000000000000000000000000000000000000001000210200000000000000000000800000000000000000000000000002010000004000000000001000000000000000000000800020000000000000000000002831c9ec38401c9c380830789c2845f9faab1b861d883010002846765746888676f312e31332e34856c696e7578000000000000003311ee6830f31dc9116d8a59178b539d91eb6811c1d533c4a59bf77262689c552218bb1eae9cb9d6bf6e1066bea78052c8767313ace71c919d02e70760bd255401a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0xe0a935b1e37420ac1d855215bdad4730a5ffe315eda287c6c18aa86c426ede74', - }, - { - num: 1875652, - rlpHeader: ethers.utils.arrayify( - '0xf9025da0e0a935b1e37420ac1d855215bdad4730a5ffe315eda287c6c18aa86c426ede74a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794c2be4ec20253b8642161bc3f444f53679c1f3d47a0dbf2d40cf5533b65ac9b5be35cac75f7b106244ba14ee476a832c28d46a53452a04f83b8a51d3e17b6a02a0caa79acc7597996c5b8c68dba12c33095ae086089eea02fa2642645b2de17227a6c18c3fa491f54b3bdfe8ac8e04924a33a005a0e9e61b901000100000100000000000008000000000000000000040000000000000000800000000000000000000000000000000800000800000000000400000000000020000040100080000000000000000800000000209000001000000200000000801000400800002002030000000000000100080000002000000002004000011000000002000100040000000000100000000000000000040100009000300000000000000002004000004000000000000000020000002000000010000000200000800000000001000280000000000000008000000000000000800000000000020000002000041000000000000001200020001000080000002a40020040000000000000000002831c9ec48401c9c38083044b40845f9faab4b861d883010002846765746888676f312e31332e34856c696e757800000000000000cfc02687b2394922055792a8e67dad566f6690de06b229d752433b2067207b5f43b9f3c63f91cea5a79bbfc51d9132b933a706ab504038a92f37d57af2bb6c2e01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0x629e5abcae42940e00d7b38aa7b2ecccfbab582cb7a0b2c3658c2dad8e66549d', - }, - { - num: 1875653, - rlpHeader: ethers.utils.arrayify( - '0xf9025da0629e5abcae42940e00d7b38aa7b2ecccfbab582cb7a0b2c3658c2dad8e66549da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ce2fd7544e0b2cc94692d4a704debef7bcb61328a0718e7db53041585a814d658c32c88fd550c2c6d200826020008925e0a0f7967fa000fbf842e492a47cc9786885783259a08aed71055e78216006408932515fd960a0c7ffeb2189b8fcde43733cf1958cdb1c38c44052cfbb41125382240c232a98f8b901000000000000000000000000000000000000000002000000000004000000000000000000010000000000000000000000000000000000000200000000004020200000010000000800000000208800000000201000000000000000080000000000000000002002220000000000000000080000000000000000000000001000000000100000000000080010000000000000000000040000000000000000000000000002000000000008000000004000000000000000000000200000000000000000000000000202000000000000000000000000000000000008000000000000002080001000000000000001000000000000000000080100000000000000000000000002831c9ec58401c9c38083025019845f9faab7b861d883010002846765746888676f312e31332e34856c696e7578000000000000008c3c7a5c83e930fbd9d14f83c9b3931f032f0f678919c35b8b32ca6dae9948950bfa326fae134fa234fa7b84c06bdc3f7c6d6414c2a266df1339e563be8bd9cc00a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0xae8574651adabfd0ca55e2cee0e2e639ced73ec1cc0a35debeeceee6943442a9', - }, - { - num: 1875654, - rlpHeader: ethers.utils.arrayify( - '0xf9025da0ae8574651adabfd0ca55e2cee0e2e639ced73ec1cc0a35debeeceee6943442a9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794d6caa02bbebaebb5d7e581e4b66559e635f805ffa02df6a1173c63ec0a8acc46c818670f030aece1154b9f3bbc70f46a8427dd8dd6a0fa8835c499682d8c90759ff9ea1c291048755b967e48880a0fc21d19ec034a59a0b4e22607cb105c04156044b3f98c2cecae1553b45aa9b6044c37573791a27576b901000200000008000000000001000000000000000000000020000000000000020000000000000000000000000000000000000000000000000040000000000220000000000000000400000000001802000000201000000000000000000000000000000000002002020000000000000000080000000000000000000000001000000000000000000000100000000000000000000000040000000000000000010200200002000400000000400000000200000000000000080000000000000000000008000000000200000000000000000000000000000000000000000000000000002000001000000000000001000000000000000000000000000000000008080000000002831c9ec68401c9c3808301e575845f9faabab861d883010002846765746888676f312e31332e34856c696e757800000000000000399e73b0e963ec029e815623a414aa852508a28dd9799a1bf4e2380c8db687a46cc5b6cc20352ae21e35cfd28124a32fcd49ac8fac5b03901b3e03963e4fff5801a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', - ), - hash: '0x189990455c59a5dea78071df9a2008ede292ff0a062fc5c4c6ca35fbe476f834', - }, -] - -before(async () => { - personas = (await getUsers()).personas - blockhashStoreTestHelperFactory = await ethers.getContractFactory( - 'src/v0.6/tests/BlockhashStoreTestHelper.sol:BlockhashStoreTestHelper', - personas.Default, - ) -}) - -runBlockhashStoreTests(mainnetBlocks, 'Ethereum') -runBlockhashStoreTests(maticBlocks, 'Matic') -runBlockhashStoreTests(binanceBlocks, 'Binance Smart Chain') - -async function runBlockhashStoreTests( - blocks: TestBlocks[], - description: string, -) { - describe(`BlockhashStore (${description})`, () => { - let blockhashStoreTestHelper: Contract - - beforeEach(async () => { - blockhashStoreTestHelper = await blockhashStoreTestHelperFactory - .connect(personas.Default) - .deploy() - - const [lastBlock] = blocks.slice(-1) - await blockhashStoreTestHelper - .connect(personas.Default) - .godmodeSetHash(lastBlock.num, lastBlock.hash) - assert.strictEqual( - await blockhashStoreTestHelper.getBlockhash(lastBlock.num), - lastBlock.hash, - ) - }) - - it('getBlockhash reverts for unknown blockhashes', async () => { - await expect( - blockhashStoreTestHelper.getBlockhash(99999999), - ).to.be.revertedWith('blockhash not found in store') - }) - - it('storeVerifyHeader records valid blockhashes', async () => { - for (let i = blocks.length - 2; i >= 0; i--) { - assert.strictEqual( - ethers.utils.keccak256(blocks[i + 1].rlpHeader), - await blockhashStoreTestHelper.getBlockhash(blocks[i + 1].num), - ) - await blockhashStoreTestHelper - .connect(personas.Default) - .storeVerifyHeader(blocks[i].num, blocks[i + 1].rlpHeader) - assert.strictEqual( - await blockhashStoreTestHelper.getBlockhash(blocks[i].num), - blocks[i].hash, - ) - } - }) - - it('storeVerifyHeader rejects unknown headers', async () => { - const unknownBlock = blocks[0] - await expect( - blockhashStoreTestHelper - .connect(personas.Default) - .storeVerifyHeader(unknownBlock.num - 1, unknownBlock.rlpHeader), - ).to.be.revertedWith('header has unknown blockhash') - }) - - it('storeVerifyHeader rejects corrupted headers', async () => { - const [lastBlock] = blocks.slice(-1) - const modifiedHeader = new Uint8Array(lastBlock.rlpHeader) - modifiedHeader[137] += 1 - await expect( - blockhashStoreTestHelper - .connect(personas.Default) - .storeVerifyHeader(lastBlock.num - 1, modifiedHeader), - ).to.be.revertedWith('header has unknown blockhash') - }) - - it('store accepts recent block numbers', async () => { - await ethers.provider.send('evm_mine', []) - - const n = (await ethers.provider.getBlockNumber()) - 1 - await blockhashStoreTestHelper.connect(personas.Default).store(n) - - assert.equal( - await blockhashStoreTestHelper.getBlockhash(n), - (await ethers.provider.getBlock(n)).hash, - ) - }) - - it('store rejects future block numbers', async () => { - await expect( - blockhashStoreTestHelper.connect(personas.Default).store(99999999999), - ).to.be.revertedWith('blockhash(n) failed') - }) - - it('store rejects old block numbers', async () => { - for (let i = 0; i < 300; i++) { - await ethers.provider.send('evm_mine', []) - } - - await expect( - blockhashStoreTestHelper - .connect(personas.Default) - .store((await ethers.provider.getBlockNumber()) - 256), - ).to.be.revertedWith('blockhash(n) failed') - }) - - it('storeEarliest works', async () => { - for (let i = 0; i < 300; i++) { - await ethers.provider.send('evm_mine', []) - } - - await blockhashStoreTestHelper.connect(personas.Default).storeEarliest() - - const n = (await ethers.provider.getBlockNumber()) - 256 - assert.equal( - await blockhashStoreTestHelper.getBlockhash(n), - (await ethers.provider.getBlock(n)).hash, - ) - }) - }) -} diff --git a/contracts/test/v0.6/Chainlink.test.ts b/contracts/test/v0.6/Chainlink.test.ts deleted file mode 100644 index f3587dc30a..0000000000 --- a/contracts/test/v0.6/Chainlink.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi, decodeDietCBOR, hexToBuf } from '../test-helpers/helpers' -import { assert } from 'chai' -import { Contract, ContractFactory, providers, Signer } from 'ethers' -import { Roles, getUsers } from '../test-helpers/setup' -import { makeDebug } from '../test-helpers/debug' - -const debug = makeDebug('ChainlinkTestHelper') -let concreteChainlinkFactory: ContractFactory - -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - concreteChainlinkFactory = await ethers.getContractFactory( - 'src/v0.6/tests/ChainlinkTestHelper.sol:ChainlinkTestHelper', - roles.defaultAccount, - ) -}) - -describe('ChainlinkTestHelper', () => { - let ccl: Contract - let defaultAccount: Signer - - beforeEach(async () => { - defaultAccount = roles.defaultAccount - ccl = await concreteChainlinkFactory.connect(defaultAccount).deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(ccl, [ - 'add', - 'addBytes', - 'addInt', - 'addStringArray', - 'addUint', - 'closeEvent', - 'setBuffer', - ]) - }) - - async function parseCCLEvent(tx: providers.TransactionResponse) { - const receipt = await tx.wait() - const data = receipt.logs?.[0].data - const d = debug.extend('parseCCLEvent') - d('data %s', data) - return ethers.utils.defaultAbiCoder.decode(['bytes'], data ?? '') - } - - describe('#close', () => { - it('handles empty payloads', async () => { - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, {}) - }) - }) - - describe('#setBuffer', () => { - it('emits the buffer', async () => { - await ccl.setBuffer('0xA161616162') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { a: 'b' }) - }) - }) - - describe('#add', () => { - it('stores and logs keys and values', async () => { - await ccl.add('first', 'word!!') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { first: 'word!!' }) - }) - - it('handles two entries', async () => { - await ccl.add('first', 'uno') - await ccl.add('second', 'dos') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - assert.deepEqual(decoded, { - first: 'uno', - second: 'dos', - }) - }) - }) - - describe('#addBytes', () => { - it('stores and logs keys and values', async () => { - await ccl.addBytes('first', '0xaabbccddeeff') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - const expected = hexToBuf('0xaabbccddeeff') - assert.deepEqual(decoded, { first: expected }) - }) - - it('handles two entries', async () => { - await ccl.addBytes('first', '0x756E6F') - await ccl.addBytes('second', '0x646F73') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - const expectedFirst = hexToBuf('0x756E6F') - const expectedSecond = hexToBuf('0x646F73') - assert.deepEqual(decoded, { - first: expectedFirst, - second: expectedSecond, - }) - }) - - it('handles strings', async () => { - await ccl.addBytes('first', ethers.utils.toUtf8Bytes('apple')) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - const expected = ethers.utils.toUtf8Bytes('apple') - assert.deepEqual(decoded, { first: expected }) - }) - }) - - describe('#addInt', () => { - it('stores and logs keys and values', async () => { - await ccl.addInt('first', 1) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { first: 1 }) - }) - - it('handles two entries', async () => { - await ccl.addInt('first', 1) - await ccl.addInt('second', 2) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - assert.deepEqual(decoded, { - first: 1, - second: 2, - }) - }) - }) - - describe('#addUint', () => { - it('stores and logs keys and values', async () => { - await ccl.addUint('first', 1) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { first: 1 }) - }) - - it('handles two entries', async () => { - await ccl.addUint('first', 1) - await ccl.addUint('second', 2) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - assert.deepEqual(decoded, { - first: 1, - second: 2, - }) - }) - }) - - describe('#addStringArray', () => { - it('stores and logs keys and values', async () => { - await ccl.addStringArray('word', [ - ethers.utils.formatBytes32String('seinfeld'), - ethers.utils.formatBytes32String('"4"'), - ethers.utils.formatBytes32String('LIFE'), - ]) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { word: ['seinfeld', '"4"', 'LIFE'] }) - }) - }) -}) diff --git a/contracts/test/v0.6/ChainlinkClient.test.ts b/contracts/test/v0.6/ChainlinkClient.test.ts deleted file mode 100644 index bfd43d7f3f..0000000000 --- a/contracts/test/v0.6/ChainlinkClient.test.ts +++ /dev/null @@ -1,376 +0,0 @@ -import { ethers } from 'hardhat' -import { assert } from 'chai' -import { Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../test-helpers/setup' -import { - convertFufillParams, - decodeCCRequest, - decodeRunRequest, - RunRequest, -} from '../test-helpers/oracle' -import { decodeDietCBOR } from '../test-helpers/helpers' -import { evmRevert } from '../test-helpers/matchers' - -let concreteChainlinkClientFactory: ContractFactory -let emptyOracleFactory: ContractFactory -let getterSetterFactory: ContractFactory -let oracleFactory: ContractFactory -let linkTokenFactory: ContractFactory - -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - - concreteChainlinkClientFactory = await ethers.getContractFactory( - 'src/v0.6/tests/ChainlinkClientTestHelper.sol:ChainlinkClientTestHelper', - roles.defaultAccount, - ) - emptyOracleFactory = await ethers.getContractFactory( - 'src/v0.6/tests/EmptyOracle.sol:EmptyOracle', - roles.defaultAccount, - ) - getterSetterFactory = await ethers.getContractFactory( - 'src/v0.5/tests/GetterSetter.sol:GetterSetter', - roles.defaultAccount, - ) - oracleFactory = await ethers.getContractFactory( - 'src/v0.4/Oracle.sol:Oracle', - roles.defaultAccount, - ) - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) -}) - -describe('ChainlinkClientTestHelper', () => { - const specId = - '0x4c7b7ffb66b344fbaa64995af81e355a00000000000000000000000000000000' - let cc: Contract - let gs: Contract - let oc: Contract - let newoc: Contract - let link: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - oc = await oracleFactory.connect(roles.defaultAccount).deploy(link.address) - newoc = await oracleFactory - .connect(roles.defaultAccount) - .deploy(link.address) - gs = await getterSetterFactory.connect(roles.defaultAccount).deploy() - cc = await concreteChainlinkClientFactory - .connect(roles.defaultAccount) - .deploy(link.address, oc.address) - }) - - describe('#newRequest', () => { - it('forwards the information to the oracle contract through the link token', async () => { - const tx = await cc.publicNewRequest( - specId, - gs.address, - ethers.utils.toUtf8Bytes('requestedBytes32(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - - assert.equal(1, receipt.logs?.length) - const [jId, cbAddr, cbFId, cborData] = receipt.logs - ? decodeCCRequest(receipt.logs[0]) - : [] - const params = decodeDietCBOR(cborData ?? '') - - assert.equal(specId, jId) - assert.equal(gs.address, cbAddr) - assert.equal('0xed53e511', cbFId) - assert.deepEqual({}, params) - }) - }) - - describe('#chainlinkRequest(Request)', () => { - it('emits an event from the contract showing the run ID', async () => { - const tx = await cc.publicRequest( - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - - const { events, logs } = await tx.wait() - - assert.equal(4, events?.length) - - assert.equal(logs?.[0].address, cc.address) - assert.equal(events?.[0].event, 'ChainlinkRequested') - }) - }) - - describe('#chainlinkRequestTo(Request)', () => { - it('emits an event from the contract showing the run ID', async () => { - const tx = await cc.publicRequestRunTo( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { events } = await tx.wait() - - assert.equal(4, events?.length) - assert.equal(events?.[0].event, 'ChainlinkRequested') - }) - - it('emits an event on the target oracle contract', async () => { - const tx = await cc.publicRequestRunTo( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { logs } = await tx.wait() - const event = logs && newoc.interface.parseLog(logs[3]) - - assert.equal(4, logs?.length) - assert.equal(event?.name, 'OracleRequest') - }) - - it('does not modify the stored oracle address', async () => { - await cc.publicRequestRunTo( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - - const actualOracleAddress = await cc.publicOracleAddress() - assert.equal(oc.address, actualOracleAddress) - }) - }) - - describe('#cancelChainlinkRequest', () => { - let requestId: string - // a concrete chainlink attached to an empty oracle - let ecc: Contract - - beforeEach(async () => { - const emptyOracle = await emptyOracleFactory - .connect(roles.defaultAccount) - .deploy() - ecc = await concreteChainlinkClientFactory - .connect(roles.defaultAccount) - .deploy(link.address, emptyOracle.address) - - const tx = await ecc.publicRequest( - specId, - ecc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { events } = await tx.wait() - requestId = (events?.[0]?.args as any).id - }) - - it('emits an event from the contract showing the run was cancelled', async () => { - const tx = await ecc.publicCancelRequest( - requestId, - 0, - ethers.utils.hexZeroPad('0x', 4), - 0, - ) - const { events } = await tx.wait() - - assert.equal(1, events?.length) - assert.equal(events?.[0].event, 'ChainlinkCancelled') - assert.equal(requestId, (events?.[0].args as any).id) - }) - - it('throws if given a bogus event ID', async () => { - await evmRevert( - ecc.publicCancelRequest( - ethers.utils.formatBytes32String('bogusId'), - 0, - ethers.utils.hexZeroPad('0x', 4), - 0, - ), - ) - }) - }) - - describe('#recordChainlinkFulfillment(modifier)', () => { - let request: RunRequest - - beforeEach(async () => { - const tx = await cc.publicRequest( - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { logs } = await tx.wait() - - request = decodeRunRequest(logs?.[3]) - }) - - it('emits an event marking the request fulfilled', async () => { - const tx = await oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - const { logs } = await tx.wait() - - const event = logs && cc.interface.parseLog(logs[0]) - - assert.equal(1, logs?.length) - assert.equal(event?.name, 'ChainlinkFulfilled') - assert.equal(request.requestId, event?.args.id) - }) - - it('should only allow one fulfillment per id', async () => { - await oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - - await evmRevert( - oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Must have a valid requestId', - ) - }) - - it('should only allow the oracle to fulfill the request', async () => { - await evmRevert( - oc - .connect(roles.stranger) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Not an authorized node to fulfill requests', - ) - }) - }) - - describe('#fulfillChainlinkRequest(function)', () => { - let request: RunRequest - - beforeEach(async () => { - const tx = await cc.publicRequest( - specId, - cc.address, - ethers.utils.toUtf8Bytes( - 'publicFulfillChainlinkRequest(bytes32,bytes32)', - ), - 0, - ) - const { logs } = await tx.wait() - - request = decodeRunRequest(logs?.[3]) - }) - - it('emits an event marking the request fulfilled', async () => { - const tx = await oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - - const { logs } = await tx.wait() - const event = logs && cc.interface.parseLog(logs[0]) - - assert.equal(1, logs?.length) - assert.equal(event?.name, 'ChainlinkFulfilled') - assert.equal(request.requestId, event?.args?.id) - }) - - it('should only allow one fulfillment per id', async () => { - await oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - - await evmRevert( - oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Must have a valid requestId', - ) - }) - - it('should only allow the oracle to fulfill the request', async () => { - await evmRevert( - oc - .connect(roles.stranger) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Not an authorized node to fulfill requests', - ) - }) - }) - - describe('#chainlinkToken', () => { - it('returns the Link Token address', async () => { - const addr = await cc.publicChainlinkToken() - assert.equal(addr, link.address) - }) - }) - - describe('#addExternalRequest', () => { - let mock: Contract - let request: RunRequest - - beforeEach(async () => { - mock = await concreteChainlinkClientFactory - .connect(roles.defaultAccount) - .deploy(link.address, oc.address) - - const tx = await cc.publicRequest( - specId, - mock.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const receipt = await tx.wait() - - request = decodeRunRequest(receipt.logs?.[3]) - await mock.publicAddExternalRequest(oc.address, request.requestId) - }) - - it('allows the external request to be fulfilled', async () => { - await oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - }) - - it('does not allow the same requestId to be used', async () => { - await evmRevert( - cc.publicAddExternalRequest(newoc.address, request.requestId), - ) - }) - }) -}) diff --git a/contracts/test/v0.6/CheckedMath.test.ts b/contracts/test/v0.6/CheckedMath.test.ts deleted file mode 100644 index 14520d9d9b..0000000000 --- a/contracts/test/v0.6/CheckedMath.test.ts +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: MIT -// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/c9630526e24ba53d9647787588a19ffaa3dd65e1/test/math/SignedSafeMath.test.js - -import { ethers } from 'hardhat' -import { assert } from 'chai' -import { BigNumber, constants, Contract, ContractFactory } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { bigNumEquals } from '../test-helpers/matchers' - -let mathFactory: ContractFactory -let personas: Personas - -before(async () => { - personas = (await getUsers()).personas - mathFactory = await ethers.getContractFactory( - 'src/v0.6/tests/CheckedMathTestHelper.sol:CheckedMathTestHelper', - personas.Default, - ) -}) - -const int256Max = constants.MaxInt256 -const int256Min = constants.MinInt256 - -describe('CheckedMath', () => { - let math: Contract - - beforeEach(async () => { - math = await mathFactory.connect(personas.Default).deploy() - }) - - describe('#add', () => { - const a = BigNumber.from('1234') - const b = BigNumber.from('5678') - - it('is commutative', async () => { - const c1 = await math.add(a, b) - const c2 = await math.add(b, a) - - bigNumEquals(c1.result, c2.result) - assert.isTrue(c1.ok) - assert.isTrue(c2.ok) - }) - - it('is commutative with big numbers', async () => { - const c1 = await math.add(int256Max, int256Min) - const c2 = await math.add(int256Min, int256Max) - - bigNumEquals(c1.result, c2.result) - assert.isTrue(c1.ok) - assert.isTrue(c2.ok) - }) - - it('returns false when overflowing', async () => { - const c1 = await math.add(int256Max, 1) - const c2 = await math.add(1, int256Max) - - bigNumEquals(0, c1.result) - bigNumEquals(0, c2.result) - assert.isFalse(c1.ok) - assert.isFalse(c2.ok) - }) - - it('returns false when underflowing', async () => { - const c1 = await math.add(int256Min, -1) - const c2 = await math.add(-1, int256Min) - - bigNumEquals(0, c1.result) - bigNumEquals(0, c2.result) - assert.isFalse(c1.ok) - assert.isFalse(c2.ok) - }) - }) - - describe('#sub', () => { - const a = BigNumber.from('1234') - const b = BigNumber.from('5678') - - it('subtracts correctly if it does not overflow and the result is negative', async () => { - const c = await math.sub(a, b) - const expected = a.sub(b) - - bigNumEquals(expected, c.result) - assert.isTrue(c.ok) - }) - - it('subtracts correctly if it does not overflow and the result is positive', async () => { - const c = await math.sub(b, a) - const expected = b.sub(a) - - bigNumEquals(expected, c.result) - assert.isTrue(c.ok) - }) - - it('returns false on overflow', async () => { - const c = await math.sub(int256Max, -1) - - bigNumEquals(0, c.result) - assert.isFalse(c.ok) - }) - - it('returns false on underflow', async () => { - const c = await math.sub(int256Min, 1) - - bigNumEquals(0, c.result) - assert.isFalse(c.ok) - }) - }) - - describe('#mul', () => { - const a = BigNumber.from('5678') - const b = BigNumber.from('-1234') - - it('is commutative', async () => { - const c1 = await math.mul(a, b) - const c2 = await math.mul(b, a) - - bigNumEquals(c1.result, c2.result) - assert.isTrue(c1.ok) - assert.isTrue(c2.ok) - }) - - it('multiplies by 0 correctly', async () => { - const c = await math.mul(a, 0) - - bigNumEquals(0, c.result) - assert.isTrue(c.ok) - }) - - it('returns false on multiplication overflow', async () => { - const c = await math.mul(int256Max, 2) - - bigNumEquals(0, c.result) - assert.isFalse(c.ok) - }) - - it('returns false when the integer minimum is negated', async () => { - const c = await math.mul(int256Min, -1) - - bigNumEquals(0, c.result) - assert.isFalse(c.ok) - }) - }) - - describe('#div', () => { - const a = BigNumber.from('5678') - const b = BigNumber.from('-5678') - - it('divides correctly', async () => { - const c = await math.div(a, b) - - bigNumEquals(a.div(b), c.result) - assert.isTrue(c.ok) - }) - - it('divides a 0 numerator correctly', async () => { - const c = await math.div(0, a) - - bigNumEquals(0, c.result) - assert.isTrue(c.ok) - }) - - it('returns complete number result on non-even division', async () => { - const c = await math.div(7000, 5678) - - bigNumEquals(1, c.result) - assert.isTrue(c.ok) - }) - - it('reverts when 0 is the denominator', async () => { - const c = await math.div(a, 0) - - bigNumEquals(0, c.result) - assert.isFalse(c.ok) - }) - - it('reverts on underflow with a negative denominator', async () => { - const c = await math.div(int256Min, -1) - - bigNumEquals(0, c.result) - assert.isFalse(c.ok) - }) - }) -}) diff --git a/contracts/test/v0.6/DeviationFlaggingValidator.test.ts b/contracts/test/v0.6/DeviationFlaggingValidator.test.ts deleted file mode 100644 index f79a8c7aa4..0000000000 --- a/contracts/test/v0.6/DeviationFlaggingValidator.test.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { BigNumber, Contract, ContractFactory } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { bigNumEquals } from '../test-helpers/matchers' - -let personas: Personas -let validatorFactory: ContractFactory -let flagsFactory: ContractFactory -let acFactory: ContractFactory - -before(async () => { - personas = (await getUsers()).personas - validatorFactory = await ethers.getContractFactory( - 'src/v0.6/DeviationFlaggingValidator.sol:DeviationFlaggingValidator', - personas.Carol, - ) - flagsFactory = await ethers.getContractFactory( - 'src/v0.6/Flags.sol:Flags', - personas.Carol, - ) - acFactory = await ethers.getContractFactory( - 'src/v0.6/SimpleWriteAccessController.sol:SimpleWriteAccessController', - personas.Carol, - ) -}) - -describe('DeviationFlaggingValidator', () => { - let validator: Contract - let flags: Contract - let ac: Contract - const flaggingThreshold = 10000 // 10% - const previousRoundId = 2 - const previousValue = 1000000 - const currentRoundId = 3 - const currentValue = 1000000 - - beforeEach(async () => { - ac = await acFactory.connect(personas.Carol).deploy() - flags = await flagsFactory.connect(personas.Carol).deploy(ac.address) - validator = await validatorFactory - .connect(personas.Carol) - .deploy(flags.address, flaggingThreshold) - await ac.connect(personas.Carol).addAccess(validator.address) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(validator, [ - 'THRESHOLD_MULTIPLIER', - 'flaggingThreshold', - 'flags', - 'isValid', - 'setFlagsAddress', - 'setFlaggingThreshold', - 'validate', - // Owned methods: - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('#constructor', () => { - it('sets the arguments passed in', async () => { - assert.equal(flags.address, await validator.flags()) - bigNumEquals(flaggingThreshold, await validator.flaggingThreshold()) - }) - }) - - describe('#validate', () => { - describe('when the deviation is greater than the threshold', () => { - const currentValue = 1100010 - - it('does raises a flag for the calling address', async () => { - await expect( - validator - .connect(personas.Nelly) - .validate( - previousRoundId, - previousValue, - currentRoundId, - currentValue, - ), - ) - .to.emit(flags, 'FlagRaised') - .withArgs(await personas.Nelly.getAddress()) - }) - - it('uses less than the gas allotted by the aggregator', async () => { - const tx = await validator - .connect(personas.Nelly) - .validate( - previousRoundId, - previousValue, - currentRoundId, - currentValue, - ) - const receipt = await tx.wait() - assert(receipt) - if (receipt && receipt.gasUsed) { - assert.isAbove(receipt.gasUsed.toNumber(), 60000) - } - }) - }) - - describe('when the deviation is less than or equal to the threshold', () => { - const currentValue = 1100009 - - it('does raises a flag for the calling address', async () => { - await expect( - validator - .connect(personas.Nelly) - .validate( - previousRoundId, - previousValue, - currentRoundId, - currentValue, - ), - ).to.not.emit(flags, 'FlagRaised') - }) - - it('uses less than the gas allotted by the aggregator', async () => { - const tx = await validator - .connect(personas.Nelly) - .validate( - previousRoundId, - previousValue, - currentRoundId, - currentValue, - ) - const receipt = await tx.wait() - assert(receipt) - if (receipt && receipt.gasUsed) { - assert.isAbove(receipt.gasUsed.toNumber(), 24000) - } - }) - }) - - describe('when called with a previous value of zero', () => { - const previousValue = 0 - - it('does not raise any flags', async () => { - const tx = await validator - .connect(personas.Nelly) - .validate( - previousRoundId, - previousValue, - currentRoundId, - currentValue, - ) - const receipt = await tx.wait() - assert.equal(0, receipt.events?.length) - }) - }) - }) - - describe('#isValid', () => { - const previousValue = 1000000 - - describe('with a validation larger than the deviation', () => { - const currentValue = 1100010 - it('is not valid', async () => { - assert.isFalse( - await validator.isValid(0, previousValue, 1, currentValue), - ) - }) - }) - - describe('with a validation smaller than the deviation', () => { - const currentValue = 1100009 - it('is valid', async () => { - assert.isTrue( - await validator.isValid(0, previousValue, 1, currentValue), - ) - }) - }) - - describe('with positive previous and negative current', () => { - const previousValue = 1000000 - const currentValue = -900000 - it('correctly detects the difference', async () => { - assert.isFalse( - await validator.isValid(0, previousValue, 1, currentValue), - ) - }) - }) - - describe('with negative previous and positive current', () => { - const previousValue = -900000 - const currentValue = 1000000 - it('correctly detects the difference', async () => { - assert.isFalse( - await validator.isValid(0, previousValue, 1, currentValue), - ) - }) - }) - - describe('when the difference overflows', () => { - const previousValue = BigNumber.from(2).pow(255).sub(1) - const currentValue = BigNumber.from(-1) - - it('does not revert and returns false', async () => { - assert.isFalse( - await validator.isValid(0, previousValue, 1, currentValue), - ) - }) - }) - - describe('when the rounding overflows', () => { - const previousValue = BigNumber.from(2).pow(255).div(10000) - const currentValue = BigNumber.from(1) - - it('does not revert and returns false', async () => { - assert.isFalse( - await validator.isValid(0, previousValue, 1, currentValue), - ) - }) - }) - - describe('when the division overflows', () => { - const previousValue = BigNumber.from(2).pow(255).sub(1) - const currentValue = BigNumber.from(-1) - - it('does not revert and returns false', async () => { - assert.isFalse( - await validator.isValid(0, previousValue, 1, currentValue), - ) - }) - }) - }) - - describe('#setFlaggingThreshold', () => { - const newThreshold = 777 - - it('changes the flagging thresold', async () => { - assert.equal(flaggingThreshold, await validator.flaggingThreshold()) - - await validator.connect(personas.Carol).setFlaggingThreshold(newThreshold) - - assert.equal(newThreshold, await validator.flaggingThreshold()) - }) - - it('emits a log event only when actually changed', async () => { - await expect( - validator.connect(personas.Carol).setFlaggingThreshold(newThreshold), - ) - .to.emit(validator, 'FlaggingThresholdUpdated') - .withArgs(flaggingThreshold, newThreshold) - - await expect( - validator.connect(personas.Carol).setFlaggingThreshold(newThreshold), - ).to.not.emit(validator, 'FlaggingThresholdUpdated') - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - validator.connect(personas.Neil).setFlaggingThreshold(newThreshold), - ).to.be.revertedWith('Only callable by owner') - }) - }) - }) - - describe('#setFlagsAddress', () => { - const newFlagsAddress = '0x0123456789012345678901234567890123456789' - - it('changes the flags address', async () => { - assert.equal(flags.address, await validator.flags()) - - await validator.connect(personas.Carol).setFlagsAddress(newFlagsAddress) - - assert.equal(newFlagsAddress, await validator.flags()) - }) - - it('emits a log event only when actually changed', async () => { - await expect( - validator.connect(personas.Carol).setFlagsAddress(newFlagsAddress), - ) - .to.emit(validator, 'FlagsAddressUpdated') - .withArgs(flags.address, newFlagsAddress) - - await expect( - validator.connect(personas.Carol).setFlagsAddress(newFlagsAddress), - ).to.not.emit(validator, 'FlagsAddressUpdated') - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - validator.connect(personas.Neil).setFlagsAddress(newFlagsAddress), - ).to.be.revertedWith('Only callable by owner') - }) - }) - }) -}) diff --git a/contracts/test/v0.6/Flags.test.ts b/contracts/test/v0.6/Flags.test.ts deleted file mode 100644 index 8f58918429..0000000000 --- a/contracts/test/v0.6/Flags.test.ts +++ /dev/null @@ -1,405 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Contract, ContractFactory } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' - -let personas: Personas - -let controllerFactory: ContractFactory -let flagsFactory: ContractFactory -let consumerFactory: ContractFactory - -let controller: Contract -let flags: Contract -let consumer: Contract - -before(async () => { - personas = (await getUsers()).personas - controllerFactory = await ethers.getContractFactory( - 'src/v0.6/SimpleWriteAccessController.sol:SimpleWriteAccessController', - personas.Nelly, - ) - consumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/FlagsTestHelper.sol:FlagsTestHelper', - personas.Nelly, - ) - flagsFactory = await ethers.getContractFactory( - 'src/v0.6/Flags.sol:Flags', - personas.Nelly, - ) -}) - -describe('Flags', () => { - beforeEach(async () => { - controller = await controllerFactory.deploy() - flags = await flagsFactory.deploy(controller.address) - await flags.disableAccessCheck() - consumer = await consumerFactory.deploy(flags.address) - }) - - it('has a limited public interface [ @skip-coverage ]', async () => { - publicAbi(flags, [ - 'getFlag', - 'getFlags', - 'lowerFlags', - 'raiseFlag', - 'raiseFlags', - 'raisingAccessController', - 'setRaisingAccessController', - // Ownable methods: - 'acceptOwnership', - 'owner', - 'transferOwnership', - // AccessControl methods: - 'addAccess', - 'disableAccessCheck', - 'enableAccessCheck', - 'removeAccess', - 'checkEnabled', - 'hasAccess', - ]) - }) - - describe('#raiseFlag', () => { - describe('when called by the owner', () => { - it('updates the warning flag', async () => { - assert.equal(false, await flags.getFlag(consumer.address)) - - await flags.connect(personas.Nelly).raiseFlag(consumer.address) - - assert.equal(true, await flags.getFlag(consumer.address)) - }) - - it('emits an event log', async () => { - await expect(flags.connect(personas.Nelly).raiseFlag(consumer.address)) - .to.emit(flags, 'FlagRaised') - .withArgs(consumer.address) - }) - - describe('if a flag has already been raised', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).raiseFlag(consumer.address) - }) - - it('emits an event log', async () => { - const tx = await flags - .connect(personas.Nelly) - .raiseFlag(consumer.address) - const receipt = await tx.wait() - assert.equal(0, receipt.events?.length) - }) - }) - }) - - describe('when called by an enabled setter', () => { - beforeEach(async () => { - await controller - .connect(personas.Nelly) - .addAccess(await personas.Neil.getAddress()) - }) - - it('sets the flags', async () => { - await flags.connect(personas.Neil).raiseFlag(consumer.address), - assert.equal(true, await flags.getFlag(consumer.address)) - }) - }) - - describe('when called by a non-enabled setter', () => { - it('reverts', async () => { - await expect( - flags.connect(personas.Neil).raiseFlag(consumer.address), - ).to.be.revertedWith('Not allowed to raise flags') - }) - }) - - describe('when called when there is no raisingAccessController', () => { - beforeEach(async () => { - await expect( - flags - .connect(personas.Nelly) - .setRaisingAccessController( - '0x0000000000000000000000000000000000000000', - ), - ).to.emit(flags, 'RaisingAccessControllerUpdated') - assert.equal( - '0x0000000000000000000000000000000000000000', - await flags.raisingAccessController(), - ) - }) - - it('succeeds for the owner', async () => { - await flags.connect(personas.Nelly).raiseFlag(consumer.address) - assert.equal(true, await flags.getFlag(consumer.address)) - }) - - it('reverts for non-owner', async () => { - await expect(flags.connect(personas.Neil).raiseFlag(consumer.address)) - .to.be.reverted - }) - }) - }) - - describe('#raiseFlags', () => { - describe('when called by the owner', () => { - it('updates the warning flag', async () => { - assert.equal(false, await flags.getFlag(consumer.address)) - - await flags.connect(personas.Nelly).raiseFlags([consumer.address]) - - assert.equal(true, await flags.getFlag(consumer.address)) - }) - - it('emits an event log', async () => { - await expect( - flags.connect(personas.Nelly).raiseFlags([consumer.address]), - ) - .to.emit(flags, 'FlagRaised') - .withArgs(consumer.address) - }) - - describe('if a flag has already been raised', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).raiseFlags([consumer.address]) - }) - - it('emits an event log', async () => { - const tx = await flags - .connect(personas.Nelly) - .raiseFlags([consumer.address]) - const receipt = await tx.wait() - assert.equal(0, receipt.events?.length) - }) - }) - }) - - describe('when called by an enabled setter', () => { - beforeEach(async () => { - await controller - .connect(personas.Nelly) - .addAccess(await personas.Neil.getAddress()) - }) - - it('sets the flags', async () => { - await flags.connect(personas.Neil).raiseFlags([consumer.address]), - assert.equal(true, await flags.getFlag(consumer.address)) - }) - }) - - describe('when called by a non-enabled setter', () => { - it('reverts', async () => { - await expect( - flags.connect(personas.Neil).raiseFlags([consumer.address]), - ).to.be.revertedWith('Not allowed to raise flags') - }) - }) - - describe('when called when there is no raisingAccessController', () => { - beforeEach(async () => { - await expect( - flags - .connect(personas.Nelly) - .setRaisingAccessController( - '0x0000000000000000000000000000000000000000', - ), - ).to.emit(flags, 'RaisingAccessControllerUpdated') - - assert.equal( - '0x0000000000000000000000000000000000000000', - await flags.raisingAccessController(), - ) - }) - - it('succeeds for the owner', async () => { - await flags.connect(personas.Nelly).raiseFlags([consumer.address]) - assert.equal(true, await flags.getFlag(consumer.address)) - }) - - it('reverts for non-owners', async () => { - await expect( - flags.connect(personas.Neil).raiseFlags([consumer.address]), - ).to.be.reverted - }) - }) - }) - - describe('#lowerFlags', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).raiseFlags([consumer.address]) - }) - - describe('when called by the owner', () => { - it('updates the warning flag', async () => { - assert.equal(true, await flags.getFlag(consumer.address)) - - await flags.connect(personas.Nelly).lowerFlags([consumer.address]) - - assert.equal(false, await flags.getFlag(consumer.address)) - }) - - it('emits an event log', async () => { - await expect( - flags.connect(personas.Nelly).lowerFlags([consumer.address]), - ) - .to.emit(flags, 'FlagLowered') - .withArgs(consumer.address) - }) - - describe('if a flag has already been raised', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).lowerFlags([consumer.address]) - }) - - it('emits an event log', async () => { - const tx = await flags - .connect(personas.Nelly) - .lowerFlags([consumer.address]) - const receipt = await tx.wait() - assert.equal(0, receipt.events?.length) - }) - }) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - flags.connect(personas.Neil).lowerFlags([consumer.address]), - ).to.be.revertedWith('Only callable by owner') - }) - }) - }) - - describe('#getFlag', () => { - describe('if the access control is turned on', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).enableAccessCheck() - }) - - it('reverts', async () => { - await expect(consumer.getFlag(consumer.address)).to.be.revertedWith( - 'No access', - ) - }) - - describe('if access is granted to the address', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).addAccess(consumer.address) - }) - - it('does not revert', async () => { - await consumer.getFlag(consumer.address) - }) - }) - }) - - describe('if the access control is turned off', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).disableAccessCheck() - }) - - it('does not revert', async () => { - await consumer.getFlag(consumer.address) - }) - - describe('if access is granted to the address', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).addAccess(consumer.address) - }) - - it('does not revert', async () => { - await consumer.getFlag(consumer.address) - }) - }) - }) - }) - - describe('#getFlags', () => { - beforeEach(async () => { - await flags.connect(personas.Nelly).disableAccessCheck() - await flags - .connect(personas.Nelly) - .raiseFlags([ - await personas.Neil.getAddress(), - await personas.Norbert.getAddress(), - ]) - }) - - it('respects the access controls of #getFlag', async () => { - await flags.connect(personas.Nelly).enableAccessCheck() - - await expect(consumer.getFlag(consumer.address)).to.be.revertedWith( - 'No access', - ) - - await flags.connect(personas.Nelly).addAccess(consumer.address) - - await consumer.getFlag(consumer.address) - }) - - it('returns the flags in the order they are requested', async () => { - const response = await consumer.getFlags([ - await personas.Nelly.getAddress(), - await personas.Neil.getAddress(), - await personas.Ned.getAddress(), - await personas.Norbert.getAddress(), - ]) - - assert.deepEqual([false, true, false, true], response) - }) - }) - - describe('#setRaisingAccessController', () => { - let controller2: Contract - - beforeEach(async () => { - controller2 = await controllerFactory.connect(personas.Nelly).deploy() - await controller2.connect(personas.Nelly).enableAccessCheck() - }) - - it('updates access control rules', async () => { - const neilAddress = await personas.Neil.getAddress() - await controller.connect(personas.Nelly).addAccess(neilAddress) - await flags.connect(personas.Neil).raiseFlags([consumer.address]) // doesn't raise - - await flags - .connect(personas.Nelly) - .setRaisingAccessController(controller2.address) - - await expect( - flags.connect(personas.Neil).raiseFlags([consumer.address]), - ).to.be.revertedWith('Not allowed to raise flags') - }) - - it('emits a log announcing the change', async () => { - await expect( - flags - .connect(personas.Nelly) - .setRaisingAccessController(controller2.address), - ) - .to.emit(flags, 'RaisingAccessControllerUpdated') - .withArgs(controller.address, controller2.address) - }) - - it('does not emit a log when there is no change', async () => { - await flags - .connect(personas.Nelly) - .setRaisingAccessController(controller2.address) - - await expect( - flags - .connect(personas.Nelly) - .setRaisingAccessController(controller2.address), - ).to.not.emit(flags, 'RaisingAccessControllerUpdated') - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - flags - .connect(personas.Neil) - .setRaisingAccessController(controller2.address), - ).to.be.revertedWith('Only callable by owner') - }) - }) - }) -}) diff --git a/contracts/test/v0.6/FluxAggregator.test.ts b/contracts/test/v0.6/FluxAggregator.test.ts deleted file mode 100644 index 5a268ceebe..0000000000 --- a/contracts/test/v0.6/FluxAggregator.test.ts +++ /dev/null @@ -1,3252 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { - Signer, - Contract, - ContractFactory, - BigNumber, - BigNumberish, - ContractTransaction, - constants, -} from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { bigNumEquals, evmRevert } from '../test-helpers/matchers' -import { - publicAbi, - toWei, - increaseTimeBy, - mineBlock, - evmWordToAddress, -} from '../test-helpers/helpers' -import { randomBytes } from '@ethersproject/random' -import { fail } from 'assert' - -let personas: Personas -let linkTokenFactory: ContractFactory -let fluxAggregatorFactory: ContractFactory -let validatorMockFactory: ContractFactory -let testHelperFactory: ContractFactory -let validatorFactory: ContractFactory -let flagsFactory: ContractFactory -let acFactory: ContractFactory -let gasGuzzlerFactory: ContractFactory -let emptyAddress: string - -before(async () => { - personas = (await getUsers()).personas - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - fluxAggregatorFactory = await ethers.getContractFactory( - 'src/v0.6/FluxAggregator.sol:FluxAggregator', - ) - validatorMockFactory = await ethers.getContractFactory( - 'src/v0.6/tests/AggregatorValidatorMock.sol:AggregatorValidatorMock', - ) - testHelperFactory = await ethers.getContractFactory( - 'src/v0.6/tests/FluxAggregatorTestHelper.sol:FluxAggregatorTestHelper', - ) - validatorFactory = await ethers.getContractFactory( - 'src/v0.6/DeviationFlaggingValidator.sol:DeviationFlaggingValidator', - ) - flagsFactory = await ethers.getContractFactory('src/v0.6/Flags.sol:Flags') - acFactory = await ethers.getContractFactory( - 'src/v0.6/SimpleWriteAccessController.sol:SimpleWriteAccessController', - ) - gasGuzzlerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/GasGuzzler.sol:GasGuzzler', - ) - emptyAddress = constants.AddressZero -}) - -describe('FluxAggregator', () => { - const paymentAmount = toWei('3') - const deposit = toWei('100') - const answer = 100 - const minAns = 1 - const maxAns = 1 - const rrDelay = 0 - const timeout = 1800 - const decimals = 18 - const description = 'LINK/USD' - const reserveRounds = 2 - const minSubmissionValue = BigNumber.from('1') - const maxSubmissionValue = BigNumber.from('100000000000000000000') - - let aggregator: Contract - let link: Contract - let testHelper: Contract - let validator: Contract - let gasGuzzler: Contract - let nextRound: number - let oracles: Signer[] - - async function updateFutureRounds( - aggregator: Contract, - overrides: { - minAnswers?: BigNumberish - maxAnswers?: BigNumberish - payment?: BigNumberish - restartDelay?: BigNumberish - timeout?: BigNumberish - } = {}, - ) { - overrides = overrides || {} - const round = { - payment: overrides.payment || paymentAmount, - minAnswers: overrides.minAnswers || minAns, - maxAnswers: overrides.maxAnswers || maxAns, - restartDelay: overrides.restartDelay || rrDelay, - timeout: overrides.timeout || timeout, - } - - return aggregator.updateFutureRounds( - round.payment, - round.minAnswers, - round.maxAnswers, - round.restartDelay, - round.timeout, - ) - } - - async function addOracles( - aggregator: Contract, - oraclesAndAdmin: Signer[], - minAnswers: number, - maxAnswers: number, - restartDelay: number, - ): Promise { - return aggregator.connect(personas.Carol).changeOracles( - [], - oraclesAndAdmin.map(async (oracle) => await oracle.getAddress()), - oraclesAndAdmin.map(async (admin) => await admin.getAddress()), - minAnswers, - maxAnswers, - restartDelay, - ) - } - - async function advanceRound( - aggregator: Contract, - submitters: Signer[], - currentSubmission: number = answer, - ): Promise { - for (const submitter of submitters) { - await aggregator.connect(submitter).submit(nextRound, currentSubmission) - } - nextRound++ - return nextRound - } - - const ShouldBeSet = 'expects it to be different' - const ShouldNotBeSet = 'expects it to equal' - let startingState: any - - async function checkOracleRoundState( - state: any, - want: { - eligibleToSubmit: boolean - roundId: BigNumberish - latestSubmission: BigNumberish - startedAt: string - timeout: BigNumberish - availableFunds: BigNumberish - oracleCount: BigNumberish - paymentAmount: BigNumberish - }, - ) { - assert.equal( - want.eligibleToSubmit, - state._eligibleToSubmit, - 'round state: unexecpted eligibility', - ) - bigNumEquals( - want.roundId, - state._roundId, - 'round state: unexpected Round ID', - ) - bigNumEquals( - want.latestSubmission, - state._latestSubmission, - 'round state: unexpected latest submission', - ) - if (want.startedAt === ShouldBeSet) { - assert.isAbove( - state._startedAt.toNumber(), - startingState._startedAt.toNumber(), - 'round state: expected the started at to be the same as previous', - ) - } else { - bigNumEquals( - 0, - state._startedAt, - 'round state: expected the started at not to be updated', - ) - } - bigNumEquals( - want.timeout, - state._timeout.toNumber(), - 'round state: unexepcted timeout', - ) - bigNumEquals( - want.availableFunds, - state._availableFunds, - 'round state: unexepected funds', - ) - bigNumEquals( - want.oracleCount, - state._oracleCount, - 'round state: unexpected oracle count', - ) - bigNumEquals( - want.paymentAmount, - state._paymentAmount, - 'round state: unexpected paymentamount', - ) - } - - beforeEach(async () => { - link = await linkTokenFactory.connect(personas.Default).deploy() - aggregator = await fluxAggregatorFactory - .connect(personas.Carol) - .deploy( - link.address, - paymentAmount, - timeout, - emptyAddress, - minSubmissionValue, - maxSubmissionValue, - decimals, - ethers.utils.formatBytes32String(description), - ) - await link.transfer(aggregator.address, deposit) - await aggregator.updateAvailableFunds() - bigNumEquals(deposit, await link.balanceOf(aggregator.address)) - nextRound = 1 - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(aggregator, [ - 'acceptAdmin', - 'allocatedFunds', - 'availableFunds', - 'changeOracles', - 'decimals', - 'description', - 'getAdmin', - 'getAnswer', - 'getOracles', - 'getRoundData', - 'getTimestamp', - 'latestAnswer', - 'latestRound', - 'latestRoundData', - 'latestTimestamp', - 'linkToken', - 'maxSubmissionCount', - 'maxSubmissionValue', - 'minSubmissionCount', - 'minSubmissionValue', - 'onTokenTransfer', - 'oracleCount', - 'oracleRoundState', - 'paymentAmount', - 'requestNewRound', - 'restartDelay', - 'setRequesterPermissions', - 'setValidator', - 'submit', - 'timeout', - 'transferAdmin', - 'updateAvailableFunds', - 'updateFutureRounds', - 'withdrawFunds', - 'withdrawPayment', - 'withdrawablePayment', - 'validator', - 'version', - // Owned methods: - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('#constructor', () => { - it('sets the paymentAmount', async () => { - bigNumEquals( - BigNumber.from(paymentAmount), - await aggregator.paymentAmount(), - ) - }) - - it('sets the timeout', async () => { - bigNumEquals(BigNumber.from(timeout), await aggregator.timeout()) - }) - - it('sets the decimals', async () => { - bigNumEquals(BigNumber.from(decimals), await aggregator.decimals()) - }) - - it('sets the description', async () => { - assert.equal( - ethers.utils.formatBytes32String(description), - await aggregator.description(), - ) - }) - - it('sets the version to 3', async () => { - bigNumEquals(3, await aggregator.version()) - }) - - it('sets the validator', async () => { - assert.equal(emptyAddress, await aggregator.validator()) - }) - }) - - describe('#submit', () => { - let minMax - - beforeEach(async () => { - oracles = [personas.Neil, personas.Ned, personas.Nelly] - minMax = oracles.length - await addOracles(aggregator, oracles, minMax, minMax, rrDelay) - }) - - it('updates the allocated and available funds counters', async () => { - bigNumEquals(0, await aggregator.allocatedFunds()) - - const tx = await aggregator - .connect(personas.Neil) - .submit(nextRound, answer) - const receipt = await tx.wait() - - bigNumEquals(paymentAmount, await aggregator.allocatedFunds()) - const expectedAvailable = deposit.sub(paymentAmount) - bigNumEquals(expectedAvailable, await aggregator.availableFunds()) - const logged = BigNumber.from( - receipt.logs?.[2].topics[1] ?? BigNumber.from(-1), - ) - bigNumEquals(expectedAvailable, logged) - }) - - it('emits a log event announcing submission details', async () => { - await expect(aggregator.connect(personas.Nelly).submit(nextRound, answer)) - .to.emit(aggregator, 'SubmissionReceived') - .withArgs(answer, nextRound, await personas.Nelly.getAddress()) - }) - - describe('when the minimum oracles have not reported', () => { - it('pays the oracles that have reported', async () => { - bigNumEquals( - 0, - await aggregator - .connect(personas.Neil) - .withdrawablePayment(await personas.Neil.getAddress()), - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - - bigNumEquals( - paymentAmount, - await aggregator - .connect(personas.Neil) - .withdrawablePayment(await personas.Neil.getAddress()), - ) - bigNumEquals( - 0, - await aggregator - .connect(personas.Ned) - .withdrawablePayment(await personas.Ned.getAddress()), - ) - bigNumEquals( - 0, - await aggregator - .connect(personas.Nelly) - .withdrawablePayment(await personas.Nelly.getAddress()), - ) - }) - - it('does not update the answer', async () => { - bigNumEquals(ethers.constants.Zero, await aggregator.latestAnswer()) - - // Not updated because of changes by the owner setting minSubmissionCount to 3 - await aggregator.connect(personas.Ned).submit(nextRound, answer) - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - - bigNumEquals(ethers.constants.Zero, await aggregator.latestAnswer()) - }) - }) - - describe('when an oracle prematurely bumps the round', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { minAnswers: 2, maxAnswers: 3 }) - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - - it('reverts', async () => { - await evmRevert( - aggregator.connect(personas.Neil).submit(nextRound + 1, answer), - 'previous round not supersedable', - ) - }) - }) - - describe('when the minimum number of oracles have reported', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { minAnswers: 2, maxAnswers: 3 }) - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - - it('updates the answer with the median', async () => { - bigNumEquals(0, await aggregator.latestAnswer()) - - await aggregator.connect(personas.Ned).submit(nextRound, 99) - bigNumEquals(99, await aggregator.latestAnswer()) // ((100+99) / 2).to_i - - await aggregator.connect(personas.Nelly).submit(nextRound, 101) - - bigNumEquals(100, await aggregator.latestAnswer()) - }) - - it('updates the updated timestamp', async () => { - const originalTimestamp = await aggregator.latestTimestamp() - assert.isAbove(originalTimestamp.toNumber(), 0) - - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - - const currentTimestamp = await aggregator.latestTimestamp() - assert.isAbove( - currentTimestamp.toNumber(), - originalTimestamp.toNumber(), - ) - }) - - it('announces the new answer with a log event', async () => { - const tx = await aggregator - .connect(personas.Nelly) - .submit(nextRound, answer) - const receipt = await tx.wait() - - const newAnswer = BigNumber.from( - receipt.logs?.[0].topics[1] ?? ethers.constants.Zero, - ) - - assert.equal(answer, newAnswer.toNumber()) - }) - - it('does not set the timedout flag', async () => { - evmRevert(aggregator.getRoundData(nextRound), 'No data present') - - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - - const round = await aggregator.getRoundData(nextRound) - assert.equal(nextRound, round.answeredInRound.toNumber()) - }) - - it('updates the round details', async () => { - evmRevert(aggregator.latestRoundData(), 'No data present') - - increaseTimeBy(15, ethers.provider) - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - - const roundAfter = await aggregator.getRoundData(nextRound) - bigNumEquals(nextRound, roundAfter.roundId) - bigNumEquals(answer, roundAfter.answer) - assert.isFalse(roundAfter.startedAt.isZero()) - bigNumEquals( - await aggregator.getTimestamp(nextRound), - roundAfter.updatedAt, - ) - bigNumEquals(nextRound, roundAfter.answeredInRound) - - assert.isBelow( - roundAfter.startedAt.toNumber(), - roundAfter.updatedAt.toNumber(), - ) - - const roundAfterLatest = await aggregator.latestRoundData() - bigNumEquals(roundAfter.roundId, roundAfterLatest.roundId) - bigNumEquals(roundAfter.answer, roundAfterLatest.answer) - bigNumEquals(roundAfter.startedAt, roundAfterLatest.startedAt) - bigNumEquals(roundAfter.updatedAt, roundAfterLatest.updatedAt) - bigNumEquals( - roundAfter.answeredInRound, - roundAfterLatest.answeredInRound, - ) - }) - }) - - describe('when an oracle submits for a round twice', () => { - it('reverts', async () => { - await aggregator.connect(personas.Neil).submit(nextRound, answer) - - await evmRevert( - aggregator.connect(personas.Neil).submit(nextRound, answer), - 'cannot report on previous rounds', - ) - }) - }) - - describe('when updated after the max answers submitted', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator) - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - - it('reverts', async () => { - await evmRevert( - aggregator.connect(personas.Ned).submit(nextRound, answer), - 'round not accepting submissions', - ) - }) - }) - - describe('when a new highest round number is passed in', () => { - it('increments the answer round', async () => { - const startingState = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - bigNumEquals(1, startingState._roundId) - - await advanceRound(aggregator, oracles) - - const updatedState = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - bigNumEquals(2, updatedState._roundId) - }) - - it('sets the startedAt time for the reporting round', async () => { - evmRevert(aggregator.getRoundData(nextRound), 'No data present') - - const tx = await aggregator - .connect(oracles[0]) - .submit(nextRound, answer) - await aggregator.connect(oracles[1]).submit(nextRound, answer) - await aggregator.connect(oracles[2]).submit(nextRound, answer) - const receipt = await tx.wait() - const block = await ethers.provider.getBlock(receipt.blockHash ?? '') - - const round = await aggregator.getRoundData(nextRound) - bigNumEquals(BigNumber.from(block.timestamp), round.startedAt) - }) - - it('announces a new round by emitting a log', async () => { - const tx = await aggregator - .connect(personas.Neil) - .submit(nextRound, answer) - const receipt = await tx.wait() - - const topics = receipt.logs?.[0].topics ?? [] - const roundNumber = BigNumber.from(topics[1]) - const startedBy = evmWordToAddress(topics[2]) - - bigNumEquals(nextRound, roundNumber.toNumber()) - bigNumEquals(startedBy, await personas.Neil.getAddress()) - }) - }) - - describe('when a round is passed in higher than expected', () => { - it('reverts', async () => { - await evmRevert( - aggregator.connect(personas.Neil).submit(nextRound + 1, answer), - 'invalid round to report', - ) - }) - }) - - describe('when called by a non-oracle', () => { - it('reverts', async () => { - await evmRevert( - aggregator.connect(personas.Carol).submit(nextRound, answer), - 'not enabled oracle', - ) - }) - }) - - describe('when there are not sufficient available funds', () => { - beforeEach(async () => { - await aggregator - .connect(personas.Carol) - .withdrawFunds( - await personas.Carol.getAddress(), - deposit.sub(paymentAmount.mul(oracles.length).mul(reserveRounds)), - ) - - // drain remaining funds - await advanceRound(aggregator, oracles) - await advanceRound(aggregator, oracles) - }) - - it('reverts', async () => { - await evmRevert( - aggregator.connect(personas.Neil).submit(nextRound, answer), - 'SafeMath: subtraction overflow', - ) - }) - }) - - describe('when a new round opens before the previous rounds closes', () => { - beforeEach(async () => { - oracles = [personas.Nancy, personas.Norbert] - await addOracles(aggregator, oracles, 3, 4, rrDelay) - await advanceRound(aggregator, [ - personas.Nelly, - personas.Neil, - personas.Nancy, - ]) - - // start the next round - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - }) - - it('still allows the previous round to be answered', async () => { - await aggregator.connect(personas.Ned).submit(nextRound - 1, answer) - }) - - describe('once the current round is answered', () => { - beforeEach(async () => { - oracles = [personas.Neil, personas.Nancy] - for (let i = 0; i < oracles.length; i++) { - await aggregator.connect(oracles[i]).submit(nextRound, answer) - } - }) - - it('does not allow reports for the previous round', async () => { - await evmRevert( - aggregator.connect(personas.Ned).submit(nextRound - 1, answer), - 'invalid round to report', - ) - }) - }) - - describe('when the previous round has finished', () => { - beforeEach(async () => { - await aggregator - .connect(personas.Norbert) - .submit(nextRound - 1, answer) - }) - - it('does not allow reports for the previous round', async () => { - await evmRevert( - aggregator.connect(personas.Ned).submit(nextRound - 1, answer), - 'round not accepting submissions', - ) - }) - }) - }) - - describe('when price is updated mid-round', () => { - const newAmount = toWei('50') - - it('pays the same amount to all oracles per round', async () => { - await link.transfer( - aggregator.address, - newAmount.mul(oracles.length).mul(reserveRounds), - ) - await aggregator.updateAvailableFunds() - - bigNumEquals( - 0, - await aggregator - .connect(personas.Neil) - .withdrawablePayment(await personas.Neil.getAddress()), - ) - bigNumEquals( - 0, - await aggregator - .connect(personas.Nelly) - .withdrawablePayment(await personas.Nelly.getAddress()), - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - - await updateFutureRounds(aggregator, { payment: newAmount }) - - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - - bigNumEquals( - paymentAmount, - await aggregator - .connect(personas.Neil) - .withdrawablePayment(await personas.Neil.getAddress()), - ) - bigNumEquals( - paymentAmount, - await aggregator - .connect(personas.Nelly) - .withdrawablePayment(await personas.Nelly.getAddress()), - ) - }) - }) - - describe('when delay is on', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { - minAnswers: oracles.length, - maxAnswers: oracles.length, - restartDelay: 1, - }) - }) - - it("does not revert on the oracle's first round", async () => { - // Since lastUpdatedRound defaults to zero and that's the only - // indication that an oracle hasn't responded, this test guards against - // the situation where we don't check that and no one can start a round. - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - - it('does revert before the delay', async () => { - await aggregator.connect(personas.Neil).submit(nextRound, answer) - - nextRound++ - - await evmRevert( - aggregator.connect(personas.Neil).submit(nextRound, answer), - 'previous round not supersedable', - ) - }) - }) - - describe('when an oracle starts a round before the restart delay is over', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator.connect(personas.Carol), { - minAnswers: 1, - maxAnswers: 1, - }) - - oracles = [personas.Neil, personas.Ned, personas.Nelly] - for (let i = 0; i < oracles.length; i++) { - await aggregator.connect(oracles[i]).submit(nextRound, answer) - nextRound++ - } - - const newDelay = 2 - // Since Ned and Nelly have answered recently, and we set the delay - // to 2, only Nelly can answer as she is the only oracle that hasn't - // started the last two rounds. - await updateFutureRounds(aggregator, { - maxAnswers: oracles.length, - restartDelay: newDelay, - }) - }) - - describe('when called by an oracle who has not answered recently', () => { - it('does not revert', async () => { - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - }) - - describe('when called by an oracle who answered recently', () => { - it('reverts', async () => { - await evmRevert( - aggregator.connect(personas.Ned).submit(nextRound, answer), - 'round not accepting submissions', - ) - - await evmRevert( - aggregator.connect(personas.Nelly).submit(nextRound, answer), - 'round not accepting submissions', - ) - }) - }) - }) - - describe('when the price is not updated for a round', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { - minAnswers: oracles.length, - maxAnswers: oracles.length, - restartDelay: 1, - }) - - for (const oracle of oracles) { - await aggregator.connect(oracle).submit(nextRound, answer) - } - nextRound++ - - await aggregator.connect(personas.Ned).submit(nextRound, answer) - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - - await increaseTimeBy(timeout + 1, ethers.provider) - nextRound++ - }) - - it('allows a new round to be started', async () => { - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - }) - - it('sets the info for the previous round', async () => { - const previousRound = nextRound - 1 - let updated = await aggregator.getTimestamp(previousRound) - let ans = await aggregator.getAnswer(previousRound) - assert.equal(0, updated.toNumber()) - assert.equal(0, ans.toNumber()) - - const tx = await aggregator - .connect(personas.Nelly) - .submit(nextRound, answer) - const receipt = await tx.wait() - - const block = await ethers.provider.getBlock(receipt.blockHash ?? '') - - updated = await aggregator.getTimestamp(previousRound) - ans = await aggregator.getAnswer(previousRound) - bigNumEquals(BigNumber.from(block.timestamp), updated) - assert.equal(answer, ans.toNumber()) - - const round = await aggregator.getRoundData(previousRound) - bigNumEquals(previousRound, round.roundId) - bigNumEquals(ans, round.answer) - bigNumEquals(updated, round.updatedAt) - bigNumEquals(previousRound - 1, round.answeredInRound) - }) - - it('sets the previous round as timed out', async () => { - const previousRound = nextRound - 1 - evmRevert(aggregator.getRoundData(previousRound), 'No data present') - - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - - const round = await aggregator.getRoundData(previousRound) - assert.notEqual(round.roundId, round.answeredInRound) - bigNumEquals(previousRound - 1, round.answeredInRound) - }) - - it('still respects the delay restriction', async () => { - // expected to revert because the sender started the last round - await evmRevert( - aggregator.connect(personas.Ned).submit(nextRound, answer), - ) - }) - - it('uses the timeout set at the beginning of the round', async () => { - await updateFutureRounds(aggregator, { - timeout: timeout + 100000, - }) - - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - }) - }) - - describe('submitting values near the edges of allowed values', () => { - it('rejects values below the submission value range', async () => { - await evmRevert( - aggregator - .connect(personas.Neil) - .submit(nextRound, minSubmissionValue.sub(1)), - 'value below minSubmissionValue', - ) - }) - - it('accepts submissions equal to the min submission value', async () => { - await aggregator - .connect(personas.Neil) - .submit(nextRound, minSubmissionValue) - }) - - it('accepts submissions equal to the max submission value', async () => { - await aggregator - .connect(personas.Neil) - .submit(nextRound, maxSubmissionValue) - }) - - it('rejects submissions equal to the max submission value', async () => { - await evmRevert( - aggregator - .connect(personas.Neil) - .submit(nextRound, maxSubmissionValue.add(1)), - 'value above maxSubmissionValue', - ) - }) - }) - - describe('when a validator is set', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { minAnswers: 1, maxAnswers: 1 }) - oracles = [personas.Nelly] - - validator = await validatorMockFactory.connect(personas.Carol).deploy() - await aggregator.connect(personas.Carol).setValidator(validator.address) - }) - - it('calls out to the validator', async () => { - await expect( - aggregator.connect(personas.Nelly).submit(nextRound, answer), - ) - .to.emit(validator, 'Validated') - .withArgs(0, 0, nextRound, answer) - }) - }) - - describe('when the answer validator eats all gas', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { minAnswers: 1, maxAnswers: 1 }) - oracles = [personas.Nelly] - - gasGuzzler = await gasGuzzlerFactory.connect(personas.Carol).deploy() - await aggregator - .connect(personas.Carol) - .setValidator(gasGuzzler.address) - assert.equal(gasGuzzler.address, await aggregator.validator()) - }) - - it('still updates', async () => { - bigNumEquals(0, await aggregator.latestAnswer()) - - await aggregator - .connect(personas.Nelly) - .submit(nextRound, answer, { gasLimit: 500000 }) - - bigNumEquals(answer, await aggregator.latestAnswer()) - }) - }) - }) - - describe('#getAnswer', () => { - const answers = [1, 10, 101, 1010, 10101, 101010, 1010101] - - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - - for (const answer of answers) { - await aggregator.connect(personas.Neil).submit(nextRound++, answer) - } - }) - - it('retrieves the answer recorded for past rounds', async () => { - for (let i = nextRound; i < nextRound; i++) { - const answer = await aggregator.getAnswer(i) - bigNumEquals(BigNumber.from(answers[i - 1]), answer) - } - }) - - it("returns 0 for answers greater than uint32's max", async () => { - const overflowedId = BigNumber.from(2).pow(32).add(1) - const answer = await aggregator.getAnswer(overflowedId) - bigNumEquals(0, answer) - }) - }) - - describe('#getTimestamp', () => { - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - - for (let i = 0; i < 10; i++) { - await aggregator.connect(personas.Neil).submit(nextRound++, i + 1) - } - }) - - it('retrieves the answer recorded for past rounds', async () => { - let lastTimestamp = ethers.constants.Zero - - for (let i = 1; i < nextRound; i++) { - const currentTimestamp = await aggregator.getTimestamp(i) - assert.isAtLeast(currentTimestamp.toNumber(), lastTimestamp.toNumber()) - lastTimestamp = currentTimestamp - } - }) - - it("returns 0 for answers greater than uint32's max", async () => { - const overflowedId = BigNumber.from(2).pow(32).add(1) - const answer = await aggregator.getTimestamp(overflowedId) - bigNumEquals(0, answer) - }) - }) - - describe('#changeOracles', () => { - describe('adding oracles', () => { - it('increases the oracle count', async () => { - const pastCount = await aggregator.oracleCount() - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - const currentCount = await aggregator.oracleCount() - - bigNumEquals(currentCount, pastCount + 1) - }) - - it('adds the address in getOracles', async () => { - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - assert.deepEqual( - [await personas.Neil.getAddress()], - await aggregator.getOracles(), - ) - }) - - it('updates the round details', async () => { - await addOracles( - aggregator, - [personas.Neil, personas.Ned, personas.Nelly], - 1, - 3, - 2, - ) - bigNumEquals(1, await aggregator.minSubmissionCount()) - bigNumEquals(3, await aggregator.maxSubmissionCount()) - bigNumEquals(2, await aggregator.restartDelay()) - }) - - it('emits a log', async () => { - const tx = await aggregator - .connect(personas.Carol) - .changeOracles( - [], - [await personas.Ned.getAddress()], - [await personas.Neil.getAddress()], - 1, - 1, - 0, - ) - expect(tx) - .to.emit(aggregator, 'OraclePermissionsUpdated') - .withArgs(await personas.Ned.getAddress(), true) - - expect(tx) - .to.emit(aggregator, 'OracleAdminUpdated') - .withArgs( - await personas.Ned.getAddress(), - await personas.Neil.getAddress(), - ) - }) - - describe('when the oracle has already been added', () => { - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - }) - - it('reverts', async () => { - await evmRevert( - addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay), - 'oracle already enabled', - ) - }) - }) - - describe('when called by anyone but the owner', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Neil) - .changeOracles( - [], - [await personas.Neil.getAddress()], - [await personas.Neil.getAddress()], - minAns, - maxAns, - rrDelay, - ), - 'Only callable by owner', - ) - }) - }) - - describe('when an oracle gets added mid-round', () => { - beforeEach(async () => { - oracles = [personas.Neil, personas.Ned] - await addOracles( - aggregator, - oracles, - oracles.length, - oracles.length, - rrDelay, - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - - await addOracles( - aggregator, - [personas.Nelly], - oracles.length + 1, - oracles.length + 1, - rrDelay, - ) - }) - - it('does not allow the oracle to update the round', async () => { - await evmRevert( - aggregator.connect(personas.Nelly).submit(nextRound, answer), - 'not yet enabled oracle', - ) - }) - - it('does allow the oracle to update future rounds', async () => { - // complete round - await aggregator.connect(personas.Ned).submit(nextRound, answer) - - // now can participate in new rounds - await aggregator.connect(personas.Nelly).submit(nextRound + 1, answer) - }) - }) - - describe('when an oracle is added after removed for a round', () => { - it('allows the oracle to update', async () => { - oracles = [personas.Neil, personas.Nelly] - await addOracles( - aggregator, - oracles, - oracles.length, - oracles.length, - rrDelay, - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - nextRound++ - - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Nelly.getAddress()], - [], - [], - 1, - 1, - rrDelay, - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - nextRound++ - - await addOracles(aggregator, [personas.Nelly], 1, 1, rrDelay) - - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - }) - }) - - describe('when an oracle is added and immediately removed mid-round', () => { - it('allows the oracle to update', async () => { - await addOracles( - aggregator, - oracles, - oracles.length, - oracles.length, - rrDelay, - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - nextRound++ - - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Nelly.getAddress()], - [], - [], - 1, - 1, - rrDelay, - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - nextRound++ - - await addOracles(aggregator, [personas.Nelly], 1, 1, rrDelay) - - await aggregator.connect(personas.Nelly).submit(nextRound, answer) - }) - }) - - describe('when an oracle is re-added with a different admin address', () => { - it('reverts', async () => { - await addOracles( - aggregator, - oracles, - oracles.length, - oracles.length, - rrDelay, - ) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Nelly.getAddress()], - [], - [], - 1, - 1, - rrDelay, - ) - - await evmRevert( - aggregator - .connect(personas.Carol) - .changeOracles( - [], - [await personas.Nelly.getAddress()], - [await personas.Carol.getAddress()], - 1, - 1, - rrDelay, - ), - 'owner cannot overwrite admin', - ) - }) - }) - - const limit = 77 - describe(`when adding more than ${limit} oracles`, () => { - let oracles: Signer[] - - beforeEach(async () => { - oracles = [] - for (let i = 0; i < limit; i++) { - const account = await new ethers.Wallet( - randomBytes(32), - ethers.provider, - ) - await personas.Default.sendTransaction({ - to: account.address, - value: toWei('0.1'), - }) - - oracles.push(account) - } - - await link.transfer( - aggregator.address, - paymentAmount.mul(limit).mul(reserveRounds), - ) - await aggregator.updateAvailableFunds() - - let addresses = oracles.slice(0, 50).map(async (o) => o.getAddress()) - await aggregator - .connect(personas.Carol) - .changeOracles([], addresses, addresses, 1, 50, rrDelay) - // add in two transactions to avoid gas limit issues - addresses = oracles.slice(50, 100).map(async (o) => o.getAddress()) - await aggregator - .connect(personas.Carol) - .changeOracles([], addresses, addresses, 1, oracles.length, rrDelay) - }) - - it('not use too much gas [ @skip-coverage ]', async () => { - let tx: any - assert.deepEqual( - // test adveserial quickselect algo - [2, 4, 6, 8, 10, 12, 14, 16, 1, 9, 5, 11, 3, 13, 7, 15], - adverserialQuickselectList(16), - ) - const inputs = adverserialQuickselectList(limit) - for (let i = 0; i < limit; i++) { - tx = await aggregator - .connect(oracles[i]) - .submit(nextRound, inputs[i]) - } - assert.isTrue(!!tx) - if (tx) { - const receipt = await tx.wait() - assert.isBelow(receipt.gasUsed.toNumber(), 600_000) - } - }) - - function adverserialQuickselectList(len: number): number[] { - const xs: number[] = [] - const pi: number[] = [] - for (let i = 0; i < len; i++) { - pi[i] = i - xs[i] = 0 - } - - for (let l = len; l > 0; l--) { - const pivot = Math.floor((l - 1) / 2) - xs[pi[pivot]] = l - const temp = pi[l - 1] - pi[l - 1] = pi[pivot] - pi[pivot] = temp - } - return xs - } - - it('reverts when another oracle is added', async () => { - await evmRevert( - aggregator - .connect(personas.Carol) - .changeOracles( - [], - [await personas.Neil.getAddress()], - [await personas.Neil.getAddress()], - limit + 1, - limit + 1, - rrDelay, - ), - 'max oracles allowed', - ) - }) - }) - - it('reverts when minSubmissions is set to 0', async () => { - await evmRevert( - addOracles(aggregator, [personas.Neil], 0, 0, 0), - 'min must be greater than 0', - ) - }) - }) - - describe('removing oracles', () => { - beforeEach(async () => { - oracles = [personas.Neil, personas.Nelly] - await addOracles( - aggregator, - oracles, - oracles.length, - oracles.length, - rrDelay, - ) - }) - - it('decreases the oracle count', async () => { - const pastCount = await aggregator.oracleCount() - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ) - const currentCount = await aggregator.oracleCount() - - expect(currentCount).to.equal(pastCount - 1) - }) - - it('updates the round details', async () => { - await aggregator - .connect(personas.Carol) - .changeOracles([await personas.Neil.getAddress()], [], [], 1, 1, 0) - - bigNumEquals(1, await aggregator.minSubmissionCount()) - bigNumEquals(1, await aggregator.maxSubmissionCount()) - bigNumEquals(ethers.constants.Zero, await aggregator.restartDelay()) - }) - - it('emits a log', async () => { - await expect( - aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ), - ) - .to.emit(aggregator, 'OraclePermissionsUpdated') - .withArgs(await personas.Neil.getAddress(), false) - }) - - it('removes the address in getOracles', async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ) - assert.deepEqual( - [await personas.Nelly.getAddress()], - await aggregator.getOracles(), - ) - }) - - describe('when the oracle is not currently added', () => { - beforeEach(async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ) - }) - - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ), - 'oracle not enabled', - ) - }) - }) - - describe('when removing the last oracle', () => { - it('does not revert', async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ) - - await aggregator - .connect(personas.Carol) - .changeOracles([await personas.Nelly.getAddress()], [], [], 0, 0, 0) - }) - }) - - describe('when called by anyone but the owner', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Ned) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - 0, - 0, - rrDelay, - ), - 'Only callable by owner', - ) - }) - }) - - describe('when an oracle gets removed', () => { - beforeEach(async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Nelly.getAddress()], - [], - [], - 1, - 1, - rrDelay, - ) - }) - - it('is allowed to report on one more round', async () => { - // next round - await advanceRound(aggregator, [personas.Nelly]) - // finish round - await advanceRound(aggregator, [personas.Neil]) - - // cannot participate in future rounds - await evmRevert( - aggregator.connect(personas.Nelly).submit(nextRound, answer), - 'no longer allowed oracle', - ) - }) - }) - - describe('when an oracle gets removed mid-round', () => { - beforeEach(async () => { - await aggregator.connect(personas.Neil).submit(nextRound, answer) - - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Nelly.getAddress()], - [], - [], - 1, - 1, - rrDelay, - ) - }) - - it('is allowed to finish that round and one more round', async () => { - await advanceRound(aggregator, [personas.Nelly]) // finish round - - await advanceRound(aggregator, [personas.Nelly]) // next round - - // cannot participate in future rounds - await evmRevert( - aggregator.connect(personas.Nelly).submit(nextRound, answer), - 'no longer allowed oracle', - ) - }) - }) - - it('reverts when minSubmissions is set to 0', async () => { - await evmRevert( - aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Nelly.getAddress()], - [], - [], - 0, - 0, - 0, - ), - 'min must be greater than 0', - ) - }) - }) - - describe('adding and removing oracles at once', () => { - beforeEach(async () => { - oracles = [personas.Neil, personas.Ned] - await addOracles(aggregator, oracles, 1, 1, rrDelay) - }) - - it('can swap out oracles', async () => { - assert.include( - await aggregator.getOracles(), - await personas.Ned.getAddress(), - ) - assert.notInclude( - await aggregator.getOracles(), - await personas.Nelly.getAddress(), - ) - - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Ned.getAddress()], - [await personas.Nelly.getAddress()], - [await personas.Nelly.getAddress()], - 1, - 1, - rrDelay, - ) - - assert.notInclude( - await aggregator.getOracles(), - await personas.Ned.getAddress(), - ) - assert.include( - await aggregator.getOracles(), - await personas.Nelly.getAddress(), - ) - }) - - it('is possible to remove and add the same address', async () => { - assert.include( - await aggregator.getOracles(), - await personas.Ned.getAddress(), - ) - - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Ned.getAddress()], - [await personas.Ned.getAddress()], - [await personas.Ned.getAddress()], - 1, - 1, - rrDelay, - ) - - assert.include( - await aggregator.getOracles(), - await personas.Ned.getAddress(), - ) - }) - }) - }) - - describe('#getOracles', () => { - describe('after adding oracles', () => { - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - - assert.deepEqual( - [await personas.Neil.getAddress()], - await aggregator.getOracles(), - ) - }) - - it('returns the addresses of added oracles', async () => { - await addOracles(aggregator, [personas.Ned], minAns, maxAns, rrDelay) - - assert.deepEqual( - [await personas.Neil.getAddress(), await personas.Ned.getAddress()], - await aggregator.getOracles(), - ) - - await addOracles(aggregator, [personas.Nelly], minAns, maxAns, rrDelay) - assert.deepEqual( - [ - await personas.Neil.getAddress(), - await personas.Ned.getAddress(), - await personas.Nelly.getAddress(), - ], - await aggregator.getOracles(), - ) - }) - }) - - describe('after removing oracles', () => { - beforeEach(async () => { - await addOracles( - aggregator, - [personas.Neil, personas.Ned, personas.Nelly], - minAns, - maxAns, - rrDelay, - ) - - assert.deepEqual( - [ - await personas.Neil.getAddress(), - await personas.Ned.getAddress(), - await personas.Nelly.getAddress(), - ], - await aggregator.getOracles(), - ) - }) - - it('reorders when removing from the beginning', async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Neil.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ) - assert.deepEqual( - [await personas.Nelly.getAddress(), await personas.Ned.getAddress()], - await aggregator.getOracles(), - ) - }) - - it('reorders when removing from the middle', async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Ned.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ) - assert.deepEqual( - [await personas.Neil.getAddress(), await personas.Nelly.getAddress()], - await aggregator.getOracles(), - ) - }) - - it('pops the last node off at the end', async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [await personas.Nelly.getAddress()], - [], - [], - minAns, - maxAns, - rrDelay, - ) - assert.deepEqual( - [await personas.Neil.getAddress(), await personas.Ned.getAddress()], - await aggregator.getOracles(), - ) - }) - }) - }) - - describe('#withdrawFunds', () => { - it('succeeds', async () => { - await aggregator - .connect(personas.Carol) - .withdrawFunds(await personas.Carol.getAddress(), deposit) - - bigNumEquals(0, await aggregator.availableFunds()) - bigNumEquals( - deposit, - await link.balanceOf(await personas.Carol.getAddress()), - ) - }) - - it('does not let withdrawals happen multiple times', async () => { - await aggregator - .connect(personas.Carol) - .withdrawFunds(await personas.Carol.getAddress(), deposit) - - await evmRevert( - aggregator - .connect(personas.Carol) - .withdrawFunds(await personas.Carol.getAddress(), deposit), - 'insufficient reserve funds', - ) - }) - - describe('with a number higher than the available LINK balance', () => { - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - - it('fails', async () => { - await evmRevert( - aggregator - .connect(personas.Carol) - .withdrawFunds(await personas.Carol.getAddress(), deposit), - 'insufficient reserve funds', - ) - - bigNumEquals( - deposit.sub(paymentAmount), - await aggregator.availableFunds(), - ) - }) - }) - - describe('with oracles still present', () => { - beforeEach(async () => { - oracles = [personas.Neil, personas.Ned, personas.Nelly] - await addOracles(aggregator, oracles, 1, 1, rrDelay) - - bigNumEquals(deposit, await aggregator.availableFunds()) - }) - - it('does not allow withdrawal with less than 2x rounds of payments', async () => { - const oracleReserve = paymentAmount - .mul(oracles.length) - .mul(reserveRounds) - const allowed = deposit.sub(oracleReserve) - - //one more than the allowed amount cannot be withdrawn - await evmRevert( - aggregator - .connect(personas.Carol) - .withdrawFunds(await personas.Carol.getAddress(), allowed.add(1)), - 'insufficient reserve funds', - ) - - // the allowed amount can be withdrawn - await aggregator - .connect(personas.Carol) - .withdrawFunds(await personas.Carol.getAddress(), allowed) - }) - }) - - describe('when called by a non-owner', () => { - it('fails', async () => { - await evmRevert( - aggregator - .connect(personas.Eddy) - .withdrawFunds(await personas.Carol.getAddress(), deposit), - 'Only callable by owner', - ) - - bigNumEquals(deposit, await aggregator.availableFunds()) - }) - }) - }) - - describe('#updateFutureRounds', () => { - let minSubmissionCount, maxSubmissionCount - const newPaymentAmount = toWei('2') - const newMin = 1 - const newMax = 3 - const newDelay = 2 - - beforeEach(async () => { - oracles = [personas.Neil, personas.Ned, personas.Nelly] - minSubmissionCount = oracles.length - maxSubmissionCount = oracles.length - await addOracles( - aggregator, - oracles, - minSubmissionCount, - maxSubmissionCount, - rrDelay, - ) - - bigNumEquals(paymentAmount, await aggregator.paymentAmount()) - assert.equal(minSubmissionCount, await aggregator.minSubmissionCount()) - assert.equal(maxSubmissionCount, await aggregator.maxSubmissionCount()) - }) - - it('updates the min and max answer counts', async () => { - await updateFutureRounds(aggregator, { - payment: newPaymentAmount, - minAnswers: newMin, - maxAnswers: newMax, - restartDelay: newDelay, - }) - - bigNumEquals(newPaymentAmount, await aggregator.paymentAmount()) - bigNumEquals( - BigNumber.from(newMin), - await aggregator.minSubmissionCount(), - ) - bigNumEquals( - BigNumber.from(newMax), - await aggregator.maxSubmissionCount(), - ) - bigNumEquals(BigNumber.from(newDelay), await aggregator.restartDelay()) - }) - - it('emits a log announcing the new round details', async () => { - await expect( - updateFutureRounds(aggregator, { - payment: newPaymentAmount, - minAnswers: newMin, - maxAnswers: newMax, - restartDelay: newDelay, - timeout: timeout + 1, - }), - ) - .to.emit(aggregator, 'RoundDetailsUpdated') - .withArgs(newPaymentAmount, newMin, newMax, newDelay, timeout + 1) - }) - - describe('when it is set to higher than the number or oracles', () => { - it('reverts', async () => { - await evmRevert( - updateFutureRounds(aggregator, { - maxAnswers: 4, - }), - 'max cannot exceed total', - ) - }) - }) - - describe('when it sets the min higher than the max', () => { - it('reverts', async () => { - await evmRevert( - updateFutureRounds(aggregator, { - minAnswers: 3, - maxAnswers: 2, - }), - 'max must equal/exceed min', - ) - }) - }) - - describe('when delay equal or greater the oracle count', () => { - it('reverts', async () => { - await evmRevert( - updateFutureRounds(aggregator, { - restartDelay: 3, - }), - 'delay cannot exceed total', - ) - }) - }) - - describe('when the payment amount does not cover reserve rounds', () => { - beforeEach(async () => {}) - - it('reverts', async () => { - const most = deposit.div(oracles.length * reserveRounds) - - // Relaxed check for the revert message due to a bug in ethers where any error message - // that starts with insufficient funds will be incorrectly returned as 'insufficient funds for intrinsic transaction cost' - await updateFutureRounds(aggregator, { - payment: most.add(1), - }).then( - () => { - // onFulfillment callback - fail('expected to revert but did not') - }, - (error: any) => { - // onRejected callback - const message = - error instanceof Object && 'message' in error - ? error.message - : JSON.stringify(error) - assert.isTrue(message.includes('insufficient funds')) - }, - ) - - await updateFutureRounds(aggregator, { - payment: most, - }) - }) - }) - - describe('min oracles is set to 0', () => { - it('reverts', async () => { - await evmRevert( - aggregator.updateFutureRounds(paymentAmount, 0, 0, rrDelay, timeout), - 'min must be greater than 0', - ) - }) - }) - - describe('when called by anyone but the owner', () => { - it('reverts', async () => { - await evmRevert( - updateFutureRounds(aggregator.connect(personas.Ned)), - 'Only callable by owner', - ) - }) - }) - }) - - describe('#updateAvailableFunds', () => { - it('checks the LINK token to see if any additional funds are available', async () => { - const originalBalance = await aggregator.availableFunds() - - await aggregator.updateAvailableFunds() - - bigNumEquals(originalBalance, await aggregator.availableFunds()) - - await link.transfer(aggregator.address, deposit) - await aggregator.updateAvailableFunds() - - const newBalance = await aggregator.availableFunds() - bigNumEquals(originalBalance.add(deposit), newBalance) - }) - - it('removes allocated funds from the available balance', async () => { - const originalBalance = await aggregator.availableFunds() - - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - await aggregator.connect(personas.Neil).submit(nextRound, answer) - await link.transfer(aggregator.address, deposit) - await aggregator.updateAvailableFunds() - - const expected = originalBalance.add(deposit).sub(paymentAmount) - const newBalance = await aggregator.availableFunds() - bigNumEquals(expected, newBalance) - }) - - it('emits a log', async () => { - await link.transfer(aggregator.address, deposit) - - const tx = await aggregator.updateAvailableFunds() - const receipt = await tx.wait() - - const reportedBalance = BigNumber.from(receipt.logs?.[0].topics[1] ?? -1) - bigNumEquals(await aggregator.availableFunds(), reportedBalance) - }) - - describe('when the available funds have not changed', () => { - it('does not emit a log', async () => { - const tx = await aggregator.updateAvailableFunds() - const receipt = await tx.wait() - - assert.equal(0, receipt.logs?.length) - }) - }) - }) - - describe('#withdrawPayment', () => { - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], minAns, maxAns, rrDelay) - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - - it('transfers LINK to the recipient', async () => { - const originalBalance = await link.balanceOf(aggregator.address) - bigNumEquals(0, await link.balanceOf(await personas.Neil.getAddress())) - - await aggregator - .connect(personas.Neil) - .withdrawPayment( - await personas.Neil.getAddress(), - await personas.Neil.getAddress(), - paymentAmount, - ) - - bigNumEquals( - originalBalance.sub(paymentAmount), - await link.balanceOf(aggregator.address), - ) - bigNumEquals( - paymentAmount, - await link.balanceOf(await personas.Neil.getAddress()), - ) - }) - - it('decrements the allocated funds counter', async () => { - const originalAllocation = await aggregator.allocatedFunds() - - await aggregator - .connect(personas.Neil) - .withdrawPayment( - await personas.Neil.getAddress(), - await personas.Neil.getAddress(), - paymentAmount, - ) - - bigNumEquals( - originalAllocation.sub(paymentAmount), - await aggregator.allocatedFunds(), - ) - }) - - describe('when the caller withdraws more than they have', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Neil) - .withdrawPayment( - await personas.Neil.getAddress(), - await personas.Neil.getAddress(), - paymentAmount.add(BigNumber.from(1)), - ), - 'insufficient withdrawable funds', - ) - }) - }) - - describe('when the caller is not the admin', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Nelly) - .withdrawPayment( - await personas.Neil.getAddress(), - await personas.Nelly.getAddress(), - BigNumber.from(1), - ), - 'only callable by admin', - ) - }) - }) - }) - - describe('#transferAdmin', () => { - beforeEach(async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [], - [await personas.Ned.getAddress()], - [await personas.Neil.getAddress()], - minAns, - maxAns, - rrDelay, - ) - }) - - describe('when the admin tries to transfer the admin', () => { - it('works', async () => { - await expect( - aggregator - .connect(personas.Neil) - .transferAdmin( - await personas.Ned.getAddress(), - await personas.Nelly.getAddress(), - ), - ) - .to.emit(aggregator, 'OracleAdminUpdateRequested') - .withArgs( - await personas.Ned.getAddress(), - await personas.Neil.getAddress(), - await personas.Nelly.getAddress(), - ) - assert.equal( - await personas.Neil.getAddress(), - await aggregator.getAdmin(await personas.Ned.getAddress()), - ) - }) - }) - - describe('when the non-admin owner tries to update the admin', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Carol) - .transferAdmin( - await personas.Ned.getAddress(), - await personas.Nelly.getAddress(), - ), - 'only callable by admin', - ) - }) - }) - - describe('when the non-admin oracle tries to update the admin', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Ned) - .transferAdmin( - await personas.Ned.getAddress(), - await personas.Nelly.getAddress(), - ), - 'only callable by admin', - ) - }) - }) - }) - - describe('#acceptAdmin', () => { - beforeEach(async () => { - await aggregator - .connect(personas.Carol) - .changeOracles( - [], - [await personas.Ned.getAddress()], - [await personas.Neil.getAddress()], - minAns, - maxAns, - rrDelay, - ) - const tx = await aggregator - .connect(personas.Neil) - .transferAdmin( - await personas.Ned.getAddress(), - await personas.Nelly.getAddress(), - ) - await tx.wait() - }) - - describe('when the new admin tries to accept', () => { - it('works', async () => { - await expect( - aggregator - .connect(personas.Nelly) - .acceptAdmin(await personas.Ned.getAddress()), - ) - .to.emit(aggregator, 'OracleAdminUpdated') - .withArgs( - await personas.Ned.getAddress(), - await personas.Nelly.getAddress(), - ) - assert.equal( - await personas.Nelly.getAddress(), - await aggregator.getAdmin(await personas.Ned.getAddress()), - ) - }) - }) - - describe('when someone other than the new admin tries to accept', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Ned) - .acceptAdmin(await personas.Ned.getAddress()), - 'only callable by pending admin', - ) - await evmRevert( - aggregator - .connect(personas.Neil) - .acceptAdmin(await personas.Ned.getAddress()), - 'only callable by pending admin', - ) - }) - }) - }) - - describe('#onTokenTransfer', () => { - it('updates the available balance', async () => { - const originalBalance = await aggregator.availableFunds() - - await aggregator.updateAvailableFunds() - - bigNumEquals(originalBalance, await aggregator.availableFunds()) - - await link.transferAndCall(aggregator.address, deposit, '0x') - - const newBalance = await aggregator.availableFunds() - bigNumEquals(originalBalance.add(deposit), newBalance) - }) - - it('reverts given calldata', async () => { - await evmRevert( - // error message is not bubbled up by link token - link.transferAndCall(aggregator.address, deposit, '0x12345678'), - ) - }) - }) - - describe('#requestNewRound', () => { - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], 1, 1, 0) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - nextRound = nextRound + 1 - - await aggregator.setRequesterPermissions( - await personas.Carol.getAddress(), - true, - 0, - ) - }) - - it('announces a new round via log event', async () => { - await expect(aggregator.requestNewRound()).to.emit(aggregator, 'NewRound') - }) - - it('returns the new round ID', async () => { - testHelper = await testHelperFactory.connect(personas.Carol).deploy() - await aggregator.setRequesterPermissions(testHelper.address, true, 0) - let roundId = await testHelper.requestedRoundId() - assert.equal(roundId.toNumber(), 0) - - await testHelper.requestNewRound(aggregator.address) - - // return value captured by test helper - roundId = await testHelper.requestedRoundId() - assert.isAbove(roundId.toNumber(), 0) - }) - - describe('when there is a round in progress', () => { - beforeEach(async () => { - await aggregator.requestNewRound() - }) - - it('reverts', async () => { - await evmRevert( - aggregator.requestNewRound(), - 'prev round must be supersedable', - ) - }) - - describe('when that round has timed out', () => { - beforeEach(async () => { - await increaseTimeBy(timeout + 1, ethers.provider) - await mineBlock(ethers.provider) - }) - - it('starts a new round', async () => { - await expect(aggregator.requestNewRound()).to.emit( - aggregator, - 'NewRound', - ) - }) - }) - }) - - describe('when there is a restart delay set', () => { - beforeEach(async () => { - await aggregator.setRequesterPermissions( - await personas.Eddy.getAddress(), - true, - 1, - ) - }) - - it('reverts if a round is started before the delay', async () => { - await aggregator.connect(personas.Eddy).requestNewRound() - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - nextRound = nextRound + 1 - - // Eddy can't start because of the delay - await evmRevert( - aggregator.connect(personas.Eddy).requestNewRound(), - 'must delay requests', - ) - // Carol starts a new round instead - await aggregator.connect(personas.Carol).requestNewRound() - - // round completes - await aggregator.connect(personas.Neil).submit(nextRound, answer) - nextRound = nextRound + 1 - - // now Eddy can start again - await aggregator.connect(personas.Eddy).requestNewRound() - }) - }) - - describe('when all oracles have been removed and then re-added', () => { - it('does not get stuck', async () => { - await aggregator - .connect(personas.Carol) - .changeOracles([await personas.Neil.getAddress()], [], [], 0, 0, 0) - - // advance a few rounds - for (let i = 0; i < 7; i++) { - await aggregator.requestNewRound() - nextRound = nextRound + 1 - await increaseTimeBy(timeout + 1, ethers.provider) - await mineBlock(ethers.provider) - } - - await addOracles(aggregator, [personas.Neil], 1, 1, 0) - await aggregator.connect(personas.Neil).submit(nextRound, answer) - }) - }) - }) - - describe('#setRequesterPermissions', () => { - beforeEach(async () => { - await addOracles(aggregator, [personas.Neil], 1, 1, 0) - - await aggregator.connect(personas.Neil).submit(nextRound, answer) - nextRound = nextRound + 1 - }) - - describe('when called by the owner', () => { - it('allows the specified address to start new rounds', async () => { - await aggregator.setRequesterPermissions( - await personas.Neil.getAddress(), - true, - 0, - ) - - await aggregator.connect(personas.Neil).requestNewRound() - }) - - it('emits a log announcing the update', async () => { - await expect( - aggregator.setRequesterPermissions( - await personas.Neil.getAddress(), - true, - 0, - ), - ) - .to.emit(aggregator, 'RequesterPermissionsSet') - .withArgs(await personas.Neil.getAddress(), true, 0) - }) - - describe('when the address is already authorized', () => { - beforeEach(async () => { - await aggregator.setRequesterPermissions( - await personas.Neil.getAddress(), - true, - 0, - ) - }) - - it('does not emit a log for already authorized accounts', async () => { - const tx = await aggregator.setRequesterPermissions( - await personas.Neil.getAddress(), - true, - 0, - ) - const receipt = await tx.wait() - assert.equal(0, receipt?.logs?.length) - }) - }) - - describe('when permission is removed by the owner', () => { - beforeEach(async () => { - await aggregator.setRequesterPermissions( - await personas.Neil.getAddress(), - true, - 0, - ) - }) - - it('does not allow the specified address to start new rounds', async () => { - await aggregator.setRequesterPermissions( - await personas.Neil.getAddress(), - false, - 0, - ) - - await evmRevert( - aggregator.connect(personas.Neil).requestNewRound(), - 'not authorized requester', - ) - }) - - it('emits a log announcing the update', async () => { - await expect( - aggregator.setRequesterPermissions( - await personas.Neil.getAddress(), - false, - 0, - ), - ) - .to.emit(aggregator, 'RequesterPermissionsSet') - .withArgs(await personas.Neil.getAddress(), false, 0) - }) - - it('does not emit a log for accounts without authorization', async () => { - const tx = await aggregator.setRequesterPermissions( - await personas.Ned.getAddress(), - false, - 0, - ) - const receipt = await tx.wait() - assert.equal(0, receipt?.logs?.length) - }) - }) - }) - - describe('when called by a stranger', () => { - it('reverts', async () => { - await evmRevert( - aggregator - .connect(personas.Neil) - .setRequesterPermissions(await personas.Neil.getAddress(), true, 0), - 'Only callable by owner', - ) - - await evmRevert( - aggregator.connect(personas.Neil).requestNewRound(), - 'not authorized requester', - ) - }) - }) - }) - - describe('#oracleRoundState', () => { - describe('when round ID 0 is passed in', () => { - const previousSubmission = 42 - let baseFunds: any - let minAnswers: number - let maxAnswers: number - let submitters: Signer[] - - beforeEach(async () => { - oracles = [ - personas.Neil, - personas.Ned, - personas.Nelly, - personas.Nancy, - personas.Norbert, - ] - minAnswers = 3 - maxAnswers = 4 - - await addOracles(aggregator, oracles, minAnswers, maxAnswers, rrDelay) - submitters = [ - personas.Nelly, - personas.Ned, - personas.Neil, - personas.Nancy, - ] - await advanceRound(aggregator, submitters, previousSubmission) - baseFunds = BigNumber.from(deposit).sub( - paymentAmount.mul(submitters.length), - ) - startingState = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - }) - - it('returns all of the important round information', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 2, - latestSubmission: previousSubmission, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds, - oracleCount: oracles.length, - paymentAmount, - }) - }) - - it('reverts if called by a contract', async () => { - testHelper = await testHelperFactory.connect(personas.Carol).deploy() - await evmRevert( - testHelper.readOracleRoundState( - aggregator.address, - await personas.Neil.getAddress(), - ), - 'off-chain reading only', - ) - }) - - describe('when the restart delay is not enforced', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { - minAnswers, - maxAnswers, - restartDelay: 0, - }) - }) - - describe('< min submissions and oracle not included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [personas.Neil]) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 2, - latestSubmission: previousSubmission, - startedAt: ShouldBeSet, - timeout, - availableFunds: baseFunds.sub(paymentAmount), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - - describe('< min submissions and oracle included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [personas.Nelly]) - }) - - it('is not eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 2, - latestSubmission: answer, - startedAt: ShouldBeSet, - timeout, - availableFunds: baseFunds.sub(paymentAmount), - oracleCount: oracles.length, - paymentAmount, - }) - }) - - describe('and timed out', () => { - beforeEach(async () => { - await increaseTimeBy(timeout + 1, ethers.provider) - await mineBlock(ethers.provider) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - - describe('>= min submissions and oracle not included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [ - personas.Neil, - personas.Nancy, - personas.Ned, - ]) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 2, - latestSubmission: previousSubmission, - startedAt: ShouldBeSet, - timeout, - availableFunds: baseFunds.sub(paymentAmount.mul(3)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - - describe('>= min submissions and oracle included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [ - personas.Neil, - personas.Nelly, - personas.Ned, - ]) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(3)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - - describe('and timed out', () => { - beforeEach(async () => { - await increaseTimeBy(timeout + 1, ethers.provider) - await mineBlock(ethers.provider) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(3)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - - describe('max submissions and oracle not included', () => { - beforeEach(async () => { - submitters = [ - personas.Neil, - personas.Ned, - personas.Nancy, - personas.Norbert, - ] - assert.equal( - submitters.length, - maxAnswers, - 'precondition, please update submitters if maxAnswers changes', - ) - await advanceRound(aggregator, submitters) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 3, - latestSubmission: previousSubmission, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(4)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - - describe('max submissions and oracle included', () => { - beforeEach(async () => { - submitters = [ - personas.Neil, - personas.Ned, - personas.Nelly, - personas.Nancy, - ] - assert.equal( - submitters.length, - maxAnswers, - 'precondition, please update submitters if maxAnswers changes', - ) - await advanceRound(aggregator, submitters) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(4)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - - describe('when the restart delay is enforced', () => { - beforeEach(async () => { - await updateFutureRounds(aggregator, { - minAnswers, - maxAnswers, - restartDelay: maxAnswers - 1, - }) - }) - - describe('< min submissions and oracle not included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [personas.Neil, personas.Ned]) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 2, - latestSubmission: previousSubmission, - startedAt: ShouldBeSet, - timeout, - availableFunds: baseFunds.sub(paymentAmount.mul(2)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - - describe('< min submissions and oracle included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [personas.Neil, personas.Nelly]) - }) - - it('is not eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 2, - latestSubmission: answer, - startedAt: ShouldBeSet, - timeout, - availableFunds: baseFunds.sub(paymentAmount.mul(2)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - - describe('and timed out', () => { - beforeEach(async () => { - await increaseTimeBy(timeout + 1, ethers.provider) - await mineBlock(ethers.provider) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(2)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - - describe('>= min submissions and oracle not included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [ - personas.Neil, - personas.Ned, - personas.Nancy, - ]) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 2, - latestSubmission: previousSubmission, - startedAt: ShouldBeSet, - timeout, - availableFunds: baseFunds.sub(paymentAmount.mul(3)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - - describe('>= min submissions and oracle included', () => { - beforeEach(async () => { - await advanceRound(aggregator, [ - personas.Neil, - personas.Ned, - personas.Nelly, - ]) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(3)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - - describe('and timed out', () => { - beforeEach(async () => { - await increaseTimeBy(timeout + 1, ethers.provider) - await mineBlock(ethers.provider) - }) - - it('is eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, // restart delay enforced - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(3)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - - describe('max submissions and oracle not included', () => { - beforeEach(async () => { - submitters = [ - personas.Neil, - personas.Ned, - personas.Nancy, - personas.Norbert, - ] - assert.equal( - submitters.length, - maxAnswers, - 'precondition, please update submitters if maxAnswers changes', - ) - await advanceRound(aggregator, submitters, answer) - }) - - it('is not eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 3, - latestSubmission: previousSubmission, - startedAt: ShouldNotBeSet, - timeout: 0, // details have been deleted - availableFunds: baseFunds.sub(paymentAmount.mul(4)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - - describe('max submissions and oracle included', () => { - beforeEach(async () => { - submitters = [ - personas.Neil, - personas.Ned, - personas.Nelly, - personas.Nancy, - ] - assert.equal( - submitters.length, - maxAnswers, - 'precondition, please update submitters if maxAnswers changes', - ) - await advanceRound(aggregator, submitters, answer) - }) - - it('is not eligible to submit', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 3, - latestSubmission: answer, - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: baseFunds.sub(paymentAmount.mul(4)), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - }) - - describe('when non-zero round ID 0 is passed in', () => { - const answers = [0, 42, 47, 52, 57] - let currentFunds: any - - beforeEach(async () => { - oracles = [personas.Neil, personas.Ned, personas.Nelly] - - await addOracles(aggregator, oracles, 2, 3, rrDelay) - startingState = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 0, - ) - await advanceRound(aggregator, oracles, answers[1]) - await advanceRound( - aggregator, - [personas.Neil, personas.Ned], - answers[2], - ) - await advanceRound(aggregator, oracles, answers[3]) - await advanceRound(aggregator, [personas.Neil], answers[4]) - const submissionsSoFar = 9 - currentFunds = BigNumber.from(deposit).sub( - paymentAmount.mul(submissionsSoFar), - ) - }) - - it('returns info about previous rounds', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 1, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 1, - latestSubmission: answers[3], - startedAt: ShouldBeSet, - timeout: 0, - availableFunds: currentFunds, - oracleCount: oracles.length, - paymentAmount: 0, - }) - }) - - it('returns info about previous rounds that were not submitted to', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 2, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 2, - latestSubmission: answers[3], - startedAt: ShouldBeSet, - timeout, - availableFunds: currentFunds, - oracleCount: oracles.length, - paymentAmount, - }) - }) - - describe('for the current round', () => { - describe('which has not been submitted to', () => { - it("returns info about the current round that hasn't been submitted to", async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 4, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 4, - latestSubmission: answers[3], - startedAt: ShouldBeSet, - timeout, - availableFunds: currentFunds, - oracleCount: oracles.length, - paymentAmount, - }) - }) - - it('returns info about the subsequent round', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 5, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 5, - latestSubmission: answers[3], - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: currentFunds, - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - - describe('which has been submitted to', () => { - beforeEach(async () => { - await aggregator.connect(personas.Nelly).submit(4, answers[4]) - }) - - it("returns info about the current round that hasn't been submitted to", async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 4, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 4, - latestSubmission: answers[4], - startedAt: ShouldBeSet, - timeout, - availableFunds: currentFunds.sub(paymentAmount), - oracleCount: oracles.length, - paymentAmount, - }) - }) - - it('returns info about the subsequent round', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 5, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: true, - roundId: 5, - latestSubmission: answers[4], - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: currentFunds.sub(paymentAmount), - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - - it('returns speculative info about future rounds', async () => { - const state = await aggregator.oracleRoundState( - await personas.Nelly.getAddress(), - 6, - ) - - await checkOracleRoundState(state, { - eligibleToSubmit: false, - roundId: 6, - latestSubmission: answers[3], - startedAt: ShouldNotBeSet, - timeout: 0, - availableFunds: currentFunds, - oracleCount: oracles.length, - paymentAmount, - }) - }) - }) - }) - - describe('#getRoundData', () => { - let latestRoundId: any - beforeEach(async () => { - oracles = [personas.Nelly] - const minMax = oracles.length - await addOracles(aggregator, oracles, minMax, minMax, rrDelay) - await advanceRound(aggregator, oracles, answer) - latestRoundId = await aggregator.latestRound() - }) - - it('returns the relevant round information', async () => { - const round = await aggregator.getRoundData(latestRoundId) - bigNumEquals(latestRoundId, round.roundId) - bigNumEquals(answer, round.answer) - const nowSeconds = new Date().valueOf() / 1000 - assert.isAbove(round.updatedAt.toNumber(), nowSeconds - 120) - bigNumEquals(round.updatedAt, round.startedAt) - bigNumEquals(latestRoundId, round.answeredInRound) - }) - - it('reverts if a round is not present', async () => { - await evmRevert( - aggregator.getRoundData(latestRoundId.add(1)), - 'No data present', - ) - }) - - it('reverts if a round ID is too big', async () => { - const overflowedId = BigNumber.from(2).pow(32).add(1) - - await evmRevert(aggregator.getRoundData(overflowedId), 'No data present') - }) - }) - - describe('#latestRoundData', () => { - beforeEach(async () => { - oracles = [personas.Nelly] - const minMax = oracles.length - await addOracles(aggregator, oracles, minMax, minMax, rrDelay) - }) - - describe('when an answer has already been received', () => { - beforeEach(async () => { - await advanceRound(aggregator, oracles, answer) - }) - - it('returns the relevant round info without reverting', async () => { - const round = await aggregator.latestRoundData() - const latestRoundId = await aggregator.latestRound() - - bigNumEquals(latestRoundId, round.roundId) - bigNumEquals(answer, round.answer) - const nowSeconds = new Date().valueOf() / 1000 - assert.isAbove(round.updatedAt.toNumber(), nowSeconds - 120) - bigNumEquals(round.updatedAt, round.startedAt) - bigNumEquals(latestRoundId, round.answeredInRound) - }) - }) - - it('reverts if a round is not present', async () => { - await evmRevert(aggregator.latestRoundData(), 'No data present') - }) - }) - - describe('#latestAnswer', () => { - beforeEach(async () => { - oracles = [personas.Nelly] - const minMax = oracles.length - await addOracles(aggregator, oracles, minMax, minMax, rrDelay) - }) - - describe('when an answer has already been received', () => { - beforeEach(async () => { - await advanceRound(aggregator, oracles, answer) - }) - - it('returns the latest answer without reverting', async () => { - bigNumEquals(answer, await aggregator.latestAnswer()) - }) - }) - - it('returns zero', async () => { - bigNumEquals(0, await aggregator.latestAnswer()) - }) - }) - - describe('#setValidator', () => { - beforeEach(async () => { - validator = await validatorMockFactory.connect(personas.Carol).deploy() - assert.equal(emptyAddress, await aggregator.validator()) - }) - - it('emits a log event showing the validator was changed', async () => { - await expect( - aggregator.connect(personas.Carol).setValidator(validator.address), - ) - .to.emit(aggregator, 'ValidatorUpdated') - .withArgs(emptyAddress, validator.address) - assert.equal(validator.address, await aggregator.validator()) - - await expect( - aggregator.connect(personas.Carol).setValidator(validator.address), - ).to.not.emit(aggregator, 'ValidatorUpdated') - assert.equal(validator.address, await aggregator.validator()) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - aggregator.connect(personas.Neil).setValidator(validator.address), - 'Only callable by owner', - ) - }) - }) - }) - - describe('integrating with historic deviation checker', () => { - let validator: Contract - let flags: Contract - let ac: Contract - const flaggingThreshold = 1000 // 1% - - beforeEach(async () => { - ac = await acFactory.connect(personas.Carol).deploy() - flags = await flagsFactory.connect(personas.Carol).deploy(ac.address) - validator = await validatorFactory - .connect(personas.Carol) - .deploy(flags.address, flaggingThreshold) - await ac.connect(personas.Carol).addAccess(validator.address) - - await aggregator.connect(personas.Carol).setValidator(validator.address) - - oracles = [personas.Nelly] - const minMax = oracles.length - await addOracles(aggregator, oracles, minMax, minMax, rrDelay) - }) - - it('raises a flag on with high enough deviation', async () => { - await aggregator.connect(personas.Nelly).submit(nextRound, 100) - nextRound++ - - await expect(aggregator.connect(personas.Nelly).submit(nextRound, 102)) - .to.emit(flags, 'FlagRaised') - .withArgs(aggregator.address) - }) - - it('does not raise a flag with low enough deviation', async () => { - await aggregator.connect(personas.Nelly).submit(nextRound, 100) - nextRound++ - - await expect( - aggregator.connect(personas.Nelly).submit(nextRound, 101), - ).to.not.emit(flags, 'FlagRaised') - }) - }) -}) diff --git a/contracts/test/v0.6/Median.test.ts b/contracts/test/v0.6/Median.test.ts deleted file mode 100644 index 8aea4722b6..0000000000 --- a/contracts/test/v0.6/Median.test.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { ethers } from 'hardhat' -import { assert } from 'chai' -import { Signer, Contract, ContractFactory, BigNumber } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { bigNumEquals } from '../test-helpers/matchers' - -let defaultAccount: Signer -let medianTestHelperFactory: ContractFactory -before(async () => { - const personas: Personas = (await getUsers()).personas - defaultAccount = personas.Default - medianTestHelperFactory = await ethers.getContractFactory( - 'src/v0.6/tests/MedianTestHelper.sol:MedianTestHelper', - defaultAccount, - ) -}) - -describe('Median', () => { - let median: Contract - - beforeEach(async () => { - median = await medianTestHelperFactory.connect(defaultAccount).deploy() - }) - - describe('testing various lists', () => { - const tests = [ - { - name: 'ordered ascending', - responses: [0, 1, 2, 3, 4, 5, 6, 7], - want: 3, - }, - { - name: 'ordered descending', - responses: [7, 6, 5, 4, 3, 2, 1, 0], - want: 3, - }, - { - name: 'unordered length 1', - responses: [20], - want: 20, - }, - { - name: 'unordered length 2', - responses: [20, 0], - want: 10, - }, - { - name: 'unordered length 3', - responses: [20, 0, 16], - want: 16, - }, - { - name: 'unordered length 4', - responses: [20, 0, 15, 16], - want: 15, - }, - { - name: 'unordered length 7', - responses: [1001, 1, 101, 10, 11, 0, 111], - want: 11, - }, - { - name: 'unordered length 9', - responses: [8, 8, 4, 5, 5, 7, 9, 5, 9], - want: 7, - }, - { - name: 'unordered long', - responses: [33, 44, 89, 101, 67, 7, 23, 55, 88, 324, 0, 88], - want: 61, // 67 + 55 / 2 - }, - { - name: 'unordered longer', - responses: [ - 333121, 323453, 337654, 345363, 345363, 333456, 335477, 333323, - 332352, 354648, 983260, 333856, 335468, 376987, 333253, 388867, - 337879, 333324, 338678, - ], - want: 335477, - }, - { - name: 'overflowing numbers', - responses: [ - BigNumber.from( - '57896044618658097711785492504343953926634992332820282019728792003956564819967', - ), - BigNumber.from( - '57896044618658097711785492504343953926634992332820282019728792003956564819967', - ), - ], - want: BigNumber.from( - '57896044618658097711785492504343953926634992332820282019728792003956564819967', - ), - }, - { - name: 'overflowing numbers', - responses: [ - BigNumber.from( - '57896044618658097711785492504343953926634992332820282019728792003956564819967', - ), - BigNumber.from( - '57896044618658097711785492504343953926634992332820282019728792003956564819966', - ), - ], - want: BigNumber.from( - '57896044618658097711785492504343953926634992332820282019728792003956564819966', - ), - }, - { - name: 'really long', - responses: [ - 56, 2, 31, 33, 55, 38, 35, 12, 41, 47, 21, 22, 40, 39, 10, 32, 49, 3, - 54, 45, 53, 14, 20, 59, 1, 30, 24, 6, 5, 37, 58, 51, 46, 17, 29, 7, - 27, 9, 43, 8, 34, 42, 28, 23, 57, 0, 11, 48, 52, 50, 15, 16, 26, 25, - 4, 36, 19, 44, 18, 13, - ], - want: 29, - }, - ] - - for (const test of tests) { - it(test.name, async () => { - bigNumEquals(test.want, await median.publicGet(test.responses)) - }) - } - }) - - // long running (minutes) exhaustive test. - // skipped because very slow, but useful for thorough validation - xit('permutations', async () => { - const permutations = (list: number[]) => { - const result: number[][] = [] - const used: number[] = [] - - const permute = (unused: number[]) => { - if (unused.length == 0) { - result.push([...used]) - return - } - - for (let i = 0; i < unused.length; i++) { - const elem = unused.splice(i, 1)[0] - used.push(elem) - permute(unused) - unused.splice(i, 0, elem) - used.pop() - } - } - - permute(list) - return result - } - - { - const list = [0, 2, 5, 7, 8, 10] - for (const permuted of permutations(list)) { - for (let i = 0; i < list.length; i++) { - for (let j = 0; j < list.length; j++) { - if (i < j) { - const foo = await median.publicQuickselectTwo(permuted, i, j) - bigNumEquals(list[i], foo[0]) - bigNumEquals(list[j], foo[1]) - } - } - } - } - } - - { - const list = [0, 1, 1, 1, 2] - for (const permuted of permutations(list)) { - for (let i = 0; i < list.length; i++) { - for (let j = 0; j < list.length; j++) { - if (i < j) { - const foo = await median.publicQuickselectTwo(permuted, i, j) - bigNumEquals(list[i], foo[0]) - bigNumEquals(list[j], foo[1]) - } - } - } - } - } - }) - - // Checks the validity of the sorting network in `shortList` - describe('validate sorting network', () => { - const net = [ - [0, 1], - [2, 3], - [4, 5], - [0, 2], - [1, 3], - [4, 6], - [1, 2], - [5, 6], - [0, 4], - [1, 5], - [2, 6], - [1, 4], - [3, 6], - [2, 4], - [3, 5], - [3, 4], - ] - - // See: https://en.wikipedia.org/wiki/Sorting_network#Zero-one_principle - xit('zero-one principle', async () => { - const sortWithNet = (list: number[]) => { - for (const [i, j] of net) { - if (list[i] > list[j]) { - ;[list[i], list[j]] = [list[j], list[i]] - } - } - } - - for (let n = 0; n < (1 << 7) - 1; n++) { - const list = [ - (n >> 6) & 1, - (n >> 5) & 1, - (n >> 4) & 1, - (n >> 3) & 1, - (n >> 2) & 1, - (n >> 1) & 1, - (n >> 0) & 1, - ] - const sum = list.reduce((a, b) => a + b, 0) - sortWithNet(list) - const sortedSum = list.reduce((a, b) => a + b, 0) - assert.equal(sortedSum, sum, 'Number of zeros and ones changed') - list.reduce((switched, i) => { - assert.isTrue(!switched || i != 0, 'error at n=' + n.toString()) - return i != 0 - }, false) - } - }) - }) -}) diff --git a/contracts/test/v0.6/Owned.test.ts b/contracts/test/v0.6/Owned.test.ts deleted file mode 100644 index f522b9c44c..0000000000 --- a/contracts/test/v0.6/Owned.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Signer, Contract, ContractFactory } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' - -let personas: Personas - -let owner: Signer -let nonOwner: Signer -let newOwner: Signer - -let ownedFactory: ContractFactory -let owned: Contract - -before(async () => { - personas = (await getUsers()).personas - owner = personas.Carol - nonOwner = personas.Neil - newOwner = personas.Ned - ownedFactory = await ethers.getContractFactory( - 'src/v0.6/Owned.sol:Owned', - owner, - ) -}) - -describe('Owned', () => { - beforeEach(async () => { - owned = await ownedFactory.connect(owner).deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', async () => { - publicAbi(owned, ['acceptOwnership', 'owner', 'transferOwnership']) - }) - - describe('#constructor', () => { - it('assigns ownership to the deployer', async () => { - const [actual, expected] = await Promise.all([ - owner.getAddress(), - owned.owner(), - ]) - - assert.equal(actual, expected) - }) - }) - - describe('#transferOwnership', () => { - describe('when called by an owner', () => { - it('emits a log', async () => { - await expect( - owned.connect(owner).transferOwnership(await newOwner.getAddress()), - ) - .to.emit(owned, 'OwnershipTransferRequested') - .withArgs(await owner.getAddress(), await newOwner.getAddress()) - }) - }) - }) - - describe('when called by anyone but the owner', () => { - it('reverts', async () => - await expect( - owned.connect(nonOwner).transferOwnership(await newOwner.getAddress()), - ).to.be.reverted) - }) - - describe('#acceptOwnership', () => { - describe('after #transferOwnership has been called', () => { - beforeEach(async () => { - await owned - .connect(owner) - .transferOwnership(await newOwner.getAddress()) - }) - - it('allows the recipient to call it', async () => { - await expect(owned.connect(newOwner).acceptOwnership()) - .to.emit(owned, 'OwnershipTransferred') - .withArgs(await owner.getAddress(), await newOwner.getAddress()) - }) - - it('does not allow a non-recipient to call it', async () => - await expect(owned.connect(nonOwner).acceptOwnership()).to.be.reverted) - }) - }) -}) diff --git a/contracts/test/v0.6/SignedSafeMath.test.ts b/contracts/test/v0.6/SignedSafeMath.test.ts deleted file mode 100644 index e942f64d6b..0000000000 --- a/contracts/test/v0.6/SignedSafeMath.test.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { Signer, Contract, ContractFactory, BigNumber } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { bigNumEquals } from '../test-helpers/matchers' - -let defaultAccount: Signer -let concreteSignedSafeMathFactory: ContractFactory - -before(async () => { - const personas: Personas = (await getUsers()).personas - defaultAccount = personas.Default - concreteSignedSafeMathFactory = await ethers.getContractFactory( - 'src/v0.6/tests/ConcreteSignedSafeMath.sol:ConcreteSignedSafeMath', - defaultAccount, - ) -}) - -describe('SignedSafeMath', () => { - // a version of the adder contract where we make all ABI exposed functions constant - // TODO: submit upstream PR to support constant contract type generation - let adder: Contract - let response: BigNumber - - const INT256_MAX = BigNumber.from( - '57896044618658097711785492504343953926634992332820282019728792003956564819967', - ) - const INT256_MIN = BigNumber.from( - '-57896044618658097711785492504343953926634992332820282019728792003956564819968', - ) - - beforeEach(async () => { - adder = await concreteSignedSafeMathFactory.connect(defaultAccount).deploy() - }) - - describe('#add', () => { - describe('given a positive and a positive', () => { - it('works', async () => { - response = await adder.testAdd(1, 2) - bigNumEquals(3, response) - }) - - it('works with zero', async () => { - response = await adder.testAdd(INT256_MAX, 0) - bigNumEquals(INT256_MAX, response) - }) - - describe('when both are large enough to overflow', () => { - it('throws', async () => { - await expect(adder.testAdd(INT256_MAX, 1)).to.be.revertedWith( - 'SignedSafeMath: addition overflow', - ) - }) - }) - }) - - describe('given a negative and a negative', () => { - it('works', async () => { - response = await adder.testAdd(-1, -2) - bigNumEquals(-3, response) - }) - - it('works with zero', async () => { - response = await adder.testAdd(INT256_MIN, 0) - bigNumEquals(INT256_MIN, response) - }) - - describe('when both are large enough to overflow', () => { - it('throws', async () => { - await expect(adder.testAdd(INT256_MIN, -1)).to.be.revertedWith( - 'SignedSafeMath: addition overflow', - ) - }) - }) - }) - - describe('given a positive and a negative', () => { - it('works', async () => { - response = await adder.testAdd(1, -2) - bigNumEquals(-1, response) - }) - }) - - describe('given a negative and a positive', () => { - it('works', async () => { - response = await adder.testAdd(-1, 2) - bigNumEquals(1, response) - }) - }) - }) - - describe('#avg', () => { - describe('given a positive and a positive', () => { - it('works', async () => { - response = await adder.testAvg(2, 4) - bigNumEquals(3, response) - }) - - it('works with zero', async () => { - response = await adder.testAvg(0, 4) - bigNumEquals(2, response) - response = await adder.testAvg(4, 0) - bigNumEquals(2, response) - }) - - it('works with large numbers', async () => { - response = await adder.testAvg(INT256_MAX, INT256_MAX) - bigNumEquals(INT256_MAX, response) - }) - - it('rounds towards zero', async () => { - response = await adder.testAvg(1, 2) - bigNumEquals(1, response) - }) - }) - - describe('given a negative and a negative', () => { - it('works', async () => { - response = await adder.testAvg(-2, -4) - bigNumEquals(-3, response) - }) - - it('works with zero', async () => { - response = await adder.testAvg(0, -4) - bigNumEquals(-2, response) - response = await adder.testAvg(-4, 0) - bigNumEquals(-2, response) - }) - - it('works with large numbers', async () => { - response = await adder.testAvg(INT256_MIN, INT256_MIN) - bigNumEquals(INT256_MIN, response) - }) - - it('rounds towards zero', async () => { - response = await adder.testAvg(-1, -2) - bigNumEquals(-1, response) - }) - }) - - describe('given a positive and a negative', () => { - it('works', async () => { - response = await adder.testAvg(2, -4) - bigNumEquals(-1, response) - response = await adder.testAvg(4, -2) - bigNumEquals(1, response) - }) - - it('works with large numbers', async () => { - response = await adder.testAvg(INT256_MAX, -2) - bigNumEquals(INT256_MAX.sub(2).div(2), response) - response = await adder.testAvg(INT256_MAX, INT256_MIN) - bigNumEquals(0, response) - }) - - it('rounds towards zero', async () => { - response = await adder.testAvg(1, -4) - bigNumEquals(-1, response) - response = await adder.testAvg(4, -1) - bigNumEquals(1, response) - }) - }) - - describe('given a negative and a positive', () => { - it('works', async () => { - response = await adder.testAvg(-2, 4) - bigNumEquals(1, response) - response = await adder.testAvg(-4, 2) - bigNumEquals(-1, response) - }) - - it('works with large numbers', async () => { - response = await adder.testAvg(INT256_MIN, 2) - bigNumEquals(INT256_MIN.add(2).div(2), response) - response = await adder.testAvg(INT256_MIN, INT256_MAX) - bigNumEquals(0, response) - }) - - it('rounds towards zero', async () => { - response = await adder.testAvg(-1, 4) - bigNumEquals(1, response) - response = await adder.testAvg(-4, 1) - bigNumEquals(-1, response) - }) - }) - }) -}) diff --git a/contracts/test/v0.6/SimpleReadAccessController.test.ts b/contracts/test/v0.6/SimpleReadAccessController.test.ts deleted file mode 100644 index 7b76bc38ca..0000000000 --- a/contracts/test/v0.6/SimpleReadAccessController.test.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Contract, ContractFactory, Transaction } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' - -let personas: Personas - -let controllerFactory: ContractFactory -let controller: Contract - -before(async () => { - personas = (await getUsers()).personas - controllerFactory = await ethers.getContractFactory( - 'src/v0.6/SimpleReadAccessController.sol:SimpleReadAccessController', - personas.Carol, - ) -}) - -describe('SimpleReadAccessController', () => { - beforeEach(async () => { - controller = await controllerFactory.connect(personas.Carol).deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', async () => { - publicAbi(controller, [ - 'hasAccess', - 'addAccess', - 'disableAccessCheck', - 'enableAccessCheck', - 'removeAccess', - 'checkEnabled', - // Owned - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('#constructor', () => { - it('defaults checkEnabled to true', async () => { - assert(await controller.checkEnabled()) - }) - }) - - describe('#hasAccess', () => { - it('allows unauthorized calls originating from the same account', async () => { - assert.isTrue( - await controller - .connect(personas.Eddy) - .hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('blocks unauthorized calls originating from different accounts', async () => { - assert.isFalse( - await controller - .connect(personas.Carol) - .hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - assert.isFalse( - await controller - .connect(personas.Eddy) - .hasAccess(await personas.Carol.getAddress(), '0x00'), - ) - }) - }) - - describe('#addAccess', () => { - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller - .connect(personas.Eddy) - .addAccess(await personas.Eddy.getAddress()), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - assert.isFalse( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - tx = await controller.addAccess(await personas.Eddy.getAddress()) - }) - - it('adds the address to the controller', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - await expect(tx) - .to.emit(controller, 'AddedAccess') - .withArgs(await personas.Eddy.getAddress()) - }) - - describe('when called twice', () => { - it('does not emit a log', async () => { - const tx2 = await controller.addAccess( - await personas.Eddy.getAddress(), - ) - const receipt = await tx2.wait() - assert.equal(receipt.events?.length, 0) - }) - }) - }) - }) - - describe('#removeAccess', () => { - beforeEach(async () => { - await controller.addAccess(await personas.Eddy.getAddress()) - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller - .connect(personas.Eddy) - .removeAccess(await personas.Eddy.getAddress()), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - tx = await controller.removeAccess(await personas.Eddy.getAddress()) - }) - - it('removes the address from the controller', async () => { - assert.isFalse( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - await expect(tx) - .to.emit(controller, 'RemovedAccess') - .withArgs(await personas.Eddy.getAddress()) - }) - - describe('when called twice', () => { - it('does not emit a log', async () => { - const tx2 = await controller.removeAccess( - await personas.Eddy.getAddress(), - ) - const receipt = await tx2.wait() - assert.equal(receipt.events?.length, 0) - }) - }) - }) - }) - - describe('#disableAccessCheck', () => { - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller.connect(personas.Eddy).disableAccessCheck(), - ).to.be.revertedWith('Only callable by owner') - assert.isTrue(await controller.checkEnabled()) - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - await controller.addAccess(await personas.Eddy.getAddress()) - tx = await controller.disableAccessCheck() - }) - - it('sets checkEnabled to false', async () => { - assert.isFalse(await controller.checkEnabled()) - }) - - it('allows users with access', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('allows users without access', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Ned.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - await expect(tx).to.emit(controller, 'CheckAccessDisabled') - }) - - describe('when called twice', () => { - it('does not emit a log', async () => { - const tx2 = await controller.disableAccessCheck() - const receipt = await tx2.wait() - assert.equal(receipt.events?.length, 0) - }) - }) - }) - }) - - describe('#enableAccessCheck', () => { - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller.connect(personas.Eddy).enableAccessCheck(), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - await controller.disableAccessCheck() - await controller.addAccess(await personas.Eddy.getAddress()) - tx = await controller.enableAccessCheck() - }) - - it('allows users with access', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('does not allow users without access', async () => { - assert.isFalse( - await controller.hasAccess(await personas.Ned.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - expect(tx).to.emit(controller, 'CheckAccessEnabled') - }) - - describe('when called twice', () => { - it('does not emit a log', async () => { - const tx2 = await controller.enableAccessCheck() - const receipt = await tx2.wait() - assert.equal(receipt.events?.length, 0) - }) - }) - }) - }) -}) diff --git a/contracts/test/v0.6/SimpleWriteAccessController.test.ts b/contracts/test/v0.6/SimpleWriteAccessController.test.ts deleted file mode 100644 index ae6c1691f9..0000000000 --- a/contracts/test/v0.6/SimpleWriteAccessController.test.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Contract, ContractFactory, Transaction } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' - -let personas: Personas - -let controllerFactory: ContractFactory -let controller: Contract - -before(async () => { - personas = (await getUsers()).personas - controllerFactory = await ethers.getContractFactory( - 'src/v0.6/SimpleWriteAccessController.sol:SimpleWriteAccessController', - personas.Carol, - ) -}) - -describe('SimpleWriteAccessController', () => { - beforeEach(async () => { - controller = await controllerFactory.connect(personas.Carol).deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', async () => { - publicAbi(controller, [ - 'hasAccess', - 'addAccess', - 'disableAccessCheck', - 'enableAccessCheck', - 'removeAccess', - 'checkEnabled', - // Owned - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('#constructor', () => { - it('defaults checkEnabled to true', async () => { - assert(await controller.checkEnabled()) - }) - }) - - describe('#hasAccess', () => { - it('allows unauthorized calls originating from the same account', async () => { - assert.isFalse( - await controller - .connect(personas.Eddy) - .hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('blocks unauthorized calls originating from different accounts', async () => { - assert.isFalse( - await controller - .connect(personas.Carol) - .hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - assert.isFalse( - await controller - .connect(personas.Eddy) - .hasAccess(await personas.Carol.getAddress(), '0x00'), - ) - }) - }) - - describe('#addAccess', () => { - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller - .connect(personas.Eddy) - .addAccess(await personas.Eddy.getAddress()), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - assert.isFalse( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - tx = await controller.addAccess(await personas.Eddy.getAddress()) - }) - - it('adds the address to the controller', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - expect(tx) - .to.emit(controller, 'AddedAccess') - .withArgs(await personas.Eddy.getAddress()) - }) - }) - }) - - describe('#removeAccess', () => { - beforeEach(async () => { - await controller.addAccess(await personas.Eddy.getAddress()) - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller - .connect(personas.Eddy) - .removeAccess(await personas.Eddy.getAddress()), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - tx = await controller.removeAccess(await personas.Eddy.getAddress()) - }) - - it('removes the address from the controller', async () => { - assert.isFalse( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - expect(tx) - .to.emit(controller, 'RemovedAccess') - .withArgs(await personas.Eddy.getAddress()) - }) - }) - }) - - describe('#disableAccessCheck', () => { - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller.connect(personas.Eddy).disableAccessCheck(), - ).to.be.revertedWith('Only callable by owner') - assert.isTrue(await controller.checkEnabled()) - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - await controller.addAccess(await personas.Eddy.getAddress()) - tx = await controller.disableAccessCheck() - }) - - it('sets checkEnabled to false', async () => { - assert.isFalse(await controller.checkEnabled()) - }) - - it('allows users with access', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('allows users without access', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Ned.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - await expect(tx).to.emit(controller, 'CheckAccessDisabled') - }) - }) - }) - - describe('#enableAccessCheck', () => { - describe('when called by a non-owner', () => { - it('reverts', async () => { - await expect( - controller.connect(personas.Eddy).enableAccessCheck(), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('when called by the owner', () => { - let tx: Transaction - beforeEach(async () => { - await controller.disableAccessCheck() - await controller.addAccess(await personas.Eddy.getAddress()) - tx = await controller.enableAccessCheck() - }) - - it('allows users with access', async () => { - assert.isTrue( - await controller.hasAccess(await personas.Eddy.getAddress(), '0x00'), - ) - }) - - it('does not allow users without access', async () => { - assert.isFalse( - await controller.hasAccess(await personas.Ned.getAddress(), '0x00'), - ) - }) - - it('announces the change via a log', async () => { - await expect(tx).to.emit(controller, 'CheckAccessEnabled') - }) - }) - }) -}) diff --git a/contracts/test/v0.6/VRFD20.test.ts b/contracts/test/v0.6/VRFD20.test.ts deleted file mode 100644 index 77141be623..0000000000 --- a/contracts/test/v0.6/VRFD20.test.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { - BigNumber, - constants, - Contract, - ContractFactory, - ContractTransaction, -} from 'ethers' -import { getUsers, Personas, Roles } from '../test-helpers/setup' -import { - evmWordToAddress, - getLog, - publicAbi, - toBytes32String, - toWei, - numToBytes32, - getLogs, -} from '../test-helpers/helpers' - -let roles: Roles -let personas: Personas -let linkTokenFactory: ContractFactory -let vrfCoordinatorMockFactory: ContractFactory -let vrfD20Factory: ContractFactory - -before(async () => { - const users = await getUsers() - - roles = users.roles - personas = users.personas - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) - vrfCoordinatorMockFactory = await ethers.getContractFactory( - 'src/v0.6/tests/VRFCoordinatorMock.sol:VRFCoordinatorMock', - roles.defaultAccount, - ) - vrfD20Factory = await ethers.getContractFactory( - 'src/v0.6/examples/VRFD20.sol:VRFD20', - roles.defaultAccount, - ) -}) - -describe('VRFD20', () => { - const deposit = toWei('1') - const fee = toWei('0.1') - const keyHash = toBytes32String('keyHash') - - let link: Contract - let vrfCoordinator: Contract - let vrfD20: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - vrfCoordinator = await vrfCoordinatorMockFactory - .connect(roles.defaultAccount) - .deploy(link.address) - vrfD20 = await vrfD20Factory - .connect(roles.defaultAccount) - .deploy(vrfCoordinator.address, link.address, keyHash, fee) - await link.transfer(vrfD20.address, deposit) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(vrfD20, [ - // Owned - 'acceptOwnership', - 'owner', - 'transferOwnership', - //VRFConsumerBase - 'rawFulfillRandomness', - // VRFD20 - 'rollDice', - 'house', - 'withdrawLINK', - 'keyHash', - 'fee', - 'setKeyHash', - 'setFee', - ]) - }) - - describe('#withdrawLINK', () => { - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20 - .connect(roles.stranger) - .withdrawLINK(await roles.stranger.getAddress(), deposit), - ).to.be.revertedWith('Only callable by owner') - }) - - it('reverts when not enough LINK in the contract', async () => { - const withdrawAmount = deposit.mul(2) - await expect( - vrfD20 - .connect(roles.defaultAccount) - .withdrawLINK( - await roles.defaultAccount.getAddress(), - withdrawAmount, - ), - ).to.be.reverted - }) - }) - - describe('success', () => { - it('withdraws LINK', async () => { - const startingAmount = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - const expectedAmount = BigNumber.from(startingAmount).add(deposit) - await vrfD20 - .connect(roles.defaultAccount) - .withdrawLINK(await roles.defaultAccount.getAddress(), deposit) - const actualAmount = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - assert.equal(actualAmount.toString(), expectedAmount.toString()) - }) - }) - }) - - describe('#setKeyHash', () => { - const newHash = toBytes32String('newhash') - - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20.connect(roles.stranger).setKeyHash(newHash), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('success', () => { - it('sets the key hash', async () => { - await vrfD20.setKeyHash(newHash) - const actualHash = await vrfD20.keyHash() - assert.equal(actualHash, newHash) - }) - }) - }) - - describe('#setFee', () => { - const newFee = 1234 - - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20.connect(roles.stranger).setFee(newFee), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('success', () => { - it('sets the fee', async () => { - await vrfD20.setFee(newFee) - const actualFee = await vrfD20.fee() - assert.equal(actualFee.toString(), newFee.toString()) - }) - }) - }) - - describe('#house', () => { - describe('failure', () => { - it('reverts when dice not rolled', async () => { - await expect( - vrfD20.house(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Dice not rolled') - }) - - it('reverts when dice roll is in progress', async () => { - await vrfD20.rollDice(await personas.Nancy.getAddress()) - await expect( - vrfD20.house(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Roll in progress') - }) - }) - - describe('success', () => { - it('returns the correct house', async () => { - const randomness = 98765 - const expectedHouse = 'Martell' - const tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - const log = await getLog(tx, 3) - const eventRequestId = log?.topics?.[1] - await vrfCoordinator.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - const response = await vrfD20.house(await personas.Nancy.getAddress()) - assert.equal(response.toString(), expectedHouse) - }) - }) - }) - - describe('#rollDice', () => { - describe('success', () => { - let tx: ContractTransaction - beforeEach(async () => { - tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - }) - - it('emits a RandomnessRequest event from the VRFCoordinator', async () => { - const log = await getLog(tx, 2) - const topics = log?.topics - assert.equal(evmWordToAddress(topics?.[1]), vrfD20.address) - assert.equal(topics?.[2], keyHash) - assert.equal(topics?.[3], constants.HashZero) - }) - }) - - describe('failure', () => { - it('reverts when LINK balance is zero', async () => { - const vrfD202 = await vrfD20Factory - .connect(roles.defaultAccount) - .deploy(vrfCoordinator.address, link.address, keyHash, fee) - await expect( - vrfD202.rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Not enough LINK to pay fee') - }) - - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20 - .connect(roles.stranger) - .rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Only callable by owner') - }) - - it('reverts when the roller rolls more than once', async () => { - await vrfD20.rollDice(await personas.Nancy.getAddress()) - await expect( - vrfD20.rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Already rolled') - }) - }) - }) - - describe('#fulfillRandomness', () => { - const randomness = 98765 - const expectedModResult = (randomness % 20) + 1 - const expectedHouse = 'Martell' - let eventRequestId: string - beforeEach(async () => { - const tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - const log = await getLog(tx, 3) - eventRequestId = log?.topics?.[1] - }) - - describe('success', () => { - let tx: ContractTransaction - beforeEach(async () => { - tx = await vrfCoordinator.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - }) - - it('emits a DiceLanded event', async () => { - const log = await getLog(tx, 0) - assert.equal(log?.topics[1], eventRequestId) - assert.equal(log?.topics[2], numToBytes32(expectedModResult)) - }) - - it('sets the correct dice roll result', async () => { - const response = await vrfD20.house(await personas.Nancy.getAddress()) - assert.equal(response.toString(), expectedHouse) - }) - - it('allows someone else to roll', async () => { - const secondRandomness = 55555 - tx = await vrfD20.rollDice(await personas.Ned.getAddress()) - const log = await getLog(tx, 3) - eventRequestId = log?.topics?.[1] - tx = await vrfCoordinator.callBackWithRandomness( - eventRequestId, - secondRandomness, - vrfD20.address, - ) - }) - }) - - describe('failure', () => { - it('does not fulfill when fulfilled by the wrong VRFcoordinator', async () => { - const vrfCoordinator2 = await vrfCoordinatorMockFactory - .connect(roles.defaultAccount) - .deploy(link.address) - - const tx = await vrfCoordinator2.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - }) -}) diff --git a/contracts/test/v0.7/AggregatorProxy.test.ts b/contracts/test/v0.7/AggregatorProxy.test.ts deleted file mode 100644 index 6e8ee41983..0000000000 --- a/contracts/test/v0.7/AggregatorProxy.test.ts +++ /dev/null @@ -1,743 +0,0 @@ -import { ethers } from 'hardhat' -import { - increaseTimeBy, - numToBytes32, - publicAbi, - toWei, -} from '../test-helpers/helpers' -import { assert } from 'chai' -import { BigNumber, constants, Contract, ContractFactory, Signer } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { bigNumEquals, evmRevert } from '../test-helpers/matchers' - -let personas: Personas -let defaultAccount: Signer - -let linkTokenFactory: ContractFactory -let aggregatorFactory: ContractFactory -let historicAggregatorFactory: ContractFactory -let aggregatorFacadeFactory: ContractFactory -let aggregatorProxyFactory: ContractFactory -let fluxAggregatorFactory: ContractFactory -let reverterFactory: ContractFactory - -before(async () => { - const users = await getUsers() - - personas = users.personas - defaultAccount = users.roles.defaultAccount - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - defaultAccount, - ) - aggregatorFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', - defaultAccount, - ) - historicAggregatorFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV2Aggregator.sol:MockV2Aggregator', - defaultAccount, - ) - aggregatorFacadeFactory = await ethers.getContractFactory( - 'src/v0.6/AggregatorFacade.sol:AggregatorFacade', - defaultAccount, - ) - historicAggregatorFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV2Aggregator.sol:MockV2Aggregator', - defaultAccount, - ) - aggregatorFacadeFactory = await ethers.getContractFactory( - 'src/v0.6/AggregatorFacade.sol:AggregatorFacade', - defaultAccount, - ) - aggregatorProxyFactory = await ethers.getContractFactory( - 'src/v0.7/dev/AggregatorProxy.sol:AggregatorProxy', - defaultAccount, - ) - fluxAggregatorFactory = await ethers.getContractFactory( - 'src/v0.6/FluxAggregator.sol:FluxAggregator', - defaultAccount, - ) - reverterFactory = await ethers.getContractFactory( - 'src/v0.6/tests/Reverter.sol:Reverter', - defaultAccount, - ) -}) - -describe('AggregatorProxy', () => { - const deposit = toWei('100') - const response = numToBytes32(54321) - const response2 = numToBytes32(67890) - const decimals = 18 - const phaseBase = BigNumber.from(2).pow(64) - - let link: Contract - let aggregator: Contract - let aggregator2: Contract - let historicAggregator: Contract - let proxy: Contract - let flux: Contract - let reverter: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(defaultAccount).deploy() - aggregator = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response) - await link.transfer(aggregator.address, deposit) - proxy = await aggregatorProxyFactory - .connect(defaultAccount) - .deploy(aggregator.address) - const emptyAddress = constants.AddressZero - flux = await fluxAggregatorFactory - .connect(personas.Carol) - .deploy(link.address, 0, 0, emptyAddress, 0, 0, 18, 'TEST / LINK') - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(proxy, [ - 'aggregator', - 'confirmAggregator', - 'decimals', - 'description', - 'getAnswer', - 'getRoundData', - 'getTimestamp', - 'latestAnswer', - 'latestRound', - 'latestRoundData', - 'latestTimestamp', - 'phaseAggregators', - 'phaseId', - 'proposeAggregator', - 'proposedAggregator', - 'proposedGetRoundData', - 'proposedLatestRoundData', - 'version', - // Ownable methods: - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('constructor', () => { - it('sets the proxy phase and aggregator', async () => { - bigNumEquals(1, await proxy.phaseId()) - assert.equal(aggregator.address, await proxy.phaseAggregators(1)) - }) - }) - - describe('#latestRound', () => { - it('pulls the rate from the aggregator', async () => { - bigNumEquals(phaseBase.add(1), await proxy.latestRound()) - }) - }) - - describe('#latestAnswer', () => { - it('pulls the rate from the aggregator', async () => { - bigNumEquals(response, await proxy.latestAnswer()) - const latestRound = await proxy.latestRound() - bigNumEquals(response, await proxy.getAnswer(latestRound)) - }) - - describe('after being updated to another contract', () => { - beforeEach(async () => { - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - await link.transfer(aggregator2.address, deposit) - bigNumEquals(response2, await aggregator2.latestAnswer()) - - await proxy.proposeAggregator(aggregator2.address) - await proxy.confirmAggregator(aggregator2.address) - }) - - it('pulls the rate from the new aggregator', async () => { - bigNumEquals(response2, await proxy.latestAnswer()) - const latestRound = await proxy.latestRound() - bigNumEquals(response2, await proxy.getAnswer(latestRound)) - }) - }) - - describe('when the relevant info is not available', () => { - beforeEach(async () => { - await proxy.proposeAggregator(flux.address) - await proxy.confirmAggregator(flux.address) - }) - - it('does not revert when called with a non existent ID', async () => { - const actual = await proxy.latestAnswer() - bigNumEquals(0, actual) - }) - }) - }) - - describe('#getAnswer', () => { - describe('when the relevant round is not available', () => { - beforeEach(async () => { - await proxy.proposeAggregator(flux.address) - await proxy.confirmAggregator(flux.address) - }) - - it('does not revert when called with a non existent ID', async () => { - const proxyId = phaseBase.mul(await proxy.phaseId()).add(1) - const actual = await proxy.getAnswer(proxyId) - bigNumEquals(0, actual) - }) - }) - - describe('when the answer reverts in a non-predicted way', () => { - it('reverts', async () => { - reverter = await reverterFactory.connect(defaultAccount).deploy() - await proxy.proposeAggregator(reverter.address) - await proxy.confirmAggregator(reverter.address) - assert.equal(reverter.address, await proxy.aggregator()) - - const proxyId = phaseBase.mul(await proxy.phaseId()) - - await evmRevert(proxy.getAnswer(proxyId), 'Raised by Reverter.sol') - }) - }) - - describe('after being updated to another contract', () => { - let preUpdateRoundId: BigNumber - let preUpdateAnswer: BigNumber - - beforeEach(async () => { - preUpdateRoundId = await proxy.latestRound() - preUpdateAnswer = await proxy.latestAnswer() - - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - await link.transfer(aggregator2.address, deposit) - bigNumEquals(response2, await aggregator2.latestAnswer()) - - await proxy.proposeAggregator(aggregator2.address) - await proxy.confirmAggregator(aggregator2.address) - }) - - it('reports answers for previous phases', async () => { - const actualAnswer = await proxy.getAnswer(preUpdateRoundId) - bigNumEquals(preUpdateAnswer, actualAnswer) - }) - }) - - describe('when the relevant info is not available', () => { - it('returns 0', async () => { - const actual = await proxy.getAnswer(phaseBase.mul(777)) - bigNumEquals(0, actual) - }) - }) - - describe('when the round ID is too large', () => { - const overflowRoundId = BigNumber.from(2) - .pow(255) - .add(phaseBase) // get the original phase - .add(1) // get the original round - it('returns 0', async () => { - const actual = await proxy.getTimestamp(overflowRoundId) - bigNumEquals(0, actual) - }) - }) - }) - - describe('#getTimestamp', () => { - describe('when the relevant round is not available', () => { - beforeEach(async () => { - await proxy.proposeAggregator(flux.address) - await proxy.confirmAggregator(flux.address) - }) - - it('does not revert when called with a non existent ID', async () => { - const proxyId = phaseBase.mul(await proxy.phaseId()).add(1) - const actual = await proxy.getTimestamp(proxyId) - bigNumEquals(0, actual) - }) - }) - - describe('when the relevant info is not available', () => { - it('returns 0', async () => { - const actual = await proxy.getTimestamp(phaseBase.mul(777)) - bigNumEquals(0, actual) - }) - }) - - describe('when the round ID is too large', () => { - const overflowRoundId = BigNumber.from(2) - .pow(255) - .add(phaseBase) // get the original phase - .add(1) // get the original round - - it('returns 0', async () => { - const actual = await proxy.getTimestamp(overflowRoundId) - bigNumEquals(0, actual) - }) - }) - }) - - describe('#latestTimestamp', () => { - beforeEach(async () => { - const height = await aggregator.latestTimestamp() - assert.notEqual('0', height.toString()) - }) - - it('pulls the timestamp from the aggregator', async () => { - bigNumEquals( - await aggregator.latestTimestamp(), - await proxy.latestTimestamp(), - ) - const latestRound = await proxy.latestRound() - bigNumEquals( - await aggregator.latestTimestamp(), - await proxy.getTimestamp(latestRound), - ) - }) - - describe('after being updated to another contract', () => { - beforeEach(async () => { - await increaseTimeBy(30, ethers.provider) - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - - const height2 = await aggregator2.latestTimestamp() - assert.notEqual('0', height2.toString()) - - const height1 = await aggregator.latestTimestamp() - assert.notEqual( - height1.toString(), - height2.toString(), - 'Height1 and Height2 should not be equal', - ) - - await proxy.proposeAggregator(aggregator2.address) - await proxy.confirmAggregator(aggregator2.address) - }) - - it('pulls the timestamp from the new aggregator', async () => { - bigNumEquals( - await aggregator2.latestTimestamp(), - await proxy.latestTimestamp(), - ) - const latestRound = await proxy.latestRound() - bigNumEquals( - await aggregator2.latestTimestamp(), - await proxy.getTimestamp(latestRound), - ) - }) - }) - }) - - describe('#getRoundData', () => { - describe('when pointed at a Historic Aggregator', () => { - beforeEach(async () => { - historicAggregator = await historicAggregatorFactory - .connect(defaultAccount) - .deploy(response2) - await proxy.proposeAggregator(historicAggregator.address) - await proxy.confirmAggregator(historicAggregator.address) - }) - - it('reverts', async () => { - const latestRoundId = await historicAggregator.latestRound() - await evmRevert(proxy.getRoundData(latestRoundId)) - }) - - describe('when pointed at an Aggregator Facade', () => { - beforeEach(async () => { - const facade = await aggregatorFacadeFactory - .connect(defaultAccount) - .deploy(aggregator.address, 18, 'LINK/USD: Aggregator Facade') - await proxy.proposeAggregator(facade.address) - await proxy.confirmAggregator(facade.address) - }) - - it('works for a valid roundId', async () => { - const aggId = await aggregator.latestRound() - const phaseId = phaseBase.mul(await proxy.phaseId()) - const proxyId = phaseId.add(aggId) - - const round = await proxy.getRoundData(proxyId) - bigNumEquals(proxyId, round.id) - bigNumEquals(response, round.answer) - const nowSeconds = new Date().valueOf() / 1000 - assert.isAbove(round.updatedAt.toNumber(), nowSeconds - 120) - bigNumEquals(round.updatedAt, round.startedAt) - bigNumEquals(proxyId, round.answeredInRound) - }) - }) - }) - - describe('when pointed at a FluxAggregator', () => { - beforeEach(async () => { - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - - await proxy.proposeAggregator(aggregator2.address) - await proxy.confirmAggregator(aggregator2.address) - }) - - it('works for a valid round ID', async () => { - const aggId = phaseBase.sub(2) - await aggregator2 - .connect(personas.Carol) - .updateRoundData(aggId, response2, 77, 42) - - const phaseId = phaseBase.mul(await proxy.phaseId()) - const proxyId = phaseId.add(aggId) - - const round = await proxy.getRoundData(proxyId) - bigNumEquals(proxyId, round.id) - bigNumEquals(response2, round.answer) - bigNumEquals(42, round.startedAt) - bigNumEquals(77, round.updatedAt) - bigNumEquals(proxyId, round.answeredInRound) - }) - }) - - it('reads round ID of a previous phase', async () => { - const oldphaseId = phaseBase.mul(await proxy.phaseId()) - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - - await proxy.proposeAggregator(aggregator2.address) - await proxy.confirmAggregator(aggregator2.address) - - const aggId = await aggregator.latestRound() - const proxyId = oldphaseId.add(aggId) - - const round = await proxy.getRoundData(proxyId) - bigNumEquals(proxyId, round.id) - bigNumEquals(response, round.answer) - - const nowSeconds = new Date().valueOf() / 1000 - assert.isAbove(round.startedAt.toNumber(), nowSeconds - 120) - bigNumEquals(round.startedAt, round.updatedAt) - bigNumEquals(proxyId, round.answeredInRound) - }) - }) - - describe('#latestRoundData', () => { - describe('when pointed at a Historic Aggregator', () => { - beforeEach(async () => { - historicAggregator = await historicAggregatorFactory - .connect(defaultAccount) - .deploy(response2) - await proxy.proposeAggregator(historicAggregator.address) - await proxy.confirmAggregator(historicAggregator.address) - }) - - it('reverts', async () => { - await evmRevert(proxy.latestRoundData()) - }) - - describe('when pointed at an Aggregator Facade', () => { - beforeEach(async () => { - const facade = await aggregatorFacadeFactory - .connect(defaultAccount) - .deploy( - historicAggregator.address, - 17, - 'DOGE/ZWL: Aggregator Facade', - ) - await proxy.proposeAggregator(facade.address) - await proxy.confirmAggregator(facade.address) - }) - - it('does not revert', async () => { - const aggId = await historicAggregator.latestRound() - const phaseId = phaseBase.mul(await proxy.phaseId()) - const proxyId = phaseId.add(aggId) - - const round = await proxy.latestRoundData() - bigNumEquals(proxyId, round.id) - bigNumEquals(response2, round.answer) - const nowSeconds = new Date().valueOf() / 1000 - assert.isAbove(round.updatedAt.toNumber(), nowSeconds - 120) - bigNumEquals(round.updatedAt, round.startedAt) - bigNumEquals(proxyId, round.answeredInRound) - }) - - it('uses the decimals set in the constructor', async () => { - bigNumEquals(17, await proxy.decimals()) - }) - - it('uses the description set in the constructor', async () => { - assert.equal('DOGE/ZWL: Aggregator Facade', await proxy.description()) - }) - - it('sets the version to 2', async () => { - bigNumEquals(2, await proxy.version()) - }) - }) - }) - - describe('when pointed at a FluxAggregator', () => { - beforeEach(async () => { - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - - await proxy.proposeAggregator(aggregator2.address) - await proxy.confirmAggregator(aggregator2.address) - }) - - it('does not revert', async () => { - const aggId = phaseBase.sub(2) - await aggregator2 - .connect(personas.Carol) - .updateRoundData(aggId, response2, 77, 42) - - const phaseId = phaseBase.mul(await proxy.phaseId()) - const proxyId = phaseId.add(aggId) - - const round = await proxy.latestRoundData() - bigNumEquals(proxyId, round.id) - bigNumEquals(response2, round.answer) - bigNumEquals(42, round.startedAt) - bigNumEquals(77, round.updatedAt) - bigNumEquals(proxyId, round.answeredInRound) - }) - - it('uses the decimals of the aggregator', async () => { - bigNumEquals(18, await proxy.decimals()) - }) - - it('uses the description of the aggregator', async () => { - assert.equal( - 'v0.6/tests/MockV3Aggregator.sol', - await proxy.description(), - ) - }) - - it('uses the version of the aggregator', async () => { - bigNumEquals(0, await proxy.version()) - }) - }) - }) - - describe('#proposeAggregator', () => { - beforeEach(async () => { - await proxy.transferOwnership(await personas.Carol.getAddress()) - await proxy.connect(personas.Carol).acceptOwnership() - - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, 1) - - assert.equal(aggregator.address, await proxy.aggregator()) - }) - - describe('when called by the owner', () => { - it('sets the address of the proposed aggregator', async () => { - await proxy - .connect(personas.Carol) - .proposeAggregator(aggregator2.address) - - assert.equal(aggregator2.address, await proxy.proposedAggregator()) - }) - - it('emits an AggregatorProposed event', async () => { - const tx = await proxy - .connect(personas.Carol) - .proposeAggregator(aggregator2.address) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 1) - assert.equal(eventLog?.[0].event, 'AggregatorProposed') - assert.equal(eventLog?.[0].args?.[0], aggregator.address) - assert.equal(eventLog?.[0].args?.[1], aggregator2.address) - }) - }) - - describe('when called by a non-owner', () => { - it('does not update', async () => { - await evmRevert( - proxy.connect(personas.Neil).proposeAggregator(aggregator2.address), - 'Only callable by owner', - ) - - assert.equal(aggregator.address, await proxy.aggregator()) - }) - }) - }) - - describe('#confirmAggregator', () => { - beforeEach(async () => { - await proxy.transferOwnership(await personas.Carol.getAddress()) - await proxy.connect(personas.Carol).acceptOwnership() - - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, 1) - - assert.equal(aggregator.address, await proxy.aggregator()) - }) - - describe('when called by the owner', () => { - beforeEach(async () => { - await proxy - .connect(personas.Carol) - .proposeAggregator(aggregator2.address) - }) - - it('sets the address of the new aggregator', async () => { - await proxy - .connect(personas.Carol) - .confirmAggregator(aggregator2.address) - - assert.equal(aggregator2.address, await proxy.aggregator()) - }) - - it('increases the phase', async () => { - bigNumEquals(1, await proxy.phaseId()) - - await proxy - .connect(personas.Carol) - .confirmAggregator(aggregator2.address) - - bigNumEquals(2, await proxy.phaseId()) - }) - - it('increases the round ID', async () => { - bigNumEquals(phaseBase.add(1), await proxy.latestRound()) - - await proxy - .connect(personas.Carol) - .confirmAggregator(aggregator2.address) - - bigNumEquals(phaseBase.mul(2).add(1), await proxy.latestRound()) - }) - - it('sets the proxy phase and aggregator', async () => { - assert.equal( - '0x0000000000000000000000000000000000000000', - await proxy.phaseAggregators(2), - ) - - await proxy - .connect(personas.Carol) - .confirmAggregator(aggregator2.address) - - assert.equal(aggregator2.address, await proxy.phaseAggregators(2)) - }) - - it('emits an AggregatorConfirmed event', async () => { - const tx = await proxy - .connect(personas.Carol) - .confirmAggregator(aggregator2.address) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 1) - assert.equal(eventLog?.[0].event, 'AggregatorConfirmed') - assert.equal(eventLog?.[0].args?.[0], aggregator.address) - assert.equal(eventLog?.[0].args?.[1], aggregator2.address) - }) - }) - - describe('when called by a non-owner', () => { - beforeEach(async () => { - await proxy - .connect(personas.Carol) - .proposeAggregator(aggregator2.address) - }) - - it('does not update', async () => { - await evmRevert( - proxy.connect(personas.Neil).confirmAggregator(aggregator2.address), - 'Only callable by owner', - ) - - assert.equal(aggregator.address, await proxy.aggregator()) - }) - }) - }) - - describe('#proposedGetRoundData', () => { - beforeEach(async () => { - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - }) - - describe('when an aggregator has been proposed', () => { - beforeEach(async () => { - await proxy - .connect(defaultAccount) - .proposeAggregator(aggregator2.address) - assert.equal(await proxy.proposedAggregator(), aggregator2.address) - }) - - it('returns the data for the proposed aggregator', async () => { - const roundId = await aggregator2.latestRound() - const round = await proxy.proposedGetRoundData(roundId) - bigNumEquals(roundId, round.id) - bigNumEquals(response2, round.answer) - }) - - describe('after the aggregator has been confirmed', () => { - beforeEach(async () => { - await proxy - .connect(defaultAccount) - .confirmAggregator(aggregator2.address) - assert.equal(await proxy.aggregator(), aggregator2.address) - }) - - it('reverts', async () => { - const roundId = await aggregator2.latestRound() - await evmRevert( - proxy.proposedGetRoundData(roundId), - 'No proposed aggregator present', - ) - }) - }) - }) - }) - - describe('#proposedLatestRoundData', () => { - beforeEach(async () => { - aggregator2 = await aggregatorFactory - .connect(defaultAccount) - .deploy(decimals, response2) - }) - - describe('when an aggregator has been proposed', () => { - beforeEach(async () => { - await proxy - .connect(defaultAccount) - .proposeAggregator(aggregator2.address) - assert.equal(await proxy.proposedAggregator(), aggregator2.address) - }) - - it('returns the data for the proposed aggregator', async () => { - const roundId = await aggregator2.latestRound() - const round = await proxy.proposedLatestRoundData() - bigNumEquals(roundId, round.id) - bigNumEquals(response2, round.answer) - }) - - describe('after the aggregator has been confirmed', () => { - beforeEach(async () => { - await proxy - .connect(defaultAccount) - .confirmAggregator(aggregator2.address) - assert.equal(await proxy.aggregator(), aggregator2.address) - }) - - it('reverts', async () => { - await evmRevert( - proxy.proposedLatestRoundData(), - 'No proposed aggregator present', - ) - }) - }) - }) - }) -}) diff --git a/contracts/test/v0.7/AuthorizedForwarder.test.ts b/contracts/test/v0.7/AuthorizedForwarder.test.ts deleted file mode 100644 index e1fa2f1f70..0000000000 --- a/contracts/test/v0.7/AuthorizedForwarder.test.ts +++ /dev/null @@ -1,444 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Contract, ContractFactory, ContractReceipt } from 'ethers' -import { getUsers, Roles } from '../test-helpers/setup' -import { evmRevert } from '../test-helpers/matchers' - -let getterSetterFactory: ContractFactory -let forwarderFactory: ContractFactory -let brokenFactory: ContractFactory -let linkTokenFactory: ContractFactory - -let roles: Roles -const zeroAddress = ethers.constants.AddressZero - -before(async () => { - const users = await getUsers() - - roles = users.roles - getterSetterFactory = await ethers.getContractFactory( - 'src/v0.4/tests/GetterSetter.sol:GetterSetter', - roles.defaultAccount, - ) - brokenFactory = await ethers.getContractFactory( - 'src/v0.8/tests/Broken.sol:Broken', - roles.defaultAccount, - ) - forwarderFactory = await ethers.getContractFactory( - 'src/v0.7/AuthorizedForwarder.sol:AuthorizedForwarder', - roles.defaultAccount, - ) - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) -}) - -describe('AuthorizedForwarder', () => { - let link: Contract - let forwarder: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - forwarder = await forwarderFactory - .connect(roles.defaultAccount) - .deploy( - link.address, - await roles.defaultAccount.getAddress(), - zeroAddress, - '0x', - ) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(forwarder, [ - 'forward', - 'getAuthorizedSenders', - 'getChainlinkToken', - 'isAuthorizedSender', - 'ownerForward', - 'setAuthorizedSenders', - 'transferOwnershipWithMessage', - 'typeAndVersion', - // ConfirmedOwner - 'transferOwnership', - 'acceptOwnership', - 'owner', - ]) - }) - - describe('#typeAndVersion', () => { - it('describes the authorized forwarder', async () => { - assert.equal( - await forwarder.typeAndVersion(), - 'AuthorizedForwarder 1.0.0', - ) - }) - }) - - describe('deployment', () => { - it('sets the correct link token', async () => { - assert.equal(await forwarder.getChainlinkToken(), link.address) - }) - - it('reverts on zeroAddress value for link token', async () => { - await evmRevert( - forwarderFactory.connect(roles.defaultAccount).deploy( - zeroAddress, // Link Address - await roles.defaultAccount.getAddress(), - zeroAddress, - '0x', - ), - ) - }) - - it('sets no authorized senders', async () => { - const senders = await forwarder.getAuthorizedSenders() - assert.equal(senders.length, 0) - }) - }) - - describe('#setAuthorizedSenders', () => { - let newSenders: string[] - let receipt: ContractReceipt - describe('when called by the owner', () => { - describe('set authorized senders containing duplicate/s', () => { - beforeEach(async () => { - newSenders = [ - await roles.oracleNode1.getAddress(), - await roles.oracleNode1.getAddress(), - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - ] - }) - it('reverts with a must not have duplicate senders message', async () => { - await evmRevert( - forwarder - .connect(roles.defaultAccount) - .setAuthorizedSenders(newSenders), - 'Must not have duplicate senders', - ) - }) - }) - - describe('setting 3 authorized senders', () => { - beforeEach(async () => { - newSenders = [ - await roles.oracleNode1.getAddress(), - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - ] - const tx = await forwarder - .connect(roles.defaultAccount) - .setAuthorizedSenders(newSenders) - receipt = await tx.wait() - }) - - it('adds the authorized nodes', async () => { - const authorizedSenders = await forwarder.getAuthorizedSenders() - assert.equal(newSenders.length, authorizedSenders.length) - for (let i = 0; i < authorizedSenders.length; i++) { - assert.equal(authorizedSenders[i], newSenders[i]) - } - }) - - it('emits an event', async () => { - assert.equal(receipt.events?.length, 1) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'AuthorizedSendersChanged') - const encodedSenders = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'address'], - [newSenders, await roles.defaultAccount.getAddress()], - ) - assert.equal(responseEvent?.data, encodedSenders) - }) - - it('replaces the authorized nodes', async () => { - const newSenders = await forwarder - .connect(roles.defaultAccount) - .getAuthorizedSenders() - assert.notIncludeOrderedMembers(newSenders, [ - await roles.oracleNode.getAddress(), - ]) - }) - - after(async () => { - await forwarder - .connect(roles.defaultAccount) - .setAuthorizedSenders([await roles.oracleNode.getAddress()]) - }) - }) - - describe('setting 0 authorized senders', () => { - beforeEach(async () => { - newSenders = [] - }) - - it('reverts with a minimum senders message', async () => { - await evmRevert( - forwarder - .connect(roles.defaultAccount) - .setAuthorizedSenders(newSenders), - 'Must have at least 1 sender', - ) - }) - }) - }) - - describe('when called by a non-owner', () => { - it('cannot add an authorized node', async () => { - await evmRevert( - forwarder - .connect(roles.stranger) - .setAuthorizedSenders([await roles.stranger.getAddress()]), - 'Cannot set authorized senders', - ) - }) - }) - }) - - describe('#forward', () => { - let bytes: string - let payload: string - let mock: Contract - - beforeEach(async () => { - mock = await getterSetterFactory.connect(roles.defaultAccount).deploy() - bytes = ethers.utils.hexlify(ethers.utils.randomBytes(100)) - payload = getterSetterFactory.interface.encodeFunctionData( - getterSetterFactory.interface.getFunction('setBytes'), - [bytes], - ) - }) - - describe('when called by an unauthorized node', () => { - it('reverts', async () => { - await evmRevert( - forwarder.connect(roles.stranger).forward(mock.address, payload), - ) - }) - }) - - describe('when called by an authorized node', () => { - beforeEach(async () => { - await forwarder - .connect(roles.defaultAccount) - .setAuthorizedSenders([await roles.defaultAccount.getAddress()]) - }) - - describe('when destination call reverts', () => { - let brokenMock: Contract - let brokenPayload: string - let brokenMsgPayload: string - - beforeEach(async () => { - brokenMock = await brokenFactory - .connect(roles.defaultAccount) - .deploy() - brokenMsgPayload = brokenFactory.interface.encodeFunctionData( - brokenFactory.interface.getFunction('revertWithMessage'), - ['Failure message'], - ) - - brokenPayload = brokenFactory.interface.encodeFunctionData( - brokenFactory.interface.getFunction('revertSilently'), - [], - ) - }) - - describe('when reverts with message', () => { - it('return revert message', async () => { - await evmRevert( - forwarder - .connect(roles.defaultAccount) - .forward(brokenMock.address, brokenMsgPayload), - "reverted with reason string 'Failure message'", - ) - }) - }) - - describe('when reverts without message', () => { - it('return silent failure message', async () => { - await evmRevert( - forwarder - .connect(roles.defaultAccount) - .forward(brokenMock.address, brokenPayload), - 'Forwarded call reverted without reason', - ) - }) - }) - }) - - describe('when sending to a non-contract address', () => { - it('reverts', async () => { - await evmRevert( - forwarder - .connect(roles.defaultAccount) - .forward(zeroAddress, payload), - 'Must forward to a contract', - ) - }) - }) - - describe('when attempting to forward to the link token', () => { - it('reverts', async () => { - const sighash = linkTokenFactory.interface.getSighash('name') // any Link Token function - await evmRevert( - forwarder - .connect(roles.defaultAccount) - .forward(link.address, sighash), - ) - }) - }) - - describe('when forwarding to any other address', () => { - it('forwards the data', async () => { - const tx = await forwarder - .connect(roles.defaultAccount) - .forward(mock.address, payload) - await tx.wait() - assert.equal(await mock.getBytes(), bytes) - }) - - it('perceives the message is sent by the AuthorizedForwarder', async () => { - const tx = await forwarder - .connect(roles.defaultAccount) - .forward(mock.address, payload) - await expect(tx) - .to.emit(mock, 'SetBytes') - .withArgs(forwarder.address, bytes) - }) - }) - }) - }) - - describe('#transferOwnershipWithMessage', () => { - const message = '0x42' - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - forwarder - .connect(roles.stranger) - .transferOwnershipWithMessage( - await roles.stranger.getAddress(), - message, - ), - 'Only callable by owner', - ) - }) - }) - - describe('when called by the owner', () => { - it('calls the normal ownership transfer proposal', async () => { - const tx = await forwarder - .connect(roles.defaultAccount) - .transferOwnershipWithMessage( - await roles.stranger.getAddress(), - message, - ) - const receipt = await tx.wait() - - assert.equal(receipt?.events?.[0]?.event, 'OwnershipTransferRequested') - assert.equal(receipt?.events?.[0]?.address, forwarder.address) - assert.equal( - receipt?.events?.[0]?.args?.[0], - await roles.defaultAccount.getAddress(), - ) - assert.equal( - receipt?.events?.[0]?.args?.[1], - await roles.stranger.getAddress(), - ) - }) - - it('calls the normal ownership transfer proposal', async () => { - const tx = await forwarder - .connect(roles.defaultAccount) - .transferOwnershipWithMessage( - await roles.stranger.getAddress(), - message, - ) - const receipt = await tx.wait() - - assert.equal( - receipt?.events?.[1]?.event, - 'OwnershipTransferRequestedWithMessage', - ) - assert.equal(receipt?.events?.[1]?.address, forwarder.address) - assert.equal( - receipt?.events?.[1]?.args?.[0], - await roles.defaultAccount.getAddress(), - ) - assert.equal( - receipt?.events?.[1]?.args?.[1], - await roles.stranger.getAddress(), - ) - assert.equal(receipt?.events?.[1]?.args?.[2], message) - }) - }) - }) - - describe('#ownerForward', () => { - let bytes: string - let payload: string - let mock: Contract - - beforeEach(async () => { - mock = await getterSetterFactory.connect(roles.defaultAccount).deploy() - bytes = ethers.utils.hexlify(ethers.utils.randomBytes(100)) - payload = getterSetterFactory.interface.encodeFunctionData( - getterSetterFactory.interface.getFunction('setBytes'), - [bytes], - ) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - forwarder.connect(roles.stranger).ownerForward(mock.address, payload), - ) - }) - }) - - describe('when called by owner', () => { - describe('when attempting to forward to the link token', () => { - it('does not revert', async () => { - const sighash = linkTokenFactory.interface.getSighash('name') // any Link Token function - - await forwarder - .connect(roles.defaultAccount) - .ownerForward(link.address, sighash) - }) - }) - - describe('when forwarding to any other address', () => { - it('forwards the data', async () => { - const tx = await forwarder - .connect(roles.defaultAccount) - .ownerForward(mock.address, payload) - await tx.wait() - assert.equal(await mock.getBytes(), bytes) - }) - - it('reverts when sending to a non-contract address', async () => { - await evmRevert( - forwarder - .connect(roles.defaultAccount) - .ownerForward(zeroAddress, payload), - 'Must forward to a contract', - ) - }) - - it('perceives the message is sent by the Operator', async () => { - const tx = await forwarder - .connect(roles.defaultAccount) - .ownerForward(mock.address, payload) - await expect(tx) - .to.emit(mock, 'SetBytes') - .withArgs(forwarder.address, bytes) - }) - }) - }) - }) -}) diff --git a/contracts/test/v0.7/Chainlink.test.ts b/contracts/test/v0.7/Chainlink.test.ts deleted file mode 100644 index 7792895934..0000000000 --- a/contracts/test/v0.7/Chainlink.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi, decodeDietCBOR, hexToBuf } from '../test-helpers/helpers' -import { assert } from 'chai' -import { Contract, ContractFactory, providers, Signer } from 'ethers' -import { Roles, getUsers } from '../test-helpers/setup' -import { makeDebug } from '../test-helpers/debug' - -const debug = makeDebug('ChainlinkTestHelper') -let concreteChainlinkFactory: ContractFactory - -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - concreteChainlinkFactory = await ethers.getContractFactory( - 'src/v0.7/tests/ChainlinkTestHelper.sol:ChainlinkTestHelper', - roles.defaultAccount, - ) -}) - -describe('ChainlinkTestHelper', () => { - let ccl: Contract - let defaultAccount: Signer - - beforeEach(async () => { - defaultAccount = roles.defaultAccount - ccl = await concreteChainlinkFactory.connect(defaultAccount).deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(ccl, [ - 'add', - 'addBytes', - 'addInt', - 'addStringArray', - 'addUint', - 'closeEvent', - 'setBuffer', - ]) - }) - - async function parseCCLEvent(tx: providers.TransactionResponse) { - const receipt = await tx.wait() - const data = receipt.logs?.[0].data - const d = debug.extend('parseCCLEvent') - d('data %s', data) - return ethers.utils.defaultAbiCoder.decode(['bytes'], data ?? '') - } - - describe('#close', () => { - it('handles empty payloads', async () => { - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, {}) - }) - }) - - describe('#setBuffer', () => { - it('emits the buffer', async () => { - await ccl.setBuffer('0xA161616162') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { a: 'b' }) - }) - }) - - describe('#add', () => { - it('stores and logs keys and values', async () => { - await ccl.add('first', 'word!!') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { first: 'word!!' }) - }) - - it('handles two entries', async () => { - await ccl.add('first', 'uno') - await ccl.add('second', 'dos') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - assert.deepEqual(decoded, { - first: 'uno', - second: 'dos', - }) - }) - }) - - describe('#addBytes', () => { - it('stores and logs keys and values', async () => { - await ccl.addBytes('first', '0xaabbccddeeff') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - const expected = hexToBuf('0xaabbccddeeff') - assert.deepEqual(decoded, { first: expected }) - }) - - it('handles two entries', async () => { - await ccl.addBytes('first', '0x756E6F') - await ccl.addBytes('second', '0x646F73') - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - const expectedFirst = hexToBuf('0x756E6F') - const expectedSecond = hexToBuf('0x646F73') - assert.deepEqual(decoded, { - first: expectedFirst, - second: expectedSecond, - }) - }) - - it('handles strings', async () => { - await ccl.addBytes('first', ethers.utils.toUtf8Bytes('apple')) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - const expected = ethers.utils.toUtf8Bytes('apple') - assert.deepEqual(decoded, { first: expected }) - }) - }) - - describe('#addInt', () => { - it('stores and logs keys and values', async () => { - await ccl.addInt('first', 1) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { first: 1 }) - }) - - it('handles two entries', async () => { - await ccl.addInt('first', 1) - await ccl.addInt('second', 2) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - assert.deepEqual(decoded, { - first: 1, - second: 2, - }) - }) - }) - - describe('#addUint', () => { - it('stores and logs keys and values', async () => { - await ccl.addUint('first', 1) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { first: 1 }) - }) - - it('handles two entries', async () => { - await ccl.addUint('first', 1) - await ccl.addUint('second', 2) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - - assert.deepEqual(decoded, { - first: 1, - second: 2, - }) - }) - }) - - describe('#addStringArray', () => { - it('stores and logs keys and values', async () => { - await ccl.addStringArray('word', [ - ethers.utils.formatBytes32String('seinfeld'), - ethers.utils.formatBytes32String('"4"'), - ethers.utils.formatBytes32String('LIFE'), - ]) - const tx = await ccl.closeEvent() - const [payload] = await parseCCLEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual(decoded, { word: ['seinfeld', '"4"', 'LIFE'] }) - }) - }) -}) diff --git a/contracts/test/v0.7/ChainlinkClient.test.ts b/contracts/test/v0.7/ChainlinkClient.test.ts deleted file mode 100644 index 198d382af7..0000000000 --- a/contracts/test/v0.7/ChainlinkClient.test.ts +++ /dev/null @@ -1,454 +0,0 @@ -import { ethers } from 'hardhat' -import { assert } from 'chai' -import { Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../test-helpers/setup' -import { - convertFufillParams, - decodeCCRequest, - decodeRunRequest, - RunRequest, -} from '../test-helpers/oracle' -import { decodeDietCBOR } from '../test-helpers/helpers' -import { evmRevert } from '../test-helpers/matchers' - -let concreteChainlinkClientFactory: ContractFactory -let emptyOracleFactory: ContractFactory -let getterSetterFactory: ContractFactory -let operatorFactory: ContractFactory -let linkTokenFactory: ContractFactory - -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - - concreteChainlinkClientFactory = await ethers.getContractFactory( - 'src/v0.7/tests/ChainlinkClientTestHelper.sol:ChainlinkClientTestHelper', - roles.defaultAccount, - ) - emptyOracleFactory = await ethers.getContractFactory( - 'src/v0.6/tests/EmptyOracle.sol:EmptyOracle', - roles.defaultAccount, - ) - getterSetterFactory = await ethers.getContractFactory( - 'src/v0.5/tests/GetterSetter.sol:GetterSetter', - roles.defaultAccount, - ) - operatorFactory = await ethers.getContractFactory( - 'src/v0.7/Operator.sol:Operator', - roles.defaultAccount, - ) - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) -}) - -describe('ChainlinkClientTestHelper', () => { - const specId = - '0x4c7b7ffb66b344fbaa64995af81e355a00000000000000000000000000000000' - let cc: Contract - let gs: Contract - let oc: Contract - let newoc: Contract - let link: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - oc = await operatorFactory - .connect(roles.defaultAccount) - .deploy(link.address, await roles.defaultAccount.getAddress()) - newoc = await operatorFactory - .connect(roles.defaultAccount) - .deploy(link.address, await roles.defaultAccount.getAddress()) - gs = await getterSetterFactory.connect(roles.defaultAccount).deploy() - cc = await concreteChainlinkClientFactory - .connect(roles.defaultAccount) - .deploy(link.address, oc.address) - }) - - describe('#newRequest', () => { - it('forwards the information to the oracle contract through the link token', async () => { - const tx = await cc.publicNewRequest( - specId, - gs.address, - ethers.utils.toUtf8Bytes('requestedBytes32(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - - assert.equal(1, receipt.logs?.length) - const [jId, cbAddr, cbFId, cborData] = receipt.logs - ? decodeCCRequest(receipt.logs[0]) - : [] - const params = decodeDietCBOR(cborData ?? '') - - assert.equal(specId, jId) - assert.equal(gs.address, cbAddr) - assert.equal('0xed53e511', cbFId) - assert.deepEqual({}, params) - }) - }) - - describe('#chainlinkRequest(Request)', () => { - it('emits an event from the contract showing the run ID', async () => { - const tx = await cc.publicRequest( - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - - const { events, logs } = await tx.wait() - - assert.equal(4, events?.length) - - assert.equal(logs?.[0].address, cc.address) - assert.equal(events?.[0].event, 'ChainlinkRequested') - }) - }) - - describe('#chainlinkRequestTo(Request)', () => { - it('emits an event from the contract showing the run ID', async () => { - const tx = await cc.publicRequestRunTo( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { events } = await tx.wait() - - assert.equal(4, events?.length) - assert.equal(events?.[0].event, 'ChainlinkRequested') - }) - - it('emits an event on the target oracle contract', async () => { - const tx = await cc.publicRequestRunTo( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { logs } = await tx.wait() - const event = logs && newoc.interface.parseLog(logs[3]) - - assert.equal(4, logs?.length) - assert.equal(event?.name, 'OracleRequest') - }) - - it('does not modify the stored oracle address', async () => { - await cc.publicRequestRunTo( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - - const actualOracleAddress = await cc.publicOracleAddress() - assert.equal(oc.address, actualOracleAddress) - }) - }) - - describe('#requestOracleData', () => { - it('emits an event from the contract showing the run ID', async () => { - const tx = await cc.publicRequestOracleData( - specId, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - - const { events, logs } = await tx.wait() - - assert.equal(4, events?.length) - - assert.equal(logs?.[0].address, cc.address) - assert.equal(events?.[0].event, 'ChainlinkRequested') - }) - }) - - describe('#requestOracleDataFrom', () => { - it('emits an event from the contract showing the run ID', async () => { - const tx = await cc.publicRequestOracleDataFrom( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { events } = await tx.wait() - - assert.equal(4, events?.length) - assert.equal(events?.[0].event, 'ChainlinkRequested') - }) - - it('emits an event on the target oracle contract', async () => { - const tx = await cc.publicRequestOracleDataFrom( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { logs } = await tx.wait() - const event = logs && newoc.interface.parseLog(logs[3]) - - assert.equal(4, logs?.length) - assert.equal(event?.name, 'OracleRequest') - }) - - it('does not modify the stored oracle address', async () => { - await cc.publicRequestOracleDataFrom( - newoc.address, - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - - const actualOracleAddress = await cc.publicOracleAddress() - assert.equal(oc.address, actualOracleAddress) - }) - }) - - describe('#cancelChainlinkRequest', () => { - let requestId: string - // a concrete chainlink attached to an empty oracle - let ecc: Contract - - beforeEach(async () => { - const emptyOracle = await emptyOracleFactory - .connect(roles.defaultAccount) - .deploy() - ecc = await concreteChainlinkClientFactory - .connect(roles.defaultAccount) - .deploy(link.address, emptyOracle.address) - - const tx = await ecc.publicRequest( - specId, - ecc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { events } = await tx.wait() - requestId = (events?.[0]?.args as any).id - }) - - it('emits an event from the contract showing the run was cancelled', async () => { - const tx = await ecc.publicCancelRequest( - requestId, - 0, - ethers.utils.hexZeroPad('0x', 4), - 0, - ) - const { events } = await tx.wait() - - assert.equal(1, events?.length) - assert.equal(events?.[0].event, 'ChainlinkCancelled') - assert.equal(requestId, (events?.[0].args as any).id) - }) - - it('throws if given a bogus event ID', async () => { - await evmRevert( - ecc.publicCancelRequest( - ethers.utils.formatBytes32String('bogusId'), - 0, - ethers.utils.hexZeroPad('0x', 4), - 0, - ), - ) - }) - }) - - describe('#recordChainlinkFulfillment(modifier)', () => { - let request: RunRequest - - beforeEach(async () => { - await oc.setAuthorizedSenders([await roles.defaultAccount.getAddress()]) - const tx = await cc.publicRequest( - specId, - cc.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const { logs } = await tx.wait() - - request = decodeRunRequest(logs?.[3]) - }) - - it('emits an event marking the request fulfilled', async () => { - const tx = await oc - .connect(roles.defaultAccount) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - const { logs } = await tx.wait() - - const event = logs && cc.interface.parseLog(logs[1]) - - assert.equal(2, logs?.length) - assert.equal(event?.name, 'ChainlinkFulfilled') - assert.equal(request.requestId, event?.args.id) - }) - - it('should only allow one fulfillment per id', async () => { - await oc - .connect(roles.defaultAccount) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - - await evmRevert( - oc - .connect(roles.defaultAccount) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Must have a valid requestId', - ) - }) - - it('should only allow the oracle to fulfill the request', async () => { - await evmRevert( - oc - .connect(roles.stranger) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Not authorized sender', - ) - }) - }) - - describe('#fulfillChainlinkRequest(function)', () => { - let request: RunRequest - - beforeEach(async () => { - await oc.setAuthorizedSenders([await roles.defaultAccount.getAddress()]) - const tx = await cc.publicRequest( - specId, - cc.address, - ethers.utils.toUtf8Bytes( - 'publicFulfillChainlinkRequest(bytes32,bytes32)', - ), - 0, - ) - const { logs } = await tx.wait() - - request = decodeRunRequest(logs?.[3]) - }) - - it('emits an event marking the request fulfilled', async () => { - const tx = await oc - .connect(roles.defaultAccount) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - - const { logs } = await tx.wait() - const event = logs && cc.interface.parseLog(logs[1]) - - assert.equal(2, logs?.length) - assert.equal(event?.name, 'ChainlinkFulfilled') - assert.equal(request.requestId, event?.args?.id) - }) - - it('should only allow one fulfillment per id', async () => { - await oc - .connect(roles.defaultAccount) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - - await evmRevert( - oc - .connect(roles.defaultAccount) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Must have a valid requestId', - ) - }) - - it('should only allow the oracle to fulfill the request', async () => { - await evmRevert( - oc - .connect(roles.stranger) - .fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ), - 'Not authorized sender', - ) - }) - }) - - describe('#chainlinkToken', () => { - it('returns the Link Token address', async () => { - const addr = await cc.publicChainlinkToken() - assert.equal(addr, link.address) - }) - }) - - describe('#addExternalRequest', () => { - let mock: Contract - let request: RunRequest - - beforeEach(async () => { - mock = await concreteChainlinkClientFactory - .connect(roles.defaultAccount) - .deploy(link.address, oc.address) - - const tx = await cc.publicRequest( - specId, - mock.address, - ethers.utils.toUtf8Bytes('fulfillRequest(bytes32,bytes32)'), - 0, - ) - const receipt = await tx.wait() - - request = decodeRunRequest(receipt.logs?.[3]) - await mock.publicAddExternalRequest(oc.address, request.requestId) - }) - - it('allows the external request to be fulfilled', async () => { - await oc.setAuthorizedSenders([await roles.defaultAccount.getAddress()]) - await oc.fulfillOracleRequest( - ...convertFufillParams( - request, - ethers.utils.formatBytes32String('hi mom!'), - ), - ) - }) - - it('does not allow the same requestId to be used', async () => { - await evmRevert( - cc.publicAddExternalRequest(newoc.address, request.requestId), - ) - }) - }) -}) diff --git a/contracts/test/v0.7/CompoundPriceFlaggingValidator.test.ts b/contracts/test/v0.7/CompoundPriceFlaggingValidator.test.ts deleted file mode 100644 index 315f7bd9e6..0000000000 --- a/contracts/test/v0.7/CompoundPriceFlaggingValidator.test.ts +++ /dev/null @@ -1,471 +0,0 @@ -import { ethers } from 'hardhat' -import { evmWordToAddress, getLogs, publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { - BigNumber, - Contract, - ContractFactory, - ContractTransaction, -} from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { evmRevert } from '../test-helpers/matchers' - -let personas: Personas -let validatorFactory: ContractFactory -let acFactory: ContractFactory -let flagsFactory: ContractFactory -let aggregatorFactory: ContractFactory -let compoundOracleFactory: ContractFactory - -before(async () => { - personas = (await getUsers()).personas - - validatorFactory = await ethers.getContractFactory( - 'src/v0.7/dev/CompoundPriceFlaggingValidator.sol:CompoundPriceFlaggingValidator', - personas.Carol, - ) - acFactory = await ethers.getContractFactory( - 'src/v0.6/SimpleWriteAccessController.sol:SimpleWriteAccessController', - personas.Carol, - ) - flagsFactory = await ethers.getContractFactory( - 'src/v0.6/Flags.sol:Flags', - personas.Carol, - ) - aggregatorFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', - personas.Carol, - ) - compoundOracleFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MockCompoundOracle.sol:MockCompoundOracle', - personas.Carol, - ) -}) - -describe('CompoundPriceFlaggingVlidator', () => { - let validator: Contract - let aggregator: Contract - let compoundOracle: Contract - let flags: Contract - let ac: Contract - - const aggregatorDecimals = 18 - // 1000 - const initialAggregatorPrice = BigNumber.from('1000000000000000000000') - - const compoundSymbol = 'ETH' - const compoundDecimals = 6 - // 1100 (10% deviation from aggregator price) - const initialCompoundPrice = BigNumber.from('1100000000') - - // (50,000,000 / 1,000,000,000) = 0.05 = 5% deviation threshold - const initialDeviationNumerator = 50_000_000 - - beforeEach(async () => { - ac = await acFactory.connect(personas.Carol).deploy() - flags = await flagsFactory.connect(personas.Carol).deploy(ac.address) - aggregator = await aggregatorFactory - .connect(personas.Carol) - .deploy(aggregatorDecimals, initialAggregatorPrice) - compoundOracle = await compoundOracleFactory - .connect(personas.Carol) - .deploy() - await compoundOracle.setPrice( - compoundSymbol, - initialCompoundPrice, - compoundDecimals, - ) - validator = await validatorFactory - .connect(personas.Carol) - .deploy(flags.address, compoundOracle.address) - await validator - .connect(personas.Carol) - .setFeedDetails( - aggregator.address, - compoundSymbol, - compoundDecimals, - initialDeviationNumerator, - ) - await ac.connect(personas.Carol).addAccess(validator.address) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(validator, [ - 'update', - 'check', - 'setFeedDetails', - 'setFlagsAddress', - 'setCompoundOpenOracleAddress', - 'getFeedDetails', - 'flags', - 'compoundOpenOracle', - // Upkeep methods: - 'checkUpkeep', - 'performUpkeep', - // Owned methods: - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('#constructor', () => { - it('sets the owner', async () => { - assert.equal(await validator.owner(), await personas.Carol.getAddress()) - }) - - it('sets the arguments passed in', async () => { - assert.equal(await validator.flags(), flags.address) - assert.equal(await validator.compoundOpenOracle(), compoundOracle.address) - }) - }) - - describe('#setOpenOracleAddress', () => { - let newCompoundOracle: Contract - let tx: ContractTransaction - - beforeEach(async () => { - newCompoundOracle = await compoundOracleFactory - .connect(personas.Carol) - .deploy() - tx = await validator - .connect(personas.Carol) - .setCompoundOpenOracleAddress(newCompoundOracle.address) - }) - - it('changes the compound oracke address', async () => { - assert.equal( - await validator.compoundOpenOracle(), - newCompoundOracle.address, - ) - }) - - it('emits a log event', async () => { - await expect(tx) - .to.emit(validator, 'CompoundOpenOracleAddressUpdated') - .withArgs(compoundOracle.address, newCompoundOracle.address) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - validator - .connect(personas.Neil) - .setCompoundOpenOracleAddress(newCompoundOracle.address), - 'Only callable by owner', - ) - }) - }) - }) - - describe('#setFlagsAddress', () => { - let newFlagsContract: Contract - let tx: ContractTransaction - - beforeEach(async () => { - newFlagsContract = await flagsFactory - .connect(personas.Carol) - .deploy(ac.address) - tx = await validator - .connect(personas.Carol) - .setFlagsAddress(newFlagsContract.address) - }) - - it('changes the flags address', async () => { - assert.equal(await validator.flags(), newFlagsContract.address) - }) - - it('emits a log event', async () => { - await expect(tx) - .to.emit(validator, 'FlagsAddressUpdated') - .withArgs(flags.address, newFlagsContract.address) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - validator - .connect(personas.Neil) - .setFlagsAddress(newFlagsContract.address), - 'Only callable by owner', - ) - }) - }) - }) - - describe('#setFeedDetails', () => { - let mockAggregator: Contract - let tx: ContractTransaction - const symbol = 'BTC' - const decimals = 8 - const deviationNumerator = 50_000_000 // 5% - - beforeEach(async () => { - await compoundOracle.connect(personas.Carol).setPrice('BTC', 1500000, 2) - mockAggregator = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, 4000000000000) - tx = await validator - .connect(personas.Carol) - .setFeedDetails( - mockAggregator.address, - symbol, - decimals, - deviationNumerator, - ) - }) - - it('sets the correct state', async () => { - const response = await validator - .connect(personas.Carol) - .getFeedDetails(mockAggregator.address) - - assert.equal(response[0], symbol) - assert.equal(response[1], decimals) - assert.equal(response[2].toString(), deviationNumerator.toString()) - }) - - it('uses the existing symbol if one already exists', async () => { - const newSymbol = 'LINK' - - await compoundOracle - .connect(personas.Carol) - .setPrice(newSymbol, 1500000, 2) - - tx = await validator - .connect(personas.Carol) - .setFeedDetails( - mockAggregator.address, - newSymbol, - decimals, - deviationNumerator, - ) - - // Check the event - await expect(tx) - .to.emit(validator, 'FeedDetailsSet') - .withArgs(mockAggregator.address, symbol, decimals, deviationNumerator) - - // Check the state - const response = await validator - .connect(personas.Carol) - .getFeedDetails(mockAggregator.address) - assert.equal(response[0], symbol) - }) - - it('emits an event', async () => { - await expect(tx) - .to.emit(validator, 'FeedDetailsSet') - .withArgs(mockAggregator.address, symbol, decimals, deviationNumerator) - }) - - it('fails when given a 0 numerator', async () => { - await evmRevert( - validator - .connect(personas.Carol) - .setFeedDetails(mockAggregator.address, symbol, decimals, 0), - 'Invalid threshold numerator', - ) - }) - - it('fails when given a numerator above 1 billion', async () => { - await evmRevert( - validator - .connect(personas.Carol) - .setFeedDetails( - mockAggregator.address, - symbol, - decimals, - 1_200_000_000, - ), - 'Invalid threshold numerator', - ) - }) - - it('fails when the compound price is invalid', async () => { - await evmRevert( - validator - .connect(personas.Carol) - .setFeedDetails( - mockAggregator.address, - 'TEST', - decimals, - deviationNumerator, - ), - 'Invalid Compound price', - ) - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - validator - .connect(personas.Neil) - .setFeedDetails( - mockAggregator.address, - symbol, - decimals, - deviationNumerator, - ), - 'Only callable by owner', - ) - }) - }) - }) - - describe('#check', () => { - describe('with a single aggregator', () => { - describe('with a deviated price exceding threshold', () => { - it('returns the deviated aggregator', async () => { - const aggregators = [aggregator.address] - const response = await validator.check(aggregators) - assert.equal(response.length, 1) - assert.equal(response[0], aggregator.address) - }) - }) - - describe('with a price within the threshold', () => { - const newCompoundPrice = BigNumber.from('1000000000') - beforeEach(async () => { - await compoundOracle.setPrice( - 'ETH', - newCompoundPrice, - compoundDecimals, - ) - }) - - it('returns an empty array', async () => { - const aggregators = [aggregator.address] - const response = await validator.check(aggregators) - assert.equal(response.length, 0) - }) - }) - }) - }) - - describe('#update', () => { - describe('with a single aggregator', () => { - describe('with a deviated price exceding threshold', () => { - it('raises a flag on the flags contract', async () => { - const aggregators = [aggregator.address] - const tx = await validator.connect(personas.Carol).update(aggregators) - const logs = await getLogs(tx) - assert.equal(logs.length, 1) - assert.equal(evmWordToAddress(logs[0].topics[1]), aggregator.address) - }) - }) - - describe('with a price within the threshold', () => { - const newCompoundPrice = BigNumber.from('1000000000') - beforeEach(async () => { - await compoundOracle.setPrice( - 'ETH', - newCompoundPrice, - compoundDecimals, - ) - }) - - it('does nothing', async () => { - const aggregators = [aggregator.address] - const tx = await validator.connect(personas.Carol).update(aggregators) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - }) - }) - - describe('#checkUpkeep', () => { - describe('with a single aggregator', () => { - describe('with a deviated price exceding threshold', () => { - it('returns the deviated aggregator', async () => { - const aggregators = [aggregator.address] - const encodedAggregators = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const response = await validator - .connect(personas.Carol) - .checkUpkeep(encodedAggregators) - - const decodedResponse = ethers.utils.defaultAbiCoder.decode( - ['address[]'], - response?.[1], - ) - assert.equal(decodedResponse?.[0]?.[0], aggregators[0]) - }) - }) - - describe('with a price within the threshold', () => { - const newCompoundPrice = BigNumber.from('1000000000') - beforeEach(async () => { - await compoundOracle.setPrice( - 'ETH', - newCompoundPrice, - compoundDecimals, - ) - }) - - it('returns an empty array', async () => { - const aggregators = [aggregator.address] - const encodedAggregators = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const response = await validator - .connect(personas.Carol) - .checkUpkeep(encodedAggregators) - const decodedResponse = ethers.utils.defaultAbiCoder.decode( - ['address[]'], - response?.[1], - ) - assert.equal(decodedResponse?.[0]?.length, 0) - }) - }) - }) - }) - - describe('#performUpkeep', () => { - describe('with a single aggregator', () => { - describe('with a deviated price exceding threshold', () => { - it('raises a flag on the flags contract', async () => { - const aggregators = [aggregator.address] - const encodedAggregators = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const tx = await validator - .connect(personas.Carol) - .performUpkeep(encodedAggregators) - const logs = await getLogs(tx) - assert.equal(logs.length, 1) - assert.equal(evmWordToAddress(logs[0].topics[1]), aggregator.address) - }) - }) - - describe('with a price within the threshold', () => { - const newCompoundPrice = BigNumber.from('1000000000') - beforeEach(async () => { - await compoundOracle.setPrice( - 'ETH', - newCompoundPrice, - compoundDecimals, - ) - }) - - it('does nothing', async () => { - const aggregators = [aggregator.address] - const encodedAggregators = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const tx = await validator - .connect(personas.Carol) - .performUpkeep(encodedAggregators) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - }) - }) -}) diff --git a/contracts/test/v0.7/ConfirmedOwner.test.ts b/contracts/test/v0.7/ConfirmedOwner.test.ts deleted file mode 100644 index 3502cd15bc..0000000000 --- a/contracts/test/v0.7/ConfirmedOwner.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { ethers } from 'hardhat' -import { publicAbi } from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Contract, ContractFactory, Signer } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { evmRevert } from '../test-helpers/matchers' - -let confirmedOwnerTestHelperFactory: ContractFactory -let confirmedOwnerFactory: ContractFactory - -let personas: Personas -let owner: Signer -let nonOwner: Signer -let newOwner: Signer - -before(async () => { - const users = await getUsers() - personas = users.personas - owner = personas.Carol - nonOwner = personas.Neil - newOwner = personas.Ned - - confirmedOwnerTestHelperFactory = await ethers.getContractFactory( - 'src/v0.7/tests/ConfirmedOwnerTestHelper.sol:ConfirmedOwnerTestHelper', - owner, - ) - confirmedOwnerFactory = await ethers.getContractFactory( - 'src/v0.7/ConfirmedOwner.sol:ConfirmedOwner', - owner, - ) -}) - -describe('ConfirmedOwner', () => { - let confirmedOwner: Contract - - beforeEach(async () => { - confirmedOwner = await confirmedOwnerTestHelperFactory - .connect(owner) - .deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(confirmedOwner, [ - 'acceptOwnership', - 'owner', - 'transferOwnership', - // test helper public methods - 'modifierOnlyOwner', - ]) - }) - - describe('#constructor', () => { - it('assigns ownership to the deployer', async () => { - const [actual, expected] = await Promise.all([ - owner.getAddress(), - confirmedOwner.owner(), - ]) - - assert.equal(actual, expected) - }) - - it('reverts if assigned to the zero address', async () => { - await evmRevert( - confirmedOwnerFactory - .connect(owner) - .deploy(ethers.constants.AddressZero), - 'Cannot set owner to zero', - ) - }) - }) - - describe('#onlyOwner modifier', () => { - describe('when called by an owner', () => { - it('successfully calls the method', async () => { - const tx = await confirmedOwner.connect(owner).modifierOnlyOwner() - await expect(tx).to.emit(confirmedOwner, 'Here') - }) - }) - - describe('when called by anyone but the owner', () => { - it('reverts', async () => - await evmRevert(confirmedOwner.connect(nonOwner).modifierOnlyOwner())) - }) - }) - - describe('#transferOwnership', () => { - describe('when called by an owner', () => { - it('emits a log', async () => { - const tx = await confirmedOwner - .connect(owner) - .transferOwnership(await newOwner.getAddress()) - await expect(tx) - .to.emit(confirmedOwner, 'OwnershipTransferRequested') - .withArgs(await owner.getAddress(), await newOwner.getAddress()) - }) - - it('does not allow ownership transfer to self', async () => { - await evmRevert( - confirmedOwner - .connect(owner) - .transferOwnership(await owner.getAddress()), - 'Cannot transfer to self', - ) - }) - }) - }) - - describe('when called by anyone but the owner', () => { - it('reverts', async () => - await evmRevert( - confirmedOwner - .connect(nonOwner) - .transferOwnership(await newOwner.getAddress()), - )) - }) - - describe('#acceptOwnership', () => { - describe('after #transferOwnership has been called', () => { - beforeEach(async () => { - await confirmedOwner - .connect(owner) - .transferOwnership(await newOwner.getAddress()) - }) - - it('allows the recipient to call it', async () => { - const tx = await confirmedOwner.connect(newOwner).acceptOwnership() - await expect(tx) - .to.emit(confirmedOwner, 'OwnershipTransferred') - .withArgs(await owner.getAddress(), await newOwner.getAddress()) - }) - - it('does not allow a non-recipient to call it', async () => - await evmRevert(confirmedOwner.connect(nonOwner).acceptOwnership())) - }) - }) -}) diff --git a/contracts/test/v0.7/KeeperRegistry1_1.test.ts b/contracts/test/v0.7/KeeperRegistry1_1.test.ts deleted file mode 100644 index 4e3a8c91b3..0000000000 --- a/contracts/test/v0.7/KeeperRegistry1_1.test.ts +++ /dev/null @@ -1,1725 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { evmRevert } from '../test-helpers/matchers' -import { getUsers, Personas } from '../test-helpers/setup' -import { BigNumber, BigNumberish, Signer } from 'ethers' -import { LinkToken__factory as LinkTokenFactory } from '../../typechain/factories/LinkToken__factory' -import { KeeperRegistry1_1__factory as KeeperRegistryFactory } from '../../typechain/factories/KeeperRegistry1_1__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../typechain/factories/UpkeepMock__factory' -import { UpkeepReverter__factory as UpkeepReverterFactory } from '../../typechain/factories/UpkeepReverter__factory' -import { KeeperRegistry1_1 as KeeperRegistry } from '../../typechain/KeeperRegistry1_1' -import { MockV3Aggregator } from '../../typechain/MockV3Aggregator' -import { LinkToken } from '../../typechain/LinkToken' -import { UpkeepMock } from '../../typechain/UpkeepMock' -import { toWei } from '../test-helpers/helpers' - -async function getUpkeepID(tx: any) { - const receipt = await tx.wait() - return receipt.events[0].args.id -} - -// ----------------------------------------------------------------------------------------------- -// DEV: these *should* match the perform/check gas overhead values in the contract and on the node -const PERFORM_GAS_OVERHEAD = BigNumber.from(90000) -const CHECK_GAS_OVERHEAD = BigNumber.from(170000) -// ----------------------------------------------------------------------------------------------- - -// Smart contract factories -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let keeperRegistryFactory: KeeperRegistryFactory -let upkeepMockFactory: UpkeepMockFactory -let upkeepReverterFactory: UpkeepReverterFactory - -let personas: Personas - -before(async () => { - personas = (await getUsers()).personas - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - // need full path because there are two contracts with name MockV3Aggregator - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - // @ts-ignore bug in autogen file - keeperRegistryFactory = await ethers.getContractFactory('KeeperRegistry1_1') - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') - upkeepReverterFactory = await ethers.getContractFactory('UpkeepReverter') -}) - -describe('KeeperRegistry1_1', () => { - const linkEth = BigNumber.from(300000000) - const gasWei = BigNumber.from(100) - const linkDivisibility = BigNumber.from('1000000000000000000') - const executeGas = BigNumber.from('100000') - const paymentPremiumBase = BigNumber.from('1000000000') - const paymentPremiumPPB = BigNumber.from('250000000') - const flatFeeMicroLink = BigNumber.from(0) - const blockCountPerTurn = BigNumber.from(3) - const emptyBytes = '0x00' - const zeroAddress = ethers.constants.AddressZero - const extraGas = BigNumber.from('250000') - const registryGasOverhead = BigNumber.from('80000') - const stalenessSeconds = BigNumber.from(43820) - const gasCeilingMultiplier = BigNumber.from(1) - const maxCheckGas = BigNumber.from(20000000) - const fallbackGasPrice = BigNumber.from(200) - const fallbackLinkPrice = BigNumber.from(200000000) - - let owner: Signer - let keeper1: Signer - let keeper2: Signer - let keeper3: Signer - let nonkeeper: Signer - let admin: Signer - let payee1: Signer - let payee2: Signer - let payee3: Signer - - let linkToken: LinkToken - let linkEthFeed: MockV3Aggregator - let gasPriceFeed: MockV3Aggregator - let registry: KeeperRegistry - let mock: UpkeepMock - - let id: BigNumber - let keepers: string[] - let payees: string[] - - beforeEach(async () => { - owner = personas.Default - keeper1 = personas.Carol - keeper2 = personas.Eddy - keeper3 = personas.Nancy - nonkeeper = personas.Ned - admin = personas.Neil - payee1 = personas.Nelly - payee2 = personas.Norbert - payee3 = personas.Nick - - keepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - payees = [ - await payee1.getAddress(), - await payee2.getAddress(), - await payee3.getAddress(), - ] - - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - registry = await keeperRegistryFactory - .connect(owner) - .deploy( - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - maxCheckGas, - stalenessSeconds, - gasCeilingMultiplier, - fallbackGasPrice, - fallbackLinkPrice, - ) - - mock = await upkeepMockFactory.deploy() - await linkToken - .connect(owner) - .transfer(await keeper1.getAddress(), toWei('1000')) - await linkToken - .connect(owner) - .transfer(await keeper2.getAddress(), toWei('1000')) - await linkToken - .connect(owner) - .transfer(await keeper3.getAddress(), toWei('1000')) - - await registry.connect(owner).setKeepers(keepers, payees) - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - }) - - const linkForGas = ( - upkeepGasSpent: BigNumberish, - premiumPPB?: BigNumberish, - flatFee?: BigNumberish, - ) => { - premiumPPB = premiumPPB === undefined ? paymentPremiumPPB : premiumPPB - flatFee = flatFee === undefined ? flatFeeMicroLink : flatFee - const gasSpent = registryGasOverhead.add(BigNumber.from(upkeepGasSpent)) - const base = gasWei.mul(gasSpent).mul(linkDivisibility).div(linkEth) - const premium = base.mul(premiumPPB).div(paymentPremiumBase) - const flatFeeJules = BigNumber.from(flatFee).mul('1000000000000') - return base.add(premium).add(flatFeeJules) - } - - describe('#setKeepers', () => { - const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' - it('reverts when not called by the owner', async () => { - await evmRevert( - registry.connect(keeper1).setKeepers([], []), - 'Only callable by owner', - ) - }) - - it('reverts when adding the same keeper twice', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper1.getAddress()], - [await payee1.getAddress(), await payee1.getAddress()], - ), - 'cannot add keeper twice', - ) - }) - - it('reverts with different numbers of keepers/payees', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [await payee1.getAddress()], - ), - 'address lists not the same length', - ) - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress()], - [await payee1.getAddress(), await payee2.getAddress()], - ), - 'address lists not the same length', - ) - }) - - it('reverts if the payee is the zero address', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [ - await payee1.getAddress(), - '0x0000000000000000000000000000000000000000', - ], - ), - 'cannot set payee to the zero address', - ) - }) - - it('emits events for every keeper added and removed', async () => { - const oldKeepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - ] - const oldPayees = [await payee1.getAddress(), await payee2.getAddress()] - await registry.connect(owner).setKeepers(oldKeepers, oldPayees) - assert.deepEqual(oldKeepers, await registry.getKeeperList()) - - // remove keepers - const newKeepers = [ - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - const newPayees = [await payee2.getAddress(), await payee3.getAddress()] - const tx = await registry.connect(owner).setKeepers(newKeepers, newPayees) - assert.deepEqual(newKeepers, await registry.getKeeperList()) - - await expect(tx) - .to.emit(registry, 'KeepersUpdated') - .withArgs(newKeepers, newPayees) - }) - - it('updates the keeper to inactive when removed', async () => { - await registry.connect(owner).setKeepers(keepers, payees) - await registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper3.getAddress()], - [await payee1.getAddress(), await payee3.getAddress()], - ) - const added = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.isTrue(added.active) - const removed = await registry.getKeeperInfo(await keeper2.getAddress()) - assert.isFalse(removed.active) - }) - - it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { - const oldKeepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - ] - const oldPayees = [await payee1.getAddress(), await payee2.getAddress()] - await registry.connect(owner).setKeepers(oldKeepers, oldPayees) - assert.deepEqual(oldKeepers, await registry.getKeeperList()) - - const newKeepers = [ - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - const newPayees = [IGNORE_ADDRESS, await payee3.getAddress()] - const tx = await registry.connect(owner).setKeepers(newKeepers, newPayees) - assert.deepEqual(newKeepers, await registry.getKeeperList()) - - const ignored = await registry.getKeeperInfo(await keeper2.getAddress()) - assert.equal(await payee2.getAddress(), ignored.payee) - assert.equal(true, ignored.active) - - await expect(tx) - .to.emit(registry, 'KeepersUpdated') - .withArgs(newKeepers, newPayees) - }) - - it('reverts if the owner changes the payee', async () => { - await registry.connect(owner).setKeepers(keepers, payees) - await evmRevert( - registry - .connect(owner) - .setKeepers(keepers, [ - await payee1.getAddress(), - await payee2.getAddress(), - await owner.getAddress(), - ]), - 'cannot change payee', - ) - }) - }) - - describe('#registerUpkeep', () => { - it('reverts if the target is not a contract', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - zeroAddress, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'target is not a contract', - ) - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry - .connect(keeper1) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'Only callable by owner or registrar', - ) - }) - - it('reverts if execute gas is too low', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 2299, - await admin.getAddress(), - emptyBytes, - ), - 'min gas is 2300', - ) - }) - - it('reverts if execute gas is too high', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 5000001, - await admin.getAddress(), - emptyBytes, - ), - 'max gas is 5000000', - ) - }) - - it('creates a record of the registration', async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - await expect(tx) - .to.emit(registry, 'UpkeepRegistered') - .withArgs(id, executeGas, await admin.getAddress()) - const registration = await registry.getUpkeep(id) - assert.equal(mock.address, registration.target) - assert.equal(0, registration.balance.toNumber()) - assert.equal(emptyBytes, registration.checkData) - assert(registration.maxValidBlocknumber.eq('0xffffffffffffffff')) - }) - }) - - describe('#addFunds', () => { - const amount = toWei('1') - - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - }) - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).addFunds(id.add(1), amount), - 'upkeep must be active', - ) - }) - - it('adds to the balance of the registration', async () => { - await registry.connect(keeper1).addFunds(id, amount) - const registration = await registry.getUpkeep(id) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('emits a log', async () => { - const tx = await registry.connect(keeper1).addFunds(id, amount) - await expect(tx) - .to.emit(registry, 'FundsAdded') - .withArgs(id, await keeper1.getAddress(), amount) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).addFunds(id, amount), - 'upkeep must be active', - ) - }) - }) - - describe('#checkUpkeep', () => { - it('reverts if the upkeep is not funded', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'insufficient funds', - ) - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - }) - - it('reverts if executed', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry.checkUpkeep(id, await keeper1.getAddress()), - 'only for simulated backend', - ) - }) - - it('reverts if the specified keeper is not valid', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry.checkUpkeep(id, await owner.getAddress()), - 'only for simulated backend', - ) - }) - - context('and upkeep is not needed', () => { - beforeEach(async () => { - await mock.setCanCheck(false) - }) - - it('reverts', async () => { - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'upkeep not needed', - ) - }) - }) - - context('and the upkeep check fails', () => { - beforeEach(async () => { - const reverter = await upkeepReverterFactory.deploy() - const tx = await registry - .connect(owner) - .registerUpkeep( - reverter.address, - 2500000, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - await linkToken - .connect(keeper1) - .approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - }) - - it('reverts', async () => { - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'call to check target failed', - ) - }) - }) - - context('and upkeep check simulations succeeds', () => { - beforeEach(async () => { - await mock.setCanCheck(true) - await mock.setCanPerform(true) - }) - - context('and the registry is paused', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts', async () => { - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'Pausable: paused', - ) - - await registry.connect(owner).unpause() - - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()) - }) - }) - - it('returns true with pricing info if the target can execute', async () => { - const newGasMultiplier = BigNumber.from(10) - await registry - .connect(owner) - .setConfig( - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - maxCheckGas, - stalenessSeconds, - newGasMultiplier, - fallbackGasPrice, - fallbackLinkPrice, - ) - const response = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()) - assert.isTrue(response.gasLimit.eq(executeGas)) - assert.isTrue(response.linkEth.eq(linkEth)) - assert.isTrue( - response.adjustedGasWei.eq(gasWei.mul(newGasMultiplier)), - ) - assert.isTrue( - response.maxLinkPayment.eq( - linkForGas(executeGas.toNumber()).mul(newGasMultiplier), - ), - ) - }) - - it('has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', async () => { - await mock.setCheckGasToBurn(maxCheckGas) - await mock.setPerformGasToBurn(executeGas) - const gas = maxCheckGas - .add(executeGas) - .add(PERFORM_GAS_OVERHEAD) - .add(CHECK_GAS_OVERHEAD) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress(), { - gasLimit: gas, - }) - }) - }) - }) - }) - - describe('#performUpkeep', () => { - let _lastKeeper = keeper1 - async function getPerformPaymentAmount() { - _lastKeeper = _lastKeeper === keeper1 ? keeper2 : keeper1 - const before = ( - await registry.getKeeperInfo(await _lastKeeper.getAddress()) - ).balance - await registry.connect(_lastKeeper).performUpkeep(id, '0x') - const after = ( - await registry.getKeeperInfo(await _lastKeeper.getAddress()) - ).balance - const difference = after.sub(before) - return difference - } - - it('reverts if the registration is not funded', async () => { - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'insufficient funds', - ) - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - }) - - it('does not revert if the target cannot execute', async () => { - const mockResponse = await mock - .connect(zeroAddress) - .callStatic.checkUpkeep('0x') - assert.isFalse(mockResponse.callable) - - await registry.connect(keeper3).performUpkeep(id, '0x') - }) - - it('returns false if the target cannot execute', async () => { - const mockResponse = await mock - .connect(zeroAddress) - .callStatic.checkUpkeep('0x') - assert.isFalse(mockResponse.callable) - - assert.isFalse( - await registry.connect(keeper1).callStatic.performUpkeep(id, '0x'), - ) - }) - - it('returns true if called', async () => { - await mock.setCanPerform(true) - - const response = await registry - .connect(keeper1) - .callStatic.performUpkeep(id, '0x') - assert.isTrue(response) - }) - - it('reverts if not enough gas supplied', async () => { - await mock.setCanPerform(true) - - await evmRevert( - registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasLimit: BigNumber.from('120000') }), - ) - }) - - it('executes the data passed to the registry', async () => { - await mock.setCanPerform(true) - - const performData = '0xc0ffeec0ffee' - const tx = await registry - .connect(keeper1) - .performUpkeep(id, performData, { gasLimit: extraGas }) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 2) - assert.equal(eventLog?.[1].event, 'UpkeepPerformed') - assert.equal(eventLog?.[1].args?.[0].toNumber(), id.toNumber()) - assert.equal(eventLog?.[1].args?.[1], true) - assert.equal(eventLog?.[1].args?.[2], await keeper1.getAddress()) - assert.isNotEmpty(eventLog?.[1].args?.[3]) - assert.equal(eventLog?.[1].args?.[4], performData) - }) - - it('updates payment balances', async () => { - const keeperBefore = await registry.getKeeperInfo( - await keeper1.getAddress(), - ) - const registrationBefore = await registry.getUpkeep(id) - const keeperLinkBefore = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const keeperAfter = await registry.getKeeperInfo( - await keeper1.getAddress(), - ) - const registrationAfter = await registry.getUpkeep(id) - const keeperLinkAfter = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(keeperAfter.balance.gt(keeperBefore.balance)) - assert.isTrue(registrationBefore.balance.gt(registrationAfter.balance)) - assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) - assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) - }) - - it('only pays for gas used [ @skip-coverage ]', async () => { - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry.connect(keeper1).performUpkeep(id, '0x') - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas.toNumber()) - const totalTx = linkForGas(receipt.gasUsed.toNumber()) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).lt(difference)) // exact number is flaky - assert.isTrue(linkForGas(6000).gt(difference)) // instead test a range - }) - - it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { - const multiplier = BigNumber.from(10) - const gasPrice = BigNumber.from('1000000000') // 10M x the gas feed's rate - await registry - .connect(owner) - .setConfig( - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - maxCheckGas, - stalenessSeconds, - multiplier, - fallbackGasPrice, - fallbackLinkPrice, - ) - - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasPrice }) - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas).mul(multiplier) - const totalTx = linkForGas(receipt.gasUsed).mul(multiplier) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).mul(multiplier).lt(difference)) - assert.isTrue(linkForGas(6000).mul(multiplier).gt(difference)) - }) - - it('only pays as much as the node spent [ @skip-coverage ]', async () => { - const multiplier = BigNumber.from(10) - const gasPrice = BigNumber.from(200) // 2X the gas feed's rate - const effectiveMultiplier = BigNumber.from(2) - await registry - .connect(owner) - .setConfig( - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - maxCheckGas, - stalenessSeconds, - multiplier, - fallbackGasPrice, - fallbackLinkPrice, - ) - - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasPrice }) - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas.toNumber()).mul(effectiveMultiplier) - const totalTx = linkForGas(receipt.gasUsed).mul(effectiveMultiplier) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).mul(effectiveMultiplier).lt(difference)) - assert.isTrue(linkForGas(6000).mul(effectiveMultiplier).gt(difference)) - }) - - it('pays the caller even if the target function fails', async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id = await getUpkeepID(tx) - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - const keeperBalanceBefore = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const keeperBalanceAfter = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - assert.isTrue(keeperBalanceAfter.gt(keeperBalanceBefore)) - }) - - it('reverts if called by a non-keeper', async () => { - await evmRevert( - registry.connect(nonkeeper).performUpkeep(id, '0x'), - 'only active keepers', - ) - }) - - it('reverts if the upkeep has been canceled', async () => { - await mock.setCanPerform(true) - - await registry.connect(owner).cancelUpkeep(id) - - await evmRevert( - registry.connect(keeper1).performUpkeep(id, '0x'), - 'invalid upkeep id', - ) - }) - - it('uses the fallback gas price if the feed price is stale [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const answer = 100 - const updatedAt = 946684800 // New Years 2000 🥳 - const startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - const amountWithStaleFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithStaleFeed)) - }) - - it('uses the fallback gas price if the feed price is non-sensical [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const updatedAt = Math.floor(Date.now() / 1000) - const startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - const amountWithNegativeFeed = await getPerformPaymentAmount() - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - const amountWithZeroFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithNegativeFeed)) - assert.isTrue(normalAmount.lt(amountWithZeroFeed)) - }) - - it('uses the fallback if the link price feed is stale', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const answer = 100 - const updatedAt = 946684800 // New Years 2000 🥳 - const startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - const amountWithStaleFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithStaleFeed)) - }) - - it('uses the fallback link price if the feed price is non-sensical', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const updatedAt = Math.floor(Date.now() / 1000) - const startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - const amountWithNegativeFeed = await getPerformPaymentAmount() - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - const amountWithZeroFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithNegativeFeed)) - assert.isTrue(normalAmount.lt(amountWithZeroFeed)) - }) - - it('reverts if the same caller calls twice in a row', async () => { - await registry.connect(keeper1).performUpkeep(id, '0x') - await evmRevert( - registry.connect(keeper1).performUpkeep(id, '0x'), - 'keepers must take turns', - ) - await registry.connect(keeper2).performUpkeep(id, '0x') - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'keepers must take turns', - ) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', async () => { - await mock.setPerformGasToBurn(executeGas) - await mock.setCanPerform(true) - const gas = executeGas.add(PERFORM_GAS_OVERHEAD) - const performData = '0xc0ffeec0ffee' - const tx = await registry - .connect(keeper1) - .performUpkeep(id, performData, { gasLimit: gas }) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 2) - assert.equal(eventLog?.[1].event, 'UpkeepPerformed') - assert.equal(eventLog?.[1].args?.[0].toNumber(), id.toNumber()) - assert.equal(eventLog?.[1].args?.[1], true) - assert.equal(eventLog?.[1].args?.[2], await keeper1.getAddress()) - assert.isNotEmpty(eventLog?.[1].args?.[3]) - assert.equal(eventLog?.[1].args?.[4], performData) - }) - }) - }) - - describe('#withdrawFunds', () => { - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('1')) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry - .connect(owner) - .withdrawFunds(id.add(1).toNumber(), await payee1.getAddress()), - 'only callable by admin', - ) - }) - - it('reverts if called on an uncanceled upkeep', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(id, await payee1.getAddress()), - 'upkeep must be canceled', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(id, zeroAddress), - 'cannot send to zero address', - ) - }) - - describe('after the registration is cancelled', () => { - beforeEach(async () => { - await registry.connect(owner).cancelUpkeep(id) - }) - - it('moves the funds out and updates the balance', async () => { - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const registryBefore = await linkToken.balanceOf(registry.address) - - let registration = await registry.getUpkeep(id) - assert.isTrue(toWei('1').eq(registration.balance)) - - await registry - .connect(admin) - .withdrawFunds(id, await payee1.getAddress()) - - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - const registryAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(payee1Before.add(toWei('1')).eq(payee1After)) - assert.isTrue(registryBefore.sub(toWei('1')).eq(registryAfter)) - - registration = await registry.getUpkeep(id) - assert.equal(0, registration.balance.toNumber()) - }) - }) - }) - - describe('#cancelUpkeep', () => { - it('reverts if the ID is not valid', async () => { - await evmRevert( - registry.connect(owner).cancelUpkeep(id.add(1).toNumber()), - 'too late to cancel upkeep', - ) - }) - - it('reverts if called by a non-owner/non-admin', async () => { - await evmRevert( - registry.connect(keeper1).cancelUpkeep(id), - 'only owner or admin', - ) - }) - - describe('when called by the owner', async () => { - it('sets the registration to invalid immediately', async () => { - const tx = await registry.connect(owner).cancelUpkeep(id) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(id) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).cancelUpkeep(id) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(id, BigNumber.from(receipt.blockNumber)) - }) - - it('updates the canceled registrations list', async () => { - let canceled = await registry.callStatic.getCanceledUpkeepList() - assert.deepEqual([], canceled) - - await registry.connect(owner).cancelUpkeep(id) - - canceled = await registry.callStatic.getCanceledUpkeepList() - assert.deepEqual([id], canceled) - }) - - it('immediately prevents upkeep', async () => { - await registry.connect(owner).cancelUpkeep(id) - - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'invalid upkeep id', - ) - }) - - it('does not revert if reverts if called multiple times', async () => { - await registry.connect(owner).cancelUpkeep(id) - await evmRevert( - registry.connect(owner).cancelUpkeep(id), - 'too late to cancel upkeep', - ) - }) - - describe('when called by the owner when the admin has just canceled', () => { - let oldExpiration: BigNumber - - beforeEach(async () => { - await registry.connect(admin).cancelUpkeep(id) - const registration = await registry.getUpkeep(id) - oldExpiration = registration.maxValidBlocknumber - }) - - it('allows the owner to cancel it more quickly', async () => { - await registry.connect(owner).cancelUpkeep(id) - - const registration = await registry.getUpkeep(id) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - }) - }) - - describe('when called by the admin', async () => { - const delay = 50 - - it('sets the registration to invalid in 50 blocks', async () => { - const tx = await registry.connect(admin).cancelUpkeep(id) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(id) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber + 50, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(admin).cancelUpkeep(id) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(id, BigNumber.from(receipt.blockNumber + delay)) - }) - - it('updates the canceled registrations list', async () => { - let canceled = await registry.callStatic.getCanceledUpkeepList() - assert.deepEqual([], canceled) - - await registry.connect(admin).cancelUpkeep(id) - - canceled = await registry.callStatic.getCanceledUpkeepList() - assert.deepEqual([id], canceled) - }) - - it('immediately prevents upkeep', async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.connect(admin).cancelUpkeep(id) - await registry.connect(keeper2).performUpkeep(id, '0x') // still works - - for (let i = 0; i < delay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'invalid upkeep id', - ) - }) - - it('reverts if called again by the admin', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await evmRevert( - registry.connect(admin).cancelUpkeep(id), - 'too late to cancel upkeep', - ) - }) - - it('does not revert or double add the cancellation record if called by the owner immediately after', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await registry.connect(owner).cancelUpkeep(id) - - const canceled = await registry.callStatic.getCanceledUpkeepList() - assert.deepEqual([id], canceled) - }) - - it('reverts if called by the owner after the timeout', async () => { - await registry.connect(admin).cancelUpkeep(id) - - for (let i = 0; i < delay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(owner).cancelUpkeep(id), - 'too late to cancel upkeep', - ) - }) - }) - }) - - describe('#withdrawPayment', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('reverts if called by anyone but the payee', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ), - 'only callable by payee', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment(await keeper1.getAddress(), zeroAddress), - 'cannot send to zero address', - ) - }) - - it('updates the balances', async () => { - const to = await nonkeeper.getAddress() - const keeperBefore = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const registrationBefore = (await registry.getUpkeep(id)).balance - const toLinkBefore = await linkToken.balanceOf(to) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - - //// Do the thing - await registry - .connect(payee1) - .withdrawPayment(await keeper1.getAddress(), to) - - const keeperAfter = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const registrationAfter = (await registry.getUpkeep(id)).balance - const toLinkAfter = await linkToken.balanceOf(to) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(keeperAfter.eq(BigNumber.from(0))) - assert.isTrue(registrationBefore.eq(registrationAfter)) - assert.isTrue(toLinkBefore.add(keeperBefore).eq(toLinkAfter)) - assert.isTrue(registryLinkBefore.sub(keeperBefore).eq(registryLinkAfter)) - }) - - it('emits a log announcing the withdrawal', async () => { - const balance = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - const tx = await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PaymentWithdrawn') - .withArgs( - await keeper1.getAddress(), - balance, - await nonkeeper.getAddress(), - await payee1.getAddress(), - ) - }) - }) - - describe('#transferPayeeship', () => { - it('reverts when called by anyone but the current payee', async () => { - await evmRevert( - registry - .connect(payee2) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ), - 'only callable by payee', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee1.getAddress(), - ), - 'cannot transfer to self', - ) - }) - - it('does not change the payee', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const info = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.equal(await payee1.getAddress(), info.payee) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferRequested') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does not emit an event when called with the same proposal', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptPayeeship', () => { - beforeEach(async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('reverts when called by anyone but the proposed payee', async () => { - await evmRevert( - registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), - 'only callable by proposed payee', - ) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee2) - .acceptPayeeship(await keeper1.getAddress()) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferred') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does change the payee', async () => { - await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) - - const info = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.equal(await payee2.getAddress(), info.payee) - }) - }) - - describe('#setConfig', () => { - const payment = BigNumber.from(1) - const flatFee = BigNumber.from(2) - const checks = BigNumber.from(3) - const staleness = BigNumber.from(4) - const ceiling = BigNumber.from(5) - const maxGas = BigNumber.from(6) - const fbGasEth = BigNumber.from(7) - const fbLinkEth = BigNumber.from(8) - - it('reverts when called by anyone but the proposed owner', async () => { - await evmRevert( - registry - .connect(payee1) - .setConfig( - payment, - flatFee, - checks, - maxGas, - staleness, - gasCeilingMultiplier, - fbGasEth, - fbLinkEth, - ), - 'Only callable by owner', - ) - }) - - it('updates the config', async () => { - const old = await registry.getConfig() - const oldFlatFee = await registry.getFlatFee() - assert.isTrue(paymentPremiumPPB.eq(old.paymentPremiumPPB)) - assert.isTrue(flatFeeMicroLink.eq(oldFlatFee)) - assert.isTrue(blockCountPerTurn.eq(old.blockCountPerTurn)) - assert.isTrue(stalenessSeconds.eq(old.stalenessSeconds)) - assert.isTrue(gasCeilingMultiplier.eq(old.gasCeilingMultiplier)) - - await registry - .connect(owner) - .setConfig( - payment, - flatFee, - checks, - maxGas, - staleness, - ceiling, - fbGasEth, - fbLinkEth, - ) - - const updated = await registry.getConfig() - const newFlatFee = await registry.getFlatFee() - assert.equal(updated.paymentPremiumPPB, payment.toNumber()) - assert.equal(newFlatFee, flatFee.toNumber()) - assert.equal(updated.blockCountPerTurn, checks.toNumber()) - assert.equal(updated.stalenessSeconds, staleness.toNumber()) - assert.equal(updated.gasCeilingMultiplier, ceiling.toNumber()) - assert.equal(updated.checkGasLimit, maxGas.toNumber()) - assert.equal(updated.fallbackGasPrice.toNumber(), fbGasEth.toNumber()) - assert.equal(updated.fallbackLinkPrice.toNumber(), fbLinkEth.toNumber()) - }) - - it('emits an event', async () => { - const tx = await registry - .connect(owner) - .setConfig( - payment, - flatFee, - checks, - maxGas, - staleness, - ceiling, - fbGasEth, - fbLinkEth, - ) - await expect(tx) - .to.emit(registry, 'ConfigSet') - .withArgs( - payment, - checks, - maxGas, - staleness, - ceiling, - fbGasEth, - fbLinkEth, - ) - }) - }) - - describe('#onTokenTransfer', () => { - const amount = toWei('1') - - it('reverts if not called by the LINK token', async () => { - const data = ethers.utils.defaultAbiCoder.encode( - ['uint256'], - [id.toNumber().toString()], - ) - - await evmRevert( - registry - .connect(keeper1) - .onTokenTransfer(await keeper1.getAddress(), amount, data), - 'only callable through LINK', - ) - }) - - it('reverts if not called with more or less than 32 bytes', async () => { - const longData = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256'], - ['33', '34'], - ) - const shortData = '0x12345678' - - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, longData), - ) - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, shortData), - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).addFunds(id, amount), - 'upkeep must be active', - ) - }) - - it('updates the funds of the job id passed', async () => { - const data = ethers.utils.defaultAbiCoder.encode( - ['uint256'], - [id.toNumber().toString()], - ) - - const before = (await registry.getUpkeep(id)).balance - await linkToken - .connect(owner) - .transferAndCall(registry.address, amount, data) - const after = (await registry.getUpkeep(id)).balance - - assert.isTrue(before.add(amount).eq(after)) - }) - }) - - describe('#recoverFunds', () => { - const sent = toWei('7') - - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - - // add funds to upkeep 1 and perform and withdraw some payment - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id1 = await getUpkeepID(tx) - await registry.connect(keeper1).addFunds(id1, toWei('5')) - await registry.connect(keeper1).performUpkeep(id1, '0x') - await registry.connect(keeper2).performUpkeep(id1, '0x') - await registry.connect(keeper3).performUpkeep(id1, '0x') - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds directly to the registry - await linkToken.connect(keeper1).transfer(registry.address, sent) - - // add funds to upkeep 2 and perform and withdraw some payment - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id2 = await getUpkeepID(tx2) - await registry.connect(keeper1).addFunds(id2, toWei('5')) - await registry.connect(keeper1).performUpkeep(id2, '0x') - await registry.connect(keeper2).performUpkeep(id2, '0x') - await registry.connect(keeper3).performUpkeep(id2, '0x') - await registry - .connect(payee2) - .withdrawPayment( - await keeper2.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds using onTokenTransfer - const data = ethers.utils.defaultAbiCoder.encode( - ['uint256'], - [id2.toNumber().toString()], - ) - await linkToken - .connect(owner) - .transferAndCall(registry.address, toWei('1'), data) - - // remove a keeper - await registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [await payee1.getAddress(), await payee2.getAddress()], - ) - - // withdraw some funds - await registry.connect(owner).cancelUpkeep(id1) - await registry.connect(admin).withdrawFunds(id1, await admin.getAddress()) - }) - - it('reverts if not called by owner', async () => { - await evmRevert( - registry.connect(keeper1).recoverFunds(), - 'Only callable by owner', - ) - }) - - it('allows any funds that have been accidentally transfered to be moved', async () => { - const balanceBefore = await linkToken.balanceOf(registry.address) - - await linkToken.balanceOf(registry.address) - - await registry.connect(owner).recoverFunds() - const balanceAfter = await linkToken.balanceOf(registry.address) - assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) - }) - }) - - describe('#pause', () => { - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).pause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as paused', async () => { - assert.isFalse(await registry.paused()) - - await registry.connect(owner).pause() - - assert.isTrue(await registry.paused()) - }) - }) - - describe('#unpause', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).unpause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as not paused', async () => { - assert.isTrue(await registry.paused()) - - await registry.connect(owner).unpause() - - assert.isFalse(await registry.paused()) - }) - }) - - describe('#getMaxPaymentForGas', () => { - const gasAmounts = [100000, 10000000] - const premiums = [0, 250000000] - const flatFees = [0, 1000000] - it('calculates the max fee approptiately', async () => { - for (let idx = 0; idx < gasAmounts.length; idx++) { - const gas = gasAmounts[idx] - for (let jdx = 0; jdx < premiums.length; jdx++) { - const premium = premiums[jdx] - for (let kdx = 0; kdx < flatFees.length; kdx++) { - const flatFee = flatFees[kdx] - await registry - .connect(owner) - .setConfig( - premium, - flatFee, - blockCountPerTurn, - maxCheckGas, - stalenessSeconds, - gasCeilingMultiplier, - fallbackGasPrice, - fallbackLinkPrice, - ) - const price = await registry.getMaxPaymentForGas(gas) - expect(price).to.equal(linkForGas(gas, premium, flatFee)) - } - } - } - }) - }) - - describe('#checkUpkeep / #performUpkeep', () => { - const performData = '0xc0ffeec0ffee' - const multiplier = BigNumber.from(10) - const flatFee = BigNumber.from('100000') //0.1 LINK - const callGasPrice = 1 - - it('uses the same minimum balance calculation [ @skip-coverage ]', async () => { - await registry - .connect(owner) - .setConfig( - paymentPremiumPPB, - flatFee, - blockCountPerTurn, - maxCheckGas, - stalenessSeconds, - multiplier, - fallbackGasPrice, - fallbackLinkPrice, - ) - await linkToken.connect(owner).approve(registry.address, toWei('100')) - - const tx1 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const upkeepID1 = await getUpkeepID(tx1) - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const upkeepID2 = await getUpkeepID(tx2) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - // upkeep 1 is underfunded, 2 is funded - const minBalance1 = (await registry.getMaxPaymentForGas(executeGas)).sub( - 1, - ) - const minBalance2 = await registry.getMaxPaymentForGas(executeGas) - await registry.connect(owner).addFunds(upkeepID1, minBalance1) - await registry.connect(owner).addFunds(upkeepID2, minBalance2) - // upkeep 1 check should revert, 2 should succeed - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID1, await keeper1.getAddress(), { - gasPrice: callGasPrice, - }), - ) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID2, await keeper1.getAddress(), { - gasPrice: callGasPrice, - }) - // upkeep 1 perform should revert, 2 should succeed - await evmRevert( - registry - .connect(keeper1) - .performUpkeep(upkeepID1, performData, { gasLimit: extraGas }), - 'insufficient funds', - ) - await registry - .connect(keeper1) - .performUpkeep(upkeepID2, performData, { gasLimit: extraGas }) - }) - }) - - describe('#getMinBalanceForUpkeep / #checkUpkeep', () => { - it('calculates the minimum balance appropriately', async () => { - const oneWei = BigNumber.from('1') - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - const minBalance = await registry.getMinBalanceForUpkeep(id) - const tooLow = minBalance.sub(oneWei) - await registry.connect(keeper1).addFunds(id, tooLow) - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'insufficient funds', - ) - await registry.connect(keeper1).addFunds(id, oneWei) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()) - }) - }) -}) diff --git a/contracts/test/v0.7/Operator.test.ts b/contracts/test/v0.7/Operator.test.ts deleted file mode 100644 index 4af846576b..0000000000 --- a/contracts/test/v0.7/Operator.test.ts +++ /dev/null @@ -1,3819 +0,0 @@ -import { ethers } from 'hardhat' -import { - publicAbi, - toBytes32String, - toWei, - stringToBytes, - increaseTime5Minutes, - getLog, -} from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { - BigNumber, - constants, - Contract, - ContractFactory, - ContractReceipt, - ContractTransaction, - Signer, -} from 'ethers' -import { getUsers, Roles } from '../test-helpers/setup' -import { bigNumEquals, evmRevert } from '../test-helpers/matchers' -import type { providers } from 'ethers' -import { - convertCancelParams, - convertCancelByRequesterParams, - convertFufillParams, - convertFulfill2Params, - decodeRunRequest, - encodeOracleRequest, - encodeRequestOracleData, - RunRequest, -} from '../test-helpers/oracle' - -let v7ConsumerFactory: ContractFactory -let basicConsumerFactory: ContractFactory -let multiWordConsumerFactory: ContractFactory -let gasGuzzlingConsumerFactory: ContractFactory -let getterSetterFactory: ContractFactory -let maliciousRequesterFactory: ContractFactory -let maliciousConsumerFactory: ContractFactory -let maliciousMultiWordConsumerFactory: ContractFactory -let operatorFactory: ContractFactory -let forwarderFactory: ContractFactory -let linkTokenFactory: ContractFactory -const zeroAddress = ethers.constants.AddressZero - -let roles: Roles - -before(async () => { - const users = await getUsers() - - roles = users.roles - v7ConsumerFactory = await ethers.getContractFactory( - 'src/v0.7/tests/Consumer.sol:Consumer', - ) - basicConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/BasicConsumer.sol:BasicConsumer', - ) - multiWordConsumerFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MultiWordConsumer.sol:MultiWordConsumer', - ) - gasGuzzlingConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/GasGuzzlingConsumer.sol:GasGuzzlingConsumer', - ) - getterSetterFactory = await ethers.getContractFactory( - 'src/v0.4/tests/GetterSetter.sol:GetterSetter', - ) - maliciousRequesterFactory = await ethers.getContractFactory( - 'src/v0.4/tests/MaliciousRequester.sol:MaliciousRequester', - ) - maliciousConsumerFactory = await ethers.getContractFactory( - 'src/v0.4/tests/MaliciousConsumer.sol:MaliciousConsumer', - ) - maliciousMultiWordConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/MaliciousMultiWordConsumer.sol:MaliciousMultiWordConsumer', - ) - operatorFactory = await ethers.getContractFactory( - 'src/v0.7/Operator.sol:Operator', - ) - forwarderFactory = await ethers.getContractFactory( - 'src/v0.7/AuthorizedForwarder.sol:AuthorizedForwarder', - ) - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) -}) - -describe('Operator', () => { - let fHash: string - let specId: string - let to: string - let link: Contract - let operator: Contract - let forwarder1: Contract - let forwarder2: Contract - let owner: Signer - - beforeEach(async () => { - fHash = getterSetterFactory.interface.getSighash('requestedBytes32') - specId = - '0x4c7b7ffb66b344fbaa64995af81e355a00000000000000000000000000000000' - to = '0x80e29acb842498fe6591f020bd82766dce619d43' - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - owner = roles.defaultAccount - operator = await operatorFactory - .connect(owner) - .deploy(link.address, await owner.getAddress()) - await operator - .connect(roles.defaultAccount) - .setAuthorizedSenders([await roles.oracleNode.getAddress()]) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(operator, [ - 'acceptAuthorizedReceivers', - 'acceptOwnableContracts', - 'cancelOracleRequest', - 'cancelOracleRequestByRequester', - 'distributeFunds', - 'fulfillOracleRequest', - 'fulfillOracleRequest2', - 'getAuthorizedSenders', - 'getChainlinkToken', - 'getExpiryTime', - 'isAuthorizedSender', - 'onTokenTransfer', - 'operatorRequest', - 'oracleRequest', - 'ownerForward', - 'ownerTransferAndCall', - 'setAuthorizedSenders', - 'setAuthorizedSendersOn', - 'transferOwnableContracts', - 'typeAndVersion', - 'withdraw', - 'withdrawable', - // Ownable methods: - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('#typeAndVersion', () => { - it('describes the operator', async () => { - assert.equal(await operator.typeAndVersion(), 'Operator 1.0.0') - }) - }) - - describe('#transferOwnableContracts', () => { - beforeEach(async () => { - forwarder1 = await forwarderFactory - .connect(owner) - .deploy(link.address, operator.address, zeroAddress, '0x') - forwarder2 = await forwarderFactory - .connect(owner) - .deploy(link.address, operator.address, zeroAddress, '0x') - }) - - describe('being called by the owner', () => { - it('cannot transfer to self', async () => { - await evmRevert( - operator - .connect(owner) - .transferOwnableContracts([forwarder1.address], operator.address), - 'Cannot transfer to self', - ) - }) - - it('emits an ownership transfer request event', async () => { - const tx = await operator - .connect(owner) - .transferOwnableContracts( - [forwarder1.address, forwarder2.address], - await roles.oracleNode1.getAddress(), - ) - const receipt = await tx.wait() - assert.equal(receipt?.events?.length, 2) - const log1 = receipt?.events?.[0] - assert.equal(log1?.event, 'OwnershipTransferRequested') - assert.equal(log1?.address, forwarder1.address) - assert.equal(log1?.args?.[0], operator.address) - assert.equal(log1?.args?.[1], await roles.oracleNode1.getAddress()) - const log2 = receipt?.events?.[1] - assert.equal(log2?.event, 'OwnershipTransferRequested') - assert.equal(log2?.address, forwarder2.address) - assert.equal(log2?.args?.[0], operator.address) - assert.equal(log2?.args?.[1], await roles.oracleNode1.getAddress()) - }) - }) - - describe('being called by a non-owner', () => { - it('reverts with message', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .transferOwnableContracts( - [forwarder1.address], - await roles.oracleNode2.getAddress(), - ), - 'Only callable by owner', - ) - }) - }) - }) - - describe('#acceptOwnableContracts', () => { - describe('being called by the owner', () => { - let operator2: Contract - let receipt: ContractReceipt - - beforeEach(async () => { - operator2 = await operatorFactory - .connect(roles.defaultAccount) - .deploy(link.address, await roles.defaultAccount.getAddress()) - forwarder1 = await forwarderFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, zeroAddress, '0x') - forwarder2 = await forwarderFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, zeroAddress, '0x') - await operator - .connect(roles.defaultAccount) - .transferOwnableContracts( - [forwarder1.address, forwarder2.address], - operator2.address, - ) - const tx = await operator2 - .connect(roles.defaultAccount) - .acceptOwnableContracts([forwarder1.address, forwarder2.address]) - receipt = await tx.wait() - }) - - it('sets the new owner on the forwarder', async () => { - assert.equal(await forwarder1.owner(), operator2.address) - }) - - it('emits ownership transferred events', async () => { - assert.equal(receipt?.events?.[0]?.event, 'OwnableContractAccepted') - assert.equal(receipt?.events?.[0]?.args?.[0], forwarder1.address) - - assert.equal(receipt?.events?.[1]?.event, 'OwnershipTransferred') - assert.equal(receipt?.events?.[1]?.address, forwarder1.address) - assert.equal(receipt?.events?.[1]?.args?.[0], operator.address) - assert.equal(receipt?.events?.[1]?.args?.[1], operator2.address) - - assert.equal(receipt?.events?.[2]?.event, 'OwnableContractAccepted') - assert.equal(receipt?.events?.[2]?.args?.[0], forwarder2.address) - - assert.equal(receipt?.events?.[3]?.event, 'OwnershipTransferred') - assert.equal(receipt?.events?.[3]?.address, forwarder2.address) - assert.equal(receipt?.events?.[3]?.args?.[0], operator.address) - assert.equal(receipt?.events?.[3]?.args?.[1], operator2.address) - }) - }) - - describe('being called by a non-owner authorized sender', () => { - it('does not revert', async () => { - await operator - .connect(roles.defaultAccount) - .setAuthorizedSenders([await roles.oracleNode1.getAddress()]) - - await operator.connect(roles.oracleNode1).acceptOwnableContracts([]) - }) - }) - - describe('being called by a non owner', () => { - it('reverts with message', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .acceptOwnableContracts([await roles.oracleNode2.getAddress()]), - 'Cannot set authorized senders', - ) - }) - }) - }) - - describe('#distributeFunds', () => { - describe('when called with empty arrays', () => { - it('reverts with invalid array message', async () => { - await evmRevert( - operator.connect(roles.defaultAccount).distributeFunds([], []), - 'Invalid array length(s)', - ) - }) - }) - - describe('when called with unequal array lengths', () => { - it('reverts with invalid array message', async () => { - const receivers = [ - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - ] - const amounts = [1, 2, 3] - await evmRevert( - operator - .connect(roles.defaultAccount) - .distributeFunds(receivers, amounts), - 'Invalid array length(s)', - ) - }) - }) - - describe('when called with not enough ETH', () => { - it('reverts with subtraction overflow message', async () => { - const amountToSend = toWei('2') - const ethSent = toWei('1') - await evmRevert( - operator - .connect(roles.defaultAccount) - .distributeFunds( - [await roles.oracleNode2.getAddress()], - [amountToSend], - { - value: ethSent, - }, - ), - 'SafeMath: subtraction overflow', - ) - }) - }) - - describe('when called with too much ETH', () => { - it('reverts with too much ETH message', async () => { - const amountToSend = toWei('2') - const ethSent = toWei('3') - await evmRevert( - operator - .connect(roles.defaultAccount) - .distributeFunds( - [await roles.oracleNode2.getAddress()], - [amountToSend], - { - value: ethSent, - }, - ), - 'Too much ETH sent', - ) - }) - }) - - describe('when called with correct values', () => { - it('updates the balances', async () => { - const node2BalanceBefore = await roles.oracleNode2.getBalance() - const node3BalanceBefore = await roles.oracleNode3.getBalance() - const receivers = [ - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - ] - const sendNode2 = toWei('2') - const sendNode3 = toWei('3') - const totalAmount = toWei('5') - const amounts = [sendNode2, sendNode3] - - await operator - .connect(roles.defaultAccount) - .distributeFunds(receivers, amounts, { value: totalAmount }) - - const node2BalanceAfter = await roles.oracleNode2.getBalance() - const node3BalanceAfter = await roles.oracleNode3.getBalance() - - assert.equal( - node2BalanceAfter.sub(node2BalanceBefore).toString(), - sendNode2.toString(), - ) - - assert.equal( - node3BalanceAfter.sub(node3BalanceBefore).toString(), - sendNode3.toString(), - ) - }) - }) - }) - - describe('#setAuthorizedSenders', () => { - let newSenders: string[] - let receipt: ContractReceipt - describe('when called by the owner', () => { - describe('setting 3 authorized senders', () => { - beforeEach(async () => { - newSenders = [ - await roles.oracleNode1.getAddress(), - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - ] - const tx = await operator - .connect(roles.defaultAccount) - .setAuthorizedSenders(newSenders) - receipt = await tx.wait() - }) - - it('adds the authorized nodes', async () => { - const authorizedSenders = await operator.getAuthorizedSenders() - assert.equal(newSenders.length, authorizedSenders.length) - for (let i = 0; i < authorizedSenders.length; i++) { - assert.equal(authorizedSenders[i], newSenders[i]) - } - }) - - it('emits an event on the Operator', async () => { - assert.equal(receipt.events?.length, 1) - - const encodedSenders1 = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'address'], - [newSenders, await roles.defaultAccount.getAddress()], - ) - - const responseEvent1 = receipt.events?.[0] - assert.equal(responseEvent1?.event, 'AuthorizedSendersChanged') - assert.equal(responseEvent1?.data, encodedSenders1) - }) - - it('replaces the authorized nodes', async () => { - const originalAuthorization = await operator - .connect(roles.defaultAccount) - .isAuthorizedSender(await roles.oracleNode.getAddress()) - assert.isFalse(originalAuthorization) - }) - - after(async () => { - await operator - .connect(roles.defaultAccount) - .setAuthorizedSenders([await roles.oracleNode.getAddress()]) - }) - }) - - describe('setting 0 authorized senders', () => { - beforeEach(async () => { - newSenders = [] - }) - - it('reverts with a minimum senders message', async () => { - await evmRevert( - operator - .connect(roles.defaultAccount) - .setAuthorizedSenders(newSenders), - 'Must have at least 1 sender', - ) - }) - }) - }) - - describe('when called by an authorized sender', () => { - beforeEach(async () => { - newSenders = [await roles.oracleNode1.getAddress()] - await operator - .connect(roles.defaultAccount) - .setAuthorizedSenders(newSenders) - }) - - it('succeeds', async () => { - await operator - .connect(roles.defaultAccount) - .setAuthorizedSenders([await roles.stranger.getAddress()]) - }) - }) - - describe('when called by a non-owner', () => { - it('cannot add an authorized node', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .setAuthorizedSenders([await roles.stranger.getAddress()]), - 'Cannot set authorized senders', - ) - }) - }) - }) - - describe('#setAuthorizedSendersOn', () => { - let newSenders: string[] - - beforeEach(async () => { - await operator - .connect(roles.defaultAccount) - .setAuthorizedSenders([await roles.oracleNode1.getAddress()]) - newSenders = [ - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - ] - - forwarder1 = await forwarderFactory - .connect(owner) - .deploy(link.address, operator.address, zeroAddress, '0x') - forwarder2 = await forwarderFactory - .connect(owner) - .deploy(link.address, operator.address, zeroAddress, '0x') - }) - - describe('when called by a non-authorized sender', () => { - it('reverts', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .setAuthorizedSendersOn(newSenders, [forwarder1.address]), - 'Cannot set authorized senders', - ) - }) - }) - - describe('when called by an owner', () => { - it('does not revert', async () => { - await operator - .connect(roles.defaultAccount) - .setAuthorizedSendersOn( - [forwarder1.address, forwarder2.address], - newSenders, - ) - }) - }) - - describe('when called by an authorized sender', () => { - it('does not revert', async () => { - await operator - .connect(roles.oracleNode1) - .setAuthorizedSendersOn( - [forwarder1.address, forwarder2.address], - newSenders, - ) - }) - - it('does revert with 0 senders', async () => { - await operator - .connect(roles.oracleNode1) - .setAuthorizedSendersOn( - [forwarder1.address, forwarder2.address], - newSenders, - ) - }) - - it('emits a log announcing the change and who made it', async () => { - const targets = [forwarder1.address, forwarder2.address] - const tx = await operator - .connect(roles.oracleNode1) - .setAuthorizedSendersOn(targets, newSenders) - - const receipt = await tx.wait() - const encodedArgs = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'address[]', 'address'], - [targets, newSenders, await roles.oracleNode1.getAddress()], - ) - - const event1 = receipt.events?.[0] - assert.equal(event1?.event, 'TargetsUpdatedAuthorizedSenders') - assert.equal(event1?.address, operator.address) - assert.equal(event1?.data, encodedArgs) - }) - - it('updates the sender list on each of the targets', async () => { - const tx = await operator - .connect(roles.oracleNode1) - .setAuthorizedSendersOn( - [forwarder1.address, forwarder2.address], - newSenders, - ) - - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 3, receipt.toString()) - const encodedSenders = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'address'], - [newSenders, operator.address], - ) - - const event1 = receipt.events?.[1] - assert.equal(event1?.event, 'AuthorizedSendersChanged') - assert.equal(event1?.address, forwarder1.address) - assert.equal(event1?.data, encodedSenders) - - const event2 = receipt.events?.[2] - assert.equal(event2?.event, 'AuthorizedSendersChanged') - assert.equal(event2?.address, forwarder2.address) - assert.equal(event2?.data, encodedSenders) - }) - }) - }) - - describe('#acceptAuthorizedReceivers', () => { - let newSenders: string[] - - describe('being called by the owner', () => { - let operator2: Contract - let receipt: ContractReceipt - - beforeEach(async () => { - operator2 = await operatorFactory - .connect(roles.defaultAccount) - .deploy(link.address, await roles.defaultAccount.getAddress()) - forwarder1 = await forwarderFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, zeroAddress, '0x') - forwarder2 = await forwarderFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, zeroAddress, '0x') - await operator - .connect(roles.defaultAccount) - .transferOwnableContracts( - [forwarder1.address, forwarder2.address], - operator2.address, - ) - newSenders = [ - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - ] - - const tx = await operator2 - .connect(roles.defaultAccount) - .acceptAuthorizedReceivers( - [forwarder1.address, forwarder2.address], - newSenders, - ) - receipt = await tx.wait() - }) - - it('sets the new owner on the forwarder', async () => { - assert.equal(await forwarder1.owner(), operator2.address) - }) - - it('emits ownership transferred events', async () => { - assert.equal(receipt?.events?.[0]?.event, 'OwnableContractAccepted') - assert.equal(receipt?.events?.[0]?.args?.[0], forwarder1.address) - - assert.equal(receipt?.events?.[1]?.event, 'OwnershipTransferred') - assert.equal(receipt?.events?.[1]?.address, forwarder1.address) - assert.equal(receipt?.events?.[1]?.args?.[0], operator.address) - assert.equal(receipt?.events?.[1]?.args?.[1], operator2.address) - - assert.equal(receipt?.events?.[2]?.event, 'OwnableContractAccepted') - assert.equal(receipt?.events?.[2]?.args?.[0], forwarder2.address) - - assert.equal(receipt?.events?.[3]?.event, 'OwnershipTransferred') - assert.equal(receipt?.events?.[3]?.address, forwarder2.address) - assert.equal(receipt?.events?.[3]?.args?.[0], operator.address) - assert.equal(receipt?.events?.[3]?.args?.[1], operator2.address) - - assert.equal( - receipt?.events?.[4]?.event, - 'TargetsUpdatedAuthorizedSenders', - ) - - const encodedSenders = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'address'], - [newSenders, operator2.address], - ) - assert.equal(receipt?.events?.[5]?.event, 'AuthorizedSendersChanged') - assert.equal(receipt?.events?.[5]?.address, forwarder1.address) - assert.equal(receipt?.events?.[5]?.data, encodedSenders) - - assert.equal(receipt?.events?.[6]?.event, 'AuthorizedSendersChanged') - assert.equal(receipt?.events?.[6]?.address, forwarder2.address) - assert.equal(receipt?.events?.[6]?.data, encodedSenders) - }) - }) - - describe('being called by a non owner', () => { - it('reverts with message', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .acceptAuthorizedReceivers( - [forwarder1.address, forwarder2.address], - newSenders, - ), - 'Cannot set authorized senders', - ) - }) - }) - }) - - describe('#onTokenTransfer', () => { - describe('when called from any address but the LINK token', () => { - it('triggers the intended method', async () => { - const callData = encodeOracleRequest( - specId, - to, - fHash, - 0, - constants.HashZero, - ) - - await evmRevert( - operator.onTokenTransfer( - await roles.defaultAccount.getAddress(), - 0, - callData, - ), - ) - }) - }) - - describe('when called from the LINK token', () => { - it('triggers the intended method', async () => { - const callData = encodeOracleRequest( - specId, - to, - fHash, - 0, - constants.HashZero, - ) - - const tx = await link.transferAndCall(operator.address, 0, callData, { - value: 0, - }) - const receipt = await tx.wait() - - assert.equal(3, receipt.logs?.length) - }) - - describe('with no data', () => { - it('reverts', async () => { - await evmRevert( - link.transferAndCall(operator.address, 0, '0x', { - value: 0, - }), - ) - }) - }) - }) - - describe('malicious requester', () => { - let mock: Contract - let requester: Contract - const paymentAmount = toWei('1') - - beforeEach(async () => { - mock = await maliciousRequesterFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(mock.address, paymentAmount) - }) - - it('cannot withdraw from oracle', async () => { - const operatorOriginalBalance = await link.balanceOf(operator.address) - const mockOriginalBalance = await link.balanceOf(mock.address) - - await evmRevert(mock.maliciousWithdraw()) - - const operatorNewBalance = await link.balanceOf(operator.address) - const mockNewBalance = await link.balanceOf(mock.address) - - bigNumEquals(operatorOriginalBalance, operatorNewBalance) - bigNumEquals(mockNewBalance, mockOriginalBalance) - }) - - describe('if the requester tries to create a requestId for another contract', () => { - it('the requesters ID will not match with the oracle contract', async () => { - const tx = await mock.maliciousTargetConsumer(to) - const receipt = await tx.wait() - - const mockRequestId = receipt.logs?.[0].data - const requestId = (receipt.events?.[0].args as any).requestId - assert.notEqual(mockRequestId, requestId) - }) - - it('the target requester can still create valid requests', async () => { - requester = await basicConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - await link.transfer(requester.address, paymentAmount) - await mock.maliciousTargetConsumer(requester.address) - await requester.requestEthereumPrice('USD', paymentAmount) - }) - }) - }) - - it('does not allow recursive calls of onTokenTransfer', async () => { - const requestPayload = encodeOracleRequest( - specId, - to, - fHash, - 0, - constants.HashZero, - ) - - const ottSelector = - operatorFactory.interface.getSighash('onTokenTransfer') - const header = - '000000000000000000000000c5fdf4076b8f3a5357c5e395ab970b5b54098fef' + // to - '0000000000000000000000000000000000000000000000000000000000000539' + // amount - '0000000000000000000000000000000000000000000000000000000000000060' + // offset - '0000000000000000000000000000000000000000000000000000000000000136' // length - - const maliciousPayload = ottSelector + header + requestPayload.slice(2) - - await evmRevert( - link.transferAndCall(operator.address, 0, maliciousPayload, { - value: 0, - }), - ) - }) - }) - - describe('#oracleRequest', () => { - describe('when called through the LINK token', () => { - const paid = 100 - let log: providers.Log | undefined - let receipt: providers.TransactionReceipt - - beforeEach(async () => { - const args = encodeOracleRequest( - specId, - to, - fHash, - 1, - constants.HashZero, - ) - const tx = await link.transferAndCall(operator.address, paid, args) - receipt = await tx.wait() - assert.equal(3, receipt?.logs?.length) - - log = receipt.logs && receipt.logs[2] - }) - - it('logs an event', async () => { - assert.equal(operator.address, log?.address) - - assert.equal(log?.topics?.[1], specId) - - const req = decodeRunRequest(receipt?.logs?.[2]) - assert.equal(await roles.defaultAccount.getAddress(), req.requester) - bigNumEquals(paid, req.payment) - }) - - it('uses the expected event signature', async () => { - // If updating this test, be sure to update models.RunLogTopic. - const eventSignature = - '0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65' - assert.equal(eventSignature, log?.topics?.[0]) - }) - - it('does not allow the same requestId to be used twice', async () => { - const args2 = encodeOracleRequest( - specId, - to, - fHash, - 1, - constants.HashZero, - ) - await evmRevert(link.transferAndCall(operator.address, paid, args2)) - }) - - describe('when called with a payload less than 2 EVM words + function selector', () => { - it('throws an error', async () => { - const funcSelector = - operatorFactory.interface.getSighash('oracleRequest') - const maliciousData = - funcSelector + - '0000000000000000000000000000000000000000000000000000000000000000000' - await evmRevert( - link.transferAndCall(operator.address, paid, maliciousData), - ) - }) - }) - - describe('when called with a payload between 3 and 9 EVM words', () => { - it('throws an error', async () => { - const funcSelector = - operatorFactory.interface.getSighash('oracleRequest') - const maliciousData = - funcSelector + - '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' - await evmRevert( - link.transferAndCall(operator.address, paid, maliciousData), - ) - }) - }) - }) - - describe('when dataVersion is higher than 255', () => { - it('throws an error', async () => { - const paid = 100 - const args = encodeOracleRequest( - specId, - to, - fHash, - 1, - constants.HashZero, - 256, - ) - await evmRevert(link.transferAndCall(operator.address, paid, args)) - }) - }) - - describe('when not called through the LINK token', () => { - it('reverts', async () => { - await evmRevert( - operator - .connect(roles.oracleNode) - .oracleRequest( - '0x0000000000000000000000000000000000000000', - 0, - specId, - to, - fHash, - 1, - 1, - '0x', - ), - ) - }) - }) - }) - - describe('#operatorRequest', () => { - describe('when called through the LINK token', () => { - const paid = 100 - let log: providers.Log | undefined - let receipt: providers.TransactionReceipt - - beforeEach(async () => { - const args = encodeRequestOracleData( - specId, - fHash, - 1, - constants.HashZero, - ) - const tx = await link.transferAndCall(operator.address, paid, args) - receipt = await tx.wait() - assert.equal(3, receipt?.logs?.length) - - log = receipt.logs && receipt.logs[2] - }) - - it('logs an event', async () => { - assert.equal(operator.address, log?.address) - - assert.equal(log?.topics?.[1], specId) - - const req = decodeRunRequest(receipt?.logs?.[2]) - assert.equal(await roles.defaultAccount.getAddress(), req.requester) - bigNumEquals(paid, req.payment) - }) - - it('uses the expected event signature', async () => { - // If updating this test, be sure to update models.RunLogTopic. - const eventSignature = - '0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65' - assert.equal(eventSignature, log?.topics?.[0]) - }) - - it('does not allow the same requestId to be used twice', async () => { - const args2 = encodeRequestOracleData( - specId, - fHash, - 1, - constants.HashZero, - ) - await evmRevert(link.transferAndCall(operator.address, paid, args2)) - }) - - describe('when called with a payload less than 2 EVM words + function selector', () => { - it('throws an error', async () => { - const funcSelector = - operatorFactory.interface.getSighash('oracleRequest') - const maliciousData = - funcSelector + - '0000000000000000000000000000000000000000000000000000000000000000000' - await evmRevert( - link.transferAndCall(operator.address, paid, maliciousData), - ) - }) - }) - - describe('when called with a payload between 3 and 9 EVM words', () => { - it('throws an error', async () => { - const funcSelector = - operatorFactory.interface.getSighash('oracleRequest') - const maliciousData = - funcSelector + - '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' - await evmRevert( - link.transferAndCall(operator.address, paid, maliciousData), - ) - }) - }) - }) - - describe('when dataVersion is higher than 255', () => { - it('throws an error', async () => { - const paid = 100 - const args = encodeRequestOracleData( - specId, - fHash, - 1, - constants.HashZero, - 256, - ) - await evmRevert(link.transferAndCall(operator.address, paid, args)) - }) - }) - - describe('when not called through the LINK token', () => { - it('reverts', async () => { - await evmRevert( - operator - .connect(roles.oracleNode) - .oracleRequest( - '0x0000000000000000000000000000000000000000', - 0, - specId, - to, - fHash, - 1, - 1, - '0x', - ), - ) - }) - }) - }) - - describe('#fulfillOracleRequest', () => { - const response = 'Hi Mom!' - let maliciousRequester: Contract - let basicConsumer: Contract - let maliciousConsumer: Contract - let gasGuzzlingConsumer: Contract - let request: ReturnType - - describe('gas guzzling consumer [ @skip-coverage ]', () => { - beforeEach(async () => { - gasGuzzlingConsumer = await gasGuzzlingConsumerFactory - .connect(roles.consumer) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = - await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('emits an OracleResponse event', async () => { - const fulfillParams = convertFufillParams(request, response) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 1) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - }) - - describe('cooperative consumer', () => { - beforeEach(async () => { - basicConsumer = await basicConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(basicConsumer.address, paymentAmount) - const currency = 'USD' - const tx = await basicConsumer.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - describe('when called by an unauthorized node', () => { - beforeEach(async () => { - assert.equal( - false, - await operator.isAuthorizedSender( - await roles.stranger.getAddress(), - ), - ) - }) - - it('raises an error', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .fulfillOracleRequest(...convertFufillParams(request, response)), - ) - }) - }) - - describe('when fulfilled with the wrong function', () => { - let v7Consumer - beforeEach(async () => { - v7Consumer = await v7ConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(v7Consumer.address, paymentAmount) - const currency = 'USD' - const tx = await v7Consumer.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('raises an error', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .fulfillOracleRequest(...convertFufillParams(request, response)), - ) - }) - }) - - describe('when called by an authorized node', () => { - it('raises an error if the request ID does not exist', async () => { - request.requestId = ethers.utils.formatBytes32String('DOESNOTEXIST') - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)), - ) - }) - - it('sets the value on the requested contract', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - const currentValue = await basicConsumer.currentPrice() - assert.equal(response, ethers.utils.parseBytes32String(currentValue)) - }) - - it('emits an OracleResponse event', async () => { - const fulfillParams = convertFufillParams(request, response) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 3) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - - it('does not allow a request to be fulfilled twice', async () => { - const response2 = response + ' && Hello World!!' - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response2)), - ) - - const currentValue = await basicConsumer.currentPrice() - assert.equal(response, ethers.utils.parseBytes32String(currentValue)) - }) - }) - - describe('when the oracle does not provide enough gas', () => { - // if updating this defaultGasLimit, be sure it matches with the - // defaultGasLimit specified in store/tx_manager.go - const defaultGasLimit = 500000 - - beforeEach(async () => { - bigNumEquals(0, await operator.withdrawable()) - }) - - it('does not allow the oracle to withdraw the payment', async () => { - await evmRevert( - operator.connect(roles.oracleNode).fulfillOracleRequest( - ...convertFufillParams(request, response, { - gasLimit: 70000, - }), - ), - ) - - bigNumEquals(0, await operator.withdrawable()) - }) - - it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { - await operator.connect(roles.oracleNode).fulfillOracleRequest( - ...convertFufillParams(request, response, { - gasLimit: defaultGasLimit, - }), - ) - - bigNumEquals(request.payment, await operator.withdrawable()) - }) - }) - }) - - describe('with a malicious requester', () => { - beforeEach(async () => { - const paymentAmount = toWei('1') - maliciousRequester = await maliciousRequesterFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousRequester.address, paymentAmount) - }) - - it('cannot cancel before the expiration', async () => { - await evmRevert( - maliciousRequester.maliciousRequestCancel( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ), - ) - }) - - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) - - describe('requester lies about amount of LINK sent', () => { - it('the oracle uses the amount of LINK actually paid', async () => { - const tx = await maliciousRequester.maliciousPrice(specId) - const receipt = await tx.wait() - const req = decodeRunRequest(receipt.logs?.[3]) - - assert(toWei('1').eq(req.payment)) - }) - }) - }) - - describe('with a malicious consumer', () => { - const paymentAmount = toWei('1') - - beforeEach(async () => { - maliciousConsumer = await maliciousConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousConsumer.address, paymentAmount) - }) - - describe('fails during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response2 = 'hack the planet 102' - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response2)), - ) - }) - }) - - describe('calls selfdestruct', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - await maliciousConsumer.remove() - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - }) - - describe('request is canceled during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('cancelRequestOnFulfill(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - const mockBalance = await link.balanceOf(maliciousConsumer.address) - bigNumEquals(mockBalance, 0) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response2 = 'hack the planet 102' - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response2)), - ) - }) - }) - - describe('tries to steal funds from node', () => { - it('is not successful with call', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with send', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with transfer', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, response)) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - }) - - describe('when calling an owned contract', () => { - beforeEach(async () => { - forwarder1 = await forwarderFactory - .connect(roles.defaultAccount) - .deploy(link.address, link.address, operator.address, '0x') - }) - - it('does not allow the contract to callback to owned contracts', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('whatever(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - let request = decodeRunRequest(receipt.logs?.[3]) - let responseParams = convertFufillParams(request, response) - // set the params to be the owned address - responseParams[2] = forwarder1.address - - //accept ownership - await operator - .connect(roles.defaultAccount) - .acceptOwnableContracts([forwarder1.address]) - - // do the thing - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...responseParams), - 'Cannot call owned contract', - ) - - await operator - .connect(roles.defaultAccount) - .transferOwnableContracts([forwarder1.address], link.address) - //reverts for a different reason after transferring ownership - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...responseParams), - 'Params do not match request ID', - ) - }) - }) - }) - }) - - describe('#fulfillOracleRequest2', () => { - describe('single word fulfils', () => { - const response = 'Hi mom!' - const responseTypes = ['bytes32'] - const responseValues = [toBytes32String(response)] - let maliciousRequester: Contract - let basicConsumer: Contract - let maliciousConsumer: Contract - let gasGuzzlingConsumer: Contract - let request: ReturnType - let request2: ReturnType - - describe('gas guzzling consumer [ @skip-coverage ]', () => { - beforeEach(async () => { - gasGuzzlingConsumer = await gasGuzzlingConsumerFactory - .connect(roles.consumer) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = - await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('emits an OracleResponse2 event', async () => { - const fulfillParams = convertFulfill2Params( - request, - responseTypes, - responseValues, - ) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 1) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - }) - - describe('cooperative consumer', () => { - beforeEach(async () => { - basicConsumer = await basicConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(basicConsumer.address, paymentAmount) - const currency = 'USD' - const tx = await basicConsumer.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - describe('when called by an unauthorized node', () => { - beforeEach(async () => { - assert.equal( - false, - await operator.isAuthorizedSender( - await roles.stranger.getAddress(), - ), - ) - }) - - it('raises an error', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ), - ) - }) - }) - - describe('when called by an authorized node', () => { - it('raises an error if the request ID does not exist', async () => { - request.requestId = ethers.utils.formatBytes32String('DOESNOTEXIST') - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ), - ) - }) - - it('sets the value on the requested contract', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const currentValue = await basicConsumer.currentPrice() - assert.equal( - response, - ethers.utils.parseBytes32String(currentValue), - ) - }) - - it('emits an OracleResponse2 event', async () => { - const fulfillParams = convertFulfill2Params( - request, - responseTypes, - responseValues, - ) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 3) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - - it('does not allow a request to be fulfilled twice', async () => { - const response2 = response + ' && Hello World!!' - const response2Values = [toBytes32String(response2)] - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - response2Values, - ), - ), - ) - - const currentValue = await basicConsumer.currentPrice() - assert.equal( - response, - ethers.utils.parseBytes32String(currentValue), - ) - }) - }) - - describe('when the oracle does not provide enough gas', () => { - // if updating this defaultGasLimit, be sure it matches with the - // defaultGasLimit specified in store/tx_manager.go - const defaultGasLimit = 500000 - - beforeEach(async () => { - bigNumEquals(0, await operator.withdrawable()) - }) - - it('does not allow the oracle to withdraw the payment', async () => { - await evmRevert( - operator.connect(roles.oracleNode).fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - { - gasLimit: 70000, - }, - ), - ), - ) - - bigNumEquals(0, await operator.withdrawable()) - }) - - it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { - await operator.connect(roles.oracleNode).fulfillOracleRequest2( - ...convertFulfill2Params(request, responseTypes, responseValues, { - gasLimit: defaultGasLimit, - }), - ) - - bigNumEquals(request.payment, await operator.withdrawable()) - }) - }) - }) - - describe('with a malicious oracle', () => { - beforeEach(async () => { - // Setup Request 1 - basicConsumer = await basicConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(basicConsumer.address, paymentAmount) - const currency = 'USD' - const tx = await basicConsumer.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - // Setup Request 2 - await link.transfer(basicConsumer.address, paymentAmount) - const tx2 = await basicConsumer.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt2 = await tx2.wait() - request2 = decodeRunRequest(receipt2.logs?.[3]) - }) - - it('cannot spoof requestId in response data by moving calldata offset', async () => { - // Malicious Oracle Fulfill 2 - const functionSelector = '0x6ae0bc76' // fulfillOracleRequest2 - const dataOffset = - '0000000000000000000000000000000000000000000000000000000000000100' // Moved to 0x0124 - const fillerBytes = - '0000000000000000000000000000000000000000000000000000000000000000' - const expectedCalldataStart = request.requestId.slice(2) // 0xe4, this is checked against requestId in validateMultiWordResponseId - const dataSize = - '0000000000000000000000000000000000000000000000000000000000000040' // Two 32 byte blocks - const maliciousCalldataId = request2.requestId.slice(2) // 0x0124, set to a different requestId - const calldataData = - '1122334455667788991122334455667788991122334455667788991122334455' // some garbage value as response value - - const data = - functionSelector + - /** Input Params - slice off 0x prefix and pad with 0's */ - request.requestId.slice(2) + - request.payment.slice(2).padStart(64, '0') + - request.callbackAddr.slice(2).padStart(64, '0') + - request.callbackFunc.slice(2).padEnd(64, '0') + - request.expiration.slice(2).padStart(64, '0') + - // calldata "data" - dataOffset + - fillerBytes + - expectedCalldataStart + - dataSize + - maliciousCalldataId + - calldataData - - await evmRevert( - operator.connect(roles.oracleNode).signer.sendTransaction({ - to: operator.address, - data, - }), - ) - }) - }) - - describe('with a malicious requester', () => { - beforeEach(async () => { - const paymentAmount = toWei('1') - maliciousRequester = await maliciousRequesterFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousRequester.address, paymentAmount) - }) - - it('cannot cancel before the expiration', async () => { - await evmRevert( - maliciousRequester.maliciousRequestCancel( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ), - ) - }) - - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) - - describe('requester lies about amount of LINK sent', () => { - it('the oracle uses the amount of LINK actually paid', async () => { - const tx = await maliciousRequester.maliciousPrice(specId) - const receipt = await tx.wait() - const req = decodeRunRequest(receipt.logs?.[3]) - - assert(toWei('1').eq(req.payment)) - }) - }) - }) - - describe('with a malicious consumer', () => { - const paymentAmount = toWei('1') - - beforeEach(async () => { - maliciousConsumer = await maliciousConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousConsumer.address, paymentAmount) - }) - - describe('fails during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response2 = 'hack the planet 102' - const response2Values = [toBytes32String(response2)] - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - response2Values, - ), - ), - ) - }) - }) - - describe('calls selfdestruct', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - await maliciousConsumer.remove() - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - }) - - describe('request is canceled during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes( - 'cancelRequestOnFulfill(bytes32,bytes32)', - ), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const mockBalance = await link.balanceOf(maliciousConsumer.address) - bigNumEquals(mockBalance, 0) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response2 = 'hack the planet 102' - const response2Values = [toBytes32String(response2)] - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - response2Values, - ), - ), - ) - }) - }) - - describe('tries to steal funds from node', () => { - it('is not successful with call', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with send', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with transfer', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - }) - - describe('when calling an owned contract', () => { - beforeEach(async () => { - forwarder1 = await forwarderFactory - .connect(roles.defaultAccount) - .deploy(link.address, link.address, operator.address, '0x') - }) - - it('does not allow the contract to callback to owned contracts', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('whatever(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - let request = decodeRunRequest(receipt.logs?.[3]) - let responseParams = convertFufillParams(request, response) - // set the params to be the owned address - responseParams[2] = forwarder1.address - - //accept ownership - await operator - .connect(roles.defaultAccount) - .acceptOwnableContracts([forwarder1.address]) - - // do the thing - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...responseParams), - 'Cannot call owned contract', - ) - - await operator - .connect(roles.defaultAccount) - .transferOwnableContracts([forwarder1.address], link.address) - //reverts for a different reason after transferring ownership - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...responseParams), - 'Params do not match request ID', - ) - }) - }) - }) - }) - - describe('multi word fulfils', () => { - describe('one bytes parameter', () => { - const response = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.\ - Fusce euismod malesuada ligula, eget semper metus ultrices sit amet.' - const responseTypes = ['bytes'] - const responseValues = [stringToBytes(response)] - let maliciousRequester: Contract - let multiConsumer: Contract - let maliciousConsumer: Contract - let gasGuzzlingConsumer: Contract - let request: ReturnType - - describe('gas guzzling consumer [ @skip-coverage ]', () => { - beforeEach(async () => { - gasGuzzlingConsumer = await gasGuzzlingConsumerFactory - .connect(roles.consumer) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = - await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('emits an OracleResponse2 event', async () => { - const fulfillParams = convertFulfill2Params( - request, - responseTypes, - responseValues, - ) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 1) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - }) - - describe('cooperative consumer', () => { - beforeEach(async () => { - multiConsumer = await multiWordConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(multiConsumer.address, paymentAmount) - const currency = 'USD' - const tx = await multiConsumer.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it("matches the consumer's request ID", async () => { - const nonce = await multiConsumer.publicGetNextRequestCount() - const tx = await multiConsumer.requestEthereumPrice('USD', 0) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - const packed = ethers.utils.solidityPack( - ['address', 'uint256'], - [multiConsumer.address, nonce], - ) - const expected = ethers.utils.keccak256(packed) - assert.equal(expected, request.requestId) - }) - - describe('when called by an unauthorized node', () => { - beforeEach(async () => { - assert.equal( - false, - await operator.isAuthorizedSender( - await roles.stranger.getAddress(), - ), - ) - }) - - it('raises an error', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ), - ) - }) - }) - - describe('when called by an authorized node', () => { - it('raises an error if the request ID does not exist', async () => { - request.requestId = - ethers.utils.formatBytes32String('DOESNOTEXIST') - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ), - ) - }) - - it('sets the value on the requested contract', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const currentValue = await multiConsumer.currentPrice() - assert.equal(response, ethers.utils.toUtf8String(currentValue)) - }) - - it('emits an OracleResponse2 event', async () => { - const fulfillParams = convertFulfill2Params( - request, - responseTypes, - responseValues, - ) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 3) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - - it('does not allow a request to be fulfilled twice', async () => { - const response2 = response + ' && Hello World!!' - const response2Values = [stringToBytes(response2)] - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - response2Values, - ), - ), - ) - - const currentValue = await multiConsumer.currentPrice() - assert.equal(response, ethers.utils.toUtf8String(currentValue)) - }) - }) - - describe('when the oracle does not provide enough gas', () => { - // if updating this defaultGasLimit, be sure it matches with the - // defaultGasLimit specified in store/tx_manager.go - const defaultGasLimit = 500000 - - beforeEach(async () => { - bigNumEquals(0, await operator.withdrawable()) - }) - - it('does not allow the oracle to withdraw the payment', async () => { - await evmRevert( - operator.connect(roles.oracleNode).fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - { - gasLimit: 70000, - }, - ), - ), - ) - - bigNumEquals(0, await operator.withdrawable()) - }) - - it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { - await operator.connect(roles.oracleNode).fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - { - gasLimit: defaultGasLimit, - }, - ), - ) - - bigNumEquals(request.payment, await operator.withdrawable()) - }) - }) - }) - - describe('with a malicious requester', () => { - beforeEach(async () => { - const paymentAmount = toWei('1') - maliciousRequester = await maliciousRequesterFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousRequester.address, paymentAmount) - }) - - it('cannot cancel before the expiration', async () => { - await evmRevert( - maliciousRequester.maliciousRequestCancel( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ), - ) - }) - - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) - - describe('requester lies about amount of LINK sent', () => { - it('the oracle uses the amount of LINK actually paid', async () => { - const tx = await maliciousRequester.maliciousPrice(specId) - const receipt = await tx.wait() - const req = decodeRunRequest(receipt.logs?.[3]) - - assert(toWei('1').eq(req.payment)) - }) - }) - }) - - describe('with a malicious consumer', () => { - const paymentAmount = toWei('1') - - beforeEach(async () => { - maliciousConsumer = await maliciousMultiWordConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousConsumer.address, paymentAmount) - }) - - describe('fails during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response2 = 'hack the planet 102' - const response2Values = [stringToBytes(response2)] - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - response2Values, - ), - ), - ) - }) - }) - - describe('calls selfdestruct', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - await maliciousConsumer.remove() - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - }) - - describe('request is canceled during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes( - 'cancelRequestOnFulfill(bytes32,bytes32)', - ), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const mockBalance = await link.balanceOf( - maliciousConsumer.address, - ) - bigNumEquals(mockBalance, 0) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response2 = 'hack the planet 102' - const response2Values = [stringToBytes(response2)] - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - response2Values, - ), - ), - ) - }) - }) - - describe('tries to steal funds from node', () => { - it('is not successful with call', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with send', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with transfer', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - }) - }) - }) - - describe('multiple bytes32 parameters', () => { - const response1 = '100' - const response2 = '7777777' - const response3 = 'forty two' - const responseTypes = ['bytes32', 'bytes32', 'bytes32'] - const responseValues = [ - toBytes32String(response1), - toBytes32String(response2), - toBytes32String(response3), - ] - let maliciousRequester: Contract - let multiConsumer: Contract - let maliciousConsumer: Contract - let gasGuzzlingConsumer: Contract - let request: ReturnType - - describe('gas guzzling consumer [ @skip-coverage ]', () => { - beforeEach(async () => { - gasGuzzlingConsumer = await gasGuzzlingConsumerFactory - .connect(roles.consumer) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = - await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('emits an OracleResponse2 event', async () => { - const fulfillParams = convertFulfill2Params( - request, - responseTypes, - responseValues, - ) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 1) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - }) - - describe('cooperative consumer', () => { - beforeEach(async () => { - multiConsumer = await multiWordConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(multiConsumer.address, paymentAmount) - const currency = 'USD' - const tx = await multiConsumer.requestMultipleParameters( - currency, - paymentAmount, - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - describe('when called by an unauthorized node', () => { - beforeEach(async () => { - assert.equal( - false, - await operator.isAuthorizedSender( - await roles.stranger.getAddress(), - ), - ) - }) - - it('raises an error', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ), - ) - }) - }) - - describe('when called by an authorized node', () => { - it('raises an error if the request ID does not exist', async () => { - request.requestId = - ethers.utils.formatBytes32String('DOESNOTEXIST') - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ), - ) - }) - - it('sets the value on the requested contract', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const firstValue = await multiConsumer.usd() - const secondValue = await multiConsumer.eur() - const thirdValue = await multiConsumer.jpy() - assert.equal( - response1, - ethers.utils.parseBytes32String(firstValue), - ) - assert.equal( - response2, - ethers.utils.parseBytes32String(secondValue), - ) - assert.equal( - response3, - ethers.utils.parseBytes32String(thirdValue), - ) - }) - - it('emits an OracleResponse2 event', async () => { - const fulfillParams = convertFulfill2Params( - request, - responseTypes, - responseValues, - ) - const tx = await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...fulfillParams) - const receipt = await tx.wait() - assert.equal(receipt.events?.length, 3) - const responseEvent = receipt.events?.[0] - assert.equal(responseEvent?.event, 'OracleResponse') - assert.equal(responseEvent?.args?.[0], request.requestId) - }) - - it('does not allow a request to be fulfilled twice', async () => { - const response4 = response3 + ' && Hello World!!' - const repeatedResponseValues = [ - toBytes32String(response1), - toBytes32String(response2), - toBytes32String(response4), - ] - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - repeatedResponseValues, - ), - ), - ) - - const firstValue = await multiConsumer.usd() - const secondValue = await multiConsumer.eur() - const thirdValue = await multiConsumer.jpy() - assert.equal( - response1, - ethers.utils.parseBytes32String(firstValue), - ) - assert.equal( - response2, - ethers.utils.parseBytes32String(secondValue), - ) - assert.equal( - response3, - ethers.utils.parseBytes32String(thirdValue), - ) - }) - }) - - describe('when the oracle does not provide enough gas', () => { - // if updating this defaultGasLimit, be sure it matches with the - // defaultGasLimit specified in store/tx_manager.go - const defaultGasLimit = 500000 - - beforeEach(async () => { - bigNumEquals(0, await operator.withdrawable()) - }) - - it('does not allow the oracle to withdraw the payment', async () => { - await evmRevert( - operator.connect(roles.oracleNode).fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - { - gasLimit: 70000, - }, - ), - ), - ) - - bigNumEquals(0, await operator.withdrawable()) - }) - - it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { - await operator.connect(roles.oracleNode).fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - { - gasLimit: defaultGasLimit, - }, - ), - ) - - bigNumEquals(request.payment, await operator.withdrawable()) - }) - }) - }) - - describe('with a malicious requester', () => { - beforeEach(async () => { - const paymentAmount = toWei('1') - maliciousRequester = await maliciousRequesterFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousRequester.address, paymentAmount) - }) - - it('cannot cancel before the expiration', async () => { - await evmRevert( - maliciousRequester.maliciousRequestCancel( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ), - ) - }) - - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) - - describe('requester lies about amount of LINK sent', () => { - it('the oracle uses the amount of LINK actually paid', async () => { - const tx = await maliciousRequester.maliciousPrice(specId) - const receipt = await tx.wait() - const req = decodeRunRequest(receipt.logs?.[3]) - - assert(toWei('1').eq(req.payment)) - }) - }) - }) - - describe('with a malicious consumer', () => { - const paymentAmount = toWei('1') - - beforeEach(async () => { - maliciousConsumer = await maliciousMultiWordConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address) - await link.transfer(maliciousConsumer.address, paymentAmount) - }) - - describe('fails during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response4 = 'hack the planet 102' - const repeatedResponseValues = [ - toBytes32String(response1), - toBytes32String(response2), - toBytes32String(response4), - ] - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - repeatedResponseValues, - ), - ), - ) - }) - }) - - describe('calls selfdestruct', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - await maliciousConsumer.remove() - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - }) - - describe('request is canceled during fulfillment', () => { - beforeEach(async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes( - 'cancelRequestOnFulfill(bytes32,bytes32)', - ), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) - }) - - it('allows the oracle node to receive their payment', async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - const mockBalance = await link.balanceOf( - maliciousConsumer.address, - ) - bigNumEquals(mockBalance, 0) - - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(balance, 0) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), paymentAmount) - const newBalance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - bigNumEquals(paymentAmount, newBalance) - }) - - it("can't fulfill the data again", async () => { - const response4 = 'hack the planet 102' - const repeatedResponseValues = [ - toBytes32String(response1), - toBytes32String(response2), - toBytes32String(response4), - ] - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - repeatedResponseValues, - ), - ), - ) - }) - }) - - describe('tries to steal funds from node', () => { - it('is not successful with call', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with send', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - - it('is not successful with transfer', async () => { - const tx = await maliciousConsumer.requestData( - specId, - ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), - ) - const receipt = await tx.wait() - request = decodeRunRequest(receipt.logs?.[3]) - - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params( - request, - responseTypes, - responseValues, - ), - ) - bigNumEquals( - 0, - await ethers.provider.getBalance(maliciousConsumer.address), - ) - }) - }) - }) - }) - }) - - describe('when the response data is too short', () => { - const response = 'Hi mom!' - const responseTypes = ['bytes32'] - const responseValues = [toBytes32String(response)] - - it('reverts', async () => { - let basicConsumer = await basicConsumerFactory - .connect(roles.defaultAccount) - .deploy(link.address, operator.address, specId) - const paymentAmount = toWei('1') - await link.transfer(basicConsumer.address, paymentAmount) - const tx = await basicConsumer.requestEthereumPrice( - 'USD', - paymentAmount, - ) - const receipt = await tx.wait() - let request = decodeRunRequest(receipt.logs?.[3]) - - const fulfillParams = convertFulfill2Params( - request, - responseTypes, - responseValues, - ) - fulfillParams[5] = '0x' // overwrite the data to be of lenght 0 - await evmRevert( - operator - .connect(roles.oracleNode) - .fulfillOracleRequest2(...fulfillParams), - 'Response must be > 32 bytes', - ) - }) - }) - }) - - describe('#withdraw', () => { - describe('without reserving funds via oracleRequest', () => { - it('does nothing', async () => { - let balance = await link.balanceOf(await roles.oracleNode.getAddress()) - assert.equal(0, balance.toNumber()) - await evmRevert( - operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), toWei('1')), - ) - balance = await link.balanceOf(await roles.oracleNode.getAddress()) - assert.equal(0, balance.toNumber()) - }) - - describe('recovering funds that were mistakenly sent', () => { - const paid = 1 - beforeEach(async () => { - await link.transfer(operator.address, paid) - }) - - it('withdraws funds', async () => { - const operatorBalanceBefore = await link.balanceOf(operator.address) - const accountBalanceBefore = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.defaultAccount.getAddress(), paid) - - const operatorBalanceAfter = await link.balanceOf(operator.address) - const accountBalanceAfter = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - - const accountDifference = - accountBalanceAfter.sub(accountBalanceBefore) - const operatorDifference = - operatorBalanceBefore.sub(operatorBalanceAfter) - - bigNumEquals(operatorDifference, paid) - bigNumEquals(accountDifference, paid) - }) - }) - }) - - describe('reserving funds via oracleRequest', () => { - const payment = 15 - let request: ReturnType - - beforeEach(async () => { - const requester = await roles.defaultAccount.getAddress() - const args = encodeOracleRequest( - specId, - requester, - fHash, - 0, - constants.HashZero, - ) - const tx = await link.transferAndCall(operator.address, payment, args) - const receipt = await tx.wait() - assert.equal(3, receipt.logs?.length) - request = decodeRunRequest(receipt.logs?.[2]) - }) - - describe('but not freeing funds w fulfillOracleRequest', () => { - it('does not transfer funds', async () => { - await evmRevert( - operator - .connect(roles.defaultAccount) - .withdraw(await roles.oracleNode.getAddress(), payment), - ) - const balance = await link.balanceOf( - await roles.oracleNode.getAddress(), - ) - assert.equal(0, balance.toNumber()) - }) - - describe('recovering funds that were mistakenly sent', () => { - const paid = 1 - beforeEach(async () => { - await link.transfer(operator.address, paid) - }) - - it('withdraws funds', async () => { - const operatorBalanceBefore = await link.balanceOf(operator.address) - const accountBalanceBefore = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.defaultAccount.getAddress(), paid) - - const operatorBalanceAfter = await link.balanceOf(operator.address) - const accountBalanceAfter = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - - const accountDifference = - accountBalanceAfter.sub(accountBalanceBefore) - const operatorDifference = - operatorBalanceBefore.sub(operatorBalanceAfter) - - bigNumEquals(operatorDifference, paid) - bigNumEquals(accountDifference, paid) - }) - }) - }) - - describe('and freeing funds', () => { - beforeEach(async () => { - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest( - ...convertFufillParams(request, 'Hello World!'), - ) - }) - - it('does not allow input greater than the balance', async () => { - const originalOracleBalance = await link.balanceOf(operator.address) - const originalStrangerBalance = await link.balanceOf( - await roles.stranger.getAddress(), - ) - const withdrawalAmount = payment + 1 - - assert.isAbove(withdrawalAmount, originalOracleBalance.toNumber()) - await evmRevert( - operator - .connect(roles.defaultAccount) - .withdraw(await roles.stranger.getAddress(), withdrawalAmount), - ) - - const newOracleBalance = await link.balanceOf(operator.address) - const newStrangerBalance = await link.balanceOf( - await roles.stranger.getAddress(), - ) - - assert.equal( - originalOracleBalance.toNumber(), - newOracleBalance.toNumber(), - ) - assert.equal( - originalStrangerBalance.toNumber(), - newStrangerBalance.toNumber(), - ) - }) - - it('allows transfer of partial balance by owner to specified address', async () => { - const partialAmount = 6 - const difference = payment - partialAmount - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.stranger.getAddress(), partialAmount) - const strangerBalance = await link.balanceOf( - await roles.stranger.getAddress(), - ) - const oracleBalance = await link.balanceOf(operator.address) - assert.equal(partialAmount, strangerBalance.toNumber()) - assert.equal(difference, oracleBalance.toNumber()) - }) - - it('allows transfer of entire balance by owner to specified address', async () => { - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.stranger.getAddress(), payment) - const balance = await link.balanceOf( - await roles.stranger.getAddress(), - ) - assert.equal(payment, balance.toNumber()) - }) - - it('does not allow a transfer of funds by non-owner', async () => { - await evmRevert( - operator - .connect(roles.stranger) - .withdraw(await roles.stranger.getAddress(), payment), - ) - const balance = await link.balanceOf( - await roles.stranger.getAddress(), - ) - assert.isTrue(ethers.constants.Zero.eq(balance)) - }) - - describe('recovering funds that were mistakenly sent', () => { - const paid = 1 - beforeEach(async () => { - await link.transfer(operator.address, paid) - }) - - it('withdraws funds', async () => { - const operatorBalanceBefore = await link.balanceOf(operator.address) - const accountBalanceBefore = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - - await operator - .connect(roles.defaultAccount) - .withdraw(await roles.defaultAccount.getAddress(), paid) - - const operatorBalanceAfter = await link.balanceOf(operator.address) - const accountBalanceAfter = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - - const accountDifference = - accountBalanceAfter.sub(accountBalanceBefore) - const operatorDifference = - operatorBalanceBefore.sub(operatorBalanceAfter) - - bigNumEquals(operatorDifference, paid) - bigNumEquals(accountDifference, paid) - }) - }) - }) - }) - }) - - describe('#withdrawable', () => { - let request: ReturnType - const amount = toWei('1') - - beforeEach(async () => { - const requester = await roles.defaultAccount.getAddress() - const args = encodeOracleRequest( - specId, - requester, - fHash, - 0, - constants.HashZero, - ) - const tx = await link.transferAndCall(operator.address, amount, args) - const receipt = await tx.wait() - assert.equal(3, receipt.logs?.length) - request = decodeRunRequest(receipt.logs?.[2]) - await operator - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request, 'Hello World!')) - }) - - it('returns the correct value', async () => { - const withdrawAmount = await operator.withdrawable() - bigNumEquals(withdrawAmount, request.payment) - }) - - describe('funds that were mistakenly sent', () => { - const paid = 1 - beforeEach(async () => { - await link.transfer(operator.address, paid) - }) - - it('returns the correct value', async () => { - const withdrawAmount = await operator.withdrawable() - - const expectedAmount = amount.add(paid) - bigNumEquals(withdrawAmount, expectedAmount) - }) - }) - }) - - describe('#ownerTransferAndCall', () => { - let operator2: Contract - let args: string - let to: string - const startingBalance = 1000 - const payment = 20 - - beforeEach(async () => { - operator2 = await operatorFactory - .connect(roles.oracleNode2) - .deploy(link.address, await roles.oracleNode2.getAddress()) - to = operator2.address - args = encodeOracleRequest( - specId, - operator.address, - operatorFactory.interface.getSighash('fulfillOracleRequest'), - 1, - constants.HashZero, - ) - }) - - describe('when called by a non-owner', () => { - it('reverts with owner error message', async () => { - await link.transfer(operator.address, startingBalance) - await evmRevert( - operator - .connect(roles.stranger) - .ownerTransferAndCall(to, payment, args), - 'Only callable by owner', - ) - }) - }) - - describe('when called by the owner', () => { - beforeEach(async () => { - await link.transfer(operator.address, startingBalance) - }) - - describe('without sufficient funds in contract', () => { - it('reverts with funds message', async () => { - const tooMuch = startingBalance * 2 - await evmRevert( - operator - .connect(roles.defaultAccount) - .ownerTransferAndCall(to, tooMuch, args), - 'Amount requested is greater than withdrawable balance', - ) - }) - }) - - describe('with sufficient funds', () => { - let tx: ContractTransaction - let receipt: ContractReceipt - let requesterBalanceBefore: BigNumber - let requesterBalanceAfter: BigNumber - let receiverBalanceBefore: BigNumber - let receiverBalanceAfter: BigNumber - - before(async () => { - requesterBalanceBefore = await link.balanceOf(operator.address) - receiverBalanceBefore = await link.balanceOf(operator2.address) - tx = await operator - .connect(roles.defaultAccount) - .ownerTransferAndCall(to, payment, args) - receipt = await tx.wait() - requesterBalanceAfter = await link.balanceOf(operator.address) - receiverBalanceAfter = await link.balanceOf(operator2.address) - }) - - it('emits an event', async () => { - assert.equal(3, receipt.logs?.length) - const transferLog = await getLog(tx, 1) - const parsedLog = link.interface.parseLog({ - data: transferLog.data, - topics: transferLog.topics, - }) - await expect(parsedLog.name).to.equal('Transfer') - }) - - it('transfers the tokens', async () => { - bigNumEquals( - requesterBalanceBefore.sub(requesterBalanceAfter), - payment, - ) - bigNumEquals(receiverBalanceAfter.sub(receiverBalanceBefore), payment) - }) - }) - }) - }) - - describe('#cancelOracleRequestByRequester', () => { - const nonce = 17 - - describe('with no pending requests', () => { - it('fails', async () => { - const fakeRequest: RunRequest = { - requestId: ethers.utils.formatBytes32String('1337'), - payment: '0', - callbackFunc: - getterSetterFactory.interface.getSighash('requestedBytes32'), - expiration: '999999999999', - - callbackAddr: '', - data: Buffer.from(''), - dataVersion: 0, - specId: '', - requester: '', - topic: '', - } - await increaseTime5Minutes(ethers.provider) - - await evmRevert( - operator - .connect(roles.stranger) - .cancelOracleRequestByRequester( - ...convertCancelByRequesterParams(fakeRequest, nonce), - ), - ) - }) - }) - - describe('with a pending request', () => { - const startingBalance = 100 - let request: ReturnType - let receipt: providers.TransactionReceipt - - beforeEach(async () => { - const requestAmount = 20 - - await link.transfer(await roles.consumer.getAddress(), startingBalance) - - const args = encodeOracleRequest( - specId, - await roles.consumer.getAddress(), - fHash, - nonce, - constants.HashZero, - ) - const tx = await link - .connect(roles.consumer) - .transferAndCall(operator.address, requestAmount, args) - receipt = await tx.wait() - - assert.equal(3, receipt.logs?.length) - request = decodeRunRequest(receipt.logs?.[2]) - - // pre conditions - const oracleBalance = await link.balanceOf(operator.address) - bigNumEquals(request.payment, oracleBalance) - - const consumerAmount = await link.balanceOf( - await roles.consumer.getAddress(), - ) - assert.equal( - startingBalance - Number(request.payment), - consumerAmount.toNumber(), - ) - }) - - describe('from a stranger', () => { - it('fails', async () => { - await evmRevert( - operator - .connect(roles.consumer) - .cancelOracleRequestByRequester( - ...convertCancelByRequesterParams(request, nonce), - ), - ) - }) - }) - - describe('from the requester', () => { - it('refunds the correct amount', async () => { - await increaseTime5Minutes(ethers.provider) - await operator - .connect(roles.consumer) - .cancelOracleRequestByRequester( - ...convertCancelByRequesterParams(request, nonce), - ) - const balance = await link.balanceOf( - await roles.consumer.getAddress(), - ) - - assert.equal(startingBalance, balance.toNumber()) // 100 - }) - - it('triggers a cancellation event', async () => { - await increaseTime5Minutes(ethers.provider) - const tx = await operator - .connect(roles.consumer) - .cancelOracleRequestByRequester( - ...convertCancelByRequesterParams(request, nonce), - ) - const receipt = await tx.wait() - - assert.equal(receipt.logs?.length, 2) - assert.equal(request.requestId, receipt.logs?.[0].topics[1]) - }) - - it('fails when called twice', async () => { - await increaseTime5Minutes(ethers.provider) - await operator - .connect(roles.consumer) - .cancelOracleRequestByRequester( - ...convertCancelByRequesterParams(request, nonce), - ) - - await evmRevert( - operator - .connect(roles.consumer) - .cancelOracleRequestByRequester(...convertCancelParams(request)), - ) - }) - }) - }) - }) - - describe('#cancelOracleRequest', () => { - describe('with no pending requests', () => { - it('fails', async () => { - const fakeRequest: RunRequest = { - requestId: ethers.utils.formatBytes32String('1337'), - payment: '0', - callbackFunc: - getterSetterFactory.interface.getSighash('requestedBytes32'), - expiration: '999999999999', - - callbackAddr: '', - data: Buffer.from(''), - dataVersion: 0, - specId: '', - requester: '', - topic: '', - } - await increaseTime5Minutes(ethers.provider) - - await evmRevert( - operator - .connect(roles.stranger) - .cancelOracleRequest(...convertCancelParams(fakeRequest)), - ) - }) - }) - - describe('with a pending request', () => { - const startingBalance = 100 - let request: ReturnType - let receipt: providers.TransactionReceipt - - beforeEach(async () => { - const requestAmount = 20 - - await link.transfer(await roles.consumer.getAddress(), startingBalance) - - const args = encodeOracleRequest( - specId, - await roles.consumer.getAddress(), - fHash, - 1, - constants.HashZero, - ) - const tx = await link - .connect(roles.consumer) - .transferAndCall(operator.address, requestAmount, args) - receipt = await tx.wait() - - assert.equal(3, receipt.logs?.length) - request = decodeRunRequest(receipt.logs?.[2]) - }) - - it('has correct initial balances', async () => { - const oracleBalance = await link.balanceOf(operator.address) - bigNumEquals(request.payment, oracleBalance) - - const consumerAmount = await link.balanceOf( - await roles.consumer.getAddress(), - ) - assert.equal( - startingBalance - Number(request.payment), - consumerAmount.toNumber(), - ) - }) - - describe('from a stranger', () => { - it('fails', async () => { - await evmRevert( - operator - .connect(roles.consumer) - .cancelOracleRequest(...convertCancelParams(request)), - ) - }) - }) - - describe('from the requester', () => { - it('refunds the correct amount', async () => { - await increaseTime5Minutes(ethers.provider) - await operator - .connect(roles.consumer) - .cancelOracleRequest(...convertCancelParams(request)) - const balance = await link.balanceOf( - await roles.consumer.getAddress(), - ) - - assert.equal(startingBalance, balance.toNumber()) // 100 - }) - - it('triggers a cancellation event', async () => { - await increaseTime5Minutes(ethers.provider) - const tx = await operator - .connect(roles.consumer) - .cancelOracleRequest(...convertCancelParams(request)) - const receipt = await tx.wait() - - assert.equal(receipt.logs?.length, 2) - assert.equal(request.requestId, receipt.logs?.[0].topics[1]) - }) - - it('fails when called twice', async () => { - await increaseTime5Minutes(ethers.provider) - await operator - .connect(roles.consumer) - .cancelOracleRequest(...convertCancelParams(request)) - - await evmRevert( - operator - .connect(roles.consumer) - .cancelOracleRequest(...convertCancelParams(request)), - ) - }) - }) - }) - }) - - describe('#ownerForward', () => { - let bytes: string - let payload: string - let mock: Contract - - beforeEach(async () => { - bytes = ethers.utils.hexlify(ethers.utils.randomBytes(100)) - payload = getterSetterFactory.interface.encodeFunctionData( - getterSetterFactory.interface.getFunction('setBytes'), - [bytes], - ) - mock = await getterSetterFactory.connect(roles.defaultAccount).deploy() - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - operator.connect(roles.stranger).ownerForward(mock.address, payload), - ) - }) - }) - - describe('when called by owner', () => { - describe('when attempting to forward to the link token', () => { - it('reverts', async () => { - const sighash = linkTokenFactory.interface.getSighash('name') - await evmRevert( - operator - .connect(roles.defaultAccount) - .ownerForward(link.address, sighash), - 'Cannot call to LINK', - ) - }) - }) - - describe('when forwarding to any other address', () => { - it('forwards the data', async () => { - const tx = await operator - .connect(roles.defaultAccount) - .ownerForward(mock.address, payload) - await tx.wait() - assert.equal(await mock.getBytes(), bytes) - }) - - it('reverts when sending to a non-contract address', async () => { - await evmRevert( - operator - .connect(roles.defaultAccount) - .ownerForward(zeroAddress, payload), - 'Must forward to a contract', - ) - }) - - it('perceives the message is sent by the Operator', async () => { - const tx = await operator - .connect(roles.defaultAccount) - .ownerForward(mock.address, payload) - const receipt = await tx.wait() - const log: any = receipt.logs?.[0] - const logData = mock.interface.decodeEventLog( - mock.interface.getEvent('SetBytes'), - log.data, - log.topics, - ) - assert.equal(ethers.utils.getAddress(logData.from), operator.address) - }) - }) - }) - }) -}) diff --git a/contracts/test/v0.7/OperatorFactory.test.ts b/contracts/test/v0.7/OperatorFactory.test.ts deleted file mode 100644 index d2a24600e2..0000000000 --- a/contracts/test/v0.7/OperatorFactory.test.ts +++ /dev/null @@ -1,293 +0,0 @@ -import { ethers } from 'hardhat' -import { evmWordToAddress, publicAbi } from '../test-helpers/helpers' -import { assert } from 'chai' -import { Contract, ContractFactory, ContractReceipt } from 'ethers' -import { getUsers, Roles } from '../test-helpers/setup' - -let linkTokenFactory: ContractFactory -let operatorGeneratorFactory: ContractFactory -let operatorFactory: ContractFactory -let forwarderFactory: ContractFactory - -let roles: Roles - -before(async () => { - const users = await getUsers() - - roles = users.roles - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) - operatorGeneratorFactory = await ethers.getContractFactory( - 'src/v0.7/OperatorFactory.sol:OperatorFactory', - roles.defaultAccount, - ) - operatorFactory = await ethers.getContractFactory( - 'src/v0.7/Operator.sol:Operator', - roles.defaultAccount, - ) - forwarderFactory = await ethers.getContractFactory( - 'src/v0.7/AuthorizedForwarder.sol:AuthorizedForwarder', - roles.defaultAccount, - ) -}) - -describe('OperatorFactory', () => { - let link: Contract - let operatorGenerator: Contract - let operator: Contract - let forwarder: Contract - let receipt: ContractReceipt - let emittedOperator: string - let emittedForwarder: string - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - operatorGenerator = await operatorGeneratorFactory - .connect(roles.defaultAccount) - .deploy(link.address) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(operatorGenerator, [ - 'created', - 'deployNewOperator', - 'deployNewOperatorAndForwarder', - 'deployNewForwarder', - 'deployNewForwarderAndTransferOwnership', - 'getChainlinkToken', - 'typeAndVersion', - ]) - }) - - describe('#typeAndVersion', () => { - it('describes the authorized forwarder', async () => { - assert.equal( - await operatorGenerator.typeAndVersion(), - 'OperatorFactory 1.0.0', - ) - }) - }) - - describe('#deployNewOperator', () => { - beforeEach(async () => { - const tx = await operatorGenerator - .connect(roles.oracleNode) - .deployNewOperator() - - receipt = await tx.wait() - emittedOperator = evmWordToAddress(receipt.logs?.[0].topics?.[1]) - }) - - it('emits an event', async () => { - assert.equal(receipt?.events?.[0]?.event, 'OperatorCreated') - assert.equal(emittedOperator, receipt.events?.[0].args?.[0]) - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[0].args?.[1], - ) - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[0].args?.[2], - ) - }) - - it('sets the correct owner', async () => { - operator = await operatorFactory - .connect(roles.defaultAccount) - .attach(emittedOperator) - const ownerString = await operator.owner() - assert.equal(ownerString, await roles.oracleNode.getAddress()) - }) - - it('records that it deployed that address', async () => { - assert.isTrue(await operatorGenerator.created(emittedOperator)) - }) - }) - - describe('#deployNewOperatorAndForwarder', () => { - beforeEach(async () => { - const tx = await operatorGenerator - .connect(roles.oracleNode) - .deployNewOperatorAndForwarder() - - receipt = await tx.wait() - emittedOperator = evmWordToAddress(receipt.logs?.[0].topics?.[1]) - emittedForwarder = evmWordToAddress(receipt.logs?.[3].topics?.[1]) - }) - - it('emits an event recording that the operator was deployed', async () => { - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[0].args?.[1], - ) - assert.equal(receipt?.events?.[0]?.event, 'OperatorCreated') - assert.equal(receipt?.events?.[0]?.args?.[0], emittedOperator) - assert.equal( - receipt?.events?.[0]?.args?.[1], - await roles.oracleNode.getAddress(), - ) - assert.equal( - receipt?.events?.[0]?.args?.[2], - await roles.oracleNode.getAddress(), - ) - }) - - it('proposes the transfer of the forwarder to the operator', async () => { - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[0].args?.[1], - ) - assert.equal( - receipt?.events?.[1]?.topics?.[0], - '0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278', //OwnershipTransferRequested(address,address) - ) - assert.equal( - evmWordToAddress(receipt?.events?.[1]?.topics?.[1]), - operatorGenerator.address, - ) - assert.equal( - evmWordToAddress(receipt?.events?.[1]?.topics?.[2]), - emittedOperator, - ) - - assert.equal( - receipt?.events?.[2]?.topics?.[0], - '0x4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e', //OwnershipTransferRequestedWithMessage(address,address,bytes) - ) - assert.equal( - evmWordToAddress(receipt?.events?.[2]?.topics?.[1]), - operatorGenerator.address, - ) - assert.equal( - evmWordToAddress(receipt?.events?.[2]?.topics?.[2]), - emittedOperator, - ) - }) - - it('emits an event recording that the forwarder was deployed', async () => { - assert.equal(receipt?.events?.[3]?.event, 'AuthorizedForwarderCreated') - assert.equal(receipt?.events?.[3]?.args?.[0], emittedForwarder) - assert.equal(receipt?.events?.[3]?.args?.[1], operatorGenerator.address) - assert.equal( - receipt?.events?.[3]?.args?.[2], - await roles.oracleNode.getAddress(), - ) - }) - - it('sets the correct owner on the operator', async () => { - operator = await operatorFactory - .connect(roles.defaultAccount) - .attach(receipt?.events?.[0]?.args?.[0]) - assert.equal(await roles.oracleNode.getAddress(), await operator.owner()) - }) - - it('sets the operator as the owner of the forwarder', async () => { - forwarder = await forwarderFactory - .connect(roles.defaultAccount) - .attach(emittedForwarder) - assert.equal(operatorGenerator.address, await forwarder.owner()) - }) - - it('records that it deployed that address', async () => { - assert.isTrue(await operatorGenerator.created(emittedOperator)) - assert.isTrue(await operatorGenerator.created(emittedForwarder)) - }) - }) - - describe('#deployNewForwarder', () => { - beforeEach(async () => { - const tx = await operatorGenerator - .connect(roles.oracleNode) - .deployNewForwarder() - - receipt = await tx.wait() - emittedForwarder = receipt.events?.[0].args?.[0] - }) - - it('emits an event', async () => { - assert.equal(receipt?.events?.[0]?.event, 'AuthorizedForwarderCreated') - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[0].args?.[1], - ) // owner - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[0].args?.[2], - ) // sender - }) - - it('sets the caller as the owner', async () => { - forwarder = await forwarderFactory - .connect(roles.defaultAccount) - .attach(emittedForwarder) - const ownerString = await forwarder.owner() - assert.equal(ownerString, await roles.oracleNode.getAddress()) - }) - - it('records that it deployed that address', async () => { - assert.isTrue(await operatorGenerator.created(emittedForwarder)) - }) - }) - - describe('#deployNewForwarderAndTransferOwnership', () => { - const message = '0x42' - - beforeEach(async () => { - const tx = await operatorGenerator - .connect(roles.oracleNode) - .deployNewForwarderAndTransferOwnership( - await roles.stranger.getAddress(), - message, - ) - receipt = await tx.wait() - - emittedForwarder = evmWordToAddress(receipt.logs?.[2].topics?.[1]) - }) - - it('emits an event', async () => { - assert.equal(receipt?.events?.[2]?.event, 'AuthorizedForwarderCreated') - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[2].args?.[1], - ) // owner - assert.equal( - await roles.oracleNode.getAddress(), - receipt.events?.[2].args?.[2], - ) // sender - }) - - it('sets the caller as the owner', async () => { - forwarder = await forwarderFactory - .connect(roles.defaultAccount) - .attach(emittedForwarder) - const ownerString = await forwarder.owner() - assert.equal(ownerString, await roles.oracleNode.getAddress()) - }) - - it('proposes a transfer to the recipient', async () => { - const emittedOwner = evmWordToAddress(receipt.logs?.[0].topics?.[1]) - assert.equal(emittedOwner, await roles.oracleNode.getAddress()) - const emittedRecipient = evmWordToAddress(receipt.logs?.[0].topics?.[2]) - assert.equal(emittedRecipient, await roles.stranger.getAddress()) - }) - - it('proposes a transfer to the recipient with the specified message', async () => { - const emittedOwner = evmWordToAddress(receipt.logs?.[1].topics?.[1]) - assert.equal(emittedOwner, await roles.oracleNode.getAddress()) - const emittedRecipient = evmWordToAddress(receipt.logs?.[1].topics?.[2]) - assert.equal(emittedRecipient, await roles.stranger.getAddress()) - - const encodedMessage = ethers.utils.defaultAbiCoder.encode( - ['bytes'], - [message], - ) - assert.equal(receipt?.logs?.[1]?.data, encodedMessage) - }) - - it('records that it deployed that address', async () => { - assert.isTrue(await operatorGenerator.created(emittedForwarder)) - }) - }) -}) diff --git a/contracts/test/v0.7/StalenessFlaggingValidator.test.ts b/contracts/test/v0.7/StalenessFlaggingValidator.test.ts deleted file mode 100644 index 8a5c4b6763..0000000000 --- a/contracts/test/v0.7/StalenessFlaggingValidator.test.ts +++ /dev/null @@ -1,632 +0,0 @@ -import { ethers } from 'hardhat' -import { - evmWordToAddress, - getLog, - getLogs, - numToBytes32, - publicAbi, -} from '../test-helpers/helpers' -import { assert, expect } from 'chai' -import { BigNumber, Contract, ContractFactory } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' -import { evmRevert } from '../test-helpers/matchers' - -let personas: Personas -let validatorFactory: ContractFactory -let flagsFactory: ContractFactory -let acFactory: ContractFactory -let aggregatorFactory: ContractFactory - -before(async () => { - personas = (await getUsers()).personas - - validatorFactory = await ethers.getContractFactory( - 'src/v0.7/dev/StalenessFlaggingValidator.sol:StalenessFlaggingValidator', - personas.Carol, - ) - flagsFactory = await ethers.getContractFactory( - 'src/v0.6/Flags.sol:Flags', - personas.Carol, - ) - acFactory = await ethers.getContractFactory( - 'src/v0.6/SimpleWriteAccessController.sol:SimpleWriteAccessController', - personas.Carol, - ) - aggregatorFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', - personas.Carol, - ) -}) - -describe('StalenessFlaggingValidator', () => { - let validator: Contract - let flags: Contract - let ac: Contract - - const flaggingThreshold1 = 10000 - const flaggingThreshold2 = 20000 - - beforeEach(async () => { - ac = await acFactory.connect(personas.Carol).deploy() - flags = await flagsFactory.connect(personas.Carol).deploy(ac.address) - validator = await validatorFactory - .connect(personas.Carol) - .deploy(flags.address) - - await ac.connect(personas.Carol).addAccess(validator.address) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(validator, [ - 'update', - 'check', - 'setThresholds', - 'setFlagsAddress', - 'threshold', - 'flags', - // Upkeep methods: - 'checkUpkeep', - 'performUpkeep', - // Owned methods: - 'acceptOwnership', - 'owner', - 'transferOwnership', - ]) - }) - - describe('#constructor', () => { - it('sets the arguments passed in', async () => { - assert.equal(await validator.flags(), flags.address) - }) - - it('sets the owner', async () => { - assert.equal(await validator.owner(), await personas.Carol.getAddress()) - }) - }) - - describe('#setFlagsAddress', () => { - const newFlagsAddress = '0x0123456789012345678901234567890123456789' - - it('changes the flags address', async () => { - assert.equal(flags.address, await validator.flags()) - - await validator.connect(personas.Carol).setFlagsAddress(newFlagsAddress) - - assert.equal(newFlagsAddress, await validator.flags()) - }) - - it('emits a log event only when actually changed', async () => { - const tx = await validator - .connect(personas.Carol) - .setFlagsAddress(newFlagsAddress) - await expect(tx) - .to.emit(validator, 'FlagsAddressUpdated') - .withArgs(flags.address, newFlagsAddress) - - const sameChangeTx = await validator - .connect(personas.Carol) - .setFlagsAddress(newFlagsAddress) - - await expect(sameChangeTx).to.not.emit(validator, 'FlagsAddressUpdated') - }) - - describe('when called by a non-owner', () => { - it('reverts', async () => { - await evmRevert( - validator.connect(personas.Neil).setFlagsAddress(newFlagsAddress), - 'Only callable by owner', - ) - }) - }) - }) - - describe('#setThresholds', () => { - let agg1: Contract - let agg2: Contract - let aggregators: Array - let thresholds: Array - - beforeEach(async () => { - const decimals = 8 - const initialAnswer = 10000000000 - agg1 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - agg2 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - }) - - describe('failure', () => { - beforeEach(() => { - aggregators = [agg1.address, agg2.address] - thresholds = [flaggingThreshold1] - }) - - it('reverts when called by a non-owner', async () => { - await evmRevert( - validator - .connect(personas.Neil) - .setThresholds(aggregators, thresholds), - 'Only callable by owner', - ) - }) - - it('reverts when passed uneven arrays', async () => { - await evmRevert( - validator - .connect(personas.Carol) - .setThresholds(aggregators, thresholds), - 'Different sized arrays', - ) - }) - }) - - describe('success', () => { - let tx: any - - beforeEach(() => { - aggregators = [agg1.address, agg2.address] - thresholds = [flaggingThreshold1, flaggingThreshold2] - }) - - describe('when called with 2 new thresholds', () => { - beforeEach(async () => { - tx = await validator - .connect(personas.Carol) - .setThresholds(aggregators, thresholds) - }) - - it('sets the thresholds', async () => { - const first = await validator.threshold(agg1.address) - const second = await validator.threshold(agg2.address) - assert.equal(first.toString(), flaggingThreshold1.toString()) - assert.equal(second.toString(), flaggingThreshold2.toString()) - }) - - it('emits events', async () => { - const firstEvent = await getLog(tx, 0) - assert.equal(evmWordToAddress(firstEvent.topics[1]), agg1.address) - assert.equal(firstEvent.topics[3], numToBytes32(flaggingThreshold1)) - const secondEvent = await getLog(tx, 1) - assert.equal(evmWordToAddress(secondEvent.topics[1]), agg2.address) - assert.equal(secondEvent.topics[3], numToBytes32(flaggingThreshold2)) - }) - }) - - describe('when called with 2, but 1 has not changed', () => { - it('emits only 1 event', async () => { - tx = await validator - .connect(personas.Carol) - .setThresholds(aggregators, thresholds) - - const newThreshold = flaggingThreshold2 + 1 - tx = await validator - .connect(personas.Carol) - .setThresholds(aggregators, [flaggingThreshold1, newThreshold]) - const logs = await getLogs(tx) - assert.equal(logs.length, 1) - const log = logs[0] - assert.equal(evmWordToAddress(log.topics[1]), agg2.address) - assert.equal(log.topics[2], numToBytes32(flaggingThreshold2)) - assert.equal(log.topics[3], numToBytes32(newThreshold)) - }) - }) - }) - }) - - describe('#check', () => { - let agg1: Contract - let agg2: Contract - let aggregators: Array - let thresholds: Array - const decimals = 8 - const initialAnswer = 10000000000 - beforeEach(async () => { - agg1 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - agg2 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - aggregators = [agg1.address, agg2.address] - thresholds = [flaggingThreshold1, flaggingThreshold2] - await validator.setThresholds(aggregators, thresholds) - }) - - describe('when neither are stale', () => { - it('returns an empty array', async () => { - const response = await validator.check(aggregators) - assert.equal(response.length, 0) - }) - }) - - describe('when threshold is not set in the validator', () => { - it('returns an empty array', async () => { - const agg3 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - const response = await validator.check([agg3.address]) - assert.equal(response.length, 0) - }) - }) - - describe('when one of the aggregators is stale', () => { - it('returns an array with one stale aggregator', async () => { - const currentTimestamp = await agg1.latestTimestamp() - const staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - const response = await validator.check(aggregators) - - assert.equal(response.length, 1) - assert.equal(response[0], agg1.address) - }) - }) - - describe('When both aggregators are stale', () => { - it('returns an array with both aggregators', async () => { - let currentTimestamp = await agg1.latestTimestamp() - let staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - currentTimestamp = await agg2.latestTimestamp() - staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold2 + 1), - ) - await agg2.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - const response = await validator.check(aggregators) - - assert.equal(response.length, 2) - assert.equal(response[0], agg1.address) - assert.equal(response[1], agg2.address) - }) - }) - }) - - describe('#update', () => { - let agg1: Contract - let agg2: Contract - let aggregators: Array - let thresholds: Array - const decimals = 8 - const initialAnswer = 10000000000 - beforeEach(async () => { - agg1 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - agg2 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - aggregators = [agg1.address, agg2.address] - thresholds = [flaggingThreshold1, flaggingThreshold2] - await validator.setThresholds(aggregators, thresholds) - }) - - describe('when neither are stale', () => { - it('does not raise a flag', async () => { - const tx = await validator.update(aggregators) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - - describe('when threshold is not set in the validator', () => { - it('does not raise a flag', async () => { - const agg3 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - const tx = await validator.update([agg3.address]) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - - describe('when one is stale', () => { - it('raises a flag for that aggregator', async () => { - const currentTimestamp = await agg1.latestTimestamp() - const staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - const tx = await validator.update(aggregators) - const logs = await getLogs(tx) - assert.equal(logs.length, 1) - assert.equal(evmWordToAddress(logs[0].topics[1]), agg1.address) - }) - }) - - describe('when both are stale', () => { - it('raises 2 flags, one for each aggregator', async () => { - let currentTimestamp = await agg1.latestTimestamp() - let staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - currentTimestamp = await agg2.latestTimestamp() - staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold2 + 1), - ) - await agg2.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - const tx = await validator.update(aggregators) - const logs = await getLogs(tx) - assert.equal(logs.length, 2) - assert.equal(evmWordToAddress(logs[0].topics[1]), agg1.address) - assert.equal(evmWordToAddress(logs[1].topics[1]), agg2.address) - }) - }) - }) - - describe('#checkUpkeep', () => { - let agg1: Contract - let agg2: Contract - let aggregators: Array - let thresholds: Array - const decimals = 8 - const initialAnswer = 10000000000 - beforeEach(async () => { - agg1 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - agg2 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - aggregators = [agg1.address, agg2.address] - thresholds = [flaggingThreshold1, flaggingThreshold2] - await validator.setThresholds(aggregators, thresholds) - }) - - describe('when neither are stale', () => { - it('returns false and an empty array', async () => { - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const response = await validator.checkUpkeep(bytesData) - - assert.equal(response[0], false) - const decodedResponse = ethers.utils.defaultAbiCoder.decode( - ['address[]'], - response?.[1], - ) - assert.equal(decodedResponse[0].length, 0) - }) - }) - - describe('when threshold is not set in the validator', () => { - it('returns flase and an empty array', async () => { - const agg3 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [[agg3.address]], - ) - const response = await validator.checkUpkeep(bytesData) - - assert.equal(response[0], false) - const decodedResponse = ethers.utils.defaultAbiCoder.decode( - ['address[]'], - response?.[1], - ) - assert.equal(decodedResponse[0].length, 0) - }) - }) - - describe('when one of the aggregators is stale', () => { - it('returns true with an array with one stale aggregator', async () => { - const currentTimestamp = await agg1.latestTimestamp() - const staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const response = await validator.checkUpkeep(bytesData) - - assert.equal(response[0], true) - const decodedResponse = ethers.utils.defaultAbiCoder.decode( - ['address[]'], - response?.[1], - ) - const decodedArray = decodedResponse[0] - assert.equal(decodedArray.length, 1) - assert.equal(decodedArray[0], agg1.address) - }) - }) - - describe('When both aggregators are stale', () => { - it('returns true with an array with both aggregators', async () => { - let currentTimestamp = await agg1.latestTimestamp() - let staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - currentTimestamp = await agg2.latestTimestamp() - staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold2 + 1), - ) - await agg2.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const response = await validator.checkUpkeep(bytesData) - - assert.equal(response[0], true) - const decodedResponse = ethers.utils.defaultAbiCoder.decode( - ['address[]'], - response?.[1], - ) - const decodedArray = decodedResponse[0] - assert.equal(decodedArray.length, 2) - assert.equal(decodedArray[0], agg1.address) - assert.equal(decodedArray[1], agg2.address) - }) - }) - }) - - describe('#performUpkeep', () => { - let agg1: Contract - let agg2: Contract - let aggregators: Array - let thresholds: Array - const decimals = 8 - const initialAnswer = 10000000000 - beforeEach(async () => { - agg1 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - agg2 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - aggregators = [agg1.address, agg2.address] - thresholds = [flaggingThreshold1, flaggingThreshold2] - await validator.setThresholds(aggregators, thresholds) - }) - - describe('when neither are stale', () => { - it('does not raise a flag', async () => { - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const tx = await validator.performUpkeep(bytesData) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - - describe('when threshold is not set in the validator', () => { - it('does not raise a flag', async () => { - const agg3 = await aggregatorFactory - .connect(personas.Carol) - .deploy(decimals, initialAnswer) - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [[agg3.address]], - ) - const tx = await validator.performUpkeep(bytesData) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - - describe('when one is stale', () => { - it('raises a flag for that aggregator', async () => { - const currentTimestamp = await agg1.latestTimestamp() - const staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const tx = await validator.performUpkeep(bytesData) - const logs = await getLogs(tx) - assert.equal(logs.length, 1) - assert.equal(evmWordToAddress(logs[0].topics[1]), agg1.address) - }) - }) - - describe('when both are stale', () => { - it('raises 2 flags, one for each aggregator', async () => { - let currentTimestamp = await agg1.latestTimestamp() - let staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold1 + 1), - ) - await agg1.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - currentTimestamp = await agg2.latestTimestamp() - staleTimestamp = currentTimestamp.sub( - BigNumber.from(flaggingThreshold2 + 1), - ) - await agg2.updateRoundData( - 99, - initialAnswer, - staleTimestamp, - staleTimestamp, - ) - - const bytesData = ethers.utils.defaultAbiCoder.encode( - ['address[]'], - [aggregators], - ) - const tx = await validator.performUpkeep(bytesData) - const logs = await getLogs(tx) - assert.equal(logs.length, 2) - assert.equal(evmWordToAddress(logs[0].topics[1]), agg1.address) - assert.equal(evmWordToAddress(logs[1].topics[1]), agg2.address) - }) - }) - }) -}) diff --git a/contracts/test/v0.7/UpkeepRegistrationRequests.test.ts b/contracts/test/v0.7/UpkeepRegistrationRequests.test.ts deleted file mode 100644 index 5ec9306c66..0000000000 --- a/contracts/test/v0.7/UpkeepRegistrationRequests.test.ts +++ /dev/null @@ -1,603 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { evmRevert } from '../test-helpers/matchers' -import { getUsers, Personas } from '../test-helpers/setup' -import { BigNumber, Signer } from 'ethers' -import { LinkToken__factory as LinkTokenFactory } from '../../typechain/factories/LinkToken__factory' -import { KeeperRegistry1_1__factory as KeeperRegistryFactory } from '../../typechain/factories/KeeperRegistry1_1__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepRegistrationRequests__factory as UpkeepRegistrationRequestsFactory } from '../../typechain/factories/UpkeepRegistrationRequests__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../typechain/factories/UpkeepMock__factory' -import { KeeperRegistry1_1 as KeeperRegistry } from '../../typechain/KeeperRegistry1_1' -import { UpkeepRegistrationRequests } from '../../typechain/UpkeepRegistrationRequests' -import { MockV3Aggregator } from '../../typechain/MockV3Aggregator' -import { LinkToken } from '../../typechain/LinkToken' -import { UpkeepMock } from '../../typechain/UpkeepMock' - -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let keeperRegistryFactory: KeeperRegistryFactory -let upkeepRegistrationRequestsFactory: UpkeepRegistrationRequestsFactory -let upkeepMockFactory: UpkeepMockFactory - -let personas: Personas - -before(async () => { - personas = (await getUsers()).personas - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - // @ts-ignore bug in autogen file - keeperRegistryFactory = await ethers.getContractFactory('KeeperRegistry1_1') - upkeepRegistrationRequestsFactory = await ethers.getContractFactory( - 'UpkeepRegistrationRequests', - ) - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') -}) - -const errorMsgs = { - onlyOwner: 'revert Only callable by owner', - onlyAdmin: 'only admin / owner can cancel', - hashPayload: 'hash and payload do not match', - requestNotFound: 'request not found', -} - -describe('UpkeepRegistrationRequests', () => { - const upkeepName = 'SampleUpkeep' - - const linkEth = BigNumber.from(300000000) - const gasWei = BigNumber.from(100) - const executeGas = BigNumber.from(100000) - const source = BigNumber.from(100) - const paymentPremiumPPB = BigNumber.from(250000000) - const flatFeeMicroLink = BigNumber.from(0) - - const window_big = BigNumber.from(1000) - const window_small = BigNumber.from(2) - const threshold_big = BigNumber.from(1000) - const threshold_small = BigNumber.from(5) - - const blockCountPerTurn = BigNumber.from(3) - const emptyBytes = '0x00' - const stalenessSeconds = BigNumber.from(43820) - const gasCeilingMultiplier = BigNumber.from(1) - const maxCheckGas = BigNumber.from(20000000) - const fallbackGasPrice = BigNumber.from(200) - const fallbackLinkPrice = BigNumber.from(200000000) - const minLINKJuels = BigNumber.from('1000000000000000000') - const amount = BigNumber.from('5000000000000000000') - const amount1 = BigNumber.from('6000000000000000000') - - let owner: Signer - let admin: Signer - let someAddress: Signer - let registrarOwner: Signer - let stranger: Signer - - let linkToken: LinkToken - let linkEthFeed: MockV3Aggregator - let gasPriceFeed: MockV3Aggregator - let registry: KeeperRegistry - let mock: UpkeepMock - let registrar: UpkeepRegistrationRequests - - beforeEach(async () => { - owner = personas.Default - admin = personas.Neil - someAddress = personas.Ned - registrarOwner = personas.Nelly - stranger = personas.Nancy - - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - registry = await keeperRegistryFactory - .connect(owner) - .deploy( - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - maxCheckGas, - stalenessSeconds, - gasCeilingMultiplier, - fallbackGasPrice, - fallbackLinkPrice, - ) - - mock = await upkeepMockFactory.deploy() - - registrar = await upkeepRegistrationRequestsFactory - .connect(registrarOwner) - .deploy(linkToken.address, minLINKJuels) - - await registry.setRegistrar(registrar.address) - }) - - describe('#typeAndVersion', () => { - it('uses the correct type and version', async () => { - const typeAndVersion = await registrar.typeAndVersion() - assert.equal(typeAndVersion, 'UpkeepRegistrationRequests 1.0.0') - }) - }) - - describe('#register', () => { - it('reverts if not called by the LINK token', async () => { - await evmRevert( - registrar - .connect(someAddress) - .register( - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - amount, - source, - ), - 'Must use LINK token', - ) - }) - - it('reverts if the amount passed in data mismatches actual amount sent', async () => { - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - true, - window_small, - threshold_big, - registry.address, - minLINKJuels, - ) - - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - amount1, - source, - ], - ) - - await evmRevert( - linkToken.transferAndCall(registrar.address, amount, abiEncodedBytes), - 'Amount mismatch', - ) - }) - - it('reverts if the admin address is 0x0000...', async () => { - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - '0x0000000000000000000000000000000000000000', - emptyBytes, - amount, - source, - ], - ) - - await evmRevert( - linkToken.transferAndCall(registrar.address, amount, abiEncodedBytes), - 'Unable to create request', - ) - }) - - it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { - //get current upkeep count - const upkeepCount = await registry.getUpkeepCount() - - //set auto approve ON with high threshold limits - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - true, - window_small, - threshold_big, - registry.address, - minLINKJuels, - ) - - //register with auto approve ON - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - amount, - source, - ], - ) - const tx = await linkToken.transferAndCall( - registrar.address, - amount, - abiEncodedBytes, - ) - - //confirm if a new upkeep has been registered and the details are the same as the one just registered - const newupkeep = await registry.getUpkeep(upkeepCount) - assert.equal(newupkeep.target, mock.address) - assert.equal(newupkeep.admin, await admin.getAddress()) - assert.equal(newupkeep.checkData, emptyBytes) - assert.equal(newupkeep.balance.toString(), amount.toString()) - assert.equal(newupkeep.executeGas, executeGas.toNumber()) - - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('Auto Approve OFF - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { - //get upkeep count before attempting registration - const beforeCount = await registry.getUpkeepCount() - - //set auto approve OFF, threshold limits dont matter in this case - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - false, - window_small, - threshold_big, - registry.address, - minLINKJuels, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - amount, - source, - ], - ) - const tx = await linkToken.transferAndCall( - registrar.address, - amount, - abiEncodedBytes, - ) - const receipt = await tx.wait() - - //get upkeep count after attempting registration - const afterCount = await registry.getUpkeepCount() - //confirm that a new upkeep has NOT been registered and upkeep count is still the same - assert.deepEqual(beforeCount, afterCount) - - //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).not.to.emit(registrar, 'RegistrationApproved') - - const hash = receipt.logs[2].topics[1] - const pendingRequest = await registrar.getPendingRequest(hash) - assert.equal(await admin.getAddress(), pendingRequest[0]) - assert.ok(amount.eq(pendingRequest[1])) - }) - - it('Auto Approve ON - Throttle max approvals - does not registers an upkeep on KeeperRegistry beyond the throttle limit, emits only RegistrationRequested event after throttle starts', async () => { - //get upkeep count before attempting registration - const beforeCount = await registry.getUpkeepCount() - - //set auto approve on, with low threshold limits - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - true, - window_big, - threshold_small, - registry.address, - minLINKJuels, - ) - - let abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - amount, - source, - ]) - - //register within threshold, new upkeep should be registered - await linkToken.transferAndCall( - registrar.address, - amount, - abiEncodedBytes, - ) - const intermediateCount = await registry.getUpkeepCount() - //make sure 1 upkeep was registered - assert.equal(beforeCount.toNumber() + 1, intermediateCount.toNumber()) - - //try registering more than threshold(say 2x), new upkeeps should not be registered after the threshold amount is reached - for (let step = 0; step < threshold_small.toNumber() * 2; step++) { - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - executeGas.toNumber() + step, // make unique hash - await admin.getAddress(), - emptyBytes, - amount, - source, - ]) - - await linkToken.transferAndCall( - registrar.address, - amount, - abiEncodedBytes, - ) - } - const afterCount = await registry.getUpkeepCount() - //count of newly registered upkeeps should be equal to the threshold set for auto approval - const newRegistrationsCount = - afterCount.toNumber() - beforeCount.toNumber() - assert( - newRegistrationsCount == threshold_small.toNumber(), - 'Registrations beyond threshold', - ) - }) - }) - - describe('#approve', () => { - let hash: string - - beforeEach(async () => { - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - false, - window_small, - threshold_big, - registry.address, - minLINKJuels, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - amount, - source, - ], - ) - - const tx = await linkToken.transferAndCall( - registrar.address, - amount, - abiEncodedBytes, - ) - const receipt = await tx.wait() - hash = receipt.logs[2].topics[1] - }) - - it('reverts if not called by the owner', async () => { - const tx = registrar - .connect(stranger) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - hash, - ) - await evmRevert(tx, 'Only callable by owner') - }) - - it('reverts if the hash does not exist', async () => { - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - - it('reverts if any member of the payload changes', async () => { - let tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - ethers.Wallet.createRandom().address, - executeGas, - await admin.getAddress(), - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - 10000, - await admin.getAddress(), - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - ethers.Wallet.createRandom().address, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - '0x1234', - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - }) - - it('approves an existing registration request', async () => { - const tx = await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - hash, - ) - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('deletes the request afterwards / reverts if the request DNE', async () => { - await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - hash, - ) - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - }) - - describe('#cancel', () => { - let hash: string - - beforeEach(async () => { - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - false, - window_small, - threshold_big, - registry.address, - minLINKJuels, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - amount, - source, - ], - ) - const tx = await linkToken.transferAndCall( - registrar.address, - amount, - abiEncodedBytes, - ) - const receipt = await tx.wait() - hash = receipt.logs[2].topics[1] - // submit duplicate request (increase balance) - await linkToken.transferAndCall( - registrar.address, - amount, - abiEncodedBytes, - ) - }) - - it('reverts if not called by the admin / owner', async () => { - const tx = registrar.connect(stranger).cancel(hash) - await evmRevert(tx, errorMsgs.onlyAdmin) - }) - - it('reverts if the hash does not exist', async () => { - const tx = registrar - .connect(registrarOwner) - .cancel( - '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', - ) - await evmRevert(tx, 'request not found') - }) - - it('refunds the total request balance to the admin address', async () => { - const before = await linkToken.balanceOf(await admin.getAddress()) - const tx = await registrar.connect(admin).cancel(hash) - const after = await linkToken.balanceOf(await admin.getAddress()) - assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) - await expect(tx).to.emit(registrar, 'RegistrationRejected') - }) - - it('deletes the request hash', async () => { - await registrar.connect(registrarOwner).cancel(hash) - let tx = registrar.connect(registrarOwner).cancel(hash) - await evmRevert(tx, errorMsgs.requestNotFound) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - }) -}) diff --git a/contracts/test/v0.7/VRFD20.test.ts b/contracts/test/v0.7/VRFD20.test.ts deleted file mode 100644 index f1e0e9ab0a..0000000000 --- a/contracts/test/v0.7/VRFD20.test.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { - BigNumber, - constants, - Contract, - ContractFactory, - ContractTransaction, -} from 'ethers' -import { getUsers, Personas, Roles } from '../test-helpers/setup' -import { - evmWordToAddress, - getLog, - publicAbi, - toBytes32String, - toWei, - numToBytes32, - getLogs, -} from '../test-helpers/helpers' - -let roles: Roles -let personas: Personas -let linkTokenFactory: ContractFactory -let vrfCoordinatorMockFactory: ContractFactory -let vrfD20Factory: ContractFactory - -before(async () => { - const users = await getUsers() - - roles = users.roles - personas = users.personas - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) - vrfCoordinatorMockFactory = await ethers.getContractFactory( - 'src/v0.7/tests/VRFCoordinatorMock.sol:VRFCoordinatorMock', - roles.defaultAccount, - ) - vrfD20Factory = await ethers.getContractFactory( - 'src/v0.6/examples/VRFD20.sol:VRFD20', - roles.defaultAccount, - ) -}) - -describe('VRFD20', () => { - const deposit = toWei('1') - const fee = toWei('0.1') - const keyHash = toBytes32String('keyHash') - - let link: Contract - let vrfCoordinator: Contract - let vrfD20: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - vrfCoordinator = await vrfCoordinatorMockFactory - .connect(roles.defaultAccount) - .deploy(link.address) - vrfD20 = await vrfD20Factory - .connect(roles.defaultAccount) - .deploy(vrfCoordinator.address, link.address, keyHash, fee) - await link.transfer(vrfD20.address, deposit) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(vrfD20, [ - // Owned - 'acceptOwnership', - 'owner', - 'transferOwnership', - //VRFConsumerBase - 'rawFulfillRandomness', - // VRFD20 - 'rollDice', - 'house', - 'withdrawLINK', - 'keyHash', - 'fee', - 'setKeyHash', - 'setFee', - ]) - }) - - describe('#withdrawLINK', () => { - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20 - .connect(roles.stranger) - .withdrawLINK(await roles.stranger.getAddress(), deposit), - ).to.be.revertedWith('Only callable by owner') - }) - - it('reverts when not enough LINK in the contract', async () => { - const withdrawAmount = deposit.mul(2) - await expect( - vrfD20 - .connect(roles.defaultAccount) - .withdrawLINK( - await roles.defaultAccount.getAddress(), - withdrawAmount, - ), - ).to.be.reverted - }) - }) - - describe('success', () => { - it('withdraws LINK', async () => { - const startingAmount = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - const expectedAmount = BigNumber.from(startingAmount).add(deposit) - await vrfD20 - .connect(roles.defaultAccount) - .withdrawLINK(await roles.defaultAccount.getAddress(), deposit) - const actualAmount = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - assert.equal(actualAmount.toString(), expectedAmount.toString()) - }) - }) - }) - - describe('#setKeyHash', () => { - const newHash = toBytes32String('newhash') - - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20.connect(roles.stranger).setKeyHash(newHash), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('success', () => { - it('sets the key hash', async () => { - await vrfD20.setKeyHash(newHash) - const actualHash = await vrfD20.keyHash() - assert.equal(actualHash, newHash) - }) - }) - }) - - describe('#setFee', () => { - const newFee = 1234 - - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20.connect(roles.stranger).setFee(newFee), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('success', () => { - it('sets the fee', async () => { - await vrfD20.setFee(newFee) - const actualFee = await vrfD20.fee() - assert.equal(actualFee.toString(), newFee.toString()) - }) - }) - }) - - describe('#house', () => { - describe('failure', () => { - it('reverts when dice not rolled', async () => { - await expect( - vrfD20.house(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Dice not rolled') - }) - - it('reverts when dice roll is in progress', async () => { - await vrfD20.rollDice(await personas.Nancy.getAddress()) - await expect( - vrfD20.house(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Roll in progress') - }) - }) - - describe('success', () => { - it('returns the correct house', async () => { - const randomness = 98765 - const expectedHouse = 'Martell' - const tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - const log = await getLog(tx, 3) - const eventRequestId = log?.topics?.[1] - await vrfCoordinator.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - const response = await vrfD20.house(await personas.Nancy.getAddress()) - assert.equal(response.toString(), expectedHouse) - }) - }) - }) - - describe('#rollDice', () => { - describe('success', () => { - let tx: ContractTransaction - beforeEach(async () => { - tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - }) - - it('emits a RandomnessRequest event from the VRFCoordinator', async () => { - const log = await getLog(tx, 2) - const topics = log?.topics - assert.equal(evmWordToAddress(topics?.[1]), vrfD20.address) - assert.equal(topics?.[2], keyHash) - assert.equal(topics?.[3], constants.HashZero) - }) - }) - - describe('failure', () => { - it('reverts when LINK balance is zero', async () => { - const vrfD202 = await vrfD20Factory - .connect(roles.defaultAccount) - .deploy(vrfCoordinator.address, link.address, keyHash, fee) - await expect( - vrfD202.rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Not enough LINK to pay fee') - }) - - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20 - .connect(roles.stranger) - .rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Only callable by owner') - }) - - it('reverts when the roller rolls more than once', async () => { - await vrfD20.rollDice(await personas.Nancy.getAddress()) - await expect( - vrfD20.rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Already rolled') - }) - }) - }) - - describe('#fulfillRandomness', () => { - const randomness = 98765 - const expectedModResult = (randomness % 20) + 1 - const expectedHouse = 'Martell' - let eventRequestId: string - beforeEach(async () => { - const tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - const log = await getLog(tx, 3) - eventRequestId = log?.topics?.[1] - }) - - describe('success', () => { - let tx: ContractTransaction - beforeEach(async () => { - tx = await vrfCoordinator.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - }) - - it('emits a DiceLanded event', async () => { - const log = await getLog(tx, 0) - assert.equal(log?.topics[1], eventRequestId) - assert.equal(log?.topics[2], numToBytes32(expectedModResult)) - }) - - it('sets the correct dice roll result', async () => { - const response = await vrfD20.house(await personas.Nancy.getAddress()) - assert.equal(response.toString(), expectedHouse) - }) - - it('allows someone else to roll', async () => { - const secondRandomness = 55555 - tx = await vrfD20.rollDice(await personas.Ned.getAddress()) - const log = await getLog(tx, 3) - eventRequestId = log?.topics?.[1] - tx = await vrfCoordinator.callBackWithRandomness( - eventRequestId, - secondRandomness, - vrfD20.address, - ) - }) - }) - - describe('failure', () => { - it('does not fulfill when fulfilled by the wrong VRFcoordinator', async () => { - const vrfCoordinator2 = await vrfCoordinatorMockFactory - .connect(roles.defaultAccount) - .deploy(link.address) - - const tx = await vrfCoordinator2.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - }) -}) diff --git a/contracts/test/v0.7/gasUsage.test.ts b/contracts/test/v0.7/gasUsage.test.ts deleted file mode 100644 index 97146622d0..0000000000 --- a/contracts/test/v0.7/gasUsage.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { ethers } from 'hardhat' -import { toBytes32String, toWei } from '../test-helpers/helpers' -import { Contract, ContractFactory } from 'ethers' -import { getUsers, Roles } from '../test-helpers/setup' -import { - convertFufillParams, - convertFulfill2Params, - decodeRunRequest, -} from '../test-helpers/oracle' -import { gasDiffLessThan } from '../test-helpers/matchers' - -let operatorFactory: ContractFactory -let oracleFactory: ContractFactory -let basicConsumerFactory: ContractFactory -let linkTokenFactory: ContractFactory - -let roles: Roles - -before(async () => { - const users = await getUsers() - - roles = users.roles - operatorFactory = await ethers.getContractFactory( - 'src/v0.7/Operator.sol:Operator', - roles.defaultAccount, - ) - oracleFactory = await ethers.getContractFactory( - 'src/v0.6/Oracle.sol:Oracle', - roles.defaultAccount, - ) - basicConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/BasicConsumer.sol:BasicConsumer', - roles.defaultAccount, - ) - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) -}) - -describe('Operator Gas Tests [ @skip-coverage ]', () => { - const specId = - '0x4c7b7ffb66b344fbaa64995af81e355a00000000000000000000000000000000' - let link: Contract - let oracle1: Contract - let operator1: Contract - let operator2: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - - operator1 = await operatorFactory - .connect(roles.defaultAccount) - .deploy(link.address, await roles.defaultAccount.getAddress()) - await operator1.setAuthorizedSenders([await roles.oracleNode.getAddress()]) - - operator2 = await operatorFactory - .connect(roles.defaultAccount) - .deploy(link.address, await roles.defaultAccount.getAddress()) - await operator2.setAuthorizedSenders([await roles.oracleNode.getAddress()]) - - oracle1 = await oracleFactory - .connect(roles.defaultAccount) - .deploy(link.address) - await oracle1.setFulfillmentPermission( - await roles.oracleNode.getAddress(), - true, - ) - }) - - // Test Oracle.fulfillOracleRequest vs Operator.fulfillOracleRequest - describe('v0.6/Oracle vs v0.7/Operator #fulfillOracleRequest', () => { - const response = 'Hi Mom!' - let basicConsumer1: Contract - let basicConsumer2: Contract - - let request1: ReturnType - let request2: ReturnType - - beforeEach(async () => { - basicConsumer1 = await basicConsumerFactory - .connect(roles.consumer) - .deploy(link.address, oracle1.address, specId) - basicConsumer2 = await basicConsumerFactory - .connect(roles.consumer) - .deploy(link.address, operator1.address, specId) - - const paymentAmount = toWei('1') - const currency = 'USD' - - await link.transfer(basicConsumer1.address, paymentAmount) - const tx1 = await basicConsumer1.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt1 = await tx1.wait() - request1 = decodeRunRequest(receipt1.logs?.[3]) - - await link.transfer(basicConsumer2.address, paymentAmount) - const tx2 = await basicConsumer2.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt2 = await tx2.wait() - request2 = decodeRunRequest(receipt2.logs?.[3]) - }) - - it('uses acceptable gas', async () => { - const tx1 = await oracle1 - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request1, response)) - const tx2 = await operator1 - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request2, response)) - const receipt1 = await tx1.wait() - const receipt2 = await tx2.wait() - // 38014 vs 40260 - gasDiffLessThan(3900, receipt1, receipt2) - }) - }) - - // Test Operator1.fulfillOracleRequest vs Operator2.fulfillOracleRequest2 - // with single word response - describe('Operator #fulfillOracleRequest vs #fulfillOracleRequest2', () => { - const response = 'Hi Mom!' - let basicConsumer1: Contract - let basicConsumer2: Contract - - let request1: ReturnType - let request2: ReturnType - - beforeEach(async () => { - basicConsumer1 = await basicConsumerFactory - .connect(roles.consumer) - .deploy(link.address, operator1.address, specId) - basicConsumer2 = await basicConsumerFactory - .connect(roles.consumer) - .deploy(link.address, operator2.address, specId) - - const paymentAmount = toWei('1') - const currency = 'USD' - - await link.transfer(basicConsumer1.address, paymentAmount) - const tx1 = await basicConsumer1.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt1 = await tx1.wait() - request1 = decodeRunRequest(receipt1.logs?.[3]) - - await link.transfer(basicConsumer2.address, paymentAmount) - const tx2 = await basicConsumer2.requestEthereumPrice( - currency, - paymentAmount, - ) - const receipt2 = await tx2.wait() - request2 = decodeRunRequest(receipt2.logs?.[3]) - }) - - it('uses acceptable gas', async () => { - const tx1 = await operator1 - .connect(roles.oracleNode) - .fulfillOracleRequest(...convertFufillParams(request1, response)) - - const responseTypes = ['bytes32'] - const responseValues = [toBytes32String(response)] - const tx2 = await operator2 - .connect(roles.oracleNode) - .fulfillOracleRequest2( - ...convertFulfill2Params(request2, responseTypes, responseValues), - ) - - const receipt1 = await tx1.wait() - const receipt2 = await tx2.wait() - gasDiffLessThan(1240, receipt1, receipt2) - }) - }) -}) From b058357980ef75a06602fd26f19db4b0a1a286ce Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Mon, 13 Nov 2023 10:14:24 +0100 Subject: [PATCH 129/327] bump foundry (#11245) --- .github/workflows/solidity-foundry.yml | 2 +- contracts/GNUmakefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 7c9df79617..90d18ecac2 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -58,7 +58,7 @@ jobs: uses: foundry-rs/foundry-toolchain@v1 with: # Has to match the `make foundry` version. - version: nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b + version: nightly-09fe3e041369a816365a020f715ad6f94dbce9f2 - name: Run Forge build if: needs.changes.outputs.changes == 'true' diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index e41d6422c2..e880813867 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -38,7 +38,7 @@ mockery: $(mockery) ## Install mockery. .PHONY: foundry foundry: ## Install foundry. - foundryup --version nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b + foundryup --version nightly-09fe3e041369a816365a020f715ad6f94dbce9f2 .PHONY: foundry-refresh foundry-refresh: foundry From 35e146fcb61e9036b747bd32ee76cf0d039bd344 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Mon, 13 Nov 2023 14:54:48 +0100 Subject: [PATCH 130/327] Eth2 showcase with log poller (#11214) * move workflow to correct directory * streamline on-demand values a bit * get RPC urls and private keys from secrets * download and run from inside the test folder * checkout repo before running tests * get inputs and mask them * fix step ordering in workflow * fix default image tag * use latest pumba@CTF * run one test * fix directory name * run on powerful runner * show usage of ethereum env builder with eth2 * update usage of eth2 * adjust to latest --- integration-tests/docker/test_env/test_env.go | 46 +++++-- .../docker/test_env/test_env_builder.go | 68 +++++++--- .../docker/test_env/test_env_config.go | 10 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/smoke/automation_test.go | 4 +- integration-tests/smoke/log_poller_test.go | 128 +++++++++++++++++- .../universal/log_poller/helpers.go | 13 +- 8 files changed, 230 insertions(+), 45 deletions(-) diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index b3fc1c0cf6..4a30487211 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -40,15 +40,16 @@ type CLClusterTestEnv struct { LogWatch *logwatch.LogWatch /* components */ - ClCluster *ClCluster - Geth *test_env.Geth // for tests using --dev networks - PrivateChain []test_env.PrivateChain // for tests using non-dev networks - MockAdapter *test_env.Killgrave - EVMClient blockchain.EVMClient - ContractDeployer contracts.ContractDeployer - ContractLoader contracts.ContractLoader - l zerolog.Logger - t *testing.T + ClCluster *ClCluster + PrivateChain []test_env.PrivateChain // for tests using non-dev networks -- unify it with new approach + MockAdapter *test_env.Killgrave + EVMClient blockchain.EVMClient + ContractDeployer contracts.ContractDeployer + ContractLoader contracts.ContractLoader + RpcProvider test_env.RpcProvider + PrivateEthereumConfig *test_env.EthereumNetwork // new approach to private chains, supporting eth1 and eth2 + l zerolog.Logger + t *testing.T } func NewTestEnv() (*CLClusterTestEnv, error) { @@ -59,7 +60,6 @@ func NewTestEnv() (*CLClusterTestEnv, error) { } n := []string{network.Name} return &CLClusterTestEnv{ - Geth: test_env.NewGeth(n), MockAdapter: test_env.NewKillgrave(n, ""), Network: network, l: log.Logger, @@ -67,11 +67,10 @@ func NewTestEnv() (*CLClusterTestEnv, error) { } // WithTestEnvConfig sets the test environment cfg. -// Sets up the Geth and MockAdapter containers with the provided cfg. +// Sets up private ethereum chain and MockAdapter containers with the provided cfg. func (te *CLClusterTestEnv) WithTestEnvConfig(cfg *TestEnvConfig) *CLClusterTestEnv { te.Cfg = cfg n := []string{te.Network.Name} - te.Geth = test_env.NewGeth(n, test_env.WithContainerName(te.Cfg.Geth.ContainerName)) te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName)) return te } @@ -79,7 +78,6 @@ func (te *CLClusterTestEnv) WithTestEnvConfig(cfg *TestEnvConfig) *CLClusterTest func (te *CLClusterTestEnv) WithTestLogger(t *testing.T) *CLClusterTestEnv { te.t = t te.l = logging.GetTestLogger(t) - te.Geth.WithTestLogger(t) te.MockAdapter.WithTestLogger(t) return te } @@ -128,8 +126,26 @@ func (te *CLClusterTestEnv) StartPrivateChain() error { return nil } -func (te *CLClusterTestEnv) StartGeth() (blockchain.EVMNetwork, test_env.InternalDockerUrls, error) { - return te.Geth.StartContainer() +func (te *CLClusterTestEnv) StartEthereumNetwork(cfg *test_env.EthereumNetwork) (blockchain.EVMNetwork, test_env.RpcProvider, error) { + // if environment is being restored from a previous state, use the existing config + // this might fail terribly if temporary folders with chain data on the host machine were removed + if te.Cfg != nil && te.Cfg.EthereumNetwork != nil { + builder := test_env.NewEthereumNetworkBuilder() + c, err := builder.WithExistingConfig(*te.Cfg.EthereumNetwork). + WithTest(te.t). + Build() + if err != nil { + return blockchain.EVMNetwork{}, test_env.RpcProvider{}, err + } + cfg = &c + } + n, rpc, err := cfg.Start() + + if err != nil { + return blockchain.EVMNetwork{}, test_env.RpcProvider{}, err + } + + return n, rpc, nil } func (te *CLClusterTestEnv) StartMockAdapter() error { diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 9f64ab64c9..e97f869d64 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -31,8 +31,8 @@ const ( ) type CLTestEnvBuilder struct { - hasLogWatch bool - hasGeth bool + hasLogWatch bool + // hasGeth bool hasKillgrave bool hasForwarders bool clNodeConfig *chainlink.Config @@ -49,6 +49,7 @@ type CLTestEnvBuilder struct { cleanUpCustomFn func() chainOptionsFn []ChainOption evmClientNetworkOption []EVMClientNetworkOption + ethereumNetwork *test_env.EthereumNetwork /* funding */ ETHFunds *big.Float @@ -118,8 +119,27 @@ func (b *CLTestEnvBuilder) WithFunding(eth *big.Float) *CLTestEnvBuilder { return b } +// deprecated +// left only for backward compatibility func (b *CLTestEnvBuilder) WithGeth() *CLTestEnvBuilder { - b.hasGeth = true + ethBuilder := test_env.NewEthereumNetworkBuilder() + cfg, err := ethBuilder. + WithConsensusType(test_env.ConsensusType_PoW). + WithExecutionLayer(test_env.ExecutionLayer_Geth). + WithTest(b.t). + Build() + + if err != nil { + panic(err) + } + + b.ethereumNetwork = &cfg + + return b +} + +func (b *CLTestEnvBuilder) WithPrivateEthereumNetwork(en test_env.EthereumNetwork) *CLTestEnvBuilder { + b.ethereumNetwork = &en return b } @@ -191,13 +211,6 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, err } } - b.l.Info(). - Bool("hasGeth", b.hasGeth). - Bool("hasKillgrave", b.hasKillgrave). - Int("clNodesCount", b.clNodesCount). - Strs("customNodeCsaKeys", b.customNodeCsaKeys). - Strs("defaultNodeCsaKeys", b.defaultNodeCsaKeys). - Msg("Building CL cluster test environment..") var err error if b.t != nil { @@ -259,13 +272,21 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } return b.te, nil } + networkConfig := networks.MustGetSelectedNetworksFromEnv()[0] - var internalDockerUrls test_env.InternalDockerUrls - if b.hasGeth && networkConfig.Simulated { - networkConfig, internalDockerUrls, err = b.te.StartGeth() + var rpcProvider test_env.RpcProvider + if b.ethereumNetwork != nil && networkConfig.Simulated { + // TODO here we should save the ethereum network config to te.Cfg, but it doesn't exist at this point + // in general it seems we have no methods for saving config to file and we only load it from file + // but I don't know how that config file is to be created or whether anyone ever done that + var enCfg test_env.EthereumNetwork + b.ethereumNetwork.DockerNetworkNames = []string{b.te.Network.Name} + networkConfig, rpcProvider, err = b.te.StartEthereumNetwork(b.ethereumNetwork) if err != nil { return nil, err } + b.te.RpcProvider = rpcProvider + b.te.PrivateEthereumConfig = &enCfg } if !b.isNonEVM { @@ -311,8 +332,8 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { var httpUrls []string var wsUrls []string if networkConfig.Simulated { - httpUrls = []string{internalDockerUrls.HttpUrl} - wsUrls = []string{internalDockerUrls.WsUrl} + httpUrls = rpcProvider.PrivateHttpUrls() + wsUrls = rpcProvider.PrivateWsUrsl() } else { httpUrls = networkConfig.HTTPURLs wsUrls = networkConfig.URLs @@ -341,7 +362,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { b.defaultNodeCsaKeys = nodeCsaKeys } - if b.hasGeth && b.clNodesCount > 0 && b.ETHFunds != nil { + if b.ethereumNetwork != nil && b.clNodesCount > 0 && b.ETHFunds != nil { b.te.ParallelTransactions(true) defer b.te.ParallelTransactions(false) if err := b.te.FundChainlinkNodes(b.ETHFunds); err != nil { @@ -349,5 +370,20 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } + var enDesc string + if b.te.PrivateEthereumConfig != nil { + enDesc = b.te.PrivateEthereumConfig.Describe() + } else { + enDesc = "none" + } + + b.l.Info(). + Str("privateEthereumNetwork", enDesc). + Bool("hasKillgrave", b.hasKillgrave). + Int("clNodesCount", b.clNodesCount). + Strs("customNodeCsaKeys", b.customNodeCsaKeys). + Strs("defaultNodeCsaKeys", b.defaultNodeCsaKeys). + Msg("Building CL cluster test environment..") + return b.te, nil } diff --git a/integration-tests/docker/test_env/test_env_config.go b/integration-tests/docker/test_env/test_env_config.go index 1a0c8d5c86..0902deb0c2 100644 --- a/integration-tests/docker/test_env/test_env_config.go +++ b/integration-tests/docker/test_env/test_env_config.go @@ -3,14 +3,16 @@ package test_env import ( "encoding/json" + cte "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" env "github.com/smartcontractkit/chainlink/integration-tests/types/envcommon" ) type TestEnvConfig struct { - Networks []string `json:"networks"` - Geth GethConfig `json:"geth"` - MockAdapter MockAdapterConfig `json:"mock_adapter"` - ClCluster *ClCluster `json:"clCluster"` + Networks []string `json:"networks"` + Geth GethConfig `json:"geth"` + MockAdapter MockAdapterConfig `json:"mock_adapter"` + ClCluster *ClCluster `json:"clCluster"` + EthereumNetwork *cte.EthereumNetwork `json:"private_ethereum_config"` } type MockAdapterConfig struct { diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 83657baa01..6a7e7195ff 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,7 +22,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-testing-framework v1.18.5 + github.com/smartcontractkit/chainlink-testing-framework v1.18.6 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index a873f9b7c1..780e81c7ef 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2375,8 +2375,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.5 h1:R0f13AUbon1ltHE/vudkyUnLRGaoeocIDVv+FsHZjno= -github.com/smartcontractkit/chainlink-testing-framework v1.18.5/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-testing-framework v1.18.6 h1:UL3DxsPflSRALP62rsg5v3NdOsa8RHGhHMUImoWDD6k= +github.com/smartcontractkit/chainlink-testing-framework v1.18.6/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 9e35b24df1..4f969c5d68 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -1070,8 +1070,8 @@ func setupAutomationTestDocker( var httpUrls []string var wsUrls []string if network.Simulated { - httpUrls = []string{env.Geth.InternalHttpUrl} - wsUrls = []string{env.Geth.InternalWsUrl} + httpUrls = []string{env.RpcProvider.PrivateHttpUrls()[0]} + wsUrls = []string{env.RpcProvider.PrivateWsUrsl()[0]} } else { httpUrls = network.HTTPURLs wsUrls = network.URLs diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index 0df7817f1e..36ee2164c4 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -9,7 +9,7 @@ import ( // consistency test with no network disruptions with approximate emission of 1500-1600 logs per second for ~110-120 seconds // 6 filters are registered -func TestLogPollerFewFilters(t *testing.T) { +func TestLogPollerFewFiltersFixedDepth(t *testing.T) { cfg := logpoller.Config{ General: &logpoller.General{ Generator: logpoller.GeneratorType_Looped, @@ -38,9 +38,38 @@ func TestLogPollerFewFilters(t *testing.T) { logpoller.ExecuteBasicLogPollerTest(t, &cfg) } +func TestLogPollerFewFiltersFinalityTag(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 4, + UseFinalityTag: true, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + + logpoller.ExecuteBasicLogPollerTest(t, &cfg) +} + // consistency test with no network disruptions with approximate emission of 1000-1100 logs per second for ~110-120 seconds // 900 filters are registered -func TestLogManyFiltersPoller(t *testing.T) { +func TestLogManyFiltersPollerFixedDepth(t *testing.T) { cfg := logpoller.Config{ General: &logpoller.General{ Generator: logpoller.GeneratorType_Looped, @@ -69,10 +98,39 @@ func TestLogManyFiltersPoller(t *testing.T) { logpoller.ExecuteBasicLogPollerTest(t, &cfg) } +func TestLogManyFiltersPollerFinalityTag(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 300, + EventsPerTx: 3, + UseFinalityTag: true, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 30, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + + logpoller.ExecuteBasicLogPollerTest(t, &cfg) +} + // consistency test that introduces random distruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds // with approximate emission of 520-550 logs per second for ~110 seconds // 6 filters are registered -func TestLogPollerWithChaos(t *testing.T) { +func TestLogPollerWithChaosFixedDepth(t *testing.T) { cfg := logpoller.Config{ General: &logpoller.General{ Generator: logpoller.GeneratorType_Looped, @@ -104,12 +162,74 @@ func TestLogPollerWithChaos(t *testing.T) { logpoller.ExecuteBasicLogPollerTest(t, &cfg) } +func TestLogPollerWithChaosFinalityTag(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 100, + UseFinalityTag: true, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + ChaosConfig: &logpoller.ChaosConfig{ + ExperimentCount: 10, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + + logpoller.ExecuteBasicLogPollerTest(t, &cfg) +} + // consistency test that registers filters after events were emitted and then triggers replay via API // unfortunately there is no way to make sure that logs that are indexed are only picked up by replay // and not by backup poller // with approximate emission of 24 logs per second for ~110 seconds // 6 filters are registered -func TestLogPollerReplay(t *testing.T) { +func TestLogPollerReplayFixedDepth(t *testing.T) { + cfg := logpoller.Config{ + General: &logpoller.General{ + Generator: logpoller.GeneratorType_Looped, + Contracts: 2, + EventsPerTx: 4, + UseFinalityTag: false, + }, + LoopedConfig: &logpoller.LoopedConfig{ + ContractConfig: logpoller.ContractConfig{ + ExecutionCount: 100, + }, + FuzzConfig: logpoller.FuzzConfig{ + MinEmitWaitTimeMs: 200, + MaxEmitWaitTimeMs: 500, + }, + }, + } + + eventsToEmit := []abi.Event{} + for _, event := range logpoller.EmitterABI.Events { + eventsToEmit = append(eventsToEmit, event) + } + + cfg.General.EventsToEmit = eventsToEmit + consistencyTimeout := "5m" + + logpoller.ExecuteLogPollerReplay(t, &cfg, consistencyTimeout) +} + +func TestLogPollerReplayFinalityTag(t *testing.T) { cfg := logpoller.Config{ General: &logpoller.General{ Generator: logpoller.GeneratorType_Looped, diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index ab7a221955..9f88827bb4 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -1068,9 +1068,20 @@ func setupLogPollerTestDocker( return network } + ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() + cfg, err := ethBuilder. + WithConsensusType(ctf_test_env.ConsensusType_PoS). + WithConsensusLayer(ctf_test_env.ConsensusLayer_Prysm). + WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). + WithBeaconChainConfig(ctf_test_env.BeaconChainConfig{ + SecondsPerSlot: 8, + SlotsPerEpoch: 2, + }). + Build() + env, err = test_env.NewCLTestEnvBuilder(). WithTestLogger(t). - WithGeth(). + WithPrivateEthereumNetwork(cfg). WithCLNodes(clNodesCount). WithCLNodeConfig(clNodeConfig). WithFunding(big.NewFloat(chainlinkNodeFunding)). From de5027383ba3120554e8dc88b5b178973585159b Mon Sep 17 00:00:00 2001 From: ferglor <19188060+ferglor@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:04:10 +0000 Subject: [PATCH 131/327] Always wait for doCheck to complete before returning (#10878) * Always wait for doCheck to complete before returning Use threadctrl to avail of context cancellation but still rely on a wait group to blocl until the lookups finish Update tests * Revert async streamsLookup to fix test * Rearrange thread control as a test * Copy index * WIP --- .../ocr2keeper/evm21/registry_check_pipeline.go | 5 ++++- .../plugins/ocr2keeper/evm21/streams_lookup.go | 16 +++++++++++++--- .../ocr2keeper/evm21/streams_lookup_test.go | 15 ++++++++++++++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go index d353099470..c9752ea14d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go @@ -41,7 +41,10 @@ func (r *EvmRegistry) CheckUpkeeps(ctx context.Context, keys ...ocr2keepers.Upke } chResult := make(chan checkResult, 1) - go r.doCheck(ctx, keys, chResult) + + r.threadCtrl.Go(func(ctx context.Context) { + r.doCheck(ctx, keys, chResult) + }) select { case rs := <-chResult: diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go index 660550afe9..fb2821a74b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go @@ -149,10 +149,15 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep } var wg sync.WaitGroup + for i, lookup := range lookups { + i := i wg.Add(1) - go r.doLookup(ctx, &wg, lookup, i, checkResults, lggr) + r.threadCtrl.Go(func(ctx context.Context) { + r.doLookup(ctx, &wg, lookup, i, checkResults, lggr) + }) } + wg.Wait() // don't surface error to plugin bc StreamsLookup process should be self-contained. @@ -289,14 +294,19 @@ func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, p if sl.FeedParamKey == feedIdHex && sl.TimeParamKey == blockNumber { // only mercury v0.2 for i := range sl.Feeds { - go r.singleFeedRequest(ctx, ch, i, sl, lggr) + i := i + r.threadCtrl.Go(func(ctx context.Context) { + r.singleFeedRequest(ctx, ch, i, sl, lggr) + }) } } else if sl.FeedParamKey == feedIDs { // only mercury v0.3 resultLen = 1 isMercuryV03 = true ch = make(chan MercuryData, resultLen) - go r.multiFeedsRequest(ctx, ch, sl, lggr) + r.threadCtrl.Go(func(ctx context.Context) { + r.multiFeedsRequest(ctx, ch, sl, lggr) + }) } else { return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go index 8d7c67d80c..145d701454 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" + "github.com/smartcontractkit/chainlink/v2/core/utils" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -70,7 +71,8 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { allowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), }, - hc: mockHttpClient, + hc: mockHttpClient, + threadCtrl: utils.NewThreadControl(), } return r } @@ -220,6 +222,7 @@ func TestEvmRegistry_StreamsLookup(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + defer r.Close() client := new(evmClientMocks.Client) r.client = client @@ -362,6 +365,7 @@ func TestEvmRegistry_AllowedToUseMercury(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + defer r.Close() client := new(evmClientMocks.Client) r.client = client @@ -576,9 +580,12 @@ func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + defer r.Close() + if tt.pluginRetries != 0 { r.mercury.pluginRetryCache.Set(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) } + hc := mocks.NewHttpClient(t) for _, blob := range tt.mockChainlinkBlobs { @@ -812,6 +819,8 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + defer r.Close() + hc := mocks.NewHttpClient(t) mr := MercuryV02Response{ChainlinkBlob: tt.blob} @@ -1157,6 +1166,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + defer r.Close() + if tt.pluginRetries != 0 { r.mercury.pluginRetryCache.Set(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) } @@ -1319,6 +1330,8 @@ func TestEvmRegistry_CheckCallback(t *testing.T) { t.Run(tt.name, func(t *testing.T) { client := new(evmClientMocks.Client) r := setupEVMRegistry(t) + defer r.Close() + payload, err := r.abi.Pack("checkCallback", tt.lookup.upkeepId, values, tt.lookup.ExtraData) require.Nil(t, err) args := map[string]interface{}{ From 12062831ae01b21c6ea6bc052107ecbe254da6c4 Mon Sep 17 00:00:00 2001 From: Bruno Moura Date: Mon, 13 Nov 2023 15:04:39 +0000 Subject: [PATCH 132/327] Remove Mercury plugin dependency on raw evm chain. (#11201) * mercury: remove dead code * mercury: Add ChainReader * mercury: services init * fix sqlx import * mercury: error handling * mod tidy * mercury: log error from reader * mercury: ensure a failed observation when reading from chain return an error * mercury: add test for setLatestBlocks error * make a happy linter * Update core/services/relay/evm/mercury_provider.go Co-authored-by: Sam --------- Co-authored-by: Sam --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/ocr2/delegate.go | 6 +- core/services/ocr2/plugins/mercury/plugin.go | 3 +- core/services/relay/evm/evm.go | 5 +- .../evm/mercury/mocks/chain_head_tracker.go | 47 ------------- .../services/relay/evm/mercury/types/types.go | 6 -- .../relay/evm/mercury/v1/data_source.go | 53 +++++++------- .../relay/evm/mercury/v1/data_source_test.go | 70 +++++++++---------- core/services/relay/evm/mercury_provider.go | 38 ++++++++++ go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 14 files changed, 113 insertions(+), 133 deletions(-) delete mode 100644 core/services/relay/evm/mercury/mocks/chain_head_tracker.go diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 5f881f354e..bb68175ddf 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.20231108205920-694ce17a4a78 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742 // 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 1d455305a9..bd3b75d37a 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.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-relay v0.1.7-0.20231108215906-8bbaf383b742 h1:28XkPE6YfJ4uabTX9/7sueRV6IKtY4hcm1nIt1e6b20= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742/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/ocr2/delegate.go b/core/services/ocr2/delegate.go index 95ec146915..19296c72f0 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -653,10 +653,6 @@ func (d *Delegate) newServicesMercury( if err != nil { return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: "mercury"} } - chain, err := d.legacyChains.Get(rid.ChainID) - if err != nil { - return nil, fmt.Errorf("mercury services: failed to get chain %s: %w", rid.ChainID, err) - } provider, err2 := relayer.NewPluginProvider(ctx, types.RelayArgs{ @@ -695,7 +691,7 @@ func (d *Delegate) newServicesMercury( chEnhancedTelem := make(chan ocrcommon.EnhancedTelemetryMercuryData, 100) - mercuryServices, err2 := mercury.NewServices(jb, mercuryProvider, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, d.cfg.JobPipeline(), chEnhancedTelem, chain, d.mercuryORM, (mercuryutils.FeedID)(*spec.FeedID)) + mercuryServices, err2 := mercury.NewServices(jb, mercuryProvider, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, d.cfg.JobPipeline(), chEnhancedTelem, d.mercuryORM, (mercuryutils.FeedID)(*spec.FeedID)) if ocrcommon.ShouldCollectEnhancedTelemetryMercury(jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.FeedID.String(), synchronization.EnhancedEAMercury), lggr.Named("EnhancedTelemetryMercury")) diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index 69a3b53c28..ddef1374a4 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -37,7 +37,6 @@ func NewServices( argsNoPlugin libocr2.MercuryOracleArgs, cfg Config, chEnhancedTelem chan ocrcommon.EnhancedTelemetryMercuryData, - chainHeadTracker types.ChainHeadTracker, orm types.DataSourceORM, feedID utils.FeedID, ) ([]job.ServiceCtx, error) { @@ -66,7 +65,7 @@ func NewServices( lggr, runResults, chEnhancedTelem, - chainHeadTracker, + ocr2Provider.ChainReader(), ocr2Provider.MercuryServerFetcher(), pluginConfig.InitialBlockNumber.Ptr(), feedID, diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 111e3622b1..aa1d1d774b 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -10,10 +10,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" pkgerrors "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median/evmreportcodec" @@ -189,7 +189,8 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype } transmitter := mercury.NewTransmitter(lggr, cw.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) - return NewMercuryProvider(cw, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, lggr), nil + chainReader := NewChainReader(r.chain.HeadTracker()) + return NewMercuryProvider(cw, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, chainReader, lggr), nil } func (r *Relayer) NewFunctionsProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (relaytypes.FunctionsProvider, error) { diff --git a/core/services/relay/evm/mercury/mocks/chain_head_tracker.go b/core/services/relay/evm/mercury/mocks/chain_head_tracker.go deleted file mode 100644 index b6f2981cf0..0000000000 --- a/core/services/relay/evm/mercury/mocks/chain_head_tracker.go +++ /dev/null @@ -1,47 +0,0 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. - -package mocks - -import ( - common "github.com/ethereum/go-ethereum/common" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - - mock "github.com/stretchr/testify/mock" - - types "github.com/smartcontractkit/chainlink/v2/common/types" -) - -// ChainHeadTracker is an autogenerated mock type for the ChainHeadTracker type -type ChainHeadTracker struct { - mock.Mock -} - -// HeadTracker provides a mock function with given fields: -func (_m *ChainHeadTracker) HeadTracker() types.HeadTracker[*evmtypes.Head, common.Hash] { - ret := _m.Called() - - var r0 types.HeadTracker[*evmtypes.Head, common.Hash] - if rf, ok := ret.Get(0).(func() types.HeadTracker[*evmtypes.Head, common.Hash]); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.HeadTracker[*evmtypes.Head, common.Hash]) - } - } - - return r0 -} - -// NewChainHeadTracker creates a new instance of ChainHeadTracker. 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 NewChainHeadTracker(t interface { - mock.TestingT - Cleanup(func()) -}) *ChainHeadTracker { - mock := &ChainHeadTracker{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/relay/evm/mercury/types/types.go b/core/services/relay/evm/mercury/types/types.go index 7059689939..49bffb6c29 100644 --- a/core/services/relay/evm/mercury/types/types.go +++ b/core/services/relay/evm/mercury/types/types.go @@ -8,15 +8,9 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) -//go:generate mockery --quiet --name ChainHeadTracker --output ../mocks/ --case=underscore -type ChainHeadTracker interface { - HeadTracker() httypes.HeadTracker -} - type DataSourceORM interface { LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg.QOpt) (report []byte, err error) } diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index 0f8f56f46e..0bdfb67de7 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -16,7 +16,6 @@ import ( relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" @@ -67,7 +66,7 @@ type datasource struct { mu sync.RWMutex chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData - chainHeadTracker types.ChainHeadTracker + chainReader relaymercury.ChainReader fetcher Fetcher initialBlockNumber *int64 @@ -77,8 +76,8 @@ type datasource struct { var _ relaymercuryv1.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, rr chan *pipeline.Run, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainHeadTracker types.ChainHeadTracker, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { - return &datasource{pr, jb, spec, lggr, rr, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainHeadTracker, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, rr chan *pipeline.Run, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainReader relaymercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { + return &datasource{pr, jb, spec, lggr, rr, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} } type ErrEmptyLatestReport struct { @@ -94,7 +93,11 @@ func (e ErrEmptyLatestReport) Error() string { func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs relaymercuryv1.Observation, pipelineExecutionErr error) { // setLatestBlocks must come chronologically before observations, along // with observationTimestamp, to avoid front-running - ds.setLatestBlocks(ctx, &obs) + + // Errors are not expected when reading from the underlying ChainReader + if err := ds.setLatestBlocks(ctx, &obs); err != nil { + return obs, err + } var wg sync.WaitGroup if fetchMaxFinalizedBlockNum { @@ -290,8 +293,13 @@ func (ds *datasource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.T return run, trrs, err } -func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.Observation) { - latestBlocks := ds.getLatestBlocks(ctx, nBlocksObservation) +func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.Observation) error { + latestBlocks, err := ds.chainReader.LatestHeads(ctx, nBlocksObservation) + if err != nil { + ds.lggr.Errorw("failed to read latest blocks", "error", err) + return err + } + if len(latestBlocks) < nBlocksObservation { ds.insufficientBlocksCounter.Inc() ds.lggr.Warnw("Insufficient blocks", "latestBlocks", latestBlocks, "lenLatestBlocks", len(latestBlocks), "nBlocksObservation", nBlocksObservation) @@ -299,31 +307,22 @@ func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.O // TODO: remove with https://smartcontract-it.atlassian.net/browse/BCF-2209 if len(latestBlocks) == 0 { + obsErr := fmt.Errorf("no blocks available") ds.zeroBlocksCounter.Inc() - err := errors.New("no blocks available") - obs.CurrentBlockNum.Err = err - obs.CurrentBlockHash.Err = err - obs.CurrentBlockTimestamp.Err = err + obs.CurrentBlockNum.Err = obsErr + obs.CurrentBlockHash.Err = obsErr + obs.CurrentBlockTimestamp.Err = obsErr } else { - obs.CurrentBlockNum.Val = latestBlocks[0].Number - obs.CurrentBlockHash.Val = latestBlocks[0].Hash.Bytes() - if latestBlocks[0].Timestamp.IsZero() { - obs.CurrentBlockTimestamp.Val = 0 - } else { - obs.CurrentBlockTimestamp.Val = uint64(latestBlocks[0].Timestamp.Unix()) - } + obs.CurrentBlockNum.Val = int64(latestBlocks[0].Number) + obs.CurrentBlockHash.Val = latestBlocks[0].Hash + obs.CurrentBlockTimestamp.Val = latestBlocks[0].Timestamp } for _, block := range latestBlocks { - obs.LatestBlocks = append(obs.LatestBlocks, relaymercuryv1.NewBlock(block.Number, block.Hash.Bytes(), uint64(block.Timestamp.Unix()))) + obs.LatestBlocks = append( + obs.LatestBlocks, + relaymercuryv1.NewBlock(int64(block.Number), block.Hash, block.Timestamp)) } -} -func (ds *datasource) getLatestBlocks(ctx context.Context, k int) (blocks []*evmtypes.Head) { - // Use the headtracker's view of the chain, this is very fast since - // it doesn't make any external network requests, and it is the - // headtracker's job to ensure it has an up-to-date view of the chain based - // on responses from all available RPC nodes - latestHead := ds.chainHeadTracker.HeadTracker().LatestChain() - return latestHead.AsSlice(k) + return nil } diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 42983fa002..40542c2631 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -3,6 +3,7 @@ package mercury_v1 import ( "context" "fmt" + "io" "math/big" "math/rand" "testing" @@ -18,7 +19,6 @@ import ( relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/assets" - httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -26,8 +26,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" mercurymocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -52,14 +52,6 @@ func (m *mockFetcher) LatestTimestamp(context.Context) (int64, error) { return 0, nil } -var _ types.ChainHeadTracker = &mockHeadTracker{} - -type mockHeadTracker struct { - h httypes.HeadTracker -} - -func (m *mockHeadTracker) HeadTracker() httypes.HeadTracker { return m.h } - type mockORM struct { report []byte err error @@ -69,6 +61,15 @@ func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg return m.report, m.err } +type mockChainReader struct { + err error + obs []relaymercury.Head +} + +func (m *mockChainReader) LatestHeads(context.Context, int) ([]relaymercury.Head, error) { + return m.obs, m.err +} + func TestMercury_Observe(t *testing.T) { orm := &mockORM{} lggr := logger.TestLogger(t) @@ -106,10 +107,7 @@ func TestMercury_Observe(t *testing.T) { ds.spec = spec h := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - ht := &mockHeadTracker{ - h: h, - } - ds.chainHeadTracker = ht + ds.chainReader = evm.NewChainReader(h) head := &evmtypes.Head{ Number: int64(rand.Int31()), @@ -201,7 +199,7 @@ func TestMercury_Observe(t *testing.T) { t.Run("if no current block available", func(t *testing.T) { h2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) h2.On("LatestChain").Return((*evmtypes.Head)(nil)) - ht.h = h2 + ds.chainReader = evm.NewChainReader(h2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -212,7 +210,7 @@ func TestMercury_Observe(t *testing.T) { }) }) - ht.h = h + ds.chainReader = evm.NewChainReader(h) t.Run("when fetchMaxFinalizedBlockNum=false", func(t *testing.T) { t.Run("when run execution fails, returns error", func(t *testing.T) { @@ -320,7 +318,7 @@ func TestMercury_Observe(t *testing.T) { t.Run("when chain length is zero", func(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return((*evmtypes.Head)(nil)) - ht.h = ht2 + ds.chainReader = evm.NewChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -345,7 +343,7 @@ func TestMercury_Observe(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(h6) - ht.h = ht2 + ds.chainReader = evm.NewChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -384,7 +382,7 @@ func TestMercury_Observe(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(h6) - ht.h = ht2 + ds.chainReader = evm.NewChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -398,6 +396,18 @@ func TestMercury_Observe(t *testing.T) { ht2.AssertExpectations(t) }) + + t.Run("when chain reader returns an error", func(t *testing.T) { + + ds.chainReader = &mockChainReader{ + err: io.EOF, + obs: nil, + } + + obs, err := ds.Observe(ctx, repts, true) + assert.Error(t, err) + assert.Equal(t, obs, relaymercuryv1.Observation{}) + }) }) } @@ -418,39 +428,31 @@ func TestMercury_SetLatestBlocks(t *testing.T) { t.Run("returns head from headtracker if present", func(t *testing.T) { headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - chainHeadTracker := mercurymocks.NewChainHeadTracker(t) - - chainHeadTracker.On("HeadTracker").Return(headTracker) headTracker.On("LatestChain").Return(&h, nil) - - ds.chainHeadTracker = chainHeadTracker + ds.chainReader = evm.NewChainReader(headTracker) obs := relaymercuryv1.Observation{} - ds.setLatestBlocks(context.Background(), &obs) + err := ds.setLatestBlocks(context.Background(), &obs) + assert.NoError(t, err) assert.Equal(t, h.Number, obs.CurrentBlockNum.Val) assert.Equal(t, h.Hash.Bytes(), obs.CurrentBlockHash.Val) assert.Equal(t, uint64(h.Timestamp.Unix()), obs.CurrentBlockTimestamp.Val) assert.Len(t, obs.LatestBlocks, 1) - - chainHeadTracker.AssertExpectations(t) headTracker.AssertExpectations(t) }) t.Run("if headtracker returns nil head", func(t *testing.T) { headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - chainHeadTracker := mercurymocks.NewChainHeadTracker(t) - - chainHeadTracker.On("HeadTracker").Return(headTracker) // This can happen in some cases e.g. RPC node is offline headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) - ds.chainHeadTracker = chainHeadTracker - + ds.chainReader = evm.NewChainReader(headTracker) obs := relaymercuryv1.Observation{} - ds.setLatestBlocks(context.Background(), &obs) + err := ds.setLatestBlocks(context.Background(), &obs) + assert.NoError(t, err) assert.Zero(t, obs.CurrentBlockNum.Val) assert.Zero(t, obs.CurrentBlockHash.Val) assert.Zero(t, obs.CurrentBlockTimestamp.Val) @@ -459,8 +461,6 @@ func TestMercury_SetLatestBlocks(t *testing.T) { assert.EqualError(t, obs.CurrentBlockTimestamp.Err, "no blocks available") assert.Len(t, obs.LatestBlocks, 0) - - chainHeadTracker.AssertExpectations(t) headTracker.AssertExpectations(t) }) } diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index 914401c089..bba5e699bc 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -12,6 +12,7 @@ import ( relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink-relay/pkg/services" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" @@ -25,6 +26,7 @@ type mercuryProvider struct { reportCodecV1 relaymercuryv1.ReportCodec reportCodecV2 relaymercuryv2.ReportCodec reportCodecV3 relaymercuryv3.ReportCodec + chainReader relaymercury.ChainReader logger logger.Logger ms services.MultiStart @@ -36,6 +38,7 @@ func NewMercuryProvider( reportCodecV1 relaymercuryv1.ReportCodec, reportCodecV2 relaymercuryv2.ReportCodec, reportCodecV3 relaymercuryv3.ReportCodec, + chainReader relaymercury.ChainReader, lggr logger.Logger, ) *mercuryProvider { return &mercuryProvider{ @@ -44,6 +47,7 @@ func NewMercuryProvider( reportCodecV1, reportCodecV2, reportCodecV3, + chainReader, lggr, services.MultiStart{}, } @@ -103,3 +107,37 @@ func (p *mercuryProvider) ContractTransmitter() ocrtypes.ContractTransmitter { func (p *mercuryProvider) MercuryServerFetcher() relaymercury.MercuryServerFetcher { return p.transmitter } + +func (p *mercuryProvider) ChainReader() relaymercury.ChainReader { + return p.chainReader +} + +var _ relaymercury.ChainReader = (*chainReader)(nil) + +type chainReader struct { + tracker httypes.HeadTracker +} + +func NewChainReader(h httypes.HeadTracker) relaymercury.ChainReader { + return &chainReader{ + tracker: h, + } +} + +func (r *chainReader) LatestHeads(ctx context.Context, k int) ([]relaymercury.Head, error) { + evmBlocks := r.tracker.LatestChain().AsSlice(k) + if len(evmBlocks) == 0 { + return nil, nil + } + + blocks := make([]relaymercury.Head, len(evmBlocks)) + for x := 0; x < len(evmBlocks); x++ { + blocks[x] = relaymercury.Head{ + Number: uint64(evmBlocks[x].BlockNumber()), + Hash: evmBlocks[x].Hash.Bytes(), + Timestamp: uint64(evmBlocks[x].Timestamp.Unix()), + } + } + + return blocks, nil +} diff --git a/go.mod b/go.mod index f35077e923..8a4d58469c 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.20231108205920-694ce17a4a78 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742 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 2c9d9e5371..1b96c936c5 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.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-relay v0.1.7-0.20231108215906-8bbaf383b742 h1:28XkPE6YfJ4uabTX9/7sueRV6IKtY4hcm1nIt1e6b20= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742/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 6a7e7195ff..b5455838b5 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.20231108205920-694ce17a4a78 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742 // 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 780e81c7ef..fc486e5451 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.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-relay v0.1.7-0.20231108215906-8bbaf383b742 h1:28XkPE6YfJ4uabTX9/7sueRV6IKtY4hcm1nIt1e6b20= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742/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= From 94625ef958b02c3eb759dd10d897b1d9bfc2fe5c Mon Sep 17 00:00:00 2001 From: ferglor <19188060+ferglor@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:25:50 +0000 Subject: [PATCH 133/327] Add a csv flag to the verifiable load subcommand (#10833) --- .../command/keeper/verifiable_load.go | 12 +++++++- .../handler/keeper_verifiable_load.go | 30 +++++++++++++++---- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/core/scripts/chaincli/command/keeper/verifiable_load.go b/core/scripts/chaincli/command/keeper/verifiable_load.go index 7d77f0d3a3..33acf9bf3b 100644 --- a/core/scripts/chaincli/command/keeper/verifiable_load.go +++ b/core/scripts/chaincli/command/keeper/verifiable_load.go @@ -1,6 +1,8 @@ package keeper import ( + "log" + "github.com/spf13/cobra" "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" @@ -15,6 +17,14 @@ var verifiableLoad = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { cfg := config.New() hdlr := handler.NewKeeper(cfg) - hdlr.GetVerifiableLoadStats(cmd.Context()) + csv, err := cmd.Flags().GetBool("csv") + if err != nil { + log.Fatal("failed to get verify flag: ", err) + } + hdlr.GetVerifiableLoadStats(cmd.Context(), csv) }, } + +func init() { + verifiableLoad.Flags().BoolP("csv", "c", false, "Specify if stats should be output as CSV") +} diff --git a/core/scripts/chaincli/handler/keeper_verifiable_load.go b/core/scripts/chaincli/handler/keeper_verifiable_load.go index 429a762007..b71a9af338 100644 --- a/core/scripts/chaincli/handler/keeper_verifiable_load.go +++ b/core/scripts/chaincli/handler/keeper_verifiable_load.go @@ -2,6 +2,7 @@ package handler import ( "context" + "fmt" "log" "math/big" "sort" @@ -57,7 +58,7 @@ type upkeepStats struct { SortedAllDelays []float64 } -func (k *Keeper) GetVerifiableLoadStats(ctx context.Context) { +func (k *Keeper) GetVerifiableLoadStats(ctx context.Context, csv bool) { var v verifiableLoad var err error addr := common.HexToAddress(k.cfg.VerifiableLoadContractAddress) @@ -84,6 +85,10 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context) { log.Fatalf("failed to get active upkeep IDs from %s: %v", k.cfg.VerifiableLoadContractAddress, err) } + if csv { + fmt.Println("upkeep ID,total performs,p50,p90,p95,p99,max delay,total delay blocks,average perform delay") + } + us := &upkeepStats{BlockNumber: blockNum} resultsChan := make(chan *upkeepInfo, maxUpkeepNum) @@ -94,7 +99,7 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context) { // create a number of workers to process the upkeep ids in batch for i := 0; i < workerNum; i++ { wg.Add(1) - go k.getUpkeepInfo(idChan, resultsChan, v, opts, &wg) + go k.getUpkeepInfo(idChan, resultsChan, v, opts, &wg, csv) } for _, id := range upkeepIds { @@ -120,12 +125,16 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context) { p90, _ := stats.Percentile(us.SortedAllDelays, 90) p95, _ := stats.Percentile(us.SortedAllDelays, 95) p99, _ := stats.Percentile(us.SortedAllDelays, 99) - maxDelay := us.SortedAllDelays[len(us.SortedAllDelays)-1] + + maxDelay := float64(0) + if len(us.SortedAllDelays) > 0 { + maxDelay = us.SortedAllDelays[len(us.SortedAllDelays)-1] + } log.Printf("For total %d upkeeps: total performs: %d, p50: %f, p90: %f, p95: %f, p99: %f, max delay: %f, total delay blocks: %f, average perform delay: %f\n", len(upkeepIds), us.TotalPerforms, p50, p90, p95, p99, maxDelay, us.TotalDelayBlock, us.TotalDelayBlock/float64(us.TotalPerforms)) log.Printf("All STATS ABOVE ARE CALCULATED AT BLOCK %d", blockNum) } -func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInfo, v verifiableLoad, opts *bind.CallOpts, wg *sync.WaitGroup) { +func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInfo, v verifiableLoad, opts *bind.CallOpts, wg *sync.WaitGroup, csv bool) { defer wg.Done() for id := range idChan { @@ -171,9 +180,18 @@ func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInf p90, _ := stats.Percentile(info.SortedAllDelays, 90) p95, _ := stats.Percentile(info.SortedAllDelays, 95) p99, _ := stats.Percentile(info.SortedAllDelays, 99) - maxDelay := info.SortedAllDelays[len(info.SortedAllDelays)-1] - log.Printf("upkeep ID %s has %d performs in total. p50: %f, p90: %f, p95: %f, p99: %f, max delay: %f, total delay blocks: %d, average perform delay: %f\n", id, info.TotalPerforms, p50, p90, p95, p99, maxDelay, uint64(info.TotalDelayBlock), info.TotalDelayBlock/float64(info.TotalPerforms)) + maxDelay := float64(0) + + if len(info.SortedAllDelays) > 0 { + maxDelay = info.SortedAllDelays[len(info.SortedAllDelays)-1] + } + + if csv { + fmt.Printf("%s,%d,%f,%f,%f,%f,%f,%d,%f\n", id, info.TotalPerforms, p50, p90, p95, p99, maxDelay, uint64(info.TotalDelayBlock), info.TotalDelayBlock/float64(info.TotalPerforms)) + } else { + log.Printf("upkeep ID %s has %d performs in total. p50: %f, p90: %f, p95: %f, p99: %f, max delay: %f, total delay blocks: %d, average perform delay: %f\n", id, info.TotalPerforms, p50, p90, p95, p99, maxDelay, uint64(info.TotalDelayBlock), info.TotalDelayBlock/float64(info.TotalPerforms)) + } resultsChan <- info } } From 0ba7e9a7cd402ed558835a39d0ced4e7c2b39732 Mon Sep 17 00:00:00 2001 From: george-dorin <120329946+george-dorin@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:37:45 +0200 Subject: [PATCH 134/327] EVM GRPC provider (#11208) * Initial draft * Add median provider checks * Move provider-server to relay * Bump chainlink-relay version * Add tests * Add comment explaining why the code lives inside the newServicesGenericPlugin method * Fix formatting * Fix lint --- core/services/ocr2/delegate.go | 23 ++++++- core/services/relay/grpc_provider_server.go | 68 +++++++++++++++++++ .../relay/grpc_provider_server_test.go | 27 ++++++++ core/services/relay/relay_test.go | 26 +++++++ 4 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 core/services/relay/grpc_provider_server.go create mode 100644 core/services/relay/grpc_provider_server_test.go diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 19296c72f0..9905ed6ae6 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -590,9 +590,26 @@ func (d *Delegate) newServicesGenericPlugin( } errorLog := &errorLog{jobID: jb.ID, recordError: d.jobORM.RecordError} + var providerClientConn grpc.ClientConnInterface providerConn, ok := provider.(connProvider) - if !ok { - return nil, errors.New("provider not supported: the provider is not a LOOPP provider") + if ok { + providerClientConn = providerConn.ClientConn() + } else { + //We chose to deal with the difference between a LOOP provider and an embedded provider here rather than + //in NewServerAdapter because this has a smaller blast radius, as the scope of this workaround is to + //enable the medianpoc for EVM and not touch the other providers. + //TODO: remove this workaround when the EVM relayer is running inside of an LOOPP + d.lggr.Info("provider is not a LOOPP provider, switching to provider server") + + ps, err2 := relay.NewProviderServer(provider, types.OCR2PluginType(cconf.ProviderType), d.lggr) + if err2 != nil { + return nil, fmt.Errorf("cannot start EVM provider server: %s", err) + } + providerClientConn, err2 = ps.GetConn() + if err2 != nil { + return nil, fmt.Errorf("cannot connect to EVM provider server: %s", err) + } + srvs = append(srvs, ps) } pluginConfig := types.ReportingPluginServiceConfig{ @@ -606,7 +623,7 @@ func (d *Delegate) newServicesGenericPlugin( pr := generic.NewPipelineRunnerAdapter(pluginLggr, jb, d.pipelineRunner) ta := generic.NewTelemetryAdapter(d.monitoringEndpointGen) - plugin := reportingplugins.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerConn.ClientConn(), pr, ta, errorLog) + plugin := reportingplugins.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, errorLog) oracleArgs.ReportingPluginFactory = plugin srvs = append(srvs, plugin) diff --git a/core/services/relay/grpc_provider_server.go b/core/services/relay/grpc_provider_server.go new file mode 100644 index 0000000000..943af0e636 --- /dev/null +++ b/core/services/relay/grpc_provider_server.go @@ -0,0 +1,68 @@ +package relay + +import ( + "context" + "net" + + "go.uber.org/multierr" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +type ProviderServer struct { + s *grpc.Server + lis net.Listener + lggr logger.Logger + conns []*grpc.ClientConn +} + +func (p *ProviderServer) Start(ctx context.Context) error { + p.serve() + return nil +} + +func (p *ProviderServer) Close() error { + var err error + for _, c := range p.conns { + err = multierr.Combine(err, c.Close()) + } + p.s.Stop() + return err +} + +func (p *ProviderServer) GetConn() (*grpc.ClientConn, error) { + cc, err := grpc.Dial(p.lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) + p.conns = append(p.conns, cc) + return cc, err +} + +// NewProviderServer creates a GRPC server that will wrap a provider, this is a workaround to test the Node API PoC until the EVM relayer is loopifyed +func NewProviderServer(p types.PluginProvider, pType types.OCR2PluginType, lggr logger.Logger) (*ProviderServer, error) { + lis, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, err + } + ps := ProviderServer{ + s: grpc.NewServer(), + lis: lis, + lggr: lggr.Named("EVM.ProviderServer"), + } + err = loop.RegisterStandAloneProvider(ps.s, p, pType) + if err != nil { + return nil, err + } + + return &ps, nil +} + +func (p *ProviderServer) serve() { + go func() { + if err := p.s.Serve(p.lis); err != nil { + p.lggr.Errorf("Failed to serve EVM provider server: %v", err) + } + }() +} diff --git a/core/services/relay/grpc_provider_server_test.go b/core/services/relay/grpc_provider_server_test.go new file mode 100644 index 0000000000..e7ee8d7f15 --- /dev/null +++ b/core/services/relay/grpc_provider_server_test.go @@ -0,0 +1,27 @@ +package relay + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +func TestProviderServer(t *testing.T) { + r := &mockRelayer{} + sa := NewServerAdapter(r, mockRelayerExt{}) + mp, _ := sa.NewPluginProvider(context.Background(), types.RelayArgs{ProviderType: string(types.Median)}, types.PluginArgs{}) + + lggr := logger.TestLogger(t) + _, err := NewProviderServer(mp, "unsupported-type", lggr) + require.Error(t, err) + + ps, err := NewProviderServer(staticMedianProvider{}, types.Median, lggr) + require.NoError(t, err) + + _, err = ps.GetConn() + require.NoError(t, err) +} diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index d3a9477349..5bcd14c64a 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/smartcontractkit/chainlink-relay/pkg/loop" @@ -61,6 +63,30 @@ type staticMedianProvider struct { types.MedianProvider } +func (s staticMedianProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester { + return nil +} + +func (s staticMedianProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { + return nil +} + +func (s staticMedianProvider) ContractTransmitter() ocrtypes.ContractTransmitter { + return nil +} + +func (s staticMedianProvider) ReportCodec() median.ReportCodec { + return nil +} + +func (s staticMedianProvider) MedianContract() median.MedianContract { + return nil +} + +func (s staticMedianProvider) OnchainConfigCodec() median.OnchainConfigCodec { + return nil +} + type staticFunctionsProvider struct { types.FunctionsProvider } From b66b7233ed5b9f432e621b62c213daf45f365574 Mon Sep 17 00:00:00 2001 From: Tate Date: Mon, 13 Nov 2023 09:06:03 -0700 Subject: [PATCH 135/327] [TT-500][TT-682]Add build and lint to integration-tests (#11221) * Add build and lint to integration-tests * Fix the build to actually build all the test files * Add needs for the new job so it will affect required steps * Review comments * fix build and lint errors * bump lint and go versions * lint weirdness in migration test * Wire the test context in the VRFV2SoakTest Run function to a parent context tied to the test. * Merge conflict fix and improved .golangci lint file with fixes for those * One more .golangci cleanup * Fix newly added lint errors * add build to integration-tests makefile --- .github/actions/golangci-lint/action.yml | 2 +- .github/workflows/integration-tests.yml | 72 ++++-- .../on-demand-vrfv2plus-performance-test.yml | 2 +- .tool-versions | 4 +- GNUmakefile | 2 +- integration-tests/.golangci.yml | 78 +++++++ integration-tests/.tool-versions | 3 +- integration-tests/Makefile | 6 + integration-tests/actions/actions.go | 1 - integration-tests/actions/actions_local.go | 2 +- .../actions/automation_ocr_helpers.go | 5 +- integration-tests/actions/ocr2_helpers.go | 7 +- .../actions/ocr2_helpers_local.go | 11 +- .../ocr2vrf_actions/ocr2vrf_config_helpers.go | 7 +- .../actions/ocr2vrf_actions/ocr2vrf_steps.go | 8 +- integration-tests/actions/ocr_helpers.go | 1 - .../actions/ocr_helpers_local.go | 3 +- .../actions/operator_forwarder_helpers.go | 18 +- .../actions/vrfv2plus/vrfv2plus_steps.go | 5 +- .../chaos/automation_chaos_test.go | 15 +- integration-tests/chaos/ocr2vrf_chaos_test.go | 7 +- integration-tests/chaos/ocr_chaos_test.go | 8 +- integration-tests/client/chainlink_k8s.go | 2 +- .../contracts/contract_deployer.go | 32 +-- .../contracts/contract_loader.go | 1 + .../contracts/contract_vrf_models.go | 13 +- .../contracts/ethereum_contracts.go | 15 +- .../contracts/ethereum_keeper_contracts.go | 95 ++++---- integration-tests/contracts/test_contracts.go | 1 + integration-tests/docker/cmd/test_env.go | 7 +- integration-tests/docker/test_env/cl_node.go | 102 +-------- integration-tests/docker/test_env/test_env.go | 5 +- .../docker/test_env/test_env_builder.go | 4 +- integration-tests/load/functions/config.go | 4 +- .../load/functions/functions_test.go | 5 +- integration-tests/load/functions/gateway.go | 5 +- .../load/functions/gateway_gun.go | 9 +- .../load/functions/onchain_monitoring.go | 5 +- .../load/functions/request_gun.go | 19 +- integration-tests/load/functions/setup.go | 3 +- .../load/log_poller/log_poller_test.go | 3 +- integration-tests/load/vrfv2/cmd/dashboard.go | 3 +- integration-tests/load/vrfv2/config.go | 1 + integration-tests/load/vrfv2/gun.go | 5 +- .../load/vrfv2/onchain_monitoring.go | 12 +- integration-tests/load/vrfv2/vrfv2_test.go | 3 +- integration-tests/load/vrfv2/vu.go | 3 +- .../load/vrfv2plus/cmd/dashboard.go | 3 +- integration-tests/load/vrfv2plus/config.go | 4 + integration-tests/load/vrfv2plus/gun.go | 10 +- .../load/vrfv2plus/onchain_monitoring.go | 8 +- .../load/vrfv2plus/vrfv2plus_test.go | 22 +- .../migration/upgrade_version_test.go | 5 +- integration-tests/performance/cron_test.go | 3 +- .../performance/directrequest_test.go | 4 +- integration-tests/performance/flux_test.go | 10 +- integration-tests/performance/keeper_test.go | 10 +- integration-tests/performance/ocr_test.go | 8 +- integration-tests/performance/vrf_test.go | 6 +- .../reorg/automation_reorg_test.go | 16 +- .../reorg/log_poller_maybe_reorg_test.go | 1 + integration-tests/reorg/reorg_test.go | 8 +- integration-tests/runner_helpers.go | 4 +- integration-tests/smoke/automation_test.go | 120 +++++----- integration-tests/smoke/flux_test.go | 10 +- integration-tests/smoke/forwarder_ocr_test.go | 6 +- .../smoke/forwarders_ocr2_test.go | 6 +- integration-tests/smoke/keeper_test.go | 92 ++++---- integration-tests/smoke/log_poller_test.go | 1 + integration-tests/smoke/ocr2_test.go | 6 +- integration-tests/smoke/ocr2vrf_test.go | 11 +- integration-tests/smoke/ocr_test.go | 6 +- integration-tests/smoke/runlog_test.go | 4 +- integration-tests/smoke/vrf_test.go | 6 +- integration-tests/smoke/vrfv2_test.go | 6 +- integration-tests/smoke/vrfv2plus_test.go | 89 ++++---- .../testreporters/keeper_benchmark.go | 4 +- integration-tests/testreporters/ocr.go | 4 +- integration-tests/testreporters/profile.go | 2 +- integration-tests/testreporters/vrfv2plus.go | 5 +- .../testsetups/keeper_benchmark.go | 10 +- integration-tests/testsetups/ocr.go | 17 +- integration-tests/testsetups/vrfv2.go | 6 +- integration-tests/types/envcommon/common.go | 4 +- .../universal/log_poller/config.go | 27 +-- integration-tests/universal/log_poller/gun.go | 7 +- .../universal/log_poller/helpers.go | 212 ++++++++---------- .../universal/log_poller/scenarios.go | 26 +-- integration-tests/utils/cl_node_jobs.go | 5 +- integration-tests/utils/common.go | 19 ++ integration-tests/utils/log.go | 19 -- integration-tests/utils/templates/secrets.go | 1 + 92 files changed, 759 insertions(+), 718 deletions(-) create mode 100644 integration-tests/.golangci.yml delete mode 100644 integration-tests/utils/log.go diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index 97755fa46e..055960ff28 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -53,7 +53,7 @@ runs: - name: golangci-lint uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: - version: v1.55.0 + version: v1.55.2 # We already cache these directories in setup-go skip-pkg-cache: true skip-build-cache: true diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index ba66a53ab6..9294dceae6 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -64,6 +64,36 @@ jobs: outputs: src: ${{ steps.changes.outputs.src }} + build-lint-integration-tests: + name: Build and Lint integration-tests + runs-on: ubuntu20.04-16cores-64GB + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Go + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + with: + test_download_vendor_packages_command: cd ./integration-tests && go mod download + go_mod_path: ./integration-tests/go.mod + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + - name: Build Go + run: | + cd ./integration-tests + go build ./... + SELECTED_NETWORKS=SIMULATED go test -run=^# ./... + - name: Lint Go + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + with: + version: v1.55.2 + # We already cache these directories in setup-go + skip-pkg-cache: true + skip-build-cache: true + # only-new-issues is only applicable to PRs, otherwise it is always set to false + only-new-issues: false # disabled for PRs due to unreliability + args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml + working-directory: ./integration-tests + build-chainlink: environment: integration permissions: @@ -174,7 +204,7 @@ jobs: pull-requests: write id-token: write contents: read - needs: [build-chainlink, changes, compare-tests] + needs: [build-chainlink, changes, compare-tests, build-lint-integration-tests] env: SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 CHAINLINK_COMMIT_SHA: ${{ github.sha }} @@ -242,7 +272,7 @@ jobs: pull-requests: write id-token: write contents: read - needs: [build-chainlink, changes] + needs: [build-chainlink, changes, build-lint-integration-tests] env: SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 CHAINLINK_COMMIT_SHA: ${{ github.sha }} @@ -356,16 +386,16 @@ jobs: run: | PORT_BASE=3001 MAX_PORT=8000 - + # Use PR number as offset. Given GitHub PRs are incremental, this guarantees uniqueness for at least 5000 PRs. OFFSET=$GITHUB_PR_NUMBER echo "PR Number: $OFFSET" - + # Ensure that we don't exceed the max port if (( OFFSET > (MAX_PORT - PORT_BASE) )); then OFFSET=$((OFFSET % (MAX_PORT - PORT_BASE))) fi - + # Map the offset to the port range REMOTE_PORT=$((PORT_BASE + OFFSET)) echo "REMOTE_PORT=$REMOTE_PORT" >> $GITHUB_OUTPUT @@ -376,25 +406,25 @@ jobs: TRACING_SSH_SERVER: ${{ secrets.TRACING_SSH_SERVER }} REMOTE_PORT: ${{ steps.generate-port.outputs.REMOTE_PORT }} run: | - eval $(ssh-agent) - echo "test" - echo "$TRACING_SSH_KEY" | wc -c - echo "$TRACING_SSH_KEY" | tr -d '\r' | wc -c - echo "$TRACING_SSH_KEY" | tr -d '\r' | base64 --decode | ssh-add - - # f: background process - # N: do not execute a remote command - # R: remote port forwarding - ssh -o StrictHostKeyChecking=no -f -N -R $REMOTE_PORT:127.0.0.1:3000 user-gha@$TRACING_SSH_SERVER - echo "To view Grafana locally:" - echo "ssh -N -L 8000:localhost:$REMOTE_PORT user-gha@$TRACING_SSH_SERVER" - echo "Then visit http://localhost:8000 in a browser." - echo "If you are unable to connect, check with the security team that you have access to the tracing server." + eval $(ssh-agent) + echo "test" + echo "$TRACING_SSH_KEY" | wc -c + echo "$TRACING_SSH_KEY" | tr -d '\r' | wc -c + echo "$TRACING_SSH_KEY" | tr -d '\r' | base64 --decode | ssh-add - + # f: background process + # N: do not execute a remote command + # R: remote port forwarding + ssh -o StrictHostKeyChecking=no -f -N -R $REMOTE_PORT:127.0.0.1:3000 user-gha@$TRACING_SSH_SERVER + echo "To view Grafana locally:" + echo "ssh -N -L 8000:localhost:$REMOTE_PORT user-gha@$TRACING_SSH_SERVER" + echo "Then visit http://localhost:8000 in a browser." + echo "If you are unable to connect, check with the security team that you have access to the tracing server." - name: Show Grafana Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - docker logs grafana - docker logs tempo - docker logs otel-collector + docker logs grafana + docker logs tempo + docker logs otel-collector - name: Set sleep time to use in future steps if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index c51f7f5a2f..b4f9f46de0 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -54,7 +54,7 @@ on: useExistingEnv: description: Set `true` to use existing environment or `false` to deploy CL node and all contracts required: false - default: false + default: "false" configBase64: description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) required: false diff --git a/.tool-versions b/.tool-versions index 87910cf6d6..c60396ccb8 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,7 +1,7 @@ -golang 1.21.1 +golang 1.21.4 mockery 2.35.4 nodejs 16.16.0 postgres 13.3 helm 3.10.3 zig 0.10.1 -golangci-lint 1.55.0 +golangci-lint 1.55.2 diff --git a/GNUmakefile b/GNUmakefile index 69d82da6c8..2801f94968 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -138,7 +138,7 @@ config-docs: ## Generate core node configuration documentation .PHONY: golangci-lint golangci-lint: ## Run golangci-lint for all issues. [ -d "./golangci-lint" ] || mkdir ./golangci-lint && \ - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.55.0 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.55.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt GORELEASER_CONFIG ?= .goreleaser.yaml diff --git a/integration-tests/.golangci.yml b/integration-tests/.golangci.yml new file mode 100644 index 0000000000..d22b26b826 --- /dev/null +++ b/integration-tests/.golangci.yml @@ -0,0 +1,78 @@ +run: + timeout: 15m +linters: + enable: + - exhaustive + - exportloopref + - revive + - goimports + - gosec + - misspell + - rowserrcheck + - errorlint +linters-settings: + exhaustive: + default-signifies-exhaustive: true + goimports: + local-prefixes: github.com/smartcontractkit/chainlink + golint: + min-confidence: 0.999 + gosec: + excludes: + - G101 + govet: + # report about shadowed variables + check-shadowing: true + revive: + confidence: 0.8 + rules: + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: if-return + - name: increment-decrement + # - name: var-naming // doesn't work with some generated names + - name: var-declaration + - name: package-comments + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + - name: unreachable-code + - name: redefines-builtin-id + - name: waitgroup-by-value + - name: unconditional-recursion + - name: struct-tag + - name: string-format + - name: string-of-int + - name: range-val-address + - name: range-val-in-closure + - name: modifies-value-receiver + - name: modifies-parameter + - name: identical-branches + - name: get-return + # - name: flag-parameter // probably one we should work on doing better at in the future + # - name: early-return // probably one we should work on doing better at in the future + - name: defer + - name: constant-logical-expr + - name: confusing-naming + - name: confusing-results + - name: bool-literal-in-expr + - name: atomic +issues: + exclude-rules: + - text: "^G404: Use of weak random number generator" + linters: + - gosec + - linters: + - govet + text: "declaration of \"err\" shadows" diff --git a/integration-tests/.tool-versions b/integration-tests/.tool-versions index 68b6d99419..47b73e9de1 100644 --- a/integration-tests/.tool-versions +++ b/integration-tests/.tool-versions @@ -1,4 +1,5 @@ -golang 1.21.1 +golang 1.21.4 k3d 5.4.6 kubectl 1.25.5 nodejs 18.13.0 +golangci-lint 1.55.2 diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 257331afcf..fb4bfa74f3 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -56,6 +56,12 @@ install_gotestfmt: go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest set -euo pipefail +lint: + golangci-lint --color=always run ./... --fix -v + +build: + @go build ./... && SELECTED_NETWORKS=SIMULATED go test -run=^# ./... + # Builds the test image # tag: the tag for the test image being built, example: tag=tate # base_tag: the tag for the base-test-image to use, example: base_tag=latest diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index bacf5a9dbf..02a2523477 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -254,7 +254,6 @@ func GetMockserverInitializerDataForOTPE( func TeardownSuite( t *testing.T, env *environment.Environment, - logsFolderPath string, chainlinkNodes []*client.ChainlinkK8sClient, optionalTestReporter testreporters.TestReporter, // Optionally pass in a test reporter to log further metrics failingLogLevel zapcore.Level, // Examines logs after the test, and fails the test if any Chainlink logs are found at or above provided level diff --git a/integration-tests/actions/actions_local.go b/integration-tests/actions/actions_local.go index f5d2a9035f..d4913cabd8 100644 --- a/integration-tests/actions/actions_local.go +++ b/integration-tests/actions/actions_local.go @@ -17,7 +17,7 @@ func UpgradeChainlinkNodeVersionsLocal( return fmt.Errorf("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") } for _, node := range nodes { - if err := node.UpgradeVersion(node.NodeConfig, newImage, newVersion); err != nil { + if err := node.UpgradeVersion(newImage, newVersion); err != nil { return err } } diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index 998b1ee89c..e1635902db 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -14,14 +14,15 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" diff --git a/integration-tests/actions/ocr2_helpers.go b/integration-tests/actions/ocr2_helpers.go index aead74f2bd..02ce73e813 100644 --- a/integration-tests/actions/ocr2_helpers.go +++ b/integration-tests/actions/ocr2_helpers.go @@ -15,14 +15,15 @@ import ( "golang.org/x/sync/errgroup" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" - "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" diff --git a/integration-tests/actions/ocr2_helpers_local.go b/integration-tests/actions/ocr2_helpers_local.go index b3fe6eb041..65e0a466be 100644 --- a/integration-tests/actions/ocr2_helpers_local.go +++ b/integration-tests/actions/ocr2_helpers_local.go @@ -12,6 +12,12 @@ import ( "github.com/google/uuid" "github.com/lib/pq" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "golang.org/x/sync/errgroup" + "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -19,11 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" - "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "golang.org/x/sync/errgroup" - "gopkg.in/guregu/null.v4" ) func CreateOCRv2JobsLocal( diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go index ce69396432..e424aaa11b 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go @@ -16,9 +16,6 @@ import ( "go.dedis.ch/kyber/v3/group/edwards25519" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/ocr2vrf/altbn_128" @@ -26,6 +23,10 @@ import ( "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go index c123aaff6a..72d668076e 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func SetAndWaitForVRFBeaconProcessToFinish(t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, vrfBeacon contracts.VRFBeacon) { @@ -172,7 +173,7 @@ func FundVRFCoordinatorV3Subscription(t *testing.T, linkToken contracts.LinkToke require.NoError(t, err, "Error waiting for TXs to complete") } -func DeployOCR2VRFContracts(t *testing.T, contractDeployer contracts.ContractDeployer, chainClient blockchain.EVMClient, linkToken contracts.LinkToken, mockETHLinkFeed contracts.MockETHLINKFeed, beaconPeriodBlocksCount *big.Int, keyID string) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer) { +func DeployOCR2VRFContracts(t *testing.T, contractDeployer contracts.ContractDeployer, chainClient blockchain.EVMClient, linkToken contracts.LinkToken, beaconPeriodBlocksCount *big.Int, keyID string) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer) { dkg, err := contractDeployer.DeployDKG() require.NoError(t, err, "Error deploying DKG Contract") @@ -272,14 +273,14 @@ func RequestRandomnessFulfillmentAndWaitForFulfilment( } func getRequestId(t *testing.T, consumer contracts.VRFBeaconConsumer, receipt *types.Receipt, confirmationDelay *big.Int) *big.Int { - periodBlocks, err := consumer.IBeaconPeriodBlocks(nil) + periodBlocks, err := consumer.IBeaconPeriodBlocks(utils.TestContext(t)) require.NoError(t, err, "Error getting Beacon Period block count") blockNumber := receipt.BlockNumber periodOffset := new(big.Int).Mod(blockNumber, periodBlocks) nextBeaconOutputHeight := new(big.Int).Sub(new(big.Int).Add(blockNumber, periodBlocks), periodOffset) - requestID, err := consumer.GetRequestIdsBy(nil, nextBeaconOutputHeight, confirmationDelay) + requestID, err := consumer.GetRequestIdsBy(utils.TestContext(t), nextBeaconOutputHeight, confirmationDelay) require.NoError(t, err, "Error getting requestID from consumer contract") return requestID @@ -305,7 +306,6 @@ func SetupOCR2VRFUniverse( contractDeployer, chainClient, linkToken, - mockETHLinkFeed, ocr2vrf_constants.BeaconPeriodBlocksCount, ocr2vrf_constants.KeyID, ) diff --git a/integration-tests/actions/ocr_helpers.go b/integration-tests/actions/ocr_helpers.go index cfc8cfe589..4f713dcdd6 100644 --- a/integration-tests/actions/ocr_helpers.go +++ b/integration-tests/actions/ocr_helpers.go @@ -27,7 +27,6 @@ func DeployOCRContracts( numberOfContracts int, linkTokenContract contracts.LinkToken, contractDeployer contracts.ContractDeployer, - bootstrapNode *client.ChainlinkK8sClient, workerNodes []*client.ChainlinkK8sClient, client blockchain.EVMClient, ) ([]contracts.OffchainAggregator, error) { diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index 5836ee7945..e6dd5ae77f 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -10,9 +10,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/rs/zerolog" + "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" - "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" diff --git a/integration-tests/actions/operator_forwarder_helpers.go b/integration-tests/actions/operator_forwarder_helpers.go index 37b50c4fa9..a1d7135416 100644 --- a/integration-tests/actions/operator_forwarder_helpers.go +++ b/integration-tests/actions/operator_forwarder_helpers.go @@ -1,7 +1,6 @@ package actions import ( - "context" "math/big" "testing" @@ -17,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func DeployForwarderContracts( @@ -67,7 +67,7 @@ func AcceptAuthorizedReceiversOperator( err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for events in nodes shouldn't fail") - senders, err := forwarderInstance.GetAuthorizedSenders(context.Background()) + senders, err := forwarderInstance.GetAuthorizedSenders(utils.TestContext(t)) require.NoError(t, err, "Getting authorized senders shouldn't fail") var nodesAddrs []string for _, o := range nodeAddresses { @@ -75,20 +75,18 @@ func AcceptAuthorizedReceiversOperator( } require.Equal(t, nodesAddrs, senders, "Senders addresses should match node addresses") - owner, err := forwarderInstance.Owner(context.Background()) + owner, err := forwarderInstance.Owner(utils.TestContext(t)) require.NoError(t, err, "Getting authorized forwarder owner shouldn't fail") require.Equal(t, operator.Hex(), owner, "Forwarder owner should match operator") } func ProcessNewEvent( t *testing.T, - eventSub geth.Subscription, operatorCreated chan *operator_factory.OperatorFactoryOperatorCreated, authorizedForwarderCreated chan *operator_factory.OperatorFactoryAuthorizedForwarderCreated, event *types.Log, eventDetails *abi.Event, operatorFactoryInstance contracts.OperatorFactory, - contractABI *abi.ABI, chainClient blockchain.EVMClient, ) { l := logging.GetTestLogger(t) @@ -141,7 +139,7 @@ func SubscribeOperatorFactoryEvents( l := logging.GetTestLogger(t) contractABI, err := operator_factory.OperatorFactoryMetaData.GetAbi() require.NoError(t, err, "Getting contract abi for OperatorFactory shouldn't fail") - latestBlockNum, err := chainClient.LatestBlockNumber(context.Background()) + latestBlockNum, err := chainClient.LatestBlockNumber(utils.TestContext(t)) require.NoError(t, err, "Subscribing to contract event log for OperatorFactory instance shouldn't fail") query := geth.FilterQuery{ FromBlock: big.NewInt(0).SetUint64(latestBlockNum), @@ -149,7 +147,7 @@ func SubscribeOperatorFactoryEvents( } eventLogs := make(chan types.Log) - sub, err := chainClient.SubscribeFilterLogs(context.Background(), query, eventLogs) + sub, err := chainClient.SubscribeFilterLogs(utils.TestContext(t), query, eventLogs) require.NoError(t, err, "Subscribing to contract event log for OperatorFactory instance shouldn't fail") go func() { defer sub.Unsubscribe() @@ -160,14 +158,14 @@ func SubscribeOperatorFactoryEvents( l.Error().Err(err).Msg("Error while watching for new contract events. Retrying Subscription") sub.Unsubscribe() - sub, err = chainClient.SubscribeFilterLogs(context.Background(), query, eventLogs) + sub, err = chainClient.SubscribeFilterLogs(utils.TestContext(t), query, eventLogs) require.NoError(t, err, "Subscribing to contract event log for OperatorFactory instance shouldn't fail") case vLog := <-eventLogs: eventDetails, err := contractABI.EventByID(vLog.Topics[0]) require.NoError(t, err, "Getting event details for OperatorFactory instance shouldn't fail") go ProcessNewEvent( - t, sub, operatorCreated, authorizedForwarderCreated, &vLog, - eventDetails, operatorFactoryInstance, contractABI, chainClient, + t, operatorCreated, authorizedForwarderCreated, &vLog, + eventDetails, operatorFactoryInstance, chainClient, ) if eventDetails.Name == "AuthorizedForwarderCreated" || eventDetails.Name == "OperatorCreated" { remainingExpectedEvents-- diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index e964623fb2..28fb2635ff 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" @@ -802,7 +803,7 @@ func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadT fmt.Errorf("timeout waiting for rand request and fulfilments to be equal AFTER performance test was executed. Request Count: %d, Fulfilment Count: %d", metrics.RequestCount.Uint64(), metrics.FulfilmentCount.Uint64()) case <-ticker.C: - go getLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) + go retreiveLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) case metrics = <-metricsChannel: if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { ticker.Stop() @@ -852,7 +853,7 @@ func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator co return nil } -func getLoadTestMetrics( +func retreiveLoadTestMetrics( consumer contracts.VRFv2PlusLoadTestConsumer, metricsChannel chan *contracts.VRFLoadTestMetrics, metricsErrorChannel chan error, diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 22c9e742f3..6ebf14d806 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -1,7 +1,6 @@ package chaos import ( - "context" "fmt" "math/big" "testing" @@ -25,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -116,6 +116,7 @@ func TestAutomationChaos(t *testing.T) { } for name, registryVersion := range registryVersions { + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() @@ -176,9 +177,9 @@ func TestAutomationChaos(t *testing.T) { }, } - for n, tst := range testCases { - name := n - testCase := tst + for name, testCase := range testCases { + name := name + testCase := testCase t.Run(fmt.Sprintf("Automation_%s", name), func(t *testing.T) { t.Parallel() network := networks.MustGetSelectedNetworksFromEnv()[0] // Need a new copy of the network for each test @@ -223,7 +224,7 @@ func TestAutomationChaos(t *testing.T) { if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -268,7 +269,7 @@ func TestAutomationChaos(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(it_utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") @@ -283,7 +284,7 @@ func TestAutomationChaos(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(it_utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 10 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index ba75974f01..8739a5960a 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCR2VRFChaos(t *testing.T) { @@ -149,7 +150,7 @@ func TestOCR2VRFChaos(t *testing.T) { require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -185,7 +186,7 @@ func TestOCR2VRFChaos(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(nil, requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) require.NoError(t, err) l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") @@ -212,7 +213,7 @@ func TestOCR2VRFChaos(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(nil, requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) require.NoError(t, err, "Error getting Randomness result from Consumer Contract") l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 599fad8ddc..76e25d9200 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -1,7 +1,6 @@ package chaos import ( - "context" "fmt" "math/big" "os" @@ -27,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -164,7 +164,7 @@ func TestOCRChaos(t *testing.T) { if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -180,7 +180,7 @@ func TestOCRChaos(t *testing.T) { err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(10)) require.NoError(t, err) - ocrInstances, err := actions.DeployOCRContracts(1, lt, cd, bootstrapNode, workerNodes, chainClient) + ocrInstances, err := actions.DeployOCRContracts(1, lt, cd, workerNodes, chainClient) require.NoError(t, err) err = chainClient.WaitForEvents() require.NoError(t, err) @@ -195,7 +195,7 @@ func TestOCRChaos(t *testing.T) { err := ocr.RequestNewRound() require.NoError(t, err, "Error requesting new round") } - round, err := ocrInstances[0].GetLatestRound(context.Background()) + round, err := ocrInstances[0].GetLatestRound(it_utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred()) l.Info().Int64("RoundID", round.RoundId.Int64()).Msg("Latest OCR Round") if round.RoundId.Int64() == chaosStartRound && !chaosApplied { diff --git a/integration-tests/client/chainlink_k8s.go b/integration-tests/client/chainlink_k8s.go index 3fbf9eaf73..27fd956103 100644 --- a/integration-tests/client/chainlink_k8s.go +++ b/integration-tests/client/chainlink_k8s.go @@ -63,7 +63,7 @@ func (c *ChainlinkK8sClient) UpgradeVersion(testEnvironment *environment.Environ }, }, } - testEnvironment, err := testEnvironment.UpdateHelm(c.ChartName, upgradeVals) + _, err := testEnvironment.UpdateHelm(c.ChartName, upgradeVals) return err } diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 916971f82d..45195d327e 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -12,11 +12,12 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_v1_events_mock" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_consumer_benchmark" @@ -868,22 +869,21 @@ func (e *EthereumContractDeployer) LoadKeeperRegistrar(address common.Address, r client: e.client, registrar20: instance.(*keeper_registrar_wrapper2_0.KeeperRegistrar), }, err - } else { - instance, err := e.client.LoadContract("AutomationRegistrar", address, func( - address common.Address, - backend bind.ContractBackend, - ) (interface{}, error) { - return registrar21.NewAutomationRegistrar(address, backend) - }) - if err != nil { - return nil, err - } - return &EthereumKeeperRegistrar{ - address: &address, - client: e.client, - registrar21: instance.(*registrar21.AutomationRegistrar), - }, err } + instance, err := e.client.LoadContract("AutomationRegistrar", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return registrar21.NewAutomationRegistrar(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumKeeperRegistrar{ + address: &address, + client: e.client, + registrar21: instance.(*registrar21.AutomationRegistrar), + }, err } func (e *EthereumContractDeployer) DeployKeeperRegistry( diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index cfe7a35467..9a2f20226d 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -2,6 +2,7 @@ package contracts import ( "errors" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index c82924143b..baee2ccd92 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -262,12 +262,13 @@ type RequestStatus struct { } type LoadTestRequestStatus struct { - Fulfilled bool - RandomWords []*big.Int - requestTimestamp *big.Int - fulfilmentTimestamp *big.Int - requestBlockNumber *big.Int - fulfilmentBlockNumber *big.Int + Fulfilled bool + RandomWords []*big.Int + // Currently Unused November 8, 2023, Mignt be used in near future, will remove if not. + // requestTimestamp *big.Int + // fulfilmentTimestamp *big.Int + // requestBlockNumber *big.Int + // fulfilmentBlockNumber *big.Int } type VRFLoadTestMetrics struct { diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index cde6e325f2..9cb858fe00 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -16,6 +16,11 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" + ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" @@ -43,10 +48,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/werc20_mock" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" - ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink/integration-tests/client" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" @@ -939,7 +940,7 @@ func (f *EthereumFluxAggregator) PaymentAmount(ctx context.Context) (*big.Int, e return payment, nil } -func (f *EthereumFluxAggregator) RequestNewRound(ctx context.Context) error { +func (f *EthereumFluxAggregator) RequestNewRound(_ context.Context) error { opts, err := f.client.TransactionOpts(f.client.GetDefaultWallet()) if err != nil { return err @@ -978,7 +979,7 @@ func (f *EthereumFluxAggregator) WatchSubmissionReceived(ctx context.Context, ev } } -func (f *EthereumFluxAggregator) SetRequesterPermissions(ctx context.Context, addr common.Address, authorized bool, roundsDelay uint32) error { +func (f *EthereumFluxAggregator) SetRequesterPermissions(_ context.Context, addr common.Address, authorized bool, roundsDelay uint32) error { opts, err := f.client.TransactionOpts(f.client.GetDefaultWallet()) if err != nil { return err @@ -1019,7 +1020,7 @@ func (f *EthereumFluxAggregator) LatestRoundID(ctx context.Context) (*big.Int, e } func (f *EthereumFluxAggregator) WithdrawPayment( - ctx context.Context, + _ context.Context, from common.Address, to common.Address, amount *big.Int) error { diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index 135b016ee5..2c0250e745 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -250,25 +250,25 @@ func (rcs *KeeperRegistrySettings) EncodeOnChainConfig(registrar string, registr encodedOnchainConfig, err := utilsABI.Methods["_onChainConfig"].Inputs.Pack(&onchainConfigStruct) return encodedOnchainConfig, err - } else { - configType := goabi.MustNewType("tuple(uint32 paymentPremiumPPB,uint32 flatFeeMicroLink,uint32 checkGasLimit,uint24 stalenessSeconds,uint16 gasCeilingMultiplier,uint96 minUpkeepSpend,uint32 maxPerformGas,uint32 maxCheckDataSize,uint32 maxPerformDataSize,uint256 fallbackGasPrice,uint256 fallbackLinkPrice,address transcoder,address registrar)") - onchainConfig, err := goabi.Encode(map[string]interface{}{ - "paymentPremiumPPB": rcs.PaymentPremiumPPB, - "flatFeeMicroLink": rcs.FlatFeeMicroLINK, - "checkGasLimit": rcs.CheckGasLimit, - "stalenessSeconds": rcs.StalenessSeconds, - "gasCeilingMultiplier": rcs.GasCeilingMultiplier, - "minUpkeepSpend": rcs.MinUpkeepSpend, - "maxPerformGas": rcs.MaxPerformGas, - "maxCheckDataSize": rcs.MaxCheckDataSize, - "maxPerformDataSize": rcs.MaxPerformDataSize, - "fallbackGasPrice": rcs.FallbackGasPrice, - "fallbackLinkPrice": rcs.FallbackLinkPrice, - "transcoder": common.Address{}, - "registrar": registrar, - }, configType) - return onchainConfig, err } + configType := goabi.MustNewType("tuple(uint32 paymentPremiumPPB,uint32 flatFeeMicroLink,uint32 checkGasLimit,uint24 stalenessSeconds,uint16 gasCeilingMultiplier,uint96 minUpkeepSpend,uint32 maxPerformGas,uint32 maxCheckDataSize,uint32 maxPerformDataSize,uint256 fallbackGasPrice,uint256 fallbackLinkPrice,address transcoder,address registrar)") + onchainConfig, err := goabi.Encode(map[string]interface{}{ + "paymentPremiumPPB": rcs.PaymentPremiumPPB, + "flatFeeMicroLink": rcs.FlatFeeMicroLINK, + "checkGasLimit": rcs.CheckGasLimit, + "stalenessSeconds": rcs.StalenessSeconds, + "gasCeilingMultiplier": rcs.GasCeilingMultiplier, + "minUpkeepSpend": rcs.MinUpkeepSpend, + "maxPerformGas": rcs.MaxPerformGas, + "maxCheckDataSize": rcs.MaxCheckDataSize, + "maxPerformDataSize": rcs.MaxPerformDataSize, + "fallbackGasPrice": rcs.FallbackGasPrice, + "fallbackLinkPrice": rcs.FallbackLinkPrice, + "transcoder": common.Address{}, + "registrar": registrar, + }, configType) + return onchainConfig, err + } func (v *EthereumKeeperRegistry) RegistryOwnerAddress() common.Address { @@ -276,6 +276,7 @@ func (v *EthereumKeeperRegistry) RegistryOwnerAddress() common.Address { Pending: false, } + //nolint: exhaustive switch v.version { case ethereum.RegistryVersion_2_1: ownerAddress, _ := v.registry2_1.Owner(callOpts) @@ -283,6 +284,8 @@ func (v *EthereumKeeperRegistry) RegistryOwnerAddress() common.Address { case ethereum.RegistryVersion_2_0: ownerAddress, _ := v.registry2_0.Owner(callOpts) return ownerAddress + case ethereum.RegistryVersion_1_0, ethereum.RegistryVersion_1_1, ethereum.RegistryVersion_1_2, ethereum.RegistryVersion_1_3: + return common.HexToAddress(v.client.GetDefaultWallet().Address()) } return common.HexToAddress(v.client.GetDefaultWallet().Address()) @@ -664,7 +667,7 @@ func (v *EthereumKeeperRegistry) GetKeeperInfo(ctx context.Context, keeperAddr s info, err = v.registry1_2.GetKeeperInfo(opts, common.HexToAddress(keeperAddr)) case ethereum.RegistryVersion_1_3: info, err = v.registry1_3.GetKeeperInfo(opts, common.HexToAddress(keeperAddr)) - case ethereum.RegistryVersion_2_0: + case ethereum.RegistryVersion_2_0, ethereum.RegistryVersion_2_1: // this is not used anywhere return nil, fmt.Errorf("not supported") } @@ -710,6 +713,8 @@ func (v *EthereumKeeperRegistry) SetKeepers(keepers []string, payees []string, o ocrConfig.OffchainConfigVersion, ocrConfig.OffchainConfig, ) + case ethereum.RegistryVersion_2_1: + return fmt.Errorf("not supported") } if err != nil { @@ -760,6 +765,8 @@ func (v *EthereumKeeperRegistry) RegisterUpkeep(target string, gasLimit uint32, checkData, nil, //offchain config ) + case ethereum.RegistryVersion_2_1: + return fmt.Errorf("not supported") } if err != nil { @@ -877,6 +884,8 @@ func (v *EthereumKeeperRegistry) GetKeeperList(ctx context.Context) ([]string, e return []string{}, err } list = state.Transmitters + case ethereum.RegistryVersion_2_1: + return nil, fmt.Errorf("not supported") } if err != nil { @@ -1112,6 +1121,7 @@ func (v *EthereumKeeperRegistry) ParseUpkeepPerformedLog(log *types.Log) (*Upkee // ParseStaleUpkeepReportLog Parses Stale upkeep report log func (v *EthereumKeeperRegistry) ParseStaleUpkeepReportLog(log *types.Log) (*StaleUpkeepReportLog, error) { + //nolint:exhaustive switch v.version { case ethereum.RegistryVersion_2_0: parsedLog, err := v.registry2_0.ParseStaleUpkeepReport(*log) @@ -1129,7 +1139,6 @@ func (v *EthereumKeeperRegistry) ParseStaleUpkeepReportLog(log *types.Log) (*Sta return &StaleUpkeepReportLog{ Id: parsedLog.Id, }, nil - } return nil, fmt.Errorf("keeper registry version %d is not supported", v.version) } @@ -1850,7 +1859,7 @@ func (v *EthereumKeeperConsumerPerformance) GetUpkeepCount(ctx context.Context) return eligible, err } -func (v *EthereumKeeperConsumerPerformance) SetCheckGasToBurn(ctx context.Context, gas *big.Int) error { +func (v *EthereumKeeperConsumerPerformance) SetCheckGasToBurn(_ context.Context, gas *big.Int) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -1862,7 +1871,7 @@ func (v *EthereumKeeperConsumerPerformance) SetCheckGasToBurn(ctx context.Contex return v.client.ProcessTransaction(tx) } -func (v *EthereumKeeperConsumerPerformance) SetPerformGasToBurn(ctx context.Context, gas *big.Int) error { +func (v *EthereumKeeperConsumerPerformance) SetPerformGasToBurn(_ context.Context, gas *big.Int) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -1897,7 +1906,7 @@ func (v *EthereumKeeperPerformDataCheckerConsumer) Counter(ctx context.Context) return cnt, nil } -func (v *EthereumKeeperPerformDataCheckerConsumer) SetExpectedData(ctx context.Context, expectedData []byte) error { +func (v *EthereumKeeperPerformDataCheckerConsumer) SetExpectedData(_ context.Context, expectedData []byte) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -2041,31 +2050,23 @@ func (v *EthereumKeeperRegistrar) EncodeRegisterRequest(name string, email []byt common.HexToAddress(senderAddr), ) - if err != nil { - return nil, err - } - return req, nil - } else { - req, err := registrarABI.Pack( - "register", - name, - email, - common.HexToAddress(upkeepAddr), - gasLimit, - common.HexToAddress(adminAddr), - uint8(0), // trigger type - checkData, - []byte{}, // triggerConfig - []byte{}, // offchainConfig - amount, - common.HexToAddress(senderAddr), - ) - - if err != nil { - return nil, err - } - return req, nil + return req, err } + req, err := registrarABI.Pack( + "register", + name, + email, + common.HexToAddress(upkeepAddr), + gasLimit, + common.HexToAddress(adminAddr), + uint8(0), // trigger type + checkData, + []byte{}, // triggerConfig + []byte{}, // offchainConfig + amount, + common.HexToAddress(senderAddr), + ) + return req, err } registryABI, err := abi.JSON(strings.NewReader(keeper_registrar_wrapper1_2.KeeperRegistrarMetaData.ABI)) if err != nil { diff --git a/integration-tests/contracts/test_contracts.go b/integration-tests/contracts/test_contracts.go index ccdd2989e4..3080668da6 100644 --- a/integration-tests/contracts/test_contracts.go +++ b/integration-tests/contracts/test_contracts.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" diff --git a/integration-tests/docker/cmd/test_env.go b/integration-tests/docker/cmd/test_env.go index f760f45f8d..5fe2001350 100644 --- a/integration-tests/docker/cmd/test_env.go +++ b/integration-tests/docker/cmd/test_env.go @@ -9,10 +9,11 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/spf13/cobra" "github.com/testcontainers/testcontainers-go" + + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) func main() { @@ -31,7 +32,7 @@ func main() { Use: "cl-cluster", Short: "Basic CL cluster", RunE: func(cmd *cobra.Command, args []string) error { - utils.SetupCoreDockerEnvLogger() + log.Logger = logging.GetLogger(nil, "CORE_DOCKER_ENV_LOG_LEVEL") log.Info().Msg("Starting CL cluster test environment..") _, err := test_env.NewCLTestEnvBuilder(). diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 6e74e54a4f..3c0a6d3af7 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -1,15 +1,11 @@ package test_env import ( - "context" - "crypto/ed25519" - "encoding/hex" "fmt" "math/big" "net/url" "os" "strings" - "sync" "testing" "time" @@ -29,8 +25,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logwatch" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2/types" - "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/utils" @@ -118,7 +112,7 @@ func (n *ClNode) SetTestLogger(t *testing.T) { // Restart restarts only CL node, DB container is reused func (n *ClNode) Restart(cfg *chainlink.Config) error { - if err := n.Container.Terminate(context.Background()); err != nil { + if err := n.Container.Terminate(utils.TestContext(n.t)); err != nil { return err } n.NodeConfig = cfg @@ -126,7 +120,7 @@ func (n *ClNode) Restart(cfg *chainlink.Config) error { } // UpgradeVersion restarts the cl node with new image and version -func (n *ClNode) UpgradeVersion(cfg *chainlink.Config, newImage, newVersion string) error { +func (n *ClNode) UpgradeVersion(newImage, newVersion string) error { if newVersion == "" { return fmt.Errorf("new version is empty") } @@ -142,9 +136,9 @@ func (n *ClNode) PrimaryETHAddress() (string, error) { return n.API.PrimaryEthAddress() } -func (n *ClNode) AddBootstrapJob(verifierAddr common.Address, fromBlock uint64, chainId int64, +func (n *ClNode) AddBootstrapJob(verifierAddr common.Address, chainId int64, feedId [32]byte) (*client.Job, error) { - spec := utils.BuildBootstrapSpec(verifierAddr, chainId, fromBlock, feedId) + spec := utils.BuildBootstrapSpec(verifierAddr, chainId, feedId) return n.API.MustCreateJob(spec) } @@ -196,7 +190,7 @@ func (n *ClNode) AddMercuryOCRJob(verifierAddr common.Address, fromBlock uint64, } func (n *ClNode) GetContainerName() string { - name, err := n.Container.Name(context.Background()) + name, err := n.Container.Name(utils.TestContext(n.t)) if err != nil { return "" } @@ -288,15 +282,15 @@ func (n *ClNode) StartContainer() error { return fmt.Errorf("%s err: %w", ErrStartCLNodeContainer, err) } if n.lw != nil { - if err := n.lw.ConnectContainer(context.Background(), container, "cl-node", true); err != nil { + if err := n.lw.ConnectContainer(utils.TestContext(n.t), container, "cl-node", true); err != nil { return err } } - clEndpoint, err := test_env.GetEndpoint(context.Background(), container, "http") + clEndpoint, err := test_env.GetEndpoint(utils.TestContext(n.t), container, "http") if err != nil { return err } - ip, err := container.ContainerIP(context.Background()) + ip, err := container.ContainerIP(utils.TestContext(n.t)) if err != nil { return err } @@ -414,83 +408,3 @@ func (n *ClNode) getContainerRequest(secrets string) ( }, }, nil } - -func GetOracleIdentities(chainlinkNodes []*ClNode) ([]int, []confighelper.OracleIdentityExtra) { - S := make([]int, len(chainlinkNodes)) - oracleIdentities := make([]confighelper.OracleIdentityExtra, len(chainlinkNodes)) - sharedSecretEncryptionPublicKeys := make([]ocrtypes.ConfigEncryptionPublicKey, len(chainlinkNodes)) - var wg sync.WaitGroup - for i, cl := range chainlinkNodes { - wg.Add(1) - go func(i int, cl *ClNode) error { - defer wg.Done() - - ocr2Keys, err := cl.API.MustReadOCR2Keys() - if err != nil { - return err - } - var ocr2Config client.OCR2KeyAttributes - for _, key := range ocr2Keys.Data { - if key.Attributes.ChainType == string(chaintype.EVM) { - ocr2Config = key.Attributes - break - } - } - - keys, err := cl.API.MustReadP2PKeys() - if err != nil { - return err - } - p2pKeyID := keys.Data[0].Attributes.PeerID - - offchainPkBytes, err := hex.DecodeString(strings.TrimPrefix(ocr2Config.OffChainPublicKey, "ocr2off_evm_")) - if err != nil { - return err - } - - offchainPkBytesFixed := [ed25519.PublicKeySize]byte{} - copy(offchainPkBytesFixed[:], offchainPkBytes) - if err != nil { - return err - } - - configPkBytes, err := hex.DecodeString(strings.TrimPrefix(ocr2Config.ConfigPublicKey, "ocr2cfg_evm_")) - if err != nil { - return err - } - - configPkBytesFixed := [ed25519.PublicKeySize]byte{} - copy(configPkBytesFixed[:], configPkBytes) - if err != nil { - return err - } - - onchainPkBytes, err := hex.DecodeString(strings.TrimPrefix(ocr2Config.OnChainPublicKey, "ocr2on_evm_")) - if err != nil { - return err - } - - csaKeys, _, err := cl.API.ReadCSAKeys() - if err != nil { - return err - } - - sharedSecretEncryptionPublicKeys[i] = configPkBytesFixed - oracleIdentities[i] = confighelper.OracleIdentityExtra{ - OracleIdentity: confighelper.OracleIdentity{ - OnchainPublicKey: onchainPkBytes, - OffchainPublicKey: offchainPkBytesFixed, - PeerID: p2pKeyID, - TransmitAccount: ocrtypes.Account(csaKeys.Data[0].ID), - }, - ConfigEncryptionPublicKey: configPkBytesFixed, - } - S[i] = 1 - - return nil - }(i, cl) - } - wg.Wait() - - return S, oracleIdentities -} diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 4a30487211..9987bab2fe 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -1,7 +1,6 @@ package test_env import ( - "context" "encoding/json" "fmt" "io" @@ -53,7 +52,7 @@ type CLClusterTestEnv struct { } func NewTestEnv() (*CLClusterTestEnv, error) { - utils.SetupCoreDockerEnvLogger() + log.Logger = logging.GetLogger(nil, "CORE_DOCKER_ENV_LOG_LEVEL") network, err := docker.CreateNetwork(log.Logger) if err != nil { return nil, err @@ -267,7 +266,7 @@ func (te *CLClusterTestEnv) collectTestLogs() error { return err } defer logFile.Close() - logReader, err := node.Container.Logs(context.Background()) + logReader, err := node.Container.Logs(utils.TestContext(te.t)) if err != nil { return err } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index e97f869d64..77c5669015 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -188,7 +188,7 @@ func (b *CLTestEnvBuilder) WithCustomCleanup(customFn func()) *CLTestEnvBuilder type ChainOption = func(*evmcfg.Chain) *evmcfg.Chain func (b *CLTestEnvBuilder) WithChainOptions(opts ...ChainOption) *CLTestEnvBuilder { - b.chainOptionsFn = make([]ChainOption, 0, 0) + b.chainOptionsFn = make([]ChainOption, 0) b.chainOptionsFn = append(b.chainOptionsFn, opts...) return b @@ -197,7 +197,7 @@ func (b *CLTestEnvBuilder) WithChainOptions(opts ...ChainOption) *CLTestEnvBuild type EVMClientNetworkOption = func(*blockchain.EVMNetwork) *blockchain.EVMNetwork func (b *CLTestEnvBuilder) EVMClientNetworkOptions(opts ...EVMClientNetworkOption) *CLTestEnvBuilder { - b.evmClientNetworkOption = make([]EVMClientNetworkOption, 0, 0) + b.evmClientNetworkOption = make([]EVMClientNetworkOption, 0) b.evmClientNetworkOption = append(b.evmClientNetworkOption, opts...) return b diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go index 451d01a6c8..ad7e7446af 100644 --- a/integration-tests/load/functions/config.go +++ b/integration-tests/load/functions/config.go @@ -7,6 +7,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -118,8 +119,7 @@ func ReadConfig() (*PerformanceConfig, error) { return nil, fmt.Errorf( "ensure variables are set:\nMUMBAI_KEYS variable, private keys, comma separated\nSELECTED_NETWORKS=MUMBAI\nMUMBAI_URLS variable, websocket urls, comma separated", ) - } else { - cfg.MumbaiPrivateKey = mpk } + cfg.MumbaiPrivateKey = mpk return cfg, nil } diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index 7822035208..dc52846d3c 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -1,10 +1,11 @@ package loadfunctions import ( - "github.com/smartcontractkit/wasp" - "github.com/stretchr/testify/require" "testing" "time" + + "github.com/smartcontractkit/wasp" + "github.com/stretchr/testify/require" ) func TestFunctionsLoad(t *testing.T) { diff --git a/integration-tests/load/functions/gateway.go b/integration-tests/load/functions/gateway.go index 78b0f14cf1..ac5f895ac1 100644 --- a/integration-tests/load/functions/gateway.go +++ b/integration-tests/load/functions/gateway.go @@ -14,10 +14,11 @@ import ( "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/go-resty/resty/v2" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" ) type RPCResponse struct { @@ -115,7 +116,7 @@ func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) (uint8, uint64, erro log.Debug().Interface("Result", result).Msg("S4 secrets_set response result") for _, nodeResponse := range result.Result.Body.Payload.NodeResponses { if !nodeResponse.Body.Payload.Success { - return 0, 0, fmt.Errorf("node response was not succesful") + return 0, 0, fmt.Errorf("node response was not successful") } } return uint8(envelope.SlotID), envelope.Version, nil diff --git a/integration-tests/load/functions/gateway_gun.go b/integration-tests/load/functions/gateway_gun.go index fd13922d0a..3dafb458a5 100644 --- a/integration-tests/load/functions/gateway_gun.go +++ b/integration-tests/load/functions/gateway_gun.go @@ -3,14 +3,15 @@ package loadfunctions import ( "crypto/ecdsa" "fmt" - "github.com/go-resty/resty/v2" - "github.com/rs/zerolog/log" - "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" - "github.com/smartcontractkit/wasp" "math/rand" "os" "strconv" "time" + + "github.com/go-resty/resty/v2" + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" + "github.com/smartcontractkit/wasp" ) /* SingleFunctionCallGun is a gun that constantly requests randomness for one feed */ diff --git a/integration-tests/load/functions/onchain_monitoring.go b/integration-tests/load/functions/onchain_monitoring.go index 0a8b4cef46..c4b4bdb78c 100644 --- a/integration-tests/load/functions/onchain_monitoring.go +++ b/integration-tests/load/functions/onchain_monitoring.go @@ -1,10 +1,11 @@ package loadfunctions import ( - "github.com/rs/zerolog/log" - "github.com/smartcontractkit/wasp" "testing" "time" + + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/wasp" ) /* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ diff --git a/integration-tests/load/functions/request_gun.go b/integration-tests/load/functions/request_gun.go index d9987eaa75..bd4cf5f35a 100644 --- a/integration-tests/load/functions/request_gun.go +++ b/integration-tests/load/functions/request_gun.go @@ -13,16 +13,15 @@ const ( ) type SingleFunctionCallGun struct { - ft *FunctionsTest - mode TestMode - times uint32 - source string - slotID uint8 - slotVersion uint64 - encryptedSecrets []byte - args []string - subscriptionId uint64 - jobId [32]byte + ft *FunctionsTest + mode TestMode + times uint32 + source string + slotID uint8 + slotVersion uint64 + args []string + subscriptionId uint64 + jobId [32]byte } func NewSingleFunctionCallGun( diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index 81bc660b35..c0be47ca83 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -12,9 +12,10 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/go-resty/resty/v2" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" "github.com/smartcontractkit/chainlink/integration-tests/contracts" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/integration-tests/load/log_poller/log_poller_test.go b/integration-tests/load/log_poller/log_poller_test.go index ec67815832..04366848f0 100644 --- a/integration-tests/load/log_poller/log_poller_test.go +++ b/integration-tests/load/log_poller/log_poller_test.go @@ -5,8 +5,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" - lp_helpers "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" "github.com/stretchr/testify/require" + + lp_helpers "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" ) func TestLoadTestLogPoller(t *testing.T) { diff --git a/integration-tests/load/vrfv2/cmd/dashboard.go b/integration-tests/load/vrfv2/cmd/dashboard.go index 3035da0422..0fb7be2b78 100644 --- a/integration-tests/load/vrfv2/cmd/dashboard.go +++ b/integration-tests/load/vrfv2/cmd/dashboard.go @@ -1,6 +1,8 @@ package main import ( + "os" + "github.com/K-Phoen/grabana/dashboard" "github.com/K-Phoen/grabana/logs" "github.com/K-Phoen/grabana/row" @@ -8,7 +10,6 @@ import ( "github.com/K-Phoen/grabana/timeseries" "github.com/K-Phoen/grabana/timeseries/axis" "github.com/smartcontractkit/wasp" - "os" ) func main() { diff --git a/integration-tests/load/vrfv2/config.go b/integration-tests/load/vrfv2/config.go index 0c62cc351b..0a595f753c 100644 --- a/integration-tests/load/vrfv2/config.go +++ b/integration-tests/load/vrfv2/config.go @@ -7,6 +7,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index d6a8977738..8100baaa7f 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -1,9 +1,10 @@ package loadvrfv2 import ( + "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" - "github.com/smartcontractkit/wasp" ) /* SingleHashGun is a gun that constantly requests randomness for one feed */ @@ -21,7 +22,7 @@ func SingleFeedGun(contracts *vrfv2_actions.VRFV2Contracts, keyHash [32]byte) *S } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleHashGun) Call(l *wasp.Generator) *wasp.CallResult { +func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { err := m.contracts.LoadTestConsumer.RequestRandomness( m.keyHash, vrfConst.SubID, diff --git a/integration-tests/load/vrfv2/onchain_monitoring.go b/integration-tests/load/vrfv2/onchain_monitoring.go index b4503d27fa..879c7089e1 100644 --- a/integration-tests/load/vrfv2/onchain_monitoring.go +++ b/integration-tests/load/vrfv2/onchain_monitoring.go @@ -1,12 +1,14 @@ package loadvrfv2 import ( - "context" - "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - "github.com/smartcontractkit/wasp" "testing" "time" + + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) /* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ @@ -34,7 +36,7 @@ func MonitorLoadStats(t *testing.T, vrfv2Contracts *vrfv2_actions.VRFV2Contracts } for { time.Sleep(1 * time.Second) - metrics, err := vrfv2Contracts.LoadTestConsumer.GetLoadTestMetrics(context.Background()) + metrics, err := vrfv2Contracts.LoadTestConsumer.GetLoadTestMetrics(utils.TestContext(t)) if err != nil { log.Error().Err(err).Msg(ErrMetrics) } diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index a9fb80a72a..44325965bd 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -3,9 +3,10 @@ package loadvrfv2 import ( "testing" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" ) func TestVRFV2Load(t *testing.T) { diff --git a/integration-tests/load/vrfv2/vu.go b/integration-tests/load/vrfv2/vu.go index 4658388d40..7eb02ae330 100644 --- a/integration-tests/load/vrfv2/vu.go +++ b/integration-tests/load/vrfv2/vu.go @@ -4,11 +4,12 @@ import ( "fmt" "time" + "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/wasp" ) /* JobVolumeVU is a "virtual user" that creates a VRFv2 job and constantly requesting new randomness only for this job instance */ diff --git a/integration-tests/load/vrfv2plus/cmd/dashboard.go b/integration-tests/load/vrfv2plus/cmd/dashboard.go index 9a0ba682a1..049ee9ff2e 100644 --- a/integration-tests/load/vrfv2plus/cmd/dashboard.go +++ b/integration-tests/load/vrfv2plus/cmd/dashboard.go @@ -1,6 +1,8 @@ package main import ( + "os" + "github.com/K-Phoen/grabana/dashboard" "github.com/K-Phoen/grabana/logs" "github.com/K-Phoen/grabana/row" @@ -8,7 +10,6 @@ import ( "github.com/K-Phoen/grabana/timeseries" "github.com/K-Phoen/grabana/timeseries/axis" "github.com/smartcontractkit/wasp" - "os" ) func main() { diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index cba3fdcde5..96dbf99c6b 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -7,6 +7,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -100,6 +101,9 @@ func ReadConfig() (*PerformanceConfig, error) { } } else { d, err = base64.StdEncoding.DecodeString(rawConfig) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) + } } err = toml.Unmarshal(d, &cfg) if err != nil { diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index 21be1c74ca..8ab278b73e 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -1,12 +1,14 @@ package loadvrfv2plus import ( + "math/big" + "math/rand" + "github.com/rs/zerolog" + "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" - "github.com/smartcontractkit/wasp" - "math/big" - "math/rand" ) /* SingleHashGun is a gun that constantly requests randomness for one feed */ @@ -36,7 +38,7 @@ func NewSingleHashGun( } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleHashGun) Call(l *wasp.Generator) *wasp.CallResult { +func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { //todo - should work with multiple consumers and consumers having different keyhashes and wallets //randomly increase/decrease randomness request count per TX diff --git a/integration-tests/load/vrfv2plus/onchain_monitoring.go b/integration-tests/load/vrfv2plus/onchain_monitoring.go index c56d835234..c911546af0 100644 --- a/integration-tests/load/vrfv2plus/onchain_monitoring.go +++ b/integration-tests/load/vrfv2plus/onchain_monitoring.go @@ -2,11 +2,13 @@ package loadvrfv2plus import ( "context" - "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/wasp" "testing" "time" + + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) /* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 4d3de014bc..e7734fee0d 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -1,20 +1,22 @@ package loadvrfv2plus import ( - "context" - "github.com/ethereum/go-ethereum/common" - "github.com/kelseyhightower/envconfig" - "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/wasp" - "github.com/stretchr/testify/require" "math/big" "os" "sync" "testing" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/kelseyhightower/envconfig" + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/wasp" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + "github.com/smartcontractkit/chainlink/integration-tests/utils" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" @@ -97,7 +99,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { Str("Returning funds from SubID", subID.String()). Str("Returning funds to", eoaWalletAddress). Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subID) + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(utils.TestContext(t), subID) if err != nil { l.Error().Err(err).Msg("Error checking if pending requests exist") } @@ -228,7 +230,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) } diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index bf97f43d05..c851f36ec6 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -1,13 +1,12 @@ package migration import ( + "os" "testing" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/stretchr/testify/require" - "os" - + "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index e700a66e1f..7e90d29221 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -20,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink-testing-framework/networks" @@ -44,7 +43,7 @@ func CleanupPerformanceTest( if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, &testReporter, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, &testReporter, zapcore.PanicLevel, chainClient) require.NoError(t, err, "Error tearing down environment") } diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index d229f9fb3e..1a3f1d2a01 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -1,7 +1,6 @@ package performance import ( - "context" "fmt" "math/big" "strings" @@ -25,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/google/uuid" ) @@ -108,7 +108,7 @@ func TestDirectRequestPerformance(t *testing.T) { gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(context.Background()) + d, err := consumer.Data(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") l.Debug().Int64("Data", d.Int64()).Msg("Found on chain") diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index be536450a7..18b13ab907 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -1,7 +1,6 @@ package performance import ( - "context" "fmt" "math/big" "strings" @@ -26,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestFluxPerformance(t *testing.T) { @@ -83,7 +83,7 @@ func TestFluxPerformance(t *testing.T) { require.NoError(t, err, "Setting oracle options in the Flux Aggregator contract shouldn't fail") err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - oracles, err := fluxInstance.GetOracles(context.Background()) + oracles, err := fluxInstance.GetOracles(utils.TestContext(t)) require.NoError(t, err, "Getting oracle details from the Flux aggregator contract shouldn't fail") l.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") @@ -120,7 +120,7 @@ func TestFluxPerformance(t *testing.T) { chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err := fluxInstance.GetContractData(context.Background()) + data, err := fluxInstance.GetContractData(utils.TestContext(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") l.Info().Interface("Data", data).Msg("Round data") require.Equal(t, int64(1e5), data.LatestRoundData.Answer.Int64(), @@ -140,7 +140,7 @@ func TestFluxPerformance(t *testing.T) { require.NoError(t, err, "Setting value path in mock server shouldn't fail") err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err = fluxInstance.GetContractData(context.Background()) + data, err = fluxInstance.GetContractData(utils.TestContext(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") require.Equal(t, int64(1e10), data.LatestRoundData.Answer.Int64(), "Expected latest round answer to be %d, but found %d", int64(1e10), data.LatestRoundData.Answer.Int64()) @@ -153,7 +153,7 @@ func TestFluxPerformance(t *testing.T) { l.Info().Interface("data", data).Msg("Round data") for _, oracleAddr := range nodeAddresses { - payment, _ := fluxInstance.WithdrawablePayment(context.Background(), oracleAddr) + payment, _ := fluxInstance.WithdrawablePayment(utils.TestContext(t), oracleAddr) require.Equal(t, int64(2), payment.Int64(), "Expected flux aggregator contract's withdrawable payment to be %d, but found %d", int64(2), payment.Int64()) } diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index cd9818f99d..8e273a96f6 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -2,7 +2,6 @@ package performance //revive:disable:dot-imports import ( - "context" "fmt" "math/big" "strings" @@ -26,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var keeperDefaultRegistryConfig = contracts.KeeperRegistrySettings{ @@ -74,7 +74,7 @@ func TestKeeperPerformance(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) @@ -84,7 +84,7 @@ func TestKeeperPerformance(t *testing.T) { // Cancel all the registered upkeeps via the registry for i := 0; i < len(upkeepIDs); i++ { - err := registry.CancelUpkeep(upkeepIDs[i]) + err = registry.CancelUpkeep(upkeepIDs[i]) require.NoError(t, err, "Could not cancel upkeep at index %d", i) } @@ -95,7 +95,7 @@ func TestKeeperPerformance(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(context.Background()) + countersAfterCancellation[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Index", i).Int64("Upkeeps Performed", countersAfterCancellation[i].Int64()).Msg("Cancelled Upkeep") } @@ -103,7 +103,7 @@ func TestKeeperPerformance(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant because the upkeep was cancelled, so it shouldn't increase anymore - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterCancellation[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index e81cc91cf7..47879cebb8 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -1,7 +1,6 @@ package performance import ( - "context" "fmt" "math/big" "strings" @@ -25,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCRBasic(t *testing.T) { @@ -53,7 +53,7 @@ func TestOCRBasic(t *testing.T) { err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.05)) require.NoError(t, err, "Error funding Chainlink nodes") - ocrInstances, err := actions.DeployOCRContracts(1, linkTokenContract, contractDeployer, bootstrapNode, workerNodes, chainClient) + ocrInstances, err := actions.DeployOCRContracts(1, linkTokenContract, contractDeployer, workerNodes, chainClient) require.NoError(t, err) err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -64,7 +64,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(1, ocrInstances, chainClient, l) require.NoError(t, err) - answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) @@ -73,7 +73,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(2, ocrInstances, chainClient, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index eeaceffaaf..7a38a45495 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -1,7 +1,6 @@ package performance import ( - "context" "fmt" "math/big" "strings" @@ -23,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestVRFBasic(t *testing.T) { @@ -97,7 +97,7 @@ func TestVRFBasic(t *testing.T) { encodedProvingKeys := make([][2]*big.Int, 0) encodedProvingKeys = append(encodedProvingKeys, provingKey) - requestHash, err := coordinator.HashOfKey(context.Background(), encodedProvingKeys[0]) + requestHash, err := coordinator.HashOfKey(utils.TestContext(t), encodedProvingKeys[0]) require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") err = consumer.RequestRandomness(requestHash, big.NewInt(1)) require.NoError(t, err, "Requesting randomness shouldn't fail") @@ -108,7 +108,7 @@ func TestVRFBasic(t *testing.T) { jobRuns, err := chainlinkNodes[0].MustReadRunsByJob(job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - out, err := consumer.RandomnessOutput(context.Background()) + out, err := consumer.RandomnessOutput(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") // Checks that the job has actually run g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index 697ae28ce3..58cd147201 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -2,7 +2,6 @@ package reorg //revive:disable:dot-imports import ( - "context" "fmt" "math/big" "testing" @@ -19,12 +18,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -133,6 +132,8 @@ func TestAutomationReorg(t *testing.T) { } for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() network := networks.MustGetSelectedNetworksFromEnv()[0] @@ -167,7 +168,7 @@ func TestAutomationReorg(t *testing.T) { // Register cleanup for any test t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -209,7 +210,7 @@ func TestAutomationReorg(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(it_utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") @@ -240,7 +241,7 @@ func TestAutomationReorg(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(it_utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 10 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") @@ -250,13 +251,14 @@ func TestAutomationReorg(t *testing.T) { }, "5m", "1s").Should(gomega.Succeed()) l.Info().Msg("Upkeep performed during unstable chain, waiting for reorg to finish") - rc.WaitDepthReached() + err = rc.WaitDepthReached() + require.NoError(t, err) l.Info().Msg("Reorg finished, chain should be stable now. Expecting upkeeps to keep getting performed") gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 20 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(it_utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 20 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") diff --git a/integration-tests/reorg/log_poller_maybe_reorg_test.go b/integration-tests/reorg/log_poller_maybe_reorg_test.go index 0176fdbbdd..d319e39aa2 100644 --- a/integration-tests/reorg/log_poller_maybe_reorg_test.go +++ b/integration-tests/reorg/log_poller_maybe_reorg_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/accounts/abi" + logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" ) diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go index f92becfa50..d5fefdbc56 100644 --- a/integration-tests/reorg/reorg_test.go +++ b/integration-tests/reorg/reorg_test.go @@ -1,7 +1,6 @@ package reorg import ( - "context" "fmt" "math/big" "os" @@ -22,15 +21,16 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/onsi/gomega" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) const ( @@ -85,7 +85,7 @@ func CleanupReorgTest( if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) require.NoError(t, err, "Error tearing down environment") } @@ -221,7 +221,7 @@ func TestDirectRequestReorg(t *testing.T) { gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(context.Background()) + d, err := consumer.Data(it_utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") log.Debug().Int64("Data", d.Int64()).Msg("Found on chain") diff --git a/integration-tests/runner_helpers.go b/integration-tests/runner_helpers.go index 43268a703a..def2ebdc1d 100644 --- a/integration-tests/runner_helpers.go +++ b/integration-tests/runner_helpers.go @@ -122,7 +122,7 @@ func collectBranchesAndTags(results chan []string, errChan chan error) { go func() { stdOut, stdErr, err := gh.Exec("api", fmt.Sprintf("repos/%s/branches", chainlinkRepo), "-q", ".[][\"name\"]", "--paginate") if err != nil { - errChan <- fmt.Errorf("%v: %s", err, stdErr.String()) + errChan <- fmt.Errorf("%w: %s", err, stdErr.String()) } branches := strings.Split(stdOut.String(), "\n") cleanBranches := []string{} @@ -139,7 +139,7 @@ func collectBranchesAndTags(results chan []string, errChan chan error) { go func() { stdOut, stdErr, err := gh.Exec("api", fmt.Sprintf("repos/%s/tags", chainlinkRepo), "-q", ".[][\"name\"]", "--paginate") if err != nil { - errChan <- fmt.Errorf("%v: %s", err, stdErr.String()) + errChan <- fmt.Errorf("%w: %s", err, stdErr.String()) } tags := strings.Split(stdOut.String(), "\n") cleanTags := []string{} diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 4f969c5d68..1a093a8815 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "encoding/json" "fmt" "math/big" @@ -32,7 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) @@ -110,7 +109,6 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { upgradeImage string upgradeVersion string err error - testName = "basic-upkeep" ) if nodeUpgrade { upgradeImage = os.Getenv("UPGRADE_IMAGE") @@ -118,7 +116,6 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { if len(upgradeImage) == 0 || len(upgradeVersion) == 0 { t.Fatal("UPGRADE_IMAGE and UPGRADE_VERSION must be set to upgrade nodes") } - testName = "node-upgrade" } // Use the name to determine if this is a log trigger or mercury @@ -128,7 +125,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { isMercury := isMercuryV02 || isMercuryV03 chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupAutomationTestDocker( - t, testName, registryVersion, defaultOCRRegistryConfig, nodeUpgrade, isMercuryV02, isMercuryV03, + t, registryVersion, defaultOCRRegistryConfig, isMercuryV02, isMercuryV03, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -172,7 +169,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") @@ -187,13 +184,14 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { expect := 5 // Upgrade the nodes one at a time and check that the upkeeps are still being performed for i := 0; i < 5; i++ { - actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, testEnv.ClCluster.Nodes[i]) + err = actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, testEnv.ClCluster.Nodes[i]) + require.NoError(t, err, "Error when upgrading node %d", i) time.Sleep(time.Second * 10) expect = expect + 5 gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are increasing by 5 in each step within 5 minutes for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), @@ -216,7 +214,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(context.Background()) + countersAfterCancellation[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeep Count", countersAfterCancellation[i].Int64()).Int("Upkeep Index", i).Msg("Cancelled upkeep") } @@ -225,7 +223,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant (At most increase by 1 to account for stale performs) because the upkeep was cancelled - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterCancellation[i].Int64()+1), "Expected consumer counter to remain less than or equal to %d, but got %d", @@ -241,7 +239,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "set-trigger-config", ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, false, false, + t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, false, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -271,7 +269,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") @@ -328,7 +326,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { time.Sleep(10 * time.Second) for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterSetNoMatch[i], err = consumers[i].Counter(context.Background()) + countersAfterSetNoMatch[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeep Count", countersAfterSetNoMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") } @@ -338,7 +336,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant (At most increase by 2 to account for stale performs) because the upkeep trigger config is not met bufferCount := int64(2) - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterSetNoMatch[i].Int64()+bufferCount), "Expected consumer counter to remain less than or equal to %d, but got %d", @@ -374,7 +372,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterSetMatch[i], err = consumers[i].Counter(context.Background()) + countersAfterSetMatch[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeep Count", countersAfterSetMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") } @@ -393,7 +391,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := int64(5) l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") @@ -416,7 +414,7 @@ func TestAutomationAddFunds(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "add-funds", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(1), automationDefaultUpkeepGasLimit, false, false) @@ -424,7 +422,7 @@ func TestAutomationAddFunds(t *testing.T) { gom := gomega.NewGomegaWithT(t) // Since the upkeep is currently underfunded, check that it doesn't get executed gom.Consistently(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(context.Background()) + counter, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), "Expected consumer counter to remain zero, but got %d", counter.Int64()) @@ -444,7 +442,7 @@ func TestAutomationAddFunds(t *testing.T) { // Now the new upkeep should be performing because we added enough funds gom.Eventually(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(context.Background()) + counter, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -467,7 +465,7 @@ func TestAutomationPauseUnPause(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "pause-unpause", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) @@ -476,7 +474,7 @@ func TestAutomationPauseUnPause(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)), "Expected consumer counter to be greater than 5, but got %d", counter.Int64()) @@ -496,7 +494,7 @@ func TestAutomationPauseUnPause(t *testing.T) { var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterPause[i], err = consumers[i].Counter(context.Background()) + countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Upkeep Index", i).Int64("Upkeeps Performed", countersAfterPause[i].Int64()).Msg("Paused Upkeep") } @@ -505,7 +503,7 @@ func TestAutomationPauseUnPause(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // In most cases counters should remain constant, but there might be a straggling perform tx which // gets committed later and increases counter by 1 - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterPause[i].Int64()+1), "Expected consumer counter not have increased more than %d, but got %d", @@ -525,7 +523,7 @@ func TestAutomationPauseUnPause(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 + numbers of performing before pause for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", countersAfterPause[i].Int64()+1), "Expected consumer counter to be greater than %d, but got %d", countersAfterPause[i].Int64()+1, counter.Int64()) @@ -550,7 +548,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "register-upkeep", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) @@ -561,7 +559,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { // store the value of their initial counters in order to compare later on that the value increased. gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -581,7 +579,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { // Test that the newly registered upkeep is also performing. gom.Eventually(func(g gomega.Gomega) { - counter, err := newUpkeep.Counter(context.Background()) + counter, err := newUpkeep.Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling newly deployed upkeep's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -590,7 +588,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(context.Background()) + currentCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info(). @@ -621,7 +619,7 @@ func TestAutomationPauseRegistry(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "pause-registry", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) @@ -630,7 +628,7 @@ func TestAutomationPauseRegistry(t *testing.T) { // Observe that the upkeeps which are initially registered are performing gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d") @@ -646,7 +644,7 @@ func TestAutomationPauseRegistry(t *testing.T) { // Store how many times each upkeep performed once the registry was successfully paused var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterPause[i], err = consumers[i].Counter(context.Background()) + countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) } @@ -654,7 +652,7 @@ func TestAutomationPauseRegistry(t *testing.T) { // because they are no longer getting serviced gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterPause[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", @@ -679,7 +677,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "keeper-nodes-down", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) @@ -691,7 +689,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // Watch upkeeps being performed and store their counters in order to compare them later in the test gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -710,7 +708,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // Assert that upkeeps are still performed and their counters have increased gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(context.Background()) + currentCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(currentCounter.Int64()).Should(gomega.BeNumerically(">", initialCounters[i].Int64()), "Expected counter to have increased from initial value of %s, but got %s", @@ -731,7 +729,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // See how many times each upkeep was executed var countersAfterNoMoreNodes = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterNoMoreNodes[i], err = consumers[i].Counter(context.Background()) + countersAfterNoMoreNodes[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Upkeep Index", i).Int64("Performed", countersAfterNoMoreNodes[i].Int64()).Msg("Upkeeps Performed") } @@ -740,7 +738,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // all the nodes were taken down gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterNoMoreNodes[i].Int64()+1), "Expected consumer counter to not have increased more than %d, but got %d", @@ -764,7 +762,7 @@ func TestAutomationPerformSimulation(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "perform-simulation", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) consumersPerformance, _ := actions.DeployPerformanceConsumers( @@ -789,7 +787,7 @@ func TestAutomationPerformSimulation(t *testing.T) { // Initially performGas is set high, so performUpkeep reverts and no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { // Consumer count should remain at 0 - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.Equal(int64(0)), "Expected consumer counter to remain constant at %d, but got %d", 0, cnt.Int64(), @@ -797,14 +795,14 @@ func TestAutomationPerformSimulation(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Set performGas on consumer to be low, so that performUpkeep starts becoming successful - err := consumerPerformance.SetPerformGasToBurn(context.Background(), big.NewInt(100000)) + err := consumerPerformance.SetPerformGasToBurn(utils.TestContext(t), big.NewInt(100000)) require.NoError(t, err, "Perform gas should be set successfully on consumer") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for set perform gas tx") // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -828,7 +826,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "gas-limit", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( @@ -854,7 +852,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { // Initially performGas is set higher than defaultUpkeepGasLimit, so no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.Equal(int64(0)), @@ -870,7 +868,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -878,19 +876,19 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m to perform once, 1m buffer // Now increase the checkGasBurn on consumer, upkeep should stop performing - err = consumerPerformance.SetCheckGasToBurn(context.Background(), big.NewInt(3000000)) + err = consumerPerformance.SetCheckGasToBurn(utils.TestContext(t), big.NewInt(3000000)) require.NoError(t, err, "Check gas burn should be set successfully on consumer") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetCheckGasToBurn tx") // Get existing performed count - existingCnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + existingCnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) require.NoError(t, err, "Calling consumer's counter shouldn't fail") l.Info().Int64("Upkeep counter", existingCnt.Int64()).Msg("Upkeep counter when check gas increased") // In most cases count should remain constant, but it might increase by upto 1 due to pending perform gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.BeNumerically("<=", existingCnt.Int64()+1), @@ -898,7 +896,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { ) }, "1m", "1s").Should(gomega.Succeed()) - existingCnt, err = consumerPerformance.GetUpkeepCount(context.Background()) + existingCnt, err = consumerPerformance.GetUpkeepCount(utils.TestContext(t)) require.NoError(t, err, "Calling consumer's counter shouldn't fail") existingCntInt := existingCnt.Int64() l.Info().Int64("Upkeep counter", existingCntInt).Msg("Upkeep counter when consistently block finished") @@ -918,7 +916,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { // Upkeep should start performing again, and it should get regularly performed gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", existingCntInt), "Expected consumer counter to be greater than %d, but got %d", existingCntInt, cnt.Int64(), @@ -942,7 +940,7 @@ func TestUpdateCheckData(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "update-check-data", registryVersion, defaultOCRRegistryConfig, false, false, false, + t, registryVersion, defaultOCRRegistryConfig, false, false, ) performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( @@ -962,7 +960,7 @@ func TestUpdateCheckData(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { // expect the counter to remain 0 because perform data does not match for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(context.Background()) + counter, err := performDataChecker[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker"+ " for upkeep at index "+strconv.Itoa(i)) g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), @@ -981,7 +979,7 @@ func TestUpdateCheckData(t *testing.T) { // retrieve new check data for all upkeeps for i := 0; i < len(upkeepIDs); i++ { - upkeep, err := registry.GetUpkeepInfo(context.Background(), upkeepIDs[i]) + upkeep, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepIDs[i]) require.NoError(t, err, "Failed to get upkeep info at index %d", i) require.Equal(t, []byte(automationExpectedData), upkeep.CheckData, "Upkeep data not as expected") } @@ -989,7 +987,7 @@ func TestUpdateCheckData(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(context.Background()) + counter, err := performDataChecker[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker counter"+ " for upkeep at index "+strconv.Itoa(i)) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -1007,10 +1005,8 @@ type TestConfig struct { func setupAutomationTestDocker( t *testing.T, - testName string, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, - statefulDb bool, isMercuryV02 bool, isMercuryV03 bool, ) ( @@ -1032,11 +1028,11 @@ func setupAutomationTestDocker( // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) syncInterval := models.MustMakeDuration(5 * time.Minute) - clNodeConfig.Feature.LogPoller = it_utils.Ptr[bool](true) - clNodeConfig.OCR2.Enabled = it_utils.Ptr[bool](true) - clNodeConfig.Keeper.TurnLookBack = it_utils.Ptr[int64](int64(0)) + clNodeConfig.Feature.LogPoller = utils.Ptr[bool](true) + clNodeConfig.OCR2.Enabled = utils.Ptr[bool](true) + clNodeConfig.Keeper.TurnLookBack = utils.Ptr[int64](int64(0)) clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval - clNodeConfig.Keeper.Registry.PerformGasOverhead = it_utils.Ptr[uint32](uint32(150000)) + clNodeConfig.Keeper.Registry.PerformGasOverhead = utils.Ptr[uint32](uint32(150000)) clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} @@ -1086,11 +1082,13 @@ func setupAutomationTestDocker( if isMercuryV02 { output := `{"chainlinkBlob":"0x0001c38d71fed6c320b90e84b6f559459814d068e2a1700adc931ca9717d4fe70000000000000000000000000000000000000000000000000000000001a80b52b4bf1233f9cb71144a253a1791b202113c4ab4a92fa1b176d684b4959666ff8200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004254432d5553442d415242495452554d2d544553544e4554000000000000000000000000000000000000000000000000000000000000000000000000645570be000000000000000000000000000000000000000000000000000002af2b818dc5000000000000000000000000000000000000000000000000000002af2426faf3000000000000000000000000000000000000000000000000000002af32dc209700000000000000000000000000000000000000000000000000000000012130f8df0a9745bb6ad5e2df605e158ba8ad8a33ef8a0acf9851f0f01668a3a3f2b68600000000000000000000000000000000000000000000000000000000012130f60000000000000000000000000000000000000000000000000000000000000002c4a7958dce105089cf5edb68dad7dcfe8618d7784eb397f97d5a5fade78c11a58275aebda478968e545f7e3657aba9dcbe8d44605e4c6fde3e24edd5e22c94270000000000000000000000000000000000000000000000000000000000000002459c12d33986018a8959566d145225f0c4a4e61a9a3f50361ccff397899314f0018162cf10cd89897635a0bb62a822355bd199d09f4abe76e4d05261bb44733d"}` - env.MockAdapter.SetStringValuePath("/client", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) + err = env.MockAdapter.SetStringValuePath("/client", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) + require.NoError(t, err) } if isMercuryV03 { output := `{"reports":[{"feedID":"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000","validFromTimestamp":0,"observationsTimestamp":0,"fullReport":"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}]}` - env.MockAdapter.SetStringValuePath("/api/v1/reports/bulk", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) + err = env.MockAdapter.SetStringValuePath("/api/v1/reports/bulk", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) + require.NoError(t, err) } } else { env, err = test_env.NewCLTestEnvBuilder(). diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 8c2b3638bf..2997ff1c74 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "net/http" @@ -19,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestFluxBasic(t *testing.T) { @@ -74,7 +74,7 @@ func TestFluxBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - oracles, err := fluxInstance.GetOracles(context.Background()) + oracles, err := fluxInstance.GetOracles(utils.TestContext(t)) require.NoError(t, err, "Getting oracle details from the Flux aggregator contract shouldn't fail") l.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") @@ -108,7 +108,7 @@ func TestFluxBasic(t *testing.T) { env.EVMClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err := fluxInstance.GetContractData(context.Background()) + data, err := fluxInstance.GetContractData(utils.TestContext(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") require.Equal(t, int64(1e5), data.LatestRoundData.Answer.Int64(), "Expected latest round answer to be %d, but found %d", int64(1e5), data.LatestRoundData.Answer.Int64()) @@ -127,7 +127,7 @@ func TestFluxBasic(t *testing.T) { require.NoError(t, err, "Setting value path in mock server shouldn't fail") err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err = fluxInstance.GetContractData(context.Background()) + data, err = fluxInstance.GetContractData(utils.TestContext(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") require.Equal(t, int64(1e10), data.LatestRoundData.Answer.Int64(), "Expected latest round answer to be %d, but found %d", int64(1e10), data.LatestRoundData.Answer.Int64()) @@ -140,7 +140,7 @@ func TestFluxBasic(t *testing.T) { l.Info().Interface("data", data).Msg("Round data") for _, oracleAddr := range nodeAddresses { - payment, _ := fluxInstance.WithdrawablePayment(context.Background(), oracleAddr) + payment, _ := fluxInstance.WithdrawablePayment(utils.TestContext(t), oracleAddr) require.Equal(t, int64(2), payment.Int64(), "Expected flux aggregator contract's withdrawable payment to be %d, but found %d", int64(2), payment.Int64()) } diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index 727b83a601..7203e03178 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "math/big" "testing" @@ -12,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestForwarderOCRBasic(t *testing.T) { @@ -72,7 +72,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) @@ -83,7 +83,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - answer, err = ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index baa5a781f6..be87eb5629 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "net/http" @@ -17,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestForwarderOCR2Basic(t *testing.T) { @@ -92,7 +92,7 @@ func TestForwarderOCR2Basic(t *testing.T) { err = actions.StartNewOCR2Round(1, ocrInstances, env.EVMClient, time.Minute*10, l) require.NoError(t, err) - answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Getting latest answer from OCRv2 contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCRw contract to be 5 but got %d", answer.Int64()) @@ -103,7 +103,7 @@ func TestForwarderOCR2Basic(t *testing.T) { err = actions.StartNewOCR2Round(int64(i), ocrInstances, env.EVMClient, time.Minute*10, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Error getting latest OCRv2 answer") require.Equal(t, int64(ocrRoundVal), answer.Int64(), fmt.Sprintf("Expected latest answer from OCRv2 contract to be %d but got %d", ocrRoundVal, answer.Int64())) } diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index d42944fd55..b28ab1ff10 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "strconv" @@ -23,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) const ( @@ -109,7 +109,7 @@ func TestKeeperBasicSmoke(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) @@ -131,7 +131,7 @@ func TestKeeperBasicSmoke(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(context.Background()) + countersAfterCancellation[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Index", i).Int64("Upkeeps Performed", countersAfterCancellation[i].Int64()).Msg("Cancelled Upkeep") } @@ -139,7 +139,7 @@ func TestKeeperBasicSmoke(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant because the upkeep was cancelled, so it shouldn't increase anymore - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterCancellation[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", @@ -187,11 +187,11 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { // Wait for upkeep to be performed twice by different keepers (buddies) gom.Eventually(func(g gomega.Gomega) error { - counter, err := consumers[0].Counter(context.Background()) + counter, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Number of upkeeps performed") - upkeepInfo, err := registry.GetUpkeepInfo(context.Background(), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -205,7 +205,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { }, "1m", "1s").Should(gomega.Succeed()) gom.Eventually(func(g gomega.Gomega) error { - upkeepInfo, err := registry.GetUpkeepInfo(context.Background(), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -219,7 +219,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { // Expect no new keepers to perform for a while gom.Consistently(func(g gomega.Gomega) { - upkeepInfo, err := registry.GetUpkeepInfo(context.Background(), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -235,11 +235,11 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { // Expect a new keeper to perform gom.Eventually(func(g gomega.Gomega) error { - counter, err := consumers[0].Counter(context.Background()) + counter, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Num upkeeps performed") - upkeepInfo, err := registry.GetUpkeepInfo(context.Background(), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -296,7 +296,7 @@ func TestKeeperSimulation(t *testing.T) { // Initially performGas is set high, so performUpkeep reverts and no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { // Consumer count should remain at 0 - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.Equal(int64(0)), @@ -304,20 +304,20 @@ func TestKeeperSimulation(t *testing.T) { ) // Not even reverted upkeeps should be performed. Last keeper for the upkeep should be 0 address - upkeepInfo, err := registry.GetUpkeepInfo(context.Background(), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") g.Expect(upkeepInfo.LastKeeper).Should(gomega.Equal(actions.ZeroAddress.String()), "Last keeper should be zero address") }, "1m", "1s").Should(gomega.Succeed()) // Set performGas on consumer to be low, so that performUpkeep starts becoming successful - err = consumerPerformance.SetPerformGasToBurn(context.Background(), big.NewInt(100000)) + err = consumerPerformance.SetPerformGasToBurn(utils.TestContext(t), big.NewInt(100000)) require.NoError(t, err, "Error setting PerformGasToBurn") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting to set PerformGasToBurn") // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) error { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -368,7 +368,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // Initially performGas is set higher than defaultUpkeepGasLimit, so no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.Equal(int64(0)), @@ -384,7 +384,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) error { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -393,13 +393,13 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { }, "1m", "1s").Should(gomega.Succeed()) // Now increase the checkGasBurn on consumer, upkeep should stop performing - err = consumerPerformance.SetCheckGasToBurn(context.Background(), big.NewInt(3000000)) + err = consumerPerformance.SetCheckGasToBurn(utils.TestContext(t), big.NewInt(3000000)) require.NoError(t, err, "Error setting CheckGasToBurn") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetCheckGasToBurn tx") // Get existing performed count - existingCnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + existingCnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) require.NoError(t, err, "Error calling consumer's counter") l.Info().Int64("Upkeep counter", existingCnt.Int64()).Msg("Check Gas Increased") @@ -407,7 +407,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // gets committed later. Since every keeper node cannot have more than 1 straggling tx, it // is sufficient to check that the upkeep count does not increase by more than 6. gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.BeNumerically("<=", existingCnt.Int64()+numUpkeepsAllowedForStragglingTxs), @@ -415,7 +415,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { ) }, "3m", "1s").Should(gomega.Succeed()) - existingCnt, err = consumerPerformance.GetUpkeepCount(context.Background()) + existingCnt, err = consumerPerformance.GetUpkeepCount(utils.TestContext(t)) require.NoError(t, err, "Error calling consumer's counter") existingCntInt := existingCnt.Int64() l.Info().Int64("Upkeep counter", existingCntInt).Msg("Upkeep counter when consistently block finished") @@ -430,7 +430,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // Upkeep should start performing again, and it should get regularly performed gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(context.Background()) + cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", existingCntInt), "Expected consumer counter to be greater than %d, but got %d", existingCntInt, cnt.Int64(), @@ -478,7 +478,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { // store the value of their initial counters in order to compare later on that the value increased. gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter"+ " for upkeep at index "+strconv.Itoa(i)) @@ -500,7 +500,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { // Test that the newly registered upkeep is also performing. gom.Eventually(func(g gomega.Gomega) error { - counter, err := newUpkeep.Counter(context.Background()) + counter, err := newUpkeep.Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling newly deployed upkeep's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -510,7 +510,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(context.Background()) + currentCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info(). @@ -563,7 +563,7 @@ func TestKeeperAddFunds(t *testing.T) { // Since the upkeep is currently underfunded, check that it doesn't get executed gom.Consistently(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(context.Background()) + counter, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), "Expected consumer counter to remain zero, but got %d", counter.Int64()) @@ -583,7 +583,7 @@ func TestKeeperAddFunds(t *testing.T) { // Now the new upkeep should be performing because we added enough funds gom.Eventually(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(context.Background()) + counter, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -628,7 +628,7 @@ func TestKeeperRemove(t *testing.T) { // Make sure the upkeeps are running before we remove a keeper gom.Eventually(func(g gomega.Gomega) error { for upkeepID := 0; upkeepID < len(upkeepIDs); upkeepID++ { - counter, err := consumers[upkeepID].Counter(context.Background()) + counter, err := consumers[upkeepID].Counter(utils.TestContext(t)) initialCounters[upkeepID] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter"+ " for upkeep with ID "+strconv.Itoa(upkeepID)) @@ -637,7 +637,7 @@ func TestKeeperRemove(t *testing.T) { return nil }, "1m", "1s").Should(gomega.Succeed()) - keepers, err := registry.GetKeeperList(context.Background()) + keepers, err := registry.GetKeeperList(utils.TestContext(t)) require.NoError(t, err, "Error getting list of Keepers") // Remove the first keeper from the list @@ -660,7 +660,7 @@ func TestKeeperRemove(t *testing.T) { // The upkeeps should still perform and their counters should have increased compared to the first check gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Cmp(initialCounters[i]) == 1, "Expected consumer counter to be greater "+ "than initial counter which was %s, but got %s", initialCounters[i], counter) @@ -705,7 +705,7 @@ func TestKeeperPauseRegistry(t *testing.T) { // Observe that the upkeeps which are initially registered are performing gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d") @@ -722,7 +722,7 @@ func TestKeeperPauseRegistry(t *testing.T) { // Store how many times each upkeep performed once the registry was successfully paused var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterPause[i], err = consumers[i].Counter(context.Background()) + countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Error retrieving consumer at index %d", i) } @@ -730,7 +730,7 @@ func TestKeeperPauseRegistry(t *testing.T) { // because they are no longer getting serviced gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Error retrieving consumer contract at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterPause[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", @@ -791,7 +791,7 @@ func TestKeeperMigrateRegistry(t *testing.T) { // Check that the first upkeep from the first registry is performing (before being migrated) gom.Eventually(func(g gomega.Gomega) error { - counterBeforeMigration, err := consumers[0].Counter(context.Background()) + counterBeforeMigration, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counterBeforeMigration.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %s", counterBeforeMigration) @@ -810,12 +810,12 @@ func TestKeeperMigrateRegistry(t *testing.T) { err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting to pause first registry") - counterAfterMigration, err := consumers[0].Counter(context.Background()) + counterAfterMigration, err := consumers[0].Counter(utils.TestContext(t)) require.NoError(t, err, "Error calling consumer's counter") // Check that once we migrated the upkeep, the counter has increased gom.Eventually(func(g gomega.Gomega) error { - currentCounter, err := consumers[0].Counter(context.Background()) + currentCounter, err := consumers[0].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(currentCounter.Int64()).Should(gomega.BeNumerically(">", counterAfterMigration.Int64()), "Expected counter to have increased, but stayed constant at %s", counterAfterMigration) @@ -860,7 +860,7 @@ func TestKeeperNodeDown(t *testing.T) { // Watch upkeeps being performed and store their counters in order to compare them later in the test gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -882,7 +882,7 @@ func TestKeeperNodeDown(t *testing.T) { // Assert that upkeeps are still performed and their counters have increased gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(context.Background()) + currentCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(currentCounter.Int64()).Should(gomega.BeNumerically(">", initialCounters[i].Int64()), "Expected counter to have increased from initial value of %s, but got %s", @@ -908,7 +908,7 @@ func TestKeeperNodeDown(t *testing.T) { // See how many times each upkeep was executed var countersAfterNoMoreNodes = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterNoMoreNodes[i], err = consumers[i].Counter(context.Background()) + countersAfterNoMoreNodes[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Error retrieving consumer counter %d", i) l.Info(). Int("Index", i). @@ -921,7 +921,7 @@ func TestKeeperNodeDown(t *testing.T) { // so a +6 on the upper limit side should be sufficient. gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterNoMoreNodes[i].Int64()+numUpkeepsAllowedForStragglingTxs, @@ -964,7 +964,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)), "Expected consumer counter to be greater than 5, but got %d", counter.Int64()) @@ -985,7 +985,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterPause[i], err = consumers[i].Counter(context.Background()) + countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Error retrieving upkeep count at index %d", i) l.Info(). Int("Index", i). @@ -998,7 +998,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { // In most cases counters should remain constant, but there might be a straggling perform tx which // gets committed later. Since every keeper node cannot have more than 1 straggling tx, it // is sufficient to check that the upkeep count does not increase by more than 6. - latestCounter, err := consumers[i].Counter(context.Background()) + latestCounter, err := consumers[i].Counter(utils.TestContext(t)) require.NoError(t, err, "Error retrieving counter at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterPause[i].Int64()+numUpkeepsAllowedForStragglingTxs), "Expected consumer counter not have increased more than %d, but got %d", @@ -1018,7 +1018,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 + numbers of performing before pause for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) + counter, err := consumers[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter"+ " for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)+countersAfterPause[i].Int64()), @@ -1055,7 +1055,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { // expect the counter to remain 0 because perform data does not match for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(context.Background()) + counter, err := performDataChecker[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), "Expected perform data checker counter to be 0, but got %d", counter.Int64()) @@ -1073,7 +1073,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { // retrieve new check data for all upkeeps for i := 0; i < len(upkeepIDs); i++ { - upkeep, err := registry.GetUpkeepInfo(context.Background(), upkeepIDs[i]) + upkeep, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepIDs[i]) require.NoError(t, err, "Error getting upkeep info from index %d", i) require.Equal(t, []byte(keeperExpectedData), upkeep.CheckData, "Check data not as expected") } @@ -1081,7 +1081,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(context.Background()) + counter, err := performDataChecker[i].Counter(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)), "Expected perform data checker counter to be greater than 5, but got %d", counter.Int64()) diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index 36ee2164c4..03a287ee6b 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/accounts/abi" + logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" ) diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index a6dcdcd139..5950e9febb 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "net/http" @@ -16,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) // Tests a basic OCRv2 median feed @@ -73,7 +73,7 @@ func TestOCRv2Basic(t *testing.T) { err = actions.StartNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err, "Error starting new OCR2 round") - roundData, err := aggregatorContracts[0].GetRound(context.Background(), big.NewInt(1)) + roundData, err := aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", @@ -85,7 +85,7 @@ func TestOCRv2Basic(t *testing.T) { err = actions.StartNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err) - roundData, err = aggregatorContracts[0].GetRound(context.Background(), big.NewInt(2)) + roundData, err = aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(2)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), roundData.Answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 912c121d07..57bd5412b1 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "strings" @@ -16,7 +15,6 @@ import ( eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" @@ -24,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCR2VRFRedeemModel(t *testing.T) { @@ -45,7 +44,7 @@ func TestOCR2VRFRedeemModel(t *testing.T) { require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -81,7 +80,7 @@ func TestOCR2VRFRedeemModel(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(context.Background(), requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) require.NoError(t, err) l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") @@ -107,7 +106,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -142,7 +141,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(context.Background(), requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) require.NoError(t, err, "Error getting Randomness result from Consumer Contract") l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness Fulfillment retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness Fulfillment retrieved from Consumer contract give an answer other than 0") diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 8952f00d76..45205565e2 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "math/big" "testing" @@ -11,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCRBasic(t *testing.T) { @@ -46,7 +46,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) - answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) @@ -55,7 +55,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(context.Background()) + answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index f29cb4bc89..20389da378 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "net/http" @@ -16,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestRunLogBasic(t *testing.T) { @@ -87,7 +87,7 @@ func TestRunLogBasic(t *testing.T) { gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(context.Background()) + d, err := consumer.Data(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") l.Debug().Int64("Data", d.Int64()).Msg("Found on chain") diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 444d1ce20e..61d2c5cdd7 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "testing" @@ -17,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv1" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestVRFBasic(t *testing.T) { @@ -81,7 +81,7 @@ func TestVRFBasic(t *testing.T) { encodedProvingKeys := make([][2]*big.Int, 0) encodedProvingKeys = append(encodedProvingKeys, provingKey) - requestHash, err := contracts.Coordinator.HashOfKey(context.Background(), encodedProvingKeys[0]) + requestHash, err := contracts.Coordinator.HashOfKey(utils.TestContext(t), encodedProvingKeys[0]) require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") err = contracts.Consumer.RequestRandomness(requestHash, big.NewInt(1)) require.NoError(t, err, "Requesting randomness shouldn't fail") @@ -92,7 +92,7 @@ func TestVRFBasic(t *testing.T) { jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - out, err := contracts.Consumer.RandomnessOutput(context.Background()) + out, err := contracts.Consumer.RandomnessOutput(utils.TestContext(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") // Checks that the job has actually run g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index c960bb6c69..714ed752a3 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "math/big" "testing" "time" @@ -16,6 +15,7 @@ import ( vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestVRFv2Basic(t *testing.T) { @@ -97,11 +97,11 @@ func TestVRFv2Basic(t *testing.T) { jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfV2jobs[0].Job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred()) g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically("==", 1)) - lastRequestID, err = vrfv2Contracts.LoadTestConsumer.GetLastRequestId(context.Background()) + lastRequestID, err = vrfv2Contracts.LoadTestConsumer.GetLastRequestId(utils.TestContext(t)) l.Debug().Interface("Last Request ID", lastRequestID).Msg("Last Request ID Received") g.Expect(err).ShouldNot(gomega.HaveOccurred()) - status, err := vrfv2Contracts.LoadTestConsumer.GetRequestStatus(context.Background(), lastRequestID) + status, err := vrfv2Contracts.LoadTestConsumer.GetRequestStatus(utils.TestContext(t), lastRequestID) g.Expect(err).ShouldNot(gomega.HaveOccurred()) g.Expect(status.Fulfilled).Should(gomega.BeTrue()) l.Debug().Interface("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 3510a1505a..cfeca0a66a 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -1,7 +1,6 @@ package smoke import ( - "context" "fmt" "math/big" "testing" @@ -55,7 +54,7 @@ func TestVRFv2Plus(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) @@ -83,7 +82,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) @@ -92,7 +91,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -125,7 +124,7 @@ func TestVRFv2Plus(t *testing.T) { ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceWei := new(big.Int).Sub(subNativeTokenBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) require.NoError(t, err) subBalanceAfterRequest := subscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) @@ -134,7 +133,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -162,10 +161,10 @@ func TestVRFv2Plus(t *testing.T) { testConfig := vrfv2PlusConfig var isNativeBilling = false - wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) + wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(utils.TestContext(t), wrapperContracts.LoadTestConsumers[0].Address()) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.Balance @@ -182,18 +181,18 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, consumerStatus.Fulfilled) expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) - wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) + wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(utils.TestContext(t), wrapperContracts.LoadTestConsumers[0].Address()) require.NoError(t, err, "error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) @@ -211,10 +210,10 @@ func TestVRFv2Plus(t *testing.T) { testConfig := vrfv2PlusConfig var isNativeBilling = true - wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.NativeBalance @@ -231,18 +230,18 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, consumerStatus.Fulfilled) expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) - wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) require.NoError(t, err, "error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) @@ -273,13 +272,13 @@ func TestVRFv2Plus(t *testing.T) { testWalletAddress, err := actions.GenerateWallet() require.NoError(t, err) - testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), testWalletAddress) + testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), testWalletAddress) require.NoError(t, err) - testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(context.Background(), testWalletAddress.String()) + testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), testWalletAddress.String()) require.NoError(t, err) - subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -318,14 +317,14 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - testWalletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), testWalletAddress) + testWalletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), testWalletAddress) require.NoError(t, err) - testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(context.Background(), testWalletAddress.String()) + testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), testWalletAddress.String()) require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedNativeActual := new(big.Int).Sub(testWalletBalanceNativeAfterSubCancelling, testWalletBalanceNativeBeforeSubCancelling) @@ -367,17 +366,17 @@ func TestVRFv2Plus(t *testing.T) { subIDForCancelling := subIDsForCancelling[0] - subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2PlusContracts.Coordinator) - activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err) require.True(t, utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subIDForCancelling)) - pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subIDForCancelling) + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(utils.TestContext(t), subIDForCancelling) require.NoError(t, err) require.False(t, pendingRequestsExist, "Pending requests should not exist") @@ -409,17 +408,17 @@ func TestVRFv2Plus(t *testing.T) { require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") - pendingRequestsExist, err = vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subIDForCancelling) + pendingRequestsExist, err = vrfv2PlusContracts.Coordinator.PendingRequestsExist(utils.TestContext(t), subIDForCancelling) require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfulfilled rand requests due to low sub balance") - walletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) require.NoError(t, err) - subscriptionForCancelling, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + subscriptionForCancelling, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -458,14 +457,14 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - walletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) fmt.Println("err", err) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") @@ -494,7 +493,7 @@ func TestVRFv2Plus(t *testing.T) { //require.Equal(t, subFundsReturnedNativeExpected, subFundsReturnedNativeActual, "Returned funds are not equal to sub balance that was cancelled") require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") - activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error getting active subscription ids") require.False( @@ -543,10 +542,10 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) amountToWithdrawLink := fulfilledEventLink.Payment - defaultWalletBalanceNativeBeforeOracleWithdraw, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeBeforeOracleWithdraw, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) require.NoError(t, err) l.Info(). @@ -575,10 +574,10 @@ func TestVRFv2Plus(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) - defaultWalletBalanceNativeAfterOracleWithdraw, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeAfterOracleWithdraw, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) require.NoError(t, err) //not possible to verify exact amount of Native/LINK returned as defaultWallet is used in other tests in parallel which might affect the balance @@ -618,17 +617,17 @@ func TestVRFv2PlusMigration(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) - activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") require.Len(t, activeSubIdsOldCoordinatorBeforeMigration, 1, "Active Sub Ids length is not equal to 1") require.Equal(t, subID, activeSubIdsOldCoordinatorBeforeMigration[0]) - oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) require.NoError(t, err, "error getting subscription information") //Migration Process @@ -699,14 +698,14 @@ func TestVRFv2PlusMigration(t *testing.T) { migratedCoordinatorLinkTotalBalanceAfterMigration, migratedCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) require.NoError(t, err) - migratedSubscription, err := newCoordinator.GetSubscription(context.Background(), subID) + migratedSubscription, err := newCoordinator.GetSubscription(utils.TestContext(t), subID) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetailsAfterMigration(l, newCoordinator, subID, migratedSubscription) //Verify that Coordinators were updated in Consumers for _, consumer := range vrfv2PlusContracts.LoadTestConsumers { - coordinatorAddressInConsumerAfterMigration, err := consumer.GetCoordinator(context.Background()) + coordinatorAddressInConsumerAfterMigration, err := consumer.GetCoordinator(utils.TestContext(t)) require.NoError(t, err, "error getting Coordinator from Consumer contract") require.Equal(t, newCoordinator.Address(), coordinatorAddressInConsumerAfterMigration.String()) l.Debug(). @@ -722,13 +721,13 @@ func TestVRFv2PlusMigration(t *testing.T) { require.Equal(t, oldSubscriptionBeforeMigration.Consumers, migratedSubscription.Consumers) //Verify that old sub was deleted from old Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") - _, err = vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + _, err = vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) require.Error(t, err, "error not occurred getting active sub ids. Should occur since it should revert when sub id array is empty") - activeSubIdsMigratedCoordinator, err := newCoordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + activeSubIdsMigratedCoordinator, err := newCoordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") require.Len(t, activeSubIdsMigratedCoordinator, 1, "Active Sub Ids length is not equal to 1 for Migrated Coordinator after migration") require.Equal(t, subID, activeSubIdsMigratedCoordinator[0]) diff --git a/integration-tests/testreporters/keeper_benchmark.go b/integration-tests/testreporters/keeper_benchmark.go index c800eb37be..e9f2eaad7c 100644 --- a/integration-tests/testreporters/keeper_benchmark.go +++ b/integration-tests/testreporters/keeper_benchmark.go @@ -183,7 +183,7 @@ func (k *KeeperBenchmarkTestReporter) WriteReport(folderLocation string) error { } for contractIndex, report := range k.Reports { - avg, median, ninetyPct, ninetyNinePct, max := intListStats(report.AllCheckDelays) + avg, median, ninetyPct, ninetyNinePct, max = intListStats(report.AllCheckDelays) err = keeperReportWriter.Write([]string{ fmt.Sprint(contractIndex), report.RegistryAddress, @@ -305,6 +305,8 @@ func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackC } // intListStats helper calculates some statistics on an int list: avg, median, 90pct, 99pct, max +// +//nolint:revive func intListStats(in []int64) (float64, int64, int64, int64, int64) { length := len(in) if length == 0 { diff --git a/integration-tests/testreporters/ocr.go b/integration-tests/testreporters/ocr.go index a04718ea22..abbb261fa7 100644 --- a/integration-tests/testreporters/ocr.go +++ b/integration-tests/testreporters/ocr.go @@ -67,9 +67,7 @@ func (e *OCRRoundState) Time() time.Time { // CSV returns a CSV representation of the test state and all events func (e *OCRRoundState) CSV() [][]string { rows := [][]string{{e.StartTime.Format("2006-01-02 15:04:05.00 MST"), fmt.Sprintf("Expecting new Answer: %d", e.Answer)}} - for _, anomaly := range e.anomalies { - rows = append(rows, anomaly) - } + rows = append(rows, e.anomalies...) return rows } diff --git a/integration-tests/testreporters/profile.go b/integration-tests/testreporters/profile.go index 9ac7713e94..ab9dec138e 100644 --- a/integration-tests/testreporters/profile.go +++ b/integration-tests/testreporters/profile.go @@ -54,7 +54,7 @@ func (c *ChainlinkProfileTestReporter) WriteReport(folderLocation string) error } // SendNotification hasn't been implemented for this test -func (c *ChainlinkProfileTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (c *ChainlinkProfileTestReporter) SendSlackNotification(_ *testing.T, _ *slack.Client) error { log.Warn().Msg("No Slack notification integration for Chainlink profile tests") return nil } diff --git a/integration-tests/testreporters/vrfv2plus.go b/integration-tests/testreporters/vrfv2plus.go index 83d4678dfd..38220ca882 100644 --- a/integration-tests/testreporters/vrfv2plus.go +++ b/integration-tests/testreporters/vrfv2plus.go @@ -2,12 +2,13 @@ package testreporters import ( "fmt" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "math/big" "os" "testing" "time" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/slack-go/slack" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" @@ -53,7 +54,7 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient headerText = fmt.Sprintf(":x: VRF %s Test FAILED :x:", o.TestType) } - messageBlocks := testreporters.SlackNotifyBlocks(headerText, fmt.Sprintf("%s", os.Getenv("SELECTED_NETWORKS")), []string{ + messageBlocks := testreporters.SlackNotifyBlocks(headerText, os.Getenv("SELECTED_NETWORKS"), []string{ fmt.Sprintf( "Summary\n"+ "Perf Test Type: %s\n"+ diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index f786cca9bb..bb6c582c13 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -37,6 +37,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) // KeeperBenchmarkTest builds a test to check that chainlink nodes are able to upkeep a specified amount of Upkeep @@ -229,7 +230,7 @@ func (k *KeeperBenchmarkTest) Run() { "NumberOfRegistries": len(k.keeperRegistries), } inputs := k.Inputs - startingBlock, err := k.chainClient.LatestBlockNumber(context.Background()) + startingBlock, err := k.chainClient.LatestBlockNumber(utils.TestContext(k.t)) require.NoError(k.t, err, "Error getting latest block number") k.startingBlock = big.NewInt(0).SetUint64(startingBlock) startTime := time.Now() @@ -305,7 +306,7 @@ func (k *KeeperBenchmarkTest) Run() { err = fmt.Errorf("initial error") // to ensure our for loop runs at least once ) for err != nil { // This RPC call can possibly time out or otherwise die. Failure is not an option, keep retrying to get our stats. - ctx, cancel := context.WithTimeout(context.Background(), timeout) + ctx, cancel := context.WithTimeout(utils.TestContext(k.t), timeout) logs, err = k.chainClient.FilterLogs(ctx, filterQuery) cancel() if err != nil { @@ -407,12 +408,13 @@ func (k *KeeperBenchmarkTest) observeUpkeepEvents() { FromBlock: k.startingBlock, } - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(utils.TestContext(k.t), 5*time.Second) sub, err := k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) cancel() require.NoError(k.t, err, "Subscribing to upkeep performed events log shouldn't fail") interruption := make(chan os.Signal, 1) + //nolint:staticcheck //ignore SA1016 we need to send the os.Kill signal signal.Notify(interruption, os.Kill, os.Interrupt, syscall.SIGTERM) go func() { @@ -429,7 +431,7 @@ func (k *KeeperBenchmarkTest) observeUpkeepEvents() { Str("Backoff", backoff.String()). Msg("Error while subscribing to Keeper Event Logs. Resubscribing...") - ctx, cancel := context.WithTimeout(context.Background(), backoff) + ctx, cancel := context.WithTimeout(utils.TestContext(k.t), backoff) sub, err = k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) cancel() if err != nil { diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index ee8116f3f9..3fb9dd9844 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -42,6 +42,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) const ( @@ -163,7 +164,7 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { } // LoadEnvironment loads an existing test environment using the provided URLs -func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, chainURL, mockServerURL string) { +func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, mockServerURL string) { var ( network = networks.MustGetSelectedNetworksFromEnv()[0] err error @@ -241,7 +242,6 @@ func (o *OCRSoakTest) Setup() { o.Inputs.NumberOfContracts, linkTokenContract, contractDeployer, - o.bootstrapNode, o.workerNodes, o.chainClient, ) @@ -258,7 +258,7 @@ func (o *OCRSoakTest) Setup() { // Run starts the OCR soak test func (o *OCRSoakTest) Run() { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + ctx, cancel := context.WithTimeout(utils.TestContext(o.t), time.Second*5) latestBlockNum, err := o.chainClient.LatestBlockNumber(ctx) cancel() require.NoError(o.t, err, "Error getting current block number") @@ -343,7 +343,7 @@ func (o *OCRSoakTest) SaveState() error { if err != nil { return err } - // #nosec G306 - let everyone read + //nolint:gosec // G306 - let everyone read if err = os.WriteFile(saveFileLocation, data, 0644); err != nil { return err } @@ -468,6 +468,7 @@ func (o *OCRSoakTest) Interrupted() bool { func (o *OCRSoakTest) testLoop(testDuration time.Duration, newValue int) { endTest := time.After(testDuration) interruption := make(chan os.Signal, 1) + //nolint:staticcheck //ignore SA1016 we need to send the os.Kill signal signal.Notify(interruption, os.Kill, os.Interrupt, syscall.SIGTERM) lastValue := 0 newRoundTrigger := time.NewTimer(0) // Want to trigger a new round ASAP @@ -558,7 +559,7 @@ func (o *OCRSoakTest) setFilterQuery() { // WARNING: Should only be used for observation and logging. This is not a reliable way to collect events. func (o *OCRSoakTest) observeOCREvents() error { eventLogs := make(chan types.Log) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(utils.TestContext(o.t), 5*time.Second) eventSub, err := o.chainClient.SubscribeFilterLogs(ctx, o.filterQuery, eventLogs) cancel() if err != nil { @@ -592,7 +593,7 @@ func (o *OCRSoakTest) observeOCREvents() error { Str("Backoff", backoff.String()). Interface("Query", o.filterQuery). Msg("Error while subscribed to OCR Logs. Resubscribing") - ctx, cancel = context.WithTimeout(context.Background(), backoff) + ctx, cancel = context.WithTimeout(utils.TestContext(o.t), backoff) eventSub, err = o.chainClient.SubscribeFilterLogs(ctx, o.filterQuery, eventLogs) cancel() if err != nil { @@ -645,12 +646,12 @@ func (o *OCRSoakTest) collectEvents() error { timeout := time.Second * 15 o.log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") - ctx, cancel := context.WithTimeout(context.Background(), timeout) + ctx, cancel := context.WithTimeout(utils.TestContext(o.t), timeout) contractEvents, err := o.chainClient.FilterLogs(ctx, o.filterQuery) cancel() for err != nil { o.log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") - ctx, cancel := context.WithTimeout(context.Background(), timeout) + ctx, cancel := context.WithTimeout(utils.TestContext(o.t), timeout) contractEvents, err = o.chainClient.FilterLogs(ctx, o.filterQuery) cancel() if err != nil { diff --git a/integration-tests/testsetups/vrfv2.go b/integration-tests/testsetups/vrfv2.go index 194c7ff4e6..8c5fde7216 100644 --- a/integration-tests/testsetups/vrfv2.go +++ b/integration-tests/testsetups/vrfv2.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) // VRFV2SoakTest defines a typical VRFV2 soak test @@ -87,7 +88,8 @@ func (v *VRFV2SoakTest) Run(t *testing.T) { Msg("Starting VRFV2 Soak Test") // set the requests to only run for a certain amount of time - testContext, testCancel := context.WithTimeout(context.Background(), v.Inputs.TestDuration) + ctx := utils.TestContext(t) + testContext, testCancel := context.WithTimeout(ctx, v.Inputs.TestDuration) defer testCancel() v.NumberOfRandRequests = 0 @@ -126,7 +128,7 @@ func (v *VRFV2SoakTest) Run(t *testing.T) { //todo - need to find better way for this time.Sleep(1 * time.Minute) - loadTestMetrics, err := v.Inputs.ConsumerContract.GetLoadTestMetrics(nil) + loadTestMetrics, err := v.Inputs.ConsumerContract.GetLoadTestMetrics(ctx) if err != nil { l.Error().Err(err).Msg("Error Occurred when getting Load Test Metrics from Consumer contract") } diff --git a/integration-tests/types/envcommon/common.go b/integration-tests/types/envcommon/common.go index 607c481f33..bdabcaf96b 100644 --- a/integration-tests/types/envcommon/common.go +++ b/integration-tests/types/envcommon/common.go @@ -2,7 +2,7 @@ package envcommon import ( "encoding/json" - "io/ioutil" + "io" "os" ) @@ -12,7 +12,7 @@ func ParseJSONFile(path string, v any) error { return err } defer jsonFile.Close() - b, _ := ioutil.ReadAll(jsonFile) + b, _ := io.ReadAll(jsonFile) err = json.Unmarshal(b, v) if err != nil { return err diff --git a/integration-tests/universal/log_poller/config.go b/integration-tests/universal/log_poller/config.go index 7297e81124..78a0da46bc 100644 --- a/integration-tests/universal/log_poller/config.go +++ b/integration-tests/universal/log_poller/config.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -131,33 +132,33 @@ func (c *Config) validate() error { err := c.General.validate() if err != nil { - return fmt.Errorf("General config validation failed: %v", err) + return fmt.Errorf("General config validation failed: %w", err) } switch c.General.Generator { case GeneratorType_WASP: if c.Wasp == nil { - return fmt.Errorf("Wasp config is nil") + return fmt.Errorf("wasp config is nil") } if c.Wasp.Load == nil { - return fmt.Errorf("Wasp load config is nil") + return fmt.Errorf("wasp load config is nil") } err = c.Wasp.validate() if err != nil { - return fmt.Errorf("Wasp config validation failed: %v", err) + return fmt.Errorf("wasp config validation failed: %w", err) } case GeneratorType_Looped: if c.LoopedConfig == nil { - return fmt.Errorf("Looped config is nil") + return fmt.Errorf("looped config is nil") } err = c.LoopedConfig.validate() if err != nil { - return fmt.Errorf("Looped config validation failed: %v", err) + return fmt.Errorf("looped config validation failed: %w", err) } default: - return fmt.Errorf("Unknown generator type: %s", c.General.Generator) + return fmt.Errorf("unknown generator type: %s", c.General.Generator) } return nil @@ -165,15 +166,15 @@ func (c *Config) validate() error { func (g *General) validate() error { if g.Generator == "" { - return fmt.Errorf("Generator is empty") + return fmt.Errorf("generator is empty") } if g.Contracts == 0 { - return fmt.Errorf("Contracts is 0, but must be > 0") + return fmt.Errorf("contracts is 0, but must be > 0") } if g.EventsPerTx == 0 { - return fmt.Errorf("Events_per_tx is 0, but must be > 0") + return fmt.Errorf("events_per_tx is 0, but must be > 0") } return nil @@ -186,7 +187,7 @@ func (w *WaspConfig) validate() error { err := w.Load.validate() if err != nil { - return fmt.Errorf("Load config validation failed: %v", err) + return fmt.Errorf("Load config validation failed: %w", err) } return nil @@ -194,11 +195,11 @@ func (w *WaspConfig) validate() error { func (l *Load) validate() error { if l.RPS == 0 && l.LPS == 0 { - return fmt.Errorf("Either RPS or LPS needs to be set") + return fmt.Errorf("either RPS or LPS needs to be set") } if l.RPS != 0 && l.LPS != 0 { - return fmt.Errorf("Only one of RPS or LPS can be set") + return fmt.Errorf("only one of RPS or LPS can be set") } if l.Duration == nil { diff --git a/integration-tests/universal/log_poller/gun.go b/integration-tests/universal/log_poller/gun.go index 11932330a3..39286f1b53 100644 --- a/integration-tests/universal/log_poller/gun.go +++ b/integration-tests/universal/log_poller/gun.go @@ -7,8 +7,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/rs/zerolog" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) /* LogEmitterGun is a gun that constantly emits logs from a contract */ @@ -53,13 +54,13 @@ func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { case "Log3": _, err = logEmitter.EmitLogStrings(getStringSlice(m.eventsPerTx)) default: - err = fmt.Errorf("Unknown event name: %s", event.Name) + err = fmt.Errorf("unknown event name: %s", event.Name) } if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } - localCounter += 1 + localCounter++ } // I don't think that will work as expected, I should atomically read the value and save it, so maybe just a mutex? diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 9f88827bb4..08ceb4a7be 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -3,7 +3,6 @@ package logpoller import ( "bytes" "context" - "errors" "fmt" "math/big" "math/rand" @@ -22,16 +21,15 @@ import ( "github.com/scylladb/go-reflectx" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctf_blockchain "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/wasp" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - lpEvm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" @@ -41,12 +39,13 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" - utils2 "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -80,64 +79,65 @@ var registerSingleTopicFilter = func(registry contracts.KeeperRegistry, upkeepID return nil } +// Currently Unused November 8, 2023, Might be useful in the near future so keeping it here for now // this is not really possible, log trigger doesn't support multiple topics, even if log poller does -var registerMultipleTopicsFilter = func(registry contracts.KeeperRegistry, upkeepID *big.Int, emitterAddress common.Address, topics []abi.Event) error { - if len(topics) > 4 { - return errors.New("Cannot register more than 4 topics") - } - - var getTopic = func(topics []abi.Event, i int) common.Hash { - if i > len(topics)-1 { - return bytes0 - } - - return topics[i].ID - } - - var getFilterSelector = func(topics []abi.Event) (uint8, error) { - switch len(topics) { - case 0: - return 0, errors.New("Cannot register filter with 0 topics") - case 1: - return 0, nil - case 2: - return 1, nil - case 3: - return 3, nil - case 4: - return 7, nil - default: - return 0, errors.New("Cannot register filter with more than 4 topics") - } - } - - filterSelector, err := getFilterSelector(topics) - if err != nil { - return err - } - - logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ - ContractAddress: emitterAddress, - FilterSelector: filterSelector, - Topic0: getTopic(topics, 0), - Topic1: getTopic(topics, 1), - Topic2: getTopic(topics, 2), - Topic3: getTopic(topics, 3), - } - encodedLogTriggerConfig, err := automationUtilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) - if err != nil { - return err - } - - err = registry.SetUpkeepTriggerConfig(upkeepID, encodedLogTriggerConfig) - if err != nil { - return err - } - - return nil -} - -func NewOrm(logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (*lpEvm.DbORM, *sqlx.DB, error) { +// var registerMultipleTopicsFilter = func(registry contracts.KeeperRegistry, upkeepID *big.Int, emitterAddress common.Address, topics []abi.Event) error { +// if len(topics) > 4 { +// return errors.New("Cannot register more than 4 topics") +// } + +// var getTopic = func(topics []abi.Event, i int) common.Hash { +// if i > len(topics)-1 { +// return bytes0 +// } + +// return topics[i].ID +// } + +// var getFilterSelector = func(topics []abi.Event) (uint8, error) { +// switch len(topics) { +// case 0: +// return 0, errors.New("Cannot register filter with 0 topics") +// case 1: +// return 0, nil +// case 2: +// return 1, nil +// case 3: +// return 3, nil +// case 4: +// return 7, nil +// default: +// return 0, errors.New("Cannot register filter with more than 4 topics") +// } +// } + +// filterSelector, err := getFilterSelector(topics) +// if err != nil { +// return err +// } + +// logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ +// ContractAddress: emitterAddress, +// FilterSelector: filterSelector, +// Topic0: getTopic(topics, 0), +// Topic1: getTopic(topics, 1), +// Topic2: getTopic(topics, 2), +// Topic3: getTopic(topics, 3), +// } +// encodedLogTriggerConfig, err := automationUtilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) +// if err != nil { +// return err +// } + +// err = registry.SetUpkeepTriggerConfig(upkeepID, encodedLogTriggerConfig) +// if err != nil { +// return err +// } + +// return nil +// } + +func NewOrm(logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (*logpoller.DbORM, *sqlx.DB, error) { dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", "127.0.0.1", postgresDb.ExternalPort, postgresDb.User, postgresDb.Password, postgresDb.DbName) db, err := sqlx.Open("postgres", dsn) if err != nil { @@ -145,7 +145,7 @@ func NewOrm(logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_ } db.MapperFunc(reflectx.CamelToSnakeASCII) - return lpEvm.NewORM(chainID, db, logger, pg.NewQConfig(false)), db, nil + return logpoller.NewORM(chainID, db, logger, pg.NewQConfig(false)), db, nil } type ExpectedFilter struct { @@ -189,7 +189,7 @@ var nodeHasExpectedFilters = func(expectedFilters []ExpectedFilter, logger core_ } if !filterFound { - return false, fmt.Errorf("No filter found for emitter %s and topic %s", expectedFilter.emitterAddress.String(), expectedFilter.topic.Hex()) + return false, fmt.Errorf("no filter found for emitter %s and topic %s", expectedFilter.emitterAddress.String(), expectedFilter.topic.Hex()) } } @@ -203,9 +203,10 @@ var randomWait = func(minMilliseconds, maxMilliseconds int) { } type LogEmitterChannel struct { - logsEmitted int - err error - currentIndex int + logsEmitted int + err error + // unused + // currentIndex int } func getIntSlice(length int) []int { @@ -247,7 +248,7 @@ var emitEvents = func(ctx context.Context, l zerolog.Logger, logEmitter *contrac case "Log3": _, err = (*logEmitter).EmitLogStrings(getStringSlice(cfg.General.EventsPerTx)) default: - err = fmt.Errorf("Unknown event name: %s", event.Name) + err = fmt.Errorf("unknown event name: %s", event.Name) } if err != nil { @@ -276,29 +277,7 @@ var emitEvents = func(ctx context.Context, l zerolog.Logger, logEmitter *contrac } } -var waitForEndBlockInLogPoller = func(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { - for i := 1; i < len(nodes.Nodes); i++ { - clNode := nodes.Nodes[i] - orm, db, err := NewOrm(coreLogger, chainID, clNode.PostgresDb) - if err != nil { - return false, err - } - - defer db.Close() - block, err := orm.SelectBlockByNumber(endBlock) - if err != nil { - return false, err - } - - if block == nil { - return false, nil - } - } - - return true, nil -} - -var chainHasFinalisedEndBlock = func(l zerolog.Logger, evmClient ctf_blockchain.EVMClient, endBlock int64) (bool, error) { +var chainHasFinalisedEndBlock = func(l zerolog.Logger, evmClient blockchain.EVMClient, endBlock int64) (bool, error) { effectiveEndBlock := endBlock + 1 lastFinalisedBlockHeader, err := evmClient.GetLatestFinalizedBlockHeader(context.Background()) if err != nil { @@ -512,7 +491,7 @@ func (m *MissingLogs) IsEmpty() bool { return true } -var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient ctf_blockchain.EVMClient, clnodeCluster *test_env.ClCluster, l zerolog.Logger, coreLogger core_logger.SugaredLogger, cfg *Config) (MissingLogs, error) { +var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, clnodeCluster *test_env.ClCluster, l zerolog.Logger, coreLogger core_logger.SugaredLogger, cfg *Config) (MissingLogs, error) { wg := &sync.WaitGroup{} type dbQueryResult struct { @@ -696,11 +675,7 @@ var printMissingLogsByType = func(missingLogs map[string][]geth_types.Log, l zer for _, logs := range missingLogs { for _, v := range logs { humanName := findHumanName(v.Topics[0]) - if _, ok := missingByType[humanName]; ok { - missingByType[humanName] += 1 - } else { - missingByType[humanName] = 1 - } + missingByType[humanName]++ } } @@ -709,7 +684,7 @@ var printMissingLogsByType = func(missingLogs map[string][]geth_types.Log, l zer } } -var getEVMLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient ctf_blockchain.EVMClient, l zerolog.Logger, cfg *Config) ([]geth_types.Log, error) { +var getEVMLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, l zerolog.Logger, cfg *Config) ([]geth_types.Log, error) { allLogsInEVMNode := make([]geth_types.Log, 0) for j := 0; j < len(logEmitters); j++ { address := (*logEmitters[j]).Address() @@ -757,7 +732,7 @@ func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmi RPSprime = cfg.Wasp.Load.LPS / int64(cfg.General.Contracts) / int64(cfg.General.EventsPerTx) / int64(len(cfg.General.EventsToEmit)) if RPSprime < 1 { - return 0, fmt.Errorf("Invalid load configuration, effective RPS would have been zero. Adjust LPS, contracts count, events per tx or events to emit") + return 0, fmt.Errorf("invalid load configuration, effective RPS would have been zero. Adjust LPS, contracts count, events per tx or events to emit") } } @@ -854,9 +829,8 @@ func getExpectedLogCount(cfg *Config) int64 { if cfg.General.Generator == GeneratorType_WASP { if cfg.Wasp.Load.RPS != 0 { return cfg.Wasp.Load.RPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) * int64(cfg.General.EventsPerTx) - } else { - return cfg.Wasp.Load.LPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) } + return cfg.Wasp.Load.LPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) } return int64(len(cfg.General.EventsToEmit) * cfg.LoopedConfig.ExecutionCount * cfg.General.Contracts * cfg.General.EventsPerTx) @@ -903,6 +877,7 @@ var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterT guardChan := make(chan struct{}, 1) for i := 0; i < cfg.ChaosConfig.ExperimentCount; i++ { + i := i wg.Add(1) guardChan <- struct{}{} go func() { @@ -921,22 +896,21 @@ var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterT }() go func() { - for { - select { - case err, ok := <-chaosChan: - if !ok { - l.Info().Msg("All chaos experiments finished") - errorCh <- nil - return - } else { - if err != nil { - l.Err(err).Msg("Error encountered during chaos experiment") - errorCh <- err - return - } - } + for err := range chaosChan { + // This will receive errors until chaosChan is closed + if err != nil { + // If an error is encountered, log it, send it to the error channel, and return from the function + l.Err(err).Msg("Error encountered during chaos experiment") + errorCh <- err + return // Return on actual error } + // No need for an else block here, because if err is nil (which happens when the channel is closed), + // the loop will exit and the following log and nil send will execute. } + + // After the loop exits, which it will do when chaosChan is closed, log that all experiments are finished. + l.Info().Msg("All chaos experiments finished") + errorCh <- nil // Only send nil once, after all errors have been handled and the channel is closed }() } @@ -953,7 +927,7 @@ var GetFinalityDepth = func(chainId int64) (int64, error) { case 1337: finalityDepth = 10 default: - return 0, fmt.Errorf("No known finality depth for chain %d", chainId) + return 0, fmt.Errorf("no known finality depth for chain %d", chainId) } return finalityDepth, nil @@ -1014,7 +988,6 @@ var ( func setupLogPollerTestDocker( t *testing.T, - testName string, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, upkeepsNeeded int, @@ -1057,8 +1030,8 @@ func setupLogPollerTestDocker( var logPolllerSettingsFn = func(chain *evmcfg.Chain) *evmcfg.Chain { chain.LogPollInterval = models.MustNewDuration(lpPollingInterval) - chain.FinalityDepth = utils2.Ptr[uint32](uint32(finalityDepth)) - chain.FinalityTagEnabled = utils2.Ptr[bool](finalityTagEnabled) + chain.FinalityDepth = it_utils.Ptr[uint32](uint32(finalityDepth)) + chain.FinalityTagEnabled = it_utils.Ptr[bool](finalityTagEnabled) return chain } @@ -1078,6 +1051,7 @@ func setupLogPollerTestDocker( SlotsPerEpoch: 2, }). Build() + require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). WithTestLogger(t). diff --git a/integration-tests/universal/log_poller/scenarios.go b/integration-tests/universal/log_poller/scenarios.go index 1110a2f8ca..886547d46e 100644 --- a/integration-tests/universal/log_poller/scenarios.go +++ b/integration-tests/universal/log_poller/scenarios.go @@ -1,19 +1,20 @@ package logpoller import ( - "context" "fmt" "math/big" "testing" "time" "github.com/onsi/gomega" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/utils" core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/stretchr/testify/require" ) func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { @@ -31,12 +32,11 @@ func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { var ( err error - testName = "basic-log-poller" upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) ) chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, testName, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(500*time.Millisecond), cfg.General.UseFinalityTag, + t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(500*time.Millisecond), cfg.General.UseFinalityTag, ) _, upkeepIDs := actions.DeployConsumers( @@ -100,7 +100,7 @@ func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + sb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -122,7 +122,7 @@ func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + eb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) require.NoError(t, err, "Error getting latest block number") endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) @@ -194,13 +194,12 @@ func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string var ( err error - testName = "replay-log-poller" upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) ) // we set blockBackfillDepth to 0, to make sure nothing will be backfilled and won't interfere with our test chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, testName, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag) + t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag) _, upkeepIDs := actions.DeployConsumers( t, @@ -230,7 +229,7 @@ func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string time.Sleep(5 * time.Second) // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + sb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -244,7 +243,7 @@ func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + eb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) require.NoError(t, err, "Error getting latest block number") endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) @@ -352,12 +351,11 @@ func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { var ( err error - testName = "ci-log-poller" upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) ) chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, testName, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag, + t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag, ) _, upkeepIDs := actions.DeployConsumers( @@ -421,7 +419,7 @@ func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + sb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -443,7 +441,7 @@ func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(context.Background()) + eb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) require.NoError(t, err, "Error getting latest block number") endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) diff --git a/integration-tests/utils/cl_node_jobs.go b/integration-tests/utils/cl_node_jobs.go index 16b0c167cf..65dc6e4e39 100644 --- a/integration-tests/utils/cl_node_jobs.go +++ b/integration-tests/utils/cl_node_jobs.go @@ -10,13 +10,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/lib/pq" + "gopkg.in/guregu/null.v4" + coreClient "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "gopkg.in/guregu/null.v4" ) -func BuildBootstrapSpec(verifierAddr common.Address, chainID int64, fromBlock uint64, feedId [32]byte) *coreClient.OCR2TaskJobSpec { +func BuildBootstrapSpec(verifierAddr common.Address, chainID int64, feedId [32]byte) *coreClient.OCR2TaskJobSpec { hash := common.BytesToHash(feedId[:]) return &coreClient.OCR2TaskJobSpec{ Name: fmt.Sprintf("bootstrap-%s", uuid.NewString()), diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go index 9aacaeed41..5ef3209c92 100644 --- a/integration-tests/utils/common.go +++ b/integration-tests/utils/common.go @@ -1,8 +1,10 @@ package utils import ( + "context" "math/big" "net" + "testing" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -33,3 +35,20 @@ func BigIntSliceContains(slice []*big.Int, b *big.Int) bool { } return false } + +// TestContext returns a context with the test's deadline, if available. +func TestContext(tb testing.TB) context.Context { + ctx := context.Background() + var cancel func() + switch t := tb.(type) { + case *testing.T: + if d, ok := t.Deadline(); ok { + ctx, cancel = context.WithDeadline(ctx, d) + } + } + if cancel == nil { + ctx, cancel = context.WithCancel(ctx) + } + tb.Cleanup(cancel) + return ctx +} diff --git a/integration-tests/utils/log.go b/integration-tests/utils/log.go deleted file mode 100644 index 499be8002d..0000000000 --- a/integration-tests/utils/log.go +++ /dev/null @@ -1,19 +0,0 @@ -package utils - -import ( - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" - "os" -) - -func SetupCoreDockerEnvLogger() { - lvlStr := os.Getenv("CORE_DOCKER_ENV_LOG_LEVEL") - if lvlStr == "" { - lvlStr = "info" - } - lvl, err := zerolog.ParseLevel(lvlStr) - if err != nil { - panic(err) - } - log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Level(lvl) -} diff --git a/integration-tests/utils/templates/secrets.go b/integration-tests/utils/templates/secrets.go index f81287e871..45edf0d012 100644 --- a/integration-tests/utils/templates/secrets.go +++ b/integration-tests/utils/templates/secrets.go @@ -2,6 +2,7 @@ package templates import ( "github.com/google/uuid" + "github.com/smartcontractkit/chainlink-testing-framework/utils/templates" ) From f7981f5c10403eca31a11d55b356e1191725f5c3 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Mon, 13 Nov 2023 17:43:00 +0100 Subject: [PATCH 136/327] CCIP-1277 LogPoller - Fixing leaky abstraction by removing Q() from the ORM interface (#11200) * Fixing leaky abstraction by removing Q() from the ORM interface. Moving all the TX internals into the ORM implementation * Adding test * Post review fix * Post rebase fixes --- core/chains/evm/logpoller/log_poller.go | 39 +---- core/chains/evm/logpoller/models.go | 9 ++ core/chains/evm/logpoller/observability.go | 22 +-- .../evm/logpoller/observability_test.go | 2 +- core/chains/evm/logpoller/orm.go | 99 ++++++++---- core/chains/evm/logpoller/orm_test.go | 141 +++++++++++++++++- 6 files changed, 232 insertions(+), 80 deletions(-) diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 01d6a2aad4..b86ede5dbc 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -679,9 +679,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } lp.lggr.Debugw("Backfill found logs", "from", from, "to", to, "logs", len(gethLogs), "blocks", blocks) - err = lp.orm.Q().WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { - return lp.orm.InsertLogs(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), pg.WithQueryer(tx)) - }) + err = lp.orm.InsertLogs(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), pg.WithParentCtx(ctx)) if err != nil { lp.lggr.Warnw("Unable to insert logs, retrying", "err", err, "from", from, "to", to) return err @@ -750,21 +748,7 @@ func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, curren // the canonical set per read. Typically, if an application took action on a log // it would be saved elsewhere e.g. evm.txes, so it seems better to just support the fast reads. // Its also nicely analogous to reading from the chain itself. - err2 = lp.orm.Q().WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { - // These deletes are bounded by reorg depth, so they are - // fast and should not slow down the log readers. - err3 := lp.orm.DeleteBlocksAfter(blockAfterLCA.Number, pg.WithQueryer(tx)) - if err3 != nil { - lp.lggr.Warnw("Unable to clear reorged blocks, retrying", "err", err3) - return err3 - } - err3 = lp.orm.DeleteLogsAfter(blockAfterLCA.Number, pg.WithQueryer(tx)) - if err3 != nil { - lp.lggr.Warnw("Unable to clear reorged logs, retrying", "err", err3) - return err3 - } - return nil - }) + err2 = lp.orm.DeleteLogsAndBlocksAfter(blockAfterLCA.Number, pg.WithParentCtx(ctx)) if err2 != nil { // If we error on db commit, we can't know if the tx went through or not. // We return an error here which will cause us to restart polling from lastBlockSaved + 1 @@ -849,20 +833,11 @@ func (lp *logPoller) PollAndSaveLogs(ctx context.Context, currentBlockNumber int return } lp.lggr.Debugw("Unfinalized log query", "logs", len(logs), "currentBlockNumber", currentBlockNumber, "blockHash", currentBlock.Hash, "timestamp", currentBlock.Timestamp.Unix()) - err = lp.orm.Q().WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { - if err2 := lp.orm.InsertBlock(h, currentBlockNumber, currentBlock.Timestamp, latestFinalizedBlockNumber, pg.WithQueryer(tx)); err2 != nil { - return err2 - } - if len(logs) == 0 { - return nil - } - return lp.orm.InsertLogs(convertLogs(logs, - []LogPollerBlock{{BlockNumber: currentBlockNumber, - BlockTimestamp: currentBlock.Timestamp}}, - lp.lggr, - lp.ec.ConfiguredChainID(), - ), pg.WithQueryer(tx)) - }) + block := NewLogPollerBlock(h, currentBlockNumber, currentBlock.Timestamp, latestFinalizedBlockNumber) + err = lp.orm.InsertLogsWithBlock( + convertLogs(logs, []LogPollerBlock{block}, lp.lggr, lp.ec.ConfiguredChainID()), + block, + ) if err != nil { lp.lggr.Warnw("Unable to save logs resuming from last saved block + 1", "err", err, "block", currentBlockNumber) return diff --git a/core/chains/evm/logpoller/models.go b/core/chains/evm/logpoller/models.go index 9c55786777..87ddd079a5 100644 --- a/core/chains/evm/logpoller/models.go +++ b/core/chains/evm/logpoller/models.go @@ -56,3 +56,12 @@ func (l *Log) ToGethLog() types.Log { Index: uint(l.LogIndex), } } + +func NewLogPollerBlock(blockHash common.Hash, blockNumber int64, timestamp time.Time, finalizedBlockNumber int64) LogPollerBlock { + return LogPollerBlock{ + BlockHash: blockHash, + BlockNumber: blockNumber, + BlockTimestamp: timestamp, + FinalizedBlockNumber: finalizedBlockNumber, + } +} diff --git a/core/chains/evm/logpoller/observability.go b/core/chains/evm/logpoller/observability.go index c4b58b42a2..03f4b77be2 100644 --- a/core/chains/evm/logpoller/observability.go +++ b/core/chains/evm/logpoller/observability.go @@ -68,19 +68,15 @@ func NewObservedORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QC } } -func (o *ObservedORM) Q() pg.Q { - return o.ORM.Q() -} - func (o *ObservedORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { return withObservedExec(o, "InsertLogs", func() error { return o.ORM.InsertLogs(logs, qopts...) }) } -func (o *ObservedORM) InsertBlock(hash common.Hash, blockNumber int64, blockTimestamp time.Time, lastFinalizedBlock int64, qopts ...pg.QOpt) error { - return withObservedExec(o, "InsertBlock", func() error { - return o.ORM.InsertBlock(hash, blockNumber, blockTimestamp, lastFinalizedBlock, qopts...) +func (o *ObservedORM) InsertLogsWithBlock(logs []Log, block LogPollerBlock, qopts ...pg.QOpt) error { + return withObservedExec(o, "InsertLogsWithBlock", func() error { + return o.ORM.InsertLogsWithBlock(logs, block, qopts...) }) } @@ -102,21 +98,15 @@ func (o *ObservedORM) DeleteFilter(name string, qopts ...pg.QOpt) error { }) } -func (o *ObservedORM) DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error { - return withObservedExec(o, "DeleteBlocksAfter", func() error { - return o.ORM.DeleteBlocksAfter(start, qopts...) - }) -} - func (o *ObservedORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { return withObservedExec(o, "DeleteBlocksBefore", func() error { return o.ORM.DeleteBlocksBefore(end, qopts...) }) } -func (o *ObservedORM) DeleteLogsAfter(start int64, qopts ...pg.QOpt) error { - return withObservedExec(o, "DeleteLogsAfter", func() error { - return o.ORM.DeleteLogsAfter(start, qopts...) +func (o *ObservedORM) DeleteLogsAndBlocksAfter(start int64, qopts ...pg.QOpt) error { + return withObservedExec(o, "DeleteLogsAndBlocksAfter", func() error { + return o.ORM.DeleteLogsAndBlocksAfter(start, qopts...) }) } diff --git a/core/chains/evm/logpoller/observability_test.go b/core/chains/evm/logpoller/observability_test.go index 0d3eadf47d..ded3d7854d 100644 --- a/core/chains/evm/logpoller/observability_test.go +++ b/core/chains/evm/logpoller/observability_test.go @@ -38,7 +38,7 @@ func TestMultipleMetricsArePublished(t *testing.T) { _, _ = orm.SelectLatestLogEventSigsAddrsWithConfs(0, []common.Address{{}}, []common.Hash{{}}, 1, pg.WithParentCtx(ctx)) _, _ = orm.SelectIndexedLogsCreatedAfter(common.Address{}, common.Hash{}, 1, []common.Hash{}, time.Now(), 0, pg.WithParentCtx(ctx)) _ = orm.InsertLogs([]Log{}, pg.WithParentCtx(ctx)) - _ = orm.InsertBlock(common.Hash{}, 1, time.Now(), 0, pg.WithParentCtx(ctx)) + _ = orm.InsertLogsWithBlock([]Log{}, NewLogPollerBlock(common.Hash{}, 1, time.Now(), 0), pg.WithParentCtx(ctx)) require.Equal(t, 13, testutil.CollectAndCount(orm.queryDuration)) require.Equal(t, 10, testutil.CollectAndCount(orm.datasetSize)) diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index e044be2e0c..a1b86d2cb2 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -20,17 +20,15 @@ import ( // it exposes some of the database implementation details (e.g. pg.Q). Ideally it should be agnostic and could be applied to any persistence layer. // What is more, LogPoller should not be aware of the underlying database implementation and delegate all the queries to the ORM. type ORM interface { - Q() pg.Q InsertLogs(logs []Log, qopts ...pg.QOpt) error - InsertBlock(blockHash common.Hash, blockNumber int64, blockTimestamp time.Time, lastFinalizedBlockNumber int64, qopts ...pg.QOpt) error + InsertLogsWithBlock(logs []Log, block LogPollerBlock, qopts ...pg.QOpt) error InsertFilter(filter Filter, qopts ...pg.QOpt) error LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) DeleteFilter(name string, qopts ...pg.QOpt) error - DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error - DeleteLogsAfter(start int64, qopts ...pg.QOpt) error + DeleteLogsAndBlocksAfter(start int64, qopts ...pg.QOpt) error DeleteExpiredLogs(qopts ...pg.QOpt) error GetBlocksRange(start int64, end int64, qopts ...pg.QOpt) ([]LogPollerBlock, error) @@ -58,6 +56,7 @@ type ORM interface { type DbORM struct { chainID *big.Int q pg.Q + lggr logger.Logger } // NewORM creates a DbORM scoped to chainID. @@ -67,13 +66,10 @@ func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) * return &DbORM{ chainID: chainID, q: q, + lggr: lggr, } } -func (o *DbORM) Q() pg.Q { - return o.q -} - // InsertBlock is idempotent to support replays. func (o *DbORM) InsertBlock(blockHash common.Hash, blockNumber int64, blockTimestamp time.Time, finalizedBlock int64, qopts ...pg.QOpt) error { args, err := newQueryArgs(o.chainID). @@ -191,12 +187,6 @@ func (o *DbORM) SelectLatestLogByEventSigWithConfs(eventSig common.Hash, address return &l, nil } -// DeleteBlocksAfter delete all blocks after and including start. -func (o *DbORM) DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - return q.ExecQ(`DELETE FROM evm.log_poller_blocks WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) -} - // DeleteBlocksBefore delete all blocks before and including end. func (o *DbORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) @@ -204,9 +194,31 @@ func (o *DbORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { return err } -func (o *DbORM) DeleteLogsAfter(start int64, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - return q.ExecQ(`DELETE FROM evm.logs WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) +func (o *DbORM) DeleteLogsAndBlocksAfter(start int64, qopts ...pg.QOpt) error { + // These deletes are bounded by reorg depth, so they are + // fast and should not slow down the log readers. + return o.q.WithOpts(qopts...).Transaction(func(tx pg.Queryer) error { + args, err := newQueryArgs(o.chainID). + withStartBlock(start). + toArgs() + if err != nil { + o.lggr.Error("Cant build args for DeleteLogsAndBlocksAfter queries", "err", err) + return err + } + + _, err = tx.NamedExec(`DELETE FROM evm.log_poller_blocks WHERE block_number >= :start_block AND evm_chain_id = :evm_chain_id`, args) + if err != nil { + o.lggr.Warnw("Unable to clear reorged blocks, retrying", "err", err) + return err + } + + _, err = tx.NamedExec(`DELETE FROM evm.logs WHERE block_number >= :start_block AND evm_chain_id = :evm_chain_id`, args) + if err != nil { + o.lggr.Warnw("Unable to clear reorged logs, retrying", "err", err) + return err + } + return nil + }) } type Exp struct { @@ -233,13 +245,35 @@ func (o *DbORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { // InsertLogs is idempotent to support replays. func (o *DbORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { - for _, log := range logs { - if o.chainID.Cmp(log.EvmChainId.ToInt()) != 0 { - return errors.Errorf("invalid chainID in log got %v want %v", log.EvmChainId.ToInt(), o.chainID) - } + if err := o.validateLogs(logs); err != nil { + return err } - q := o.q.WithOpts(qopts...) + return o.q.WithOpts(qopts...).Transaction(func(tx pg.Queryer) error { + return o.insertLogsWithinTx(logs, tx) + }) +} + +func (o *DbORM) InsertLogsWithBlock(logs []Log, block LogPollerBlock, qopts ...pg.QOpt) error { + // Optimization, don't open TX when there is only a block to be persisted + if len(logs) == 0 { + return o.InsertBlock(block.BlockHash, block.BlockNumber, block.BlockTimestamp, block.FinalizedBlockNumber, qopts...) + } + + if err := o.validateLogs(logs); err != nil { + return err + } + + // Block and logs goes with the same TX to ensure atomicity + return o.q.WithOpts(qopts...).Transaction(func(tx pg.Queryer) error { + if err := o.InsertBlock(block.BlockHash, block.BlockNumber, block.BlockTimestamp, block.FinalizedBlockNumber, pg.WithQueryer(tx)); err != nil { + return err + } + return o.insertLogsWithinTx(logs, tx) + }) +} + +func (o *DbORM) insertLogsWithinTx(logs []Log, tx pg.Queryer) error { batchInsertSize := 4000 for i := 0; i < len(logs); i += batchInsertSize { start, end := i, i+batchInsertSize @@ -247,12 +281,14 @@ func (o *DbORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { end = len(logs) } - err := q.ExecQNamed(` - INSERT INTO evm.logs - (evm_chain_id, log_index, block_hash, block_number, block_timestamp, address, event_sig, topics, tx_hash, data, created_at) + _, err := tx.NamedExec(` + INSERT INTO evm.logs + (evm_chain_id, log_index, block_hash, block_number, block_timestamp, address, event_sig, topics, tx_hash, data, created_at) VALUES - (:evm_chain_id, :log_index, :block_hash, :block_number, :block_timestamp, :address, :event_sig, :topics, :tx_hash, :data, NOW()) - ON CONFLICT DO NOTHING`, logs[start:end]) + (:evm_chain_id, :log_index, :block_hash, :block_number, :block_timestamp, :address, :event_sig, :topics, :tx_hash, :data, NOW()) + ON CONFLICT DO NOTHING`, + logs[start:end], + ) if err != nil { if errors.Is(err, context.DeadlineExceeded) && batchInsertSize > 500 { @@ -267,6 +303,15 @@ func (o *DbORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { return nil } +func (o *DbORM) validateLogs(logs []Log) error { + for _, log := range logs { + if o.chainID.Cmp(log.EvmChainId.ToInt()) != 0 { + return errors.Errorf("invalid chainID in log got %v want %v", log.EvmChainId.ToInt(), o.chainID) + } + } + return nil +} + func (o *DbORM) SelectLogsByBlockRange(start, end int64) ([]Log, error) { args, err := newQueryArgs(o.chainID). withStartBlock(start). diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 66e1afdc93..887984055e 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -4,6 +4,7 @@ import ( "bytes" "database/sql" "fmt" + "math" "math/big" "testing" "time" @@ -15,7 +16,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -179,13 +183,13 @@ func TestORM(t *testing.T) { assert.Equal(t, int64(12), latest.BlockNumber) // Delete a block (only 10 on chain). - require.NoError(t, o1.DeleteBlocksAfter(10)) + require.NoError(t, o1.DeleteLogsAndBlocksAfter(10)) _, err = o1.SelectBlockByHash(common.HexToHash("0x1234")) require.Error(t, err) assert.True(t, errors.Is(err, sql.ErrNoRows)) // Delete blocks from another chain. - require.NoError(t, o2.DeleteBlocksAfter(11)) + require.NoError(t, o2.DeleteLogsAndBlocksAfter(11)) _, err = o2.SelectBlockByHash(common.HexToHash("0x1234")) require.Error(t, err) assert.True(t, errors.Is(err, sql.ErrNoRows)) @@ -318,7 +322,6 @@ func TestORM(t *testing.T) { require.Error(t, err) assert.True(t, errors.Is(err, sql.ErrNoRows)) // With block 12, anything <=2 should work - require.NoError(t, o1.DeleteBlocksAfter(10)) require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 11, time.Now(), 0)) require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 12, time.Now(), 0)) _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) @@ -421,7 +424,7 @@ func TestORM(t *testing.T) { assert.Len(t, logs, 7) // Delete logs after should delete all logs. - err = o1.DeleteLogsAfter(1) + err = o1.DeleteLogsAndBlocksAfter(1) require.NoError(t, err) logs, err = o1.SelectLogsByBlockRange(1, latest.BlockNumber) require.NoError(t, err) @@ -1301,3 +1304,133 @@ func TestNestedLogPollerBlocksQuery(t *testing.T) { require.NoError(t, err) require.Len(t, logs, 0) } + +func TestInsertLogsWithBlock(t *testing.T) { + chainID := testutils.NewRandomEVMChainID() + event := utils.RandomBytes32() + address := utils.RandomAddress() + + // We need full db here, because we want to test transaction rollbacks. + // Using pgtest.NewSqlxDB(t) will run all tests in TXs which is not desired for this type of test + // (inner tx rollback will rollback outer tx, blocking rest of execution) + _, db := heavyweight.FullTestDBV2(t, nil) + o := logpoller.NewORM(chainID, db, logger.TestLogger(t), pgtest.NewQConfig(true)) + + correctLog := GenLog(chainID, 1, 1, utils.RandomAddress().String(), event[:], address) + invalidLog := GenLog(chainID, -10, -10, utils.RandomAddress().String(), event[:], address) + correctBlock := logpoller.NewLogPollerBlock(utils.RandomBytes32(), 20, time.Now(), 10) + invalidBlock := logpoller.NewLogPollerBlock(utils.RandomBytes32(), -10, time.Now(), -10) + + tests := []struct { + name string + logs []logpoller.Log + block logpoller.LogPollerBlock + shouldRollback bool + }{ + { + name: "properly persist all data", + logs: []logpoller.Log{correctLog}, + block: correctBlock, + shouldRollback: false, + }, + { + name: "rollbacks transaction when block is invalid", + logs: []logpoller.Log{correctLog}, + block: invalidBlock, + shouldRollback: true, + }, + { + name: "rollbacks transaction when log is invalid", + logs: []logpoller.Log{invalidLog}, + block: correctBlock, + shouldRollback: true, + }, + { + name: "rollback when only some logs are invalid", + logs: []logpoller.Log{correctLog, invalidLog}, + block: correctBlock, + shouldRollback: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // clean all logs and blocks between test cases + defer func() { _ = o.DeleteLogsAndBlocksAfter(0) }() + insertError := o.InsertLogsWithBlock(tt.logs, tt.block) + + logs, logsErr := o.SelectLogs(0, math.MaxInt, address, event) + block, blockErr := o.SelectLatestBlock() + + if tt.shouldRollback { + assert.Error(t, insertError) + + assert.NoError(t, logsErr) + assert.Len(t, logs, 0) + + assert.Error(t, blockErr) + } else { + assert.NoError(t, insertError) + + assert.NoError(t, logsErr) + assert.Len(t, logs, len(tt.logs)) + + assert.NoError(t, blockErr) + assert.Equal(t, block.BlockNumber, tt.block.BlockNumber) + } + }) + } +} + +func TestInsertLogsInTx(t *testing.T) { + chainID := testutils.NewRandomEVMChainID() + event := utils.RandomBytes32() + address := utils.RandomAddress() + maxLogsSize := 9000 + + // We need full db here, because we want to test transaction rollbacks. + _, db := heavyweight.FullTestDBV2(t, nil) + o := logpoller.NewORM(chainID, db, logger.TestLogger(t), pgtest.NewQConfig(true)) + + logs := make([]logpoller.Log, maxLogsSize, maxLogsSize+1) + for i := 0; i < maxLogsSize; i++ { + logs[i] = GenLog(chainID, int64(i+1), int64(i+1), utils.RandomAddress().String(), event[:], address) + } + invalidLog := GenLog(chainID, -10, -10, utils.RandomAddress().String(), event[:], address) + + tests := []struct { + name string + logs []logpoller.Log + shouldRollback bool + }{ + { + name: "all logs persisted", + logs: logs, + shouldRollback: false, + }, + { + name: "rollback when invalid log is passed", + logs: append(logs, invalidLog), + shouldRollback: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // clean all logs and blocks between test cases + defer func() { _ = o.DeleteLogsAndBlocksAfter(0) }() + + insertErr := o.InsertLogs(tt.logs) + logsFromDb, err := o.SelectLogs(0, math.MaxInt, address, event) + assert.NoError(t, err) + + if tt.shouldRollback { + assert.Error(t, insertErr) + assert.Len(t, logsFromDb, 0) + } else { + assert.NoError(t, insertErr) + assert.Len(t, logsFromDb, len(tt.logs)) + } + }) + } +} From c8902245b2847fd3c201ebc10a992181f84a3d02 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 13 Nov 2023 13:03:15 -0500 Subject: [PATCH 137/327] bumping relay and wiring logger through (#11172) --- core/cmd/shell.go | 5 +++-- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 595c42b9fe..e1ac0b99ca 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -60,7 +60,7 @@ var ( grpcOpts loop.GRPCOpts ) -func initGlobals(cfgProm config.Prometheus, cfgTracing config.Tracing) error { +func initGlobals(cfgProm config.Prometheus, cfgTracing config.Tracing, logger logger.Logger) error { // Avoid double initializations, but does not prevent relay methods from being called multiple times. var err error initGlobalsOnce.Do(func() { @@ -71,6 +71,7 @@ func initGlobals(cfgProm config.Prometheus, cfgTracing config.Tracing) error { CollectorTarget: cfgTracing.CollectorTarget(), NodeAttributes: cfgTracing.Attributes(), SamplingRatio: cfgTracing.SamplingRatio(), + OnDialError: func(error) { logger.Errorw("Failed to dial", "err", err) }, }) }) return err @@ -134,7 +135,7 @@ type ChainlinkAppFactory struct{} // NewApplication returns a new instance of the node with the given config. func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.GeneralConfig, appLggr logger.Logger, db *sqlx.DB) (app chainlink.Application, err error) { - err = initGlobals(cfg.Prometheus(), cfg.Tracing()) + err = initGlobals(cfg.Prometheus(), cfg.Tracing(), appLggr) if err != nil { appLggr.Errorf("Failed to initialize globals: %v", err) } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index bb68175ddf..eb41312a6a 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.20231108215906-8bbaf383b742 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a // 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 bd3b75d37a..35e85fe2c9 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.20231108215906-8bbaf383b742 h1:28XkPE6YfJ4uabTX9/7sueRV6IKtY4hcm1nIt1e6b20= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a h1:G/pD8uI1PULRJU8Y3eLLzjqQBp9ruG9hj+wWxtyrgTo= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a/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/go.mod b/go.mod index 8a4d58469c..0a85fe7f48 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.20231108215906-8bbaf383b742 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a 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 1b96c936c5..7fe91a6b12 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.20231108215906-8bbaf383b742 h1:28XkPE6YfJ4uabTX9/7sueRV6IKtY4hcm1nIt1e6b20= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a h1:G/pD8uI1PULRJU8Y3eLLzjqQBp9ruG9hj+wWxtyrgTo= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a/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 b5455838b5..a943e1c41a 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.20231108215906-8bbaf383b742 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a // 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 fc486e5451..5719c36b5a 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.20231108215906-8bbaf383b742 h1:28XkPE6YfJ4uabTX9/7sueRV6IKtY4hcm1nIt1e6b20= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108215906-8bbaf383b742/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a h1:G/pD8uI1PULRJU8Y3eLLzjqQBp9ruG9hj+wWxtyrgTo= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a/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= From 58b0e2536cad8f183865cc2004cd6969492c0816 Mon Sep 17 00:00:00 2001 From: FelixFan1992 Date: Mon, 13 Nov 2023 13:38:17 -0500 Subject: [PATCH 138/327] add ocr3-automation telemetry type (#11087) * add ocr3-automation telemetry type * pass ocr3 automation telem type to 2.1 --- core/services/ocr2/delegate.go | 2 +- core/services/synchronization/common.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 9905ed6ae6..bbb3b5cf7a 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -1122,7 +1122,7 @@ func (d *Delegate) newServicesOCR2Keepers21( ContractConfigTracker: keeperProvider.ContractConfigTracker(), KeepersDatabase: ocrDB, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR2Automation), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR3Automation), OffchainConfigDigester: keeperProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: services.Keyring(), diff --git a/core/services/synchronization/common.go b/core/services/synchronization/common.go index 32f3a86c6f..584f5b2438 100644 --- a/core/services/synchronization/common.go +++ b/core/services/synchronization/common.go @@ -22,6 +22,7 @@ const ( OCR3Mercury TelemetryType = "ocr3-mercury" OCR2VRF TelemetryType = "ocr2-vrf" AutomationCustom TelemetryType = "automation-custom" + OCR3Automation TelemetryType = "ocr3-automation" ) type TelemPayload struct { From 023985b15d3a58db8425bc30aed49cca454679f4 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Mon, 13 Nov 2023 14:53:46 -0500 Subject: [PATCH 139/327] [Functions] Coordinator v1.1 changes (#11269) * inline abi decode and reduce string length * mv ChainSpecificUtil to lib * Regenerate geth wrappers & gas snapshot --------- Co-authored-by: Rens Rooimans --- .../gas-snapshots/functions.gas-snapshot | 24 +++++++++---------- .../functions/dev/v1_X/FunctionsBilling.sol | 2 +- .../dev/v1_X/FunctionsCoordinator.sol | 20 +++++++--------- .../{ => libraries}/ChainSpecificUtil.sol | 4 ++-- .../functions_coordinator.go | 2 +- ...rapper-dependency-versions-do-not-edit.txt | 2 +- 6 files changed, 25 insertions(+), 29 deletions(-) rename contracts/src/v0.8/functions/dev/v1_X/{ => libraries}/ChainSpecificUtil.sol (94%) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 521b3bffac..82b5b494a7 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: 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) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14577815) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14577793) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14577809) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14589229) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14589206) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14589178) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14589129) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14589118) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14589162) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -141,10 +141,10 @@ 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, μ: 43863, ~: 45548) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46375, ~: 48060) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43508, ~: 45548) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46020, ~: 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_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) 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 e4b6fe7d90..cb4f2f4567 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -10,7 +10,7 @@ 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"; +import {ChainSpecificUtil} from "./libraries/ChainSpecificUtil.sol"; /// @title Functions Billing contract /// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). 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 15949a497e..16e9029ce3 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -133,15 +133,13 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli address[MAX_NUM_ORACLES] memory /*signers*/, bytes calldata report ) internal override { - bytes32[] memory requestIds; - bytes[] memory results; - bytes[] memory errors; - bytes[] memory onchainMetadata; - bytes[] memory offchainMetadata; - (requestIds, results, errors, onchainMetadata, offchainMetadata) = abi.decode( - report, - (bytes32[], bytes[], bytes[], bytes[], bytes[]) - ); + ( + bytes32[] memory requestIds, + bytes[] memory results, + bytes[] memory errors, + bytes[] memory onchainMetadata, + bytes[] memory offchainMetadata + ) = abi.decode(report, (bytes32[], bytes[], bytes[], bytes[], bytes[])); uint256 numberOfFulfillments = uint8(requestIds.length); if ( @@ -151,9 +149,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli numberOfFulfillments != onchainMetadata.length || numberOfFulfillments != offchainMetadata.length ) { - revert ReportInvalid( - "All fields on the report must be of equal length: requestIds, results, errors, onchainMetadata, offchainMetadata" - ); + revert ReportInvalid("Fields must be equal length"); } // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig diff --git a/contracts/src/v0.8/functions/dev/v1_X/ChainSpecificUtil.sol b/contracts/src/v0.8/functions/dev/v1_X/libraries/ChainSpecificUtil.sol similarity index 94% rename from contracts/src/v0.8/functions/dev/v1_X/ChainSpecificUtil.sol rename to contracts/src/v0.8/functions/dev/v1_X/libraries/ChainSpecificUtil.sol index f0eec19db2..d6569a256b 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/ChainSpecificUtil.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/libraries/ChainSpecificUtil.sol @@ -1,8 +1,8 @@ // 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"; +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. diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 3e3fac16d1..5f0d2d45f2 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\":[{\"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", + Bin: "0x60a06040523480156200001157600080fd5b50604051620056d0380380620056d083398101604081905262000034916200046d565b8282828233806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000139565b5050506001600160a01b038116620000ed57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200012d82620001e4565b5050505050506200062c565b336001600160a01b03821603620001935760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee62000342565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033790839062000576565b60405180910390a150565b6200034c6200034e565b565b6000546001600160a01b031633146200034c5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000086565b80516001600160a01b0381168114620003c257600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f957634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c257600080fd5b80516001600160481b0381168114620003c257600080fd5b805164ffffffffff81168114620003c257600080fd5b805161ffff81168114620003c257600080fd5b80516001600160e01b0381168114620003c257600080fd5b60008060008385036101608112156200048557600080fd5b6200049085620003aa565b935061012080601f1983011215620004a757600080fd5b620004b1620003c7565b9150620004c160208701620003ff565b8252620004d160408701620003ff565b6020830152620004e460608701620003ff565b6040830152620004f760808701620003ff565b60608301526200050a60a0870162000414565b60808301526200051d60c087016200042c565b60a08301526200053060e0870162000442565b60c08301526101006200054581880162000455565b60e084015262000557828801620003ff565b908301525091506200056d6101408501620003aa565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005c960808401826001600160481b03169052565b5060a0830151620005e360a084018264ffffffffff169052565b5060c0830151620005fa60c084018261ffff169052565b5060e08301516200061660e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805161505e6200067260003960008181610845015281816109d301528181610ca601528181610f3a01528181611045015281816117890152613490015261505e6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046139d4565b61059c565b005b6101a56101b5366004613b7d565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613ca1565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613d42565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613dd1565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046139d4565b610d92565b6102a0610de2565b6040516102039190613e5b565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613e6e565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613e87565b610fd4565b6040516102039190613fdc565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004614030565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b60405161020391906140e7565b61053b6105363660046141d7565b611785565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f66118e5565b6101a561056e3660046142f0565b61193c565b61057b6124b8565b604051908152602001610203565b6101a56105973660046143bd565b612711565b6105a4612725565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec828483614473565b505050565b6105f96127a8565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906108369083906140e7565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d29190614599565b905090565b6108df6127b0565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6127a8565b610ba26127b0565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561460a565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614639565b9050610bb1565b5050565b610d9a612725565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec828483614473565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e60906143da565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea8906143da565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed4906143da565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614671565b61295c565b90506110bf60608301604084016143bd565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a0880161475e565b61111f610160880161014089016143bd565b611129888061477b565b61113b6101208b016101008c016147e0565b60208b01356111516101008d0160e08e016147fb565b8b60405161116799989796959493929190614818565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16111d68a8a8a8a8a8a612dfa565b6003546000906002906111f49060ff808216916101009004166148c0565b6111fe9190614908565b6112099060016148c0565b60ff169050878114611277576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b878614611306576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e6774680000000000000000000000000000000000000000000000006064820152608401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113495761134961492a565b600281111561135a5761135a61492a565b90525090506002816020015160028111156113775761137761492a565b141580156113c057506006816000015160ff168154811061139a5761139a61460a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611427576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b5050505061143361396c565b6000808a8a604051611446929190614959565b60405190819003812061145d918e90602001614969565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117675760006001848984602081106114c6576114c661460a565b6114d391901a601b6148c0565b8e8e868181106114e5576114e561460a565b905060200201358d8d878181106114fe576114fe61460a565b905060200201356040516000815260200160405260405161153b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561155d573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156115dd576115dd61492a565b60028111156115ee576115ee61492a565b905250925060018360200151600281111561160b5761160b61492a565b14611672576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061168c5761168c61460a565b602002015173ffffffffffffffffffffffffffffffffffffffff161461170e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117285761172861460a565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117536001866148c0565b9450508061176090614639565b90506114a7565b505050611778833383858e8e612eb1565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561182557600080fd5b505afa158015611839573d6000803e3d6000fd5b5050505066038d7ea4c6800082111561187e576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611888610841565b905060006118cb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b90506118d9858583856130b0565b98975050505050505050565b6060600c80546118f4906143da565b905060000361192f576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea8906143da565b855185518560ff16601f8311156119af576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611a19576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611aa7576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611ab281600361497d565b8311611b1a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611b22612725565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611b69908861321d565b60055415611d1e57600554600090611b8390600190614994565b9050600060058281548110611b9a57611b9a61460a565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611bd457611bd461460a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611c5457611c546149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611cbd57611cbd6149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611b69915050565b60005b8151518110156122d557815180516000919083908110611d4357611d4361460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611dc8576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d70747900000000000000006044820152606401610b0d565b600073ffffffffffffffffffffffffffffffffffffffff1682602001518281518110611df657611df661460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611e7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d7074790000006044820152606401610b0d565b60006004600084600001518481518110611e9757611e9761460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611ee157611ee161492a565b14611f48576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611f7957611f7961460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561201a5761201a61492a565b02179055506000915061202a9050565b60046000846020015184815181106120445761204461460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561208e5761208e61492a565b146120f5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106121285761212861460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156121c9576121c961492a565b0217905550508251805160059250839081106121e7576121e761460a565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106122635761226361460a565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806122cd81614639565b915050611d21565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161238d918491740100000000000000000000000000000000000000009004166149d6565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123ec4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613236565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986124a3988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926149f3565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266a9190614aa3565b50935050925050804261267d9190614994565b836020015163ffffffff1610801561269f57506000836020015163ffffffff16115b156126cd57505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361270a576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b612719612725565b612722816132e1565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146127a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6127a6612725565b600b546bffffffffffffffffffffffff166000036127ca57565b60006127d4610de2565b80519091506000819003612814576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546000906128339083906bffffffffffffffffffffffff16614af3565b905060005b828110156128fe5781600a60008684815181106128575761285761460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128bf9190614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806128f790614639565b9050612838565b506129098282614b43565b600b80546000906129299084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612b17576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612b548560e001513a8488608001516130b0565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612bb0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612bc99190614b6b565b905060003087604001518860a001518960c001516001612be99190614b7e565b8a5180516020918201206101008d015160e08e0151604051612c9d98979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612dac9190613fdc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612e0782602061497d565b612e1285602061497d565b612e1e88610144614b6b565b612e289190614b6b565b612e329190614b6b565b612e3d906000614b6b565b9050368114612ea8576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b600080808080612ec386880188614c7a565b84519499509297509095509350915060ff16801580612ee3575084518114155b80612eef575083518114155b80612efb575082518114155b80612f07575081518114155b15612f6e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e67746800000000006044820152606401610b0d565b60005b818110156130a1576000613006888381518110612f9057612f9061460a565b6020026020010151888481518110612faa57612faa61460a565b6020026020010151888581518110612fc457612fc461460a565b6020026020010151888681518110612fde57612fde61460a565b6020026020010151888781518110612ff857612ff861460a565b6020026020010151886133d6565b9050600081600681111561301c5761301c61492a565b1480613039575060018160068111156130375761303761492a565b145b15613090578782815181106130505761305061460a565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b5061309a81614639565b9050612f71565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561310b57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b600854600090612710906131259063ffffffff168761497d565b61312f9190614d4c565b6131399086614b6b565b60085490915060009087906131729063ffffffff6c010000000000000000000000008204811691680100000000000000009004166149d6565b61317c91906149d6565b63ffffffff16905060006131c66000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b905060006131e7826131d8858761497d565b6131e29190614b6b565b61382c565b9050600061320368ffffffffffffffffff808916908a16614b1e565b905061320f8183614b1e565b9a9950505050505050505050565b6000613227610de2565b511115610d8e57610d8e6127b0565b6000808a8a8a8a8a8a8a8a8a60405160200161325a99989796959493929190614d60565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133ed9190614e2c565b905060003a8261012001518361010001516134089190614ef4565b64ffffffffff16613419919061497d565b905060008460ff166134616000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b61346b9190614d4c565b9050600061347c6131e28385614b6b565b905060006134893a61382c565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff16896134e89190614b1e565b338d6040518763ffffffff1660e01b815260040161350b96959493929190614f12565b60408051808303816000875af1158015613529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354d9190614f8e565b909250905060008260068111156135665761356661492a565b1480613583575060018260068111156135815761358161492a565b145b156136d95760008e8152600760205260408120556135a18185614b1e565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161360d91859116614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b61368c9190614b1e565b6136969190614b1e565b6136a09190614b1e565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b6000466136f681613860565b1561377257606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376b9190614fc1565b9392505050565b61377b81613883565b156138235773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161500a604891396040516020016137db929190614fda565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016138069190613ca1565b602060405180830381865afa158015613747573d6000803e3d6000fd5b50600092915050565b600061385a6138396124b8565b61384b84670de0b6b3a764000061497d565b6138559190614d4c565b6138ca565b92915050565b600061a4b1821480613874575062066eed82145b8061385a57505062066eee1490565b6000600a82148061389557506101a482145b806138a2575062aa37dc82145b806138ae575061210582145b806138bb575062014a3382145b8061385a57505062014a341490565b60006bffffffffffffffffffffffff821115613968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261399d57600080fd5b50813567ffffffffffffffff8111156139b557600080fd5b6020830191508360208285010111156139cd57600080fd5b9250929050565b600080602083850312156139e757600080fd5b823567ffffffffffffffff8111156139fe57600080fd5b613a0a8582860161398b565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613a6957613a69613a16565b60405290565b604051610160810167ffffffffffffffff81118282101715613a6957613a69613a16565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a16565b604052919050565b63ffffffff8116811461272257600080fd5b803561117081613ae2565b68ffffffffffffffffff8116811461272257600080fd5b803561117081613aff565b64ffffffffff8116811461272257600080fd5b803561117081613b21565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613b9057600080fd5b613b98613a45565b613ba183613af4565b8152613baf60208401613af4565b6020820152613bc060408401613af4565b6040820152613bd160608401613af4565b6060820152613be260808401613b16565b6080820152613bf360a08401613b34565b60a0820152613c0460c08401613b3f565b60c0820152613c1560e08401613b51565b60e0820152610100613c28818501613af4565b908201529392505050565b60005b83811015613c4e578181015183820152602001613c36565b50506000910152565b60008151808452613c6f816020860160208601613c33565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061376b6020830184613c57565b600082601f830112613cc557600080fd5b813567ffffffffffffffff811115613cdf57613cdf613a16565b613d1060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613a93565b818152846020838601011115613d2557600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613d5457600080fd5b813567ffffffffffffffff811115613d6b57600080fd5b613d7784828501613cb4565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461272257600080fd5b803561117081613d7f565b6bffffffffffffffffffffffff8116811461272257600080fd5b803561117081613dac565b60008060408385031215613de457600080fd5b8235613def81613d7f565b91506020830135613dff81613dac565b809150509250929050565b600081518084526020808501945080840160005b83811015613e5057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e1e565b509495945050505050565b60208152600061376b6020830184613e0a565b600060208284031215613e8057600080fd5b5035919050565b600060208284031215613e9957600080fd5b813567ffffffffffffffff811115613eb057600080fd5b8201610160818503121561376b57600080fd5b805182526020810151613eee602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613f0e60408401826bffffffffffffffffffffffff169052565b506060810151613f36606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613f52608084018267ffffffffffffffff169052565b5060a0810151613f6a60a084018263ffffffff169052565b5060c0810151613f8760c084018268ffffffffffffffffff169052565b5060e0810151613fa460e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161385a8284613ec3565b60008083601f840112613ffd57600080fd5b50813567ffffffffffffffff81111561401557600080fd5b6020830191508360208260051b85010111156139cd57600080fd5b60008060008060008060008060e0898b03121561404c57600080fd5b606089018a81111561405d57600080fd5b8998503567ffffffffffffffff8082111561407757600080fd5b6140838c838d0161398b565b909950975060808b013591508082111561409c57600080fd5b6140a88c838d01613feb565b909750955060a08b01359150808211156140c157600080fd5b506140ce8b828c01613feb565b999c989b50969995989497949560c00135949350505050565b815163ffffffff90811682526020808401518216908301526040808401518216908301526060808401519182169083015261012082019050608083015161413b608084018268ffffffffffffffffff169052565b5060a083015161415460a084018264ffffffffff169052565b5060c083015161416a60c084018261ffff169052565b5060e083015161419a60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461272257600080fd5b8035611170816141b6565b6000806000806000608086880312156141ef57600080fd5b85356141fa816141b6565b9450602086013567ffffffffffffffff81111561421657600080fd5b6142228882890161398b565b909550935050604086013561423681613ae2565b949793965091946060013592915050565b600067ffffffffffffffff82111561426157614261613a16565b5060051b60200190565b600082601f83011261427c57600080fd5b8135602061429161428c83614247565b613a93565b82815260059290921b840181019181810190868411156142b057600080fd5b8286015b848110156142d45780356142c781613d7f565b83529183019183016142b4565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561430957600080fd5b863567ffffffffffffffff8082111561432157600080fd5b61432d8a838b0161426b565b9750602089013591508082111561434357600080fd5b61434f8a838b0161426b565b965061435d60408a016142df565b9550606089013591508082111561437357600080fd5b61437f8a838b01613cb4565b945061438d60808a016141cc565b935060a08901359150808211156143a357600080fd5b506143b089828a01613cb4565b9150509295509295509295565b6000602082840312156143cf57600080fd5b813561376b81613d7f565b600181811c908216806143ee57607f821691505b602082108103614427577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156144545750805b601f850160051c820191505b81811015610a8857828155600101614460565b67ffffffffffffffff83111561448b5761448b613a16565b61449f8361449983546143da565b8361442d565b6000601f8411600181146144f157600085156144bb5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614587565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145405786850135825560209485019460019092019101614520565b508682101561457b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613aff565b6000602082840312156145ab57600080fd5b815161376b81613aff565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561270a5761270a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361466a5761466a6145b6565b5060010190565b6000610160823603121561468457600080fd5b61468c613a6f565b823567ffffffffffffffff8111156146a357600080fd5b6146af36828601613cb4565b825250602083013560208201526146c860408401613da1565b60408201526146d960608401613dc6565b60608201526146ea60808401613b16565b60808201526146fb60a084016141cc565b60a082015261470c60c084016141cc565b60c082015261471d60e08401613af4565b60e0820152610100614730818501613b3f565b908201526101206147428482016141cc565b90820152610140614754848201613da1565b9082015292915050565b60006020828403121561477057600080fd5b813561376b816141b6565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126147b057600080fd5b83018035915067ffffffffffffffff8211156147cb57600080fd5b6020019150368190038213156139cd57600080fd5b6000602082840312156147f257600080fd5b61376b82613b3f565b60006020828403121561480d57600080fd5b813561376b81613ae2565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061320f60e0830184613ec3565b60ff818116838216019081111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061491b5761491b6148d9565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761385a5761385a6145b6565b8181038181111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561270a5761270a6145b6565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152614a238184018a613e0a565b90508281036080840152614a378189613e0a565b905060ff871660a084015282810360c0840152614a548187613c57565b905067ffffffffffffffff851660e0840152828103610100840152614a798185613c57565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a08688031215614abb57600080fd5b614ac486614a89565b9450602086015193506040860151925060608601519150614ae760808701614a89565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614b1257614b126148d9565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561270a5761270a6145b6565b6bffffffffffffffffffffffff8181168382160280821691908281146141ae576141ae6145b6565b8082018082111561385a5761385a6145b6565b67ffffffffffffffff81811683821601908082111561270a5761270a6145b6565b600082601f830112614bb057600080fd5b81356020614bc061428c83614247565b82815260059290921b84018101918181019086841115614bdf57600080fd5b8286015b848110156142d45780358352918301918301614be3565b600082601f830112614c0b57600080fd5b81356020614c1b61428c83614247565b82815260059290921b84018101918181019086841115614c3a57600080fd5b8286015b848110156142d457803567ffffffffffffffff811115614c5e5760008081fd5b614c6c8986838b0101613cb4565b845250918301918301614c3e565b600080600080600060a08688031215614c9257600080fd5b853567ffffffffffffffff80821115614caa57600080fd5b614cb689838a01614b9f565b96506020880135915080821115614ccc57600080fd5b614cd889838a01614bfa565b95506040880135915080821115614cee57600080fd5b614cfa89838a01614bfa565b94506060880135915080821115614d1057600080fd5b614d1c89838a01614bfa565b93506080880135915080821115614d3257600080fd5b50614d3f88828901614bfa565b9150509295509295909350565b600082614d5b57614d5b6148d9565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614da78285018b613e0a565b91508382036080850152614dbb828a613e0a565b915060ff881660a085015283820360c0850152614dd88288613c57565b90861660e08501528381036101008501529050614a798185613c57565b805161117081613d7f565b805161117081613dac565b8051611170816141b6565b805161117081613ae2565b805161117081613b21565b60006101608284031215614e3f57600080fd5b614e47613a6f565b82518152614e5760208401614df5565b6020820152614e6860408401614e00565b6040820152614e7960608401614df5565b6060820152614e8a60808401614e0b565b6080820152614e9b60a08401614e16565b60a0820152614eac60c0840161458e565b60c0820152614ebd60e0840161458e565b60e0820152610100614ed0818501614e21565b90820152610120614ee2848201614e21565b90820152610140613c28848201614e16565b64ffffffffff81811683821601908082111561270a5761270a6145b6565b6000610200808352614f268184018a613c57565b90508281036020840152614f3a8189613c57565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614f83905060a0830184613ec3565b979650505050505050565b60008060408385031215614fa157600080fd5b825160078110614fb057600080fd5b6020840151909250613dff81613dac565b600060208284031215614fd357600080fd5b5051919050565b60008351614fec818460208801613c33565b835190830190615000818360208801613c33565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } 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 93c4e64a3a..ac1fc4e83d 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 4e05ca5e624b7a1e604b81b84bc088818b376d533f556ba1c2ee586b7eb38b68 +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 97aa7c56d78c703056990eff102279af86b97b11b5855b059e8dd658dc15da8a 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 aa0223133f392f0f02b4e1e563347ad4b3a58afc Mon Sep 17 00:00:00 2001 From: amit-momin <108959691+amit-momin@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:15:46 -0600 Subject: [PATCH 140/327] Decouple job pipeline tables from the TXM DB (#11173) * Decoupled job pipeline tables from the TXM DB * Updated errors to return better context * Updated method comment --- common/txmgr/broadcaster.go | 7 +- common/txmgr/confirmer.go | 6 +- common/txmgr/types/mocks/tx_store.go | 66 ++++++++------ common/txmgr/types/tx.go | 8 ++ common/txmgr/types/tx_store.go | 8 +- core/chains/evm/txmgr/broadcaster_test.go | 1 + core/chains/evm/txmgr/confirmer_test.go | 48 +++++++++-- core/chains/evm/txmgr/evm_tx_store.go | 47 +++++++--- core/chains/evm/txmgr/evm_tx_store_test.go | 85 ++++++++++++++++--- core/chains/evm/txmgr/mocks/evm_tx_store.go | 66 ++++++++------ core/services/pipeline/orm.go | 6 +- core/services/pipeline/runner.go | 2 +- core/services/pipeline/task.eth_tx.go | 1 + core/services/pipeline/task.eth_tx_test.go | 8 ++ ...resume_pipeline_task_flags_to_evm_txes.sql | 15 ++++ 15 files changed, 281 insertions(+), 93 deletions(-) create mode 100644 core/store/migrate/migrations/0209_add_resume_pipeline_task_flags_to_evm_txes.sql diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index d68b509101..00522abf22 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -775,12 +775,17 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save // Now we have an errored pipeline even though the tx succeeded. This case // is relatively benign and probably nobody will ever run into it in // practice, but something to be aware of. - if etx.PipelineTaskRunID.Valid && eb.resumeCallback != nil { + if etx.PipelineTaskRunID.Valid && eb.resumeCallback != nil && etx.SignalCallback { err := eb.resumeCallback(etx.PipelineTaskRunID.UUID, nil, errors.Errorf("fatal error while sending transaction: %s", etx.Error.String)) if errors.Is(err, sql.ErrNoRows) { lgr.Debugw("callback missing or already resumed", "etxID", etx.ID) } else if err != nil { return errors.Wrap(err, "failed to resume pipeline") + } else { + // Mark tx as having completed callback + if err := eb.txStore.UpdateTxCallbackCompleted(ctx, etx.PipelineTaskRunID.UUID, eb.chainID); err != nil { + return err + } } } return eb.txStore.UpdateTxFatalError(ctx, etx) diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index 1d7446d9d2..afb2b3003a 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -1083,7 +1083,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) sen // ResumePendingTaskRuns issues callbacks to task runs that are pending waiting for receipts func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ResumePendingTaskRuns(ctx context.Context, head types.Head[BLOCK_HASH]) error { - receiptsPlus, err := ec.txStore.FindReceiptsPendingConfirmation(ctx, head.BlockNumber(), ec.chainID) + receiptsPlus, err := ec.txStore.FindTxesPendingCallback(ctx, head.BlockNumber(), ec.chainID) if err != nil { return err @@ -1105,6 +1105,10 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Res ec.lggr.Debugw("Callback: resuming tx with receipt", "output", output, "taskErr", taskErr, "pipelineTaskRunID", data.ID) if err := ec.resumeCallback(data.ID, output, taskErr); err != nil { + return fmt.Errorf("failed to resume suspended pipeline run: %w", err) + } + // Mark tx as having completed callback + if err := ec.txStore.UpdateTxCallbackCompleted(ctx, data.ID, ec.chainID); err != nil { return err } } diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index 7da51de606..0e344b9b6f 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -180,32 +180,6 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUns return r0 } -// FindReceiptsPendingConfirmation provides a mock function with given fields: ctx, blockNum, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindReceiptsPendingConfirmation(ctx context.Context, blockNum int64, chainID CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error) { - ret := _m.Called(ctx, blockNum, chainID) - - var r0 []txmgrtypes.ReceiptPlus[R] - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error)); ok { - return rf(ctx, blockNum, chainID) - } - if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) []txmgrtypes.ReceiptPlus[R]); ok { - r0 = rf(ctx, blockNum, chainID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]txmgrtypes.ReceiptPlus[R]) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int64, CHAIN_ID) error); ok { - r1 = rf(ctx, blockNum, chainID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // FindTransactionsConfirmedInBlockRange provides a mock function with given fields: ctx, highBlockNumber, lowBlockNumber, chainID func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) @@ -388,6 +362,32 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesByM return r0, r1 } +// FindTxesPendingCallback provides a mock function with given fields: ctx, blockNum, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error) { + ret := _m.Called(ctx, blockNum, chainID) + + var r0 []txmgrtypes.ReceiptPlus[R] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error)); ok { + return rf(ctx, blockNum, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) []txmgrtypes.ReceiptPlus[R]); ok { + r0 = rf(ctx, blockNum, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]txmgrtypes.ReceiptPlus[R]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, CHAIN_ID) error); ok { + r1 = rf(ctx, blockNum, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, ids, states, chainID) @@ -814,6 +814,20 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAtt return r0 } +// UpdateTxCallbackCompleted provides a mock function with given fields: ctx, pipelineTaskRunRid, chainId +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId CHAIN_ID) error { + ret := _m.Called(ctx, pipelineTaskRunRid, chainId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, CHAIN_ID) error); ok { + r0 = rf(ctx, pipelineTaskRunRid, chainId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // UpdateTxFatalError provides a mock function with given fields: ctx, etx func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFatalError(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx) diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index d95f07afab..11017bd032 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -91,6 +91,9 @@ type TxRequest[ADDR types.Hashable, TX_HASH types.Hashable] struct { // Checker defines the check that should be run before a transaction is submitted on chain. Checker TransmitCheckerSpec[ADDR] + + // Mark tx requiring callback + SignalCallback bool } // TransmitCheckerSpec defines the check that should be performed before a transaction is submitted @@ -217,6 +220,11 @@ type Tx[ // TransmitChecker defines the check that should be performed before a transaction is submitted on // chain. TransmitChecker *datatypes.JSON + + // Marks tx requiring callback + SignalCallback bool + // Marks tx callback as signaled + CallbackCompleted bool } func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetError() error { diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index 83cb4b85ee..c2dfeee414 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -35,8 +35,10 @@ type TxStore[ TxHistoryReaper[CHAIN_ID] TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] - // methods for saving & retreiving receipts - FindReceiptsPendingConfirmation(ctx context.Context, blockNum int64, chainID CHAIN_ID) (receiptsPlus []ReceiptPlus[R], err error) + // Find confirmed txes beyond the minConfirmations param that require callback but have not yet been signaled + FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID CHAIN_ID) (receiptsPlus []ReceiptPlus[R], err error) + // Update tx to mark that its callback has been signaled + UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId CHAIN_ID) error SaveFetchedReceipts(ctx context.Context, receipts []R, chainID CHAIN_ID) (err error) // additional methods for tx store management @@ -93,6 +95,8 @@ type TransactionStore[ SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID CHAIN_ID) error UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState TxAttemptState) error + // Update tx to mark that its callback has been signaled + UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId CHAIN_ID) error UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error UpdateTxFatalError(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index fcbc7a1f4c..460f9629fb 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -1055,6 +1055,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { FeeLimit: gasLimit, State: txmgrcommon.TxUnstarted, PipelineTaskRunID: uuid.NullUUID{UUID: tr.ID, Valid: true}, + SignalCallback: true, } t.Run("with erroring callback bails out", func(t *testing.T) { diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 1385250a20..3a0d33f7ba 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -2933,11 +2933,12 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 1, fromAddress) cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + // Setting both signal_callback and callback_completed to TRUE to simulate a completed pipeline task + // It would only be in a state past suspended if the resume callback was called and callback_completed was set to TRUE + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE, callback_completed = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) - }) t.Run("doesn't process task runs where the receipt is younger than minConfirmations", func(t *testing.T) { @@ -2952,15 +2953,15 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 2, 1, fromAddress) cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) - }) t.Run("processes eth_txes with receipts older than minConfirmations", func(t *testing.T) { ch := make(chan interface{}) + nonce := evmtypes.Nonce(3) var err error ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr @@ -2972,15 +2973,19 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run.ID) - etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 1, fromAddress) + etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(nonce), 1, fromAddress) pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) receipt := cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) go func() { err2 := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err2) + // Retrieve Tx to check if callback completed flag was set to true + updateTx, err3 := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, nonce) + require.NoError(t, err3) + require.Equal(t, true, updateTx.CallbackCompleted) }() select { @@ -3000,6 +3005,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Run("processes eth_txes with receipt older than minConfirmations that reverted", func(t *testing.T) { ch := make(chan interface{}) + nonce := evmtypes.Nonce(4) var err error ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr @@ -3011,17 +3017,21 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run.ID) - etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 4, 1, fromAddress) + etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(nonce), 1, fromAddress) pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) // receipt is not passed through as a value since it reverted and caused an error cltest.MustInsertRevertedEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) go func() { err2 := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err2) + // Retrieve Tx to check if callback completed flag was set to true + updateTx, err3 := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, nonce) + require.NoError(t, err3) + require.Equal(t, true, updateTx.CallbackCompleted) }() select { @@ -3036,6 +3046,28 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Fatal("no value received") } }) + + t.Run("does not mark callback complete if callback fails", func(t *testing.T) { + nonce := evmtypes.Nonce(5) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + return errors.New("error") + }) + + run := cltest.MustInsertPipelineRun(t, db) + tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) + + etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(nonce), 1, fromAddress) + cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + + err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) + require.Error(t, err) + + // Retrieve Tx to check if callback completed flag was left unchanged + updateTx, err := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, nonce) + require.NoError(t, err) + require.Equal(t, false, updateTx.CallbackCompleted) + }) } func ptr[T any](t T) *T { return &t } diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 4db7989b46..c3371fee80 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -115,7 +115,7 @@ type rawOnchainReceipt = evmtypes.Receipt // Does not map to a single database table. // It's comprised of fields from different tables. type dbReceiptPlus struct { - ID uuid.UUID `db:"id"` + ID uuid.UUID `db:"pipeline_task_run_id"` Receipt evmtypes.Receipt `db:"receipt"` FailOnRevert bool `db:"FailOnRevert"` } @@ -180,6 +180,10 @@ type DbEthTx struct { // chain. TransmitChecker *datatypes.JSON InitialBroadcastAt *time.Time + // Marks tx requiring callback + SignalCallback bool + // Marks tx callback as signaled + CallbackCompleted bool } func (db *DbEthTx) FromTx(tx *Tx) { @@ -200,6 +204,8 @@ func (db *DbEthTx) FromTx(tx *Tx) { db.MinConfirmations = tx.MinConfirmations db.TransmitChecker = tx.TransmitChecker db.InitialBroadcastAt = tx.InitialBroadcastAt + db.SignalCallback = tx.SignalCallback + db.CallbackCompleted = tx.CallbackCompleted if tx.ChainID != nil { db.EVMChainID = *utils.NewBig(tx.ChainID) @@ -233,6 +239,8 @@ func (db DbEthTx) ToTx(tx *Tx) { tx.ChainID = db.EVMChainID.ToInt() tx.TransmitChecker = db.TransmitChecker tx.InitialBroadcastAt = db.InitialBroadcastAt + tx.SignalCallback = db.SignalCallback + tx.CallbackCompleted = db.CallbackCompleted } func dbEthTxsToEvmEthTxs(dbEthTxs []DbEthTx) []Tx { @@ -512,8 +520,8 @@ func (o *evmTxStore) InsertTx(etx *Tx) error { if etx.CreatedAt == (time.Time{}) { etx.CreatedAt = time.Now() } - const insertEthTxSQL = `INSERT INTO evm.txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, error, broadcast_at, initial_broadcast_at, created_at, state, meta, subject, pipeline_task_run_id, min_confirmations, evm_chain_id, transmit_checker, idempotency_key) VALUES ( -:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit, :error, :broadcast_at, :initial_broadcast_at, :created_at, :state, :meta, :subject, :pipeline_task_run_id, :min_confirmations, :evm_chain_id, :transmit_checker, :idempotency_key + const insertEthTxSQL = `INSERT INTO evm.txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, error, broadcast_at, initial_broadcast_at, created_at, state, meta, subject, pipeline_task_run_id, min_confirmations, evm_chain_id, transmit_checker, idempotency_key, signal_callback, callback_completed) VALUES ( +:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit, :error, :broadcast_at, :initial_broadcast_at, :created_at, :state, :meta, :subject, :pipeline_task_run_id, :min_confirmations, :evm_chain_id, :transmit_checker, :idempotency_key, :signal_callback, :callback_completed ) RETURNING *` var dbTx DbEthTx dbTx.FromTx(etx) @@ -941,25 +949,40 @@ WHERE evm.tx_attempts.state = 'in_progress' AND evm.txes.from_address = $1 AND e return attempts, pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed") } -func (o *evmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, blockNum int64, chainID *big.Int) (receiptsPlus []ReceiptPlus, err error) { +// Find confirmed txes requiring callback but have not yet been signaled +func (o *evmTxStore) FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID *big.Int) (receiptsPlus []ReceiptPlus, err error) { var rs []dbReceiptPlus var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() err = o.q.SelectContext(ctx, &rs, ` - SELECT pipeline_task_runs.id, evm.receipts.receipt, COALESCE((evm.txes.meta->>'FailOnRevert')::boolean, false) "FailOnRevert" FROM pipeline_task_runs - INNER JOIN pipeline_runs ON pipeline_runs.id = pipeline_task_runs.pipeline_run_id - INNER JOIN evm.txes ON evm.txes.pipeline_task_run_id = pipeline_task_runs.id + SELECT evm.txes.pipeline_task_run_id, evm.receipts.receipt, COALESCE((evm.txes.meta->>'FailOnRevert')::boolean, false) "FailOnRevert" FROM evm.txes INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id INNER JOIN evm.receipts ON evm.tx_attempts.hash = evm.receipts.tx_hash - WHERE pipeline_runs.state = 'suspended' AND evm.receipts.block_number <= ($1 - evm.txes.min_confirmations) AND evm.txes.evm_chain_id = $2 + WHERE evm.txes.pipeline_task_run_id IS NOT NULL AND evm.txes.signal_callback = TRUE AND evm.txes.callback_completed = FALSE + AND evm.receipts.block_number <= ($1 - evm.txes.min_confirmations) AND evm.txes.evm_chain_id = $2 `, blockNum, chainID.String()) - + if err != nil { + return nil, fmt.Errorf("failed to retrieve transactions pending pipeline resume callback: %w", err) + } receiptsPlus = fromDBReceiptsPlus(rs) return } +// Update tx to mark that its callback has been signaled +func (o *evmTxStore) UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunId uuid.UUID, chainId *big.Int) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + _, err := qq.Exec(`UPDATE evm.txes SET callback_completed = TRUE WHERE pipeline_task_run_id = $1 AND evm_chain_id = $2`, pipelineTaskRunId, chainId.String()) + if err != nil { + return fmt.Errorf("failed to mark callback completed for transaction: %w", err) + } + return nil +} + func (o *evmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (nonce evmtypes.Nonce, err error) { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) @@ -1661,12 +1684,12 @@ func (o *evmTxStore) CreateTransaction(ctx context.Context, txRequest TxRequest, } } err = tx.Get(&dbEtx, ` -INSERT INTO evm.txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id, transmit_checker, idempotency_key) +INSERT INTO evm.txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id, transmit_checker, idempotency_key, signal_callback) VALUES ( -$1,$2,$3,$4,$5,'unstarted',NOW(),$6,$7,$8,$9,$10,$11,$12 +$1,$2,$3,$4,$5,'unstarted',NOW(),$6,$7,$8,$9,$10,$11,$12,$13 ) RETURNING "txes".* -`, txRequest.FromAddress, txRequest.ToAddress, txRequest.EncodedPayload, assets.Eth(txRequest.Value), txRequest.FeeLimit, txRequest.Meta, txRequest.Strategy.Subject(), chainID.String(), txRequest.MinConfirmations, txRequest.PipelineTaskRunID, txRequest.Checker, txRequest.IdempotencyKey) +`, txRequest.FromAddress, txRequest.ToAddress, txRequest.EncodedPayload, assets.Eth(txRequest.Value), txRequest.FeeLimit, txRequest.Meta, txRequest.Strategy.Subject(), chainID.String(), txRequest.MinConfirmations, txRequest.PipelineTaskRunID, txRequest.Checker, txRequest.IdempotencyKey, txRequest.SignalCallback) if err != nil { return pkgerrors.Wrap(err, "CreateEthTransaction failed to insert evm tx") } diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index ba02f118cf..f8798f9f83 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -21,6 +21,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -617,7 +618,7 @@ func TestORM_GetInProgressTxAttempts(t *testing.T) { assert.Equal(t, etx.TxAttempts[0].ID, attempts[0].ID) } -func TestORM_FindReceiptsPendingConfirmation(t *testing.T) { +func TestORM_FindTxesPendingCallback(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) @@ -645,21 +646,50 @@ func TestORM_FindReceiptsPendingConfirmation(t *testing.T) { minConfirmations := int64(2) - run := cltest.MustInsertPipelineRun(t, db) - tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) - pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run.ID) - - etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 1, fromAddress) + // Suspended run waiting for callback + run1 := cltest.MustInsertPipelineRun(t, db) + tr1 := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run1.ID) + pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run1.ID) + etx1 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 1, fromAddress) pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) - attempt := etx.TxAttempts[0] - cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt.Hash) - - pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) - - receiptsPlus, err := txStore.FindReceiptsPendingConfirmation(testutils.Context(t), head.Number, ethClient.ConfiguredChainID()) + attempt1 := etx1.TxAttempts[0] + cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt1.Hash) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr1.ID, minConfirmations, etx1.ID) + + // Callback to pipeline service completed. Should be ignored + run2 := cltest.MustInsertPipelineRunWithStatus(t, db, 0, pipeline.RunStatusCompleted) + tr2 := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run2.ID) + etx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 4, 1, fromAddress) + pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": false}'`) + attempt2 := etx2.TxAttempts[0] + cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt2.Hash) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE, callback_completed = TRUE WHERE id = $3`, &tr2.ID, minConfirmations, etx2.ID) + + // Suspended run younger than minConfirmations. Should be ignored + run3 := cltest.MustInsertPipelineRun(t, db) + tr3 := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run3.ID) + pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run3.ID) + etx3 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 5, 1, fromAddress) + pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": false}'`) + attempt3 := etx3.TxAttempts[0] + cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, attempt3.Hash) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr3.ID, minConfirmations, etx3.ID) + + // Tx not marked for callback. Should be ignore + etx4 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 6, 1, fromAddress) + attempt4 := etx4.TxAttempts[0] + cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, attempt4.Hash) + pgtest.MustExec(t, db, `UPDATE evm.txes SET min_confirmations = $1 WHERE id = $2`, minConfirmations, etx4.ID) + + // Unconfirmed Tx without receipts. Should be ignored + etx5 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 7, 1, fromAddress) + pgtest.MustExec(t, db, `UPDATE evm.txes SET min_confirmations = $1 WHERE id = $2`, minConfirmations, etx5.ID) + + // Search evm.txes table for tx requiring callback + receiptsPlus, err := txStore.FindTxesPendingCallback(testutils.Context(t), head.Number, ethClient.ConfiguredChainID()) require.NoError(t, err) assert.Len(t, receiptsPlus, 1) - assert.Equal(t, tr.ID, receiptsPlus[0].ID) + assert.Equal(t, tr1.ID, receiptsPlus[0].ID) } func Test_FindTxWithIdempotencyKey(t *testing.T) { @@ -1569,6 +1599,35 @@ func TestORM_CreateTransaction(t *testing.T) { assert.Equal(t, tx1.GetID(), tx2.GetID()) }) + + t.Run("sets signal callback flag", func(t *testing.T) { + subject := uuid.New() + strategy := newMockTxStrategy(t) + strategy.On("Subject").Return(uuid.NullUUID{UUID: subject, Valid: true}) + strategy.On("PruneQueue", mock.Anything, mock.AnythingOfType("*txmgr.evmTxStore")).Return(int64(0), nil) + etx, err := txStore.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ + FromAddress: fromAddress, + ToAddress: toAddress, + EncodedPayload: payload, + FeeLimit: gasLimit, + Meta: nil, + Strategy: strategy, + SignalCallback: true, + }, ethClient.ConfiguredChainID()) + assert.NoError(t, err) + + assert.Greater(t, etx.ID, int64(0)) + assert.Equal(t, fromAddress, etx.FromAddress) + assert.Equal(t, true, etx.SignalCallback) + + cltest.AssertCount(t, db, "evm.txes", 3) + + var dbEthTx txmgr.DbEthTx + require.NoError(t, db.Get(&dbEthTx, `SELECT * FROM evm.txes ORDER BY id DESC LIMIT 1`)) + + assert.Equal(t, fromAddress, dbEthTx.FromAddress) + assert.Equal(t, true, dbEthTx.SignalCallback) + }) } func TestORM_PruneUnstartedTxQueue(t *testing.T) { diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 4632a8ae34..f491bda40b 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -183,32 +183,6 @@ func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Contex return r0 } -// FindReceiptsPendingConfirmation provides a mock function with given fields: ctx, blockNum, chainID -func (_m *EvmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, blockNum int64, chainID *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error) { - ret := _m.Called(ctx, blockNum, chainID) - - var r0 []types.ReceiptPlus[*evmtypes.Receipt] - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error)); ok { - return rf(ctx, blockNum, chainID) - } - if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) []types.ReceiptPlus[*evmtypes.Receipt]); ok { - r0 = rf(ctx, blockNum, chainID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.ReceiptPlus[*evmtypes.Receipt]) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int64, *big.Int) error); ok { - r1 = rf(ctx, blockNum, chainID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // FindTransactionsConfirmedInBlockRange provides a mock function with given fields: ctx, highBlockNumber, lowBlockNumber, chainID func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) @@ -493,6 +467,32 @@ func (_m *EvmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaFiel return r0, r1 } +// FindTxesPendingCallback provides a mock function with given fields: ctx, blockNum, chainID +func (_m *EvmTxStore) FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error) { + ret := _m.Called(ctx, blockNum, chainID) + + var r0 []types.ReceiptPlus[*evmtypes.Receipt] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error)); ok { + return rf(ctx, blockNum, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) []types.ReceiptPlus[*evmtypes.Receipt]); ok { + r0 = rf(ctx, blockNum, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.ReceiptPlus[*evmtypes.Receipt]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, *big.Int) error); ok { + r1 = rf(ctx, blockNum, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, ids, states, chainID) @@ -1018,6 +1018,20 @@ func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, return r0 } +// UpdateTxCallbackCompleted provides a mock function with given fields: ctx, pipelineTaskRunRid, chainId +func (_m *EvmTxStore) UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId *big.Int) error { + ret := _m.Called(ctx, pipelineTaskRunRid, chainId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *big.Int) error); ok { + r0 = rf(ctx, pipelineTaskRunRid, chainId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // UpdateTxFatalError provides a mock function with given fields: ctx, etx func (_m *EvmTxStore) UpdateTxFatalError(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx) diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index d60050700f..056a7deab2 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -306,13 +306,13 @@ func (o *orm) UpdateTaskRunResult(taskID uuid.UUID, result Result) (run Run, sta WHERE pipeline_task_runs.id = $1 AND pipeline_runs.state in ('running', 'suspended') FOR UPDATE` if err = tx.Get(&run, sql, taskID); err != nil { - return err + return fmt.Errorf("failed to find pipeline run for ID %s: %w", taskID.String(), err) } // Update the task with result sql = `UPDATE pipeline_task_runs SET output = $2, error = $3, finished_at = $4 WHERE id = $1` if _, err = tx.Exec(sql, taskID, result.OutputDB(), result.ErrorDB(), time.Now()); err != nil { - return errors.Wrap(err, "UpdateTaskRunResult") + return fmt.Errorf("failed to update pipeline task run: %w", err) } if run.State == RunStatusSuspended { @@ -321,7 +321,7 @@ func (o *orm) UpdateTaskRunResult(taskID uuid.UUID, result Result) (run Run, sta sql = `UPDATE pipeline_runs SET state = $2 WHERE id = $1` if _, err = tx.Exec(sql, run.ID, run.State); err != nil { - return errors.Wrap(err, "UpdateTaskRunResult") + return fmt.Errorf("failed to update pipeline run state: %w", err) } } diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 3dbe94747e..d33913b475 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -609,7 +609,7 @@ func (r *runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) error Error: err, }) if err != nil { - return err + return fmt.Errorf("failed to update task run result: %w", err) } // TODO: Should probably replace this with a listener to update events diff --git a/core/services/pipeline/task.eth_tx.go b/core/services/pipeline/task.eth_tx.go index 57f1c0a7ed..384c86446e 100644 --- a/core/services/pipeline/task.eth_tx.go +++ b/core/services/pipeline/task.eth_tx.go @@ -155,6 +155,7 @@ func (t *ETHTxTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inpu ForwarderAddress: forwarderAddress, Strategy: strategy, Checker: transmitChecker, + SignalCallback: true, } if minOutgoingConfirmations > 0 { diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index e5f50bc29e..a0ff54d444 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -95,6 +95,7 @@ func TestETHTxTask(t *testing.T) { CheckerType: txmgr.TransmitCheckerTypeVRFV2, VRFCoordinatorAddress: &addr, }, + SignalCallback: true, }).Return(txmgr.Tx{}, nil) }, nil, nil, "", pipeline.RunInfo{}, @@ -138,6 +139,7 @@ func TestETHTxTask(t *testing.T) { FeeLimit: gasLimit, Meta: txMeta, Strategy: txmgrcommon.NewSendEveryStrategy(), + SignalCallback: true, }).Return(txmgr.Tx{}, nil) }, nil, nil, "", pipeline.RunInfo{}, @@ -215,6 +217,7 @@ func TestETHTxTask(t *testing.T) { FeeLimit: gasLimit, Meta: txMeta, Strategy: txmgrcommon.NewSendEveryStrategy(), + SignalCallback: true, }).Return(txmgr.Tx{}, nil) }, nil, nil, "", pipeline.RunInfo{}, @@ -260,6 +263,7 @@ func TestETHTxTask(t *testing.T) { FeeLimit: gasLimit, Meta: txMeta, Strategy: txmgrcommon.NewSendEveryStrategy(), + SignalCallback: true, }).Return(txmgr.Tx{}, nil) }, nil, nil, "", pipeline.RunInfo{}, @@ -290,6 +294,7 @@ func TestETHTxTask(t *testing.T) { FeeLimit: gasLimit, Meta: txMeta, Strategy: txmgrcommon.NewSendEveryStrategy(), + SignalCallback: true, }).Return(txmgr.Tx{}, nil) }, nil, nil, "", pipeline.RunInfo{}, @@ -324,6 +329,7 @@ func TestETHTxTask(t *testing.T) { FeeLimit: drJobTypeGasLimit, Meta: txMeta, Strategy: txmgrcommon.NewSendEveryStrategy(), + SignalCallback: true, }).Return(txmgr.Tx{}, nil) }, nil, nil, "", pipeline.RunInfo{}, @@ -358,6 +364,7 @@ func TestETHTxTask(t *testing.T) { FeeLimit: specGasLimit, Meta: txMeta, Strategy: txmgrcommon.NewSendEveryStrategy(), + SignalCallback: true, }).Return(txmgr.Tx{}, nil) }, nil, nil, "", pipeline.RunInfo{}, @@ -423,6 +430,7 @@ func TestETHTxTask(t *testing.T) { FeeLimit: gasLimit, Meta: txMeta, Strategy: txmgrcommon.NewSendEveryStrategy(), + SignalCallback: true, }).Return(txmgr.Tx{}, errors.New("uh oh")) }, nil, pipeline.ErrTaskRunFailed, "while creating transaction", pipeline.RunInfo{IsRetryable: true}, diff --git a/core/store/migrate/migrations/0209_add_resume_pipeline_task_flags_to_evm_txes.sql b/core/store/migrate/migrations/0209_add_resume_pipeline_task_flags_to_evm_txes.sql new file mode 100644 index 0000000000..dbe7e91b9f --- /dev/null +++ b/core/store/migrate/migrations/0209_add_resume_pipeline_task_flags_to_evm_txes.sql @@ -0,0 +1,15 @@ +-- +goose Up +ALTER TABLE evm.txes ADD COLUMN "signal_callback" BOOL DEFAULT FALSE; +ALTER TABLE evm.txes ADD COLUMN "callback_completed" BOOL DEFAULT FALSE; + +UPDATE evm.txes +SET signal_callback = TRUE AND callback_completed = FALSE +WHERE evm.txes.pipeline_task_run_id IN ( + SELECT pipeline_task_runs.id FROM pipeline_task_runs + INNER JOIN pipeline_runs ON pipeline_runs.id = pipeline_task_runs.pipeline_run_id + WHERE pipeline_runs.state = 'suspended' +); + +-- +goose Down +ALTER TABLE evm.txes DROP COLUMN "signal_callback"; +ALTER TABLE evm.txes DROP COLUMN "callback_completed"; From 6fb7fae8511edb4b9c7ef3fbc3373f7de5dd90a0 Mon Sep 17 00:00:00 2001 From: Patrick Date: Tue, 14 Nov 2023 05:57:27 -0500 Subject: [PATCH 141/327] feature/tracing-data: Trace data as artifact in CI (#11113) * WIP: generate traces as artifact * Splitting otel collector into dev and ci environments * feature/tracing-data: minor cleanup --- .github/tracing/README.md | 43 ++++++++- .../tracing/local-smoke-docker-compose.yaml | 4 +- .github/tracing/otel-collector-ci.yaml | 22 +++++ ...collector.yaml => otel-collector-dev.yaml} | 5 + .github/tracing/replay.sh | 6 ++ .github/workflows/integration-tests.yml | 92 +++++++------------ 6 files changed, 111 insertions(+), 61 deletions(-) create mode 100644 .github/tracing/otel-collector-ci.yaml rename .github/tracing/{otel-collector.yaml => otel-collector-dev.yaml} (67%) create mode 100644 .github/tracing/replay.sh diff --git a/.github/tracing/README.md b/.github/tracing/README.md index 6988383ca7..eb75738429 100644 --- a/.github/tracing/README.md +++ b/.github/tracing/README.md @@ -1,5 +1,44 @@ # Distributed Tracing -These config files are for an OTEL collector, grafana Tempo, and a grafana UI instance to run as containers on the same network. +As part of the LOOP plugin effort, we've added distributed tracing to the core node. This is helpful for initial development and maintenance of LOOPs, but will also empower product teams building on top of core. + +## Dev environment + +One way to generate traces locally today is with the OCR2 basic smoke test. + +1. navigate to `.github/tracing/` and then run `docker compose --file local-smoke-docker-compose.yaml up` +2. setup a local docker registry at `127.0.0.1:5000` (https://www.docker.com/blog/how-to-use-your-own-registry-2/) +3. run `make build_push_plugin_docker_image` in `chainlink/integration-tests/Makefile` +4. run `SELECTED_NETWORKS=SIMULATED CHAINLINK_IMAGE="127.0.0.1:5000/chainlink" CHAINLINK_VERSION="develop" go test -run TestOCRv2Basic ./smoke/ocr2_test.go` +5. navigate to `localhost:3000/explore` in a web browser to query for traces + +Core and the median plugins are instrumented with open telemetry traces, which are sent to the OTEL collector and forwarded to the Tempo backend. The grafana UI can then read the trace data from the Tempo backend. + + -A localhost client can send gRPC calls to the server. The gRPC server is instrumented with open telemetry traces, which are sent to the OTEL collector and forwarded to the Tempo backend. The grafana UI can then read the trace data from the Tempo backend. \ No newline at end of file +## CI environment + +Another way to generate traces is by enabling traces for PRs. This will instrument traces for `TestOCRv2Basic` in the CI run. + +1. Cut a PR in the core repo +2. Add the `enable tracing` label to the PR +3. Navigate to `Integration Tests / ETH Smoke Tests ocr2-plugins (pull_request)` details +4. Navigate to the summary of the integration tests +5. After the test completes, the generated trace data will be saved as an artifact, currently called `trace-data` +6. Download the artifact to this directory (`chainlink/.github/tracing`) +7. `docker compose --file local-smoke-docker-compose.yaml up` +8. Run `sh replay.sh` to replay those traces to the otel-collector container that was spun up in the last step. +9. navigate to `localhost:3000/explore` in a web browser to query for traces + +The artifact is not json encoded - each individual line is a well formed and complete json object. + +## Configuration +This folder contains the following config files: +* otel-collector-ci.yaml +* otel-collector-dev.yaml +* tempo.yaml +* grafana-datasources.yaml + +These config files are for an OTEL collector, grafana Tempo, and a grafana UI instance to run as containers on the same network. +`otel-collector-dev.yaml` is the configuration for dev (i.e. your local machine) environments, and forwards traces from the otel collector to the grafana tempo instance on the same network. +`otel-collector-ci.yaml` is the configuration for the CI runs, and exports the trace data to the artifact from the github run. \ No newline at end of file diff --git a/.github/tracing/local-smoke-docker-compose.yaml b/.github/tracing/local-smoke-docker-compose.yaml index e0e60a675e..744ba88ef6 100644 --- a/.github/tracing/local-smoke-docker-compose.yaml +++ b/.github/tracing/local-smoke-docker-compose.yaml @@ -6,9 +6,11 @@ services: image: otel/opentelemetry-collector:0.61.0 command: [ "--config=/etc/otel-collector.yaml" ] volumes: - - ./otel-collector.yaml:/etc/otel-collector.yaml + - ./otel-collector-dev.yaml:/etc/otel-collector.yaml + - ../../integration-tests/smoke/traces/trace-data.json:/etc/trace-data.json # local trace data stored consistent with smoke/logs ports: - "4317:4317" # otlp grpc + - "3100:3100" depends_on: - tempo networks: diff --git a/.github/tracing/otel-collector-ci.yaml b/.github/tracing/otel-collector-ci.yaml new file mode 100644 index 0000000000..0bf123d29b --- /dev/null +++ b/.github/tracing/otel-collector-ci.yaml @@ -0,0 +1,22 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: "0.0.0.0:4317" + http: + endpoint: "0.0.0.0:3100" +exporters: + file: + path: /tracing/trace-data.json + otlp: + endpoint: tempo:4317 + tls: + insecure: true +service: + telemetry: + logs: + level: "debug" # Set log level to debug + pipelines: + traces: + receivers: [otlp] + exporters: [file,otlp] \ No newline at end of file diff --git a/.github/tracing/otel-collector.yaml b/.github/tracing/otel-collector-dev.yaml similarity index 67% rename from .github/tracing/otel-collector.yaml rename to .github/tracing/otel-collector-dev.yaml index fb8721cba2..dd059127b8 100644 --- a/.github/tracing/otel-collector.yaml +++ b/.github/tracing/otel-collector-dev.yaml @@ -3,12 +3,17 @@ receivers: protocols: grpc: endpoint: "0.0.0.0:4317" + http: + endpoint: "0.0.0.0:3100" exporters: otlp: endpoint: tempo:4317 tls: insecure: true service: + telemetry: + logs: + level: "debug" # Set log level to debug pipelines: traces: receivers: [otlp] diff --git a/.github/tracing/replay.sh b/.github/tracing/replay.sh new file mode 100644 index 0000000000..b2e564567c --- /dev/null +++ b/.github/tracing/replay.sh @@ -0,0 +1,6 @@ +# Read JSON file and loop through each trace +while IFS= read -r trace; do + curl -X POST http://localhost:3100/v1/traces \ + -H "Content-Type: application/json" \ + -d "$trace" +done < "trace-data" diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 9294dceae6..17f571fd63 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -368,67 +368,33 @@ jobs: # Create network docker network create --driver bridge tracing - # Start Grafana - cd ./.github/tracing - docker run -d --network=tracing --name=grafana -p 3000:3000 -v $PWD/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml -e GF_AUTH_ANONYMOUS_ENABLED=true -e GF_AUTH_ANONYMOUS_ORG_ROLE=Admin -e GF_AUTH_DISABLE_LOGIN_FORM=true -e GF_FEATURE_TOGGLES_ENABLE=traceqlEditor grafana/grafana:9.4.3 + # Make trace directory + cd integration-tests/smoke/ + mkdir ./traces + chmod -R 777 ./traces - # Start Tempo - docker run -d --network=tracing --name=tempo -v ./tempo.yaml:/etc/tempo.yaml -v $PWD/tempo-data:/tmp/tempo grafana/tempo:latest -config.file=/etc/tempo.yaml + # Switch directory + cd ../../.github/tracing - # Start OpenTelemetry Collector - docker run -d --network=tracing --name=otel-collector -v $PWD/otel-collector.yaml:/etc/otel-collector.yaml -p 4317:4317 otel/opentelemetry-collector:0.61.0 --config=/etc/otel-collector.yaml - - - name: Generate port - id: generate-port - if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' - env: - GITHUB_PR_NUMBER: ${{ github.event.number }} - run: | - PORT_BASE=3001 - MAX_PORT=8000 + # Create a Docker volume for traces + # docker volume create otel-traces - # Use PR number as offset. Given GitHub PRs are incremental, this guarantees uniqueness for at least 5000 PRs. - OFFSET=$GITHUB_PR_NUMBER - echo "PR Number: $OFFSET" - - # Ensure that we don't exceed the max port - if (( OFFSET > (MAX_PORT - PORT_BASE) )); then - OFFSET=$((OFFSET % (MAX_PORT - PORT_BASE))) - fi - - # Map the offset to the port range - REMOTE_PORT=$((PORT_BASE + OFFSET)) - echo "REMOTE_PORT=$REMOTE_PORT" >> $GITHUB_OUTPUT - - name: Reverse SSH Tunneling - if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' - env: - TRACING_SSH_KEY: ${{ secrets.TRACING_SSH_KEY }} - TRACING_SSH_SERVER: ${{ secrets.TRACING_SSH_SERVER }} - REMOTE_PORT: ${{ steps.generate-port.outputs.REMOTE_PORT }} - run: | - eval $(ssh-agent) - echo "test" - echo "$TRACING_SSH_KEY" | wc -c - echo "$TRACING_SSH_KEY" | tr -d '\r' | wc -c - echo "$TRACING_SSH_KEY" | tr -d '\r' | base64 --decode | ssh-add - - # f: background process - # N: do not execute a remote command - # R: remote port forwarding - ssh -o StrictHostKeyChecking=no -f -N -R $REMOTE_PORT:127.0.0.1:3000 user-gha@$TRACING_SSH_SERVER - echo "To view Grafana locally:" - echo "ssh -N -L 8000:localhost:$REMOTE_PORT user-gha@$TRACING_SSH_SERVER" - echo "Then visit http://localhost:8000 in a browser." - echo "If you are unable to connect, check with the security team that you have access to the tracing server." - - name: Show Grafana Logs - if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + # Start OpenTelemetry Collector + # Note the user must be set to the same user as the runner for the trace data to be accessible + docker run -d --network=tracing --name=otel-collector \ + -v $PWD/otel-collector-ci.yaml:/etc/otel-collector.yaml \ + -v $PWD/../../integration-tests/smoke/traces:/tracing \ + --user "$(id -u):$(id -g)" \ + -p 4317:4317 otel/opentelemetry-collector:0.88.0 --config=/etc/otel-collector.yaml + - name: Locate Docker Volume + id: locate-volume + if: false run: | - docker logs grafana - docker logs tempo - docker logs otel-collector - - name: Set sleep time to use in future steps + echo "VOLUME_PATH=$(docker volume inspect --format '{{ .Mountpoint }}' otel-traces)" >> $GITHUB_OUTPUT + - name: Show Otel-Collector Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - echo "SLEEP_TIME=2400" >> "$GITHUB_ENV" + docker logs otel-collector ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' @@ -465,6 +431,10 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Show Otel-Collector Logs + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + run: | + docker logs otel-collector - name: Collect Metrics if: always() id: collect-gha-metrics @@ -475,11 +445,17 @@ jobs: this-job-name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - - name: Keep action running to view traces + - name: Permissions on traces if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - echo "Sleeping for $SLEEP_TIME seconds..." - sleep $SLEEP_TIME + ls -l ./integration-tests/smoke/traces + - name: Upload Trace Data + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + uses: actions/upload-artifact@v3 + with: + name: trace-data + path: ./integration-tests/smoke/traces/trace-data.json + ### Used to check the required checks box when the matrix completes eth-smoke-tests: From ac94719b7d4f7a73ad132db4910d515bb6a633e2 Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:19:29 +0100 Subject: [PATCH 142/327] Use resty as http response in E2E tests and fix if testing.T context is nil (#11271) * Use resty as http response * Fix for nil testing.T context --- integration-tests/client/chainlink.go | 31 ++++++++++++++++++++++----- integration-tests/utils/common.go | 4 ++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 3638fa11c7..ef7bd06142 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -117,11 +117,11 @@ func (c *ChainlinkClient) MustCreateJob(spec JobSpec) (*Job, error) { if err != nil { return nil, err } - return job, VerifyStatusCode(resp.StatusCode, http.StatusOK) + return job, VerifyStatusCode(resp.RawResponse.StatusCode, http.StatusOK) } // CreateJob creates a Chainlink job based on the provided spec struct -func (c *ChainlinkClient) CreateJob(spec JobSpec) (*Job, *http.Response, error) { +func (c *ChainlinkClient) CreateJob(spec JobSpec) (*Job, *resty.Response, error) { job := &Job{} specString, err := spec.String() if err != nil { @@ -138,7 +138,7 @@ func (c *ChainlinkClient) CreateJob(spec JobSpec) (*Job, *http.Response, error) if err != nil { return nil, nil, err } - return job, resp.RawResponse, err + return job, resp, err } // ReadJobs reads all jobs from the Chainlink node @@ -881,8 +881,16 @@ func (c *ChainlinkClient) CreateCSAKey() (*CSAKey, *http.Response, error) { return csaKey, resp.RawResponse, err } +func (c *ChainlinkClient) MustReadCSAKeys() (*CSAKeys, *resty.Response, error) { + csaKeys, res, err := c.ReadCSAKeys() + if err != nil { + return nil, res, err + } + return csaKeys, res, VerifyStatusCodeWithResponse(res, http.StatusOK) +} + // ReadCSAKeys reads CSA keys from the Chainlink node -func (c *ChainlinkClient) ReadCSAKeys() (*CSAKeys, *http.Response, error) { +func (c *ChainlinkClient) ReadCSAKeys() (*CSAKeys, *resty.Response, error) { csaKeys := &CSAKeys{} c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading CSA Keys") resp, err := c.APIClient.R(). @@ -894,7 +902,7 @@ func (c *ChainlinkClient) ReadCSAKeys() (*CSAKeys, *http.Response, error) { if err != nil { return nil, nil, err } - return csaKeys, resp.RawResponse, err + return csaKeys, resp, err } // CreateEI creates an EI on the Chainlink node based on the provided attributes and returns the respective secrets @@ -1105,6 +1113,19 @@ func VerifyStatusCode(actStatusCd, expStatusCd int) error { return nil } +func VerifyStatusCodeWithResponse(res *resty.Response, expStatusCd int) error { + actStatusCd := res.RawResponse.StatusCode + if actStatusCd != expStatusCd { + return fmt.Errorf( + "unexpected response code, got %d, expected %d, response: %s", + actStatusCd, + expStatusCd, + res.Body(), + ) + } + return nil +} + func CreateNodeKeysBundle(nodes []*ChainlinkClient, chainName string, chainId string) ([]NodeKeysBundle, []*CLNodesWithKeys, error) { nkb := make([]NodeKeysBundle, 0) var clNodes []*CLNodesWithKeys diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go index 5ef3209c92..f13c71cfd9 100644 --- a/integration-tests/utils/common.go +++ b/integration-tests/utils/common.go @@ -42,6 +42,10 @@ func TestContext(tb testing.TB) context.Context { var cancel func() switch t := tb.(type) { case *testing.T: + // Return background context if testing.T not set + if t == nil { + return ctx + } if d, ok := t.Deadline(); ok { ctx, cancel = context.WithDeadline(ctx, d) } From b7f042ceafe543937310fa1e47f2909a86dcf797 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 14 Nov 2023 06:47:24 -0600 Subject: [PATCH 143/327] core/services/pg: simplify TxOptions (#11276) --- core/services/pg/transaction.go | 38 ++++----------------------------- core/services/pg/utils.go | 6 ------ 2 files changed, 4 insertions(+), 40 deletions(-) diff --git a/core/services/pg/transaction.go b/core/services/pg/transaction.go index d237c20d4c..92d72b3d81 100644 --- a/core/services/pg/transaction.go +++ b/core/services/pg/transaction.go @@ -7,20 +7,16 @@ import ( "time" "github.com/getsentry/sentry-go" + "github.com/jmoiron/sqlx" "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - corelogger "github.com/smartcontractkit/chainlink/v2/core/logger" ) type TxOptions struct { sql.TxOptions - LockTimeout time.Duration - IdleInTxSessionTimeout time.Duration } // NOTE: In an ideal world the timeouts below would be set to something sane in @@ -39,27 +35,14 @@ func OptReadOnlyTx() TxOptions { return TxOptions{TxOptions: sql.TxOptions{ReadOnly: true}} } -func applyDefaults(optss []TxOptions) (lockTimeout, idleInTxSessionTimeout time.Duration, txOpts sql.TxOptions) { - lockTimeout = defaultLockTimeout - idleInTxSessionTimeout = defaultIdleInTxSessionTimeout - txIsolation := DefaultIsolation +func applyDefaults(optss []TxOptions) (txOpts sql.TxOptions) { readOnly := false if len(optss) > 0 { opts := optss[0] - if opts.LockTimeout != 0 { - lockTimeout = opts.LockTimeout - } - if opts.IdleInTxSessionTimeout != 0 { - idleInTxSessionTimeout = opts.IdleInTxSessionTimeout - } - if opts.Isolation != 0 { - txIsolation = opts.Isolation - } readOnly = opts.ReadOnly } txOpts = sql.TxOptions{ - Isolation: txIsolation, - ReadOnly: readOnly, + ReadOnly: readOnly, } return } @@ -86,7 +69,7 @@ type TxBeginner interface { } func sqlxTransactionQ(ctx context.Context, db TxBeginner, lggr logger.Logger, fn func(q Queryer) error, optss ...TxOptions) (err error) { - lockTimeout, idleInTxSessionTimeout, txOpts := applyDefaults(optss) + txOpts := applyDefaults(optss) var tx *sqlx.Tx tx, err = db.BeginTxx(ctx, &txOpts) @@ -126,19 +109,6 @@ func sqlxTransactionQ(ctx context.Context, db TxBeginner, lggr logger.Logger, fn } }() - if lockTimeout != defaultLockTimeout { - _, err = tx.Exec(fmt.Sprintf(`SET LOCAL lock_timeout = %d`, lockTimeout.Milliseconds())) - if err != nil { - return errors.Wrap(err, "error setting transaction local lock_timeout") - } - } - if idleInTxSessionTimeout != defaultIdleInTxSessionTimeout { - _, err = tx.Exec(fmt.Sprintf(`SET LOCAL idle_in_transaction_session_timeout = %d`, idleInTxSessionTimeout.Milliseconds())) - if err != nil { - return errors.Wrap(err, "error setting transaction local idle_in_transaction_session_timeout") - } - } - err = fn(tx) return diff --git a/core/services/pg/utils.go b/core/services/pg/utils.go index 5be2a4915b..eb53c26129 100644 --- a/core/services/pg/utils.go +++ b/core/services/pg/utils.go @@ -12,12 +12,6 @@ const ( DefaultQueryTimeout = 10 * time.Second // longQueryTimeout is a bigger upper bound for how long a SQL query should take longQueryTimeout = 1 * time.Minute - // defaultLockTimeout controls the max time we will wait for any kind of database lock. - // It's good to set this to _something_ because waiting for locks forever is really bad. - defaultLockTimeout = 15 * time.Second - // defaultIdleInTxSessionTimeout controls the max time we leave a transaction open and idle. - // It's good to set this to _something_ because leaving transactions open forever is really bad. - defaultIdleInTxSessionTimeout = 1 * time.Hour ) var _ driver.Valuer = Limit(-1) From b36d9ebe3f2e35ccbe26f7c83774e589b369d7fc Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:02:42 +0100 Subject: [PATCH 144/327] Add ReadBridges() to E2E tests core client (#11282) --- integration-tests/client/chainlink.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index ef7bd06142..7d5825c261 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -302,6 +302,19 @@ func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, return &bt, resp.RawResponse, err } +// ReadBridges reads bridges from the Chainlink node +func (c *ChainlinkClient) ReadBridges() (*ResponseSlice, *resty.Response, error) { + result := &ResponseSlice{} + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Getting all bridges") + resp, err := c.APIClient.R(). + SetResult(&result). + Get("/v2/bridge_types") + if err != nil { + return nil, nil, err + } + return result, resp, err +} + // DeleteBridge deletes a bridge on the Chainlink node based on the provided name func (c *ChainlinkClient) DeleteBridge(name string) (*http.Response, error) { c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting Bridge") From 7be17c91539f2db930ed339117b589d4f7d500eb Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 14 Nov 2023 07:30:49 -0600 Subject: [PATCH 145/327] core/utils: remove unused LazyLoad (#11277) --- core/utils/lazy.go | 36 --------------------- core/utils/lazy_test.go | 71 ----------------------------------------- 2 files changed, 107 deletions(-) delete mode 100644 core/utils/lazy.go delete mode 100644 core/utils/lazy_test.go diff --git a/core/utils/lazy.go b/core/utils/lazy.go deleted file mode 100644 index 43e8480815..0000000000 --- a/core/utils/lazy.go +++ /dev/null @@ -1,36 +0,0 @@ -package utils - -import ( - "sync" -) - -type LazyLoad[T any] struct { - f func() (T, error) - state T - ok bool - lock sync.Mutex -} - -func NewLazyLoad[T any](f func() (T, error)) *LazyLoad[T] { - return &LazyLoad[T]{ - f: f, - } -} - -func (l *LazyLoad[T]) Get() (out T, err error) { - l.lock.Lock() - defer l.lock.Unlock() - - if l.ok { - return l.state, nil - } - l.state, err = l.f() - l.ok = err == nil - return l.state, err -} - -func (l *LazyLoad[T]) Reset() { - l.lock.Lock() - defer l.lock.Unlock() - l.ok = false -} diff --git a/core/utils/lazy_test.go b/core/utils/lazy_test.go deleted file mode 100644 index 88d02eea7f..0000000000 --- a/core/utils/lazy_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package utils - -import ( - "sync" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLazyLoad(t *testing.T) { - var clientwg sync.WaitGroup - - tc := func() (int, error) { - clientwg.Done() - return 10, nil - } - - // Get should only request a client once, use cached afterward - t.Run("get", func(t *testing.T) { - clientwg.Add(1) // expect one call to get client - c := NewLazyLoad(tc) - rw, err := c.Get() - assert.NoError(t, err) - assert.NotNil(t, rw) - assert.NotNil(t, c.state) - - // used cached client - rw, err = c.Get() - assert.NoError(t, err) - assert.NotNil(t, rw) - clientwg.Wait() - }) - - // Clear removes the cached client, should refetch - t.Run("clear", func(t *testing.T) { - clientwg.Add(2) // expect two calls to get client - - c := NewLazyLoad(tc) - rw, err := c.Get() - assert.NotNil(t, rw) - assert.NoError(t, err) - - c.Reset() - - rw, err = c.Get() - assert.NotNil(t, rw) - assert.NoError(t, err) - clientwg.Wait() - }) - - // Race checks a race condition of Getting and Clearing a new client - t.Run("race", func(t *testing.T) { - clientwg.Add(1) // expect one call to get client - - c := NewLazyLoad(tc) - var wg sync.WaitGroup - wg.Add(2) - go func() { - rw, err := c.Get() - assert.NoError(t, err) - assert.NotNil(t, rw) - wg.Done() - }() - go func() { - c.Reset() - wg.Done() - }() - wg.Wait() - clientwg.Wait() - }) -} From 9471f2eb833225310e90da93148e89650f15edfd Mon Sep 17 00:00:00 2001 From: ferglor <19188060+ferglor@users.noreply.github.com> Date: Tue, 14 Nov 2023 15:12:12 +0000 Subject: [PATCH 146/327] Attempt to fix streams lookup race condition (#11284) --- .../ocr2/plugins/ocr2keeper/evm21/streams_lookup.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go index fb2821a74b..af7ff42b93 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go @@ -151,11 +151,13 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep var wg sync.WaitGroup for i, lookup := range lookups { - i := i wg.Add(1) - r.threadCtrl.Go(func(ctx context.Context) { - r.doLookup(ctx, &wg, lookup, i, checkResults, lggr) - }) + func(i int, lookup *StreamsLookup) { + r.threadCtrl.Go(func(ctx context.Context) { + r.doLookup(ctx, &wg, lookup, i, checkResults, lggr) + }) + }(i, lookup) + } wg.Wait() From 039ffa93794203bd0b0f8f43278fb49f53aa597e Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Tue, 14 Nov 2023 11:56:17 -0500 Subject: [PATCH 147/327] [Functions] Use @eth-optimism/contracts-bedrock GasPriceOracle (#11275) * (chore): Add @eth-optimism/contracts-bedrock v0.16.2 to vendor * Use GasPriceOracle in Functions ChainSpecificUtil --- .../dev/v1_X/libraries/ChainSpecificUtil.sol | 8 +- .../v0.16.2/src/L2/GasPriceOracle.sol | 99 +++++++++++++++++++ .../v0.16.2/src/L2/L1Block.sol | 76 ++++++++++++++ .../v0.16.2/src/libraries/Predeploys.sol | 77 +++++++++++++++ .../v0.16.2/src/universal/ISemver.sol | 13 +++ 5 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/GasPriceOracle.sol create mode 100644 contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/L1Block.sol create mode 100644 contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/libraries/Predeploys.sol create mode 100644 contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/universal/ISemver.sol diff --git a/contracts/src/v0.8/functions/dev/v1_X/libraries/ChainSpecificUtil.sol b/contracts/src/v0.8/functions/dev/v1_X/libraries/ChainSpecificUtil.sol index d6569a256b..574d1bf164 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/libraries/ChainSpecificUtil.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/libraries/ChainSpecificUtil.sol @@ -2,7 +2,7 @@ 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"; +import {GasPriceOracle} from "../../../../vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/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. @@ -24,10 +24,10 @@ library ChainSpecificUtil { /// @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 OVM_GASPRICEORACLE_ADDR is the address of the 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); + GasPriceOracle private constant OVM_GASPRICEORACLE = GasPriceOracle(OVM_GASPRICEORACLE_ADDR); uint256 private constant OP_MAINNET_CHAIN_ID = 10; uint256 private constant OP_GOERLI_CHAIN_ID = 420; @@ -44,7 +44,7 @@ library ChainSpecificUtil { /// @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 On Optimism, the provided calldata is passed to the 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; diff --git a/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/GasPriceOracle.sol b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/GasPriceOracle.sol new file mode 100644 index 0000000000..aebc1f747a --- /dev/null +++ b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/GasPriceOracle.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import { ISemver } from "../universal/ISemver.sol"; +import { Predeploys } from "../libraries/Predeploys.sol"; +import { L1Block } from "./L1Block.sol"; + +/// @custom:proxied +/// @custom:predeploy 0x420000000000000000000000000000000000000F +/// @title GasPriceOracle +/// @notice This contract maintains the variables responsible for computing the L1 portion of the +/// total fee charged on L2. Before Bedrock, this contract held variables in state that were +/// read during the state transition function to compute the L1 portion of the transaction +/// fee. After Bedrock, this contract now simply proxies the L1Block contract, which has +/// the values used to compute the L1 portion of the fee in its state. +/// +/// The contract exposes an API that is useful for knowing how large the L1 portion of the +/// transaction fee will be. The following events were deprecated with Bedrock: +/// - event OverheadUpdated(uint256 overhead); +/// - event ScalarUpdated(uint256 scalar); +/// - event DecimalsUpdated(uint256 decimals); +contract GasPriceOracle is ISemver { + /// @notice Number of decimals used in the scalar. + uint256 public constant DECIMALS = 6; + + /// @notice Semantic version. + /// @custom:semver 1.1.0 + string public constant version = "1.1.0"; + + /// @notice Computes the L1 portion of the fee based on the size of the rlp encoded input + /// transaction, the current L1 base fee, and the various dynamic parameters. + /// @param _data Unsigned fully RLP-encoded transaction to get the L1 fee for. + /// @return L1 fee that should be paid for the tx + function getL1Fee(bytes memory _data) external view returns (uint256) { + uint256 l1GasUsed = getL1GasUsed(_data); + uint256 l1Fee = l1GasUsed * l1BaseFee(); + uint256 divisor = 10 ** DECIMALS; + uint256 unscaled = l1Fee * scalar(); + uint256 scaled = unscaled / divisor; + return scaled; + } + + /// @notice Retrieves the current gas price (base fee). + /// @return Current L2 gas price (base fee). + function gasPrice() public view returns (uint256) { + return block.basefee; + } + + /// @notice Retrieves the current base fee. + /// @return Current L2 base fee. + function baseFee() public view returns (uint256) { + return block.basefee; + } + + /// @notice Retrieves the current fee overhead. + /// @return Current fee overhead. + function overhead() public view returns (uint256) { + return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeOverhead(); + } + + /// @notice Retrieves the current fee scalar. + /// @return Current fee scalar. + function scalar() public view returns (uint256) { + return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeScalar(); + } + + /// @notice Retrieves the latest known L1 base fee. + /// @return Latest known L1 base fee. + function l1BaseFee() public view returns (uint256) { + return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).basefee(); + } + + /// @custom:legacy + /// @notice Retrieves the number of decimals used in the scalar. + /// @return Number of decimals used in the scalar. + function decimals() public pure returns (uint256) { + return DECIMALS; + } + + /// @notice Computes the amount of L1 gas used for a transaction. Adds the overhead which + /// represents the per-transaction gas overhead of posting the transaction and state + /// roots to L1. Adds 68 bytes of padding to account for the fact that the input does + /// not have a signature. + /// @param _data Unsigned fully RLP-encoded transaction to get the L1 gas for. + /// @return Amount of L1 gas used to publish the transaction. + function getL1GasUsed(bytes memory _data) public view returns (uint256) { + uint256 total = 0; + uint256 length = _data.length; + for (uint256 i = 0; i < length; i++) { + if (_data[i] == 0) { + total += 4; + } else { + total += 16; + } + } + uint256 unsigned = total + overhead(); + return unsigned + (68 * 16); + } +} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/L1Block.sol b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/L1Block.sol new file mode 100644 index 0000000000..7722b53b30 --- /dev/null +++ b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/L1Block.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import { ISemver } from "../universal/ISemver.sol"; + +/// @custom:proxied +/// @custom:predeploy 0x4200000000000000000000000000000000000015 +/// @title L1Block +/// @notice The L1Block predeploy gives users access to information about the last known L1 block. +/// Values within this contract are updated once per epoch (every L1 block) and can only be +/// set by the "depositor" account, a special system address. Depositor account transactions +/// are created by the protocol whenever we move to a new epoch. +contract L1Block is ISemver { + /// @notice Address of the special depositor account. + address public constant DEPOSITOR_ACCOUNT = 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001; + + /// @notice The latest L1 block number known by the L2 system. + uint64 public number; + + /// @notice The latest L1 timestamp known by the L2 system. + uint64 public timestamp; + + /// @notice The latest L1 basefee. + uint256 public basefee; + + /// @notice The latest L1 blockhash. + bytes32 public hash; + + /// @notice The number of L2 blocks in the same epoch. + uint64 public sequenceNumber; + + /// @notice The versioned hash to authenticate the batcher by. + bytes32 public batcherHash; + + /// @notice The overhead value applied to the L1 portion of the transaction fee. + uint256 public l1FeeOverhead; + + /// @notice The scalar value applied to the L1 portion of the transaction fee. + uint256 public l1FeeScalar; + + /// @custom:semver 1.1.0 + string public constant version = "1.1.0"; + + /// @notice Updates the L1 block values. + /// @param _number L1 blocknumber. + /// @param _timestamp L1 timestamp. + /// @param _basefee L1 basefee. + /// @param _hash L1 blockhash. + /// @param _sequenceNumber Number of L2 blocks since epoch start. + /// @param _batcherHash Versioned hash to authenticate batcher by. + /// @param _l1FeeOverhead L1 fee overhead. + /// @param _l1FeeScalar L1 fee scalar. + function setL1BlockValues( + uint64 _number, + uint64 _timestamp, + uint256 _basefee, + bytes32 _hash, + uint64 _sequenceNumber, + bytes32 _batcherHash, + uint256 _l1FeeOverhead, + uint256 _l1FeeScalar + ) + external + { + require(msg.sender == DEPOSITOR_ACCOUNT, "L1Block: only the depositor account can set L1 block values"); + + number = _number; + timestamp = _timestamp; + basefee = _basefee; + hash = _hash; + sequenceNumber = _sequenceNumber; + batcherHash = _batcherHash; + l1FeeOverhead = _l1FeeOverhead; + l1FeeScalar = _l1FeeScalar; + } +} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/libraries/Predeploys.sol b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/libraries/Predeploys.sol new file mode 100644 index 0000000000..4a0d399ce7 --- /dev/null +++ b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/libraries/Predeploys.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title Predeploys +/// @notice Contains constant addresses for contracts that are pre-deployed to the L2 system. +library Predeploys { + /// @notice Address of the L2ToL1MessagePasser predeploy. + address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000016; + + /// @notice Address of the L2CrossDomainMessenger predeploy. + address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; + + /// @notice Address of the L2StandardBridge predeploy. + address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; + + /// @notice Address of the L2ERC721Bridge predeploy. + address internal constant L2_ERC721_BRIDGE = 0x4200000000000000000000000000000000000014; + + //// @notice Address of the SequencerFeeWallet predeploy. + address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; + + /// @notice Address of the OptimismMintableERC20Factory predeploy. + address internal constant OPTIMISM_MINTABLE_ERC20_FACTORY = 0x4200000000000000000000000000000000000012; + + /// @notice Address of the OptimismMintableERC721Factory predeploy. + address internal constant OPTIMISM_MINTABLE_ERC721_FACTORY = 0x4200000000000000000000000000000000000017; + + /// @notice Address of the L1Block predeploy. + address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015; + + /// @notice Address of the GasPriceOracle predeploy. Includes fee information + /// and helpers for computing the L1 portion of the transaction fee. + address internal constant GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F; + + /// @custom:legacy + /// @notice Address of the L1MessageSender predeploy. Deprecated. Use L2CrossDomainMessenger + /// or access tx.origin (or msg.sender) in a L1 to L2 transaction instead. + address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; + + /// @custom:legacy + /// @notice Address of the DeployerWhitelist predeploy. No longer active. + address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; + + /// @custom:legacy + /// @notice Address of the LegacyERC20ETH predeploy. Deprecated. Balances are migrated to the + /// state trie as of the Bedrock upgrade. Contract has been locked and write functions + /// can no longer be accessed. + address internal constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000; + + /// @custom:legacy + /// @notice Address of the L1BlockNumber predeploy. Deprecated. Use the L1Block predeploy + /// instead, which exposes more information about the L1 state. + address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; + + /// @custom:legacy + /// @notice Address of the LegacyMessagePasser predeploy. Deprecate. Use the updated + /// L2ToL1MessagePasser contract instead. + address internal constant LEGACY_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; + + /// @notice Address of the ProxyAdmin predeploy. + address internal constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018; + + /// @notice Address of the BaseFeeVault predeploy. + address internal constant BASE_FEE_VAULT = 0x4200000000000000000000000000000000000019; + + /// @notice Address of the L1FeeVault predeploy. + address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A; + + /// @notice Address of the GovernanceToken predeploy. + address internal constant GOVERNANCE_TOKEN = 0x4200000000000000000000000000000000000042; + + /// @notice Address of the SchemaRegistry predeploy. + address internal constant SCHEMA_REGISTRY = 0x4200000000000000000000000000000000000020; + + /// @notice Address of the EAS predeploy. + address internal constant EAS = 0x4200000000000000000000000000000000000021; +} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/universal/ISemver.sol b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/universal/ISemver.sol new file mode 100644 index 0000000000..ae9569a050 --- /dev/null +++ b/contracts/src/v0.8/vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/universal/ISemver.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title ISemver +/// @notice ISemver is a simple contract for ensuring that contracts are +/// versioned using semantic versioning. +interface ISemver { + /// @notice Getter for the semantic version of the contract. This is not + /// meant to be used onchain but instead meant to be used by offchain + /// tooling. + /// @return Semver contract version as a string. + function version() external view returns (string memory); +} \ No newline at end of file From 5bcd414622294d8142e6cfff08f8c1b0c2dc72df Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Tue, 14 Nov 2023 15:26:34 -0400 Subject: [PATCH 148/327] =?UTF-8?q?VRF-749:=20updating=20setup-env=20scrip?= =?UTF-8?q?t=20for=20VRF=20to=20include=20chainId=20when=20cr=E2=80=A6=20(?= =?UTF-8?q?#11286)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-749: updating setup-env script for VRF to include chainId when creating eth keys; README update * VRF-749: updating README.md --- core/scripts/common/vrf/setup-envs/README.md | 83 ++++++++++++++++++-- core/scripts/common/vrf/setup-envs/main.go | 2 + 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/core/scripts/common/vrf/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md index f3b391f0ee..9aa76ffbbb 100644 --- a/core/scripts/common/vrf/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -15,6 +15,7 @@ export ETH_CHAIN_ID= export ACCOUNT_KEY= ``` 5. execute from `core/scripts/common/vrf/setup-envs` folder + * `--vrf-version` - "v2" or "v2plus" ``` go run . \ --vrf-version="v2plus" \ @@ -28,24 +29,96 @@ go run . \ --bhs-bk-creds-file \ --bhf-node-url=http://localhost:6614 \ --bhf-creds-file \ +--num-eth-keys=1 \ +--num-vrf-keys=1 \ +--sending-key-funding-amount="1e17" \ --deploy-contracts-and-create-jobs="true" \ --subscription-balance="1e19" \ --subscription-balance-native="1e18" \ --batch-fulfillment-enabled="true" \ --min-confs=3 \ ---num-eth-keys=1 \ ---num-vrf-keys=1 \ ---sending-key-funding-amount="1e17" \ --register-vrf-key-against-address= ``` -Optional parameters - will not be deployed if specified (NOT WORKING YET) +Optional parameters - will not be deployed if specified ``` --link-address

\ --link-eth-feed
\ +``` + +WIP - Not working yet: +``` --bhs-address
\ --batch-bhs-address
\ --coordinator-address
\ --batch-coordinator-address
-``` \ No newline at end of file +``` + + +## Process Example + +1. If the CL nodes do not have needed amount of ETH and VRF keys, you need to create them first: +``` +go run . \ +--vrf-version="v2" \ +--vrf-primary-node-url= \ +--vrf-primary-creds-file \ +--bhs-node-url= \ +--bhs-creds-file \ +--num-eth-keys=3 \ +--num-vrf-keys=1 \ +--sending-key-funding-amount="1e17" \ +--deploy-contracts-and-create-jobs="false" +``` +Then update corresponding deployment scripts with the new ETH addresses, specifying max gas price for each key + +e.g.: +``` +[[EVM.KeySpecific]] +Key = '' +GasEstimator.PriceMax = '30 gwei' +``` + +2. If the CL nodes already have needed amount of ETH and VRF keys, you can deploy contracts and create jobs with the following command: +NOTE - nodes will be funded at least to the amount specified in `--sending-key-funding-amount` parameter. +``` +go run . \ +--vrf-version="v2" \ +--vrf-primary-node-url= \ +--vrf-primary-creds-file \ +--bhs-node-url= \ +--bhs-creds-file \ +--num-eth-keys=3 \ +--num-vrf-keys=1 \ +--sending-key-funding-amount="1e17" \ +--deploy-contracts-and-create-jobs="true" \ +--subscription-balance="1e19" \ +--subscription-balance-native="1e18" \ +--batch-fulfillment-enabled="true" \ +--min-confs=3 \ +--register-vrf-key-against-address="" \ +--link-address "" \ +--link-eth-feed "" +``` + + +3. We can run sample rand request to see if the setup works. + After previous script was done, we should see the command to run in the console: + + e.g. to trigger rand request: + 1. navigate to `core/scripts/vrfv2plus/testnet` or `core/scripts/vrfv2/testnet` folder + 2. set needed env variables + ``` + export ETH_URL= + export ETH_CHAIN_ID= + export ACCOUNT_KEY= + ``` + 3. Trigger rand request (get this command from the console after running `setup-envs` script ) + ```bash + go run . eoa-load-test-request-with-metrics --consumer-address= --sub-id=1 --key-hash= --request-confirmations <> --requests 1 --runs 1 --cb-gas-limit 1_000_000 + ``` + 4. Then to check that rand request was fulfilled (get this command from the console after running `setup-envs` script ) + ```bash + go run . eoa-load-test-read-metrics --consumer-address= + ``` \ No newline at end of file diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index 7c2530ffd4..94662aa183 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -506,6 +506,8 @@ func createETHKeysIfNeeded(client *clcmd.Shell, app *cli.App, output *bytes.Buff if *maxGasPriceGwei > 0 { helpers.PanicErr(flagSet.Set("max-gas-price-gwei", fmt.Sprintf("%d", *maxGasPriceGwei))) } + err := flagSet.Parse([]string{"-evm-chain-id", os.Getenv("ETH_CHAIN_ID")}) + helpers.PanicErr(err) err = client.CreateETHKey(cli.NewContext(app, flagSet, nil)) helpers.PanicErr(err) helpers.PanicErr(json.Unmarshal(output.Bytes(), &newKey)) From e7e0d42ee76ddc019abae7072187e99f98ba699e Mon Sep 17 00:00:00 2001 From: Tate Date: Tue, 14 Nov 2023 13:53:54 -0700 Subject: [PATCH 149/327] [TT-707] chainlink-tests image build workflow dispatch (#11288) --- .github/actions/build-test-image/action.yml | 6 +++++- .../workflows/integration-tests-publish.yml | 20 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index a241f51d92..252b292d03 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -17,6 +17,9 @@ inputs: description: The test suites to build into the image default: chaos migration performance reorg smoke soak benchmark required: false + base_image_tag: + description: The test base image version to use, if not provided it will use the version from the ./integration-tests/go.mod file + required: false QA_AWS_ROLE_TO_ASSUME: description: The AWS role to assume as the CD user, if any. Used in configuring the docker/login-action required: true @@ -31,6 +34,7 @@ runs: using: composite steps: - name: Get CTF Version + if: ${{ inputs.base_image_tag == '' }} id: version uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: @@ -55,7 +59,7 @@ runs: file: ./integration-tests/test.Dockerfile build-args: | BASE_IMAGE=${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image - IMAGE_VERSION=${{ steps.version.outputs.version }} + IMAGE_VERSION=${{ inputs.base_image_tag || steps.version.outputs.version }} SUITES="${{ inputs.suites }}" AWS_REGION: ${{ inputs.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index a66ea61228..9579b83b98 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -5,9 +5,20 @@ on: push: branches: - develop + workflow_dispatch: + inputs: + chainlink-tests-tag: + description: 'The tag to be pushed' + required: true + ctf-base-image-tag: + description: | + 'The tag of the CTF base image to be used, + typically something like v1.18.6 from https://github.com/smartcontractkit/chainlink-testing-framework/releases + or a custom tag or branch you have pushed.' + required: true env: - ECR_TAG: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:develop + ECR_TAG_BASE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests jobs: publish-integration-test-image: @@ -16,7 +27,7 @@ jobs: id-token: write contents: read name: Publish Integration Test Image - runs-on: ubuntu-latest + runs-on: ubuntu20.04-16cores-64GB steps: - name: Collect Metrics id: collect-gha-metrics @@ -29,11 +40,12 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Build Image uses: ./.github/actions/build-test-image with: - other_tags: ${{ env.ECR_TAG }} + other_tags: "${{ env.ECR_TAG_BASE }}:${{ inputs.chainlink-tests-tag || 'develop' }}" + base_image_tag: ${{ inputs.ctf-base-image-tag }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} From 3a38e9052fa49df94fe309efa719ef44268f5545 Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Tue, 14 Nov 2023 16:21:09 -0800 Subject: [PATCH 150/327] [Functions] Offchain heartbeat support in Listener and OCR2 plugin (#11274) 1. Add new API structs 2. Mark offchain requests in Listener 3. Introduce a simple OffchainTransmitter to pass responses from the plugin --- core/services/functions/listener.go | 42 +++++++++++++ core/services/functions/listener_test.go | 40 +++++++++++++ .../functions/mocks/offchain_transmitter.go | 59 ++++++++++++++++++ .../functions/offchain_transmitter.go | 39 ++++++++++++ .../functions/offchain_transmitter_test.go | 31 ++++++++++ core/services/functions/request.go | 15 +++++ .../services/ocr2/plugins/functions/plugin.go | 17 +++--- .../ocr2/plugins/functions/reporting.go | 48 +++++++++------ .../ocr2/plugins/functions/reporting_test.go | 60 +++++++++++++------ 9 files changed, 308 insertions(+), 43 deletions(-) create mode 100644 core/services/functions/mocks/offchain_transmitter.go create mode 100644 core/services/functions/offchain_transmitter.go create mode 100644 core/services/functions/offchain_transmitter_test.go diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index 773ae61040..5614c5331d 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -111,6 +111,9 @@ const ( DefaultPruneCheckFrequencySec uint32 = 60 * 10 DefaultPruneBatchSize uint32 = 500 + // Used in place of OnchainMetadata for all offchain requests. + OffchainRequestMarker string = "OFFCHAIN_REQUEST" + FlagCBORMaxSize uint32 = 1 FlagSecretsMaxSize uint32 = 2 ) @@ -280,6 +283,45 @@ func (l *FunctionsListener) getMaxSecretsSize(flags RequestFlags) uint32 { return l.pluginConfig.MaxSecretsSizesList[idx] } +func (l *FunctionsListener) HandleOffchainRequest(ctx context.Context, request *OffchainRequest) error { + if request == nil { + return errors.New("HandleOffchainRequest: received nil request") + } + if len(request.RequestId) != RequestIDLength { + return fmt.Errorf("HandleOffchainRequest: invalid request ID length %d", len(request.RequestId)) + } + if len(request.SubscriptionOwner) != common.AddressLength || len(request.RequestInitiator) != common.AddressLength { + return fmt.Errorf("HandleOffchainRequest: SubscriptionOwner and RequestInitiator must be set to valid addresses") + } + + var requestId RequestID + copy(requestId[:], request.RequestId[:32]) + subscriptionOwner := common.BytesToAddress(request.SubscriptionOwner) + senderAddr := common.BytesToAddress(request.RequestInitiator) + emptyTxHash := common.Hash{} + zeroCallbackGasLimit := uint32(0) + newReq := &Request{ + RequestID: requestId, + RequestTxHash: &emptyTxHash, + ReceivedAt: time.Now(), + Flags: []byte{}, + CallbackGasLimit: &zeroCallbackGasLimit, + // use sender address in place of coordinator contract to keep batches uniform + CoordinatorContractAddress: &senderAddr, + OnchainMetadata: []byte(OffchainRequestMarker), + } + if err := l.pluginORM.CreateRequest(newReq, pg.WithParentCtx(ctx)); err != nil { + if errors.Is(err, ErrDuplicateRequestID) { + l.logger.Warnw("HandleOffchainRequest: received duplicate request ID", "requestID", formatRequestId(requestId), "err", err) + } else { + l.logger.Errorw("HandleOffchainRequest: failed to create a DB entry for new request", "requestID", formatRequestId(requestId), "err", err) + } + return err + } + l.handleRequest(ctx, requestId, request.SubscriptionId, subscriptionOwner, RequestFlags{}, &request.Data) + return nil +} + func (l *FunctionsListener) handleOracleRequestV1(request *evmrelayTypes.OracleRequest) { defer l.shutdownWaitGroup.Done() l.logger.Infow("handleOracleRequestV1: oracle request v1 received", "requestID", formatRequestId(request.RequestId)) diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 3b7ed46988..ac2bc64184 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -179,6 +179,46 @@ func TestFunctionsListener_HandleOracleRequestV1_Success(t *testing.T) { uni.service.Close() } +func TestFunctionsListener_HandleOffchainRequest_Success(t *testing.T) { + testutils.SkipShortDB(t) + t.Parallel() + + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + + uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) + uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) + uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(ResultBytes, nil, nil, nil) + uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Return(nil) + + request := &functions_service.OffchainRequest{ + RequestId: RequestID[:], + RequestInitiator: SubscriptionOwner.Bytes(), + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner.Bytes(), + Data: functions_service.RequestData{}, + } + require.NoError(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) +} + +func TestFunctionsListener_HandleOffchainRequest_Invalid(t *testing.T) { + testutils.SkipShortDB(t) + t.Parallel() + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + + request := &functions_service.OffchainRequest{ + RequestId: RequestID[:], + RequestInitiator: []byte("invalid_address"), + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner.Bytes(), + Data: functions_service.RequestData{}, + } + require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) + + request.RequestInitiator = SubscriptionOwner.Bytes() + request.SubscriptionOwner = []byte("invalid_address") + require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) +} + func TestFunctionsListener_HandleOracleRequestV1_ComputationError(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() diff --git a/core/services/functions/mocks/offchain_transmitter.go b/core/services/functions/mocks/offchain_transmitter.go new file mode 100644 index 0000000000..d9a7be04dd --- /dev/null +++ b/core/services/functions/mocks/offchain_transmitter.go @@ -0,0 +1,59 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package mocks + +import ( + context "context" + + functions "github.com/smartcontractkit/chainlink/v2/core/services/functions" + mock "github.com/stretchr/testify/mock" +) + +// OffchainTransmitter is an autogenerated mock type for the OffchainTransmitter type +type OffchainTransmitter struct { + mock.Mock +} + +// ReportChannel provides a mock function with given fields: +func (_m *OffchainTransmitter) ReportChannel() chan *functions.OffchainResponse { + ret := _m.Called() + + var r0 chan *functions.OffchainResponse + if rf, ok := ret.Get(0).(func() chan *functions.OffchainResponse); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(chan *functions.OffchainResponse) + } + } + + return r0 +} + +// TransmitReport provides a mock function with given fields: ctx, report +func (_m *OffchainTransmitter) TransmitReport(ctx context.Context, report *functions.OffchainResponse) error { + ret := _m.Called(ctx, report) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *functions.OffchainResponse) error); ok { + r0 = rf(ctx, report) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewOffchainTransmitter creates a new instance of OffchainTransmitter. 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 NewOffchainTransmitter(t interface { + mock.TestingT + Cleanup(func()) +}) *OffchainTransmitter { + mock := &OffchainTransmitter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/services/functions/offchain_transmitter.go b/core/services/functions/offchain_transmitter.go new file mode 100644 index 0000000000..63527937f9 --- /dev/null +++ b/core/services/functions/offchain_transmitter.go @@ -0,0 +1,39 @@ +package functions + +import ( + "context" + + "github.com/pkg/errors" +) + +// Simple wrapper around a channel to transmit offchain reports between +// OCR plugin and Gateway connector +// +//go:generate mockery --quiet --name OffchainTransmitter --output ./mocks/ --case=underscore +type OffchainTransmitter interface { + TransmitReport(ctx context.Context, report *OffchainResponse) error + ReportChannel() chan *OffchainResponse +} + +type offchainTransmitter struct { + reportCh chan *OffchainResponse +} + +func NewOffchainTransmitter(chanSize uint32) OffchainTransmitter { + return &offchainTransmitter{ + reportCh: make(chan *OffchainResponse, chanSize), + } +} + +func (t *offchainTransmitter) TransmitReport(ctx context.Context, report *OffchainResponse) error { + select { + case t.reportCh <- report: + return nil + case <-ctx.Done(): + return errors.New("context cancelled") + } +} + +func (t *offchainTransmitter) ReportChannel() chan *OffchainResponse { + return t.reportCh +} diff --git a/core/services/functions/offchain_transmitter_test.go b/core/services/functions/offchain_transmitter_test.go new file mode 100644 index 0000000000..bec639bf27 --- /dev/null +++ b/core/services/functions/offchain_transmitter_test.go @@ -0,0 +1,31 @@ +package functions_test + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/services/functions" +) + +func TestOffchainTransmitter(t *testing.T) { + t.Parallel() + + transmitter := functions.NewOffchainTransmitter(1) + ch := transmitter.ReportChannel() + report := &functions.OffchainResponse{RequestId: []byte("testID")} + ctx := testutils.Context(t) + + require.NoError(t, transmitter.TransmitReport(ctx, report)) + require.Equal(t, report, <-ch) + + require.NoError(t, transmitter.TransmitReport(ctx, report)) + + ctxTimeout, cancel := context.WithTimeout(ctx, time.Millisecond*20) + defer cancel() + // should not freeze + require.Error(t, transmitter.TransmitReport(ctxTimeout, report)) +} diff --git a/core/services/functions/request.go b/core/services/functions/request.go index 181058b83d..14c0b0d0e5 100644 --- a/core/services/functions/request.go +++ b/core/services/functions/request.go @@ -9,6 +9,14 @@ const ( type RequestFlags [32]byte +type OffchainRequest struct { + RequestId []byte `json:"requestId"` + RequestInitiator []byte `json:"requestInitiator"` + SubscriptionId uint64 `json:"subscriptionId"` + SubscriptionOwner []byte `json:"subscriptionOwner"` + Data RequestData `json:"data"` +} + type RequestData struct { Source string `json:"source" cbor:"source"` Language int `json:"language" cbor:"language"` @@ -19,6 +27,13 @@ type RequestData struct { BytesArgs [][]byte `json:"bytesArgs,omitempty" cbor:"bytesArgs"` } +// NOTE: to be extended with raw report and signatures when needed +type OffchainResponse struct { + RequestId []byte `json:"requestId"` + Result []byte `json:"result"` + Error []byte `json:"error"` +} + type DONHostedSecrets struct { SlotID uint `json:"slotId" cbor:"slotId"` Version uint64 `json:"version" cbor:"version"` diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 26cffac5ab..8597b8ad4c 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -50,9 +50,10 @@ type FunctionsServicesConfig struct { } const ( - FunctionsBridgeName string = "ea_bridge" - FunctionsS4Namespace string = "functions" - MaxAdapterResponseBytes int64 = 1_000_000 + FunctionsBridgeName string = "ea_bridge" + FunctionsS4Namespace string = "functions" + MaxAdapterResponseBytes int64 = 1_000_000 + DefaultOffchainTransmitterChannelSize uint32 = 1000 ) // Create all OCR2 plugin Oracles and all extra services needed to run a Functions job. @@ -100,6 +101,7 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs s4Storage = s4.NewStorage(conf.Logger, *pluginConfig.S4Constraints, s4ORM, utils.NewRealClock()) } + offchainTransmitter := functions.NewOffchainTransmitter(DefaultOffchainTransmitterChannelSize) listenerLogger := conf.Logger.Named("FunctionsListener") bridgeAccessor := functions.NewBridgeAccessor(conf.BridgeORM, FunctionsBridgeName, MaxAdapterResponseBytes) functionsListener := functions.NewFunctionsListener( @@ -118,10 +120,11 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs allServices = append(allServices, functionsListener) functionsOracleArgs.ReportingPluginFactory = FunctionsReportingPluginFactory{ - Logger: functionsOracleArgs.Logger, - PluginORM: pluginORM, - JobID: conf.Job.ExternalJobID, - ContractVersion: pluginConfig.ContractVersion, + Logger: functionsOracleArgs.Logger, + PluginORM: pluginORM, + JobID: conf.Job.ExternalJobID, + ContractVersion: pluginConfig.ContractVersion, + OffchainTransmitter: offchainTransmitter, } functionsReportingPluginOracle, err := libocr2.NewOracle(*functionsOracleArgs) if err != nil { diff --git a/core/services/ocr2/plugins/functions/reporting.go b/core/services/ocr2/plugins/functions/reporting.go index dfa8f575d1..36e8a88273 100644 --- a/core/services/ocr2/plugins/functions/reporting.go +++ b/core/services/ocr2/plugins/functions/reporting.go @@ -1,6 +1,7 @@ package functions import ( + "bytes" "context" "fmt" @@ -21,22 +22,24 @@ import ( ) type FunctionsReportingPluginFactory struct { - Logger commontypes.Logger - PluginORM functions.ORM - JobID uuid.UUID - ContractVersion uint32 + Logger commontypes.Logger + PluginORM functions.ORM + JobID uuid.UUID + ContractVersion uint32 + OffchainTransmitter functions.OffchainTransmitter } var _ types.ReportingPluginFactory = (*FunctionsReportingPluginFactory)(nil) type functionsReporting struct { - logger commontypes.Logger - pluginORM functions.ORM - jobID uuid.UUID - reportCodec encoding.ReportCodec - genericConfig *types.ReportingPluginConfig - specificConfig *config.ReportingPluginConfigWrapper - contractVersion uint32 + logger commontypes.Logger + pluginORM functions.ORM + jobID uuid.UUID + reportCodec encoding.ReportCodec + genericConfig *types.ReportingPluginConfig + specificConfig *config.ReportingPluginConfigWrapper + contractVersion uint32 + offchainTransmitter functions.OffchainTransmitter } var _ types.ReportingPlugin = &functionsReporting{} @@ -112,13 +115,14 @@ func (f FunctionsReportingPluginFactory) NewReportingPlugin(rpConfig types.Repor }, } plugin := functionsReporting{ - logger: f.Logger, - pluginORM: f.PluginORM, - jobID: f.JobID, - reportCodec: codec, - genericConfig: &rpConfig, - specificConfig: pluginConfig, - contractVersion: f.ContractVersion, + logger: f.Logger, + pluginORM: f.PluginORM, + jobID: f.JobID, + reportCodec: codec, + genericConfig: &rpConfig, + specificConfig: pluginConfig, + contractVersion: f.ContractVersion, + offchainTransmitter: f.OffchainTransmitter, } promReportingPlugins.WithLabelValues(f.JobID.String()).Inc() return &plugin, info, nil @@ -437,6 +441,14 @@ func (r *functionsReporting) ShouldAcceptFinalizedReport(ctx context.Context, ts r.logger.Debug("FunctionsReporting ShouldAcceptFinalizedReport: state couldn't be changed to FINALIZED. Not transmitting.", commontypes.LogFields{"requestID": reqIdStr, "err": err}) continue } + if bytes.Equal(item.OnchainMetadata, []byte(functions.OffchainRequestMarker)) { + r.logger.Debug("FunctionsReporting ShouldAcceptFinalizedReport: transmitting offchain", commontypes.LogFields{"requestID": reqIdStr}) + result := functions.OffchainResponse{RequestId: item.RequestID, Result: item.Result, Error: item.Error} + if err := r.offchainTransmitter.TransmitReport(ctx, &result); err != nil { + r.logger.Error("FunctionsReporting ShouldAcceptFinalizedReport: unable to transmit offchain", commontypes.LogFields{"requestID": reqIdStr, "err": err}) + } + continue // doesn't need onchain transmission + } needTransmissionIds = append(needTransmissionIds, reqIdStr) } r.logger.Debug("FunctionsReporting ShouldAcceptFinalizedReport end", commontypes.LogFields{ diff --git a/core/services/ocr2/plugins/functions/reporting_test.go b/core/services/ocr2/plugins/functions/reporting_test.go index 24b430abd9..860492bfc5 100644 --- a/core/services/ocr2/plugins/functions/reporting_test.go +++ b/core/services/ocr2/plugins/functions/reporting_test.go @@ -22,14 +22,16 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/encoding" ) -func preparePlugin(t *testing.T, batchSize uint32, maxTotalGasLimit uint32) (types.ReportingPlugin, *functions_mocks.ORM, encoding.ReportCodec) { +func preparePlugin(t *testing.T, batchSize uint32, maxTotalGasLimit uint32) (types.ReportingPlugin, *functions_mocks.ORM, encoding.ReportCodec, *functions_mocks.OffchainTransmitter) { lggr := logger.TestLogger(t) ocrLogger := relaylogger.NewOCRWrapper(lggr, true, func(msg string) {}) orm := functions_mocks.NewORM(t) + offchainTransmitter := functions_mocks.NewOffchainTransmitter(t) factory := functions.FunctionsReportingPluginFactory{ - Logger: ocrLogger, - PluginORM: orm, - ContractVersion: 1, + Logger: ocrLogger, + PluginORM: orm, + ContractVersion: 1, + OffchainTransmitter: offchainTransmitter, } pluginConfig := config.ReportingPluginConfigWrapper{ @@ -48,7 +50,7 @@ func preparePlugin(t *testing.T, batchSize uint32, maxTotalGasLimit uint32) (typ require.NoError(t, err) codec, err := encoding.NewReportCodec(1) require.NoError(t, err) - return plugin, orm, codec + return plugin, orm, codec, offchainTransmitter } func newRequestID() functions_srv.RequestID { @@ -130,7 +132,7 @@ func newObservation(t *testing.T, observerId uint8, requests ...*encoding.Proces func TestFunctionsReporting_Query(t *testing.T) { t.Parallel() const batchSize = 10 - plugin, orm, _ := preparePlugin(t, batchSize, 0) + plugin, orm, _, _ := preparePlugin(t, batchSize, 0) reqs := []functions_srv.Request{newRequest(), newRequest()} orm.On("FindOldestEntriesByState", functions_srv.RESULT_READY, uint32(batchSize), mock.Anything).Return(reqs, nil) @@ -148,7 +150,7 @@ func TestFunctionsReporting_Query(t *testing.T) { func TestFunctionsReporting_Query_HandleCoordinatorMismatch(t *testing.T) { t.Parallel() const batchSize = 10 - plugin, orm, _ := preparePlugin(t, batchSize, 1000000) + plugin, orm, _, _ := preparePlugin(t, batchSize, 1000000) reqs := []functions_srv.Request{newRequest(), newRequest()} reqs[0].CoordinatorContractAddress = &common.Address{1} reqs[1].CoordinatorContractAddress = &common.Address{2} @@ -167,7 +169,7 @@ func TestFunctionsReporting_Query_HandleCoordinatorMismatch(t *testing.T) { func TestFunctionsReporting_Observation(t *testing.T) { t.Parallel() - plugin, orm, _ := preparePlugin(t, 10, 0) + plugin, orm, _, _ := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("abc")) req2 := newRequest() @@ -202,7 +204,7 @@ func TestFunctionsReporting_Observation(t *testing.T) { func TestFunctionsReporting_Observation_IncorrectQuery(t *testing.T) { t.Parallel() - plugin, orm, _ := preparePlugin(t, 10, 0) + plugin, orm, _, _ := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("abc")) invalidId := []byte("invalid") @@ -229,7 +231,7 @@ func TestFunctionsReporting_Observation_IncorrectQuery(t *testing.T) { func TestFunctionsReporting_Report(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 1000000) + plugin, _, codec, _ := preparePlugin(t, 10, 1000000) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult := []byte("aaa") procReq1 := newProcessedRequest(reqId1, compResult, []byte{}) @@ -266,7 +268,7 @@ func TestFunctionsReporting_Report(t *testing.T) { func TestFunctionsReporting_Report_WithGasLimitAndMetadata(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 300000) + plugin, _, codec, _ := preparePlugin(t, 10, 300000) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult := []byte("aaa") gasLimit1, gasLimit2 := uint32(100_000), uint32(200_000) @@ -307,7 +309,7 @@ func TestFunctionsReporting_Report_WithGasLimitAndMetadata(t *testing.T) { func TestFunctionsReporting_Report_HandleCoordinatorMismatch(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 300000) + plugin, _, codec, _ := preparePlugin(t, 10, 300000) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult, meta := []byte("aaa"), []byte("meta") coordinatorContractA, coordinatorContractB := common.Address{1}, common.Address{2} @@ -337,7 +339,7 @@ func TestFunctionsReporting_Report_HandleCoordinatorMismatch(t *testing.T) { func TestFunctionsReporting_Report_CallbackGasLimitExceeded(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 200000) + plugin, _, codec, _ := preparePlugin(t, 10, 200000) reqId1, reqId2 := newRequestID(), newRequestID() compResult := []byte("aaa") gasLimit1, gasLimit2 := uint32(100_000), uint32(200_000) @@ -368,7 +370,7 @@ func TestFunctionsReporting_Report_CallbackGasLimitExceeded(t *testing.T) { func TestFunctionsReporting_Report_DeterministicOrderOfRequests(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 0) + plugin, _, codec, _ := preparePlugin(t, 10, 0) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult := []byte("aaa") @@ -397,7 +399,7 @@ func TestFunctionsReporting_Report_DeterministicOrderOfRequests(t *testing.T) { func TestFunctionsReporting_Report_IncorrectObservation(t *testing.T) { t.Parallel() - plugin, _, _ := preparePlugin(t, 10, 0) + plugin, _, _, _ := preparePlugin(t, 10, 0) reqId1 := newRequestID() compResult := []byte("aaa") @@ -416,7 +418,14 @@ func getReportBytes(t *testing.T, codec encoding.ReportCodec, reqs ...functions_ var report []*encoding.ProcessedRequest for _, req := range reqs { req := req - report = append(report, &encoding.ProcessedRequest{RequestID: req.RequestID[:], Result: req.Result}) + report = append(report, &encoding.ProcessedRequest{ + RequestID: req.RequestID[:], + Result: req.Result, + Error: req.Error, + CallbackGasLimit: *req.CallbackGasLimit, + CoordinatorContract: req.CoordinatorContractAddress[:], + OnchainMetadata: req.OnchainMetadata, + }) } reportBytes, err := codec.EncodeReport(report) require.NoError(t, err) @@ -425,7 +434,7 @@ func getReportBytes(t *testing.T, codec encoding.ReportCodec, reqs ...functions_ func TestFunctionsReporting_ShouldAcceptFinalizedReport(t *testing.T) { t.Parallel() - plugin, orm, codec := preparePlugin(t, 10, 0) + plugin, orm, codec, _ := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("xxx")) // nonexistent req2 := newRequestWithResult([]byte("abc")) @@ -462,9 +471,24 @@ func TestFunctionsReporting_ShouldAcceptFinalizedReport(t *testing.T) { require.True(t, should) } +func TestFunctionsReporting_ShouldAcceptFinalizedReport_OffchainTransmission(t *testing.T) { + t.Parallel() + plugin, orm, codec, offchainTransmitter := preparePlugin(t, 10, 0) + req1 := newRequestWithResult([]byte("abc")) + req1.OnchainMetadata = []byte(functions_srv.OffchainRequestMarker) + + orm.On("FindById", req1.RequestID, mock.Anything).Return(&req1, nil) + orm.On("SetFinalized", req1.RequestID, mock.Anything, mock.Anything, mock.Anything).Return(nil) + offchainTransmitter.On("TransmitReport", mock.Anything, mock.Anything).Return(nil) + + should, err := plugin.ShouldAcceptFinalizedReport(testutils.Context(t), types.ReportTimestamp{}, getReportBytes(t, codec, req1)) + require.NoError(t, err) + require.False(t, should) +} + func TestFunctionsReporting_ShouldTransmitAcceptedReport(t *testing.T) { t.Parallel() - plugin, orm, codec := preparePlugin(t, 10, 0) + plugin, orm, codec, _ := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("xxx")) // nonexistent req2 := newRequestWithResult([]byte("abc")) From 75c70f730b08ce07bc4fbf2ec77d619b39d55968 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 15 Nov 2023 06:01:48 -0600 Subject: [PATCH 151/327] core/services/pg: simplify API (#11296) --- core/services/pg/connection.go | 2 +- core/services/pg/q.go | 2 +- core/services/pg/sqlx.go | 2 +- core/services/pg/transaction.go | 54 +++++++++++---------------------- 4 files changed, 20 insertions(+), 40 deletions(-) diff --git a/core/services/pg/connection.go b/core/services/pg/connection.go index 0bafd5dcd0..ee345bb625 100644 --- a/core/services/pg/connection.go +++ b/core/services/pg/connection.go @@ -42,7 +42,7 @@ func NewConnection(uri string, dialect dialects.DialectName, config ConnectionCo lockTimeout := config.DefaultLockTimeout().Milliseconds() idleInTxSessionTimeout := config.DefaultIdleInTxSessionTimeout().Milliseconds() stmt := fmt.Sprintf(`SET TIME ZONE 'UTC'; SET lock_timeout = %d; SET idle_in_transaction_session_timeout = %d; SET default_transaction_isolation = %q`, - lockTimeout, idleInTxSessionTimeout, DefaultIsolation.String()) + lockTimeout, idleInTxSessionTimeout, defaultIsolation.String()) if _, err = db.Exec(stmt); err != nil { return nil, err } diff --git a/core/services/pg/q.go b/core/services/pg/q.go index 470d39c825..9c9c15d983 100644 --- a/core/services/pg/q.go +++ b/core/services/pg/q.go @@ -165,7 +165,7 @@ func (q Q) Context() (context.Context, context.CancelFunc) { return context.WithTimeout(q.ParentCtx, q.QueryTimeout) } -func (q Q) Transaction(fc func(q Queryer) error, txOpts ...TxOptions) error { +func (q Q) Transaction(fc func(q Queryer) error, txOpts ...TxOption) error { ctx, cancel := q.Context() defer cancel() return SqlxTransaction(ctx, q.Queryer, q.originalLogger(), fc, txOpts...) diff --git a/core/services/pg/sqlx.go b/core/services/pg/sqlx.go index 820cd51712..c371c29213 100644 --- a/core/services/pg/sqlx.go +++ b/core/services/pg/sqlx.go @@ -35,7 +35,7 @@ func WrapDbWithSqlx(rdb *sql.DB) *sqlx.DB { return db } -func SqlxTransaction(ctx context.Context, q Queryer, lggr logger.Logger, fc func(q Queryer) error, txOpts ...TxOptions) (err error) { +func SqlxTransaction(ctx context.Context, q Queryer, lggr logger.Logger, fc func(q Queryer) error, txOpts ...TxOption) (err error) { switch db := q.(type) { case *sqlx.Tx: // nested transaction: just use the outer transaction diff --git a/core/services/pg/transaction.go b/core/services/pg/transaction.go index 92d72b3d81..74841d010b 100644 --- a/core/services/pg/transaction.go +++ b/core/services/pg/transaction.go @@ -15,44 +15,21 @@ import ( corelogger "github.com/smartcontractkit/chainlink/v2/core/logger" ) -type TxOptions struct { - sql.TxOptions -} +// NOTE: This is the default level in Postgres anyway, we just make it +// explicit here +const defaultIsolation = sql.LevelReadCommitted -// NOTE: In an ideal world the timeouts below would be set to something sane in -// the postgres configuration by the user. Since we do not live in an ideal -// world, it is necessary to override them here. -// -// They cannot easily be set at a session level due to how Go's connection -// pooling works. -const ( - // NOTE: This is the default level in Postgres anyway, we just make it - // explicit here - DefaultIsolation = sql.LevelReadCommitted -) +// TxOption is a functional option for SQL transactions. +type TxOption func(*sql.TxOptions) -func OptReadOnlyTx() TxOptions { - return TxOptions{TxOptions: sql.TxOptions{ReadOnly: true}} -} - -func applyDefaults(optss []TxOptions) (txOpts sql.TxOptions) { - readOnly := false - if len(optss) > 0 { - opts := optss[0] - readOnly = opts.ReadOnly - } - txOpts = sql.TxOptions{ - ReadOnly: readOnly, +func OptReadOnlyTx() TxOption { + return func(opts *sql.TxOptions) { + opts.ReadOnly = true } - return } -func SqlTransaction(ctx context.Context, rdb *sql.DB, lggr logger.Logger, fn func(tx *sqlx.Tx) error, optss ...TxOptions) (err error) { +func SqlTransaction(ctx context.Context, rdb *sql.DB, lggr logger.Logger, fn func(tx *sqlx.Tx) error, opts ...TxOption) (err error) { db := WrapDbWithSqlx(rdb) - return sqlxTransaction(ctx, db, lggr, fn, optss...) -} - -func sqlxTransaction(ctx context.Context, db *sqlx.DB, lggr logger.Logger, fn func(tx *sqlx.Tx) error, optss ...TxOptions) (err error) { wrapFn := func(q Queryer) error { tx, ok := q.(*sqlx.Tx) if !ok { @@ -60,16 +37,19 @@ func sqlxTransaction(ctx context.Context, db *sqlx.DB, lggr logger.Logger, fn fu } return fn(tx) } - return sqlxTransactionQ(ctx, db, lggr, wrapFn, optss...) + return sqlxTransactionQ(ctx, db, lggr, wrapFn, opts...) } -// TxBeginner can be a db or a conn, anything that implements BeginTxx -type TxBeginner interface { +// txBeginner can be a db or a conn, anything that implements BeginTxx +type txBeginner interface { BeginTxx(context.Context, *sql.TxOptions) (*sqlx.Tx, error) } -func sqlxTransactionQ(ctx context.Context, db TxBeginner, lggr logger.Logger, fn func(q Queryer) error, optss ...TxOptions) (err error) { - txOpts := applyDefaults(optss) +func sqlxTransactionQ(ctx context.Context, db txBeginner, lggr logger.Logger, fn func(q Queryer) error, opts ...TxOption) (err error) { + var txOpts sql.TxOptions + for _, o := range opts { + o(&txOpts) + } var tx *sqlx.Tx tx, err = db.BeginTxx(ctx, &txOpts) From 50fbfd2bce762745122e514329fa6be93f867e28 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 15 Nov 2023 06:03:41 -0600 Subject: [PATCH 152/327] core/store/migrate: add context and error; remove panics (#11295) --- core/cmd/shell.go | 6 ++--- core/cmd/shell_local.go | 34 +++++++++++++++-------- core/store/migrate/migrate.go | 43 +++++++++++++++++------------- core/store/migrate/migrate_test.go | 11 ++++---- 4 files changed, 56 insertions(+), 38 deletions(-) diff --git a/core/cmd/shell.go b/core/cmd/shell.go index e1ac0b99ca..07cd2185dc 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -145,7 +145,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G return nil, err } - err = handleNodeVersioning(db, appLggr, cfg.RootDir(), cfg.Database(), cfg.WebServer().HTTPPort()) + err = handleNodeVersioning(ctx, db, appLggr, cfg.RootDir(), cfg.Database(), cfg.WebServer().HTTPPort()) if err != nil { return nil, err } @@ -229,7 +229,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G } // handleNodeVersioning is a setup-time helper to encapsulate version changes and db migration -func handleNodeVersioning(db *sqlx.DB, appLggr logger.Logger, rootDir string, cfg config.Database, healthReportPort uint16) error { +func handleNodeVersioning(ctx context.Context, db *sqlx.DB, appLggr logger.Logger, rootDir string, cfg config.Database, healthReportPort uint16) error { var err error // Set up the versioning Configs verORM := versioning.NewORM(db, appLggr, cfg.DefaultQueryTimeout()) @@ -260,7 +260,7 @@ func handleNodeVersioning(db *sqlx.DB, appLggr logger.Logger, rootDir string, cf // Migrate the database if cfg.MigrateDatabase() { - if err = migrate.Migrate(db.DB, appLggr); err != nil { + if err = migrate.Migrate(ctx, db.DB, appLggr); err != nil { return fmt.Errorf("initializeORM#Migrate: %w", err) } } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 954cead5c3..70d75f761b 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -705,9 +705,17 @@ func (s *Shell) validateDB(c *cli.Context) error { return s.configExitErr(s.Config.ValidateDB) } +// ctx returns a context.Context that will be cancelled when SIGINT|SIGTERM is received +func (s *Shell) ctx() context.Context { + ctx, cancel := context.WithCancel(context.Background()) + go shutdown.HandleShutdown(func(_ string) { cancel() }) + return ctx +} + // ResetDatabase drops, creates and migrates the database specified by CL_DATABASE_URL or Database.URL // in secrets TOML. This is useful to set up the database for testing func (s *Shell) ResetDatabase(c *cli.Context) error { + ctx := s.ctx() cfg := s.Config.Database() parsed := cfg.URL() if parsed.String() == "" { @@ -727,7 +735,7 @@ func (s *Shell) ResetDatabase(c *cli.Context) error { return s.errorOut(err) } lggr.Debugf("Migrating database: %#v", parsed.String()) - if err := migrateDB(cfg, lggr); err != nil { + if err := migrateDB(ctx, cfg, lggr); err != nil { return s.errorOut(err) } schema, err := dumpSchema(parsed) @@ -736,7 +744,7 @@ func (s *Shell) ResetDatabase(c *cli.Context) error { } lggr.Debugf("Testing rollback and re-migrate for database: %#v", parsed.String()) var baseVersionID int64 = 54 - if err := downAndUpDB(cfg, lggr, baseVersionID); err != nil { + if err := downAndUpDB(ctx, cfg, lggr, baseVersionID); err != nil { return s.errorOut(err) } if err := checkSchema(parsed, schema); err != nil { @@ -828,6 +836,7 @@ func (s *Shell) PrepareTestDatabaseUserOnly(c *cli.Context) error { // MigrateDatabase migrates the database func (s *Shell) MigrateDatabase(_ *cli.Context) error { + ctx := s.ctx() cfg := s.Config.Database() parsed := cfg.URL() if parsed.String() == "" { @@ -840,7 +849,7 @@ func (s *Shell) MigrateDatabase(_ *cli.Context) error { } s.Logger.Infof("Migrating database: %#v", parsed.String()) - if err := migrateDB(cfg, s.Logger); err != nil { + if err := migrateDB(ctx, cfg, s.Logger); err != nil { return s.errorOut(err) } return nil @@ -848,6 +857,7 @@ func (s *Shell) MigrateDatabase(_ *cli.Context) error { // RollbackDatabase rolls back the database via down migrations. func (s *Shell) RollbackDatabase(c *cli.Context) error { + ctx := s.ctx() var version null.Int if c.Args().Present() { arg := c.Args().First() @@ -863,7 +873,7 @@ func (s *Shell) RollbackDatabase(c *cli.Context) error { return fmt.Errorf("failed to initialize orm: %v", err) } - if err := migrate.Rollback(db.DB, s.Logger, version); err != nil { + if err := migrate.Rollback(ctx, db.DB, s.Logger, version); err != nil { return fmt.Errorf("migrateDB failed: %v", err) } @@ -872,12 +882,13 @@ func (s *Shell) RollbackDatabase(c *cli.Context) error { // VersionDatabase displays the current database version. func (s *Shell) VersionDatabase(_ *cli.Context) error { + ctx := s.ctx() db, err := newConnection(s.Config.Database()) if err != nil { return fmt.Errorf("failed to initialize orm: %v", err) } - version, err := migrate.Current(db.DB, s.Logger) + version, err := migrate.Current(ctx, db.DB, s.Logger) if err != nil { return fmt.Errorf("migrateDB failed: %v", err) } @@ -888,12 +899,13 @@ func (s *Shell) VersionDatabase(_ *cli.Context) error { // StatusDatabase displays the database migration status func (s *Shell) StatusDatabase(_ *cli.Context) error { + ctx := s.ctx() db, err := newConnection(s.Config.Database()) if err != nil { return fmt.Errorf("failed to initialize orm: %v", err) } - if err = migrate.Status(db.DB, s.Logger); err != nil { + if err = migrate.Status(ctx, db.DB, s.Logger); err != nil { return fmt.Errorf("Status failed: %v", err) } return nil @@ -1017,27 +1029,27 @@ func dropAndCreatePristineDB(db *sqlx.DB, template string) (err error) { return nil } -func migrateDB(config dbConfig, lggr logger.Logger) error { +func migrateDB(ctx context.Context, config dbConfig, lggr logger.Logger) error { db, err := newConnection(config) if err != nil { return fmt.Errorf("failed to initialize orm: %v", err) } - if err = migrate.Migrate(db.DB, lggr); err != nil { + if err = migrate.Migrate(ctx, db.DB, lggr); err != nil { return fmt.Errorf("migrateDB failed: %v", err) } return db.Close() } -func downAndUpDB(cfg dbConfig, lggr logger.Logger, baseVersionID int64) error { +func downAndUpDB(ctx context.Context, cfg dbConfig, lggr logger.Logger, baseVersionID int64) error { db, err := newConnection(cfg) if err != nil { return fmt.Errorf("failed to initialize orm: %v", err) } - if err = migrate.Rollback(db.DB, lggr, null.IntFrom(baseVersionID)); err != nil { + if err = migrate.Rollback(ctx, db.DB, lggr, null.IntFrom(baseVersionID)); err != nil { return fmt.Errorf("test rollback failed: %v", err) } - if err = migrate.Migrate(db.DB, lggr); err != nil { + if err = migrate.Migrate(ctx, db.DB, lggr); err != nil { return fmt.Errorf("second migrateDB failed: %v", err) } return db.Close() diff --git a/core/store/migrate/migrate.go b/core/store/migrate/migrate.go index 1e58d7a0b0..04da4c48e9 100644 --- a/core/store/migrate/migrate.go +++ b/core/store/migrate/migrate.go @@ -36,22 +36,22 @@ func init() { } // Ensure we migrated from v1 migrations to goose_migrations -func ensureMigrated(db *sql.DB, lggr logger.Logger) { +func ensureMigrated(ctx context.Context, db *sql.DB, lggr logger.Logger) error { sqlxDB := pg.WrapDbWithSqlx(db) var names []string - err := sqlxDB.Select(&names, `SELECT id FROM migrations`) + err := sqlxDB.SelectContext(ctx, &names, `SELECT id FROM migrations`) if err != nil { // already migrated - return + return nil } - err = pg.SqlTransaction(context.Background(), db, lggr, func(tx *sqlx.Tx) error { + err = pg.SqlTransaction(ctx, db, lggr, func(tx *sqlx.Tx) error { // ensure that no legacy job specs are present: we _must_ bail out early if // so because otherwise we run the risk of dropping working jobs if the // user has not read the release notes return migrations.CheckNoLegacyJobs(tx.Tx) }) if err != nil { - panic(err) + return err } // Look for the squashed migration. If not present, the db needs to be migrated on an earlier release first @@ -62,18 +62,18 @@ func ensureMigrated(db *sql.DB, lggr logger.Logger) { } } if !found { - panic("Database state is too old. Need to migrate to chainlink version 0.9.10 first before upgrading to this version. This upgrade is NOT REVERSIBLE, so it is STRONGLY RECOMMENDED that you take a database backup before continuing.") + return errors.New("database state is too old. Need to migrate to chainlink version 0.9.10 first before upgrading to this version. This upgrade is NOT REVERSIBLE, so it is STRONGLY RECOMMENDED that you take a database backup before continuing") } // ensure a goose migrations table exists with it's initial v0 if _, err = goose.GetDBVersion(db); err != nil { - panic(err) + return err } // insert records for existing migrations //nolint sql := fmt.Sprintf(`INSERT INTO %s (version_id, is_applied) VALUES ($1, true);`, goose.TableName()) - err = pg.SqlTransaction(context.Background(), db, lggr, func(tx *sqlx.Tx) error { + return pg.SqlTransaction(ctx, db, lggr, func(tx *sqlx.Tx) error { for _, name := range names { var id int64 // the first migration doesn't follow the naming convention @@ -100,33 +100,38 @@ func ensureMigrated(db *sql.DB, lggr logger.Logger) { _, err = db.Exec("DROP TABLE migrations;") return err }) - if err != nil { - panic(err) - } } -func Migrate(db *sql.DB, lggr logger.Logger) error { - ensureMigrated(db, lggr) +func Migrate(ctx context.Context, db *sql.DB, lggr logger.Logger) error { + if err := ensureMigrated(ctx, db, lggr); err != nil { + return err + } // WithAllowMissing is necessary when upgrading from 0.10.14 since it // includes out-of-order migrations return goose.Up(db, MIGRATIONS_DIR, goose.WithAllowMissing()) } -func Rollback(db *sql.DB, lggr logger.Logger, version null.Int) error { - ensureMigrated(db, lggr) +func Rollback(ctx context.Context, db *sql.DB, lggr logger.Logger, version null.Int) error { + if err := ensureMigrated(ctx, db, lggr); err != nil { + return err + } if version.Valid { return goose.DownTo(db, MIGRATIONS_DIR, version.Int64) } return goose.Down(db, MIGRATIONS_DIR) } -func Current(db *sql.DB, lggr logger.Logger) (int64, error) { - ensureMigrated(db, lggr) +func Current(ctx context.Context, db *sql.DB, lggr logger.Logger) (int64, error) { + if err := ensureMigrated(ctx, db, lggr); err != nil { + return -1, err + } return goose.EnsureDBVersion(db) } -func Status(db *sql.DB, lggr logger.Logger) error { - ensureMigrated(db, lggr) +func Status(ctx context.Context, db *sql.DB, lggr logger.Logger) error { + if err := ensureMigrated(ctx, db, lggr); err != nil { + return err + } return goose.Status(db, MIGRATIONS_DIR) } diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index ef105c75ff..0ff0900016 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -391,25 +391,26 @@ func TestMigrate_101_GenericOCR2(t *testing.T) { } func TestMigrate(t *testing.T) { + ctx := testutils.Context(t) lggr := logger.TestLogger(t) _, db := heavyweight.FullTestDBEmptyV2(t, nil) err := goose.UpTo(db.DB, migrationDir, 100) require.NoError(t, err) - err = migrate.Status(db.DB, lggr) + err = migrate.Status(ctx, db.DB, lggr) require.NoError(t, err) - ver, err := migrate.Current(db.DB, lggr) + ver, err := migrate.Current(ctx, db.DB, lggr) require.NoError(t, err) require.Equal(t, int64(100), ver) - err = migrate.Migrate(db.DB, lggr) + err = migrate.Migrate(ctx, db.DB, lggr) require.NoError(t, err) - err = migrate.Rollback(db.DB, lggr, null.IntFrom(99)) + err = migrate.Rollback(ctx, db.DB, lggr, null.IntFrom(99)) require.NoError(t, err) - ver, err = migrate.Current(db.DB, lggr) + ver, err = migrate.Current(ctx, db.DB, lggr) require.NoError(t, err) require.Equal(t, int64(99), ver) } From 5fd94b0c36556dfa6b81153214f30a8c75ae0529 Mon Sep 17 00:00:00 2001 From: Cedric Date: Wed, 15 Nov 2023 13:38:05 +0000 Subject: [PATCH 153/327] [BCF-2788] Correctly unmarshal the plugin config (#11283) --- core/services/ocr2/delegate.go | 2 +- core/services/ocr2/validate/validate.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index bbb3b5cf7a..20c1351297 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -617,7 +617,7 @@ func (d *Delegate) newServicesGenericPlugin( Command: command, ProviderType: cconf.ProviderType, TelemetryType: cconf.TelemetryType, - PluginConfig: string(p.PluginConfig), + PluginConfig: p.PluginConfig, } pr := generic.NewPipelineRunnerAdapter(pluginLggr, jb, d.pipelineRunner) diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 78802f6559..65b95cb31a 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -134,7 +134,7 @@ type coreConfig struct { type OCR2GenericPluginConfig struct { CoreConfig coreConfig `json:"coreConfig"` - PluginConfig json.RawMessage + PluginConfig string } func validateOCR2GenericPluginSpec(jsonConfig job.JSONConfig) error { From 66d9e23219831c8ecd937431ead528dc0e9afcbb Mon Sep 17 00:00:00 2001 From: george-dorin <120329946+george-dorin@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:00:10 +0200 Subject: [PATCH 154/327] Test job creation and replacement (#9934) * Initial draft * - Add OCR, OCR2, Automation, VRF and cron tests * - Update keeper test * Fix merge * - Split functions into DeleteJobs and DeleteBridges * Use standardCleanup * Fix merge conflict * Update error style * Remove unused method --- .../actions/ocr2_helpers_local.go | 47 ++++++++ integration-tests/client/chainlink.go | 7 +- integration-tests/client/chainlink_models.go | 5 + integration-tests/smoke/cron_test.go | 71 +++++++++++ integration-tests/smoke/keeper_test.go | 66 +++++++++++ .../smoke/keeper_test.go_test_list.json | 3 + integration-tests/smoke/ocr2_test.go | 93 ++++++++++++++- integration-tests/smoke/ocr_test.go | 66 ++++++++++- integration-tests/smoke/vrf_test.go | 111 ++++++++++++++++++ 9 files changed, 463 insertions(+), 6 deletions(-) diff --git a/integration-tests/actions/ocr2_helpers_local.go b/integration-tests/actions/ocr2_helpers_local.go index 65e0a466be..e1b470bd0d 100644 --- a/integration-tests/actions/ocr2_helpers_local.go +++ b/integration-tests/actions/ocr2_helpers_local.go @@ -19,6 +19,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -273,3 +274,49 @@ func GetOracleIdentitiesWithKeyIndexLocal( return S, oracleIdentities, eg.Wait() } + +// DeleteJobs will delete ALL jobs from the nodes +func DeleteJobs(nodes []*client.ChainlinkClient) error { + for _, node := range nodes { + if node == nil { + return fmt.Errorf("found a nil chainlink node in the list of chainlink nodes while tearing down: %v", nodes) + } + jobs, _, err := node.ReadJobs() + if err != nil { + return fmt.Errorf("error reading jobs from chainlink node: %w", err) + } + for _, maps := range jobs.Data { + if _, ok := maps["id"]; !ok { + return fmt.Errorf("error reading job id from chainlink node's jobs %+v", jobs.Data) + } + id := maps["id"].(string) + _, err2 := node.DeleteJob(id) + if err2 != nil { + return fmt.Errorf("error deleting job from chainlink node: %w", err) + } + } + } + return nil +} + +// DeleteBridges will delete ALL bridges from the nodes +func DeleteBridges(nodes []*client.ChainlinkClient) error { + for _, node := range nodes { + if node == nil { + return fmt.Errorf("found a nil chainlink node in the list of chainlink nodes while tearing down: %v", nodes) + } + + bridges, _, err := node.ReadBridges() + if err != nil { + return err + } + for _, b := range bridges.Data { + _, err = node.DeleteBridge(b.Attributes.Name) + if err != nil { + return err + } + } + + } + return nil +} diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 7d5825c261..4603679ff8 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -5,12 +5,11 @@ import ( "fmt" "math/big" "net/http" + "os" "strings" "sync" "time" - "os" - "github.com/ethereum/go-ethereum/common" "github.com/go-resty/resty/v2" "github.com/rs/zerolog" @@ -303,8 +302,8 @@ func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, } // ReadBridges reads bridges from the Chainlink node -func (c *ChainlinkClient) ReadBridges() (*ResponseSlice, *resty.Response, error) { - result := &ResponseSlice{} +func (c *ChainlinkClient) ReadBridges() (*Bridges, *resty.Response, error) { + result := &Bridges{} c.l.Info().Str(NodeURL, c.Config.URL).Msg("Getting all bridges") resp, err := c.APIClient.R(). SetResult(&result). diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index c6d1209d2e..17a0a50845 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -107,6 +107,11 @@ type BridgeTypeData struct { Attributes BridgeTypeAttributes `json:"attributes"` } +// Bridges is the model that represents the bridges when read on a Chainlink node +type Bridges struct { + Data []BridgeTypeData `json:"data"` +} + // BridgeTypeAttributes is the model that represents the bridge when read or created on a Chainlink node type BridgeTypeAttributes struct { Name string `json:"name"` diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index e9d20f588e..013e4c631c 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -60,3 +60,74 @@ func TestCronBasic(t *testing.T) { } }, "2m", "3s").Should(gomega.Succeed()) } + +func TestCronJobReplacement(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithMockAdapter(). + WithCLNodes(1). + WithStandardCleanup(). + Build() + require.NoError(t, err) + + err = env.MockAdapter.SetAdapterBasedIntValuePath("/variable", []string{http.MethodGet, http.MethodPost}, 5) + require.NoError(t, err, "Setting value path in mockserver shouldn't fail") + + bta := &client.BridgeTypeAttributes{ + Name: fmt.Sprintf("variable-%s", uuid.NewString()), + URL: fmt.Sprintf("%s/variable", env.MockAdapter.InternalEndpoint), + RequestData: "{}", + } + err = env.ClCluster.Nodes[0].API.MustCreateBridge(bta) + require.NoError(t, err, "Creating bridge in chainlink node shouldn't fail") + + // CRON job creation and replacement + job, err := env.ClCluster.Nodes[0].API.MustCreateJob(&client.CronJobSpec{ + Schedule: "CRON_TZ=UTC * * * * * *", + ObservationSource: client.ObservationSourceSpecBridge(bta), + }) + require.NoError(t, err, "Creating Cron Job in chainlink node shouldn't fail") + + gom := gomega.NewWithT(t) + gom.Eventually(func(g gomega.Gomega) { + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) + if err != nil { + l.Info().Err(err).Msg("error while waiting for job runs") + } + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Reading Job run data shouldn't fail") + + g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 5), "Expected number of job runs to be greater than 5, but got %d", len(jobRuns.Data)) + + for _, jr := range jobRuns.Data { + g.Expect(jr.Attributes.Errors).Should(gomega.Equal([]interface{}{nil}), "Job run %s shouldn't have errors", jr.ID) + } + }, "3m", "3s").Should(gomega.Succeed()) + + err = env.ClCluster.Nodes[0].API.MustDeleteJob(job.Data.ID) + require.NoError(t, err) + + job, err = env.ClCluster.Nodes[0].API.MustCreateJob(&client.CronJobSpec{ + Schedule: "CRON_TZ=UTC * * * * * *", + ObservationSource: client.ObservationSourceSpecBridge(bta), + }) + require.NoError(t, err, "Recreating Cron Job in chainlink node shouldn't fail") + + gom.Eventually(func(g gomega.Gomega) { + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) + if err != nil { + l.Info().Err(err).Msg("error while waiting for job runs") + } + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Reading Job run data shouldn't fail") + + g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 5), "Expected number of job runs to be greater than 5, but got %d", len(jobRuns.Data)) + + for _, jr := range jobRuns.Data { + g.Expect(jr.Attributes.Errors).Should(gomega.Equal([]interface{}{nil}), "Job run %s shouldn't have errors", jr.ID) + } + }, "3m", "3s").Should(gomega.Succeed()) + +} diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index b28ab1ff10..29a819af13 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1126,3 +1126,69 @@ func setupKeeperTest(t *testing.T) ( return env.EVMClient, env.ClCluster.NodeAPIs(), env.ContractDeployer, linkTokenContract, env } + +func TestKeeperJobReplacement(t *testing.T) { + t.Parallel() + registryVersion := ethereum.RegistryVersion_1_3 + + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( + t, + registryVersion, + keeperDefaultRegistryConfig, + keeperDefaultUpkeepsToDeploy, + keeperDefaultUpkeepGasLimit, + linkToken, + contractDeployer, + chainClient, + big.NewInt(keeperDefaultLinkFunds), + ) + gom := gomega.NewGomegaWithT(t) + + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + require.NoError(t, err, "Error creating keeper jobs") + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error creating keeper jobs") + + gom.Eventually(func(g gomega.Gomega) error { + // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(utils.TestContext(t)) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), + "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) + l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Number of upkeeps performed") + } + return nil + }, "5m", "1s").Should(gomega.Succeed()) + + for _, n := range chainlinkNodes { + jobs, _, err := n.ReadJobs() + require.NoError(t, err) + for _, maps := range jobs.Data { + _, ok := maps["id"] + require.Equal(t, true, ok) + id := maps["id"].(string) + _, err := n.DeleteJob(id) + require.NoError(t, err) + } + } + + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + require.NoError(t, err, "Error creating keeper jobs") + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error creating keeper jobs") + + gom.Eventually(func(g gomega.Gomega) error { + // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(utils.TestContext(t)) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), + "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) + l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Number of upkeeps performed") + } + return nil + }, "5m", "1s").Should(gomega.Succeed()) +} diff --git a/integration-tests/smoke/keeper_test.go_test_list.json b/integration-tests/smoke/keeper_test.go_test_list.json index dfa2c49358..b874bc65ee 100644 --- a/integration-tests/smoke/keeper_test.go_test_list.json +++ b/integration-tests/smoke/keeper_test.go_test_list.json @@ -53,6 +53,9 @@ }, { "name": "TestKeeperUpdateCheckData" + }, + { + "name": "TestKeeperJobReplacement" } ] } diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 5950e9febb..bec82e633f 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -92,3 +91,95 @@ func TestOCRv2Basic(t *testing.T) { roundData.Answer.Int64(), ) } + +func TestOCRv2JobReplacement(t *testing.T) { + l := logging.GetTestLogger(t) + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithMockAdapter(). + WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), + node.WithOCR2(), + node.WithP2Pv2(), + node.WithTracing(), + )). + WithCLNodes(6). + WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). + Build() + require.NoError(t, err) + + env.ParallelTransactions(true) + + nodeClients := env.ClCluster.NodeAPIs() + bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] + + linkToken, err := env.ContractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + + err = actions.FundChainlinkNodesLocal(workerNodes, env.EVMClient, big.NewFloat(.05)) + require.NoError(t, err, "Error funding Chainlink nodes") + + // Gather transmitters + var transmitters []string + for _, node := range workerNodes { + addr, err := node.PrimaryEthAddress() + if err != nil { + require.NoError(t, fmt.Errorf("error getting node's primary ETH address: %w", err)) + } + transmitters = append(transmitters, addr) + } + + ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() + aggregatorContracts, err := actions.DeployOCRv2Contracts(1, linkToken, env.ContractDeployer, transmitters, env.EVMClient, ocrOffchainOptions) + require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") + + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) + require.NoError(t, err, "Error creating OCRv2 jobs") + + ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) + require.NoError(t, err, "Error building OCRv2 config") + + err = actions.ConfigureOCRv2AggregatorContracts(env.EVMClient, ocrv2Config, aggregatorContracts) + require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") + + err = actions.StartNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) + require.NoError(t, err, "Error starting new OCR2 round") + roundData, err := aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(1)) + require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") + require.Equal(t, int64(5), roundData.Answer.Int64(), + "Expected latest answer from OCR contract to be 5 but got %d", + roundData.Answer.Int64(), + ) + + err = env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) + require.NoError(t, err) + err = actions.StartNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) + require.NoError(t, err) + + roundData, err = aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(2)) + require.NoError(t, err, "Error getting latest OCR answer") + require.Equal(t, int64(10), roundData.Answer.Int64(), + "Expected latest answer from OCR contract to be 10 but got %d", + roundData.Answer.Int64(), + ) + + err = actions.DeleteJobs(nodeClients) + require.NoError(t, err) + + err = actions.DeleteBridges(nodeClients) + require.NoError(t, err) + + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, env.EVMClient.GetChainID().Uint64(), false) + require.NoError(t, err, "Error creating OCRv2 jobs") + + err = actions.StartNewOCR2Round(3, aggregatorContracts, env.EVMClient, time.Minute*3, l) + require.NoError(t, err, "Error starting new OCR2 round") + roundData, err = aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(3)) + require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") + require.Equal(t, int64(15), roundData.Answer.Int64(), + "Expected latest answer from OCR contract to be 15 but got %d", + roundData.Answer.Int64(), + ) +} diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 45205565e2..8fbc1109e2 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/utils" @@ -59,3 +58,68 @@ func TestOCRBasic(t *testing.T) { require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } + +func TestOCRJobReplacement(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithMockAdapter(). + WithCLNodes(6). + WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). + Build() + require.NoError(t, err) + + env.ParallelTransactions(true) + + nodeClients := env.ClCluster.NodeAPIs() + bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] + + linkTokenContract, err := env.ContractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + + ocrInstances, err := actions.DeployOCRContractsLocal(1, linkTokenContract, env.ContractDeployer, workerNodes, env.EVMClient) + require.NoError(t, err) + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, "Error waiting for events") + + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) + require.NoError(t, err) + + err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + require.NoError(t, err) + + answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") + require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) + + err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) + require.NoError(t, err) + err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) + require.NoError(t, err) + + answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + require.NoError(t, err, "Error getting latest OCR answer") + require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) + + err = actions.DeleteJobs(nodeClients) + require.NoError(t, err) + + err = actions.DeleteBridges(nodeClients) + require.NoError(t, err) + + //Recreate job + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) + require.NoError(t, err) + + err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + require.NoError(t, err) + + answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") + require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) + +} diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 61d2c5cdd7..e477d45926 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -107,3 +107,114 @@ func TestVRFBasic(t *testing.T) { }, timeout, "1s").Should(gomega.Succeed()) } } + +func TestVRFJobReplacement(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithCLNodes(1). + WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). + Build() + require.NoError(t, err) + env.ParallelTransactions(true) + + lt, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + contracts, err := vrfv1.DeployVRFContracts(env.ContractDeployer, env.EVMClient, lt) + require.NoError(t, err, "Deploying VRF Contracts shouldn't fail") + + err = lt.Transfer(contracts.Consumer.Address(), big.NewInt(2e18)) + require.NoError(t, err, "Funding consumer contract shouldn't fail") + _, err = env.ContractDeployer.DeployVRFContract() + require.NoError(t, err, "Deploying VRF contract shouldn't fail") + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") + + for _, n := range env.ClCluster.Nodes { + nodeKey, err := n.API.MustCreateVRFKey() + require.NoError(t, err, "Creating VRF key shouldn't fail") + l.Debug().Interface("Key JSON", nodeKey).Msg("Created proving key") + pubKeyCompressed := nodeKey.Data.ID + jobUUID := uuid.New() + os := &client.VRFTxPipelineSpec{ + Address: contracts.Coordinator.Address(), + } + ost, err := os.String() + require.NoError(t, err, "Building observation source spec shouldn't fail") + job, err := n.API.MustCreateJob(&client.VRFJobSpec{ + Name: fmt.Sprintf("vrf-%s", jobUUID), + CoordinatorAddress: contracts.Coordinator.Address(), + MinIncomingConfirmations: 1, + PublicKey: pubKeyCompressed, + ExternalJobID: jobUUID.String(), + EVMChainID: env.EVMClient.GetChainID().String(), + ObservationSource: ost, + }) + require.NoError(t, err, "Creating VRF Job shouldn't fail") + + oracleAddr, err := n.API.PrimaryEthAddress() + require.NoError(t, err, "Getting primary ETH address of chainlink node shouldn't fail") + provingKey, err := actions.EncodeOnChainVRFProvingKey(*nodeKey) + require.NoError(t, err, "Encoding on-chain VRF Proving key shouldn't fail") + err = contracts.Coordinator.RegisterProvingKey( + big.NewInt(1), + oracleAddr, + provingKey, + actions.EncodeOnChainExternalJobID(jobUUID), + ) + require.NoError(t, err, "Registering the on-chain VRF Proving key shouldn't fail") + encodedProvingKeys := make([][2]*big.Int, 0) + encodedProvingKeys = append(encodedProvingKeys, provingKey) + + requestHash, err := contracts.Coordinator.HashOfKey(utils.TestContext(t), encodedProvingKeys[0]) + require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") + err = contracts.Consumer.RequestRandomness(requestHash, big.NewInt(1)) + require.NoError(t, err, "Requesting randomness shouldn't fail") + + gom := gomega.NewGomegaWithT(t) + timeout := time.Minute * 2 + gom.Eventually(func(g gomega.Gomega) { + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") + + out, err := contracts.Consumer.RandomnessOutput(utils.TestContext(t)) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") + // Checks that the job has actually run + g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), + fmt.Sprintf("Expected the VRF job to run once or more after %s", timeout)) + + g.Expect(out.Uint64()).ShouldNot(gomega.BeNumerically("==", 0), "Expected the VRF job give an answer other than 0") + l.Debug().Uint64("Output", out.Uint64()).Msg("Randomness fulfilled") + }, timeout, "1s").Should(gomega.Succeed()) + + err = n.API.MustDeleteJob(job.Data.ID) + require.NoError(t, err) + + job, err = n.API.MustCreateJob(&client.VRFJobSpec{ + Name: fmt.Sprintf("vrf-%s", jobUUID), + CoordinatorAddress: contracts.Coordinator.Address(), + MinIncomingConfirmations: 1, + PublicKey: pubKeyCompressed, + ExternalJobID: jobUUID.String(), + EVMChainID: env.EVMClient.GetChainID().String(), + ObservationSource: ost, + }) + require.NoError(t, err, "Recreating VRF Job shouldn't fail") + gom.Eventually(func(g gomega.Gomega) { + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") + + out, err := contracts.Consumer.RandomnessOutput(utils.TestContext(t)) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") + // Checks that the job has actually run + g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), + fmt.Sprintf("Expected the VRF job to run once or more after %s", timeout)) + g.Expect(out.Uint64()).ShouldNot(gomega.BeNumerically("==", 0), "Expected the VRF job give an answer other than 0") + l.Debug().Uint64("Output", out.Uint64()).Msg("Randomness fulfilled") + }, timeout, "1s").Should(gomega.Succeed()) + } +} From a75f900e0536f3eb9282284ac5cfec57206a3ec6 Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 15 Nov 2023 14:04:05 -0700 Subject: [PATCH 155/327] [TT-707] Add chainlink image build to test image publish for workflow dispatch (#11304) This allows teams to run this one dispatch and not have to make a work in progress PR before they start testing. --- .../workflows/integration-tests-publish.yml | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index 9579b83b98..9eb2673db2 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -7,9 +7,6 @@ on: - develop workflow_dispatch: inputs: - chainlink-tests-tag: - description: 'The tag to be pushed' - required: true ctf-base-image-tag: description: | 'The tag of the CTF base image to be used, @@ -18,7 +15,8 @@ on: required: true env: - ECR_TAG_BASE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests + ECR_TAG: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:develop + CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink jobs: publish-integration-test-image: @@ -41,19 +39,71 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Setup Other Tags + id: tags + env: + BASE_IMAGE_TAG: ${{ inputs.ctf-base-image-tag}} + run: | + if [ -z "${BASE_IMAGE_TAG+x}" ]; then + echo "ctf-base-image-tag is not set, we are part of a merge and want to push the develop tag" + echo "other_tags=${ECR_TAG}" >> $GITHUB_OUTPUT + fi - name: Build Image uses: ./.github/actions/build-test-image with: - other_tags: "${{ env.ECR_TAG_BASE }}:${{ inputs.chainlink-tests-tag || 'develop' }}" + other_tags: ${{ steps.tags.outputs.other_tags }} base_image_tag: ${{ inputs.ctf-base-image-tag }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - name: Notify Slack - if: failure() + # Only run this notification for merge to develop failures + if: failure() && github.event_name != 'workflow_dispatch' uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} with: channel-id: "#team-test-tooling-internal" slack-message: ":x: :mild-panic-intensifies: Publish Integration Test Image failed: ${{ job.html_url }}\n${{ format('https://github.com/smartcontractkit/chainlink/actions/runs/{0}', github.run_id) }}" + build-chainlink-image: + environment: integration + # Only run this build for workflow_dispatch + if: ${{ inputs.ctf-base-image-tag != '' }} + permissions: + id-token: write + contents: read + strategy: + matrix: + image: + - name: "" + dockerfile: core/chainlink.Dockerfile + tag-suffix: "" + # uncomment in the future if we end up needing to soak test the plugins image + # - name: (plugins) + # dockerfile: plugins/chainlink.Dockerfile + # tag-suffix: -plugins + name: Build Chainlink Image ${{ matrix.image.name }} + runs-on: ubuntu20.04-8cores-32GB + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Build Chainlink Image ${{ matrix.image.name }} + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.sha }} + - name: Build Chainlink Image + uses: ./.github/actions/build-chainlink-image + with: + tag_suffix: ${{ matrix.image.tag-suffix }} + dockerfile: ${{ matrix.image.dockerfile }} + git_commit_sha: ${{ github.sha }} + GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} + AWS_REGION: ${{ secrets.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} From 2a947ccf50536601a0032650920056d7d68a0421 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Wed, 15 Nov 2023 19:17:44 -0500 Subject: [PATCH 156/327] [Functions] (test): Add Functions HasUniqueGlobalRequestId foundry test (#11306) * (test): Add Functions HasUniqueGlobalRequestId foundry test * Regenerate gas snapshot --- .../gas-snapshots/functions.gas-snapshot | 35 ++++++++-------- .../v0.8/functions/tests/v1_X/BaseTest.t.sol | 2 +- .../tests/v1_X/FunctionsBilling.t.sol | 40 +++++++++++++++++-- .../src/v0.8/functions/tests/v1_X/Setup.t.sol | 5 ++- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 82b5b494a7..4e6cf83cd1 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: 14577815) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14577793) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14577809) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14589229) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14589206) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14589178) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14589129) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14589118) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14589162) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14578318) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14578296) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14578312) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14589732) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14589709) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14589681) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14589632) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14589621) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14589665) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -28,6 +28,7 @@ FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 38251) FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8810) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13302) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 180763) +FunctionsBilling__StartBilling:test__FulfillAndBill_HasUniqueGlobalRequestId() (gas: 398312) FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 497786) FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 198990) @@ -51,17 +52,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: 167459) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 157790) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 167477) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 157808) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38115) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 175935) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 175953) FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28086) -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_Fulfill:test_Fulfill_RevertIfPaused() (gas: 151496) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 321059) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 334680) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2509962) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 540441) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159) diff --git a/contracts/src/v0.8/functions/tests/v1_X/BaseTest.t.sol b/contracts/src/v0.8/functions/tests/v1_X/BaseTest.t.sol index b012732897..ffa684e84c 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/BaseTest.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/BaseTest.t.sol @@ -19,7 +19,7 @@ contract BaseTest is Test { // BaseTest.setUp is often called multiple times from tests' setUp due to inheritance. if (s_baseTestInitialized) return; s_baseTestInitialized = true; - // Set msg.sender to OWNER until stopPrank is called + // Set msg.sender and tx.origin to OWNER until stopPrank is called vm.startPrank(OWNER_ADDRESS, OWNER_ADDRESS); } } 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 6e94e4fc5f..739521c530 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 @@ -8,7 +8,7 @@ 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"; -import {FunctionsRouterSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; +import {FunctionsRouterSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsFulfillmentSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; /// @notice #constructor contract FunctionsBilling_Constructor is FunctionsSubscriptionSetup { @@ -217,8 +217,42 @@ contract FunctionsBilling__CalculateCostEstimate { } /// @notice #_startBilling -contract FunctionsBilling__StartBilling { - // TODO: make contract internal function helper +contract FunctionsBilling__StartBilling is FunctionsFulfillmentSetup { + function test__FulfillAndBill_HasUniqueGlobalRequestId() public { + // Variables that go into a requestId: + // - Coordinator address + // - Consumer contract + // - Subscription ID, + // - Consumer initiated requests + // - Request data + // - Request data version + // - Request callback gas limit + // - Estimated total cost in Juels + // - Request timeout timestamp + // - tx.origin + + // Request #1 has already been fulfilled by the test setup + + // Reset the nonce (initiatedRequests) by removing and re-adding the consumer + s_functionsRouter.removeConsumer(s_subscriptionId, address(s_functionsClient)); + assertEq(s_functionsRouter.getSubscription(s_subscriptionId).consumers.length, 0); + s_functionsRouter.addConsumer(s_subscriptionId, address(s_functionsClient)); + assertEq(s_functionsRouter.getSubscription(s_subscriptionId).consumers[0], address(s_functionsClient)); + + // Make Request #2 + _sendAndStoreRequest( + 2, + s_requests[1].requestData.sourceCode, + s_requests[1].requestData.secrets, + s_requests[1].requestData.args, + s_requests[1].requestData.bytesArgs, + s_requests[1].requestData.callbackGasLimit + ); + + // Request #1 and #2 should have different request IDs, because the request timeout timestamp has advanced. + // A request cannot be fulfilled in the same block, which prevents removing a consumer in the same block + assertNotEq(s_requests[1].requestId, s_requests[2].requestId); + } } /// @notice #_fulfillAndBill 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 97418958bc..41ee663e8b 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 @@ -525,7 +525,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { // Return prank to Owner vm.stopPrank(); - vm.startPrank(OWNER_ADDRESS); + vm.startPrank(OWNER_ADDRESS, OWNER_ADDRESS); } /// @notice Provide a response from the DON to fulfill one or more requests and store the updated balances of the DON & Admin @@ -604,6 +604,9 @@ contract FunctionsFulfillmentSetup is FunctionsClientRequestSetup { function setUp() public virtual override { FunctionsClientRequestSetup.setUp(); + // Fast forward time by 30 seconds to simulate the DON executing the computation + vm.warp(block.timestamp + 30); + // Fulfill request 1 uint256[] memory requestNumberKeys = new uint256[](1); requestNumberKeys[0] = 1; From b012cc426d0ec5515b7c40a10d5924734df760a8 Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Wed, 15 Nov 2023 23:20:24 -0800 Subject: [PATCH 157/327] [Functions] Require minimum balance only for secrets_set, not for list (#11309) Additionally refactor a helper method in connector_handler.go. --- core/services/functions/connector_handler.go | 41 ++++++++----------- .../functions/connector_handler_test.go | 3 -- .../handlers/functions/handler.functions.go | 2 +- .../functions/handler.functions_test.go | 3 +- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 8a8710e6ea..c5dbff6f10 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -76,24 +76,21 @@ func (h *functionsConnectorHandler) HandleGatewayMessage(ctx context.Context, ga h.lggr.Errorw("request rate-limited", "id", gatewayId, "address", fromAddr) return } - if balance, err := h.subscriptions.GetMaxUserBalance(fromAddr); err != nil || balance.Cmp(h.minimumBalance.ToInt()) < 0 { - h.lggr.Errorw("user subscription has insufficient balance", "id", gatewayId, "address", fromAddr, "balance", balance, "minBalance", h.minimumBalance) - response := functions.SecretsResponseBase{ - Success: false, - ErrorMessage: "user subscription has insufficient balance", - } - if err := h.sendResponse(ctx, gatewayId, body, response); err != nil { - h.lggr.Errorw("failed to send response to gateway", "id", gatewayId, "error", err) - } - return - } - h.lggr.Debugw("handling gateway request", "id", gatewayId, "method", body.Method) switch body.Method { case functions.MethodSecretsList: h.handleSecretsList(ctx, gatewayId, body, fromAddr) case functions.MethodSecretsSet: + if balance, err := h.subscriptions.GetMaxUserBalance(fromAddr); err != nil || balance.Cmp(h.minimumBalance.ToInt()) < 0 { + h.lggr.Errorw("user subscription has insufficient balance", "id", gatewayId, "address", fromAddr, "balance", balance, "minBalance", h.minimumBalance) + response := functions.SecretsResponseBase{ + Success: false, + ErrorMessage: "user subscription has insufficient balance", + } + h.sendResponseAndLog(ctx, gatewayId, body, response) + return + } h.handleSecretsSet(ctx, gatewayId, body, fromAddr) default: h.lggr.Errorw("unsupported method", "id", gatewayId, "method", body.Method) @@ -133,10 +130,7 @@ func (h *functionsConnectorHandler) handleSecretsList(ctx context.Context, gatew } else { response.ErrorMessage = fmt.Sprintf("Failed to list secrets: %v", err) } - - if err := h.sendResponse(ctx, gatewayId, body, response); err != nil { - h.lggr.Errorw("failed to send response to gateway", "id", gatewayId, "error", err) - } + h.sendResponseAndLog(ctx, gatewayId, body, response) } func (h *functionsConnectorHandler) handleSecretsSet(ctx context.Context, gatewayId string, body *api.MessageBody, fromAddr ethCommon.Address) { @@ -163,9 +157,15 @@ func (h *functionsConnectorHandler) handleSecretsSet(ctx context.Context, gatewa } else { response.ErrorMessage = fmt.Sprintf("Bad request to set secret: %v", err) } + h.sendResponseAndLog(ctx, gatewayId, body, response) +} - if err := h.sendResponse(ctx, gatewayId, body, response); err != nil { +func (h *functionsConnectorHandler) sendResponseAndLog(ctx context.Context, gatewayId string, requestBody *api.MessageBody, payload any) { + err := h.sendResponse(ctx, gatewayId, requestBody, payload) + if err != nil { h.lggr.Errorw("failed to send response to gateway", "id", gatewayId, "error", err) + } else { + h.lggr.Debugw("sent to gateway", "id", gatewayId, "messageId", requestBody.MessageId, "donId", requestBody.DonId, "method", requestBody.Method) } } @@ -187,10 +187,5 @@ func (h *functionsConnectorHandler) sendResponse(ctx context.Context, gatewayId if err = msg.Sign(h.signerKey); err != nil { return err } - - err = h.connector.SendToGateway(ctx, gatewayId, msg) - if err == nil { - h.lggr.Debugw("sent to gateway", "id", gatewayId, "messageId", requestBody.MessageId, "donId", requestBody.DonId, "method", requestBody.Method) - } - return err + return h.connector.SendToGateway(ctx, gatewayId, msg) } diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index 7bf98d7501..fa9f74712b 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -78,7 +78,6 @@ func TestFunctionsConnectorHandler(t *testing.T) { } storage.On("List", ctx, addr).Return(snapshot, nil).Once() allowlist.On("Allow", addr).Return(true).Once() - subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -91,7 +90,6 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("orm error", func(t *testing.T) { storage.On("List", ctx, addr).Return(nil, errors.New("boom")).Once() allowlist.On("Allow", addr).Return(true).Once() - subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() connector.On("SendToGateway", ctx, "gw1", mock.Anything).Run(func(args mock.Arguments) { msg, ok := args[2].(*api.Message) require.True(t, ok) @@ -218,7 +216,6 @@ func TestFunctionsConnectorHandler(t *testing.T) { require.NoError(t, msg.Sign(privateKey)) allowlist.On("Allow", addr).Return(true).Once() - subscriptions.On("GetMaxUserBalance", mock.Anything).Return(big.NewInt(100), nil).Once() handler.HandleGatewayMessage(testutils.Context(t), "gw1", &msg) }) }) diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index d0011145d4..bb6812c1f9 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -178,7 +178,7 @@ func (h *functionsHandler) HandleUserMessage(ctx context.Context, msg *api.Messa promHandlerError.WithLabelValues(h.donConfig.DonId, ErrRateLimited.Error()).Inc() return ErrRateLimited } - if h.subscriptions != nil && h.minimumBalance != nil { + if msg.Body.Method == MethodSecretsSet && h.subscriptions != nil && h.minimumBalance != nil { balance, err := h.subscriptions.GetMaxUserBalance(sender) if err != nil { h.lggr.Debugw("error getting max user balance", "sender", msg.Body.Sender, "err", err) diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index 1446bc8457..49fdae2bb2 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -148,11 +148,10 @@ func TestFunctionsHandler_HandleUserMessage_InvalidMethod(t *testing.T) { t.Parallel() nodes, user := gc.NewTestNodes(t, 4), gc.NewTestNodes(t, 1)[0] - handler, _, allowlist, subscriptions := newFunctionsHandlerForATestDON(t, nodes, time.Hour*24) + handler, _, allowlist, _ := newFunctionsHandlerForATestDON(t, nodes, time.Hour*24) userRequestMsg := newSignedMessage(t, "1234", "secrets_reveal_all_please", "don_id", user.PrivateKey) allowlist.On("Allow", common.HexToAddress(user.Address)).Return(true, nil) - subscriptions.On("GetMaxUserBalance", common.HexToAddress(user.Address)).Return(big.NewInt(1000), nil) err := handler.HandleUserMessage(testutils.Context(t), &userRequestMsg, make(chan handlers.UserCallbackPayload)) require.Error(t, err) } From bd5a35b661caed4a4ce1afe8d275d41acc372c76 Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 16 Nov 2023 10:41:45 +0000 Subject: [PATCH 158/327] [BCF-2738] Modify build-publish-develop ECR (#11279) - push images to chainlink-develop in production rather than chainlink in the sdlc environment. --- .github/workflows/build-publish-develop.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index b885972237..a7220deec4 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -47,9 +47,9 @@ jobs: publish: true aws-role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }} aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} - aws-region: ${{ secrets.AWS_REGION }} - ecr-hostname: ${{ secrets.AWS_DEVELOP_ECR_HOSTNAME }} - ecr-image-name: chainlink + aws-region: us-west-2 + ecr-hostname: 804282218731.dkr.ecr.us-west-2.com + ecr-image-name: chainlink-develop/chainlink ecr-tag-suffix: ${{ matrix.image.tag-suffix }} dockerfile: ${{ matrix.image.dockerfile }} dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} From af2f91996db2a67f69f7c2582e69e1b5e6493d4d Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 16 Nov 2023 11:05:47 +0000 Subject: [PATCH 159/327] Revert "[BCF-2738] Modify build-publish-develop ECR (#11279)" (#11310) This reverts commit bd5a35b661caed4a4ce1afe8d275d41acc372c76. --- .github/workflows/build-publish-develop.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index a7220deec4..b885972237 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -47,9 +47,9 @@ jobs: publish: true aws-role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }} aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} - aws-region: us-west-2 - ecr-hostname: 804282218731.dkr.ecr.us-west-2.com - ecr-image-name: chainlink-develop/chainlink + aws-region: ${{ secrets.AWS_REGION }} + ecr-hostname: ${{ secrets.AWS_DEVELOP_ECR_HOSTNAME }} + ecr-image-name: chainlink ecr-tag-suffix: ${{ matrix.image.tag-suffix }} dockerfile: ${{ matrix.image.dockerfile }} dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} From 26e5e3740c8629c01c330e15c9fc35f55ca841ca Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Thu, 16 Nov 2023 17:15:56 +0200 Subject: [PATCH 160/327] Extract Link and move Eth to evm folder (#11287) * Extract Link and move Eth to evm folder * Move ChainType to common folder * Fix lint * Fix currency relay imports * Fix relay import dependency * Fix lint * Address comments --- common/client/mock_rpc_test.go | 2 +- common/client/multi_node.go | 4 +- common/client/multi_node_test.go | 2 +- common/client/types.go | 2 +- {core => common}/config/chaintype.go | 0 core/assets/currencies.go | 301 --------------- core/assets/currencies_test.go | 357 ------------------ core/bridges/bridge_type.go | 2 +- core/bridges/bridge_type_test.go | 2 +- core/chains/evm/assets/assets.go | 117 ++++++ core/chains/evm/assets/assets_test.go | 116 ++++++ core/{ => chains/evm}/assets/units.go | 0 core/{ => chains/evm}/assets/units_test.go | 2 +- core/{ => chains/evm}/assets/wei.go | 0 core/{ => chains/evm}/assets/wei_test.go | 0 core/chains/evm/chain.go | 3 +- core/chains/evm/client/chain_client.go | 7 +- core/chains/evm/client/client.go | 4 +- core/chains/evm/client/helpers_test.go | 2 +- core/chains/evm/client/mocks/client.go | 2 +- core/chains/evm/client/null_client.go | 2 +- core/chains/evm/client/pool.go | 2 +- core/chains/evm/client/rpc_client.go | 9 +- core/chains/evm/client/send_only_node_test.go | 2 +- .../evm/client/simulated_backend_client.go | 2 +- core/chains/evm/config/chain_scoped.go | 13 +- .../evm/config/chain_scoped_gas_estimator.go | 2 +- core/chains/evm/config/config.go | 8 +- core/chains/evm/config/config_test.go | 7 +- core/chains/evm/config/mocks/gas_estimator.go | 2 +- core/chains/evm/config/toml/config.go | 7 +- core/chains/evm/config/toml/defaults.go | 2 +- core/chains/evm/gas/arbitrum_estimator.go | 2 +- .../chains/evm/gas/arbitrum_estimator_test.go | 2 +- .../chains/evm/gas/block_history_estimator.go | 4 +- .../evm/gas/block_history_estimator_test.go | 4 +- core/chains/evm/gas/chain_specific.go | 4 +- core/chains/evm/gas/cmd/arbgas/main.go | 2 +- core/chains/evm/gas/fixed_price_estimator.go | 2 +- .../evm/gas/fixed_price_estimator_test.go | 2 +- core/chains/evm/gas/gas_test.go | 2 +- core/chains/evm/gas/helpers_test.go | 4 +- core/chains/evm/gas/mocks/config.go | 2 +- core/chains/evm/gas/mocks/evm_estimator.go | 2 +- .../chains/evm/gas/mocks/evm_fee_estimator.go | 2 +- core/chains/evm/gas/models.go | 4 +- core/chains/evm/gas/models_test.go | 2 +- .../evm/gas/rollups/l1_gas_price_oracle.go | 4 +- .../gas/rollups/l1_gas_price_oracle_test.go | 4 +- .../chains/evm/gas/rollups/mocks/l1_oracle.go | 2 +- core/chains/evm/gas/rollups/models.go | 2 +- .../evm/gas/suggested_price_estimator.go | 2 +- .../evm/gas/suggested_price_estimator_test.go | 2 +- core/chains/evm/mocks/balance_monitor.go | 2 +- core/chains/evm/monitor/balance.go | 2 +- core/chains/evm/monitor/balance_test.go | 2 +- core/chains/evm/txmgr/attempts.go | 2 +- core/chains/evm/txmgr/attempts_test.go | 2 +- core/chains/evm/txmgr/broadcaster_test.go | 2 +- core/chains/evm/txmgr/config.go | 6 +- core/chains/evm/txmgr/confirmer_test.go | 2 +- core/chains/evm/txmgr/evm_tx_store.go | 2 +- core/chains/evm/txmgr/evm_tx_store_test.go | 2 +- core/chains/evm/txmgr/mocks/config.go | 2 +- core/chains/evm/txmgr/test_helpers.go | 15 +- core/chains/evm/txmgr/transmitchecker_test.go | 2 +- core/chains/evm/txmgr/txmgr_test.go | 2 +- .../evm/types/block_json_benchmark_test.go | 2 +- core/chains/evm/types/models.go | 2 +- core/chains/evm/types/models_test.go | 2 +- core/cmd/cosmos_node_commands_test.go | 4 +- core/cmd/eth_keys_commands_test.go | 13 +- core/cmd/evm_transaction_commands.go | 2 +- core/cmd/evm_transaction_commands_test.go | 2 +- core/cmd/shell_local.go | 2 +- core/cmd/solana_node_commands_test.go | 6 +- core/cmd/starknet_node_commands_test.go | 6 +- core/config/docs/docs_test.go | 2 +- core/config/parse/parsers.go | 9 +- core/internal/cltest/cltest.go | 2 +- core/internal/cltest/factories.go | 2 +- core/internal/features/features_test.go | 2 +- .../features/ocr2/features_ocr2_test.go | 2 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/scripts/ocr2vrf/main.go | 2 +- core/scripts/vrfv2/testnet/main.go | 2 +- core/scripts/vrfv2plus/testnet/main.go | 2 +- core/services/chainlink/config_test.go | 71 ++-- .../relayer_chain_interoperators_test.go | 18 +- core/services/directrequest/delegate.go | 2 +- core/services/directrequest/delegate_test.go | 2 +- core/services/directrequest/validate.go | 2 +- core/services/fluxmonitorv2/config.go | 2 +- .../fluxmonitorv2/flux_monitor_test.go | 2 +- .../fluxmonitorv2/integrations_test.go | 2 +- .../services/fluxmonitorv2/payment_checker.go | 2 +- .../fluxmonitorv2/payment_checker_test.go | 2 +- core/services/fluxmonitorv2/validate_test.go | 2 +- core/services/functions/connector_handler.go | 2 +- .../functions/connector_handler_test.go | 2 +- .../handlers/functions/handler.functions.go | 2 +- .../functions/handler.functions_test.go | 2 +- core/services/job/job_orm_test.go | 2 +- core/services/job/models.go | 7 +- core/services/keeper/integration_test.go | 2 +- core/services/keeper/upkeep_executer.go | 2 +- core/services/keeper/upkeep_executer_test.go | 2 +- .../keeper/upkeep_executer_unit_test.go | 2 +- core/services/keystore/keys/ethkey/address.go | 4 +- core/services/ocr/contract_tracker.go | 2 +- core/services/ocr/validate.go | 2 +- .../ocr2/plugins/functions/config/config.go | 2 +- .../v1/internal/testutils.go | 2 +- .../services/ocr2/plugins/functions/plugin.go | 2 +- .../ocr2/plugins/functions/plugin_test.go | 2 +- .../ocr2/plugins/mercury/integration_test.go | 2 +- .../evm21/logprovider/integration_test.go | 2 +- .../plugins/ocr2keeper/integration_21_test.go | 2 +- .../plugins/ocr2keeper/integration_test.go | 2 +- .../internal/ocr2vrf_integration_test.go | 2 +- .../reasonable_gas_price_provider.go | 2 +- .../reasonable_gas_price_test.go | 2 +- core/services/ocrcommon/block_translator.go | 2 +- core/services/ocrcommon/config.go | 2 +- .../relay/evm/mercury/v1/data_source_test.go | 2 +- .../services/transmission/integration_test.go | 2 +- core/services/vrf/delegate.go | 2 +- core/services/vrf/delegate_test.go | 2 +- core/services/vrf/mocks/fee_config.go | 2 +- .../services/vrf/proof/proof_response_test.go | 2 +- .../vrf_coordinator_interface.go | 2 +- .../vrf_coordinator_interface_test.go | 7 +- .../vrf_hash_to_curve_cost_test.go | 2 +- .../vrf_solidity_crosscheck_test.go | 2 +- .../vrf_v08_solidity_crosscheck_test.go | 2 +- core/services/vrf/v2/bhs_feeder_test.go | 2 +- .../vrf/v2/integration_helpers_test.go | 2 +- .../vrf/v2/integration_v2_plus_test.go | 2 +- core/services/vrf/v2/integration_v2_test.go | 5 +- core/services/vrf/v2/listener_v2.go | 2 +- .../vrf/v2/listener_v2_helpers_test.go | 2 +- core/services/vrf/vrfcommon/types.go | 2 +- core/services/vrf/vrfcommon/validate.go | 2 +- core/services/vrf/vrfcommon/validate_test.go | 2 +- core/services/vrf/vrftesthelpers/helpers.go | 2 +- core/store/models/common.go | 2 +- core/testdata/testspecs/v2_specs.go | 2 +- core/utils/big.go | 3 +- core/utils/utils.go | 16 - core/web/bridge_types_controller.go | 2 +- core/web/bridge_types_controller_test.go | 2 +- core/web/eth_keys_controller.go | 9 +- core/web/eth_keys_controller_test.go | 2 +- core/web/evm_transactions_controller_test.go | 2 +- core/web/evm_transfer_controller.go | 2 +- core/web/evm_transfer_controller_test.go | 2 +- core/web/presenters/bridges.go | 2 +- core/web/presenters/bridges_test.go | 2 +- core/web/presenters/eth_key.go | 21 +- core/web/presenters/eth_key_test.go | 7 +- core/web/presenters/eth_tx.go | 2 +- core/web/presenters/eth_tx_test.go | 2 +- core/web/presenters/job.go | 7 +- core/web/presenters/job_test.go | 2 +- core/web/resolver/bridge_test.go | 2 +- core/web/resolver/eth_key_test.go | 9 +- core/web/resolver/eth_transaction.go | 2 +- core/web/resolver/eth_transaction_test.go | 2 +- core/web/resolver/helpers.go | 2 +- core/web/resolver/mutation.go | 2 +- core/web/resolver/spec_test.go | 9 +- core/web/solana_chains_controller_test.go | 6 +- go.mod | 2 +- go.sum | 4 +- .../actions/vrfv2plus/vrfv2plus_steps.go | 13 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/types/config/node/core.go | 7 +- tools/flakeytests/runner_test.go | 88 ++--- 180 files changed, 598 insertions(+), 1017 deletions(-) rename {core => common}/config/chaintype.go (100%) delete mode 100644 core/assets/currencies.go delete mode 100644 core/assets/currencies_test.go create mode 100644 core/chains/evm/assets/assets.go create mode 100644 core/chains/evm/assets/assets_test.go rename core/{ => chains/evm}/assets/units.go (100%) rename core/{ => chains/evm}/assets/units_test.go (93%) rename core/{ => chains/evm}/assets/wei.go (100%) rename core/{ => chains/evm}/assets/wei_test.go (100%) diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go index c378b9384e..8f171302a2 100644 --- a/common/client/mock_rpc_test.go +++ b/common/client/mock_rpc_test.go @@ -5,7 +5,7 @@ package client import ( big "math/big" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink-relay/pkg/assets" context "context" diff --git a/common/client/multi_node.go b/common/client/multi_node.go index c268cfb23c..df91c61a9d 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -11,12 +11,12 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/config" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 1fddbc3be3..3621d6d862 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -14,8 +14,8 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/v2/common/config" "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" ) diff --git a/common/client/types.go b/common/client/types.go index 0e52f1db72..ef9f94dafe 100644 --- a/common/client/types.go +++ b/common/client/types.go @@ -4,9 +4,9 @@ import ( "context" "math/big" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/config/chaintype.go b/common/config/chaintype.go similarity index 100% rename from core/config/chaintype.go rename to common/config/chaintype.go diff --git a/core/assets/currencies.go b/core/assets/currencies.go deleted file mode 100644 index 1201f0be35..0000000000 --- a/core/assets/currencies.go +++ /dev/null @@ -1,301 +0,0 @@ -package assets - -import ( - "database/sql/driver" - "fmt" - "math/big" - "strings" - - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - "github.com/shopspring/decimal" -) - -var ErrNoQuotesForCurrency = errors.New("cannot unmarshal json.Number into currency") - -// getDenominator returns 10**precision. -func getDenominator(precision int) *big.Int { - x := big.NewInt(10) - return new(big.Int).Exp(x, big.NewInt(int64(precision)), nil) -} - -func format(i *big.Int, precision int) string { - r := big.NewRat(1, 1).SetFrac(i, getDenominator(precision)) - return fmt.Sprintf("%v", r.FloatString(precision)) -} - -// Link contains a field to represent the smallest units of LINK -type Link big.Int - -// NewLinkFromJuels returns a new struct to represent LINK from it's smallest unit -func NewLinkFromJuels(w int64) *Link { - return (*Link)(big.NewInt(w)) -} - -// String returns Link formatted as a string. -func (l *Link) String() string { - if l == nil { - return "0" - } - return fmt.Sprintf("%v", (*big.Int)(l)) -} - -// Link returns Link formatted as a string, in LINK units -func (l *Link) Link() string { - if l == nil { - return "0" - } - return format((*big.Int)(l), 18) -} - -// SetInt64 delegates to *big.Int.SetInt64 -func (l *Link) SetInt64(w int64) *Link { - return (*Link)((*big.Int)(l).SetInt64(w)) -} - -// ToInt returns the Link value as a *big.Int. -func (l *Link) ToInt() *big.Int { - return (*big.Int)(l) -} - -// ToHash returns a 32 byte representation of this value -func (l *Link) ToHash() common.Hash { - return common.BigToHash((*big.Int)(l)) -} - -// Set delegates to *big.Int.Set -func (l *Link) Set(x *Link) *Link { - il := (*big.Int)(l) - ix := (*big.Int)(x) - - w := il.Set(ix) - return (*Link)(w) -} - -// SetString delegates to *big.Int.SetString -func (l *Link) SetString(s string, base int) (*Link, bool) { - w, ok := (*big.Int)(l).SetString(s, base) - return (*Link)(w), ok -} - -// Cmp defers to big.Int Cmp -func (l *Link) Cmp(y *Link) int { - return (*big.Int)(l).Cmp((*big.Int)(y)) -} - -// Add defers to big.Int Add -func (l *Link) Add(x, y *Link) *Link { - il := (*big.Int)(l) - ix := (*big.Int)(x) - iy := (*big.Int)(y) - - return (*Link)(il.Add(ix, iy)) -} - -// Text defers to big.Int Text -func (l *Link) Text(base int) string { - return (*big.Int)(l).Text(base) -} - -var linkFmtThreshold = (*Link)(new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil)) - -// MarshalText implements the encoding.TextMarshaler interface. -func (l *Link) MarshalText() ([]byte, error) { - if l.Cmp(linkFmtThreshold) >= 0 { - return []byte(fmt.Sprintf("%s link", decimal.NewFromBigInt(l.ToInt(), -18))), nil - } - return (*big.Int)(l).MarshalText() -} - -// MarshalJSON implements the json.Marshaler interface. -func (l Link) MarshalJSON() ([]byte, error) { - value, err := l.MarshalText() - if err != nil { - return nil, err - } - return []byte(fmt.Sprintf(`"%s"`, value)), nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (l *Link) UnmarshalJSON(data []byte) error { - if utils.IsQuoted(data) { - return l.UnmarshalText(utils.RemoveQuotes(data)) - } - return ErrNoQuotesForCurrency -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -func (l *Link) UnmarshalText(text []byte) error { - s := string(text) - if strings.HasSuffix(s, "link") { - s = strings.TrimSuffix(s, "link") - s = strings.TrimSuffix(s, " ") - d, err := decimal.NewFromString(s) - if err != nil { - return errors.Wrapf(err, "assets: cannot unmarshal %q into a *assets.Link", text) - } - d = d.Mul(decimal.New(1, 18)) - if !d.IsInteger() { - err := errors.New("maximum precision is juels") - return errors.Wrapf(err, "assets: cannot unmarshal %q into a *assets.Link", text) - } - l.Set((*Link)(d.Rat().Num())) - return nil - } - if strings.HasSuffix(s, "juels") { - s = strings.TrimSuffix(s, "juels") - s = strings.TrimSuffix(s, " ") - } - if _, ok := l.SetString(s, 10); !ok { - return errors.Errorf("assets: cannot unmarshal %q into a *assets.Link", text) - } - return nil -} - -// IsZero returns true when the value is 0 and false otherwise -func (l *Link) IsZero() bool { - zero := big.NewInt(0) - return (*big.Int)(l).Cmp(zero) == 0 -} - -// Symbol returns LINK -func (*Link) Symbol() string { - return "LINK" -} - -// Value returns the Link value for serialization to database. -func (l Link) Value() (driver.Value, error) { - b := (big.Int)(l) - return b.String(), nil -} - -// Scan reads the database value and returns an instance. -func (l *Link) Scan(value interface{}) error { - switch v := value.(type) { - case string: - decoded, ok := l.SetString(v, 10) - if !ok { - return fmt.Errorf("unable to set string %v of %T to base 10 big.Int for Link", value, value) - } - *l = *decoded - case []uint8: - // The SQL library returns numeric() types as []uint8 of the string representation - decoded, ok := l.SetString(string(v), 10) - if !ok { - return fmt.Errorf("unable to set string %v of %T to base 10 big.Int for Link", value, value) - } - *l = *decoded - case int64: - return fmt.Errorf("unable to convert %v of %T to Link, is the sql type set to varchar?", value, value) - default: - return fmt.Errorf("unable to convert %v of %T to Link", value, value) - } - - return nil -} - -// Eth contains a field to represent the smallest units of ETH -type Eth big.Int - -// NewEth returns a new struct to represent ETH from it's smallest unit (wei) -func NewEth(w int64) *Eth { - return (*Eth)(big.NewInt(w)) -} - -// NewEthValue returns a new struct to represent ETH from it's smallest unit (wei) -func NewEthValue(w int64) Eth { - eth := NewEth(w) - return *eth -} - -// NewEthValueS returns a new struct to represent ETH from a string value of Eth (not wei) -// the underlying value is still wei -func NewEthValueS(s string) (Eth, error) { - e, err := decimal.NewFromString(s) - if err != nil { - return Eth{}, err - } - w := e.Mul(decimal.RequireFromString("10").Pow(decimal.RequireFromString("18"))) - return *(*Eth)(w.BigInt()), nil -} - -// Cmp delegates to *big.Int.Cmp -func (e *Eth) Cmp(y *Eth) int { - return e.ToInt().Cmp(y.ToInt()) -} - -func (e *Eth) String() string { - if e == nil { - return "" - } - return format(e.ToInt(), 18) -} - -// SetInt64 delegates to *big.Int.SetInt64 -func (e *Eth) SetInt64(w int64) *Eth { - return (*Eth)(e.ToInt().SetInt64(w)) -} - -// SetString delegates to *big.Int.SetString -func (e *Eth) SetString(s string, base int) (*Eth, bool) { - w, ok := e.ToInt().SetString(s, base) - return (*Eth)(w), ok -} - -// MarshalJSON implements the json.Marshaler interface. -func (e Eth) MarshalJSON() ([]byte, error) { - value, err := e.MarshalText() - if err != nil { - return nil, err - } - return []byte(fmt.Sprintf(`"%s"`, value)), nil -} - -// MarshalText implements the encoding.TextMarshaler interface. -func (e *Eth) MarshalText() ([]byte, error) { - return e.ToInt().MarshalText() -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (e *Eth) UnmarshalJSON(data []byte) error { - if utils.IsQuoted(data) { - return e.UnmarshalText(utils.RemoveQuotes(data)) - } - return ErrNoQuotesForCurrency -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -func (e *Eth) UnmarshalText(text []byte) error { - if _, ok := e.SetString(string(text), 10); !ok { - return fmt.Errorf("assets: cannot unmarshal %q into a *assets.Eth", text) - } - return nil -} - -// IsZero returns true when the value is 0 and false otherwise -func (e *Eth) IsZero() bool { - zero := big.NewInt(0) - return e.ToInt().Cmp(zero) == 0 -} - -// Symbol returns ETH -func (*Eth) Symbol() string { - return "ETH" -} - -// ToInt returns the Eth value as a *big.Int. -func (e *Eth) ToInt() *big.Int { - return (*big.Int)(e) -} - -// Scan reads the database value and returns an instance. -func (e *Eth) Scan(value interface{}) error { - return (*utils.Big)(e).Scan(value) -} - -// Value returns the Eth value for serialization to database. -func (e Eth) Value() (driver.Value, error) { - return (utils.Big)(e).Value() -} diff --git a/core/assets/currencies_test.go b/core/assets/currencies_test.go deleted file mode 100644 index 5f2a00223f..0000000000 --- a/core/assets/currencies_test.go +++ /dev/null @@ -1,357 +0,0 @@ -package assets_test - -import ( - "encoding/json" - "math/big" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink/v2/core/assets" -) - -func TestAssets_NewLinkAndString(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(0) - - assert.Equal(t, "0", link.String()) - - link.SetInt64(1) - assert.Equal(t, "1", link.String()) - - link.SetString("900000000000000000", 10) - assert.Equal(t, "900000000000000000", link.String()) - - link.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10) - assert.Equal(t, "115792089237316195423570985008687907853269984665640564039457584007913129639935", link.String()) - - var nilLink *assets.Link - assert.Equal(t, "0", nilLink.String()) -} - -func TestAssets_NewLinkAndLink(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(0) - - assert.Equal(t, "0.000000000000000000", link.Link()) - - link.SetInt64(1) - assert.Equal(t, "0.000000000000000001", link.Link()) - - link.SetString("900000000000000000", 10) - assert.Equal(t, "0.900000000000000000", link.Link()) - - link.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10) - assert.Equal(t, "115792089237316195423570985008687907853269984665640564039457.584007913129639935", link.Link()) - - link.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639936", 10) - assert.Equal(t, "115792089237316195423570985008687907853269984665640564039457.584007913129639936", link.Link()) - - var nilLink *assets.Link - assert.Equal(t, "0", nilLink.Link()) -} - -func TestAssets_Link_MarshalJson(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(1) - - b, err := json.Marshal(link) - assert.NoError(t, err) - assert.Equal(t, []byte(`"1"`), b) -} - -func TestAssets_Link_UnmarshalJsonOk(t *testing.T) { - t.Parallel() - - link := assets.Link{} - - err := json.Unmarshal([]byte(`"1"`), &link) - assert.NoError(t, err) - assert.Equal(t, "0.000000000000000001", link.Link()) -} - -func TestAssets_Link_UnmarshalJsonError(t *testing.T) { - t.Parallel() - - link := assets.Link{} - - err := json.Unmarshal([]byte(`"x"`), &link) - assert.EqualError(t, err, "assets: cannot unmarshal \"x\" into a *assets.Link") - - err = json.Unmarshal([]byte(`1`), &link) - assert.Equal(t, assets.ErrNoQuotesForCurrency, err) -} - -func TestAssets_NewEthAndString(t *testing.T) { - t.Parallel() - - eth := assets.NewEth(0) - - assert.Equal(t, "0.000000000000000000", eth.String()) - - eth.SetInt64(1) - assert.Equal(t, "0.000000000000000001", eth.String()) - - eth.SetString("900000000000000000", 10) - assert.Equal(t, "0.900000000000000000", eth.String()) - - eth.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10) - assert.Equal(t, "115792089237316195423570985008687907853269984665640564039457.584007913129639935", eth.String()) - - eth.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639936", 10) - assert.Equal(t, "115792089237316195423570985008687907853269984665640564039457.584007913129639936", eth.String()) -} - -func TestAssets_Eth_IsZero(t *testing.T) { - t.Parallel() - - zeroEth := assets.NewEth(0) - assert.True(t, zeroEth.IsZero()) - - oneLink := assets.NewEth(1) - assert.False(t, oneLink.IsZero()) -} - -func TestAssets_Eth_MarshalJson(t *testing.T) { - t.Parallel() - - eth := assets.NewEth(1) - - b, err := json.Marshal(eth) - assert.NoError(t, err) - assert.Equal(t, []byte(`"1"`), b) -} - -func TestAssets_Eth_UnmarshalJsonOk(t *testing.T) { - t.Parallel() - - eth := assets.Eth{} - - err := json.Unmarshal([]byte(`"1"`), ð) - assert.NoError(t, err) - assert.Equal(t, "0.000000000000000001", eth.String()) -} - -func TestAssets_Eth_UnmarshalJsonError(t *testing.T) { - t.Parallel() - - eth := assets.Eth{} - - err := json.Unmarshal([]byte(`"x"`), ð) - assert.EqualError(t, err, "assets: cannot unmarshal \"x\" into a *assets.Eth") - - err = json.Unmarshal([]byte(`1`), ð) - assert.Equal(t, assets.ErrNoQuotesForCurrency, err) -} - -func TestAssets_LinkToInt(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(0) - assert.Equal(t, big.NewInt(0), link.ToInt()) - - link = assets.NewLinkFromJuels(123) - assert.Equal(t, big.NewInt(123), link.ToInt()) -} - -func TestAssets_LinkToHash(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(123) - expected := common.BigToHash((*big.Int)(link)) - assert.Equal(t, expected, link.ToHash()) -} - -func TestAssets_LinkSetLink(t *testing.T) { - t.Parallel() - - link1 := assets.NewLinkFromJuels(123) - link2 := assets.NewLinkFromJuels(321) - link3 := link1.Set(link2) - assert.Equal(t, link3, link2) -} - -func TestAssets_LinkCmpLink(t *testing.T) { - t.Parallel() - - link1 := assets.NewLinkFromJuels(123) - link2 := assets.NewLinkFromJuels(321) - assert.NotZero(t, link1.Cmp(link2)) - - link3 := assets.NewLinkFromJuels(321) - assert.Zero(t, link3.Cmp(link2)) -} - -func TestAssets_LinkAddLink(t *testing.T) { - t.Parallel() - - link1 := assets.NewLinkFromJuels(123) - link2 := assets.NewLinkFromJuels(321) - sum := assets.NewLinkFromJuels(123 + 321) - assert.Equal(t, sum, link1.Add(link1, link2)) -} - -func TestAssets_LinkText(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(123) - assert.Equal(t, "123", link.Text(10)) - assert.Equal(t, "7b", link.Text(16)) -} - -func TestAssets_LinkIsZero(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(123) - assert.False(t, link.IsZero()) - - link = assets.NewLinkFromJuels(0) - assert.True(t, link.IsZero()) -} - -func TestAssets_LinkSymbol(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(123) - assert.Equal(t, "LINK", link.Symbol()) -} - -func TestAssets_LinkScanValue(t *testing.T) { - t.Parallel() - - link := assets.NewLinkFromJuels(123) - v, err := link.Value() - assert.NoError(t, err) - - link2 := assets.NewLinkFromJuels(0) - err = link2.Scan(v) - assert.NoError(t, err) - assert.Equal(t, link2, link) - - err = link2.Scan("123") - assert.NoError(t, err) - assert.Equal(t, link2, link) - - err = link2.Scan([]uint8{'1', '2', '3'}) - assert.NoError(t, err) - assert.Equal(t, link2, link) - - assert.ErrorContains(t, link2.Scan([]uint8{'x'}), "unable to set string") - assert.ErrorContains(t, link2.Scan("123.56"), "unable to set string") - assert.ErrorContains(t, link2.Scan(1.5), "unable to convert") - assert.ErrorContains(t, link2.Scan(int64(123)), "unable to convert") -} - -func TestAssets_NewEth(t *testing.T) { - t.Parallel() - - ethRef := assets.NewEth(123) - ethVal := assets.NewEthValue(123) - ethStr, err := assets.NewEthValueS(ethRef.String()) - assert.NoError(t, err) - assert.Equal(t, *ethRef, ethVal) - assert.Equal(t, *ethRef, ethStr) -} - -func TestAssets_EthSymbol(t *testing.T) { - t.Parallel() - - eth := assets.NewEth(123) - assert.Equal(t, "ETH", eth.Symbol()) -} - -func TestAssets_EthScanValue(t *testing.T) { - t.Parallel() - - eth := assets.NewEth(123) - v, err := eth.Value() - assert.NoError(t, err) - - eth2 := assets.NewEth(0) - err = eth2.Scan(v) - assert.NoError(t, err) - - assert.Equal(t, eth, eth2) -} - -func TestAssets_EthCmpEth(t *testing.T) { - t.Parallel() - - eth1 := assets.NewEth(123) - eth2 := assets.NewEth(321) - assert.NotZero(t, eth1.Cmp(eth2)) - - eth3 := assets.NewEth(321) - assert.Zero(t, eth3.Cmp(eth2)) -} - -func TestLink(t *testing.T) { - for _, tt := range []struct { - input string - exp string - }{ - {"0", "0"}, - {"1", "1"}, - {"1 juels", "1"}, - {"100000000000", "100000000000"}, - {"0.0000001 link", "100000000000"}, - {"1000000000000", "0.000001 link"}, - {"100000000000000", "0.0001 link"}, - {"0.0001 link", "0.0001 link"}, - {"10000000000000000", "0.01 link"}, - {"0.01 link", "0.01 link"}, - {"100000000000000000", "0.1 link"}, - {"0.1 link", "0.1 link"}, - {"1.0 link", "1 link"}, - {"1000000000000000000", "1 link"}, - {"1000000000000000000 juels", "1 link"}, - {"1100000000000000000", "1.1 link"}, - {"1.1link", "1.1 link"}, - {"1.1 link", "1.1 link"}, - } { - t.Run(tt.input, func(t *testing.T) { - var l assets.Link - err := l.UnmarshalText([]byte(tt.input)) - require.NoError(t, err) - b, err := l.MarshalText() - require.NoError(t, err) - assert.Equal(t, tt.exp, string(b)) - }) - } -} - -func FuzzLink(f *testing.F) { - f.Add("1") - f.Add("1 link") - f.Add("1.1link") - f.Add("2.3") - f.Add("2.3 link") - f.Add("00005 link") - f.Add("0.0005link") - f.Add("1100000000000000000000000000000") - f.Add("1100000000000000000000000000000 juels") - f.Fuzz(func(t *testing.T, v string) { - if len(v) > 1_000 { - t.Skip() - } - var l assets.Link - err := l.UnmarshalText([]byte(v)) - if err != nil { - t.Skip() - } - - b, err := l.MarshalText() - require.NoErrorf(t, err, "failed to marshal %v after unmarshaling from %q", l, v) - - var l2 assets.Link - err = l2.UnmarshalText(b) - require.NoErrorf(t, err, "failed to unmarshal %s after marshaling from %v", string(b), l) - require.Equal(t, l, l2, "unequal values after marshal/unmarshal") - }) -} diff --git a/core/bridges/bridge_type.go b/core/bridges/bridge_type.go index 9b3a8570ca..9031541f22 100644 --- a/core/bridges/bridge_type.go +++ b/core/bridges/bridge_type.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/bridges/bridge_type_test.go b/core/bridges/bridge_type_test.go index 8c4a7cbace..c04aba5c2c 100644 --- a/core/bridges/bridge_type_test.go +++ b/core/bridges/bridge_type_test.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/store/models" diff --git a/core/chains/evm/assets/assets.go b/core/chains/evm/assets/assets.go new file mode 100644 index 0000000000..c6c81b5ab4 --- /dev/null +++ b/core/chains/evm/assets/assets.go @@ -0,0 +1,117 @@ +package assets + +import ( + "database/sql/driver" + "fmt" + "math/big" + + "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/utils/bytes" + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/shopspring/decimal" +) + +// Eth contains a field to represent the smallest units of ETH +type Eth big.Int + +// NewEth returns a new struct to represent ETH from it's smallest unit (wei) +func NewEth(w int64) *Eth { + return (*Eth)(big.NewInt(w)) +} + +// NewEthValue returns a new struct to represent ETH from it's smallest unit (wei) +func NewEthValue(w int64) Eth { + eth := NewEth(w) + return *eth +} + +// NewEthValueS returns a new struct to represent ETH from a string value of Eth (not wei) +// the underlying value is still wei +func NewEthValueS(s string) (Eth, error) { + e, err := decimal.NewFromString(s) + if err != nil { + return Eth{}, err + } + w := e.Mul(decimal.RequireFromString("10").Pow(decimal.RequireFromString("18"))) + return *(*Eth)(w.BigInt()), nil +} + +// Cmp delegates to *big.Int.Cmp +func (e *Eth) Cmp(y *Eth) int { + return e.ToInt().Cmp(y.ToInt()) +} + +func (e *Eth) String() string { + if e == nil { + return "" + } + return assets.Format(e.ToInt(), 18) +} + +// SetInt64 delegates to *big.Int.SetInt64 +func (e *Eth) SetInt64(w int64) *Eth { + return (*Eth)(e.ToInt().SetInt64(w)) +} + +// SetString delegates to *big.Int.SetString +func (e *Eth) SetString(s string, base int) (*Eth, bool) { + w, ok := e.ToInt().SetString(s, base) + return (*Eth)(w), ok +} + +// MarshalJSON implements the json.Marshaler interface. +func (e Eth) MarshalJSON() ([]byte, error) { + value, err := e.MarshalText() + if err != nil { + return nil, err + } + return []byte(fmt.Sprintf(`"%s"`, value)), nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (e *Eth) MarshalText() ([]byte, error) { + return e.ToInt().MarshalText() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (e *Eth) UnmarshalJSON(data []byte) error { + if bytes.HasQuotes(data) { + return e.UnmarshalText(bytes.TrimQuotes(data)) + } + return assets.ErrNoQuotesForCurrency +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (e *Eth) UnmarshalText(text []byte) error { + if _, ok := e.SetString(string(text), 10); !ok { + return fmt.Errorf("assets: cannot unmarshal %q into a *assets.Eth", text) + } + return nil +} + +// IsZero returns true when the value is 0 and false otherwise +func (e *Eth) IsZero() bool { + zero := big.NewInt(0) + return e.ToInt().Cmp(zero) == 0 +} + +// Symbol returns ETH +func (*Eth) Symbol() string { + return "ETH" +} + +// ToInt returns the Eth value as a *big.Int. +func (e *Eth) ToInt() *big.Int { + return (*big.Int)(e) +} + +// Scan reads the database value and returns an instance. +func (e *Eth) Scan(value interface{}) error { + return (*utils.Big)(e).Scan(value) +} + +// Value returns the Eth value for serialization to database. +func (e Eth) Value() (driver.Value, error) { + return (utils.Big)(e).Value() +} diff --git a/core/chains/evm/assets/assets_test.go b/core/chains/evm/assets/assets_test.go new file mode 100644 index 0000000000..9496554f11 --- /dev/null +++ b/core/chains/evm/assets/assets_test.go @@ -0,0 +1,116 @@ +package assets_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" +) + +func TestAssets_NewEthAndString(t *testing.T) { + t.Parallel() + + eth := assets.NewEth(0) + + assert.Equal(t, "0.000000000000000000", eth.String()) + + eth.SetInt64(1) + assert.Equal(t, "0.000000000000000001", eth.String()) + + eth.SetString("900000000000000000", 10) + assert.Equal(t, "0.900000000000000000", eth.String()) + + eth.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10) + assert.Equal(t, "115792089237316195423570985008687907853269984665640564039457.584007913129639935", eth.String()) + + eth.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639936", 10) + assert.Equal(t, "115792089237316195423570985008687907853269984665640564039457.584007913129639936", eth.String()) +} + +func TestAssets_Eth_IsZero(t *testing.T) { + t.Parallel() + + zeroEth := assets.NewEth(0) + assert.True(t, zeroEth.IsZero()) + + oneLink := assets.NewEth(1) + assert.False(t, oneLink.IsZero()) +} + +func TestAssets_Eth_MarshalJson(t *testing.T) { + t.Parallel() + + eth := assets.NewEth(1) + + b, err := json.Marshal(eth) + assert.NoError(t, err) + assert.Equal(t, []byte(`"1"`), b) +} + +func TestAssets_Eth_UnmarshalJsonOk(t *testing.T) { + t.Parallel() + + eth := assets.Eth{} + + err := json.Unmarshal([]byte(`"1"`), ð) + assert.NoError(t, err) + assert.Equal(t, "0.000000000000000001", eth.String()) +} + +func TestAssets_Eth_UnmarshalJsonError(t *testing.T) { + t.Parallel() + + eth := assets.Eth{} + + err := json.Unmarshal([]byte(`"x"`), ð) + assert.EqualError(t, err, "assets: cannot unmarshal \"x\" into a *assets.Eth") + + err = json.Unmarshal([]byte(`1`), ð) + assert.Equal(t, relayassets.ErrNoQuotesForCurrency, err) +} + +func TestAssets_NewEth(t *testing.T) { + t.Parallel() + + ethRef := assets.NewEth(123) + ethVal := assets.NewEthValue(123) + ethStr, err := assets.NewEthValueS(ethRef.String()) + assert.NoError(t, err) + assert.Equal(t, *ethRef, ethVal) + assert.Equal(t, *ethRef, ethStr) +} + +func TestAssets_EthSymbol(t *testing.T) { + t.Parallel() + + eth := assets.NewEth(123) + assert.Equal(t, "ETH", eth.Symbol()) +} + +func TestAssets_EthScanValue(t *testing.T) { + t.Parallel() + + eth := assets.NewEth(123) + v, err := eth.Value() + assert.NoError(t, err) + + eth2 := assets.NewEth(0) + err = eth2.Scan(v) + assert.NoError(t, err) + + assert.Equal(t, eth, eth2) +} + +func TestAssets_EthCmpEth(t *testing.T) { + t.Parallel() + + eth1 := assets.NewEth(123) + eth2 := assets.NewEth(321) + assert.NotZero(t, eth1.Cmp(eth2)) + + eth3 := assets.NewEth(321) + assert.Zero(t, eth3.Cmp(eth2)) +} diff --git a/core/assets/units.go b/core/chains/evm/assets/units.go similarity index 100% rename from core/assets/units.go rename to core/chains/evm/assets/units.go diff --git a/core/assets/units_test.go b/core/chains/evm/assets/units_test.go similarity index 93% rename from core/assets/units_test.go rename to core/chains/evm/assets/units_test.go index 7b23072033..37eb139325 100644 --- a/core/assets/units_test.go +++ b/core/chains/evm/assets/units_test.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" ) func TestAssets_Units(t *testing.T) { diff --git a/core/assets/wei.go b/core/chains/evm/assets/wei.go similarity index 100% rename from core/assets/wei.go rename to core/chains/evm/assets/wei.go diff --git a/core/assets/wei_test.go b/core/chains/evm/assets/wei_test.go similarity index 100% rename from core/assets/wei_test.go rename to core/chains/evm/assets/wei_test.go diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index b5896393d3..f21bf2525a 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink-relay/pkg/types" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -473,7 +474,7 @@ func (c *chain) Logger() logger.Logger { return c.logger } func (c *chain) BalanceMonitor() monitor.BalanceMonitor { return c.balanceMonitor } func (c *chain) GasEstimator() gas.EvmFeeEstimator { return c.gasEstimator } -func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType config.ChainType, nodes []*toml.Node) (evmclient.Client, error) { +func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType commonconfig.ChainType, nodes []*toml.Node) (evmclient.Client, error) { var primaries []evmclient.Node var sendonlys []evmclient.SendOnlyNode for i, node := range nodes { diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 4c5108745c..79a91dfc05 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -10,10 +10,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -182,7 +183,7 @@ func (c *chainClient) IsL2() bool { return c.multiNode.IsL2() } -func (c *chainClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*assets.Link, error) { +func (c *chainClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*relayassets.Link, error) { return c.multiNode.LINKBalance(ctx, address, linkAddress) } diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index fb8a39f379..988a7404c9 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -6,11 +6,11 @@ import ( "strings" "time" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + "github.com/smartcontractkit/chainlink/v2/common/config" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 2820ba992c..b1d477b1a2 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -10,9 +10,9 @@ import ( "github.com/pkg/errors" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - commonconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index 7617a7c05f..f1ff5fab45 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -5,7 +5,7 @@ package mocks import ( big "math/big" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink-relay/pkg/assets" common "github.com/ethereum/go-ethereum/common" diff --git a/core/chains/evm/client/null_client.go b/core/chains/evm/client/null_client.go index 286f62b3b8..45876d9259 100644 --- a/core/chains/evm/client/null_client.go +++ b/core/chains/evm/client/null_client.go @@ -9,8 +9,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" - "github.com/smartcontractkit/chainlink/v2/core/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 2d679ab3d7..473ab6d1eb 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -17,8 +17,8 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index 04b9fad1fc..f952c04d5b 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -17,9 +17,10 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -868,12 +869,12 @@ func (r *rpcClient) TokenBalance(ctx context.Context, address common.Address, co } // LINKBalance returns the balance of LINK at the given address -func (r *rpcClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*assets.Link, error) { +func (r *rpcClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*relayassets.Link, error) { balance, err := r.TokenBalance(ctx, address, linkAddress) if err != nil { - return assets.NewLinkFromJuels(0), err + return relayassets.NewLinkFromJuels(0), err } - return (*assets.Link)(balance), nil + return (*relayassets.Link)(balance), nil } func (r *rpcClient) FilterEvents(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { diff --git a/core/chains/evm/client/send_only_node_test.go b/core/chains/evm/client/send_only_node_test.go index b37ee14253..876ae9bc4d 100644 --- a/core/chains/evm/client/send_only_node_test.go +++ b/core/chains/evm/client/send_only_node_test.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index f4ad6a65a1..33ecc3d0d5 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -18,8 +18,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" - "github.com/smartcontractkit/chainlink/v2/core/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index 7971a18d4d..6030991179 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -9,13 +9,14 @@ import ( ocr "github.com/smartcontractkit/libocr/offchainreporting" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - gencfg "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" ) -func NewTOMLChainScopedConfig(appCfg gencfg.AppConfig, tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { +func NewTOMLChainScopedConfig(appCfg config.AppConfig, tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { return &ChainScoped{ AppConfig: appCfg, evmConfig: &evmConfig{c: tomlConfig}, @@ -24,7 +25,7 @@ func NewTOMLChainScopedConfig(appCfg gencfg.AppConfig, tomlConfig *toml.EVMConfi // ChainScoped implements config.ChainScopedConfig with a gencfg.BasicConfig and EVMConfig. type ChainScoped struct { - gencfg.AppConfig + config.AppConfig lggr logger.Logger evmConfig *evmConfig @@ -140,11 +141,11 @@ func (e *evmConfig) BlockEmissionIdleWarningThreshold() time.Duration { return e.c.NoNewHeadsThreshold.Duration() } -func (e *evmConfig) ChainType() gencfg.ChainType { +func (e *evmConfig) ChainType() commonconfig.ChainType { if e.c.ChainType == nil { return "" } - return gencfg.ChainType(*e.c.ChainType) + return commonconfig.ChainType(*e.c.ChainType) } func (e *evmConfig) ChainID() *big.Int { diff --git a/core/chains/evm/config/chain_scoped_gas_estimator.go b/core/chains/evm/config/chain_scoped_gas_estimator.go index cc28ce75f0..0c52cf0a46 100644 --- a/core/chains/evm/config/chain_scoped_gas_estimator.go +++ b/core/chains/evm/config/chain_scoped_gas_estimator.go @@ -3,7 +3,7 @@ package config import ( gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" ) diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index f8ec030969..ec90797d7f 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -6,7 +6,9 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/config" ) @@ -24,7 +26,7 @@ type EVM interface { BlockBackfillSkip() bool BlockEmissionIdleWarningThreshold() time.Duration ChainID() *big.Int - ChainType() config.ChainType + ChainType() commonconfig.ChainType FinalityDepth() uint32 FinalityTagEnabled() bool FlagsContractAddress() string @@ -32,7 +34,7 @@ type EVM interface { LogBackfillBatchSize() uint32 LogKeepBlocksDepth() uint32 LogPollInterval() time.Duration - MinContractPayment() *assets.Link + MinContractPayment() *relayassets.Link MinIncomingConfirmations() uint32 NonceAutoSync() bool OperatorFactoryAddress() string diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index 0a3fc5f41e..d34d1eae63 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -11,7 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -402,7 +403,7 @@ func Test_chainScopedConfig_Validate(t *testing.T) { t.Run("arbitrum-estimator", func(t *testing.T) { t.Run("custom", func(t *testing.T) { cfg := configWithChains(t, 0, &toml.Chain{ - ChainType: ptr(string(config.ChainArbitrum)), + ChainType: ptr(string(commonconfig.ChainArbitrum)), GasEstimator: toml.GasEstimator{ Mode: ptr("BlockHistory"), }, @@ -433,7 +434,7 @@ func Test_chainScopedConfig_Validate(t *testing.T) { t.Run("optimism-estimator", func(t *testing.T) { t.Run("custom", func(t *testing.T) { cfg := configWithChains(t, 0, &toml.Chain{ - ChainType: ptr(string(config.ChainOptimismBedrock)), + ChainType: ptr(string(commonconfig.ChainOptimismBedrock)), GasEstimator: toml.GasEstimator{ Mode: ptr("BlockHistory"), }, diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go index 8cb54132f5..6260b3cd50 100644 --- a/core/chains/evm/config/mocks/gas_estimator.go +++ b/core/chains/evm/config/mocks/gas_estimator.go @@ -4,7 +4,7 @@ package mocks import ( common "github.com/ethereum/go-ethereum/common" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" config "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index cf2cde460e..ae0fb41c5e 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -12,12 +12,13 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -354,7 +355,7 @@ type Chain struct { LogPollInterval *models.Duration LogKeepBlocksDepth *uint32 MinIncomingConfirmations *uint32 - MinContractPayment *assets.Link + MinContractPayment *relayassets.Link NonceAutoSync *bool NoNewHeadsThreshold *models.Duration OperatorFactoryAddress *ethkey.EIP55Address diff --git a/core/chains/evm/config/toml/defaults.go b/core/chains/evm/config/toml/defaults.go index 6851338358..d362e9ac3d 100644 --- a/core/chains/evm/config/toml/defaults.go +++ b/core/chains/evm/config/toml/defaults.go @@ -8,7 +8,7 @@ import ( "slices" "strings" - "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/utils" configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 78d93243bb..860126a588 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index a226368edf..894b531dc9 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 80ae19f109..eb35cd2751 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -16,12 +16,12 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index c8b193c443..2747ea067d 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -18,12 +18,12 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" diff --git a/core/chains/evm/gas/chain_specific.go b/core/chains/evm/gas/chain_specific.go index 4f0d2e6b2f..c989cd0aa9 100644 --- a/core/chains/evm/gas/chain_specific.go +++ b/core/chains/evm/gas/chain_specific.go @@ -1,9 +1,9 @@ package gas import ( - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" ) // chainSpecificIsUsable allows for additional logic specific to a particular diff --git a/core/chains/evm/gas/cmd/arbgas/main.go b/core/chains/evm/gas/cmd/arbgas/main.go index 4ceeb0009e..6b79ff2f13 100644 --- a/core/chains/evm/gas/cmd/arbgas/main.go +++ b/core/chains/evm/gas/cmd/arbgas/main.go @@ -12,7 +12,7 @@ import ( "go.uber.org/zap/zapcore" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/chains/evm/gas/fixed_price_estimator.go b/core/chains/evm/gas/fixed_price_estimator.go index a45df741a2..7eb7454dad 100644 --- a/core/chains/evm/gas/fixed_price_estimator.go +++ b/core/chains/evm/gas/fixed_price_estimator.go @@ -7,7 +7,7 @@ import ( commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/chains/evm/gas/fixed_price_estimator_test.go b/core/chains/evm/gas/fixed_price_estimator_test.go index a6cb313e5e..9fa0997c10 100644 --- a/core/chains/evm/gas/fixed_price_estimator_test.go +++ b/core/chains/evm/gas/fixed_price_estimator_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/gas/gas_test.go b/core/chains/evm/gas/gas_test.go index 4c6be2cf50..a3f7224a09 100644 --- a/core/chains/evm/gas/gas_test.go +++ b/core/chains/evm/gas/gas_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/chains/evm/gas/helpers_test.go b/core/chains/evm/gas/helpers_test.go index ac1f5129e0..9a5076be6d 100644 --- a/core/chains/evm/gas/helpers_test.go +++ b/core/chains/evm/gas/helpers_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" ) func init() { diff --git a/core/chains/evm/gas/mocks/config.go b/core/chains/evm/gas/mocks/config.go index eabbd0f03e..c09005b5e3 100644 --- a/core/chains/evm/gas/mocks/config.go +++ b/core/chains/evm/gas/mocks/config.go @@ -3,7 +3,7 @@ package mocks import ( - config "github.com/smartcontractkit/chainlink/v2/core/config" + config "github.com/smartcontractkit/chainlink/v2/common/config" mock "github.com/stretchr/testify/mock" ) diff --git a/core/chains/evm/gas/mocks/evm_estimator.go b/core/chains/evm/gas/mocks/evm_estimator.go index 80ab3c68cc..f2cb51f856 100644 --- a/core/chains/evm/gas/mocks/evm_estimator.go +++ b/core/chains/evm/gas/mocks/evm_estimator.go @@ -5,7 +5,7 @@ package mocks import ( context "context" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/chains/evm/gas/mocks/evm_fee_estimator.go b/core/chains/evm/gas/mocks/evm_fee_estimator.go index 42ea96cd50..b9b1636779 100644 --- a/core/chains/evm/gas/mocks/evm_fee_estimator.go +++ b/core/chains/evm/gas/mocks/evm_fee_estimator.go @@ -5,7 +5,7 @@ package mocks import ( big "math/big" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" context "context" diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index 299d7d5473..50cbddcd9b 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -11,16 +11,16 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index c1dd9e44ff..8ac94a2269 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index d990017bd0..09244e9d31 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -13,9 +13,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go index 320c9cb71d..801d72919e 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go @@ -13,8 +13,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" - "github.com/smartcontractkit/chainlink/v2/core/assets" - "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/chains/evm/gas/rollups/mocks/l1_oracle.go b/core/chains/evm/gas/rollups/mocks/l1_oracle.go index 31407300b6..f6f8cc736a 100644 --- a/core/chains/evm/gas/rollups/mocks/l1_oracle.go +++ b/core/chains/evm/gas/rollups/mocks/l1_oracle.go @@ -5,7 +5,7 @@ package mocks import ( context "context" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" mock "github.com/stretchr/testify/mock" ) diff --git a/core/chains/evm/gas/rollups/models.go b/core/chains/evm/gas/rollups/models.go index 83ae29f4ea..1659436071 100644 --- a/core/chains/evm/gas/rollups/models.go +++ b/core/chains/evm/gas/rollups/models.go @@ -3,7 +3,7 @@ package rollups import ( "context" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services" ) diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index a4ffb80997..24cf20f172 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index 808b28a3a6..3b6b8184e3 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/chains/evm/mocks/balance_monitor.go b/core/chains/evm/mocks/balance_monitor.go index 2a5e66bbc0..cdda18b7f0 100644 --- a/core/chains/evm/mocks/balance_monitor.go +++ b/core/chains/evm/mocks/balance_monitor.go @@ -4,7 +4,7 @@ package mocks import ( common "github.com/ethereum/go-ethereum/common" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" context "context" diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index 5f5b8a243b..476d3c7019 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index c80d64e7ef..6a62549e49 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index 7b2a05a34c..06c1126b86 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -12,7 +12,7 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index 863eae4723..11304384ab 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 460f9629fb..48b68f9b55 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -25,7 +25,7 @@ import ( commonclient "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" diff --git a/core/chains/evm/txmgr/config.go b/core/chains/evm/txmgr/config.go index 0e6b46574a..8346a0d055 100644 --- a/core/chains/evm/txmgr/config.go +++ b/core/chains/evm/txmgr/config.go @@ -5,9 +5,9 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/common/config" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" - coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" ) // ChainConfig encompasses config used by txmgr package @@ -15,7 +15,7 @@ import ( // //go:generate mockery --quiet --recursive --name ChainConfig --output ./mocks/ --case=underscore --structname Config --filename config.go type ChainConfig interface { - ChainType() coreconfig.ChainType + ChainType() config.ChainType FinalityDepth() uint32 FinalityTagEnabled() bool NonceAutoSync() bool diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 3a0d33f7ba..31464f8f52 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -24,7 +24,7 @@ import ( commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index c3371fee80..9262c85a83 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -20,7 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index f8798f9f83..73bfc6fc85 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -9,7 +9,7 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/chains/evm/txmgr/mocks/config.go b/core/chains/evm/txmgr/mocks/config.go index d6f961ccb5..ab98d686c8 100644 --- a/core/chains/evm/txmgr/mocks/config.go +++ b/core/chains/evm/txmgr/mocks/config.go @@ -3,7 +3,7 @@ package mocks import ( - config "github.com/smartcontractkit/chainlink/v2/core/config" + config "github.com/smartcontractkit/chainlink/v2/common/config" mock "github.com/stretchr/testify/mock" ) diff --git a/core/chains/evm/txmgr/test_helpers.go b/core/chains/evm/txmgr/test_helpers.go index f9c0423a62..e279dddf5f 100644 --- a/core/chains/evm/txmgr/test_helpers.go +++ b/core/chains/evm/txmgr/test_helpers.go @@ -6,7 +6,8 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -136,12 +137,12 @@ func (c *MockConfig) EVM() evmconfig.EVM { return c.EvmConfig } -func (c *MockConfig) NonceAutoSync() bool { return true } -func (c *MockConfig) ChainType() config.ChainType { return "" } -func (c *MockConfig) FinalityDepth() uint32 { return c.finalityDepth } -func (c *MockConfig) SetFinalityDepth(fd uint32) { c.finalityDepth = fd } -func (c *MockConfig) FinalityTagEnabled() bool { return c.finalityTagEnabled } -func (c *MockConfig) RPCDefaultBatchSize() uint32 { return c.RpcDefaultBatchSize } +func (c *MockConfig) NonceAutoSync() bool { return true } +func (c *MockConfig) ChainType() commonconfig.ChainType { return "" } +func (c *MockConfig) FinalityDepth() uint32 { return c.finalityDepth } +func (c *MockConfig) SetFinalityDepth(fd uint32) { c.finalityDepth = fd } +func (c *MockConfig) FinalityTagEnabled() bool { return c.finalityTagEnabled } +func (c *MockConfig) RPCDefaultBatchSize() uint32 { return c.RpcDefaultBatchSize } func MakeTestConfigs(t *testing.T) (*MockConfig, *TestDatabaseConfig, *TestEvmConfig) { db := &TestDatabaseConfig{defaultQueryTimeout: pg.DefaultQueryTimeout} diff --git a/core/chains/evm/txmgr/transmitchecker_test.go b/core/chains/evm/txmgr/transmitchecker_test.go index 79868e6a64..b43fcb4f45 100644 --- a/core/chains/evm/txmgr/transmitchecker_test.go +++ b/core/chains/evm/txmgr/transmitchecker_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/require" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 4e201b9c6f..e27cea137b 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -19,7 +19,7 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" diff --git a/core/chains/evm/types/block_json_benchmark_test.go b/core/chains/evm/types/block_json_benchmark_test.go index 8c5f766d63..21c58bd198 100644 --- a/core/chains/evm/types/block_json_benchmark_test.go +++ b/core/chains/evm/types/block_json_benchmark_test.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index c2d61e0070..83b90b4d53 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -18,7 +18,7 @@ import ( htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types/internal/blocks" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index 2911e426e8..3507b6a131 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/cmd/cosmos_node_commands_test.go b/core/cmd/cosmos_node_commands_test.go index 9ac7dfb2ba..591160629e 100644 --- a/core/cmd/cosmos_node_commands_test.go +++ b/core/cmd/cosmos_node_commands_test.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" + relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -35,7 +35,7 @@ func TestShell_IndexCosmosNodes(t *testing.T) { chainID := cosmostest.RandomChainID() node := config.Node{ Name: ptr("second"), - TendermintURL: utils.MustParseURL("http://tender.mint.test/bombay-12"), + TendermintURL: relaycfg.MustParseURL("http://tender.mint.test/bombay-12"), } chain := config.TOMLConfig{ ChainID: ptr(chainID), diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index 630e76783a..d74ae231d7 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -12,7 +12,8 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -34,7 +35,7 @@ func TestEthKeysPresenter_RenderTable(t *testing.T) { var ( address = "0x5431F5F973781809D18643b87B44921b11355d81" ethBalance = assets.NewEth(1) - linkBalance = assets.NewLinkFromJuels(2) + linkBalance = relayassets.NewLinkFromJuels(2) isDisabled = true createdAt = time.Now() updatedAt = time.Now().Add(time.Second) @@ -89,7 +90,7 @@ func TestShell_ListETHKeys(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(13), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(13), nil) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) @@ -168,7 +169,7 @@ func TestShell_CreateETHKey(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(42), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(42), nil) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -243,7 +244,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(42), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(42), nil) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) @@ -361,7 +362,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { ethClient.On("Dial", mock.Anything).Maybe() ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(42), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(42), nil) set := flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") diff --git a/core/cmd/evm_transaction_commands.go b/core/cmd/evm_transaction_commands.go index 68fffde303..d702bc3b79 100644 --- a/core/cmd/evm_transaction_commands.go +++ b/core/cmd/evm_transaction_commands.go @@ -10,7 +10,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index 484b1ccd3d..e071d875f0 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/cmd" diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 70d75f761b..f7e17ef7fc 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -31,8 +31,8 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/build" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/cmd/solana_node_commands_test.go b/core/cmd/solana_node_commands_test.go index 3f95ebc0d8..7c88557c6d 100644 --- a/core/cmd/solana_node_commands_test.go +++ b/core/cmd/solana_node_commands_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" + "github.com/smartcontractkit/chainlink-relay/pkg/config" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" @@ -35,11 +35,11 @@ func TestShell_IndexSolanaNodes(t *testing.T) { id := solanatest.RandomChainID() node1 := solcfg.Node{ Name: ptr("first"), - URL: utils.MustParseURL("https://solana1.example"), + URL: config.MustParseURL("https://solana1.example"), } node2 := solcfg.Node{ Name: ptr("second"), - URL: utils.MustParseURL("https://solana2.example"), + URL: config.MustParseURL("https://solana2.example"), } chain := solana.TOMLConfig{ ChainID: &id, diff --git a/core/cmd/starknet_node_commands_test.go b/core/cmd/starknet_node_commands_test.go index e799e5aac0..9d7c6fcaf4 100644 --- a/core/cmd/starknet_node_commands_test.go +++ b/core/cmd/starknet_node_commands_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" + relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" @@ -34,11 +34,11 @@ func TestShell_IndexStarkNetNodes(t *testing.T) { id := "starknet chain ID" node1 := config.Node{ Name: ptr("first"), - URL: utils.MustParseURL("https://starknet1.example"), + URL: relaycfg.MustParseURL("https://starknet1.example"), } node2 := config.Node{ Name: ptr("second"), - URL: utils.MustParseURL("https://starknet2.example"), + URL: relaycfg.MustParseURL("https://starknet2.example"), } chain := config.TOMLConfig{ ChainID: &id, diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index 927592e448..74fa6682c9 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/solana" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/config/parse/parsers.go b/core/config/parse/parsers.go index 93e519064b..e2f6978187 100644 --- a/core/config/parse/parsers.go +++ b/core/config/parse/parsers.go @@ -13,7 +13,8 @@ import ( "github.com/pkg/errors" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -22,10 +23,10 @@ func String(str string) (string, error) { return str, nil } -func Link(str string) (*assets.Link, error) { - i, ok := new(assets.Link).SetString(str, 10) +func Link(str string) (*relayassets.Link, error) { + i, ok := new(relayassets.Link).SetString(str, 10) if !ok { - return i, fmt.Errorf("unable to parse '%v' into *assets.Link(base 10)", str) + return i, fmt.Errorf("unable to parse '%v' into *relayassets.Link(base 10)", str) } return i, nil } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 778ccbdb15..644c516c21 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -47,10 +47,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index a52b9a5d06..741afe828f 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -25,9 +25,9 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index b5f42d8bf3..7749b173c5 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -41,9 +41,9 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 3e22093568..387b15f76c 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -34,8 +34,8 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" diff --git a/core/scripts/go.mod b/core/scripts/go.mod index eb41312a6a..7bf60aff8b 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.20231113174149-046d4ddaca1a // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd // 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 35e85fe2c9..7139f0efa4 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.20231113174149-046d4ddaca1a h1:G/pD8uI1PULRJU8Y3eLLzjqQBp9ruG9hj+wWxtyrgTo= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd h1:PRVJxNK67pQWufXuB1cxckH/xZkcQFDy8KjN9ZYqong= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd/go.mod h1:rOayi690YxLlkQy959PD8INhOAIAUi9LoN0G+J/CEf4= 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/scripts/ocr2vrf/main.go b/core/scripts/ocr2vrf/main.go index 60260c54d9..c698fcd730 100644 --- a/core/scripts/ocr2vrf/main.go +++ b/core/scripts/ocr2vrf/main.go @@ -15,7 +15,7 @@ import ( ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" ) diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index 677c0b105e..5856256504 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -24,7 +24,7 @@ import ( "github.com/jmoiron/sqlx" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index b7940d6fda..6b1ef585a5 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -29,7 +29,7 @@ import ( "github.com/jmoiron/sqlx" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2plus" diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 34fcc4bbe9..0caae3607f 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -17,12 +17,13 @@ import ( ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - relayutils "github.com/smartcontractkit/chainlink-relay/pkg/utils" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" legacy "github.com/smartcontractkit/chainlink/v2/core/config" @@ -144,7 +145,7 @@ var ( MaxMsgsPerBatch: ptr[int64](13), }, Nodes: []*coscfg.Node{ - {Name: ptr("primary"), TendermintURL: relayutils.MustParseURL("http://columbus.cosmos.com")}, + {Name: ptr("primary"), TendermintURL: relaycfg.MustParseURL("http://columbus.cosmos.com")}, }}, { ChainID: ptr("Malaga-420"), @@ -152,7 +153,7 @@ var ( BlocksUntilTxTimeout: ptr[int64](20), }, Nodes: []*coscfg.Node{ - {Name: ptr("secondary"), TendermintURL: relayutils.MustParseURL("http://bombay.cosmos.com")}, + {Name: ptr("secondary"), TendermintURL: relaycfg.MustParseURL("http://bombay.cosmos.com")}, }}, }, Solana: []*solana.TOMLConfig{ @@ -162,16 +163,16 @@ var ( MaxRetries: ptr[int64](12), }, Nodes: []*solcfg.Node{ - {Name: ptr("primary"), URL: relayutils.MustParseURL("http://mainnet.solana.com")}, + {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://mainnet.solana.com")}, }, }, { ChainID: ptr("testnet"), Chain: solcfg.Chain{ - OCR2CachePollPeriod: relayutils.MustNewDuration(time.Minute), + OCR2CachePollPeriod: relaycfg.MustNewDuration(time.Minute), }, Nodes: []*solcfg.Node{ - {Name: ptr("secondary"), URL: relayutils.MustParseURL("http://testnet.solana.com")}, + {Name: ptr("secondary"), URL: relaycfg.MustParseURL("http://testnet.solana.com")}, }, }, }, @@ -179,10 +180,10 @@ var ( { ChainID: ptr("foobar"), Chain: stkcfg.Chain{ - ConfirmationPoll: relayutils.MustNewDuration(time.Hour), + ConfirmationPoll: relaycfg.MustNewDuration(time.Hour), }, Nodes: []*stkcfg.Node{ - {Name: ptr("primary"), URL: relayutils.MustParseURL("http://stark.node")}, + {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://stark.node")}, }, }, }, @@ -537,7 +538,7 @@ func TestConfig_Marshal(t *testing.T) { LogBackfillBatchSize: ptr[uint32](17), LogPollInterval: &minute, LogKeepBlocksDepth: ptr[uint32](100000), - MinContractPayment: assets.NewLinkFromJuels(math.MaxInt64), + MinContractPayment: relayassets.NewLinkFromJuels(math.MaxInt64), MinIncomingConfirmations: ptr[uint32](13), NonceAutoSync: ptr(true), NoNewHeadsThreshold: &minute, @@ -602,13 +603,13 @@ func TestConfig_Marshal(t *testing.T) { ChainID: ptr("mainnet"), Enabled: ptr(false), Chain: solcfg.Chain{ - BalancePollPeriod: relayutils.MustNewDuration(time.Minute), - ConfirmPollPeriod: relayutils.MustNewDuration(time.Second), - OCR2CachePollPeriod: relayutils.MustNewDuration(time.Minute), - OCR2CacheTTL: relayutils.MustNewDuration(time.Hour), - TxTimeout: relayutils.MustNewDuration(time.Hour), - TxRetryTimeout: relayutils.MustNewDuration(time.Minute), - TxConfirmTimeout: relayutils.MustNewDuration(time.Second), + BalancePollPeriod: relaycfg.MustNewDuration(time.Minute), + ConfirmPollPeriod: relaycfg.MustNewDuration(time.Second), + OCR2CachePollPeriod: relaycfg.MustNewDuration(time.Minute), + OCR2CacheTTL: relaycfg.MustNewDuration(time.Hour), + TxTimeout: relaycfg.MustNewDuration(time.Hour), + TxRetryTimeout: relaycfg.MustNewDuration(time.Minute), + TxConfirmTimeout: relaycfg.MustNewDuration(time.Second), SkipPreflight: ptr(true), Commitment: ptr("banana"), MaxRetries: ptr[int64](7), @@ -616,12 +617,12 @@ func TestConfig_Marshal(t *testing.T) { ComputeUnitPriceMax: ptr[uint64](1000), ComputeUnitPriceMin: ptr[uint64](10), ComputeUnitPriceDefault: ptr[uint64](100), - FeeBumpPeriod: relayutils.MustNewDuration(time.Minute), + FeeBumpPeriod: relaycfg.MustNewDuration(time.Minute), }, Nodes: []*solcfg.Node{ - {Name: ptr("primary"), URL: relayutils.MustParseURL("http://solana.web")}, - {Name: ptr("foo"), URL: relayutils.MustParseURL("http://solana.foo")}, - {Name: ptr("bar"), URL: relayutils.MustParseURL("http://solana.bar")}, + {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://solana.web")}, + {Name: ptr("foo"), URL: relaycfg.MustParseURL("http://solana.foo")}, + {Name: ptr("bar"), URL: relaycfg.MustParseURL("http://solana.bar")}, }, }, } @@ -630,14 +631,14 @@ func TestConfig_Marshal(t *testing.T) { ChainID: ptr("foobar"), Enabled: ptr(true), Chain: stkcfg.Chain{ - OCR2CachePollPeriod: relayutils.MustNewDuration(6 * time.Hour), - OCR2CacheTTL: relayutils.MustNewDuration(3 * time.Minute), - RequestTimeout: relayutils.MustNewDuration(time.Minute + 3*time.Second), - TxTimeout: relayutils.MustNewDuration(13 * time.Second), - ConfirmationPoll: relayutils.MustNewDuration(42 * time.Second), + OCR2CachePollPeriod: relaycfg.MustNewDuration(6 * time.Hour), + OCR2CacheTTL: relaycfg.MustNewDuration(3 * time.Minute), + RequestTimeout: relaycfg.MustNewDuration(time.Minute + 3*time.Second), + TxTimeout: relaycfg.MustNewDuration(13 * time.Second), + ConfirmationPoll: relaycfg.MustNewDuration(42 * time.Second), }, Nodes: []*stkcfg.Node{ - {Name: ptr("primary"), URL: relayutils.MustParseURL("http://stark.node")}, + {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://stark.node")}, }, }, } @@ -647,21 +648,21 @@ func TestConfig_Marshal(t *testing.T) { Enabled: ptr(true), Chain: coscfg.Chain{ Bech32Prefix: ptr("wasm"), - BlockRate: relayutils.MustNewDuration(time.Minute), + BlockRate: relaycfg.MustNewDuration(time.Minute), BlocksUntilTxTimeout: ptr[int64](12), - ConfirmPollPeriod: relayutils.MustNewDuration(time.Second), + ConfirmPollPeriod: relaycfg.MustNewDuration(time.Second), FallbackGasPrice: mustDecimal("0.001"), GasToken: ptr("ucosm"), GasLimitMultiplier: mustDecimal("1.2"), MaxMsgsPerBatch: ptr[int64](17), - OCR2CachePollPeriod: relayutils.MustNewDuration(time.Minute), - OCR2CacheTTL: relayutils.MustNewDuration(time.Hour), - TxMsgTimeout: relayutils.MustNewDuration(time.Second), + OCR2CachePollPeriod: relaycfg.MustNewDuration(time.Minute), + OCR2CacheTTL: relaycfg.MustNewDuration(time.Hour), + TxMsgTimeout: relaycfg.MustNewDuration(time.Second), }, Nodes: []*coscfg.Node{ - {Name: ptr("primary"), TendermintURL: relayutils.MustParseURL("http://tender.mint")}, - {Name: ptr("foo"), TendermintURL: relayutils.MustParseURL("http://foo.url")}, - {Name: ptr("bar"), TendermintURL: relayutils.MustParseURL("http://bar.web")}, + {Name: ptr("primary"), TendermintURL: relaycfg.MustParseURL("http://tender.mint")}, + {Name: ptr("foo"), TendermintURL: relaycfg.MustParseURL("http://foo.url")}, + {Name: ptr("bar"), TendermintURL: relaycfg.MustParseURL("http://bar.web")}, }, }, } diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 8729306964..293cc298c8 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/require" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relayutils "github.com/smartcontractkit/chainlink-relay/pkg/utils" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" @@ -84,7 +84,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 1 node 1"), - URL: ((*relayutils.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8547").URL())), }}, }, &solana.TOMLConfig{ @@ -93,7 +93,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 2 node 1"), - URL: ((*relayutils.URL)(models.MustParseURL("http://localhost:8527").URL())), + URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8527").URL())), }}, }, } @@ -106,15 +106,15 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 1 node 1"), - URL: ((*relayutils.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8547").URL())), }, { Name: ptr("starknet chain 1 node 2"), - URL: ((*relayutils.URL)(models.MustParseURL("http://localhost:8548").URL())), + URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8548").URL())), }, { Name: ptr("starknet chain 1 node 3"), - URL: ((*relayutils.URL)(models.MustParseURL("http://localhost:8549").URL())), + URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8549").URL())), }, }, }, @@ -125,7 +125,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 2 node 1"), - URL: ((*relayutils.URL)(models.MustParseURL("http://localhost:3547").URL())), + URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:3547").URL())), }, }, }, @@ -143,7 +143,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 1 node 1"), - TendermintURL: (*relayutils.URL)(models.MustParseURL("http://localhost:9548").URL()), + TendermintURL: (*relaycfg.URL)(models.MustParseURL("http://localhost:9548").URL()), }, }, }, @@ -158,7 +158,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 2 node 1"), - TendermintURL: (*relayutils.URL)(models.MustParseURL("http://localhost:9598").URL()), + TendermintURL: (*relaycfg.URL)(models.MustParseURL("http://localhost:9598").URL()), }, }, }, diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 920f94b4d6..10943308b3 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -9,9 +9,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 34c79a0afb..1c7929d94d 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" diff --git a/core/services/directrequest/validate.go b/core/services/directrequest/validate.go index 95ea9b6023..cdb478e8aa 100644 --- a/core/services/directrequest/validate.go +++ b/core/services/directrequest/validate.go @@ -4,7 +4,7 @@ import ( "github.com/pelletier/go-toml" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/services/fluxmonitorv2/config.go b/core/services/fluxmonitorv2/config.go index 5e5e56e768..0360e9ce03 100644 --- a/core/services/fluxmonitorv2/config.go +++ b/core/services/fluxmonitorv2/config.go @@ -3,7 +3,7 @@ package fluxmonitorv2 import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index e81e1ba9e6..e8bbf739bb 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -20,8 +20,8 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index 38c73d3ad7..729bcd76eb 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -26,8 +26,8 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" faw "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" diff --git a/core/services/fluxmonitorv2/payment_checker.go b/core/services/fluxmonitorv2/payment_checker.go index 6b11ec1343..b5dbd73c06 100644 --- a/core/services/fluxmonitorv2/payment_checker.go +++ b/core/services/fluxmonitorv2/payment_checker.go @@ -3,7 +3,7 @@ package fluxmonitorv2 import ( "math/big" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" ) // MinFundedRounds defines the minimum number of rounds that needs to be paid diff --git a/core/services/fluxmonitorv2/payment_checker_test.go b/core/services/fluxmonitorv2/payment_checker_test.go index c987fdf360..48a06553cb 100644 --- a/core/services/fluxmonitorv2/payment_checker_test.go +++ b/core/services/fluxmonitorv2/payment_checker_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" ) diff --git a/core/services/fluxmonitorv2/validate_test.go b/core/services/fluxmonitorv2/validate_test.go index 78dda2e3d3..b397e6d374 100644 --- a/core/services/fluxmonitorv2/validate_test.go +++ b/core/services/fluxmonitorv2/validate_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index c5dbff6f10..5b67e333d2 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -10,9 +10,9 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index fa9f74712b..1bf9f8e593 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -7,7 +7,7 @@ import ( "math/big" "testing" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/functions" diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index bb6812c1f9..a4301ef7e9 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -13,8 +13,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index 49fdae2bb2..4c8ba5bec3 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index f4471e75c6..c2fc425918 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -16,8 +16,8 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/job/models.go b/core/services/job/models.go index a474040dd4..0b3e622f59 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -14,10 +14,11 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -433,7 +434,7 @@ type DirectRequestSpec struct { ContractAddress ethkey.EIP55Address `toml:"contractAddress"` MinIncomingConfirmations clnull.Uint32 `toml:"minIncomingConfirmations"` Requesters models.AddressCollection `toml:"requesters"` - MinContractPayment *assets.Link `toml:"minContractPaymentLinkJuels"` + MinContractPayment *relayassets.Link `toml:"minContractPaymentLinkJuels"` EVMChainID *utils.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` @@ -474,7 +475,7 @@ type FluxMonitorSpec struct { DrumbeatSchedule string DrumbeatRandomDelay time.Duration DrumbeatEnabled bool - MinPayment *assets.Link + MinPayment *relayassets.Link EVMChainID *utils.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index f76ef93574..29a0b68702 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/link_token_interface" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" diff --git a/core/services/keeper/upkeep_executer.go b/core/services/keeper/upkeep_executer.go index 33ad8b7d77..30e9f36357 100644 --- a/core/services/keeper/upkeep_executer.go +++ b/core/services/keeper/upkeep_executer.go @@ -13,7 +13,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 32b1d2c191..a064c3ed4b 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -15,8 +15,8 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" diff --git a/core/services/keeper/upkeep_executer_unit_test.go b/core/services/keeper/upkeep_executer_unit_test.go index f4e99341ca..a8fc46319c 100644 --- a/core/services/keeper/upkeep_executer_unit_test.go +++ b/core/services/keeper/upkeep_executer_unit_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/services/keystore/keys/ethkey/address.go b/core/services/keystore/keys/ethkey/address.go index 4a161045ea..c14b602c59 100644 --- a/core/services/keystore/keys/ethkey/address.go +++ b/core/services/keystore/keys/ethkey/address.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink-relay/pkg/utils/bytes" ) // EIP55Address is a new type for string which persists an ethereum address in @@ -85,7 +85,7 @@ func (a *EIP55Address) UnmarshalText(input []byte) error { // UnmarshalJSON parses a hash from a JSON string func (a *EIP55Address) UnmarshalJSON(input []byte) error { - input = utils.RemoveQuotes(input) + input = bytes.TrimQuotes(input) return a.UnmarshalText(input) } diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index db19bdd4f0..3e614fef4a 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -22,11 +22,11 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/config" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" diff --git a/core/services/ocr/validate.go b/core/services/ocr/validate.go index 07fdc15912..145bb7597e 100644 --- a/core/services/ocr/validate.go +++ b/core/services/ocr/validate.go @@ -10,9 +10,9 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/libocr/offchainreporting" + "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" diff --git a/core/services/ocr2/plugins/functions/config/config.go b/core/services/ocr2/plugins/functions/config/config.go index 0978500deb..a179a22ce4 100644 --- a/core/services/ocr2/plugins/functions/config/config.go +++ b/core/services/ocr2/plugins/functions/config/config.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index 9f63d60eef..e576e82967 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -29,8 +29,8 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_allow_list" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_client_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 8597b8ad4c..14d7415cab 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -13,7 +13,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/functions/plugin_test.go b/core/services/ocr2/plugins/functions/plugin_test.go index 2e35672e92..eea751789a 100644 --- a/core/services/ocr2/plugins/functions/plugin_test.go +++ b/core/services/ocr2/plugins/functions/plugin_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index e7e059289a..ae2b4ca974 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -39,8 +39,8 @@ import ( relaycodecv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" relaycodecv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" token "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/fee_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/reward_manager" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index 9a1e99610c..0df774d5df 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -21,7 +21,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 562f972bc4..ee8b7cd6e9 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -33,7 +33,7 @@ import ( "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" automationForwarderLogic "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_forwarder_logic" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index f50321631c..569dc20753 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -34,7 +34,7 @@ import ( "github.com/stretchr/testify/require" "github.com/umbracle/ethgo/abi" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/config/toml" diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index 0dbb6a5915..57d13a69ec 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -31,7 +31,7 @@ import ( "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" diff --git a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go index 43262d6ad5..c0e969a287 100644 --- a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go +++ b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go @@ -6,7 +6,7 @@ import ( "github.com/smartcontractkit/ocr2vrf/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" ) diff --git a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_test.go b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_test.go index a33c146564..ec8b085dea 100644 --- a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" ) func Test_ReasonableGasPrice(t *testing.T) { diff --git a/core/services/ocrcommon/block_translator.go b/core/services/ocrcommon/block_translator.go index 48b9641699..dcac83fd2b 100644 --- a/core/services/ocrcommon/block_translator.go +++ b/core/services/ocrcommon/block_translator.go @@ -4,9 +4,9 @@ import ( "context" "math/big" + "github.com/smartcontractkit/chainlink/v2/common/config" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/services/ocrcommon/config.go b/core/services/ocrcommon/config.go index a61a47519c..2fcc877610 100644 --- a/core/services/ocrcommon/config.go +++ b/core/services/ocrcommon/config.go @@ -5,7 +5,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/common/config" ) type Config interface { diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 40542c2631..3aea503ae6 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -18,7 +18,7 @@ import ( relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/transmission/integration_test.go b/core/services/transmission/integration_test.go index 0484b1d8cd..58521dcdf8 100644 --- a/core/services/transmission/integration_test.go +++ b/core/services/transmission/integration_test.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface_v08" diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index e976d01b99..3b91f783b4 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -12,8 +12,8 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 389e1159be..3d544027d4 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -8,9 +8,9 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" diff --git a/core/services/vrf/mocks/fee_config.go b/core/services/vrf/mocks/fee_config.go index 55a6360c33..067ce7e445 100644 --- a/core/services/vrf/mocks/fee_config.go +++ b/core/services/vrf/mocks/fee_config.go @@ -4,7 +4,7 @@ package mocks import ( common "github.com/ethereum/go-ethereum/common" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" + assets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" config "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" diff --git a/core/services/vrf/proof/proof_response_test.go b/core/services/vrf/proof/proof_response_test.go index 24df77d4b3..c547be2be2 100644 --- a/core/services/vrf/proof/proof_response_test.go +++ b/core/services/vrf/proof/proof_response_test.go @@ -16,7 +16,7 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" ) diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go index f0c398f8cf..a8e662c931 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go index 9fab3737ae..2601f800e9 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/solidity_cross_tests" ) @@ -18,14 +17,14 @@ var ( jobID = common.BytesToHash([]byte("1234567890abcdef1234567890abcdef")) seed = big.NewInt(1) sender = common.HexToAddress("0xecfcab0a285d3380e488a39b4bb21e777f8a4eac") - fee = assets.NewLinkFromJuels(100) + fee = big.NewInt(100) requestID = common.HexToHash("0xcafe") raw = solidity_cross_tests.RawRandomnessRequestLog{ KeyHash: keyHash, Seed: seed, JobID: jobID, Sender: sender, - Fee: (*big.Int)(fee), + Fee: fee, RequestID: requestID, Raw: types.Log{ // A raw, on-the-wire RandomnessRequestLog is the concat of fields as uint256's @@ -33,7 +32,7 @@ var ( keyHash.Bytes(), common.BigToHash(seed).Bytes()...), sender.Hash().Bytes()...), - fee.ToHash().Bytes()...), + common.BigToHash(fee).Bytes()...), requestID.Bytes()...), Topics: []common.Hash{{}, jobID}, }, diff --git a/core/services/vrf/solidity_cross_tests/vrf_hash_to_curve_cost_test.go b/core/services/vrf/solidity_cross_tests/vrf_hash_to_curve_cost_test.go index 38675e2651..29d1db437d 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_hash_to_curve_cost_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_hash_to_curve_cost_test.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" diff --git a/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go b/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go index c2896d4231..06875edd74 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go @@ -19,7 +19,7 @@ import ( "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" diff --git a/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go b/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go index 695a9dfd2f..d1b21b5864 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" diff --git a/core/services/vrf/v2/bhs_feeder_test.go b/core/services/vrf/v2/bhs_feeder_test.go index 219fe1c8fd..f388f80f56 100644 --- a/core/services/vrf/v2/bhs_feeder_test.go +++ b/core/services/vrf/v2/bhs_feeder_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index a086cbbb09..a573737191 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/require" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 75026423f4..e45e650dc8 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 1f607da2f2..df886924aa 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -30,10 +30,11 @@ import ( "github.com/jmoiron/sqlx" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -1461,7 +1462,7 @@ func simulatedOverrides(t *testing.T, defaultGasPrice *assets.Wei, ks ...toml.Ke c.EVM[0].FinalityDepth = ptr[uint32](15) c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - c.EVM[0].MinContractPayment = assets.NewLinkFromJuels(100) + c.EVM[0].MinContractPayment = relayassets.NewLinkFromJuels(100) c.EVM[0].KeySpecific = ks } } diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 17cb9ec96e..3480f63f09 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -28,8 +28,8 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/services" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/services/vrf/v2/listener_v2_helpers_test.go b/core/services/vrf/v2/listener_v2_helpers_test.go index fc34a115b1..401a5bcc57 100644 --- a/core/services/vrf/v2/listener_v2_helpers_test.go +++ b/core/services/vrf/v2/listener_v2_helpers_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" v2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" diff --git a/core/services/vrf/vrfcommon/types.go b/core/services/vrf/vrfcommon/types.go index 03de4eb562..175b362b5a 100644 --- a/core/services/vrf/vrfcommon/types.go +++ b/core/services/vrf/vrfcommon/types.go @@ -5,7 +5,7 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" ) diff --git a/core/services/vrf/vrfcommon/validate.go b/core/services/vrf/vrfcommon/validate.go index d417336562..07e8676ddb 100644 --- a/core/services/vrf/vrfcommon/validate.go +++ b/core/services/vrf/vrfcommon/validate.go @@ -9,7 +9,7 @@ import ( "github.com/pelletier/go-toml" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" diff --git a/core/services/vrf/vrfcommon/validate_test.go b/core/services/vrf/vrfcommon/validate_test.go index 03d544f818..efb1f22216 100644 --- a/core/services/vrf/vrfcommon/validate_test.go +++ b/core/services/vrf/vrfcommon/validate_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services/job" ) diff --git a/core/services/vrf/vrftesthelpers/helpers.go b/core/services/vrf/vrftesthelpers/helpers.go index f36fb1ea02..2f269fbff0 100644 --- a/core/services/vrf/vrftesthelpers/helpers.go +++ b/core/services/vrf/vrftesthelpers/helpers.go @@ -17,7 +17,7 @@ import ( "github.com/shopspring/decimal" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" diff --git a/core/store/models/common.go b/core/store/models/common.go index fc7f776204..10f391861e 100644 --- a/core/store/models/common.go +++ b/core/store/models/common.go @@ -17,7 +17,7 @@ import ( "github.com/tidwall/gjson" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index beda735456..0155dc0a53 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -8,7 +8,7 @@ import ( "github.com/google/uuid" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/utils/big.go b/core/utils/big.go index 6bdb95c121..f0f9a2d96d 100644 --- a/core/utils/big.go +++ b/core/utils/big.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/smartcontractkit/chainlink-relay/pkg/utils/bytes" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) @@ -80,7 +81,7 @@ func (b Big) MarshalJSON() ([]byte, error) { // UnmarshalText implements encoding.TextUnmarshaler. func (b *Big) UnmarshalText(input []byte) error { - input = RemoveQuotes(input) + input = bytes.TrimQuotes(input) str := string(input) if HasHexPrefix(str) { decoded, err := hexutil.DecodeBig(str) diff --git a/core/utils/utils.go b/core/utils/utils.go index e5541ecf55..6ea7164df1 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -305,22 +305,6 @@ func Sha256(in string) (string, error) { return hex.EncodeToString(hasher.Sum(nil)), nil } -// IsQuoted checks if the first and last characters are either " or '. -func IsQuoted(input []byte) bool { - return len(input) >= 2 && - ((input[0] == '"' && input[len(input)-1] == '"') || - (input[0] == '\'' && input[len(input)-1] == '\'')) -} - -// RemoveQuotes removes the first and last character if they are both either -// " or ', otherwise it is a noop. -func RemoveQuotes(input []byte) []byte { - if IsQuoted(input) { - return input[1 : len(input)-1] - } - return input -} - // EIP55CapitalizedAddress returns true iff possibleAddressString has the correct // capitalization for an Ethereum address, per EIP 55 func EIP55CapitalizedAddress(possibleAddressString string) bool { diff --git a/core/web/bridge_types_controller.go b/core/web/bridge_types_controller.go index eca99f1a20..57a79e2b61 100644 --- a/core/web/bridge_types_controller.go +++ b/core/web/bridge_types_controller.go @@ -8,7 +8,7 @@ import ( "github.com/jackc/pgconn" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/web/bridge_types_controller_test.go b/core/web/bridge_types_controller_test.go index 6459cad054..a65362ba9a 100644 --- a/core/web/bridge_types_controller_test.go +++ b/core/web/bridge_types_controller_test.go @@ -6,7 +6,7 @@ import ( "net/http" "testing" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index 28afe8c43b..6e2a3b2efc 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -9,8 +9,9 @@ import ( "strconv" "strings" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" @@ -364,13 +365,13 @@ func (ekc *ETHKeysController) getEthBalance(ctx context.Context, state ethkey.St } -func (ekc *ETHKeysController) setLinkBalance(bal *assets.Link) presenters.NewETHKeyOption { +func (ekc *ETHKeysController) setLinkBalance(bal *relayassets.Link) presenters.NewETHKeyOption { return presenters.SetETHKeyLinkBalance(bal) } // queries the EthClient for the LINK balance at the address associated with state -func (ekc *ETHKeysController) getLinkBalance(ctx context.Context, state ethkey.State) *assets.Link { - var bal *assets.Link +func (ekc *ETHKeysController) getLinkBalance(ctx context.Context, state ethkey.State) *relayassets.Link { + var bal *relayassets.Link chainID := state.EVMChainID.ToInt() chain, err := ekc.app.GetRelayers().LegacyEVMChains().Get(chainID.String()) if err != nil { diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index e3a39d541a..8941c2d2fd 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -8,9 +8,9 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/web/evm_transactions_controller_test.go b/core/web/evm_transactions_controller_test.go index 9d8336325e..9135be432d 100644 --- a/core/web/evm_transactions_controller_test.go +++ b/core/web/evm_transactions_controller_test.go @@ -6,7 +6,7 @@ import ( "testing" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go index f5973a20f2..7f09bc9fdc 100644 --- a/core/web/evm_transfer_controller.go +++ b/core/web/evm_transfer_controller.go @@ -11,8 +11,8 @@ import ( "github.com/pkg/errors" commontxmgr "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index 14259637b4..c41219e189 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/web/presenters/bridges.go b/core/web/presenters/bridges.go index 3317895e16..440e444c61 100644 --- a/core/web/presenters/bridges.go +++ b/core/web/presenters/bridges.go @@ -3,7 +3,7 @@ package presenters import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" ) diff --git a/core/web/presenters/bridges_test.go b/core/web/presenters/bridges_test.go index b9fefd022d..f6ce3af756 100644 --- a/core/web/presenters/bridges_test.go +++ b/core/web/presenters/bridges_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/core/web/presenters/eth_key.go b/core/web/presenters/eth_key.go index 167679513e..9265442761 100644 --- a/core/web/presenters/eth_key.go +++ b/core/web/presenters/eth_key.go @@ -3,7 +3,8 @@ package presenters import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -12,14 +13,14 @@ import ( // representation of the address plus its ETH & LINK balances type ETHKeyResource struct { JAID - EVMChainID utils.Big `json:"evmChainID"` - Address string `json:"address"` - EthBalance *assets.Eth `json:"ethBalance"` - LinkBalance *assets.Link `json:"linkBalance"` - Disabled bool `json:"disabled"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - MaxGasPriceWei *utils.Big `json:"maxGasPriceWei"` + EVMChainID utils.Big `json:"evmChainID"` + Address string `json:"address"` + EthBalance *assets.Eth `json:"ethBalance"` + LinkBalance *relayassets.Link `json:"linkBalance"` + Disabled bool `json:"disabled"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + MaxGasPriceWei *utils.Big `json:"maxGasPriceWei"` } // GetName implements the api2go EntityNamer interface @@ -62,7 +63,7 @@ func SetETHKeyEthBalance(ethBalance *assets.Eth) NewETHKeyOption { } } -func SetETHKeyLinkBalance(linkBalance *assets.Link) NewETHKeyOption { +func SetETHKeyLinkBalance(linkBalance *relayassets.Link) NewETHKeyOption { return func(r *ETHKeyResource) { r.LinkBalance = linkBalance } diff --git a/core/web/presenters/eth_key_test.go b/core/web/presenters/eth_key_test.go index 7afb55068f..0e68fbc90c 100644 --- a/core/web/presenters/eth_key_test.go +++ b/core/web/presenters/eth_key_test.go @@ -5,7 +5,8 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -39,12 +40,12 @@ func TestETHKeyResource(t *testing.T) { r := NewETHKeyResource(key, state, SetETHKeyEthBalance(assets.NewEth(1)), - SetETHKeyLinkBalance(assets.NewLinkFromJuels(1)), + SetETHKeyLinkBalance(relayassets.NewLinkFromJuels(1)), SetETHKeyMaxGasPriceWei(utils.NewBigI(12345)), ) assert.Equal(t, assets.NewEth(1), r.EthBalance) - assert.Equal(t, assets.NewLinkFromJuels(1), r.LinkBalance) + assert.Equal(t, relayassets.NewLinkFromJuels(1), r.LinkBalance) assert.Equal(t, utils.NewBigI(12345), r.MaxGasPriceWei) b, err := jsonapi.Marshal(r) diff --git a/core/web/presenters/eth_tx.go b/core/web/presenters/eth_tx.go index 8878733d70..2c2b5b90ff 100644 --- a/core/web/presenters/eth_tx.go +++ b/core/web/presenters/eth_tx.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/web/presenters/eth_tx_test.go b/core/web/presenters/eth_tx_test.go index 10f4ceab00..2ed8e23c76 100644 --- a/core/web/presenters/eth_tx_test.go +++ b/core/web/presenters/eth_tx_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index 06b9950755..d9ec1844ae 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -7,7 +7,8 @@ import ( "github.com/lib/pq" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -43,7 +44,7 @@ const ( type DirectRequestSpec struct { ContractAddress ethkey.EIP55Address `json:"contractAddress"` MinIncomingConfirmations clnull.Uint32 `json:"minIncomingConfirmations"` - MinContractPayment *assets.Link `json:"minContractPaymentLinkJuels"` + MinContractPayment *relayassets.Link `json:"minContractPaymentLinkJuels"` Requesters models.AddressCollection `json:"requesters"` Initiator string `json:"initiator"` CreatedAt time.Time `json:"createdAt"` @@ -80,7 +81,7 @@ type FluxMonitorSpec struct { DrumbeatEnabled bool `json:"drumbeatEnabled"` DrumbeatSchedule *string `json:"drumbeatSchedule"` DrumbeatRandomDelay *string `json:"drumbeatRandomDelay"` - MinPayment *assets.Link `json:"minPayment"` + MinPayment *relayassets.Link `json:"minPayment"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` EVMChainID *utils.Big `json:"evmChainID"` diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index bb79c8e953..46c765a38b 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/web/resolver/bridge_test.go b/core/web/resolver/bridge_test.go index b12186e112..e708ac92a4 100644 --- a/core/web/resolver/bridge_test.go +++ b/core/web/resolver/bridge_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index a7f8ce56d9..f8f417ca44 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -9,8 +9,9 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/mock" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -95,7 +96,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) f.Mocks.ethKs.On("GetAll").Return(keys, nil) - f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(assets.NewLinkFromJuels(12), nil) + f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(relayassets.NewLinkFromJuels(12), nil) f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) f.Mocks.balM.On("GetEthBalance", address).Return(assets.NewEth(1)) f.Mocks.chain.On("BalanceMonitor").Return(f.Mocks.balM) @@ -300,7 +301,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) f.Mocks.ethKs.On("GetAll").Return(keys, nil) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) - f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(assets.NewLinkFromJuels(12), gError) + f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(relayassets.NewLinkFromJuels(12), gError) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(f.Mocks.chain, nil) f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) @@ -353,7 +354,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) f.Mocks.ethKs.On("GetAll").Return(keys, nil) - f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(assets.NewLinkFromJuels(12), nil) + f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(relayassets.NewLinkFromJuels(12), nil) f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) f.Mocks.chain.On("BalanceMonitor").Return(nil) f.Mocks.chain.On("Config").Return(f.Mocks.scfg) diff --git a/core/web/resolver/eth_transaction.go b/core/web/resolver/eth_transaction.go index 31a96727a9..1292b6bc10 100644 --- a/core/web/resolver/eth_transaction.go +++ b/core/web/resolver/eth_transaction.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/graph-gophers/graphql-go" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" "github.com/smartcontractkit/chainlink/v2/core/web/loader" diff --git a/core/web/resolver/eth_transaction_test.go b/core/web/resolver/eth_transaction_test.go index 8a1685e4f7..a719c838e8 100644 --- a/core/web/resolver/eth_transaction_test.go +++ b/core/web/resolver/eth_transaction_test.go @@ -10,7 +10,7 @@ import ( gqlerrors "github.com/graph-gophers/graphql-go/errors" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/web/resolver/helpers.go b/core/web/resolver/helpers.go index 5c855a1c16..2dc865674e 100644 --- a/core/web/resolver/helpers.go +++ b/core/web/resolver/helpers.go @@ -8,7 +8,7 @@ import ( "github.com/graph-gophers/graphql-go" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" ) diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index f9eee0734a..52f914e0a8 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -13,7 +13,7 @@ import ( "go.uber.org/zap/zapcore" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 8e4095e171..fd369088bb 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -9,9 +9,10 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -96,7 +97,7 @@ func TestResolver_DirectRequestSpec(t *testing.T) { CreatedAt: f.Timestamp(), EVMChainID: utils.NewBigI(42), MinIncomingConfirmations: clnull.NewUint32(1, true), - MinContractPayment: assets.NewLinkFromJuels(1000), + MinContractPayment: relayassets.NewLinkFromJuels(1000), Requesters: models.AddressCollection{requesterAddress}, }, }, nil) @@ -163,7 +164,7 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { DrumbeatEnabled: false, IdleTimerDisabled: false, IdleTimerPeriod: time.Duration(1 * time.Hour), - MinPayment: assets.NewLinkFromJuels(1000), + MinPayment: relayassets.NewLinkFromJuels(1000), PollTimerDisabled: false, PollTimerPeriod: time.Duration(1 * time.Minute), }, @@ -232,7 +233,7 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { DrumbeatSchedule: "CRON_TZ=UTC 0 0 1 1 *", IdleTimerDisabled: true, IdleTimerPeriod: time.Duration(1 * time.Hour), - MinPayment: assets.NewLinkFromJuels(1000), + MinPayment: relayassets.NewLinkFromJuels(1000), PollTimerDisabled: true, PollTimerPeriod: time.Duration(1 * time.Minute), }, diff --git a/core/web/solana_chains_controller_test.go b/core/web/solana_chains_controller_test.go index 724d5cd2c3..c4023f166b 100644 --- a/core/web/solana_chains_controller_test.go +++ b/core/web/solana_chains_controller_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" @@ -84,7 +84,7 @@ Nodes = [] ChainID: ptr(validId), Chain: config.Chain{ SkipPreflight: ptr(false), - TxTimeout: utils.MustNewDuration(time.Hour), + TxTimeout: relaycfg.MustNewDuration(time.Hour), }, }) @@ -114,7 +114,7 @@ func Test_SolanaChainsController_Index(t *testing.T) { chainA := &solana.TOMLConfig{ ChainID: ptr(fmt.Sprintf("ChainlinktestA-%d", rand.Int31n(999999))), Chain: config.Chain{ - TxTimeout: utils.MustNewDuration(time.Hour), + TxTimeout: relaycfg.MustNewDuration(time.Hour), }, } chainB := &solana.TOMLConfig{ diff --git a/go.mod b/go.mod index 0a85fe7f48..40803d504c 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.20231113174149-046d4ddaca1a + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd 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 7fe91a6b12..52975e722a 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.20231113174149-046d4ddaca1a h1:G/pD8uI1PULRJU8Y3eLLzjqQBp9ruG9hj+wWxtyrgTo= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd h1:PRVJxNK67pQWufXuB1cxckH/xZkcQFDy8KjN9ZYqong= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd/go.mod h1:rOayi690YxLlkQy959PD8INhOAIAUi9LoN0G+J/CEf4= 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/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 28fb2635ff..254f2ca6ce 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -9,7 +9,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils" - "github.com/smartcontractkit/chainlink/v2/core/assets" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" "github.com/ethereum/go-ethereum/common" @@ -868,7 +869,7 @@ func retreiveLoadTestMetrics( func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2_5.GetSubscription, subID *big.Int, coordinator contracts.VRFCoordinatorV2_5) { l.Debug(). Str("Coordinator", coordinator.Address()). - Str("Link Balance", (*assets.Link)(subscription.Balance).Link()). + Str("Link Balance", (*relayassets.Link)(subscription.Balance).Link()). Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)). Str("Subscription ID", subID.String()). Str("Subscription Owner", subscription.Owner.String()). @@ -971,11 +972,11 @@ func LogFulfillmentDetailsLinkBilling( randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, ) { l.Debug(). - Str("Consumer Balance Before Request (Link)", (*assets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). - Str("Consumer Balance After Request (Link)", (*assets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). + Str("Consumer Balance Before Request (Link)", (*relayassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). + Str("Consumer Balance After Request (Link)", (*relayassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid by Consumer Contract (Link)", (*assets.Link)(consumerStatus.Paid).Link()). - Str("Paid by Coordinator Sub (Link)", (*assets.Link)(randomWordsFulfilledEvent.Payment).Link()). + Str("Paid by Consumer Contract (Link)", (*relayassets.Link)(consumerStatus.Paid).Link()). + Str("Paid by Coordinator Sub (Link)", (*relayassets.Link)(randomWordsFulfilledEvent.Payment).Link()). Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a943e1c41a..a450dd235a 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,6 +22,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd github.com/smartcontractkit/chainlink-testing-framework v1.18.6 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 @@ -387,7 +388,6 @@ 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.20231113174149-046d4ddaca1a // 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 5719c36b5a..f882a7bb57 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.20231113174149-046d4ddaca1a h1:G/pD8uI1PULRJU8Y3eLLzjqQBp9ruG9hj+wWxtyrgTo= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231113174149-046d4ddaca1a/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd h1:PRVJxNK67pQWufXuB1cxckH/xZkcQFDy8KjN9ZYqong= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd/go.mod h1:rOayi690YxLlkQy959PD8INhOAIAUi9LoN0G+J/CEf4= 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/types/config/node/core.go b/integration-tests/types/config/node/core.go index 37047cdb66..7ddddafdd5 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -11,8 +11,9 @@ import ( "github.com/segmentio/ksuid" + relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -167,7 +168,7 @@ func SetChainConfig( chainConfig = evmcfg.Chain{ AutoCreateKey: utils2.Ptr(true), FinalityDepth: utils2.Ptr[uint32](1), - MinContractPayment: assets.NewLinkFromJuels(0), + MinContractPayment: relayassets.NewLinkFromJuels(0), } } cfg.EVM = evmcfg.EVMConfigs{ @@ -193,7 +194,7 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { Chain: evmcfg.Chain{ AutoCreateKey: utils2.Ptr(true), FinalityDepth: utils2.Ptr[uint32](50), - MinContractPayment: assets.NewLinkFromJuels(0), + MinContractPayment: relayassets.NewLinkFromJuels(0), LogPollInterval: models.MustNewDuration(1 * time.Second), HeadTracker: evmcfg.HeadTracker{ HistoryDepth: utils2.Ptr(uint32(100)), diff --git a/tools/flakeytests/runner_test.go b/tools/flakeytests/runner_test.go index c4509ff2cc..31f300dcbe 100644 --- a/tools/flakeytests/runner_test.go +++ b/tools/flakeytests/runner_test.go @@ -25,7 +25,7 @@ func newMockReporter() *mockReporter { } func TestParser(t *testing.T) { - output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0} ` r := strings.NewReader(output) @@ -33,14 +33,14 @@ func TestParser(t *testing.T) { require.NoError(t, err) assert.Len(t, ts, 1) - assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/assets"], 1) - assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestLink"], 1) + assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) + assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"], 1) } func TestParser_SkipsNonJSON(t *testing.T) { output := `Failed tests and panics: ------- -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0} ` r := strings.NewReader(output) @@ -48,13 +48,13 @@ func TestParser_SkipsNonJSON(t *testing.T) { require.NoError(t, err) assert.Len(t, ts, 1) - assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/assets"], 1) - assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestLink"], 1) + assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) + assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"], 1) } func TestParser_PanicDueToLogging(t *testing.T) { output := ` -{"Time":"2023-09-07T16:01:40.649849+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_LinkScanValue","Output":"panic: foo\n"} +{"Time":"2023-09-07T16:01:40.649849+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_LinkScanValue","Output":"panic: foo\n"} ` r := strings.NewReader(output) @@ -62,24 +62,24 @@ func TestParser_PanicDueToLogging(t *testing.T) { require.NoError(t, err) assert.Len(t, ts, 1) - assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/assets"], 1) - assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestAssets_LinkScanValue"], 1) + assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) + assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestAssets_LinkScanValue"], 1) } func TestParser_SuccessfulOutput(t *testing.T) { output := ` -{"Time":"2023-09-07T16:22:52.556853+01:00","Action":"start","Package":"github.com/smartcontractkit/chainlink/v2/core/assets"} -{"Time":"2023-09-07T16:22:52.762353+01:00","Action":"run","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} -{"Time":"2023-09-07T16:22:52.762456+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== RUN TestAssets_NewLinkAndString\n"} -{"Time":"2023-09-07T16:22:52.76249+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== PAUSE TestAssets_NewLinkAndString\n"} -{"Time":"2023-09-07T16:22:52.7625+01:00","Action":"pause","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} -{"Time":"2023-09-07T16:22:52.762511+01:00","Action":"cont","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} -{"Time":"2023-09-07T16:22:52.762528+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== CONT TestAssets_NewLinkAndString\n"} -{"Time":"2023-09-07T16:22:52.762546+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"--- PASS: TestAssets_NewLinkAndString (0.00s)\n"} -{"Time":"2023-09-07T16:22:52.762557+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Elapsed":0} -{"Time":"2023-09-07T16:22:52.762566+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Output":"PASS\n"} -{"Time":"2023-09-07T16:22:52.762955+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Output":"ok \tgithub.com/smartcontractkit/chainlink/v2/core/assets\t0.206s\n"} -{"Time":"2023-09-07T16:22:52.765598+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Elapsed":0.209} +{"Time":"2023-09-07T16:22:52.556853+01:00","Action":"start","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"} +{"Time":"2023-09-07T16:22:52.762353+01:00","Action":"run","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762456+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString","Output":"=== RUN TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.76249+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString","Output":"=== PAUSE TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.7625+01:00","Action":"pause","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762511+01:00","Action":"cont","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762528+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString","Output":"=== CONT TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.762546+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString","Output":"--- PASS: TestAssets_NewLinkAndString (0.00s)\n"} +{"Time":"2023-09-07T16:22:52.762557+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestAssets_NewLinkAndString","Elapsed":0} +{"Time":"2023-09-07T16:22:52.762566+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Output":"PASS\n"} +{"Time":"2023-09-07T16:22:52.762955+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Output":"ok \tgithub.com/smartcontractkit/chainlink/v2/core/assets\t0.206s\n"} +{"Time":"2023-09-07T16:22:52.765598+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Elapsed":0.209} ` r := strings.NewReader(output) @@ -95,9 +95,9 @@ func (t testAdapter) test(pkg string, tests []string, out io.Writer) error { } func TestRunner_WithFlake(t *testing.T) { - initialOutput := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` + initialOutput := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}` outputs := []string{ - `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`, + `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}`, ``, } m := newMockReporter() @@ -120,18 +120,18 @@ func TestRunner_WithFlake(t *testing.T) { err := r.Run() require.NoError(t, err) assert.Len(t, m.entries, 1) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestLink"] + _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } func TestRunner_WithFailedPackage(t *testing.T) { initialOutput := ` -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Elapsed":0} ` outputs := []string{` -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Elapsed":0} `, ``, } @@ -155,16 +155,16 @@ func TestRunner_WithFailedPackage(t *testing.T) { err := r.Run() require.NoError(t, err) assert.Len(t, m.entries, 1) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestLink"] + _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } func TestRunner_AllFailures(t *testing.T) { - output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}` rerunOutput := ` -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0} ` m := newMockReporter() r := &Runner{ @@ -184,11 +184,11 @@ func TestRunner_AllFailures(t *testing.T) { } func TestRunner_RerunSuccessful(t *testing.T) { - output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}` rerunOutputs := []string{ - `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`, - `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`, + `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}`, + `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}`, } m := newMockReporter() i := 0 @@ -206,7 +206,7 @@ func TestRunner_RerunSuccessful(t *testing.T) { err := r.Run() require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestLink"] + _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -233,11 +233,11 @@ func TestRunner_RootLevelTest(t *testing.T) { } func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { - output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}` rerunOutputs := []string{ - `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`, - `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`, + `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}`, + `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}`, } m := newMockReporter() i := 0 @@ -255,14 +255,14 @@ func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { err := r.Run() require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestLink"] + _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } func TestRunner_RerunWithNonZeroExitCodeDoesntStopCommand(t *testing.T) { outputs := []io.Reader{ strings.NewReader(` -{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0} `), strings.NewReader(` {"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2","Test":"TestMaybeReservedLinkV2","Elapsed":0} @@ -270,8 +270,8 @@ func TestRunner_RerunWithNonZeroExitCodeDoesntStopCommand(t *testing.T) { } rerunOutputs := []string{ - `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`, - `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`, + `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}`, + `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets","Test":"TestLink","Elapsed":0}`, `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2","Test":"TestMaybeReservedLinkV2","Elapsed":0}`, `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2","Test":"TestMaybeReservedLinkV2","Elapsed":0}`, } @@ -295,7 +295,7 @@ func TestRunner_RerunWithNonZeroExitCodeDoesntStopCommand(t *testing.T) { calls := index assert.Equal(t, 4, calls) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/assets"]["TestLink"] + _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } From 6fd7be8e9e565ee3358d125f88c6f67017248e57 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Thu, 16 Nov 2023 10:35:07 -0500 Subject: [PATCH 161/327] [TT-688] Batch Keeper Benchmark Read Requests (#11294) * Batch Keeper Benchmark Read Requests * Actually add number --- .../testsetups/keeper_benchmark.go | 60 +++++++++++++------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index bb6c582c13..d9b389a965 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -293,32 +293,54 @@ func (k *KeeperBenchmarkTest) Run() { require.NoError(k.t, err, "Error waiting for keeper subscriptions") // Collect logs for each registry to calculate test metrics - registryLogs := make([][]types.Log, len(k.keeperRegistries)) + // This test generates a LOT of logs, and we need to break up our reads, or risk getting rate-limited by the node + var ( + endBlock = big.NewInt(0).Add(k.startingBlock, big.NewInt(u.BlockRange)) + registryLogs = make([][]types.Log, len(k.keeperRegistries)) + blockBatchSize int64 = 100 + ) for rIndex := range k.keeperRegistries { + // Variables for the full registry var ( - logs []types.Log - timeout = 5 * time.Second - addr = k.keeperRegistries[rIndex].Address() - filterQuery = geth.FilterQuery{ + logs []types.Log + timeout = 5 * time.Second + addr = k.keeperRegistries[rIndex].Address() + queryStartBlock = big.NewInt(0).Set(k.startingBlock) + ) + + // Gather logs from the registry in 100 block chunks to avoid read limits + for queryStartBlock.Cmp(endBlock) < 0 { + filterQuery := geth.FilterQuery{ Addresses: []common.Address{common.HexToAddress(addr)}, - FromBlock: k.startingBlock, + FromBlock: queryStartBlock, + ToBlock: big.NewInt(0).Add(queryStartBlock, big.NewInt(blockBatchSize)), } + + // This RPC call can possibly time out or otherwise die. Failure is not an option, keep retrying to get our stats. err = fmt.Errorf("initial error") // to ensure our for loop runs at least once - ) - for err != nil { // This RPC call can possibly time out or otherwise die. Failure is not an option, keep retrying to get our stats. - ctx, cancel := context.WithTimeout(utils.TestContext(k.t), timeout) - logs, err = k.chainClient.FilterLogs(ctx, filterQuery) - cancel() - if err != nil { - k.log.Error().Err(err). - Interface("Filter Query", filterQuery). - Str("Timeout", timeout.String()). - Msg("Error getting logs from chain, trying again") - } else { - k.log.Info().Int("Log Count", len(logs)).Str("Registry Address", addr).Msg("Collected logs") + for err != nil { + ctx, cancel := context.WithTimeout(utils.TestContext(k.t), timeout) + logs, err = k.chainClient.FilterLogs(ctx, filterQuery) + cancel() + if err != nil { + k.log.Error(). + Err(err). + Interface("Filter Query", filterQuery). + Str("Timeout", timeout.String()). + Msg("Error getting logs from chain, trying again") + timeout = time.Duration(math.Min(float64(timeout)*2, float64(2*time.Minute))) + continue + } + k.log.Info(). + Uint64("From Block", queryStartBlock.Uint64()). + Uint64("To Block", filterQuery.ToBlock.Uint64()). + Int("Log Count", len(logs)). + Str("Registry Address", addr). + Msg("Collected logs") + queryStartBlock.Add(queryStartBlock, big.NewInt(blockBatchSize)) + registryLogs[rIndex] = append(registryLogs[rIndex], logs...) } } - registryLogs[rIndex] = logs } // Count reverts and stale upkeeps From 01fbf8e445b2ae4db616d0fc8e10fa4d44895e0b Mon Sep 17 00:00:00 2001 From: amit-momin <108959691+amit-momin@users.noreply.github.com> Date: Thu, 16 Nov 2023 10:34:08 -0600 Subject: [PATCH 162/327] Update loading next sequence map to avoid startup failure (#11307) * Updated loading next sequence map to avoid startup failure * Moved logic to populate next sequence map during runtime * Added changelog * Addressed feedback * Addressed feedback --- common/txmgr/broadcaster.go | 77 ++++++---- core/chains/evm/txmgr/broadcaster_test.go | 175 +++++++++++++++------- docs/CHANGELOG.md | 6 + 3 files changed, 176 insertions(+), 82 deletions(-) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 00522abf22..1e3b2fa0a9 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "fmt" + "slices" "sync" "time" @@ -228,10 +229,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star eb.sequenceLock.Lock() defer eb.sequenceLock.Unlock() - eb.nextSequenceMap, err = eb.loadNextSequenceMap(eb.enabledAddresses) - if err != nil { - return errors.Wrap(err, "Broadcaster: failed to load next sequence map") - } + eb.nextSequenceMap = eb.loadNextSequenceMap(eb.enabledAddresses) eb.isStarted = true return nil @@ -287,30 +285,38 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trig } // Load the next sequence map using the tx table or on-chain (if not found in tx table) -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(addresses []ADDR) (map[ADDR]SEQ, error) { +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(addresses []ADDR) map[ADDR]SEQ { ctx, cancel := eb.chStop.NewCtx() defer cancel() nextSequenceMap := make(map[ADDR]SEQ) for _, address := range addresses { - // Get the highest sequence from the tx table - // Will need to be incremented since this sequence is already used - seq, err := eb.txStore.FindLatestSequence(ctx, address, eb.chainID) - if err != nil { - // Look for nonce on-chain if no tx found for address in TxStore or if error occurred - // Returns the nonce that should be used for the next transaction so no need to increment - seq, err = eb.client.PendingSequenceAt(ctx, address) - if err != nil { - return nil, errors.New("failed to retrieve next sequence from on-chain causing failure to load next sequence map on broadcaster startup") - } - + seq, err := eb.getSequenceForAddr(ctx, address) + if err == nil { nextSequenceMap[address] = seq - } else { - nextSequenceMap[address] = eb.generateNextSequence(seq) } } - return nextSequenceMap, nil + return nextSequenceMap +} + +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) getSequenceForAddr(ctx context.Context, address ADDR) (seq SEQ, err error) { + // Get the highest sequence from the tx table + // Will need to be incremented since this sequence is already used + seq, err = eb.txStore.FindLatestSequence(ctx, address, eb.chainID) + if err == nil { + seq = eb.generateNextSequence(seq) + return seq, nil + } + // Look for nonce on-chain if no tx found for address in TxStore or if error occurred + // Returns the nonce that should be used for the next transaction so no need to increment + seq, err = eb.client.PendingSequenceAt(ctx, address) + if err == nil { + return seq, nil + } + eb.logger.Criticalw("failed to retrieve next sequence from on-chain for address: ", "address", address.String()) + return seq, err + } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) newSequenceSyncBackoff() backoff.Backoff { @@ -393,7 +399,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) moni // syncSequence tries to sync the key sequence, retrying indefinitely until success or stop signal is sent func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SyncSequence(ctx context.Context, addr ADDR) { sequenceSyncRetryBackoff := eb.newSequenceSyncBackoff() - localSequence, err := eb.GetNextSequence(addr) + localSequence, err := eb.GetNextSequence(ctx, addr) // Address not found in map so skip sync if err != nil { eb.logger.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) @@ -607,7 +613,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand observeTimeUntilBroadcast(eb.chainID, etx.CreatedAt, time.Now()) // Check if from_address exists in map to ensure it is valid before broadcasting var sequence SEQ - sequence, err = eb.GetNextSequence(etx.FromAddress) + sequence, err = eb.GetNextSequence(ctx, etx.FromAddress) if err != nil { return err, true } @@ -665,7 +671,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // Check if from_address exists in map to ensure it is valid before broadcasting var sequence SEQ - sequence, err = eb.GetNextSequence(etx.FromAddress) + sequence, err = eb.GetNextSequence(ctx, etx.FromAddress) if err != nil { return err, true } @@ -702,7 +708,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next return nil, errors.Wrap(err, "findNextUnstartedTransactionFromAddress failed") } - sequence, err := eb.GetNextSequence(etx.FromAddress) + sequence, err := eb.GetNextSequence(ctx, etx.FromAddress) if err != nil { return nil, err } @@ -792,15 +798,32 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save } // Used to get the next usable sequence for a transaction -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetNextSequence(address ADDR) (seq SEQ, err error) { +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetNextSequence(ctx context.Context, address ADDR) (seq SEQ, err error) { eb.sequenceLock.Lock() defer eb.sequenceLock.Unlock() // Get next sequence from map seq, exists := eb.nextSequenceMap[address] - if !exists { - return seq, errors.New(fmt.Sprint("address not found in next sequence map: ", address)) + if exists { + return seq, nil + } + + eb.logger.Infow("address not found in local next sequence map. Attempting to search and populate sequence.", "address", address.String()) + // Check if address is in the enabled address list + if !slices.Contains(eb.enabledAddresses, address) { + return seq, fmt.Errorf("address disabled: %s", address) } - return seq, nil + + // Try to retrieve next sequence from tx table or on-chain to load the map + // A scenario could exist where loading the map during startup failed (e.g. All configured RPC's are unreachable at start) + // The expectation is that the node does not fail startup so sequences need to be loaded during runtime + foundSeq, err := eb.getSequenceForAddr(ctx, address) + if err != nil { + return seq, fmt.Errorf("failed to find next sequence for address: %s", address) + } + + // Set sequence in map + eb.nextSequenceMap[address] = foundSeq + return foundSeq, nil } // Used to increment the sequence in the mapping to have the next usable one available for the next transaction diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 48b68f9b55..7967478e62 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -130,6 +130,38 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { require.NoError(t, eb.XXXTestCloseInternal()) } +// Failure to load next sequnce map should not fail Broadcaster startup +func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) { + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + estimator := gasmocks.NewEvmFeeEstimator(t) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), errors.New("Getting on-chain nonce failed")) + eb := txmgr.NewEvmBroadcaster( + txStore, + txmgr.NewEvmTxmClient(ethClient), + txmgr.NewEvmTxmConfig(evmcfg.EVM()), + txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), + evmcfg.EVM().Transactions(), + evmcfg.Database().Listener(), + ethKeyStore, + txBuilder, + nil, + logger.TestLogger(t), + &testCheckerFactory{}, + false, + ) + + // Instance starts without error even if loading next sequence map fails + err := eb.Start(testutils.Context(t)) + require.NoError(t, err) +} + func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) @@ -946,7 +978,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { } func getLocalNextNonce(t *testing.T, eb *txmgr.Broadcaster, fromAddress gethCommon.Address) uint64 { - n, err := eb.GetNextSequence(fromAddress) + n, err := eb.GetNextSequence(testutils.Context(t), fromAddress) require.NoError(t, err) require.NotNil(t, n) return uint64(n) @@ -972,6 +1004,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + ctx := testutils.Context(t) require.NoError(t, utils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) @@ -983,7 +1016,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(commonclient.Successful, errors.New("replacement transaction underpriced")).Once() // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1019,7 +1052,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Fatal, errors.New(fatalErrorExample)).Once() - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1036,7 +1069,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Check that the key had its nonce reset var nonce evmtypes.Nonce - nonce, err = eb.GetNextSequence(fromAddress) + nonce, err = eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be @@ -1070,7 +1103,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Fatal, errors.New(fatalErrorExample)).Once() - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) require.Contains(t, err.Error(), "something exploded in the callback") assert.True(t, retryable) @@ -1092,7 +1125,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(commonclient.Fatal, errors.New(fatalErrorExample)).Once() { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) } @@ -1105,7 +1138,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce = getLocalNextNonce(t, eb, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() eb2 := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, nil, lggr, &testCheckerFactory{}, false) - retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) }) @@ -1127,7 +1160,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // another node even if the primary one returns "exceeds the configured // cap" - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) assert.Contains(t, err.Error(), "tx fee (1.10 ether) exceeds the configured cap (1.00 ether)") assert.Contains(t, err.Error(), "error while sending transaction") @@ -1147,7 +1180,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Check that the key had its nonce reset var nonce evmtypes.Nonce - nonce, err = eb.GetNextSequence(fromAddress) + nonce, err = eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be @@ -1156,7 +1189,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // On the second try, the tx has been accepted into the mempool ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() - retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err = eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1184,7 +1217,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) require.Contains(t, err.Error(), retryableErrorExample) assert.True(t, retryable) @@ -1207,7 +1240,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Successful, nil).Once() - retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err = eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1235,7 +1268,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("pending nonce fetch failed")).Once() // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) require.Contains(t, err.Error(), retryableErrorExample) require.Contains(t, err.Error(), "pending nonce fetch failed") @@ -1259,7 +1292,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Successful, nil).Once() - retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err = eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1288,7 +1321,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.NoError(t, err) assert.False(t, retryable) @@ -1330,7 +1363,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(commonclient.Successful, nil).Once() // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.NoError(t, err) assert.False(t, retryable) @@ -1366,7 +1399,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(commonclient.Retryable, failedToReachNodeError).Once() // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) assert.Contains(t, err.Error(), "context deadline exceeded") assert.True(t, retryable) @@ -1397,7 +1430,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(commonclient.Successful, errors.New(temporarilyUnderpricedError)).Once() // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1437,7 +1470,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Do the thing - retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) require.Contains(t, err.Error(), "bumped fee price of 20 gwei is equal to original fee price of 20 gwei. ACTION REQUIRED: This is a configuration error, you must increase either FeeEstimator.BumpPercent or FeeEstimator.BumpMin") assert.True(t, retryable) @@ -1454,7 +1487,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.InsufficientFunds, errors.New(insufficientEthError)).Once() - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) assert.Contains(t, err.Error(), "insufficient funds for transfer") assert.True(t, retryable) @@ -1484,7 +1517,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Retryable, errors.New(nonceGapError)).Once() - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) assert.Contains(t, err.Error(), nonceGapError) assert.True(t, retryable) @@ -1529,7 +1562,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() // Check gas tip cap verification - retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) require.Contains(t, err.Error(), "bumped gas tip cap of 1 wei is less than or equal to original gas tip cap of 1 wei") assert.True(t, retryable) @@ -1553,7 +1586,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) - retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) require.Contains(t, err.Error(), "specified gas tip cap of 0 is below min configured gas tip of 1 wei for key") assert.True(t, retryable) @@ -1580,7 +1613,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), big.NewInt(0).Mul(evmcfg2.EVM().GasEstimator().BumpMin().ToInt(), big.NewInt(2)))) == 0 }), fromAddress).Return(commonclient.Successful, nil).Once() - retryable, err = eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err = eb2.ProcessUnstartedTxs(ctx, fromAddress) require.NoError(t, err) assert.False(t, retryable) @@ -1612,7 +1645,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) - _, err := eb.GetNextSequence(fromAddress) + ctx := testutils.Context(t) + _, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) t.Run("tx signing fails", func(t *testing.T) { @@ -1626,7 +1660,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { })).Return(&tx, errors.New("could not sign transaction")) // Do the thing - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) require.Contains(t, err.Error(), "could not sign transaction") assert.True(t, retryable) @@ -1640,7 +1674,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { // Check that the key did not have its nonce incremented var nonce types.Nonce - nonce, err = eb.GetNextSequence(fromAddress) + nonce, err = eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) require.Equal(t, int64(localNonce), int64(nonce)) }) @@ -1678,12 +1712,13 @@ func TestEthBroadcaster_IncrementNextNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) - nonce, err := eb.GetNextSequence(fromAddress) + ctx := testutils.Context(t) + nonce, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) eb.IncrementNextSequence(fromAddress, nonce) // Nonce bumped to 1 - nonce, err = eb.GetNextSequence(fromAddress) + nonce, err = eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) require.Equal(t, int64(1), int64(nonce)) } @@ -1737,7 +1772,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, nil, lggr, checkerFactory, false) - err := eb.Start(testutils.Context(t)) + err := eb.Start(ctx) assert.NoError(t, err) defer func() { assert.NoError(t, eb.Close()) }() @@ -1763,12 +1798,12 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") // Check nextSequenceMap to make sure it has correct nonce assigned - nonce, err := eb.GetNextSequence(fromAddress) + nonce, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) - assert.Equal(t, strconv.FormatUint(ethNodeNonce, 10), nonce.String()) + require.Equal(t, strconv.FormatUint(ethNodeNonce, 10), nonce.String()) // The disabled key did not get updated - _, err = eb.GetNextSequence(disabledAddress) + _, err = eb.GetNextSequence(ctx, disabledAddress) require.Error(t, err) }) @@ -1797,19 +1832,19 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") // Check keyState to make sure it has correct nonce assigned - nonce, err := eb.GetNextSequence(fromAddress) + nonce, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) assert.Equal(t, int64(ethNodeNonce), int64(nonce)) // The disabled key did not get updated - _, err = eb.GetNextSequence(disabledAddress) + _, err = eb.GetNextSequence(ctx, disabledAddress) require.Error(t, err) }) - } func Test_LoadSequenceMap(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) t.Run("set next nonce using entries from tx table", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) @@ -1824,9 +1859,9 @@ func Test_LoadSequenceMap(t *testing.T) { cltest.MustInsertUnconfirmedEthTx(t, txStore, int64(1), fromAddress) eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - nonce, err := eb.GetNextSequence(fromAddress) + nonce, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) - assert.Equal(t, int64(2), int64(nonce)) + require.Equal(t, int64(2), int64(nonce)) }) t.Run("set next nonce using client when not found in tx table", func(t *testing.T) { @@ -1842,9 +1877,9 @@ func Test_LoadSequenceMap(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(10), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - nonce, err := eb.GetNextSequence(fromAddress) + nonce, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) - assert.Equal(t, int64(10), int64(nonce)) + require.Equal(t, int64(10), int64(nonce)) }) } @@ -1863,25 +1898,53 @@ func Test_NextNonce(t *testing.T) { _, addr1 := cltest.MustInsertRandomKey(t, ks) ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - + ctx := testutils.Context(t) cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.FixtureChainID)) - nonce, err := eb.GetNextSequence(addr1) + nonce, err := eb.GetNextSequence(ctx, addr1) require.NoError(t, err) - assert.Equal(t, randNonce, int64(nonce)) + require.Equal(t, randNonce, int64(nonce)) randAddr1 := utils.RandomAddress() - _, err = eb.GetNextSequence(randAddr1) + _, err = eb.GetNextSequence(ctx, randAddr1) require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr1.Hex())) + require.Contains(t, err.Error(), fmt.Sprintf("address disabled: %s", randAddr1.Hex())) randAddr2 := utils.RandomAddress() - _, err = eb.GetNextSequence(randAddr2) + _, err = eb.GetNextSequence(ctx, randAddr2) require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr2.Hex())) + require.Contains(t, err.Error(), fmt.Sprintf("address disabled: %s", randAddr2.Hex())) } +func Test_SetNonceAfterInit(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + randNonce := testutils.NewRandomPositiveInt64() + _, addr1 := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(0), errors.New("failed to retrieve nonce at startup")).Once() + ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + ctx := testutils.Context(t) + nonce, err := eb.GetNextSequence(ctx, addr1) + require.NoError(t, err) + require.Equal(t, randNonce, int64(nonce)) + + // Test that the new nonce is set in the map and does not need a client call to retrieve on subsequent calls + nonce, err = eb.GetNextSequence(ctx, addr1) + require.NoError(t, err) + require.Equal(t, randNonce, int64(nonce)) +} + func Test_IncrementNextNonce(t *testing.T) { t.Parallel() @@ -1898,26 +1961,27 @@ func Test_IncrementNextNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - nonce, err := eb.GetNextSequence(addr1) + ctx := testutils.Context(t) + nonce, err := eb.GetNextSequence(ctx, addr1) require.NoError(t, err) eb.IncrementNextSequence(addr1, nonce) - nonce, err = eb.GetNextSequence(addr1) + nonce, err = eb.GetNextSequence(ctx, addr1) require.NoError(t, err) assert.Equal(t, randNonce+1, int64(nonce)) eb.IncrementNextSequence(addr1, nonce) - nonce, err = eb.GetNextSequence(addr1) + nonce, err = eb.GetNextSequence(ctx, addr1) require.NoError(t, err) assert.Equal(t, randNonce+2, int64(nonce)) randAddr1 := utils.RandomAddress() - _, err = eb.GetNextSequence(randAddr1) + _, err = eb.GetNextSequence(ctx, randAddr1) require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr1.Hex())) + assert.Contains(t, err.Error(), fmt.Sprintf("address disabled: %s", randAddr1.Hex())) // verify it didnt get changed by any erroring calls - nonce, err = eb.GetNextSequence(addr1) + nonce, err = eb.GetNextSequence(ctx, addr1) require.NoError(t, err) assert.Equal(t, randNonce+2, int64(nonce)) } @@ -1936,14 +2000,15 @@ func Test_SetNextNonce(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKey(t, ks) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + ctx := testutils.Context(t) t.Run("update next nonce", func(t *testing.T) { - nonce, err := eb.GetNextSequence(fromAddress) + nonce, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) assert.Equal(t, int64(0), int64(nonce)) eb.SetNextSequence(fromAddress, evmtypes.Nonce(24)) - newNextNonce, err := eb.GetNextSequence(fromAddress) + newNextNonce, err := eb.GetNextSequence(ctx, fromAddress) require.NoError(t, err) assert.Equal(t, int64(24), int64(newNextNonce)) }) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a10f9dd1c6..1351c42134 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -36,6 +36,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ... +## 2.7.1 - UNRELEASED + +### Fixed + +- Fixed a bug that causes the node to shutdown if all configured RPC's are unreachable during startup. + ## 2.7.0 - UNRELEASED ### Added From 101d5deab2db52a09744ad12c7693372a9fd8bac Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 16 Nov 2023 12:00:54 -0600 Subject: [PATCH 163/327] replace all context.TODO()s (#11313) --- common/txmgr/confirmer.go | 8 ++++---- core/chains/evm/txmgr/confirmer_test.go | 10 +++++----- core/cmd/shell_local.go | 7 ++++--- core/internal/cltest/cltest.go | 1 + .../chainlink/relayer_chain_interoperators.go | 2 +- core/services/chainlink/relayer_factory.go | 2 +- .../ocr2/plugins/dkg/persistence/db_test.go | 14 +++++++------- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index afb2b3003a..4d3626ffac 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -1025,7 +1025,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) mar // This operates completely orthogonal to the normal Confirmer and can result in untracked attempts! // Only for emergency usage. // This is in case of some unforeseen scenario where the node is refusing to release the lock. KISS. -func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ForceRebroadcast(seqs []SEQ, fee FEE, address ADDR, overrideGasLimit uint32) error { +func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ForceRebroadcast(ctx context.Context, seqs []SEQ, fee FEE, address ADDR, overrideGasLimit uint32) error { if len(seqs) == 0 { ec.lggr.Infof("ForceRebroadcast: No sequences provided. Skipping") return nil @@ -1034,13 +1034,13 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For for _, seq := range seqs { - etx, err := ec.txStore.FindTxWithSequence(context.TODO(), address, seq) + etx, err := ec.txStore.FindTxWithSequence(ctx, address, seq) if err != nil { return errors.Wrap(err, "ForceRebroadcast failed") } if etx == nil { ec.lggr.Debugf("ForceRebroadcast: no tx found with sequence %s, will rebroadcast empty transaction", seq) - hashStr, err := ec.sendEmptyTransaction(context.TODO(), address, seq, overrideGasLimit, fee) + hashStr, err := ec.sendEmptyTransaction(ctx, address, seq, overrideGasLimit, fee) if err != nil { ec.lggr.Errorw("ForceRebroadcast: failed to send empty transaction", "sequence", seq, "err", err) continue @@ -1058,7 +1058,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For } attempt.Tx = *etx // for logging ec.lggr.Debugw("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "err", err, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt) - if errCode, err := ec.client.SendTransactionReturnCode(context.TODO(), *etx, attempt, ec.lggr); errCode != client.Successful && err != nil { + if errCode, err := ec.client.SendTransactionReturnCode(ctx, *etx, attempt, ec.lggr); errCode != client.Successful && err != nil { ec.lggr.Errorw(fmt.Sprintf("ForceRebroadcast: failed to rebroadcast tx %v with sequence %v and gas limit %v: %s", etx.ID, *etx.Sequence, etx.FeeLimit, err.Error()), "err", err, "fee", attempt.TxFee) continue } diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 31464f8f52..e17e7993cf 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -2819,7 +2819,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { tx.To().String() == etx1.ToAddress.String() }), mock.Anything).Return(commonclient.Successful, nil).Once() - require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{1}, gasPriceWei, fromAddress, overrideGasLimit)) + require.NoError(t, ec.ForceRebroadcast(testutils.Context(t), []evmtypes.Nonce{1}, gasPriceWei, fromAddress, overrideGasLimit)) }) t.Run("uses default gas limit if overrideGasLimit is 0", func(t *testing.T) { @@ -2834,7 +2834,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { tx.To().String() == etx1.ToAddress.String() }), mock.Anything).Return(commonclient.Successful, nil).Once() - require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{(1)}, gasPriceWei, fromAddress, 0)) + require.NoError(t, ec.ForceRebroadcast(testutils.Context(t), []evmtypes.Nonce{(1)}, gasPriceWei, fromAddress, 0)) }) t.Run("rebroadcasts several eth_txes in nonce range", func(t *testing.T) { @@ -2848,7 +2848,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { return tx.Nonce() == uint64(*etx2.Sequence) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == uint64(overrideGasLimit) }), mock.Anything).Return(commonclient.Successful, nil).Once() - require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{(1), (2)}, gasPriceWei, fromAddress, overrideGasLimit)) + require.NoError(t, ec.ForceRebroadcast(testutils.Context(t), []evmtypes.Nonce{(1), (2)}, gasPriceWei, fromAddress, overrideGasLimit)) }) t.Run("broadcasts zero transactions if eth_tx doesn't exist for that nonce", func(t *testing.T) { @@ -2874,7 +2874,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { } nonces := []evmtypes.Nonce{(1), (2), (3), (4), (5)} - require.NoError(t, ec.ForceRebroadcast(nonces, gasPriceWei, fromAddress, overrideGasLimit)) + require.NoError(t, ec.ForceRebroadcast(testutils.Context(t), nonces, gasPriceWei, fromAddress, overrideGasLimit)) }) t.Run("zero transactions use default gas limit if override wasn't specified", func(t *testing.T) { @@ -2885,7 +2885,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { return tx.Nonce() == uint64(0) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && uint32(tx.Gas()) == config.EVM().GasEstimator().LimitDefault() }), mock.Anything).Return(commonclient.Successful, nil).Once() - require.NoError(t, ec.ForceRebroadcast([]evmtypes.Nonce{(0)}, gasPriceWei, fromAddress, 0)) + require.NoError(t, ec.ForceRebroadcast(testutils.Context(t), []evmtypes.Nonce{(0)}, gasPriceWei, fromAddress, 0)) }) } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index f7e17ef7fc..cbd0feccbf 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -558,6 +558,7 @@ func checkFilePermissions(lggr logger.Logger, rootDir string) error { // RebroadcastTransactions run locally to force manual rebroadcasting of // transactions in a given nonce range. func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { + ctx := s.ctx() beginningNonce := c.Int64("beginningNonce") endingNonce := c.Int64("endingNonce") gasPriceWei := c.Uint64("gasPriceWei") @@ -587,7 +588,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { } defer lggr.ErrorIfFn(db.Close, "Error closing db") - app, err := s.AppFactory.NewApplication(context.TODO(), s.Config, lggr, db) + app, err := s.AppFactory.NewApplication(ctx, s.Config, lggr, db) if err != nil { return s.errorOut(errors.Wrap(err, "fatal error instantiating application")) } @@ -603,7 +604,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { ethClient := chain.Client() - err = ethClient.Dial(context.TODO()) + err = ethClient.Dial(ctx) if err != nil { return err } @@ -642,7 +643,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { for i := int64(0); i < totalNonces; i++ { nonces[i] = evmtypes.Nonce(beginningNonce + i) } - err = ec.ForceRebroadcast(nonces, gas.EvmFee{Legacy: assets.NewWeiI(int64(gasPriceWei))}, address, uint32(overrideGasLimit)) + err = ec.ForceRebroadcast(ctx, nonces, gas.EvmFee{Legacy: assets.NewWeiI(int64(gasPriceWei))}, address, uint32(overrideGasLimit)) return s.errorOut(err) } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 644c516c21..83a97833bd 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -40,6 +40,7 @@ import ( "github.com/urfave/cli" "github.com/jmoiron/sqlx" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-relay/pkg/loop" diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index b2ec0822d4..1183277ac0 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -121,7 +121,7 @@ func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfi // InitCosmos is a option for instantiating Cosmos relayers func InitCosmos(ctx context.Context, factory RelayerFactory, config CosmosFactoryConfig) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) (err error) { - adapters, err2 := factory.NewCosmos(ctx, config) + adapters, err2 := factory.NewCosmos(config) if err2 != nil { return fmt.Errorf("failed to setup Cosmos relayer: %w", err2) } diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index d452decda1..4bbabea4c8 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -250,7 +250,7 @@ func (c CosmosFactoryConfig) Validate() error { return err } -func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConfig) (map[relay.ID]CosmosLoopRelayerChainer, error) { +func (r *RelayerFactory) NewCosmos(config CosmosFactoryConfig) (map[relay.ID]CosmosLoopRelayerChainer, error) { err := config.Validate() if err != nil { return nil, fmt.Errorf("cannot create Cosmos relayer: %w", err) diff --git a/core/services/ocr2/plugins/dkg/persistence/db_test.go b/core/services/ocr2/plugins/dkg/persistence/db_test.go index 4e029c1cb2..d4a4546fb9 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db_test.go +++ b/core/services/ocr2/plugins/dkg/persistence/db_test.go @@ -1,18 +1,18 @@ package persistence import ( - "context" "fmt" "math/big" "testing" "github.com/ethereum/go-ethereum/crypto" "github.com/jmoiron/sqlx" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - "github.com/smartcontractkit/ocr2vrf/types/hash" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + "github.com/smartcontractkit/ocr2vrf/types/hash" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -50,7 +50,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { expectedRecords = append(expectedRecords, rec) } - err := shareDB.WriteShareRecords(context.TODO(), configDigest, keyID, expectedRecords) + err := shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, expectedRecords) require.NoError(tt, err) rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) @@ -79,7 +79,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { } // no error, but there will be no rows inserted in the db - err = shareDB.WriteShareRecords(context.TODO(), configDigest, keyID, records) + err = shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, records) require.NoError(tt, err) rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) @@ -116,7 +116,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { records = append(records, rec) } - err := shareDB.WriteShareRecords(context.TODO(), configDigest, keyID, records) + err := shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, records) require.Error(tt, err) // no rows should have been inserted @@ -160,7 +160,7 @@ func TestShareDBE2E(t *testing.T) { expectedRecordsMap[*playerIdx] = rec } - err := shareDB.WriteShareRecords(context.TODO(), configDigest, keyID, expectedRecords) + err := shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, expectedRecords) require.NoError(t, err) actualRecords, err := shareDB.ReadShareRecords(configDigest, keyID) From e030073e8cfbb12ef86321f9755b2488a472c4f8 Mon Sep 17 00:00:00 2001 From: Lei Date: Thu, 16 Nov 2023 10:10:23 -0800 Subject: [PATCH 164/327] refactor mercury (#11137) * refactor mercury, rebase on top of PR 10878 * change back to use eth_call, sigh, simulated backend in integration test doesnt like using the registry contract directly * fixes and include new threadctl changes * address comments, add time in logs * rebase and add a test --- core/scripts/chaincli/handler/debug.go | 31 +- core/scripts/chaincli/handler/keeper.go | 5 +- .../handler/mercury_lookup_handler.go | 6 +- .../ocr2keeper/evm21/block_subscriber.go | 5 + .../ocr2keeper/evm21/encoding/interface.go | 61 +- .../ocr2keeper/evm21/encoding/packer.go | 25 +- .../ocr2keeper/evm21/encoding/packer_test.go | 12 +- .../ocr2keeper/evm21/mercury/mercury.go | 122 ++ .../ocr2keeper/evm21/mercury/mercury_test.go | 49 + .../evm21/mercury/streams/streams.go | 330 ++++ .../evm21/mercury/streams/streams_test.go | 726 +++++++++ .../evm21/mercury/upkeep_failure_reasons.go | 15 + .../ocr2keeper/evm21/mercury/upkeep_states.go | 14 + .../ocr2keeper/evm21/mercury/v02/request.go | 203 +++ .../evm21/mercury/v02/v02_request_test.go | 468 ++++++ .../ocr2keeper/evm21/mercury/v03/request.go | 252 +++ .../evm21/mercury/v03/v03_request_test.go | 536 +++++++ .../ocr2/plugins/ocr2keeper/evm21/registry.go | 89 +- .../evm21/registry_check_pipeline.go | 6 +- .../evm21/registry_check_pipeline_test.go | 56 +- .../ocr2keeper/evm21/streams_lookup.go | 642 -------- .../ocr2keeper/evm21/streams_lookup_test.go | 1354 ----------------- .../plugins/ocr2keeper/integration_21_test.go | 9 +- integration-tests/smoke/automation_test.go | 10 +- 24 files changed, 2928 insertions(+), 2098 deletions(-) create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury_test.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_failure_reasons.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_states.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go delete mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go delete mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index daf012ee16..8f65b1f881 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -18,16 +18,18 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" ) const ( @@ -227,6 +229,13 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) } if checkResult.UpkeepFailureReason == uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { + // TODO use the new streams lookup lib + //mc := &models.MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey} + //mercuryConfig := evm.NewMercuryConfig(mc, core.StreamsCompatibleABI) + //lggr, _ := logger.NewLogger() + //blockSub := &blockSubscriber{k.client} + //_ = streams.NewStreamsLookup(packer, mercuryConfig, blockSub, keeperRegistry21, k.rpcClient, lggr) + streamsLookupErr, err := packer.DecodeStreamsLookupRequest(checkResult.PerformData) if err == nil { message("upkeep reverted with StreamsLookup") @@ -240,7 +249,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } allowed := false if len(cfg) > 0 { - var privilegeConfig evm.UpkeepPrivilegeConfig + var privilegeConfig streams.UpkeepPrivilegeConfig if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { failUnknown("failed to unmarshal privilege config ", err) } @@ -307,6 +316,22 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } } +type blockSubscriber struct { + ethClient *ethclient.Client +} + +func (bs *blockSubscriber) LatestBlock() *ocr2keepers.BlockKey { + header, err := bs.ethClient.HeaderByNumber(context.Background(), nil) + if err != nil { + return nil + } + + return &ocr2keepers.BlockKey{ + Number: ocr2keepers.BlockNumber(header.Number.Uint64()), + Hash: header.Hash(), + } +} + func logMatchesTriggerConfig(log *types.Log, config automation_utils_2_1.LogTriggerConfig) bool { if log.Topics[0] != config.Topic0 { return false diff --git a/core/scripts/chaincli/handler/keeper.go b/core/scripts/chaincli/handler/keeper.go index ba8276efb5..453ef43a56 100644 --- a/core/scripts/chaincli/handler/keeper.go +++ b/core/scripts/chaincli/handler/keeper.go @@ -14,6 +14,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/umbracle/ethgo/abi" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/cmd" @@ -34,7 +36,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/verifiable_load_upkeep_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" - evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" ) // Keeper is the keepers commands handler @@ -719,7 +720,7 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, log.Printf("registry version is %s", v) log.Printf("active upkeep ids: %v", activeUpkeepIds) - adminBytes, err := json.Marshal(evm.UpkeepPrivilegeConfig{ + adminBytes, err := json.Marshal(streams.UpkeepPrivilegeConfig{ MercuryEnabled: true, }) if err != nil { diff --git a/core/scripts/chaincli/handler/mercury_lookup_handler.go b/core/scripts/chaincli/handler/mercury_lookup_handler.go index 0db142df9f..1bd4b2e183 100644 --- a/core/scripts/chaincli/handler/mercury_lookup_handler.go +++ b/core/scripts/chaincli/handler/mercury_lookup_handler.go @@ -3,7 +3,9 @@ package handler import ( "context" "crypto/hmac" + "crypto/sha256" "encoding/hex" + "encoding/json" "fmt" "io" "math/big" @@ -13,10 +15,6 @@ import ( "strings" "time" - "crypto/sha256" - - "encoding/json" - "github.com/avast/retry-go" ethabi "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go index d97156ed18..6cc19a4d02 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go @@ -12,6 +12,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/smartcontractkit/chainlink-relay/pkg/services" + httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -56,6 +57,10 @@ type BlockSubscriber struct { lggr logger.Logger } +func (bs *BlockSubscriber) LatestBlock() *ocr2keepers.BlockKey { + return bs.latestBlock.Load() +} + var _ ocr2keepers.BlockSubscriber = &BlockSubscriber{} func NewBlockSubscriber(hb httypes.HeadBroadcaster, lp logpoller.LogPoller, finalityDepth uint32, lggr logger.Logger) *BlockSubscriber { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go index 217f0dcb57..e21ecfb800 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go @@ -5,56 +5,55 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" ) -type UpkeepFailureReason uint8 -type PipelineExecutionState uint8 - const ( // upkeep failure onchain reasons - UpkeepFailureReasonNone UpkeepFailureReason = 0 - UpkeepFailureReasonUpkeepCancelled UpkeepFailureReason = 1 - UpkeepFailureReasonUpkeepPaused UpkeepFailureReason = 2 - UpkeepFailureReasonTargetCheckReverted UpkeepFailureReason = 3 - UpkeepFailureReasonUpkeepNotNeeded UpkeepFailureReason = 4 - UpkeepFailureReasonPerformDataExceedsLimit UpkeepFailureReason = 5 - UpkeepFailureReasonInsufficientBalance UpkeepFailureReason = 6 - UpkeepFailureReasonMercuryCallbackReverted UpkeepFailureReason = 7 - UpkeepFailureReasonRevertDataExceedsLimit UpkeepFailureReason = 8 - UpkeepFailureReasonRegistryPaused UpkeepFailureReason = 9 + UpkeepFailureReasonNone uint8 = 0 + UpkeepFailureReasonUpkeepCancelled uint8 = 1 + UpkeepFailureReasonUpkeepPaused uint8 = 2 + UpkeepFailureReasonTargetCheckReverted uint8 = 3 + UpkeepFailureReasonUpkeepNotNeeded uint8 = 4 + UpkeepFailureReasonPerformDataExceedsLimit uint8 = 5 + UpkeepFailureReasonInsufficientBalance uint8 = 6 + UpkeepFailureReasonMercuryCallbackReverted uint8 = 7 + UpkeepFailureReasonRevertDataExceedsLimit uint8 = 8 + UpkeepFailureReasonRegistryPaused uint8 = 9 // leaving a gap here for more onchain failure reasons in the future // upkeep failure offchain reasons - UpkeepFailureReasonMercuryAccessNotAllowed UpkeepFailureReason = 32 - UpkeepFailureReasonTxHashNoLongerExists UpkeepFailureReason = 33 - UpkeepFailureReasonInvalidRevertDataInput UpkeepFailureReason = 34 - UpkeepFailureReasonSimulationFailed UpkeepFailureReason = 35 - UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 + UpkeepFailureReasonMercuryAccessNotAllowed uint8 = 32 + UpkeepFailureReasonTxHashNoLongerExists uint8 = 33 + UpkeepFailureReasonInvalidRevertDataInput uint8 = 34 + UpkeepFailureReasonSimulationFailed uint8 = 35 + UpkeepFailureReasonTxHashReorged uint8 = 36 // pipeline execution error - NoPipelineError PipelineExecutionState = 0 - CheckBlockTooOld PipelineExecutionState = 1 - CheckBlockInvalid PipelineExecutionState = 2 - RpcFlakyFailure PipelineExecutionState = 3 - MercuryFlakyFailure PipelineExecutionState = 4 - PackUnpackDecodeFailed PipelineExecutionState = 5 - MercuryUnmarshalError PipelineExecutionState = 6 - InvalidMercuryRequest PipelineExecutionState = 7 - InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses - UpkeepNotAuthorized PipelineExecutionState = 9 + NoPipelineError uint8 = 0 + CheckBlockTooOld uint8 = 1 + CheckBlockInvalid uint8 = 2 + RpcFlakyFailure uint8 = 3 + MercuryFlakyFailure uint8 = 4 + PackUnpackDecodeFailed uint8 = 5 + MercuryUnmarshalError uint8 = 6 + InvalidMercuryRequest uint8 = 7 + InvalidMercuryResponse uint8 = 8 // this will only happen if Mercury server sends bad responses + UpkeepNotAuthorized uint8 = 9 ) type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo type Packer interface { UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw string) (ocr2keepers.CheckResult, error) - UnpackCheckCallbackResult(callbackResp []byte) (PipelineExecutionState, bool, []byte, uint8, *big.Int, error) - UnpackPerformResult(raw string) (PipelineExecutionState, bool, error) + UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) + UnpackPerformResult(raw string) (uint8, bool, error) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) - DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) + DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go index 9e070b2838..28c6c4a975 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go @@ -6,8 +6,11 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common/hexutil" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) @@ -80,7 +83,7 @@ func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) return bts, nil } -func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (PipelineExecutionState, bool, []byte, uint8, *big.Int, error) { +func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) { out, err := p.registryABI.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) if err != nil { return PackUnpackDecodeFailed, false, nil, 0, nil, fmt.Errorf("%w: unpack checkUpkeep return: %s", err, hexutil.Encode(callbackResp)) @@ -94,7 +97,7 @@ func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (PipelineExec return NoPipelineError, upkeepNeeded, rawPerformData, failureReason, gasUsed, nil } -func (p *abiPacker) UnpackPerformResult(raw string) (PipelineExecutionState, bool, error) { +func (p *abiPacker) UnpackPerformResult(raw string) (uint8, bool, error) { b, err := hexutil.Decode(raw) if err != nil { return PackUnpackDecodeFailed, false, err @@ -161,16 +164,8 @@ func (p *abiPacker) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistr return report, nil } -type StreamsLookupError struct { - FeedParamKey string - Feeds []string - TimeParamKey string - Time *big.Int - ExtraData []byte -} - // DecodeStreamsLookupRequest decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) -func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) { +func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error) { e := p.streamsABI.Errors["StreamsLookup"] unpack, err := e.Unpack(data) if err != nil { @@ -178,7 +173,7 @@ func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError } errorParameters := unpack.([]interface{}) - return &StreamsLookupError{ + return &mercury.StreamsLookupError{ FeedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), Feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), TimeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), @@ -188,10 +183,10 @@ func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError } // GetIneligibleCheckResultWithoutPerformData returns an ineligible check result with ineligibility reason and pipeline execution state but without perform data -func GetIneligibleCheckResultWithoutPerformData(p ocr2keepers.UpkeepPayload, reason UpkeepFailureReason, state PipelineExecutionState, retryable bool) ocr2keepers.CheckResult { +func GetIneligibleCheckResultWithoutPerformData(p ocr2keepers.UpkeepPayload, reason uint8, state uint8, retryable bool) ocr2keepers.CheckResult { return ocr2keepers.CheckResult{ - IneligibilityReason: uint8(reason), - PipelineExecutionState: uint8(state), + IneligibilityReason: reason, + PipelineExecutionState: state, Retryable: retryable, UpkeepID: p.UpkeepID, Trigger: p.Trigger, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go index 1801b01857..03b55bfccc 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go @@ -13,6 +13,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" automation21Utils "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" @@ -210,7 +212,7 @@ func TestPacker_UnpackPerformResult(t *testing.T) { tests := []struct { Name string RawData string - State PipelineExecutionState + State uint8 }{ { Name: "unpack success", @@ -238,7 +240,7 @@ func TestPacker_UnpackCheckCallbackResult(t *testing.T) { FailureReason uint8 GasUsed *big.Int ErrorString string - State PipelineExecutionState + State uint8 }{ { Name: "unpack upkeep needed", @@ -441,14 +443,14 @@ func TestPacker_DecodeStreamsLookupRequest(t *testing.T) { tests := []struct { name string data []byte - expected *StreamsLookupError - state PipelineExecutionState + expected *mercury.StreamsLookupError + state uint8 err error }{ { name: "success - decode to streams lookup", data: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000002435eb50000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - expected: &StreamsLookupError{ + expected: &mercury.StreamsLookupError{ FeedParamKey: "feedIdHex", Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, TimeParamKey: "blockNumber", diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury.go new file mode 100644 index 0000000000..cf6ebeafc6 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury.go @@ -0,0 +1,122 @@ +package mercury + +import ( + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "fmt" + "math/big" + "net/http" + "time" + + "github.com/patrickmn/go-cache" + + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" +) + +const ( + FeedIDs = "feedIDs" // valid for v0.3 + FeedIdHex = "feedIdHex" // valid for v0.2 + BlockNumber = "blockNumber" // valid for v0.2 + Timestamp = "timestamp" // valid for v0.3 + totalFastPluginRetries = 5 + totalMediumPluginRetries = 10 +) + +var GenerateHMACFn = func(method string, path string, body []byte, clientId string, secret string, ts int64) string { + bodyHash := sha256.New() + bodyHash.Write(body) + hashString := fmt.Sprintf("%s %s %s %s %d", + method, + path, + hex.EncodeToString(bodyHash.Sum(nil)), + clientId, + ts) + signedMessage := hmac.New(sha256.New, []byte(secret)) + signedMessage.Write([]byte(hashString)) + userHmac := hex.EncodeToString(signedMessage.Sum(nil)) + return userHmac +} + +// CalculateRetryConfig returns plugin retry interval based on how many times plugin has retried this work +var CalculateRetryConfigFn = func(prk string, mercuryConfig MercuryConfigProvider) time.Duration { + var retryInterval time.Duration + var retries int + totalAttempts, ok := mercuryConfig.GetPluginRetry(prk) + if ok { + retries = totalAttempts.(int) + if retries < totalFastPluginRetries { + retryInterval = 1 * time.Second + } else if retries < totalMediumPluginRetries { + retryInterval = 5 * time.Second + } + // if the core node has retried totalMediumPluginRetries times, do not set retry interval and plugin will use + // the default interval + } else { + retryInterval = 1 * time.Second + } + mercuryConfig.SetPluginRetry(prk, retries+1, cache.DefaultExpiration) + return retryInterval +} + +type MercuryData struct { + Index int + Error error + Retryable bool + Bytes [][]byte + State MercuryUpkeepState +} + +type Packer interface { + UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) + PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) + UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) + DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) +} + +type MercuryConfigProvider interface { + Credentials() *models.MercuryCredentials + IsUpkeepAllowed(string) (interface{}, bool) + SetUpkeepAllowed(string, interface{}, time.Duration) + GetPluginRetry(string) (interface{}, bool) + SetPluginRetry(string, interface{}, time.Duration) +} + +type HttpClient interface { + Do(req *http.Request) (*http.Response, error) +} + +type MercuryClient interface { + DoRequest(ctx context.Context, streamsLookup *StreamsLookup, pluginRetryKey string) (MercuryUpkeepState, MercuryUpkeepFailureReason, [][]byte, bool, time.Duration, error) +} + +type StreamsLookupError struct { + FeedParamKey string + Feeds []string + TimeParamKey string + Time *big.Int + ExtraData []byte +} + +type StreamsLookup struct { + *StreamsLookupError + UpkeepId *big.Int + Block uint64 +} + +func (l *StreamsLookup) IsMercuryVersionUnkown() bool { + return l.FeedParamKey != FeedIDs +} + +func (l *StreamsLookup) IsMercuryV02() bool { + return l.FeedParamKey == FeedIdHex && l.TimeParamKey == BlockNumber +} + +func (l *StreamsLookup) IsMercuryV03() bool { + return l.FeedParamKey == FeedIDs +} + +func (l *StreamsLookup) IsMercuryUsingBatchPathV03() bool { + return l.TimeParamKey == BlockNumber +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury_test.go new file mode 100644 index 0000000000..baa939dbec --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury_test.go @@ -0,0 +1,49 @@ +package mercury + +import ( + "testing" +) + +func TestGenerateHMACFn(t *testing.T) { + testCases := []struct { + name string + method string + path string + body []byte + clientId string + secret string + ts int64 + expected string + }{ + { + name: "generate hmac function", + method: "GET", + path: "/example", + body: []byte(""), + clientId: "yourClientId", + secret: "yourSecret", + ts: 1234567890, + expected: "17b0bb6b14f7b48ef9d24f941ff8f33ad2d5e94ac343380be02c2f1ca32fdbd8", + }, + { + name: "generate hmac function with non-empty body", + method: "POST", + path: "/api", + body: []byte("request body"), + clientId: "anotherClientId", + secret: "anotherSecret", + ts: 1597534567, + expected: "d326c168c50c996e271d6b3b4c97944db01163994090f73fcf4fd42f23f06bbb", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := GenerateHMACFn(tc.method, tc.path, tc.body, tc.clientId, tc.secret, tc.ts) + + if result != tc.expected { + t.Errorf("Expected: %s, Got: %s", tc.expected, result) + } + }) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go new file mode 100644 index 0000000000..b83aca8a02 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go @@ -0,0 +1,330 @@ +package streams + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "net/http" + "sync" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/patrickmn/go-cache" + + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" + + iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02" + v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type Lookup interface { + Lookup(ctx context.Context, checkResults []ocr2keepers.CheckResult) []ocr2keepers.CheckResult +} + +type latestBlockProvider interface { + LatestBlock() *ocr2keepers.BlockKey +} + +type streamsRegistry interface { + GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) + Address() common.Address +} + +type contextCaller interface { + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error +} + +type streams struct { + services.StateMachine + packer mercury.Packer + mercuryConfig mercury.MercuryConfigProvider + abi abi.ABI + blockSubscriber latestBlockProvider + registry streamsRegistry + client contextCaller + lggr logger.Logger + threadCtrl utils.ThreadControl + v02Client mercury.MercuryClient + v03Client mercury.MercuryClient +} + +// UpkeepPrivilegeConfig represents the administrative offchain config for each upkeep. It can be set by s_upkeepPrivilegeManager +// role on the registry. Upkeeps allowed to use Mercury server will have this set to true. +type UpkeepPrivilegeConfig struct { + MercuryEnabled bool `json:"mercuryEnabled"` +} + +func NewStreamsLookup( + packer mercury.Packer, + mercuryConfig mercury.MercuryConfigProvider, + blockSubscriber latestBlockProvider, + client contextCaller, + registry streamsRegistry, + lggr logger.Logger) *streams { + httpClient := http.DefaultClient + threadCtrl := utils.NewThreadControl() + return &streams{ + packer: packer, + mercuryConfig: mercuryConfig, + abi: core.RegistryABI, + blockSubscriber: blockSubscriber, + registry: registry, + client: client, + lggr: lggr, + threadCtrl: threadCtrl, + v02Client: v02.NewClient(mercuryConfig, httpClient, threadCtrl, lggr), + v03Client: v03.NewClient(mercuryConfig, httpClient, threadCtrl, lggr), + } +} + +// Lookup looks through check upkeep results looking for any that need off chain lookup +func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckResult) []ocr2keepers.CheckResult { + lookups := map[int]*mercury.StreamsLookup{} + for i, checkResult := range checkResults { + s.buildResult(ctx, i, checkResult, checkResults, lookups) + } + + var wg sync.WaitGroup + for i, lookup := range lookups { + wg.Add(1) + func(i int, lookup *mercury.StreamsLookup) { + s.threadCtrl.Go(func(ctx context.Context) { + s.doLookup(ctx, &wg, lookup, i, checkResults) + }) + }(i, lookup) + } + wg.Wait() + + // don't surface error to plugin bc StreamsLookup process should be self-contained. + return checkResults +} + +// buildResult checks if the upkeep is allowed by Mercury and builds a streams lookup request from the check result +func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keepers.CheckResult, checkResults []ocr2keepers.CheckResult, lookups map[int]*mercury.StreamsLookup) { + lookupLggr := s.lggr.With("where", "StreamsLookup") + if checkResult.IneligibilityReason != uint8(mercury.MercuryUpkeepFailureReasonTargetCheckReverted) { + // Streams Lookup only works when upkeep target check reverts + return + } + + block := big.NewInt(int64(checkResult.Trigger.BlockNumber)) + upkeepId := checkResult.UpkeepID + + if s.mercuryConfig.Credentials() == nil { + lookupLggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) + return + } + + // Try to decode the revert error into streams lookup format. User upkeeps can revert with any reason, see if they + // tried to call mercury + lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) + streamsLookupErr, err := s.packer.DecodeStreamsLookupRequest(checkResult.PerformData) + if err != nil { + lookupLggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) + // user contract did not revert with StreamsLookup error + return + } + streamsLookupResponse := &mercury.StreamsLookup{StreamsLookupError: streamsLookupErr} + + if len(streamsLookupResponse.Feeds) == 0 { + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + lookupLggr.Debugf("at block %s upkeep %s has empty feeds array", block, upkeepId) + return + } + + // mercury permission checking for v0.3 is done by mercury server + if streamsLookupResponse.IsMercuryV02() { + // check permission on the registry for mercury v0.2 + opts := s.buildCallOpts(ctx, block) + if state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId.BigInt()); err != nil { + lookupLggr.Warnf("at block %s upkeep %s failed to query mercury allow list: %s", block, upkeepId, err) + checkResults[i].PipelineExecutionState = uint8(state) + checkResults[i].IneligibilityReason = uint8(reason) + checkResults[i].Retryable = retryable + return + } else if !allowed { + lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed) + return + } + } else if streamsLookupResponse.IsMercuryVersionUnkown() { + // if mercury version cannot be determined, set failure reason + lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + return + } + + streamsLookupResponse.UpkeepId = upkeepId.BigInt() + // the block here is exclusively used to call checkCallback at this block, not to be confused with the block number + // in the revert for mercury v0.2, which is denoted by time in the struct bc starting from v0.3, only timestamp will be supported + streamsLookupResponse.Block = uint64(block.Int64()) + lookupLggr.Infof("at block %d upkeep %s DecodeStreamsLookupRequest feedKey=%s timeKey=%s feeds=%v time=%s extraData=%s", block, upkeepId, streamsLookupResponse.FeedParamKey, streamsLookupResponse.TimeParamKey, streamsLookupResponse.Feeds, streamsLookupResponse.Time, hexutil.Encode(streamsLookupResponse.ExtraData)) + lookups[i] = streamsLookupResponse +} + +func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, i int, checkResults []ocr2keepers.CheckResult) { + defer wg.Done() + + state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) + pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) + + if lookup.IsMercuryV02() { + state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) + } else if lookup.IsMercuryV03() { + state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) + } + + if err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.Block, lookup.UpkeepId, lookup.Time, retryable, retryInterval, err.Error()) + checkResults[i].Retryable = retryable + checkResults[i].RetryInterval = retryInterval + checkResults[i].PipelineExecutionState = uint8(state) + checkResults[i].IneligibilityReason = uint8(reason) + return + } + + for j, v := range values { + s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) + } + + state, retryable, mercuryBytes, err := s.checkCallback(ctx, values, lookup) + if err != nil { + s.lggr.Errorf("at block %d upkeep %s checkCallback err: %s", lookup.Block, lookup.UpkeepId, err.Error()) + checkResults[i].Retryable = retryable + checkResults[i].PipelineExecutionState = uint8(state) + return + } + s.lggr.Infof("at block %d upkeep %s requested time %s checkCallback mercuryBytes: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(mercuryBytes)) + + unpackCallBackState, needed, performData, failureReason, _, err := s.packer.UnpackCheckCallbackResult(mercuryBytes) + if err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s UnpackCheckCallbackResult err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + checkResults[i].PipelineExecutionState = unpackCallBackState + return + } + + if failureReason == uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) { + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) + s.lggr.Debugf("at block %d upkeep %s requested time %s mercury callback reverts", lookup.Block, lookup.UpkeepId, lookup.Time) + return + } + + if !needed { + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonUpkeepNotNeeded) + s.lggr.Debugf("at block %d upkeep %s requested time %s callback reports upkeep not needed", lookup.Block, lookup.UpkeepId, lookup.Time) + return + } + + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonNone) + checkResults[i].Eligible = true + checkResults[i].PerformData = performData + s.lggr.Infof("at block %d upkeep %s requested time %s successful with perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(performData)) +} + +// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if +// this upkeep is allowed to use Mercury service. +func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { + allowed, ok := s.mercuryConfig.IsUpkeepAllowed(upkeepId.String()) + if ok { + return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, allowed.(bool), nil + } + + payload, err := s.packer.PackGetUpkeepPrivilegeConfig(upkeepId) + if err != nil { + // pack error, no retryable + s.lggr.Warnf("failed to pack getUpkeepPrivilegeConfig data for upkeepId %s: %s", upkeepId, err) + + return mercury.PackUnpackDecodeFailed, mercury.MercuryUpkeepFailureReasonNone, false, false, fmt.Errorf("failed to pack upkeepId: %w", err) + } + + var resultBytes hexutil.Bytes + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + + // call checkCallback function at the block which OCR3 has agreed upon + if err = s.client.CallContext(opts.Context, &resultBytes, "eth_call", args, hexutil.EncodeBig(opts.BlockNumber)); err != nil { + return mercury.RpcFlakyFailure, mercury.MercuryUpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) + } + + var upkeepPrivilegeConfigBytes []byte + upkeepPrivilegeConfigBytes, err = s.packer.UnpackGetUpkeepPrivilegeConfig(resultBytes) + if err != nil { + return mercury.PackUnpackDecodeFailed, mercury.MercuryUpkeepFailureReasonNone, false, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) + } + + if len(upkeepPrivilegeConfigBytes) == 0 { + s.mercuryConfig.SetUpkeepAllowed(upkeepId.String(), false, cache.DefaultExpiration) + return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed, false, false, fmt.Errorf("upkeep privilege config is empty") + } + + var privilegeConfig UpkeepPrivilegeConfig + if err = json.Unmarshal(upkeepPrivilegeConfigBytes, &privilegeConfig); err != nil { + return mercury.MercuryUnmarshalError, mercury.MercuryUpkeepFailureReasonNone, false, false, fmt.Errorf("failed to unmarshal privilege config: %v", err) + } + + s.mercuryConfig.SetUpkeepAllowed(upkeepId.String(), privilegeConfig.MercuryEnabled, cache.DefaultExpiration) + + return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil +} + +func (s *streams) checkCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup) (mercury.MercuryUpkeepState, bool, hexutil.Bytes, error) { + payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) + if err != nil { + return mercury.PackUnpackDecodeFailed, false, nil, err + } + + var b hexutil.Bytes + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + + // call checkCallback function at the block which OCR3 has agreed upon + if err := s.client.CallContext(ctx, &b, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { + return mercury.RpcFlakyFailure, true, nil, err + } + + return mercury.NoPipelineError, false, b, nil +} + +func (s *streams) buildCallOpts(ctx context.Context, block *big.Int) *bind.CallOpts { + opts := bind.CallOpts{ + Context: ctx, + } + + if block == nil || block.Int64() == 0 { + if latestBlock := s.blockSubscriber.LatestBlock(); latestBlock != nil && latestBlock.Number != 0 { + opts.BlockNumber = big.NewInt(int64(latestBlock.Number)) + } + } else { + opts.BlockNumber = block + } + + return &opts +} + +// generatePluginRetryKey returns a plugin retry cache key +func generatePluginRetryKey(workID string, block uint64) string { + return workID + "|" + fmt.Sprintf("%d", block) +} + +func (s *streams) Close() error { + return s.StopOnce("streams_lookup", func() error { + s.threadCtrl.Close() + return nil + }) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go new file mode 100644 index 0000000000..194d74febb --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go @@ -0,0 +1,726 @@ +package streams + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + + "github.com/stretchr/testify/assert" + + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/stretchr/testify/mock" + + evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02" + v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" +) + +type MockMercuryConfigProvider struct { + mock.Mock +} + +func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { + mc := &models.MercuryCredentials{ + LegacyURL: "https://google.old.com", + URL: "https://google.com", + Username: "FakeClientID", + Password: "FakeClientKey", + } + return mc +} + +func (m *MockMercuryConfigProvider) IsUpkeepAllowed(s string) (interface{}, bool) { + args := m.Called(s) + return args.Get(0), args.Bool(1) +} + +func (m *MockMercuryConfigProvider) SetUpkeepAllowed(s string, i interface{}, d time.Duration) { + m.Called(s, i, d) +} + +func (m *MockMercuryConfigProvider) GetPluginRetry(s string) (interface{}, bool) { + args := m.Called(s) + return args.Get(0), args.Bool(1) +} + +func (m *MockMercuryConfigProvider) SetPluginRetry(s string, i interface{}, d time.Duration) { + m.Called(s, i, d) +} + +type MockBlockSubscriber struct { + mock.Mock +} + +func (b *MockBlockSubscriber) LatestBlock() *ocr2keepers.BlockKey { + return nil +} + +type MockHttpClient struct { + mock.Mock +} + +func (mock *MockHttpClient) Do(req *http.Request) (*http.Response, error) { + args := mock.Called(req) + return args.Get(0).(*http.Response), args.Error(1) +} + +type mockRegistry struct { + GetUpkeepPrivilegeConfigFn func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + CheckCallbackFn func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) +} + +func (r *mockRegistry) Address() common.Address { + return common.HexToAddress("0x6cA639822c6C241Fa9A7A6b5032F6F7F1C513CAD") +} + +func (r *mockRegistry) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return r.GetUpkeepPrivilegeConfigFn(opts, upkeepId) +} + +func (r *mockRegistry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return r.CheckCallbackFn(opts, id, values, extraData) +} + +// setups up a streams object for tests. +func setupStreams(t *testing.T) *streams { + lggr := logger.TestLogger(t) + packer := encoding.NewAbiPacker() + mercuryConfig := new(MockMercuryConfigProvider) + blockSubscriber := new(MockBlockSubscriber) + registry := &mockRegistry{} + client := evmClientMocks.NewClient(t) + + streams := NewStreamsLookup( + packer, + mercuryConfig, + blockSubscriber, + client, + registry, + lggr, + ) + return streams +} + +func TestStreams_CheckCallback(t *testing.T) { + upkeepId := big.NewInt(123456789) + bn := uint64(999) + bs := []byte{183, 114, 215, 10, 0, 0, 0, 0, 0, 0} + values := [][]byte{bs} + tests := []struct { + name string + lookup *mercury.StreamsLookup + values [][]byte + statusCode int + + callbackResp []byte + callbackErr error + + upkeepNeeded bool + performData []byte + wantErr assert.ErrorAssertionFunc + + state mercury.MercuryUpkeepState + retryable bool + registry streamsRegistry + }{ + { + name: "success - empty extra data", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"ETD-USD", "BTC-ETH"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(100), + ExtraData: []byte{48, 120, 48, 48}, + }, + UpkeepId: upkeepId, + Block: bn, + }, + values: values, + statusCode: http.StatusOK, + callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + upkeepNeeded: true, + performData: []byte{48, 120, 48, 48}, + wantErr: assert.NoError, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{ + UpkeepNeeded: true, + PerformData: []byte{48, 120, 48, 48}, + }, nil + }, + }, + }, + { + name: "success - with extra data", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(18952430), + // this is the address of precompile contract ArbSys(0x0000000000000000000000000000000000000064) + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + Block: bn, + }, + values: values, + statusCode: http.StatusOK, + callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + upkeepNeeded: true, + performData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + wantErr: assert.NoError, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{ + UpkeepNeeded: true, + PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, nil + }, + }, + }, + { + name: "failure - bad response", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"ETD-USD", "BTC-ETH"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(100), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + UpkeepId: upkeepId, + Block: bn, + }, + values: values, + statusCode: http.StatusOK, + callbackResp: []byte{}, + callbackErr: errors.New("bad response"), + wantErr: assert.Error, + state: mercury.RpcFlakyFailure, + retryable: true, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, errors.New("bad response") + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := setupStreams(t) + defer r.Close() + r.registry = tt.registry + + client := new(evmClientMocks.Client) + s := setupStreams(t) + payload, err := s.abi.Pack("checkCallback", tt.lookup.UpkeepId, values, tt.lookup.ExtraData) + require.Nil(t, err) + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, hexutil.EncodeUint64(tt.lookup.Block)).Return(tt.callbackErr). + Run(func(args mock.Arguments) { + by := args.Get(1).(*hexutil.Bytes) + *by = tt.callbackResp + }).Once() + s.client = client + + state, retryable, _, err := s.checkCallback(context.Background(), tt.values, tt.lookup) + tt.wantErr(t, err, fmt.Sprintf("Error asserion failed: %v", tt.name)) + assert.Equal(t, tt.state, state) + assert.Equal(t, tt.retryable, retryable) + }) + } +} + +func TestStreams_AllowedToUseMercury(t *testing.T) { + upkeepId, ok := new(big.Int).SetString("71022726777042968814359024671382968091267501884371696415772139504780367423725", 10) + assert.True(t, ok, t.Name()) + tests := []struct { + name string + cached bool + allowed bool + ethCallErr error + err error + state mercury.MercuryUpkeepState + reason mercury.MercuryUpkeepFailureReason + registry streamsRegistry + retryable bool + config []byte + }{ + { + name: "success - allowed via cache", + cached: true, + allowed: true, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return nil, nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, nil + }, + }, + }, + { + name: "success - allowed via fetching privilege config", + allowed: true, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, nil + }, + }, + }, + { + name: "success - not allowed via cache", + cached: true, + allowed: false, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return nil, nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, nil + }, + }, + }, + { + name: "success - not allowed via fetching privilege config", + allowed: false, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":false}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, nil + }, + }, + }, + { + name: "failure - cannot unmarshal privilege config", + err: fmt.Errorf("failed to unmarshal privilege config: invalid character '\\x00' looking for beginning of value"), + state: mercury.MercuryUnmarshalError, + config: []byte{0, 1}, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, nil + }, + }, + }, + { + name: "failure - flaky RPC", + retryable: true, + err: fmt.Errorf("failed to get upkeep privilege config: flaky RPC"), + state: mercury.RpcFlakyFailure, + ethCallErr: fmt.Errorf("flaky RPC"), + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return nil, errors.New("flaky RPC") + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, nil + }, + }, + }, + { + name: "failure - empty upkeep privilege config", + err: fmt.Errorf("upkeep privilege config is empty"), + reason: mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed, + config: []byte{}, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(``), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{}, nil + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := setupStreams(t) + defer s.Close() + s.registry = tt.registry + + client := new(evmClientMocks.Client) + s.client = client + + mc := new(MockMercuryConfigProvider) + mc.On("IsUpkeepAllowed", mock.Anything).Return(tt.allowed, tt.cached).Once() + mc.On("SetUpkeepAllowed", mock.Anything, mock.Anything, mock.Anything).Return().Once() + s.mercuryConfig = mc + + if !tt.cached { + if tt.err != nil { + bContractCfg, err := s.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{tt.config}) + require.Nil(t, err) + + payload, err := s.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) + require.Nil(t, err) + + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("string")). + Return(tt.ethCallErr). + Run(func(args mock.Arguments) { + b := args.Get(1).(*hexutil.Bytes) + *b = bContractCfg + }).Once() + } else { + cfg := UpkeepPrivilegeConfig{MercuryEnabled: tt.allowed} + bCfg, err := json.Marshal(cfg) + require.Nil(t, err) + + bContractCfg, err := s.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{bCfg}) + require.Nil(t, err) + + payload, err := s.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) + require.Nil(t, err) + + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("string")).Return(nil). + Run(func(args mock.Arguments) { + b := args.Get(1).(*hexutil.Bytes) + *b = bContractCfg + }).Once() + } + } + + opts := &bind.CallOpts{ + BlockNumber: big.NewInt(10), + } + + state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId) + assert.Equal(t, tt.err, err) + assert.Equal(t, tt.allowed, allowed) + assert.Equal(t, tt.state, state) + assert.Equal(t, tt.reason, reason) + assert.Equal(t, tt.retryable, retryable) + }) + } +} + +func TestStreams_StreamsLookup(t *testing.T) { + upkeepId, ok := new(big.Int).SetString("71022726777042968814359024671382968091267501884371696415772139504780367423725", 10) + var upkeepIdentifier [32]byte + copy(upkeepIdentifier[:], upkeepId.Bytes()) + assert.True(t, ok, t.Name()) + blockNum := ocr2keepers.BlockNumber(37974374) + tests := []struct { + name string + input []ocr2keepers.CheckResult + blobs map[string]string + callbackResp []byte + expectedResults []ocr2keepers.CheckResult + callbackNeeded bool + extraData []byte + checkCallbackResp []byte + values [][]byte + cachedAdminCfg bool + hasError bool + hasPermission bool + v3 bool + registry streamsRegistry + }{ + { + name: "success - happy path no cache", + input: []ocr2keepers.CheckResult{ + { + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(mercury.MercuryUpkeepFailureReasonTargetCheckReverted), + }, + }, + blobs: map[string]string{ + "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000": "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3", + "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000": "0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d", + }, + cachedAdminCfg: false, + extraData: hexutil.MustDecode("0x0000000000000000000000000000000000000064"), + callbackNeeded: true, + checkCallbackResp: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063a400000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + values: [][]byte{hexutil.MustDecode("0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3"), hexutil.MustDecode("0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d")}, + expectedResults: []ocr2keepers.CheckResult{ + { + Eligible: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonNone), + }, + }, + hasPermission: true, + v3: false, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{ + UpkeepNeeded: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + }, nil + }, + }, + }, + { + name: "success - happy path no cache - v0.3", + input: []ocr2keepers.CheckResult{ + { + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000766656564494473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), + }, + }, + blobs: map[string]string{ + "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000": "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3", + "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000": "0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d", + }, + cachedAdminCfg: false, + extraData: hexutil.MustDecode("0x0000000000000000000000000000000000000064"), + callbackNeeded: true, + checkCallbackResp: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063a400000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + values: [][]byte{hexutil.MustDecode("0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3"), hexutil.MustDecode("0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d")}, + expectedResults: []ocr2keepers.CheckResult{ + { + Eligible: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonNone), + }, + }, + hasPermission: true, + v3: true, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{ + UpkeepNeeded: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + }, nil + }, + }, + }, + { + name: "skip - failure reason is insufficient balance", + input: []ocr2keepers.CheckResult{ + { + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), + }, + }, + expectedResults: []ocr2keepers.CheckResult{ + { + Eligible: false, + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), + }, + }, + hasError: true, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{ + UpkeepNeeded: true, + PerformData: []byte{}, + }, nil + }, + }, + }, + { + name: "skip - invalid revert data", + input: []ocr2keepers.CheckResult{ + { + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), + }, + }, + expectedResults: []ocr2keepers.CheckResult{ + { + Eligible: false, + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), + }, + }, + hasError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := setupStreams(t) + defer s.Close() + s.registry = tt.registry + + client := new(evmClientMocks.Client) + s.client = client + + mc := new(MockMercuryConfigProvider) + mc.On("IsUpkeepAllowed", mock.Anything).Return(tt.hasPermission, tt.cachedAdminCfg).Once() + mc.On("SetUpkeepAllowed", mock.Anything, mock.Anything, mock.Anything).Return().Once() + s.mercuryConfig = mc + + if !tt.cachedAdminCfg && !tt.hasError { + cfg := UpkeepPrivilegeConfig{MercuryEnabled: tt.hasPermission} + bCfg, err := json.Marshal(cfg) + require.Nil(t, err) + + bContractCfg, err := s.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{bCfg}) + require.Nil(t, err) + + payload, err := s.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) + require.Nil(t, err) + + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("string")).Return(nil). + Run(func(args mock.Arguments) { + b := args.Get(1).(*hexutil.Bytes) + *b = bContractCfg + }).Once() + } + + if len(tt.blobs) > 0 { + if tt.v3 { + hc03 := new(MockHttpClient) + v03HttpClient := v03.NewClient(s.mercuryConfig, hc03, s.threadCtrl, s.lggr) + s.v03Client = v03HttpClient + + mr1 := v03.MercuryV03Response{ + Reports: []v03.MercuryV03Report{{FullReport: tt.blobs["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]}, {FullReport: tt.blobs["0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"]}}} + b1, err := json.Marshal(mr1) + assert.Nil(t, err) + resp1 := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b1)), + } + hc03.On("Do", mock.Anything).Return(resp1, nil).Once() + } else { + hc02 := new(MockHttpClient) + v02HttpClient := v02.NewClient(s.mercuryConfig, hc02, s.threadCtrl, s.lggr) + s.v02Client = v02HttpClient + + mr1 := v02.MercuryV02Response{ChainlinkBlob: tt.blobs["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]} + b1, err := json.Marshal(mr1) + assert.Nil(t, err) + resp1 := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b1)), + } + mr2 := v02.MercuryV02Response{ChainlinkBlob: tt.blobs["0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"]} + b2, err := json.Marshal(mr2) + assert.Nil(t, err) + resp2 := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b2)), + } + + hc02.On("Do", mock.MatchedBy(func(req *http.Request) bool { + return strings.Contains(req.URL.String(), "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000") + })).Return(resp2, nil).Once() + + hc02.On("Do", mock.MatchedBy(func(req *http.Request) bool { + return strings.Contains(req.URL.String(), "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000") + })).Return(resp1, nil).Once() + } + } + + if tt.callbackNeeded { + payload, err := s.abi.Pack("checkCallback", upkeepId, tt.values, tt.extraData) + require.Nil(t, err) + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, hexutil.EncodeUint64(uint64(blockNum))).Return(nil). + Run(func(args mock.Arguments) { + b := args.Get(1).(*hexutil.Bytes) + *b = tt.checkCallbackResp + }).Once() + } + + got := s.Lookup(context.Background(), tt.input) + assert.Equal(t, tt.expectedResults, got, tt.name) + }) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_failure_reasons.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_failure_reasons.go new file mode 100644 index 0000000000..261fc33bd4 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_failure_reasons.go @@ -0,0 +1,15 @@ +package mercury + +type MercuryUpkeepFailureReason uint8 + +const ( + // upkeep failure onchain reasons + MercuryUpkeepFailureReasonNone MercuryUpkeepFailureReason = 0 + MercuryUpkeepFailureReasonTargetCheckReverted MercuryUpkeepFailureReason = 3 + MercuryUpkeepFailureReasonUpkeepNotNeeded MercuryUpkeepFailureReason = 4 + MercuryUpkeepFailureReasonMercuryCallbackReverted MercuryUpkeepFailureReason = 7 + // leaving a gap here for more onchain failure reasons in the future + // upkeep failure offchain reasons + MercuryUpkeepFailureReasonMercuryAccessNotAllowed MercuryUpkeepFailureReason = 32 + MercuryUpkeepFailureReasonInvalidRevertDataInput MercuryUpkeepFailureReason = 34 +) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_states.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_states.go new file mode 100644 index 0000000000..4e9cd14aee --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_states.go @@ -0,0 +1,14 @@ +package mercury + +type MercuryUpkeepState uint8 + +const ( + NoPipelineError MercuryUpkeepState = 0 + RpcFlakyFailure MercuryUpkeepState = 3 + MercuryFlakyFailure MercuryUpkeepState = 4 + PackUnpackDecodeFailed MercuryUpkeepState = 5 + MercuryUnmarshalError MercuryUpkeepState = 6 + InvalidMercuryRequest MercuryUpkeepState = 7 + InvalidMercuryResponse MercuryUpkeepState = 8 // this will only happen if Mercury server sends bad responses + UpkeepNotAuthorized MercuryUpkeepState = 9 +) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go new file mode 100644 index 0000000000..55436937d1 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go @@ -0,0 +1,203 @@ +package v02 + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "time" + + "github.com/avast/retry-go/v4" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +const ( + mercuryPathV02 = "/client?" // only used to access mercury v0.2 server + retryDelay = 500 * time.Millisecond + totalAttempt = 3 + contentTypeHeader = "Content-Type" + authorizationHeader = "Authorization" + timestampHeader = "X-Authorization-Timestamp" + signatureHeader = "X-Authorization-Signature-SHA256" +) + +type MercuryV02Response struct { + ChainlinkBlob string `json:"chainlinkBlob"` +} + +type client struct { + utils.StartStopOnce + mercuryConfig mercury.MercuryConfigProvider + httpClient mercury.HttpClient + threadCtrl utils.ThreadControl + lggr logger.Logger +} + +func NewClient(mercuryConfig mercury.MercuryConfigProvider, httpClient mercury.HttpClient, threadCtrl utils.ThreadControl, lggr logger.Logger) *client { + return &client{ + mercuryConfig: mercuryConfig, + httpClient: httpClient, + threadCtrl: threadCtrl, + lggr: lggr, + } +} + +func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (mercury.MercuryUpkeepState, mercury.MercuryUpkeepFailureReason, [][]byte, bool, time.Duration, error) { + resultLen := len(streamsLookup.Feeds) + ch := make(chan mercury.MercuryData, resultLen) + if len(streamsLookup.Feeds) == 0 { + return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", streamsLookup.FeedParamKey, streamsLookup.TimeParamKey, streamsLookup.Feeds) + } + for i := range streamsLookup.Feeds { + // TODO (AUTO-7209): limit the number of concurrent requests + i := i + c.threadCtrl.Go(func(ctx context.Context) { + c.singleFeedRequest(ctx, ch, i, streamsLookup) + }) + } + + var reqErr error + var retryInterval time.Duration + results := make([][]byte, len(streamsLookup.Feeds)) + retryable := true + allSuccess := true + // in v0.2, use the last execution error as the state, if no execution errors, state will be no error + state := mercury.NoPipelineError + for i := 0; i < resultLen; i++ { + m := <-ch + if m.Error != nil { + reqErr = errors.Join(reqErr, m.Error) + retryable = retryable && m.Retryable + allSuccess = false + if m.State != mercury.NoPipelineError { + state = mercury.MercuryUpkeepState(m.State) + } + continue + } + results[m.Index] = m.Bytes[0] + } + if retryable && !allSuccess { + retryInterval = mercury.CalculateRetryConfigFn(pluginRetryKey, c.mercuryConfig) + } + // only retry when not all successful AND none are not retryable + return state, mercury.MercuryUpkeepFailureReasonNone, results, retryable && !allSuccess, retryInterval, reqErr +} + +func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.MercuryData, index int, sl *mercury.StreamsLookup) { + var httpRequest *http.Request + var err error + + q := url.Values{ + sl.FeedParamKey: {sl.Feeds[index]}, + sl.TimeParamKey: {sl.Time.String()}, + } + mercuryURL := c.mercuryConfig.Credentials().LegacyURL + reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, mercuryPathV02, q.Encode()) + c.lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.UpkeepId.String(), sl.Feeds[index], reqUrl) + + httpRequest, err = http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) + if err != nil { + ch <- mercury.MercuryData{Index: index, Error: err, Retryable: false, State: mercury.InvalidMercuryRequest} + return + } + + ts := time.Now().UTC().UnixMilli() + signature := mercury.GenerateHMACFn(http.MethodGet, mercuryPathV02+q.Encode(), []byte{}, c.mercuryConfig.Credentials().Username, c.mercuryConfig.Credentials().Password, ts) + httpRequest.Header.Set(contentTypeHeader, "application/json") + httpRequest.Header.Set(authorizationHeader, c.mercuryConfig.Credentials().Username) + httpRequest.Header.Set(timestampHeader, strconv.FormatInt(ts, 10)) + httpRequest.Header.Set(signatureHeader, signature) + + // in the case of multiple retries here, use the last attempt's data + state := mercury.NoPipelineError + retryable := false + sent := false + retryErr := retry.Do( + func() error { + var httpResponse *http.Response + var responseBody []byte + var blobBytes []byte + + retryable = false + if httpResponse, err = c.httpClient.Do(httpRequest); err != nil { + c.lggr.Warnf("at block %s upkeep %s GET request fails for feed %s: %v", sl.Time.String(), sl.UpkeepId.String(), sl.Feeds[index], err) + retryable = true + state = mercury.MercuryFlakyFailure + return err + } + defer httpResponse.Body.Close() + + if responseBody, err = io.ReadAll(httpResponse.Body); err != nil { + state = mercury.InvalidMercuryResponse + return err + } + + switch httpResponse.StatusCode { + case http.StatusNotFound, http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: + c.lggr.Warnf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.UpkeepId.String(), httpResponse.StatusCode, sl.Feeds[index]) + retryable = true + state = mercury.MercuryFlakyFailure + return errors.New(strconv.FormatInt(int64(httpResponse.StatusCode), 10)) + case http.StatusOK: + // continue + default: + state = mercury.InvalidMercuryRequest + return fmt.Errorf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.UpkeepId.String(), httpResponse.StatusCode, sl.Feeds[index]) + } + + c.lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", sl.Time.String(), sl.UpkeepId.String(), httpResponse.StatusCode, hexutil.Encode(responseBody)) + + var m MercuryV02Response + if err = json.Unmarshal(responseBody, &m); err != nil { + c.lggr.Warnf("at block %s upkeep %s failed to unmarshal body to MercuryV02Response for feed %s: %v", sl.Time.String(), sl.UpkeepId.String(), sl.Feeds[index], err) + state = mercury.MercuryUnmarshalError + return err + } + if blobBytes, err = hexutil.Decode(m.ChainlinkBlob); err != nil { + c.lggr.Warnf("at block %s upkeep %s failed to decode chainlinkBlob %s for feed %s: %v", sl.Time.String(), sl.UpkeepId.String(), m.ChainlinkBlob, sl.Feeds[index], err) + state = mercury.InvalidMercuryResponse + return err + } + ch <- mercury.MercuryData{ + Index: index, + Bytes: [][]byte{blobBytes}, + Retryable: false, + State: mercury.NoPipelineError, + } + sent = true + return nil + }, + // only retry when the error is 404 Not Found, 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout + retry.RetryIf(func(err error) bool { + return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) || err.Error() == fmt.Sprintf("%d", http.StatusBadGateway) || err.Error() == fmt.Sprintf("%d", http.StatusServiceUnavailable) || err.Error() == fmt.Sprintf("%d", http.StatusGatewayTimeout) + }), + retry.Context(ctx), + retry.Delay(retryDelay), + retry.Attempts(totalAttempt), + ) + + if !sent { + ch <- mercury.MercuryData{ + Index: index, + Bytes: [][]byte{}, + Retryable: retryable, + Error: fmt.Errorf("failed to request feed for %s: %w", sl.Feeds[index], retryErr), + State: state, + } + } +} + +func (c *client) Close() error { + return c.StopOnce("v02_request", func() error { + c.threadCtrl.Close() + return nil + }) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go new file mode 100644 index 0000000000..17ef8515fd --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go @@ -0,0 +1,468 @@ +package v02 + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "io" + "math/big" + "net/http" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/patrickmn/go-cache" + "github.com/stretchr/testify/mock" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" +) + +const ( + defaultPluginRetryExpiration = 30 * time.Minute + cleanupInterval = 5 * time.Minute +) + +type MockMercuryConfigProvider struct { + cache *cache.Cache + mock.Mock +} + +func NewMockMercuryConfigProvider() *MockMercuryConfigProvider { + return &MockMercuryConfigProvider{ + cache: cache.New(defaultPluginRetryExpiration, cleanupInterval), + } +} + +func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { + mc := &models.MercuryCredentials{ + LegacyURL: "https://google.old.com", + URL: "https://google.com", + Username: "FakeClientID", + Password: "FakeClientKey", + } + return mc +} + +func (m *MockMercuryConfigProvider) IsUpkeepAllowed(s string) (interface{}, bool) { + args := m.Called(s) + return args.Get(0), args.Bool(1) +} + +func (m *MockMercuryConfigProvider) SetUpkeepAllowed(s string, i interface{}, d time.Duration) { + m.Called(s, i, d) +} + +func (m *MockMercuryConfigProvider) GetPluginRetry(s string) (interface{}, bool) { + if value, found := m.cache.Get(s); found { + return value, true + } + + return nil, false +} + +func (m *MockMercuryConfigProvider) SetPluginRetry(s string, i interface{}, d time.Duration) { + m.cache.Set(s, i, d) +} + +type MockHttpClient struct { + mock.Mock +} + +func (mock *MockHttpClient) Do(req *http.Request) (*http.Response, error) { + args := mock.Called(req) + return args.Get(0).(*http.Response), args.Error(1) +} + +// setups up a client object for tests. +func setupClient(t *testing.T) *client { + lggr := logger.TestLogger(t) + mockHttpClient := new(MockHttpClient) + mercuryConfig := NewMockMercuryConfigProvider() + threadCtl := utils.NewThreadControl() + + client := NewClient( + mercuryConfig, + mockHttpClient, + threadCtl, + lggr, + ) + return client +} + +func TestV02_SingleFeedRequest(t *testing.T) { + upkeepId := big.NewInt(123456789) + tests := []struct { + name string + index int + lookup *mercury.StreamsLookup + blob string + statusCode int + lastStatusCode int + retryNumber int + retryable bool + errorMessage string + }{ + { + name: "success - mercury responds in the first try", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dc00000012", + }, + { + name: "success - retry for 404", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dcbabbad", + retryNumber: 1, + statusCode: http.StatusNotFound, + lastStatusCode: http.StatusOK, + }, + { + name: "success - retry for 500", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dcbbabad", + retryNumber: 2, + statusCode: http.StatusInternalServerError, + lastStatusCode: http.StatusOK, + }, + { + name: "failure - returns retryable", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dc", + retryNumber: totalAttempt, + statusCode: http.StatusNotFound, + retryable: true, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: 404\n#3: 404", + }, + { + name: "failure - returns retryable and then non-retryable", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dc", + retryNumber: 1, + statusCode: http.StatusNotFound, + lastStatusCode: http.StatusTooManyRequests, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: at block 123456 upkeep 123456789 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + }, + { + name: "failure - returns not retryable", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dc", + statusCode: http.StatusConflict, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 409 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := setupClient(t) + defer c.Close() + hc := new(MockHttpClient) + + mr := MercuryV02Response{ChainlinkBlob: tt.blob} + b, err := json.Marshal(mr) + assert.Nil(t, err) + + if tt.retryNumber == 0 { + if tt.errorMessage != "" { + resp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } else { + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } + } else if tt.retryNumber > 0 && tt.retryNumber < totalAttempt { + retryResp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) + + resp := &http.Response{ + StatusCode: tt.lastStatusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } else { + resp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Times(tt.retryNumber) + } + c.httpClient = hc + + ch := make(chan mercury.MercuryData, 1) + c.singleFeedRequest(context.Background(), ch, tt.index, tt.lookup) + + m := <-ch + assert.Equal(t, tt.index, m.Index) + assert.Equal(t, tt.retryable, m.Retryable) + if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { + assert.Equal(t, tt.errorMessage, m.Error.Error()) + assert.Equal(t, [][]byte{}, m.Bytes) + } else { + blobBytes, err := hexutil.Decode(tt.blob) + assert.Nil(t, err) + assert.Nil(t, m.Error) + assert.Equal(t, [][]byte{blobBytes}, m.Bytes) + } + }) + } +} + +func TestV02_DoMercuryRequestV02(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + + tests := []struct { + name string + lookup *mercury.StreamsLookup + mockHttpStatusCode int + mockChainlinkBlobs []string + pluginRetries int + pluginRetryKey string + expectedValues [][]byte + expectedRetryable bool + expectedRetryInterval time.Duration + expectedError error + state mercury.MercuryUpkeepState + reason mercury.MercuryUpkeepFailureReason + }{ + { + name: "success", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + mockHttpStatusCode: http.StatusOK, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{{0, 6, 109, 252, 209, 237, 45, 149, 177, 140, 148, 141, 188, 91, 214, 76, 104, 122, 254, 147, 228, 202, 125, 102, 61, 222, 193, 76, 32, 9, 10, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 69, 84, 72, 45, 85, 83, 68, 45, 65, 82, 66, 73, 84, 82, 85, 77, 45, 84, 69, 83, 84, 78, 69, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 216, 211, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 207, 11, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 155, 61, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 206, 116, 217, 250, 37, 42, 137, 131, 151, 110, 171, 96, 13, 199, 89, 12, 119, 141, 4, 129, 52, 48, 132, 27, 198, 231, 101, 195, 76, 216, 26, 22, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 96, 65, 43, 148, 229, 37, 202, 108, 237, 201, 245, 68, 253, 134, 247, 118, 6, 213, 47, 231, 49, 165, 208, 105, 219, 232, 54, 168, 191, 192, 251, 140, 145, 25, 99, 176, 174, 122, 20, 151, 31, 59, 70, 33, 191, 251, 128, 46, 240, 96, 83, 146, 185, 166, 200, 156, 127, 171, 29, 248, 99, 58, 90, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 69, 0, 194, 245, 33, 248, 63, 186, 94, 252, 43, 243, 239, 250, 174, 221, 228, 61, 10, 74, 223, 247, 133, 193, 33, 59, 113, 42, 58, 237, 13, 129, 87, 100, 42, 132, 50, 77, 176, 207, 150, 149, 235, 210, 119, 8, 212, 96, 142, 176, 51, 126, 13, 216, 123, 14, 67, 240, 250, 112, 199, 0, 217, 17}}, + expectedRetryable: false, + expectedError: nil, + }, + { + name: "failure - retryable and interval is 1s", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + mockHttpStatusCode: http.StatusInternalServerError, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{nil}, + expectedRetryable: true, + pluginRetries: 0, + expectedRetryInterval: 1 * time.Second, + expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), + state: mercury.MercuryFlakyFailure, + }, + { + name: "failure - retryable and interval is 5s", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + pluginRetries: 5, + mockHttpStatusCode: http.StatusInternalServerError, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{nil}, + expectedRetryable: true, + expectedRetryInterval: 5 * time.Second, + expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), + state: mercury.MercuryFlakyFailure, + }, + { + name: "failure - not retryable because there are many plugin retries already", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + pluginRetries: 10, + mockHttpStatusCode: http.StatusInternalServerError, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{nil}, + expectedRetryable: true, + expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), + state: mercury.MercuryFlakyFailure, + }, + { + name: "failure - not retryable", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + mockHttpStatusCode: http.StatusTooManyRequests, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{nil}, + expectedRetryable: false, + expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 25880526 upkeep 88786950015966611018675766524283132478093844178961698330929478019253453382042 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + state: mercury.InvalidMercuryRequest, + }, + { + name: "failure - no feeds", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + expectedValues: [][]byte{}, + reason: mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, + }, + { + name: "failure - invalid revert data", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + expectedValues: [][]byte{}, + reason: mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := setupClient(t) + defer c.Close() + if tt.pluginRetries != 0 { + c.mercuryConfig.SetPluginRetry(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) + } + hc := new(MockHttpClient) + + for _, blob := range tt.mockChainlinkBlobs { + mr := MercuryV02Response{ChainlinkBlob: blob} + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: tt.mockHttpStatusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + if tt.expectedError != nil && tt.expectedRetryable || tt.pluginRetries > 0 { + hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) + } else { + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } + } + c.httpClient = hc + + state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(context.Background(), tt.lookup, tt.pluginRetryKey) + assert.Equal(t, tt.expectedValues, values) + assert.Equal(t, tt.expectedRetryable, retryable) + if retryable { + newRetries, _ := c.mercuryConfig.GetPluginRetry(tt.pluginRetryKey) + assert.Equal(t, tt.pluginRetries+1, newRetries.(int)) + } + assert.Equal(t, tt.expectedRetryInterval, retryInterval) + assert.Equal(t, tt.state, state) + assert.Equal(t, tt.reason, reason) + if tt.expectedError != nil { + assert.True(t, strings.HasPrefix(reqErr.Error(), "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000")) + } + }) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go new file mode 100644 index 0000000000..3697dca53c --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go @@ -0,0 +1,252 @@ +package v03 + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/avast/retry-go/v4" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +const ( + mercuryBatchPathV03 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server + mercuryBatchPathV03BlockNumber = "/api/v1gmx/reports/bulk?" // only used to access mercury v0.3 server with blockNumber + retryDelay = 500 * time.Millisecond + totalAttempt = 3 + contentTypeHeader = "Content-Type" + authorizationHeader = "Authorization" + timestampHeader = "X-Authorization-Timestamp" + signatureHeader = "X-Authorization-Signature-SHA256" + upkeepIDHeader = "X-Authorization-Upkeep-Id" +) + +type MercuryV03Response struct { + Reports []MercuryV03Report `json:"reports"` +} + +type MercuryV03Report struct { + FeedID string `json:"feedID"` // feed id in hex encoded + ValidFromTimestamp uint32 `json:"validFromTimestamp"` + ObservationsTimestamp uint32 `json:"observationsTimestamp"` + FullReport string `json:"fullReport"` // the actual hex encoded mercury report of this feed, can be sent to verifier +} + +type client struct { + utils.StartStopOnce + mercuryConfig mercury.MercuryConfigProvider + httpClient mercury.HttpClient + threadCtrl utils.ThreadControl + lggr logger.Logger +} + +func NewClient(mercuryConfig mercury.MercuryConfigProvider, httpClient mercury.HttpClient, threadCtrl utils.ThreadControl, lggr logger.Logger) *client { + return &client{ + mercuryConfig: mercuryConfig, + httpClient: httpClient, + threadCtrl: threadCtrl, + lggr: lggr, + } +} + +func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (mercury.MercuryUpkeepState, mercury.MercuryUpkeepFailureReason, [][]byte, bool, time.Duration, error) { + resultLen := len(streamsLookup.Feeds) + ch := make(chan mercury.MercuryData, resultLen) + if len(streamsLookup.Feeds) == 0 { + return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", streamsLookup.FeedParamKey, streamsLookup.TimeParamKey, streamsLookup.Feeds) + } + resultLen = 1 + c.threadCtrl.Go(func(ctx context.Context) { + c.multiFeedsRequest(ctx, ch, streamsLookup) + }) + + var reqErr error + var retryInterval time.Duration + results := make([][]byte, len(streamsLookup.Feeds)) + retryable := true + allSuccess := true + state := mercury.NoPipelineError + + for i := 0; i < resultLen; i++ { + m := <-ch + if m.Error != nil { + reqErr = errors.Join(reqErr, m.Error) + retryable = retryable && m.Retryable + allSuccess = false + if m.State != mercury.NoPipelineError { + state = m.State + } + continue + } + results = m.Bytes + } + // only retry when not all successful AND none are not retryable + if retryable && !allSuccess { + retryInterval = mercury.CalculateRetryConfigFn(pluginRetryKey, c.mercuryConfig) + } + // only retry when not all successful AND none are not retryable + return state, mercury.MercuryUpkeepFailureReasonNone, results, retryable && !allSuccess, retryInterval, reqErr +} + +func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.MercuryData, sl *mercury.StreamsLookup) { + // this won't work bc q.Encode() will encode commas as '%2C' but the server is strictly expecting a comma separated list + //q := url.Values{ + // feedIDs: {strings.Join(sl.Feeds, ",")}, + // timestamp: {sl.Time.String()}, + //} + + params := fmt.Sprintf("%s=%s&%s=%s", mercury.FeedIDs, strings.Join(sl.Feeds, ","), mercury.Timestamp, sl.Time.String()) + batchPathV03 := mercuryBatchPathV03 + if sl.IsMercuryUsingBatchPathV03() { + batchPathV03 = mercuryBatchPathV03BlockNumber + } + reqUrl := fmt.Sprintf("%s%s%s", c.mercuryConfig.Credentials().URL, batchPathV03, params) + + c.lggr.Debugf("request URL for upkeep %s userId %s: %s", sl.UpkeepId.String(), c.mercuryConfig.Credentials().Username, reqUrl) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) + if err != nil { + ch <- mercury.MercuryData{Index: 0, Error: err, Retryable: false, State: mercury.InvalidMercuryRequest} + return + } + + ts := time.Now().UTC().UnixMilli() + signature := mercury.GenerateHMACFn(http.MethodGet, mercuryBatchPathV03+params, []byte{}, c.mercuryConfig.Credentials().Username, c.mercuryConfig.Credentials().Password, ts) + + req.Header.Set(contentTypeHeader, "application/json") + // username here is often referred to as user id + req.Header.Set(authorizationHeader, c.mercuryConfig.Credentials().Username) + req.Header.Set(timestampHeader, strconv.FormatInt(ts, 10)) + req.Header.Set(signatureHeader, signature) + // mercury will inspect authorization headers above to make sure this user (in automation's context, this node) is eligible to access mercury + // and if it has an automation role. it will then look at this upkeep id to check if it has access to all the requested feeds. + req.Header.Set(upkeepIDHeader, sl.UpkeepId.String()) + + // in the case of multiple retries here, use the last attempt's data + state := mercury.NoPipelineError + retryable := false + sent := false + retryErr := retry.Do( + func() error { + retryable = false + resp, err := c.httpClient.Do(req) + if err != nil { + c.lggr.Warnf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.Time.String(), sl.UpkeepId.String(), err) + retryable = true + state = mercury.MercuryFlakyFailure + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + retryable = false + state = mercury.InvalidMercuryResponse + return err + } + + c.lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) + switch resp.StatusCode { + case http.StatusUnauthorized: + retryable = false + state = mercury.UpkeepNotAuthorized + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) + case http.StatusBadRequest: + retryable = false + state = mercury.InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) + case http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: + retryable = true + state = mercury.MercuryFlakyFailure + return fmt.Errorf("%d", resp.StatusCode) + case http.StatusPartialContent: + // TODO (AUTO-5044): handle response code 206 entirely with errors field parsing + c.lggr.Warnf("at timestamp %s upkeep %s requested [%s] feeds but mercury v0.3 server returned 206 status, treating it as 404 and retrying", sl.Time.String(), sl.UpkeepId.String(), sl.Feeds) + retryable = true + state = mercury.MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusPartialContent) + case http.StatusOK: + // continue + default: + retryable = false + state = mercury.InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) + } + c.lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.3 with BODY=%s", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + + var response MercuryV03Response + if err := json.Unmarshal(body, &response); err != nil { + c.lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.Time.String(), sl.UpkeepId.String(), err) + retryable = false + state = mercury.MercuryUnmarshalError + return err + } + + // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract + // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated + if len(response.Reports) != len(sl.Feeds) { + var receivedFeeds []string + for _, f := range response.Reports { + receivedFeeds = append(receivedFeeds, f.FeedID) + } + c.lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server returned 206 status with [%s] reports while we requested [%s] feeds, retrying", sl.Time.String(), sl.UpkeepId.String(), receivedFeeds, sl.Feeds) + retryable = true + state = mercury.MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusNotFound) + } + var reportBytes [][]byte + for _, rsp := range response.Reports { + b, err := hexutil.Decode(rsp.FullReport) + if err != nil { + c.lggr.Warnf("at timestamp %s upkeep %s failed to decode reportBlob %s: %v", sl.Time.String(), sl.UpkeepId.String(), rsp.FullReport, err) + retryable = false + state = mercury.InvalidMercuryResponse + return err + } + reportBytes = append(reportBytes, b) + } + ch <- mercury.MercuryData{ + Index: 0, + Bytes: reportBytes, + Retryable: false, + State: mercury.NoPipelineError, + } + sent = true + return nil + }, + // only retry when the error is 206 Partial Content, 404 Not Found, 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout + retry.RetryIf(func(err error) bool { + return err.Error() == fmt.Sprintf("%d", http.StatusPartialContent) || err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) || err.Error() == fmt.Sprintf("%d", http.StatusBadGateway) || err.Error() == fmt.Sprintf("%d", http.StatusServiceUnavailable) || err.Error() == fmt.Sprintf("%d", http.StatusGatewayTimeout) + }), + retry.Context(ctx), + retry.Delay(retryDelay), + retry.Attempts(totalAttempt), + ) + + if !sent { + ch <- mercury.MercuryData{ + Index: 0, + Bytes: [][]byte{}, + Retryable: retryable, + Error: retryErr, + State: state, + } + } +} + +func (c *client) Close() error { + return c.StopOnce("v03_request", func() error { + c.threadCtrl.Close() + return nil + }) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go new file mode 100644 index 0000000000..bef2cdac58 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go @@ -0,0 +1,536 @@ +package v03 + +import ( + "bytes" + "context" + "encoding/json" + "io" + "math/big" + "net/http" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/patrickmn/go-cache" + "github.com/stretchr/testify/mock" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" +) + +const ( + defaultPluginRetryExpiration = 30 * time.Minute + cleanupInterval = 5 * time.Minute +) + +type MockMercuryConfigProvider struct { + cache *cache.Cache + mock.Mock +} + +func NewMockMercuryConfigProvider() *MockMercuryConfigProvider { + return &MockMercuryConfigProvider{ + cache: cache.New(defaultPluginRetryExpiration, cleanupInterval), + } +} + +func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { + mc := &models.MercuryCredentials{ + LegacyURL: "https://google.old.com", + URL: "https://google.com", + Username: "FakeClientID", + Password: "FakeClientKey", + } + return mc +} + +func (m *MockMercuryConfigProvider) IsUpkeepAllowed(s string) (interface{}, bool) { + args := m.Called(s) + return args.Get(0), args.Bool(1) +} + +func (m *MockMercuryConfigProvider) SetUpkeepAllowed(s string, i interface{}, d time.Duration) { + m.Called(s, i, d) +} + +func (m *MockMercuryConfigProvider) GetPluginRetry(s string) (interface{}, bool) { + if value, found := m.cache.Get(s); found { + return value, true + } + + return nil, false +} + +func (m *MockMercuryConfigProvider) SetPluginRetry(s string, i interface{}, d time.Duration) { + m.cache.Set(s, i, d) +} + +type MockHttpClient struct { + mock.Mock +} + +func (mock *MockHttpClient) Do(req *http.Request) (*http.Response, error) { + args := mock.Called(req) + return args.Get(0).(*http.Response), args.Error(1) +} + +// setups up a client object for tests. +func setupClient(t *testing.T) *client { + lggr := logger.TestLogger(t) + mockHttpClient := new(MockHttpClient) + mercuryConfig := NewMockMercuryConfigProvider() + threadCtl := utils.NewThreadControl() + + client := NewClient( + mercuryConfig, + mockHttpClient, + threadCtl, + lggr, + ) + return client +} + +func TestV03_DoMercuryRequestV03(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + + tests := []struct { + name string + lookup *mercury.StreamsLookup + mockHttpStatusCode int + mockChainlinkBlobs []string + pluginRetryKey string + expectedValues [][]byte + expectedRetryable bool + expectedRetryInterval time.Duration + expectedError error + state mercury.MercuryUpkeepState + reason mercury.MercuryUpkeepFailureReason + }{ + { + name: "success v0.3", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + mockHttpStatusCode: http.StatusOK, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{{0, 6, 109, 252, 209, 237, 45, 149, 177, 140, 148, 141, 188, 91, 214, 76, 104, 122, 254, 147, 228, 202, 125, 102, 61, 222, 193, 76, 32, 9, 10, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 69, 84, 72, 45, 85, 83, 68, 45, 65, 82, 66, 73, 84, 82, 85, 77, 45, 84, 69, 83, 84, 78, 69, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 216, 211, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 207, 11, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 155, 61, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 206, 116, 217, 250, 37, 42, 137, 131, 151, 110, 171, 96, 13, 199, 89, 12, 119, 141, 4, 129, 52, 48, 132, 27, 198, 231, 101, 195, 76, 216, 26, 22, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 96, 65, 43, 148, 229, 37, 202, 108, 237, 201, 245, 68, 253, 134, 247, 118, 6, 213, 47, 231, 49, 165, 208, 105, 219, 232, 54, 168, 191, 192, 251, 140, 145, 25, 99, 176, 174, 122, 20, 151, 31, 59, 70, 33, 191, 251, 128, 46, 240, 96, 83, 146, 185, 166, 200, 156, 127, 171, 29, 248, 99, 58, 90, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 69, 0, 194, 245, 33, 248, 63, 186, 94, 252, 43, 243, 239, 250, 174, 221, 228, 61, 10, 74, 223, 247, 133, 193, 33, 59, 113, 42, 58, 237, 13, 129, 87, 100, 42, 132, 50, 77, 176, 207, 150, 149, 235, 210, 119, 8, 212, 96, 142, 176, 51, 126, 13, 216, 123, 14, 67, 240, 250, 112, 199, 0, 217, 17}}, + expectedRetryable: false, + expectedError: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := setupClient(t) + defer c.Close() + hc := mocks.NewHttpClient(t) + + mr := MercuryV03Response{} + for i, blob := range tt.mockChainlinkBlobs { + r := MercuryV03Report{ + FeedID: tt.lookup.Feeds[i], + ValidFromTimestamp: 0, + ObservationsTimestamp: 0, + FullReport: blob, + } + mr.Reports = append(mr.Reports, r) + } + + b, err := json.Marshal(mr) + assert.Nil(t, err) + resp := &http.Response{ + StatusCode: tt.mockHttpStatusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + if tt.expectedError != nil && tt.expectedRetryable { + hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) + } else { + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } + c.httpClient = hc + + state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(context.Background(), tt.lookup, tt.pluginRetryKey) + + assert.Equal(t, tt.expectedValues, values) + assert.Equal(t, tt.expectedRetryable, retryable) + assert.Equal(t, tt.expectedRetryInterval, retryInterval) + assert.Equal(t, tt.state, state) + assert.Equal(t, tt.reason, reason) + if tt.expectedError != nil { + assert.Equal(t, tt.expectedError.Error(), reqErr.Error()) + } + }) + } +} + +func TestV03_MultiFeedRequest(t *testing.T) { + upkeepId := big.NewInt(123456789) + tests := []struct { + name string + lookup *mercury.StreamsLookup + statusCode int + lastStatusCode int + pluginRetries int + pluginRetryKey string + retryNumber int + retryable bool + errorMessage string + firstResponse *MercuryV03Response + response *MercuryV03Response + }{ + { + name: "success - mercury responds in the first try", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000016", + }, + }, + }, + statusCode: http.StatusOK, + }, + { + name: "success - mercury responds in the first try with blocknumber", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000016", + }, + }, + }, + statusCode: http.StatusOK, + }, + { + name: "success - retry 206", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + firstResponse: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000019", + }, + }, + }, + retryNumber: 1, + statusCode: http.StatusPartialContent, + lastStatusCode: http.StatusOK, + }, + { + name: "success - retry for 500", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + retryNumber: 2, + statusCode: http.StatusInternalServerError, + lastStatusCode: http.StatusOK, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000019", + }, + }, + }, + }, + { + name: "failure - fail to decode reportBlob", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "qerwiu", // invalid hex blob + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000016", + }, + }, + }, + statusCode: http.StatusOK, + retryable: false, + errorMessage: "All attempts fail:\n#1: hex string without 0x prefix", + }, + { + name: "failure - returns retryable with 1s plugin retry interval", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + retryNumber: totalAttempt, + statusCode: http.StatusInternalServerError, + retryable: true, + errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", + }, + { + name: "failure - returns retryable with 5s plugin retry interval", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + pluginRetries: 6, + retryNumber: totalAttempt, + statusCode: http.StatusInternalServerError, + retryable: true, + errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", + }, + { + name: "failure - returns retryable and then non-retryable", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + retryNumber: 1, + statusCode: http.StatusInternalServerError, + lastStatusCode: http.StatusUnauthorized, + errorMessage: "All attempts fail:\n#1: 500\n#2: at timestamp 123456 upkeep 123456789 received status code 401 from mercury v0.3, most likely this is caused by unauthorized upkeep", + }, + { + name: "failure - returns status code 422 not retryable", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + statusCode: http.StatusUnprocessableEntity, + errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 422 from mercury v0.3", + }, + { + name: "success - retry when reports length does not match feeds length", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + firstResponse: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000019", + }, + }, + }, + retryNumber: 1, + statusCode: http.StatusOK, + lastStatusCode: http.StatusOK, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := setupClient(t) + defer c.Close() + if tt.pluginRetries != 0 { + c.mercuryConfig.SetPluginRetry(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) + } + + hc := new(MockHttpClient) + b, err := json.Marshal(tt.response) + assert.Nil(t, err) + + if tt.retryNumber == 0 { + resp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } else if tt.retryNumber < totalAttempt { + if tt.firstResponse != nil && tt.response != nil { + b0, err := json.Marshal(tt.firstResponse) + assert.Nil(t, err) + resp0 := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b0)), + } + b1, err := json.Marshal(tt.response) + assert.Nil(t, err) + resp1 := &http.Response{ + StatusCode: tt.lastStatusCode, + Body: io.NopCloser(bytes.NewReader(b1)), + } + hc.On("Do", mock.Anything).Return(resp0, nil).Once().On("Do", mock.Anything).Return(resp1, nil).Once() + } else { + retryResp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) + + resp := &http.Response{ + StatusCode: tt.lastStatusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } + } else { + resp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Times(tt.retryNumber) + } + c.httpClient = hc + + ch := make(chan mercury.MercuryData, 1) + c.multiFeedsRequest(context.Background(), ch, tt.lookup) + + m := <-ch + assert.Equal(t, 0, m.Index) + assert.Equal(t, tt.retryable, m.Retryable) + if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { + assert.Equal(t, tt.errorMessage, m.Error.Error()) + assert.Equal(t, [][]byte{}, m.Bytes) + } else { + assert.Nil(t, m.Error) + var reports [][]byte + for _, rsp := range tt.response.Reports { + b, _ := hexutil.Decode(rsp.FullReport) + reports = append(reports, b) + } + assert.Equal(t, reports, m.Bytes) + } + }) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 73e2bc0a9c..252d2d91c7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -17,9 +17,9 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -42,8 +42,6 @@ const ( // cleanupInterval decides when the expired items in cache will be deleted. cleanupInterval = 5 * time.Minute logTriggerRefreshBatchSize = 32 - totalFastPluginRetries = 5 - totalMediumPluginRetries = 10 ) var ( @@ -89,30 +87,34 @@ func NewEvmRegistry( blockSub *BlockSubscriber, finalityDepth uint32, ) *EvmRegistry { + mercuryConfig := &MercuryConfig{ + cred: mc, + Abi: core.StreamsCompatibleABI, + AllowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), + pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), + } + + hc := http.DefaultClient + return &EvmRegistry{ - ctx: context.Background(), - threadCtrl: utils.NewThreadControl(), - lggr: lggr.Named(RegistryServiceName), - poller: client.LogPoller(), - addr: addr, - client: client.Client(), - logProcessed: make(map[string]bool), - registry: registry, - abi: core.RegistryABI, - active: al, - packer: packer, - headFunc: func(ocr2keepers.BlockKey) {}, - chLog: make(chan logpoller.Log, 1000), - mercury: &MercuryConfig{ - cred: mc, - abi: core.StreamsCompatibleABI, - allowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), - pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), - }, - hc: http.DefaultClient, + ctx: context.Background(), + threadCtrl: utils.NewThreadControl(), + lggr: lggr.Named(RegistryServiceName), + poller: client.LogPoller(), + addr: addr, + client: client.Client(), + logProcessed: make(map[string]bool), + registry: registry, + abi: core.RegistryABI, + active: al, + packer: packer, + headFunc: func(ocr2keepers.BlockKey) {}, + chLog: make(chan logpoller.Log, 1000), + hc: hc, logEventProvider: logEventProvider, bs: blockSub, finalityDepth: finalityDepth, + streams: streams.NewStreamsLookup(packer, mercuryConfig, blockSub, client.Client(), registry, lggr), } } @@ -128,15 +130,43 @@ var upkeepStateEvents = []common.Hash{ type MercuryConfig struct { cred *models.MercuryCredentials - abi abi.ABI - // allowListCache stores the upkeeps privileges. In 2.1, this only includes a JSON bytes for allowed to use mercury - allowListCache *cache.Cache - + Abi abi.ABI + // AllowListCache stores the upkeeps privileges. In 2.1, this only includes a JSON bytes for allowed to use mercury + AllowListCache *cache.Cache pluginRetryCache *cache.Cache } +func NewMercuryConfig(credentials *models.MercuryCredentials, abi abi.ABI) *MercuryConfig { + return &MercuryConfig{ + cred: credentials, + Abi: abi, + AllowListCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), + pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), + } +} + +func (c *MercuryConfig) Credentials() *models.MercuryCredentials { + return c.cred +} + +func (c *MercuryConfig) IsUpkeepAllowed(k string) (interface{}, bool) { + return c.AllowListCache.Get(k) +} + +func (c *MercuryConfig) SetUpkeepAllowed(k string, v interface{}, d time.Duration) { + c.AllowListCache.Set(k, v, d) +} + +func (c *MercuryConfig) GetPluginRetry(k string) (interface{}, bool) { + return c.pluginRetryCache.Get(k) +} + +func (c *MercuryConfig) SetPluginRetry(k string, v interface{}, d time.Duration) { + c.pluginRetryCache.Set(k, v, d) +} + type EvmRegistry struct { - services.StateMachine + utils.StartStopOnce threadCtrl utils.ThreadControl lggr logger.Logger poller logpoller.LogPoller @@ -158,6 +188,7 @@ type EvmRegistry struct { bs *BlockSubscriber logEventProvider logprovider.LogEventProvider finalityDepth uint32 + streams streams.Lookup } func (r *EvmRegistry) Name() string { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go index c9752ea14d..ad31c8feb0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go @@ -70,7 +70,7 @@ func (r *EvmRegistry) doCheck(ctx context.Context, keys []ocr2keepers.UpkeepPayl return } - upkeepResults = r.streamsLookup(ctx, upkeepResults) + upkeepResults = r.streams.Lookup(ctx, upkeepResults) upkeepResults, err = r.simulatePerformUpkeeps(ctx, upkeepResults) if err != nil { @@ -104,7 +104,7 @@ func (r *EvmRegistry) getBlockHash(blockNumber *big.Int) (common.Hash, error) { } // verifyCheckBlock checks that the check block and hash are valid, returns the pipeline execution state and retryable -func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state encoding.PipelineExecutionState, retryable bool) { +func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state uint8, retryable bool) { // verify check block number and hash are valid h, ok := r.bs.queryBlocksMap(checkBlock.Int64()) // if this block number/hash combo exists in block subscriber, this check block and hash still exist on chain and are valid @@ -127,7 +127,7 @@ func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId * } // verifyLogExists checks that the log still exists on chain, returns failure reason, pipeline error, and retryable -func (r *EvmRegistry) verifyLogExists(upkeepId *big.Int, p ocr2keepers.UpkeepPayload) (encoding.UpkeepFailureReason, encoding.PipelineExecutionState, bool) { +func (r *EvmRegistry) verifyLogExists(upkeepId *big.Int, p ocr2keepers.UpkeepPayload) (uint8, uint8, bool) { logBlockNumber := int64(p.Trigger.LogTriggerExtension.BlockNumber) logBlockHash := common.BytesToHash(p.Trigger.LogTriggerExtension.BlockHash[:]) checkBlockHash := common.BytesToHash(p.Trigger.BlockHash[:]) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go index 5ea2bdc667..2e39892e47 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go @@ -4,12 +4,23 @@ import ( "context" "fmt" "math/big" + "strings" "sync/atomic" "testing" + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/patrickmn/go-cache" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -81,7 +92,7 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { payload ocr2keepers.UpkeepPayload blocks map[int64]string poller logpoller.LogPoller - state encoding.PipelineExecutionState + state uint8 retryable bool makeEthCall bool }{ @@ -239,8 +250,8 @@ func TestRegistry_VerifyLogExists(t *testing.T) { payload ocr2keepers.UpkeepPayload blocks map[int64]string makeEthCall bool - reason encoding.UpkeepFailureReason - state encoding.PipelineExecutionState + reason uint8 + state uint8 retryable bool ethCallErr error receipt *types.Receipt @@ -645,5 +656,44 @@ func TestRegistry_SimulatePerformUpkeeps(t *testing.T) { assert.Equal(t, tc.err, err) }) } +} +// setups up an evm registry for tests. +func setupEVMRegistry(t *testing.T) *EvmRegistry { + lggr := logger.TestLogger(t) + addr := common.HexToAddress("0x6cA639822c6C241Fa9A7A6b5032F6F7F1C513CAD") + keeperRegistryABI, err := abi.JSON(strings.NewReader(i_keeper_registry_master_wrapper_2_1.IKeeperRegistryMasterABI)) + require.Nil(t, err, "need registry abi") + streamsLookupCompatibleABI, err := abi.JSON(strings.NewReader(streams_lookup_compatible_interface.StreamsLookupCompatibleInterfaceABI)) + require.Nil(t, err, "need mercury abi") + var logPoller logpoller.LogPoller + mockReg := mocks.NewRegistry(t) + mockHttpClient := mocks.NewHttpClient(t) + client := evmClientMocks.NewClient(t) + + r := &EvmRegistry{ + lggr: lggr, + poller: logPoller, + addr: addr, + client: client, + logProcessed: make(map[string]bool), + registry: mockReg, + abi: keeperRegistryABI, + active: NewActiveUpkeepList(), + packer: encoding.NewAbiPacker(), + headFunc: func(ocr2keepers.BlockKey) {}, + chLog: make(chan logpoller.Log, 1000), + mercury: &MercuryConfig{ + cred: &models.MercuryCredentials{ + LegacyURL: "https://google.old.com", + URL: "https://google.com", + Username: "FakeClientID", + Password: "FakeClientKey", + }, + Abi: streamsLookupCompatibleABI, + AllowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), + }, + hc: mockHttpClient, + } + return r } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go deleted file mode 100644 index af7ff42b93..0000000000 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ /dev/null @@ -1,642 +0,0 @@ -package evm - -import ( - "context" - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "io" - "math/big" - "net/http" - "net/url" - "strconv" - "strings" - "sync" - "time" - - "github.com/avast/retry-go/v4" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/patrickmn/go-cache" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" -) - -const ( - applicationJson = "application/json" - blockNumber = "blockNumber" // valid for v0.2 - feedIDs = "feedIDs" // valid for v0.3 - feedIdHex = "feedIdHex" // valid for v0.2 - headerAuthorization = "Authorization" - headerContentType = "Content-Type" - headerTimestamp = "X-Authorization-Timestamp" - headerSignature = "X-Authorization-Signature-SHA256" - headerUpkeepId = "X-Authorization-Upkeep-Id" - mercuryPathV02 = "/client?" // only used to access mercury v0.2 server - mercuryBatchPathV03 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server - mercuryBatchPathV03BlockNumber = "/api/v1gmx/reports/bulk?" // only used to access mercury v0.3 server with blockNumber - retryDelay = 500 * time.Millisecond - timestamp = "timestamp" // valid for v0.3 - totalAttempt = 3 -) - -type StreamsLookup struct { - *encoding.StreamsLookupError - upkeepId *big.Int - block uint64 -} - -// MercuryV02Response represents a JSON structure used by Mercury v0.2 -type MercuryV02Response struct { - ChainlinkBlob string `json:"chainlinkBlob"` -} - -// MercuryV03Response represents a JSON structure used by Mercury v0.3 -type MercuryV03Response struct { - Reports []MercuryV03Report `json:"reports"` -} - -type MercuryV03Report struct { - FeedID string `json:"feedID"` // feed id in hex encoded - ValidFromTimestamp uint32 `json:"validFromTimestamp"` - ObservationsTimestamp uint32 `json:"observationsTimestamp"` - FullReport string `json:"fullReport"` // the actual hex encoded mercury report of this feed, can be sent to verifier -} - -type MercuryData struct { - Index int - Error error - Retryable bool - Bytes [][]byte - State encoding.PipelineExecutionState -} - -// UpkeepPrivilegeConfig represents the administrative offchain config for each upkeep. It can be set by s_upkeepPrivilegeManager -// role on the registry. Upkeeps allowed to use Mercury server will have this set to true. -type UpkeepPrivilegeConfig struct { - MercuryEnabled bool `json:"mercuryEnabled"` -} - -// streamsLookup looks through check upkeep results looking for any that need off chain lookup -func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keepers.CheckResult) []ocr2keepers.CheckResult { - lggr := r.lggr.With("where", "StreamsLookup") - lookups := map[int]*StreamsLookup{} - for i, res := range checkResults { - if res.IneligibilityReason != uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { - // Streams Lookup only works when upkeep target check reverts - continue - } - - block := big.NewInt(int64(res.Trigger.BlockNumber)) - upkeepId := res.UpkeepID - - // Try to decode the revert error into streams lookup format. User upkeeps can revert with any reason, see if they - // tried to call mercury - lggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) - streamsLookupErr, err := r.packer.DecodeStreamsLookupRequest(res.PerformData) - if err != nil { - lggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) - // user contract did not revert with StreamsLookup error - continue - } - l := &StreamsLookup{StreamsLookupError: streamsLookupErr} - if r.mercury.cred == nil { - lggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) - continue - } - - if len(l.Feeds) == 0 { - checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) - lggr.Debugf("at block %s upkeep %s has empty feeds array", block, upkeepId) - continue - } - // mercury permission checking for v0.3 is done by mercury server - if l.FeedParamKey == feedIdHex && l.TimeParamKey == blockNumber { - // check permission on the registry for mercury v0.2 - opts := r.buildCallOpts(ctx, block) - state, reason, retryable, allowed, err := r.allowedToUseMercury(opts, upkeepId.BigInt()) - if err != nil { - lggr.Warnf("at block %s upkeep %s failed to query mercury allow list: %s", block, upkeepId, err) - checkResults[i].PipelineExecutionState = uint8(state) - checkResults[i].IneligibilityReason = uint8(reason) - checkResults[i].Retryable = retryable - continue - } - - if !allowed { - lggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonMercuryAccessNotAllowed) - continue - } - } else if l.FeedParamKey != feedIDs { - // if mercury version cannot be determined, set failure reason - lggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) - continue - } - - l.upkeepId = upkeepId.BigInt() - // the block here is exclusively used to call checkCallback at this block, not to be confused with the block number - // in the revert for mercury v0.2, which is denoted by time in the struct bc starting from v0.3, only timestamp will be supported - l.block = uint64(block.Int64()) - lggr.Infof("at block %d upkeep %s DecodeStreamsLookupRequest feedKey=%s timeKey=%s feeds=%v time=%s extraData=%s", block, upkeepId, l.FeedParamKey, l.TimeParamKey, l.Feeds, l.Time, hexutil.Encode(l.ExtraData)) - lookups[i] = l - } - - var wg sync.WaitGroup - - for i, lookup := range lookups { - wg.Add(1) - func(i int, lookup *StreamsLookup) { - r.threadCtrl.Go(func(ctx context.Context) { - r.doLookup(ctx, &wg, lookup, i, checkResults, lggr) - }) - }(i, lookup) - - } - - wg.Wait() - - // don't surface error to plugin bc StreamsLookup process should be self-contained. - return checkResults -} - -func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *StreamsLookup, i int, checkResults []ocr2keepers.CheckResult, lggr logger.Logger) { - defer wg.Done() - - state, reason, values, retryable, ri, err := r.doMercuryRequest(ctx, lookup, generatePluginRetryKey(checkResults[i].WorkID, lookup.block), lggr) - if err != nil { - lggr.Errorf("upkeep %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.upkeepId, retryable, ri, err.Error()) - checkResults[i].Retryable = retryable - checkResults[i].RetryInterval = ri - checkResults[i].PipelineExecutionState = uint8(state) - checkResults[i].IneligibilityReason = uint8(reason) - return - } - - for j, v := range values { - lggr.Infof("upkeep %s doMercuryRequest values[%d]: %s", lookup.upkeepId, j, hexutil.Encode(v)) - } - - state, retryable, mercuryBytes, err := r.checkCallback(ctx, values, lookup) - if err != nil { - lggr.Errorf("at block %d upkeep %s checkCallback err: %s", lookup.block, lookup.upkeepId, err.Error()) - checkResults[i].Retryable = retryable - checkResults[i].PipelineExecutionState = uint8(state) - return - } - lggr.Infof("checkCallback mercuryBytes=%s", hexutil.Encode(mercuryBytes)) - - state, needed, performData, failureReason, _, err := r.packer.UnpackCheckCallbackResult(mercuryBytes) - if err != nil { - lggr.Errorf("at block %d upkeep %s UnpackCheckCallbackResult err: %s", lookup.block, lookup.upkeepId, err.Error()) - checkResults[i].PipelineExecutionState = uint8(state) - return - } - - if failureReason == uint8(encoding.UpkeepFailureReasonMercuryCallbackReverted) { - checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonMercuryCallbackReverted) - lggr.Debugf("at block %d upkeep %s mercury callback reverts", lookup.block, lookup.upkeepId) - return - } - - if !needed { - checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonUpkeepNotNeeded) - lggr.Debugf("at block %d upkeep %s callback reports upkeep not needed", lookup.block, lookup.upkeepId) - return - } - - checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonNone) - checkResults[i].Eligible = true - checkResults[i].PerformData = performData - lggr.Infof("at block %d upkeep %s successful with perform data: %s", lookup.block, lookup.upkeepId, hexutil.Encode(performData)) -} - -// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if -// this upkeep is allowed to use Mercury service. -func (r *EvmRegistry) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state encoding.PipelineExecutionState, reason encoding.UpkeepFailureReason, retryable bool, allow bool, err error) { - allowed, ok := r.mercury.allowListCache.Get(upkeepId.String()) - if ok { - return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, allowed.(bool), nil - } - - payload, err := r.packer.PackGetUpkeepPrivilegeConfig(upkeepId) - if err != nil { - // pack error, no retryable - r.lggr.Warnf("failed to pack getUpkeepPrivilegeConfig data for upkeepId %s: %s", upkeepId, err) - - return encoding.PackUnpackDecodeFailed, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to pack upkeepId: %w", err) - } - - var resultBytes hexutil.Bytes - args := map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - } - - // call checkCallback function at the block which OCR3 has agreed upon - err = r.client.CallContext(opts.Context, &resultBytes, "eth_call", args, hexutil.EncodeBig(opts.BlockNumber)) - if err != nil { - return encoding.RpcFlakyFailure, encoding.UpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) - } - - cfg, err := r.packer.UnpackGetUpkeepPrivilegeConfig(resultBytes) - if err != nil { - return encoding.PackUnpackDecodeFailed, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) - } - - if len(cfg) == 0 { - r.mercury.allowListCache.Set(upkeepId.String(), false, cache.DefaultExpiration) - return encoding.NoPipelineError, encoding.UpkeepFailureReasonMercuryAccessNotAllowed, false, false, fmt.Errorf("upkeep privilege config is empty") - } - - var privilegeConfig UpkeepPrivilegeConfig - if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { - return encoding.MercuryUnmarshalError, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to unmarshal privilege config: %v", err) - } - - r.mercury.allowListCache.Set(upkeepId.String(), privilegeConfig.MercuryEnabled, cache.DefaultExpiration) - - return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil -} - -func (r *EvmRegistry) checkCallback(ctx context.Context, values [][]byte, lookup *StreamsLookup) (encoding.PipelineExecutionState, bool, hexutil.Bytes, error) { - payload, err := r.abi.Pack("checkCallback", lookup.upkeepId, values, lookup.ExtraData) - if err != nil { - return encoding.PackUnpackDecodeFailed, false, nil, err - } - - var b hexutil.Bytes - args := map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - } - - // call checkCallback function at the block which OCR3 has agreed upon - err = r.client.CallContext(ctx, &b, "eth_call", args, hexutil.EncodeUint64(lookup.block)) - if err != nil { - return encoding.RpcFlakyFailure, true, nil, err - } - return encoding.NoPipelineError, false, b, nil -} - -// doMercuryRequest sends requests to Mercury API to retrieve mercury data. -func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, prk string, lggr logger.Logger) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, time.Duration, error) { - var isMercuryV03 bool - resultLen := len(sl.Feeds) - ch := make(chan MercuryData, resultLen) - if len(sl.Feeds) == 0 { - return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) - } - if sl.FeedParamKey == feedIdHex && sl.TimeParamKey == blockNumber { - // only mercury v0.2 - for i := range sl.Feeds { - i := i - r.threadCtrl.Go(func(ctx context.Context) { - r.singleFeedRequest(ctx, ch, i, sl, lggr) - }) - } - } else if sl.FeedParamKey == feedIDs { - // only mercury v0.3 - resultLen = 1 - isMercuryV03 = true - ch = make(chan MercuryData, resultLen) - r.threadCtrl.Go(func(ctx context.Context) { - r.multiFeedsRequest(ctx, ch, sl, lggr) - }) - } else { - return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) - } - - var reqErr error - var ri time.Duration - results := make([][]byte, len(sl.Feeds)) - retryable := true - allSuccess := true - // in v0.2, use the last execution error as the state, if no execution errors, state will be no error - state := encoding.NoPipelineError - for i := 0; i < resultLen; i++ { - m := <-ch - if m.Error != nil { - reqErr = errors.Join(reqErr, m.Error) - retryable = retryable && m.Retryable - allSuccess = false - if m.State != encoding.NoPipelineError { - state = m.State - } - continue - } - if isMercuryV03 { - results = m.Bytes - } else { - results[m.Index] = m.Bytes[0] - } - } - if retryable && !allSuccess { - ri = r.calculateRetryConfig(prk) - } - // only retry when not all successful AND none are not retryable - return state, encoding.UpkeepFailureReasonNone, results, retryable && !allSuccess, ri, reqErr -} - -// singleFeedRequest sends a v0.2 Mercury request for a single feed report. -func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryData, index int, sl *StreamsLookup, lggr logger.Logger) { - q := url.Values{ - sl.FeedParamKey: {sl.Feeds[index]}, - sl.TimeParamKey: {sl.Time.String()}, - } - mercuryURL := r.mercury.cred.LegacyURL - reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, mercuryPathV02, q.Encode()) - lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.upkeepId.String(), sl.Feeds[index], reqUrl) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) - if err != nil { - ch <- MercuryData{Index: index, Error: err, Retryable: false, State: encoding.InvalidMercuryRequest} - return - } - - ts := time.Now().UTC().UnixMilli() - signature := r.generateHMAC(http.MethodGet, mercuryPathV02+q.Encode(), []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) - req.Header.Set(headerContentType, applicationJson) - req.Header.Set(headerAuthorization, r.mercury.cred.Username) - req.Header.Set(headerTimestamp, strconv.FormatInt(ts, 10)) - req.Header.Set(headerSignature, signature) - - // in the case of multiple retries here, use the last attempt's data - state := encoding.NoPipelineError - retryable := false - sent := false - retryErr := retry.Do( - func() error { - retryable = false - resp, err1 := r.hc.Do(req) - if err1 != nil { - lggr.Warnf("at block %s upkeep %s GET request fails for feed %s: %v", sl.Time.String(), sl.upkeepId.String(), sl.Feeds[index], err1) - retryable = true - state = encoding.MercuryFlakyFailure - return err1 - } - defer func(Body io.ReadCloser) { - err = Body.Close() - if err != nil { - lggr.Warnf("failed to close mercury response Body: %s", err) - } - }(resp.Body) - - body, err1 := io.ReadAll(resp.Body) - if err1 != nil { - retryable = false - state = encoding.InvalidMercuryResponse - return err1 - } - - if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError || resp.StatusCode == http.StatusBadGateway || resp.StatusCode == http.StatusServiceUnavailable || resp.StatusCode == http.StatusGatewayTimeout { - lggr.Warnf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, sl.Feeds[index]) - retryable = true - state = encoding.MercuryFlakyFailure - return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) - } else if resp.StatusCode != http.StatusOK { - retryable = false - state = encoding.InvalidMercuryRequest - return fmt.Errorf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, sl.Feeds[index]) - } - - lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) - - var m MercuryV02Response - err1 = json.Unmarshal(body, &m) - if err1 != nil { - lggr.Warnf("at block %s upkeep %s failed to unmarshal body to MercuryV02Response for feed %s: %v", sl.Time.String(), sl.upkeepId.String(), sl.Feeds[index], err1) - retryable = false - state = encoding.MercuryUnmarshalError - return err1 - } - blobBytes, err1 := hexutil.Decode(m.ChainlinkBlob) - if err1 != nil { - lggr.Warnf("at block %s upkeep %s failed to decode chainlinkBlob %s for feed %s: %v", sl.Time.String(), sl.upkeepId.String(), m.ChainlinkBlob, sl.Feeds[index], err1) - retryable = false - state = encoding.InvalidMercuryResponse - return err1 - } - ch <- MercuryData{ - Index: index, - Bytes: [][]byte{blobBytes}, - Retryable: false, - State: encoding.NoPipelineError, - } - sent = true - return nil - }, - // only retry when the error is 404 Not Found, 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout - retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) || err.Error() == fmt.Sprintf("%d", http.StatusBadGateway) || err.Error() == fmt.Sprintf("%d", http.StatusServiceUnavailable) || err.Error() == fmt.Sprintf("%d", http.StatusGatewayTimeout) - }), - retry.Context(ctx), - retry.Delay(retryDelay), - retry.Attempts(totalAttempt)) - - if !sent { - md := MercuryData{ - Index: index, - Bytes: [][]byte{}, - Retryable: retryable, - Error: fmt.Errorf("failed to request feed for %s: %w", sl.Feeds[index], retryErr), - State: state, - } - ch <- md - } -} - -// multiFeedsRequest sends a Mercury v0.3 request for a multi-feed report -func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, sl *StreamsLookup, lggr logger.Logger) { - // this won't work bc q.Encode() will encode commas as '%2C' but the server is strictly expecting a comma separated list - //q := url.Values{ - // feedIDs: {strings.Join(sl.Feeds, ",")}, - // timestamp: {sl.Time.String()}, - //} - params := fmt.Sprintf("%s=%s&%s=%s", feedIDs, strings.Join(sl.Feeds, ","), sl.TimeParamKey, sl.Time.String()) - batchPathV03 := mercuryBatchPathV03 - if sl.TimeParamKey == blockNumber { - batchPathV03 = mercuryBatchPathV03BlockNumber - } - reqUrl := fmt.Sprintf("%s%s%s", r.mercury.cred.URL, batchPathV03, params) - lggr.Debugf("request URL for upkeep %s userId %s: %s", sl.upkeepId.String(), r.mercury.cred.Username, reqUrl) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) - if err != nil { - ch <- MercuryData{Index: 0, Error: err, Retryable: false, State: encoding.InvalidMercuryRequest} - return - } - - ts := time.Now().UTC().UnixMilli() - signature := r.generateHMAC(http.MethodGet, batchPathV03+params, []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) - req.Header.Set(headerContentType, applicationJson) - // username here is often referred to as user id - req.Header.Set(headerAuthorization, r.mercury.cred.Username) - req.Header.Set(headerTimestamp, strconv.FormatInt(ts, 10)) - req.Header.Set(headerSignature, signature) - // mercury will inspect authorization headers above to make sure this user (in automation's context, this node) is eligible to access mercury - // and if it has an automation role. it will then look at this upkeep id to check if it has access to all the requested feeds. - req.Header.Set(headerUpkeepId, sl.upkeepId.String()) - - // in the case of multiple retries here, use the last attempt's data - state := encoding.NoPipelineError - retryable := false - sent := false - retryErr := retry.Do( - func() error { - retryable = false - resp, err1 := r.hc.Do(req) - if err1 != nil { - lggr.Warnf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.Time.String(), sl.upkeepId.String(), err1) - retryable = true - state = encoding.MercuryFlakyFailure - return err1 - } - defer func(Body io.ReadCloser) { - err = Body.Close() - if err != nil { - lggr.Warnf("failed to close mercury response Body: %s", err) - } - }(resp.Body) - - body, err1 := io.ReadAll(resp.Body) - if err1 != nil { - retryable = false - state = encoding.InvalidMercuryResponse - return err1 - } - - lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) - if resp.StatusCode == http.StatusUnauthorized { - retryable = false - state = encoding.UpkeepNotAuthorized - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) - } else if resp.StatusCode == http.StatusBadRequest { - retryable = false - state = encoding.InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3 with message: %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, string(body)) - } else if resp.StatusCode == http.StatusInternalServerError || resp.StatusCode == http.StatusBadGateway || resp.StatusCode == http.StatusServiceUnavailable || resp.StatusCode == http.StatusGatewayTimeout { - retryable = true - state = encoding.MercuryFlakyFailure - return fmt.Errorf("%d", resp.StatusCode) - } else if resp.StatusCode == http.StatusPartialContent { - // TODO (AUTO-5044): handle response code 206 entirely with errors field parsing - lggr.Warnf("at timestamp %s upkeep %s requested [%s] feeds but mercury v0.3 server returned 206 status, treating it as 404 and retrying", sl.Time.String(), sl.upkeepId.String(), sl.Feeds) - retryable = true - state = encoding.MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusPartialContent) - } else if resp.StatusCode != http.StatusOK { - retryable = false - state = encoding.InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) - } - - lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.3 with BODY=%s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) - - var response MercuryV03Response - err1 = json.Unmarshal(body, &response) - if err1 != nil { - lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.Time.String(), sl.upkeepId.String(), err1) - retryable = false - state = encoding.MercuryUnmarshalError - return err1 - } - // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract - // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated - if len(response.Reports) != len(sl.Feeds) { - var receivedFeeds []string - for _, f := range response.Reports { - receivedFeeds = append(receivedFeeds, f.FeedID) - } - lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server returned 206 status with [%s] reports while we requested [%s] feeds, retrying", sl.Time.String(), sl.upkeepId.String(), receivedFeeds, sl.Feeds) - retryable = true - state = encoding.MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusNotFound) - } - var reportBytes [][]byte - for _, rsp := range response.Reports { - b, err := hexutil.Decode(rsp.FullReport) - if err != nil { - lggr.Warnf("at timestamp %s upkeep %s failed to decode reportBlob %s: %v", sl.Time.String(), sl.upkeepId.String(), rsp.FullReport, err) - retryable = false - state = encoding.InvalidMercuryResponse - return err - } - reportBytes = append(reportBytes, b) - } - ch <- MercuryData{ - Index: 0, - Bytes: reportBytes, - Retryable: false, - State: encoding.NoPipelineError, - } - sent = true - return nil - }, - // only retry when the error is 206 Partial Content, 404 Not Found, 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout - retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusPartialContent) || err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) || err.Error() == fmt.Sprintf("%d", http.StatusBadGateway) || err.Error() == fmt.Sprintf("%d", http.StatusServiceUnavailable) || err.Error() == fmt.Sprintf("%d", http.StatusGatewayTimeout) - }), - retry.Context(ctx), - retry.Delay(retryDelay), - retry.Attempts(totalAttempt)) - - if !sent { - md := MercuryData{ - Index: 0, - Bytes: [][]byte{}, - Retryable: retryable, - Error: retryErr, - State: state, - } - ch <- md - } -} - -// generateHMAC calculates a user HMAC for Mercury server authentication. -func (r *EvmRegistry) generateHMAC(method string, path string, body []byte, clientId string, secret string, ts int64) string { - bodyHash := sha256.New() - bodyHash.Write(body) - hashString := fmt.Sprintf("%s %s %s %s %d", - method, - path, - hex.EncodeToString(bodyHash.Sum(nil)), - clientId, - ts) - signedMessage := hmac.New(sha256.New, []byte(secret)) - signedMessage.Write([]byte(hashString)) - userHmac := hex.EncodeToString(signedMessage.Sum(nil)) - return userHmac -} - -// calculateRetryConfig returns plugin retry interval based on how many times plugin has retried this work -func (r *EvmRegistry) calculateRetryConfig(prk string) time.Duration { - var ri time.Duration - var retries int - totalAttempts, ok := r.mercury.pluginRetryCache.Get(prk) - if ok { - retries = totalAttempts.(int) - if retries < totalFastPluginRetries { - ri = 1 * time.Second - } else if retries < totalMediumPluginRetries { - ri = 5 * time.Second - } - // if the core node has retried totalMediumPluginRetries times, do not set retry interval and plugin will use - // the default interval - } else { - ri = 1 * time.Second - } - r.mercury.pluginRetryCache.Set(prk, retries+1, cache.DefaultExpiration) - return ri -} - -// generatePluginRetryKey returns a plugin retry cache key -func generatePluginRetryKey(workID string, block uint64) string { - return workID + "|" + fmt.Sprintf("%d", block) -} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go deleted file mode 100644 index 145d701454..0000000000 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go +++ /dev/null @@ -1,1354 +0,0 @@ -package evm - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "math/big" - "net/http" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/patrickmn/go-cache" - "github.com/pkg/errors" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" -) - -// setups up an evm registry for tests. -func setupEVMRegistry(t *testing.T) *EvmRegistry { - lggr := logger.TestLogger(t) - addr := common.HexToAddress("0x6cA639822c6C241Fa9A7A6b5032F6F7F1C513CAD") - keeperRegistryABI, err := abi.JSON(strings.NewReader(i_keeper_registry_master_wrapper_2_1.IKeeperRegistryMasterABI)) - require.Nil(t, err, "need registry abi") - streamsLookupCompatibleABI, err := abi.JSON(strings.NewReader(streams_lookup_compatible_interface.StreamsLookupCompatibleInterfaceABI)) - require.Nil(t, err, "need mercury abi") - var logPoller logpoller.LogPoller - mockReg := mocks.NewRegistry(t) - mockHttpClient := mocks.NewHttpClient(t) - client := evmClientMocks.NewClient(t) - - r := &EvmRegistry{ - lggr: lggr, - poller: logPoller, - addr: addr, - client: client, - logProcessed: make(map[string]bool), - registry: mockReg, - abi: keeperRegistryABI, - active: NewActiveUpkeepList(), - packer: encoding.NewAbiPacker(), - headFunc: func(ocr2keepers.BlockKey) {}, - chLog: make(chan logpoller.Log, 1000), - mercury: &MercuryConfig{ - cred: &models.MercuryCredentials{ - LegacyURL: "https://google.old.com", - URL: "https://google.com", - Username: "FakeClientID", - Password: "FakeClientKey", - }, - abi: streamsLookupCompatibleABI, - allowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), - pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), - }, - hc: mockHttpClient, - threadCtrl: utils.NewThreadControl(), - } - return r -} - -func TestEvmRegistry_StreamsLookup(t *testing.T) { - upkeepId, ok := new(big.Int).SetString("71022726777042968814359024671382968091267501884371696415772139504780367423725", 10) - var upkeepIdentifier [32]byte - copy(upkeepIdentifier[:], upkeepId.Bytes()) - assert.True(t, ok, t.Name()) - blockNum := ocr2keepers.BlockNumber(37974374) - tests := []struct { - name string - input []ocr2keepers.CheckResult - blobs map[string]string - callbackResp []byte - expectedResults []ocr2keepers.CheckResult - callbackNeeded bool - extraData []byte - checkCallbackResp []byte - values [][]byte - cachedAdminCfg bool - hasError bool - hasPermission bool - v3 bool - }{ - { - name: "success - happy path no cache", - input: []ocr2keepers.CheckResult{ - { - PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: blockNum, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), - }, - }, - blobs: map[string]string{ - "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000": "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3", - "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000": "0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d", - }, - cachedAdminCfg: false, - extraData: hexutil.MustDecode("0x0000000000000000000000000000000000000064"), - callbackNeeded: true, - checkCallbackResp: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063a400000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - values: [][]byte{hexutil.MustDecode("0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3"), hexutil.MustDecode("0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d")}, - expectedResults: []ocr2keepers.CheckResult{ - { - Eligible: true, - PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: blockNum, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonNone), - }, - }, - hasPermission: true, - }, - { - name: "success - happy path no cache - v0.3", - input: []ocr2keepers.CheckResult{ - { - PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000766656564494473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: blockNum, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), - }, - }, - blobs: map[string]string{ - "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000": "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3", - "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000": "0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d", - }, - cachedAdminCfg: false, - extraData: hexutil.MustDecode("0x0000000000000000000000000000000000000064"), - callbackNeeded: true, - checkCallbackResp: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063a400000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - values: [][]byte{hexutil.MustDecode("0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3"), hexutil.MustDecode("0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d")}, - expectedResults: []ocr2keepers.CheckResult{ - { - Eligible: true, - PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: blockNum, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonNone), - }, - }, - hasPermission: true, - v3: true, - }, - { - name: "skip - failure reason is insufficient balance", - input: []ocr2keepers.CheckResult{ - { - PerformData: []byte{}, - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: 26046145, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), - }, - }, - expectedResults: []ocr2keepers.CheckResult{ - { - Eligible: false, - PerformData: []byte{}, - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: 26046145, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), - }, - }, - hasError: true, - }, - { - name: "skip - invalid revert data", - input: []ocr2keepers.CheckResult{ - { - PerformData: []byte{}, - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: 26046145, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), - }, - }, - expectedResults: []ocr2keepers.CheckResult{ - { - Eligible: false, - PerformData: []byte{}, - UpkeepID: upkeepIdentifier, - Trigger: ocr2keepers.Trigger{ - BlockNumber: 26046145, - }, - IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), - }, - }, - hasError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := setupEVMRegistry(t) - defer r.Close() - client := new(evmClientMocks.Client) - r.client = client - - if !tt.cachedAdminCfg && !tt.hasError { - cfg := UpkeepPrivilegeConfig{MercuryEnabled: tt.hasPermission} - bCfg, err := json.Marshal(cfg) - require.Nil(t, err) - - bContractCfg, err := r.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{bCfg}) - require.Nil(t, err) - - payload, err := r.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) - require.Nil(t, err) - - args := map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - } - - client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("string")).Return(nil). - Run(func(args mock.Arguments) { - b := args.Get(1).(*hexutil.Bytes) - *b = bContractCfg - }).Once() - } - - if len(tt.blobs) > 0 { - if tt.v3 { - hc := mocks.NewHttpClient(t) - mr1 := MercuryV03Response{ - Reports: []MercuryV03Report{{FullReport: tt.blobs["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]}, {FullReport: tt.blobs["0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"]}}} - b1, err := json.Marshal(mr1) - assert.Nil(t, err) - resp1 := &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(b1)), - } - hc.On("Do", mock.Anything).Return(resp1, nil).Once() - r.hc = hc - } else { - hc := mocks.NewHttpClient(t) - mr1 := MercuryV02Response{ChainlinkBlob: tt.blobs["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]} - b1, err := json.Marshal(mr1) - assert.Nil(t, err) - resp1 := &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(b1)), - } - mr2 := MercuryV02Response{ChainlinkBlob: tt.blobs["0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"]} - b2, err := json.Marshal(mr2) - assert.Nil(t, err) - resp2 := &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(b2)), - } - hc.On("Do", mock.MatchedBy(func(req *http.Request) bool { - return strings.Contains(req.URL.String(), "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000") - })).Return(resp2, nil).Once() - - hc.On("Do", mock.MatchedBy(func(req *http.Request) bool { - return strings.Contains(req.URL.String(), "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000") - })).Return(resp1, nil).Once() - r.hc = hc - } - } - - if tt.callbackNeeded { - payload, err := r.abi.Pack("checkCallback", upkeepId, tt.values, tt.extraData) - require.Nil(t, err) - args := map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - } - client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, hexutil.EncodeUint64(uint64(blockNum))).Return(nil). - Run(func(args mock.Arguments) { - b := args.Get(1).(*hexutil.Bytes) - *b = tt.checkCallbackResp - }).Once() - } - - got := r.streamsLookup(context.Background(), tt.input) - assert.Equal(t, tt.expectedResults, got, tt.name) - }) - } -} - -func TestEvmRegistry_AllowedToUseMercury(t *testing.T) { - upkeepId, ok := new(big.Int).SetString("71022726777042968814359024671382968091267501884371696415772139504780367423725", 10) - assert.True(t, ok, t.Name()) - tests := []struct { - name string - cached bool - allowed bool - ethCallErr error - err error - state encoding.PipelineExecutionState - reason encoding.UpkeepFailureReason - retryable bool - config []byte - }{ - { - name: "success - allowed via cache", - cached: true, - allowed: true, - }, - { - name: "success - allowed via fetching privilege config", - allowed: true, - }, - { - name: "success - not allowed via cache", - cached: true, - allowed: false, - }, - { - name: "success - not allowed via fetching privilege config", - allowed: false, - }, - { - name: "failure - cannot unmarshal privilege config", - err: fmt.Errorf("failed to unmarshal privilege config: invalid character '\\x00' looking for beginning of value"), - state: encoding.MercuryUnmarshalError, - config: []byte{0, 1}, - }, - { - name: "failure - flaky RPC", - retryable: true, - err: fmt.Errorf("failed to get upkeep privilege config: flaky RPC"), - state: encoding.RpcFlakyFailure, - ethCallErr: fmt.Errorf("flaky RPC"), - }, - { - name: "failure - empty upkeep privilege config", - err: fmt.Errorf("upkeep privilege config is empty"), - reason: encoding.UpkeepFailureReasonMercuryAccessNotAllowed, - config: []byte{}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := setupEVMRegistry(t) - defer r.Close() - - client := new(evmClientMocks.Client) - r.client = client - - if tt.cached { - r.mercury.allowListCache.Set(upkeepId.String(), tt.allowed, cache.DefaultExpiration) - } else { - if tt.err != nil { - bContractCfg, err := r.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{tt.config}) - require.Nil(t, err) - - payload, err := r.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) - require.Nil(t, err) - - args := map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - } - - client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("string")). - Return(tt.ethCallErr). - Run(func(args mock.Arguments) { - b := args.Get(1).(*hexutil.Bytes) - *b = bContractCfg - }).Once() - } else { - cfg := UpkeepPrivilegeConfig{MercuryEnabled: tt.allowed} - bCfg, err := json.Marshal(cfg) - require.Nil(t, err) - - bContractCfg, err := r.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{bCfg}) - require.Nil(t, err) - - payload, err := r.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) - require.Nil(t, err) - - args := map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - } - - client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("string")).Return(nil). - Run(func(args mock.Arguments) { - b := args.Get(1).(*hexutil.Bytes) - *b = bContractCfg - }).Once() - } - } - - opts := &bind.CallOpts{ - BlockNumber: big.NewInt(10), - } - - state, reason, retryable, allowed, err := r.allowedToUseMercury(opts, upkeepId) - assert.Equal(t, tt.err, err) - assert.Equal(t, tt.allowed, allowed) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.reason, reason) - assert.Equal(t, tt.retryable, retryable) - }) - } -} - -func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { - upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) - - tests := []struct { - name string - lookup *StreamsLookup - mockHttpStatusCode int - mockChainlinkBlobs []string - pluginRetries int - pluginRetryKey string - expectedValues [][]byte - expectedRetryable bool - expectedRetryInterval time.Duration - expectedError error - state encoding.PipelineExecutionState - reason encoding.UpkeepFailureReason - }{ - { - name: "success", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - mockHttpStatusCode: http.StatusOK, - mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{{0, 6, 109, 252, 209, 237, 45, 149, 177, 140, 148, 141, 188, 91, 214, 76, 104, 122, 254, 147, 228, 202, 125, 102, 61, 222, 193, 76, 32, 9, 10, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 69, 84, 72, 45, 85, 83, 68, 45, 65, 82, 66, 73, 84, 82, 85, 77, 45, 84, 69, 83, 84, 78, 69, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 216, 211, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 207, 11, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 155, 61, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 206, 116, 217, 250, 37, 42, 137, 131, 151, 110, 171, 96, 13, 199, 89, 12, 119, 141, 4, 129, 52, 48, 132, 27, 198, 231, 101, 195, 76, 216, 26, 22, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 96, 65, 43, 148, 229, 37, 202, 108, 237, 201, 245, 68, 253, 134, 247, 118, 6, 213, 47, 231, 49, 165, 208, 105, 219, 232, 54, 168, 191, 192, 251, 140, 145, 25, 99, 176, 174, 122, 20, 151, 31, 59, 70, 33, 191, 251, 128, 46, 240, 96, 83, 146, 185, 166, 200, 156, 127, 171, 29, 248, 99, 58, 90, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 69, 0, 194, 245, 33, 248, 63, 186, 94, 252, 43, 243, 239, 250, 174, 221, 228, 61, 10, 74, 223, 247, 133, 193, 33, 59, 113, 42, 58, 237, 13, 129, 87, 100, 42, 132, 50, 77, 176, 207, 150, 149, 235, 210, 119, 8, 212, 96, 142, 176, 51, 126, 13, 216, 123, 14, 67, 240, 250, 112, 199, 0, 217, 17}}, - expectedRetryable: false, - expectedError: nil, - }, - { - name: "failure - retryable and interval is 1s", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - mockHttpStatusCode: http.StatusInternalServerError, - mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{nil}, - expectedRetryable: true, - pluginRetries: 0, - expectedRetryInterval: 1 * time.Second, - expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: encoding.MercuryFlakyFailure, - }, - { - name: "failure - retryable and interval is 5s", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - pluginRetries: 5, - mockHttpStatusCode: http.StatusInternalServerError, - mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{nil}, - expectedRetryable: true, - expectedRetryInterval: 5 * time.Second, - expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: encoding.MercuryFlakyFailure, - }, - { - name: "failure - not retryable because there are many plugin retries already", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - pluginRetries: 10, - mockHttpStatusCode: http.StatusInternalServerError, - mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{nil}, - expectedRetryable: true, - expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: encoding.MercuryFlakyFailure, - }, - { - name: "failure - not retryable", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - mockHttpStatusCode: http.StatusTooManyRequests, - mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{nil}, - expectedRetryable: false, - expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 25880526 upkeep 88786950015966611018675766524283132478093844178961698330929478019253453382042 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), - state: encoding.InvalidMercuryRequest, - }, - { - name: "failure - no feeds", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - expectedValues: [][]byte{}, - reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, - }, - { - name: "failure - invalid revert data", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - expectedValues: [][]byte{}, - reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := setupEVMRegistry(t) - defer r.Close() - - if tt.pluginRetries != 0 { - r.mercury.pluginRetryCache.Set(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) - } - - hc := mocks.NewHttpClient(t) - - for _, blob := range tt.mockChainlinkBlobs { - mr := MercuryV02Response{ChainlinkBlob: blob} - b, err := json.Marshal(mr) - assert.Nil(t, err) - - resp := &http.Response{ - StatusCode: tt.mockHttpStatusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - if tt.expectedError != nil && tt.expectedRetryable || tt.pluginRetries > 0 { - hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) - } else { - hc.On("Do", mock.Anything).Return(resp, nil).Once() - } - } - r.hc = hc - - state, reason, values, retryable, ri, reqErr := r.doMercuryRequest(context.Background(), tt.lookup, tt.pluginRetryKey, r.lggr) - assert.Equal(t, tt.expectedValues, values) - assert.Equal(t, tt.expectedRetryable, retryable) - if retryable { - newRetries, _ := r.mercury.pluginRetryCache.Get(tt.pluginRetryKey) - assert.Equal(t, tt.pluginRetries+1, newRetries.(int)) - } - assert.Equal(t, tt.expectedRetryInterval, ri) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.reason, reason) - if tt.expectedError != nil { - assert.True(t, strings.HasPrefix(reqErr.Error(), "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000")) - } - }) - } -} - -func TestEvmRegistry_DoMercuryRequestV03(t *testing.T) { - upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) - - tests := []struct { - name string - lookup *StreamsLookup - mockHttpStatusCode int - mockChainlinkBlobs []string - pluginRetryKey string - expectedValues [][]byte - expectedRetryable bool - expectedRetryInterval time.Duration - expectedError error - state encoding.PipelineExecutionState - reason encoding.UpkeepFailureReason - }{ - { - name: "success v0.3", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(25880526), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - }, - mockHttpStatusCode: http.StatusOK, - mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{{0, 6, 109, 252, 209, 237, 45, 149, 177, 140, 148, 141, 188, 91, 214, 76, 104, 122, 254, 147, 228, 202, 125, 102, 61, 222, 193, 76, 32, 9, 10, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 69, 84, 72, 45, 85, 83, 68, 45, 65, 82, 66, 73, 84, 82, 85, 77, 45, 84, 69, 83, 84, 78, 69, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 216, 211, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 207, 11, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 155, 61, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 206, 116, 217, 250, 37, 42, 137, 131, 151, 110, 171, 96, 13, 199, 89, 12, 119, 141, 4, 129, 52, 48, 132, 27, 198, 231, 101, 195, 76, 216, 26, 22, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 96, 65, 43, 148, 229, 37, 202, 108, 237, 201, 245, 68, 253, 134, 247, 118, 6, 213, 47, 231, 49, 165, 208, 105, 219, 232, 54, 168, 191, 192, 251, 140, 145, 25, 99, 176, 174, 122, 20, 151, 31, 59, 70, 33, 191, 251, 128, 46, 240, 96, 83, 146, 185, 166, 200, 156, 127, 171, 29, 248, 99, 58, 90, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 69, 0, 194, 245, 33, 248, 63, 186, 94, 252, 43, 243, 239, 250, 174, 221, 228, 61, 10, 74, 223, 247, 133, 193, 33, 59, 113, 42, 58, 237, 13, 129, 87, 100, 42, 132, 50, 77, 176, 207, 150, 149, 235, 210, 119, 8, 212, 96, 142, 176, 51, 126, 13, 216, 123, 14, 67, 240, 250, 112, 199, 0, 217, 17}}, - expectedRetryable: false, - expectedError: nil, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := setupEVMRegistry(t) - hc := mocks.NewHttpClient(t) - - mr := MercuryV03Response{} - for i, blob := range tt.mockChainlinkBlobs { - r := MercuryV03Report{ - FeedID: tt.lookup.Feeds[i], - ValidFromTimestamp: 0, - ObservationsTimestamp: 0, - FullReport: blob, - } - mr.Reports = append(mr.Reports, r) - } - - b, err := json.Marshal(mr) - assert.Nil(t, err) - resp := &http.Response{ - StatusCode: tt.mockHttpStatusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - if tt.expectedError != nil && tt.expectedRetryable { - hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) - } else { - hc.On("Do", mock.Anything).Return(resp, nil).Once() - } - r.hc = hc - - state, reason, values, retryable, ri, reqErr := r.doMercuryRequest(context.Background(), tt.lookup, tt.pluginRetryKey, r.lggr) - assert.Equal(t, tt.expectedValues, values) - assert.Equal(t, tt.expectedRetryable, retryable) - assert.Equal(t, tt.expectedRetryInterval, ri) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.reason, reason) - if tt.expectedError != nil { - assert.Equal(t, tt.expectedError.Error(), reqErr.Error()) - } - }) - } -} - -func TestEvmRegistry_SingleFeedRequest(t *testing.T) { - upkeepId := big.NewInt(123456789) - tests := []struct { - name string - index int - lookup *StreamsLookup - pluginRetryKey string - blob string - statusCode int - lastStatusCode int - retryNumber int - retryable bool - errorMessage string - }{ - { - name: "success - mercury responds in the first try", - index: 0, - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - blob: "0xab2123dc00000012", - }, - { - name: "success - retry for 404", - index: 0, - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - blob: "0xab2123dcbabbad", - retryNumber: 1, - statusCode: http.StatusNotFound, - lastStatusCode: http.StatusOK, - }, - { - name: "success - retry for 500", - index: 0, - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - blob: "0xab2123dcbbabad", - retryNumber: 2, - statusCode: http.StatusInternalServerError, - lastStatusCode: http.StatusOK, - }, - { - name: "failure - returns retryable", - index: 0, - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - blob: "0xab2123dc", - retryNumber: totalAttempt, - statusCode: http.StatusNotFound, - retryable: true, - errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: 404\n#3: 404", - }, - { - name: "failure - returns retryable and then non-retryable", - index: 0, - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - blob: "0xab2123dc", - retryNumber: 1, - statusCode: http.StatusNotFound, - lastStatusCode: http.StatusTooManyRequests, - errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: at block 123456 upkeep 123456789 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - }, - { - name: "failure - returns not retryable", - index: 0, - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - blob: "0xab2123dc", - statusCode: http.StatusConflict, - errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 409 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := setupEVMRegistry(t) - defer r.Close() - - hc := mocks.NewHttpClient(t) - - mr := MercuryV02Response{ChainlinkBlob: tt.blob} - b, err := json.Marshal(mr) - assert.Nil(t, err) - - if tt.retryNumber == 0 { - if tt.errorMessage != "" { - resp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(resp, nil).Once() - } else { - resp := &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(resp, nil).Once() - } - } else if tt.retryNumber > 0 && tt.retryNumber < totalAttempt { - retryResp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) - - resp := &http.Response{ - StatusCode: tt.lastStatusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(resp, nil).Once() - } else { - resp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(resp, nil).Times(tt.retryNumber) - } - r.hc = hc - - ch := make(chan MercuryData, 1) - r.singleFeedRequest(context.Background(), ch, tt.index, tt.lookup, r.lggr) - - m := <-ch - assert.Equal(t, tt.index, m.Index) - assert.Equal(t, tt.retryable, m.Retryable) - if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { - assert.Equal(t, tt.errorMessage, m.Error.Error()) - assert.Equal(t, [][]byte{}, m.Bytes) - } else { - blobBytes, err := hexutil.Decode(tt.blob) - assert.Nil(t, err) - assert.Nil(t, m.Error) - assert.Equal(t, [][]byte{blobBytes}, m.Bytes) - } - }) - } -} - -func TestEvmRegistry_MultiFeedRequest(t *testing.T) { - upkeepId := big.NewInt(123456789) - tests := []struct { - name string - lookup *StreamsLookup - statusCode int - lastStatusCode int - pluginRetries int - pluginRetryKey string - retryNumber int - retryable bool - errorMessage string - firstResponse *MercuryV03Response - response *MercuryV03Response - }{ - { - name: "success - mercury responds in the first try", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - response: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "0xab2123dc00000012", - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123458, - ObservationsTimestamp: 123458, - FullReport: "0xab2123dc00000016", - }, - }, - }, - statusCode: http.StatusOK, - }, - { - name: "success - mercury responds in the first try with blocknumber", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - response: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "0xab2123dc00000012", - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123458, - ObservationsTimestamp: 123458, - FullReport: "0xab2123dc00000016", - }, - }, - }, - statusCode: http.StatusOK, - }, - { - name: "success - retry 206", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - firstResponse: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "0xab2123dc00000012", - }, - }, - }, - response: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "0xab2123dc00000012", - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123458, - ObservationsTimestamp: 123458, - FullReport: "0xab2123dc00000019", - }, - }, - }, - retryNumber: 1, - statusCode: http.StatusPartialContent, - lastStatusCode: http.StatusOK, - }, - { - name: "success - retry for 500", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - retryNumber: 2, - statusCode: http.StatusInternalServerError, - lastStatusCode: http.StatusOK, - response: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "0xab2123dc00000012", - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123458, - ObservationsTimestamp: 123458, - FullReport: "0xab2123dc00000019", - }, - }, - }, - }, - { - name: "failure - fail to decode reportBlob", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - response: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "qerwiu", // invalid hex blob - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123458, - ObservationsTimestamp: 123458, - FullReport: "0xab2123dc00000016", - }, - }, - }, - statusCode: http.StatusOK, - retryable: false, - errorMessage: "All attempts fail:\n#1: hex string without 0x prefix", - }, - { - name: "failure - returns retryable with 1s plugin retry interval", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - retryNumber: totalAttempt, - statusCode: http.StatusInternalServerError, - retryable: true, - errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", - }, - { - name: "failure - returns retryable with 5s plugin retry interval", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - pluginRetries: 6, - retryNumber: totalAttempt, - statusCode: http.StatusInternalServerError, - retryable: true, - errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", - }, - { - name: "failure - returns retryable and then non-retryable", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - retryNumber: 1, - statusCode: http.StatusInternalServerError, - lastStatusCode: http.StatusUnauthorized, - errorMessage: "All attempts fail:\n#1: 500\n#2: at timestamp 123456 upkeep 123456789 received status code 401 from mercury v0.3, most likely this is caused by unauthorized upkeep", - }, - { - name: "failure - returns status code 422 not retryable", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - statusCode: http.StatusUnprocessableEntity, - errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 422 from mercury v0.3", - }, - { - name: "success - retry when reports length does not match feeds length", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIDs, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: timestamp, - Time: big.NewInt(123456), - }, - upkeepId: upkeepId, - }, - firstResponse: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "0xab2123dc00000012", - }, - }, - }, - response: &MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123456, - ObservationsTimestamp: 123456, - FullReport: "0xab2123dc00000012", - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: 123458, - ObservationsTimestamp: 123458, - FullReport: "0xab2123dc00000019", - }, - }, - }, - retryNumber: 1, - statusCode: http.StatusOK, - lastStatusCode: http.StatusOK, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := setupEVMRegistry(t) - defer r.Close() - - if tt.pluginRetries != 0 { - r.mercury.pluginRetryCache.Set(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) - } - - hc := mocks.NewHttpClient(t) - b, err := json.Marshal(tt.response) - assert.Nil(t, err) - - if tt.retryNumber == 0 { - resp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(resp, nil).Once() - } else if tt.retryNumber < totalAttempt { - if tt.firstResponse != nil && tt.response != nil { - b0, err := json.Marshal(tt.firstResponse) - assert.Nil(t, err) - resp0 := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b0)), - } - b1, err := json.Marshal(tt.response) - assert.Nil(t, err) - resp1 := &http.Response{ - StatusCode: tt.lastStatusCode, - Body: io.NopCloser(bytes.NewReader(b1)), - } - hc.On("Do", mock.Anything).Return(resp0, nil).Once().On("Do", mock.Anything).Return(resp1, nil).Once() - } else { - retryResp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) - - resp := &http.Response{ - StatusCode: tt.lastStatusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(resp, nil).Once() - } - } else { - resp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(resp, nil).Times(tt.retryNumber) - } - r.hc = hc - - ch := make(chan MercuryData, 1) - r.multiFeedsRequest(context.Background(), ch, tt.lookup, r.lggr) - - m := <-ch - assert.Equal(t, 0, m.Index) - assert.Equal(t, tt.retryable, m.Retryable) - if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { - assert.Equal(t, tt.errorMessage, m.Error.Error()) - assert.Equal(t, [][]byte{}, m.Bytes) - } else { - assert.Nil(t, m.Error) - var reports [][]byte - for _, rsp := range tt.response.Reports { - b, _ := hexutil.Decode(rsp.FullReport) - reports = append(reports, b) - } - assert.Equal(t, reports, m.Bytes) - } - }) - } -} - -func TestEvmRegistry_CheckCallback(t *testing.T) { - upkeepId := big.NewInt(123456789) - bn := uint64(999) - bs := []byte{183, 114, 215, 10, 0, 0, 0, 0, 0, 0} - values := [][]byte{bs} - tests := []struct { - name string - lookup *StreamsLookup - values [][]byte - statusCode int - - callbackResp []byte - callbackErr error - - upkeepNeeded bool - performData []byte - wantErr assert.ErrorAssertionFunc - - state encoding.PipelineExecutionState - retryable bool - }{ - { - name: "success - empty extra data", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"ETD-USD", "BTC-ETH"}, - TimeParamKey: blockNumber, - Time: big.NewInt(100), - ExtraData: []byte{48, 120, 48, 48}, - }, - upkeepId: upkeepId, - block: bn, - }, - values: values, - statusCode: http.StatusOK, - callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - upkeepNeeded: true, - performData: []byte{48, 120, 48, 48}, - wantErr: assert.NoError, - }, - { - name: "success - with extra data", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: blockNumber, - Time: big.NewInt(18952430), - // this is the address of precompile contract ArbSys(0x0000000000000000000000000000000000000064) - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - upkeepId: upkeepId, - block: bn, - }, - values: values, - statusCode: http.StatusOK, - callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - upkeepNeeded: true, - performData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - wantErr: assert.NoError, - }, - { - name: "failure - bad response", - lookup: &StreamsLookup{ - StreamsLookupError: &encoding.StreamsLookupError{ - FeedParamKey: feedIdHex, - Feeds: []string{"ETD-USD", "BTC-ETH"}, - TimeParamKey: blockNumber, - Time: big.NewInt(100), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - upkeepId: upkeepId, - block: bn, - }, - values: values, - statusCode: http.StatusOK, - callbackResp: []byte{}, - callbackErr: errors.New("bad response"), - wantErr: assert.Error, - state: encoding.RpcFlakyFailure, - retryable: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - client := new(evmClientMocks.Client) - r := setupEVMRegistry(t) - defer r.Close() - - payload, err := r.abi.Pack("checkCallback", tt.lookup.upkeepId, values, tt.lookup.ExtraData) - require.Nil(t, err) - args := map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - } - client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, hexutil.EncodeUint64(tt.lookup.block)).Return(tt.callbackErr). - Run(func(args mock.Arguments) { - by := args.Get(1).(*hexutil.Bytes) - *by = tt.callbackResp - }).Once() - r.client = client - - state, retryable, _, err := r.checkCallback(context.Background(), tt.values, tt.lookup) - tt.wantErr(t, err, fmt.Sprintf("Error asserion failed: %v", tt.name)) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.retryable, retryable) - }) - } -} diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index ee8b7cd6e9..f4fbf24f41 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -26,6 +26,8 @@ import ( "github.com/stretchr/testify/require" "github.com/umbracle/ethgo/abi" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" @@ -33,7 +35,9 @@ import ( "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" automationForwarderLogic "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_forwarder_logic" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" @@ -52,7 +56,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -884,7 +887,7 @@ func (c *feedLookupUpkeepController) EnableMercury( registry *iregistry21.IKeeperRegistryMaster, registryOwner *bind.TransactOpts, ) error { - adminBytes, _ := json.Marshal(evm21.UpkeepPrivilegeConfig{ + adminBytes, _ := json.Marshal(streams.UpkeepPrivilegeConfig{ MercuryEnabled: true, }) @@ -908,7 +911,7 @@ func (c *feedLookupUpkeepController) EnableMercury( return err } - var checkBytes evm21.UpkeepPrivilegeConfig + var checkBytes streams.UpkeepPrivilegeConfig if err := json.Unmarshal(bts, &checkBytes); err != nil { require.NoError(t, err) diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 1a093a8815..87074e786d 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -10,12 +10,16 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" + + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" @@ -23,8 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/store/models" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" - "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -152,7 +154,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { if isMercury { // Set privilege config to enable mercury - privilegeConfigBytes, _ := json.Marshal(evm21.UpkeepPrivilegeConfig{ + privilegeConfigBytes, _ := json.Marshal(streams.UpkeepPrivilegeConfig{ MercuryEnabled: true, }) if err := registry.SetUpkeepPrivilegeConfig(upkeepIDs[i], privilegeConfigBytes); err != nil { From 96498b692963bbea6b9b1d1e7d5bcaf6f0786542 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Thu, 16 Nov 2023 15:10:14 -0500 Subject: [PATCH 165/327] [TT-695] Deprecate P2Pv1 in Tests (#11305) * Deprecating P2Pv1 in Tests * P2Pv2 Swap * Lint * Stupid typose --- integration-tests/actions/ocr_helpers_local.go | 8 ++++---- integration-tests/client/chainlink.go | 5 ++++- integration-tests/client/chainlink_models.go | 14 +++++--------- .../docker/test_env/test_env_builder.go | 5 +++-- integration-tests/smoke/keeper_test.go | 2 +- integration-tests/smoke/ocr_test.go | 7 ++++--- integration-tests/types/config/node/core.go | 2 ++ integration-tests/universal/log_poller/helpers.go | 3 --- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index e6dd5ae77f..fb0fd0bd47 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -146,7 +146,7 @@ func CreateOCRJobsLocal( workerNodes []*client.ChainlinkClient, mockValue int, mockAdapter *test_env.Killgrave, - evmChainID string, + evmChainID *big.Int, ) error { for _, ocrInstance := range ocrInstances { bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() @@ -157,7 +157,7 @@ func CreateOCRJobsLocal( bootstrapSpec := &client.OCRBootstrapJobSpec{ Name: fmt.Sprintf("bootstrap-%s", uuid.New().String()), ContractAddress: ocrInstance.Address(), - EVMChainID: evmChainID, + EVMChainID: evmChainID.String(), P2PPeerID: bootstrapP2PId, IsBootstrapPeer: true, } @@ -202,7 +202,7 @@ func CreateOCRJobsLocal( bootstrapPeers := []*client.ChainlinkClient{bootstrapNode} ocrSpec := &client.OCRTaskJobSpec{ ContractAddress: ocrInstance.Address(), - EVMChainID: evmChainID, + EVMChainID: evmChainID.String(), P2PPeerID: nodeP2PId, P2PBootstrapPeers: bootstrapPeers, KeyBundleID: nodeOCRKeyId, @@ -211,7 +211,7 @@ func CreateOCRJobsLocal( } _, err = node.MustCreateJob(ocrSpec) if err != nil { - return fmt.Errorf("creating OCR task job on OCR node have failed: %w", err) + return fmt.Errorf("creating OCR job on OCR node failed: %w", err) } } } diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 4603679ff8..16299a1ac8 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -116,7 +116,7 @@ func (c *ChainlinkClient) MustCreateJob(spec JobSpec) (*Job, error) { if err != nil { return nil, err } - return job, VerifyStatusCode(resp.RawResponse.StatusCode, http.StatusOK) + return job, VerifyStatusCodeWithResponse(resp, http.StatusOK) } // CreateJob creates a Chainlink job based on the provided spec struct @@ -1114,6 +1114,7 @@ func (c *ChainlinkClient) SetPageSize(size int) { c.pageSize = size } +// VerifyStatusCode verifies the status code of the response. Favor VerifyStatusCodeWithResponse over this for better errors func VerifyStatusCode(actStatusCd, expStatusCd int) error { if actStatusCd != expStatusCd { return fmt.Errorf( @@ -1125,6 +1126,8 @@ func VerifyStatusCode(actStatusCd, expStatusCd int) error { return nil } +// VerifyStatusCodeWithResponse verifies the status code of the response and returns the response as part of the error. +// Favor this over VerifyStatusCode func VerifyStatusCodeWithResponse(res *resty.Response, expStatusCd int) error { actStatusCd := res.RawResponse.StatusCode if actStatusCd != expStatusCd { diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index 17a0a50845..8ff8494155 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -889,7 +889,7 @@ contractConfigConfirmations ={{if not .ContractConfirmations}} 3 {{el contractConfigTrackerPollInterval ={{if not .TrackerPollInterval}} "1m" {{else}} {{.TrackerPollInterval}} {{end}} contractConfigTrackerSubscribeInterval ={{if not .TrackerSubscribeInterval}} "2m" {{else}} {{.TrackerSubscribeInterval}} {{end}} contractAddress = "{{.ContractAddress}}" -evmChainID = "{{.EVMChainID}}" +evmChainID = "{{.EVMChainID}}" p2pBootstrapPeers = [] isBootstrapPeer = {{.IsBootstrapPeer}} p2pPeerID = "{{.P2PPeerID}}"` @@ -988,22 +988,18 @@ contractConfigConfirmations ={{if not .ContractConfirmations}} 3 {{el contractConfigTrackerPollInterval ={{if not .TrackerPollInterval}} "1m" {{else}} {{.TrackerPollInterval}} {{end}} contractConfigTrackerSubscribeInterval ={{if not .TrackerSubscribeInterval}} "2m" {{else}} {{.TrackerSubscribeInterval}} {{end}} contractAddress = "{{.ContractAddress}}" -evmChainID = "{{.EVMChainID}}" +evmChainID = "{{.EVMChainID}}" {{if .P2PBootstrapPeers}} -p2pBootstrapPeers = [ - {{range $peer := .P2PBootstrapPeers}} - "/dns4/{{$peer.InternalIP}}/tcp/6690/p2p/{{$peer.PeerID}}", - {{end}} -] +p2pv2Bootstrappers = [{{range $peer := .P2PBootstrapPeers}}"{{$peer.PeerID}}@{{$peer.InternalIP}}:6690",{{end}}] {{else}} -p2pBootstrapPeers = [] +p2pv2Bootstrappers = [] {{end}} isBootstrapPeer = {{.IsBootstrapPeer}} p2pPeerID = "{{.P2PPeerID}}" keyBundleID = "{{.KeyBundleID}}" monitoringEndpoint ={{if not .MonitoringEndpoint}} "chain.link:4321" {{else}} "{{.MonitoringEndpoint}}" {{end}} transmitterAddress = "{{.TransmitterAddress}}" -forwardingAllowed = {{.ForwardingAllowed}} +forwardingAllowed = {{.ForwardingAllowed}} observationSource = """ {{.ObservationSource}} """` diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 77c5669015..32f84991ee 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -17,9 +17,10 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" ) type CleanUpType string @@ -324,7 +325,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } else { cfg = node.NewConfig(node.NewBaseConfig(), node.WithOCR1(), - node.WithP2Pv1(), + node.WithP2Pv2(), ) } diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 29a819af13..6f892e60ac 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1098,7 +1098,7 @@ func setupKeeperTest(t *testing.T) ( contracts.LinkToken, *test_env.CLClusterTestEnv, ) { - clNodeConfig := node.NewConfig(node.NewBaseConfig(), node.WithP2Pv1()) + clNodeConfig := node.NewConfig(node.NewBaseConfig(), node.WithP2Pv2()) turnLookBack := int64(0) syncInterval := models.MustMakeDuration(5 * time.Second) performGasOverhead := uint32(150000) diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 8fbc1109e2..a078b8ca41 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/utils" @@ -39,7 +40,7 @@ func TestOCRBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) @@ -86,7 +87,7 @@ func TestOCRJobReplacement(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) @@ -112,7 +113,7 @@ func TestOCRJobReplacement(t *testing.T) { require.NoError(t, err) //Recreate job - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 7ddddafdd5..e044d1ba32 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -109,6 +109,8 @@ func WithOCR2() NodeConfigOpt { } } +// Deprecated: P2Pv1 is soon to be fully deprecated +// WithP2Pv1 enables P2Pv1 and disables P2Pv2 func WithP2Pv1() NodeConfigOpt { return func(c *chainlink.Config) { c.P2P.V1 = toml.P2PV1{ diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 08ceb4a7be..505337f032 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -27,7 +27,6 @@ import ( ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -39,12 +38,10 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) From a9d81ae52ccd4e76ed414768ad7adc4532d3facd Mon Sep 17 00:00:00 2001 From: Tate Date: Thu, 16 Nov 2023 14:01:31 -0700 Subject: [PATCH 166/327] [TT-653] More integration-test lib migration to chainlink-testing-framework (#11317) * [TT-653] Migrate more integration-test libs to chainlink-testing-framework * testing * merge conflict fix * bump ctf version --- integration-tests/actions/actions.go | 4 +- .../actions/ocr2vrf_actions/ocr2vrf_steps.go | 6 +- .../actions/operator_forwarder_helpers.go | 12 +-- .../actions/vrfv2plus/vrfv2plus_steps.go | 6 +- integration-tests/benchmark/keeper_test.go | 3 +- .../chaos/automation_chaos_test.go | 26 ++--- integration-tests/chaos/ocr2vrf_chaos_test.go | 26 ++--- integration-tests/chaos/ocr_chaos_test.go | 24 ++--- .../client/chainlink_config_builder.go | 52 ---------- integration-tests/docker/test_env/cl_node.go | 19 ++-- integration-tests/docker/test_env/test_env.go | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- .../load/vrfv2/onchain_monitoring.go | 5 +- .../load/vrfv2plus/vrfv2plus_test.go | 6 +- .../migration/upgrade_version_test.go | 6 +- integration-tests/performance/cron_test.go | 2 +- .../performance/directrequest_test.go | 6 +- integration-tests/performance/flux_test.go | 12 +-- integration-tests/performance/keeper_test.go | 10 +- integration-tests/performance/ocr_test.go | 9 +- integration-tests/performance/vrf_test.go | 8 +- .../reorg/automation_reorg_test.go | 10 +- integration-tests/reorg/reorg_confirmer.go | 7 +- integration-tests/reorg/reorg_test.go | 12 +-- integration-tests/smoke/automation_test.go | 87 ++++++++--------- integration-tests/smoke/flux_test.go | 10 +- integration-tests/smoke/forwarder_ocr_test.go | 6 +- .../smoke/forwarders_ocr2_test.go | 6 +- integration-tests/smoke/keeper_test.go | 96 +++++++++---------- integration-tests/smoke/ocr2_test.go | 12 +-- integration-tests/smoke/ocr2vrf_test.go | 8 +- integration-tests/smoke/ocr_test.go | 13 ++- integration-tests/smoke/runlog_test.go | 4 +- integration-tests/smoke/vrf_test.go | 12 +-- integration-tests/smoke/vrfv2_test.go | 6 +- integration-tests/smoke/vrfv2plus_test.go | 96 +++++++++---------- integration-tests/soak/forwarder_ocr_test.go | 2 +- integration-tests/soak/ocr_test.go | 2 +- .../testsetups/keeper_benchmark.go | 10 +- integration-tests/testsetups/ocr.go | 14 +-- integration-tests/testsetups/vrfv2.go | 4 +- integration-tests/types/config/node/core.go | 91 +++++++++--------- .../universal/log_poller/helpers.go | 16 ++-- .../universal/log_poller/scenarios.go | 14 +-- integration-tests/utils/common.go | 25 ----- 46 files changed, 368 insertions(+), 447 deletions(-) delete mode 100644 integration-tests/client/chainlink_config_builder.go diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 02a2523477..438c36a9f0 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -23,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -48,7 +48,7 @@ func FundChainlinkNodes( msg := ethereum.CallMsg{ From: common.HexToAddress(client.GetDefaultWallet().Address()), To: &recipient, - Value: utils.EtherToWei(amount), + Value: conversions.EtherToWei(amount), } gasEstimates, err := client.EstimateGas(msg) if err != nil { diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go index 72d668076e..2904162f49 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func SetAndWaitForVRFBeaconProcessToFinish(t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, vrfBeacon contracts.VRFBeacon) { @@ -273,14 +273,14 @@ func RequestRandomnessFulfillmentAndWaitForFulfilment( } func getRequestId(t *testing.T, consumer contracts.VRFBeaconConsumer, receipt *types.Receipt, confirmationDelay *big.Int) *big.Int { - periodBlocks, err := consumer.IBeaconPeriodBlocks(utils.TestContext(t)) + periodBlocks, err := consumer.IBeaconPeriodBlocks(testcontext.Get(t)) require.NoError(t, err, "Error getting Beacon Period block count") blockNumber := receipt.BlockNumber periodOffset := new(big.Int).Mod(blockNumber, periodBlocks) nextBeaconOutputHeight := new(big.Int).Sub(new(big.Int).Add(blockNumber, periodBlocks), periodOffset) - requestID, err := consumer.GetRequestIdsBy(utils.TestContext(t), nextBeaconOutputHeight, confirmationDelay) + requestID, err := consumer.GetRequestIdsBy(testcontext.Get(t), nextBeaconOutputHeight, confirmationDelay) require.NoError(t, err, "Error getting requestID from consumer contract") return requestID diff --git a/integration-tests/actions/operator_forwarder_helpers.go b/integration-tests/actions/operator_forwarder_helpers.go index a1d7135416..e308cd8fd5 100644 --- a/integration-tests/actions/operator_forwarder_helpers.go +++ b/integration-tests/actions/operator_forwarder_helpers.go @@ -12,11 +12,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func DeployForwarderContracts( @@ -67,7 +67,7 @@ func AcceptAuthorizedReceiversOperator( err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for events in nodes shouldn't fail") - senders, err := forwarderInstance.GetAuthorizedSenders(utils.TestContext(t)) + senders, err := forwarderInstance.GetAuthorizedSenders(testcontext.Get(t)) require.NoError(t, err, "Getting authorized senders shouldn't fail") var nodesAddrs []string for _, o := range nodeAddresses { @@ -75,7 +75,7 @@ func AcceptAuthorizedReceiversOperator( } require.Equal(t, nodesAddrs, senders, "Senders addresses should match node addresses") - owner, err := forwarderInstance.Owner(utils.TestContext(t)) + owner, err := forwarderInstance.Owner(testcontext.Get(t)) require.NoError(t, err, "Getting authorized forwarder owner shouldn't fail") require.Equal(t, operator.Hex(), owner, "Forwarder owner should match operator") } @@ -139,7 +139,7 @@ func SubscribeOperatorFactoryEvents( l := logging.GetTestLogger(t) contractABI, err := operator_factory.OperatorFactoryMetaData.GetAbi() require.NoError(t, err, "Getting contract abi for OperatorFactory shouldn't fail") - latestBlockNum, err := chainClient.LatestBlockNumber(utils.TestContext(t)) + latestBlockNum, err := chainClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Subscribing to contract event log for OperatorFactory instance shouldn't fail") query := geth.FilterQuery{ FromBlock: big.NewInt(0).SetUint64(latestBlockNum), @@ -147,7 +147,7 @@ func SubscribeOperatorFactoryEvents( } eventLogs := make(chan types.Log) - sub, err := chainClient.SubscribeFilterLogs(utils.TestContext(t), query, eventLogs) + sub, err := chainClient.SubscribeFilterLogs(testcontext.Get(t), query, eventLogs) require.NoError(t, err, "Subscribing to contract event log for OperatorFactory instance shouldn't fail") go func() { defer sub.Unsubscribe() @@ -158,7 +158,7 @@ func SubscribeOperatorFactoryEvents( l.Error().Err(err).Msg("Error while watching for new contract events. Retrying Subscription") sub.Unsubscribe() - sub, err = chainClient.SubscribeFilterLogs(utils.TestContext(t), query, eventLogs) + sub, err = chainClient.SubscribeFilterLogs(testcontext.Get(t), query, eventLogs) require.NoError(t, err, "Subscribing to contract event log for OperatorFactory instance shouldn't fail") case vLog := <-eventLogs: eventDetails, err := contractABI.EventByID(vLog.Topics[0]) diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 254f2ca6ce..f48d415792 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -599,7 +599,7 @@ func FundSubscriptions( ) error { for _, subID := range subIDs { //Native Billing - amountWei := utils.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountNative)) + amountWei := conversions.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountNative)) err := coordinator.FundSubscriptionWithNative( subID, amountWei, @@ -608,7 +608,7 @@ func FundSubscriptions( return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) } //Link Billing - amountJuels := utils.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountLink)) + amountJuels := conversions.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountLink)) err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 9342f3629b..6d398c685e 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -22,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" @@ -434,7 +433,7 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc testNetwork.HTTPURLs = []string{internalHttpURLs[i]} testNetwork.URLs = []string{internalWsURLs[i]} testEnvironment.AddHelm(chainlink.New(i, map[string]any{ - "toml": client.AddNetworkDetailedConfig(keeperBenchmarkBaseTOML, networkDetailTOML, testNetwork), + "toml": networks.AddNetworkDetailedConfig(keeperBenchmarkBaseTOML, networkDetailTOML, testNetwork), "chainlink": chainlinkResources, "db": dbResources, })) diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 6ebf14d806..06352a93d7 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -18,13 +18,13 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -41,7 +41,7 @@ ListenAddresses = ["0.0.0.0:6690"]` defaultAutomationSettings = map[string]interface{}{ "replicas": 6, - "toml": client.AddNetworksConfig(baseTOML, networks.MustGetSelectedNetworksFromEnv()[0]), + "toml": networks.AddNetworksConfig(baseTOML, networks.MustGetSelectedNetworksFromEnv()[0]), "db": map[string]interface{}{ "stateful": true, "capacity": "1Gi", @@ -132,7 +132,7 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -141,7 +141,7 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -150,9 +150,9 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, DurationStr: "1m", - ContainerNames: &[]*string{utils.Ptr("chainlink-db")}, + ContainerNames: &[]*string{ptr.Ptr("chainlink-db")}, }, }, NetworkChaosFailMajorityNetwork: { @@ -160,8 +160,8 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, - ToLabels: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, + FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, + ToLabels: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -170,8 +170,8 @@ func TestAutomationChaos(t *testing.T) { chainlink.New(0, defaultAutomationSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{"app": utils.Ptr("geth")}, - ToLabels: &map[string]*string{ChaosGroupMajorityPlus: utils.Ptr("1")}, + FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, + ToLabels: &map[string]*string{ChaosGroupMajorityPlus: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -269,7 +269,7 @@ func TestAutomationChaos(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(it_utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") @@ -284,7 +284,7 @@ func TestAutomationChaos(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(it_utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 10 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 8739a5960a..200114ddaf 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -17,7 +17,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCR2VRFChaos(t *testing.T) { @@ -35,7 +35,7 @@ func TestOCR2VRFChaos(t *testing.T) { defaultOCR2VRFSettings := map[string]interface{}{ "replicas": 6, - "toml": client.AddNetworkDetailedConfig( + "toml": networks.AddNetworkDetailedConfig( config.BaseOCR2Config, config.DefaultOCR2VRFNetworkDetailTomlConfig, loadedNetwork, @@ -68,7 +68,7 @@ func TestOCR2VRFChaos(t *testing.T) { chainlink.New(0, defaultOCR2VRFSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -78,7 +78,7 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewFailPods, // &chaos.Props{ - // LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, // DurationStr: "1m", // }, //}, @@ -88,9 +88,9 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewFailPods, // &chaos.Props{ - // LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, // DurationStr: "1m", - // ContainerNames: &[]*string{utils.Ptr("chainlink-db")}, + // ContainerNames: &[]*string{ptr.Ptr("chainlink-db")}, // }, //}, //NetworkChaosFailMajorityNetwork: { @@ -98,8 +98,8 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewNetworkPartition, // &chaos.Props{ - // FromLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, - // ToLabels: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, + // FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, + // ToLabels: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, // DurationStr: "1m", // }, //}, @@ -108,8 +108,8 @@ func TestOCR2VRFChaos(t *testing.T) { // chainlink.New(0, defaultOCR2VRFSettings), // chaos.NewNetworkPartition, // &chaos.Props{ - // FromLabels: &map[string]*string{"app": utils.Ptr("geth")}, - // ToLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + // FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, + // ToLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, // DurationStr: "1m", // }, //}, @@ -186,7 +186,7 @@ func TestOCR2VRFChaos(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) require.NoError(t, err) l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") @@ -213,7 +213,7 @@ func TestOCR2VRFChaos(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) require.NoError(t, err, "Error getting Randomness result from Consumer Contract") l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 76e25d9200..5368997daa 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -20,13 +20,13 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -52,7 +52,7 @@ var ( ) func TestMain(m *testing.M) { - defaultOCRSettings["toml"] = client.AddNetworksConfig(config.BaseOCRP2PV1Config, networks.MustGetSelectedNetworksFromEnv()[0]) + defaultOCRSettings["toml"] = networks.AddNetworksConfig(config.BaseOCRP2PV1Config, networks.MustGetSelectedNetworksFromEnv()[0]) os.Exit(m.Run()) } @@ -80,8 +80,8 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, - ToLabels: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, + FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, + ToLabels: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -90,8 +90,8 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewNetworkPartition, &chaos.Props{ - FromLabels: &map[string]*string{"app": utils.Ptr("geth")}, - ToLabels: &map[string]*string{ChaosGroupMajorityPlus: utils.Ptr("1")}, + FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, + ToLabels: &map[string]*string{ChaosGroupMajorityPlus: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -100,7 +100,7 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: utils.Ptr("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -109,7 +109,7 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, DurationStr: "1m", }, }, @@ -118,9 +118,9 @@ func TestOCRChaos(t *testing.T) { chainlink.New(0, defaultOCRSettings), chaos.NewFailPods, &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: utils.Ptr("1")}, + LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, DurationStr: "1m", - ContainerNames: &[]*string{utils.Ptr("chainlink-db")}, + ContainerNames: &[]*string{ptr.Ptr("chainlink-db")}, }, }, } @@ -195,7 +195,7 @@ func TestOCRChaos(t *testing.T) { err := ocr.RequestNewRound() require.NoError(t, err, "Error requesting new round") } - round, err := ocrInstances[0].GetLatestRound(it_utils.TestContext(t)) + round, err := ocrInstances[0].GetLatestRound(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred()) l.Info().Int64("RoundID", round.RoundId.Int64()).Msg("Latest OCR Round") if round.RoundId.Int64() == chaosStartRound && !chaosApplied { diff --git a/integration-tests/client/chainlink_config_builder.go b/integration-tests/client/chainlink_config_builder.go deleted file mode 100644 index 13cc1e7fe9..0000000000 --- a/integration-tests/client/chainlink_config_builder.go +++ /dev/null @@ -1,52 +0,0 @@ -package client - -import ( - "fmt" - "os" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" -) - -const ( - pyroscopeTOML = `[Pyroscope] -ServerAddress = '%s' -Environment = '%s'` - - secretTOML = ` -[Mercury.Credentials.cred1] -URL = '%s' -Username = '%s' -Password = '%s' -` -) - -// AddNetworksConfig adds EVM network configurations to a base config TOML. Useful for adding networks with default -// settings. See AddNetworkDetailedConfig for adding more detailed network configuration. -func AddNetworksConfig(baseTOML string, networks ...blockchain.EVMNetwork) string { - networksToml := "" - for _, network := range networks { - networksToml = fmt.Sprintf("%s\n\n%s", networksToml, network.MustChainlinkTOML("")) - } - return fmt.Sprintf("%s\n\n%s\n\n%s", baseTOML, pyroscopeSettings(), networksToml) -} - -func AddSecretTomlConfig(url, username, password string) string { - return fmt.Sprintf(secretTOML, url, username, password) -} - -// AddNetworkDetailedConfig adds EVM config to a base TOML. Also takes a detailed network config TOML where values like -// using transaction forwarders can be included. -// See https://github.com/smartcontractkit/chainlink/blob/develop/docs/CONFIG.md#EVM -func AddNetworkDetailedConfig(baseTOML, detailedNetworkConfig string, network blockchain.EVMNetwork) string { - return fmt.Sprintf("%s\n\n%s\n\n%s", baseTOML, pyroscopeSettings(), network.MustChainlinkTOML(detailedNetworkConfig)) -} - -func pyroscopeSettings() string { - pyroscopeServer := os.Getenv(config.EnvVarPyroscopeServer) - pyroscopeEnv := os.Getenv(config.EnvVarPyroscopeEnvironment) - if pyroscopeServer == "" { - return "" - } - return fmt.Sprintf(pyroscopeTOML, pyroscopeServer, pyroscopeEnv) -} diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 3c0a6d3af7..c781ddfc1b 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -23,11 +23,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/utils" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/integration-tests/utils/templates" ) @@ -112,7 +113,7 @@ func (n *ClNode) SetTestLogger(t *testing.T) { // Restart restarts only CL node, DB container is reused func (n *ClNode) Restart(cfg *chainlink.Config) error { - if err := n.Container.Terminate(utils.TestContext(n.t)); err != nil { + if err := n.Container.Terminate(testcontext.Get(n.t)); err != nil { return err } n.NodeConfig = cfg @@ -138,7 +139,7 @@ func (n *ClNode) PrimaryETHAddress() (string, error) { func (n *ClNode) AddBootstrapJob(verifierAddr common.Address, chainId int64, feedId [32]byte) (*client.Job, error) { - spec := utils.BuildBootstrapSpec(verifierAddr, chainId, feedId) + spec := it_utils.BuildBootstrapSpec(verifierAddr, chainId, feedId) return n.API.MustCreateJob(spec) } @@ -166,7 +167,7 @@ func (n *ClNode) AddMercuryOCRJob(verifierAddr common.Address, fromBlock uint64, } } - bridges := utils.BuildBridges(eaUrls) + bridges := it_utils.BuildBridges(eaUrls) for index := range bridges { err = n.API.MustCreateBridge(&bridges[index]) if err != nil { @@ -181,7 +182,7 @@ func (n *ClNode) AddMercuryOCRJob(verifierAddr common.Address, fromBlock uint64, allowedFaults = 2 } - spec := utils.BuildOCRSpec( + spec := it_utils.BuildOCRSpec( verifierAddr, chainId, fromBlock, feedId, bridges, csaPubKey, mercuryServerUrl, mercuryServerPubKey, nodeOCRKeyId[0], bootstrapUrl, allowedFaults) @@ -190,7 +191,7 @@ func (n *ClNode) AddMercuryOCRJob(verifierAddr common.Address, fromBlock uint64, } func (n *ClNode) GetContainerName() string { - name, err := n.Container.Name(utils.TestContext(n.t)) + name, err := n.Container.Name(testcontext.Get(n.t)) if err != nil { return "" } @@ -282,15 +283,15 @@ func (n *ClNode) StartContainer() error { return fmt.Errorf("%s err: %w", ErrStartCLNodeContainer, err) } if n.lw != nil { - if err := n.lw.ConnectContainer(utils.TestContext(n.t), container, "cl-node", true); err != nil { + if err := n.lw.ConnectContainer(testcontext.Get(n.t), container, "cl-node", true); err != nil { return err } } - clEndpoint, err := test_env.GetEndpoint(utils.TestContext(n.t), container, "http") + clEndpoint, err := test_env.GetEndpoint(testcontext.Get(n.t), container, "http") if err != nil { return err } - ip, err := container.ContainerIP(utils.TestContext(n.t)) + ip, err := container.ContainerIP(testcontext.Get(n.t)) if err != nil { return err } diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 9987bab2fe..6278ec1398 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -22,11 +22,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -266,7 +266,7 @@ func (te *CLClusterTestEnv) collectTestLogs() error { return err } defer logFile.Close() - logReader, err := node.Container.Logs(utils.TestContext(te.t)) + logReader, err := node.Container.Logs(testcontext.Get(te.t)) if err != nil { return err } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a450dd235a..99dd990bec 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -23,7 +23,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd - github.com/smartcontractkit/chainlink-testing-framework v1.18.6 + github.com/smartcontractkit/chainlink-testing-framework v1.19.0 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f882a7bb57..0402b12f3f 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2375,8 +2375,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.18.6 h1:UL3DxsPflSRALP62rsg5v3NdOsa8RHGhHMUImoWDD6k= -github.com/smartcontractkit/chainlink-testing-framework v1.18.6/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-testing-framework v1.19.0 h1:ungyY1gYcXCtmdX2yCon8pkx9HgPPLg4aNAhKNZFP5c= +github.com/smartcontractkit/chainlink-testing-framework v1.19.0/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/load/vrfv2/onchain_monitoring.go b/integration-tests/load/vrfv2/onchain_monitoring.go index 879c7089e1..66af1807ac 100644 --- a/integration-tests/load/vrfv2/onchain_monitoring.go +++ b/integration-tests/load/vrfv2/onchain_monitoring.go @@ -7,8 +7,9 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) /* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ @@ -36,7 +37,7 @@ func MonitorLoadStats(t *testing.T, vrfv2Contracts *vrfv2_actions.VRFV2Contracts } for { time.Sleep(1 * time.Second) - metrics, err := vrfv2Contracts.LoadTestConsumer.GetLoadTestMetrics(utils.TestContext(t)) + metrics, err := vrfv2Contracts.LoadTestConsumer.GetLoadTestMetrics(testcontext.Get(t)) if err != nil { log.Error().Err(err).Msg(ErrMetrics) } diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index e7734fee0d..11e160297f 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -14,8 +14,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" @@ -99,7 +99,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { Str("Returning funds from SubID", subID.String()). Str("Returning funds to", eoaWalletAddress). Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(utils.TestContext(t), subID) + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subID) if err != nil { l.Error().Err(err).Msg("Error checking if pending requests exist") } @@ -230,7 +230,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) } diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index c851f36ec6..d1f07a52b7 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) @@ -19,9 +19,9 @@ func TestVersionUpgrade(t *testing.T) { Build() require.NoError(t, err) - upgradeImage, err := utils.GetEnv("UPGRADE_IMAGE") + upgradeImage, err := osutil.GetEnv("UPGRADE_IMAGE") require.NoError(t, err, "Error getting upgrade image") - upgradeVersion, err := utils.GetEnv("UPGRADE_VERSION") + upgradeVersion, err := osutil.GetEnv("UPGRADE_VERSION") require.NoError(t, err, "Error getting upgrade version") _ = os.Setenv("CHAINLINK_IMAGE", upgradeImage) diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index 7e90d29221..38d861cee0 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -121,7 +121,7 @@ func setupCronTest(t *testing.T) (testEnvironment *environment.Environment) { HTTPWriteTimout = '300s'` cd := chainlink.New(0, map[string]interface{}{ "replicas": 1, - "toml": client.AddNetworksConfig(baseTOML, network), + "toml": networks.AddNetworksConfig(baseTOML, network), }) testEnvironment = environment.New(&environment.Config{ diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index 1a3f1d2a01..0fe1ca37e1 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -19,12 +19,12 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/google/uuid" ) @@ -108,7 +108,7 @@ func TestDirectRequestPerformance(t *testing.T) { gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(utils.TestContext(t)) + d, err := consumer.Data(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") l.Debug().Int64("Data", d.Int64()).Msg("Found on chain") @@ -142,7 +142,7 @@ func setupDirectRequestTest(t *testing.T) (testEnvironment *environment.Environm HTTPWriteTimout = '300s'` cd := chainlink.New(0, map[string]interface{}{ "replicas": 1, - "toml": client.AddNetworksConfig(baseTOML, network), + "toml": networks.AddNetworksConfig(baseTOML, network), }) testEnvironment = environment.New(&environment.Config{ diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index 18b13ab907..5fa31b626a 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -20,12 +20,12 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestFluxPerformance(t *testing.T) { @@ -83,7 +83,7 @@ func TestFluxPerformance(t *testing.T) { require.NoError(t, err, "Setting oracle options in the Flux Aggregator contract shouldn't fail") err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - oracles, err := fluxInstance.GetOracles(utils.TestContext(t)) + oracles, err := fluxInstance.GetOracles(testcontext.Get(t)) require.NoError(t, err, "Getting oracle details from the Flux aggregator contract shouldn't fail") l.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") @@ -120,7 +120,7 @@ func TestFluxPerformance(t *testing.T) { chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err := fluxInstance.GetContractData(utils.TestContext(t)) + data, err := fluxInstance.GetContractData(testcontext.Get(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") l.Info().Interface("Data", data).Msg("Round data") require.Equal(t, int64(1e5), data.LatestRoundData.Answer.Int64(), @@ -140,7 +140,7 @@ func TestFluxPerformance(t *testing.T) { require.NoError(t, err, "Setting value path in mock server shouldn't fail") err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err = fluxInstance.GetContractData(utils.TestContext(t)) + data, err = fluxInstance.GetContractData(testcontext.Get(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") require.Equal(t, int64(1e10), data.LatestRoundData.Answer.Int64(), "Expected latest round answer to be %d, but found %d", int64(1e10), data.LatestRoundData.Answer.Int64()) @@ -153,7 +153,7 @@ func TestFluxPerformance(t *testing.T) { l.Info().Interface("data", data).Msg("Round data") for _, oracleAddr := range nodeAddresses { - payment, _ := fluxInstance.WithdrawablePayment(utils.TestContext(t), oracleAddr) + payment, _ := fluxInstance.WithdrawablePayment(testcontext.Get(t), oracleAddr) require.Equal(t, int64(2), payment.Int64(), "Expected flux aggregator contract's withdrawable payment to be %d, but found %d", int64(2), payment.Int64()) } @@ -189,7 +189,7 @@ HTTPWriteTimout = '300s' Enabled = true` cd := chainlink.New(0, map[string]interface{}{ "replicas": 3, - "toml": client.AddNetworksConfig(baseTOML, testNetwork), + "toml": networks.AddNetworksConfig(baseTOML, testNetwork), }) testEnvironment = environment.New(&environment.Config{ diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index 8e273a96f6..ac6e9e6a57 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -19,13 +19,13 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var keeperDefaultRegistryConfig = contracts.KeeperRegistrySettings{ @@ -74,7 +74,7 @@ func TestKeeperPerformance(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) @@ -95,7 +95,7 @@ func TestKeeperPerformance(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterCancellation[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Index", i).Int64("Upkeeps Performed", countersAfterCancellation[i].Int64()).Msg("Cancelled Upkeep") } @@ -103,7 +103,7 @@ func TestKeeperPerformance(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant because the upkeep was cancelled, so it shouldn't increase anymore - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterCancellation[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", @@ -155,7 +155,7 @@ PerformGasOverhead = 150_000` networkName := strings.ReplaceAll(strings.ToLower(network.Name), " ", "-") cd := chainlink.New(0, map[string]interface{}{ "replicas": 5, - "toml": client.AddNetworksConfig(baseTOML, network), + "toml": networks.AddNetworksConfig(baseTOML, network), }) testEnvironment := environment.New( diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index 47879cebb8..7f91f4321a 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -17,14 +17,13 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCRBasic(t *testing.T) { @@ -64,7 +63,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(1, ocrInstances, chainClient, l) require.NoError(t, err) - answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) @@ -73,7 +72,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(2, ocrInstances, chainClient, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } @@ -113,7 +112,7 @@ ListenIP = '0.0.0.0' ListenPort = 6690` cd := chainlink.New(0, map[string]interface{}{ "replicas": 6, - "toml": client.AddNetworksConfig(baseTOML, testNetwork), + "toml": networks.AddNetworksConfig(baseTOML, testNetwork), }) testEnvironment = environment.New(&environment.Config{ diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index 7a38a45495..cad4ea5eeb 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -17,12 +17,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestVRFBasic(t *testing.T) { @@ -97,7 +97,7 @@ func TestVRFBasic(t *testing.T) { encodedProvingKeys := make([][2]*big.Int, 0) encodedProvingKeys = append(encodedProvingKeys, provingKey) - requestHash, err := coordinator.HashOfKey(utils.TestContext(t), encodedProvingKeys[0]) + requestHash, err := coordinator.HashOfKey(testcontext.Get(t), encodedProvingKeys[0]) require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") err = consumer.RequestRandomness(requestHash, big.NewInt(1)) require.NoError(t, err, "Requesting randomness shouldn't fail") @@ -108,7 +108,7 @@ func TestVRFBasic(t *testing.T) { jobRuns, err := chainlinkNodes[0].MustReadRunsByJob(job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - out, err := consumer.RandomnessOutput(utils.TestContext(t)) + out, err := consumer.RandomnessOutput(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") // Checks that the job has actually run g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), @@ -147,7 +147,7 @@ func setupVRFTest(t *testing.T) (testEnvironment *environment.Environment, testN baseTOML := `[WebServer] HTTPWriteTimout = '300s'` cd := chainlink.New(0, map[string]interface{}{ - "toml": client.AddNetworksConfig(baseTOML, testNetwork), + "toml": networks.AddNetworksConfig(baseTOML, testNetwork), }) testEnvironment = environment.New(&environment.Config{ diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index 58cd147201..dae977d3ee 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -18,12 +18,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -49,7 +49,7 @@ Mode = 'FixedPrice' LimitDefault = 5_000_000` activeEVMNetwork = networks.MustGetSelectedNetworksFromEnv()[0] defaultAutomationSettings = map[string]interface{}{ - "toml": client.AddNetworkDetailedConfig(baseTOML, networkTOML, activeEVMNetwork), + "toml": networks.AddNetworkDetailedConfig(baseTOML, networkTOML, activeEVMNetwork), "db": map[string]interface{}{ "stateful": false, "capacity": "1Gi", @@ -210,7 +210,7 @@ func TestAutomationReorg(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(it_utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") @@ -241,7 +241,7 @@ func TestAutomationReorg(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(it_utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 10 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") @@ -258,7 +258,7 @@ func TestAutomationReorg(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 20 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(it_utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 20 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") diff --git a/integration-tests/reorg/reorg_confirmer.go b/integration-tests/reorg/reorg_confirmer.go index 2193131680..a5659e6678 100644 --- a/integration-tests/reorg/reorg_confirmer.go +++ b/integration-tests/reorg/reorg_confirmer.go @@ -15,8 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" - - "github.com/smartcontractkit/chainlink/integration-tests/utils" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" ) // The steps are: @@ -232,8 +231,8 @@ func (rc *ReorgController) forkNetwork(header blockchain.NodeHeader) error { rc.cfg.Env.Cfg.Namespace, &chaos.Props{ DurationStr: "999h", - FromLabels: &map[string]*string{"app": utils.Ptr(reorg.TXNodesAppLabel)}, - ToLabels: &map[string]*string{"app": utils.Ptr(reorg.MinerNodesAppLabel)}, + FromLabels: &map[string]*string{"app": ptr.Ptr(reorg.TXNodesAppLabel)}, + ToLabels: &map[string]*string{"app": ptr.Ptr(reorg.MinerNodesAppLabel)}, }, )) rc.chaosExperimentName = expName diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go index d5fefdbc56..fc35047d0e 100644 --- a/integration-tests/reorg/reorg_test.go +++ b/integration-tests/reorg/reorg_test.go @@ -9,6 +9,8 @@ import ( "time" "github.com/google/uuid" + "github.com/onsi/gomega" + "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" @@ -21,16 +23,12 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/logging" - - "github.com/onsi/gomega" - "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) const ( @@ -127,7 +125,7 @@ func TestDirectRequestReorg(t *testing.T) { netCfg := fmt.Sprintf(networkDRTOML, EVMFinalityDepth, EVMTrackerHistoryDepth) chainlinkDeployment := chainlink.New(0, map[string]interface{}{ "replicas": 1, - "toml": client.AddNetworkDetailedConfig(baseDRTOML, netCfg, activeEVMNetwork), + "toml": networks.AddNetworkDetailedConfig(baseDRTOML, netCfg, activeEVMNetwork), }) err = testEnvironment.AddHelm(chainlinkDeployment).Run() @@ -221,7 +219,7 @@ func TestDirectRequestReorg(t *testing.T) { gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(it_utils.TestContext(t)) + d, err := consumer.Data(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") log.Debug().Int64("Data", d.Int64()).Msg("Found on chain") diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 87074e786d..05d19d5ccd 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -22,6 +22,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" @@ -33,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) @@ -171,7 +172,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") @@ -193,7 +194,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are increasing by 5 in each step within 5 minutes for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), @@ -216,7 +217,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterCancellation[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeep Count", countersAfterCancellation[i].Int64()).Int("Upkeep Index", i).Msg("Cancelled upkeep") } @@ -225,7 +226,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant (At most increase by 1 to account for stale performs) because the upkeep was cancelled - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterCancellation[i].Int64()+1), "Expected consumer counter to remain less than or equal to %d, but got %d", @@ -271,7 +272,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := 5 l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") @@ -328,7 +329,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { time.Sleep(10 * time.Second) for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterSetNoMatch[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterSetNoMatch[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeep Count", countersAfterSetNoMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") } @@ -338,7 +339,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant (At most increase by 2 to account for stale performs) because the upkeep trigger config is not met bufferCount := int64(2) - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterSetNoMatch[i].Int64()+bufferCount), "Expected consumer counter to remain less than or equal to %d, but got %d", @@ -374,7 +375,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterSetMatch[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterSetMatch[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int64("Upkeep Count", countersAfterSetMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") } @@ -393,7 +394,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) expect := int64(5) l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") @@ -424,7 +425,7 @@ func TestAutomationAddFunds(t *testing.T) { gom := gomega.NewGomegaWithT(t) // Since the upkeep is currently underfunded, check that it doesn't get executed gom.Consistently(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(utils.TestContext(t)) + counter, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), "Expected consumer counter to remain zero, but got %d", counter.Int64()) @@ -444,7 +445,7 @@ func TestAutomationAddFunds(t *testing.T) { // Now the new upkeep should be performing because we added enough funds gom.Eventually(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(utils.TestContext(t)) + counter, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -476,7 +477,7 @@ func TestAutomationPauseUnPause(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)), "Expected consumer counter to be greater than 5, but got %d", counter.Int64()) @@ -496,7 +497,7 @@ func TestAutomationPauseUnPause(t *testing.T) { var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterPause[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Upkeep Index", i).Int64("Upkeeps Performed", countersAfterPause[i].Int64()).Msg("Paused Upkeep") } @@ -505,7 +506,7 @@ func TestAutomationPauseUnPause(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // In most cases counters should remain constant, but there might be a straggling perform tx which // gets committed later and increases counter by 1 - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterPause[i].Int64()+1), "Expected consumer counter not have increased more than %d, but got %d", @@ -525,7 +526,7 @@ func TestAutomationPauseUnPause(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 + numbers of performing before pause for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", countersAfterPause[i].Int64()+1), "Expected consumer counter to be greater than %d, but got %d", countersAfterPause[i].Int64()+1, counter.Int64()) @@ -561,7 +562,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { // store the value of their initial counters in order to compare later on that the value increased. gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -581,7 +582,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { // Test that the newly registered upkeep is also performing. gom.Eventually(func(g gomega.Gomega) { - counter, err := newUpkeep.Counter(utils.TestContext(t)) + counter, err := newUpkeep.Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling newly deployed upkeep's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -590,7 +591,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(utils.TestContext(t)) + currentCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info(). @@ -630,7 +631,7 @@ func TestAutomationPauseRegistry(t *testing.T) { // Observe that the upkeeps which are initially registered are performing gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d") @@ -646,7 +647,7 @@ func TestAutomationPauseRegistry(t *testing.T) { // Store how many times each upkeep performed once the registry was successfully paused var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterPause[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) } @@ -654,7 +655,7 @@ func TestAutomationPauseRegistry(t *testing.T) { // because they are no longer getting serviced gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterPause[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", @@ -691,7 +692,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // Watch upkeeps being performed and store their counters in order to compare them later in the test gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -710,7 +711,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // Assert that upkeeps are still performed and their counters have increased gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(utils.TestContext(t)) + currentCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(currentCounter.Int64()).Should(gomega.BeNumerically(">", initialCounters[i].Int64()), "Expected counter to have increased from initial value of %s, but got %s", @@ -731,7 +732,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // See how many times each upkeep was executed var countersAfterNoMoreNodes = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterNoMoreNodes[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterNoMoreNodes[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Upkeep Index", i).Int64("Performed", countersAfterNoMoreNodes[i].Int64()).Msg("Upkeeps Performed") } @@ -740,7 +741,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // all the nodes were taken down gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterNoMoreNodes[i].Int64()+1), "Expected consumer counter to not have increased more than %d, but got %d", @@ -789,7 +790,7 @@ func TestAutomationPerformSimulation(t *testing.T) { // Initially performGas is set high, so performUpkeep reverts and no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { // Consumer count should remain at 0 - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.Equal(int64(0)), "Expected consumer counter to remain constant at %d, but got %d", 0, cnt.Int64(), @@ -797,14 +798,14 @@ func TestAutomationPerformSimulation(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Set performGas on consumer to be low, so that performUpkeep starts becoming successful - err := consumerPerformance.SetPerformGasToBurn(utils.TestContext(t), big.NewInt(100000)) + err := consumerPerformance.SetPerformGasToBurn(testcontext.Get(t), big.NewInt(100000)) require.NoError(t, err, "Perform gas should be set successfully on consumer") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for set perform gas tx") // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -854,7 +855,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { // Initially performGas is set higher than defaultUpkeepGasLimit, so no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.Equal(int64(0)), @@ -870,7 +871,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -878,19 +879,19 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m to perform once, 1m buffer // Now increase the checkGasBurn on consumer, upkeep should stop performing - err = consumerPerformance.SetCheckGasToBurn(utils.TestContext(t), big.NewInt(3000000)) + err = consumerPerformance.SetCheckGasToBurn(testcontext.Get(t), big.NewInt(3000000)) require.NoError(t, err, "Check gas burn should be set successfully on consumer") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetCheckGasToBurn tx") // Get existing performed count - existingCnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + existingCnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) require.NoError(t, err, "Calling consumer's counter shouldn't fail") l.Info().Int64("Upkeep counter", existingCnt.Int64()).Msg("Upkeep counter when check gas increased") // In most cases count should remain constant, but it might increase by upto 1 due to pending perform gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.BeNumerically("<=", existingCnt.Int64()+1), @@ -898,7 +899,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { ) }, "1m", "1s").Should(gomega.Succeed()) - existingCnt, err = consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + existingCnt, err = consumerPerformance.GetUpkeepCount(testcontext.Get(t)) require.NoError(t, err, "Calling consumer's counter shouldn't fail") existingCntInt := existingCnt.Int64() l.Info().Int64("Upkeep counter", existingCntInt).Msg("Upkeep counter when consistently block finished") @@ -918,7 +919,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { // Upkeep should start performing again, and it should get regularly performed gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", existingCntInt), "Expected consumer counter to be greater than %d, but got %d", existingCntInt, cnt.Int64(), @@ -962,7 +963,7 @@ func TestUpdateCheckData(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { // expect the counter to remain 0 because perform data does not match for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(utils.TestContext(t)) + counter, err := performDataChecker[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker"+ " for upkeep at index "+strconv.Itoa(i)) g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), @@ -981,7 +982,7 @@ func TestUpdateCheckData(t *testing.T) { // retrieve new check data for all upkeeps for i := 0; i < len(upkeepIDs); i++ { - upkeep, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepIDs[i]) + upkeep, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepIDs[i]) require.NoError(t, err, "Failed to get upkeep info at index %d", i) require.Equal(t, []byte(automationExpectedData), upkeep.CheckData, "Upkeep data not as expected") } @@ -989,7 +990,7 @@ func TestUpdateCheckData(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(utils.TestContext(t)) + counter, err := performDataChecker[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker counter"+ " for upkeep at index "+strconv.Itoa(i)) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -1030,11 +1031,11 @@ func setupAutomationTestDocker( // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) syncInterval := models.MustMakeDuration(5 * time.Minute) - clNodeConfig.Feature.LogPoller = utils.Ptr[bool](true) - clNodeConfig.OCR2.Enabled = utils.Ptr[bool](true) - clNodeConfig.Keeper.TurnLookBack = utils.Ptr[int64](int64(0)) + clNodeConfig.Feature.LogPoller = ptr.Ptr[bool](true) + clNodeConfig.OCR2.Enabled = ptr.Ptr[bool](true) + clNodeConfig.Keeper.TurnLookBack = ptr.Ptr[int64](int64(0)) clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval - clNodeConfig.Keeper.Registry.PerformGasOverhead = utils.Ptr[uint32](uint32(150000)) + clNodeConfig.Keeper.Registry.PerformGasOverhead = ptr.Ptr[uint32](uint32(150000)) clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 2997ff1c74..72dc15e7b1 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -13,12 +13,12 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestFluxBasic(t *testing.T) { @@ -74,7 +74,7 @@ func TestFluxBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - oracles, err := fluxInstance.GetOracles(utils.TestContext(t)) + oracles, err := fluxInstance.GetOracles(testcontext.Get(t)) require.NoError(t, err, "Getting oracle details from the Flux aggregator contract shouldn't fail") l.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") @@ -108,7 +108,7 @@ func TestFluxBasic(t *testing.T) { env.EVMClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err := fluxInstance.GetContractData(utils.TestContext(t)) + data, err := fluxInstance.GetContractData(testcontext.Get(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") require.Equal(t, int64(1e5), data.LatestRoundData.Answer.Int64(), "Expected latest round answer to be %d, but found %d", int64(1e5), data.LatestRoundData.Answer.Int64()) @@ -127,7 +127,7 @@ func TestFluxBasic(t *testing.T) { require.NoError(t, err, "Setting value path in mock server shouldn't fail") err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err = fluxInstance.GetContractData(utils.TestContext(t)) + data, err = fluxInstance.GetContractData(testcontext.Get(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") require.Equal(t, int64(1e10), data.LatestRoundData.Answer.Int64(), "Expected latest round answer to be %d, but found %d", int64(1e10), data.LatestRoundData.Answer.Int64()) @@ -140,7 +140,7 @@ func TestFluxBasic(t *testing.T) { l.Info().Interface("data", data).Msg("Round data") for _, oracleAddr := range nodeAddresses { - payment, _ := fluxInstance.WithdrawablePayment(utils.TestContext(t), oracleAddr) + payment, _ := fluxInstance.WithdrawablePayment(testcontext.Get(t), oracleAddr) require.Equal(t, int64(2), payment.Int64(), "Expected flux aggregator contract's withdrawable payment to be %d, but found %d", int64(2), payment.Int64()) } diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index 7203e03178..d4f9b5884a 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestForwarderOCRBasic(t *testing.T) { @@ -72,7 +72,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) @@ -83,7 +83,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index be87eb5629..c9fe3cb11d 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -11,12 +11,12 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestForwarderOCR2Basic(t *testing.T) { @@ -92,7 +92,7 @@ func TestForwarderOCR2Basic(t *testing.T) { err = actions.StartNewOCR2Round(1, ocrInstances, env.EVMClient, time.Minute*10, l) require.NoError(t, err) - answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCRv2 contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCRw contract to be 5 but got %d", answer.Int64()) @@ -103,7 +103,7 @@ func TestForwarderOCR2Basic(t *testing.T) { err = actions.StartNewOCR2Round(int64(i), ocrInstances, env.EVMClient, time.Minute*10, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Error getting latest OCRv2 answer") require.Equal(t, int64(ocrRoundVal), answer.Int64(), fmt.Sprintf("Expected latest answer from OCRv2 contract to be %d but got %d", ocrRoundVal, answer.Int64())) } diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 6f892e60ac..bcf64a5feb 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) const ( @@ -109,7 +109,7 @@ func TestKeeperBasicSmoke(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) @@ -131,7 +131,7 @@ func TestKeeperBasicSmoke(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterCancellation[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) l.Info().Int("Index", i).Int64("Upkeeps Performed", countersAfterCancellation[i].Int64()).Msg("Cancelled Upkeep") } @@ -139,7 +139,7 @@ func TestKeeperBasicSmoke(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { // Expect the counter to remain constant because the upkeep was cancelled, so it shouldn't increase anymore - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterCancellation[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", @@ -187,11 +187,11 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { // Wait for upkeep to be performed twice by different keepers (buddies) gom.Eventually(func(g gomega.Gomega) error { - counter, err := consumers[0].Counter(utils.TestContext(t)) + counter, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Number of upkeeps performed") - upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -205,7 +205,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { }, "1m", "1s").Should(gomega.Succeed()) gom.Eventually(func(g gomega.Gomega) error { - upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -219,7 +219,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { // Expect no new keepers to perform for a while gom.Consistently(func(g gomega.Gomega) { - upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -235,11 +235,11 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { // Expect a new keeper to perform gom.Eventually(func(g gomega.Gomega) error { - counter, err := consumers[0].Counter(utils.TestContext(t)) + counter, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Num upkeeps performed") - upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") latestKeeper := upkeepInfo.LastKeeper @@ -296,7 +296,7 @@ func TestKeeperSimulation(t *testing.T) { // Initially performGas is set high, so performUpkeep reverts and no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { // Consumer count should remain at 0 - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.Equal(int64(0)), @@ -304,20 +304,20 @@ func TestKeeperSimulation(t *testing.T) { ) // Not even reverted upkeeps should be performed. Last keeper for the upkeep should be 0 address - upkeepInfo, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepID) + upkeepInfo, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Registry's getUpkeep shouldn't fail") g.Expect(upkeepInfo.LastKeeper).Should(gomega.Equal(actions.ZeroAddress.String()), "Last keeper should be zero address") }, "1m", "1s").Should(gomega.Succeed()) // Set performGas on consumer to be low, so that performUpkeep starts becoming successful - err = consumerPerformance.SetPerformGasToBurn(utils.TestContext(t), big.NewInt(100000)) + err = consumerPerformance.SetPerformGasToBurn(testcontext.Get(t), big.NewInt(100000)) require.NoError(t, err, "Error setting PerformGasToBurn") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting to set PerformGasToBurn") // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) error { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -368,7 +368,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // Initially performGas is set higher than defaultUpkeepGasLimit, so no upkeep should be performed gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.Equal(int64(0)), @@ -384,7 +384,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // Upkeep should now start performing gom.Eventually(func(g gomega.Gomega) error { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", cnt.Int64(), @@ -393,13 +393,13 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { }, "1m", "1s").Should(gomega.Succeed()) // Now increase the checkGasBurn on consumer, upkeep should stop performing - err = consumerPerformance.SetCheckGasToBurn(utils.TestContext(t), big.NewInt(3000000)) + err = consumerPerformance.SetCheckGasToBurn(testcontext.Get(t), big.NewInt(3000000)) require.NoError(t, err, "Error setting CheckGasToBurn") err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetCheckGasToBurn tx") // Get existing performed count - existingCnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + existingCnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) require.NoError(t, err, "Error calling consumer's counter") l.Info().Int64("Upkeep counter", existingCnt.Int64()).Msg("Check Gas Increased") @@ -407,7 +407,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // gets committed later. Since every keeper node cannot have more than 1 straggling tx, it // is sufficient to check that the upkeep count does not increase by more than 6. gom.Consistently(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(cnt.Int64()).Should( gomega.BeNumerically("<=", existingCnt.Int64()+numUpkeepsAllowedForStragglingTxs), @@ -415,7 +415,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { ) }, "3m", "1s").Should(gomega.Succeed()) - existingCnt, err = consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + existingCnt, err = consumerPerformance.GetUpkeepCount(testcontext.Get(t)) require.NoError(t, err, "Error calling consumer's counter") existingCntInt := existingCnt.Int64() l.Info().Int64("Upkeep counter", existingCntInt).Msg("Upkeep counter when consistently block finished") @@ -430,7 +430,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { // Upkeep should start performing again, and it should get regularly performed gom.Eventually(func(g gomega.Gomega) { - cnt, err := consumerPerformance.GetUpkeepCount(utils.TestContext(t)) + cnt, err := consumerPerformance.GetUpkeepCount(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's Counter shouldn't fail") g.Expect(cnt.Int64()).Should(gomega.BeNumerically(">", existingCntInt), "Expected consumer counter to be greater than %d, but got %d", existingCntInt, cnt.Int64(), @@ -478,7 +478,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { // store the value of their initial counters in order to compare later on that the value increased. gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter"+ " for upkeep at index "+strconv.Itoa(i)) @@ -500,7 +500,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { // Test that the newly registered upkeep is also performing. gom.Eventually(func(g gomega.Gomega) error { - counter, err := newUpkeep.Counter(utils.TestContext(t)) + counter, err := newUpkeep.Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling newly deployed upkeep's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -510,7 +510,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(utils.TestContext(t)) + currentCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") l.Info(). @@ -563,7 +563,7 @@ func TestKeeperAddFunds(t *testing.T) { // Since the upkeep is currently underfunded, check that it doesn't get executed gom.Consistently(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(utils.TestContext(t)) + counter, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), "Expected consumer counter to remain zero, but got %d", counter.Int64()) @@ -583,7 +583,7 @@ func TestKeeperAddFunds(t *testing.T) { // Now the new upkeep should be performing because we added enough funds gom.Eventually(func(g gomega.Gomega) { - counter, err := consumers[0].Counter(utils.TestContext(t)) + counter, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected newly registered upkeep's counter to be greater than 0, but got %d", counter.Int64()) @@ -628,7 +628,7 @@ func TestKeeperRemove(t *testing.T) { // Make sure the upkeeps are running before we remove a keeper gom.Eventually(func(g gomega.Gomega) error { for upkeepID := 0; upkeepID < len(upkeepIDs); upkeepID++ { - counter, err := consumers[upkeepID].Counter(utils.TestContext(t)) + counter, err := consumers[upkeepID].Counter(testcontext.Get(t)) initialCounters[upkeepID] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter"+ " for upkeep with ID "+strconv.Itoa(upkeepID)) @@ -637,7 +637,7 @@ func TestKeeperRemove(t *testing.T) { return nil }, "1m", "1s").Should(gomega.Succeed()) - keepers, err := registry.GetKeeperList(utils.TestContext(t)) + keepers, err := registry.GetKeeperList(testcontext.Get(t)) require.NoError(t, err, "Error getting list of Keepers") // Remove the first keeper from the list @@ -660,7 +660,7 @@ func TestKeeperRemove(t *testing.T) { // The upkeeps should still perform and their counters should have increased compared to the first check gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Cmp(initialCounters[i]) == 1, "Expected consumer counter to be greater "+ "than initial counter which was %s, but got %s", initialCounters[i], counter) @@ -705,7 +705,7 @@ func TestKeeperPauseRegistry(t *testing.T) { // Observe that the upkeeps which are initially registered are performing gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d") @@ -722,7 +722,7 @@ func TestKeeperPauseRegistry(t *testing.T) { // Store how many times each upkeep performed once the registry was successfully paused var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterPause[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Error retrieving consumer at index %d", i) } @@ -730,7 +730,7 @@ func TestKeeperPauseRegistry(t *testing.T) { // because they are no longer getting serviced gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Error retrieving consumer contract at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterPause[i].Int64()), "Expected consumer counter to remain constant at %d, but got %d", @@ -791,7 +791,7 @@ func TestKeeperMigrateRegistry(t *testing.T) { // Check that the first upkeep from the first registry is performing (before being migrated) gom.Eventually(func(g gomega.Gomega) error { - counterBeforeMigration, err := consumers[0].Counter(utils.TestContext(t)) + counterBeforeMigration, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(counterBeforeMigration.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %s", counterBeforeMigration) @@ -810,12 +810,12 @@ func TestKeeperMigrateRegistry(t *testing.T) { err = chainClient.WaitForEvents() require.NoError(t, err, "Error waiting to pause first registry") - counterAfterMigration, err := consumers[0].Counter(utils.TestContext(t)) + counterAfterMigration, err := consumers[0].Counter(testcontext.Get(t)) require.NoError(t, err, "Error calling consumer's counter") // Check that once we migrated the upkeep, the counter has increased gom.Eventually(func(g gomega.Gomega) error { - currentCounter, err := consumers[0].Counter(utils.TestContext(t)) + currentCounter, err := consumers[0].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Calling consumer's counter shouldn't fail") g.Expect(currentCounter.Int64()).Should(gomega.BeNumerically(">", counterAfterMigration.Int64()), "Expected counter to have increased, but stayed constant at %s", counterAfterMigration) @@ -860,7 +860,7 @@ func TestKeeperNodeDown(t *testing.T) { // Watch upkeeps being performed and store their counters in order to compare them later in the test gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) initialCounters[i] = counter g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), @@ -882,7 +882,7 @@ func TestKeeperNodeDown(t *testing.T) { // Assert that upkeeps are still performed and their counters have increased gom.Eventually(func(g gomega.Gomega) error { for i := 0; i < len(upkeepIDs); i++ { - currentCounter, err := consumers[i].Counter(utils.TestContext(t)) + currentCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(currentCounter.Int64()).Should(gomega.BeNumerically(">", initialCounters[i].Int64()), "Expected counter to have increased from initial value of %s, but got %s", @@ -908,7 +908,7 @@ func TestKeeperNodeDown(t *testing.T) { // See how many times each upkeep was executed var countersAfterNoMoreNodes = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { - countersAfterNoMoreNodes[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterNoMoreNodes[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Error retrieving consumer counter %d", i) l.Info(). Int("Index", i). @@ -921,7 +921,7 @@ func TestKeeperNodeDown(t *testing.T) { // so a +6 on the upper limit side should be sufficient. gom.Consistently(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterNoMoreNodes[i].Int64()+numUpkeepsAllowedForStragglingTxs, @@ -964,7 +964,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)), "Expected consumer counter to be greater than 5, but got %d", counter.Int64()) @@ -985,7 +985,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { var countersAfterPause = make([]*big.Int, len(upkeepIDs)) for i := 0; i < len(upkeepIDs); i++ { // Obtain the amount of times the upkeep has been executed so far - countersAfterPause[i], err = consumers[i].Counter(utils.TestContext(t)) + countersAfterPause[i], err = consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Error retrieving upkeep count at index %d", i) l.Info(). Int("Index", i). @@ -998,7 +998,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { // In most cases counters should remain constant, but there might be a straggling perform tx which // gets committed later. Since every keeper node cannot have more than 1 straggling tx, it // is sufficient to check that the upkeep count does not increase by more than 6. - latestCounter, err := consumers[i].Counter(utils.TestContext(t)) + latestCounter, err := consumers[i].Counter(testcontext.Get(t)) require.NoError(t, err, "Error retrieving counter at index %d", i) g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterPause[i].Int64()+numUpkeepsAllowedForStragglingTxs), "Expected consumer counter not have increased more than %d, but got %d", @@ -1018,7 +1018,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 + numbers of performing before pause for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter"+ " for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)+countersAfterPause[i].Int64()), @@ -1055,7 +1055,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { gom.Consistently(func(g gomega.Gomega) { // expect the counter to remain 0 because perform data does not match for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(utils.TestContext(t)) + counter, err := performDataChecker[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.Equal(int64(0)), "Expected perform data checker counter to be 0, but got %d", counter.Int64()) @@ -1073,7 +1073,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { // retrieve new check data for all upkeeps for i := 0; i < len(upkeepIDs); i++ { - upkeep, err := registry.GetUpkeepInfo(utils.TestContext(t), upkeepIDs[i]) + upkeep, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepIDs[i]) require.NoError(t, err, "Error getting upkeep info from index %d", i) require.Equal(t, []byte(keeperExpectedData), upkeep.CheckData, "Check data not as expected") } @@ -1081,7 +1081,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 5 for i := 0; i < len(upkeepIDs); i++ { - counter, err := performDataChecker[i].Counter(utils.TestContext(t)) + counter, err := performDataChecker[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve perform data checker counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(5)), "Expected perform data checker counter to be greater than 5, but got %d", counter.Int64()) @@ -1154,7 +1154,7 @@ func TestKeeperJobReplacement(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) @@ -1183,7 +1183,7 @@ func TestKeeperJobReplacement(t *testing.T) { gom.Eventually(func(g gomega.Gomega) error { // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(utils.TestContext(t)) + counter, err := consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index bec82e633f..0676ed0300 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -10,11 +10,11 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) // Tests a basic OCRv2 median feed @@ -72,7 +72,7 @@ func TestOCRv2Basic(t *testing.T) { err = actions.StartNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err, "Error starting new OCR2 round") - roundData, err := aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(1)) + roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", @@ -84,7 +84,7 @@ func TestOCRv2Basic(t *testing.T) { err = actions.StartNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err) - roundData, err = aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(2)) + roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), roundData.Answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", @@ -146,7 +146,7 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.StartNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err, "Error starting new OCR2 round") - roundData, err := aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(1)) + roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", @@ -158,7 +158,7 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.StartNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err) - roundData, err = aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(2)) + roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), roundData.Answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", @@ -176,7 +176,7 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.StartNewOCR2Round(3, aggregatorContracts, env.EVMClient, time.Minute*3, l) require.NoError(t, err, "Error starting new OCR2 round") - roundData, err = aggregatorContracts[0].GetRound(utils.TestContext(t), big.NewInt(3)) + roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(3)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(15), roundData.Answer.Int64(), "Expected latest answer from OCR contract to be 15 but got %d", diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 57bd5412b1..773476826c 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -15,6 +15,7 @@ import ( eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCR2VRFRedeemModel(t *testing.T) { @@ -80,7 +80,7 @@ func TestOCR2VRFRedeemModel(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) require.NoError(t, err) l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") @@ -141,7 +141,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { ) for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(it_utils.TestContext(t), requestID, big.NewInt(int64(i))) + randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) require.NoError(t, err, "Error getting Randomness result from Consumer Contract") l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness Fulfillment retrieved from Consumer contract") require.NotEqual(t, 0, randomness.Uint64(), "Randomness Fulfillment retrieved from Consumer contract give an answer other than 0") @@ -161,7 +161,7 @@ func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environ cd := chainlink.New(0, map[string]interface{}{ "replicas": 6, - "toml": client.AddNetworkDetailedConfig( + "toml": networks.AddNetworkDetailedConfig( config.BaseOCR2Config, config.DefaultOCR2VRFNetworkDetailTomlConfig, testNetwork, diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index a078b8ca41..9ed692700a 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -7,10 +7,9 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" - + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCRBasic(t *testing.T) { @@ -46,7 +45,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) - answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) @@ -55,7 +54,7 @@ func TestOCRBasic(t *testing.T) { err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } @@ -93,7 +92,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) - answer, err := ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) @@ -102,7 +101,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Error getting latest OCR answer") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) @@ -119,7 +118,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) - answer, err = ocrInstances[0].GetLatestAnswer(utils.TestContext(t)) + answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index 20389da378..e2cd28b332 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -12,10 +12,10 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestRunLogBasic(t *testing.T) { @@ -87,7 +87,7 @@ func TestRunLogBasic(t *testing.T) { gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(utils.TestContext(t)) + d, err := consumer.Data(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") l.Debug().Int64("Data", d.Int64()).Msg("Found on chain") diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index e477d45926..9c24d97b13 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -11,12 +11,12 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv1" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestVRFBasic(t *testing.T) { @@ -81,7 +81,7 @@ func TestVRFBasic(t *testing.T) { encodedProvingKeys := make([][2]*big.Int, 0) encodedProvingKeys = append(encodedProvingKeys, provingKey) - requestHash, err := contracts.Coordinator.HashOfKey(utils.TestContext(t), encodedProvingKeys[0]) + requestHash, err := contracts.Coordinator.HashOfKey(testcontext.Get(t), encodedProvingKeys[0]) require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") err = contracts.Consumer.RequestRandomness(requestHash, big.NewInt(1)) require.NoError(t, err, "Requesting randomness shouldn't fail") @@ -92,7 +92,7 @@ func TestVRFBasic(t *testing.T) { jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - out, err := contracts.Consumer.RandomnessOutput(utils.TestContext(t)) + out, err := contracts.Consumer.RandomnessOutput(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") // Checks that the job has actually run g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), @@ -170,7 +170,7 @@ func TestVRFJobReplacement(t *testing.T) { encodedProvingKeys := make([][2]*big.Int, 0) encodedProvingKeys = append(encodedProvingKeys, provingKey) - requestHash, err := contracts.Coordinator.HashOfKey(utils.TestContext(t), encodedProvingKeys[0]) + requestHash, err := contracts.Coordinator.HashOfKey(testcontext.Get(t), encodedProvingKeys[0]) require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") err = contracts.Consumer.RequestRandomness(requestHash, big.NewInt(1)) require.NoError(t, err, "Requesting randomness shouldn't fail") @@ -181,7 +181,7 @@ func TestVRFJobReplacement(t *testing.T) { jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - out, err := contracts.Consumer.RandomnessOutput(utils.TestContext(t)) + out, err := contracts.Consumer.RandomnessOutput(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") // Checks that the job has actually run g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), @@ -208,7 +208,7 @@ func TestVRFJobReplacement(t *testing.T) { jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - out, err := contracts.Consumer.RandomnessOutput(utils.TestContext(t)) + out, err := contracts.Consumer.RandomnessOutput(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") // Checks that the job has actually run g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 714ed752a3..09024b28ba 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -9,13 +9,13 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestVRFv2Basic(t *testing.T) { @@ -97,11 +97,11 @@ func TestVRFv2Basic(t *testing.T) { jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfV2jobs[0].Job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred()) g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically("==", 1)) - lastRequestID, err = vrfv2Contracts.LoadTestConsumer.GetLastRequestId(utils.TestContext(t)) + lastRequestID, err = vrfv2Contracts.LoadTestConsumer.GetLastRequestId(testcontext.Get(t)) l.Debug().Interface("Last Request ID", lastRequestID).Msg("Last Request ID Received") g.Expect(err).ShouldNot(gomega.HaveOccurred()) - status, err := vrfv2Contracts.LoadTestConsumer.GetRequestStatus(utils.TestContext(t), lastRequestID) + status, err := vrfv2Contracts.LoadTestConsumer.GetRequestStatus(testcontext.Get(t), lastRequestID) g.Expect(err).ShouldNot(gomega.HaveOccurred()) g.Expect(status.Fulfilled).Should(gomega.BeTrue()) l.Debug().Interface("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index cfeca0a66a..b171ea65f9 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -6,19 +6,19 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink/integration-tests/utils" - "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestVRFv2Plus(t *testing.T) { @@ -54,7 +54,7 @@ func TestVRFv2Plus(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) @@ -82,7 +82,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) + subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) @@ -91,7 +91,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) + status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -124,7 +124,7 @@ func TestVRFv2Plus(t *testing.T) { ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceWei := new(big.Int).Sub(subNativeTokenBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) + subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err) subBalanceAfterRequest := subscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) @@ -133,7 +133,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) + status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -161,10 +161,10 @@ func TestVRFv2Plus(t *testing.T) { testConfig := vrfv2PlusConfig var isNativeBilling = false - wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(utils.TestContext(t), wrapperContracts.LoadTestConsumers[0].Address()) + wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.Balance @@ -181,18 +181,18 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, consumerStatus.Fulfilled) expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) - wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(utils.TestContext(t), wrapperContracts.LoadTestConsumers[0].Address()) + wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) require.NoError(t, err, "error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) @@ -210,10 +210,10 @@ func TestVRFv2Plus(t *testing.T) { testConfig := vrfv2PlusConfig var isNativeBilling = true - wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.NativeBalance @@ -230,18 +230,18 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), wrapperSubID) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(utils.TestContext(t), randomWordsFulfilledEvent.RequestId) + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, consumerStatus.Fulfilled) expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) - wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) require.NoError(t, err, "error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) @@ -272,13 +272,13 @@ func TestVRFv2Plus(t *testing.T) { testWalletAddress, err := actions.GenerateWallet() require.NoError(t, err) - testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), testWalletAddress) + testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), testWalletAddress) require.NoError(t, err) - testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), testWalletAddress.String()) + testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) - subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -317,14 +317,14 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - testWalletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), testWalletAddress) + testWalletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), testWalletAddress) require.NoError(t, err) - testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), testWalletAddress.String()) + testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedNativeActual := new(big.Int).Sub(testWalletBalanceNativeAfterSubCancelling, testWalletBalanceNativeBeforeSubCancelling) @@ -366,17 +366,17 @@ func TestVRFv2Plus(t *testing.T) { subIDForCancelling := subIDsForCancelling[0] - subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2PlusContracts.Coordinator) - activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) + activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err) - require.True(t, utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subIDForCancelling)) + require.True(t, it_utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subIDForCancelling)) - pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(utils.TestContext(t), subIDForCancelling) + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) require.NoError(t, err) require.False(t, pendingRequestsExist, "Pending requests should not exist") @@ -408,17 +408,17 @@ func TestVRFv2Plus(t *testing.T) { require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") - pendingRequestsExist, err = vrfv2PlusContracts.Coordinator.PendingRequestsExist(utils.TestContext(t), subIDForCancelling) + pendingRequestsExist, err = vrfv2PlusContracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfulfilled rand requests due to low sub balance") - walletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) + walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) - subscriptionForCancelling, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) + subscriptionForCancelling, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -457,14 +457,14 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - walletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) + walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subIDForCancelling) + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) fmt.Println("err", err) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") @@ -493,12 +493,12 @@ func TestVRFv2Plus(t *testing.T) { //require.Equal(t, subFundsReturnedNativeExpected, subFundsReturnedNativeActual, "Returned funds are not equal to sub balance that was cancelled") require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") - activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) + activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error getting active subscription ids") require.False( t, - utils.BigIntSliceContains(activeSubscriptionIdsAfterSubCancellation, subIDForCancelling), + it_utils.BigIntSliceContains(activeSubscriptionIdsAfterSubCancellation, subIDForCancelling), "Active subscription ids should not contain sub id after sub cancellation", ) }) @@ -542,10 +542,10 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) amountToWithdrawLink := fulfilledEventLink.Payment - defaultWalletBalanceNativeBeforeOracleWithdraw, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeBeforeOracleWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) + defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) l.Info(). @@ -574,10 +574,10 @@ func TestVRFv2Plus(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) - defaultWalletBalanceNativeAfterOracleWithdraw, err := env.EVMClient.BalanceAt(utils.TestContext(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeAfterOracleWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(utils.TestContext(t), defaultWalletAddress) + defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) //not possible to verify exact amount of Native/LINK returned as defaultWallet is used in other tests in parallel which might affect the balance @@ -617,17 +617,17 @@ func TestVRFv2PlusMigration(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) - activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) + activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") require.Len(t, activeSubIdsOldCoordinatorBeforeMigration, 1, "Active Sub Ids length is not equal to 1") require.Equal(t, subID, activeSubIdsOldCoordinatorBeforeMigration[0]) - oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) + oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") //Migration Process @@ -698,14 +698,14 @@ func TestVRFv2PlusMigration(t *testing.T) { migratedCoordinatorLinkTotalBalanceAfterMigration, migratedCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) require.NoError(t, err) - migratedSubscription, err := newCoordinator.GetSubscription(utils.TestContext(t), subID) + migratedSubscription, err := newCoordinator.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") vrfv2plus.LogSubDetailsAfterMigration(l, newCoordinator, subID, migratedSubscription) //Verify that Coordinators were updated in Consumers for _, consumer := range vrfv2PlusContracts.LoadTestConsumers { - coordinatorAddressInConsumerAfterMigration, err := consumer.GetCoordinator(utils.TestContext(t)) + coordinatorAddressInConsumerAfterMigration, err := consumer.GetCoordinator(testcontext.Get(t)) require.NoError(t, err, "error getting Coordinator from Consumer contract") require.Equal(t, newCoordinator.Address(), coordinatorAddressInConsumerAfterMigration.String()) l.Debug(). @@ -721,13 +721,13 @@ func TestVRFv2PlusMigration(t *testing.T) { require.Equal(t, oldSubscriptionBeforeMigration.Consumers, migratedSubscription.Consumers) //Verify that old sub was deleted from old Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(utils.TestContext(t), subID) + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") - _, err = vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) + _, err = vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.Error(t, err, "error not occurred getting active sub ids. Should occur since it should revert when sub id array is empty") - activeSubIdsMigratedCoordinator, err := newCoordinator.GetActiveSubscriptionIds(utils.TestContext(t), big.NewInt(0), big.NewInt(0)) + activeSubIdsMigratedCoordinator, err := newCoordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") require.Len(t, activeSubIdsMigratedCoordinator, 1, "Active Sub Ids length is not equal to 1 for Migrated Coordinator after migration") require.Equal(t, subID, activeSubIdsMigratedCoordinator[0]) diff --git a/integration-tests/soak/forwarder_ocr_test.go b/integration-tests/soak/forwarder_ocr_test.go index bc02f36789..538f5ff156 100644 --- a/integration-tests/soak/forwarder_ocr_test.go +++ b/integration-tests/soak/forwarder_ocr_test.go @@ -18,7 +18,7 @@ func TestForwarderOCRSoak(t *testing.T) { ForwardersEnabled = true` // Uncomment below for debugging TOML issues on the node // fmt.Println("Using Chainlink TOML\n---------------------") - // fmt.Println(client.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) + // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) // fmt.Println("---------------------") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, true) diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index 9973c23808..c7d4bc80f6 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -18,7 +18,7 @@ func TestOCRSoak(t *testing.T) { // Uncomment below for debugging TOML issues on the node // network := networks.MustGetSelectedNetworksFromEnv()[0] // fmt.Println("Using Chainlink TOML\n---------------------") - // fmt.Println(client.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) + // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) // fmt.Println("---------------------") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, false) diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index d9b389a965..575ed3e7de 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" @@ -37,7 +38,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) // KeeperBenchmarkTest builds a test to check that chainlink nodes are able to upkeep a specified amount of Upkeep @@ -230,7 +230,7 @@ func (k *KeeperBenchmarkTest) Run() { "NumberOfRegistries": len(k.keeperRegistries), } inputs := k.Inputs - startingBlock, err := k.chainClient.LatestBlockNumber(utils.TestContext(k.t)) + startingBlock, err := k.chainClient.LatestBlockNumber(testcontext.Get(k.t)) require.NoError(k.t, err, "Error getting latest block number") k.startingBlock = big.NewInt(0).SetUint64(startingBlock) startTime := time.Now() @@ -319,7 +319,7 @@ func (k *KeeperBenchmarkTest) Run() { // This RPC call can possibly time out or otherwise die. Failure is not an option, keep retrying to get our stats. err = fmt.Errorf("initial error") // to ensure our for loop runs at least once for err != nil { - ctx, cancel := context.WithTimeout(utils.TestContext(k.t), timeout) + ctx, cancel := context.WithTimeout(testcontext.Get(k.t), timeout) logs, err = k.chainClient.FilterLogs(ctx, filterQuery) cancel() if err != nil { @@ -430,7 +430,7 @@ func (k *KeeperBenchmarkTest) observeUpkeepEvents() { FromBlock: k.startingBlock, } - ctx, cancel := context.WithTimeout(utils.TestContext(k.t), 5*time.Second) + ctx, cancel := context.WithTimeout(testcontext.Get(k.t), 5*time.Second) sub, err := k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) cancel() require.NoError(k.t, err, "Subscribing to upkeep performed events log shouldn't fail") @@ -453,7 +453,7 @@ func (k *KeeperBenchmarkTest) observeUpkeepEvents() { Str("Backoff", backoff.String()). Msg("Error while subscribing to Keeper Event Logs. Resubscribing...") - ctx, cancel := context.WithTimeout(utils.TestContext(k.t), backoff) + ctx, cancel := context.WithTimeout(testcontext.Get(k.t), backoff) sub, err = k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) cancel() if err != nil { diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 3fb9dd9844..dfeb4bb916 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -36,13 +36,13 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) const ( @@ -142,7 +142,7 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { cd := chainlink.New(0, map[string]any{ "replicas": 6, - "toml": client.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customChainlinkNetworkTOML, network), + "toml": networks.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customChainlinkNetworkTOML, network), "db": map[string]any{ "stateful": true, // stateful DB by default for soak tests }, @@ -258,7 +258,7 @@ func (o *OCRSoakTest) Setup() { // Run starts the OCR soak test func (o *OCRSoakTest) Run() { - ctx, cancel := context.WithTimeout(utils.TestContext(o.t), time.Second*5) + ctx, cancel := context.WithTimeout(testcontext.Get(o.t), time.Second*5) latestBlockNum, err := o.chainClient.LatestBlockNumber(ctx) cancel() require.NoError(o.t, err, "Error getting current block number") @@ -559,7 +559,7 @@ func (o *OCRSoakTest) setFilterQuery() { // WARNING: Should only be used for observation and logging. This is not a reliable way to collect events. func (o *OCRSoakTest) observeOCREvents() error { eventLogs := make(chan types.Log) - ctx, cancel := context.WithTimeout(utils.TestContext(o.t), 5*time.Second) + ctx, cancel := context.WithTimeout(testcontext.Get(o.t), 5*time.Second) eventSub, err := o.chainClient.SubscribeFilterLogs(ctx, o.filterQuery, eventLogs) cancel() if err != nil { @@ -593,7 +593,7 @@ func (o *OCRSoakTest) observeOCREvents() error { Str("Backoff", backoff.String()). Interface("Query", o.filterQuery). Msg("Error while subscribed to OCR Logs. Resubscribing") - ctx, cancel = context.WithTimeout(utils.TestContext(o.t), backoff) + ctx, cancel = context.WithTimeout(testcontext.Get(o.t), backoff) eventSub, err = o.chainClient.SubscribeFilterLogs(ctx, o.filterQuery, eventLogs) cancel() if err != nil { @@ -646,12 +646,12 @@ func (o *OCRSoakTest) collectEvents() error { timeout := time.Second * 15 o.log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") - ctx, cancel := context.WithTimeout(utils.TestContext(o.t), timeout) + ctx, cancel := context.WithTimeout(testcontext.Get(o.t), timeout) contractEvents, err := o.chainClient.FilterLogs(ctx, o.filterQuery) cancel() for err != nil { o.log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") - ctx, cancel := context.WithTimeout(utils.TestContext(o.t), timeout) + ctx, cancel := context.WithTimeout(testcontext.Get(o.t), timeout) contractEvents, err = o.chainClient.FilterLogs(ctx, o.filterQuery) cancel() if err != nil { diff --git a/integration-tests/testsetups/vrfv2.go b/integration-tests/testsetups/vrfv2.go index 8c5fde7216..ef18bd267d 100644 --- a/integration-tests/testsetups/vrfv2.go +++ b/integration-tests/testsetups/vrfv2.go @@ -18,11 +18,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/utils" ) // VRFV2SoakTest defines a typical VRFV2 soak test @@ -88,7 +88,7 @@ func (v *VRFV2SoakTest) Run(t *testing.T) { Msg("Starting VRFV2 Soak Test") // set the requests to only run for a certain amount of time - ctx := utils.TestContext(t) + ctx := testcontext.Get(t) testContext, testCancel := context.WithTimeout(ctx, v.Inputs.TestDuration) defer testCancel() diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index e044d1ba32..6da1d94371 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -13,6 +13,7 @@ import ( relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/toml" @@ -23,42 +24,42 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils/config" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" - utils2 "github.com/smartcontractkit/chainlink/integration-tests/utils" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func NewBaseConfig() *chainlink.Config { return &chainlink.Config{ Core: toml.Core{ - RootDir: utils2.Ptr("/home/chainlink"), + RootDir: ptr.Ptr("/home/chainlink"), Database: toml.Database{ - MaxIdleConns: utils2.Ptr(int64(20)), - MaxOpenConns: utils2.Ptr(int64(40)), - MigrateOnStartup: utils2.Ptr(true), + MaxIdleConns: ptr.Ptr(int64(20)), + MaxOpenConns: ptr.Ptr(int64(40)), + MigrateOnStartup: ptr.Ptr(true), }, Log: toml.Log{ - Level: utils2.Ptr(toml.LogLevel(zapcore.DebugLevel)), - JSONConsole: utils2.Ptr(true), + Level: ptr.Ptr(toml.LogLevel(zapcore.DebugLevel)), + JSONConsole: ptr.Ptr(true), File: toml.LogFile{ - MaxSize: utils2.Ptr(utils.FileSize(0)), + MaxSize: ptr.Ptr(utils.FileSize(0)), }, }, WebServer: toml.WebServer{ - AllowOrigins: utils2.Ptr("*"), - HTTPPort: utils2.Ptr[uint16](6688), - SecureCookies: utils2.Ptr(false), + AllowOrigins: ptr.Ptr("*"), + HTTPPort: ptr.Ptr[uint16](6688), + SecureCookies: ptr.Ptr(false), SessionTimeout: models.MustNewDuration(time.Hour * 999), TLS: toml.WebServerTLS{ - HTTPSPort: utils2.Ptr[uint16](0), + HTTPSPort: ptr.Ptr[uint16](0), }, RateLimit: toml.WebServerRateLimit{ - Authenticated: utils2.Ptr(int64(2000)), - Unauthenticated: utils2.Ptr(int64(100)), + Authenticated: ptr.Ptr(int64(2000)), + Unauthenticated: ptr.Ptr(int64(100)), }, }, Feature: toml.Feature{ - LogPoller: utils2.Ptr(true), - FeedsManager: utils2.Ptr(true), - UICSAKeys: utils2.Ptr(true), + LogPoller: ptr.Ptr(true), + FeedsManager: ptr.Ptr(true), + UICSAKeys: ptr.Ptr(true), }, P2P: toml.P2P{}, }, @@ -96,7 +97,7 @@ func NewConfigFromToml(tomlFile string, opts ...NodeConfigOpt) (*chainlink.Confi func WithOCR1() NodeConfigOpt { return func(c *chainlink.Config) { c.OCR = toml.OCR{ - Enabled: utils2.Ptr(true), + Enabled: ptr.Ptr(true), } } } @@ -104,7 +105,7 @@ func WithOCR1() NodeConfigOpt { func WithOCR2() NodeConfigOpt { return func(c *chainlink.Config) { c.OCR2 = toml.OCR2{ - Enabled: utils2.Ptr(true), + Enabled: ptr.Ptr(true), } } } @@ -114,12 +115,12 @@ func WithOCR2() NodeConfigOpt { func WithP2Pv1() NodeConfigOpt { return func(c *chainlink.Config) { c.P2P.V1 = toml.P2PV1{ - Enabled: utils2.Ptr(true), - ListenIP: utils2.MustIP("0.0.0.0"), - ListenPort: utils2.Ptr[uint16](6690), + Enabled: ptr.Ptr(true), + ListenIP: it_utils.MustIP("0.0.0.0"), + ListenPort: ptr.Ptr[uint16](6690), } // disabled default - c.P2P.V2 = toml.P2PV2{Enabled: utils2.Ptr(false)} + c.P2P.V2 = toml.P2PV2{Enabled: ptr.Ptr(false)} } } @@ -134,14 +135,14 @@ func WithP2Pv2() NodeConfigOpt { func WithTracing() NodeConfigOpt { return func(c *chainlink.Config) { c.Tracing = toml.Tracing{ - Enabled: utils2.Ptr(true), - CollectorTarget: utils2.Ptr("otel-collector:4317"), + Enabled: ptr.Ptr(true), + CollectorTarget: ptr.Ptr("otel-collector:4317"), // ksortable unique id - NodeID: utils2.Ptr(ksuid.New().String()), + NodeID: ptr.Ptr(ksuid.New().String()), Attributes: map[string]string{ "env": "smoke", }, - SamplingRatio: utils2.Ptr(1.0), + SamplingRatio: ptr.Ptr(1.0), } } } @@ -157,10 +158,10 @@ func SetChainConfig( var nodes []*evmcfg.Node for i := range wsUrls { node := evmcfg.Node{ - Name: utils2.Ptr(fmt.Sprintf("node_%d_%s", i, chain.Name)), - WSURL: utils2.MustURL(wsUrls[i]), - HTTPURL: utils2.MustURL(httpUrls[i]), - SendOnly: utils2.Ptr(false), + Name: ptr.Ptr(fmt.Sprintf("node_%d_%s", i, chain.Name)), + WSURL: it_utils.MustURL(wsUrls[i]), + HTTPURL: it_utils.MustURL(httpUrls[i]), + SendOnly: ptr.Ptr(false), } nodes = append(nodes, &node) @@ -168,8 +169,8 @@ func SetChainConfig( var chainConfig evmcfg.Chain if chain.Simulated { chainConfig = evmcfg.Chain{ - AutoCreateKey: utils2.Ptr(true), - FinalityDepth: utils2.Ptr[uint32](1), + AutoCreateKey: ptr.Ptr(true), + FinalityDepth: ptr.Ptr[uint32](1), MinContractPayment: relayassets.NewLinkFromJuels(0), } } @@ -182,7 +183,7 @@ func SetChainConfig( } if forwarders { cfg.EVM[0].Transactions = evmcfg.Transactions{ - ForwardersEnabled: utils2.Ptr(true), + ForwardersEnabled: ptr.Ptr(true), } } } @@ -194,25 +195,25 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { evmConfigs = append(evmConfigs, &evmcfg.EVMConfig{ ChainID: utils.NewBig(big.NewInt(network.ChainID)), Chain: evmcfg.Chain{ - AutoCreateKey: utils2.Ptr(true), - FinalityDepth: utils2.Ptr[uint32](50), + AutoCreateKey: ptr.Ptr(true), + FinalityDepth: ptr.Ptr[uint32](50), MinContractPayment: relayassets.NewLinkFromJuels(0), LogPollInterval: models.MustNewDuration(1 * time.Second), HeadTracker: evmcfg.HeadTracker{ - HistoryDepth: utils2.Ptr(uint32(100)), + HistoryDepth: ptr.Ptr(uint32(100)), }, GasEstimator: evmcfg.GasEstimator{ - LimitDefault: utils2.Ptr(uint32(6000000)), + LimitDefault: ptr.Ptr(uint32(6000000)), PriceMax: assets.GWei(200), FeeCapDefault: assets.GWei(200), }, }, Nodes: []*evmcfg.Node{ { - Name: utils2.Ptr(network.Name), - WSURL: utils2.MustURL(network.URLs[0]), - HTTPURL: utils2.MustURL(network.HTTPURLs[0]), - SendOnly: utils2.Ptr(false), + Name: ptr.Ptr(network.Name), + WSURL: it_utils.MustURL(network.URLs[0]), + HTTPURL: it_utils.MustURL(network.HTTPURLs[0]), + SendOnly: ptr.Ptr(false), }, }, }) @@ -227,17 +228,17 @@ func WithVRFv2EVMEstimator(addr string) NodeConfigOpt { return func(c *chainlink.Config) { c.EVM[0].KeySpecific = evmcfg.KeySpecificConfig{ { - Key: utils2.Ptr(ethkey.EIP55Address(addr)), + Key: ptr.Ptr(ethkey.EIP55Address(addr)), GasEstimator: evmcfg.KeySpecificGasEstimator{ PriceMax: est, }, }, } c.EVM[0].Chain.GasEstimator = evmcfg.GasEstimator{ - LimitDefault: utils2.Ptr[uint32](3500000), + LimitDefault: ptr.Ptr[uint32](3500000), } c.EVM[0].Chain.Transactions = evmcfg.Transactions{ - MaxQueued: utils2.Ptr[uint32](10000), + MaxQueued: ptr.Ptr[uint32](10000), } } } diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 505337f032..7bf1657316 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -27,6 +27,7 @@ import ( ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -42,7 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ( @@ -1010,12 +1010,12 @@ func setupLogPollerTestDocker( // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) syncInterval := models.MustMakeDuration(5 * time.Minute) - clNodeConfig.Feature.LogPoller = it_utils.Ptr[bool](true) - clNodeConfig.OCR2.Enabled = it_utils.Ptr[bool](true) - clNodeConfig.Keeper.TurnLookBack = it_utils.Ptr[int64](int64(0)) + clNodeConfig.Feature.LogPoller = ptr.Ptr[bool](true) + clNodeConfig.OCR2.Enabled = ptr.Ptr[bool](true) + clNodeConfig.Keeper.TurnLookBack = ptr.Ptr[int64](int64(0)) clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval - clNodeConfig.Keeper.Registry.PerformGasOverhead = it_utils.Ptr[uint32](uint32(150000)) - clNodeConfig.P2P.V2.Enabled = it_utils.Ptr[bool](true) + clNodeConfig.Keeper.Registry.PerformGasOverhead = ptr.Ptr[uint32](uint32(150000)) + clNodeConfig.P2P.V2.Enabled = ptr.Ptr[bool](true) clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} @@ -1027,8 +1027,8 @@ func setupLogPollerTestDocker( var logPolllerSettingsFn = func(chain *evmcfg.Chain) *evmcfg.Chain { chain.LogPollInterval = models.MustNewDuration(lpPollingInterval) - chain.FinalityDepth = it_utils.Ptr[uint32](uint32(finalityDepth)) - chain.FinalityTagEnabled = it_utils.Ptr[bool](finalityTagEnabled) + chain.FinalityDepth = ptr.Ptr[uint32](uint32(finalityDepth)) + chain.FinalityTagEnabled = ptr.Ptr[bool](finalityTagEnabled) return chain } diff --git a/integration-tests/universal/log_poller/scenarios.go b/integration-tests/universal/log_poller/scenarios.go index 886547d46e..5331c63f75 100644 --- a/integration-tests/universal/log_poller/scenarios.go +++ b/integration-tests/universal/log_poller/scenarios.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/utils" core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -100,7 +100,7 @@ func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) + sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -122,7 +122,7 @@ func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) + eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) @@ -229,7 +229,7 @@ func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string time.Sleep(5 * time.Second) // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) + sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -243,7 +243,7 @@ func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) + eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) @@ -419,7 +419,7 @@ func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) + sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -441,7 +441,7 @@ func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(utils.TestContext(t)) + eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go index f13c71cfd9..34a40e396d 100644 --- a/integration-tests/utils/common.go +++ b/integration-tests/utils/common.go @@ -1,16 +1,12 @@ package utils import ( - "context" "math/big" "net" - "testing" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) -func Ptr[T any](t T) *T { return &t } - func MustURL(s string) *models.URL { var u models.URL if err := u.UnmarshalText([]byte(s)); err != nil { @@ -35,24 +31,3 @@ func BigIntSliceContains(slice []*big.Int, b *big.Int) bool { } return false } - -// TestContext returns a context with the test's deadline, if available. -func TestContext(tb testing.TB) context.Context { - ctx := context.Background() - var cancel func() - switch t := tb.(type) { - case *testing.T: - // Return background context if testing.T not set - if t == nil { - return ctx - } - if d, ok := t.Deadline(); ok { - ctx, cancel = context.WithDeadline(ctx, d) - } - } - if cancel == nil { - ctx, cancel = context.WithCancel(ctx) - } - tb.Cleanup(cancel) - return ctx -} From 4eb170b51d67be85b950efa0aa8e5daad3bed00d Mon Sep 17 00:00:00 2001 From: Sergey Kudasov Date: Fri, 17 Nov 2023 02:54:02 +0300 Subject: [PATCH 167/327] Devspace update + Cluster dashboard (#11222) * fix chainlink config * init dashboard * bump CTF * move dashboard rows * dashboard * comments * exclude dashboard from SonarQube * common dashboard * extend opts * rg filter --- charts/chainlink-cluster/README.md | 21 +- .../dashboard/cmd/dashboard_deploy.go | 42 ++ .../chainlink-cluster/dashboard/dashboard.go | 392 ++++++++++++++++++ charts/chainlink-cluster/devspace.yaml | 2 + charts/chainlink-cluster/go.mod | 15 + charts/chainlink-cluster/go.sum | 20 + .../templates/chainlink-cm.yaml | 5 +- .../templates/chainlink-deployment.yaml | 2 + .../templates/chainlink-pod-monitor.yaml | 16 +- sonar-project.properties | 2 +- 10 files changed, 505 insertions(+), 12 deletions(-) create mode 100644 charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go create mode 100644 charts/chainlink-cluster/dashboard/dashboard.go create mode 100644 charts/chainlink-cluster/go.mod create mode 100644 charts/chainlink-cluster/go.sum diff --git a/charts/chainlink-cluster/README.md b/charts/chainlink-cluster/README.md index f7d4c45fa5..46c337dc72 100644 --- a/charts/chainlink-cluster/README.md +++ b/charts/chainlink-cluster/README.md @@ -34,7 +34,7 @@ If you don't need a build use devspace deploy --skip-build ``` -Connect to your environment +Connect to your environment, by replacing container with label `node-1` with your local repository files ``` devspace dev -p node make chainlink @@ -117,4 +117,23 @@ helm test cl-cluster ## Uninstall ``` helm uninstall cl-cluster +``` + +# Grafana dashboard +We are using [Grabana]() lib to create dashboards programmatically +``` +export GRAFANA_URL=... +export GRAFANA_TOKEN=... +export LOKI_DATA_SOURCE_NAME=Loki +export PROMETHEUS_DATA_SOURCE_NAME=Thanos +export DASHBOARD_FOLDER=CLClusterEphemeralDevspace +export DASHBOARD_NAME=ChainlinkCluster + +cd dashboard/cmd && go run dashboard_deploy.go +``` +Open Grafana folder `CLClusterEphemeralDevspace` and find dashboard `ChainlinkCluster` + +If you'd like to add more metrics or verify that all of them are added you can have the full list using IDE search or `ripgrep`: +``` +rg -U ".*promauto.*\n.*Name: \"(.*)\"" ../.. > metrics.txt ``` \ No newline at end of file diff --git a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go new file mode 100644 index 0000000000..c752794f53 --- /dev/null +++ b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go @@ -0,0 +1,42 @@ +package main + +import ( + "os" + + "github.com/smartcontractkit/chainlink/v2/dashboard/dashboard" +) + +func main() { + name := os.Getenv("DASHBOARD_NAME") + if name == "" { + panic("DASHBOARD_NAME must be provided") + } + ldsn := os.Getenv("LOKI_DATA_SOURCE_NAME") + if ldsn == "" { + panic("DATA_SOURCE_NAME must be provided") + } + pdsn := os.Getenv("PROMETHEUS_DATA_SOURCE_NAME") + if ldsn == "" { + panic("DATA_SOURCE_NAME must be provided") + } + dbf := os.Getenv("DASHBOARD_FOLDER") + if dbf == "" { + panic("DASHBOARD_FOLDER must be provided") + } + grafanaURL := os.Getenv("GRAFANA_URL") + if grafanaURL == "" { + panic("GRAFANA_URL must be provided") + } + grafanaToken := os.Getenv("GRAFANA_TOKEN") + if grafanaToken == "" { + panic("GRAFANA_TOKEN must be provided") + } + // if you'll use this dashboard base in other projects, you can add your own opts here to extend it + db, err := dashboard.NewCLClusterDashboard(name, ldsn, pdsn, dbf, grafanaURL, grafanaToken, nil) + if err != nil { + panic(err) + } + if err := db.Deploy(); err != nil { + panic(err) + } +} diff --git a/charts/chainlink-cluster/dashboard/dashboard.go b/charts/chainlink-cluster/dashboard/dashboard.go new file mode 100644 index 0000000000..7918b996dd --- /dev/null +++ b/charts/chainlink-cluster/dashboard/dashboard.go @@ -0,0 +1,392 @@ +package dashboard + +import ( + "context" + "fmt" + "net/http" + + "github.com/K-Phoen/grabana" + "github.com/K-Phoen/grabana/dashboard" + "github.com/K-Phoen/grabana/logs" + "github.com/K-Phoen/grabana/row" + "github.com/K-Phoen/grabana/stat" + "github.com/K-Phoen/grabana/target/prometheus" + "github.com/K-Phoen/grabana/timeseries" + "github.com/K-Phoen/grabana/timeseries/axis" + "github.com/K-Phoen/grabana/variable/interval" + "github.com/K-Phoen/grabana/variable/query" + "github.com/pkg/errors" +) + +const ( + ErrFailedToCreateDashboard = "failed to create dashboard" + ErrFailedToCreateFolder = "failed to create folder" +) + +// CLClusterDashboard is a dashboard for a Chainlink cluster +type CLClusterDashboard struct { + Name string + LokiDataSourceName string + PrometheusDataSourceName string + Folder string + GrafanaURL string + GrafanaToken string + opts []dashboard.Option + extendedOpts []dashboard.Option + builder dashboard.Builder +} + +// NewCLClusterDashboard returns a new dashboard for a Chainlink cluster, can be used as a base for more complex plugin based dashboards +func NewCLClusterDashboard(name, ldsn, pdsn, dbf, grafanaURL, grafanaToken string, opts []dashboard.Option) (*CLClusterDashboard, error) { + db := &CLClusterDashboard{ + Name: name, + Folder: dbf, + LokiDataSourceName: ldsn, + PrometheusDataSourceName: pdsn, + GrafanaURL: grafanaURL, + GrafanaToken: grafanaToken, + extendedOpts: opts, + } + if err := db.generate(); err != nil { + return db, err + } + return db, nil +} + +func (m *CLClusterDashboard) Opts() []dashboard.Option { + return m.opts +} + +// logsRowOption returns a row option for a node's logs with name and instance selector +func (m *CLClusterDashboard) logsRowOption(name, instanceSelector string) row.Option { + return row.WithLogs( + name, + logs.DataSource(m.LokiDataSourceName), + logs.Span(12), + logs.Height("300px"), + logs.Transparent(), + logs.WithLokiTarget(fmt.Sprintf(` + {namespace="${namespace}", app="app", instance="%s", container="node"} + `, instanceSelector)), + ) +} + +// timeseriesRowOption returns a row option for a timeseries with name, axis unit, query and legend template +func (m *CLClusterDashboard) timeseriesRowOption(name, axisUnit, query, legendTemplate string) row.Option { + var tsq timeseries.Option + if legendTemplate != "" { + tsq = timeseries.WithPrometheusTarget( + query, + prometheus.Legend(legendTemplate), + ) + } else { + tsq = timeseries.WithPrometheusTarget(query) + } + var au timeseries.Option + if axisUnit != "" { + au = timeseries.Axis( + axis.Unit(axisUnit), + ) + } else { + au = timeseries.Axis() + } + return row.WithTimeSeries( + name, + timeseries.Span(6), + timeseries.Height("300px"), + timeseries.DataSource(m.PrometheusDataSourceName), + au, + tsq, + ) +} + +// statRowOption returns a row option for a stat with name, prometheus target and legend template +func (m *CLClusterDashboard) statRowOption(name, target, legend string) row.Option { + return row.WithStat( + name, + stat.Transparent(), + stat.DataSource(m.PrometheusDataSourceName), + stat.Text(stat.TextValueAndName), + stat.Orientation(stat.OrientationVertical), + stat.TitleFontSize(12), + stat.ValueFontSize(20), + stat.Span(12), + stat.Height("100px"), + stat.WithPrometheusTarget(target, prometheus.Legend(legend)), + ) +} + +// generate generates the dashboard, adding extendedOpts to the default options +func (m *CLClusterDashboard) generate() error { + opts := []dashboard.Option{ + dashboard.AutoRefresh("10s"), + dashboard.Tags([]string{"generated"}), + dashboard.VariableAsQuery( + "namespace", + query.DataSource(m.LokiDataSourceName), + query.Multiple(), + query.IncludeAll(), + query.Request(fmt.Sprintf("label_values(%s)", "namespace")), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsInterval( + "interval", + interval.Values([]string{"30s", "1m", "5m", "10m", "30m", "1h", "6h", "12h"}), + ), + dashboard.Row( + "Cluster health", + m.statRowOption( + "App Version", + `version{namespace="${namespace}"}`, + "{{pod}} - {{version}}", + ), + row.WithTimeSeries( + "Restarts", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(m.PrometheusDataSourceName), + timeseries.WithPrometheusTarget( + `sum(increase(kube_pod_container_status_restarts_total{namespace=~"${namespace}"}[5m])) by (pod)`, + prometheus.Legend("{{pod}}"), + ), + ), + row.WithTimeSeries( + "Service Components Health", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(m.PrometheusDataSourceName), + timeseries.WithPrometheusTarget( + `health{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - {{service_id}}"), + ), + ), + row.WithTimeSeries( + "Log Counters", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(m.PrometheusDataSourceName), + timeseries.WithPrometheusTarget( + `log_panic_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - panic"), + ), + timeseries.WithPrometheusTarget( + `log_fatal_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - fatal"), + ), + timeseries.WithPrometheusTarget( + `log_critical_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - critical"), + ), + timeseries.WithPrometheusTarget( + `log_error_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - error"), + ), + ), + row.WithTimeSeries( + "ETH Balance", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(m.PrometheusDataSourceName), + timeseries.WithPrometheusTarget( + `eth_balance{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - {{account}}"), + ), + ), + ), + // logs + dashboard.Row( + "Logs", + row.Collapse(), + m.logsRowOption("Node 1", "node-1"), + m.logsRowOption("Node 2", "node-2"), + m.logsRowOption("Node 3", "node-3"), + m.logsRowOption("Node 4", "node-4"), + ), + // DON report metrics + dashboard.Row("DON Report metrics", + row.Collapse(), + m.timeseriesRowOption( + "Plugin Query() count", + "Count", + `sum(rate(ocr2_reporting_plugin_query_count{namespace="${namespace}", app="app"}[$__rate_interval])) by (service)`, + "", + ), + m.timeseriesRowOption( + "Plugin Observation() time (95th)", + "Sec", + `histogram_quantile(0.95, sum(rate(ocr2_reporting_plugin_observation_time_bucket{namespace="${namespace}", app="app"}[$__rate_interval])) by (le, service)) / 1e9`, + "", + ), + m.timeseriesRowOption( + "Plugin ShouldAcceptReport() time (95th)", + "Sec", + `histogram_quantile(0.95, sum(rate(ocr2_reporting_plugin_should_accept_report_time_bucket{namespace="${namespace}", app="app"}[$__rate_interval])) by (le, service)) / 1e9`, + "", + ), + m.timeseriesRowOption( + "Plugin Report() time (95th)", + "Sec", + `histogram_quantile(0.95, sum(rate(ocr2_reporting_plugin_report_time_bucket{namespace="${namespace}", app="app"}[$__rate_interval])) by (le, service)) / 1e9`, + "", + ), + m.timeseriesRowOption( + "Plugin ShouldTransmitReport() time (95th)", + "Sec", + `histogram_quantile(0.95, sum(rate(ocr2_reporting_plugin_should_transmit_report_time_bucket{namespace="${namespace}", app="app"}[$__rate_interval])) by (le, service)) / 1e9`, + "", + ), + ), + dashboard.Row( + "DB Connection Metrics (App)", + row.Collapse(), + m.timeseriesRowOption( + "DB Connections MAX", + "Conn", + `db_conns_max{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "DB Connections Open", + "Conn", + `db_conns_open{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "DB Connections Used", + "Conn", + `db_conns_used{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "DB Connections Wait", + "Conn", + `db_conns_wait{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "DB Wait time", + "Sec", + `db_wait_time_seconds{namespace="${namespace}"}`, + "{{pod}}", + ), + ), + dashboard.Row( + "EVM Pool RPC Node Metrics (App)", + row.Collapse(), + m.timeseriesRowOption( + "EVM Pool RPC Node Calls Success", + "", + `evm_pool_rpc_node_calls_success{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node Calls Total", + "", + `evm_pool_rpc_node_calls_total{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node Dials Success", + "", + `evm_pool_rpc_node_dials_success{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node Dials Total", + "", + `evm_pool_rpc_node_dials_total{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Highest Seen Block", + "", + `evm_pool_rpc_node_highest_seen_block{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Total Transitions to Alive", + "", + `evm_pool_rpc_node_num_transitions_to_alive{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node Polls Success", + "", + `evm_pool_rpc_node_polls_success{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node Polls Total", + "", + `evm_pool_rpc_node_polls_total{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node States", + "", + `evm_pool_rpc_node_states{namespace="${namespace}"}`, + "{{pod}} - {{evmChainID}} - {{state}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node Verifies Total", + "", + `evm_pool_rpc_node_verifies{namespace="${namespace}"}`, + "{{pod}} - {{evmChainID}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Node Verifies Success", + "", + `evm_pool_rpc_node_verifies_success{namespace="${namespace}"}`, + "{{pod}} - {{evmChainID}}", + ), + ), + dashboard.Row( + "EVM Pool RPC Node Latencies (App)", + row.Collapse(), + m.timeseriesRowOption( + "EVM Pool RPC Node Calls Latency 0.95 quantile", + "ms", + `histogram_quantile(0.95, sum(rate(evm_pool_rpc_node_rpc_call_time_bucket{namespace="${namespace}"}[$__rate_interval])) by (le, rpcCallName)) / 1e6`, + "{{pod}}", + ), + ), + dashboard.Row( + "Pipeline Tasks Metrics (App)", + row.Collapse(), + m.timeseriesRowOption( + "Pipeline Runs Queued", + "", + `pipeline_runs_queued{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "Pipeline Runs Tasks Queued", + "", + `pipeline_task_runs_queued{namespace="${namespace}"}`, + "{{pod}}", + ), + ), + } + opts = append(opts, m.extendedOpts...) + builder, err := dashboard.New( + "Chainlink Cluster Dashboard", + opts..., + ) + m.opts = opts + m.builder = builder + return err +} + +// Deploy deploys the dashboard to Grafana +func (m *CLClusterDashboard) Deploy() error { + ctx := context.Background() + client := grabana.NewClient(&http.Client{}, m.GrafanaURL, grabana.WithAPIToken(m.GrafanaToken)) + folder, err := client.FindOrCreateFolder(ctx, m.Folder) + if err != nil { + return errors.Wrap(err, ErrFailedToCreateFolder) + } + if _, err := client.UpsertDashboard(ctx, folder, m.builder); err != nil { + return errors.Wrap(err, ErrFailedToCreateDashboard) + } + return nil +} diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index 54b5f9f01e..688660d918 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -32,6 +32,7 @@ images: deployments: app: helm: + releaseName: "app" chart: name: cl-cluster path: . @@ -68,6 +69,7 @@ deployments: - name: node-4 image: ${DEVSPACE_IMAGE} version: latest + prometheusMonitor: "true" podAnnotations: { } nodeSelector: { } tolerations: [ ] diff --git a/charts/chainlink-cluster/go.mod b/charts/chainlink-cluster/go.mod new file mode 100644 index 0000000000..990ebbf713 --- /dev/null +++ b/charts/chainlink-cluster/go.mod @@ -0,0 +1,15 @@ +module github.com/smartcontractkit/chainlink/v2/dashboard + +go 1.21 + +require ( + github.com/K-Phoen/grabana v0.21.19 + github.com/pkg/errors v0.9.1 +) + +require ( + github.com/K-Phoen/sdk v0.12.3 // indirect + github.com/gosimple/slug v1.13.1 // indirect + github.com/gosimple/unidecode v1.0.1 // indirect + github.com/prometheus/common v0.39.0 // indirect +) diff --git a/charts/chainlink-cluster/go.sum b/charts/chainlink-cluster/go.sum new file mode 100644 index 0000000000..093a42d608 --- /dev/null +++ b/charts/chainlink-cluster/go.sum @@ -0,0 +1,20 @@ +github.com/K-Phoen/grabana v0.21.19 h1:tJjRO8nN9JrFjLoQGtOB9P5ILoqENZZGAtt3nK+Ry2Y= +github.com/K-Phoen/grabana v0.21.19/go.mod h1:B7gxVxacQUgHWmgqduf4WPZoKYHO1mvZnRVCoyQiwdw= +github.com/K-Phoen/sdk v0.12.3 h1:ScutEQASc9VEKJCm3OjIMD82BIS9B2XtNg3gEf6Gs+M= +github.com/K-Phoen/sdk v0.12.3/go.mod h1:qmM0wO23CtoDux528MXPpYvS4XkRWkWX6rvX9Za8EVU= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= +github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= +github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= +github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/charts/chainlink-cluster/templates/chainlink-cm.yaml b/charts/chainlink-cluster/templates/chainlink-cm.yaml index fa9c2c2657..736a332204 100644 --- a/charts/chainlink-cluster/templates/chainlink-cm.yaml +++ b/charts/chainlink-cluster/templates/chainlink-cm.yaml @@ -29,10 +29,9 @@ data: [OCR] Enabled = true [P2P] - [P2P.V1] + [P2P.V2] Enabled = true - ListenIP = '0.0.0.0' - ListenPort = 6690 + ListenAddresses = ["0.0.0.0:6690"] [[EVM]] ChainID = '1337' MinContractPayment = '0' diff --git a/charts/chainlink-cluster/templates/chainlink-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-deployment.yaml index 16665916f5..b434c9894b 100644 --- a/charts/chainlink-cluster/templates/chainlink-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-deployment.yaml @@ -37,6 +37,8 @@ spec: {{- end }} annotations: prometheus.io/scrape: 'true' + app.kubernetes.io/managed-by: "Helm" + meta.helm.sh/release-namespace: "{{ $.Release.Namespace }}" {{- range $key, $value := $.Values.podAnnotations }} {{ $key }}: {{ $value | quote }} {{- end }} diff --git a/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml b/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml index 4a74ff6c45..2cd9c3df2b 100644 --- a/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml +++ b/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml @@ -1,16 +1,18 @@ -{{- range $cfg := .Values.chainlink.nodes }} {{- if $.Values.prometheusMonitor }} apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: + name: {{ $.Release.Name }}-pod-monitor labels: release: grafana-agent spec: - selector: - matchLabels: - release: {{ $.Release.Name }}-{{ $cfg.name }} + namespaceSelector: + matchNames: + - "cl-cluster" podMetricsEndpoints: - port: access - {{- end }} ---- -{{- end }} \ No newline at end of file + selector: + matchLabels: + app: {{ $.Release.Name }} +{{- end }} +--- \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties index ea142ce17f..c40b5f361e 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -12,4 +12,4 @@ sonar.cpd.exclusions=**/contracts/**/*.sol, **/config.go, /core/services/ocr2/pl # Tests' root folder, inclusions (tests to check and count) and exclusions sonar.tests=. sonar.test.inclusions=**/*_test.go, **/*.test.ts -sonar.test.exclusions=**/integration-tests/**/* +sonar.test.exclusions=**/integration-tests/**/*, **/charts/chainlink-cluster/dashboard/cmd/* From 55d4d9c88667065f56257a71c133d3b700690097 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Fri, 17 Nov 2023 09:10:37 +0400 Subject: [PATCH 168/327] [AUTO-7258] Setup log trigger load test using wasp (#11267) * add simple log upkeep counter contract * WIP- add automationv2_1 load test * update contract * working state * add config * try GHA * disable reads inside loadgen * updates * add specs * fix linkfunds * detach runner, add loglevel config * increase geth capacity * fix batching - test end FilterLogs * fix batching * fix log filter context and batching * increase upkeep funding, fix event count calc * increase GasLimitPerReport to 10.3M * Decrease PerformLockoutWindow to 80k * reduce sleep time - log filter batch * use ConcurrentEVMClients * increase RR CPU and Mem * add pyroscope, add slack notifications * add tag and image to test config * fix dashbord URL * contracts prettier * run lint * add new load test workflow * fix AddNetworksConfig * undo changes to benchmark test workflow * add load/automationv2_1 to build test image steps * lint --- .github/actions/build-test-image/action.yml | 2 +- .../workflows/automation-benchmark-tests.yml | 3 +- .github/workflows/automation-load-tests.yml | 105 +++ CODEOWNERS | 1 + .../native_solc_compile_all_automation | 1 + .../testhelpers/SimpleLogUpkeepCounter.sol | 45 ++ .../simple_log_upkeep_counter_wrapper.go | 504 ++++++++++++++ ...rapper-dependency-versions-do-not-edit.txt | 1 + core/gethwrappers/go_generate.go | 1 + .../contracts/contract_deployer.go | 21 + .../contracts/ethereum_keeper_contracts.go | 27 + .../automationv2_1/automationv2_1_test.go | 621 ++++++++++++++++++ integration-tests/load/automationv2_1/gun.go | 43 ++ .../load/automationv2_1/helpers.go | 71 ++ .../testreporters/keeper_benchmark.go | 6 +- 15 files changed, 1447 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/automation-load-tests.yml create mode 100644 contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol create mode 100644 core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go create mode 100644 integration-tests/load/automationv2_1/automationv2_1_test.go create mode 100644 integration-tests/load/automationv2_1/gun.go create mode 100644 integration-tests/load/automationv2_1/helpers.go diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index 252b292d03..4b1dce6ee1 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -15,7 +15,7 @@ inputs: required: false suites: description: The test suites to build into the image - default: chaos migration performance reorg smoke soak benchmark + default: chaos migration performance reorg smoke soak benchmark load/automationv2_1 required: false base_image_tag: description: The test base image version to use, if not provided it will use the version from the ./integration-tests/go.mod file diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index a4338d642b..0fff36f8df 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -6,7 +6,7 @@ on: description: Chainlink image version to use required: true type: string - default: 2.5.0 + default: 2.6.0 chainlinkImage: description: Chainlink image repo to use required: true @@ -108,6 +108,7 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + suites: benchmark load/automationv2_1 chaos reorg - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 env: diff --git a/.github/workflows/automation-load-tests.yml b/.github/workflows/automation-load-tests.yml new file mode 100644 index 0000000000..eebd87322c --- /dev/null +++ b/.github/workflows/automation-load-tests.yml @@ -0,0 +1,105 @@ +name: Automation Load Test +on: + workflow_dispatch: + inputs: + chainlinkVersion: + description: Chainlink image version to use + required: true + type: string + default: 2.6.0 + chainlinkImage: + description: Chainlink image repo to use + required: true + type: string + default: public.ecr.aws/chainlink/chainlink + network: + description: Network to run tests on + required: true + type: choice + options: + - SIMULATED + TestInputs: + description: TestInputs + required: false + type: string + slackMemberID: + description: Notifies test results (Not your @) + required: true + default: U02Q14G80TY + type: string + +jobs: + automation_load: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + name: ${{ inputs.network }} Automation Load Test + runs-on: ubuntu20.04-16cores-64GB + env: + SELECTED_NETWORKS: ${{ inputs.network }} + SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} + SLACK_CHANNEL: C03KJ5S7KEK + TEST_INPUTS: ${{ inputs.TestInputs }} + CHAINLINK_ENV_USER: ${{ github.actor }} + REF_NAME: ${{ github.head_ref || github.ref_name }} + steps: + - name: Setup Push Tag + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + + - name: Add mask + run: | + SLACK_USER=$(jq -r '.inputs.slackMemberID' $GITHUB_EVENT_PATH) + echo ::add-mask::$SLACK_USER + echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} + - name: Build Test Image + uses: ./.github/actions/build-test-image + with: + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + suites: benchmark load/automationv2_1 chaos reorg + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + env: + RR_CPU: 4000m + RR_MEM: 4Gi + DETACH_RUNNER: true + TEST_SUITE: automationv2_1 + TEST_ARGS: -test.timeout 720h + ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }} + INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: cd integration-tests && go test -timeout 1h -v -run TestLogTrigger ./load/automationv2_1 -count=1 + test_download_vendor_packages_command: make gomod + cl_repo: ${{ inputs.chainlinkImage }} + cl_image_tag: ${{ inputs.chainlinkVersion }} + token: ${{ secrets.GITHUB_TOKEN }} + should_cleanup: false + go_mod_path: ./integration-tests/go.mod + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ${{ inputs.network }} Automation Load Test + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true diff --git a/CODEOWNERS b/CODEOWNERS index 8ec42ed6dd..5f33e68e51 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -104,6 +104,7 @@ core/scripts/gateway @bolekk @pinebit /.github/workflows/performance-tests.yml @smartcontractkit/test-tooling-team /.github/workflows/automation-ondemand-tests.yml @smartcontractkit/keepers /.github/workflows/automation-benchmark-tests.yml @smartcontractkit/keepers +/.github/workflows/automation-load-tests.yml @smartcontractkit/keepers /core/chainlink.Dockerfile @smartcontractkit/prodsec-public diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index 1c54d67713..ddf6c2c8bf 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -41,6 +41,7 @@ compileContract automation/v2_0/KeeperRegistryLogic2_0.sol compileContract automation/UpkeepTranscoder.sol compileContract automation/mocks/MockAggregatorProxy.sol compileContract automation/testhelpers/LogUpkeepCounter.sol +compileContract automation/testhelpers/SimpleLogUpkeepCounter.sol compileContract automation/mocks/KeeperRegistrar1_2Mock.sol compileContract automation/mocks/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.sol diff --git a/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol b/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol new file mode 100644 index 0000000000..563c1354b6 --- /dev/null +++ b/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.6; + +import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; + +contract SimpleLogUpkeepCounter is ILogAutomation { + event PerformingUpkeep( + address indexed from, + uint256 initialBlock, + uint256 lastBlock, + uint256 previousBlock, + uint256 counter, + uint256 timeToPerform + ); + + uint256 public lastBlock; + uint256 public previousPerformBlock; + uint256 public initialBlock; + uint256 public counter; + uint256 public timeToPerform; + + constructor() { + previousPerformBlock = 0; + lastBlock = block.number; + initialBlock = 0; + counter = 0; + } + + function checkLog(Log calldata log, bytes memory) external view override returns (bool, bytes memory) { + return (true, abi.encode(log)); + } + + function performUpkeep(bytes calldata performData) external override { + if (initialBlock == 0) { + initialBlock = block.number; + } + lastBlock = block.number; + counter = counter + 1; + previousPerformBlock = lastBlock; + Log memory log = abi.decode(performData, (Log)); + timeToPerform = block.timestamp - log.timestamp; + emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter, timeToPerform); + } +} diff --git a/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go b/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go new file mode 100644 index 0000000000..bb28c8bd6c --- /dev/null +++ b/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go @@ -0,0 +1,504 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package simple_log_upkeep_counter_wrapper + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type Log struct { + Index *big.Int + Timestamp *big.Int + TxHash [32]byte + BlockNumber *big.Int + BlockHash [32]byte + Source common.Address + Topics [][32]byte + Data []byte +} + +var SimpleLogUpkeepCounterMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lastBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"counter\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timeToPerform\",\"type\":\"uint256\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeToPerform\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5060006001819055438155600281905560035561088a806100326000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806361bc221a1161005b57806361bc221a146100d4578063806b984f146100dd578063917d895f146100e6578063c6066f0d146100ef57600080fd5b80632cb158641461008257806340691db41461009e5780634585e33b146100bf575b600080fd5b61008b60025481565b6040519081526020015b60405180910390f35b6100b16100ac366004610384565b6100f8565b60405161009592919061055e565b6100d26100cd366004610312565b61012a565b005b61008b60035481565b61008b60005481565b61008b60015481565b61008b60045481565b6000606060018460405160200161010f91906105db565b604051602081830303815290604052915091505b9250929050565b60025461013657436002555b436000556003546101489060016107f0565b6003556000805460015561015e828401846103f1565b90508060200151426101709190610808565b6004819055600254600054600154600354604080519485526020850193909352918301526060820152608081019190915232907f4874b8dd61a40fe23599b4360a9a824d7081742fca9f555bcee3d389c4f4bd659060a00160405180910390a2505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101f957600080fd5b919050565b600082601f83011261020f57600080fd5b8135602067ffffffffffffffff82111561022b5761022b61084e565b8160051b61023a8282016106d6565b83815282810190868401838801850189101561025557600080fd5b600093505b8584101561027857803583526001939093019291840191840161025a565b50979650505050505050565b600082601f83011261029557600080fd5b813567ffffffffffffffff8111156102af576102af61084e565b6102e060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016106d6565b8181528460208386010111156102f557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806020838503121561032557600080fd5b823567ffffffffffffffff8082111561033d57600080fd5b818501915085601f83011261035157600080fd5b81358181111561036057600080fd5b86602082850101111561037257600080fd5b60209290920196919550909350505050565b6000806040838503121561039757600080fd5b823567ffffffffffffffff808211156103af57600080fd5b9084019061010082870312156103c457600080fd5b909250602084013590808211156103da57600080fd5b506103e785828601610284565b9150509250929050565b60006020828403121561040357600080fd5b813567ffffffffffffffff8082111561041b57600080fd5b90830190610100828603121561043057600080fd5b6104386106ac565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015261047060a084016101d5565b60a082015260c08301358281111561048757600080fd5b610493878286016101fe565b60c08301525060e0830135828111156104ab57600080fd5b6104b787828601610284565b60e08301525095945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156104f857600080fd5b8260051b8083602087013760009401602001938452509192915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b821515815260006020604081840152835180604085015260005b8181101561059457858101830151858201606001528201610578565b818111156105a6576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b6020815281356020820152602082013560408201526040820135606082015260608201356080820152608082013560a082015273ffffffffffffffffffffffffffffffffffffffff61062f60a084016101d5565b1660c0820152600061064460c0840184610725565b6101008060e086015261065c610120860183856104c6565b925061066b60e087018761078c565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086850301828701526106a1848483610515565b979650505050505050565b604051610100810167ffffffffffffffff811182821017156106d0576106d061084e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561071d5761071d61084e565b604052919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261075a57600080fd5b830160208101925035905067ffffffffffffffff81111561077a57600080fd5b8060051b360383131561012357600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126107c157600080fd5b830160208101925035905067ffffffffffffffff8111156107e157600080fd5b80360383131561012357600080fd5b600082198211156108035761080361081f565b500190565b60008282101561081a5761081a61081f565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", +} + +var SimpleLogUpkeepCounterABI = SimpleLogUpkeepCounterMetaData.ABI + +var SimpleLogUpkeepCounterBin = SimpleLogUpkeepCounterMetaData.Bin + +func DeploySimpleLogUpkeepCounter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SimpleLogUpkeepCounter, error) { + parsed, err := SimpleLogUpkeepCounterMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SimpleLogUpkeepCounterBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &SimpleLogUpkeepCounter{address: address, abi: *parsed, SimpleLogUpkeepCounterCaller: SimpleLogUpkeepCounterCaller{contract: contract}, SimpleLogUpkeepCounterTransactor: SimpleLogUpkeepCounterTransactor{contract: contract}, SimpleLogUpkeepCounterFilterer: SimpleLogUpkeepCounterFilterer{contract: contract}}, nil +} + +type SimpleLogUpkeepCounter struct { + address common.Address + abi abi.ABI + SimpleLogUpkeepCounterCaller + SimpleLogUpkeepCounterTransactor + SimpleLogUpkeepCounterFilterer +} + +type SimpleLogUpkeepCounterCaller struct { + contract *bind.BoundContract +} + +type SimpleLogUpkeepCounterTransactor struct { + contract *bind.BoundContract +} + +type SimpleLogUpkeepCounterFilterer struct { + contract *bind.BoundContract +} + +type SimpleLogUpkeepCounterSession struct { + Contract *SimpleLogUpkeepCounter + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type SimpleLogUpkeepCounterCallerSession struct { + Contract *SimpleLogUpkeepCounterCaller + CallOpts bind.CallOpts +} + +type SimpleLogUpkeepCounterTransactorSession struct { + Contract *SimpleLogUpkeepCounterTransactor + TransactOpts bind.TransactOpts +} + +type SimpleLogUpkeepCounterRaw struct { + Contract *SimpleLogUpkeepCounter +} + +type SimpleLogUpkeepCounterCallerRaw struct { + Contract *SimpleLogUpkeepCounterCaller +} + +type SimpleLogUpkeepCounterTransactorRaw struct { + Contract *SimpleLogUpkeepCounterTransactor +} + +func NewSimpleLogUpkeepCounter(address common.Address, backend bind.ContractBackend) (*SimpleLogUpkeepCounter, error) { + abi, err := abi.JSON(strings.NewReader(SimpleLogUpkeepCounterABI)) + if err != nil { + return nil, err + } + contract, err := bindSimpleLogUpkeepCounter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SimpleLogUpkeepCounter{address: address, abi: abi, SimpleLogUpkeepCounterCaller: SimpleLogUpkeepCounterCaller{contract: contract}, SimpleLogUpkeepCounterTransactor: SimpleLogUpkeepCounterTransactor{contract: contract}, SimpleLogUpkeepCounterFilterer: SimpleLogUpkeepCounterFilterer{contract: contract}}, nil +} + +func NewSimpleLogUpkeepCounterCaller(address common.Address, caller bind.ContractCaller) (*SimpleLogUpkeepCounterCaller, error) { + contract, err := bindSimpleLogUpkeepCounter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SimpleLogUpkeepCounterCaller{contract: contract}, nil +} + +func NewSimpleLogUpkeepCounterTransactor(address common.Address, transactor bind.ContractTransactor) (*SimpleLogUpkeepCounterTransactor, error) { + contract, err := bindSimpleLogUpkeepCounter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SimpleLogUpkeepCounterTransactor{contract: contract}, nil +} + +func NewSimpleLogUpkeepCounterFilterer(address common.Address, filterer bind.ContractFilterer) (*SimpleLogUpkeepCounterFilterer, error) { + contract, err := bindSimpleLogUpkeepCounter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SimpleLogUpkeepCounterFilterer{contract: contract}, nil +} + +func bindSimpleLogUpkeepCounter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SimpleLogUpkeepCounterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SimpleLogUpkeepCounter.Contract.SimpleLogUpkeepCounterCaller.contract.Call(opts, result, method, params...) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SimpleLogUpkeepCounterTransactor.contract.Transfer(opts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SimpleLogUpkeepCounterTransactor.contract.Transact(opts, method, params...) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SimpleLogUpkeepCounter.Contract.contract.Call(opts, result, method, params...) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.contract.Transfer(opts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.contract.Transact(opts, method, params...) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) CheckLog(opts *bind.CallOpts, log Log, arg1 []byte) (bool, []byte, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "checkLog", log, arg1) + + if err != nil { + return *new(bool), *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + out1 := *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return out0, out1, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) CheckLog(log Log, arg1 []byte) (bool, []byte, error) { + return _SimpleLogUpkeepCounter.Contract.CheckLog(&_SimpleLogUpkeepCounter.CallOpts, log, arg1) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) CheckLog(log Log, arg1 []byte) (bool, []byte, error) { + return _SimpleLogUpkeepCounter.Contract.CheckLog(&_SimpleLogUpkeepCounter.CallOpts, log, arg1) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) Counter(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "counter") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) Counter() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.Counter(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) Counter() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.Counter(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) InitialBlock(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "initialBlock") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) InitialBlock() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.InitialBlock(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) InitialBlock() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.InitialBlock(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) LastBlock(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "lastBlock") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) LastBlock() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.LastBlock(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) LastBlock() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.LastBlock(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) PreviousPerformBlock(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "previousPerformBlock") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) PreviousPerformBlock() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.PreviousPerformBlock(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) PreviousPerformBlock() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.PreviousPerformBlock(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) TimeToPerform(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "timeToPerform") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) TimeToPerform() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.TimeToPerform(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) TimeToPerform() (*big.Int, error) { + return _SimpleLogUpkeepCounter.Contract.TimeToPerform(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactor) PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.contract.Transact(opts, "performUpkeep", performData) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.PerformUpkeep(&_SimpleLogUpkeepCounter.TransactOpts, performData) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.PerformUpkeep(&_SimpleLogUpkeepCounter.TransactOpts, performData) +} + +type SimpleLogUpkeepCounterPerformingUpkeepIterator struct { + Event *SimpleLogUpkeepCounterPerformingUpkeep + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SimpleLogUpkeepCounterPerformingUpkeepIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SimpleLogUpkeepCounterPerformingUpkeep) + 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(SimpleLogUpkeepCounterPerformingUpkeep) + 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 *SimpleLogUpkeepCounterPerformingUpkeepIterator) Error() error { + return it.fail +} + +func (it *SimpleLogUpkeepCounterPerformingUpkeepIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SimpleLogUpkeepCounterPerformingUpkeep struct { + From common.Address + InitialBlock *big.Int + LastBlock *big.Int + PreviousBlock *big.Int + Counter *big.Int + TimeToPerform *big.Int + Raw types.Log +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterFilterer) FilterPerformingUpkeep(opts *bind.FilterOpts, from []common.Address) (*SimpleLogUpkeepCounterPerformingUpkeepIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _SimpleLogUpkeepCounter.contract.FilterLogs(opts, "PerformingUpkeep", fromRule) + if err != nil { + return nil, err + } + return &SimpleLogUpkeepCounterPerformingUpkeepIterator{contract: _SimpleLogUpkeepCounter.contract, event: "PerformingUpkeep", logs: logs, sub: sub}, nil +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterFilterer) WatchPerformingUpkeep(opts *bind.WatchOpts, sink chan<- *SimpleLogUpkeepCounterPerformingUpkeep, from []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _SimpleLogUpkeepCounter.contract.WatchLogs(opts, "PerformingUpkeep", fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SimpleLogUpkeepCounterPerformingUpkeep) + if err := _SimpleLogUpkeepCounter.contract.UnpackLog(event, "PerformingUpkeep", 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 (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterFilterer) ParsePerformingUpkeep(log types.Log) (*SimpleLogUpkeepCounterPerformingUpkeep, error) { + event := new(SimpleLogUpkeepCounterPerformingUpkeep) + if err := _SimpleLogUpkeepCounter.contract.UnpackLog(event, "PerformingUpkeep", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounter) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _SimpleLogUpkeepCounter.abi.Events["PerformingUpkeep"].ID: + return _SimpleLogUpkeepCounter.ParsePerformingUpkeep(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (SimpleLogUpkeepCounterPerformingUpkeep) Topic() common.Hash { + return common.HexToHash("0x4874b8dd61a40fe23599b4360a9a824d7081742fca9f555bcee3d389c4f4bd65") +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounter) Address() common.Address { + return _SimpleLogUpkeepCounter.address +} + +type SimpleLogUpkeepCounterInterface interface { + CheckLog(opts *bind.CallOpts, log Log, arg1 []byte) (bool, []byte, error) + + Counter(opts *bind.CallOpts) (*big.Int, error) + + InitialBlock(opts *bind.CallOpts) (*big.Int, error) + + LastBlock(opts *bind.CallOpts) (*big.Int, error) + + PreviousPerformBlock(opts *bind.CallOpts) (*big.Int, error) + + TimeToPerform(opts *bind.CallOpts) (*big.Int, error) + + PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) + + FilterPerformingUpkeep(opts *bind.FilterOpts, from []common.Address) (*SimpleLogUpkeepCounterPerformingUpkeepIterator, error) + + WatchPerformingUpkeep(opts *bind.WatchOpts, sink chan<- *SimpleLogUpkeepCounterPerformingUpkeep, from []common.Address) (event.Subscription, error) + + ParsePerformingUpkeep(log types.Log) (*SimpleLogUpkeepCounterPerformingUpkeep, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 6482c01cf8..6efc75fce9 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -50,6 +50,7 @@ operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.a operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin d7abd0e67f30a3a4c9c04c896124391306fa364fcf579fa6df04dbf912b48568 oracle_wrapper: ../../contracts/solc/v0.6/Oracle/Oracle.abi ../../contracts/solc/v0.6/Oracle/Oracle.bin 7af2fbac22a6e8c2847e8e685a5400cac5101d72ddf5365213beb79e4dede43a perform_data_checker_wrapper: ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 +simple_log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin 0a7a0cc4da7dc2a3d0a0c36c746b1adc044af5cad1838367356a0604f3255a01 solidity_vrf_consumer_interface: ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.bin ecc99378aa798014de9db42b2eb81320778b0663dbe208008dad75ccdc1d4366 solidity_vrf_consumer_interface_v08: ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.bin b14f9136b15e3dc9d6154d5700f3ed4cf88ddc4f70f20c3bb57fc46050904c8f solidity_vrf_coordinator_interface: ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.bin a23d3c395156804788c7f6fbda2994e8f7184304c0f0c9f2c4ddeaf073d346d2 diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 3965c15908..07e4fa9b8f 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -59,6 +59,7 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin AutomationUtils automation_utils_2_1 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin AutomationForwarderLogic automation_forwarder_logic //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.bin LogUpkeepCounter log_upkeep_counter_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin SimpleLogUpkeepCounter simple_log_upkeep_counter_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin LogTriggeredStreamsLookup log_triggered_streams_lookup_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.bin DummyProtocol dummy_protocol_wrapper diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 45195d327e..000fe7b2b8 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -55,6 +55,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/oracle_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/perform_data_checker_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_upkeep_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/test_api_consumer_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_counter_wrapper" @@ -92,6 +93,7 @@ type ContractDeployer interface { LoadKeeperRegistry(address common.Address, registryVersion eth_contracts.KeeperRegistryVersion) (KeeperRegistry, error) DeployKeeperConsumer(updateInterval *big.Int) (KeeperConsumer, error) DeployAutomationLogTriggerConsumer(testInterval *big.Int) (KeeperConsumer, error) + DeployAutomationSimpleLogTriggerConsumer() (KeeperConsumer, error) DeployAutomationStreamsLookupUpkeepConsumer(testRange *big.Int, interval *big.Int, useArbBlock bool, staging bool, verify bool) (KeeperConsumer, error) DeployAutomationLogTriggeredStreamsLookupUpkeepConsumer() (KeeperConsumer, error) DeployKeeperConsumerPerformance( @@ -1292,6 +1294,25 @@ func (e *EthereumContractDeployer) DeployAutomationLogTriggerConsumer(testInterv }, err } +func (e *EthereumContractDeployer) DeployAutomationSimpleLogTriggerConsumer() (KeeperConsumer, error) { + address, _, instance, err := e.client.DeployContract("SimpleLogUpkeepCounter", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return simple_log_upkeep_counter_wrapper.DeploySimpleLogUpkeepCounter( + auth, backend, + ) + }) + if err != nil { + return nil, err + } + return &EthereumAutomationSimpleLogCounterConsumer{ + client: e.client, + consumer: instance.(*simple_log_upkeep_counter_wrapper.SimpleLogUpkeepCounter), + address: address, + }, err +} + func (e *EthereumContractDeployer) DeployAutomationStreamsLookupUpkeepConsumer(testRange *big.Int, interval *big.Int, useArbBlock bool, staging bool, verify bool) (KeeperConsumer, error) { address, _, instance, err := e.client.DeployContract("StreamsLookupUpkeep", func( auth *bind.TransactOpts, diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index 2c0250e745..7519b5de4c 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -35,6 +35,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/perform_data_checker_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_upkeep_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_transcoder" @@ -1821,6 +1822,32 @@ func (v *EthereumAutomationLogCounterConsumer) Counter(ctx context.Context) (*bi return cnt, nil } +type EthereumAutomationSimpleLogCounterConsumer struct { + client blockchain.EVMClient + consumer *simple_log_upkeep_counter_wrapper.SimpleLogUpkeepCounter + address *common.Address +} + +func (v *EthereumAutomationSimpleLogCounterConsumer) Address() string { + return v.address.Hex() +} + +func (v *EthereumAutomationSimpleLogCounterConsumer) Start() error { + return nil +} + +func (v *EthereumAutomationSimpleLogCounterConsumer) Counter(ctx context.Context) (*big.Int, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + cnt, err := v.consumer.Counter(opts) + if err != nil { + return nil, err + } + return cnt, nil +} + // EthereumKeeperConsumerPerformance represents a more complicated keeper consumer contract, one intended only for // performance tests. type EthereumKeeperConsumerPerformance struct { diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go new file mode 100644 index 0000000000..dfef099c17 --- /dev/null +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -0,0 +1,621 @@ +package automationv2_1 + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "os" + "strconv" + "strings" + "testing" + "time" + + geth "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/slack-go/slack" + ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" + "github.com/smartcontractkit/wasp" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + contractseth "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + registrar21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" +) + +const ( + StartupWaitTime = 30 * time.Second + StopWaitTime = 60 * time.Second +) + +var ( + baseTOML = `[Feature] +LogPoller = true + +[OCR2] +Enabled = true + +[P2P] +[P2P.V2] +Enabled = true +AnnounceAddresses = ["0.0.0.0:6690"] +ListenAddresses = ["0.0.0.0:6690"]` + + minimumNodeSpec = map[string]interface{}{ + "resources": map[string]interface{}{ + "requests": map[string]interface{}{ + "cpu": "2000m", + "memory": "4Gi", + }, + "limits": map[string]interface{}{ + "cpu": "2000m", + "memory": "4Gi", + }, + }, + } + + minimumDbSpec = map[string]interface{}{ + "resources": map[string]interface{}{ + "requests": map[string]interface{}{ + "cpu": "1000m", + "memory": "1Gi", + }, + "limits": map[string]interface{}{ + "cpu": "1000m", + "memory": "1Gi", + }, + }, + "stateful": true, + "capacity": "5Gi", + } + + recNodeSpec = map[string]interface{}{ + "resources": map[string]interface{}{ + "requests": map[string]interface{}{ + "cpu": "4000m", + "memory": "8Gi", + }, + "limits": map[string]interface{}{ + "cpu": "4000m", + "memory": "8Gi", + }, + }, + } + + recDbSpec = map[string]interface{}{ + "resources": map[string]interface{}{ + "requests": map[string]interface{}{ + "cpu": "2000m", + "memory": "2Gi", + }, + "limits": map[string]interface{}{ + "cpu": "2000m", + "memory": "2Gi", + }, + }, + "stateful": true, + "capacity": "10Gi", + } +) + +var ( + numberofNodes, _ = strconv.Atoi(getEnv("NUMBEROFNODES", "6")) // Number of nodes in the DON + numberOfUpkeeps, _ = strconv.Atoi(getEnv("NUMBEROFUPKEEPS", "100")) // Number of log triggered upkeeps + duration, _ = strconv.Atoi(getEnv("DURATION", "900")) // Test duration in seconds + blockTime, _ = strconv.Atoi(getEnv("BLOCKTIME", "1")) // Block time in seconds for geth simulated dev network + numberOfEvents, _ = strconv.Atoi(getEnv("NUMBEROFEVENTS", "1")) // Number of events to emit per trigger + specType = getEnv("SPECTYPE", "minimum") // minimum, recommended, local specs for the test + logLevel = getEnv("LOGLEVEL", "info") // log level for the chainlink nodes + pyroscope, _ = strconv.ParseBool(getEnv("PYROSCOPE", "false")) // enable pyroscope for the chainlink nodes +) + +func TestLogTrigger(t *testing.T) { + l := logging.GetTestLogger(t) + + l.Info().Msg("Starting automation v2.1 log trigger load test") + l.Info().Str("TEST_INPUTS", os.Getenv("TEST_INPUTS")).Int("Number of Nodes", numberofNodes). + Int("Number of Upkeeps", numberOfUpkeeps). + Int("Duration", duration). + Int("Block Time", blockTime). + Int("Number of Events", numberOfEvents). + Str("Spec Type", specType). + Str("Log Level", logLevel). + Str("Image", os.Getenv(config.EnvVarCLImage)). + Str("Tag", os.Getenv(config.EnvVarCLTag)). + Msg("Test Config") + + testConfig := fmt.Sprintf("Number of Nodes: %d\nNumber of Upkeeps: %d\nDuration: %d\nBlock Time: %d\n"+ + "Number of Events: %d\nSpec Type: %s\nLog Level: %s\nImage: %s\nTag: %s\n", numberofNodes, numberOfUpkeeps, duration, + blockTime, numberOfEvents, specType, logLevel, os.Getenv(config.EnvVarCLImage), os.Getenv(config.EnvVarCLTag)) + + testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] + testType := "load" + loadDuration := time.Duration(duration) * time.Second + automationDefaultLinkFunds := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(10000))) //10000 LINK + automationDefaultUpkeepGasLimit := uint32(1_000_000) + + registrySettings := &contracts.KeeperRegistrySettings{ + PaymentPremiumPPB: uint32(0), + FlatFeeMicroLINK: uint32(40_000), + BlockCountPerTurn: big.NewInt(100), + CheckGasLimit: uint32(45_000_000), //45M + StalenessSeconds: big.NewInt(90_000), + GasCeilingMultiplier: uint16(2), + MaxPerformGas: uint32(5_000_000), + MinUpkeepSpend: big.NewInt(0), + FallbackGasPrice: big.NewInt(2e11), + FallbackLinkPrice: big.NewInt(2e18), + MaxCheckDataSize: uint32(5_000), + MaxPerformDataSize: uint32(5_000), + RegistryVersion: contractseth.RegistryVersion_2_1, + } + + testEnvironment := environment.New(&environment.Config{ + TTL: time.Hour * 24, // 1 day, + NamespacePrefix: fmt.Sprintf( + "automation-%s-%s", + testType, + strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-"), + ), + Test: t, + PreventPodEviction: true, + }) + + if testEnvironment.WillUseRemoteRunner() { + key := "TEST_INPUTS" + err := os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) + require.NoError(t, err, "failed to set the environment variable TEST_INPUTS for remote runner") + + key = config.EnvVarPyroscopeServer + err = os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) + require.NoError(t, err, "failed to set the environment variable PYROSCOPE_SERVER for remote runner") + + key = config.EnvVarPyroscopeKey + err = os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) + require.NoError(t, err, "failed to set the environment variable PYROSCOPE_KEY for remote runner") + + key = "GRAFANA_DASHBOARD_URL" + err = os.Setenv(fmt.Sprintf("TEST_%s", key), getEnv(key, "")) + require.NoError(t, err, "failed to set the environment variable GRAFANA_DASHBOARD_URL for remote runner") + } + + testEnvironment. + AddHelm(ethereum.New(ðereum.Props{ + NetworkName: testNetwork.Name, + Simulated: testNetwork.Simulated, + WsURLs: testNetwork.URLs, + Values: map[string]interface{}{ + "resources": map[string]interface{}{ + "requests": map[string]interface{}{ + "cpu": "4000m", + "memory": "4Gi", + }, + "limits": map[string]interface{}{ + "cpu": "8000m", + "memory": "8Gi", + }, + }, + "geth": map[string]interface{}{ + "blocktime": blockTime, + "capacity": "10Gi", + }, + }, + })) + + err := testEnvironment.Run() + require.NoError(t, err, "Error launching test environment") + + if testEnvironment.WillUseRemoteRunner() { + return + } + + var ( + nodeSpec = minimumNodeSpec + dbSpec = minimumDbSpec + ) + + switch specType { + case "recommended": + nodeSpec = recNodeSpec + dbSpec = recDbSpec + case "local": + nodeSpec = map[string]interface{}{} + dbSpec = map[string]interface{}{"stateful": true} + default: + // minimum: + + } + + if !pyroscope { + err = os.Setenv(config.EnvVarPyroscopeServer, "") + require.NoError(t, err, "Error setting pyroscope server env var") + } + + err = os.Setenv(config.EnvVarPyroscopeEnvironment, testEnvironment.Cfg.Namespace) + require.NoError(t, err, "Error setting pyroscope environment env var") + + for i := 0; i < numberofNodes+1; i++ { // +1 for the OCR boot node + var nodeTOML string + if i == 1 || i == 3 { + nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"%s\"", baseTOML, logLevel) + } else { + nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"info\"", baseTOML) + } + nodeTOML = networks.AddNetworksConfig(nodeTOML, testNetwork) + testEnvironment.AddHelm(chainlink.New(i, map[string]any{ + "toml": nodeTOML, + "chainlink": nodeSpec, + "db": dbSpec, + })) + } + + err = testEnvironment.Run() + require.NoError(t, err, "Error running chainlink DON") + + chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) + require.NoError(t, err, "Error building chain client") + + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) + require.NoError(t, err, "Error building contract deployer") + + chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) + require.NoError(t, err, "Error connecting to chainlink nodes") + + chainClient.ParallelTransactions(true) + + linkToken, err := contractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Error deploying link token contract") + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Failed waiting for contracts to deploy") + + registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( + t, contractseth.RegistryVersion_2_1, *registrySettings, linkToken, contractDeployer, chainClient, + ) + + err = actions.FundChainlinkNodesAddress(chainlinkNodes[1:], chainClient, big.NewFloat(100), 0) + require.NoError(t, err, "Error funding chainlink nodes") + + actions.CreateOCRKeeperJobs( + t, + chainlinkNodes, + registry.Address(), + chainClient.GetChainID().Int64(), + 0, + contractseth.RegistryVersion_2_1, + ) + + S, oracleIdentities, err := actions.GetOracleIdentities(chainlinkNodes) + require.NoError(t, err, "Error getting oracle identities") + offC, err := json.Marshal(ocr2keepers30config.OffchainConfig{ + TargetProbability: "0.999", + TargetInRounds: 1, + PerformLockoutWindow: 80_000, // Copied from arbitrum mainnet prod value + GasLimitPerReport: 10_300_000, + GasOverheadPerUpkeep: 300_000, + MinConfirmations: 0, + MaxUpkeepBatchSize: 10, + }) + require.NoError(t, err, "Error marshalling offchain config") + + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err := ocr3.ContractSetConfigArgsForTests( + 10*time.Second, // deltaProgress time.Duration, + 15*time.Second, // deltaResend time.Duration, + 500*time.Millisecond, // deltaInitial time.Duration, + 1000*time.Millisecond, // deltaRound time.Duration, + 200*time.Millisecond, // deltaGrace time.Duration, + 300*time.Millisecond, // deltaCertifiedCommitRequest time.Duration + 15*time.Second, // deltaStage time.Duration, + 24, // rMax uint64, + S, // s []int, + oracleIdentities, // oracles []OracleIdentityExtra, + offC, // reportingPluginConfig []byte, + 20*time.Millisecond, // maxDurationQuery time.Duration, + 20*time.Millisecond, // maxDurationObservation time.Duration, // good to here + 1200*time.Millisecond, // maxDurationShouldAcceptAttestedReport time.Duration, + 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, + 1, // f int, + nil, // onchainConfig []byte, + ) + require.NoError(t, err, "Error setting OCR config vars") + + var signers []common.Address + for _, signer := range signerOnchainPublicKeys { + require.Equal(t, 20, len(signer), "OnChainPublicKey '%v' has wrong length for address", signer) + signers = append(signers, common.BytesToAddress(signer)) + } + + var transmitters []common.Address + for _, transmitter := range transmitterAccounts { + require.True(t, common.IsHexAddress(string(transmitter)), "TransmitAccount '%s' is not a valid Ethereum address", string(transmitter)) + transmitters = append(transmitters, common.HexToAddress(string(transmitter))) + } + + onchainConfig, err := registrySettings.EncodeOnChainConfig(registrar.Address(), common.HexToAddress(chainClient.GetDefaultWallet().Address())) + require.NoError(t, err, "Error encoding onchain config") + l.Info().Msg("Done building OCR config") + ocrConfig := contracts.OCRv2Config{ + Signers: signers, + Transmitters: transmitters, + F: f, + OnchainConfig: onchainConfig, + OffchainConfigVersion: offchainConfigVersion, + OffchainConfig: offchainConfig, + } + + err = registry.SetConfig(*registrySettings, ocrConfig) + require.NoError(t, err, "Error setting registry config") + + consumerContracts := make([]contracts.KeeperConsumer, 0) + triggerContracts := make([]contracts.LogEmitter, 0) + + utilsABI, err := automation_utils_2_1.AutomationUtilsMetaData.GetAbi() + require.NoError(t, err, "Error getting automation utils abi") + registrarABI, err := registrar21.AutomationRegistrarMetaData.GetAbi() + require.NoError(t, err, "Error getting automation registrar abi") + emitterABI, err := log_emitter.LogEmitterMetaData.GetAbi() + require.NoError(t, err, "Error getting log emitter abi") + consumerABI, err := simple_log_upkeep_counter_wrapper.SimpleLogUpkeepCounterMetaData.GetAbi() + require.NoError(t, err, "Error getting consumer abi") + + var bytes0 = [32]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + } + registrationTxHashes := make([]common.Hash, 0) + upkeepIds := make([]*big.Int, 0) + + for i := 0; i < numberOfUpkeeps; i++ { + consumerContract, err := contractDeployer.DeployAutomationSimpleLogTriggerConsumer() + require.NoError(t, err, "Error deploying automation consumer contract") + consumerContracts = append(consumerContracts, consumerContract) + l.Debug(). + Str("Contract Address", consumerContract.Address()). + Int("Number", i+1). + Int("Out Of", numberOfUpkeeps). + Msg("Deployed Automation Log Trigger Consumer Contract") + + cEVMClient, err := blockchain.ConcurrentEVMClient(testNetwork, testEnvironment, chainClient, l) + require.NoError(t, err, "Error building concurrent chain client") + + cContractDeployer, err := contracts.NewContractDeployer(cEVMClient, l) + require.NoError(t, err, "Error building concurrent contract deployer") + + triggerContract, err := cContractDeployer.DeployLogEmitterContract() + require.NoError(t, err, "Error deploying log emitter contract") + triggerContracts = append(triggerContracts, triggerContract) + l.Debug(). + Str("Contract Address", triggerContract.Address().Hex()). + Int("Number", i+1). + Int("Out Of", numberOfUpkeeps). + Msg("Deployed Automation Log Trigger Emitter Contract") + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Failed waiting for contracts to deploy") + + for i, consumerContract := range consumerContracts { + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: triggerContracts[i].Address(), + FilterSelector: 0, + Topic0: emitterABI.Events["Log1"].ID, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := utilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + require.NoError(t, err, "Error encoding log trigger config") + l.Debug().Bytes("Encoded Log Trigger Config", encodedLogTriggerConfig).Msg("Encoded Log Trigger Config") + + registrationRequest, err := registrarABI.Pack( + "register", + fmt.Sprintf("LogTriggerUpkeep-%d", i), + []byte("test@mail.com"), + common.HexToAddress(consumerContract.Address()), + automationDefaultUpkeepGasLimit, + common.HexToAddress(chainClient.GetDefaultWallet().Address()), + uint8(1), + []byte("0"), + encodedLogTriggerConfig, + []byte("0"), + automationDefaultLinkFunds, + common.HexToAddress(chainClient.GetDefaultWallet().Address()), + ) + require.NoError(t, err, "Error encoding upkeep registration request") + tx, err := linkToken.TransferAndCall(registrar.Address(), automationDefaultLinkFunds, registrationRequest) + require.NoError(t, err, "Error sending upkeep registration request") + registrationTxHashes = append(registrationTxHashes, tx.Hash()) + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Failed waiting for upkeeps to be registered") + + for _, txHash := range registrationTxHashes { + receipt, err := chainClient.GetTxReceipt(txHash) + require.NoError(t, err, "Registration tx should be completed") + var upkeepId *big.Int + for _, rawLog := range receipt.Logs { + parsedUpkeepId, err := registry.ParseUpkeepIdFromRegisteredLog(rawLog) + if err == nil { + upkeepId = parsedUpkeepId + break + } + } + require.NotNil(t, upkeepId, "Upkeep ID should be found after registration") + l.Debug(). + Str("TxHash", txHash.String()). + Str("Upkeep ID", upkeepId.String()). + Msg("Found upkeepId in tx hash") + upkeepIds = append(upkeepIds, upkeepId) + } + l.Info().Msg("Successfully registered all Automation Consumer Contracts") + l.Info().Interface("Upkeep IDs", upkeepIds).Msg("Upkeep IDs") + l.Info().Str("STARTUP_WAIT_TIME", StartupWaitTime.String()).Msg("Waiting for plugin to start") + time.Sleep(StartupWaitTime) + + startBlock, err := chainClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + + p := wasp.NewProfile() + + for i, triggerContract := range triggerContracts { + g, err := wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: fmt.Sprintf("log_trigger_gen_%s", triggerContract.Address().String()), + CallTimeout: time.Second * 10, + Schedule: wasp.Plain( + 1, + loadDuration, + ), + Gun: NewLogTriggerUser( + triggerContract, + consumerContracts[i], + l, + numberOfEvents, + ), + CallResultBufLen: 1000000, + }) + p.Add(g, err) + } + + l.Info().Msg("Starting load generators") + startTime := time.Now() + err = sendSlackNotification("Started", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), + strconv.FormatInt(startTime.UnixMilli(), 10), "now", + []slack.Block{extraBlockWithText("\bTest Config\b\n```" + testConfig + "```")}) + if err != nil { + l.Error().Err(err).Msg("Error sending slack notification") + } + _, err = p.Run(true) + require.NoError(t, err, "Error running load generators") + + l.Info().Msg("Finished load generators") + l.Info().Str("STOP_WAIT_TIME", StopWaitTime.String()).Msg("Waiting for upkeeps to be performed") + time.Sleep(StopWaitTime) + l.Info().Msg("Finished waiting 60s for upkeeps to be performed") + endTime := time.Now() + testDuration := endTime.Sub(startTime) + l.Info().Str("Duration", testDuration.String()).Msg("Test Duration") + endBlock, err := chainClient.LatestBlockNumber(context.Background()) + require.NoError(t, err, "Error getting latest block number") + l.Info().Uint64("Starting Block", startBlock).Uint64("Ending Block", endBlock).Msg("Test Block Range") + + upkeepDelays := make([][]int64, 0) + var numberOfEventsEmitted int + var batchSize = 500 + + for _, gen := range p.Generators { + numberOfEventsEmitted += len(gen.GetData().OKData.Data) + } + numberOfEventsEmitted = numberOfEventsEmitted * numberOfEvents + l.Info().Int("Number of Events Emitted", numberOfEventsEmitted).Msg("Number of Events Emitted") + + if endBlock-startBlock < uint64(batchSize) { + batchSize = int(endBlock - startBlock) + } + + for cIter, consumerContract := range consumerContracts { + var ( + logs []types.Log + address = common.HexToAddress(consumerContract.Address()) + timeout = 5 * time.Second + ) + for fromBlock := startBlock; fromBlock < endBlock; fromBlock += uint64(batchSize) + 1 { + var ( + filterQuery = geth.FilterQuery{ + Addresses: []common.Address{address}, + FromBlock: big.NewInt(0).SetUint64(fromBlock), + ToBlock: big.NewInt(0).SetUint64(fromBlock + uint64(batchSize)), + Topics: [][]common.Hash{{consumerABI.Events["PerformingUpkeep"].ID}}, + } + ) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + logsInBatch, err := chainClient.FilterLogs(ctx, filterQuery) + cancel() + if err != nil { + l.Error().Err(err). + Interface("FilterQuery", filterQuery). + Str("Contract Address", consumerContract.Address()). + Str("Timeout", timeout.String()). + Msg("Error getting logs") + } + logs = append(logs, logsInBatch...) + time.Sleep(time.Millisecond * 500) + } + + if len(logs) > 0 { + delay := make([]int64, 0) + for _, log := range logs { + eventDetails, err := consumerABI.EventByID(log.Topics[0]) + require.NoError(t, err, "Error getting event details") + consumer, err := simple_log_upkeep_counter_wrapper.NewSimpleLogUpkeepCounter( + address, chainClient.Backend(), + ) + require.NoError(t, err, "Error getting consumer contract") + if eventDetails.Name == "PerformingUpkeep" { + parsedLog, err := consumer.ParsePerformingUpkeep(log) + require.NoError(t, err, "Error parsing log") + delay = append(delay, parsedLog.TimeToPerform.Int64()) + } + } + upkeepDelays = append(upkeepDelays, delay) + } + if (cIter+1)%batchSize == 0 { + time.Sleep(time.Millisecond * 500) + } + } + + l.Info().Interface("Upkeep Delays", upkeepDelays).Msg("Upkeep Delays") + + var allUpkeepDelays []int64 + + for _, upkeepDelay := range upkeepDelays { + allUpkeepDelays = append(allUpkeepDelays, upkeepDelay...) + } + + avg, median, ninetyPct, ninetyNinePct, maximum := testreporters.IntListStats(allUpkeepDelays) + l.Info(). + Float64("Average", avg).Int64("Median", median). + Int64("90th Percentile", ninetyPct).Int64("99th Percentile", ninetyNinePct). + Int64("Max", maximum).Msg("Upkeep Delays in seconds") + + l.Info(). + Int("Total Perform Count", len(allUpkeepDelays)). + Int("Total Events Emitted", numberOfEventsEmitted). + Int("Total Events Missed", numberOfEventsEmitted-len(allUpkeepDelays)). + Msg("Test completed") + + testReport := fmt.Sprintf("Upkeep Delays in seconds\nAverage: %f\nMedian: %d\n90th Percentile: %d\n"+ + "99th Percentile: %d\nMax: %d\nTotal Perform Count: %d\n\nTotal Events Emitted: %d\nTotal Events Missed: %d\nTest Duration: %s\n", + avg, median, ninetyPct, ninetyNinePct, maximum, len(allUpkeepDelays), numberOfEventsEmitted, + numberOfEventsEmitted-len(allUpkeepDelays), testDuration.String()) + + err = sendSlackNotification("Finished", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), + strconv.FormatInt(startTime.UnixMilli(), 10), strconv.FormatInt(endTime.UnixMilli(), 10), + []slack.Block{extraBlockWithText("\bTest Report\b\n```" + testReport + "```")}) + if err != nil { + l.Error().Err(err).Msg("Error sending slack notification") + } + + t.Cleanup(func() { + if err = actions.TeardownRemoteSuite(t, testEnvironment.Cfg.Namespace, chainlinkNodes, nil, chainClient); err != nil { + l.Error().Err(err).Msg("Error when tearing down remote suite") + } + }) + +} diff --git a/integration-tests/load/automationv2_1/gun.go b/integration-tests/load/automationv2_1/gun.go new file mode 100644 index 0000000000..a2863a6064 --- /dev/null +++ b/integration-tests/load/automationv2_1/gun.go @@ -0,0 +1,43 @@ +package automationv2_1 + +import ( + "github.com/rs/zerolog" + "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink/integration-tests/contracts" +) + +type LogTriggerGun struct { + triggerContract contracts.LogEmitter + upkeepContract contracts.KeeperConsumer + logger zerolog.Logger + numberOfEvents int +} + +func NewLogTriggerUser( + triggerContract contracts.LogEmitter, + upkeepContract contracts.KeeperConsumer, + logger zerolog.Logger, + numberOfEvents int, +) *LogTriggerGun { + return &LogTriggerGun{ + triggerContract: triggerContract, + upkeepContract: upkeepContract, + logger: logger, + numberOfEvents: numberOfEvents, + } +} + +func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.CallResult { + m.logger.Debug().Str("Trigger address", m.triggerContract.Address().String()).Msg("Triggering upkeep") + payload := make([]int, 0) + for i := 0; i < m.numberOfEvents; i++ { + payload = append(payload, 1) + } + _, err := m.triggerContract.EmitLogInts(payload) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + + return &wasp.CallResult{} +} diff --git a/integration-tests/load/automationv2_1/helpers.go b/integration-tests/load/automationv2_1/helpers.go new file mode 100644 index 0000000000..3c08199a9c --- /dev/null +++ b/integration-tests/load/automationv2_1/helpers.go @@ -0,0 +1,71 @@ +package automationv2_1 + +import ( + "fmt" + "os" + "strings" + + "github.com/rs/zerolog" + "github.com/slack-go/slack" + + "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" + reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + "github.com/smartcontractkit/chainlink/integration-tests/testreporters" +) + +func getEnv(key, fallback string) string { + if inputs, ok := os.LookupEnv("TEST_INPUTS"); ok { + values := strings.Split(inputs, ",") + for _, value := range values { + if strings.Contains(value, key) { + return strings.Split(value, "=")[1] + } + } + } + return fallback +} + +func extraBlockWithText(text string) slack.Block { + return slack.NewSectionBlock(slack.NewTextBlockObject( + "mrkdwn", text, false, false), nil, nil) +} + +func sendSlackNotification(header string, l zerolog.Logger, namespace string, numberOfNodes, + startingTime string, endingTime string, extraBlocks []slack.Block) error { + slackClient := slack.New(reportModel.SlackAPIKey) + + headerText := ":chainlink-keepers: Automation Load Test " + header + " :white_check_mark:" + + formattedDashboardUrl := fmt.Sprintf("%s?orgId=1&from=%s&to=%s&var-namespace=%s&var-number_of_nodes=%s", testreporters.DashboardUrl, startingTime, endingTime, namespace, numberOfNodes) + l.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") + + pyroscopeServer := os.Getenv(config.EnvVarPyroscopeServer) + pyroscopeEnvironment := os.Getenv(config.EnvVarPyroscopeEnvironment) + + formattedPyroscopeUrl := fmt.Sprintf("%s/?query=chainlink-node.cpu{Environment=\"%s\"}&from=%s&to=%s", pyroscopeServer, pyroscopeEnvironment, startingTime, endingTime) + + var notificationBlocks []slack.Block + + notificationBlocks = append(notificationBlocks, + slack.NewHeaderBlock(slack.NewTextBlockObject("plain_text", headerText, true, false))) + notificationBlocks = append(notificationBlocks, + slack.NewContextBlock("context_block", slack.NewTextBlockObject("plain_text", namespace, false, false))) + notificationBlocks = append(notificationBlocks, slack.NewDividerBlock()) + if pyroscopeServer != "" { + l.Info().Str("Pyroscope", formattedPyroscopeUrl).Msg("Dashboard URL") + notificationBlocks = append(notificationBlocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", + fmt.Sprintf("<%s|Pyroscope>", + formattedPyroscopeUrl), false, true), nil, nil)) + } + notificationBlocks = append(notificationBlocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", + fmt.Sprintf("<%s|Test Dashboard> \nNotifying <@%s>", + formattedDashboardUrl, reportModel.SlackUserID), false, true), nil, nil)) + + if len(extraBlocks) > 0 { + notificationBlocks = append(notificationBlocks, extraBlocks...) + } + + ts, err := reportModel.SendSlackMessage(slackClient, slack.MsgOptionBlocks(notificationBlocks...)) + l.Info().Str("ts", ts).Msg("Sent Slack Message") + return err +} diff --git a/integration-tests/testreporters/keeper_benchmark.go b/integration-tests/testreporters/keeper_benchmark.go index e9f2eaad7c..5db6cca3ec 100644 --- a/integration-tests/testreporters/keeper_benchmark.go +++ b/integration-tests/testreporters/keeper_benchmark.go @@ -133,7 +133,7 @@ func (k *KeeperBenchmarkTestReporter) WriteReport(folderLocation string) error { if err != nil { return err } - avg, median, ninetyPct, ninetyNinePct, max := intListStats(allDelays) + avg, median, ninetyPct, ninetyNinePct, max := IntListStats(allDelays) err = keeperReportWriter.Write([]string{ fmt.Sprint(totalEligibleCount), fmt.Sprint(totalPerformed), @@ -183,7 +183,7 @@ func (k *KeeperBenchmarkTestReporter) WriteReport(folderLocation string) error { } for contractIndex, report := range k.Reports { - avg, median, ninetyPct, ninetyNinePct, max = intListStats(report.AllCheckDelays) + avg, median, ninetyPct, ninetyNinePct, max = IntListStats(report.AllCheckDelays) err = keeperReportWriter.Write([]string{ fmt.Sprint(contractIndex), report.RegistryAddress, @@ -307,7 +307,7 @@ func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackC // intListStats helper calculates some statistics on an int list: avg, median, 90pct, 99pct, max // //nolint:revive -func intListStats(in []int64) (float64, int64, int64, int64, int64) { +func IntListStats(in []int64) (float64, int64, int64, int64, int64) { length := len(in) if length == 0 { return 0, 0, 0, 0, 0 From 3ed1689b9c50083770c550f9b5e072b7e283df58 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Fri, 17 Nov 2023 10:59:03 -0500 Subject: [PATCH 169/327] Fixes Live Test Blocker (#11322) --- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 99dd990bec..aed5e0682c 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -23,7 +23,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd - github.com/smartcontractkit/chainlink-testing-framework v1.19.0 + github.com/smartcontractkit/chainlink-testing-framework v1.19.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 0402b12f3f..896ae8c6d2 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2375,8 +2375,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab0 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= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.19.0 h1:ungyY1gYcXCtmdX2yCon8pkx9HgPPLg4aNAhKNZFP5c= -github.com/smartcontractkit/chainlink-testing-framework v1.19.0/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-testing-framework v1.19.1 h1:MdGM5jIrBi858Cv7qzfl1Qon93YW8InohAlDQqFoIb4= +github.com/smartcontractkit/chainlink-testing-framework v1.19.1/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= From 738146e8d39eeaeef8e1479a7a2879b24cf7930d Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:11:52 -0800 Subject: [PATCH 170/327] [Functions] Minor Listener refactor (#11323) 1. Add an interface type to make Listener mockable 2. Return internal errors from handleRequest() --- core/services/functions/listener.go | 74 +++++++++++-------- core/services/functions/listener_test.go | 21 +++++- .../functions/mocks/functions_listener.go | 71 ++++++++++++++++++ 3 files changed, 134 insertions(+), 32 deletions(-) create mode 100644 core/services/functions/mocks/functions_listener.go diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index 5614c5331d..efb40330cb 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -29,8 +29,6 @@ import ( ) var ( - _ job.ServiceCtx = &FunctionsListener{} - sizeBuckets = []float64{ 1024, 1024 * 4, @@ -118,7 +116,14 @@ const ( FlagSecretsMaxSize uint32 = 2 ) -type FunctionsListener struct { +//go:generate mockery --quiet --name FunctionsListener --output ./mocks/ --case=underscore +type FunctionsListener interface { + job.ServiceCtx + + HandleOffchainRequest(ctx context.Context, request *OffchainRequest) error +} + +type functionsListener struct { services.StateMachine client client.Client contractAddressHex string @@ -137,11 +142,13 @@ type FunctionsListener struct { logPollerWrapper evmrelayTypes.LogPollerWrapper } -func (l *FunctionsListener) HealthReport() map[string]error { +var _ FunctionsListener = &functionsListener{} + +func (l *functionsListener) HealthReport() map[string]error { return map[string]error{l.Name(): l.Healthy()} } -func (l *FunctionsListener) Name() string { return l.logger.Name() } +func (l *functionsListener) Name() string { return l.logger.Name() } func formatRequestId(requestId [32]byte) string { return fmt.Sprintf("0x%x", requestId) @@ -159,8 +166,8 @@ func NewFunctionsListener( urlsMonEndpoint commontypes.MonitoringEndpoint, decryptor threshold.Decryptor, logPollerWrapper evmrelayTypes.LogPollerWrapper, -) *FunctionsListener { - return &FunctionsListener{ +) *functionsListener { + return &functionsListener{ client: client, contractAddressHex: contractAddressHex, job: job, @@ -177,7 +184,7 @@ func NewFunctionsListener( } // Start complies with job.Service -func (l *FunctionsListener) Start(context.Context) error { +func (l *functionsListener) Start(context.Context) error { return l.StartOnce("FunctionsListener", func() error { l.serviceContext, l.serviceCancel = context.WithCancel(context.Background()) @@ -204,7 +211,7 @@ func (l *FunctionsListener) Start(context.Context) error { } // Close complies with job.Service -func (l *FunctionsListener) Close() error { +func (l *functionsListener) Close() error { return l.StopOnce("FunctionsListener", func() error { l.serviceCancel() close(l.chStop) @@ -213,7 +220,7 @@ func (l *FunctionsListener) Close() error { }) } -func (l *FunctionsListener) processOracleEventsV1() { +func (l *functionsListener) processOracleEventsV1() { defer l.shutdownWaitGroup.Done() freqMillis := l.pluginConfig.ListenerEventsCheckFrequencyMillis if freqMillis == 0 { @@ -247,7 +254,7 @@ func (l *FunctionsListener) processOracleEventsV1() { } } -func (l *FunctionsListener) getNewHandlerContext() (context.Context, context.CancelFunc) { +func (l *functionsListener) getNewHandlerContext() (context.Context, context.CancelFunc) { timeoutSec := l.pluginConfig.ListenerEventHandlerTimeoutSec if timeoutSec == 0 { return context.WithCancel(l.serviceContext) @@ -255,7 +262,7 @@ func (l *FunctionsListener) getNewHandlerContext() (context.Context, context.Can return context.WithTimeout(l.serviceContext, time.Duration(timeoutSec)*time.Second) } -func (l *FunctionsListener) setError(ctx context.Context, requestId RequestID, errType ErrType, errBytes []byte) { +func (l *functionsListener) setError(ctx context.Context, requestId RequestID, errType ErrType, errBytes []byte) { if errType == INTERNAL_ERROR { promRequestInternalError.WithLabelValues(l.contractAddressHex).Inc() } else { @@ -267,7 +274,7 @@ func (l *FunctionsListener) setError(ctx context.Context, requestId RequestID, e } } -func (l *FunctionsListener) getMaxCBORsize(flags RequestFlags) uint32 { +func (l *functionsListener) getMaxCBORsize(flags RequestFlags) uint32 { idx := flags[FlagCBORMaxSize] if int(idx) >= len(l.pluginConfig.MaxRequestSizesList) { return l.pluginConfig.MaxRequestSizeBytes // deprecated @@ -275,7 +282,7 @@ func (l *FunctionsListener) getMaxCBORsize(flags RequestFlags) uint32 { return l.pluginConfig.MaxRequestSizesList[idx] } -func (l *FunctionsListener) getMaxSecretsSize(flags RequestFlags) uint32 { +func (l *functionsListener) getMaxSecretsSize(flags RequestFlags) uint32 { idx := flags[FlagSecretsMaxSize] if int(idx) >= len(l.pluginConfig.MaxSecretsSizesList) { return math.MaxUint32 // not enforced if not configured @@ -283,7 +290,7 @@ func (l *FunctionsListener) getMaxSecretsSize(flags RequestFlags) uint32 { return l.pluginConfig.MaxSecretsSizesList[idx] } -func (l *FunctionsListener) HandleOffchainRequest(ctx context.Context, request *OffchainRequest) error { +func (l *functionsListener) HandleOffchainRequest(ctx context.Context, request *OffchainRequest) error { if request == nil { return errors.New("HandleOffchainRequest: received nil request") } @@ -318,11 +325,10 @@ func (l *FunctionsListener) HandleOffchainRequest(ctx context.Context, request * } return err } - l.handleRequest(ctx, requestId, request.SubscriptionId, subscriptionOwner, RequestFlags{}, &request.Data) - return nil + return l.handleRequest(ctx, requestId, request.SubscriptionId, subscriptionOwner, RequestFlags{}, &request.Data) } -func (l *FunctionsListener) handleOracleRequestV1(request *evmrelayTypes.OracleRequest) { +func (l *functionsListener) handleOracleRequestV1(request *evmrelayTypes.OracleRequest) { defer l.shutdownWaitGroup.Done() l.logger.Infow("handleOracleRequestV1: oracle request v1 received", "requestID", formatRequestId(request.RequestId)) ctx, cancel := l.getNewHandlerContext() @@ -354,10 +360,13 @@ func (l *FunctionsListener) handleOracleRequestV1(request *evmrelayTypes.OracleR l.setError(ctx, request.RequestId, USER_ERROR, []byte(err.Error())) return } - l.handleRequest(ctx, request.RequestId, request.SubscriptionId, request.SubscriptionOwner, request.Flags, requestData) + err = l.handleRequest(ctx, request.RequestId, request.SubscriptionId, request.SubscriptionOwner, request.Flags, requestData) + if err != nil { + l.logger.Errorw("handleOracleRequestV1: error in handleRequest()", "requestID", formatRequestId(request.RequestId), "err", err) + } } -func (l *FunctionsListener) parseCBOR(requestId RequestID, cborData []byte, maxSizeBytes uint32) (*RequestData, error) { +func (l *functionsListener) parseCBOR(requestId RequestID, cborData []byte, maxSizeBytes uint32) (*RequestData, error) { if maxSizeBytes > 0 && uint32(len(cborData)) > maxSizeBytes { l.logger.Errorw("request too big", "requestID", formatRequestId(requestId), "requestSize", len(cborData), "maxRequestSize", maxSizeBytes) return nil, fmt.Errorf("request too big (max %d bytes)", maxSizeBytes) @@ -372,7 +381,8 @@ func (l *FunctionsListener) parseCBOR(requestId RequestID, cborData []byte, maxS return &requestData, nil } -func (l *FunctionsListener) handleRequest(ctx context.Context, requestID RequestID, subscriptionId uint64, subscriptionOwner common.Address, flags RequestFlags, requestData *RequestData) { +// Handle secret fetching/decryption and functions computation. Return error only for internal errors. +func (l *functionsListener) handleRequest(ctx context.Context, requestID RequestID, subscriptionId uint64, subscriptionOwner common.Address, flags RequestFlags, requestData *RequestData) error { startTime := time.Now() defer func() { duration := time.Since(startTime) @@ -385,26 +395,26 @@ func (l *FunctionsListener) handleRequest(ctx context.Context, requestID Request if err != nil { l.logger.Errorw("failed to create ExternalAdapterClient", "requestID", requestIDStr, "err", err) l.setError(ctx, requestID, INTERNAL_ERROR, []byte(err.Error())) - return + return err } nodeProvidedSecrets, userErr, internalErr := l.getSecrets(ctx, eaClient, requestID, subscriptionOwner, requestData) if internalErr != nil { l.logger.Errorw("internal error during getSecrets", "requestID", requestIDStr, "err", internalErr) l.setError(ctx, requestID, INTERNAL_ERROR, []byte(internalErr.Error())) - return + return internalErr } if userErr != nil { l.logger.Debugw("user error during getSecrets", "requestID", requestIDStr, "err", userErr) l.setError(ctx, requestID, USER_ERROR, []byte(userErr.Error())) - return + return nil // user error } maxSecretsSize := l.getMaxSecretsSize(flags) if uint32(len(nodeProvidedSecrets)) > maxSecretsSize { l.logger.Errorw("secrets size too big", "requestID", requestIDStr, "secretsSize", len(nodeProvidedSecrets), "maxSecretsSize", maxSecretsSize) l.setError(ctx, requestID, USER_ERROR, []byte("secrets size too big")) - return + return nil // user error } computationResult, computationError, domains, err := eaClient.RunComputation(ctx, requestIDStr, l.job.Name.ValueOrZero(), subscriptionOwner.Hex(), subscriptionId, flags, nodeProvidedSecrets, requestData) @@ -412,7 +422,7 @@ func (l *FunctionsListener) handleRequest(ctx context.Context, requestID Request if err != nil { l.logger.Errorw("internal adapter error", "requestID", requestIDStr, "err", err) l.setError(ctx, requestID, INTERNAL_ERROR, []byte(err.Error())) - return + return err } if len(computationError) == 0 && len(computationResult) == 0 { @@ -438,11 +448,13 @@ func (l *FunctionsListener) handleRequest(ctx context.Context, requestID Request l.logger.Debugw("saving computation result", "requestID", requestIDStr) if err2 := l.pluginORM.SetResult(requestID, computationResult, time.Now(), pg.WithParentCtx(ctx)); err2 != nil { l.logger.Errorw("call to SetResult failed", "requestID", requestIDStr, "err", err2) + return err2 } } + return nil } -func (l *FunctionsListener) handleOracleResponseV1(response *evmrelayTypes.OracleResponse) { +func (l *functionsListener) handleOracleResponseV1(response *evmrelayTypes.OracleResponse) { defer l.shutdownWaitGroup.Done() l.logger.Infow("oracle response v1 received", "requestID", formatRequestId(response.RequestId)) @@ -454,7 +466,7 @@ func (l *FunctionsListener) handleOracleResponseV1(response *evmrelayTypes.Oracl promRequestConfirmed.WithLabelValues(l.contractAddressHex).Inc() } -func (l *FunctionsListener) timeoutRequests() { +func (l *functionsListener) timeoutRequests() { defer l.shutdownWaitGroup.Done() timeoutSec, freqSec, batchSize := l.pluginConfig.RequestTimeoutSec, l.pluginConfig.RequestTimeoutCheckFrequencySec, l.pluginConfig.RequestTimeoutBatchLookupSize if timeoutSec == 0 || freqSec == 0 || batchSize == 0 { @@ -490,7 +502,7 @@ func (l *FunctionsListener) timeoutRequests() { } } -func (l *FunctionsListener) pruneRequests() { +func (l *functionsListener) pruneRequests() { defer l.shutdownWaitGroup.Done() maxStoredRequests, freqSec, batchSize := l.pluginConfig.PruneMaxStoredRequests, l.pluginConfig.PruneCheckFrequencySec, l.pluginConfig.PruneBatchSize if maxStoredRequests == 0 { @@ -532,7 +544,7 @@ func (l *FunctionsListener) pruneRequests() { } } -func (l *FunctionsListener) reportSourceCodeDomains(requestId RequestID, domains []string) { +func (l *functionsListener) reportSourceCodeDomains(requestId RequestID, domains []string) { r := &telem.FunctionsRequest{ RequestId: formatRequestId(requestId), NodeAddress: l.job.OCR2OracleSpec.TransmitterID.ValueOrZero(), @@ -547,7 +559,7 @@ func (l *FunctionsListener) reportSourceCodeDomains(requestId RequestID, domains } } -func (l *FunctionsListener) getSecrets(ctx context.Context, eaClient ExternalAdapterClient, requestID RequestID, subscriptionOwner common.Address, requestData *RequestData) (decryptedSecrets string, userError, internalError error) { +func (l *functionsListener) getSecrets(ctx context.Context, eaClient ExternalAdapterClient, requestID RequestID, subscriptionOwner common.Address, requestData *RequestData) (decryptedSecrets string, userError, internalError error) { if l.decryptor == nil { l.logger.Warn("Decryptor not configured") return "", nil, nil diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index ac2bc64184..ecad9e4cce 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -46,7 +46,7 @@ import ( ) type FunctionsListenerUniverse struct { - service *functions_service.FunctionsListener + service functions_service.FunctionsListener bridgeAccessor *functions_mocks.BridgeAccessor eaClient *functions_mocks.ExternalAdapterClient pluginORM *functions_mocks.ORM @@ -219,6 +219,25 @@ func TestFunctionsListener_HandleOffchainRequest_Invalid(t *testing.T) { require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) } +func TestFunctionsListener_HandleOffchainRequest_InternalError(t *testing.T) { + testutils.SkipShortDB(t) + t.Parallel() + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) + uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) + uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, nil, errors.New("error")) + uni.pluginORM.On("SetError", RequestID, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + + request := &functions_service.OffchainRequest{ + RequestId: RequestID[:], + RequestInitiator: SubscriptionOwner.Bytes(), + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner.Bytes(), + Data: functions_service.RequestData{}, + } + require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) +} + func TestFunctionsListener_HandleOracleRequestV1_ComputationError(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() diff --git a/core/services/functions/mocks/functions_listener.go b/core/services/functions/mocks/functions_listener.go new file mode 100644 index 0000000000..d2aeb2ddab --- /dev/null +++ b/core/services/functions/mocks/functions_listener.go @@ -0,0 +1,71 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package mocks + +import ( + context "context" + + functions "github.com/smartcontractkit/chainlink/v2/core/services/functions" + mock "github.com/stretchr/testify/mock" +) + +// FunctionsListener is an autogenerated mock type for the FunctionsListener type +type FunctionsListener struct { + mock.Mock +} + +// Close provides a mock function with given fields: +func (_m *FunctionsListener) 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 +} + +// HandleOffchainRequest provides a mock function with given fields: ctx, request +func (_m *FunctionsListener) HandleOffchainRequest(ctx context.Context, request *functions.OffchainRequest) error { + ret := _m.Called(ctx, request) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *functions.OffchainRequest) error); ok { + r0 = rf(ctx, request) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Start provides a mock function with given fields: _a0 +func (_m *FunctionsListener) 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 +} + +// NewFunctionsListener creates a new instance of FunctionsListener. 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 NewFunctionsListener(t interface { + mock.TestingT + Cleanup(func()) +}) *FunctionsListener { + mock := &FunctionsListener{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 5f09e55075e98e8863fe686f41682d4feca268b5 Mon Sep 17 00:00:00 2001 From: Tate Date: Fri, 17 Nov 2023 12:10:28 -0700 Subject: [PATCH 171/327] [TT-707] Build Test Base Image As Needed in CI (#11329) --- .github/actions/build-test-image/action.yml | 62 +++++++++++++++++-- .../workflows/integration-tests-publish.yml | 20 ++---- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index 4b1dce6ee1..e6c759109b 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -17,9 +17,6 @@ inputs: description: The test suites to build into the image default: chaos migration performance reorg smoke soak benchmark load/automationv2_1 required: false - base_image_tag: - description: The test base image version to use, if not provided it will use the version from the ./integration-tests/go.mod file - required: false QA_AWS_ROLE_TO_ASSUME: description: The AWS role to assume as the CD user, if any. Used in configuring the docker/login-action required: true @@ -33,14 +30,66 @@ inputs: runs: using: composite steps: + + # Base Test Image Logic - name: Get CTF Version - if: ${{ inputs.base_image_tag == '' }} id: version uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: go-project-path: ./integration-tests module-name: github.com/smartcontractkit/chainlink-testing-framework - enforce-semantic-tag: "true" # it has to be in the form of v1.2.3 or the image won't exist + enforce-semantic-tag: false + - name: Get CTF sha + if: steps.version.outputs.is_semantic == 'false' + id: short_sha + env: + VERSION: ${{ steps.version.outputs.version }} + shell: bash + run: | + short_sha="${VERSION##*-}" + echo "short sha is: ${short_sha}" + echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" + - name: Checkout chainlink-testing-framework + if: steps.version.outputs.is_semantic == 'false' + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + repository: smartcontractkit/chainlink-testing-framework + ref: main + fetch-depth: 0 + path: ctf + - name: Get long sha + if: steps.version.outputs.is_semantic == 'false' + id: long_sha + env: + SHORT_SHA: ${{ steps.short_sha.outputs.short_sha }} + shell: bash + run: | + cd ctf + long_sha=$(git rev-parse ${SHORT_SHA}) + echo "sha is: ${long_sha}" + echo "long_sha=${long_sha}" >> "$GITHUB_OUTPUT" + - name: Check if test base image exists + if: steps.version.outputs.is_semantic == 'false' + id: check-base-image + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + with: + repository: ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image + tag: ${{ steps.long_sha.outputs.long_sha }} + AWS_REGION: ${{ inputs.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} + - name: Build Base Image + if: steps.version.outputs.is_semantic == 'false' && steps.check-base-image.outputs.exists == 'false' + uses: smartcontractkit/chainlink-github-actions/docker/build-push@ce87f8986ca18336cc5015df75916c2ec0a7c4b3 # v2.1.2 + env: + BASE_IMAGE_NAME: ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image:${{ steps.long_sha.outputs.long_sha }} + with: + tags: ${{ env.BASE_IMAGE_NAME }} + file: ctf/k8s/Dockerfile.base + AWS_REGION: ${{ inputs.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} + # End Base Image Logic + + # Test Runner Logic - name: Check if image exists id: check-image uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 @@ -59,7 +108,7 @@ runs: file: ./integration-tests/test.Dockerfile build-args: | BASE_IMAGE=${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image - IMAGE_VERSION=${{ inputs.base_image_tag || steps.version.outputs.version }} + IMAGE_VERSION=${{ steps.long_sha.outputs.long_sha || steps.version.outputs.version }} SUITES="${{ inputs.suites }}" AWS_REGION: ${{ inputs.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} @@ -71,3 +120,4 @@ runs: run: | echo "### ${INPUTS_REPOSITORY} image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${INPUTS_TAG}\`" >>$GITHUB_STEP_SUMMARY + # End Test Runner Logic diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index 9eb2673db2..176947a092 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -6,13 +6,6 @@ on: branches: - develop workflow_dispatch: - inputs: - ctf-base-image-tag: - description: | - 'The tag of the CTF base image to be used, - typically something like v1.18.6 from https://github.com/smartcontractkit/chainlink-testing-framework/releases - or a custom tag or branch you have pushed.' - required: true env: ECR_TAG: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:develop @@ -39,20 +32,15 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} - - name: Setup Other Tags + - name: Setup Other Tags If Not Workflow Dispatch id: tags - env: - BASE_IMAGE_TAG: ${{ inputs.ctf-base-image-tag}} + if: github.event_name != 'workflow_dispatch' run: | - if [ -z "${BASE_IMAGE_TAG+x}" ]; then - echo "ctf-base-image-tag is not set, we are part of a merge and want to push the develop tag" - echo "other_tags=${ECR_TAG}" >> $GITHUB_OUTPUT - fi + echo "other_tags=${ECR_TAG}" >> $GITHUB_OUTPUT - name: Build Image uses: ./.github/actions/build-test-image with: other_tags: ${{ steps.tags.outputs.other_tags }} - base_image_tag: ${{ inputs.ctf-base-image-tag }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} @@ -68,7 +56,7 @@ jobs: build-chainlink-image: environment: integration # Only run this build for workflow_dispatch - if: ${{ inputs.ctf-base-image-tag != '' }} + if: github.event_name == 'workflow_dispatch' permissions: id-token: write contents: read From b2c1a17cf529317d70674aa9f73596a4a426f418 Mon Sep 17 00:00:00 2001 From: JonWong203 <82334955+JonWong203@users.noreply.github.com> Date: Fri, 17 Nov 2023 14:19:54 -0500 Subject: [PATCH 172/327] Automation Telemetry: Send BlockNumber and Node Version (#9927) * rebase on toml feature flag * fixes + send node version rebase on feature flag PR * fixes * comments * minor changes * lint * constant added * logger * toggle by feature flag * minor fixes * marshal error exits start() * marshal error fix * add automation custom telem to job * rename toml tag * test * removed print statement * merge * configDigest go routine getter * configDigest var * refactor1 * send NodeVersion msg every new ConfigDigest * lint * refactor * move registry creation outside delegate.go * plugin config bool flag * custom telem for 2.1 * block subscriber + thread controller * ContractConfigTracker * reset forge-std * use toml config flag * set toml flag default to true * plugin config bool flag * make generate * refactor * hourly node version msg * fix tests * lint fix * goimports fixed * goimport fix 2 --------- Co-authored-by: FelixFan1992 --- core/config/docs/core.toml | 2 +- core/services/chainlink/config_ocr2_test.go | 2 +- core/services/chainlink/config_test.go | 4 +- .../testdata/config-empty-effective.toml | 2 +- .../chainlink/testdata/config-full.toml | 2 +- .../config-multi-chain-effective.toml | 2 +- core/services/ocr2/delegate.go | 23 ++- .../ocr2/plugins/ocr2keeper/config.go | 2 + .../plugins/ocr2keeper/custom_telemetry.go | 156 +++++++++++++++++ .../ocr2keeper/custom_telemetry_test.go | 17 ++ .../evm21/autotelemetry21/custom_telemetry.go | 160 ++++++++++++++++++ .../autotelemetry21/custom_telemetry_test.go | 56 ++++++ .../testdata/config-empty-effective.toml | 2 +- core/web/resolver/testdata/config-full.toml | 2 +- .../config-multi-chain-effective.toml | 2 +- docs/CONFIG.md | 4 +- testdata/scripts/node/validate/default.txtar | 2 +- .../disk-based-logging-disabled.txtar | 2 +- .../validate/disk-based-logging-no-dir.txtar | 2 +- .../node/validate/disk-based-logging.txtar | 2 +- testdata/scripts/node/validate/invalid.txtar | 2 +- testdata/scripts/node/validate/valid.txtar | 2 +- testdata/scripts/node/validate/warnings.txtar | 2 +- 23 files changed, 431 insertions(+), 21 deletions(-) create mode 100644 core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go create mode 100644 core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry_test.go diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 0a8e6aba3b..148de90cd9 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -352,7 +352,7 @@ KeyBundleID = '7a5f66bbe6594259325bf2b4f5b1a9c900000000000000000000000000000000' # CaptureEATelemetry toggles collecting extra information from External Adaptares CaptureEATelemetry = false # Default # CaptureAutomationCustomTelemetry toggles collecting automation specific telemetry -CaptureAutomationCustomTelemetry = false # Default +CaptureAutomationCustomTelemetry = true # Default # DefaultTransactionQueueDepth controls the queue size for `DropOldestStrategy` in OCR2. Set to 0 to use `SendEvery` strategy instead. DefaultTransactionQueueDepth = 1 # Default # SimulateTransactions enables transaction simulation for OCR2. diff --git a/core/services/chainlink/config_ocr2_test.go b/core/services/chainlink/config_ocr2_test.go index 6642748924..5bf84934d1 100644 --- a/core/services/chainlink/config_ocr2_test.go +++ b/core/services/chainlink/config_ocr2_test.go @@ -38,7 +38,7 @@ func TestOCR2Config(t *testing.T) { require.Equal(t, false, ocr2Cfg.TraceLogging()) require.Equal(t, uint32(1), ocr2Cfg.DefaultTransactionQueueDepth()) require.Equal(t, false, ocr2Cfg.CaptureEATelemetry()) - require.Equal(t, false, ocr2Cfg.CaptureAutomationCustomTelemetry()) + require.Equal(t, true, ocr2Cfg.CaptureAutomationCustomTelemetry()) keyBundleID, err := ocr2Cfg.KeyBundleID() require.NoError(t, err) diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 0caae3607f..fbadb379ca 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -385,7 +385,7 @@ func TestConfig_Marshal(t *testing.T) { DatabaseTimeout: models.MustNewDuration(8 * time.Second), KeyBundleID: ptr(models.MustSha256HashFromHex("7a5f66bbe6594259325bf2b4f5b1a9c9")), CaptureEATelemetry: ptr(false), - CaptureAutomationCustomTelemetry: ptr(false), + CaptureAutomationCustomTelemetry: ptr(true), DefaultTransactionQueueDepth: ptr[uint32](1), SimulateTransactions: ptr(false), TraceLogging: ptr(false), @@ -848,7 +848,7 @@ ContractTransmitterTransmitTimeout = '1m0s' DatabaseTimeout = '8s' KeyBundleID = '7a5f66bbe6594259325bf2b4f5b1a9c900000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index f5d775fe74..b897fba7f1 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -137,7 +137,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 5ede10ef69..531c98d734 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -143,7 +143,7 @@ ContractTransmitterTransmitTimeout = '1m0s' DatabaseTimeout = '8s' KeyBundleID = '7a5f66bbe6594259325bf2b4f5b1a9c900000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 9dd0be8f5d..c743601ced 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -137,7 +137,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '20s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 20c1351297..944c04c8d4 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -49,6 +49,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21" ocr2keeper21core "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" ocr2coordinator "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/coordinator" @@ -174,6 +175,7 @@ type ocr2Config interface { DatabaseTimeout() time.Duration KeyBundleID() (string, error) TraceLogging() bool + CaptureAutomationCustomTelemetry() bool } type insecureConfig interface { @@ -1161,7 +1163,7 @@ func (d *Delegate) newServicesOCR2Keepers21( d.cfg.JobPipeline().MaxSuccessfulRuns(), ) - return []job.ServiceCtx{ + automationServices := []job.ServiceCtx{ runResultSaver, keeperProvider, services.Registry(), @@ -1171,7 +1173,24 @@ func (d *Delegate) newServicesOCR2Keepers21( services.UpkeepStateStore(), services.TransmitEventProvider(), pluginService, - }, nil + } + + if cfg.CaptureAutomationCustomTelemetry != nil && *cfg.CaptureAutomationCustomTelemetry || + cfg.CaptureAutomationCustomTelemetry == nil && d.cfg.OCR2().CaptureAutomationCustomTelemetry() { + endpoint := d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.AutomationCustom) + customTelemService, custErr := autotelemetry21.NewAutomationCustomTelemetryService( + endpoint, + lggr, + services.BlockSubscriber(), + keeperProvider.ContractConfigTracker(), + ) + if custErr != nil { + return nil, errors.Wrap(custErr, "Error when creating AutomationCustomTelemetryService") + } + automationServices = append(automationServices, customTelemService) + } + + return automationServices, nil } func (d *Delegate) newServicesOCR2Keepers20( diff --git a/core/services/ocr2/plugins/ocr2keeper/config.go b/core/services/ocr2/plugins/ocr2keeper/config.go index d3035878ec..ec56f9c699 100644 --- a/core/services/ocr2/plugins/ocr2keeper/config.go +++ b/core/services/ocr2/plugins/ocr2keeper/config.go @@ -58,6 +58,8 @@ type PluginConfig struct { ServiceQueueLength int `json:"serviceQueueLength"` // ContractVersion is the contract version ContractVersion string `json:"contractVersion"` + // CaptureAutomationCustomTelemetry is a bool flag to toggle Custom Telemetry Service + CaptureAutomationCustomTelemetry *bool `json:"captureAutomationCustomTelemetry,omitempty"` } func ValidatePluginConfig(cfg PluginConfig) error { diff --git a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go new file mode 100644 index 0000000000..0f03ae5bd0 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go @@ -0,0 +1,156 @@ +package ocr2keeper + +import ( + "context" + "encoding/hex" + "time" + + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "google.golang.org/protobuf/proto" + + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" + "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" + "github.com/smartcontractkit/chainlink/v2/core/static" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type AutomationCustomTelemetryService struct { + utils.StartStopOnce + monitoringEndpoint commontypes.MonitoringEndpoint + blockSubscriber *evm21.BlockSubscriber + blockSubChanID int + threadCtrl utils.ThreadControl + lggr logger.Logger + configDigest [32]byte + contractConfigTracker types.ContractConfigTracker +} + +// NewAutomationCustomTelemetryService creates a telemetry service for new blocks and node version +func NewAutomationCustomTelemetryService(me commontypes.MonitoringEndpoint, + lggr logger.Logger, blocksub *evm21.BlockSubscriber, configTracker types.ContractConfigTracker) (*AutomationCustomTelemetryService, error) { + return &AutomationCustomTelemetryService{ + monitoringEndpoint: me, + threadCtrl: utils.NewThreadControl(), + lggr: lggr.Named("AutomationCustomTelem"), + contractConfigTracker: configTracker, + blockSubscriber: blocksub, + }, nil +} + +// Start starts Custom Telemetry Service, sends 1 NodeVersion message to endpoint at start and sends new BlockNumber messages +func (e *AutomationCustomTelemetryService) Start(ctx context.Context) error { + return e.StartOnce("AutomationCustomTelemetryService", func() error { + e.lggr.Infof("Starting: Custom Telemetry Service") + _, configDetails, err := e.contractConfigTracker.LatestConfigDetails(ctx) + if err != nil { + e.lggr.Errorf("Error occurred while getting newestConfigDetails for initialization %s", err) + } else { + e.configDigest = configDetails + e.sendNodeVersionMsg() + } + e.threadCtrl.Go(func(ctx context.Context) { + ticker := time.NewTicker(1 * time.Minute) + defer ticker.Stop() + for { + select { + case <-ticker.C: + _, newConfigDigest, err := e.contractConfigTracker.LatestConfigDetails(ctx) + if err != nil { + e.lggr.Errorf("Error occurred while getting newestConfigDetails in configDigest loop %s", err) + } + if newConfigDigest != e.configDigest { + e.configDigest = newConfigDigest + e.sendNodeVersionMsg() + } + case <-ctx.Done(): + return + } + } + }) + + chanID, blockSubscriberChan, blockSubErr := e.blockSubscriber.Subscribe() + if blockSubErr != nil { + e.lggr.Errorf("Block Subscriber Error: Subscribe(): %s", blockSubErr) + + } else { + e.blockSubChanID = chanID + e.threadCtrl.Go(func(ctx context.Context) { + e.lggr.Infof("Started: Sending BlockNumber Messages") + for { + select { + case blockHistory := <-blockSubscriberChan: + latestBlockKey, err := blockHistory.Latest() + if err != nil { + e.lggr.Errorf("BlockSubscriber BlockHistory.Latest() failed: %s", err) + continue + } + e.sendBlockNumberMsg(latestBlockKey) + case <-ctx.Done(): + return + } + } + }) + } + return nil + }) +} + +// Close stops go routines and closes channels +func (e *AutomationCustomTelemetryService) Close() error { + // use utils + return e.StopOnce("AutomationCustomTelemetryService", func() error { + e.lggr.Infof("Stopping: custom telemetry service") + e.threadCtrl.Close() + err := e.blockSubscriber.Unsubscribe(e.blockSubChanID) + if err != nil { + return err + } + e.lggr.Infof("Stopped: Custom telemetry service") + return nil + }) +} + +func (e *AutomationCustomTelemetryService) sendNodeVersionMsg() { + vMsg := &telem.NodeVersion{ + Timestamp: uint64(time.Now().UTC().UnixMilli()), + NodeVersion: static.Version, + ConfigDigest: e.configDigest[:], + } + wrappedVMsg := &telem.AutomationTelemWrapper{ + Msg: &telem.AutomationTelemWrapper_NodeVersion{ + NodeVersion: vMsg, + }, + } + bytes, err := proto.Marshal(wrappedVMsg) + if err != nil { + e.lggr.Errorf("Error occurred while marshalling the Node Version Message %s: %v", wrappedVMsg.String(), err) + } else { + e.monitoringEndpoint.SendLog(bytes) + e.lggr.Infof("NodeVersion Message Sent to Endpoint: %d", vMsg.Timestamp) + } +} + +func (e *AutomationCustomTelemetryService) sendBlockNumberMsg(blockKey ocr2keepers.BlockKey) { + blockNumMsg := &telem.BlockNumber{ + Timestamp: uint64(time.Now().UTC().UnixMilli()), + BlockNumber: uint64(blockKey.Number), + BlockHash: hex.EncodeToString(blockKey.Hash[:]), + ConfigDigest: e.configDigest[:], + } + wrappedBlockNumMsg := &telem.AutomationTelemWrapper{ + Msg: &telem.AutomationTelemWrapper_BlockNumber{ + BlockNumber: blockNumMsg, + }, + } + b, err := proto.Marshal(wrappedBlockNumMsg) + if err != nil { + e.lggr.Errorf("Error occurred while marshalling the Block Num Message %s: %v", wrappedBlockNumMsg.String(), err) + } else { + e.monitoringEndpoint.SendLog(b) + e.lggr.Infof("BlockNumber Message Sent to Endpoint: %d", blockNumMsg.Timestamp) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go new file mode 100644 index 0000000000..a40a3f3525 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go @@ -0,0 +1,17 @@ +package ocr2keeper + +import ( + "testing" +) + +func TestNewAutomationCustomTelemetryService(t *testing.T) { + // me := &MockMonitoringEndpoint{} + // lggr := &MockLogger{} + // blocksub := &MockBlockSubscriber{} + // configTracker := &MockContractConfigTracker{} + + // service, err := NewAutomationCustomTelemetryService(me, lggr, blocksub, configTracker) + // if err != nil { + // t.Errorf("Expected no error, but got: %v", err) + // } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go new file mode 100644 index 0000000000..93f35ce0d2 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go @@ -0,0 +1,160 @@ +package autotelemetry21 + +import ( + "context" + "encoding/hex" + "time" + + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "google.golang.org/protobuf/proto" + + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" + "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" + "github.com/smartcontractkit/chainlink/v2/core/static" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type AutomationCustomTelemetryService struct { + utils.StartStopOnce + monitoringEndpoint commontypes.MonitoringEndpoint + blockSubscriber *evm21.BlockSubscriber + blockSubChanID int + threadCtrl utils.ThreadControl + lggr logger.Logger + configDigest [32]byte + contractConfigTracker types.ContractConfigTracker +} + +// NewAutomationCustomTelemetryService creates a telemetry service for new blocks and node version +func NewAutomationCustomTelemetryService(me commontypes.MonitoringEndpoint, + lggr logger.Logger, blocksub *evm21.BlockSubscriber, configTracker types.ContractConfigTracker) (*AutomationCustomTelemetryService, error) { + return &AutomationCustomTelemetryService{ + monitoringEndpoint: me, + threadCtrl: utils.NewThreadControl(), + lggr: lggr.Named("AutomationCustomTelem"), + contractConfigTracker: configTracker, + blockSubscriber: blocksub, + }, nil +} + +// Start starts Custom Telemetry Service, sends 1 NodeVersion message to endpoint at start and sends new BlockNumber messages +func (e *AutomationCustomTelemetryService) Start(ctx context.Context) error { + return e.StartOnce("AutomationCustomTelemetryService", func() error { + e.lggr.Infof("Starting: Custom Telemetry Service") + _, configDetails, err := e.contractConfigTracker.LatestConfigDetails(ctx) + if err != nil { + e.lggr.Errorf("Error occurred while getting newestConfigDetails for initialization %s", err) + } else { + e.configDigest = configDetails + e.sendNodeVersionMsg() + } + e.threadCtrl.Go(func(ctx context.Context) { + minuteTicker := time.NewTicker(1 * time.Minute) + hourTicker := time.NewTicker(1 * time.Hour) + defer minuteTicker.Stop() + defer hourTicker.Stop() + for { + select { + case <-minuteTicker.C: + _, newConfigDigest, err := e.contractConfigTracker.LatestConfigDetails(ctx) + if err != nil { + e.lggr.Errorf("Error occurred while getting newestConfigDetails in configDigest loop %s", err) + } + if newConfigDigest != e.configDigest { + e.configDigest = newConfigDigest + e.sendNodeVersionMsg() + } + case <-hourTicker.C: + e.sendNodeVersionMsg() + case <-ctx.Done(): + return + } + } + }) + + chanID, blockSubscriberChan, blockSubErr := e.blockSubscriber.Subscribe() + if blockSubErr != nil { + e.lggr.Errorf("Block Subscriber Error: Subscribe(): %s", blockSubErr) + return blockSubErr + } + e.blockSubChanID = chanID + e.threadCtrl.Go(func(ctx context.Context) { + e.lggr.Debug("Started: Sending BlockNumber Messages") + for { + select { + case blockHistory := <-blockSubscriberChan: + // Exploratory: Debounce blocks to avoid overflow in case of re-org + latestBlockKey, err := blockHistory.Latest() + if err != nil { + e.lggr.Errorf("BlockSubscriber BlockHistory.Latest() failed: %s", err) + continue + } + e.sendBlockNumberMsg(latestBlockKey) + case <-ctx.Done(): + return + } + } + }) + return nil + }) +} + +// Close stops go routines and closes channels +func (e *AutomationCustomTelemetryService) Close() error { + return e.StopOnce("AutomationCustomTelemetryService", func() error { + e.lggr.Debug("Stopping: custom telemetry service") + e.threadCtrl.Close() + err := e.blockSubscriber.Unsubscribe(e.blockSubChanID) + if err != nil { + e.lggr.Errorf("Custom telemetry service encounters error %v when stopping", err) + return err + } + e.lggr.Infof("Stopped: Custom telemetry service") + return nil + }) +} + +func (e *AutomationCustomTelemetryService) sendNodeVersionMsg() { + vMsg := &telem.NodeVersion{ + Timestamp: uint64(time.Now().UTC().UnixMilli()), + NodeVersion: static.Version, + ConfigDigest: e.configDigest[:], + } + wrappedVMsg := &telem.AutomationTelemWrapper{ + Msg: &telem.AutomationTelemWrapper_NodeVersion{ + NodeVersion: vMsg, + }, + } + bytes, err := proto.Marshal(wrappedVMsg) + if err != nil { + e.lggr.Errorf("Error occurred while marshalling the Node Version Message %s: %v", wrappedVMsg.String(), err) + } else { + e.monitoringEndpoint.SendLog(bytes) + e.lggr.Debugf("NodeVersion Message Sent to Endpoint: %d", vMsg.Timestamp) + } +} + +func (e *AutomationCustomTelemetryService) sendBlockNumberMsg(blockKey ocr2keepers.BlockKey) { + blockNumMsg := &telem.BlockNumber{ + Timestamp: uint64(time.Now().UTC().UnixMilli()), + BlockNumber: uint64(blockKey.Number), + BlockHash: hex.EncodeToString(blockKey.Hash[:]), + ConfigDigest: e.configDigest[:], + } + wrappedBlockNumMsg := &telem.AutomationTelemWrapper{ + Msg: &telem.AutomationTelemWrapper_BlockNumber{ + BlockNumber: blockNumMsg, + }, + } + b, err := proto.Marshal(wrappedBlockNumMsg) + if err != nil { + e.lggr.Errorf("Error occurred while marshalling the Block Num Message %s: %v", wrappedBlockNumMsg.String(), err) + } else { + e.monitoringEndpoint.SendLog(b) + e.lggr.Debugf("BlockNumber Message Sent to Endpoint: %d", blockNumMsg.Timestamp) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry_test.go new file mode 100644 index 0000000000..4318d9aac6 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry_test.go @@ -0,0 +1,56 @@ +package autotelemetry21 + +import ( + "sync" + "testing" + + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/assert" + + headtracker "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/logger" + evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" +) + +// const historySize = 4 +// const blockSize = int64(4) +const finality = uint32(4) + +func TestNewAutomationCustomTelemetryService(t *testing.T) { + me := &MockMonitoringEndpoint{} + lggr := logger.TestLogger(t) + var hb headtracker.HeadBroadcaster + var lp logpoller.LogPoller + + bs := evm.NewBlockSubscriber(hb, lp, finality, lggr) + // configTracker := &MockContractConfigTracker{} + var configTracker types.ContractConfigTracker + + service, err := NewAutomationCustomTelemetryService(me, lggr, bs, configTracker) + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + service.monitoringEndpoint.SendLog([]byte("test")) + assert.Equal(t, me.LogCount(), 1) + service.monitoringEndpoint.SendLog([]byte("test2")) + assert.Equal(t, me.LogCount(), 2) + service.Close() +} + +type MockMonitoringEndpoint struct { + sentLogs [][]byte + lock sync.RWMutex +} + +func (me *MockMonitoringEndpoint) SendLog(log []byte) { + me.lock.Lock() + defer me.lock.Unlock() + me.sentLogs = append(me.sentLogs, log) +} + +func (me *MockMonitoringEndpoint) LogCount() int { + me.lock.RLock() + defer me.lock.RUnlock() + return len(me.sentLogs) +} diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index f5d775fe74..b897fba7f1 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -137,7 +137,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 95d898c353..6cd6eaabc3 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -143,7 +143,7 @@ ContractTransmitterTransmitTimeout = '1m0s' DatabaseTimeout = '8s' KeyBundleID = '7a5f66bbe6594259325bf2b4f5b1a9c900000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 9dd0be8f5d..c743601ced 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -137,7 +137,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '20s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 1eb9cd5023..5b93c7061e 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -890,7 +890,7 @@ ContractTransmitterTransmitTimeout = '10s' # Default DatabaseTimeout = '10s' # Default KeyBundleID = '7a5f66bbe6594259325bf2b4f5b1a9c900000000000000000000000000000000' # Example CaptureEATelemetry = false # Default -CaptureAutomationCustomTelemetry = false # Default +CaptureAutomationCustomTelemetry = true # Default DefaultTransactionQueueDepth = 1 # Default SimulateTransactions = false # Default TraceLogging = false # Default @@ -987,7 +987,7 @@ CaptureEATelemetry toggles collecting extra information from External Adaptares ### CaptureAutomationCustomTelemetry ```toml -CaptureAutomationCustomTelemetry = false # Default +CaptureAutomationCustomTelemetry = true # Default ``` CaptureAutomationCustomTelemetry toggles collecting automation specific telemetry diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 8a3b1af96f..01e96ac944 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -149,7 +149,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 31fded1b42..1f6901e9ff 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -193,7 +193,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 78fc976912..4c1a1c75fc 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -193,7 +193,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 226a7bbb3b..536b7d8ac0 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -193,7 +193,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 5cd3d56746..89f59574fc 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -183,7 +183,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index fd24150b58..2d32b39a64 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -190,7 +190,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index 828d953da9..e478203e00 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -186,7 +186,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -CaptureAutomationCustomTelemetry = false +CaptureAutomationCustomTelemetry = true DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false From 29315fff30d0aa112036c01b6ccd98ef47e831d4 Mon Sep 17 00:00:00 2001 From: Tate Date: Fri, 17 Nov 2023 14:59:39 -0700 Subject: [PATCH 173/327] Bump chainlink-github-actions refs to be up to date (#11332) --- .github/actions/build-chainlink-image/action.yml | 4 ++-- .github/actions/build-test-image/action.yml | 8 ++++---- .github/actions/version-file-bump/action.yml | 2 +- .github/workflows/automation-benchmark-tests.yml | 2 +- .github/workflows/automation-load-tests.yml | 2 +- .github/workflows/automation-ondemand-tests.yml | 6 +++--- .github/workflows/ci-core.yml | 2 +- .github/workflows/integration-chaos-tests.yml | 6 +++--- .github/workflows/integration-tests.yml | 16 ++++++++-------- .github/workflows/live-testnet-tests.yml | 6 +++--- .github/workflows/on-demand-ocr-soak-test.yml | 2 +- .../on-demand-vrfv2plus-performance-test.yml | 2 +- .github/workflows/performance-tests.yml | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/actions/build-chainlink-image/action.yml b/.github/actions/build-chainlink-image/action.yml index ac29a3d7b8..d5839cc79b 100644 --- a/.github/actions/build-chainlink-image/action.yml +++ b/.github/actions/build-chainlink-image/action.yml @@ -25,7 +25,7 @@ runs: steps: - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: repository: chainlink tag: ${{ inputs.git_commit_sha }}${{ inputs.tag_suffix }} @@ -33,7 +33,7 @@ runs: AWS_ROLE_TO_ASSUME: ${{ inputs.AWS_ROLE_TO_ASSUME }} - name: Build Image if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: cl_repo: smartcontractkit/chainlink cl_ref: ${{ inputs.git_commit_sha }} diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index e6c759109b..b7a7948d2c 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -71,7 +71,7 @@ runs: - name: Check if test base image exists if: steps.version.outputs.is_semantic == 'false' id: check-base-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: repository: ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image tag: ${{ steps.long_sha.outputs.long_sha }} @@ -79,7 +79,7 @@ runs: AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} - name: Build Base Image if: steps.version.outputs.is_semantic == 'false' && steps.check-base-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/docker/build-push@ce87f8986ca18336cc5015df75916c2ec0a7c4b3 # v2.1.2 + uses: smartcontractkit/chainlink-github-actions/docker/build-push@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: BASE_IMAGE_NAME: ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image:${{ steps.long_sha.outputs.long_sha }} with: @@ -92,7 +92,7 @@ runs: # Test Runner Logic - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: repository: ${{ inputs.repository }} tag: ${{ inputs.tag }} @@ -100,7 +100,7 @@ runs: AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} - name: Build and Publish Test Runner if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/docker/build-push@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/docker/build-push@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: tags: | ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/${{ inputs.repository }}:${{ inputs.tag }} diff --git a/.github/actions/version-file-bump/action.yml b/.github/actions/version-file-bump/action.yml index 73a374762d..2083217400 100644 --- a/.github/actions/version-file-bump/action.yml +++ b/.github/actions/version-file-bump/action.yml @@ -31,7 +31,7 @@ runs: current_version=$(head -n1 ./VERSION) echo "current_version=${current_version}" | tee -a "$GITHUB_OUTPUT" - name: Compare semantic versions - uses: smartcontractkit/chainlink-github-actions/semver-compare@v2.2.0 + uses: smartcontractkit/chainlink-github-actions/semver-compare@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 id: compare with: version1: ${{ steps.get-current-version.outputs.current_version }} diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index 0fff36f8df..efe6d2eb59 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -110,7 +110,7 @@ jobs: QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} suites: benchmark load/automationv2_1 chaos reorg - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: DETACH_RUNNER: true TEST_SUITE: benchmark diff --git a/.github/workflows/automation-load-tests.yml b/.github/workflows/automation-load-tests.yml index eebd87322c..b19ac8fd24 100644 --- a/.github/workflows/automation-load-tests.yml +++ b/.github/workflows/automation-load-tests.yml @@ -71,7 +71,7 @@ jobs: QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} suites: benchmark load/automationv2_1 chaos reorg - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: RR_CPU: 4000m RR_MEM: 4Gi diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 88c2c126dc..5cd2182ff6 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -59,7 +59,7 @@ jobs: - name: Check if image exists if: inputs.chainlinkImage == '' id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: repository: chainlink tag: ${{ github.sha }}${{ matrix.image.tag-suffix }} @@ -67,7 +67,7 @@ jobs: AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - name: Build Image if: steps.check-image.outputs.exists == 'false' && inputs.chainlinkImage == '' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: cl_repo: smartcontractkit/chainlink cl_ref: ${{ github.sha }} @@ -172,7 +172,7 @@ jobs: echo "version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT fi - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: PYROSCOPE_SERVER: ${{ matrix.tests.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }} diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index d0bae66480..e69fc64cc7 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -84,7 +84,7 @@ jobs: run: ./tools/bin/${{ matrix.cmd }} ./... - name: Print Filtered Test Results if: ${{ failure() && matrix.cmd == 'go_core_tests' }} - uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: results-file: ./output.txt output-file: ./output-short.txt diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 892a43e76f..10c6281099 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: repository: chainlink tag: ${{ github.sha }} @@ -38,7 +38,7 @@ jobs: AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - name: Build Image if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: cl_repo: smartcontractkit/chainlink cl_ref: ${{ github.sha }} @@ -109,7 +109,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 11 ./chaos 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 17f571fd63..9550be83ce 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -233,7 +233,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} @@ -398,7 +398,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} @@ -422,7 +422,7 @@ jobs: ## Run this step when changes that do not need the test to run are made - name: Run Setup if: needs.changes.outputs.src == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod @@ -521,7 +521,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Setup - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_download_vendor_packages_command: | cd ./integration-tests @@ -569,7 +569,7 @@ jobs: run: | echo "Running migration tests from version '${{ steps.get_latest_version.outputs.latest_version }}' to: '${{ github.sha }}'" - name: Run Migration Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -669,7 +669,7 @@ jobs: steps: - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: repository: chainlink-solana-tests tag: ${{ needs.get_solana_sha.outputs.sha }} @@ -814,7 +814,7 @@ jobs: ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Run Setup if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: go_mod_path: ./integration-tests/go.mod cache_restore_only: true @@ -843,7 +843,7 @@ jobs: docker rm "$CONTAINER_ID" - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_command_to_run: export ENV_JOB_IMAGE=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} && make test_smoke cl_repo: ${{ env.CHAINLINK_IMAGE }} diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index 23e9b3c04c..7eb1669b35 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -78,7 +78,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia @@ -133,7 +133,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-goerli @@ -188,7 +188,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-arbitrum-goerli diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 4ea10cd482..b17fdc6beb 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -133,7 +133,7 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: DETACH_RUNNER: true TEST_SUITE: soak diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index b4f9f46de0..2e765ab79b 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -118,7 +118,7 @@ jobs: with: fetch-depth: 0 - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 6h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./load/vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index 57907fe6c2..4b6dd1a228 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -57,7 +57,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 10 ./performance 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: make gomod From 6662c1ccef948be947c225f58b7c8372b5577e74 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 17 Nov 2023 16:07:01 -0600 Subject: [PATCH 174/327] switch from chainlink-relay to chainlink-common (#11320) --- common/client/mock_rpc_test.go | 2 +- common/client/multi_node.go | 4 +- common/client/multi_node_test.go | 2 +- common/client/node.go | 2 +- common/client/node_lifecycle_test.go | 2 +- common/client/send_only_node.go | 2 +- common/client/send_only_node_test.go | 2 +- common/client/types.go | 2 +- common/headtracker/head_broadcaster.go | 2 +- common/headtracker/head_tracker.go | 2 +- common/txmgr/broadcaster.go | 4 +- common/txmgr/confirmer.go | 4 +- common/txmgr/resender.go | 2 +- common/txmgr/txmgr.go | 2 +- core/bridges/bridge_type.go | 2 +- core/bridges/bridge_type_test.go | 2 +- core/chains/chain_kv.go | 2 +- core/chains/chain_kv_test.go | 2 +- core/chains/evm/assets/assets.go | 4 +- core/chains/evm/assets/assets_test.go | 4 +- core/chains/evm/chain.go | 10 +-- core/chains/evm/client/chain_client.go | 4 +- core/chains/evm/client/client.go | 2 +- core/chains/evm/client/mocks/client.go | 2 +- core/chains/evm/client/node.go | 2 +- core/chains/evm/client/null_client.go | 2 +- core/chains/evm/client/pool.go | 2 +- core/chains/evm/client/rpc_client.go | 8 +-- core/chains/evm/client/send_only_node.go | 2 +- .../evm/client/simulated_backend_client.go | 2 +- core/chains/evm/config/chain_scoped.go | 2 +- core/chains/evm/config/config.go | 4 +- core/chains/evm/config/toml/config.go | 22 +++--- .../evm/forwarders/forwarder_manager.go | 2 +- core/chains/evm/gas/arbitrum_estimator.go | 2 +- .../chains/evm/gas/block_history_estimator.go | 2 +- core/chains/evm/gas/models.go | 2 +- .../evm/gas/rollups/l1_gas_price_oracle.go | 2 +- .../evm/gas/suggested_price_estimator.go | 2 +- .../evm/headtracker/head_tracker_test.go | 2 +- core/chains/evm/log/broadcaster.go | 2 +- core/chains/evm/logpoller/log_poller.go | 2 +- core/chains/evm/mocks/chain.go | 2 +- core/chains/evm/monitor/balance.go | 2 +- core/chains/evm/types/types.go | 2 +- core/cmd/cosmos_node_commands_test.go | 11 ++- core/cmd/cosmos_transaction_commands_test.go | 6 +- core/cmd/eth_keys_commands_test.go | 12 ++-- core/cmd/shell.go | 2 +- core/cmd/solana_node_commands_test.go | 2 +- core/cmd/solana_transaction_commands_test.go | 6 +- core/cmd/starknet_node_commands_test.go | 6 +- core/config/parse/parsers.go | 8 +-- core/internal/cltest/cltest.go | 2 +- core/internal/testutils/evmtest/evmtest.go | 2 +- core/logger/logger.go | 4 +- core/scripts/go.mod | 8 +-- core/scripts/go.sum | 16 ++--- core/services/blockhashstore/delegate.go | 2 +- core/services/blockheaderfeeder/delegate.go | 2 +- core/services/chainlink/application.go | 6 +- core/services/chainlink/config_test.go | 70 +++++++++---------- .../mocks/relayer_chain_interoperators.go | 4 +- .../chainlink/relayer_chain_interoperators.go | 4 +- .../relayer_chain_interoperators_test.go | 20 +++--- core/services/chainlink/relayer_factory.go | 2 +- core/services/directrequest/delegate.go | 4 +- core/services/directrequest/delegate_test.go | 2 +- core/services/directrequest/validate.go | 2 +- core/services/feeds/service.go | 2 +- core/services/fluxmonitorv2/config.go | 2 +- core/services/fluxmonitorv2/flux_monitor.go | 2 +- .../fluxmonitorv2/flux_monitor_test.go | 2 +- .../services/fluxmonitorv2/payment_checker.go | 2 +- .../fluxmonitorv2/payment_checker_test.go | 2 +- core/services/fluxmonitorv2/validate_test.go | 2 +- core/services/functions/connector_handler.go | 4 +- .../functions/connector_handler_test.go | 2 +- core/services/functions/listener.go | 2 +- core/services/gateway/connectionmanager.go | 2 +- core/services/gateway/connector/connector.go | 2 +- core/services/gateway/gateway.go | 2 +- .../gateway/handlers/functions/allowlist.go | 2 +- .../handlers/functions/handler.functions.go | 4 +- .../functions/handler.functions_test.go | 2 +- .../handlers/functions/subscriptions.go | 2 +- core/services/gateway/network/httpserver.go | 2 +- core/services/gateway/network/wsconnection.go | 2 +- core/services/gateway/network/wsserver.go | 2 +- core/services/health.go | 2 +- core/services/job/job_orm_test.go | 2 +- core/services/job/models.go | 8 +-- core/services/job/orm.go | 2 +- core/services/job/spawner.go | 8 +-- core/services/job/spawner_test.go | 4 +- .../keeper/registry_synchronizer_core.go | 2 +- core/services/keeper/upkeep_executer.go | 2 +- core/services/keystore/cosmos.go | 4 +- core/services/keystore/keys/ethkey/address.go | 2 +- core/services/keystore/starknet.go | 8 +-- core/services/mocks/checker.go | 2 +- core/services/multi.go | 2 +- core/services/nurse.go | 2 +- core/services/ocr/config_overrider.go | 2 +- core/services/ocr/contract_tracker.go | 2 +- core/services/ocr/delegate.go | 4 +- core/services/ocr2/delegate.go | 15 ++-- core/services/ocr2/delegate_test.go | 2 +- .../ocr2/plugins/functions/config/config.go | 2 +- .../services/ocr2/plugins/functions/plugin.go | 2 +- .../ocr2/plugins/functions/plugin_test.go | 2 +- .../ocr2/plugins/functions/reporting_test.go | 4 +- .../generic/pipeline_runner_adapter.go | 2 +- .../generic/pipeline_runner_adapter_test.go | 2 +- .../ocr2/plugins/generic/telemetry_adapter.go | 2 +- core/services/ocr2/plugins/median/plugin.go | 8 +-- core/services/ocr2/plugins/median/services.go | 4 +- .../ocr2/plugins/mercury/integration_test.go | 8 +-- core/services/ocr2/plugins/mercury/plugin.go | 10 +-- .../plugins/ocr2keeper/evm20/log_provider.go | 2 +- .../ocr2/plugins/ocr2keeper/evm20/registry.go | 2 +- .../ocr2keeper/evm21/block_subscriber.go | 2 +- .../ocr2keeper/evm21/logprovider/provider.go | 2 +- .../ocr2keeper/evm21/logprovider/recoverer.go | 2 +- .../evm21/mercury/streams/streams.go | 2 +- .../evm21/transmit/event_provider.go | 2 +- .../ocr2keeper/evm21/upkeepstate/store.go | 2 +- .../plugins/ocr2keeper/integration_21_test.go | 11 ++- .../plugins/ocr2keeper/integration_test.go | 10 +-- core/services/ocr2/plugins/ocr2keeper/util.go | 3 +- .../ocr2vrf/coordinator/coordinator_test.go | 12 ++-- core/services/ocr2/plugins/s4/factory_test.go | 4 +- .../ocr2/plugins/s4/integration_test.go | 4 +- core/services/ocr2/plugins/s4/plugin_test.go | 19 ++--- core/services/ocr2/validate/validate.go | 2 +- core/services/ocrbootstrap/delegate.go | 9 +-- core/services/ocrcommon/peer_wrapper.go | 7 +- core/services/ocrcommon/peerstore.go | 2 +- core/services/ocrcommon/run_saver.go | 2 +- core/services/ocrcommon/telemetry.go | 8 +-- core/services/ocrcommon/telemetry_test.go | 9 +-- core/services/periodicbackup/backup.go | 2 +- core/services/pg/event_broadcaster.go | 2 +- core/services/pg/q.go | 2 +- core/services/pg/sqlx.go | 2 +- core/services/pg/transaction.go | 2 +- core/services/pipeline/orm.go | 2 +- core/services/pipeline/runner.go | 2 +- core/services/promreporter/prom_reporter.go | 2 +- core/services/relay/evm/config_poller.go | 2 +- core/services/relay/evm/evm.go | 22 +++--- core/services/relay/evm/functions.go | 12 ++-- .../relay/evm/functions/logpoller_wrapper.go | 2 +- core/services/relay/evm/loop_impl.go | 2 +- .../relay/evm/mercury/persistence_manager.go | 2 +- core/services/relay/evm/mercury/queue.go | 2 +- .../services/relay/evm/mercury/transmitter.go | 5 +- .../relay/evm/mercury/v1/data_source.go | 4 +- .../relay/evm/mercury/v1/data_source_test.go | 4 +- .../mercury/v1/reportcodec/report_codec.go | 3 +- .../v1/reportcodec/report_codec_test.go | 2 +- .../relay/evm/mercury/v2/data_source.go | 4 +- .../relay/evm/mercury/v2/data_source_test.go | 4 +- .../mercury/v2/reportcodec/report_codec.go | 3 +- .../v2/reportcodec/report_codec_test.go | 2 +- .../relay/evm/mercury/v3/data_source.go | 4 +- .../relay/evm/mercury/v3/data_source_test.go | 4 +- .../mercury/v3/reportcodec/report_codec.go | 3 +- .../v3/reportcodec/report_codec_test.go | 2 +- .../relay/evm/mercury/wsrpc/client.go | 2 +- core/services/relay/evm/mercury_provider.go | 14 ++-- .../relay/evm/mocks/loop_relay_adapter.go | 2 +- core/services/relay/evm/ocr2keeper.go | 15 ++-- core/services/relay/evm/ocr2vrf.go | 17 ++--- core/services/relay/evm/relayer_extender.go | 8 +-- .../relay/evm/request_round_tracker.go | 3 +- core/services/relay/evm/types/types.go | 12 ++-- core/services/relay/grpc_provider_server.go | 4 +- .../relay/grpc_provider_server_test.go | 2 +- core/services/relay/relay.go | 4 +- core/services/relay/relay_test.go | 7 +- core/services/service.go | 2 +- .../telemetry_ingress_batch_client.go | 2 +- .../telemetry_ingress_client.go | 2 +- core/services/telemetry/manager.go | 2 +- core/services/telemetry/manager_test.go | 2 +- .../vrf_coordinator_interface.go | 2 +- core/services/vrf/v1/listener_v1.go | 2 +- core/services/vrf/v2/integration_v2_test.go | 4 +- core/services/vrf/v2/listener_v2.go | 2 +- core/store/migrate/migrate_test.go | 2 +- core/utils/big.go | 2 +- core/utils/config/validate.go | 2 +- core/utils/mailbox_prom.go | 2 +- core/utils/sleeper_task.go | 2 +- core/utils/utils.go | 2 +- core/web/bridge_types_controller.go | 2 +- core/web/bridge_types_controller_test.go | 2 +- core/web/chains_controller.go | 2 +- core/web/cosmos_chains_controller_test.go | 2 +- core/web/eth_keys_controller.go | 8 +-- core/web/eth_keys_controller_test.go | 2 +- core/web/loader/getters.go | 6 +- core/web/loader/loader_test.go | 22 +++--- core/web/loader/node.go | 2 +- core/web/loop_registry_test.go | 2 +- core/web/nodes_controller.go | 2 +- core/web/presenters/bridges.go | 2 +- core/web/presenters/bridges_test.go | 2 +- core/web/presenters/cosmos_chain.go | 2 +- core/web/presenters/eth_key.go | 20 +++--- core/web/presenters/eth_key_test.go | 6 +- core/web/presenters/evm_chain.go | 2 +- core/web/presenters/job.go | 6 +- core/web/presenters/job_test.go | 2 +- core/web/presenters/solana_chain.go | 2 +- core/web/presenters/starknet_chain.go | 2 +- core/web/resolver/bridge_test.go | 2 +- core/web/resolver/chain.go | 2 +- core/web/resolver/eth_key_test.go | 8 +-- core/web/resolver/helpers.go | 2 +- core/web/resolver/mutation.go | 2 +- core/web/resolver/node.go | 2 +- core/web/resolver/node_test.go | 2 +- core/web/resolver/query.go | 2 +- core/web/resolver/spec_test.go | 10 +-- core/web/solana_chains_controller_test.go | 8 +-- go.mod | 8 +-- go.sum | 16 ++--- .../actions/vrfv2plus/vrfv2plus_steps.go | 12 ++-- integration-tests/go.mod | 8 +-- integration-tests/go.sum | 16 ++--- integration-tests/types/config/node/core.go | 6 +- plugins/cmd/chainlink-median/main.go | 2 +- plugins/cmd/chainlink-medianpoc/main.go | 6 +- plugins/config.go | 2 +- plugins/loop_registry.go | 4 +- plugins/medianpoc/data_source.go | 4 +- plugins/medianpoc/data_source_test.go | 5 +- plugins/medianpoc/plugin.go | 10 +-- plugins/medianpoc/plugin_test.go | 2 +- 241 files changed, 551 insertions(+), 538 deletions(-) diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go index 8f171302a2..d5e8db8283 100644 --- a/common/client/mock_rpc_test.go +++ b/common/client/mock_rpc_test.go @@ -5,7 +5,7 @@ package client import ( big "math/big" - assets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + assets "github.com/smartcontractkit/chainlink-common/pkg/assets" context "context" diff --git a/common/client/multi_node.go b/common/client/multi_node.go index df91c61a9d..acab47f083 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -11,8 +11,8 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 3621d6d862..4c0ebb1db9 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - "github.com/smartcontractkit/chainlink-relay/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/common/types" diff --git a/common/client/node.go b/common/client/node.go index f28a171a55..5faaa5da62 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -11,7 +11,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index 564c08bbdc..0dffe935fe 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/mock" "go.uber.org/zap" - "github.com/smartcontractkit/chainlink-relay/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/common/types/mocks" diff --git a/common/client/send_only_node.go b/common/client/send_only_node.go index fa793a826a..767fff5aee 100644 --- a/common/client/send_only_node.go +++ b/common/client/send_only_node.go @@ -6,7 +6,7 @@ import ( "net/url" "sync" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/common/client/send_only_node_test.go b/common/client/send_only_node_test.go index bfe5515365..3034b3f0a1 100644 --- a/common/client/send_only_node_test.go +++ b/common/client/send_only_node_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - "github.com/smartcontractkit/chainlink-relay/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/common/client/types.go b/common/client/types.go index ef9f94dafe..6d3a22cee7 100644 --- a/common/client/types.go +++ b/common/client/types.go @@ -4,7 +4,7 @@ import ( "context" "math/big" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index e9ae93419b..3efe64e1c3 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 54262dd93f..bf63675128 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -10,7 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/common/types" diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 1e3b2fa0a9..ba01fb9e2a 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -15,8 +15,8 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/chains/label" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/chains/label" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index 4d3626ffac..bf35611582 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -14,8 +14,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/chains/label" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/chains/label" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 75781c0840..e604a960bf 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/chains/label" + "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 5b7afd3224..24d2428f61 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -11,7 +11,7 @@ import ( "github.com/google/uuid" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" diff --git a/core/bridges/bridge_type.go b/core/bridges/bridge_type.go index 9031541f22..b2e86df4b9 100644 --- a/core/bridges/bridge_type.go +++ b/core/bridges/bridge_type.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/bridges/bridge_type_test.go b/core/bridges/bridge_type_test.go index c04aba5c2c..6a719d5b53 100644 --- a/core/bridges/bridge_type_test.go +++ b/core/bridges/bridge_type_test.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/store/models" diff --git a/core/chains/chain_kv.go b/core/chains/chain_kv.go index 5094f2885e..4365a859bb 100644 --- a/core/chains/chain_kv.go +++ b/core/chains/chain_kv.go @@ -6,7 +6,7 @@ import ( "golang.org/x/exp/maps" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) type ChainsKV[T types.ChainService] struct { diff --git a/core/chains/chain_kv_test.go b/core/chains/chain_kv_test.go index a30de3090b..205ee693d6 100644 --- a/core/chains/chain_kv_test.go +++ b/core/chains/chain_kv_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" ) diff --git a/core/chains/evm/assets/assets.go b/core/chains/evm/assets/assets.go index c6c81b5ab4..377e92a855 100644 --- a/core/chains/evm/assets/assets.go +++ b/core/chains/evm/assets/assets.go @@ -5,8 +5,8 @@ import ( "fmt" "math/big" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" - "github.com/smartcontractkit/chainlink-relay/pkg/utils/bytes" + "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/shopspring/decimal" diff --git a/core/chains/evm/assets/assets_test.go b/core/chains/evm/assets/assets_test.go index 9496554f11..09eb7b6888 100644 --- a/core/chains/evm/assets/assets_test.go +++ b/core/chains/evm/assets/assets_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" ) @@ -69,7 +69,7 @@ func TestAssets_Eth_UnmarshalJsonError(t *testing.T) { assert.EqualError(t, err, "assets: cannot unmarshal \"x\" into a *assets.Eth") err = json.Unmarshal([]byte(`1`), ð) - assert.Equal(t, relayassets.ErrNoQuotesForCurrency, err) + assert.Equal(t, commonassets.ErrNoQuotesForCurrency, err) } func TestAssets_NewEth(t *testing.T) { diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index f21bf2525a..1e52bed5cb 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -13,9 +13,9 @@ import ( "github.com/jmoiron/sqlx" - relaychains "github.com/smartcontractkit/chainlink-relay/pkg/chains" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + common "github.com/smartcontractkit/chainlink-common/pkg/chains" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains" @@ -422,7 +422,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]types.NodeStatus, int, error nodes := c.cfg.Nodes() total := len(nodes) if start >= total { - return nil, total, relaychains.ErrOutOfRange + return nil, total, common.ErrOutOfRange } if end > total { end = total @@ -459,7 +459,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]types.NodeStatus, int, error } func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) { - return relaychains.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) + return common.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) } func (c *chain) ID() *big.Int { return c.id } diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 79a91dfc05..0f15b35ee9 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -183,7 +183,7 @@ func (c *chainClient) IsL2() bool { return c.multiNode.IsL2() } -func (c *chainClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*relayassets.Link, error) { +func (c *chainClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*commonassets.Link, error) { return c.multiNode.LINKBalance(ctx, address, linkAddress) } diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index 988a7404c9..5263c74de1 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/common/config" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index f1ff5fab45..22498370a2 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -5,7 +5,7 @@ package mocks import ( big "math/big" - assets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + assets "github.com/smartcontractkit/chainlink-common/pkg/assets" common "github.com/ethereum/go-ethereum/common" diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index 80bac25448..b690720240 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -19,7 +19,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/client/null_client.go b/core/chains/evm/client/null_client.go index 45876d9259..e25fed6d96 100644 --- a/core/chains/evm/client/null_client.go +++ b/core/chains/evm/client/null_client.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 473ab6d1eb..18f59b172d 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -15,7 +15,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index f952c04d5b..785acbb2b7 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -17,7 +17,7 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -869,12 +869,12 @@ func (r *rpcClient) TokenBalance(ctx context.Context, address common.Address, co } // LINKBalance returns the balance of LINK at the given address -func (r *rpcClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*relayassets.Link, error) { +func (r *rpcClient) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*commonassets.Link, error) { balance, err := r.TokenBalance(ctx, address, linkAddress) if err != nil { - return relayassets.NewLinkFromJuels(0), err + return commonassets.NewLinkFromJuels(0), err } - return (*relayassets.Link)(balance), nil + return (*commonassets.Link)(balance), nil } func (r *rpcClient) FilterEvents(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { diff --git a/core/chains/evm/client/send_only_node.go b/core/chains/evm/client/send_only_node.go index 3f2481c189..beb12dbc4d 100644 --- a/core/chains/evm/client/send_only_node.go +++ b/core/chains/evm/client/send_only_node.go @@ -14,7 +14,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 33ecc3d0d5..e922715eb9 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -18,7 +18,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index 6030991179..804c354e0e 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -9,7 +9,7 @@ import ( ocr "github.com/smartcontractkit/libocr/offchainreporting" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config" diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index ec90797d7f..2dd2d4704c 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -6,7 +6,7 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/config" @@ -34,7 +34,7 @@ type EVM interface { LogBackfillBatchSize() uint32 LogKeepBlocksDepth() uint32 LogPollInterval() time.Duration - MinContractPayment() *relayassets.Link + MinContractPayment() *commonassets.Link MinIncomingConfirmations() uint32 NonceAutoSync() bool OperatorFactoryAddress() string diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index ae0fb41c5e..26587cd3b0 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -12,8 +12,8 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains" @@ -107,7 +107,7 @@ func (cs EVMConfigs) totalChains() int { } return total } -func (cs EVMConfigs) Chains(ids ...relay.ChainID) (r []relaytypes.ChainStatus, total int, err error) { +func (cs EVMConfigs) Chains(ids ...relay.ChainID) (r []commontypes.ChainStatus, total int, err error) { total = cs.totalChains() for _, ch := range cs { if ch == nil { @@ -126,7 +126,7 @@ func (cs EVMConfigs) Chains(ids ...relay.ChainID) (r []relaytypes.ChainStatus, t continue } } - ch2 := relaytypes.ChainStatus{ + ch2 := commontypes.ChainStatus{ ID: ch.ChainID.String(), Enabled: ch.IsEnabled(), } @@ -150,7 +150,7 @@ func (cs EVMConfigs) Node(name string) (types.Node, error) { return types.Node{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) } -func (cs EVMConfigs) NodeStatus(name string) (relaytypes.NodeStatus, error) { +func (cs EVMConfigs) NodeStatus(name string) (commontypes.NodeStatus, error) { for i := range cs { for _, n := range cs[i].Nodes { if n.Name != nil && *n.Name == name { @@ -158,7 +158,7 @@ func (cs EVMConfigs) NodeStatus(name string) (relaytypes.NodeStatus, error) { } } } - return relaytypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) + return commontypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) } func legacyNode(n *Node, chainID *utils.Big) (v2 types.Node) { @@ -179,13 +179,13 @@ func legacyNode(n *Node, chainID *utils.Big) (v2 types.Node) { return } -func nodeStatus(n *Node, chainID relay.ChainID) (relaytypes.NodeStatus, error) { - var s relaytypes.NodeStatus +func nodeStatus(n *Node, chainID relay.ChainID) (commontypes.NodeStatus, error) { + var s commontypes.NodeStatus s.ChainID = chainID s.Name = *n.Name b, err := toml.Marshal(n) if err != nil { - return relaytypes.NodeStatus{}, err + return commontypes.NodeStatus{}, err } s.Config = string(b) return s, nil @@ -220,7 +220,7 @@ func (cs EVMConfigs) Nodes(chainID relay.ChainID) (ns []types.Node, err error) { return } -func (cs EVMConfigs) NodeStatuses(chainIDs ...relay.ChainID) (ns []relaytypes.NodeStatus, err error) { +func (cs EVMConfigs) NodeStatuses(chainIDs ...relay.ChainID) (ns []commontypes.NodeStatus, err error) { if len(chainIDs) == 0 { for i := range cs { for _, n := range cs[i].Nodes { @@ -355,7 +355,7 @@ type Chain struct { LogPollInterval *models.Duration LogKeepBlocksDepth *uint32 MinIncomingConfirmations *uint32 - MinContractPayment *relayassets.Link + MinContractPayment *commonassets.Link NonceAutoSync *bool NoNewHeadsThreshold *models.Duration OperatorFactoryAddress *ethkey.EIP55Address diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 934da487fd..819fb31951 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -12,7 +12,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmlogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 860126a588..c79202c731 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index eb35cd2751..a3f3520b36 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -15,7 +15,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index 50cbddcd9b..b6f34ab87a 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index 09244e9d31..88c61c4934 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index 24cf20f172..dadec6210c 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index 8af344098f..d734b230e1 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -20,7 +20,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index 9c4050fd79..11c282a4d2 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index b86ede5dbc..6676b694b0 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -20,7 +20,7 @@ import ( "github.com/pkg/errors" "golang.org/x/exp/maps" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/chains/evm/mocks/chain.go b/core/chains/evm/mocks/chain.go index f0f202b093..3a686887d7 100644 --- a/core/chains/evm/mocks/chain.go +++ b/core/chains/evm/mocks/chain.go @@ -30,7 +30,7 @@ import ( txmgr "github.com/smartcontractkit/chainlink/v2/common/txmgr" - types "github.com/smartcontractkit/chainlink-relay/pkg/types" + types "github.com/smartcontractkit/chainlink-common/pkg/types" ) // Chain is an autogenerated mock type for the Chain type diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index 476d3c7019..b12346ac00 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -13,7 +13,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/chains/evm/types/types.go b/core/chains/evm/types/types.go index 7d756485d0..d0e7292b20 100644 --- a/core/chains/evm/types/types.go +++ b/core/chains/evm/types/types.go @@ -12,7 +12,7 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/cmd/cosmos_node_commands_test.go b/core/cmd/cosmos_node_commands_test.go index 591160629e..728be9396f 100644 --- a/core/cmd/cosmos_node_commands_test.go +++ b/core/cmd/cosmos_node_commands_test.go @@ -9,9 +9,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + "github.com/smartcontractkit/chainlink-common/pkg/config" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -33,14 +32,14 @@ func TestShell_IndexCosmosNodes(t *testing.T) { t.Parallel() chainID := cosmostest.RandomChainID() - node := config.Node{ + node := coscfg.Node{ Name: ptr("second"), - TendermintURL: relaycfg.MustParseURL("http://tender.mint.test/bombay-12"), + TendermintURL: config.MustParseURL("http://tender.mint.test/bombay-12"), } - chain := config.TOMLConfig{ + chain := coscfg.TOMLConfig{ ChainID: ptr(chainID), Enabled: ptr(true), - Nodes: config.Nodes{&node}, + Nodes: coscfg.Nodes{&node}, } app := cosmosStartNewApplication(t, &chain) client, r := app.NewShellAndRenderer() diff --git a/core/cmd/cosmos_transaction_commands_test.go b/core/cmd/cosmos_transaction_commands_test.go index 67b014af2c..f54ccaf4a6 100644 --- a/core/cmd/cosmos_transaction_commands_test.go +++ b/core/cmd/cosmos_transaction_commands_test.go @@ -13,16 +13,16 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "github.com/smartcontractkit/chainlink-common/pkg/config" cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" cosmosdb "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/denom" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/params" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" ) @@ -50,7 +50,7 @@ func TestShell_SendCosmosCoins(t *testing.T) { nodes := coscfg.Nodes{ &coscfg.Node{ Name: ptr("random"), - TendermintURL: utils.MustParseURL(url), + TendermintURL: config.MustParseURL(url), }, } chainConfig := coscfg.TOMLConfig{ChainID: &chainID, Enabled: ptr(true), Chain: cosmosChain, Nodes: nodes} diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index d74ae231d7..293a2d3f6d 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -12,7 +12,7 @@ import ( "github.com/pkg/errors" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -35,7 +35,7 @@ func TestEthKeysPresenter_RenderTable(t *testing.T) { var ( address = "0x5431F5F973781809D18643b87B44921b11355d81" ethBalance = assets.NewEth(1) - linkBalance = relayassets.NewLinkFromJuels(2) + linkBalance = commonassets.NewLinkFromJuels(2) isDisabled = true createdAt = time.Now() updatedAt = time.Now().Add(time.Second) @@ -90,7 +90,7 @@ func TestShell_ListETHKeys(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(13), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(commonassets.NewLinkFromJuels(13), nil) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) @@ -169,7 +169,7 @@ func TestShell_CreateETHKey(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(42), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(commonassets.NewLinkFromJuels(42), nil) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -244,7 +244,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(42), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(commonassets.NewLinkFromJuels(42), nil) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) @@ -362,7 +362,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { ethClient.On("Dial", mock.Anything).Maybe() ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) - ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(relayassets.NewLinkFromJuels(42), nil) + ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(commonassets.NewLinkFromJuels(42), nil) set := flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 07cd2185dc..52c9090736 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -31,7 +31,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/cmd/solana_node_commands_test.go b/core/cmd/solana_node_commands_test.go index 7c88557c6d..316cf16212 100644 --- a/core/cmd/solana_node_commands_test.go +++ b/core/cmd/solana_node_commands_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/config" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" diff --git a/core/cmd/solana_transaction_commands_test.go b/core/cmd/solana_transaction_commands_test.go index cdb182cba4..f019616cb8 100644 --- a/core/cmd/solana_transaction_commands_test.go +++ b/core/cmd/solana_transaction_commands_test.go @@ -15,11 +15,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" solanaClient "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - "github.com/smartcontractkit/chainlink-solana/pkg/solana" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" ) @@ -29,7 +29,7 @@ func TestShell_SolanaSendSol(t *testing.T) { url := solanaClient.SetupLocalSolNode(t) node := solcfg.Node{ Name: ptr(t.Name()), - URL: utils.MustParseURL(url), + URL: config.MustParseURL(url), } cfg := solana.TOMLConfig{ ChainID: &chainID, diff --git a/core/cmd/starknet_node_commands_test.go b/core/cmd/starknet_node_commands_test.go index 9d7c6fcaf4..0347cdd18f 100644 --- a/core/cmd/starknet_node_commands_test.go +++ b/core/cmd/starknet_node_commands_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" + commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" @@ -34,11 +34,11 @@ func TestShell_IndexStarkNetNodes(t *testing.T) { id := "starknet chain ID" node1 := config.Node{ Name: ptr("first"), - URL: relaycfg.MustParseURL("https://starknet1.example"), + URL: commoncfg.MustParseURL("https://starknet1.example"), } node2 := config.Node{ Name: ptr("second"), - URL: relaycfg.MustParseURL("https://starknet2.example"), + URL: commoncfg.MustParseURL("https://starknet2.example"), } chain := config.TOMLConfig{ ChainID: &id, diff --git a/core/config/parse/parsers.go b/core/config/parse/parsers.go index e2f6978187..6243b74dd5 100644 --- a/core/config/parse/parsers.go +++ b/core/config/parse/parsers.go @@ -13,7 +13,7 @@ import ( "github.com/pkg/errors" "go.uber.org/zap/zapcore" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -23,10 +23,10 @@ func String(str string) (string, error) { return str, nil } -func Link(str string) (*relayassets.Link, error) { - i, ok := new(relayassets.Link).SetString(str, 10) +func Link(str string) (*commonassets.Link, error) { + i, ok := new(commonassets.Link).SetString(str, 10) if !ok { - return i, fmt.Errorf("unable to parse '%v' into *relayassets.Link(base 10)", str) + return i, fmt.Errorf("unable to parse '%s'", str) } return i, nil } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 83a97833bd..02aa2de0cc 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -43,7 +43,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 80237d218d..7674650c01 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains" diff --git a/core/logger/logger.go b/core/logger/logger.go index 8e847a99ac..1feaf0f5d6 100644 --- a/core/logger/logger.go +++ b/core/logger/logger.go @@ -12,7 +12,7 @@ import ( "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + common "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -49,7 +49,7 @@ func init() { } } -var _ relaylogger.Logger = (Logger)(nil) +var _ common.Logger = (Logger)(nil) //go:generate mockery --quiet --name Logger --output . --filename logger_mock_test.go --inpackage --case=underscore //go:generate mockery --quiet --name Logger --output ./mocks/ --case=underscore diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 7bf60aff8b..1d8ba40b82 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -303,10 +303,10 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 // indirect 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.20231115124244-8303409abccd // 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/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7139f0efa4..13496adb7a 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1462,14 +1462,14 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= 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.20231115124244-8303409abccd h1:PRVJxNK67pQWufXuB1cxckH/xZkcQFDy8KjN9ZYqong= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd/go.mod h1:rOayi690YxLlkQy959PD8INhOAIAUi9LoN0G+J/CEf4= -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= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index c8e55e47c3..1a84323b6f 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 971a691d77..3de42d7a9e 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 0d479b1f1a..29679ee92f 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -18,8 +18,8 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relayservices "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/build" @@ -417,7 +417,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger.Debug("Off-chain reporting v2 disabled") } - healthChecker := relayservices.NewChecker() + healthChecker := commonservices.NewChecker() var lbs []utils.DependentAwaiter for _, c := range legacyEVMChains.Slice() { diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index fbadb379ca..891c0a490f 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -16,9 +16,9 @@ import ( ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" - relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" @@ -145,7 +145,7 @@ var ( MaxMsgsPerBatch: ptr[int64](13), }, Nodes: []*coscfg.Node{ - {Name: ptr("primary"), TendermintURL: relaycfg.MustParseURL("http://columbus.cosmos.com")}, + {Name: ptr("primary"), TendermintURL: commoncfg.MustParseURL("http://columbus.cosmos.com")}, }}, { ChainID: ptr("Malaga-420"), @@ -153,7 +153,7 @@ var ( BlocksUntilTxTimeout: ptr[int64](20), }, Nodes: []*coscfg.Node{ - {Name: ptr("secondary"), TendermintURL: relaycfg.MustParseURL("http://bombay.cosmos.com")}, + {Name: ptr("secondary"), TendermintURL: commoncfg.MustParseURL("http://bombay.cosmos.com")}, }}, }, Solana: []*solana.TOMLConfig{ @@ -163,16 +163,16 @@ var ( MaxRetries: ptr[int64](12), }, Nodes: []*solcfg.Node{ - {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://mainnet.solana.com")}, + {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://mainnet.solana.com")}, }, }, { ChainID: ptr("testnet"), Chain: solcfg.Chain{ - OCR2CachePollPeriod: relaycfg.MustNewDuration(time.Minute), + OCR2CachePollPeriod: commoncfg.MustNewDuration(time.Minute), }, Nodes: []*solcfg.Node{ - {Name: ptr("secondary"), URL: relaycfg.MustParseURL("http://testnet.solana.com")}, + {Name: ptr("secondary"), URL: commoncfg.MustParseURL("http://testnet.solana.com")}, }, }, }, @@ -180,10 +180,10 @@ var ( { ChainID: ptr("foobar"), Chain: stkcfg.Chain{ - ConfirmationPoll: relaycfg.MustNewDuration(time.Hour), + ConfirmationPoll: commoncfg.MustNewDuration(time.Hour), }, Nodes: []*stkcfg.Node{ - {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://stark.node")}, + {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://stark.node")}, }, }, }, @@ -538,7 +538,7 @@ func TestConfig_Marshal(t *testing.T) { LogBackfillBatchSize: ptr[uint32](17), LogPollInterval: &minute, LogKeepBlocksDepth: ptr[uint32](100000), - MinContractPayment: relayassets.NewLinkFromJuels(math.MaxInt64), + MinContractPayment: commonassets.NewLinkFromJuels(math.MaxInt64), MinIncomingConfirmations: ptr[uint32](13), NonceAutoSync: ptr(true), NoNewHeadsThreshold: &minute, @@ -603,13 +603,13 @@ func TestConfig_Marshal(t *testing.T) { ChainID: ptr("mainnet"), Enabled: ptr(false), Chain: solcfg.Chain{ - BalancePollPeriod: relaycfg.MustNewDuration(time.Minute), - ConfirmPollPeriod: relaycfg.MustNewDuration(time.Second), - OCR2CachePollPeriod: relaycfg.MustNewDuration(time.Minute), - OCR2CacheTTL: relaycfg.MustNewDuration(time.Hour), - TxTimeout: relaycfg.MustNewDuration(time.Hour), - TxRetryTimeout: relaycfg.MustNewDuration(time.Minute), - TxConfirmTimeout: relaycfg.MustNewDuration(time.Second), + BalancePollPeriod: commoncfg.MustNewDuration(time.Minute), + ConfirmPollPeriod: commoncfg.MustNewDuration(time.Second), + OCR2CachePollPeriod: commoncfg.MustNewDuration(time.Minute), + OCR2CacheTTL: commoncfg.MustNewDuration(time.Hour), + TxTimeout: commoncfg.MustNewDuration(time.Hour), + TxRetryTimeout: commoncfg.MustNewDuration(time.Minute), + TxConfirmTimeout: commoncfg.MustNewDuration(time.Second), SkipPreflight: ptr(true), Commitment: ptr("banana"), MaxRetries: ptr[int64](7), @@ -617,12 +617,12 @@ func TestConfig_Marshal(t *testing.T) { ComputeUnitPriceMax: ptr[uint64](1000), ComputeUnitPriceMin: ptr[uint64](10), ComputeUnitPriceDefault: ptr[uint64](100), - FeeBumpPeriod: relaycfg.MustNewDuration(time.Minute), + FeeBumpPeriod: commoncfg.MustNewDuration(time.Minute), }, Nodes: []*solcfg.Node{ - {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://solana.web")}, - {Name: ptr("foo"), URL: relaycfg.MustParseURL("http://solana.foo")}, - {Name: ptr("bar"), URL: relaycfg.MustParseURL("http://solana.bar")}, + {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://solana.web")}, + {Name: ptr("foo"), URL: commoncfg.MustParseURL("http://solana.foo")}, + {Name: ptr("bar"), URL: commoncfg.MustParseURL("http://solana.bar")}, }, }, } @@ -631,14 +631,14 @@ func TestConfig_Marshal(t *testing.T) { ChainID: ptr("foobar"), Enabled: ptr(true), Chain: stkcfg.Chain{ - OCR2CachePollPeriod: relaycfg.MustNewDuration(6 * time.Hour), - OCR2CacheTTL: relaycfg.MustNewDuration(3 * time.Minute), - RequestTimeout: relaycfg.MustNewDuration(time.Minute + 3*time.Second), - TxTimeout: relaycfg.MustNewDuration(13 * time.Second), - ConfirmationPoll: relaycfg.MustNewDuration(42 * time.Second), + OCR2CachePollPeriod: commoncfg.MustNewDuration(6 * time.Hour), + OCR2CacheTTL: commoncfg.MustNewDuration(3 * time.Minute), + RequestTimeout: commoncfg.MustNewDuration(time.Minute + 3*time.Second), + TxTimeout: commoncfg.MustNewDuration(13 * time.Second), + ConfirmationPoll: commoncfg.MustNewDuration(42 * time.Second), }, Nodes: []*stkcfg.Node{ - {Name: ptr("primary"), URL: relaycfg.MustParseURL("http://stark.node")}, + {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://stark.node")}, }, }, } @@ -648,21 +648,21 @@ func TestConfig_Marshal(t *testing.T) { Enabled: ptr(true), Chain: coscfg.Chain{ Bech32Prefix: ptr("wasm"), - BlockRate: relaycfg.MustNewDuration(time.Minute), + BlockRate: commoncfg.MustNewDuration(time.Minute), BlocksUntilTxTimeout: ptr[int64](12), - ConfirmPollPeriod: relaycfg.MustNewDuration(time.Second), + ConfirmPollPeriod: commoncfg.MustNewDuration(time.Second), FallbackGasPrice: mustDecimal("0.001"), GasToken: ptr("ucosm"), GasLimitMultiplier: mustDecimal("1.2"), MaxMsgsPerBatch: ptr[int64](17), - OCR2CachePollPeriod: relaycfg.MustNewDuration(time.Minute), - OCR2CacheTTL: relaycfg.MustNewDuration(time.Hour), - TxMsgTimeout: relaycfg.MustNewDuration(time.Second), + OCR2CachePollPeriod: commoncfg.MustNewDuration(time.Minute), + OCR2CacheTTL: commoncfg.MustNewDuration(time.Hour), + TxMsgTimeout: commoncfg.MustNewDuration(time.Second), }, Nodes: []*coscfg.Node{ - {Name: ptr("primary"), TendermintURL: relaycfg.MustParseURL("http://tender.mint")}, - {Name: ptr("foo"), TendermintURL: relaycfg.MustParseURL("http://foo.url")}, - {Name: ptr("bar"), TendermintURL: relaycfg.MustParseURL("http://bar.web")}, + {Name: ptr("primary"), TendermintURL: commoncfg.MustParseURL("http://tender.mint")}, + {Name: ptr("foo"), TendermintURL: commoncfg.MustParseURL("http://foo.url")}, + {Name: ptr("bar"), TendermintURL: commoncfg.MustParseURL("http://bar.web")}, }, }, } diff --git a/core/services/chainlink/mocks/relayer_chain_interoperators.go b/core/services/chainlink/mocks/relayer_chain_interoperators.go index 81f112f766..f778f61b0c 100644 --- a/core/services/chainlink/mocks/relayer_chain_interoperators.go +++ b/core/services/chainlink/mocks/relayer_chain_interoperators.go @@ -9,11 +9,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) // FakeRelayerChainInteroperators is a fake chainlink.RelayerChainInteroperators. diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 1183277ac0..3be1395694 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -7,10 +7,10 @@ import ( "sort" "sync" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 293cc298c8..da1246c7bf 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -9,9 +9,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/loop" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" @@ -84,7 +84,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 1 node 1"), - URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8547").URL())), }}, }, &solana.TOMLConfig{ @@ -93,7 +93,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 2 node 1"), - URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8527").URL())), + URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8527").URL())), }}, }, } @@ -106,15 +106,15 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 1 node 1"), - URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8547").URL())), }, { Name: ptr("starknet chain 1 node 2"), - URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8548").URL())), + URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8548").URL())), }, { Name: ptr("starknet chain 1 node 3"), - URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:8549").URL())), + URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8549").URL())), }, }, }, @@ -125,7 +125,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 2 node 1"), - URL: ((*relaycfg.URL)(models.MustParseURL("http://localhost:3547").URL())), + URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:3547").URL())), }, }, }, @@ -143,7 +143,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 1 node 1"), - TendermintURL: (*relaycfg.URL)(models.MustParseURL("http://localhost:9548").URL()), + TendermintURL: (*commoncfg.URL)(models.MustParseURL("http://localhost:9548").URL()), }, }, }, @@ -158,7 +158,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 2 node 1"), - TendermintURL: (*relaycfg.URL)(models.MustParseURL("http://localhost:9598").URL()), + TendermintURL: (*commoncfg.URL)(models.MustParseURL("http://localhost:9598").URL()), }, }, }, diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 4bbabea4c8..6376839c70 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -9,9 +9,9 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-solana/pkg/solana" pkgsolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" pkgstarknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink" diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 10943308b3..9da84fd3ee 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -9,8 +9,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 1c7929d94d..56c28e5745 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" diff --git a/core/services/directrequest/validate.go b/core/services/directrequest/validate.go index cdb478e8aa..bc31f09b68 100644 --- a/core/services/directrequest/validate.go +++ b/core/services/directrequest/validate.go @@ -4,7 +4,7 @@ import ( "github.com/pelletier/go-toml" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index f6e8952d6b..da19a33abc 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -17,7 +17,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/fluxmonitorv2/config.go b/core/services/fluxmonitorv2/config.go index 0360e9ce03..2680f30a77 100644 --- a/core/services/fluxmonitorv2/config.go +++ b/core/services/fluxmonitorv2/config.go @@ -3,7 +3,7 @@ package fluxmonitorv2 import ( "time" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index 5dbeaeafc3..ea853d879d 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -15,7 +15,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index e8bbf739bb..1a14fb8bd0 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -20,7 +20,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" diff --git a/core/services/fluxmonitorv2/payment_checker.go b/core/services/fluxmonitorv2/payment_checker.go index b5dbd73c06..e4cc40c96a 100644 --- a/core/services/fluxmonitorv2/payment_checker.go +++ b/core/services/fluxmonitorv2/payment_checker.go @@ -3,7 +3,7 @@ package fluxmonitorv2 import ( "math/big" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" ) // MinFundedRounds defines the minimum number of rounds that needs to be paid diff --git a/core/services/fluxmonitorv2/payment_checker_test.go b/core/services/fluxmonitorv2/payment_checker_test.go index 48a06553cb..baec564233 100644 --- a/core/services/fluxmonitorv2/payment_checker_test.go +++ b/core/services/fluxmonitorv2/payment_checker_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" ) diff --git a/core/services/fluxmonitorv2/validate_test.go b/core/services/fluxmonitorv2/validate_test.go index b397e6d374..94dc8b6b70 100644 --- a/core/services/fluxmonitorv2/validate_test.go +++ b/core/services/fluxmonitorv2/validate_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 5b67e333d2..343980afdd 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -10,8 +10,8 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index 1bf9f8e593..82c3dab3af 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -7,7 +7,7 @@ import ( "math/big" "testing" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/functions" diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index efb40330cb..3a30843180 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/cbor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/gateway/connectionmanager.go b/core/services/gateway/connectionmanager.go index 278c4beaaa..ce4a54f4c2 100644 --- a/core/services/gateway/connectionmanager.go +++ b/core/services/gateway/connectionmanager.go @@ -15,7 +15,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" diff --git a/core/services/gateway/connector/connector.go b/core/services/gateway/connector/connector.go index 5578681944..0694e9ad15 100644 --- a/core/services/gateway/connector/connector.go +++ b/core/services/gateway/connector/connector.go @@ -10,7 +10,7 @@ import ( "github.com/gorilla/websocket" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" diff --git a/core/services/gateway/gateway.go b/core/services/gateway/gateway.go index 42e03107f3..79ddf0a5c6 100644 --- a/core/services/gateway/gateway.go +++ b/core/services/gateway/gateway.go @@ -13,7 +13,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" diff --git a/core/services/gateway/handlers/functions/allowlist.go b/core/services/gateway/handlers/functions/allowlist.go index 914a933eb1..3ba9a65d57 100644 --- a/core/services/gateway/handlers/functions/allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_allow_list" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index a4301ef7e9..32a132c075 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -13,8 +13,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index 4c8ba5bec3..00334d3068 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" diff --git a/core/services/gateway/handlers/functions/subscriptions.go b/core/services/gateway/handlers/functions/subscriptions.go index c7a6519e69..7a59e05731 100644 --- a/core/services/gateway/handlers/functions/subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/gateway/network/httpserver.go b/core/services/gateway/network/httpserver.go index 3cae8dc276..d4340a92e9 100644 --- a/core/services/gateway/network/httpserver.go +++ b/core/services/gateway/network/httpserver.go @@ -8,7 +8,7 @@ import ( "net/http" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" ) diff --git a/core/services/gateway/network/wsconnection.go b/core/services/gateway/network/wsconnection.go index 9215d183d1..813b644282 100644 --- a/core/services/gateway/network/wsconnection.go +++ b/core/services/gateway/network/wsconnection.go @@ -5,7 +5,7 @@ import ( "errors" "sync/atomic" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/gorilla/websocket" diff --git a/core/services/gateway/network/wsserver.go b/core/services/gateway/network/wsserver.go index 86812a313e..58b2dfe663 100644 --- a/core/services/gateway/network/wsserver.go +++ b/core/services/gateway/network/wsserver.go @@ -10,7 +10,7 @@ import ( "github.com/gorilla/websocket" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" ) diff --git a/core/services/health.go b/core/services/health.go index 568823fa32..32e97fd8db 100644 --- a/core/services/health.go +++ b/core/services/health.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index c2fc425918..87ee15873d 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" diff --git a/core/services/job/models.go b/core/services/job/models.go index 0b3e622f59..05dcab831f 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -14,8 +14,8 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -434,7 +434,7 @@ type DirectRequestSpec struct { ContractAddress ethkey.EIP55Address `toml:"contractAddress"` MinIncomingConfirmations clnull.Uint32 `toml:"minIncomingConfirmations"` Requesters models.AddressCollection `toml:"requesters"` - MinContractPayment *relayassets.Link `toml:"minContractPaymentLinkJuels"` + MinContractPayment *commonassets.Link `toml:"minContractPaymentLinkJuels"` EVMChainID *utils.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` @@ -475,7 +475,7 @@ type FluxMonitorSpec struct { DrumbeatSchedule string DrumbeatRandomDelay time.Duration DrumbeatEnabled bool - MinPayment *relayassets.Link + MinPayment *commonassets.Link EVMChainID *utils.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` diff --git a/core/services/job/orm.go b/core/services/job/orm.go index fb897bc928..ba102c6bb8 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -18,7 +18,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index 03ee8cee13..5656011e14 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -11,7 +11,7 @@ import ( "github.com/jmoiron/sqlx" - relayservices "github.com/smartcontractkit/chainlink-relay/pkg/services" + commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" @@ -43,7 +43,7 @@ type ( } spawner struct { - relayservices.StateMachine + commonservices.StateMachine orm ORM config Config checker services.Checker @@ -170,7 +170,7 @@ func (js *spawner) stopService(jobID int32) { for i := len(aj.services) - 1; i >= 0; i-- { service := aj.services[i] sLggr := lggr.With("subservice", i, "serviceType", reflect.TypeOf(service)) - if c, ok := service.(relayservices.HealthReporter); ok { + if c, ok := service.(commonservices.HealthReporter); ok { if err := js.checker.Unregister(c.Name()); err != nil { sLggr.Warnw("Failed to unregister service from health checker", "err", err) } @@ -230,7 +230,7 @@ func (js *spawner) StartService(ctx context.Context, jb Job, qopts ...pg.QOpt) e lggr.Criticalw("Error starting service for job", "err", err) return err } - if c, ok := srv.(relayservices.HealthReporter); ok { + if c, ok := srv.(commonservices.HealthReporter); ok { err = js.checker.Register(c) if err != nil { lggr.Errorw("Error registering service with health checker", "err", err) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index cfe646d866..0ad7649143 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -11,8 +11,8 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" diff --git a/core/services/keeper/registry_synchronizer_core.go b/core/services/keeper/registry_synchronizer_core.go index 761958ce19..db7cca1763 100644 --- a/core/services/keeper/registry_synchronizer_core.go +++ b/core/services/keeper/registry_synchronizer_core.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/services/keeper/upkeep_executer.go b/core/services/keeper/upkeep_executer.go index 30e9f36357..ece6f85b06 100644 --- a/core/services/keeper/upkeep_executer.go +++ b/core/services/keeper/upkeep_executer.go @@ -12,7 +12,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" diff --git a/core/services/keystore/cosmos.go b/core/services/keystore/cosmos.go index c06dfcdbce..e3549fdb93 100644 --- a/core/services/keystore/cosmos.go +++ b/core/services/keystore/cosmos.go @@ -6,7 +6,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" ) @@ -147,7 +147,7 @@ func (ks *cosmos) getByID(id string) (cosmoskey.Key, error) { return key, nil } -// CosmosLoopKeystore implements the [github.com/smartcontractkit/chainlink-relay/pkg/loop.Keystore] interface and +// CosmosLoopKeystore implements the [github.com/smartcontractkit/chainlink-common/pkg/loop.Keystore] interface and // handles signing for Cosmos messages. type CosmosLoopKeystore struct { Cosmos diff --git a/core/services/keystore/keys/ethkey/address.go b/core/services/keystore/keys/ethkey/address.go index c14b602c59..1b26413f63 100644 --- a/core/services/keystore/keys/ethkey/address.go +++ b/core/services/keystore/keys/ethkey/address.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink-relay/pkg/utils/bytes" + "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" ) // EIP55Address is a new type for string which persists an ethereum address in diff --git a/core/services/keystore/starknet.go b/core/services/keystore/starknet.go index 7bf454004d..251c74d0e0 100644 --- a/core/services/keystore/starknet.go +++ b/core/services/keystore/starknet.go @@ -9,8 +9,8 @@ import ( "github.com/smartcontractkit/caigo" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - adapters "github.com/smartcontractkit/chainlink-relay/pkg/loop/adapters/starknet" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + adapters "github.com/smartcontractkit/chainlink-common/pkg/loop/adapters/starknet" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" ) @@ -155,7 +155,7 @@ func (ks *starknet) getByID(id string) (starkkey.Key, error) { return key, nil } -// StarknetLooppSigner implements [github.com/smartcontractkit/chainlink-relay/pkg/loop.Keystore] interface and the requirements +// StarknetLooppSigner implements [github.com/smartcontractkit/chainlink-common/pkg/loop.Keystore] interface and the requirements // of signature d/encoding of the [github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/txm.NewKeystoreAdapter] type StarknetLooppSigner struct { StarkNet @@ -165,7 +165,7 @@ var _ loop.Keystore = &StarknetLooppSigner{} // Sign implements [loop.Keystore] // hash is expected to be the byte representation of big.Int -// the returned []byte is an encoded [github.com/smartcontractkit/chainlink-relay/pkg/loop/adapters/starknet.Signature]. +// the returned []byte is an encoded [github.com/smartcontractkit/chainlink-common/pkg/loop/adapters/starknet.Signature]. // this enables compatibility with [github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/txm.NewKeystoreAdapter] func (lk *StarknetLooppSigner) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { diff --git a/core/services/mocks/checker.go b/core/services/mocks/checker.go index 354812d021..e0c209d8af 100644 --- a/core/services/mocks/checker.go +++ b/core/services/mocks/checker.go @@ -3,7 +3,7 @@ package mocks import ( - pkgservices "github.com/smartcontractkit/chainlink-relay/pkg/services" + pkgservices "github.com/smartcontractkit/chainlink-common/pkg/services" mock "github.com/stretchr/testify/mock" ) diff --git a/core/services/multi.go b/core/services/multi.go index 4ea263f5a3..1e465d5e72 100644 --- a/core/services/multi.go +++ b/core/services/multi.go @@ -3,7 +3,7 @@ package services import ( "io" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" ) // StartClose is a subset of the ServiceCtx interface. diff --git a/core/services/nurse.go b/core/services/nurse.go index e414ca280e..3d896a80ff 100644 --- a/core/services/nurse.go +++ b/core/services/nurse.go @@ -17,7 +17,7 @@ import ( "github.com/google/pprof/profile" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/services/ocr/config_overrider.go b/core/services/ocr/config_overrider.go index 5b2ac20c00..b1acf9a7d7 100644 --- a/core/services/ocr/config_overrider.go +++ b/core/services/ocr/config_overrider.go @@ -12,7 +12,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 3e614fef4a..5fecbe8628 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -20,7 +20,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index 0559469abb..c8de3ec33c 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -11,7 +11,7 @@ import ( "github.com/jmoiron/sqlx" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrnetworking "github.com/smartcontractkit/libocr/networking" @@ -167,7 +167,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e v2Bootstrappers = peerWrapper.P2PConfig().V2().DefaultBootstrappers() } - ocrLogger := relaylogger.NewOCRWrapper(lggr, chain.Config().OCR().TraceLogging(), func(msg string) { + ocrLogger := commonlogger.NewOCRWrapper(lggr, chain.Config().OCR().TraceLogging(), func(msg string) { d.jobORM.TryRecordError(jb.ID, msg) }) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 944c04c8d4..4b5932cd70 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -15,6 +15,7 @@ import ( "github.com/pkg/errors" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -29,10 +30,10 @@ import ( dkgpkg "github.com/smartcontractkit/ocr2vrf/dkg" "github.com/smartcontractkit/ocr2vrf/ocr2vrf" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/loop/reportingplugins" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -387,7 +388,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { return nil, errors.New("peerWrapper is not started. OCR2 jobs require a started and running p2p v2 peer") } - ocrLogger := relaylogger.NewOCRWrapper(lggr, d.cfg.OCR2().TraceLogging(), func(msg string) { + ocrLogger := commonlogger.NewOCRWrapper(lggr, d.cfg.OCR2().TraceLogging(), func(msg string) { lggr.ErrorIf(d.jobORM.RecordError(jb.ID, msg), "unable to record error") }) @@ -958,11 +959,11 @@ func (d *Delegate) newServicesOCR2VRF( "jobName", jb.Name.ValueOrZero(), "jobID", jb.ID, ) - vrfLogger := relaylogger.NewOCRWrapper(l.With( + vrfLogger := commonlogger.NewOCRWrapper(l.With( "vrfContractID", spec.ContractID), d.cfg.OCR2().TraceLogging(), func(msg string) { lggr.ErrorIf(d.jobORM.RecordError(jb.ID, msg), "unable to record error") }) - dkgLogger := relaylogger.NewOCRWrapper(l.With( + dkgLogger := commonlogger.NewOCRWrapper(l.With( "dkgContractID", cfg.DKGContractAddress), d.cfg.OCR2().TraceLogging(), func(msg string) { lggr.ErrorIf(d.jobORM.RecordError(jb.ID, msg), "unable to record error") }) diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index daffac3f96..b55e128119 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" diff --git a/core/services/ocr2/plugins/functions/config/config.go b/core/services/ocr2/plugins/functions/config/config.go index a179a22ce4..13e0204250 100644 --- a/core/services/ocr2/plugins/functions/config/config.go +++ b/core/services/ocr2/plugins/functions/config/config.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/types" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 14d7415cab..475cf0a2af 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -13,7 +13,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/functions/plugin_test.go b/core/services/ocr2/plugins/functions/plugin_test.go index eea751789a..453d4b67aa 100644 --- a/core/services/ocr2/plugins/functions/plugin_test.go +++ b/core/services/ocr2/plugins/functions/plugin_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" diff --git a/core/services/ocr2/plugins/functions/reporting_test.go b/core/services/ocr2/plugins/functions/reporting_test.go index 860492bfc5..5b9f59ccb2 100644 --- a/core/services/ocr2/plugins/functions/reporting_test.go +++ b/core/services/ocr2/plugins/functions/reporting_test.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" functions_srv "github.com/smartcontractkit/chainlink/v2/core/services/functions" @@ -24,7 +24,7 @@ import ( func preparePlugin(t *testing.T, batchSize uint32, maxTotalGasLimit uint32) (types.ReportingPlugin, *functions_mocks.ORM, encoding.ReportCodec, *functions_mocks.OffchainTransmitter) { lggr := logger.TestLogger(t) - ocrLogger := relaylogger.NewOCRWrapper(lggr, true, func(msg string) {}) + ocrLogger := commonlogger.NewOCRWrapper(lggr, true, func(msg string) {}) orm := functions_mocks.NewORM(t) offchainTransmitter := functions_mocks.NewOffchainTransmitter(t) factory := functions.FunctionsReportingPluginFactory{ diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go index def33114e8..872f83d3c3 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go index ef0e7421b5..f70e0dd443 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" _ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter.go b/core/services/ocr2/plugins/generic/telemetry_adapter.go index 51d94f5cfe..a2ec6ba20c 100644 --- a/core/services/ocr2/plugins/generic/telemetry_adapter.go +++ b/core/services/ocr2/plugins/generic/telemetry_adapter.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) var _ types.TelemetryService = (*TelemetryAdapter)(nil) diff --git a/core/services/ocr2/plugins/median/plugin.go b/core/services/ocr2/plugins/median/plugin.go index f8517386b3..4f83c4b5dd 100644 --- a/core/services/ocr2/plugins/median/plugin.go +++ b/core/services/ocr2/plugins/median/plugin.go @@ -6,10 +6,10 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 8d121083f3..9d65921ef2 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -9,8 +9,8 @@ import ( libocr "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index ae2b4ca974..e8adb55b39 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -34,10 +34,10 @@ import ( ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/wsrpc/credentials" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaycodecv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" - relaycodecv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" - relaycodecv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaycodecv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + relaycodecv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + relaycodecv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index ddef1374a4..bd68ccd8b7 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -7,10 +7,10 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -30,7 +30,7 @@ type Config interface { func NewServices( jb job.Job, - ocr2Provider relaytypes.MercuryProvider, + ocr2Provider commontypes.MercuryProvider, pipelineRunner pipeline.Runner, runResults chan *pipeline.Run, lggr logger.Logger, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go index 4044bb5f2a..d8941d505b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go @@ -15,7 +15,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" "github.com/smartcontractkit/ocr2keepers/pkg/v2/encoding" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go index 2d49a91e98..7fe4087cfa 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go @@ -19,7 +19,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go index 6cc19a4d02..ae407b0ea9 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go @@ -11,7 +11,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go index 349db2902b..d3f069a9bf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go @@ -18,7 +18,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index d6e7ad51d1..c656656815 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go index b83aca8a02..d34787f501 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go @@ -17,7 +17,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go index 8f84ca1495..000d40f407 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go @@ -10,7 +10,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go index 6c5f767bd3..f5e3969bc7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go @@ -10,7 +10,7 @@ import ( ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index f4fbf24f41..109a644ca0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -18,7 +18,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" + gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" @@ -34,10 +34,9 @@ import ( ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" automationForwarderLogic "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_forwarder_logic" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" @@ -67,7 +66,7 @@ func TestFilterNamesFromSpec21(t *testing.T) { address := common.HexToAddress(hexutil.Encode(b)) spec := &job.OCR2OracleSpec{ - PluginType: relaytypes.OCR2Keeper, + PluginType: types.OCR2Keeper, ContractID: address.String(), // valid contract addr } @@ -79,7 +78,7 @@ func TestFilterNamesFromSpec21(t *testing.T) { assert.Equal(t, logpoller.FilterName("KeeperRegistry Events", address), names[1]) spec = &job.OCR2OracleSpec{ - PluginType: relaytypes.OCR2Keeper, + PluginType: types.OCR2Keeper, ContractID: "0x5431", // invalid contract addr } _, err = ocr2keeper.FilterNamesFromSpec21(spec) @@ -723,7 +722,7 @@ func deployKeeper21Registry( return registryMaster } -func getUpkeepIdFromTx21(t *testing.T, registry *iregistry21.IKeeperRegistryMaster, registrationTx *types.Transaction, backend *backends.SimulatedBackend) *big.Int { +func getUpkeepIdFromTx21(t *testing.T, registry *iregistry21.IKeeperRegistryMaster, registrationTx *gethtypes.Transaction, backend *backends.SimulatedBackend) *big.Int { receipt, err := backend.TransactionReceipt(testutils.Context(t), registrationTx.Hash()) require.NoError(t, err) parsedLog, err := registry.ParseUpkeepRegistered(*receipt.Logs[0]) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 569dc20753..a2184d92ae 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -19,7 +19,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" + gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" @@ -62,7 +62,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) const ( @@ -196,7 +196,7 @@ func accountsToAddress(accounts []ocrTypes.Account) (addresses []common.Address, return addresses, nil } -func getUpkeepIdFromTx(t *testing.T, registry *keeper_registry_wrapper2_0.KeeperRegistry, registrationTx *types.Transaction, backend *backends.SimulatedBackend) *big.Int { +func getUpkeepIdFromTx(t *testing.T, registry *keeper_registry_wrapper2_0.KeeperRegistry, registrationTx *gethtypes.Transaction, backend *backends.SimulatedBackend) *big.Int { receipt, err := backend.TransactionReceipt(testutils.Context(t), registrationTx.Hash()) require.NoError(t, err) parsedLog, err := registry.ParseUpkeepRegistered(*receipt.Logs[0]) @@ -714,7 +714,7 @@ func TestFilterNamesFromSpec20(t *testing.T) { address := common.HexToAddress(hexutil.Encode(b)) spec := &job.OCR2OracleSpec{ - PluginType: relaytypes.OCR2Keeper, + PluginType: types.OCR2Keeper, ContractID: address.String(), // valid contract addr } @@ -726,7 +726,7 @@ func TestFilterNamesFromSpec20(t *testing.T) { assert.Equal(t, logpoller.FilterName("EvmRegistry - Upkeep events for", address), names[1]) spec = &job.OCR2OracleSpec{ - PluginType: relaytypes.OCR2Keeper, + PluginType: types.OCR2Keeper, ContractID: "0x5431", // invalid contract addr } _, err = ocr2keeper.FilterNamesFromSpec20(spec) diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index fca98d8700..504b6267c6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -4,13 +4,14 @@ import ( "fmt" "github.com/jmoiron/sqlx" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocr2keepers20 "github.com/smartcontractkit/ocr2keepers/pkg/v2" ocr2keepers20coordinator "github.com/smartcontractkit/ocr2keepers/pkg/v2/coordinator" ocr2keepers20polling "github.com/smartcontractkit/ocr2keepers/pkg/v2/observer/polling" ocr2keepers20runner "github.com/smartcontractkit/ocr2keepers/pkg/v2/runner" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ocr2keepers21 "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index dc489b4958..f634ee0c01 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" + gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -25,7 +25,7 @@ import ( "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -1469,7 +1469,7 @@ func newRandomnessRequestedLog( SubID: big.NewInt(1), CostJuels: big.NewInt(50_000), NewSubBalance: big.NewInt(100_000), - Raw: types.Log{ + Raw: gethtypes.Log{ BlockNumber: requestBlock, }, } @@ -1544,7 +1544,7 @@ func newRandomnessFulfillmentRequestedLog( Requester: common.HexToAddress("0x1234567890"), CostJuels: big.NewInt(50_000), NewSubBalance: big.NewInt(100_000), - Raw: types.Log{ + Raw: gethtypes.Log{ BlockNumber: requestBlock, }, } @@ -1763,7 +1763,7 @@ func TestFilterNamesFromSpec(t *testing.T) { spec := &job.OCR2OracleSpec{ ContractID: beaconAddress.String(), - PluginType: relaytypes.OCR2VRF, + PluginType: types.OCR2VRF, PluginConfig: job.JSONConfig{ "VRFCoordinatorAddress": coordinatorAddress.String(), "DKGContractAddress": dkgAddress.String(), @@ -1777,7 +1777,7 @@ func TestFilterNamesFromSpec(t *testing.T) { assert.Equal(t, logpoller.FilterName("VRF Coordinator", beaconAddress, coordinatorAddress, dkgAddress), names[0]) spec = &job.OCR2OracleSpec{ - PluginType: relaytypes.OCR2VRF, + PluginType: types.OCR2VRF, ContractID: beaconAddress.String(), PluginConfig: nil, // missing coordinator & dkg addresses } diff --git a/core/services/ocr2/plugins/s4/factory_test.go b/core/services/ocr2/plugins/s4/factory_test.go index 1b75988d83..13a36a5382 100644 --- a/core/services/ocr2/plugins/s4/factory_test.go +++ b/core/services/ocr2/plugins/s4/factory_test.go @@ -8,7 +8,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" s4_mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/libocr/offchainreporting2/types" @@ -18,7 +18,7 @@ import ( func TestS4ReportingPluginFactory_NewReportingPlugin(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) orm := s4_mocks.NewORM(t) f := s4.S4ReportingPluginFactory{ diff --git a/core/services/ocr2/plugins/s4/integration_test.go b/core/services/ocr2/plugins/s4/integration_test.go index 98ccd312e4..54f0f02ad9 100644 --- a/core/services/ocr2/plugins/s4/integration_test.go +++ b/core/services/ocr2/plugins/s4/integration_test.go @@ -18,7 +18,7 @@ import ( s4_svc "github.com/smartcontractkit/chainlink/v2/core/services/s4" "github.com/smartcontractkit/chainlink/v2/core/utils" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2/types" @@ -56,7 +56,7 @@ func newDON(t *testing.T, size int, config *s4.PluginConfig) *don { orm := s4_svc.NewPostgresORM(db, logger, pgtest.NewQConfig(false), s4_svc.SharedTableName, ns) orms[i] = orm - ocrLogger := relaylogger.NewOCRWrapper(logger, true, func(msg string) {}) + ocrLogger := commonlogger.NewOCRWrapper(logger, true, func(msg string) {}) plugin, err := s4.NewReportingPlugin(ocrLogger, config, orm) require.NoError(t, err) plugins[i] = plugin diff --git a/core/services/ocr2/plugins/s4/plugin_test.go b/core/services/ocr2/plugins/s4/plugin_test.go index 94c876a4f7..e2b5d21b84 100644 --- a/core/services/ocr2/plugins/s4/plugin_test.go +++ b/core/services/ocr2/plugins/s4/plugin_test.go @@ -13,13 +13,14 @@ import ( s4_mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" "github.com/smartcontractkit/chainlink/v2/core/utils" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "google.golang.org/protobuf/proto" + + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) func createPluginConfig(maxEntries uint) *s4.PluginConfig { @@ -121,7 +122,7 @@ func rowsToShapshotRows(rows []*s4_svc.Row) []*s4_svc.SnapshotRow { func TestPlugin_NewReportingPlugin(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) orm := s4_mocks.NewORM(t) t.Run("ErrInvalidIntervals", func(t *testing.T) { @@ -167,7 +168,7 @@ func TestPlugin_NewReportingPlugin(t *testing.T) { func TestPlugin_Close(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) config := createPluginConfig(10) orm := s4_mocks.NewORM(t) plugin, err := s4.NewReportingPlugin(logger, config, orm) @@ -180,7 +181,7 @@ func TestPlugin_Close(t *testing.T) { func TestPlugin_ShouldTransmitAcceptedReport(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) config := createPluginConfig(10) orm := s4_mocks.NewORM(t) plugin, err := s4.NewReportingPlugin(logger, config, orm) @@ -194,7 +195,7 @@ func TestPlugin_ShouldTransmitAcceptedReport(t *testing.T) { func TestPlugin_ShouldAcceptFinalizedReport(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) config := createPluginConfig(10) orm := s4_mocks.NewORM(t) plugin, err := s4.NewReportingPlugin(logger, config, orm) @@ -255,7 +256,7 @@ func TestPlugin_ShouldAcceptFinalizedReport(t *testing.T) { func TestPlugin_Query(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) config := createPluginConfig(10) orm := s4_mocks.NewORM(t) plugin, err := s4.NewReportingPlugin(logger, config, orm) @@ -332,7 +333,7 @@ func TestPlugin_Query(t *testing.T) { func TestPlugin_Observation(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) config := createPluginConfig(10) orm := s4_mocks.NewORM(t) plugin, err := s4.NewReportingPlugin(logger, config, orm) @@ -465,7 +466,7 @@ func TestPlugin_Observation(t *testing.T) { func TestPlugin_Report(t *testing.T) { t.Parallel() - logger := relaylogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) + logger := commonlogger.NewOCRWrapper(logger.TestLogger(t), true, func(msg string) {}) config := createPluginConfig(10) orm := s4_mocks.NewORM(t) plugin, err := s4.NewReportingPlugin(logger, config, orm) diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 65b95cb31a..c97d23dca0 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -12,7 +12,7 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/job" dkgconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" diff --git a/core/services/ocrbootstrap/delegate.go b/core/services/ocrbootstrap/delegate.go index 34e3ee0a71..7912741802 100644 --- a/core/services/ocrbootstrap/delegate.go +++ b/core/services/ocrbootstrap/delegate.go @@ -8,11 +8,12 @@ import ( "github.com/pkg/errors" "github.com/jmoiron/sqlx" + ocr "github.com/smartcontractkit/libocr/offchainreporting2plus" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -165,7 +166,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e ContractConfigTracker: configProvider.ContractConfigTracker(), Database: NewDB(d.db.DB, spec.ID, lggr), LocalConfig: lc, - Logger: relaylogger.NewOCRWrapper(lggr.Named("OCRBootstrap"), d.ocr2Cfg.TraceLogging(), func(msg string) { + Logger: commonlogger.NewOCRWrapper(lggr.Named("OCRBootstrap"), d.ocr2Cfg.TraceLogging(), func(msg string) { logger.Sugared(lggr).ErrorIf(d.jobORM.RecordError(jb.ID, msg), "unable to record error") }), OffchainConfigDigester: configProvider.OffchainConfigDigester(), diff --git a/core/services/ocrcommon/peer_wrapper.go b/core/services/ocrcommon/peer_wrapper.go index 1daa84b721..a7d510ef90 100644 --- a/core/services/ocrcommon/peer_wrapper.go +++ b/core/services/ocrcommon/peer_wrapper.go @@ -12,13 +12,14 @@ import ( "go.uber.org/multierr" "github.com/jmoiron/sqlx" + ocrnetworking "github.com/smartcontractkit/libocr/networking" ocrnetworkingtypes "github.com/smartcontractkit/libocr/networking/types" ocr1types "github.com/smartcontractkit/libocr/offchainreporting/types" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -194,7 +195,7 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { peerConfig := ocrnetworking.PeerConfig{ NetworkingStack: config.NetworkStack(), PrivKey: key.PrivKey, - Logger: relaylogger.NewOCRWrapper(p.lggr, p.ocrCfg.TraceLogging(), func(string) {}), + Logger: commonlogger.NewOCRWrapper(p.lggr, p.ocrCfg.TraceLogging(), func(string) {}), // V1 config V1ListenIP: config.V1().ListenIP(), V1ListenPort: p2pPort, diff --git a/core/services/ocrcommon/peerstore.go b/core/services/ocrcommon/peerstore.go index 02a4d90f57..1d859184ab 100644 --- a/core/services/ocrcommon/peerstore.go +++ b/core/services/ocrcommon/peerstore.go @@ -14,7 +14,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" diff --git a/core/services/ocrcommon/run_saver.go b/core/services/ocrcommon/run_saver.go index d8dcc34358..184226605f 100644 --- a/core/services/ocrcommon/run_saver.go +++ b/core/services/ocrcommon/run_saver.go @@ -3,7 +3,7 @@ package ocrcommon import ( "context" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index be139723ef..c9d3e85cd2 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -13,7 +13,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -21,9 +21,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/utils" - relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" + relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" ) type eaTelemetry struct { diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index 9e3dedce8a..24c798259d 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -6,16 +6,17 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" "google.golang.org/protobuf/proto" - "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - mercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" - mercury_v2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + mercury_v2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/periodicbackup/backup.go b/core/services/periodicbackup/backup.go index f43698bbdb..b1bcf40ee3 100644 --- a/core/services/periodicbackup/backup.go +++ b/core/services/periodicbackup/backup.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/pg/event_broadcaster.go b/core/services/pg/event_broadcaster.go index f18ac3251a..70008f4c0d 100644 --- a/core/services/pg/event_broadcaster.go +++ b/core/services/pg/event_broadcaster.go @@ -11,7 +11,7 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/static" diff --git a/core/services/pg/q.go b/core/services/pg/q.go index 9c9c15d983..050606c793 100644 --- a/core/services/pg/q.go +++ b/core/services/pg/q.go @@ -17,7 +17,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" ) var promSQLQueryTime = promauto.NewHistogram(prometheus.HistogramOpts{ diff --git a/core/services/pg/sqlx.go b/core/services/pg/sqlx.go index c371c29213..c252edf9f5 100644 --- a/core/services/pg/sqlx.go +++ b/core/services/pg/sqlx.go @@ -9,7 +9,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" ) type Queryer interface { diff --git a/core/services/pg/transaction.go b/core/services/pg/transaction.go index 74841d010b..fd7e74baca 100644 --- a/core/services/pg/transaction.go +++ b/core/services/pg/transaction.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" corelogger "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index 056a7deab2..eb242e6276 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -13,7 +13,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index d33913b475..edb1d337af 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -14,7 +14,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/services/promreporter/prom_reporter.go b/core/services/promreporter/prom_reporter.go index fd6afeeb8e..2306640bea 100644 --- a/core/services/promreporter/prom_reporter.go +++ b/core/services/promreporter/prom_reporter.go @@ -13,7 +13,7 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index daccf400ea..fe39ed0e34 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index aa1d1d774b..e8267c9a84 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -20,8 +20,8 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -44,7 +44,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) -var _ relaytypes.Relayer = &Relayer{} //nolint:staticcheck +var _ commontypes.Relayer = &Relayer{} //nolint:staticcheck type Relayer struct { db *sqlx.DB @@ -130,7 +130,7 @@ func (r *Relayer) HealthReport() (report map[string]error) { return } -func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (relaytypes.MercuryProvider, error) { +func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.MercuryProvider, error) { lggr := r.lggr.Named("MercuryProvider").Named(rargs.ExternalJobID.String()) relayOpts := types.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() @@ -193,13 +193,13 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype return NewMercuryProvider(cw, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, chainReader, lggr), nil } -func (r *Relayer) NewFunctionsProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (relaytypes.FunctionsProvider, error) { +func (r *Relayer) NewFunctionsProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.FunctionsProvider, error) { lggr := r.lggr.Named("FunctionsProvider").Named(rargs.ExternalJobID.String()) // TODO(FUN-668): Not ready yet (doesn't implement FunctionsEvents() properly) return NewFunctionsProvider(r.chain, rargs, pargs, lggr, r.ks.Eth(), functions.FunctionsPlugin) } -func (r *Relayer) NewConfigProvider(args relaytypes.RelayArgs) (relaytypes.ConfigProvider, error) { +func (r *Relayer) NewConfigProvider(args commontypes.RelayArgs) (commontypes.ConfigProvider, error) { lggr := r.lggr.Named("ConfigProvider").Named(args.ExternalJobID.String()) relayOpts := types.NewRelayOpts(args) relayConfig, err := relayOpts.RelayConfig() @@ -219,7 +219,7 @@ func (r *Relayer) NewConfigProvider(args relaytypes.RelayArgs) (relaytypes.Confi return configProvider, err } -func FilterNamesFromRelayArgs(args relaytypes.RelayArgs) (filterNames []string, err error) { +func FilterNamesFromRelayArgs(args commontypes.RelayArgs) (filterNames []string, err error) { var addr ethkey.EIP55Address if addr, err = ethkey.NewEIP55Address(args.ContractID); err != nil { return nil, err @@ -373,7 +373,7 @@ func newConfigProvider(lggr logger.Logger, chain evm.Chain, opts *types.RelayOpt return newConfigWatcher(lggr, aggregatorAddress, contractABI, offchainConfigDigester, cp, chain, relayConfig.FromBlock, opts.New), nil } -func newContractTransmitter(lggr logger.Logger, rargs relaytypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth) (*contractTransmitter, error) { +func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth) (*contractTransmitter, error) { var relayConfig types.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -442,7 +442,7 @@ func newContractTransmitter(lggr logger.Logger, rargs relaytypes.RelayArgs, tran ) } -func newPipelineContractTransmitter(lggr logger.Logger, rargs relaytypes.RelayArgs, transmitterID string, pluginGasLimit *uint32, configWatcher *configWatcher, spec job.Job, pr pipeline.Runner) (*contractTransmitter, error) { +func newPipelineContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, pluginGasLimit *uint32, configWatcher *configWatcher, spec job.Job, pr pipeline.Runner) (*contractTransmitter, error) { var relayConfig types.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -491,7 +491,7 @@ func newPipelineContractTransmitter(lggr logger.Logger, rargs relaytypes.RelayAr ) } -func (r *Relayer) NewMedianProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (relaytypes.MedianProvider, error) { +func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.MedianProvider, error) { lggr := r.lggr.Named("MedianProvider").Named(rargs.ExternalJobID.String()) relayOpts := types.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() @@ -526,7 +526,7 @@ func (r *Relayer) NewMedianProvider(rargs relaytypes.RelayArgs, pargs relaytypes }, nil } -var _ relaytypes.MedianProvider = (*medianProvider)(nil) +var _ commontypes.MedianProvider = (*medianProvider)(nil) type medianProvider struct { configWatcher *configWatcher diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index fdd6201c69..88f9d22099 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -16,8 +16,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -46,7 +46,7 @@ func (p *functionsProvider) LogPollerWrapper() evmRelayTypes.LogPollerWrapper { return p.logPollerWrapper } -func (p *functionsProvider) FunctionsEvents() relaytypes.FunctionsEvents { +func (p *functionsProvider) FunctionsEvents() commontypes.FunctionsEvents { // TODO (FUN-668): implement return nil } @@ -85,7 +85,7 @@ func (p *functionsProvider) Name() string { return p.configWatcher.Name() } -func NewFunctionsProvider(chain evm.Chain, rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { +func NewFunctionsProvider(chain evm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { relayOpts := evmRelayTypes.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() if err != nil { @@ -130,7 +130,7 @@ func NewFunctionsProvider(chain evm.Chain, rargs relaytypes.RelayArgs, pargs rel }, nil } -func newFunctionsConfigProvider(pluginType functionsRelay.FunctionsPluginType, chain evm.Chain, args relaytypes.RelayArgs, fromBlock uint64, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (*configWatcher, error) { +func newFunctionsConfigProvider(pluginType functionsRelay.FunctionsPluginType, chain evm.Chain, args commontypes.RelayArgs, fromBlock uint64, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (*configWatcher, error) { if !common.IsHexAddress(args.ContractID) { return nil, errors.Errorf("invalid contractID, expected hex address") } @@ -153,7 +153,7 @@ func newFunctionsConfigProvider(pluginType functionsRelay.FunctionsPluginType, c return newConfigWatcher(lggr, routerContractAddress, contractABI, offchainConfigDigester, cp, chain, fromBlock, args.New), nil } -func newFunctionsContractTransmitter(contractVersion uint32, rargs relaytypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (ContractTransmitter, error) { +func newFunctionsContractTransmitter(contractVersion uint32, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (ContractTransmitter, error) { var relayConfig evmRelayTypes.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go index 6193f4ba86..230185d0ad 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper.go +++ b/core/services/relay/evm/functions/logpoller_wrapper.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" diff --git a/core/services/relay/evm/loop_impl.go b/core/services/relay/evm/loop_impl.go index f69660373e..309b5e24f6 100644 --- a/core/services/relay/evm/loop_impl.go +++ b/core/services/relay/evm/loop_impl.go @@ -1,7 +1,7 @@ package evm import ( - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/services/relay" diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index 9de1f80c6b..69dfce9c16 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -7,7 +7,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" diff --git a/core/services/relay/evm/mercury/queue.go b/core/services/relay/evm/mercury/queue.go index 3d20b3f2b0..07ef8a9742 100644 --- a/core/services/relay/evm/mercury/queue.go +++ b/core/services/relay/evm/mercury/queue.go @@ -13,7 +13,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 269f28b122..73aa10243f 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -17,11 +17,12 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index 0bdfb67de7..79eb32af44 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -13,8 +13,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 3aea503ae6..635658d786 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -15,8 +15,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go index fefddd6395..28688e3b17 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go @@ -8,9 +8,10 @@ import ( "github.com/ethereum/go-ethereum/common" pkgerrors "github.com/pkg/errors" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go index 3f4838c3e7..f630b4522b 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index 17bc4a6670..f7b7892513 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -10,8 +10,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/services/relay/evm/mercury/v2/data_source_test.go b/core/services/relay/evm/mercury/v2/data_source_test.go index b66355ac7f..0249203193 100644 --- a/core/services/relay/evm/mercury/v2/data_source_test.go +++ b/core/services/relay/evm/mercury/v2/data_source_test.go @@ -8,8 +8,8 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go index 0e1dfe9c46..6b13b3b6ef 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go @@ -6,9 +6,10 @@ import ( "math/big" pkgerrors "github.com/pkg/errors" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go index 8cf16a5dab..3a58337b4c 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" ) func newValidReportFields() relaymercuryv2.ReportFields { diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index 6f2b2eb6bd..34dbd13be9 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -11,8 +11,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/services/relay/evm/mercury/v3/data_source_test.go b/core/services/relay/evm/mercury/v3/data_source_test.go index aefc766996..c4b5b4c610 100644 --- a/core/services/relay/evm/mercury/v3/data_source_test.go +++ b/core/services/relay/evm/mercury/v3/data_source_test.go @@ -8,8 +8,8 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go index 4c0b3756d7..6b379dc194 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go @@ -7,9 +7,10 @@ import ( "math/big" pkgerrors "github.com/pkg/errors" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" + reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go index 98b81edb00..88416f7ea6 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" + relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" ) func newValidReportFields() relaymercuryv3.ReportFields { diff --git a/core/services/relay/evm/mercury/wsrpc/client.go b/core/services/relay/evm/mercury/wsrpc/client.go index f6ed1d0db8..c4db80a58d 100644 --- a/core/services/relay/evm/mercury/wsrpc/client.go +++ b/core/services/relay/evm/mercury/wsrpc/client.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/wsrpc" "github.com/smartcontractkit/wsrpc/connectivity" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index bba5e699bc..9025380817 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -6,19 +6,19 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" + relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + "github.com/smartcontractkit/chainlink-common/pkg/services" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" ) -var _ relaytypes.MercuryProvider = (*mercuryProvider)(nil) +var _ commontypes.MercuryProvider = (*mercuryProvider)(nil) type mercuryProvider struct { configWatcher *configWatcher diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 13107fe8ae..13a73036a1 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -9,7 +9,7 @@ import ( evm "github.com/smartcontractkit/chainlink/v2/core/chains/evm" mock "github.com/stretchr/testify/mock" - types "github.com/smartcontractkit/chainlink-relay/pkg/types" + types "github.com/smartcontractkit/chainlink-common/pkg/types" ) // LoopRelayAdapter is an autogenerated mock type for the LoopRelayAdapter type diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index a284d677eb..2e8f9cbf48 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -10,12 +10,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -33,19 +34,19 @@ var ( // OCR2KeeperProviderOpts is the custom options to create a keeper provider type OCR2KeeperProviderOpts struct { - RArgs relaytypes.RelayArgs - PArgs relaytypes.PluginArgs + RArgs commontypes.RelayArgs + PArgs commontypes.PluginArgs InstanceID int } // OCR2KeeperProvider provides all components needed for a OCR2Keeper plugin. type OCR2KeeperProvider interface { - relaytypes.Plugin + commontypes.Plugin } // OCR2KeeperRelayer contains the relayer and instantiating functions for OCR2Keeper providers. type OCR2KeeperRelayer interface { - NewOCR2KeeperProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (OCR2KeeperProvider, error) + NewOCR2KeeperProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (OCR2KeeperProvider, error) } // ocr2keeperRelayer is the relayer with added DKG and OCR2Keeper provider functions. @@ -68,7 +69,7 @@ func NewOCR2KeeperRelayer(db *sqlx.DB, chain evm.Chain, pr pipeline.Runner, spec } } -func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (OCR2KeeperProvider, error) { +func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (OCR2KeeperProvider, error) { cfgWatcher, err := newOCR2KeeperConfigProvider(r.lggr, r.chain, rargs) if err != nil { return nil, err @@ -129,7 +130,7 @@ func (c *ocr2keeperProvider) ContractTransmitter() ocrtypes.ContractTransmitter return c.contractTransmitter } -func newOCR2KeeperConfigProvider(lggr logger.Logger, chain evm.Chain, rargs relaytypes.RelayArgs) (*configWatcher, error) { +func newOCR2KeeperConfigProvider(lggr logger.Logger, chain evm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) if err != nil { diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index 0c9414068e..66ce42b7d8 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -9,11 +9,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -24,18 +25,18 @@ import ( // DKGProvider provides all components needed for a DKG plugin. type DKGProvider interface { - relaytypes.Plugin + commontypes.Plugin } // OCR2VRFProvider provides all components needed for a OCR2VRF plugin. type OCR2VRFProvider interface { - relaytypes.Plugin + commontypes.Plugin } // OCR2VRFRelayer contains the relayer and instantiating functions for OCR2VRF providers. type OCR2VRFRelayer interface { - NewDKGProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (DKGProvider, error) - NewOCR2VRFProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (OCR2VRFProvider, error) + NewDKGProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (DKGProvider, error) + NewOCR2VRFProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (OCR2VRFProvider, error) } var ( @@ -61,7 +62,7 @@ func NewOCR2VRFRelayer(db *sqlx.DB, chain evm.Chain, lggr logger.Logger, ethKeys } } -func (r *ocr2vrfRelayer) NewDKGProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (DKGProvider, error) { +func (r *ocr2vrfRelayer) NewDKGProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (DKGProvider, error) { configWatcher, err := newOCR2VRFConfigProvider(r.lggr, r.chain, rargs) if err != nil { return nil, err @@ -84,7 +85,7 @@ func (r *ocr2vrfRelayer) NewDKGProvider(rargs relaytypes.RelayArgs, pargs relayt }, nil } -func (r *ocr2vrfRelayer) NewOCR2VRFProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (OCR2VRFProvider, error) { +func (r *ocr2vrfRelayer) NewOCR2VRFProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (OCR2VRFProvider, error) { configWatcher, err := newOCR2VRFConfigProvider(r.lggr, r.chain, rargs) if err != nil { return nil, err @@ -118,7 +119,7 @@ func (c *ocr2vrfProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } -func newOCR2VRFConfigProvider(lggr logger.Logger, chain evm.Chain, rargs relaytypes.RelayArgs) (*configWatcher, error) { +func newOCR2VRFConfigProvider(lggr logger.Logger, chain evm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) if err != nil { diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index b6ca4d75fb..43626037a1 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -8,8 +8,8 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmchain "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -75,11 +75,11 @@ type ChainRelayerExt struct { var _ EVMChainRelayerExtender = &ChainRelayerExt{} -func (s *ChainRelayerExt) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { +func (s *ChainRelayerExt) GetChainStatus(ctx context.Context) (commontypes.ChainStatus, error) { return s.chain.GetChainStatus(ctx) } -func (s *ChainRelayerExt) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { +func (s *ChainRelayerExt) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []commontypes.NodeStatus, nextPageToken string, total int, err error) { return s.chain.ListNodeStatuses(ctx, pageSize, pageToken) } diff --git a/core/services/relay/evm/request_round_tracker.go b/core/services/relay/evm/request_round_tracker.go index c1c3a49e0e..1f1ed71fc3 100644 --- a/core/services/relay/evm/request_round_tracker.go +++ b/core/services/relay/evm/request_round_tracker.go @@ -10,10 +10,11 @@ import ( "github.com/pkg/errors" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index 6a1e66bd09..d2edef8b11 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -13,9 +13,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink-relay/pkg/types" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -36,7 +36,7 @@ type RelayConfig struct { type RelayOpts struct { // TODO BCF-2508 -- should anyone ever get the raw config bytes that are embedded in args? if not, // make this private and wrap the arg fields with funcs on RelayOpts - relaytypes.RelayArgs + commontypes.RelayArgs c *RelayConfig } @@ -71,9 +71,9 @@ type ConfigPoller interface { Replay(ctx context.Context, fromBlock int64) error } -// TODO(FUN-668): Migrate this fully into relaytypes.FunctionsProvider +// TODO(FUN-668): Migrate this fully into commontypes.FunctionsProvider type FunctionsProvider interface { - relaytypes.FunctionsProvider + commontypes.FunctionsProvider LogPollerWrapper() LogPollerWrapper } diff --git a/core/services/relay/grpc_provider_server.go b/core/services/relay/grpc_provider_server.go index 943af0e636..67bbb8c6c2 100644 --- a/core/services/relay/grpc_provider_server.go +++ b/core/services/relay/grpc_provider_server.go @@ -8,8 +8,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/services/relay/grpc_provider_server_test.go b/core/services/relay/grpc_provider_server_test.go index e7ee8d7f15..fafe20ef12 100644 --- a/core/services/relay/grpc_provider_server_test.go +++ b/core/services/relay/grpc_provider_server_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" ) diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index 5c7bf5cab5..eb6d3faf4f 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -5,8 +5,8 @@ import ( "fmt" "regexp" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) type Network = string diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index 5bcd14c64a..fc9e273e30 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -4,12 +4,13 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) func TestIdentifier_UnmarshalString(t *testing.T) { diff --git a/core/services/service.go b/core/services/service.go index 066405ac01..19ca118373 100644 --- a/core/services/service.go +++ b/core/services/service.go @@ -1,7 +1,7 @@ package services import ( - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" ) type ServiceCtx = services.Service diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go index 26abda65d3..c551ac85b3 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client.go +++ b/core/services/synchronization/telemetry_ingress_batch_client.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/wsrpc" "github.com/smartcontractkit/wsrpc/examples/simple/keys" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go index 9458b7627c..b889b3fc97 100644 --- a/core/services/synchronization/telemetry_ingress_client.go +++ b/core/services/synchronization/telemetry_ingress_client.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/wsrpc" "github.com/smartcontractkit/wsrpc/examples/simple/keys" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go index cc14a956c1..d760d13b2b 100644 --- a/core/services/telemetry/manager.go +++ b/core/services/telemetry/manager.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 2d51d9f449..d24fb348b7 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go index a8e662c931..35556c6b45 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index b1f9bbb503..566e5ac9bd 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -16,7 +16,7 @@ import ( heaps "github.com/theodesp/go-heaps" "github.com/theodesp/go-heaps/pairing" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index df886924aa..15121ba306 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -30,7 +30,7 @@ import ( "github.com/jmoiron/sqlx" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -1462,7 +1462,7 @@ func simulatedOverrides(t *testing.T, defaultGasPrice *assets.Wei, ks ...toml.Ke c.EVM[0].FinalityDepth = ptr[uint32](15) c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - c.EVM[0].MinContractPayment = relayassets.NewLinkFromJuels(100) + c.EVM[0].MinContractPayment = commonassets.NewLinkFromJuels(100) c.EVM[0].KeySpecific = ks } } diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 3480f63f09..5b73ac9e24 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -25,7 +25,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 0ff0900016..43ddd41d56 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/utils/big.go b/core/utils/big.go index f0f9a2d96d..22cd8e64e5 100644 --- a/core/utils/big.go +++ b/core/utils/big.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/smartcontractkit/chainlink-relay/pkg/utils/bytes" + "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/core/utils/config/validate.go b/core/utils/config/validate.go index 32cb94b520..5fbae24ad5 100644 --- a/core/utils/config/validate.go +++ b/core/utils/config/validate.go @@ -9,7 +9,7 @@ import ( "github.com/Masterminds/semver/v3" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink-relay/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/utils/mailbox_prom.go b/core/utils/mailbox_prom.go index dc20db84d9..33cbb2357b 100644 --- a/core/utils/mailbox_prom.go +++ b/core/utils/mailbox_prom.go @@ -10,7 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" ) var mailboxLoad = promauto.NewGaugeVec(prometheus.GaugeOpts{ diff --git a/core/utils/sleeper_task.go b/core/utils/sleeper_task.go index fcec254249..d84457e932 100644 --- a/core/utils/sleeper_task.go +++ b/core/utils/sleeper_task.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" ) // SleeperTask represents a task that waits in the background to process some work. diff --git a/core/utils/utils.go b/core/utils/utils.go index 6ea7164df1..a2e418fe04 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -32,7 +32,7 @@ import ( "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/sha3" - "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" ) const ( diff --git a/core/web/bridge_types_controller.go b/core/web/bridge_types_controller.go index 57a79e2b61..f320a52523 100644 --- a/core/web/bridge_types_controller.go +++ b/core/web/bridge_types_controller.go @@ -8,7 +8,7 @@ import ( "github.com/jackc/pgconn" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/web/bridge_types_controller_test.go b/core/web/bridge_types_controller_test.go index a65362ba9a..a7873ad9f7 100644 --- a/core/web/bridge_types_controller_test.go +++ b/core/web/bridge_types_controller_test.go @@ -6,7 +6,7 @@ import ( "net/http" "testing" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/web/chains_controller.go b/core/web/chains_controller.go index c11d457c49..e547cf0150 100644 --- a/core/web/chains_controller.go +++ b/core/web/chains_controller.go @@ -7,7 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/manyminds/api2go/jsonapi" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" diff --git a/core/web/cosmos_chains_controller_test.go b/core/web/cosmos_chains_controller_test.go index f8dbe4614f..5491b33c35 100644 --- a/core/web/cosmos_chains_controller_test.go +++ b/core/web/cosmos_chains_controller_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/types" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index 6e2a3b2efc..b202d90f21 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/config/toml" @@ -365,13 +365,13 @@ func (ekc *ETHKeysController) getEthBalance(ctx context.Context, state ethkey.St } -func (ekc *ETHKeysController) setLinkBalance(bal *relayassets.Link) presenters.NewETHKeyOption { +func (ekc *ETHKeysController) setLinkBalance(bal *commonassets.Link) presenters.NewETHKeyOption { return presenters.SetETHKeyLinkBalance(bal) } // queries the EthClient for the LINK balance at the address associated with state -func (ekc *ETHKeysController) getLinkBalance(ctx context.Context, state ethkey.State) *relayassets.Link { - var bal *relayassets.Link +func (ekc *ETHKeysController) getLinkBalance(ctx context.Context, state ethkey.State) *commonassets.Link { + var bal *commonassets.Link chainID := state.EVMChainID.ToInt() chain, err := ekc.app.GetRelayers().LegacyEVMChains().Get(chainID.String()) if err != nil { diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index 8941c2d2fd..d0ad27262f 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" diff --git a/core/web/loader/getters.go b/core/web/loader/getters.go index 8ca29cc962..27a39181ff 100644 --- a/core/web/loader/getters.go +++ b/core/web/loader/getters.go @@ -7,7 +7,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -21,7 +21,7 @@ import ( var ErrInvalidType = errors.New("invalid type") // GetChainByID fetches the chain by it's id. -func GetChainByID(ctx context.Context, id string) (*relaytypes.ChainStatus, error) { +func GetChainByID(ctx context.Context, id string) (*commontypes.ChainStatus, error) { ldr := For(ctx) thunk := ldr.ChainsByIDLoader.Load(ctx, dataloader.StringKey(id)) @@ -30,7 +30,7 @@ func GetChainByID(ctx context.Context, id string) (*relaytypes.ChainStatus, erro return nil, err } - chain, ok := result.(relaytypes.ChainStatus) + chain, ok := result.(commontypes.ChainStatus) if !ok { return nil, ErrInvalidType } diff --git a/core/web/loader/loader_test.go b/core/web/loader/loader_test.go index 984aa9f618..9bd1feb05b 100644 --- a/core/web/loader/loader_test.go +++ b/core/web/loader/loader_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -50,12 +50,12 @@ func TestLoader_Chains(t *testing.T) { assert.Len(t, results, 3) config2, err := chain2.TOMLString() require.NoError(t, err) - want2 := relaytypes.ChainStatus{ID: "2", Enabled: true, Config: config2} - assert.Equal(t, want2, results[0].Data.(relaytypes.ChainStatus)) + want2 := commontypes.ChainStatus{ID: "2", Enabled: true, Config: config2} + assert.Equal(t, want2, results[0].Data.(commontypes.ChainStatus)) config1, err := chain.TOMLString() require.NoError(t, err) - want1 := relaytypes.ChainStatus{ID: "1", Enabled: true, Config: config1} - assert.Equal(t, want1, results[1].Data.(relaytypes.ChainStatus)) + want1 := commontypes.ChainStatus{ID: "1", Enabled: true, Config: config1} + assert.Equal(t, want1, results[1].Data.(commontypes.ChainStatus)) assert.Nil(t, results[2].Data) assert.Error(t, results[2].Error) assert.ErrorIs(t, results[2].Error, chains.ErrNotFound) @@ -69,13 +69,13 @@ func TestLoader_Nodes(t *testing.T) { chainID1, chainID2, notAnID := big.NewInt(1), big.NewInt(2), big.NewInt(3) - genNodeStat := func(id string) relaytypes.NodeStatus { - return relaytypes.NodeStatus{ + genNodeStat := func(id string) commontypes.NodeStatus { + return commontypes.NodeStatus{ Name: "test-node-" + id, ChainID: id, } } - rcInterops := &chainlinkmocks.FakeRelayerChainInteroperators{Nodes: []relaytypes.NodeStatus{ + rcInterops := &chainlinkmocks.FakeRelayerChainInteroperators{Nodes: []commontypes.NodeStatus{ genNodeStat(chainID2.String()), genNodeStat(chainID1.String()), }} @@ -86,9 +86,9 @@ func TestLoader_Nodes(t *testing.T) { found := batcher.loadByChainIDs(ctx, keys) require.Len(t, found, 3) - assert.Equal(t, []relaytypes.NodeStatus{genNodeStat(chainID2.String())}, found[0].Data) - assert.Equal(t, []relaytypes.NodeStatus{genNodeStat(chainID1.String())}, found[1].Data) - assert.Equal(t, []relaytypes.NodeStatus{}, found[2].Data) + assert.Equal(t, []commontypes.NodeStatus{genNodeStat(chainID2.String())}, found[0].Data) + assert.Equal(t, []commontypes.NodeStatus{genNodeStat(chainID1.String())}, found[1].Data) + assert.Equal(t, []commontypes.NodeStatus{}, found[2].Data) } func TestLoader_FeedsManagers(t *testing.T) { diff --git a/core/web/loader/node.go b/core/web/loader/node.go index 9ea6062dc2..ef8e363d9f 100644 --- a/core/web/loader/node.go +++ b/core/web/loader/node.go @@ -5,7 +5,7 @@ import ( "github.com/graph-gophers/dataloader" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/relay" diff --git a/core/web/loop_registry_test.go b/core/web/loop_registry_test.go index ea76672564..94e2bc856d 100644 --- a/core/web/loop_registry_test.go +++ b/core/web/loop_registry_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" diff --git a/core/web/nodes_controller.go b/core/web/nodes_controller.go index 3547b150bc..04c4693983 100644 --- a/core/web/nodes_controller.go +++ b/core/web/nodes_controller.go @@ -7,7 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/manyminds/api2go/jsonapi" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" diff --git a/core/web/presenters/bridges.go b/core/web/presenters/bridges.go index 440e444c61..82f4a961c9 100644 --- a/core/web/presenters/bridges.go +++ b/core/web/presenters/bridges.go @@ -3,7 +3,7 @@ package presenters import ( "time" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" ) diff --git a/core/web/presenters/bridges_test.go b/core/web/presenters/bridges_test.go index f6ce3af756..746d361958 100644 --- a/core/web/presenters/bridges_test.go +++ b/core/web/presenters/bridges_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/core/web/presenters/cosmos_chain.go b/core/web/presenters/cosmos_chain.go index d65a110287..c3b006e5c7 100644 --- a/core/web/presenters/cosmos_chain.go +++ b/core/web/presenters/cosmos_chain.go @@ -1,7 +1,7 @@ package presenters import ( - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) // CosmosChainResource is an Cosmos chain JSONAPI resource. diff --git a/core/web/presenters/eth_key.go b/core/web/presenters/eth_key.go index 9265442761..3d952dabed 100644 --- a/core/web/presenters/eth_key.go +++ b/core/web/presenters/eth_key.go @@ -3,7 +3,7 @@ package presenters import ( "time" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -13,14 +13,14 @@ import ( // representation of the address plus its ETH & LINK balances type ETHKeyResource struct { JAID - EVMChainID utils.Big `json:"evmChainID"` - Address string `json:"address"` - EthBalance *assets.Eth `json:"ethBalance"` - LinkBalance *relayassets.Link `json:"linkBalance"` - Disabled bool `json:"disabled"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - MaxGasPriceWei *utils.Big `json:"maxGasPriceWei"` + EVMChainID utils.Big `json:"evmChainID"` + Address string `json:"address"` + EthBalance *assets.Eth `json:"ethBalance"` + LinkBalance *commonassets.Link `json:"linkBalance"` + Disabled bool `json:"disabled"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + MaxGasPriceWei *utils.Big `json:"maxGasPriceWei"` } // GetName implements the api2go EntityNamer interface @@ -63,7 +63,7 @@ func SetETHKeyEthBalance(ethBalance *assets.Eth) NewETHKeyOption { } } -func SetETHKeyLinkBalance(linkBalance *relayassets.Link) NewETHKeyOption { +func SetETHKeyLinkBalance(linkBalance *commonassets.Link) NewETHKeyOption { return func(r *ETHKeyResource) { r.LinkBalance = linkBalance } diff --git a/core/web/presenters/eth_key_test.go b/core/web/presenters/eth_key_test.go index 0e68fbc90c..85d005cf61 100644 --- a/core/web/presenters/eth_key_test.go +++ b/core/web/presenters/eth_key_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -40,12 +40,12 @@ func TestETHKeyResource(t *testing.T) { r := NewETHKeyResource(key, state, SetETHKeyEthBalance(assets.NewEth(1)), - SetETHKeyLinkBalance(relayassets.NewLinkFromJuels(1)), + SetETHKeyLinkBalance(commonassets.NewLinkFromJuels(1)), SetETHKeyMaxGasPriceWei(utils.NewBigI(12345)), ) assert.Equal(t, assets.NewEth(1), r.EthBalance) - assert.Equal(t, relayassets.NewLinkFromJuels(1), r.LinkBalance) + assert.Equal(t, commonassets.NewLinkFromJuels(1), r.LinkBalance) assert.Equal(t, utils.NewBigI(12345), r.MaxGasPriceWei) b, err := jsonapi.Marshal(r) diff --git a/core/web/presenters/evm_chain.go b/core/web/presenters/evm_chain.go index 25862875ee..8cc6da46a7 100644 --- a/core/web/presenters/evm_chain.go +++ b/core/web/presenters/evm_chain.go @@ -1,6 +1,6 @@ package presenters -import "github.com/smartcontractkit/chainlink-relay/pkg/types" +import "github.com/smartcontractkit/chainlink-common/pkg/types" // EVMChainResource is an EVM chain JSONAPI resource. type EVMChainResource struct { diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index d9ec1844ae..dc5bf62333 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -7,7 +7,7 @@ import ( "github.com/lib/pq" "gopkg.in/guregu/null.v4" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -44,7 +44,7 @@ const ( type DirectRequestSpec struct { ContractAddress ethkey.EIP55Address `json:"contractAddress"` MinIncomingConfirmations clnull.Uint32 `json:"minIncomingConfirmations"` - MinContractPayment *relayassets.Link `json:"minContractPaymentLinkJuels"` + MinContractPayment *commonassets.Link `json:"minContractPaymentLinkJuels"` Requesters models.AddressCollection `json:"requesters"` Initiator string `json:"initiator"` CreatedAt time.Time `json:"createdAt"` @@ -81,7 +81,7 @@ type FluxMonitorSpec struct { DrumbeatEnabled bool `json:"drumbeatEnabled"` DrumbeatSchedule *string `json:"drumbeatSchedule"` DrumbeatRandomDelay *string `json:"drumbeatRandomDelay"` - MinPayment *relayassets.Link `json:"minPayment"` + MinPayment *commonassets.Link `json:"minPayment"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` EVMChainID *utils.Big `json:"evmChainID"` diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index 46c765a38b..7e997c899c 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" diff --git a/core/web/presenters/solana_chain.go b/core/web/presenters/solana_chain.go index ba6cace7c3..f04d2b65d5 100644 --- a/core/web/presenters/solana_chain.go +++ b/core/web/presenters/solana_chain.go @@ -1,7 +1,7 @@ package presenters import ( - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) // SolanaChainResource is an Solana chain JSONAPI resource. diff --git a/core/web/presenters/starknet_chain.go b/core/web/presenters/starknet_chain.go index 2a9e49e74c..ec1cd453a5 100644 --- a/core/web/presenters/starknet_chain.go +++ b/core/web/presenters/starknet_chain.go @@ -1,7 +1,7 @@ package presenters import ( - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) // StarkNetChainResource is an StarkNet chain JSONAPI resource. diff --git a/core/web/resolver/bridge_test.go b/core/web/resolver/bridge_test.go index e708ac92a4..71ef4a2b34 100644 --- a/core/web/resolver/bridge_test.go +++ b/core/web/resolver/bridge_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/core/web/resolver/chain.go b/core/web/resolver/chain.go index 53f1016d72..32e9a8caac 100644 --- a/core/web/resolver/chain.go +++ b/core/web/resolver/chain.go @@ -3,7 +3,7 @@ package resolver import ( "github.com/graph-gophers/graphql-go" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) // ChainResolver resolves the Chain type. diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index f8f417ca44..d75282e0fb 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/mock" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -96,7 +96,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) f.Mocks.ethKs.On("GetAll").Return(keys, nil) - f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(relayassets.NewLinkFromJuels(12), nil) + f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(commonassets.NewLinkFromJuels(12), nil) f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) f.Mocks.balM.On("GetEthBalance", address).Return(assets.NewEth(1)) f.Mocks.chain.On("BalanceMonitor").Return(f.Mocks.balM) @@ -301,7 +301,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) f.Mocks.ethKs.On("GetAll").Return(keys, nil) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) - f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(relayassets.NewLinkFromJuels(12), gError) + f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(commonassets.NewLinkFromJuels(12), gError) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(f.Mocks.chain, nil) f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) @@ -354,7 +354,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) f.Mocks.ethKs.On("GetAll").Return(keys, nil) - f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(relayassets.NewLinkFromJuels(12), nil) + f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(commonassets.NewLinkFromJuels(12), nil) f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) f.Mocks.chain.On("BalanceMonitor").Return(nil) f.Mocks.chain.On("Config").Return(f.Mocks.scfg) diff --git a/core/web/resolver/helpers.go b/core/web/resolver/helpers.go index 2dc865674e..36080a8b54 100644 --- a/core/web/resolver/helpers.go +++ b/core/web/resolver/helpers.go @@ -8,7 +8,7 @@ import ( "github.com/graph-gophers/graphql-go" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" ) diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index 52f914e0a8..990a6c0805 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -13,7 +13,7 @@ import ( "go.uber.org/zap/zapcore" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-relay/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" diff --git a/core/web/resolver/node.go b/core/web/resolver/node.go index 39a85e83b1..8e01b7056b 100644 --- a/core/web/resolver/node.go +++ b/core/web/resolver/node.go @@ -7,7 +7,7 @@ import ( "github.com/graph-gophers/graphql-go" "github.com/pelletier/go-toml/v2" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" evmtoml "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/web/loader" diff --git a/core/web/resolver/node_test.go b/core/web/resolver/node_test.go index 9f34b27420..24a31b986f 100644 --- a/core/web/resolver/node_test.go +++ b/core/web/resolver/node_test.go @@ -6,7 +6,7 @@ import ( gqlerrors "github.com/graph-gophers/graphql-go/errors" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" diff --git a/core/web/resolver/query.go b/core/web/resolver/query.go index e9fd18cf19..da15b7f7c2 100644 --- a/core/web/resolver/query.go +++ b/core/web/resolver/query.go @@ -10,7 +10,7 @@ import ( "github.com/graph-gophers/graphql-go" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index fd369088bb..4de66f1dcb 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -9,8 +9,8 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" @@ -97,7 +97,7 @@ func TestResolver_DirectRequestSpec(t *testing.T) { CreatedAt: f.Timestamp(), EVMChainID: utils.NewBigI(42), MinIncomingConfirmations: clnull.NewUint32(1, true), - MinContractPayment: relayassets.NewLinkFromJuels(1000), + MinContractPayment: commonassets.NewLinkFromJuels(1000), Requesters: models.AddressCollection{requesterAddress}, }, }, nil) @@ -164,7 +164,7 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { DrumbeatEnabled: false, IdleTimerDisabled: false, IdleTimerPeriod: time.Duration(1 * time.Hour), - MinPayment: relayassets.NewLinkFromJuels(1000), + MinPayment: commonassets.NewLinkFromJuels(1000), PollTimerDisabled: false, PollTimerPeriod: time.Duration(1 * time.Minute), }, @@ -233,7 +233,7 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { DrumbeatSchedule: "CRON_TZ=UTC 0 0 1 1 *", IdleTimerDisabled: true, IdleTimerPeriod: time.Duration(1 * time.Hour), - MinPayment: relayassets.NewLinkFromJuels(1000), + MinPayment: commonassets.NewLinkFromJuels(1000), PollTimerDisabled: true, PollTimerPeriod: time.Duration(1 * time.Minute), }, diff --git a/core/web/solana_chains_controller_test.go b/core/web/solana_chains_controller_test.go index c4023f166b..1377cb65ab 100644 --- a/core/web/solana_chains_controller_test.go +++ b/core/web/solana_chains_controller_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - relaycfg "github.com/smartcontractkit/chainlink-relay/pkg/config" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" @@ -84,7 +84,7 @@ Nodes = [] ChainID: ptr(validId), Chain: config.Chain{ SkipPreflight: ptr(false), - TxTimeout: relaycfg.MustNewDuration(time.Hour), + TxTimeout: commoncfg.MustNewDuration(time.Hour), }, }) @@ -114,7 +114,7 @@ func Test_SolanaChainsController_Index(t *testing.T) { chainA := &solana.TOMLConfig{ ChainID: ptr(fmt.Sprintf("ChainlinktestA-%d", rand.Int31n(999999))), Chain: config.Chain{ - TxTimeout: relaycfg.MustNewDuration(time.Hour), + TxTimeout: commoncfg.MustNewDuration(time.Hour), }, } chainB := &solana.TOMLConfig{ diff --git a/go.mod b/go.mod index 40803d504c..784d3ff78e 100644 --- a/go.mod +++ b/go.mod @@ -65,10 +65,10 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 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.20231115124244-8303409abccd - 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/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 diff --git a/go.sum b/go.sum index 52975e722a..fb09e792d6 100644 --- a/go.sum +++ b/go.sum @@ -1463,14 +1463,14 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= 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.20231115124244-8303409abccd h1:PRVJxNK67pQWufXuB1cxckH/xZkcQFDy8KjN9ZYqong= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd/go.mod h1:rOayi690YxLlkQy959PD8INhOAIAUi9LoN0G+J/CEf4= -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= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index f48d415792..fd15d51af4 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" @@ -869,7 +869,7 @@ func retreiveLoadTestMetrics( func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2_5.GetSubscription, subID *big.Int, coordinator contracts.VRFCoordinatorV2_5) { l.Debug(). Str("Coordinator", coordinator.Address()). - Str("Link Balance", (*relayassets.Link)(subscription.Balance).Link()). + Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)). Str("Subscription ID", subID.String()). Str("Subscription Owner", subscription.Owner.String()). @@ -972,11 +972,11 @@ func LogFulfillmentDetailsLinkBilling( randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, ) { l.Debug(). - Str("Consumer Balance Before Request (Link)", (*relayassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). - Str("Consumer Balance After Request (Link)", (*relayassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). + Str("Consumer Balance Before Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). + Str("Consumer Balance After Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid by Consumer Contract (Link)", (*relayassets.Link)(consumerStatus.Paid).Link()). - Str("Paid by Coordinator Sub (Link)", (*relayassets.Link)(randomWordsFulfilledEvent.Payment).Link()). + Str("Paid by Consumer Contract (Link)", (*commonassets.Link)(consumerStatus.Paid).Link()). + Str("Paid by Coordinator Sub (Link)", (*commonassets.Link)(randomWordsFulfilledEvent.Payment).Link()). Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). diff --git a/integration-tests/go.mod b/integration-tests/go.mod index aed5e0682c..3b1a5423df 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,7 +22,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e github.com/smartcontractkit/chainlink-testing-framework v1.19.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 @@ -387,9 +387,9 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect 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-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/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 896ae8c6d2..427ad1421c 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2367,14 +2367,14 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= 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.20231115124244-8303409abccd h1:PRVJxNK67pQWufXuB1cxckH/xZkcQFDy8KjN9ZYqong= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231115124244-8303409abccd/go.mod h1:rOayi690YxLlkQy959PD8INhOAIAUi9LoN0G+J/CEf4= -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= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= github.com/smartcontractkit/chainlink-testing-framework v1.19.1 h1:MdGM5jIrBi858Cv7qzfl1Qon93YW8InohAlDQqFoIb4= github.com/smartcontractkit/chainlink-testing-framework v1.19.1/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 6da1d94371..ad85506a04 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -11,7 +11,7 @@ import ( "github.com/segmentio/ksuid" - relayassets "github.com/smartcontractkit/chainlink-relay/pkg/assets" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -171,7 +171,7 @@ func SetChainConfig( chainConfig = evmcfg.Chain{ AutoCreateKey: ptr.Ptr(true), FinalityDepth: ptr.Ptr[uint32](1), - MinContractPayment: relayassets.NewLinkFromJuels(0), + MinContractPayment: commonassets.NewLinkFromJuels(0), } } cfg.EVM = evmcfg.EVMConfigs{ @@ -197,7 +197,7 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { Chain: evmcfg.Chain{ AutoCreateKey: ptr.Ptr(true), FinalityDepth: ptr.Ptr[uint32](50), - MinContractPayment: relayassets.NewLinkFromJuels(0), + MinContractPayment: commonassets.NewLinkFromJuels(0), LogPollInterval: models.MustNewDuration(1 * time.Second), HeadTracker: evmcfg.HeadTracker{ HistoryDepth: ptr.Ptr(uint32(100)), diff --git a/plugins/cmd/chainlink-median/main.go b/plugins/cmd/chainlink-median/main.go index 87815d24d9..e95bfbb221 100644 --- a/plugins/cmd/chainlink-median/main.go +++ b/plugins/cmd/chainlink-median/main.go @@ -3,7 +3,7 @@ package main import ( "github.com/hashicorp/go-plugin" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median" ) diff --git a/plugins/cmd/chainlink-medianpoc/main.go b/plugins/cmd/chainlink-medianpoc/main.go index 325de6538f..eaef96d1b0 100644 --- a/plugins/cmd/chainlink-medianpoc/main.go +++ b/plugins/cmd/chainlink-medianpoc/main.go @@ -3,9 +3,9 @@ package main import ( "github.com/hashicorp/go-plugin" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/loop/reportingplugins" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/plugins/medianpoc" ) diff --git a/plugins/config.go b/plugins/config.go index 938cfd0d00..01574d8209 100644 --- a/plugins/config.go +++ b/plugins/config.go @@ -3,7 +3,7 @@ package plugins import ( "os/exec" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop" ) // RegistrarConfig generates contains static configuration inher diff --git a/plugins/loop_registry.go b/plugins/loop_registry.go index f402fc6fa1..17ad7cba5a 100644 --- a/plugins/loop_registry.go +++ b/plugins/loop_registry.go @@ -5,8 +5,8 @@ import ( "sort" "sync" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/config" ) diff --git a/plugins/medianpoc/data_source.go b/plugins/medianpoc/data_source.go index 7b20f1e5eb..92d4b04ba6 100644 --- a/plugins/medianpoc/data_source.go +++ b/plugins/medianpoc/data_source.go @@ -10,8 +10,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/plugins/medianpoc/data_source_test.go b/plugins/medianpoc/data_source_test.go index e9a7945cee..5848705b7b 100644 --- a/plugins/medianpoc/data_source_test.go +++ b/plugins/medianpoc/data_source_test.go @@ -6,13 +6,14 @@ import ( "math/big" "testing" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) type mockPipelineRunner struct { diff --git a/plugins/medianpoc/plugin.go b/plugins/medianpoc/plugin.go index ceea1eb84f..62b6acc043 100644 --- a/plugins/medianpoc/plugin.go +++ b/plugins/medianpoc/plugin.go @@ -9,11 +9,11 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink-relay/pkg/loop/reportingplugins" - "github.com/smartcontractkit/chainlink-relay/pkg/services" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go index 74a0695c6c..569fcb464b 100644 --- a/plugins/medianpoc/plugin_test.go +++ b/plugins/medianpoc/plugin_test.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" ) From 3d25a9e6b858438035e46691cce6e192f6d3fe46 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Fri, 17 Nov 2023 17:35:05 -0500 Subject: [PATCH 175/327] [TT-724] Fix P2Pv2 For Soak Tests (#11331) * Fix P2Pv2 For Soak Tests * Update default * Tidy * Fix all OCR1 Configs * Tidy? * Tweaked the right setting --- .github/workflows/on-demand-ocr-soak-test.yml | 2 +- integration-tests/chaos/ocr_chaos_test.go | 2 +- integration-tests/config/config.go | 10 +++------- integration-tests/performance/ocr_test.go | 8 ++------ integration-tests/soak/ocr_test.go | 11 +++++++---- integration-tests/testsetups/ocr.go | 2 +- 6 files changed, 15 insertions(+), 20 deletions(-) diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index b17fdc6beb..567d9510de 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -54,7 +54,7 @@ on: chainlinkVersion: description: Container image version for the Chainlink nodes required: true - default: "1.11.0" + default: "2.7.0" testDuration: description: Duration of the test (time string) required: false diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 5368997daa..a59a0a028c 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -52,7 +52,7 @@ var ( ) func TestMain(m *testing.M) { - defaultOCRSettings["toml"] = networks.AddNetworksConfig(config.BaseOCRP2PV1Config, networks.MustGetSelectedNetworksFromEnv()[0]) + defaultOCRSettings["toml"] = networks.AddNetworksConfig(config.BaseOCR1Config, networks.MustGetSelectedNetworksFromEnv()[0]) os.Exit(m.Run()) } diff --git a/integration-tests/config/config.go b/integration-tests/config/config.go index 1da8254e0e..6d00ceb32b 100644 --- a/integration-tests/config/config.go +++ b/integration-tests/config/config.go @@ -1,17 +1,13 @@ package config var ( - BaseOCRP2PV1Config = `[OCR] + BaseOCR1Config = `[OCR] Enabled = true [P2P] [P2P.V2] -Enabled = false - -[P2P.V1] -Enabled = true -ListenIP = '0.0.0.0' -ListenPort = 6690` +AnnounceAddresses = ["0.0.0.0:6690"] +ListenAddresses = ["0.0.0.0:6690"]` BaseOCR2Config = `[Feature] LogPoller = true diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index 7f91f4321a..7e0ed0111d 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -103,13 +103,9 @@ Enabled = true [P2P] [P2P.V2] -Enabled = false +AnnounceAddresses = ["0.0.0.0:6690"] +ListenAddresses = ["0.0.0.0:6690"]` -[P2P] -[P2P.V1] -Enabled = true -ListenIP = '0.0.0.0' -ListenPort = 6690` cd := chainlink.New(0, map[string]interface{}{ "replicas": 6, "toml": networks.AddNetworksConfig(baseTOML, testNetwork), diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index c7d4bc80f6..4f42ff803e 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -1,13 +1,16 @@ package soak import ( + "fmt" "testing" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -16,10 +19,10 @@ func TestOCRSoak(t *testing.T) { // Use this variable to pass in any custom EVM specific TOML values to your Chainlink nodes customNetworkTOML := `` // Uncomment below for debugging TOML issues on the node - // network := networks.MustGetSelectedNetworksFromEnv()[0] - // fmt.Println("Using Chainlink TOML\n---------------------") - // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) - // fmt.Println("---------------------") + network := networks.MustGetSelectedNetworksFromEnv()[0] + fmt.Println("Using Chainlink TOML\n---------------------") + fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customNetworkTOML, network)) + fmt.Println("---------------------") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, false) require.NoError(t, err, "Error creating soak test") diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index dfeb4bb916..a35d915ea9 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -142,7 +142,7 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { cd := chainlink.New(0, map[string]any{ "replicas": 6, - "toml": networks.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customChainlinkNetworkTOML, network), + "toml": networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customChainlinkNetworkTOML, network), "db": map[string]any{ "stateful": true, // stateful DB by default for soak tests }, From 7e1b9cec1c453713779c3b2358050e95e4c30782 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Mon, 20 Nov 2023 10:47:36 +0100 Subject: [PATCH 176/327] bump packages (#11325) --- contracts/package.json | 26 +-- contracts/pnpm-lock.yaml | 382 +++++++++++++++++++-------------------- 2 files changed, 201 insertions(+), 207 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 6d0b7af6cc..2ceb1602dc 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 371 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 369 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", @@ -47,32 +47,32 @@ "@typechain/ethers-v5": "^7.2.0", "@typechain/hardhat": "^7.0.0", "@types/cbor": "5.0.1", - "@types/chai": "^4.3.9", - "@types/debug": "^4.1.10", - "@types/deep-equal-in-any-order": "^1.0.2", - "@types/mocha": "^10.0.3", - "@types/node": "^16.18.58", - "@typescript-eslint/eslint-plugin": "^6.8.0", - "@typescript-eslint/parser": "^6.8.0", + "@types/chai": "^4.3.10", + "@types/debug": "^4.1.12", + "@types/deep-equal-in-any-order": "^1.0.3", + "@types/mocha": "^10.0.4", + "@types/node": "^16.18.61", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", "abi-to-sol": "^0.6.6", "cbor": "^5.2.0", "chai": "^4.3.10", "debug": "^4.3.4", - "eslint": "^8.51.0", + "eslint": "^8.53.0", "eslint-config-prettier": "^9.0.0", "deep-equal-in-any-order": "^2.0.6", "eslint-plugin-prettier": "^5.0.1", "ethereum-waffle": "^3.4.4", "ethers": "~5.7.2", - "hardhat": "~2.18.1", + "hardhat": "~2.19.1", "hardhat-abi-exporter": "^2.10.1", "hardhat-contract-sizer": "^2.10.0", "hardhat-gas-reporter": "^1.0.9", "hardhat-ignore-warnings": "^0.2.6", "istanbul": "^0.4.5", "moment": "^2.29.4", - "prettier": "^3.0.3", - "prettier-plugin-solidity": "1.1.4-dev", + "prettier": "^3.1.0", + "prettier-plugin-solidity": "1.2.0", "rlp": "^2.2.7", "solhint": "^4.0.0", "solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.0", @@ -80,7 +80,7 @@ "solidity-coverage": "^0.8.5", "ts-node": "^10.9.1", "tslib": "^2.6.2", - "typechain": "^8.2.0", + "typechain": "^8.2.1", "typescript": "^5.2.2" }, "dependencies": { diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index ac4efd5f59..fbae71fb3d 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -39,52 +39,52 @@ devDependencies: version: 5.7.0 '@nomicfoundation/hardhat-network-helpers': specifier: ^1.0.9 - version: 1.0.9(hardhat@2.18.1) + version: 1.0.9(hardhat@2.19.1) '@nomiclabs/hardhat-ethers': specifier: ^2.2.3 - version: 2.2.3(ethers@5.7.2)(hardhat@2.18.1) + version: 2.2.3(ethers@5.7.2)(hardhat@2.19.1) '@nomiclabs/hardhat-etherscan': specifier: ^3.1.7 - version: 3.1.7(hardhat@2.18.1) + version: 3.1.7(hardhat@2.19.1) '@nomiclabs/hardhat-waffle': specifier: 2.0.6 - version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.18.1) + version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.1) '@openzeppelin/hardhat-upgrades': specifier: 1.28.0 - version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.18.1) + version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.19.1) '@openzeppelin/test-helpers': specifier: ^0.5.16 version: 0.5.16(bn.js@4.12.0) '@typechain/ethers-v5': specifier: ^7.2.0 - version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.2.2) + version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.2.2) '@typechain/hardhat': specifier: ^7.0.0 - version: 7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.18.1)(typechain@8.2.0) + version: 7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.1)(typechain@8.3.2) '@types/cbor': specifier: 5.0.1 version: 5.0.1 '@types/chai': - specifier: ^4.3.9 - version: 4.3.9 + specifier: ^4.3.10 + version: 4.3.10 '@types/debug': - specifier: ^4.1.10 - version: 4.1.10 + specifier: ^4.1.12 + version: 4.1.12 '@types/deep-equal-in-any-order': - specifier: ^1.0.2 - version: 1.0.2 + specifier: ^1.0.3 + version: 1.0.3 '@types/mocha': - specifier: ^10.0.3 - version: 10.0.3 + specifier: ^10.0.4 + version: 10.0.4 '@types/node': - specifier: ^16.18.58 - version: 16.18.58 + specifier: ^16.18.61 + version: 16.18.61 '@typescript-eslint/eslint-plugin': - specifier: ^6.8.0 - version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2) + specifier: ^6.11.0 + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: ^6.8.0 - version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) + specifier: ^6.11.0 + version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) abi-to-sol: specifier: ^0.6.6 version: 0.6.6 @@ -101,14 +101,14 @@ devDependencies: specifier: ^2.0.6 version: 2.0.6 eslint: - specifier: ^8.51.0 - version: 8.51.0 + specifier: ^8.53.0 + version: 8.53.0 eslint-config-prettier: specifier: ^9.0.0 - version: 9.0.0(eslint@8.51.0) + version: 9.0.0(eslint@8.53.0) eslint-plugin-prettier: specifier: ^5.0.1 - version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.51.0)(prettier@3.0.3) + version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0) ethereum-waffle: specifier: ^3.4.4 version: 3.4.4(typescript@5.2.2) @@ -116,17 +116,17 @@ devDependencies: specifier: ~5.7.2 version: 5.7.2 hardhat: - specifier: ~2.18.1 - version: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + specifier: ~2.19.1 + version: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) hardhat-abi-exporter: specifier: ^2.10.1 - version: 2.10.1(hardhat@2.18.1) + version: 2.10.1(hardhat@2.19.1) hardhat-contract-sizer: specifier: ^2.10.0 - version: 2.10.0(hardhat@2.18.1) + version: 2.10.0(hardhat@2.19.1) hardhat-gas-reporter: specifier: ^1.0.9 - version: 1.0.9(debug@4.3.4)(hardhat@2.18.1) + version: 1.0.9(debug@4.3.4)(hardhat@2.19.1) hardhat-ignore-warnings: specifier: ^0.2.6 version: 0.2.9 @@ -137,11 +137,11 @@ devDependencies: specifier: ^2.29.4 version: 2.29.4 prettier: - specifier: ^3.0.3 - version: 3.0.3 + specifier: ^3.1.0 + version: 3.1.0 prettier-plugin-solidity: - specifier: 1.1.4-dev - version: 1.1.4-dev(prettier@3.0.3) + specifier: 1.2.0 + version: 1.2.0(prettier@3.1.0) rlp: specifier: ^2.2.7 version: 2.2.7 @@ -153,19 +153,19 @@ devDependencies: version: github.com/smartcontractkit/chainlink-solhint-rules/cfc50b32f95b730304a50deb2e27e88d87115874 solhint-plugin-prettier: specifier: ^0.1.0 - version: 0.1.0(prettier-plugin-solidity@1.1.4-dev)(prettier@3.0.3) + version: 0.1.0(prettier-plugin-solidity@1.2.0)(prettier@3.1.0) solidity-coverage: specifier: ^0.8.5 - version: 0.8.5(hardhat@2.18.1) + version: 0.8.5(hardhat@2.19.1) ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@16.18.58)(typescript@5.2.2) + version: 10.9.1(@types/node@16.18.61)(typescript@5.2.2) tslib: specifier: ^2.6.2 version: 2.6.2 typechain: - specifier: ^8.2.0 - version: 8.2.0(typescript@5.2.2) + specifier: ^8.2.1 + version: 8.3.2(typescript@5.2.2) typescript: specifier: ^5.2.2 version: 5.2.2 @@ -324,13 +324,13 @@ packages: deprecated: Please use @ensdomains/ens-contracts dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.51.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.53.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.51.0 + eslint: 8.53.0 eslint-visitor-keys: 3.4.3 dev: true @@ -339,8 +339,8 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@2.1.2: - resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + /@eslint/eslintrc@2.1.3: + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 @@ -356,8 +356,8 @@ packages: - supports-color dev: true - /@eslint/js@8.51.0: - resolution: {integrity: sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==} + /@eslint/js@8.53.0: + resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -789,11 +789,11 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - /@humanwhocodes/config-array@0.11.11: - resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 1.2.1 + '@humanwhocodes/object-schema': 2.0.1 debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: @@ -805,8 +805,8 @@ packages: engines: {node: '>=12.22'} dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: true /@jridgewell/resolve-uri@3.1.1: @@ -1037,13 +1037,13 @@ packages: - utf-8-validate dev: true - /@nomicfoundation/hardhat-network-helpers@1.0.9(hardhat@2.18.1): + /@nomicfoundation/hardhat-network-helpers@1.0.9(hardhat@2.19.1): resolution: {integrity: sha512-OXWCv0cHpwLUO2u7bFxBna6dQtCC2Gg/aN/KtJLO7gmuuA28vgmVKYFRCDUqrbjujzgfwQ2aKyZ9Y3vSmDqS7Q==} peerDependencies: hardhat: ^2.9.5 dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) dev: true /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0: @@ -1152,17 +1152,17 @@ packages: '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.0 dev: true - /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.18.1): + /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.19.1): resolution: {integrity: sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==} peerDependencies: ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: ethers: 5.7.2 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) dev: true - /@nomiclabs/hardhat-etherscan@3.1.7(hardhat@2.18.1): + /@nomiclabs/hardhat-etherscan@3.1.7(hardhat@2.19.1): resolution: {integrity: sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ==} peerDependencies: hardhat: ^2.0.4 @@ -1173,7 +1173,7 @@ packages: chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 7.0.1 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) lodash: 4.17.21 semver: 6.3.0 table: 6.8.1 @@ -1182,7 +1182,7 @@ packages: - supports-color dev: true - /@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.18.1): + /@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.1): resolution: {integrity: sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg==} peerDependencies: '@nomiclabs/hardhat-ethers': ^2.0.0 @@ -1191,11 +1191,11 @@ packages: ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.18.1) + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.1) '@types/sinon-chai': 3.2.8 ethereum-waffle: 3.4.4(typescript@5.2.2) ethers: 5.7.2 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) dev: true /@openzeppelin/contract-loader@0.6.3: @@ -1226,7 +1226,7 @@ packages: - encoding dev: true - /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.18.1): + /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.19.1): resolution: {integrity: sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ==} hasBin: true peerDependencies: @@ -1239,15 +1239,15 @@ packages: '@nomiclabs/harhdat-etherscan': optional: true dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.18.1) - '@nomiclabs/hardhat-etherscan': 3.1.7(hardhat@2.18.1) + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.1) + '@nomiclabs/hardhat-etherscan': 3.1.7(hardhat@2.19.1) '@openzeppelin/defender-base-client': 1.49.0(debug@4.3.4) '@openzeppelin/platform-deploy-client': 0.8.0(debug@4.3.4) '@openzeppelin/upgrades-core': 1.30.1 chalk: 4.1.2 debug: 4.3.4(supports-color@8.1.1) ethers: 5.7.2 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) proper-lockfile: 4.1.2 transitivePeerDependencies: - encoding @@ -1338,12 +1338,12 @@ packages: config-chain: 1.1.13 dev: true - /@prettier/sync@0.3.0(prettier@3.0.3): + /@prettier/sync@0.3.0(prettier@3.1.0): resolution: {integrity: sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==} peerDependencies: prettier: ^3.0.0 dependencies: - prettier: 3.0.3 + prettier: 3.1.0 dev: true /@resolver-engine/core@0.3.3: @@ -1506,8 +1506,8 @@ packages: antlr4ts: 0.5.0-alpha.4 dev: true - /@solidity-parser/parser@0.16.1: - resolution: {integrity: sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==} + /@solidity-parser/parser@0.16.2: + resolution: {integrity: sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==} dependencies: antlr4ts: 0.5.0-alpha.4 dev: true @@ -1663,7 +1663,7 @@ packages: typechain: 3.0.0(typescript@5.2.2) dev: true - /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.2.2): + /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.2.2): resolution: {integrity: sha512-jfcmlTvaaJjng63QsT49MT6R1HFhtO/TBMWbyzPFSzMmVIqb2tL6prnKBs4ZJrSvmgIXWy+ttSjpaxCTq8D/Tw==} peerDependencies: '@ethersproject/abi': ^5.0.0 @@ -1679,11 +1679,11 @@ packages: ethers: 5.7.2 lodash: 4.17.21 ts-essentials: 7.0.3(typescript@5.2.2) - typechain: 8.2.0(typescript@5.2.2) + typechain: 8.3.2(typescript@5.2.2) typescript: 5.2.2 dev: true - /@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.18.1)(typechain@8.2.0): + /@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.1)(typechain@8.3.2): resolution: {integrity: sha512-XB79i5ewg9Met7gMVGfgVkmypicbnI25T5clJBEooMoW2161p4zvKFpoS2O+lBppQyMrPIZkdvl2M3LMDayVcA==} peerDependencies: '@ethersproject/abi': ^5.4.7 @@ -1695,23 +1695,23 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/providers': 5.7.2 - '@typechain/ethers-v5': 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.2.2) + '@typechain/ethers-v5': 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.2.2) ethers: 5.7.2 fs-extra: 9.1.0 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) - typechain: 8.2.0(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + typechain: 8.3.2(typescript@5.2.2) dev: true /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/cacheable-request@6.0.2: @@ -1719,34 +1719,34 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 16.18.58 + '@types/node': 16.18.61 '@types/responselike': 1.0.0 dev: true /@types/cbor@5.0.1: resolution: {integrity: sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true - /@types/chai@4.3.9: - resolution: {integrity: sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg==} + /@types/chai@4.3.10: + resolution: {integrity: sha512-of+ICnbqjmFCiixUnqRulbylyXQrPqIGf/B3Jax1wIF3DvSheysQxAWvqHhZiW3IQrycvokcLcFQlveGp+vyNg==} dev: true /@types/concat-stream@1.6.1: resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true - /@types/debug@4.1.10: - resolution: {integrity: sha512-tOSCru6s732pofZ+sMv9o4o3Zc+Sa8l3bxd/tweTQudFn06vAzb13ZX46Zi6m6EJ+RUbRTHvgQJ1gBtSgkaUYA==} + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: '@types/ms': 0.7.31 dev: true - /@types/deep-equal-in-any-order@1.0.2: - resolution: {integrity: sha512-IUjUMsroT9qb8d7ySAl5V+iT/7UsJDpIFspTLxBWxCLqeJwwptSvmjvDBEEaZt0qodMyUSoOQkLhqZAkqt6dLg==} + /@types/deep-equal-in-any-order@1.0.3: + resolution: {integrity: sha512-jT0O3hAILDKeKbdWJ9FZLD0Xdfhz7hMvfyFlRWpirjiEVr8G+GZ4kVIzPIqM6x6Rpp93TNPgOAed4XmvcuV6Qg==} dev: true /@types/events@3.0.0: @@ -1756,7 +1756,7 @@ packages: /@types/form-data@0.0.33: resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/glob@7.1.1: @@ -1764,7 +1764,7 @@ packages: dependencies: '@types/events': 3.0.0 '@types/minimatch': 3.0.3 - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/http-cache-semantics@4.0.1: @@ -1778,7 +1778,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/lru-cache@5.1.1: @@ -1792,11 +1792,11 @@ packages: /@types/mkdirp@0.5.2: resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true - /@types/mocha@10.0.3: - resolution: {integrity: sha512-RsOPImTriV/OE4A9qKjMtk2MnXiuLLbcO3nCXK+kvq4nr0iMfFgpjaX3MPLb6f7+EL1FGSelYvuJMV6REH+ZPQ==} + /@types/mocha@10.0.4: + resolution: {integrity: sha512-xKU7bUjiFTIttpWaIZ9qvgg+22O1nmbA+HRxdlR+u6TWsGfmFdXrheJoK4fFxrHNVIOBDvDNKZG+LYBpMHpX3w==} dev: true /@types/ms@0.7.31: @@ -1806,7 +1806,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 form-data: 3.0.1 dev: true @@ -1818,8 +1818,8 @@ packages: resolution: {integrity: sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==} dev: true - /@types/node@16.18.58: - resolution: {integrity: sha512-YGncyA25/MaVtQkjWW9r0EFBukZ+JulsLcVZBlGUfIb96OBMjkoRWwQo5IEWJ8Fj06Go3GHw+bjYDitv6BaGsA==} + /@types/node@16.18.61: + resolution: {integrity: sha512-k0N7BqGhJoJzdh6MuQg1V1ragJiXTh8VUBAZTWjJ9cUq23SG0F0xavOwZbhiP4J3y20xd6jxKx+xNUhkMAi76Q==} dev: true /@types/node@8.10.66: @@ -1829,7 +1829,7 @@ packages: /@types/pbkdf2@3.1.0: resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/prettier@2.7.1: @@ -1843,26 +1843,26 @@ packages: /@types/readable-stream@2.3.15: resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 safe-buffer: 5.1.2 dev: true /@types/resolve@0.0.8: resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/secp256k1@4.0.3: resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==} dependencies: - '@types/node': 16.18.58 + '@types/node': 16.18.61 dev: true /@types/semver@7.5.0: @@ -1872,7 +1872,7 @@ packages: /@types/sinon-chai@3.2.8: resolution: {integrity: sha512-d4ImIQbT/rKMG8+AXpmcan5T2/PNeSjrYhvkwet6z0p8kzYtfgA32xzOBlbU0yqJfq+/0Ml805iFoODO0LP5/g==} dependencies: - '@types/chai': 4.3.9 + '@types/chai': 4.3.10 '@types/sinon': 10.0.13 dev: true @@ -1886,8 +1886,8 @@ packages: resolution: {integrity: sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==} dev: true - /@typescript-eslint/eslint-plugin@6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==} + /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -1898,13 +1898,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.8.0 - '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/scope-manager': 6.8.0 - '@typescript-eslint/type-utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.11.0 + '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.11.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.51.0 + eslint: 8.53.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -1915,8 +1915,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.8.0(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==} + /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1925,27 +1925,27 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.8.0 - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/scope-manager': 6.11.0 + '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.11.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.51.0 + eslint: 8.53.0 typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@6.8.0: - resolution: {integrity: sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==} + /@typescript-eslint/scope-manager@6.11.0: + resolution: {integrity: sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/visitor-keys': 6.11.0 dev: true - /@typescript-eslint/type-utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==} + /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1954,23 +1954,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.51.0 + eslint: 8.53.0 ts-api-utils: 1.0.3(typescript@5.2.2) typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@6.8.0: - resolution: {integrity: sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==} + /@typescript-eslint/types@6.11.0: + resolution: {integrity: sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==} engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.8.0(typescript@5.2.2): - resolution: {integrity: sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==} + /@typescript-eslint/typescript-estree@6.11.0(typescript@5.2.2): + resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -1978,8 +1978,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/visitor-keys': 6.11.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 @@ -1990,33 +1990,37 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==} + /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.8.0 - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) - eslint: 8.51.0 + '@typescript-eslint/scope-manager': 6.11.0 + '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) + eslint: 8.53.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@6.8.0: - resolution: {integrity: sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==} + /@typescript-eslint/visitor-keys@6.11.0: + resolution: {integrity: sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/types': 6.11.0 eslint-visitor-keys: 3.4.3 dev: true + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + /@yarnpkg/lockfile@1.1.0: resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} dev: true @@ -2042,7 +2046,7 @@ packages: source-map-support: 0.5.21 optionalDependencies: prettier: 2.8.8 - prettier-plugin-solidity: 1.1.3(prettier@2.8.8) + prettier-plugin-solidity: 1.2.0(prettier@2.8.8) transitivePeerDependencies: - supports-color dev: true @@ -4703,16 +4707,16 @@ packages: source-map: 0.2.0 dev: true - /eslint-config-prettier@9.0.0(eslint@8.51.0): + /eslint-config-prettier@9.0.0(eslint@8.53.0): resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.51.0 + eslint: 8.53.0 dev: true - /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.51.0)(prettier@3.0.3): + /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0): resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -4726,9 +4730,9 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.51.0 - eslint-config-prettier: 9.0.0(eslint@8.51.0) - prettier: 3.0.3 + eslint: 8.53.0 + eslint-config-prettier: 9.0.0(eslint@8.53.0) + prettier: 3.1.0 prettier-linter-helpers: 1.0.0 synckit: 0.8.5 dev: true @@ -4746,18 +4750,19 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.51.0: - resolution: {integrity: sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==} + /eslint@8.53.0: + resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) '@eslint-community/regexpp': 4.8.0 - '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.51.0 - '@humanwhocodes/config-array': 0.11.11 + '@eslint/eslintrc': 2.1.3 + '@eslint/js': 8.53.0 + '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 @@ -6206,7 +6211,7 @@ packages: har-schema: 2.0.0 dev: true - /hardhat-abi-exporter@2.10.1(hardhat@2.18.1): + /hardhat-abi-exporter@2.10.1(hardhat@2.19.1): resolution: {integrity: sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==} engines: {node: '>=14.14.0'} peerDependencies: @@ -6214,28 +6219,28 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 delete-empty: 3.0.0 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) dev: true - /hardhat-contract-sizer@2.10.0(hardhat@2.18.1): + /hardhat-contract-sizer@2.10.0(hardhat@2.19.1): resolution: {integrity: sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==} peerDependencies: hardhat: ^2.0.0 dependencies: chalk: 4.1.2 cli-table3: 0.6.3 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) strip-ansi: 6.0.1 dev: true - /hardhat-gas-reporter@1.0.9(debug@4.3.4)(hardhat@2.18.1): + /hardhat-gas-reporter@1.0.9(debug@4.3.4)(hardhat@2.19.1): resolution: {integrity: sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==} peerDependencies: hardhat: ^2.0.2 dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27(debug@4.3.4) - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -6252,8 +6257,8 @@ packages: solidity-comments: 0.0.2 dev: true - /hardhat@2.18.1(ts-node@10.9.1)(typescript@5.2.2): - resolution: {integrity: sha512-b55rW7Ka+fvJeg6oWuBTXoYQEUurevCCankjGNTwczwD3GnkhV9GEei7KUT+9IKmWx3lC+zyxlFxeDbg0gUoHw==} + /hardhat@2.19.1(ts-node@10.9.1)(typescript@5.2.2): + resolution: {integrity: sha512-bsWa63g1GB78ZyMN08WLhFElLPA+J+pShuKD1BFO2+88g3l+BL3R07vj9deIi9dMbssxgE714Gof1dBEDGqnCw==} hasBin: true peerDependencies: ts-node: '*' @@ -6308,7 +6313,7 @@ packages: solc: 0.7.3(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.1(@types/node@16.18.58)(typescript@5.2.2) + ts-node: 10.9.1(@types/node@16.18.61)(typescript@5.2.2) tsort: 0.0.1 typescript: 5.2.2 undici: 5.19.1 @@ -8878,28 +8883,27 @@ packages: fast-diff: 1.2.0 dev: true - /prettier-plugin-solidity@1.1.3(prettier@2.8.8): - resolution: {integrity: sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==} - engines: {node: '>=12'} - requiresBuild: true + /prettier-plugin-solidity@1.2.0(prettier@2.8.8): + resolution: {integrity: sha512-fgxcUZpVAP+LlRfy5JI5oaAkXGkmsje2VJ5krv/YMm+rcTZbIUwFguSw5f+WFuttMjpDm6wB4UL7WVkArEfiVA==} + engines: {node: '>=16'} peerDependencies: - prettier: '>=2.3.0 || >=3.0.0-alpha.0' + prettier: '>=2.3.0' dependencies: - '@solidity-parser/parser': 0.16.0 + '@solidity-parser/parser': 0.16.2 prettier: 2.8.8 - semver: 7.5.0 + semver: 7.5.4 solidity-comments-extractor: 0.0.7 dev: true optional: true - /prettier-plugin-solidity@1.1.4-dev(prettier@3.0.3): - resolution: {integrity: sha512-SIDnHIPLN/Pod/dZoyJL07ViEcDxrXoT47ROQshpA/WFgyq/rRzLIc3oWkKfWiicHOD493Y/L1n9ds1GbwPoKQ==} + /prettier-plugin-solidity@1.2.0(prettier@3.1.0): + resolution: {integrity: sha512-fgxcUZpVAP+LlRfy5JI5oaAkXGkmsje2VJ5krv/YMm+rcTZbIUwFguSw5f+WFuttMjpDm6wB4UL7WVkArEfiVA==} engines: {node: '>=16'} peerDependencies: prettier: '>=2.3.0' dependencies: - '@solidity-parser/parser': 0.16.1 - prettier: 3.0.3 + '@solidity-parser/parser': 0.16.2 + prettier: 3.1.0 semver: 7.5.4 solidity-comments-extractor: 0.0.7 dev: true @@ -8910,8 +8914,8 @@ packages: hasBin: true dev: true - /prettier@3.0.3: - resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + /prettier@3.1.0: + resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} engines: {node: '>=14'} hasBin: true dev: true @@ -9637,16 +9641,6 @@ packages: lru-cache: 6.0.0 dev: true - /semver@7.5.0: - resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} - engines: {node: '>=10'} - hasBin: true - requiresBuild: true - dependencies: - lru-cache: 6.0.0 - dev: true - optional: true - /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} @@ -9953,16 +9947,16 @@ packages: - debug dev: true - /solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.1.4-dev)(prettier@3.0.3): + /solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.2.0)(prettier@3.1.0): resolution: {integrity: sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==} peerDependencies: prettier: ^3.0.0 prettier-plugin-solidity: ^1.0.0 dependencies: - '@prettier/sync': 0.3.0(prettier@3.0.3) - prettier: 3.0.3 + '@prettier/sync': 0.3.0(prettier@3.1.0) + prettier: 3.1.0 prettier-linter-helpers: 1.0.0 - prettier-plugin-solidity: 1.1.4-dev(prettier@3.0.3) + prettier-plugin-solidity: 1.2.0(prettier@3.1.0) dev: true /solhint@4.0.0: @@ -10107,7 +10101,7 @@ packages: solidity-comments-win32-x64-msvc: 0.0.2 dev: true - /solidity-coverage@0.8.5(hardhat@2.18.1): + /solidity-coverage@0.8.5(hardhat@2.19.1): resolution: {integrity: sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==} hasBin: true peerDependencies: @@ -10123,7 +10117,7 @@ packages: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) jsonschema: 1.4.0 lodash: 4.17.21 mocha: 10.2.0 @@ -10766,7 +10760,7 @@ packages: ts-essentials: 1.0.4 dev: true - /ts-node@10.9.1(@types/node@16.18.58)(typescript@5.2.2): + /ts-node@10.9.1(@types/node@16.18.61)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -10785,7 +10779,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 16.18.58 + '@types/node': 16.18.61 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 @@ -10893,8 +10887,8 @@ packages: - typescript dev: true - /typechain@8.2.0(typescript@5.2.2): - resolution: {integrity: sha512-tZqhqjxJ9xAS/Lh32jccTjMkpx7sTdUVVHAy5Bf0TIer5QFNYXotiX74oCvoVYjyxUKDK3MXHtMFzMyD3kE+jg==} + /typechain@8.3.2(typescript@5.2.2): + resolution: {integrity: sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==} hasBin: true peerDependencies: typescript: '>=4.3.0' From e42562cc435d6136925383e2368e99dbd1663a59 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Mon, 20 Nov 2023 14:26:13 +0100 Subject: [PATCH 177/327] fix solidity codeowners (#11300) --- CODEOWNERS | 33 ++++++++++++++++------- contracts/scripts/native_solc_compile_all | 2 +- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 5f33e68e51..bd2d0419cf 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -73,23 +73,38 @@ core/scripts/gateway @bolekk @pinebit # Contracts /contracts/ @se3000 @connorwstein @RensR -/contracts/srv/v0.8/automation @smartcontractkit/keepers +# First we match on project names to catch files like the compilation scripts, +# gas snapshots and other files not places in the project directories. +# This could give some false positives, so afterwards we match on the project directories +# to ensure the entire directory is always owned by the correct team. + +/contracts/**/*shared* @RensR /contracts/**/*keeper* @smartcontractkit/keepers /contracts/**/*upkeep* @smartcontractkit/keepers /contracts/**/*automation* @smartcontractkit/keepers -/contracts/gas-snapshots/automation.gas-snapshot @smartcontractkit/keepers - -/contracts/src/v0.8/functions @smartcontractkit/functions /contracts/**/*functions* @smartcontractkit/functions -/contracts/gas-snapshots/functions.gas-snapshot @smartcontractkit/functions +/contracts/**/*llo-feeds* @austinborn @Fletch153 +/contracts/**/*vrf* @smartcontractkit/vrf-team +/contracts/**/*l2ep* @simsonraj +/contracts/**/*operatorforwarder* @essamhassan +/contracts/src/v0.8/automation @smartcontractkit/keepers +/contracts/src/v0.8/functions @smartcontractkit/functions +# TODO: interfaces folder, folder should be removed and files moved to the correct folders +/contracts/src/v0.8/l2ep @simsonraj /contracts/src/v0.8/llo-feeds @austinborn @Fletch153 -/contracts/gas-snapshots/llo-feeds.gas-snapshot @austinborn @Fletch153 - +# TODO: mocks folder, folder should be removed and files moved to the correct folders +/contracts/src/v0.8/operatorforwarder @essamhassan +/contracts/src/v0.8/shared @RensR +# TODO: tests folder, folder should be removed and files moved to the correct folders +# TODO: transmission folder, owner should be found /contracts/src/v0.8/vrf @smartcontractkit/vrf-team -/contracts/**/*vrf* @smartcontractkit/vrf-team -/contracts/src/v0.8/l2ep @simsonraj + + +# At the end, match any files missed by the patterns above +/contracts/scripts/native_solc_compile_all_events_mock @smartcontractkit/functions + # Tests /integration-tests/ @smartcontractkit/test-tooling-team diff --git a/contracts/scripts/native_solc_compile_all b/contracts/scripts/native_solc_compile_all index a2f2f1a0bc..cf1226a2d5 100755 --- a/contracts/scripts/native_solc_compile_all +++ b/contracts/scripts/native_solc_compile_all @@ -12,7 +12,7 @@ python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt # 6 and 7 are legacy contracts, for each other product we have a native_solc_compile_all_$product script # These scripts can be run individually, or all together with this script. # To add new CL products, simply write a native_solc_compile_all_$product script and add it to the list below. -for product in 6 7 feeds functions llo-feeds transmission vrf automation operatorforwarder logpoller events_mock shared +for product in 6 7 automation events_mock feeds functions llo-feeds logpoller operatorforwarder shared transmission vrf do $SCRIPTPATH/native_solc_compile_all_$product done From 7e0fa2313580c7497f3a956a4f690c85ede678bb Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Mon, 20 Nov 2023 07:14:46 -0800 Subject: [PATCH 178/327] [Functions] Rename a few secrets-specific objects to more generic names (#11340) These structs/functions are generic enough to be used for non-secrets related requests. --- core/services/functions/connector_handler.go | 2 +- .../gateway/handlers/functions/api.go | 10 +++---- .../handlers/functions/handler.functions.go | 28 +++++++++---------- .../functions/handler.functions_test.go | 4 +-- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 343980afdd..76608b8ada 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -84,7 +84,7 @@ func (h *functionsConnectorHandler) HandleGatewayMessage(ctx context.Context, ga case functions.MethodSecretsSet: if balance, err := h.subscriptions.GetMaxUserBalance(fromAddr); err != nil || balance.Cmp(h.minimumBalance.ToInt()) < 0 { h.lggr.Errorw("user subscription has insufficient balance", "id", gatewayId, "address", fromAddr, "balance", balance, "minBalance", h.minimumBalance) - response := functions.SecretsResponseBase{ + response := functions.ResponseBase{ Success: false, ErrorMessage: "user subscription has insufficient balance", } diff --git a/core/services/gateway/handlers/functions/api.go b/core/services/gateway/handlers/functions/api.go index 979cdb939b..202fa99e41 100644 --- a/core/services/gateway/handlers/functions/api.go +++ b/core/services/gateway/handlers/functions/api.go @@ -17,17 +17,17 @@ type SecretsSetRequest struct { // SecretsListRequest has empty payload -type SecretsResponseBase struct { +type ResponseBase struct { Success bool `json:"success"` ErrorMessage string `json:"error_message,omitempty"` } type SecretsSetResponse struct { - SecretsResponseBase + ResponseBase } type SecretsListResponse struct { - SecretsResponseBase + ResponseBase Rows []SecretsListRow `json:"rows,omitempty"` } @@ -38,7 +38,7 @@ type SecretsListRow struct { } // Gateway -> User response, which combines responses from several nodes -type CombinedSecretsResponse struct { - SecretsResponseBase +type CombinedResponse struct { + ResponseBase NodeResponses []*api.Message `json:"node_responses"` } diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index 32a132c075..6cc4581a50 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -75,7 +75,7 @@ type functionsHandler struct { handlerConfig FunctionsHandlerConfig donConfig *config.DONConfig don handlers.DON - pendingRequests hc.RequestCache[PendingSecretsRequest] + pendingRequests hc.RequestCache[PendingRequest] allowlist OnchainAllowlist subscriptions OnchainSubscriptions minimumBalance *assets.Link @@ -85,7 +85,7 @@ type functionsHandler struct { lggr logger.Logger } -type PendingSecretsRequest struct { +type PendingRequest struct { request *api.Message responses map[string]*api.Message successful []*api.Message @@ -136,7 +136,7 @@ func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *con return nil, err2 } } - pendingRequestsCache := hc.NewRequestCache[PendingSecretsRequest](time.Millisecond*time.Duration(cfg.RequestTimeoutMillis), cfg.MaxPendingRequests) + pendingRequestsCache := hc.NewRequestCache[PendingRequest](time.Millisecond*time.Duration(cfg.RequestTimeoutMillis), cfg.MaxPendingRequests) return NewFunctionsHandler(cfg, donConfig, don, pendingRequestsCache, allowlist, subscriptions, cfg.MinimumSubscriptionBalance, userRateLimiter, nodeRateLimiter, lggr), nil } @@ -144,7 +144,7 @@ func NewFunctionsHandler( cfg FunctionsHandlerConfig, donConfig *config.DONConfig, don handlers.DON, - pendingRequestsCache hc.RequestCache[PendingSecretsRequest], + pendingRequestsCache hc.RequestCache[PendingRequest], allowlist OnchainAllowlist, subscriptions OnchainSubscriptions, minimumBalance *assets.Link, @@ -193,7 +193,7 @@ func (h *functionsHandler) HandleUserMessage(ctx context.Context, msg *api.Messa } switch msg.Body.Method { case MethodSecretsSet, MethodSecretsList: - return h.handleSecretsRequest(ctx, msg, callbackCh) + return h.handleRequest(ctx, msg, callbackCh) default: h.lggr.Debugw("unsupported method", "method", msg.Body.Method) promHandlerError.WithLabelValues(h.donConfig.DonId, ErrUnsupportedMethod.Error()).Inc() @@ -201,11 +201,11 @@ func (h *functionsHandler) HandleUserMessage(ctx context.Context, msg *api.Messa } } -func (h *functionsHandler) handleSecretsRequest(ctx context.Context, msg *api.Message, callbackCh chan<- handlers.UserCallbackPayload) error { - h.lggr.Debugw("handleSecretsRequest: processing message", "sender", msg.Body.Sender, "messageId", msg.Body.MessageId) - err := h.pendingRequests.NewRequest(msg, callbackCh, &PendingSecretsRequest{request: msg, responses: make(map[string]*api.Message)}) +func (h *functionsHandler) handleRequest(ctx context.Context, msg *api.Message, callbackCh chan<- handlers.UserCallbackPayload) error { + h.lggr.Debugw("handleRequest: processing message", "sender", msg.Body.Sender, "messageId", msg.Body.MessageId) + err := h.pendingRequests.NewRequest(msg, callbackCh, &PendingRequest{request: msg, responses: make(map[string]*api.Message)}) if err != nil { - h.lggr.Warnw("handleSecretsRequest: error adding new request", "sender", msg.Body.Sender, "err", err) + h.lggr.Warnw("handleRequest: error adding new request", "sender", msg.Body.Sender, "err", err) promHandlerError.WithLabelValues(h.donConfig.DonId, err.Error()).Inc() return err } @@ -213,7 +213,7 @@ func (h *functionsHandler) handleSecretsRequest(ctx context.Context, msg *api.Me for _, member := range h.donConfig.Members { err := h.don.SendToNode(ctx, member.Address, msg) if err != nil { - h.lggr.Debugw("handleSecretsRequest: failed to send to a node", "node", member.Address, "err", err) + h.lggr.Debugw("handleRequest: failed to send to a node", "node", member.Address, "err", err) } } return nil @@ -234,8 +234,8 @@ func (h *functionsHandler) HandleNodeMessage(ctx context.Context, msg *api.Messa } } -// Conforms to ResponseProcessor[*PendingSecretsRequest] -func (h *functionsHandler) processSecretsResponse(response *api.Message, responseData *PendingSecretsRequest) (*handlers.UserCallbackPayload, *PendingSecretsRequest, error) { +// Conforms to ResponseProcessor[*PendingRequest] +func (h *functionsHandler) processSecretsResponse(response *api.Message, responseData *PendingRequest) (*handlers.UserCallbackPayload, *PendingRequest, error) { if _, exists := responseData.responses[response.Body.Sender]; exists { return nil, nil, errors.New("duplicate response") } @@ -243,7 +243,7 @@ func (h *functionsHandler) processSecretsResponse(response *api.Message, respons return nil, responseData, errors.New("invalid method") } responseData.responses[response.Body.Sender] = response - var responsePayload SecretsResponseBase + var responsePayload ResponseBase err := json.Unmarshal(response.Body.Payload, &responsePayload) if err != nil { responseData.errors = append(responseData.errors, response) @@ -270,7 +270,7 @@ func (h *functionsHandler) processSecretsResponse(response *api.Message, respons } func newSecretsResponse(request *api.Message, success bool, responses []*api.Message) (*handlers.UserCallbackPayload, error) { - payload := CombinedSecretsResponse{SecretsResponseBase: SecretsResponseBase{Success: success}, NodeResponses: responses} + payload := CombinedResponse{ResponseBase: ResponseBase{Success: success}, NodeResponses: responses} payloadJson, err := json.Marshal(payload) if err != nil { return nil, err diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index 00334d3068..402823df17 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -47,7 +47,7 @@ func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTi require.NoError(t, err) nodeRateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) - pendingRequestsCache := hc.NewRequestCache[functions.PendingSecretsRequest](requestTimeout, 1000) + pendingRequestsCache := hc.NewRequestCache[functions.PendingRequest](requestTimeout, 1000) handler := functions.NewFunctionsHandler(cfg, donConfig, don, pendingRequestsCache, allowlist, subscriptions, minBalance, userRateLimiter, nodeRateLimiter, logger.TestLogger(t)) return handler, don, allowlist, subscriptions } @@ -128,7 +128,7 @@ func TestFunctionsHandler_HandleUserMessage_SecretsSet(t *testing.T) { response := <-callbachCh require.Equal(t, api.NoError, response.ErrCode) require.Equal(t, userRequestMsg.Body.MessageId, response.Msg.Body.MessageId) - var payload functions.CombinedSecretsResponse + var payload functions.CombinedResponse require.NoError(t, json.Unmarshal(response.Msg.Body.Payload, &payload)) require.Equal(t, test.expectedGatewayResult, payload.Success) require.Equal(t, test.expectedNodeMessageCount, len(payload.NodeResponses)) From c9312c6120809c53418233fb5109d1217b427a8f Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 20 Nov 2023 09:21:42 -0600 Subject: [PATCH 179/327] core/utils: StopChan & StartStopOnce cleanup (#11341) * core/utils: make StopChan an alias to common * use services.StopChan; deprecate utils.StopChan * use services.StateMachine instead of deprecated utils.StartStopOnce --- common/client/multi_node.go | 4 +- common/client/send_only_node.go | 3 +- common/headtracker/head_broadcaster.go | 2 +- common/headtracker/head_listener.go | 4 +- common/headtracker/head_tracker.go | 2 +- common/txmgr/broadcaster.go | 2 +- common/txmgr/reaper.go | 8 +- common/txmgr/txmgr.go | 4 +- core/chains/evm/client/node.go | 2 +- core/chains/evm/client/pool.go | 2 +- core/chains/evm/client/send_only_node.go | 3 +- core/chains/evm/gas/arbitrum_estimator.go | 2 +- .../evm/gas/rollups/l1_gas_price_oracle.go | 2 +- .../evm/gas/suggested_price_estimator.go | 2 +- core/chains/evm/log/broadcaster.go | 2 +- core/chains/evm/log/eth_subscriber.go | 4 +- core/chains/evm/txmgr/broadcaster_test.go | 4 +- core/chains/evm/txmgr/confirmer_test.go | 4 +- core/logger/audit/audit_logger.go | 14 ++-- core/services/cron/cron.go | 5 +- core/services/directrequest/delegate.go | 10 +-- core/services/fluxmonitorv2/flux_monitor.go | 8 +- core/services/gateway/connectionmanager.go | 6 +- core/services/gateway/connector/connector.go | 6 +- .../gateway/handlers/functions/allowlist.go | 4 +- .../handlers/functions/handler.functions.go | 5 +- .../handlers/functions/subscriptions.go | 4 +- core/services/job/spawner.go | 24 +++--- core/services/keeper/upkeep_executer.go | 4 +- core/services/ocr/contract_tracker.go | 4 +- core/services/ocr2/plugins/median/plugin.go | 6 +- .../plugins/ocr2keeper/custom_telemetry.go | 7 +- .../evm21/autotelemetry21/custom_telemetry.go | 7 +- .../ocr2keeper/evm21/mercury/v02/request.go | 4 +- .../ocr2keeper/evm21/mercury/v03/request.go | 4 +- .../ocr2/plugins/ocr2keeper/evm21/registry.go | 5 +- core/services/pipeline/runner.go | 2 +- core/services/promreporter/prom_reporter.go | 2 +- .../relay/evm/functions/logpoller_wrapper.go | 4 +- .../relay/evm/mercury/persistence_manager.go | 4 +- .../services/relay/evm/mercury/transmitter.go | 4 +- .../relay/evm/mercury/wsrpc/client.go | 4 +- .../telemetry_ingress_batch_worker.go | 8 +- .../telemetry_ingress_client.go | 7 +- core/services/vrf/v1/listener_v1.go | 2 +- core/services/vrf/v2/listener_v2.go | 4 +- core/services/webhook/delegate.go | 5 +- core/utils/thread_control.go | 4 +- core/utils/utils.go | 60 +++------------ core/utils/utils_example_test.go | 48 ------------ core/utils/utils_test.go | 73 ------------------- plugins/medianpoc/plugin.go | 5 +- 52 files changed, 138 insertions(+), 281 deletions(-) delete mode 100644 core/utils/utils_example_test.go diff --git a/common/client/multi_node.go b/common/client/multi_node.go index acab47f083..48a4d37ad8 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -99,7 +99,7 @@ type multiNode[ activeMu sync.RWMutex activeNode Node[CHAIN_ID, HEAD, RPC_CLIENT] - chStop utils.StopChan + chStop services.StopChan wg sync.WaitGroup sendOnlyErrorParser func(err error) SendTxReturnCode @@ -146,7 +146,7 @@ func NewMultiNode[ selectionMode: selectionMode, noNewHeadsThreshold: noNewHeadsThreshold, nodeSelector: nodeSelector, - chStop: make(chan struct{}), + chStop: make(services.StopChan), leaseDuration: leaseDuration, chainFamily: chainFamily, sendOnlyErrorParser: sendOnlyErrorParser, diff --git a/common/client/send_only_node.go b/common/client/send_only_node.go index 767fff5aee..904916122f 100644 --- a/common/client/send_only_node.go +++ b/common/client/send_only_node.go @@ -10,7 +10,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "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 @@ -59,7 +58,7 @@ type sendOnlyNode[ log logger.Logger name string chainID CHAIN_ID - chStop utils.StopChan + chStop services.StopChan wg sync.WaitGroup } diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index 3efe64e1c3..62b2f47b68 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -31,7 +31,7 @@ type HeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct callbacks callbackSet[H, BLOCK_HASH] mailbox *utils.Mailbox[H] mutex sync.Mutex - chClose utils.StopChan + chClose services.StopChan wgDone sync.WaitGroup latest H lastCallbackID int diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index ee4969497a..a3f262f4b7 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -9,6 +9,8 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/services" + htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -35,7 +37,7 @@ type HeadListener[ config htrktypes.Config client htrktypes.Client[HTH, S, ID, BLOCK_HASH] logger logger.Logger - chStop utils.StopChan + chStop services.StopChan chHeaders chan HTH headSubscription types.Subscription connected atomic.Bool diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index bf63675128..810e749a2d 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -53,7 +53,7 @@ type HeadTracker[ backfillMB *utils.Mailbox[HTH] broadcastMB *utils.Mailbox[HTH] headListener types.HeadListener[HTH, BLOCK_HASH] - chStop utils.StopChan + chStop services.StopChan wgDone sync.WaitGroup getNilHead func() HTH } diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index ba01fb9e2a..d9a72e367a 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -135,7 +135,7 @@ type Broadcaster[ // Each key has its own trigger triggers map[ADDR]chan struct{} - chStop utils.StopChan + chStop services.StopChan wg sync.WaitGroup initSync sync.Mutex diff --git a/common/txmgr/reaper.go b/common/txmgr/reaper.go index 96bc4860d7..7286efa3a8 100644 --- a/common/txmgr/reaper.go +++ b/common/txmgr/reaper.go @@ -5,6 +5,8 @@ import ( "sync/atomic" "time" + "github.com/smartcontractkit/chainlink-common/pkg/services" + txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -20,7 +22,7 @@ type Reaper[CHAIN_ID types.ID] struct { log logger.Logger latestBlockNum atomic.Int64 trigger chan struct{} - chStop chan struct{} + chStop services.StopChan chDone chan struct{} } @@ -34,7 +36,7 @@ func NewReaper[CHAIN_ID types.ID](lggr logger.Logger, store txmgrtypes.TxHistory lggr.Named("Reaper"), atomic.Int64{}, make(chan struct{}, 1), - make(chan struct{}), + make(services.StopChan), make(chan struct{}), } r.latestBlockNum.Store(-1) @@ -97,7 +99,7 @@ func (r *Reaper[CHAIN_ID]) SetLatestBlockNum(latestBlockNum int64) { // ReapTxes deletes old txes func (r *Reaper[CHAIN_ID]) ReapTxes(headNum int64) error { - ctx, cancel := utils.StopChan(r.chStop).NewCtx() + ctx, cancel := r.chStop.NewCtx() defer cancel() threshold := r.txConfig.ReaperThreshold() if threshold == 0 { diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 24d2428f61..b49c2b72f1 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -90,7 +90,7 @@ type Txm[ reset chan reset resumeCallback ResumeCallback - chStop chan struct{} + chStop services.StopChan chSubbed chan struct{} wg sync.WaitGroup @@ -228,7 +228,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(addr // - marks all pending and inflight transactions fatally errored (note: at this point all transactions are either confirmed or fatally errored) // this must not be run while Broadcaster or Confirmer are running func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) abandon(addr ADDR) (err error) { - ctx, cancel := utils.StopChan(b.chStop).NewCtx() + ctx, cancel := services.StopChan(b.chStop).NewCtx() defer cancel() if err = b.txStore.Abandon(ctx, b.chainID, addr); err != nil { return fmt.Errorf("abandon failed to update txes for key %s: %w", addr.String(), err) diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index b690720240..b3ce489cf5 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -1101,7 +1101,7 @@ func (n *node) makeQueryCtx(ctx context.Context) (context.Context, context.Cance // 1. Passed in ctx cancels // 2. Passed in channel is closed // 3. Default timeout is reached (queryTimeout) -func makeQueryCtx(ctx context.Context, ch utils.StopChan) (context.Context, context.CancelFunc) { +func makeQueryCtx(ctx context.Context, ch services.StopChan) (context.Context, context.CancelFunc) { var chCancel, timeoutCancel context.CancelFunc ctx, chCancel = ch.Ctx(ctx) ctx, timeoutCancel = context.WithTimeout(ctx, queryTimeout) diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 18f59b172d..289a402a1c 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -72,7 +72,7 @@ type Pool struct { activeMu sync.RWMutex activeNode Node - chStop utils.StopChan + chStop services.StopChan wg sync.WaitGroup } diff --git a/core/chains/evm/client/send_only_node.go b/core/chains/evm/client/send_only_node.go index beb12dbc4d..02f04881c4 100644 --- a/core/chains/evm/client/send_only_node.go +++ b/core/chains/evm/client/send_only_node.go @@ -16,7 +16,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name SendOnlyNode --output ../mocks/ --case=underscore @@ -69,7 +68,7 @@ type sendOnlyNode struct { dialed bool name string chainID *big.Int - chStop utils.StopChan + chStop services.StopChan wg sync.WaitGroup } diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index c79202c731..480abfe721 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -48,7 +48,7 @@ type arbitrumEstimator struct { chForceRefetch chan (chan struct{}) chInitialised chan struct{} - chStop utils.StopChan + chStop services.StopChan chDone chan struct{} } diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index 88c61c4934..1a0fe8b8b2 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -38,7 +38,7 @@ type l1GasPriceOracle struct { l1GasPrice *assets.Wei chInitialised chan struct{} - chStop utils.StopChan + chStop services.StopChan chDone chan struct{} } diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index dadec6210c..cd5acbc694 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -40,7 +40,7 @@ type SuggestedPriceEstimator struct { chForceRefetch chan (chan struct{}) chInitialised chan struct{} - chStop utils.StopChan + chStop services.StopChan chDone chan struct{} } diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index 11c282a4d2..d69fd696fd 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -110,7 +110,7 @@ type ( utils.DependentAwaiter - chStop utils.StopChan + chStop services.StopChan wgDone sync.WaitGroup trackedAddressesCount atomic.Uint32 replayChannel chan replayRequest diff --git a/core/chains/evm/log/eth_subscriber.go b/core/chains/evm/log/eth_subscriber.go index cd1b18b474..b4d386140e 100644 --- a/core/chains/evm/log/eth_subscriber.go +++ b/core/chains/evm/log/eth_subscriber.go @@ -10,6 +10,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" @@ -21,7 +23,7 @@ type ( ethClient evmclient.Client config Config logger logger.Logger - chStop utils.StopChan + chStop services.StopChan } ) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 7967478e62..bf480c66af 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -112,10 +112,10 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { err = eb.Close() require.NoError(t, err) - // Can't start more than once (Broadcaster implements utils.StartStopOnce) + // Can't start more than once (Broadcaster uses services.StateMachine) err = eb.Start(ctx) require.Error(t, err) - // Can't close more than once (Broadcaster implements utils.StartStopOnce) + // Can't close more than once (Broadcaster uses services.StateMachine) err = eb.Close() require.Error(t, err) diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index e17e7993cf..60d0648a54 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -157,10 +157,10 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { err = ec.Close() require.NoError(t, err) - // Can't start more than once (Confirmer implements utils.StartStopOnce) + // Can't start more than once (Confirmer uses services.StateMachine) err = ec.Start(ctx) require.Error(t, err) - // Can't close more than once (Confirmer implements utils.StartStopOnce) + // Can't close more than once (Confirmer use services.StateMachine) err = ec.Close() require.Error(t, err) diff --git a/core/logger/audit/audit_logger.go b/core/logger/audit/audit_logger.go index 38afd77a28..ef66a063a5 100644 --- a/core/logger/audit/audit_logger.go +++ b/core/logger/audit/audit_logger.go @@ -4,6 +4,8 @@ import ( "bytes" "context" "encoding/json" + "errors" + "fmt" "io" "net" "net/http" @@ -11,13 +13,11 @@ import ( "os" "time" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/pkg/errors" ) const bufferCapacity = 2048 @@ -26,7 +26,7 @@ const webRequestTimeout = 10 type Data = map[string]any type AuditLogger interface { - services.ServiceCtx + services.Service Audit(eventID EventID, data Data) } @@ -47,7 +47,7 @@ type AuditLoggerService struct { loggingClient HTTPAuditLoggerInterface // Abstract type for sending logs onward loggingChannel chan wrappedAuditLog - chStop utils.StopChan + chStop services.StopChan chDone chan struct{} } @@ -72,7 +72,7 @@ func NewAuditLogger(logger logger.Logger, config config.AuditLogger) (AuditLogge hostname, err := os.Hostname() if err != nil { - return nil, errors.Errorf("initialization error - unable to get hostname: %s", err) + return nil, fmt.Errorf("initialization error - unable to get hostname: %w", err) } forwardToUrl, err := config.ForwardToUrl() diff --git a/core/services/cron/cron.go b/core/services/cron/cron.go index e89dd1ceab..500192554f 100644 --- a/core/services/cron/cron.go +++ b/core/services/cron/cron.go @@ -6,10 +6,11 @@ import ( "github.com/robfig/cron/v3" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Cron runs a cron jobSpec from a CronSpec @@ -18,7 +19,7 @@ type Cron struct { logger logger.Logger jobSpec job.Job pipelineRunner pipeline.Runner - chStop utils.StopChan + chStop services.StopChan } // NewCronFromJobSpec instantiates a job that executes on a predefined schedule. diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 9da84fd3ee..687e1cea67 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -129,7 +129,7 @@ type listener struct { pipelineORM pipeline.ORM mailMon *utils.MailboxMonitor job job.Job - runs sync.Map // map[string]utils.StopChan + runs sync.Map // map[string]services.StopChan shutdownWaitGroup sync.WaitGroup mbOracleRequests *utils.Mailbox[log.Broadcast] mbOracleCancelRequests *utils.Mailbox[log.Broadcast] @@ -178,7 +178,7 @@ func (l *listener) Start(context.Context) error { func (l *listener) Close() error { return l.StopOnce("DirectRequestListener", func() error { l.runs.Range(func(key, runCloserChannelIf interface{}) bool { - runCloserChannel := runCloserChannelIf.(utils.StopChan) + runCloserChannel := runCloserChannelIf.(services.StopChan) close(runCloserChannel) return true }) @@ -338,10 +338,10 @@ func (l *listener) handleOracleRequest(request *operator_wrapper.OperatorOracleR meta := make(map[string]interface{}) meta["oracleRequest"] = oracleRequestToMap(request) - runCloserChannel := make(utils.StopChan) + runCloserChannel := make(services.StopChan) runCloserChannelIf, loaded := l.runs.LoadOrStore(formatRequestId(request.RequestId), runCloserChannel) if loaded { - runCloserChannel = runCloserChannelIf.(utils.StopChan) + runCloserChannel = runCloserChannelIf.(services.StopChan) } ctx, cancel := runCloserChannel.NewCtx() defer cancel() @@ -398,7 +398,7 @@ func (l *listener) allowRequester(requester common.Address) bool { func (l *listener) handleCancelOracleRequest(request *operator_wrapper.OperatorCancelOracleRequest, lb log.Broadcast) { runCloserChannelIf, loaded := l.runs.LoadAndDelete(formatRequestId(request.RequestId)) if loaded { - close(runCloserChannelIf.(utils.StopChan)) + close(runCloserChannelIf.(services.StopChan)) } l.markLogConsumed(lb) } diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index ea853d879d..79dd44c801 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -83,7 +83,7 @@ type FluxMonitor struct { backlog *utils.BoundedPriorityQueue[log.Broadcast] chProcessLogs chan struct{} - chStop chan struct{} + chStop services.StopChan waitOnStop chan struct{} } @@ -137,7 +137,7 @@ func NewFluxMonitor( PriorityFlagChangedLog: 2, }), chProcessLogs: make(chan struct{}, 1), - chStop: make(chan struct{}), + chStop: make(services.StopChan), waitOnStop: make(chan struct{}), } @@ -588,7 +588,7 @@ func (fm *FluxMonitor) respondToAnswerUpdatedLog(log flux_aggregator_wrapper.Flu // need to poll and submit an answer to the contract regardless of the deviation. func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggregatorNewRound, lb log.Broadcast) { started := time.Now() - ctx, cancel := utils.StopChan(fm.chStop).NewCtx() + ctx, cancel := fm.chStop.NewCtx() defer cancel() newRoundLogger := fm.logger.With( @@ -814,7 +814,7 @@ func (fm *FluxMonitor) checkEligibilityAndAggregatorFunding(roundState flux_aggr func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker *DeviationChecker, broadcast log.Broadcast) { started := time.Now() - ctx, cancel := utils.StopChan(fm.chStop).NewCtx() + ctx, cancel := fm.chStop.NewCtx() defer cancel() l := fm.logger.With( diff --git a/core/services/gateway/connectionmanager.go b/core/services/gateway/connectionmanager.go index ce4a54f4c2..9f88b51e7b 100644 --- a/core/services/gateway/connectionmanager.go +++ b/core/services/gateway/connectionmanager.go @@ -72,7 +72,7 @@ type donConnectionManager struct { handler handlers.Handler codec api.Codec closeWait sync.WaitGroup - shutdownCh chan struct{} + shutdownCh services.StopChan lggr logger.Logger } @@ -271,7 +271,7 @@ func (m *donConnectionManager) SendToNode(ctx context.Context, nodeAddress strin } func (m *donConnectionManager) readLoop(nodeAddress string, nodeState *nodeState) { - ctx, _ := utils.StopChan(m.shutdownCh).NewCtx() + ctx, _ := m.shutdownCh.NewCtx() for { select { case <-m.shutdownCh: @@ -296,7 +296,7 @@ func (m *donConnectionManager) readLoop(nodeAddress string, nodeState *nodeState } func (m *donConnectionManager) heartbeatLoop(intervalSec uint32) { - ctx, _ := utils.StopChan(m.shutdownCh).NewCtx() + ctx, _ := m.shutdownCh.NewCtx() defer m.closeWait.Done() if intervalSec == 0 { diff --git a/core/services/gateway/connector/connector.go b/core/services/gateway/connector/connector.go index 0694e9ad15..27db8fd44b 100644 --- a/core/services/gateway/connector/connector.go +++ b/core/services/gateway/connector/connector.go @@ -57,7 +57,7 @@ type gatewayConnector struct { gateways map[string]*gatewayState urlToId map[string]string closeWait sync.WaitGroup - shutdownCh chan struct{} + shutdownCh services.StopChan lggr logger.Logger } @@ -143,7 +143,7 @@ func (c *gatewayConnector) SendToGateway(ctx context.Context, gatewayId string, } func (c *gatewayConnector) readLoop(gatewayState *gatewayState) { - ctx, cancel := utils.StopChan(c.shutdownCh).NewCtx() + ctx, cancel := c.shutdownCh.NewCtx() defer cancel() for { @@ -168,7 +168,7 @@ func (c *gatewayConnector) readLoop(gatewayState *gatewayState) { func (c *gatewayConnector) reconnectLoop(gatewayState *gatewayState) { redialBackoff := utils.NewRedialBackoff() - ctx, cancel := utils.StopChan(c.shutdownCh).NewCtx() + ctx, cancel := c.shutdownCh.NewCtx() defer cancel() for { diff --git a/core/services/gateway/handlers/functions/allowlist.go b/core/services/gateway/handlers/functions/allowlist.go index 3ba9a65d57..0a18d6e6d8 100644 --- a/core/services/gateway/handlers/functions/allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist.go @@ -55,7 +55,7 @@ type onchainAllowlist struct { blockConfirmations *big.Int lggr logger.Logger closeWait sync.WaitGroup - stopCh utils.StopChan + stopCh services.StopChan } func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, lggr logger.Logger) (OnchainAllowlist, error) { @@ -78,7 +78,7 @@ func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, contractV1: contractV1, blockConfirmations: big.NewInt(int64(config.BlockConfirmations)), lggr: lggr.Named("OnchainAllowlist"), - stopCh: make(utils.StopChan), + stopCh: make(services.StopChan), } emptyMap := make(map[common.Address]struct{}) allowlist.allowlist.Store(&emptyMap) diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index 6cc4581a50..3269caa2d6 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -81,7 +80,7 @@ type functionsHandler struct { minimumBalance *assets.Link userRateLimiter *hc.RateLimiter nodeRateLimiter *hc.RateLimiter - chStop utils.StopChan + chStop services.StopChan lggr logger.Logger } @@ -161,7 +160,7 @@ func NewFunctionsHandler( minimumBalance: minimumBalance, userRateLimiter: userRateLimiter, nodeRateLimiter: nodeRateLimiter, - chStop: make(utils.StopChan), + chStop: make(services.StopChan), lggr: lggr, } } diff --git a/core/services/gateway/handlers/functions/subscriptions.go b/core/services/gateway/handlers/functions/subscriptions.go index 7a59e05731..ebffbbdd20 100644 --- a/core/services/gateway/handlers/functions/subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions.go @@ -49,7 +49,7 @@ type onchainSubscriptions struct { lggr logger.Logger closeWait sync.WaitGroup rwMutex sync.RWMutex - stopCh utils.StopChan + stopCh services.StopChan } func NewOnchainSubscriptions(client evmclient.Client, config OnchainSubscriptionsConfig, lggr logger.Logger) (OnchainSubscriptions, error) { @@ -70,7 +70,7 @@ func NewOnchainSubscriptions(client evmclient.Client, config OnchainSubscription router: router, blockConfirmations: big.NewInt(int64(config.BlockConfirmations)), lggr: lggr.Named("OnchainSubscriptions"), - stopCh: make(utils.StopChan), + stopCh: make(services.StopChan), }, nil } diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index 5656011e14..5ed017b874 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -11,10 +11,9 @@ import ( "github.com/jmoiron/sqlx" - commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -26,7 +25,7 @@ type ( // services that perform the work described by job specs. Each active job spec // has 1 or more of these services associated with it. Spawner interface { - services.ServiceCtx + services.Service // CreateJob creates a new job and starts services. // All services must start without errors for the job to be active. @@ -42,18 +41,23 @@ type ( StartService(ctx context.Context, spec Job, qopts ...pg.QOpt) error } + Checker interface { + Register(service services.HealthReporter) error + Unregister(name string) error + } + spawner struct { - commonservices.StateMachine + services.StateMachine orm ORM config Config - checker services.Checker + checker Checker jobTypeDelegates map[Type]Delegate activeJobs map[int32]activeJob activeJobsMu sync.RWMutex q pg.Q lggr logger.Logger - chStop utils.StopChan + chStop services.StopChan lbDependentAwaiters []utils.DependentAwaiter } @@ -86,7 +90,7 @@ type ( var _ Spawner = (*spawner)(nil) -func NewSpawner(orm ORM, config Config, checker services.Checker, jobTypeDelegates map[Type]Delegate, db *sqlx.DB, lggr logger.Logger, lbDependentAwaiters []utils.DependentAwaiter) *spawner { +func NewSpawner(orm ORM, config Config, checker Checker, jobTypeDelegates map[Type]Delegate, db *sqlx.DB, lggr logger.Logger, lbDependentAwaiters []utils.DependentAwaiter) *spawner { namedLogger := lggr.Named("JobSpawner") s := &spawner{ orm: orm, @@ -96,7 +100,7 @@ func NewSpawner(orm ORM, config Config, checker services.Checker, jobTypeDelegat q: pg.NewQ(db, namedLogger, config), lggr: namedLogger, activeJobs: make(map[int32]activeJob), - chStop: make(chan struct{}), + chStop: make(services.StopChan), lbDependentAwaiters: lbDependentAwaiters, } return s @@ -170,7 +174,7 @@ func (js *spawner) stopService(jobID int32) { for i := len(aj.services) - 1; i >= 0; i-- { service := aj.services[i] sLggr := lggr.With("subservice", i, "serviceType", reflect.TypeOf(service)) - if c, ok := service.(commonservices.HealthReporter); ok { + if c, ok := service.(services.HealthReporter); ok { if err := js.checker.Unregister(c.Name()); err != nil { sLggr.Warnw("Failed to unregister service from health checker", "err", err) } @@ -230,7 +234,7 @@ func (js *spawner) StartService(ctx context.Context, jb Job, qopts ...pg.QOpt) e lggr.Criticalw("Error starting service for job", "err", err) return err } - if c, ok := srv.(commonservices.HealthReporter); ok { + if c, ok := srv.(services.HealthReporter); ok { err = js.checker.Register(c) if err != nil { lggr.Errorw("Error registering service with health checker", "err", err) diff --git a/core/services/keeper/upkeep_executer.go b/core/services/keeper/upkeep_executer.go index ece6f85b06..84349ba2dc 100644 --- a/core/services/keeper/upkeep_executer.go +++ b/core/services/keeper/upkeep_executer.go @@ -55,7 +55,7 @@ type UpkeepExecuterConfig interface { // UpkeepExecuter implements the logic to communicate with KeeperRegistry type UpkeepExecuter struct { services.StateMachine - chStop utils.StopChan + chStop services.StopChan ethClient evmclient.Client config UpkeepExecuterConfig executionQueue chan struct{} @@ -83,7 +83,7 @@ func NewUpkeepExecuter( effectiveKeeperAddress common.Address, ) *UpkeepExecuter { return &UpkeepExecuter{ - chStop: make(chan struct{}), + chStop: make(services.StopChan), ethClient: ethClient, executionQueue: make(chan struct{}, executionQueueSize), headBroadcaster: headBroadcaster, diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 5fecbe8628..4f79bcfc31 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -74,7 +74,7 @@ type ( unsubscribeHeads func() // Start/Stop lifecycle - chStop utils.StopChan + chStop services.StopChan wg sync.WaitGroup unsubscribeLogs func() @@ -134,7 +134,7 @@ func NewOCRContractTracker( cfg: cfg, mailMon: mailMon, headBroadcaster: headBroadcaster, - chStop: make(chan struct{}), + chStop: make(services.StopChan), latestRoundRequested: offchainaggregator.OffchainAggregatorRoundRequested{}, configsMB: utils.NewMailbox[ocrtypes.ContractConfig](configMailboxSanityLimit), chConfigs: make(chan ocrtypes.ContractConfig), diff --git a/core/services/ocr2/plugins/median/plugin.go b/core/services/ocr2/plugins/median/plugin.go index 4f83c4b5dd..11197f0917 100644 --- a/core/services/ocr2/plugins/median/plugin.go +++ b/core/services/ocr2/plugins/median/plugin.go @@ -10,17 +10,15 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" - - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type Plugin struct { loop.Plugin - stop utils.StopChan + stop services.StopChan } func NewPlugin(lggr logger.Logger) *Plugin { - return &Plugin{Plugin: loop.Plugin{Logger: lggr}, stop: make(utils.StopChan)} + return &Plugin{Plugin: loop.Plugin{Logger: lggr}, stop: make(services.StopChan)} } func (p *Plugin) NewMedianFactory(ctx context.Context, provider types.MedianProvider, dataSource, juelsPerFeeCoin median.DataSource, errorLog loop.ErrorLog) (loop.ReportingPluginFactory, error) { diff --git a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go index 0f03ae5bd0..6d52c0e8d2 100644 --- a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go @@ -5,12 +5,15 @@ import ( "encoding/hex" "time" + "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "google.golang.org/protobuf/proto" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" @@ -19,7 +22,7 @@ import ( ) type AutomationCustomTelemetryService struct { - utils.StartStopOnce + services.StateMachine monitoringEndpoint commontypes.MonitoringEndpoint blockSubscriber *evm21.BlockSubscriber blockSubChanID int diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go index 93f35ce0d2..0cf0bbef5c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go @@ -5,12 +5,15 @@ import ( "encoding/hex" "time" + "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "google.golang.org/protobuf/proto" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" @@ -19,7 +22,7 @@ import ( ) type AutomationCustomTelemetryService struct { - utils.StartStopOnce + services.StateMachine monitoringEndpoint commontypes.MonitoringEndpoint blockSubscriber *evm21.BlockSubscriber blockSubChanID int diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go index 55436937d1..4ce7893a0b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go @@ -14,6 +14,8 @@ import ( "github.com/avast/retry-go/v4" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -34,7 +36,7 @@ type MercuryV02Response struct { } type client struct { - utils.StartStopOnce + services.StateMachine mercuryConfig mercury.MercuryConfigProvider httpClient mercury.HttpClient threadCtrl utils.ThreadControl diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go index 3697dca53c..1c60788974 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go @@ -14,6 +14,8 @@ import ( "github.com/avast/retry-go/v4" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -43,7 +45,7 @@ type MercuryV03Report struct { } type client struct { - utils.StartStopOnce + services.StateMachine mercuryConfig mercury.MercuryConfigProvider httpClient mercury.HttpClient threadCtrl utils.ThreadControl diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 252d2d91c7..afb1a7cf6c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -17,7 +17,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/chainlink-common/pkg/services" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" @@ -31,6 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -166,7 +167,7 @@ func (c *MercuryConfig) SetPluginRetry(k string, v interface{}, d time.Duration) } type EvmRegistry struct { - utils.StartStopOnce + services.StateMachine threadCtrl utils.ThreadControl lggr logger.Logger poller logpoller.LogPoller diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index edb1d337af..388f7358ef 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -68,7 +68,7 @@ type runner struct { // test helper runFinished func(*Run) - chStop utils.StopChan + chStop services.StopChan wgDone sync.WaitGroup } diff --git a/core/services/promreporter/prom_reporter.go b/core/services/promreporter/prom_reporter.go index 2306640bea..d115b1022c 100644 --- a/core/services/promreporter/prom_reporter.go +++ b/core/services/promreporter/prom_reporter.go @@ -27,7 +27,7 @@ type ( lggr logger.Logger backend PrometheusBackend newHeads *utils.Mailbox[*evmtypes.Head] - chStop utils.StopChan + chStop services.StopChan wgDone sync.WaitGroup reportPeriod time.Duration } diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go index 230185d0ad..95f45022ab 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper.go +++ b/core/services/relay/evm/functions/logpoller_wrapper.go @@ -39,7 +39,7 @@ type logPollerWrapper struct { detectedResponses detectedEvents mu sync.Mutex closeWait sync.WaitGroup - stopCh utils.StopChan + stopCh services.StopChan lggr logger.Logger } @@ -106,7 +106,7 @@ func NewLogPollerWrapper(routerContractAddress common.Address, pluginConfig conf logPoller: logPoller, client: client, subscribers: make(map[string]evmRelayTypes.RouteUpdateSubscriber), - stopCh: make(utils.StopChan), + stopCh: make(services.StopChan), lggr: lggr, }, nil } diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index 69dfce9c16..779e275f15 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -24,7 +24,7 @@ type PersistenceManager struct { orm ORM once services.StateMachine - stopCh utils.StopChan + stopCh services.StopChan wg sync.WaitGroup deleteMu sync.Mutex @@ -41,7 +41,7 @@ func NewPersistenceManager(lggr logger.Logger, orm ORM, jobID int32, maxTransmit return &PersistenceManager{ lggr: lggr.Named("MercuryPersistenceManager"), orm: orm, - stopCh: make(chan struct{}), + stopCh: make(services.StopChan), jobID: jobID, maxTransmitQueueSize: maxTransmitQueueSize, flushDeletesFrequency: flushDeletesFrequency, diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 73aa10243f..d5346ad28c 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -115,7 +115,7 @@ type mercuryTransmitter struct { jobID int32 fromAccount string - stopCh utils.StopChan + stopCh services.StopChan queue *TransmitQueue wg sync.WaitGroup @@ -161,7 +161,7 @@ func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrp feedID, jobID, fmt.Sprintf("%x", fromAccount), - make(chan (struct{})), + make(services.StopChan), nil, sync.WaitGroup{}, make(chan *pb.TransmitRequest, maxDeleteQueueSize), diff --git a/core/services/relay/evm/mercury/wsrpc/client.go b/core/services/relay/evm/mercury/wsrpc/client.go index c4db80a58d..c04c00074a 100644 --- a/core/services/relay/evm/mercury/wsrpc/client.go +++ b/core/services/relay/evm/mercury/wsrpc/client.go @@ -84,7 +84,7 @@ type client struct { consecutiveTimeoutCnt atomic.Int32 wg sync.WaitGroup - chStop utils.StopChan + chStop services.StopChan chResetTransport chan struct{} timeoutCountMetric prometheus.Counter @@ -106,7 +106,7 @@ func newClient(lggr logger.Logger, clientPrivKey csakey.KeyV2, serverPubKey []by serverURL: serverURL, logger: lggr.Named("WSRPC").With("mercuryServerURL", serverURL), chResetTransport: make(chan struct{}, 1), - chStop: make(chan struct{}), + chStop: make(services.StopChan), timeoutCountMetric: timeoutCount.WithLabelValues(serverURL), dialCountMetric: dialCount.WithLabelValues(serverURL), dialSuccessCountMetric: dialSuccessCount.WithLabelValues(serverURL), diff --git a/core/services/synchronization/telemetry_ingress_batch_worker.go b/core/services/synchronization/telemetry_ingress_batch_worker.go index 141eb30c81..e7ea659581 100644 --- a/core/services/synchronization/telemetry_ingress_batch_worker.go +++ b/core/services/synchronization/telemetry_ingress_batch_worker.go @@ -6,23 +6,23 @@ import ( "sync/atomic" "time" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // telemetryIngressBatchWorker pushes telemetry in batches to the ingress server via wsrpc. // A worker is created per ContractID. type telemetryIngressBatchWorker struct { - services.ServiceCtx + services.Service telemMaxBatchSize uint telemSendInterval time.Duration telemSendTimeout time.Duration telemClient telemPb.TelemClient wgDone *sync.WaitGroup - chDone utils.StopChan + chDone services.StopChan chTelemetry chan TelemPayload contractID string telemType TelemetryType diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go index b889b3fc97..b566199fdc 100644 --- a/core/services/synchronization/telemetry_ingress_client.go +++ b/core/services/synchronization/telemetry_ingress_client.go @@ -15,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type NoopTelemetryIngressClient struct{} @@ -46,7 +45,7 @@ type telemetryIngressClient struct { lggr logger.Logger wgDone sync.WaitGroup - chDone chan struct{} + chDone services.StopChan dropMessageCount atomic.Uint32 chTelemetry chan TelemPayload } @@ -61,7 +60,7 @@ func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore logging: logging, lggr: lggr.Named("TelemetryIngressClient"), chTelemetry: make(chan TelemPayload, telemBufferSize), - chDone: make(chan struct{}), + chDone: make(services.StopChan), } } @@ -132,7 +131,7 @@ func (tc *telemetryIngressClient) connect(ctx context.Context, clientPrivKey []b func (tc *telemetryIngressClient) handleTelemetry() { go func() { - ctx, cancel := utils.StopChan(tc.chDone).NewCtx() + ctx, cancel := tc.chDone.NewCtx() defer cancel() for { select { diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 566e5ac9bd..3e958801cd 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -58,7 +58,7 @@ type Listener struct { GethKs vrfcommon.GethKeyStore MailMon *utils.MailboxMonitor ReqLogs *utils.Mailbox[log.Broadcast] - ChStop utils.StopChan + ChStop services.StopChan WaitOnStop chan struct{} NewHead chan struct{} LatestHead uint64 diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 5b73ac9e24..7f23e02277 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -128,7 +128,7 @@ func New( q: q, gethks: gethks, reqLogs: reqLogs, - chStop: make(chan struct{}), + chStop: make(services.StopChan), reqAdded: reqAdded, blockNumberToReqID: pairing.New(), latestHeadMu: sync.RWMutex{}, @@ -183,7 +183,7 @@ type listenerV2 struct { q pg.Q gethks keystore.Eth reqLogs *utils.Mailbox[log.Broadcast] - chStop utils.StopChan + chStop services.StopChan // We can keep these pending logs in memory because we // only mark them confirmed once we send a corresponding fulfillment transaction. // So on node restart in the middle of processing, the lb will resend them. diff --git a/core/services/webhook/delegate.go b/core/services/webhook/delegate.go index f5a8d553f2..237245b81c 100644 --- a/core/services/webhook/delegate.go +++ b/core/services/webhook/delegate.go @@ -8,11 +8,12 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ( @@ -111,7 +112,7 @@ func newWebhookJobRunner(runner pipeline.Runner, lggr logger.Logger) *webhookJob type registeredJob struct { job.Job - chRemove utils.StopChan + chRemove services.StopChan } func (r *webhookJobRunner) addSpec(spec job.Job) error { diff --git a/core/utils/thread_control.go b/core/utils/thread_control.go index 8f7fff4249..52cda82797 100644 --- a/core/utils/thread_control.go +++ b/core/utils/thread_control.go @@ -3,6 +3,8 @@ package utils import ( "context" "sync" + + "github.com/smartcontractkit/chainlink-common/pkg/services" ) var _ ThreadControl = &threadControl{} @@ -25,7 +27,7 @@ func NewThreadControl() *threadControl { type threadControl struct { threadsWG sync.WaitGroup - stop StopChan + stop services.StopChan } func (tc *threadControl) Go(fn func(context.Context)) { diff --git a/core/utils/utils.go b/core/utils/utils.go index a2e418fe04..69597fb9e4 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -399,68 +399,28 @@ func WaitGroupChan(wg *sync.WaitGroup) <-chan struct{} { } // WithCloseChan wraps a context so that it is canceled if the passed in channel is closed. -// Deprecated: Call StopChan.Ctx directly +// Deprecated: Call [services.StopChan.Ctx] directly func WithCloseChan(parentCtx context.Context, chStop chan struct{}) (context.Context, context.CancelFunc) { - return StopChan(chStop).Ctx(parentCtx) + return services.StopChan(chStop).Ctx(parentCtx) } // ContextFromChan creates a context that finishes when the provided channel receives or is closed. -// Deprecated: Call StopChan.NewCtx directly. +// Deprecated: Call [services.StopChan.NewCtx] directly. func ContextFromChan(chStop chan struct{}) (context.Context, context.CancelFunc) { - return StopChan(chStop).NewCtx() + return services.StopChan(chStop).NewCtx() } // ContextFromChanWithTimeout creates a context with a timeout that finishes when the provided channel receives or is closed. -// Deprecated: Call StopChan.CtxCancel directly +// Deprecated: Call [services.StopChan.CtxCancel] directly func ContextFromChanWithTimeout(chStop chan struct{}, timeout time.Duration) (context.Context, context.CancelFunc) { - return StopChan(chStop).CtxCancel(context.WithTimeout(context.Background(), timeout)) + return services.StopChan(chStop).CtxCancel(context.WithTimeout(context.Background(), timeout)) } -// A StopChan signals when some work should stop. -type StopChan chan struct{} +// Deprecated: use services.StopChan +type StopChan = services.StopChan -// NewCtx returns a background [context.Context] that is cancelled when StopChan is closed. -func (s StopChan) NewCtx() (context.Context, context.CancelFunc) { - return StopRChan((<-chan struct{})(s)).NewCtx() -} - -// Ctx cancels a [context.Context] when StopChan is closed. -func (s StopChan) Ctx(ctx context.Context) (context.Context, context.CancelFunc) { - return StopRChan((<-chan struct{})(s)).Ctx(ctx) -} - -// CtxCancel cancels a [context.Context] when StopChan is closed. -// Returns ctx and cancel unmodified, for convenience. -func (s StopChan) CtxCancel(ctx context.Context, cancel context.CancelFunc) (context.Context, context.CancelFunc) { - return StopRChan((<-chan struct{})(s)).CtxCancel(ctx, cancel) -} - -// A StopRChan signals when some work should stop. -// This version is receive-only. -type StopRChan <-chan struct{} - -// NewCtx returns a background [context.Context] that is cancelled when StopChan is closed. -func (s StopRChan) NewCtx() (context.Context, context.CancelFunc) { - return s.Ctx(context.Background()) -} - -// Ctx cancels a [context.Context] when StopChan is closed. -func (s StopRChan) Ctx(ctx context.Context) (context.Context, context.CancelFunc) { - return s.CtxCancel(context.WithCancel(ctx)) -} - -// CtxCancel cancels a [context.Context] when StopChan is closed. -// Returns ctx and cancel unmodified, for convenience. -func (s StopRChan) CtxCancel(ctx context.Context, cancel context.CancelFunc) (context.Context, context.CancelFunc) { - go func() { - select { - case <-s: - cancel() - case <-ctx.Done(): - } - }() - return ctx, cancel -} +// Deprecated: use services.StopRChan +type StopRChan = services.StopRChan // DependentAwaiter contains Dependent funcs type DependentAwaiter interface { diff --git a/core/utils/utils_example_test.go b/core/utils/utils_example_test.go deleted file mode 100644 index 0ca9d0be88..0000000000 --- a/core/utils/utils_example_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package utils - -import ( - "context" - "sync" - "time" -) - -func ExampleStopChan() { - stopCh := make(StopChan) - - work := func(context.Context) {} - - a := func(ctx context.Context, done func()) { - defer done() - ctx, cancel := stopCh.Ctx(ctx) - defer cancel() - work(ctx) - } - - b := func(ctx context.Context, done func()) { - defer done() - ctx, cancel := stopCh.CtxCancel(context.WithTimeout(ctx, time.Second)) - defer cancel() - work(ctx) - } - - c := func(ctx context.Context, done func()) { - defer done() - ctx, cancel := stopCh.CtxCancel(context.WithDeadline(ctx, time.Now().Add(5*time.Second))) - defer cancel() - work(ctx) - } - - ctx, cancel := stopCh.NewCtx() - defer cancel() - - var wg sync.WaitGroup - wg.Add(3) - go a(ctx, wg.Done) - go b(ctx, wg.Done) - go c(ctx, wg.Done) - - time.AfterFunc(time.Second, func() { close(stopCh) }) - - wg.Wait() - // Output: -} diff --git a/core/utils/utils_test.go b/core/utils/utils_test.go index 04802feb3a..e11c01a8e4 100644 --- a/core/utils/utils_test.go +++ b/core/utils/utils_test.go @@ -374,79 +374,6 @@ func Test_WithJitter(t *testing.T) { } } -func Test_StartStopOnce_StopWaitsForStartToFinish(t *testing.T) { - t.Parallel() - - once := utils.StartStopOnce{} - - ch := make(chan int, 3) - - ready := make(chan bool) - - go func() { - assert.NoError(t, once.StartOnce("slow service", func() (err error) { - ch <- 1 - ready <- true - <-time.After(time.Millisecond * 500) // wait for StopOnce to happen - ch <- 2 - - return nil - })) - }() - - go func() { - <-ready // try stopping halfway through startup - assert.NoError(t, once.StopOnce("slow service", func() (err error) { - ch <- 3 - - return nil - })) - }() - - require.Equal(t, 1, <-ch) - require.Equal(t, 2, <-ch) - require.Equal(t, 3, <-ch) -} - -func Test_StartStopOnce_MultipleStartNoBlock(t *testing.T) { - t.Parallel() - - once := utils.StartStopOnce{} - - ch := make(chan int, 3) - - ready := make(chan bool) - next := make(chan bool) - - go func() { - ch <- 1 - assert.NoError(t, once.StartOnce("slow service", func() (err error) { - ready <- true - <-next // continue after the other StartOnce call fails - - return nil - })) - <-next - ch <- 2 - - }() - - go func() { - <-ready // try starting halfway through startup - assert.Error(t, once.StartOnce("slow service", func() (err error) { - return nil - })) - next <- true - ch <- 3 - next <- true - - }() - - require.Equal(t, 1, <-ch) - require.Equal(t, 3, <-ch) // 3 arrives before 2 because it returns immediately - require.Equal(t, 2, <-ch) -} - func TestAllEqual(t *testing.T) { t.Parallel() diff --git a/plugins/medianpoc/plugin.go b/plugins/medianpoc/plugin.go index 62b6acc043..af4ec41ab8 100644 --- a/plugins/medianpoc/plugin.go +++ b/plugins/medianpoc/plugin.go @@ -14,20 +14,19 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func NewPlugin(lggr logger.Logger) *Plugin { return &Plugin{ Plugin: loop.Plugin{Logger: lggr}, MedianProviderServer: reportingplugins.MedianProviderServer{}, - stop: make(utils.StopChan), + stop: make(services.StopChan), } } type Plugin struct { loop.Plugin - stop utils.StopChan + stop services.StopChan reportingplugins.MedianProviderServer } From f7949c5994b8c653072ea49747cce84dfe886df4 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 20 Nov 2023 18:13:50 -0600 Subject: [PATCH 180/327] replace context.Background() (#11334) --- .../dashboard/cmd/dashboard_deploy.go | 4 +- .../chainlink-cluster/dashboard/dashboard.go | 3 +- common/client/send_only_node_lifecycle.go | 7 +- .../evm/client/send_only_node_lifecycle.go | 7 +- core/chains/evm/gas/models_test.go | 4 +- core/chains/evm/logpoller/log_poller.go | 11 +- .../evm/logpoller/log_poller_internal_test.go | 147 ++++++++---------- core/chains/evm/logpoller/log_poller_test.go | 10 +- core/chains/evm/txmgr/evm_tx_store.go | 18 ++- core/cmd/ocr2vrf_configure_commands.go | 30 ++-- core/internal/cltest/cltest.go | 2 +- core/internal/testutils/pgtest/txdb_test.go | 4 +- core/services/blockhashstore/bhs_test.go | 8 +- core/services/feeds/service.go | 2 +- .../gateway/handlers/handler.dummy_test.go | 9 +- core/services/job/job_orm_test.go | 2 +- core/services/job/mocks/orm.go | 18 +-- core/services/job/orm.go | 6 +- core/services/keystore/starknet_test.go | 8 +- .../generic/pipeline_runner_adapter_test.go | 9 +- .../plugins/generic/telemetry_adapter_test.go | 7 +- .../ocr2/plugins/mercury/helpers_test.go | 4 +- .../plugins/ocr2keeper/evm20/registry_test.go | 7 +- .../ocr2keeper/evm21/block_subscriber_test.go | 6 +- .../evm21/logprovider/block_time_test.go | 5 +- .../evm21/logprovider/integration_test.go | 13 +- .../logprovider/provider_life_cycle_test.go | 11 +- .../evm21/logprovider/provider_test.go | 7 +- .../evm21/logprovider/recoverer_test.go | 11 +- .../evm21/mercury/streams/streams_test.go | 9 +- .../evm21/mercury/v02/v02_request_test.go | 6 +- .../evm21/mercury/v03/v03_request_test.go | 6 +- .../ocr2keeper/evm21/payload_builder_test.go | 6 +- .../evm21/registry_check_pipeline_test.go | 12 +- .../evm21/transmit/event_provider_test.go | 8 +- .../evm21/upkeepstate/store_test.go | 13 +- .../plugins/ocr2keeper/integration_21_test.go | 5 +- .../plugins/ocr2keeper/integration_test.go | 5 +- .../internal/ocr2vrf_integration_test.go | 8 +- .../ocr2/plugins/promwrapper/plugin_test.go | 16 +- .../evm/mercury/persistence_manager_test.go | 10 +- .../relay/evm/mercury/v1/data_source_test.go | 4 +- .../relay/grpc_provider_server_test.go | 4 +- core/services/relay/relay_test.go | 5 +- core/services/telemetry/manager_test.go | 3 +- .../services/transmission/integration_test.go | 3 +- core/services/vrf/v2/integration_v2_test.go | 10 +- core/web/jobs_controller.go | 2 +- .../automationv2_1/automationv2_1_test.go | 12 +- plugins/medianpoc/data_source_test.go | 7 +- plugins/medianpoc/plugin_test.go | 4 +- 51 files changed, 269 insertions(+), 269 deletions(-) diff --git a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go index c752794f53..170ffa0288 100644 --- a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go +++ b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go @@ -1,12 +1,14 @@ package main import ( + "context" "os" "github.com/smartcontractkit/chainlink/v2/dashboard/dashboard" ) func main() { + ctx := context.Background() name := os.Getenv("DASHBOARD_NAME") if name == "" { panic("DASHBOARD_NAME must be provided") @@ -36,7 +38,7 @@ func main() { if err != nil { panic(err) } - if err := db.Deploy(); err != nil { + if err := db.Deploy(ctx); err != nil { panic(err) } } diff --git a/charts/chainlink-cluster/dashboard/dashboard.go b/charts/chainlink-cluster/dashboard/dashboard.go index 7918b996dd..293cded2b0 100644 --- a/charts/chainlink-cluster/dashboard/dashboard.go +++ b/charts/chainlink-cluster/dashboard/dashboard.go @@ -378,8 +378,7 @@ func (m *CLClusterDashboard) generate() error { } // Deploy deploys the dashboard to Grafana -func (m *CLClusterDashboard) Deploy() error { - ctx := context.Background() +func (m *CLClusterDashboard) Deploy(ctx context.Context) error { client := grabana.NewClient(&http.Client{}, m.GrafanaURL, grabana.WithAPIToken(m.GrafanaToken)) folder, err := client.FindOrCreateFolder(ctx, m.Folder) if err != nil { diff --git a/common/client/send_only_node_lifecycle.go b/common/client/send_only_node_lifecycle.go index 0f663eab30..4d5b102b5b 100644 --- a/common/client/send_only_node_lifecycle.go +++ b/common/client/send_only_node_lifecycle.go @@ -1,7 +1,6 @@ package client import ( - "context" "fmt" "time" @@ -14,15 +13,17 @@ import ( // It will continue checking until success and then exit permanently. func (s *sendOnlyNode[CHAIN_ID, RPC]) verifyLoop() { defer s.wg.Done() + ctx, cancel := s.chStop.NewCtx() + defer cancel() backoff := utils.NewRedialBackoff() for { select { - case <-s.chStop: + case <-ctx.Done(): return case <-time.After(backoff.Duration()): } - chainID, err := s.rpc.ChainID(context.Background()) + chainID, err := s.rpc.ChainID(ctx) if err != nil { ok := s.IfStarted(func() { if changed := s.setState(nodeStateUnreachable); changed { diff --git a/core/chains/evm/client/send_only_node_lifecycle.go b/core/chains/evm/client/send_only_node_lifecycle.go index 509be53c8a..9d704e4938 100644 --- a/core/chains/evm/client/send_only_node_lifecycle.go +++ b/core/chains/evm/client/send_only_node_lifecycle.go @@ -1,7 +1,6 @@ package client import ( - "context" "fmt" "time" @@ -14,12 +13,14 @@ import ( // It will continue checking until success and then exit permanently. func (s *sendOnlyNode) verifyLoop() { defer s.wg.Done() + ctx, cancel := s.chStop.NewCtx() + defer cancel() backoff := utils.NewRedialBackoff() for { select { case <-time.After(backoff.Duration()): - chainID, err := s.sender.ChainID(context.Background()) + chainID, err := s.sender.ChainID(ctx) if err != nil { ok := s.IfStarted(func() { if changed := s.setState(NodeStateUnreachable); changed { @@ -60,7 +61,7 @@ func (s *sendOnlyNode) verifyLoop() { s.log.Infow("Sendonly RPC Node is online", "nodeState", s.state) return } - case <-s.chStop: + case <-ctx.Done(): return } } diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index 8ac94a2269..a2dce58ee3 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -1,7 +1,6 @@ package gas_test import ( - "context" "math/big" "testing" @@ -14,11 +13,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) func TestWrappedEvmEstimator(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := testutils.Context(t) // fee values gasLimit := uint32(10) diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 6676b694b0..bb93db4037 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -130,8 +130,10 @@ type logPoller struct { // support chain, polygon, which has 2s block times, we need RPCs roughly with <= 500ms latency func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, pollPeriod time.Duration, useFinalityTag bool, finalityDepth int64, backfillBatchSize int64, rpcBatchSize int64, keepFinalizedBlocksDepth int64) *logPoller { - + ctx, cancel := context.WithCancel(context.Background()) return &logPoller{ + ctx: ctx, + cancel: cancel, ec: ec, orm: orm, lggr: lggr.Named("LogPoller"), @@ -371,18 +373,15 @@ func (lp *logPoller) recvReplayComplete() { func (lp *logPoller) ReplayAsync(fromBlock int64) { lp.wg.Add(1) go func() { - if err := lp.Replay(context.Background(), fromBlock); err != nil { + if err := lp.Replay(lp.ctx, fromBlock); err != nil { lp.lggr.Error(err) } lp.wg.Done() }() } -func (lp *logPoller) Start(parentCtx context.Context) error { +func (lp *logPoller) Start(context.Context) error { return lp.StartOnce("LogPoller", func() error { - ctx, cancel := context.WithCancel(parentCtx) - lp.ctx = ctx - lp.cancel = cancel lp.wg.Add(1) go lp.run() return nil diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index c0d081582f..2ef276802b 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/services" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" @@ -233,7 +234,6 @@ func TestLogPoller_BackupPollerStartup(t *testing.T) { func TestLogPoller_Replay(t *testing.T) { t.Parallel() addr := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbc") - tctx := testutils.Context(t) lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.ErrorLevel) chainID := testutils.FixtureChainID @@ -259,48 +259,39 @@ func TestLogPoller_Replay(t *testing.T) { lp := NewLogPoller(orm, ec, lggr, time.Hour, false, 3, 3, 3, 20) // process 1 log in block 3 - lp.PollAndSaveLogs(tctx, 4) + lp.PollAndSaveLogs(testutils.Context(t), 4) latest, err := lp.LatestBlock() require.NoError(t, err) require.Equal(t, int64(4), latest.BlockNumber) t.Run("abort before replayStart received", func(t *testing.T) { // Replay() should abort immediately if caller's context is cancelled before request signal is read - ctx, cancel := context.WithCancel(tctx) + ctx, cancel := context.WithCancel(testutils.Context(t)) cancel() err = lp.Replay(ctx, 3) assert.ErrorIs(t, err, ErrReplayRequestAborted) }) - recvStartReplay := func(parentCtx context.Context, block int64, withTimeout bool) { - var err error - var ctx context.Context - var cancel context.CancelFunc - if withTimeout { - ctx, cancel = context.WithTimeout(parentCtx, testutils.WaitTimeout(t)) - } else { - ctx, cancel = context.WithCancel(parentCtx) - } - defer cancel() + recvStartReplay := func(ctx context.Context, block int64) { select { case fromBlock := <-lp.replayStart: assert.Equal(t, block, fromBlock) case <-ctx.Done(): - err = ctx.Err() + assert.NoError(t, ctx.Err(), "Timed out waiting to receive replay request from lp.replayStart") } - assert.NoError(t, err, "Timed out waiting to receive replay request from lp.replayStart") } // Replay() should return error code received from replayComplete t.Run("returns error code on replay complete", func(t *testing.T) { + ctx := testutils.Context(t) anyErr := errors.New("any error") done := make(chan struct{}) go func() { defer close(done) - recvStartReplay(tctx, 1, true) + recvStartReplay(ctx, 1) lp.replayComplete <- anyErr }() - assert.ErrorIs(t, lp.Replay(tctx, 1), anyErr) + assert.ErrorIs(t, lp.Replay(ctx, 1), anyErr) <-done }) @@ -310,7 +301,7 @@ func TestLogPoller_Replay(t *testing.T) { done := make(chan struct{}) go func() { defer close(done) - recvStartReplay(ctx, 4, false) + recvStartReplay(ctx, 4) cancel() }() assert.ErrorIs(t, lp.Replay(ctx, 4), ErrReplayInProgress) @@ -323,29 +314,33 @@ func TestLogPoller_Replay(t *testing.T) { t.Run("client abort doesnt hang run loop", func(t *testing.T) { lp.backupPollerNextBlock = 0 - timeLeft := testutils.WaitTimeout(t) - timeout := time.After(timeLeft) - ctx, cancel := context.WithCancel(tctx) + ctx := testutils.Context(t) - var wg sync.WaitGroup pass := make(chan struct{}) cancelled := make(chan struct{}) + rctx, rcancel := context.WithCancel(testutils.Context(t)) + var wg sync.WaitGroup + defer func() { wg.Wait() }() ec.On("FilterLogs", mock.Anything, mock.Anything).Once().Return([]types.Log{log1}, nil).Run(func(args mock.Arguments) { wg.Add(1) go func() { defer wg.Done() - assert.ErrorIs(t, lp.Replay(ctx, 4), ErrReplayInProgress) + assert.ErrorIs(t, lp.Replay(rctx, 4), ErrReplayInProgress) close(cancelled) }() }) ec.On("FilterLogs", mock.Anything, mock.Anything).Once().Return([]types.Log{log1}, nil).Run(func(args mock.Arguments) { - cancel() + rcancel() wg.Add(1) go func() { defer wg.Done() - lp.replayStart <- 4 - close(pass) + select { + case lp.replayStart <- 4: + close(pass) + case <-ctx.Done(): + return + } }() // We cannot return until we're sure that Replay() received the cancellation signal, // otherwise replayComplete<- might be sent first @@ -354,24 +349,13 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Maybe() // in case task gets delayed by >= 100ms - lp.ctx, lp.cancel = context.WithCancel(tctx) - lp.wg.Add(1) - defer func() { - select { - case <-lp.replayStart: - default: - } - wg.Wait() - lp.cancel() - lp.wg.Wait() - }() + t.Cleanup(lp.reset) + require.NoError(t, lp.Start(ctx)) + t.Cleanup(func() { assert.NoError(t, lp.Close()) }) - go func() { - lp.run() - }() select { - case <-timeout: - assert.Failf(t, "lp.run() got stuck--failed to respond to second replay event within %s", timeLeft.String()) + case <-ctx.Done(): + t.Errorf("timed out waiting for lp.run() to respond to second replay event") case <-pass: } }) @@ -383,13 +367,18 @@ func TestLogPoller_Replay(t *testing.T) { t.Run("shutdown during replay", func(t *testing.T) { lp.backupPollerNextBlock = 0 - safeToExit := make(chan struct{}) pass := make(chan struct{}) + done := make(chan struct{}) + defer func() { <-done }() + ctx := testutils.Context(t) ec.On("FilterLogs", mock.Anything, mock.Anything).Once().Return([]types.Log{log1}, nil).Run(func(args mock.Arguments) { go func() { - lp.replayStart <- 4 - close(safeToExit) + defer close(done) + select { + case lp.replayStart <- 4: + case <-ctx.Done(): + } }() }) ec.On("FilterLogs", mock.Anything, mock.Anything).Once().Return([]types.Log{log1}, nil).Run(func(args mock.Arguments) { @@ -398,71 +387,57 @@ func TestLogPoller_Replay(t *testing.T) { }) ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Maybe() // in case task gets delayed by >= 100ms - timeLeft := testutils.WaitTimeout(t) - timeout := time.After(timeLeft) - require.NoError(t, lp.Start(tctx)) - - defer func() { - select { - case <-lp.replayStart: // unblock replayStart<- goroutine if it's stuck - default: - } - <-safeToExit - lp.Close() - }() + t.Cleanup(lp.reset) + require.NoError(t, lp.Start(ctx)) + t.Cleanup(func() { assert.NoError(t, lp.Close()) }) select { - case <-timeout: - assert.Failf(t, "lp.run() failed to respond to shutdown event during replay within %s", timeLeft.String()) + case <-ctx.Done(): + t.Error("timed out waiting for lp.run() to respond to shutdown event during replay") case <-pass: } }) // ReplayAsync should return as soon as replayStart is received t.Run("ReplayAsync success", func(t *testing.T) { - lp.ctx, lp.cancel = context.WithTimeout(tctx, testutils.WaitTimeout(t)) - defer func() { - lp.replayComplete <- nil - lp.cancel() - lp.wg.Wait() - }() + t.Cleanup(lp.reset) + require.NoError(t, lp.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, lp.Close()) }) - done := make(chan struct{}) - go func() { - lp.ReplayAsync(1) - close(done) - }() - recvStartReplay(tctx, 1, true) - <-done + lp.ReplayAsync(1) + + recvStartReplay(testutils.Context(t), 1) }) t.Run("ReplayAsync error", func(t *testing.T) { - timeLeft := testutils.WaitTimeout(t) - lp.ctx, lp.cancel = context.WithTimeout(tctx, timeLeft) - defer func() { - lp.cancel() - lp.wg.Wait() - }() + t.Cleanup(lp.reset) + require.NoError(t, lp.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + anyErr := errors.New("async error") observedLogs.TakeAll() lp.ReplayAsync(4) - recvStartReplay(tctx, 4, true) + recvStartReplay(testutils.Context(t), 4) select { case lp.replayComplete <- anyErr: time.Sleep(2 * time.Second) case <-lp.ctx.Done(): - assert.Failf(t, "failed to receive replayComplete signal within %s", timeLeft.String()) + t.Error("timed out waiting to send replaceComplete") } require.Equal(t, 1, observedLogs.Len()) assert.Equal(t, observedLogs.All()[0].Message, anyErr.Error()) }) } +func (lp *logPoller) reset() { + lp.StateMachine = services.StateMachine{} + lp.ctx, lp.cancel = context.WithCancel(context.Background()) +} + func Test_latestBlockAndFinalityDepth(t *testing.T) { - tctx := testutils.Context(t) - lggr, _ := logger.TestLoggerObserved(t, zapcore.ErrorLevel) + lggr := logger.TestLogger(t) chainID := testutils.FixtureChainID db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) @@ -474,7 +449,7 @@ func Test_latestBlockAndFinalityDepth(t *testing.T) { ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(&head, nil) lp := NewLogPoller(orm, ec, lggr, time.Hour, false, finalityDepth, 3, 3, 20) - latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(tctx) + latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(testutils.Context(t)) require.NoError(t, err) require.Equal(t, latestBlock.Number, head.Number) require.Equal(t, finalityDepth, latestBlock.Number-lastFinalizedBlockNumber) @@ -499,7 +474,7 @@ func Test_latestBlockAndFinalityDepth(t *testing.T) { lp := NewLogPoller(orm, ec, lggr, time.Hour, true, 3, 3, 3, 20) - latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(tctx) + latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(testutils.Context(t)) require.NoError(t, err) require.Equal(t, expectedLatestBlockNumber, latestBlock.Number) require.Equal(t, expectedLastFinalizedBlockNumber, lastFinalizedBlockNumber) @@ -516,7 +491,7 @@ func Test_latestBlockAndFinalityDepth(t *testing.T) { }) lp := NewLogPoller(orm, ec, lggr, time.Hour, true, 3, 3, 3, 20) - _, _, err := lp.latestBlocks(tctx) + _, _, err := lp.latestBlocks(testutils.Context(t)) require.Error(t, err) }) @@ -525,7 +500,7 @@ func Test_latestBlockAndFinalityDepth(t *testing.T) { ec.On("BatchCallContext", mock.Anything, mock.Anything).Return(fmt.Errorf("some error")) lp := NewLogPoller(orm, ec, lggr, time.Hour, true, 3, 3, 3, 20) - _, _, err := lp.latestBlocks(tctx) + _, _, err := lp.latestBlocks(testutils.Context(t)) require.Error(t, err) }) }) diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 5f013ca914..94589f505a 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -626,19 +626,19 @@ func TestLogPoller_BlockTimestamps(t *testing.T) { require.Len(t, gethLogs, 2) lb, _ := th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) - th.PollAndSaveLogs(context.Background(), lb.BlockNumber+1) + th.PollAndSaveLogs(ctx, lb.BlockNumber+1) lg1, err := th.LogPoller.Logs(0, 20, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, - pg.WithParentCtx(testutils.Context(t))) + pg.WithParentCtx(ctx)) require.NoError(t, err) lg2, err := th.LogPoller.Logs(0, 20, EmitterABI.Events["Log2"].ID, th.EmitterAddress2, - pg.WithParentCtx(testutils.Context(t))) + pg.WithParentCtx(ctx)) require.NoError(t, err) // Logs should have correct timestamps - b, _ := th.Client.BlockByHash(context.Background(), lg1[0].BlockHash) + b, _ := th.Client.BlockByHash(ctx, lg1[0].BlockHash) t.Log(len(lg1), lg1[0].BlockTimestamp) assert.Equal(t, int64(b.Time()), lg1[0].BlockTimestamp.UTC().Unix(), time1) - b2, _ := th.Client.BlockByHash(context.Background(), lg2[0].BlockHash) + b2, _ := th.Client.BlockByHash(ctx, lg2[0].BlockHash) assert.Equal(t, int64(b2.Time()), lg2[0].BlockTimestamp.UTC().Unix(), time2) } diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 9262c85a83..0e08d32b77 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -1107,11 +1107,9 @@ ORDER BY nonce ASC return etxs, pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed") } -func saveAttemptWithNewState(q pg.Queryer, timeout time.Duration, logger logger.Logger, attempt TxAttempt, broadcastAt time.Time) error { - ctx, cancel := context.WithTimeout(context.Background(), timeout) +func saveAttemptWithNewState(ctx context.Context, q pg.Queryer, logger logger.Logger, attempt TxAttempt, broadcastAt time.Time) error { var dbAttempt DbEthTxAttempt dbAttempt.FromTxAttempt(&attempt) - defer cancel() return pg.SqlxTransaction(ctx, q, logger, func(tx pg.Queryer) error { // In case of null broadcast_at (shouldn't happen) we don't want to // update anyway because it indicates a state where broadcast_at makes @@ -1133,15 +1131,19 @@ func (o *evmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout t return errors.New("expected state to be either in_progress or insufficient_eth") } attempt.State = txmgrtypes.TxAttemptInsufficientFunds - return pkgerrors.Wrap(saveAttemptWithNewState(qq, timeout, o.logger, *attempt, broadcastAt), "saveInsufficientEthAttempt failed") + ctx, cancel = context.WithTimeout(ctx, timeout) + defer cancel() + return pkgerrors.Wrap(saveAttemptWithNewState(ctx, qq, o.logger, *attempt, broadcastAt), "saveInsufficientEthAttempt failed") } -func saveSentAttempt(q pg.Queryer, timeout time.Duration, logger logger.Logger, attempt *TxAttempt, broadcastAt time.Time) error { +func saveSentAttempt(ctx context.Context, q pg.Queryer, timeout time.Duration, logger logger.Logger, attempt *TxAttempt, broadcastAt time.Time) error { if attempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("expected state to be in_progress") } attempt.State = txmgrtypes.TxAttemptBroadcast - return pkgerrors.Wrap(saveAttemptWithNewState(q, timeout, logger, *attempt, broadcastAt), "saveSentAttempt failed") + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + return pkgerrors.Wrap(saveAttemptWithNewState(ctx, q, logger, *attempt, broadcastAt), "saveSentAttempt failed") } func (o *evmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { @@ -1149,7 +1151,7 @@ func (o *evmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration, ctx, cancel = o.mergeContexts(ctx) defer cancel() qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - return saveSentAttempt(qq, timeout, o.logger, attempt, broadcastAt) + return saveSentAttempt(ctx, qq, timeout, o.logger, attempt, broadcastAt) } func (o *evmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { @@ -1158,7 +1160,7 @@ func (o *evmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, tim defer cancel() qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err := qq.Transaction(func(tx pg.Queryer) error { - if err := saveSentAttempt(tx, timeout, o.logger, attempt, broadcastAt); err != nil { + if err := saveSentAttempt(ctx, tx, timeout, o.logger, attempt, broadcastAt); err != nil { return err } if _, err := tx.Exec(`UPDATE evm.txes SET state = 'confirmed_missing_receipt' WHERE id = $1`, attempt.TxID); err != nil { diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index bb4cef4708..cf014d5e5d 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -126,6 +126,7 @@ chainID = %d const forwarderAdditionalEOACount = 4 func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, ec *ethclient.Client) (*SetupOCR2VRFNodePayload, error) { + ctx := s.ctx() lggr := logger.Sugared(s.Logger.Named("ConfigureOCR2VRFNode")) lggr.Infow( fmt.Sprintf("Configuring Chainlink Node for job type %s %s at commit %s", c.String("job-type"), static.Version, static.Sha), @@ -156,15 +157,13 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e cfg := s.Config ldb := pg.NewLockedDB(cfg.AppID(), cfg.Database(), cfg.Database().Lock(), lggr) - rootCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - if err = ldb.Open(rootCtx); err != nil { + if err = ldb.Open(ctx); err != nil { return nil, s.errorOut(errors.Wrap(err, "opening db")) } defer lggr.ErrorIfFn(ldb.Close, "Error closing db") - app, err := s.AppFactory.NewApplication(rootCtx, s.Config, lggr, ldb.DB()) + app, err := s.AppFactory.NewApplication(ctx, s.Config, lggr, ldb.DB()) if err != nil { return nil, s.errorOut(errors.Wrap(err, "fatal error instantiating application")) } @@ -179,7 +178,7 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e } // Start application. - err = app.Start(rootCtx) + err = app.Start(ctx) if err != nil { return nil, s.errorOut(err) } @@ -243,10 +242,10 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e if c.Bool("isBootstrapper") { // Set up bootstrapper job if bootstrapper. - err = createBootstrapperJob(lggr, c, app) + err = createBootstrapperJob(ctx, lggr, c, app) } else if c.String("job-type") == "DKG" { // Set up DKG job. - err = createDKGJob(lggr, app, dkgTemplateArgs{ + err = createDKGJob(ctx, lggr, app, dkgTemplateArgs{ contractID: c.String("contractID"), ocrKeyBundleID: ocr2.ID(), p2pv2BootstrapperPeerID: peerID, @@ -260,7 +259,7 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e }) } else if c.String("job-type") == "OCR2VRF" { // Set up OCR2VRF job. - err = createOCR2VRFJob(lggr, app, ocr2vrfTemplateArgs{ + err = createOCR2VRFJob(ctx, lggr, app, ocr2vrfTemplateArgs{ dkgTemplateArgs: dkgTemplateArgs{ contractID: c.String("dkg-address"), ocrKeyBundleID: ocr2.ID(), @@ -320,12 +319,13 @@ func (s *Shell) appendForwarders(chainID int64, ks keystore.Eth, sendingKeys []s } func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, lggr logger.Logger, chainID int64, ec *ethclient.Client, owner *bind.TransactOpts, sendingKeysAddresses []common.Address) error { + ctx := s.ctx() // Replace the transmitter ID with the forwarder address. forwarderAddress := c.String("forwarder-address") // We have to set the authorized senders on-chain here, otherwise the job spawner will fail as the // forwarder will not be recognized. - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + ctx, cancel := context.WithTimeout(ctx, 300*time.Second) defer cancel() f, err := authorized_forwarder.NewAuthorizedForwarder(common.HexToAddress(forwarderAddress), ec) if err != nil { @@ -400,7 +400,7 @@ func setupKeystore(cli *Shell, app chainlink.Application, keyStore keystore.Mast return nil } -func createBootstrapperJob(lggr logger.Logger, c *cli.Context, app chainlink.Application) error { +func createBootstrapperJob(ctx context.Context, lggr logger.Logger, c *cli.Context, app chainlink.Application) error { sp := fmt.Sprintf(BootstrapTemplate, c.Int64("chainID"), c.String("contractID"), @@ -418,7 +418,7 @@ func createBootstrapperJob(lggr logger.Logger, c *cli.Context, app chainlink.App } jb.BootstrapSpec = &os - err = app.AddJobV2(context.Background(), &jb) + err = app.AddJobV2(ctx, &jb) if err != nil { return errors.Wrap(err, "failed to add job") } @@ -430,7 +430,7 @@ func createBootstrapperJob(lggr logger.Logger, c *cli.Context, app chainlink.App return nil } -func createDKGJob(lggr logger.Logger, app chainlink.Application, args dkgTemplateArgs) error { +func createDKGJob(ctx context.Context, lggr logger.Logger, app chainlink.Application, args dkgTemplateArgs) error { sp := fmt.Sprintf(DKGTemplate, args.contractID, args.ocrKeyBundleID, @@ -455,7 +455,7 @@ func createDKGJob(lggr logger.Logger, app chainlink.Application, args dkgTemplat } jb.OCR2OracleSpec = &os - err = app.AddJobV2(context.Background(), &jb) + err = app.AddJobV2(ctx, &jb) if err != nil { return errors.Wrap(err, "failed to add job") } @@ -464,7 +464,7 @@ func createDKGJob(lggr logger.Logger, app chainlink.Application, args dkgTemplat return nil } -func createOCR2VRFJob(lggr logger.Logger, app chainlink.Application, args ocr2vrfTemplateArgs) error { +func createOCR2VRFJob(ctx context.Context, lggr logger.Logger, app chainlink.Application, args ocr2vrfTemplateArgs) error { var sendingKeysString = fmt.Sprintf(`"%s"`, args.sendingKeys[0]) for x := 1; x < len(args.sendingKeys); x++ { sendingKeysString = fmt.Sprintf(`%s,"%s"`, sendingKeysString, args.sendingKeys[x]) @@ -498,7 +498,7 @@ func createOCR2VRFJob(lggr logger.Logger, app chainlink.Application, args ocr2vr } jb.OCR2OracleSpec = &os - err = app.AddJobV2(context.Background(), &jb) + err = app.AddJobV2(ctx, &jb) if err != nil { return errors.Wrap(err, "failed to add job") } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 02aa2de0cc..cf3f4f5c07 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -1076,7 +1076,7 @@ type TransactionReceipter interface { func RequireTxSuccessful(t testing.TB, client TransactionReceipter, txHash common.Hash) *types.Receipt { t.Helper() - r, err := client.TransactionReceipt(context.Background(), txHash) + r, err := client.TransactionReceipt(testutils.Context(t), txHash) require.NoError(t, err) require.NotNil(t, r) require.Equal(t, uint64(1), r.Status) diff --git a/core/internal/testutils/pgtest/txdb_test.go b/core/internal/testutils/pgtest/txdb_test.go index c1aeef4b8c..37339bf28b 100644 --- a/core/internal/testutils/pgtest/txdb_test.go +++ b/core/internal/testutils/pgtest/txdb_test.go @@ -8,6 +8,8 @@ import ( "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) func TestTxDBDriver(t *testing.T) { @@ -35,7 +37,7 @@ func TestTxDBDriver(t *testing.T) { ensureValuesPresent(t, db) t.Run("Cancel of tx's context does not trigger rollback of driver's tx", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(testutils.Context(t)) _, err := db.BeginTx(ctx, nil) assert.NoError(t, err) cancel() diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index 5c501a62ac..44205ec7b8 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -1,7 +1,6 @@ package blockhashstore_test import ( - "context" "testing" "github.com/ethereum/go-ethereum/common" @@ -12,6 +11,7 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -66,9 +66,11 @@ func TestStoreRotatesFromAddresses(t *testing.T) { return tx.FromAddress.String() == k2.Address.String() })).Once().Return(txmgr.Tx{}, nil) + ctx := testutils.Context(t) + // store 2 blocks - err = bhs.Store(context.Background(), 1) + err = bhs.Store(ctx, 1) require.NoError(t, err) - err = bhs.Store(context.Background(), 2) + err = bhs.Store(ctx, 2) require.NoError(t, err) } diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index da19a33abc..32a8432f87 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -186,7 +186,7 @@ func (s *service) RegisterManager(ctx context.Context, params RegisterManagerPar } var id int64 - q := s.q.WithOpts(pg.WithParentCtx(context.Background())) + q := s.q.WithOpts(pg.WithParentCtx(ctx)) err = q.Transaction(func(tx pg.Queryer) error { var txerr error diff --git a/core/services/gateway/handlers/handler.dummy_test.go b/core/services/gateway/handlers/handler.dummy_test.go index c2c7a7a12a..c3f23935e6 100644 --- a/core/services/gateway/handlers/handler.dummy_test.go +++ b/core/services/gateway/handlers/handler.dummy_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" @@ -41,15 +42,17 @@ func TestDummyHandler_BasicFlow(t *testing.T) { require.NoError(t, err) connMgr.SetHandler(handler) + ctx := testutils.Context(t) + // User request msg := api.Message{Body: api.MessageBody{MessageId: "1234"}} callbackCh := make(chan handlers.UserCallbackPayload, 1) - require.NoError(t, handler.HandleUserMessage(context.Background(), &msg, callbackCh)) + require.NoError(t, handler.HandleUserMessage(ctx, &msg, callbackCh)) require.Equal(t, 2, connMgr.sendCounter) // Responses from both nodes - require.NoError(t, handler.HandleNodeMessage(context.Background(), &msg, "addr_1")) - require.NoError(t, handler.HandleNodeMessage(context.Background(), &msg, "addr_2")) + require.NoError(t, handler.HandleNodeMessage(ctx, &msg, "addr_1")) + require.NoError(t, handler.HandleNodeMessage(ctx, &msg, "addr_2")) response := <-callbackCh require.Equal(t, "1234", response.Msg.Body.MessageId) } diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 87ee15873d..21035140f5 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -1615,7 +1615,7 @@ func Test_FindJobWithoutSpecErrors(t *testing.T) { jb, err = orm.FindJobWithoutSpecErrors(jobSpec.ID) require.NoError(t, err) - jbWithErrors, err := orm.FindJobTx(jobSpec.ID) + jbWithErrors, err := orm.FindJobTx(testutils.Context(t), jobSpec.ID) require.NoError(t, err) assert.Equal(t, len(jb.JobSpecErrors), 0) diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index 3d858f8132..9e18573f4e 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -247,23 +247,23 @@ func (_m *ORM) FindJobIDsWithBridge(name string) ([]int32, error) { return r0, r1 } -// FindJobTx provides a mock function with given fields: id -func (_m *ORM) FindJobTx(id int32) (job.Job, error) { - ret := _m.Called(id) +// FindJobTx provides a mock function with given fields: ctx, id +func (_m *ORM) FindJobTx(ctx context.Context, id int32) (job.Job, error) { + ret := _m.Called(ctx, id) var r0 job.Job var r1 error - if rf, ok := ret.Get(0).(func(int32) (job.Job, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, int32) (job.Job, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(int32) job.Job); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, int32) job.Job); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(job.Job) } - if rf, ok := ret.Get(1).(func(int32) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, int32) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } diff --git a/core/services/job/orm.go b/core/services/job/orm.go index ba102c6bb8..c5f533c3d2 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -49,7 +49,7 @@ type ORM interface { InsertJob(job *Job, qopts ...pg.QOpt) error CreateJob(jb *Job, qopts ...pg.QOpt) error FindJobs(offset, limit int) ([]Job, int, error) - FindJobTx(id int32) (Job, error) + FindJobTx(ctx context.Context, id int32) (Job, error) FindJob(ctx context.Context, id int32) (Job, error) FindJobByExternalJobID(uuid uuid.UUID, qopts ...pg.QOpt) (Job, error) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils.Big, qopts ...pg.QOpt) (int32, error) @@ -782,8 +782,8 @@ func LoadConfigVarsOCR(evmOcrCfg evmconfig.OCR, ocrCfg OCRConfig, os OCROracleSp return LoadConfigVarsLocalOCR(evmOcrCfg, os, ocrCfg), nil } -func (o *orm) FindJobTx(id int32) (Job, error) { - ctx, cancel := context.WithTimeout(context.Background(), o.cfg.DefaultQueryTimeout()) +func (o *orm) FindJobTx(ctx context.Context, id int32) (Job, error) { + ctx, cancel := context.WithTimeout(ctx, o.cfg.DefaultQueryTimeout()) defer cancel() return o.FindJob(ctx, id) } diff --git a/core/services/keystore/starknet_test.go b/core/services/keystore/starknet_test.go index df9516f871..7fc5718bac 100644 --- a/core/services/keystore/starknet_test.go +++ b/core/services/keystore/starknet_test.go @@ -1,7 +1,6 @@ package keystore_test import ( - "context" "fmt" "math/big" "testing" @@ -13,6 +12,7 @@ import ( "github.com/smartcontractkit/caigo" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -121,13 +121,13 @@ func TestStarknetSigner(t *testing.T) { // on existing sender id t.Run("key exists", func(t *testing.T) { baseKs.On("Get", starknetSenderAddr).Return(starkKey, nil) - signed, err := lk.Sign(context.Background(), starknetSenderAddr, nil) + signed, err := lk.Sign(testutils.Context(t), starknetSenderAddr, nil) require.Nil(t, signed) require.NoError(t, err) }) t.Run("key doesn't exists", func(t *testing.T) { baseKs.On("Get", mock.Anything).Return(starkkey.Key{}, fmt.Errorf("key doesn't exist")) - signed, err := lk.Sign(context.Background(), "not an address", nil) + signed, err := lk.Sign(testutils.Context(t), "not an address", nil) require.Nil(t, signed) require.Error(t, err) }) @@ -140,7 +140,7 @@ func TestStarknetSigner(t *testing.T) { baseKs.On("Get", starknetSenderAddr).Return(starkKey, nil) hash, err := caigo.Curve.PedersenHash([]*big.Int{big.NewInt(42)}) require.NoError(t, err) - r, s, err := adapter.Sign(context.Background(), starknetSenderAddr, hash) + r, s, err := adapter.Sign(testutils.Context(t), starknetSenderAddr, hash) require.NoError(t, err) require.NotNil(t, r) require.NotNil(t, s) diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go index f70e0dd443..c2060a9290 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" _ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -53,7 +54,7 @@ func TestAdapter_Integration(t *testing.T) { http.DefaultClient, ) pra := generic.NewPipelineRunnerAdapter(logger, job.Job{}, pr) - results, err := pra.ExecuteRun(context.Background(), spec, types.Vars{Vars: map[string]interface{}{"val": 1}}, types.Options{}) + results, err := pra.ExecuteRun(testutils.Context(t), spec, types.Vars{Vars: map[string]interface{}{"val": 1}}, types.Options{}) require.NoError(t, err) finalResult := results[0].Value.(decimal.Decimal) @@ -85,7 +86,7 @@ func TestAdapter_AddsDefaultVars(t *testing.T) { jobID, externalJobID, name := int32(100), uuid.New(), null.StringFrom("job-name") pra := generic.NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name}, mpr) - _, err := pra.ExecuteRun(context.Background(), spec, types.Vars{}, types.Options{}) + _, err := pra.ExecuteRun(testutils.Context(t), spec, types.Vars{}, types.Options{}) require.NoError(t, err) gotName, err := mpr.vars.Get("jb.name") @@ -107,8 +108,8 @@ func TestPipelineRunnerAdapter_SetsVarsOnSpec(t *testing.T) { jobID, externalJobID, name, jobType := int32(100), uuid.New(), null.StringFrom("job-name"), job.Type("generic") pra := generic.NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name, Type: jobType}, mpr) - maxDuration := time.Duration(100 * time.Second) - _, err := pra.ExecuteRun(context.Background(), spec, types.Vars{}, types.Options{MaxTaskDuration: maxDuration}) + maxDuration := 100 * time.Second + _, err := pra.ExecuteRun(testutils.Context(t), spec, types.Vars{}, types.Options{MaxTaskDuration: maxDuration}) require.NoError(t, err) assert.Equal(t, jobID, mpr.spec.JobID) diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter_test.go b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go index e137343f2b..24f422bf0c 100644 --- a/core/services/ocr2/plugins/generic/telemetry_adapter_test.go +++ b/core/services/ocr2/plugins/generic/telemetry_adapter_test.go @@ -1,13 +1,14 @@ package generic_test import ( - "context" "testing" - "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/commontypes" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/generic" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" ) @@ -88,7 +89,7 @@ func TestTelemetryAdapter(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := ta.Send(context.Background(), test.networkID, test.chainID, test.contractID, test.telemetryType, test.payload) + err := ta.Send(testutils.Context(t), test.networkID, test.chainID, test.contractID, test.telemetryType, test.payload) if test.errorMsg != "" { assert.ErrorContains(t, err, test.errorMsg) } else { diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index 588f772120..ed59213840 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -138,14 +138,14 @@ func (node *Node) AddJob(t *testing.T, spec string) { c := node.App.GetConfig() job, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &job) + err = node.App.AddJobV2(testutils.Context(t), &job) require.NoError(t, err) } func (node *Node) AddBootstrapJob(t *testing.T, spec string) { job, err := ocrbootstrap.ValidatedBootstrapSpecToml(spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &job) + err = node.App.AddJobV2(testutils.Context(t), &job) require.NoError(t, err) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go index 8662bfd047..340bd92357 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go @@ -1,21 +1,22 @@ package evm import ( - "context" "fmt" "math/big" "testing" "time" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" + commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -54,7 +55,7 @@ func TestGetActiveUpkeepKeys(t *testing.T) { active: actives, } - keys, err := rg.GetActiveUpkeepIDs(context.Background()) + keys, err := rg.GetActiveUpkeepIDs(testutils.Context(t)) if test.ExpectedErr != nil { assert.ErrorIs(t, err, test.ExpectedErr) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go index 004b5fac6c..afb9d4a091 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go @@ -1,16 +1,16 @@ package evm import ( - "context" "fmt" "testing" "time" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -304,7 +304,7 @@ func TestBlockSubscriber_Start(t *testing.T) { bs := NewBlockSubscriber(hb, lp, finality, lggr) bs.blockHistorySize = historySize bs.blockSize = blockSize - err := bs.Start(context.Background()) + err := bs.Start(testutils.Context(t)) assert.Nil(t, err) h97 := evmtypes.Head{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go index 7009cfaa9b..683ba37894 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go @@ -1,7 +1,6 @@ package logprovider import ( - "context" "fmt" "testing" "time" @@ -11,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) func TestBlockTimeResolver_BlockTime(t *testing.T) { @@ -63,8 +63,7 @@ func TestBlockTimeResolver_BlockTime(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) lp := new(lpmocks.LogPoller) resolver := newBlockTimeResolver(lp) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index 0df774d5df..c7db01d878 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -614,10 +614,11 @@ func deployUpkeepCounter( backend *backends.SimulatedBackend, account *bind.TransactOpts, logProvider logprovider.LogEventProvider, -) ([]*big.Int, []common.Address, []*log_upkeep_counter_wrapper.LogUpkeepCounter) { - var ids []*big.Int - var contracts []*log_upkeep_counter_wrapper.LogUpkeepCounter - var contractsAddrs []common.Address +) ( + ids []*big.Int, + contractsAddrs []common.Address, + contracts []*log_upkeep_counter_wrapper.LogUpkeepCounter, +) { for i := 0; i < n; i++ { upkeepAddr, _, upkeepContract, err := log_upkeep_counter_wrapper.DeployLogUpkeepCounter( account, backend, @@ -633,7 +634,7 @@ func deployUpkeepCounter( upkeepID := ocr2keepers.UpkeepIdentifier(append(common.LeftPadBytes([]byte{1}, 16), upkeepAddr[:16]...)) id := upkeepID.BigInt() ids = append(ids, id) - b, err := ethClient.BlockByHash(context.Background(), backend.Commit()) + b, err := ethClient.BlockByHash(ctx, backend.Commit()) require.NoError(t, err) bn := b.Number() err = logProvider.RegisterFilter(ctx, logprovider.FilterOptions{ @@ -643,7 +644,7 @@ func deployUpkeepCounter( }) require.NoError(t, err) } - return ids, contractsAddrs, contracts + return } func newPlainLogTriggerConfig(upkeepAddr common.Address) logprovider.LogTriggerConfig { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go index 03395cb5b5..b28b45fcb4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go @@ -1,19 +1,20 @@ package logprovider import ( - "context" "fmt" "math/big" "testing" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) @@ -103,8 +104,7 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) if tc.mockPoller { lp := new(mocks.LogPoller) @@ -144,8 +144,7 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { } func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) mp := new(mocks.LogPoller) mp.On("RegisterFilter", mock.Anything).Return(nil) mp.On("UnregisterFilter", mock.Anything).Return(nil) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go index a8e33ba23b..c6ebb1c51a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "golang.org/x/time/rate" @@ -174,8 +175,7 @@ func TestLogEventProvider_ScheduleReadJobs(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) readInterval := 10 * time.Millisecond opts := NewOptions(200) @@ -239,8 +239,7 @@ func TestLogEventProvider_ScheduleReadJobs(t *testing.T) { } func TestLogEventProvider_ReadLogs(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) mp := new(mocks.LogPoller) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go index c882a22bc1..77b0eec545 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go @@ -11,11 +11,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -29,8 +30,7 @@ import ( ) func TestLogRecoverer_GetRecoverables(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) lp := &lpmocks.LogPoller{} lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: 100}, nil) r := NewLogRecoverer(logger.TestLogger(t), lp, nil, nil, nil, nil, NewOptions(200)) @@ -213,8 +213,7 @@ func TestLogRecoverer_Clean(t *testing.T) { } func TestLogRecoverer_Recover(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) tests := []struct { name string @@ -1079,7 +1078,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { recoverer.states = tc.stateReader } - b, err := recoverer.GetProposalData(context.Background(), tc.proposal) + b, err := recoverer.GetProposalData(testutils.Context(t), tc.proposal) if tc.expectErr { assert.Error(t, err) assert.Equal(t, tc.wantErr.Error(), err.Error()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go index 194d74febb..0653796f41 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go @@ -2,7 +2,6 @@ package streams import ( "bytes" - "context" "encoding/json" "fmt" "io" @@ -20,11 +19,13 @@ import ( "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/mock" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02" v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03" @@ -257,7 +258,7 @@ func TestStreams_CheckCallback(t *testing.T) { }).Once() s.client = client - state, retryable, _, err := s.checkCallback(context.Background(), tt.values, tt.lookup) + state, retryable, _, err := s.checkCallback(testutils.Context(t), tt.values, tt.lookup) tt.wantErr(t, err, fmt.Sprintf("Error asserion failed: %v", tt.name)) assert.Equal(t, tt.state, state) assert.Equal(t, tt.retryable, retryable) @@ -719,7 +720,7 @@ func TestStreams_StreamsLookup(t *testing.T) { }).Once() } - got := s.Lookup(context.Background(), tt.input) + got := s.Lookup(testutils.Context(t), tt.input) assert.Equal(t, tt.expectedResults, got, tt.name) }) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go index 17ef8515fd..2aecc0df77 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go @@ -2,7 +2,6 @@ package v02 import ( "bytes" - "context" "encoding/json" "errors" "io" @@ -16,6 +15,7 @@ import ( "github.com/patrickmn/go-cache" "github.com/stretchr/testify/mock" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -258,7 +258,7 @@ func TestV02_SingleFeedRequest(t *testing.T) { c.httpClient = hc ch := make(chan mercury.MercuryData, 1) - c.singleFeedRequest(context.Background(), ch, tt.index, tt.lookup) + c.singleFeedRequest(testutils.Context(t), ch, tt.index, tt.lookup) m := <-ch assert.Equal(t, tt.index, m.Index) @@ -450,7 +450,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { } c.httpClient = hc - state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(context.Background(), tt.lookup, tt.pluginRetryKey) + state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(testutils.Context(t), tt.lookup, tt.pluginRetryKey) assert.Equal(t, tt.expectedValues, values) assert.Equal(t, tt.expectedRetryable, retryable) if retryable { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go index bef2cdac58..049448f8f7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go @@ -2,7 +2,6 @@ package v03 import ( "bytes" - "context" "encoding/json" "io" "math/big" @@ -14,6 +13,7 @@ import ( "github.com/patrickmn/go-cache" "github.com/stretchr/testify/mock" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" @@ -162,7 +162,7 @@ func TestV03_DoMercuryRequestV03(t *testing.T) { } c.httpClient = hc - state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(context.Background(), tt.lookup, tt.pluginRetryKey) + state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(testutils.Context(t), tt.lookup, tt.pluginRetryKey) assert.Equal(t, tt.expectedValues, values) assert.Equal(t, tt.expectedRetryable, retryable) @@ -514,7 +514,7 @@ func TestV03_MultiFeedRequest(t *testing.T) { c.httpClient = hc ch := make(chan mercury.MercuryData, 1) - c.multiFeedsRequest(context.Background(), ch, tt.lookup) + c.multiFeedsRequest(testutils.Context(t), ch, tt.lookup) m := <-ch assert.Equal(t, 0, m.Index) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go index e75084ff96..e68e316ae3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go @@ -6,9 +6,11 @@ import ( "testing" "github.com/pkg/errors" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" @@ -191,7 +193,7 @@ func TestNewPayloadBuilder(t *testing.T) { t.Run(tc.name, func(t *testing.T) { lggr, _ := logger.NewLogger() builder := NewPayloadBuilder(tc.activeList, tc.recoverer, lggr) - payloads, err := builder.BuildPayloads(context.Background(), tc.proposals...) + payloads, err := builder.BuildPayloads(testutils.Context(t), tc.proposals...) assert.NoError(t, err) assert.Equal(t, tc.wantPayloads, payloads) }) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go index 2e39892e47..d4e38637d8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go @@ -18,13 +18,15 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -205,7 +207,7 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { e.client = client } - state, retryable := e.verifyCheckBlock(context.Background(), tc.checkBlock, tc.upkeepId, tc.checkHash) + state, retryable := e.verifyCheckBlock(testutils.Context(t), tc.checkBlock, tc.upkeepId, tc.checkHash) assert.Equal(t, tc.state, state) assert.Equal(t, tc.retryable, retryable) }) @@ -350,7 +352,7 @@ func TestRegistry_VerifyLogExists(t *testing.T) { e := &EvmRegistry{ lggr: lggr, bs: bs, - ctx: context.Background(), + ctx: testutils.Context(t), } if tc.makeEthCall { @@ -530,7 +532,7 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { } e.client = client - results, err := e.checkUpkeeps(context.Background(), tc.inputs) + results, err := e.checkUpkeeps(testutils.Context(t), tc.inputs) assert.Equal(t, tc.results, results) assert.Equal(t, tc.err, err) }) @@ -651,7 +653,7 @@ func TestRegistry_SimulatePerformUpkeeps(t *testing.T) { }).Once() e.client = client - results, err := e.simulatePerformUpkeeps(context.Background(), tc.inputs) + results, err := e.simulatePerformUpkeeps(testutils.Context(t), tc.inputs) assert.Equal(t, tc.results, results) assert.Equal(t, tc.err, err) }) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go index 58e95bc423..a33056977a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go @@ -1,29 +1,29 @@ package transmit import ( - "context" "math/big" "runtime" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) func TestTransmitEventProvider_Sanity(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := testutils.Context(t) lp := new(mocks.LogPoller) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go index 8e2e77f7fb..579d875792 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go @@ -357,7 +357,7 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { }) for _, insert := range test.storedValues { - require.NoError(t, store.SetUpkeepState(context.Background(), insert.result, insert.state), "storing states should not produce an error") + require.NoError(t, store.SetUpkeepState(ctx, insert.result, insert.state), "storing states should not produce an error") } tickerCh <- time.Now() @@ -408,7 +408,7 @@ func TestUpkeepStateStore_emptyDB(t *testing.T) { scanner := &mockScanner{} store := NewUpkeepStateStore(orm, lggr, scanner) - states, err := store.SelectByWorkIDs(context.Background(), []string{"0x1", "0x2", "0x3", "0x4"}...) + states, err := store.SelectByWorkIDs(testutils.Context(t), []string{"0x1", "0x2", "0x3", "0x4"}...) assert.NoError(t, err) assert.Equal(t, []ocr2keepers.UpkeepState{ ocr2keepers.UnknownState, @@ -454,6 +454,7 @@ func TestUpkeepStateStore_Upsert(t *testing.T) { } func TestUpkeepStateStore_Service(t *testing.T) { + ctx := testutils.Context(t) orm := &mockORM{ onDelete: func(tm time.Time) { @@ -466,10 +467,10 @@ func TestUpkeepStateStore_Service(t *testing.T) { store.retention = 500 * time.Millisecond store.cleanCadence = 100 * time.Millisecond - assert.NoError(t, store.Start(context.Background()), "no error from starting service") + assert.NoError(t, store.Start(ctx), "no error from starting service") // add a value to set up the test - require.NoError(t, store.SetUpkeepState(context.Background(), ocr2keepers.CheckResult{ + require.NoError(t, store.SetUpkeepState(ctx, ocr2keepers.CheckResult{ Eligible: false, WorkID: "0x2", Trigger: ocr2keepers.Trigger{ @@ -481,7 +482,7 @@ func TestUpkeepStateStore_Service(t *testing.T) { time.Sleep(110 * time.Millisecond) // select from store to ensure values still exist - values, err := store.SelectByWorkIDs(context.Background(), "0x2") + values, err := store.SelectByWorkIDs(ctx, "0x2") require.NoError(t, err, "no error from selecting states") require.Equal(t, []ocr2keepers.UpkeepState{ocr2keepers.Ineligible}, values, "selected values should match expected") @@ -489,7 +490,7 @@ func TestUpkeepStateStore_Service(t *testing.T) { time.Sleep(700 * time.Millisecond) // select from store to ensure cached values were removed - values, err = store.SelectByWorkIDs(context.Background(), "0x2") + values, err = store.SelectByWorkIDs(ctx, "0x2") require.NoError(t, err, "no error from selecting states") require.Equal(t, []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, values, "selected values should match expected") diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 109a644ca0..d2f35a3e37 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -890,6 +890,7 @@ func (c *feedLookupUpkeepController) EnableMercury( MercuryEnabled: true, }) + ctx := testutils.Context(t) for _, id := range c.upkeepIds { if _, err := registry.SetUpkeepPrivilegeConfig(registryOwner, id, adminBytes); err != nil { require.NoError(t, err) @@ -900,7 +901,7 @@ func (c *feedLookupUpkeepController) EnableMercury( callOpts := &bind.CallOpts{ Pending: true, From: registryOwner.From, - Context: context.Background(), + Context: ctx, } bts, err := registry.GetUpkeepPrivilegeConfig(callOpts, id) @@ -989,7 +990,7 @@ func (c *feedLookupUpkeepController) EmitEvents( backend.Commit() // verify event was emitted - block, _ := backend.BlockByHash(context.Background(), backend.Commit()) + block, _ := backend.BlockByHash(ctx, backend.Commit()) t.Logf("block number after emit event: %d", block.NumberU64()) iter, _ := c.protocol.FilterLimitOrderExecuted( diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index a2184d92ae..3eda886796 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -1,7 +1,6 @@ package ocr2keeper_test import ( - "context" "crypto/rand" "encoding/hex" "encoding/json" @@ -171,14 +170,14 @@ func (node *Node) AddJob(t *testing.T, spec string) { c := node.App.GetConfig() jb, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &jb) + err = node.App.AddJobV2(testutils.Context(t), &jb) require.NoError(t, err) } func (node *Node) AddBootstrapJob(t *testing.T, spec string) { jb, err := ocrbootstrap.ValidatedBootstrapSpecToml(spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &jb) + err = node.App.AddJobV2(testutils.Context(t), &jb) require.NoError(t, err) } diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index 57d13a69ec..38d7acf7e9 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -1,7 +1,6 @@ package internal_test import ( - "context" "crypto/rand" "encoding/hex" "errors" @@ -336,6 +335,7 @@ func TestIntegration_OCR2VRF(t *testing.T) { } func runOCR2VRFTest(t *testing.T, useForwarders bool) { + ctx := testutils.Context(t) keyID := randomKeyID(t) uni := setupOCR2VRFContracts(t, 5, keyID, false) @@ -409,7 +409,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { } }() - blockBeforeConfig, err := uni.backend.BlockByNumber(context.Background(), nil) + blockBeforeConfig, err := uni.backend.BlockByNumber(ctx, nil) require.NoError(t, err) t.Log("Setting DKG config before block:", blockBeforeConfig.Number().String()) @@ -447,7 +447,7 @@ fromBlock = %d t.Log("Creating bootstrap job:", bootstrapJobSpec) ocrJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(bootstrapJobSpec) require.NoError(t, err) - err = bootstrapNode.app.AddJobV2(context.Background(), &ocrJob) + err = bootstrapNode.app.AddJobV2(ctx, &ocrJob) require.NoError(t, err) t.Log("Creating OCR2VRF jobs") @@ -499,7 +499,7 @@ linkEthFeedAddress = "%s" t.Log("Creating OCR2VRF job with spec:", jobSpec) ocrJob2, err2 := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), jobSpec) require.NoError(t, err2) - err2 = apps[i].AddJobV2(context.Background(), &ocrJob2) + err2 = apps[i].AddJobV2(ctx, &ocrJob2) require.NoError(t, err2) } diff --git a/core/services/ocr2/plugins/promwrapper/plugin_test.go b/core/services/ocr2/plugins/promwrapper/plugin_test.go index 5c12c18f85..b4de7f027f 100644 --- a/core/services/ocr2/plugins/promwrapper/plugin_test.go +++ b/core/services/ocr2/plugins/promwrapper/plugin_test.go @@ -8,10 +8,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/promwrapper/mocks" ) @@ -194,14 +196,16 @@ func TestPlugin_GetLatencies(t *testing.T) { ).(*promPlugin) require.NotEqual(t, nil, promPlugin) + ctx := testutils.Context(t) + // Run OCR methods. - _, err := promPlugin.Query(context.Background(), reportTimestamp) + _, err := promPlugin.Query(ctx, reportTimestamp) require.NoError(t, err) _, ok := promPlugin.queryEndTimes.Load(reportTimestamp) require.Equal(t, true, ok) time.Sleep(qToOLatency) - _, err = promPlugin.Observation(context.Background(), reportTimestamp, nil) + _, err = promPlugin.Observation(ctx, reportTimestamp, nil) require.NoError(t, err) _, ok = promPlugin.queryEndTimes.Load(reportTimestamp) require.Equal(t, false, ok) @@ -209,7 +213,7 @@ func TestPlugin_GetLatencies(t *testing.T) { require.Equal(t, true, ok) time.Sleep(oToRLatency) - _, _, err = promPlugin.Report(context.Background(), reportTimestamp, nil, nil) + _, _, err = promPlugin.Report(ctx, reportTimestamp, nil, nil) require.NoError(t, err) _, ok = promPlugin.observationEndTimes.Load(reportTimestamp) require.Equal(t, false, ok) @@ -217,7 +221,7 @@ func TestPlugin_GetLatencies(t *testing.T) { require.Equal(t, true, ok) time.Sleep(rToALatency) - _, err = promPlugin.ShouldAcceptFinalizedReport(context.Background(), reportTimestamp, nil) + _, err = promPlugin.ShouldAcceptFinalizedReport(ctx, reportTimestamp, nil) require.NoError(t, err) _, ok = promPlugin.reportEndTimes.Load(reportTimestamp) require.Equal(t, false, ok) @@ -225,7 +229,7 @@ func TestPlugin_GetLatencies(t *testing.T) { require.Equal(t, true, ok) time.Sleep(aToTLatency) - _, err = promPlugin.ShouldTransmitAcceptedReport(context.Background(), reportTimestamp, nil) + _, err = promPlugin.ShouldTransmitAcceptedReport(ctx, reportTimestamp, nil) require.NoError(t, err) _, ok = promPlugin.acceptFinalizedReportEndTimes.Load(reportTimestamp) require.Equal(t, false, ok) diff --git a/core/services/relay/evm/mercury/persistence_manager_test.go b/core/services/relay/evm/mercury/persistence_manager_test.go index dbdb977725..755d64a5a2 100644 --- a/core/services/relay/evm/mercury/persistence_manager_test.go +++ b/core/services/relay/evm/mercury/persistence_manager_test.go @@ -1,18 +1,18 @@ package mercury import ( - "context" "testing" "time" "github.com/cometbft/cometbft/libs/rand" "github.com/jmoiron/sqlx" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -30,7 +30,7 @@ func TestPersistenceManager(t *testing.T) { jobID1 := rand.Int32() jobID2 := jobID1 + 1 - ctx := context.Background() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) @@ -69,7 +69,7 @@ func TestPersistenceManager(t *testing.T) { } func TestPersistenceManagerAsyncDelete(t *testing.T) { - ctx := context.Background() + ctx := testutils.Context(t) jobID := rand.Int32() db := pgtest.NewSqlxDB(t) pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) @@ -120,7 +120,7 @@ func TestPersistenceManagerPrune(t *testing.T) { pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) - ctx := context.Background() + ctx := testutils.Context(t) reports := make([][]byte, 25) for i := 0; i < 25; i++ { diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 635658d786..6eb9f430c6 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -432,7 +432,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { ds.chainReader = evm.NewChainReader(headTracker) obs := relaymercuryv1.Observation{} - err := ds.setLatestBlocks(context.Background(), &obs) + err := ds.setLatestBlocks(testutils.Context(t), &obs) assert.NoError(t, err) assert.Equal(t, h.Number, obs.CurrentBlockNum.Val) @@ -450,7 +450,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { ds.chainReader = evm.NewChainReader(headTracker) obs := relaymercuryv1.Observation{} - err := ds.setLatestBlocks(context.Background(), &obs) + err := ds.setLatestBlocks(testutils.Context(t), &obs) assert.NoError(t, err) assert.Zero(t, obs.CurrentBlockNum.Val) diff --git a/core/services/relay/grpc_provider_server_test.go b/core/services/relay/grpc_provider_server_test.go index fafe20ef12..6aff32f5e3 100644 --- a/core/services/relay/grpc_provider_server_test.go +++ b/core/services/relay/grpc_provider_server_test.go @@ -1,19 +1,19 @@ package relay import ( - "context" "testing" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestProviderServer(t *testing.T) { r := &mockRelayer{} sa := NewServerAdapter(r, mockRelayerExt{}) - mp, _ := sa.NewPluginProvider(context.Background(), types.RelayArgs{ProviderType: string(types.Median)}, types.PluginArgs{}) + mp, _ := sa.NewPluginProvider(testutils.Context(t), types.RelayArgs{ProviderType: string(types.Median)}, types.PluginArgs{}) lggr := logger.TestLogger(t) _, err := NewProviderServer(mp, "unsupported-type", lggr) diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index fc9e273e30..18a7b1b44e 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -1,7 +1,6 @@ package relay import ( - "context" "testing" "github.com/stretchr/testify/assert" @@ -11,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) func TestIdentifier_UnmarshalString(t *testing.T) { @@ -160,9 +160,10 @@ func TestRelayerServerAdapter(t *testing.T) { }, } + ctx := testutils.Context(t) for _, tc := range testCases { pp, err := sa.NewPluginProvider( - context.Background(), + ctx, types.RelayArgs{ProviderType: tc.ProviderType}, types.PluginArgs{}, ) diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index d24fb348b7..31f7ea74c1 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -1,7 +1,6 @@ package telemetry import ( - "context" "fmt" "math/big" "net/url" @@ -190,7 +189,7 @@ func TestNewManager(t *testing.T) { require.Equal(t, "TelemetryManager", m.Name()) - require.Nil(t, m.Start(context.Background())) + require.Nil(t, m.Start(testutils.Context(t))) testutils.WaitForLogMessageCount(t, logObs, "error connecting error while dialing dial tcp", 3) hr := m.HealthReport() diff --git a/core/services/transmission/integration_test.go b/core/services/transmission/integration_test.go index 58521dcdf8..c8c6137cad 100644 --- a/core/services/transmission/integration_test.go +++ b/core/services/transmission/integration_test.go @@ -1,7 +1,6 @@ package transmission_test import ( - "context" "math/big" "testing" @@ -398,7 +397,7 @@ func Test4337WithLinkTokenVRFRequestAndPaymaster(t *testing.T) { ) require.NoError(t, err) backend.Commit() - _, err = bind.WaitMined(context.Background(), backend, tx) + _, err = bind.WaitMined(testutils.Context(t), backend, tx) require.NoError(t, err) // Generate encoded paymaster data to fund the VRF consumer. diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 15121ba306..6880fa1799 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -1,7 +1,6 @@ package v2_test import ( - "context" "encoding/hex" "encoding/json" "fmt" @@ -422,21 +421,22 @@ func deployOldCoordinator( common.Address, *vrf_coordinator_v2.VRFCoordinatorV2, ) { + ctx := testutils.Context(t) bytecode := hexutil.MustDecode("0x60e06040523480156200001157600080fd5b506040516200608c3803806200608c8339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c615e2762000265600039600081816105260152613bd901526000818161061d015261402401526000818161036d01528181611599015281816125960152818161302c0152818161318201526138360152615e276000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106fa578063e82ad7d41461070d578063f2fde38b1461073057600080fd5b8063d2f9f9a7146106d4578063d7ae1d30146106e757600080fd5b8063ad17836114610618578063af198b971461063f578063c3f909d41461066f578063caf70c4a146106c157600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105da578063a47c7696146105e2578063a4c0ed361461060557600080fd5b80638da5cb5b146105a95780639f87fad7146105c757600080fd5b80636f64f03f146105685780637341c10c1461057b57806379ba50971461058e578063823597401461059657600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d1461050e578063689c45171461052157806369bcdb7d1461054857600080fd5b80635fbbc0d21461040057806364d51a2a1461050657600080fd5b8063356dac71146103b457806340d6bb82146103bc5780634cb48a54146103da5780635d3b1d30146103ed57600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610743565b60405161027793929190615964565b60405180910390f35b61029361028e366004615792565b6107bf565b005b6102936102a33660046157ad565b61086b565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd3660046154a3565b610a60565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e30000000000000000000006020820152905161027791906158f1565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610277565b600a54610300565b6103c56101f481565b60405163ffffffff9091168152602001610277565b6102936103e836600461563c565b610c3f565b6103006103fb366004615516565b611036565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361051c36600461545b565b611444565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610300610556366004615779565b60009081526009602052604090205490565b6102936105763660046153a0565b6116ad565b6102936105893660046157ad565b6117f7565b610293611a85565b6102936105a4366004615792565b611b82565b60005473ffffffffffffffffffffffffffffffffffffffff1661038f565b6102936105d53660046157ad565b611d7c565b6102b66121fd565b6105f56105f0366004615792565b6123ed565b6040516102779493929190615b02565b6102936106133660046153d4565b612537565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b61065261064d366004615574565b6127a8565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106cf3660046154bf565b612c6d565b6103c56106e2366004615792565b612c9d565b6102936106f53660046157ad565b612e92565b610293610708366004615385565b612ff3565b61072061071b366004615792565b613257565b6040519015158152602001610277565b61029361073e366004615385565b6134ae565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff169391928391908301828280156107ad57602002820191906000526020600020905b815481526020019060010190808311610799575b50505050509050925092509250909192565b6107c76134bf565b67ffffffffffffffff811660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1661082d576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526003602052604090205461086890829073ffffffffffffffffffffffffffffffffffffffff16613542565b50565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff16806108d4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821614610940576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b600b546601000000000000900460ff1615610987576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff841660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff848116911614610a5a5767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b610a686134bf565b604080518082018252600091610a97919084906002908390839080828437600092019190915250612c6d915050565b60008181526006602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1680610af9576040517f77f5b84c00000000000000000000000000000000000000000000000000000000815260048101839052602401610937565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610be9578260078281548110610b4c57610b4c615dbc565b90600052602060002001541415610bd7576007805460009190610b7190600190615c76565b81548110610b8157610b81615dbc565b906000526020600020015490508060078381548110610ba257610ba2615dbc565b6000918252602090912001556007805480610bbf57610bbf615d8d565b60019003818190600052602060002001600090559055505b80610be181615cba565b915050610b2e565b508073ffffffffffffffffffffffffffffffffffffffff167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610c3291815260200190565b60405180910390a2505050565b610c476134bf565b60c861ffff87161115610c9a576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c86044820152606401610937565b60008213610cd7576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610937565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb2916110269189918991899189918991906159c3565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615611080576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff851660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff166110e6576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a1685529252909120541680611156576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff87166004820152336024820152604401610937565b600b5461ffff9081169086161080611172575060c861ffff8616115b156111c257600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c86044820152606401610937565b600b5463ffffffff620100009091048116908516111561122957600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff8087166004830152620100009092049091166024820152604401610937565b6101f463ffffffff8416111561127b576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f46024820152604401610937565b6000611288826001615bd2565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925060009182916040805160208101849052439181019190915267ffffffffffffffff8c16606082015263ffffffff808b166080830152891660a08201523360c0820152919350915060e001604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff161561148b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff808316911610156114e5576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906115129084906bffffffffffffffffffffffff16615c8d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166115699190615c8d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff1660e01b815260040161162192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561163b57600080fd5b505af115801561164f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167391906154db565b6116a9576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6116b56134bf565b6040805180820182526000916116e4919084906002908390839080828437600092019190915250612c6d915050565b60008181526006602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1615611746576040517f4a0b8fa700000000000000000000000000000000000000000000000000000000815260048101829052602401610937565b600081815260066020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610c32565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff1680611860576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff8216146118c7576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610937565b600b546601000000000000900460ff161561190e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff841660009081526003602052604090206002015460641415611965576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416156119ac57610a5a565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09101610a51565b60015473ffffffffffffffffffffffffffffffffffffffff163314611b06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610937565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611bc9576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16611c2f576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff163314611cd15767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e97500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610937565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560019093018054909316909255835173ffffffffffffffffffffffffffffffffffffffff909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff1680611de5576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821614611e4c576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610937565b600b546601000000000000900460ff1615611e93576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611f2e576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff84166024820152604401610937565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611fa957602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611f7e575b50505050509050600060018251611fc09190615c76565b905060005b825181101561215f578573ffffffffffffffffffffffffffffffffffffffff16838281518110611ff757611ff7615dbc565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16141561214d57600083838151811061202f5761202f615dbc565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020600201838154811061207557612075615dbc565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff8a1681526003909152604090206002018054806120ef576120ef615d8d565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190555061215f565b8061215781615cba565b915050611fc5565b5073ffffffffffffffffffffffffffffffffffffffff8516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff1615612247576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff1690600061226183615cf3565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005541690506000806040519080825280602002602001820160405280156122b4578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c010000000000000000000000009190931602919091179094558451606081018652338152808301848152818701888152958552600384529590932083518154831673ffffffffffffffffffffffffffffffffffffffff918216178255955160018201805490931696169590951790559151805194955090936123a592600285019201906150c5565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff81166000908152600360205260408120548190819060609073ffffffffffffffffffffffffffffffffffffffff1661245a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c010000000000000000000000009096049095169473ffffffffffffffffffffffffffffffffffffffff90921693909291839183018282801561252157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f6575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff161561257e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146125ed576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612627576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061263582840184615792565b67ffffffffffffffff811660009081526003602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1661269e576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff16918691906126d58385615bfe565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff1661272c9190615bfe565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846127939190615bba565b604080519283526020830191909152016121ed565b600b546000906601000000000000900460ff16156127f2576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a9050600080600061280687876139b5565b9250925092506000866060015163ffffffff1667ffffffffffffffff81111561283157612831615deb565b60405190808252806020026020018201604052801561285a578160200160208202803683370190505b50905060005b876060015163ffffffff168110156128ce5760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c8282815181106128b1576128b1615dbc565b6020908102919091010152806128c681615cba565b915050612860565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906129169087908690602401615ab4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b01519192506000916129e49163ffffffff169084613d04565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c92612a68928692900416615bd2565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506000612abf8a600b600001600b9054906101000a900463ffffffff1663ffffffff16612ab985612c9d565b3a613d52565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff80831691161015612b2b576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff1660009081526004909152604081208054839290612b679084906bffffffffffffffffffffffff16615c8d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526006602090815260408083205473ffffffffffffffffffffffffffffffffffffffff1683526008909152812080548594509092612bd091859116615bfe565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4888386604051612c53939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b600081604051602001612c8091906158e3565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612dbb575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612df057508060c0015162ffffff168367ffffffffffffffff1611155b15612dff576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612e3457508060e0015162ffffff168367ffffffffffffffff1611155b15612e43576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612e79575080610100015162ffffff168367ffffffffffffffff1611155b15612e88576060015192915050565b6080015192915050565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff1680612efb576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821614612f62576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610937565b600b546601000000000000900460ff1615612fa9576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612fb284613257565b15612fe9576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a5a8484613542565b612ffb6134bf565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b15801561308357600080fd5b505afa158015613097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130bb91906154fd565b6005549091506801000000000000000090046bffffffffffffffffffffffff168181111561311f576040517fa99da3020000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610937565b818110156132525760006131338284615c76565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b1580156131c857600080fd5b505af11580156131dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061320091906154db565b506040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff811660009081526003602090815260408083208151606081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561330657602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132db575b505050505081525050905060005b8160400151518110156134a45760005b60075481101561349157600061345a6007838154811061334657613346615dbc565b90600052602060002001548560400151858151811061336757613367615dbc565b602002602001015188600260008960400151898151811061338a5761338a615dbc565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808f168352935220541660408051602080820187905273ffffffffffffffffffffffffffffffffffffffff959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b506000818152600960205260409020549091501561347e5750600195945050505050565b508061348981615cba565b915050613324565b508061349c81615cba565b915050613314565b5060009392505050565b6134b66134bf565b61086881613e5a565b60005473ffffffffffffffffffffffffffffffffffffffff163314613540576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610937565b565b600b546601000000000000900460ff1615613589576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660009081526003602090815260408083208151606081018352815473ffffffffffffffffffffffffffffffffffffffff90811682526001830154168185015260028201805484518187028101870186528181529295939486019383018282801561363457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613609575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b83604001515181101561373b5760026000856040015183815181106136bc576136bc615dbc565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558061373381615cba565b915050613695565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590613796600283018261514f565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906138069084906801000000000000000090046bffffffffffffffffffffffff16615c8d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b81526004016138be92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b602060405180830381600087803b1580156138d857600080fd5b505af11580156138ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061391091906154db565b613946576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b60008060006139c78560000151612c6d565b60008181526006602052604090205490935073ffffffffffffffffffffffffffffffffffffffff1680613a29576040517f77f5b84c00000000000000000000000000000000000000000000000000000000815260048101859052602401610937565b6080860151604051613a48918691602001918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301206000818152600990935291205490935080613ac5576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c01519251613b3e968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff908116606085015291909116608083015273ffffffffffffffffffffffffffffffffffffffff1660a082015260c00190565b604051602081830303815290604052805190602001208114613b8c576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff164080613cb05786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e9413d389060240160206040518083038186803b158015613c3057600080fd5b505afa158015613c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c6891906154fd565b905080613cb05786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610937565b6000886080015182604051602001613cd2929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c9050613cf78982613f50565b9450505050509250925092565b60005a611388811015613d1657600080fd5b611388810390508460408204820311613d2e57600080fd5b50823b613d3a57600080fd5b60008083516020850160008789f190505b9392505050565b600080613d5d613fd9565b905060008113613d9c576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101829052602401610937565b6000815a613daa8989615bba565b613db49190615c76565b613dc686670de0b6b3a7640000615c39565b613dd09190615c39565b613dda9190615c25565b90506000613df363ffffffff871664e8d4a51000615c39565b9050613e0b816b033b2e3c9fd0803ce8000000615c76565b821115613e44576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613e4e8183615bba565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116331415613eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610937565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000613f848360000151846020015185604001518660600151868860a001518960c001518a60e001518b61010001516140ed565b60038360200151604051602001613f9c929190615aa0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169163feaf968c9160048083019260a0929190829003018186803b15801561407f57600080fd5b505afa158015614093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140b791906157d7565b5094509092508491505080156140db57506140d28242615c76565b8463ffffffff16105b156140e55750600a545b949350505050565b6140f6896143c4565b61415c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610937565b614165886143c4565b6141cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610937565b6141d4836143c4565b61423a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610937565b614243826143c4565b6142a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610937565b6142b5878a888761451f565b61431b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610937565b60006143278a876146c2565b9050600061433a898b878b868989614726565b9050600061434b838d8d8a866148ae565b9050808a146143b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610937565b505050505050505050505050565b80516000907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f11614451576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610937565b60208201517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f116144de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610937565b60208201517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f9080096145188360005b602002015161490c565b1492915050565b600073ffffffffffffffffffffffffffffffffffffffff821661459e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f626164207769746e6573730000000000000000000000000000000000000000006044820152606401610937565b6020840151600090600116156145b557601c6145b8565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa15801561466f573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff9081169088161495505050505050949350505050565b6146ca61516d565b6146f7600184846040516020016146e3939291906158c2565b604051602081830303815290604052614964565b90505b614703816143c4565b612c6757805160408051602081019290925261471f91016146e3565b90506146fa565b61472e61516d565b825186517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f90819006910614156147c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610937565b6147cc8789886149cd565b614832576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610937565b61483d8486856149cd565b6148a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610937565b613e4e868484614b5a565b6000600286868685876040516020016148cc96959493929190615850565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209695505050505050565b6000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f80848509840990507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f600782089392505050565b61496c61516d565b61497582614c89565b815261498a61498582600061450e565b614cde565b6020820181905260029006600114156149c8576020810180517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0390525b919050565b600082614a36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7a65726f207363616c61720000000000000000000000000000000000000000006044820152606401610937565b83516020850151600090614a4c90600290615d1b565b15614a5857601c614a5b565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614adb573d6000803e3d6000fd5b505050602060405103519050600086604051602001614afa919061583e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012073ffffffffffffffffffffffffffffffffffffffff92831692169190911498975050505050505050565b614b6261516d565b835160208086015185519186015160009384938493614b8393909190614d18565b919450925090507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f858209600114614c17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610937565b60405180604001604052807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f80614c5057614c50615d5e565b87860981526020017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8785099052979650505050505050565b805160208201205b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f81106149c857604080516020808201939093528151808203840181529082019091528051910120614c91565b6000612c67826002614d117ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f6001615bba565b901c614eae565b60008080600180827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f897ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f038808905060007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f038a0890506000614dc083838585614fa2565b9098509050614dd188828e88614ffa565b9098509050614de288828c87614ffa565b90985090506000614df58d878b85614ffa565b9098509050614e0688828686614fa2565b9098509050614e1788828e89614ffa565b9098509050818114614e9a577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f818a0998507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f82890997507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183099650614e9e565b8196505b5050505050509450945094915050565b600080614eb961518b565b6020808252818101819052604082015260608101859052608081018490527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f60a0820152614f056151a9565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa925082614f98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610937565b5195945050505050565b6000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8487097ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8487099097909650945050505050565b600080807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f878509905060007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f87877ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f030990507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183087ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f86890990999098509650505050505050565b82805482825590600052602060002090810192821561513f579160200282015b8281111561513f57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906150e5565b5061514b9291506151c7565b5090565b508054600082559060005260206000209081019061086891906151c7565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b8082111561514b57600081556001016151c8565b803573ffffffffffffffffffffffffffffffffffffffff811681146149c857600080fd5b8060408101831015612c6757600080fd5b600082601f83011261522257600080fd5b6040516040810181811067ffffffffffffffff8211171561524557615245615deb565b806040525080838560408601111561525c57600080fd5b60005b600281101561527e57813583526020928301929091019060010161525f565b509195945050505050565b600060a0828403121561529b57600080fd5b60405160a0810181811067ffffffffffffffff821117156152be576152be615deb565b6040529050806152cd83615353565b81526152db60208401615353565b60208201526152ec6040840161533f565b60408201526152fd6060840161533f565b606082015261530e608084016151dc565b60808201525092915050565b803561ffff811681146149c857600080fd5b803562ffffff811681146149c857600080fd5b803563ffffffff811681146149c857600080fd5b803567ffffffffffffffff811681146149c857600080fd5b805169ffffffffffffffffffff811681146149c857600080fd5b60006020828403121561539757600080fd5b613d4b826151dc565b600080606083850312156153b357600080fd5b6153bc836151dc565b91506153cb8460208501615200565b90509250929050565b600080600080606085870312156153ea57600080fd5b6153f3856151dc565b935060208501359250604085013567ffffffffffffffff8082111561541757600080fd5b818701915087601f83011261542b57600080fd5b81358181111561543a57600080fd5b88602082850101111561544c57600080fd5b95989497505060200194505050565b6000806040838503121561546e57600080fd5b615477836151dc565b915060208301356bffffffffffffffffffffffff8116811461549857600080fd5b809150509250929050565b6000604082840312156154b557600080fd5b613d4b8383615200565b6000604082840312156154d157600080fd5b613d4b8383615211565b6000602082840312156154ed57600080fd5b81518015158114613d4b57600080fd5b60006020828403121561550f57600080fd5b5051919050565b600080600080600060a0868803121561552e57600080fd5b8535945061553e60208701615353565b935061554c6040870161531a565b925061555a6060870161533f565b91506155686080870161533f565b90509295509295909350565b60008082840361024081121561558957600080fd5b6101a08082121561559957600080fd5b6155a1615b90565b91506155ad8686615211565b82526155bc8660408701615211565b60208301526080850135604083015260a0850135606083015260c085013560808301526155eb60e086016151dc565b60a08301526101006155ff87828801615211565b60c0840152615612876101408801615211565b60e0840152610180860135818401525081935061563186828701615289565b925050509250929050565b6000806000806000808688036101c081121561565757600080fd5b6156608861531a565b965061566e6020890161533f565b955061567c6040890161533f565b945061568a6060890161533f565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60830112156156c557600080fd5b6156cd615b90565b91506156db60a08a0161533f565b82526156e960c08a0161533f565b60208301526156fa60e08a0161533f565b604083015261010061570d818b0161533f565b606084015261571d828b0161533f565b608084015261572f6101408b0161532c565b60a08401526157416101608b0161532c565b60c08401526157536101808b0161532c565b60e08401526157656101a08b0161532c565b818401525050809150509295509295509295565b60006020828403121561578b57600080fd5b5035919050565b6000602082840312156157a457600080fd5b613d4b82615353565b600080604083850312156157c057600080fd5b6157c983615353565b91506153cb602084016151dc565b600080600080600060a086880312156157ef57600080fd5b6157f88661536b565b94506020860151935060408601519250606086015191506155686080870161536b565b8060005b6002811015610a5a57815184526020938401939091019060010161581f565b615848818361581b565b604001919050565b868152615860602082018761581b565b61586d606082018661581b565b61587a60a082018561581b565b61588760e082018461581b565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b8381526158d2602082018461581b565b606081019190915260800192915050565b60408101612c67828461581b565b600060208083528351808285015260005b8181101561591e57858101830151858201604001528201615902565b81811115615930576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b818110156159b557845183529383019391830191600101615999565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a0850152615a1760c08501838360201c1663ffffffff169052565b615a2e60e08501838360401c1663ffffffff169052565b615a466101008501838360601c1663ffffffff169052565b615a5e6101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b82815260608101613d4b602083018461581b565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015615af557845183529383019391830191600101615ad9565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff87168185015273ffffffffffffffffffffffffffffffffffffffff80871660408601526080606086015282865180855260a087019150838801945060005b81811015615b80578551841683529484019491840191600101615b62565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff81118282101715615bb457615bb4615deb565b60405290565b60008219821115615bcd57615bcd615d2f565b500190565b600067ffffffffffffffff808316818516808303821115615bf557615bf5615d2f565b01949350505050565b60006bffffffffffffffffffffffff808316818516808303821115615bf557615bf5615d2f565b600082615c3457615c34615d5e565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615c7157615c71615d2f565b500290565b600082821015615c8857615c88615d2f565b500390565b60006bffffffffffffffffffffffff83811690831681811015615cb257615cb2615d2f565b039392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615cec57615cec615d2f565b5060010190565b600067ffffffffffffffff80831681811415615d1157615d11615d2f565b6001019392505050565b600082615d2a57615d2a615d5e565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a") ctorArgs, err := utils.ABIEncode(`[{"type":"address"}, {"type":"address"}, {"type":"address"}]`, linkAddress, bhsAddress, linkEthFeed) require.NoError(t, err) bytecode = append(bytecode, ctorArgs...) - nonce, err := backend.PendingNonceAt(context.Background(), neil.From) + nonce, err := backend.PendingNonceAt(ctx, neil.From) require.NoError(t, err) - gasPrice, err := backend.SuggestGasPrice(context.Background()) + gasPrice, err := backend.SuggestGasPrice(ctx) require.NoError(t, err) unsignedTx := gethtypes.NewContractCreation(nonce, big.NewInt(0), 15e6, gasPrice, bytecode) signedTx, err := neil.Signer(neil.From, unsignedTx) require.NoError(t, err) - err = backend.SendTransaction(context.Background(), signedTx) + err = backend.SendTransaction(ctx, signedTx) require.NoError(t, err, "could not deploy old vrf coordinator to simulated blockchain") backend.Commit() - receipt, err := backend.TransactionReceipt(context.Background(), signedTx.Hash()) + receipt, err := backend.TransactionReceipt(ctx, signedTx.Hash()) require.NoError(t, err) oldRootContractAddress := receipt.ContractAddress require.NotEqual(t, common.HexToAddress("0x0"), oldRootContractAddress, "old vrf coordinator address equal to zero address, deployment failed") diff --git a/core/web/jobs_controller.go b/core/web/jobs_controller.go index 4c8a77d370..0f97e0b53d 100644 --- a/core/web/jobs_controller.go +++ b/core/web/jobs_controller.go @@ -71,7 +71,7 @@ func (jc *JobsController) Show(c *gin.Context) { jobSpec, err = jc.App.JobORM().FindJobByExternalJobID(externalJobID, pg.WithParentCtx(c.Request.Context())) } else if pErr = jobSpec.SetID(c.Param("ID")); pErr == nil { // Find a job by job ID - jobSpec, err = jc.App.JobORM().FindJobTx(jobSpec.ID) + jobSpec, err = jc.App.JobORM().FindJobTx(c, jobSpec.ID) } else { jsonAPIError(c, http.StatusUnprocessableEntity, pErr) return diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index dfef099c17..06c2624d0f 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -15,11 +15,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/slack-go/slack" + "github.com/stretchr/testify/require" + ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" "github.com/smartcontractkit/wasp" - "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" @@ -125,6 +127,7 @@ var ( ) func TestLogTrigger(t *testing.T) { + ctx := tests.Context(t) l := logging.GetTestLogger(t) l.Info().Msg("Starting automation v2.1 log trigger load test") @@ -467,7 +470,7 @@ func TestLogTrigger(t *testing.T) { l.Info().Str("STARTUP_WAIT_TIME", StartupWaitTime.String()).Msg("Waiting for plugin to start") time.Sleep(StartupWaitTime) - startBlock, err := chainClient.LatestBlockNumber(context.Background()) + startBlock, err := chainClient.LatestBlockNumber(ctx) require.NoError(t, err, "Error getting latest block number") p := wasp.NewProfile() @@ -511,7 +514,7 @@ func TestLogTrigger(t *testing.T) { endTime := time.Now() testDuration := endTime.Sub(startTime) l.Info().Str("Duration", testDuration.String()).Msg("Test Duration") - endBlock, err := chainClient.LatestBlockNumber(context.Background()) + endBlock, err := chainClient.LatestBlockNumber(ctx) require.NoError(t, err, "Error getting latest block number") l.Info().Uint64("Starting Block", startBlock).Uint64("Ending Block", endBlock).Msg("Test Block Range") @@ -544,7 +547,8 @@ func TestLogTrigger(t *testing.T) { Topics: [][]common.Hash{{consumerABI.Events["PerformingUpkeep"].ID}}, } ) - ctx, cancel := context.WithTimeout(context.Background(), timeout) + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, timeout) logsInBatch, err := chainClient.FilterLogs(ctx, filterQuery) cancel() if err != nil { diff --git a/plugins/medianpoc/data_source_test.go b/plugins/medianpoc/data_source_test.go index 5848705b7b..9977daef3d 100644 --- a/plugins/medianpoc/data_source_test.go +++ b/plugins/medianpoc/data_source_test.go @@ -11,6 +11,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -60,7 +61,7 @@ func TestDataSource(t *testing.T) { spec: spec, lggr: lggr, } - res, err := ds.Observe(context.Background(), ocrtypes.ReportTimestamp{}) + res, err := ds.Observe(tests.Context(t), ocrtypes.ReportTimestamp{}) require.NoError(t, err) assert.Equal(t, big.NewInt(expect), res) assert.Equal(t, spec, pr.spec) @@ -86,7 +87,7 @@ func TestDataSource_ResultErrors(t *testing.T) { spec: spec, lggr: lggr, } - _, err := ds.Observe(context.Background(), ocrtypes.ReportTimestamp{}) + _, err := ds.Observe(tests.Context(t), ocrtypes.ReportTimestamp{}) assert.ErrorContains(t, err, "something went wrong") } @@ -111,6 +112,6 @@ func TestDataSource_ResultNotAnInt(t *testing.T) { spec: spec, lggr: lggr, } - _, err := ds.Observe(context.Background(), ocrtypes.ReportTimestamp{}) + _, err := ds.Observe(tests.Context(t), ocrtypes.ReportTimestamp{}) assert.ErrorContains(t, err, "cannot convert observation to decimal") } diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go index 569fcb464b..bc6af7ae5d 100644 --- a/plugins/medianpoc/plugin_test.go +++ b/plugins/medianpoc/plugin_test.go @@ -1,7 +1,6 @@ package medianpoc import ( - "context" "fmt" "testing" @@ -13,6 +12,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -89,7 +89,7 @@ func TestNewPlugin(t *testing.T) { prov := provider{} f, err := p.newFactory( - context.Background(), + tests.Context(t), config, prov, pr, From 5e3d68e39b10917c0ed87c9097063ea9017ca56b Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Tue, 21 Nov 2023 08:52:30 +0100 Subject: [PATCH 181/327] Style update shared contracts (#11343) * style update shared ocr2 * fix comment syntax in shared * add struct packing comments and make natspec --------- Co-authored-by: Austin Born --- .../automation/v2_0/KeeperRegistry2_0.sol | 2 +- .../automation/v2_1/KeeperRegistry2_1.sol | 2 +- .../src/v0.8/shared/access/ConfirmedOwner.sol | 6 +- .../access/ConfirmedOwnerWithProposal.sol | 31 ++-- .../access/SimpleReadAccessController.sol | 26 ++-- .../access/SimpleWriteAccessController.sol | 40 ++---- .../src/v0.8/shared/ocr2/OCR2Abstract.sol | 100 ++++++------- contracts/src/v0.8/shared/ocr2/OCR2Base.sol | 136 ++++++++---------- 8 files changed, 136 insertions(+), 207 deletions(-) diff --git a/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol b/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol index 7db02e72e7..bd3c78e45a 100644 --- a/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol +++ b/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol @@ -281,7 +281,7 @@ contract KeeperRegistry2_0 is uint64 offchainConfigVersion, bytes memory offchainConfig ) external override onlyOwner { - if (signers.length > maxNumOracles) revert TooManyOracles(); + if (signers.length > MAX_NUM_ORACLES) revert TooManyOracles(); if (f == 0) revert IncorrectNumberOfFaultyOracles(); if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners(); diff --git a/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol b/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol index 2f96df6d57..7c88f12f5a 100644 --- a/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol +++ b/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol @@ -250,7 +250,7 @@ contract KeeperRegistry2_1 is KeeperRegistryBase2_1, OCR2Abstract, Chainable, IE uint64 offchainConfigVersion, bytes memory offchainConfig ) public onlyOwner { - if (signers.length > maxNumOracles) revert TooManyOracles(); + if (signers.length > MAX_NUM_ORACLES) revert TooManyOracles(); if (f == 0) revert IncorrectNumberOfFaultyOracles(); if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners(); diff --git a/contracts/src/v0.8/shared/access/ConfirmedOwner.sol b/contracts/src/v0.8/shared/access/ConfirmedOwner.sol index a25d92ffd6..5b0c1593cc 100644 --- a/contracts/src/v0.8/shared/access/ConfirmedOwner.sol +++ b/contracts/src/v0.8/shared/access/ConfirmedOwner.sol @@ -3,10 +3,8 @@ pragma solidity ^0.8.0; import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol"; -/** - * @title The ConfirmedOwner contract - * @notice A contract with helpers for basic contract ownership. - */ +/// @title The ConfirmedOwner contract +/// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwner is ConfirmedOwnerWithProposal { constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {} } diff --git a/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol b/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol index a6757c3886..7b68418754 100644 --- a/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol +++ b/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol @@ -3,10 +3,8 @@ pragma solidity ^0.8.0; import {IOwnable} from "../interfaces/IOwnable.sol"; -/** - * @title The ConfirmedOwner contract - * @notice A contract with helpers for basic contract ownership. - */ +/// @title The ConfirmedOwner contract +/// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwnerWithProposal is IOwnable { address private s_owner; address private s_pendingOwner; @@ -24,17 +22,12 @@ contract ConfirmedOwnerWithProposal is IOwnable { } } - /** - * @notice Allows an owner to begin transferring ownership to a new address, - * pending. - */ + /// @notice Allows an owner to begin transferring ownership to a new address. function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } - /** - * @notice Allows an ownership transfer to be completed by the recipient. - */ + /// @notice Allows an ownership transfer to be completed by the recipient. function acceptOwnership() external override { // solhint-disable-next-line custom-errors require(msg.sender == s_pendingOwner, "Must be proposed owner"); @@ -46,16 +39,12 @@ contract ConfirmedOwnerWithProposal is IOwnable { emit OwnershipTransferred(oldOwner, msg.sender); } - /** - * @notice Get the current owner - */ + /// @notice Get the current owner function owner() public view override returns (address) { return s_owner; } - /** - * @notice validate, transfer ownership, and emit relevant events - */ + /// @notice validate, transfer ownership, and emit relevant events function _transferOwnership(address to) private { // solhint-disable-next-line custom-errors require(to != msg.sender, "Cannot transfer to self"); @@ -65,17 +54,13 @@ contract ConfirmedOwnerWithProposal is IOwnable { emit OwnershipTransferRequested(s_owner, to); } - /** - * @notice validate access - */ + /// @notice validate access function _validateOwnership() internal view { // solhint-disable-next-line custom-errors require(msg.sender == s_owner, "Only callable by owner"); } - /** - * @notice Reverts if called by anyone other than the contract owner. - */ + /// @notice Reverts if called by anyone other than the contract owner. modifier onlyOwner() { _validateOwnership(); _; diff --git a/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol b/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol index b36fa4e4b6..f4ea905bf9 100644 --- a/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol +++ b/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol @@ -3,22 +3,18 @@ pragma solidity ^0.8.0; import {SimpleWriteAccessController} from "./SimpleWriteAccessController.sol"; -/** - * @title SimpleReadAccessController - * @notice Gives access to: - * - any externally owned account (note that off-chain actors can always read - * any contract storage regardless of on-chain access control measures, so this - * does not weaken the access control while improving usability) - * - accounts explicitly added to an access list - * @dev SimpleReadAccessController is not suitable for access controlling writes - * since it grants any externally owned account access! See - * SimpleWriteAccessController for that. - */ +/// @title SimpleReadAccessController +/// @notice Gives access to: +/// - any externally owned account (note that off-chain actors can always read +/// any contract storage regardless of on-chain access control measures, so this +/// does not weaken the access control while improving usability) +/// - accounts explicitly added to an access list +/// @dev SimpleReadAccessController is not suitable for access controlling writes +/// since it grants any externally owned account access! See +/// SimpleWriteAccessController for that. contract SimpleReadAccessController is SimpleWriteAccessController { - /** - * @notice Returns the access of an address - * @param _user The address to query - */ + /// @notice Returns the access of an address + /// @param _user The address to query function hasAccess(address _user, bytes memory _calldata) public view virtual override returns (bool) { // solhint-disable-next-line avoid-tx-origin return super.hasAccess(_user, _calldata) || _user == tx.origin; diff --git a/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol b/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol index 117d2e77dd..b431331bc8 100644 --- a/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol +++ b/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol @@ -4,13 +4,9 @@ pragma solidity ^0.8.0; import {ConfirmedOwner} from "./ConfirmedOwner.sol"; import {AccessControllerInterface} from "../interfaces/AccessControllerInterface.sol"; -/** - * @title SimpleWriteAccessController - * @notice Gives access to accounts explicitly added to an access list by the - * controller's owner. - * @dev does not make any special permissions for externally, see - * SimpleReadAccessController for that. - */ +/// @title SimpleWriteAccessController +/// @notice Gives access to accounts explicitly added to an access list by the controller's owner. +/// @dev does not make any special permissions for externally, see SimpleReadAccessController for that. contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwner { bool public checkEnabled; mapping(address => bool) internal s_accessList; @@ -24,18 +20,14 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne checkEnabled = true; } - /** - * @notice Returns the access of an address - * @param _user The address to query - */ + /// @notice Returns the access of an address + /// @param _user The address to query function hasAccess(address _user, bytes memory) public view virtual override returns (bool) { return s_accessList[_user] || !checkEnabled; } - /** - * @notice Adds an address to the access list - * @param _user The address to add - */ + /// @notice Adds an address to the access list + /// @param _user The address to add function addAccess(address _user) external onlyOwner { if (!s_accessList[_user]) { s_accessList[_user] = true; @@ -44,10 +36,8 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne } } - /** - * @notice Removes an address from the access list - * @param _user The address to remove - */ + /// @notice Removes an address from the access list + /// @param _user The address to remove function removeAccess(address _user) external onlyOwner { if (s_accessList[_user]) { s_accessList[_user] = false; @@ -56,9 +46,7 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne } } - /** - * @notice makes the access check enforced - */ + /// @notice makes the access check enforced function enableAccessCheck() external onlyOwner { if (!checkEnabled) { checkEnabled = true; @@ -67,9 +55,7 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne } } - /** - * @notice makes the access check unenforced - */ + /// @notice makes the access check unenforced function disableAccessCheck() external onlyOwner { if (checkEnabled) { checkEnabled = false; @@ -78,9 +64,7 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne } } - /** - * @dev reverts if the caller does not have access - */ + /// @dev reverts if the caller does not have access modifier checkAccess() { // solhint-disable-next-line custom-errors require(hasAccess(msg.sender, msg.data), "No access"); diff --git a/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol b/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol index 1f19d0de54..cd3f197113 100644 --- a/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol +++ b/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol @@ -4,26 +4,20 @@ pragma solidity ^0.8.0; import {ITypeAndVersion} from "../interfaces/ITypeAndVersion.sol"; abstract contract OCR2Abstract is ITypeAndVersion { - // Maximum number of oracles the offchain reporting protocol is designed for - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint256 internal constant maxNumOracles = 31; - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint256 private constant prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint256 private constant prefix = 0x0001 << (256 - 16); // 0x000100..00 + uint256 internal constant MAX_NUM_ORACLES = 31; + uint256 private constant PREFIX_MASK = type(uint256).max << (256 - 16); // 0xFFFF00..00 + uint256 private constant PREFIX = 0x0001 << (256 - 16); // 0x000100..00 - /** - * @notice triggers a new run of the offchain reporting protocol - * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis - * @param configDigest configDigest of this configuration - * @param configCount ordinal number of this config setting among all config settings over the life of this contract - * @param signers ith element is address ith oracle uses to sign a report - * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method - * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly - * @param onchainConfig serialized configuration used by the contract (and possibly oracles) - * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter - * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract - */ + /// @notice triggers a new run of the offchain reporting protocol + /// @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis + /// @param configDigest configDigest of this configuration + /// @param configCount ordinal number of this config setting among all config settings over the life of this contract + /// @param signers ith element is address ith oracle uses to sign a report + /// @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method + /// @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly + /// @param onchainConfig serialized configuration used by the contract (and possibly oracles) + /// @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter + /// @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract event ConfigSet( uint32 previousConfigBlockNumber, bytes32 configDigest, @@ -36,15 +30,13 @@ abstract contract OCR2Abstract is ITypeAndVersion { bytes offchainConfig ); - /** - * @notice sets offchain reporting protocol configuration incl. participating oracles - * @param signers addresses with which oracles sign the reports - * @param transmitters addresses oracles use to transmit the reports - * @param f number of faulty oracles the system can tolerate - * @param onchainConfig serialized configuration used by the contract (and possibly oracles) - * @param offchainConfigVersion version number for offchainEncoding schema - * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract - */ + /// @notice sets offchain reporting protocol configuration incl. participating oracles + /// @param signers addresses with which oracles sign the reports + /// @param transmitters addresses oracles use to transmit the reports + /// @param f number of faulty oracles the system can tolerate + /// @param onchainConfig serialized configuration used by the contract (and possibly oracles) + /// @param offchainConfigVersion version number for offchainEncoding schema + /// @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract function setConfig( address[] memory signers, address[] memory transmitters, @@ -54,12 +46,10 @@ abstract contract OCR2Abstract is ITypeAndVersion { bytes memory offchainConfig ) external virtual; - /** - * @notice information about current offchain reporting protocol configuration - * @return configCount ordinal number of current config, out of all configs applied to this contract so far - * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) - */ + /// @notice information about current offchain reporting protocol configuration + /// @return configCount ordinal number of current config, out of all configs applied to this contract so far + /// @return blockNumber block at which this config was set + /// @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) function latestConfigDetails() external view @@ -92,40 +82,34 @@ abstract contract OCR2Abstract is ITypeAndVersion { ) ) ); - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); + return bytes32((PREFIX & PREFIX_MASK) | (h & ~PREFIX_MASK)); } - /** - * @notice optionally emited to indicate the latest configDigest and epoch for - which a report was successfully transmited. Alternatively, the contract may - use latestConfigDigestAndEpoch with scanLogs set to false. - */ + /// @notice optionally emitted to indicate the latest configDigest and epoch for + /// which a report was successfully transmitted. Alternatively, the contract may + /// use latestConfigDigestAndEpoch with scanLogs set to false. event Transmitted(bytes32 configDigest, uint32 epoch); - /** - * @notice optionally returns the latest configDigest and epoch for which a - report was successfully transmitted. Alternatively, the contract may return - scanLogs set to true and use Transmitted events to provide this information - to offchain watchers. - * @return scanLogs indicates whether to rely on the configDigest and epoch - returned or whether to scan logs for the Transmitted event instead. - * @return configDigest - * @return epoch - */ + /// @notice optionally returns the latest configDigest and epoch for which a + /// report was successfully transmitted. Alternatively, the contract may return + /// scanLogs set to true and use Transmitted events to provide this information + /// to offchain watchers. + /// @return scanLogs indicates whether to rely on the configDigest and epoch + /// returned or whether to scan logs for the Transmitted event instead. + /// @return configDigest + /// @return epoch function latestConfigDigestAndEpoch() external view virtual returns (bool scanLogs, bytes32 configDigest, uint32 epoch); - /** - * @notice transmit is called to post a new report to the contract - * @param reportContext [0]: ConfigDigest, [1]: 27 byte padding, 4-byte epoch and 1-byte round, [2]: ExtraHash - * @param report serialized report, which the signatures are signing. - * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries - * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries - * @param rawVs ith element is the the V component of the ith signature - */ + /// @notice transmit is called to post a new report to the contract + /// @param reportContext [0]: ConfigDigest, [1]: 27 byte padding, 4-byte epoch and 1-byte round, [2]: ExtraHash + /// @param report serialized report, which the signatures are signing. + /// @param rs ith element is the R components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries + /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries + /// @param rawVs ith element is the the V component of the ith signature function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly diff --git a/contracts/src/v0.8/shared/ocr2/OCR2Base.sol b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol index 0f0317602d..baedac7710 100644 --- a/contracts/src/v0.8/shared/ocr2/OCR2Base.sol +++ b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol @@ -1,47 +1,45 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {ConfirmedOwner} from "../access/ConfirmedOwner.sol"; +import {OwnerIsCreator} from "../access/OwnerIsCreator.sol"; import {OCR2Abstract} from "./OCR2Abstract.sol"; -/** - * @notice Onchain verification of reports from the offchain reporting protocol - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - * @dev For details on its operation, see the offchain reporting protocol design - * doc, which refers to this contract as simply the "contract". - * @dev This contract is meant to aid rapid development of new applications based on OCR2. - * However, for actual production contracts, it is expected that most of the logic of this contract - * will be folded directly into the application contract. Inheritance prevents us from doing lots - * of juicy storage layout optimizations, leading to a substantial increase in gas cost. - */ +/// @notice Onchain verification of reports from the offchain reporting protocol +/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. +/// @dev For details on its operation, see the offchain reporting protocol design +/// doc, which refers to this contract as simply the "contract". +/// @dev This contract is meant to aid rapid development of new applications based on OCR2. +/// However, for actual production contracts, it is expected that most of the logic of this contract +/// will be folded directly into the application contract. Inheritance prevents us from doing lots +/// of juicy storage layout optimizations, leading to a substantial increase in gas cost. // solhint-disable custom-errors -abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { +abstract contract OCR2Base is OwnerIsCreator, OCR2Abstract { error ReportInvalid(); bool internal immutable i_uniqueReports; - constructor(bool uniqueReports) ConfirmedOwner(msg.sender) { + constructor(bool uniqueReports) OwnerIsCreator() { i_uniqueReports = uniqueReports; } - // Storing these fields used on the hot path in a ConfigInfo variable reduces the - // retrieval of all of them to a single SLOAD. If any further fields are - // added, make sure that storage of the struct still takes at most 32 bytes. + /// @dev Storing these fields used on the hot path in a ConfigInfo variable reduces + /// the retrieval of all of them to a single SLOAD. If any further fields are + /// added, make sure that storage of the struct still takes at most 32 bytes. struct ConfigInfo { bytes32 latestConfigDigest; - uint8 f; // TODO: could be optimized by squeezing into one slot - uint8 n; + uint8 f; // ───╮ + uint8 n; // ───╯ } ConfigInfo internal s_configInfo; - // incremented each time a new config is posted. This count is incorporated - // into the config digest, to prevent replay attacks. + /// @dev Incremented each time a new config is posted. This count is incorporated + /// into the config digest, to prevent replay attacks. uint32 internal s_configCount; - uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems - // to extract config from logs. + /// @dev Makes it easier for offchain systems to extract config from logs. + uint32 internal s_latestConfigBlockNumber; - // Used for s_oracles[a].role, where a is an address, to track the purpose - // of the address, or to indicate that the address is unset. + /// @dev Used for s_oracles[a].role, where a is an address, to track the purpose + /// of the address, or to indicate that the address is unset. enum Role { // No oracle role has been set for address a Unset, @@ -55,30 +53,26 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { } struct Oracle { - uint8 index; // Index of oracle in s_signers/s_transmitters - Role role; // Role of the address which mapped to this struct + uint8 index; // ───╮ Index of oracle in s_signers/s_transmitters + Role role; // ─────╯ Role of the address which mapped to this struct } mapping(address => Oracle) /* signer OR transmitter address */ internal s_oracles; - // s_signers contains the signing address of each oracle + /// @notice Contains the signing address of each oracle address[] internal s_signers; - // s_transmitters contains the transmission address of each oracle, - // i.e. the address the oracle actually sends transactions to the contract from + /// @notice Contains the transmission address of each oracle, + /// i.e. the address the oracle actually sends transactions to the contract from address[] internal s_transmitters; - /* - * Config logic - */ - - // Reverts transaction if config args are invalid + /// @dev Reverts transaction if config args are invalid modifier checkConfigValid( uint256 _numSigners, uint256 _numTransmitters, uint256 _f ) { - require(_numSigners <= maxNumOracles, "too many signers"); + require(_numSigners <= MAX_NUM_ORACLES, "too many signers"); require(_f > 0, "f must be positive"); require(_numSigners == _numTransmitters, "oracle addresses out of registration"); require(_numSigners > 3 * _f, "faulty-oracle f too high"); @@ -105,15 +99,13 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { return (true, bytes32(0), uint32(0)); } - /** - * @notice sets offchain reporting protocol configuration incl. participating oracles - * @param _signers addresses with which oracles sign the reports - * @param _transmitters addresses oracles use to transmit the reports - * @param _f number of faulty oracles the system can tolerate - * @param _onchainConfig encoded on-chain contract configuration - * @param _offchainConfigVersion version number for offchainEncoding schema - * @param _offchainConfig encoded off-chain oracle configuration - */ + /// @notice sets offchain reporting protocol configuration incl. participating oracles + /// @param _signers addresses with which oracles sign the reports + /// @param _transmitters addresses oracles use to transmit the reports + /// @param _f number of faulty oracles the system can tolerate + /// @param _onchainConfig encoded on-chain contract configuration + /// @param _offchainConfigVersion version number for offchainEncoding schema + /// @param _offchainConfig encoded off-chain oracle configuration function setConfig( address[] memory _signers, address[] memory _transmitters, @@ -187,12 +179,10 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { _afterSetConfig(args.f, args.onchainConfig); } - /** - * @notice information about current offchain reporting protocol configuration - * @return configCount ordinal number of current config, out of all configs applied to this contract so far - * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see configDigestFromConfigData) - */ + /// @notice information about current offchain reporting protocol configuration + /// @return configCount ordinal number of current config, out of all configs applied to this contract so far + /// @return blockNumber block at which this config was set + /// @return configDigest domain-separation tag for current config (see configDigestFromConfigData) function latestConfigDetails() external view @@ -202,10 +192,8 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); } - /** - * @return list of addresses permitted to transmit reports to this contract - * @dev The list will match the order used to specify the transmitter during setConfig - */ + /// @return list of addresses permitted to transmit reports to this contract + /// @dev The list will match the order used to specify the transmitter during setConfig function transmitters() external view returns (address[] memory) { return s_transmitters; } @@ -214,31 +202,27 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { function _afterSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; - /** - * @dev hook to allow additional validation of the report by the extending contract - * @param configDigest separation tag for current config (see configDigestFromConfigData) - * @param epochAndRound 27 byte padding, 4-byte epoch and 1-byte round - * @param report serialized report - */ + /// @dev hook to allow additional validation of the report by the extending contract + /// @param configDigest separation tag for current config (see configDigestFromConfigData) + /// @param epochAndRound 27 byte padding, 4-byte epoch and 1-byte round + /// @param report serialized report function _validateReport( bytes32 configDigest, uint40 epochAndRound, bytes memory report ) internal virtual returns (bool); - /** - * @dev hook called after the report has been fully validated - * for the extending contract to handle additional logic, such as oracle payment - * @param initialGas the amount of gas before validation - * @param transmitter the address of the account that submitted the report - * @param signers the addresses of all signing accounts - * @param report serialized report - */ + /// @dev hook called after the report has been fully validated + /// for the extending contract to handle additional logic, such as oracle payment + /// @param initialGas the amount of gas before validation + /// @param transmitter the address of the account that submitted the report + /// @param signers the addresses of all signing accounts + /// @param report serialized report function _report( uint256 initialGas, address transmitter, uint8 signerCount, - address[maxNumOracles] memory signers, + address[MAX_NUM_ORACLES] memory signers, bytes calldata report ) internal virtual; @@ -274,13 +258,11 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { require(msg.data.length == expected, "calldata length mismatch"); } - /** - * @notice transmit is called to post a new report to the contract - * @param report serialized report, which the signatures are signing. - * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries - * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries - * @param rawVs ith element is the the V component of the ith signature - */ + /// @notice transmit is called to post a new report to the contract + /// @param report serialized report, which the signatures are signing. + /// @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries + /// @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries + /// @param rawVs ith element is the the V component of the ith signature function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly @@ -328,7 +310,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { ); } - address[maxNumOracles] memory signed; + address[MAX_NUM_ORACLES] memory signed; uint8 signerCount = 0; { From 0c8c1cd000131018dff070279b4e1a18b3562d53 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 21 Nov 2023 06:05:58 -0600 Subject: [PATCH 182/327] switch from ocr2vrf to chainlink-vrf (#11346) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- core/scripts/ocr2vrf/main.go | 3 ++- core/scripts/ocr2vrf/util.go | 9 +++++---- core/scripts/ocr2vrf/verify.go | 5 +++-- core/services/keystore/keys/dkgencryptkey/key.go | 3 ++- core/services/ocr2/delegate.go | 15 +++++++-------- core/services/ocr2/plugins/dkg/key_consumer.go | 2 +- .../services/ocr2/plugins/dkg/onchain_contract.go | 6 +++--- core/services/ocr2/plugins/dkg/persistence/db.go | 6 ++++-- .../ocr2/plugins/dkg/persistence/db_test.go | 4 ++-- core/services/ocr2/plugins/dkg/plugin.go | 6 ++++-- .../plugins/ocr2vrf/coordinator/coordinator.go | 10 ++++++---- .../ocr2vrf/coordinator/coordinator_test.go | 7 ++++--- .../ocr2vrf/internal/ocr2vrf_integration_test.go | 9 +++++---- .../juelsfeecoin/link_eth_price_provider.go | 3 ++- .../reasonable_gas_price_provider.go | 2 +- .../ocr2vrf/reportserializer/report_serializer.go | 4 ++-- .../reportserializer/report_serializer_test.go | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- .../ocr2vrf_actions/ocr2vrf_config_helpers.go | 9 +++++---- .../ocr2vrf_constants/ocr2vrf_constants.go | 2 +- .../actions/ocr2vrf_actions/ocr2vrf_models.go | 2 +- .../actions/ocr2vrf_actions/ocr2vrf_steps.go | 2 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 27 files changed, 72 insertions(+), 59 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 1d8ba40b82..09c76dd195 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -21,10 +21,10 @@ require ( github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 + github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 - github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.4 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 13496adb7a..b1a0870114 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1470,6 +1470,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= +github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= +github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= @@ -1478,8 +1480,6 @@ github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XO github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/core/scripts/ocr2vrf/main.go b/core/scripts/ocr2vrf/main.go index c698fcd730..532fbd3f22 100644 --- a/core/scripts/ocr2vrf/main.go +++ b/core/scripts/ocr2vrf/main.go @@ -12,7 +12,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/shopspring/decimal" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" diff --git a/core/scripts/ocr2vrf/util.go b/core/scripts/ocr2vrf/util.go index a2ff55524d..4ec78472e5 100644 --- a/core/scripts/ocr2vrf/util.go +++ b/core/scripts/ocr2vrf/util.go @@ -21,10 +21,11 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2vrf/altbn_128" - "github.com/smartcontractkit/ocr2vrf/dkg" - "github.com/smartcontractkit/ocr2vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + "github.com/smartcontractkit/chainlink-vrf/dkg" + "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" diff --git a/core/scripts/ocr2vrf/verify.go b/core/scripts/ocr2vrf/verify.go index 4b91148a8c..7d7fb94496 100644 --- a/core/scripts/ocr2vrf/verify.go +++ b/core/scripts/ocr2vrf/verify.go @@ -9,12 +9,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" bn256 "github.com/ethereum/go-ethereum/crypto/bn256/google" - "github.com/smartcontractkit/ocr2vrf/altbn_128" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/group/mod" "go.dedis.ch/kyber/v3/pairing" + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" + helpers "github.com/smartcontractkit/chainlink/core/scripts/common" dkgContract "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" diff --git a/core/services/keystore/keys/dkgencryptkey/key.go b/core/services/keystore/keys/dkgencryptkey/key.go index 461dc4e2ad..e94f2a6bdf 100644 --- a/core/services/keystore/keys/dkgencryptkey/key.go +++ b/core/services/keystore/keys/dkgencryptkey/key.go @@ -6,9 +6,10 @@ import ( "math/big" "github.com/pkg/errors" - "github.com/smartcontractkit/ocr2vrf/altbn_128" "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/pairing" + + "github.com/smartcontractkit/chainlink-vrf/altbn_128" ) var suite pairing.Suite = &altbn_128.PairingSuite{} diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 4b5932cd70..2f2a903339 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -8,13 +8,11 @@ import ( "log" "time" - "google.golang.org/grpc" - "gopkg.in/guregu/null.v4" - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - "github.com/jmoiron/sqlx" + "github.com/pkg/errors" + "google.golang.org/grpc" + "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" @@ -26,9 +24,10 @@ import ( ocr2keepers20runner "github.com/smartcontractkit/ocr2keepers/pkg/v2/runner" ocr2keepers21config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" ocr2keepers21 "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" - "github.com/smartcontractkit/ocr2vrf/altbn_128" - dkgpkg "github.com/smartcontractkit/ocr2vrf/dkg" - "github.com/smartcontractkit/ocr2vrf/ocr2vrf" + + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + dkgpkg "github.com/smartcontractkit/chainlink-vrf/dkg" + "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/loop" diff --git a/core/services/ocr2/plugins/dkg/key_consumer.go b/core/services/ocr2/plugins/dkg/key_consumer.go index 99115af70d..23ca7e795b 100644 --- a/core/services/ocr2/plugins/dkg/key_consumer.go +++ b/core/services/ocr2/plugins/dkg/key_consumer.go @@ -4,7 +4,7 @@ import ( "encoding/hex" "fmt" - "github.com/smartcontractkit/ocr2vrf/dkg" + "github.com/smartcontractkit/chainlink-vrf/dkg" ) type dummyKeyConsumer struct{} diff --git a/core/services/ocr2/plugins/dkg/onchain_contract.go b/core/services/ocr2/plugins/dkg/onchain_contract.go index 5f23f33c5d..c6ea84de23 100644 --- a/core/services/ocr2/plugins/dkg/onchain_contract.go +++ b/core/services/ocr2/plugins/dkg/onchain_contract.go @@ -8,9 +8,9 @@ import ( "github.com/pkg/errors" "go.dedis.ch/kyber/v3/sign/anon" - "github.com/smartcontractkit/ocr2vrf/dkg" - dkgwrapper "github.com/smartcontractkit/ocr2vrf/gethwrappers/dkg" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + "github.com/smartcontractkit/chainlink-vrf/dkg" + dkgwrapper "github.com/smartcontractkit/chainlink-vrf/gethwrappers/dkg" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" ) diff --git a/core/services/ocr2/plugins/dkg/persistence/db.go b/core/services/ocr2/plugins/dkg/persistence/db.go index c020a68cbe..304422ace2 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db.go +++ b/core/services/ocr2/plugins/dkg/persistence/db.go @@ -13,9 +13,11 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - "github.com/smartcontractkit/ocr2vrf/types/hash" + + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" + "github.com/smartcontractkit/chainlink-vrf/types/hash" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" diff --git a/core/services/ocr2/plugins/dkg/persistence/db_test.go b/core/services/ocr2/plugins/dkg/persistence/db_test.go index d4a4546fb9..b4fa000cb9 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db_test.go +++ b/core/services/ocr2/plugins/dkg/persistence/db_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - "github.com/smartcontractkit/ocr2vrf/types/hash" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" + "github.com/smartcontractkit/chainlink-vrf/types/hash" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" diff --git a/core/services/ocr2/plugins/dkg/plugin.go b/core/services/ocr2/plugins/dkg/plugin.go index 92910ff7bb..0310122655 100644 --- a/core/services/ocr2/plugins/dkg/plugin.go +++ b/core/services/ocr2/plugins/dkg/plugin.go @@ -8,10 +8,12 @@ import ( "github.com/jmoiron/sqlx" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/ocr2vrf/altbn_128" - "github.com/smartcontractkit/ocr2vrf/dkg" + + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + "github.com/smartcontractkit/chainlink-vrf/dkg" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go index 1b58a01732..6353894153 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go @@ -17,13 +17,15 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/libocr/commontypes" - ocr2Types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2vrf/dkg" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" "golang.org/x/exp/maps" "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/libocr/commontypes" + ocr2Types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-vrf/dkg" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index f634ee0c01..418e4356c6 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -21,9 +21,10 @@ import ( "github.com/smartcontractkit/libocr/commontypes" ocr2Types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2vrf/dkg" - "github.com/smartcontractkit/ocr2vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + + "github.com/smartcontractkit/chainlink-vrf/dkg" + "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink-common/pkg/types" diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index 38d7acf7e9..e93824283b 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -25,10 +25,11 @@ import ( "github.com/smartcontractkit/libocr/commontypes" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2vrf/altbn_128" - ocr2dkg "github.com/smartcontractkit/ocr2vrf/dkg" - "github.com/smartcontractkit/ocr2vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + ocr2dkg "github.com/smartcontractkit/chainlink-vrf/dkg" + "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" diff --git a/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider.go b/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider.go index d2330d87e4..2601ae1466 100644 --- a/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider.go +++ b/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider.go @@ -10,7 +10,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/ocr2vrf/types" + + "github.com/smartcontractkit/chainlink-vrf/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" diff --git a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go index c0e969a287..880b808433 100644 --- a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go +++ b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go @@ -4,7 +4,7 @@ import ( "math/big" "time" - "github.com/smartcontractkit/ocr2vrf/types" + "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" diff --git a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer.go b/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer.go index 19b625ff6d..e4112b5543 100644 --- a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer.go +++ b/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer.go @@ -4,8 +4,8 @@ import ( "github.com/pkg/errors" "go.dedis.ch/kyber/v3" - "github.com/smartcontractkit/ocr2vrf/ocr2vrf" - types "github.com/smartcontractkit/ocr2vrf/types" + "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" + "github.com/smartcontractkit/chainlink-vrf/types" ) type reportSerializer struct { diff --git a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer_test.go b/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer_test.go index dcfd627ac9..32704a55b0 100644 --- a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer_test.go @@ -7,8 +7,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/ocr2vrf/altbn_128" - "github.com/smartcontractkit/ocr2vrf/types" + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/reportserializer" ) diff --git a/go.mod b/go.mod index 784d3ff78e..c13f476bf2 100644 --- a/go.mod +++ b/go.mod @@ -69,9 +69,9 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 + github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 - github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 diff --git a/go.sum b/go.sum index fb09e792d6..4f465dc8f9 100644 --- a/go.sum +++ b/go.sum @@ -1471,6 +1471,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= +github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= +github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= @@ -1479,8 +1481,6 @@ github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XO github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go index e424aaa11b..58e394cb79 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go @@ -18,10 +18,11 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2vrf/altbn_128" - "github.com/smartcontractkit/ocr2vrf/dkg" - "github.com/smartcontractkit/ocr2vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + "github.com/smartcontractkit/chainlink-vrf/dkg" + "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants/ocr2vrf_constants.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants/ocr2vrf_constants.go index 7caceec941..7f17be3fd8 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants/ocr2vrf_constants.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants/ocr2vrf_constants.go @@ -4,7 +4,7 @@ import ( "math/big" "time" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" ) var ( diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_models.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_models.go index 8f218ab5c7..0858020338 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_models.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_models.go @@ -1,6 +1,6 @@ package ocr2vrf_actions -import ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" +import ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" type DKGKeyConfig struct { DKGEncryptionPublicKey string diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go index 2904162f49..c3add16ec6 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" - ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 3b1a5423df..9e99f39b44 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,10 +24,10 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e github.com/smartcontractkit/chainlink-testing-framework v1.19.1 + github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/ocr2keepers v0.7.28 - github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.3.0 github.com/spf13/cobra v1.6.1 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 427ad1421c..87cceb9b99 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2377,6 +2377,8 @@ github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.202311 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= github.com/smartcontractkit/chainlink-testing-framework v1.19.1 h1:MdGM5jIrBi858Cv7qzfl1Qon93YW8InohAlDQqFoIb4= github.com/smartcontractkit/chainlink-testing-framework v1.19.1/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= +github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= @@ -2385,8 +2387,6 @@ github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XO github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= From 98ac92b9e57c8ba386999fe739ca09f0b4886ffb Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 21 Nov 2023 08:08:17 -0600 Subject: [PATCH 183/327] core/services/job: close test peer wrappers (#11349) --- core/services/job/orm_test.go | 2 +- core/services/job/runner_integration_test.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/services/job/orm_test.go b/core/services/job/orm_test.go index 41d02dba06..2e19669417 100644 --- a/core/services/job/orm_test.go +++ b/core/services/job/orm_test.go @@ -23,7 +23,7 @@ import ( func NewTestORM(t *testing.T, db *sqlx.DB, pipelineORM pipeline.ORM, bridgeORM bridges.ORM, keyStore keystore.Master, cfg pg.QConfig) job.ORM { o := job.NewORM(db, pipelineORM, bridgeORM, keyStore, logger.TestLogger(t), cfg) - t.Cleanup(func() { o.Close() }) + t.Cleanup(func() { assert.NoError(t, o.Close()) }) return o } diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index deb4bff6b0..eb6af3607f 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -450,6 +450,7 @@ answer1 [type=median index=0]; assert.NoError(t, err) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) require.NoError(t, pw.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, pw.Close()) }) sd := ocr.NewDelegate( db, jobORM, @@ -484,6 +485,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) require.NoError(t, pw.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, pw.Close()) }) sd := ocr.NewDelegate( db, jobORM, @@ -512,6 +514,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) require.NoError(t, pw.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, pw.Close()) }) sd := ocr.NewDelegate( db, jobORM, @@ -566,6 +569,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) require.NoError(t, pw.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, pw.Close()) }) sd := ocr.NewDelegate( db, jobORM, @@ -610,7 +614,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) require.NoError(t, pw.Start(testutils.Context(t))) - + t.Cleanup(func() { assert.NoError(t, pw.Close()) }) sd := ocr.NewDelegate( db, jobORM, From 530225a1918556cbee65bbe2e5aff6bfaeb05abd Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Tue, 21 Nov 2023 10:06:19 -0500 Subject: [PATCH 184/327] [TT-524] [TT-729] More Products and Reporting for Live Tests (#11327) * More Specific Tests * Disable sepolia * Specify automation test * Don't give up * Reduce default funding * Fix test name * Messing with jq * Change all OCR config * Fiddling with jq more * Little better reports * I think I got the formatting now * Ensure prerequisites * Debugging * Remove Sepolia * Formatting * Remove if (we'll make it pretty later) * Strip out quotes * Fix GHA label * Remove debug * More accurate colors * Ease the debugging process * More debugging * Fix needs check * Check fail * Check fail better * Learned some tricks * Successes * Extra paren * Fix emojis * Purty * Remove debug and mocks * Cleanup --- .github/workflows/live-testnet-tests.yml | 205 ++++++++++++++--------- integration-tests/soak/ocr_test.go | 11 +- 2 files changed, 128 insertions(+), 88 deletions(-) diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index 7eb1669b35..f174e8847b 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -11,12 +11,16 @@ env: CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com MOD_CACHE_VERSION: 2 + CHAINLINK_NODE_FUNDING: .1 CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} TEST_LOG_LEVEL: debug EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} + SEPOLIA_URLS: ${{ secrets.QA_SEPOLIA_URLS }} + SEPOLIA_HTTP_URLS: ${{ secrets.QA_SEPOLIA_HTTP_URLS }} + OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} @@ -55,61 +59,66 @@ jobs: AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - sepolia-smoke-tests: - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink] - env: - SELECTED_NETWORKS: SEPOLIA - strategy: - fail-fast: false - matrix: - product: [ocr, automation] - name: Sepolia ${{ matrix.product }} Tests - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/${{ matrix.product }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt - test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./integration-tests/smoke/logs - publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results - token: ${{ secrets.GITHUB_TOKEN }} - go_mod_path: ./integration-tests/go.mod - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Sepolia ${{ matrix.product }} Tests - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - continue-on-error: true + # TODO: Re-enable when we have secrets properly configured + # sepolia-smoke-tests: + # environment: integration + # permissions: + # checks: write + # pull-requests: write + # id-token: write + # contents: read + # needs: [build-chainlink] + # env: + # SELECTED_NETWORKS: SEPOLIA + # strategy: + # max-parallel: 1 + # fail-fast: false + # matrix: + # include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + # - product: OCR + # test: TestOCRBasic + # - product: Automation + # test: TestAutomationBasic/registry_2_0 + # name: Sepolia ${{ matrix.product }} Tests + # runs-on: ubuntu-latest + # steps: + # - name: Checkout the repo + # uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + # with: + # ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + # - name: Run Tests + # uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + # env: + # PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + # PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia + # PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + # with: + # test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt + # test_download_vendor_packages_command: cd ./integration-tests && go mod download + # cl_repo: ${{ env.CHAINLINK_IMAGE }} + # cl_image_tag: ${{ github.sha }} + # aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + # dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + # dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + # artifacts_location: ./integration-tests/smoke/logs + # publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results + # token: ${{ secrets.GITHUB_TOKEN }} + # go_mod_path: ./integration-tests/go.mod + # cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + # cache_restore_only: "true" + # QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + # QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + # QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + # - name: Collect Metrics + # if: always() + # id: collect-gha-metrics + # uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + # with: + # basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + # hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + # this-job-name: Sepolia ${{ matrix.product }} Tests + # test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + # continue-on-error: true optimism-goerli-smoke-tests: environment: integration @@ -123,8 +132,13 @@ jobs: SELECTED_NETWORKS: OPTIMISM_GOERLI strategy: fail-fast: false + max-parallel: 1 matrix: - product: [ocr, automation] + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation + test: TestAutomationBasic/registry_2_0 name: Optimism Goerli ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: @@ -139,7 +153,7 @@ jobs: PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-goerli PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/${{ matrix.product }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} @@ -177,9 +191,14 @@ jobs: env: SELECTED_NETWORKS: ARBITRUM_GOERLI strategy: + max-parallel: 1 fail-fast: false matrix: - product: [ocr, automation] + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation + test: TestAutomationBasic/registry_2_0 name: Arbitrum Goerli ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: @@ -194,7 +213,7 @@ jobs: PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-arbitrum-goerli PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 ./smoke/${{ matrix.product }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} @@ -233,10 +252,10 @@ jobs: id-token: write contents: read runs-on: ubuntu-latest - needs: [sepolia-smoke-tests, optimism-goerli-smoke-tests, arbitrum-goerli-smoke-tests] + needs: [optimism-goerli-smoke-tests, arbitrum-goerli-smoke-tests] steps: - name: Debug Result - run: echo ${{needs.*.result}} + run: echo ${{ join(needs.*.result, ',') }} - name: Main Slack Notification uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 id: slack @@ -246,13 +265,13 @@ jobs: { "attachments": [ { - "color": "${{ needs.*.result == 'success' && '#2E7D32' || '#C62828' }}", + "color": "${{ contains(join(needs.*.result, ','), 'failure') && '#C62828' || '#2E7D32' }}", "blocks": [ { "type": "header", "text": { "type": "plain_text", - "text": "Live Smoke Test Results ${{ needs.*.result == 'success' && ':white_check_mark:' || ':x:'}}", + "text": "Live Smoke Test Results ${{ contains(join(needs.*.result, ','), 'failure') && ':x:' || ':white_check_mark:'}}", "emoji": true } }, @@ -274,7 +293,7 @@ jobs: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} testnet-smoke-tests-results: - name: Post Test Results + name: Post Test Results for ${{ matrix.network }} if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} environment: integration permissions: @@ -287,23 +306,53 @@ jobs: strategy: fail-fast: false matrix: - testnet: [sepolia, optimism-goerli, arbitrum-goerli] + network: [Optimism Goerli, Arbitrum Goerli] steps: - name: Get Results id: test-results run: | + # I feel like there's some clever, fully jq way to do this, but I ain't got the motivation to figure it out echo "Querying test results" - echo "status=$(curl \ + PARSED_RESULTS=$(curl \ -H "Authorization: Bearer ${{ github.token }}" \ 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ - | jq -r '.jobs[] | select(.name == "Live Testnet Smoke Tests ${{ matrix.testnet }}-smoke-tests").steps[] | select(.name == "Run Tests").conclusion')" >> $GITHUB_OUTPUT + | jq -r --arg pattern "${{ matrix.network }} (?\\w+) Tests" '.jobs[] + | select(.name | test($pattern)) as $job + | $job.steps[] + | select(.name == "Run Tests") + | { conclusion: (if .conclusion == "success" then ":white_check_mark:" else ":x:" end), product: ("*" + ($job.name | capture($pattern).product) + "*") }') - echo "status=$(curl \ - -H "Authorization: Bearer ${{ github.token }}" \ - 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ - | jq -r '.jobs[] | select(.name == "Live Testnet Smoke Tests ${{ matrix.testnet }}-smoke-tests"").steps[] | select(.name == "Run Tests").conclusion')" - echo "thread_ts=${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}" + echo "Parsed Results:" + echo $PARSED_RESULTS + + ALL_SUCCESS=true + for row in $(echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")'); do + success=false + break + done + + echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT + + FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] + | { + conclusion: .conclusion, + product: .product + } + ] + | map("{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"\(.product): \(.conclusion)\"}}") + | join(",")') + + echo "Formatted Results:" + echo $FORMATTED_RESULTS + + # Cleans out backslashes and quotes from jq + CLEAN_RESULTS=$(echo "$FORMATTED_RESULTS" | sed 's/\\\"/"/g' | sed 's/^"//;s/"$//') + + echo "Clean Results" + echo $CLEAN_RESULTS + + echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT - name: Test Details uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 @@ -314,26 +363,20 @@ jobs: "thread_ts": "${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}", "attachments": [ { - "color": "${{ steps.test-results.outputs.status == 'success' && '#2E7D32' || '#C62828' }}", + "color": "${{ steps.test-results.outputs.all_success && '#2E7D32' || '#C62828' }}", "blocks": [ { "type": "header", "text": { "type": "plain_text", - "text": "${{ matrix.testnet }} Smoke Test Results ${{ steps.test-results.outputs.status == 'success' && ':white_check_mark:' || ':x:'}}", + "text": "${{ matrix.network }} ${{ steps.test-results.outputs.all_success && ':white_check_mark:' || ':x: Notifying <@U01Q4N37KFG>'}}", "emoji": true } }, { "type": "divider" }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "OCR ${{ steps.test-results.outputs.status == 'success' && ':white_check_mark:' || ':x:'}}" - } - } + ${{ steps.test-results.outputs.results }} ] } ] diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index 4f42ff803e..4d7971d678 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -1,16 +1,13 @@ package soak import ( - "fmt" "testing" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -19,10 +16,10 @@ func TestOCRSoak(t *testing.T) { // Use this variable to pass in any custom EVM specific TOML values to your Chainlink nodes customNetworkTOML := `` // Uncomment below for debugging TOML issues on the node - network := networks.MustGetSelectedNetworksFromEnv()[0] - fmt.Println("Using Chainlink TOML\n---------------------") - fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customNetworkTOML, network)) - fmt.Println("---------------------") + // network := networks.MustGetSelectedNetworksFromEnv()[0] + // fmt.Println("Using Chainlink TOML\n---------------------") + // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customNetworkTOML, network)) + // fmt.Println("---------------------") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, false) require.NoError(t, err, "Error creating soak test") From f34b581ae7bee8529635e9526eecd4bdc30b26e5 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 21 Nov 2023 10:13:03 -0600 Subject: [PATCH 185/327] switch from ocr2keepers to chainlink-automation (#11333) --- contracts/src/v0.8/automation/v2_1/LICENSE | 2 +- core/scripts/chaincli/handler/debug.go | 3 ++- .../chaincli/handler/keeper_deployer.go | 7 ++++--- core/scripts/chaincli/handler/ocr2_config.go | 4 +++- core/scripts/chaincli/handler/report.go | 4 +++- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- core/services/ocr2/delegate.go | 16 +++++++-------- .../plugins/ocr2keeper/custom_telemetry.go | 2 +- .../ocr2/plugins/ocr2keeper/evm20/abi.go | 3 ++- .../ocr2/plugins/ocr2keeper/evm20/abi_test.go | 3 ++- .../ocr2/plugins/ocr2keeper/evm20/encoder.go | 5 +++-- .../plugins/ocr2keeper/evm20/encoder_test.go | 3 ++- .../ocr2/plugins/ocr2keeper/evm20/head.go | 2 +- .../plugins/ocr2keeper/evm20/log_provider.go | 6 +++--- .../ocr2/plugins/ocr2keeper/evm20/registry.go | 2 +- .../plugins/ocr2keeper/evm20/registry_test.go | 2 +- .../plugins/ocr2keeper/evm21/active_list.go | 2 +- .../ocr2keeper/evm21/active_list_test.go | 3 ++- .../evm21/autotelemetry21/custom_telemetry.go | 2 +- .../ocr2keeper/evm21/block_subscriber.go | 2 +- .../ocr2keeper/evm21/block_subscriber_test.go | 2 +- .../ocr2keeper/evm21/core/interfaces.go | 2 +- .../evm21/core/mocks/upkeep_state_reader.go | 2 +- .../plugins/ocr2keeper/evm21/core/payload.go | 3 ++- .../ocr2keeper/evm21/core/payload_test.go | 4 ++-- .../plugins/ocr2keeper/evm21/core/testutil.go | 3 ++- .../plugins/ocr2keeper/evm21/core/trigger.go | 2 +- .../ocr2keeper/evm21/core/trigger_test.go | 3 ++- .../plugins/ocr2keeper/evm21/core/type.go | 2 +- .../ocr2keeper/evm21/core/type_test.go | 4 ++-- .../ocr2keeper/evm21/encoding/encoder.go | 2 +- .../ocr2keeper/evm21/encoding/encoder_test.go | 3 ++- .../ocr2keeper/evm21/encoding/interface.go | 2 +- .../ocr2keeper/evm21/encoding/packer.go | 2 +- .../ocr2keeper/evm21/encoding/packer_test.go | 3 ++- .../ocr2/plugins/ocr2keeper/evm21/keyring.go | 3 ++- .../plugins/ocr2keeper/evm21/keyring_test.go | 6 ++++-- .../ocr2keeper/evm21/logprovider/buffer.go | 4 ++-- .../evm21/logprovider/buffer_test.go | 3 ++- .../evm21/logprovider/integration_test.go | 5 ++--- .../ocr2keeper/evm21/logprovider/provider.go | 2 +- .../logprovider/provider_life_cycle_test.go | 2 +- .../evm21/logprovider/provider_test.go | 5 ++--- .../ocr2keeper/evm21/logprovider/recoverer.go | 4 ++-- .../evm21/logprovider/recoverer_test.go | 2 +- .../evm21/mercury/streams/streams.go | 2 +- .../evm21/mercury/streams/streams_test.go | 13 +++++------- .../ocr2keeper/evm21/payload_builder.go | 2 +- .../ocr2keeper/evm21/payload_builder_test.go | 2 +- .../ocr2/plugins/ocr2keeper/evm21/registry.go | 2 +- .../evm21/registry_check_pipeline.go | 3 ++- .../evm21/registry_check_pipeline_test.go | 20 ++++++++----------- .../plugins/ocr2keeper/evm21/registry_test.go | 3 ++- .../ocr2/plugins/ocr2keeper/evm21/services.go | 6 ++++-- .../ocr2keeper/evm21/transmit/cache.go | 2 +- .../ocr2keeper/evm21/transmit/cache_test.go | 3 ++- .../ocr2keeper/evm21/transmit/encoding.go | 2 +- .../evm21/transmit/encoding_test.go | 3 ++- .../evm21/transmit/event_provider.go | 2 +- .../evm21/transmit/event_provider_test.go | 2 +- .../ocr2keeper/evm21/upkeep_provider.go | 2 +- .../ocr2keeper/evm21/upkeep_provider_test.go | 3 ++- .../ocr2keeper/evm21/upkeepstate/store.go | 2 +- .../evm21/upkeepstate/store_test.go | 2 +- .../plugins/ocr2keeper/integration_21_test.go | 6 +++--- .../plugins/ocr2keeper/integration_test.go | 11 +++++----- core/services/ocr2/plugins/ocr2keeper/util.go | 12 +++++------ core/services/relay/evm/ocr2keeper.go | 6 +++--- core/services/telemetry/manager_test.go | 5 +++-- go.mod | 2 +- go.sum | 4 ++-- .../actions/automation_ocr_helpers.go | 5 +++-- .../actions/automation_ocr_helpers_local.go | 8 +++++--- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- .../automationv2_1/automationv2_1_test.go | 13 +++++++----- 77 files changed, 166 insertions(+), 142 deletions(-) diff --git a/contracts/src/v0.8/automation/v2_1/LICENSE b/contracts/src/v0.8/automation/v2_1/LICENSE index 03ba03d779..7d09d647f5 100644 --- a/contracts/src/v0.8/automation/v2_1/LICENSE +++ b/contracts/src/v0.8/automation/v2_1/LICENSE @@ -12,7 +12,7 @@ Licensor: SmartContract Chainlink Limited SEZC Licensed Work: Automation v2.1 The Licensed Work is (c) 2023 SmartContract Chainlink Limited SEZC -Additional Use Grant: Any uses listed and defined at https://github.com/smartcontractkit/ocr2keepers/tree/main/pkg/v3/Automation_v2.1_Grants.md +Additional Use Grant: Any uses listed and defined at https://github.com/smartcontractkit/chainlink-automation/tree/main/pkg/v3/Automation_v2.1_Grants.md Change Date: September 12, 2027 diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 8f65b1f881..4938907669 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -19,7 +19,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" diff --git a/core/scripts/chaincli/handler/keeper_deployer.go b/core/scripts/chaincli/handler/keeper_deployer.go index eae8c68d33..7c53275342 100644 --- a/core/scripts/chaincli/handler/keeper_deployer.go +++ b/core/scripts/chaincli/handler/keeper_deployer.go @@ -13,14 +13,15 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/umbracle/ethgo/abi" + ocr2config "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - ocr3confighelper "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/umbracle/ethgo/abi" "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" - offchain20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" + offchain20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" diff --git a/core/scripts/chaincli/handler/ocr2_config.go b/core/scripts/chaincli/handler/ocr2_config.go index 7cf2536405..21b2ad414a 100644 --- a/core/scripts/chaincli/handler/ocr2_config.go +++ b/core/scripts/chaincli/handler/ocr2_config.go @@ -11,8 +11,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/olekukonko/tablewriter" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" + + ocr2keepers20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" ) diff --git a/core/scripts/chaincli/handler/report.go b/core/scripts/chaincli/handler/report.go index 90f2be9654..8381bbc137 100644 --- a/core/scripts/chaincli/handler/report.go +++ b/core/scripts/chaincli/handler/report.go @@ -16,8 +16,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" "github.com/olekukonko/tablewriter" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers20 "github.com/smartcontractkit/ocr2keepers/pkg/v2" + + ocr2keepers20 "github.com/smartcontractkit/chainlink-automation/pkg/v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm20" diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 09c76dd195..0d78e15d59 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -21,10 +21,10 @@ require ( github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 + github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 - github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.4 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index b1a0870114..3dd48f7445 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1462,6 +1462,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= +github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= +github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= @@ -1478,8 +1480,6 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= -github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 2f2a903339..7a90e3b07e 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -17,13 +17,14 @@ import ( "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers20 "github.com/smartcontractkit/ocr2keepers/pkg/v2" - ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" - ocr2keepers20coordinator "github.com/smartcontractkit/ocr2keepers/pkg/v2/coordinator" - ocr2keepers20polling "github.com/smartcontractkit/ocr2keepers/pkg/v2/observer/polling" - ocr2keepers20runner "github.com/smartcontractkit/ocr2keepers/pkg/v2/runner" - ocr2keepers21config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" - ocr2keepers21 "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" + + ocr2keepers20 "github.com/smartcontractkit/chainlink-automation/pkg/v2" + ocr2keepers20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" + ocr2keepers20coordinator "github.com/smartcontractkit/chainlink-automation/pkg/v2/coordinator" + ocr2keepers20polling "github.com/smartcontractkit/chainlink-automation/pkg/v2/observer/polling" + ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" + ocr2keepers21config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" + ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" "github.com/smartcontractkit/chainlink-vrf/altbn_128" dkgpkg "github.com/smartcontractkit/chainlink-vrf/dkg" @@ -66,7 +67,6 @@ import ( functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" evmmercury "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" - evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" diff --git a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go index 6d52c0e8d2..fd43747f52 100644 --- a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/abi.go b/core/services/ocr2/plugins/ocr2keeper/evm20/abi.go index 4c0beee8fd..98aeed6678 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/abi.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/abi.go @@ -8,7 +8,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" ) type evmRegistryPackerV2_0 struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/abi_test.go b/core/services/ocr2/plugins/ocr2keeper/evm20/abi_test.go index 7efc3feb1f..c63c0d00f3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/abi_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/abi_test.go @@ -8,9 +8,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" "github.com/stretchr/testify/assert" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evm20/encoder.go index 3984cb7496..aa98fd44ce 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/encoder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/encoder.go @@ -6,8 +6,9 @@ import ( "reflect" "github.com/ethereum/go-ethereum/accounts/abi" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" - "github.com/smartcontractkit/ocr2keepers/pkg/v2/encoding" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" + "github.com/smartcontractkit/chainlink-automation/pkg/v2/encoding" ) type EVMAutomationEncoder20 struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm20/encoder_test.go index 74be6b46ee..7621289265 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/encoder_test.go @@ -5,8 +5,9 @@ import ( "testing" "github.com/pkg/errors" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" "github.com/stretchr/testify/assert" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" ) func TestEVMAutomationEncoder20(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/head.go b/core/services/ocr2/plugins/ocr2keeper/evm20/head.go index 1023bff5dd..7898317355 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/head.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/head.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go index d8941d505b..7ab641d2bf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go @@ -11,9 +11,9 @@ import ( "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" - pluginutils "github.com/smartcontractkit/ocr2keepers/pkg/util" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" - "github.com/smartcontractkit/ocr2keepers/pkg/v2/encoding" + pluginutils "github.com/smartcontractkit/chainlink-automation/pkg/util" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" + "github.com/smartcontractkit/chainlink-automation/pkg/v2/encoding" "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go index 7fe4087cfa..3cb91ab8dc 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go @@ -17,7 +17,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "go.uber.org/multierr" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go index 340bd92357..0e0ceba716 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v2" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list.go b/core/services/ocr2/plugins/ocr2keeper/evm21/active_list.go index 899dd398d0..9f82555633 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/active_list.go @@ -4,7 +4,7 @@ import ( "math/big" "sync" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/active_list_test.go index 76ca6bfdf1..06b9979eef 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/active_list_test.go @@ -5,9 +5,10 @@ import ( "sort" "testing" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go index 0cf0bbef5c..0ed4c84dbb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go index ae407b0ea9..134a75fc2c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go index afb9d4a091..41a43b951e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/interfaces.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/interfaces.go index d9417c72a1..49975855b5 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/interfaces.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/interfaces.go @@ -3,7 +3,7 @@ package core import ( "context" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) // UpkeepStateReader is the interface for reading the current state of upkeeps. diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go index 40b63611c9..b036fbb26c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go @@ -7,7 +7,7 @@ import ( mock "github.com/stretchr/testify/mock" - types "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + types "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) // UpkeepStateReader is an autogenerated mock type for the UpkeepStateReader type diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload.go index d733673767..ed5530ae7b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload.go @@ -6,7 +6,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/crypto" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) var ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go index 1ca280c0d2..cb3a67dde0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/stretchr/testify/assert" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) func TestWorkID(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/testutil.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/testutil.go index 47935b56f6..3c0eeb1c44 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/testutil.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/testutil.go @@ -4,7 +4,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) // GenUpkeepID generates an ocr2keepers.UpkeepIdentifier with a specific UpkeepType and some random string diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go index 7927347959..02e6946c8f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go index 0233e40679..366d59b639 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go @@ -7,8 +7,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) func TestPackUnpackTrigger(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/type.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/type.go index aeb56a16f6..7820b47e6e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/type.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/type.go @@ -3,7 +3,7 @@ package core import ( "math/big" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) const ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/type_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/type_test.go index 8a2a51533e..6f81ca7690 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/type_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/type_test.go @@ -4,9 +4,9 @@ import ( "math/big" "testing" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/stretchr/testify/assert" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) func TestGetUpkeepType(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go index 239de099c0..fadf55633d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go index 578153e07a..63ff2650be 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go @@ -5,9 +5,10 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go index e21ecfb800..cf98115d76 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go @@ -3,7 +3,7 @@ package encoding import ( "math/big" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go index 28c6c4a975..0157d1baf8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go index 03b55bfccc..b52b777dbe 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go @@ -9,10 +9,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/keyring.go b/core/services/ocr2/plugins/ocr2keeper/evm21/keyring.go index df4e3a8650..2d84f09637 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/keyring.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/keyring.go @@ -3,7 +3,8 @@ package evm import ( "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" + + "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" ) var _ ocr3types.OnchainKeyring[plugin.AutomationReportInfo] = &onchainKeyringV3Wrapper{} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/keyring_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/keyring_test.go index 14c42a810c..92a05c2d76 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/keyring_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/keyring_test.go @@ -3,10 +3,12 @@ package evm import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" - "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" ) func TestNewOnchainKeyringV3Wrapper(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go index b06a3ca809..81f51311d4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go @@ -7,8 +7,8 @@ import ( "sync" "sync/atomic" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/random" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go index 5c8908f9be..a973ea6e19 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go @@ -7,9 +7,10 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index c7db01d878..dd90b5e00b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -12,14 +12,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "golang.org/x/time/rate" - "github.com/jmoiron/sqlx" - - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go index d3f069a9bf..a3887cbe78 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go index b28b45fcb4..c58bd85951 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go index c6ebb1c51a..81774e2638 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go @@ -11,15 +11,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "golang.org/x/time/rate" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - - "golang.org/x/time/rate" ) func TestLogEventProvider_GetFilters(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index c656656815..98eb0b291b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -16,8 +16,8 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/random" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go index 77b0eec545..10e58bf26b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go index d34787f501..f98d4ed2df 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go @@ -15,7 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go index 0653796f41..baa277e035 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go @@ -15,24 +15,21 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" - v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02" - v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02" + v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03" ) type MockMercuryConfigProvider struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go index b14e687b5d..e138f440e4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go @@ -3,7 +3,7 @@ package evm import ( "context" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go index e68e316ae3..d7c2312d19 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index afb1a7cf6c..18795eb073 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go index ad31c8feb0..b0db3f7dd1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go @@ -9,7 +9,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go index d4e38637d8..4eaf334f7c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go @@ -8,31 +8,27 @@ import ( "sync/atomic" "testing" - "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/patrickmn/go-cache" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" - + "github.com/patrickmn/go-cache" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go index 4be0ccce4e..fdc6675da8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go @@ -11,10 +11,11 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" coreTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + types3 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go index d178a9af57..18c9ed6d39 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go @@ -5,10 +5,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + + "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache.go index 5e0dadbdc4..99e1f1dc16 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache.go @@ -3,7 +3,7 @@ package transmit import ( "sync" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) // transmitEventCache holds a ring buffer of the last visited blocks (transmit block), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache_test.go index 55d245c168..7f4a129656 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache_test.go @@ -3,8 +3,9 @@ package transmit import ( "testing" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/require" + + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" ) func TestTransmitEventCache_Sanity(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding.go index ec709d04bd..17d3cd439f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding_test.go index f081f82f2a..7415b3701f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding_test.go @@ -4,9 +4,10 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go index 000d40f407..95f5ec0bf1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go index a33056977a..8d56fec22a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go index 5cb60d5dc1..5b6d4ac703 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider_test.go index ac49675812..69bfabb259 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider_test.go @@ -5,9 +5,10 @@ import ( "sync/atomic" "testing" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go index f5e3969bc7..505959b8f3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go @@ -8,7 +8,7 @@ import ( "sync" "time" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go index 579d875792..138b9ffd78 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index d2f35a3e37..01418b9f76 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -26,13 +26,12 @@ import ( "github.com/stretchr/testify/require" "github.com/umbracle/ethgo/abi" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" - "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" + + "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -55,6 +54,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 3eda886796..1ab9194c49 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -23,15 +23,16 @@ import ( "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo/abi" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo/abi" + "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -60,8 +61,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/smartcontractkit/chainlink-common/pkg/types" ) const ( diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 504b6267c6..2c477e7a6a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -6,14 +6,14 @@ import ( "github.com/jmoiron/sqlx" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers20 "github.com/smartcontractkit/ocr2keepers/pkg/v2" - ocr2keepers20coordinator "github.com/smartcontractkit/ocr2keepers/pkg/v2/coordinator" - ocr2keepers20polling "github.com/smartcontractkit/ocr2keepers/pkg/v2/observer/polling" - ocr2keepers20runner "github.com/smartcontractkit/ocr2keepers/pkg/v2/runner" - "github.com/smartcontractkit/chainlink-common/pkg/types" + ocr2keepers20 "github.com/smartcontractkit/chainlink-automation/pkg/v2" + ocr2keepers20coordinator "github.com/smartcontractkit/chainlink-automation/pkg/v2/coordinator" + ocr2keepers20polling "github.com/smartcontractkit/chainlink-automation/pkg/v2/observer/polling" + ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" + ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - ocr2keepers21 "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 2e8f9cbf48..2b484edb79 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -14,11 +14,11 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" - "github.com/smartcontractkit/ocr2keepers/pkg/v3/plugin" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 31f7ea74c1..f09e4d3482 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -190,12 +190,13 @@ func TestNewManager(t *testing.T) { require.Equal(t, "TelemetryManager", m.Name()) require.Nil(t, m.Start(testutils.Context(t))) + t.Cleanup(func() { + require.NoError(t, m.Close()) + }) testutils.WaitForLogMessageCount(t, logObs, "error connecting error while dialing dial tcp", 3) hr := m.HealthReport() require.Equal(t, 4, len(hr)) - require.Nil(t, m.Close()) - time.Sleep(time.Second * 1) } func TestCorrectEndpointRouting(t *testing.T) { diff --git a/go.mod b/go.mod index c13f476bf2..b3bdeb74cf 100644 --- a/go.mod +++ b/go.mod @@ -65,13 +65,13 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 + github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 - github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 diff --git a/go.sum b/go.sum index 4f465dc8f9..bdfbe2107e 100644 --- a/go.sum +++ b/go.sum @@ -1463,6 +1463,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= +github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= +github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= @@ -1479,8 +1481,6 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= -github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index e1635902db..38df2e00b5 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -17,8 +17,9 @@ import ( ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" - ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" + + ocr2keepers20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" + ocr2keepers30config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" diff --git a/integration-tests/actions/automation_ocr_helpers_local.go b/integration-tests/actions/automation_ocr_helpers_local.go index f541594c4d..e591e75a98 100644 --- a/integration-tests/actions/automation_ocr_helpers_local.go +++ b/integration-tests/actions/automation_ocr_helpers_local.go @@ -9,12 +9,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" "github.com/rs/zerolog" + "gopkg.in/guregu/null.v4" + ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" - ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" - "gopkg.in/guregu/null.v4" + + ocr2keepers20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" + ocr2keepers30config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 9e99f39b44..cdd42deda7 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,12 +22,12 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 + github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e github.com/smartcontractkit/chainlink-testing-framework v1.19.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 - github.com/smartcontractkit/ocr2keepers v0.7.28 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.3.0 github.com/spf13/cobra v1.6.1 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 87cceb9b99..08b772c9ce 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2367,6 +2367,8 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= +github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= +github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= @@ -2385,8 +2387,6 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= -github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index 06c2624d0f..1f39d5e4b0 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -18,9 +18,10 @@ import ( "github.com/stretchr/testify/require" ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" - ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" "github.com/smartcontractkit/wasp" + ocr2keepers30config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" @@ -29,15 +30,17 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + + registrar21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" contractseth "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - registrar21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" ) const ( From 4342e167b5f4b3ace7be3f374a64d047dd7492cc Mon Sep 17 00:00:00 2001 From: Sneha Agnihotri <180277+snehaagni@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:29:38 -0800 Subject: [PATCH 186/327] release/2.7.0 -> develop (#11291) * Bump version and update CHANGELOG for core v2.7.0 * core: log a warning when deprecated P2P.V1 config is set in TOML (#11073) * core: log a warning when deprecated P2P.V1 config is set in TOML * change default P2P from V1 to V2 * bump operator ui (cherry picked from commit 5808e734cf024a5e8c5450e939e1f2d5b3cba546) * operator-ui deprecation warnings (#11104) Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> Co-authored-by: github-merge-queue[bot] Co-authored-by: Jordan Krage * chore: bump sigstore/cosign-installer from 2.1.0 to 3.1.2 * Finalize date on changelog for 2.7.0 --------- Co-authored-by: Jordan Krage Co-authored-by: chainchad <96362174+chainchad@users.noreply.github.com> Co-authored-by: george-dorin <120329946+george-dorin@users.noreply.github.com> Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> Co-authored-by: github-merge-queue[bot] Co-authored-by: Erik Burton --- docs/CHANGELOG.md | 4 ++-- integration-tests/smoke/automation_test.go | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 1351c42134..8e016347c4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -36,6 +36,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ... + + ## 2.7.1 - UNRELEASED ### Fixed @@ -74,8 +76,6 @@ Starting in `v2.9.0`: - Removed the ability to set a next nonce value for an address through CLI - - ## 2.6.0 - 2023-10-18 ### Added diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 05d19d5ccd..cdc8748676 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -10,16 +10,12 @@ import ( "testing" "time" - "github.com/kelseyhightower/envconfig" - - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" - "github.com/ethereum/go-ethereum/common" + "github.com/kelseyhightower/envconfig" "github.com/onsi/gomega" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" @@ -27,6 +23,7 @@ import ( cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/integration-tests/actions" From 4c6d0fe9d0bc4e4c450b0c528e08db000b745e9f Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:49:47 -0500 Subject: [PATCH 187/327] Avoid checking version file bump on forks in CI (#11351) --- .github/workflows/build-publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 1bda6957a2..de33663d88 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -17,7 +17,8 @@ jobs: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Check for VERSION file bump on tags - if: ${{ startsWith(github.ref, 'refs/tags/v') }} + # Avoids checking VERSION file bump on forks. + if: ${{ github.repository == 'smartcontractkit/chainlink' && startsWith(github.ref, 'refs/tags/v') }} uses: ./.github/actions/version-file-bump with: github-token: ${{ secrets.GITHUB_TOKEN }} From aca537daff2cd5c01cc0f204b1b345a7e6c1385c Mon Sep 17 00:00:00 2001 From: amit-momin <108959691+amit-momin@users.noreply.github.com> Date: Tue, 21 Nov 2023 16:04:20 -0600 Subject: [PATCH 188/327] Remove dependencies on services package in common (#11321) * Removed dependencies on services package in common * Marked json data type as deprecated and cleaned up test vars * Replaced json data type with alias --- common/txmgr/types/forwarder_manager.go | 4 +- common/txmgr/types/tx.go | 6 +- common/txmgr/types/tx_attempt_builder.go | 4 +- common/txmgr/types/tx_store.go | 3 - common/types/head_tracker.go | 6 +- core/chains/evm/txmgr/broadcaster_test.go | 4 +- core/chains/evm/txmgr/evm_tx_store.go | 7 +-- core/chains/evm/txmgr/transmitchecker_test.go | 6 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/keystore/keys/ethkey/key.go | 10 ++-- core/services/pg/datatypes/json.go | 56 +------------------ core/services/vrf/v2/integration_v2_test.go | 17 +++--- core/services/vrf/v2/listener_v2_test.go | 10 ++-- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 18 files changed, 49 insertions(+), 102 deletions(-) diff --git a/common/txmgr/types/forwarder_manager.go b/common/txmgr/types/forwarder_manager.go index 8d58f91295..4d70b73000 100644 --- a/common/txmgr/types/forwarder_manager.go +++ b/common/txmgr/types/forwarder_manager.go @@ -1,13 +1,13 @@ package types import ( + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/services" ) //go:generate mockery --quiet --name ForwarderManager --output ./mocks/ --case=underscore type ForwarderManager[ADDR types.Hashable] interface { - services.ServiceCtx + services.Service ForwarderFor(addr ADDR) (forwarder ADDR, err error) // Converts payload to be forwarder-friendly ConvertPayload(dest ADDR, origPayload []byte) ([]byte, error) diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index 11017bd032..78f6fba459 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -13,11 +13,11 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" clnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" ) // TxStrategy controls how txes are queued and sent @@ -210,7 +210,7 @@ type Tx[ // Marshalled TxMeta // Used for additional context around transactions which you want to log // at send time. - Meta *datatypes.JSON + Meta *sqlutil.JSON Subject uuid.NullUUID ChainID CHAIN_ID @@ -219,7 +219,7 @@ type Tx[ // TransmitChecker defines the check that should be performed before a transaction is submitted on // chain. - TransmitChecker *datatypes.JSON + TransmitChecker *sqlutil.JSON // Marks tx requiring callback SignalCallback bool diff --git a/common/txmgr/types/tx_attempt_builder.go b/common/txmgr/types/tx_attempt_builder.go index 887219c490..75712fc0c3 100644 --- a/common/txmgr/types/tx_attempt_builder.go +++ b/common/txmgr/types/tx_attempt_builder.go @@ -3,10 +3,10 @@ package types import ( "context" + "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" ) // TxAttemptBuilder takes the base unsigned transaction + optional parameters (tx type, gas parameters) @@ -23,7 +23,7 @@ type TxAttemptBuilder[ FEE feetypes.Fee, // FEE - chain fee type ] interface { // interfaces for running the underlying estimator - services.ServiceCtx + services.Service types.HeadTrackable[HEAD, BLOCK_HASH] // NewTxAttempt builds a transaction using the configured transaction type and fee estimator (new estimation) diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index c2dfeee414..f731031f92 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -9,7 +9,6 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // TxStore is a superset of all the needed persistence layer methods @@ -118,8 +117,6 @@ type ReceiptPlus[R any] struct { FailOnRevert bool `db:"fail_on_revert"` } -type QueryerFunc = func(tx pg.Queryer) error - type ChainReceipt[TX_HASH, BLOCK_HASH types.Hashable] interface { GetStatus() uint64 GetTxHash() TX_HASH diff --git a/common/types/head_tracker.go b/common/types/head_tracker.go index 811298f895..d8fa801178 100644 --- a/common/types/head_tracker.go +++ b/common/types/head_tracker.go @@ -3,7 +3,7 @@ package types import ( "context" - "github.com/smartcontractkit/chainlink/v2/core/services" + "github.com/smartcontractkit/chainlink-common/pkg/services" ) // HeadTracker holds and stores the block experienced by a particular node in a thread safe manner. @@ -11,7 +11,7 @@ import ( // //go:generate mockery --quiet --name HeadTracker --output ../mocks/ --case=underscore type HeadTracker[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - services.ServiceCtx + services.Service // Backfill given a head will fill in any missing heads up to the given depth // (used for testing) Backfill(ctx context.Context, headWithChain H, depth uint) (err error) @@ -68,7 +68,7 @@ type NewHeadHandler[H Head[BLOCK_HASH], BLOCK_HASH Hashable] func(ctx context.Co // //go:generate mockery --quiet --name HeadBroadcaster --output ../mocks/ --case=underscore type HeadBroadcaster[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - services.ServiceCtx + services.Service BroadcastNewLongestChain(H) HeadBroadcasterRegistry[H, BLOCK_HASH] } diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index bf480c66af..d1e26c6c96 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -22,6 +22,7 @@ import ( "go.uber.org/zap/zapcore" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -43,7 +44,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -255,7 +255,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { tr := int32(99) b, err := json.Marshal(txmgr.TxMeta{JobID: &tr}) require.NoError(t, err) - meta := datatypes.JSON(b) + meta := sqlutil.JSON(b) earlierEthTx := txmgr.Tx{ FromAddress: fromAddress, ToAddress: toAddress, diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 0e08d32b77..84fe9a02c6 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -18,6 +18,7 @@ import ( pkgerrors "github.com/pkg/errors" nullv4 "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -27,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -171,14 +171,14 @@ type DbEthTx struct { // Marshalled EvmTxMeta // Used for additional context around transactions which you want to log // at send time. - Meta *datatypes.JSON + Meta *sqlutil.JSON Subject uuid.NullUUID PipelineTaskRunID uuid.NullUUID MinConfirmations null.Uint32 EVMChainID utils.Big // TransmitChecker defines the check that should be performed before a transaction is submitted on // chain. - TransmitChecker *datatypes.JSON + TransmitChecker *sqlutil.JSON InitialBroadcastAt *time.Time // Marks tx requiring callback SignalCallback bool @@ -1451,7 +1451,6 @@ func (o *evmTxStore) UpdateTxFatalError(ctx context.Context, etx *Tx) error { } // Updates eth attempt from in_progress to broadcast. Also updates the eth tx to unconfirmed. -// One of the more complicated signatures. We have to accept variable pg.QOpt and QueryerFunc arguments func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *Tx, attempt TxAttempt, NewAttemptState txmgrtypes.TxAttemptState) error { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) diff --git a/core/chains/evm/txmgr/transmitchecker_test.go b/core/chains/evm/txmgr/transmitchecker_test.go index b43fcb4f45..5ebf5f32e3 100644 --- a/core/chains/evm/txmgr/transmitchecker_test.go +++ b/core/chains/evm/txmgr/transmitchecker_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -29,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" ) func TestFactory(t *testing.T) { @@ -192,7 +192,7 @@ func TestTransmitCheckers(t *testing.T) { b, err := json.Marshal(meta) require.NoError(t, err) - metaJson := datatypes.JSON(b) + metaJson := sqlutil.JSON(b) tx := txmgr.Tx{ FromAddress: common.HexToAddress("0xfe0629509E6CB8dfa7a99214ae58Ceb465d5b5A9"), @@ -296,7 +296,7 @@ func TestTransmitCheckers(t *testing.T) { b, err := json.Marshal(meta) require.NoError(t, err) - metaJson := datatypes.JSON(b) + metaJson := sqlutil.JSON(b) tx := txmgr.Tx{ FromAddress: common.HexToAddress("0xfe0629509E6CB8dfa7a99214ae58Ceb465d5b5A9"), diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 0d78e15d59..e9fa432d4c 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -303,7 +303,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 3dd48f7445..3d9962474b 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-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= diff --git a/core/services/keystore/keys/ethkey/key.go b/core/services/keystore/keys/ethkey/key.go index 4201251e34..6335ed55ad 100644 --- a/core/services/keystore/keys/ethkey/key.go +++ b/core/services/keystore/keys/ethkey/key.go @@ -3,7 +3,7 @@ package ethkey import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" ) // NOTE: This model refers to the OLD key and is only used for migrations @@ -15,10 +15,10 @@ import ( type Key struct { ID int32 Address EIP55Address - JSON datatypes.JSON `json:"-"` - CreatedAt time.Time `json:"-"` - UpdatedAt time.Time `json:"-"` - DeletedAt *time.Time `json:"-"` + JSON sqlutil.JSON `json:"-"` + CreatedAt time.Time `json:"-"` + UpdatedAt time.Time `json:"-"` + DeletedAt *time.Time `json:"-"` // IsFunding marks the address as being used for rescuing the node and the pending transactions // Only one key can be IsFunding=true at a time. IsFunding bool diff --git a/core/services/pg/datatypes/json.go b/core/services/pg/datatypes/json.go index d84c89269c..ac72a5a5ed 100644 --- a/core/services/pg/datatypes/json.go +++ b/core/services/pg/datatypes/json.go @@ -1,59 +1,9 @@ package datatypes import ( - "database/sql/driver" - "encoding/json" - "errors" - "fmt" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" ) // JSON defined JSON data type, need to implements driver.Valuer, sql.Scanner interface -type JSON json.RawMessage - -// Value return json value, implement driver.Valuer interface -func (j JSON) Value() (driver.Value, error) { - if len(j) == 0 { - return nil, nil - } - bytes, err := json.RawMessage(j).MarshalJSON() - return string(bytes), err -} - -// Scan scan value into Jsonb, implements sql.Scanner interface -func (j *JSON) Scan(value interface{}) error { - if value == nil { - *j = JSON("null") - return nil - } - var bytes []byte - switch v := value.(type) { - case []byte: - bytes = v - case string: - bytes = []byte(v) - default: - return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value)) - } - - result := json.RawMessage{} - err := json.Unmarshal(bytes, &result) - *j = JSON(result) - return err -} - -// MarshalJSON to output non base64 encoded []byte -func (j JSON) MarshalJSON() ([]byte, error) { - return json.RawMessage(j).MarshalJSON() -} - -// UnmarshalJSON to deserialize []byte -func (j *JSON) UnmarshalJSON(b []byte) error { - result := json.RawMessage{} - err := result.UnmarshalJSON(b) - *j = JSON(result) - return err -} - -func (j JSON) String() string { - return string(j) -} +// Deprecated: Use sqlutil.JSON instead +type JSON = sqlutil.JSON diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 6880fa1799..f57cb640f6 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -30,6 +30,7 @@ import ( "github.com/jmoiron/sqlx" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -70,7 +71,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" @@ -2038,13 +2038,13 @@ func TestStartingCountsV1(t *testing.T) { } md1, err := json.Marshal(&m1) require.NoError(t, err) - md1_ := datatypes.JSON(md1) + md1SQL := sqlutil.JSON(md1) reqID2 := utils.PadByteToHash(0x11) m2 := txmgr.TxMeta{ RequestID: &reqID2, } md2, err := json.Marshal(&m2) - md2_ := datatypes.JSON(md2) + md2SQL := sqlutil.JSON(md2) require.NoError(t, err) chainID := utils.NewBig(testutils.SimulatedChainID) confirmedTxes := []txmgr.Tx{ @@ -2056,7 +2056,7 @@ func TestStartingCountsV1(t *testing.T) { InitialBroadcastAt: &b, CreatedAt: b, State: txmgrcommon.TxConfirmed, - Meta: &datatypes.JSON{}, + Meta: &sqlutil.JSON{}, EncodedPayload: []byte{}, ChainID: chainID.ToInt(), }, @@ -2068,7 +2068,7 @@ func TestStartingCountsV1(t *testing.T) { InitialBroadcastAt: &b, CreatedAt: b, State: txmgrcommon.TxConfirmed, - Meta: &md1_, + Meta: &md1SQL, EncodedPayload: []byte{}, ChainID: chainID.ToInt(), }, @@ -2080,7 +2080,7 @@ func TestStartingCountsV1(t *testing.T) { InitialBroadcastAt: &b, CreatedAt: b, State: txmgrcommon.TxConfirmed, - Meta: &md2_, + Meta: &md2SQL, EncodedPayload: []byte{}, ChainID: chainID.ToInt(), }, @@ -2092,7 +2092,7 @@ func TestStartingCountsV1(t *testing.T) { InitialBroadcastAt: &b, CreatedAt: b, State: txmgrcommon.TxConfirmed, - Meta: &md2_, + Meta: &md2SQL, EncodedPayload: []byte{}, ChainID: chainID.ToInt(), }, @@ -2105,6 +2105,7 @@ func TestStartingCountsV1(t *testing.T) { RequestID: &reqID3, }) require.NoError(t, err2) + mdSQL := sqlutil.JSON(md) newNonce := evmtypes.Nonce(i + 1) unconfirmedTxes = append(unconfirmedTxes, txmgr.Tx{ Sequence: &newNonce, @@ -2114,7 +2115,7 @@ func TestStartingCountsV1(t *testing.T) { State: txmgrcommon.TxUnconfirmed, BroadcastAt: &b, InitialBroadcastAt: &b, - Meta: (*datatypes.JSON)(&md), + Meta: &mdSQL, EncodedPayload: []byte{}, ChainID: chainID.ToInt(), }) diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 17615feb63..513aa01ef6 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -17,9 +17,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -77,7 +77,7 @@ func addEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, from common.Address, s RequestTxHash: &reqTxHash, }) require.NoError(t, err) - meta := datatypes.JSON(b) + meta := sqlutil.JSON(b) tx := &txmgr.Tx{ FromAddress: from, ToAddress: from, @@ -103,7 +103,7 @@ func addConfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, from common.A GlobalSubID: txMetaGlobalSubID, }) require.NoError(t, err) - meta := datatypes.JSON(b) + meta := sqlutil.JSON(b) now := time.Now() tx := &txmgr.Tx{ @@ -135,7 +135,7 @@ func addEthTxNativePayment(t *testing.T, txStore txmgr.TestEvmTxStore, from comm RequestTxHash: &reqTxHash, }) require.NoError(t, err) - meta := datatypes.JSON(b) + meta := sqlutil.JSON(b) tx := &txmgr.Tx{ FromAddress: from, ToAddress: from, @@ -161,7 +161,7 @@ func addConfirmedEthTxNativePayment(t *testing.T, txStore txmgr.TestEvmTxStore, GlobalSubID: txMetaGlobalSubID, }) require.NoError(t, err) - meta := datatypes.JSON(b) + meta := sqlutil.JSON(b) now := time.Now() tx := &txmgr.Tx{ Sequence: &nonce, diff --git a/go.mod b/go.mod index b3bdeb74cf..e6bb7347ff 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-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 diff --git a/go.sum b/go.sum index bdfbe2107e..24d662390d 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-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index cdd42deda7..d626b38cca 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -23,7 +23,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 github.com/smartcontractkit/chainlink-testing-framework v1.19.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 08b772c9ce..b8a84de26e 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-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= From f7c254bc9c7320506536b1c23bd5005476e17ee7 Mon Sep 17 00:00:00 2001 From: cfal Date: Wed, 22 Nov 2023 20:12:32 +0900 Subject: [PATCH 189/327] core/cmd/shell.go: pass DB and QConfig fields to CosmosFactoryConfig (#11360) --- core/cmd/shell.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 52c9090736..b82bd85e3e 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -176,6 +176,8 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G cosmosCfg := chainlink.CosmosFactoryConfig{ Keystore: keyStore.Cosmos(), TOMLConfigs: cfg.CosmosConfigs(), + DB: db, + QConfig: cfg.Database(), } initOps = append(initOps, chainlink.InitCosmos(ctx, relayerFactory, cosmosCfg)) } From 60cb43a46b8d9d1eb7d3820687aa911249228bde Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Wed, 22 Nov 2023 11:09:29 -0500 Subject: [PATCH 190/327] Update CTF (#11367) --- integration-tests/go.mod | 14 ++++++++------ integration-tests/go.sum | 21 ++++++++++++--------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index d626b38cca..ba90493d29 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,12 +24,12 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 - github.com/smartcontractkit/chainlink-testing-framework v1.19.1 + github.com/smartcontractkit/chainlink-testing-framework v1.19.4 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 - github.com/smartcontractkit/wasp v0.3.0 + github.com/smartcontractkit/wasp v0.3.6 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 github.com/testcontainers/testcontainers-go v0.23.0 @@ -85,6 +85,7 @@ require ( github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee // indirect + github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect @@ -205,7 +206,7 @@ require ( github.com/gosimple/slug v1.13.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 // indirect - github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737 // indirect + github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6 // indirect github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 // indirect github.com/grafana/pyroscope-go v1.0.4 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect @@ -360,6 +361,7 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/otiai10/copy v1.14.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect @@ -381,7 +383,7 @@ require ( github.com/russross/blackfriday v1.6.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - github.com/sercand/kuberesolver v2.4.0+incompatible // indirect + github.com/sercand/kuberesolver/v4 v4.0.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.23.9 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -420,7 +422,7 @@ require ( github.com/ugorji/go/codec v1.2.11 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect - github.com/weaveworks/common v0.0.0-20221201103051-7c2720a9024d // indirect + github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205 // indirect github.com/weaveworks/promrus v1.2.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect @@ -513,5 +515,5 @@ replace ( github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 - github.com/sercand/kuberesolver v2.4.0+incompatible => github.com/sercand/kuberesolver/v5 v5.1.1 + github.com/sercand/kuberesolver/v4 => github.com/sercand/kuberesolver/v5 v5.1.1 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index b8a84de26e..849df2afca 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -721,6 +721,8 @@ github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I= github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= +github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 h1:rvc39Ol6z3MvaBzXkxFC6Nfsnixq/dRypushKDd7Nc0= github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5/go.mod h1:R/pdNYDYFQk+tuuOo7QES1kkv6OLmp5ze2XBZQIVffM= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= @@ -1360,8 +1362,8 @@ github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6 github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 h1:IOks+FXJ6iO/pfbaVEf4efNw+YzYBYNCkCabyrbkFTM= github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2/go.mod h1:zj+5BNZAVmQafV583uLTAOzRr963KPdEm4d6NPmtbwg= -github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737 h1:o45+fZAYRtTjx+9fFml9LZxsCmLX65l39eWDgvdkIr0= -github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737/go.mod h1:kxNnWCr4EMobhndjy7a2Qpm7jkLPnJW2ariYvY77hLE= +github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6 h1:V5PspEXlSlNh22sMyGkgfSOVVLTsSmhbmsp1VPt8Fdc= +github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6/go.mod h1:+aWr7OBDuZMT+p0rKmLfW5saO2m3YOGBnt++IlgLhVk= github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 h1:VXitROTlmZtLzvokNe8ZbUKpmwldM4Hy1zdNRO32jKU= github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765/go.mod h1:DhJMrd2QInI/1CNtTN43BZuTmkccdizW1jZ+F6aHkhY= github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= @@ -1377,7 +1379,6 @@ github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLt github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 h1:f4tggROQKKcnh4eItay6z/HbHLqghBxS8g7pyMhmDio= @@ -2197,6 +2198,8 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= @@ -2377,8 +2380,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= -github.com/smartcontractkit/chainlink-testing-framework v1.19.1 h1:MdGM5jIrBi858Cv7qzfl1Qon93YW8InohAlDQqFoIb4= -github.com/smartcontractkit/chainlink-testing-framework v1.19.1/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk= +github.com/smartcontractkit/chainlink-testing-framework v1.19.4 h1:a5zG5k3MNbDBWiBdxF2cBLaMyB+WD0ROWPiZ0DVJQMc= +github.com/smartcontractkit/chainlink-testing-framework v1.19.4/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= @@ -2391,8 +2394,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -github.com/smartcontractkit/wasp v0.3.0 h1:mueeLvpb6HyGNwILxCOKShDR6q18plQn7Gb1j3G/Qkk= -github.com/smartcontractkit/wasp v0.3.0/go.mod h1:skquNdMbKxIrHi5O8Kyukf66AaaXuEpEEaSTxfHbhak= +github.com/smartcontractkit/wasp v0.3.6 h1:1TLWfrTzqZwNvyyoKzPZ8FLQat2lNz640eM+mMh2YxM= +github.com/smartcontractkit/wasp v0.3.6/go.mod h1:L/cyUGfpaWxy/2twOVJLRt2mySJEIqGrFj9nyvRLpSo= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -2530,8 +2533,8 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= -github.com/weaveworks/common v0.0.0-20221201103051-7c2720a9024d h1:9Z/HiqeGN+LOnmotAMpFEQjuXZ4AGAVFG0rC1laP5Go= -github.com/weaveworks/common v0.0.0-20221201103051-7c2720a9024d/go.mod h1:Fnq3+U51tMkPRMC6Wr7zKGUeFFYX4YjNrNK50iU0fcE= +github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205 h1:gjb7t9LCnRu14LHubyLIgrE+EYlAaREiPn/VknV7R3s= +github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205/go.mod h1:O9wmSPNVSuqxzUZPFlHnPQ8xnyvx0qBnKGFfGbj95uY= github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= From 543d94633499d592c2cd44f7048912eb38f7bae6 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 22 Nov 2023 10:17:51 -0600 Subject: [PATCH 191/327] core/web: go:generate operator-ui assets (#11239) --- .gitignore | 3 - .goreleaser.develop.yaml | 2 - GNUmakefile | 2 +- core/web/assets/9f6d832ef97e8493764e.svg | 1 + core/web/assets/9f6d832ef97e8493764e.svg.gz | Bin 0 -> 193 bytes core/web/assets/ba8bbf16ebf8e1d05bef.svg | 1 + core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz | Bin 0 -> 1739 bytes core/web/assets/index.html | 1 + core/web/assets/index.html.gz | Bin 0 -> 420 bytes core/web/assets/main.b0b6f79f7f4a94560e37.js | 187 ++++++++++++++++++ .../assets/main.b0b6f79f7f4a94560e37.js.gz | Bin 0 -> 1190421 bytes core/web/middleware.go | 1 + 12 files changed, 192 insertions(+), 6 deletions(-) create mode 100644 core/web/assets/9f6d832ef97e8493764e.svg create mode 100644 core/web/assets/9f6d832ef97e8493764e.svg.gz create mode 100644 core/web/assets/ba8bbf16ebf8e1d05bef.svg create mode 100644 core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz create mode 100644 core/web/assets/index.html.gz create mode 100644 core/web/assets/main.b0b6f79f7f4a94560e37.js create mode 100644 core/web/assets/main.b0b6f79f7f4a94560e37.js.gz diff --git a/.gitignore b/.gitignore index 48e228eb83..3f016503a8 100644 --- a/.gitignore +++ b/.gitignore @@ -55,9 +55,6 @@ golangci-lint-output.txt # can be left behind by tests core/cmd/vrfkey1 -# left behind by webpack - compiled frontend assets -core/web/assets - # Integration Tests integration-tests/**/logs/ tests-*.xml diff --git a/.goreleaser.develop.yaml b/.goreleaser.develop.yaml index 53c927c9f9..2031249165 100644 --- a/.goreleaser.develop.yaml +++ b/.goreleaser.develop.yaml @@ -10,8 +10,6 @@ env: before: hooks: - - go mod tidy - - make operator-ui - ./tools/bin/goreleaser_utils before_hook # See https://goreleaser.com/customization/build/ diff --git a/GNUmakefile b/GNUmakefile index 2801f94968..cb665498a3 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -79,7 +79,7 @@ docker-plugins: .PHONY: operator-ui operator-ui: ## Fetch the frontend - ./operator_ui/install.sh + go generate ./core/web .PHONY: abigen abigen: ## Build & install abigen. diff --git a/core/web/assets/9f6d832ef97e8493764e.svg b/core/web/assets/9f6d832ef97e8493764e.svg new file mode 100644 index 0000000000..e35f1df284 --- /dev/null +++ b/core/web/assets/9f6d832ef97e8493764e.svg @@ -0,0 +1 @@ + diff --git a/core/web/assets/9f6d832ef97e8493764e.svg.gz b/core/web/assets/9f6d832ef97e8493764e.svg.gz new file mode 100644 index 0000000000000000000000000000000000000000..44cd870b0bbe539c0d37376c0006f03325f13e24 GIT binary patch literal 193 zcmV;y06za8iwFP!0000212vC34}&lag!ldmE1hv34m4DRp);)PRo_xtP(cLo>ze@G z?(?0`a?y_unBMNwTlO4=?#Q|K9z9|EeQ+g&;32_aeBJ!1oh%a|fDULt6K1R|y7Taa zt7Ww`n1gVM28C2rE_o-SHkGRDgyK2+|0?+AM<`2YX_KeSc1 literal 0 HcmV?d00001 diff --git a/core/web/assets/ba8bbf16ebf8e1d05bef.svg b/core/web/assets/ba8bbf16ebf8e1d05bef.svg new file mode 100644 index 0000000000..3ca546a8aa --- /dev/null +++ b/core/web/assets/ba8bbf16ebf8e1d05bef.svg @@ -0,0 +1 @@ +Artboard 1 \ No newline at end of file diff --git a/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz b/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz new file mode 100644 index 0000000000000000000000000000000000000000..7e4f235f1b9263b49c03bad9b2924a6355913d21 GIT binary patch literal 1739 zcmV;+1~mB}iwFP!000021I1WNZxlxm{wpiz+S8t@eiMU4eDT3KA^G4-G+7&LX$*+9 z)}Sc=J>OS7yBI7M!Xc4GZ%x0d>Z@mSve~{_-CjLEI-fpWfA~X=R#(&gG`yYeu9vwL z=04udZ#U16Ztm~jKRZ5tczEy+!N2?P=2*vZJjNAAtL^Re!*B0CK0g{)<4Q2S!kQn` z(TkI->(`qXC!70E^YshAo;QR1_4;<6pZ%g!ny#i_|2{eHizml@>;3ILzFvN~|MT7S z;c6u($9?AH{d9k`TF=u4!q`O+_xaK9ItHJLYt6^J9tRzLs7{jCG6eNGxgb6*B&KU~ zqtoO=aLtG8w0cPnr?kz3j4ohuJ&3PqC_Xg|xegL+#MV6xHtLKW?#0f9Qt+wZAkp{% zgv_}pWKrTmV?J?H#<}c^!_8TFbIEhVckoh9HRHzYL?KLp$l@h90ap#lOYS622I*wS zL8SQ_-D6ZPkB+~MUR7UsEu=fsqCQ>Z?5o^BL=6{>yw~cR3=pnC(NczF2rCipB(yP| z6GSIyosx3VuMO~ph>sCQsW1_K+MqtPq4^Ys>TBp!@;L(2N{OP^2&xIpROFBfAp~3x zDY75yECS=@3YlXWd`QF+=Au+a1wX7m^gF-5$)VLH!=rn4F2dV|POI)PNMoKshN^cVZZ*bL2f0wa%Nc#nJmv=a#g1buF z0nzNxFczoASz@J883@v~)d4hd%eSCubLFkjT zA4)+#gL}$dEL`7asZOJ>XDK6d>3K>BHMlwA2LVOK78qO6vlJ0p`Lm$_4YER*tu9D` zcxS015D&4=5y{or6>FS}3`SJE%EG}^*J+f$lwakPsUE9EKL%9+$OASnr72z*+IcD^R<*~`GP%>Ba&DsoL-Akl;P}{0z zTI3FdQAJwT8`Qf7=coZWU#w1%&zKqhjR`rIg;XxVM;akvo$XYw$s^Zmg))6ARZ6O| z(9Ee!up>JI;1lWoU;>K^^Lp0HJNp?D$F(M8Cj4ZtGmj+S1D zRS^KFk@!WC8BLhhyP9rob~Q~Gx|bq)gtHRfu?vAgOPl$&t7gg;NAp=>ai|kDHFcMA z2(p;|D(jBB^=d<~N;g%TRJxW*`njxA;{|3 z=obwRQ6@O3?oP8sgbrvE3s~=s9O)*DCE*~lTHu7Pr#n`pE#vmgX19o2 z_&*;m)ud#yVTnOsM{2T;!}YOaZ9xJ%ZV}rEzHIv0*r7Jb<+FD~x;C(cFC@o{W<|^P zEP0sS-#YfEK<>WPq*K82qHqbx`miTAvqi)E2P#=YfkQ-lH!<%jW7y~oKk!6o#>q&V zM_5PO2-n(Am-31iH)Q?&{YW26N?2RHS3WImfRxNQro!CFzLrLOhYxS_1|QeSY03Y876$sE+efF5u9-35Us|h z8F|1ZImaS9c@{oA+;Zm!FVcBnQt3N($9Yv?G&p#K1oKR!s1a==BGB0**r8F0ZT6!j z4|EX5rzaJxip4%sQ9P$tp~piZkonOxg4Operator UIChainlink
\ No newline at end of file diff --git a/core/web/assets/index.html.gz b/core/web/assets/index.html.gz new file mode 100644 index 0000000000000000000000000000000000000000..24cc3068f6e66871c3c3479164b48ea3e892d6ee GIT binary patch literal 420 zcmV;V0bBkbiwFP!000021C^3bZ`3dl#lMQN#EEVk=(bC%I6YKCDiT7X^uTdqPc{bs zi9EAu_uJzn+m(=z5QjMNi{I~!$8O%(WcWCu7&!R0IgJRmZ2~d~Ge9O}EuX%B+I*Di zBu5CS<>c^rOqr!HDKf^g?Aci!w8hC8+$@s|7acqB8#3Tgzn>ZG*kk*3#0;FWczS5m zDmC84Um~N|l7>Py2Ntftr5G~yS`N%3-6}-^%Fhy-!Eoim-n~>2S(S2KoEcSd-NAvA zHYto5iQay=?^6!Ia{)`tpUA$@sM@Er_Xwk-su-0ay6Yi0f7IVnmpI*C*7e1&5Ak zJ+@6uC;3M@h=^zfCxH<x2 literal 0 HcmV?d00001 diff --git a/core/web/assets/main.b0b6f79f7f4a94560e37.js b/core/web/assets/main.b0b6f79f7f4a94560e37.js new file mode 100644 index 0000000000..6c9f23d1cc --- /dev/null +++ b/core/web/assets/main.b0b6f79f7f4a94560e37.js @@ -0,0 +1,187 @@ +(()=>{var __webpack_modules__={23564(e,t,n){"use strict";n.d(t,{Jh:()=>u,ZT:()=>i,_T:()=>o,ev:()=>c,mG:()=>s,pi:()=>a});/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n}function s(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||(n=Promise))(function(n,a){function o(e){try{u(r.next(e))}catch(t){a(t)}}function s(e){try{u(r.throw(e))}catch(t){a(t)}}function u(e){e.done?n(e.value):i(e.value).then(o,s)}u((r=r.apply(e,t||[])).next())})}function u(e,t){var n,r,i,a,o={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return a={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function s(e){return function(t){return u([e,t])}}function u(a){if(n)throw TypeError("Generator is already executing.");for(;o;)try{if(n=1,r&&(i=2&a[0]?r.return:a[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,a[1])).done)return i;switch(r=0,i&&(a=[2&a[0],i.value]),a[0]){case 0:case 1:i=a;break;case 4:return o.label++,{value:a[1],done:!1};case 5:o.label++,r=a[1],a=[0];continue;case 7:a=o.ops.pop(),o.trys.pop();continue;default:if(!(i=(i=o.trys).length>0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}e.exports=i,e.exports.default=e.exports,e.exports.__esModule=!0},37316(e){function t(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}e.exports=t,e.exports.default=e.exports,e.exports.__esModule=!0},78585(e,t,n){var r=n(50008).default,i=n(81506);function a(e,t){return t&&("object"===r(t)||"function"==typeof t)?t:i(e)}e.exports=a,e.exports.default=e.exports,e.exports.__esModule=!0},99489(e){function t(n,r){return e.exports=t=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},e.exports.default=e.exports,e.exports.__esModule=!0,t(n,r)}e.exports=t,e.exports.default=e.exports,e.exports.__esModule=!0},319(e,t,n){var r=n(23646),i=n(46860),a=n(60379),o=n(98206);function s(e){return r(e)||i(e)||a(e)||o()}e.exports=s,e.exports.default=e.exports,e.exports.__esModule=!0},50008(e){function t(n){return"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?(e.exports=t=function(e){return typeof e},e.exports.default=e.exports,e.exports.__esModule=!0):(e.exports=t=function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e.exports.default=e.exports,e.exports.__esModule=!0),t(n)}e.exports=t,e.exports.default=e.exports,e.exports.__esModule=!0},60379(e,t,n){var r=n(67228);function i(e,t){if(e){if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return r(e,t)}}e.exports=i,e.exports.default=e.exports,e.exports.__esModule=!0},98925(e,t,n){"use strict";let r=n(98633),i=n.g.Date;class a extends i{constructor(e){super(e),this.isDate=!0}toISOString(){return`${this.getUTCFullYear()}-${r(2,this.getUTCMonth()+1)}-${r(2,this.getUTCDate())}`}}e.exports=e=>{let t=new a(e);if(!isNaN(t))return t;throw TypeError("Invalid Datetime")}},86595(e,t,n){"use strict";let r=n(98633);class i extends Date{constructor(e){super(e+"Z"),this.isFloating=!0}toISOString(){let e=`${this.getUTCFullYear()}-${r(2,this.getUTCMonth()+1)}-${r(2,this.getUTCDate())}`,t=`${r(2,this.getUTCHours())}:${r(2,this.getUTCMinutes())}:${r(2,this.getUTCSeconds())}.${r(3,this.getUTCMilliseconds())}`;return`${e}T${t}`}}e.exports=e=>{let t=new i(e);if(!isNaN(t))return t;throw TypeError("Invalid Datetime")}},76114(e){"use strict";e.exports=e=>{let t=new Date(e);if(!isNaN(t))return t;throw TypeError("Invalid Datetime")}},99439(e,t,n){"use strict";let r=n(98633);class i extends Date{constructor(e){super(`0000-01-01T${e}Z`),this.isTime=!0}toISOString(){return`${r(2,this.getUTCHours())}:${r(2,this.getUTCMinutes())}:${r(2,this.getUTCSeconds())}.${r(3,this.getUTCMilliseconds())}`}}e.exports=e=>{let t=new i(e);if(!isNaN(t))return t;throw TypeError("Invalid Datetime")}},98633(e){"use strict";e.exports=(e,t)=>{for(t=String(t);t.length{let t=new TomlError(e.message);return t.code=e.code,t.wrapped=e,t},module.exports.TomlError=TomlError;let createDateTime=__webpack_require__(76114),createDateTimeFloat=__webpack_require__(86595),createDate=__webpack_require__(98925),createTime=__webpack_require__(99439),CTRL_I=9,CTRL_J=10,CTRL_M=13,CTRL_CHAR_BOUNDARY=31,CHAR_SP=32,CHAR_QUOT=34,CHAR_NUM=35,CHAR_APOS=39,CHAR_PLUS=43,CHAR_COMMA=44,CHAR_HYPHEN=45,CHAR_PERIOD=46,CHAR_0=48,CHAR_1=49,CHAR_7=55,CHAR_9=57,CHAR_COLON=58,CHAR_EQUALS=61,CHAR_A=65,CHAR_E=69,CHAR_F=70,CHAR_T=84,CHAR_U=85,CHAR_Z=90,CHAR_LOWBAR=95,CHAR_a=97,CHAR_b=98,CHAR_e=101,CHAR_f=102,CHAR_i=105,CHAR_l=108,CHAR_n=110,CHAR_o=111,CHAR_r=114,CHAR_s=115,CHAR_t=116,CHAR_u=117,CHAR_x=120,CHAR_z=122,CHAR_LCUB=123,CHAR_RCUB=125,CHAR_LSQB=91,CHAR_BSOL=92,CHAR_RSQB=93,CHAR_DEL=127,SURROGATE_FIRST=55296,SURROGATE_LAST=57343,escapes={[CHAR_b]:"\b",[CHAR_t]:" ",[CHAR_n]:"\n",[CHAR_f]:"\f",[CHAR_r]:"\r",[CHAR_QUOT]:'"',[CHAR_BSOL]:"\\"};function isDigit(e){return e>=CHAR_0&&e<=CHAR_9}function isHexit(e){return e>=CHAR_A&&e<=CHAR_F||e>=CHAR_a&&e<=CHAR_f||e>=CHAR_0&&e<=CHAR_9}function isBit(e){return e===CHAR_1||e===CHAR_0}function isOctit(e){return e>=CHAR_0&&e<=CHAR_7}function isAlphaNumQuoteHyphen(e){return e>=CHAR_A&&e<=CHAR_Z||e>=CHAR_a&&e<=CHAR_z||e>=CHAR_0&&e<=CHAR_9||e===CHAR_APOS||e===CHAR_QUOT||e===CHAR_LOWBAR||e===CHAR_HYPHEN}function isAlphaNumHyphen(e){return e>=CHAR_A&&e<=CHAR_Z||e>=CHAR_a&&e<=CHAR_z||e>=CHAR_0&&e<=CHAR_9||e===CHAR_LOWBAR||e===CHAR_HYPHEN}let _type=Symbol("type"),_declared=Symbol("declared"),hasOwnProperty=Object.prototype.hasOwnProperty,defineProperty=Object.defineProperty,descriptor={configurable:!0,enumerable:!0,writable:!0,value:void 0};function hasKey(e,t){return!!hasOwnProperty.call(e,t)||("__proto__"===t&&defineProperty(e,"__proto__",descriptor),!1)}let INLINE_TABLE=Symbol("inline-table");function InlineTable(){return Object.defineProperties({},{[_type]:{value:INLINE_TABLE}})}function isInlineTable(e){return null!==e&&"object"==typeof e&&e[_type]===INLINE_TABLE}let TABLE=Symbol("table");function Table(){return Object.defineProperties({},{[_type]:{value:TABLE},[_declared]:{value:!1,writable:!0}})}function isTable(e){return null!==e&&"object"==typeof e&&e[_type]===TABLE}let _contentType=Symbol("content-type"),INLINE_LIST=Symbol("inline-list");function InlineList(e){return Object.defineProperties([],{[_type]:{value:INLINE_LIST},[_contentType]:{value:e}})}function isInlineList(e){return null!==e&&"object"==typeof e&&e[_type]===INLINE_LIST}let LIST=Symbol("list");function List(){return Object.defineProperties([],{[_type]:{value:LIST}})}function isList(e){return null!==e&&"object"==typeof e&&e[_type]===LIST}let _custom;try{let utilInspect=eval("require('util').inspect");_custom=utilInspect.custom}catch(_){}let _inspect=_custom||"inspect";class BoxedBigInt{constructor(e){try{this.value=__webpack_require__.g.BigInt.asIntN(64,e)}catch(t){this.value=null}Object.defineProperty(this,_type,{value:INTEGER})}isNaN(){return null===this.value}toString(){return String(this.value)}[_inspect](){return`[BigInt: ${this.toString()}]}`}valueOf(){return this.value}}let INTEGER=Symbol("integer");function Integer(e){let t=Number(e);return(Object.is(t,-0)&&(t=0),__webpack_require__.g.BigInt&&!Number.isSafeInteger(t))?new BoxedBigInt(e):Object.defineProperties(new Number(t),{isNaN:{value:function(){return isNaN(this)}},[_type]:{value:INTEGER},[_inspect]:{value:()=>`[Integer: ${e}]`}})}function isInteger(e){return null!==e&&"object"==typeof e&&e[_type]===INTEGER}let FLOAT=Symbol("float");function Float(e){return Object.defineProperties(new Number(e),{[_type]:{value:FLOAT},[_inspect]:{value:()=>`[Float: ${e}]`}})}function isFloat(e){return null!==e&&"object"==typeof e&&e[_type]===FLOAT}function tomlType(e){let t=typeof e;if("object"===t){if(null===e)return"null";if(e instanceof Date)return"datetime";if(_type in e)switch(e[_type]){case INLINE_TABLE:return"inline-table";case INLINE_LIST:return"inline-list";case TABLE:return"table";case LIST:return"list";case FLOAT:return"float";case INTEGER:return"integer"}}return t}function makeParserClass(e){class t extends e{constructor(){super(),this.ctx=this.obj=Table()}atEndOfWord(){return this.char===CHAR_NUM||this.char===CTRL_I||this.char===CHAR_SP||this.atEndOfLine()}atEndOfLine(){return this.char===e.END||this.char===CTRL_J||this.char===CTRL_M}parseStart(){if(this.char===e.END)return null;if(this.char===CHAR_LSQB)return this.call(this.parseTableOrList);if(this.char===CHAR_NUM)return this.call(this.parseComment);if(this.char===CTRL_J||this.char===CHAR_SP||this.char===CTRL_I||this.char===CTRL_M)return null;if(isAlphaNumQuoteHyphen(this.char))return this.callNow(this.parseAssignStatement);else throw this.error(new TomlError(`Unknown character "${this.char}"`))}parseWhitespaceToEOL(){if(this.char===CHAR_SP||this.char===CTRL_I||this.char===CTRL_M)return null;if(this.char===CHAR_NUM)return this.goto(this.parseComment);if(this.char===e.END||this.char===CTRL_J)return this.return();throw this.error(new TomlError("Unexpected character, expected only whitespace or comments till end of line"))}parseAssignStatement(){return this.callNow(this.parseAssign,this.recordAssignStatement)}recordAssignStatement(e){let t=this.ctx,n=e.key.pop();for(let r of e.key){if(hasKey(t,r)&&!isTable(t[r]))throw this.error(new TomlError("Can't redefine existing key"));t=t[r]=t[r]||Table()}if(hasKey(t,n))throw this.error(new TomlError("Can't redefine existing key"));return t[_declared]=!0,isInteger(e.value)||isFloat(e.value)?t[n]=e.value.valueOf():t[n]=e.value,this.goto(this.parseWhitespaceToEOL)}parseAssign(){return this.callNow(this.parseKeyword,this.recordAssignKeyword)}recordAssignKeyword(e){return this.state.resultTable?this.state.resultTable.push(e):this.state.resultTable=[e],this.goto(this.parseAssignKeywordPreDot)}parseAssignKeywordPreDot(){return this.char===CHAR_PERIOD?this.next(this.parseAssignKeywordPostDot):this.char!==CHAR_SP&&this.char!==CTRL_I?this.goto(this.parseAssignEqual):void 0}parseAssignKeywordPostDot(){if(this.char!==CHAR_SP&&this.char!==CTRL_I)return this.callNow(this.parseKeyword,this.recordAssignKeyword)}parseAssignEqual(){if(this.char===CHAR_EQUALS)return this.next(this.parseAssignPreValue);throw this.error(new TomlError('Invalid character, expected "="'))}parseAssignPreValue(){return this.char===CHAR_SP||this.char===CTRL_I?null:this.callNow(this.parseValue,this.recordAssignValue)}recordAssignValue(e){return this.returnNow({key:this.state.resultTable,value:e})}parseComment(){do{if(this.char===e.END||this.char===CTRL_J)return this.return();if(this.char===CHAR_DEL||this.char<=CTRL_CHAR_BOUNDARY&&this.char!==CTRL_I)throw this.errorControlCharIn("comments")}while(this.nextChar())}parseTableOrList(){if(this.char!==CHAR_LSQB)return this.goto(this.parseTable);this.next(this.parseList)}parseTable(){return this.ctx=this.obj,this.goto(this.parseTableNext)}parseTableNext(){return this.char===CHAR_SP||this.char===CTRL_I?null:this.callNow(this.parseKeyword,this.parseTableMore)}parseTableMore(e){if(this.char===CHAR_SP||this.char===CTRL_I)return null;if(this.char===CHAR_RSQB){if(hasKey(this.ctx,e)&&(!isTable(this.ctx[e])||this.ctx[e][_declared]))throw this.error(new TomlError("Can't redefine existing key"));return this.ctx=this.ctx[e]=this.ctx[e]||Table(),this.ctx[_declared]=!0,this.next(this.parseWhitespaceToEOL)}if(this.char===CHAR_PERIOD){if(hasKey(this.ctx,e)){if(isTable(this.ctx[e]))this.ctx=this.ctx[e];else if(isList(this.ctx[e]))this.ctx=this.ctx[e][this.ctx[e].length-1];else throw this.error(new TomlError("Can't redefine existing key"))}else this.ctx=this.ctx[e]=Table();return this.next(this.parseTableNext)}throw this.error(new TomlError("Unexpected character, expected whitespace, . or ]"))}parseList(){return this.ctx=this.obj,this.goto(this.parseListNext)}parseListNext(){return this.char===CHAR_SP||this.char===CTRL_I?null:this.callNow(this.parseKeyword,this.parseListMore)}parseListMore(e){if(this.char===CHAR_SP||this.char===CTRL_I)return null;if(this.char===CHAR_RSQB){if(hasKey(this.ctx,e)||(this.ctx[e]=List()),isInlineList(this.ctx[e]))throw this.error(new TomlError("Can't extend an inline array"));if(isList(this.ctx[e])){let t=Table();this.ctx[e].push(t),this.ctx=t}else throw this.error(new TomlError("Can't redefine an existing key"));return this.next(this.parseListEnd)}if(this.char===CHAR_PERIOD){if(hasKey(this.ctx,e)){if(isInlineList(this.ctx[e]))throw this.error(new TomlError("Can't extend an inline array"));if(isInlineTable(this.ctx[e]))throw this.error(new TomlError("Can't extend an inline table"));else if(isList(this.ctx[e]))this.ctx=this.ctx[e][this.ctx[e].length-1];else if(isTable(this.ctx[e]))this.ctx=this.ctx[e];else throw this.error(new TomlError("Can't redefine an existing key"))}else this.ctx=this.ctx[e]=Table();return this.next(this.parseListNext)}throw this.error(new TomlError("Unexpected character, expected whitespace, . or ]"))}parseListEnd(e){if(this.char===CHAR_RSQB)return this.next(this.parseWhitespaceToEOL);throw this.error(new TomlError("Unexpected character, expected whitespace, . or ]"))}parseValue(){if(this.char===e.END)throw this.error(new TomlError("Key without value"));if(this.char===CHAR_QUOT)return this.next(this.parseDoubleString);if(this.char===CHAR_APOS)return this.next(this.parseSingleString);if(this.char===CHAR_HYPHEN||this.char===CHAR_PLUS)return this.goto(this.parseNumberSign);if(this.char===CHAR_i)return this.next(this.parseInf);if(this.char===CHAR_n)return this.next(this.parseNan);if(isDigit(this.char))return this.goto(this.parseNumberOrDateTime);else if(this.char===CHAR_t||this.char===CHAR_f)return this.goto(this.parseBoolean);else if(this.char===CHAR_LSQB)return this.call(this.parseInlineList,this.recordValue);else if(this.char===CHAR_LCUB)return this.call(this.parseInlineTable,this.recordValue);else throw this.error(new TomlError("Unexpected character, expecting string, number, datetime, boolean, inline array or inline table"))}recordValue(e){return this.returnNow(e)}parseInf(){if(this.char===CHAR_n)return this.next(this.parseInf2);throw this.error(new TomlError('Unexpected character, expected "inf", "+inf" or "-inf"'))}parseInf2(){if(this.char===CHAR_f)return"-"===this.state.buf?this.return(-1/0):this.return(1/0);throw this.error(new TomlError('Unexpected character, expected "inf", "+inf" or "-inf"'))}parseNan(){if(this.char===CHAR_a)return this.next(this.parseNan2);throw this.error(new TomlError('Unexpected character, expected "nan"'))}parseNan2(){if(this.char===CHAR_n)return this.return(NaN);throw this.error(new TomlError('Unexpected character, expected "nan"'))}parseKeyword(){return this.char===CHAR_QUOT?this.next(this.parseBasicString):this.char===CHAR_APOS?this.next(this.parseLiteralString):this.goto(this.parseBareKey)}parseBareKey(){do{if(this.char===e.END)throw this.error(new TomlError("Key ended without value"));if(isAlphaNumHyphen(this.char))this.consume();else if(0!==this.state.buf.length)return this.returnNow();else throw this.error(new TomlError("Empty bare keys are not allowed"))}while(this.nextChar())}parseSingleString(){return this.char===CHAR_APOS?this.next(this.parseLiteralMultiStringMaybe):this.goto(this.parseLiteralString)}parseLiteralString(){do{if(this.char===CHAR_APOS)return this.return();if(this.atEndOfLine())throw this.error(new TomlError("Unterminated string"));if(this.char===CHAR_DEL||this.char<=CTRL_CHAR_BOUNDARY&&this.char!==CTRL_I)throw this.errorControlCharIn("strings");else this.consume()}while(this.nextChar())}parseLiteralMultiStringMaybe(){return this.char===CHAR_APOS?this.next(this.parseLiteralMultiString):this.returnNow()}parseLiteralMultiString(){return this.char===CTRL_M?null:this.char===CTRL_J?this.next(this.parseLiteralMultiStringContent):this.goto(this.parseLiteralMultiStringContent)}parseLiteralMultiStringContent(){do{if(this.char===CHAR_APOS)return this.next(this.parseLiteralMultiEnd);if(this.char===e.END)throw this.error(new TomlError("Unterminated multi-line string"));if(this.char===CHAR_DEL||this.char<=CTRL_CHAR_BOUNDARY&&this.char!==CTRL_I&&this.char!==CTRL_J&&this.char!==CTRL_M)throw this.errorControlCharIn("strings");else this.consume()}while(this.nextChar())}parseLiteralMultiEnd(){return this.char===CHAR_APOS?this.next(this.parseLiteralMultiEnd2):(this.state.buf+="'",this.goto(this.parseLiteralMultiStringContent))}parseLiteralMultiEnd2(){return this.char===CHAR_APOS?this.next(this.parseLiteralMultiEnd3):(this.state.buf+="''",this.goto(this.parseLiteralMultiStringContent))}parseLiteralMultiEnd3(){return this.char===CHAR_APOS?(this.state.buf+="'",this.next(this.parseLiteralMultiEnd4)):this.returnNow()}parseLiteralMultiEnd4(){return this.char===CHAR_APOS?(this.state.buf+="'",this.return()):this.returnNow()}parseDoubleString(){return this.char===CHAR_QUOT?this.next(this.parseMultiStringMaybe):this.goto(this.parseBasicString)}parseBasicString(){do{if(this.char===CHAR_BSOL)return this.call(this.parseEscape,this.recordEscapeReplacement);if(this.char===CHAR_QUOT)return this.return();if(this.atEndOfLine())throw this.error(new TomlError("Unterminated string"));else if(this.char===CHAR_DEL||this.char<=CTRL_CHAR_BOUNDARY&&this.char!==CTRL_I)throw this.errorControlCharIn("strings");else this.consume()}while(this.nextChar())}recordEscapeReplacement(e){return this.state.buf+=e,this.goto(this.parseBasicString)}parseMultiStringMaybe(){return this.char===CHAR_QUOT?this.next(this.parseMultiString):this.returnNow()}parseMultiString(){return this.char===CTRL_M?null:this.char===CTRL_J?this.next(this.parseMultiStringContent):this.goto(this.parseMultiStringContent)}parseMultiStringContent(){do{if(this.char===CHAR_BSOL)return this.call(this.parseMultiEscape,this.recordMultiEscapeReplacement);if(this.char===CHAR_QUOT)return this.next(this.parseMultiEnd);if(this.char===e.END)throw this.error(new TomlError("Unterminated multi-line string"));else if(this.char===CHAR_DEL||this.char<=CTRL_CHAR_BOUNDARY&&this.char!==CTRL_I&&this.char!==CTRL_J&&this.char!==CTRL_M)throw this.errorControlCharIn("strings");else this.consume()}while(this.nextChar())}errorControlCharIn(e){let t="\\u00";return this.char<16&&(t+="0"),t+=this.char.toString(16),this.error(new TomlError(`Control characters (codes < 0x1f and 0x7f) are not allowed in ${e}, use ${t} instead`))}recordMultiEscapeReplacement(e){return this.state.buf+=e,this.goto(this.parseMultiStringContent)}parseMultiEnd(){return this.char===CHAR_QUOT?this.next(this.parseMultiEnd2):(this.state.buf+='"',this.goto(this.parseMultiStringContent))}parseMultiEnd2(){return this.char===CHAR_QUOT?this.next(this.parseMultiEnd3):(this.state.buf+='""',this.goto(this.parseMultiStringContent))}parseMultiEnd3(){return this.char===CHAR_QUOT?(this.state.buf+='"',this.next(this.parseMultiEnd4)):this.returnNow()}parseMultiEnd4(){return this.char===CHAR_QUOT?(this.state.buf+='"',this.return()):this.returnNow()}parseMultiEscape(){return this.char===CTRL_M||this.char===CTRL_J?this.next(this.parseMultiTrim):this.char===CHAR_SP||this.char===CTRL_I?this.next(this.parsePreMultiTrim):this.goto(this.parseEscape)}parsePreMultiTrim(){if(this.char===CHAR_SP||this.char===CTRL_I)return null;if(this.char===CTRL_M||this.char===CTRL_J)return this.next(this.parseMultiTrim);throw this.error(new TomlError("Can't escape whitespace"))}parseMultiTrim(){return this.char===CTRL_J||this.char===CHAR_SP||this.char===CTRL_I||this.char===CTRL_M?null:this.returnNow()}parseEscape(){if(this.char in escapes)return this.return(escapes[this.char]);if(this.char===CHAR_u)return this.call(this.parseSmallUnicode,this.parseUnicodeReturn);if(this.char===CHAR_U)return this.call(this.parseLargeUnicode,this.parseUnicodeReturn);throw this.error(new TomlError("Unknown escape character: "+this.char))}parseUnicodeReturn(e){try{let t=parseInt(e,16);if(t>=SURROGATE_FIRST&&t<=SURROGATE_LAST)throw this.error(new TomlError("Invalid unicode, character in range 0xD800 - 0xDFFF is reserved"));return this.returnNow(String.fromCodePoint(t))}catch(n){throw this.error(TomlError.wrap(n))}}parseSmallUnicode(){if(isHexit(this.char)){if(this.consume(),this.state.buf.length>=4)return this.return()}else throw this.error(new TomlError("Invalid character in unicode sequence, expected hex"))}parseLargeUnicode(){if(isHexit(this.char)){if(this.consume(),this.state.buf.length>=8)return this.return()}else throw this.error(new TomlError("Invalid character in unicode sequence, expected hex"))}parseNumberSign(){return this.consume(),this.next(this.parseMaybeSignedInfOrNan)}parseMaybeSignedInfOrNan(){return this.char===CHAR_i?this.next(this.parseInf):this.char===CHAR_n?this.next(this.parseNan):this.callNow(this.parseNoUnder,this.parseNumberIntegerStart)}parseNumberIntegerStart(){return this.char===CHAR_0?(this.consume(),this.next(this.parseNumberIntegerExponentOrDecimal)):this.goto(this.parseNumberInteger)}parseNumberIntegerExponentOrDecimal(){return this.char===CHAR_PERIOD?(this.consume(),this.call(this.parseNoUnder,this.parseNumberFloat)):this.char===CHAR_E||this.char===CHAR_e?(this.consume(),this.next(this.parseNumberExponentSign)):this.returnNow(Integer(this.state.buf))}parseNumberInteger(){if(isDigit(this.char))this.consume();else{if(this.char===CHAR_LOWBAR)return this.call(this.parseNoUnder);if(this.char===CHAR_E||this.char===CHAR_e)return this.consume(),this.next(this.parseNumberExponentSign);if(this.char===CHAR_PERIOD)return this.consume(),this.call(this.parseNoUnder,this.parseNumberFloat);let e=Integer(this.state.buf);if(!e.isNaN())return this.returnNow(e);throw this.error(new TomlError("Invalid number"))}}parseNoUnder(){if(this.char===CHAR_LOWBAR||this.char===CHAR_PERIOD||this.char===CHAR_E||this.char===CHAR_e)throw this.error(new TomlError("Unexpected character, expected digit"));if(this.atEndOfWord())throw this.error(new TomlError("Incomplete number"));return this.returnNow()}parseNoUnderHexOctBinLiteral(){if(this.char===CHAR_LOWBAR||this.char===CHAR_PERIOD)throw this.error(new TomlError("Unexpected character, expected digit"));if(this.atEndOfWord())throw this.error(new TomlError("Incomplete number"));return this.returnNow()}parseNumberFloat(){if(this.char===CHAR_LOWBAR)return this.call(this.parseNoUnder,this.parseNumberFloat);if(isDigit(this.char))this.consume();else if(this.char===CHAR_E||this.char===CHAR_e)return this.consume(),this.next(this.parseNumberExponentSign);else return this.returnNow(Float(this.state.buf))}parseNumberExponentSign(){if(isDigit(this.char))return this.goto(this.parseNumberExponent);if(this.char===CHAR_HYPHEN||this.char===CHAR_PLUS)this.consume(),this.call(this.parseNoUnder,this.parseNumberExponent);else throw this.error(new TomlError("Unexpected character, expected -, + or digit"))}parseNumberExponent(){if(isDigit(this.char))this.consume();else if(this.char===CHAR_LOWBAR)return this.call(this.parseNoUnder);else return this.returnNow(Float(this.state.buf))}parseNumberOrDateTime(){return this.char===CHAR_0?(this.consume(),this.next(this.parseNumberBaseOrDateTime)):this.goto(this.parseNumberOrDateTimeOnly)}parseNumberOrDateTimeOnly(){if(this.char===CHAR_LOWBAR)return this.call(this.parseNoUnder,this.parseNumberInteger);if(isDigit(this.char))this.consume(),this.state.buf.length>4&&this.next(this.parseNumberInteger);else if(this.char===CHAR_E||this.char===CHAR_e)return this.consume(),this.next(this.parseNumberExponentSign);else if(this.char===CHAR_PERIOD)return this.consume(),this.call(this.parseNoUnder,this.parseNumberFloat);else if(this.char===CHAR_HYPHEN)return this.goto(this.parseDateTime);else if(this.char===CHAR_COLON)return this.goto(this.parseOnlyTimeHour);else return this.returnNow(Integer(this.state.buf))}parseDateTimeOnly(){if(this.state.buf.length<4){if(isDigit(this.char))return this.consume();if(this.char===CHAR_COLON)return this.goto(this.parseOnlyTimeHour);throw this.error(new TomlError("Expected digit while parsing year part of a date"))}if(this.char===CHAR_HYPHEN)return this.goto(this.parseDateTime);throw this.error(new TomlError("Expected hyphen (-) while parsing year part of date"))}parseNumberBaseOrDateTime(){if(this.char===CHAR_b)return this.consume(),this.call(this.parseNoUnderHexOctBinLiteral,this.parseIntegerBin);if(this.char===CHAR_o)return this.consume(),this.call(this.parseNoUnderHexOctBinLiteral,this.parseIntegerOct);if(this.char===CHAR_x)return this.consume(),this.call(this.parseNoUnderHexOctBinLiteral,this.parseIntegerHex);if(this.char===CHAR_PERIOD)return this.goto(this.parseNumberInteger);if(isDigit(this.char))return this.goto(this.parseDateTimeOnly);else return this.returnNow(Integer(this.state.buf))}parseIntegerHex(){if(isHexit(this.char))this.consume();else{if(this.char===CHAR_LOWBAR)return this.call(this.parseNoUnderHexOctBinLiteral);let e=Integer(this.state.buf);if(!e.isNaN())return this.returnNow(e);throw this.error(new TomlError("Invalid number"))}}parseIntegerOct(){if(isOctit(this.char))this.consume();else{if(this.char===CHAR_LOWBAR)return this.call(this.parseNoUnderHexOctBinLiteral);let e=Integer(this.state.buf);if(!e.isNaN())return this.returnNow(e);throw this.error(new TomlError("Invalid number"))}}parseIntegerBin(){if(isBit(this.char))this.consume();else{if(this.char===CHAR_LOWBAR)return this.call(this.parseNoUnderHexOctBinLiteral);let e=Integer(this.state.buf);if(!e.isNaN())return this.returnNow(e);throw this.error(new TomlError("Invalid number"))}}parseDateTime(){if(this.state.buf.length<4)throw this.error(new TomlError("Years less than 1000 must be zero padded to four characters"));return this.state.result=this.state.buf,this.state.buf="",this.next(this.parseDateMonth)}parseDateMonth(){if(this.char===CHAR_HYPHEN){if(this.state.buf.length<2)throw this.error(new TomlError("Months less than 10 must be zero padded to two characters"));return this.state.result+="-"+this.state.buf,this.state.buf="",this.next(this.parseDateDay)}if(isDigit(this.char))this.consume();else throw this.error(new TomlError("Incomplete datetime"))}parseDateDay(){if(this.char===CHAR_T||this.char===CHAR_SP){if(this.state.buf.length<2)throw this.error(new TomlError("Days less than 10 must be zero padded to two characters"));return this.state.result+="-"+this.state.buf,this.state.buf="",this.next(this.parseStartTimeHour)}if(this.atEndOfWord())return this.returnNow(createDate(this.state.result+"-"+this.state.buf));if(isDigit(this.char))this.consume();else throw this.error(new TomlError("Incomplete datetime"))}parseStartTimeHour(){return this.atEndOfWord()?this.returnNow(createDate(this.state.result)):this.goto(this.parseTimeHour)}parseTimeHour(){if(this.char===CHAR_COLON){if(this.state.buf.length<2)throw this.error(new TomlError("Hours less than 10 must be zero padded to two characters"));return this.state.result+="T"+this.state.buf,this.state.buf="",this.next(this.parseTimeMin)}if(isDigit(this.char))this.consume();else throw this.error(new TomlError("Incomplete datetime"))}parseTimeMin(){if(this.state.buf.length<2&&isDigit(this.char))this.consume();else if(2===this.state.buf.length&&this.char===CHAR_COLON)return this.state.result+=":"+this.state.buf,this.state.buf="",this.next(this.parseTimeSec);else throw this.error(new TomlError("Incomplete datetime"))}parseTimeSec(){if(isDigit(this.char)){if(this.consume(),2===this.state.buf.length)return this.state.result+=":"+this.state.buf,this.state.buf="",this.next(this.parseTimeZoneOrFraction)}else throw this.error(new TomlError("Incomplete datetime"))}parseOnlyTimeHour(){if(this.char===CHAR_COLON){if(this.state.buf.length<2)throw this.error(new TomlError("Hours less than 10 must be zero padded to two characters"));return this.state.result=this.state.buf,this.state.buf="",this.next(this.parseOnlyTimeMin)}throw this.error(new TomlError("Incomplete time"))}parseOnlyTimeMin(){if(this.state.buf.length<2&&isDigit(this.char))this.consume();else if(2===this.state.buf.length&&this.char===CHAR_COLON)return this.state.result+=":"+this.state.buf,this.state.buf="",this.next(this.parseOnlyTimeSec);else throw this.error(new TomlError("Incomplete time"))}parseOnlyTimeSec(){if(isDigit(this.char)){if(this.consume(),2===this.state.buf.length)return this.next(this.parseOnlyTimeFractionMaybe)}else throw this.error(new TomlError("Incomplete time"))}parseOnlyTimeFractionMaybe(){if(this.state.result+=":"+this.state.buf,this.char!==CHAR_PERIOD)return this.return(createTime(this.state.result));this.state.buf="",this.next(this.parseOnlyTimeFraction)}parseOnlyTimeFraction(){if(isDigit(this.char))this.consume();else if(this.atEndOfWord()){if(0===this.state.buf.length)throw this.error(new TomlError("Expected digit in milliseconds"));return this.returnNow(createTime(this.state.result+"."+this.state.buf))}else throw this.error(new TomlError("Unexpected character in datetime, expected period (.), minus (-), plus (+) or Z"))}parseTimeZoneOrFraction(){if(this.char===CHAR_PERIOD)this.consume(),this.next(this.parseDateTimeFraction);else if(this.char===CHAR_HYPHEN||this.char===CHAR_PLUS)this.consume(),this.next(this.parseTimeZoneHour);else if(this.char===CHAR_Z)return this.consume(),this.return(createDateTime(this.state.result+this.state.buf));else if(this.atEndOfWord())return this.returnNow(createDateTimeFloat(this.state.result+this.state.buf));else throw this.error(new TomlError("Unexpected character in datetime, expected period (.), minus (-), plus (+) or Z"))}parseDateTimeFraction(){if(isDigit(this.char))this.consume();else if(1===this.state.buf.length)throw this.error(new TomlError("Expected digit in milliseconds"));else if(this.char===CHAR_HYPHEN||this.char===CHAR_PLUS)this.consume(),this.next(this.parseTimeZoneHour);else if(this.char===CHAR_Z)return this.consume(),this.return(createDateTime(this.state.result+this.state.buf));else if(this.atEndOfWord())return this.returnNow(createDateTimeFloat(this.state.result+this.state.buf));else throw this.error(new TomlError("Unexpected character in datetime, expected period (.), minus (-), plus (+) or Z"))}parseTimeZoneHour(){if(isDigit(this.char)){if(this.consume(),/\d\d$/.test(this.state.buf))return this.next(this.parseTimeZoneSep)}else throw this.error(new TomlError("Unexpected character in datetime, expected digit"))}parseTimeZoneSep(){if(this.char===CHAR_COLON)this.consume(),this.next(this.parseTimeZoneMin);else throw this.error(new TomlError("Unexpected character in datetime, expected colon"))}parseTimeZoneMin(){if(isDigit(this.char)){if(this.consume(),/\d\d$/.test(this.state.buf))return this.return(createDateTime(this.state.result+this.state.buf))}else throw this.error(new TomlError("Unexpected character in datetime, expected digit"))}parseBoolean(){return this.char===CHAR_t?(this.consume(),this.next(this.parseTrue_r)):this.char===CHAR_f?(this.consume(),this.next(this.parseFalse_a)):void 0}parseTrue_r(){if(this.char===CHAR_r)return this.consume(),this.next(this.parseTrue_u);throw this.error(new TomlError("Invalid boolean, expected true or false"))}parseTrue_u(){if(this.char===CHAR_u)return this.consume(),this.next(this.parseTrue_e);throw this.error(new TomlError("Invalid boolean, expected true or false"))}parseTrue_e(){if(this.char===CHAR_e)return this.return(!0);throw this.error(new TomlError("Invalid boolean, expected true or false"))}parseFalse_a(){if(this.char===CHAR_a)return this.consume(),this.next(this.parseFalse_l);throw this.error(new TomlError("Invalid boolean, expected true or false"))}parseFalse_l(){if(this.char===CHAR_l)return this.consume(),this.next(this.parseFalse_s);throw this.error(new TomlError("Invalid boolean, expected true or false"))}parseFalse_s(){if(this.char===CHAR_s)return this.consume(),this.next(this.parseFalse_e);throw this.error(new TomlError("Invalid boolean, expected true or false"))}parseFalse_e(){if(this.char===CHAR_e)return this.return(!1);throw this.error(new TomlError("Invalid boolean, expected true or false"))}parseInlineList(){if(this.char===CHAR_SP||this.char===CTRL_I||this.char===CTRL_M||this.char===CTRL_J)return null;if(this.char===e.END)throw this.error(new TomlError("Unterminated inline array"));return this.char===CHAR_NUM?this.call(this.parseComment):this.char===CHAR_RSQB?this.return(this.state.resultArr||InlineList()):this.callNow(this.parseValue,this.recordInlineListValue)}recordInlineListValue(e){return this.state.resultArr||(this.state.resultArr=InlineList(tomlType(e))),isFloat(e)||isInteger(e)?this.state.resultArr.push(e.valueOf()):this.state.resultArr.push(e),this.goto(this.parseInlineListNext)}parseInlineListNext(){if(this.char===CHAR_SP||this.char===CTRL_I||this.char===CTRL_M||this.char===CTRL_J)return null;if(this.char===CHAR_NUM)return this.call(this.parseComment);if(this.char===CHAR_COMMA)return this.next(this.parseInlineList);if(this.char===CHAR_RSQB)return this.goto(this.parseInlineList);throw this.error(new TomlError("Invalid character, expected whitespace, comma (,) or close bracket (])"))}parseInlineTable(){if(this.char===CHAR_SP||this.char===CTRL_I)return null;if(this.char===e.END||this.char===CHAR_NUM||this.char===CTRL_J||this.char===CTRL_M)throw this.error(new TomlError("Unterminated inline array"));return this.char===CHAR_RCUB?this.return(this.state.resultTable||InlineTable()):(this.state.resultTable||(this.state.resultTable=InlineTable()),this.callNow(this.parseAssign,this.recordInlineTableValue))}recordInlineTableValue(e){let t=this.state.resultTable,n=e.key.pop();for(let r of e.key){if(hasKey(t,r)&&(!isTable(t[r])||t[r][_declared]))throw this.error(new TomlError("Can't redefine existing key"));t=t[r]=t[r]||Table()}if(hasKey(t,n))throw this.error(new TomlError("Can't redefine existing key"));return isInteger(e.value)||isFloat(e.value)?t[n]=e.value.valueOf():t[n]=e.value,this.goto(this.parseInlineTableNext)}parseInlineTableNext(){if(this.char===CHAR_SP||this.char===CTRL_I)return null;if(this.char===e.END||this.char===CHAR_NUM||this.char===CTRL_J||this.char===CTRL_M)throw this.error(new TomlError("Unterminated inline array"));if(this.char===CHAR_COMMA)return this.next(this.parseInlineTablePostComma);if(this.char===CHAR_RCUB)return this.goto(this.parseInlineTable);throw this.error(new TomlError("Invalid character, expected whitespace, comma (,) or close bracket (])"))}parseInlineTablePostComma(){if(this.char===CHAR_SP||this.char===CTRL_I)return null;if(this.char===e.END||this.char===CHAR_NUM||this.char===CTRL_J||this.char===CTRL_M)throw this.error(new TomlError("Unterminated inline array"));if(this.char===CHAR_COMMA)throw this.error(new TomlError("Empty elements in inline tables are not permitted"));if(this.char!==CHAR_RCUB)return this.goto(this.parseInlineTable);throw this.error(new TomlError("Trailing commas in inline tables are not permitted"))}}return t}},90560(e,t,n){"use strict";e.exports=a;let r=n(8676),i=n(22418);function a(e,t){t||(t={});let n=0,a=t.blocksize||40960,o=new r;return new Promise((e,t)=>{setImmediate(s,n,a,e,t)});function s(t,n,r,a){if(t>=e.length)try{return r(o.finish())}catch(u){return a(i(u,e))}try{o.parse(e.slice(t,t+n)),setImmediate(s,t+n,n,r,a)}catch(c){a(i(c,e))}}}},22418(e){"use strict";function t(e,t){if(null==e.pos||null==e.line)return e;let n=e.message;if(n+=` at row ${e.line+1}, col ${e.col+1}, pos ${e.pos}: +`,t&&t.split){let r=t.split(/\n/),i=String(Math.min(r.length,e.line+3)).length,a=" ";for(;a.length "+r[o]+"\n",n+=a+" ";for(let u=0;u{let i,a=!1,o=!1;function s(){if(a=!0,!i)try{n(t.finish())}catch(e){r(e)}}function u(e){o=!0,r(e)}function c(){i=!0;let n;for(;null!==(n=e.read());)try{t.parse(n)}catch(r){return u(r)}if(i=!1,a)return s();o||e.once("readable",c)}e.once("end",s),e.once("error",u),c()})}function s(){let e=new i;return new r.Transform({objectMode:!0,transform(t,n,r){try{e.parse(t.toString(n))}catch(i){this.emit("error",i)}r()},flush(t){try{this.push(e.finish())}catch(n){this.emit("error",n)}t()}})}},56530(e,t,n){"use strict";e.exports=a;let r=n(8676),i=n(22418);function a(e){n.g.Buffer&&n.g.Buffer.isBuffer(e)&&(e=e.toString("utf8"));let t=new r;try{return t.parse(e),t.finish()}catch(a){throw i(a,e)}}},83512(e,t,n){"use strict";e.exports=n(56530),e.exports.async=n(90560),e.exports.stream=n(6435),e.exports.prettyError=n(22418)},36921(e){"use strict";function t(e){if(null===e)throw n("null");if(void 0===e)throw n("undefined");if("object"!=typeof e)throw n(typeof e);if("function"==typeof e.toJSON&&(e=e.toJSON()),null==e)return null;let t=u(e);if("table"!==t)throw n(t);return o("","",e)}function n(e){return Error("Can only stringify objects, not "+e)}function r(e){return Object.keys(e).filter(t=>s(e[t]))}function i(e){return Object.keys(e).filter(t=>!s(e[t]))}function a(e){let t=Array.isArray(e)?[]:Object.prototype.hasOwnProperty.call(e,"__proto__")?{["__proto__"]:void 0}:{};for(let n of Object.keys(e))!e[n]||"function"!=typeof e[n].toJSON||"toISOString"in e[n]?t[n]=e[n]:t[n]=e[n].toJSON();return t}function o(e,t,n){let o,s;o=r(n=a(n)),s=i(n);let l=[],f=t||"";o.forEach(e=>{var t=u(n[e]);"undefined"!==t&&"null"!==t&&l.push(f+c(e)+" = "+b(n[e],!0))}),l.length>0&&l.push("");let d=e&&o.length>0?t+" ":"";return s.forEach(t=>{l.push(S(e,d,t,n[t]))}),l.join("\n")}function s(e){switch(u(e)){case"undefined":case"null":case"integer":case"nan":case"float":case"boolean":case"string":case"datetime":return!0;case"array":return 0===e.length||"table"!==u(e[0]);case"table":return 0===Object.keys(e).length;default:return!1}}function u(e){if(void 0===e)return"undefined";if(null===e)return"null";if("bigint"==typeof e||Number.isInteger(e)&&!Object.is(e,-0))return"integer";if("number"==typeof e)return"float";if("boolean"==typeof e)return"boolean";else if("string"==typeof e)return"string";else if("toISOString"in e)return isNaN(e)?"undefined":"datetime";else if(Array.isArray(e))return"array";else return"table"}function c(e){let t=String(e);return/^[-A-Za-z0-9_]+$/.test(t)?t:l(t)}function l(e){return'"'+h(e).replace(/"/g,'\\"')+'"'}function f(e){return"'"+e+"'"}function d(e,t){for(;t.length"\\u"+d(4,e.codePointAt(0).toString(16)))}function p(e){let t=e.split(/\n/).map(e=>h(e).replace(/"(?="")/g,'\\"')).join("\n");return'"'===t.slice(-1)&&(t+="\\\n"),'"""\n'+t+'"""'}function b(e,t){let n=u(e);return"string"===n&&(t&&/\n/.test(e)?n="string-multiline":!/[\b\t\n\f\r']/.test(e)&&/"/.test(e)&&(n="string-literal")),m(e,n)}function m(e,t){switch(t||(t=u(e)),t){case"string-multiline":return p(e);case"string":return l(e);case"string-literal":return f(e);case"integer":return g(e);case"float":return v(e);case"boolean":return y(e);case"datetime":return w(e);case"array":return _(e.filter(e=>"null"!==u(e)&&"undefined"!==u(e)&&"nan"!==u(e)));case"table":return E(e);default:throw n(t)}}function g(e){return String(e).replace(/\B(?=(\d{3})+(?!\d))/g,"_")}function v(e){if(e===1/0)return"inf";if(e===-1/0)return"-inf";if(Object.is(e,NaN))return"nan";if(Object.is(e,-0))return"-0.0";let[t,n]=String(e).split(".");return g(t)+"."+n}function y(e){return String(e)}function w(e){return e.toISOString()}function _(e){e=a(e);let t="[",n=e.map(e=>m(e));return n.join(", ").length>60||/\n/.test(n)?t+="\n "+n.join(",\n ")+"\n":t+=" "+n.join(", ")+(n.length>0?" ":""),t+"]"}function E(e){e=a(e);let t=[];return Object.keys(e).forEach(n=>{t.push(c(n)+" = "+b(e[n],!1))}),"{ "+t.join(", ")+(t.length>0?" ":"")+"}"}function S(e,t,r,i){let a=u(i);if("array"===a)return k(e,t,r,i);if("table"===a)return x(e,t,r,i);throw n(a)}function k(e,t,r,i){i=a(i);let s=u(i[0]);if("table"!==s)throw n(s);let l=e+c(r),f="";return i.forEach(e=>{f.length>0&&(f+="\n"),f+=t+"[["+l+"]]\n",f+=o(l+".",t,e)}),f}function x(e,t,n,i){let a=e+c(n),s="";return r(i).length>0&&(s+=t+"["+a+"]\n"),s+o(a+".",t,i)}e.exports=t,e.exports.value=m},5022(e,t,n){"use strict";t.parse=n(83512),t.stringify=n(36921)},46515(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184)),c=r(n(78252)),l=n(98741),f=r(n(68821)),d=function(e){var t="light"===e.palette.type?e.palette.grey[100]:e.palette.grey[900];return{root:{display:"flex",flexDirection:"column",width:"100%",boxSizing:"border-box",zIndex:e.zIndex.appBar,flexShrink:0},positionFixed:{position:"fixed",top:0,left:"auto",right:0},positionAbsolute:{position:"absolute",top:0,left:"auto",right:0},positionSticky:{position:"sticky",top:0,left:"auto",right:0},positionStatic:{position:"static"},positionRelative:{position:"relative"},colorDefault:{backgroundColor:t,color:e.palette.getContrastText(t)},colorPrimary:{backgroundColor:e.palette.primary.main,color:e.palette.primary.contrastText},colorSecondary:{backgroundColor:e.palette.secondary.main,color:e.palette.secondary.contrastText}}};function h(e){var t,n=e.children,r=e.classes,c=e.className,d=e.color,h=e.position,p=(0,o.default)(e,["children","classes","className","color","position"]),b=(0,u.default)(r.root,r["position".concat((0,l.capitalize)(h))],(t={},(0,a.default)(t,r["color".concat((0,l.capitalize)(d))],"inherit"!==d),(0,a.default)(t,"mui-fixed","fixed"===h),t),c);return s.default.createElement(f.default,(0,i.default)({square:!0,component:"header",elevation:4,className:b},p),n)}t.styles=d,h.defaultProps={color:"primary",position:"fixed"};var p=(0,c.default)(d,{name:"MuiAppBar"})(h);t.default=p},95880(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(46515))},68477(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(59713)),a=r(n(67154)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184));n(55252);var c=r(n(78252)),l=function(e){return{root:{position:"relative",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0,width:40,height:40,fontFamily:e.typography.fontFamily,fontSize:e.typography.pxToRem(20),borderRadius:"50%",overflow:"hidden",userSelect:"none"},colorDefault:{color:e.palette.background.default,backgroundColor:"light"===e.palette.type?e.palette.grey[400]:e.palette.grey[600]},img:{width:"100%",height:"100%",textAlign:"center",objectFit:"cover"}}};function f(e){var t=e.alt,n=e.children,r=e.childrenClassName,c=e.classes,l=e.className,f=e.component,d=e.imgProps,h=e.sizes,p=e.src,b=e.srcSet,m=(0,o.default)(e,["alt","children","childrenClassName","classes","className","component","imgProps","sizes","src","srcSet"]),g=null,v=p||b;return g=v?s.default.createElement("img",(0,a.default)({alt:t,src:p,srcSet:b,sizes:h,className:c.img},d)):r&&s.default.isValidElement(n)?s.default.cloneElement(n,{className:(0,u.default)(r,n.props.className)}):n,s.default.createElement(f,(0,a.default)({className:(0,u.default)(c.root,c.system,(0,i.default)({},c.colorDefault,!v),l)},m),g)}t.styles=l,f.defaultProps={component:"div"};var d=(0,c.default)(l,{name:"MuiAvatar"})(f);t.default=d},90338(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(68477))},9211(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184)),c=r(n(78252)),l=r(n(46408)),f={root:{zIndex:-1,position:"fixed",right:0,bottom:0,top:0,left:0,backgroundColor:"rgba(0, 0, 0, 0.5)",WebkitTapHighlightColor:"transparent",touchAction:"none"},invisible:{backgroundColor:"transparent"}};function d(e){var t=e.classes,n=e.className,r=e.invisible,c=e.open,f=e.transitionDuration,d=(0,o.default)(e,["classes","className","invisible","open","transitionDuration"]);return s.default.createElement(l.default,(0,i.default)({in:c,timeout:f},d),s.default.createElement("div",{className:(0,u.default)(t.root,(0,a.default)({},t.invisible,r),n),"aria-hidden":"true"}))}t.styles=f,d.defaultProps={invisible:!1};var h=(0,c.default)(f,{name:"MuiBackdrop"})(d);t.default=h},14983(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(9211))},84732(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184));n(55252);var c=r(n(78252)),l=n(98741),f=10,d=function(e){return{root:{position:"relative",display:"inline-flex",verticalAlign:"middle"},badge:{display:"flex",flexDirection:"row",flexWrap:"wrap",justifyContent:"center",alignContent:"center",alignItems:"center",position:"absolute",top:0,right:0,boxSizing:"border-box",fontFamily:e.typography.fontFamily,fontWeight:e.typography.fontWeightMedium,fontSize:e.typography.pxToRem(12),minWidth:2*f,padding:"0 4px",height:2*f,borderRadius:f,backgroundColor:e.palette.color,color:e.palette.textColor,zIndex:1,transform:"scale(1) translate(50%, -50%)",transformOrigin:"100% 0%",transition:e.transitions.create("transform",{easing:e.transitions.easing.easeInOut,duration:e.transitions.duration.enteringScreen})},colorPrimary:{backgroundColor:e.palette.primary.main,color:e.palette.primary.contrastText},colorSecondary:{backgroundColor:e.palette.secondary.main,color:e.palette.secondary.contrastText},colorError:{backgroundColor:e.palette.error.main,color:e.palette.error.contrastText},invisible:{transition:e.transitions.create("transform",{easing:e.transitions.easing.easeInOut,duration:e.transitions.duration.leavingScreen}),transform:"scale(0) translate(50%, -50%)",transformOrigin:"100% 0%"},dot:{height:6,minWidth:6,padding:0}}};function h(e){var t,n=e.badgeContent,r=e.children,c=e.classes,f=e.className,d=e.color,h=e.component,p=e.invisible,b=e.showZero,m=e.max,g=e.variant,v=(0,o.default)(e,["badgeContent","children","classes","className","color","component","invisible","showZero","max","variant"]),y=p;null!=p||0!==Number(n)||b||(y=!0);var w=(0,u.default)(c.badge,(t={},(0,a.default)(t,c["color".concat((0,l.capitalize)(d))],"default"!==d),(0,a.default)(t,c.invisible,y),(0,a.default)(t,c.dot,"dot"===g),t)),_="";return"dot"!==g&&(_=n>m?"".concat(m,"+"):n),s.default.createElement(h,(0,i.default)({className:(0,u.default)(c.root,f)},v),r,s.default.createElement("span",{className:w},_))}t.styles=d,h.defaultProps={color:"default",component:"span",max:99,showZero:!1,variant:"standard"};var p=(0,c.default)(d,{name:"MuiBadge"})(h);t.default=p},70398(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(84732))},21783(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(59713)),a=r(n(6479)),o=r(n(67154)),s=r(n(67294));r(n(45697));var u=r(n(94184));n(55252);var c=r(n(78252)),l=n(59114),f=r(n(16070)),d=n(98741),h=function(e){return{root:(0,o.default)({lineHeight:1.75},e.typography.button,{boxSizing:"border-box",minWidth:64,padding:"6px 16px",borderRadius:e.shape.borderRadius,color:e.palette.text.primary,transition:e.transitions.create(["background-color","box-shadow","border"],{duration:e.transitions.duration.short}),"&:hover":{textDecoration:"none",backgroundColor:(0,l.fade)(e.palette.text.primary,e.palette.action.hoverOpacity),"@media (hover: none)":{backgroundColor:"transparent"},"&$disabled":{backgroundColor:"transparent"}},"&$disabled":{color:e.palette.action.disabled}}),label:{width:"100%",display:"inherit",alignItems:"inherit",justifyContent:"inherit"},text:{padding:"6px 8px"},textPrimary:{color:e.palette.primary.main,"&:hover":{backgroundColor:(0,l.fade)(e.palette.primary.main,e.palette.action.hoverOpacity),"@media (hover: none)":{backgroundColor:"transparent"}}},textSecondary:{color:e.palette.secondary.main,"&:hover":{backgroundColor:(0,l.fade)(e.palette.secondary.main,e.palette.action.hoverOpacity),"@media (hover: none)":{backgroundColor:"transparent"}}},flat:{},flatPrimary:{},flatSecondary:{},outlined:{padding:"5px 16px",border:"1px solid ".concat("light"===e.palette.type?"rgba(0, 0, 0, 0.23)":"rgba(255, 255, 255, 0.23)"),"&$disabled":{border:"1px solid ".concat(e.palette.action.disabled)}},outlinedPrimary:{color:e.palette.primary.main,border:"1px solid ".concat((0,l.fade)(e.palette.primary.main,.5)),"&:hover":{border:"1px solid ".concat(e.palette.primary.main),backgroundColor:(0,l.fade)(e.palette.primary.main,e.palette.action.hoverOpacity),"@media (hover: none)":{backgroundColor:"transparent"}}},outlinedSecondary:{color:e.palette.secondary.main,border:"1px solid ".concat((0,l.fade)(e.palette.secondary.main,.5)),"&:hover":{border:"1px solid ".concat(e.palette.secondary.main),backgroundColor:(0,l.fade)(e.palette.secondary.main,e.palette.action.hoverOpacity),"@media (hover: none)":{backgroundColor:"transparent"}},"&$disabled":{border:"1px solid ".concat(e.palette.action.disabled)}},contained:{color:e.palette.getContrastText(e.palette.grey[300]),backgroundColor:e.palette.grey[300],boxShadow:e.shadows[2],"&$focusVisible":{boxShadow:e.shadows[6]},"&:active":{boxShadow:e.shadows[8]},"&$disabled":{color:e.palette.action.disabled,boxShadow:e.shadows[0],backgroundColor:e.palette.action.disabledBackground},"&:hover":{backgroundColor:e.palette.grey.A100,"@media (hover: none)":{backgroundColor:e.palette.grey[300]},"&$disabled":{backgroundColor:e.palette.action.disabledBackground}}},containedPrimary:{color:e.palette.primary.contrastText,backgroundColor:e.palette.primary.main,"&:hover":{backgroundColor:e.palette.primary.dark,"@media (hover: none)":{backgroundColor:e.palette.primary.main}}},containedSecondary:{color:e.palette.secondary.contrastText,backgroundColor:e.palette.secondary.main,"&:hover":{backgroundColor:e.palette.secondary.dark,"@media (hover: none)":{backgroundColor:e.palette.secondary.main}}},raised:{},raisedPrimary:{},raisedSecondary:{},fab:{borderRadius:"50%",padding:0,minWidth:0,width:56,height:56,boxShadow:e.shadows[6],"&:active":{boxShadow:e.shadows[12]}},extendedFab:{borderRadius:24,padding:"0 16px",width:"auto",minWidth:48,height:48},focusVisible:{},disabled:{},colorInherit:{color:"inherit",borderColor:"currentColor"},mini:{width:40,height:40},sizeSmall:{padding:"4px 8px",minWidth:64,fontSize:e.typography.pxToRem(13)},sizeLarge:{padding:"8px 24px",fontSize:e.typography.pxToRem(15)},fullWidth:{width:"100%"}}};function p(e){var t,n=e.children,r=e.classes,c=e.className,l=e.color,h=e.disabled,p=e.disableFocusRipple,b=e.focusVisibleClassName,m=e.fullWidth,g=e.mini,v=e.size,y=e.variant,w=(0,a.default)(e,["children","classes","className","color","disabled","disableFocusRipple","focusVisibleClassName","fullWidth","mini","size","variant"]),_="fab"===y||"extendedFab"===y,E="contained"===y||"raised"===y,S="text"===y||"flat"===y,k=(0,u.default)(r.root,(t={},(0,i.default)(t,r.fab,_),(0,i.default)(t,r.mini,_&&g),(0,i.default)(t,r.extendedFab,"extendedFab"===y),(0,i.default)(t,r.text,S),(0,i.default)(t,r.textPrimary,S&&"primary"===l),(0,i.default)(t,r.textSecondary,S&&"secondary"===l),(0,i.default)(t,r.flat,S),(0,i.default)(t,r.flatPrimary,S&&"primary"===l),(0,i.default)(t,r.flatSecondary,S&&"secondary"===l),(0,i.default)(t,r.contained,E||_),(0,i.default)(t,r.containedPrimary,(E||_)&&"primary"===l),(0,i.default)(t,r.containedSecondary,(E||_)&&"secondary"===l),(0,i.default)(t,r.raised,E||_),(0,i.default)(t,r.raisedPrimary,(E||_)&&"primary"===l),(0,i.default)(t,r.raisedSecondary,(E||_)&&"secondary"===l),(0,i.default)(t,r.outlined,"outlined"===y),(0,i.default)(t,r.outlinedPrimary,"outlined"===y&&"primary"===l),(0,i.default)(t,r.outlinedSecondary,"outlined"===y&&"secondary"===l),(0,i.default)(t,r["size".concat((0,d.capitalize)(v))],"medium"!==v),(0,i.default)(t,r.disabled,h),(0,i.default)(t,r.fullWidth,m),(0,i.default)(t,r.colorInherit,"inherit"===l),t),c);return s.default.createElement(f.default,(0,o.default)({className:k,disabled:h,focusRipple:!p,focusVisibleClassName:(0,u.default)(r.focusVisible,b)},w),s.default.createElement("span",{className:r.label},n))}t.styles=h,p.defaultProps={color:"default",component:"button",disabled:!1,disableFocusRipple:!1,fullWidth:!1,mini:!1,size:"medium",type:"button",variant:"text"};var b=(0,c.default)(h,{name:"MuiButton"})(p);t.default=b},83638(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(21783))},74610(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(34575)),u=r(n(93913)),c=r(n(78585)),l=r(n(29754)),f=r(n(2205)),d=r(n(81506)),h=r(n(67294));r(n(45697));var p=r(n(73935)),b=r(n(94184));n(55252);var m=r(n(62614)),g=r(n(78252)),v=r(n(78582)),y=n(32252),w=r(n(65406)),_=r(n(83673)),E={root:{display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:"none",border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle","-moz-appearance":"none","-webkit-appearance":"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},"&$disabled":{pointerEvents:"none",cursor:"default"}},disabled:{},focusVisible:{}};t.styles=E;var S=function(e){function t(){(0,s.default)(this,t);for(var e,n,r=arguments.length,i=Array(r),a=0;a0&&void 0!==arguments[0]?arguments[0]:{},o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=arguments.length>2?arguments[2]:void 0,u=o.pulsate,c=void 0!==u&&u,l=o.center,f=void 0===l?n.props.center||o.pulsate:l,h=o.fakeElement,b=void 0!==h&&h;if("mousedown"===a.type&&n.ignoringMouseDown){n.ignoringMouseDown=!1;return}"touchstart"===a.type&&(n.ignoringMouseDown=!0);var m=b?null:p.default.findDOMNode((0,d.default)((0,d.default)(n))),g=m?m.getBoundingClientRect():{width:0,height:0,left:0,top:0};if(!f&&(0!==a.clientX||0!==a.clientY)&&(a.clientX||a.touches)){var v=a.clientX?a.clientX:a.touches[0].clientX,y=a.clientY?a.clientY:a.touches[0].clientY;t=Math.round(v-g.left),r=Math.round(y-g.top)}else t=Math.round(g.width/2),r=Math.round(g.height/2);if(f)(i=Math.sqrt((2*Math.pow(g.width,2)+Math.pow(g.height,2))/3))%2==0&&(i+=1);else{i=Math.sqrt(Math.pow(2*Math.max(Math.abs((m?m.clientWidth:0)-t),t)+2,2)+Math.pow(2*Math.max(Math.abs((m?m.clientHeight:0)-r),r)+2,2))}a.touches?(n.startTimerCommit=function(){n.startCommit({pulsate:c,rippleX:t,rippleY:r,rippleSize:i,cb:s})},n.startTimer=setTimeout(function(){n.startTimerCommit&&(n.startTimerCommit(),n.startTimerCommit=null)},w)):n.startCommit({pulsate:c,rippleX:t,rippleY:r,rippleSize:i,cb:s})},n.startCommit=function(e){var t=e.pulsate,r=e.rippleX,i=e.rippleY,a=e.rippleSize,s=e.cb;n.setState(function(e){return{nextKey:e.nextKey+1,ripples:[].concat((0,o.default)(e.ripples),[h.default.createElement(v.default,{key:e.nextKey,classes:n.props.classes,timeout:{exit:y,enter:y},pulsate:t,rippleX:r,rippleY:i,rippleSize:a})])}},s)},n.stop=function(e,t){clearTimeout(n.startTimer);var r=n.state.ripples;if("touchend"===e.type&&n.startTimerCommit){e.persist(),n.startTimerCommit(),n.startTimerCommit=null,n.startTimer=setTimeout(function(){n.stop(e,t)});return}n.startTimerCommit=null,r&&r.length&&n.setState({ripples:r.slice(1)},t)},n}return(0,f.default)(t,e),(0,u.default)(t,[{key:"componentWillUnmount",value:function(){clearTimeout(this.startTimer)}},{key:"render",value:function(){var e=this.props,t=(e.center,e.classes),n=e.className,r=(0,a.default)(e,["center","classes","className"]);return h.default.createElement(b.default,(0,i.default)({component:"span",enter:!0,exit:!0,className:(0,m.default)(t.root,n)},r),this.state.ripples)}}]),t}(h.default.PureComponent);E.defaultProps={center:!1};var S=(0,g.default)(_,{flip:!1,name:"MuiTouchRipple"})(E);t.default=S},83673(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=function(e,t,n,r){return function(i){r&&r.call(e,i);var a=!1;return i.defaultPrevented&&(a=!0),e.props.disableTouchRipple&&"Blur"!==t&&(a=!0),!a&&e.ripple&&e.ripple[n](i),"function"==typeof e.props["on".concat(t)]&&e.props["on".concat(t)](i),!0}};"undefined"==typeof window&&(n=function(){return function(){}});var r=n;t.default=r},32252(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.detectFocusVisible=s,t.listenForFocusKeys=f,r(n(42473));var i=r(n(16143)),a={focusKeyPressed:!1,keyUpEventTimeout:-1};function o(e){for(var t=e.activeElement;t&&t.shadowRoot&&t.shadowRoot.activeElement;)t=t.shadowRoot.activeElement;return t}function s(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1;e.focusVisibleTimeout=setTimeout(function(){var u=(0,i.default)(t),c=o(u);a.focusKeyPressed&&(c===t||t.contains(c))?n():r-1}var l=function(e){c(e)&&(a.focusKeyPressed=!0,clearTimeout(a.keyUpEventTimeout),a.keyUpEventTimeout=setTimeout(function(){a.focusKeyPressed=!1},500))};function f(e){e.addEventListener("keyup",l)}},16070(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(74610))},46003(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(67294));r(n(45697));var s=r(n(94184)),u=r(n(68821)),c=r(n(78252)),l={root:{overflow:"hidden"}};function f(e){var t=e.classes,n=e.className,r=e.raised,c=(0,a.default)(e,["classes","className","raised"]);return o.default.createElement(u.default,(0,i.default)({className:(0,s.default)(t.root,n),elevation:r?8:1},c))}t.styles=l,f.defaultProps={raised:!1};var d=(0,c.default)(l,{name:"MuiCard"})(f);t.default=d},82204(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(46003))},5780(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(67294));r(n(45697));var s=r(n(94184));n(55252);var u=r(n(78252)),c={root:{padding:16,"&:last-child":{paddingBottom:24}}};function l(e){var t=e.classes,n=e.className,r=e.component,u=(0,a.default)(e,["classes","className","component"]);return o.default.createElement(r,(0,i.default)({className:(0,s.default)(t.root,n)},u))}t.styles=c,l.defaultProps={component:"div"};var f=(0,u.default)(c,{name:"MuiCardContent"})(l);t.default=f},30060(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(5780))},50704(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(67294));r(n(45697));var s=r(n(94184));n(55252);var u=r(n(78252)),c=r(n(71426)),l={root:{display:"flex",alignItems:"center",padding:16},avatar:{flex:"0 0 auto",marginRight:16},action:{flex:"0 0 auto",alignSelf:"flex-start",marginTop:-8,marginRight:-8},content:{flex:"1 1 auto"},title:{},subheader:{}};function f(e){var t=e.action,n=e.avatar,r=e.classes,u=e.className,l=e.component,f=e.disableTypography,d=e.subheader,h=e.subheaderTypographyProps,p=e.title,b=e.titleTypographyProps,m=(0,a.default)(e,["action","avatar","classes","className","component","disableTypography","subheader","subheaderTypographyProps","title","titleTypographyProps"]),g=p;null==g||g.type===c.default||f||(g=o.default.createElement(c.default,(0,i.default)({variant:n?"body2":"headline",internalDeprecatedVariant:!0,className:r.title,component:"span"},b),g));var v=d;return null==v||v.type===c.default||f||(v=o.default.createElement(c.default,(0,i.default)({variant:n?"body2":"body1",className:r.subheader,color:"textSecondary",component:"span"},h),v)),o.default.createElement(l,(0,i.default)({className:(0,s.default)(r.root,u)},m),n&&o.default.createElement("div",{className:r.avatar},n),o.default.createElement("div",{className:r.content},g,v),t&&o.default.createElement("div",{className:r.action},t))}t.styles=l,f.defaultProps={component:"div",disableTypography:!1};var d=(0,u.default)(l,{name:"MuiCardHeader"})(f);t.default=d},52658(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(50704))},82811(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184)),c=r(n(85609)),l=r(n(42159)),f=r(n(41549)),d=r(n(61486)),h=n(98741),p=r(n(78252)),b=function(e){return{root:{color:e.palette.text.secondary},checked:{},disabled:{},indeterminate:{},colorPrimary:{"&$checked":{color:e.palette.primary.main},"&$disabled":{color:e.palette.action.disabled}},colorSecondary:{"&$checked":{color:e.palette.secondary.main},"&$disabled":{color:e.palette.action.disabled}}}};function m(e){var t=e.checkedIcon,n=e.classes,r=e.className,l=e.color,f=e.icon,d=e.indeterminate,p=e.indeterminateIcon,b=e.inputProps,m=(0,o.default)(e,["checkedIcon","classes","className","color","icon","indeterminate","indeterminateIcon","inputProps"]);return s.default.createElement(c.default,(0,i.default)({type:"checkbox",checkedIcon:d?p:t,className:(0,u.default)((0,a.default)({},n.indeterminate,d),r),classes:{root:(0,u.default)(n.root,n["color".concat((0,h.capitalize)(l))]),checked:n.checked,disabled:n.disabled},inputProps:(0,i.default)({"data-indeterminate":d},b),icon:d?p:f},m))}t.styles=b,m.defaultProps={checkedIcon:s.default.createElement(f.default,null),color:"secondary",icon:s.default.createElement(l.default,null),indeterminate:!1,indeterminateIcon:s.default.createElement(d.default,null)};var g=(0,p.default)(b,{name:"MuiCheckbox"})(m);t.default=g},71209(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(82811))},16444(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(34575)),u=r(n(93913)),c=r(n(78585)),l=r(n(29754)),f=r(n(2205)),d=r(n(67294));r(n(45697));var h=r(n(94184));r(n(42473)),n(55252);var p=r(n(99781)),b=r(n(78252)),m=n(59114);r(n(21677));var g=n(98741);n(68477);var v=function(e){var t=32,n="light"===e.palette.type?e.palette.grey[300]:e.palette.grey[700],r=(0,m.fade)(e.palette.text.primary,.26);return{root:{fontFamily:e.typography.fontFamily,fontSize:e.typography.pxToRem(13),display:"inline-flex",alignItems:"center",justifyContent:"center",height:t,color:e.palette.getContrastText(n),backgroundColor:n,borderRadius:t/2,whiteSpace:"nowrap",transition:e.transitions.create(["background-color","box-shadow"]),cursor:"default",outline:"none",textDecoration:"none",border:"none",padding:0,verticalAlign:"middle",boxSizing:"border-box"},colorPrimary:{backgroundColor:e.palette.primary.main,color:e.palette.primary.contrastText},colorSecondary:{backgroundColor:e.palette.secondary.main,color:e.palette.secondary.contrastText},clickable:{WebkitTapHighlightColor:"transparent",cursor:"pointer","&:hover, &:focus":{backgroundColor:(0,m.emphasize)(n,.08)},"&:active":{boxShadow:e.shadows[1],backgroundColor:(0,m.emphasize)(n,.12)}},clickableColorPrimary:{"&:hover, &:focus":{backgroundColor:(0,m.emphasize)(e.palette.primary.main,.08)},"&:active":{backgroundColor:(0,m.emphasize)(e.palette.primary.main,.12)}},clickableColorSecondary:{"&:hover, &:focus":{backgroundColor:(0,m.emphasize)(e.palette.secondary.main,.08)},"&:active":{backgroundColor:(0,m.emphasize)(e.palette.secondary.main,.12)}},deletable:{"&:focus":{backgroundColor:(0,m.emphasize)(n,.08)}},deletableColorPrimary:{"&:focus":{backgroundColor:(0,m.emphasize)(e.palette.primary.main,.2)}},deletableColorSecondary:{"&:focus":{backgroundColor:(0,m.emphasize)(e.palette.secondary.main,.2)}},outlined:{backgroundColor:"transparent",border:"1px solid ".concat("light"===e.palette.type?"rgba(0, 0, 0, 0.23)":"rgba(255, 255, 255, 0.23)"),"$clickable&:hover, $clickable&:focus, $deletable&:focus":{backgroundColor:(0,m.fade)(e.palette.text.primary,e.palette.action.hoverOpacity)},"& $avatar":{marginLeft:-1}},outlinedPrimary:{color:e.palette.primary.main,border:"1px solid ".concat(e.palette.primary.main),"$clickable&:hover, $clickable&:focus, $deletable&:focus":{backgroundColor:(0,m.fade)(e.palette.primary.main,e.palette.action.hoverOpacity)}},outlinedSecondary:{color:e.palette.secondary.main,border:"1px solid ".concat(e.palette.secondary.main),"$clickable&:hover, $clickable&:focus, $deletable&:focus":{backgroundColor:(0,m.fade)(e.palette.secondary.main,e.palette.action.hoverOpacity)}},avatar:{marginRight:-4,width:t,height:t,color:"light"===e.palette.type?e.palette.grey[700]:e.palette.grey[300],fontSize:e.typography.pxToRem(16)},avatarColorPrimary:{color:e.palette.primary.contrastText,backgroundColor:e.palette.primary.dark},avatarColorSecondary:{color:e.palette.secondary.contrastText,backgroundColor:e.palette.secondary.dark},avatarChildren:{width:19,height:19},icon:{color:"light"===e.palette.type?e.palette.grey[700]:e.palette.grey[300],marginLeft:4,marginRight:-8},iconColorPrimary:{color:"inherit"},iconColorSecondary:{color:"inherit"},label:{display:"flex",alignItems:"center",paddingLeft:12,paddingRight:12,userSelect:"none",whiteSpace:"nowrap",cursor:"inherit"},deleteIcon:{WebkitTapHighlightColor:"transparent",color:r,cursor:"pointer",height:"auto",margin:"0 4px 0 -8px","&:hover":{color:(0,m.fade)(r,.4)}},deleteIconColorPrimary:{color:(0,m.fade)(e.palette.primary.contrastText,.7),"&:hover, &:active":{color:e.palette.primary.contrastText}},deleteIconColorSecondary:{color:(0,m.fade)(e.palette.secondary.contrastText,.7),"&:hover, &:active":{color:e.palette.secondary.contrastText}},deleteIconOutlinedColorPrimary:{color:(0,m.fade)(e.palette.primary.main,.7),"&:hover, &:active":{color:e.palette.primary.main}},deleteIconOutlinedColorSecondary:{color:(0,m.fade)(e.palette.secondary.main,.7),"&:hover, &:active":{color:e.palette.secondary.main}}}};t.styles=v;var y=function(e){function t(){(0,s.default)(this,t);for(var e,n,r=arguments.length,i=Array(r),a=0;a :last-child":{paddingRight:32},"&$expanded":{margin:"20px 0"}},expandIcon:{position:"absolute",top:"50%",right:8,transform:"translateY(-50%) rotate(0deg)",transition:e.transitions.create("transform",t),"&:hover":{backgroundColor:"transparent"},"&$expanded":{transform:"translateY(-50%) rotate(180deg)"}}}};t.styles=g;var v=function(e){function t(){(0,s.default)(this,t);for(var e,n,r=arguments.length,i=Array(r),a=0;a $item":{padding:e/2}})}),n}var b=function(e){return(0,o.default)({container:{boxSizing:"border-box",display:"flex",flexWrap:"wrap",width:"100%"},item:{boxSizing:"border-box",margin:"0"},zeroMinWidth:{minWidth:0},"direction-xs-column":{flexDirection:"column"},"direction-xs-column-reverse":{flexDirection:"column-reverse"},"direction-xs-row-reverse":{flexDirection:"row-reverse"},"wrap-xs-nowrap":{flexWrap:"nowrap"},"wrap-xs-wrap-reverse":{flexWrap:"wrap-reverse"},"align-items-xs-center":{alignItems:"center"},"align-items-xs-flex-start":{alignItems:"flex-start"},"align-items-xs-flex-end":{alignItems:"flex-end"},"align-items-xs-baseline":{alignItems:"baseline"},"align-content-xs-center":{alignContent:"center"},"align-content-xs-flex-start":{alignContent:"flex-start"},"align-content-xs-flex-end":{alignContent:"flex-end"},"align-content-xs-space-between":{alignContent:"space-between"},"align-content-xs-space-around":{alignContent:"space-around"},"justify-xs-center":{justifyContent:"center"},"justify-xs-flex-end":{justifyContent:"flex-end"},"justify-xs-space-between":{justifyContent:"space-between"},"justify-xs-space-around":{justifyContent:"space-around"},"justify-xs-space-evenly":{justifyContent:"space-evenly"}},p(e,"xs"),l.keys.reduce(function(t,n){return h(t,e,n),t},{}))};function m(e){var t,n=e.alignContent,r=e.alignItems,c=e.classes,l=e.className,f=e.component,d=e.container,h=e.direction,p=e.item,b=e.justify,g=e.lg,v=e.md,y=e.sm,w=e.spacing,_=e.wrap,E=e.xl,S=e.xs,k=e.zeroMinWidth,x=(0,a.default)(e,["alignContent","alignItems","classes","className","component","container","direction","item","justify","lg","md","sm","spacing","wrap","xl","xs","zeroMinWidth"]),T=(0,u.default)((t={},(0,i.default)(t,c.container,d),(0,i.default)(t,c.item,p),(0,i.default)(t,c.zeroMinWidth,k),(0,i.default)(t,c["spacing-xs-".concat(String(w))],d&&0!==w),(0,i.default)(t,c["direction-xs-".concat(String(h))],h!==m.defaultProps.direction),(0,i.default)(t,c["wrap-xs-".concat(String(_))],_!==m.defaultProps.wrap),(0,i.default)(t,c["align-items-xs-".concat(String(r))],r!==m.defaultProps.alignItems),(0,i.default)(t,c["align-content-xs-".concat(String(n))],n!==m.defaultProps.alignContent),(0,i.default)(t,c["justify-xs-".concat(String(b))],b!==m.defaultProps.justify),(0,i.default)(t,c["grid-xs-".concat(String(S))],!1!==S),(0,i.default)(t,c["grid-sm-".concat(String(y))],!1!==y),(0,i.default)(t,c["grid-md-".concat(String(v))],!1!==v),(0,i.default)(t,c["grid-lg-".concat(String(g))],!1!==g),(0,i.default)(t,c["grid-xl-".concat(String(E))],!1!==E),t),l);return s.default.createElement(f,(0,o.default)({className:T},x))}t.styles=b,m.defaultProps={alignContent:"stretch",alignItems:"stretch",component:"div",container:!1,direction:"row",item:!1,justify:"flex-start",lg:!1,md:!1,sm:!1,spacing:0,wrap:"wrap",xl:!1,xs:!1,zeroMinWidth:!1};var g,v=(0,c.default)(b,{name:"MuiGrid"})(m);t.default=v},97779(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(27973))},57205(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(60644)),h=r(n(82313)),p=n(41929);function b(e){return"scale(".concat(e,", ").concat(Math.pow(e,2),")")}var m={entering:{opacity:1,transform:b(1)},entered:{opacity:1,transform:"".concat(b(1)," translateZ(0)")}},g=function(e){function t(){(0,o.default)(this,t);for(var e,n,r=arguments.length,i=Array(r),a=0;a=Number(e.rows)&&(n=Math.min(Number(e.rowsMax)*t,n)),n=Math.max(n,t),Math.abs(this.state.height-n)>1&&this.setState({height:n}))}}},{key:"render",value:function(){var e=this.props,t=e.classes,n=e.className,r=e.defaultValue,o=(e.onChange,e.rows),s=(e.rowsMax,e.style),u=(e.textareaRef,e.value),c=(0,a.default)(e,["classes","className","defaultValue","onChange","rows","rowsMax","style","textareaRef","value"]);return f.default.createElement("div",{className:t.root},f.default.createElement(p.default,{target:"window",onResize:this.handleResize}),f.default.createElement("textarea",{"aria-hidden":"true",className:(0,d.default)(t.textarea,t.shadow),readOnly:!0,ref:this.handleRefSinglelineShadow,rows:"1",tabIndex:-1,value:""}),f.default.createElement("textarea",{"aria-hidden":"true",className:(0,d.default)(t.textarea,t.shadow),defaultValue:r,readOnly:!0,ref:this.handleRefShadow,rows:o,tabIndex:-1,value:u}),f.default.createElement("textarea",(0,i.default)({rows:o,className:(0,d.default)(t.textarea,n),defaultValue:r,value:u,onChange:this.handleChange,ref:this.handleRefInput,style:(0,i.default)({height:this.state.height},s)},c)))}}]),t}(f.default.Component);y.defaultProps={rows:1};var w=(0,b.default)(v,{name:"MuiPrivateTextarea"})(y);t.default=w},67598(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(62010))},78586(e,t){"use strict";function n(e){return null!=e&&!(Array.isArray(e)&&0===e.length)}function r(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return e&&(n(e.value)&&""!==e.value||t&&n(e.defaultValue)&&""!==e.defaultValue)}function i(e){return e.startAdornment}Object.defineProperty(t,"__esModule",{value:!0}),t.hasValue=n,t.isFilled=r,t.isAdornedStart=i},56030(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184)),c=r(n(58189)),l=r(n(52598)),f=r(n(78252)),d=r(n(69645)),h=function(e){return{root:{transformOrigin:"top left"},focused:{},disabled:{},error:{},required:{},formControl:{position:"absolute",left:0,top:0,transform:"translate(0, 24px) scale(1)"},marginDense:{transform:"translate(0, 21px) scale(1)"},shrink:{transform:"translate(0, 1.5px) scale(0.75)",transformOrigin:"top left"},animated:{transition:e.transitions.create(["color","transform"],{duration:e.transitions.duration.shorter,easing:e.transitions.easing.easeOut})},filled:{zIndex:1,pointerEvents:"none",transform:"translate(12px, 20px) scale(1)","&$marginDense":{transform:"translate(12px, 17px) scale(1)"},"&$shrink":{transform:"translate(12px, 10px) scale(0.75)","&$marginDense":{transform:"translate(12px, 7px) scale(0.75)"}}},outlined:{zIndex:1,pointerEvents:"none",transform:"translate(14px, 20px) scale(1)","&$marginDense":{transform:"translate(14px, 17px) scale(1)"},"&$shrink":{transform:"translate(14px, -6px) scale(0.75)"}}}};function p(e){var t,n=e.children,r=e.classes,l=e.className,f=e.disableAnimation,h=e.FormLabelClasses,p=(e.margin,e.muiFormControl),b=e.shrink,m=(e.variant,(0,o.default)(e,["children","classes","className","disableAnimation","FormLabelClasses","margin","muiFormControl","shrink","variant"])),g=b;void 0===g&&p&&(g=p.filled||p.focused||p.adornedStart);var v=(0,c.default)({props:e,muiFormControl:p,states:["margin","variant"]}),y=(0,u.default)(r.root,(t={},(0,a.default)(t,r.formControl,p),(0,a.default)(t,r.animated,!f),(0,a.default)(t,r.shrink,g),(0,a.default)(t,r.marginDense,"dense"===v.margin),(0,a.default)(t,r.filled,"filled"===v.variant),(0,a.default)(t,r.outlined,"outlined"===v.variant),t),l);return s.default.createElement(d.default,(0,i.default)({"data-shrink":g,className:y,classes:(0,i.default)({focused:r.focused,disabled:r.disabled,error:r.error,required:r.required},h)},m),n)}t.styles=h,p.defaultProps={disableAnimation:!1};var b=(0,f.default)(h,{name:"MuiInputLabel"})((0,l.default)(p));t.default=b},23153(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(56030))},46616(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184));r(n(42473));var c=r(n(78252)),l=n(59114),f=4,d=function(e){return{root:{position:"relative",overflow:"hidden",height:4},colorPrimary:{backgroundColor:(0,l.lighten)(e.palette.primary.light,.6)},colorSecondary:{backgroundColor:(0,l.lighten)(e.palette.secondary.light,.4)},determinate:{},indeterminate:{},buffer:{backgroundColor:"transparent"},query:{transform:"rotate(180deg)"},dashed:{position:"absolute",marginTop:0,height:"100%",width:"100%",animation:"buffer 3s infinite linear",animationName:"$buffer"},dashedColorPrimary:{backgroundImage:"radial-gradient(".concat((0,l.lighten)(e.palette.primary.light,.6)," 0%, ").concat((0,l.lighten)(e.palette.primary.light,.6)," 16%, transparent 42%)"),backgroundSize:"10px 10px",backgroundPosition:"0px -23px"},dashedColorSecondary:{backgroundImage:"radial-gradient(".concat((0,l.lighten)(e.palette.secondary.light,.4)," 0%, ").concat((0,l.lighten)(e.palette.secondary.light,.6)," 16%, transparent 42%)"),backgroundSize:"10px 10px",backgroundPosition:"0px -23px"},bar:{width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left"},barColorPrimary:{backgroundColor:e.palette.primary.main},barColorSecondary:{backgroundColor:e.palette.secondary.main},bar1Indeterminate:{width:"auto",animation:"mui-indeterminate1 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite",animationName:"$mui-indeterminate1"},bar1Determinate:{transition:"transform .".concat(f,"s linear")},bar1Buffer:{zIndex:1,transition:"transform .".concat(f,"s linear")},bar2Indeterminate:{width:"auto",animation:"mui-indeterminate2 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite",animationName:"$mui-indeterminate2",animationDelay:"1.15s"},bar2Buffer:{transition:"transform .".concat(f,"s linear")},"@keyframes mui-indeterminate1":{"0%":{left:"-35%",right:"100%"},"60%":{left:"100%",right:"-90%"},"100%":{left:"100%",right:"-90%"}},"@keyframes mui-indeterminate2":{"0%":{left:"-200%",right:"100%"},"60%":{left:"107%",right:"-8%"},"100%":{left:"107%",right:"-8%"}},"@keyframes buffer":{"0%":{opacity:1,backgroundPosition:"0px -23px"},"50%":{opacity:0,backgroundPosition:"0px -23px"},"100%":{opacity:1,backgroundPosition:"-200px -23px"}}}};function h(e){var t,n,r,c,l=e.classes,f=e.className,d=e.color,h=e.value,p=e.valueBuffer,b=e.variant,m=(0,o.default)(e,["classes","className","color","value","valueBuffer","variant"]),g=(0,u.default)(l.root,(t={},(0,a.default)(t,l.colorPrimary,"primary"===d),(0,a.default)(t,l.colorSecondary,"secondary"===d),(0,a.default)(t,l.determinate,"determinate"===b),(0,a.default)(t,l.indeterminate,"indeterminate"===b),(0,a.default)(t,l.buffer,"buffer"===b),(0,a.default)(t,l.query,"query"===b),t),f),v=(0,u.default)(l.dashed,(n={},(0,a.default)(n,l.dashedColorPrimary,"primary"===d),(0,a.default)(n,l.dashedColorSecondary,"secondary"===d),n)),y=(0,u.default)(l.bar,(r={},(0,a.default)(r,l.barColorPrimary,"primary"===d),(0,a.default)(r,l.barColorSecondary,"secondary"===d),(0,a.default)(r,l.bar1Indeterminate,"indeterminate"===b||"query"===b),(0,a.default)(r,l.bar1Determinate,"determinate"===b),(0,a.default)(r,l.bar1Buffer,"buffer"===b),r)),w=(0,u.default)(l.bar,(c={},(0,a.default)(c,l.barColorPrimary,"primary"===d&&"buffer"!==b),(0,a.default)(c,l.colorPrimary,"primary"===d&&"buffer"===b),(0,a.default)(c,l.barColorSecondary,"secondary"===d&&"buffer"!==b),(0,a.default)(c,l.colorSecondary,"secondary"===d&&"buffer"===b),(0,a.default)(c,l.bar2Indeterminate,"indeterminate"===b||"query"===b),(0,a.default)(c,l.bar2Buffer,"buffer"===b),c)),_={},E={bar1:{},bar2:{}};return("determinate"===b||"buffer"===b)&&void 0!==h&&(_["aria-valuenow"]=Math.round(h),E.bar1.transform="scaleX(".concat(h/100,")")),"buffer"===b&&void 0!==p&&(E.bar2.transform="scaleX(".concat((p||0)/100,")")),s.default.createElement("div",(0,i.default)({className:g,role:"progressbar"},_,m),"buffer"===b?s.default.createElement("div",{className:v}):null,s.default.createElement("div",{className:y,style:E.bar1}),"determinate"===b?null:s.default.createElement("div",{className:w,style:E.bar2}))}t.styles=d,h.defaultProps={color:"primary",variant:"indeterminate"};var p=(0,c.default)(d,{name:"MuiLinearProgress"})(h);t.default=p},79424(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(46616))},74080(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184));n(55252);var c=r(n(78252)),l=r(n(47457)),f={root:{listStyle:"none",margin:0,padding:0,position:"relative"},padding:{paddingTop:8,paddingBottom:8},dense:{paddingTop:4,paddingBottom:4},subheader:{paddingTop:0}};function d(e){var t,n=e.children,r=e.classes,c=e.className,f=e.component,d=e.dense,h=e.disablePadding,p=e.subheader,b=(0,o.default)(e,["children","classes","className","component","dense","disablePadding","subheader"]);return s.default.createElement(f,(0,i.default)({className:(0,u.default)(r.root,(t={},(0,a.default)(t,r.dense,d&&!h),(0,a.default)(t,r.padding,!h),(0,a.default)(t,r.subheader,p),t),c)},b),s.default.createElement(l.default.Provider,{value:{dense:d}},p,n))}t.styles=f,d.defaultProps={component:"ul",dense:!1,disablePadding:!1};var h=(0,c.default)(f,{name:"MuiList"})(d);t.default=h},47457(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)).default.createContext({});t.default=i},3022(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(74080))},29936(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184));n(55252);var c=r(n(78252)),l=r(n(16070)),f=n(44370),d=r(n(671)),h=function(e){return{root:{display:"flex",justifyContent:"flex-start",alignItems:"center",position:"relative",textDecoration:"none",width:"100%",boxSizing:"border-box",textAlign:"left",paddingTop:11,paddingBottom:11,"&$selected, &$selected:hover, &$selected:focus":{backgroundColor:e.palette.action.selected}},container:{position:"relative"},focusVisible:{},default:{},dense:{paddingTop:8,paddingBottom:8},alignItemsFlexStart:{alignItems:"flex-start"},disabled:{opacity:.5},divider:{borderBottom:"1px solid ".concat(e.palette.divider),backgroundClip:"padding-box"},gutters:{paddingLeft:16,paddingRight:16},button:{transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),"&:hover":{textDecoration:"none",backgroundColor:e.palette.action.hover,"@media (hover: none)":{backgroundColor:"transparent"}},"&:focus":{backgroundColor:e.palette.action.hover}},secondaryAction:{paddingRight:32},selected:{}}};function p(e){var t=e.alignItems,n=e.button,r=e.children,c=e.classes,h=e.className,p=e.component,b=e.ContainerComponent,m=e.ContainerProps,g=(m=void 0===m?{}:m).className,v=(0,o.default)(m,["className"]),y=e.dense,w=e.disabled,_=e.disableGutters,E=e.divider,S=e.focusVisibleClassName,k=e.selected,x=(0,o.default)(e,["alignItems","button","children","classes","className","component","ContainerComponent","ContainerProps","dense","disabled","disableGutters","divider","focusVisibleClassName","selected"]);return s.default.createElement(d.default,{dense:y,alignItems:t},function(e){var o,d=e.dense,m=s.default.Children.toArray(r),y=m.some(function(e){return(0,f.isMuiElement)(e,["ListItemAvatar"])}),T=m.length&&(0,f.isMuiElement)(m[m.length-1],["ListItemSecondaryAction"]),M=(0,u.default)(c.root,c.default,(o={},(0,a.default)(o,c.dense,d||y),(0,a.default)(o,c.gutters,!_),(0,a.default)(o,c.divider,E),(0,a.default)(o,c.disabled,w),(0,a.default)(o,c.button,n),(0,a.default)(o,c.alignItemsFlexStart,"flex-start"===t),(0,a.default)(o,c.secondaryAction,T),(0,a.default)(o,c.selected,k),o),h),O=(0,i.default)({className:M,disabled:w},x),A=p||"li";return(n&&(O.component=p||"div",O.focusVisibleClassName=(0,u.default)(c.focusVisible,S),A=l.default),T)?(A=O.component||p?A:"div","li"===b&&("li"===A?A="div":"li"===O.component&&(O.component="div")),s.default.createElement(b,(0,i.default)({className:(0,u.default)(c.container,g)},v),s.default.createElement(A,O,m),m.pop())):s.default.createElement(A,O,m)})}t.styles=h,p.defaultProps={alignItems:"center",button:!1,ContainerComponent:"li",dense:!1,disabled:!1,disableGutters:!1,divider:!1,selected:!1};var b=(0,c.default)(h,{name:"MuiListItem"})(p);t.default=b},671(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294));r(n(45697));var a=r(n(47457));function o(e){var t=e.alignItems,n=e.children,r=e.dense;return i.default.createElement(a.default.Consumer,null,function(e){var o={dense:r||e.dense||!1,alignItems:t};return i.default.createElement(a.default.Provider,{value:o},n(o))})}var s=o;t.default=s},60323(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(29936))},69394(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(67294));r(n(45697));var s=r(n(94184)),u=r(n(78252)),c=function(e){return{root:{marginRight:16,color:e.palette.action.active,flexShrink:0,display:"inline-flex"}}};function l(e){var t=e.children,n=e.classes,r=e.className,u=(0,a.default)(e,["children","classes","className"]);return o.default.createElement("div",(0,i.default)({className:(0,s.default)(n.root,r)},u),t)}t.styles=c;var f=(0,u.default)(c,{name:"MuiListItemIcon"})(l);t.default=f},11186(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(69394))},73390(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184)),c=r(n(78252)),l=r(n(71426)),f=r(n(47457)),d=function(e){return{root:{flex:"1 1 auto",minWidth:0,padding:"0 16px","&:first-child":{paddingLeft:0}},inset:{"&:first-child":{paddingLeft:56}},dense:{fontSize:e.typography.pxToRem(13)},primary:{"&$textDense":{fontSize:"inherit"}},secondary:{"&$textDense":{fontSize:"inherit"}},textDense:{}}};function h(e){var t=e.children,n=e.classes,r=e.className,c=e.disableTypography,d=e.inset,h=e.primary,p=e.primaryTypographyProps,b=e.secondary,m=e.secondaryTypographyProps,g=e.theme,v=(0,o.default)(e,["children","classes","className","disableTypography","inset","primary","primaryTypographyProps","secondary","secondaryTypographyProps","theme"]);return s.default.createElement(f.default.Consumer,null,function(e){var o,f=e.dense,y=null!=h?h:t;null==y||y.type===l.default||c||(y=s.default.createElement(l.default,(0,i.default)({variant:g.typography.useNextVariants?"body1":"subheading",className:(0,u.default)(n.primary,(0,a.default)({},n.textDense,f)),component:"span"},p),y));var w=b;return null==w||w.type===l.default||c||(w=s.default.createElement(l.default,(0,i.default)({className:(0,u.default)(n.secondary,(0,a.default)({},n.textDense,f)),color:"textSecondary"},m),w)),s.default.createElement("div",(0,i.default)({className:(0,u.default)(n.root,(o={},(0,a.default)(o,n.dense,f),(0,a.default)(o,n.inset,d),o),r)},v),y,w)})}t.styles=d,h.defaultProps={disableTypography:!1,inset:!1};var p=(0,c.default)(d,{name:"MuiListItemText",withTheme:!0})(h);t.default=p},87591(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(73390))},95890(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(73935)),h=r(n(44825)),p=r(n(78252)),b=r(n(50810)),m=r(n(34980)),g={vertical:"top",horizontal:"right"},v={vertical:"top",horizontal:"left"},y={paper:{maxHeight:"calc(100% - 96px)",WebkitOverflowScrolling:"touch"}};t.styles=y;var w=function(e){function t(){(0,o.default)(this,t);for(var e,n,r=arguments.length,i=Array(r),a=0;a=0?t.children[e].focus():t.firstChild.focus())}},{key:"resetTabIndex",value:function(){for(var e=this.listRef,t=(0,h.default)(e).activeElement,n=[],r=0;r0&&void 0!==arguments[0]?arguments[0]:{};(0,i.default)(this,e);var n=t.hideSiblingNodes,r=void 0===n||n,a=t.handleContainerOverflow,o=void 0===a||a;this.hideSiblingNodes=r,this.handleContainerOverflow=o,this.modals=[],this.data=[]}return(0,a.default)(e,[{key:"add",value:function(e,t){var n=this.modals.indexOf(e);if(-1!==n)return n;n=this.modals.length,this.modals.push(e),e.modalRef&&(0,l.ariaHidden)(e.modalRef,!1),this.hideSiblingNodes&&(0,l.ariaHiddenSiblings)(t,e.mountNode,e.modalRef,!0);var r=f(this.data,function(e){return e.container===t});if(-1!==r)return this.data[r].modals.push(e),n;var i={modals:[e],container:t,overflowing:(0,c.default)(t),prevPaddings:[]};return this.data.push(i),n}},{key:"mount",value:function(e){var t=f(this.data,function(t){return -1!==t.modals.indexOf(e)}),n=this.data[t];!n.style&&this.handleContainerOverflow&&h(n)}},{key:"remove",value:function(e){var t=this.modals.indexOf(e);if(-1===t)return t;var n=f(this.data,function(t){return -1!==t.modals.indexOf(e)}),r=this.data[n];if(r.modals.splice(r.modals.indexOf(e),1),this.modals.splice(t,1),0===r.modals.length)this.handleContainerOverflow&&p(r),e.modalRef&&(0,l.ariaHidden)(e.modalRef,!0),this.hideSiblingNodes&&(0,l.ariaHiddenSiblings)(r.container,e.mountNode,e.modalRef,!1),this.data.splice(n,1);else if(this.hideSiblingNodes){var i=r.modals[r.modals.length-1];i.modalRef&&(0,l.ariaHidden)(i.modalRef,!1)}return t}},{key:"isTopModal",value:function(e){return!!this.modals.length&&this.modals[this.modals.length-1]===e}}]),e}();t.default=b},55536(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"ModalManager",{enumerable:!0,get:function(){return a.default}});var i=r(n(58228)),a=r(n(2158))},16575(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.isBody=s,t.default=u;var i=r(n(7624)),a=r(n(16143)),o=r(n(62614));function s(e){return e&&"body"===e.tagName.toLowerCase()}function u(e){var t=(0,a.default)(e),n=(0,o.default)(t);if(!(0,i.default)(t)&&!s(e))return e.scrollHeight>e.clientHeight;var r=n.getComputedStyle(t.body),u=parseInt(r.getPropertyValue("margin-left"),10),c=parseInt(r.getPropertyValue("margin-right"),10);return u+t.body.clientWidth+c0?.75*r+8:0;return s.default.createElement("fieldset",(0,a.default)({"aria-hidden":!0,style:(0,a.default)((0,i.default)({},"padding".concat((0,l.capitalize)(p)),8+(c?0:b/2)),f),className:(0,u.default)(t.root,n)},h),s.default.createElement("legend",{className:t.legend,style:{width:c?b:.01}},s.default.createElement("span",{dangerouslySetInnerHTML:{__html:"​"}})))}t.styles=f;var h=(0,c.withStyles)(f,{name:"MuiPrivateNotchedOutline",withTheme:!0})(d);t.default=h},96405(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(67294));r(n(45697));var s=r(n(94184));n(55252);var u=r(n(67598)),c=r(n(21142)),l=r(n(78252)),f=function(e){var t="light"===e.palette.type?"rgba(0, 0, 0, 0.23)":"rgba(255, 255, 255, 0.23)";return{root:{position:"relative","& $notchedOutline":{borderColor:t},"&:hover:not($disabled):not($focused):not($error) $notchedOutline":{borderColor:e.palette.text.primary,"@media (hover: none)":{borderColor:t}},"&$focused $notchedOutline":{borderColor:e.palette.primary.main,borderWidth:2},"&$error $notchedOutline":{borderColor:e.palette.error.main},"&$disabled $notchedOutline":{borderColor:e.palette.action.disabled}},focused:{},disabled:{},adornedStart:{paddingLeft:14},adornedEnd:{paddingRight:14},error:{},multiline:{padding:"18.5px 14px",boxSizing:"border-box"},notchedOutline:{},input:{padding:"18.5px 14px"},inputMarginDense:{paddingTop:15,paddingBottom:15},inputMultiline:{padding:0},inputAdornedStart:{paddingLeft:0},inputAdornedEnd:{paddingRight:0}}};function d(e){var t=e.classes,n=e.labelWidth,r=e.notched,l=(0,a.default)(e,["classes","labelWidth","notched"]);return o.default.createElement(u.default,(0,i.default)({renderPrefix:function(e){return o.default.createElement(c.default,{className:t.notchedOutline,labelWidth:n,notched:void 0!==r?r:Boolean(e.startAdornment||e.filled||e.focused)})},classes:(0,i.default)({},t,{root:(0,s.default)(t.root,t.underline),notchedOutline:null})},l))}t.styles=f,u.default.defaultProps={fullWidth:!1,inputComponent:"input",multiline:!1,type:"text"},d.muiName="Input";var h=(0,l.default)(f,{name:"MuiOutlinedInput"})(d);t.default=h},59537(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(96405))},30083(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(59713)),a=r(n(6479)),o=r(n(67154)),s=r(n(67294));r(n(45697));var u=r(n(94184));r(n(42473)),n(55252);var c=r(n(78252)),l=function(e){var t={};return e.shadows.forEach(function(e,n){t["elevation".concat(n)]={boxShadow:e}}),(0,o.default)({root:{backgroundColor:e.palette.background.paper},rounded:{borderRadius:e.shape.borderRadius}},t)};function f(e){var t=e.classes,n=e.className,r=e.component,c=e.square,l=e.elevation,f=(0,a.default)(e,["classes","className","component","square","elevation"]),d=(0,u.default)(t.root,t["elevation".concat(l)],(0,i.default)({},t.rounded,!c),n);return s.default.createElement(r,(0,o.default)({className:d},f))}t.styles=l,f.defaultProps={component:"div",elevation:2,square:!1};var d=(0,c.default)(l,{name:"MuiPaper"})(f);t.default=d},68821(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(30083))},64224(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(73935));r(n(42473));var h=r(n(20296)),p=r(n(96421));n(55252);var b=r(n(16143)),m=r(n(62614)),g=n(98741),v=r(n(78252)),y=r(n(55536)),w=r(n(261)),_=r(n(68821));function E(e,t){var n=0;return"number"==typeof t?n=t:"center"===t?n=e.height/2:"bottom"===t&&(n=e.height),n}function S(e,t){var n=0;return"number"==typeof t?n=t:"center"===t?n=e.width/2:"right"===t&&(n=e.width),n}function k(e){return[e.horizontal,e.vertical].map(function(e){return"number"==typeof e?"".concat(e,"px"):e}).join(" ")}function x(e,t){for(var n=t,r=0;n&&n!==e;)r+=(n=n.parentNode).scrollTop;return r}function T(e){return"function"==typeof e?e():e}var M={paper:{position:"absolute",overflowY:"auto",overflowX:"hidden",minWidth:16,minHeight:16,maxWidth:"calc(100% - 32px)",maxHeight:"calc(100% - 32px)",outline:"none"}};t.styles=M;var O=function(e){function t(){var e;return(0,o.default)(this,t),(e=(0,u.default)(this,(0,c.default)(t).call(this))).handleGetOffsetTop=E,e.handleGetOffsetLeft=S,e.componentWillUnmount=function(){e.handleResize.clear()},e.setPositioningStyles=function(t){var n=e.getPositioningStyle(t);null!==n.top&&(t.style.top=n.top),null!==n.left&&(t.style.left=n.left),t.style.transformOrigin=n.transformOrigin},e.getPositioningStyle=function(t){var n=e.props,r=n.anchorEl,i=n.anchorReference,a=n.marginThreshold,o=e.getContentAnchorOffset(t),s={width:t.offsetWidth,height:t.offsetHeight},u=e.getTransformOrigin(s,o);if("none"===i)return{top:null,left:null,transformOrigin:k(u)};var c=e.getAnchorOffset(o),l=c.top-u.vertical,f=c.left-u.horizontal,d=l+s.height,h=f+s.width,p=(0,m.default)(T(r)),b=p.innerHeight-a,g=p.innerWidth-a;if(lb){var y=d-b;l-=y,u.vertical+=y}if(fg){var _=h-g;f-=_,u.horizontal+=_}return{top:"".concat(l,"px"),left:"".concat(f,"px"),transformOrigin:k(u)}},e.handleEntering=function(t){e.props.onEntering&&e.props.onEntering(t),e.setPositioningStyles(t)},"undefined"!=typeof window&&(e.handleResize=(0,h.default)(function(){e.props.open&&e.setPositioningStyles(e.paperRef)},166)),e}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){this.props.action&&this.props.action({updatePosition:this.handleResize})}},{key:"getAnchorOffset",value:function(e){var t=this.props,n=t.anchorEl,r=t.anchorOrigin,i=t.anchorReference,a=t.anchorPosition;if("anchorPosition"===i)return a;var o=(T(n)||(0,b.default)(this.paperRef).body).getBoundingClientRect(),s=0===e?r.vertical:"center";return{top:o.top+this.handleGetOffsetTop(o,s),left:o.left+this.handleGetOffsetLeft(o,r.horizontal)}}},{key:"getContentAnchorOffset",value:function(e){var t=this.props,n=t.getContentAnchorEl,r=t.anchorReference,i=0;if(n&&"anchorEl"===r){var a=n(e);if(a&&e.contains(a)){var o=x(e,a);i=a.offsetTop+a.clientHeight/2-o||0}}return i}},{key:"getTransformOrigin",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=this.props.transformOrigin;return{vertical:this.handleGetOffsetTop(e,n.vertical)+t,horizontal:this.handleGetOffsetLeft(e,n.horizontal)}}},{key:"render",value:function(){var e=this,t=this.props,n=(t.action,t.anchorEl),r=(t.anchorOrigin,t.anchorPosition,t.anchorReference,t.children),o=t.classes,s=t.container,u=t.elevation,c=(t.getContentAnchorEl,t.marginThreshold,t.ModalClasses),l=t.onEnter,h=t.onEntered,m=(t.onEntering,t.onExit),v=t.onExited,w=t.onExiting,E=t.open,S=t.PaperProps,k=t.role,x=(t.transformOrigin,t.TransitionComponent),M=t.transitionDuration,O=t.TransitionProps,A=void 0===O?{}:O,L=(0,a.default)(t,["action","anchorEl","anchorOrigin","anchorPosition","anchorReference","children","classes","container","elevation","getContentAnchorEl","marginThreshold","ModalClasses","onEnter","onEntered","onEntering","onExit","onExited","onExiting","open","PaperProps","role","transformOrigin","TransitionComponent","transitionDuration","TransitionProps"]),C=M;"auto"!==M||x.muiSupportAuto||(C=void 0);var I=s||(n?(0,b.default)(T(n)).body:void 0);return f.default.createElement(y.default,(0,i.default)({classes:c,container:I,open:E,BackdropProps:{invisible:!0}},L),f.default.createElement(x,(0,i.default)({appear:!0,in:E,onEnter:l,onEntered:h,onExit:m,onExited:v,onExiting:w,role:k,timeout:C},A,{onEntering:(0,g.createChainedFunction)(this.handleEntering,A.onEntering)}),f.default.createElement(_.default,(0,i.default)({className:o.paper,elevation:u,ref:function(t){e.paperRef=d.default.findDOMNode(t)}},S),f.default.createElement(p.default,{target:"window",onResize:this.handleResize}),r)))}}]),t}(f.default.Component);O.defaultProps={anchorReference:"anchorEl",anchorOrigin:{vertical:"top",horizontal:"left"},elevation:8,marginThreshold:16,transformOrigin:{vertical:"top",horizontal:"left"},TransitionComponent:w.default,transitionDuration:"auto"};var A=(0,v.default)(M,{name:"MuiPopover"})(O);t.default=A},50810(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(64224))},24693(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(6479)),a=r(n(67154)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(81506)),d=r(n(67294)),h=r(n(73935));r(n(45697));var p=r(n(28981)),b=r(n(25649));function m(e){if("rtl"!==("undefined"!=typeof window&&document.body.getAttribute("dir")||"ltr"))return e;switch(e){case"bottom-end":return"bottom-start";case"bottom-start":return"bottom-end";case"top-end":return"top-start";case"top-start":return"top-end";default:return e}}function g(e){return"function"==typeof e?e():e}var v=function(e){function t(e){var n;return(0,o.default)(this,t),(n=(0,u.default)(this,(0,c.default)(t).call(this))).handleOpen=function(){var e=n.props,t=e.anchorEl,r=e.modifiers,i=e.open,o=e.placement,s=e.popperOptions,u=void 0===s?{}:s,c=e.disablePortal,l=h.default.findDOMNode((0,f.default)((0,f.default)(n)));l&&t&&i&&(n.popper&&(n.popper.destroy(),n.popper=null),n.popper=new p.default(g(t),l,(0,a.default)({placement:m(o)},u,{modifiers:(0,a.default)({},c?{}:{preventOverflow:{boundariesElement:"window"}},r,u.modifiers),onCreate:n.handlePopperUpdate,onUpdate:n.handlePopperUpdate})))},n.handlePopperUpdate=function(e){e.placement!==n.state.placement&&n.setState({placement:e.placement})},n.handleExited=function(){n.setState({exited:!0}),n.handleClose()},n.handleClose=function(){n.popper&&(n.popper.destroy(),n.popper=null)},n.state={exited:!e.open},n}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidUpdate",value:function(e){e.open===this.props.open||this.props.open||this.props.transition||this.handleClose(),(e.open!==this.props.open||e.anchorEl!==this.props.anchorEl||e.popperOptions!==this.props.popperOptions||e.modifiers!==this.props.modifiers||e.disablePortal!==this.props.disablePortal||e.placement!==this.props.placement)&&this.handleOpen()}},{key:"componentWillUnmount",value:function(){this.handleClose()}},{key:"render",value:function(){var e=this.props,t=(e.anchorEl,e.children),n=e.container,r=e.disablePortal,o=e.keepMounted,s=(e.modifiers,e.open),u=e.placement,c=(e.popperOptions,e.transition),l=(0,i.default)(e,["anchorEl","children","container","disablePortal","keepMounted","modifiers","open","placement","popperOptions","transition"]),f=this.state,h=f.exited,p=f.placement;if(!o&&!s&&(!c||h))return null;var g={placement:p||m(u)};return c&&(g.TransitionProps={in:s,onExited:this.handleExited}),d.default.createElement(b.default,{onRendered:this.handleOpen,disablePortal:r,container:n},d.default.createElement("div",(0,a.default)({role:"tooltip",style:{position:"absolute"}},l),"function"==typeof t?t(g):t))}}],[{key:"getDerivedStateFromProps",value:function(e){return e.open?{exited:!1}:e.transition?null:{exited:!0}}}]),t}(d.default.Component);v.defaultProps={disablePortal:!1,placement:"bottom",transition:!1};var y=v;t.default=y},60111(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(24693))},92261(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(34575)),a=r(n(93913)),o=r(n(78585)),s=r(n(29754)),u=r(n(2205)),c=r(n(67294)),l=r(n(73935));r(n(45697));var f=r(n(16143));function d(e,t){return e="function"==typeof e?e():e,l.default.findDOMNode(e)||t}function h(e){return(0,f.default)(l.default.findDOMNode(e))}n(55252);var p=function(e){function t(){(0,i.default)(this,t);for(var e,n,r=arguments.length,a=Array(r),u=0;u1;n.state.labelWrapped!==e&&n.setState({labelWrapped:e})}},n}return(0,c.default)(t,e),(0,o.default)(t,[{key:"componentDidMount",value:function(){this.checkTextWrap()}},{key:"componentDidUpdate",value:function(e,t){this.state.labelWrapped===t.labelWrapped&&this.checkTextWrap()}},{key:"render",value:function(){var e,t,n=this,r=this.props,a=r.classes,o=r.className,s=r.disabled,u=r.fullWidth,c=r.icon,p=r.indicator,g=r.label,v=(r.onChange,r.selected),y=r.textColor,w=(r.value,(0,i.default)(r,["classes","className","disabled","fullWidth","icon","indicator","label","onChange","selected","textColor","value"]));return void 0!==g&&(e=d.default.createElement("span",{className:a.labelContainer},d.default.createElement("span",{className:(0,h.default)(a.label,(0,l.default)({},a.labelWrapped,this.state.labelWrapped)),ref:function(e){n.labelRef=e}},g))),d.default.createElement(b.default,(0,f.default)({focusRipple:!0,className:(0,h.default)(a.root,a["textColor".concat((0,m.capitalize)(y))],(t={},(0,l.default)(t,a.disabled,s),(0,l.default)(t,a.selected,v),(0,l.default)(t,a.labelIcon,c&&e),(0,l.default)(t,a.fullWidth,u),t),o),role:"tab","aria-selected":v,disabled:s},w,{onClick:this.handleChange}),d.default.createElement("span",{className:a.wrapper},c,e),p)}}]),t}(d.default.Component);v.defaultProps={disabled:!1,textColor:"inherit"};var y=(0,p.default)(g,{name:"MuiTab"})(v);t.default=y},75759(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(70201))},7575(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(94184));n(55252);var h=r(n(78252)),p=r(n(82577)),b=function(e){return{root:{display:"table",fontFamily:e.typography.fontFamily,width:"100%",borderCollapse:"collapse",borderSpacing:0}}};t.styles=b;var m=function(e){function t(){(0,o.default)(this,t);for(var e,n,r=arguments.length,i=Array(r),a=0;ai&&n(null,i)}},{key:"render",value:function(){var e,t=this.props,n=t.ActionsComponent,r=t.backIconButtonProps,o=t.classes,s=t.colSpan,u=t.component,c=t.count,l=t.labelDisplayedRows,d=t.labelRowsPerPage,y=t.nextIconButtonProps,w=t.onChangePage,_=t.onChangeRowsPerPage,E=t.page,S=t.rowsPerPage,k=t.rowsPerPageOptions,x=t.SelectProps,T=void 0===x?{}:x,M=(0,a.default)(t,["ActionsComponent","backIconButtonProps","classes","colSpan","component","count","labelDisplayedRows","labelRowsPerPage","nextIconButtonProps","onChangePage","onChangeRowsPerPage","page","rowsPerPage","rowsPerPageOptions","SelectProps"]);(u===m.default||"td"===u)&&(e=s||1e3);var O=T.native?"option":p.default;return f.default.createElement(u,(0,i.default)({className:o.root,colSpan:e},M),f.default.createElement(g.default,{className:o.toolbar},f.default.createElement("div",{className:o.spacer}),k.length>1&&f.default.createElement(v.default,{color:"inherit",variant:"caption",className:o.caption},d),k.length>1&&f.default.createElement(b.default,(0,i.default)({classes:{root:o.selectRoot,select:o.select,icon:o.selectIcon},input:f.default.createElement(h.default,{className:o.input}),value:S,onChange:_},T),k.map(function(e){return f.default.createElement(O,{className:o.menuItem,key:e,value:e},e)})),f.default.createElement(v.default,{color:"inherit",variant:"caption",className:o.caption},l({from:0===c?0:E*S+1,to:Math.min(c,(E+1)*S),count:c,page:E})),f.default.createElement(n,{className:o.actions,backIconButtonProps:r,count:c,nextIconButtonProps:y,onChangePage:w,page:E,rowsPerPage:S})))}}]),t}(f.default.Component);_.defaultProps={ActionsComponent:y.default,component:m.default,labelDisplayedRows:function(e){var t=e.from,n=e.to,r=e.count;return"".concat(t,"-").concat(n," of ").concat(r)},labelRowsPerPage:"Rows per page:",rowsPerPageOptions:[10,25,50,100]};var E=(0,d.default)(w,{name:"MuiTablePagination"})(_);t.default=E},32844(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(86861)),h=r(n(43836)),p=r(n(82313)),b=r(n(81701)),m=f.default.createElement(h.default,null),g=f.default.createElement(d.default,null),v=f.default.createElement(d.default,null),y=f.default.createElement(h.default,null),w=function(e){function t(){(0,o.default)(this,t);for(var e,n,r=arguments.length,i=Array(r),a=0;a=Math.ceil(n/s)-1,color:"inherit"},r),"rtl"===u.direction?v:y))}}]),t}(f.default.Component),_=(0,p.default)()(w);t.default=_},18217(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(71744))},86424(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184));n(55252);var c=r(n(78252)),l=r(n(27628)),f=function(e){return{root:{color:"inherit",display:"table-row",height:48,verticalAlign:"middle",outline:"none","&$selected":{backgroundColor:"light"===e.palette.type?"rgba(0, 0, 0, 0.04)":"rgba(255, 255, 255, 0.08)"},"&$hover:hover":{backgroundColor:"light"===e.palette.type?"rgba(0, 0, 0, 0.07)":"rgba(255, 255, 255, 0.14)"}},selected:{},hover:{},head:{height:56},footer:{height:56}}};function d(e){var t=e.classes,n=e.className,r=e.component,c=e.hover,f=e.selected,d=(0,o.default)(e,["classes","className","component","hover","selected"]);return s.default.createElement(l.default.Consumer,null,function(e){var o,l=(0,u.default)(t.root,(o={},(0,a.default)(o,t.head,e&&"head"===e.variant),(0,a.default)(o,t.footer,e&&"footer"===e.variant),(0,a.default)(o,t.hover,c),(0,a.default)(o,t.selected,f),o),n);return s.default.createElement(r,(0,i.default)({className:l},d))})}t.styles=f,d.defaultProps={component:"tr",hover:!1,selected:!1};var h=(0,c.default)(f,{name:"MuiTableRow"})(d);t.default=h},17175(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(86424))},28550(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(34575)),a=r(n(93913)),o=r(n(78585)),s=r(n(29754)),u=r(n(2205)),c=r(n(67294));r(n(45697));var l,f=r(n(96421)),d=r(n(20296)),h={width:90,height:90,position:"absolute",top:-9e3,overflow:"scroll",msOverflowStyle:"scrollbar"},p=function(e){function t(){var e;return(0,i.default)(this,t),(e=(0,o.default)(this,(0,s.default)(t).call(this))).handleRef=function(t){e.nodeRef=t},e.setMeasurements=function(){var t=e.nodeRef;t&&(e.scrollbarHeight=t.offsetHeight-t.clientHeight)},"undefined"!=typeof window&&(e.handleResize=(0,d.default)(function(){var t=e.scrollbarHeight;e.setMeasurements(),t!==e.scrollbarHeight&&e.props.onChange(e.scrollbarHeight)},166)),e}return(0,u.default)(t,e),(0,a.default)(t,[{key:"componentDidMount",value:function(){this.setMeasurements(),this.props.onChange(this.scrollbarHeight)}},{key:"componentWillUnmount",value:function(){this.handleResize.clear()}},{key:"render",value:function(){return c.default.createElement(c.default.Fragment,null,c.default.createElement(f.default,{target:"window",onResize:this.handleResize}),c.default.createElement("div",{style:h,ref:this.handleRef}))}}]),t}(c.default.Component);t.default=p},12417(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(67294));r(n(45697));var s=r(n(94184)),u=r(n(78252)),c=n(98741),l=function(e){return{root:{position:"absolute",height:2,bottom:0,width:"100%",transition:e.transitions.create()},colorPrimary:{backgroundColor:e.palette.primary.main},colorSecondary:{backgroundColor:e.palette.secondary.main}}};function f(e){var t=e.classes,n=e.className,r=e.color,u=(0,a.default)(e,["classes","className","color"]);return o.default.createElement("span",(0,i.default)({className:(0,s.default)(t.root,t["color".concat((0,c.capitalize)(r))],n)},u))}t.styles=l;var d=(0,u.default)(l,{name:"MuiPrivateTabIndicator"})(f);t.default=d},69583(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(67294));r(n(45697));var s=r(n(94184)),u=r(n(86861)),c=r(n(43836)),l=r(n(78252)),f=r(n(16070)),d={root:{color:"inherit",width:56,flexShrink:0}};t.styles=d;var h=o.default.createElement(u.default,null),p=o.default.createElement(c.default,null);function b(e){var t=e.classes,n=e.className,r=e.direction,u=e.onClick,c=e.visible,l=(0,a.default)(e,["classes","className","direction","onClick","visible"]),d=(0,s.default)(t.root,n);return c?o.default.createElement(f.default,(0,i.default)({className:d,onClick:u,tabIndex:-1},l),"left"===r?h:p):o.default.createElement("div",{className:d})}b.defaultProps={visible:!0};var m=(0,l.default)(d,{name:"MuiPrivateTabScrollButton"})(b);t.default=m},89172(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(59713)),d=r(n(67294));r(n(45697)),r(n(42473));var h=r(n(94184)),p=r(n(96421)),b=r(n(20296)),m=n(46417);n(55252);var g=r(n(13329)),v=r(n(28550)),y=r(n(78252)),w=r(n(12417)),_=r(n(69583));r(n(346));var E=function(e){return{root:{overflow:"hidden",minHeight:48,WebkitOverflowScrolling:"touch"},flexContainer:{display:"flex"},centered:{justifyContent:"center"},scroller:{position:"relative",display:"inline-block",flex:"1 1 auto",whiteSpace:"nowrap"},fixed:{overflowX:"hidden",width:"100%"},scrollable:{overflowX:"scroll"},scrollButtons:{},scrollButtonsAuto:(0,f.default)({},e.breakpoints.down("xs"),{display:"none"}),indicator:{}}};t.styles=E;var S=function(e){function t(){var e;return(0,o.default)(this,t),(e=(0,u.default)(this,(0,c.default)(t).call(this))).state={indicatorStyle:{},scrollerStyle:{marginBottom:0},showLeftScroll:!1,showRightScroll:!1,mounted:!1},e.getConditionalElements=function(){var t=e.props,n=t.classes,r=t.scrollable,i=t.ScrollButtonComponent,a=t.scrollButtons,o=t.theme,s=t.variant,u={},c="scrollable"===s||r;u.scrollbarSizeListener=c?d.default.createElement(v.default,{onChange:e.handleScrollbarSizeChange}):null;var l=c&&("auto"===a||"on"===a);return u.scrollButtonLeft=l?d.default.createElement(i,{direction:o&&"rtl"===o.direction?"right":"left",onClick:e.handleLeftScrollClick,visible:e.state.showLeftScroll,className:(0,h.default)(n.scrollButtons,(0,f.default)({},n.scrollButtonsAuto,"auto"===a))}):null,u.scrollButtonRight=l?d.default.createElement(i,{direction:o&&"rtl"===o.direction?"left":"right",onClick:e.handleRightScrollClick,visible:e.state.showRightScroll,className:(0,h.default)(n.scrollButtons,(0,f.default)({},n.scrollButtonsAuto,"auto"===a))}):null,u},e.getTabsMeta=function(t,n){if(e.tabsRef){var r,i,a=e.tabsRef.getBoundingClientRect();r={clientWidth:e.tabsRef.clientWidth,scrollLeft:e.tabsRef.scrollLeft,scrollLeftNormalized:(0,m.getNormalizedScrollLeft)(e.tabsRef,n),scrollWidth:e.tabsRef.scrollWidth,left:a.left,right:a.right}}if(e.tabsRef&&!1!==t){var o=e.tabsRef.children[0].children;if(o.length>0){var s=o[e.valueToIndex.get(t)];i=s?s.getBoundingClientRect():null}}return{tabsMeta:r,tabMeta:i}},e.handleLeftScrollClick=function(){e.moveTabsScroll(-e.tabsRef.clientWidth)},e.handleRightScrollClick=function(){e.moveTabsScroll(e.tabsRef.clientWidth)},e.handleScrollbarSizeChange=function(t){e.setState({scrollerStyle:{marginBottom:-t}})},e.moveTabsScroll=function(t){var n=e.props.theme,r="rtl"===n.direction?-1:1,i=e.tabsRef.scrollLeft+t*r,a="rtl"===n.direction&&"reverse"===(0,m.detectScrollType)()?-1:1;e.scroll(a*i)},e.scrollSelectedIntoView=function(){var t=e.props,n=t.theme,r=t.value,i=e.getTabsMeta(r,n.direction),a=i.tabsMeta,o=i.tabMeta;if(o&&a){if(o.lefta.right){var u=a.scrollLeft+(o.right-a.right);e.scroll(u)}}},e.scroll=function(t){(0,g.default)("scrollLeft",e.tabsRef,t)},e.updateScrollButtonState=function(){var t=e.props,n=t.scrollable,r=t.scrollButtons,i=t.theme;if(("scrollable"===t.variant||n)&&"off"!==r){var a=e.tabsRef,o=a.scrollWidth,s=a.clientWidth,u=(0,m.getNormalizedScrollLeft)(e.tabsRef,i.direction),c="rtl"===i.direction?o>s+u:u>0,l="rtl"===i.direction?u>0:o>s+u;(c!==e.state.showLeftScroll||l!==e.state.showRightScroll)&&e.setState({showLeftScroll:c,showRightScroll:l})}},"undefined"!=typeof window&&(e.handleResize=(0,b.default)(function(){e.updateIndicatorState(e.props),e.updateScrollButtonState()},166),e.handleTabsScroll=(0,b.default)(function(){e.updateScrollButtonState()},166)),e}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){this.setState({mounted:!0}),this.updateIndicatorState(this.props),this.updateScrollButtonState(),this.props.action&&this.props.action({updateIndicator:this.handleResize})}},{key:"componentDidUpdate",value:function(e,t){this.updateIndicatorState(this.props),this.updateScrollButtonState(),this.state.indicatorStyle!==t.indicatorStyle&&this.scrollSelectedIntoView()}},{key:"componentWillUnmount",value:function(){this.handleResize.clear(),this.handleTabsScroll.clear()}},{key:"updateIndicatorState",value:function(e){var t=e.theme,n=e.value,r=this.getTabsMeta(n,t.direction),i=r.tabsMeta,a=r.tabMeta,o=0;if(a&&i){var s="rtl"===t.direction?i.scrollLeftNormalized+i.clientWidth-i.scrollWidth:i.scrollLeft;o=Math.round(a.left-i.left+s)}var u={left:o,width:a?Math.round(a.width):0};u.left===this.state.indicatorStyle.left&&u.width===this.state.indicatorStyle.width||isNaN(u.left)||isNaN(u.width)||this.setState({indicatorStyle:u})}},{key:"render",value:function(){var e,t=this,n=this.props,r=(n.action,n.centered),o=n.children,s=n.classes,u=n.className,c=n.component,l=n.fullWidth,b=void 0!==l&&l,m=n.indicatorColor,g=n.onChange,v=n.scrollable,y=void 0!==v&&v,_=(n.ScrollButtonComponent,n.scrollButtons,n.TabIndicatorProps),E=void 0===_?{}:_,S=n.textColor,k=(n.theme,n.value),x=n.variant,T=(0,a.default)(n,["action","centered","children","classes","className","component","fullWidth","indicatorColor","onChange","scrollable","ScrollButtonComponent","scrollButtons","TabIndicatorProps","textColor","theme","value","variant"]),M="scrollable"===x||y,O=(0,h.default)(s.root,u),A=(0,h.default)(s.flexContainer,(0,f.default)({},s.centered,r&&!M)),L=(0,h.default)(s.scroller,(e={},(0,f.default)(e,s.fixed,!M),(0,f.default)(e,s.scrollable,M),e)),C=d.default.createElement(w.default,(0,i.default)({className:s.indicator,color:m},E,{style:(0,i.default)({},this.state.indicatorStyle,E.style)}));this.valueToIndex=new Map;var I=0,D=d.default.Children.map(o,function(e){if(!d.default.isValidElement(e))return null;var n=void 0===e.props.value?I:e.props.value;t.valueToIndex.set(n,I);var r=n===k;return I+=1,d.default.cloneElement(e,{fullWidth:"fullWidth"===x||b,indicator:r&&!t.state.mounted&&C,selected:r,onChange:g,textColor:S,value:n})}),N=this.getConditionalElements();return d.default.createElement(c,(0,i.default)({className:O},T),d.default.createElement(p.default,{target:"window",onResize:this.handleResize}),N.scrollbarSizeListener,d.default.createElement("div",{className:s.flexContainer},N.scrollButtonLeft,d.default.createElement("div",{className:L,style:this.state.scrollerStyle,ref:function(e){t.tabsRef=e},role:"tablist",onScroll:this.handleTabsScroll},d.default.createElement("div",{className:A},D),this.state.mounted&&C),N.scrollButtonRight))}}]),t}(d.default.Component);S.defaultProps={centered:!1,component:"div",indicatorColor:"secondary",ScrollButtonComponent:_.default,scrollButtons:"auto",textColor:"inherit",variant:"standard"};var k=(0,y.default)(E,{name:"MuiTabs",withTheme:!0})(S);t.default=k},12794(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(89172))},78592(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294)),d=r(n(73935));r(n(42473)),r(n(45697));var h=r(n(54846)),p=r(n(1402)),b=r(n(59537)),m=r(n(23153)),g=r(n(85461)),v=r(n(76023)),y=r(n(11970)),w={standard:h.default,filled:p.default,outlined:b.default},_=function(e){function t(e){var n;return(0,o.default)(this,t),(n=(0,u.default)(this,(0,c.default)(t).call(this,e))).labelRef=f.default.createRef(),n}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){"outlined"===this.props.variant&&(this.labelNode=d.default.findDOMNode(this.labelRef.current),this.forceUpdate())}},{key:"render",value:function(){var e=this.props,t=e.autoComplete,n=e.autoFocus,r=e.children,o=e.className,s=e.defaultValue,u=e.error,c=e.FormHelperTextProps,l=e.fullWidth,d=e.helperText,h=e.id,p=e.InputLabelProps,b=e.inputProps,_=e.InputProps,E=e.inputRef,S=e.label,k=e.multiline,x=e.name,T=e.onBlur,M=e.onChange,O=e.onFocus,A=e.placeholder,L=e.required,C=e.rows,I=e.rowsMax,D=e.select,N=e.SelectProps,P=e.type,R=e.value,j=e.variant,F=(0,a.default)(e,["autoComplete","autoFocus","children","className","defaultValue","error","FormHelperTextProps","fullWidth","helperText","id","InputLabelProps","inputProps","InputProps","inputRef","label","multiline","name","onBlur","onChange","onFocus","placeholder","required","rows","rowsMax","select","SelectProps","type","value","variant"]),Y={};"outlined"===j&&(p&&void 0!==p.shrink&&(Y.notched=p.shrink),Y.labelWidth=this.labelNode&&this.labelNode.offsetWidth||0);var B=d&&h?"".concat(h,"-helper-text"):void 0,U=w[j],H=f.default.createElement(U,(0,i.default)({"aria-describedby":B,autoComplete:t,autoFocus:n,defaultValue:s,fullWidth:l,multiline:k,name:x,rows:C,rowsMax:I,type:P,value:R,id:h,inputRef:E,onBlur:T,onChange:M,onFocus:O,placeholder:A,inputProps:b},Y,_));return f.default.createElement(g.default,(0,i.default)({className:o,error:u,fullWidth:l,required:L,variant:j},F),S&&f.default.createElement(m.default,(0,i.default)({htmlFor:h,ref:this.labelRef},p),S),D?f.default.createElement(y.default,(0,i.default)({"aria-describedby":B,value:R,input:H},N),r):H,d&&f.default.createElement(v.default,(0,i.default)({id:B},c),d))}}]),t}(f.default.Component);_.defaultProps={required:!1,select:!1,variant:"standard"};var E=_;t.default=E},60520(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(78592))},48596(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184)),c=r(n(78252)),l=function(e){return{root:{position:"relative",display:"flex",alignItems:"center"},gutters:e.mixins.gutters(),regular:e.mixins.toolbar,dense:{minHeight:48}}};function f(e){var t=e.children,n=e.classes,r=e.className,c=e.disableGutters,l=e.variant,f=(0,o.default)(e,["children","classes","className","disableGutters","variant"]),d=(0,u.default)(n.root,n[l],(0,a.default)({},n.gutters,!c),r);return s.default.createElement("div",(0,i.default)({className:d},f),t)}t.styles=l,f.defaultProps={disableGutters:!1,variant:"regular"};var d=(0,c.default)(l,{name:"MuiToolbar"})(f);t.default=d},28902(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(48596))},83065(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(59713)),d=r(n(67294));r(n(45697)),r(n(42473));var h=r(n(94184));n(55252);var p=r(n(39737)),b=r(n(78252)),m=n(98741),g=r(n(261)),v=r(n(60111)),y=function(e){return{popper:{zIndex:e.zIndex.tooltip,opacity:.9,pointerEvents:"none"},popperInteractive:{pointerEvents:"auto"},tooltip:{backgroundColor:e.palette.grey[700],borderRadius:e.shape.borderRadius,color:e.palette.common.white,fontFamily:e.typography.fontFamily,padding:"4px 8px",fontSize:e.typography.pxToRem(10),lineHeight:"".concat(e.typography.round(1.4),"em"),maxWidth:300},touch:{padding:"8px 16px",fontSize:e.typography.pxToRem(14),lineHeight:"".concat(e.typography.round(16/14),"em")},tooltipPlacementLeft:(0,f.default)({transformOrigin:"right center",margin:"0 24px "},e.breakpoints.up("sm"),{margin:"0 14px"}),tooltipPlacementRight:(0,f.default)({transformOrigin:"left center",margin:"0 24px"},e.breakpoints.up("sm"),{margin:"0 14px"}),tooltipPlacementTop:(0,f.default)({transformOrigin:"center bottom",margin:"24px 0"},e.breakpoints.up("sm"),{margin:"14px 0"}),tooltipPlacementBottom:(0,f.default)({transformOrigin:"center top",margin:"24px 0"},e.breakpoints.up("sm"),{margin:"14px 0"})}};t.styles=y;var w=function(e){function t(e){var n;return(0,o.default)(this,t),(n=(0,u.default)(this,(0,c.default)(t).call(this))).ignoreNonTouchEvents=!1,n.onRootRef=function(e){n.childrenRef=e},n.handleFocus=function(e){n.childrenRef||(n.childrenRef=e.currentTarget),n.handleEnter(e);var t=n.props.children.props;t.onFocus&&t.onFocus(e)},n.handleEnter=function(e){var t=n.props,r=t.children,i=t.enterDelay,a=r.props;"mouseover"===e.type&&a.onMouseOver&&a.onMouseOver(e),(!n.ignoreNonTouchEvents||"touchstart"===e.type)&&(n.childrenRef.setAttribute("title",""),clearTimeout(n.enterTimer),clearTimeout(n.leaveTimer),i?(e.persist(),n.enterTimer=setTimeout(function(){n.handleOpen(e)},i)):n.handleOpen(e))},n.handleOpen=function(e){n.isControlled||n.state.open||n.setState({open:!0}),n.props.onOpen&&n.props.onOpen(e)},n.handleLeave=function(e){var t=n.props,r=t.children,i=t.leaveDelay,a=r.props;"blur"===e.type&&a.onBlur&&a.onBlur(e),"mouseleave"===e.type&&a.onMouseLeave&&a.onMouseLeave(e),clearTimeout(n.enterTimer),clearTimeout(n.leaveTimer),i?(e.persist(),n.leaveTimer=setTimeout(function(){n.handleClose(e)},i)):n.handleClose(e)},n.handleClose=function(e){n.isControlled||n.setState({open:!1}),n.props.onClose&&n.props.onClose(e),clearTimeout(n.closeTimer),n.closeTimer=setTimeout(function(){n.ignoreNonTouchEvents=!1},n.props.theme.transitions.duration.shortest)},n.handleTouchStart=function(e){n.ignoreNonTouchEvents=!0;var t=n.props,r=t.children,i=t.enterTouchDelay;r.props.onTouchStart&&r.props.onTouchStart(e),clearTimeout(n.leaveTimer),clearTimeout(n.closeTimer),clearTimeout(n.touchTimer),e.persist(),n.touchTimer=setTimeout(function(){n.handleEnter(e)},i)},n.handleTouchEnd=function(e){var t=n.props,r=t.children,i=t.leaveTouchDelay;r.props.onTouchEnd&&r.props.onTouchEnd(e),clearTimeout(n.touchTimer),clearTimeout(n.leaveTimer),e.persist(),n.leaveTimer=setTimeout(function(){n.handleClose(e)},i)},n.isControlled=null!=e.open,n.state={open:null},n.isControlled||(n.state.open=!1),n}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){this.defaultId="mui-tooltip-".concat(Math.round(1e5*Math.random())),this.props.open&&this.forceUpdate()}},{key:"componentWillUnmount",value:function(){clearTimeout(this.closeTimer),clearTimeout(this.enterTimer),clearTimeout(this.focusTimer),clearTimeout(this.leaveTimer),clearTimeout(this.touchTimer)}},{key:"render",value:function(){var e=this,t=this.props,n=t.children,r=t.classes,o=t.disableFocusListener,s=t.disableHoverListener,u=t.disableTouchListener,c=(t.enterDelay,t.enterTouchDelay,t.id),l=t.interactive,b=(t.leaveDelay,t.leaveTouchDelay,t.onClose,t.onOpen,t.open),g=t.placement,y=t.PopperProps,w=t.theme,_=t.title,E=t.TransitionComponent,S=t.TransitionProps,k=(0,a.default)(t,["children","classes","disableFocusListener","disableHoverListener","disableTouchListener","enterDelay","enterTouchDelay","id","interactive","leaveDelay","leaveTouchDelay","onClose","onOpen","open","placement","PopperProps","theme","title","TransitionComponent","TransitionProps"]),x=this.isControlled?b:this.state.open;""===_&&(x=!1);var T=!x&&!s,M=(0,i.default)({"aria-describedby":x?c||this.defaultId:null,title:T&&"string"==typeof _?_:null},k,n.props,{className:(0,h.default)(k.className,n.props.className)});u||(M.onTouchStart=this.handleTouchStart,M.onTouchEnd=this.handleTouchEnd),s||(M.onMouseOver=this.handleEnter,M.onMouseLeave=this.handleLeave),o||(M.onFocus=this.handleFocus,M.onBlur=this.handleLeave);var O=l?{onMouseOver:M.onMouseOver,onMouseLeave:M.onMouseLeave,onFocus:M.onFocus,onBlur:M.onBlur}:{};return d.default.createElement(d.default.Fragment,null,d.default.createElement(p.default,{rootRef:this.onRootRef},d.default.cloneElement(n,M)),d.default.createElement(v.default,(0,i.default)({className:(0,h.default)(r.popper,(0,f.default)({},r.popperInteractive,l)),placement:g,anchorEl:this.childrenRef,open:x,id:M["aria-describedby"],transition:!0},O,y),function(t){var n=t.placement,a=t.TransitionProps;return d.default.createElement(E,(0,i.default)({timeout:w.transitions.duration.shorter},a,S),d.default.createElement("div",{className:(0,h.default)(r.tooltip,(0,f.default)({},r.touch,e.ignoreNonTouchEvents),r["tooltipPlacement".concat((0,m.capitalize)(n.split("-")[0]))])},_))}))}}]),t}(d.default.Component);w.defaultProps={disableFocusListener:!1,disableHoverListener:!1,disableTouchListener:!1,enterDelay:0,enterTouchDelay:1e3,interactive:!1,leaveDelay:0,leaveTouchDelay:1500,placement:"bottom",TransitionComponent:g.default};var _=(0,b.default)(y,{name:"MuiTooltip",withTheme:!0})(w);t.default=_},31657(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"Z",{enumerable:!0,get:function(){return a.default}});var a=i(n(83065))},49476(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(67294));r(n(45697));var u=r(n(94184));n(55252);var c=r(n(78252)),l=n(98741),f=function(e){return{root:{display:"block",margin:0},display4:e.typography.display4,display3:e.typography.display3,display2:e.typography.display2,display1:e.typography.display1,headline:e.typography.headline,title:e.typography.title,subheading:e.typography.subheading,body2:e.typography.body2,body1:e.typography.body1,caption:e.typography.caption,button:e.typography.button,h1:e.typography.h1,h2:e.typography.h2,h3:e.typography.h3,h4:e.typography.h4,h5:e.typography.h5,h6:e.typography.h6,subtitle1:e.typography.subtitle1,subtitle2:e.typography.subtitle2,overline:e.typography.overline,srOnly:{position:"absolute",height:1,width:1,overflow:"hidden"},alignLeft:{textAlign:"left"},alignCenter:{textAlign:"center"},alignRight:{textAlign:"right"},alignJustify:{textAlign:"justify"},noWrap:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},gutterBottom:{marginBottom:"0.35em"},paragraph:{marginBottom:16},colorInherit:{color:"inherit"},colorPrimary:{color:e.palette.primary.main},colorSecondary:{color:e.palette.secondary.main},colorTextPrimary:{color:e.palette.text.primary},colorTextSecondary:{color:e.palette.text.secondary},colorError:{color:e.palette.error.main},inline:{display:"inline"}}};t.styles=f;var d={display4:"h1",display3:"h2",display2:"h3",display1:"h4",headline:"h5",title:"h6",subheading:"subtitle1"};function h(e,t){var n=e.typography,r=t;return r||(r=n.useNextVariants?"body2":"body1"),n.useNextVariants&&(r=d[r]||r),r}var p={h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",h6:"h6",subtitle1:"h6",subtitle2:"h6",body1:"p",body2:"p",display4:"h1",display3:"h1",display2:"h1",display1:"h1",headline:"h1",title:"h2",subheading:"h3"};function b(e){var t,n=e.align,r=e.classes,c=e.className,f=e.color,d=e.component,b=e.gutterBottom,m=e.headlineMapping,g=e.inline,v=(e.internalDeprecatedVariant,e.noWrap),y=e.paragraph,w=e.theme,_=e.variant,E=(0,o.default)(e,["align","classes","className","color","component","gutterBottom","headlineMapping","inline","internalDeprecatedVariant","noWrap","paragraph","theme","variant"]),S=h(w,_),k=(0,u.default)(r.root,(t={},(0,a.default)(t,r[S],"inherit"!==S),(0,a.default)(t,r["color".concat((0,l.capitalize)(f))],"default"!==f),(0,a.default)(t,r.noWrap,v),(0,a.default)(t,r.gutterBottom,b),(0,a.default)(t,r.paragraph,y),(0,a.default)(t,r["align".concat((0,l.capitalize)(n))],"inherit"!==n),(0,a.default)(t,r.inline,g),t),c),x=d||(y?"p":m[S]||p[S])||"span";return s.default.createElement(x,(0,i.default)({className:k},E))}b.defaultProps={align:"inherit",color:"default",gutterBottom:!1,headlineMapping:p,inline:!1,noWrap:!1,paragraph:!1};var m=(0,c.default)(f,{name:"MuiTypography",withTheme:!0})(b);t.default=m},71426(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i.default}});var i=r(n(49476))},8070(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#fff8e1",100:"#ffecb3",200:"#ffe082",300:"#ffd54f",400:"#ffca28",500:"#ffc107",600:"#ffb300",700:"#ffa000",800:"#ff8f00",900:"#ff6f00",A100:"#ffe57f",A200:"#ffd740",A400:"#ffc400",A700:"#ffab00"};t.default=n},63259(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#e3f2fd",100:"#bbdefb",200:"#90caf9",300:"#64b5f6",400:"#42a5f5",500:"#2196f3",600:"#1e88e5",700:"#1976d2",800:"#1565c0",900:"#0d47a1",A100:"#82b1ff",A200:"#448aff",A400:"#2979ff",A700:"#2962ff"};t.default=n},38236(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#eceff1",100:"#cfd8dc",200:"#b0bec5",300:"#90a4ae",400:"#78909c",500:"#607d8b",600:"#546e7a",700:"#455a64",800:"#37474f",900:"#263238",A100:"#cfd8dc",A200:"#b0bec5",A400:"#78909c",A700:"#455a64"};t.default=n},60169(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#efebe9",100:"#d7ccc8",200:"#bcaaa4",300:"#a1887f",400:"#8d6e63",500:"#795548",600:"#6d4c41",700:"#5d4037",800:"#4e342e",900:"#3e2723",A100:"#d7ccc8",A200:"#bcaaa4",A400:"#8d6e63",A700:"#5d4037"};t.default=n},515(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={black:"#000",white:"#fff"};t.default=n},57646(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#e0f7fa",100:"#b2ebf2",200:"#80deea",300:"#4dd0e1",400:"#26c6da",500:"#00bcd4",600:"#00acc1",700:"#0097a7",800:"#00838f",900:"#006064",A100:"#84ffff",A200:"#18ffff",A400:"#00e5ff",A700:"#00b8d4"};t.default=n},50173(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#fbe9e7",100:"#ffccbc",200:"#ffab91",300:"#ff8a65",400:"#ff7043",500:"#ff5722",600:"#f4511e",700:"#e64a19",800:"#d84315",900:"#bf360c",A100:"#ff9e80",A200:"#ff6e40",A400:"#ff3d00",A700:"#dd2c00"};t.default=n},45018(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#ede7f6",100:"#d1c4e9",200:"#b39ddb",300:"#9575cd",400:"#7e57c2",500:"#673ab7",600:"#5e35b1",700:"#512da8",800:"#4527a0",900:"#311b92",A100:"#b388ff",A200:"#7c4dff",A400:"#651fff",A700:"#6200ea"};t.default=n},47559(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#e8f5e9",100:"#c8e6c9",200:"#a5d6a7",300:"#81c784",400:"#66bb6a",500:"#4caf50",600:"#43a047",700:"#388e3c",800:"#2e7d32",900:"#1b5e20",A100:"#b9f6ca",A200:"#69f0ae",A400:"#00e676",A700:"#00c853"};t.default=n},70167(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#fafafa",100:"#f5f5f5",200:"#eeeeee",300:"#e0e0e0",400:"#bdbdbd",500:"#9e9e9e",600:"#757575",700:"#616161",800:"#424242",900:"#212121",A100:"#d5d5d5",A200:"#aaaaaa",A400:"#303030",A700:"#616161"};t.default=n},19350(e,t,n){"use strict";var r,i=n(95318);r={value:!0},Object.defineProperty(t,"y0",{enumerable:!0,get:function(){return a.default}}),r={enumerable:!0,get:function(){return o.default}},r={enumerable:!0,get:function(){return s.default}},r={enumerable:!0,get:function(){return u.default}},r={enumerable:!0,get:function(){return c.default}},r={enumerable:!0,get:function(){return l.default}},r={enumerable:!0,get:function(){return f.default}},r={enumerable:!0,get:function(){return d.default}},r={enumerable:!0,get:function(){return h.default}},r={enumerable:!0,get:function(){return p.default}},Object.defineProperty(t,"ek",{enumerable:!0,get:function(){return b.default}}),r={enumerable:!0,get:function(){return m.default}},r={enumerable:!0,get:function(){return g.default}},r={enumerable:!0,get:function(){return v.default}},r={enumerable:!0,get:function(){return y.default}},r={enumerable:!0,get:function(){return w.default}},r={enumerable:!0,get:function(){return _.default}},r={enumerable:!0,get:function(){return E.default}},Object.defineProperty(t,"BA",{enumerable:!0,get:function(){return S.default}}),r={enumerable:!0,get:function(){return k.default}};var a=i(n(515)),o=i(n(83165)),s=i(n(124)),u=i(n(18118)),c=i(n(45018)),l=i(n(78768)),f=i(n(63259)),d=i(n(4923)),h=i(n(57646)),p=i(n(91605)),b=i(n(47559)),m=i(n(40192)),g=i(n(98567)),v=i(n(74578)),y=i(n(8070)),w=i(n(36594)),_=i(n(50173)),E=i(n(60169)),S=i(n(70167)),k=i(n(38236))},78768(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#e8eaf6",100:"#c5cae9",200:"#9fa8da",300:"#7986cb",400:"#5c6bc0",500:"#3f51b5",600:"#3949ab",700:"#303f9f",800:"#283593",900:"#1a237e",A100:"#8c9eff",A200:"#536dfe",A400:"#3d5afe",A700:"#304ffe"};t.default=n},4923(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#e1f5fe",100:"#b3e5fc",200:"#81d4fa",300:"#4fc3f7",400:"#29b6f6",500:"#03a9f4",600:"#039be5",700:"#0288d1",800:"#0277bd",900:"#01579b",A100:"#80d8ff",A200:"#40c4ff",A400:"#00b0ff",A700:"#0091ea"};t.default=n},40192(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#f1f8e9",100:"#dcedc8",200:"#c5e1a5",300:"#aed581",400:"#9ccc65",500:"#8bc34a",600:"#7cb342",700:"#689f38",800:"#558b2f",900:"#33691e",A100:"#ccff90",A200:"#b2ff59",A400:"#76ff03",A700:"#64dd17"};t.default=n},98567(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#f9fbe7",100:"#f0f4c3",200:"#e6ee9c",300:"#dce775",400:"#d4e157",500:"#cddc39",600:"#c0ca33",700:"#afb42b",800:"#9e9d24",900:"#827717",A100:"#f4ff81",A200:"#eeff41",A400:"#c6ff00",A700:"#aeea00"};t.default=n},36594(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#fff3e0",100:"#ffe0b2",200:"#ffcc80",300:"#ffb74d",400:"#ffa726",500:"#ff9800",600:"#fb8c00",700:"#f57c00",800:"#ef6c00",900:"#e65100",A100:"#ffd180",A200:"#ffab40",A400:"#ff9100",A700:"#ff6d00"};t.default=n},124(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#fce4ec",100:"#f8bbd0",200:"#f48fb1",300:"#f06292",400:"#ec407a",500:"#e91e63",600:"#d81b60",700:"#c2185b",800:"#ad1457",900:"#880e4f",A100:"#ff80ab",A200:"#ff4081",A400:"#f50057",A700:"#c51162"};t.default=n},18118(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#f3e5f5",100:"#e1bee7",200:"#ce93d8",300:"#ba68c8",400:"#ab47bc",500:"#9c27b0",600:"#8e24aa",700:"#7b1fa2",800:"#6a1b9a",900:"#4a148c",A100:"#ea80fc",A200:"#e040fb",A400:"#d500f9",A700:"#aa00ff"};t.default=n},83165(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#ffebee",100:"#ffcdd2",200:"#ef9a9a",300:"#e57373",400:"#ef5350",500:"#f44336",600:"#e53935",700:"#d32f2f",800:"#c62828",900:"#b71c1c",A100:"#ff8a80",A200:"#ff5252",A400:"#ff1744",A700:"#d50000"};t.default=n},91605(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#e0f2f1",100:"#b2dfdb",200:"#80cbc4",300:"#4db6ac",400:"#26a69a",500:"#009688",600:"#00897b",700:"#00796b",800:"#00695c",900:"#004d40",A100:"#a7ffeb",A200:"#64ffda",A400:"#1de9b6",A700:"#00bfa5"};t.default=n},74578(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={50:"#fffde7",100:"#fff9c4",200:"#fff59d",300:"#fff176",400:"#ffee58",500:"#ffeb3b",600:"#fdd835",700:"#fbc02d",800:"#f9a825",900:"#f57f17",A100:"#ffff8d",A200:"#ffff00",A400:"#ffea00",A700:"#ffd600"};t.default=n},85609(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.styles=void 0;var i=r(n(67154)),a=r(n(59713)),o=r(n(6479)),s=r(n(34575)),u=r(n(93913)),c=r(n(78585)),l=r(n(29754)),f=r(n(2205)),d=r(n(67294));r(n(45697));var h=r(n(94184)),p=r(n(52598)),b=r(n(78252)),m=r(n(81701)),g={root:{display:"inline-flex",alignItems:"center",transition:"none","&:hover":{backgroundColor:"transparent"}},checked:{},disabled:{},input:{cursor:"inherit",position:"absolute",opacity:0,width:"100%",height:"100%",top:0,left:0,margin:0,padding:0}};t.styles=g;var v=function(e){function t(e){var n;return(0,s.default)(this,t),(n=(0,c.default)(this,(0,l.default)(t).call(this))).handleFocus=function(e){n.props.onFocus&&n.props.onFocus(e);var t=n.props.muiFormControl;t&&t.onFocus&&t.onFocus(e)},n.handleBlur=function(e){n.props.onBlur&&n.props.onBlur(e);var t=n.props.muiFormControl;t&&t.onBlur&&t.onBlur(e)},n.handleInputChange=function(e){var t=e.target.checked;n.isControlled||n.setState({checked:t}),n.props.onChange&&n.props.onChange(e,t)},n.isControlled=null!=e.checked,n.state={},n.isControlled||(n.state.checked=void 0!==e.defaultChecked&&e.defaultChecked),n}return(0,f.default)(t,e),(0,u.default)(t,[{key:"render",value:function(){var e,t=this.props,n=t.autoFocus,r=t.checked,s=t.checkedIcon,u=t.classes,c=t.className,l=t.defaultChecked,f=t.disabled,p=t.icon,b=t.id,g=t.inputProps,v=t.inputRef,y=t.muiFormControl,w=t.name,_=(t.onBlur,t.onChange,t.onFocus,t.readOnly),E=t.required,S=t.tabIndex,k=t.type,x=t.value,T=(0,o.default)(t,["autoFocus","checked","checkedIcon","classes","className","defaultChecked","disabled","icon","id","inputProps","inputRef","muiFormControl","name","onBlur","onChange","onFocus","readOnly","required","tabIndex","type","value"]),M=f;y&&void 0===M&&(M=y.disabled);var O=this.isControlled?r:this.state.checked,A="checkbox"===k||"radio"===k;return d.default.createElement(m.default,(0,i.default)({component:"span",className:(0,h.default)(u.root,(e={},(0,a.default)(e,u.checked,O),(0,a.default)(e,u.disabled,M),e),c),disabled:M,tabIndex:null,role:void 0,onFocus:this.handleFocus,onBlur:this.handleBlur},T),O?s:p,d.default.createElement("input",(0,i.default)({autoFocus:n,checked:r,defaultChecked:l,className:u.input,disabled:M,id:A&&b,name:w,onChange:this.handleInputChange,readOnly:_,ref:v,required:E,tabIndex:S,type:k,value:x},g)))}}]),t}(d.default.Component),y=(0,b.default)(g,{name:"MuiPrivateSwitchBase"})((0,p.default)(v));t.default=y},13329(e,t){"use strict";function n(e){return(1+Math.sin(Math.PI*e-Math.PI/2))/2}function r(e,t,r){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:function(){},o=i.ease,s=void 0===o?n:o,u=i.duration,c=void 0===u?300:u,l=null,f=t[e],d=!1,h=function(){d=!0},p=function n(i){if(d){a(Error("Animation cancelled"));return}null===l&&(l=i);var o=Math.min(1,(i-l)/c);if(t[e]=s(o)*(r-f)+f,o>=1){requestAnimationFrame(function(){a(null)});return}requestAnimationFrame(n)};return f===r?(a(Error("Element already at target position")),h):(requestAnimationFrame(p),h)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r;t.default=i},74622(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)),a=r(n(46949)),o=r(n(40577)),s=i.default.createElement("path",{d:"M7 10l5 5 5-5z"}),u=function(e){return i.default.createElement(o.default,e,s)};(u=(0,a.default)(u)).muiName="SvgIcon";var c=u;t.default=c},99781(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)),a=r(n(46949)),o=r(n(40577)),s=i.default.createElement("path",{d:"M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"}),u=function(e){return i.default.createElement(o.default,e,s)};(u=(0,a.default)(u)).muiName="SvgIcon";var c=u;t.default=c},41549(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)),a=r(n(46949)),o=r(n(40577)),s=i.default.createElement("path",{d:"M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"}),u=function(e){return i.default.createElement(o.default,e,s)};(u=(0,a.default)(u)).muiName="SvgIcon";var c=u;t.default=c},42159(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)),a=r(n(46949)),o=r(n(40577)),s=i.default.createElement("path",{d:"M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"}),u=function(e){return i.default.createElement(o.default,e,s)};(u=(0,a.default)(u)).muiName="SvgIcon";var c=u;t.default=c},61486(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)),a=r(n(46949)),o=r(n(40577)),s=i.default.createElement("path",{d:"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10H7v-2h10v2z"}),u=function(e){return i.default.createElement(o.default,e,s)};(u=(0,a.default)(u)).muiName="SvgIcon";var c=u;t.default=c},86861(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)),a=r(n(46949)),o=r(n(40577)),s=i.default.createElement("path",{d:"M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"}),u=function(e){return i.default.createElement(o.default,e,s)};(u=(0,a.default)(u)).muiName="SvgIcon";var c=u;t.default=c},43836(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67294)),a=r(n(46949)),o=r(n(40577)),s=i.default.createElement("path",{d:"M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"}),u=function(e){return i.default.createElement(o.default,e,s)};(u=(0,a.default)(u)).muiName="SvgIcon";var c=u;t.default=c},93078(e,t,n){"use strict";/*! + * is-plain-object + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ var r=n(47798);function i(e){return!0===r(e)&&"[object Object]"===Object.prototype.toString.call(e)}e.exports=function(e){var t,n;return!1!==i(e)&&"function"==typeof(t=e.constructor)&&!1!==i(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")}},72366(e,t,n){"use strict";var r=n(20862),i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.MuiThemeProviderOld=void 0;var a=i(n(67154)),o=i(n(59713)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294)),h=i(n(45697));i(n(42473));var p=i(n(43890)),b=n(55252),m=r(n(51067)),g=function(e){function t(e,n){var r;return(0,s.default)(this,t),(r=(0,c.default)(this,(0,l.default)(t).call(this))).broadcast=(0,p.default)(),r.outerTheme=m.default.initial(n),r.broadcast.setState(r.mergeOuterLocalTheme(e.theme)),r}return(0,f.default)(t,e),(0,u.default)(t,[{key:"getChildContext",value:function(){var e,t=this.props,n=t.disableStylesGeneration,r=t.sheetsCache,i=t.sheetsManager,a=this.context.muiThemeProviderOptions||{};return void 0!==n&&(a.disableStylesGeneration=n),void 0!==r&&(a.sheetsCache=r),void 0!==i&&(a.sheetsManager=i),e={},(0,o.default)(e,m.CHANNEL,this.broadcast),(0,o.default)(e,"muiThemeProviderOptions",a),e}},{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.outerTheme=t,e.broadcast.setState(e.mergeOuterLocalTheme(e.props.theme))})}},{key:"componentDidUpdate",value:function(e){this.props.theme!==e.theme&&this.broadcast.setState(this.mergeOuterLocalTheme(this.props.theme))}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"mergeOuterLocalTheme",value:function(e){return"function"==typeof e?e(this.outerTheme):this.outerTheme?(0,a.default)({},this.outerTheme,e):e}},{key:"render",value:function(){return this.props.children}}]),t}(d.default.Component);t.MuiThemeProviderOld=g,g.childContextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),g.contextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider||(b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider=g);var v=b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider;t.default=v},59114(e,t,n){"use strict";var r=n(95318);function i(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return en?n:e}function a(e){e=e.substr(1);var t=RegExp(".{1,".concat(e.length/3,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map(function(e){return e+e})),n?"rgb(".concat(n.map(function(e){return parseInt(e,16)}).join(", "),")"):""}function o(e){if(0===e.indexOf("#"))return e;function t(e){var t=e.toString(16);return 1===t.length?"0".concat(t):t}var n=s(e).values;return n=n.map(function(e){return t(e)}),"#".concat(n.join(""))}function s(e){if("#"===e.charAt(0))return s(a(e));var t=e.indexOf("("),n=e.substring(0,t),r=e.substring(t+1,e.length-1).split(",");return r=r.map(function(e){return parseFloat(e)}),{type:n,values:r}}function u(e){var t=e.type,n=e.values;return -1!==t.indexOf("rgb")&&(n=n.map(function(e,t){return t<3?parseInt(e,10):e})),-1!==t.indexOf("hsl")&&(n[1]="".concat(n[1],"%"),n[2]="".concat(n[2],"%")),"".concat(e.type,"(").concat(n.join(", "),")")}function c(e,t){var n=l(e),r=l(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function l(e){var t=s(e);if(-1!==t.type.indexOf("rgb")){var n=t.values.map(function(e){return(e/=255)<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)});return Number((.2126*n[0]+.7152*n[1]+.0722*n[2]).toFixed(3))}return t.values[2]/100}function f(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return l(e)>.5?h(e,t):p(e,t)}function d(e,t){return e?(e=s(e),t=i(t),("rgb"===e.type||"hsl"===e.type)&&(e.type+="a"),e.values[3]=t,u(e)):e}function h(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return u(e)}function p(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;return u(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.convertHexToRGB=a,t.rgbToHex=o,t.decomposeColor=s,t.recomposeColor=u,t.getContrastRatio=c,t.getLuminance=l,t.emphasize=f,t.fade=d,t.darken=h,t.lighten=p,r(n(42473))},94811(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=s,t.keys=void 0;var i=r(n(67154)),a=r(n(6479)),o=["xs","sm","md","lg","xl"];function s(e){var t=e.values,n=void 0===t?{xs:0,sm:600,md:960,lg:1280,xl:1920}:t,r=e.unit,s=void 0===r?"px":r,u=e.step,c=void 0===u?5:u,l=(0,a.default)(e,["values","unit","step"]);function f(e){var t="number"==typeof n[e]?n[e]:e;return"@media (min-width:".concat(t).concat(s,")")}function d(e){var t=o.indexOf(e)+1,r=n[o[t]];if(t===o.length)return f("xs");var i="number"==typeof r&&t>0?r:e;return"@media (max-width:".concat(i-c/100).concat(s,")")}function h(e,t){var r=o.indexOf(t)+1;return r===o.length?f(e):"@media (min-width:".concat(n[e]).concat(s,") and ")+"(max-width:".concat(n[o[r]]-c/100).concat(s,")")}function p(e){return h(e,e)}function b(e){return n[e]}return(0,i.default)({keys:o,values:n,up:f,down:d,between:h,only:p,width:b},l)}t.keys=o},20237(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o,r(n(42473));var i=/([[\].#*$><+~=|^:(),"'`\s])/g;function a(e){var t;return String(e).replace(i,"-")}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.dangerouslyUseGlobalCSS,n=void 0!==t&&t,r=e.productionPrefix,i=void 0===r?"jss":r,o=e.seed,s=void 0===o?"":o,u=0;return function(e,t){return(u+=1,n&&t&&t.options.name)?"".concat(a(t.options.name),"-").concat(e.key):"".concat(i).concat(s).concat(u)}}},40226(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o;var i=r(n(59713)),a=r(n(67154));function o(e,t,n){var r;return(0,a.default)({gutters:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,a.default)({paddingLeft:2*t.unit,paddingRight:2*t.unit},n,(0,i.default)({},e.up("sm"),(0,a.default)({paddingLeft:3*t.unit,paddingRight:3*t.unit},n[e.up("sm")])))},toolbar:(r={minHeight:56},(0,i.default)(r,"".concat(e.up("xs")," and (orientation: landscape)"),{minHeight:48}),(0,i.default)(r,e.up("sm"),{minHeight:64}),r)},n)}},71615(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,r(n(59713));var i=r(n(67154)),a=r(n(6479)),o=r(n(94863)),s=r(n(93078));r(n(42473));var u=r(n(94811)),c=r(n(40226)),l=r(n(21091)),f=r(n(45184)),d=r(n(80743)),h=r(n(59591)),p=r(n(5324)),b=r(n(15406)),m=r(n(88676));function g(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.breakpoints,r=void 0===n?{}:n,g=t.mixins,v=void 0===g?{}:g,y=t.palette,w=void 0===y?{}:y,_=t.shadows,E=t.spacing,S=void 0===E?{}:E,k=t.typography,x=void 0===k?{}:k,T=(0,a.default)(t,["breakpoints","mixins","palette","shadows","spacing","typography"]),M=(0,l.default)(w),O=(0,u.default)(r),A=(0,i.default)({},p.default,S);return(0,i.default)({breakpoints:O,direction:"ltr",mixins:(0,c.default)(O,A,v),overrides:{},palette:M,props:{},shadows:_||d.default,typography:(0,f.default)(M,x)},(0,o.default)({shape:h.default,spacing:A,transitions:b.default,zIndex:m.default},T,{isMergeableObject:s.default}))}var v=g;t.default=v},21091(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=m,t.dark=t.light=void 0;var i=r(n(67154)),a=r(n(6479));r(n(42473));var o=r(n(94863)),s=r(n(78768)),u=r(n(124)),c=r(n(70167)),l=r(n(83165)),f=r(n(515)),d=n(59114),h={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.54)",disabled:"rgba(0, 0, 0, 0.38)",hint:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:f.default.white,default:c.default[50]},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.08)",hoverOpacity:.08,selected:"rgba(0, 0, 0, 0.14)",disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)"}};t.light=h;var p={text:{primary:f.default.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",hint:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:c.default[800],default:"#303030"},action:{active:f.default.white,hover:"rgba(255, 255, 255, 0.1)",hoverOpacity:.1,selected:"rgba(255, 255, 255, 0.2)",disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)"}};function b(e,t,n,r){e[t]||(e.hasOwnProperty(n)?e[t]=e[n]:"light"===t?e.light=(0,d.lighten)(e.main,r):"dark"===t&&(e.dark=(0,d.darken)(e.main,1.5*r)))}function m(e){var t=e.primary,n=void 0===t?{light:s.default[300],main:s.default[500],dark:s.default[700]}:t,r=e.secondary,m=void 0===r?{light:u.default.A200,main:u.default.A400,dark:u.default.A700}:r,g=e.error,v=void 0===g?{light:l.default[300],main:l.default[500],dark:l.default[700]}:g,y=e.type,w=void 0===y?"light":y,_=e.contrastThreshold,E=void 0===_?3:_,S=e.tonalOffset,k=void 0===S?.2:S,x=(0,a.default)(e,["primary","secondary","error","type","contrastThreshold","tonalOffset"]);function T(e){var t;return(0,d.getContrastRatio)(e,p.text.primary)>=E?p.text.primary:h.text.primary}function M(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:500,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:700;return!e.main&&e[t]&&(e.main=e[t]),b(e,"light",n,k),b(e,"dark",r,k),e.contrastText||(e.contrastText=T(e.main)),e}M(n),M(m,"A400","A200","A700"),M(v);var O={dark:p,light:h};return(0,o.default)((0,i.default)({common:f.default,type:w,primary:n,secondary:m,error:v,grey:c.default,contrastThreshold:E,getContrastText:T,augmentColor:M,tonalOffset:k},O[w]),x,{clone:!1})}t.dark=p},16059(e,t){"use strict";function n(e){return e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},45184(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=f;var i=r(n(67154)),a=r(n(6479)),o=r(n(94863));r(n(42473));var s=n(55252);function u(e){return Math.round(1e5*e)/1e5}var c={textTransform:"uppercase"},l='"Roboto", "Helvetica", "Arial", sans-serif';function f(e,t){var n="function"==typeof t?t(e):t,r=n.fontFamily,f=void 0===r?l:r,d=n.fontSize,h=void 0===d?14:d,p=n.fontWeightLight,b=void 0===p?300:p,m=n.fontWeightRegular,g=void 0===m?400:m,v=n.fontWeightMedium,y=void 0===v?500:v,w=n.htmlFontSize,_=void 0===w?16:w,E=n.useNextVariants,S=void 0===E?Boolean(s.ponyfillGlobal.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__):E,k=(n.suppressWarning,n.allVariants),x=(0,a.default)(n,["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","htmlFontSize","useNextVariants","suppressWarning","allVariants"]),T=h/14,M=function(e){return"".concat(e/_*T,"rem")},O=function(t,n,r,a,o){return(0,i.default)({color:e.text.primary,fontFamily:f,fontWeight:t,fontSize:M(n),lineHeight:r},f===l?{letterSpacing:"".concat(u(a/n),"em")}:{},o,k)},A={h1:O(b,96,1,-1.5),h2:O(b,60,1,-.5),h3:O(g,48,1.04,0),h4:O(g,34,1.17,.25),h5:O(g,24,1.33,0),h6:O(y,20,1.6,.15),subtitle1:O(g,16,1.75,.15),subtitle2:O(y,14,1.57,.1),body1Next:O(g,16,1.5,.15),body2Next:O(g,14,1.5,.15),buttonNext:O(y,14,1.75,.4,c),captionNext:O(g,12,1.66,.4),overline:O(g,12,2.66,1,c)},L={display4:(0,i.default)({fontSize:M(112),fontWeight:b,fontFamily:f,letterSpacing:"-.04em",lineHeight:"".concat(u(128/112),"em"),marginLeft:"-.04em",color:e.text.secondary},k),display3:(0,i.default)({fontSize:M(56),fontWeight:g,fontFamily:f,letterSpacing:"-.02em",lineHeight:"".concat(u(73/56),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display2:(0,i.default)({fontSize:M(45),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(51/45),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display1:(0,i.default)({fontSize:M(34),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(41/34),"em"),color:e.text.secondary},k),headline:(0,i.default)({fontSize:M(24),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(32.5/24),"em"),color:e.text.primary},k),title:(0,i.default)({fontSize:M(21),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24.5/21),"em"),color:e.text.primary},k),subheading:(0,i.default)({fontSize:M(16),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.5),"em"),color:e.text.primary},k),body2:(0,i.default)({fontSize:M(14),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24/14),"em"),color:e.text.primary},k),body1:(0,i.default)({fontSize:M(14),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(20.5/14),"em"),color:e.text.primary},k),caption:(0,i.default)({fontSize:M(12),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.375),"em"),color:e.text.secondary},k),button:(0,i.default)({fontSize:M(14),textTransform:"uppercase",fontWeight:y,fontFamily:f,color:e.text.primary},k)};return(0,o.default)((0,i.default)({pxToRem:M,round:u,fontFamily:f,fontSize:h,fontWeightLight:b,fontWeightRegular:g,fontWeightMedium:y},L,A,S?{body1:A.body1Next,body2:A.body2Next,button:A.buttonNext,caption:A.captionNext}:{},{useNextVariants:S}),x,{clone:!1})}},42458(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));r(n(50008)),r(n(42473));var a=r(n(94863));function o(e,t){return t}function s(e){var t="function"==typeof e;function n(n,r){var s=t?e(n):e;if(!r||!n.overrides||!n.overrides[r])return s;var u=n.overrides[r],c=(0,i.default)({},s);return Object.keys(u).forEach(function(e){c[e]=(0,a.default)(c[e],u[e],{arrayMerge:o})}),c}return{create:n,options:{},themingEnabled:t}}var u=s;t.default=u},58057(e,t){"use strict";function n(e){var t,n=e.theme,r=e.name,i=e.props;if(!n.props||!r||!n.props[r])return i;var a=n.props[r];for(t in a)void 0===i[t]&&(i[t]=a[t]);return i}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},32316(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createGenerateClassName",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"createMuiTheme",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"jssPreset",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"MuiThemeProvider",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(t,"createStyles",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"withStyles",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(t,"withTheme",{enumerable:!0,get:function(){return l.default}});var i=r(n(20237)),a=r(n(71615)),o=r(n(9399)),s=r(n(72366)),u=r(n(16059)),c=r(n(78252)),l=r(n(82313))},9399(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(29059)),a=r(n(28752)),o=r(n(35828)),s=r(n(50462)),u=r(n(65926)),c=r(n(89347));function l(){return{plugins:[(0,i.default)(),(0,a.default)(),(0,o.default)(),(0,s.default)(),"undefined"==typeof window?null:(0,u.default)(),(0,c.default)()]}}var f=l;t.default=f},35199(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.baseClasses,n=e.newClasses;if(e.Component,!n)return t;var r=(0,i.default)({},t);return Object.keys(n).forEach(function(e){n[e]&&(r[e]="".concat(t[e]," ").concat(n[e]))}),r}r(n(42473)),n(55252);var o=a;t.default=o},88693(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={set:function(e,t,n,r){var i=e.get(t);i||(i=new Map,e.set(t,i)),i.set(n,r)},get:function(e,t,n){var r=e.get(t);return r?r.get(n):void 0},delete:function(e,t,n){e.get(t).delete(n)}};t.default=n},31898(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={jss:"64a55d578f856d258dc345b094a2a2b3",sheetsRegistry:"d4bd0baacbc52bbd48bbb9eb24344ecd",sheetOptions:"6fc570d6bd61383819d0f9e7407c452d"};t.default=n},80743(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=.2,r=.14,i=.12;function a(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(n,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(r,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(i,")")].join(",")}var o=["none",a(0,1,3,0,0,1,1,0,0,2,1,-1),a(0,1,5,0,0,2,2,0,0,3,1,-2),a(0,1,8,0,0,3,4,0,0,3,3,-2),a(0,2,4,-1,0,4,5,0,0,1,10,0),a(0,3,5,-1,0,5,8,0,0,1,14,0),a(0,3,5,-1,0,6,10,0,0,1,18,0),a(0,4,5,-2,0,7,10,1,0,2,16,1),a(0,5,5,-3,0,8,10,1,0,3,14,2),a(0,5,6,-3,0,9,12,1,0,3,16,2),a(0,6,6,-3,0,10,14,1,0,4,18,3),a(0,6,7,-4,0,11,15,1,0,4,20,3),a(0,7,8,-4,0,12,17,2,0,5,22,4),a(0,7,8,-4,0,13,19,2,0,5,24,4),a(0,7,9,-4,0,14,21,2,0,5,26,4),a(0,8,9,-5,0,15,22,2,0,6,28,5),a(0,8,10,-5,0,16,24,2,0,6,30,5),a(0,8,11,-5,0,17,26,2,0,6,32,5),a(0,9,11,-5,0,18,28,2,0,7,34,6),a(0,9,12,-6,0,19,29,2,0,7,36,6),a(0,10,13,-6,0,20,31,3,0,8,38,7),a(0,10,13,-6,0,21,33,3,0,8,40,7),a(0,10,14,-6,0,22,35,3,0,8,42,7),a(0,11,14,-7,0,23,36,3,0,9,44,8),a(0,11,15,-7,0,24,38,3,0,9,46,8)];t.default=o},59591(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={borderRadius:4};t.default=n},5324(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={unit:8};t.default=n},51067(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.CHANNEL=void 0;var i=r(n(59713)),a="__THEMING__";t.CHANNEL=a;var o={contextTypes:(0,i.default)({},a,function(){}),initial:function(e){return e[a]?e[a].getState():null},subscribe:function(e,t){return e[a]?e[a].subscribe(t):null},unsubscribe:function(e,t){e[a]&&e[a].unsubscribe(t)}};t.default=o},15406(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isNumber=t.isString=t.formatMs=t.duration=t.easing=void 0;var i=r(n(6479));r(n(42473));var a={easeInOut:"cubic-bezier(0.4, 0, 0.2, 1)",easeOut:"cubic-bezier(0.0, 0, 0.2, 1)",easeIn:"cubic-bezier(0.4, 0, 1, 1)",sharp:"cubic-bezier(0.4, 0, 0.6, 1)"};t.easing=a;var o={shortest:150,shorter:200,short:250,standard:300,complex:375,enteringScreen:225,leavingScreen:195};t.duration=o;var s=function(e){return"".concat(Math.round(e),"ms")};t.formatMs=s;var u=function(e){return"string"==typeof e};t.isString=u;var c=function(e){return!isNaN(parseFloat(e))};t.isNumber=c;var l={easing:a,duration:o,create:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["all"],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.duration,r=void 0===n?o.standard:n,u=t.easing,c=void 0===u?a.easeInOut:u,l=t.delay,f=void 0===l?0:l;return(0,i.default)(t,["duration","easing","delay"]),(Array.isArray(e)?e:[e]).map(function(e){return"".concat(e," ").concat("string"==typeof r?r:s(r)," ").concat(c," ").concat("string"==typeof f?f:s(f))}).join(",")},getAutoHeightDuration:function(e){if(!e)return 0;var t=e/36;return Math.round((4+15*Math.pow(t,.25)+t/5)*10)}};t.default=l},78252(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.sheetsManager=void 0;var i=r(n(59713)),a=r(n(67154)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(6479)),d=r(n(67294)),h=r(n(45697));r(n(42473));var p=r(n(8679)),b=n(55252),m=n(55690),g=r(n(31898)),v=r(n(9399)),y=r(n(35199)),w=r(n(88693)),_=r(n(71615)),E=r(n(51067)),S=r(n(20237)),k=r(n(42458)),x=r(n(58057)),T=(0,m.create)((0,v.default)()),M=(0,S.default)(),O=-1e11,A=new Map;t.sheetsManager=A;var L={},C=(0,_.default)({typography:{suppressWarning:!0}}),I=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(n){var r,b=t.withTheme,m=void 0!==b&&b,v=t.flip,_=void 0===v?null:v,S=t.name,I=(0,f.default)(t,["withTheme","flip","name"]),D=(0,k.default)(e),N=D.themingEnabled||"string"==typeof S||m;O+=1,D.options.index=O;var P=function(e){function t(e,n){(0,o.default)(this,t),(r=(0,u.default)(this,(0,c.default)(t).call(this,e,n))).jss=n[g.default.jss]||T,r.sheetsManager=A,r.unsubscribeId=null;var r,i=n.muiThemeProviderOptions;return i&&(i.sheetsManager&&(r.sheetsManager=i.sheetsManager),r.sheetsCache=i.sheetsCache,r.disableStylesGeneration=i.disableStylesGeneration),r.stylesCreatorSaved=D,r.sheetOptions=(0,a.default)({generateClassName:M},n[g.default.sheetOptions]),r.theme=N?E.default.initial(n)||C:L,r.attach(r.theme),r.cacheClasses={value:null,lastProp:null,lastJSS:{}},r}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){var e=this;N&&(this.unsubscribeId=E.default.subscribe(this.context,function(t){var n=e.theme;e.theme=t,e.attach(e.theme),e.setState({},function(){e.detach(n)})}))}},{key:"componentDidUpdate",value:function(){this.stylesCreatorSaved}},{key:"componentWillUnmount",value:function(){this.detach(this.theme),null!==this.unsubscribeId&&E.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"getClasses",value:function(){if(this.disableStylesGeneration)return this.props.classes||{};var e=!1,t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,this.theme);return t.sheet.classes!==this.cacheClasses.lastJSS&&(this.cacheClasses.lastJSS=t.sheet.classes,e=!0),this.props.classes!==this.cacheClasses.lastProp&&(this.cacheClasses.lastProp=this.props.classes,e=!0),e&&(this.cacheClasses.value=(0,y.default)({baseClasses:this.cacheClasses.lastJSS,newClasses:this.props.classes,Component:n})),this.cacheClasses.value}},{key:"attach",value:function(e){if(!this.disableStylesGeneration){var t=this.stylesCreatorSaved,n=w.default.get(this.sheetsManager,t,e);if(n||(n={refs:0,sheet:null},w.default.set(this.sheetsManager,t,e,n)),0===n.refs){this.sheetsCache&&(r=w.default.get(this.sheetsCache,t,e)),!r&&((r=this.createSheet(e)).attach(),this.sheetsCache&&w.default.set(this.sheetsCache,t,e,r)),n.sheet=r;var r,i=this.context[g.default.sheetsRegistry];i&&i.add(r)}n.refs+=1}}},{key:"createSheet",value:function(e){var t=this.stylesCreatorSaved.create(e,S),r=S;return this.jss.createStyleSheet(t,(0,a.default)({meta:r,classNamePrefix:r,flip:"boolean"==typeof _?_:"rtl"===e.direction,link:!1},this.sheetOptions,this.stylesCreatorSaved.options,{name:S||n.displayName},I))}},{key:"detach",value:function(e){if(!this.disableStylesGeneration){var t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,e);if(t.refs-=1,0===t.refs){w.default.delete(this.sheetsManager,this.stylesCreatorSaved,e),this.jss.removeStyleSheet(t.sheet);var n=this.context[g.default.sheetsRegistry];n&&n.remove(t.sheet)}}}},{key:"render",value:function(){var e=this.props,t=(e.classes,e.innerRef),r=(0,f.default)(e,["classes","innerRef"]),i=(0,x.default)({theme:this.theme,name:S,props:r});return m&&!i.theme&&(i.theme=this.theme),d.default.createElement(n,(0,a.default)({},i,{classes:this.getClasses(),ref:t}))}}]),t}(d.default.Component);return P.contextTypes=(0,a.default)((r={muiThemeProviderOptions:h.default.object},(0,i.default)(r,g.default.jss,h.default.object),(0,i.default)(r,g.default.sheetOptions,h.default.object),(0,i.default)(r,g.default.sheetsRegistry,h.default.object),r),N?E.default.contextTypes:{}),(0,p.default)(P,n),P}};b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.withStyles||(b.ponyfillGlobal.__MUI_STYLES__.withStyles=I);var D=function(e,t){return b.ponyfillGlobal.__MUI_STYLES__.withStyles(e,(0,a.default)({defaultTheme:C},t))};t.default=D},82313(e,t,n){"use strict";var r,i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=i(n(67154)),o=i(n(6479)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294));i(n(45697));var h=i(n(8679)),p=n(55252),b=i(n(71615)),m=i(n(51067));function g(){return r||(r=(0,b.default)({typography:{suppressWarning:!0}}))}var v=function(){return function(e){var t=function(t){function n(e,t){var r;return(0,s.default)(this,n),(r=(0,c.default)(this,(0,l.default)(n).call(this))).state={theme:m.default.initial(t)||g()},r}return(0,f.default)(n,t),(0,u.default)(n,[{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.setState({theme:t})})}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"render",value:function(){var t=this.props,n=t.innerRef,r=(0,o.default)(t,["innerRef"]);return d.default.createElement(e,(0,a.default)({theme:this.state.theme,ref:n},r))}}]),n}(d.default.Component);return t.contextTypes=m.default.contextTypes,(0,h.default)(t,e),t}};p.ponyfillGlobal.__MUI_STYLES__||(p.ponyfillGlobal.__MUI_STYLES__={}),p.ponyfillGlobal.__MUI_STYLES__.withTheme||(p.ponyfillGlobal.__MUI_STYLES__.withTheme=v);var y=p.ponyfillGlobal.__MUI_STYLES__.withTheme;t.default=y},88676(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={mobileStepper:1e3,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500};t.default=n},41929(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getTransitionProps=r,t.reflow=void 0;var n=function(e){return e.scrollTop};function r(e,t){var n=e.timeout,r=e.style,i=void 0===r?{}:r;return{duration:i.transitionDuration||"number"==typeof n?n:n[t.mode],delay:i.transitionDelay}}t.reflow=n},346(e,t){"use strict";function n(e,t){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},98741(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.capitalize=a,t.contains=o,t.findIndex=s,t.find=u,t.createChainedFunction=c;var i=r(n(50008));function a(e){return e.charAt(0).toUpperCase()+e.slice(1)}function o(e,t){return Object.keys(t).every(function(n){return e.hasOwnProperty(n)&&e[n]===t[n]})}function s(e,t){for(var n=(0,i.default)(t),r=0;r-1?e[n]:void 0}function c(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:window,n=(0,i.default)(e);return n.defaultView||n.parentView||t}var o=a;t.default=o},44370(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.cloneElementWithClassName=o,t.cloneChildrenWithClassName=s,t.isMuiElement=u,t.setRef=c;var i=r(n(67294)),a=r(n(94184));function o(e,t){return i.default.cloneElement(e,{className:(0,a.default)(e.props.className,t)})}function s(e,t){return i.default.Children.map(e,function(e){return i.default.isValidElement(e)&&o(e,t)})}function u(e,t){return i.default.isValidElement(e)&&-1!==t.indexOf(e.type.muiName)}function c(e,t){"function"==typeof e?e(t):e&&(e.current=t)}},47348(e,t){"use strict";function n(e){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},21677(e,t){"use strict";function n(e,t,n,r,i){return null}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},78290(e,t,n){"use strict";var r=n(20862);Object.defineProperty(t,"__esModule",{value:!0});var i={};Object.defineProperty(t,"default",{enumerable:!0,get:function(){return a.default}});var a=r(n(88446));Object.keys(a).forEach(function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(i,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return a[e]}}))})},88446(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isWidthDown=t.isWidthUp=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(96421)),h=r(n(20296));n(55252);var p=r(n(8679)),b=r(n(82313)),m=n(94811),g=r(n(58057)),v=function(e,t){var n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(e)<=m.keys.indexOf(t):m.keys.indexOf(e)2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(t)<=m.keys.indexOf(e):m.keys.indexOf(t)0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=e.withTheme,r=void 0!==n&&n,v=e.noSSR,y=void 0!==v&&v,w=e.initialWidth,_=e.resizeInterval,E=void 0===_?166:_,S=function(e){function n(e){var t;return(0,o.default)(this,n),(t=(0,u.default)(this,(0,c.default)(n).call(this,e))).state={width:y?t.getWidth():void 0},"undefined"!=typeof window&&(t.handleResize=(0,h.default)(function(){var e=t.getWidth();e!==t.state.width&&t.setState({width:e})},E)),t}return(0,l.default)(n,e),(0,s.default)(n,[{key:"componentDidMount",value:function(){var e=this.getWidth();e!==this.state.width&&this.setState({width:e})}},{key:"componentWillUnmount",value:function(){this.handleResize.clear()}},{key:"getWidth",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.innerWidth,t=this.props.theme.breakpoints,n=null,r=1;null===n&&ri.Z,componentPropType:()=>r.Z,exactProp:()=>a.ZP,getDisplayName:()=>o.ZP,ponyfillGlobal:()=>s.Z});var r=n(78728),i=n(5477),a=n(43781),o=n(25189),s=n(34712);/** @license Material-UI v3.0.0-alpha.3 + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ },34712(e,t){"use strict";n={value:!0},t.Z=void 0;var n,r="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();t.Z=r},82152(e,t,n){"use strict";n.d(t,{D:()=>u});var r=Object.prototype,i=r.toString,a=r.hasOwnProperty,o=Function.prototype.toString,s=new Map;function u(e,t){try{return c(e,t)}finally{s.clear()}}function c(e,t){if(e===t)return!0;var n=i.call(e),r=i.call(t);if(n!==r)return!1;switch(n){case"[object Array]":if(e.length!==t.length)break;case"[object Object]":if(p(e,t))return!0;var s=l(e),u=l(t),f=s.length;if(f!==u.length)break;for(var b=0;b=0&&e.indexOf(t,n)===n}function p(e,t){var n=s.get(e);if(n){if(n.has(t))return!0}else s.set(e,n=new Set);return n.add(t),!1}},79742(e,t){"use strict";t.byteLength=c,t.toByteArray=f,t.fromByteArray=p;for(var n=[],r=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,s=a.length;o0)throw Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");-1===n&&(n=t);var r=n===t?0:4-n%4;return[n,r]}function c(e){var t=u(e),n=t[0],r=t[1];return(n+r)*3/4-r}function l(e,t,n){return(t+n)*3/4-n}function f(e){var t,n,a=u(e),o=a[0],s=a[1],c=new i(l(e,o,s)),f=0,d=s>0?o-4:o;for(n=0;n>16&255,c[f++]=t>>8&255,c[f++]=255&t;return 2===s&&(t=r[e.charCodeAt(n)]<<2|r[e.charCodeAt(n+1)]>>4,c[f++]=255&t),1===s&&(t=r[e.charCodeAt(n)]<<10|r[e.charCodeAt(n+1)]<<4|r[e.charCodeAt(n+2)]>>2,c[f++]=t>>8&255,c[f++]=255&t),c}function d(e){return n[e>>18&63]+n[e>>12&63]+n[e>>6&63]+n[63&e]}function h(e,t,n){for(var r,i=[],a=t;au?u:s+o));return 1===i?a.push(n[(t=e[r-1])>>2]+n[t<<4&63]+"=="):2===i&&a.push(n[(t=(e[r-2]<<8)+e[r-1])>>10]+n[t>>4&63]+n[t<<2&63]+"="),a.join("")}r["-".charCodeAt(0)]=62,r["_".charCodeAt(0)]=63},44431:function(e,t,n){var r;!function(i){"use strict";var a,o=/^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i,s=Math.ceil,u=Math.floor,c="[BigNumber Error] ",l=c+"Number primitive has more than 15 significant digits: ",f=1e14,d=14,h=9007199254740991,p=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],b=1e7,m=1e9;function g(e){var t,n,r,i,a,x,T,M,O,A,L=$.prototype={constructor:$,toString:null,valueOf:null},C=new $(1),I=20,D=4,N=-7,P=21,R=-1e7,j=1e7,F=!1,Y=1,B=0,U={prefix:"",groupSize:3,secondaryGroupSize:0,groupSeparator:",",decimalSeparator:".",fractionGroupSize:0,fractionGroupSeparator:"\xa0",suffix:""},H="0123456789abcdefghijklmnopqrstuvwxyz";function $(e,t){var n,r,i,a,s,c,f,p,b=this;if(!(b instanceof $))return new $(e,t);if(null==t){if(e&&!0===e._isBigNumber){b.s=e.s,!e.c||e.e>j?b.c=b.e=null:e.e=10;s/=10,a++);a>j?b.c=b.e=null:(b.e=a,b.c=[e]);return}p=String(e)}else{if(!o.test(p=String(e)))return A(b,p,c);b.s=45==p.charCodeAt(0)?(p=p.slice(1),-1):1}(a=p.indexOf("."))>-1&&(p=p.replace(".","")),(s=p.search(/e/i))>0?(a<0&&(a=s),a+=+p.slice(s+1),p=p.substring(0,s)):a<0&&(a=p.length)}else{if(_(t,2,H.length,"Base"),10==t)return b=new $(e),K(b,I+b.e+1,D);if(p=String(e),c="number"==typeof e){if(0*e!=0)return A(b,p,c,t);if(b.s=1/e<0?(p=p.slice(1),-1):1,$.DEBUG&&p.replace(/^0\.0*|\./,"").length>15)throw Error(l+e)}else b.s=45===p.charCodeAt(0)?(p=p.slice(1),-1):1;for(n=H.slice(0,t),a=s=0,f=p.length;sn.indexOf(r=p.charAt(s))){if("."==r){if(s>a){a=f;continue}}else if(!i&&(p==p.toUpperCase()&&(p=p.toLowerCase())||p==p.toLowerCase()&&(p=p.toUpperCase()))){i=!0,s=-1,a=0;continue}return A(b,String(e),c,t)}c=!1,(a=(p=O(p,t,10,b.s)).indexOf("."))>-1?p=p.replace(".",""):a=p.length}for(s=0;48===p.charCodeAt(s);s++);for(f=p.length;48===p.charCodeAt(--f););if(p=p.slice(s,++f)){if(f-=s,c&&$.DEBUG&&f>15&&(e>h||e!==u(e)))throw Error(l+b.s*e);if((a=a-s-1)>j)b.c=b.e=null;else if(a=P)?S(u,o):k(u,o,"0");else if(a=(e=K(new $(e),t,n)).e,s=(u=y(e.c)).length,1==r||2==r&&(t<=a||a<=N)){for(;ss){if(--t>0)for(u+=".";t--;u+="0");}else if((t+=a-s)>0)for(a+1==s&&(u+=".");t--;u+="0");return e.s<0&&i?"-"+u:u}function G(e,t){for(var n,r=1,i=new $(e[0]);r=10;i/=10,r++);return(n=r+n*d-1)>j?e.c=e.e=null:n=10;c/=10,i++);if((a=t-i)<0)a+=d,o=t,b=(l=m[h=0])/g[i-o-1]%10|0;else if((h=s((a+1)/d))>=m.length){if(r){for(;m.length<=h;m.push(0));l=b=0,i=1,a%=d,o=a-d+1}else break out}else{for(i=1,l=c=m[h];c>=10;c/=10,i++);a%=d,b=(o=a-d+i)<0?0:l/g[i-o-1]%10|0}if(r=r||t<0||null!=m[h+1]||(o<0?l:l%g[i-o-1]),r=n<4?(b||r)&&(0==n||n==(e.s<0?3:2)):b>5||5==b&&(4==n||r||6==n&&(a>0?o>0?l/g[i-o]:0:m[h-1])%10&1||n==(e.s<0?8:7)),t<1||!m[0])return m.length=0,r?(t-=e.e+1,m[0]=g[(d-t%d)%d],e.e=-t||0):m[0]=e.e=0,e;if(0==a?(m.length=h,c=1,h--):(m.length=h+1,c=g[d-a],m[h]=o>0?u(l/g[i-o]%g[o])*c:0),r)for(;;){if(0==h){for(a=1,o=m[0];o>=10;o/=10,a++);for(o=m[0]+=c,c=1;o>=10;o/=10,c++);a!=c&&(e.e++,m[0]==f&&(m[0]=1));break}if(m[h]+=c,m[h]!=f)break;m[h--]=0,c=1}for(a=m.length;0===m[--a];m.pop());}e.e>j?e.c=e.e=null:e.e=P?S(t,n):k(t,n,"0"),e.s<0?"-"+t:t)}return $.clone=g,$.ROUND_UP=0,$.ROUND_DOWN=1,$.ROUND_CEIL=2,$.ROUND_FLOOR=3,$.ROUND_HALF_UP=4,$.ROUND_HALF_DOWN=5,$.ROUND_HALF_EVEN=6,$.ROUND_HALF_CEIL=7,$.ROUND_HALF_FLOOR=8,$.EUCLID=9,$.config=$.set=function(e){var t,n;if(null!=e){if("object"==typeof e){if(e.hasOwnProperty(t="DECIMAL_PLACES")&&(_(n=e[t],0,m,t),I=n),e.hasOwnProperty(t="ROUNDING_MODE")&&(_(n=e[t],0,8,t),D=n),e.hasOwnProperty(t="EXPONENTIAL_AT")&&((n=e[t])&&n.pop?(_(n[0],-m,0,t),_(n[1],0,m,t),N=n[0],P=n[1]):(_(n,-m,m,t),N=-(P=n<0?-n:n))),e.hasOwnProperty(t="RANGE")){if((n=e[t])&&n.pop)_(n[0],-m,-1,t),_(n[1],1,m,t),R=n[0],j=n[1];else if(_(n,-m,m,t),n)R=-(j=n<0?-n:n);else throw Error(c+t+" cannot be zero: "+n)}if(e.hasOwnProperty(t="CRYPTO")){if(!!(n=e[t])===n){if(n){if("undefined"!=typeof crypto&&crypto&&(crypto.getRandomValues||crypto.randomBytes))F=n;else throw F=!n,Error(c+"crypto unavailable")}else F=n}else throw Error(c+t+" not true or false: "+n)}if(e.hasOwnProperty(t="MODULO_MODE")&&(_(n=e[t],0,9,t),Y=n),e.hasOwnProperty(t="POW_PRECISION")&&(_(n=e[t],0,m,t),B=n),e.hasOwnProperty(t="FORMAT")){if("object"==typeof(n=e[t]))U=n;else throw Error(c+t+" not an object: "+n)}if(e.hasOwnProperty(t="ALPHABET")){if("string"!=typeof(n=e[t])||/^.?$|[+\-.\s]|(.).*\1/.test(n))throw Error(c+t+" invalid: "+n);H=n}}else throw Error(c+"Object expected: "+e)}return{DECIMAL_PLACES:I,ROUNDING_MODE:D,EXPONENTIAL_AT:[N,P],RANGE:[R,j],CRYPTO:F,MODULO_MODE:Y,POW_PRECISION:B,FORMAT:U,ALPHABET:H}},$.isBigNumber=function(e){if(!e||!0!==e._isBigNumber)return!1;if(!$.DEBUG)return!0;var t,n,r=e.c,i=e.e,a=e.s;out:if("[object Array]"==({}).toString.call(r)){if((1===a||-1===a)&&i>=-m&&i<=m&&i===u(i)){if(0===r[0]){if(0===i&&1===r.length)return!0;break out}if((t=(i+1)%d)<1&&(t+=d),String(r[0]).length==t){for(t=0;t=f||n!==u(n))break out;if(0!==n)return!0}}}else if(null===r&&null===i&&(null===a||1===a||-1===a))return!0;throw Error(c+"Invalid BigNumber: "+e)},$.maximum=$.max=function(){return G(arguments,L.lt)},$.minimum=$.min=function(){return G(arguments,L.gt)},$.random=(n=Math.random()*(t=9007199254740992)&2097151?function(){return u(Math.random()*t)}:function(){return(1073741824*Math.random()|0)*8388608+(8388608*Math.random()|0)},function(e){var t,r,i,a,o,l=0,f=[],h=new $(C);if(null==e?e=I:_(e,0,m),a=s(e/d),F){if(crypto.getRandomValues){for(t=crypto.getRandomValues(new Uint32Array(a*=2));l>>11))>=9e15?(r=crypto.getRandomValues(new Uint32Array(2)),t[l]=r[0],t[l+1]=r[1]):(f.push(o%1e14),l+=2);l=a/2}else if(crypto.randomBytes){for(t=crypto.randomBytes(a*=7);l=9e15?crypto.randomBytes(7).copy(t,l):(f.push(o%1e14),l+=7);l=a/7}else throw F=!1,Error(c+"crypto unavailable")}if(!F)for(;l=10;o/=10,l++);ln-1&&(null==o[i+1]&&(o[i+1]=0),o[i+1]+=o[i]/n|0,o[i]%=n)}return o.reverse()}return function(n,r,i,a,o){var s,u,c,l,f,d,h,p,b=n.indexOf("."),m=I,g=D;for(b>=0&&(l=B,B=0,n=n.replace(".",""),d=(p=new $(r)).pow(n.length-b),B=l,p.c=t(k(y(d.c),d.e,"0"),10,i,e),p.e=p.c.length),c=l=(h=t(n,r,i,o?(s=H,e):(s=e,H))).length;0==h[--l];h.pop());if(!h[0])return s.charAt(0);if(b<0?--c:(d.c=h,d.e=c,d.s=a,h=(d=M(d,p,m,g,i)).c,f=d.r,c=d.e),b=h[u=c+m+1],l=i/2,f=f||u<0||null!=h[u+1],f=g<4?(null!=b||f)&&(0==g||g==(d.s<0?3:2)):b>l||b==l&&(4==g||f||6==g&&1&h[u-1]||g==(d.s<0?8:7)),u<1||!h[0])n=f?k(s.charAt(1),-m,s.charAt(0)):s.charAt(0);else{if(h.length=u,f)for(--i;++h[--u]>i;)h[u]=0,u||(++c,h=[1].concat(h));for(l=h.length;!h[--l];);for(b=0,n="";b<=l;n+=s.charAt(h[b++]));n=k(n,c,s.charAt(0))}return n}}(),M=function(){function e(e,t,n){var r,i,a,o,s=0,u=e.length,c=t%b,l=t/b|0;for(e=e.slice();u--;)r=l*(a=e[u]%b)+(o=e[u]/b|0)*c,s=((i=c*a+r%b*b+s)/n|0)+(r/b|0)+l*o,e[u]=i%n;return s&&(e=[s].concat(e)),e}function t(e,t,n,r){var i,a;if(n!=r)a=n>r?1:-1;else for(i=a=0;it[i]?1:-1;break}return a}function n(e,t,n,r){for(var i=0;n--;)e[n]-=i,i=e[n]1;e.splice(0,1));}return function(r,i,a,o,s){var c,l,h,p,b,m,g,y,w,_,E,S,k,x,T,M,O,A=r.s==i.s?1:-1,L=r.c,C=i.c;if(!L||!L[0]||!C||!C[0])return new $(r.s&&i.s&&(L?!C||L[0]!=C[0]:C)?L&&0==L[0]||!C?0*A:A/0:NaN);for(w=(y=new $(A)).c=[],A=a+(l=r.e-i.e)+1,s||(s=f,l=v(r.e/d)-v(i.e/d),A=A/d|0),h=0;C[h]==(L[h]||0);h++);if(C[h]>(L[h]||0)&&l--,A<0)w.push(1),p=!0;else{for(x=L.length,M=C.length,h=0,A+=2,(b=u(s/(C[0]+1)))>1&&(C=e(C,b,s),L=e(L,b,s),M=C.length,x=L.length),k=M,E=(_=L.slice(0,M)).length;E=s/2&&T++;do{if(b=0,(c=t(C,_,M,E))<0){if(S=_[0],M!=E&&(S=S*s+(_[1]||0)),(b=u(S/T))>1)for(b>=s&&(b=s-1),g=(m=e(C,b,s)).length,E=_.length;1==t(m,_,g,E);)b--,n(m,Mt(C,_,M,E);)b++,n(_,M=10;A/=10,h++);K(y,a+(y.e=h+l*d-1)+1,o,p)}else y.e=l,y.r=+p;return y}}(),A=(r=/^(-?)0([xbo])(?=\w[\w.]*$)/i,i=/^([^.]+)\.$/,a=/^\.([^.]+)$/,x=/^-?(Infinity|NaN)$/,T=/^\s*\+(?=[\w.])|^\s+|\s+$/g,function(e,t,n,o){var s,u=n?t:t.replace(T,"");if(x.test(u))e.s=isNaN(u)?null:u<0?-1:1;else{if(!n&&(u=u.replace(r,function(e,t,n){return s="x"==(n=n.toLowerCase())?16:"b"==n?2:8,o&&o!=s?e:t}),o&&(s=o,u=u.replace(i,"$1").replace(a,"0.$1")),t!=u))return new $(u,s);if($.DEBUG)throw Error(c+"Not a"+(o?" base "+o:"")+" number: "+t);e.s=null}e.c=e.e=null}),L.absoluteValue=L.abs=function(){var e=new $(this);return e.s<0&&(e.s=1),e},L.comparedTo=function(e,t){return w(this,new $(e,t))},L.decimalPlaces=L.dp=function(e,t){var n,r,i,a=this;if(null!=e)return _(e,0,m),null==t?t=D:_(t,0,8),K(new $(a),e+a.e+1,t);if(!(n=a.c))return null;if(r=((i=n.length-1)-v(this.e/d))*d,i=n[i])for(;i%10==0;i/=10,r--);return r<0&&(r=0),r},L.dividedBy=L.div=function(e,t){return M(this,new $(e,t),I,D)},L.dividedToIntegerBy=L.idiv=function(e,t){return M(this,new $(e,t),0,1)},L.exponentiatedBy=L.pow=function(e,t){var n,r,i,a,o,l,f,h,p,b=this;if((e=new $(e)).c&&!e.isInteger())throw Error(c+"Exponent not an integer: "+V(e));if(null!=t&&(t=new $(t)),l=e.e>14,!b.c||!b.c[0]||1==b.c[0]&&!b.e&&1==b.c.length||!e.c||!e.c[0])return p=new $(Math.pow(+V(b),l?2-E(e):+V(e))),t?p.mod(t):p;if(f=e.s<0,t){if(t.c?!t.c[0]:!t.s)return new $(NaN);(r=!f&&b.isInteger()&&t.isInteger())&&(b=b.mod(t))}else{if(e.e>9&&(b.e>0||b.e<-1||(0==b.e?b.c[0]>1||l&&b.c[1]>=24e7:b.c[0]<8e13||l&&b.c[0]<=9999975e7)))return a=(b.s<0&&E(e),-0),b.e>-1&&(a=1/a),new $(f?1/a:a);B&&(a=s(B/d+2))}for(l?(n=new $(.5),f&&(e.s=1),h=E(e)):h=(i=Math.abs(+V(e)))%2,p=new $(C);;){if(h){if(!(p=p.times(b)).c)break;a?p.c.length>a&&(p.c.length=a):r&&(p=p.mod(t))}if(i){if(0===(i=u(i/2)))break;h=i%2}else if(K(e=e.times(n),e.e+1,1),e.e>14)h=E(e);else{if(0==(i=+V(e)))break;h=i%2}b=b.times(b),a?b.c&&b.c.length>a&&(b.c.length=a):r&&(b=b.mod(t))}return r?p:(f&&(p=C.div(p)),t?p.mod(t):a?K(p,B,D,o):p)},L.integerValue=function(e){var t=new $(this);return null==e?e=D:_(e,0,8),K(t,t.e+1,e)},L.isEqualTo=L.eq=function(e,t){return 0===w(this,new $(e,t))},L.isFinite=function(){return!!this.c},L.isGreaterThan=L.gt=function(e,t){return w(this,new $(e,t))>0},L.isGreaterThanOrEqualTo=L.gte=function(e,t){return 1===(t=w(this,new $(e,t)))||0===t},L.isInteger=function(){return!!this.c&&v(this.e/d)>this.c.length-2},L.isLessThan=L.lt=function(e,t){return 0>w(this,new $(e,t))},L.isLessThanOrEqualTo=L.lte=function(e,t){return -1===(t=w(this,new $(e,t)))||0===t},L.isNaN=function(){return!this.s},L.isNegative=function(){return this.s<0},L.isPositive=function(){return this.s>0},L.isZero=function(){return!!this.c&&0==this.c[0]},L.minus=function(e,t){var n,r,i,a,o=this,s=o.s;if(t=(e=new $(e,t)).s,!s||!t)return new $(NaN);if(s!=t)return e.s=-t,o.plus(e);var u=o.e/d,c=e.e/d,l=o.c,h=e.c;if(!u||!c){if(!l||!h)return l?(e.s=-t,e):new $(h?o:NaN);if(!l[0]||!h[0])return h[0]?(e.s=-t,e):new $(l[0]?o:-0)}if(u=v(u),c=v(c),l=l.slice(),s=u-c){for((a=s<0)?(s=-s,i=l):(c=u,i=h),i.reverse(),t=s;t--;i.push(0));i.reverse()}else for(r=(a=(s=l.length)<(t=h.length))?s:t,s=t=0;t0)for(;t--;l[n++]=0);for(t=f-1;r>s;){if(l[--r]=0;){for(n=0,p=S[i]%w,m=S[i]/w|0,a=i+(o=u);a>i;)s=m*(c=E[--o]%w)+(l=E[o]/w|0)*p,n=((c=p*c+s%w*w+g[a]+n)/y|0)+(s/w|0)+m*l,g[a--]=c%y;g[a]=n}return n?++r:g.splice(0,1),W(e,g,r)},L.negated=function(){var e=new $(this);return e.s=-e.s||null,e},L.plus=function(e,t){var n,r=this,i=r.s;if(t=(e=new $(e,t)).s,!i||!t)return new $(NaN);if(i!=t)return e.s=-t,r.minus(e);var a=r.e/d,o=e.e/d,s=r.c,u=e.c;if(!a||!o){if(!s||!u)return new $(i/0);if(!s[0]||!u[0])return u[0]?e:new $(s[0]?r:0*i)}if(a=v(a),o=v(o),s=s.slice(),i=a-o){for(i>0?(o=a,n=u):(i=-i,n=s),n.reverse();i--;n.push(0));n.reverse()}for((i=s.length)-(t=u.length)<0&&(n=u,u=s,s=n,t=i),i=0;t;)i=(s[--t]=s[t]+u[t]+i)/f|0,s[t]=f===s[t]?0:s[t]%f;return i&&(s=[i].concat(s),++o),W(e,s,o)},L.precision=L.sd=function(e,t){var n,r,i,a=this;if(null!=e&&!!e!==e)return _(e,1,m),null==t?t=D:_(t,0,8),K(new $(a),e,t);if(!(n=a.c))return null;if(r=(i=n.length-1)*d+1,i=n[i]){for(;i%10==0;i/=10,r--);for(i=n[0];i>=10;i/=10,r++);}return e&&a.e+1>r&&(r=a.e+1),r},L.shiftedBy=function(e){return _(e,-h,h),this.times("1e"+e)},L.squareRoot=L.sqrt=function(){var e,t,n,r,i,a=this,o=a.c,s=a.s,u=a.e,c=I+4,l=new $("0.5");if(1!==s||!o||!o[0])return new $(!s||s<0&&(!o||o[0])?NaN:o?a:1/0);if(0==(s=Math.sqrt(+V(a)))||s==1/0?(((t=y(o)).length+u)%2==0&&(t+="0"),s=Math.sqrt(+t),u=v((u+1)/2)-(u<0||u%2),t=s==1/0?"5e"+u:(t=s.toExponential()).slice(0,t.indexOf("e")+1)+u,n=new $(t)):n=new $(s+""),n.c[0]){for((s=(u=n.e)+c)<3&&(s=0);;)if(i=n,n=l.times(i.plus(M(a,i,c,1))),y(i.c).slice(0,s)===(t=y(n.c)).slice(0,s)){if(n.e0&&b>0){for(a=b%s||s,f=p.substr(0,a);a0&&(f+=l+p.slice(a)),h&&(f="-"+f)}r=d?f+(n.decimalSeparator||"")+((u=+n.fractionGroupSize)?d.replace(RegExp("\\d{"+u+"}\\B","g"),"$&"+(n.fractionGroupSeparator||"")):d):f}return(n.prefix||"")+r+(n.suffix||"")},L.toFraction=function(e){var t,n,r,i,a,o,s,u,l,f,h,b,m=this,g=m.c;if(null!=e&&(!(s=new $(e)).isInteger()&&(s.c||1!==s.s)||s.lt(C)))throw Error(c+"Argument "+(s.isInteger()?"out of range: ":"not an integer: ")+V(s));if(!g)return new $(m);for(t=new $(C),l=n=new $(C),r=u=new $(C),b=y(g),a=t.e=b.length-m.e-1,t.c[0]=p[(o=a%d)<0?d+o:o],e=!e||s.comparedTo(t)>0?a>0?t:l:s,o=j,j=1/0,s=new $(b),u.c[0]=0;f=M(s,t,0,1),1!=(i=n.plus(f.times(r))).comparedTo(e);)n=r,r=i,l=u.plus(f.times(i=l)),u=i,t=s.minus(f.times(i=t)),s=i;return i=M(e.minus(n),r,0,1),u=u.plus(i.times(l)),n=n.plus(i.times(r)),u.s=l.s=m.s,a*=2,h=1>M(l,r,a,D).minus(m).abs().comparedTo(M(u,n,a,D).minus(m).abs())?[l,r]:[u,n],j=o,h},L.toNumber=function(){return+V(this)},L.toPrecision=function(e,t){return null!=e&&_(e,1,m),z(this,e,t,2)},L.toString=function(e){var t,n=this,r=n.s,i=n.e;return null===i?r?(t="Infinity",r<0&&(t="-"+t)):t="NaN":(null==e?t=i<=N||i>=P?S(y(n.c),i):k(y(n.c),i,"0"):10===e?(n=K(new $(n),I+i+1,D),t=k(y(n.c),n.e,"0")):(_(e,2,H.length,"Base"),t=O(k(y(n.c),i,"0"),10,e,r,!0)),r<0&&n.c[0]&&(t="-"+t)),t},L.valueOf=L.toJSON=function(){return V(this)},L._isBigNumber=!0,null!=e&&$.set(e),$}function v(e){var t=0|e;return e>0||e===t?t:t-1}function y(e){for(var t,n,r=1,i=e.length,a=e[0]+"";rc^n?1:-1;for(o=0,s=(u=i.length)<(c=a.length)?u:c;oa[o]^n?1:-1;return u==c?0:u>c^n?1:-1}function _(e,t,n,r){if(en||e!==u(e))throw Error(c+(r||"Argument")+("number"==typeof e?en?" out of range: ":" not an integer: ":" not a primitive number: ")+String(e))}function E(e){var t=e.c.length-1;return v(e.e/d)==t&&e.c[t]%2!=0}function S(e,t){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(t<0?"e":"e+")+t}function k(e,t,n){var r,i;if(t<0){for(i=n+".";++t;i+=n);e=i+e}else if(r=e.length,++t>r){for(i=n,t-=r;--t;i+=n);e+=i}else ti});let i=r},48764(e,t,n){"use strict";/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ var r=n(79742),i=n(80645),a="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;t.Buffer=c,t.SlowBuffer=w,t.INSPECT_MAX_BYTES=50;var o=2147483647;function s(){try{var e=new Uint8Array(1),t={foo:function(){return 42}};return Object.setPrototypeOf(t,Uint8Array.prototype),Object.setPrototypeOf(e,t),42===e.foo()}catch(n){return!1}}function u(e){if(e>o)throw RangeError('The value "'+e+'" is invalid for option "size"');var t=new Uint8Array(e);return Object.setPrototypeOf(t,c.prototype),t}function c(e,t,n){if("number"==typeof e){if("string"==typeof t)throw TypeError('The "string" argument must be of type string. Received type number');return h(e)}return l(e,t,n)}function l(e,t,n){if("string"==typeof e)return p(e,t);if(ArrayBuffer.isView(e))return m(e);if(null==e)throw TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(X(e,ArrayBuffer)||e&&X(e.buffer,ArrayBuffer)||"undefined"!=typeof SharedArrayBuffer&&(X(e,SharedArrayBuffer)||e&&X(e.buffer,SharedArrayBuffer)))return g(e,t,n);if("number"==typeof e)throw TypeError('The "value" argument must not be of type number. Received type number');var r=e.valueOf&&e.valueOf();if(null!=r&&r!==e)return c.from(r,t,n);var i=v(e);if(i)return i;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof e[Symbol.toPrimitive])return c.from(e[Symbol.toPrimitive]("string"),t,n);throw TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}function f(e){if("number"!=typeof e)throw TypeError('"size" argument must be of type number');if(e<0)throw RangeError('The value "'+e+'" is invalid for option "size"')}function d(e,t,n){return(f(e),e<=0)?u(e):void 0!==t?"string"==typeof n?u(e).fill(t,n):u(e).fill(t):u(e)}function h(e){return f(e),u(e<0?0:0|y(e))}function p(e,t){if(("string"!=typeof t||""===t)&&(t="utf8"),!c.isEncoding(t))throw TypeError("Unknown encoding: "+t);var n=0|_(e,t),r=u(n),i=r.write(e,t);return i!==n&&(r=r.slice(0,i)),r}function b(e){for(var t=e.length<0?0:0|y(e.length),n=u(t),r=0;r=o)throw RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+o.toString(16)+" bytes");return 0|e}function w(e){return+e!=e&&(e=0),c.alloc(+e)}function _(e,t){if(c.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||X(e,ArrayBuffer))return e.byteLength;if("string"!=typeof e)throw TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);var n=e.length,r=arguments.length>2&&!0===arguments[2];if(!r&&0===n)return 0;for(var i=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":return W(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return q(e).length;default:if(i)return r?-1:W(e).length;t=(""+t).toLowerCase(),i=!0}}function E(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length||((void 0===n||n>this.length)&&(n=this.length),n<=0||(n>>>=0)<=(t>>>=0)))return"";for(e||(e="utf8");;)switch(e){case"hex":return j(this,t,n);case"utf8":case"utf-8":return I(this,t,n);case"ascii":return P(this,t,n);case"latin1":case"binary":return R(this,t,n);case"base64":return C(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return F(this,t,n);default:if(r)throw TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function S(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function k(e,t,n,r,i){if(0===e.length)return -1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),J(n=+n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return -1;n=e.length-1}else if(n<0){if(!i)return -1;n=0}if("string"==typeof t&&(t=c.from(t,r)),c.isBuffer(t))return 0===t.length?-1:x(e,t,n,r,i);if("number"==typeof t)return(t&=255,"function"==typeof Uint8Array.prototype.indexOf)?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):x(e,[t],n,r,i);throw TypeError("val must be string, number or Buffer")}function x(e,t,n,r,i){var a,o=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return -1;o=2,s/=2,u/=2,n/=2}function c(e,t){return 1===o?e[t]:e.readUInt16BE(t*o)}if(i){var l=-1;for(a=n;as&&(n=s-u),a=n;a>=0;a--){for(var f=!0,d=0;di&&(r=i):r=i;var a=t.length;r>a/2&&(r=a/2);for(var o=0;o239?4:c>223?3:c>191?2:1;if(i+f<=n)switch(f){case 1:c<128&&(l=c);break;case 2:(192&(a=e[i+1]))==128&&(u=(31&c)<<6|63&a)>127&&(l=u);break;case 3:a=e[i+1],o=e[i+2],(192&a)==128&&(192&o)==128&&(u=(15&c)<<12|(63&a)<<6|63&o)>2047&&(u<55296||u>57343)&&(l=u);break;case 4:a=e[i+1],o=e[i+2],s=e[i+3],(192&a)==128&&(192&o)==128&&(192&s)==128&&(u=(15&c)<<18|(63&a)<<12|(63&o)<<6|63&s)>65535&&u<1114112&&(l=u)}null===l?(l=65533,f=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),i+=f}return N(r)}t.kMaxLength=o,c.TYPED_ARRAY_SUPPORT=s(),c.TYPED_ARRAY_SUPPORT||"undefined"==typeof console||"function"!=typeof console.error||console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."),Object.defineProperty(c.prototype,"parent",{enumerable:!0,get:function(){if(c.isBuffer(this))return this.buffer}}),Object.defineProperty(c.prototype,"offset",{enumerable:!0,get:function(){if(c.isBuffer(this))return this.byteOffset}}),c.poolSize=8192,c.from=function(e,t,n){return l(e,t,n)},Object.setPrototypeOf(c.prototype,Uint8Array.prototype),Object.setPrototypeOf(c,Uint8Array),c.alloc=function(e,t,n){return d(e,t,n)},c.allocUnsafe=function(e){return h(e)},c.allocUnsafeSlow=function(e){return h(e)},c.isBuffer=function(e){return null!=e&&!0===e._isBuffer&&e!==c.prototype},c.compare=function(e,t){if(X(e,Uint8Array)&&(e=c.from(e,e.offset,e.byteLength)),X(t,Uint8Array)&&(t=c.from(t,t.offset,t.byteLength)),!c.isBuffer(e)||!c.isBuffer(t))throw TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);ir.length?c.from(a).copy(r,i):Uint8Array.prototype.set.call(r,a,i);else if(c.isBuffer(a))a.copy(r,i);else throw TypeError('"list" argument must be an Array of Buffers');i+=a.length}return r},c.byteLength=_,c.prototype._isBuffer=!0,c.prototype.swap16=function(){var e=this.length;if(e%2!=0)throw RangeError("Buffer size must be a multiple of 16-bits");for(var t=0;tn&&(e+=" ... "),""},a&&(c.prototype[a]=c.prototype.inspect),c.prototype.compare=function(e,t,n,r,i){if(X(e,Uint8Array)&&(e=c.from(e,e.offset,e.byteLength)),!c.isBuffer(e))throw TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw RangeError("out of range index");if(r>=i&&t>=n)return 0;if(r>=i)return -1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,o=n-t,s=Math.min(a,o),u=this.slice(r,i),l=e.slice(t,n),f=0;f>>=0,isFinite(n)?(n>>>=0,void 0===r&&(r="utf8")):(r=n,n=void 0);else throw Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");var i=this.length-t;if((void 0===n||n>i)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var a=!1;;)switch(r){case"hex":return T(this,e,t,n);case"utf8":case"utf-8":return M(this,e,t,n);case"ascii":case"latin1":case"binary":return O(this,e,t,n);case"base64":return A(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return L(this,e,t,n);default:if(a)throw TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),a=!0}},c.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var D=4096;function N(e){var t=e.length;if(t<=D)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",a=t;an)throw RangeError("Trying to access beyond buffer length")}function B(e,t,n,r,i,a){if(!c.isBuffer(e))throw TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw RangeError("Index out of range")}function U(e,t,n,r,i,a){if(n+r>e.length||n<0)throw RangeError("Index out of range")}function H(e,t,n,r,a){return t=+t,n>>>=0,a||U(e,t,n,4,34028234663852886e22,-34028234663852886e22),i.write(e,t,n,r,23,4),n+4}function $(e,t,n,r,a){return t=+t,n>>>=0,a||U(e,t,n,8,17976931348623157e292,-17976931348623157e292),i.write(e,t,n,r,52,8),n+8}c.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n)<0&&(e=0):e>n&&(e=n),t<0?(t+=n)<0&&(t=0):t>n&&(t=n),t>>=0,t>>>=0,n||Y(e,t,this.length);for(var r=this[e],i=1,a=0;++a>>=0,t>>>=0,n||Y(e,t,this.length);for(var r=this[e+--t],i=1;t>0&&(i*=256);)r+=this[e+--t]*i;return r},c.prototype.readUint8=c.prototype.readUInt8=function(e,t){return e>>>=0,t||Y(e,1,this.length),this[e]},c.prototype.readUint16LE=c.prototype.readUInt16LE=function(e,t){return e>>>=0,t||Y(e,2,this.length),this[e]|this[e+1]<<8},c.prototype.readUint16BE=c.prototype.readUInt16BE=function(e,t){return e>>>=0,t||Y(e,2,this.length),this[e]<<8|this[e+1]},c.prototype.readUint32LE=c.prototype.readUInt32LE=function(e,t){return e>>>=0,t||Y(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},c.prototype.readUint32BE=c.prototype.readUInt32BE=function(e,t){return e>>>=0,t||Y(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},c.prototype.readIntLE=function(e,t,n){e>>>=0,t>>>=0,n||Y(e,t,this.length);for(var r=this[e],i=1,a=0;++a=(i*=128)&&(r-=Math.pow(2,8*t)),r},c.prototype.readIntBE=function(e,t,n){e>>>=0,t>>>=0,n||Y(e,t,this.length);for(var r=t,i=1,a=this[e+--r];r>0&&(i*=256);)a+=this[e+--r]*i;return a>=(i*=128)&&(a-=Math.pow(2,8*t)),a},c.prototype.readInt8=function(e,t){return(e>>>=0,t||Y(e,1,this.length),128&this[e])?-((255-this[e]+1)*1):this[e]},c.prototype.readInt16LE=function(e,t){e>>>=0,t||Y(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt16BE=function(e,t){e>>>=0,t||Y(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt32LE=function(e,t){return e>>>=0,t||Y(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},c.prototype.readInt32BE=function(e,t){return e>>>=0,t||Y(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},c.prototype.readFloatLE=function(e,t){return e>>>=0,t||Y(e,4,this.length),i.read(this,e,!0,23,4)},c.prototype.readFloatBE=function(e,t){return e>>>=0,t||Y(e,4,this.length),i.read(this,e,!1,23,4)},c.prototype.readDoubleLE=function(e,t){return e>>>=0,t||Y(e,8,this.length),i.read(this,e,!0,52,8)},c.prototype.readDoubleBE=function(e,t){return e>>>=0,t||Y(e,8,this.length),i.read(this,e,!1,52,8)},c.prototype.writeUintLE=c.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t>>>=0,n>>>=0,!r){var i=Math.pow(2,8*n)-1;B(this,e,t,n,i,0)}var a=1,o=0;for(this[t]=255&e;++o>>=0,n>>>=0,!r){var i=Math.pow(2,8*n)-1;B(this,e,t,n,i,0)}var a=n-1,o=1;for(this[t+a]=255&e;--a>=0&&(o*=256);)this[t+a]=e/o&255;return t+n},c.prototype.writeUint8=c.prototype.writeUInt8=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,1,255,0),this[t]=255&e,t+1},c.prototype.writeUint16LE=c.prototype.writeUInt16LE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},c.prototype.writeUint16BE=c.prototype.writeUInt16BE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},c.prototype.writeUint32LE=c.prototype.writeUInt32LE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},c.prototype.writeUint32BE=c.prototype.writeUInt32BE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},c.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=Math.pow(2,8*n-1);B(this,e,t,n,i-1,-i)}var a=0,o=1,s=0;for(this[t]=255&e;++a>0)-s&255;return t+n},c.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=Math.pow(2,8*n-1);B(this,e,t,n,i-1,-i)}var a=n-1,o=1,s=0;for(this[t+a]=255&e;--a>=0&&(o*=256);)e<0&&0===s&&0!==this[t+a+1]&&(s=1),this[t+a]=(e/o>>0)-s&255;return t+n},c.prototype.writeInt8=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=255&e,t+1},c.prototype.writeInt16LE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},c.prototype.writeInt16BE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},c.prototype.writeInt32LE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},c.prototype.writeInt32BE=function(e,t,n){return e=+e,t>>>=0,n||B(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},c.prototype.writeFloatLE=function(e,t,n){return H(this,e,t,!0,n)},c.prototype.writeFloatBE=function(e,t,n){return H(this,e,t,!1,n)},c.prototype.writeDoubleLE=function(e,t,n){return $(this,e,t,!0,n)},c.prototype.writeDoubleBE=function(e,t,n){return $(this,e,t,!1,n)},c.prototype.copy=function(e,t,n,r){if(!c.isBuffer(e))throw TypeError("argument should be a Buffer");if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw RangeError("Index out of range");if(r<0)throw RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!i){if(n>56319||o+1===r){(t-=3)>-1&&a.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&a.push(239,191,189),i=n;continue}n=(i-55296<<10|n-56320)+65536}else i&&(t-=3)>-1&&a.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;a.push(n)}else if(n<2048){if((t-=2)<0)break;a.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;a.push(n>>12|224,n>>6&63|128,63&n|128)}else if(n<1114112){if((t-=4)<0)break;a.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}else throw Error("Invalid code point")}return a}function K(e){for(var t=[],n=0;n>8,a.push(i=n%256),a.push(r);return a}function q(e){return r.toByteArray(G(e))}function Z(e,t,n,r){for(var i=0;i=t.length)&&!(i>=e.length);++i)t[i+n]=e[i];return i}function X(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function J(e){return e!=e}var Q=function(){for(var e="0123456789abcdef",t=Array(256),n=0;n<16;++n)for(var r=16*n,i=0;i<16;++i)t[r+i]=e[n]+e[i];return t}()},94184(e,t){var n,r; /*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ !function(){"use strict";var i={}.hasOwnProperty;function a(){for(var e=[],t=0;t>8&255]},F=function(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]},Y=function(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]},B=function(e){return N(e,23,4)},U=function(e){return N(e,52,8)},H=function(e,t){g(e[x],t,{get:function(){return _(this)[t]}})},$=function(e,t,n,r){var i=d(n),a=_(e);if(i+t>a.byteLength)throw D(M);var o=_(a.buffer).bytes,s=i+a.byteOffset,u=o.slice(s,s+t);return r?u:u.reverse()},z=function(e,t,n,r,i,a){var o=d(n),s=_(e);if(o+t>s.byteLength)throw D(M);for(var u=_(s.buffer).bytes,c=o+s.byteOffset,l=r(+i),f=0;fV;)(G=K[V++])in A||o(A,G,O[G]);W.constructor=A}b&&p(C)!==I&&b(C,I);var q=new L(new A(2)),Z=C.setInt8;q.setInt8(0,2147483648),q.setInt8(1,2147483649),(q.getInt8(0)||!q.getInt8(1))&&s(C,{setInt8:function(e,t){Z.call(this,e,t<<24>>24)},setUint8:function(e,t){Z.call(this,e,t<<24>>24)}},{unsafe:!0})}else A=function(e){c(this,A,S);var t=d(e);E(this,{bytes:v.call(Array(t),0),byteLength:t}),i||(this.byteLength=t)},L=function(e,t,n){c(this,L,k),c(e,A,k);var r=_(e).byteLength,a=l(t);if(a<0||a>r)throw D("Wrong offset");if(n=void 0===n?r-a:f(n),a+n>r)throw D(T);E(this,{buffer:e,byteLength:n,byteOffset:a}),i||(this.buffer=e,this.byteLength=n,this.byteOffset=a)},i&&(H(A,"byteLength"),H(L,"buffer"),H(L,"byteLength"),H(L,"byteOffset")),s(L[x],{getInt8:function(e){return $(this,1,e)[0]<<24>>24},getUint8:function(e){return $(this,1,e)[0]},getInt16:function(e){var t=$(this,2,e,arguments.length>1?arguments[1]:void 0);return(t[1]<<8|t[0])<<16>>16},getUint16:function(e){var t=$(this,2,e,arguments.length>1?arguments[1]:void 0);return t[1]<<8|t[0]},getInt32:function(e){return Y($(this,4,e,arguments.length>1?arguments[1]:void 0))},getUint32:function(e){return Y($(this,4,e,arguments.length>1?arguments[1]:void 0))>>>0},getFloat32:function(e){return P($(this,4,e,arguments.length>1?arguments[1]:void 0),23)},getFloat64:function(e){return P($(this,8,e,arguments.length>1?arguments[1]:void 0),52)},setInt8:function(e,t){z(this,1,e,R,t)},setUint8:function(e,t){z(this,1,e,R,t)},setInt16:function(e,t){z(this,2,e,j,t,arguments.length>2?arguments[2]:void 0)},setUint16:function(e,t){z(this,2,e,j,t,arguments.length>2?arguments[2]:void 0)},setInt32:function(e,t){z(this,4,e,F,t,arguments.length>2?arguments[2]:void 0)},setUint32:function(e,t){z(this,4,e,F,t,arguments.length>2?arguments[2]:void 0)},setFloat32:function(e,t){z(this,4,e,B,t,arguments.length>2?arguments[2]:void 0)},setFloat64:function(e,t){z(this,8,e,U,t,arguments.length>2?arguments[2]:void 0)}});y(A,S),y(L,k),e.exports={ArrayBuffer:A,DataView:L}},1048(e,t,n){"use strict";var r=n(47908),i=n(51400),a=n(17466),o=Math.min;e.exports=[].copyWithin||function(e,t){var n=r(this),s=a(n.length),u=i(e,s),c=i(t,s),l=arguments.length>2?arguments[2]:void 0,f=o((void 0===l?s:i(l,s))-c,s-u),d=1;for(c0;)c in n?n[u]=n[c]:delete n[u],u+=d,c+=d;return n}},21285(e,t,n){"use strict";var r=n(47908),i=n(51400),a=n(17466);e.exports=function(e){for(var t=r(this),n=a(t.length),o=arguments.length,s=i(o>1?arguments[1]:void 0,n),u=o>2?arguments[2]:void 0,c=void 0===u?n:i(u,n);c>s;)t[s++]=e;return t}},18533(e,t,n){"use strict";var r=n(42092).forEach,i=n(9341)("forEach");e.exports=i?[].forEach:function(e){return r(this,e,arguments.length>1?arguments[1]:void 0)}},97745(e){e.exports=function(e,t){for(var n=0,r=t.length,i=new e(r);r>n;)i[n]=t[n++];return i}},48457(e,t,n){"use strict";var r=n(49974),i=n(47908),a=n(53411),o=n(97659),s=n(17466),u=n(86135),c=n(18554),l=n(71246);e.exports=function(e){var t,n,f,d,h,p,b=i(e),m="function"==typeof this?this:Array,g=arguments.length,v=g>1?arguments[1]:void 0,y=void 0!==v,w=l(b),_=0;if(y&&(v=r(v,g>2?arguments[2]:void 0,2)),void 0==w||m==Array&&o(w))for(t=s(b.length),n=new m(t);t>_;_++)p=y?v(b[_],_):b[_],u(n,_,p);else for(h=(d=c(b,w)).next,n=new m;!(f=h.call(d)).done;_++)p=y?a(d,v,[f.value,_],!0):f.value,u(n,_,p);return n.length=_,n}},61386(e,t,n){var r=n(49974),i=n(68361),a=n(47908),o=n(17466),s=n(34948),u=n(70030),c=n(97745),l=[].push;e.exports=function(e,t,n,f){for(var d,h,p,b=a(e),m=i(b),g=r(t,n,3),v=u(null),y=o(m.length),w=0;y>w;w++)(h=s(g(p=m[w],w,b)))in v?l.call(v[h],p):v[h]=[p];if(f&&(d=f(b))!==Array)for(h in v)v[h]=c(d,v[h]);return v}},41318(e,t,n){var r=n(45656),i=n(17466),a=n(51400),o=function(e){return function(t,n,o){var s,u=r(t),c=i(u.length),l=a(o,c);if(e&&n!=n){for(;c>l;)if((s=u[l++])!=s)return!0}else for(;c>l;l++)if((e||l in u)&&u[l]===n)return e||l||0;return!e&&-1}};e.exports={includes:o(!0),indexOf:o(!1)}},9671(e,t,n){var r=n(49974),i=n(68361),a=n(47908),o=n(17466),s=function(e){var t=1==e;return function(n,s,u){for(var c,l,f=a(n),d=i(f),h=r(s,u,3),p=o(d.length);p-- >0;)if(l=h(c=d[p],p,f))switch(e){case 0:return c;case 1:return p}return t?-1:void 0}};e.exports={findLast:s(0),findLastIndex:s(1)}},42092(e,t,n){var r=n(49974),i=n(68361),a=n(47908),o=n(17466),s=n(65417),u=[].push,c=function(e){var t=1==e,n=2==e,c=3==e,l=4==e,f=6==e,d=7==e,h=5==e||f;return function(p,b,m,g){for(var v,y,w=a(p),_=i(w),E=r(b,m,3),S=o(_.length),k=0,x=g||s,T=t?x(p,S):n||d?x(p,0):void 0;S>k;k++)if((h||k in _)&&(y=E(v=_[k],k,w),e)){if(t)T[k]=y;else if(y)switch(e){case 3:return!0;case 5:return v;case 6:return k;case 2:u.call(T,v)}else switch(e){case 4:return!1;case 7:u.call(T,v)}}return f?-1:c||l?l:T}};e.exports={forEach:c(0),map:c(1),filter:c(2),some:c(3),every:c(4),find:c(5),findIndex:c(6),filterReject:c(7)}},86583(e,t,n){"use strict";var r=n(45656),i=n(99958),a=n(17466),o=n(9341),s=Math.min,u=[].lastIndexOf,c=!!u&&1/[1].lastIndexOf(1,-0)<0,l=o("lastIndexOf"),f=c||!l;e.exports=f?function(e){if(c)return u.apply(this,arguments)||0;var t=r(this),n=a(t.length),o=n-1;for(arguments.length>1&&(o=s(o,i(arguments[1]))),o<0&&(o=n+o);o>=0;o--)if(o in t&&t[o]===e)return o||0;return -1}:u},81194(e,t,n){var r=n(47293),i=n(5112),a=n(7392),o=i("species");e.exports=function(e){return a>=51||!r(function(){var t=[];return(t.constructor={})[o]=function(){return{foo:1}},1!==t[e](Boolean).foo})}},9341(e,t,n){"use strict";var r=n(47293);e.exports=function(e,t){var n=[][e];return!!n&&r(function(){n.call(null,t||function(){throw 1},1)})}},53671(e,t,n){var r=n(13099),i=n(47908),a=n(68361),o=n(17466),s=function(e){return function(t,n,s,u){r(n);var c=i(t),l=a(c),f=o(c.length),d=e?f-1:0,h=e?-1:1;if(s<2)for(;;){if(d in l){u=l[d],d+=h;break}if(d+=h,e?d<0:f<=d)throw TypeError("Reduce of empty array with no initial value")}for(;e?d>=0:f>d;d+=h)d in l&&(u=n(u,l[d],d,c));return u}};e.exports={left:s(!1),right:s(!0)}},94362(e){var t=Math.floor,n=function(e,a){var o=e.length,s=t(o/2);return o<8?r(e,a):i(n(e.slice(0,s),a),n(e.slice(s),a),a)},r=function(e,t){for(var n,r,i=e.length,a=1;a0;)e[r]=e[--r];r!==a++&&(e[r]=n)}return e},i=function(e,t,n){for(var r=e.length,i=t.length,a=0,o=0,s=[];a=n(e[a],t[o])?e[a++]:t[o++]):s.push(a1?arguments[1]:void 0;return(r(this),(t=void 0!==c)&&r(c),void 0==e)?new this:(n=[],t?(o=0,s=i(c,u>2?arguments[2]:void 0,2),a(e,function(e){n.push(s(e,o++))})):a(e,n.push,{that:n}),new this(n))}},82044(e){"use strict";e.exports=function(){for(var e=arguments.length,t=Array(e);e--;)t[e]=arguments[e];return new this(t)}},95631(e,t,n){"use strict";var r=n(3070).f,i=n(70030),a=n(12248),o=n(49974),s=n(25787),u=n(20408),c=n(70654),l=n(96340),f=n(19781),d=n(62423).fastKey,h=n(29909),p=h.set,b=h.getterFor;e.exports={getConstructor:function(e,t,n,c){var l=e(function(e,r){s(e,l,t),p(e,{type:t,index:i(null),first:void 0,last:void 0,size:0}),f||(e.size=0),void 0!=r&&u(r,e[c],{that:e,AS_ENTRIES:n})}),h=b(t),m=function(e,t,n){var r,i,a=h(e),o=g(e,t);return o?o.value=n:(a.last=o={index:i=d(t,!0),key:t,value:n,previous:r=a.last,next:void 0,removed:!1},a.first||(a.first=o),r&&(r.next=o),f?a.size++:e.size++,"F"!==i&&(a.index[i]=o)),e},g=function(e,t){var n,r=h(e),i=d(t);if("F"!==i)return r.index[i];for(n=r.first;n;n=n.next)if(n.key==t)return n};return a(l.prototype,{clear:function(){for(var e=this,t=h(e),n=t.index,r=t.first;r;)r.removed=!0,r.previous&&(r.previous=r.previous.next=void 0),delete n[r.index],r=r.next;t.first=t.last=void 0,f?t.size=0:e.size=0},delete:function(e){var t=this,n=h(t),r=g(t,e);if(r){var i=r.next,a=r.previous;delete n.index[r.index],r.removed=!0,a&&(a.next=i),i&&(i.previous=a),n.first==r&&(n.first=i),n.last==r&&(n.last=a),f?n.size--:t.size--}return!!r},forEach:function(e){for(var t,n=h(this),r=o(e,arguments.length>1?arguments[1]:void 0,3);t=t?t.next:n.first;)for(r(t.value,t.key,this);t&&t.removed;)t=t.previous},has:function(e){return!!g(this,e)}}),a(l.prototype,n?{get:function(e){var t=g(this,e);return t&&t.value},set:function(e,t){return m(this,0===e?0:e,t)}}:{add:function(e){return m(this,e=0===e?0:e,e)}}),f&&r(l.prototype,"size",{get:function(){return h(this).size}}),l},setStrong:function(e,t,n){var r=t+" Iterator",i=b(t),a=b(r);c(e,t,function(e,t){p(this,{type:r,target:e,state:i(e),kind:t,last:void 0})},function(){for(var e=a(this),t=e.kind,n=e.last;n&&n.removed;)n=n.previous;return e.target&&(e.last=n=n?n.next:e.state.first)?"keys"==t?{value:n.key,done:!1}:"values"==t?{value:n.value,done:!1}:{value:[n.key,n.value],done:!1}:(e.target=void 0,{value:void 0,done:!0})},n?"entries":"values",!n,!0),l(t)}}},29320(e,t,n){"use strict";var r=n(12248),i=n(62423).getWeakData,a=n(19670),o=n(70111),s=n(25787),u=n(20408),c=n(42092),l=n(86656),f=n(29909),d=f.set,h=f.getterFor,p=c.find,b=c.findIndex,m=0,g=function(e){return e.frozen||(e.frozen=new v)},v=function(){this.entries=[]},y=function(e,t){return p(e.entries,function(e){return e[0]===t})};v.prototype={get:function(e){var t=y(this,e);if(t)return t[1]},has:function(e){return!!y(this,e)},set:function(e,t){var n=y(this,e);n?n[1]=t:this.entries.push([e,t])},delete:function(e){var t=b(this.entries,function(t){return t[0]===e});return~t&&this.entries.splice(t,1),!!~t}},e.exports={getConstructor:function(e,t,n,c){var f=e(function(e,r){s(e,f,t),d(e,{type:t,id:m++,frozen:void 0}),void 0!=r&&u(r,e[c],{that:e,AS_ENTRIES:n})}),p=h(t),b=function(e,t,n){var r=p(e),o=i(a(t),!0);return!0===o?g(r).set(t,n):o[r.id]=n,e};return r(f.prototype,{delete:function(e){var t=p(this);if(!o(e))return!1;var n=i(e);return!0===n?g(t).delete(e):n&&l(n,t.id)&&delete n[t.id]},has:function(e){var t=p(this);if(!o(e))return!1;var n=i(e);return!0===n?g(t).has(e):n&&l(n,t.id)}}),r(f.prototype,n?{get:function(e){var t=p(this);if(o(e)){var n=i(e);return!0===n?g(t).get(e):n?n[t.id]:void 0}},set:function(e,t){return b(this,e,t)}}:{add:function(e){return b(this,e,!0)}}),f}}},77710(e,t,n){"use strict";var r=n(82109),i=n(17854),a=n(54705),o=n(31320),s=n(62423),u=n(20408),c=n(25787),l=n(70111),f=n(47293),d=n(17072),h=n(58003),p=n(79587);e.exports=function(e,t,n){var b=-1!==e.indexOf("Map"),m=-1!==e.indexOf("Weak"),g=b?"set":"add",v=i[e],y=v&&v.prototype,w=v,_={},E=function(e){var t=y[e];o(y,e,"add"==e?function(e){return t.call(this,0===e?0:e),this}:"delete"==e?function(e){return(!m||!!l(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return m&&!l(e)?void 0:t.call(this,0===e?0:e)}:"has"==e?function(e){return(!m||!!l(e))&&t.call(this,0===e?0:e)}:function(e,n){return t.call(this,0===e?0:e,n),this})};if(a(e,"function"!=typeof v||!(m||y.forEach&&!f(function(){new v().entries().next()}))))w=n.getConstructor(t,e,b,g),s.enable();else if(a(e,!0)){var S=new w,k=S[g](m?{}:-0,1)!=S,x=f(function(){S.has(1)}),T=d(function(e){new v(e)}),M=!m&&f(function(){for(var e=new v,t=5;t--;)e[g](t,t);return!e.has(-0)});T||((w=t(function(t,n){c(t,w,e);var r=p(new v,t,w);return void 0!=n&&u(n,r[g],{that:r,AS_ENTRIES:b}),r})).prototype=y,y.constructor=w),(x||M)&&(E("delete"),E("has"),b&&E("get")),(M||k)&&E(g),m&&y.clear&&delete y.clear}return _[e]=w,r({global:!0,forced:w!=v},_),h(w,e),m||n.setStrong(w,e,b),w}},10313(e,t,n){var r=n(51532),i=n(4129),a=n(70030),o=n(70111),s=function(){this.object=null,this.symbol=null,this.primitives=null,this.objectsByIndex=a(null)};s.prototype.get=function(e,t){return this[e]||(this[e]=t())},s.prototype.next=function(e,t,n){var a=n?this.objectsByIndex[e]||(this.objectsByIndex[e]=new i):this.primitives||(this.primitives=new r),o=a.get(t);return o||a.set(t,o=new s),o};var u=new s;e.exports=function(){var e,t,n=u,r=arguments.length;for(e=0;e"+s+""}},24994(e,t,n){"use strict";var r=n(13383).IteratorPrototype,i=n(70030),a=n(79114),o=n(58003),s=n(97497),u=function(){return this};e.exports=function(e,t,n){var c=t+" Iterator";return e.prototype=i(r,{next:a(1,n)}),o(e,c,!1,!0),s[c]=u,e}},68880(e,t,n){var r=n(19781),i=n(3070),a=n(79114);e.exports=r?function(e,t,n){return i.f(e,t,a(1,n))}:function(e,t,n){return e[t]=n,e}},79114(e){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},86135(e,t,n){"use strict";var r=n(34948),i=n(3070),a=n(79114);e.exports=function(e,t,n){var o=r(t);o in e?i.f(e,o,a(0,n)):e[o]=n}},85573(e,t,n){"use strict";var r=n(47293),i=n(76650).start,a=Math.abs,o=Date.prototype,s=o.getTime,u=o.toISOString;e.exports=r(function(){return"0385-07-25T07:06:39.999Z"!=u.call(new Date(-5e13-1))})||!r(function(){u.call(new Date(NaN))})?function(){if(!isFinite(s.call(this)))throw RangeError("Invalid time value");var e=this,t=e.getUTCFullYear(),n=e.getUTCMilliseconds(),r=t<0?"-":t>9999?"+":"";return r+i(a(t),r?6:4,0)+"-"+i(e.getUTCMonth()+1,2,0)+"-"+i(e.getUTCDate(),2,0)+"T"+i(e.getUTCHours(),2,0)+":"+i(e.getUTCMinutes(),2,0)+":"+i(e.getUTCSeconds(),2,0)+"."+i(n,3,0)+"Z"}:u},38709(e,t,n){"use strict";var r=n(19670),i=n(92140);e.exports=function(e){if(r(this),"string"===e||"default"===e)e="string";else if("number"!==e)throw TypeError("Incorrect hint");return i(this,e)}},70654(e,t,n){"use strict";var r=n(82109),i=n(24994),a=n(79518),o=n(27674),s=n(58003),u=n(68880),c=n(31320),l=n(5112),f=n(31913),d=n(97497),h=n(13383),p=h.IteratorPrototype,b=h.BUGGY_SAFARI_ITERATORS,m=l("iterator"),g="keys",v="values",y="entries",w=function(){return this};e.exports=function(e,t,n,l,h,_,E){i(n,t,l);var S,k,x,T=function(e){if(e===h&&C)return C;if(!b&&e in A)return A[e];switch(e){case g:case v:case y:return function(){return new n(this,e)}}return function(){return new n(this)}},M=t+" Iterator",O=!1,A=e.prototype,L=A[m]||A["@@iterator"]||h&&A[h],C=!b&&L||T(h),I="Array"==t&&A.entries||L;if(I&&(S=a(I.call(new e)),p!==Object.prototype&&S.next&&(f||a(S)===p||(o?o(S,p):"function"!=typeof S[m]&&u(S,m,w)),s(S,M,!0,!0),f&&(d[M]=w))),h==v&&L&&L.name!==v&&(O=!0,C=function(){return L.call(this)}),(!f||E)&&A[m]!==C&&u(A,m,C),d[t]=C,h){if(k={values:T(v),keys:_?C:T(g),entries:T(y)},E)for(x in k)!b&&!O&&x in A||c(A,x,k[x]);else r({target:t,proto:!0,forced:b||O},k)}return k}},97235(e,t,n){var r=n(40857),i=n(86656),a=n(6061),o=n(3070).f;e.exports=function(e){var t=r.Symbol||(r.Symbol={});i(t,e)||o(t,e,{value:a.f(e)})}},19781(e,t,n){var r=n(47293);e.exports=!r(function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})},80317(e,t,n){var r=n(17854),i=n(70111),a=r.document,o=i(a)&&i(a.createElement);e.exports=function(e){return o?a.createElement(e):{}}},48324(e){e.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},68886(e,t,n){var r=n(88113).match(/firefox\/(\d+)/i);e.exports=!!r&&+r[1]},7871(e){e.exports="object"==typeof window},30256(e,t,n){var r=n(88113);e.exports=/MSIE|Trident/.test(r)},71528(e,t,n){var r=n(88113),i=n(17854);e.exports=/ipad|iphone|ipod/i.test(r)&&void 0!==i.Pebble},6833(e,t,n){var r=n(88113);e.exports=/(?:ipad|iphone|ipod).*applewebkit/i.test(r)},35268(e,t,n){var r=n(84326),i=n(17854);e.exports="process"==r(i.process)},71036(e,t,n){var r=n(88113);e.exports=/web0s(?!.*chrome)/i.test(r)},88113(e,t,n){var r=n(35005);e.exports=r("navigator","userAgent")||""},7392(e,t,n){var r,i,a=n(17854),o=n(88113),s=a.process,u=a.Deno,c=s&&s.versions||u&&u.version,l=c&&c.v8;l?i=(r=l.split("."))[0]<4?1:r[0]+r[1]:o&&(!(r=o.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=o.match(/Chrome\/(\d+)/))&&(i=r[1]),e.exports=i&&+i},98008(e,t,n){var r=n(88113).match(/AppleWebKit\/(\d+)\./);e.exports=!!r&&+r[1]},80748(e){e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},82109(e,t,n){var r=n(17854),i=n(31236).f,a=n(68880),o=n(31320),s=n(83505),u=n(99920),c=n(54705);e.exports=function(e,t){var n,l,f,d,h,p,b=e.target,m=e.global,g=e.stat;if(l=m?r:g?r[b]||s(b,{}):(r[b]||{}).prototype)for(f in t){if(h=t[f],d=e.noTargetGet?(p=i(l,f))&&p.value:l[f],!(n=c(m?f:b+(g?".":"#")+f,e.forced))&&void 0!==d){if(typeof h==typeof d)continue;u(h,d)}(e.sham||d&&d.sham)&&a(h,"sham",!0),o(l,f,h,e)}}},47293(e){e.exports=function(e){try{return!!e()}catch(t){return!0}}},27007(e,t,n){"use strict";n(74916);var r=n(31320),i=n(22261),a=n(47293),o=n(5112),s=n(68880),u=o("species"),c=RegExp.prototype;e.exports=function(e,t,n,l){var f=o(e),d=!a(function(){var t={};return t[f]=function(){return 7},7!=""[e](t)}),h=d&&!a(function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[u]=function(){return n},n.flags="",n[f]=/./[f]),n.exec=function(){return t=!0,null},n[f](""),!t});if(!d||!h||n){var p=/./[f],b=t(f,""[e],function(e,t,n,r,a){var o=t.exec;return o===i||o===c.exec?d&&!a?{done:!0,value:p.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}});r(String.prototype,e,b[0]),r(c,f,b[1])}l&&s(c[f],"sham",!0)}},6790(e,t,n){"use strict";var r=n(43157),i=n(17466),a=n(49974),o=function(e,t,n,s,u,c,l,f){for(var d,h=u,p=0,b=!!l&&a(l,f,3);p0&&r(d))h=o(e,t,d,i(d.length),h,c-1)-1;else{if(h>=9007199254740991)throw TypeError("Exceed the acceptable array length");e[h]=d}h++}p++}return h};e.exports=o},76677(e,t,n){var r=n(47293);e.exports=!r(function(){return Object.isExtensible(Object.preventExtensions({}))})},49974(e,t,n){var r=n(13099);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},27065(e,t,n){"use strict";var r=n(13099),i=n(70111),a=[].slice,o={},s=function(e,t,n){if(!(t in o)){for(var r=[],i=0;i]*>)/g,s=/\$([$&'`]|\d{1,2})/g;e.exports=function(e,t,n,u,c,l){var f=n+e.length,d=u.length,h=s;return void 0!==c&&(c=r(c),h=o),a.call(l,h,function(r,a){var o;switch(a.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(f);case"<":o=c[a.slice(1,-1)];break;default:var s=+a;if(0===s)return r;if(s>d){var l=i(s/10);if(0===l)return r;if(l<=d)return void 0===u[l-1]?a.charAt(1):u[l-1]+a.charAt(1);return r}o=u[s-1]}return void 0===o?"":o})}},17854(e,t,n){var r=function(e){return e&&e.Math==Math&&e};e.exports=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},86656(e,t,n){var r=n(47908),i={}.hasOwnProperty;e.exports=Object.hasOwn||function(e,t){return i.call(r(e),t)}},3501(e){e.exports={}},842(e,t,n){var r=n(17854);e.exports=function(e,t){var n=r.console;n&&n.error&&(1===arguments.length?n.error(e):n.error(e,t))}},60490(e,t,n){var r=n(35005);e.exports=r("document","documentElement")},64664(e,t,n){var r=n(19781),i=n(47293),a=n(80317);e.exports=!r&&!i(function(){return 7!=Object.defineProperty(a("div"),"a",{get:function(){return 7}}).a})},11179(e){var t=Math.abs,n=Math.pow,r=Math.floor,i=Math.log,a=Math.LN2,o=function(e,o,s){var u,c,l,f=Array(s),d=8*s-o-1,h=(1<>1,b=23===o?n(2,-24)-n(2,-77):0,m=e<0||0===e&&1/e<0?1:0,g=0;for((e=t(e))!=e||e===1/0?(c=e!=e?1:0,u=h):(u=r(i(e)/a),e*(l=n(2,-u))<1&&(u--,l*=2),u+p>=1?e+=b/l:e+=b*n(2,1-p),e*l>=2&&(u++,l/=2),u+p>=h?(c=0,u=h):u+p>=1?(c=(e*l-1)*n(2,o),u+=p):(c=e*n(2,p-1)*n(2,o),u=0));o>=8;f[g++]=255&c,c/=256,o-=8);for(u=u<0;f[g++]=255&u,u/=256,d-=8);return f[--g]|=128*m,f},s=function(e,t){var r,i=e.length,a=8*i-t-1,o=(1<>1,u=a-7,c=i-1,l=e[c--],f=127&l;for(l>>=7;u>0;f=256*f+e[c],c--,u-=8);for(r=f&(1<<-u)-1,f>>=-u,u+=t;u>0;r=256*r+e[c],c--,u-=8);if(0===f)f=1-s;else{if(f===o)return r?NaN:l?-1/0:1/0;r+=n(2,t),f-=s}return(l?-1:1)*r*n(2,f-t)};e.exports={pack:o,unpack:s}},68361(e,t,n){var r=n(47293),i=n(84326),a="".split;e.exports=r(function(){return!Object("z").propertyIsEnumerable(0)})?function(e){return"String"==i(e)?a.call(e,""):Object(e)}:Object},79587(e,t,n){var r=n(70111),i=n(27674);e.exports=function(e,t,n){var a,o;return i&&"function"==typeof(a=t.constructor)&&a!==n&&r(o=a.prototype)&&o!==n.prototype&&i(e,o),e}},42788(e,t,n){var r=n(5465),i=Function.toString;"function"!=typeof r.inspectSource&&(r.inspectSource=function(e){return i.call(e)}),e.exports=r.inspectSource},62423(e,t,n){var r=n(82109),i=n(3501),a=n(70111),o=n(86656),s=n(3070).f,u=n(8006),c=n(1156),l=n(69711),f=n(76677),d=!1,h=l("meta"),p=0,b=Object.isExtensible||function(){return!0},m=function(e){s(e,h,{value:{objectID:"O"+p++,weakData:{}}})},g=function(e,t){if(!a(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!o(e,h)){if(!b(e))return"F";if(!t)return"E";m(e)}return e[h].objectID},v=function(e,t){if(!o(e,h)){if(!b(e))return!0;if(!t)return!1;m(e)}return e[h].weakData},y=function(e){return f&&d&&b(e)&&!o(e,h)&&m(e),e},w=function(){_.enable=function(){},d=!0;var e=u.f,t=[].splice,n={};n[h]=1,e(n).length&&(u.f=function(n){for(var r=e(n),i=0,a=r.length;ih;h++)if((b=k(e[h]))&&b instanceof l)return b;return new l(!1)}f=s(e,d)}for(m=f.next;!(g=m.call(f)).done;){try{b=k(g.value)}catch(x){c(f,"throw",x)}if("object"==typeof b&&b&&b instanceof l)return b}return new l(!1)}},99212(e,t,n){var r=n(19670);e.exports=function(e,t,n){var i,a;r(e);try{if(void 0===(i=e.return)){if("throw"===t)throw n;return n}i=i.call(e)}catch(o){a=!0,i=o}if("throw"===t)throw n;if(a)throw i;return r(i),n}},54956(e,t,n){"use strict";var r=n(40857),i=n(13099),a=n(19670),o=n(70030),s=n(68880),u=n(12248),c=n(5112),l=n(29909),f=l.set,d=l.get,h=c("toStringTag");e.exports=function(e,t){var n=function(e){e.next=i(e.iterator.next),e.done=!1,e.ignoreArg=!t,f(this,e)};return n.prototype=u(o(r.Iterator.prototype),{next:function(n){var r=d(this),i=arguments.length?[r.ignoreArg?void 0:n]:t?[]:[void 0];r.ignoreArg=!1;var a=r.done?void 0:e.call(r,i);return{done:r.done,value:a}},return:function(e){var t=d(this).iterator;t.done=!0;var n=t.return;return{done:!0,value:void 0===n?e:a(n.call(t,e)).value}},throw:function(e){var t=d(this).iterator;t.done=!0;var n=t.throw;if(void 0===n)throw e;return n.call(t,e)}}),t||s(n.prototype,h,"Generator"),n}},13383(e,t,n){"use strict";var r,i,a,o=n(47293),s=n(79518),u=n(68880),c=n(86656),l=n(5112),f=n(31913),d=l("iterator"),h=!1,p=function(){return this};[].keys&&("next"in(a=[].keys())?(i=s(s(a)))!==Object.prototype&&(r=i):h=!0);var b=void 0==r||o(function(){var e={};return r[d].call(e)!==e});b&&(r={}),f&&!b||c(r,d)||u(r,d,p),e.exports={IteratorPrototype:r,BUGGY_SAFARI_ITERATORS:h}},97497(e){e.exports={}},37502(e,t,n){"use strict";var r=n(19670);e.exports=function(e,t){var n=r(this),i=n.has(e)&&"update"in t?t.update(n.get(e),e,n):t.insert(e,n);return n.set(e,i),i}},8154(e,t,n){"use strict";var r=n(19670);e.exports=function(e,t){var n,i=r(this),a=arguments.length>2?arguments[2]:void 0;if("function"!=typeof t&&"function"!=typeof a)throw TypeError("At least one callback required");return i.has(e)?(n=i.get(e),"function"==typeof t&&(n=t(n),i.set(e,n))):"function"==typeof a&&(n=a(),i.set(e,n)),n}},66736(e){var t=Math.expm1,n=Math.exp;e.exports=!t||t(10)>22025.465794806718||22025.465794806718>t(10)||-.00000000000000002!=t(-.00000000000000002)?function(e){return 0==(e=+e)?e:e>-.000001&&e<1e-6?e+e*e/2:n(e)-1}:t},26130(e,t,n){var r=n(64310),i=Math.abs,a=Math.pow,o=a(2,-52),s=a(2,-23),u=a(2,127)*(2-s),c=a(2,-126),l=function(e){return e+1/o-1/o};e.exports=Math.fround||function(e){var t,n,a=i(e),f=r(e);return au||n!=n?f*(1/0):f*n}},26513(e){var t=Math.log;e.exports=Math.log1p||function(e){return(e=+e)>-.00000001&&e<1e-8?e-e*e/2:t(1+e)}},47103(e){e.exports=Math.scale||function(e,t,n,r,i){return 0===arguments.length||e!=e||t!=t||n!=n||r!=r||i!=i?NaN:e===1/0||e===-1/0?e:(e-t)*(i-r)/(n-t)+r}},64310(e){e.exports=Math.sign||function(e){return 0==(e=+e)||e!=e?e:e<0?-1:1}},95948(e,t,n){var r,i,a,o,s,u,c,l,f=n(17854),d=n(31236).f,h=n(20261).set,p=n(6833),b=n(71528),m=n(71036),g=n(35268),v=f.MutationObserver||f.WebKitMutationObserver,y=f.document,w=f.process,_=f.Promise,E=d(f,"queueMicrotask"),S=E&&E.value;S||(r=function(){var e,t;for(g&&(e=w.domain)&&e.exit();i;){t=i.fn,i=i.next;try{t()}catch(n){throw i?o():a=void 0,n}}a=void 0,e&&e.enter()},p||g||m||!v||!y?!b&&_&&_.resolve?((c=_.resolve(void 0)).constructor=_,l=c.then,o=function(){l.call(c,r)}):o=g?function(){w.nextTick(r)}:function(){h.call(f,r)}:(s=!0,u=y.createTextNode(""),new v(r).observe(u,{characterData:!0}),o=function(){u.data=s=!s})),e.exports=S||function(e){var t={fn:e,next:void 0};a&&(a.next=t),i||(i=t,o()),a=t}},13366(e,t,n){var r=n(17854);e.exports=r.Promise},30133(e,t,n){var r=n(7392),i=n(47293);e.exports=!!Object.getOwnPropertySymbols&&!i(function(){var e=Symbol();return!String(e)||!(Object(e) instanceof Symbol)||!Symbol.sham&&r&&r<41})},590(e,t,n){var r=n(47293),i=n(5112),a=n(31913),o=i("iterator");e.exports=!r(function(){var e=new URL("b?a=1&b=2&c=3","http://a"),t=e.searchParams,n="";return e.pathname="c%20d",t.forEach(function(e,r){t.delete("b"),n+=r+e}),a&&!e.toJSON||!t.sort||"http://a/c%20d?a=1&c=3"!==e.href||"3"!==t.get("c")||"a=1"!==String(new URLSearchParams("?a=1"))||!t[o]||"a"!==new URL("https://a@b").username||"b"!==new URLSearchParams(new URLSearchParams("a=b")).get("a")||"xn--e1aybc"!==new URL("http://тест").host||"#%D0%B1"!==new URL("http://a#б").hash||"a1c3"!==n||"x"!==new URL("http://x",void 0).host})},68536(e,t,n){var r=n(17854),i=n(42788),a=r.WeakMap;e.exports="function"==typeof a&&/native code/.test(i(a))},78523(e,t,n){"use strict";var r=n(13099),i=function(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=r(t),this.reject=r(n)};e.exports.f=function(e){return new i(e)}},3929(e,t,n){var r=n(47850);e.exports=function(e){if(r(e))throw TypeError("The method doesn't accept regular expressions");return e}},77023(e,t,n){var r=n(17854).isFinite;e.exports=Number.isFinite||function(e){return"number"==typeof e&&r(e)}},2814(e,t,n){var r=n(17854),i=n(41340),a=n(53111).trim,o=n(81361),s=r.parseFloat,u=1/s(o+"-0")!=-1/0;e.exports=u?function(e){var t=a(i(e)),n=s(t);return 0===n&&"-"==t.charAt(0)?-0:n}:s},83009(e,t,n){var r=n(17854),i=n(41340),a=n(53111).trim,o=n(81361),s=r.parseInt,u=/^[+-]?0[Xx]/,c=8!==s(o+"08")||22!==s(o+"0x16");e.exports=c?function(e,t){var n=a(i(e));return s(n,t>>>0||(u.test(n)?16:10))}:s},80430(e,t,n){"use strict";var r=n(29909),i=n(24994),a=n(70111),o=n(36048),s=n(19781),u="Incorrect Number.range arguments",c="NumericRangeIterator",l=r.set,f=r.getterFor(c),d=i(function(e,t,n,r,i,o){if(typeof e!=r||t!==1/0&&t!==-1/0&&typeof t!=r)throw TypeError(u);if(e===1/0||e===-1/0)throw RangeError(u);var f,d=t>e,h=!1;if(void 0===n)f=void 0;else if(a(n))f=n.step,h=!!n.inclusive;else if(typeof n==r)f=n;else throw TypeError(u);if(null==f&&(f=d?o:-o),typeof f!=r)throw TypeError(u);if(f===1/0||f===-1/0||f===i&&e!==t)throw RangeError(u);var p=e!=e||t!=t||f!=f||t>e!=f>i;l(this,{type:c,start:e,end:t,step:f,inclusiveEnd:h,hitsEnd:p,currentCount:i,zero:i}),s||(this.start=e,this.end=t,this.step=f,this.inclusive=h)},c,function(){var e,t=f(this);if(t.hitsEnd)return{value:void 0,done:!0};var n=t.start,r=t.end,i=n+t.step*t.currentCount++;i===r&&(t.hitsEnd=!0);var a=t.inclusiveEnd;return(e=r>n?a?i>r:i>=r:a?r>i:r>=i)?{value:void 0,done:t.hitsEnd=!0}:{value:i,done:!1}}),h=function(e){return{get:e,set:function(){},configurable:!0,enumerable:!1}};s&&o(d.prototype,{start:h(function(){return f(this).start}),end:h(function(){return f(this).end}),inclusive:h(function(){return f(this).inclusiveEnd}),step:h(function(){return f(this).step})}),e.exports=d},21574(e,t,n){"use strict";var r=n(19781),i=n(47293),a=n(81956),o=n(25181),s=n(55296),u=n(47908),c=n(68361),l=Object.assign,f=Object.defineProperty;e.exports=!l||i(function(){if(r&&1!==l({b:1},l(f({},"a",{enumerable:!0,get:function(){f(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},n=Symbol(),i="abcdefghijklmnopqrst";return e[n]=7,i.split("").forEach(function(e){t[e]=e}),7!=l({},e)[n]||a(l({},t)).join("")!=i})?function(e,t){for(var n=u(e),i=arguments.length,l=1,f=o.f,d=s.f;i>l;)for(var h,p=c(arguments[l++]),b=f?a(p).concat(f(p)):a(p),m=b.length,g=0;m>g;)h=b[g++],(!r||d.call(p,h))&&(n[h]=p[h]);return n}:l},70030(e,t,n){var r,i=n(19670),a=n(36048),o=n(80748),s=n(3501),u=n(60490),c=n(80317),l=n(6200),f=">",d="<",h="prototype",p="script",b=l("IE_PROTO"),m=function(){},g=function(e){return d+p+f+e+d+"/"+p+f},v=function(e){e.write(g("")),e.close();var t=e.parentWindow.Object;return e=null,t},y=function(){var e,t=c("iframe"),n="java"+p+":";return t.style.display="none",u.appendChild(t),t.src=String(n),(e=t.contentWindow.document).open(),e.write(g("document.F=Object")),e.close(),e.F},w=function(){try{r=new ActiveXObject("htmlfile")}catch(e){}w="undefined"!=typeof document?document.domain&&r?v(r):y():v(r);for(var t=o.length;t--;)delete w[h][o[t]];return w()};s[b]=!0,e.exports=Object.create||function(e,t){var n;return null!==e?(m[h]=i(e),n=new m,m[h]=null,n[b]=e):n=w(),void 0===t?n:a(n,t)}},36048(e,t,n){var r=n(19781),i=n(3070),a=n(19670),o=n(81956);e.exports=r?Object.defineProperties:function(e,t){a(e);for(var n,r=o(t),s=r.length,u=0;s>u;)i.f(e,n=r[u++],t[n]);return e}},3070(e,t,n){var r=n(19781),i=n(64664),a=n(19670),o=n(34948),s=Object.defineProperty;t.f=r?s:function(e,t,n){if(a(e),t=o(t),a(n),i)try{return s(e,t,n)}catch(r){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(e[t]=n.value),e}},31236(e,t,n){var r=n(19781),i=n(55296),a=n(79114),o=n(45656),s=n(34948),u=n(86656),c=n(64664),l=Object.getOwnPropertyDescriptor;t.f=r?l:function(e,t){if(e=o(e),t=s(t),c)try{return l(e,t)}catch(n){}if(u(e,t))return a(!i.f.call(e,t),e[t])}},1156(e,t,n){var r=n(45656),i=n(8006).f,a={}.toString,o="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(e){try{return i(e)}catch(t){return o.slice()}};e.exports.f=function(e){return o&&"[object Window]"==a.call(e)?s(e):i(r(e))}},8006(e,t,n){var r=n(16324),i=n(80748).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return r(e,i)}},25181(e,t){t.f=Object.getOwnPropertySymbols},79518(e,t,n){var r=n(86656),i=n(47908),a=n(6200),o=n(49920),s=a("IE_PROTO"),u=Object.prototype;e.exports=o?Object.getPrototypeOf:function(e){return(e=i(e),r(e,s))?e[s]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?u:null}},60996(e,t,n){"use strict";var r=n(29909),i=n(24994),a=n(86656),o=n(81956),s=n(47908),u="Object Iterator",c=r.set,l=r.getterFor(u);e.exports=i(function(e,t){var n=s(e);c(this,{type:u,mode:t,object:n,keys:o(n),index:0})},"Object",function(){for(var e=l(this),t=e.keys;;){if(null===t||e.index>=t.length)return e.object=e.keys=null,{value:void 0,done:!0};var n=t[e.index++],r=e.object;if(a(r,n)){switch(e.mode){case"keys":return{value:n,done:!1};case"values":return{value:r[n],done:!1}}return{value:[n,r[n]],done:!1}}}})},16324(e,t,n){var r=n(86656),i=n(45656),a=n(41318).indexOf,o=n(3501);e.exports=function(e,t){var n,s=i(e),u=0,c=[];for(n in s)!r(o,n)&&r(s,n)&&c.push(n);for(;t.length>u;)r(s,n=t[u++])&&(~a(c,n)||c.push(n));return c}},81956(e,t,n){var r=n(16324),i=n(80748);e.exports=Object.keys||function(e){return r(e,i)}},55296(e,t){"use strict";var n={}.propertyIsEnumerable,r=Object.getOwnPropertyDescriptor,i=r&&!n.call({1:2},1);t.f=i?function(e){var t=r(this,e);return!!t&&t.enumerable}:n},69026(e,t,n){"use strict";var r=n(31913),i=n(17854),a=n(47293),o=n(98008);e.exports=r||!a(function(){if(!o||!(o<535)){var e=Math.random();__defineSetter__.call(null,e,function(){}),delete i[e]}})},27674(e,t,n){var r=n(19670),i=n(96077);e.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var e,t=!1,n={};try{(e=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(n,[]),t=n instanceof Array}catch(a){}return function(n,a){return r(n),i(a),t?e.call(n,a):n.__proto__=a,n}}():void 0)},44699(e,t,n){var r=n(19781),i=n(81956),a=n(45656),o=n(55296).f,s=function(e){return function(t){for(var n,s=a(t),u=i(s),c=u.length,l=0,f=[];c>l;)n=u[l++],(!r||o.call(s,n))&&f.push(e?[n,s[n]]:s[n]);return f}};e.exports={entries:s(!0),values:s(!1)}},90288(e,t,n){"use strict";var r=n(51694),i=n(70648);e.exports=r?({}).toString:function(){return"[object "+i(this)+"]"}},92140(e,t,n){var r=n(70111);e.exports=function(e,t){var n,i;if("string"===t&&"function"==typeof(n=e.toString)&&!r(i=n.call(e))||"function"==typeof(n=e.valueOf)&&!r(i=n.call(e))||"string"!==t&&"function"==typeof(n=e.toString)&&!r(i=n.call(e)))return i;throw TypeError("Can't convert object to primitive value")}},53887(e,t,n){var r=n(35005),i=n(8006),a=n(25181),o=n(19670);e.exports=r("Reflect","ownKeys")||function(e){var t=i.f(o(e)),n=a.f;return n?t.concat(n(e)):t}},40857(e,t,n){var r=n(17854);e.exports=r},12534(e){e.exports=function(e){try{return{error:!1,value:e()}}catch(t){return{error:!0,value:t}}}},69478(e,t,n){var r=n(19670),i=n(70111),a=n(78523);e.exports=function(e,t){if(r(e),i(t)&&t.constructor===e)return t;var n=a.f(e);return(0,n.resolve)(t),n.promise}},12248(e,t,n){var r=n(31320);e.exports=function(e,t,n){for(var i in t)r(e,i,t[i],n);return e}},31320(e,t,n){var r=n(17854),i=n(68880),a=n(86656),o=n(83505),s=n(42788),u=n(29909),c=u.get,l=u.enforce,f=String(String).split("String");(e.exports=function(e,t,n,s){var u,c=!!s&&!!s.unsafe,d=!!s&&!!s.enumerable,h=!!s&&!!s.noTargetGet;if("function"!=typeof n||("string"!=typeof t||a(n,"name")||i(n,"name",t),(u=l(n)).source||(u.source=f.join("string"==typeof t?t:""))),e===r){d?e[t]=n:o(t,n);return}c?!h&&e[t]&&(d=!0):delete e[t],d?e[t]=n:i(e,t,n)})(Function.prototype,"toString",function(){return"function"==typeof this&&c(this).source||s(this)})},38845(e,t,n){var r=n(51532),i=n(4129),a=n(72309)("metadata"),o=a.store||(a.store=new i),s=function(e,t,n){var i=o.get(e);if(!i){if(!n)return;o.set(e,i=new r)}var a=i.get(t);if(!a){if(!n)return;i.set(t,a=new r)}return a},u=function(e,t,n){var r=s(t,n,!1);return void 0!==r&&r.has(e)},c=function(e,t,n){var r=s(t,n,!1);return void 0===r?void 0:r.get(e)},l=function(e,t,n,r){s(n,r,!0).set(e,t)},f=function(e,t){var n=s(e,t,!1),r=[];return n&&n.forEach(function(e,t){r.push(t)}),r},d=function(e){return void 0===e||"symbol"==typeof e?e:String(e)};e.exports={store:o,getMap:s,has:u,get:c,set:l,keys:f,toKey:d}},97651(e,t,n){var r=n(84326),i=n(22261);e.exports=function(e,t){var n=e.exec;if("function"==typeof n){var a=n.call(e,t);if("object"!=typeof a)throw TypeError("RegExp exec method returned something other than an Object or null");return a}if("RegExp"!==r(e))throw TypeError("RegExp#exec called on incompatible receiver");return i.call(e,t)}},22261(e,t,n){"use strict";var r,i,a=n(41340),o=n(67066),s=n(52999),u=n(72309),c=n(70030),l=n(29909).get,f=n(9441),d=n(38173),h=RegExp.prototype.exec,p=u("native-string-replace",String.prototype.replace),b=h,m=(r=/a/,i=/b*/g,h.call(r,"a"),h.call(i,"a"),0!==r.lastIndex||0!==i.lastIndex),g=s.UNSUPPORTED_Y||s.BROKEN_CARET,v=void 0!==/()??/.exec("")[1];(m||v||g||f||d)&&(b=function(e){var t,n,r,i,s,u,f,d=this,y=l(d),w=a(e),_=y.raw;if(_)return _.lastIndex=d.lastIndex,t=b.call(_,w),d.lastIndex=_.lastIndex,t;var E=y.groups,S=g&&d.sticky,k=o.call(d),x=d.source,T=0,M=w;if(S&&(-1===(k=k.replace("y","")).indexOf("g")&&(k+="g"),M=w.slice(d.lastIndex),d.lastIndex>0&&(!d.multiline||d.multiline&&"\n"!==w.charAt(d.lastIndex-1))&&(x="(?: "+x+")",M=" "+M,T++),n=RegExp("^(?:"+x+")",k)),v&&(n=RegExp("^"+x+"$(?!\\s)",k)),m&&(r=d.lastIndex),i=h.call(S?n:d,M),S?i?(i.input=i.input.slice(T),i[0]=i[0].slice(T),i.index=d.lastIndex,d.lastIndex+=i[0].length):d.lastIndex=0:m&&i&&(d.lastIndex=d.global?i.index+i[0].length:r),v&&i&&i.length>1&&p.call(i[0],n,function(){for(s=1;sb)","g");return"b"!==e.exec("b").groups.a||"bc"!=="b".replace(e,"$c")})},84488(e){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},46465(e){e.exports=function(e,t){return e===t||e!=e&&t!=t}},81150(e){e.exports=Object.is||function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}},83505(e,t,n){var r=n(17854);e.exports=function(e,t){try{Object.defineProperty(r,e,{value:t,configurable:!0,writable:!0})}catch(n){r[e]=t}return t}},96340(e,t,n){"use strict";var r=n(35005),i=n(3070),a=n(5112),o=n(19781),s=a("species");e.exports=function(e){var t=r(e),n=i.f;o&&t&&!t[s]&&n(t,s,{configurable:!0,get:function(){return this}})}},58003(e,t,n){var r=n(3070).f,i=n(86656),a=n(5112)("toStringTag");e.exports=function(e,t,n){e&&!i(e=n?e:e.prototype,a)&&r(e,a,{configurable:!0,value:t})}},6200(e,t,n){var r=n(72309),i=n(69711),a=r("keys");e.exports=function(e){return a[e]||(a[e]=i(e))}},5465(e,t,n){var r=n(17854),i=n(83505),a="__core-js_shared__",o=r[a]||i(a,{});e.exports=o},72309(e,t,n){var r=n(31913),i=n(5465);(e.exports=function(e,t){return i[e]||(i[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.17.0",mode:r?"pure":"global",copyright:"\xa9 2021 Denis Pushkarev (zloirock.ru)"})},36707(e,t,n){var r=n(19670),i=n(13099),a=n(5112)("species");e.exports=function(e,t){var n,o=r(e).constructor;return void 0===o||void 0==(n=r(o)[a])?t:i(n)}},43429(e,t,n){var r=n(47293);e.exports=function(e){return r(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3})}},28710(e,t,n){var r=n(99958),i=n(41340),a=n(84488),o=function(e){return function(t,n){var o,s,u=i(a(t)),c=r(n),l=u.length;return c<0||c>=l?e?"":void 0:(o=u.charCodeAt(c))<55296||o>56319||c+1===l||(s=u.charCodeAt(c+1))<56320||s>57343?e?u.charAt(c):o:e?u.slice(c,c+2):(o-55296<<10)+(s-56320)+65536}};e.exports={codeAt:o(!1),charAt:o(!0)}},54986(e,t,n){var r=n(88113);e.exports=/Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(r)},76650(e,t,n){var r=n(17466),i=n(41340),a=n(38415),o=n(84488),s=Math.ceil,u=function(e){return function(t,n,u){var c,l,f=i(o(t)),d=f.length,h=void 0===u?" ":i(u),p=r(n);return p<=d||""==h?f:(c=p-d,(l=a.call(h,s(c/h.length))).length>c&&(l=l.slice(0,c)),e?f+l:l+f)}};e.exports={start:u(!1),end:u(!0)}},33197(e){"use strict";var t=2147483647,n=36,r=1,i=26,a=38,o=700,s=72,u=128,c="-",l=/[^\0-\u007E]/,f=/[.\u3002\uFF0E\uFF61]/g,d="Overflow: input needs wider integers to process",h=n-r,p=Math.floor,b=String.fromCharCode,m=function(e){for(var t=[],n=0,r=e.length;n=55296&&i<=56319&&n>1,e+=p(e/t);e>h*i>>1;s+=n)e=p(e/h);return p(s+(h+1)*e/(e+a))},y=function(e){var a,o,l=[],f=(e=m(e)).length,h=u,y=0,w=s;for(a=0;a=h&&op((t-y)/k))throw RangeError(d);for(y+=(S-h)*k,h=S,a=0;at)throw RangeError(d);if(o==h){for(var x=y,T=n;;T+=n){var M=T<=w?r:T>=w+i?i:T-w;if(x0;(o>>>=1)&&(t+=t))1&o&&(n+=t);return n}},76091(e,t,n){var r=n(47293),i=n(81361),a="​\x85᠎";e.exports=function(e){return r(function(){return!!i[e]()||a[e]()!=a||i[e].name!==e})}},53111(e,t,n){var r=n(84488),i=n(41340),a="["+n(81361)+"]",o=RegExp("^"+a+a+"*"),s=RegExp(a+a+"*$"),u=function(e){return function(t){var n=i(r(t));return 1&e&&(n=n.replace(o,"")),2&e&&(n=n.replace(s,"")),n}};e.exports={start:u(1),end:u(2),trim:u(3)}},20261(e,t,n){var r,i,a,o,s=n(17854),u=n(47293),c=n(49974),l=n(60490),f=n(80317),d=n(6833),h=n(35268),p=s.setImmediate,b=s.clearImmediate,m=s.process,g=s.MessageChannel,v=s.Dispatch,y=0,w={},_="onreadystatechange";try{r=s.location}catch(E){}var S=function(e){if(w.hasOwnProperty(e)){var t=w[e];delete w[e],t()}},k=function(e){return function(){S(e)}},x=function(e){S(e.data)},T=function(e){s.postMessage(String(e),r.protocol+"//"+r.host)};p&&b||(p=function(e){for(var t=[],n=arguments.length,r=1;n>r;)t.push(arguments[r++]);return w[++y]=function(){("function"==typeof e?e:Function(e)).apply(void 0,t)},i(y),y},b=function(e){delete w[e]},h?i=function(e){m.nextTick(k(e))}:v&&v.now?i=function(e){v.now(k(e))}:g&&!d?(o=(a=new g).port2,a.port1.onmessage=x,i=c(o.postMessage,o,1)):s.addEventListener&&"function"==typeof postMessage&&!s.importScripts&&r&&"file:"!==r.protocol&&!u(T)?(i=T,s.addEventListener("message",x,!1)):i=_ in f("script")?function(e){l.appendChild(f("script"))[_]=function(){l.removeChild(this),S(e)}}:function(e){setTimeout(k(e),0)}),e.exports={set:p,clear:b}},50863(e,t,n){var r=n(84326);e.exports=function(e){if("number"!=typeof e&&"Number"!=r(e))throw TypeError("Incorrect invocation");return+e}},51400(e,t,n){var r=n(99958),i=Math.max,a=Math.min;e.exports=function(e,t){var n=r(e);return n<0?i(n+t,0):a(n,t)}},57067(e,t,n){var r=n(99958),i=n(17466);e.exports=function(e){if(void 0===e)return 0;var t=r(e),n=i(t);if(t!==n)throw RangeError("Wrong length or index");return n}},45656(e,t,n){var r=n(68361),i=n(84488);e.exports=function(e){return r(i(e))}},99958(e){var t=Math.ceil,n=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?n:t)(e)}},17466(e,t,n){var r=n(99958),i=Math.min;e.exports=function(e){return e>0?i(r(e),9007199254740991):0}},47908(e,t,n){var r=n(84488);e.exports=function(e){return Object(r(e))}},84590(e,t,n){var r=n(73002);e.exports=function(e,t){var n=r(e);if(n%t)throw RangeError("Wrong offset");return n}},73002(e,t,n){var r=n(99958);e.exports=function(e){var t=r(e);if(t<0)throw RangeError("The argument can't be less than 0");return t}},57593(e,t,n){var r=n(70111),i=n(52190),a=n(92140),o=n(5112)("toPrimitive");e.exports=function(e,t){if(!r(e)||i(e))return e;var n,s=e[o];if(void 0!==s){if(void 0===t&&(t="default"),!r(n=s.call(e,t))||i(n))return n;throw TypeError("Can't convert object to primitive value")}return void 0===t&&(t="number"),a(e,t)}},34948(e,t,n){var r=n(57593),i=n(52190);e.exports=function(e){var t=r(e,"string");return i(t)?t:String(t)}},51694(e,t,n){var r=n(5112)("toStringTag"),i={};i[r]="z",e.exports="[object z]"===String(i)},41340(e,t,n){var r=n(52190);e.exports=function(e){if(r(e))throw TypeError("Cannot convert a Symbol value to a string");return String(e)}},19843(e,t,n){"use strict";var r=n(82109),i=n(17854),a=n(19781),o=n(63832),s=n(90260),u=n(13331),c=n(25787),l=n(79114),f=n(68880),d=n(18730),h=n(17466),p=n(57067),b=n(84590),m=n(34948),g=n(86656),v=n(70648),y=n(70111),w=n(52190),_=n(70030),E=n(27674),S=n(8006).f,k=n(97321),x=n(42092).forEach,T=n(96340),M=n(3070),O=n(31236),A=n(29909),L=n(79587),C=A.get,I=A.set,D=M.f,N=O.f,P=Math.round,R=i.RangeError,j=u.ArrayBuffer,F=u.DataView,Y=s.NATIVE_ARRAY_BUFFER_VIEWS,B=s.TYPED_ARRAY_CONSTRUCTOR,U=s.TYPED_ARRAY_TAG,H=s.TypedArray,$=s.TypedArrayPrototype,z=s.aTypedArrayConstructor,G=s.isTypedArray,W="BYTES_PER_ELEMENT",K="Wrong length",V=function(e,t){for(var n=0,r=t.length,i=new(z(e))(r);r>n;)i[n]=t[n++];return i},q=function(e,t){D(e,t,{get:function(){return C(this)[t]}})},Z=function(e){var t;return e instanceof j||"ArrayBuffer"==(t=v(e))||"SharedArrayBuffer"==t},X=function(e,t){return G(e)&&!w(t)&&t in e&&d(+t)&&t>=0},J=function(e,t){return t=m(t),X(e,t)?l(2,e[t]):N(e,t)},Q=function(e,t,n){return(t=m(t),X(e,t)&&y(n)&&g(n,"value")&&!g(n,"get")&&!g(n,"set")&&!n.configurable&&(!g(n,"writable")||n.writable)&&(!g(n,"enumerable")||n.enumerable))?(e[t]=n.value,e):D(e,t,n)};a?(Y||(O.f=J,M.f=Q,q($,"buffer"),q($,"byteOffset"),q($,"byteLength"),q($,"length")),r({target:"Object",stat:!0,forced:!Y},{getOwnPropertyDescriptor:J,defineProperty:Q}),e.exports=function(e,t,n){var a=e.match(/\d+$/)[0]/8,s=e+(n?"Clamped":"")+"Array",u="get"+e,l="set"+e,d=i[s],m=d,g=m&&m.prototype,v={},w=function(e,t){var n=C(e);return n.view[u](t*a+n.byteOffset,!0)},M=function(e,t,r){var i=C(e);n&&(r=(r=P(r))<0?0:r>255?255:255&r),i.view[l](t*a+i.byteOffset,r,!0)},O=function(e,t){D(e,t,{get:function(){return w(this,t)},set:function(e){return M(this,t,e)},enumerable:!0})};Y?o&&(m=t(function(e,t,n,r){return c(e,m,s),L(y(t)?Z(t)?void 0!==r?new d(t,b(n,a),r):void 0!==n?new d(t,b(n,a)):new d(t):G(t)?V(m,t):k.call(m,t):new d(p(t)),e,m)}),E&&E(m,H),x(S(d),function(e){e in m||f(m,e,d[e])}),m.prototype=g):(m=t(function(e,t,n,r){c(e,m,s);var i,o,u,l=0,f=0;if(y(t)){if(Z(t)){i=t,f=b(n,a);var d=t.byteLength;if(void 0===r){if(d%a||(o=d-f)<0)throw R(K)}else if((o=h(r)*a)+f>d)throw R(K);u=o/a}else if(G(t))return V(m,t);else return k.call(m,t)}else o=(u=p(t))*a,i=new j(o);for(I(e,{buffer:i,byteOffset:f,byteLength:o,length:u,view:new F(i)});l1?arguments[1]:void 0,g=void 0!==m,v=o(p);if(void 0!=v&&!s(v))for(h=(d=a(p,v)).next,p=[];!(f=h.call(d)).done;)p.push(f.value);for(g&&b>2&&(m=u(m,arguments[2],2)),n=i(p.length),l=new(c(this))(n),t=0;n>t;t++)l[t]=g?m(p[t],t):p[t];return l}},66304(e,t,n){var r=n(90260),i=n(36707),a=r.TYPED_ARRAY_CONSTRUCTOR,o=r.aTypedArrayConstructor;e.exports=function(e){return o(i(e,e[a]))}},69711(e){var t=0,n=Math.random();e.exports=function(e){return"Symbol("+String(void 0===e?"":e)+")_"+(++t+n).toString(36)}},43307(e,t,n){var r=n(30133);e.exports=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},6061(e,t,n){var r=n(5112);t.f=r},5112(e,t,n){var r=n(17854),i=n(72309),a=n(86656),o=n(69711),s=n(30133),u=n(43307),c=i("wks"),l=r.Symbol,f=u?l:l&&l.withoutSetter||o;e.exports=function(e){return a(c,e)&&(s||"string"==typeof c[e])||(s&&a(l,e)?c[e]=l[e]:c[e]=f("Symbol."+e)),c[e]}},81361(e){e.exports=" \n\v\f\r \xa0               \u2028\u2029\uFEFF"},9170(e,t,n){"use strict";var r=n(82109),i=n(79518),a=n(27674),o=n(70030),s=n(68880),u=n(79114),c=n(20408),l=n(41340),f=function(e,t){var n=this;if(!(n instanceof f))return new f(e,t);a&&(n=a(Error(void 0),i(n))),void 0!==t&&s(n,"message",l(t));var r=[];return c(e,r.push,{that:r}),s(n,"errors",r),n};f.prototype=o(Error.prototype,{constructor:u(5,f),message:u(5,""),name:u(5,"AggregateError")}),r({global:!0},{AggregateError:f})},18264(e,t,n){"use strict";var r=n(82109),i=n(17854),a=n(13331),o=n(96340),s="ArrayBuffer",u=a[s];r({global:!0,forced:i[s]!==u},{ArrayBuffer:u}),o(s)},76938(e,t,n){var r=n(82109),i=n(90260);r({target:"ArrayBuffer",stat:!0,forced:!i.NATIVE_ARRAY_BUFFER_VIEWS},{isView:i.isView})},39575(e,t,n){"use strict";var r=n(82109),i=n(47293),a=n(13331),o=n(19670),s=n(51400),u=n(17466),c=n(36707),l=a.ArrayBuffer,f=a.DataView,d=l.prototype.slice,h=i(function(){return!new l(2).slice(1,void 0).byteLength});r({target:"ArrayBuffer",proto:!0,unsafe:!0,forced:h},{slice:function(e,t){if(void 0!==d&&void 0===t)return d.call(o(this),e);for(var n=o(this).byteLength,r=s(e,n),i=s(void 0===t?n:t,n),a=new(c(this,l))(u(i-r)),h=new f(this),p=new f(a),b=0;r=0?r:n+r;return s<0||s>=n?void 0:t[s]}}),s("at")},92222(e,t,n){"use strict";var r=n(82109),i=n(47293),a=n(43157),o=n(70111),s=n(47908),u=n(17466),c=n(86135),l=n(65417),f=n(81194),d=n(5112),h=n(7392),p=d("isConcatSpreadable"),b=9007199254740991,m="Maximum allowed index exceeded",g=h>=51||!i(function(){var e=[];return e[p]=!1,e.concat()[0]!==e}),v=f("concat"),y=function(e){if(!o(e))return!1;var t=e[p];return void 0!==t?!!t:a(e)};r({target:"Array",proto:!0,forced:!g||!v},{concat:function(e){var t,n,r,i,a,o=s(this),f=l(o,0),d=0;for(t=-1,r=arguments.length;tb)throw TypeError(m);for(n=0;n=b)throw TypeError(m);c(f,d++,a)}return f.length=d,f}})},50545(e,t,n){var r=n(82109),i=n(1048),a=n(51223);r({target:"Array",proto:!0},{copyWithin:i}),a("copyWithin")},26541(e,t,n){"use strict";var r=n(82109),i=n(42092).every,a=n(9341)("every");r({target:"Array",proto:!0,forced:!a},{every:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}})},43290(e,t,n){var r=n(82109),i=n(21285),a=n(51223);r({target:"Array",proto:!0},{fill:i}),a("fill")},57327(e,t,n){"use strict";var r=n(82109),i=n(42092).filter,a=n(81194)("filter");r({target:"Array",proto:!0,forced:!a},{filter:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}})},34553(e,t,n){"use strict";var r=n(82109),i=n(42092).findIndex,a=n(51223),o="findIndex",s=!0;o in[]&&[,][o](function(){s=!1}),r({target:"Array",proto:!0,forced:s},{findIndex:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}}),a(o)},69826(e,t,n){"use strict";var r=n(82109),i=n(42092).find,a=n(51223),o="find",s=!0;o in[]&&[,][o](function(){s=!1}),r({target:"Array",proto:!0,forced:s},{find:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}}),a(o)},86535(e,t,n){"use strict";var r=n(82109),i=n(6790),a=n(47908),o=n(17466),s=n(13099),u=n(65417);r({target:"Array",proto:!0},{flatMap:function(e){var t,n=a(this),r=o(n.length);return s(e),(t=u(n,0)).length=i(t,n,n,r,0,1,e,arguments.length>1?arguments[1]:void 0),t}})},84944(e,t,n){"use strict";var r=n(82109),i=n(6790),a=n(47908),o=n(17466),s=n(99958),u=n(65417);r({target:"Array",proto:!0},{flat:function(){var e=arguments.length?arguments[0]:void 0,t=a(this),n=o(t.length),r=u(t,0);return r.length=i(r,t,t,n,0,void 0===e?1:s(e)),r}})},89554(e,t,n){"use strict";var r=n(82109),i=n(18533);r({target:"Array",proto:!0,forced:[].forEach!=i},{forEach:i})},91038(e,t,n){var r=n(82109),i=n(48457),a=!n(17072)(function(e){Array.from(e)});r({target:"Array",stat:!0,forced:a},{from:i})},26699(e,t,n){"use strict";var r=n(82109),i=n(41318).includes,a=n(51223);r({target:"Array",proto:!0},{includes:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}}),a("includes")},82772(e,t,n){"use strict";var r=n(82109),i=n(41318).indexOf,a=n(9341),o=[].indexOf,s=!!o&&1/[1].indexOf(1,-0)<0,u=a("indexOf");r({target:"Array",proto:!0,forced:s||!u},{indexOf:function(e){return s?o.apply(this,arguments)||0:i(this,e,arguments.length>1?arguments[1]:void 0)}})},79753(e,t,n){var r=n(82109),i=n(43157);r({target:"Array",stat:!0},{isArray:i})},66992(e,t,n){"use strict";var r=n(45656),i=n(51223),a=n(97497),o=n(29909),s=n(70654),u="Array Iterator",c=o.set,l=o.getterFor(u);e.exports=s(Array,"Array",function(e,t){c(this,{type:u,target:r(e),index:0,kind:t})},function(){var e=l(this),t=e.target,n=e.kind,r=e.index++;return!t||r>=t.length?(e.target=void 0,{value:void 0,done:!0}):"keys"==n?{value:r,done:!1}:"values"==n?{value:t[r],done:!1}:{value:[r,t[r]],done:!1}},"values"),a.Arguments=a.Array,i("keys"),i("values"),i("entries")},69600(e,t,n){"use strict";var r=n(82109),i=n(68361),a=n(45656),o=n(9341),s=[].join,u=i!=Object,c=o("join",",");r({target:"Array",proto:!0,forced:u||!c},{join:function(e){return s.call(a(this),void 0===e?",":e)}})},94986(e,t,n){var r=n(82109),i=n(86583);r({target:"Array",proto:!0,forced:i!==[].lastIndexOf},{lastIndexOf:i})},21249(e,t,n){"use strict";var r=n(82109),i=n(42092).map,a=n(81194)("map");r({target:"Array",proto:!0,forced:!a},{map:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}})},26572(e,t,n){"use strict";var r=n(82109),i=n(47293),a=n(86135),o=i(function(){function e(){}return!(Array.of.call(e) instanceof e)});r({target:"Array",stat:!0,forced:o},{of:function(){for(var e=0,t=arguments.length,n=new("function"==typeof this?this:Array)(t);t>e;)a(n,e,arguments[e++]);return n.length=t,n}})},96644(e,t,n){"use strict";var r=n(82109),i=n(53671).right,a=n(9341),o=n(7392),s=n(35268),u=a("reduceRight"),c=!s&&o>79&&o<83;r({target:"Array",proto:!0,forced:!u||c},{reduceRight:function(e){return i(this,e,arguments.length,arguments.length>1?arguments[1]:void 0)}})},85827(e,t,n){"use strict";var r=n(82109),i=n(53671).left,a=n(9341),o=n(7392),s=n(35268),u=a("reduce"),c=!s&&o>79&&o<83;r({target:"Array",proto:!0,forced:!u||c},{reduce:function(e){return i(this,e,arguments.length,arguments.length>1?arguments[1]:void 0)}})},65069(e,t,n){"use strict";var r=n(82109),i=n(43157),a=[].reverse,o=[1,2];r({target:"Array",proto:!0,forced:String(o)===String(o.reverse())},{reverse:function(){return i(this)&&(this.length=this.length),a.call(this)}})},47042(e,t,n){"use strict";var r=n(82109),i=n(70111),a=n(43157),o=n(51400),s=n(17466),u=n(45656),c=n(86135),l=n(5112),f=n(81194)("slice"),d=l("species"),h=[].slice,p=Math.max;r({target:"Array",proto:!0,forced:!f},{slice:function(e,t){var n,r,l,f=u(this),b=s(f.length),m=o(e,b),g=o(void 0===t?b:t,b);if(a(f)&&("function"==typeof(n=f.constructor)&&(n===Array||a(n.prototype))?n=void 0:i(n)&&null===(n=n[d])&&(n=void 0),n===Array||void 0===n))return h.call(f,m,g);for(l=0,r=new(void 0===n?Array:n)(p(g-m,0));m1?arguments[1]:void 0)}})},2707(e,t,n){"use strict";var r=n(82109),i=n(13099),a=n(47908),o=n(17466),s=n(41340),u=n(47293),c=n(94362),l=n(9341),f=n(68886),d=n(30256),h=n(7392),p=n(98008),b=[],m=b.sort,g=u(function(){b.sort(void 0)}),v=u(function(){b.sort(null)}),y=l("sort"),w=!u(function(){if(h)return h<70;if(!f||!(f>3)){if(d)return!0;if(p)return p<603;var e,t,n,r,i="";for(e=65;e<76;e++){switch(t=String.fromCharCode(e),e){case 66:case 69:case 70:case 72:n=3;break;case 68:case 71:n=4;break;default:n=2}for(r=0;r<47;r++)b.push({k:t+r,v:n})}for(b.sort(function(e,t){return t.v-e.v}),r=0;rs(n)?1:-1}};r({target:"Array",proto:!0,forced:_},{sort:function(e){void 0!==e&&i(e);var t,n,r=a(this);if(w)return void 0===e?m.call(r):m.call(r,e);var s=[],u=o(r.length);for(n=0;nh)throw TypeError(p);for(b=0,l=u(v,r);by-r+n;b--)delete v[b-1]}else if(n>r)for(b=y-r;b>w;b--)m=b+r-1,g=b+n-1,m in v?v[g]=v[m]:delete v[g];for(b=0;b94906265.62425156?s(e)+c:a(e-1+u(e-1)*u(e+1))}})},82376(e,t,n){var r=n(82109),i=Math.asinh,a=Math.log,o=Math.sqrt;function s(e){return isFinite(e=+e)&&0!=e?e<0?-s(-e):a(e+o(e*e+1)):e}r({target:"Math",stat:!0,forced:!(i&&1/i(0)>0)},{asinh:s})},73181(e,t,n){var r=n(82109),i=Math.atanh,a=Math.log;r({target:"Math",stat:!0,forced:!(i&&1/i(-0)<0)},{atanh:function(e){return 0==(e=+e)?e:a((1+e)/(1-e))/2}})},23484(e,t,n){var r=n(82109),i=n(64310),a=Math.abs,o=Math.pow;r({target:"Math",stat:!0},{cbrt:function(e){return i(e=+e)*o(a(e),1/3)}})},2388(e,t,n){var r=n(82109),i=Math.floor,a=Math.log,o=Math.LOG2E;r({target:"Math",stat:!0},{clz32:function(e){return(e>>>=0)?31-i(a(e+.5)*o):32}})},88621(e,t,n){var r=n(82109),i=n(66736),a=Math.cosh,o=Math.abs,s=Math.E;r({target:"Math",stat:!0,forced:!a||a(710)===1/0},{cosh:function(e){var t=i(o(e)-1)+1;return(t+1/(t*s*s))*(s/2)}})},60403(e,t,n){var r=n(82109),i=n(66736);r({target:"Math",stat:!0,forced:i!=Math.expm1},{expm1:i})},84755(e,t,n){var r=n(82109),i=n(26130);r({target:"Math",stat:!0},{fround:i})},25438(e,t,n){var r=n(82109),i=Math.hypot,a=Math.abs,o=Math.sqrt,s=!!i&&i(1/0,NaN)!==1/0;r({target:"Math",stat:!0,forced:s},{hypot:function(e,t){for(var n,r,i=0,s=0,u=arguments.length,c=0;s0?i+=(r=n/c)*r:i+=n;return c===1/0?1/0:c*o(i)}})},90332(e,t,n){var r=n(82109),i=n(47293),a=Math.imul,o=i(function(){return -5!=a(4294967295,5)||2!=a.length});r({target:"Math",stat:!0,forced:o},{imul:function(e,t){var n=65535,r=+e,i=+t,a=n&r,o=n&i;return 0|a*o+((n&r>>>16)*o+a*(n&i>>>16)<<16>>>0)}})},40658(e,t,n){var r=n(82109),i=Math.log,a=Math.LOG10E;r({target:"Math",stat:!0},{log10:function(e){return i(e)*a}})},40197(e,t,n){var r=n(82109),i=n(26513);r({target:"Math",stat:!0},{log1p:i})},44914(e,t,n){var r=n(82109),i=Math.log,a=Math.LN2;r({target:"Math",stat:!0},{log2:function(e){return i(e)/a}})},52420(e,t,n){var r=n(82109),i=n(64310);r({target:"Math",stat:!0},{sign:i})},60160(e,t,n){var r=n(82109),i=n(47293),a=n(66736),o=Math.abs,s=Math.exp,u=Math.E,c=i(function(){return -.00000000000000002!=Math.sinh(-.00000000000000002)});r({target:"Math",stat:!0,forced:c},{sinh:function(e){return 1>o(e=+e)?(a(e)-a(-e))/2:(s(e-1)-s(-e-1))*(u/2)}})},60970(e,t,n){var r=n(82109),i=n(66736),a=Math.exp;r({target:"Math",stat:!0},{tanh:function(e){var t=i(e=+e),n=i(-e);return t==1/0?1:n==1/0?-1:(t-n)/(a(e)+a(-e))}})},10408(e,t,n){n(58003)(Math,"Math",!0)},73689(e,t,n){var r=n(82109),i=Math.ceil,a=Math.floor;r({target:"Math",stat:!0},{trunc:function(e){return(e>0?a:i)(e)}})},9653(e,t,n){"use strict";var r=n(19781),i=n(17854),a=n(54705),o=n(31320),s=n(86656),u=n(84326),c=n(79587),l=n(52190),f=n(57593),d=n(47293),h=n(70030),p=n(8006).f,b=n(31236).f,m=n(3070).f,g=n(53111).trim,v="Number",y=i[v],w=y.prototype,_=u(h(w))==v,E=function(e){if(l(e))throw TypeError("Cannot convert a Symbol value to a number");var t,n,r,i,a,o,s,u,c=f(e,"number");if("string"==typeof c&&c.length>2){if(43===(t=(c=g(c)).charCodeAt(0))||45===t){if(88===(n=c.charCodeAt(2))||120===n)return NaN}else if(48===t){switch(c.charCodeAt(1)){case 66:case 98:r=2,i=49;break;case 79:case 111:r=8,i=55;break;default:return+c}for(s=0,o=(a=c.slice(2)).length;si)return NaN;return parseInt(a,r)}}return+c};if(a(v,!y(" 0o1")||!y("0b1")||y("+0x1"))){for(var S,k=function(e){var t=arguments.length<1?0:e,n=this;return n instanceof k&&(_?d(function(){w.valueOf.call(n)}):u(n)!=v)?c(new y(E(t)),n,k):E(t)},x=r?p(y):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,fromString,range".split(","),T=0;x.length>T;T++)s(y,S=x[T])&&!s(k,S)&&m(k,S,b(y,S));k.prototype=w,w.constructor=k,o(i,v,k)}},93299(e,t,n){n(82109)({target:"Number",stat:!0},{EPSILON:2220446049250313e-31})},35192(e,t,n){var r=n(82109),i=n(77023);r({target:"Number",stat:!0},{isFinite:i})},33161(e,t,n){var r=n(82109),i=n(18730);r({target:"Number",stat:!0},{isInteger:i})},44048(e,t,n){n(82109)({target:"Number",stat:!0},{isNaN:function(e){return e!=e}})},78285(e,t,n){var r=n(82109),i=n(18730),a=Math.abs;r({target:"Number",stat:!0},{isSafeInteger:function(e){return i(e)&&9007199254740991>=a(e)}})},44363(e,t,n){n(82109)({target:"Number",stat:!0},{MAX_SAFE_INTEGER:9007199254740991})},55994(e,t,n){n(82109)({target:"Number",stat:!0},{MIN_SAFE_INTEGER:-9007199254740991})},61874(e,t,n){var r=n(82109),i=n(2814);r({target:"Number",stat:!0,forced:Number.parseFloat!=i},{parseFloat:i})},9494(e,t,n){var r=n(82109),i=n(83009);r({target:"Number",stat:!0,forced:Number.parseInt!=i},{parseInt:i})},56977(e,t,n){"use strict";var r=n(82109),i=n(99958),a=n(50863),o=n(38415),s=n(47293),u=1..toFixed,c=Math.floor,l=function(e,t,n){return 0===t?n:t%2==1?l(e,t-1,n*e):l(e*e,t/2,n)},f=function(e){for(var t=0,n=e;n>=4096;)t+=12,n/=4096;for(;n>=2;)t+=1,n/=2;return t},d=function(e,t,n){for(var r=-1,i=n;++r<6;)i+=t*e[r],e[r]=i%1e7,i=c(i/1e7)},h=function(e,t){for(var n=6,r=0;--n>=0;)r+=e[n],e[n]=c(r/t),r=r%t*1e7},p=function(e){for(var t=6,n="";--t>=0;)if(""!==n||0===t||0!==e[t]){var r=String(e[t]);n=""===n?r:n+o.call("0",7-r.length)+r}return n},b=!!u||!s(function(){u.call({})});r({target:"Number",proto:!0,forced:b},{toFixed:function(e){var t,n,r,s,u=a(this),c=i(e),b=[0,0,0,0,0,0],m="",g="0";if(c<0||c>20)throw RangeError("Incorrect fraction digits");if(u!=u)return"NaN";if(u<=-1e21||u>=1e21)return String(u);if(u<0&&(m="-",u=-u),u>1e-21){if(n=(t=f(u*l(2,69,1))-69)<0?u*l(2,-t,1):u/l(2,t,1),n*=4503599627370496,(t=52-t)>0){for(d(b,0,n),r=c;r>=7;)d(b,1e7,0),r-=7;for(d(b,l(10,r,1),0),r=t-1;r>=23;)h(b,8388608),r-=23;h(b,1<0?m+((s=g.length)<=c?"0."+o.call("0",c-s)+g:g.slice(0,s-c)+"."+g.slice(s-c)):m+g}})},55147(e,t,n){"use strict";var r=n(82109),i=n(47293),a=n(50863),o=1..toPrecision,s=i(function(){return"1"!==o.call(1,void 0)})||!i(function(){o.call({})});r({target:"Number",proto:!0,forced:s},{toPrecision:function(e){return void 0===e?o.call(a(this)):o.call(a(this),e)}})},19601(e,t,n){var r=n(82109),i=n(21574);r({target:"Object",stat:!0,forced:Object.assign!==i},{assign:i})},78011(e,t,n){var r=n(82109),i=n(19781),a=n(70030);r({target:"Object",stat:!0,sham:!i},{create:a})},59595(e,t,n){"use strict";var r=n(82109),i=n(19781),a=n(69026),o=n(47908),s=n(13099),u=n(3070);i&&r({target:"Object",proto:!0,forced:a},{__defineGetter__:function(e,t){u.f(o(this),e,{get:s(t),enumerable:!0,configurable:!0})}})},33321(e,t,n){var r=n(82109),i=n(19781),a=n(36048);r({target:"Object",stat:!0,forced:!i,sham:!i},{defineProperties:a})},69070(e,t,n){var r=n(82109),i=n(19781),a=n(3070);r({target:"Object",stat:!0,forced:!i,sham:!i},{defineProperty:a.f})},35500(e,t,n){"use strict";var r=n(82109),i=n(19781),a=n(69026),o=n(47908),s=n(13099),u=n(3070);i&&r({target:"Object",proto:!0,forced:a},{__defineSetter__:function(e,t){u.f(o(this),e,{set:s(t),enumerable:!0,configurable:!0})}})},69720(e,t,n){var r=n(82109),i=n(44699).entries;r({target:"Object",stat:!0},{entries:function(e){return i(e)}})},43371(e,t,n){var r=n(82109),i=n(76677),a=n(47293),o=n(70111),s=n(62423).onFreeze,u=Object.freeze,c=a(function(){u(1)});r({target:"Object",stat:!0,forced:c,sham:!i},{freeze:function(e){return u&&o(e)?u(s(e)):e}})},38559(e,t,n){var r=n(82109),i=n(20408),a=n(86135);r({target:"Object",stat:!0},{fromEntries:function(e){var t={};return i(e,function(e,n){a(t,e,n)},{AS_ENTRIES:!0}),t}})},38880(e,t,n){var r=n(82109),i=n(47293),a=n(45656),o=n(31236).f,s=n(19781),u=i(function(){o(1)}),c=!s||u;r({target:"Object",stat:!0,forced:c,sham:!s},{getOwnPropertyDescriptor:function(e,t){return o(a(e),t)}})},49337(e,t,n){var r=n(82109),i=n(19781),a=n(53887),o=n(45656),s=n(31236),u=n(86135);r({target:"Object",stat:!0,sham:!i},{getOwnPropertyDescriptors:function(e){for(var t,n,r=o(e),i=s.f,c=a(r),l={},f=0;c.length>f;)void 0!==(n=i(r,t=c[f++]))&&u(l,t,n);return l}})},36210(e,t,n){var r=n(82109),i=n(47293),a=n(1156).f,o=i(function(){return!Object.getOwnPropertyNames(1)});r({target:"Object",stat:!0,forced:o},{getOwnPropertyNames:a})},30489(e,t,n){var r=n(82109),i=n(47293),a=n(47908),o=n(79518),s=n(49920),u=i(function(){o(1)});r({target:"Object",stat:!0,forced:u,sham:!s},{getPrototypeOf:function(e){return o(a(e))}})},46314(e,t,n){var r=n(82109),i=n(86656);r({target:"Object",stat:!0},{hasOwn:i})},41825(e,t,n){var r=n(82109),i=n(47293),a=n(70111),o=Object.isExtensible,s=i(function(){o(1)});r({target:"Object",stat:!0,forced:s},{isExtensible:function(e){return!!a(e)&&(!o||o(e))}})},98410(e,t,n){var r=n(82109),i=n(47293),a=n(70111),o=Object.isFrozen,s=i(function(){o(1)});r({target:"Object",stat:!0,forced:s},{isFrozen:function(e){return!a(e)||!!o&&o(e)}})},72200(e,t,n){var r=n(82109),i=n(47293),a=n(70111),o=Object.isSealed,s=i(function(){o(1)});r({target:"Object",stat:!0,forced:s},{isSealed:function(e){return!a(e)||!!o&&o(e)}})},43304(e,t,n){var r=n(82109),i=n(81150);r({target:"Object",stat:!0},{is:i})},47941(e,t,n){var r=n(82109),i=n(47908),a=n(81956),o=n(47293)(function(){a(1)});r({target:"Object",stat:!0,forced:o},{keys:function(e){return a(i(e))}})},94869(e,t,n){"use strict";var r=n(82109),i=n(19781),a=n(69026),o=n(47908),s=n(34948),u=n(79518),c=n(31236).f;i&&r({target:"Object",proto:!0,forced:a},{__lookupGetter__:function(e){var t,n=o(this),r=s(e);do if(t=c(n,r))return t.get;while(n=u(n))}})},33952(e,t,n){"use strict";var r=n(82109),i=n(19781),a=n(69026),o=n(47908),s=n(34948),u=n(79518),c=n(31236).f;i&&r({target:"Object",proto:!0,forced:a},{__lookupSetter__:function(e){var t,n=o(this),r=s(e);do if(t=c(n,r))return t.set;while(n=u(n))}})},57227(e,t,n){var r=n(82109),i=n(70111),a=n(62423).onFreeze,o=n(76677),s=n(47293),u=Object.preventExtensions,c=s(function(){u(1)});r({target:"Object",stat:!0,forced:c,sham:!o},{preventExtensions:function(e){return u&&i(e)?u(a(e)):e}})},60514(e,t,n){var r=n(82109),i=n(70111),a=n(62423).onFreeze,o=n(76677),s=n(47293),u=Object.seal,c=s(function(){u(1)});r({target:"Object",stat:!0,forced:c,sham:!o},{seal:function(e){return u&&i(e)?u(a(e)):e}})},68304(e,t,n){var r=n(82109),i=n(27674);r({target:"Object",stat:!0},{setPrototypeOf:i})},41539(e,t,n){var r=n(51694),i=n(31320),a=n(90288);r||i(Object.prototype,"toString",a,{unsafe:!0})},26833(e,t,n){var r=n(82109),i=n(44699).values;r({target:"Object",stat:!0},{values:function(e){return i(e)}})},54678(e,t,n){var r=n(82109),i=n(2814);r({global:!0,forced:parseFloat!=i},{parseFloat:i})},91058(e,t,n){var r=n(82109),i=n(83009);r({global:!0,forced:parseInt!=i},{parseInt:i})},17922(e,t,n){"use strict";var r=n(82109),i=n(13099),a=n(78523),o=n(12534),s=n(20408);r({target:"Promise",stat:!0},{allSettled:function(e){var t=this,n=a.f(t),r=n.resolve,u=n.reject,c=o(function(){var n=i(t.resolve),a=[],o=0,u=1;s(e,function(e){var i=o++,s=!1;a.push(void 0),u++,n.call(t,e).then(function(e){!s&&(s=!0,a[i]={status:"fulfilled",value:e},--u||r(a))},function(e){!s&&(s=!0,a[i]={status:"rejected",reason:e},--u||r(a))})}),--u||r(a)});return c.error&&u(c.value),n.promise}})},34668(e,t,n){"use strict";var r=n(82109),i=n(13099),a=n(35005),o=n(78523),s=n(12534),u=n(20408),c="No one promise resolved";r({target:"Promise",stat:!0},{any:function(e){var t=this,n=o.f(t),r=n.resolve,l=n.reject,f=s(function(){var n=i(t.resolve),o=[],s=0,f=1,d=!1;u(e,function(e){var i=s++,u=!1;o.push(void 0),f++,n.call(t,e).then(function(e){u||d||(d=!0,r(e))},function(e){!u&&!d&&(u=!0,o[i]=e,--f||l(new(a("AggregateError"))(o,c)))})}),--f||l(new(a("AggregateError"))(o,c))});return f.error&&l(f.value),n.promise}})},17727(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(13366),o=n(47293),s=n(35005),u=n(36707),c=n(69478),l=n(31320),f=!!a&&o(function(){a.prototype.finally.call({then:function(){}},function(){})});if(r({target:"Promise",proto:!0,real:!0,forced:f},{finally:function(e){var t=u(this,s("Promise")),n="function"==typeof e;return this.then(n?function(n){return c(t,e()).then(function(){return n})}:e,n?function(n){return c(t,e()).then(function(){throw n})}:e)}}),!i&&"function"==typeof a){var d=s("Promise").prototype.finally;a.prototype.finally!==d&&l(a.prototype,"finally",d,{unsafe:!0})}},88674(e,t,n){"use strict";var r,i,a,o,s=n(82109),u=n(31913),c=n(17854),l=n(35005),f=n(13366),d=n(31320),h=n(12248),p=n(27674),b=n(58003),m=n(96340),g=n(70111),v=n(13099),y=n(25787),w=n(42788),_=n(20408),E=n(17072),S=n(36707),k=n(20261).set,x=n(95948),T=n(69478),M=n(842),O=n(78523),A=n(12534),L=n(29909),C=n(54705),I=n(5112),D=n(7871),N=n(35268),P=n(7392),R=I("species"),j="Promise",F=L.get,Y=L.set,B=L.getterFor(j),U=f&&f.prototype,H=f,$=U,z=c.TypeError,G=c.document,W=c.process,K=O.f,V=K,q=!!(G&&G.createEvent&&c.dispatchEvent),Z="function"==typeof PromiseRejectionEvent,X="unhandledrejection",J="rejectionhandled",Q=0,ee=1,et=2,en=1,er=2,ei=!1,ea=C(j,function(){var e=w(H),t=e!==String(H);if(!t&&66===P||u&&!$.finally)return!0;if(P>=51&&/native code/.test(e))return!1;var n=new H(function(e){e(1)}),r=function(e){e(function(){},function(){})};return(n.constructor={})[R]=r,!(ei=n.then(function(){}) instanceof r)||!t&&D&&!Z}),eo=ea||!E(function(e){H.all(e).catch(function(){})}),es=function(e){var t;return!!g(e)&&"function"==typeof(t=e.then)&&t},eu=function(e,t){if(!e.notified){e.notified=!0;var n=e.reactions;x(function(){for(var r=e.value,i=e.state==ee,a=0;n.length>a;){var o,s,u,c=n[a++],l=i?c.ok:c.fail,f=c.resolve,d=c.reject,h=c.domain;try{l?(i||(e.rejection===er&&ed(e),e.rejection=en),!0===l?o=r:(h&&h.enter(),o=l(r),h&&(h.exit(),u=!0)),o===c.promise?d(z("Promise-chain cycle")):(s=es(o))?s.call(o,f,d):f(o)):d(r)}catch(p){h&&!u&&h.exit(),d(p)}}e.reactions=[],e.notified=!1,t&&!e.rejection&&el(e)})}},ec=function(e,t,n){var r,i;q?((r=G.createEvent("Event")).promise=t,r.reason=n,r.initEvent(e,!1,!0),c.dispatchEvent(r)):r={promise:t,reason:n},!Z&&(i=c["on"+e])?i(r):e===X&&M("Unhandled promise rejection",n)},el=function(e){k.call(c,function(){var t,n=e.facade,r=e.value;if(ef(e)&&(t=A(function(){N?W.emit("unhandledRejection",r,n):ec(X,n,r)}),e.rejection=N||ef(e)?er:en,t.error))throw t.value})},ef=function(e){return e.rejection!==en&&!e.parent},ed=function(e){k.call(c,function(){var t=e.facade;N?W.emit("rejectionHandled",t):ec(J,t,e.value)})},eh=function(e,t,n){return function(r){e(t,r,n)}},ep=function(e,t,n){e.done||(e.done=!0,n&&(e=n),e.value=t,e.state=et,eu(e,!0))},eb=function(e,t,n){if(!e.done){e.done=!0,n&&(e=n);try{if(e.facade===t)throw z("Promise can't be resolved itself");var r=es(t);r?x(function(){var n={done:!1};try{r.call(t,eh(eb,n,e),eh(ep,n,e))}catch(i){ep(n,i,e)}}):(e.value=t,e.state=ee,eu(e,!1))}catch(i){ep({done:!1},i,e)}}};if(ea&&($=(H=function(e){y(this,H,j),v(e),r.call(this);var t=F(this);try{e(eh(eb,t),eh(ep,t))}catch(n){ep(t,n)}}).prototype,(r=function(e){Y(this,{type:j,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:Q,value:void 0})}).prototype=h($,{then:function(e,t){var n=B(this),r=K(S(this,H));return r.ok="function"!=typeof e||e,r.fail="function"==typeof t&&t,r.domain=N?W.domain:void 0,n.parent=!0,n.reactions.push(r),n.state!=Q&&eu(n,!1),r.promise},catch:function(e){return this.then(void 0,e)}}),i=function(){var e=new r,t=F(e);this.promise=e,this.resolve=eh(eb,t),this.reject=eh(ep,t)},O.f=K=function(e){return e===H||e===a?new i(e):V(e)},!u&&"function"==typeof f&&U!==Object.prototype)){o=U.then,ei||(d(U,"then",function(e,t){var n=this;return new H(function(e,t){o.call(n,e,t)}).then(e,t)},{unsafe:!0}),d(U,"catch",$.catch,{unsafe:!0}));try{delete U.constructor}catch(em){}p&&p(U,$)}s({global:!0,wrap:!0,forced:ea},{Promise:H}),b(H,j,!1,!0),m(j),a=l(j),s({target:j,stat:!0,forced:ea},{reject:function(e){var t=K(this);return t.reject.call(void 0,e),t.promise}}),s({target:j,stat:!0,forced:u||ea},{resolve:function(e){return T(u&&this===a?H:this,e)}}),s({target:j,stat:!0,forced:eo},{all:function(e){var t=this,n=K(t),r=n.resolve,i=n.reject,a=A(function(){var n=v(t.resolve),a=[],o=0,s=1;_(e,function(e){var u=o++,c=!1;a.push(void 0),s++,n.call(t,e).then(function(e){!c&&(c=!0,a[u]=e,--s||r(a))},i)}),--s||r(a)});return a.error&&i(a.value),n.promise},race:function(e){var t=this,n=K(t),r=n.reject,i=A(function(){var i=v(t.resolve);_(e,function(e){i.call(t,e).then(n.resolve,r)})});return i.error&&r(i.value),n.promise}})},36535(e,t,n){var r=n(82109),i=n(35005),a=n(13099),o=n(19670),s=n(47293),u=i("Reflect","apply"),c=Function.apply,l=!s(function(){u(function(){})});r({target:"Reflect",stat:!0,forced:l},{apply:function(e,t,n){return a(e),o(n),u?u(e,t,n):c.call(e,t,n)}})},12419(e,t,n){var r=n(82109),i=n(35005),a=n(13099),o=n(19670),s=n(70111),u=n(70030),c=n(27065),l=n(47293),f=i("Reflect","construct"),d=l(function(){function e(){}return!(f(function(){},[],e) instanceof e)}),h=!l(function(){f(function(){})}),p=d||h;r({target:"Reflect",stat:!0,forced:p,sham:p},{construct:function(e,t){a(e),o(t);var n=arguments.length<3?e:a(arguments[2]);if(h&&!d)return f(e,t,n);if(e==n){switch(t.length){case 0:return new e;case 1:return new e(t[0]);case 2:return new e(t[0],t[1]);case 3:return new e(t[0],t[1],t[2]);case 4:return new e(t[0],t[1],t[2],t[3])}var r=[null];return r.push.apply(r,t),new(c.apply(e,r))}var i=n.prototype,l=u(s(i)?i:Object.prototype),p=Function.apply.call(e,l,t);return s(p)?p:l}})},69596(e,t,n){var r=n(82109),i=n(19781),a=n(19670),o=n(34948),s=n(3070),u=n(47293)(function(){Reflect.defineProperty(s.f({},1,{value:1}),1,{value:2})});r({target:"Reflect",stat:!0,forced:u,sham:!i},{defineProperty:function(e,t,n){a(e);var r=o(t);a(n);try{return s.f(e,r,n),!0}catch(i){return!1}}})},52586(e,t,n){var r=n(82109),i=n(19670),a=n(31236).f;r({target:"Reflect",stat:!0},{deleteProperty:function(e,t){var n=a(i(e),t);return(!n||!!n.configurable)&&delete e[t]}})},95683(e,t,n){var r=n(82109),i=n(19781),a=n(19670),o=n(31236);r({target:"Reflect",stat:!0,sham:!i},{getOwnPropertyDescriptor:function(e,t){return o.f(a(e),t)}})},39361(e,t,n){var r=n(82109),i=n(19670),a=n(79518),o=n(49920);r({target:"Reflect",stat:!0,sham:!o},{getPrototypeOf:function(e){return a(i(e))}})},74819(e,t,n){var r=n(82109),i=n(70111),a=n(19670),o=n(45032),s=n(31236),u=n(79518);function c(e,t){var n,r,l=arguments.length<3?e:arguments[2];return a(e)===l?e[t]:(n=s.f(e,t))?o(n)?n.value:void 0===n.get?void 0:n.get.call(l):i(r=u(e))?c(r,t,l):void 0}r({target:"Reflect",stat:!0},{get:c})},51037(e,t,n){n(82109)({target:"Reflect",stat:!0},{has:function(e,t){return t in e}})},5898(e,t,n){var r=n(82109),i=n(19670),a=Object.isExtensible;r({target:"Reflect",stat:!0},{isExtensible:function(e){return i(e),!a||a(e)}})},67556(e,t,n){var r=n(82109),i=n(53887);r({target:"Reflect",stat:!0},{ownKeys:i})},14361(e,t,n){var r=n(82109),i=n(35005),a=n(19670),o=n(76677);r({target:"Reflect",stat:!0,sham:!o},{preventExtensions:function(e){a(e);try{var t=i("Object","preventExtensions");return t&&t(e),!0}catch(n){return!1}}})},39532(e,t,n){var r=n(82109),i=n(19670),a=n(96077),o=n(27674);o&&r({target:"Reflect",stat:!0},{setPrototypeOf:function(e,t){i(e),a(t);try{return o(e,t),!0}catch(n){return!1}}})},83593(e,t,n){var r=n(82109),i=n(19670),a=n(70111),o=n(45032),s=n(47293),u=n(3070),c=n(31236),l=n(79518),f=n(79114);function d(e,t,n){var r,s,h,p=arguments.length<4?e:arguments[3],b=c.f(i(e),t);if(!b){if(a(s=l(e)))return d(s,t,n,p);b=f(0)}if(o(b)){if(!1===b.writable||!a(p))return!1;if(r=c.f(p,t)){if(r.get||r.set||!1===r.writable)return!1;r.value=n,u.f(p,t,r)}else u.f(p,t,f(0,n))}else{if(void 0===(h=b.set))return!1;h.call(p,n)}return!0}var h=s(function(){var e=function(){},t=u.f(new e,"a",{configurable:!0});return!1!==Reflect.set(e.prototype,"a",1,t)});r({target:"Reflect",stat:!0,forced:h},{set:d})},81299(e,t,n){var r=n(82109),i=n(17854),a=n(58003);r({global:!0},{Reflect:{}}),a(i.Reflect,"Reflect",!0)},24603(e,t,n){var r=n(19781),i=n(17854),a=n(54705),o=n(79587),s=n(68880),u=n(3070).f,c=n(8006).f,l=n(47850),f=n(41340),d=n(67066),h=n(52999),p=n(31320),b=n(47293),m=n(86656),g=n(29909).enforce,v=n(96340),y=n(5112),w=n(9441),_=n(38173),E=y("match"),S=i.RegExp,k=S.prototype,x=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,T=/a/g,M=/a/g,O=new S(T)!==T,A=h.UNSUPPORTED_Y,L=r&&(!O||A||w||_||b(function(){return M[E]=!1,S(T)!=T||S(M)==M||"/a/i"!=S(T,"i")})),C=function(e){for(var t,n=e.length,r=0,i="",a=!1;r<=n;r++){if("\\"===(t=e.charAt(r))){i+=t+e.charAt(++r);continue}a||"."!==t?("["===t?a=!0:"]"===t&&(a=!1),i+=t):i+="[\\s\\S]"}return i},I=function(e){for(var t,n=e.length,r=0,i="",a=[],o={},s=!1,u=!1,c=0,l="";r<=n;r++){if("\\"===(t=e.charAt(r)))t+=e.charAt(++r);else if("]"===t)s=!1;else if(!s)switch(!0){case"["===t:s=!0;break;case"("===t:x.test(e.slice(r+1))&&(r+=2,u=!0),i+=t,c++;continue;case">"===t&&u:if(""===l||m(o,l))throw SyntaxError("Invalid capture group name");o[l]=!0,a.push([l,c]),u=!1,l="";continue}u?l+=t:i+=t}return[i,a]};if(a("RegExp",L)){for(var D=function(e,t){var n,r,i,a,u,c,h=this instanceof D,p=l(e),b=void 0===t,m=[],v=e;if(!h&&p&&b&&e.constructor===D)return e;if((p||e instanceof D)&&(e=e.source,b&&(t=("flags"in v)?v.flags:d.call(v))),e=void 0===e?"":f(e),t=void 0===t?"":f(t),v=e,w&&("dotAll"in T)&&(r=!!t&&t.indexOf("s")>-1)&&(t=t.replace(/s/g,"")),n=t,A&&("sticky"in T)&&(i=!!t&&t.indexOf("y")>-1)&&(t=t.replace(/y/g,"")),_&&(e=(a=I(e))[0],m=a[1]),u=o(S(e,t),h?this:k,D),(r||i||m.length)&&(c=g(u),r&&(c.dotAll=!0,c.raw=D(C(e),n)),i&&(c.sticky=!0),m.length&&(c.groups=m)),e!==v)try{s(u,"source",""===v?"(?:)":v)}catch(y){}return u},N=function(e){(e in D)||u(D,e,{configurable:!0,get:function(){return S[e]},set:function(t){S[e]=t}})},P=c(S),R=0;P.length>R;)N(P[R++]);k.constructor=D,D.prototype=k,p(i,"RegExp",D)}v("RegExp")},28450(e,t,n){var r=n(19781),i=n(9441),a=n(3070).f,o=n(29909).get,s=RegExp.prototype;r&&i&&a(s,"dotAll",{configurable:!0,get:function(){if(this!==s){if(this instanceof RegExp)return!!o(this).dotAll;throw TypeError("Incompatible receiver, RegExp required")}}})},74916(e,t,n){"use strict";var r=n(82109),i=n(22261);r({target:"RegExp",proto:!0,forced:/./.exec!==i},{exec:i})},92087(e,t,n){var r=n(19781),i=n(3070),a=n(67066),o=n(47293);r&&o(function(){return"sy"!==Object.getOwnPropertyDescriptor(RegExp.prototype,"flags").get.call({dotAll:!0,sticky:!0})})&&i.f(RegExp.prototype,"flags",{configurable:!0,get:a})},88386(e,t,n){var r=n(19781),i=n(52999).UNSUPPORTED_Y,a=n(3070).f,o=n(29909).get,s=RegExp.prototype;r&&i&&a(s,"sticky",{configurable:!0,get:function(){if(this!==s){if(this instanceof RegExp)return!!o(this).sticky;throw TypeError("Incompatible receiver, RegExp required")}}})},77601(e,t,n){"use strict";n(74916);var r,i,a=n(82109),o=n(70111),s=(r=!1,(i=/[ac]/).exec=function(){return r=!0,/./.exec.apply(this,arguments)},!0===i.test("abc")&&r),u=/./.test;a({target:"RegExp",proto:!0,forced:!s},{test:function(e){if("function"!=typeof this.exec)return u.call(this,e);var t=this.exec(e);if(null!==t&&!o(t))throw Error("RegExp exec method returned something other than an Object or null");return!!t}})},39714(e,t,n){"use strict";var r=n(31320),i=n(19670),a=n(41340),o=n(47293),s=n(67066),u="toString",c=RegExp.prototype,l=c[u],f=o(function(){return"/a/b"!=l.call({source:"a",flags:"b"})}),d=l.name!=u;(f||d)&&r(RegExp.prototype,u,function(){var e=i(this),t=a(e.source),n=e.flags,r=a(void 0===n&&e instanceof RegExp&&!("flags"in c)?s.call(e):n);return"/"+t+"/"+r},{unsafe:!0})},70189(e,t,n){"use strict";var r=n(77710),i=n(95631);e.exports=r("Set",function(e){return function(){return e(this,arguments.length?arguments[0]:void 0)}},i)},15218(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("anchor")},{anchor:function(e){return i(this,"a","name",e)}})},24506(e,t,n){"use strict";var r=n(82109),i=n(84488),a=n(99958),o=n(17466),s=n(41340),u=n(47293)(function(){return"\uD842"!=="𠮷".at(0)});r({target:"String",proto:!0,forced:u},{at:function(e){var t=s(i(this)),n=o(t.length),r=a(e),u=r>=0?r:n+r;return u<0||u>=n?void 0:t.charAt(u)}})},74475(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("big")},{big:function(){return i(this,"big","","")}})},57929(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("blink")},{blink:function(){return i(this,"blink","","")}})},50915(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("bold")},{bold:function(){return i(this,"b","","")}})},79841(e,t,n){"use strict";var r=n(82109),i=n(28710).codeAt;r({target:"String",proto:!0},{codePointAt:function(e){return i(this,e)}})},27852(e,t,n){"use strict";var r,i=n(82109),a=n(31236).f,o=n(17466),s=n(41340),u=n(3929),c=n(84488),l=n(84964),f=n(31913),d="".endsWith,h=Math.min,p=l("endsWith"),b=!f&&!p&&!!(r=a(String.prototype,"endsWith"))&&!r.writable;i({target:"String",proto:!0,forced:!b&&!p},{endsWith:function(e){var t=s(c(this));u(e);var n=arguments.length>1?arguments[1]:void 0,r=o(t.length),i=void 0===n?r:h(o(n),r),a=s(e);return d?d.call(t,a,i):t.slice(i-a.length,i)===a}})},29253(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("fixed")},{fixed:function(){return i(this,"tt","","")}})},42125(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("fontcolor")},{fontcolor:function(e){return i(this,"font","color",e)}})},78830(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("fontsize")},{fontsize:function(e){return i(this,"font","size",e)}})},94953(e,t,n){var r=n(82109),i=n(51400),a=String.fromCharCode,o=String.fromCodePoint;r({target:"String",stat:!0,forced:!!o&&1!=o.length},{fromCodePoint:function(e){for(var t,n=[],r=arguments.length,o=0;r>o;){if(t=+arguments[o++],i(t,1114111)!==t)throw RangeError(t+" is not a valid code point");n.push(t<65536?a(t):a(((t-=65536)>>10)+55296,t%1024+56320))}return n.join("")}})},32023(e,t,n){"use strict";var r=n(82109),i=n(3929),a=n(84488),o=n(41340),s=n(84964);r({target:"String",proto:!0,forced:!s("includes")},{includes:function(e){return!!~o(a(this)).indexOf(o(i(e)),arguments.length>1?arguments[1]:void 0)}})},58734(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("italics")},{italics:function(){return i(this,"i","","")}})},78783(e,t,n){"use strict";var r=n(28710).charAt,i=n(41340),a=n(29909),o=n(70654),s="String Iterator",u=a.set,c=a.getterFor(s);o(String,"String",function(e){u(this,{type:s,string:i(e),index:0})},function(){var e,t=c(this),n=t.string,i=t.index;return i>=n.length?{value:void 0,done:!0}:(e=r(n,i),t.index+=e.length,{value:e,done:!1})})},29254(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("link")},{link:function(e){return i(this,"a","href",e)}})},76373(e,t,n){"use strict";var r=n(82109),i=n(24994),a=n(84488),o=n(17466),s=n(41340),u=n(13099),c=n(19670),l=n(84326),f=n(47850),d=n(67066),h=n(68880),p=n(47293),b=n(5112),m=n(36707),g=n(31530),v=n(29909),y=n(31913),w=b("matchAll"),_="RegExp String",E=_+" Iterator",S=v.set,k=v.getterFor(E),x=RegExp.prototype,T=x.exec,M="".matchAll,O=!!M&&!p(function(){"a".matchAll(/./)}),A=function(e,t){var n,r=e.exec;if("function"==typeof r){if("object"!=typeof(n=r.call(e,t)))throw TypeError("Incorrect exec result");return n}return T.call(e,t)},L=i(function(e,t,n,r){S(this,{type:E,regexp:e,string:t,global:n,unicode:r,done:!1})},_,function(){var e=k(this);if(e.done)return{value:void 0,done:!0};var t=e.regexp,n=e.string,r=A(t,n);return null===r?{value:void 0,done:e.done=!0}:e.global?(""===s(r[0])&&(t.lastIndex=g(n,o(t.lastIndex),e.unicode)),{value:r,done:!1}):(e.done=!0,{value:r,done:!1})}),C=function(e){var t,n,r,i,a,u,l=c(this),f=s(e);return t=m(l,RegExp),void 0===(n=l.flags)&&l instanceof RegExp&&!("flags"in x)&&(n=d.call(l)),r=void 0===n?"":s(n),i=new t(t===RegExp?l.source:l,r),a=!!~r.indexOf("g"),u=!!~r.indexOf("u"),i.lastIndex=o(l.lastIndex),new L(i,f,a,u)};r({target:"String",proto:!0,forced:O},{matchAll:function(e){var t,n,r,i,o=a(this);if(null!=e){if(f(e)&&!~(t=s(a("flags"in x?e.flags:d.call(e)))).indexOf("g"))throw TypeError("`.matchAll` does not allow non-global regexes");if(O)return M.apply(o,arguments);if(void 0===(r=e[w])&&y&&"RegExp"==l(e)&&(r=C),null!=r)return u(r).call(e,o)}else if(O)return M.apply(o,arguments);return n=s(o),i=RegExp(e,"g"),y?C.call(i,n):i[w](n)}}),y||w in x||h(x,w,C)},4723(e,t,n){"use strict";var r=n(27007),i=n(19670),a=n(17466),o=n(41340),s=n(84488),u=n(31530),c=n(97651);r("match",function(e,t,n){return[function(t){var n=s(this),r=void 0==t?void 0:t[e];return void 0!==r?r.call(t,n):RegExp(t)[e](o(n))},function(e){var r,s=i(this),l=o(e),f=n(t,s,l);if(f.done)return f.value;if(!s.global)return c(s,l);var d=s.unicode;s.lastIndex=0;for(var h=[],p=0;null!==(r=c(s,l));){var b=o(r[0]);h[p]=b,""===b&&(s.lastIndex=u(l,a(s.lastIndex),d)),p++}return 0===p?null:h}]})},66528(e,t,n){"use strict";var r=n(82109),i=n(76650).end,a=n(54986);r({target:"String",proto:!0,forced:a},{padEnd:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}})},83112(e,t,n){"use strict";var r=n(82109),i=n(76650).start,a=n(54986);r({target:"String",proto:!0,forced:a},{padStart:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}})},38992(e,t,n){var r=n(82109),i=n(45656),a=n(17466),o=n(41340);r({target:"String",stat:!0},{raw:function(e){for(var t=i(e.raw),n=a(t.length),r=arguments.length,s=[],u=0;n>u;)s.push(o(t[u++])),ue.length?-1:""===t?n:e.indexOf(t,n)};r({target:"String",proto:!0},{replaceAll:function(e,t){var n,r,c,b,m,g,v,y,w,_=i(this),E=0,S=0,k="";if(null!=e){if((n=a(e))&&!~(r=o(i("flags"in d?e.flags:s.call(e)))).indexOf("g"))throw TypeError("`.replaceAll` does not allow non-global regexes");if(void 0!==(c=e[f]))return c.call(e,_,t);if(l&&n)return o(_).replace(e,t)}for(b=o(_),m=o(e),(g="function"==typeof t)||(t=o(t)),y=h(1,v=m.length),E=p(b,m,0);-1!==E;)w=g?o(t(m,E,b)):u(m,b,E,[],void 0,t),k+=b.slice(S,E)+w,S=E+v,E=p(b,m,E+y);return S")});r("replace",function(e,t,n){var r=v?"$":"$0";return[function(e,n){var r=c(this),i=void 0==e?void 0:e[h];return void 0!==i?i.call(e,r,n):t.call(u(r),e,n)},function(e,i){var c=a(this),h=u(e);if("string"==typeof i&&-1===i.indexOf(r)&&-1===i.indexOf("$<")){var g=n(t,c,h,i);if(g.done)return g.value}var v="function"==typeof i;v||(i=u(i));var y=c.global;if(y){var w=c.unicode;c.lastIndex=0}for(var _=[];;){var E=d(c,h);if(null===E||(_.push(E),!y))break;""===u(E[0])&&(c.lastIndex=l(h,s(c.lastIndex),w))}for(var S="",k=0,x=0;x<_.length;x++){for(var T=u((E=_[x])[0]),M=p(b(o(E.index),h.length),0),O=[],A=1;A=k&&(S+=h.slice(k,M)+I,k=M+T.length)}return S+h.slice(k)}]},!y||!g||v)},64765(e,t,n){"use strict";var r=n(27007),i=n(19670),a=n(84488),o=n(81150),s=n(41340),u=n(97651);r("search",function(e,t,n){return[function(t){var n=a(this),r=void 0==t?void 0:t[e];return void 0!==r?r.call(t,n):RegExp(t)[e](s(n))},function(e){var r=i(this),a=s(e),c=n(t,r,a);if(c.done)return c.value;var l=r.lastIndex;o(l,0)||(r.lastIndex=0);var f=u(r,a);return o(r.lastIndex,l)||(r.lastIndex=l),null===f?-1:f.index}]})},37268(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("small")},{small:function(){return i(this,"small","","")}})},23123(e,t,n){"use strict";var r=n(27007),i=n(47850),a=n(19670),o=n(84488),s=n(36707),u=n(31530),c=n(17466),l=n(41340),f=n(97651),d=n(22261),h=n(52999),p=n(47293),b=h.UNSUPPORTED_Y,m=[].push,g=Math.min,v=4294967295,y=!p(function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]});r("split",function(e,t,n){var r;return r="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(e,n){var r,a,s,u=l(o(this)),c=void 0===n?v:n>>>0;if(0===c)return[];if(void 0===e)return[u];if(!i(e))return t.call(u,e,c);for(var f=[],h=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),p=0,b=RegExp(e.source,h+"g");(r=d.call(b,u))&&(!((a=b.lastIndex)>p)||(f.push(u.slice(p,r.index)),r.length>1&&r.index=c)));)b.lastIndex===r.index&&b.lastIndex++;return p===u.length?(s||!b.test(""))&&f.push(""):f.push(u.slice(p)),f.length>c?f.slice(0,c):f}:"0".split(void 0,0).length?function(e,n){return void 0===e&&0===n?[]:t.call(this,e,n)}:t,[function(t,n){var i=o(this),a=void 0==t?void 0:t[e];return void 0!==a?a.call(t,i,n):r.call(l(i),t,n)},function(e,i){var o=a(this),d=l(e),h=n(r,o,d,i,r!==t);if(h.done)return h.value;var p=s(o,RegExp),m=o.unicode,y=(o.ignoreCase?"i":"")+(o.multiline?"m":"")+(o.unicode?"u":"")+(b?"g":"y"),w=new p(b?"^(?:"+o.source+")":o,y),_=void 0===i?v:i>>>0;if(0===_)return[];if(0===d.length)return null===f(w,d)?[d]:[];for(var E=0,S=0,k=[];S1?arguments[1]:void 0,t.length)),r=s(e);return d?d.call(t,r,n):t.slice(n,n+r.length)===r}})},7397(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("strike")},{strike:function(){return i(this,"strike","","")}})},60086(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("sub")},{sub:function(){return i(this,"sub","","")}})},83650(e,t,n){"use strict";var r=n(82109),i=n(84488),a=n(99958),o=n(41340),s="".slice,u=Math.max,c=Math.min;r({target:"String",proto:!0},{substr:function(e,t){var n,r,l=o(i(this)),f=l.length,d=a(e);return(d===1/0&&(d=0),d<0&&(d=u(f+d,0)),(n=void 0===t?f:a(t))<=0||n===1/0)?"":(r=c(d+n,f),d>=r?"":s.call(l,d,r))}})},80623(e,t,n){"use strict";var r=n(82109),i=n(14230),a=n(43429);r({target:"String",proto:!0,forced:a("sup")},{sup:function(){return i(this,"sup","","")}})},48702(e,t,n){"use strict";var r=n(82109),i=n(53111).end,a=n(76091)("trimEnd"),o=a?function(){return i(this)}:"".trimEnd;r({target:"String",proto:!0,forced:a},{trimEnd:o,trimRight:o})},55674(e,t,n){"use strict";var r=n(82109),i=n(53111).start,a=n(76091)("trimStart"),o=a?function(){return i(this)}:"".trimStart;r({target:"String",proto:!0,forced:a},{trimStart:o,trimLeft:o})},73210(e,t,n){"use strict";var r=n(82109),i=n(53111).trim,a=n(76091);r({target:"String",proto:!0,forced:a("trim")},{trim:function(){return i(this)}})},72443(e,t,n){n(97235)("asyncIterator")},41817(e,t,n){"use strict";var r=n(82109),i=n(19781),a=n(17854),o=n(86656),s=n(70111),u=n(3070).f,c=n(99920),l=a.Symbol;if(i&&"function"==typeof l&&(!("description"in l.prototype)||void 0!==l().description)){var f={},d=function(){var e=arguments.length<1||void 0===arguments[0]?void 0:String(arguments[0]),t=this instanceof d?new l(e):void 0===e?l():l(e);return""===e&&(f[t]=!0),t};c(d,l);var h=d.prototype=l.prototype;h.constructor=d;var p=h.toString,b="Symbol(test)"==String(l("test")),m=/^Symbol\((.*)\)[^)]+$/;u(h,"description",{configurable:!0,get:function(){var e=s(this)?this.valueOf():this,t=p.call(e);if(o(f,e))return"";var n=b?t.slice(7,-1):t.replace(m,"$1");return""===n?void 0:n}}),r({global:!0,forced:!0},{Symbol:d})}},92401(e,t,n){n(97235)("hasInstance")},8722(e,t,n){n(97235)("isConcatSpreadable")},32165(e,t,n){n(97235)("iterator")},82526(e,t,n){"use strict";var r=n(82109),i=n(17854),a=n(35005),o=n(31913),s=n(19781),u=n(30133),c=n(47293),l=n(86656),f=n(43157),d=n(70111),h=n(52190),p=n(19670),b=n(47908),m=n(45656),g=n(34948),v=n(41340),y=n(79114),w=n(70030),_=n(81956),E=n(8006),S=n(1156),k=n(25181),x=n(31236),T=n(3070),M=n(55296),O=n(68880),A=n(31320),L=n(72309),C=n(6200),I=n(3501),D=n(69711),N=n(5112),P=n(6061),R=n(97235),j=n(58003),F=n(29909),Y=n(42092).forEach,B=C("hidden"),U="Symbol",H="prototype",$=N("toPrimitive"),z=F.set,G=F.getterFor(U),W=Object[H],K=i.Symbol,V=a("JSON","stringify"),q=x.f,Z=T.f,X=S.f,J=M.f,Q=L("symbols"),ee=L("op-symbols"),et=L("string-to-symbol-registry"),en=L("symbol-to-string-registry"),er=L("wks"),ei=i.QObject,ea=!ei||!ei[H]||!ei[H].findChild,eo=s&&c(function(){return 7!=w(Z({},"a",{get:function(){return Z(this,"a",{value:7}).a}})).a})?function(e,t,n){var r=q(W,t);r&&delete W[t],Z(e,t,n),r&&e!==W&&Z(W,t,r)}:Z,es=function(e,t){var n=Q[e]=w(K[H]);return z(n,{type:U,tag:e,description:t}),s||(n.description=t),n},eu=function(e,t,n){e===W&&eu(ee,t,n),p(e);var r=g(t);return(p(n),l(Q,r))?(n.enumerable?(l(e,B)&&e[B][r]&&(e[B][r]=!1),n=w(n,{enumerable:y(0,!1)})):(l(e,B)||Z(e,B,y(1,{})),e[B][r]=!0),eo(e,r,n)):Z(e,r,n)},ec=function(e,t){p(e);var n=m(t),r=_(n).concat(ep(n));return Y(r,function(t){(!s||ef.call(n,t))&&eu(e,t,n[t])}),e},el=function(e,t){return void 0===t?w(e):ec(w(e),t)},ef=function(e){var t=g(e),n=J.call(this,t);return(!(this===W&&l(Q,t))||!!l(ee,t))&&(!(n||!l(this,t)||!l(Q,t)||l(this,B)&&this[B][t])||n)},ed=function(e,t){var n=m(e),r=g(t);if(!(n===W&&l(Q,r))||l(ee,r)){var i=q(n,r);return i&&l(Q,r)&&!(l(n,B)&&n[B][r])&&(i.enumerable=!0),i}},eh=function(e){var t=X(m(e)),n=[];return Y(t,function(e){l(Q,e)||l(I,e)||n.push(e)}),n},ep=function(e){var t=e===W,n=X(t?ee:m(e)),r=[];return Y(n,function(e){l(Q,e)&&(!t||l(W,e))&&r.push(Q[e])}),r};if(u||(A((K=function(){if(this instanceof K)throw TypeError("Symbol is not a constructor");var e=arguments.length&&void 0!==arguments[0]?v(arguments[0]):void 0,t=D(e),n=function(e){this===W&&n.call(ee,e),l(this,B)&&l(this[B],t)&&(this[B][t]=!1),eo(this,t,y(1,e))};return s&&ea&&eo(W,t,{configurable:!0,set:n}),es(t,e)})[H],"toString",function(){return G(this).tag}),A(K,"withoutSetter",function(e){return es(D(e),e)}),M.f=ef,T.f=eu,x.f=ed,E.f=S.f=eh,k.f=ep,P.f=function(e){return es(N(e),e)},s&&(Z(K[H],"description",{configurable:!0,get:function(){return G(this).description}}),o||A(W,"propertyIsEnumerable",ef,{unsafe:!0}))),r({global:!0,wrap:!0,forced:!u,sham:!u},{Symbol:K}),Y(_(er),function(e){R(e)}),r({target:U,stat:!0,forced:!u},{for:function(e){var t=v(e);if(l(et,t))return et[t];var n=K(t);return et[t]=n,en[n]=t,n},keyFor:function(e){if(!h(e))throw TypeError(e+" is not a symbol");if(l(en,e))return en[e]},useSetter:function(){ea=!0},useSimple:function(){ea=!1}}),r({target:"Object",stat:!0,forced:!u,sham:!s},{create:el,defineProperty:eu,defineProperties:ec,getOwnPropertyDescriptor:ed}),r({target:"Object",stat:!0,forced:!u},{getOwnPropertyNames:eh,getOwnPropertySymbols:ep}),r({target:"Object",stat:!0,forced:c(function(){k.f(1)})},{getOwnPropertySymbols:function(e){return k.f(b(e))}}),V){var eb=!u||c(function(){var e=K();return"[null]"!=V([e])||"{}"!=V({a:e})||"{}"!=V(Object(e))});r({target:"JSON",stat:!0,forced:eb},{stringify:function(e,t,n){for(var r,i=[e],a=1;arguments.length>a;)i.push(arguments[a++]);if(r=t,!(!d(t)&&void 0===e||h(e)))return f(t)||(t=function(e,t){if("function"==typeof r&&(t=r.call(this,e,t)),!h(t))return t}),i[1]=t,V.apply(null,i)}})}K[H][$]||O(K[H],$,K[H].valueOf),j(K,U),I[B]=!0},16066(e,t,n){n(97235)("matchAll")},69007(e,t,n){n(97235)("match")},83510(e,t,n){n(97235)("replace")},41840(e,t,n){n(97235)("search")},6982(e,t,n){n(97235)("species")},32159(e,t,n){n(97235)("split")},96649(e,t,n){n(97235)("toPrimitive")},39341(e,t,n){n(97235)("toStringTag")},60543(e,t,n){n(97235)("unscopables")},48675(e,t,n){"use strict";var r=n(90260),i=n(17466),a=n(99958),o=r.aTypedArray;(0,r.exportTypedArrayMethod)("at",function(e){var t=o(this),n=i(t.length),r=a(e),s=r>=0?r:n+r;return s<0||s>=n?void 0:t[s]})},92990(e,t,n){"use strict";var r=n(90260),i=n(1048),a=r.aTypedArray;(0,r.exportTypedArrayMethod)("copyWithin",function(e,t){return i.call(a(this),e,t,arguments.length>2?arguments[2]:void 0)})},18927(e,t,n){"use strict";var r=n(90260),i=n(42092).every,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("every",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},33105(e,t,n){"use strict";var r=n(90260),i=n(21285),a=r.aTypedArray;(0,r.exportTypedArrayMethod)("fill",function(e){return i.apply(a(this),arguments)})},35035(e,t,n){"use strict";var r=n(90260),i=n(42092).filter,a=n(43074),o=r.aTypedArray;(0,r.exportTypedArrayMethod)("filter",function(e){var t=i(o(this),e,arguments.length>1?arguments[1]:void 0);return a(this,t)})},7174(e,t,n){"use strict";var r=n(90260),i=n(42092).findIndex,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("findIndex",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},74345(e,t,n){"use strict";var r=n(90260),i=n(42092).find,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("find",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},44197(e,t,n){n(19843)("Float32",function(e){return function(t,n,r){return e(this,t,n,r)}})},76495(e,t,n){n(19843)("Float64",function(e){return function(t,n,r){return e(this,t,n,r)}})},32846(e,t,n){"use strict";var r=n(90260),i=n(42092).forEach,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("forEach",function(e){i(a(this),e,arguments.length>1?arguments[1]:void 0)})},98145(e,t,n){"use strict";var r=n(63832),i=n(90260).exportTypedArrayStaticMethod,a=n(97321);i("from",a,r)},44731(e,t,n){"use strict";var r=n(90260),i=n(41318).includes,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("includes",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},77209(e,t,n){"use strict";var r=n(90260),i=n(41318).indexOf,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("indexOf",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},35109(e,t,n){n(19843)("Int16",function(e){return function(t,n,r){return e(this,t,n,r)}})},65125(e,t,n){n(19843)("Int32",function(e){return function(t,n,r){return e(this,t,n,r)}})},87145(e,t,n){n(19843)("Int8",function(e){return function(t,n,r){return e(this,t,n,r)}})},96319(e,t,n){"use strict";var r=n(17854),i=n(90260),a=n(66992),o=n(5112)("iterator"),s=r.Uint8Array,u=a.values,c=a.keys,l=a.entries,f=i.aTypedArray,d=i.exportTypedArrayMethod,h=s&&s.prototype[o],p=!!h&&("values"==h.name||void 0==h.name),b=function(){return u.call(f(this))};d("entries",function(){return l.call(f(this))}),d("keys",function(){return c.call(f(this))}),d("values",b,!p),d(o,b,!p)},58867(e,t,n){"use strict";var r=n(90260),i=r.aTypedArray,a=r.exportTypedArrayMethod,o=[].join;a("join",function(e){return o.apply(i(this),arguments)})},37789(e,t,n){"use strict";var r=n(90260),i=n(86583),a=r.aTypedArray;(0,r.exportTypedArrayMethod)("lastIndexOf",function(e){return i.apply(a(this),arguments)})},33739(e,t,n){"use strict";var r=n(90260),i=n(42092).map,a=n(66304),o=r.aTypedArray;(0,r.exportTypedArrayMethod)("map",function(e){return i(o(this),e,arguments.length>1?arguments[1]:void 0,function(e,t){return new(a(e))(t)})})},95206(e,t,n){"use strict";var r=n(90260),i=n(63832),a=r.aTypedArrayConstructor;(0,r.exportTypedArrayStaticMethod)("of",function(){for(var e=0,t=arguments.length,n=new(a(this))(t);t>e;)n[e]=arguments[e++];return n},i)},14483(e,t,n){"use strict";var r=n(90260),i=n(53671).right,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("reduceRight",function(e){return i(a(this),e,arguments.length,arguments.length>1?arguments[1]:void 0)})},29368(e,t,n){"use strict";var r=n(90260),i=n(53671).left,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("reduce",function(e){return i(a(this),e,arguments.length,arguments.length>1?arguments[1]:void 0)})},12056(e,t,n){"use strict";var r=n(90260),i=r.aTypedArray,a=r.exportTypedArrayMethod,o=Math.floor;a("reverse",function(){for(var e,t=this,n=i(t).length,r=o(n/2),a=0;a1?arguments[1]:void 0,1),n=this.length,r=o(e),s=i(r.length),c=0;if(s+t>n)throw RangeError("Wrong length");for(;ca;)c[a]=n[a++];return c},c)},27462(e,t,n){"use strict";var r=n(90260),i=n(42092).some,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("some",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},33824(e,t,n){"use strict";var r=n(90260),i=n(17854),a=n(47293),o=n(13099),s=n(17466),u=n(94362),c=n(68886),l=n(30256),f=n(7392),d=n(98008),h=r.aTypedArray,p=r.exportTypedArrayMethod,b=i.Uint16Array,m=b&&b.prototype.sort,g=!!m&&!a(function(){var e=new b(2);e.sort(null),e.sort({})}),v=!!m&&!a(function(){if(f)return f<74;if(c)return c<67;if(l)return!0;if(d)return d<602;var e,t,n=new b(516),r=Array(516);for(e=0;e<516;e++)t=e%4,n[e]=515-e,r[e]=e-2*t+3;for(n.sort(function(e,t){return(e/4|0)-(t/4|0)}),e=0;e<516;e++)if(n[e]!==r[e])return!0}),y=function(e){return function(t,n){return void 0!==e?+e(t,n)||0:n!=n?-1:t!=t?1:0===t&&0===n?1/t>0&&1/n<0?1:-1:t>n}};p("sort",function(e){var t,n=this;if(void 0!==e&&o(e),v)return m.call(n,e);h(n);var r=s(n.length),i=Array(r);for(t=0;t1?arguments[1]:void 0)}}),a("filterOut")},34286(e,t,n){"use strict";var r=n(82109),i=n(42092).filterReject,a=n(51223);r({target:"Array",proto:!0},{filterReject:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}}),a("filterReject")},77461(e,t,n){"use strict";var r=n(82109),i=n(9671).findLastIndex,a=n(51223);r({target:"Array",proto:!0},{findLastIndex:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}}),a("findLastIndex")},3048(e,t,n){"use strict";var r=n(82109),i=n(9671).findLast,a=n(51223);r({target:"Array",proto:!0},{findLast:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}}),a("findLast")},1999(e,t,n){"use strict";var r=n(82109),i=n(61386),a=n(77475),o=n(51223);r({target:"Array",proto:!0},{groupBy:function(e){var t=arguments.length>1?arguments[1]:void 0;return i(this,e,t,a)}}),o("groupBy")},8e4(e,t,n){var r=n(82109),i=n(43157),a=Object.isFrozen,o=function(e,t){if(!a||!i(e)||!a(e))return!1;for(var n,r=0,o=e.length;r1?arguments[1]:void 0,3);return!u(n,function(e,n,i){if(!r(n,e,t))return i()},{AS_ENTRIES:!0,IS_ITERATOR:!0,INTERRUPTED:!0}).stopped}})},71957(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(49974),c=n(36707),l=n(54647),f=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{filter:function(e){var t=o(this),n=l(t),r=u(e,arguments.length>1?arguments[1]:void 0,3),i=new(c(t,a("Map"))),d=s(i.set);return f(n,function(e,n){r(n,e,t)&&d.call(i,e,n)},{AS_ENTRIES:!0,IS_ITERATOR:!0}),i}})},103(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(49974),s=n(54647),u=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{findKey:function(e){var t=a(this),n=s(t),r=o(e,arguments.length>1?arguments[1]:void 0,3);return u(n,function(e,n,i){if(r(n,e,t))return i(e)},{AS_ENTRIES:!0,IS_ITERATOR:!0,INTERRUPTED:!0}).result}})},96306(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(49974),s=n(54647),u=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{find:function(e){var t=a(this),n=s(t),r=o(e,arguments.length>1?arguments[1]:void 0,3);return u(n,function(e,n,i){if(r(n,e,t))return i(n)},{AS_ENTRIES:!0,IS_ITERATOR:!0,INTERRUPTED:!0}).result}})},8582(e,t,n){var r=n(82109),i=n(27296);r({target:"Map",stat:!0},{from:i})},90618(e,t,n){"use strict";var r=n(82109),i=n(20408),a=n(13099);r({target:"Map",stat:!0},{groupBy:function(e,t){var n=new this;a(t);var r=a(n.has),o=a(n.get),s=a(n.set);return i(e,function(e){var i=t(e);r.call(n,i)?o.call(n,i).push(e):s.call(n,i,[e])}),n}})},74592(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(54647),s=n(46465),u=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{includes:function(e){return u(o(a(this)),function(t,n,r){if(s(n,e))return r()},{AS_ENTRIES:!0,IS_ITERATOR:!0,INTERRUPTED:!0}).stopped}})},88440(e,t,n){"use strict";var r=n(82109),i=n(20408),a=n(13099);r({target:"Map",stat:!0},{keyBy:function(e,t){var n=new this;a(t);var r=a(n.set);return i(e,function(e){r.call(n,t(e),e)}),n}})},58276(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(54647),s=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{keyOf:function(e){return s(o(a(this)),function(t,n,r){if(n===e)return r(t)},{AS_ENTRIES:!0,IS_ITERATOR:!0,INTERRUPTED:!0}).result}})},35082(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(49974),c=n(36707),l=n(54647),f=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{mapKeys:function(e){var t=o(this),n=l(t),r=u(e,arguments.length>1?arguments[1]:void 0,3),i=new(c(t,a("Map"))),d=s(i.set);return f(n,function(e,n){d.call(i,r(n,e,t),n)},{AS_ENTRIES:!0,IS_ITERATOR:!0}),i}})},12813(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(49974),c=n(36707),l=n(54647),f=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{mapValues:function(e){var t=o(this),n=l(t),r=u(e,arguments.length>1?arguments[1]:void 0,3),i=new(c(t,a("Map"))),d=s(i.set);return f(n,function(e,n){d.call(i,e,r(n,e,t))},{AS_ENTRIES:!0,IS_ITERATOR:!0}),i}})},18222(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(13099),s=n(20408);r({target:"Map",proto:!0,real:!0,forced:i},{merge:function(e){for(var t=a(this),n=o(t.set),r=arguments.length,i=0;i1?arguments[1]:void 0,3);return u(n,function(e,n,i){if(r(n,e,t))return i()},{AS_ENTRIES:!0,IS_ITERATOR:!0,INTERRUPTED:!0}).stopped}})},74442(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(8154);r({target:"Map",proto:!0,real:!0,forced:i},{updateOrInsert:a})},7512(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(13099);r({target:"Map",proto:!0,real:!0,forced:i},{update:function(e,t){var n=a(this),r=arguments.length;o(t);var i=n.has(e);if(!i&&r<3)throw TypeError("Updating absent value");var s=i?n.get(e):o(r>2?arguments[2]:void 0)(e,n);return n.set(e,t(s,e,n)),n}})},87713(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(8154);r({target:"Map",proto:!0,real:!0,forced:i},{upsert:a})},46603(e,t,n){var r=n(82109),i=Math.min,a=Math.max;r({target:"Math",stat:!0},{clamp:function(e,t,n){return i(n,a(t,e))}})},70100(e,t,n){n(82109)({target:"Math",stat:!0},{DEG_PER_RAD:Math.PI/180})},26429(e,t,n){var r=n(82109),i=180/Math.PI;r({target:"Math",stat:!0},{degrees:function(e){return e*i}})},13187(e,t,n){var r=n(82109),i=n(47103),a=n(26130);r({target:"Math",stat:!0},{fscale:function(e,t,n,r,o){return a(i(e,t,n,r,o))}})},60092(e,t,n){n(82109)({target:"Math",stat:!0},{iaddh:function(e,t,n,r){var i=e>>>0,a=n>>>0;return(t>>>0)+(r>>>0)+((i&a|(i|a)&~(i+a>>>0))>>>31)|0}})},19041(e,t,n){n(82109)({target:"Math",stat:!0},{imulh:function(e,t){var n=65535,r=+e,i=+t,a=r&n,o=i&n,s=r>>16,u=i>>16,c=(s*o>>>0)+(a*o>>>16);return s*u+(c>>16)+((a*u>>>0)+(c&n)>>16)}})},30666(e,t,n){n(82109)({target:"Math",stat:!0},{isubh:function(e,t,n,r){var i=e>>>0,a=n>>>0;return(t>>>0)-(r>>>0)-((~i&a|~(i^a)&i-a>>>0)>>>31)|0}})},51638(e,t,n){n(82109)({target:"Math",stat:!0},{RAD_PER_DEG:180/Math.PI})},62975(e,t,n){var r=n(82109),i=Math.PI/180;r({target:"Math",stat:!0},{radians:function(e){return e*i}})},15728(e,t,n){var r=n(82109),i=n(47103);r({target:"Math",stat:!0},{scale:i})},46056(e,t,n){var r=n(82109),i=n(19670),a=n(77023),o=n(24994),s=n(29909),u="Seeded Random",c=u+" Generator",l=s.set,f=s.getterFor(c),d='Math.seededPRNG() argument should have a "seed" field with a finite value.',h=o(function(e){l(this,{type:c,seed:e%2147483647})},u,function(){var e=f(this);return{value:(1073741823&(e.seed=(1103515245*e.seed+12345)%2147483647))/1073741823,done:!1}});r({target:"Math",stat:!0,forced:!0},{seededPRNG:function(e){var t=i(e).seed;if(!a(t))throw TypeError(d);return new h(t)}})},44299(e,t,n){n(82109)({target:"Math",stat:!0},{signbit:function(e){return(e=+e)==e&&0==e?1/e==-1/0:e<0}})},5162(e,t,n){n(82109)({target:"Math",stat:!0},{umulh:function(e,t){var n=65535,r=+e,i=+t,a=r&n,o=i&n,s=r>>>16,u=i>>>16,c=(s*o>>>0)+(a*o>>>16);return s*u+(c>>>16)+((a*u>>>0)+(c&n)>>>16)}})},50292(e,t,n){"use strict";var r=n(82109),i=n(99958),a=n(83009),o="Invalid number representation",s="Invalid radix",u=/^[\da-z]+$/;r({target:"Number",stat:!0},{fromString:function(e,t){var n,r,c=1;if("string"!=typeof e)throw TypeError(o);if(!e.length||"-"==e.charAt(0)&&(c=-1,!(e=e.slice(1)).length))throw SyntaxError(o);if((n=void 0===t?10:i(t))<2||n>36)throw RangeError(s);if(!u.test(e)||(r=a(e,n)).toString(n)!==e)throw SyntaxError(o);return c*r}})},29427(e,t,n){"use strict";var r=n(82109),i=n(80430);r({target:"Number",stat:!0},{range:function(e,t,n){return new i(e,t,n,"number",0,1)}})},96936(e,t,n){n(46314)},99964(e,t,n){"use strict";var r=n(82109),i=n(60996);r({target:"Object",stat:!0},{iterateEntries:function(e){return new i(e,"entries")}})},75238(e,t,n){"use strict";var r=n(82109),i=n(60996);r({target:"Object",stat:!0},{iterateKeys:function(e){return new i(e,"keys")}})},4987(e,t,n){"use strict";var r=n(82109),i=n(60996);r({target:"Object",stat:!0},{iterateValues:function(e){return new i(e,"values")}})},1025(e,t,n){"use strict";var r=n(82109),i=n(19781),a=n(96340),o=n(13099),s=n(19670),u=n(70111),c=n(25787),l=n(3070).f,f=n(68880),d=n(12248),h=n(18554),p=n(58173),b=n(20408),m=n(842),g=n(5112),v=n(29909),y=g("observable"),w=v.get,_=v.set,E=function(e){var t=e.cleanup;if(t){e.cleanup=void 0;try{t()}catch(n){m(n)}}},S=function(e){return void 0===e.observer},k=function(e){var t=e.facade;if(!i){t.closed=!0;var n=e.subscriptionObserver;n&&(n.closed=!0)}e.observer=void 0},x=function(e,t){var n,r=_(this,{cleanup:void 0,observer:s(e),subscriptionObserver:void 0});i||(this.closed=!1);try{(n=p(e.start))&&n.call(e,this)}catch(a){m(a)}if(!S(r)){var u=r.subscriptionObserver=new T(this);try{var c=t(u),l=c;null!=c&&(r.cleanup="function"==typeof c.unsubscribe?function(){l.unsubscribe()}:o(c))}catch(f){u.error(f);return}S(r)&&E(r)}};x.prototype=d({},{unsubscribe:function(){var e=w(this);S(e)||(k(e),E(e))}}),i&&l(x.prototype,"closed",{configurable:!0,get:function(){return S(w(this))}});var T=function(e){_(this,{subscription:e}),i||(this.closed=!1)};T.prototype=d({},{next:function(e){var t=w(w(this).subscription);if(!S(t)){var n=t.observer;try{var r=p(n.next);r&&r.call(n,e)}catch(i){m(i)}}},error:function(e){var t=w(w(this).subscription);if(!S(t)){var n=t.observer;k(t);try{var r=p(n.error);r?r.call(n,e):m(e)}catch(i){m(i)}E(t)}},complete:function(){var e=w(w(this).subscription);if(!S(e)){var t=e.observer;k(e);try{var n=p(t.complete);n&&n.call(t)}catch(r){m(r)}E(e)}}}),i&&l(T.prototype,"closed",{configurable:!0,get:function(){return S(w(w(this).subscription))}});var M=function(e){c(this,M,"Observable"),_(this,{subscriber:o(e)})};d(M.prototype,{subscribe:function(e){var t=arguments.length;return new x("function"==typeof e?{next:e,error:t>1?arguments[1]:void 0,complete:t>2?arguments[2]:void 0}:u(e)?e:{},w(this).subscriber)}}),d(M,{from:function(e){var t="function"==typeof this?this:M,n=p(s(e)[y]);if(n){var r=s(n.call(e));return r.constructor===t?r:new t(function(e){return r.subscribe(e)})}var i=h(e);return new t(function(e){b(i,function(t,n){if(e.next(t),e.closed)return n()},{IS_ITERATOR:!0,INTERRUPTED:!0}),e.complete()})},of:function(){for(var e="function"==typeof this?this:M,t=arguments.length,n=Array(t),r=0;r1?arguments[1]:void 0,3);return!u(n,function(e,n){if(!r(e,e,t))return n()},{IS_ITERATOR:!0,INTERRUPTED:!0}).stopped}})},64362(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(49974),c=n(36707),l=n(96767),f=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{filter:function(e){var t=o(this),n=l(t),r=u(e,arguments.length>1?arguments[1]:void 0,3),i=new(c(t,a("Set"))),d=s(i.add);return f(n,function(e){r(e,e,t)&&d.call(i,e)},{IS_ITERATOR:!0}),i}})},15389(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(49974),s=n(96767),u=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{find:function(e){var t=a(this),n=s(t),r=o(e,arguments.length>1?arguments[1]:void 0,3);return u(n,function(e,n){if(r(e,e,t))return n(e)},{IS_ITERATOR:!0,INTERRUPTED:!0}).result}})},46006(e,t,n){var r=n(82109),i=n(27296);r({target:"Set",stat:!0},{from:i})},90401(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(36707),c=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{intersection:function(e){var t=o(this),n=new(u(t,a("Set"))),r=s(t.has),i=s(n.add);return c(e,function(e){r.call(t,e)&&i.call(n,e)}),n}})},45164(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(13099),s=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{isDisjointFrom:function(e){var t=a(this),n=o(t.has);return!s(e,function(e,r){if(!0===n.call(t,e))return r()},{INTERRUPTED:!0}).stopped}})},91238(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(18554),c=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{isSubsetOf:function(e){var t=u(this),n=o(e),r=n.has;return"function"!=typeof r&&(n=new(a("Set"))(e),r=s(n.has)),!c(t,function(e,t){if(!1===r.call(n,e))return t()},{IS_ITERATOR:!0,INTERRUPTED:!0}).stopped}})},54837(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(13099),s=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{isSupersetOf:function(e){var t=a(this),n=o(t.has);return!s(e,function(e,r){if(!1===n.call(t,e))return r()},{INTERRUPTED:!0}).stopped}})},87485(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(96767),s=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{join:function(e){var t=a(this),n=o(t),r=void 0===e?",":String(e),i=[];return s(n,i.push,{that:i,IS_ITERATOR:!0}),i.join(r)}})},56767(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(49974),c=n(36707),l=n(96767),f=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{map:function(e){var t=o(this),n=l(t),r=u(e,arguments.length>1?arguments[1]:void 0,3),i=new(c(t,a("Set"))),d=s(i.add);return f(n,function(e){d.call(i,r(e,e,t))},{IS_ITERATOR:!0}),i}})},69916(e,t,n){var r=n(82109),i=n(82044);r({target:"Set",stat:!0},{of:i})},76651(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(13099),s=n(96767),u=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{reduce:function(e){var t=a(this),n=s(t),r=arguments.length<2,i=r?void 0:arguments[1];if(o(e),u(n,function(n){r?(r=!1,i=n):i=e(i,n,n,t)},{IS_ITERATOR:!0}),r)throw TypeError("Reduce of empty set with no initial value");return i}})},61437(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(19670),o=n(49974),s=n(96767),u=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{some:function(e){var t=a(this),n=s(t),r=o(e,arguments.length>1?arguments[1]:void 0,3);return u(n,function(e,n){if(r(e,e,t))return n()},{IS_ITERATOR:!0,INTERRUPTED:!0}).stopped}})},35285(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(36707),c=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{symmetricDifference:function(e){var t=o(this),n=new(u(t,a("Set")))(t),r=s(n.delete),i=s(n.add);return c(e,function(e){r.call(n,e)||i.call(n,e)}),n}})},39865(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(35005),o=n(19670),s=n(13099),u=n(36707),c=n(20408);r({target:"Set",proto:!0,real:!0,forced:i},{union:function(e){var t=o(this),n=new(u(t,a("Set")))(t);return c(e,s(n.add),{that:n}),n}})},86035(e,t,n){"use strict";var r=n(82109),i=n(28710).charAt,a=n(47293)(function(){return"𠮷"!=="𠮷".at(0)});r({target:"String",proto:!0,forced:a},{at:function(e){return i(this,e)}})},67501(e,t,n){"use strict";var r=n(82109),i=n(24994),a=n(84488),o=n(41340),s=n(29909),u=n(28710),c=u.codeAt,l=u.charAt,f="String Iterator",d=s.set,h=s.getterFor(f),p=i(function(e){d(this,{type:f,string:e,index:0})},"String",function(){var e,t=h(this),n=t.string,r=t.index;return r>=n.length?{value:void 0,done:!0}:(e=l(n,r),t.index+=e.length,{value:{codePoint:c(e,0),position:r},done:!1})});r({target:"String",proto:!0},{codePoints:function(){return new p(o(a(this)))}})},13728(e,t,n){n(76373)},27207(e,t,n){n(68757)},609(e,t,n){n(97235)("asyncDispose")},21568(e,t,n){n(97235)("dispose")},54534(e,t,n){n(97235)("matcher")},95090(e,t,n){n(97235)("metadata")},48824(e,t,n){n(97235)("observable")},44130(e,t,n){n(97235)("patternMatch")},35954(e,t,n){n(97235)("replaceAll")},38012(e,t,n){n(48675)},26182(e,t,n){"use strict";var r=n(90260),i=n(42092).filterReject,a=n(43074),o=r.aTypedArray;(0,r.exportTypedArrayMethod)("filterOut",function(e){var t=i(o(this),e,arguments.length>1?arguments[1]:void 0);return a(this,t)})},8922(e,t,n){"use strict";var r=n(90260),i=n(42092).filterReject,a=n(43074),o=r.aTypedArray;(0,r.exportTypedArrayMethod)("filterReject",function(e){var t=i(o(this),e,arguments.length>1?arguments[1]:void 0);return a(this,t)})},1118(e,t,n){"use strict";var r=n(90260),i=n(9671).findLastIndex,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("findLastIndex",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},37380(e,t,n){"use strict";var r=n(90260),i=n(9671).findLast,a=r.aTypedArray;(0,r.exportTypedArrayMethod)("findLast",function(e){return i(a(this),e,arguments.length>1?arguments[1]:void 0)})},5835(e,t,n){"use strict";var r=n(90260),i=n(61386),a=n(66304),o=r.aTypedArray;(0,r.exportTypedArrayMethod)("groupBy",function(e){var t=arguments.length>1?arguments[1]:void 0;return i(o(this),e,t,a)})},84444(e,t,n){"use strict";var r=n(90260),i=n(60956),a=n(43074),o=r.aTypedArray;(0,r.exportTypedArrayMethod)("uniqueBy",function(e){return a(this,i.call(o(this),e))})},78206(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(34092);r({target:"WeakMap",proto:!0,real:!0,forced:i},{deleteAll:function(){return a.apply(this,arguments)}})},12714(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(37502);r({target:"WeakMap",proto:!0,real:!0,forced:i},{emplace:a})},76478(e,t,n){var r=n(82109),i=n(27296);r({target:"WeakMap",stat:!0},{from:i})},79715(e,t,n){var r=n(82109),i=n(82044);r({target:"WeakMap",stat:!0},{of:i})},5964(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(8154);r({target:"WeakMap",proto:!0,real:!0,forced:i},{upsert:a})},43561(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(31501);r({target:"WeakSet",proto:!0,real:!0,forced:i},{addAll:function(){return a.apply(this,arguments)}})},32049(e,t,n){"use strict";var r=n(82109),i=n(31913),a=n(34092);r({target:"WeakSet",proto:!0,real:!0,forced:i},{deleteAll:function(){return a.apply(this,arguments)}})},86020(e,t,n){var r=n(82109),i=n(27296);r({target:"WeakSet",stat:!0},{from:i})},56585(e,t,n){var r=n(82109),i=n(82044);r({target:"WeakSet",stat:!0},{of:i})},54747(e,t,n){var r=n(17854),i=n(48324),a=n(18533),o=n(68880);for(var s in i){var u=r[s],c=u&&u.prototype;if(c&&c.forEach!==a)try{o(c,"forEach",a)}catch(l){c.forEach=a}}},33948(e,t,n){var r=n(17854),i=n(48324),a=n(66992),o=n(68880),s=n(5112),u=s("iterator"),c=s("toStringTag"),l=a.values;for(var f in i){var d=r[f],h=d&&d.prototype;if(h){if(h[u]!==l)try{o(h,u,l)}catch(p){h[u]=l}if(h[c]||o(h,c,f),i[f]){for(var b in a)if(h[b]!==a[b])try{o(h,b,a[b])}catch(m){h[b]=a[b]}}}}},84633(e,t,n){var r=n(82109),i=n(17854),a=n(20261);r({global:!0,bind:!0,enumerable:!0,forced:!i.setImmediate||!i.clearImmediate},{setImmediate:a.set,clearImmediate:a.clear})},85844(e,t,n){var r=n(82109),i=n(17854),a=n(95948),o=n(35268),s=i.process;r({global:!0,enumerable:!0,noTargetGet:!0},{queueMicrotask:function(e){var t=o&&s.domain;a(t?t.bind(e):e)}})},32564(e,t,n){var r=n(82109),i=n(17854),a=n(88113),o=[].slice,s=/MSIE .\./.test(a),u=function(e){return function(t,n){var r=arguments.length>2,i=r?o.call(arguments,2):void 0;return e(r?function(){("function"==typeof t?t:Function(t)).apply(this,i)}:t,n)}};r({global:!0,bind:!0,forced:s},{setTimeout:u(i.setTimeout),setInterval:u(i.setInterval)})},41637(e,t,n){"use strict";n(66992);var r=n(82109),i=n(35005),a=n(590),o=n(31320),s=n(12248),u=n(58003),c=n(24994),l=n(29909),f=n(25787),d=n(86656),h=n(49974),p=n(70648),b=n(19670),m=n(70111),g=n(41340),v=n(70030),y=n(79114),w=n(18554),_=n(71246),E=n(5112),S=i("fetch"),k=i("Request"),x=k&&k.prototype,T=i("Headers"),M=E("iterator"),O="URLSearchParams",A=O+"Iterator",L=l.set,C=l.getterFor(O),I=l.getterFor(A),D=/\+/g,N=[,,,,],P=function(e){return N[e-1]||(N[e-1]=RegExp("((?:%[\\da-f]{2}){"+e+"})","gi"))},R=function(e){try{return decodeURIComponent(e)}catch(t){return e}},j=function(e){var t=e.replace(D," "),n=4;try{return decodeURIComponent(t)}catch(r){for(;n;)t=t.replace(P(n--),R);return t}},F=/[!'()~]|%20/g,Y={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"},B=function(e){return Y[e]},U=function(e){return encodeURIComponent(e).replace(F,B)},H=function(e,t){if(t)for(var n,r,i=t.split("&"),a=0;a0?arguments[0]:void 0,l=this,h=[];if(L(l,{type:O,entries:h,updateURL:function(){},updateSearchParams:$}),void 0!==c){if(m(c)){if("function"==typeof(e=_(c)))for(n=(t=w(c,e)).next;!(r=n.call(t)).done;){if((o=(a=(i=w(b(r.value))).next).call(i)).done||(s=a.call(i)).done||!a.call(i).done)throw TypeError("Expected sequence with length 2");h.push({key:g(o.value),value:g(s.value)})}else for(u in c)d(c,u)&&h.push({key:u,value:g(c[u])})}else H(h,"string"==typeof c?"?"===c.charAt(0)?c.slice(1):c:g(c))}},K=W.prototype;if(s(K,{append:function(e,t){z(arguments.length,2);var n=C(this);n.entries.push({key:g(e),value:g(t)}),n.updateURL()},delete:function(e){z(arguments.length,1);for(var t=C(this),n=t.entries,r=g(e),i=0;ie.key){i.splice(t,0,e);break}t===n&&i.push(e)}r.updateURL()},forEach:function(e){for(var t,n=C(this).entries,r=h(e,arguments.length>1?arguments[1]:void 0,3),i=0;i1?V(arguments[1]):{})}}),"function"==typeof k){var q=function(e){return f(this,q,"Request"),new k(e,arguments.length>1?V(arguments[1]):{})};x.constructor=q,q.prototype=x,r({global:!0,forced:!0},{Request:q})}}e.exports={URLSearchParams:W,getState:C}},60285(e,t,n){"use strict";n(78783);var r,i=n(82109),a=n(19781),o=n(590),s=n(17854),u=n(36048),c=n(31320),l=n(25787),f=n(86656),d=n(21574),h=n(48457),p=n(28710).codeAt,b=n(33197),m=n(41340),g=n(58003),v=n(41637),y=n(29909),w=s.URL,_=v.URLSearchParams,E=v.getState,S=y.set,k=y.getterFor("URL"),x=Math.floor,T=Math.pow,M="Invalid authority",O="Invalid scheme",A="Invalid host",L="Invalid port",C=/[A-Za-z]/,I=/[\d+-.A-Za-z]/,D=/\d/,N=/^0x/i,P=/^[0-7]+$/,R=/^\d+$/,j=/^[\dA-Fa-f]+$/,F=/[\0\t\n\r #%/:<>?@[\\\]^|]/,Y=/[\0\t\n\r #/:<>?@[\\\]^|]/,B=/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g,U=/[\t\n\r]/g,H=function(e,t){var n,r,i;if("["==t.charAt(0)){if("]"!=t.charAt(t.length-1)||!(n=z(t.slice(1,-1))))return A;e.host=n}else if(Q(e)){if(t=b(t),F.test(t)||null===(n=$(t)))return A;e.host=n}else{if(Y.test(t))return A;for(i=0,n="",r=h(t);i4)return e;for(r=0,n=[];r1&&"0"==i.charAt(0)&&(a=N.test(i)?16:8,i=i.slice(8==a?1:2)),""===i)o=0;else{if(!(10==a?R:8==a?P:j).test(i))return e;o=parseInt(i,a)}n.push(o)}for(r=0;r=T(256,5-t))return null}else if(o>255)return null;for(r=0,s=n.pop();r6))return;for(r=0;d();){if(i=null,r>0){if("."!=d()||!(r<4))return;f++}if(!D.test(d()))return;for(;D.test(d());){if(a=parseInt(d(),10),null===i)i=a;else{if(0==i)return;i=10*i+a}if(i>255)return;f++}u[c]=256*u[c]+i,(2==++r||4==r)&&c++}if(4!=r)return;break}if(":"==d()){if(f++,!d())return}else if(d())return;u[c++]=t}if(null!==l)for(o=c-l,c=7;0!=c&&o>0;)s=u[c],u[c--]=u[l+o-1],u[l+--o]=s;else if(8!=c)return;return u},G=function(e){for(var t=null,n=1,r=null,i=0,a=0;a<8;a++)0!==e[a]?(i>n&&(t=r,n=i),r=null,i=0):(null===r&&(r=a),++i);return i>n&&(t=r,n=i),t},W=function(e){var t,n,r,i;if("number"==typeof e){for(n=0,t=[];n<4;n++)t.unshift(e%256),e=x(e/256);return t.join(".")}if("object"==typeof e){for(n=0,t="",r=G(e);n<8;n++)(!i||0!==e[n])&&(i&&(i=!1),r===n?(t+=n?":":"::",i=!0):(t+=e[n].toString(16),n<7&&(t+=":")));return"["+t+"]"}return e},K={},V=d({},K,{" ":1,'"':1,"<":1,">":1,"`":1}),q=d({},V,{"#":1,"?":1,"{":1,"}":1}),Z=d({},q,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),X=function(e,t){var n=p(e,0);return n>32&&n<127&&!f(t,e)?e:encodeURIComponent(e)},J={ftp:21,file:null,http:80,https:443,ws:80,wss:443},Q=function(e){return f(J,e.scheme)},ee=function(e){return""!=e.username||""!=e.password},et=function(e){return!e.host||e.cannotBeABaseURL||"file"==e.scheme},en=function(e,t){var n;return 2==e.length&&C.test(e.charAt(0))&&(":"==(n=e.charAt(1))||!t&&"|"==n)},er=function(e){var t;return e.length>1&&en(e.slice(0,2))&&(2==e.length||"/"===(t=e.charAt(2))||"\\"===t||"?"===t||"#"===t)},ei=function(e){var t=e.path,n=t.length;n&&("file"!=e.scheme||1!=n||!en(t[0],!0))&&t.pop()},ea=function(e){return"."===e||"%2e"===e.toLowerCase()},eo=function(e){return".."===(e=e.toLowerCase())||"%2e."===e||".%2e"===e||"%2e%2e"===e},es={},eu={},ec={},el={},ef={},ed={},eh={},ep={},eb={},em={},eg={},ev={},ey={},ew={},e_={},eE={},eS={},ek={},ex={},eT={},eM={},eO=function(e,t,n,i){var a,o,s,u,c=n||es,l=0,d="",p=!1,b=!1,m=!1;for(n||(e.scheme="",e.username="",e.password="",e.host=null,e.port=null,e.path=[],e.query=null,e.fragment=null,e.cannotBeABaseURL=!1,t=t.replace(B,"")),t=t.replace(U,""),a=h(t);l<=a.length;){switch(o=a[l],c){case es:if(o&&C.test(o))d+=o.toLowerCase(),c=eu;else{if(n)return O;c=ec;continue}break;case eu:if(o&&(I.test(o)||"+"==o||"-"==o||"."==o))d+=o.toLowerCase();else if(":"==o){if(n&&(Q(e)!=f(J,d)||"file"==d&&(ee(e)||null!==e.port)||"file"==e.scheme&&!e.host))return;if(e.scheme=d,n){Q(e)&&J[e.scheme]==e.port&&(e.port=null);return}d="","file"==e.scheme?c=ew:Q(e)&&i&&i.scheme==e.scheme?c=el:Q(e)?c=ep:"/"==a[l+1]?(c=ef,l++):(e.cannotBeABaseURL=!0,e.path.push(""),c=ex)}else{if(n)return O;d="",c=ec,l=0;continue}break;case ec:if(!i||i.cannotBeABaseURL&&"#"!=o)return O;if(i.cannotBeABaseURL&&"#"==o){e.scheme=i.scheme,e.path=i.path.slice(),e.query=i.query,e.fragment="",e.cannotBeABaseURL=!0,c=eM;break}c="file"==i.scheme?ew:ed;continue;case el:if("/"==o&&"/"==a[l+1])c=eb,l++;else{c=ed;continue}break;case ef:if("/"==o){c=em;break}c=ek;continue;case ed:if(e.scheme=i.scheme,o==r)e.username=i.username,e.password=i.password,e.host=i.host,e.port=i.port,e.path=i.path.slice(),e.query=i.query;else if("/"==o||"\\"==o&&Q(e))c=eh;else if("?"==o)e.username=i.username,e.password=i.password,e.host=i.host,e.port=i.port,e.path=i.path.slice(),e.query="",c=eT;else if("#"==o)e.username=i.username,e.password=i.password,e.host=i.host,e.port=i.port,e.path=i.path.slice(),e.query=i.query,e.fragment="",c=eM;else{e.username=i.username,e.password=i.password,e.host=i.host,e.port=i.port,e.path=i.path.slice(),e.path.pop(),c=ek;continue}break;case eh:if(Q(e)&&("/"==o||"\\"==o))c=eb;else if("/"==o)c=em;else{e.username=i.username,e.password=i.password,e.host=i.host,e.port=i.port,c=ek;continue}break;case ep:if(c=eb,"/"!=o||"/"!=d.charAt(l+1))continue;l++;break;case eb:if("/"!=o&&"\\"!=o){c=em;continue}break;case em:if("@"==o){p&&(d="%40"+d),p=!0,s=h(d);for(var g=0;g65535)return L;e.port=Q(e)&&w===J[e.scheme]?null:w,d=""}if(n)return;c=eS;continue}break;case ew:if(e.scheme="file","/"==o||"\\"==o)c=e_;else if(i&&"file"==i.scheme){if(o==r)e.host=i.host,e.path=i.path.slice(),e.query=i.query;else if("?"==o)e.host=i.host,e.path=i.path.slice(),e.query="",c=eT;else if("#"==o)e.host=i.host,e.path=i.path.slice(),e.query=i.query,e.fragment="",c=eM;else{er(a.slice(l).join(""))||(e.host=i.host,e.path=i.path.slice(),ei(e)),c=ek;continue}}else{c=ek;continue}break;case e_:if("/"==o||"\\"==o){c=eE;break}i&&"file"==i.scheme&&!er(a.slice(l).join(""))&&(en(i.path[0],!0)?e.path.push(i.path[0]):e.host=i.host),c=ek;continue;case eE:if(o==r||"/"==o||"\\"==o||"?"==o||"#"==o){if(!n&&en(d))c=ek;else if(""==d){if(e.host="",n)return;c=eS}else{if(u=H(e,d))return u;if("localhost"==e.host&&(e.host=""),n)return;d="",c=eS}continue}d+=o;break;case eS:if(Q(e)){if(c=ek,"/"!=o&&"\\"!=o)continue}else if(n||"?"!=o){if(n||"#"!=o){if(o!=r&&(c=ek,"/"!=o))continue}else e.fragment="",c=eM}else e.query="",c=eT;break;case ek:if(o==r||"/"==o||"\\"==o&&Q(e)||!n&&("?"==o||"#"==o)){if(eo(d)?(ei(e),"/"==o||"\\"==o&&Q(e)||e.path.push("")):ea(d)?"/"==o||"\\"==o&&Q(e)||e.path.push(""):("file"==e.scheme&&!e.path.length&&en(d)&&(e.host&&(e.host=""),d=d.charAt(0)+":"),e.path.push(d)),d="","file"==e.scheme&&(o==r||"?"==o||"#"==o))for(;e.path.length>1&&""===e.path[0];)e.path.shift();"?"==o?(e.query="",c=eT):"#"==o&&(e.fragment="",c=eM)}else d+=X(o,q);break;case ex:"?"==o?(e.query="",c=eT):"#"==o?(e.fragment="",c=eM):o!=r&&(e.path[0]+=X(o,K));break;case eT:n||"#"!=o?o!=r&&("'"==o&&Q(e)?e.query+="%27":"#"==o?e.query+="%23":e.query+=X(o,K)):(e.fragment="",c=eM);break;case eM:o!=r&&(e.fragment+=X(o,V))}l++}},eA=function(e){var t,n,r=l(this,eA,"URL"),i=arguments.length>1?arguments[1]:void 0,o=m(e),s=S(r,{type:"URL"});if(void 0!==i){if(i instanceof eA)t=k(i);else if(n=eO(t={},m(i)))throw TypeError(n)}if(n=eO(s,o,null,t))throw TypeError(n);var u=s.searchParams=new _,c=E(u);c.updateSearchParams(s.query),c.updateURL=function(){s.query=String(u)||null},a||(r.href=eC.call(r),r.origin=eI.call(r),r.protocol=eD.call(r),r.username=eN.call(r),r.password=eP.call(r),r.host=eR.call(r),r.hostname=ej.call(r),r.port=eF.call(r),r.pathname=eY.call(r),r.search=eB.call(r),r.searchParams=eU.call(r),r.hash=eH.call(r))},eL=eA.prototype,eC=function(){var e=k(this),t=e.scheme,n=e.username,r=e.password,i=e.host,a=e.port,o=e.path,s=e.query,u=e.fragment,c=t+":";return null!==i?(c+="//",ee(e)&&(c+=n+(r?":"+r:"")+"@"),c+=W(i),null!==a&&(c+=":"+a)):"file"==t&&(c+="//"),c+=e.cannotBeABaseURL?o[0]:o.length?"/"+o.join("/"):"",null!==s&&(c+="?"+s),null!==u&&(c+="#"+u),c},eI=function(){var e=k(this),t=e.scheme,n=e.port;if("blob"==t)try{return new eA(t.path[0]).origin}catch(r){return"null"}return"file"!=t&&Q(e)?t+"://"+W(e.host)+(null!==n?":"+n:""):"null"},eD=function(){return k(this).scheme+":"},eN=function(){return k(this).username},eP=function(){return k(this).password},eR=function(){var e=k(this),t=e.host,n=e.port;return null===t?"":null===n?W(t):W(t)+":"+n},ej=function(){var e=k(this).host;return null===e?"":W(e)},eF=function(){var e=k(this).port;return null===e?"":String(e)},eY=function(){var e=k(this),t=e.path;return e.cannotBeABaseURL?t[0]:t.length?"/"+t.join("/"):""},eB=function(){var e=k(this).query;return e?"?"+e:""},eU=function(){return k(this).searchParams},eH=function(){var e=k(this).fragment;return e?"#"+e:""},e$=function(e,t){return{get:e,set:t,configurable:!0,enumerable:!0}};if(a&&u(eL,{href:e$(eC,function(e){var t=k(this),n=m(e),r=eO(t,n);if(r)throw TypeError(r);E(t.searchParams).updateSearchParams(t.query)}),origin:e$(eI),protocol:e$(eD,function(e){var t=k(this);eO(t,m(e)+":",es)}),username:e$(eN,function(e){var t=k(this),n=h(m(e));if(!et(t)){t.username="";for(var r=0;rc});var r={value:function(){}};function i(){for(var e,t=0,n=arguments.length,r={};t=0&&(n=e.slice(r+1),e=e.slice(0,r)),e&&!t.hasOwnProperty(e))throw Error("unknown type: "+e);return{type:e,name:n}})}function s(e,t){for(var n,r=0,i=e.length;r0)for(var n,r,i=Array(n),a=0;am,dragDisable:()=>u.Z,dragEnable:()=>u.D});var r=n(92626),i=n(25109),a=n(43095),o=n(94017),s=n(24793),u=n(44266),c=n(34299);function l(e){return function(){return e}}function f(e,t,n,r,i,a,o,s,u,c){this.target=e,this.type=t,this.subject=n,this.identifier=r,this.active=i,this.x=a,this.y=o,this.dx=s,this.dy=u,this._=c}function d(){return!i.B.ctrlKey&&!i.B.button}function h(){return this.parentNode}function p(e){return null==e?{x:i.B.x,y:i.B.y}:e}function b(){return navigator.maxTouchPoints||"ontouchstart"in this}function m(){var e,t,n,m,g=d,v=h,y=p,w=b,_={},E=(0,r.Z)("start","drag","end"),S=0,k=0;function x(e){e.on("mousedown.drag",T).filter(w).on("touchstart.drag",A).on("touchmove.drag",L).on("touchend.drag touchcancel.drag",C).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function T(){if(!m&&g.apply(this,arguments)){var r=I("mouse",v.apply(this,arguments),a.Z,this,arguments);r&&((0,o.Z)(i.B.view).on("mousemove.drag",M,!0).on("mouseup.drag",O,!0),(0,u.Z)(i.B.view),(0,c.r)(),n=!1,e=i.B.clientX,t=i.B.clientY,r("start"))}}function M(){if((0,c.Z)(),!n){var r=i.B.clientX-e,a=i.B.clientY-t;n=r*r+a*a>k}_.mouse("drag")}function O(){(0,o.Z)(i.B.view).on("mousemove.drag mouseup.drag",null),(0,u.D)(i.B.view,n),(0,c.Z)(),_.mouse("end")}function A(){if(g.apply(this,arguments)){var e,t,n=i.B.changedTouches,r=v.apply(this,arguments),a=n.length;for(e=0;eo,Z:()=>a});var r=n(94017),i=n(34299);function a(e){var t=e.document.documentElement,n=(0,r.Z)(e).on("dragstart.drag",i.Z,!0);"onselectstart"in t?n.on("selectstart.drag",i.Z,!0):(t.__noselect=t.style.MozUserSelect,t.style.MozUserSelect="none")}function o(e,t){var n=e.document.documentElement,a=(0,r.Z)(e).on("dragstart.drag",null);t&&(a.on("click.drag",i.Z,!0),setTimeout(function(){a.on("click.drag",null)},0)),"onselectstart"in n?a.on("selectstart.drag",null):(n.style.MozUserSelect=n.__noselect,delete n.__noselect)}},34299(e,t,n){"use strict";n.d(t,{Z:()=>a,r:()=>i});var r=n(25109);function i(){r.B.stopImmediatePropagation()}function a(){r.B.preventDefault(),r.B.stopImmediatePropagation()}},9893(e,t,n){"use strict";function r(e,t){var n;function r(){var r,i,a=n.length,o=0,s=0;for(r=0;r=(a=(b+g)/2))?b=a:g=a,(l=n>=(o=(m+v)/2))?m=o:v=o,i=h,!(h=h[f=l<<1|c]))return i[f]=p,e;if(s=+e._x.call(null,h.data),u=+e._y.call(null,h.data),t===s&&n===u)return p.next=h,i?i[f]=p:e._root=p,e;do i=i?i[f]=[,,,,]:e._root=[,,,,],(c=t>=(a=(b+g)/2))?b=a:g=a,(l=n>=(o=(m+v)/2))?m=o:v=o;while((f=l<<1|c)==(d=(u>=o)<<1|s>=a))return i[d]=h,i[f]=p,e}function u(e){var t,n,r,i,a=e.length,o=Array(a),u=Array(a),c=1/0,l=1/0,f=-1/0,d=-1/0;for(n=0;nf&&(f=r),id&&(d=i));if(c>f||l>d)return this;for(this.cover(c,l).cover(f,d),n=0;ne||e>=i||r>t||t>=a;)switch(s=(th)&&!((a=u.y0)>p)&&!((o=u.x1)=v)<<1|e>=g)&&(u=b[b.length-1],b[b.length-1]=b[b.length-1-c],b[b.length-1-c]=u)}else{var y=e-+this._x.call(null,m.data),w=t-+this._y.call(null,m.data),_=y*y+w*w;if(_=(s=(p+m)/2))?p=s:m=s,(l=o>=(u=(b+g)/2))?b=u:g=u,t=h,!(h=h[f=l<<1|c]))return this;if(!h.length)break;(t[f+1&3]||t[f+2&3]||t[f+3&3])&&(n=t,d=f)}for(;h.data!==e;)if(r=h,!(h=h.next))return this;return((i=h.next)&&delete h.next,r)?(i?r.next=i:delete r.next,this):t?(i?t[f]=i:delete t[f],(h=t[0]||t[1]||t[2]||t[3])&&h===(t[3]||t[2]||t[1]||t[0])&&!h.length&&(n?n[d]=h:this._root=h),this):(this._root=i,this)}function b(e){for(var t=0,n=e.length;tr,forceCollide:()=>L,forceLink:()=>B,forceManyBody:()=>V,forceRadial:()=>q,forceSimulation:()=>K,forceX:()=>Z,forceY:()=>X});var M=k.prototype=x.prototype;function O(e){return e.x+e.vx}function A(e){return e.y+e.vy}function L(e){var t,n,r=1,o=1;function s(){for(var e,i,s,c,l,f,d,h=t.length,p=0;ps.index){var b=c-u.x-u.vx,m=l-u.y-u.vy,g=b*b+m*m;gc+p||il+p||oe.r&&(e.r=e[t].r)}function c(){if(t){var r,i,a=t.length;for(r=0,n=Array(a);r1?(null==n?s.remove(e):s.set(e,h(n)),t):s.get(e)},find:function(t,n,r){var i,a,o,s,u,c=0,l=e.length;for(null==r?r=1/0:r*=r,c=0;c1?(c.on(e,n),t):c.on(e)}}}function V(){var e,t,n,r,o=i(-30),s=1,u=1/0,c=.81;function l(r){var i,a=e.length,o=k(e,$,z).visitAfter(d);for(n=r,i=0;i=u)){(e.data!==t||e.next)&&(0===f&&(p+=(f=a())*f),0===d&&(p+=(d=a())*d),ps});var r=n(73888),i=n(31986);function a(e){return function(){var t=this.ownerDocument,n=this.namespaceURI;return n===i.P&&t.documentElement.namespaceURI===i.P?t.createElement(e):t.createElementNS(n,e)}}function o(e){return function(){return this.ownerDocument.createElementNS(e.space,e.local)}}function s(e){var t=(0,r.Z)(e);return(t.local?o:a)(t)}},58556(e,t,n){"use strict";n.r(t),n.d(t,{clientPoint:()=>h.Z,create:()=>a,creator:()=>r.Z,customEvent:()=>S._H,event:()=>S.B,local:()=>s,matcher:()=>c.Z,mouse:()=>l.Z,namespace:()=>f.Z,namespaces:()=>d.Z,select:()=>i.Z,selectAll:()=>b,selection:()=>p.ZP,selector:()=>m.Z,selectorAll:()=>g.Z,style:()=>v.S,touch:()=>y.Z,touches:()=>_,window:()=>E.Z});var r=n(789),i=n(94017);function a(e){return(0,i.Z)((0,r.Z)(e).call(document.documentElement))}var o=0;function s(){return new u}function u(){this._="@"+(++o).toString(36)}u.prototype=s.prototype={constructor:u,get:function(e){for(var t=this._;!(t in e);)if(!(e=e.parentNode))return;return e[t]},set:function(e,t){return e[this._]=t},remove:function(e){return this._ in e&&delete e[this._]},toString:function(){return this._}};var c=n(3083),l=n(43095),f=n(73888),d=n(31986),h=n(42115),p=n(23817);function b(e){return"string"==typeof e?new p.Y1([document.querySelectorAll(e)],[document.documentElement]):new p.Y1([null==e?[]:e],p.Jz)}var m=n(82634),g=n(3545),v=n(49986),y=n(24793),w=n(45553);function _(e,t){null==t&&(t=(0,w.Z)().touches);for(var n=0,r=t?t.length:0,i=Array(r);nr})},43095(e,t,n){"use strict";n.d(t,{Z:()=>a});var r=n(45553),i=n(42115);function a(e){var t=(0,r.Z)();return t.changedTouches&&(t=t.changedTouches[0]),(0,i.Z)(e,t)}},73888(e,t,n){"use strict";n.d(t,{Z:()=>i});var r=n(31986);function i(e){var t=e+="",n=t.indexOf(":");return n>=0&&"xmlns"!==(t=e.slice(0,n))&&(e=e.slice(n+1)),r.Z.hasOwnProperty(t)?{space:r.Z[t],local:e}:e}},31986(e,t,n){"use strict";n.d(t,{P:()=>r,Z:()=>i});var r="http://www.w3.org/1999/xhtml";let i={svg:"http://www.w3.org/2000/svg",xhtml:r,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"}},42115(e,t,n){"use strict";function r(e,t){var n=e.ownerSVGElement||e;if(n.createSVGPoint){var r=n.createSVGPoint();return r.x=t.clientX,r.y=t.clientY,[(r=r.matrixTransform(e.getScreenCTM().inverse())).x,r.y]}var i=e.getBoundingClientRect();return[t.clientX-i.left-e.clientLeft,t.clientY-i.top-e.clientTop]}n.d(t,{Z:()=>r})},94017(e,t,n){"use strict";n.d(t,{Z:()=>i});var r=n(23817);function i(e){return"string"==typeof e?new r.Y1([[document.querySelector(e)]],[document.documentElement]):new r.Y1([[e]],r.Jz)}},23817(e,t,n){"use strict";n.d(t,{Y1:()=>eT,ZP:()=>eO,Jz:()=>ex});var r=n(82634);function i(e){"function"!=typeof e&&(e=(0,r.Z)(e));for(var t=this._groups,n=t.length,i=Array(n),a=0;a=k&&(k=S+1);!(E=y[k])&&++k=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this}function _(e){function t(t,n){return t&&n?e(t.__data__,n.__data__):!t-!n}e||(e=E);for(var n=this._groups,r=n.length,i=Array(r),a=0;at?1:e>=t?0:NaN}function S(){var e=arguments[0];return arguments[0]=this,e.apply(null,arguments),this}function k(){var e=Array(this.size()),t=-1;return this.each(function(){e[++t]=this}),e}function x(){for(var e=this._groups,t=0,n=e.length;t1?this.each((null==t?F:"function"==typeof t?B:Y)(e,t)):this.node()[e]}function H(e){return e.trim().split(/^|\s+/)}function $(e){return e.classList||new z(e)}function z(e){this._node=e,this._names=H(e.getAttribute("class")||"")}function G(e,t){for(var n=$(e),r=-1,i=t.length;++rthis._names.indexOf(e)&&(this._names.push(e),this._node.setAttribute("class",this._names.join(" ")))},remove:function(e){var t=this._names.indexOf(e);t>=0&&(this._names.splice(t,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(e){return this._names.indexOf(e)>=0}};var ec=n(789);function el(e){var t="function"==typeof e?e:(0,ec.Z)(e);return this.select(function(){return this.appendChild(t.apply(this,arguments))})}function ef(){return null}function ed(e,t){var n="function"==typeof e?e:(0,ec.Z)(e),i=null==t?ef:"function"==typeof t?t:(0,r.Z)(t);return this.select(function(){return this.insertBefore(n.apply(this,arguments),i.apply(this,arguments)||null)})}function eh(){var e=this.parentNode;e&&e.removeChild(this)}function ep(){return this.each(eh)}function eb(){var e=this.cloneNode(!1),t=this.parentNode;return t?t.insertBefore(e,this.nextSibling):e}function em(){var e=this.cloneNode(!0),t=this.parentNode;return t?t.insertBefore(e,this.nextSibling):e}function eg(e){return this.select(e?em:eb)}function ev(e){return arguments.length?this.property("__data__",e):this.node().__data__}var ey=n(25109),ew=n(85021);function e_(e,t,n){var r=(0,ew.Z)(e),i=r.CustomEvent;"function"==typeof i?i=new i(t,n):(i=r.document.createEvent("Event"),n?(i.initEvent(t,n.bubbles,n.cancelable),i.detail=n.detail):i.initEvent(t,!1,!1)),e.dispatchEvent(i)}function eE(e,t){return function(){return e_(this,e,t)}}function eS(e,t){return function(){return e_(this,e,t.apply(this,arguments))}}function ek(e,t){return this.each(("function"==typeof t?eS:eE)(e,t))}var ex=[null];function eT(e,t){this._groups=e,this._parents=t}function eM(){return new eT([[document.documentElement]],ex)}eT.prototype=eM.prototype={constructor:eT,select:i,selectAll:o,filter:u,data:m,enter:l,exit:g,join:v,merge:y,order:w,sort:_,call:S,nodes:k,node:x,size:T,empty:M,each:O,attr:R,style:j.Z,property:U,classed:Z,text:ee,html:ei,raise:eo,lower:eu,append:el,insert:ed,remove:ep,clone:eg,datum:ev,on:ey.ZP,dispatch:ek};let eO=eM},25109(e,t,n){"use strict";n.d(t,{B:()=>i,ZP:()=>l,_H:()=>f});var r={},i=null;function a(e,t,n){return e=o(e,t,n),function(t){var n=t.relatedTarget;n&&(n===this||8&n.compareDocumentPosition(this))||e.call(this,t)}}function o(e,t,n){return function(r){var a=i;i=r;try{e.call(this,this.__data__,t,n)}finally{i=a}}}function s(e){return e.trim().split(/^|\s+/).map(function(e){var t="",n=e.indexOf(".");return n>=0&&(t=e.slice(n+1),e=e.slice(0,n)),{type:e,name:t}})}function u(e){return function(){var t=this.__on;if(t){for(var n,r=0,i=-1,a=t.length;ru,Z:()=>s});var r=n(85021);function i(e){return function(){this.style.removeProperty(e)}}function a(e,t,n){return function(){this.style.setProperty(e,t,n)}}function o(e,t,n){return function(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(e):this.style.setProperty(e,r,n)}}function s(e,t,n){return arguments.length>1?this.each((null==t?i:"function"==typeof t?o:a)(e,t,null==n?"":n)):u(this.node(),e)}function u(e,t){return e.style.getPropertyValue(t)||(0,r.Z)(e).getComputedStyle(e,null).getPropertyValue(t)}},82634(e,t,n){"use strict";function r(){}function i(e){return null==e?r:function(){return this.querySelector(e)}}n.d(t,{Z:()=>i})},3545(e,t,n){"use strict";function r(){return[]}function i(e){return null==e?r:function(){return this.querySelectorAll(e)}}n.d(t,{Z:()=>i})},45553(e,t,n){"use strict";n.d(t,{Z:()=>i});var r=n(25109);function i(){for(var e,t=r.B;e=t.sourceEvent;)t=e;return t}},24793(e,t,n){"use strict";n.d(t,{Z:()=>a});var r=n(45553),i=n(42115);function a(e,t,n){arguments.length<3&&(n=t,t=(0,r.Z)().changedTouches);for(var a,o=0,s=t?t.length:0;or})},71098(e,t,n){"use strict";n.r(t),n.d(t,{arc:()=>C,area:()=>j,areaRadial:()=>W,curveBasis:()=>eM,curveBasisClosed:()=>eA,curveBasisOpen:()=>eC,curveBundle:()=>eD,curveCardinal:()=>eR,curveCardinalClosed:()=>eF,curveCardinalOpen:()=>eB,curveCatmullRom:()=>e$,curveCatmullRomClosed:()=>eG,curveCatmullRomOpen:()=>eK,curveLinear:()=>D,curveLinearClosed:()=>eq,curveMonotoneX:()=>e3,curveMonotoneY:()=>e4,curveNatural:()=>e9,curveStep:()=>e7,curveStepAfter:()=>tt,curveStepBefore:()=>te,line:()=>R,lineRadial:()=>G,linkHorizontal:()=>et,linkRadial:()=>er,linkVertical:()=>en,pie:()=>B,pointRadial:()=>K,radialArea:()=>W,radialLine:()=>G,stack:()=>ta,stackOffsetDiverging:()=>ts,stackOffsetExpand:()=>to,stackOffsetNone:()=>tn,stackOffsetSilhouette:()=>tu,stackOffsetWiggle:()=>tc,stackOrderAppearance:()=>tl,stackOrderAscending:()=>td,stackOrderDescending:()=>tp,stackOrderInsideOut:()=>tb,stackOrderNone:()=>tr,stackOrderReverse:()=>tm,symbol:()=>eS,symbolCircle:()=>ei,symbolCross:()=>ea,symbolDiamond:()=>eu,symbolSquare:()=>ep,symbolStar:()=>eh,symbolTriangle:()=>em,symbolWye:()=>e_,symbols:()=>eE});var r=Math.PI,i=2*r,a=1e-6,o=i-a;function s(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function u(){return new s}s.prototype=u.prototype={constructor:s,moveTo:function(e,t){this._+="M"+(this._x0=this._x1=+e)+","+(this._y0=this._y1=+t)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(e,t){this._+="L"+(this._x1=+e)+","+(this._y1=+t)},quadraticCurveTo:function(e,t,n,r){this._+="Q"+ +e+","+ +t+","+(this._x1=+n)+","+(this._y1=+r)},bezierCurveTo:function(e,t,n,r,i,a){this._+="C"+ +e+","+ +t+","+ +n+","+ +r+","+(this._x1=+i)+","+(this._y1=+a)},arcTo:function(e,t,n,i,o){e=+e,t=+t,n=+n,i=+i,o=+o;var s=this._x1,u=this._y1,c=n-e,l=i-t,f=s-e,d=u-t,h=f*f+d*d;if(o<0)throw Error("negative radius: "+o);if(null===this._x1)this._+="M"+(this._x1=e)+","+(this._y1=t);else if(h>a){if(Math.abs(d*c-l*f)>a&&o){var p=n-s,b=i-u,m=c*c+l*l,g=Math.sqrt(m),v=Math.sqrt(h),y=o*Math.tan((r-Math.acos((m+h-(p*p+b*b))/(2*g*v)))/2),w=y/v,_=y/g;Math.abs(w-1)>a&&(this._+="L"+(e+w*f)+","+(t+w*d)),this._+="A"+o+","+o+",0,0,"+ +(d*p>f*b)+","+(this._x1=e+_*c)+","+(this._y1=t+_*l)}else this._+="L"+(this._x1=e)+","+(this._y1=t)}},arc:function(e,t,n,s,u,c){e=+e,t=+t,n=+n,c=!!c;var l=n*Math.cos(s),f=n*Math.sin(s),d=e+l,h=t+f,p=1^c,b=c?s-u:u-s;if(n<0)throw Error("negative radius: "+n);null===this._x1?this._+="M"+d+","+h:(Math.abs(this._x1-d)>a||Math.abs(this._y1-h)>a)&&(this._+="L"+d+","+h),n&&(b<0&&(b=b%i+i),b>o?this._+="A"+n+","+n+",0,1,"+p+","+(e-l)+","+(t-f)+"A"+n+","+n+",0,1,"+p+","+(this._x1=d)+","+(this._y1=h):b>a&&(this._+="A"+n+","+n+",0,"+ +(b>=r)+","+p+","+(this._x1=e+n*Math.cos(u))+","+(this._y1=t+n*Math.sin(u))))},rect:function(e,t,n,r){this._+="M"+(this._x0=this._x1=+e)+","+(this._y0=this._y1=+t)+"h"+ +n+"v"+ +r+"h"+-n+"Z"},toString:function(){return this._}};let c=u;function l(e){return function(){return e}}var f=Math.abs,d=Math.atan2,h=Math.cos,p=Math.max,b=Math.min,m=Math.sin,g=Math.sqrt,v=1e-12,y=Math.PI,w=y/2,_=2*y;function E(e){return e>1?0:e<-1?y:Math.acos(e)}function S(e){return e>=1?w:e<=-1?-w:Math.asin(e)}function k(e){return e.innerRadius}function x(e){return e.outerRadius}function T(e){return e.startAngle}function M(e){return e.endAngle}function O(e){return e&&e.padAngle}function A(e,t,n,r,i,a,o,s){var u=n-e,c=r-t,l=o-i,f=s-a,d=f*u-l*c;if(!(d*dI*I+D*D&&(T=O,M=A),{cx:T,cy:M,x01:-l,y01:-f,x11:T*(i/S-1),y11:M*(i/S-1)}}function C(){var e=k,t=x,n=l(0),r=null,i=T,a=M,o=O,s=null;function u(){var u,l,p=+e.apply(this,arguments),k=+t.apply(this,arguments),x=i.apply(this,arguments)-w,T=a.apply(this,arguments)-w,M=f(T-x),O=T>x;if(s||(s=u=c()),kv){if(M>_-v)s.moveTo(k*h(x),k*m(x)),s.arc(0,0,k,x,T,!O),p>v&&(s.moveTo(p*h(T),p*m(T)),s.arc(0,0,p,T,x,O));else{var C,I,D=x,N=T,P=x,R=T,j=M,F=M,Y=o.apply(this,arguments)/2,B=Y>v&&(r?+r.apply(this,arguments):g(p*p+k*k)),U=b(f(k-p)/2,+n.apply(this,arguments)),H=U,$=U;if(B>v){var z=S(B/p*m(Y)),G=S(B/k*m(Y));(j-=2*z)>v?(z*=O?1:-1,P+=z,R-=z):(j=0,P=R=(x+T)/2),(F-=2*G)>v?(G*=O?1:-1,D+=G,N-=G):(F=0,D=N=(x+T)/2)}var W=k*h(D),K=k*m(D),V=p*h(R),q=p*m(R);if(U>v){var Z,X=k*h(N),J=k*m(N),Q=p*h(P),ee=p*m(P);if(Mv?$>v?(C=L(Q,ee,W,K,k,$,O),I=L(X,J,V,q,k,$,O),s.moveTo(C.cx+C.x01,C.cy+C.y01),$v&&j>v?H>v?(C=L(V,q,X,J,p,-H,O),I=L(W,K,Q,ee,p,-H,O),s.lineTo(C.cx+C.x01,C.cy+C.y01),H=f;--d)s.point(g[d],v[d]);s.lineEnd(),s.areaEnd()}}m&&(g[l]=+e(h,l,u),v[l]=+n(h,l,u),s.point(t?+t(h,l,u):g[l],r?+r(h,l,u):v[l]))}if(p)return s=null,p+""||null}function f(){return R().defined(i).curve(o).context(a)}return u.x=function(n){return arguments.length?(e="function"==typeof n?n:l(+n),t=null,u):e},u.x0=function(t){return arguments.length?(e="function"==typeof t?t:l(+t),u):e},u.x1=function(e){return arguments.length?(t=null==e?null:"function"==typeof e?e:l(+e),u):t},u.y=function(e){return arguments.length?(n="function"==typeof e?e:l(+e),r=null,u):n},u.y0=function(e){return arguments.length?(n="function"==typeof e?e:l(+e),u):n},u.y1=function(e){return arguments.length?(r=null==e?null:"function"==typeof e?e:l(+e),u):r},u.lineX0=u.lineY0=function(){return f().x(e).y(n)},u.lineY1=function(){return f().x(e).y(r)},u.lineX1=function(){return f().x(t).y(n)},u.defined=function(e){return arguments.length?(i="function"==typeof e?e:l(!!e),u):i},u.curve=function(e){return arguments.length?(o=e,null!=a&&(s=o(a)),u):o},u.context=function(e){return arguments.length?(null==e?a=s=null:s=o(a=e),u):a},u}function F(e,t){return te?1:t>=e?0:NaN}function Y(e){return e}function B(){var e=Y,t=F,n=null,r=l(0),i=l(_),a=l(0);function o(o){var s,u,c,l,f,d=o.length,h=0,p=Array(d),b=Array(d),m=+r.apply(this,arguments),g=Math.min(_,Math.max(-_,i.apply(this,arguments)-m)),v=Math.min(Math.abs(g)/d,a.apply(this,arguments)),y=v*(g<0?-1:1);for(s=0;s0&&(h+=f);for(null!=t?p.sort(function(e,n){return t(b[e],b[n])}):null!=n&&p.sort(function(e,t){return n(o[e],o[t])}),s=0,c=h?(g-d*y)/h:0;s0?f*c:0)+y,b[u]={data:o[u],index:s,value:f,startAngle:m,endAngle:l,padAngle:v};return b}return o.value=function(t){return arguments.length?(e="function"==typeof t?t:l(+t),o):e},o.sortValues=function(e){return arguments.length?(t=e,n=null,o):t},o.sort=function(e){return arguments.length?(n=e,t=null,o):n},o.startAngle=function(e){return arguments.length?(r="function"==typeof e?e:l(+e),o):r},o.endAngle=function(e){return arguments.length?(i="function"==typeof e?e:l(+e),o):i},o.padAngle=function(e){return arguments.length?(a="function"==typeof e?e:l(+e),o):a},o}I.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1,this._line?this._context.lineTo(e,t):this._context.moveTo(e,t);break;case 1:this._point=2;default:this._context.lineTo(e,t)}}};var U=$(D);function H(e){this._curve=e}function $(e){function t(t){return new H(e(t))}return t._curve=e,t}function z(e){var t=e.curve;return e.angle=e.x,delete e.x,e.radius=e.y,delete e.y,e.curve=function(e){return arguments.length?t($(e)):t()._curve},e}function G(){return z(R().curve(U))}function W(){var e=j().curve(U),t=e.curve,n=e.lineX0,r=e.lineX1,i=e.lineY0,a=e.lineY1;return e.angle=e.x,delete e.x,e.startAngle=e.x0,delete e.x0,e.endAngle=e.x1,delete e.x1,e.radius=e.y,delete e.y,e.innerRadius=e.y0,delete e.y0,e.outerRadius=e.y1,delete e.y1,e.lineStartAngle=function(){return z(n())},delete e.lineX0,e.lineEndAngle=function(){return z(r())},delete e.lineX1,e.lineInnerRadius=function(){return z(i())},delete e.lineY0,e.lineOuterRadius=function(){return z(a())},delete e.lineY1,e.curve=function(e){return arguments.length?t($(e)):t()._curve},e}function K(e,t){return[(t=+t)*Math.cos(e-=Math.PI/2),t*Math.sin(e)]}H.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(e,t){this._curve.point(t*Math.sin(e),-(t*Math.cos(e)))}};var V=Array.prototype.slice;function q(e){return e.source}function Z(e){return e.target}function X(e){var t=q,n=Z,r=N,i=P,a=null;function o(){var o,s=V.call(arguments),u=t.apply(this,s),l=n.apply(this,s);if(a||(a=o=c()),e(a,+r.apply(this,(s[0]=u,s)),+i.apply(this,s),+r.apply(this,(s[0]=l,s)),+i.apply(this,s)),o)return a=null,o+""||null}return o.source=function(e){return arguments.length?(t=e,o):t},o.target=function(e){return arguments.length?(n=e,o):n},o.x=function(e){return arguments.length?(r="function"==typeof e?e:l(+e),o):r},o.y=function(e){return arguments.length?(i="function"==typeof e?e:l(+e),o):i},o.context=function(e){return arguments.length?(a=null==e?null:e,o):a},o}function J(e,t,n,r,i){e.moveTo(t,n),e.bezierCurveTo(t=(t+r)/2,n,t,i,r,i)}function Q(e,t,n,r,i){e.moveTo(t,n),e.bezierCurveTo(t,n=(n+i)/2,r,n,r,i)}function ee(e,t,n,r,i){var a=K(t,n),o=K(t,n=(n+i)/2),s=K(r,n),u=K(r,i);e.moveTo(a[0],a[1]),e.bezierCurveTo(o[0],o[1],s[0],s[1],u[0],u[1])}function et(){return X(J)}function en(){return X(Q)}function er(){var e=X(ee);return e.angle=e.x,delete e.x,e.radius=e.y,delete e.y,e}let ei={draw:function(e,t){var n=Math.sqrt(t/y);e.moveTo(n,0),e.arc(0,0,n,0,_)}},ea={draw:function(e,t){var n=Math.sqrt(t/5)/2;e.moveTo(-3*n,-n),e.lineTo(-n,-n),e.lineTo(-n,-3*n),e.lineTo(n,-3*n),e.lineTo(n,-n),e.lineTo(3*n,-n),e.lineTo(3*n,n),e.lineTo(n,n),e.lineTo(n,3*n),e.lineTo(-n,3*n),e.lineTo(-n,n),e.lineTo(-3*n,n),e.closePath()}};var eo=Math.sqrt(1/3),es=2*eo;let eu={draw:function(e,t){var n=Math.sqrt(t/es),r=n*eo;e.moveTo(0,-n),e.lineTo(r,0),e.lineTo(0,n),e.lineTo(-r,0),e.closePath()}};var ec=.8908130915292852,el=Math.sin(y/10)/Math.sin(7*y/10),ef=Math.sin(_/10)*el,ed=-Math.cos(_/10)*el;let eh={draw:function(e,t){var n=Math.sqrt(t*ec),r=ef*n,i=ed*n;e.moveTo(0,-n),e.lineTo(r,i);for(var a=1;a<5;++a){var o=_*a/5,s=Math.cos(o),u=Math.sin(o);e.lineTo(u*n,-s*n),e.lineTo(s*r-u*i,u*r+s*i)}e.closePath()}},ep={draw:function(e,t){var n=Math.sqrt(t),r=-n/2;e.rect(r,r,n,n)}};var eb=Math.sqrt(3);let em={draw:function(e,t){var n=-Math.sqrt(t/(3*eb));e.moveTo(0,2*n),e.lineTo(-eb*n,-n),e.lineTo(eb*n,-n),e.closePath()}};var eg=-.5,ev=Math.sqrt(3)/2,ey=1/Math.sqrt(12),ew=(ey/2+1)*3;let e_={draw:function(e,t){var n=Math.sqrt(t/ew),r=n/2,i=n*ey,a=r,o=n*ey+n,s=-a,u=o;e.moveTo(r,i),e.lineTo(a,o),e.lineTo(s,u),e.lineTo(eg*r-ev*i,ev*r+eg*i),e.lineTo(eg*a-ev*o,ev*a+eg*o),e.lineTo(eg*s-ev*u,ev*s+eg*u),e.lineTo(eg*r+ev*i,eg*i-ev*r),e.lineTo(eg*a+ev*o,eg*o-ev*a),e.lineTo(eg*s+ev*u,eg*u-ev*s),e.closePath()}};var eE=[ei,ea,eu,ep,eh,em,e_];function eS(){var e=l(ei),t=l(64),n=null;function r(){var r;if(n||(n=r=c()),e.apply(this,arguments).draw(n,+t.apply(this,arguments)),r)return n=null,r+""||null}return r.type=function(t){return arguments.length?(e="function"==typeof t?t:l(t),r):e},r.size=function(e){return arguments.length?(t="function"==typeof e?e:l(+e),r):t},r.context=function(e){return arguments.length?(n=null==e?null:e,r):n},r}function ek(){}function ex(e,t,n){e._context.bezierCurveTo((2*e._x0+e._x1)/3,(2*e._y0+e._y1)/3,(e._x0+2*e._x1)/3,(e._y0+2*e._y1)/3,(e._x0+4*e._x1+t)/6,(e._y0+4*e._y1+n)/6)}function eT(e){this._context=e}function eM(e){return new eT(e)}function eO(e){this._context=e}function eA(e){return new eO(e)}function eL(e){this._context=e}function eC(e){return new eL(e)}function eI(e,t){this._basis=new eT(e),this._beta=t}eT.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:ex(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1,this._line?this._context.lineTo(e,t):this._context.moveTo(e,t);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:ex(this,e,t)}this._x0=this._x1,this._x1=e,this._y0=this._y1,this._y1=t}},eO.prototype={areaStart:ek,areaEnd:ek,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1,this._x2=e,this._y2=t;break;case 1:this._point=2,this._x3=e,this._y3=t;break;case 2:this._point=3,this._x4=e,this._y4=t,this._context.moveTo((this._x0+4*this._x1+e)/6,(this._y0+4*this._y1+t)/6);break;default:ex(this,e,t)}this._x0=this._x1,this._x1=e,this._y0=this._y1,this._y1=t}},eL.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var n=(this._x0+4*this._x1+e)/6,r=(this._y0+4*this._y1+t)/6;this._line?this._context.lineTo(n,r):this._context.moveTo(n,r);break;case 3:this._point=4;default:ex(this,e,t)}this._x0=this._x1,this._x1=e,this._y0=this._y1,this._y1=t}},eI.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var e=this._x,t=this._y,n=e.length-1;if(n>0)for(var r,i=e[0],a=t[0],o=e[n]-i,s=t[n]-a,u=-1;++u<=n;)r=u/n,this._basis.point(this._beta*e[u]+(1-this._beta)*(i+r*o),this._beta*t[u]+(1-this._beta)*(a+r*s));this._x=this._y=null,this._basis.lineEnd()},point:function(e,t){this._x.push(+e),this._y.push(+t)}};let eD=function e(t){function n(e){return 1===t?new eT(e):new eI(e,t)}return n.beta=function(t){return e(+t)},n}(.85);function eN(e,t,n){e._context.bezierCurveTo(e._x1+e._k*(e._x2-e._x0),e._y1+e._k*(e._y2-e._y0),e._x2+e._k*(e._x1-t),e._y2+e._k*(e._y1-n),e._x2,e._y2)}function eP(e,t){this._context=e,this._k=(1-t)/6}eP.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:eN(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1,this._line?this._context.lineTo(e,t):this._context.moveTo(e,t);break;case 1:this._point=2,this._x1=e,this._y1=t;break;case 2:this._point=3;default:eN(this,e,t)}this._x0=this._x1,this._x1=this._x2,this._x2=e,this._y0=this._y1,this._y1=this._y2,this._y2=t}};let eR=function e(t){function n(e){return new eP(e,0)}return n.tension=function(t){return e(+t)},n}(0);function ej(e,t){this._context=e,this._k=(1-t)/6}ej.prototype={areaStart:ek,areaEnd:ek,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1,this._x3=e,this._y3=t;break;case 1:this._point=2,this._context.moveTo(this._x4=e,this._y4=t);break;case 2:this._point=3,this._x5=e,this._y5=t;break;default:eN(this,e,t)}this._x0=this._x1,this._x1=this._x2,this._x2=e,this._y0=this._y1,this._y1=this._y2,this._y2=t}};let eF=function e(t){function n(e){return new ej(e,0)}return n.tension=function(t){return e(+t)},n}(0);function eY(e,t){this._context=e,this._k=(1-t)/6}eY.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:eN(this,e,t)}this._x0=this._x1,this._x1=this._x2,this._x2=e,this._y0=this._y1,this._y1=this._y2,this._y2=t}};let eB=function e(t){function n(e){return new eY(e,0)}return n.tension=function(t){return e(+t)},n}(0);function eU(e,t,n){var r=e._x1,i=e._y1,a=e._x2,o=e._y2;if(e._l01_a>v){var s=2*e._l01_2a+3*e._l01_a*e._l12_a+e._l12_2a,u=3*e._l01_a*(e._l01_a+e._l12_a);r=(r*s-e._x0*e._l12_2a+e._x2*e._l01_2a)/u,i=(i*s-e._y0*e._l12_2a+e._y2*e._l01_2a)/u}if(e._l23_a>v){var c=2*e._l23_2a+3*e._l23_a*e._l12_a+e._l12_2a,l=3*e._l23_a*(e._l23_a+e._l12_a);a=(a*c+e._x1*e._l23_2a-t*e._l12_2a)/l,o=(o*c+e._y1*e._l23_2a-n*e._l12_2a)/l}e._context.bezierCurveTo(r,i,a,o,e._x2,e._y2)}function eH(e,t){this._context=e,this._alpha=t}eH.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(e,t){if(e=+e,t=+t,this._point){var n=this._x2-e,r=this._y2-t;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(e,t):this._context.moveTo(e,t);break;case 1:this._point=2;break;case 2:this._point=3;default:eU(this,e,t)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=e,this._y0=this._y1,this._y1=this._y2,this._y2=t}};let e$=function e(t){function n(e){return t?new eH(e,t):new eP(e,0)}return n.alpha=function(t){return e(+t)},n}(.5);function ez(e,t){this._context=e,this._alpha=t}ez.prototype={areaStart:ek,areaEnd:ek,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(e,t){if(e=+e,t=+t,this._point){var n=this._x2-e,r=this._y2-t;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=e,this._y3=t;break;case 1:this._point=2,this._context.moveTo(this._x4=e,this._y4=t);break;case 2:this._point=3,this._x5=e,this._y5=t;break;default:eU(this,e,t)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=e,this._y0=this._y1,this._y1=this._y2,this._y2=t}};let eG=function e(t){function n(e){return t?new ez(e,t):new ej(e,0)}return n.alpha=function(t){return e(+t)},n}(.5);function eW(e,t){this._context=e,this._alpha=t}eW.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(e,t){if(e=+e,t=+t,this._point){var n=this._x2-e,r=this._y2-t;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:eU(this,e,t)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=e,this._y0=this._y1,this._y1=this._y2,this._y2=t}};let eK=function e(t){function n(e){return t?new eW(e,t):new eY(e,0)}return n.alpha=function(t){return e(+t)},n}(.5);function eV(e){this._context=e}function eq(e){return new eV(e)}function eZ(e){return e<0?-1:1}function eX(e,t,n){var r=e._x1-e._x0,i=t-e._x1,a=(e._y1-e._y0)/(r||i<0&&-0),o=(n-e._y1)/(i||r<0&&-0),s=(a*i+o*r)/(r+i);return(eZ(a)+eZ(o))*Math.min(Math.abs(a),Math.abs(o),.5*Math.abs(s))||0}function eJ(e,t){var n=e._x1-e._x0;return n?(3*(e._y1-e._y0)/n-t)/2:t}function eQ(e,t,n){var r=e._x0,i=e._y0,a=e._x1,o=e._y1,s=(a-r)/3;e._context.bezierCurveTo(r+s,i+s*t,a-s,o-s*n,a,o)}function e1(e){this._context=e}function e0(e){this._context=new e2(e)}function e2(e){this._context=e}function e3(e){return new e1(e)}function e4(e){return new e0(e)}function e5(e){this._context=e}function e6(e){var t,n,r=e.length-1,i=Array(r),a=Array(r),o=Array(r);for(i[0]=0,a[0]=2,o[0]=e[0]+2*e[1],t=1;t=0;--t)i[t]=(o[t]-i[t+1])/a[t];for(t=0,a[r-1]=(e[r]+i[r-1])/2;t1)for(var n,r,i,a=1,o=e[t[0]],s=o.length;a=0;)n[t]=t;return n}function ti(e,t){return e[t]}function ta(){var e=l([]),t=tr,n=tn,r=ti;function i(i){var a,o,s=e.apply(this,arguments),u=i.length,c=s.length,l=Array(c);for(a=0;a0){for(var n,r,i,a=0,o=e[0].length;a0)for(var n,r,i,a,o,s,u=0,c=e[t[0]].length;u0?(r[0]=a,r[1]=a+=i):i<0?(r[1]=o,r[0]=o+=i):(r[0]=0,r[1]=i)}function tu(e,t){if((n=e.length)>0){for(var n,r=0,i=e[t[0]],a=i.length;r0&&(r=(n=e[t[0]]).length)>0){for(var n,r,i,a=0,o=1;oa&&(a=t,r=n);return r}function td(e){var t=e.map(th);return tr(e).sort(function(e,n){return t[e]-t[n]})}function th(e){for(var t,n=0,r=-1,i=e.length;++r=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(e,t){switch(e=+e,t=+t,this._point){case 0:this._point=1,this._line?this._context.lineTo(e,t):this._context.moveTo(e,t);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,t),this._context.lineTo(e,t);else{var n=this._x*(1-this._t)+e*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,t)}}this._x=e,this._y=t}}},35374(e,t,n){"use strict";n.d(t,{B7:()=>m,HT:()=>g,zO:()=>p});var r,i,a=0,o=0,s=0,u=1e3,c=0,l=0,f=0,d="object"==typeof performance&&performance.now?performance:Date,h="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(e){setTimeout(e,17)};function p(){return l||(h(b),l=d.now()+f)}function b(){l=0}function m(){this._call=this._time=this._next=null}function g(e,t,n){var r=new m;return r.restart(e,t,n),r}function v(){p(),++a;for(var e,t=r;t;)(e=l-t._time)>=0&&t._call.call(null,e),t=t._next;--a}function y(){l=(c=d.now())+f,a=o=0;try{v()}finally{a=0,_(),l=0}}function w(){var e=d.now(),t=e-c;t>u&&(f-=t,c=e)}function _(){for(var e,t,n=r,a=1/0;n;)n._call?(a>n._time&&(a=n._time),e=n,n=n._next):(t=n._next,n._next=null,n=e?e._next=t:r=t);i=e,E(a)}function E(e){if(!a){var t;o&&(o=clearTimeout(o)),e-l>24?(e<1/0&&(o=setTimeout(y,e-d.now()-f)),s&&(s=clearInterval(s))):(s||(c=d.now(),s=setInterval(w,u)),a=1,h(y))}}m.prototype=g.prototype={constructor:m,restart:function(e,t,n){if("function"!=typeof e)throw TypeError("callback is not a function");n=(null==n?p():+n)+(null==t?0:+t),this._next||i===this||(i?i._next=this:r=this,i=this),this._call=e,this._time=n,E()},stop:function(){this._call&&(this._call=null,this._time=1/0,E())}}},76626(e,t,n){"use strict";n.r(t),n.d(t,{zoom:()=>t5,zoomIdentity:()=>tq,zoomTransform:()=>tZ});var r,i,a,o,s=n(92626),u=n(44266),c=Math.SQRT2,l=2,f=4,d=1e-12;function h(e){return((e=Math.exp(e))+1/e)/2}function p(e){return((e=Math.exp(e))-1/e)/2}function b(e){return((e=Math.exp(2*e))-1)/(e+1)}function m(e,t){var n,r,i=e[0],a=e[1],o=e[2],s=t[0],u=t[1],m=t[2],g=s-i,v=u-a,y=g*g+v*v;if(yT)throw Error("too late; already scheduled");return n}function P(e,t){var n=R(e,t);if(n.state>A)throw Error("too late; already running");return n}function R(e,t){var n=e.__transition;if(!n||!(n=n[t]))throw Error("transition not found");return n}function j(e,t,n){var r,i=e.__transition;function a(e){n.state=M,n.timer.restart(o,n.delay,n.time),n.delay<=e&&o(e-n.delay)}function o(a){var c,l,f,d;if(n.state!==M)return u();for(c in i)if((d=i[c]).name===n.name){if(d.state===A)return S(o);d.state===L?(d.state=I,d.timer.stop(),d.on.call("interrupt",e,e.__data__,d.index,d.group),delete i[c]):+cO&&n.state180?t+=360:t-e>180&&(e+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:B(e,t)})):t&&n.push(i(n)+"rotate("+t+r)}function s(e,t,n,a){e!==t?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:B(e,t)}):t&&n.push(i(n)+"skewX("+t+r)}function u(e,t,n,r,a,o){if(e!==n||t!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:B(e,n)},{i:s-2,x:B(t,r)})}else(1!==n||1!==r)&&a.push(i(a)+"scale("+n+","+r+")")}return function(t,n){var r=[],i=[];return t=e(t),n=e(n),a(t.translateX,t.translateY,n.translateX,n.translateY,r,i),o(t.rotate,n.rotate,r,i),s(t.skewX,n.skewX,r,i),u(t.scaleX,t.scaleY,n.scaleX,n.scaleY,r,i),t=n=null,function(e){for(var t,n=-1,a=i.length;++n>8&15|t>>4&240,t>>4&15|240&t,(15&t)<<4|15&t,1):8===n?e_(t>>24&255,t>>16&255,t>>8&255,(255&t)/255):4===n?e_(t>>12&15|t>>8&240,t>>8&15|t>>4&240,t>>4&15|240&t,((15&t)<<4|15&t)/255):null):(t=ec.exec(e))?new ek(t[1],t[2],t[3],1):(t=el.exec(e))?new ek(255*t[1]/100,255*t[2]/100,255*t[3]/100,1):(t=ef.exec(e))?e_(t[1],t[2],t[3],t[4]):(t=ed.exec(e))?e_(255*t[1]/100,255*t[2]/100,255*t[3]/100,t[4]):(t=eh.exec(e))?eO(t[1],t[2]/100,t[3]/100,1):(t=ep.exec(e))?eO(t[1],t[2]/100,t[3]/100,t[4]):eb.hasOwnProperty(e)?ew(eb[e]):"transparent"===e?new ek(NaN,NaN,NaN,0):null}function ew(e){return new ek(e>>16&255,e>>8&255,255&e,1)}function e_(e,t,n,r){return r<=0&&(e=t=n=NaN),new ek(e,t,n,r)}function eE(e){return(e instanceof en||(e=ey(e)),e)?(e=e.rgb(),new ek(e.r,e.g,e.b,e.opacity)):new ek}function eS(e,t,n,r){return 1===arguments.length?eE(e):new ek(e,t,n,null==r?1:r)}function ek(e,t,n,r){this.r=+e,this.g=+t,this.b=+n,this.opacity=+r}function ex(){return"#"+eM(this.r)+eM(this.g)+eM(this.b)}function eT(){var e=this.opacity;return(1===(e=isNaN(e)?1:Math.max(0,Math.min(1,e)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===e?")":", "+e+")")}function eM(e){return((e=Math.max(0,Math.min(255,Math.round(e)||0)))<16?"0":"")+e.toString(16)}function eO(e,t,n,r){return r<=0?e=t=n=NaN:n<=0||n>=1?e=t=NaN:t<=0&&(e=NaN),new eC(e,t,n,r)}function eA(e){if(e instanceof eC)return new eC(e.h,e.s,e.l,e.opacity);if(e instanceof en||(e=ey(e)),!e)return new eC;if(e instanceof eC)return e;var t=(e=e.rgb()).r/255,n=e.g/255,r=e.b/255,i=Math.min(t,n,r),a=Math.max(t,n,r),o=NaN,s=a-i,u=(a+i)/2;return s?(o=t===a?(n-r)/s+(n0&&u<1?0:o,new eC(o,s,u,e.opacity)}function eL(e,t,n,r){return 1===arguments.length?eA(e):new eC(e,t,n,null==r?1:r)}function eC(e,t,n,r){this.h=+e,this.s=+t,this.l=+n,this.opacity=+r}function eI(e,t,n){return(e<60?t+(n-t)*e/60:e<180?n:e<240?t+(n-t)*(240-e)/60:t)*255}function eD(e,t,n,r,i){var a=e*e,o=a*e;return((1-3*e+3*a-o)*t+(4-6*a+3*o)*n+(1+3*e+3*a-3*o)*r+o*i)/6}function eN(e){var t=e.length-1;return function(n){var r=n<=0?n=0:n>=1?(n=1,t-1):Math.floor(n*t),i=e[r],a=e[r+1],o=r>0?e[r-1]:2*i-a,s=r=240?e-240:e+120,i,r),eI(e,i,r),eI(e<120?e+240:e-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var e=this.opacity;return(1===(e=isNaN(e)?1:Math.max(0,Math.min(1,e)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===e?")":", "+e+")")}}));let eU=function e(t){var n=eY(1);function r(e,t){var r=n((e=eS(e)).r,(t=eS(t)).r),i=n(e.g,t.g),a=n(e.b,t.b),o=eB(e.opacity,t.opacity);return function(t){return e.r=r(t),e.g=i(t),e.b=a(t),e.opacity=o(t),e+""}}return r.gamma=e,r}(1);function eH(e){return function(t){var n,r,i=t.length,a=Array(i),o=Array(i),s=Array(i);for(n=0;na&&(i=t.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,u.push({i:o,x:B(n,r)})),a=ez.lastIndex;return a=0&&(e=e.slice(0,t)),!e||"start"===e})}function tc(e,t,n){var r,i,a=tu(t)?N:P;return function(){var o=a(this,e),s=o.on;s!==r&&(i=(r=s).copy()).on(t,n),o.on=i}}function tl(e,t){var n=this._id;return arguments.length<2?R(this.node(),n).on.on(e):this.each(tc(n,e,t))}function tf(e){return function(){var t=this.parentNode;for(var n in this.__transition)if(+n!==e)return;t&&t.removeChild(this)}}function td(){return this.on("end.remove",tf(this._id))}var th=n(82634);function tp(e){var t=this._name,n=this._id;"function"!=typeof e&&(e=(0,th.Z)(e));for(var r=this._groups,i=r.length,a=Array(i),o=0;or?(r+i)/2:Math.min(0,r)||Math.max(0,i),o>a?(a+o)/2:Math.min(0,a)||Math.max(0,o))}function t5(){var e,t,n=tQ,r=t1,i=t4,a=t2,o=t3,c=[0,1/0],l=[[-1/0,-1/0],[1/0,1/0]],f=250,d=m,h=(0,s.Z)("start","zoom","end"),p=500,b=150,_=0;function E(e){e.property("__zoom",t0).on("wheel.zoom",A).on("mousedown.zoom",L).on("dblclick.zoom",C).filter(o).on("touchstart.zoom",I).on("touchmove.zoom",D).on("touchend.zoom touchcancel.zoom",N).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function S(e,t){return(t=Math.max(c[0],Math.min(c[1],t)))===e.k?e:new tV(t,e.x,e.y)}function k(e,t,n){var r=t[0]-n[0]*e.k,i=t[1]-n[1]*e.k;return r===e.x&&i===e.y?e:new tV(e.k,r,i)}function x(e){return[(+e[0][0]+ +e[1][0])/2,(+e[0][1]+ +e[1][1])/2]}function T(e,t,n){e.on("start.zoom",function(){M(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){M(this,arguments).end()}).tween("zoom",function(){var e=this,i=arguments,a=M(e,i),o=r.apply(e,i),s=null==n?x(o):"function"==typeof n?n.apply(e,i):n,u=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),c=e.__zoom,l="function"==typeof t?t.apply(e,i):t,f=d(c.invert(s).concat(u/c.k),l.invert(s).concat(u/l.k));return function(e){if(1===e)e=l;else{var t=f(e),n=u/t[2];e=new tV(n,s[0]-t[0]*n,s[1]-t[1]*n)}a.zoom(null,e)}})}function M(e,t,n){return!n&&e.__zooming||new O(e,t)}function O(e,t){this.that=e,this.args=t,this.active=0,this.extent=r.apply(e,t),this.taps=0}function A(){if(n.apply(this,arguments)){var e=M(this,arguments),t=this.__zoom,r=Math.max(c[0],Math.min(c[1],t.k*Math.pow(2,a.apply(this,arguments)))),o=(0,v.Z)(this);if(e.wheel)(e.mouse[0][0]!==o[0]||e.mouse[0][1]!==o[1])&&(e.mouse[1]=t.invert(e.mouse[0]=o)),clearTimeout(e.wheel);else{if(t.k===r)return;e.mouse=[o,t.invert(o)],F(this),e.start()}tJ(),e.wheel=setTimeout(s,b),e.zoom("mouse",i(k(S(t,r),e.mouse[0],e.mouse[1]),e.extent,l))}function s(){e.wheel=null,e.end()}}function L(){if(!t&&n.apply(this,arguments)){var e=M(this,arguments,!0),r=(0,y.Z)(g.B.view).on("mousemove.zoom",c,!0).on("mouseup.zoom",f,!0),a=(0,v.Z)(this),o=g.B.clientX,s=g.B.clientY;(0,u.Z)(g.B.view),tX(),e.mouse=[a,this.__zoom.invert(a)],F(this),e.start()}function c(){if(tJ(),!e.moved){var t=g.B.clientX-o,n=g.B.clientY-s;e.moved=t*t+n*n>_}e.zoom("mouse",i(k(e.that.__zoom,e.mouse[0]=(0,v.Z)(e.that),e.mouse[1]),e.extent,l))}function f(){r.on("mousemove.zoom mouseup.zoom",null),(0,u.D)(g.B.view,e.moved),tJ(),e.end()}}function C(){if(n.apply(this,arguments)){var e=this.__zoom,t=(0,v.Z)(this),a=e.invert(t),o=e.k*(g.B.shiftKey?.5:2),s=i(k(S(e,o),t,a),r.apply(this,arguments),l);tJ(),f>0?(0,y.Z)(this).transition().duration(f).call(T,s,t):(0,y.Z)(this).call(E.transform,s)}}function I(){if(n.apply(this,arguments)){var t,r,i,a,o=g.B.touches,s=o.length,u=M(this,arguments,g.B.changedTouches.length===s);for(tX(),r=0;r=0?i=setTimeout(r,t-c):(i=null,n||(u=e.apply(o,a),o=a=null))}null==t&&(t=100);var i,a,o,s,u,c=function(){o=this,a=arguments,s=Date.now();var c=n&&!i;return i||(i=setTimeout(r,t)),c&&(u=e.apply(o,a),o=a=null),u};return c.clear=function(){i&&(clearTimeout(i),i=null)},c.flush=function(){i&&(u=e.apply(o,a),o=a=null,clearTimeout(i),i=null)},c}t.debounce=t,e.exports=t},94863:function(e){var t,n;t=this,n=function(){"use strict";var e=function(e){return t(e)&&!n(e)};function t(e){return!!e&&"object"==typeof e}function n(e){var t=Object.prototype.toString.call(e);return"[object RegExp]"===t||"[object Date]"===t||i(e)}var r="function"==typeof Symbol&&Symbol.for?Symbol.for("react.element"):60103;function i(e){return e.$$typeof===r}function a(e){return Array.isArray(e)?[]:{}}function o(e,t){return!1!==t.clone&&t.isMergeableObject(e)?d(a(e),e,t):e}function s(e,t,n){return e.concat(t).map(function(e){return o(e,n)})}function u(e,t){if(!t.customMerge)return d;var n=t.customMerge(e);return"function"==typeof n?n:d}function c(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return e.propertyIsEnumerable(t)}):[]}function l(e){return Object.keys(e).concat(c(e))}function f(e,t,n){var r={};return n.isMergeableObject(e)&&l(e).forEach(function(t){r[t]=o(e[t],n)}),l(t).forEach(function(i){n.isMergeableObject(t[i])&&e[i]?r[i]=u(i,n)(e[i],t[i],n):r[i]=o(t[i],n)}),r}function d(t,n,r){(r=r||{}).arrayMerge=r.arrayMerge||s,r.isMergeableObject=r.isMergeableObject||e;var i=Array.isArray(n);return i!==Array.isArray(t)?o(n,r):i?r.arrayMerge(t,n,r):f(t,n,r)}return d.all=function(e,t){if(!Array.isArray(e))throw Error("first argument should be an array");return e.reduce(function(e,n){return d(e,n,t)},{})},d},e.exports=n()},7624(e,t){"use strict";function n(e){return e===e.window?e:9===e.nodeType&&(e.defaultView||e.parentWindow)}t.__esModule=!0,t.default=n,e.exports=t.default},87797(e,t,n){"use strict";var r=n(95318);t.__esModule=!0,t.default=s;var i=r(n(53497)),a=/^(top|right|bottom|left)$/,o=/^([+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|))(?!px)[a-z%]+$/i;function s(e){if(!e)throw TypeError("No Element passed to `getComputedStyle()`");var t=e.ownerDocument;return"defaultView"in t?t.defaultView.opener?e.ownerDocument.defaultView.getComputedStyle(e,null):window.getComputedStyle(e,null):{getPropertyValue:function(t){var n=e.style;"float"==(t=(0,i.default)(t))&&(t="styleFloat");var r=e.currentStyle[t]||null;if(null==r&&n&&n[t]&&(r=n[t]),o.test(r)&&!a.test(t)){var s=n.left,u=e.runtimeStyle,c=u&&u.left;c&&(u.left=e.currentStyle.left),n.left="fontSize"===t?"1em":r,r=n.pixelLeft+"px",n.left=s,c&&(u.left=c)}return r}}}e.exports=t.default},10162(e,t,n){"use strict";var r=n(95318);t.__esModule=!0,t.default=l;var i=r(n(53497)),a=r(n(24403)),o=r(n(87797)),s=r(n(91760)),u=n(20702),c=r(n(43293));function l(e,t,n){var r="",l="",f=t;if("string"==typeof t){if(void 0===n)return e.style[(0,i.default)(t)]||(0,o.default)(e).getPropertyValue((0,a.default)(t));(f={})[t]=n}Object.keys(f).forEach(function(t){var n=f[t];n||0===n?(0,c.default)(t)?l+=t+"("+n+") ":r+=(0,a.default)(t)+": "+n+";":(0,s.default)(e,(0,a.default)(t))}),l&&(r+=u.transform+": "+l+";"),e.style.cssText+=";"+r}e.exports=t.default},91760(e,t){"use strict";function n(e,t){return"removeProperty"in e.style?e.style.removeProperty(t):e.style.removeAttribute(t)}t.__esModule=!0,t.default=n,e.exports=t.default},43293(e,t){"use strict";t.__esModule=!0,t.default=r;var n=/^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i;function r(e){return!!(e&&n.test(e))}e.exports=t.default},20702(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d,h,p=n(95318);t.__esModule=!0,t.default=t.animationEnd=t.animationDelay=t.animationTiming=t.animationDuration=t.animationName=t.transitionEnd=t.transitionDuration=t.transitionDelay=t.transitionTiming=t.transitionProperty=t.transform=void 0;var b=p(n(50139)),m="transform";if(t.transform=m,t.animationEnd=a,t.transitionEnd=i,t.transitionDelay=c,t.transitionTiming=u,t.transitionDuration=s,t.transitionProperty=o,t.animationDelay=h,t.animationTiming=d,t.animationDuration=f,t.animationName=l,b.default){var g=y();r=g.prefix,t.transitionEnd=i=g.transitionEnd,t.animationEnd=a=g.animationEnd,t.transform=m=r+"-"+m,t.transitionProperty=o=r+"-transition-property",t.transitionDuration=s=r+"-transition-duration",t.transitionDelay=c=r+"-transition-delay",t.transitionTiming=u=r+"-transition-timing-function",t.animationName=l=r+"-animation-name",t.animationDuration=f=r+"-animation-duration",t.animationTiming=d=r+"-animation-delay",t.animationDelay=h=r+"-animation-timing-function"}var v={transform:m,end:i,property:o,timing:u,delay:c,duration:s};function y(){for(var e,t,n=document.createElement("div").style,r={O:function(e){return"o"+e.toLowerCase()},Moz:function(e){return e.toLowerCase()},Webkit:function(e){return"webkit"+e},ms:function(e){return"MS"+e}},i=Object.keys(r),a="",o=0;o0&&void 0!==arguments[0]?arguments[0]:{},r=n.defaultLayoutOptions,a=void 0===r?{}:r,s=n.algorithms,u=void 0===s?["layered","stress","mrtree","radial","force","disco","sporeOverlap","sporeCompaction","rectpacking"]:s,c=n.workerFactory,l=n.workerUrl;if(i(this,e),this.defaultLayoutOptions=a,this.initialized=!1,void 0===l&&void 0===c)throw Error("Cannot construct an ELK without both 'workerUrl' and 'workerFactory'.");var f=c;void 0!==l&&void 0===c&&(f=function(e){return new Worker(e)});var d=f(l);if("function"!=typeof d.postMessage)throw TypeError("Created worker does not provide the required 'postMessage' function.");this.worker=new o(d),this.worker.postMessage({cmd:"register",algorithms:u}).then(function(e){return t.initialized=!0}).catch(console.err)}return r(e,[{key:"layout",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.layoutOptions,r=void 0===n?this.defaultLayoutOptions:n,i=t.logging,a=void 0!==i&&i,o=t.measureExecutionTime,s=void 0!==o&&o;return e?this.worker.postMessage({cmd:"layout",graph:e,layoutOptions:r,options:{logging:a,measureExecutionTime:s}}):Promise.reject(Error("Missing mandatory parameter 'graph'."))}},{key:"knownLayoutAlgorithms",value:function(){return this.worker.postMessage({cmd:"algorithms"})}},{key:"knownLayoutOptions",value:function(){return this.worker.postMessage({cmd:"options"})}},{key:"knownLayoutCategories",value:function(){return this.worker.postMessage({cmd:"categories"})}},{key:"terminateWorker",value:function(){this.worker.terminate()}}]),e}();n.default=a;var o=function(){function e(t){var n=this;if(i(this,e),void 0===t)throw Error("Missing mandatory parameter 'worker'.");this.resolvers={},this.worker=t,this.worker.onmessage=function(e){setTimeout(function(){n.receive(n,e)},0)}}return r(e,[{key:"postMessage",value:function(e){var t=this.id||0;this.id=t+1,e.id=t;var n=this;return new Promise(function(r,i){n.resolvers[t]=function(e,t){e?(n.convertGwtStyleError(e),i(e)):r(t)},n.worker.postMessage(e)})}},{key:"receive",value:function(e,t){var n=t.data,r=e.resolvers[n.id];r&&(delete e.resolvers[n.id],n.error?r(n.error):r(null,n.data))}},{key:"terminate",value:function(){this.worker.terminate&&this.worker.terminate()}},{key:"convertGwtStyleError",value:function(e){if(e){var t=e.__java$exception;t&&(t.cause&&t.cause.backingJsObject&&(e.cause=t.cause.backingJsObject,this.convertGwtStyleError(e.cause)),delete e.__java$exception)}}}]),e}()},{}],2:[function(e,t,n){"use strict";var r=e("./elk-api.js").default;Object.defineProperty(t.exports,"__esModule",{value:!0}),t.exports=r,r.default=r},{"./elk-api.js":1}]},{},[2])(2)},e.exports=t()},55273(e,t,n){"use strict";function r(){}function i(){}function a(){}function o(){}function s(){}function u(){}function c(){}function l(){}function f(){}function d(){}function h(){}function p(){}function b(){}function m(){}function g(){}function v(){}function y(){}function w(){}function _(){}function E(){}function S(){}function k(){}function x(){}function T(){}function M(){}function O(){}function A(){}function L(){}function C(){}function I(){}function D(){}function N(){}function P(){}function R(){}function j(){}function F(){}function Y(){}function B(){}function U(){}function H(){}function $(){}function z(){}function G(){}function W(){}function K(){}function V(){}function q(){}function Z(){}function X(){}function J(){}function Q(){}function ee(){}function et(){}function en(){}function er(){}function ei(){}function ea(){}function eo(){}function es(){}function eu(){}function ec(){}function el(){}function ef(){}function ed(){}function eh(){}function ep(){}function eb(){}function em(){}function eg(){}function ev(){}function ey(){}function ew(){}function e_(){}function eE(){}function eS(){}function ek(){}function ex(){}function eT(){}function eM(){}function eO(){}function eA(){}function eL(){}function eC(){}function eI(){}function eD(){}function eN(){}function eP(){}function eR(){}function ej(){}function eF(){}function eY(){}function eB(){}function eU(){}function eH(){}function e$(){}function ez(){}function eG(){}function eW(){}function eK(){}function eV(){}function eq(){}function eZ(){}function eX(){}function eJ(){}function eQ(){}function e1(){}function e0(){}function e2(){}function e3(){}function e4(){}function e5(){}function e6(){}function e9(){}function e8(){}function e7(){}function te(){}function tt(){}function tn(){}function tr(){}function ti(){}function ta(){}function to(){}function ts(){}function tu(){}function tc(){}function tl(){}function tf(){}function td(){}function th(){}function tp(){}function tb(){}function tm(){}function tg(){}function tv(){}function ty(){}function tw(){}function t_(){}function tE(){}function tS(){}function tk(){}function tx(){}function tT(){}function tM(){}function tO(){}function tA(){}function tL(){}function tC(){}function tI(){}function tD(){}function tN(){}function tP(){}function tR(){}function tj(){}function tF(){}function tY(){}function tB(){}function tU(){}function tH(){}function t$(){}function tz(){}function tG(){}function tW(){}function tK(){}function tV(){}function tq(){}function tZ(){}function tX(){}function tJ(){}function tQ(){}function t1(){}function t0(){}function t2(){}function t3(){}function t4(){}function t5(){}function t6(){}function t9(){}function t8(){}function t7(){}function ne(){}function nt(){}function nn(){}function nr(){}function ni(){}function na(){}function no(){}function ns(){}function nu(){}function nc(){}function nl(){}function nf(){}function nd(){}function nh(){}function np(){}function nb(){}function nm(){}function ng(){}function nv(){}function ny(){}function nw(){}function n_(){}function nE(){}function nS(){}function nk(){}function nx(){}function nT(){}function nM(){}function nO(){}function nA(){}function nL(){}function nC(){}function nI(){}function nD(){}function nN(){}function nP(){}function nR(){}function nj(){}function nF(){}function nY(){}function nB(){}function nU(){}function nH(){}function n$(){}function nz(){}function nG(){}function nW(){}function nK(){}function nV(){}function nq(){}function nZ(){}function nX(){}function nJ(){}function nQ(){}function n1(){}function n0(){}function n2(){}function n3(){}function n4(){}function n5(){}function n6(){}function n9(){}function n8(){}function n7(){}function re(){}function rt(){}function rn(){}function rr(){}function ri(){}function ra(){}function ro(){}function rs(){}function ru(){}function rc(){}function rl(){}function rf(){}function rd(){}function rh(){}function rp(){}function rb(){}function rm(){}function rg(){}function rv(){}function ry(){}function rw(){}function r_(){}function rE(){}function rS(){}function rk(){}function rx(){}function rT(){}function rM(){}function rO(){}function rA(){}function rL(){}function rC(){}function rI(){}function rD(){}function rN(){}function rP(){}function rR(){}function rj(){}function rF(){}function rY(){}function rB(){}function rU(){}function rH(){}function r$(){}function rz(){}function rG(){}function rW(){}function rK(){}function rV(){}function rq(){}function rZ(){}function rX(){}function rJ(){}function rQ(){}function r1(){}function r0(){}function r2(){}function r3(){}function r4(){}function r5(){}function r6(){}function r9(){}function r8(){}function r7(){}function ie(){}function it(){}function ir(){}function ii(){}function ia(){}function io(){}function is(){}function iu(){}function ic(){}function il(){}function id(){}function ih(){}function ip(){}function ib(){}function im(){}function ig(){}function iv(){}function iy(){}function iw(){}function i_(){}function iE(){}function iS(){}function ik(){}function ix(){}function iT(){}function iM(){}function iO(){}function iA(){}function iL(){}function iC(){}function iI(){}function iD(){}function iN(){}function iP(){}function iR(){}function ij(){}function iF(){}function iY(){}function iB(){}function iU(){}function iH(){}function i$(){}function iz(){}function iG(){}function iW(){}function iK(){}function iV(){}function iq(){}function iZ(){}function iX(){}function iJ(){}function iQ(){}function i1(){}function i0(){}function i2(){}function i3(){}function i4(){}function i5(){}function i6(){}function i9(){}function i8(){}function i7(){}function ae(){}function at(){}function an(){}function ar(){}function ai(){}function aa(){}function ao(){}function as(){}function au(){}function ac(){}function al(){}function af(){}function ad(){}function ah(){}function ap(){}function ab(){}function am(){}function ag(){}function av(){}function ay(){}function aw(){}function a_(){}function aE(){}function aS(){}function ak(){}function ax(){}function aT(){}function aM(){}function aO(){}function aA(){}function aL(){}function aC(){}function aI(){}function aD(){}function aN(){}function aP(){}function aR(){}function aj(){}function aF(){}function aY(){}function aB(){}function aU(){}function aH(){}function a$(){}function az(){}function aG(){}function aW(){}function aK(){}function aV(){}function aq(){}function aZ(){}function aX(){}function aJ(){}function aQ(){}function a1(){}function a0(){}function a2(){}function a3(){}function a4(){}function a5(){}function a6(){}function a9(){}function a8(){}function a7(){}function oe(){}function ot(){}function on(){}function or(){}function oi(){}function oa(){}function oo(){}function os(){}function ou(){}function oc(){}function ol(){}function of(){}function od(){}function oh(){}function op(){}function ob(){}function om(){}function og(){}function ov(){}function oy(){}function ow(){}function o_(){}function oE(){}function oS(){}function ok(){}function ox(){}function oT(){}function oM(){}function oO(){}function oA(){}function oL(){}function oC(){}function oI(){}function oD(){}function oN(){}function oP(){}function oR(){}function oj(){}function oF(){}function oY(){}function oB(){}function oU(){}function oH(){}function o$(){}function oz(){}function oG(){}function oW(){}function oK(){}function oV(){}function oq(){}function oZ(){}function oX(){}function oJ(){}function oQ(){}function o1(){}function o0(){}function o2(){}function o3(){}function o4(){}function o5(){}function o6(){}function o9(){}function o8(){}function o7(){}function se(){}function st(){}function sn(){}function sr(){}function si(){}function sa(){}function so(){}function ss(){}function su(){}function sc(){}function sl(){}function sf(){}function sd(){}function sh(){}function sp(){}function sb(){}function sm(){}function sg(){}function sv(){}function sy(){}function sw(){}function s_(){}function sE(){}function sS(){}function sk(){}function sx(){}function sT(){}function sM(){}function sO(){}function sA(){}function sL(){}function sC(){}function sI(){}function sD(){}function sN(){}function sP(){}function sR(){}function sj(){}function sF(){}function sY(){}function sB(){}function sU(){}function sH(){}function s$(){}function sz(){}function sG(){}function sW(){}function sK(){}function sV(){}function sq(){}function sZ(){}function sX(){}function sJ(){}function sQ(){}function s1(){}function s0(){}function s2(){}function s3(){}function s4(){}function s5(){}function s6(){}function s9(){}function s8(){}function s7(){}function ue(){}function ut(){}function un(){}function ur(){}function ui(){}function ua(){}function uo(){}function us(){}function uu(){}function uc(){}function ul(){}function uf(){}function ud(){}function uh(){}function up(){}function ub(){}function um(){}function ug(){}function uv(){}function uy(){}function uw(){}function u_(){}function uE(){}function uS(){}function uk(){}function ux(){}function uT(){}function uM(){}function uO(){}function uA(){}function uL(){}function uC(){}function uI(){}function uD(){}function uN(){}function uP(){}function uR(){}function uj(){}function uF(){}function uY(){}function uB(){}function uU(){}function uH(){}function u$(){}function uz(){}function uG(){}function uW(){}function uK(){}function uV(){}function uq(){}function uZ(){}function uX(){}function uJ(){}function uQ(){}function u1(){}function u0(){}function u2(){}function u3(){}function u4(){}function u5(){}function u6(){}function u9(){}function u8(){}function u7(){}function ce(){}function ct(){}function cn(e){}function cr(e){}function ci(){m4()}function ca(){eug()}function co(){epz()}function cs(){evw()}function cu(){eEg()}function cc(){eCk()}function cl(){egA()}function cf(){egq()}function cd(){_O()}function ch(){_k()}function cp(){DR()}function cb(){_A()}function cm(){erJ()}function cg(){_C()}function cv(){Xi()}function cy(){en6()}function cw(){Jb()}function c_(){Gw()}function cE(){euv()}function cS(){e_z()}function ck(){en9()}function cx(){K9()}function cT(){eBH()}function cM(){egP()}function cO(){G_()}function cA(){eBy()}function cL(){Gv()}function cC(){en8()}function cI(){eoz()}function cD(){Gx()}function cN(){JK()}function cP(){_I()}function cR(){eTK()}function cj(){egj()}function cF(){eiQ()}function cY(){e_L()}function cB(){eCT()}function cU(){ebJ()}function cH(){eTj()}function c$(){eaB()}function cz(){GS()}function cG(){eDn()}function cW(){eTU()}function cK(){eMK()}function cV(){J1()}function cq(){e_C()}function cZ(){eBB()}function cX(){euw()}function cJ(){ed5()}function cQ(){ePm()}function c1(){De()}function c0(){eiM()}function c2(){eD4()}function c3(e){BJ(e)}function c4(e){this.a=e}function c5(e){this.a=e}function c6(e){this.a=e}function c9(e){this.a=e}function c8(e){this.a=e}function c7(e){this.a=e}function le(e){this.a=e}function lt(e){this.a=e}function ln(e){this.a=e}function lr(e){this.a=e}function li(e){this.a=e}function la(e){this.a=e}function lo(e){this.a=e}function ls(e){this.a=e}function lu(e){this.a=e}function lc(e){this.a=e}function ll(e){this.a=e}function lf(e){this.a=e}function ld(e){this.a=e}function lh(e){this.a=e}function lp(e){this.a=e}function lb(e){this.b=e}function lm(e){this.c=e}function lg(e){this.a=e}function lv(e){this.a=e}function ly(e){this.a=e}function lw(e){this.a=e}function l_(e){this.a=e}function lE(e){this.a=e}function lS(e){this.a=e}function lk(e){this.a=e}function lx(e){this.a=e}function lT(e){this.a=e}function lM(e){this.a=e}function lO(e){this.a=e}function lA(e){this.a=e}function lL(e){this.a=e}function lC(e){this.a=e}function lI(e){this.a=e}function lD(e){this.a=e}function lN(){this.a=[]}function lP(e,t){e.a=t}function lR(e,t){e.a=t}function lj(e,t){e.b=t}function lF(e,t){e.b=t}function lY(e,t){e.b=t}function lB(e,t){e.j=t}function lU(e,t){e.g=t}function lH(e,t){e.i=t}function l$(e,t){e.c=t}function lz(e,t){e.d=t}function lG(e,t){e.d=t}function lW(e,t){e.c=t}function lK(e,t){e.k=t}function lV(e,t){e.c=t}function lq(e,t){e.c=t}function lZ(e,t){e.a=t}function lX(e,t){e.a=t}function lJ(e,t){e.f=t}function lQ(e,t){e.a=t}function l1(e,t){e.b=t}function l0(e,t){e.d=t}function l2(e,t){e.i=t}function l3(e,t){e.o=t}function l4(e,t){e.r=t}function l5(e,t){e.a=t}function l6(e,t){e.b=t}function l9(e,t){e.e=t}function l8(e,t){e.f=t}function l7(e,t){e.g=t}function fe(e,t){e.e=t}function ft(e,t){e.f=t}function fn(e,t){e.f=t}function fr(e,t){e.n=t}function fi(e,t){e.a=t}function fa(e,t){e.a=t}function fo(e,t){e.c=t}function fs(e,t){e.c=t}function fu(e,t){e.d=t}function fc(e,t){e.e=t}function fl(e,t){e.g=t}function ff(e,t){e.a=t}function fd(e,t){e.c=t}function fh(e,t){e.d=t}function fp(e,t){e.e=t}function fb(e,t){e.f=t}function fm(e,t){e.j=t}function fg(e,t){e.a=t}function fv(e,t){e.b=t}function fy(e,t){e.a=t}function fw(e){e.b=e.a}function f_(e){e.c=e.d.d}function fE(e){this.d=e}function fS(e){this.a=e}function fk(e){this.a=e}function fx(e){this.a=e}function fT(e){this.a=e}function fM(e){this.a=e}function fO(e){this.a=e}function fA(e){this.a=e}function fL(e){this.a=e}function fC(e){this.a=e}function fI(e){this.a=e}function fD(e){this.a=e}function fN(e){this.a=e}function fP(e){this.a=e}function fR(e){this.a=e}function fj(e){this.b=e}function fF(e){this.b=e}function fY(e){this.b=e}function fB(e){this.a=e}function fU(e){this.a=e}function fH(e){this.a=e}function f$(e){this.c=e}function fz(e){this.c=e}function fG(e){this.c=e}function fW(e){this.a=e}function fK(e){this.a=e}function fV(e){this.a=e}function fq(e){this.a=e}function fZ(e){this.a=e}function fX(e){this.a=e}function fJ(e){this.a=e}function fQ(e){this.a=e}function f1(e){this.a=e}function f0(e){this.a=e}function f2(e){this.a=e}function f3(e){this.a=e}function f4(e){this.a=e}function f5(e){this.a=e}function f6(e){this.a=e}function f9(e){this.a=e}function f8(e){this.a=e}function f7(e){this.a=e}function de(e){this.a=e}function dt(e){this.a=e}function dn(e){this.a=e}function dr(e){this.a=e}function di(e){this.a=e}function da(e){this.a=e}function ds(e){this.a=e}function du(e){this.a=e}function dc(e){this.a=e}function dl(e){this.a=e}function df(e){this.a=e}function dd(e){this.a=e}function dh(e){this.a=e}function dp(e){this.a=e}function db(e){this.a=e}function dm(e){this.a=e}function dg(e){this.a=e}function dv(e){this.a=e}function dy(e){this.a=e}function dw(e){this.a=e}function d_(e){this.a=e}function dE(e){this.a=e}function dS(e){this.a=e}function dk(e){this.a=e}function dx(e){this.a=e}function dT(e){this.a=e}function dM(e){this.a=e}function dO(e){this.e=e}function dA(e){this.a=e}function dL(e){this.a=e}function dC(e){this.a=e}function dI(e){this.a=e}function dD(e){this.a=e}function dN(e){this.a=e}function dP(e){this.a=e}function dR(e){this.a=e}function dj(e){this.a=e}function dF(e){this.a=e}function dY(e){this.a=e}function dB(e){this.a=e}function dU(e){this.a=e}function dH(e){this.a=e}function d$(e){this.a=e}function dz(e){this.a=e}function dG(e){this.a=e}function dW(e){this.a=e}function dK(e){this.a=e}function dV(e){this.a=e}function dq(e){this.a=e}function dZ(e){this.a=e}function dX(e){this.a=e}function dJ(e){this.a=e}function dQ(e){this.a=e}function d1(e){this.a=e}function d0(e){this.a=e}function d2(e){this.a=e}function d3(e){this.a=e}function d4(e){this.a=e}function d5(e){this.a=e}function d6(e){this.a=e}function d9(e){this.a=e}function d8(e){this.a=e}function d7(e){this.a=e}function he(e){this.a=e}function ht(e){this.a=e}function hn(e){this.a=e}function hr(e){this.a=e}function hi(e){this.a=e}function ha(e){this.a=e}function ho(e){this.a=e}function hs(e){this.a=e}function hu(e){this.a=e}function hc(e){this.a=e}function hl(e){this.a=e}function hf(e){this.a=e}function hd(e){this.a=e}function hh(e){this.a=e}function hp(e){this.a=e}function hb(e){this.a=e}function hm(e){this.a=e}function hg(e){this.a=e}function hv(e){this.c=e}function hy(e){this.b=e}function hw(e){this.a=e}function h_(e){this.a=e}function hE(e){this.a=e}function hS(e){this.a=e}function hk(e){this.a=e}function hx(e){this.a=e}function hT(e){this.a=e}function hM(e){this.a=e}function hO(e){this.a=e}function hA(e){this.a=e}function hL(e){this.a=e}function hC(e){this.a=e}function hI(e){this.a=e}function hD(e){this.a=e}function hN(e){this.a=e}function hP(e){this.a=e}function hR(e){this.a=e}function hj(e){this.a=e}function hF(e){this.a=e}function hY(e){this.a=e}function hB(e){this.a=e}function hU(e){this.a=e}function hH(e){this.a=e}function h$(e){this.a=e}function hz(e){this.a=e}function hG(e){this.a=e}function hW(e){this.a=e}function hK(e){this.a=e}function hV(e){this.a=e}function hq(e){this.a=e}function hZ(e){this.a=e}function hX(e){this.a=e}function hJ(e){this.a=e}function hQ(e){this.a=e}function h1(e){this.a=e}function h0(e){this.a=e}function h2(e){this.a=e}function h3(e){this.a=e}function h4(e){this.a=e}function h5(e){this.a=e}function h6(e){this.a=e}function h9(e){this.a=e}function h8(e){this.a=e}function h7(e){this.a=e}function pe(e){this.a=e}function pt(e){this.a=e}function pn(e){this.a=e}function pr(e){this.a=e}function pi(e){this.a=e}function pa(e){this.a=e}function po(e){this.a=e}function ps(e){this.a=e}function pu(e){this.a=e}function pc(e){this.a=e}function pl(e){this.a=e}function pf(e){this.a=e}function pd(e){this.a=e}function ph(e){this.a=e}function pp(e){this.a=e}function pb(e){this.a=e}function pm(e){this.a=e}function pg(e){this.a=e}function pv(e){this.a=e}function py(e){this.a=e}function pw(e){this.a=e}function p_(e){this.a=e}function pE(e){this.a=e}function pS(e){this.a=e}function pk(e){this.a=e}function px(e){this.a=e}function pT(e){this.a=e}function pM(e){this.a=e}function pO(e){this.b=e}function pA(e){this.f=e}function pL(e){this.a=e}function pC(e){this.a=e}function pI(e){this.a=e}function pD(e){this.a=e}function pN(e){this.a=e}function pP(e){this.a=e}function pR(e){this.a=e}function pj(e){this.a=e}function pF(e){this.a=e}function pY(e){this.a=e}function pB(e){this.a=e}function pU(e){this.b=e}function pH(e){this.c=e}function p$(e){this.e=e}function pz(e){this.a=e}function pG(e){this.a=e}function pW(e){this.a=e}function pK(e){this.a=e}function pV(e){this.a=e}function pq(e){this.d=e}function pZ(e){this.a=e}function pX(e){this.a=e}function pJ(e){this.e=e}function pQ(){this.a=0}function p1(){TG(this)}function p0(){Tz(this)}function p2(){Yy(this)}function p3(){UP(this)}function p4(){cn(this)}function p5(){this.c=tgK}function p6(e,t){t.Wb(e)}function p9(e,t){e.b+=t}function p8(e){e.b=new gQ}function p7(e){return e.e}function be(e){return e.a}function bt(e){return e.a}function bn(e){return e.a}function br(e){return e.a}function bi(e){return e.a}function ba(){return null}function bo(){return null}function bs(){yC(),eY2()}function bu(e){e.b.tf(e.e)}function bc(e,t){e.b=t-e.b}function bl(e,t){e.a=t-e.a}function bf(e,t){t.ad(e.a)}function bd(e,t){ekv(t,e)}function bh(e,t,n){e.Od(n,t)}function bp(e,t){e.e=t,t.b=e}function bb(e){Dn(),this.a=e}function bm(e){Dn(),this.a=e}function bg(e){Dn(),this.a=e}function bv(e){Bx(),this.a=e}function by(e){$O(),e0E.be(e)}function bw(){O5.call(this)}function b_(){O5.call(this)}function bE(){bw.call(this)}function bS(){bw.call(this)}function bk(){bw.call(this)}function bx(){bw.call(this)}function bT(){bw.call(this)}function bM(){bw.call(this)}function bO(){bw.call(this)}function bA(){bw.call(this)}function bL(){bw.call(this)}function bC(){bw.call(this)}function bI(){bw.call(this)}function bD(){this.a=this}function bN(){this.Bb|=256}function bP(){this.b=new xW}function bR(){bR=A,new p2}function bj(){bE.call(this)}function bF(e,t){e.length=t}function bY(e,t){P_(e.a,t)}function bB(e,t){eEU(e.c,t)}function bU(e,t){Yf(e.b,t)}function bH(e,t){ebB(e.a,t)}function b$(e,t){elj(e.a,t)}function bz(e,t){eam(e.e,t)}function bG(e){exZ(e.c,e.b)}function bW(e,t){e.kc().Nb(t)}function bK(e){this.a=efh(e)}function bV(){this.a=new p2}function bq(){this.a=new p2}function bZ(){this.a=new p0}function bX(){this.a=new p0}function bJ(){this.a=new p0}function bQ(){this.a=new ey}function b1(){this.a=new Z6}function b0(){this.a=new tt}function b2(){this.a=new w7}function b3(){this.a=new W9}function b4(){this.a=new zZ}function b5(){this.a=new Cz}function b6(){this.a=new p0}function b9(){this.a=new p0}function b8(){this.a=new p0}function b7(){this.a=new p0}function me(){this.d=new p0}function mt(){this.a=new bV}function mn(){this.a=new p2}function mr(){this.b=new p2}function mi(){this.b=new p0}function ma(){this.e=new p0}function mo(){this.d=new p0}function ms(){this.a=new cS}function mu(){p0.call(this)}function mc(){bZ.call(this)}function ml(){CK.call(this)}function mf(){b9.call(this)}function md(){mh.call(this)}function mh(){p4.call(this)}function mp(){p4.call(this)}function mb(){mp.call(this)}function mm(){$m.call(this)}function mg(){$m.call(this)}function mv(){mq.call(this)}function my(){mq.call(this)}function mw(){mq.call(this)}function m_(){mZ.call(this)}function mE(){_n.call(this)}function mS(){oZ.call(this)}function mk(){oZ.call(this)}function mx(){m0.call(this)}function mT(){m0.call(this)}function mM(){p2.call(this)}function mO(){p2.call(this)}function mA(){p2.call(this)}function mL(){bV.call(this)}function mC(){en0.call(this)}function mI(){bN.call(this)}function mD(){Oy.call(this)}function mN(){Oy.call(this)}function mP(){p2.call(this)}function mR(){p2.call(this)}function mj(){p2.call(this)}function mF(){sr.call(this)}function mY(){sr.call(this)}function mB(){mF.call(this)}function mU(){u7.call(this)}function mH(e){eti.call(this,e)}function m$(e){eti.call(this,e)}function mz(e){ln.call(this,e)}function mG(e){wB.call(this,e)}function mW(e){mG.call(this,e)}function mK(e){wB.call(this,e)}function mV(){this.a=new _n}function mq(){this.a=new bV}function mZ(){this.a=new p2}function mX(){this.a=new p0}function mJ(){this.j=new p0}function mQ(){this.a=new aX}function m1(){this.a=new y4}function m0(){this.a=new sn}function m2(){m2=A,e0d=new vm}function m3(){m3=A,e0f=new vb}function m4(){m4=A,e0l=new i}function m5(){m5=A,e0m=new OV}function m6(e){mG.call(this,e)}function m9(e){mG.call(this,e)}function m8(e){ql.call(this,e)}function m7(e){ql.call(this,e)}function ge(e){IJ.call(this,e)}function gt(e){eEb.call(this,e)}function gn(e){w$.call(this,e)}function gr(e){wG.call(this,e)}function gi(e){wG.call(this,e)}function ga(e){wG.call(this,e)}function go(e){Fu.call(this,e)}function gs(e){go.call(this,e)}function gu(){lD.call(this,{})}function gc(e){Og(),this.a=e}function gl(e){e.b=null,e.c=0}function gf(e,t){e.e=t,eA9(e,t)}function gd(e,t){e.a=t,eSG(e)}function gh(e,t,n){e.a[t.g]=n}function gp(e,t,n){evq(n,e,t)}function gb(e,t){In(t.i,e.n)}function gm(e,t){esW(e).td(t)}function gg(e,t){return e*e/t}function gv(e,t){return e.g-t.g}function gy(e){return new lI(e)}function gw(e){return new B_(e)}function g_(e){go.call(this,e)}function gE(e){go.call(this,e)}function gS(e){go.call(this,e)}function gk(e){Fu.call(this,e)}function gx(e){eiJ(),this.a=e}function gT(e){I7(),this.a=e}function gM(e){jK(),this.f=e}function gO(e){jK(),this.f=e}function gA(e){go.call(this,e)}function gL(e){go.call(this,e)}function gC(e){go.call(this,e)}function gI(e){go.call(this,e)}function gD(e){go.call(this,e)}function gN(e){return BJ(e),e}function gP(e){return BJ(e),e}function gR(e){return BJ(e),e}function gj(e){return BJ(e),e}function gF(e){return BJ(e),e}function gY(e){return e.b==e.c}function gB(e){return!!e&&e.b}function gU(e){return!!e&&e.k}function gH(e){return!!e&&e.j}function g$(e){BJ(e),this.a=e}function gz(e){return esR(e),e}function gG(e){Ya(e,e.length)}function gW(e){go.call(this,e)}function gK(e){go.call(this,e)}function gV(e){go.call(this,e)}function gq(e){go.call(this,e)}function gZ(e){go.call(this,e)}function gX(e){go.call(this,e)}function gJ(e){AI.call(this,e,0)}function gQ(){G$.call(this,12,3)}function g1(){g1=A,e0_=new _}function g0(){g0=A,e0y=new r}function g2(){g2=A,e0k=new b}function g3(){g3=A,e0M=new g}function g4(){throw p7(new bO)}function g5(){throw p7(new bO)}function g6(){throw p7(new bO)}function g9(){throw p7(new bO)}function g8(){throw p7(new bO)}function g7(){throw p7(new bO)}function ve(){this.a=Lq(Y9(eUd))}function vt(e){Dn(),this.a=Y9(e)}function vn(e,t){e.Td(t),t.Sd(e)}function vr(e,t){e.a.ec().Mc(t)}function vi(e,t,n){e.c.lf(t,n)}function va(e){gE.call(this,e)}function vo(e){gL.call(this,e)}function vs(){fM.call(this,"")}function vu(){fM.call(this,"")}function vc(){fM.call(this,"")}function vl(){fM.call(this,"")}function vf(e){gE.call(this,e)}function vd(e){fF.call(this,e)}function vh(e){O2.call(this,e)}function vp(e){vd.call(this,e)}function vb(){ls.call(this,null)}function vm(){ls.call(this,null)}function vg(){vg=A,$O()}function vv(){vv=A,e2d=eyz()}function vy(e){return e.a?e.b:0}function vw(e){return e.a?e.b:0}function v_(e,t){return e.a-t.a}function vE(e,t){return e.a-t.a}function vS(e,t){return e.a-t.a}function vk(e,t){return QO(e,t)}function vx(e,t){return z9(e,t)}function vT(e,t){return t in e.a}function vM(e,t){return e.f=t,e}function vO(e,t){return e.b=t,e}function vA(e,t){return e.c=t,e}function vL(e,t){return e.g=t,e}function vC(e,t){return e.a=t,e}function vI(e,t){return e.f=t,e}function vD(e,t){return e.k=t,e}function vN(e,t){return e.a=t,e}function vP(e,t){return e.e=t,e}function vR(e,t){return e.e=t,e}function vj(e,t){return e.f=t,e}function vF(e,t){e.b=!0,e.d=t}function vY(e,t){e.b=new TS(t)}function vB(e,t,n){t.td(e.a[n])}function vU(e,t,n){t.we(e.a[n])}function vH(e,t){return e.b-t.b}function v$(e,t){return e.g-t.g}function vz(e,t){return e.s-t.s}function vG(e,t){return e?0:t-1}function vW(e,t){return e?0:t-1}function vK(e,t){return e?t-1:0}function vV(e,t){return t.Yf(e)}function vq(e,t){return e.b=t,e}function vZ(e,t){return e.a=t,e}function vX(e,t){return e.c=t,e}function vJ(e,t){return e.d=t,e}function vQ(e,t){return e.e=t,e}function v1(e,t){return e.f=t,e}function v0(e,t){return e.a=t,e}function v2(e,t){return e.b=t,e}function v3(e,t){return e.c=t,e}function v4(e,t){return e.c=t,e}function v5(e,t){return e.b=t,e}function v6(e,t){return e.d=t,e}function v9(e,t){return e.e=t,e}function v8(e,t){return e.f=t,e}function v7(e,t){return e.g=t,e}function ye(e,t){return e.a=t,e}function yt(e,t){return e.i=t,e}function yn(e,t){return e.j=t,e}function yr(e,t){return e.k=t,e}function yi(e,t){return e.j=t,e}function ya(e,t){e_z(),Gc(t,e)}function yo(e,t,n){jX(e.a,t,n)}function ys(e){U8.call(this,e)}function yu(e){U8.call(this,e)}function yc(e){I3.call(this,e)}function yl(e){efB.call(this,e)}function yf(e){eta.call(this,e)}function yd(e){HO.call(this,e)}function yh(e){HO.call(this,e)}function yp(){MA.call(this,"")}function yb(){this.a=0,this.b=0}function ym(){this.b=0,this.a=0}function yg(e,t){e.b=0,enh(e,t)}function yv(e,t){e.c=t,e.b=!0}function yy(e,t){return e.c._b(t)}function yw(e){return e.e&&e.e()}function y_(e){return e?e.d:null}function yE(e,t){return ecD(e.b,t)}function yS(e){return e?e.g:null}function yk(e){return e?e.i:null}function yx(e){return LW(e),e.o}function yT(){yT=A,tmc=evO()}function yM(){yM=A,tml=ewS()}function yO(){yO=A,tgg=evL()}function yA(){yA=A,tvE=evA()}function yL(){yL=A,tvS=eSH()}function yC(){yC=A,tmF=enF()}function yI(){throw p7(new bO)}function yD(){throw p7(new bO)}function yN(){throw p7(new bO)}function yP(){throw p7(new bO)}function yR(){throw p7(new bO)}function yj(){throw p7(new bO)}function yF(e){this.a=new w8(e)}function yY(e){eF7(),eBh(this,e)}function yB(e){this.a=new FG(e)}function yU(e,t){for(;e.ye(t););}function yH(e,t){for(;e.sd(t););}function y$(e,t){return e.a+=t,e}function yz(e,t){return e.a+=t,e}function yG(e,t){return e.a+=t,e}function yW(e,t){return e.a+=t,e}function yK(e){return B1(e),e.a}function yV(e){return e.b!=e.d.c}function yq(e){return e.l|e.m<<22}function yZ(e,t){return e.d[t.p]}function yX(e,t){return eA5(e,t)}function yJ(e,t,n){e.splice(t,n)}function yQ(e){e.c?eL3(e):eL4(e)}function y1(e){this.a=0,this.b=e}function y0(){this.a=new eAs(e5I)}function y2(){this.b=new eAs(e5T)}function y3(){this.b=new eAs(e5H)}function y4(){this.b=new eAs(e5H)}function y5(){throw p7(new bO)}function y6(){throw p7(new bO)}function y9(){throw p7(new bO)}function y8(){throw p7(new bO)}function y7(){throw p7(new bO)}function we(){throw p7(new bO)}function wt(){throw p7(new bO)}function wn(){throw p7(new bO)}function wr(){throw p7(new bO)}function wi(){throw p7(new bO)}function wa(){throw p7(new bC)}function wo(){throw p7(new bC)}function ws(e){this.a=new wu(e)}function wu(e){erh(this,e,ey0())}function wc(e){return!e||BV(e)}function wl(e){return -1!=tvJ[e]}function wf(){0!=e1Z&&(e1Z=0),e1J=-1}function wd(){null==eUn&&(eUn=[])}function wh(e,t){eTl(H9(e.a),t)}function wp(e,t){eTl(H9(e.a),t)}function wb(e,t){OC.call(this,e,t)}function wm(e,t){wb.call(this,e,t)}function wg(e,t){this.b=e,this.c=t}function wv(e,t){this.b=e,this.a=t}function wy(e,t){this.a=e,this.b=t}function ww(e,t){this.a=e,this.b=t}function w_(e,t){this.a=e,this.b=t}function wE(e,t){this.a=e,this.b=t}function wS(e,t){this.a=e,this.b=t}function wk(e,t){this.a=e,this.b=t}function wx(e,t){this.a=e,this.b=t}function wT(e,t){this.a=e,this.b=t}function wM(e,t){this.b=e,this.a=t}function wO(e,t){this.b=e,this.a=t}function wA(e,t){this.b=e,this.a=t}function wL(e,t){this.b=e,this.a=t}function wC(e,t){this.f=e,this.g=t}function wI(e,t){this.e=e,this.d=t}function wD(e,t){this.g=e,this.i=t}function wN(e,t){this.a=e,this.b=t}function wP(e,t){this.a=e,this.f=t}function wR(e,t){this.b=e,this.c=t}function wj(e,t){this.a=e,this.b=t}function wF(e,t){this.a=e,this.b=t}function wY(e,t){this.a=e,this.b=t}function wB(e){Oq(e.dc()),this.c=e}function wU(e){this.b=Pp(Y9(e),83)}function wH(e){this.a=Pp(Y9(e),83)}function w$(e){this.a=Pp(Y9(e),15)}function wz(e){this.a=Pp(Y9(e),15)}function wG(e){this.b=Pp(Y9(e),47)}function wW(){this.q=new eB4.Date}function wK(){wK=A,e0V=new L}function wV(){wV=A,e2o=new T}function wq(e){return e.f.c+e.g.c}function wZ(e,t){return e.b.Hc(t)}function wX(e,t){return e.b.Ic(t)}function wJ(e,t){return e.b.Qc(t)}function wQ(e,t){return e.b.Hc(t)}function w1(e,t){return e.c.uc(t)}function w0(e,t){return e.a._b(t)}function w2(e,t){return ecX(e.c,t)}function w3(e,t){return F9(e.b,t)}function w4(e,t){return e>t&&t0}function Ei(e,t){return 0>ecd(e,t)}function Ea(e,t){return e.a.get(t)}function Eo(e,t){return t.split(e)}function Es(e,t){return F9(e.e,t)}function Eu(e){return BJ(e),!1}function Ec(e){Gq.call(this,e,21)}function El(e,t){zL.call(this,e,t)}function Ef(e,t){wC.call(this,e,t)}function Ed(e,t){wC.call(this,e,t)}function Eh(e){BT(),IJ.call(this,e)}function Ep(e,t){jA(e,e.length,t)}function Eb(e,t){Yj(e,e.length,t)}function Em(e,t,n){t.ud(e.a.Ge(n))}function Eg(e,t,n){t.we(e.a.Fe(n))}function Ev(e,t,n){t.td(e.a.Kb(n))}function Ey(e,t,n){e.Mb(n)&&t.td(n)}function Ew(e,t,n){e.splice(t,0,n)}function E_(e,t){return Aa(e.e,t)}function EE(e,t){this.d=e,this.e=t}function ES(e,t){this.b=e,this.a=t}function Ek(e,t){this.b=e,this.a=t}function Ex(e,t){this.b=e,this.a=t}function ET(e,t){this.a=e,this.b=t}function EM(e,t){this.a=e,this.b=t}function EO(e,t){this.a=e,this.b=t}function EA(e,t){this.a=e,this.b=t}function EL(e,t){this.a=e,this.b=t}function EC(e,t){this.b=e,this.a=t}function EI(e,t){this.b=e,this.a=t}function ED(e,t){wC.call(this,e,t)}function EN(e,t){wC.call(this,e,t)}function EP(e,t){wC.call(this,e,t)}function ER(e,t){wC.call(this,e,t)}function Ej(e,t){wC.call(this,e,t)}function EF(e,t){wC.call(this,e,t)}function EY(e,t){wC.call(this,e,t)}function EB(e,t){wC.call(this,e,t)}function EU(e,t){wC.call(this,e,t)}function EH(e,t){wC.call(this,e,t)}function E$(e,t){wC.call(this,e,t)}function Ez(e,t){wC.call(this,e,t)}function EG(e,t){wC.call(this,e,t)}function EW(e,t){wC.call(this,e,t)}function EK(e,t){wC.call(this,e,t)}function EV(e,t){wC.call(this,e,t)}function Eq(e,t){wC.call(this,e,t)}function EZ(e,t){wC.call(this,e,t)}function EX(e,t){this.a=e,this.b=t}function EJ(e,t){this.a=e,this.b=t}function EQ(e,t){this.a=e,this.b=t}function E1(e,t){this.a=e,this.b=t}function E0(e,t){this.a=e,this.b=t}function E2(e,t){this.a=e,this.b=t}function E3(e,t){this.a=e,this.b=t}function E4(e,t){this.a=e,this.b=t}function E5(e,t){this.a=e,this.b=t}function E6(e,t){this.b=e,this.a=t}function E9(e,t){this.b=e,this.a=t}function E8(e,t){this.b=e,this.a=t}function E7(e,t){this.b=e,this.a=t}function Se(e,t){this.c=e,this.d=t}function St(e,t){this.e=e,this.d=t}function Sn(e,t){this.a=e,this.b=t}function Sr(e,t){this.b=t,this.c=e}function Si(e,t){wC.call(this,e,t)}function Sa(e,t){wC.call(this,e,t)}function So(e,t){wC.call(this,e,t)}function Ss(e,t){wC.call(this,e,t)}function Su(e,t){wC.call(this,e,t)}function Sc(e,t){wC.call(this,e,t)}function Sl(e,t){wC.call(this,e,t)}function Sf(e,t){wC.call(this,e,t)}function Sd(e,t){wC.call(this,e,t)}function Sh(e,t){wC.call(this,e,t)}function Sp(e,t){wC.call(this,e,t)}function Sb(e,t){wC.call(this,e,t)}function Sm(e,t){wC.call(this,e,t)}function Sg(e,t){wC.call(this,e,t)}function Sv(e,t){wC.call(this,e,t)}function Sy(e,t){wC.call(this,e,t)}function Sw(e,t){wC.call(this,e,t)}function S_(e,t){wC.call(this,e,t)}function SE(e,t){wC.call(this,e,t)}function SS(e,t){wC.call(this,e,t)}function Sk(e,t){wC.call(this,e,t)}function Sx(e,t){wC.call(this,e,t)}function ST(e,t){wC.call(this,e,t)}function SM(e,t){wC.call(this,e,t)}function SO(e,t){wC.call(this,e,t)}function SA(e,t){wC.call(this,e,t)}function SL(e,t){wC.call(this,e,t)}function SC(e,t){wC.call(this,e,t)}function SI(e,t){wC.call(this,e,t)}function SD(e,t){wC.call(this,e,t)}function SN(e,t){wC.call(this,e,t)}function SP(e,t){wC.call(this,e,t)}function SR(e,t){wC.call(this,e,t)}function Sj(e,t){wC.call(this,e,t)}function SF(e,t){this.b=e,this.a=t}function SY(e,t){this.a=e,this.b=t}function SB(e,t){this.a=e,this.b=t}function SU(e,t){this.a=e,this.b=t}function SH(e,t){this.a=e,this.b=t}function S$(e,t){wC.call(this,e,t)}function Sz(e,t){wC.call(this,e,t)}function SG(e,t){this.b=e,this.d=t}function SW(e,t){wC.call(this,e,t)}function SK(e,t){wC.call(this,e,t)}function SV(e,t){this.a=e,this.b=t}function Sq(e,t){this.a=e,this.b=t}function SZ(e,t){wC.call(this,e,t)}function SX(e,t){wC.call(this,e,t)}function SJ(e,t){wC.call(this,e,t)}function SQ(e,t){wC.call(this,e,t)}function S1(e,t){wC.call(this,e,t)}function S0(e,t){wC.call(this,e,t)}function S2(e,t){wC.call(this,e,t)}function S3(e,t){wC.call(this,e,t)}function S4(e,t){wC.call(this,e,t)}function S5(e,t){wC.call(this,e,t)}function S6(e,t){wC.call(this,e,t)}function S9(e,t){wC.call(this,e,t)}function S8(e,t){wC.call(this,e,t)}function S7(e,t){wC.call(this,e,t)}function ke(e,t){wC.call(this,e,t)}function kt(e,t){wC.call(this,e,t)}function kn(e,t){return Aa(e.c,t)}function kr(e,t){return Aa(t.b,e)}function ki(e,t){return-e.b.Je(t)}function ka(e,t){return Aa(e.g,t)}function ko(e,t){wC.call(this,e,t)}function ks(e,t){wC.call(this,e,t)}function ku(e,t){this.a=e,this.b=t}function kc(e,t){this.a=e,this.b=t}function kl(e,t){this.a=e,this.b=t}function kf(e,t){wC.call(this,e,t)}function kd(e,t){wC.call(this,e,t)}function kh(e,t){wC.call(this,e,t)}function kp(e,t){wC.call(this,e,t)}function kb(e,t){wC.call(this,e,t)}function km(e,t){wC.call(this,e,t)}function kg(e,t){wC.call(this,e,t)}function kv(e,t){wC.call(this,e,t)}function ky(e,t){wC.call(this,e,t)}function kw(e,t){wC.call(this,e,t)}function k_(e,t){wC.call(this,e,t)}function kE(e,t){wC.call(this,e,t)}function kS(e,t){wC.call(this,e,t)}function kk(e,t){wC.call(this,e,t)}function kx(e,t){wC.call(this,e,t)}function kT(e,t){wC.call(this,e,t)}function kM(e,t){this.a=e,this.b=t}function kO(e,t){this.a=e,this.b=t}function kA(e,t){this.a=e,this.b=t}function kL(e,t){this.a=e,this.b=t}function kC(e,t){this.a=e,this.b=t}function kI(e,t){this.a=e,this.b=t}function kD(e,t){this.a=e,this.b=t}function kN(e,t){wC.call(this,e,t)}function kP(e,t){this.a=e,this.b=t}function kR(e,t){this.a=e,this.b=t}function kj(e,t){this.a=e,this.b=t}function kF(e,t){this.a=e,this.b=t}function kY(e,t){this.a=e,this.b=t}function kB(e,t){this.a=e,this.b=t}function kU(e,t){this.b=e,this.a=t}function kH(e,t){this.b=e,this.a=t}function k$(e,t){this.b=e,this.a=t}function kz(e,t){this.b=e,this.a=t}function kG(e,t){this.a=e,this.b=t}function kW(e,t){this.a=e,this.b=t}function kK(e,t){eOU(e.a,Pp(t,56))}function kV(e,t){QM(e.a,Pp(t,11))}function kq(e,t){return Pj(),t!=e}function kZ(){return vv(),new e2d}function kX(){Gk(),this.b=new bV}function kJ(){eAV(),this.a=new bV}function kQ(){Gy(),jG.call(this)}function k1(e,t){wC.call(this,e,t)}function k0(e,t){this.a=e,this.b=t}function k2(e,t){this.a=e,this.b=t}function k3(e,t){this.a=e,this.b=t}function k4(e,t){this.a=e,this.b=t}function k5(e,t){this.a=e,this.b=t}function k6(e,t){this.a=e,this.b=t}function k9(e,t){this.d=e,this.b=t}function k8(e,t){this.d=e,this.e=t}function k7(e,t){this.f=e,this.c=t}function xe(e,t){this.b=e,this.c=t}function xt(e,t){this.i=e,this.g=t}function xn(e,t){this.e=e,this.a=t}function xr(e,t){this.a=e,this.b=t}function xi(e,t){e.i=null,erA(e,t)}function xa(e,t){e&&Um(tmR,e,t)}function xo(e,t){return edG(e.a,t)}function xs(e){return edK(e.c,e.b)}function xu(e){return e?e.dd():null}function xc(e){return null==e?null:e}function xl(e){return typeof e===eUi}function xf(e){return typeof e===eUa}function xd(e){return typeof e===eUo}function xh(e,t){return e.Hd().Xb(t)}function xp(e,t){return ei7(e.Kc(),t)}function xb(e,t){return 0==ecd(e,t)}function xm(e,t){return ecd(e,t)>=0}function xg(e,t){return 0!=ecd(e,t)}function xv(e){return""+(BJ(e),e)}function xy(e,t){return e.substr(t)}function xw(e){return efH(e),e.d.gc()}function x_(e){return eTe(e,e.c),e}function xE(e){return Rb(null==e),e}function xS(e,t){return e.a+=""+t,e}function xk(e,t){return e.a+=""+t,e}function xx(e,t){return e.a+=""+t,e}function xT(e,t){return e.a+=""+t,e}function xM(e,t){return e.a+=""+t,e}function xO(e,t){return e.a+=""+t,e}function xA(e,t){qQ(e,t,e.a,e.a.a)}function xL(e,t){qQ(e,t,e.c.b,e.c)}function xC(e,t,n){eyc(t,eSE(e,n))}function xI(e,t,n){eyc(t,eSE(e,n))}function xD(e,t){eeS(new Ow(e),t)}function xN(e,t){e.q.setTime(Kj(t))}function xP(e,t){FH.call(this,e,t)}function xR(e,t){FH.call(this,e,t)}function xj(e,t){FH.call(this,e,t)}function xF(e){Yy(this),eij(this,e)}function xY(e){return GK(e,0),null}function xB(e){return e.a=0,e.b=0,e}function xU(e,t){return e.a=t.g+1,e}function xH(e,t){return 2==e.j[t.p]}function x$(e){return YZ(Pp(e,79))}function xz(){xz=A,e4r=euY(epE())}function xG(){xG=A,e7$=euY(eAn())}function xW(){this.b=new w8(ee0(12))}function xK(){this.b=0,this.a=!1}function xV(){this.b=0,this.a=!1}function xq(e){this.a=e,ci.call(this)}function xZ(e){this.a=e,ci.call(this)}function xX(e,t){Cm.call(this,e,t)}function xJ(e,t){Ii.call(this,e,t)}function xQ(e,t){xt.call(this,e,t)}function x1(e,t){eaN.call(this,e,t)}function x0(e,t){AA.call(this,e,t)}function x2(e,t){_5(),Um(tmU,e,t)}function x3(e,t){return Az(e.a,0,t)}function x4(e,t){return e.a.a.a.cc(t)}function x5(e,t){return xc(e)===xc(t)}function x6(e,t){return elN(e.a,t.a)}function x9(e,t){return ME(e.a,t.a)}function x8(e,t){return YM(e.a,t.a)}function x7(e,t){return e.indexOf(t)}function Te(e,t){return e==t?0:e?1:-1}function Tt(e){return e<10?"0"+e:""+e}function Tn(e){return Y9(e),new xq(e)}function Tr(e){return Mk(e.l,e.m,e.h)}function Ti(e){return zy((BJ(e),e))}function Ta(e){return zy((BJ(e),e))}function To(e,t){return ME(e.g,t.g)}function Ts(e){return typeof e===eUa}function Tu(e){return e==e8f||e==e8p}function Tc(e){return e==e8f||e==e8d}function Tl(e){return QI(e.b.b,e,0)}function Tf(e){this.a=kZ(),this.b=e}function Td(e){this.a=kZ(),this.b=e}function Th(e,t){return P_(e.a,t),t}function Tp(e,t){return P_(e.c,t),e}function Tb(e,t){return eat(e.a,t),e}function Tm(e,t){return Dj(),t.a+=e}function Tg(e,t){return Dj(),t.a+=e}function Tv(e,t){return Dj(),t.c+=e}function Ty(e,t){Qe(e,0,e.length,t)}function Tw(){fJ.call(this,new qh)}function T_(){jp.call(this,0,0,0,0)}function TE(){Hr.call(this,0,0,0,0)}function TS(e){this.a=e.a,this.b=e.b}function Tk(e){return e==tpm||e==tpg}function Tx(e){return e==tpy||e==tpb}function TT(e){return e==tss||e==tso}function TM(e){return e!=tbc&&e!=tbl}function TO(e){return e.Lg()&&e.Mg()}function TA(e){return UB(Pp(e,118))}function TL(e){return eat(new K2,e)}function TC(e,t){return new eaN(t,e)}function TI(e,t){return new eaN(t,e)}function TD(e,t,n){ent(e,t),enn(e,n)}function TN(e,t,n){ena(e,t),eni(e,n)}function TP(e,t,n){eno(e,t),ens(e,n)}function TR(e,t,n){enr(e,t),enc(e,n)}function Tj(e,t,n){enu(e,t),enl(e,n)}function TF(e,t){euc(e,t),enp(e,e.D)}function TY(e){k7.call(this,e,!0)}function TB(e,t,n){L3.call(this,e,t,n)}function TU(e){eLQ(),ead.call(this,e)}function TH(){Ef.call(this,"Head",1)}function T$(){Ef.call(this,"Tail",3)}function Tz(e){e.c=Je(e1R,eUp,1,0,5,1)}function TG(e){e.a=Je(e1R,eUp,1,8,5,1)}function TW(e){ety(e.xf(),new dh(e))}function TK(e){return null!=e?esj(e):0}function TV(e,t){return etg(t,zY(e))}function Tq(e,t){return etg(t,zY(e))}function TZ(e,t){return e[e.length]=t}function TX(e,t){return e[e.length]=t}function TJ(e){return Ph(e.b.Kc(),e.a)}function TQ(e,t){return erb(Bi(e.d),t)}function T1(e,t){return erb(Bi(e.g),t)}function T0(e,t){return erb(Bi(e.j),t)}function T2(e,t){Cm.call(this,e.b,t)}function T3(e){jp.call(this,e,e,e,e)}function T4(e){return e.b&&ePE(e),e.a}function T5(e){return e.b&&ePE(e),e.c}function T6(e,t){!e2M&&(e.b=t)}function T9(e,t,n){return Bc(e,t,n),n}function T8(e,t,n){Bc(e.c[t.g],t.g,n)}function T7(e,t,n){Pp(e.c,69).Xh(t,n)}function Me(e,t,n){TP(n,n.i+e,n.j+t)}function Mt(e,t){JL(qt(e.a),Gj(t))}function Mn(e,t){JL(QX(e.a),GF(t))}function Mr(e){eBG(),pJ.call(this,e)}function Mi(e){return null==e?0:esj(e)}function Ma(){Ma=A,tuT=new efY(e59)}function Mo(){Mo=A,new Ms,new p0}function Ms(){new p2,new p2,new p2}function Mu(){Mu=A,bR(),e0S=new p2}function Mc(){Mc=A,eB4.Math.log(2)}function Ml(){Ml=A,tgZ=(_Z(),tmE)}function Mf(){throw p7(new gW(e1O))}function Md(){throw p7(new gW(e1O))}function Mh(){throw p7(new gW(e1A))}function Mp(){throw p7(new gW(e1A))}function Mb(e){this.a=e,PS.call(this,e)}function Mm(e){this.a=e,wU.call(this,e)}function Mg(e){this.a=e,wU.call(this,e)}function Mv(e,t){jM(e.c,e.c.length,t)}function My(e){return e.at?1:0}function MS(e,t){return ecd(e,t)>0?e:t}function Mk(e,t,n){return{l:e,m:t,h:n}}function Mx(e,t){null!=e.a&&kV(t,e.a)}function MT(e){e.a=new C,e.c=new C}function MM(e){this.b=e,this.a=new p0}function MO(e){this.b=new e1,this.a=e}function MA(e){CW.call(this),this.a=e}function ML(){Ef.call(this,"Range",2)}function MC(){evR(),this.a=new eAs(e4k)}function MI(e,t){Y9(t),Uz(e).Jc(new d)}function MD(e,t){return GE(),t.n.b+=e}function MN(e,t,n){return Um(e.g,n,t)}function MP(e,t,n){return Um(e.k,n,t)}function MR(e,t){return Um(e.a,t.a,t)}function Mj(e,t,n){return eho(t,n,e.c)}function MF(e){return new kl(e.c,e.d)}function MY(e){return new kl(e.c,e.d)}function MB(e){return new kl(e.a,e.b)}function MU(e,t){return ej8(e.a,t,null)}function MH(e){Gs(e,null),Go(e,null)}function M$(e){GA(e,null),GL(e,null)}function Mz(){AA.call(this,null,null)}function MG(){AL.call(this,null,null)}function MW(e){this.a=e,p2.call(this)}function MK(e){this.b=(Hj(),new f$(e))}function MV(e){e.j=Je(e18,eUP,310,0,0,1)}function Mq(e,t,n){e.c.Vc(t,Pp(n,133))}function MZ(e,t,n){e.c.ji(t,Pp(n,133))}function MX(e,t){eRT(e),e.Gc(Pp(t,15))}function MJ(e,t){return eR4(e.c,e.b,t)}function MQ(e,t){return new O6(e.Kc(),t)}function M1(e,t){return -1!=eoD(e.Kc(),t)}function M0(e,t){return null!=e.a.Bc(t)}function M2(e){return e.Ob()?e.Pb():null}function M3(e){return ehv(e,0,e.length)}function M4(e,t){return null!=e&&ebs(e,t)}function M5(e,t){e.q.setHours(t),eNq(e,t)}function M6(e,t){e.c&&(Re(t),zd(t))}function M9(e,t,n){Pp(e.Kb(n),164).Nb(t)}function M8(e,t,n){return ejq(e,t,n),n}function M7(e,t,n){e.a=1502^t,e.b=n^e$d}function Oe(e,t,n){return e.a[t.g][n.g]}function Ot(e,t){return e.a[t.c.p][t.p]}function On(e,t){return e.e[t.c.p][t.p]}function Or(e,t){return e.c[t.c.p][t.p]}function Oi(e,t){return e.j[t.p]=eOo(t)}function Oa(e,t){return ZZ(e.f,t.tg())}function Oo(e,t){return ZZ(e.b,t.tg())}function Os(e,t){return e.a0?t*t/e:t*t*100}function Li(e,t){return e>0?t/(e*e):100*t}function La(e,t,n){return P_(t,ef5(e,n))}function Lo(e,t,n){J1(),e.Xe(t)&&n.td(e)}function Ls(e,t,n){var r;(r=e.Zc(t)).Rb(n)}function Lu(e,t,n){return e.a+=t,e.b+=n,e}function Lc(e,t,n){return e.a*=t,e.b*=n,e}function Ll(e,t,n){return e.a-=t,e.b-=n,e}function Lf(e,t){return e.a=t.a,e.b=t.b,e}function Ld(e){return e.a=-e.a,e.b=-e.b,e}function Lh(e){this.c=e,this.a=1,this.b=1}function Lp(e){this.c=e,eno(e,0),ens(e,0)}function Lb(e){_n.call(this),enD(this,e)}function Lm(e){eBp(),p8(this),this.mf(e)}function Lg(e,t){_0(),AA.call(this,e,t)}function Lv(e,t){_2(),AL.call(this,e,t)}function Ly(e,t){_2(),AL.call(this,e,t)}function Lw(e,t){_2(),Lv.call(this,e,t)}function L_(e,t,n){JY.call(this,e,t,n,2)}function LE(e,t){Ml(),jd.call(this,e,t)}function LS(e,t){Ml(),LE.call(this,e,t)}function Lk(e,t){Ml(),LE.call(this,e,t)}function Lx(e,t){Ml(),Lk.call(this,e,t)}function LT(e,t){Ml(),jd.call(this,e,t)}function LM(e,t){Ml(),LT.call(this,e,t)}function LO(e,t){Ml(),jd.call(this,e,t)}function LA(e,t){return e.c.Fc(Pp(t,133))}function LL(e,t,n){return eP9(Qq(e,t),n)}function LC(e,t,n){return t.Qk(e.e,e.c,n)}function LI(e,t,n){return t.Rk(e.e,e.c,n)}function LD(e,t){return ecv(e.e,Pp(t,49))}function LN(e,t,n){elm(QX(e.a),t,GF(n))}function LP(e,t,n){elm(qt(e.a),t,Gj(n))}function LR(e,t){t.$modCount=e.$modCount}function Lj(){Lj=A,tcV=new pO("root")}function LF(){LF=A,tmB=new mx,new mT}function LY(){this.a=new zu,this.b=new zu}function LB(){en0.call(this),this.Bb|=eH3}function LU(){wC.call(this,"GROW_TREE",0)}function LH(e){return null==e?null:eYt(e)}function L$(e){return null==e?null:eEO(e)}function Lz(e){return null==e?null:efF(e)}function LG(e){return null==e?null:efF(e)}function LW(e){null==e.o&&eMb(e)}function LK(e){return Rb(null==e||xl(e)),e}function LV(e){return Rb(null==e||xf(e)),e}function Lq(e){return Rb(null==e||xd(e)),e}function LZ(e){this.q=new eB4.Date(Kj(e))}function LX(e,t){this.c=e,wI.call(this,e,t)}function LJ(e,t){this.a=e,LX.call(this,e,t)}function LQ(e,t){this.d=e,f_(this),this.b=t}function L1(e,t){Jo.call(this,e),this.a=t}function L0(e,t){Jo.call(this,e),this.a=t}function L2(e){edL.call(this,0,0),this.f=e}function L3(e,t,n){XS.call(this,e,t,n,null)}function L4(e,t,n){XS.call(this,e,t,n,null)}function L5(e,t,n){return 0>=e.ue(t,n)?n:t}function L6(e,t,n){return 0>=e.ue(t,n)?t:n}function L9(e,t){return Pp(eef(e.b,t),149)}function L8(e,t){return Pp(eef(e.c,t),229)}function L7(e){return Pp(RJ(e.a,e.b),287)}function Ce(e){return new kl(e.c,e.d+e.a)}function Ct(e){return GE(),TT(Pp(e,197))}function Cn(){Cn=A,e4i=el9((ed6(),tbq))}function Cr(e,t){t.a?eLc(e,t):Ai(e.a,t.b)}function Ci(e,t){!e2M&&P_(e.a,t)}function Ca(e,t){return _k(),eag(t.d.i,e)}function Co(e,t){return erJ(),new eIu(t,e)}function Cs(e,t){return $C(t,ezr),e.f=t,e}function Cu(e,t,n){return n=eDg(e,t,3,n)}function Cc(e,t,n){return n=eDg(e,t,6,n)}function Cl(e,t,n){return n=eDg(e,t,9,n)}function Cf(e,t,n){++e.j,e.Ki(),X8(e,t,n)}function Cd(e,t,n){++e.j,e.Hi(t,e.oi(t,n))}function Ch(e,t,n){var r;(r=e.Zc(t)).Rb(n)}function Cp(e,t,n){return ePT(e.c,e.b,t,n)}function Cb(e,t){return(t&eUu)%e.d.length}function Cm(e,t){pO.call(this,e),this.a=t}function Cg(e,t){pH.call(this,e),this.a=t}function Cv(e,t){pH.call(this,e),this.a=t}function Cy(e,t){this.c=e,eta.call(this,t)}function Cw(e,t){this.a=e,pU.call(this,t)}function C_(e,t){this.a=e,pU.call(this,t)}function CE(e){this.a=(enG(e,eU3),new XM(e))}function CS(e){this.a=(enG(e,eU3),new XM(e))}function Ck(e){return e.a||(e.a=new h),e.a}function Cx(e){return e>8?0:e+1}function CT(e,t){return OQ(),e==t?0:e?1:-1}function CM(e,t,n){return jT(e,Pp(t,22),n)}function CO(e,t,n){return e.apply(t,n)}function CA(e,t,n){return e.a+=ehv(t,0,n),e}function CL(e,t){var n;return n=e.e,e.e=t,n}function CC(e,t){var n;(n=e[e$c]).call(e,t)}function CI(e,t){var n;(n=e[e$c]).call(e,t)}function CD(e,t){e.a.Vc(e.b,t),++e.b,e.c=-1}function CN(e){Yy(e.e),e.d.b=e.d,e.d.a=e.d}function CP(e){e.b?CP(e.b):e.f.c.zc(e.e,e.d)}function CR(e,t,n){_w(),lP(e,t.Ce(e.a,n))}function Cj(e,t){return y_(ehn(e.a,t,!0))}function CF(e,t){return y_(ehr(e.a,t,!0))}function CY(e,t){return vk(Array(t),e)}function CB(e){return String.fromCharCode(e)}function CU(e){return null==e?null:e.message}function CH(){this.a=new p0,this.b=new p0}function C$(){this.a=new tt,this.b=new bP}function Cz(){this.b=new yb,this.c=new p0}function CG(){this.d=new yb,this.e=new yb}function CW(){this.n=new yb,this.o=new yb}function CK(){this.n=new mp,this.i=new TE}function CV(){this.a=new cg,this.b=new i_}function Cq(){this.a=new p0,this.d=new p0}function CZ(){this.b=new bV,this.a=new bV}function CX(){this.b=new p2,this.a=new p2}function CJ(){this.b=new y2,this.a=new ay}function CQ(){CK.call(this),this.a=new yb}function C1(e){eaD.call(this,e,(Qu(),e2D))}function C0(e,t,n,r){jp.call(this,e,t,n,r)}function C2(e,t,n){null!=n&&ern(t,emI(e,n))}function C3(e,t,n){null!=n&&err(t,emI(e,n))}function C4(e,t,n){return n=eDg(e,t,11,n)}function C5(e,t){return e.a+=t.a,e.b+=t.b,e}function C6(e,t){return e.a-=t.a,e.b-=t.b,e}function C9(e,t){return e.n.a=(BJ(t),t+10)}function C8(e,t){return e.n.a=(BJ(t),t+10)}function C7(e,t){return t==e||ev9(eOg(t),e)}function Ie(e,t){return null==Um(e.a,t,"")}function It(e,t){return _k(),!eag(t.d.i,e)}function In(e,t){Tk(e.f)?eMi(e,t):ewz(e,t)}function Ir(e,t){var n;return t.Hh(e.a)}function Ii(e,t){gE.call(this,eJT+e+eXH+t)}function Ia(e,t,n,r){FQ.call(this,e,t,n,r)}function Io(e,t,n,r){FQ.call(this,e,t,n,r)}function Is(e,t,n,r){Io.call(this,e,t,n,r)}function Iu(e,t,n,r){F1.call(this,e,t,n,r)}function Ic(e,t,n,r){F1.call(this,e,t,n,r)}function Il(e,t,n,r){F1.call(this,e,t,n,r)}function If(e,t,n,r){Ic.call(this,e,t,n,r)}function Id(e,t,n,r){Ic.call(this,e,t,n,r)}function Ih(e,t,n,r){Il.call(this,e,t,n,r)}function Ip(e,t,n,r){Id.call(this,e,t,n,r)}function Ib(e,t,n,r){FZ.call(this,e,t,n,r)}function Im(e,t,n){this.a=e,AI.call(this,t,n)}function Ig(e,t,n){this.c=t,this.b=n,this.a=e}function Iv(e,t,n){return e.d=Pp(t.Kb(n),164)}function Iy(e,t){return e.Aj().Nh().Kh(e,t)}function Iw(e,t){return e.Aj().Nh().Ih(e,t)}function I_(e,t){return BJ(e),xc(e)===xc(t)}function IE(e,t){return BJ(e),xc(e)===xc(t)}function IS(e,t){return y_(ehn(e.a,t,!1))}function Ik(e,t){return y_(ehr(e.a,t,!1))}function Ix(e,t){return e.b.sd(new EM(e,t))}function IT(e,t){return e.b.sd(new EO(e,t))}function IM(e,t){return e.b.sd(new EA(e,t))}function IO(e,t,n){return e.lastIndexOf(t,n)}function IA(e,t,n){return elN(e[t.b],e[n.b])}function IL(e,t){return eo3(t,(eBy(),tat),e)}function IC(e,t){return ME(t.a.d.p,e.a.d.p)}function II(e,t){return ME(e.a.d.p,t.a.d.p)}function ID(e,t){return elN(e.c-e.s,t.c-t.s)}function IN(e){return e.c?QI(e.c.a,e,0):-1}function IP(e){return e<100?null:new yf(e)}function IR(e){return e==tba||e==tbs||e==tbo}function Ij(e,t){return M4(t,15)&&eCc(e.c,t)}function IF(e,t){!e2M&&t&&(e.d=t)}function IY(e,t){var n;return!!esq(e,n=t)}function IB(e,t){this.c=e,YC.call(this,e,t)}function IU(e){this.c=e,xj.call(this,eUY,0)}function IH(e,t){Px.call(this,e,e.length,t)}function I$(e,t,n){return Pp(e.c,69).lk(t,n)}function Iz(e,t,n){return Pp(e.c,69).mk(t,n)}function IG(e,t,n){return LC(e,Pp(t,332),n)}function IW(e,t,n){return LI(e,Pp(t,332),n)}function IK(e,t,n){return ey1(e,Pp(t,332),n)}function IV(e,t,n){return e_t(e,Pp(t,332),n)}function Iq(e,t){return null==t?null:ecA(e.b,t)}function IZ(e){return xf(e)?(BJ(e),e):e.ke()}function IX(e){return!isNaN(e)&&!isFinite(e)}function IJ(e){Dn(),this.a=(Hj(),new vd(e))}function IQ(e){Pj(),this.d=e,this.a=new p1}function I1(e,t,n){this.a=e,this.b=t,this.c=n}function I0(e,t,n){this.a=e,this.b=t,this.c=n}function I2(e,t,n){this.d=e,this.b=n,this.a=t}function I3(e){MT(this),HC(this),er7(this,e)}function I4(e){Tz(this),PO(this.c,0,e.Pc())}function I5(e){BH(e.a),Jl(e.c,e.b),e.b=null}function I6(e){this.a=e,wK(),eap(Date.now())}function I9(){I9=A,e2G=new r,e2W=new r}function I8(){I8=A,e2h=new I,e2p=new D}function I7(){I7=A,tmY=Je(e1R,eUp,1,0,5,1)}function De(){De=A,tgH=Je(e1R,eUp,1,0,5,1)}function Dt(){Dt=A,tg$=Je(e1R,eUp,1,0,5,1)}function Dn(){Dn=A,new bb((Hj(),Hj(),e2r))}function Dr(e){return Qu(),eeM((Qc(),e2j),e)}function Di(e){return eum(),eeM((XC(),e2$),e)}function Da(e){return epC(),eeM((qk(),e3d),e)}function Do(e){return eeR(),eeM((qx(),e3b),e)}function Ds(e){return eCp(),eeM((eaF(),e3I),e)}function Du(e){return etx(),eeM((XO(),e3R),e)}function Dc(e){return Qs(),eeM((XA(),e3B),e)}function Dl(e){return QQ(),eeM((XL(),e3z),e)}function Df(e){return eBW(),eeM((xz(),e4r),e)}function Dd(e){return eaY(),eeM((Qf(),e4l),e)}function Dh(e){return ep7(),eeM((Qd(),e4b),e)}function Dp(e){return ebe(),eeM((Qh(),e6z),e)}function Db(e){return _y(),eeM((Vt(),e6W),e)}function Dm(e){return eej(),eeM((qT(),e9h),e)}function Dg(e){return QJ(),eeM((XI(),e96),e)}function Dv(e){return e_x(),eeM((eeW(),e8a),e)}function Dy(e){return eok(),eeM((Ql(),e8b),e)}function Dw(e){return ec4(),eeM((XD(),e8T),e)}function D_(e,t){if(!e)throw p7(new gL(t))}function DE(e){return eEn(),eeM((etQ(),e8R),e)}function DS(e){jp.call(this,e.d,e.c,e.a,e.b)}function Dk(e){jp.call(this,e.d,e.c,e.a,e.b)}function Dx(e,t,n){this.b=e,this.c=t,this.a=n}function DT(e,t,n){this.b=e,this.a=t,this.c=n}function DM(e,t,n){this.a=e,this.b=t,this.c=n}function DO(e,t,n){this.a=e,this.b=t,this.c=n}function DA(e,t,n){this.a=e,this.b=t,this.c=n}function DL(e,t,n){this.a=e,this.b=t,this.c=n}function DC(e,t,n){this.b=e,this.a=t,this.c=n}function DI(e,t,n){this.e=t,this.b=e,this.d=n}function DD(e,t,n){return _w(),e.a.Od(t,n),t}function DN(e){var t;return(t=new ew).e=e,t}function DP(e){var t;return(t=new me).b=e,t}function DR(){DR=A,e8V=new nd,e8q=new nh}function Dj(){Dj=A,e75=new rB,e76=new rU}function DF(e){return eoE(),eeM((Qb(),e7X),e)}function DY(e){return eoS(),eeM((Qg(),tet),e)}function DB(e){return eLz(),eeM((ei3(),tek),e)}function DU(e){return eSg(),eeM((et2(),teI),e)}function DH(e){return Jp(),eeM((qI(),teP),e)}function D$(e){return en7(),eeM((XN(),teY),e)}function Dz(e){return ey4(),eeM((eeU(),tes),e)}function DG(e){return erX(),eeM((Xj(),teb),e)}function DW(e){return enB(),eeM((XP(),te$),e)}function DK(e){return eb6(),eeM((eeY(),teq),e)}function DV(e){return eeF(),eeM((qO(),teJ),e)}function Dq(e){return eoG(),eeM((XR(),te2),e)}function DZ(e){return eEf(),eeM((et6(),te7),e)}function DX(e){return Qx(),eeM((qA(),ttn),e)}function DJ(e){return eyd(),eeM((et4(),ttc),e)}function DQ(e){return e_3(),eeM((et3(),ttm),e)}function D1(e){return eLR(),eeM((eoH(),ttM),e)}function D0(e){return eaU(),eeM((XY(),ttC),e)}function D2(e){return Q1(),eeM((XF(),ttP),e)}function D3(e){return K6(),eeM((qD(),ttF),e)}function D4(e){return ef_(),eeM((eeH(),tnF),e)}function D5(e){return ewY(),eeM((et5(),tst),e)}function D6(e){return euJ(),eeM((XB(),tsa),e)}function D9(e){return ebk(),eeM((Qv(),tsl),e)}function D8(e){return enY(),eeM((X$(),tsR),e)}function D7(e){return eOJ(),eeM((ei2(),tsx),e)}function Ne(e){return esn(),eeM((XH(),tsA),e)}function Nt(e){return Q0(),eeM((qC(),tsI),e)}function Nn(e){return ei0(),eeM((XU(),tsB),e)}function Nr(e){return ebG(),eeM((eeB(),tsm),e)}function Ni(e){return Xo(),eeM((qL(),ts$),e)}function Na(e){return euy(),eeM((XG(),tsK),e)}function No(e){return eiO(),eeM((XW(),tsX),e)}function Ns(e){return eox(),eeM((Xz(),ts0),e)}function Nu(e){return enU(),eeM((XK(),tuo),e)}function Nc(e){return qG(),eeM((qP(),tud),e)}function Nl(e){return zs(),eeM((qR(),tu_),e)}function Nf(e){return zQ(),eeM((qj(),tuk),e)}function Nd(e){return Xa(),eeM((qN(),tu$),e)}function Nh(e){return zo(),eeM((qF(),tuX),e)}function Np(e){return egR(),eeM((Qp(),tu2),e)}function Nb(e){return eS_(),eeM((et9(),tu7),e)}function Nm(e){return z1(),eeM((qU(),tcB),e)}function Ng(e){return erZ(),eeM((qB(),tcX),e)}function Nv(e){return Kn(),eeM((qY(),tc$),e)}function Ny(e){return efx(),eeM((XV(),tc0),e)}function Nw(e){return J0(),eeM((qH(),tc4),e)}function N_(e){return eub(),eeM((Xq(),tc8),e)}function NE(e){return emC(),eeM((Qm(),tlA),e)}function NS(e){return ei1(),eeM((XX(),tlD),e)}function Nk(e){return efS(),eeM((XZ(),tlj),e)}function Nx(e){return eOB(),eeM((eeG(),tfl),e)}function NT(e){return efk(),eeM((XJ(),tfp),e)}function NM(e){return _D(),eeM((K7(),tfm),e)}function NO(e){return _N(),eeM((K8(),tfv),e)}function NA(e){return Xs(),eeM((qz(),tf_),e)}function NL(e){return eEM(),eeM((ee$(),tfM),e)}function NC(e){return _P(),eeM((Ve(),tf7),e)}function NI(e){return eoT(),eeM((q$(),tdn),e)}function ND(e){return epx(),eeM((eez(),tdb),e)}function NN(e){return eSd(),eeM((ei4(),tdk),e)}function NP(e){return ebx(),eeM((et0(),tdD),e)}function NR(e){return eyY(),eeM((et1(),tdJ),e)}function Nj(e){return eB$(),eeM((xG(),e7$),e)}function NF(e){return erq(),eeM((qM(),e8K),e)}function NY(e){return ec3(),eeM((eeK(),tpw),e)}function NB(e){return etT(),eeM((X1(),tpk),e)}function NU(e){return efE(),eeM((Q_(),tpA),e)}function NH(e){return e_a(),eeM((et7(),tpR),e)}function N$(e){return eck(),eeM((XQ(),tpK),e)}function Nz(e){return egF(),eeM((Qw(),tpJ),e)}function NG(e){return eT7(),eeM((eaj(),tp8),e)}function NW(e){return epT(),eeM((eeV(),tbi),e)}function NK(e){return ewf(),eeM((etC(),tbf),e)}function NV(e){return ekU(),eeM((et8(),tbv),e)}function Nq(e){return ed6(),eeM((QS(),tbZ),e)}function NZ(e){return eI3(),eeM((eo$(),tb6),e)}function NX(e){return eYu(),eeM((eeq(),tbB),e)}function NJ(e){return edM(),eeM((QE(),tmt),e)}function NQ(e){return eup(),eeM((Qy(),tmo),e)}function N1(e){return eTy(),eeM((ei5(),tmP),e)}function N0(e,t){return BJ(e),e+(BJ(t),t)}function N2(e,t){return wK(),JL(H9(e.a),t)}function N3(e,t){return wK(),JL(H9(e.a),t)}function N4(e,t){this.c=e,this.a=t,this.b=t-e}function N5(e,t,n){this.a=e,this.b=t,this.c=n}function N6(e,t,n){this.a=e,this.b=t,this.c=n}function N9(e,t,n){this.a=e,this.b=t,this.c=n}function N8(e,t,n){this.a=e,this.b=t,this.c=n}function N7(e,t,n){this.a=e,this.b=t,this.c=n}function Pe(e,t,n){this.e=e,this.a=t,this.c=n}function Pt(e,t,n){Ml(),zl.call(this,e,t,n)}function Pn(e,t,n){Ml(),BP.call(this,e,t,n)}function Pr(e,t,n){Ml(),BP.call(this,e,t,n)}function Pi(e,t,n){Ml(),BP.call(this,e,t,n)}function Pa(e,t,n){Ml(),Pn.call(this,e,t,n)}function Po(e,t,n){Ml(),Pn.call(this,e,t,n)}function Ps(e,t,n){Ml(),Po.call(this,e,t,n)}function Pu(e,t,n){Ml(),Pr.call(this,e,t,n)}function Pc(e,t,n){Ml(),Pi.call(this,e,t,n)}function Pl(e,t){return Y9(e),Y9(t),new wx(e,t)}function Pf(e,t){return Y9(e),Y9(t),new Rn(e,t)}function Pd(e,t){return Y9(e),Y9(t),new Rr(e,t)}function Ph(e,t){return Y9(e),Y9(t),new wM(e,t)}function Pp(e,t){return Rb(null==e||ebs(e,t)),e}function Pb(e){var t;return t=new p0,eel(t,e),t}function Pm(e){var t;return t=new bV,eel(t,e),t}function Pg(e){var t;return ein(t=new b2,e),t}function Pv(e){var t;return ein(t=new _n,e),t}function Py(e){return e.e||(e.e=new p0),e.e}function Pw(e){return e.c||(e.c=new sk),e.c}function P_(e,t){return e.c[e.c.length]=t,!0}function PE(e,t){this.c=e,this.b=t,this.a=!1}function PS(e){this.d=e,f_(this),this.b=Ft(e.d)}function Pk(){this.a=";,;",this.b="",this.c=""}function Px(e,t,n){F$.call(this,t,n),this.a=e}function PT(e,t,n){this.b=e,xP.call(this,t,n)}function PM(e,t,n){this.c=e,EE.call(this,t,n)}function PO(e,t,n){ekp(n,0,e,t,n.length,!1)}function PA(e,t,n,r,i){e.b=t,e.c=n,e.d=r,e.a=i}function PL(e,t){t&&(e.b=t,e.a=(B1(t),t.a))}function PC(e,t,n,r,i){e.d=t,e.c=n,e.a=r,e.b=i}function PI(e){var t,n;t=e.b,n=e.c,e.b=n,e.c=t}function PD(e){var t,n;n=e.d,t=e.a,e.d=t,e.a=n}function PN(e){return eal(YE(Ts(e)?eaL(e):e))}function PP(e,t){return ME(Rx(e.d),Rx(t.d))}function PR(e,t){return t==(eYu(),tbY)?e.c:e.d}function Pj(){Pj=A,tuu=(eYu(),tbY),tuc=tby}function PF(){this.b=gP(LV(epB((eCk(),e9N))))}function PY(e){return _w(),Je(e1R,eUp,1,e,5,1)}function PB(e){return new kl(e.c+e.b,e.d+e.a)}function PU(e,t){return _C(),ME(e.d.p,t.d.p)}function PH(e){return A6(0!=e.b),etw(e,e.a.a)}function P$(e){return A6(0!=e.b),etw(e,e.c.b)}function Pz(e,t){if(!e)throw p7(new gS(t))}function PG(e,t){if(!e)throw p7(new gL(t))}function PW(e,t,n){Se.call(this,e,t),this.b=n}function PK(e,t,n){k8.call(this,e,t),this.c=n}function PV(e,t,n){etn.call(this,t,n),this.d=e}function Pq(e){Dt(),sr.call(this),this.th(e)}function PZ(e,t,n){this.a=e,xQ.call(this,t,n)}function PX(e,t,n){this.a=e,xQ.call(this,t,n)}function PJ(e,t,n){k8.call(this,e,t),this.c=n}function PQ(){ZE(),BY.call(this,(_Q(),tgp))}function P1(e){return null!=e&&!efz(e,tm1,tm0)}function P0(e,t){return(elt(e)<<4|elt(t))&eHd}function P2(e,t){return U_(),eb2(e,t),new Uf(e,t)}function P3(e,t){var n;e.n&&(n=t,P_(e.f,n))}function P4(e,t,n){var r;ee3(e,t,r=new B_(n))}function P5(e,t){var n;return n=e.c,ers(e,t),n}function P6(e,t){return t<0?e.g=-1:e.g=t,e}function P9(e,t){return etN(e),e.a*=t,e.b*=t,e}function P8(e,t,n,r,i){e.c=t,e.d=n,e.b=r,e.a=i}function P7(e,t){return qQ(e,t,e.c.b,e.c),!0}function Re(e){e.a.b=e.b,e.b.a=e.a,e.a=e.b=null}function Rt(e){this.b=e,this.a=Fc(this.b.a).Ed()}function Rn(e,t){this.b=e,this.a=t,ci.call(this)}function Rr(e,t){this.a=e,this.b=t,ci.call(this)}function Ri(e,t){F$.call(this,t,1040),this.a=e}function Ra(e){return 0==e||isNaN(e)?e:e<0?-1:1}function Ro(e){return HR(),e_I(e)==z$(e_P(e))}function Rs(e){return HR(),e_P(e)==z$(e_I(e))}function Ru(e,t){return eyE(e,new Se(t.a,t.b))}function Rc(e){return!q8(e)&&e.c.i.c==e.d.i.c}function Rl(e){var t;return t=e.n,e.a.b+t.d+t.a}function Rf(e){var t;return t=e.n,e.e.b+t.d+t.a}function Rd(e){var t;return t=e.n,e.e.a+t.b+t.c}function Rh(e){return eBG(),++tyv,new jb(0,e)}function Rp(e){return e.a?e.a:Hh(e)}function Rb(e){if(!e)throw p7(new gA(null))}function Rm(){Rm=A,tvm=(Hj(),new fB(eQU))}function Rg(){Rg=A,new ebw((m2(),e0d),(m3(),e0f))}function Rv(){Rv=A,e0B=Je(e15,eUP,19,256,0,1)}function Ry(e,t,n,r){ef3.call(this,e,t,n,r,0,0)}function Rw(e,t,n){return Um(e.b,Pp(n.b,17),t)}function R_(e,t,n){return Um(e.b,Pp(n.b,17),t)}function RE(e,t){return P_(e,new kl(t.a,t.b))}function RS(e,t){return e.c=t)throw p7(new bj)}function FR(e,t,n){return Bc(t,0,R5(t[0],n[0])),t}function Fj(e,t,n){t.Ye(n,gP(LV(Bp(e.b,n)))*e.a)}function FF(e,t,n){return eLG(),eiq(e,t)&&eiq(e,n)}function FY(e){return ekU(),!e.Hc(tbp)&&!e.Hc(tbm)}function FB(e){return new kl(e.c+e.b/2,e.d+e.a/2)}function FU(e,t){return t.kh()?ecv(e.b,Pp(t,49)):t}function FH(e,t){this.e=e,this.d=(64&t)!=0?t|eUR:t}function F$(e,t){this.c=0,this.d=e,this.b=64|t|eUR}function Fz(e){this.b=new XM(11),this.a=(HF(),e)}function FG(e){this.b=null,this.a=(HF(),e||e2s)}function FW(e){this.a=ebb(e.a),this.b=new I4(e.b)}function FK(e){this.b=e,AF.call(this,e),Op(this)}function FV(e){this.b=e,AB.call(this,e),Ob(this)}function Fq(e,t,n){this.a=e,Ia.call(this,t,n,5,6)}function FZ(e,t,n,r){this.b=e,O_.call(this,t,n,r)}function FX(e,t,n,r,i){JB.call(this,e,t,n,r,i,-1)}function FJ(e,t,n,r,i){JU.call(this,e,t,n,r,i,-1)}function FQ(e,t,n,r){O_.call(this,e,t,n),this.b=r}function F1(e,t,n,r){PK.call(this,e,t,n),this.b=r}function F0(e){k7.call(this,e,!1),this.a=!1}function F2(e,t){this.b=e,lm.call(this,e.b),this.a=t}function F3(e,t){Bx(),wj.call(this,e,ecT(new g$(t)))}function F4(e,t){return eBG(),++tyv,new BR(e,t,0)}function F5(e,t){return eBG(),++tyv,new BR(6,e,t)}function F6(e,t){return IE(e.substr(0,t.length),t)}function F9(e,t){return xd(t)?$r(e,t):!!$I(e.f,t)}function F8(e,t){for(BJ(t);e.Ob();)t.td(e.Pb())}function F7(e,t,n){eLQ(),this.e=e,this.d=t,this.a=n}function Ye(e,t,n,r){var i;(i=e.i).i=t,i.a=n,i.b=r}function Yt(e){var t;for(t=e;t.f;)t=t.f;return t}function Yn(e){var t;return A6(null!=(t=eso(e))),t}function Yr(e){var t;return A6(null!=(t=elT(e))),t}function Yi(e,t){var n;return ZQ(t,n=e.a.gc()),n-t}function Ya(e,t){var n;for(n=0;n0?eB4.Math.log(e/t):-100}function YM(e,t){return 0>ecd(e,t)?-1:ecd(e,t)>0?1:0}function YO(e,t,n){return ePQ(e,Pp(t,46),Pp(n,167))}function YA(e,t){return Pp(Ff(Fc(e.a)).Xb(t),42).cd()}function YL(e,t){return eto(t,e.length),new Ri(e,t)}function YC(e,t){this.d=e,Ow.call(this,e),this.e=t}function YI(e){this.d=(BJ(e),e),this.a=0,this.c=eUY}function YD(e,t){pJ.call(this,1),this.a=e,this.b=t}function YN(e,t){return e.c?YN(e.c,t):P_(e.b,t),e}function YP(e,t,n){var r;return r=eep(e,t),V7(e,t,n),r}function YR(e,t){var n;return QO(n=e.slice(0,t),e)}function Yj(e,t,n){var r;for(r=0;r=e.g}function BL(e,t,n){var r;return r=er$(e,t,n),eCK(e,r)}function BC(e,t){var n;n=e.a.length,eep(e,n),V7(e,n,t)}function BI(e,t){var n;(n=console[e]).call(console,t)}function BD(e,t){var n;++e.j,n=e.Vi(),e.Ii(e.oi(n,t))}function BN(e,t,n){Pp(t.b,65),ety(t.a,new N6(e,n,t))}function BP(e,t,n){p$.call(this,t),this.a=e,this.b=n}function BR(e,t,n){pJ.call(this,e),this.a=t,this.b=n}function Bj(e,t,n){this.a=e,pH.call(this,t),this.b=n}function BF(e,t,n){this.a=e,K3.call(this,8,t,null,n)}function BY(e){this.a=(BJ(eJ7),eJ7),this.b=e,new mP}function BB(e){this.c=e,this.b=this.c.a,this.a=this.c.e}function BU(e){this.c=e,this.b=e.a.d.a,LR(e.a.e,this)}function BH(e){A4(-1!=e.c),e.d.$c(e.c),e.b=e.c,e.c=-1}function B$(e){return eB4.Math.sqrt(e.a*e.a+e.b*e.b)}function Bz(e,t){return FP(t,e.a.c.length),RJ(e.a,t)}function BG(e,t){return xc(e)===xc(t)||null!=e&&ecX(e,t)}function BW(e){return 0>=e?new _e:erg(e-1)}function BK(e){return!!tyb&&$r(tyb,e)}function BV(e){return e?e.dc():!e.Kc().Ob()}function Bq(e){return!e.a&&e.c?e.c.b:e.a}function BZ(e){return e.a||(e.a=new O_(e6f,e,4)),e.a}function BX(e){return e.d||(e.d=new O_(tgr,e,1)),e.d}function BJ(e){if(null==e)throw p7(new bM);return e}function BQ(e){e.c?e.c.He():(e.d=!0,eAA(e))}function B1(e){e.c?B1(e.c):(el3(e),e.d=!0)}function B0(e){UG(e.a),e.b=Je(e1R,eUp,1,e.b.length,5,1)}function B2(e,t){return ME(t.j.c.length,e.j.c.length)}function B3(e,t){e.c<0||e.b.b=0?e.Bh(n):ekN(e,t)}function B5(e){var t,n;return(t=e.c.i.c)==(n=e.d.i.c)}function B6(e){if(4!=e.p)throw p7(new bT);return e.e}function B9(e){if(3!=e.p)throw p7(new bT);return e.e}function B8(e){if(6!=e.p)throw p7(new bT);return e.f}function B7(e){if(6!=e.p)throw p7(new bT);return e.k}function Ue(e){if(3!=e.p)throw p7(new bT);return e.j}function Ut(e){if(4!=e.p)throw p7(new bT);return e.j}function Un(e){return e.b||(e.b=new pG(new mR)),e.b}function Ur(e){return -2==e.c&&fd(e,e_d(e.g,e.b)),e.c}function Ui(e,t){var n;return(n=Y6("",e)).n=t,n.i=1,n}function Ua(e,t){jB(Pp(t.b,65),e),ety(t.a,new dv(e))}function Uo(e,t){JL((e.a||(e.a=new C_(e,e)),e.a),t)}function Us(e,t){this.b=e,YC.call(this,e,t),Op(this)}function Uu(e,t){this.b=e,IB.call(this,e,t),Ob(this)}function Uc(e,t,n,r){wD.call(this,e,t),this.d=n,this.a=r}function Ul(e,t,n,r){wD.call(this,e,n),this.a=t,this.f=r}function Uf(e,t){MK.call(this,erv(Y9(e),Y9(t))),this.a=t}function Ud(){e_w.call(this,eQB,(yA(),tvE)),ejt(this)}function Uh(){e_w.call(this,eQc,(yO(),tgg)),eP3(this)}function Up(){wC.call(this,"DELAUNAY_TRIANGULATION",0)}function Ub(e){return String.fromCharCode.apply(null,e)}function Um(e,t,n){return xd(t)?Ge(e,t,n):eS9(e.f,t,n)}function Ug(e){return Hj(),e?e.ve():(HF(),HF(),e2c)}function Uv(e,t,n){return eoM(),n.pg(e,Pp(t.cd(),146))}function Uy(e,t){return Rg(),new ebw(new OK(e),new OW(t))}function Uw(e){return enG(e,eU6),ee1(eft(eft(5,e),e/10|0))}function U_(){U_=A,e0p=new gt(eow(vx(e1$,1),eUK,42,0,[]))}function UE(e){return e.d||(e.d=new fF(e.c.Cc())),e.d}function US(e){return e.a||(e.a=new vp(e.c.vc())),e.a}function Uk(e){return e.b||(e.b=new vd(e.c.ec())),e.b}function Ux(e,t){for(;t-- >0;)e=e<<1|(e<0?1:0);return e}function UT(e,t){return xc(e)===xc(t)||null!=e&&ecX(e,t)}function UM(e,t){return OQ(),Pp(t.b,19).ar&&++r,r}function Hl(e){var t,n;return etV(n=t=new p5,e),n}function Hf(e){var t,n;return e_U(n=t=new p5,e),n}function Hd(e,t){var n;return n=Bp(e.f,t),eiX(t,n),null}function Hh(e){var t;return(t=erw(e))?t:null}function Hp(e){return e.b||(e.b=new FQ(e6g,e,12,3)),e.b}function Hb(e){return null!=e&&wZ(tm$,e.toLowerCase())}function Hm(e,t){return elN(jl(e)*jc(e),jl(t)*jc(t))}function Hg(e,t){return elN(jl(e)*jc(e),jl(t)*jc(t))}function Hv(e,t){return elN(e.d.c+e.d.b/2,t.d.c+t.d.b/2)}function Hy(e,t){return elN(e.g.c+e.g.b/2,t.g.c+t.g.b/2)}function Hw(e,t,n){n.a?ens(e,t.b-e.f/2):eno(e,t.a-e.g/2)}function H_(e,t,n,r){this.a=e,this.b=t,this.c=n,this.d=r}function HE(e,t,n,r){this.a=e,this.b=t,this.c=n,this.d=r}function HS(e,t,n,r){this.e=e,this.a=t,this.c=n,this.d=r}function Hk(e,t,n,r){this.a=e,this.c=t,this.d=n,this.b=r}function Hx(e,t,n,r){Ml(),ZU.call(this,t,n,r),this.a=e}function HT(e,t,n,r){Ml(),ZU.call(this,t,n,r),this.a=e}function HM(e,t){this.a=e,LQ.call(this,e,Pp(e.d,15).Zc(t))}function HO(e){this.f=e,this.c=this.f.e,e.f>0&&evH(this)}function HA(e,t,n,r){this.b=e,this.c=r,xj.call(this,t,n)}function HL(e){return A6(e.b=0&&IE(e.substr(n,t.length),t)}function $N(e,t,n,r,i,a,o){return new qu(e.e,t,n,r,i,a,o)}function $P(e,t,n,r,i,a){this.a=e,en1.call(this,t,n,r,i,a)}function $R(e,t,n,r,i,a){this.a=e,en1.call(this,t,n,r,i,a)}function $j(e,t){this.g=e,this.d=eow(vx(e4N,1),eGW,10,0,[t])}function $F(e,t){this.e=e,this.a=e1R,this.b=eCz(t),this.c=t}function $Y(e,t){CK.call(this),etk(this),this.a=e,this.c=t}function $B(e,t,n,r){Bc(e.c[t.g],n.g,r),Bc(e.c[n.g],t.g,r)}function $U(e,t,n,r){Bc(e.c[t.g],t.g,n),Bc(e.b[t.g],t.g,r)}function $H(){return Xo(),eow(vx(e5u,1),eU4,376,0,[tsH,tsU])}function $$(){return Qx(),eow(vx(e40,1),eU4,479,0,[ttt,tte])}function $z(){return eeF(),eow(vx(e4J,1),eU4,419,0,[teZ,teX])}function $G(){return Jp(),eow(vx(e4V,1),eU4,422,0,[teD,teN])}function $W(){return K6(),eow(vx(e49,1),eU4,420,0,[ttR,ttj])}function $K(){return Q0(),eow(vx(e5a,1),eU4,421,0,[tsL,tsC])}function $V(){return qG(),eow(vx(e5v,1),eU4,523,0,[tuf,tul])}function $q(){return Xa(),eow(vx(e5k,1),eU4,520,0,[tuH,tuU])}function $Z(){return zs(),eow(vx(e5E,1),eU4,516,0,[tuw,tuy])}function $X(){return zQ(),eow(vx(e5S,1),eU4,515,0,[tuE,tuS])}function $J(){return zo(),eow(vx(e5x,1),eU4,455,0,[tuq,tuZ])}function $Q(){return Kn(),eow(vx(e5C,1),eU4,425,0,[tcH,tcU])}function $1(){return z1(),eow(vx(e5L,1),eU4,480,0,[tcF,tcY])}function $0(){return erZ(),eow(vx(e5I,1),eU4,495,0,[tcq,tcZ])}function $2(){return J0(),eow(vx(e5N,1),eU4,426,0,[tc2,tc3])}function $3(){return eoT(),eow(vx(e5V,1),eU4,429,0,[tdt,tde])}function $4(){return Xs(),eow(vx(e5G,1),eU4,430,0,[tfw,tfy])}function $5(){return epC(),eow(vx(e2Q,1),eU4,428,0,[e3f,e3l])}function $6(){return eeR(),eow(vx(e21,1),eU4,427,0,[e3h,e3p])}function $9(){return eej(),eow(vx(e4E,1),eU4,424,0,[e9f,e9d])}function $8(){return erq(),eow(vx(e4F,1),eU4,511,0,[e8W,e8G])}function $7(e,t,n,r){return n>=0?e.jh(t,n,r):e.Sg(null,n,r)}function ze(e){return 0==e.b.b?e.a.$e():PH(e.b)}function zt(e){if(5!=e.p)throw p7(new bT);return jE(e.f)}function zn(e){if(5!=e.p)throw p7(new bT);return jE(e.k)}function zr(e){return xc(e.a)===xc((eiM(),tgW))&&eR1(e),e.a}function zi(e){this.a=Pp(Y9(e),271),this.b=(Hj(),new O4(e))}function za(e,t){l5(this,new kl(e.a,e.b)),l6(this,Pv(t))}function zo(){zo=A,tuq=new SK(ezt,0),tuZ=new SK(ezn,1)}function zs(){zs=A,tuw=new Sz(ezn,0),tuy=new Sz(ezt,1)}function zu(){m9.call(this,new w8(ee0(12))),Oq(!0),this.a=2}function zc(e,t,n){eBG(),pJ.call(this,e),this.b=t,this.a=n}function zl(e,t,n){Ml(),p$.call(this,t),this.a=e,this.b=n}function zf(e){CK.call(this),etk(this),this.a=e,this.c=!0}function zd(e){var t;t=e.c.d.b,e.b=t,e.a=e.c.d,t.a=e.c.d.b=e}function zh(e){var t;enZ(e.a),TW(e.a),efJ(t=new dp(e.a))}function zp(e,t){eC_(e,!0),ety(e.e.wf(),new Dx(e,!0,t))}function zb(e,t){return qe(t),enL(e,Je(ty_,eHT,25,t,15,1),t)}function zm(e,t){return HR(),e==z$(e_I(t))||e==z$(e_P(t))}function zg(e,t){return null==t?xu($I(e.f,null)):Ea(e.g,t)}function zv(e){return 0==e.b?null:(A6(0!=e.b),etw(e,e.a.a))}function zy(e){return 0|Math.max(Math.min(e,eUu),-2147483648)}function zw(e,t){var n=e0w[e.charCodeAt(0)];return null==n?e:n}function z_(e,t){return H5(e,"set1"),H5(t,"set2"),new wF(e,t)}function zE(e,t){var n;return C5(Ld(n=et$(e.f,t)),e.f.d)}function zS(e,t){var n,r;return ej4(e,n=t,r=new H),r.d}function zk(e,t,n,r){var i;i=new CQ,t.a[n.g]=i,jT(e.b,r,i)}function zx(e,t,n){var r;(r=e.Yg(t))>=0?e.sh(r,n):eOh(e,t,n)}function zT(e,t,n){z0(),e&&Um(tmj,e,t),e&&Um(tmR,e,n)}function zM(e,t,n){this.i=new p0,this.b=e,this.g=t,this.a=n}function zO(e,t,n){this.c=new p0,this.e=e,this.f=t,this.b=n}function zA(e,t,n){this.a=new p0,this.e=e,this.f=t,this.c=n}function zL(e,t){MV(this),this.f=t,this.g=e,HD(this),this._d()}function zC(e,t){var n;n=e.q.getHours(),e.q.setDate(t),eNq(e,n)}function zI(e,t){var n;for(Y9(t),n=e.a;n;n=n.c)t.Od(n.g,n.i)}function zD(e){var t;return esb(t=new yF(ee0(e.length)),e),t}function zN(e){function t(){}return t.prototype=e||{},new t}function zP(e,t){return!!eos(e,t)&&(enP(e),!0)}function zR(e,t){if(null==t)throw p7(new bM);return ehF(e,t)}function zj(e){return e.qe()?null:(0,eUt[e.n])}function zF(e){return e.Db>>16!=3?null:Pp(e.Cb,33)}function zY(e){return e.Db>>16!=9?null:Pp(e.Cb,33)}function zB(e){return e.Db>>16!=6?null:Pp(e.Cb,79)}function zU(e){return e.Db>>16!=7?null:Pp(e.Cb,235)}function zH(e){return e.Db>>16!=7?null:Pp(e.Cb,160)}function z$(e){return e.Db>>16!=11?null:Pp(e.Cb,33)}function zz(e,t){var n;return(n=e.Yg(t))>=0?e.lh(n):exu(e,t)}function zG(e,t){var n;return n=new RZ(t),e_h(n,e),new I4(n)}function zW(e){var t;return t=e.d,t=e.si(e.f),JL(e,t),t.Ob()}function zK(e,t){return e.b+=t.b,e.c+=t.c,e.d+=t.d,e.a+=t.a,e}function zV(e,t){return eB4.Math.abs(e)0}function zZ(){this.a=new Tw,this.e=new bV,this.g=0,this.i=0}function zX(e){this.a=e,this.b=Je(e5b,eUP,1944,e.e.length,0,2)}function zJ(e,t,n){var r;r=esg(e,t,n),e.b=new erH(r.c.length)}function zQ(){zQ=A,tuE=new S$(ezh,0),tuS=new S$("UP",1)}function z1(){z1=A,tcF=new SJ(eV2,0),tcY=new SJ("FAN",1)}function z0(){z0=A,tmj=new p2,tmR=new p2,xa(e0r,new o8)}function z2(e){if(0!=e.p)throw p7(new bT);return xg(e.f,0)}function z3(e){if(0!=e.p)throw p7(new bT);return xg(e.k,0)}function z4(e){return e.Db>>16!=3?null:Pp(e.Cb,147)}function z5(e){return e.Db>>16!=6?null:Pp(e.Cb,235)}function z6(e){return e.Db>>16!=17?null:Pp(e.Cb,26)}function z9(e,t){var n=e.a=e.a||[];return n[t]||(n[t]=e.le(t))}function z8(e,t){var n;return null==(n=e.a.get(t))?[]:n}function z7(e,t){var n;n=e.q.getHours(),e.q.setMonth(t),eNq(e,n)}function Ge(e,t,n){return null==t?eS9(e.f,null,n):efi(e.g,t,n)}function Gt(e,t,n,r,i,a){return new Q$(e.e,t,e.aj(),n,r,i,a)}function Gn(e,t,n){return e.a=Az(e.a,0,t)+""+n+xy(e.a,t),e}function Gr(e,t,n){return P_(e.a,(U_(),eb2(t,n),new wD(t,n))),e}function Gi(e){return OX(e.c),e.e=e.a=e.c,e.c=e.c.c,++e.d,e.a.f}function Ga(e){return OX(e.e),e.c=e.a=e.e,e.e=e.e.e,--e.d,e.a.f}function Go(e,t){e.d&&QA(e.d.e,e),e.d=t,e.d&&P_(e.d.e,e)}function Gs(e,t){e.c&&QA(e.c.g,e),e.c=t,e.c&&P_(e.c.g,e)}function Gu(e,t){e.c&&QA(e.c.a,e),e.c=t,e.c&&P_(e.c.a,e)}function Gc(e,t){e.i&&QA(e.i.j,e),e.i=t,e.i&&P_(e.i.j,e)}function Gl(e,t,n){this.a=t,this.c=e,this.b=(Y9(n),new I4(n))}function Gf(e,t,n){this.a=t,this.c=e,this.b=(Y9(n),new I4(n))}function Gd(e,t){this.a=e,this.c=MB(this.a),this.b=new $g(t)}function Gh(e){var t;return el3(e),t=new bV,UJ(e,new di(t))}function Gp(e,t){if(e<0||e>t)throw p7(new gE(e$O+e+e$A+t))}function Gb(e,t){return jR(e.a,t)?Yl(e,Pp(t,22).g,null):null}function Gm(e){return euQ(),OQ(),0!=Pp(e.a,81).d.e}function Gg(){Gg=A,e0g=euY((m5(),eow(vx(e1W,1),eU4,538,0,[e0m])))}function Gv(){Gv=A,ts2=j0(new K2,(e_x(),e8i),(eB$(),e7N))}function Gy(){Gy=A,ts3=j0(new K2,(e_x(),e8i),(eB$(),e7N))}function Gw(){Gw=A,ts5=j0(new K2,(e_x(),e8i),(eB$(),e7N))}function G_(){G_=A,tuh=RI(new K2,(e_x(),e8i),(eB$(),e7o))}function GE(){GE=A,tug=RI(new K2,(e_x(),e8i),(eB$(),e7o))}function GS(){GS=A,tuv=RI(new K2,(e_x(),e8i),(eB$(),e7o))}function Gk(){Gk=A,tux=RI(new K2,(e_x(),e8i),(eB$(),e7o))}function Gx(){Gx=A,tcz=j0(new K2,(egR(),tu0),(eS_(),tu3))}function GT(e,t,n,r){this.c=e,this.d=r,GA(this,t),GL(this,n)}function GM(e){this.c=new _n,this.b=e.b,this.d=e.c,this.a=e.a}function GO(e){this.a=eB4.Math.cos(e),this.b=eB4.Math.sin(e)}function GA(e,t){e.a&&QA(e.a.k,e),e.a=t,e.a&&P_(e.a.k,e)}function GL(e,t){e.b&&QA(e.b.f,e),e.b=t,e.b&&P_(e.b.f,e)}function GC(e,t){BN(e,e.b,e.c),Pp(e.b.b,65),t&&Pp(t.b,65).b}function GI(e,t){elJ(e,t),M4(e.Cb,88)&&eko(Zd(Pp(e.Cb,88)),2)}function GD(e,t){M4(e.Cb,88)&&eko(Zd(Pp(e.Cb,88)),4),er3(e,t)}function GN(e,t){M4(e.Cb,179)&&(Pp(e.Cb,179).tb=null),er3(e,t)}function GP(e,t){return _4(),eec(t)?new RA(t,e):new xe(t,e)}function GR(e,t){var n,r;(r=null!=(n=t.c))&&BC(e,new B_(t.c))}function Gj(e){var t,n;return n=(yO(),t=new p5),etV(n,e),n}function GF(e){var t,n;return n=(yO(),t=new p5),etV(n,e),n}function GY(e,t){var n;return n=new By(e),t.c[t.c.length]=n,n}function GB(e,t){var n;return(n=Pp(ecA(HU(e.a),t),14))?n.gc():0}function GU(e){var t;return el3(e),etc(e,t=(HF(),HF(),e2u))}function GH(e){for(var t;;)if(t=e.Pb(),!e.Ob())return t}function G$(e,t){mK.call(this,new w8(ee0(e))),enG(t,eUN),this.a=t}function Gz(e,t,n){ec5(t,n,e.gc()),this.c=e,this.a=t,this.b=n-t}function GG(e,t,n){var r;ec5(t,n,e.c.length),r=n-t,yJ(e.c,t,r)}function GW(e,t){M7(e,jE(WM(Fv(t,24),e$b)),jE(WM(t,e$b)))}function GK(e,t){if(e<0||e>=t)throw p7(new gE(e$O+e+e$A+t))}function GV(e,t){if(e<0||e>=t)throw p7(new vf(e$O+e+e$A+t))}function Gq(e,t){this.b=(BJ(e),e),this.a=(t&eH0)==0?64|t|eUR:t}function GZ(e){TG(this),bF(this.a,esi(eB4.Math.max(8,e))<<1)}function GX(e){return esp(eow(vx(e50,1),eUP,8,0,[e.i.n,e.n,e.a]))}function GJ(){return eum(),eow(vx(e2L,1),eU4,132,0,[e2B,e2U,e2H])}function GQ(){return etx(),eow(vx(e26,1),eU4,232,0,[e3D,e3N,e3P])}function G1(){return Qs(),eow(vx(e27,1),eU4,461,0,[e3F,e3j,e3Y])}function G0(){return QQ(),eow(vx(e3t,1),eU4,462,0,[e3$,e3H,e3U])}function G2(){return ec4(),eow(vx(e4L,1),eU4,423,0,[e8x,e8k,e8S])}function G3(){return QJ(),eow(vx(e4S,1),eU4,379,0,[e94,e93,e95])}function G4(){return euJ(),eow(vx(e5e,1),eU4,378,0,[tsn,tsr,tsi])}function G5(){return en7(),eow(vx(e4q,1),eU4,314,0,[tej,teR,teF])}function G6(){return enB(),eow(vx(e4Z,1),eU4,337,0,[teB,teH,teU])}function G9(){return eoG(),eow(vx(e4Q,1),eU4,450,0,[te1,teQ,te0])}function G8(){return erX(),eow(vx(e4G,1),eU4,361,0,[tep,teh,ted])}function G7(){return Q1(),eow(vx(e46,1),eU4,303,0,[ttD,ttN,ttI])}function We(){return eaU(),eow(vx(e45,1),eU4,292,0,[ttA,ttL,ttO])}function Wt(){return enY(),eow(vx(e5o,1),eU4,452,0,[tsP,tsD,tsN])}function Wn(){return esn(),eow(vx(e5i,1),eU4,339,0,[tsM,tsT,tsO])}function Wr(){return ei0(),eow(vx(e5s,1),eU4,375,0,[tsj,tsF,tsY])}function Wi(){return eox(),eow(vx(e5f,1),eU4,377,0,[tsQ,ts1,tsJ])}function Wa(){return euy(),eow(vx(e5c,1),eU4,336,0,[tsz,tsG,tsW])}function Wo(){return eiO(),eow(vx(e5l,1),eU4,338,0,[tsZ,tsV,tsq])}function Ws(){return enU(),eow(vx(e5p,1),eU4,454,0,[tur,tui,tua])}function Wu(){return efx(),eow(vx(e5D,1),eU4,442,0,[tc1,tcJ,tcQ])}function Wc(){return eub(),eow(vx(e5P,1),eU4,380,0,[tc5,tc6,tc9])}function Wl(){return efS(),eow(vx(e5Y,1),eU4,381,0,[tlP,tlR,tlN])}function Wf(){return ei1(),eow(vx(e5j,1),eU4,293,0,[tlC,tlI,tlL])}function Wd(){return efk(),eow(vx(e5H,1),eU4,437,0,[tff,tfd,tfh])}function Wh(){return eck(),eow(vx(e57,1),eU4,334,0,[tpG,tpz,tpW])}function Wp(){return etT(),eow(vx(e56,1),eU4,272,0,[tp_,tpE,tpS])}function Wb(e,t){return eMw(e,t,M4(t,99)&&(Pp(t,18).Bb&eH3)!=0)}function Wm(e,t,n){var r;return(r=ePI(e,t,!1)).b<=t&&r.a<=n}function Wg(e,t,n){var r;(r=new ac).b=t,r.a=n,++t.b,P_(e.d,r)}function Wv(e,t){var n;return A3(!!(n=(BJ(e),e).g)),BJ(t),n(t)}function Wy(e,t){var n,r;return r=Yi(e,t),n=e.a.Zc(r),new wR(e,n)}function Ww(e){return e.Db>>16!=6?null:Pp(eTp(e),235)}function W_(e){if(2!=e.p)throw p7(new bT);return jE(e.f)&eHd}function WE(e){if(2!=e.p)throw p7(new bT);return jE(e.k)&eHd}function WS(e){return e.a==(ZE(),tvd)&&ff(e,eM0(e.g,e.b)),e.a}function Wk(e){return e.d==(ZE(),tvd)&&fh(e,eIj(e.g,e.b)),e.d}function Wx(e){return A6(e.ar?1:0}function WY(e,t){var n,r;return r=n=QP(t),Pp(Bp(e.c,r),19).a}function WB(e,t){var n;for(n=e+"";n.length0&&0==e.a[--e.d];);0==e.a[e.d++]&&(e.e=0)}function Kc(e){return e.a?0==e.e.length?e.a.a:e.a.a+""+e.e:e.c}function Kl(e){return!!e.a&&0!=QX(e.a.a).i&&!(e.b&&ebq(e.b))}function Kf(e){return!!e.u&&0!=qt(e.u.a).i&&!(e.n&&ebV(e.n))}function Kd(e){return Rj(e.e.Hd().gc()*e.c.Hd().gc(),16,new c9(e))}function Kh(e,t){return YM(eap(e.q.getTime()),eap(t.q.getTime()))}function Kp(e){return Pp(epg(e,Je(e4C,eGG,17,e.c.length,0,1)),474)}function Kb(e){return Pp(epg(e,Je(e4N,eGW,10,e.c.length,0,1)),193)}function Km(e){return GE(),!q8(e)&&!(!q8(e)&&e.c.i.c==e.d.i.c)}function Kg(e,t,n){var r;r=(Y9(e),new I4(e)),egT(new Gl(r,t,n))}function Kv(e,t,n){var r;r=(Y9(e),new I4(e)),egM(new Gf(r,t,n))}function Ky(e,t){var n;return n=1-t,e.a[n]=erj(e.a[n],n),erj(e,t)}function Kw(e,t){var n;e.e=new mQ,n=eLj(t),Mv(n,e.c),eLJ(e,n,0)}function K_(e,t,n,r){var i;(i=new od).a=t,i.b=n,i.c=r,P7(e.a,i)}function KE(e,t,n,r){var i;(i=new od).a=t,i.b=n,i.c=r,P7(e.b,i)}function KS(e){var t,n,r;return n=eI4(t=new YQ,e),eFg(t),r=n}function Kk(){var e,t,n;return P_(tg6,t=n=e=new p5),t}function Kx(e){return e.j.c=Je(e1R,eUp,1,0,5,1),UG(e.c),Uj(e.a),e}function KT(e){return(_L(),M4(e.g,10))?Pp(e.g,10):null}function KM(e){return!Uz(e).dc()&&(MI(e,new v),!0)}function KO(e){if(!("stack"in e))try{throw e}catch(t){}return e}function KA(e,t){if(e<0||e>=t)throw p7(new gE(eku(e,t)));return e}function KL(e,t,n){if(e<0||tn)throw p7(new gE(eE3(e,t,n)))}function KC(e,t){if(Yf(e.a,t),t.d)throw p7(new go(e$P));t.d=e}function KI(e,t){if(t.$modCount!=e.$modCount)throw p7(new bA)}function KD(e,t){return!!M4(t,42)&&emT(e.a,Pp(t,42))}function KN(e,t){return!!M4(t,42)&&emT(e.a,Pp(t,42))}function KP(e,t){return!!M4(t,42)&&emT(e.a,Pp(t,42))}function KR(e,t){return e.a<=e.b&&(t.ud(e.a++),!0)}function Kj(e){var t;return Ts(e)?-0==(t=e)?0:t:eem(e)}function KF(e){var t;return B1(e),t=new Y,yU(e.a,new dn(t)),t}function KY(e){var t;return B1(e),t=new F,yU(e.a,new dt(t)),t}function KB(e,t){this.a=e,fE.call(this,e),Gp(t,e.gc()),this.b=t}function KU(e){this.e=e,this.b=this.e.a.entries(),this.a=[]}function KH(e){return Rj(e.e.Hd().gc()*e.c.Hd().gc(),273,new c6(e))}function K$(e){return new XM((enG(e,eU6),ee1(eft(eft(5,e),e/10|0))))}function Kz(e){return Pp(epg(e,Je(e4j,eGK,11,e.c.length,0,1)),1943)}function KG(e,t,n){return n.f.c.length>0?YO(e.a,t,n):YO(e.b,t,n)}function KW(e,t,n){e.d&&QA(e.d.e,e),e.d=t,e.d&&jO(e.d.e,n,e)}function KK(e,t){eY5(t,e),PD(e.d),PD(Pp(e_k(e,(eBy(),taq)),207))}function KV(e,t){eY4(t,e),PI(e.d),PI(Pp(e_k(e,(eBy(),taq)),207))}function Kq(e,t){var n,r;return n=zR(e,t),r=null,n&&(r=n.fe()),r}function KZ(e,t){var n,r;return n=eep(e,t),r=null,n&&(r=n.ie()),r}function KX(e,t){var n,r;return n=zR(e,t),r=null,n&&(r=n.ie()),r}function KJ(e,t){var n,r;return n=zR(e,t),r=null,n&&(r=eSa(n)),r}function KQ(e,t,n){var r;return r=ehM(n),eIg(e.g,r,t),eIg(e.i,t,n),t}function K1(e,t,n){var r;r=ehl();try{return CO(e,t,n)}finally{Vx(r)}}function K0(e){var t;t=e.Wg(),this.a=M4(t,69)?Pp(t,69).Zh():t.Kc()}function K2(){mJ.call(this),this.j.c=Je(e1R,eUp,1,0,5,1),this.a=-1}function K3(e,t,n,r){this.d=e,this.n=t,this.g=n,this.o=r,this.p=-1}function K4(e,t,n,r){this.e=r,this.d=null,this.c=e,this.a=t,this.b=n}function K5(e,t,n){this.d=new hg(this),this.e=e,this.i=t,this.f=n}function K6(){K6=A,ttR=new S_(e$8,0),ttj=new S_("TOP_LEFT",1)}function K9(){K9=A,ts7=Uy(ell(1),ell(4)),ts8=Uy(ell(1),ell(2))}function K8(){K8=A,tfv=euY((_N(),eow(vx(e5z,1),eU4,551,0,[tfg])))}function K7(){K7=A,tfm=euY((_D(),eow(vx(e5$,1),eU4,482,0,[tfb])))}function Ve(){Ve=A,tf7=euY((_P(),eow(vx(e5K,1),eU4,530,0,[tf8])))}function Vt(){Vt=A,e6W=euY((_y(),eow(vx(e4w,1),eU4,481,0,[e6G])))}function Vn(){return eaY(),eow(vx(e3r,1),eU4,406,0,[e4c,e4o,e4s,e4u])}function Vr(){return Qu(),eow(vx(e2E,1),eU4,297,0,[e2D,e2N,e2P,e2R])}function Vi(){return ebe(),eow(vx(e4y,1),eU4,394,0,[e6U,e6B,e6H,e6$])}function Va(){return ep7(),eow(vx(e3i,1),eU4,323,0,[e4d,e4f,e4h,e4p])}function Vo(){return eok(),eow(vx(e4A,1),eU4,405,0,[e8f,e8p,e8d,e8h])}function Vs(){return eoE(),eow(vx(e4U,1),eU4,360,0,[e7Z,e7V,e7q,e7K])}function Vu(e,t,n,r){return M4(n,54)?new A7(e,t,n,r):new Fo(e,t,n,r)}function Vc(){return eoS(),eow(vx(e4$,1),eU4,411,0,[e79,e78,e77,tee])}function Vl(e){var t;return e.j==(eYu(),tbj)&&(t=eTt(e),Aa(t,tby))}function Vf(e,t){var n;Gs(n=t.a,t.c.d),Go(n,t.d.d),etH(n.a,e.n)}function Vd(e,t){return Pp(Af(FT(Pp(Zq(e.k,t),15).Oc(),tex)),113)}function Vh(e,t){return Pp(Af(FM(Pp(Zq(e.k,t),15).Oc(),tex)),113)}function Vp(e){return new Gq(eip(Pp(e.a.dd(),14).gc(),e.a.cd()),16)}function Vb(e){return M4(e,14)?Pp(e,14).dc():!e.Kc().Ob()}function Vm(e){return(_L(),M4(e.g,145))?Pp(e.g,145):null}function Vg(e){if(e.e.g!=e.b)throw p7(new bA);return!!e.c&&e.d>0}function Vv(e){return A6(e.b!=e.d.c),e.c=e.b,e.b=e.b.a,++e.a,e.c.c}function Vy(e,t){BJ(t),Bc(e.a,e.c,t),e.c=e.c+1&e.a.length-1,ega(e)}function Vw(e,t){BJ(t),e.b=e.b-1&e.a.length-1,Bc(e.a,e.b,t),ega(e)}function V_(e,t){var n;for(n=e.j.c.length;n0&&ePD(e.g,0,t,0,e.i),t}function VB(e,t){var n;return _5(),!(n=Pp(Bp(tmU,e),55))||n.wj(t)}function VU(e){if(1!=e.p)throw p7(new bT);return jE(e.f)<<24>>24}function VH(e){if(1!=e.p)throw p7(new bT);return jE(e.k)<<24>>24}function V$(e){if(7!=e.p)throw p7(new bT);return jE(e.k)<<16>>16}function Vz(e){if(7!=e.p)throw p7(new bT);return jE(e.f)<<16>>16}function VG(e){var t;for(t=0;e.Ob();)e.Pb(),t=eft(t,1);return ee1(t)}function VW(e,t){var n;return n=new vl,e.xd(n),n.a+="..",t.yd(n),n.a}function VK(e,t,n){var r;r=Pp(Bp(e.g,n),57),P_(e.a.c,new kD(t,r))}function VV(e,t,n){return F_(LV(xu($I(e.f,t))),LV(xu($I(e.f,n))))}function Vq(e,t,n){return eNA(e,t,n,M4(t,99)&&(Pp(t,18).Bb&eH3)!=0)}function VZ(e,t,n){return eN1(e,t,n,M4(t,99)&&(Pp(t,18).Bb&eH3)!=0)}function VX(e,t,n){return eMN(e,t,n,M4(t,99)&&(Pp(t,18).Bb&eH3)!=0)}function VJ(e,t){return e==(eEn(),e8N)&&t==e8N?4:e==e8N||t==e8N?8:32}function VQ(e,t){return xc(t)===xc(e)?"(this Map)":null==t?eUg:efF(t)}function V1(e,t){return Pp(null==t?xu($I(e.f,null)):Ea(e.g,t),281)}function V0(e,t,n){var r;return r=ehM(n),Um(e.b,r,t),Um(e.c,t,n),t}function V2(e,t){var n;for(n=t;n;)Lu(e,n.i,n.j),n=z$(n);return e}function V3(e,t){var n;return n=$a(Pb(new Qj(e,t))),RG(new Qj(e,t)),n}function V4(e,t){var n;return _4(),eEy(n=Pp(e,66).Mj(),t),n.Ok(t)}function V5(e,t,n,r,i){var a;a=eMW(i,n,r),P_(t,eS4(i,a)),e_X(e,i,t)}function V6(e,t,n){e.i=0,e.e=0,t!=n&&(esC(e,t,n),esL(e,t,n))}function V9(e,t){var n;n=e.q.getHours(),e.q.setFullYear(t+eHx),eNq(e,n)}function V8(e,t,n){if(n){var r=n.ee();e.a[t]=r(n)}else delete e.a[t]}function V7(e,t,n){n=n?n.ee()(n):void 0,e.a[t]=n}function qe(e){if(e<0)throw p7(new gI("Negative array size: "+e))}function qt(e){return e.n||(Zd(e),e.n=new j4(e,tgr,e),$E(e)),e.n}function qn(e){return A6(e.a=0&&e.a[n]===t[n];n--);return n<0}function qy(e,t){var n;return(euv(),0!=(n=e.j.g-t.j.g))?n:0}function qw(e,t){return(BJ(t),null!=e.a)?jN(t.Kb(e.a)):e2b}function q_(e){var t;return e?new RZ(e):(t=new Tw,ein(t,e),t)}function qE(e,t){var n;return t.b.Kb(QD(e,t.c.Ee(),n=new ds(t)))}function qS(e){ewP(),M7(this,jE(WM(Fv(e,24),e$b)),jE(WM(e,e$b)))}function qk(){qk=A,e3d=euY((epC(),eow(vx(e2Q,1),eU4,428,0,[e3f,e3l])))}function qx(){qx=A,e3b=euY((eeR(),eow(vx(e21,1),eU4,427,0,[e3h,e3p])))}function qT(){qT=A,e9h=euY((eej(),eow(vx(e4E,1),eU4,424,0,[e9f,e9d])))}function qM(){qM=A,e8K=euY((erq(),eow(vx(e4F,1),eU4,511,0,[e8W,e8G])))}function qO(){qO=A,teJ=euY((eeF(),eow(vx(e4J,1),eU4,419,0,[teZ,teX])))}function qA(){qA=A,ttn=euY((Qx(),eow(vx(e40,1),eU4,479,0,[ttt,tte])))}function qL(){qL=A,ts$=euY((Xo(),eow(vx(e5u,1),eU4,376,0,[tsH,tsU])))}function qC(){qC=A,tsI=euY((Q0(),eow(vx(e5a,1),eU4,421,0,[tsL,tsC])))}function qI(){qI=A,teP=euY((Jp(),eow(vx(e4V,1),eU4,422,0,[teD,teN])))}function qD(){qD=A,ttF=euY((K6(),eow(vx(e49,1),eU4,420,0,[ttR,ttj])))}function qN(){qN=A,tu$=euY((Xa(),eow(vx(e5k,1),eU4,520,0,[tuH,tuU])))}function qP(){qP=A,tud=euY((qG(),eow(vx(e5v,1),eU4,523,0,[tuf,tul])))}function qR(){qR=A,tu_=euY((zs(),eow(vx(e5E,1),eU4,516,0,[tuw,tuy])))}function qj(){qj=A,tuk=euY((zQ(),eow(vx(e5S,1),eU4,515,0,[tuE,tuS])))}function qF(){qF=A,tuX=euY((zo(),eow(vx(e5x,1),eU4,455,0,[tuq,tuZ])))}function qY(){qY=A,tc$=euY((Kn(),eow(vx(e5C,1),eU4,425,0,[tcH,tcU])))}function qB(){qB=A,tcX=euY((erZ(),eow(vx(e5I,1),eU4,495,0,[tcq,tcZ])))}function qU(){qU=A,tcB=euY((z1(),eow(vx(e5L,1),eU4,480,0,[tcF,tcY])))}function qH(){qH=A,tc4=euY((J0(),eow(vx(e5N,1),eU4,426,0,[tc2,tc3])))}function q$(){q$=A,tdn=euY((eoT(),eow(vx(e5V,1),eU4,429,0,[tdt,tde])))}function qz(){qz=A,tf_=euY((Xs(),eow(vx(e5G,1),eU4,430,0,[tfw,tfy])))}function qG(){qG=A,tuf=new Sj("UPPER",0),tul=new Sj("LOWER",1)}function qW(e,t){var n;H1(n=new gu,"x",t.a),H1(n,"y",t.b),BC(e,n)}function qK(e,t){var n;H1(n=new gu,"x",t.a),H1(n,"y",t.b),BC(e,n)}function qV(e,t){var n,r;r=!1;do n=eo6(e,t),r|=n;while(n)return r}function qq(e,t){var n,r;for(n=t,r=0;n>0;)r+=e.a[n],n-=n&-n;return r}function qZ(e,t){var n;for(n=t;n;)Lu(e,-n.i,-n.j),n=z$(n);return e}function qX(e,t){var n,r;for(BJ(t),r=e.Kc();r.Ob();)n=r.Pb(),t.td(n)}function qJ(e,t){var n;return n=t.cd(),new wD(n,e.e.pc(n,Pp(t.dd(),14)))}function qQ(e,t,n,r){var i;(i=new C).c=t,i.b=n,i.a=r,r.b=n.a=i,++e.b}function q1(e,t,n){var r;return r=(GK(t,e.c.length),e.c[t]),e.c[t]=n,r}function q0(e,t,n){return Pp(null==t?eS9(e.f,null,n):efi(e.g,t,n),281)}function q2(e){return e.c&&e.d?WH(e.c)+"->"+WH(e.d):"e_"+Ao(e)}function q3(e,t){return(el3(e),yK(new R1(e,new Qa(t,e.a)))).sd(e2z)}function q4(){return e_x(),eow(vx(e4k,1),eU4,356,0,[e8e,e8t,e8n,e8r,e8i])}function q5(){return eYu(),eow(vx(e6a,1),eGj,61,0,[tbF,tbw,tby,tbj,tbY])}function q6(e){return vg(),function(){return K1(e,this,arguments)}}function q9(){return Date.now?Date.now():(new Date).getTime()}function q8(e){return!!e.c&&!!e.d&&!!e.c.i&&e.c.i==e.d.i}function q7(e){if(!e.c.Sb())throw p7(new bC);return e.a=!0,e.c.Ub()}function Ze(e){e.i=0,Eb(e.b,null),Eb(e.c,null),e.a=null,e.e=null,++e.g}function Zt(e){El.call(this,null==e?eUg:efF(e),M4(e,78)?Pp(e,78):null)}function Zn(e){eBD(),p8(this),this.a=new _n,esJ(this,e),P7(this.a,e)}function Zr(){Tz(this),this.b=new kl(eHQ,eHQ),this.a=new kl(eH1,eH1)}function Zi(e,t){this.c=0,this.b=t,xR.call(this,e,17493),this.a=this.c}function Za(e){Zo(),!e2M&&(this.c=e,this.e=!0,this.a=new p0)}function Zo(){Zo=A,e2M=!0,e2x=!1,e2T=!1,e2A=!1,e2O=!1}function Zs(e,t){return!!M4(t,149)&&IE(e.c,Pp(t,149).c)}function Zu(e,t){var n;return n=0,e&&(n+=e.f.a/2),t&&(n+=t.f.a/2),n}function Zc(e,t){var n;return(n=Pp(eef(e.d,t),23))||Pp(eef(e.e,t),23)}function Zl(e){this.b=e,Ow.call(this,e),this.a=Pp(eaS(this.b.a,4),126)}function Zf(e){this.b=e,AY.call(this,e),this.a=Pp(eaS(this.b.a,4),126)}function Zd(e){return e.t||(e.t=new pR(e),elm(new gT(e),0,e.t)),e.t}function Zh(){return ec3(),eow(vx(e55,1),eU4,103,0,[tpv,tpg,tpm,tpb,tpy])}function Zp(){return epT(),eow(vx(e6n,1),eU4,249,0,[tbt,tbr,tp7,tbe,tbn])}function Zb(){return epx(),eow(vx(e5Q,1),eU4,175,0,[tdh,tdd,tdl,tdp,tdf])}function Zm(){return eEM(),eow(vx(e5W,1),eU4,316,0,[tfE,tfS,tfT,tfk,tfx])}function Zg(){return ebG(),eow(vx(e5n,1),eU4,315,0,[tsb,tsd,tsh,tsf,tsp])}function Zv(){return eb6(),eow(vx(e4X,1),eU4,335,0,[teG,tez,teK,teV,teW])}function Zy(){return eOB(),eow(vx(e5U,1),eU4,355,0,[tfo,tfa,tfu,tfs,tfc])}function Zw(){return ey4(),eow(vx(e4z,1),eU4,363,0,[ter,tea,teo,tei,ten])}function Z_(){return ef_(),eow(vx(e48,1),eU4,163,0,[tnj,tnD,tnN,tnP,tnR])}function ZE(){var e,t;ZE=A,tvf=(yO(),t=new bN),tvd=e=new mC}function ZS(e){var t;return!e.c&&M4(t=e.r,88)&&(e.c=Pp(t,26)),e.c}function Zk(e){return e.e=3,e.d=e.Yb(),2!=e.e&&(e.e=0,!0)}function Zx(e){var t,n,r;return t=e&eHH,Mk(t,n=e>>22&eHH,r=e<0?eH$:0)}function ZT(e){var t,n,r,i;for(r=0,i=(n=e).length;r0?ehe(e,t):eA8(e,-t)}function ZL(e,t){return 0==t||0==e.e?e:t>0?eA8(e,t):ehe(e,-t)}function ZC(e){if(eTk(e))return e.c=e.a,e.a.Pb();throw p7(new bC)}function ZI(e){var t,n;return t=e.c.i,n=e.d.i,t.k==(eEn(),e8C)&&n.k==e8C}function ZD(e){var t;return t=new $b,eaW(t,e),eo3(t,(eBy(),taR),null),t}function ZN(e,t,n){var r;return(r=e.Yg(t))>=0?e._g(r,n,!0):exk(e,t,n)}function ZP(e,t,n,r){var i;for(i=0;it)throw p7(new gE(eS1(e,t,"index")));return e}function Z1(e,t,n,r){var i;return i=Je(ty_,eHT,25,t,15,1),ewD(i,e,t,n,r),i}function Z0(e,t){var n;n=e.q.getHours()+(t/60|0),e.q.setMinutes(t),eNq(e,n)}function Z2(e,t){return eB4.Math.min(Jh(t.a,e.d.d.c),Jh(t.b,e.d.d.c))}function Z3(e,t){return xd(t)?null==t?eTx(e.f,null):eaK(e.g,t):eTx(e.f,t)}function Z4(e){this.c=e,this.a=new fz(this.c.a),this.b=new fz(this.c.b)}function Z5(){this.e=new p0,this.c=new p0,this.d=new p0,this.b=new p0}function Z6(){this.g=new bJ,this.b=new bJ,this.a=new p0,this.k=new p0}function Z9(e,t,n){this.a=e,this.c=t,this.d=n,P_(t.e,this),P_(n.b,this)}function Z8(e,t){xP.call(this,t.rd(),-6&t.qd()),BJ(e),this.a=e,this.b=t}function Z7(e,t){xR.call(this,t.rd(),-6&t.qd()),BJ(e),this.a=e,this.b=t}function Xe(e,t){xj.call(this,t.rd(),-6&t.qd()),BJ(e),this.a=e,this.b=t}function Xt(e,t,n){this.a=e,this.b=t,this.c=n,P_(e.t,this),P_(t.i,this)}function Xn(){this.b=new _n,this.a=new _n,this.b=new _n,this.a=new _n}function Xr(){Xr=A,tdx=new pO("org.eclipse.elk.labels.labelManager")}function Xi(){Xi=A,e7W=new Cm("separateLayerConnections",(eoE(),e7Z))}function Xa(){Xa=A,tuH=new SW("REGULAR",0),tuU=new SW("CRITICAL",1)}function Xo(){Xo=A,tsH=new SI("STACKED",0),tsU=new SI("SEQUENCED",1)}function Xs(){Xs=A,tfw=new S7("FIXED",0),tfy=new S7("CENTER_NODE",1)}function Xu(e,t){var n;return n=ejH(e,t),e.b=new erH(n.c.length),eRj(e,n)}function Xc(e,t,n){var r;return++e.e,--e.f,(r=Pp(e.d[t].$c(n),133)).dd()}function Xl(e){var t;return!e.a&&M4(t=e.r,148)&&(e.a=Pp(t,148)),e.a}function Xf(e){return e.a?e.e?Xf(e.e):null:e}function Xd(e,t){return e.pt.p?-1:0}function Xh(e,t){return BJ(t),e.c=0,"Initial capacity must not be negative")}function XO(){XO=A,e3R=euY((etx(),eow(vx(e26,1),eU4,232,0,[e3D,e3N,e3P])))}function XA(){XA=A,e3B=euY((Qs(),eow(vx(e27,1),eU4,461,0,[e3F,e3j,e3Y])))}function XL(){XL=A,e3z=euY((QQ(),eow(vx(e3t,1),eU4,462,0,[e3$,e3H,e3U])))}function XC(){XC=A,e2$=euY((eum(),eow(vx(e2L,1),eU4,132,0,[e2B,e2U,e2H])))}function XI(){XI=A,e96=euY((QJ(),eow(vx(e4S,1),eU4,379,0,[e94,e93,e95])))}function XD(){XD=A,e8T=euY((ec4(),eow(vx(e4L,1),eU4,423,0,[e8x,e8k,e8S])))}function XN(){XN=A,teY=euY((en7(),eow(vx(e4q,1),eU4,314,0,[tej,teR,teF])))}function XP(){XP=A,te$=euY((enB(),eow(vx(e4Z,1),eU4,337,0,[teB,teH,teU])))}function XR(){XR=A,te2=euY((eoG(),eow(vx(e4Q,1),eU4,450,0,[te1,teQ,te0])))}function Xj(){Xj=A,teb=euY((erX(),eow(vx(e4G,1),eU4,361,0,[tep,teh,ted])))}function XF(){XF=A,ttP=euY((Q1(),eow(vx(e46,1),eU4,303,0,[ttD,ttN,ttI])))}function XY(){XY=A,ttC=euY((eaU(),eow(vx(e45,1),eU4,292,0,[ttA,ttL,ttO])))}function XB(){XB=A,tsa=euY((euJ(),eow(vx(e5e,1),eU4,378,0,[tsn,tsr,tsi])))}function XU(){XU=A,tsB=euY((ei0(),eow(vx(e5s,1),eU4,375,0,[tsj,tsF,tsY])))}function XH(){XH=A,tsA=euY((esn(),eow(vx(e5i,1),eU4,339,0,[tsM,tsT,tsO])))}function X$(){X$=A,tsR=euY((enY(),eow(vx(e5o,1),eU4,452,0,[tsP,tsD,tsN])))}function Xz(){Xz=A,ts0=euY((eox(),eow(vx(e5f,1),eU4,377,0,[tsQ,ts1,tsJ])))}function XG(){XG=A,tsK=euY((euy(),eow(vx(e5c,1),eU4,336,0,[tsz,tsG,tsW])))}function XW(){XW=A,tsX=euY((eiO(),eow(vx(e5l,1),eU4,338,0,[tsZ,tsV,tsq])))}function XK(){XK=A,tuo=euY((enU(),eow(vx(e5p,1),eU4,454,0,[tur,tui,tua])))}function XV(){XV=A,tc0=euY((efx(),eow(vx(e5D,1),eU4,442,0,[tc1,tcJ,tcQ])))}function Xq(){Xq=A,tc8=euY((eub(),eow(vx(e5P,1),eU4,380,0,[tc5,tc6,tc9])))}function XZ(){XZ=A,tlj=euY((efS(),eow(vx(e5Y,1),eU4,381,0,[tlP,tlR,tlN])))}function XX(){XX=A,tlD=euY((ei1(),eow(vx(e5j,1),eU4,293,0,[tlC,tlI,tlL])))}function XJ(){XJ=A,tfp=euY((efk(),eow(vx(e5H,1),eU4,437,0,[tff,tfd,tfh])))}function XQ(){XQ=A,tpK=euY((eck(),eow(vx(e57,1),eU4,334,0,[tpG,tpz,tpW])))}function X1(){X1=A,tpk=euY((etT(),eow(vx(e56,1),eU4,272,0,[tp_,tpE,tpS])))}function X0(){return ewf(),eow(vx(e6r,1),eU4,98,0,[tbl,tbc,tbu,tba,tbs,tbo])}function X2(e,t){return e.o||(e.o=new JY((eBa(),tmy),e6O,e,0)),edG(e.o,t)}function X3(e){return e.g||(e.g=new o2),e.g.d||(e.g.d=new pD(e)),e.g.d}function X4(e){return e.g||(e.g=new o2),e.g.a||(e.g.a=new pN(e)),e.g.a}function X5(e){return e.g||(e.g=new o2),e.g.b||(e.g.b=new pI(e)),e.g.b}function X6(e){return e.g||(e.g=new o2),e.g.c||(e.g.c=new pP(e)),e.g.c}function X9(e,t,n){var r,i;for(r=0,i=new eaN(t,e);rn||t=0?e._g(n,!0,!0):exk(e,t,!0)}function JW(e,t){return elN(gP(LV(e_k(e,(eBU(),tnv)))),gP(LV(e_k(t,tnv))))}function JK(){JK=A,tcG=ehY(ehY(_G(new K2,(egR(),tuQ)),(eS_(),tu8)),tu4)}function JV(e,t,n){var r;return r=esg(e,t,n),e.b=new erH(r.c.length),eLI(e,r)}function Jq(e){if(e.b<=0)throw p7(new bC);return--e.b,e.a-=e.c.c,ell(e.a)}function JZ(e){var t;if(!e.a)throw p7(new UD);return t=e.a,e.a=z$(e.a),t}function JX(e){for(;!e.a;)if(!IM(e.c,new dr(e)))return!1;return!0}function JJ(e){var t;return(Y9(e),M4(e,198))?t=Pp(e,198):new lp(e)}function JQ(e){J1(),Pp(e.We((eBB(),thJ)),174).Fc((ekU(),tbb)),e.Ye(thX,null)}function J1(){J1=A,tdo=new os,tdu=new ou,tds=es0((eBB(),thX),tdo,thL,tdu)}function J0(){J0=A,tc2=new S2("LEAF_NUMBER",0),tc3=new S2("NODE_SIZE",1)}function J2(e,t,n){e.a=t,e.c=n,e.b.a.$b(),HC(e.d),e.e.a.c=Je(e1R,eUp,1,0,5,1)}function J3(e){e.a=Je(ty_,eHT,25,e.b+1,15,1),e.c=Je(ty_,eHT,25,e.b,15,1),e.d=0}function J4(e,t){e.a.ue(t.d,e.b)>0&&(P_(e.c,new PW(t.c,t.d,e.d)),e.b=t.d)}function J5(e,t){if(null==e.g||t>=e.i)throw p7(new xJ(t,e.i));return e.g[t]}function J6(e,t,n){if(euu(e,n),null!=n&&!e.wj(n))throw p7(new bS);return n}function J9(e){var t;if(e.Ek())for(t=e.i-1;t>=0;--t)etj(e,t);return VY(e)}function J8(e){var t,n;if(!e.b)return null;for(n=e.b;t=n.a[0];)n=t;return n}function J7(e,t){var n,r;return qe(t),(n=QO(r=e.slice(0,t),e)).length=t,n}function Qe(e,t,n,r){var i;r=(HF(),r||e2s),eS0(i=e.slice(t,n),e,t,n,-t,r)}function Qt(e,t,n,r,i){return t<0?exk(e,n,r):Pp(n,66).Nj().Pj(e,e.yh(),t,r,i)}function Qn(e){return M4(e,172)?""+Pp(e,172).a:null==e?null:efF(e)}function Qr(e){return M4(e,172)?""+Pp(e,172).a:null==e?null:efF(e)}function Qi(e,t){if(t.a)throw p7(new go(e$P));Yf(e.a,t),t.a=e,e.j||(e.j=t)}function Qa(e,t){xj.call(this,t.rd(),-16449&t.qd()),BJ(e),this.a=e,this.c=t}function Qo(e,t){var n,r;return r=t/e.c.Hd().gc()|0,n=t%e.c.Hd().gc(),X_(e,r,n)}function Qs(){Qs=A,e3F=new EY(ezt,0),e3j=new EY(e$8,1),e3Y=new EY(ezn,2)}function Qu(){Qu=A,e2D=new Ef("All",0),e2N=new TH,e2P=new ML,e2R=new T$}function Qc(){Qc=A,e2j=euY((Qu(),eow(vx(e2E,1),eU4,297,0,[e2D,e2N,e2P,e2R])))}function Ql(){Ql=A,e8b=euY((eok(),eow(vx(e4A,1),eU4,405,0,[e8f,e8p,e8d,e8h])))}function Qf(){Qf=A,e4l=euY((eaY(),eow(vx(e3r,1),eU4,406,0,[e4c,e4o,e4s,e4u])))}function Qd(){Qd=A,e4b=euY((ep7(),eow(vx(e3i,1),eU4,323,0,[e4d,e4f,e4h,e4p])))}function Qh(){Qh=A,e6z=euY((ebe(),eow(vx(e4y,1),eU4,394,0,[e6U,e6B,e6H,e6$])))}function Qp(){Qp=A,tu2=euY((egR(),eow(vx(e5T,1),eU4,393,0,[tuJ,tuQ,tu1,tu0])))}function Qb(){Qb=A,e7X=euY((eoE(),eow(vx(e4U,1),eU4,360,0,[e7Z,e7V,e7q,e7K])))}function Qm(){Qm=A,tlA=euY((emC(),eow(vx(e5R,1),eU4,340,0,[tlO,tlT,tlM,tlx])))}function Qg(){Qg=A,tet=euY((eoS(),eow(vx(e4$,1),eU4,411,0,[e79,e78,e77,tee])))}function Qv(){Qv=A,tsl=euY((ebk(),eow(vx(e5t,1),eU4,197,0,[tsu,tsc,tss,tso])))}function Qy(){Qy=A,tmo=euY((eup(),eow(vx(e6l,1),eU4,396,0,[tmr,tmi,tmn,tma])))}function Qw(){Qw=A,tpJ=euY((egF(),eow(vx(e6e,1),eU4,285,0,[tpX,tpV,tpq,tpZ])))}function Q_(){Q_=A,tpA=euY((efE(),eow(vx(e59,1),eU4,218,0,[tpO,tpT,tpx,tpM])))}function QE(){QE=A,tmt=euY((edM(),eow(vx(e6u,1),eU4,311,0,[tme,tb9,tb7,tb8])))}function QS(){QS=A,tbZ=euY((ed6(),eow(vx(e6o,1),eU4,374,0,[tbV,tbq,tbK,tbW])))}function Qk(){Qk=A,ePm(),tvq=eHQ,tvV=eH1,tvX=new fL(eHQ),tvZ=new fL(eH1)}function Qx(){Qx=A,ttt=new Sb(eGR,0),tte=new Sb("IMPROVE_STRAIGHTNESS",1)}function QT(e,t){return Pj(),P_(e,new kD(t,ell(t.e.c.length+t.g.c.length)))}function QM(e,t){return Pj(),P_(e,new kD(t,ell(t.e.c.length+t.g.c.length)))}function QO(e,t){return 10!=eeg(t)&&eow(esF(t),t.hm,t.__elementTypeId$,eeg(t),e),e}function QA(e,t){var n;return -1!=(n=QI(e,t,0))&&(ZV(e,n),!0)}function QL(e,t){var n;return(n=Pp(Z3(e.e,t),387))?(Re(n),n.e):null}function QC(e){var t;return Ts(e)&&!isNaN(t=0-e)?t:eal(eoQ(e))}function QI(e,t,n){for(;n=0?ebl(e,n,!0,!0):exk(e,t,!0)}function Q8(e,t){var n,r;return _L(),n=Vm(e),r=Vm(t),!!n&&!!r&&!ep5(n.k,r.k)}function Q7(e,t){eno(e,null==t||IX((BJ(t),t))||isNaN((BJ(t),t))?0:(BJ(t),t))}function eee(e,t){ens(e,null==t||IX((BJ(t),t))||isNaN((BJ(t),t))?0:(BJ(t),t))}function eet(e,t){ena(e,null==t||IX((BJ(t),t))||isNaN((BJ(t),t))?0:(BJ(t),t))}function een(e,t){eni(e,null==t||IX((BJ(t),t))||isNaN((BJ(t),t))?0:(BJ(t),t))}function eer(e){(this.q?this.q:(Hj(),Hj(),e2i)).Ac(e.q?e.q:(Hj(),Hj(),e2i))}function eei(e,t){return M4(t,99)&&(Pp(t,18).Bb&eH3)!=0?new x1(t,e):new eaN(t,e)}function eea(e,t){return M4(t,99)&&(Pp(t,18).Bb&eH3)!=0?new x1(t,e):new eaN(t,e)}function eeo(e,t){e4g=new e0,e4v=t,Pp((e4m=e).b,65),Jr(e4m,e4g,null),eRk(e4m)}function ees(e,t,n){var r;return r=e.g[t],Of(e,t,e.oi(t,n)),e.gi(t,n,r),e.ci(),r}function eeu(e,t){var n;return(n=e.Xc(t))>=0&&(e.$c(n),!0)}function eec(e){var t;return e.d!=e.r&&(t=evl(e),e.e=!!t&&t.Cj()==eJK,e.d=t),e.e}function eel(e,t){var n;for(Y9(e),Y9(t),n=!1;t.Ob();)n|=e.Fc(t.Pb());return n}function eef(e,t){var n;return(n=Pp(Bp(e.e,t),387))?(M6(e,n),n.e):null}function eed(e){var t,n;return(t=e/60|0,0==(n=e%60))?""+t:""+t+":"+n}function eeh(e,t){var n,r;return el3(e),r=new Xe(t,e.a),n=new IU(r),new R1(e,n)}function eep(e,t){var n=e.a[t],r=(eoW(),e0O)[typeof n];return r?r(n):euV(typeof n)}function eeb(e){switch(e.g){case 0:return eUu;case 1:return -1;default:return 0}}function eem(e){return 0>evy(e,(Q2(),e0D))?-As(eoQ(e)):e.l+e.m*eHG+e.h*eHW}function eeg(e){return null==e.__elementTypeCategory$?10:e.__elementTypeCategory$}function eev(e){var t;return null!=(t=0==e.b.c.length?null:RJ(e.b,0))&&erD(e,0),t}function eey(e,t){for(;t[0]=0;)++t[0]}function eew(e,t){this.e=t,this.a=eaJ(e),this.a<54?this.f=Kj(e):this.c=ep_(e)}function ee_(e,t,n,r){eBG(),pJ.call(this,26),this.c=e,this.a=t,this.d=n,this.b=r}function eeE(e,t,n){var r,i;for(i=0,r=10;ie.a[r]&&(r=n);return r}function eeI(e,t){var n;return 0==(n=efT(e.e.c,t.e.c))?elN(e.e.d,t.e.d):n}function eeD(e,t){return 0==t.e||0==e.e?e08:(exX(),eAl(e,t))}function eeN(e,t){if(!e)throw p7(new gL(eAL("Enum constant undefined: %s",t)))}function eeP(){eeP=A,e8v=new tp,e8y=new td,e8m=new ty,e8g=new tw,e8w=new t_}function eeR(){eeR=A,e3h=new ER("BY_SIZE",0),e3p=new ER("BY_SIZE_AND_SHAPE",1)}function eej(){eej=A,e9f=new EH("EADES",0),e9d=new EH("FRUCHTERMAN_REINGOLD",1)}function eeF(){eeF=A,teZ=new Sd("READING_DIRECTION",0),teX=new Sd("ROTATION",1)}function eeY(){eeY=A,teq=euY((eb6(),eow(vx(e4X,1),eU4,335,0,[teG,tez,teK,teV,teW])))}function eeB(){eeB=A,tsm=euY((ebG(),eow(vx(e5n,1),eU4,315,0,[tsb,tsd,tsh,tsf,tsp])))}function eeU(){eeU=A,tes=euY((ey4(),eow(vx(e4z,1),eU4,363,0,[ter,tea,teo,tei,ten])))}function eeH(){eeH=A,tnF=euY((ef_(),eow(vx(e48,1),eU4,163,0,[tnj,tnD,tnN,tnP,tnR])))}function ee$(){ee$=A,tfM=euY((eEM(),eow(vx(e5W,1),eU4,316,0,[tfE,tfS,tfT,tfk,tfx])))}function eez(){eez=A,tdb=euY((epx(),eow(vx(e5Q,1),eU4,175,0,[tdh,tdd,tdl,tdp,tdf])))}function eeG(){eeG=A,tfl=euY((eOB(),eow(vx(e5U,1),eU4,355,0,[tfo,tfa,tfu,tfs,tfc])))}function eeW(){eeW=A,e8a=euY((e_x(),eow(vx(e4k,1),eU4,356,0,[e8e,e8t,e8n,e8r,e8i])))}function eeK(){eeK=A,tpw=euY((ec3(),eow(vx(e55,1),eU4,103,0,[tpv,tpg,tpm,tpb,tpy])))}function eeV(){eeV=A,tbi=euY((epT(),eow(vx(e6n,1),eU4,249,0,[tbt,tbr,tp7,tbe,tbn])))}function eeq(){eeq=A,tbB=euY((eYu(),eow(vx(e6a,1),eGj,61,0,[tbF,tbw,tby,tbj,tbY])))}function eeZ(e,t){var n;return(n=Pp(Bp(e.a,t),134))||(n=new eX,Um(e.a,t,n)),n}function eeX(e){var t;return!!(t=Pp(e_k(e,(eBU(),ttU)),305))&&t.a==e}function eeJ(e){var t;return!!(t=Pp(e_k(e,(eBU(),ttU)),305))&&t.i==e}function eeQ(e,t){return BJ(t),FD(e),!!e.d.Ob()&&(t.td(e.d.Pb()),!0)}function ee1(e){return ecd(e,eUu)>0?eUu:0>ecd(e,eHt)?eHt:jE(e)}function ee0(e){return e<3?(enG(e,eU0),e+1):e=0&&t=-.01&&e.a<=ezs&&(e.a=0),e.b>=-.01&&e.b<=ezs&&(e.b=0),e}function ee5(e,t){return t==(I8(),I8(),e2p)?e.toLocaleLowerCase():e.toLowerCase()}function ee6(e){return((2&e.i)!=0?"interface ":(1&e.i)!=0?"":"class ")+(LW(e),e.o)}function ee9(e){var t,n;n=t=new mD,JL((e.q||(e.q=new FQ(tgi,e,11,10)),e.q),n)}function ee8(e,t){var n;return n=t>0?t-1:t,yr(yi(eny(P6(new mV,n),e.n),e.j),e.k)}function ee7(e,t,n,r){var i;e.j=-1,ex8(e,eSu(e,t,n),(_4(),(i=Pp(t,66).Mj()).Ok(r)))}function ete(e){this.g=e,this.f=new p0,this.a=eB4.Math.min(this.g.c.c,this.g.d.c)}function ett(e){this.b=new p0,this.a=new p0,this.c=new p0,this.d=new p0,this.e=e}function etn(e,t){this.a=new p2,this.e=new p2,this.b=(euJ(),tsi),this.c=e,this.b=t}function etr(e,t,n){CK.call(this),etk(this),this.a=e,this.c=n,this.b=t.d,this.f=t.e}function eti(e){this.d=e,this.c=e.c.vc().Kc(),this.b=null,this.a=null,this.e=(m5(),e0m)}function eta(e){if(e<0)throw p7(new gL("Illegal Capacity: "+e));this.g=this.ri(e)}function eto(e,t){if(0>e||e>t)throw p7(new va("fromIndex: 0, toIndex: "+e+e$m+t))}function ets(e){var t;if(e.a==e.b.a)throw p7(new bC);return t=e.a,e.c=t,e.a=e.a.e,t}function etu(e){var t;A4(!!e.c),t=e.c.a,etw(e.d,e.c),e.b==e.c?e.b=t:--e.a,e.c=null}function etc(e,t){var n;return el3(e),n=new HA(e,e.a.rd(),4|e.a.qd(),t),new R1(e,n)}function etl(e,t){var n,r;return(n=Pp(ecA(e.d,t),14))?(r=t,e.e.pc(r,n)):null}function etf(e,t){var n,r;for(r=e.Kc();r.Ob();)eo3(n=Pp(r.Pb(),70),(eBU(),tnt),t)}function etd(e){var t;return(t=gP(LV(e_k(e,(eBy(),tak)))))<0&&eo3(e,tak,t=0),t}function eth(e,t,n){var r;ev_(n,r=eB4.Math.max(0,e.b/2-.5),1),P_(t,new EJ(n,r))}function etp(e,t,n){var r;return zy(Ra(r=e.a.e[Pp(t.a,10).p]-e.a.e[Pp(n.a,10).p]))}function etb(e,t,n,r,i,a){var o;o=ZD(r),Gs(o,i),Go(o,a),exg(e.a,r,new DT(o,t,n.f))}function etm(e,t){var n;if(!(n=eAh(e.Tg(),t)))throw p7(new gL(eZV+t+eZX));return n}function etg(e,t){var n;for(n=e;z$(n);)if((n=z$(n))==t)return!0;return!1}function etv(e,t){var n,r,i;for(i=0,r=t.a.cd(),n=Pp(t.a.dd(),14).gc();i0&&(e.a/=t,e.b/=t),e}function etP(e){var t;return e.w?e.w:((t=Ww(e))&&!t.kh()&&(e.w=t),t)}function etR(e){var t;return null==e?null:e_e(t=Pp(e,190),t.length)}function etj(e,t){if(null==e.g||t>=e.i)throw p7(new xJ(t,e.i));return e.li(t,e.g[t])}function etF(e){var t,n;for(t=e.a.d.j,n=e.c.d.j;t!=n;)erC(e.b,t),t=elI(t);erC(e.b,t)}function etY(e){var t;for(t=0;t=14&&t<=16)),e}function etW(e,t,n){var r=function(){return e.apply(r,arguments)};return t.apply(r,n),r}function etK(e,t,n){var r,i;r=t;do i=gP(e.p[r.p])+n,e.p[r.p]=i,r=e.a[r.p];while(r!=t)}function etV(e,t){var n,r;r=e.a,n=elr(e,t,null),r==t||e.e||(n=eFr(e,t,n)),n&&n.Fi()}function etq(e,t){return Mc(),enj(eHe),eB4.Math.abs(e-t)<=eHe||e==t||isNaN(e)&&isNaN(t)}function etZ(e,t){return Mc(),enj(eHe),eB4.Math.abs(e-t)<=eHe||e==t||isNaN(e)&&isNaN(t)}function etX(e,t){return e_z(),ME(e.b.c.length-e.e.c.length,t.b.c.length-t.e.c.length)}function etJ(e,t){return yk(eif(e,t,jE(efn(eUJ,Ux(jE(efn(null==t?0:esj(t),eUQ)),15)))))}function etQ(){etQ=A,e8R=euY((eEn(),eow(vx(e4P,1),eU4,267,0,[e8N,e8D,e8C,e8P,e8I,e8L])))}function et1(){et1=A,tdJ=euY((eyY(),eow(vx(e54,1),eU4,291,0,[tdX,tdZ,tdq,tdK,tdW,tdV])))}function et0(){et0=A,tdD=euY((ebx(),eow(vx(e53,1),eU4,248,0,[tdM,tdL,tdC,tdI,tdO,tdA])))}function et2(){et2=A,teI=euY((eSg(),eow(vx(e4K,1),eU4,227,0,[teO,teL,teM,teA,teC,teT])))}function et3(){et3=A,ttm=euY((e_3(),eow(vx(e43,1),eU4,275,0,[ttp,ttf,ttb,tth,ttd,ttl])))}function et4(){et4=A,ttc=euY((eyd(),eow(vx(e42,1),eU4,274,0,[tto,tta,ttu,tti,tts,ttr])))}function et5(){et5=A,tst=euY((ewY(),eow(vx(e47,1),eU4,313,0,[to7,to9,to5,to6,tse,to8])))}function et6(){et6=A,te7=euY((eEf(),eow(vx(e41,1),eU4,276,0,[te4,te3,te6,te5,te8,te9])))}function et9(){et9=A,tu7=euY((eS_(),eow(vx(e5A,1),eU4,327,0,[tu8,tu4,tu6,tu5,tu9,tu3])))}function et8(){et8=A,tbv=euY((ekU(),eow(vx(e6i,1),eU4,273,0,[tbm,tbp,tbb,tbh,tbd,tbg])))}function et7(){et7=A,tpR=euY((e_a(),eow(vx(e58,1),eU4,312,0,[tpN,tpI,tpP,tpL,tpD,tpC])))}function ene(){return eT7(),eow(vx(e6t,1),eU4,93,0,[tp1,tpQ,tp2,tp9,tp6,tp5,tp3,tp4,tp0])}function ent(e,t){var n;n=e.a,e.a=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,0,n,e.a))}function enn(e,t){var n;n=e.b,e.b=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,1,n,e.b))}function enr(e,t){var n;n=e.b,e.b=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,3,n,e.b))}function eni(e,t){var n;n=e.f,e.f=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,3,n,e.f))}function ena(e,t){var n;n=e.g,e.g=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,4,n,e.g))}function eno(e,t){var n;n=e.i,e.i=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,5,n,e.i))}function ens(e,t){var n;n=e.j,e.j=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,6,n,e.j))}function enu(e,t){var n;n=e.j,e.j=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,1,n,e.j))}function enc(e,t){var n;n=e.c,e.c=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,4,n,e.c))}function enl(e,t){var n;n=e.k,e.k=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qo(e,2,n,e.k))}function enf(e,t){var n;n=e.d,e.d=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qs(e,2,n,e.d))}function end(e,t){var n;n=e.s,e.s=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qs(e,4,n,e.s))}function enh(e,t){var n;n=e.t,e.t=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new qs(e,5,n,e.t))}function enp(e,t){var n;n=e.F,e.F=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,5,n,t))}function enb(e,t){var n;return(n=Pp(Bp((_5(),tmU),e),55))?n.xj(t):Je(e1R,eUp,1,t,5,1)}function enm(e,t){var n,r;return(n=t in e.a)&&(r=zR(e,t).he())?r.a:null}function eng(e,t){var n,r,i;return n=(r=(yT(),i=new o0),t&&eAu(r,t),r),eri(n,e),n}function env(e,t,n){if(euu(e,n),!e.Bk()&&null!=n&&!e.wj(n))throw p7(new bS);return n}function eny(e,t){return e.n=t,e.n?(e.f=new p0,e.e=new p0):(e.f=null,e.e=null),e}function enw(e,t,n,r,i,a){var o;return enA(n,o=Y6(e,t)),o.i=i?8:0,o.f=r,o.e=i,o.g=a,o}function en_(e,t,n,r,i){this.d=t,this.k=r,this.f=i,this.o=-1,this.p=1,this.c=e,this.a=n}function enE(e,t,n,r,i){this.d=t,this.k=r,this.f=i,this.o=-1,this.p=2,this.c=e,this.a=n}function enS(e,t,n,r,i){this.d=t,this.k=r,this.f=i,this.o=-1,this.p=6,this.c=e,this.a=n}function enk(e,t,n,r,i){this.d=t,this.k=r,this.f=i,this.o=-1,this.p=7,this.c=e,this.a=n}function enx(e,t,n,r,i){this.d=t,this.j=r,this.e=i,this.o=-1,this.p=4,this.c=e,this.a=n}function enT(e,t){var n,r,i,a;for(i=0,a=(r=t).length;i=0),0>ehP(e.d,e.c)&&(e.a=e.a-1&e.d.a.length-1,e.b=e.d.c),e.c=-1}function enR(e){return e.a<54?e.f<0?-1:e.f>0?1:0:(e.c||(e.c=euK(e.f)),e.c).e}function enj(e){if(!(e>=0))throw p7(new gL("tolerance ("+e+") must be >= 0"));return e}function enF(){return tdc||(tdc=new eC$,es4(tdc,eow(vx(e20,1),eUp,130,0,[new cZ]))),tdc}function enY(){enY=A,tsP=new SL(ezo,0),tsD=new SL("INPUT",1),tsN=new SL("OUTPUT",2)}function enB(){enB=A,teB=new Sl("ARD",0),teH=new Sl("MSD",1),teU=new Sl("MANUAL",2)}function enU(){enU=A,tur=new SR("BARYCENTER",0),tui=new SR(eG7,1),tua=new SR(eWe,2)}function enH(e,t){var n;if(n=e.gc(),t<0||t>n)throw p7(new Ii(t,n));return new IB(e,t)}function en$(e,t){var n;return M4(t,42)?e.c.Mc(t):(n=edG(e,t),ehx(e,t),n)}function enz(e,t,n){return eu2(e,t),er3(e,n),end(e,0),enh(e,1),els(e,!0),eli(e,!0),e}function enG(e,t){if(e<0)throw p7(new gL(t+" cannot be negative but was: "+e));return e}function enW(e,t){var n,r;for(n=0,r=e.gc();n0)?Pp(RJ(n.a,r-1),10):null}function ert(e,t){var n;n=e.k,e.k=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,2,n,e.k))}function ern(e,t){var n;n=e.f,e.f=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,8,n,e.f))}function err(e,t){var n;n=e.i,e.i=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,7,n,e.i))}function eri(e,t){var n;n=e.a,e.a=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,8,n,e.a))}function era(e,t){var n;n=e.b,e.b=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,0,n,e.b))}function ero(e,t){var n;n=e.b,e.b=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,0,n,e.b))}function ers(e,t){var n;n=e.c,e.c=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,1,n,e.c))}function eru(e,t){var n;n=e.c,e.c=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,1,n,e.c))}function erc(e,t){var n;n=e.c,e.c=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,4,n,e.c))}function erl(e,t){var n;n=e.d,e.d=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,1,n,e.d))}function erf(e,t){var n;n=e.D,e.D=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,2,n,e.D))}function erd(e,t){e.r>0&&e.c0&&0!=e.g&&erd(e.i,t/e.r*e.i.d))}function erh(e,t,n){var r;e.b=t,e.a=n,r=(512&e.a)==512?new mU:new u7,e.c=eLV(r,e.b,e.a)}function erp(e,t){return eLt(e.e,t)?(_4(),eec(t)?new RA(t,e):new xe(t,e)):new xr(t,e)}function erb(e,t){return yS(eid(e.a,t,jE(efn(eUJ,Ux(jE(efn(null==t?0:esj(t),eUQ)),15)))))}function erm(e,t,n){return Qz(e,new f9(t),new ea,new f8(n),eow(vx(e2L,1),eU4,132,0,[]))}function erg(e){var t,n;return 0>e?new _e:(t=e+1,n=new Zi(t,e),new L0(null,n))}function erv(e,t){var n;return Hj(),n=new w8(1),xd(e)?Ge(n,e,t):eS9(n.f,e,t),new f$(n)}function ery(e,t){var n,r;return(n=e.o+e.p)<(r=t.o+t.p)?-1:n==r?0:1}function erw(e){var t;return(t=e_k(e,(eBU(),tnc)),M4(t,160))?edo(Pp(t,160)):null}function er_(e){var t;return(t=esi(e=eB4.Math.max(e,2)),e>t)?(t<<=1)>0?t:eU2:t}function erE(e){switch(OZ(3!=e.e),e.e){case 2:return!1;case 0:return!0}return Zk(e)}function erS(e,t){var n;return!!M4(t,8)&&(n=Pp(t,8),e.a==n.a&&e.b==n.b)}function erk(e,t,n){var r,i,a;return a=t>>5,i=31&t,r=WM(Fy(e.n[n][a],jE(Fg(i,1))),3)}function erx(e,t){var n,r;for(r=t.vc().Kc();r.Ob();)evQ(e,(n=Pp(r.Pb(),42)).cd(),n.dd())}function erT(e,t){var n;n=new e0,Pp(t.b,65),Pp(t.b,65),Pp(t.b,65),ety(t.a,new N9(e,n,t))}function erM(e,t){var n;n=e.b,e.b=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,21,n,e.b))}function erO(e,t){var n;n=e.d,e.d=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,11,n,e.d))}function erA(e,t){var n;n=e.j,e.j=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,13,n,e.j))}function erL(e,t,n){var r,i,a;for(a=e.a.length-1,i=e.b,r=0;r>>31;0!=r&&(e[n]=r)}function eip(e,t){var n,r;for(Hj(),r=new p0,n=0;n0&&(this.g=this.ri(this.i+(this.i/8|0)+1),e.Qc(this.g))}function eiR(e,t){PJ.call(this,tgd,e,t),this.b=this,this.a=eAY(e.Tg(),ee2(this.e.Tg(),this.c))}function eij(e,t){var n,r;for(BJ(t),r=t.vc().Kc();r.Ob();)n=Pp(r.Pb(),42),e.zc(n.cd(),n.dd())}function eiF(e,t,n){var r;for(r=n.Kc();r.Ob();)if(!Vq(e,t,r.Pb()))return!1;return!0}function eiY(e,t,n,r,i){var a;return n&&(a=edv(t.Tg(),e.c),i=n.gh(t,-1-(-1==a?r:a),null,i)),i}function eiB(e,t,n,r,i){var a;return n&&(a=edv(t.Tg(),e.c),i=n.ih(t,-1-(-1==a?r:a),null,i)),i}function eiU(e){var t;if(-2==e.b){if(0==e.e)t=-1;else for(t=0;0==e.a[t];t++);e.b=t}return e.b}function eiH(e){switch(e.g){case 2:return eYu(),tbY;case 4:return eYu(),tby;default:return e}}function ei$(e){switch(e.g){case 1:return eYu(),tbj;case 3:return eYu(),tbw;default:return e}}function eiz(e){var t,n,r;return e.j==(eYu(),tbw)&&(t=eTt(e),n=Aa(t,tby),(r=Aa(t,tbY))||r&&n)}function eiG(e){var t,n;return t=Pp(e.e&&e.e(),9),n=Pp(YR(t,t.length),9),new I1(t,n,t.length)}function eiW(e,t){ewG(t,eG9,1),efJ(_p(new dp((__(),new U7(e,!1,!1,new tO))))),eEj(t)}function eiK(e,t){return OQ(),xd(e)?ZZ(e,Lq(t)):xf(e)?F_(e,LV(t)):xl(e)?Fw(e,LK(t)):e.wd(t)}function eiV(e,t){t.q=e,e.d=eB4.Math.max(e.d,t.r),e.b+=t.d+(0==e.a.c.length?0:e.c),P_(e.a,t)}function eiq(e,t){var n,r,i,a;return i=e.c,n=e.c+e.b,a=e.d,r=e.d+e.a,t.a>i&&t.aa&&t.b1||e.Ob())return++e.a,e.g=0,t=e.i,e.Ob(),t;throw p7(new bC)}function eaA(e){var t;return Ma(),En(tuT,e)||((t=new af).a=e,CM(tuT,e,t)),Pp(UA(tuT,e),635)}function eaL(e){var t,n,r,i;return r=0,(i=e)<0&&(i+=eHW,r=eH$),n=zy(i/eHG),Mk(t=zy(i-n*eHG),n,r)}function eaC(e){var t,n,r;for(r=0,n=new _t(e.a);n.aecd(e,0)&&(e=PN(e)),64-(0!=(t=jE(Fv(e,32)))?exv(t):exv(jE(e))+32)}function eaQ(e){var t;return t=Pp(e_k(e,(eBU(),tt1)),61),e.k==(eEn(),e8C)&&(t==(eYu(),tbY)||t==tby)}function ea1(e,t,n){var r,i;(i=Pp(e_k(e,(eBy(),taR)),74))&&(eu_(r=new mE,0,i),etH(r,n),er7(t,r))}function ea0(e,t,n){var r,i,a,o;r=(o=Bq(e)).d,i=o.c,a=e.n,t&&(a.a=a.a-r.b-i.a),n&&(a.b=a.b-r.d-i.b)}function ea2(e,t){var n,r;return(n=e.j)!=(r=t.j)?n.g-r.g:e.p==t.p?0:n==(eYu(),tbw)?e.p-t.p:t.p-e.p}function ea3(e){var t,n;for(eYp(e),n=new fz(e.d);n.a>22),i=e.h+t.h+(r>>22),Mk(n&eHH,r&eHH,i&eH$)}function eor(e,t){var n,r,i;return n=e.l-t.l,r=e.m-t.m+(n>>22),i=e.h-t.h+(r>>22),Mk(n&eHH,r&eHH,i&eH$)}function eoi(e){var t;return e<128?((t=(RH(),e0Y)[e])||(t=e0Y[e]=new fA(e)),t):new fA(e)}function eoa(e){var t;return M4(e,78)?e:((t=e&&e.__java$exception)||(t=new euq(e),by(t)),t)}function eoo(e){if(M4(e,186))return Pp(e,118);if(e)return null;throw p7(new gD(eXR))}function eos(e,t){if(null==t)return!1;for(;e.a!=e.b;)if(ecX(t,ecn(e)))return!0;return!1}function eou(e){return!!e.a.Ob()||e.a==e.d&&(e.a=new KU(e.e.f),e.a.Ob())}function eoc(e,t){var n,r;return 0!=(r=(n=t.Pc()).length)&&(PO(e.c,e.c.length,n),!0)}function eol(e,t,n){var r,i;for(i=t.vc().Kc();i.Ob();)r=Pp(i.Pb(),42),e.yc(r.cd(),r.dd(),n);return e}function eof(e,t){var n,r;for(r=new fz(e.b);r.a=0,"Negative initial capacity"),PG(t>=0,"Non-positive load factor"),Yy(this)}function eoV(e,t,n){return!(e>=128)&&(e<64?xg(WM(Fg(1,e),n),0):xg(WM(Fg(1,e-64),t),0))}function eoq(e,t){return!!e&&!!t&&e!=t&&0>efT(e.b.c,t.b.c+t.b.b)&&0>efT(t.b.c,e.b.c+e.b.b)}function eoZ(e){var t,n,r;return n=e.n,r=e.o,t=e.d,new Hr(n.a-t.b,n.b-t.d,r.a+(t.b+t.c),r.b+(t.d+t.a))}function eoX(e){var t,n,r,i;for(n=e.a,r=0,i=n.length;r(r=e.gc()))throw p7(new Ii(t,r));return e.hi()&&(n=zG(e,n)),e.Vh(t,n)}function eo2(e,t,n){return null==n?(e.q||(e.q=new p2),Z3(e.q,t)):(e.q||(e.q=new p2),Um(e.q,t,n)),e}function eo3(e,t,n){return null==n?(e.q||(e.q=new p2),Z3(e.q,t)):(e.q||(e.q=new p2),Um(e.q,t,n)),e}function eo4(e){var t,n;return n=new Z5,eaW(n,e),eo3(n,(erV(),e9j),e),t=new p2,eNY(e,n,t),eFS(e,n,t),n}function eo5(e){var t,n,r;for(eLG(),n=Je(e50,eUP,8,2,0,1),r=0,t=0;t<2;t++)r+=.5,n[t]=emh(r,e);return n}function eo6(e,t){var n,r,i,a;for(a=0,n=!1,r=e.a[t].length;a>=1);return t}function esa(e){var t,n;return 32==(n=exv(e.h))?32==(t=exv(e.m))?exv(e.l)+32:t+20-10:n-12}function eso(e){var t;return null==(t=e.a[e.b])?null:(Bc(e.a,e.b,null),e.b=e.b+1&e.a.length-1,t)}function ess(e){var t,n;return t=e.t-e.k[e.o.p]*e.d+e.j[e.o.p]>e.f,n=e.u+e.e[e.o.p]*e.d>e.f*e.s*e.d,t||n}function esu(e,t,n){var r,i;return r=new Js(t,n),i=new H,e.b=eLg(e,e.b,r,i),i.b||++e.c,e.b.b=!1,i.d}function esc(e,t,n){var r,i,a,o;for(o=ecZ(t,n),a=0,i=o.Kc();i.Ob();)r=Pp(i.Pb(),11),Um(e.c,r,ell(a++))}function esl(e){var t,n;for(n=new fz(e.a.b);n.an&&(n=e[t]);return n}function esg(e,t,n){var r;return r=new p0,eA0(e,t,r,(eYu(),tby),!0,!1),eA0(e,n,r,tbY,!1,!1),r}function esv(e,t,n){var r,i,a,o;return a=null,i=Kq(o=t,"labels"),a=(eT2((r=new kG(e,n)).a,r.b,i),i)}function esy(e,t,n,r){var i;return!(!(i=eMv(e,t,n,r))&&(i=elh(e,n,r)))||eR3(e,t,i)?i:null}function esw(e,t,n,r){var i;return!(!(i=eMy(e,t,n,r))&&(i=elp(e,n,r)))||eR3(e,t,i)?i:null}function es_(e,t){var n;for(n=0;n1||t>=0&&e.b<3)}function esP(e){var t,n,r;for(t=new mE,r=epL(e,0);r.b!=r.d.c;)n=Pp(Vv(r),8),Ls(t,0,new TS(n));return t}function esR(e){var t,n;for(n=new fz(e.a.b);n.ar?1:0}function esJ(e,t){return!!eO2(e,t)&&(exg(e.b,Pp(e_k(t,(eBU(),ttX)),21),t),P7(e.a,t),!0)}function esQ(e){var t,n;(t=Pp(e_k(e,(eBU(),tng)),10))&&(QA((n=t.c).a,t),0==n.a.c.length&&QA(Bq(t).b,n))}function es1(e){return e2M?Je(e2k,e$_,572,0,0,1):Pp(epg(e.a,Je(e2k,e$_,572,e.a.c.length,0,1)),842)}function es0(e,t,n,r){return U_(),new gt(eow(vx(e1$,1),eUK,42,0,[(eb2(e,t),new wD(e,t)),(eb2(n,r),new wD(n,r))]))}function es2(e,t,n){var r,i;return enz(i=r=new mD,t,n),JL((e.q||(e.q=new FQ(tgi,e,11,10)),e.q),i),i}function es3(e){var t,n,r,i;for(t=0,r=Je(e17,eUP,2,n=(i=Eo(tmx,e)).length,6,1);t=e.b.c.length)&&(es6(e,2*t+1),(n=2*t+2)=0&&e[r]===t[r];r--);return r<0?0:Ei(WM(e[r],eH8),WM(t[r],eH8))?-1:1}function es7(e,t){var n,r;for(r=epL(e,0);r.b!=r.d.c;)(n=Pp(Vv(r),214)).e.length>0&&(t.td(n),n.i&&elk(n))}function eue(e,t){var n,r;return r=Pp(eaS(e.a,4),126),n=Je(e6N,eJM,415,t,0,1),null!=r&&ePD(r,0,n,0,r.length),n}function eut(e,t){var n;return n=new eCg((256&e.f)!=0,e.i,e.a,e.d,(16&e.f)!=0,e.j,e.g,t),null!=e.e||(n.c=e),n}function eun(e,t){var n,r;for(r=e.Zb().Cc().Kc();r.Ob();)if((n=Pp(r.Pb(),14)).Hc(t))return!0;return!1}function eur(e,t,n,r,i){var a,o;for(o=n;o<=i;o++)for(a=t;a<=r;a++)if(emy(e,a,o))return!0;return!1}function eui(e,t,n){var r,i,a,o;for(BJ(n),o=!1,a=e.Zc(t),i=n.Kc();i.Ob();)r=i.Pb(),a.Rb(r),o=!0;return o}function eua(e,t){var n;return e===t||!!M4(t,83)&&(n=Pp(t,83),eEB(Fc(e),n.vc()))}function euo(e,t,n){var r,i;for(i=n.Kc();i.Ob();)if(r=Pp(i.Pb(),42),e.re(t,r.dd()))return!0;return!1}function eus(e,t,n){return e.d[t.p][n.p]||(ebp(e,t,n),e.d[t.p][n.p]=!0,e.d[n.p][t.p]=!0),e.a[t.p][n.p]}function euu(e,t){if(!e.ai()&&null==t)throw p7(new gL("The 'no null' constraint is violated"));return t}function euc(e,t){null==e.D&&null!=e.B&&(e.D=e.B,e.B=null),erf(e,null==t?null:(BJ(t),t)),e.C&&e.yk(null)}function eul(e,t){var n;return!!(e&&e!=t&&Ln(t,(eBU(),tt8)))&&(n=Pp(e_k(t,(eBU(),tt8)),10))!=e}function euf(e){switch(e.i){case 2:return!0;case 1:return!1;case -1:++e.c;default:return e.pl()}}function eud(e){switch(e.i){case -2:return!0;case -1:return!1;case 1:--e.c;default:return e.ql()}}function euh(e){zL.call(this,"The given string does not match the expected format for individual spacings.",e)}function eup(){eup=A,tmr=new kN("ELK",0),tmi=new kN("JSON",1),tmn=new kN("DOT",2),tma=new kN("SVG",3)}function eub(){eub=A,tc5=new S3(eGR,0),tc6=new S3("RADIAL_COMPACTION",1),tc9=new S3("WEDGE_COMPACTION",2)}function eum(){eum=A,e2B=new Ed("CONCURRENT",0),e2U=new Ed("IDENTITY_FINISH",1),e2H=new Ed("UNORDERED",2)}function eug(){eug=A,e6q=(_y(),e6G),e6V=new xX(ezj,e6q),e6K=new pO(ezF),e6Z=new pO(ezY),e6X=new pO(ezB)}function euv(){euv=A,e72=new n1,e73=new n0,e70=new n2,e71=new n3,e7J=(BJ(e7Q=new n4),new P)}function euy(){euy=A,tsz=new SD("CONSERVATIVE",0),tsG=new SD("CONSERVATIVE_SOFT",1),tsW=new SD("SLOPPY",2)}function euw(){euw=A,tpH=new T3(15),tpU=new T2((eBB(),thN),tpH),tp$=th3,tpj=td3,tpF=thx,tpB=thO,tpY=thM}function eu_(e,t,n){var r,i,a;for(r=new _n,a=epL(n,0);a.b!=a.d.c;)i=Pp(Vv(a),8),P7(r,new TS(i));eui(e,t,r)}function euE(e){var t,n,r;for(t=0,r=Je(e50,eUP,8,e.b,0,1),n=epL(e,0);n.b!=n.d.c;)r[t++]=Pp(Vv(n),8);return r}function euS(e){var t;return 0!=(t=(e.a||(e.a=new FQ(tgn,e,9,5)),e.a)).i?_K(Pp(etj(t,0),678)):null}function euk(e,t){var n;return(n=eft(e,t),Ei(WA(e,t),0)|xm(WA(e,n),0))?n:eft(eUY,WA(Fy(n,63),1))}function eux(e,t){var n;n=null!=epB((edk(),to3))&&null!=t.wg()?gP(LV(t.wg()))/gP(LV(epB(to3))):1,Um(e.b,t,n)}function euT(e,t){var n,r;return(n=Pp(e.d.Bc(t),14))?((r=e.e.hc()).Gc(n),e.e.d-=n.gc(),n.$b(),r):null}function euM(e,t){var n,r;if(0!=(r=e.c[t]))for(e.c[t]=0,e.d-=r,n=t+1;n0)return FP(t-1,e.a.c.length),ZV(e.a,t-1);throw p7(new bL)}function euA(e,t,n){if(t<0)throw p7(new gE(eq1+t));tt)throw p7(new gL(e$x+e+e$T+t));if(e<0||t>n)throw p7(new va(e$x+e+e$M+t+e$m+n))}function euC(e){if(!e.a||(8&e.a.i)==0)throw p7(new gC("Enumeration class expected for layout option "+e.f))}function euI(e){var t;++e.j,0==e.i?e.g=null:e.ieVq?e-n>eVq:n-e>eVq)}function euG(e,t){return!e||t&&!e.j||M4(e,124)&&0==Pp(e,124).a.b?0:e.Re()}function euW(e,t){return!e||t&&!e.k||M4(e,124)&&0==Pp(e,124).a.a?0:e.Se()}function euK(e){return(eLQ(),e<0)?-1!=e?new ep4(-1,-e):e03:e<=10?e05[zy(e)]:new ep4(1,e)}function euV(e){throw eoW(),p7(new gs("Unexpected typeof result '"+e+"'; please report this bug to the GWT team"))}function euq(e){g0(),MV(this),HD(this),this.e=e,eA9(this,e),this.g=null==e?eUg:efF(e),this.a="",this.b=e,this.a=""}function euZ(){this.a=new a4,this.f=new hW(this),this.b=new hK(this),this.i=new hV(this),this.e=new hq(this)}function euX(){m6.call(this,new Ju(ee0(16))),enG(2,eUN),this.b=2,this.a=new Uc(null,null,0,null),bp(this.a,this.a)}function euJ(){euJ=A,tsn=new SS("DUMMY_NODE_OVER",0),tsr=new SS("DUMMY_NODE_UNDER",1),tsi=new SS("EQUAL",2)}function euQ(){euQ=A,e8u=zD(eow(vx(e55,1),eU4,103,0,[(ec3(),tpm),tpg])),e8c=zD(eow(vx(e55,1),eU4,103,0,[tpy,tpb]))}function eu1(e){return(eYu(),tbC).Hc(e.j)?gP(LV(e_k(e,(eBU(),tnM)))):esp(eow(vx(e50,1),eUP,8,0,[e.i.n,e.n,e.a])).b}function eu0(e){var t,n,r,i;for(n=(r=e.b.a).a.ec().Kc();n.Ob();)t=Pp(n.Pb(),561),i=new eMq(t,e.e,e.f),P_(e.g,i)}function eu2(e,t){var n,r,i;r=e.nk(t,null),i=null,t&&(i=(yO(),n=new p5),etV(i,e.r)),(r=ew3(e,i,r))&&r.Fi()}function eu3(e,t){var n,r;for(r=0!=eMU(e.d,1),n=!0;n;)n=!1,n=t.c.Tf(t.e,r),n|=eAb(e,t,r,!1),r=!r;er0(e)}function eu4(e,t){var n,r,i;return r=!1,n=t.q.d,t.di&&(eyC(t.q,i),r=n!=t.q.d)),r}function eu5(e,t){var n,r,i,a,o,s,u,c;return u=t.i,c=t.j,i=(r=e.f).i,a=r.j,o=u-i,s=c-a,n=eB4.Math.sqrt(o*o+s*s)}function eu6(e,t){var n,r;return(r=ehO(e))||(tmT||(tmT=new sh),n=(eRe(),eSR(t)),JL((r=new pq(n)).Vk(),e)),r}function eu9(e,t){var n,r;return(n=Pp(e.c.Bc(t),14))?((r=e.hc()).Gc(n),e.d-=n.gc(),n.$b(),e.mc(r)):e.jc()}function eu8(e,t){var n;for(n=0;n=e.c.b:e.a<=e.c.b))throw p7(new bC);return t=e.a,e.a+=e.c.c,++e.b,ell(t)}function eci(e){var t;return t=new ete(e),Kv(e.a,e8w,new g$(eow(vx(e4M,1),eUp,369,0,[t]))),t.d&&P_(t.f,t.d),t.f}function eca(e){var t;return eaW(t=new MA(e.a),e),eo3(t,(eBU(),tnc),e),t.o.a=e.g,t.o.b=e.f,t.n.a=e.i,t.n.b=e.j,t}function eco(e,t,n,r){var i,a;for(a=e.Kc();a.Ob();)(i=Pp(a.Pb(),70)).n.a=t.a+(r.a-i.o.a)/2,i.n.b=t.b,t.b+=i.o.b+n}function ecs(e,t,n){var r,i;for(i=t.a.a.ec().Kc();i.Ob();)if($o(e,r=Pp(i.Pb(),57),n))return!0;return!1}function ecu(e){var t,n;for(n=new fz(e.r);n.a=0?t:-t;r>0;)r%2==0?(n*=n,r=r/2|0):(i*=n,r-=1);return t<0?1/i:i}function ecw(e,t){var n,r,i;for(i=1,n=e,r=t>=0?t:-t;r>0;)r%2==0?(n*=n,r=r/2|0):(i*=n,r-=1);return t<0?1/i:i}function ec_(e){var t,n,r,i;if(null!=e){for(n=0;n0&&esJ(n=Pp(RJ(e.a,e.a.c.length-1),570),t))&&P_(e.a,new Zn(t))}function ecP(e){var t,n;Dj(),t=e.d.c-e.e.c,ety((n=Pp(e.g,145)).b,new d7(t)),ety(n.c,new he(t)),qX(n.i,new ht(t))}function ecR(e){var t;return t=new vc,t.a+="VerticalSegment ",xT(t,e.e),t.a+=" ",xM(t,OU(new ve,new fz(e.k))),t.a}function ecj(e){var t;return(t=Pp(eef(e.c.c,""),229))||(t=new GM(v3(v2(new of,""),"Other")),epy(e.c.c,"",t)),t}function ecF(e){var t;return(64&e.Db)!=0?eMT(e):(t=new O1(eMT(e)),t.a+=" (name: ",xk(t,e.zb),t.a+=")",t.a)}function ecY(e,t,n){var r,i;return i=e.sb,e.sb=t,(4&e.Db)!=0&&(1&e.Db)==0&&(r=new FX(e,1,4,i,t),n?n.Ei(r):n=r),n}function ecB(e,t){var n,r,i;for(n=0,i=efr(e,t).Kc();i.Ob();)n+=null!=e_k(r=Pp(i.Pb(),11),(eBU(),tng))?1:0;return n}function ecU(e,t,n){var r,i,a;for(r=0,a=epL(e,0);a.b!=a.d.c&&!((i=gP(LV(Vv(a))))>n);)i>=t&&++r;return r}function ecH(e,t,n){var r,i;return r=new Q$(e.e,3,13,null,(i=t.c)||(eBK(),tgA),ebv(e,t),!1),n?n.Ei(r):n=r,n}function ec$(e,t,n){var r,i;return r=new Q$(e.e,4,13,(i=t.c)||(eBK(),tgA),null,ebv(e,t),!1),n?n.Ei(r):n=r,n}function ecz(e,t,n){var r,i;return i=e.r,e.r=t,(4&e.Db)!=0&&(1&e.Db)==0&&(r=new FX(e,1,8,i,e.r),n?n.Ei(r):n=r),n}function ecG(e,t){var n,r;return(r=(n=Pp(t,676)).vk())||n.wk(r=M4(t,88)?new k9(e,Pp(t,26)):new Ke(e,Pp(t,148))),r}function ecW(e,t,n){var r;e.qi(e.i+1),r=e.oi(t,n),t!=e.i&&ePD(e.g,t,e.g,t+1,e.i-t),Bc(e.g,t,r),++e.i,e.bi(t,n),e.ci()}function ecK(e,t){var n;return t.a&&(n=t.a.a.length,e.a?xM(e.a,e.b):e.a=new O0(e.d),Ka(e.a,t.a,t.d.length,n)),e}function ecV(e,t){var n,r,i,a;if(t.vi(e.a),null!=(a=Pp(eaS(e.a,8),1936)))for(r=0,i=(n=a).length;rn)throw p7(new gE(e$x+e+e$M+t+", size: "+n));if(e>t)throw p7(new gL(e$x+e+e$T+t))}function ec6(e,t,n){if(t<0)ekN(e,n);else{if(!n.Ij())throw p7(new gL(eZV+n.ne()+eZq));Pp(n,66).Nj().Vj(e,e.yh(),t)}}function ec9(e,t,n,r,i,a,o,s){var u;for(u=n;a=r||t=s.ue(e[t],e[u])?Bc(i,a++,e[t++]):Bc(i,a++,e[u++])}function ec8(e,t,n,r,i,a){this.e=new p0,this.f=(enY(),tsP),P_(this.e,e),this.d=t,this.a=n,this.b=r,this.f=i,this.c=a}function ec7(e,t){var n,r;for(r=new Ow(e);r.e!=r.i.gc();)if(n=Pp(epH(r),26),xc(t)===xc(n))return!0;return!1}function ele(e){var t,n,r,i;for(eBW(),n=epE(),r=0,i=n.length;r=65&&e<=70?e-65+10:e>=97&&e<=102?e-97+10:e>=48&&e<=57?e-48:0}function eln(e){var t;return(64&e.Db)!=0?eMT(e):(t=new O1(eMT(e)),t.a+=" (source: ",xk(t,e.d),t.a+=")",t.a)}function elr(e,t,n){var r,i;return i=e.a,e.a=t,(4&e.Db)!=0&&(1&e.Db)==0&&(r=new FX(e,1,5,i,e.a),n?ey7(n,r):n=r),n}function eli(e,t){var n;n=(256&e.Bb)!=0,t?e.Bb|=256:e.Bb&=-257,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,2,n,t))}function ela(e,t){var n;n=(256&e.Bb)!=0,t?e.Bb|=256:e.Bb&=-257,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,8,n,t))}function elo(e,t){var n;n=(256&e.Bb)!=0,t?e.Bb|=256:e.Bb&=-257,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,8,n,t))}function els(e,t){var n;n=(512&e.Bb)!=0,t?e.Bb|=512:e.Bb&=-513,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,3,n,t))}function elu(e,t){var n;n=(512&e.Bb)!=0,t?e.Bb|=512:e.Bb&=-513,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,9,n,t))}function elc(e,t){var n;return -1==e.b&&e.a&&(n=e.a.Gj(),e.b=n?e.c.Xg(e.a.aj(),n):edv(e.c.Tg(),e.a)),e.c.Og(e.b,t)}function ell(e){var t,n;return e>-129&&e<128?(t=e+128,(n=(Rv(),e0B)[t])||(n=e0B[t]=new fC(e)),n):new fC(e)}function elf(e){var t,n;return e>-129&&e<128?(t=e+128,(n=(RU(),e0K)[t])||(n=e0K[t]=new fD(e)),n):new fD(e)}function eld(e){var t,n;return(t=e.k)==(eEn(),e8C)&&((n=Pp(e_k(e,(eBU(),tt1)),61))==(eYu(),tbw)||n==tbj)}function elh(e,t,n){var r,i,a;return(a=i=eMC(e.b,t))&&(r=Pp(eP9(Qq(e,a),""),26))?eMv(e,r,t,n):null}function elp(e,t,n){var r,i,a;return(a=i=eMC(e.b,t))&&(r=Pp(eP9(Qq(e,a),""),26))?eMy(e,r,t,n):null}function elb(e,t){var n,r;for(r=new Ow(e);r.e!=r.i.gc();)if(n=Pp(epH(r),138),xc(t)===xc(n))return!0;return!1}function elm(e,t,n){var r;if(t>(r=e.gc()))throw p7(new Ii(t,r));if(e.hi()&&e.Hc(n))throw p7(new gL(eXB));e.Xh(t,n)}function elg(e,t){var n;if(null==(n=etJ(e.i,t)))throw p7(new gK("Node did not exist in input."));return eiX(t,n),null}function elv(e,t){var n;if(n=eAh(e,t),M4(n,322))return Pp(n,34);throw p7(new gL(eZV+t+"' is not a valid attribute"))}function ely(e,t,n){var r,i;for(r=0,i=M4(t,99)&&(Pp(t,18).Bb&eH3)!=0?new x1(t,e):new eaN(t,e);rt?1:e==t?0==e?elN(1/e,1/t):0:isNaN(e)?isNaN(t)?0:1:-1}function elP(e,t){ewG(t,"Sort end labels",1),_r(UJ(eeh(new R1(null,new Gq(e.b,16)),new t2),new t3),new t4),eEj(t)}function elR(e,t,n){var r,i;return e.ej()?(i=e.fj(),r=exm(e,t,n),e.$i(e.Zi(7,ell(n),r,t,i)),r):exm(e,t,n)}function elj(e,t){var n,r,i;null==e.d?(++e.e,--e.f):(i=t.cd(),r=((n=t.Sh())&eUu)%e.d.length,Xc(e,r,eML(e,r,n,i)))}function elF(e,t){var n;n=(e.Bb&eXt)!=0,t?e.Bb|=eXt:e.Bb&=-1025,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,10,n,t))}function elY(e,t){var n;n=(e.Bb&eH0)!=0,t?e.Bb|=eH0:e.Bb&=-4097,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,12,n,t))}function elB(e,t){var n;n=(e.Bb&eJV)!=0,t?e.Bb|=eJV:e.Bb&=-8193,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,15,n,t))}function elU(e,t){var n;n=(e.Bb&eJq)!=0,t?e.Bb|=eJq:e.Bb&=-2049,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new ZB(e,1,11,n,t))}function elH(e,t){var n;return 0!=(n=elN(e.b.c,t.b.c))||0!=(n=elN(e.a.a,t.a.a))?n:elN(e.a.b,t.a.b)}function el$(e,t){var n;if(null==(n=Bp(e.k,t)))throw p7(new gK("Port did not exist in input."));return eiX(t,n),null}function elz(e){var t,n;for(n=eM$(etP(e)).Kc();n.Ob();)if(eDM(e,t=Lq(n.Pb())))return qb((_X(),tgh),t);return null}function elG(e,t){var n,r,i,a,o;for(i=0,o=eAY(e.e.Tg(),t),a=0,n=Pp(e.g,119);i>10)+eH4&eHd,t[1]=(1023&e)+56320&eHd,ehv(t,0,t.length)}function el0(e){var t,n;return(n=Pp(e_k(e,(eBy(),tal)),103))==(ec3(),tpv)?(t=gP(LV(e_k(e,tiX))))>=1?tpg:tpb:n}function el2(e){switch(Pp(e_k(e,(eBy(),tag)),218).g){case 1:return new ig;case 3:return new iE;default:return new im}}function el3(e){if(e.c)el3(e.c);else if(e.d)throw p7(new gC("Stream already terminated, can't be modified or used"))}function el4(e){var t;return(64&e.Db)!=0?eMT(e):(t=new O1(eMT(e)),t.a+=" (identifier: ",xk(t,e.k),t.a+=")",t.a)}function el5(e,t,n){var r,i;return r=(yT(),i=new oJ),ent(r,t),enn(r,n),e&&JL((e.a||(e.a=new O_(e6h,e,5)),e.a),r),r}function el6(e,t,n,r){var i,a;return BJ(r),BJ(n),null==(a=null==(i=e.xc(t))?n:_i(Pp(i,15),Pp(n,14)))?e.Bc(t):e.zc(t,a),a}function el9(e){var t,n,r,i;return n=(t=Pp(yw((i=(r=e.gm).f)==e1G?r:i),9),new I1(t,Pp(CY(t,t.length),9),0)),erC(n,e),n}function el8(e,t,n){var r,i;for(i=e.a.ec().Kc();i.Ob();)if(r=Pp(i.Pb(),10),eot(n,Pp(RJ(t,r.p),14)))return r;return null}function el7(e,t,n){var r;try{esE(e,t,n)}catch(i){if(i=eoa(i),M4(i,597))throw r=i,p7(new Zt(r));throw p7(i)}return t}function efe(e,t){var n;return Ts(e)&&Ts(t)&&eHV<(n=e-t)&&n>1,e.k=n-1>>1}function efo(){var e,t,n;ewP(),n=e2w+++Date.now(),e=zy(eB4.Math.floor(n*e$h))&e$b,t=zy(n-e*e$p),this.a=1502^e,this.b=t^e$d}function efs(e){var t,n,r;for(t=new p0,r=new fz(e.j);r.a34028234663852886e22?eHQ:t<-34028234663852886e22?eH1:t}function efp(e){return e-=e>>1&1431655765,e=((e=(e>>2&858993459)+(858993459&e))>>4)+e&252645135,e+=e>>8,63&(e+=e>>16)}function efb(e){var t,n,r,i;for(t=new CS(e.Hd().gc()),i=0,r=JJ(e.Hd().Kc());r.Ob();)Gr(t,n=r.Pb(),ell(i++));return eEA(t.a)}function efm(e,t){var n,r,i;for(i=new p2,r=t.vc().Kc();r.Ob();)Um(i,(n=Pp(r.Pb(),42)).cd(),eab(e,Pp(n.dd(),15)));return i}function efg(e,t){0==e.n.c.length&&P_(e.n,new zO(e.s,e.t,e.i)),P_(e.b,t),eml(Pp(RJ(e.n,e.n.c.length-1),211),t),eNk(e,t)}function efv(e){return(e.c!=e.b.b||e.i!=e.g.b)&&(e.a.c=Je(e1R,eUp,1,0,5,1),eoc(e.a,e.b),eoc(e.a,e.g),e.c=e.b.b,e.i=e.g.b),e.a}function efy(e,t){var n,r,i;for(i=0,r=Pp(t.Kb(e),20).Kc();r.Ob();)gN(LK(e_k(n=Pp(r.Pb(),17),(eBU(),tnE))))||++i;return i}function efw(e,t){var n,r,i;i=gP(LV(ed$(r=KT(t),(eBy(),toO)))),ev_(t,n=eB4.Math.max(0,i/2-.5),1),P_(e,new E9(t,n))}function ef_(){ef_=A,tnj=new ST(eGR,0),tnD=new ST("FIRST",1),tnN=new ST(eWi,2),tnP=new ST("LAST",3),tnR=new ST(eWa,4)}function efE(){efE=A,tpO=new kb(ezo,0),tpT=new kb("POLYLINE",1),tpx=new kb("ORTHOGONAL",2),tpM=new kb("SPLINES",3)}function efS(){efS=A,tlP=new S6("ASPECT_RATIO_DRIVEN",0),tlR=new S6("MAX_SCALE_DRIVEN",1),tlN=new S6("AREA_DRIVEN",2)}function efk(){efk=A,tff=new S8("P1_STRUCTURE",0),tfd=new S8("P2_PROCESSING_ORDER",1),tfh=new S8("P3_EXECUTION",2)}function efx(){efx=A,tc1=new S0("OVERLAP_REMOVAL",0),tcJ=new S0("COMPACTION",1),tcQ=new S0("GRAPH_SIZE_CALCULATION",2)}function efT(e,t){return Mc(),enj(eHe),eB4.Math.abs(e-t)<=eHe||e==t||isNaN(e)&&isNaN(t)?0:et?1:Te(isNaN(e),isNaN(t))}function efM(e,t){var n,r;for(n=epL(e,0);n.b!=n.d.c;){if((r=gR(LV(Vv(n))))==t)return;if(r>t){Ks(n);break}}YU(n,t)}function efO(e,t){var n,r,i,a,o;if(n=t.f,epy(e.c.d,n,t),null!=t.g)for(i=t.g,a=0,o=i.length;at&&r.ue(e[a-1],e[a])>0;--a)o=e[a],Bc(e,a,e[a-1]),Bc(e,a-1,o)}function efL(e,t,n,r){if(t<0)eOh(e,n,r);else{if(!n.Ij())throw p7(new gL(eZV+n.ne()+eZq));Pp(n,66).Nj().Tj(e,e.yh(),t,r)}}function efC(e,t){if(t==e.d)return e.e;if(t==e.e)return e.d;throw p7(new gL("Node "+t+" not part of edge "+e))}function efI(e,t){switch(t.g){case 2:return e.b;case 1:return e.c;case 4:return e.d;case 3:return e.a;default:return!1}}function efD(e,t){switch(t.g){case 2:return e.b;case 1:return e.c;case 4:return e.d;case 3:return e.a;default:return!1}}function efN(e,t,n,r){switch(t){case 3:return e.f;case 4:return e.g;case 5:return e.i;case 6:return e.j}return ec2(e,t,n,r)}function efP(e){return e.k==(eEn(),e8N)&&q3(new R1(null,new YI(new Fa(OH(efc(e).a.Kc(),new c)))),new it)}function efR(e){return null==e.e?e:(e.c||(e.c=new eCg((256&e.f)!=0,e.i,e.a,e.d,(16&e.f)!=0,e.j,e.g,null)),e.c)}function efj(e,t){return e.h==eHz&&0==e.m&&0==e.l?(t&&(e0A=Mk(0,0,0)),Tr((Q2(),e0I))):(t&&(e0A=Mk(e.l,e.m,e.h)),Mk(0,0,0))}function efF(e){var t;return Array.isArray(e)&&e.im===O?yx(esF(e))+"@"+(t=esj(e)>>>0).toString(16):e.toString()}function efY(e){var t;this.a=(t=Pp(e.e&&e.e(),9),new I1(t,Pp(CY(t,t.length),9),0)),this.b=Je(e1R,eUp,1,this.a.a.length,5,1)}function efB(e){var t,n,r;for(this.a=new Tw,r=new fz(e);r.a0&&(GV(t-1,e.length),58==e.charCodeAt(t-1))&&!efz(e,tm1,tm0)}function efz(e,t,n){var r,i;for(r=0,i=e.length;r=i)return t.c+n;return t.c+t.b.gc()}function efK(e,t){var n,r,i,a;for(LF(),r=J9(e),i=t,Qe(r,0,r.length,i),n=0;n0&&(r+=i,++n);return n>1&&(r+=e.d*(n-1)),r}function efq(e){var t,n,r;for(r=new vs,r.a+="[",t=0,n=e.gc();t0&&this.b>0&&ji(this.c,this.b,this.a)}function ef4(e){edk(),this.c=ZW(eow(vx(e5Z,1),eUp,831,0,[to2])),this.b=new p2,this.a=e,Um(this.b,to3,1),ety(to4,new h4(this))}function ef5(e,t){var n;return e.d?F9(e.b,t)?Pp(Bp(e.b,t),51):(n=t.Kf(),Um(e.b,t,n),n):t.Kf()}function ef6(e,t){var n;return xc(e)===xc(t)||!!M4(t,91)&&(n=Pp(t,91),e.e==n.e&&e.d==n.d&&qv(e,n.a))}function ef9(e){switch(eYu(),e.g){case 4:return tbw;case 1:return tby;case 3:return tbj;case 2:return tbY;default:return tbF}}function ef8(e,t){switch(t){case 3:return 0!=e.f;case 4:return 0!=e.g;case 5:return 0!=e.i;case 6:return 0!=e.j}return eaT(e,t)}function ef7(e){switch(e.g){case 0:return new aV;case 1:return new aq;default:throw p7(new gL(eqa+(null!=e.f?e.f:""+e.g)))}}function ede(e){switch(e.g){case 0:return new aK;case 1:return new aZ;default:throw p7(new gL(eWt+(null!=e.f?e.f:""+e.g)))}}function edt(e){switch(e.g){case 0:return new mZ;case 1:return new m_;default:throw p7(new gL(eqN+(null!=e.f?e.f:""+e.g)))}}function edn(e){switch(e.g){case 1:return new aU;case 2:return new LY;default:throw p7(new gL(eqa+(null!=e.f?e.f:""+e.g)))}}function edr(e){var t,n;if(e.b)return e.b;for(n=e2M?null:e.d;n;){if(t=e2M?null:n.b)return t;n=e2M?null:n.d}return _g(),e2F}function edi(e){var t,n,r;return 0==e.e?0:(t=e.d<<5,n=e.a[e.d-1],e.e<0&&(r=eiU(e))==e.d-1&&(--n,n|=0),t-=exv(n))}function eda(e){var t,n,r;return e>5,t=31&e,(r=Je(ty_,eHT,25,n+1,15,1))[n]=1<3;)i*=10,--a;e=(e+(i>>1))/i|0}return r.i=e,!0}function edl(e){return euQ(),OQ(),!!(efD(Pp(e.a,81).j,Pp(e.b,103))||0!=Pp(e.a,81).d.e&&efD(Pp(e.a,81).j,Pp(e.b,103)))}function edf(e){J1(),Pp(e.We((eBB(),thL)),174).Hc((eI3(),tb4))&&(Pp(e.We(thJ),174).Fc((ekU(),tbg)),Pp(e.We(thL),174).Mc(tb4))}function edd(e,t){var n,r;if(!t)return!1;for(n=0;n=0;--r)for(i=0,t=n[r];i>1,this.k=t-1>>1}function edC(e,t){ewG(t,"End label post-processing",1),_r(UJ(eeh(new R1(null,new Gq(e.b,16)),new tV),new tq),new tZ),eEj(t)}function edI(e,t,n){var r,i;return r=gP(e.p[t.i.p])+gP(e.d[t.i.p])+t.n.b+t.a.b,(i=gP(e.p[n.i.p])+gP(e.d[n.i.p])+n.n.b+n.a.b)-r}function edD(e,t,n){var r,i;for(i=0,r=WM(n,eH8);0!=ecd(r,0)&&i0&&(GV(0,t.length),43==t.charCodeAt(0))?t.substr(1):t)}function edR(e){var t;return null==e?null:new TU((t=ePh(e,!0)).length>0&&(GV(0,t.length),43==t.charCodeAt(0))?t.substr(1):t)}function edj(e,t){var n;return e.i>0&&(t.lengthe.i&&Bc(t,e.i,null),t}function edF(e,t,n){var r,i,a;return e.ej()?(r=e.i,a=e.fj(),ecW(e,r,t),i=e.Zi(3,null,t,r,a),n?n.Ei(i):n=i):ecW(e,e.i,t),n}function edY(e,t,n){var r,i;return r=new Q$(e.e,4,10,M4(i=t.c,88)?Pp(i,26):(eBK(),tgI),null,ebv(e,t),!1),n?n.Ei(r):n=r,n}function edB(e,t,n){var r,i;return r=new Q$(e.e,3,10,null,M4(i=t.c,88)?Pp(i,26):(eBK(),tgI),ebv(e,t),!1),n?n.Ei(r):n=r,n}function edU(e){var t;return Cn(),t=new TS(Pp(e.e.We((eBB(),thO)),8)),e.B.Hc((eI3(),tbQ))&&(t.a<=0&&(t.a=20),t.b<=0&&(t.b=20)),t}function edH(e){var t;return ebk(),t=(e.q?e.q:(Hj(),Hj(),e2i))._b((eBy(),ta0))?Pp(e_k(e,ta0),197):Pp(e_k(Bq(e),ta2),197)}function ed$(e,t){var n,r;return r=null,Ln(e,(eBy(),toD))&&(n=Pp(e_k(e,toD),94)).Xe(t)&&(r=n.We(t)),null==r&&(r=e_k(Bq(e),t)),r}function edz(e,t){var n,r,i;return!!M4(t,42)&&(r=(n=Pp(t,42)).cd(),i=ecA(e.Rc(),r),BG(i,n.dd())&&(null!=i||e.Rc()._b(r)))}function edG(e,t){var n,r,i;return e.f>0&&(e.qj(),i=((r=null==t?0:esj(t))&eUu)%e.d.length,-1!=(n=eML(e,i,r,t)))}function edW(e,t){var n,r,i;return e.f>0&&(e.qj(),i=((r=null==t?0:esj(t))&eUu)%e.d.length,n=exx(e,i,r,t))?n.dd():null}function edK(e,t){var n,r,i,a;for(i=0,a=eAY(e.e.Tg(),t),n=Pp(e.g,119);i1?WO(Fg(t.a[1],32),WM(t.a[0],eH8)):WM(t.a[0],eH8),Kj(efn(t.e,n))))}function edQ(e,t){var n;return Ts(e)&&Ts(t)&&eHV<(n=e%t)&&n>5,t&=31,r=Je(ty_,eHT,25,i=e.d+n+(0==t?0:1),15,1),ewZ(r,e.a,n,t),a=new F7(e.e,i,r),Ku(a),a}function eht(e,t,n){var r,i;r=Pp(zg(tv4,t),117),i=Pp(zg(tv5,t),117),n?(Ge(tv4,e,r),Ge(tv5,e,i)):(Ge(tv5,e,r),Ge(tv4,e,i))}function ehn(e,t,n){var r,i,a;for(i=null,a=e.b;a;){if(r=e.a.ue(t,a.d),n&&0==r)return a;r>=0?a=a.a[1]:(i=a,a=a.a[0])}return i}function ehr(e,t,n){var r,i,a;for(i=null,a=e.b;a;){if(r=e.a.ue(t,a.d),n&&0==r)return a;r<=0?a=a.a[0]:(i=a,a=a.a[1])}return i}function ehi(e,t,n,r){var i,a,o;return i=!1,ejB(e.f,n,r)&&(epn(e.f,e.a[t][n],e.a[t][r]),o=(a=e.a[t])[r],a[r]=a[n],a[n]=o,i=!0),i}function eha(e,t,n,r,i){var a,o,s;for(o=i;t.b!=t.c;)a=Pp(Yn(t),10),s=Pp(efr(a,r).Xb(0),11),e.d[s.p]=o++,n.c[n.c.length]=s;return o}function eho(e,t,n){var r,i,a,o,s;return o=e.k,s=t.k,i=LV(ed$(e,r=n[o.g][s.g])),a=LV(ed$(t,r)),eB4.Math.max((BJ(i),i),(BJ(a),a))}function ehs(e,t,n){var r,i,a,o;for(r=n/e.c.length,i=0,o=new fz(e);o.a2e3&&(e1X=e,e1J=eB4.setTimeout(wf,10)),0==e1Z++&&(eeA((g1(),e0_)),!0)}function ehf(e,t){var n,r,i;for(r=new Fa(OH(efc(e).a.Kc(),new c));eTk(r);)if((i=(n=Pp(ZC(r),17)).d.i).c==t)return!1;return!0}function ehd(e,t){var n,r;if(M4(t,245)){r=Pp(t,245);try{return n=e.vd(r),0==n}catch(i){if(i=eoa(i),!M4(i,205))throw p7(i)}}return!1}function ehh(){return Error.stackTraceLimit>0?(eB4.Error.stackTraceLimit=Error.stackTraceLimit=64,!0):"stack"in Error()}function ehp(e,t){return Mc(),Mc(),enj(eHe),(eB4.Math.abs(e-t)<=eHe||e==t||isNaN(e)&&isNaN(t)?0:et?1:Te(isNaN(e),isNaN(t)))>0}function ehb(e,t){return Mc(),Mc(),enj(eHe),(eB4.Math.abs(e-t)<=eHe||e==t||isNaN(e)&&isNaN(t)?0:et?1:Te(isNaN(e),isNaN(t)))<0}function ehm(e,t){return Mc(),Mc(),enj(eHe),(eB4.Math.abs(e-t)<=eHe||e==t||isNaN(e)&&isNaN(t)?0:et?1:Te(isNaN(e),isNaN(t)))<=0}function ehg(e,t){for(var n=0;!t[n]||""==t[n];)n++;for(var r=t[n++];neH6)return n.fh();if((r=n.Zg())||n==e)break}return r}function ehA(e){return(z0(),M4(e,156))?Pp(Bp(tmR,e0r),288).vg(e):F9(tmR,esF(e))?Pp(Bp(tmR,esF(e)),288).vg(e):null}function ehL(e){if(ehZ(eq6,e))return OQ(),e0P;if(ehZ(eq9,e))return OQ(),e0N;throw p7(new gL("Expecting true or false"))}function ehC(e,t){if(t.c==e)return t.d;if(t.d==e)return t.c;throw p7(new gL("Input edge is not connected to the input port."))}function ehI(e,t){return e.e>t.e?1:e.et.d?e.e:e.d=48&&e<48+eB4.Math.min(10,10)?e-48:e>=97&&e<97?e-97+10:e>=65&&e<65?e-65+10:-1}function ehN(e,t){var n;return xc(t)===xc(e)||!!M4(t,21)&&(n=Pp(t,21)).gc()==e.gc()&&e.Ic(n)}function ehP(e,t){var n,r,i,a;return(r=e.a.length-1,n=t-e.b&r,a=e.c-t&r,A2(n<(i=e.c-e.b&r)),n>=a)?(euD(e,t),-1):(euN(e,t),1)}function ehR(e,t){var n,r;for(n=(GV(t,e.length),e.charCodeAt(t)),r=t+1;rt.e?1:e.ft.f?1:esj(e)-esj(t)}function ehZ(e,t){return BJ(e),null!=t&&(!!IE(e,t)||e.length==t.length&&IE(e.toLowerCase(),t.toLowerCase()))}function ehX(e,t){var n,r,i,a;for(r=0,i=t.gc();r0&&0>ecd(e,128)?(t=jE(e)+128,(n=(RB(),e0H)[t])||(n=e0H[t]=new fI(e)),n):new fI(e)}function eh1(e,t){var n,r;return(n=t.Hh(e.a))&&null!=(r=Lq(edW((n.b||(n.b=new L_((eBK(),tgF),tgf,n)),n.b),eXP)))?r:t.ne()}function eh0(e,t){var n,r;return(n=t.Hh(e.a))&&null!=(r=Lq(edW((n.b||(n.b=new L_((eBK(),tgF),tgf,n)),n.b),eXP)))?r:t.ne()}function eh2(e,t){var n,r;for(Gk(),r=new Fa(OH(efs(e).a.Kc(),new c));eTk(r);)if((n=Pp(ZC(r),17)).d.i==t||n.c.i==t)return n;return null}function eh3(e,t,n){this.c=e,this.f=new p0,this.e=new yb,this.j=new R$,this.n=new R$,this.b=t,this.g=new Hr(t.c,t.d,t.b,t.a),this.a=n}function eh4(e){var t,n,r,i;for(r=0,this.a=new Tw,this.d=new bV,this.e=0,i=(n=e).length;r0)}function ept(e){var t;xc(eT8(e,(eBB(),thl)))===xc((eck(),tpG))&&(z$(e)?(t=Pp(eT8(z$(e),thl),334),ebu(e,thl,t)):ebu(e,thl,tpW))}function epn(e,t,n){var r,i;e_m(e.e,t,n,(eYu(),tbY)),e_m(e.i,t,n,tby),e.a&&(i=Pp(e_k(t,(eBU(),tnc)),11),r=Pp(e_k(n,tnc),11),WW(e.g,i,r))}function epr(e,t,n){var r,i,a;r=t.c.p,a=t.p,e.b[r][a]=new $j(e,t),n&&(e.a[r][a]=new hv(t),(i=Pp(e_k(t,(eBU(),tt8)),10))&&exg(e.d,i,t))}function epi(e,t){var n,r,i;if(P_(e9n,e),t.Fc(e),n=Pp(Bp(e9t,e),21))for(i=n.Kc();i.Ob();)-1!=QI(e9n,r=Pp(i.Pb(),33),0)||epi(r,t)}function epa(e,t,n){var r;(e2x?(edr(e),0):e2T?(_g(),0):e2A?(_g(),0):!e2O||(_g(),1))||((r=new I6(t)).b=n,eEt(e,r))}function epo(e,t){var n;n=!e.A.Hc((ed6(),tbq))||e.q==(ewf(),tbo),e.u.Hc((ekU(),tbp))?n?eY_(e,t):eF3(e,t):e.u.Hc(tbm)&&(n?eFO(e,t):eYY(e,t))}function eps(e,t){var n,r;if(++e.j,null!=t&&exM(t,n=M4(r=e.a.Cb,97)?Pp(r,97).Jg():null)){ehU(e.a,4,n);return}ehU(e.a,4,Pp(t,126))}function epu(e,t,n){return new Hr(eB4.Math.min(e.a,t.a)-n/2,eB4.Math.min(e.b,t.b)-n/2,eB4.Math.abs(e.a-t.a)+n,eB4.Math.abs(e.b-t.b)+n)}function epc(e,t){var n,r;return 0!=(n=ME(e.a.c.p,t.a.c.p))?n:0!=(r=ME(e.a.d.i.p,t.a.d.i.p))?r:ME(t.a.d.p,e.a.d.p)}function epl(e,t,n){var r,i,a,o;return(a=t.j)!=(o=n.j)?a.g-o.g:(r=e.f[t.p],i=e.f[n.p],0==r&&0==i?0:0==r?-1:0==i?1:elN(r,i))}function epf(e,t,n){var r,i,a;if(!n[t.d])for(n[t.d]=!0,i=new fz(efv(t));i.a=(i=e.length))return i;for(t=t>0?t:0;tr&&Bc(t,r,null),t}function epv(e,t){var n,r;for(r=e.a.length,t.lengthr&&Bc(t,r,null),t}function epy(e,t,n){var r,i,a;return(i=Pp(Bp(e.e,t),387))?(a=CL(i,n),M6(e,i),a):(r=new PM(e,t,n),Um(e.e,t,r),zd(r),null)}function epw(e){var t;if(null==e)return null;if(null==(t=eMI(ePh(e,!0))))throw p7(new gV("Invalid hexBinary value: '"+e+"'"));return t}function ep_(e){return(eLQ(),0>ecd(e,0))?0!=ecd(e,-1)?new ey$(-1,QC(e)):e03:0>=ecd(e,10)?e05[jE(e)]:new ey$(1,e)}function epE(){return eBW(),eow(vx(e3n,1),eU4,159,0,[e4e,e37,e4t,e30,e31,e32,e35,e34,e33,e38,e39,e36,e3J,e3X,e3Q,e3q,e3V,e3Z,e3W,e3G,e3K,e4n])}function epS(e){var t;this.d=new p0,this.j=new yb,this.g=new yb,t=e.g.b,this.f=Pp(e_k(Bq(t),(eBy(),tal)),103),this.e=gP(LV(epj(t,toN)))}function epk(e){this.b=new p0,this.e=new p0,this.d=e,this.a=!yK(UJ(new R1(null,new YI(new Z4(e.b))),new f2(new ir))).sd((_w(),e2z))}function epx(){epx=A,tdh=new ko("PARENTS",0),tdd=new ko("NODES",1),tdl=new ko("EDGES",2),tdp=new ko("PORTS",3),tdf=new ko("LABELS",4)}function epT(){epT=A,tbt=new kw("DISTRIBUTED",0),tbr=new kw("JUSTIFIED",1),tp7=new kw("BEGIN",2),tbe=new kw(e$8,3),tbn=new kw("END",4)}function epM(e){var t;switch(t=e.yi(null)){case 10:return 0;case 15:return 1;case 14:return 2;case 11:return 3;case 21:return 4}return -1}function epO(e){switch(e.g){case 1:return ec3(),tpy;case 4:return ec3(),tpm;case 2:return ec3(),tpg;case 3:return ec3(),tpb}return ec3(),tpv}function epA(e,t,n){var r;switch((r=n.q.getFullYear()-eHx+eHx)<0&&(r=-r),t){case 1:e.a+=r;break;case 2:eeE(e,r%100,2);break;default:eeE(e,r,t)}}function epL(e,t){var n,r;if(Gp(t,e.b),t>=e.b>>1)for(r=e.c,n=e.b;n>t;--n)r=r.b;else for(n=0,r=e.a.a;n=64&&t<128&&(i=WO(i,Fg(1,t-64)));return i}function epj(e,t){var n,r;return r=null,Ln(e,(eBB(),tpa))&&(n=Pp(e_k(e,tpa),94)).Xe(t)&&(r=n.We(t)),null==r&&Bq(e)&&(r=e_k(Bq(e),t)),r}function epF(e,t){var n,r,i;(r=(i=t.d.i).k)!=(eEn(),e8N)&&r!=e8L&&(n=new Fa(OH(efc(i).a.Kc(),new c)),eTk(n)&&Um(e.k,t,Pp(ZC(n),17)))}function epY(e,t){var n,r,i;return r=ee2(e.Tg(),t),(n=t-e.Ah())<0?(i=e.Yg(r))>=0?e.lh(i):exu(e,r):n<0?exu(e,r):Pp(r,66).Nj().Sj(e,e.yh(),n)}function epB(e){var t;if(!M4(e.a,4))return e.a;if(null==(t=ehA(e.a)))throw p7(new gC(eq8+e.b+"'. "+eq4+(LW(e6D),e6D.k)+eq5));return t}function epU(e){var t;if(null==e)return null;if(null==(t=eYD(ePh(e,!0))))throw p7(new gV("Invalid base64Binary value: '"+e+"'"));return t}function epH(e){var t;try{return t=e.i.Xb(e.e),e.mj(),e.g=e.e++,t}catch(n){if(n=eoa(n),M4(n,73))throw e.mj(),p7(new bC);throw p7(n)}}function ep$(e){var t;try{return t=e.c.ki(e.e),e.mj(),e.g=e.e++,t}catch(n){if(n=eoa(n),M4(n,73))throw e.mj(),p7(new bC);throw p7(n)}}function epz(){epz=A,e67=(eBB(),tpt),e63=ths,e6J=td2,e64=thN,e69=(evw(),e3y),e66=e3g,e68=e3_,e65=e3m,e61=(eug(),e6V),e6Q=e6K,e60=e6Z,e62=e6X}function epG(e){switch(_M(),this.c=new p0,this.d=e,e.g){case 0:case 2:this.a=Ug(e8_),this.b=eHQ;break;case 3:case 1:this.a=e8_,this.b=eH1}}function epW(e,t,n){var r,i;if(e.c)eno(e.c,e.c.i+t),ens(e.c,e.c.j+n);else for(i=new fz(e.b);i.a0&&(P_(e.b,new PE(t.a,n)),0<(r=t.a.length)?t.a=t.a.substr(0,0):0>r&&(t.a+=M3(Je(tyw,eHl,25,-r,15,1))))}function epq(e,t){var n,r,i;for(n=e.o,i=Pp(Pp(Zq(e.r,t),21),84).Kc();i.Ob();)(r=Pp(i.Pb(),111)).e.a=ego(r,n.a),r.e.b=n.b*gP(LV(r.b.We(e4a)))}function epZ(e,t){var n,r,i,a;return i=e.k,n=gP(LV(e_k(e,(eBU(),tnv)))),a=t.k,r=gP(LV(e_k(t,tnv))),a!=(eEn(),e8C)?-1:i!=e8C?1:n==r?0:n=0?e.hh(t,n,r):(e.eh()&&(r=(i=e.Vg())>=0?e.Qg(r):e.eh().ih(e,-1-i,null,r)),e.Sg(t,n,r))}function ep2(e,t){switch(t){case 7:e.e||(e.e=new Ih(e6g,e,7,4)),eRT(e.e);return;case 8:e.d||(e.d=new Ih(e6g,e,8,5)),eRT(e.d);return}edS(e,t)}function ep3(e,t){var n;n=e.Zc(t);try{return n.Pb()}catch(r){if(r=eoa(r),M4(r,109))throw p7(new gE("Can't get element "+t));throw p7(r)}}function ep4(e,t){this.e=e,t=0&&(n.d=e.t);break;case 3:e.t>=0&&(n.a=e.t)}e.C&&(n.b=e.C.b,n.c=e.C.c)}function ep7(){ep7=A,e4d=new EN(ezb,0),e4f=new EN(ezm,1),e4h=new EN(ezg,2),e4p=new EN(ezv,3),e4d.a=!1,e4f.a=!0,e4h.a=!1,e4p.a=!0}function ebe(){ebe=A,e6U=new ED(ezb,0),e6B=new ED(ezm,1),e6H=new ED(ezg,2),e6$=new ED(ezv,3),e6U.a=!1,e6B.a=!0,e6H.a=!1,e6$.a=!0}function ebt(e){var t;t=e.a;do(t=Pp(ZC(new Fa(OH(efu(t).a.Kc(),new c))),17).c.i).k==(eEn(),e8D)&&e.b.Fc(t);while(t.k==(eEn(),e8D))e.b=eaa(e.b)}function ebn(e){var t,n,r;for(r=e.c.a,e.p=(Y9(r),new I4(r)),n=new fz(r);n.an.b))}function ebs(e,t){return xd(e)?!!e0c[t]:e.hm?!!e.hm[t]:xf(e)?!!e0u[t]:!!xl(e)&&!!e0s[t]}function ebu(e,t,n){return null==n?(e.o||(e.o=new JY((eBa(),tmy),e6O,e,0)),ehx(e.o,t)):(e.o||(e.o=new JY((eBa(),tmy),e6O,e,0)),evQ(e.o,t,n)),e}function ebc(e,t,n,r){var i,a;a=t.Xe((eBB(),thS))?Pp(t.We(thS),21):e.j,(i=ele(a))!=(eBW(),e4n)&&(!n||ehj(i))&&eEU(eMD(e,i,r),t)}function ebl(e,t,n,r){var i,a,o;return a=ee2(e.Tg(),t),(i=t-e.Ah())<0?(o=e.Yg(a))>=0?e._g(o,n,!0):exk(e,a,n):Pp(a,66).Nj().Pj(e,e.yh(),i,n,r)}function ebf(e,t,n,r){var i,a,o;n.mh(t)&&(_4(),eec(t)?ehX(e,i=Pp(n.ah(t),153)):(a=(o=t)?Pp(r,49).xh(o):null)&&p6(n.ah(t),a))}function ebd(e){switch(e.g){case 1:return eaY(),e4c;case 3:return eaY(),e4o;case 2:return eaY(),e4u;case 4:return eaY(),e4s;default:return null}}function ebh(e){switch(typeof e){case eUo:return ebA(e);case eUa:return zy(e);case eUi:return OQ(),e?1231:1237;default:return null==e?0:Ao(e)}}function ebp(e,t,n){if(e.e)switch(e.b){case 1:HJ(e.c,t,n);break;case 0:HQ(e.c,t,n)}else V6(e.c,t,n);e.a[t.p][n.p]=e.c.i,e.a[n.p][t.p]=e.c.e}function ebb(e){var t,n;if(null==e)return null;for(t=0,n=Je(e4N,eUP,193,e.length,0,2);t=0)return i;if(e.Fk()){for(r=0;r=(i=e.gc()))throw p7(new Ii(t,i));if(e.hi()&&(r=e.Xc(n))>=0&&r!=t)throw p7(new gL(eXB));return e.mi(t,n)}function ebw(e,t){if(this.a=Pp(Y9(e),245),this.b=Pp(Y9(t),245),e.vd(t)>0||e==(m3(),e0f)||t==(m2(),e0d))throw p7(new gL("Invalid range: "+VW(e,t)))}function eb_(e){var t,n;for(this.b=new p0,this.c=e,this.a=!1,n=new fz(e.a);n.a0),(t&-t)==t)return zy(t*eMU(e,31)*4656612873077393e-25);do r=(n=eMU(e,31))%t;while(n-r+(t-1)<0)return zy(r)}function ebA(e){var t,n,r;return(I9(),null!=(r=e2W[n=":"+e]))?zy((BJ(r),r)):(t=null==(r=e2G[n])?eAC(e):zy((BJ(r),r)),HB(),e2W[n]=t,t)}function ebL(e,t,n){ewG(n,"Compound graph preprocessor",1),e.a=new zu,eFC(e,t,null),eRs(e,t),eOz(e),eo3(t,(eBU(),ttW),e.a),e.a=null,Yy(e.b),eEj(n)}function ebC(e,t,n){switch(n.g){case 1:e.a=t.a/2,e.b=0;break;case 2:e.a=t.a,e.b=t.b/2;break;case 3:e.a=t.a/2,e.b=t.b;break;case 4:e.a=0,e.b=t.b/2}}function ebI(e){var t,n,r;for(r=Pp(Zq(e.a,(ey4(),tea)),15).Kc();r.Ob();)t=egD(n=Pp(r.Pb(),101)),Yz(e,n,t[0],(erX(),ted),0),Yz(e,n,t[1],tep,1)}function ebD(e){var t,n,r;for(r=Pp(Zq(e.a,(ey4(),teo)),15).Kc();r.Ob();)t=egD(n=Pp(r.Pb(),101)),Yz(e,n,t[0],(erX(),ted),0),Yz(e,n,t[1],tep,1)}function ebN(e){switch(e.g){case 0:return null;case 1:return new er1;case 2:return new mQ;default:throw p7(new gL(eqa+(null!=e.f?e.f:""+e.g)))}}function ebP(e,t,n){var r,i;for(eod(e,t-e.s,n-e.t),i=new fz(e.n);i.a1&&(a=ebE(e,t)),a}function ebj(e){var t;return e.f&&e.f.kh()&&(t=Pp(e.f,49),e.f=Pp(ecv(e,t),82),e.f!=t&&(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,9,8,t,e.f))),e.f}function ebF(e){var t;return e.i&&e.i.kh()&&(t=Pp(e.i,49),e.i=Pp(ecv(e,t),82),e.i!=t&&(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,9,7,t,e.i))),e.i}function ebY(e){var t;return e.b&&(64&e.b.Db)!=0&&(t=e.b,e.b=Pp(ecv(e,t),18),e.b!=t&&(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,9,21,t,e.b))),e.b}function ebB(e,t){var n,r,i;null==e.d?(++e.e,++e.f):(r=t.Sh(),eO1(e,e.f+1),i=(r&eUu)%e.d.length,(n=e.d[i])||(n=e.d[i]=e.uj()),n.Fc(t),++e.f)}function ebU(e,t,n){var r;return!t.Kj()&&(-2!=t.Zj()?null==(r=t.zj())?null==n:ecX(r,n):t.Hj()==e.e.Tg()&&null==n)}function ebH(){var e;enG(16,eU0),e=er_(16),this.b=Je(e1z,eU1,317,e,0,1),this.c=Je(e1z,eU1,317,e,0,1),this.a=null,this.e=null,this.i=0,this.f=e-1,this.g=0}function eb$(e){CW.call(this),this.k=(eEn(),e8N),this.j=(enG(6,eU3),new XM(6)),this.b=(enG(2,eU3),new XM(2)),this.d=new md,this.f=new mb,this.a=e}function ebz(e){var t,n;!(e.c.length<=1)&&(t=eLW(e,(eYu(),tbj)),eSe(e,Pp(t.a,19).a,Pp(t.b,19).a),n=eLW(e,tbY),eSe(e,Pp(n.a,19).a,Pp(n.b,19).a))}function ebG(){ebG=A,tsb=new Sx("SIMPLE",0),tsd=new Sx(eWg,1),tsh=new Sx("LINEAR_SEGMENTS",2),tsf=new Sx("BRANDES_KOEPF",3),tsp=new Sx(eVI,4)}function ebW(e,t,n){IR(Pp(e_k(t,(eBy(),tol)),98))||(Q3(e,t,eEC(t,n)),Q3(e,t,eEC(t,(eYu(),tbj))),Q3(e,t,eEC(t,tbw)),Hj(),Mv(t.j,new hm(e)))}function ebK(e,t,n,r){var i,a,o;for(o=(i=r?Pp(Zq(e.a,t),21):Pp(Zq(e.b,t),21)).Kc();o.Ob();)if(eL8(e,n,a=Pp(o.Pb(),33)))return!0;return!1}function ebV(e){var t,n;for(n=new Ow(e);n.e!=n.i.gc();)if((t=Pp(epH(n),87)).e||0!=(t.d||(t.d=new O_(tgr,t,1)),t.d).i)return!0;return!1}function ebq(e){var t,n;for(n=new Ow(e);n.e!=n.i.gc();)if((t=Pp(epH(n),87)).e||0!=(t.d||(t.d=new O_(tgr,t,1)),t.d).i)return!0;return!1}function ebZ(e){var t,n,r;for(t=0,r=new fz(e.c.a);r.a102?-1:e<=57?e-48:e<65?-1:e<=70?e-65+10:e<97?-1:e-97+10}function eb2(e,t){if(null==e)throw p7(new gD("null key in entry: null="+t));if(null==t)throw p7(new gD("null value in entry: "+e+"=null"))}function eb3(e,t){for(var n,r;e.Ob();)if(!t.Ob()||(n=e.Pb(),r=t.Pb(),!(xc(n)===xc(r)||null!=n&&ecX(n,r))))return!1;return!t.Ob()}function eb4(e,t){var n;return n=eow(vx(tyx,1),eH5,25,15,[euG(e.a[0],t),euG(e.a[1],t),euG(e.a[2],t)]),e.d&&(n[0]=eB4.Math.max(n[0],n[2]),n[2]=n[0]),n}function eb5(e,t){var n;return n=eow(vx(tyx,1),eH5,25,15,[euW(e.a[0],t),euW(e.a[1],t),euW(e.a[2],t)]),e.d&&(n[0]=eB4.Math.max(n[0],n[2]),n[2]=n[0]),n}function eb6(){eb6=A,teG=new Sf("GREEDY",0),tez=new Sf(eWv,1),teK=new Sf(eWg,2),teV=new Sf("MODEL_ORDER",3),teW=new Sf("GREEDY_MODEL_ORDER",4)}function eb9(e,t){var n,r,i;for(e.b[t.g]=1,r=epL(t.d,0);r.b!=r.d.c;)i=(n=Pp(Vv(r),188)).c,1==e.b[i.g]?P7(e.a,n):2==e.b[i.g]?e.b[i.g]=1:eb9(e,i)}function eb8(e,t){var n,r,i;for(i=new XM(t.gc()),r=t.Kc();r.Ob();)(n=Pp(r.Pb(),286)).c==n.f?eE5(e,n,n.c):eEQ(e,n)||(i.c[i.c.length]=n);return i}function eb7(e,t,n){var r,i,a,o,s;for(s=e.r+t,e.r+=t,e.d+=n,r=n/e.n.c.length,i=0,o=new fz(e.n);o.aa&&Bc(t,a,null),t}function emx(e,t){var n,r;if(r=e.gc(),null==t){for(n=0;n0&&(u+=i),c[l]=o,o+=s*(u+r)}function emj(e){var t,n,r;for(t=0,r=e.f,e.n=Je(tyx,eH5,25,r,15,1),e.d=Je(tyx,eH5,25,r,15,1);t0?e.c:0),++i;e.b=r,e.d=a}function emW(e,t){var n,r,i,a,o;for(r=0,i=0,n=0,o=new fz(t);o.a0?e.g:0),++n;e.c=i,e.d=r}function emK(e,t){var n;return n=eow(vx(tyx,1),eH5,25,15,[ebM(e,(etx(),e3D),t),ebM(e,e3N,t),ebM(e,e3P,t)]),e.f&&(n[0]=eB4.Math.max(n[0],n[2]),n[2]=n[0]),n}function emV(e,t,n){var r;try{eCQ(e,t+e.j,n+e.k,!1,!0)}catch(i){if(i=eoa(i),M4(i,73))throw r=i,p7(new gE(r.g+ezk+t+eUd+n+")."));throw p7(i)}}function emq(e,t,n){var r;try{eCQ(e,t+e.j,n+e.k,!0,!1)}catch(i){if(i=eoa(i),M4(i,73))throw r=i,p7(new gE(r.g+ezk+t+eUd+n+")."));throw p7(i)}}function emZ(e){var t;Ln(e,(eBy(),taZ))&&((t=Pp(e_k(e,taZ),21)).Hc((eT7(),tp1))?(t.Mc(tp1),t.Fc(tp2)):t.Hc(tp2)&&(t.Mc(tp2),t.Fc(tp1)))}function emX(e){var t;Ln(e,(eBy(),taZ))&&((t=Pp(e_k(e,taZ),21)).Hc((eT7(),tp9))?(t.Mc(tp9),t.Fc(tp5)):t.Hc(tp5)&&(t.Mc(tp5),t.Fc(tp9)))}function emJ(e,t,n){ewG(n,"Self-Loop ordering",1),_r(UQ(UJ(UJ(eeh(new R1(null,new Gq(t.b,16)),new n9),new n8),new n7),new re),new d1(e)),eEj(n)}function emQ(e,t,n,r){var i,a;for(i=t;i0&&(i.b+=t),i}function em8(e,t){var n,r,i;for(i=new yb,r=e.Kc();r.Ob();)eIn(n=Pp(r.Pb(),37),0,i.b),i.b+=n.f.b+t,i.a=eB4.Math.max(i.a,n.f.a);return i.a>0&&(i.a+=t),i}function em7(e){var t,n,r;for(r=eUu,n=new fz(e.a);n.a>16==6?e.Cb.ih(e,5,e6E,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||e.zh(),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function egr(e){$O();var t=e.e;if(t&&t.stack){var n=t.stack,r=t+"\n";return n.substring(0,r.length)==r&&(n=n.substring(r.length)),n.split("\n")}return[]}function egi(e){var t;return(t=(en4(),e0U))[e>>>28]|t[e>>24&15]<<4|t[e>>20&15]<<8|t[e>>16&15]<<12|t[e>>12&15]<<16|t[e>>8&15]<<20|t[e>>4&15]<<24|t[15&e]<<28}function ega(e){var t,n,r;e.b==e.c&&(r=e.a.length,n=esi(eB4.Math.max(8,r))<<1,0!=e.b?(t=CY(e.a,n),erL(e,t,r),e.a=t,e.b=0):bF(e.a,n),e.c=r)}function ego(e,t){var n;return(n=e.b).Xe((eBB(),thK))?n.Hf()==(eYu(),tbY)?-n.rf().a-gP(LV(n.We(thK))):t+gP(LV(n.We(thK))):n.Hf()==(eYu(),tbY)?-n.rf().a:t}function egs(e){var t;return 0!=e.b.c.length&&Pp(RJ(e.b,0),70).a?Pp(RJ(e.b,0),70).a:null!=(t=Hh(e))?t:""+(e.c?QI(e.c.a,e,0):-1)}function egu(e){var t;return 0!=e.f.c.length&&Pp(RJ(e.f,0),70).a?Pp(RJ(e.f,0),70).a:null!=(t=Hh(e))?t:""+(e.i?QI(e.i.j,e,0):-1)}function egc(e,t){var n,r;if(t<0||t>=e.gc())return null;for(n=t;n0?e.c:0),i=eB4.Math.max(i,t.d),++r;e.e=a,e.b=i}function egd(e){var t,n;if(!e.b)for(e.b=K$(Pp(e.f,118).Ag().i),n=new Ow(Pp(e.f,118).Ag());n.e!=n.i.gc();)t=Pp(epH(n),137),P_(e.b,new gO(t));return e.b}function egh(e,t){var n,r,i;if(t.dc())return LF(),LF(),tmB;for(n=new Cy(e,t.gc()),i=new Ow(e);i.e!=i.i.gc();)r=epH(i),t.Hc(r)&&JL(n,r);return n}function egp(e,t,n,r){return 0==t?r?(e.o||(e.o=new JY((eBa(),tmy),e6O,e,0)),e.o):(e.o||(e.o=new JY((eBa(),tmy),e6O,e,0)),X6(e.o)):ebl(e,t,n,r)}function egb(e){var t,n;if(e.rb)for(t=0,n=e.rb.i;t>22))>>22)<0)&&(e.l=n&eHH,e.m=r&eHH,e.h=i&eH$,!0))}function egw(e,t,n,r,i,a,o){var s,u;return!(t.Ae()&&((u=e.a.ue(n,r))<0||!i&&0==u)||t.Be()&&((s=e.a.ue(n,a))>0||!o&&0==s))}function eg_(e,t){var n;if(euv(),0!=(n=e.j.g-t.j.g))return 0;switch(e.j.g){case 2:return efy(t,e73)-efy(e,e73);case 4:return efy(e,e72)-efy(t,e72)}return 0}function egE(e){switch(e.g){case 0:return te3;case 1:return te4;case 2:return te5;case 3:return te6;case 4:return te9;case 5:return te8;default:return null}}function egS(e,t,n){var r,i;return r=(eu2(i=new mN,t),er3(i,n),JL((e.c||(e.c=new FQ(tga,e,12,10)),e.c),i),i),end(r,0),enh(r,1),els(r,!0),eli(r,!0),r}function egk(e,t){var n,r;if(t>=e.i)throw p7(new xJ(t,e.i));return++e.j,n=e.g[t],(r=e.i-t-1)>0&&ePD(e.g,t+1,e.g,t,r),Bc(e.g,--e.i,null),e.fi(t,n),e.ci(),n}function egx(e,t){var n,r;return e.Db>>16==17?e.Cb.ih(e,21,tm7,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||e.zh(),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function egT(e){var t,n,r,i;for(Hj(),Mv(e.c,e.a),i=new fz(e.c);i.an.a.c.length))throw p7(new gL("index must be >= 0 and <= layer node count"));e.c&&QA(e.c.a,e),e.c=n,n&&jO(n.a,t,e)}function egH(e,t){var n,r,i;for(r=new Fa(OH(efs(e).a.Kc(),new c));eTk(r);)return n=Pp(ZC(r),17),i=Pp(t.Kb(n),10),new c5(Y9(i.n.b+i.o.b/2));return m4(),m4(),e0l}function eg$(e,t){this.c=new p2,this.a=e,this.b=t,this.d=Pp(e_k(e,(eBU(),tnx)),304),xc(e_k(e,(eBy(),taX)))===xc((Qx(),tte))?this.e=new mg:this.e=new mm}function egz(e,t){var n,r,i,a;for(a=0,r=new fz(e);r.a>16==6?e.Cb.ih(e,6,e6g,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBa(),tmp),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function eg0(e,t){var n,r;return e.Db>>16==7?e.Cb.ih(e,1,e6p,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBa(),tmm),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function eg2(e,t){var n,r;return e.Db>>16==9?e.Cb.ih(e,9,e6k,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBa(),tmv),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function eg3(e,t){var n,r;return e.Db>>16==5?e.Cb.ih(e,9,tgt,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBK(),tgT),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function eg4(e,t){var n,r;return e.Db>>16==3?e.Cb.ih(e,0,e6y,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBK(),tgy),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function eg5(e,t){var n,r;return e.Db>>16==7?e.Cb.ih(e,6,e6E,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBK(),tgP),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function eg6(){this.a=new o6,this.g=new ebH,this.j=new ebH,this.b=new p2,this.d=new ebH,this.i=new ebH,this.k=new p2,this.c=new p2,this.e=new p2,this.f=new p2}function eg9(e,t,n){var r,i,a;for(n<0&&(n=0),a=e.i,i=n;ieH6)return eg7(e,r);if(r==e)return!0}}return!1}function eve(e){switch(Ab(),e.q.g){case 5:ekK(e,(eYu(),tbw)),ekK(e,tbj);break;case 4:eMz(e,(eYu(),tbw)),eMz(e,tbj);break;default:eYa(e,(eYu(),tbw)),eYa(e,tbj)}}function evt(e){switch(Ab(),e.q.g){case 5:exG(e,(eYu(),tby)),exG(e,tbY);break;case 4:epq(e,(eYu(),tby)),epq(e,tbY);break;default:eYo(e,(eYu(),tby)),eYo(e,tbY)}}function evn(e){var t,n;(t=Pp(e_k(e,(eCk(),e9O)),19))?0==(n=t.a)?eo3(e,(erV(),e9F),new efo):eo3(e,(erV(),e9F),new qS(n)):eo3(e,(erV(),e9F),new qS(1))}function evr(e,t){var n;switch(n=e.i,t.g){case 1:return-(e.n.b+e.o.b);case 2:return e.n.a-n.o.a;case 3:return e.n.b-n.o.b;case 4:return-(e.n.a+e.o.a)}return 0}function evi(e,t){switch(e.g){case 0:return t==(ef_(),tnN)?e7V:e7q;case 1:return t==(ef_(),tnN)?e7V:e7K;case 2:return t==(ef_(),tnN)?e7K:e7q;default:return e7K}}function eva(e,t){var n,r,i;for(QA(e.a,t),e.e-=t.r+(0==e.a.c.length?0:e.c),i=eqe,r=new fz(e.a);r.a>16==3?e.Cb.ih(e,12,e6k,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBa(),tmh),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function evs(e,t){var n,r;return e.Db>>16==11?e.Cb.ih(e,10,e6k,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBa(),tmg),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function evu(e,t){var n,r;return e.Db>>16==10?e.Cb.ih(e,11,tm7,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBK(),tgD),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function evc(e,t){var n,r;return e.Db>>16==10?e.Cb.ih(e,12,tgi,t):(r=ebY(Pp(ee2((n=Pp(eaS(e,16),26))||(eBK(),tgR),e.Db>>16),18)),e.Cb.ih(e,r.n,r.f,t))}function evl(e){var t;return(1&e.Bb)==0&&e.r&&e.r.kh()&&(t=Pp(e.r,49),e.r=Pp(ecv(e,t),138),e.r!=t&&(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,9,8,t,e.r))),e.r}function evf(e,t,n){var r;return r=eow(vx(tyx,1),eH5,25,15,[e_u(e,(etx(),e3D),t,n),e_u(e,e3N,t,n),e_u(e,e3P,t,n)]),e.f&&(r[0]=eB4.Math.max(r[0],r[2]),r[2]=r[0]),r}function evd(e,t){var n,r,i;if(0!=(i=eb8(e,t)).c.length)for(Mv(i,new nD),n=i.c.length,r=0;r>19)!=(c=t.h>>19)?c-u:(i=e.h)!=(s=t.h)?i-s:(r=e.m)!=(o=t.m)?r-o:(n=e.l)-(a=t.l)}function evw(){evw=A,e3E=(eCp(),e3A),e3_=new xX(e$J,e3E),e3w=(eeR(),e3p),e3y=new xX(e$Q,e3w),e3v=(epC(),e3f),e3g=new xX(e$1,e3v),e3m=new xX(e$0,(OQ(),!0))}function ev_(e,t,n){var r,i;r=t*n,M4(e.g,145)?(i=Vm(e)).f.d?i.f.a||(e.d.a+=r+ezs):(e.d.d-=r+ezs,e.d.a+=r+ezs):M4(e.g,10)&&(e.d.d-=r,e.d.a+=2*r)}function evE(e,t,n){var r,i,a,o,s;for(i=e[n.g],s=new fz(t.d);s.a0?e.g:0),++n;t.b=r,t.e=i}function evk(e){var t,n,r;if(r=e.b,w4(e.i,r.length)){for(n=2*r.length,e.b=Je(e1z,eU1,317,n,0,1),e.c=Je(e1z,eU1,317,n,0,1),e.f=n-1,e.i=0,t=e.a;t;t=t.c)ekT(e,t,t);++e.g}}function evx(e,t,n,r){var i,a,o,s;for(i=0;io&&(s=o/r),i>a&&(u=a/i),Ol(e,eB4.Math.min(s,u)),e}function evO(){var e,t;ePm();try{if(t=Pp(eyv((_Q(),tgp),eXe),2014))return t}catch(n){if(n=eoa(n),M4(n,102))e=n,Fi((Mo(),e));else throw p7(n)}return new o1}function evA(){var e,t;Qk();try{if(t=Pp(eyv((_Q(),tgp),eQB),2024))return t}catch(n){if(n=eoa(n),M4(n,102))e=n,Fi((Mo(),e));else throw p7(n)}return new uc}function evL(){var e,t;ePm();try{if(t=Pp(eyv((_Q(),tgp),eQc),1941))return t}catch(n){if(n=eoa(n),M4(n,102))e=n,Fi((Mo(),e));else throw p7(n)}return new sT}function evC(e,t,n){var r,i;return i=e.e,e.e=t,(4&e.Db)!=0&&(1&e.Db)==0&&(r=new FX(e,1,4,i,t),n?n.Ei(r):n=r),i!=t&&(n=t?eFr(e,eOl(e,t),n):eFr(e,e.a,n)),n}function evI(){wW.call(this),this.e=-1,this.a=!1,this.p=eHt,this.k=-1,this.c=-1,this.b=-1,this.g=!1,this.f=-1,this.j=-1,this.n=-1,this.i=-1,this.d=-1,this.o=eHt}function evD(e,t){var n,r,i;if(r=e.b.d.d,e.a||(r+=e.b.d.a),i=t.b.d.d,t.a||(i+=t.b.d.a),0==(n=elN(r,i))){if(!e.a&&t.a)return -1;if(!t.a&&e.a)return 1}return n}function evN(e,t){var n,r,i;if(r=e.b.b.d,e.a||(r+=e.b.b.a),i=t.b.b.d,t.a||(i+=t.b.b.a),0==(n=elN(r,i))){if(!e.a&&t.a)return -1;if(!t.a&&e.a)return 1}return n}function evP(e,t){var n,r,i;if(r=e.b.g.d,e.a||(r+=e.b.g.a),i=t.b.g.d,t.a||(i+=t.b.g.a),0==(n=elN(r,i))){if(!e.a&&t.a)return -1;if(!t.a&&e.a)return 1}return n}function evR(){evR=A,e99=j0(RI(RI(RI(new K2,(e_x(),e8r),(eB$(),e7f)),e8r,e7b),e8i,e7E),e8i,e87),e97=RI(RI(new K2,e8r,e8Q),e8r,e7e),e98=j0(new K2,e8i,e7n)}function evj(e){var t,n,r,i,a;for(t=Pp(e_k(e,(eBU(),ttq)),83),a=e.n,r=t.Cc().Kc();r.Ob();)i=(n=Pp(r.Pb(),306)).i,i.c+=a.a,i.d+=a.b,n.c?eL3(n):eL4(n);eo3(e,ttq,null)}function evF(e,t,n){var r,i;switch(r=(i=e.b).d,t.g){case 1:return-r.d-n;case 2:return i.o.a+r.c+n;case 3:return i.o.b+r.a+n;case 4:return-r.b-n;default:return -1}}function evY(e){var t,n,r,i,a;if(r=0,i=ezq,e.b)for(t=0;t<360;t++)n=.017453292519943295*t,eIq(e,e.d,0,0,eV7,n),(a=e.b.ig(e.d))0&&(o=(a&eUu)%e.d.length,i=exx(e,o,a,t)))?s=i.ed(n):(r=e.tj(a,t,n),e.c.Fc(r),null)}function ev1(e,t){var n,r,i,a;switch(ecG(e,t)._k()){case 3:case 2:for(i=0,a=(n=ePk(t)).i;i=0;r--)if(IE(e[r].d,t)||IE(e[r].d,n)){e.length>=r+1&&e.splice(0,r+1);break}return e}function eyt(e,t){var n;return Ts(e)&&Ts(t)&&eHV<(n=e/t)&&n0&&(e.b+=2,e.a+=r):(e.b+=1,e.a+=eB4.Math.min(r,i))}function eyc(e,t){var n,r;if(r=!1,xd(t)&&(r=!0,BC(e,new B_(Lq(t)))),!r&&M4(t,236)&&(r=!0,BC(e,(n=IZ(Pp(t,236)),new lI(n)))),!r)throw p7(new gk(eXE))}function eyl(e,t,n,r){var i,a,o;return i=new Q$(e.e,1,10,M4(o=t.c,88)?Pp(o,26):(eBK(),tgI),M4(a=n.c,88)?Pp(a,26):(eBK(),tgI),ebv(e,t),!1),r?r.Ei(i):r=i,r}function eyf(e){var t,n;switch(Pp(e_k(Bq(e),(eBy(),taP)),420).g){case 0:return t=e.n,n=e.o,new kl(t.a+n.a/2,t.b+n.b/2);case 1:return new TS(e.n);default:return null}}function eyd(){eyd=A,tto=new Sm(eGR,0),tta=new Sm("LEFTUP",1),ttu=new Sm("RIGHTUP",2),tti=new Sm("LEFTDOWN",3),tts=new Sm("RIGHTDOWN",4),ttr=new Sm("BALANCED",5)}function eyh(e,t,n){var r,i,a;if(0==(r=elN(e.a[t.p],e.a[n.p]))){if(i=Pp(e_k(t,(eBU(),tt7)),15),a=Pp(e_k(n,tt7),15),i.Hc(n))return -1;if(a.Hc(t))return 1}return r}function eyp(e){switch(e.g){case 1:return new a$;case 2:return new az;case 3:return new aH;case 0:return null;default:throw p7(new gL(eqa+(null!=e.f?e.f:""+e.g)))}}function eyb(e,t,n){switch(t){case 1:e.n||(e.n=new FQ(e6S,e,1,7)),eRT(e.n),e.n||(e.n=new FQ(e6S,e,1,7)),Y4(e.n,Pp(n,14));return;case 2:ert(e,Lq(n));return}esU(e,t,n)}function eym(e,t,n){switch(t){case 3:eni(e,gP(LV(n)));return;case 4:ena(e,gP(LV(n)));return;case 5:eno(e,gP(LV(n)));return;case 6:ens(e,gP(LV(n)));return}eyb(e,t,n)}function eyg(e,t,n){var r,i,a;(i=ew3(a=r=new mN,t,null))&&i.Fi(),er3(a,n),JL((e.c||(e.c=new FQ(tga,e,12,10)),e.c),a),end(a,0),enh(a,1),els(a,!0),eli(a,!0)}function eyv(e,t){var n,r,i;return M4(n=Ea(e.g,t),235)?((i=Pp(n,235)).Qh(),i.Nh()):M4(n,498)?i=(r=Pp(n,1938)).b:null}function eyy(e,t,n,r){var i,a;return Y9(t),Y9(n),a=Pp(Iq(e.d,t),19),QW(!!a,"Row %s not in %s",t,e.e),i=Pp(Iq(e.b,n),19),QW(!!i,"Column %s not in %s",n,e.c),eoy(e,a.a,i.a,r)}function eyw(e,t,n,r,i,a,o){var s,u,c,l,f;if(l=i[a],f=emH(s=(c=a==o-1)?r:0,l),10!=r&&eow(vx(e,o-a),t[a],n[a],s,f),!c)for(++a,u=0;u1||-1==s?(a=Pp(u,15),i.Wb(ehk(e,a))):i.Wb(eI4(e,Pp(u,56))))}function eyP(e,t,n,r){wd();var i=eUn;function a(){for(var e=0;eeVW);)i>-.000001&&++n;return n}function eyW(e,t){var n;t!=e.b?(n=null,e.b&&(n=$7(e.b,e,-4,n)),t&&(n=ep0(t,e,-4,n)),(n=ecm(e,t,n))&&n.Fi()):(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,3,t,t))}function eyK(e,t){var n;t!=e.f?(n=null,e.f&&(n=$7(e.f,e,-1,n)),t&&(n=ep0(t,e,-1,n)),(n=ecg(e,t,n))&&n.Fi()):(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,0,t,t))}function eyV(e){var t,n,r;if(null==e)return null;if((n=Pp(e,15)).dc())return"";for(r=new vs,t=n.Kc();t.Ob();)xk(r,(eR7(),Lq(t.Pb()))),r.a+=" ";return x3(r,r.a.length-1)}function eyq(e){var t,n,r;if(null==e)return null;if((n=Pp(e,15)).dc())return"";for(r=new vs,t=n.Kc();t.Ob();)xk(r,(eR7(),Lq(t.Pb()))),r.a+=" ";return x3(r,r.a.length-1)}function eyZ(e,t,n){var r,i;return(r=e.c[t.c.p][t.p],i=e.c[n.c.p][n.p],null!=r.a&&null!=i.a)?F_(r.a,i.a):null!=r.a?-1:null!=i.a?1:0}function eyX(e,t){var n,r,i,a,o,s;if(t)for(a=t.a.length,s=((n=new Fs(a)).b-n.a)*n.c<0?(_9(),eB3):new OR(n);s.Ob();)i=KZ(t,(o=Pp(s.Pb(),19)).a),UX((r=new pu(e)).a,i)}function eyJ(e,t){var n,r,i,a,o,s;if(t)for(a=t.a.length,s=((n=new Fs(a)).b-n.a)*n.c<0?(_9(),eB3):new OR(n);s.Ob();)i=KZ(t,(o=Pp(s.Pb(),19)).a),UZ((r=new h7(e)).a,i)}function eyQ(e){var t;if(null!=e&&e.length>0&&33==UI(e,e.length-1))try{return t=eSR(Az(e,0,e.length-1)),null==t.e}catch(n){if(n=eoa(n),!M4(n,32))throw p7(n)}return!1}function ey1(e,t,n){var r,i,a;return r=t.ak(),a=t.dd(),i=r.$j()?$N(e,3,r,null,a,eN1(e,r,a,M4(r,99)&&(Pp(r,18).Bb&eH3)!=0),!0):$N(e,1,r,r.zj(),a,-1,!0),n?n.Ei(i):n=i,n}function ey0(){var e,t,n;for(e=0,t=0;e<1;e++){if(0==(n=eTa((GV(e,1),"X".charCodeAt(e)))))throw p7(new gX("Unknown Option: "+"X".substr(e)));t|=n}return t}function ey2(e,t,n){var r,i,a;switch(i=el0(r=Bq(t)),a=new eES,Gc(a,t),n.g){case 1:ekv(a,elC(ef9(i)));break;case 2:ekv(a,ef9(i))}return eo3(a,(eBy(),toc),LV(e_k(e,toc))),a}function ey3(e){var t,n;return t=Pp(ZC(new Fa(OH(efu(e.a).a.Kc(),new c))),17),n=Pp(ZC(new Fa(OH(efc(e.a).a.Kc(),new c))),17),gN(LK(e_k(t,(eBU(),tnE))))||gN(LK(e_k(n,tnE)))}function ey4(){ey4=A,ter=new Sa("ONE_SIDE",0),tea=new Sa("TWO_SIDES_CORNER",1),teo=new Sa("TWO_SIDES_OPPOSING",2),tei=new Sa("THREE_SIDES",3),ten=new Sa("FOUR_SIDES",4)}function ey5(e,t,n,r,i){var a,o;a=Pp(qE(UJ(t.Oc(),new ih),JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[(eum(),e2U)]))),15),o=Pp(eay(e.b,n,r),15),0==i?o.Wc(0,a):o.Gc(a)}function ey6(e,t){var n,r,i,a,o;for(a=new fz(t.a);a.a0&&egL(this,this.c-1,(eYu(),tby)),this.c0&&e[0].length>0&&(this.c=gN(LK(e_k(Bq(e[0][0]),(eBU(),tne))))),this.a=Je(e5d,eUP,2018,e.length,0,2),this.b=Je(e5h,eUP,2019,e.length,0,2),this.d=new euX}function ewu(e){return 0!=e.c.length&&((GK(0,e.c.length),Pp(e.c[0],17)).c.i.k==(eEn(),e8D)||q3(UQ(new R1(null,new Gq(e,16)),new iJ),new iQ))}function ewc(e,t,n){return ewG(n,"Tree layout",1),Kx(e.b),Yb(e.b,(egR(),tuJ),tuJ),Yb(e.b,tuQ,tuQ),Yb(e.b,tu1,tu1),Yb(e.b,tu0,tu0),e.a=eRq(e.b,t),eAG(e,t,eiI(n,1)),eEj(n),t}function ewl(e,t){var n,r,i,a,o,s,u;for(s=eLj(t),a=t.f,u=t.g,o=eB4.Math.sqrt(a*a+u*u),i=0,r=new fz(s);r.a=0?(n=eyt(e,eHK),r=edQ(e,eHK)):(n=eyt(t=Fy(e,1),5e8),r=eft(Fg(r=edQ(t,5e8),1),WM(e,1))),WO(Fg(r,32),WM(n,eH8))}function ewM(e,t,n){var r,i;switch(r=(A6(0!=t.b),Pp(etw(t,t.a.a),8)),n.g){case 0:r.b=0;break;case 2:r.b=e.f;break;case 3:r.a=0;break;default:r.a=e.g}return YU(i=epL(t,0),r),t}function ewO(e,t,n,r){var i,a,o,s,u;switch(u=e.b,s=epd(o=(a=t.d).j,u.d[o.g],n),i=C5(MB(a.n),a.a),a.j.g){case 1:case 3:s.a+=i.a;break;case 2:case 4:s.b+=i.b}qQ(r,s,r.c.b,r.c)}function ewA(e,t,n){var r,i,a,o;for(o=QI(e.e,t,0),(a=new ma).b=n,r=new KB(e.e,o);r.b1;t>>=1)(1&t)!=0&&(r=eeD(r,n)),n=1==n.d?eeD(n,n):new eh5(eDE(n.a,n.d,Je(ty_,eHT,25,n.d<<1,15,1)));return eeD(r,n)}function ewP(){var e,t,n,r;for(t=32,ewP=A,e2v=Je(tyx,eH5,25,25,15,1),e2y=Je(tyx,eH5,25,33,15,1),r=152587890625e-16;t>=0;t--)e2y[t]=r,r*=.5;for(e=24,n=1;e>=0;e--)e2v[e]=n,n*=.5}function ewR(e){var t,n;if(gN(LK(eT8(e,(eBy(),taI))))){for(n=new Fa(OH(eOi(e).a.Kc(),new c));eTk(n);)if(t=Pp(ZC(n),79),exb(t)&&gN(LK(eT8(t,taD))))return!0}return!1}function ewj(e,t){var n,r,i;Yf(e.f,t)&&(t.b=e,r=t.c,-1!=QI(e.j,r,0)||P_(e.j,r),i=t.d,-1!=QI(e.j,i,0)||P_(e.j,i),0!=(n=t.a.b).c.length&&(e.i||(e.i=new epS(e)),ea_(e.i,n)))}function ewF(e){var t,n,r,i,a;return(r=(n=e.c.d).j)==(a=(i=e.d.d).j)?n.p=0&&IE(e.substr(t,3),"GMT")?(n[0]=t+3,eDh(e,n,r)):(t>=0&&IE(e.substr(t,3),"UTC")&&(n[0]=t+3),eDh(e,n,r))}function ewz(e,t){var n,r,i,a,o;for(a=e.g.a,o=e.g.b,r=new fz(e.d);r.an;a--)e[a]|=t[a-n-1]>>>o,e[a-1]=t[a-n-1]<=e.f)break;a.c[a.c.length]=n}return a}function ew1(e){var t,n,r,i;for(t=null,i=new fz(e.wf());i.a0&&ePD(e.g,t,e.g,t+r,s),o=n.Kc(),e.i+=r,i=0;ia&&F6(c,ee5(n[s],e2h))&&(i=s,a=u);return i>=0&&(r[0]=t+a),i}function ew9(e,t){var n;if(0!=(n=To(e.b.Hf(),t.b.Hf())))return n;switch(e.b.Hf().g){case 1:case 2:return ME(e.b.sf(),t.b.sf());case 3:case 4:return ME(t.b.sf(),e.b.sf())}return 0}function ew8(e){var t,n,r;for(r=e.e.c.length,e.a=RF(ty_,[eUP,eHT],[48,25],15,[r,r],2),n=new fz(e.c);n.a>4&15,a=15&e[r],o[i++]=tmk[n],o[i++]=tmk[a];return ehv(o,0,o.length)}function e_t(e,t,n){var r,i,a;return r=t.ak(),a=t.dd(),i=r.$j()?$N(e,4,r,a,null,eN1(e,r,a,M4(r,99)&&(Pp(r,18).Bb&eH3)!=0),!0):$N(e,r.Kj()?2:1,r,a,r.zj(),-1,!0),n?n.Ei(i):n=i,n}function e_n(e){var t,n;return e>=eH3?(t=eH4+(e-eH3>>10&1023)&eHd,n=56320+(e-eH3&1023)&eHd,String.fromCharCode(t)+""+String.fromCharCode(n)):String.fromCharCode(e&eHd)}function e_r(e,t){var n,r,i,a;return Cn(),(i=Pp(Pp(Zq(e.r,t),21),84)).gc()>=2&&(r=Pp(i.Kc().Pb(),111),n=e.u.Hc((ekU(),tbh)),a=e.u.Hc(tbg),!r.a&&!n&&(2==i.gc()||a))}function e_i(e,t,n,r,i){var a,o,s;for(a=eLx(e,t,n,r,i),s=!1;!a;)eME(e,i,!0),s=!0,a=eLx(e,t,n,r,i);s&&eME(e,i,!1),0!=(o=eoA(i)).c.length&&(e.d&&e.d.lg(o),e_i(e,i,n,r,o))}function e_a(){e_a=A,tpN=new km(eGR,0),tpI=new km("DIRECTED",1),tpP=new km("UNDIRECTED",2),tpL=new km("ASSOCIATION",3),tpD=new km("GENERALIZATION",4),tpC=new km("DEPENDENCY",5)}function e_o(e,t){var n;if(!zY(e))throw p7(new gC(eZL));switch(n=zY(e),t.g){case 1:return-(e.j+e.f);case 2:return e.i-n.g;case 3:return e.j-n.f;case 4:return-(e.i+e.g)}return 0}function e_s(e,t){var n,r;for(BJ(t),r=e.b.c.length,P_(e.b,t);r>0;){if(n=r,r=(r-1)/2|0,0>=e.a.ue(RJ(e.b,r),t))return q1(e.b,n,t),!0;q1(e.b,n,RJ(e.b,r))}return q1(e.b,r,t),!0}function e_u(e,t,n,r){var i,a;if(i=0,n)i=euW(e.a[n.g][t.g],r);else for(a=0;a=s)}function e_l(e,t,n,r){var i;if(i=!1,xd(r)&&(i=!0,P4(t,n,Lq(r))),!i&&xl(r)&&(i=!0,e_l(e,t,n,r)),!i&&M4(r,236)&&(i=!0,H1(t,n,Pp(r,236))),!i)throw p7(new gk(eXE))}function e_f(e,t){var n,r,i;if((n=t.Hh(e.a))&&null!=(i=edW((n.b||(n.b=new L_((eBK(),tgF),tgf,n)),n.b),eQe))){for(r=1;r<(eSp(),tvs).length;++r)if(IE(tvs[r],i))return r}return 0}function e_d(e,t){var n,r,i;if((n=t.Hh(e.a))&&null!=(i=edW((n.b||(n.b=new L_((eBK(),tgF),tgf,n)),n.b),eQe))){for(r=1;r<(eSp(),tvu).length;++r)if(IE(tvu[r],i))return r}return 0}function e_h(e,t){var n,r,i,a;if(BJ(t),(a=e.a.gc())0?1:0;a.a[i]!=n;)a=a.a[i],i=e.a.ue(n.d,a.d)>0?1:0;a.a[i]=r,r.b=n.b,r.a[0]=n.a[0],r.a[1]=n.a[1],n.a[0]=null,n.a[1]=null}function e_y(e){var t,n;return ekU(),t=jL(tbp,eow(vx(e6i,1),eU4,273,0,[tbm])),!(eaC(z_(t,e))>1)&&(n=jL(tbh,eow(vx(e6i,1),eU4,273,0,[tbd,tbg])),!(eaC(z_(n,e))>1))}function e_w(e,t){var n;M4(n=zg((_Q(),tgp),e),498)?Ge(tgp,e,new k5(this,t)):Ge(tgp,e,this),e_8(this,t),t==(yO(),tgg)?(this.wb=Pp(this,1939),Pp(t,1941)):this.wb=(BM(),tgv)}function e__(e){var t,n,r;if(null==e)return null;for(n=0,t=null;n=eHf?"error":r>=900?"warn":r>=800?"info":"log",e.a),e.b&&eAp(t,n,e.b,"Exception: ",!0))}function e_k(e,t){var n,r;return null!=(r=(e.q||(e.q=new p2),Bp(e.q,t)))?r:(M4(n=t.wg(),4)&&(null==n?(e.q||(e.q=new p2),Z3(e.q,t)):(e.q||(e.q=new p2),Um(e.q,t,n))),n)}function e_x(){e_x=A,e8e=new Ez("P1_CYCLE_BREAKING",0),e8t=new Ez("P2_LAYERING",1),e8n=new Ez("P3_NODE_ORDERING",2),e8r=new Ez("P4_NODE_PLACEMENT",3),e8i=new Ez("P5_EDGE_ROUTING",4)}function e_T(e,t){var n,r,i,a,o;for(r=(i=1==t?e8c:e8u).a.ec().Kc();r.Ob();)for(n=Pp(r.Pb(),103),o=Pp(Zq(e.f.c,n),21).Kc();o.Ob();)a=Pp(o.Pb(),46),QA(e.b.b,a.b),QA(e.b.a,Pp(a.b,81).d)}function e_M(e,t){var n;if(eeP(),e.c!=t.c)return elN(e.c,t.c);if(e.b==t.b||eiS(e.b,t.b)){if(n=Tu(e.b)?1:-1,e.a&&!t.a)return n;if(!e.a&&t.a)return-n}return ME(e.b.g,t.b.g)}function e_O(e,t){var n;ewG(t,"Hierarchical port position processing",1),(n=e.b).c.length>0&&eI6((GK(0,n.c.length),Pp(n.c[0],29)),e),n.c.length>1&&eI6(Pp(RJ(n,n.c.length-1),29),e),eEj(t)}function e_A(e,t){var n,r,i;if(e_Y(e,t))return!0;for(r=new fz(t);r.a=(i=e.Vi())||t<0)throw p7(new gE(eXU+t+eXH+i));if(n>=i||n<0)throw p7(new gE(eX$+n+eXH+i));return t!=n?(a=e.Ti(n),e.Hi(t,a),a):e.Oi(n)}function e_j(e){var t,n,r;if(r=e,e)for(t=0,n=e.Ug();n;n=n.Ug()){if(++t>eH6)return e_j(n);if(r=n,n==e)throw p7(new gC("There is a cycle in the containment hierarchy of "+e))}return r}function e_F(e){var t,n,r;for(r=new eaP(eUd,"[","]"),n=e.Kc();n.Ob();)ZJ(r,xc(t=n.Pb())===xc(e)?"(this Collection)":null==t?eUg:efF(t));return r.a?0==r.e.length?r.a.a:r.a.a+""+r.e:r.c}function e_Y(e,t){var n,r;if(r=!1,2>t.gc())return!1;for(n=0;n=e.charCodeAt(r));)++r;for(t=n;t>r&&(GV(t-1,e.length),32>=e.charCodeAt(t-1));)--t;return r>0||t1&&(e.j.b+=e.e)):(e.j.a+=n.a,e.j.b=eB4.Math.max(e.j.b,n.b),e.d.c.length>1&&(e.j.a+=e.e))}function e_z(){e_z=A,tec=eow(vx(e6a,1),eGj,61,0,[(eYu(),tbw),tby,tbj]),teu=eow(vx(e6a,1),eGj,61,0,[tby,tbj,tbY]),tel=eow(vx(e6a,1),eGj,61,0,[tbj,tbY,tbw]),tef=eow(vx(e6a,1),eGj,61,0,[tbY,tbw,tby])}function e_G(e,t,n,r){var i,a,o,s,u,c,l;if(o=e.c.d,s=e.d.d,o.j!=s.j)for(l=e.b,i=o.j,u=null;i!=s.j;)u=0==t?elI(i):elL(i),P7(r,C5(a=epd(i,l.d[i.g],n),c=epd(u,l.d[u.g],n))),i=u}function e_W(e,t,n,r){var i,a,o,s,u;return o=egN(e.a,t,n),s=Pp(o.a,19).a,a=Pp(o.b,19).a,r&&(u=Pp(e_k(t,(eBU(),tng)),10),i=Pp(e_k(n,tng),10),u&&i&&(V6(e.b,u,i),s+=e.b.i,a+=e.b.e)),s>a}function e_K(e){var t,n,r,i,a,o,s,u,c;for(r=0,this.a=ebb(e),this.b=new p0,i=(n=e).length;rL7(e.d).c?(e.i+=e.g.c,ed3(e.d)):L7(e.d).c>L7(e.g).c?(e.e+=e.d.c,ed3(e.g)):(e.i+=R6(e.g),e.e+=R6(e.d),ed3(e.g),ed3(e.d))}function e_X(e,t,n){var r,i,a,o;for(a=t.q,o=t.r,new GT((Xa(),tuU),t,a,1),new GT(tuU,a,o,1),i=new fz(n);i.as&&(u=s/r),i>a&&(c=a/i),o=eB4.Math.min(u,c),e.a+=o*(t.a-e.a),e.b+=o*(t.b-e.b)}function e_5(e,t,n,r,i){var a,o;for(o=!1,a=Pp(RJ(n.b,0),33);eNK(e,t,a,r,i)&&(o=!0,eyL(n,a),0!=n.b.c.length);)a=Pp(RJ(n.b,0),33);return 0==n.b.c.length&&eva(n.j,n),o&&emG(t.q),o}function e_6(e,t){var n,r,i,a;if(eLG(),t.b<2)return!1;for(r=n=Pp(Vv(a=epL(t,0)),8);a.b!=a.d.c;){if(eOV(e,r,i=Pp(Vv(a),8)))return!0;r=i}return!!eOV(e,r,n)}function e_9(e,t,n,r){var i,a;return 0==n?(e.o||(e.o=new JY((eBa(),tmy),e6O,e,0)),Iz(e.o,t,r)):(a=Pp(ee2((i=Pp(eaS(e,16),26))||e.zh(),n),66)).Nj().Rj(e,ehH(e),n-Y1(e.zh()),t,r)}function e_8(e,t){var n;t!=e.sb?(n=null,e.sb&&(n=Pp(e.sb,49).ih(e,1,e6w,n)),t&&(n=Pp(t,49).gh(e,1,e6w,n)),(n=ecY(e,t,n))&&n.Fi()):(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,4,t,t))}function e_7(e,t){var n,r,i,a;if(t)i=enm(t,"x"),enr((n=new pa(e)).a,(BJ(i),i)),a=enm(t,"y"),enc((r=new po(e)).a,(BJ(a),a));else throw p7(new gK("All edge sections need an end point."))}function eEe(e,t){var n,r,i,a;if(t)i=enm(t,"x"),enu((n=new pn(e)).a,(BJ(i),i)),a=enm(t,"y"),enl((r=new pr(e)).a,(BJ(a),a));else throw p7(new gK("All edge sections need a start point."))}function eEt(e,t){var n,r,i,a,o,s,u;for(r=es1(e),a=0,s=r.length;a>22-t,i=e.h<>22-t):t<44?(n=0,r=e.l<>44-t):(n=0,r=0,i=e.l<e))return 0==t||t==e?1:0==e?0:ev6(e)/(ev6(t)*ev6(e-t));throw p7(new gL("k must be smaller than n"))}function eEh(e,t){var n,r,i,a;for(n=new TY(e);null!=n.g||n.c?null==n.g||0!=n.i&&Pp(n.g[n.i-1],47).Ob():zW(n);)if(M4(a=Pp(eM5(n),56),160))for(i=0,r=Pp(a,160);i>4],t[2*n+1]=tv0[15&a];return ehv(t,0,t.length)}function eEA(e){var t,n,r;switch(U_(),r=e.c.length){case 0:return e0p;case 1:return P2((t=Pp(ekM(new fz(e)),42)).cd(),t.dd());default:return n=Pp(epg(e,Je(e1$,eUK,42,e.c.length,0,1)),165),new gt(n)}}function eEL(e){var t,n,r,i,a,o;for(t=new p1,n=new p1,Vw(t,e),Vw(n,e);n.b!=n.c;)for(i=Pp(Yn(n),37),o=new fz(i.a);o.a0&&eIl(e,n,t),i):exV(e,t,n)}function eEN(e,t,n){var r,i,a,o;if(0!=t.b){for(r=new _n,o=epL(t,0);o.b!=o.d.c;)er7(r,eoO(a=Pp(Vv(o),86))),(i=a.e).a=Pp(e_k(a,(eR6(),tcg)),19).a,i.b=Pp(e_k(a,tcv),19).a;eEN(e,r,eiI(n,r.b/e.a|0))}}function eEP(e,t){var n,r,i,a,o;if(e.e<=t||Wm(e,e.g,t))return e.g;for(a=e.r,r=e.g,o=e.r,i=(a-r)/2+r;r+11&&(e.e.b+=e.a)):(e.e.a+=n.a,e.e.b=eB4.Math.max(e.e.b,n.b),e.d.c.length>1&&(e.e.a+=e.a))}function eEH(e){var t,n,r,i;switch(t=(i=e.i).b,r=i.j,n=i.g,i.a.g){case 0:n.a=(e.g.b.o.a-r.a)/2;break;case 1:n.a=t.d.n.a+t.d.a.a;break;case 2:n.a=t.d.n.a+t.d.a.a-r.a;break;case 3:n.b=t.d.n.b+t.d.a.b}}function eE$(e,t,n,r,i){if(rr&&(e.a=r),e.bi&&(e.b=i),e}function eEz(e){if(M4(e,149))return eAi(Pp(e,149));if(M4(e,229))return efZ(Pp(e,229));if(M4(e,23))return eEa(Pp(e,23));throw p7(new gL(eXx+e_F(new g$(eow(vx(e1R,1),eUp,1,5,[e])))))}function eEG(e,t,n,r,i){var a,o,s;for(o=0,a=!0;o>>i|n[o+r+1]<>>i,++o}return a}function eEW(e,t,n,r){var i,a,o;if(t.k==(eEn(),e8D)){for(a=new Fa(OH(efu(t).a.Kc(),new c));eTk(a);)if((o=(i=Pp(ZC(a),17)).c.i.k)==e8D&&e.c.a[i.c.i.c.p]==r&&e.c.a[t.c.p]==n)return!0}return!1}function eEK(e,t){var n,r,i,a;return t&=63,n=e.h&eH$,t<22?(a=n>>>t,i=e.m>>t|n<<22-t,r=e.l>>t|e.m<<22-t):t<44?(a=0,i=n>>>t-22,r=e.m>>t-22|e.h<<44-t):(a=0,i=0,r=n>>>t-44),Mk(r&eHH,i&eHH,a&eH$)}function eEV(e,t,n,r){var i;this.b=r,this.e=e==(enU(),tui),i=t[n],this.d=RF(tyE,[eUP,e$5],[177,25],16,[i.length,i.length],2),this.a=RF(ty_,[eUP,eHT],[48,25],15,[i.length,i.length],2),this.c=new ewo(t,n)}function eEq(e){var t,n,r;for(e.k=new G$((eYu(),eow(vx(e6a,1),eGj,61,0,[tbF,tbw,tby,tbj,tbY])).length,e.j.c.length),r=new fz(e.j);r.a=n)return eE5(e,t,r.p),!0;return!1}function eE1(e){var t;return(64&e.Db)!=0?eEp(e):(t=new O0(eZ$),e.a&&xM(xM((t.a+=' "',t),e.a),'"'),xM(yW(xM(yW(xM(yW(xM(yW((t.a+=" (",t),e.i),","),e.j)," | "),e.g),","),e.f),")"),t.a)}function eE0(e,t,n){var r,i,a,o,s;for(o=0,s=eAY(e.e.Tg(),t),i=Pp(e.g,119),r=0;on?eS1(e,n,"start index"):t<0||t>n?eS1(t,n,"end index"):eCG("end index (%s) must not be less than start index (%s)",eow(vx(e1R,1),eUp,1,5,[ell(t),ell(e)]))}function eE4(e,t){var n,r,i,a;for(r=0,i=e.length;r0&&eE9(e,a,n));t.p=0}function eE8(e){var t;this.c=new _n,this.f=e.e,this.e=e.d,this.i=e.g,this.d=e.c,this.b=e.b,this.k=e.j,this.a=e.a,e.i?this.j=e.i:this.j=(t=Pp(yw(e5Q),9),new I1(t,Pp(CY(t,t.length),9),0)),this.g=e.f}function eE7(e){var t,n,r,i;for(t=Bd(xM(new O0("Predicates."),"and"),40),n=!0,i=new fE(e);i.b0?s[o-1]:Je(e4N,eGW,10,0,0,1),i=s[o],c=o=0?e.Bh(i):ekN(e,r);else throw p7(new gL(eZV+r.ne()+eZq))}else throw p7(new gL(eZJ+t+eZQ))}else ec6(e,n,r)}function eSa(e){var t,n;if(n=null,t=!1,M4(e,204)&&(t=!0,n=Pp(e,204).a),!t&&M4(e,258)&&(t=!0,n=""+Pp(e,258).a),!t&&M4(e,483)&&(t=!0,n=""+Pp(e,483).a),!t)throw p7(new gk(eXE));return n}function eSo(e,t){var n,r;if(!e.f)return t.Ob();for(;t.Ob();)if(M4(r=(n=Pp(t.Pb(),72)).ak(),99)&&(Pp(r,18).Bb&eZ1)!=0&&(!e.e||r.Gj()!=e6d||0!=r.aj())&&null!=n.dd())return t.Ub(),!0;return!1}function eSs(e,t){var n,r;if(!e.f)return t.Sb();for(;t.Sb();)if(M4(r=(n=Pp(t.Ub(),72)).ak(),99)&&(Pp(r,18).Bb&eZ1)!=0&&(!e.e||r.Gj()!=e6d||0!=r.aj())&&null!=n.dd())return t.Pb(),!0;return!1}function eSu(e,t,n){var r,i,a,o,s,u;for(o=0,u=eAY(e.e.Tg(),t),r=0,s=e.i,i=Pp(e.g,119);o1&&(t.c[t.c.length]=a)}function eSf(e){var t,n,r,i;for(er7(n=new _n,e.o),r=new mc;0!=n.b;)(i=eYP(e,t=Pp(0==n.b?null:(A6(0!=n.b),etw(n,n.a.a)),508),!0))&&P_(r.a,t);for(;0!=r.a.c.length;)eYP(e,t=Pp(euO(r),508),!1)}function eSd(){eSd=A,tdS=new ks(ezo,0),tdm=new ks("BOOLEAN",1),tdw=new ks("INT",2),tdE=new ks("STRING",3),tdg=new ks("DOUBLE",4),tdv=new ks("ENUM",5),tdy=new ks("ENUMSET",6),td_=new ks("OBJECT",7)}function eSh(e,t){var n,r,i,a,o;r=eB4.Math.min(e.c,t.c),a=eB4.Math.min(e.d,t.d),i=eB4.Math.max(e.c+e.b,t.c+t.b),o=eB4.Math.max(e.d+e.a,t.d+t.a),i=(i/2|0))for(this.e=r?r.c:null,this.d=i;n++0;)Gi(this);this.b=t,this.a=null}function eSk(e,t){var n,r;t.a?eAk(e,t):((n=Pp(Ik(e.b,t.b),57))&&n==e.a[t.b.f]&&n.a&&n.a!=t.b.a&&n.c.Fc(t.b),(r=Pp(IS(e.b,t.b),57))&&e.a[r.f]==t.b&&r.a&&r.a!=t.b.a&&t.b.c.Fc(r),Ai(e.b,t.b))}function eSx(e,t){var n,r;if(n=Pp(UA(e.b,t),124),Pp(Pp(Zq(e.r,t),21),84).dc()){n.n.b=0,n.n.c=0;return}n.n.b=e.C.b,n.n.c=e.C.c,e.A.Hc((ed6(),tbq))&&eCD(e,t),r=ebi(e,t),eLZ(e,t)==(epT(),tbt)&&(r+=2*e.w),n.a.a=r}function eST(e,t){var n,r;if(n=Pp(UA(e.b,t),124),Pp(Pp(Zq(e.r,t),21),84).dc()){n.n.d=0,n.n.a=0;return}n.n.d=e.C.d,n.n.a=e.C.a,e.A.Hc((ed6(),tbq))&&eCN(e,t),r=eba(e,t),eLZ(e,t)==(epT(),tbt)&&(r+=2*e.w),n.a.b=r}function eSM(e,t){var n,r,i,a;for(a=new p0,r=new fz(t);r.aeB4.Math.abs(r-i))}function eSU(e,t,n){var r,i,a,o,s,u;if(null!=(s=Pp(eaS(e.a,8),1936)))for(a=0,o=(i=s).length;an.a&&(r.Hc((eyY(),tdW))?i=(t.a-n.a)/2:r.Hc(tdV)&&(i=t.a-n.a)),t.b>n.b&&(r.Hc((eyY(),tdZ))?a=(t.b-n.b)/2:r.Hc(tdq)&&(a=t.b-n.b)),e_g(e,i,a)}function eSJ(e,t,n,r,i,a,o,s,u,c,l,f,d){M4(e.Cb,88)&&eko(Zd(Pp(e.Cb,88)),4),er3(e,n),e.f=o,elY(e,s),elU(e,u),elF(e,c),elB(e,l),els(e,f),elZ(e,d),eli(e,!0),end(e,i),e.ok(a),eu2(e,t),null!=r&&(e.i=null,erA(e,r))}function eSQ(e){var t,n;if(!e.f)return e.n>0;for(;e.n>0;){if(M4(n=(t=Pp(e.k.Xb(e.n-1),72)).ak(),99)&&(Pp(n,18).Bb&eZ1)!=0&&(!e.e||n.Gj()!=e6d||0!=n.aj())&&null!=t.dd())return!0;--e.n}return!1}function eS1(e,t,n){if(e<0)return eCG(eUh,eow(vx(e1R,1),eUp,1,5,[n,ell(e)]));if(!(t<0))return eCG("%s (%s) must not be greater than size (%s)",eow(vx(e1R,1),eUp,1,5,[n,ell(e),ell(t)]));throw p7(new gL(eUb+t))}function eS0(e,t,n,r,i,a){var o,s,u,c;if((o=r-n)<7){efA(t,n,r,a);return}if(c=(u=n+i)+((s=r+i)-u>>1),eS0(t,e,u,c,-i,a),eS0(t,e,c,s,-i,a),0>=a.ue(e[c-1],e[c])){for(;n=0?e.sh(a,n):eOh(e,i,n);else throw p7(new gL(eZV+i.ne()+eZq))}else throw p7(new gL(eZJ+t+eZQ))}else efL(e,r,i,n)}function eS6(e){var t,n,r,i;if(n=Pp(e,49).qh())try{if(r=null,(t=eMC((_Q(),tgp),eDv(efR(n))))&&(i=t.rh())&&(r=i.Wk(gF(n.e))),r&&r!=e)return eS6(r)}catch(a){if(a=eoa(a),!M4(a,60))throw p7(a)}return e}function eS9(e,t,n){var r,i,a,o;if(o=null==t?0:e.b.se(t),0==(i=null==(r=e.a.get(o))?[]:r).length)e.a.set(o,i);else if(a=euj(e,t,i))return a.ed(n);return Bc(i,i.length,new EE(t,n)),++e.c,$c(e.b),null}function eS8(e,t){var n,r;return Kx(e.a),Yb(e.a,(erZ(),tcq),tcq),Yb(e.a,tcZ,tcZ),r=new K2,RI(r,tcZ,(efx(),tc1)),xc(eT8(t,(egj(),tlf)))!==xc((eub(),tc5))&&RI(r,tcZ,tcJ),RI(r,tcZ,tcQ),Tb(e.a,r),n=eRq(e.a,t)}function eS7(e){if(!e)return g3(),e0M;var t=e.valueOf?e.valueOf():e;if(t!==e){var n=e0O[typeof t];return n?n(t):euV(typeof t)}return e instanceof Array||e instanceof eB4.Array?new lL(e):new lD(e)}function eke(e,t,n){var r,i,a;switch(a=e.o,(i=(r=Pp(UA(e.p,n),244)).i).b=ek0(r),i.a=ek1(r),i.b=eB4.Math.max(i.b,a.a),i.b>a.a&&!t&&(i.b=a.a),i.c=-(i.b-a.a)/2,n.g){case 1:i.d=-i.a;break;case 3:i.d=a.b}eNE(r),eNM(r)}function ekt(e,t,n){var r,i,a;switch(a=e.o,(i=(r=Pp(UA(e.p,n),244)).i).b=ek0(r),i.a=ek1(r),i.a=eB4.Math.max(i.a,a.b),i.a>a.b&&!t&&(i.a=a.b),i.d=-(i.a-a.b)/2,n.g){case 4:i.c=-i.b;break;case 2:i.c=a.a}eNE(r),eNM(r)}function ekn(e,t){var n,r,i,a,o;if(!t.dc()){if(i=Pp(t.Xb(0),128),1==t.gc()){eA1(e,i,i,1,0,t);return}for(n=1;n0)try{i=eDa(t,eHt,eUu)}catch(a){if(a=eoa(a),M4(a,127))throw r=a,p7(new QH(r));throw p7(a)}return i<(n=(e.a||(e.a=new pK(e)),e.a)).i&&i>=0?Pp(etj(n,i),56):null}function eku(e,t){if(e<0)return eCG(eUh,eow(vx(e1R,1),eUp,1,5,["index",ell(e)]));if(!(t<0))return eCG("%s (%s) must be less than size (%s)",eow(vx(e1R,1),eUp,1,5,["index",ell(e),ell(t)]));throw p7(new gL(eUb+t))}function ekc(e){var t,n,r,i,a;if(null==e)return eUg;for(r=0,a=new eaP(eUd,"[","]"),i=(n=e).length;re.a.ue(RJ(e.b,o),RJ(e.b,a))&&(s=o),s),!(0>e.a.ue(i,RJ(e.b,r))));)q1(e.b,t,RJ(e.b,r)),t=r;q1(e.b,t,i)}function ekp(e,t,n,r,i,a){var o,s,u,c,l;for(xc(e)===xc(n)&&(e=e.slice(t,t+i),t=0),u=n,s=t,c=t+i;s0)for(o=e.c.d,s=e.d.d,i=Ol(C6(new kl(s.a,s.b),o),1/(r+1)),a=new kl(o.a,o.b),n=new fz(e.a);n.a=0?e._g(n,!0,!0):exk(e,i,!0),153),Pp(r,215).ol(t);else throw p7(new gL(eZV+t.ne()+eZq))}function ekP(e){var t,n;return e>-140737488355328&&e<0x800000000000?0==e?0:((t=e<0)&&(e=-e),n=zy(eB4.Math.floor(eB4.Math.log(e)/.6931471805599453)),(!t||e!=eB4.Math.pow(2,n))&&++n,n):eaJ(eap(e))}function ekR(e){var t,n,r,i,a,o,s;for(a=new Tw,n=new fz(e);n.a2&&s.e.b+s.j.b<=2&&(i=s,r=o),a.a.zc(i,a),i.q=r);return a}function ekj(e,t){var n,r,i;return r=new eb$(e),eaW(r,t),eo3(r,(eBU(),ttQ),t),eo3(r,(eBy(),tol),(ewf(),tbo)),eo3(r,tiq,(ebx(),tdA)),lK(r,(eEn(),e8C)),n=new eES,Gc(n,r),ekv(n,(eYu(),tbY)),i=new eES,Gc(i,r),ekv(i,tby),r}function ekF(e){switch(e.g){case 0:return new gx((enU(),tur));case 1:return new cC;case 2:return new cF;default:throw p7(new gL("No implementation is available for the crossing minimizer "+(null!=e.f?e.f:""+e.g)))}}function ekY(e,t){var n,r,i,a,o;for(e.c[t.p]=!0,P_(e.a,t),o=new fz(t.j);o.a=(a=o.gc()))o.$b();else for(r=0,i=o.Kc();r0?g5():o<0&&ekJ(e,t,-o),!0)}function ek1(e){var t,n,r,i,a,o,s;if(s=0,0==e.b){for(i=0,o=eb4(e,!0),t=0,a=(r=o).length;i0&&(s+=n,++t);t>1&&(s+=e.c*(t-1))}else s=vy(eib(U1(UJ(Yw(e.a),new eS),new ek)));return s>0?s+e.n.d+e.n.a:0}function ek0(e){var t,n,r,i,a,o,s;if(s=0,0==e.b)s=vy(eib(U1(UJ(Yw(e.a),new e_),new eE)));else{for(i=0,o=eb5(e,!0),t=0,a=(r=o).length;i0&&(s+=n,++t);t>1&&(s+=e.c*(t-1))}return s>0?s+e.n.b+e.n.c:0}function ek2(e,t){var n,r,i,a;for(n=(a=Pp(UA(e.b,t),124)).a,i=Pp(Pp(Zq(e.r,t),21),84).Kc();i.Ob();)(r=Pp(i.Pb(),111)).c&&(n.a=eB4.Math.max(n.a,Rd(r.c)));if(n.a>0)switch(t.g){case 2:a.n.c=e.s;break;case 4:a.n.b=e.s}}function ek3(e,t){var n,r,i;return 0==(n=Pp(e_k(t,(eCk(),e9M)),19).a-Pp(e_k(e,e9M),19).a)?(r=C6(MB(Pp(e_k(e,(erV(),e9P)),8)),Pp(e_k(e,e9R),8)),i=C6(MB(Pp(e_k(t,e9P),8)),Pp(e_k(t,e9R),8)),elN(r.a*r.b,i.a*i.b)):n}function ek4(e,t){var n,r,i;return 0==(n=Pp(e_k(t,(eTj(),tcD)),19).a-Pp(e_k(e,tcD),19).a)?(r=C6(MB(Pp(e_k(e,(eR6(),tce)),8)),Pp(e_k(e,tct),8)),i=C6(MB(Pp(e_k(t,tce),8)),Pp(e_k(t,tct),8)),elN(r.a*r.b,i.a*i.b)):n}function ek5(e){var t,n;return n=new vc,n.a+="e_",null!=(t=eaZ(e))&&(n.a+=""+t),e.c&&e.d&&(xM((n.a+=" ",n),egu(e.c)),xM(xT((n.a+="[",n),e.c.i),"]"),xM((n.a+=eGH,n),egu(e.d)),xM(xT((n.a+="[",n),e.d.i),"]")),n.a}function ek6(e){switch(e.g){case 0:return new cD;case 1:return new cN;case 2:return new cI;case 3:return new cP;default:throw p7(new gL("No implementation is available for the layout phase "+(null!=e.f?e.f:""+e.g)))}}function ek9(e,t,n,r,i){var a;switch(a=0,i.g){case 1:a=eB4.Math.max(0,t.b+e.b-(n.b+r));break;case 3:a=eB4.Math.max(0,-e.b-r);break;case 2:a=eB4.Math.max(0,-e.a-r);break;case 4:a=eB4.Math.max(0,t.a+e.a-(n.a+r))}return a}function ek8(e,t,n){var r,i,a,o,s;if(n)for(i=n.a.length,s=((r=new Fs(i)).b-r.a)*r.c<0?(_9(),eB3):new OR(r);s.Ob();)eXh in(a=KZ(n,(o=Pp(s.Pb(),19)).a)).a||eXp in a.a?eId(e,a,t):eBe(e,a,t),Om(Pp(Bp(e.b,ehM(a)),79))}function ek7(e){var t,n;switch(e.b){case -1:return!0;case 0:if((n=e.t)>1||-1==n||(t=evl(e))&&(_4(),t.Cj()==eJK))return e.b=-1,!0;return e.b=1,!1;default:return!1}}function exe(e,t){var n,r,i,a,o;for(i=0,r=(t.s||(t.s=new FQ(tm6,t,21,17)),t.s),a=null,o=r.i;i=0&&r=0?e._g(n,!0,!0):exk(e,i,!0),153),Pp(r,215).ll(t);throw p7(new gL(eZV+t.ne()+eZX))}function exc(){var e;return(_6(),tg9)?Pp(eMC((_Q(),tgp),eQc),1939):(x2(e1$,new ut),ej9(),e=Pp(M4(zg((_Q(),tgp),eQc),547)?zg(tgp,eQc):new Uh,547),tg9=!0,eBY(e),eB0(e),Um((_1(),tgm),e,new sM),Ge(tgp,eQc,e),e)}function exl(e,t){var n,r,i,a;e.j=-1,TO(e.e)?(n=e.i,a=0!=e.i,Zz(e,t),r=new Q$(e.e,3,e.c,null,t,n,a),i=t.Qk(e.e,e.c,null),(i=ey1(e,t,i))?(i.Ei(r),i.Fi()):eam(e.e,r)):(Zz(e,t),(i=t.Qk(e.e,e.c,null))&&i.Fi())}function exf(e,t){var n,r,i;if(i=0,(r=t[0])>=e.length)return -1;for(n=(GV(r,e.length),e.charCodeAt(r));n>=48&&n<=57&&(i=10*i+(n-48),!(++r>=e.length));)n=(GV(r,e.length),e.charCodeAt(r));return r>t[0]?t[0]=r:i=-1,i}function exd(e){var t,n,r,i,a;return i=Pp(e.a,19).a,a=Pp(e.b,19).a,n=i,r=a,t=eB4.Math.max(eB4.Math.abs(i),eB4.Math.abs(a)),i<=0&&i==a?(n=0,r=a-1):i==-t&&a!=t?(n=a,r=i,a>=0&&++n):(n=-a,r=i),new kD(ell(n),ell(r))}function exh(e,t,n,r){var i,a,o,s,u,c;for(i=0;i=0&&c>=0&&u=e.i)throw p7(new gE(eXU+t+eXH+e.i));if(n>=e.i)throw p7(new gE(eX$+n+eXH+e.i));return r=e.g[n],t!=n&&(t>16))>>16&16),e>>=t,n+=t=(r=e-256)>>16&8,e<<=t,n+=t=(r=e-eH0)>>16&4,e<<=t,n+=t=(r=e-eUR)>>16&2,e<<=t,n+2-(t=(r=e>>14)&~(r>>1)))}function exy(e){var t,n,r,i;for(HR(),e9n=new p0,e9t=new p2,e9e=new p0,t=(e.a||(e.a=new FQ(e6k,e,10,11)),e.a),eYE(t),i=new Ow(t);i.e!=i.i.gc();)r=Pp(epH(i),33),-1==QI(e9n,r,0)&&(n=new p0,P_(e9e,n),epi(r,n));return e9e}function exw(e,t,n){var r,i,a,o;e.a=n.b.d,M4(t,352)?(i=eLO(Pp(t,79),!1,!1),a=eEF(i),qX(a,r=new d_(e)),eNI(a,i),null!=t.We((eBB(),thg))&&qX(Pp(t.We(thg),74),r)):((o=Pp(t,470)).Hg(o.Dg()+e.a.a),o.Ig(o.Eg()+e.a.b))}function ex_(e,t){var n,r,i,a,o,s,u,c;for(s=1,c=gP(LV(e_k(t,(eBy(),toH)))),u=e[0].n.a+e[0].o.a+e[0].d.c+c;s=0)?n:(s=B$(C6(new kl(o.c+o.b/2,o.d+o.a/2),new kl(a.c+a.b/2,a.d+a.a/2))),-(eDz(a,o)-1)*s)}function exS(e,t,n){var r;_r(new R1(null,(n.a||(n.a=new FQ(e6v,n,6,6)),new Gq(n.a,16))),new kC(e,t)),_r(new R1(null,(n.n||(n.n=new FQ(e6S,n,1,7)),new Gq(n.n,16))),new kI(e,t)),(r=Pp(eT8(n,(eBB(),thg)),74))&&eil(r,e,t)}function exk(e,t,n){var r,i,a;if(a=eR3((eSp(),tvc),e.Tg(),t))return _4(),Pp(a,66).Oj()||(a=Wk(QZ(tvc,a))),i=Pp((r=e.Yg(a))>=0?e._g(r,!0,!0):exk(e,a,!0),153),Pp(i,215).hl(t,n);throw p7(new gL(eZV+t.ne()+eZX))}function exx(e,t,n,r){var i,a,o,s,u;if(i=e.d[t]){if(a=i.g,u=i.i,null!=r){for(s=0;s=n&&(r=t,o=(c=(u.c+u.a)/2)-n,u.c<=c-n&&(i=new N4(u.c,o),jO(e,r++,i)),(s=c+n)<=u.a&&(a=new N4(s,u.a),Gp(r,e.c.length),Ew(e.c,r,a)))}function exI(e){var t;if(e.c||null!=e.g){if(null==e.g)return!0;if(0==e.i)return!1;t=Pp(e.g[e.i-1],47)}else e.d=e.si(e.f),JL(e,e.d),t=e.d;return t==e.b&&null.km>=null.jm()?(eM5(e),exI(e)):t.Ob()}function exD(e,t,n){var r,i,a,o,s;if((s=n)||(s=P6(new mV,0)),ewG(s,eGA,1),ejY(e.c,t),1==(o=ejz(e.a,t)).gc())eRd(Pp(o.Xb(0),37),s);else for(a=1/o.gc(),i=o.Kc();i.Ob();)eRd(r=Pp(i.Pb(),37),eiI(s,a));vi(e.a,o,t),eL7(t),eEj(s)}function exN(e){if(this.a=e,e.c.i.k==(eEn(),e8C))this.c=e.c,this.d=Pp(e_k(e.c.i,(eBU(),tt1)),61);else if(e.d.i.k==e8C)this.c=e.d,this.d=Pp(e_k(e.d.i,(eBU(),tt1)),61);else throw p7(new gL("Edge "+e+" is not an external edge."))}function exP(e,t){var n,r,i;i=e.b,e.b=t,(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,3,i,e.b)),t?t!=e&&(er3(e,t.zb),enf(e,t.d),erc(e,null==(n=null==(r=t.c)?t.zb:r)||IE(n,t.zb)?null:n)):(er3(e,null),enf(e,0),erc(e,null))}function exR(e){var t,n;if(!e.f)return e.n=(o=null==(n=Pp(eaS(e.a,4),126))?0:n.length))throw p7(new Ii(t,o));return i=n[t],1==o?r=null:(r=Je(e6N,eJM,415,o-1,0,1),ePD(n,0,r,0,t),(a=o-t-1)>0&&ePD(n,t+1,r,t,a)),eps(e,r),eSU(e,t,i),i}function ex$(){ex$=A,tvw=Pp(etj(H9((yL(),tvS).qb),6),34),tvg=Pp(etj(H9(tvS.qb),3),34),tvv=Pp(etj(H9(tvS.qb),4),34),tvy=Pp(etj(H9(tvS.qb),5),18),eyD(tvw),eyD(tvg),eyD(tvv),eyD(tvy),tv_=new g$(eow(vx(tm6,1),eJ4,170,0,[tvw,tvg]))}function exz(e,t){var n;this.d=new mh,this.b=t,this.e=new TS(t.qf()),n=e.u.Hc((ekU(),tbb)),e.u.Hc(tbp)?e.D?this.a=n&&!t.If():this.a=!0:e.u.Hc(tbm)&&n?this.a=!(t.zf().Kc().Ob()||t.Bf().Kc().Ob()):this.a=!1}function exG(e,t){var n,r,i,a;for(n=e.o.a,a=Pp(Pp(Zq(e.r,t),21),84).Kc();a.Ob();)(i=Pp(a.Pb(),111)).e.a=(r=i.b).Xe((eBB(),thK))?r.Hf()==(eYu(),tbY)?-r.rf().a-gP(LV(r.We(thK))):n+gP(LV(r.We(thK))):r.Hf()==(eYu(),tbY)?-r.rf().a:n}function exW(e,t){var n,r,i,a;n=Pp(e_k(e,(eBy(),tal)),103),a=Pp(eT8(t,tob),61),(i=Pp(e_k(e,tol),98))!=(ewf(),tbc)&&i!=tbl?a==(eYu(),tbF)&&(a=eNh(t,n))==tbF&&(a=ef9(n)):a=(r=eRl(t))>0?ef9(n):elC(ef9(n)),ebu(t,tob,a)}function exK(e,t){var n,r,i,a,o;for(o=e.j,t.a!=t.b&&Mv(o,new ia),i=o.c.length/2|0,r=0;r0&&eIl(e,n,t),a):null!=r.a?(eIl(e,t,n),-1):null!=i.a?(eIl(e,n,t),1):0}function exq(e,t){var n,r,i,a;e.ej()?(n=e.Vi(),a=e.fj(),++e.j,e.Hi(n,e.oi(n,t)),r=e.Zi(3,null,t,n,a),e.bj()&&(i=e.cj(t,null))?(i.Ei(r),i.Fi()):e.$i(r)):(BD(e,t),e.bj()&&(i=e.cj(t,null))&&i.Fi())}function exZ(e,t){var n,r,i,a,o;for(o=eAY(e.e.Tg(),t),i=new o7,n=Pp(e.g,119),a=e.i;--a>=0;)r=n[a],o.rl(r.ak())&&JL(i,r);!eYK(e,i)&&TO(e.e)&&bz(e,t.$j()?$N(e,6,t,(Hj(),e2r),null,-1,!1):$N(e,t.Kj()?2:1,t,null,null,-1,!1))}function exX(){var e,t;for(t=0,exX=A,e2t=Je(e0t,eUP,91,32,0,1),e2n=Je(e0t,eUP,91,32,0,1),e=1;t<=18;t++)e2t[t]=ep_(e),e2n[t]=ep_(Fg(e,t)),e=efn(e,5);for(;to)))&&(!t.q||(o=(r=t.C).c.c.a-r.o.a/2,!((i=r.n.a-n)>o))))}function exQ(e,t){var n;ewG(t,"Partition preprocessing",1),n=Pp(qE(UJ(eeh(UJ(new R1(null,new Gq(e.a,16)),new nZ),new nX),new nJ),JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[(eum(),e2U)]))),15),_r(n.Oc(),new nQ),eEj(t)}function ex1(e){var t,n,r,i,a,o,s;for(Gk(),n=new qh,i=new fz(e.e.b);i.a1?e.e*=gP(e.a):e.f/=gP(e.a),eu0(e),ehK(e),eCj(e),eo3(e.b,(epz(),e62),e.g)}function ex9(e,t,n){var r,i,a,o,s,u;for(r=0,u=n,t||(r=n*(e.c.length-1),u*=-1),a=new fz(e);a.a=0?(!t&&(t=new vu,r>0&&xk(t,e.substr(0,r))),t.a+="\\",Bf(t,n&eHd)):t&&Bf(t,n&eHd);return t?t.a:e}function eTh(e){var t;if(!e.a)throw p7(new gC("IDataType class expected for layout option "+e.f));if(null==(t=VN(e.a)))throw p7(new gC("Couldn't create new instance of property '"+e.f+"'. "+eq4+(LW(e6D),e6D.k)+eq5));return Pp(t,414)}function eTp(e){var t,n,r,i,a;return(a=e.eh())&&a.kh()&&(i=ecv(e,a))!=a?(n=e.Vg(),r=(t=e.Vg())>=0?e.Qg(null):e.eh().ih(e,-1-t,null,null),e.Rg(Pp(i,49),n),r&&r.Fi(),e.Lg()&&e.Mg()&&n>-1&&eam(e,new FX(e,9,n,a,i)),i):a}function eTb(e){var t,n,r,i,a,o,s,u;for(r=0,o=0,a=e.f.e;r>5)>=e.d)return e.e<0;if(n=e.a[i],t=1<<(31&t),e.e<0){if(i<(r=eiU(e)))return!1;n=r==i?-n:~n}return(n&t)!=0}function eT_(e,t,n,r){var i;Pp(n.b,65),Pp(n.b,65),Pp(r.b,65),Pp(r.b,65),P9(i=C6(MB(Pp(n.b,65).c),Pp(r.b,65).c),ekg(Pp(n.b,65),Pp(r.b,65),i)),Pp(r.b,65),Pp(r.b,65),Pp(r.b,65).c.a,i.a,Pp(r.b,65).c.b,i.b,Pp(r.b,65),ety(r.a,new N9(e,t,r))}function eTE(e,t){var n,r,i,a,o,s,u;if(a=t.e){for(o=0,n=eTp(a),r=Pp(e.g,674);o>16)),15).Xc(a))0&&(Tk(e.a.c)&&t.n.d||Tx(e.a.c)&&t.n.b||(t.g.d+=eB4.Math.max(0,r/2-.5)),Tk(e.a.c)&&t.n.a||Tx(e.a.c)&&t.n.c||(t.g.a-=r-1))}function eTO(e){var t,n,r,i,a;if(i=new p0,a=eDC(e,i),t=Pp(e_k(e,(eBU(),tng)),10))for(r=new fz(t.j);r.a>t,a=e.m>>t|n<<22-t,i=e.l>>t|e.m<<22-t):t<44?(o=r?eH$:0,a=n>>t-22,i=e.m>>t-22|n<<44-t):(o=r?eH$:0,a=r?eHH:0,i=n>>t-44),Mk(i&eHH,a&eHH,o&eH$)}function eTI(e){var t,n,r,i,a,o;for(this.c=new p0,this.d=e,r=eHQ,i=eHQ,t=eH1,n=eH1,o=epL(e,0);o.b!=o.d.c;)a=Pp(Vv(o),8),r=eB4.Math.min(r,a.a),i=eB4.Math.min(i,a.b),t=eB4.Math.max(t,a.a),n=eB4.Math.max(n,a.b);this.a=new Hr(r,i,t-r,n-i)}function eTD(e,t){var n,r,i,a,o,s;for(a=new fz(e.b);a.a0&&M4(t,42)&&(e.a.qj(),a=null==(u=(c=Pp(t,42)).cd())?0:esj(u),o=Cb(e.a,a),n=e.a.d[o])){for(s=0,r=Pp(n.g,367),l=n.i;s=2)for(t=LV((n=i.Kc()).Pb());n.Ob();)a=t,t=LV(n.Pb()),r=eB4.Math.min(r,(BJ(t),t-(BJ(a),a)));return r}function eTX(e,t){var n,r,i,a,o;qQ(r=new _n,t,r.c.b,r.c);do for(n=(A6(0!=r.b),Pp(etw(r,r.a.a),86)),e.b[n.g]=1,a=epL(n.d,0);a.b!=a.d.c;)o=(i=Pp(Vv(a),188)).c,1==e.b[o.g]?P7(e.a,i):2==e.b[o.g]?e.b[o.g]=1:qQ(r,o,r.c.b,r.c);while(0!=r.b)}function eTJ(e,t){var n,r,i;if(xc(t)===xc(Y9(e)))return!0;if(!M4(t,15)||(r=Pp(t,15),(i=e.gc())!=r.gc()))return!1;if(!M4(r,54))return eb3(e.Kc(),r.Kc());for(n=0;n0&&(i=n),o=new fz(e.f.e);o.a0?(t-=1,n-=1):r>=0&&i<0?(t+=1,n+=1):r>0&&i>=0?(t-=1,n+=1):(t+=1,n-=1),new kD(ell(t),ell(n))}function eMf(e,t){if(e.ct.c)return 1;if(e.bt.b)return 1;if(e.a!=t.a)return esj(e.a)-esj(t.a);else if(e.d==(qG(),tuf)&&t.d==tul)return -1;else if(e.d==tul&&t.d==tuf)return 1;return 0}function eMd(e,t){var n,r,i,a,o;return(o=(a=t.a).c.i==t.b?a.d:a.c,r=a.c.i==t.b?a.c:a.d,(i=edI(e.a,o,r))>0&&i0):i<0&&-i0)}function eMh(e,t,n,r){var i,a,o,s,u,c,l,f;for(i=(t-e.d)/e.c.c.length,a=0,e.a+=n,e.d=t,f=new fz(e.c);f.a>24;return o}function eMb(e){if(e.pe()){var t=e.c;t.qe()?e.o="["+t.n:t.pe()?e.o="["+t.ne():e.o="[L"+t.ne()+";",e.b=t.me()+"[]",e.k=t.oe()+"[]";return}var n=e.j,r=e.d;r=r.split("/"),e.o=ehg(".",[n,ehg("$",r)]),e.b=ehg(".",[n,ehg(".",r)]),e.k=r[r.length-1]}function eMm(e,t){var n,r,i,a,o;for(o=null,a=new fz(e.e.a);a.a=0;t-=2)for(n=0;n<=t;n+=2)(e.b[n]>e.b[n+2]||e.b[n]===e.b[n+2]&&e.b[n+1]>e.b[n+3])&&(r=e.b[n+2],e.b[n+2]=e.b[n],e.b[n]=r,r=e.b[n+3],e.b[n+3]=e.b[n+1],e.b[n+1]=r);e.c=!0}}function eMk(e,t){var n,r,i,a,o,s,u,c;for(a=(o=1==t?e8c:e8u).a.ec().Kc();a.Ob();)for(i=Pp(a.Pb(),103),u=Pp(Zq(e.f.c,i),21).Kc();u.Ob();)switch(s=Pp(u.Pb(),46),r=Pp(s.b,81),n=(c=Pp(s.a,189)).c,i.g){case 2:case 1:r.g.d+=n;break;case 4:case 3:r.g.c+=n}}function eMx(e,t){var n,r,i,a,o,s,u,c,l;for(s=0,c=-1,l=0,u=(o=e).length;s0&&++l;++c}return l}function eMT(e){var t,n;return n=new O0(yx(e.gm)),n.a+="@",xM(n,(t=esj(e)>>>0).toString(16)),e.kh()?(n.a+=" (eProxyURI: ",xT(n,e.qh()),e.$g()&&(n.a+=" eClass: ",xT(n,e.$g())),n.a+=")"):e.$g()&&(n.a+=" (eClass: ",xT(n,e.$g()),n.a+=")"),n.a}function eMM(e){var t,n,r,i;if(e.e)throw p7(new gC((LW(e2J),e$j+e2J.k+e$F)));for(e.d==(ec3(),tpv)&&eF_(e,tpm),n=new fz(e.a.a);n.a>24}return n}function eMD(e,t,n){var r,i,a;if(!(i=Pp(UA(e.i,t),306))){if(i=new etr(e.d,t,n),jT(e.i,t,i),ehj(t))Od(e.a,t.c,t.b,i);else switch(a=eSv(t),r=Pp(UA(e.p,a),244),a.g){case 1:case 3:i.j=!0,gh(r,t.b,i);break;case 4:case 2:i.k=!0,gh(r,t.c,i)}}return i}function eMN(e,t,n,r){var i,a,o,s,u,c;if(s=new o7,u=eAY(e.e.Tg(),t),i=Pp(e.g,119),_4(),Pp(t,66).Oj())for(o=0;o=0)return i;for(a=1,s=new fz(t.j);s.a0&&t.ue((GK(i-1,e.c.length),Pp(e.c[i-1],10)),a)>0;)q1(e,i,(GK(i-1,e.c.length),Pp(e.c[i-1],10))),--i;GK(i,e.c.length),e.c[i]=a}n.a=new p2,n.b=new p2}function eMj(e,t,n){var r,i,a,o,s,u,c,l;for(o=0,l=(r=Pp(t.e&&t.e(),9),new I1(r,Pp(CY(r,r.length),9),0)),s=(a=u=eIk(n,"[\\[\\]\\s,]+")).length;o0&&(Tk(e.a.c)&&t.n.d||Tx(e.a.c)&&t.n.b||(t.g.d-=eB4.Math.max(0,r/2-.5)),Tk(e.a.c)&&t.n.a||Tx(e.a.c)&&t.n.c||(t.g.a+=eB4.Math.max(0,r-1)))}function eMY(e,t,n){var r,i;if((e.c-e.b&e.a.length-1)==2)t==(eYu(),tbw)||t==tby?(etf(Pp(eso(e),15),(egF(),tpV)),etf(Pp(eso(e),15),tpq)):(etf(Pp(eso(e),15),(egF(),tpq)),etf(Pp(eso(e),15),tpV));else for(i=new UN(e);i.a!=i.b;)etf(r=Pp(ecn(i),15),n)}function eMB(e,t){var n,r,i,a,o,s,u;for(i=Pb(new pL(e)),s=new KB(i,i.c.length),a=Pb(new pL(t)),u=new KB(a,a.c.length),o=null;s.b>0&&u.b>0;)if((n=(A6(s.b>0),Pp(s.a.Xb(s.c=--s.b),33)))==(r=(A6(u.b>0),Pp(u.a.Xb(u.c=--u.b),33))))o=n;else break;return o}function eMU(e,t){var n,r,i,a,o,s;return(a=e.a*e$d+1502*e.b,s=e.b*e$d+11,a+=n=eB4.Math.floor(s*e$h),s-=n*e$p,a%=e$p,e.a=a,e.b=s,t<=24)?eB4.Math.floor(e.a*e2v[t]):((r=(i=e.a*(1<=2147483648&&(r-=eH7),r)}function eMH(e,t,n){var r,i,a,o;WY(e,t)>WY(e,n)?(r=efr(n,(eYu(),tby)),e.d=r.dc()?0:Rk(Pp(r.Xb(0),11)),o=efr(t,tbY),e.b=o.dc()?0:Rk(Pp(o.Xb(0),11))):(i=efr(n,(eYu(),tbY)),e.d=i.dc()?0:Rk(Pp(i.Xb(0),11)),a=efr(t,tby),e.b=a.dc()?0:Rk(Pp(a.Xb(0),11)))}function eM$(e){var t,n,r,i,a,o,s;if(e&&(t=e.Hh(eQc))&&null!=(o=Lq(edW((t.b||(t.b=new L_((eBK(),tgF),tgf,t)),t.b),"conversionDelegates")))){for(s=new p0,r=eIk(o,"\\w+"),i=0,a=r.length;ie.c);o++)i.a>=e.s&&(a<0&&(a=o),s=o);return u=(e.s+e.c)/2,a>=0&&(r=eIe(e,t,a,s),u=_V((GK(r,t.c.length),Pp(t.c[r],329))),exC(t,r,n)),u}function eMK(){eMK=A,tlK=new T2((eBB(),td2),1.3),tlX=thc,tfe=new T3(15),tl7=new T2(thN,tfe),tfr=new T2(tpl,15),tlV=td9,tl3=thx,tl4=thO,tl5=thL,tl2=thS,tl6=thD,tft=thJ,tl8=(eTU(),tl$),tl0=tlU,tl9=tlH,tfn=tlG,tlJ=tlB,tlQ=thb,tl1=thm,tlZ=tlY,tlq=tlF,tfi=tlW}function eMV(e,t,n){var r,i,a,o,s,u,c;for(erl(o=a=new sa,(BJ(t),t)),c=(o.b||(o.b=new L_((eBK(),tgF),tgf,o)),o.b),u=1;u0&&eRJ(this,i)}function eMZ(e,t,n,r,i,a){var o,s,u;if(!i[t.b]){for(i[t.b]=!0,(o=r)||(o=new Z5),P_(o.e,t),u=a[t.b].Kc();u.Ob();)(s=Pp(u.Pb(),282)).d!=n&&s.c!=n&&(s.c!=t&&eMZ(e,s.c,t,o,i,a),s.d!=t&&eMZ(e,s.d,t,o,i,a),P_(o.c,s),eoc(o.d,s.b));return o}return null}function eMX(e){var t,n,r,i,a,o,s;for(t=0,i=new fz(e.e);i.a=2}function eMJ(e,t){var n,r,i,a;for(ewG(t,"Self-Loop pre-processing",1),r=new fz(e.a);r.a1)&&(t=jL(tp1,eow(vx(e6t,1),eU4,93,0,[tpQ,tp2])),!(eaC(z_(t,e))>1)&&(r=jL(tp9,eow(vx(e6t,1),eU4,93,0,[tp6,tp5])),!(eaC(z_(r,e))>1)))}function eM0(e,t){var n,r,i;return(n=t.Hh(e.a))&&null!=(i=Lq(edW((n.b||(n.b=new L_((eBK(),tgF),tgf,n)),n.b),"affiliation")))?-1==(r=O8(i,e_n(35)))?elp(e,Fr(e,etP(t.Hj())),i):0==r?elp(e,null,i.substr(1)):elp(e,i.substr(0,r),i.substr(r+1)):null}function eM2(e){var t,n,r;try{return null==e?eUg:efF(e)}catch(i){if(i=eoa(i),M4(i,102))return t=i,r=yx(esF(e))+"@"+(n=(wK(),ebh(e)>>>0)).toString(16),epa(eob(),(_g(),"Exception during lenientFormat for "+r),t),"<"+r+" threw "+yx(t.gm)+">";throw p7(i)}}function eM3(e){switch(e.g){case 0:return new ck;case 1:return new cy;case 2:return new _j;case 3:return new i$;case 4:return new CZ;case 5:return new cx;default:throw p7(new gL("No implementation is available for the layerer "+(null!=e.f?e.f:""+e.g)))}}function eM4(e,t,n){var r,i,a;for(a=new fz(e.t);a.a0&&(r.b.n-=r.c,r.b.n<=0&&r.b.u>0&&P7(t,r.b));for(i=new fz(e.i);i.a0&&(r.a.u-=r.c,r.a.u<=0&&r.a.n>0&&P7(n,r.a))}function eM5(e){var t,n,r,i,a;if(null==e.g&&(e.d=e.si(e.f),JL(e,e.d),e.c))return e.f;if(i=(t=Pp(e.g[e.i-1],47)).Pb(),e.e=t,(n=e.si(i)).Ob())e.d=n,JL(e,n);else for(e.d=null;!t.Ob()&&(Bc(e.g,--e.i,null),0!=e.i);)t=r=Pp(e.g[e.i-1],47);return i}function eM6(e,t){var n,r,i,a,o,s;if(i=(r=t).ak(),eLt(e.e,i)){if(i.hi()&&Vq(e,i,r.dd()))return!1}else for(a=0,s=eAY(e.e.Tg(),i),n=Pp(e.g,119);a1||n>1)return 2;return t+n==1?2:0}function eOs(e,t,n){var r,i,a,o,s;for(ewG(n,"ELK Force",1),gN(LK(eT8(t,(eCk(),e9E))))||zh(r=new df((_q(),new gM(t)))),s=eo4(t),evn(s),esO(e,Pp(e_k(s,e9v),424)),a=(o=eNx(e.a,s)).Kc();a.Ob();)i=Pp(a.Pb(),231),eIL(e.b,i,eiI(n,1/o.gc()));s=eYC(o),eYh(s),eEj(n)}function eOu(e,t){var n,r,i,a,o;if(ewG(t,"Breaking Point Processor",1),eFM(e),gN(LK(e_k(e,(eBy(),toJ))))){for(i=new fz(e.b);i.a=0?e._g(r,!0,!0):exk(e,a,!0),153),Pp(i,215).ml(t,n)}else throw p7(new gL(eZV+t.ne()+eZq))}function eOp(e,t){var n,r,i,a,o;for(r=1,n=new p0,i=eeh(new R1(null,new Gq(e,16)),new aM),a=eeh(new R1(null,new Gq(e,16)),new aO),o=QN(Xg(U1(eAa(eow(vx(e2C,1),eUp,833,0,[i,a])),new aA)));r=2*t&&P_(n,new N4(o[r-1]+t,o[r]-t));return n}function eOb(e,t,n){ewG(n,"Eades radial",1),n.n&&t&&WG(n,KS(t),(eup(),tmr)),e.d=Pp(eT8(t,(Lj(),tcV)),33),e.c=gP(LV(eT8(t,(egj(),tl_)))),e.e=ebN(Pp(eT8(t,tlE),293)),e.a=ef7(Pp(eT8(t,tlk),426)),e.b=eyp(Pp(eT8(t,tlg),340)),evY(e),n.n&&t&&WG(n,KS(t),(eup(),tmr))}function eOm(e,t,n){var r,i,a,o,s,u,c,l;if(n)for(a=n.a.length,s=((r=new Fs(a)).b-r.a)*r.c<0?(_9(),eB3):new OR(r);s.Ob();)(i=KZ(n,(o=Pp(s.Pb(),19)).a))&&(eB8=null,u=Vj(e,(c=(yT(),l=new mk),t&&eOL(c,t),c),i),ert(u,KJ(i,eXS)),ewU(i,u),eka(i,u),esv(e,i,u))}function eOg(e){var t,n,r,i,a,o;if(!e.j){if(o=new sd,null==(a=(t=tgz).a.zc(e,t))){for(r=new Ow($E(e));r.e!=r.i.gc();)n=Pp(epH(r),26),i=eOg(n),Y4(o,i),JL(o,n);t.a.Bc(e)}euI(o),e.j=new xQ((Pp(etj(H9((BM(),tgv).o),11),18),o.i),o.g),Zd(e).b&=-33}return e.j}function eOv(e){var t,n,r,i;if(null==e)return null;if(r=ePh(e,!0),i=eQq.length,IE(r.substr(r.length-i,i),eQq)){if(4==(n=r.length)){if(43==(t=(GV(0,r.length),r.charCodeAt(0))))return tvX;if(45==t)return tvZ}else if(3==n)return tvX}return new bK(r)}function eOy(e){var t,n,r;return((n=e.l)&n-1)!=0||((r=e.m)&r-1)!=0||((t=e.h)&t-1)!=0||0==t&&0==r&&0==n?-1:0==t&&0==r&&0!=n?enq(n):0==t&&0!=r&&0==n?enq(r)+22:0!=t&&0==r&&0==n?enq(t)+44:-1}function eOw(e,t){var n,r,i,a,o;for(ewG(t,"Edge joining",1),n=gN(LK(e_k(e,(eBy(),toz)))),i=new fz(e.b);i.a1)for(i=new fz(e.a);i.a0),a.a.Xb(a.c=--a.b),CD(a,i),A6(a.becd(r,0)?(i=eHf-jE(edQ(QC(r),eHf)))==eHf&&(i=0):i=jE(edQ(r,eHf)),1==t?Bd(e,48+(i=eB4.Math.min((i+50)/100|0,9))&eHd):2==t?eeE(e,i=eB4.Math.min((i+5)/10|0,99),2):(eeE(e,i,3),t>3&&eeE(e,0,t-3))}function eOM(e){var t,n,r,i;return xc(e_k(e,(eBy(),taM)))===xc((eck(),tpz))?!e.e&&xc(e_k(e,tat))!==xc((eaU(),ttO)):(r=Pp(e_k(e,tan),292),i=gN(LK(e_k(e,tao)))||xc(e_k(e,tas))===xc((en7(),teR)),t=Pp(e_k(e,tae),19).a,n=e.a.c.length,!i&&r!=(eaU(),ttO)&&(0==t||t>n))}function eOO(e){var t,n;for(n=0;n0);n++);if(n>0&&n0);t++);return t>0&&n>16!=6&&t){if(eg7(e,t))throw p7(new gL(eZ4+ex2(e)));r=null,e.Cb&&(r=(n=e.Db>>16)>=0?eg1(e,r):e.Cb.ih(e,-1-n,null,r)),t&&(r=ep0(t,e,6,r)),(r=Cc(e,t,r))&&r.Fi()}else(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,6,t,t))}function eOL(e,t){var n,r;if(t!=e.Cb||e.Db>>16!=9&&t){if(eg7(e,t))throw p7(new gL(eZ4+eC5(e)));r=null,e.Cb&&(r=(n=e.Db>>16)>=0?eg2(e,r):e.Cb.ih(e,-1-n,null,r)),t&&(r=ep0(t,e,9,r)),(r=Cl(e,t,r))&&r.Fi()}else(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,9,t,t))}function eOC(e,t){var n,r;if(t!=e.Cb||e.Db>>16!=3&&t){if(eg7(e,t))throw p7(new gL(eZ4+ePY(e)));r=null,e.Cb&&(r=(n=e.Db>>16)>=0?evo(e,r):e.Cb.ih(e,-1-n,null,r)),t&&(r=ep0(t,e,12,r)),(r=Cu(e,t,r))&&r.Fi()}else(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,3,t,t))}function eOI(e){var t,n,r,i,a;if(r=evl(e),null==(a=e.j)&&r)return e.$j()?null:r.zj();if(M4(r,148)){if((n=r.Aj())&&(i=n.Nh())!=e.i){if((t=Pp(r,148)).Ej())try{e.g=i.Kh(t,a)}catch(o){if(o=eoa(o),M4(o,78))e.g=null;else throw p7(o)}e.i=i}return e.g}return null}function eOD(e){var t;return t=new p0,P_(t,new EL(new kl(e.c,e.d),new kl(e.c+e.b,e.d))),P_(t,new EL(new kl(e.c,e.d),new kl(e.c,e.d+e.a))),P_(t,new EL(new kl(e.c+e.b,e.d+e.a),new kl(e.c+e.b,e.d))),P_(t,new EL(new kl(e.c+e.b,e.d+e.a),new kl(e.c,e.d+e.a))),t}function eON(e,t,n,r){var i,a,o;if(o=eyn(t,n),r.c[r.c.length]=t,-1==e.j[o.p]||2==e.j[o.p]||e.a[t.p])return r;for(e.j[o.p]=-1,a=new Fa(OH(efs(o).a.Kc(),new c));eTk(a);)if(i=Pp(ZC(a),17),!q8(i)&&!(!q8(i)&&i.c.i.c==i.d.i.c)&&i!=t)return eON(e,i,o,r);return r}function eOP(e,t,n){var r,i,a;for(a=t.a.ec().Kc();a.Ob();)i=Pp(a.Pb(),79),(r=Pp(Bp(e.b,i),266))||(z$(e_I(i))==z$(e_P(i))?eLk(e,i,n):e_I(i)==z$(e_P(i))?null==Bp(e.c,i)&&null!=Bp(e.b,e_P(i))&&eFt(e,i,n,!1):null==Bp(e.d,i)&&null!=Bp(e.b,e_I(i))&&eFt(e,i,n,!0))}function eOR(e,t){var n,r,i,a,o,s,u;for(i=e.Kc();i.Ob();)for(r=Pp(i.Pb(),10),s=new eES,Gc(s,r),ekv(s,(eYu(),tby)),eo3(s,(eBU(),tnm),(OQ(),!0)),o=t.Kc();o.Ob();)a=Pp(o.Pb(),10),u=new eES,Gc(u,a),ekv(u,tbY),eo3(u,tnm,!0),n=new $b,eo3(n,tnm,!0),Gs(n,s),Go(n,u)}function eOj(e,t,n,r){var i,a,o,s;i=ehu(e,t,n),a=ehu(e,n,t),o=Pp(Bp(e.c,t),112),s=Pp(Bp(e.c,n),112),ir.b.g&&(a.c[a.c.length]=r);return a}function eOB(){eOB=A,tfo=new S9("CANDIDATE_POSITION_LAST_PLACED_RIGHT",0),tfa=new S9("CANDIDATE_POSITION_LAST_PLACED_BELOW",1),tfu=new S9("CANDIDATE_POSITION_WHOLE_DRAWING_RIGHT",2),tfs=new S9("CANDIDATE_POSITION_WHOLE_DRAWING_BELOW",3),tfc=new S9("WHOLE_DRAWING",4)}function eOU(e,t){if(M4(t,239))return elg(e,Pp(t,33));if(M4(t,186))return el$(e,Pp(t,118));if(M4(t,354))return Hd(e,Pp(t,137));if(M4(t,352))return eNP(e,Pp(t,79));if(t)return null;else throw p7(new gL(eXx+e_F(new g$(eow(vx(e1R,1),eUp,1,5,[t])))))}function eOH(e){var t,n,r,i,a,o,s;for(a=new _n,i=new fz(e.d.a);i.a1)for(t=Al((n=new b1,++e.b,n),e.d),s=epL(a,0);s.b!=s.d.c;)o=Pp(Vv(s),121),eAx(_f(_l(_d(_c(new bQ,1),0),t),o))}function eO$(e,t){var n,r;if(t!=e.Cb||e.Db>>16!=11&&t){if(eg7(e,t))throw p7(new gL(eZ4+eC4(e)));r=null,e.Cb&&(r=(n=e.Db>>16)>=0?evs(e,r):e.Cb.ih(e,-1-n,null,r)),t&&(r=ep0(t,e,10,r)),(r=C4(e,t,r))&&r.Fi()}else(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,11,t,t))}function eOz(e){var t,n,r,i;for(r=new esz(new fS(e.b).a);r.b;)n=etz(r),i=Pp(n.cd(),11),eo3(t=Pp(n.dd(),10),(eBU(),tnc),i),eo3(i,tng,t),eo3(i,tt6,(OQ(),!0)),ekv(i,Pp(e_k(t,tt1),61)),e_k(t,tt1),eo3(i.i,(eBy(),tol),(ewf(),tbu)),Pp(e_k(Bq(i.i),tt3),21).Fc((eLR(),ttS))}function eOG(e,t,n){var r,i,a,o,s,u;if(a=0,o=0,e.c)for(u=new fz(e.d.i.j);u.aa.a)?-1:i.a(u=null==e.d?0:e.d.length)))return!1;for(a=0,l=e.d,e.d=Je(e6C,eJA,63,2*u+4,0,1);a=0x7fffffffffffffff?(Q2(),e0L):(i=!1,e<0&&(i=!0,e=-e),r=0,e>=eHW&&(r=zy(e/eHW),e-=r*eHW),n=0,e>=eHG&&(n=zy(e/eHG),e-=n*eHG),a=Mk(t=zy(e),n,r),i&&esh(a),a)}function eO6(e,t){var n,r,i,a;for(n=!t||!e.u.Hc((ekU(),tbp)),a=0,i=new fz(e.e.Cf());i.a=-t&&r==t?new kD(ell(n-1),ell(r)):new kD(ell(n),ell(r-1))}function eAn(){return eB$(),eow(vx(e4B,1),eU4,77,0,[e85,e82,e86,e7d,e7C,e7m,e7j,e7_,e7A,e7s,e7x,e7w,e7L,e7r,e7Y,e8Z,e7k,e7D,e7h,e7I,e7U,e7M,e8X,e7O,e7H,e7P,e7B,e7p,e7e,e7b,e7f,e7F,e81,e88,e7v,e8Q,e7y,e7c,e7i,e7E,e7o,e83,e80,e7l,e7a,e7S,e7R,e8J,e7T,e7u,e7g,e7t,e87,e7N,e89,e7n,e84])}function eAr(e,t,n){e.d=0,e.b=0,t.k==(eEn(),e8P)&&n.k==e8P&&Pp(e_k(t,(eBU(),tnc)),10)==Pp(e_k(n,tnc),10)&&(QP(t).j==(eYu(),tbw)?eMH(e,t,n):eMH(e,n,t)),t.k==e8P&&n.k==e8D?QP(t).j==(eYu(),tbw)?e.d=1:e.b=1:n.k==e8P&&t.k==e8D&&(QP(n).j==(eYu(),tbw)?e.b=1:e.d=1),emu(e,t,n)}function eAi(e){var t,n,r,i,a,o,s,u,c,l,f;return f=ewW(e),(u=null!=(t=e.a))&&P4(f,"category",e.a),(o=!(i=wc(new fk(e.d))))&&(ee3(f,"knownOptions",c=new lN),n=new pS(c),qX(new fk(e.d),n)),(s=!(a=wc(e.g)))&&(ee3(f,"supportedFeatures",l=new lN),r=new pk(l),qX(e.g,r)),f}function eAa(e){var t,n,r,i,a,o,s,u,c;for(u=0,r=!1,t=336,n=0,a=new CE(e.length),c=(s=e).length;u>16!=7&&t){if(eg7(e,t))throw p7(new gL(eZ4+eE1(e)));r=null,e.Cb&&(r=(n=e.Db>>16)>=0?eg0(e,r):e.Cb.ih(e,-1-n,null,r)),t&&(r=Pp(t,49).gh(e,1,e6p,r)),(r=j2(e,t,r))&&r.Fi()}else(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,7,t,t))}function eAc(e,t){var n,r;if(t!=e.Cb||e.Db>>16!=3&&t){if(eg7(e,t))throw p7(new gL(eZ4+eln(e)));r=null,e.Cb&&(r=(n=e.Db>>16)>=0?eg4(e,r):e.Cb.ih(e,-1-n,null,r)),t&&(r=Pp(t,49).gh(e,0,e6y,r)),(r=j3(e,t,r))&&r.Fi()}else(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,3,t,t))}function eAl(e,t){var n,r,i,a,o,s,u,c,l;return(exX(),t.d>e.d&&(s=e,e=t,t=s),t.d<63)?eLm(e,t):(o=(-2&e.d)<<4,c=ZL(e,o),l=ZL(t,o),r=eNz(e,ZA(c,o)),i=eNz(t,ZA(l,o)),u=eAl(c,l),n=eAl(r,i),a=eAl(eNz(c,r),eNz(i,l)),a=eP5(eP5(a,u),n),a=ZA(a,o),u=ZA(u,o<<1),eP5(eP5(u,a),n))}function eAf(e,t,n){var r,i,a,o,s;for(o=ecZ(e,n),s=Je(e4N,eGW,10,t.length,0,1),r=0,a=o.Kc();a.Ob();)gN(LK(e_k(i=Pp(a.Pb(),11),(eBU(),tt6))))&&(s[r++]=Pp(e_k(i,tng),10));if(r=0;a+=n?1:-1)o|=t.c.Sf(u,a,n,r&&!gN(LK(e_k(t.j,(eBU(),tt2))))&&!gN(LK(e_k(t.j,(eBU(),tnS))))),o|=t.q._f(u,a,n),o|=eCA(e,u[a],n,r);return Yf(e.c,t),o}function eAm(e,t,n){var r,i,a,o,s,u,c,l,f,d;for(l=Kz(e.j),f=0,d=l.length;f1&&(e.a=!0),jU(Pp(n.b,65),C5(MB(Pp(t.b,65).c),Ol(C6(MB(Pp(n.b,65).a),Pp(t.b,65).a),i))),GC(e,t),eAy(e,n)}function eAw(e){var t,n,r,i,a,o,s;for(a=new fz(e.a.a);a.a0&&a>0?o.p=t++:r>0?o.p=n++:a>0?o.p=i++:o.p=n++}Hj(),Mv(e.j,new nG)}function eAE(e){var t,n;n=null,t=Pp(RJ(e.g,0),17);do{if(Ln(n=t.d.i,(eBU(),tna)))return Pp(e_k(n,tna),11).i;if(n.k!=(eEn(),e8N)&&eTk(new Fa(OH(efc(n).a.Kc(),new c))))t=Pp(ZC(new Fa(OH(efc(n).a.Kc(),new c))),17);else if(n.k!=e8N)return null}while(!!n&&n.k!=(eEn(),e8N))return n}function eAS(e,t){var n,r,i,a,o,s,u,c,l;for(a=1,s=t.j,o=t.g,c=em1(e,o,u=Pp(RJ(s,s.c.length-1),113),l=(GK(0,s.c.length),Pp(s.c[0],113)));ac&&(u=n,l=i,c=r);t.a=l,t.c=u}function eAk(e,t){var n,r;if(!(r=YB(e.b,t.b)))throw p7(new gC("Invalid hitboxes for scanline constraint calculation."));(eop(t.b,Pp(CF(e.b,t.b),57))||eop(t.b,Pp(Cj(e.b,t.b),57)))&&(wK(),t.b),e.a[t.b.f]=Pp(Ik(e.b,t.b),57),(n=Pp(IS(e.b,t.b),57))&&(e.a[n.f]=t.b)}function eAx(e){if(!e.a.d||!e.a.e)throw p7(new gC((LW(e23),e23.k+" must have a source and target "+(LW(e24),e24.k)+" specified.")));if(e.a.d==e.a.e)throw p7(new gC("Network simplex does not support self-loops: "+e.a+" "+e.a.d+" "+e.a.e));return Am(e.a.d.g,e.a),Am(e.a.e.b,e.a),e.a}function eAT(e,t,n){var r,i,a,o,s,u,c;for(c=new yB(new hA(e)),o=eow(vx(e4j,1),eGK,11,0,[t,n]),s=0,u=o.length;su-e.b&&su-e.a&&s0&&++h;++d}return h}function eAF(e,t){var n,r,i,a,o;for(o=Pp(e_k(t,(eTj(),tcN)),425),a=epL(t.b,0);a.b!=a.d.c;)if(i=Pp(Vv(a),86),0==e.b[i.g]){switch(o.g){case 0:eb9(e,i);break;case 1:eTX(e,i)}e.b[i.g]=2}for(r=epL(e.a,0);r.b!=r.d.c;)eds((n=Pp(Vv(r),188)).b.d,n,!0),eds(n.c.b,n,!0);eo3(t,(eR6(),tch),e.a)}function eAY(e,t){var n,r,i,a;return(_4(),t)?t==(eR7(),tvG)||(t==tvM||t==tvx||t==tvT)&&e!=tvk?new eF2(e,t):((n=(r=Pp(t,677)).pk())||(UH(QZ((eSp(),tvc),t)),n=r.pk()),a=(n.i||(n.i=new p2),n.i),(i=Pp(xu($I(a.f,e)),1942))||Um(a,e,i=new eF2(e,t)),i):tvb}function eAB(e,t){var n,r,i,a,o,s,u,c,l;for(a=0,u=Pp(e_k(e,(eBU(),tnc)),11),c=esp(eow(vx(e50,1),eUP,8,0,[u.i.n,u.n,u.a])).a,l=e.i.n.b,o=(i=n=Kp(e.e)).length;a0?a.a?n>(s=a.b.rf().a)&&(i=(n-s)/2,a.d.b=i,a.d.c=i):a.d.c=e.s+n:FY(e.u)&&((r=ew1(a.b)).c<0&&(a.d.b=-r.c),r.c+r.b>a.b.rf().a&&(a.d.c=r.c+r.b-a.b.rf().a))}function eAz(e,t){var n,r,i,a;for(ewG(t,"Semi-Interactive Crossing Minimization Processor",1),n=!1,i=new fz(e.b);i.a=0){if(t==n)return new kD(ell(-t-1),ell(-t-1));if(t==-n)return new kD(ell(-t),ell(n+1))}return eB4.Math.abs(t)>eB4.Math.abs(n)?t<0?new kD(ell(-t),ell(n)):new kD(ell(-t),ell(n+1)):new kD(ell(t+1),ell(n))}function eAK(e){var t,n;n=Pp(e_k(e,(eBy(),taY)),163),t=Pp(e_k(e,(eBU(),tt9)),303),n==(ef_(),tnN)?(eo3(e,taY,tnj),eo3(e,tt9,(Q1(),ttN))):n==tnR?(eo3(e,taY,tnj),eo3(e,tt9,(Q1(),ttI))):t==(Q1(),ttN)?(eo3(e,taY,tnN),eo3(e,tt9,ttD)):t==ttI&&(eo3(e,taY,tnR),eo3(e,tt9,ttD))}function eAV(){eAV=A,tuY=new ad,tuP=RI(new K2,(e_x(),e8n),(eB$(),e7h)),tuF=j0(RI(new K2,e8n,e7M),e8i,e7T),tuB=ehY(ehY(_G(j0(RI(new K2,e8e,e7j),e8i,e7R),e8r),e7P),e7F),tuR=j0(RI(RI(RI(new K2,e8t,e7m),e8r,e7v),e8r,e7y),e8i,e7g),tuj=j0(RI(RI(new K2,e8r,e7y),e8r,e88),e8i,e89)}function eAq(){eAq=A,tuz=RI(j0(new K2,(e_x(),e8i),(eB$(),e7t)),e8n,e7h),tuV=ehY(ehY(_G(j0(RI(new K2,e8e,e7j),e8i,e7R),e8r),e7P),e7F),tuG=j0(RI(RI(RI(new K2,e8t,e7m),e8r,e7v),e8r,e7y),e8i,e7g),tuK=RI(RI(new K2,e8n,e7M),e8i,e7T),tuW=j0(RI(RI(new K2,e8r,e7y),e8r,e88),e8i,e89)}function eAZ(e,t,n,r,i){var a,o;(q8(t)||t.c.i.c!=t.d.i.c)&&erS(esp(eow(vx(e50,1),eUP,8,0,[i.i.n,i.n,i.a])),n)||q8(t)||(t.c==i?Ls(t.a,0,new TS(n)):P7(t.a,new TS(n)),r&&!w0(e.a,n)&&((o=Pp(e_k(t,(eBy(),taR)),74))||eo3(t,taR,o=new mE),qQ(o,a=new TS(n),o.c.b,o.c),Yf(e.a,a)))}function eAX(e){var t,n;for(n=new Fa(OH(efu(e).a.Kc(),new c));eTk(n);)if((t=Pp(ZC(n),17)).c.i.k!=(eEn(),e8I))throw p7(new gq(eWr+egs(e)+"' has its layer constraint set to FIRST, but has at least one incoming edge that does not come from a FIRST_SEPARATE node. That must not happen."))}function eAJ(e,t,n){var r,i,a,o,s,u,c;if(0==(i=efp(254&e.Db)))e.Eb=n;else{if(1==i)s=Je(e1R,eUp,1,2,5,1),0==(a=emF(e,t))?(s[0]=n,s[1]=e.Eb):(s[0]=e.Eb,s[1]=n);else for(r=2,s=Je(e1R,eUp,1,i+1,5,1),o=etG(e.Eb),u=0,c=0;r<=128;r<<=1)r==t?s[c++]=n:(e.Db&r)!=0&&(s[c++]=o[u++]);e.Eb=s}e.Db|=t}function eAQ(e,t,n){var r,i,a,o;for(this.b=new p0,i=0,r=0,o=new fz(e);o.a0&&(i+=(a=Pp(RJ(this.b,0),167)).o,r+=a.p),i*=2,r*=2,t>1?i=zy(eB4.Math.ceil(i*t)):r=zy(eB4.Math.ceil(r/t)),this.a=new edL(i,r)}function eA1(e,t,n,r,i,a){var o,s,u,c,l,f,d,h,p,b,m,g;for(l=r,t.j&&t.o?(b=(h=Pp(Bp(e.f,t.A),57)).d.c+h.d.b,--l):b=t.a.c+t.a.b,f=i,n.q&&n.o?(c=(h=Pp(Bp(e.f,n.C),57)).d.c,++f):c=n.a.c,m=c-b,p=b+(s=m/(u=eB4.Math.max(2,f-l))),d=l;d=0;o+=i?1:-1){for(s=t[o],u=r==(eYu(),tby)?i?efr(s,r):eaa(efr(s,r)):i?eaa(efr(s,r)):efr(s,r),a&&(e.c[s.p]=u.gc()),f=u.Kc();f.Ob();)l=Pp(f.Pb(),11),e.d[l.p]=c++;eoc(n,u)}}function eA2(e,t,n){var r,i,a,o,s,u,c,l;for(a=gP(LV(e.b.Kc().Pb())),c=gP(LV(eaX(t.b))),l=C5(r=Ol(MB(e.a),c-n),i=Ol(MB(t.a),n-a)),Ol(l,1/(c-a)),this.a=l,this.b=new p0,s=!0,(o=e.b.Kc()).Pb();o.Ob();)u=gP(LV(o.Pb())),s&&u-n>eVW&&(this.b.Fc(n),s=!1),this.b.Fc(u);s&&this.b.Fc(n)}function eA3(e){var t,n,r,i;if(eIh(e,e.n),e.d.c.length>0){for(gG(e.c);eTT(e,Pp(Wx(new fz(e.e.a)),121))>5,t&=31,r>=e.d)return e.e<0?(eLQ(),e03):(eLQ(),e08);if(i=Je(ty_,eHT,25,(a=e.d-r)+1,15,1),eEG(i,a,e.a,r,t),e.e<0){for(n=0;n0&&e.a[n]<<32-t!=0){for(n=0;n=0)&&(!(n=eR3((eSp(),tvc),i,t))||((r=n.Zj())>1||-1==r)&&3!=Ur(QZ(tvc,n))))}function eLn(e,t,n,r){var i,a,o,s,u;return(s=ewH(Pp(etj((t.b||(t.b=new Ih(e6m,t,4,7)),t.b),0),82)),u=ewH(Pp(etj((t.c||(t.c=new Ih(e6m,t,5,8)),t.c),0),82)),z$(s)==z$(u)||etg(u,s))?null:(o=zF(t))==n?r:(a=Pp(Bp(e.a,o),10))&&(i=a.e)?i:null}function eLr(e,t){var n;switch(n=Pp(e_k(e,(eBy(),tam)),276),ewG(t,"Label side selection ("+n+")",1),n.g){case 0:eTD(e,(egF(),tpV));break;case 1:eTD(e,(egF(),tpq));break;case 2:eNW(e,(egF(),tpV));break;case 3:eNW(e,(egF(),tpq));break;case 4:eLL(e,(egF(),tpV));break;case 5:eLL(e,(egF(),tpq))}eEj(t)}function eLi(e,t,n){var r,i,a,o,s,u;if((o=e[r=vK(n,e.length)])[0].k==(eEn(),e8C))for(i=0,a=vW(n,o.length),u=t.j;i0&&(n[0]+=e.d,o-=n[0]),n[2]>0&&(n[2]+=e.d,o-=n[2]),a=eB4.Math.max(0,o),n[1]=eB4.Math.max(n[1],o),ZR(e,e3N,i.c+r.b+n[0]-(n[1]-o)/2,n),t==e3N&&(e.c.b=a,e.c.c=i.c+r.b+(a-o)/2)}function eLy(){this.c=Je(tyx,eH5,25,(eYu(),eow(vx(e6a,1),eGj,61,0,[tbF,tbw,tby,tbj,tbY])).length,15,1),this.b=Je(tyx,eH5,25,eow(vx(e6a,1),eGj,61,0,[tbF,tbw,tby,tbj,tbY]).length,15,1),this.a=Je(tyx,eH5,25,eow(vx(e6a,1),eGj,61,0,[tbF,tbw,tby,tbj,tbY]).length,15,1),Ep(this.c,eHQ),Ep(this.b,eH1),Ep(this.a,eH1)}function eLw(e,t,n){var r,i,a,o;if(t<=n?(i=t,a=n):(i=n,a=t),r=0,null==e.b)e.b=Je(ty_,eHT,25,2,15,1),e.b[0]=i,e.b[1]=a,e.c=!0;else{if(r=e.b.length,e.b[r-1]+1==i){e.b[r-1]=a;return}o=Je(ty_,eHT,25,r+2,15,1),ePD(e.b,0,o,0,r),e.b=o,e.b[r-1]>=i&&(e.c=!1,e.a=!1),e.b[r++]=i,e.b[r]=a,e.c||eMS(e)}}function eL_(e,t,n){var r,i,a,o,s,u,c;for(c=t.d,e.a=new XM(c.c.length),e.c=new p2,s=new fz(c);s.a=0?e._g(c,!1,!0):exk(e,n,!1),58);n:for(a=f.Kc();a.Ob();){for(l=0,i=Pp(a.Pb(),56);l1;)eLN(i,i.i-1);return r}function eLA(e,t){var n,r,i,a,o,s,u;for(ewG(t,"Comment post-processing",1),a=new fz(e.b);a.ae.d[o.p]&&(n+=qq(e.b,a),Vw(e.a,ell(a)));for(;!gY(e.a);)eek(e.b,Pp(Yn(e.a),19).a)}return n}function eLD(e,t,n){var r,i,a,o;for(a=(t.a||(t.a=new FQ(e6k,t,10,11)),t.a).i,i=new Ow((t.a||(t.a=new FQ(e6k,t,10,11)),t.a));i.e!=i.i.gc();)0==((r=Pp(epH(i),33)).a||(r.a=new FQ(e6k,r,10,11)),r.a).i||(a+=eLD(e,r,!1));if(n)for(o=z$(t);o;)a+=(o.a||(o.a=new FQ(e6k,o,10,11)),o.a).i,o=z$(o);return a}function eLN(e,t){var n,r,i,a;return e.ej()?(r=null,i=e.fj(),e.ij()&&(r=e.kj(e.pi(t),null)),n=e.Zi(4,a=egk(e,t),null,t,i),e.bj()&&null!=a?(r=e.dj(a,r))?(r.Ei(n),r.Fi()):e.$i(n):r?(r.Ei(n),r.Fi()):e.$i(n),a):(a=egk(e,t),e.bj()&&null!=a&&(r=e.dj(a,null))&&r.Fi(),a)}function eLP(e){var t,n,r,i,a,o,s,u,c,l;for(c=e.a,t=new bV,u=0,r=new fz(e.d);r.as.d&&(l=s.d+s.a+c));n.c.d=l,t.a.zc(n,t),u=eB4.Math.max(u,n.c.d+n.c.a)}return u}function eLR(){eLR=A,ttv=new Sv("COMMENTS",0),ttw=new Sv("EXTERNAL_PORTS",1),tt_=new Sv("HYPEREDGES",2),ttE=new Sv("HYPERNODES",3),ttS=new Sv("NON_FREE_PORTS",4),ttk=new Sv("NORTH_SOUTH_PORTS",5),ttT=new Sv(eWw,6),ttg=new Sv("CENTER_LABELS",7),tty=new Sv("END_LABELS",8),ttx=new Sv("PARTITIONS",9)}function eLj(e){var t,n,r,i,a;for(i=new p0,t=new Rq((e.a||(e.a=new FQ(e6k,e,10,11)),e.a)),r=new Fa(OH(eOi(e).a.Kc(),new c));eTk(r);)n=Pp(ZC(r),79),!M4(etj((n.b||(n.b=new Ih(e6m,n,4,7)),n.b),0),186)&&(a=ewH(Pp(etj((n.c||(n.c=new Ih(e6m,n,5,8)),n.c),0),82)),t.a._b(a)||(i.c[i.c.length]=a));return i}function eLF(e){var t,n,r,i,a,o;for(a=new bV,t=new Rq((e.a||(e.a=new FQ(e6k,e,10,11)),e.a)),i=new Fa(OH(eOi(e).a.Kc(),new c));eTk(i);)r=Pp(ZC(i),79),!M4(etj((r.b||(r.b=new Ih(e6m,r,4,7)),r.b),0),186)&&(o=ewH(Pp(etj((r.c||(r.c=new Ih(e6m,r,5,8)),r.c),0),82)),t.a._b(o)||(n=a.a.zc(o,a)));return a}function eLY(e,t,n,r,i){return r<0?((r=ew6(e,i,eow(vx(e17,1),eUP,2,6,[eHh,eHp,eHb,eHm,eHg,eHv,eHy,eHw,eH_,eHE,eHS,eHk]),t))<0&&(r=ew6(e,i,eow(vx(e17,1),eUP,2,6,["Jan","Feb","Mar","Apr",eHg,"Jun","Jul","Aug","Sep","Oct","Nov","Dec"]),t)),!(r<0)&&(n.k=r,!0)):r>0&&(n.k=r-1,!0)}function eLB(e,t,n,r,i){return r<0?((r=ew6(e,i,eow(vx(e17,1),eUP,2,6,[eHh,eHp,eHb,eHm,eHg,eHv,eHy,eHw,eH_,eHE,eHS,eHk]),t))<0&&(r=ew6(e,i,eow(vx(e17,1),eUP,2,6,["Jan","Feb","Mar","Apr",eHg,"Jun","Jul","Aug","Sep","Oct","Nov","Dec"]),t)),!(r<0)&&(n.k=r,!0)):r>0&&(n.k=r-1,!0)}function eLU(e,t,n,r,i,a){var o,s,u,c;if(s=32,r<0){if(t[0]>=e.length||43!=(s=UI(e,t[0]))&&45!=s||(++t[0],(r=exf(e,t))<0))return!1;45==s&&(r=-r)}return 32==s&&t[0]-n==2&&2==i.b&&(o=(c=(u=new wW).q.getFullYear()-eHx+eHx-80)%100,a.a=r==o,r+=(c/100|0)*100+(r=c&&(u=r);u&&(l=eB4.Math.max(l,u.a.o.a)),l>d&&(f=c,d=l)}return f}function eLV(e,t,n){var r,i,a;if(e.e=n,e.d=0,e.b=0,e.f=1,e.i=t,(16&e.e)==16&&(e.i=eIw(e.i)),e.j=e.i.length,eBM(e),a=ehT(e),e.d!=e.j)throw p7(new gX(eBJ((Mo(),eXV))));if(e.g){for(r=0;reqg?Mv(u,e.b):r<=eqg&&r>eqv?Mv(u,e.d):r<=eqv&&r>eqy?Mv(u,e.c):r<=eqy&&Mv(u,e.a),a=eLJ(e,u,a);return i}function eLQ(){var e;for(e=0,eLQ=A,e04=new XE(1,1),e06=new XE(1,10),e08=new XE(0,0),e03=new XE(-1,1),e05=eow(vx(e0t,1),eUP,91,0,[e08,e04,new XE(1,2),new XE(1,3),new XE(1,4),new XE(1,5),new XE(1,6),new XE(1,7),new XE(1,8),new XE(1,9),e06]),e09=Je(e0t,eUP,91,32,0,1);e1)&&(r=new kl(i,n.b),P7(t.a,r)),enD(t.a,eow(vx(e50,1),eUP,8,0,[d,f]))}function eL6(e){_Y(e,new ewB(vQ(vq(vJ(vX(new oc,eZA),"ELK Randomizer"),'Distributes the nodes randomly on the plane, leading to very obfuscating layouts. Can be useful to demonstrate the power of "real" layout algorithms.'),new oz))),KE(e,eZA,ezW,tb$),KE(e,eZA,eGi,15),KE(e,eZA,eGo,ell(0)),KE(e,eZA,ezG,eGt)}function eL9(){var e,t,n,r,i,a;for(t=0,eL9=A,tv1=Je(tyk,eZ8,25,255,15,1),tv0=Je(tyw,eHl,25,16,15,1);t<255;t++)tv1[t]=-1;for(n=57;n>=48;n--)tv1[n]=n-48<<24>>24;for(r=70;r>=65;r--)tv1[r]=r-65+10<<24>>24;for(i=102;i>=97;i--)tv1[i]=i-97+10<<24>>24;for(a=0;a<10;a++)tv0[a]=48+a&eHd;for(e=10;e<=15;e++)tv0[e]=65+e-10&eHd}function eL8(e,t,n){var r,i,a,o,s,u,c,l;return s=t.i-e.g/2,u=n.i-e.g/2,c=t.j-e.g/2,l=n.j-e.g/2,a=t.g+e.g/2,o=n.g+e.g/2,r=t.f+e.g/2,i=n.f+e.g/2,!!(s>19!=0)return"-"+eCr(eoQ(e));for(n=e,r="";!(0==n.l&&0==n.m&&0==n.h);){if(n=eRV(n,i=Zx(eHK),!0),t=""+yq(e0A),!(0==n.l&&0==n.m&&0==n.h))for(a=9-t.length;a>0;a--)t="0"+t;r=t+r}return r}function eCi(){if(!Object.create||!Object.getOwnPropertyNames)return!1;var e="__proto__",t=Object.create(null);return void 0===t[e]&&0==Object.getOwnPropertyNames(t).length&&(t[e]=42,42===t[e]&&0!=Object.getOwnPropertyNames(t).length)}function eCa(e){var t,n,r,i,a,o,s;for(t=!1,n=0,i=new fz(e.d.b);i.a=e.a||!ewg(t,n))return -1;if(Vb(Pp(r.Kb(t),20)))return 1;for(i=0,o=Pp(r.Kb(t),20).Kc();o.Ob();)if(-1==(s=eCu(e,u=(a=Pp(o.Pb(),17)).c.i==t?a.d.i:a.c.i,n,r))||(i=eB4.Math.max(i,s))>e.c-1)return -1;return i+1}function eCc(e,t){var n,r,i,a,o,s;if(xc(t)===xc(e))return!0;if(!M4(t,15)||(r=Pp(t,15),s=e.gc(),r.gc()!=s))return!1;if(o=r.Kc(),e.ni()){for(n=0;n0){if(e.qj(),null!=t){for(a=0;a>24;case 97:case 98:case 99:case 100:case 101:case 102:return e-97+10<<24>>24;case 65:case 66:case 67:case 68:case 69:case 70:return e-65+10<<24>>24;default:throw p7(new vo("Invalid hexadecimal"))}}function eCh(e,t,n){var r,i,a,o;for(ewG(n,"Processor order nodes",2),e.a=gP(LV(e_k(t,(eTj(),tcR)))),i=new _n,o=epL(t.b,0);o.b!=o.d.c;)gN(LK(e_k(a=Pp(Vv(o),86),(eR6(),tcm))))&&qQ(i,a,i.c.b,i.c);eRt(e,r=(A6(0!=i.b),Pp(i.a.a.c,86))),n.b||erd(n,1),eC1(e,r,0-gP(LV(e_k(r,(eR6(),tcu))))/2,0),n.b||erd(n,1),eEj(n)}function eCp(){eCp=A,e3C=new Ej("SPIRAL",0),e3T=new Ej("LINE_BY_LINE",1),e3M=new Ej("MANHATTAN",2),e3x=new Ej("JITTER",3),e3A=new Ej("QUADRANTS_LINE_BY_LINE",4),e3L=new Ej("QUADRANTS_MANHATTAN",5),e3O=new Ej("QUADRANTS_JITTER",6),e3k=new Ej("COMBINE_LINE_BY_LINE_MANHATTAN",7),e3S=new Ej("COMBINE_JITTER_MANHATTAN",8)}function eCb(e,t,n,r){var i,a,o,s,u,c;for(u=eya(e,n),c=eya(t,n),i=!1;u&&c;)if(r||egl(u,c,n))o=eya(u,n),s=eya(c,n),QB(t),QB(e),a=u.c,ejf(u,!1),ejf(c,!1),n?(egU(t,c.p,a),t.p=c.p,egU(e,u.p+1,a),e.p=u.p):(egU(e,u.p,a),e.p=u.p,egU(t,c.p+1,a),t.p=c.p),Gu(u,null),Gu(c,null),u=o,c=s,i=!0;else break;return i}function eCm(e,t,n,r){var i,a,o,s,u;for(i=!1,a=!1,s=new fz(r.j);s.a=t.length)throw p7(new gE("Greedy SwitchDecider: Free layer not in graph."));this.c=t[e],this.e=new IQ(r),er$(this.e,this.c,(eYu(),tbY)),this.i=new IQ(r),er$(this.i,this.c,tby),this.f=new jy(this.c),this.a=!a&&i.i&&!i.s&&this.c[0].k==(eEn(),e8C),this.a&&eSt(this,e,t.length)}function eC_(e,t){var n,r,i,a,o,s;a=!e.B.Hc((eI3(),tbX)),o=e.B.Hc(tb1),e.a=new edA(o,a,e.c),e.n&&HI(e.a.n,e.n),gh(e.g,(etx(),e3N),e.a),t||((r=new eh6(1,a,e.c)).n.a=e.k,jT(e.p,(eYu(),tbw),r),(i=new eh6(1,a,e.c)).n.d=e.k,jT(e.p,tbj,i),(s=new eh6(0,a,e.c)).n.c=e.k,jT(e.p,tbY,s),(n=new eh6(0,a,e.c)).n.b=e.k,jT(e.p,tby,n))}function eCE(e){var t,n,r;switch((t=Pp(e_k(e.d,(eBy(),tag)),218)).g){case 2:n=eBn(e);break;case 3:n=(r=new p0,_r(UJ(UQ(eeh(eeh(new R1(null,new Gq(e.d.b,16)),new rJ),new rQ),new r1),new rY),new ha(r)),r);break;default:throw p7(new gC("Compaction not supported for "+t+" edges."))}eRD(e,n),qX(new fk(e.g),new hr(e))}function eCS(e,t){var n;return(n=new eX,t&&eaW(n,Pp(Bp(e.a,e6p),94)),M4(t,470)&&eaW(n,Pp(Bp(e.a,e6b),94)),M4(t,354))?(eaW(n,Pp(Bp(e.a,e6S),94)),n):(M4(t,82)&&eaW(n,Pp(Bp(e.a,e6m),94)),M4(t,239))?(eaW(n,Pp(Bp(e.a,e6k),94)),n):M4(t,186)?(eaW(n,Pp(Bp(e.a,e6x),94)),n):(M4(t,352)&&eaW(n,Pp(Bp(e.a,e6g),94)),n)}function eCk(){eCk=A,e9M=new T2((eBB(),th4),ell(1)),e9D=new T2(tpl,80),e9I=new T2(tpr,5),e9p=new T2(td2,eGt),e9O=new T2(th5,ell(1)),e9C=new T2(th8,(OQ(),!0)),e9k=new T3(50),e9S=new T2(thN,e9k),e9m=thb,e9x=thV,e9b=new T2(thn,!1),e9E=thD,e9_=thL,e9w=thx,e9y=thS,e9T=thJ,e9v=(eEg(),e9i),e9N=e9c,e9g=e9r,e9A=e9o,e9L=e9u}function eCx(e){var t,n,r,i,a,o,s,u;for(u=new Zr,s=new fz(e.a);s.a0&&t=0)return!1;if(t.p=n.b,P_(n.e,t),i==(eEn(),e8D)||i==e8P){for(o=new fz(t.j);o.a1||-1==o)&&(a|=16),(i.Bb&eZ1)!=0&&(a|=64)),(n.Bb&eH3)!=0&&(a|=eJq),a|=eXt):M4(t,457)?a|=512:(r=t.Bj())&&(1&r.i)!=0&&(a|=256),(512&e.Bb)!=0&&(a|=128),a}function eCG(e,t){var n,r,i,a,o;for(i=0,e=null==e?eUg:(BJ(e),e);ie.d[s.p]&&(n+=qq(e.b,a),Vw(e.a,ell(a))):++o;for(n+=e.b.d*o;!gY(e.a);)eek(e.b,Pp(Yn(e.a),19).a)}return n}function eCV(e,t){var n;return e.f==tvm?(n=Ur(QZ((eSp(),tvc),t)),e.e?4==n&&t!=(ex$(),tvw)&&t!=(ex$(),tvg)&&t!=(ex$(),tvv)&&t!=(ex$(),tvy):2==n):!!(e.d&&(e.d.Hc(t)||e.d.Hc(Wk(QZ((eSp(),tvc),t)))||e.d.Hc(eR3((eSp(),tvc),e.b,t))))||!!(e.f&&eOq((eSp(),e.f),U$(QZ(tvc,t))))&&(n=Ur(QZ(tvc,t)),e.e?4==n:2==n)}function eCq(e,t,n,r){var i,a,o,s,u,c,l,f;return u=(o=Pp(eT8(n,(eBB(),th3)),8)).a,l=o.b+e,(i=eB4.Math.atan2(l,u))<0&&(i+=eV7),(i+=t)>eV7&&(i-=eV7),c=(s=Pp(eT8(r,th3),8)).a,f=s.b+e,(a=eB4.Math.atan2(f,c))<0&&(a+=eV7),(a+=t)>eV7&&(a-=eV7),Mc(),enj(1e-10),1e-10>=eB4.Math.abs(i-a)||i==a||isNaN(i)&&isNaN(a)?0:ia?1:Te(isNaN(i),isNaN(a))}function eCZ(e){var t,n,r,i,a,o,s;for(s=new p2,r=new fz(e.a.b);r.a=e.o)throw p7(new bj);s=t>>5,o=31&t,a=Fg(1,jE(Fg(o,1))),i?e.n[n][s]=WO(e.n[n][s],a):e.n[n][s]=WM(e.n[n][s],PN(a)),a=Fg(a,1),r?e.n[n][s]=WO(e.n[n][s],a):e.n[n][s]=WM(e.n[n][s],PN(a))}catch(u){if(u=eoa(u),M4(u,320))throw p7(new gE(ez_+e.o+"*"+e.p+ezE+t+eUd+n+ezS));throw p7(u)}}function eC1(e,t,n,r){var i,a,o;t&&(a=gP(LV(e_k(t,(eR6(),tcd))))+r,o=n+gP(LV(e_k(t,tcu)))/2,eo3(t,tcg,ell(jE(eap(eB4.Math.round(a))))),eo3(t,tcv,ell(jE(eap(eB4.Math.round(o))))),0==t.d.b||eC1(e,Pp(M2((i=epL(new hz(t).a.d,0),new hG(i))),86),n+gP(LV(e_k(t,tcu)))+e.a,r+gP(LV(e_k(t,tcc)))),null!=e_k(t,tcb)&&eC1(e,Pp(e_k(t,tcb),86),n,r))}function eC0(e,t){var n,r,i,a,o,s,u,c,l,f,d;for(i=2*gP(LV(e_k(u=Bq(t.a),(eBy(),toI)))),l=gP(LV(e_k(u,toY))),c=eB4.Math.max(i,l),a=Je(tyx,eH5,25,t.f-t.c+1,15,1),r=-c,n=0,s=t.b.Kc();s.Ob();)o=Pp(s.Pb(),10),r+=e.a[o.c.p]+c,a[n++]=r;for(r+=e.a[t.a.c.p]+c,a[n++]=r,d=new fz(t.e);d.a0&&(r=(e.n||(e.n=new FQ(e6S,e,1,7)),Pp(etj(e.n,0),137)).a)&&xM(xM((t.a+=' "',t),r),'"')),xM(yW(xM(yW(xM(yW(xM(yW((t.a+=" (",t),e.i),","),e.j)," | "),e.g),","),e.f),")"),t.a)}function eC5(e){var t,n,r;return(64&e.Db)!=0?eEp(e):(t=new O0(eZG),(n=e.k)?xM(xM((t.a+=' "',t),n),'"'):(e.n||(e.n=new FQ(e6S,e,1,7)),e.n.i>0&&(r=(e.n||(e.n=new FQ(e6S,e,1,7)),Pp(etj(e.n,0),137)).a)&&xM(xM((t.a+=' "',t),r),'"')),xM(yW(xM(yW(xM(yW(xM(yW((t.a+=" (",t),e.i),","),e.j)," | "),e.g),","),e.f),")"),t.a)}function eC6(e,t){var n,r,i,a,o,s,u;if(null==t||0==t.length)return null;if(!(i=Pp(zg(e.a,t),149))){for(r=(s=new fT(e.b).a.vc().Kc(),new fN(s));r.a.Ob();)if(o=(n=(a=Pp(r.a.Pb(),42),Pp(a.dd(),149))).c,u=t.length,IE(o.substr(o.length-u,u),t)&&(t.length==o.length||46==UI(o,o.length-t.length-1))){if(i)return null;i=n}i&&Ge(e.a,t,i)}return i}function eC9(e,t){var n,r,i,a;return(n=new eD,i=(r=Pp(qE(UQ(new R1(null,new Gq(e.f,16)),n),Qz(new q,new Z,new er,new ei,eow(vx(e2L,1),eU4,132,0,[(eum(),e2H),e2U]))),21)).gc(),a=(r=Pp(qE(UQ(new R1(null,new Gq(t.f,16)),n),Qz(new q,new Z,new er,new ei,eow(vx(e2L,1),eU4,132,0,[e2H,e2U]))),21)).gc(),ii.p?(ekv(a,tbj),a.d&&(s=a.o.b,t=a.a.b,a.a.b=s-t)):a.j==tbj&&i.p>e.p&&(ekv(a,tbw),a.d&&(s=a.o.b,t=a.a.b,a.a.b=-(s-t)));break}return i}function eIe(e,t,n,r){var i,a,o,s,u,c,l,f,d,h,p;if(a=n,n1)&&(r=new kl(i,n.b),P7(t.a,r)),enD(t.a,eow(vx(e50,1),eUP,8,0,[d,f]))}function eIy(e,t,n){var r,i,a,o,s,u;if(!t)return null;if(!(n<=-1))return ebY(Pp(ee2(e.Tg(),n),18));if(r=ee2(t.Tg(),-1-n),M4(r,99))return Pp(r,18);for(s=0,u=(o=Pp(t.ah(r),153)).gc();s0){for(i=u.length;i>0&&""==u[i-1];)--i;i=t.d.a.gc()){o=t.a.c,s=t.a.c+t.a.b,u=new kl(o+(s-o)/2,t.b),P7(Pp(t.d.a.ec().Kc().Pb(),17).a,u);continue}if((i=Pp(Bp(t.c,n),459)).b||i.c){eIv(e,n,t);continue}(a=e.d==(euy(),tsW)&&(i.d||i.e)&&exJ(e,t)&&1>=t.d.a.gc())?eFd(n,t):eL5(e,n,t)}t.k&&qX(t.d,new nn)}}function eIq(e,t,n,r,i,a){var o,s,u,c,l,f,d,h,p,b,m,g,v,y;for(s=(r+i)/2+(d=a),m=n*eB4.Math.cos(s),g=n*eB4.Math.sin(s),v=m-t.g/2,y=g-t.f/2,eno(t,v),ens(t,y),f=e.a.jg(t),(b=2*eB4.Math.acos(n/n+e.c))=40)&&eNo(e),eRi(e),eA3(e),n=elM(e),r=0;n&&r0&&P7(e.f,a)):(e.c[o]-=c+1,e.c[o]<=0&&e.a[o]>0&&P7(e.e,a))))}function eI1(e){var t,n,r,i,a,o,s,u,c;for(s=new yB(Pp(Y9(new eP),62)),c=eH1,n=new fz(e.d);n.a=0&&un?t:n;c<=f;++c)c==n?s=r++:(a=i[c],l=p.rl(a.ak()),c==t&&(u=c!=f||l?r:r-1),l&&++r);return d=Pp(elR(e,t,n),72),s!=u&&bz(e,new JU(e.e,7,o,ell(s),h.dd(),u)),d}return Pp(elR(e,t,n),72)}function eDe(e,t){var n,r,i,a,o,s,u;for(ewG(t,"Port order processing",1),u=Pp(e_k(e,(eBy(),tom)),421),r=new fz(e.b);r.a=0&&(!(s=egy(e,o))||(c<22?u.l|=1<>>1,o.m=l>>>1|(1&f)<<21,o.l=d>>>1|(1&l)<<21,--c;return n&&esh(u),a&&(r?(e0A=eoQ(e),i&&(e0A=eor(e0A,(Q2(),e0I)))):e0A=Mk(e.l,e.m,e.h)),u}function eDi(e,t){var n,r,i,a,o,s,u,c,l,f;for(c=e.e[t.c.p][t.p]+1,u=t.c.a.c.length+1,s=new fz(e.a);s.a0&&(GV(0,e.length),45==e.charCodeAt(0)||(GV(0,e.length),43==e.charCodeAt(0)))?1:0;rn)throw p7(new vo(eHJ+e+'"'));return s}function eDo(e){var t,n,r,i,a,o,s;for(o=new _n,a=new fz(e.a);a.a1)&&1==t&&Pp(e.a[e.b],10).k==(eEn(),e8I)?eD3(Pp(e.a[e.b],10),(egF(),tpV)):r&&(!n||(e.c-e.b&e.a.length-1)>1)&&1==t&&Pp(e.a[e.c-1&e.a.length-1],10).k==(eEn(),e8I)?eD3(Pp(e.a[e.c-1&e.a.length-1],10),(egF(),tpq)):(e.c-e.b&e.a.length-1)==2?(eD3(Pp(eso(e),10),(egF(),tpV)),eD3(Pp(eso(e),10),tpq)):eM8(e,i),qr(e)}function eDf(e,t,n){var r,i,a,o,s;for(a=0,i=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));i.e!=i.i.gc();)r=Pp(epH(i),33),o="",0==(r.n||(r.n=new FQ(e6S,r,1,7)),r.n).i||(o=Pp(etj((r.n||(r.n=new FQ(e6S,r,1,7)),r.n),0),137).a),eaW(s=new esH(a++,t,o),r),eo3(s,(eR6(),tcl),r),s.e.b=r.j+r.f/2,s.f.a=eB4.Math.max(r.g,1),s.e.a=r.i+r.g/2,s.f.b=eB4.Math.max(r.f,1),P7(t.b,s),eS9(n.f,r,s)}function eDd(e){var t,n,r,i,a;r=Pp(e_k(e,(eBU(),tnc)),33),a=Pp(eT8(r,(eBy(),ta4)),174).Hc((ed6(),tbq)),!e.e&&(i=Pp(e_k(e,tt3),21),t=new kl(e.f.a+e.d.b+e.d.c,e.f.b+e.d.d+e.d.a),i.Hc((eLR(),ttw))?(ebu(r,tol,(ewf(),tbo)),eYx(r,t.a,t.b,!1,!0)):gN(LK(eT8(r,ta5)))||eYx(r,t.a,t.b,!0,!0)),a?ebu(r,ta4,el9(tbq)):ebu(r,ta4,(n=Pp(yw(e6o),9),new I1(n,Pp(CY(n,n.length),9),0)))}function eDh(e,t,n){var r,i,a,o;if(t[0]>=e.length)return n.o=0,!0;switch(UI(e,t[0])){case 43:i=1;break;case 45:i=-1;break;default:return n.o=0,!0}if(++t[0],a=t[0],0==(o=exf(e,t))&&t[0]==a)return!1;if(t[0]=0&&s!=n&&(a=new FX(e,1,s,o,null),r?r.Ei(a):r=a),n>=0&&(a=new FX(e,1,n,s==n?o:null,t),r?r.Ei(a):r=a)),r}function eDv(e){var t,n,r;if(null==e.b){if(r=new vs,null!=e.i&&(xk(r,e.i),r.a+=":"),(256&e.f)!=0){for((256&e.f)!=0&&null!=e.a&&(Hb(e.i)||(r.a+="//"),xk(r,e.a)),null!=e.d&&(r.a+="/",xk(r,e.d)),(16&e.f)!=0&&(r.a+="/"),t=0,n=e.j.length;td)&&(f=(u=ePI(r,d,!1)).a,l+s+f<=t.b&&(JR(n,a-n.s),n.c=!0,JR(r,a-n.s),ebP(r,n.s,n.t+n.d+s),r.k=!0,eiV(n.q,r),h=!0,i&&(enN(t,r),r.j=t,e.c.length>o&&(eva((GK(o,e.c.length),Pp(e.c[o],200)),r),0==(GK(o,e.c.length),Pp(e.c[o],200)).a.c.length&&ZV(e,o)))),h)}function eDx(e,t){var n,r,i,a,o,s;if(ewG(t,"Partition midprocessing",1),i=new zu,_r(UJ(new R1(null,new Gq(e.a,16)),new nK),new dQ(i)),0!=i.d){for(r=(s=Pp(qE(GU((a=i.i,new R1(null,(a||(i.i=new OC(i,i.c))).Nc()))),JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[(eum(),e2U)]))),15)).Kc(),n=Pp(r.Pb(),19);r.Ob();)o=Pp(r.Pb(),19),eOR(Pp(Zq(i,n),21),Pp(Zq(i,o),21)),n=o;eEj(t)}}function eDT(e,t,n){var r,i,a,o,s,u,c,l;if(0==t.p){for(t.p=1,(o=n)||(i=new p0,a=(r=Pp(yw(e6a),9),new I1(r,Pp(CY(r,r.length),9),0)),o=new kD(i,a)),Pp(o.a,15).Fc(t),t.k==(eEn(),e8C)&&Pp(o.b,21).Fc(Pp(e_k(t,(eBU(),tt1)),61)),u=new fz(t.j);u.a0){if(i=Pp(e.Ab.g,1934),null==t){for(a=0;a1)for(r=new fz(i);r.an.s&&ss&&(s=i,f.c=Je(e1R,eUp,1,0,5,1)),i==s&&P_(f,new kD(n.c.i,n)));Hj(),Mv(f,e.c),jO(e.b,u.p,f)}}function eDR(e,t){var n,r,i,a,o,s,u,l,f;for(o=new fz(t.b);o.as&&(s=i,f.c=Je(e1R,eUp,1,0,5,1)),i==s&&P_(f,new kD(n.d.i,n)));Hj(),Mv(f,e.c),jO(e.f,u.p,f)}}function eDj(e){_Y(e,new ewB(vQ(vq(vJ(vX(new oc,eZn),"ELK Box"),"Algorithm for packing of unconnected boxes, i.e. graphs without edges."),new oA))),KE(e,eZn,ezW,td$),KE(e,eZn,eGi,15),KE(e,eZn,eGr,ell(0)),KE(e,eZn,eqC,epB(tdj)),KE(e,eZn,eGh,epB(tdY)),KE(e,eZn,eGd,epB(tdU)),KE(e,eZn,ezG,eZt),KE(e,eZn,eGu,epB(tdF)),KE(e,eZn,eGM,epB(tdB)),KE(e,eZn,eZr,epB(tdP)),KE(e,eZn,eVg,epB(tdR))}function eDF(e,t){var n,r,i,a,o,s,u,c,l;if(o=(i=e.i).o.a,a=i.o.b,o<=0&&a<=0)return eYu(),tbF;switch(c=e.n.a,l=e.n.b,s=e.o.a,n=e.o.b,t.g){case 2:case 1:if(c<0)return eYu(),tbY;if(c+s>o)return eYu(),tby;break;case 4:case 3:if(l<0)return eYu(),tbw;if(l+n>a)return eYu(),tbj}return(u=(c+s/2)/o)+(r=(l+n/2)/a)<=1&&u-r<=0?(eYu(),tbY):u+r>=1&&u-r>=0?(eYu(),tby):r<.5?(eYu(),tbw):(eYu(),tbj)}function eDY(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b;for(n=!1,l=gP(LV(e_k(t,(eBy(),toF)))),p=eHe*l,i=new fz(t.b);i.a(u=s.n.b-s.d.d+d.a)+p&&(b=f.g+d.g,d.a=(d.g*d.a+f.g*f.a)/b,d.g=b,f.f=d,n=!0)),a=s,f=d;return n}function eDB(e,t,n,r,i,a,o){var s,u,c,l,f,d;for(d=new TE,c=t.Kc();c.Ob();)for(s=Pp(c.Pb(),839),f=new fz(s.wf());f.a0?s.a?i>(c=s.b.rf().b)&&(e.v||1==s.c.d.c.length?(o=(i-c)/2,s.d.d=o,s.d.a=o):(r=((n=Pp(RJ(s.c.d,0),181).rf().b)-c)/2,s.d.d=eB4.Math.max(0,r),s.d.a=i-r-c)):s.d.a=e.t+i:FY(e.u)&&((a=ew1(s.b)).d<0&&(s.d.d=-a.d),a.d+a.a>s.b.rf().b&&(s.d.a=a.d+a.a-s.b.rf().b))}function eD$(e,t){var n;switch(eeg(e)){case 6:return xd(t);case 7:return xf(t);case 8:return xl(t);case 3:return Array.isArray(t)&&!((n=eeg(t))>=14&&n<=16);case 11:return null!=t&&typeof t===eUs;case 12:return null!=t&&(typeof t===eUr||typeof t==eUs);case 0:return ebs(t,e.__elementTypeId$);case 2:return YS(t)&&t.im!==O;case 1:return YS(t)&&t.im!==O||ebs(t,e.__elementTypeId$);default:return!0}}function eDz(e,t){var n,r,i,a;return(r=eB4.Math.min(eB4.Math.abs(e.c-(t.c+t.b)),eB4.Math.abs(e.c+e.b-t.c)),a=eB4.Math.min(eB4.Math.abs(e.d-(t.d+t.a)),eB4.Math.abs(e.d+e.a-t.d)),(n=eB4.Math.abs(e.c+e.b/2-(t.c+t.b/2)))>e.b/2+t.b/2||(i=eB4.Math.abs(e.d+e.a/2-(t.d+t.a/2)))>e.a/2+t.a/2)?1:0==n&&0==i?0:0==n?a/i+1:0==i?r/n+1:eB4.Math.min(r/n,a/i)+1}function eDG(e,t){var n,r,i,a,o,s;return(i=enR(e),s=enR(t),i!=s)?it.f?1:0:(r=e.e-t.e,(n=(e.d>0?e.d:eB4.Math.floor((e.a-1)*eH9)+1)-(t.d>0?t.d:eB4.Math.floor((t.a-1)*eH9)+1))>r+1)?i:n0&&(o=eeD(o,eN4(r))),ehI(a,o))}function eDW(e,t){var n,r,i,a,o,s,u;for(a=0,s=0,u=0,i=new fz(e.f.e);i.a0&&e.d!=(QJ(),e95)&&(s+=o*(r.d.a+e.a[t.b][r.b]*(t.d.a-r.d.a)/n)),n>0&&e.d!=(QJ(),e93)&&(u+=o*(r.d.b+e.a[t.b][r.b]*(t.d.b-r.d.b)/n)));switch(e.d.g){case 1:return new kl(s/a,t.d.b);case 2:return new kl(t.d.a,u/a);default:return new kl(s/a,u/a)}}function eDK(e,t){var n,r,i,a,o;if(euv(),o=Pp(e_k(e.i,(eBy(),tol)),98),0!=(a=e.j.g-t.j.g)||!(o==(ewf(),tba)||o==tbs||o==tbo))return 0;if(o==(ewf(),tba)&&(n=Pp(e_k(e,tof),19),r=Pp(e_k(t,tof),19),n&&r&&0!=(i=n.a-r.a)))return i;switch(e.j.g){case 1:return elN(e.n.a,t.n.a);case 2:return elN(e.n.b,t.n.b);case 3:return elN(t.n.a,e.n.a);case 4:return elN(t.n.b,e.n.b);default:throw p7(new gC(eGz))}}function eDV(e){var t,n,r,i,a,o;for(n=(e.a||(e.a=new O_(e6h,e,5)),e.a).i+2,o=new XM(n),P_(o,new kl(e.j,e.k)),_r(new R1(null,(e.a||(e.a=new O_(e6h,e,5)),new Gq(e.a,16))),new h6(o)),P_(o,new kl(e.b,e.c)),t=1;t0&&(eoY(u,!1,(ec3(),tpm)),eoY(u,!0,tpg)),ety(t.g,new E4(e,n)),Um(e.g,t,n)}function eDZ(){var e;for(e=2,eDZ=A,e0$=eow(vx(ty_,1),eHT,25,15,[-1,-1,30,19,15,13,11,11,10,9,9,8,8,8,8,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5]),e0z=Je(ty_,eHT,25,37,15,1),e0G=eow(vx(ty_,1),eHT,25,15,[-1,-1,63,40,32,28,25,23,21,20,19,19,18,18,17,17,16,16,16,15,15,15,15,14,14,14,14,14,14,13,13,13,13,13,13,13,13]),e0W=Je(tyS,eH2,25,37,14,1);e<=36;e++)e0z[e]=zy(eB4.Math.pow(e,e0$[e])),e0W[e]=eyt(eUY,e0z[e])}function eDX(e){var t;if(1!=(e.a||(e.a=new FQ(e6v,e,6,6)),e.a).i)throw p7(new gL(eZC+(e.a||(e.a=new FQ(e6v,e,6,6)),e.a).i));return t=new mE,eoo(Pp(etj((e.b||(e.b=new Ih(e6m,e,4,7)),e.b),0),82))&&er7(t,eBE(e,eoo(Pp(etj((e.b||(e.b=new Ih(e6m,e,4,7)),e.b),0),82)),!1)),eoo(Pp(etj((e.c||(e.c=new Ih(e6m,e,5,8)),e.c),0),82))&&er7(t,eBE(e,eoo(Pp(etj((e.c||(e.c=new Ih(e6m,e,5,8)),e.c),0),82)),!0)),t}function eDJ(e,t){var n,r,i,a,o;for(i=t.d?e.a.c==(zs(),tuw)?efu(t.b):efc(t.b):e.a.c==(zs(),tuy)?efu(t.b):efc(t.b),a=!1,r=new Fa(OH(i.a.Kc(),new c));eTk(r);)if(n=Pp(ZC(r),17),!(!(o=gN(e.a.f[e.a.g[t.b.p].p]))&&!q8(n)&&n.c.i.c==n.d.i.c||gN(e.a.n[e.a.g[t.b.p].p])||gN(e.a.n[e.a.g[t.b.p].p]))&&(a=!0,w0(e.b,e.a.g[emN(n,t.b).p])))return t.c=!0,t.a=n,t;return t.c=a,t.a=null,t}function eDQ(e,t,n,r,i){var a,o,s,u,c,l,f;for(Hj(),Mv(e,new oU),s=new KB(e,0),f=new p0,a=0;s.b2*a?(l=new etD(f),c=jl(o)/jc(o),u=eY9(l,t,new mp,n,r,i,c),C5(xB(l.e),u),f.c=Je(e1R,eUp,1,0,5,1),a=0,f.c[f.c.length]=l,f.c[f.c.length]=o,a=jl(l)*jc(l)+jl(o)*jc(o)):(f.c[f.c.length]=o,a+=jl(o)*jc(o));return f}function eD1(e,t,n){var r,i,a,o,s,u,c;if(0==(r=n.gc()))return!1;if(e.ej()){if(u=e.fj(),edu(e,t,n),o=1==r?e.Zi(3,null,n.Kc().Pb(),t,u):e.Zi(5,null,n,t,u),e.bj()){for(s=r<100?null:new yf(r),a=t+r,i=t;i0){for(o=0;o>16==-15&&e.Cb.nh()&&QU(new JB(e.Cb,9,13,n,e.c,ebv(QX(Pp(e.Cb,59)),e))):M4(e.Cb,88)&&e.Db>>16==-23&&e.Cb.nh()&&(M4(t=e.c,88)||(t=(eBK(),tgI)),M4(n,88)||(n=(eBK(),tgI)),QU(new JB(e.Cb,9,10,n,t,ebv(qt(Pp(e.Cb,26)),e)))))),e.c}function eD6(e,t){var n,r,i,a,o,s,u,c,l,f;for(ewG(t,"Hypernodes processing",1),i=new fz(e.b);i.an)return i}function eNe(e,t){var n,r,i;r=0!=eMU(e.d,1),(gN(LK(e_k(t.j,(eBU(),tt2))))||gN(LK(e_k(t.j,tnS))))&&xc(e_k(t.j,(eBy(),ti9)))!==xc((esn(),tsM))?r=gN(LK(e_k(t.j,tt2))):t.c.Tf(t.e,r),eAb(e,t,r,!0),gN(LK(e_k(t.j,tnS)))&&eo3(t.j,tnS,(OQ(),!1)),gN(LK(e_k(t.j,tt2)))&&(eo3(t.j,tt2,(OQ(),!1)),eo3(t.j,tnS,!0)),n=eSY(e,t);do{if(er0(e),0==n)return 0;r=!r,i=n,eAb(e,t,r,!1),n=eSY(e,t)}while(i>n)return i}function eNt(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p;if(t==n)return!0;if(t=eTE(e,t),n=eTE(e,n),!(r=eb1(t)))return(s=t.e)==(h=n.e);if((l=eb1(n))!=r)return!!l&&(u=r.Dj())==(p=l.Dj())&&null!=u;if(a=(o=(t.d||(t.d=new O_(tgr,t,1)),t.d)).i,d=(n.d||(n.d=new O_(tgr,n,1)),n.d),a==d.i){for(c=0;c0,s=efC(t,a),n?Ag(s.b,t):Ag(s.g,t),1==efv(s).c.length&&qQ(r,s,r.c.b,r.c),i=new kD(a,t),Vw(e.o,i),QA(e.e.a,a))}function eNs(e,t){var n,r,i,a,o,s,u;return r=eB4.Math.abs(FB(e.b).a-FB(t.b).a),s=eB4.Math.abs(FB(e.b).b-FB(t.b).b),i=0,u=0,n=1,o=1,r>e.b.b/2+t.b.b/2&&(n=1-(i=eB4.Math.min(eB4.Math.abs(e.b.c-(t.b.c+t.b.b)),eB4.Math.abs(e.b.c+e.b.b-t.b.c)))/r),s>e.b.a/2+t.b.a/2&&(o=1-(u=eB4.Math.min(eB4.Math.abs(e.b.d-(t.b.d+t.b.a)),eB4.Math.abs(e.b.d+e.b.a-t.b.d)))/s),(1-(a=eB4.Math.min(n,o)))*eB4.Math.sqrt(r*r+s*s)}function eNu(e){var t,n,r,i;for(eFX(e,e.e,e.f,(zo(),tuq),!0,e.c,e.i),eFX(e,e.e,e.f,tuq,!1,e.c,e.i),eFX(e,e.e,e.f,tuZ,!0,e.c,e.i),eFX(e,e.e,e.f,tuZ,!1,e.c,e.i),eNd(e,e.c,e.e,e.f,e.i),r=new KB(e.i,0);r.b=65;n--)tvJ[n]=n-65<<24>>24;for(r=122;r>=97;r--)tvJ[r]=r-97+26<<24>>24;for(i=57;i>=48;i--)tvJ[i]=i-48+52<<24>>24;for(a=0,tvJ[43]=62,tvJ[47]=63;a<=25;a++)tvQ[a]=65+a&eHd;for(o=26,u=0;o<=51;++o,u++)tvQ[o]=97+u&eHd;for(e=52,s=0;e<=61;++e,s++)tvQ[e]=48+s&eHd;tvQ[62]=43,tvQ[63]=47}function eNf(e,t){var n,r,i,a,o,s,u,c,l,f,d,h;if(e.dc())return new yb;for(c=0,f=0,i=e.Kc();i.Ob();)a=(r=Pp(i.Pb(),37)).f,c=eB4.Math.max(c,a.a),f+=a.a*a.b;for(c=eB4.Math.max(c,eB4.Math.sqrt(f)*gP(LV(e_k(Pp(e.Kc().Pb(),37),(eBy(),tiX))))),d=0,h=0,u=0,n=t,s=e.Kc();s.Ob();)d+(l=(o=Pp(s.Pb(),37)).f).a>c&&(d=0,h+=u+t,u=0),eIn(o,d,h),n=eB4.Math.max(n,d+l.a),u=eB4.Math.max(u,l.b),d+=l.a+t;return new kl(n+t,h+u+t)}function eNd(e,t,n,r,i){var a,o,s,u,c,l,f;for(o=new fz(t);o.aa)return eYu(),tby;break;case 4:case 3:if(u<0)return eYu(),tbw;if(u+e.f>i)return eYu(),tbj}return(o=(s+e.g/2)/a)+(n=(u+e.f/2)/i)<=1&&o-n<=0?(eYu(),tbY):o+n>=1&&o-n>=0?(eYu(),tby):n<.5?(eYu(),tbw):(eYu(),tbj)}function eNp(e,t,n,r,i){var a,o;if(a=eft(WM(t[0],eH8),WM(r[0],eH8)),e[0]=jE(a),a=Fv(a,32),n>=i){for(o=1;o0&&(i.b[o++]=0,i.b[o++]=a.b[0]-1),t=1;t0&&(l0(u,u.d-i.d),i.c==(Xa(),tuU)&&lQ(u,u.a-i.d),u.d<=0&&u.i>0&&qQ(t,u,t.c.b,t.c));for(a=new fz(e.f);a.a0&&(l2(s,s.i-i.d),i.c==(Xa(),tuU)&&l1(s,s.b-i.d),s.i<=0&&s.d>0&&qQ(n,s,n.c.b,n.c))}function eNv(e,t,n){var r,i,a,o,s,u,c,l;for(ewG(n,"Processor compute fanout",1),Yy(e.b),Yy(e.a),s=null,a=epL(t.b,0);!s&&a.b!=a.d.c;)gN(LK(e_k(c=Pp(Vv(a),86),(eR6(),tcm))))&&(s=c);for(qQ(u=new _n,s,u.c.b,u.c),eYc(e,u),l=epL(t.b,0);l.b!=l.d.c;)o=Lq(e_k(c=Pp(Vv(l),86),(eR6(),tca))),eo3(c,tci,ell(i=null!=zg(e.b,o)?Pp(zg(e.b,o),19).a:0)),eo3(c,tcn,ell(r=1+(null!=zg(e.a,o)?Pp(zg(e.a,o),19).a:0)));eEj(n)}function eNy(e,t,n,r,i){var a,o,s,u,c,l,f,d,h,p;for(u=0,d=eyG(e,n);u0),r.a.Xb(r.c=--r.b),f>d+u&&BH(r);for(o=new fz(h);o.a0),r.a.Xb(r.c=--r.b)}}function eNw(){var e,t,n,r,i,a;if(eBG(),tyg)return tyg;for(e=(++tyv,new WZ(4)),ePR(e,eYB(e1_,!0)),ej0(e,eYB("M",!0)),ej0(e,eYB("C",!0)),a=(++tyv,new WZ(4)),r=0;r<11;r++)eLw(a,r,r);return t=(++tyv,new WZ(4)),ePR(t,eYB("M",!0)),eLw(t,4448,4607),eLw(t,65438,65439),i=(++tyv,new Mr(2)),eRv(i,e),eRv(i,tye),(n=(++tyv,new Mr(2))).$l(jS(a,eYB("L",!0))),n.$l(t),n=(++tyv,new qa(3,n)),tyg=n=(++tyv,new YD(i,n))}function eN_(e){var t,n;if(t=Lq(eT8(e,(eBB(),tdQ))),!eae(t,e)&&!X2(e,th6)&&(0!=(e.a||(e.a=new FQ(e6k,e,10,11)),e.a).i||gN(LK(eT8(e,thh))))){if(null==t||0==e_H(t).length){if(!eae(eG1,e))throw eFh(e,n=xM(xM(new O0("Unable to load default layout algorithm "),eG1)," for unconfigured node ")),p7(new gq(n.a))}else throw eFh(e,n=xM(xM(new O0("Layout algorithm '"),t),"' not found for ")),p7(new gq(n.a))}}function eNE(e){var t,n,r,i,a,o,s,u,c,l,f,d,h;if(n=e.i,t=e.n,0==e.b)for(h=n.c+t.b,d=n.b-t.b-t.c,o=e.a,u=0,l=o.length;u0&&(f-=r[0]+e.c,r[0]+=e.c),r[2]>0&&(f-=r[2]+e.c),r[1]=eB4.Math.max(r[1],f),jQ(e.a[1],n.c+t.b+r[0]-(r[1]-f)/2,r[1]);for(a=e.a,s=0,c=a.length;s0?(e.n.c.length-1)*e.i:0,r=new fz(e.n);r.a1)for(r=epL(i,0);r.b!=r.d.c;)for(n=Pp(Vv(r),231),a=0,u=new fz(n.e);u.a0&&(t[0]+=e.c,f-=t[0]),t[2]>0&&(f-=t[2]+e.c),t[1]=eB4.Math.max(t[1],f),j1(e.a[1],r.d+n.d+t[0]-(t[1]-f)/2,t[1]);else for(p=r.d+n.d,h=r.a-n.d-n.a,o=e.a,u=0,l=o.length;u=0&&a!=n)throw p7(new gL(eXB));for(u=0,i=0;u=efT(e.b.c,i.b.c+i.b.b)&&0>=efT(i.b.c,e.b.c+e.b.b)&&0>=efT(e.b.d,i.b.d+i.b.a)&&0>=efT(i.b.d,e.b.d+e.b.a)){if(0==efT(i.b.c,e.b.c+e.b.b)&&r.a<0||0==efT(i.b.c+i.b.b,e.b.c)&&r.a>0||0==efT(i.b.d,e.b.d+e.b.a)&&r.b<0||0==efT(i.b.d+i.b.a,e.b.d)&&r.b>0){s=0;break}}else s=eB4.Math.min(s,ekg(e,i,r));s=eB4.Math.min(s,eNC(e,a,s,r))}return s}function eNI(e,t){var n,r,i,a,o,s,u;if(e.b<2)throw p7(new gL("The vector chain must contain at least a source and a target point."));for(Tj(t,(i=(A6(0!=e.b),Pp(e.a.a.c,8))).a,i.b),u=new AF((t.a||(t.a=new O_(e6h,t,5)),t.a)),o=epL(e,1);o.agP(Ot(o.g,o.d[0]).a)?(A6(u.b>0),u.a.Xb(u.c=--u.b),CD(u,o),i=!0):s.e&&s.e.gc()>0&&(a=(s.e||(s.e=new p0),s.e).Mc(t),c=(s.e||(s.e=new p0),s.e).Mc(n),(a||c)&&((s.e||(s.e=new p0),s.e).Fc(o),++o.c));i||(r.c[r.c.length]=o)}function eNH(e){var t,n,r;if(TM(Pp(e_k(e,(eBy(),tol)),98)))for(n=new fz(e.j);n.a>>0).toString(16),n.length-2,n.length):e>=eH3?"\\v"+Az(n="0"+(t=e>>>0).toString(16),n.length-6,n.length):""+String.fromCharCode(e&eHd)}return r}function eNz(e,t){var n,r,i,a,o,s,u,c,l,f;if(o=e.e,0==(u=t.e))return e;if(0==o)return 0==t.e?t:new F7(-t.e,t.d,t.a);if((a=e.d)+(s=t.d)==2)return n=WM(e.a[0],eH8),r=WM(t.a[0],eH8),o<0&&(n=QC(n)),u<0&&(r=QC(r)),ep_(efe(n,r));if(-1==(i=a!=s?a>s?1:-1:es8(e.a,t.a,a)))f=-u,l=o==u?Z1(t.a,s,e.a,a):X7(t.a,s,e.a,a);else if(f=o,o==u){if(0==i)return eLQ(),e08;l=Z1(e.a,a,t.a,s)}else l=X7(e.a,a,t.a,s);return c=new F7(f,l.length,l),Ku(c),c}function eNG(e){var t,n,r,i,a,o;for(this.e=new p0,this.a=new p0,n=e.b-1;n<3;n++)Ls(e,0,Pp(ep3(e,0),8));if(e.b<4)throw p7(new gL("At (least dimension + 1) control points are necessary!"));for(this.b=3,this.d=!0,this.c=!1,eMO(this,e.b+this.b-1),o=new p0,a=new fz(this.e),t=0;t=t.o&&n.f<=t.f||.5*t.a<=n.f&&1.5*t.a>=n.f){if((o=Pp(RJ(t.n,t.n.c.length-1),211)).e+o.d+n.g+i<=r&&((a=Pp(RJ(t.n,t.n.c.length-1),211)).f-e.f+n.f<=e.b||1==e.a.c.length))return efg(t,n),!0;if(t.s+n.g<=r&&(t.t+t.d+n.f+i<=e.b||1==e.a.c.length))return P_(t.b,n),s=Pp(RJ(t.n,t.n.c.length-1),211),P_(t.n,new zO(t.s,s.f+s.a+t.i,t.i)),eml(Pp(RJ(t.n,t.n.c.length-1),211),n),eNk(t,n),!0}return!1}function eNV(e,t,n){var r,i,a,o;return e.ej()?(i=null,a=e.fj(),r=e.Zi(1,o=ees(e,t,n),n,t,a),e.bj()&&!(e.ni()&&null!=o?ecX(o,n):xc(o)===xc(n))?(null!=o&&(i=e.dj(o,i)),i=e.cj(n,i),e.ij()&&(i=e.lj(o,n,i)),i?(i.Ei(r),i.Fi()):e.$i(r)):(e.ij()&&(i=e.lj(o,n,i)),i?(i.Ei(r),i.Fi()):e.$i(r)),o):(o=ees(e,t,n),e.bj()&&!(e.ni()&&null!=o?ecX(o,n):xc(o)===xc(n))&&(i=null,null!=o&&(i=e.dj(o,null)),(i=e.cj(n,i))&&i.Fi()),o)}function eNq(e,t){var n,r,i,a,o,s,u,c;t%=24,e.q.getHours()!=t&&((r=new eB4.Date(e.q.getTime())).setDate(r.getDate()+1),(s=e.q.getTimezoneOffset()-r.getTimezoneOffset())>0&&(u=s/60|0,c=s%60,i=e.q.getDate(),(n=e.q.getHours())+u>=24&&++i,a=new eB4.Date(e.q.getFullYear(),e.q.getMonth(),i,t+u,e.q.getMinutes()+c,e.q.getSeconds(),e.q.getMilliseconds()),e.q.setTime(a.getTime()))),o=e.q.getTime(),e.q.setTime(o+36e5),e.q.getHours()!=t&&e.q.setTime(o)}function eNZ(e,t){var n,r,i,a,o;if(ewG(t,"Path-Like Graph Wrapping",1),0==e.b.c.length||(n=(o=(null==(i=new eTN(e)).i&&(i.i=eis(i,new iP)),gP(i.i)*i.f))/(null==i.i&&(i.i=eis(i,new iP)),gP(i.i)),i.b>n)){eEj(t);return}switch(Pp(e_k(e,(eBy(),toq)),337).g){case 2:a=new iF;break;case 0:a=new iO;break;default:a=new iY}if(r=a.Vf(e,i),!a.Wf())switch(Pp(e_k(e,to0),338).g){case 2:r=ekE(i,r);break;case 1:r=ewQ(i,r)}eRw(e,i,r),eEj(t)}function eNX(e,t){var n,r,i,a;if(GW(e.d,e.e),e.c.a.$b(),0!=gP(LV(e_k(t.j,(eBy(),ti3))))||0!=gP(LV(e_k(t.j,ti3))))for(n=ezq,xc(e_k(t.j,ti9))!==xc((esn(),tsM))&&eo3(t.j,(eBU(),tt2),(OQ(),!0)),a=Pp(e_k(t.j,to$),19).a,i=0;i(i=(GK(s+1,t.c.length),Pp(t.c[s+1],19)).a-r)&&++c,P_(o,(GK(s+c,t.c.length),Pp(t.c[s+c],19))),u+=(GK(s+c,t.c.length),Pp(t.c[s+c],19)).a-r,++n;n1&&(u>jl(s)*jc(s)/2||0==o.b)&&(f=new etD(d),l=jl(s)/jc(s),c=eY9(f,t,new mp,n,r,i,l),C5(xB(f.e),c),s=f,h.c[h.c.length]=f,u=0,d.c=Je(e1R,eUp,1,0,5,1)));return eoc(h,d),h}function eN2(e,t,n,r){var i,a,o,s,u,c,l,f,d,h,p,b;if(n.mh(t)&&(l=(h=t)?Pp(r,49).xh(h):null)){if(b=n.bh(t,e.a),(p=t.t)>1||-1==p){if(f=Pp(b,69),d=Pp(l,69),f.dc())d.$b();else for(o=!!ebY(t),a=0,s=e.a?f.Kc():f.Zh();s.Ob();)c=Pp(s.Pb(),56),(i=Pp(eef(e,c),56))?(o?-1==(u=d.Xc(i))?d.Xh(a,i):a!=u&&d.ji(a,i):d.Xh(a,i),++a):e.b&&!o&&(d.Xh(a,c),++a)}else null==b?l.Wb(null):null==(i=eef(e,b))?e.b&&!ebY(t)&&l.Wb(b):l.Wb(i)}}function eN3(e,t){var n,r,i,a,o,s,u,l;for(n=new nf,i=new Fa(OH(efu(t).a.Kc(),new c));eTk(i);)if(r=Pp(ZC(i),17),!q8(r)&&ewg(s=r.c.i,e8q)){if(-1==(l=eCu(e,s,e8q,e8V)))continue;n.b=eB4.Math.max(n.b,l),n.a||(n.a=new p0),P_(n.a,s)}for(o=new Fa(OH(efc(t).a.Kc(),new c));eTk(o);)if(a=Pp(ZC(o),17),!q8(a)&&ewg(u=a.d.i,e8V)){if(-1==(l=eCu(e,u,e8V,e8q)))continue;n.d=eB4.Math.max(n.d,l),n.c||(n.c=new p0),P_(n.c,u)}return n}function eN4(e){var t,n,r,i;if(exX(),t=zy(e),e1e6)throw p7(new g_("power of ten too big"));if(e<=eUu)return ZA(exT(e2t[1],t),t);for(i=r=exT(e2t[1],eUu),n=eap(e-eUu),t=zy(e%eUu);ecd(n,eUu)>0;)i=eeD(i,r),n=efe(n,eUu);for(i=eeD(i,exT(e2t[1],t)),i=ZA(i,eUu),n=eap(e-eUu);ecd(n,eUu)>0;)i=ZA(i,eUu),n=efe(n,eUu);return ZA(i,t)}function eN5(e,t){var n,r,i,a,o,s,u,c,l;for(ewG(t,"Hierarchical port dummy size processing",1),u=new p0,l=new p0,n=2*(r=gP(LV(e_k(e,(eBy(),toA))))),a=new fz(e.b);a.ac&&r>c)l=s,c=gP(t.p[s.p])+gP(t.d[s.p])+s.o.b+s.d.a;else{i=!1,n.n&&P3(n,"bk node placement breaks on "+s+" which should have been after "+l);break}if(!i)break}return n.n&&P3(n,t+" is feasible: "+i),i}function ePr(e,t,n,r){var i,a,o,s,u,c,l;for(s=-1,l=new fz(e);l.a=m&&e.e[u.p]>p*e.b||y>=n*m)&&(d.c[d.c.length]=s,s=new p0,er7(o,a),a.a.$b(),c-=l,h=eB4.Math.max(h,c*e.b+b),c+=y,v=y,y=0,l=0,b=0);return new kD(h,d)}function ePs(e){var t,n,r,i,a,o,s,u,c,l,f,d,h;for(n=(c=new fT(e.c.b).a.vc().Kc(),new fN(c));n.a.Ob();)null==(i=(t=(s=Pp(n.a.Pb(),42),Pp(s.dd(),149))).a)&&(i=""),(r=L8(e.c,i))||0!=i.length||(r=ecj(e)),r&&!eds(r.c,t,!1)&&P7(r.c,t);for(o=epL(e.a,0);o.b!=o.d.c;)a=Pp(Vv(o),478),l=Zc(e.c,a.a),h=Zc(e.c,a.b),l&&h&&P7(l.c,new kD(h,a.c));for(HC(e.a),d=epL(e.b,0);d.b!=d.d.c;)f=Pp(Vv(d),478),t=L9(e.c,f.a),u=Zc(e.c,f.b),t&&u&&_U(t,u,f.c);HC(e.b)}function ePu(e,t,n){var r,i,a,o,s,u,c,l,f,d,h;a=new lD(e),o=new eg6,i=(Ze(o.g),Ze(o.j),Yy(o.b),Ze(o.d),Ze(o.i),Yy(o.k),Yy(o.c),Yy(o.e),h=ekH(o,a,null),eMA(o,a),h),t&&(s=ePA(c=new lD(t)),eEh(i,eow(vx(e5q,1),eUp,527,0,[s]))),d=!1,f=!1,n&&(eXW in(c=new lD(n)).a&&(d=zR(c,eXW).ge().a),eXK in c.a&&(f=zR(c,eXK).ge().a)),l=yr(eny(new mV,d),f),eER(new or,i,l),eXW in a.a&&ee3(a,eXW,null),(d||f)&&(eNj(l,u=new gu,d,f),ee3(a,eXW,u)),r=new pp(o),esA(new TY(i),r)}function ePc(e,t,n){var r,i,a,o,s,u,c,l,f;for(u=0,o=new evI,c=eow(vx(ty_,1),eHT,25,15,[0]),i=-1,a=0,r=0;u0){if(i<0&&l.a&&(i=u,a=c[0],r=0),i>=0){if(s=l.b,u==i&&0==(s-=r++))return 0;if(!eYw(t,c,l,s,o)){u=i-1,c[0]=a;continue}}else if(i=-1,!eYw(t,c,l,0,o))return 0}else{if(i=-1,32==UI(l.c,0)){if(f=c[0],eey(t,c),c[0]>f)continue}else if($D(t,l.c,c[0])){c[0]+=l.c.length;continue}return 0}return eYn(o,n)?c[0]:0}function ePl(e){var t,n,r,i,a,o,s,u;if(!e.f){if(u=new su,s=new su,null==(o=(t=tgz).a.zc(e,t))){for(a=new Ow($E(e));a.e!=a.i.gc();)i=Pp(epH(a),26),Y4(u,ePl(i));t.a.Bc(e),t.a.gc()}for(r=(e.s||(e.s=new FQ(tm6,e,21,17)),new Ow(e.s));r.e!=r.i.gc();)n=Pp(epH(r),170),M4(n,99)&&JL(s,Pp(n,18));euI(s),e.r=new PX(e,(Pp(etj(H9((BM(),tgv).o),6),18),s.i),s.g),Y4(u,e.r),euI(u),e.f=new xQ((Pp(etj(H9(tgv.o),5),18),u.i),u.g),Zd(e).b&=-3}return e.f}function ePf(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p;for(c=0,r=Je(ty_,eHT,25,o=e.o,15,1),i=Je(ty_,eHT,25,o,15,1),t=Je(ty_,eHT,25,n=e.p,15,1),a=Je(ty_,eHT,25,n,15,1);c=0&&!emy(e,l,f);)--f;i[l]=f}for(h=0;h=0&&!emy(e,s,p);)--s;a[p]=s}for(u=0;ut[d]&&dr[u]&&eCQ(e,u,d,!1,!0)}function ePd(e){var t,n,r,i,a,o,s,u;n=gN(LK(e_k(e,(eCk(),e9b)))),a=e.a.c.d,s=e.a.d.d,n?(o=Ol(C6(new kl(s.a,s.b),a),.5),u=Ol(MB(e.e),.5),t=C6(C5(new kl(a.a,a.b),o),u),Lf(e.d,t)):(i=gP(LV(e_k(e.a,e9I))),r=e.d,a.a>=s.a?a.b>=s.b?(r.a=s.a+(a.a-s.a)/2+i,r.b=s.b+(a.b-s.b)/2-i-e.e.b):(r.a=s.a+(a.a-s.a)/2+i,r.b=a.b+(s.b-a.b)/2+i):a.b>=s.b?(r.a=a.a+(s.a-a.a)/2+i,r.b=s.b+(a.b-s.b)/2+i):(r.a=a.a+(s.a-a.a)/2+i,r.b=a.b+(s.b-a.b)/2-i-e.e.b))}function ePh(e,t){var n,r,i,a,o,s,u;if(null==e)return null;if(0==(a=e.length))return"";for(u=Je(tyw,eHl,25,a,15,1),Ji(0,a,e.length),Ji(0,a,u.length),YF(e,0,a,u,0),n=null,s=t,i=0,o=0;i0?Az(n.a,0,a-1):"":e.substr(0,a-1):n?n.a:e}function ePp(e){_Y(e,new ewB(vQ(vq(vJ(vX(new oc,ezH),"ELK DisCo"),"Layouter for arranging unconnected subgraphs. The subgraphs themselves are, by default, not laid out."),new e4))),KE(e,ezH,ez$,epB(e67)),KE(e,ezH,ezz,epB(e63)),KE(e,ezH,ezG,epB(e6J)),KE(e,ezH,ezW,epB(e64)),KE(e,ezH,e$Q,epB(e69)),KE(e,ezH,e$1,epB(e66)),KE(e,ezH,e$J,epB(e68)),KE(e,ezH,e$0,epB(e65)),KE(e,ezH,ezj,epB(e61)),KE(e,ezH,ezF,epB(e6Q)),KE(e,ezH,ezY,epB(e60)),KE(e,ezH,ezB,epB(e62))}function ePb(e,t,n,r){var i,a,o,s,u,c,l,f,d;if(a=new eb$(e),lK(a,(eEn(),e8P)),eo3(a,(eBy(),tol),(ewf(),tbo)),i=0,t){for(o=new eES,eo3(o,(eBU(),tnc),t),eo3(a,tnc,t.i),ekv(o,(eYu(),tbY)),Gc(o,a),d=Kp(t.e),l=0,f=(c=d).length;lenR(e)?1:0,n=e.e,i=(r.length,eB4.Math.abs(zy(e.e)),new vl),1==t&&(i.a+="-"),e.e>0){if((n-=r.length-t)>=0){for(i.a+="0.";n>e0Z.length;n-=e0Z.length)RX(i,e0Z);CA(i,e0Z,zy(n)),xM(i,r.substr(t))}else n=t-n,xM(i,Az(r,t,zy(n))),i.a+=".",xM(i,xy(r,zy(n)))}else{for(xM(i,r.substr(t));n<-e0Z.length;n+=e0Z.length)RX(i,e0Z);CA(i,e0Z,zy(-n))}return i.a}function ePv(e,t,n,r){var i,a,o,s,u,c,l,f,d;return(c=(u=C6(new kl(n.a,n.b),e)).a*t.b-u.b*t.a,l=t.a*r.b-t.b*r.a,f=(u.a*r.b-u.b*r.a)/l,d=c/l,0!=l)?f>=0&&f<=1&&d>=0&&d<=1?C5(new kl(e.a,e.b),Ol(new kl(t.a,t.b),f)):null:0!=c?null:(a=Jh(e,i=C5(new kl(n.a,n.b),Ol(new kl(r.a,r.b),.5))),o=Jh(C5(new kl(e.a,e.b),t),i),s=.5*eB4.Math.sqrt(r.a*r.a+r.b*r.b),at.a&&(r.Hc((eyY(),tdW))?e.c.a+=(n.a-t.a)/2:r.Hc(tdV)&&(e.c.a+=n.a-t.a)),n.b>t.b&&(r.Hc((eyY(),tdZ))?e.c.b+=(n.b-t.b)/2:r.Hc(tdq)&&(e.c.b+=n.b-t.b)),Pp(e_k(e,(eBU(),tt3)),21).Hc((eLR(),ttw))&&(n.a>t.a||n.b>t.b))for(s=new fz(e.a);s.at.a&&(r.Hc((eyY(),tdW))?e.c.a+=(n.a-t.a)/2:r.Hc(tdV)&&(e.c.a+=n.a-t.a)),n.b>t.b&&(r.Hc((eyY(),tdZ))?e.c.b+=(n.b-t.b)/2:r.Hc(tdq)&&(e.c.b+=n.b-t.b)),Pp(e_k(e,(eBU(),tt3)),21).Hc((eLR(),ttw))&&(n.a>t.a||n.b>t.b))for(o=new fz(e.a);o.at&&(i=0,a+=l.b+n,f.c[f.c.length]=l,l=new W6(a,n),r=new es$(0,l.f,l,n),enN(l,r),i=0),0==r.b.c.length||u.f>=r.o&&u.f<=r.f||.5*r.a<=u.f&&1.5*r.a>=u.f?efg(r,u):(o=new es$(r.s+r.r+n,l.f,l,n),enN(l,o),efg(o,u)),i=u.i+u.g;return f.c[f.c.length]=l,f}function ePk(e){var t,n,r,i,a,o,s,u;if(!e.a){if(e.o=null,u=new pj(e),t=new sc,null==(s=(n=tgz).a.zc(e,n))){for(o=new Ow($E(e));o.e!=o.i.gc();)a=Pp(epH(o),26),Y4(u,ePk(a));n.a.Bc(e),n.a.gc()}for(i=(e.s||(e.s=new FQ(tm6,e,21,17)),new Ow(e.s));i.e!=i.i.gc();)r=Pp(epH(i),170),M4(r,322)&&JL(t,Pp(r,34));euI(t),e.k=new PZ(e,(Pp(etj(H9((BM(),tgv).o),7),18),t.i),t.g),Y4(u,e.k),euI(u),e.a=new xQ((Pp(etj(H9(tgv.o),4),18),u.i),u.g),Zd(e).b&=-2}return e.a}function ePx(e,t,n,r,i,a,o){var s,u,c,l,f,d;return f=!1,u=eO4(n.q,t.f+t.b-n.q.f),!((d=i-(n.q.e+u-o))=(GK(a,e.c.length),Pp(e.c[a],200)).e,(!((l=(s=ePI(r,d,!1)).a)>t.b)||!!c)&&((c||l<=t.b)&&(c&&l>t.b?(n.d=l,JR(n,eEP(n,l))):(eyC(n.q,u),n.c=!0),JR(r,i-(n.s+n.r)),ebP(r,n.q.e+n.q.d,t.f),enN(t,r),e.c.length>a&&(eva((GK(a,e.c.length),Pp(e.c[a],200)),r),0==(GK(a,e.c.length),Pp(e.c[a],200)).a.c.length&&ZV(e,a)),f=!0),f))}function ePT(e,t,n,r){var i,a,o,s,u,c,l;if(l=eAY(e.e.Tg(),t),i=0,a=Pp(e.g,119),u=null,_4(),Pp(t,66).Oj()){for(s=0;se.o.a&&(l=(u-e.o.a)/2,s.b=eB4.Math.max(s.b,l),s.c=eB4.Math.max(s.c,l))}}function ePA(e){var t,n,r,i,a,o,s,u;for(a=new W8,Tp(a,(eoM(),tdr)),r=(i=erG(e,Je(e17,eUP,2,0,6,1)),new fE(new g$(new wY(e,i).b)));r.b0?e.i:0)>t&&u>0&&(a=0,o+=u+e.i,i=eB4.Math.max(i,d),r+=u+e.i,u=0,d=0,n&&(++f,P_(e.n,new zO(e.s,o,e.i))),s=0),d+=c.g+(s>0?e.i:0),u=eB4.Math.max(u,c.f),n&&eml(Pp(RJ(e.n,f),211),c),a+=c.g+(s>0?e.i:0),++s;return i=eB4.Math.max(i,d),r+=u,n&&(e.r=i,e.d=r,egf(e.j)),new Hr(e.s,e.t,i,r)}function ePD(e,t,n,r,i){var a,o,s,u,c,l,f,d,h;if(wK(),Yh(e,"src"),Yh(n,"dest"),d=esF(e),u=esF(n),Pz((4&d.i)!=0,"srcType is not an array"),Pz((4&u.i)!=0,"destType is not an array"),f=d.c,o=u.c,Pz((1&f.i)!=0?f==o:(1&o.i)==0,"Array types don't match"),h=e.length,c=n.length,t<0||r<0||i<0||t+i>h||r+i>c)throw p7(new bE);if((1&f.i)==0&&d!=u){if(l=etG(e),a=etG(n),xc(e)===xc(n)&&tr;)Bc(a,s,l[--t]);else for(s=r+i;r0&&ekp(e,t,n,r,i,!0)}function ePN(){ePN=A,e07=eow(vx(ty_,1),eHT,25,15,[eHt,1162261467,eU2,1220703125,362797056,1977326743,eU2,387420489,eHK,214358881,429981696,815730721,1475789056,170859375,268435456,410338673,612220032,893871739,128e7,1801088541,113379904,148035889,191102976,244140625,308915776,387420489,481890304,594823321,729e6,887503681,eU2,1291467969,1544804416,1838265625,60466176]),e2e=eow(vx(ty_,1),eHT,25,15,[-1,-1,31,19,15,13,11,11,10,9,9,8,8,8,8,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5])}function ePP(e){var t,n,r,i,a,o,s,u;for(i=new fz(e.b);i.a=e.b.length?(a[i++]=o.b[r++],a[i++]=o.b[r++]):r>=o.b.length?(a[i++]=e.b[n++],a[i++]=e.b[n++]):o.b[r]0?e.i:0)),++t;for(efX(e.n,u),e.d=n,e.r=r,e.g=0,e.f=0,e.e=0,e.o=eHQ,e.p=eHQ,a=new fz(e.b);a.a0&&(i=(e.n||(e.n=new FQ(e6S,e,1,7)),Pp(etj(e.n,0),137)).a)&&xM(xM((t.a+=' "',t),i),'"')),(n=(e.b||(e.b=new Ih(e6m,e,4,7)),!(e.b.i<=1&&(e.c||(e.c=new Ih(e6m,e,5,8)),e.c.i<=1))))?(t.a+=" [",t):(t.a+=" ",t),xM(t,OU(new ve,new Ow(e.b))),n&&(t.a+="]"),t.a+=eGH,n&&(t.a+="["),xM(t,OU(new ve,new Ow(e.c))),n&&(t.a+="]"),t.a)}function ePB(e,t){var n,r,i,a,o,s,u;if(e.a){if(s=e.a.ne(),u=null,null!=s?t.a+=""+s:null!=(o=e.a.Dj())&&(-1!=(a=x7(o,e_n(91)))?(u=o.substr(a),t.a+=""+Az(null==o?eUg:(BJ(o),o),0,a)):t.a+=""+o),e.d&&0!=e.d.i){for(i=!0,t.a+="<",r=new Ow(e.d);r.e!=r.i.gc();)n=Pp(epH(r),87),i?i=!1:(t.a+=eUd,t),ePB(n,t);t.a+=">"}null!=u&&(t.a+=""+u)}else e.e?null!=(s=e.e.zb)&&(t.a+=""+s):(t.a+="?",e.b?(t.a+=" super ",ePB(e.b,t)):e.f&&(t.a+=" extends ",ePB(e.f,t)))}function ePU(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T;for(_=e.c,E=t.c,n=QI(_.a,e,0),r=QI(E.a,t,0),y=Pp(edE(e,(enY(),tsD)).Kc().Pb(),11),x=Pp(edE(e,tsN).Kc().Pb(),11),w=Pp(edE(t,tsD).Kc().Pb(),11),T=Pp(edE(t,tsN).Kc().Pb(),11),g=Kp(y.e),S=Kp(x.g),v=Kp(w.e),k=Kp(T.g),egU(e,r,E),l=0,p=(o=v).length;ll?new GT((Xa(),tuH),n,t,c-l):c>0&&l>0&&(new GT((Xa(),tuH),t,n,0),new GT(tuH,n,t,0))),o)}function ePz(e,t){var n,r,i,a,o,s;for(o=new esz(new fS(e.f.b).a);o.b;){if(a=etz(o),i=Pp(a.cd(),594),1==t){if(i.gf()!=(ec3(),tpy)&&i.gf()!=tpb)continue}else if(i.gf()!=(ec3(),tpm)&&i.gf()!=tpg)continue;switch(r=Pp(Pp(a.dd(),46).b,81),n=(s=Pp(Pp(a.dd(),46).a,189)).c,i.gf().g){case 2:r.g.c=e.e.a,r.g.b=eB4.Math.max(1,r.g.b+n);break;case 1:r.g.c=r.g.c+n,r.g.b=eB4.Math.max(1,r.g.b-n);break;case 4:r.g.d=e.e.b,r.g.a=eB4.Math.max(1,r.g.a+n);break;case 3:r.g.d=r.g.d+n,r.g.a=eB4.Math.max(1,r.g.a-n)}}}function ePG(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b;for(s=Je(ty_,eHT,25,t.b.c.length,15,1),c=Je(e4P,eU4,267,t.b.c.length,0,1),u=Je(e4N,eGW,10,t.b.c.length,0,1),f=e.a,d=0,h=f.length;d0&&u[r]&&(p=Mj(e.b,u[r],i)),b=eB4.Math.max(b,i.c.c.b+p);for(a=new fz(l.e);a.a1)throw p7(new gL(eQ$));u||(a=V4(t,r.Kc().Pb()),o.Fc(a))}return eo0(e,eSu(e,t,n),o)}function ePZ(e,t){var n,r,i,a;for(etY(t.b.j),_r(UQ(new R1(null,new Gq(t.d,16)),new iy),new iw),a=new fz(t.d);a.ae.o.b||(n=efr(e,tby),(s=t.d+t.a+(n.gc()-1)*o)>e.o.b)))}function eP5(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p;if(o=e.e,u=t.e,0==o)return t;if(0==u)return e;if((a=e.d)+(s=t.d)==2)return(n=WM(e.a[0],eH8),r=WM(t.a[0],eH8),o==u)?(p=jE(l=eft(n,r)),0==(h=jE(Fy(l,32)))?new XE(o,p):new F7(o,2,eow(vx(ty_,1),eHT,25,15,[p,h]))):ep_(o<0?efe(r,n):efe(n,r));if(o==u)d=o,f=a>=s?X7(e.a,a,t.a,s):X7(t.a,s,e.a,a);else{if(0==(i=a!=s?a>s?1:-1:es8(e.a,t.a,a)))return eLQ(),e08;1==i?(d=o,f=Z1(e.a,a,t.a,s)):(d=u,f=Z1(t.a,s,e.a,a))}return c=new F7(d,f.length,f),Ku(c),c}function eP6(e,t,n,r,i,a,o){var s,u,c,l,f,d,h;return f=gN(LK(e_k(t,(eBy(),taV)))),d=null,a==(enY(),tsD)&&r.c.i==n?d=r.c:a==tsN&&r.d.i==n&&(d=r.d),(c=o)&&f&&!d?(P_(c.e,r),h=eB4.Math.max(gP(LV(e_k(c.d,tak))),gP(LV(e_k(r,tak)))),eo3(c.d,tak,h)):(l=(eYu(),tbF),d?l=d.j:TM(Pp(e_k(n,tol),98))&&(l=a==tsD?tbY:tby),u=eP8(e,t,n,a,l,r),s=ZD((Bq(n),r)),a==tsD?(Gs(s,Pp(RJ(u.j,0),11)),Go(s,i)):(Gs(s,i),Go(s,Pp(RJ(u.j,0),11))),c=new ec8(r,s,u,Pp(e_k(u,(eBU(),tnc)),11),a,!d)),exg(e.a,r,new DT(c.d,t,a)),c}function eP9(e,t){var n,r,i,a,o,s,u,c,l,f;if(l=null,e.d&&(l=Pp(zg(e.d,t),138)),!l){if(f=(a=e.a.Mh()).i,!e.d||wq(e.d)!=f){for(u=new p2,e.d&&eij(u,e.d),s=c=u.f.c+u.g.c;s0?(h=(p-1)*n,s&&(h+=r),l&&(h+=r),!(h=e.b[i+1])i+=2;else if(n0)for(r=new I4(Pp(Zq(e.a,a),21)),Hj(),Mv(r,new dT(t)),i=new KB(a.b,0);i.b_)?(u=2,o=eUu):0==u?(u=1,o=S):(u=0,o=S):(h=S>=o||o-S0?1:Te(isNaN(r),isNaN(0)))>=0^(enj(eVU),(eB4.Math.abs(s)<=eVU||0==s||isNaN(s)&&isNaN(0)?0:s<0?-1:s>0?1:Te(isNaN(s),isNaN(0)))>=0))?eB4.Math.max(s,r):(enj(eVU),(eB4.Math.abs(r)<=eVU||0==r||isNaN(r)&&isNaN(0)?0:r<0?-1:r>0?1:Te(isNaN(r),isNaN(0)))>0)?eB4.Math.sqrt(s*s+r*r):-eB4.Math.sqrt(s*s+r*r)}function eRv(e,t){var n,r,i,a,o,s;if(t){if(e.a||(e.a=new bZ),2==e.e){bY(e.a,t);return}if(1==t.e){for(i=0;i=eH3?xk(n,el1(r)):Bf(n,r&eHd),o=(++tyv,new zc(10,null,0)),Yu(e.a,o,s-1)):xk(n=(o.bm().length,new vu),o.bm()),0==t.e?(r=t._l())>=eH3?xk(n,el1(r)):Bf(n,r&eHd):xk(n,t.bm()),Pp(o,521).b=n.a}}function eRy(e){var t,n,r,i,a;return null!=e.g?e.g:e.a<32?(e.g=eYS(eap(e.f),zy(e.e)),e.g):(i=eBw((e.c||(e.c=euK(e.f)),e.c),0),0==e.e)?i:(t=(e.c||(e.c=euK(e.f)),e.c).e<0?2:1,n=i.length,r=-e.e+n-t,a=new vc,a.a+=""+i,e.e>0&&r>=-6?r>=0?Gn(a,n-zy(e.e),"."):(a.a=Az(a.a,0,t-1)+"0."+xy(a.a,t-1),Gn(a,t+1,ehv(e0Z,0,-zy(r)-1))):(n-t>=1&&(Gn(a,t,"."),++n),Gn(a,n,"E"),r>0&&Gn(a,++n,"+"),Gn(a,++n,""+Fb(eap(r)))),e.g=a.a,e.g)}function eRw(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m;if(!n.dc()){for(s=0,d=0,p=Pp((r=n.Kc()).Pb(),19).a;s1&&(u=c.mg(u,e.a,s));return 1==u.c.length?Pp(RJ(u,u.c.length-1),220):2==u.c.length?eRr((GK(0,u.c.length),Pp(u.c[0],220)),(GK(1,u.c.length),Pp(u.c[1],220)),o,a):null}function eRk(e){var t,n,r,i,a,o;for(ety(e.a,new eJ),n=new fz(e.a);n.a=eB4.Math.abs(r.b)?(r.b=0,a.d+a.a>o.d&&a.do.c&&a.c0){if(t=new xt(e.i,e.g),a=(n=e.i)<100?null:new yf(n),e.ij())for(r=0;r0){for(s=e.g,c=e.i,ZG(e),a=c<100?null:new yf(c),r=0;r>13|(15&e.m)<<9,i=e.m>>4&8191,a=e.m>>17|(255&e.h)<<5,o=(1048320&e.h)>>8,s=8191&t.l,u=t.l>>13|(15&t.m)<<9,c=t.m>>4&8191,l=t.m>>17|(255&t.h)<<5,f=(1048320&t.h)>>8,k=n*s,x=r*s,T=i*s,M=a*s,O=o*s,0!=u&&(x+=n*u,T+=r*u,M+=i*u,O+=a*u),0!=c&&(T+=n*c,M+=r*c,O+=i*c),0!=l&&(M+=n*l,O+=r*l),0!=f&&(O+=n*f),d=(h=k&eHH)+(p=(511&x)<<13),m=k>>22,g=x>>9,b=m+g+(v=(262143&T)<<4)+(y=(31&M)<<17),_=T>>18,w=_+(E=M>>5)+(S=(4095&O)<<8),b+=d>>22,d&=eHH,w+=b>>22,Mk(d,b&=eHH,w&=eH$)}function eRA(e){var t,n,r,i,a,o,s;if(0!=(s=Pp(RJ(e.j,0),11)).g.c.length&&0!=s.e.c.length)throw p7(new gC("Interactive layout does not support NORTH/SOUTH ports with incoming _and_ outgoing edges."));if(0!=s.g.c.length){for(a=eHQ,n=new fz(s.g);n.a4){if(!e.wj(t))return!1;if(e.rk()){if(u=(r=(i=Pp(t,49)).Ug())==e.e&&(e.Dk()?i.Og(i.Vg(),e.zk())==e.Ak():-1-i.Vg()==e.aj()),e.Ek()&&!u&&!r&&i.Zg()){for(a=0;a0&&(c=e.n.a/a);break;case 2:case 4:(i=e.i.o.b)>0&&(c=e.n.b/i)}eo3(e,(eBU(),tnv),c)}if(u=e.o,o=e.a,r)o.a=r.a,o.b=r.b,e.d=!0;else if(t!=tbc&&t!=tbl&&s!=tbF)switch(s.g){case 1:o.a=u.a/2;break;case 2:o.a=u.a,o.b=u.b/2;break;case 3:o.a=u.a/2,o.b=u.b;break;case 4:o.b=u.b/2}else o.a=u.a/2,o.b=u.b/2}function eRP(e){var t,n,r,i,a,o,s,u,c,l;if(e.ej()){if(l=e.Vi(),u=e.fj(),l>0){if(t=new eiP(e.Gi()),a=(n=l)<100?null:new yf(n),Cf(e,n,t.g),i=1==n?e.Zi(4,etj(t,0),null,0,u):e.Zi(6,t,null,-1,u),e.bj()){for(r=new Ow(t);r.e!=r.i.gc();)a=e.dj(epH(r),a);a?(a.Ei(i),a.Fi()):e.$i(i)}else a?(a.Ei(i),a.Fi()):e.$i(i)}else Cf(e,e.Vi(),e.Wi()),e.$i(e.Zi(6,(Hj(),e2r),null,-1,u))}else if(e.bj()){if((l=e.Vi())>0){for(s=e.Wi(),c=l,Cf(e,l,s),a=c<100?null:new yf(c),r=0;re.d[o.p]&&(n+=qq(e.b,a)*Pp(u.b,19).a,Vw(e.a,ell(a)));for(;!gY(e.a);)eek(e.b,Pp(Yn(e.a),19).a)}return n}function eRF(e,t,n,r){var i,a,o,s,u,c,l,f,d,h,p,b,m;for((f=new TS(Pp(eT8(e,(e_C(),tdB)),8))).a=eB4.Math.max(f.a-n.b-n.c,0),f.b=eB4.Math.max(f.b-n.d-n.a,0),(null==(i=LV(eT8(e,tdN)))||(BJ(i),i<=0))&&(i=1.3),s=new p0,p=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));p.e!=p.i.gc();)h=Pp(epH(p),33),o=new Lp(h),s.c[s.c.length]=o;switch((d=Pp(eT8(e,tdP),311)).g){case 3:m=eDQ(s,t,f.a,f.b,(c=r,BJ(i),c));break;case 1:m=eN0(s,t,f.a,f.b,(l=r,BJ(i),l));break;default:m=eRH(s,t,f.a,f.b,(u=r,BJ(i),u))}a=new etD(m),b=eY9(a,t,n,f.a,f.b,r,(BJ(i),i)),eYx(e,b.a,b.b,!1,!0)}function eRY(e,t){var n,r,i,a;n=t.b,a=new I4(n.j),i=0,(r=n.j).c=Je(e1R,eUp,1,0,5,1),Y$(Pp(eay(e.b,(eYu(),tbw),(erX(),tep)),15),n),i=emQ(a,i,new r3,r),Y$(Pp(eay(e.b,tbw,teh),15),n),i=emQ(a,i,new r2,r),Y$(Pp(eay(e.b,tbw,ted),15),n),Y$(Pp(eay(e.b,tby,tep),15),n),Y$(Pp(eay(e.b,tby,teh),15),n),i=emQ(a,i,new r4,r),Y$(Pp(eay(e.b,tby,ted),15),n),Y$(Pp(eay(e.b,tbj,tep),15),n),i=emQ(a,i,new r5,r),Y$(Pp(eay(e.b,tbj,teh),15),n),i=emQ(a,i,new r6,r),Y$(Pp(eay(e.b,tbj,ted),15),n),Y$(Pp(eay(e.b,tbY,tep),15),n),i=emQ(a,i,new ic,r),Y$(Pp(eay(e.b,tbY,teh),15),n),Y$(Pp(eay(e.b,tbY,ted),15),n)}function eRB(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b;for(ewG(t,"Layer size calculation",1),l=eHQ,c=eH1,i=!1,s=new fz(e.b);s.a.5?g-=2*o*(p-.5):p<.5&&(g+=2*a*(.5-p)),g<(i=s.d.b)&&(g=i),b=s.d.c,g>m.a-b-l&&(g=m.a-b-l),s.n.a=t+g}}function eRH(e,t,n,r,i){var a,o,s,u,c,l,f,d,h,p,b,m;for(s=Je(tyx,eH5,25,e.c.length,15,1),d=new Fz(new oB),egV(d,e),c=0,b=new p0;0!=d.b.c.length;)if(o=Pp(0==d.b.c.length?null:RJ(d.b,0),157),c>1&&jl(o)*jc(o)/2>s[0]){for(a=0;as[a];)++a;p=new Gz(b,0,a+1),f=new etD(p),l=jl(o)/jc(o),u=eY9(f,t,new mp,n,r,i,l),C5(xB(f.e),u),Ja(e_s(d,f)),egV(d,h=new Gz(b,a+1,b.c.length)),b.c=Je(e1R,eUp,1,0,5,1),c=0,jA(s,s.length,0)}else null!=(m=0==d.b.c.length?null:RJ(d.b,0))&&erD(d,0),c>0&&(s[c]=s[c-1]),s[c]+=jl(o)*jc(o),++c,b.c[b.c.length]=o;return b}function eR$(e){var t,n,r,i,a;if((r=Pp(e_k(e,(eBy(),taY)),163))==(ef_(),tnN)){for(n=new Fa(OH(efu(e).a.Kc(),new c));eTk(n);)if(t=Pp(ZC(n),17),!ZI(t))throw p7(new gq(eWr+egs(e)+"' has its layer constraint set to FIRST_SEPARATE, but has at least one incoming edge. FIRST_SEPARATE nodes must not have incoming edges."))}else if(r==tnR){for(a=new Fa(OH(efc(e).a.Kc(),new c));eTk(a);)if(i=Pp(ZC(a),17),!ZI(i))throw p7(new gq(eWr+egs(e)+"' has its layer constraint set to LAST_SEPARATE, but has at least one outgoing edge. LAST_SEPARATE nodes must not have outgoing edges."))}}function eRz(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p;for(ewG(t,"Label dummy removal",1),r=gP(LV(e_k(e,(eBy(),toL)))),i=gP(LV(e_k(e,toN))),c=Pp(e_k(e,tal),103),u=new fz(e.b);u.a0&&eE9(e,s,f);for(i=new fz(f);i.a>19!=0&&(t=eoQ(t),u=!u),o=eOy(t),a=!1,i=!1,r=!1,e.h==eHz&&0==e.m&&0==e.l){if(i=!0,a=!0,-1!=o)return s=eTC(e,o),u&&esh(s),n&&(e0A=Mk(0,0,0)),s;e=Tr((Q2(),e0L)),r=!0,u=!u}else e.h>>19!=0&&(a=!0,e=eoQ(e),r=!0,u=!u);return -1!=o?esk(e,o,u,a,n):0>evy(e,t)?(n&&(e0A=a?eoQ(e):Mk(e.l,e.m,e.h)),Mk(0,0,0)):eDr(r?e:Mk(e.l,e.m,e.h),t,u,a,i,n)}function eRq(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p;if(e.e&&e.c.ct.f)&&!(t.g>e.f)){for(n=0,r=0,o=e.w.a.ec().Kc();o.Ob();)i=Pp(o.Pb(),11),euz(esp(eow(vx(e50,1),eUP,8,0,[i.i.n,i.n,i.a])).b,t.g,t.f)&&++n;for(s=e.r.a.ec().Kc();s.Ob();)i=Pp(s.Pb(),11),euz(esp(eow(vx(e50,1),eUP,8,0,[i.i.n,i.n,i.a])).b,t.g,t.f)&&--n;for(u=t.w.a.ec().Kc();u.Ob();)i=Pp(u.Pb(),11),euz(esp(eow(vx(e50,1),eUP,8,0,[i.i.n,i.n,i.a])).b,e.g,e.f)&&++r;for(a=t.r.a.ec().Kc();a.Ob();)i=Pp(a.Pb(),11),euz(esp(eow(vx(e50,1),eUP,8,0,[i.i.n,i.n,i.a])).b,e.g,e.f)&&--r;n=0)return i=efd(e,t.substr(1,o-1)),eYF(e,l=t.substr(o+1,u-(o+1)),i)}else{if(n=-1,null==e0F&&(e0F=RegExp("\\d")),e0F.test(String.fromCharCode(s))&&(n=IO(t,e_n(46),u-1))>=0){r=Pp(ZN(e,etm(e,t.substr(1,n-1)),!1),58),c=0;try{c=eDa(t.substr(n+1),eHt,eUu)}catch(d){if(d=eoa(d),M4(d,127))throw a=d,p7(new QH(a));throw p7(d)}if(c=0)return n;switch(Ur(QZ(e,n))){case 2:if(IE("",ecG(e,n.Hj()).ne())){if(u=U$(QZ(e,n)),s=UH(QZ(e,n)),l=eMv(e,t,u,s))return l;for(o=0,f=(i=eIx(e,t)).gc();o1)throw p7(new gL(eQ$));for(o=0,l=eAY(e.e.Tg(),t),r=Pp(e.g,119);o1,c=new Z4(d.b);My(c.a)||My(c.b);)f=(u=Pp(My(c.a)?Wx(c.a):Wx(c.b),17)).c==d?u.d:u.c,eB4.Math.abs(esp(eow(vx(e50,1),eUP,8,0,[f.i.n,f.n,f.a])).b-o.b)>1&&eAZ(e,u,o,a,d)}}function eR8(e){var t,n,r,i,a,o;if(i=new KB(e.e,0),r=new KB(e.a,0),e.d)for(n=0;neVW;){for(a=t,o=0;eB4.Math.abs(t-a)0),i.a.Xb(i.c=--i.b),eNy(e,e.b-o,a,r,i),A6(i.b0),r.a.Xb(r.c=--r.b)}if(!e.d)for(n=0;n0?(e.f[l.p]=h/(l.e.c.length+l.g.c.length),e.c=eB4.Math.min(e.c,e.f[l.p]),e.b=eB4.Math.max(e.b,e.f[l.p])):s&&(e.f[l.p]=h)}}function ejt(e){e.b=null,e.bb=null,e.fb=null,e.qb=null,e.a=null,e.c=null,e.d=null,e.e=null,e.f=null,e.n=null,e.M=null,e.L=null,e.Q=null,e.R=null,e.K=null,e.db=null,e.eb=null,e.g=null,e.i=null,e.j=null,e.k=null,e.gb=null,e.o=null,e.p=null,e.q=null,e.r=null,e.$=null,e.ib=null,e.S=null,e.T=null,e.t=null,e.s=null,e.u=null,e.v=null,e.w=null,e.B=null,e.A=null,e.C=null,e.D=null,e.F=null,e.G=null,e.H=null,e.I=null,e.J=null,e.P=null,e.Z=null,e.U=null,e.V=null,e.W=null,e.X=null,e.Y=null,e._=null,e.ab=null,e.cb=null,e.hb=null,e.nb=null,e.lb=null,e.mb=null,e.ob=null,e.pb=null,e.jb=null,e.kb=null,e.N=!1,e.O=!1}function ejn(e,t,n){var r,i,a,o;for(ewG(n,"Graph transformation ("+e.a+")",1),o=WC(t.a),a=new fz(t.b);a.a0&&(e.a=u+(p-1)*a,t.c.b+=e.a,t.f.b+=e.a),0!=b.a.gc()&&(p=ejF(h=new YJ(1,a),t,b,m,t.f.b+u-t.c.b))>0&&(t.f.b+=u+(p-1)*a)}function eji(e,t){var n,r,i,a;a=e.F,null==t?(e.F=null,euc(e,null)):(e.F=(BJ(t),t),-1!=(r=x7(t,e_n(60)))?(i=t.substr(0,r),-1!=x7(t,e_n(46))||IE(i,eUi)||IE(i,eJZ)||IE(i,eJX)||IE(i,eJJ)||IE(i,eJQ)||IE(i,eJ1)||IE(i,eJ0)||IE(i,eJ2)||(i=eJ3),-1!=(n=O8(t,e_n(62)))&&(i+=""+t.substr(n+1)),euc(e,i)):(i=t,-1==x7(t,e_n(46))&&(-1!=(r=x7(t,e_n(91)))&&(i=t.substr(0,r)),IE(i,eUi)||IE(i,eJZ)||IE(i,eJX)||IE(i,eJJ)||IE(i,eJQ)||IE(i,eJ1)||IE(i,eJ0)||IE(i,eJ2)?i=t:(i=eJ3,-1!=r&&(i+=""+t.substr(r)))),euc(e,i),i==t&&(e.F=e.D))),(4&e.Db)!=0&&(1&e.Db)==0&&eam(e,new FX(e,1,5,a,t))}function eja(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y;if(!((b=t.b.c.length)<3)){for(h=Je(ty_,eHT,25,b,15,1),f=0,l=new fz(t.b);l.ao)&&Yf(e.b,Pp(m.b,17));++s}a=o}}}function ejo(e,t){var n;if(null==t||IE(t,eUg)||0==t.length&&e.k!=(eSd(),tdy))return null;switch(e.k.g){case 1:return ehZ(t,eq6)?(OQ(),e0P):ehZ(t,eq9)?(OQ(),e0N):null;case 2:try{return ell(eDa(t,eHt,eUu))}catch(r){if(r=eoa(r),M4(r,127))return null;throw p7(r)}case 4:try{return eEu(t)}catch(i){if(i=eoa(i),M4(i,127))return null;throw p7(i)}case 3:return t;case 5:return euC(e),exs(e,t);case 6:return euC(e),eMj(e,e.a,t);case 7:try{return(n=eTh(e)).Jf(t),n}catch(a){if(a=eoa(a),M4(a,32))return null;throw p7(a)}default:throw p7(new gC("Invalid type set for this layout option."))}}function ejs(e){var t,n,r,i,a,o,s;for(eeP(),s=new b6,n=new fz(e);n.a=s.b.c)&&(s.b=t),(!s.c||t.c<=s.c.c)&&(s.d=s.c,s.c=t),(!s.e||t.d>=s.e.d)&&(s.e=t),(!s.f||t.d<=s.f.d)&&(s.f=t);return r=new epG((eok(),e8f)),Kv(e,e8y,new g$(eow(vx(e4M,1),eUp,369,0,[r]))),o=new epG(e8p),Kv(e,e8v,new g$(eow(vx(e4M,1),eUp,369,0,[o]))),i=new epG(e8d),Kv(e,e8g,new g$(eow(vx(e4M,1),eUp,369,0,[i]))),a=new epG(e8h),Kv(e,e8m,new g$(eow(vx(e4M,1),eUp,369,0,[a]))),eOk(r.c,e8f),eOk(i.c,e8d),eOk(a.c,e8h),eOk(o.c,e8p),s.a.c=Je(e1R,eUp,1,0,5,1),eoc(s.a,r.c),eoc(s.a,eaa(i.c)),eoc(s.a,a.c),eoc(s.a,eaa(o.c)),s}function eju(e){var t;switch(e.d){case 1:if(e.hj())return -2!=e.o;break;case 2:if(e.hj())return -2==e.o;break;case 3:case 5:case 4:case 6:case 7:return e.o>-2;default:return!1}switch(t=e.gj(),e.p){case 0:return null!=t&&gN(LK(t))!=xg(e.k,0);case 1:return null!=t&&Pp(t,217).a!=jE(e.k)<<24>>24;case 2:return null!=t&&Pp(t,172).a!=(jE(e.k)&eHd);case 6:return null!=t&&xg(Pp(t,162).a,e.k);case 5:return null!=t&&Pp(t,19).a!=jE(e.k);case 7:return null!=t&&Pp(t,184).a!=jE(e.k)<<16>>16;case 3:return null!=t&&gP(LV(t))!=e.j;case 4:return null!=t&&Pp(t,155).a!=e.j;default:return null==t?null!=e.n:!ecX(t,e.n)}}function ejc(e,t,n){var r,i,a,o;return e.Fk()&&e.Ek()&&(o=FU(e,Pp(n,56)),xc(o)!==xc(n))?(e.Oi(t),e.Ui(t,J6(e,t,o)),e.rk()&&(a=(i=Pp(n,49),e.Dk()?e.Bk()?i.ih(e.b,ebY(Pp(ee2($S(e.b),e.aj()),18)).n,Pp(ee2($S(e.b),e.aj()).Yj(),26).Bj(),null):i.ih(e.b,edv(i.Tg(),ebY(Pp(ee2($S(e.b),e.aj()),18))),null,null):i.ih(e.b,-1-e.aj(),null,null)),Pp(o,49).eh()||(a=(r=Pp(o,49),e.Dk()?e.Bk()?r.gh(e.b,ebY(Pp(ee2($S(e.b),e.aj()),18)).n,Pp(ee2($S(e.b),e.aj()).Yj(),26).Bj(),a):r.gh(e.b,edv(r.Tg(),ebY(Pp(ee2($S(e.b),e.aj()),18))),null,a):r.gh(e.b,-1-e.aj(),null,a))),a&&a.Fi()),TO(e.b)&&e.$i(e.Zi(9,n,o,t,!1)),o):n}function ejl(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w;for(l=gP(LV(e_k(e,(eBy(),toC)))),r=gP(LV(e_k(e,toG))),eo3(d=new oG,toC,l+r),g=(c=t).d,b=c.c.i,v=c.d.i,m=Tl(b.c),y=Tl(v.c),i=new p0,f=m;f<=y;f++)s=new eb$(e),lK(s,(eEn(),e8D)),eo3(s,(eBU(),tnc),c),eo3(s,tol,(ewf(),tbo)),eo3(s,toD,d),h=Pp(RJ(e.b,f),29),f==m?egU(s,h.a.c.length-n,h):Gu(s,h),(w=gP(LV(e_k(c,tak))))<0&&eo3(c,tak,w=0),s.o.b=w,p=eB4.Math.floor(w/2),o=new eES,ekv(o,(eYu(),tbY)),Gc(o,s),o.n.b=p,u=new eES,ekv(u,tby),Gc(u,s),u.n.b=p,Go(c,o),a=new $b,eaW(a,c),eo3(a,taR,null),Gs(a,u),Go(a,g),evT(s,c,a),i.c[i.c.length]=a,c=a;return i}function ejf(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y;for(u=Pp(eEC(e,(eYu(),tbY)).Kc().Pb(),11).e,h=Pp(eEC(e,tby).Kc().Pb(),11).g,s=u.c.length,y=GX(Pp(RJ(e.j,0),11));s-- >0;){for(b=(GK(0,u.c.length),Pp(u.c[0],17)),a=QI(v=(i=(GK(0,h.c.length),Pp(h.c[0],17))).d.e,i,0),KW(b,i.d,a),Gs(i,null),Go(i,null),p=b.a,t&&P7(p,new TS(y)),r=epL(i.a,0);r.b!=r.d.c;)n=Pp(Vv(r),8),P7(p,new TS(n));for(g=b.b,d=new fz(i.b);d.a0&&(o=eB4.Math.max(o,eix(e.C.b+r.d.b,i))),l=r,f=i,d=a;e.C&&e.C.c>0&&(h=d+e.C.c,c&&(h+=l.d.c),o=eB4.Math.max(o,(Mc(),enj(ezs),eB4.Math.abs(f-1)<=ezs||1==f||isNaN(f)&&isNaN(1)?0:h/(1-f)))),n.n.b=0,n.a.a=o}function ejh(e,t){var n,r,i,a,o,s,u,c,l,f,d,h;if(n=Pp(UA(e.b,t),124),(u=Pp(Pp(Zq(e.r,t),21),84)).dc()){n.n.d=0,n.n.a=0;return}for(c=e.u.Hc((ekU(),tbp)),o=0,e.A.Hc((ed6(),tbq))&&eCN(e,t),s=u.Kc(),l=null,d=0,f=0;s.Ob();)a=gP(LV((r=Pp(s.Pb(),111)).b.We((Ab(),e4a)))),i=r.b.rf().b,l?(h=f+l.d.a+e.w+r.d.d,o=eB4.Math.max(o,(Mc(),enj(ezs),eB4.Math.abs(d-a)<=ezs||d==a||isNaN(d)&&isNaN(a)?0:h/(a-d)))):e.C&&e.C.d>0&&(o=eB4.Math.max(o,eix(e.C.d+r.d.d,a))),l=r,d=a,f=i;e.C&&e.C.a>0&&(h=f+e.C.a,c&&(h+=l.d.a),o=eB4.Math.max(o,(Mc(),enj(ezs),eB4.Math.abs(d-1)<=ezs||1==d||isNaN(d)&&isNaN(1)?0:h/(1-d)))),n.n.d=0,n.a.b=o}function ejp(e,t,n){var r,i,a,o,s,u;for(o=0,this.g=e,s=t.d.length,u=n.d.length,this.d=Je(e4N,eGW,10,s+u,0,1);o0?etU(this,this.f/this.a):null!=Ot(t.g,t.d[0]).a&&null!=Ot(n.g,n.d[0]).a?etU(this,(gP(Ot(t.g,t.d[0]).a)+gP(Ot(n.g,n.d[0]).a))/2):null!=Ot(t.g,t.d[0]).a?etU(this,Ot(t.g,t.d[0]).a):null!=Ot(n.g,n.d[0]).a&&etU(this,Ot(n.g,n.d[0]).a)}function ejb(e,t){var n,r,i,a,o,s,u,c,l,f;for(e.a=new Bv(eiG(e55)),r=new fz(t.a);r.a=1&&(m-o>0&&f>=0?(u.n.a+=b,u.n.b+=a*o):m-o<0&&l>=0&&(u.n.a+=b*m,u.n.b+=a));e.o.a=t.a,e.o.b=t.b,eo3(e,(eBy(),ta4),(ed6(),r=Pp(yw(e6o),9),new I1(r,Pp(CY(r,r.length),9),0)))}function ej_(e,t,n,r,i,a){var o;if(!(null==t||!efz(t,tmJ,tmQ)))throw p7(new gL("invalid scheme: "+t));if(!e&&!(null!=n&&-1==x7(n,e_n(35))&&n.length>0&&(GV(0,n.length),47!=n.charCodeAt(0))))throw p7(new gL("invalid opaquePart: "+n));if(e&&!(null!=t&&wZ(tm$,t.toLowerCase()))&&!(null==n||!efz(n,tm1,tm0))||e&&null!=t&&wZ(tm$,t.toLowerCase())&&!eyQ(n))throw p7(new gL(eJI+n));if(!ef$(r))throw p7(new gL("invalid device: "+r));if(!ece(i))throw o=null==i?"invalid segments: null":"invalid segment: "+euR(i),p7(new gL(o));if(!(null==a||-1==x7(a,e_n(35))))throw p7(new gL("invalid query: "+a))}function ejE(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g;for(ewG(t,"Calculate Graph Size",1),t.n&&e&&WG(t,KS(e),(eup(),tmr)),s=ezq,u=ezq,a=eqe,o=eqe,f=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));f.e!=f.i.gc();)p=(c=Pp(epH(f),33)).i,b=c.j,g=c.g,r=c.f,i=Pp(eT8(c,(eBB(),thy)),142),s=eB4.Math.min(s,p-i.b),u=eB4.Math.min(u,b-i.d),a=eB4.Math.max(a,p+g+i.c),o=eB4.Math.max(o,b+r+i.a);for(h=Pp(eT8(e,(eBB(),thN)),116),d=new kl(s-h.b,u-h.d),l=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));l.e!=l.i.gc();)c=Pp(epH(l),33),eno(c,c.i-d.a),ens(c,c.j-d.b);m=a-s+(h.b+h.c),n=o-u+(h.d+h.a),ena(e,m),eni(e,n),t.n&&e&&WG(t,KS(e),(eup(),tmr))}function ejS(e){var t,n,r,i,a,o,s,u,c,l;for(r=new p0,o=new fz(e.e.a);o.a0){epV(e,n,0),n.a+=String.fromCharCode(r),epV(e,n,i=ehR(t,a)),a+=i-1;continue}39==r?a+11)for(b=Je(ty_,eHT,25,e.b.b.c.length,15,1),f=0,c=new fz(e.b.b);c.a=s&&i<=u)s<=i&&a<=u?(n[l++]=i,n[l++]=a,r+=2):s<=i?(n[l++]=i,n[l++]=u,e.b[r]=u+1,o+=2):a<=u?(n[l++]=s,n[l++]=a,r+=2):(n[l++]=s,n[l++]=u,e.b[r]=u+1);else if(ueHe)&&s<10)vR(e.c,new tf),ejM(e),Ym(e.c),ejv(e.f)}function ejL(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m;if(gN(LK(e_k(n,(eBy(),taI)))))for(s=new fz(n.j);s.a=2){for(o=Pp(Vv(u=epL(n,0)),8),s=Pp(Vv(u),8);s.a0&&eoY(l,!0,(ec3(),tpg)),s.k==(eEn(),e8C)&&UP(l),Um(e.f,s,t)}}function ejN(e,t,n){var r,i,a,o,s,u,c,l,f,d;switch(ewG(n,"Node promotion heuristic",1),e.g=t,eYs(e),e.q=Pp(e_k(t,(eBy(),taz)),260),l=Pp(e_k(e.g,ta$),19).a,a=new nH,e.q.g){case 2:case 1:default:eRn(e,a);break;case 3:for(e.q=(eOJ(),tsk),eRn(e,a),u=0,s=new fz(e.a);s.ae.j&&(e.q=tsv,eRn(e,a));break;case 4:for(e.q=(eOJ(),tsk),eRn(e,a),c=0,i=new fz(e.b);i.ae.k&&(e.q=ts_,eRn(e,a));break;case 6:d=zy(eB4.Math.ceil(e.f.length*l/100)),eRn(e,new dq(d));break;case 5:f=zy(eB4.Math.ceil(e.d*l/100)),eRn(e,new dZ(f))}eLC(e,t),eEj(n)}function ejP(e,t,n){var r,i,a,o;this.j=e,this.e=ewi(e),this.o=this.j.e,this.i=!!this.o,this.p=this.i?Pp(RJ(n,Bq(this.o).p),214):null,i=Pp(e_k(e,(eBU(),tt3)),21),this.g=i.Hc((eLR(),ttw)),this.b=new p0,this.d=new ed0(this.e),o=Pp(e_k(this.j,tnw),230),this.q=eaG(t,o,this.e),this.k=new zX(this),a=ZW(eow(vx(e4H,1),eUp,225,0,[this,this.d,this.k,this.q])),t!=(enU(),tur)||gN(LK(e_k(e,(eBy(),ti7))))?t==tur&&gN(LK(e_k(e,(eBy(),ti7))))?(r=new ews(this.e),a.c[a.c.length]=r,this.c=new erB(r,o,Pp(this.q,402))):this.c=new Sr(t,this):(r=new ews(this.e),a.c[a.c.length]=r,this.c=new K5(r,o,Pp(this.q,402))),P_(a,this.c),eP0(a,this.e),this.s=eY0(this.k)}function ejR(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w;for(p=(f=Pp(M2((o=epL(new hz(t).a.d,0),new hG(o))),86))?Pp(e_k(f,(eR6(),tco)),86):null,i=1;f&&p;){for(s=0,u=0,w=0,n=f,r=p;s=e.i?(++e.i,P_(e.a,ell(1)),P_(e.b,f)):(r=e.c[t.p][1],q1(e.a,l,ell(Pp(RJ(e.a,l),19).a+1-r)),q1(e.b,l,gP(LV(RJ(e.b,l)))+f-r*e.e)),(e.q==(eOJ(),tsv)&&(Pp(RJ(e.a,l),19).a>e.j||Pp(RJ(e.a,l-1),19).a>e.j)||e.q==ts_&&(gP(LV(RJ(e.b,l)))>e.k||gP(LV(RJ(e.b,l-1)))>e.k))&&(u=!1),o=new Fa(OH(efu(t).a.Kc(),new c));eTk(o);)s=(a=Pp(ZC(o),17)).c.i,e.f[s.p]==l&&(d=ejj(e,s),i+=Pp(d.a,19).a,u=u&&gN(LK(d.b)));return e.f[t.p]=l,i+=e.c[t.p][0],new kD(ell(i),(OQ(),!!u))}function ejF(e,t,n,r,i){var a,o,s,u,c,l,f,d,h,p,b,m,g;for(f=new p2,o=new p0,ekD(e,n,e.d.fg(),o,f),ekD(e,r,e.d.gg(),o,f),e.b=.2*(b=eTZ(eeh(new R1(null,new Gq(o,16)),new aL)),m=eTZ(eeh(new R1(null,new Gq(o,16)),new aC)),eB4.Math.min(b,m)),a=0,s=0;s=2&&(g=eOY(o,!0,d),e.e||(e.e=new h$(e)),ehB(e.e,g,o,e.b)),ewv(o,d),eFn(o),h=-1,l=new fz(o);l.as)}function ejU(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b;for(n=Pp(e_k(e,(eBy(),tol)),98),o=e.f,a=e.d,s=o.a+a.b+a.c,u=0-a.d-e.c.b,l=o.b+a.d+a.a-e.c.b,c=new p0,f=new p0,i=new fz(t);i.a0),Pp(l.a.Xb(l.c=--l.b),17));a!=r&&l.b>0;)e.a[a.p]=!0,e.a[r.p]=!0,a=(A6(l.b>0),Pp(l.a.Xb(l.c=--l.b),17));l.b>0&&BH(l)}}function ejZ(e,t,n){var r,i,a,o,s,u,c,l,f;if(e.a!=t.Aj())throw p7(new gL(eZ5+t.ne()+eZ6));if(r=ecG((eSp(),tvc),t).$k())return r.Aj().Nh().Ih(r,n);if(o=ecG(tvc,t).al()){if(null==n)return null;if((s=Pp(n,15)).dc())return"";for(f=new vs,a=s.Kc();a.Ob();)i=a.Pb(),xk(f,o.Aj().Nh().Ih(o,i)),f.a+=" ";return x3(f,f.a.length-1)}if(!(l=ecG(tvc,t).bl()).dc()){for(c=l.Kc();c.Ob();)if((u=Pp(c.Pb(),148)).wj(n))try{if(f=u.Aj().Nh().Ih(u,n),null!=f)return f}catch(d){if(d=eoa(d),!M4(d,102))throw p7(d)}throw p7(new gL("Invalid value: '"+n+"' for datatype :"+t.ne()))}return Pp(t,834).Fj(),null==n?null:M4(n,172)?""+Pp(n,172).a:esF(n)==e1Q?MU(tmS[0],Pp(n,199)):efF(n)}function ejX(e){var t,n,r,i,a,o,s,u,c,l;for(c=new _n,s=new _n,a=new fz(e);a.a-1){for(i=epL(s,0);i.b!=i.d.c;)(r=Pp(Vv(i),128)).v=o;for(;0!=s.b;)for(r=Pp(egW(s,0),128),n=new fz(r.i);n.a0&&(n+=u.n.a+u.o.a/2,++f),p=new fz(u.j);p.a0&&(n/=f),g=Je(tyx,eH5,25,r.a.c.length,15,1),s=0,c=new fz(r.a);c.a=s&&i<=u)s<=i&&a<=u?r+=2:s<=i?(e.b[r]=u+1,o+=2):a<=u?(n[l++]=i,n[l++]=s-1,r+=2):(n[l++]=i,n[l++]=s-1,e.b[r]=u+1,o+=2);else if(u0?i-=864e5:i+=864e5,u=new LZ(eft(eap(t.q.getTime()),i))),l=new vl,c=e.a.length,a=0;a=97&&r<=122||r>=65&&r<=90){for(o=a+1;o=c)throw p7(new gL("Missing trailing '"));o+10&&0==n.c&&(t||(t=new p0),t.c[t.c.length]=n);if(t)for(;0!=t.c.length;){if((n=Pp(ZV(t,0),233)).b&&n.b.c.length>0){for(a=(n.b||(n.b=new p0),new fz(n.b));a.aQI(e,n,0))return new kD(i,n)}else if(gP(Ot(i.g,i.d[0]).a)>gP(Ot(n.g,n.d[0]).a))return new kD(i,n)}for(s=(n.e||(n.e=new p0),n.e).Kc();s.Ob();)u=((o=Pp(s.Pb(),233)).b||(o.b=new p0),o.b),Gp(0,u.c.length),Ew(u.c,0,n),o.c==u.c.length&&(t.c[t.c.length]=o)}return null}function eFe(e,t){var n,r,i,a,o,s,u,c,l;if(null==e)return eUg;if(null!=(u=t.a.zc(e,t)))return"[...]";for(a=0,n=new eaP(eUd,"[","]"),o=(i=e).length;a=14&&l<=16)?t.a._b(r)?(n.a?xM(n.a,n.b):n.a=new O0(n.d),xx(n.a,"[...]")):ZJ(n,eFe(s=etG(r),c=new Rq(t))):M4(r,177)?ZJ(n,ekd(Pp(r,177))):M4(r,190)?ZJ(n,ewh(Pp(r,190))):M4(r,195)?ZJ(n,eEm(Pp(r,195))):M4(r,2012)?ZJ(n,ewp(Pp(r,2012))):M4(r,48)?ZJ(n,ekf(Pp(r,48))):M4(r,364)?ZJ(n,ekG(Pp(r,364))):M4(r,832)?ZJ(n,ekl(Pp(r,832))):M4(r,104)&&ZJ(n,ekc(Pp(r,104))):ZJ(n,null==r?eUg:efF(r));return n.a?0==n.e.length?n.a.a:n.a.a+""+n.e:n.c}function eFt(e,t,n,r){var i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y;for(s=eLO(t,!1,!1),g=eEF(s),r&&(g=esP(g)),y=gP(LV(eT8(t,(epz(),e63)))),m=(A6(0!=g.b),Pp(g.a.a.c,8)),f=Pp(ep3(g,1),8),g.b>2?(l=new p0,eoc(l,new Gz(g,1,g.b)),a=eBk(l,y+e.a),v=new eTI(a),eaW(v,t),n.c[n.c.length]=v):v=r?Pp(Bp(e.b,e_I(t)),266):Pp(Bp(e.b,e_P(t)),266),u=e_I(t),r&&(u=e_P(t)),o=eEJ(m,u),c=y+e.a,o.a?(c+=eB4.Math.abs(m.b-f.b),b=new kl(f.a,(f.b+m.b)/2)):(c+=eB4.Math.abs(m.a-f.a),b=new kl((f.a+m.a)/2,f.b)),r?Um(e.d,t,new emL(v,o,b,c)):Um(e.c,t,new emL(v,o,b,c)),Um(e.b,t,v),p=(t.n||(t.n=new FQ(e6S,t,1,7)),t.n),h=new Ow(p);h.e!=h.i.gc();)d=Pp(epH(h),137),i=eIt(e,d,!0,0,0),n.c[n.c.length]=i}function eFn(e){var t,n,r,i,a,o,s,u,c,l;for(c=new p0,s=new p0,o=new fz(e);o.a-1){for(a=new fz(s);a.a0)&&(l3(u,eB4.Math.min(u.o,i.o-1)),l2(u,u.i-1),0==u.i&&(s.c[s.c.length]=u))}}function eFr(e,t,n){var r,i,a,o,s,u,c;if(c=e.c,t||(t=tgK),e.c=t,(4&e.Db)!=0&&(1&e.Db)==0&&(u=new FX(e,1,2,c,e.c),n?n.Ei(u):n=u),c!=t){if(M4(e.Cb,284))e.Db>>16==-10?n=Pp(e.Cb,284).nk(t,n):e.Db>>16==-15&&(t||(t=(eBK(),tgA)),c||(c=(eBK(),tgA)),e.Cb.nh()&&(u=new Q$(e.Cb,1,13,c,t,ebv(QX(Pp(e.Cb,59)),e),!1),n?n.Ei(u):n=u));else if(M4(e.Cb,88))e.Db>>16==-23&&(M4(t,88)||(t=(eBK(),tgI)),M4(c,88)||(c=(eBK(),tgI)),e.Cb.nh()&&(u=new Q$(e.Cb,1,10,c,t,ebv(qt(Pp(e.Cb,26)),e),!1),n?n.Ei(u):n=u));else if(M4(e.Cb,444))for(o=((s=Pp(e.Cb,836)).b||(s.b=new pG(new mR)),s.b),a=(r=new esz(new fS(o.a).a),new pW(r));a.a.b;)n=eFr(i=Pp(etz(a.a).cd(),87),eOl(i,s),n)}return n}function eFi(e,t){var n,r,i,a,o,s,u,c,l,f,d;for(o=gN(LK(eT8(e,(eBy(),taI)))),d=Pp(eT8(e,toh),21),u=!1,c=!1,f=new Ow((e.c||(e.c=new FQ(e6x,e,9,9)),e.c));f.e!=f.i.gc()&&(!u||!c);){for(a=Pp(epH(f),118),s=0,i=Y_(enM(eow(vx(e1B,1),eUp,20,0,[(a.d||(a.d=new Ih(e6g,a,8,5)),a.d),(a.e||(a.e=new Ih(e6g,a,7,4)),a.e)])));eTk(i)&&(r=Pp(ZC(i),79),l=o&&exb(r)&&gN(LK(eT8(r,taD))),n=eRL((r.b||(r.b=new Ih(e6m,r,4,7)),r.b),a)?e==z$(ewH(Pp(etj((r.c||(r.c=new Ih(e6m,r,5,8)),r.c),0),82))):e==z$(ewH(Pp(etj((r.b||(r.b=new Ih(e6m,r,4,7)),r.b),0),82))),!((l||n)&&++s>1)););s>0?u=!0:d.Hc((ekU(),tbp))&&(a.n||(a.n=new FQ(e6S,a,1,7)),a.n).i>0&&(u=!0),s>1&&(c=!0)}u&&t.Fc((eLR(),ttw)),c&&t.Fc((eLR(),tt_))}function eFa(e){var t,n,r,i,a,o,s,u,c,l,f,d;if((d=Pp(eT8(e,(eBB(),thx)),21)).dc())return null;if(s=0,o=0,d.Hc((ed6(),tbV))){for(l=Pp(eT8(e,thV),98),r=2,n=2,i=2,a=2,t=z$(e)?Pp(eT8(z$(e),the),103):Pp(eT8(e,the),103),c=new Ow((e.c||(e.c=new FQ(e6x,e,9,9)),e.c));c.e!=c.i.gc();)if(u=Pp(epH(c),118),(f=Pp(eT8(u,th0),61))==(eYu(),tbF)&&(f=eNh(u,t),ebu(u,th0,f)),l==(ewf(),tbo))switch(f.g){case 1:r=eB4.Math.max(r,u.i+u.g);break;case 2:n=eB4.Math.max(n,u.j+u.f);break;case 3:i=eB4.Math.max(i,u.i+u.g);break;case 4:a=eB4.Math.max(a,u.j+u.f)}else switch(f.g){case 1:r+=u.g+2;break;case 2:n+=u.f+2;break;case 3:i+=u.g+2;break;case 4:a+=u.f+2}s=eB4.Math.max(r,i),o=eB4.Math.max(n,a)}return eYx(e,s,o,!0,!0)}function eFo(e,t,n,r,i){var a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w;for(v=Pp(qE(etc(UJ(new R1(null,new Gq(t.d,16)),new hc(n)),new hl(n)),JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[(eum(),e2U)]))),15),f=eUu,l=eHt,u=new fz(t.b.j);u.a0)?c&&(d=g.p,o?++d:--d,h=!(eOV(r=eoZ(f=Pp(RJ(g.c.a,d),10)),E,n[0])||FF(r,E,n[0]))):h=!0),p=!1,(_=t.D.i)&&_.c&&s.e&&((l=o&&_.p>0||!o&&_.p<_.c.a.c.length-1)?(d=_.p,o?--d:++d,p=!(eOV(r=eoZ(f=Pp(RJ(_.c.a,d),10)),n[0],k)||FF(r,n[0],k))):p=!0),h&&p&&P7(e.a,S),h||enD(e.a,eow(vx(e50,1),eUP,8,0,[b,m])),p||enD(e.a,eow(vx(e50,1),eUP,8,0,[w,y]))}function eFh(e,t){var n,r,i,a,o,s,u,c;if(M4(e.Ug(),160)?(eFh(Pp(e.Ug(),160),t),t.a+=" > "):t.a+="Root ",IE((n=e.Tg().zb).substr(0,3),"Elk")?xM(t,n.substr(3)):(t.a+=""+n,t),i=e.zg()){xM((t.a+=" ",t),i);return}if(M4(e,354)&&(c=Pp(e,137).a)){xM((t.a+=" ",t),c);return}for(o=new Ow(e.Ag());o.e!=o.i.gc();)if(c=(a=Pp(epH(o),137)).a){xM((t.a+=" ",t),c);return}if(M4(e,352)&&((r=Pp(e,79)).b||(r.b=new Ih(e6m,r,4,7)),0!=r.b.i&&(r.c||(r.c=new Ih(e6m,r,5,8)),0!=r.c.i))){for(t.a+=" (",s=new AF((r.b||(r.b=new Ih(e6m,r,4,7)),r.b));s.e!=s.i.gc();)s.e>0&&(t.a+=eUd),eFh(Pp(epH(s),160),t);for(t.a+=eGH,u=new AF((r.c||(r.c=new Ih(e6m,r,5,8)),r.c));u.e!=u.i.gc();)u.e>0&&(t.a+=eUd),eFh(Pp(epH(u),160),t);t.a+=")"}}function eFp(e,t,n){var r,i,a,o,s,u,c,l,f,d,h;if(a=Pp(e_k(e,(eBU(),tnc)),79)){for(r=e.a,C5(i=new TS(n),eyr(e)),eag(e.d.i,e.c.i)?(d=e.c,f=esp(eow(vx(e50,1),eUP,8,0,[d.n,d.a])),C6(f,n)):f=GX(e.c),qQ(r,f,r.a,r.a.a),h=GX(e.d),null!=e_k(e,tnC)&&C5(h,Pp(e_k(e,tnC),8)),qQ(r,h,r.c.b,r.c),etH(r,i),o=eLO(a,!0,!0),ern(o,Pp(etj((a.b||(a.b=new Ih(e6m,a,4,7)),a.b),0),82)),err(o,Pp(etj((a.c||(a.c=new Ih(e6m,a,5,8)),a.c),0),82)),eNI(r,o),l=new fz(e.b);l.a=0){for(u=null,s=new KB(l.a,c+1);s.bo?1:Te(isNaN(0),isNaN(o)))<0&&(enj(eVU),(eB4.Math.abs(o-1)<=eVU||1==o||isNaN(o)&&isNaN(1)?0:o<1?-1:o>1?1:Te(isNaN(o),isNaN(1)))<0)&&(enj(eVU),(eB4.Math.abs(0-s)<=eVU||0==s||isNaN(0)&&isNaN(s)?0:0s?1:Te(isNaN(0),isNaN(s)))<0)&&(enj(eVU),(eB4.Math.abs(s-1)<=eVU||1==s||isNaN(s)&&isNaN(1)?0:s<1?-1:s>1?1:Te(isNaN(s),isNaN(1)))<0)))}function eFg(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E;for(f=new BU(new fQ(e));f.b!=f.c.a.d;)for(b=0,s=Pp((l=JO(f)).d,56),t=Pp(l.e,56),w=(null==(o=s.Tg()).i&&eNT(o),o.i).length;b=0&&b=c.c.c.length?VJ((eEn(),e8N),e8D):VJ((eEn(),e8D),e8D),l*=2,a=n.a.g,n.a.g=eB4.Math.max(a,a+(l-a)),o=n.b.g,n.b.g=eB4.Math.max(o,o+(l-o)),i=t}}}function eFw(e,t,n,r,i){var a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_;for(_=Pg(e),l=new p0,f=(s=e.c.length)-1,d=s+1;0!=_.a.c;){for(;0!=n.b;)y=(A6(0!=n.b),Pp(etw(n,n.a.a),112)),zS(_.a,y),y.g=f--,eNg(y,t,n,r);for(;0!=t.b;)w=(A6(0!=t.b),Pp(etw(t,t.a.a),112)),zS(_.a,w),w.g=d++,eNg(w,t,n,r);for(c=eHt,g=(o=new C1(new Ap(new fP(_.a).a).b),new fR(o));Et(g.a.a);){if(m=(a=AJ(g.a),Pp(a.cd(),112)),!r&&m.b>0&&m.a<=0){l.c=Je(e1R,eUp,1,0,5,1),l.c[l.c.length]=m;break}(b=m.i-m.d)>=c&&(b>c&&(l.c=Je(e1R,eUp,1,0,5,1),c=b),l.c[l.c.length]=m)}0!=l.c.length&&(u=Pp(RJ(l,ebO(i,l.c.length)),112),zS(_.a,u),u.g=d++,eNg(u,t,n,r),l.c=Je(e1R,eUp,1,0,5,1))}for(v=e.c.length+1,p=new fz(e);p.a0&&(d.d+=l.n.d,d.d+=l.d),d.a>0&&(d.a+=l.n.a,d.a+=l.d),d.b>0&&(d.b+=l.n.b,d.b+=l.d),d.c>0&&(d.c+=l.n.c,d.c+=l.d),d}function eFx(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p;for(d=n.d,f=n.c,o=(a=new kl(n.f.a+n.d.b+n.d.c,n.f.b+n.d.d+n.d.a)).b,c=new fz(e.a);c.a=(l=Pp(Pp(Zq(e.r,t),21),84)).gc()||t==(eYu(),tby)||t==(eYu(),tbY)){eYY(e,t);return}for(b=e.u.Hc((ekU(),tbg)),n=t==(eYu(),tbw)?(eaY(),e4c):(eaY(),e4o),g=t==tbw?(QQ(),e3U):(QQ(),e3$),r=vN(DP(n),e.s),m=t==tbw?eHQ:eH1,c=l.Kc();c.Ob();)(s=Pp(c.Pb(),111)).c&&!(s.c.d.c.length<=0)&&(p=s.b.rf(),h=s.e,(d=(f=s.c).i).b=(a=f.n,f.e.a+a.b+a.c),d.a=(o=f.n,f.e.b+o.d+o.a),b?(d.c=h.a-(i=f.n,f.e.a+i.b+i.c)-e.s,b=!1):d.c=h.a+p.a+e.s,$C(g,ezr),f.f=g,JC(f,(Qs(),e3Y)),P_(r.d,new jH(d,elO(r,d))),m=t==tbw?eB4.Math.min(m,h.b):eB4.Math.max(m,h.b+s.b.rf().b));for(m+=t==tbw?-e.t:e.t,edp((r.e=m,r)),u=l.Kc();u.Ob();)(s=Pp(u.Pb(),111)).c&&!(s.c.d.c.length<=0)&&(d=s.c.i,d.c-=s.e.a,d.d-=s.e.b)}function eFA(e,t,n){var r;if(ewG(n,"StretchWidth layering",1),0==t.a.c.length){eEj(n);return}for(e.c=t,e.t=0,e.u=0,e.i=eHQ,e.g=eH1,e.d=gP(LV(e_k(t,(eBy(),toO)))),ebn(e),eTR(e),eTP(e),eyo(e),ed2(e),e.i=eB4.Math.max(1,e.i),e.g=eB4.Math.max(1,e.g),e.d=e.d/e.i,e.f=e.g/e.i,e.s=ebZ(e),r=new By(e.c),P_(e.c.b,r),e.r=WC(e.p),e.n=zb(e.k,e.k.length);0!=e.r.c.length;)e.o=ecu(e),!e.o||ess(e)&&0!=e.b.a.gc()?(ey6(e,r),r=new By(e.c),P_(e.c.b,r),er7(e.a,e.b),e.b.a.$b(),e.t=e.u,e.u=0):ess(e)?(e.c.b.c=Je(e1R,eUp,1,0,5,1),r=new By(e.c),P_(e.c.b,r),e.t=0,e.u=0,e.b.a.$b(),e.a.a.$b(),++e.f,e.r=WC(e.p),e.n=zb(e.k,e.k.length)):(Gu(e.o,r),QA(e.r,e.o),Yf(e.b,e.o),e.t=e.t-e.k[e.o.p]*e.d+e.j[e.o.p],e.u+=e.e[e.o.p]*e.d);t.a.c=Je(e1R,eUp,1,0,5,1),eSj(t.b),eEj(n)}function eFL(e){var t,n,r,i;for(_r(UJ(new R1(null,new Gq(e.a.b,16)),new rH),new r$),eyR(e),_r(UJ(new R1(null,new Gq(e.a.b,16)),new rz),new rG),e.c==(efE(),tpM)&&(_r(UJ(eeh(new R1(null,new Gq(new fk(e.f),1)),new rW),new rK),new hn(e)),_r(UJ(UQ(eeh(eeh(new R1(null,new Gq(e.d.b,16)),new rV),new rq),new rZ),new rX),new hi(e))),i=new kl(eHQ,eHQ),t=new kl(eH1,eH1),r=new fz(e.a.b);r.a0&&(e.c[t.c.p][t.p].d+=eMU(e.i,24)*e$h*.07000000029802322-.03500000014901161,e.c[t.c.p][t.p].a=e.c[t.c.p][t.p].d/e.c[t.c.p][t.p].b)}}function eFD(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m;for(p=new fz(e);p.ar.d,r.d=eB4.Math.max(r.d,t),s&&n&&(r.d=eB4.Math.max(r.d,r.a),r.a=r.d+i);break;case 3:n=t>r.a,r.a=eB4.Math.max(r.a,t),s&&n&&(r.a=eB4.Math.max(r.a,r.d),r.d=r.a+i);break;case 2:n=t>r.c,r.c=eB4.Math.max(r.c,t),s&&n&&(r.c=eB4.Math.max(r.b,r.c),r.b=r.c+i);break;case 4:n=t>r.b,r.b=eB4.Math.max(r.b,t),s&&n&&(r.b=eB4.Math.max(r.b,r.c),r.c=r.b+i)}}}function eFj(e){var t,n,r,i,a,o,s,u,c,l,f;for(c=new fz(e);c.a0||l.j==tbY&&l.e.c.length-l.g.c.length<0)){t=!1;break}for(i=new fz(l.g);i.a=c&&_>=m&&(d+=p.n.b+b.n.b+b.a.b-w,++s));if(n)for(o=new fz(v.e);o.a=c&&_>=m&&(d+=p.n.b+b.n.b+b.a.b-w,++s))}s>0&&(E+=d/s,++h)}h>0?(t.a=i*E/h,t.g=h):(t.a=0,t.g=0)}function eFY(e,t){var n,r,i,a,o,s,u,c,l,f,d;for(i=new fz(e.a.b);i.aeH1||t.o==tuE&&l0&&eno(g,w*E),_>0&&ens(g,_*S);for(ear(e.b,new te),t=new p0,s=new esz(new fS(e.c).a);s.b;)o=etz(s),r=Pp(o.cd(),79),n=Pp(o.dd(),395).a,i=eLO(r,!1,!1),f=ewM(e_I(r),eEF(i),n),eNI(f,i),(y=e_D(r))&&-1==QI(t,y,0)&&(t.c[t.c.length]=y,Hw(y,(A6(0!=f.b),Pp(f.a.a.c,8)),n));for(m=new esz(new fS(e.d).a);m.b;)b=etz(m),r=Pp(b.cd(),79),n=Pp(b.dd(),395).a,i=eLO(r,!1,!1),f=ewM(e_P(r),esP(eEF(i)),n),eNI(f=esP(f),i),(y=e_N(r))&&-1==QI(t,y,0)&&(t.c[t.c.length]=y,Hw(y,(A6(0!=f.b),Pp(f.c.b.c,8)),n))}function eFz(e,t,n,r){var i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k;if(0!=n.c.length){for(p=new p0,h=new fz(n);h.aeB4.Math.abs(v-m))continue;v1)for(h=new eRM(p,y,r),qX(y,new SV(e,h)),o.c[o.c.length]=h,f=y.a.ec().Kc();f.Ob();)QA(a,(l=Pp(f.Pb(),46)).b);if(s.a.gc()>1)for(h=new eRM(p,s,r),qX(s,new Sq(e,h)),o.c[o.c.length]=h,f=s.a.ec().Kc();f.Ob();)QA(a,(l=Pp(f.Pb(),46)).b)}}function eFJ(e){_Y(e,new ewB(vZ(vQ(vq(vJ(vX(new oc,eqp),"ELK Radial"),'A radial layout provider which is based on the algorithm of Peter Eades published in "Drawing free trees.", published by International Institute for Advanced Study of Social Information Science, Fujitsu Limited in 1991. The radial layouter takes a tree and places the nodes in radial order around the root. The nodes of the same tree level are placed on the same radius.'),new aW),eqp))),KE(e,eqp,eVT,epB(tlw)),KE(e,eqp,eGi,epB(tlS)),KE(e,eqp,eGh,epB(tlh)),KE(e,eqp,eGM,epB(tlp)),KE(e,eqp,eGd,epB(tlb)),KE(e,eqp,eGp,epB(tld)),KE(e,eqp,eGf,epB(tlm)),KE(e,eqp,eGb,epB(tly)),KE(e,eqp,eql,epB(tll)),KE(e,eqp,eqc,epB(tlf)),KE(e,eqp,eqh,epB(tlg)),KE(e,eqp,eqs,epB(tlv)),KE(e,eqp,equ,epB(tl_)),KE(e,eqp,eqf,epB(tlE)),KE(e,eqp,eqd,epB(tlk))}function eFQ(e){var t;if(this.r=U2(new ex,new eT),this.b=new efY(Pp(Y9(e6a),290)),this.p=new efY(Pp(Y9(e6a),290)),this.i=new efY(Pp(Y9(e3n),290)),this.e=e,this.o=new TS(e.rf()),this.D=e.Df()||gN(LK(e.We((eBB(),thh)))),this.A=Pp(e.We((eBB(),thx)),21),this.B=Pp(e.We(thL),21),this.q=Pp(e.We(thV),98),this.u=Pp(e.We(thJ),21),!e_y(this.u))throw p7(new gq("Invalid port label placement: "+this.u));if(this.v=gN(LK(e.We(th1))),this.j=Pp(e.We(thS),21),!eM1(this.j))throw p7(new gq("Invalid node label placement: "+this.j));this.n=Pp(egG(e,th_),116),this.k=gP(LV(egG(e,tps))),this.d=gP(LV(egG(e,tpo))),this.w=gP(LV(egG(e,tpp))),this.s=gP(LV(egG(e,tpu))),this.t=gP(LV(egG(e,tpc))),this.C=Pp(egG(e,tpd),142),this.c=2*this.d,t=!this.B.Hc((eI3(),tbX)),this.f=new eh6(0,t,0),this.g=new eh6(1,t,0),gh(this.f,(etx(),e3N),this.g)}function eF1(e,t,n,r,i){var a,o,s,u,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M;for(w=0,b=0,p=0,h=1,y=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));y.e!=y.i.gc();)g=Pp(epH(y),33),h+=VG(new Fa(OH(eOi(g).a.Kc(),new c))),x=g.g,b=eB4.Math.max(b,x),d=g.f,p=eB4.Math.max(p,d),w+=x*d;for(m=(e.a||(e.a=new FQ(e6k,e,10,11)),e.a).i,o=w+2*r*r*h*m,a=eB4.Math.sqrt(o),u=eB4.Math.max(a*n,b),s=eB4.Math.max(a/n,p),v=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));v.e!=v.i.gc();)g=Pp(epH(v),33),T=i.b+(eMU(t,26)*e$l+eMU(t,27)*e$f)*(u-g.g),M=i.b+(eMU(t,26)*e$l+eMU(t,27)*e$f)*(s-g.f),eno(g,T),ens(g,M);for(k=u+(i.b+i.c),S=s+(i.d+i.a),E=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));E.e!=E.i.gc();)for(_=Pp(epH(E),33),f=new Fa(OH(eOi(_).a.Kc(),new c));eTk(f);)l=Pp(ZC(f),79),eTc(l)||eBv(l,t,k,S);eYx(e,k+=i.b+i.c,S+=i.d+i.a,!1,!0)}function eF0(e){var t,n,r,i,a,o,s,u,c,l,f;if(null==e)throw p7(new vo(eUg));if(c=e,a=e.length,u=!1,a>0&&(45==(t=(GV(0,e.length),e.charCodeAt(0)))||43==t)&&(e=e.substr(1),--a,u=45==t),0==a)throw p7(new vo(eHJ+c+'"'));for(;e.length>0&&(GV(0,e.length),48==e.charCodeAt(0));)e=e.substr(1),--a;if(a>(eDZ(),e0G)[10])throw p7(new vo(eHJ+c+'"'));for(i=0;i0&&(f=-parseInt(e.substr(0,r),10),e=e.substr(r),a-=r,n=!1);a>=o;){if(r=parseInt(e.substr(0,o),10),e=e.substr(o),a-=o,n)n=!1;else{if(0>ecd(f,s))throw p7(new vo(eHJ+c+'"'));f=efn(f,l)}f=efe(f,r)}if(ecd(f,0)>0||!u&&(f=QC(f),0>ecd(f,0)))throw p7(new vo(eHJ+c+'"'));return f}function eF2(e,t){var n,r,i,a,o,s,u;if(Rm(),this.a=new MW(this),this.b=e,this.c=t,this.f=Yg(QZ((eSp(),tvc),t)),this.f.dc()){if((s=ev1(tvc,e))==t)for(this.e=!0,this.d=new p0,this.f=new o5,this.f.Fc(eQB),Pp(eP9(Qq(tvc,etP(e)),""),26)==e&&this.f.Fc(Fr(tvc,etP(e))),i=eIT(tvc,e).Kc();i.Ob();)switch(Ur(QZ(tvc,r=Pp(i.Pb(),170)))){case 4:this.d.Fc(r);break;case 5:this.f.Gc(Yg(QZ(tvc,r)))}else if(_4(),Pp(t,66).Oj())for(o=0,this.e=!0,this.f=null,this.d=new p0,u=(null==e.i&&eNT(e),e.i).length;o=0&&o0&&(Pp(UA(e.b,t),124).a.b=n)}function eF4(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g;for(ewG(t,"Comment pre-processing",1),n=0,u=new fz(e.a);u.a0&&64!=(u=(GV(0,t.length),t.charCodeAt(0)))){if(37==u&&(f=t.lastIndexOf("%"),c=!1,0!=f&&(f==d-1||(c=(GV(f+1,t.length),46==t.charCodeAt(f+1)))))){if(y=IE("%",o=t.substr(1,f-1))?null:eYy(o),r=0,c)try{r=eDa(t.substr(f+2),eHt,eUu)}catch(w){if(w=eoa(w),M4(w,127))throw s=w,p7(new QH(s));throw p7(w)}for(m=erW(e.Wg());m.Ob();)if(M4(p=eaO(m),510)&&(v=(i=Pp(p,590)).d,(null==y?null==v:IE(y,v))&&0==r--))return i;return null}if(h=-1==(l=t.lastIndexOf("."))?t:t.substr(0,l),n=0,-1!=l)try{n=eDa(t.substr(l+1),eHt,eUu)}catch(_){if(_=eoa(_),M4(_,127))h=t;else throw p7(_)}for(h=IE("%",h)?null:eYy(h),b=erW(e.Wg());b.Ob();)if(M4(p=eaO(b),191)&&(g=(a=Pp(p,191)).ne(),(null==h?null==g:IE(h,g))&&0==n--))return a;return null}return eR2(e,t)}function eF8(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M;for(E=new p0,p=new fz(e.b);p.a=e.length)return{done:!0};var r=e[n++];return{value:[r,t.get(r)],done:!1}}}},eCi()||(e.prototype.createObject=function(){return{}},e.prototype.get=function(e){return this.obj[":"+e]},e.prototype.set=function(e,t){this.obj[":"+e]=t},e.prototype[e$c]=function(e){delete this.obj[":"+e]},e.prototype.keys=function(){var e=[];for(var t in this.obj)58==t.charCodeAt(0)&&e.push(t.substring(1));return e}),e}function eYt(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m;if(eNl(),null==e)return null;if(0==(f=8*e.length))return"";for(u=0,s=f%24,h=f/24|0,a=null,a=Je(tyw,eHl,25,4*(d=0!=s?h+1:h),15,1),c=0,l=0,t=0,n=0,r=0,o=0,i=0;u>24,c=(3&t)<<24>>24,p=(-128&t)==0?t>>2<<24>>24:(t>>2^192)<<24>>24,b=(-128&n)==0?n>>4<<24>>24:(n>>4^240)<<24>>24,m=(-128&r)==0?r>>6<<24>>24:(r>>6^252)<<24>>24,a[o++]=tvQ[p],a[o++]=tvQ[b|c<<4],a[o++]=tvQ[l<<2|m],a[o++]=tvQ[63&r];return 8==s?(c=(3&(t=e[i]))<<24>>24,p=(-128&t)==0?t>>2<<24>>24:(t>>2^192)<<24>>24,a[o++]=tvQ[p],a[o++]=tvQ[c<<4],a[o++]=61,a[o++]=61):16==s&&(t=e[i],l=(15&(n=e[i+1]))<<24>>24,c=(3&t)<<24>>24,p=(-128&t)==0?t>>2<<24>>24:(t>>2^192)<<24>>24,b=(-128&n)==0?n>>4<<24>>24:(n>>4^240)<<24>>24,a[o++]=tvQ[p],a[o++]=tvQ[b|c<<4],a[o++]=tvQ[l<<2],a[o++]=61),ehv(a,0,a.length)}function eYn(e,t){var n,r,i,a,o,s,u;if(0==e.e&&e.p>0&&(e.p=-(e.p-1)),e.p>eHt&&V9(t,e.p-eHx),o=t.q.getDate(),zC(t,1),e.k>=0&&z7(t,e.k),e.c>=0?zC(t,e.c):e.k>=0?(r=35-(u=new est(t.q.getFullYear()-eHx,t.q.getMonth(),35)).q.getDate(),zC(t,eB4.Math.min(r,o))):zC(t,o),e.f<0&&(e.f=t.q.getHours()),e.b>0&&e.f<12&&(e.f+=12),M5(t,24==e.f&&e.g?0:e.f),e.j>=0&&Z0(t,e.j),e.n>=0&&Jf(t,e.n),e.i>=0&&xN(t,eft(efn(eyt(eap(t.q.getTime()),eHf),eHf),e.i)),e.a&&(V9(i=new wW,i.q.getFullYear()-eHx-80),Ei(eap(t.q.getTime()),eap(i.q.getTime()))&&V9(t,i.q.getFullYear()-eHx+100)),e.d>=0){if(-1==e.c)(n=(7+e.d-t.q.getDay())%7)>3&&(n-=7),s=t.q.getMonth(),zC(t,t.q.getDate()+n),t.q.getMonth()!=s&&zC(t,t.q.getDate()+(n>0?-7:7));else if(t.q.getDay()!=e.d)return!1}return e.o>eHt&&(a=t.q.getTimezoneOffset(),xN(t,eft(eap(t.q.getTime()),(e.o-a)*60*eHf))),!0}function eYr(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w;if(i=e_k(t,(eBU(),tnc)),M4(i,239)){for(p=Pp(i,33),b=t.e,d=new TS(t.c),a=t.d,d.a+=a.b,d.b+=a.d,w=Pp(eT8(p,(eBy(),ta9)),174),Aa(w,(eI3(),tbJ))&&(h=Pp(eT8(p,ta7),116),lR(h,a.a),lG(h,a.d),lj(h,a.b),lW(h,a.c)),n=new p0,l=new fz(t.a);l.a0&&P_(e.p,f),P_(e.o,f);t-=r,p=u+t,l+=t*e.e,q1(e.a,s,ell(p)),q1(e.b,s,l),e.j=eB4.Math.max(e.j,p),e.k=eB4.Math.max(e.k,l),e.d+=t,t+=m}}function eYu(){var e;eYu=A,tbF=new kS(ezo,0),tbw=new kS(ezb,1),tby=new kS(ezm,2),tbj=new kS(ezg,3),tbY=new kS(ezv,4),tbx=(Hj(),new vd((e=Pp(yw(e6a),9),new I1(e,Pp(CY(e,e.length),9),0)))),tbT=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[]))),tb_=ecO(jL(tby,eow(vx(e6a,1),eGj,61,0,[]))),tbN=ecO(jL(tbj,eow(vx(e6a,1),eGj,61,0,[]))),tbR=ecO(jL(tbY,eow(vx(e6a,1),eGj,61,0,[]))),tbC=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[tbj]))),tbk=ecO(jL(tby,eow(vx(e6a,1),eGj,61,0,[tbY]))),tbD=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[tbY]))),tbM=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[tby]))),tbP=ecO(jL(tbj,eow(vx(e6a,1),eGj,61,0,[tbY]))),tbE=ecO(jL(tby,eow(vx(e6a,1),eGj,61,0,[tbj]))),tbL=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[tby,tbY]))),tbS=ecO(jL(tby,eow(vx(e6a,1),eGj,61,0,[tbj,tbY]))),tbI=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[tbj,tbY]))),tbO=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[tby,tbj]))),tbA=ecO(jL(tbw,eow(vx(e6a,1),eGj,61,0,[tby,tbj,tbY])))}function eYc(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y;if(0!=t.b){for(h=new _n,s=null,p=null,r=zy(eB4.Math.floor(eB4.Math.log(t.b)*eB4.Math.LOG10E)+1),u=0,y=epL(t,0);y.b!=y.d.c;)for(g=Pp(Vv(y),86),xc(p)!==xc(e_k(g,(eR6(),tca)))&&(p=Lq(e_k(g,tca)),u=0),eo3(g,tca,s=null!=p?p+WB(u++,r):WB(u++,r)),m=(i=epL(new hz(g).a.d,0),new hG(i));yV(m.a);)qQ(h,b=Pp(Vv(m.a),188).c,h.c.b,h.c),eo3(b,tca,s);for(o=0,d=new p2;o=u){A6(g.b>0),g.a.Xb(g.c=--g.b);break}b.a>c&&(i?(eoc(i.b,b.b),i.a=eB4.Math.max(i.a,b.a),BH(g)):(P_(b.b,f),b.c=eB4.Math.min(b.c,c),b.a=eB4.Math.max(b.a,u),i=b))}i||((i=new mi).c=c,i.a=u,CD(g,i),P_(i.b,f))}for(s=t.b,l=0,m=new fz(r);m.as?1:0:(e.b&&(e.b._b(a)&&(i=Pp(e.b.xc(a),19).a),e.b._b(u)&&(s=Pp(e.b.xc(u),19).a)),is?1:0);return 0!=t.e.c.length&&0!=n.g.c.length?1:-1}function eYd(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S;for(ewG(t,eWo,1),b=new p0,E=new p0,c=new fz(e.b);c.a0&&(w-=p),eRU(o,w),f=0,h=new fz(o.a);h.a0),s.a.Xb(s.c=--s.b)),u=.4*r*f,!a&&s.bt.d.c){if((p=e.c[t.a.d])==(g=e.c[d.a.d]))continue;eAx(_f(_l(_d(_c(new bQ,1),100),p),g))}}}}}}function eYy(e){var t,n,r,i,a,o,s,u;if(eRe(),null==e)return null;if((i=x7(e,e_n(37)))<0)return e;for(u=new O0(e.substr(0,i)),t=Je(tyk,eZ8,25,4,15,1),s=0,r=0,o=e.length;ii+2&&eoV((GV(i+1,e.length),e.charCodeAt(i+1)),tmZ,tmX)&&eoV((GV(i+2,e.length),e.charCodeAt(i+2)),tmZ,tmX)){if(n=P0((GV(i+1,e.length),e.charCodeAt(i+1)),(GV(i+2,e.length),e.charCodeAt(i+2))),i+=2,r>0?(192&n)==128?t[s++]=n<<24>>24:r=0:n>=128&&((224&n)==192?(t[s++]=n<<24>>24,r=2):(240&n)==224?(t[s++]=n<<24>>24,r=3):(248&n)==240&&(t[s++]=n<<24>>24,r=4)),r>0){if(s==r){switch(s){case 2:Bd(u,((31&t[0])<<6|63&t[1])&eHd);break;case 3:Bd(u,((15&t[0])<<12|(63&t[1])<<6|63&t[2])&eHd)}s=0,r=0}}else{for(a=0;a0){if(o+r>e.length)return!1;s=exf(e.substr(0,o+r),t)}else s=exf(e,t)}switch(a){case 71:return s=ew6(e,o,eow(vx(e17,1),eUP,2,6,[eHM,eHO]),t),i.e=s,!0;case 77:return eLY(e,t,i,s,o);case 76:return eLB(e,t,i,s,o);case 69:return eS$(e,t,o,i);case 99:return eSz(e,t,o,i);case 97:return s=ew6(e,o,eow(vx(e17,1),eUP,2,6,["AM","PM"]),t),i.b=s,!0;case 121:return eLU(e,t,o,s,n,i);case 100:if(s<=0)return!1;return i.c=s,!0;case 83:if(s<0)return!1;return edc(s,o,t[0],i);case 104:12==s&&(s=0);case 75:case 72:if(s<0)return!1;return i.f=s,i.g=!1,!0;case 107:if(s<0)return!1;return i.f=s,i.g=!0,!0;case 109:if(s<0)return!1;return i.j=s,!0;case 115:if(s<0)return!1;return i.n=s,!0;case 90:if(oE&&(p.c=E-p.b),P_(o.d,new jH(p,elO(o,p))),v=t==tbw?eB4.Math.max(v,b.b+c.b.rf().b):eB4.Math.min(v,b.b));for(v+=t==tbw?e.t:-e.t,(y=edp((o.e=v,o)))>0&&(Pp(UA(e.b,t),124).a.b=y),l=d.Kc();l.Ob();)(c=Pp(l.Pb(),111)).c&&!(c.c.d.c.length<=0)&&(p=c.c.i,p.c-=c.e.a,p.d-=c.e.b)}function eYE(e){var t,n,r,i,a,o,s,u,l,f,d,h,p;for(t=new p2,u=new Ow(e);u.e!=u.i.gc();){for(s=Pp(epH(u),33),n=new bV,Um(e9t,s,n),p=new e5,i=Pp(qE(new R1(null,new YI(new Fa(OH(eOr(s).a.Kc(),new c)))),jD(p,JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[(eum(),e2U)])))),83),enC(n,Pp(i.xc((OQ(),!0)),14),new e6),o=(r=Pp(qE(UJ(Pp(i.xc(!1),15).Lc(),new e9),JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[e2U]))),15)).Kc();o.Ob();)(h=e_D(a=Pp(o.Pb(),79)))&&((l=Pp(xu($I(t.f,h)),21))||(l=eA7(h),eS9(t.f,h,l)),er7(n,l));for(i=Pp(qE(new R1(null,new YI(new Fa(OH(eOi(s).a.Kc(),new c)))),jD(p,JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[e2U])))),83),enC(n,Pp(i.xc(!0),14),new e8),d=(r=Pp(qE(UJ(Pp(i.xc(!1),15).Lc(),new e7),JF(new U,new B,new en,eow(vx(e2L,1),eU4,132,0,[e2U]))),15)).Kc();d.Ob();)(h=e_N(f=Pp(d.Pb(),79)))&&((l=Pp(xu($I(t.f,h)),21))||(l=eA7(h),eS9(t.f,h,l)),er7(n,l))}}function eYS(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b;if(ePN(),(u=0>ecd(e,0))&&(e=QC(e)),0==ecd(e,0))switch(t){case 0:return"0";case 1:return e$e;case 2:return"0.00";case 3:return"0.000";case 4:return"0.0000";case 5:return"0.00000";case 6:return"0.000000";default:return h=new vc,t<0?(h.a+="0E+",h):(h.a+="0E",h),h.a+=t==eHt?"2147483648":""+-t,h.a}f=Je(tyw,eHl,25,(l=18)+1,15,1),n=l,b=e;do c=b,b=eyt(b,10),f[--n]=jE(eft(48,efe(c,efn(b,10))))&eHd;while(0!=ecd(b,0))if(i=efe(efe(efe(l,n),t),1),0==t)return u&&(f[--n]=45),ehv(f,n,l-n);if(t>0&&ecd(i,-6)>=0){if(ecd(i,0)>=0){for(a=n+jE(i),s=l-1;s>=a;s--)f[s+1]=f[s];return f[++a]=46,u&&(f[--n]=45),ehv(f,n,l-n+1)}for(o=2;Ei(o,eft(QC(i),1));o++)f[--n]=48;return f[--n]=46,f[--n]=48,u&&(f[--n]=45),ehv(f,n,l-n)}return p=n+1,r=l,d=new vl,u&&(d.a+="-"),r-p>=1?(Bd(d,f[n]),d.a+=".",d.a+=ehv(f,n+1,l-n-1)):d.a+=ehv(f,n,l-n),d.a+="E",ecd(i,0)>0&&(d.a+="+"),d.a+=""+Fb(i),d.a}function eYk(e,t,n){var r,i,a,o,s,u,c,l,f,d,h;if(e.e.a.$b(),e.f.a.$b(),e.c.c=Je(e1R,eUp,1,0,5,1),e.i.c=Je(e1R,eUp,1,0,5,1),e.g.a.$b(),t)for(o=new fz(t.a);o.a=1&&(_-c>0&&p>=0?(eno(f,f.i+w),ens(f,f.j+u*c)):_-c<0&&h>=0&&(eno(f,f.i+w*_),ens(f,f.j+u)));return ebu(e,(eBB(),thx),(ed6(),a=Pp(yw(e6o),9),new I1(a,Pp(CY(a,a.length),9),0))),new kl(E,l)}function eYT(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p;if(h=z$(ewH(Pp(etj((e.b||(e.b=new Ih(e6m,e,4,7)),e.b),0),82))),p=z$(ewH(Pp(etj((e.c||(e.c=new Ih(e6m,e,5,8)),e.c),0),82))),f=h==p,s=new yb,(t=Pp(eT8(e,(euw(),tpj)),74))&&t.b>=2){if(0==(e.a||(e.a=new FQ(e6v,e,6,6)),e.a).i)n=(yT(),i=new oQ),JL((e.a||(e.a=new FQ(e6v,e,6,6)),e.a),n);else if((e.a||(e.a=new FQ(e6v,e,6,6)),e.a).i>1)for(d=new AF((e.a||(e.a=new FQ(e6v,e,6,6)),e.a));d.e!=d.i.gc();)ey_(d);eNI(t,Pp(etj((e.a||(e.a=new FQ(e6v,e,6,6)),e.a),0),202))}if(f)for(r=new Ow((e.a||(e.a=new FQ(e6v,e,6,6)),e.a));r.e!=r.i.gc();)for(n=Pp(epH(r),202),c=new Ow((n.a||(n.a=new O_(e6h,n,5)),n.a));c.e!=c.i.gc();)u=Pp(epH(c),469),s.a=eB4.Math.max(s.a,u.a),s.b=eB4.Math.max(s.b,u.b);for(o=new Ow((e.n||(e.n=new FQ(e6S,e,1,7)),e.n));o.e!=o.i.gc();)a=Pp(epH(o),137),(l=Pp(eT8(a,tp$),8))&&TP(a,l.a,l.b),f&&(s.a=eB4.Math.max(s.a,a.i+a.g),s.b=eB4.Math.max(s.b,a.j+a.f));return s}function eYM(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,k,x;for(s=0,y=t.c.length,i=new eIW(e.a,n,null,null),x=Je(tyx,eH5,25,y,15,1),b=Je(tyx,eH5,25,y,15,1),p=Je(tyx,eH5,25,y,15,1),m=0;sx[u]&&(m=u),f=new fz(e.a.b);f.ah&&(a&&(xL(E,d),xL(k,ell(c.b-1))),A=n.b,L+=d+t,d=0,l=eB4.Math.max(l,n.b+n.c+O)),eno(s,A),ens(s,L),l=eB4.Math.max(l,A+O+n.c),d=eB4.Math.max(d,f),A+=O+t;if(l=eB4.Math.max(l,r),(M=L+d+n.a)ez8,x=eB4.Math.abs(d.b-p.b)>ez8,(!n&&k&&x||n&&(k||x))&&P7(m.a,w)),er7(m.a,r),d=0==r.b?w:(A6(0!=r.b),Pp(r.c.b.c,8)),ea1(h,f,b),eiy(i)==S&&(Bq(S.i)!=i.a&&eSb(b=new yb,Bq(S.i),v),eo3(m,tnC,b)),eEw(h,m,v),l.a.zc(h,l);Gs(m,_),Go(m,S)}for(c=l.a.ec().Kc();c.Ob();)Gs(u=Pp(c.Pb(),17),null),Go(u,null);eEj(t)}function eYC(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w;if(1==e.gc())return Pp(e.Xb(0),231);if(0>=e.gc())return new Z5;for(i=e.Kc();i.Ob();){for(n=Pp(i.Pb(),231),p=0,l=eUu,f=eUu,u=eHt,c=eHt,h=new fz(n.e);h.as&&(y=0,w+=o+g,o=0),eIJ(b,n,y,w),t=eB4.Math.max(t,y+m.a),o=eB4.Math.max(o,m.b),y+=m.a+g;return b}function eYI(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p;switch(l=new mE,e.a.g){case 3:d=Pp(e_k(t.e,(eBU(),tnO)),15),h=Pp(e_k(t.j,tnO),15),p=Pp(e_k(t.f,tnO),15),n=Pp(e_k(t.e,tnT),15),r=Pp(e_k(t.j,tnT),15),i=Pp(e_k(t.f,tnT),15),o=new p0,eoc(o,d),h.Jc(new iN),eoc(o,M4(h,152)?ZK(Pp(h,152)):M4(h,131)?Pp(h,131).a:M4(h,54)?new gn(h):new w$(h)),eoc(o,p),a=new p0,eoc(a,n),eoc(a,M4(r,152)?ZK(Pp(r,152)):M4(r,131)?Pp(r,131).a:M4(r,54)?new gn(r):new w$(r)),eoc(a,i),eo3(t.f,tnO,o),eo3(t.f,tnT,a),eo3(t.f,tnA,t.f),eo3(t.e,tnO,null),eo3(t.e,tnT,null),eo3(t.j,tnO,null),eo3(t.j,tnT,null);break;case 1:er7(l,t.e.a),P7(l,t.i.n),er7(l,eaa(t.j.a)),P7(l,t.a.n),er7(l,t.f.a);break;default:er7(l,t.e.a),er7(l,eaa(t.j.a)),er7(l,t.f.a)}HC(t.f.a),er7(t.f.a,l),Gs(t.f,t.e.c),s=Pp(e_k(t.e,(eBy(),taR)),74),c=Pp(e_k(t.j,taR),74),u=Pp(e_k(t.f,taR),74),(s||c||u)&&(Yp(f=new mE,u),Yp(f,c),Yp(f,s),eo3(t.f,taR,f)),Gs(t.j,null),Go(t.j,null),Gs(t.e,null),Go(t.e,null),Gu(t.a,null),Gu(t.i,null),t.g&&eYI(e,t.g)}function eYD(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m;if(eNl(),null==e||(a=Q4(e),(p=elw(a))%4!=0))return null;if(0==(b=p/4|0))return Je(tyk,eZ8,25,0,15,1);for(f=null,t=0,n=0,r=0,i=0,o=0,s=0,u=0,c=0,h=0,d=0,l=0,f=Je(tyk,eZ8,25,3*b,15,1);h>4)<<24>>24,f[d++]=((15&n)<<4|r>>2&15)<<24>>24,f[d++]=(r<<6|i)<<24>>24}if(!wl(o=a[l++])||!wl(s=a[l++]))return null;if(t=tvJ[o],n=tvJ[s],u=a[l++],c=a[l++],-1==tvJ[u]||-1==tvJ[c])return 61==u&&61==c?(15&n)!=0?null:(m=Je(tyk,eZ8,25,3*h+1,15,1),ePD(f,0,m,0,3*h),m[d]=(t<<2|n>>4)<<24>>24,m):61==u||61!=c?null:(3&(r=tvJ[u]))!=0?null:(m=Je(tyk,eZ8,25,3*h+2,15,1),ePD(f,0,m,0,3*h),m[d++]=(t<<2|n>>4)<<24>>24,m[d]=((15&n)<<4|r>>2&15)<<24>>24,m);return r=tvJ[u],i=tvJ[c],f[d++]=(t<<2|n>>4)<<24>>24,f[d++]=((15&n)<<4|r>>2&15)<<24>>24,f[d++]=(r<<6|i)<<24>>24,f}function eYN(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_;for(ewG(t,eWo,1),p=Pp(e_k(e,(eBy(),tag)),218),i=new fz(e.b);i.a=2){for(b=!0,n=Pp(Wx(d=new fz(a.j)),11),h=null;d.a0&&(i=Pp(RJ(m.c.a,E-1),10),o=e.i[i.p],k=eB4.Math.ceil(Mj(e.n,i,m)),a=_.a.e-m.d.d-(o.a.e+i.o.b+i.d.a)-k),c=eHQ,E0&&S.a.e.e-S.a.a-(S.b.e.e-S.b.a)<0,p=y.a.e.e-y.a.a-(y.b.e.e-y.b.a)<0&&S.a.e.e-S.a.a-(S.b.e.e-S.b.a)>0,h=y.a.e.e+y.b.aS.b.e.e+S.a.a,w=0,!b&&!p&&(d?a+f>0?w=f:c-r>0&&(w=r):h&&(a+s>0?w=s:c-v>0&&(w=v))),_.a.e+=w,_.b&&(_.d.e+=w),!1))}function eYR(e,t,n){var r,i,a,o,s,u,c,l,f,d;if(r=new Hr(t.qf().a,t.qf().b,t.rf().a,t.rf().b),i=new TE,e.c)for(o=new fz(t.wf());o.ac&&(r.a+=M3(Je(tyw,eHl,25,-c,15,1))),r.a+="Is",x7(u,e_n(32))>=0)for(i=0;i=r.o.b/2}v?(g=Pp(e_k(r,(eBU(),tnI)),15))?d?a=g:(i=Pp(e_k(r,ttB),15))?a=g.gc()<=i.gc()?g:i:(a=new p0,eo3(r,ttB,a)):(a=new p0,eo3(r,tnI,a)):(i=Pp(e_k(r,(eBU(),ttB)),15))?f?a=i:(g=Pp(e_k(r,tnI),15))?a=i.gc()<=g.gc()?i:g:(a=new p0,eo3(r,tnI,a)):(a=new p0,eo3(r,ttB,a)),a.Fc(e),eo3(e,(eBU(),ttH),n),t.d==n?(Go(t,null),n.e.c.length+n.g.c.length==0&&Gc(n,null),esQ(n)):(Gs(t,null),n.e.c.length+n.g.c.length==0&&Gc(n,null)),HC(t.a)}function eYH(e,t){var n,r,i,a,o,s,u,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A,L;for(y=new KB(e.b,0),f=t.Kc(),b=0,l=Pp(f.Pb(),19).a,E=0,n=new bV,k=new Tw;y.b=e.a&&(r=eN3(e,y),f=eB4.Math.max(f,r.b),_=eB4.Math.max(_,r.d),P_(s,new kD(y,r)));for(l=0,x=new p0;l0),g.a.Xb(g.c=--g.b),T=new By(e.b),CD(g,T),A6(g.b0?(c=0,m&&(c+=s),c+=(x-1)*o,y&&(c+=s),k&&y&&(c=eB4.Math.max(c,eAD(y,o,v,S))),!(c0){for(i=0,d=l<100?null:new yf(l),p=(c=new eiP(t)).g,g=Je(ty_,eHT,25,l,15,1),r=0,w=new eta(l);i=0;)if(null!=h?ecX(h,p[u]):xc(h)===xc(p[u])){g.length<=r&&(m=g,g=Je(ty_,eHT,25,2*g.length,15,1),ePD(m,0,g,0,r)),g[r++]=i,JL(w,p[u]);break v}if(xc(h)===xc(s))break}}if(c=w,p=w.g,l=r,r>g.length&&(m=g,g=Je(ty_,eHT,25,r,15,1),ePD(m,0,g,0,r)),r>0){for(a=0,y=!0;a=0;)egk(e,g[o]);if(r!=l){for(i=l;--i>=r;)egk(c,i);m=g,g=Je(ty_,eHT,25,r,15,1),ePD(m,0,g,0,r)}t=c}}}else for(t=egh(e,t),i=e.i;--i>=0;)t.Hc(e.g[i])&&(egk(e,i),y=!0);if(!y)return!1;if(null!=g){for(f=1==(n=t.gc())?Gt(e,4,t.Kc().Pb(),null,g[0],b):Gt(e,6,t,g,g[0],b),d=n<100?null:new yf(n),i=t.Kc();i.Ob();)d=IW(e,Pp(h=i.Pb(),72),d);d?(d.Ei(f),d.Fi()):eam(e.e,f)}else{for(d=IP(t.gc()),i=t.Kc();i.Ob();)d=IW(e,Pp(h=i.Pb(),72),d);d&&d.Fi()}return!0}function eYV(e,t){var n,r,i,a,o,s,u,l,f,d,h,p,b,m,g,v,y,w;for((n=new eb_(t)).a||eDc(t),l=eCx(t),u=new zu,g=new eLy,m=new fz(t.a);m.a0||n.o==tuS&&i0?(f=Pp(RJ(d.c.a,o-1),10),k=Mj(e.b,d,f),m=d.n.b-d.d.d-(f.n.b+f.o.b+f.d.a+k)):m=d.n.b-d.d.d,c=eB4.Math.min(m,c),oo?eIc(e,t,n):eIc(e,n,t),io?1:0}return r=Pp(e_k(t,(eBU(),tnu)),19).a,a=Pp(e_k(n,tnu),19).a,r>a?eIc(e,t,n):eIc(e,n,t),ra?1:0}function eYQ(e,t,n,r){var i,a,o,s,u,c,l,f,d,h,p,b,m,g,v;if(gN(LK(eT8(t,(eBB(),thI))))||(c=0!=(t.a||(t.a=new FQ(e6k,t,10,11)),t.a).i,l=!(f=ekq(t)).dc(),!c&&!l))return Hj(),Hj(),e2r;if(!(i=Pp(eT8(t,th6),149)))throw p7(new gq("Resolved algorithm is not set; apply a LayoutAlgorithmResolver before computing layout."));if(v=ka(i,(eTy(),tmC)),ept(t),!c&&l&&!v)return Hj(),Hj(),e2r;if(u=new p0,xc(eT8(t,thl))===xc((eck(),tpz))&&(ka(i,tmO)||ka(i,tmM)))for(h=eCL(e,t),er7(p=new _n,(t.a||(t.a=new FQ(e6k,t,10,11)),t.a));0!=p.b;)ept(d=Pp(0==p.b?null:(A6(0!=p.b),etw(p,p.a.a)),33)),(g=xc(eT8(d,thl))===xc(tpW))||X2(d,tdQ)&&!Zs(i,eT8(d,th6))?(s=eYQ(e,d,n,r),eoc(u,s),ebu(d,thl,tpW),eIU(d)):er7(p,(d.a||(d.a=new FQ(e6k,d,10,11)),d.a));else for(h=(t.a||(t.a=new FQ(e6k,t,10,11)),t.a).i,o=new Ow((t.a||(t.a=new FQ(e6k,t,10,11)),t.a));o.e!=o.i.gc();)a=Pp(epH(o),33),s=eYQ(e,a,n,r),eoc(u,s),eIU(a);for(m=new fz(u);m.a=0?ef9(s):elC(ef9(s)),e.Ye(tob,h)),c=new yb,d=!1,e.Xe(tou)?(Lf(c,Pp(e.We(tou),8)),d=!0):Oc(c,o.a/2,o.b/2),h.g){case 4:eo3(l,taY,(ef_(),tnN)),eo3(l,ttV,(eoG(),te0)),l.o.b=o.b,b<0&&(l.o.a=-b),ekv(f,(eYu(),tby)),d||(c.a=o.a),c.a-=o.a;break;case 2:eo3(l,taY,(ef_(),tnR)),eo3(l,ttV,(eoG(),teQ)),l.o.b=o.b,b<0&&(l.o.a=-b),ekv(f,(eYu(),tbY)),d||(c.a=0);break;case 1:eo3(l,tt9,(Q1(),ttN)),l.o.a=o.a,b<0&&(l.o.b=-b),ekv(f,(eYu(),tbj)),d||(c.b=o.b),c.b-=o.b;break;case 3:eo3(l,tt9,(Q1(),ttI)),l.o.a=o.a,b<0&&(l.o.b=-b),ekv(f,(eYu(),tbw)),d||(c.b=0)}if(Lf(f.n,c),eo3(l,tou,c),t==tba||t==tbs||t==tbo){if(p=0,t==tba&&e.Xe(tof))switch(h.g){case 1:case 2:p=Pp(e.We(tof),19).a;break;case 3:case 4:p=-Pp(e.We(tof),19).a}else switch(h.g){case 4:case 2:p=a.b,t==tbs&&(p/=i.b);break;case 1:case 3:p=a.a,t==tbs&&(p/=i.a)}eo3(l,tnv,p)}return eo3(l,tt1,h),l}function eY0(e){var t,n,r,i,a,o,s,u,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T;if((n=gP(LV(e_k(e.a.j,(eBy(),tar)))))<-1||!e.a.i||IR(Pp(e_k(e.a.o,tol),98))||2>efr(e.a.o,(eYu(),tby)).gc()&&2>efr(e.a.o,tbY).gc())return!0;if(e.a.c.Rf())return!1;for(E=0,_=0,w=new p0,u=e.a.e,l=0,f=u.length;l=n}function eY2(){function n(e){var t=this;this.dispatch=function(t){var n=t.data;switch(n.cmd){case"algorithms":var r=edh((Hj(),new fF(new fT(tmF.b))));e.postMessage({id:n.id,data:r});break;case"categories":var i=edh((Hj(),new fF(new fT(tmF.c))));e.postMessage({id:n.id,data:i});break;case"options":var a=edh((Hj(),new fF(new fT(tmF.d))));e.postMessage({id:n.id,data:a});break;case"register":ejy(n.algorithms),e.postMessage({id:n.id});break;case"layout":ePu(n.graph,n.layoutOptions||{},n.options||{}),e.postMessage({id:n.id,data:n.graph})}},this.saveDispatch=function(n){try{t.dispatch(n)}catch(r){e.postMessage({id:n.data.id,error:r})}}}function r(e){var t=this;this.dispatcher=new n({postMessage:function(e){t.onmessage({data:e})}}),this.postMessage=function(e){setTimeout(function(){t.dispatcher.saveDispatch({data:e})},0)}}if(yC(),typeof document===e$E&&typeof self!==e$E){var i=new n(self);self.onmessage=i.saveDispatch}else"object"!==e$E&&e.exports&&(Object.defineProperty(t,"__esModule",{value:!0}),e.exports={default:r,Worker:r})}function eY3(e){e.N||(e.N=!0,e.b=eak(e,0),er6(e.b,0),er6(e.b,1),er6(e.b,2),e.bb=eak(e,1),er6(e.bb,0),er6(e.bb,1),e.fb=eak(e,2),er6(e.fb,3),er6(e.fb,4),er9(e.fb,5),e.qb=eak(e,3),er6(e.qb,0),er9(e.qb,1),er9(e.qb,2),er6(e.qb,3),er6(e.qb,4),er9(e.qb,5),er6(e.qb,6),e.a=eax(e,4),e.c=eax(e,5),e.d=eax(e,6),e.e=eax(e,7),e.f=eax(e,8),e.g=eax(e,9),e.i=eax(e,10),e.j=eax(e,11),e.k=eax(e,12),e.n=eax(e,13),e.o=eax(e,14),e.p=eax(e,15),e.q=eax(e,16),e.s=eax(e,17),e.r=eax(e,18),e.t=eax(e,19),e.u=eax(e,20),e.v=eax(e,21),e.w=eax(e,22),e.B=eax(e,23),e.A=eax(e,24),e.C=eax(e,25),e.D=eax(e,26),e.F=eax(e,27),e.G=eax(e,28),e.H=eax(e,29),e.J=eax(e,30),e.I=eax(e,31),e.K=eax(e,32),e.M=eax(e,33),e.L=eax(e,34),e.P=eax(e,35),e.Q=eax(e,36),e.R=eax(e,37),e.S=eax(e,38),e.T=eax(e,39),e.U=eax(e,40),e.V=eax(e,41),e.X=eax(e,42),e.W=eax(e,43),e.Y=eax(e,44),e.Z=eax(e,45),e.$=eax(e,46),e._=eax(e,47),e.ab=eax(e,48),e.cb=eax(e,49),e.db=eax(e,50),e.eb=eax(e,51),e.gb=eax(e,52),e.hb=eax(e,53),e.ib=eax(e,54),e.jb=eax(e,55),e.kb=eax(e,56),e.lb=eax(e,57),e.mb=eax(e,58),e.nb=eax(e,59),e.ob=eax(e,60),e.pb=eax(e,61))}function eY4(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w;if(v=0,0==t.f.a)for(m=new fz(e);m.ac&&0==(GK(c,t.c.length),Pp(t.c[c],200)).a.c.length;)QA(t,(GK(c,t.c.length),t.c[c]));if(!u){--a;continue}if(eDk(t,l,i,u,d,n,c,r)){f=!0;continue}if(d){if(ePx(t,l,i,u,n,c,r)){f=!0;continue}if(eu4(l,i)){i.c=!0,f=!0;continue}}else if(eu4(l,i)){i.c=!0,f=!0;continue}if(f)continue}if(eu4(l,i)){i.c=!0,f=!0,u&&(u.k=!1);continue}emG(i.q)}return f}function eY9(e,t,n,r,i,a,o){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A,L;for(b=0,T=0,c=new fz(e.b);c.ab&&(a&&(xL(E,h),xL(k,ell(l.b-1)),P_(e.d,p),s.c=Je(e1R,eUp,1,0,5,1)),A=n.b,L+=h+t,h=0,f=eB4.Math.max(f,n.b+n.c+O)),s.c[s.c.length]=u,epW(u,A,L),f=eB4.Math.max(f,A+O+n.c),h=eB4.Math.max(h,d),A+=O+t,p=u;if(eoc(e.a,s),P_(e.d,Pp(RJ(s,s.c.length-1),157)),f=eB4.Math.max(f,r),(M=L+h+n.a)1&&(o=eB4.Math.min(o,eB4.Math.abs(Pp(ep3(s.a,1),8).b-l.b)))));else for(b=new fz(t.j);b.ai&&(a=d.a-i,o=eUu,r.c=Je(e1R,eUp,1,0,5,1),i=d.a),d.a>=i&&(r.c[r.c.length]=s,s.a.b>1&&(o=eB4.Math.min(o,eB4.Math.abs(Pp(ep3(s.a,s.a.b-2),8).b-d.b)))));if(0!=r.c.length&&a>t.o.a/2&&o>t.o.b/2){for(h=new eES,Gc(h,t),ekv(h,(eYu(),tbw)),h.n.a=t.o.a/2,g=new eES,Gc(g,t),ekv(g,tbj),g.n.a=t.o.a/2,g.n.b=t.o.b,u=new fz(r);u.a=c.b?Gs(s,g):Gs(s,h)):(c=Pp(P$(s.a),8),(m=0==s.a.b?GX(s.c):Pp(AZ(s.a),8)).b>=c.b?Go(s,g):Go(s,h)),(f=Pp(e_k(s,(eBy(),taR)),74))&&eds(f,c,!0);t.n.a=i-t.o.a/2}}function eBe(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A,L,C,I;if(T=null,O=t,M=V0(e,VF(n),O),ert(M,KJ(O,eXS)),A=Pp(etJ(e.g,ekZ(zR(O,eXi))),33),d=zR(O,"sourcePort"),r=null,d&&(r=ekZ(d)),L=Pp(etJ(e.j,r),118),!A)throw b=(p="An edge must have a source node (edge id: '"+(s=ehM(O)))+eXO,p7(new gK(b));if(L&&!BG(zY(L),A))throw g=(m="The source port of an edge must be a port of the edge's source node (edge id: '"+(u=KJ(O,eXS)))+eXO,p7(new gK(g));if(k=(M.b||(M.b=new Ih(e6m,M,4,7)),M.b),a=null,JL(k,a=L||A),C=Pp(etJ(e.g,ekZ(zR(O,eXC))),33),h=zR(O,"targetPort"),i=null,h&&(i=ekZ(h)),I=Pp(etJ(e.j,i),118),!C)throw y=(v="An edge must have a target node (edge id: '"+(f=ehM(O)))+eXO,p7(new gK(y));if(I&&!BG(zY(I),C))throw _=(w="The target port of an edge must be a port of the edge's target node (edge id: '"+(c=KJ(O,eXS)))+eXO,p7(new gK(_));if(x=(M.c||(M.c=new Ih(e6m,M,5,8)),M.c),o=null,JL(x,o=I||C),0==(M.b||(M.b=new Ih(e6m,M,4,7)),M.b).i||0==(M.c||(M.c=new Ih(e6m,M,5,8)),M.c).i)throw S=(E=eXM+(l=KJ(O,eXS)))+eXO,p7(new gK(S));return ewU(O,M),eMu(O,M),T=esv(e,O,M)}function eBt(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T;return f=eNf(A_(e,(eYu(),tbx)),t),p=em9(A_(e,tbT),t),w=em9(A_(e,tbN),t),k=em8(A_(e,tbR),t),d=em8(A_(e,tb_),t),v=em9(A_(e,tbD),t),b=em9(A_(e,tbM),t),E=em9(A_(e,tbP),t),_=em9(A_(e,tbE),t),x=em8(A_(e,tbk),t),g=em9(A_(e,tbC),t),y=em9(A_(e,tbL),t),S=em9(A_(e,tbS),t),T=em8(A_(e,tbI),t),h=em8(A_(e,tbO),t),m=em9(A_(e,tbA),t),n=esm(eow(vx(tyx,1),eH5,25,15,[v.a,k.a,E.a,T.a])),r=esm(eow(vx(tyx,1),eH5,25,15,[p.a,f.a,w.a,m.a])),i=g.a,a=esm(eow(vx(tyx,1),eH5,25,15,[b.a,d.a,_.a,h.a])),c=esm(eow(vx(tyx,1),eH5,25,15,[v.b,p.b,b.b,y.b])),u=esm(eow(vx(tyx,1),eH5,25,15,[k.b,f.b,d.b,m.b])),l=x.b,s=esm(eow(vx(tyx,1),eH5,25,15,[E.b,w.b,_.b,S.b])),JD(A_(e,tbx),n+i,c+l),JD(A_(e,tbA),n+i,c+l),JD(A_(e,tbT),n+i,0),JD(A_(e,tbN),n+i,c+l+u),JD(A_(e,tbR),0,c+l),JD(A_(e,tb_),n+i+r,c+l),JD(A_(e,tbM),n+i+r,0),JD(A_(e,tbP),0,c+l+u),JD(A_(e,tbE),n+i+r,c+l+u),JD(A_(e,tbk),0,c),JD(A_(e,tbC),n,0),JD(A_(e,tbS),0,c+l+u),JD(A_(e,tbO),n+i+r,0),(o=new yb).a=esm(eow(vx(tyx,1),eH5,25,15,[n+r+i+a,x.a,y.a,S.a])),o.b=esm(eow(vx(tyx,1),eH5,25,15,[c+u+l+s,g.b,T.b,h.b])),o}function eBn(e){var t,n,r,i,a,o,s,u,l,f,d,h,p,b,m,g;for(m=new p0,h=new fz(e.d.b);h.ai.d.d+i.d.a?f.f.d=!0:(f.f.d=!0,f.f.a=!0))),r.b!=r.d.c&&(t=n);f&&(a=Pp(Bp(e.f,o.d.i),57),t.ba.d.d+a.d.a?f.f.d=!0:(f.f.d=!0,f.f.a=!0))}for(s=new Fa(OH(efu(p).a.Kc(),new c));eTk(s);)0!=(o=Pp(ZC(s),17)).a.b&&(t=Pp(AZ(o.a),8),o.d.j==(eYu(),tbw)&&((g=new ePe(t,new kl(t.a,i.d.d),i,o)).f.a=!0,g.a=o.d,m.c[m.c.length]=g),o.d.j==tbj&&((g=new ePe(t,new kl(t.a,i.d.d+i.d.a),i,o)).f.d=!0,g.a=o.d,m.c[m.c.length]=g))}return m}function eBr(e,t,n){var r,i,a,o,s,u,c,l,f;if(ewG(n,"Network simplex node placement",1),e.e=t,e.n=Pp(e_k(t,(eBU(),tnx)),304),eRx(e),ey8(e),_r(eeh(new R1(null,new Gq(e.e.b,16)),new i2),new hR(e)),_r(UJ(eeh(UJ(eeh(new R1(null,new Gq(e.e.b,16)),new aa),new ao),new as),new au),new hP(e)),gN(LK(e_k(e.e,(eBy(),taQ))))&&(o=eiI(n,1),ewG(o,"Straight Edges Pre-Processing",1),eFy(e),eEj(o)),ebR(e.f),a=Pp(e_k(t,to$),19).a*e.f.a.c.length,eIX(vC(vI(DN(e.f),a),!1),eiI(n,1)),0!=e.d.a.gc()){for(o=eiI(n,1),ewG(o,"Flexible Where Space Processing",1),s=Pp(Af(FM(UQ(new R1(null,new Gq(e.f.a,16)),new i3),new iZ)),19).a,c=(u=Pp(Af(FT(UQ(new R1(null,new Gq(e.f.a,16)),new i4),new iX)),19).a)-s,l=Al(new b1,e.f),f=Al(new b1,e.f),eAx(_f(_l(_c(_d(new bQ,2e4),c),l),f)),_r(UJ(UJ(Yw(e.i),new i5),new i6),new Hn(s,l,c,f)),i=e.d.a.ec().Kc();i.Ob();)(r=Pp(i.Pb(),213)).g=1;eIX(vC(vI(DN(e.f),a),!1),eiI(o,1)),eEj(o)}gN(LK(e_k(t,taQ)))&&(o=eiI(n,1),ewG(o,"Straight Edges Post-Processing",1),eSf(e),eEj(o)),ej3(e),e.e=null,e.f=null,e.i=null,e.c=null,Yy(e.k),e.j=null,e.a=null,e.o=null,e.d.a.$b(),eEj(n)}function eBi(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_;for(s=new fz(e.a.b);s.a0){if(r=f.gc(),c=zy(eB4.Math.floor((r+1)/2))-1,i=zy(eB4.Math.ceil((r+1)/2))-1,t.o==tuS)for(l=i;l>=c;l--)t.a[w.p]==w&&(b=Pp(f.Xb(l),46),p=Pp(b.a,10),!w0(n,b.b)&&h>e.b.e[p.p]&&(t.a[p.p]=w,t.g[w.p]=t.g[p.p],t.a[w.p]=t.g[w.p],t.f[t.g[w.p].p]=(OQ(),!!(gN(t.f[t.g[w.p].p])&w.k==(eEn(),e8D))),h=e.b.e[p.p]));else for(l=c;l<=i;l++)t.a[w.p]==w&&(g=Pp(f.Xb(l),46),m=Pp(g.a,10),!w0(n,g.b)&&h=p&&(v>p&&(h.c=Je(e1R,eUp,1,0,5,1),p=v),h.c[h.c.length]=o);0!=h.c.length&&(d=Pp(RJ(h,ebO(t,h.c.length)),128),M.a.Bc(d),d.s=b++,eM4(d,x,E),h.c=Je(e1R,eUp,1,0,5,1))}for(w=e.c.length+1,s=new fz(e);s.aT.s&&(BH(n),QA(T.i,r),r.c>0&&(r.a=T,P_(T.t,r),r.b=S,P_(S.i,r)))}function eBs(e){var t,n,r,i,a;switch(t=e.c){case 11:return e.Ml();case 12:return e.Ol();case 14:return e.Ql();case 15:return e.Tl();case 16:return e.Rl();case 17:return e.Ul();case 21:return eBM(e),eBG(),eBG(),tye;case 10:switch(e.a){case 65:return e.yl();case 90:return e.Dl();case 122:return e.Kl();case 98:return e.El();case 66:return e.zl();case 60:return e.Jl();case 62:return e.Hl()}}switch(a=eY8(e),t=e.c){case 3:return e.Zl(a);case 4:return e.Xl(a);case 5:return e.Yl(a);case 0:if(123==e.a&&e.d=48&&t<=57){for(r=t-48;i=48&&t<=57;)if((r=10*r+t-48)<0)throw p7(new gX(eBJ((Mo(),eJ_))))}else throw p7(new gX(eBJ((Mo(),eJg))));if(n=r,44==t){if(i>=e.j)throw p7(new gX(eBJ((Mo(),eJy))));if((t=UI(e.i,i++))>=48&&t<=57){for(n=t-48;i=48&&t<=57;)if((n=10*n+t-48)<0)throw p7(new gX(eBJ((Mo(),eJ_))));if(r>n)throw p7(new gX(eBJ((Mo(),eJw))))}else n=-1}if(125!=t)throw p7(new gX(eBJ((Mo(),eJv))));e.sl(i)?(a=(eBG(),eBG(),++tyv,new qa(9,a)),e.d=i+1):(a=(eBG(),eBG(),++tyv,new qa(3,a)),e.d=i),a.dm(r),a.cm(n),eBM(e)}}return a}function eBu(e,t,n,r,i){var a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M;for(b=new XM(t.b),w=new XM(t.b),d=new XM(t.b),k=new XM(t.b),m=new XM(t.b),S=epL(t,0);S.b!=S.d.c;)for(_=Pp(Vv(S),11),s=new fz(_.g);s.a0,g=_.g.c.length>0,c&&g?d.c[d.c.length]=_:c?b.c[b.c.length]=_:g&&(w.c[w.c.length]=_);for(p=new fz(b);p.aefT(Jh(y.d,x),Jh(y.d,y.a))&&(a.c[a.c.length]=y);for(n.c=Je(e1R,eUp,1,0,5,1),w=new fz(a);w.a1)for(p=new AF((e.a||(e.a=new FQ(e6v,e,6,6)),e.a));p.e!=p.i.gc();)ey_(p);for(o=Pp(etj((e.a||(e.a=new FQ(e6v,e,6,6)),e.a),0),202),m=A,A>_+w?m=_+w:A<_-w&&(m=_-w),g=L,L>E+b?g=E+b:L_-w&&m<_+w&&g>E-b&&gA+O?k=A+O:_L+S?x=L+S:EA-O&&kL-S&&xn&&(d=n-1),(h=P+eMU(t,24)*e$h*f-f/2)<0?h=1:h>r&&(h=r-1),i=(yT(),u=new oJ),ent(i,d),enn(i,h),JL((o.a||(o.a=new O_(e6h,o,5)),o.a),i)}function eBy(){eBy=A,tox=(eBB(),th7),toT=tpe,toM=tpt,toO=tpn,toL=tpr,toC=tpi,toN=tpo,toR=tpu,toj=tpc,toP=tps,toF=tpl,toB=tpf,toH=tpp,toD=tpa,tok=(eBH(),tih),toA=tip,toI=tib,toY=tim,tov=new T2(th4,ell(0)),toy=til,tow=tif,to_=tid,toQ=tiB,toG=tiy,toW=tiE,toq=tiL,toK=tix,toV=tiM,to0=tiG,to1=tiH,toX=tiR,toZ=tiN,toJ=tiF,ta0=tit,ta2=tin,taE=trE,taS=trx,toe=new T3(12),ta7=new T2(thN,toe),tav=(efE(),tpx),tag=new T2(tha,tav),toc=new T2(thK,0),toE=new T2(th5,ell(1)),tiX=new T2(td2,eGt),ta8=thI,tol=thV,tob=th0,tac=td7,tiq=td1,taM=thl,toS=new T2(th8,(OQ(),!0)),taI=thh,taD=thp,ta4=thx,ta9=thL,ta5=thM,tad=(ec3(),tpv),tal=new T2(the,tad),taZ=thS,taq=th_,toh=thJ,tod=thX,top=th1,tor=(epT(),tbr),new T2(thB,tor),toa=th$,too=thz,tos=thG,toi=thH,toz=tiv,taG=trZ,taz=trV,to$=tig,taY=trB,tau=trs,tas=tra,ti7=tn1,tae=tn0,tan=tn6,tat=tn2,tao=trr,taK=trJ,taV=trQ,taP=trD,ta3=tio,taJ=tr3,tax=trO,ta1=tr7,taw=trg,ta_=trw,ti8=td9,taX=tr1,ti0=tn$,ti1=tnU,tiQ=tnB,taA=trC,taO=trL,taL=trI,ta6=thO,taR=thg,tak=ths,tab=thr,tap=thn,tar=tn7,tof=thZ,tiJ=td6,taC=thd,tou=thW,tot=thR,ton=thF,taU=tr$,taH=trG,tog=th3,tiZ=tnY,ta$=trK,tam=trh,tah=trf,taW=thy,taj=trj,taQ=tr6,toU=tpd,taf=trc,tom=tiu,tay=trb,taF=trY,tai=trt,taN=thm,taB=trH,taa=trn,ti9=tnJ,ti5=tnq,ti3=tnK,ti4=tnV,ti6=tnX,ti2=tnG,taT=trA}function eBw(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;if(ePN(),k=e.e,p=e.d,i=e.a,0==k)switch(t){case 0:return"0";case 1:return e$e;case 2:return"0.00";case 3:return"0.000";case 4:return"0.0000";case 5:return"0.00000";case 6:return"0.000000";default:return E=new vc,t<0?(E.a+="0E+",E):(E.a+="0E",E),E.a+=-t,E.a}if(w=Je(tyw,eHl,25,(y=10*p+1+7)+1,15,1),n=y,1==p){if((s=i[0])<0){A=WM(s,eH8);do b=A,A=eyt(A,10),w[--n]=48+jE(efe(b,efn(A,10)))&eHd;while(0!=ecd(A,0))}else{A=s;do b=A,A=A/10|0,w[--n]=48+(b-10*A)&eHd;while(0!=A)}}else{T=Je(ty_,eHT,25,p,15,1),ePD(i,0,T,0,O=p);I:for(;;){for(S=0,c=O-1;c>=0;c--)g=ewT(M=eft(Fg(S,32),WM(T[c],eH8))),T[c]=jE(g),S=jE(Fv(g,32));v=jE(S),m=n;do w[--n]=48+v%10&eHd;while(0!=(v=v/10|0)&&0!=n)for(u=0,r=9-m+n;u0;u++)w[--n]=48;for(f=O-1;0==T[f];f--)if(0==f)break I;O=f+1}for(;48==w[n];)++n}if(h=k<0,o=y-n-t-1,0==t)return h&&(w[--n]=45),ehv(w,n,y-n);if(t>0&&o>=-6){if(o>=0){for(l=n+o,d=y-1;d>=l;d--)w[d+1]=w[d];return w[++l]=46,h&&(w[--n]=45),ehv(w,n,y-n+1)}for(f=2;f<-o+1;f++)w[--n]=48;return w[--n]=46,w[--n]=48,h&&(w[--n]=45),ehv(w,n,y-n)}return x=n+1,a=y,_=new vl,h&&(_.a+="-"),a-x>=1?(Bd(_,w[n]),_.a+=".",_.a+=ehv(w,n+1,y-n-1)):_.a+=ehv(w,n,y-n),_.a+="E",o>0&&(_.a+="+"),_.a+=""+o,_.a}function eB_(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E;switch(e.c=t,e.g=new p2,n=(_q(),new gM(e.c)),efJ(r=new dp(n)),y=Lq(eT8(e.c,(e_L(),tfD))),u=Pp(eT8(e.c,tfP),316),_=Pp(eT8(e.c,tfR),429),o=Pp(eT8(e.c,tfO),482),w=Pp(eT8(e.c,tfN),430),e.j=gP(LV(eT8(e.c,tfj))),s=e.a,u.g){case 0:s=e.a;break;case 1:s=e.b;break;case 2:s=e.i;break;case 3:s=e.e;break;case 4:s=e.f;break;default:throw p7(new gL(eqN+(null!=u.f?u.f:""+u.g)))}if(e.d=new zM(s,_,o),eo3(e.d,(ei6(),e6F),LK(eT8(e.c,tfL))),e.d.c=gN(LK(eT8(e.c,tfA))),0==H8(e.c).i)return e.d;for(f=new Ow(H8(e.c));f.e!=f.i.gc();){for(h=(l=Pp(epH(f),33)).g/2,d=l.f/2,E=new kl(l.i+h,l.j+d);F9(e.g,E);)Lu(E,(eB4.Math.random()-.5)*ez8,(eB4.Math.random()-.5)*ez8);b=Pp(eT8(l,(eBB(),thy)),142),m=new Gd(E,new Hr(E.a-h-e.j/2-b.b,E.b-d-e.j/2-b.d,l.g+e.j+(b.b+b.c),l.f+e.j+(b.d+b.a))),P_(e.d.i,m),Um(e.g,E,new kD(m,l))}switch(w.g){case 0:if(null==y)e.d.d=Pp(RJ(e.d.i,0),65);else for(v=new fz(e.d.i);v.a1&&qQ(l,g,l.c.b,l.c),etu(i)));g=v}return l}function eBS(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A,L,C,I,D;for(ewG(n,"Greedy cycle removal",1),D=(y=t.a).c.length,e.a=Je(ty_,eHT,25,D,15,1),e.c=Je(ty_,eHT,25,D,15,1),e.b=Je(ty_,eHT,25,D,15,1),c=0,g=new fz(y);g.a0?O+1:1);for(o=new fz(E.g);o.a0?O+1:1)}0==e.c[c]?P7(e.e,b):0==e.a[c]&&P7(e.f,b),++c}for(p=-1,h=1,f=new p0,e.d=Pp(e_k(t,(eBU(),tnw)),230);D>0;){for(;0!=e.e.b;)L=Pp(PH(e.e),10),e.b[L.p]=p--,eIQ(e,L),--D;for(;0!=e.f.b;)C=Pp(PH(e.f),10),e.b[C.p]=h++,eIQ(e,C),--D;if(D>0){for(d=eHt,v=new fz(y);v.a=d&&(w>d&&(f.c=Je(e1R,eUp,1,0,5,1),d=w),f.c[f.c.length]=b);l=e.Zf(f),e.b[l.p]=h++,eIQ(e,l),--D}}for(c=0,A=y.c.length+1;ce.b[I]&&(eNF(r,!0),eo3(t,ttK,(OQ(),!0)));e.a=null,e.c=null,e.b=null,HC(e.f),HC(e.e),eEj(n)}function eBk(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g;for(r=new p0,s=new p0,m=t/2,h=e.gc(),i=Pp(e.Xb(0),8),g=Pp(e.Xb(1),8),p=eT5(i.a,i.b,g.a,g.b,m),P_(r,(GK(0,p.c.length),Pp(p.c[0],8))),P_(s,(GK(1,p.c.length),Pp(p.c[1],8))),c=2;c=0;u--)P7(n,(GK(u,o.c.length),Pp(o.c[u],8)));return n}function eBx(e){var t,n,r,i,a,o,s,u,c,l,f,d,h;if(o=!0,f=null,r=null,i=null,t=!1,h=tmH,c=null,a=null,(u=epm(e,s=0,tmJ,tmQ))=0&&IE(e.substr(s,2),"//")?(s+=2,u=epm(e,s,tm1,tm0),r=e.substr(s,u-s),s=u):null!=f&&(s==e.length||(GV(s,e.length),47!=e.charCodeAt(s)))&&(o=!1,-1==(u=O7(e,e_n(35),s))&&(u=e.length),r=e.substr(s,u-s),s=u);if(!n&&s0&&58==UI(l,l.length-1)&&(i=l,s=u)),s=e.j){e.a=-1,e.c=1;return}if(t=UI(e.i,e.d++),e.a=t,1==e.b){switch(t){case 92:if(r=10,e.d>=e.j)throw p7(new gX(eBJ((Mo(),eXZ))));e.a=UI(e.i,e.d++);break;case 45:(512&e.e)==512&&e.d=e.j||63!=UI(e.i,e.d))break;if(++e.d>=e.j)throw p7(new gX(eBJ((Mo(),eXX))));switch(t=UI(e.i,e.d++)){case 58:r=13;break;case 61:r=14;break;case 33:r=15;break;case 91:r=19;break;case 62:r=18;break;case 60:if(e.d>=e.j)throw p7(new gX(eBJ((Mo(),eXX))));if(61==(t=UI(e.i,e.d++)))r=16;else if(33==t)r=17;else throw p7(new gX(eBJ((Mo(),eXJ))));break;case 35:for(;e.d=e.j)throw p7(new gX(eBJ((Mo(),eXZ))));e.a=UI(e.i,e.d++);break;default:r=0}e.c=r}function eBO(e){var t,n,r,i,a,o,s,u,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;if((k=Pp(e_k(e,(eBy(),tol)),98))!=(ewf(),tbc)&&k!=tbl){for(p=(b=e.b).c.length,f=new XM((enG(p+2,eU6),ee1(eft(eft(5,p+2),(p+2)/10|0)))),m=new XM((enG(p+2,eU6),ee1(eft(eft(5,p+2),(p+2)/10|0)))),P_(f,new p2),P_(f,new p2),P_(m,new p0),P_(m,new p0),S=new p0,t=0;t=E||!ehf(v,r))&&(r=GY(t,f)),Gu(v,r),a=new Fa(OH(efu(v).a.Kc(),new c));eTk(a);)i=Pp(ZC(a),17),!e.a[i.p]&&(m=i.c.i,--e.e[m.p],0==e.e[m.p]&&Ja(e_s(p,m)));for(l=f.c.length-1;l>=0;--l)P_(t.b,(GK(l,f.c.length),Pp(f.c[l],29)));t.a.c=Je(e1R,eUp,1,0,5,1),eEj(n)}function eBL(e){var t,n,r,i,a,o,s,u,c;for(e.b=1,eBM(e),t=null,0==e.c&&94==e.a?(eBM(e),t=(eBG(),eBG(),++tyv,new WZ(4)),eLw(t,0,e1f),s=(++tyv,new WZ(4))):s=(eBG(),eBG(),++tyv,new WZ(4)),i=!0;1!=(c=e.c);){if(0==c&&93==e.a&&!i){t&&(ej0(t,s),s=t);break}if(n=e.a,r=!1,10==c)switch(n){case 100:case 68:case 119:case 87:case 115:case 83:ePR(s,eDu(n)),r=!0;break;case 105:case 73:case 99:case 67:(n=(ePR(s,eDu(n)),-1))<0&&(r=!0);break;case 112:case 80:if(!(u=ext(e,n)))throw p7(new gX(eBJ((Mo(),eJe))));ePR(s,u),r=!0;break;default:n=eCn(e)}else if(24==c&&!i){if(t&&(ej0(t,s),s=t),a=eBL(e),ej0(s,a),0!=e.c||93!=e.a)throw p7(new gX(eBJ((Mo(),eJi))));break}if(eBM(e),!r){if(0==c){if(91==n)throw p7(new gX(eBJ((Mo(),eJa))));if(93==n)throw p7(new gX(eBJ((Mo(),eJo))));if(45==n&&!i&&93!=e.a)throw p7(new gX(eBJ((Mo(),eJs))))}if(0!=e.c||45!=e.a||45==n&&i)eLw(s,n,n);else{if(eBM(e),1==(c=e.c))throw p7(new gX(eBJ((Mo(),eJn))));if(0==c&&93==e.a)eLw(s,n,n),eLw(s,45,45);else if(0==c&&93==e.a||24==c)throw p7(new gX(eBJ((Mo(),eJs))));else{if(o=e.a,0==c){if(91==o)throw p7(new gX(eBJ((Mo(),eJa))));if(93==o)throw p7(new gX(eBJ((Mo(),eJo))));if(45==o)throw p7(new gX(eBJ((Mo(),eJs))))}else 10==c&&(o=eCn(e));if(eBM(e),n>o)throw p7(new gX(eBJ((Mo(),eJl))));eLw(s,n,o)}}}i=!1}if(1==e.c)throw p7(new gX(eBJ((Mo(),eJn))));return eMS(s),eRo(s),e.b=0,eBM(e),s}function eBC(e){eMV(e.c,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#decimal"])),eMV(e.d,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#integer"])),eMV(e.e,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#boolean"])),eMV(e.f,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"EBoolean",eXP,"EBoolean:Object"])),eMV(e.i,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#byte"])),eMV(e.g,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#hexBinary"])),eMV(e.j,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"EByte",eXP,"EByte:Object"])),eMV(e.n,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"EChar",eXP,"EChar:Object"])),eMV(e.t,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#double"])),eMV(e.u,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"EDouble",eXP,"EDouble:Object"])),eMV(e.F,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#float"])),eMV(e.G,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"EFloat",eXP,"EFloat:Object"])),eMV(e.I,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#int"])),eMV(e.J,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"EInt",eXP,"EInt:Object"])),eMV(e.N,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#long"])),eMV(e.O,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"ELong",eXP,"ELong:Object"])),eMV(e.Z,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#short"])),eMV(e.$,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"EShort",eXP,"EShort:Object"])),eMV(e._,eJ7,eow(vx(e17,1),eUP,2,6,[eQd,"http://www.w3.org/2001/XMLSchema#string"]))}function eBI(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O;if(1==e.c.length)return GK(0,e.c.length),Pp(e.c[0],135);if(e.c.length<=0)return new Xn;for(u=new fz(e);u.af&&(M=0,O+=l+S,l=0),eOd(_,o,M,O),t=eB4.Math.max(t,M+E.a),l=eB4.Math.max(l,E.b),M+=E.a+S;for(w=new p2,n=new p2,x=new fz(e);x.aeMg(a))&&(f=a);for(f||(f=(GK(0,m.c.length),Pp(m.c[0],180))),b=new fz(t.b);b.a=-1900?1:0,n>=4?xM(e,eow(vx(e17,1),eUP,2,6,[eHM,eHO])[s]):xM(e,eow(vx(e17,1),eUP,2,6,["BC","AD"])[s]);break;case 121:epA(e,n,r);break;case 77:eIZ(e,n,r);break;case 107:0==(u=i.q.getHours())?eeE(e,24,n):eeE(e,u,n);break;case 83:eOT(e,n,i);break;case 69:l=r.q.getDay(),5==n?xM(e,eow(vx(e17,1),eUP,2,6,["S","M","T","W","T","F","S"])[l]):4==n?xM(e,eow(vx(e17,1),eUP,2,6,[eHA,eHL,eHC,eHI,eHD,eHN,eHP])[l]):xM(e,eow(vx(e17,1),eUP,2,6,["Sun","Mon","Tue","Wed","Thu","Fri","Sat"])[l]);break;case 97:i.q.getHours()>=12&&24>i.q.getHours()?xM(e,eow(vx(e17,1),eUP,2,6,["AM","PM"])[1]):xM(e,eow(vx(e17,1),eUP,2,6,["AM","PM"])[0]);break;case 104:0==(f=i.q.getHours()%12)?eeE(e,12,n):eeE(e,f,n);break;case 75:eeE(e,d=i.q.getHours()%12,n);break;case 72:eeE(e,h=i.q.getHours(),n);break;case 99:p=r.q.getDay(),5==n?xM(e,eow(vx(e17,1),eUP,2,6,["S","M","T","W","T","F","S"])[p]):4==n?xM(e,eow(vx(e17,1),eUP,2,6,[eHA,eHL,eHC,eHI,eHD,eHN,eHP])[p]):3==n?xM(e,eow(vx(e17,1),eUP,2,6,["Sun","Mon","Tue","Wed","Thu","Fri","Sat"])[p]):eeE(e,p,1);break;case 76:b=r.q.getMonth(),5==n?xM(e,eow(vx(e17,1),eUP,2,6,["J","F","M","A","M","J","J","A","S","O","N","D"])[b]):4==n?xM(e,eow(vx(e17,1),eUP,2,6,[eHh,eHp,eHb,eHm,eHg,eHv,eHy,eHw,eH_,eHE,eHS,eHk])[b]):3==n?xM(e,eow(vx(e17,1),eUP,2,6,["Jan","Feb","Mar","Apr",eHg,"Jun","Jul","Aug","Sep","Oct","Nov","Dec"])[b]):eeE(e,b+1,n);break;case 81:m=r.q.getMonth()/3|0,n<4?xM(e,eow(vx(e17,1),eUP,2,6,["Q1","Q2","Q3","Q4"])[m]):xM(e,eow(vx(e17,1),eUP,2,6,["1st quarter","2nd quarter","3rd quarter","4th quarter"])[m]);break;case 100:eeE(e,g=r.q.getDate(),n);break;case 109:eeE(e,c=i.q.getMinutes(),n);break;case 115:eeE(e,o=i.q.getSeconds(),n);break;case 122:n<4?xM(e,a.c[0]):xM(e,a.c[1]);break;case 118:xM(e,a.b);break;case 90:n<3?xM(e,ekA(a)):3==n?xM(e,ek$(a)):xM(e,ekz(a.a));break;default:return!1}return!0}function eBF(e,t,n,r){var i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;if(eIi(t),u=Pp(etj((t.b||(t.b=new Ih(e6m,t,4,7)),t.b),0),82),l=Pp(etj((t.c||(t.c=new Ih(e6m,t,5,8)),t.c),0),82),s=ewH(u),c=ewH(l),o=0==(t.a||(t.a=new FQ(e6v,t,6,6)),t.a).i?null:Pp(etj((t.a||(t.a=new FQ(e6v,t,6,6)),t.a),0),202),S=Pp(Bp(e.a,s),10),M=Pp(Bp(e.a,c),10),k=null,O=null,M4(u,186)&&(M4(E=Pp(Bp(e.a,u),299),11)?k=Pp(E,11):M4(E,10)&&(S=Pp(E,10),k=Pp(RJ(S.j,0),11))),M4(l,186)&&(M4(T=Pp(Bp(e.a,l),299),11)?O=Pp(T,11):M4(T,10)&&(M=Pp(T,10),O=Pp(RJ(M.j,0),11))),!S||!M)throw p7(new gZ("The source or the target of edge "+t+" could not be found. This usually happens when an edge connects a node laid out by ELK Layered to a node in another level of hierarchy laid out by either another instance of ELK Layered or another layout algorithm alltogether. The former can be solved by setting the hierarchyHandling option to INCLUDE_CHILDREN."));for(b=new $b,eaW(b,t),eo3(b,(eBU(),tnc),t),eo3(b,(eBy(),taR),null),h=Pp(e_k(r,tt3),21),S==M&&h.Fc((eLR(),ttT)),k||(_=(enY(),tsN),x=null,o&&TM(Pp(e_k(S,tol),98))&&(V2(x=new kl(o.j,o.k),zF(t)),qZ(x,n),etg(c,s)&&(_=tsD,C5(x,S.n))),k=ePH(S,x,_,r)),O||(_=(enY(),tsD),A=null,o&&TM(Pp(e_k(M,tol),98))&&(V2(A=new kl(o.b,o.c),zF(t)),qZ(A,n)),O=ePH(M,A,_,Bq(M))),Gs(b,k),Go(b,O),(k.e.c.length>1||k.g.c.length>1||O.e.c.length>1||O.g.c.length>1)&&h.Fc((eLR(),tt_)),d=new Ow((t.n||(t.n=new FQ(e6S,t,1,7)),t.n));d.e!=d.i.gc();)if(f=Pp(epH(d),137),!gN(LK(eT8(f,ta8)))&&f.a)switch(m=eca(f),P_(b.b,m),Pp(e_k(m,tab),272).g){case 1:case 2:h.Fc((eLR(),tty));break;case 0:h.Fc((eLR(),ttg)),eo3(m,tab,(etT(),tp_))}if(a=Pp(e_k(r,tas),314),g=Pp(e_k(r,ta3),315),i=a==(en7(),teR)||g==(ebG(),tsd),o&&0!=(o.a||(o.a=new O_(e6h,o,5)),o.a).i&&i){for(v=eEF(o),p=new mE,w=epL(v,0);w.b!=w.d.c;)y=Pp(Vv(w),8),P7(p,new TS(y));eo3(b,tnl,p)}return b}function eBY(e){e.gb||(e.gb=!0,e.b=eak(e,0),er6(e.b,18),er9(e.b,19),e.a=eak(e,1),er6(e.a,1),er9(e.a,2),er9(e.a,3),er9(e.a,4),er9(e.a,5),e.o=eak(e,2),er6(e.o,8),er6(e.o,9),er9(e.o,10),er9(e.o,11),er9(e.o,12),er9(e.o,13),er9(e.o,14),er9(e.o,15),er9(e.o,16),er9(e.o,17),er9(e.o,18),er9(e.o,19),er9(e.o,20),er9(e.o,21),er9(e.o,22),er9(e.o,23),ee9(e.o),ee9(e.o),ee9(e.o),ee9(e.o),ee9(e.o),ee9(e.o),ee9(e.o),ee9(e.o),ee9(e.o),ee9(e.o),e.p=eak(e,3),er6(e.p,2),er6(e.p,3),er6(e.p,4),er6(e.p,5),er9(e.p,6),er9(e.p,7),ee9(e.p),ee9(e.p),e.q=eak(e,4),er6(e.q,8),e.v=eak(e,5),er9(e.v,9),ee9(e.v),ee9(e.v),ee9(e.v),e.w=eak(e,6),er6(e.w,2),er6(e.w,3),er6(e.w,4),er9(e.w,5),e.B=eak(e,7),er9(e.B,1),ee9(e.B),ee9(e.B),ee9(e.B),e.Q=eak(e,8),er9(e.Q,0),ee9(e.Q),e.R=eak(e,9),er6(e.R,1),e.S=eak(e,10),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),ee9(e.S),e.T=eak(e,11),er9(e.T,10),er9(e.T,11),er9(e.T,12),er9(e.T,13),er9(e.T,14),ee9(e.T),ee9(e.T),e.U=eak(e,12),er6(e.U,2),er6(e.U,3),er9(e.U,4),er9(e.U,5),er9(e.U,6),er9(e.U,7),ee9(e.U),e.V=eak(e,13),er9(e.V,10),e.W=eak(e,14),er6(e.W,18),er6(e.W,19),er6(e.W,20),er9(e.W,21),er9(e.W,22),er9(e.W,23),e.bb=eak(e,15),er6(e.bb,10),er6(e.bb,11),er6(e.bb,12),er6(e.bb,13),er6(e.bb,14),er6(e.bb,15),er6(e.bb,16),er9(e.bb,17),ee9(e.bb),ee9(e.bb),e.eb=eak(e,16),er6(e.eb,2),er6(e.eb,3),er6(e.eb,4),er6(e.eb,5),er6(e.eb,6),er6(e.eb,7),er9(e.eb,8),er9(e.eb,9),e.ab=eak(e,17),er6(e.ab,0),er6(e.ab,1),e.H=eak(e,18),er9(e.H,0),er9(e.H,1),er9(e.H,2),er9(e.H,3),er9(e.H,4),er9(e.H,5),ee9(e.H),e.db=eak(e,19),er9(e.db,2),e.c=eax(e,20),e.d=eax(e,21),e.e=eax(e,22),e.f=eax(e,23),e.i=eax(e,24),e.g=eax(e,25),e.j=eax(e,26),e.k=eax(e,27),e.n=eax(e,28),e.r=eax(e,29),e.s=eax(e,30),e.t=eax(e,31),e.u=eax(e,32),e.fb=eax(e,33),e.A=eax(e,34),e.C=eax(e,35),e.D=eax(e,36),e.F=eax(e,37),e.G=eax(e,38),e.I=eax(e,39),e.J=eax(e,40),e.L=eax(e,41),e.M=eax(e,42),e.N=eax(e,43),e.O=eax(e,44),e.P=eax(e,45),e.X=eax(e,46),e.Y=eax(e,47),e.Z=eax(e,48),e.$=eax(e,49),e._=eax(e,50),e.cb=eax(e,51),e.K=eax(e,52))}function eBB(){var e,t;eBB=A,tdQ=new pO(eZi),th6=new pO(eZa),td0=(ebx(),tdM),td1=new xX(eVi,td0),new pQ,td2=new xX(ezG,null),td3=new pO(eZo),td8=(eyY(),jL(tdX,eow(vx(e54,1),eU4,291,0,[tdK]))),td9=new xX(eVg,td8),td7=new xX(eVr,(OQ(),!1)),tht=(ec3(),tpv),the=new xX(eVu,tht),tho=(efE(),tpO),tha=new xX(eKB,tho),thc=new xX(eqC,!1),thf=(eck(),tpG),thl=new xX(eKP,thf),thP=new T3(12),thN=new xX(ezW,thP),thb=new xX(eGu,!1),thm=new xX(eVA,!1),thD=new xX(eGf,!1),thq=(ewf(),tbl),thV=new xX(eGc,thq),th3=new pO(eVT),th4=new pO(eGr),th5=new pO(eGo),th8=new pO(eGs),thv=new mE,thg=new xX(eVv,thv),td6=new xX(eV_,!1),thd=new xX(eVE,!1),new pO(eZs),thw=new mh,thy=new xX(eVM,thw),thI=new xX(eVt,!1),new pQ,th9=new xX(eZu,1),new xX(eZc,!0),ell(0),new xX(eZl,ell(100)),new xX(eZf,!1),ell(0),new xX(eZd,ell(4e3)),ell(0),new xX(eZh,ell(400)),new xX(eZp,!1),new xX(eZb,!1),new xX(eZm,!0),new xX(eZg,!1),td5=(edM(),tme),td4=new xX(eZr,td5),th7=new xX(eKQ,10),tpe=new xX(eK1,10),tpt=new xX(ez$,20),tpn=new xX(eK0,10),tpr=new xX(eGa,2),tpi=new xX(eK2,10),tpo=new xX(eK3,0),tps=new xX(eK6,5),tpu=new xX(eK4,1),tpc=new xX(eK5,1),tpl=new xX(eGi,20),tpf=new xX(eK9,10),tpp=new xX(eK8,10),tpa=new pO(eK7),tph=new T_,tpd=new xX(eVO,tph),thF=new pO(eVx),thj=!1,thR=new xX(eVk,thj),thE=new T3(5),th_=new xX(eVc,thE),thk=(eT7(),t=Pp(yw(e6t),9),new I1(t,Pp(CY(t,t.length),9),0)),thS=new xX(eGp,thk),thU=(epT(),tbt),thB=new xX(eVd,thU),th$=new pO(eVh),thz=new pO(eVp),thG=new pO(eVb),thH=new pO(eVm),thT=(e=Pp(yw(e6o),9),new I1(e,Pp(CY(e,e.length),9),0)),thx=new xX(eGh,thT),thC=el9((eI3(),tbQ)),thL=new xX(eGd,thC),thA=new kl(0,0),thO=new xX(eGM,thA),thM=new xX(eVs,!1),thi=(etT(),tp_),thr=new xX(eVy,thi),thn=new xX(eGl,!1),new pO(eZv),ell(1),new xX(eZy,null),thW=new pO(eVS),thZ=new pO(eVw),th2=(eYu(),tbF),th0=new xX(eVn,th2),thK=new pO(eVe),thQ=(ekU(),el9(tbm)),thJ=new xX(eGb,thQ),thX=new xX(eVl,!1),th1=new xX(eVf,!0),thh=new xX(eVa,!1),thp=new xX(eVo,!1),ths=new xX(ezz,1),thu=(e_a(),tpN),new xX(eZw,thu),thY=!0}function eBU(){var e,t;eBU=A,tnc=new pO(eGm),ttz=new pO("coordinateOrigin"),tny=new pO("processors"),tt$=new Cm("compoundNode",(OQ(),!1)),tt6=new Cm("insideConnections",!1),tnl=new pO("originalBendpoints"),tnf=new pO("originalDummyNodePosition"),tnd=new pO("originalLabelEdge"),tn_=new pO("representedLabels"),ttq=new pO("endLabels"),ttZ=new pO("endLabel.origin"),tnt=new Cm("labelSide",(egF(),tpX)),tns=new Cm("maxEdgeThickness",0),tnE=new Cm("reversed",!1),tnw=new pO(eGg),tni=new Cm("longEdgeSource",null),tna=new Cm("longEdgeTarget",null),tnr=new Cm("longEdgeHasLabelDummies",!1),tnn=new Cm("longEdgeBeforeLabelDummy",!1),ttV=new Cm("edgeConstraint",(eoG(),te1)),tt8=new pO("inLayerLayoutUnit"),tt9=new Cm("inLayerConstraint",(Q1(),ttD)),tt7=new Cm("inLayerSuccessorConstraint",new p0),tne=new Cm("inLayerSuccessorConstraintBetweenNonDummies",!1),tng=new pO("portDummy"),ttG=new Cm("crossingHint",ell(0)),tt3=new Cm("graphProperties",(t=Pp(yw(e44),9),new I1(t,Pp(CY(t,t.length),9),0))),tt1=new Cm("externalPortSide",(eYu(),tbF)),tt0=new Cm("externalPortSize",new yb),ttJ=new pO("externalPortReplacedDummies"),ttQ=new pO("externalPortReplacedDummy"),ttX=new Cm("externalPortConnections",(e=Pp(yw(e6a),9),new I1(e,Pp(CY(e,e.length),9),0))),tnv=new Cm(ezf,0),ttY=new pO("barycenterAssociates"),tnI=new pO("TopSideComments"),ttB=new pO("BottomSideComments"),ttH=new pO("CommentConnectionPort"),tt5=new Cm("inputCollect",!1),tnb=new Cm("outputCollect",!1),ttK=new Cm("cyclic",!1),ttW=new pO("crossHierarchyMap"),tnC=new pO("targetOffset"),new Cm("splineLabelSize",new yb),tnx=new pO("spacings"),tnm=new Cm("partitionConstraint",!1),ttU=new pO("breakingPoint.info"),tnA=new pO("splines.survivingEdge"),tnO=new pO("splines.route.start"),tnT=new pO("splines.edgeChain"),tnp=new pO("originalPortConstraints"),tnk=new pO("selfLoopHolder"),tnM=new pO("splines.nsPortY"),tnu=new pO("modelOrder"),tno=new pO("longEdgeTargetNode"),tt2=new Cm(eW_,!1),tnS=new Cm(eW_,!1),tt4=new pO("layerConstraints.hiddenNodes"),tnh=new pO("layerConstraints.opposidePort"),tnL=new pO("targetNode.modelOrder")}function eBH(){eBH=A,trl=(eeF(),teZ),trc=new xX(eWE,trl),trO=new xX(eWS,(OQ(),!1)),trN=(K6(),ttR),trD=new xX(eWk,trN),trJ=new xX(eWx,!1),trQ=new xX(eWT,!0),tnY=new xX(eWM,!1),tic=(Q0(),tsL),tiu=new xX(eWO,tic),ell(1),tig=new xX(eWA,ell(7)),tiv=new xX(eWL,!1),trA=new xX(eWC,!1),tru=(eb6(),teG),trs=new xX(eWI,tru),trX=(ewY(),to7),trZ=new xX(eWD,trX),trU=(ef_(),tnj),trB=new xX(eWN,trU),ell(-1),trY=new xX(eWP,ell(-1)),ell(-1),trH=new xX(eWR,ell(-1)),ell(-1),tr$=new xX(eWj,ell(4)),ell(-1),trG=new xX(eWF,ell(2)),trq=(eOJ(),tsS),trV=new xX(eWY,trq),ell(0),trK=new xX(eWB,ell(0)),trj=new xX(eWU,ell(eUu)),tro=(en7(),tej),tra=new xX(eWH,tro),tn1=new xX(eW$,!1),tn7=new xX(eWz,.1),trr=new xX(eWG,!1),ell(-1),trt=new xX(eWW,ell(-1)),ell(-1),trn=new xX(eWK,ell(-1)),ell(0),tn0=new xX(eWV,ell(40)),tn9=(eaU(),ttL),tn6=new xX(eWq,tn9),tn3=ttO,tn2=new xX(eWZ,tn3),tis=(ebG(),tsf),tio=new xX(eWX,tis),tr6=new pO(eWJ),tr0=(Qx(),tte),tr1=new xX(eWQ,tr0),tr4=(eyd(),tto),tr3=new xX(eW1,tr4),new pQ,tr7=new xX(eW0,.3),tit=new pO(eW2),tir=(ebk(),tsu),tin=new xX(eW3,tir),trv=(ei0(),tsF),trg=new xX(eW4,trv),tr_=(Xo(),tsH),trw=new xX(eW5,tr_),trS=(euy(),tsW),trE=new xX(eW6,trS),trx=new xX(eW9,.2),trb=new xX(eW8,2),tih=new xX(eW7,null),tib=new xX(eKe,10),tip=new xX(eKt,10),tim=new xX(eKn,20),ell(0),til=new xX(eKr,ell(0)),ell(0),tif=new xX(eKi,ell(0)),ell(0),tid=new xX(eKa,ell(0)),tnB=new xX(eKo,!1),tnz=(e_3(),ttp),tn$=new xX(eKs,tnz),tnH=(Jp(),teN),tnU=new xX(eKu,tnH),trC=new xX(eKc,!1),ell(0),trL=new xX(eKl,ell(16)),ell(0),trI=new xX(eKf,ell(5)),tiU=(eox(),tsQ),tiB=new xX(eKd,tiU),tiy=new xX(eKh,10),tiE=new xX(eKp,1),tiC=(enB(),teH),tiL=new xX(eKb,tiC),tix=new pO(eKm),tiO=ell(1),ell(0),tiM=new xX(eKg,tiO),tiW=(eiO(),tsV),tiG=new xX(eKv,tiW),tiH=new pO(eKy),tiR=new xX(eKw,!0),tiN=new xX(eK_,2),tiF=new xX(eKE,!0),trp=(eEf(),te9),trh=new xX(eKS,trp),trd=(eSg(),teO),trf=new xX(eKk,trd),tnQ=(esn(),tsM),tnJ=new xX(eKx,tnQ),tnX=new xX(eKT,!1),tnW=(ec4(),e8x),tnG=new xX(eKM,tnW),tnZ=(euJ(),tsn),tnq=new xX(eKO,tnZ),tnK=new xX(eKA,0),tnV=new xX(eKL,0),trR=teK,trP=teR,trz=to8,trW=to8,trF=to5,tre=(eck(),tpz),tri=tej,tn8=tej,tn4=tej,tn5=tpz,tr9=tsp,tr8=tsf,tr2=tsf,tr5=tsf,tie=tsh,tia=tsp,tii=tsp,trk=(efE(),tpM),trT=tpM,trM=tsW,trm=tpT,tiw=ts1,ti_=tsJ,tiS=ts1,tik=tsJ,tiI=ts1,tiD=tsJ,tiT=teU,tiA=teH,tiK=ts1,tiV=tsJ,ti$=ts1,tiz=tsJ,tij=tsJ,tiP=tsJ,tiY=tsJ}function eB$(){eB$=A,e85=new Eq("DIRECTION_PREPROCESSOR",0),e82=new Eq("COMMENT_PREPROCESSOR",1),e86=new Eq("EDGE_AND_LAYER_CONSTRAINT_EDGE_REVERSER",2),e7d=new Eq("INTERACTIVE_EXTERNAL_PORT_POSITIONER",3),e7C=new Eq("PARTITION_PREPROCESSOR",4),e7m=new Eq("LABEL_DUMMY_INSERTER",5),e7j=new Eq("SELF_LOOP_PREPROCESSOR",6),e7_=new Eq("LAYER_CONSTRAINT_PREPROCESSOR",7),e7A=new Eq("PARTITION_MIDPROCESSOR",8),e7s=new Eq("HIGH_DEGREE_NODE_LAYER_PROCESSOR",9),e7x=new Eq("NODE_PROMOTION",10),e7w=new Eq("LAYER_CONSTRAINT_POSTPROCESSOR",11),e7L=new Eq("PARTITION_POSTPROCESSOR",12),e7r=new Eq("HIERARCHICAL_PORT_CONSTRAINT_PROCESSOR",13),e7Y=new Eq("SEMI_INTERACTIVE_CROSSMIN_PROCESSOR",14),e8Z=new Eq("BREAKING_POINT_INSERTER",15),e7k=new Eq("LONG_EDGE_SPLITTER",16),e7D=new Eq("PORT_SIDE_PROCESSOR",17),e7h=new Eq("INVERTED_PORT_PROCESSOR",18),e7I=new Eq("PORT_LIST_SORTER",19),e7U=new Eq("SORT_BY_INPUT_ORDER_OF_MODEL",20),e7M=new Eq("NORTH_SOUTH_PORT_PREPROCESSOR",21),e8X=new Eq("BREAKING_POINT_PROCESSOR",22),e7O=new Eq(eG7,23),e7H=new Eq(eWe,24),e7P=new Eq("SELF_LOOP_PORT_RESTORER",25),e7B=new Eq("SINGLE_EDGE_GRAPH_WRAPPER",26),e7p=new Eq("IN_LAYER_CONSTRAINT_PROCESSOR",27),e7e=new Eq("END_NODE_PORT_LABEL_MANAGEMENT_PROCESSOR",28),e7b=new Eq("LABEL_AND_NODE_SIZE_PROCESSOR",29),e7f=new Eq("INNERMOST_NODE_MARGIN_CALCULATOR",30),e7F=new Eq("SELF_LOOP_ROUTER",31),e81=new Eq("COMMENT_NODE_MARGIN_CALCULATOR",32),e88=new Eq("END_LABEL_PREPROCESSOR",33),e7v=new Eq("LABEL_DUMMY_SWITCHER",34),e8Q=new Eq("CENTER_LABEL_MANAGEMENT_PROCESSOR",35),e7y=new Eq("LABEL_SIDE_SELECTOR",36),e7c=new Eq("HYPEREDGE_DUMMY_MERGER",37),e7i=new Eq("HIERARCHICAL_PORT_DUMMY_SIZE_PROCESSOR",38),e7E=new Eq("LAYER_SIZE_AND_GRAPH_HEIGHT_CALCULATOR",39),e7o=new Eq("HIERARCHICAL_PORT_POSITION_PROCESSOR",40),e83=new Eq("CONSTRAINTS_POSTPROCESSOR",41),e80=new Eq("COMMENT_POSTPROCESSOR",42),e7l=new Eq("HYPERNODE_PROCESSOR",43),e7a=new Eq("HIERARCHICAL_PORT_ORTHOGONAL_EDGE_ROUTER",44),e7S=new Eq("LONG_EDGE_JOINER",45),e7R=new Eq("SELF_LOOP_POSTPROCESSOR",46),e8J=new Eq("BREAKING_POINT_REMOVER",47),e7T=new Eq("NORTH_SOUTH_PORT_POSTPROCESSOR",48),e7u=new Eq("HORIZONTAL_COMPACTOR",49),e7g=new Eq("LABEL_DUMMY_REMOVER",50),e7t=new Eq("FINAL_SPLINE_BENDPOINTS_CALCULATOR",51),e87=new Eq("END_LABEL_SORTER",52),e7N=new Eq("REVERSED_EDGE_RESTORER",53),e89=new Eq("END_LABEL_POSTPROCESSOR",54),e7n=new Eq("HIERARCHICAL_NODE_RESIZER",55),e84=new Eq("DIRECTION_POSTPROCESSOR",56)}function eBz(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A,L,C,I,D,N,P,R,j,F,Y,B,U,H,$,z,G,W,K,V,q,Z,X,J,Q,ee,et,en,er,ei,ea,eo;for(I=0,X=0,P=(A=t).length;I0&&(e.a[H.p]=X++)}for(D=0,en=0,R=(L=n).length;D0;){for(H=(A6(W.b>0),Pp(W.a.Xb(W.c=--W.b),11)),G=0,s=new fz(H.e);s.a0&&(H.j==(eYu(),tbw)?(e.a[H.p]=en,++en):(e.a[H.p]=en+j+Y,++Y))}en+=Y}for(C=0,z=new p2,p=new Tw,N=(O=t).length;Cc.b&&(c.b=K)):H.i.c==Z&&(Kc.c&&(c.c=K));for(Qe(b,0,b.length,null),et=Je(ty_,eHT,25,b.length,15,1),r=Je(ty_,eHT,25,en+1,15,1),g=0;g0;)S%2>0&&(i+=ea[S+1]),S=(S-1)/2|0,++ea[S];for(w=0,x=Je(e5g,eUp,362,2*b.length,0,1);w'?":IE(eXJ,e)?"'(?<' or '(? toIndex: ",e$M=", toIndex: ",e$O="Index: ",e$A=", Size: ",e$L="org.eclipse.elk.alg.common",e$C={62:1},e$I="org.eclipse.elk.alg.common.compaction",e$D="Scanline/EventHandler",e$N="org.eclipse.elk.alg.common.compaction.oned",e$P="CNode belongs to another CGroup.",e$R="ISpacingsHandler/1",e$j="The ",e$F=" instance has been finished already.",e$Y="The direction ",e$B=" is not supported by the CGraph instance.",e$U="OneDimensionalCompactor",e$H="OneDimensionalCompactor/lambda$0$Type",e$$="Quadruplet",e$z="ScanlineConstraintCalculator",e$G="ScanlineConstraintCalculator/ConstraintsScanlineHandler",e$W="ScanlineConstraintCalculator/ConstraintsScanlineHandler/lambda$0$Type",e$K="ScanlineConstraintCalculator/Timestamp",e$V="ScanlineConstraintCalculator/lambda$0$Type",e$q={169:1,45:1},e$Z="org.eclipse.elk.alg.common.compaction.options",e$X="org.eclipse.elk.core.data",e$J="org.eclipse.elk.polyomino.traversalStrategy",e$Q="org.eclipse.elk.polyomino.lowLevelSort",e$1="org.eclipse.elk.polyomino.highLevelSort",e$0="org.eclipse.elk.polyomino.fill",e$2={130:1},e$3="polyomino",e$4="org.eclipse.elk.alg.common.networksimplex",e$5={177:1,3:1,4:1},e$6="org.eclipse.elk.alg.common.nodespacing",e$9="org.eclipse.elk.alg.common.nodespacing.cellsystem",e$8="CENTER",e$7={212:1,326:1},eze={3:1,4:1,5:1,595:1},ezt="LEFT",ezn="RIGHT",ezr="Vertical alignment cannot be null",ezi="BOTTOM",eza="org.eclipse.elk.alg.common.nodespacing.internal",ezo="UNDEFINED",ezs=.01,ezu="org.eclipse.elk.alg.common.nodespacing.internal.algorithm",ezc="LabelPlacer/lambda$0$Type",ezl="LabelPlacer/lambda$1$Type",ezf="portRatioOrPosition",ezd="org.eclipse.elk.alg.common.overlaps",ezh="DOWN",ezp="org.eclipse.elk.alg.common.polyomino",ezb="NORTH",ezm="EAST",ezg="SOUTH",ezv="WEST",ezy="org.eclipse.elk.alg.common.polyomino.structures",ezw="Direction",ez_="Grid is only of size ",ezE=". Requested point (",ezS=") is out of bounds.",ezk=" Given center based coordinates were (",ezx="org.eclipse.elk.graph.properties",ezT="IPropertyHolder",ezM={3:1,94:1,134:1},ezO="org.eclipse.elk.alg.common.spore",ezA="org.eclipse.elk.alg.common.utils",ezL={209:1},ezC="org.eclipse.elk.core",ezI="Connected Components Compaction",ezD="org.eclipse.elk.alg.disco",ezN="org.eclipse.elk.alg.disco.graph",ezP="org.eclipse.elk.alg.disco.options",ezR="CompactionStrategy",ezj="org.eclipse.elk.disco.componentCompaction.strategy",ezF="org.eclipse.elk.disco.componentCompaction.componentLayoutAlgorithm",ezY="org.eclipse.elk.disco.debug.discoGraph",ezB="org.eclipse.elk.disco.debug.discoPolys",ezU="componentCompaction",ezH="org.eclipse.elk.disco",ez$="org.eclipse.elk.spacing.componentComponent",ezz="org.eclipse.elk.edge.thickness",ezG="org.eclipse.elk.aspectRatio",ezW="org.eclipse.elk.padding",ezK="org.eclipse.elk.alg.disco.transform",ezV=1.5707963267948966,ezq=17976931348623157e292,ezZ={3:1,4:1,5:1,192:1},ezX={3:1,6:1,4:1,5:1,106:1,120:1},ezJ="org.eclipse.elk.alg.force",ezQ="ComponentsProcessor",ez1="ComponentsProcessor/1",ez0="org.eclipse.elk.alg.force.graph",ez2="Component Layout",ez3="org.eclipse.elk.alg.force.model",ez4="org.eclipse.elk.force.model",ez5="org.eclipse.elk.force.iterations",ez6="org.eclipse.elk.force.repulsivePower",ez9="org.eclipse.elk.force.temperature",ez8=.001,ez7="org.eclipse.elk.force.repulsion",eGe="org.eclipse.elk.alg.force.options",eGt=1.600000023841858,eGn="org.eclipse.elk.force",eGr="org.eclipse.elk.priority",eGi="org.eclipse.elk.spacing.nodeNode",eGa="org.eclipse.elk.spacing.edgeLabel",eGo="org.eclipse.elk.randomSeed",eGs="org.eclipse.elk.separateConnectedComponents",eGu="org.eclipse.elk.interactive",eGc="org.eclipse.elk.portConstraints",eGl="org.eclipse.elk.edgeLabels.inline",eGf="org.eclipse.elk.omitNodeMicroLayout",eGd="org.eclipse.elk.nodeSize.options",eGh="org.eclipse.elk.nodeSize.constraints",eGp="org.eclipse.elk.nodeLabels.placement",eGb="org.eclipse.elk.portLabels.placement",eGm="origin",eGg="random",eGv="boundingBox.upLeft",eGy="boundingBox.lowRight",eGw="org.eclipse.elk.stress.fixed",eG_="org.eclipse.elk.stress.desiredEdgeLength",eGE="org.eclipse.elk.stress.dimension",eGS="org.eclipse.elk.stress.epsilon",eGk="org.eclipse.elk.stress.iterationLimit",eGx="org.eclipse.elk.stress",eGT="ELK Stress",eGM="org.eclipse.elk.nodeSize.minimum",eGO="org.eclipse.elk.alg.force.stress",eGA="Layered layout",eGL="org.eclipse.elk.alg.layered",eGC="org.eclipse.elk.alg.layered.compaction.components",eGI="org.eclipse.elk.alg.layered.compaction.oned",eGD="org.eclipse.elk.alg.layered.compaction.oned.algs",eGN="org.eclipse.elk.alg.layered.compaction.recthull",eGP="org.eclipse.elk.alg.layered.components",eGR="NONE",eGj={3:1,6:1,4:1,9:1,5:1,122:1},eGF={3:1,6:1,4:1,5:1,141:1,106:1,120:1},eGY="org.eclipse.elk.alg.layered.compound",eGB={51:1},eGU="org.eclipse.elk.alg.layered.graph",eGH=" -> ",eG$="Not supported by LGraph",eGz="Port side is undefined",eGG={3:1,6:1,4:1,5:1,474:1,141:1,106:1,120:1},eGW={3:1,6:1,4:1,5:1,141:1,193:1,203:1,106:1,120:1},eGK={3:1,6:1,4:1,5:1,141:1,1943:1,203:1,106:1,120:1},eGV="([{\"' \r\n",eGq=")]}\"' \r\n",eGZ="The given string contains parts that cannot be parsed as numbers.",eGX="org.eclipse.elk.core.math",eGJ={3:1,4:1,142:1,207:1,414:1},eGQ={3:1,4:1,116:1,207:1,414:1},eG1="org.eclipse.elk.layered",eG0="org.eclipse.elk.alg.layered.graph.transform",eG2="ElkGraphImporter",eG3="ElkGraphImporter/lambda$0$Type",eG4="ElkGraphImporter/lambda$1$Type",eG5="ElkGraphImporter/lambda$2$Type",eG6="ElkGraphImporter/lambda$4$Type",eG9="Node margin calculation",eG8="org.eclipse.elk.alg.layered.intermediate",eG7="ONE_SIDED_GREEDY_SWITCH",eWe="TWO_SIDED_GREEDY_SWITCH",eWt="No implementation is available for the layout processor ",eWn="IntermediateProcessorStrategy",eWr="Node '",eWi="FIRST_SEPARATE",eWa="LAST_SEPARATE",eWo="Odd port side processing",eWs="org.eclipse.elk.alg.layered.intermediate.compaction",eWu="org.eclipse.elk.alg.layered.intermediate.greedyswitch",eWc="org.eclipse.elk.alg.layered.p3order.counting",eWl={225:1},eWf="org.eclipse.elk.alg.layered.intermediate.loops",eWd="org.eclipse.elk.alg.layered.intermediate.loops.ordering",eWh="org.eclipse.elk.alg.layered.intermediate.loops.routing",eWp="org.eclipse.elk.alg.layered.intermediate.preserveorder",eWb="org.eclipse.elk.alg.layered.intermediate.wrapping",eWm="org.eclipse.elk.alg.layered.options",eWg="INTERACTIVE",eWv="DEPTH_FIRST",eWy="EDGE_LENGTH",eWw="SELF_LOOPS",eW_="firstTryWithInitialOrder",eWE="org.eclipse.elk.layered.directionCongruency",eWS="org.eclipse.elk.layered.feedbackEdges",eWk="org.eclipse.elk.layered.interactiveReferencePoint",eWx="org.eclipse.elk.layered.mergeEdges",eWT="org.eclipse.elk.layered.mergeHierarchyEdges",eWM="org.eclipse.elk.layered.allowNonFlowPortsToSwitchSides",eWO="org.eclipse.elk.layered.portSortingStrategy",eWA="org.eclipse.elk.layered.thoroughness",eWL="org.eclipse.elk.layered.unnecessaryBendpoints",eWC="org.eclipse.elk.layered.generatePositionAndLayerIds",eWI="org.eclipse.elk.layered.cycleBreaking.strategy",eWD="org.eclipse.elk.layered.layering.strategy",eWN="org.eclipse.elk.layered.layering.layerConstraint",eWP="org.eclipse.elk.layered.layering.layerChoiceConstraint",eWR="org.eclipse.elk.layered.layering.layerId",eWj="org.eclipse.elk.layered.layering.minWidth.upperBoundOnWidth",eWF="org.eclipse.elk.layered.layering.minWidth.upperLayerEstimationScalingFactor",eWY="org.eclipse.elk.layered.layering.nodePromotion.strategy",eWB="org.eclipse.elk.layered.layering.nodePromotion.maxIterations",eWU="org.eclipse.elk.layered.layering.coffmanGraham.layerBound",eWH="org.eclipse.elk.layered.crossingMinimization.strategy",eW$="org.eclipse.elk.layered.crossingMinimization.forceNodeModelOrder",eWz="org.eclipse.elk.layered.crossingMinimization.hierarchicalSweepiness",eWG="org.eclipse.elk.layered.crossingMinimization.semiInteractive",eWW="org.eclipse.elk.layered.crossingMinimization.positionChoiceConstraint",eWK="org.eclipse.elk.layered.crossingMinimization.positionId",eWV="org.eclipse.elk.layered.crossingMinimization.greedySwitch.activationThreshold",eWq="org.eclipse.elk.layered.crossingMinimization.greedySwitch.type",eWZ="org.eclipse.elk.layered.crossingMinimization.greedySwitchHierarchical.type",eWX="org.eclipse.elk.layered.nodePlacement.strategy",eWJ="org.eclipse.elk.layered.nodePlacement.favorStraightEdges",eWQ="org.eclipse.elk.layered.nodePlacement.bk.edgeStraightening",eW1="org.eclipse.elk.layered.nodePlacement.bk.fixedAlignment",eW0="org.eclipse.elk.layered.nodePlacement.linearSegments.deflectionDampening",eW2="org.eclipse.elk.layered.nodePlacement.networkSimplex.nodeFlexibility",eW3="org.eclipse.elk.layered.nodePlacement.networkSimplex.nodeFlexibility.default",eW4="org.eclipse.elk.layered.edgeRouting.selfLoopDistribution",eW5="org.eclipse.elk.layered.edgeRouting.selfLoopOrdering",eW6="org.eclipse.elk.layered.edgeRouting.splines.mode",eW9="org.eclipse.elk.layered.edgeRouting.splines.sloppy.layerSpacingFactor",eW8="org.eclipse.elk.layered.edgeRouting.polyline.slopedEdgeZoneWidth",eW7="org.eclipse.elk.layered.spacing.baseValue",eKe="org.eclipse.elk.layered.spacing.edgeNodeBetweenLayers",eKt="org.eclipse.elk.layered.spacing.edgeEdgeBetweenLayers",eKn="org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers",eKr="org.eclipse.elk.layered.priority.direction",eKi="org.eclipse.elk.layered.priority.shortness",eKa="org.eclipse.elk.layered.priority.straightness",eKo="org.eclipse.elk.layered.compaction.connectedComponents",eKs="org.eclipse.elk.layered.compaction.postCompaction.strategy",eKu="org.eclipse.elk.layered.compaction.postCompaction.constraints",eKc="org.eclipse.elk.layered.highDegreeNodes.treatment",eKl="org.eclipse.elk.layered.highDegreeNodes.threshold",eKf="org.eclipse.elk.layered.highDegreeNodes.treeHeight",eKd="org.eclipse.elk.layered.wrapping.strategy",eKh="org.eclipse.elk.layered.wrapping.additionalEdgeSpacing",eKp="org.eclipse.elk.layered.wrapping.correctionFactor",eKb="org.eclipse.elk.layered.wrapping.cutting.strategy",eKm="org.eclipse.elk.layered.wrapping.cutting.cuts",eKg="org.eclipse.elk.layered.wrapping.cutting.msd.freedom",eKv="org.eclipse.elk.layered.wrapping.validify.strategy",eKy="org.eclipse.elk.layered.wrapping.validify.forbiddenIndices",eKw="org.eclipse.elk.layered.wrapping.multiEdge.improveCuts",eK_="org.eclipse.elk.layered.wrapping.multiEdge.distancePenalty",eKE="org.eclipse.elk.layered.wrapping.multiEdge.improveWrappedEdges",eKS="org.eclipse.elk.layered.edgeLabels.sideSelection",eKk="org.eclipse.elk.layered.edgeLabels.centerLabelPlacementStrategy",eKx="org.eclipse.elk.layered.considerModelOrder.strategy",eKT="org.eclipse.elk.layered.considerModelOrder.noModelOrder",eKM="org.eclipse.elk.layered.considerModelOrder.components",eKO="org.eclipse.elk.layered.considerModelOrder.longEdgeStrategy",eKA="org.eclipse.elk.layered.considerModelOrder.crossingCounterNodeInfluence",eKL="org.eclipse.elk.layered.considerModelOrder.crossingCounterPortInfluence",eKC="layering",eKI="layering.minWidth",eKD="layering.nodePromotion",eKN="crossingMinimization",eKP="org.eclipse.elk.hierarchyHandling",eKR="crossingMinimization.greedySwitch",eKj="nodePlacement",eKF="nodePlacement.bk",eKY="edgeRouting",eKB="org.eclipse.elk.edgeRouting",eKU="spacing",eKH="priority",eK$="compaction",eKz="compaction.postCompaction",eKG="Specifies whether and how post-process compaction is applied.",eKW="highDegreeNodes",eKK="wrapping",eKV="wrapping.cutting",eKq="wrapping.validify",eKZ="wrapping.multiEdge",eKX="edgeLabels",eKJ="considerModelOrder",eKQ="org.eclipse.elk.spacing.commentComment",eK1="org.eclipse.elk.spacing.commentNode",eK0="org.eclipse.elk.spacing.edgeEdge",eK2="org.eclipse.elk.spacing.edgeNode",eK3="org.eclipse.elk.spacing.labelLabel",eK4="org.eclipse.elk.spacing.labelPortHorizontal",eK5="org.eclipse.elk.spacing.labelPortVertical",eK6="org.eclipse.elk.spacing.labelNode",eK9="org.eclipse.elk.spacing.nodeSelfLoop",eK8="org.eclipse.elk.spacing.portPort",eK7="org.eclipse.elk.spacing.individual",eVe="org.eclipse.elk.port.borderOffset",eVt="org.eclipse.elk.noLayout",eVn="org.eclipse.elk.port.side",eVr="org.eclipse.elk.debugMode",eVi="org.eclipse.elk.alignment",eVa="org.eclipse.elk.insideSelfLoops.activate",eVo="org.eclipse.elk.insideSelfLoops.yo",eVs="org.eclipse.elk.nodeSize.fixedGraphSize",eVu="org.eclipse.elk.direction",eVc="org.eclipse.elk.nodeLabels.padding",eVl="org.eclipse.elk.portLabels.nextToPortIfPossible",eVf="org.eclipse.elk.portLabels.treatAsGroup",eVd="org.eclipse.elk.portAlignment.default",eVh="org.eclipse.elk.portAlignment.north",eVp="org.eclipse.elk.portAlignment.south",eVb="org.eclipse.elk.portAlignment.west",eVm="org.eclipse.elk.portAlignment.east",eVg="org.eclipse.elk.contentAlignment",eVv="org.eclipse.elk.junctionPoints",eVy="org.eclipse.elk.edgeLabels.placement",eVw="org.eclipse.elk.port.index",eV_="org.eclipse.elk.commentBox",eVE="org.eclipse.elk.hypernode",eVS="org.eclipse.elk.port.anchor",eVk="org.eclipse.elk.partitioning.activate",eVx="org.eclipse.elk.partitioning.partition",eVT="org.eclipse.elk.position",eVM="org.eclipse.elk.margins",eVO="org.eclipse.elk.spacing.portsSurrounding",eVA="org.eclipse.elk.interactiveLayout",eVL="org.eclipse.elk.core.util",eVC={3:1,4:1,5:1,593:1},eVI="NETWORK_SIMPLEX",eVD={123:1,51:1},eVN="org.eclipse.elk.alg.layered.p1cycles",eVP="org.eclipse.elk.alg.layered.p2layers",eVR={402:1,225:1},eVj={832:1,3:1,4:1},eVF="org.eclipse.elk.alg.layered.p3order",eVY="org.eclipse.elk.alg.layered.p4nodes",eVB={3:1,4:1,5:1,840:1},eVU=1e-5,eVH="org.eclipse.elk.alg.layered.p4nodes.bk",eV$="org.eclipse.elk.alg.layered.p5edges",eVz="org.eclipse.elk.alg.layered.p5edges.orthogonal",eVG="org.eclipse.elk.alg.layered.p5edges.orthogonal.direction",eVW=1e-6,eVK="org.eclipse.elk.alg.layered.p5edges.splines",eVV=.09999999999999998,eVq=1e-8,eVZ=4.71238898038469,eVX=3.141592653589793,eVJ="org.eclipse.elk.alg.mrtree",eVQ="org.eclipse.elk.alg.mrtree.graph",eV1="org.eclipse.elk.alg.mrtree.intermediate",eV0="Set neighbors in level",eV2="DESCENDANTS",eV3="org.eclipse.elk.mrtree.weighting",eV4="org.eclipse.elk.mrtree.searchOrder",eV5="org.eclipse.elk.alg.mrtree.options",eV6="org.eclipse.elk.mrtree",eV9="org.eclipse.elk.tree",eV8="org.eclipse.elk.alg.radial",eV7=6.283185307179586,eqe=5e-324,eqt="org.eclipse.elk.alg.radial.intermediate",eqn="org.eclipse.elk.alg.radial.intermediate.compaction",eqr={3:1,4:1,5:1,106:1},eqi="org.eclipse.elk.alg.radial.intermediate.optimization",eqa="No implementation is available for the layout option ",eqo="org.eclipse.elk.alg.radial.options",eqs="org.eclipse.elk.radial.orderId",equ="org.eclipse.elk.radial.radius",eqc="org.eclipse.elk.radial.compactor",eql="org.eclipse.elk.radial.compactionStepSize",eqf="org.eclipse.elk.radial.sorter",eqd="org.eclipse.elk.radial.wedgeCriteria",eqh="org.eclipse.elk.radial.optimizationCriteria",eqp="org.eclipse.elk.radial",eqb="org.eclipse.elk.alg.radial.p1position.wedge",eqm="org.eclipse.elk.alg.radial.sorting",eqg=5.497787143782138,eqv=3.9269908169872414,eqy=2.356194490192345,eqw="org.eclipse.elk.alg.rectpacking",eq_="org.eclipse.elk.alg.rectpacking.firstiteration",eqE="org.eclipse.elk.alg.rectpacking.options",eqS="org.eclipse.elk.rectpacking.optimizationGoal",eqk="org.eclipse.elk.rectpacking.lastPlaceShift",eqx="org.eclipse.elk.rectpacking.currentPosition",eqT="org.eclipse.elk.rectpacking.desiredPosition",eqM="org.eclipse.elk.rectpacking.onlyFirstIteration",eqO="org.eclipse.elk.rectpacking.rowCompaction",eqA="org.eclipse.elk.rectpacking.expandToAspectRatio",eqL="org.eclipse.elk.rectpacking.targetWidth",eqC="org.eclipse.elk.expandNodes",eqI="org.eclipse.elk.rectpacking",eqD="org.eclipse.elk.alg.rectpacking.util",eqN="No implementation available for ",eqP="org.eclipse.elk.alg.spore",eqR="org.eclipse.elk.alg.spore.options",eqj="org.eclipse.elk.sporeCompaction",eqF="org.eclipse.elk.underlyingLayoutAlgorithm",eqY="org.eclipse.elk.processingOrder.treeConstruction",eqB="org.eclipse.elk.processingOrder.spanningTreeCostFunction",eqU="org.eclipse.elk.processingOrder.preferredRoot",eqH="org.eclipse.elk.processingOrder.rootSelection",eq$="org.eclipse.elk.structure.structureExtractionStrategy",eqz="org.eclipse.elk.compaction.compactionStrategy",eqG="org.eclipse.elk.compaction.orthogonal",eqW="org.eclipse.elk.overlapRemoval.maxIterations",eqK="org.eclipse.elk.overlapRemoval.runScanline",eqV="processingOrder",eqq="overlapRemoval",eqZ="org.eclipse.elk.sporeOverlap",eqX="org.eclipse.elk.alg.spore.p1structure",eqJ="org.eclipse.elk.alg.spore.p2processingorder",eqQ="org.eclipse.elk.alg.spore.p3execution",eq1="Invalid index: ",eq0="org.eclipse.elk.core.alg",eq2={331:1},eq3={288:1},eq4="Make sure its type is registered with the ",eq5=" utility class.",eq6="true",eq9="false",eq8="Couldn't clone property '",eq7=.05,eZe="org.eclipse.elk.core.options",eZt=1.2999999523162842,eZn="org.eclipse.elk.box",eZr="org.eclipse.elk.box.packingMode",eZi="org.eclipse.elk.algorithm",eZa="org.eclipse.elk.resolvedAlgorithm",eZo="org.eclipse.elk.bendPoints",eZs="org.eclipse.elk.labelManager",eZu="org.eclipse.elk.scaleFactor",eZc="org.eclipse.elk.animate",eZl="org.eclipse.elk.animTimeFactor",eZf="org.eclipse.elk.layoutAncestors",eZd="org.eclipse.elk.maxAnimTime",eZh="org.eclipse.elk.minAnimTime",eZp="org.eclipse.elk.progressBar",eZb="org.eclipse.elk.validateGraph",eZm="org.eclipse.elk.validateOptions",eZg="org.eclipse.elk.zoomToFit",eZv="org.eclipse.elk.font.name",eZy="org.eclipse.elk.font.size",eZw="org.eclipse.elk.edge.type",eZ_="partitioning",eZE="nodeLabels",eZS="portAlignment",eZk="nodeSize",eZx="port",eZT="portLabels",eZM="insideSelfLoops",eZO="org.eclipse.elk.fixed",eZA="org.eclipse.elk.random",eZL="port must have a parent node to calculate the port side",eZC="The edge needs to have exactly one edge section. Found: ",eZI="org.eclipse.elk.core.util.adapters",eZD="org.eclipse.emf.ecore",eZN="org.eclipse.elk.graph",eZP="EMapPropertyHolder",eZR="ElkBendPoint",eZj="ElkGraphElement",eZF="ElkConnectableShape",eZY="ElkEdge",eZB="ElkEdgeSection",eZU="EModelElement",eZH="ENamedElement",eZ$="ElkLabel",eZz="ElkNode",eZG="ElkPort",eZW={92:1,90:1},eZK="org.eclipse.emf.common.notify.impl",eZV="The feature '",eZq="' is not a valid changeable feature",eZZ="Expecting null",eZX="' is not a valid feature",eZJ="The feature ID",eZQ=" is not a valid feature ID",eZ1=32768,eZ0={105:1,92:1,90:1,56:1,49:1,97:1},eZ2="org.eclipse.emf.ecore.impl",eZ3="org.eclipse.elk.graph.impl",eZ4="Recursive containment not allowed for ",eZ5="The datatype '",eZ6="' is not a valid classifier",eZ9="The value '",eZ8={190:1,3:1,4:1},eZ7="The class '",eXe="http://www.eclipse.org/elk/ElkGraph",eXt=1024,eXn="property",eXr="value",eXi="source",eXa="properties",eXo="identifier",eXs="height",eXu="width",eXc="parent",eXl="text",eXf="children",eXd="hierarchical",eXh="sources",eXp="targets",eXb="sections",eXm="bendPoints",eXg="outgoingShape",eXv="incomingShape",eXy="outgoingSections",eXw="incomingSections",eX_="org.eclipse.emf.common.util",eXE="Severe implementation error in the Json to ElkGraph importer.",eXS="id",eXk="org.eclipse.elk.graph.json",eXx="Unhandled parameter types: ",eXT="startPoint",eXM="An edge must have at least one source and one target (edge id: '",eXO="').",eXA="Referenced edge section does not exist: ",eXL=" (edge id: '",eXC="target",eXI="sourcePoint",eXD="targetPoint",eXN="group",eXP="name",eXR="connectableShape cannot be null",eXj="edge cannot be null",eXF="Passed edge is not 'simple'.",eXY="org.eclipse.elk.graph.util",eXB="The 'no duplicates' constraint is violated",eXU="targetIndex=",eXH=", size=",eX$="sourceIndex=",eXz={3:1,4:1,20:1,28:1,52:1,14:1,15:1,54:1,67:1,63:1,58:1},eXG={3:1,4:1,20:1,28:1,52:1,14:1,47:1,15:1,54:1,67:1,63:1,58:1,588:1},eXW="logging",eXK="measureExecutionTime",eXV="parser.parse.1",eXq="parser.parse.2",eXZ="parser.next.1",eXX="parser.next.2",eXJ="parser.next.3",eXQ="parser.next.4",eX1="parser.factor.1",eX0="parser.factor.2",eX2="parser.factor.3",eX3="parser.factor.4",eX4="parser.factor.5",eX5="parser.factor.6",eX6="parser.atom.1",eX9="parser.atom.2",eX8="parser.atom.3",eX7="parser.atom.4",eJe="parser.atom.5",eJt="parser.cc.1",eJn="parser.cc.2",eJr="parser.cc.3",eJi="parser.cc.5",eJa="parser.cc.6",eJo="parser.cc.7",eJs="parser.cc.8",eJu="parser.ope.1",eJc="parser.ope.2",eJl="parser.ope.3",eJf="parser.descape.1",eJd="parser.descape.2",eJh="parser.descape.3",eJp="parser.descape.4",eJb="parser.descape.5",eJm="parser.process.1",eJg="parser.quantifier.1",eJv="parser.quantifier.2",eJy="parser.quantifier.3",eJw="parser.quantifier.4",eJ_="parser.quantifier.5",eJE="org.eclipse.emf.common.notify",eJS={415:1,672:1},eJk={3:1,4:1,20:1,28:1,52:1,14:1,15:1,67:1,58:1},eJx={366:1,143:1},eJT="index=",eJM={3:1,4:1,5:1,126:1},eJO={3:1,4:1,20:1,28:1,52:1,14:1,15:1,54:1,67:1,58:1},eJA={3:1,6:1,4:1,5:1,192:1},eJL={3:1,4:1,5:1,165:1,367:1},eJC=";/?:@&=+$,",eJI="invalid authority: ",eJD="EAnnotation",eJN="ETypedElement",eJP="EStructuralFeature",eJR="EAttribute",eJj="EClassifier",eJF="EEnumLiteral",eJY="EGenericType",eJB="EOperation",eJU="EParameter",eJH="EReference",eJ$="ETypeParameter",eJz="org.eclipse.emf.ecore.util",eJG={76:1},eJW={3:1,20:1,14:1,15:1,58:1,589:1,76:1,69:1,95:1},eJK="org.eclipse.emf.ecore.util.FeatureMap$Entry",eJV=8192,eJq=2048,eJZ="byte",eJX="char",eJJ="double",eJQ="float",eJ1="int",eJ0="long",eJ2="short",eJ3="java.lang.Object",eJ4={3:1,4:1,5:1,247:1},eJ5={3:1,4:1,5:1,673:1},eJ6={3:1,4:1,20:1,28:1,52:1,14:1,15:1,54:1,67:1,63:1,58:1,69:1},eJ9={3:1,4:1,20:1,28:1,52:1,14:1,15:1,54:1,67:1,63:1,58:1,76:1,69:1,95:1},eJ8="mixed",eJ7="http:///org/eclipse/emf/ecore/util/ExtendedMetaData",eQe="kind",eQt={3:1,4:1,5:1,674:1},eQn={3:1,4:1,20:1,28:1,52:1,14:1,15:1,67:1,58:1,76:1,69:1,95:1},eQr={20:1,28:1,52:1,14:1,15:1,58:1,69:1},eQi={47:1,125:1,279:1},eQa={72:1,332:1},eQo="The value of type '",eQs="' must be of type '",eQu=1316,eQc="http://www.eclipse.org/emf/2002/Ecore",eQl=-32768,eQf="constraints",eQd="baseType",eQh="getEStructuralFeature",eQp="getFeatureID",eQb="feature",eQm="getOperationID",eQg="operation",eQv="defaultValue",eQy="eTypeParameters",eQw="isInstance",eQ_="getEEnumLiteral",eQE="eContainingClass",eQS={55:1},eQk={3:1,4:1,5:1,119:1},eQx="org.eclipse.emf.ecore.resource",eQT={92:1,90:1,591:1,1935:1},eQM="org.eclipse.emf.ecore.resource.impl",eQO="unspecified",eQA="simple",eQL="attribute",eQC="attributeWildcard",eQI="element",eQD="elementWildcard",eQN="collapse",eQP="itemType",eQR="namespace",eQj="##targetNamespace",eQF="whiteSpace",eQY="wildcards",eQB="http://www.eclipse.org/emf/2003/XMLType",eQU="##any",eQH="uninitialized",eQ$="The multiplicity constraint is violated",eQz="org.eclipse.emf.ecore.xml.type",eQG="ProcessingInstruction",eQW="SimpleAnyType",eQK="XMLTypeDocumentRoot",eQV="org.eclipse.emf.ecore.xml.type.impl",eQq="INF",eQZ="processing",eQX="ENTITIES_._base",eQJ="minLength",eQQ="ENTITY",eQ1="NCName",eQ0="IDREFS_._base",eQ2="integer",eQ3="token",eQ4="pattern",eQ5="[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*",eQ6="\\i\\c*",eQ9="[\\i-[:]][\\c-[:]]*",eQ8="nonPositiveInteger",eQ7="maxInclusive",e1e="NMTOKEN",e1t="NMTOKENS_._base",e1n="nonNegativeInteger",e1r="minInclusive",e1i="normalizedString",e1a="unsignedByte",e1o="unsignedInt",e1s="18446744073709551615",e1u="unsignedShort",e1c="processingInstruction",e1l="org.eclipse.emf.ecore.xml.type.internal",e1f=1114111,e1d="Internal Error: shorthands: \\u",e1h="xml:isDigit",e1p="xml:isWord",e1b="xml:isSpace",e1m="xml:isNameChar",e1g="xml:isInitialNameChar",e1v="09٠٩۰۹०९০৯੦੯૦૯୦୯௧௯౦౯೦೯൦൯๐๙໐໙༠༩",e1y="AZaz\xc0\xd6\xd8\xf6\xf8ıĴľŁňŊžƀǃǍǰǴǵǺȗɐʨʻˁΆΆΈΊΌΌΎΡΣώϐϖϚϚϜϜϞϞϠϠϢϳЁЌЎяёќўҁҐӄӇӈӋӌӐӫӮӵӸӹԱՖՙՙաֆאתװײءغفيٱڷںھۀێېۓەەۥۦअहऽऽक़ॡঅঌএঐওনপরললশহড়ঢ়য়ৡৰৱਅਊਏਐਓਨਪਰਲਲ਼ਵਸ਼ਸਹਖ਼ੜਫ਼ਫ਼ੲੴઅઋઍઍએઑઓનપરલળવહઽઽૠૠଅଌଏଐଓନପରଲଳଶହଽଽଡ଼ଢ଼ୟୡஅஊஎஐஒகஙசஜஜஞடணதநபமவஷஹఅఌఎఐఒనపళవహౠౡಅಌಎಐಒನಪಳವಹೞೞೠೡഅഌഎഐഒനപഹൠൡกฮะะาำเๅກຂຄຄງຈຊຊຍຍດທນຟມຣລລວວສຫອຮະະາຳຽຽເໄཀཇཉཀྵႠჅაჶᄀᄀᄂᄃᄅᄇᄉᄉᄋᄌᄎᄒᄼᄼᄾᄾᅀᅀᅌᅌᅎᅎᅐᅐᅔᅕᅙᅙᅟᅡᅣᅣᅥᅥᅧᅧᅩᅩᅭᅮᅲᅳᅵᅵᆞᆞᆨᆨᆫᆫᆮᆯᆷᆸᆺᆺᆼᇂᇫᇫᇰᇰᇹᇹḀẛẠỹἀἕἘἝἠὅὈὍὐὗὙὙὛὛὝὝὟώᾀᾴᾶᾼιιῂῄῆῌῐΐῖΊῠῬῲῴῶῼΩΩKÅ℮℮ↀↂ〇〇〡〩ぁゔァヺㄅㄬ一龥가힣",e1w="Private Use",e1_="ASSIGNED",e1E="\0\x7f\x80\xffĀſƀɏɐʯʰ˿̀ͯͰϿЀӿ԰֏֐׿؀ۿ܀ݏހ޿ऀॿঀ৿਀੿઀૿଀୿஀௿ఀ౿ಀ೿ഀൿ඀෿฀๿຀໿ༀ࿿က႟Ⴀჿᄀᇿሀ፿Ꭰ᏿᐀ᙿ ᚟ᚠ᛿ក៿᠀᢯Ḁỿἀ῿ ⁰₟₠⃏⃐⃿℀⅏⅐↏←⇿∀⋿⌀⏿␀␿⑀⑟①⓿─╿▀▟■◿☀⛿✀➿⠀⣿⺀⻿⼀⿟⿰⿿ 〿぀ゟ゠ヿ㄀ㄯ㄰㆏㆐㆟ㆠㆿ㈀㋿㌀㏿㐀䶵一鿿ꀀ꒏꒐꓏가힣豈﫿ffﭏﭐ﷿︠︯︰﹏﹐﹯ﹰ﻾\uFEFF\uFEFF＀￯",e1S="UNASSIGNED",e1k={3:1,117:1},e1x="org.eclipse.emf.ecore.xml.type.util",e1T={3:1,4:1,5:1,368:1},e1M="org.eclipse.xtext.xbase.lib",e1O="Cannot add elements to a Range",e1A="Cannot set elements in a Range",e1L="Cannot remove elements from a Range",e1C="locale",e1I="default",e1D="user.agent",e1N=null;eB4.goog=eB4.goog||{},eB4.goog.global=eB4.goog.global||eB4,e_Q(),eTS(1,null,{},r),eUe.Fb=function(e){return x5(this,e)},eUe.Gb=function(){return this.gm},eUe.Hb=function(){return Ao(this)},eUe.Ib=function(){var e;return yx(esF(this))+"@"+(e=esj(this)>>>0).toString(16)},eUe.equals=function(e){return this.Fb(e)},eUe.hashCode=function(){return this.Hb()},eUe.toString=function(){return this.Ib()},eTS(290,1,{290:1,2026:1},ese),eUe.le=function(e){var t;return(t=new ese).i=4,e>1?t.c=z9(this,e-1):t.c=this,t},eUe.me=function(){return LW(this),this.b},eUe.ne=function(){return yx(this)},eUe.oe=function(){return LW(this),this.k},eUe.pe=function(){return(4&this.i)!=0},eUe.qe=function(){return(1&this.i)!=0},eUe.Ib=function(){return ee6(this)},eUe.i=0;var e1P=1,e1R=Y5(eUc,"Object",1),e1j=Y5(eUc,"Class",290);eTS(1998,1,eUl),Y5(eUf,"Optional",1998),eTS(1170,1998,eUl,i),eUe.Fb=function(e){return e===this},eUe.Hb=function(){return 2040732332},eUe.Ib=function(){return"Optional.absent()"},eUe.Jb=function(e){return Y9(e),m4(),e0l},Y5(eUf,"Absent",1170),eTS(628,1,{},ve),Y5(eUf,"Joiner",628);var e1F=RL(eUf,"Predicate");eTS(582,1,{169:1,582:1,3:1,45:1},c4),eUe.Mb=function(e){return es_(this,e)},eUe.Lb=function(e){return es_(this,e)},eUe.Fb=function(e){var t;return!!M4(e,582)&&(t=Pp(e,582),eT$(this.a,t.a))},eUe.Hb=function(){return esS(this.a)+306654252},eUe.Ib=function(){return eE7(this.a)},Y5(eUf,"Predicates/AndPredicate",582),eTS(408,1998,{408:1,3:1},c5),eUe.Fb=function(e){var t;return!!M4(e,408)&&(t=Pp(e,408),ecX(this.a,t.a))},eUe.Hb=function(){return 1502476572+esj(this.a)},eUe.Ib=function(){return eUm+this.a+")"},eUe.Jb=function(e){return new c5(H5(e.Kb(this.a),"the Function passed to Optional.transform() must not return null."))},Y5(eUf,"Present",408),eTS(198,1,eUv),eUe.Nb=function(e){F8(this,e)},eUe.Qb=function(){g4()},Y5(eUy,"UnmodifiableIterator",198),eTS(1978,198,eUw),eUe.Qb=function(){g4()},eUe.Rb=function(e){throw p7(new bO)},eUe.Wb=function(e){throw p7(new bO)},Y5(eUy,"UnmodifiableListIterator",1978),eTS(386,1978,eUw),eUe.Ob=function(){return this.c0},eUe.Pb=function(){if(this.c>=this.d)throw p7(new bC);return this.Xb(this.c++)},eUe.Tb=function(){return this.c},eUe.Ub=function(){if(this.c<=0)throw p7(new bC);return this.Xb(--this.c)},eUe.Vb=function(){return this.c-1},eUe.c=0,eUe.d=0,Y5(eUy,"AbstractIndexedListIterator",386),eTS(699,198,eUv),eUe.Ob=function(){return erE(this)},eUe.Pb=function(){return QR(this)},eUe.e=1,Y5(eUy,"AbstractIterator",699),eTS(1986,1,{224:1}),eUe.Zb=function(){var e;return(e=this.f)||(this.f=this.ac())},eUe.Fb=function(e){return es5(this,e)},eUe.Hb=function(){return esj(this.Zb())},eUe.dc=function(){return 0==this.gc()},eUe.ec=function(){return Fh(this)},eUe.Ib=function(){return efF(this.Zb())},Y5(eUy,"AbstractMultimap",1986),eTS(726,1986,eU_),eUe.$b=function(){enK(this)},eUe._b=function(e){return yy(this,e)},eUe.ac=function(){return new wI(this,this.c)},eUe.ic=function(e){return this.hc()},eUe.bc=function(){return new OC(this,this.c)},eUe.jc=function(){return this.mc(this.hc())},eUe.kc=function(){return new m$(this)},eUe.lc=function(){return ew4(this.c.vc().Nc(),new o,64,this.d)},eUe.cc=function(e){return Zq(this,e)},eUe.fc=function(e){return eu9(this,e)},eUe.gc=function(){return this.d},eUe.mc=function(e){return Hj(),new fF(e)},eUe.nc=function(){return new mH(this)},eUe.oc=function(){return ew4(this.c.Cc().Nc(),new a,64,this.d)},eUe.pc=function(e,t){return new XS(this,e,t,null)},eUe.d=0,Y5(eUy,"AbstractMapBasedMultimap",726),eTS(1631,726,eU_),eUe.hc=function(){return new XM(this.a)},eUe.jc=function(){return Hj(),Hj(),e2r},eUe.cc=function(e){return Pp(Zq(this,e),15)},eUe.fc=function(e){return Pp(eu9(this,e),15)},eUe.Zb=function(){return HU(this)},eUe.Fb=function(e){return es5(this,e)},eUe.qc=function(e){return Pp(Zq(this,e),15)},eUe.rc=function(e){return Pp(eu9(this,e),15)},eUe.mc=function(e){return $a(Pp(e,15))},eUe.pc=function(e,t){return Vu(this,e,Pp(t,15),null)},Y5(eUy,"AbstractListMultimap",1631),eTS(732,1,eUE),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return this.c.Ob()||this.e.Ob()},eUe.Pb=function(){var e;return this.e.Ob()||(e=Pp(this.c.Pb(),42),this.b=e.cd(),this.a=Pp(e.dd(),14),this.e=this.a.Kc()),this.sc(this.b,this.e.Pb())},eUe.Qb=function(){this.e.Qb(),this.a.dc()&&this.c.Qb(),--this.d.d},Y5(eUy,"AbstractMapBasedMultimap/Itr",732),eTS(1099,732,eUE,mH),eUe.sc=function(e,t){return t},Y5(eUy,"AbstractMapBasedMultimap/1",1099),eTS(1100,1,{},a),eUe.Kb=function(e){return Pp(e,14).Nc()},Y5(eUy,"AbstractMapBasedMultimap/1methodref$spliterator$Type",1100),eTS(1101,732,eUE,m$),eUe.sc=function(e,t){return new wD(e,t)},Y5(eUy,"AbstractMapBasedMultimap/2",1101);var e1Y=RL(eUS,"Map");eTS(1967,1,eUk),eUe.wc=function(e){ear(this,e)},eUe.yc=function(e,t,n){return el6(this,e,t,n)},eUe.$b=function(){this.vc().$b()},eUe.tc=function(e){return emT(this,e)},eUe._b=function(e){return!!ewt(this,e,!1)},eUe.uc=function(e){var t,n,r;for(n=this.vc().Kc();n.Ob();)if(r=(t=Pp(n.Pb(),42)).dd(),xc(e)===xc(r)||null!=e&&ecX(e,r))return!0;return!1},eUe.Fb=function(e){var t,n,r;if(e===this)return!0;if(!M4(e,83)||(r=Pp(e,83),this.gc()!=r.gc()))return!1;for(n=r.vc().Kc();n.Ob();)if(t=Pp(n.Pb(),42),!this.tc(t))return!1;return!0},eUe.xc=function(e){return xu(ewt(this,e,!1))},eUe.Hb=function(){return eoP(this.vc())},eUe.dc=function(){return 0==this.gc()},eUe.ec=function(){return new fk(this)},eUe.zc=function(e,t){throw p7(new gW("Put not supported on this map"))},eUe.Ac=function(e){eij(this,e)},eUe.Bc=function(e){return xu(ewt(this,e,!0))},eUe.gc=function(){return this.vc().gc()},eUe.Ib=function(){return ewb(this)},eUe.Cc=function(){return new fT(this)},Y5(eUS,"AbstractMap",1967),eTS(1987,1967,eUk),eUe.bc=function(){return new wU(this)},eUe.vc=function(){return Fd(this)},eUe.ec=function(){var e;return(e=this.g)||(this.g=this.bc())},eUe.Cc=function(){var e;return(e=this.i)||(this.i=new wH(this))},Y5(eUy,"Maps/ViewCachingAbstractMap",1987),eTS(389,1987,eUk,wI),eUe.xc=function(e){return etl(this,e)},eUe.Bc=function(e){return euT(this,e)},eUe.$b=function(){this.d==this.e.c?this.e.$b():RG(new RK(this))},eUe._b=function(e){return ecD(this.d,e)},eUe.Ec=function(){return new c7(this)},eUe.Dc=function(){return this.Ec()},eUe.Fb=function(e){return this===e||ecX(this.d,e)},eUe.Hb=function(){return esj(this.d)},eUe.ec=function(){return this.e.ec()},eUe.gc=function(){return this.d.gc()},eUe.Ib=function(){return efF(this.d)},Y5(eUy,"AbstractMapBasedMultimap/AsMap",389);var e1B=RL(eUc,"Iterable");eTS(28,1,eUx),eUe.Jc=function(e){qX(this,e)},eUe.Lc=function(){return this.Oc()},eUe.Nc=function(){return new Gq(this,0)},eUe.Oc=function(){return new R1(null,this.Nc())},eUe.Fc=function(e){throw p7(new gW("Add not supported on this collection"))},eUe.Gc=function(e){return er7(this,e)},eUe.$b=function(){UG(this)},eUe.Hc=function(e){return eds(this,e,!1)},eUe.Ic=function(e){return eot(this,e)},eUe.dc=function(){return 0==this.gc()},eUe.Mc=function(e){return eds(this,e,!0)},eUe.Pc=function(){return Fn(this)},eUe.Qc=function(e){return emk(this,e)},eUe.Ib=function(){return e_F(this)},Y5(eUS,"AbstractCollection",28);var e1U=RL(eUS,"Set");eTS(eUT,28,eUM),eUe.Nc=function(){return new Gq(this,1)},eUe.Fb=function(e){return ehN(this,e)},eUe.Hb=function(){return eoP(this)},Y5(eUS,"AbstractSet",eUT),eTS(1970,eUT,eUM),Y5(eUy,"Sets/ImprovedAbstractSet",1970),eTS(1971,1970,eUM),eUe.$b=function(){this.Rc().$b()},eUe.Hc=function(e){return edz(this,e)},eUe.dc=function(){return this.Rc().dc()},eUe.Mc=function(e){var t;return!!this.Hc(e)&&(t=Pp(e,42),this.Rc().ec().Mc(t.cd()))},eUe.gc=function(){return this.Rc().gc()},Y5(eUy,"Maps/EntrySet",1971),eTS(1097,1971,eUM,c7),eUe.Hc=function(e){return ecC(this.a.d.vc(),e)},eUe.Kc=function(){return new RK(this.a)},eUe.Rc=function(){return this.a},eUe.Mc=function(e){var t;return!!ecC(this.a.d.vc(),e)&&(t=Pp(e,42),ZM(this.a.e,t.cd()),!0)},eUe.Nc=function(){return Pl(this.a.d.vc().Nc(),new le(this.a))},Y5(eUy,"AbstractMapBasedMultimap/AsMap/AsMapEntries",1097),eTS(1098,1,{},le),eUe.Kb=function(e){return qJ(this.a,Pp(e,42))},Y5(eUy,"AbstractMapBasedMultimap/AsMap/AsMapEntries/0methodref$wrapEntry$Type",1098),eTS(730,1,eUE,RK),eUe.Nb=function(e){F8(this,e)},eUe.Pb=function(){var e;return e=Pp(this.b.Pb(),42),this.a=Pp(e.dd(),14),qJ(this.c,e)},eUe.Ob=function(){return this.b.Ob()},eUe.Qb=function(){eah(!!this.a),this.b.Qb(),this.c.e.d-=this.a.gc(),this.a.$b(),this.a=null},Y5(eUy,"AbstractMapBasedMultimap/AsMap/AsMapIterator",730),eTS(532,1970,eUM,wU),eUe.$b=function(){this.b.$b()},eUe.Hc=function(e){return this.b._b(e)},eUe.Jc=function(e){Y9(e),this.b.wc(new lk(e))},eUe.dc=function(){return this.b.dc()},eUe.Kc=function(){return new gr(this.b.vc().Kc())},eUe.Mc=function(e){return!!this.b._b(e)&&(this.b.Bc(e),!0)},eUe.gc=function(){return this.b.gc()},Y5(eUy,"Maps/KeySet",532),eTS(318,532,eUM,OC),eUe.$b=function(){var e;RG((e=this.b.vc().Kc(),new wg(this,e)))},eUe.Ic=function(e){return this.b.ec().Ic(e)},eUe.Fb=function(e){return this===e||ecX(this.b.ec(),e)},eUe.Hb=function(){return esj(this.b.ec())},eUe.Kc=function(){var e;return e=this.b.vc().Kc(),new wg(this,e)},eUe.Mc=function(e){var t,n;return n=0,(t=Pp(this.b.Bc(e),14))&&(n=t.gc(),t.$b(),this.a.d-=n),n>0},eUe.Nc=function(){return this.b.ec().Nc()},Y5(eUy,"AbstractMapBasedMultimap/KeySet",318),eTS(731,1,eUE,wg),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return this.c.Ob()},eUe.Pb=function(){return this.a=Pp(this.c.Pb(),42),this.a.cd()},eUe.Qb=function(){var e;eah(!!this.a),e=Pp(this.a.dd(),14),this.c.Qb(),this.b.a.d-=e.gc(),e.$b(),this.a=null},Y5(eUy,"AbstractMapBasedMultimap/KeySet/1",731),eTS(491,389,{83:1,161:1},LX),eUe.bc=function(){return this.Sc()},eUe.ec=function(){return this.Tc()},eUe.Sc=function(){return new wb(this.c,this.Uc())},eUe.Tc=function(){var e;return(e=this.b)||(this.b=this.Sc())},eUe.Uc=function(){return Pp(this.d,161)},Y5(eUy,"AbstractMapBasedMultimap/SortedAsMap",491),eTS(542,491,eUO,LJ),eUe.bc=function(){return new wm(this.a,Pp(Pp(this.d,161),171))},eUe.Sc=function(){return new wm(this.a,Pp(Pp(this.d,161),171))},eUe.ec=function(){var e;return Pp((e=this.b)||(this.b=new wm(this.a,Pp(Pp(this.d,161),171))),271)},eUe.Tc=function(){var e;return Pp((e=this.b)||(this.b=new wm(this.a,Pp(Pp(this.d,161),171))),271)},eUe.Uc=function(){return Pp(Pp(this.d,161),171)},Y5(eUy,"AbstractMapBasedMultimap/NavigableAsMap",542),eTS(490,318,eUA,wb),eUe.Nc=function(){return this.b.ec().Nc()},Y5(eUy,"AbstractMapBasedMultimap/SortedKeySet",490),eTS(388,490,eUL,wm),Y5(eUy,"AbstractMapBasedMultimap/NavigableKeySet",388),eTS(541,28,eUx,XS),eUe.Fc=function(e){var t,n;return efH(this),n=this.d.dc(),(t=this.d.Fc(e))&&(++this.f.d,n&&CP(this)),t},eUe.Gc=function(e){var t,n,r;return!e.dc()&&(r=(efH(this),this.d.gc()),(t=this.d.Gc(e))&&(n=this.d.gc(),this.f.d+=n-r,0==r&&CP(this)),t)},eUe.$b=function(){var e;0!=(e=(efH(this),this.d.gc()))&&(this.d.$b(),this.f.d-=e,jY(this))},eUe.Hc=function(e){return efH(this),this.d.Hc(e)},eUe.Ic=function(e){return efH(this),this.d.Ic(e)},eUe.Fb=function(e){return e===this||(efH(this),ecX(this.d,e))},eUe.Hb=function(){return efH(this),esj(this.d)},eUe.Kc=function(){return efH(this),new PS(this)},eUe.Mc=function(e){var t;return efH(this),(t=this.d.Mc(e))&&(--this.f.d,jY(this)),t},eUe.gc=function(){return xw(this)},eUe.Nc=function(){return efH(this),this.d.Nc()},eUe.Ib=function(){return efH(this),efF(this.d)},Y5(eUy,"AbstractMapBasedMultimap/WrappedCollection",541);var e1H=RL(eUS,"List");eTS(728,541,{20:1,28:1,14:1,15:1},Fo),eUe.ad=function(e){er8(this,e)},eUe.Nc=function(){return efH(this),this.d.Nc()},eUe.Vc=function(e,t){var n;efH(this),n=this.d.dc(),Pp(this.d,15).Vc(e,t),++this.a.d,n&&CP(this)},eUe.Wc=function(e,t){var n,r,i;return!t.dc()&&(i=(efH(this),this.d.gc()),(n=Pp(this.d,15).Wc(e,t))&&(r=this.d.gc(),this.a.d+=r-i,0==i&&CP(this)),n)},eUe.Xb=function(e){return efH(this),Pp(this.d,15).Xb(e)},eUe.Xc=function(e){return efH(this),Pp(this.d,15).Xc(e)},eUe.Yc=function(){return efH(this),new Mb(this)},eUe.Zc=function(e){return efH(this),new HM(this,e)},eUe.$c=function(e){var t;return efH(this),t=Pp(this.d,15).$c(e),--this.a.d,jY(this),t},eUe._c=function(e,t){return efH(this),Pp(this.d,15)._c(e,t)},eUe.bd=function(e,t){return efH(this),Vu(this.a,this.e,Pp(this.d,15).bd(e,t),this.b?this.b:this)},Y5(eUy,"AbstractMapBasedMultimap/WrappedList",728),eTS(1096,728,{20:1,28:1,14:1,15:1,54:1},A7),Y5(eUy,"AbstractMapBasedMultimap/RandomAccessWrappedList",1096),eTS(620,1,eUE,PS),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return UW(this),this.b.Ob()},eUe.Pb=function(){return UW(this),this.b.Pb()},eUe.Qb=function(){OG(this)},Y5(eUy,"AbstractMapBasedMultimap/WrappedCollection/WrappedIterator",620),eTS(729,620,eUC,Mb,HM),eUe.Qb=function(){OG(this)},eUe.Rb=function(e){var t;t=0==xw(this.a),(UW(this),Pp(this.b,125)).Rb(e),++this.a.a.d,t&&CP(this.a)},eUe.Sb=function(){return(UW(this),Pp(this.b,125)).Sb()},eUe.Tb=function(){return(UW(this),Pp(this.b,125)).Tb()},eUe.Ub=function(){return(UW(this),Pp(this.b,125)).Ub()},eUe.Vb=function(){return(UW(this),Pp(this.b,125)).Vb()},eUe.Wb=function(e){(UW(this),Pp(this.b,125)).Wb(e)},Y5(eUy,"AbstractMapBasedMultimap/WrappedList/WrappedListIterator",729),eTS(727,541,eUA,L3),eUe.Nc=function(){return efH(this),this.d.Nc()},Y5(eUy,"AbstractMapBasedMultimap/WrappedSortedSet",727),eTS(1095,727,eUL,TB),Y5(eUy,"AbstractMapBasedMultimap/WrappedNavigableSet",1095),eTS(1094,541,eUM,L4),eUe.Nc=function(){return efH(this),this.d.Nc()},Y5(eUy,"AbstractMapBasedMultimap/WrappedSet",1094),eTS(1103,1,{},o),eUe.Kb=function(e){return Xb(Pp(e,42))},Y5(eUy,"AbstractMapBasedMultimap/lambda$1$Type",1103),eTS(1102,1,{},lt),eUe.Kb=function(e){return new wD(this.a,e)},Y5(eUy,"AbstractMapBasedMultimap/lambda$2$Type",1102);var e1$=RL(eUS,"Map/Entry");eTS(345,1,eUI),eUe.Fb=function(e){var t;return!!M4(e,42)&&(t=Pp(e,42),BG(this.cd(),t.cd())&&BG(this.dd(),t.dd()))},eUe.Hb=function(){var e,t;return e=this.cd(),t=this.dd(),(null==e?0:esj(e))^(null==t?0:esj(t))},eUe.ed=function(e){throw p7(new bO)},eUe.Ib=function(){return this.cd()+"="+this.dd()},Y5(eUy,eUD,345),eTS(1988,28,eUx),eUe.$b=function(){this.fd().$b()},eUe.Hc=function(e){var t;return!!M4(e,42)&&(t=Pp(e,42),Kr(this.fd(),t.cd(),t.dd()))},eUe.Mc=function(e){var t;return!!M4(e,42)&&(t=Pp(e,42),Ki(this.fd(),t.cd(),t.dd()))},eUe.gc=function(){return this.fd().d},Y5(eUy,"Multimaps/Entries",1988),eTS(733,1988,eUx,ln),eUe.Kc=function(){return this.a.kc()},eUe.fd=function(){return this.a},eUe.Nc=function(){return this.a.lc()},Y5(eUy,"AbstractMultimap/Entries",733),eTS(734,733,eUM,mz),eUe.Nc=function(){return this.a.lc()},eUe.Fb=function(e){return eEB(this,e)},eUe.Hb=function(){return eie(this)},Y5(eUy,"AbstractMultimap/EntrySet",734),eTS(735,28,eUx,lr),eUe.$b=function(){this.a.$b()},eUe.Hc=function(e){return eun(this.a,e)},eUe.Kc=function(){return this.a.nc()},eUe.gc=function(){return this.a.d},eUe.Nc=function(){return this.a.oc()},Y5(eUy,"AbstractMultimap/Values",735),eTS(1989,28,{835:1,20:1,28:1,14:1}),eUe.Jc=function(e){Y9(e),Uz(this).Jc(new lS(e))},eUe.Nc=function(){var e;return ew4(e=Uz(this).Nc(),new y,64|1296&e.qd(),this.a.d)},eUe.Fc=function(e){return g5(),!0},eUe.Gc=function(e){return Y9(this),Y9(e),M4(e,543)?KM(Pp(e,835)):!e.dc()&&eel(this,e.Kc())},eUe.Hc=function(e){var t;return((t=Pp(ecA(HU(this.a),e),14))?t.gc():0)>0},eUe.Fb=function(e){return eMc(this,e)},eUe.Hb=function(){return esj(Uz(this))},eUe.dc=function(){return Uz(this).dc()},eUe.Mc=function(e){return ekJ(this,e,1)>0},eUe.Ib=function(){return efF(Uz(this))},Y5(eUy,"AbstractMultiset",1989),eTS(1991,1970,eUM),eUe.$b=function(){enK(this.a.a)},eUe.Hc=function(e){var t,n;return!!M4(e,492)&&(n=Pp(e,416),!(0>=Pp(n.a.dd(),14).gc())&&(t=GB(this.a,n.a.cd()))==Pp(n.a.dd(),14).gc())},eUe.Mc=function(e){var t,n,r,i;return!!M4(e,492)&&(t=(n=Pp(e,416)).a.cd(),0!=(r=Pp(n.a.dd(),14).gc()))&&ekQ(i=this.a,t,r)},Y5(eUy,"Multisets/EntrySet",1991),eTS(1109,1991,eUM,li),eUe.Kc=function(){return new ga(Fd(HU(this.a.a)).Kc())},eUe.gc=function(){return HU(this.a.a).gc()},Y5(eUy,"AbstractMultiset/EntrySet",1109),eTS(619,726,eU_),eUe.hc=function(){return this.gd()},eUe.jc=function(){return this.hd()},eUe.cc=function(e){return this.jd(e)},eUe.fc=function(e){return this.kd(e)},eUe.Zb=function(){var e;return(e=this.f)||(this.f=this.ac())},eUe.hd=function(){return Hj(),Hj(),e2a},eUe.Fb=function(e){return es5(this,e)},eUe.jd=function(e){return Pp(Zq(this,e),21)},eUe.kd=function(e){return Pp(eu9(this,e),21)},eUe.mc=function(e){return Hj(),new vd(Pp(e,21))},eUe.pc=function(e,t){return new L4(this,e,Pp(t,21))},Y5(eUy,"AbstractSetMultimap",619),eTS(1657,619,eU_),eUe.hc=function(){return new yB(this.b)},eUe.gd=function(){return new yB(this.b)},eUe.jc=function(){return Bo(new yB(this.b))},eUe.hd=function(){return Bo(new yB(this.b))},eUe.cc=function(e){return Pp(Pp(Zq(this,e),21),84)},eUe.jd=function(e){return Pp(Pp(Zq(this,e),21),84)},eUe.fc=function(e){return Pp(Pp(eu9(this,e),21),84)},eUe.kd=function(e){return Pp(Pp(eu9(this,e),21),84)},eUe.mc=function(e){return M4(e,271)?Bo(Pp(e,271)):(Hj(),new O4(Pp(e,84)))},eUe.Zb=function(){var e;return(e=this.f)||(this.f=M4(this.c,171)?new LJ(this,Pp(this.c,171)):M4(this.c,161)?new LX(this,Pp(this.c,161)):new wI(this,this.c))},eUe.pc=function(e,t){return M4(t,271)?new TB(this,e,Pp(t,271)):new L3(this,e,Pp(t,84))},Y5(eUy,"AbstractSortedSetMultimap",1657),eTS(1658,1657,eU_),eUe.Zb=function(){var e;return Pp(Pp((e=this.f)||(this.f=M4(this.c,171)?new LJ(this,Pp(this.c,171)):M4(this.c,161)?new LX(this,Pp(this.c,161)):new wI(this,this.c)),161),171)},eUe.ec=function(){var e;return Pp(Pp((e=this.i)||(this.i=M4(this.c,171)?new wm(this,Pp(this.c,171)):M4(this.c,161)?new wb(this,Pp(this.c,161)):new OC(this,this.c)),84),271)},eUe.bc=function(){return M4(this.c,171)?new wm(this,Pp(this.c,171)):M4(this.c,161)?new wb(this,Pp(this.c,161)):new OC(this,this.c)},Y5(eUy,"AbstractSortedKeySortedSetMultimap",1658),eTS(2010,1,{1947:1}),eUe.Fb=function(e){return ev7(this,e)},eUe.Hb=function(){var e;return eoP((e=this.g)||(this.g=new la(this)))},eUe.Ib=function(){var e;return ewb((e=this.f)||(this.f=new OP(this)))},Y5(eUy,"AbstractTable",2010),eTS(665,eUT,eUM,la),eUe.$b=function(){g6()},eUe.Hc=function(e){var t,n;return!!M4(e,468)&&(t=Pp(e,682),!!(n=Pp(ecA(Y7(this.a),xh(t.c.e,t.b)),83))&&ecC(n.vc(),new wD(xh(t.c.c,t.a),X_(t.c,t.b,t.a))))},eUe.Kc=function(){return $e(this.a)},eUe.Mc=function(e){var t,n;return!!M4(e,468)&&(t=Pp(e,682),!!(n=Pp(ecA(Y7(this.a),xh(t.c.e,t.b)),83))&&ecI(n.vc(),new wD(xh(t.c.c,t.a),X_(t.c,t.b,t.a))))},eUe.gc=function(){return R8(this.a)},eUe.Nc=function(){return KH(this.a)},Y5(eUy,"AbstractTable/CellSet",665),eTS(1928,28,eUx,lo),eUe.$b=function(){g6()},eUe.Hc=function(e){return ewx(this.a,e)},eUe.Kc=function(){return $t(this.a)},eUe.gc=function(){return R8(this.a)},eUe.Nc=function(){return Kd(this.a)},Y5(eUy,"AbstractTable/Values",1928),eTS(1632,1631,eU_),Y5(eUy,"ArrayListMultimapGwtSerializationDependencies",1632),eTS(513,1632,eU_,gQ,G$),eUe.hc=function(){return new XM(this.a)},eUe.a=0,Y5(eUy,"ArrayListMultimap",513),eTS(664,2010,{664:1,1947:1,3:1},exj),Y5(eUy,"ArrayTable",664),eTS(1924,386,eUw,OI),eUe.Xb=function(e){return new eo7(this.a,e)},Y5(eUy,"ArrayTable/1",1924),eTS(1925,1,{},c6),eUe.ld=function(e){return new eo7(this.a,e)},Y5(eUy,"ArrayTable/1methodref$getCell$Type",1925),eTS(2011,1,{682:1}),eUe.Fb=function(e){var t;return e===this||!!M4(e,468)&&(t=Pp(e,682),BG(xh(this.c.e,this.b),xh(t.c.e,t.b))&&BG(xh(this.c.c,this.a),xh(t.c.c,t.a))&&BG(X_(this.c,this.b,this.a),X_(t.c,t.b,t.a)))},eUe.Hb=function(){return euF(eow(vx(e1R,1),eUp,1,5,[xh(this.c.e,this.b),xh(this.c.c,this.a),X_(this.c,this.b,this.a)]))},eUe.Ib=function(){return"("+xh(this.c.e,this.b)+","+xh(this.c.c,this.a)+")="+X_(this.c,this.b,this.a)},Y5(eUy,"Tables/AbstractCell",2011),eTS(468,2011,{468:1,682:1},eo7),eUe.a=0,eUe.b=0,eUe.d=0,Y5(eUy,"ArrayTable/2",468),eTS(1927,1,{},c9),eUe.ld=function(e){return Qo(this.a,e)},Y5(eUy,"ArrayTable/2methodref$getValue$Type",1927),eTS(1926,386,eUw,OD),eUe.Xb=function(e){return Qo(this.a,e)},Y5(eUy,"ArrayTable/3",1926),eTS(1979,1967,eUk),eUe.$b=function(){RG(this.kc())},eUe.vc=function(){return new lx(this)},eUe.lc=function(){return new Uq(this.kc(),this.gc())},Y5(eUy,"Maps/IteratorBasedAbstractMap",1979),eTS(828,1979,eUk),eUe.$b=function(){throw p7(new bO)},eUe._b=function(e){return yE(this.c,e)},eUe.kc=function(){return new ON(this,this.c.b.c.gc())},eUe.lc=function(){return Rj(this.c.b.c.gc(),16,new c8(this))},eUe.xc=function(e){var t;return(t=Pp(Iq(this.c,e),19))?this.nd(t.a):null},eUe.dc=function(){return this.c.b.c.dc()},eUe.ec=function(){return Fl(this.c)},eUe.zc=function(e,t){var n;if(!(n=Pp(Iq(this.c,e),19)))throw p7(new gL(this.md()+" "+e+" not in "+Fl(this.c)));return this.od(n.a,t)},eUe.Bc=function(e){throw p7(new bO)},eUe.gc=function(){return this.c.b.c.gc()},Y5(eUy,"ArrayTable/ArrayMap",828),eTS(1923,1,{},c8),eUe.ld=function(e){return Bs(this.a,e)},Y5(eUy,"ArrayTable/ArrayMap/0methodref$getEntry$Type",1923),eTS(1921,345,eUI,wk),eUe.cd=function(){return OB(this.a,this.b)},eUe.dd=function(){return this.a.nd(this.b)},eUe.ed=function(e){return this.a.od(this.b,e)},eUe.b=0,Y5(eUy,"ArrayTable/ArrayMap/1",1921),eTS(1922,386,eUw,ON),eUe.Xb=function(e){return Bs(this.a,e)},Y5(eUy,"ArrayTable/ArrayMap/2",1922),eTS(1920,828,eUk,F2),eUe.md=function(){return"Column"},eUe.nd=function(e){return X_(this.b,this.a,e)},eUe.od=function(e,t){return eoy(this.b,this.a,e,t)},eUe.a=0,Y5(eUy,"ArrayTable/Row",1920),eTS(829,828,eUk,OP),eUe.nd=function(e){return new F2(this.a,e)},eUe.zc=function(e,t){return Pp(t,83),g9()},eUe.od=function(e,t){return Pp(t,83),g8()},eUe.md=function(){return"Row"},Y5(eUy,"ArrayTable/RowMap",829),eTS(1120,1,eUj,wx),eUe.qd=function(){return -262&this.a.qd()},eUe.rd=function(){return this.a.rd()},eUe.Nb=function(e){this.a.Nb(new ww(e,this.b))},eUe.sd=function(e){return this.a.sd(new wy(e,this.b))},Y5(eUy,"CollectSpliterators/1",1120),eTS(1121,1,eUF,wy),eUe.td=function(e){this.a.td(this.b.Kb(e))},Y5(eUy,"CollectSpliterators/1/lambda$0$Type",1121),eTS(1122,1,eUF,ww),eUe.td=function(e){this.a.td(this.b.Kb(e))},Y5(eUy,"CollectSpliterators/1/lambda$1$Type",1122),eTS(1123,1,eUj,K4),eUe.qd=function(){return this.a},eUe.rd=function(){return this.d&&(this.b=MS(this.b,this.d.rd())),MS(this.b,0)},eUe.Nb=function(e){this.d&&(this.d.Nb(e),this.d=null),this.c.Nb(new wv(this.e,e)),this.b=0},eUe.sd=function(e){for(;;){if(this.d&&this.d.sd(e))return xg(this.b,eUY)&&(this.b=efe(this.b,1)),!0;if(this.d=null,!this.c.sd(new w_(this,this.e)))return!1}},eUe.a=0,eUe.b=0,Y5(eUy,"CollectSpliterators/1FlatMapSpliterator",1123),eTS(1124,1,eUF,w_),eUe.td=function(e){Iv(this.a,this.b,e)},Y5(eUy,"CollectSpliterators/1FlatMapSpliterator/lambda$0$Type",1124),eTS(1125,1,eUF,wv),eUe.td=function(e){M9(this.b,this.a,e)},Y5(eUy,"CollectSpliterators/1FlatMapSpliterator/lambda$1$Type",1125),eTS(1117,1,eUj,Ig),eUe.qd=function(){return 16464|this.b},eUe.rd=function(){return this.a.rd()},eUe.Nb=function(e){this.a.xe(new wS(e,this.c))},eUe.sd=function(e){return this.a.ye(new wE(e,this.c))},eUe.b=0,Y5(eUy,"CollectSpliterators/1WithCharacteristics",1117),eTS(1118,1,eUB,wE),eUe.ud=function(e){this.a.td(this.b.ld(e))},Y5(eUy,"CollectSpliterators/1WithCharacteristics/lambda$0$Type",1118),eTS(1119,1,eUB,wS),eUe.ud=function(e){this.a.td(this.b.ld(e))},Y5(eUy,"CollectSpliterators/1WithCharacteristics/lambda$1$Type",1119),eTS(245,1,eUU),eUe.wd=function(e){return this.vd(Pp(e,245))},eUe.vd=function(e){var t;return e==(m2(),e0d)?1:e==(m3(),e0f)?-1:0!=(t=(Rg(),eiK(this.a,e.a)))?t:M4(this,519)==M4(e,519)?0:M4(this,519)?1:-1},eUe.zd=function(){return this.a},eUe.Fb=function(e){return ehd(this,e)},Y5(eUy,"Cut",245),eTS(1761,245,eUU,vb),eUe.vd=function(e){return e==this?0:1},eUe.xd=function(e){throw p7(new b_)},eUe.yd=function(e){e.a+="+∞)"},eUe.zd=function(){throw p7(new gC(eUH))},eUe.Hb=function(){return wK(),ebh(this)},eUe.Ad=function(e){return!1},eUe.Ib=function(){return"+∞"},Y5(eUy,"Cut/AboveAll",1761),eTS(519,245,{245:1,519:1,3:1,35:1},OW),eUe.xd=function(e){xT((e.a+="(",e),this.a)},eUe.yd=function(e){Bd(xT(e,this.a),93)},eUe.Hb=function(){return~esj(this.a)},eUe.Ad=function(e){return Rg(),0>eiK(this.a,e)},eUe.Ib=function(){return"/"+this.a+"\\"},Y5(eUy,"Cut/AboveValue",519),eTS(1760,245,eUU,vm),eUe.vd=function(e){return e==this?0:-1},eUe.xd=function(e){e.a+="(-∞"},eUe.yd=function(e){throw p7(new b_)},eUe.zd=function(){throw p7(new gC(eUH))},eUe.Hb=function(){return wK(),ebh(this)},eUe.Ad=function(e){return!0},eUe.Ib=function(){return"-∞"},Y5(eUy,"Cut/BelowAll",1760),eTS(1762,245,eUU,OK),eUe.xd=function(e){xT((e.a+="[",e),this.a)},eUe.yd=function(e){Bd(xT(e,this.a),41)},eUe.Hb=function(){return esj(this.a)},eUe.Ad=function(e){return Rg(),0>=eiK(this.a,e)},eUe.Ib=function(){return"\\"+this.a+"/"},Y5(eUy,"Cut/BelowValue",1762),eTS(537,1,eU$),eUe.Jc=function(e){qX(this,e)},eUe.Ib=function(){return elq(Pp(H5(this,"use Optional.orNull() instead of Optional.or(null)"),20).Kc())},Y5(eUy,"FluentIterable",537),eTS(433,537,eU$,xq),eUe.Kc=function(){return new Fa(OH(this.a.Kc(),new c))},Y5(eUy,"FluentIterable/2",433),eTS(1046,537,eU$,xZ),eUe.Kc=function(){return Y_(this)},Y5(eUy,"FluentIterable/3",1046),eTS(708,386,eUw,Oj),eUe.Xb=function(e){return this.a[e].Kc()},Y5(eUy,"FluentIterable/3/1",708),eTS(1972,1,{}),eUe.Ib=function(){return efF(this.Bd().b)},Y5(eUy,"ForwardingObject",1972),eTS(1973,1972,eUz),eUe.Bd=function(){return this.Cd()},eUe.Jc=function(e){qX(this,e)},eUe.Lc=function(){return this.Oc()},eUe.Nc=function(){return new Gq(this,0)},eUe.Oc=function(){return new R1(null,this.Nc())},eUe.Fc=function(e){return this.Cd(),yD()},eUe.Gc=function(e){return this.Cd(),yN()},eUe.$b=function(){this.Cd(),yP()},eUe.Hc=function(e){return this.Cd().Hc(e)},eUe.Ic=function(e){return this.Cd().Ic(e)},eUe.dc=function(){return this.Cd().b.dc()},eUe.Kc=function(){return this.Cd().Kc()},eUe.Mc=function(e){return this.Cd(),yR()},eUe.gc=function(){return this.Cd().b.gc()},eUe.Pc=function(){return this.Cd().Pc()},eUe.Qc=function(e){return this.Cd().Qc(e)},Y5(eUy,"ForwardingCollection",1973),eTS(1980,28,eUG),eUe.Kc=function(){return this.Ed()},eUe.Fc=function(e){throw p7(new bO)},eUe.Gc=function(e){throw p7(new bO)},eUe.$b=function(){throw p7(new bO)},eUe.Hc=function(e){return null!=e&&eds(this,e,!1)},eUe.Dd=function(){switch(this.gc()){case 0:return Bx(),Bx(),e0h;case 1:return Bx(),new Rz(Y9(this.Ed().Pb()));default:return new F3(this,this.Pc())}},eUe.Mc=function(e){throw p7(new bO)},Y5(eUy,"ImmutableCollection",1980),eTS(712,1980,eUG,bb),eUe.Kc=function(){return JJ(this.a.Kc())},eUe.Hc=function(e){return null!=e&&this.a.Hc(e)},eUe.Ic=function(e){return this.a.Ic(e)},eUe.dc=function(){return this.a.dc()},eUe.Ed=function(){return JJ(this.a.Kc())},eUe.gc=function(){return this.a.gc()},eUe.Pc=function(){return this.a.Pc()},eUe.Qc=function(e){return this.a.Qc(e)},eUe.Ib=function(){return efF(this.a)},Y5(eUy,"ForwardingImmutableCollection",712),eTS(152,1980,eUW),eUe.Kc=function(){return this.Ed()},eUe.Yc=function(){return this.Fd(0)},eUe.Zc=function(e){return this.Fd(e)},eUe.ad=function(e){er8(this,e)},eUe.Nc=function(){return new Gq(this,16)},eUe.bd=function(e,t){return this.Gd(e,t)},eUe.Vc=function(e,t){throw p7(new bO)},eUe.Wc=function(e,t){throw p7(new bO)},eUe.Fb=function(e){return eTJ(this,e)},eUe.Hb=function(){return eaI(this)},eUe.Xc=function(e){return null==e?-1:emx(this,e)},eUe.Ed=function(){return this.Fd(0)},eUe.Fd=function(e){return AR(this,e)},eUe.$c=function(e){throw p7(new bO)},eUe._c=function(e,t){throw p7(new bO)},eUe.Gd=function(e,t){var n;return ecT((n=new wz(this),new Gz(n,e,t)))},Y5(eUy,"ImmutableList",152),eTS(2006,152,eUW),eUe.Kc=function(){return JJ(this.Hd().Kc())},eUe.bd=function(e,t){return ecT(this.Hd().bd(e,t))},eUe.Hc=function(e){return null!=e&&this.Hd().Hc(e)},eUe.Ic=function(e){return this.Hd().Ic(e)},eUe.Fb=function(e){return ecX(this.Hd(),e)},eUe.Xb=function(e){return xh(this,e)},eUe.Hb=function(){return esj(this.Hd())},eUe.Xc=function(e){return this.Hd().Xc(e)},eUe.dc=function(){return this.Hd().dc()},eUe.Ed=function(){return JJ(this.Hd().Kc())},eUe.gc=function(){return this.Hd().gc()},eUe.Gd=function(e,t){return ecT(this.Hd().bd(e,t))},eUe.Pc=function(){return this.Hd().Qc(Je(e1R,eUp,1,this.Hd().gc(),5,1))},eUe.Qc=function(e){return this.Hd().Qc(e)},eUe.Ib=function(){return efF(this.Hd())},Y5(eUy,"ForwardingImmutableList",2006),eTS(714,1,eUV),eUe.vc=function(){return Fc(this)},eUe.wc=function(e){ear(this,e)},eUe.ec=function(){return Fl(this)},eUe.yc=function(e,t,n){return el6(this,e,t,n)},eUe.Cc=function(){return this.Ld()},eUe.$b=function(){throw p7(new bO)},eUe._b=function(e){return null!=this.xc(e)},eUe.uc=function(e){return this.Ld().Hc(e)},eUe.Jd=function(){return new bm(this)},eUe.Kd=function(){return new bg(this)},eUe.Fb=function(e){return eua(this,e)},eUe.Hb=function(){return Fc(this).Hb()},eUe.dc=function(){return 0==this.gc()},eUe.zc=function(e,t){return g7()},eUe.Bc=function(e){throw p7(new bO)},eUe.Ib=function(){return eEo(this)},eUe.Ld=function(){return this.e?this.e:this.e=this.Kd()},eUe.c=null,eUe.d=null,eUe.e=null,Y5(eUy,"ImmutableMap",714),eTS(715,714,eUV),eUe._b=function(e){return yE(this,e)},eUe.uc=function(e){return w1(this.b,e)},eUe.Id=function(){return ecM(new lu(this))},eUe.Jd=function(){return ecM(Uk(this.b))},eUe.Kd=function(){return Dn(),new bb(UE(this.b))},eUe.Fb=function(e){return w2(this.b,e)},eUe.xc=function(e){return Iq(this,e)},eUe.Hb=function(){return esj(this.b.c)},eUe.dc=function(){return this.b.c.dc()},eUe.gc=function(){return this.b.c.gc()},eUe.Ib=function(){return efF(this.b.c)},Y5(eUy,"ForwardingImmutableMap",715),eTS(1974,1973,eUq),eUe.Bd=function(){return this.Md()},eUe.Cd=function(){return this.Md()},eUe.Nc=function(){return new Gq(this,1)},eUe.Fb=function(e){return e===this||this.Md().Fb(e)},eUe.Hb=function(){return this.Md().Hb()},Y5(eUy,"ForwardingSet",1974),eTS(1069,1974,eUq,lu),eUe.Bd=function(){return US(this.a.b)},eUe.Cd=function(){return US(this.a.b)},eUe.Hc=function(e){if(M4(e,42)&&null==Pp(e,42).cd())return!1;try{return wQ(US(this.a.b),e)}catch(t){if(t=eoa(t),M4(t,205))return!1;throw p7(t)}},eUe.Md=function(){return US(this.a.b)},eUe.Qc=function(e){var t;return t=$L(US(this.a.b),e),US(this.a.b).b.gc()=0?"+":"")+(n/60|0),t=Tt(eB4.Math.abs(n)%60),(e_E(),e2l)[this.q.getDay()]+" "+e2f[this.q.getMonth()]+" "+Tt(this.q.getDate())+" "+Tt(this.q.getHours())+":"+Tt(this.q.getMinutes())+":"+Tt(this.q.getSeconds())+" GMT"+e+t+" "+this.q.getFullYear()};var e1Q=Y5(eUS,"Date",199);eTS(1915,199,eHB,evI),eUe.a=!1,eUe.b=0,eUe.c=0,eUe.d=0,eUe.e=0,eUe.f=0,eUe.g=!1,eUe.i=0,eUe.j=0,eUe.k=0,eUe.n=0,eUe.o=0,eUe.p=0,Y5("com.google.gwt.i18n.shared.impl","DateRecord",1915),eTS(1966,1,{}),eUe.fe=function(){return null},eUe.ge=function(){return null},eUe.he=function(){return null},eUe.ie=function(){return null},eUe.je=function(){return null},Y5(eHU,"JSONValue",1966),eTS(216,1966,{216:1},lN,lL),eUe.Fb=function(e){return!!M4(e,216)&&W$(this.a,Pp(e,216).a)},eUe.ee=function(){return be},eUe.Hb=function(){return $n(this.a)},eUe.fe=function(){return this},eUe.Ib=function(){var e,t,n;for(t=0,n=new O0("["),e=this.a.length;t0&&(n.a+=","),xT(n,eep(this,t));return n.a+="]",n.a},Y5(eHU,"JSONArray",216),eTS(483,1966,{483:1},lC),eUe.ee=function(){return bt},eUe.ge=function(){return this},eUe.Ib=function(){return OQ(),""+this.a},eUe.a=!1,Y5(eHU,"JSONBoolean",483),eTS(985,60,eHr,gs),Y5(eHU,"JSONException",985),eTS(1023,1966,{},g),eUe.ee=function(){return bo},eUe.Ib=function(){return eUg},Y5(eHU,"JSONNull",1023),eTS(258,1966,{258:1},lI),eUe.Fb=function(e){return!!M4(e,258)&&this.a==Pp(e,258).a},eUe.ee=function(){return bn},eUe.Hb=function(){return Ti(this.a)},eUe.he=function(){return this},eUe.Ib=function(){return this.a+""},eUe.a=0,Y5(eHU,"JSONNumber",258),eTS(183,1966,{183:1},gu,lD),eUe.Fb=function(e){return!!M4(e,183)&&W$(this.a,Pp(e,183).a)},eUe.ee=function(){return br},eUe.Hb=function(){return $n(this.a)},eUe.ie=function(){return this},eUe.Ib=function(){var e,t,n,r,i,a,o;for(r=0,o=new O0("{"),e=!0,i=(n=a=erG(this,Je(e17,eUP,2,0,6,1))).length;r=0?":"+this.c:"")+")"},eUe.c=0;var e18=Y5(eUc,"StackTraceElement",310);e0c={3:1,475:1,35:1,2:1};var e17=Y5(eUc,eHa,2);eTS(107,418,{475:1},vs,vu,O1),Y5(eUc,"StringBuffer",107),eTS(100,418,{475:1},vc,vl,O0),Y5(eUc,"StringBuilder",100),eTS(687,73,eHZ,vf),Y5(eUc,"StringIndexOutOfBoundsException",687),eTS(2043,1,{}),eTS(844,1,{},N),eUe.Kb=function(e){return Pp(e,78).e},Y5(eUc,"Throwable/lambda$0$Type",844),eTS(41,60,{3:1,102:1,60:1,78:1,41:1},bO,gW),Y5(eUc,"UnsupportedOperationException",41),eTS(240,236,{3:1,35:1,236:1,240:1},eew,yY),eUe.wd=function(e){return eDG(this,Pp(e,240))},eUe.ke=function(){return eEu(eRy(this))},eUe.Fb=function(e){var t;return this===e||!!M4(e,240)&&(t=Pp(e,240),this.e==t.e&&0==eDG(this,t))},eUe.Hb=function(){var e;return 0!=this.b?this.b:this.a<54?(e=eap(this.f),this.b=jE(WM(e,-1)),this.b=33*this.b+jE(WM(Fv(e,32),-1)),this.b=17*this.b+zy(this.e),this.b):(this.b=17*ect(this.c)+zy(this.e),this.b)},eUe.Ib=function(){return eRy(this)},eUe.a=0,eUe.b=0,eUe.d=0,eUe.e=0,eUe.f=0;var e0e=Y5("java.math","BigDecimal",240);eTS(91,236,{3:1,35:1,236:1,91:1},ep4,XE,F7,ey$,eh5,TU),eUe.wd=function(e){return ehI(this,Pp(e,91))},eUe.ke=function(){return eEu(eBw(this,0))},eUe.Fb=function(e){return ef6(this,e)},eUe.Hb=function(){return ect(this)},eUe.Ib=function(){return eBw(this,0)},eUe.b=-2,eUe.c=0,eUe.d=0,eUe.e=0;var e0t=Y5("java.math","BigInteger",91);eTS(488,1967,eUk),eUe.$b=function(){Yy(this)},eUe._b=function(e){return F9(this,e)},eUe.uc=function(e){return euo(this,e,this.g)||euo(this,e,this.f)},eUe.vc=function(){return new fS(this)},eUe.xc=function(e){return Bp(this,e)},eUe.zc=function(e,t){return Um(this,e,t)},eUe.Bc=function(e){return Z3(this,e)},eUe.gc=function(){return wq(this)},Y5(eUS,"AbstractHashMap",488),eTS(261,eUT,eUM,fS),eUe.$b=function(){this.a.$b()},eUe.Hc=function(e){return KN(this,e)},eUe.Kc=function(){return new esz(this.a)},eUe.Mc=function(e){var t;return!!KN(this,e)&&(t=Pp(e,42).cd(),this.a.Bc(t),!0)},eUe.gc=function(){return this.a.gc()},Y5(eUS,"AbstractHashMap/EntrySet",261),eTS(262,1,eUE,esz),eUe.Nb=function(e){F8(this,e)},eUe.Pb=function(){return etz(this)},eUe.Ob=function(){return this.b},eUe.Qb=function(){JM(this)},eUe.b=!1,Y5(eUS,"AbstractHashMap/EntrySetIterator",262),eTS(417,1,eUE,fE),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return Et(this)},eUe.Pb=function(){return HL(this)},eUe.Qb=function(){BH(this)},eUe.b=0,eUe.c=-1,Y5(eUS,"AbstractList/IteratorImpl",417),eTS(96,417,eUC,KB),eUe.Qb=function(){BH(this)},eUe.Rb=function(e){CD(this,e)},eUe.Sb=function(){return this.b>0},eUe.Tb=function(){return this.b},eUe.Ub=function(){return A6(this.b>0),this.a.Xb(this.c=--this.b)},eUe.Vb=function(){return this.b-1},eUe.Wb=function(e){A4(-1!=this.c),this.a._c(this.c,e)},Y5(eUS,"AbstractList/ListIteratorImpl",96),eTS(219,52,eU5,Gz),eUe.Vc=function(e,t){Gp(e,this.b),this.c.Vc(this.a+e,t),++this.b},eUe.Xb=function(e){return GK(e,this.b),this.c.Xb(this.a+e)},eUe.$c=function(e){var t;return GK(e,this.b),t=this.c.$c(this.a+e),--this.b,t},eUe._c=function(e,t){return GK(e,this.b),this.c._c(this.a+e,t)},eUe.gc=function(){return this.b},eUe.a=0,eUe.b=0,Y5(eUS,"AbstractList/SubList",219),eTS(384,eUT,eUM,fk),eUe.$b=function(){this.a.$b()},eUe.Hc=function(e){return this.a._b(e)},eUe.Kc=function(){var e;return e=this.a.vc().Kc(),new fx(e)},eUe.Mc=function(e){return!!this.a._b(e)&&(this.a.Bc(e),!0)},eUe.gc=function(){return this.a.gc()},Y5(eUS,"AbstractMap/1",384),eTS(691,1,eUE,fx),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return this.a.Ob()},eUe.Pb=function(){var e;return(e=Pp(this.a.Pb(),42)).cd()},eUe.Qb=function(){this.a.Qb()},Y5(eUS,"AbstractMap/1/1",691),eTS(226,28,eUx,fT),eUe.$b=function(){this.a.$b()},eUe.Hc=function(e){return this.a.uc(e)},eUe.Kc=function(){var e;return e=this.a.vc().Kc(),new fN(e)},eUe.gc=function(){return this.a.gc()},Y5(eUS,"AbstractMap/2",226),eTS(294,1,eUE,fN),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return this.a.Ob()},eUe.Pb=function(){var e;return(e=Pp(this.a.Pb(),42)).dd()},eUe.Qb=function(){this.a.Qb()},Y5(eUS,"AbstractMap/2/1",294),eTS(484,1,{484:1,42:1}),eUe.Fb=function(e){var t;return!!M4(e,42)&&(t=Pp(e,42),UT(this.d,t.cd())&&UT(this.e,t.dd()))},eUe.cd=function(){return this.d},eUe.dd=function(){return this.e},eUe.Hb=function(){return TK(this.d)^TK(this.e)},eUe.ed=function(e){return CL(this,e)},eUe.Ib=function(){return this.d+"="+this.e},Y5(eUS,"AbstractMap/AbstractEntry",484),eTS(383,484,{484:1,383:1,42:1},EE),Y5(eUS,"AbstractMap/SimpleEntry",383),eTS(1984,1,e$t),eUe.Fb=function(e){var t;return!!M4(e,42)&&(t=Pp(e,42),UT(this.cd(),t.cd())&&UT(this.dd(),t.dd()))},eUe.Hb=function(){return TK(this.cd())^TK(this.dd())},eUe.Ib=function(){return this.cd()+"="+this.dd()},Y5(eUS,eUD,1984),eTS(1992,1967,eUO),eUe.tc=function(e){return ZO(this,e)},eUe._b=function(e){return IY(this,e)},eUe.vc=function(){return new fj(this)},eUe.xc=function(e){var t;return xu(esq(this,t=e))},eUe.ec=function(){return new fP(this)},Y5(eUS,"AbstractNavigableMap",1992),eTS(739,eUT,eUM,fj),eUe.Hc=function(e){return M4(e,42)&&ZO(this.b,Pp(e,42))},eUe.Kc=function(){return new C1(this.b)},eUe.Mc=function(e){var t;return!!M4(e,42)&&(t=Pp(e,42),Jl(this.b,t))},eUe.gc=function(){return this.b.c},Y5(eUS,"AbstractNavigableMap/EntrySet",739),eTS(493,eUT,eUL,fP),eUe.Nc=function(){return new Ec(this)},eUe.$b=function(){gl(this.a)},eUe.Hc=function(e){return IY(this.a,e)},eUe.Kc=function(){var e;return e=new C1(new Ap(this.a).b),new fR(e)},eUe.Mc=function(e){return!!IY(this.a,e)&&(zS(this.a,e),!0)},eUe.gc=function(){return this.a.c},Y5(eUS,"AbstractNavigableMap/NavigableKeySet",493),eTS(494,1,eUE,fR),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return Et(this.a.a)},eUe.Pb=function(){var e;return(e=AJ(this.a)).cd()},eUe.Qb=function(){I5(this.a)},Y5(eUS,"AbstractNavigableMap/NavigableKeySet/1",494),eTS(2004,28,eUx),eUe.Fc=function(e){return Ja(e_s(this,e)),!0},eUe.Gc=function(e){return BJ(e),PG(e!=this,"Can't add a queue to itself"),er7(this,e)},eUe.$b=function(){for(;null!=eev(this););},Y5(eUS,"AbstractQueue",2004),eTS(302,28,{4:1,20:1,28:1,14:1},p1,GZ),eUe.Fc=function(e){return Vy(this,e),!0},eUe.$b=function(){qr(this)},eUe.Hc=function(e){return eos(new UN(this),e)},eUe.dc=function(){return gY(this)},eUe.Kc=function(){return new UN(this)},eUe.Mc=function(e){return zP(new UN(this),e)},eUe.gc=function(){return this.c-this.b&this.a.length-1},eUe.Nc=function(){return new Gq(this,272)},eUe.Qc=function(e){var t;return t=this.c-this.b&this.a.length-1,e.lengtht&&Bc(e,t,null),e},eUe.b=0,eUe.c=0,Y5(eUS,"ArrayDeque",302),eTS(446,1,eUE,UN),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return this.a!=this.b},eUe.Pb=function(){return ecn(this)},eUe.Qb=function(){enP(this)},eUe.a=0,eUe.b=0,eUe.c=-1,Y5(eUS,"ArrayDeque/IteratorImpl",446),eTS(12,52,e$n,p0,XM,I4),eUe.Vc=function(e,t){jO(this,e,t)},eUe.Fc=function(e){return P_(this,e)},eUe.Wc=function(e,t){return euP(this,e,t)},eUe.Gc=function(e){return eoc(this,e)},eUe.$b=function(){this.c=Je(e1R,eUp,1,0,5,1)},eUe.Hc=function(e){return -1!=QI(this,e,0)},eUe.Jc=function(e){ety(this,e)},eUe.Xb=function(e){return RJ(this,e)},eUe.Xc=function(e){return QI(this,e,0)},eUe.dc=function(){return 0==this.c.length},eUe.Kc=function(){return new fz(this)},eUe.$c=function(e){return ZV(this,e)},eUe.Mc=function(e){return QA(this,e)},eUe.Ud=function(e,t){GG(this,e,t)},eUe._c=function(e,t){return q1(this,e,t)},eUe.gc=function(){return this.c.length},eUe.ad=function(e){Mv(this,e)},eUe.Pc=function(){return AW(this)},eUe.Qc=function(e){return epg(this,e)};var e0n=Y5(eUS,"ArrayList",12);eTS(7,1,eUE,fz),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return My(this)},eUe.Pb=function(){return Wx(this)},eUe.Qb=function(){Yv(this)},eUe.a=0,eUe.b=-1,Y5(eUS,"ArrayList/1",7),eTS(2013,eB4.Function,{},S),eUe.te=function(e,t){return elN(e,t)},eTS(154,52,e$r,g$),eUe.Hc=function(e){return -1!=enW(this,e)},eUe.Jc=function(e){var t,n,r,i;for(BJ(e),n=this.a,r=0,i=n.length;r>>0).toString(16))},eUe.f=0,eUe.i=eH1;var e2X=Y5(e$N,"CNode",57);eTS(814,1,{},b5),Y5(e$N,"CNode/CNodeBuilder",814),eTS(1525,1,{},eh),eUe.Oe=function(e,t){return 0},eUe.Pe=function(e,t){return 0},Y5(e$N,e$R,1525),eTS(1790,1,{},ep),eUe.Le=function(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b;for(c=eHQ,r=new fz(e.a.b);r.ar.d.c||r.d.c==a.d.c&&r.d.b0?e+this.n.d+this.n.a:0},eUe.Se=function(){var e,t,n,r,i;if(i=0,this.e)this.b?i=this.b.a:this.a[1][1]&&(i=this.a[1][1].Se());else if(this.g)i=efV(this,evf(this,null,!0));else for(t=(etx(),eow(vx(e26,1),eU4,232,0,[e3D,e3N,e3P])),n=0,r=t.length;n0?i+this.n.b+this.n.c:0},eUe.Te=function(){var e,t,n,r,i;if(this.g)for(e=evf(this,null,!1),n=(etx(),eow(vx(e26,1),eU4,232,0,[e3D,e3N,e3P])),r=0,i=n.length;r0&&(r[0]+=this.d,n-=r[0]),r[2]>0&&(r[2]+=this.d,n-=r[2]),this.c.a=eB4.Math.max(0,n),this.c.d=t.d+e.d+(this.c.a-n)/2,r[1]=eB4.Math.max(r[1],n),ZP(this,e3N,t.d+e.d+r[0]-(r[1]-n)/2,r)},eUe.b=null,eUe.d=0,eUe.e=!1,eUe.f=!1,eUe.g=!1;var e29=0,e28=0;Y5(e$9,"GridContainerCell",1473),eTS(461,22,{3:1,35:1,22:1,461:1},EY);var e27=enw(e$9,"HorizontalLabelAlignment",461,e1G,G1,Dc);eTS(306,212,{212:1,306:1},zf,etr,$Y),eUe.Re=function(){return Rf(this)},eUe.Se=function(){return Rd(this)},eUe.a=0,eUe.c=!1;var e3e=Y5(e$9,"LabelCell",306);eTS(244,326,{212:1,326:1,244:1},eh6),eUe.Re=function(){return ek1(this)},eUe.Se=function(){return ek0(this)},eUe.Te=function(){eNE(this)},eUe.Ue=function(){eNM(this)},eUe.b=0,eUe.c=0,eUe.d=!1,Y5(e$9,"StripContainerCell",244),eTS(1626,1,eU8,e_),eUe.Mb=function(e){return gU(Pp(e,212))},Y5(e$9,"StripContainerCell/lambda$0$Type",1626),eTS(1627,1,{},eE),eUe.Fe=function(e){return Pp(e,212).Se()},Y5(e$9,"StripContainerCell/lambda$1$Type",1627),eTS(1628,1,eU8,eS),eUe.Mb=function(e){return gH(Pp(e,212))},Y5(e$9,"StripContainerCell/lambda$2$Type",1628),eTS(1629,1,{},ek),eUe.Fe=function(e){return Pp(e,212).Re()},Y5(e$9,"StripContainerCell/lambda$3$Type",1629),eTS(462,22,{3:1,35:1,22:1,462:1},EB);var e3t=enw(e$9,"VerticalLabelAlignment",462,e1G,G0,Dl);eTS(789,1,{},eFQ),eUe.c=0,eUe.d=0,eUe.k=0,eUe.s=0,eUe.t=0,eUe.v=!1,eUe.w=0,eUe.D=!1,Y5(eza,"NodeContext",789),eTS(1471,1,e$C,ex),eUe.ue=function(e,t){return To(Pp(e,61),Pp(t,61))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eza,"NodeContext/0methodref$comparePortSides$Type",1471),eTS(1472,1,e$C,eT),eUe.ue=function(e,t){return ew9(Pp(e,111),Pp(t,111))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eza,"NodeContext/1methodref$comparePortContexts$Type",1472),eTS(159,22,{3:1,35:1,22:1,159:1},ei_);var e3n=enw(eza,"NodeLabelLocation",159,e1G,epE,Df);eTS(111,1,{111:1},exz),eUe.a=!1,Y5(eza,"PortContext",111),eTS(1476,1,eUF,eM),eUe.td=function(e){yQ(Pp(e,306))},Y5(ezu,ezc,1476),eTS(1477,1,eU8,eO),eUe.Mb=function(e){return!!Pp(e,111).c},Y5(ezu,ezl,1477),eTS(1478,1,eUF,eA),eUe.td=function(e){yQ(Pp(e,111).c)},Y5(ezu,"LabelPlacer/lambda$2$Type",1478),eTS(1475,1,eUF,eC),eUe.td=function(e){Cn(),bu(Pp(e,111))},Y5(ezu,"NodeLabelAndSizeUtilities/lambda$0$Type",1475),eTS(790,1,eUF,Dx),eUe.td=function(e){_H(this.b,this.c,this.a,Pp(e,181))},eUe.a=!1,eUe.c=!1,Y5(ezu,"NodeLabelCellCreator/lambda$0$Type",790),eTS(1474,1,eUF,db),eUe.td=function(e){bB(this.a,Pp(e,181))},Y5(ezu,"PortContextCreator/lambda$0$Type",1474),eTS(1829,1,{},eI),Y5(ezd,"GreedyRectangleStripOverlapRemover",1829),eTS(1830,1,e$C,eL),eUe.ue=function(e,t){return Ay(Pp(e,222),Pp(t,222))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezd,"GreedyRectangleStripOverlapRemover/0methodref$compareByYCoordinate$Type",1830),eTS(1786,1,{},me),eUe.a=5,eUe.e=0,Y5(ezd,"RectangleStripOverlapRemover",1786),eTS(1787,1,e$C,eN),eUe.ue=function(e,t){return Aw(Pp(e,222),Pp(t,222))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezd,"RectangleStripOverlapRemover/0methodref$compareLeftRectangleBorders$Type",1787),eTS(1789,1,e$C,eP),eUe.ue=function(e,t){return YY(Pp(e,222),Pp(t,222))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezd,"RectangleStripOverlapRemover/1methodref$compareRightRectangleBorders$Type",1789),eTS(406,22,{3:1,35:1,22:1,406:1},EU);var e3r=enw(ezd,"RectangleStripOverlapRemover/OverlapRemovalDirection",406,e1G,Vn,Dd);eTS(222,1,{222:1},jH),Y5(ezd,"RectangleStripOverlapRemover/RectangleNode",222),eTS(1788,1,eUF,dm),eUe.td=function(e){emA(this.a,Pp(e,222))},Y5(ezd,"RectangleStripOverlapRemover/lambda$1$Type",1788),eTS(1304,1,e$C,eR),eUe.ue=function(e,t){return eRu(Pp(e,167),Pp(t,167))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezp,"PolyominoCompactor/CornerCasesGreaterThanRestComparator",1304),eTS(1307,1,{},ej),eUe.Kb=function(e){return Pp(e,324).a},Y5(ezp,"PolyominoCompactor/CornerCasesGreaterThanRestComparator/lambda$0$Type",1307),eTS(1308,1,eU8,eF),eUe.Mb=function(e){return Pp(e,323).a},Y5(ezp,"PolyominoCompactor/CornerCasesGreaterThanRestComparator/lambda$1$Type",1308),eTS(1309,1,eU8,eY),eUe.Mb=function(e){return Pp(e,323).a},Y5(ezp,"PolyominoCompactor/CornerCasesGreaterThanRestComparator/lambda$2$Type",1309),eTS(1302,1,e$C,eB),eUe.ue=function(e,t){return eC9(Pp(e,167),Pp(t,167))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezp,"PolyominoCompactor/MinNumOfExtensionDirectionsComparator",1302),eTS(1305,1,{},eD),eUe.Kb=function(e){return Pp(e,324).a},Y5(ezp,"PolyominoCompactor/MinNumOfExtensionDirectionsComparator/lambda$0$Type",1305),eTS(767,1,e$C,eU),eUe.ue=function(e,t){return eaq(Pp(e,167),Pp(t,167))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezp,"PolyominoCompactor/MinNumOfExtensionsComparator",767),eTS(1300,1,e$C,eH),eUe.ue=function(e,t){return ery(Pp(e,321),Pp(t,321))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezp,"PolyominoCompactor/MinPerimeterComparator",1300),eTS(1301,1,e$C,e$),eUe.ue=function(e,t){return ebg(Pp(e,321),Pp(t,321))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezp,"PolyominoCompactor/MinPerimeterComparatorWithShape",1301),eTS(1303,1,e$C,ez),eUe.ue=function(e,t){return eIz(Pp(e,167),Pp(t,167))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezp,"PolyominoCompactor/SingleExtensionSideGreaterThanRestComparator",1303),eTS(1306,1,{},eG),eUe.Kb=function(e){return Pp(e,324).a},Y5(ezp,"PolyominoCompactor/SingleExtensionSideGreaterThanRestComparator/lambda$0$Type",1306),eTS(777,1,{},EC),eUe.Ce=function(e,t){return KG(this,Pp(e,46),Pp(t,167))},Y5(ezp,"SuccessorCombination",777),eTS(644,1,{},eW),eUe.Ce=function(e,t){var n;return exd((n=Pp(e,46),Pp(t,167),n))},Y5(ezp,"SuccessorJitter",644),eTS(643,1,{},eK),eUe.Ce=function(e,t){var n;return eAW((n=Pp(e,46),Pp(t,167),n))},Y5(ezp,"SuccessorLineByLine",643),eTS(568,1,{},eV),eUe.Ce=function(e,t){var n;return eMl((n=Pp(e,46),Pp(t,167),n))},Y5(ezp,"SuccessorManhattan",568),eTS(1356,1,{},eq),eUe.Ce=function(e,t){var n;return eAt((n=Pp(e,46),Pp(t,167),n))},Y5(ezp,"SuccessorMaxNormWindingInMathPosSense",1356),eTS(400,1,{},dg),eUe.Ce=function(e,t){return YO(this,e,t)},eUe.c=!1,eUe.d=!1,eUe.e=!1,eUe.f=!1,Y5(ezp,"SuccessorQuadrantsGeneric",400),eTS(1357,1,{},eZ),eUe.Kb=function(e){return Pp(e,324).a},Y5(ezp,"SuccessorQuadrantsGeneric/lambda$0$Type",1357),eTS(323,22,{3:1,35:1,22:1,323:1},EN),eUe.a=!1;var e3i=enw(ezy,ezw,323,e1G,Va,Dh);eTS(1298,1,{}),eUe.Ib=function(){var e,t,n,r,i,a;for(i=0,n=" ",e=ell(0);i=0?"b"+e+"["+q2(this.a)+"]":"b["+q2(this.a)+"]":"b_"+Ao(this)},Y5(ez0,"FBendpoint",559),eTS(282,134,{3:1,282:1,94:1,134:1},CH),eUe.Ib=function(){return q2(this)},Y5(ez0,"FEdge",282),eTS(231,134,{3:1,231:1,94:1,134:1},Z5);var e4_=Y5(ez0,"FGraph",231);eTS(447,357,{3:1,447:1,357:1,94:1,134:1},qp),eUe.Ib=function(){return null==this.b||0==this.b.length?"l["+q2(this.a)+"]":"l_"+this.b},Y5(ez0,"FLabel",447),eTS(144,357,{3:1,144:1,357:1,94:1,134:1},Bw),eUe.Ib=function(){return WH(this)},eUe.b=0,Y5(ez0,"FNode",144),eTS(2003,1,{}),eUe.bf=function(e){eD2(this,e)},eUe.cf=function(){emz(this)},eUe.d=0,Y5(ez3,"AbstractForceModel",2003),eTS(631,2003,{631:1},eaR),eUe.af=function(e,t){var n,r,i,a,o;return ekL(this.f,e,t),i=C6(MB(t.d),e.d),o=eB4.Math.sqrt(i.a*i.a+i.b*i.b),r=eB4.Math.max(0,o-B$(e.e)/2-B$(t.e)/2),a=(n=esT(this.e,e,t))>0?-YT(r,this.c)*n:Li(r,this.b)*Pp(e_k(e,(eCk(),e9M)),19).a,Ol(i,a/o),i},eUe.bf=function(e){eD2(this,e),this.a=Pp(e_k(e,(eCk(),e9g)),19).a,this.c=gP(LV(e_k(e,e9D))),this.b=gP(LV(e_k(e,e9A)))},eUe.df=function(e){return e0&&(a-=gg(r,this.a)*n),Ol(i,a*this.b/o),i},eUe.bf=function(e){var t,n,r,i,a,o,s;for(eD2(this,e),this.b=gP(LV(e_k(e,(eCk(),e9N)))),this.c=this.b/Pp(e_k(e,e9g),19).a,r=e.e.c.length,a=0,i=0,s=new fz(e.e);s.a0},eUe.a=0,eUe.b=0,eUe.c=0,Y5(ez3,"FruchtermanReingoldModel",632),eTS(849,1,e$2,cu),eUe.Qe=function(e){efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ez4),""),"Force Model"),"Determines the model for force calculation."),e9a),(eSd(),tdv)),e4E),el9((epx(),tdh))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ez5),""),"Iterations"),"The number of iterations on the force model."),ell(300)),tdw),e15),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ez6),""),"Repulsive Power"),"Determines how many bend points are added to the edge; such bend points are regarded as repelling particles in the force model"),ell(0)),tdw),e15),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ez9),""),"FR Temperature"),"The temperature is used as a scaling factor for particle displacements."),ez8),tdg),e13),el9(tdh)))),K_(e,ez9,ez4,e9l),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ez7),""),"Eades Repulsion"),"Factor for repulsive forces in Eades' model."),5),tdg),e13),el9(tdh)))),K_(e,ez7,ez4,e9s),eYi((new cc,e))},Y5(eGe,"ForceMetaDataProvider",849),eTS(424,22,{3:1,35:1,22:1,424:1},EH);var e4E=enw(eGe,"ForceModelStrategy",424,e1G,$9,Dm);eTS(988,1,e$2,cc),eUe.Qe=function(e){eYi(e)},Y5(eGe,"ForceOptions",988),eTS(989,1,{},tr),eUe.$e=function(){return new b0},eUe._e=function(e){},Y5(eGe,"ForceOptions/ForceFactory",989),eTS(850,1,e$2,cl),eUe.Qe=function(e){efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGw),""),"Fixed Position"),"Prevent that the node is moved by the layout algorithm."),(OQ(),!1)),(eSd(),tdm)),e11),el9((epx(),tdd))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eG_),""),"Desired Edge Length"),"Either specified for parent nodes or for individual edges, where the latter takes higher precedence."),100),tdg),e13),jL(tdh,eow(vx(e5Q,1),eU4,175,0,[tdl]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGE),""),"Layout Dimension"),"Dimensions that are permitted to be altered during layout."),e9U),tdv),e4S),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGS),""),"Stress Epsilon"),"Termination criterion for the iterative process."),ez8),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGk),""),"Iteration Limit"),"Maximum number of performed iterations. Takes higher precedence than 'epsilon'."),ell(eUu)),tdw),e15),el9(tdh)))),ejQ((new cf,e))},Y5(eGe,"StressMetaDataProvider",850),eTS(992,1,e$2,cf),eUe.Qe=function(e){ejQ(e)},Y5(eGe,"StressOptions",992),eTS(993,1,{},ti),eUe.$e=function(){return new C$},eUe._e=function(e){},Y5(eGe,"StressOptions/StressFactory",993),eTS(1128,209,ezL,C$),eUe.Ze=function(e,t){var n,r,i,a,o;for(ewG(t,eGT,1),gN(LK(eT8(e,(egq(),e9q))))?gN(LK(eT8(e,e90)))||zh(n=new df((_q(),new gM(e)))):eOs(new b0,e,eiI(t,1)),i=eo4(e),o=(r=eNx(this.a,i)).Kc();o.Ob();)!((a=Pp(o.Pb(),231)).e.c.length<=1)&&(eRa(this.b,a),eMn(this.b),ety(a.d,new ta));i=eYC(r),eYh(i),eEj(t)},Y5(eGO,"StressLayoutProvider",1128),eTS(1129,1,eUF,ta),eUe.td=function(e){ePd(Pp(e,447))},Y5(eGO,"StressLayoutProvider/lambda$0$Type",1129),eTS(990,1,{},bP),eUe.c=0,eUe.e=0,eUe.g=0,Y5(eGO,"StressMajorization",990),eTS(379,22,{3:1,35:1,22:1,379:1},E$);var e4S=enw(eGO,"StressMajorization/Dimension",379,e1G,G3,Dg);eTS(991,1,e$C,dE),eUe.ue=function(e,t){return IA(this.a,Pp(e,144),Pp(t,144))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGO,"StressMajorization/lambda$0$Type",991),eTS(1229,1,{},W9),Y5(eGL,"ElkLayered",1229),eTS(1230,1,eUF,to),eUe.td=function(e){exn(Pp(e,37))},Y5(eGL,"ElkLayered/lambda$0$Type",1230),eTS(1231,1,eUF,dS),eUe.td=function(e){IL(this.a,Pp(e,37))},Y5(eGL,"ElkLayered/lambda$1$Type",1231),eTS(1263,1,{},MC),Y5(eGL,"GraphConfigurator",1263),eTS(759,1,eUF,dk),eUe.td=function(e){e_1(this.a,Pp(e,10))},Y5(eGL,"GraphConfigurator/lambda$0$Type",759),eTS(760,1,{},ts),eUe.Kb=function(e){return evR(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eGL,"GraphConfigurator/lambda$1$Type",760),eTS(761,1,eUF,dx),eUe.td=function(e){e_1(this.a,Pp(e,10))},Y5(eGL,"GraphConfigurator/lambda$2$Type",761),eTS(1127,209,ezL,b3),eUe.Ze=function(e,t){var n;n=eN7(new mn,e),xc(eT8(e,(eBy(),taM)))===xc((eck(),tpz))?ef0(this.a,n,t):exD(this.a,n,t),eYr(new ch,n)},Y5(eGL,"LayeredLayoutProvider",1127),eTS(356,22,{3:1,35:1,22:1,356:1},Ez);var e4k=enw(eGL,"LayeredPhases",356,e1G,q4,Dv);eTS(1651,1,{},enX),eUe.i=0,Y5(eGC,"ComponentsToCGraphTransformer",1651),eTS(1652,1,{},tu),eUe.ef=function(e,t){return eB4.Math.min(null!=e.a?gP(e.a):e.c.i,null!=t.a?gP(t.a):t.c.i)},eUe.ff=function(e,t){return eB4.Math.min(null!=e.a?gP(e.a):e.c.i,null!=t.a?gP(t.a):t.c.i)},Y5(eGC,"ComponentsToCGraphTransformer/1",1652),eTS(81,1,{81:1}),eUe.i=0,eUe.k=!0,eUe.o=eH1;var e4x=Y5(eGI,"CNode",81);eTS(460,81,{460:1,81:1},Ah,eh3),eUe.Ib=function(){return""},Y5(eGC,"ComponentsToCGraphTransformer/CRectNode",460),eTS(1623,1,{},tc),Y5(eGC,"OneDimensionalComponentsCompaction",1623),eTS(1624,1,{},tl),eUe.Kb=function(e){return Gm(Pp(e,46))},eUe.Fb=function(e){return this===e},Y5(eGC,"OneDimensionalComponentsCompaction/lambda$0$Type",1624),eTS(1625,1,{},tf),eUe.Kb=function(e){return edl(Pp(e,46))},eUe.Fb=function(e){return this===e},Y5(eGC,"OneDimensionalComponentsCompaction/lambda$1$Type",1625),eTS(1654,1,{},Bv),Y5(eGI,"CGraph",1654),eTS(189,1,{189:1},eh4),eUe.b=0,eUe.c=0,eUe.e=0,eUe.g=!0,eUe.i=eH1,Y5(eGI,"CGroup",189),eTS(1653,1,{},tb),eUe.ef=function(e,t){return eB4.Math.max(null!=e.a?gP(e.a):e.c.i,null!=t.a?gP(t.a):t.c.i)},eUe.ff=function(e,t){return eB4.Math.max(null!=e.a?gP(e.a):e.c.i,null!=t.a?gP(t.a):t.c.i)},Y5(eGI,e$R,1653),eTS(1655,1,{},exO),eUe.d=!1;var e4T=Y5(eGI,e$U,1655);eTS(1656,1,{},tm),eUe.Kb=function(e){return _T(),OQ(),0!=Pp(Pp(e,46).a,81).d.e},eUe.Fb=function(e){return this===e},Y5(eGI,e$H,1656),eTS(823,1,{},R$),eUe.a=!1,eUe.b=!1,eUe.c=!1,eUe.d=!1,Y5(eGI,e$$,823),eTS(1825,1,{},j$),Y5(eGD,e$z,1825);var e4M=RL(eGN,e$D);eTS(1826,1,{369:1},$h),eUe.Ke=function(e){eLh(this,Pp(e,466))},Y5(eGD,e$G,1826),eTS(1827,1,e$C,tg),eUe.ue=function(e,t){return Hy(Pp(e,81),Pp(t,81))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGD,e$W,1827),eTS(466,1,{466:1},E6),eUe.a=!1,Y5(eGD,e$K,466),eTS(1828,1,e$C,tv),eUe.ue=function(e,t){return evP(Pp(e,466),Pp(t,466))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGD,e$V,1828),eTS(140,1,{140:1},Se,PW),eUe.Fb=function(e){var t;return null!=e&&e4O==esF(e)&&(t=Pp(e,140),UT(this.c,t.c)&&UT(this.d,t.d))},eUe.Hb=function(){return euF(eow(vx(e1R,1),eUp,1,5,[this.c,this.d]))},eUe.Ib=function(){return"("+this.c+eUd+this.d+(this.a?"cx":"")+this.b+")"},eUe.a=!0,eUe.c=0,eUe.d=0;var e4O=Y5(eGN,"Point",140);eTS(405,22,{3:1,35:1,22:1,405:1},EG);var e4A=enw(eGN,"Point/Quadrant",405,e1G,Vo,Dy);eTS(1642,1,{},b6),eUe.b=null,eUe.c=null,eUe.d=null,eUe.e=null,eUe.f=null,Y5(eGN,"RectilinearConvexHull",1642),eTS(574,1,{369:1},epG),eUe.Ke=function(e){J4(this,Pp(e,140))},eUe.b=0,Y5(eGN,"RectilinearConvexHull/MaximalElementsEventHandler",574),eTS(1644,1,e$C,th),eUe.ue=function(e,t){return U3(LV(e),LV(t))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGN,"RectilinearConvexHull/MaximalElementsEventHandler/lambda$0$Type",1644),eTS(1643,1,{369:1},ete),eUe.Ke=function(e){eAo(this,Pp(e,140))},eUe.a=0,eUe.b=null,eUe.c=null,eUe.d=null,eUe.e=null,Y5(eGN,"RectilinearConvexHull/RectangleEventHandler",1643),eTS(1645,1,e$C,tp),eUe.ue=function(e,t){return WI(Pp(e,140),Pp(t,140))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGN,"RectilinearConvexHull/lambda$0$Type",1645),eTS(1646,1,e$C,td),eUe.ue=function(e,t){return WD(Pp(e,140),Pp(t,140))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGN,"RectilinearConvexHull/lambda$1$Type",1646),eTS(1647,1,e$C,ty),eUe.ue=function(e,t){return WP(Pp(e,140),Pp(t,140))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGN,"RectilinearConvexHull/lambda$2$Type",1647),eTS(1648,1,e$C,tw),eUe.ue=function(e,t){return WN(Pp(e,140),Pp(t,140))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGN,"RectilinearConvexHull/lambda$3$Type",1648),eTS(1649,1,e$C,t_),eUe.ue=function(e,t){return e_M(Pp(e,140),Pp(t,140))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGN,"RectilinearConvexHull/lambda$4$Type",1649),eTS(1650,1,{},Gf),Y5(eGN,"Scanline",1650),eTS(2005,1,{}),Y5(eGP,"AbstractGraphPlacer",2005),eTS(325,1,{325:1},Lm),eUe.mf=function(e){return!!this.nf(e)&&(exg(this.b,Pp(e_k(e,(eBU(),ttX)),21),e),!0)},eUe.nf=function(e){var t,n,r,i;for(t=Pp(e_k(e,(eBU(),ttX)),21),r=(i=Pp(Zq(e8E,t),21)).Kc();r.Ob();)if(n=Pp(r.Pb(),21),!Pp(Zq(this.b,n),15).dc())return!1;return!0},Y5(eGP,"ComponentGroup",325),eTS(765,2005,{},b9),eUe.of=function(e){var t,n;for(n=new fz(this.a);n.ah&&(_=0,E+=d+i,d=0),m=o.c,eIn(o,_+m.a,E+m.b),xB(m),n=eB4.Math.max(n,_+v.a),d=eB4.Math.max(d,v.b),_+=v.a+i;if(t.f.a=n,t.f.b=E+d,gN(LK(e_k(a,tiQ)))){for(eBb(r=new tE,e,i),f=e.Kc();f.Ob();)C5(xB((l=Pp(f.Pb(),37)).c),r.e);C5(xB(t.f),r.a)}JN(t,e)},Y5(eGP,"SimpleRowGraphPlacer",1291),eTS(1292,1,e$C,tx),eUe.ue=function(e,t){return eaV(Pp(e,37),Pp(t,37))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGP,"SimpleRowGraphPlacer/1",1292),eTS(1262,1,e$q,tT),eUe.Lb=function(e){var t;return!!(t=Pp(e_k(Pp(e,243).b,(eBy(),taR)),74))&&0!=t.b},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){var t;return!!(t=Pp(e_k(Pp(e,243).b,(eBy(),taR)),74))&&0!=t.b},Y5(eGY,"CompoundGraphPostprocessor/1",1262),eTS(1261,1,eGB,mr),eUe.pf=function(e,t){ebL(this,Pp(e,37),t)},Y5(eGY,"CompoundGraphPreprocessor",1261),eTS(441,1,{441:1},ec8),eUe.c=!1,Y5(eGY,"CompoundGraphPreprocessor/ExternalPort",441),eTS(243,1,{243:1},DT),eUe.Ib=function(){return AV(this.c)+":"+ek5(this.b)},Y5(eGY,"CrossHierarchyEdge",243),eTS(763,1,e$C,dT),eUe.ue=function(e,t){return egB(this,Pp(e,243),Pp(t,243))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eGY,"CrossHierarchyEdgeComparator",763),eTS(299,134,{3:1,299:1,94:1,134:1}),eUe.p=0,Y5(eGU,"LGraphElement",299),eTS(17,299,{3:1,17:1,299:1,94:1,134:1},$b),eUe.Ib=function(){return ek5(this)};var e4C=Y5(eGU,"LEdge",17);eTS(37,299,{3:1,20:1,37:1,299:1,94:1,134:1},enJ),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){return new fz(this.b)},eUe.Ib=function(){return 0==this.b.c.length?"G-unlayered"+e_F(this.a):0==this.a.c.length?"G-layered"+e_F(this.b):"G[layerless"+e_F(this.a)+", layers"+e_F(this.b)+"]"};var e4I=Y5(eGU,"LGraph",37);eTS(657,1,{}),eUe.qf=function(){return this.e.n},eUe.We=function(e){return e_k(this.e,e)},eUe.rf=function(){return this.e.o},eUe.sf=function(){return this.e.p},eUe.Xe=function(e){return Ln(this.e,e)},eUe.tf=function(e){this.e.n.a=e.a,this.e.n.b=e.b},eUe.uf=function(e){this.e.o.a=e.a,this.e.o.b=e.b},eUe.vf=function(e){this.e.p=e},Y5(eGU,"LGraphAdapters/AbstractLShapeAdapter",657),eTS(577,1,{839:1},dM),eUe.wf=function(){var e,t;if(!this.b)for(this.b=AH(this.a.b.c.length),t=new fz(this.a.b);t.a0&&eu7((GV(t-1,e.length),e.charCodeAt(t-1)),eGq);)--t;if(a> ",e),egu(n)),xM(xT((e.a+="[",e),n.i),"]")),e.a},eUe.c=!0,eUe.d=!1;var e4j=Y5(eGU,"LPort",11);eTS(397,1,eU$,dA),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){var e;return e=new fz(this.a.e),new dL(e)},Y5(eGU,"LPort/1",397),eTS(1290,1,eUE,dL),eUe.Nb=function(e){F8(this,e)},eUe.Pb=function(){return Pp(Wx(this.a),17).c},eUe.Ob=function(){return My(this.a)},eUe.Qb=function(){Yv(this.a)},Y5(eGU,"LPort/1/1",1290),eTS(359,1,eU$,dC),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){var e;return e=new fz(this.a.g),new dI(e)},Y5(eGU,"LPort/2",359),eTS(762,1,eUE,dI),eUe.Nb=function(e){F8(this,e)},eUe.Pb=function(){return Pp(Wx(this.a),17).d},eUe.Ob=function(){return My(this.a)},eUe.Qb=function(){Yv(this.a)},Y5(eGU,"LPort/2/1",762),eTS(1283,1,eU$,E5),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){return new Z4(this)},Y5(eGU,"LPort/CombineIter",1283),eTS(201,1,eUE,Z4),eUe.Nb=function(e){F8(this,e)},eUe.Qb=function(){yI()},eUe.Ob=function(){return Ak(this)},eUe.Pb=function(){return My(this.a)?Wx(this.a):Wx(this.b)},Y5(eGU,"LPort/CombineIter/1",201),eTS(1285,1,e$q,tA),eUe.Lb=function(e){return FO(e)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return eiA(),0!=Pp(e,11).e.c.length},Y5(eGU,"LPort/lambda$0$Type",1285),eTS(1284,1,e$q,tL),eUe.Lb=function(e){return FA(e)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return eiA(),0!=Pp(e,11).g.c.length},Y5(eGU,"LPort/lambda$1$Type",1284),eTS(1286,1,e$q,tC),eUe.Lb=function(e){return eiA(),Pp(e,11).j==(eYu(),tbw)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return eiA(),Pp(e,11).j==(eYu(),tbw)},Y5(eGU,"LPort/lambda$2$Type",1286),eTS(1287,1,e$q,tI),eUe.Lb=function(e){return eiA(),Pp(e,11).j==(eYu(),tby)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return eiA(),Pp(e,11).j==(eYu(),tby)},Y5(eGU,"LPort/lambda$3$Type",1287),eTS(1288,1,e$q,tD),eUe.Lb=function(e){return eiA(),Pp(e,11).j==(eYu(),tbj)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return eiA(),Pp(e,11).j==(eYu(),tbj)},Y5(eGU,"LPort/lambda$4$Type",1288),eTS(1289,1,e$q,tN),eUe.Lb=function(e){return eiA(),Pp(e,11).j==(eYu(),tbY)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return eiA(),Pp(e,11).j==(eYu(),tbY)},Y5(eGU,"LPort/lambda$5$Type",1289),eTS(29,299,{3:1,20:1,299:1,29:1,94:1,134:1},By),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){return new fz(this.a)},eUe.Ib=function(){return"L_"+QI(this.b.b,this,0)+e_F(this.a)},Y5(eGU,"Layer",29),eTS(1342,1,{},mn),Y5(eG0,eG2,1342),eTS(1346,1,{},tP),eUe.Kb=function(e){return ewH(Pp(e,82))},Y5(eG0,"ElkGraphImporter/0methodref$connectableShapeToNode$Type",1346),eTS(1349,1,{},tR),eUe.Kb=function(e){return ewH(Pp(e,82))},Y5(eG0,"ElkGraphImporter/1methodref$connectableShapeToNode$Type",1349),eTS(1343,1,eUF,dD),eUe.td=function(e){exW(this.a,Pp(e,118))},Y5(eG0,eG3,1343),eTS(1344,1,eUF,dN),eUe.td=function(e){exW(this.a,Pp(e,118))},Y5(eG0,eG4,1344),eTS(1345,1,{},tj),eUe.Kb=function(e){return new R1(null,new Gq(UF(Pp(e,79)),16))},Y5(eG0,eG5,1345),eTS(1347,1,eU8,dP),eUe.Mb=function(e){return TV(this.a,Pp(e,33))},Y5(eG0,eG6,1347),eTS(1348,1,{},tF),eUe.Kb=function(e){return new R1(null,new Gq(UY(Pp(e,79)),16))},Y5(eG0,"ElkGraphImporter/lambda$5$Type",1348),eTS(1350,1,eU8,dR),eUe.Mb=function(e){return Tq(this.a,Pp(e,33))},Y5(eG0,"ElkGraphImporter/lambda$7$Type",1350),eTS(1351,1,eU8,tY),eUe.Mb=function(e){return HH(Pp(e,79))},Y5(eG0,"ElkGraphImporter/lambda$8$Type",1351),eTS(1278,1,{},ch),Y5(eG0,"ElkGraphLayoutTransferrer",1278),eTS(1279,1,eU8,dj),eUe.Mb=function(e){return It(this.a,Pp(e,17))},Y5(eG0,"ElkGraphLayoutTransferrer/lambda$0$Type",1279),eTS(1280,1,eUF,dF),eUe.td=function(e){_k(),P_(this.a,Pp(e,17))},Y5(eG0,"ElkGraphLayoutTransferrer/lambda$1$Type",1280),eTS(1281,1,eU8,dY),eUe.Mb=function(e){return Ca(this.a,Pp(e,17))},Y5(eG0,"ElkGraphLayoutTransferrer/lambda$2$Type",1281),eTS(1282,1,eUF,dB),eUe.td=function(e){_k(),P_(this.a,Pp(e,17))},Y5(eG0,"ElkGraphLayoutTransferrer/lambda$3$Type",1282),eTS(1485,1,eGB,tB),eUe.pf=function(e,t){eiu(Pp(e,37),t)},Y5(eG8,"CommentNodeMarginCalculator",1485),eTS(1486,1,{},tU),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"CommentNodeMarginCalculator/lambda$0$Type",1486),eTS(1487,1,eUF,tH),eUe.td=function(e){ePO(Pp(e,10))},Y5(eG8,"CommentNodeMarginCalculator/lambda$1$Type",1487),eTS(1488,1,eGB,t$),eUe.pf=function(e,t){eLA(Pp(e,37),t)},Y5(eG8,"CommentPostprocessor",1488),eTS(1489,1,eGB,tz),eUe.pf=function(e,t){eF4(Pp(e,37),t)},Y5(eG8,"CommentPreprocessor",1489),eTS(1490,1,eGB,tG),eUe.pf=function(e,t){eOf(Pp(e,37),t)},Y5(eG8,"ConstraintsPostprocessor",1490),eTS(1491,1,eGB,tW),eUe.pf=function(e,t){eau(Pp(e,37),t)},Y5(eG8,"EdgeAndLayerConstraintEdgeReverser",1491),eTS(1492,1,eGB,tK),eUe.pf=function(e,t){edC(Pp(e,37),t)},Y5(eG8,"EndLabelPostprocessor",1492),eTS(1493,1,{},tV),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"EndLabelPostprocessor/lambda$0$Type",1493),eTS(1494,1,eU8,tq),eUe.Mb=function(e){return $T(Pp(e,10))},Y5(eG8,"EndLabelPostprocessor/lambda$1$Type",1494),eTS(1495,1,eUF,tZ),eUe.td=function(e){evj(Pp(e,10))},Y5(eG8,"EndLabelPostprocessor/lambda$2$Type",1495),eTS(1496,1,eGB,tX),eUe.pf=function(e,t){eSF(Pp(e,37),t)},Y5(eG8,"EndLabelPreprocessor",1496),eTS(1497,1,{},tJ),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"EndLabelPreprocessor/lambda$0$Type",1497),eTS(1498,1,eUF,DA),eUe.td=function(e){_$(this.a,this.b,this.c,Pp(e,10))},eUe.a=0,eUe.b=0,eUe.c=!1,Y5(eG8,"EndLabelPreprocessor/lambda$1$Type",1498),eTS(1499,1,eU8,tQ),eUe.Mb=function(e){return xc(e_k(Pp(e,70),(eBy(),tab)))===xc((etT(),tpS))},Y5(eG8,"EndLabelPreprocessor/lambda$2$Type",1499),eTS(1500,1,eUF,dU),eUe.td=function(e){P7(this.a,Pp(e,70))},Y5(eG8,"EndLabelPreprocessor/lambda$3$Type",1500),eTS(1501,1,eU8,t1),eUe.Mb=function(e){return xc(e_k(Pp(e,70),(eBy(),tab)))===xc((etT(),tpE))},Y5(eG8,"EndLabelPreprocessor/lambda$4$Type",1501),eTS(1502,1,eUF,dH),eUe.td=function(e){P7(this.a,Pp(e,70))},Y5(eG8,"EndLabelPreprocessor/lambda$5$Type",1502),eTS(1551,1,eGB,cd),eUe.pf=function(e,t){elP(Pp(e,37),t)},Y5(eG8,"EndLabelSorter",1551),eTS(1552,1,e$C,t0),eUe.ue=function(e,t){return epc(Pp(e,456),Pp(t,456))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"EndLabelSorter/1",1552),eTS(456,1,{456:1},HP),Y5(eG8,"EndLabelSorter/LabelGroup",456),eTS(1553,1,{},t2),eUe.Kb=function(e){return _O(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"EndLabelSorter/lambda$0$Type",1553),eTS(1554,1,eU8,t3),eUe.Mb=function(e){return _O(),Pp(e,10).k==(eEn(),e8N)},Y5(eG8,"EndLabelSorter/lambda$1$Type",1554),eTS(1555,1,eUF,t4),eUe.td=function(e){eEr(Pp(e,10))},Y5(eG8,"EndLabelSorter/lambda$2$Type",1555),eTS(1556,1,eU8,t5),eUe.Mb=function(e){return _O(),xc(e_k(Pp(e,70),(eBy(),tab)))===xc((etT(),tpE))},Y5(eG8,"EndLabelSorter/lambda$3$Type",1556),eTS(1557,1,eU8,t6),eUe.Mb=function(e){return _O(),xc(e_k(Pp(e,70),(eBy(),tab)))===xc((etT(),tpS))},Y5(eG8,"EndLabelSorter/lambda$4$Type",1557),eTS(1503,1,eGB,t9),eUe.pf=function(e,t){eP2(this,Pp(e,37))},eUe.b=0,eUe.c=0,Y5(eG8,"FinalSplineBendpointsCalculator",1503),eTS(1504,1,{},t8),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"FinalSplineBendpointsCalculator/lambda$0$Type",1504),eTS(1505,1,{},t7),eUe.Kb=function(e){return new R1(null,new YI(new Fa(OH(efc(Pp(e,10)).a.Kc(),new c))))},Y5(eG8,"FinalSplineBendpointsCalculator/lambda$1$Type",1505),eTS(1506,1,eU8,ne),eUe.Mb=function(e){return!q8(Pp(e,17))},Y5(eG8,"FinalSplineBendpointsCalculator/lambda$2$Type",1506),eTS(1507,1,eU8,nt),eUe.Mb=function(e){return Ln(Pp(e,17),(eBU(),tnO))},Y5(eG8,"FinalSplineBendpointsCalculator/lambda$3$Type",1507),eTS(1508,1,eUF,d$),eUe.td=function(e){eIV(this.a,Pp(e,128))},Y5(eG8,"FinalSplineBendpointsCalculator/lambda$4$Type",1508),eTS(1509,1,eUF,nn),eUe.td=function(e){eSj(Pp(e,17).a)},Y5(eG8,"FinalSplineBendpointsCalculator/lambda$5$Type",1509),eTS(792,1,eGB,dz),eUe.pf=function(e,t){ejn(this,Pp(e,37),t)},Y5(eG8,"GraphTransformer",792),eTS(511,22,{3:1,35:1,22:1,511:1},EV);var e4F=enw(eG8,"GraphTransformer/Mode",511,e1G,$8,NF);eTS(1510,1,eGB,nr),eUe.pf=function(e,t){eAP(Pp(e,37),t)},Y5(eG8,"HierarchicalNodeResizingProcessor",1510),eTS(1511,1,eGB,ni),eUe.pf=function(e,t){erP(Pp(e,37),t)},Y5(eG8,"HierarchicalPortConstraintProcessor",1511),eTS(1512,1,e$C,na),eUe.ue=function(e,t){return epZ(Pp(e,10),Pp(t,10))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"HierarchicalPortConstraintProcessor/NodeComparator",1512),eTS(1513,1,eGB,no),eUe.pf=function(e,t){eN5(Pp(e,37),t)},Y5(eG8,"HierarchicalPortDummySizeProcessor",1513),eTS(1514,1,eGB,ns),eUe.pf=function(e,t){eCf(this,Pp(e,37),t)},eUe.a=0,Y5(eG8,"HierarchicalPortOrthogonalEdgeRouter",1514),eTS(1515,1,e$C,nu),eUe.ue=function(e,t){return Av(Pp(e,10),Pp(t,10))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"HierarchicalPortOrthogonalEdgeRouter/1",1515),eTS(1516,1,e$C,nc),eUe.ue=function(e,t){return JW(Pp(e,10),Pp(t,10))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"HierarchicalPortOrthogonalEdgeRouter/2",1516),eTS(1517,1,eGB,nl),eUe.pf=function(e,t){e_O(Pp(e,37),t)},Y5(eG8,"HierarchicalPortPositionProcessor",1517),eTS(1518,1,eGB,cp),eUe.pf=function(e,t){eYG(this,Pp(e,37))},eUe.a=0,eUe.c=0,Y5(eG8,"HighDegreeNodeLayeringProcessor",1518),eTS(571,1,{571:1},nf),eUe.b=-1,eUe.d=-1,Y5(eG8,"HighDegreeNodeLayeringProcessor/HighDegreeNodeInformation",571),eTS(1519,1,{},nd),eUe.Kb=function(e){return DR(),efu(Pp(e,10))},eUe.Fb=function(e){return this===e},Y5(eG8,"HighDegreeNodeLayeringProcessor/lambda$0$Type",1519),eTS(1520,1,{},nh),eUe.Kb=function(e){return DR(),efc(Pp(e,10))},eUe.Fb=function(e){return this===e},Y5(eG8,"HighDegreeNodeLayeringProcessor/lambda$1$Type",1520),eTS(1526,1,eGB,np),eUe.pf=function(e,t){eD8(this,Pp(e,37),t)},Y5(eG8,"HyperedgeDummyMerger",1526),eTS(793,1,{},DL),eUe.a=!1,eUe.b=!1,eUe.c=!1,Y5(eG8,"HyperedgeDummyMerger/MergeState",793),eTS(1527,1,{},nb),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"HyperedgeDummyMerger/lambda$0$Type",1527),eTS(1528,1,{},nm),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,10).j,16))},Y5(eG8,"HyperedgeDummyMerger/lambda$1$Type",1528),eTS(1529,1,eUF,ng),eUe.td=function(e){Pp(e,11).p=-1},Y5(eG8,"HyperedgeDummyMerger/lambda$2$Type",1529),eTS(1530,1,eGB,nv),eUe.pf=function(e,t){eD6(Pp(e,37),t)},Y5(eG8,"HypernodesProcessor",1530),eTS(1531,1,eGB,ny),eUe.pf=function(e,t){eD9(Pp(e,37),t)},Y5(eG8,"InLayerConstraintProcessor",1531),eTS(1532,1,eGB,nw),eUe.pf=function(e,t){eiW(Pp(e,37),t)},Y5(eG8,"InnermostNodeMarginCalculator",1532),eTS(1533,1,eGB,n_),eUe.pf=function(e,t){eFW(this,Pp(e,37))},eUe.a=eH1,eUe.b=eH1,eUe.c=eHQ,eUe.d=eHQ;var e4Y=Y5(eG8,"InteractiveExternalPortPositioner",1533);eTS(1534,1,{},nE),eUe.Kb=function(e){return Pp(e,17).d.i},eUe.Fb=function(e){return this===e},Y5(eG8,"InteractiveExternalPortPositioner/lambda$0$Type",1534),eTS(1535,1,{},dG),eUe.Kb=function(e){return AE(this.a,LV(e))},eUe.Fb=function(e){return this===e},Y5(eG8,"InteractiveExternalPortPositioner/lambda$1$Type",1535),eTS(1536,1,{},nS),eUe.Kb=function(e){return Pp(e,17).c.i},eUe.Fb=function(e){return this===e},Y5(eG8,"InteractiveExternalPortPositioner/lambda$2$Type",1536),eTS(1537,1,{},dW),eUe.Kb=function(e){return AS(this.a,LV(e))},eUe.Fb=function(e){return this===e},Y5(eG8,"InteractiveExternalPortPositioner/lambda$3$Type",1537),eTS(1538,1,{},dK),eUe.Kb=function(e){return C9(this.a,LV(e))},eUe.Fb=function(e){return this===e},Y5(eG8,"InteractiveExternalPortPositioner/lambda$4$Type",1538),eTS(1539,1,{},dV),eUe.Kb=function(e){return C8(this.a,LV(e))},eUe.Fb=function(e){return this===e},Y5(eG8,"InteractiveExternalPortPositioner/lambda$5$Type",1539),eTS(77,22,{3:1,35:1,22:1,77:1,234:1},Eq),eUe.Kf=function(){switch(this.g){case 15:return new iA;case 22:return new iL;case 47:return new iD;case 28:case 35:return new nN;case 32:return new tB;case 42:return new t$;case 1:return new tz;case 41:return new tG;case 56:return new dz((erq(),e8W));case 0:return new dz((erq(),e8G));case 2:return new tW;case 54:return new tK;case 33:return new tX;case 51:return new t9;case 55:return new nr;case 13:return new ni;case 38:return new no;case 44:return new ns;case 40:return new nl;case 9:return new cp;case 49:return new AU;case 37:return new np;case 43:return new nv;case 27:return new ny;case 30:return new nw;case 3:return new n_;case 18:return new nx;case 29:return new nT;case 5:return new cb;case 50:return new nk;case 34:return new cm;case 36:return new nP;case 52:return new cd;case 11:return new nj;case 7:return new cv;case 39:return new nF;case 45:return new nY;case 16:return new nB;case 10:return new nU;case 48:return new n$;case 21:return new nz;case 23:return new gx((enU(),tui));case 8:return new nW;case 12:return new nV;case 4:return new nq;case 19:return new cE;case 17:return new n5;case 53:return new n6;case 6:return new rc;case 25:return new ms;case 46:return new rn;case 31:return new CV;case 14:return new rg;case 26:return new iB;case 20:return new rE;case 24:return new gx((enU(),tua));default:throw p7(new gL(eWt+(null!=this.f?this.f:""+this.g)))}};var e4B=enw(eG8,eWn,77,e1G,eAn,Nj);eTS(1540,1,eGB,nx),eUe.pf=function(e,t){eFq(Pp(e,37),t)},Y5(eG8,"InvertedPortProcessor",1540),eTS(1541,1,eGB,nT),eUe.pf=function(e,t){eIR(Pp(e,37),t)},Y5(eG8,"LabelAndNodeSizeProcessor",1541),eTS(1542,1,eU8,nM),eUe.Mb=function(e){return Pp(e,10).k==(eEn(),e8N)},Y5(eG8,"LabelAndNodeSizeProcessor/lambda$0$Type",1542),eTS(1543,1,eU8,nO),eUe.Mb=function(e){return Pp(e,10).k==(eEn(),e8C)},Y5(eG8,"LabelAndNodeSizeProcessor/lambda$1$Type",1543),eTS(1544,1,eUF,DC),eUe.td=function(e){_z(this.b,this.a,this.c,Pp(e,10))},eUe.a=!1,eUe.c=!1,Y5(eG8,"LabelAndNodeSizeProcessor/lambda$2$Type",1544),eTS(1545,1,eGB,cb),eUe.pf=function(e,t){eFu(Pp(e,37),t)},Y5(eG8,"LabelDummyInserter",1545),eTS(1546,1,e$q,nA),eUe.Lb=function(e){return xc(e_k(Pp(e,70),(eBy(),tab)))===xc((etT(),tp_))},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return xc(e_k(Pp(e,70),(eBy(),tab)))===xc((etT(),tp_))},Y5(eG8,"LabelDummyInserter/1",1546),eTS(1547,1,eGB,nk),eUe.pf=function(e,t){eRz(Pp(e,37),t)},Y5(eG8,"LabelDummyRemover",1547),eTS(1548,1,eU8,nL),eUe.Mb=function(e){return gN(LK(e_k(Pp(e,70),(eBy(),tap))))},Y5(eG8,"LabelDummyRemover/lambda$0$Type",1548),eTS(1359,1,eGB,cm),eUe.pf=function(e,t){ejC(this,Pp(e,37),t)},eUe.a=null,Y5(eG8,"LabelDummySwitcher",1359),eTS(286,1,{286:1},eIu),eUe.c=0,eUe.d=null,eUe.f=0,Y5(eG8,"LabelDummySwitcher/LabelDummyInfo",286),eTS(1360,1,{},nC),eUe.Kb=function(e){return erJ(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"LabelDummySwitcher/lambda$0$Type",1360),eTS(1361,1,eU8,nI),eUe.Mb=function(e){return erJ(),Pp(e,10).k==(eEn(),e8I)},Y5(eG8,"LabelDummySwitcher/lambda$1$Type",1361),eTS(1362,1,{},dX),eUe.Kb=function(e){return Co(this.a,Pp(e,10))},Y5(eG8,"LabelDummySwitcher/lambda$2$Type",1362),eTS(1363,1,eUF,dJ),eUe.td=function(e){BO(this.a,Pp(e,286))},Y5(eG8,"LabelDummySwitcher/lambda$3$Type",1363),eTS(1364,1,e$C,nD),eUe.ue=function(e,t){return FL(Pp(e,286),Pp(t,286))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"LabelDummySwitcher/lambda$4$Type",1364),eTS(791,1,eGB,nN),eUe.pf=function(e,t){XT(Pp(e,37),t)},Y5(eG8,"LabelManagementProcessor",791),eTS(1549,1,eGB,nP),eUe.pf=function(e,t){eLr(Pp(e,37),t)},Y5(eG8,"LabelSideSelector",1549),eTS(1550,1,eU8,nR),eUe.Mb=function(e){return gN(LK(e_k(Pp(e,70),(eBy(),tap))))},Y5(eG8,"LabelSideSelector/lambda$0$Type",1550),eTS(1558,1,eGB,nj),eUe.pf=function(e,t){eN6(Pp(e,37),t)},Y5(eG8,"LayerConstraintPostprocessor",1558),eTS(1559,1,eGB,cv),eUe.pf=function(e,t){eMr(Pp(e,37),t)},Y5(eG8,"LayerConstraintPreprocessor",1559),eTS(360,22,{3:1,35:1,22:1,360:1},EZ);var e4U=enw(eG8,"LayerConstraintPreprocessor/HiddenNodeConnections",360,e1G,Vs,DF);eTS(1560,1,eGB,nF),eUe.pf=function(e,t){eRB(Pp(e,37),t)},Y5(eG8,"LayerSizeAndGraphHeightCalculator",1560),eTS(1561,1,eGB,nY),eUe.pf=function(e,t){eOw(Pp(e,37),t)},Y5(eG8,"LongEdgeJoiner",1561),eTS(1562,1,eGB,nB),eUe.pf=function(e,t){eRf(Pp(e,37),t)},Y5(eG8,"LongEdgeSplitter",1562),eTS(1563,1,eGB,nU),eUe.pf=function(e,t){ejN(this,Pp(e,37),t)},eUe.d=0,eUe.e=0,eUe.i=0,eUe.j=0,eUe.k=0,eUe.n=0,Y5(eG8,"NodePromotion",1563),eTS(1564,1,{},nH),eUe.Kb=function(e){return Pp(e,46),OQ(),!0},eUe.Fb=function(e){return this===e},Y5(eG8,"NodePromotion/lambda$0$Type",1564),eTS(1565,1,{},dq),eUe.Kb=function(e){return UM(this.a,Pp(e,46))},eUe.Fb=function(e){return this===e},eUe.a=0,Y5(eG8,"NodePromotion/lambda$1$Type",1565),eTS(1566,1,{},dZ),eUe.Kb=function(e){return UO(this.a,Pp(e,46))},eUe.Fb=function(e){return this===e},eUe.a=0,Y5(eG8,"NodePromotion/lambda$2$Type",1566),eTS(1567,1,eGB,n$),eUe.pf=function(e,t){eYN(Pp(e,37),t)},Y5(eG8,"NorthSouthPortPostprocessor",1567),eTS(1568,1,eGB,nz),eUe.pf=function(e,t){eYd(Pp(e,37),t)},Y5(eG8,"NorthSouthPortPreprocessor",1568),eTS(1569,1,e$C,nG),eUe.ue=function(e,t){return ea2(Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"NorthSouthPortPreprocessor/lambda$0$Type",1569),eTS(1570,1,eGB,nW),eUe.pf=function(e,t){eDx(Pp(e,37),t)},Y5(eG8,"PartitionMidprocessor",1570),eTS(1571,1,eU8,nK),eUe.Mb=function(e){return Ln(Pp(e,10),(eBy(),ton))},Y5(eG8,"PartitionMidprocessor/lambda$0$Type",1571),eTS(1572,1,eUF,dQ),eUe.td=function(e){H$(this.a,Pp(e,10))},Y5(eG8,"PartitionMidprocessor/lambda$1$Type",1572),eTS(1573,1,eGB,nV),eUe.pf=function(e,t){eO3(Pp(e,37),t)},Y5(eG8,"PartitionPostprocessor",1573),eTS(1574,1,eGB,nq),eUe.pf=function(e,t){exQ(Pp(e,37),t)},Y5(eG8,"PartitionPreprocessor",1574),eTS(1575,1,eU8,nZ),eUe.Mb=function(e){return Ln(Pp(e,10),(eBy(),ton))},Y5(eG8,"PartitionPreprocessor/lambda$0$Type",1575),eTS(1576,1,{},nX),eUe.Kb=function(e){return new R1(null,new YI(new Fa(OH(efc(Pp(e,10)).a.Kc(),new c))))},Y5(eG8,"PartitionPreprocessor/lambda$1$Type",1576),eTS(1577,1,eU8,nJ),eUe.Mb=function(e){return epe(Pp(e,17))},Y5(eG8,"PartitionPreprocessor/lambda$2$Type",1577),eTS(1578,1,eUF,nQ),eUe.td=function(e){eoL(Pp(e,17))},Y5(eG8,"PartitionPreprocessor/lambda$3$Type",1578),eTS(1579,1,eGB,cE),eUe.pf=function(e,t){eDe(Pp(e,37),t)},Y5(eG8,"PortListSorter",1579),eTS(1580,1,{},n1),eUe.Kb=function(e){return euv(),Pp(e,11).e},Y5(eG8,"PortListSorter/lambda$0$Type",1580),eTS(1581,1,{},n0),eUe.Kb=function(e){return euv(),Pp(e,11).g},Y5(eG8,"PortListSorter/lambda$1$Type",1581),eTS(1582,1,e$C,n2),eUe.ue=function(e,t){return qy(Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"PortListSorter/lambda$2$Type",1582),eTS(1583,1,e$C,n3),eUe.ue=function(e,t){return eg_(Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"PortListSorter/lambda$3$Type",1583),eTS(1584,1,e$C,n4),eUe.ue=function(e,t){return eDK(Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"PortListSorter/lambda$4$Type",1584),eTS(1585,1,eGB,n5),eUe.pf=function(e,t){eT3(Pp(e,37),t)},Y5(eG8,"PortSideProcessor",1585),eTS(1586,1,eGB,n6),eUe.pf=function(e,t){eCH(Pp(e,37),t)},Y5(eG8,"ReversedEdgeRestorer",1586),eTS(1591,1,eGB,ms),eUe.pf=function(e,t){emJ(this,Pp(e,37),t)},Y5(eG8,"SelfLoopPortRestorer",1591),eTS(1592,1,{},n9),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"SelfLoopPortRestorer/lambda$0$Type",1592),eTS(1593,1,eU8,n8),eUe.Mb=function(e){return Pp(e,10).k==(eEn(),e8N)},Y5(eG8,"SelfLoopPortRestorer/lambda$1$Type",1593),eTS(1594,1,eU8,n7),eUe.Mb=function(e){return Ln(Pp(e,10),(eBU(),tnk))},Y5(eG8,"SelfLoopPortRestorer/lambda$2$Type",1594),eTS(1595,1,{},re),eUe.Kb=function(e){return Pp(e_k(Pp(e,10),(eBU(),tnk)),403)},Y5(eG8,"SelfLoopPortRestorer/lambda$3$Type",1595),eTS(1596,1,eUF,d1),eUe.td=function(e){eE_(this.a,Pp(e,403))},Y5(eG8,"SelfLoopPortRestorer/lambda$4$Type",1596),eTS(794,1,eUF,rt),eUe.td=function(e){eEq(Pp(e,101))},Y5(eG8,"SelfLoopPortRestorer/lambda$5$Type",794),eTS(1597,1,eGB,rn),eUe.pf=function(e,t){ep1(Pp(e,37),t)},Y5(eG8,"SelfLoopPostProcessor",1597),eTS(1598,1,{},rr),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"SelfLoopPostProcessor/lambda$0$Type",1598),eTS(1599,1,eU8,ri),eUe.Mb=function(e){return Pp(e,10).k==(eEn(),e8N)},Y5(eG8,"SelfLoopPostProcessor/lambda$1$Type",1599),eTS(1600,1,eU8,ra),eUe.Mb=function(e){return Ln(Pp(e,10),(eBU(),tnk))},Y5(eG8,"SelfLoopPostProcessor/lambda$2$Type",1600),eTS(1601,1,eUF,ro),eUe.td=function(e){eyi(Pp(e,10))},Y5(eG8,"SelfLoopPostProcessor/lambda$3$Type",1601),eTS(1602,1,{},rs),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,101).f,1))},Y5(eG8,"SelfLoopPostProcessor/lambda$4$Type",1602),eTS(1603,1,eUF,d0),eUe.td=function(e){Vf(this.a,Pp(e,409))},Y5(eG8,"SelfLoopPostProcessor/lambda$5$Type",1603),eTS(1604,1,eU8,ru),eUe.Mb=function(e){return!!Pp(e,101).i},Y5(eG8,"SelfLoopPostProcessor/lambda$6$Type",1604),eTS(1605,1,eUF,d2),eUe.td=function(e){gb(this.a,Pp(e,101))},Y5(eG8,"SelfLoopPostProcessor/lambda$7$Type",1605),eTS(1587,1,eGB,rc),eUe.pf=function(e,t){eMJ(Pp(e,37),t)},Y5(eG8,"SelfLoopPreProcessor",1587),eTS(1588,1,{},rl),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,101).f,1))},Y5(eG8,"SelfLoopPreProcessor/lambda$0$Type",1588),eTS(1589,1,{},rf),eUe.Kb=function(e){return Pp(e,409).a},Y5(eG8,"SelfLoopPreProcessor/lambda$1$Type",1589),eTS(1590,1,eUF,rd),eUe.td=function(e){MH(Pp(e,17))},Y5(eG8,"SelfLoopPreProcessor/lambda$2$Type",1590),eTS(1606,1,eGB,CV),eUe.pf=function(e,t){eEi(this,Pp(e,37),t)},Y5(eG8,"SelfLoopRouter",1606),eTS(1607,1,{},rh),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,29).a,16))},Y5(eG8,"SelfLoopRouter/lambda$0$Type",1607),eTS(1608,1,eU8,rp),eUe.Mb=function(e){return Pp(e,10).k==(eEn(),e8N)},Y5(eG8,"SelfLoopRouter/lambda$1$Type",1608),eTS(1609,1,eU8,rb),eUe.Mb=function(e){return Ln(Pp(e,10),(eBU(),tnk))},Y5(eG8,"SelfLoopRouter/lambda$2$Type",1609),eTS(1610,1,{},rm),eUe.Kb=function(e){return Pp(e_k(Pp(e,10),(eBU(),tnk)),403)},Y5(eG8,"SelfLoopRouter/lambda$3$Type",1610),eTS(1611,1,eUF,EX),eUe.td=function(e){Hs(this.a,this.b,Pp(e,403))},Y5(eG8,"SelfLoopRouter/lambda$4$Type",1611),eTS(1612,1,eGB,rg),eUe.pf=function(e,t){eAz(Pp(e,37),t)},Y5(eG8,"SemiInteractiveCrossMinProcessor",1612),eTS(1613,1,eU8,rv),eUe.Mb=function(e){return Pp(e,10).k==(eEn(),e8N)},Y5(eG8,"SemiInteractiveCrossMinProcessor/lambda$0$Type",1613),eTS(1614,1,eU8,ry),eUe.Mb=function(e){return R9(Pp(e,10))._b((eBy(),tog))},Y5(eG8,"SemiInteractiveCrossMinProcessor/lambda$1$Type",1614),eTS(1615,1,e$C,rw),eUe.ue=function(e,t){return erF(Pp(e,10),Pp(t,10))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eG8,"SemiInteractiveCrossMinProcessor/lambda$2$Type",1615),eTS(1616,1,{},r_),eUe.Ce=function(e,t){return H4(Pp(e,10),Pp(t,10))},Y5(eG8,"SemiInteractiveCrossMinProcessor/lambda$3$Type",1616),eTS(1618,1,eGB,rE),eUe.pf=function(e,t){eN8(Pp(e,37),t)},Y5(eG8,"SortByInputModelProcessor",1618),eTS(1619,1,eU8,rS),eUe.Mb=function(e){return 0!=Pp(e,11).g.c.length},Y5(eG8,"SortByInputModelProcessor/lambda$0$Type",1619),eTS(1620,1,eUF,d3),eUe.td=function(e){eE6(this.a,Pp(e,11))},Y5(eG8,"SortByInputModelProcessor/lambda$1$Type",1620),eTS(1693,803,{},erY),eUe.Me=function(e){var t,n,r,i;switch(this.c=e,this.a.g){case 2:t=new p0,_r(UJ(new R1(null,new Gq(this.c.a.b,16)),new rj),new E2(this,t)),eS2(this,new rT),ety(t,new rM),t.c=Je(e1R,eUp,1,0,5,1),_r(UJ(new R1(null,new Gq(this.c.a.b,16)),new rO),new d5(t)),eS2(this,new rA),ety(t,new rL),t.c=Je(e1R,eUp,1,0,5,1),n=M_(eim(U1(new R1(null,new Gq(this.c.a.b,16)),new d6(this))),new rC),_r(new R1(null,new Gq(this.c.a.a,16)),new EQ(n,t)),eS2(this,new rD),ety(t,new rk),t.c=Je(e1R,eUp,1,0,5,1);break;case 3:r=new p0,eS2(this,new rx),i=M_(eim(U1(new R1(null,new Gq(this.c.a.b,16)),new d4(this))),new rI),_r(UJ(new R1(null,new Gq(this.c.a.b,16)),new rN),new E0(i,r)),eS2(this,new rP),ety(r,new rR),r.c=Je(e1R,eUp,1,0,5,1);break;default:throw p7(new bI)}},eUe.b=0,Y5(eWs,"EdgeAwareScanlineConstraintCalculation",1693),eTS(1694,1,e$q,rx),eUe.Lb=function(e){return M4(Pp(e,57).g,145)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return M4(Pp(e,57).g,145)},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$0$Type",1694),eTS(1695,1,{},d4),eUe.Fe=function(e){return eky(this.a,Pp(e,57))},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$1$Type",1695),eTS(1703,1,eU7,EJ),eUe.Vd=function(){ev_(this.a,this.b,-1)},eUe.b=0,Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$10$Type",1703),eTS(1705,1,e$q,rT),eUe.Lb=function(e){return M4(Pp(e,57).g,145)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return M4(Pp(e,57).g,145)},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$11$Type",1705),eTS(1706,1,eUF,rM),eUe.td=function(e){Pp(e,365).Vd()},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$12$Type",1706),eTS(1707,1,eU8,rO),eUe.Mb=function(e){return M4(Pp(e,57).g,10)},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$13$Type",1707),eTS(1709,1,eUF,d5),eUe.td=function(e){efw(this.a,Pp(e,57))},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$14$Type",1709),eTS(1708,1,eU7,E9),eUe.Vd=function(){ev_(this.b,this.a,-1)},eUe.a=0,Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$15$Type",1708),eTS(1710,1,e$q,rA),eUe.Lb=function(e){return M4(Pp(e,57).g,10)},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return M4(Pp(e,57).g,10)},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$16$Type",1710),eTS(1711,1,eUF,rL),eUe.td=function(e){Pp(e,365).Vd()},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$17$Type",1711),eTS(1712,1,{},d6),eUe.Fe=function(e){return ekw(this.a,Pp(e,57))},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$18$Type",1712),eTS(1713,1,{},rC),eUe.De=function(){return 0},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$19$Type",1713),eTS(1696,1,{},rI),eUe.De=function(){return 0},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$2$Type",1696),eTS(1715,1,eUF,EQ),eUe.td=function(e){jq(this.a,this.b,Pp(e,307))},eUe.a=0,Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$20$Type",1715),eTS(1714,1,eU7,E1),eUe.Vd=function(){eT4(this.a,this.b,-1)},eUe.b=0,Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$21$Type",1714),eTS(1716,1,e$q,rD),eUe.Lb=function(e){return Pp(e,57),!0},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return Pp(e,57),!0},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$22$Type",1716),eTS(1717,1,eUF,rk),eUe.td=function(e){Pp(e,365).Vd()},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$23$Type",1717),eTS(1697,1,eU8,rN),eUe.Mb=function(e){return M4(Pp(e,57).g,10)},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$3$Type",1697),eTS(1699,1,eUF,E0),eUe.td=function(e){jZ(this.a,this.b,Pp(e,57))},eUe.a=0,Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$4$Type",1699),eTS(1698,1,eU7,E8),eUe.Vd=function(){ev_(this.b,this.a,-1)},eUe.a=0,Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$5$Type",1698),eTS(1700,1,e$q,rP),eUe.Lb=function(e){return Pp(e,57),!0},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return Pp(e,57),!0},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$6$Type",1700),eTS(1701,1,eUF,rR),eUe.td=function(e){Pp(e,365).Vd()},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$7$Type",1701),eTS(1702,1,eU8,rj),eUe.Mb=function(e){return M4(Pp(e,57).g,145)},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$8$Type",1702),eTS(1704,1,eUF,E2),eUe.td=function(e){eth(this.a,this.b,Pp(e,57))},Y5(eWs,"EdgeAwareScanlineConstraintCalculation/lambda$9$Type",1704),eTS(1521,1,eGB,AU),eUe.pf=function(e,t){eRE(this,Pp(e,37),t)},Y5(eWs,"HorizontalGraphCompactor",1521),eTS(1522,1,{},d9),eUe.Oe=function(e,t){var n,r,i;return Q8(e,t)?0:(n=KT(e),r=KT(t),n&&n.k==(eEn(),e8C)||r&&r.k==(eEn(),e8C))?0:(i=Pp(e_k(this.a.a,(eBU(),tnx)),304),Ax(i,n?n.k:(eEn(),e8D),r?r.k:(eEn(),e8D)))},eUe.Pe=function(e,t){var n,r,i;return Q8(e,t)?1:(n=KT(e),r=KT(t),i=Pp(e_k(this.a.a,(eBU(),tnx)),304),AT(i,n?n.k:(eEn(),e8D),r?r.k:(eEn(),e8D)))},Y5(eWs,"HorizontalGraphCompactor/1",1522),eTS(1523,1,{},rF),eUe.Ne=function(e,t){return _L(),0==e.a.i},Y5(eWs,"HorizontalGraphCompactor/lambda$0$Type",1523),eTS(1524,1,{},d8),eUe.Ne=function(e,t){return HZ(this.a,e,t)},Y5(eWs,"HorizontalGraphCompactor/lambda$1$Type",1524),eTS(1664,1,{},QF),Y5(eWs,"LGraphToCGraphTransformer",1664),eTS(1672,1,eU8,rY),eUe.Mb=function(e){return null!=e},Y5(eWs,"LGraphToCGraphTransformer/0methodref$nonNull$Type",1672),eTS(1665,1,{},rB),eUe.Kb=function(e){return Dj(),efF(e_k(Pp(Pp(e,57).g,10),(eBU(),tnc)))},Y5(eWs,"LGraphToCGraphTransformer/lambda$0$Type",1665),eTS(1666,1,{},rU),eUe.Kb=function(e){return Dj(),ecR(Pp(Pp(e,57).g,145))},Y5(eWs,"LGraphToCGraphTransformer/lambda$1$Type",1666),eTS(1675,1,eU8,rH),eUe.Mb=function(e){return Dj(),M4(Pp(e,57).g,10)},Y5(eWs,"LGraphToCGraphTransformer/lambda$10$Type",1675),eTS(1676,1,eUF,r$),eUe.td=function(e){Hq(Pp(e,57))},Y5(eWs,"LGraphToCGraphTransformer/lambda$11$Type",1676),eTS(1677,1,eU8,rz),eUe.Mb=function(e){return Dj(),M4(Pp(e,57).g,145)},Y5(eWs,"LGraphToCGraphTransformer/lambda$12$Type",1677),eTS(1681,1,eUF,rG),eUe.td=function(e){ecP(Pp(e,57))},Y5(eWs,"LGraphToCGraphTransformer/lambda$13$Type",1681),eTS(1678,1,eUF,d7),eUe.td=function(e){Tm(this.a,Pp(e,8))},eUe.a=0,Y5(eWs,"LGraphToCGraphTransformer/lambda$14$Type",1678),eTS(1679,1,eUF,he),eUe.td=function(e){Tv(this.a,Pp(e,110))},eUe.a=0,Y5(eWs,"LGraphToCGraphTransformer/lambda$15$Type",1679),eTS(1680,1,eUF,ht),eUe.td=function(e){Tg(this.a,Pp(e,8))},eUe.a=0,Y5(eWs,"LGraphToCGraphTransformer/lambda$16$Type",1680),eTS(1682,1,{},rW),eUe.Kb=function(e){return Dj(),new R1(null,new YI(new Fa(OH(efc(Pp(e,10)).a.Kc(),new c))))},Y5(eWs,"LGraphToCGraphTransformer/lambda$17$Type",1682),eTS(1683,1,eU8,rK),eUe.Mb=function(e){return Dj(),q8(Pp(e,17))},Y5(eWs,"LGraphToCGraphTransformer/lambda$18$Type",1683),eTS(1684,1,eUF,hn),eUe.td=function(e){eex(this.a,Pp(e,17))},Y5(eWs,"LGraphToCGraphTransformer/lambda$19$Type",1684),eTS(1668,1,eUF,hr),eUe.td=function(e){Wj(this.a,Pp(e,145))},Y5(eWs,"LGraphToCGraphTransformer/lambda$2$Type",1668),eTS(1685,1,{},rV),eUe.Kb=function(e){return Dj(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eWs,"LGraphToCGraphTransformer/lambda$20$Type",1685),eTS(1686,1,{},rq),eUe.Kb=function(e){return Dj(),new R1(null,new YI(new Fa(OH(efc(Pp(e,10)).a.Kc(),new c))))},Y5(eWs,"LGraphToCGraphTransformer/lambda$21$Type",1686),eTS(1687,1,{},rZ),eUe.Kb=function(e){return Dj(),Pp(e_k(Pp(e,17),(eBU(),tnO)),15)},Y5(eWs,"LGraphToCGraphTransformer/lambda$22$Type",1687),eTS(1688,1,eU8,rX),eUe.Mb=function(e){return AN(Pp(e,15))},Y5(eWs,"LGraphToCGraphTransformer/lambda$23$Type",1688),eTS(1689,1,eUF,hi),eUe.td=function(e){ekn(this.a,Pp(e,15))},Y5(eWs,"LGraphToCGraphTransformer/lambda$24$Type",1689),eTS(1667,1,eUF,E3),eUe.td=function(e){VK(this.a,this.b,Pp(e,145))},Y5(eWs,"LGraphToCGraphTransformer/lambda$3$Type",1667),eTS(1669,1,{},rJ),eUe.Kb=function(e){return Dj(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eWs,"LGraphToCGraphTransformer/lambda$4$Type",1669),eTS(1670,1,{},rQ),eUe.Kb=function(e){return Dj(),new R1(null,new YI(new Fa(OH(efc(Pp(e,10)).a.Kc(),new c))))},Y5(eWs,"LGraphToCGraphTransformer/lambda$5$Type",1670),eTS(1671,1,{},r1),eUe.Kb=function(e){return Dj(),Pp(e_k(Pp(e,17),(eBU(),tnO)),15)},Y5(eWs,"LGraphToCGraphTransformer/lambda$6$Type",1671),eTS(1673,1,eUF,ha),eUe.td=function(e){exr(this.a,Pp(e,15))},Y5(eWs,"LGraphToCGraphTransformer/lambda$8$Type",1673),eTS(1674,1,eUF,E4),eUe.td=function(e){MN(this.a,this.b,Pp(e,145))},Y5(eWs,"LGraphToCGraphTransformer/lambda$9$Type",1674),eTS(1663,1,{},r0),eUe.Le=function(e){var t,n,r,i,a;for(this.a=e,this.d=new bX,this.c=Je(e24,eUp,121,this.a.a.a.c.length,0,1),this.b=0,n=new fz(this.a.a.a);n.a=b&&(P_(a,ell(l)),v=eB4.Math.max(v,y[l-1]-f),s+=p,m+=y[l-1]-m,f=y[l-1],p=u[l]),p=eB4.Math.max(p,u[l]),++l;s+=p}(h=eB4.Math.min(1/v,1/t.b/s))>r&&(r=h,n=a)}return n},eUe.Wf=function(){return!1},Y5(eWb,"MSDCutIndexHeuristic",802),eTS(1617,1,eGB,iB),eUe.pf=function(e,t){eNZ(Pp(e,37),t)},Y5(eWb,"SingleEdgeGraphWrapper",1617),eTS(227,22,{3:1,35:1,22:1,227:1},Ss);var e4K=enw(eWm,"CenterEdgeLabelPlacementStrategy",227,e1G,Jv,DU);eTS(422,22,{3:1,35:1,22:1,422:1},Su);var e4V=enw(eWm,"ConstraintCalculationStrategy",422,e1G,$G,DH);eTS(314,22,{3:1,35:1,22:1,314:1,246:1,234:1},Sc),eUe.Kf=function(){return ekF(this)},eUe.Xf=function(){return ekF(this)};var e4q=enw(eWm,"CrossingMinimizationStrategy",314,e1G,G5,D$);eTS(337,22,{3:1,35:1,22:1,337:1},Sl);var e4Z=enw(eWm,"CuttingStrategy",337,e1G,G6,DW);eTS(335,22,{3:1,35:1,22:1,335:1,246:1,234:1},Sf),eUe.Kf=function(){return eTW(this)},eUe.Xf=function(){return eTW(this)};var e4X=enw(eWm,"CycleBreakingStrategy",335,e1G,Zv,DK);eTS(419,22,{3:1,35:1,22:1,419:1},Sd);var e4J=enw(eWm,"DirectionCongruency",419,e1G,$z,DV);eTS(450,22,{3:1,35:1,22:1,450:1},Sh);var e4Q=enw(eWm,"EdgeConstraint",450,e1G,G9,Dq);eTS(276,22,{3:1,35:1,22:1,276:1},Sp);var e41=enw(eWm,"EdgeLabelSideSelection",276,e1G,JE,DZ);eTS(479,22,{3:1,35:1,22:1,479:1},Sb);var e40=enw(eWm,"EdgeStraighteningStrategy",479,e1G,$$,DX);eTS(274,22,{3:1,35:1,22:1,274:1},Sm);var e42=enw(eWm,"FixedAlignment",274,e1G,Jw,DJ);eTS(275,22,{3:1,35:1,22:1,275:1},Sg);var e43=enw(eWm,"GraphCompactionStrategy",275,e1G,Jy,DQ);eTS(256,22,{3:1,35:1,22:1,256:1},Sv);var e44=enw(eWm,"GraphProperties",256,e1G,eiT,D1);eTS(292,22,{3:1,35:1,22:1,292:1},Sy);var e45=enw(eWm,"GreedySwitchType",292,e1G,We,D0);eTS(303,22,{3:1,35:1,22:1,303:1},Sw);var e46=enw(eWm,"InLayerConstraint",303,e1G,G7,D2);eTS(420,22,{3:1,35:1,22:1,420:1},S_);var e49=enw(eWm,"InteractiveReferencePoint",420,e1G,$W,D3);eTS(163,22,{3:1,35:1,22:1,163:1},ST);var e48=enw(eWm,"LayerConstraint",163,e1G,Z_,D4);eTS(848,1,e$2,cT),eUe.Qe=function(e){efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWE),""),"Direction Congruency"),"Specifies how drawings of the same graph with different layout directions compare to each other: either a natural reading direction is preserved or the drawings are rotated versions of each other."),trl),(eSd(),tdv)),e4J),el9((epx(),tdh))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWS),""),"Feedback Edges"),"Whether feedback edges should be highlighted by routing around the nodes."),(OQ(),!1)),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWk),""),"Interactive Reference Point"),"Determines which point of a node is considered by interactive layout phases."),trN),tdv),e49),el9(tdh)))),K_(e,eWk,eWI,trR),K_(e,eWk,eWH,trP),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWx),""),"Merge Edges"),"Edges that have no ports are merged so they touch the connected nodes at the same points. When this option is disabled, one port is created for each edge directly connected to a node. When it is enabled, all such incoming edges share an input port, and all outgoing edges share an output port."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWT),""),"Merge Hierarchy-Crossing Edges"),"If hierarchical layout is active, hierarchy-crossing edges use as few hierarchical ports as possible. They are broken by the algorithm, with hierarchical ports inserted as required. Usually, one such port is created for each edge at each hierarchy crossing point. With this option set to true, we try to create as few hierarchical ports as possible in the process. In particular, all edges that form a hyperedge can share a port."),!0),tdm),e11),el9(tdh)))),efO(e,new eE8(v8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWM),""),"Allow Non-Flow Ports To Switch Sides"),"Specifies whether non-flow ports may switch sides if their node's port constraints are either FIXED_SIDE or FIXED_ORDER. A non-flow port is a port on a side that is not part of the currently configured layout flow. For instance, given a left-to-right layout direction, north and south ports would be considered non-flow ports. Further note that the underlying criterium whether to switch sides or not solely relies on the minimization of edge crossings. Hence, edge length and other aesthetics criteria are not addressed."),!1),tdm),e11),el9(tdp)),eow(vx(e17,1),eUP,2,6,["org.eclipse.elk.layered.northOrSouthPort"])))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWO),""),"Port Sorting Strategy"),"Only relevant for nodes with FIXED_SIDE port constraints. Determines the way a node's ports are distributed on the sides of a node if their order is not prescribed. The option is set on parent nodes."),tic),tdv),e5a),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWA),""),"Thoroughness"),"How much effort should be spent to produce a nice layout."),ell(7)),tdw),e15),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWL),""),"Add Unnecessary Bendpoints"),"Adds bend points even if an edge does not change direction. If true, each long edge dummy will contribute a bend point to its edges and hierarchy-crossing edges will always get a bend point where they cross hierarchy boundaries. By default, bend points are only added where an edge changes direction."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWC),""),"Generate Position and Layer IDs"),"If enabled position id and layer id are generated, which are usually only used internally when setting the interactiveLayout option. This option should be specified on the root node."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWI),"cycleBreaking"),"Cycle Breaking Strategy"),"Strategy for cycle breaking. Cycle breaking looks for cycles in the graph and determines which edges to reverse to break the cycles. Reversed edges will end up pointing to the opposite direction of regular edges (that is, reversed edges will point left if edges usually point right)."),tru),tdv),e4X),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWD),eKC),"Node Layering Strategy"),"Strategy for node layering."),trX),tdv),e47),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWN),eKC),"Layer Constraint"),"Determines a constraint on the placement of the node regarding the layering."),trU),tdv),e48),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWP),eKC),"Layer Choice Constraint"),"Allows to set a constraint regarding the layer placement of a node. Let i be the value of teh constraint. Assumed the drawing has n layers and i < n. If set to i, it expresses that the node should be placed in i-th layer. Should i>=n be true then the node is placed in the last layer of the drawing. Note that this option is not part of any of ELK Layered's default configurations but is only evaluated as part of the `InteractiveLayeredGraphVisitor`, which must be applied manually or used via the `DiagramLayoutEngine."),ell(-1)),tdw),e15),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWR),eKC),"Layer ID"),"Layer identifier that was calculated by ELK Layered for a node. This is only generated if interactiveLayot or generatePositionAndLayerIds is set."),ell(-1)),tdw),e15),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWj),eKI),"Upper Bound On Width [MinWidth Layerer]"),"Defines a loose upper bound on the width of the MinWidth layerer. If set to '-1' multiple values are tested and the best result is selected."),ell(4)),tdw),e15),el9(tdh)))),K_(e,eWj,eWD,trz),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWF),eKI),"Upper Layer Estimation Scaling Factor [MinWidth Layerer]"),"Multiplied with Upper Bound On Width for defining an upper bound on the width of layers which haven't been determined yet, but whose maximum width had been (roughly) estimated by the MinWidth algorithm. Compensates for too high estimations. If set to '-1' multiple values are tested and the best result is selected."),ell(2)),tdw),e15),el9(tdh)))),K_(e,eWF,eWD,trW),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWY),eKD),"Node Promotion Strategy"),"Reduces number of dummy nodes after layering phase (if possible)."),trq),tdv),e5r),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWB),eKD),"Max Node Promotion Iterations"),"Limits the number of iterations for node promotion."),ell(0)),tdw),e15),el9(tdh)))),K_(e,eWB,eWY,null),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWU),"layering.coffmanGraham"),"Layer Bound"),"The maximum number of nodes allowed per layer."),ell(eUu)),tdw),e15),el9(tdh)))),K_(e,eWU,eWD,trF),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWH),eKN),"Crossing Minimization Strategy"),"Strategy for crossing minimization."),tro),tdv),e4q),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW$),eKN),"Force Node Model Order"),"The node order given by the model does not change to produce a better layout. E.g. if node A is before node B in the model this is not changed during crossing minimization. This assumes that the node model order is already respected before crossing minimization. This can be achieved by setting considerModelOrder.strategy to NODES_AND_EDGES."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWz),eKN),"Hierarchical Sweepiness"),"How likely it is to use cross-hierarchy (1) vs bottom-up (-1)."),.1),tdg),e13),el9(tdh)))),K_(e,eWz,eKP,tre),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWG),eKN),"Semi-Interactive Crossing Minimization"),"Preserves the order of nodes within a layer but still minimizes crossings between edges connecting long edge dummies. Derives the desired order from positions specified by the 'org.eclipse.elk.position' layout option. Requires a crossing minimization strategy that is able to process 'in-layer' constraints."),!1),tdm),e11),el9(tdh)))),K_(e,eWG,eWH,tri),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWW),eKN),"Position Choice Constraint"),"Allows to set a constraint regarding the position placement of a node in a layer. Assumed the layer in which the node placed includes n other nodes and i < n. If set to i, it expresses that the node should be placed at the i-th position. Should i>=n be true then the node is placed at the last position in the layer. Note that this option is not part of any of ELK Layered's default configurations but is only evaluated as part of the `InteractiveLayeredGraphVisitor`, which must be applied manually or used via the `DiagramLayoutEngine."),ell(-1)),tdw),e15),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWK),eKN),"Position ID"),"Position within a layer that was determined by ELK Layered for a node. This is only generated if interactiveLayot or generatePositionAndLayerIds is set."),ell(-1)),tdw),e15),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWV),eKR),"Greedy Switch Activation Threshold"),"By default it is decided automatically if the greedy switch is activated or not. The decision is based on whether the size of the input graph (without dummy nodes) is smaller than the value of this option. A '0' enforces the activation."),ell(40)),tdw),e15),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWq),eKR),"Greedy Switch Crossing Minimization"),"Greedy Switch strategy for crossing minimization. The greedy switch heuristic is executed after the regular crossing minimization as a post-processor. Note that if 'hierarchyHandling' is set to 'INCLUDE_CHILDREN', the 'greedySwitchHierarchical.type' option must be used."),tn9),tdv),e45),el9(tdh)))),K_(e,eWq,eWH,tn8),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWZ),"crossingMinimization.greedySwitchHierarchical"),"Greedy Switch Crossing Minimization (hierarchical)"),"Activates the greedy switch heuristic in case hierarchical layout is used. The differences to the non-hierarchical case (see 'greedySwitch.type') are: 1) greedy switch is inactive by default, 3) only the option value set on the node at which hierarchical layout starts is relevant, and 2) if it's activated by the user, it properly addresses hierarchy-crossing edges."),tn3),tdv),e45),el9(tdh)))),K_(e,eWZ,eWH,tn4),K_(e,eWZ,eKP,tn5),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWX),eKj),"Node Placement Strategy"),"Strategy for node placement."),tis),tdv),e5n),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eWJ),eKj),"Favor Straight Edges Over Balancing"),"Favor straight edges over a balanced node placement. The default behavior is determined automatically based on the used 'edgeRouting'. For an orthogonal style it is set to true, for all other styles to false."),tdm),e11),el9(tdh)))),K_(e,eWJ,eWX,tr9),K_(e,eWJ,eWX,tr8),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eWQ),eKF),"BK Edge Straightening"),"Specifies whether the Brandes Koepf node placer tries to increase the number of straight edges at the expense of diagram size. There is a subtle difference to the 'favorStraightEdges' option, which decides whether a balanced placement of the nodes is desired, or not. In bk terms this means combining the four alignments into a single balanced one, or not. This option on the other hand tries to straighten additional edges during the creation of each of the four alignments."),tr0),tdv),e40),el9(tdh)))),K_(e,eWQ,eWX,tr2),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW1),eKF),"BK Fixed Alignment"),"Tells the BK node placer to use a certain alignment (out of its four) instead of the one producing the smallest height, or the combination of all four."),tr4),tdv),e42),el9(tdh)))),K_(e,eW1,eWX,tr5),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW0),"nodePlacement.linearSegments"),"Linear Segments Deflection Dampening"),"Dampens the movement of nodes to keep the diagram from getting too large."),.3),tdg),e13),el9(tdh)))),K_(e,eW0,eWX,tie),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eW2),"nodePlacement.networkSimplex"),"Node Flexibility"),"Aims at shorter and straighter edges. Two configurations are possible: (a) allow ports to move freely on the side they are assigned to (the order is always defined beforehand), (b) additionally allow to enlarge a node wherever it helps. If this option is not configured for a node, the 'nodeFlexibility.default' value is used, which is specified for the node's parent."),tdv),e5t),el9(tdd)))),K_(e,eW2,eWX,tia),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW3),"nodePlacement.networkSimplex.nodeFlexibility"),"Node Flexibility Default"),"Default value of the 'nodeFlexibility' option for the children of a hierarchical node."),tir),tdv),e5t),el9(tdh)))),K_(e,eW3,eWX,tii),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW4),eKY),"Self-Loop Distribution"),"Alter the distribution of the loops around the node. It only takes effect for PortConstraints.FREE."),trv),tdv),e5s),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW5),eKY),"Self-Loop Ordering"),"Alter the ordering of the loops they can either be stacked or sequenced. It only takes effect for PortConstraints.FREE."),tr_),tdv),e5u),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW6),"edgeRouting.splines"),"Spline Routing Mode"),"Specifies the way control points are assembled for each individual edge. CONSERVATIVE ensures that edges are properly routed around the nodes but feels rather orthogonal at times. SLOPPY uses fewer control points to obtain curvier edge routes but may result in edges overlapping nodes."),trS),tdv),e5c),el9(tdh)))),K_(e,eW6,eKB,trk),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW9),"edgeRouting.splines.sloppy"),"Sloppy Spline Layer Spacing Factor"),"Spacing factor for routing area between layers when using sloppy spline routing."),.2),tdg),e13),el9(tdh)))),K_(e,eW9,eKB,trT),K_(e,eW9,eW6,trM),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eW8),"edgeRouting.polyline"),"Sloped Edge Zone Width"),"Width of the strip to the left and to the right of each layer where the polyline edge router is allowed to refrain from ensuring that edges are routed horizontally. This prevents awkward bend points for nodes that extent almost to the edge of their layer."),2),tdg),e13),el9(tdh)))),K_(e,eW8,eKB,trm),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eW7),eKU),"Spacing Base Value"),"An optional base value for all other layout options of the 'spacing' group. It can be used to conveniently alter the overall 'spaciousness' of the drawing. Whenever an explicit value is set for the other layout options, this base value will have no effect. The base value is not inherited, i.e. it must be set for each hierarchical node."),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKe),eKU),"Edge Node Between Layers Spacing"),"The spacing to be preserved between nodes and edges that are routed next to the node's layer. For the spacing between nodes and edges that cross the node's layer 'spacing.edgeNode' is used."),10),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKt),eKU),"Edge Edge Between Layer Spacing"),"Spacing to be preserved between pairs of edges that are routed between the same pair of layers. Note that 'spacing.edgeEdge' is used for the spacing between pairs of edges crossing the same layer."),10),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKn),eKU),"Node Node Between Layers Spacing"),"The spacing to be preserved between any pair of nodes of two adjacent layers. Note that 'spacing.nodeNode' is used for the spacing between nodes within the layer itself."),20),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKr),eKH),"Direction Priority"),"Defines how important it is to have a certain edge point into the direction of the overall layout. This option is evaluated during the cycle breaking phase."),ell(0)),tdw),e15),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKi),eKH),"Shortness Priority"),"Defines how important it is to keep an edge as short as possible. This option is evaluated during the layering phase."),ell(0)),tdw),e15),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKa),eKH),"Straightness Priority"),"Defines how important it is to keep an edge straight, i.e. aligned with one of the two axes. This option is evaluated during node placement."),ell(0)),tdw),e15),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKo),eK$),ezI),"Tries to further compact components (disconnected sub-graphs)."),!1),tdm),e11),el9(tdh)))),K_(e,eKo,eGs,!0),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKs),eKz),"Post Compaction Strategy"),eKG),tnz),tdv),e43),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKu),eKz),"Post Compaction Constraint Calculation"),eKG),tnH),tdv),e4V),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKc),eKW),"High Degree Node Treatment"),"Makes room around high degree nodes to place leafs and trees."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKl),eKW),"High Degree Node Threshold"),"Whether a node is considered to have a high degree."),ell(16)),tdw),e15),el9(tdh)))),K_(e,eKl,eKc,!0),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKf),eKW),"High Degree Node Maximum Tree Height"),"Maximum height of a subtree connected to a high degree node to be moved to separate layers."),ell(5)),tdw),e15),el9(tdh)))),K_(e,eKf,eKc,!0),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKd),eKK),"Graph Wrapping Strategy"),"For certain graphs and certain prescribed drawing areas it may be desirable to split the laid out graph into chunks that are placed side by side. The edges that connect different chunks are 'wrapped' around from the end of one chunk to the start of the other chunk. The points between the chunks are referred to as 'cuts'."),tiU),tdv),e5f),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKh),eKK),"Additional Wrapped Edges Spacing"),"To visually separate edges that are wrapped from regularly routed edges an additional spacing value can be specified in form of this layout option. The spacing is added to the regular edgeNode spacing."),10),tdg),e13),el9(tdh)))),K_(e,eKh,eKd,tiw),K_(e,eKh,eKd,ti_),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKp),eKK),"Correction Factor for Wrapping"),"At times and for certain types of graphs the executed wrapping may produce results that are consistently biased in the same fashion: either wrapping to often or to rarely. This factor can be used to correct the bias. Internally, it is simply multiplied with the 'aspect ratio' layout option."),1),tdg),e13),el9(tdh)))),K_(e,eKp,eKd,tiS),K_(e,eKp,eKd,tik),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKb),eKV),"Cutting Strategy"),"The strategy by which the layer indexes are determined at which the layering crumbles into chunks."),tiC),tdv),e4Z),el9(tdh)))),K_(e,eKb,eKd,tiI),K_(e,eKb,eKd,tiD),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eKm),eKV),"Manually Specified Cuts"),"Allows the user to specify her own cuts for a certain graph."),td_),e1H),el9(tdh)))),K_(e,eKm,eKb,tiT),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKg),"wrapping.cutting.msd"),"MSD Freedom"),"The MSD cutting strategy starts with an initial guess on the number of chunks the graph should be split into. The freedom specifies how much the strategy may deviate from this guess. E.g. if an initial number of 3 is computed, a freedom of 1 allows 2, 3, and 4 cuts."),tiO),tdw),e15),el9(tdh)))),K_(e,eKg,eKb,tiA),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKv),eKq),"Validification Strategy"),"When wrapping graphs, one can specify indices that are not allowed as split points. The validification strategy makes sure every computed split point is allowed."),tiW),tdv),e5l),el9(tdh)))),K_(e,eKv,eKd,tiK),K_(e,eKv,eKd,tiV),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eKy),eKq),"Valid Indices for Wrapping"),null),td_),e1H),el9(tdh)))),K_(e,eKy,eKd,ti$),K_(e,eKy,eKd,tiz),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKw),eKZ),"Improve Cuts"),"For general graphs it is important that not too many edges wrap backwards. Thus a compromise between evenly-distributed cuts and the total number of cut edges is sought."),!0),tdm),e11),el9(tdh)))),K_(e,eKw,eKd,tij),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK_),eKZ),"Distance Penalty When Improving Cuts"),null),2),tdg),e13),el9(tdh)))),K_(e,eK_,eKd,tiP),K_(e,eK_,eKw,!0),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKE),eKZ),"Improve Wrapped Edges"),"The initial wrapping is performed in a very simple way. As a consequence, edges that wrap from one chunk to another may be unnecessarily long. Activating this option tries to shorten such edges."),!0),tdm),e11),el9(tdh)))),K_(e,eKE,eKd,tiY),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKS),eKX),"Edge Label Side Selection"),"Method to decide on edge label sides."),trp),tdv),e41),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKk),eKX),"Edge Center Label Placement Strategy"),"Determines in which layer center labels of long edges should be placed."),trd),tdv),e4K),jL(tdh,eow(vx(e5Q,1),eU4,175,0,[tdf]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKx),eKJ),"Consider Model Order"),"Preserves the order of nodes and edges in the model file if this does not lead to additional edge crossings. Depending on the strategy this is not always possible since the node and edge order might be conflicting."),tnQ),tdv),e5i),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKT),eKJ),"No Model Order"),"Set on a node to not set a model order for this node even though it is a real node."),!1),tdm),e11),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKM),eKJ),"Consider Model Order for Components"),"If set to NONE the usual ordering strategy (by cumulative node priority and size of nodes) is used. INSIDE_PORT_SIDES orders the components with external ports only inside the groups with the same port side. FORCE_MODEL_ORDER enforces the mode order on components. This option might produce bad alignments and sub optimal drawings in terms of used area since the ordering should be respected."),tnW),tdv),e4L),el9(tdh)))),K_(e,eKM,eGs,null),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKO),eKJ),"Long Edge Ordering Strategy"),"Indicates whether long edges are sorted under, over, or equal to nodes that have no connection to a previous layer in a left-to-right or right-to-left layout. Under and over changes to right and left in a vertical layout."),tnZ),tdv),e5e),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKA),eKJ),"Crossing Counter Node Order Influence"),"Indicates with what percentage (1 for 100%) violations of the node model order are weighted against the crossings e.g. a value of 0.5 means two model order violations are as important as on edge crossing. This allows some edge crossings in favor of preserving the model order. It is advised to set this value to a very small positive value (e.g. 0.001) to have minimal crossing and a optimal node order. Defaults to no influence (0)."),0),tdg),e13),el9(tdh)))),K_(e,eKA,eKx,null),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKL),eKJ),"Crossing Counter Port Order Influence"),"Indicates with what percentage (1 for 100%) violations of the port model order are weighted against the crossings e.g. a value of 0.5 means two model order violations are as important as on edge crossing. This allows some edge crossings in favor of preserving the model order. It is advised to set this value to a very small positive value (e.g. 0.001) to have minimal crossing and a optimal port order. Defaults to no influence (0)."),0),tdg),e13),el9(tdh)))),K_(e,eKL,eKx,null),eBq((new cA,e))},Y5(eWm,"LayeredMetaDataProvider",848),eTS(986,1,e$2,cA),eUe.Qe=function(e){eBq(e)},Y5(eWm,"LayeredOptions",986),eTS(987,1,{},iH),eUe.$e=function(){return new b3},eUe._e=function(e){},Y5(eWm,"LayeredOptions/LayeredFactory",987),eTS(1372,1,{}),eUe.a=0,Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder",1372),eTS(779,1372,{},ef4),Y5(eWm,"LayeredSpacings/LayeredSpacingsBuilder",779),eTS(313,22,{3:1,35:1,22:1,313:1,246:1,234:1},SE),eUe.Kf=function(){return eM3(this)},eUe.Xf=function(){return eM3(this)};var e47=enw(eWm,"LayeringStrategy",313,e1G,J_,D5);eTS(378,22,{3:1,35:1,22:1,378:1},SS);var e5e=enw(eWm,"LongEdgeOrderingStrategy",378,e1G,G4,D6);eTS(197,22,{3:1,35:1,22:1,197:1},Sk);var e5t=enw(eWm,"NodeFlexibility",197,e1G,VT,D9);eTS(315,22,{3:1,35:1,22:1,315:1,246:1,234:1},Sx),eUe.Kf=function(){return eTG(this)},eUe.Xf=function(){return eTG(this)};var e5n=enw(eWm,"NodePlacementStrategy",315,e1G,Zg,Nr);eTS(260,22,{3:1,35:1,22:1,260:1},SM);var e5r=enw(eWm,"NodePromotionStrategy",260,e1G,etL,D7);eTS(339,22,{3:1,35:1,22:1,339:1},SO);var e5i=enw(eWm,"OrderingStrategy",339,e1G,Wn,Ne);eTS(421,22,{3:1,35:1,22:1,421:1},SA);var e5a=enw(eWm,"PortSortingStrategy",421,e1G,$K,Nt);eTS(452,22,{3:1,35:1,22:1,452:1},SL);var e5o=enw(eWm,"PortType",452,e1G,Wt,D8);eTS(375,22,{3:1,35:1,22:1,375:1},SC);var e5s=enw(eWm,"SelfLoopDistributionStrategy",375,e1G,Wr,Nn);eTS(376,22,{3:1,35:1,22:1,376:1},SI);var e5u=enw(eWm,"SelfLoopOrderingStrategy",376,e1G,$H,Ni);eTS(304,1,{304:1},ejm),Y5(eWm,"Spacings",304),eTS(336,22,{3:1,35:1,22:1,336:1},SD);var e5c=enw(eWm,"SplineRoutingMode",336,e1G,Wa,Na);eTS(338,22,{3:1,35:1,22:1,338:1},SN);var e5l=enw(eWm,"ValidifyStrategy",338,e1G,Wo,No);eTS(377,22,{3:1,35:1,22:1,377:1},SP);var e5f=enw(eWm,"WrappingStrategy",377,e1G,Wi,Ns);eTS(1383,1,eVD,cL),eUe.Yf=function(e){return Pp(e,37),ts2},eUe.pf=function(e,t){eRb(this,Pp(e,37),t)},Y5(eVN,"DepthFirstCycleBreaker",1383),eTS(782,1,eVD,jG),eUe.Yf=function(e){return Pp(e,37),ts3},eUe.pf=function(e,t){eBS(this,Pp(e,37),t)},eUe.Zf=function(e){return Pp(RJ(e,ebO(this.d,e.c.length)),10)},Y5(eVN,"GreedyCycleBreaker",782),eTS(1386,782,eVD,kQ),eUe.Zf=function(e){var t,n,r,i;for(i=null,t=eUu,r=new fz(e);r.a1&&(gN(LK(e_k(Bq((GK(0,e.c.length),Pp(e.c[0],10))),(eBy(),ti7))))?eMR(e,this.d,Pp(this,660)):(Hj(),Mv(e,this.d)),eaz(this.e,e))},eUe.Sf=function(e,t,n,r){var i,a,o,s,u,c,l;for(t!=ja(n,e.length)&&(a=e[t-(n?1:-1)],Xy(this.f,a,n?(enY(),tsN):(enY(),tsD))),i=e[t][0],l=!r||i.k==(eEn(),e8C),c=ZW(e[t]),this.ag(c,l,!1,n),o=0,u=new fz(c);u.a"),e0?zJ(this.a,e[t-1],e[t]):!n&&t1&&(gN(LK(e_k(Bq((GK(0,e.c.length),Pp(e.c[0],10))),(eBy(),ti7))))?eMR(e,this.d,this):(Hj(),Mv(e,this.d)),gN(LK(e_k(Bq((GK(0,e.c.length),Pp(e.c[0],10))),ti7)))||eaz(this.e,e))},Y5(eVF,"ModelOrderBarycenterHeuristic",660),eTS(1803,1,e$C,hx),eUe.ue=function(e,t){return eED(this.a,Pp(e,10),Pp(t,10))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVF,"ModelOrderBarycenterHeuristic/lambda$0$Type",1803),eTS(1403,1,eVD,cF),eUe.Yf=function(e){var t;return Pp(e,37),t=TL(tus),RI(t,(e_x(),e8n),(eB$(),e7I)),t},eUe.pf=function(e,t){$w((Pp(e,37),t))},Y5(eVF,"NoCrossingMinimizer",1403),eTS(796,402,eVR,yu),eUe.$f=function(e,t,n){var r,i,a,o,s,u,c,l,f,d,h;switch(f=this.g,n.g){case 1:for(i=0,a=0,l=new fz(e.j);l.a1&&(i.j==(eYu(),tby)?this.b[e]=!0:i.j==tbY&&e>0&&(this.b[e-1]=!0))},eUe.f=0,Y5(eWc,"AllCrossingsCounter",1798),eTS(587,1,{},erH),eUe.b=0,eUe.d=0,Y5(eWc,"BinaryIndexedTree",587),eTS(524,1,{},IQ),Y5(eWc,"CrossingsCounter",524),eTS(1906,1,e$C,hT),eUe.ue=function(e,t){return je(this.a,Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eWc,"CrossingsCounter/lambda$0$Type",1906),eTS(1907,1,e$C,hM),eUe.ue=function(e,t){return jt(this.a,Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eWc,"CrossingsCounter/lambda$1$Type",1907),eTS(1908,1,e$C,hO),eUe.ue=function(e,t){return jn(this.a,Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eWc,"CrossingsCounter/lambda$2$Type",1908),eTS(1909,1,e$C,hA),eUe.ue=function(e,t){return jr(this.a,Pp(e,11),Pp(t,11))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eWc,"CrossingsCounter/lambda$3$Type",1909),eTS(1910,1,eUF,hL),eUe.td=function(e){QT(this.a,Pp(e,11))},Y5(eWc,"CrossingsCounter/lambda$4$Type",1910),eTS(1911,1,eU8,hC),eUe.Mb=function(e){return kq(this.a,Pp(e,11))},Y5(eWc,"CrossingsCounter/lambda$5$Type",1911),eTS(1912,1,eUF,hI),eUe.td=function(e){kV(this,e)},Y5(eWc,"CrossingsCounter/lambda$6$Type",1912),eTS(1913,1,eUF,SF),eUe.td=function(e){var t;Pj(),Vw(this.b,(t=this.a,Pp(e,11),t))},Y5(eWc,"CrossingsCounter/lambda$7$Type",1913),eTS(826,1,e$q,iq),eUe.Lb=function(e){return Pj(),Ln(Pp(e,11),(eBU(),tng))},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return Pj(),Ln(Pp(e,11),(eBU(),tng))},Y5(eWc,"CrossingsCounter/lambda$8$Type",826),eTS(1905,1,{},hD),Y5(eWc,"HyperedgeCrossingsCounter",1905),eTS(467,1,{35:1,467:1},Cq),eUe.wd=function(e){return ehq(this,Pp(e,467))},eUe.b=0,eUe.c=0,eUe.e=0,eUe.f=0;var e5m=Y5(eWc,"HyperedgeCrossingsCounter/Hyperedge",467);eTS(362,1,{35:1,362:1},He),eUe.wd=function(e){return eMf(this,Pp(e,362))},eUe.b=0,eUe.c=0;var e5g=Y5(eWc,"HyperedgeCrossingsCounter/HyperedgeCorner",362);eTS(523,22,{3:1,35:1,22:1,523:1},Sj);var e5v=enw(eWc,"HyperedgeCrossingsCounter/HyperedgeCorner/Type",523,e1G,$V,Nc);eTS(1405,1,eVD,cO),eUe.Yf=function(e){return Pp(e_k(Pp(e,37),(eBU(),tt3)),21).Hc((eLR(),ttw))?tuh:null},eUe.pf=function(e,t){evK(this,Pp(e,37),t)},Y5(eVY,"InteractiveNodePlacer",1405),eTS(1406,1,eVD,cM),eUe.Yf=function(e){return Pp(e_k(Pp(e,37),(eBU(),tt3)),21).Hc((eLR(),ttw))?tup:null},eUe.pf=function(e,t){emS(this,Pp(e,37),t)},Y5(eVY,"LinearSegmentsNodePlacer",1406),eTS(257,1,{35:1,257:1},ma),eUe.wd=function(e){return vH(this,Pp(e,257))},eUe.Fb=function(e){var t;return!!M4(e,257)&&(t=Pp(e,257),this.b==t.b)},eUe.Hb=function(){return this.b},eUe.Ib=function(){return"ls"+e_F(this.e)},eUe.a=0,eUe.b=0,eUe.c=-1,eUe.d=-1,eUe.g=0;var e5y=Y5(eVY,"LinearSegmentsNodePlacer/LinearSegment",257);eTS(1408,1,eVD,jW),eUe.Yf=function(e){return Pp(e_k(Pp(e,37),(eBU(),tt3)),21).Hc((eLR(),ttw))?tug:null},eUe.pf=function(e,t){eBr(this,Pp(e,37),t)},eUe.b=0,eUe.g=0,Y5(eVY,"NetworkSimplexPlacer",1408),eTS(1427,1,e$C,iZ),eUe.ue=function(e,t){return ME(Pp(e,19).a,Pp(t,19).a)},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVY,"NetworkSimplexPlacer/0methodref$compare$Type",1427),eTS(1429,1,e$C,iX),eUe.ue=function(e,t){return ME(Pp(e,19).a,Pp(t,19).a)},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVY,"NetworkSimplexPlacer/1methodref$compare$Type",1429),eTS(649,1,{649:1},SY);var e5w=Y5(eVY,"NetworkSimplexPlacer/EdgeRep",649);eTS(401,1,{401:1},Ht),eUe.b=!1;var e5_=Y5(eVY,"NetworkSimplexPlacer/NodeRep",401);eTS(508,12,{3:1,4:1,20:1,28:1,52:1,12:1,14:1,15:1,54:1,508:1},mu),Y5(eVY,"NetworkSimplexPlacer/Path",508),eTS(1409,1,{},iJ),eUe.Kb=function(e){return Pp(e,17).d.i.k},Y5(eVY,"NetworkSimplexPlacer/Path/lambda$0$Type",1409),eTS(1410,1,eU8,iQ),eUe.Mb=function(e){return Pp(e,267)==(eEn(),e8D)},Y5(eVY,"NetworkSimplexPlacer/Path/lambda$1$Type",1410),eTS(1411,1,{},i1),eUe.Kb=function(e){return Pp(e,17).d.i},Y5(eVY,"NetworkSimplexPlacer/Path/lambda$2$Type",1411),eTS(1412,1,eU8,hN),eUe.Mb=function(e){return Ct(edH(Pp(e,10)))},Y5(eVY,"NetworkSimplexPlacer/Path/lambda$3$Type",1412),eTS(1413,1,eU8,i0),eUe.Mb=function(e){return RM(Pp(e,11))},Y5(eVY,"NetworkSimplexPlacer/lambda$0$Type",1413),eTS(1414,1,eUF,SB),eUe.td=function(e){MP(this.a,this.b,Pp(e,11))},Y5(eVY,"NetworkSimplexPlacer/lambda$1$Type",1414),eTS(1423,1,eUF,hP),eUe.td=function(e){ekS(this.a,Pp(e,17))},Y5(eVY,"NetworkSimplexPlacer/lambda$10$Type",1423),eTS(1424,1,{},i2),eUe.Kb=function(e){return GE(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eVY,"NetworkSimplexPlacer/lambda$11$Type",1424),eTS(1425,1,eUF,hR),eUe.td=function(e){eCe(this.a,Pp(e,10))},Y5(eVY,"NetworkSimplexPlacer/lambda$12$Type",1425),eTS(1426,1,{},i3),eUe.Kb=function(e){return GE(),ell(Pp(e,121).e)},Y5(eVY,"NetworkSimplexPlacer/lambda$13$Type",1426),eTS(1428,1,{},i4),eUe.Kb=function(e){return GE(),ell(Pp(e,121).e)},Y5(eVY,"NetworkSimplexPlacer/lambda$15$Type",1428),eTS(1430,1,eU8,i5),eUe.Mb=function(e){return GE(),Pp(e,401).c.k==(eEn(),e8N)},Y5(eVY,"NetworkSimplexPlacer/lambda$17$Type",1430),eTS(1431,1,eU8,i6),eUe.Mb=function(e){return GE(),Pp(e,401).c.j.c.length>1},Y5(eVY,"NetworkSimplexPlacer/lambda$18$Type",1431),eTS(1432,1,eUF,Hn),eUe.td=function(e){ef2(this.c,this.b,this.d,this.a,Pp(e,401))},eUe.c=0,eUe.d=0,Y5(eVY,"NetworkSimplexPlacer/lambda$19$Type",1432),eTS(1415,1,{},i9),eUe.Kb=function(e){return GE(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eVY,"NetworkSimplexPlacer/lambda$2$Type",1415),eTS(1433,1,eUF,hj),eUe.td=function(e){MD(this.a,Pp(e,11))},eUe.a=0,Y5(eVY,"NetworkSimplexPlacer/lambda$20$Type",1433),eTS(1434,1,{},i8),eUe.Kb=function(e){return GE(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eVY,"NetworkSimplexPlacer/lambda$21$Type",1434),eTS(1435,1,eUF,hF),eUe.td=function(e){Oi(this.a,Pp(e,10))},Y5(eVY,"NetworkSimplexPlacer/lambda$22$Type",1435),eTS(1436,1,eU8,i7),eUe.Mb=function(e){return Ct(e)},Y5(eVY,"NetworkSimplexPlacer/lambda$23$Type",1436),eTS(1437,1,{},ae),eUe.Kb=function(e){return GE(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eVY,"NetworkSimplexPlacer/lambda$24$Type",1437),eTS(1438,1,eU8,hY),eUe.Mb=function(e){return xH(this.a,Pp(e,10))},Y5(eVY,"NetworkSimplexPlacer/lambda$25$Type",1438),eTS(1439,1,eUF,SU),eUe.td=function(e){eSl(this.a,this.b,Pp(e,10))},Y5(eVY,"NetworkSimplexPlacer/lambda$26$Type",1439),eTS(1440,1,eU8,at),eUe.Mb=function(e){return GE(),!q8(Pp(e,17))},Y5(eVY,"NetworkSimplexPlacer/lambda$27$Type",1440),eTS(1441,1,eU8,an),eUe.Mb=function(e){return GE(),!q8(Pp(e,17))},Y5(eVY,"NetworkSimplexPlacer/lambda$28$Type",1441),eTS(1442,1,{},hB),eUe.Ce=function(e,t){return M8(this.a,Pp(e,29),Pp(t,29))},Y5(eVY,"NetworkSimplexPlacer/lambda$29$Type",1442),eTS(1416,1,{},ar),eUe.Kb=function(e){return GE(),new R1(null,new YI(new Fa(OH(efc(Pp(e,10)).a.Kc(),new c))))},Y5(eVY,"NetworkSimplexPlacer/lambda$3$Type",1416),eTS(1417,1,eU8,ai),eUe.Mb=function(e){return GE(),Km(Pp(e,17))},Y5(eVY,"NetworkSimplexPlacer/lambda$4$Type",1417),eTS(1418,1,eUF,hU),eUe.td=function(e){eNB(this.a,Pp(e,17))},Y5(eVY,"NetworkSimplexPlacer/lambda$5$Type",1418),eTS(1419,1,{},aa),eUe.Kb=function(e){return GE(),new R1(null,new Gq(Pp(e,29).a,16))},Y5(eVY,"NetworkSimplexPlacer/lambda$6$Type",1419),eTS(1420,1,eU8,ao),eUe.Mb=function(e){return GE(),Pp(e,10).k==(eEn(),e8N)},Y5(eVY,"NetworkSimplexPlacer/lambda$7$Type",1420),eTS(1421,1,{},as),eUe.Kb=function(e){return GE(),new R1(null,new YI(new Fa(OH(efs(Pp(e,10)).a.Kc(),new c))))},Y5(eVY,"NetworkSimplexPlacer/lambda$8$Type",1421),eTS(1422,1,eU8,au),eUe.Mb=function(e){return GE(),Rc(Pp(e,17))},Y5(eVY,"NetworkSimplexPlacer/lambda$9$Type",1422),eTS(1404,1,eVD,cz),eUe.Yf=function(e){return Pp(e_k(Pp(e,37),(eBU(),tt3)),21).Hc((eLR(),ttw))?tuv:null},eUe.pf=function(e,t){ePV(Pp(e,37),t)},Y5(eVY,"SimpleNodePlacer",1404),eTS(180,1,{180:1},eIW),eUe.Ib=function(){var e;return e="",this.c==(zs(),tuw)?e+=ezn:this.c==tuy&&(e+=ezt),this.o==(zQ(),tuE)?e+=ezh:this.o==tuS?e+="UP":e+="BALANCED",e},Y5(eVH,"BKAlignedLayout",180),eTS(516,22,{3:1,35:1,22:1,516:1},Sz);var e5E=enw(eVH,"BKAlignedLayout/HDirection",516,e1G,$Z,Nl);eTS(515,22,{3:1,35:1,22:1,515:1},S$);var e5S=enw(eVH,"BKAlignedLayout/VDirection",515,e1G,$X,Nf);eTS(1634,1,{},SH),Y5(eVH,"BKAligner",1634),eTS(1637,1,{},eg$),Y5(eVH,"BKCompactor",1637),eTS(654,1,{654:1},ac),eUe.a=0,Y5(eVH,"BKCompactor/ClassEdge",654),eTS(458,1,{458:1},mo),eUe.a=null,eUe.b=0,Y5(eVH,"BKCompactor/ClassNode",458),eTS(1407,1,eVD,kX),eUe.Yf=function(e){return Pp(e_k(Pp(e,37),(eBU(),tt3)),21).Hc((eLR(),ttw))?tux:null},eUe.pf=function(e,t){eBP(this,Pp(e,37),t)},eUe.d=!1,Y5(eVH,"BKNodePlacer",1407),eTS(1635,1,{},al),eUe.d=0,Y5(eVH,"NeighborhoodInformation",1635),eTS(1636,1,e$C,hH),eUe.ue=function(e,t){return etp(this,Pp(e,46),Pp(t,46))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVH,"NeighborhoodInformation/NeighborComparator",1636),eTS(808,1,{}),Y5(eVH,"ThresholdStrategy",808),eTS(1763,808,{},mm),eUe.bg=function(e,t,n){return this.a.o==(zQ(),tuS)?eHQ:eH1},eUe.cg=function(){},Y5(eVH,"ThresholdStrategy/NullThresholdStrategy",1763),eTS(579,1,{579:1},SG),eUe.c=!1,eUe.d=!1,Y5(eVH,"ThresholdStrategy/Postprocessable",579),eTS(1764,808,{},mg),eUe.bg=function(e,t,n){var r,i,a;return(i=t==n,r=this.a.a[n.p]==t,i||r)?(a=e,this.a.c,zs(),i&&(a=ePX(this,t,!0)),isNaN(a)||isFinite(a)||!r||(a=ePX(this,n,!1)),a):e},eUe.cg=function(){for(var e,t,n,r,i;0!=this.d.b;){if((r=eDJ(this,i=Pp(zv(this.d),579))).a)e=r.a,((n=gN(this.a.f[this.a.g[i.b.p].p]))||q8(e)||e.c.i.c!=e.d.i.c)&&((t=eMd(this,i))||Th(this.e,i))}for(;0!=this.e.a.c.length;)eMd(this,Pp(euO(this.e),579))},Y5(eVH,"ThresholdStrategy/SimpleThresholdStrategy",1764),eTS(635,1,{635:1,246:1,234:1},af),eUe.Kf=function(){return eaM(this)},eUe.Xf=function(){return eaM(this)},Y5(eV$,"EdgeRouterFactory",635),eTS(1458,1,eVD,cG),eUe.Yf=function(e){return eLb(Pp(e,37))},eUe.pf=function(e,t){eP7(Pp(e,37),t)},Y5(eV$,"OrthogonalEdgeRouter",1458),eTS(1451,1,eVD,kJ),eUe.Yf=function(e){return ev4(Pp(e,37))},eUe.pf=function(e,t){eYg(this,Pp(e,37),t)},Y5(eV$,"PolylineEdgeRouter",1451),eTS(1452,1,e$q,ad),eUe.Lb=function(e){return eaQ(Pp(e,10))},eUe.Fb=function(e){return this===e},eUe.Mb=function(e){return eaQ(Pp(e,10))},Y5(eV$,"PolylineEdgeRouter/1",1452),eTS(1809,1,eU8,ah),eUe.Mb=function(e){return Pp(e,129).c==(Xa(),tuU)},Y5(eVz,"HyperEdgeCycleDetector/lambda$0$Type",1809),eTS(1810,1,{},ap),eUe.Ge=function(e){return Pp(e,129).d},Y5(eVz,"HyperEdgeCycleDetector/lambda$1$Type",1810),eTS(1811,1,eU8,ab),eUe.Mb=function(e){return Pp(e,129).c==(Xa(),tuU)},Y5(eVz,"HyperEdgeCycleDetector/lambda$2$Type",1811),eTS(1812,1,{},am),eUe.Ge=function(e){return Pp(e,129).d},Y5(eVz,"HyperEdgeCycleDetector/lambda$3$Type",1812),eTS(1813,1,{},ag),eUe.Ge=function(e){return Pp(e,129).d},Y5(eVz,"HyperEdgeCycleDetector/lambda$4$Type",1813),eTS(1814,1,{},av),eUe.Ge=function(e){return Pp(e,129).d},Y5(eVz,"HyperEdgeCycleDetector/lambda$5$Type",1814),eTS(112,1,{35:1,112:1},ea$),eUe.wd=function(e){return v$(this,Pp(e,112))},eUe.Fb=function(e){var t;return!!M4(e,112)&&(t=Pp(e,112),this.g==t.g)},eUe.Hb=function(){return this.g},eUe.Ib=function(){var e,t,n,r;for(e=new O0("{"),r=new fz(this.n);r.a"+this.b+" ("+AK(this.c)+")"},eUe.d=0,Y5(eVz,"HyperEdgeSegmentDependency",129),eTS(520,22,{3:1,35:1,22:1,520:1},SW);var e5k=enw(eVz,"HyperEdgeSegmentDependency/DependencyType",520,e1G,$q,Nd);eTS(1815,1,{},h$),Y5(eVz,"HyperEdgeSegmentSplitter",1815),eTS(1816,1,{},ym),eUe.a=0,eUe.b=0,Y5(eVz,"HyperEdgeSegmentSplitter/AreaRating",1816),eTS(329,1,{329:1},N4),eUe.a=0,eUe.b=0,eUe.c=0,Y5(eVz,"HyperEdgeSegmentSplitter/FreeArea",329),eTS(1817,1,e$C,aT),eUe.ue=function(e,t){return ID(Pp(e,112),Pp(t,112))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVz,"HyperEdgeSegmentSplitter/lambda$0$Type",1817),eTS(1818,1,eUF,Hi),eUe.td=function(e){V5(this.a,this.d,this.c,this.b,Pp(e,112))},eUe.b=0,Y5(eVz,"HyperEdgeSegmentSplitter/lambda$1$Type",1818),eTS(1819,1,{},aM),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,112).e,16))},Y5(eVz,"HyperEdgeSegmentSplitter/lambda$2$Type",1819),eTS(1820,1,{},aO),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,112).j,16))},Y5(eVz,"HyperEdgeSegmentSplitter/lambda$3$Type",1820),eTS(1821,1,{},aA),eUe.Fe=function(e){return gP(LV(e))},Y5(eVz,"HyperEdgeSegmentSplitter/lambda$4$Type",1821),eTS(655,1,{},YJ),eUe.a=0,eUe.b=0,eUe.c=0,Y5(eVz,"OrthogonalRoutingGenerator",655),eTS(1638,1,{},aL),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,112).e,16))},Y5(eVz,"OrthogonalRoutingGenerator/lambda$0$Type",1638),eTS(1639,1,{},aC),eUe.Kb=function(e){return new R1(null,new Gq(Pp(e,112).j,16))},Y5(eVz,"OrthogonalRoutingGenerator/lambda$1$Type",1639),eTS(661,1,{}),Y5(eVG,"BaseRoutingDirectionStrategy",661),eTS(1807,661,{},mv),eUe.dg=function(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b;if(!e.r||e.q)for(l=t+e.o*n,c=new fz(e.n);c.aez8&&(a=l,i=e,r=new kl(f,a),P7(o.a,r),eDD(this,o,i,r,!1),(d=e.r)&&(h=gP(LV(ep3(d.e,0))),r=new kl(h,a),P7(o.a,r),eDD(this,o,i,r,!1),a=t+d.o*n,i=d,r=new kl(h,a),P7(o.a,r),eDD(this,o,i,r,!1)),r=new kl(b,a),P7(o.a,r),eDD(this,o,i,r,!1)))},eUe.eg=function(e){return e.i.n.a+e.n.a+e.a.a},eUe.fg=function(){return eYu(),tbj},eUe.gg=function(){return eYu(),tbw},Y5(eVG,"NorthToSouthRoutingStrategy",1807),eTS(1808,661,{},my),eUe.dg=function(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b;if(!e.r||e.q)for(l=t-e.o*n,c=new fz(e.n);c.aez8&&(a=l,i=e,r=new kl(f,a),P7(o.a,r),eDD(this,o,i,r,!1),(d=e.r)&&(h=gP(LV(ep3(d.e,0))),r=new kl(h,a),P7(o.a,r),eDD(this,o,i,r,!1),a=t-d.o*n,i=d,r=new kl(h,a),P7(o.a,r),eDD(this,o,i,r,!1)),r=new kl(b,a),P7(o.a,r),eDD(this,o,i,r,!1)))},eUe.eg=function(e){return e.i.n.a+e.n.a+e.a.a},eUe.fg=function(){return eYu(),tbw},eUe.gg=function(){return eYu(),tbj},Y5(eVG,"SouthToNorthRoutingStrategy",1808),eTS(1806,661,{},mw),eUe.dg=function(e,t,n){var r,i,a,o,s,u,c,l,f,d,h,p,b;if(!e.r||e.q)for(l=t+e.o*n,c=new fz(e.n);c.aez8&&(a=l,i=e,r=new kl(a,f),P7(o.a,r),eDD(this,o,i,r,!0),(d=e.r)&&(h=gP(LV(ep3(d.e,0))),r=new kl(a,h),P7(o.a,r),eDD(this,o,i,r,!0),a=t+d.o*n,i=d,r=new kl(a,h),P7(o.a,r),eDD(this,o,i,r,!0)),r=new kl(a,b),P7(o.a,r),eDD(this,o,i,r,!0)))},eUe.eg=function(e){return e.i.n.b+e.n.b+e.a.b},eUe.fg=function(){return eYu(),tby},eUe.gg=function(){return eYu(),tbY},Y5(eVG,"WestToEastRoutingStrategy",1806),eTS(813,1,{},eNG),eUe.Ib=function(){return e_F(this.a)},eUe.b=0,eUe.c=!1,eUe.d=!1,eUe.f=0,Y5(eVK,"NubSpline",813),eTS(407,1,{407:1},eA2,za),Y5(eVK,"NubSpline/PolarCP",407),eTS(1453,1,eVD,egt),eUe.Yf=function(e){return ewy(Pp(e,37))},eUe.pf=function(e,t){eYW(this,Pp(e,37),t)},Y5(eVK,"SplineEdgeRouter",1453),eTS(268,1,{268:1},Xt),eUe.Ib=function(){return this.a+" ->("+this.c+") "+this.b},eUe.c=0,Y5(eVK,"SplineEdgeRouter/Dependency",268),eTS(455,22,{3:1,35:1,22:1,455:1},SK);var e5x=enw(eVK,"SplineEdgeRouter/SideToProcess",455,e1G,$J,Nh);eTS(1454,1,eU8,ak),eUe.Mb=function(e){return eAq(),!Pp(e,128).o},Y5(eVK,"SplineEdgeRouter/lambda$0$Type",1454),eTS(1455,1,{},aS),eUe.Ge=function(e){return eAq(),Pp(e,128).v+1},Y5(eVK,"SplineEdgeRouter/lambda$1$Type",1455),eTS(1456,1,eUF,SV),eUe.td=function(e){Rw(this.a,this.b,Pp(e,46))},Y5(eVK,"SplineEdgeRouter/lambda$2$Type",1456),eTS(1457,1,eUF,Sq),eUe.td=function(e){R_(this.a,this.b,Pp(e,46))},Y5(eVK,"SplineEdgeRouter/lambda$3$Type",1457),eTS(128,1,{35:1,128:1},eSB,eRM),eUe.wd=function(e){return vz(this,Pp(e,128))},eUe.b=0,eUe.e=!1,eUe.f=0,eUe.g=0,eUe.j=!1,eUe.k=!1,eUe.n=0,eUe.o=!1,eUe.p=!1,eUe.q=!1,eUe.s=0,eUe.u=0,eUe.v=0,eUe.F=0,Y5(eVK,"SplineSegment",128),eTS(459,1,{459:1},ax),eUe.a=0,eUe.b=!1,eUe.c=!1,eUe.d=!1,eUe.e=!1,eUe.f=0,Y5(eVK,"SplineSegment/EdgeInformation",459),eTS(1234,1,{},ay),Y5(eVJ,ezQ,1234),eTS(1235,1,e$C,aw),eUe.ue=function(e,t){return ek4(Pp(e,135),Pp(t,135))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVJ,ez1,1235),eTS(1233,1,{},y2),Y5(eVJ,"MrTree",1233),eTS(393,22,{3:1,35:1,22:1,393:1,246:1,234:1},SZ),eUe.Kf=function(){return ek6(this)},eUe.Xf=function(){return ek6(this)};var e5T=enw(eVJ,"TreeLayoutPhases",393,e1G,VM,Np);eTS(1130,209,ezL,CJ),eUe.Ze=function(e,t){var n,r,i,a,o,s,u;for(gN(LK(eT8(e,(eTj(),tcA))))||zh(n=new df((_q(),new gM(e)))),o=(eaW(s=new Xn,e),eo3(s,(eR6(),tcl),e),u=new p2,eDf(e,s,u),eDU(e,s,u),s),a=eDO(this.a,o),i=new fz(a);i.a"+WU(this.c):"e_"+esj(this)},Y5(eVQ,"TEdge",188),eTS(135,134,{3:1,135:1,94:1,134:1},Xn),eUe.Ib=function(){var e,t,n,r,i;for(i=null,r=epL(this.b,0);r.b!=r.d.c;)i+=(null==(n=Pp(Vv(r),86)).c||0==n.c.length?"n_"+n.g:"n_"+n.c)+"\n";for(t=epL(this.a,0);t.b!=t.d.c;)i+=((e=Pp(Vv(t),188)).b&&e.c?WU(e.b)+"->"+WU(e.c):"e_"+esj(e))+"\n";return i};var e5M=Y5(eVQ,"TGraph",135);eTS(633,502,{3:1,502:1,633:1,94:1,134:1}),Y5(eVQ,"TShape",633),eTS(86,633,{3:1,502:1,86:1,633:1,94:1,134:1},esH),eUe.Ib=function(){return WU(this)};var e5O=Y5(eVQ,"TNode",86);eTS(255,1,eU$,hz),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){var e;return e=epL(this.a.d,0),new hG(e)},Y5(eVQ,"TNode/2",255),eTS(358,1,eUE,hG),eUe.Nb=function(e){F8(this,e)},eUe.Pb=function(){return Pp(Vv(this.a),188).c},eUe.Ob=function(){return yV(this.a)},eUe.Qb=function(){etu(this.a)},Y5(eVQ,"TNode/2/1",358),eTS(1840,1,eGB,CX),eUe.pf=function(e,t){eNv(this,Pp(e,135),t)},Y5(eV1,"FanProcessor",1840),eTS(327,22,{3:1,35:1,22:1,327:1,234:1},SX),eUe.Kf=function(){switch(this.g){case 0:return new mX;case 1:return new CX;case 2:return new aN;case 3:return new aI;case 4:return new aR;case 5:return new aj;default:throw p7(new gL(eWt+(null!=this.f?this.f:""+this.g)))}};var e5A=enw(eV1,eWn,327,e1G,JS,Nb);eTS(1843,1,eGB,aI),eUe.pf=function(e,t){eMo(this,Pp(e,135),t)},eUe.a=0,Y5(eV1,"LevelHeightProcessor",1843),eTS(1844,1,eU$,aD),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){return Hj(),wV(),e2o},Y5(eV1,"LevelHeightProcessor/1",1844),eTS(1841,1,eGB,aN),eUe.pf=function(e,t){eSP(this,Pp(e,135),t)},eUe.a=0,Y5(eV1,"NeighborsProcessor",1841),eTS(1842,1,eU$,aP),eUe.Jc=function(e){qX(this,e)},eUe.Kc=function(){return Hj(),wV(),e2o},Y5(eV1,"NeighborsProcessor/1",1842),eTS(1845,1,eGB,aR),eUe.pf=function(e,t){eMa(this,Pp(e,135),t)},eUe.a=0,Y5(eV1,"NodePositionProcessor",1845),eTS(1839,1,eGB,mX),eUe.pf=function(e,t){eRm(this,Pp(e,135))},Y5(eV1,"RootProcessor",1839),eTS(1846,1,eGB,aj),eUe.pf=function(e,t){elE(Pp(e,135))},Y5(eV1,"Untreeifyer",1846),eTS(851,1,e$2,c$),eUe.Qe=function(e){efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eV3),""),"Weighting of Nodes"),"Which weighting to use when computing a node order."),tcE),(eSd(),tdv)),e5L),el9((epx(),tdh))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eV4),""),"Search Order"),"Which search order to use when computing a spanning tree."),tcw),tdv),e5C),el9(tdh)))),ejG((new cH,e))},Y5(eV5,"MrTreeMetaDataProvider",851),eTS(994,1,e$2,cH),eUe.Qe=function(e){ejG(e)},Y5(eV5,"MrTreeOptions",994),eTS(995,1,{},aF),eUe.$e=function(){return new CJ},eUe._e=function(e){},Y5(eV5,"MrTreeOptions/MrtreeFactory",995),eTS(480,22,{3:1,35:1,22:1,480:1},SJ);var e5L=enw(eV5,"OrderWeighting",480,e1G,$1,Nm);eTS(425,22,{3:1,35:1,22:1,425:1},SQ);var e5C=enw(eV5,"TreeifyingOrder",425,e1G,$Q,Nv);eTS(1459,1,eVD,cD),eUe.Yf=function(e){return Pp(e,135),tcz},eUe.pf=function(e,t){eiD(this,Pp(e,135),t)},Y5("org.eclipse.elk.alg.mrtree.p1treeify","DFSTreeifyer",1459),eTS(1460,1,eVD,cN),eUe.Yf=function(e){return Pp(e,135),tcG},eUe.pf=function(e,t){eSZ(this,Pp(e,135),t)},Y5("org.eclipse.elk.alg.mrtree.p2order","NodeOrderer",1460),eTS(1461,1,eVD,cI),eUe.Yf=function(e){return Pp(e,135),tcW},eUe.pf=function(e,t){eCh(this,Pp(e,135),t)},eUe.a=0,Y5("org.eclipse.elk.alg.mrtree.p3place","NodePlacer",1461),eTS(1462,1,eVD,cP),eUe.Yf=function(e){return Pp(e,135),tcK},eUe.pf=function(e,t){evm(Pp(e,135),t)},Y5("org.eclipse.elk.alg.mrtree.p4route","EdgeRouter",1462),eTS(495,22,{3:1,35:1,22:1,495:1,246:1,234:1},S1),eUe.Kf=function(){return ede(this)},eUe.Xf=function(){return ede(this)};var e5I=enw(eV8,"RadialLayoutPhases",495,e1G,$0,Ng);eTS(1131,209,ezL,y0),eUe.Ze=function(e,t){var n,r,i,a,o,s;if(n=eS8(this,e),ewG(t,"Radial layout",n.c.length),gN(LK(eT8(e,(egj(),tlm))))||zh(r=new df((_q(),new gM(e)))),s=ewE(e),ebu(e,(Lj(),tcV),s),!s)throw p7(new gL("The given graph is not a tree!"));for(0==(i=gP(LV(eT8(e,tl_))))&&(i=ekB(e)),ebu(e,tl_,i),o=new fz(eS8(this,e));o.a0&&eu8((GV(t-1,e.length),e.charCodeAt(t-1)),eGq);)--t;if(r>=t)throw p7(new gL("The given string does not contain any numbers."));if(2!=(i=eIk(e.substr(r,t-r),",|;|\r|\n")).length)throw p7(new gL("Exactly two numbers are expected, "+i.length+" were found."));try{this.a=eEu(e_H(i[0])),this.b=eEu(e_H(i[1]))}catch(a){if(a=eoa(a),M4(a,127))throw n=a,p7(new gL(eGZ+n));throw p7(a)}},eUe.Ib=function(){return"("+this.a+","+this.b+")"},eUe.a=0,eUe.b=0;var e50=Y5(eGX,"KVector",8);eTS(74,68,{3:1,4:1,20:1,28:1,52:1,14:1,68:1,15:1,74:1,414:1},mE,yc,Lb),eUe.Pc=function(){return euE(this)},eUe.Jf=function(e){var t,n,r,i,a,o;r=eIk(e,",|;|\\(|\\)|\\[|\\]|\\{|\\}| | |\n"),HC(this);try{for(n=0,a=0,i=0,o=0;n0&&(a%2==0?i=eEu(r[n]):o=eEu(r[n]),a>0&&a%2!=0&&P7(this,new kl(i,o)),++a),++n}catch(s){if(s=eoa(s),M4(s,127))throw t=s,p7(new gL("The given string does not match the expected format for vectors."+t));throw p7(s)}},eUe.Ib=function(){var e,t,n;for(e=new O0("("),t=epL(this,0);t.b!=t.d.c;)xM(e,(n=Pp(Vv(t),8)).a+","+n.b),t.b!=t.d.c&&(e.a+="; ");return(e.a+=")",e).a};var e52=Y5(eGX,"KVectorChain",74);eTS(248,22,{3:1,35:1,22:1,248:1},kf);var e53=enw(eZe,"Alignment",248,e1G,Jg,NP);eTS(979,1,e$2,cq),eUe.Qe=function(e){eDj(e)},Y5(eZe,"BoxLayouterOptions",979),eTS(980,1,{},oA),eUe.$e=function(){return new oF},eUe._e=function(e){},Y5(eZe,"BoxLayouterOptions/BoxFactory",980),eTS(291,22,{3:1,35:1,22:1,291:1},kd);var e54=enw(eZe,"ContentAlignment",291,e1G,Jm,NR);eTS(684,1,e$2,cZ),eUe.Qe=function(e){efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eZi),""),"Layout Algorithm"),"Select a specific layout algorithm."),(eSd(),tdE)),e17),el9((epx(),tdh))))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eZa),""),"Resolved Layout Algorithm"),"Meta data associated with the selected algorithm."),td_),e5X),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVi),""),"Alignment"),"Alignment of the selected node relative to other nodes; the exact meaning depends on the used algorithm."),td0),tdv),e53),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,ezG),""),"Aspect Ratio"),"The desired aspect ratio of the drawing, that is the quotient of width by height."),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eZo),""),"Bend Points"),"A fixed list of bend points for the edge. This is used by the 'Fixed Layout' algorithm to specify a pre-defined routing for an edge. The vector chain must include the source point, any bend points, and the target point, so it must have at least two points."),td_),e52),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVg),""),"Content Alignment"),"Specifies how the content of a node are aligned. Each node can individually control the alignment of its contents. I.e. if a node should be aligned top left in its parent node, the parent node should specify that option."),td8),tdy),e54),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVr),""),"Debug Mode"),"Whether additional debug information shall be generated."),(OQ(),!1)),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVu),""),ezw),"Overall direction of edges: horizontal (right / left) or vertical (down / up)."),tht),tdv),e55),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKB),""),"Edge Routing"),"What kind of edge routing style should be applied for the content of a parent node. Algorithms may also set this option to single edges in order to mark them as splines. The bend point list of edges with this option set to SPLINES must be interpreted as control points for a piecewise cubic spline."),tho),tdv),e59),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eqC),""),"Expand Nodes"),"If active, nodes are expanded to fill the area of their parent."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKP),""),"Hierarchy Handling"),"Determines whether separate layout runs are triggered for different compound nodes in a hierarchical graph. Setting a node's hierarchy handling to `INCLUDE_CHILDREN` will lay out that node and all of its descendants in a single layout run, until a descendant is encountered which has its hierarchy handling set to `SEPARATE_CHILDREN`. In general, `SEPARATE_CHILDREN` will ensure that a new layout run is triggered for a node with that setting. Including multiple levels of hierarchy in a single layout run may allow cross-hierarchical edges to be laid out properly. If the root node is set to `INHERIT` (or not set at all), the default behavior is `SEPARATE_CHILDREN`."),thf),tdv),e57),jL(tdh,eow(vx(e5Q,1),eU4,175,0,[tdd]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ezW),""),"Padding"),"The padding to be left to a parent element's border when placing child elements. This can also serve as an output option of a layout algorithm if node size calculation is setup appropriately."),thP),td_),e4R),jL(tdh,eow(vx(e5Q,1),eU4,175,0,[tdd]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGu),""),"Interactive"),"Whether the algorithm should be run in interactive mode for the content of a parent node. What this means exactly depends on how the specific algorithm interprets this option. Usually in the interactive mode algorithms try to modify the current layout as little as possible."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVA),""),"interactive Layout"),"Whether the graph should be changeable interactively and by setting constraints"),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGf),""),"Omit Node Micro Layout"),"Node micro layout comprises the computation of node dimensions (if requested), the placement of ports and their labels, and the placement of node labels. The functionality is implemented independent of any specific layout algorithm and shouldn't have any negative impact on the layout algorithm's performance itself. Yet, if any unforeseen behavior occurs, this option allows to deactivate the micro layout."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGc),""),"Port Constraints"),"Defines constraints of the position of the ports of a node."),thq),tdv),e6r),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVT),""),"Position"),"The position of a node, port, or label. This is used by the 'Fixed Layout' algorithm to specify a pre-defined position."),td_),e50),jL(tdd,eow(vx(e5Q,1),eU4,175,0,[tdp,tdf]))))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eGr),""),"Priority"),"Defines the priority of an object; its meaning depends on the specific layout algorithm and the context where it is used."),tdw),e15),jL(tdd,eow(vx(e5Q,1),eU4,175,0,[tdl]))))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eGo),""),"Randomization Seed"),"Seed used for pseudo-random number generators to control the layout algorithm. If the value is 0, the seed shall be determined pseudo-randomly (e.g. from the system time)."),tdw),e15),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eGs),""),"Separate Connected Components"),"Whether each connected component should be processed separately."),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVv),""),"Junction Points"),"This option is not used as option, but as output of the layout algorithms. It is attached to edges and determines the points where junction symbols should be drawn in order to represent hyperedges with orthogonal routing. Whether such points are computed depends on the chosen layout algorithm and edge routing style. The points are put into the vector chain with no specific order."),thv),td_),e52),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eV_),""),"Comment Box"),"Whether the node should be regarded as a comment box instead of a regular node. In that case its placement should be similar to how labels are handled. Any edges incident to a comment box specify to which graph elements the comment is related."),!1),tdm),e11),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVE),""),"Hypernode"),"Whether the node should be handled as a hypernode."),!1),tdm),e11),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eZs),""),"Label Manager"),"Label managers can shorten labels upon a layout algorithm's request."),td_),tyO),jL(tdh,eow(vx(e5Q,1),eU4,175,0,[tdf]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVM),""),"Margins"),"Margins define additional space around the actual bounds of a graph element. For instance, ports or labels being placed on the outside of a node's border might introduce such a margin. The margin is used to guarantee non-overlap of other graph elements with those ports or labels."),thw),td_),e4D),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVt),""),"No Layout"),"No layout is done for the associated element. This is used to mark parts of a diagram to avoid their inclusion in the layout graph, or to mark parts of the layout graph to prevent layout engines from processing them. If you wish to exclude the contents of a compound node from automatic layout, while the node itself is still considered on its own layer, use the 'Fixed Layout' algorithm for that node."),!1),tdm),e11),jL(tdd,eow(vx(e5Q,1),eU4,175,0,[tdl,tdp,tdf]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZu),""),"Scale Factor"),"The scaling factor to be applied to the corresponding node in recursive layout. It causes the corresponding node's size to be adjusted, and its ports and labels to be sized and placed accordingly after the layout of that node has been determined (and before the node itself and its siblings are arranged). The scaling is not reverted afterwards, so the resulting layout graph contains the adjusted size and position data. This option is currently not supported if 'Layout Hierarchy' is set."),1),tdg),e13),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZc),""),"Animate"),"Whether the shift from the old layout to the new computed layout shall be animated."),!0),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZl),""),"Animation Time Factor"),"Factor for computation of animation time. The higher the value, the longer the animation time. If the value is 0, the resulting time is always equal to the minimum defined by 'Minimal Animation Time'."),ell(100)),tdw),e15),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZf),""),"Layout Ancestors"),"Whether the hierarchy levels on the path from the selected element to the root of the diagram shall be included in the layout process."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZd),""),"Maximal Animation Time"),"The maximal time for animations, in milliseconds."),ell(4e3)),tdw),e15),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZh),""),"Minimal Animation Time"),"The minimal time for animations, in milliseconds."),ell(400)),tdw),e15),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZp),""),"Progress Bar"),"Whether a progress bar shall be displayed during layout computations."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZb),""),"Validate Graph"),"Whether the graph shall be validated before any layout algorithm is applied. If this option is enabled and at least one error is found, the layout process is aborted and a message is shown to the user."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZm),""),"Validate Options"),"Whether layout options shall be validated before any layout algorithm is applied. If this option is enabled and at least one error is found, the layout process is aborted and a message is shown to the user."),!0),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZg),""),"Zoom to Fit"),"Whether the zoom level shall be set to view the whole diagram after layout."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZr),"box"),"Box Layout Mode"),"Configures the packing mode used by the {@link BoxLayoutProvider}. If SIMPLE is not required (neither priorities are used nor the interactive mode), GROUP_DEC can improve the packing and decrease the area. GROUP_MIXED and GROUP_INC may, in very specific scenarios, work better."),td5),tdv),e6u),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eKQ),eKU),"Comment Comment Spacing"),"Spacing to be preserved between a comment box and other comment boxes connected to the same node. The space left between comment boxes of different nodes is controlled by the node-node spacing."),10),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK1),eKU),"Comment Node Spacing"),"Spacing to be preserved between a node and its connected comment boxes. The space left between a node and the comments of another node is controlled by the node-node spacing."),10),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ez$),eKU),"Components Spacing"),"Spacing to be preserved between pairs of connected components. This option is only relevant if 'separateConnectedComponents' is activated."),20),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK0),eKU),"Edge Spacing"),"Spacing to be preserved between any two edges. Note that while this can somewhat easily be satisfied for the segments of orthogonally drawn edges, it is harder for general polylines or splines."),10),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGa),eKU),"Edge Label Spacing"),"The minimal distance to be preserved between a label and the edge it is associated with. Note that the placement of a label is influenced by the 'edgelabels.placement' option."),2),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK2),eKU),"Edge Node Spacing"),"Spacing to be preserved between nodes and edges."),10),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK3),eKU),"Label Spacing"),"Determines the amount of space to be left between two labels of the same graph element."),0),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK6),eKU),"Label Node Spacing"),"Spacing to be preserved between labels and the border of node they are associated with. Note that the placement of a label is influenced by the 'nodelabels.placement' option."),5),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK4),eKU),"Horizontal spacing between Label and Port"),"Horizontal spacing to be preserved between labels and the ports they are associated with. Note that the placement of a label is influenced by the 'portlabels.placement' option."),1),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK5),eKU),"Vertical spacing between Label and Port"),"Vertical spacing to be preserved between labels and the ports they are associated with. Note that the placement of a label is influenced by the 'portlabels.placement' option."),1),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGi),eKU),"Node Spacing"),"The minimal distance to be preserved between each two nodes."),20),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK9),eKU),"Node Self Loop Spacing"),"Spacing to be preserved between a node and its self loops."),10),tdg),e13),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eK8),eKU),"Port Spacing"),"Spacing between pairs of ports of the same node."),10),tdg),e13),jL(tdh,eow(vx(e5Q,1),eU4,175,0,[tdd]))))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eK7),eKU),"Individual Spacing"),"Allows to specify individual spacing values for graph elements that shall be different from the value specified for the element's parent."),td_),e6c),jL(tdd,eow(vx(e5Q,1),eU4,175,0,[tdl,tdp,tdf]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVO),eKU),"Additional Port Space"),"Additional space around the sets of ports on each node side. For each side of a node, this option can reserve additional space before and after the ports on each side. For example, a top spacing of 20 makes sure that the first port on the western and eastern side is 20 units away from the northern border."),tph),td_),e4D),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVx),eZ_),"Layout Partition"),"Partition to which the node belongs. This requires Layout Partitioning to be active. Nodes with lower partition IDs will appear to the left of nodes with higher partition IDs (assuming a left-to-right layout direction)."),tdw),e15),jL(tdh,eow(vx(e5Q,1),eU4,175,0,[tdd]))))),K_(e,eVx,eVk,thY),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVk),eZ_),"Layout Partitioning"),"Whether to activate partitioned layout. This will allow to group nodes through the Layout Partition option. a pair of nodes with different partition indices is then placed such that the node with lower index is placed to the left of the other node (with left-to-right layout direction). Depending on the layout algorithm, this may only be guaranteed to work if all nodes have a layout partition configured, or at least if edges that cross partitions are not part of a partition-crossing cycle."),thj),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVc),eZE),"Node Label Padding"),"Define padding for node labels that are placed inside of a node."),thE),td_),e4R),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGp),eZE),"Node Label Placement"),"Hints for where node labels are to be placed; if empty, the node label's position is not modified."),thk),tdy),e6t),jL(tdd,eow(vx(e5Q,1),eU4,175,0,[tdf]))))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVd),eZS),"Port Alignment"),"Defines the default port distribution for a node. May be overridden for each side individually."),thU),tdv),e6n),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVh),eZS),"Port Alignment (North)"),"Defines how ports on the northern side are placed, overriding the node's general port alignment."),tdv),e6n),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVp),eZS),"Port Alignment (South)"),"Defines how ports on the southern side are placed, overriding the node's general port alignment."),tdv),e6n),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVb),eZS),"Port Alignment (West)"),"Defines how ports on the western side are placed, overriding the node's general port alignment."),tdv),e6n),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVm),eZS),"Port Alignment (East)"),"Defines how ports on the eastern side are placed, overriding the node's general port alignment."),tdv),e6n),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGh),eZk),"Node Size Constraints"),"What should be taken into account when calculating a node's size. Empty size constraints specify that a node's size is already fixed and should not be changed."),thT),tdy),e6o),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGd),eZk),"Node Size Options"),"Options modifying the behavior of the size constraints set on a node. Each member of the set specifies something that should be taken into account when calculating node sizes. The empty set corresponds to no further modifications."),thC),tdy),e6s),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGM),eZk),"Node Size Minimum"),"The minimal size to which a node can be reduced."),thA),td_),e50),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVs),eZk),"Fixed Graph Size"),"By default, the fixed layout provider will enlarge a graph until it is large enough to contain its children. If this option is set, it won't do so."),!1),tdm),e11),el9(tdh)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVy),eKX),"Edge Label Placement"),"Gives a hint on where to put edge labels."),thi),tdv),e56),el9(tdf)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGl),eKX),"Inline Edge Labels"),"If true, an edge label is placed directly on its edge. May only apply to center edge labels. This kind of label placement is only advisable if the label's rendering is such that it is not crossed by its edge and thus stays legible."),!1),tdm),e11),el9(tdf)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eZv),"font"),"Font Name"),"Font name used for a label."),tdE),e17),el9(tdf)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eZy),"font"),"Font Size"),"Font size used for a label."),tdw),e15),el9(tdf)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVS),eZx),"Port Anchor Offset"),"The offset to the port position where connections shall be attached."),td_),e50),el9(tdp)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVw),eZx),"Port Index"),"The index of a port in the fixed order around a node. The order is assumed as clockwise, starting with the leftmost port on the top side. This option must be set if 'Port Constraints' is set to FIXED_ORDER and no specific positions are given for the ports. Additionally, the option 'Port Side' must be defined in this case."),tdw),e15),el9(tdp)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVn),eZx),"Port Side"),"The side of a node on which a port is situated. This option must be set if 'Port Constraints' is set to FIXED_SIDE or FIXED_ORDER and no specific positions are given for the ports."),th2),tdv),e6a),el9(tdp)))),efO(e,new eE8(yt(ye(yn(v4(v7(v6(v9(new oN,eVe),eZx),"Port Border Offset"),"The offset of ports on the node border. With a positive offset the port is moved outside of the node, while with a negative offset the port is moved towards the inside. An offset of 0 means that the port is placed directly on the node border, i.e. if the port side is north, the port's south border touches the nodes's north border; if the port side is east, the port's west border touches the nodes's east border; if the port side is south, the port's north border touches the node's south border; if the port side is west, the port's east border touches the node's west border."),tdg),e13),el9(tdp)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eGb),eZT),"Port Label Placement"),"Decides on a placement method for port labels; if empty, the node label's position is not modified."),thQ),tdy),e6i),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVl),eZT),"Port Labels Next to Port"),"Use 'portLabels.placement': NEXT_TO_PORT_OF_POSSIBLE."),!1),tdm),e11),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVf),eZT),"Treat Port Labels as Group"),"If this option is true (default), the labels of a port will be treated as a group when it comes to centering them next to their port. If this option is false, only the first label will be centered next to the port, with the others being placed below. This only applies to labels of eastern and western ports and will have no effect if labels are not placed next to their port."),!0),tdm),e11),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVa),eZM),"Activate Inside Self Loops"),"Whether this node allows to route self loops inside of it instead of around it. If set to true, this will make the node a compound node if it isn't already, and will require the layout algorithm to support compound nodes with hierarchical ports."),!1),tdm),e11),el9(tdd)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eVo),eZM),"Inside Self Loop"),"Whether a self loop should be routed inside a node instead of around that node."),!1),tdm),e11),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,ezz),"edge"),"Edge Thickness"),"The thickness of an edge. This is a hint on the line width used to draw an edge, possibly requiring more space to be reserved for it."),1),tdg),e13),el9(tdl)))),efO(e,new eE8(yt(ye(yn(v5(v4(v7(v6(v9(new oN,eZw),"edge"),"Edge Type"),"The type of an edge. This is usually used for UML class diagrams, where associations must be handled differently from generalizations."),thu),tdv),e58),el9(tdl)))),_B(e,new GM(v0(v3(v2(new of,eG1),"Layered"),'The layer-based method was introduced by Sugiyama, Tagawa and Toda in 1981. It emphasizes the direction of edges by pointing as many edges as possible into the same direction. The nodes are arranged in layers, which are sometimes called "hierarchies", and then reordered such that the number of edge crossings is minimized. Afterwards, concrete coordinates are computed for the nodes and edge bend points.'))),_B(e,new GM(v0(v3(v2(new of,"org.eclipse.elk.orthogonal"),"Orthogonal"),'Orthogonal methods that follow the "topology-shape-metrics" approach by Batini, Nardelli and Tamassia \'86. The first phase determines the topology of the drawing by applying a planarization technique, which results in a planar representation of the graph. The orthogonal shape is computed in the second phase, which aims at minimizing the number of edge bends, and is called orthogonalization. The third phase leads to concrete coordinates for nodes and edge bend points by applying a compaction method, thus defining the metrics.'))),_B(e,new GM(v0(v3(v2(new of,eGn),"Force"),"Layout algorithms that follow physical analogies by simulating a system of attractive and repulsive forces. The first successful method of this kind was proposed by Eades in 1984."))),_B(e,new GM(v0(v3(v2(new of,"org.eclipse.elk.circle"),"Circle"),"Circular layout algorithms emphasize cycles or biconnected components of a graph by arranging them in circles. This is useful if a drawing is desired where such components are clearly grouped, or where cycles are shown as prominent OPTIONS of the graph."))),_B(e,new GM(v0(v3(v2(new of,eV9),"Tree"),"Specialized layout methods for trees, i.e. acyclic graphs. The regular structure of graphs that have no undirected cycles can be emphasized using an algorithm of this type."))),_B(e,new GM(v0(v3(v2(new of,"org.eclipse.elk.planar"),"Planar"),"Algorithms that require a planar or upward planar graph. Most of these algorithms are theoretically interesting, but not practically usable."))),_B(e,new GM(v0(v3(v2(new of,eqp),"Radial"),"Radial layout algorithms usually position the nodes of the graph on concentric circles."))),eIm((new cX,e)),eDj((new cq,e)),eL6((new cJ,e))},Y5(eZe,"CoreOptions",684),eTS(103,22,{3:1,35:1,22:1,103:1},kh);var e55=enw(eZe,ezw,103,e1G,Zh,NY);eTS(272,22,{3:1,35:1,22:1,272:1},kp);var e56=enw(eZe,"EdgeLabelPlacement",272,e1G,Wp,NB);eTS(218,22,{3:1,35:1,22:1,218:1},kb);var e59=enw(eZe,"EdgeRouting",218,e1G,VC,NU);eTS(312,22,{3:1,35:1,22:1,312:1},km);var e58=enw(eZe,"EdgeType",312,e1G,Jx,NH);eTS(977,1,e$2,cX),eUe.Qe=function(e){eIm(e)},Y5(eZe,"FixedLayouterOptions",977),eTS(978,1,{},o$),eUe.$e=function(){return new oR},eUe._e=function(e){},Y5(eZe,"FixedLayouterOptions/FixedFactory",978),eTS(334,22,{3:1,35:1,22:1,334:1},kg);var e57=enw(eZe,"HierarchyHandling",334,e1G,Wh,N$);eTS(285,22,{3:1,35:1,22:1,285:1},kv);var e6e=enw(eZe,"LabelSide",285,e1G,VL,Nz);eTS(93,22,{3:1,35:1,22:1,93:1},ky);var e6t=enw(eZe,"NodeLabelPlacement",93,e1G,ene,NG);eTS(249,22,{3:1,35:1,22:1,249:1},kw);var e6n=enw(eZe,"PortAlignment",249,e1G,Zp,NW);eTS(98,22,{3:1,35:1,22:1,98:1},k_);var e6r=enw(eZe,"PortConstraints",98,e1G,X0,NK);eTS(273,22,{3:1,35:1,22:1,273:1},kE);var e6i=enw(eZe,"PortLabelPlacement",273,e1G,Jk,NV);eTS(61,22,{3:1,35:1,22:1,61:1},kS);var e6a=enw(eZe,"PortSide",61,e1G,q5,NX);eTS(981,1,e$2,cJ),eUe.Qe=function(e){eL6(e)},Y5(eZe,"RandomLayouterOptions",981),eTS(982,1,{},oz),eUe.$e=function(){return new oV},eUe._e=function(e){},Y5(eZe,"RandomLayouterOptions/RandomFactory",982),eTS(374,22,{3:1,35:1,22:1,374:1},kk);var e6o=enw(eZe,"SizeConstraint",374,e1G,VA,Nq);eTS(259,22,{3:1,35:1,22:1,259:1},kx);var e6s=enw(eZe,"SizeOptions",259,e1G,en2,NZ);eTS(370,1,{1949:1},mV),eUe.b=!1,eUe.c=0,eUe.d=-1,eUe.e=null,eUe.f=null,eUe.g=-1,eUe.j=!1,eUe.k=!1,eUe.n=!1,eUe.o=0,eUe.q=0,eUe.r=0,Y5(eVL,"BasicProgressMonitor",370),eTS(972,209,ezL,oF),eUe.Ze=function(e,t){var n,r,i,a,o,s,u,c,l;(ewG(t,"Box layout",2),i=gR(LV(eT8(e,(e_C(),tdG)))),a=Pp(eT8(e,tdH),116),n=gN(LK(eT8(e,tdj))),r=gN(LK(eT8(e,tdF))),0===Pp(eT8(e,tdP),311).g)?(o=(s=new I4((e.a||(e.a=new FQ(e6k,e,10,11)),e.a)),Hj(),Mv(s,new h3(r)),s),u=eSI(e),(null==(c=LV(eT8(e,tdN)))||(BJ(c),c<=0))&&(c=1.3),l=eYA(o,i,a,u.a,u.b,n,(BJ(c),c)),eYx(e,l.a,l.b,!1,!0)):eRF(e,i,a,n),eEj(t)},Y5(eVL,"BoxLayoutProvider",972),eTS(973,1,e$C,h3),eUe.ue=function(e,t){return eOQ(this,Pp(e,33),Pp(t,33))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},eUe.a=!1,Y5(eVL,"BoxLayoutProvider/1",973),eTS(157,1,{157:1},etD,Lp),eUe.Ib=function(){return this.c?eC4(this.c):e_F(this.b)},Y5(eVL,"BoxLayoutProvider/Group",157),eTS(311,22,{3:1,35:1,22:1,311:1},kT);var e6u=enw(eVL,"BoxLayoutProvider/PackingMode",311,e1G,VI,NJ);eTS(974,1,e$C,oY),eUe.ue=function(e,t){return HK(Pp(e,157),Pp(t,157))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVL,"BoxLayoutProvider/lambda$0$Type",974),eTS(975,1,e$C,oB),eUe.ue=function(e,t){return Hm(Pp(e,157),Pp(t,157))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVL,"BoxLayoutProvider/lambda$1$Type",975),eTS(976,1,e$C,oU),eUe.ue=function(e,t){return Hg(Pp(e,157),Pp(t,157))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eVL,"BoxLayoutProvider/lambda$2$Type",976),eTS(1365,1,{831:1},oH),eUe.qg=function(e,t){return _R(),!M4(t,160)||yX((eoM(),Pp(e,160)),t)},Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder/lambda$0$Type",1365),eTS(1366,1,eUF,h4),eUe.td=function(e){eux(this.a,Pp(e,146))},Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder/lambda$1$Type",1366),eTS(1367,1,eUF,oj),eUe.td=function(e){Pp(e,94),_R()},Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder/lambda$2$Type",1367),eTS(1371,1,eUF,h5),eUe.td=function(e){erQ(this.a,Pp(e,94))},Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder/lambda$3$Type",1371),eTS(1369,1,eU8,kM),eUe.Mb=function(e){return esI(this.a,this.b,Pp(e,146))},Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder/lambda$4$Type",1369),eTS(1368,1,eU8,kO),eUe.Mb=function(e){return Lt(this.a,this.b,Pp(e,831))},Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder/lambda$5$Type",1368),eTS(1370,1,eUF,kA),eUe.td=function(e){Fj(this.a,this.b,Pp(e,146))},Y5(eVL,"ElkSpacings/AbstractSpacingsBuilder/lambda$6$Type",1370),eTS(935,1,{},oP),eUe.Kb=function(e){return TA(e)},eUe.Fb=function(e){return this===e},Y5(eVL,"ElkUtil/lambda$0$Type",935),eTS(936,1,eUF,kL),eUe.td=function(e){exS(this.a,this.b,Pp(e,79))},eUe.a=0,eUe.b=0,Y5(eVL,"ElkUtil/lambda$1$Type",936),eTS(937,1,eUF,kC),eUe.td=function(e){gp(this.a,this.b,Pp(e,202))},eUe.a=0,eUe.b=0,Y5(eVL,"ElkUtil/lambda$2$Type",937),eTS(938,1,eUF,kI),eUe.td=function(e){Me(this.a,this.b,Pp(e,137))},eUe.a=0,eUe.b=0,Y5(eVL,"ElkUtil/lambda$3$Type",938),eTS(939,1,eUF,h6),eUe.td=function(e){RE(this.a,Pp(e,469))},Y5(eVL,"ElkUtil/lambda$4$Type",939),eTS(342,1,{35:1,342:1},pQ),eUe.wd=function(e){return Os(this,Pp(e,236))},eUe.Fb=function(e){var t;return!!M4(e,342)&&(t=Pp(e,342),this.a==t.a)},eUe.Hb=function(){return zy(this.a)},eUe.Ib=function(){return this.a+" (exclusive)"},eUe.a=0,Y5(eVL,"ExclusiveBounds/ExclusiveLowerBound",342),eTS(1138,209,ezL,oR),eUe.Ze=function(e,t){var n,r,i,a,o,s,u,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x;for(ewG(t,"Fixed Layout",1),a=Pp(eT8(e,(eBB(),tha)),218),d=0,h=0,y=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));y.e!=y.i.gc();){for(g=Pp(epH(y),33),(x=Pp(eT8(g,(euw(),tp$)),8))&&(TP(g,x.a,x.b),Pp(eT8(g,tpF),174).Hc((ed6(),tbW))&&(p=Pp(eT8(g,tpB),8)).a>0&&p.b>0&&eYx(g,p.a,p.b,!0,!0)),d=eB4.Math.max(d,g.i+g.g),h=eB4.Math.max(h,g.j+g.f),l=new Ow((g.n||(g.n=new FQ(e6S,g,1,7)),g.n));l.e!=l.i.gc();)s=Pp(epH(l),137),(x=Pp(eT8(s,tp$),8))&&TP(s,x.a,x.b),d=eB4.Math.max(d,g.i+s.i+s.g),h=eB4.Math.max(h,g.j+s.j+s.f);for(E=new Ow((g.c||(g.c=new FQ(e6x,g,9,9)),g.c));E.e!=E.i.gc();)for(_=Pp(epH(E),118),(x=Pp(eT8(_,tp$),8))&&TP(_,x.a,x.b),S=g.i+_.i,k=g.j+_.j,d=eB4.Math.max(d,S+_.g),h=eB4.Math.max(h,k+_.f),u=new Ow((_.n||(_.n=new FQ(e6S,_,1,7)),_.n));u.e!=u.i.gc();)s=Pp(epH(u),137),(x=Pp(eT8(s,tp$),8))&&TP(s,x.a,x.b),d=eB4.Math.max(d,S+s.i+s.g),h=eB4.Math.max(h,k+s.j+s.f);for(i=new Fa(OH(eOi(g).a.Kc(),new c));eTk(i);)n=Pp(ZC(i),79),f=eYT(n),d=eB4.Math.max(d,f.a),h=eB4.Math.max(h,f.b);for(r=new Fa(OH(eOr(g).a.Kc(),new c));eTk(r);)n=Pp(ZC(r),79),z$(e_I(n))!=e&&(f=eYT(n),d=eB4.Math.max(d,f.a),h=eB4.Math.max(h,f.b))}if(a==(efE(),tpx))for(v=new Ow((e.a||(e.a=new FQ(e6k,e,10,11)),e.a));v.e!=v.i.gc();)for(g=Pp(epH(v),33),r=new Fa(OH(eOi(g).a.Kc(),new c));eTk(r);)n=Pp(ZC(r),79),0==(o=eDX(n)).b?ebu(n,thg,null):ebu(n,thg,o);gN(LK(eT8(e,(euw(),tpY))))||(w=Pp(eT8(e,tpU),116),eYx(e,m=d+w.b+w.c,b=h+w.d+w.a,!0,!0)),eEj(t)},Y5(eVL,"FixedLayoutProvider",1138),eTS(373,134,{3:1,414:1,373:1,94:1,134:1},oG,eer),eUe.Jf=function(e){var t,n,r,i,a,o,s,u,c;if(e)try{for(a=u=eIk(e,";,;"),o=0,s=a.length;o>16&eHd|t^r<<16},eUe.Kc=function(){return new h9(this)},eUe.Ib=function(){return null==this.a&&null==this.b?"pair(null,null)":null==this.a?"pair(null,"+efF(this.b)+")":null==this.b?"pair("+efF(this.a)+",null)":"pair("+efF(this.a)+","+efF(this.b)+")"},Y5(eVL,"Pair",46),eTS(983,1,eUE,h9),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return!this.c&&(!this.b&&null!=this.a.a||null!=this.a.b)},eUe.Pb=function(){if(!this.c&&!this.b&&null!=this.a.a)return this.b=!0,this.a.a;if(!this.c&&null!=this.a.b)return this.c=!0,this.a.b;throw p7(new bC)},eUe.Qb=function(){throw this.c&&null!=this.a.b?this.a.b=null:this.b&&null!=this.a.a&&(this.a.a=null),p7(new bT)},eUe.b=!1,eUe.c=!1,Y5(eVL,"Pair/1",983),eTS(448,1,{448:1},Ho),eUe.Fb=function(e){return UT(this.a,Pp(e,448).a)&&UT(this.c,Pp(e,448).c)&&UT(this.d,Pp(e,448).d)&&UT(this.b,Pp(e,448).b)},eUe.Hb=function(){return euF(eow(vx(e1R,1),eUp,1,5,[this.a,this.c,this.d,this.b]))},eUe.Ib=function(){return"("+this.a+eUd+this.c+eUd+this.d+eUd+this.b+")"},Y5(eVL,"Quadruple",448),eTS(1126,209,ezL,oV),eUe.Ze=function(e,t){var n,r,i,a,o;if(ewG(t,"Random Layout",1),0==(e.a||(e.a=new FQ(e6k,e,10,11)),e.a).i){eEj(t);return}i=(a=Pp(eT8(e,(ed5(),tbz)),19))&&0!=a.a?new qS(a.a):new efo,n=gR(LV(eT8(e,tbU))),o=gR(LV(eT8(e,tbG))),r=Pp(eT8(e,tbH),116),eF1(e,i,n,o,r),eEj(t)},Y5(eVL,"RandomLayoutProvider",1126),eTS(553,1,{}),eUe.qf=function(){return new kl(this.f.i,this.f.j)},eUe.We=function(e){return $k(e,(eBB(),thK))?eT8(this.f,tmu):eT8(this.f,e)},eUe.rf=function(){return new kl(this.f.g,this.f.f)},eUe.sf=function(){return this.g},eUe.Xe=function(e){return X2(this.f,e)},eUe.tf=function(e){eno(this.f,e.a),ens(this.f,e.b)},eUe.uf=function(e){ena(this.f,e.a),eni(this.f,e.b)},eUe.vf=function(e){this.g=e},eUe.g=0,Y5(eZI,"ElkGraphAdapters/AbstractElkGraphElementAdapter",553),eTS(554,1,{839:1},h8),eUe.wf=function(){var e,t;if(!this.b)for(this.b=K$(UB(this.a).i),t=new Ow(UB(this.a));t.e!=t.i.gc();)e=Pp(epH(t),137),P_(this.b,new gO(e));return this.b},eUe.b=null,Y5(eZI,"ElkGraphAdapters/ElkEdgeAdapter",554),eTS(301,553,{},gM),eUe.xf=function(){return em3(this)},eUe.a=null,Y5(eZI,"ElkGraphAdapters/ElkGraphAdapter",301),eTS(630,553,{181:1},gO),Y5(eZI,"ElkGraphAdapters/ElkLabelAdapter",630),eTS(629,553,{680:1},AC),eUe.wf=function(){return em0(this)},eUe.Af=function(){var e;return(e=Pp(eT8(this.f,(eBB(),thy)),142))||(e=new mh),e},eUe.Cf=function(){return em2(this)},eUe.Ef=function(e){var t;t=new Dk(e),ebu(this.f,(eBB(),thy),t)},eUe.Ff=function(e){ebu(this.f,(eBB(),thN),new DS(e))},eUe.yf=function(){return this.d},eUe.zf=function(){var e,t;if(!this.a)for(this.a=new p0,t=new Fa(OH(eOr(Pp(this.f,33)).a.Kc(),new c));eTk(t);)e=Pp(ZC(t),79),P_(this.a,new h8(e));return this.a},eUe.Bf=function(){var e,t;if(!this.c)for(this.c=new p0,t=new Fa(OH(eOi(Pp(this.f,33)).a.Kc(),new c));eTk(t);)e=Pp(ZC(t),79),P_(this.c,new h8(e));return this.c},eUe.Df=function(){return 0!=H8(Pp(this.f,33)).i||gN(LK(Pp(this.f,33).We((eBB(),thh))))},eUe.Gf=function(){QV(this,(_q(),tms))},eUe.a=null,eUe.b=null,eUe.c=null,eUe.d=null,eUe.e=null,Y5(eZI,"ElkGraphAdapters/ElkNodeAdapter",629),eTS(1266,553,{838:1},pA),eUe.wf=function(){return egd(this)},eUe.zf=function(){var e,t;if(!this.a)for(this.a=AH(Pp(this.f,118).xg().i),t=new Ow(Pp(this.f,118).xg());t.e!=t.i.gc();)e=Pp(epH(t),79),P_(this.a,new h8(e));return this.a},eUe.Bf=function(){var e,t;if(!this.c)for(this.c=AH(Pp(this.f,118).yg().i),t=new Ow(Pp(this.f,118).yg());t.e!=t.i.gc();)e=Pp(epH(t),79),P_(this.c,new h8(e));return this.c},eUe.Hf=function(){return Pp(Pp(this.f,118).We((eBB(),th0)),61)},eUe.If=function(){var e,t,n,r,i,a,o,s;for(r=zY(Pp(this.f,118)),n=new Ow(Pp(this.f,118).yg());n.e!=n.i.gc();)for(e=Pp(epH(n),79),s=new Ow((e.c||(e.c=new Ih(e6m,e,5,8)),e.c));s.e!=s.i.gc();)if(o=Pp(epH(s),82),etg(ewH(o),r)||ewH(o)==r&&gN(LK(eT8(e,(eBB(),thp)))))return!0;for(t=new Ow(Pp(this.f,118).xg());t.e!=t.i.gc();)for(e=Pp(epH(t),79),a=new Ow((e.b||(e.b=new Ih(e6m,e,4,7)),e.b));a.e!=a.i.gc();)if(i=Pp(epH(a),82),etg(ewH(i),r))return!0;return!1},eUe.a=null,eUe.b=null,eUe.c=null,Y5(eZI,"ElkGraphAdapters/ElkPortAdapter",1266),eTS(1267,1,e$C,oq),eUe.ue=function(e,t){return eC3(Pp(e,118),Pp(t,118))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(eZI,"ElkGraphAdapters/PortComparator",1267);var e6f=RL(eZD,"EObject"),e6d=RL(eZN,eZP),e6h=RL(eZN,eZR),e6p=RL(eZN,eZj),e6b=RL(eZN,"ElkShape"),e6m=RL(eZN,eZF),e6g=RL(eZN,eZY),e6v=RL(eZN,eZB),e6y=RL(eZD,eZU),e6w=RL(eZD,"EFactory"),e6_=RL(eZD,eZH),e6E=RL(eZD,"EPackage"),e6S=RL(eZN,eZ$),e6k=RL(eZN,eZz),e6x=RL(eZN,eZG);eTS(90,1,eZW),eUe.Jg=function(){return this.Kg(),null},eUe.Kg=function(){return null},eUe.Lg=function(){return this.Kg(),!1},eUe.Mg=function(){return!1},eUe.Ng=function(e){eam(this,e)},Y5(eZK,"BasicNotifierImpl",90),eTS(97,90,eZ0),eUe.nh=function(){return TO(this)},eUe.Og=function(e,t){return e},eUe.Pg=function(){throw p7(new bO)},eUe.Qg=function(e){var t;return t=ebY(Pp(ee2(this.Tg(),this.Vg()),18)),this.eh().ih(this,t.n,t.f,e)},eUe.Rg=function(e,t){throw p7(new bO)},eUe.Sg=function(e,t,n){return eDg(this,e,t,n)},eUe.Tg=function(){var e;return this.Pg()&&(e=this.Pg().ck())?e:this.zh()},eUe.Ug=function(){return eTp(this)},eUe.Vg=function(){throw p7(new bO)},eUe.Wg=function(){var e,t;return(t=this.ph().dk())||this.Pg().ik(t=(_0(),null==(e=zr(eNT(this.Tg())))?tgV:new AA(this,e))),t},eUe.Xg=function(e,t){return e},eUe.Yg=function(e){var t;return(t=e.Gj())?e.aj():edv(this.Tg(),e)},eUe.Zg=function(){var e;return(e=this.Pg())?e.fk():null},eUe.$g=function(){return this.Pg()?this.Pg().ck():null},eUe._g=function(e,t,n){return ebl(this,e,t,n)},eUe.ah=function(e){return JG(this,e)},eUe.bh=function(e,t){return ZN(this,e,t)},eUe.dh=function(){var e;return!!(e=this.Pg())&&e.gk()},eUe.eh=function(){throw p7(new bO)},eUe.fh=function(){return ehO(this)},eUe.gh=function(e,t,n,r){return ep0(this,e,t,r)},eUe.hh=function(e,t,n){var r;return(r=Pp(ee2(this.Tg(),t),66)).Nj().Qj(this,this.yh(),t-this.Ah(),e,n)},eUe.ih=function(e,t,n,r){return $7(this,e,t,r)},eUe.jh=function(e,t,n){var r;return(r=Pp(ee2(this.Tg(),t),66)).Nj().Rj(this,this.yh(),t-this.Ah(),e,n)},eUe.kh=function(){return!!this.Pg()&&!!this.Pg().ek()},eUe.lh=function(e){return epY(this,e)},eUe.mh=function(e){return zz(this,e)},eUe.oh=function(e){return eR2(this,e)},eUe.ph=function(){throw p7(new bO)},eUe.qh=function(){return this.Pg()?this.Pg().ek():null},eUe.rh=function(){return ehO(this)},eUe.sh=function(e,t){eS5(this,e,t)},eUe.th=function(e){this.ph().hk(e)},eUe.uh=function(e){this.ph().kk(e)},eUe.vh=function(e){this.ph().jk(e)},eUe.wh=function(e,t){var n,r,i,a;return(a=this.Zg())&&e&&(t=ep6(a.Vk(),this,t),a.Zk(this)),(r=this.eh())&&((eIy(this,this.eh(),this.Vg()).Bb&eH3)!=0?(i=r.fh())&&(e?a||i.Zk(this):i.Yk(this)):(t=(n=this.Vg())>=0?this.Qg(t):this.eh().ih(this,-1-n,null,t),t=this.Sg(null,-1,t))),this.uh(e),t},eUe.xh=function(e){var t,n,r,i,a,o,s,u;if((a=edv(n=this.Tg(),e))>=(t=this.Ah()))return Pp(e,66).Nj().Uj(this,this.yh(),a-t);if(a<=-1){if(o=eR3((eSp(),tvc),n,e)){if(_4(),Pp(o,66).Oj()||(o=Wk(QZ(tvc,o))),i=Pp((r=this.Yg(o))>=0?this._g(r,!0,!0):exk(this,o,!0),153),(u=o.Zj())>1||-1==u)return Pp(Pp(i,215).hl(e,!1),76)}else throw p7(new gL(eZV+e.ne()+eZX))}else if(e.$j())return Pp((r=this.Yg(e))>=0?this._g(r,!1,!0):exk(this,e,!1),76);return new k4(this,e)},eUe.yh=function(){return Q5(this)},eUe.zh=function(){return(BM(),tgv).S},eUe.Ah=function(){return Y1(this.zh())},eUe.Bh=function(e){eSi(this,e)},eUe.Ib=function(){return eMT(this)},Y5(eZ2,"BasicEObjectImpl",97),eTS(114,97,{105:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1}),eUe.Ch=function(e){var t;return(t=Q6(this))[e]},eUe.Dh=function(e,t){var n;n=Q6(this),Bc(n,e,t)},eUe.Eh=function(e){var t;t=Q6(this),Bc(t,e,null)},eUe.Jg=function(){return Pp(eaS(this,4),126)},eUe.Kg=function(){throw p7(new bO)},eUe.Lg=function(){return(4&this.Db)!=0},eUe.Pg=function(){throw p7(new bO)},eUe.Fh=function(e){ehU(this,2,e)},eUe.Rg=function(e,t){this.Db=t<<16|255&this.Db,this.Fh(e)},eUe.Tg=function(){return $S(this)},eUe.Vg=function(){return this.Db>>16},eUe.Wg=function(){var e,t;return _0(),null==(t=zr(eNT((e=Pp(eaS(this,16),26))||this.zh())))?tgV:new AA(this,t)},eUe.Mg=function(){return(1&this.Db)==0},eUe.Zg=function(){return Pp(eaS(this,128),1935)},eUe.$g=function(){return Pp(eaS(this,16),26)},eUe.dh=function(){return(32&this.Db)!=0},eUe.eh=function(){return Pp(eaS(this,2),49)},eUe.kh=function(){return(64&this.Db)!=0},eUe.ph=function(){throw p7(new bO)},eUe.qh=function(){return Pp(eaS(this,64),281)},eUe.th=function(e){ehU(this,16,e)},eUe.uh=function(e){ehU(this,128,e)},eUe.vh=function(e){ehU(this,64,e)},eUe.yh=function(){return ehH(this)},eUe.Db=0,Y5(eZ2,"MinimalEObjectImpl",114),eTS(115,114,{105:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1}),eUe.Fh=function(e){this.Cb=e},eUe.eh=function(){return this.Cb},Y5(eZ2,"MinimalEObjectImpl/Container",115),eTS(1985,115,{105:1,413:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1}),eUe._g=function(e,t,n){return egp(this,e,t,n)},eUe.jh=function(e,t,n){return e_9(this,e,t,n)},eUe.lh=function(e){return Wz(this,e)},eUe.sh=function(e,t){esU(this,e,t)},eUe.zh=function(){return eBa(),tm_},eUe.Bh=function(e){eoF(this,e)},eUe.Ve=function(){return epD(this)},eUe.We=function(e){return eT8(this,e)},eUe.Xe=function(e){return X2(this,e)},eUe.Ye=function(e,t){return ebu(this,e,t)},Y5(eZ3,"EMapPropertyHolderImpl",1985),eTS(567,115,{105:1,469:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1},oJ),eUe._g=function(e,t,n){switch(e){case 0:return this.a;case 1:return this.b}return ebl(this,e,t,n)},eUe.lh=function(e){switch(e){case 0:return 0!=this.a;case 1:return 0!=this.b}return epY(this,e)},eUe.sh=function(e,t){switch(e){case 0:ent(this,gP(LV(t)));return;case 1:enn(this,gP(LV(t)));return}eS5(this,e,t)},eUe.zh=function(){return eBa(),tmf},eUe.Bh=function(e){switch(e){case 0:ent(this,0);return;case 1:enn(this,0);return}eSi(this,e)},eUe.Ib=function(){var e;return(64&this.Db)!=0?eMT(this):(e=new O1(eMT(this)),e.a+=" (x: ",y$(e,this.a),e.a+=", y: ",y$(e,this.b),e.a+=")",e.a)},eUe.a=0,eUe.b=0,Y5(eZ3,"ElkBendPointImpl",567),eTS(723,1985,{105:1,413:1,160:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1}),eUe._g=function(e,t,n){return ec2(this,e,t,n)},eUe.hh=function(e,t,n){return ew0(this,e,t,n)},eUe.jh=function(e,t,n){return ea9(this,e,t,n)},eUe.lh=function(e){return eaT(this,e)},eUe.sh=function(e,t){eyb(this,e,t)},eUe.zh=function(){return eBa(),tmb},eUe.Bh=function(e){ecx(this,e)},eUe.zg=function(){return this.k},eUe.Ag=function(){return UB(this)},eUe.Ib=function(){return el4(this)},eUe.k=null,Y5(eZ3,"ElkGraphElementImpl",723),eTS(724,723,{105:1,413:1,160:1,470:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1}),eUe._g=function(e,t,n){return efN(this,e,t,n)},eUe.lh=function(e){return ef8(this,e)},eUe.sh=function(e,t){eym(this,e,t)},eUe.zh=function(){return eBa(),tmw},eUe.Bh=function(e){edS(this,e)},eUe.Bg=function(){return this.f},eUe.Cg=function(){return this.g},eUe.Dg=function(){return this.i},eUe.Eg=function(){return this.j},eUe.Fg=function(e,t){TN(this,e,t)},eUe.Gg=function(e,t){TP(this,e,t)},eUe.Hg=function(e){eno(this,e)},eUe.Ig=function(e){ens(this,e)},eUe.Ib=function(){return eEp(this)},eUe.f=0,eUe.g=0,eUe.i=0,eUe.j=0,Y5(eZ3,"ElkShapeImpl",724),eTS(725,724,{105:1,413:1,82:1,160:1,470:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1}),eUe._g=function(e,t,n){return ebQ(this,e,t,n)},eUe.hh=function(e,t,n){return evZ(this,e,t,n)},eUe.jh=function(e,t,n){return evX(this,e,t,n)},eUe.lh=function(e){return esM(this,e)},eUe.sh=function(e,t){eTH(this,e,t)},eUe.zh=function(){return eBa(),tmd},eUe.Bh=function(e){ep2(this,e)},eUe.xg=function(){return this.d||(this.d=new Ih(e6g,this,8,5)),this.d},eUe.yg=function(){return this.e||(this.e=new Ih(e6g,this,7,4)),this.e},Y5(eZ3,"ElkConnectableShapeImpl",725),eTS(352,723,{105:1,413:1,79:1,160:1,352:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1},oX),eUe.Qg=function(e){return evo(this,e)},eUe._g=function(e,t,n){switch(e){case 3:return zF(this);case 4:return this.b||(this.b=new Ih(e6m,this,4,7)),this.b;case 5:return this.c||(this.c=new Ih(e6m,this,5,8)),this.c;case 6:return this.a||(this.a=new FQ(e6v,this,6,6)),this.a;case 7:return OQ(),this.b||(this.b=new Ih(e6m,this,4,7)),!(this.b.i<=1)||(this.c||(this.c=new Ih(e6m,this,5,8)),!(this.c.i<=1));case 8:return OQ(),!!eTc(this);case 9:return OQ(),!!exb(this);case 10:return OQ(),this.b||(this.b=new Ih(e6m,this,4,7)),0!=this.b.i&&(this.c||(this.c=new Ih(e6m,this,5,8)),0!=this.c.i)}return ec2(this,e,t,n)},eUe.hh=function(e,t,n){var r;switch(t){case 3:return this.Cb&&(n=(r=this.Db>>16)>=0?evo(this,n):this.Cb.ih(this,-1-r,null,n)),Cu(this,Pp(e,33),n);case 4:return this.b||(this.b=new Ih(e6m,this,4,7)),edF(this.b,e,n);case 5:return this.c||(this.c=new Ih(e6m,this,5,8)),edF(this.c,e,n);case 6:return this.a||(this.a=new FQ(e6v,this,6,6)),edF(this.a,e,n)}return ew0(this,e,t,n)},eUe.jh=function(e,t,n){switch(t){case 3:return Cu(this,null,n);case 4:return this.b||(this.b=new Ih(e6m,this,4,7)),ep6(this.b,e,n);case 5:return this.c||(this.c=new Ih(e6m,this,5,8)),ep6(this.c,e,n);case 6:return this.a||(this.a=new FQ(e6v,this,6,6)),ep6(this.a,e,n)}return ea9(this,e,t,n)},eUe.lh=function(e){switch(e){case 3:return!!zF(this);case 4:return!!this.b&&0!=this.b.i;case 5:return!!this.c&&0!=this.c.i;case 6:return!!this.a&&0!=this.a.i;case 7:return this.b||(this.b=new Ih(e6m,this,4,7)),!(this.b.i<=1&&(this.c||(this.c=new Ih(e6m,this,5,8)),this.c.i<=1));case 8:return eTc(this);case 9:return exb(this);case 10:return this.b||(this.b=new Ih(e6m,this,4,7)),0!=this.b.i&&(this.c||(this.c=new Ih(e6m,this,5,8)),0!=this.c.i)}return eaT(this,e)},eUe.sh=function(e,t){switch(e){case 3:eOC(this,Pp(t,33));return;case 4:this.b||(this.b=new Ih(e6m,this,4,7)),eRT(this.b),this.b||(this.b=new Ih(e6m,this,4,7)),Y4(this.b,Pp(t,14));return;case 5:this.c||(this.c=new Ih(e6m,this,5,8)),eRT(this.c),this.c||(this.c=new Ih(e6m,this,5,8)),Y4(this.c,Pp(t,14));return;case 6:this.a||(this.a=new FQ(e6v,this,6,6)),eRT(this.a),this.a||(this.a=new FQ(e6v,this,6,6)),Y4(this.a,Pp(t,14));return}eyb(this,e,t)},eUe.zh=function(){return eBa(),tmh},eUe.Bh=function(e){switch(e){case 3:eOC(this,null);return;case 4:this.b||(this.b=new Ih(e6m,this,4,7)),eRT(this.b);return;case 5:this.c||(this.c=new Ih(e6m,this,5,8)),eRT(this.c);return;case 6:this.a||(this.a=new FQ(e6v,this,6,6)),eRT(this.a);return}ecx(this,e)},eUe.Ib=function(){return ePY(this)},Y5(eZ3,"ElkEdgeImpl",352),eTS(439,1985,{105:1,413:1,202:1,439:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1},oQ),eUe.Qg=function(e){return eg1(this,e)},eUe._g=function(e,t,n){switch(e){case 1:return this.j;case 2:return this.k;case 3:return this.b;case 4:return this.c;case 5:return this.a||(this.a=new O_(e6h,this,5)),this.a;case 6:return zB(this);case 7:if(t)return ebF(this);return this.i;case 8:if(t)return ebj(this);return this.f;case 9:return this.g||(this.g=new Ih(e6v,this,9,10)),this.g;case 10:return this.e||(this.e=new Ih(e6v,this,10,9)),this.e;case 11:return this.d}return egp(this,e,t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 6:return this.Cb&&(n=(i=this.Db>>16)>=0?eg1(this,n):this.Cb.ih(this,-1-i,null,n)),Cc(this,Pp(e,79),n);case 9:return this.g||(this.g=new Ih(e6v,this,9,10)),edF(this.g,e,n);case 10:return this.e||(this.e=new Ih(e6v,this,10,9)),edF(this.e,e,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBa(),tmp),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBa(),tmp)),e,n)},eUe.jh=function(e,t,n){switch(t){case 5:return this.a||(this.a=new O_(e6h,this,5)),ep6(this.a,e,n);case 6:return Cc(this,null,n);case 9:return this.g||(this.g=new Ih(e6v,this,9,10)),ep6(this.g,e,n);case 10:return this.e||(this.e=new Ih(e6v,this,10,9)),ep6(this.e,e,n)}return e_9(this,e,t,n)},eUe.lh=function(e){switch(e){case 1:return 0!=this.j;case 2:return 0!=this.k;case 3:return 0!=this.b;case 4:return 0!=this.c;case 5:return!!this.a&&0!=this.a.i;case 6:return!!zB(this);case 7:return!!this.i;case 8:return!!this.f;case 9:return!!this.g&&0!=this.g.i;case 10:return!!this.e&&0!=this.e.i;case 11:return null!=this.d}return Wz(this,e)},eUe.sh=function(e,t){switch(e){case 1:enu(this,gP(LV(t)));return;case 2:enl(this,gP(LV(t)));return;case 3:enr(this,gP(LV(t)));return;case 4:enc(this,gP(LV(t)));return;case 5:this.a||(this.a=new O_(e6h,this,5)),eRT(this.a),this.a||(this.a=new O_(e6h,this,5)),Y4(this.a,Pp(t,14));return;case 6:eOA(this,Pp(t,79));return;case 7:err(this,Pp(t,82));return;case 8:ern(this,Pp(t,82));return;case 9:this.g||(this.g=new Ih(e6v,this,9,10)),eRT(this.g),this.g||(this.g=new Ih(e6v,this,9,10)),Y4(this.g,Pp(t,14));return;case 10:this.e||(this.e=new Ih(e6v,this,10,9)),eRT(this.e),this.e||(this.e=new Ih(e6v,this,10,9)),Y4(this.e,Pp(t,14));return;case 11:erO(this,Lq(t));return}esU(this,e,t)},eUe.zh=function(){return eBa(),tmp},eUe.Bh=function(e){switch(e){case 1:enu(this,0);return;case 2:enl(this,0);return;case 3:enr(this,0);return;case 4:enc(this,0);return;case 5:this.a||(this.a=new O_(e6h,this,5)),eRT(this.a);return;case 6:eOA(this,null);return;case 7:err(this,null);return;case 8:ern(this,null);return;case 9:this.g||(this.g=new Ih(e6v,this,9,10)),eRT(this.g);return;case 10:this.e||(this.e=new Ih(e6v,this,10,9)),eRT(this.e);return;case 11:erO(this,null);return}eoF(this,e)},eUe.Ib=function(){return ex2(this)},eUe.b=0,eUe.c=0,eUe.d=null,eUe.j=0,eUe.k=0,Y5(eZ3,"ElkEdgeSectionImpl",439),eTS(150,115,{105:1,92:1,90:1,147:1,56:1,108:1,49:1,97:1,150:1,114:1,115:1}),eUe._g=function(e,t,n){var r;return 0==e?(this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab):Qt(this,e-Y1(this.zh()),ee2((r=Pp(eaS(this,16),26))||this.zh(),e),t,n)},eUe.hh=function(e,t,n){var r,i;return 0==t?(this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n)):(i=Pp(ee2((r=Pp(eaS(this,16),26))||this.zh(),t),66)).Nj().Qj(this,ehH(this),t-Y1(this.zh()),e,n)},eUe.jh=function(e,t,n){var r,i;return 0==t?(this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n)):(i=Pp(ee2((r=Pp(eaS(this,16),26))||this.zh(),t),66)).Nj().Rj(this,ehH(this),t-Y1(this.zh()),e,n)},eUe.lh=function(e){var t;return 0==e?!!this.Ab&&0!=this.Ab.i:VP(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.oh=function(e){return eF9(this,e)},eUe.sh=function(e,t){var n;if(0===e){this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return}efL(this,e-Y1(this.zh()),ee2((n=Pp(eaS(this,16),26))||this.zh(),e),t)},eUe.uh=function(e){ehU(this,128,e)},eUe.zh=function(){return eBK(),tgL},eUe.Bh=function(e){var t;if(0===e){this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return}ec6(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.Gh=function(){this.Bb|=1},eUe.Hh=function(e){return eDM(this,e)},eUe.Bb=0,Y5(eZ2,"EModelElementImpl",150),eTS(704,150,{105:1,92:1,90:1,471:1,147:1,56:1,108:1,49:1,97:1,150:1,114:1,115:1},cQ),eUe.Ih=function(e,t){return ejZ(this,e,t)},eUe.Jh=function(e){var t,n,r,i,a;if(this.a!=etP(e)||(256&e.Bb)!=0)throw p7(new gL(eZ7+e.zb+eZ6));for(r=$E(e);0!=qt(r.a).i;){if(n=Pp(ejc(r,0,(a=(t=Pp(etj(qt(r.a),0),87)).c,M4(a,88)?Pp(a,26):(eBK(),tgI))),26),em4(n))return i=etP(n).Nh().Jh(n),Pp(i,49).th(e),i;r=$E(n)}return(null!=e.D?e.D:e.B)=="java.util.Map$Entry"?new RO(e):new Pq(e)},eUe.Kh=function(e,t){return eBd(this,e,t)},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.a}return Qt(this,e-Y1((eBK(),tgM)),ee2((r=Pp(eaS(this,16),26))||tgM,e),t,n)},eUe.hh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 1:return this.a&&(n=Pp(this.a,49).ih(this,4,e6E,n)),ecb(this,Pp(e,235),n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgM),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tgM)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 1:return ecb(this,null,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgM),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgM)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return!!this.a}return VP(this,e-Y1((eBK(),tgM)),ee2((t=Pp(eaS(this,16),26))||tgM,e))},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:e_B(this,Pp(t,235));return}efL(this,e-Y1((eBK(),tgM)),ee2((n=Pp(eaS(this,16),26))||tgM,e),t)},eUe.zh=function(){return eBK(),tgM},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:e_B(this,null);return}ec6(this,e-Y1((eBK(),tgM)),ee2((t=Pp(eaS(this,16),26))||tgM,e))},Y5(eZ2,"EFactoryImpl",704),eTS(eXt,704,{105:1,2014:1,92:1,90:1,471:1,147:1,56:1,108:1,49:1,97:1,150:1,114:1,115:1},o1),eUe.Ih=function(e,t){switch(e.yj()){case 12:return Pp(t,146).tg();case 13:return efF(t);default:throw p7(new gL(eZ5+e.ne()+eZ6))}},eUe.Jh=function(e){var t;switch(-1==e.G&&(e.G=(t=etP(e))?ebv(t.Mh(),e):-1),e.G){case 4:return new o0;case 6:return new mS;case 7:return new mk;case 8:return new oX;case 9:return new oJ;case 10:return new oQ;case 11:return new o3;default:throw p7(new gL(eZ7+e.zb+eZ6))}},eUe.Kh=function(e,t){switch(e.yj()){case 13:case 12:return null;default:throw p7(new gL(eZ5+e.ne()+eZ6))}},Y5(eZ3,"ElkGraphFactoryImpl",eXt),eTS(438,150,{105:1,92:1,90:1,147:1,191:1,56:1,108:1,49:1,97:1,150:1,114:1,115:1}),eUe.Wg=function(){var e,t;return null==(t=zr(eNT((e=Pp(eaS(this,16),26))||this.zh())))?(_0(),_0(),tgV):new Lg(this,t)},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.ne()}return Qt(this,e-Y1(this.zh()),ee2((r=Pp(eaS(this,16),26))||this.zh(),e),t,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb}return VP(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:this.Lh(Lq(t));return}efL(this,e-Y1(this.zh()),ee2((n=Pp(eaS(this,16),26))||this.zh(),e),t)},eUe.zh=function(){return eBK(),tgC},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:this.Lh(null);return}ec6(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.ne=function(){return this.zb},eUe.Lh=function(e){er3(this,e)},eUe.Ib=function(){return ecF(this)},eUe.zb=null,Y5(eZ2,"ENamedElementImpl",438),eTS(179,438,{105:1,92:1,90:1,147:1,191:1,56:1,235:1,108:1,49:1,97:1,150:1,179:1,114:1,115:1,675:1},$y),eUe.Qg=function(e){return eg5(this,e)},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return this.yb;case 3:return this.xb;case 4:return this.sb;case 5:return this.rb||(this.rb=new Fq(this,tm8,this)),this.rb;case 6:return this.vb||(this.vb=new Ia(e6E,this,6,7)),this.vb;case 7:if(t)return this.Db>>16==7?Pp(this.Cb,235):null;return zU(this)}return Qt(this,e-Y1((eBK(),tgP)),ee2((r=Pp(eaS(this,16),26))||tgP,e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 4:return this.sb&&(n=Pp(this.sb,49).ih(this,1,e6w,n)),ecY(this,Pp(e,471),n);case 5:return this.rb||(this.rb=new Fq(this,tm8,this)),edF(this.rb,e,n);case 6:return this.vb||(this.vb=new Ia(e6E,this,6,7)),edF(this.vb,e,n);case 7:return this.Cb&&(n=(i=this.Db>>16)>=0?eg5(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,7,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgP),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tgP)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 4:return ecY(this,null,n);case 5:return this.rb||(this.rb=new Fq(this,tm8,this)),ep6(this.rb,e,n);case 6:return this.vb||(this.vb=new Ia(e6E,this,6,7)),ep6(this.vb,e,n);case 7:return eDg(this,null,7,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgP),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgP)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return null!=this.yb;case 3:return null!=this.xb;case 4:return!!this.sb;case 5:return!!this.rb&&0!=this.rb.i;case 6:return!!this.vb&&0!=this.vb.i;case 7:return!!zU(this)}return VP(this,e-Y1((eBK(),tgP)),ee2((t=Pp(eaS(this,16),26))||tgP,e))},eUe.oh=function(e){var t;return(t=eAd(this,e))||eF9(this,e)},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:er3(this,Lq(t));return;case 2:er5(this,Lq(t));return;case 3:er4(this,Lq(t));return;case 4:e_8(this,Pp(t,471));return;case 5:this.rb||(this.rb=new Fq(this,tm8,this)),eRT(this.rb),this.rb||(this.rb=new Fq(this,tm8,this)),Y4(this.rb,Pp(t,14));return;case 6:this.vb||(this.vb=new Ia(e6E,this,6,7)),eRT(this.vb),this.vb||(this.vb=new Ia(e6E,this,6,7)),Y4(this.vb,Pp(t,14));return}efL(this,e-Y1((eBK(),tgP)),ee2((n=Pp(eaS(this,16),26))||tgP,e),t)},eUe.vh=function(e){var t,n;if(e&&this.rb)for(n=new Ow(this.rb);n.e!=n.i.gc();)t=epH(n),M4(t,351)&&(Pp(t,351).w=null);ehU(this,64,e)},eUe.zh=function(){return eBK(),tgP},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:er3(this,null);return;case 2:er5(this,null);return;case 3:er4(this,null);return;case 4:e_8(this,null);return;case 5:this.rb||(this.rb=new Fq(this,tm8,this)),eRT(this.rb);return;case 6:this.vb||(this.vb=new Ia(e6E,this,6,7)),eRT(this.vb);return}ec6(this,e-Y1((eBK(),tgP)),ee2((t=Pp(eaS(this,16),26))||tgP,e))},eUe.Gh=function(){egb(this)},eUe.Mh=function(){return this.rb||(this.rb=new Fq(this,tm8,this)),this.rb},eUe.Nh=function(){return this.sb},eUe.Oh=function(){return this.ub},eUe.Ph=function(){return this.xb},eUe.Qh=function(){return this.yb},eUe.Rh=function(e){this.ub=e},eUe.Ib=function(){var e;return(64&this.Db)!=0?ecF(this):(e=new O1(ecF(this)),e.a+=" (nsURI: ",xk(e,this.yb),e.a+=", nsPrefix: ",xk(e,this.xb),e.a+=")",e.a)},eUe.xb=null,eUe.yb=null,Y5(eZ2,"EPackageImpl",179),eTS(555,179,{105:1,2016:1,555:1,92:1,90:1,147:1,191:1,56:1,235:1,108:1,49:1,97:1,150:1,179:1,114:1,115:1,675:1},eTv),eUe.q=!1,eUe.r=!1;var e6T=!1;Y5(eZ3,"ElkGraphPackageImpl",555),eTS(354,724,{105:1,413:1,160:1,137:1,470:1,354:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1},o0),eUe.Qg=function(e){return eg0(this,e)},eUe._g=function(e,t,n){switch(e){case 7:return zH(this);case 8:return this.a}return efN(this,e,t,n)},eUe.hh=function(e,t,n){var r;return 7===t?(this.Cb&&(n=(r=this.Db>>16)>=0?eg0(this,n):this.Cb.ih(this,-1-r,null,n)),j2(this,Pp(e,160),n)):ew0(this,e,t,n)},eUe.jh=function(e,t,n){return 7==t?j2(this,null,n):ea9(this,e,t,n)},eUe.lh=function(e){switch(e){case 7:return!!zH(this);case 8:return!IE("",this.a)}return ef8(this,e)},eUe.sh=function(e,t){switch(e){case 7:eAu(this,Pp(t,160));return;case 8:eri(this,Lq(t));return}eym(this,e,t)},eUe.zh=function(){return eBa(),tmm},eUe.Bh=function(e){switch(e){case 7:eAu(this,null);return;case 8:eri(this,"");return}edS(this,e)},eUe.Ib=function(){return eE1(this)},eUe.a="",Y5(eZ3,"ElkLabelImpl",354),eTS(239,725,{105:1,413:1,82:1,160:1,33:1,470:1,239:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1},mS),eUe.Qg=function(e){return evs(this,e)},eUe._g=function(e,t,n){switch(e){case 9:return this.c||(this.c=new FQ(e6x,this,9,9)),this.c;case 10:return this.a||(this.a=new FQ(e6k,this,10,11)),this.a;case 11:return z$(this);case 12:return this.b||(this.b=new FQ(e6g,this,12,3)),this.b;case 13:return OQ(),this.a||(this.a=new FQ(e6k,this,10,11)),this.a.i>0}return ebQ(this,e,t,n)},eUe.hh=function(e,t,n){var r;switch(t){case 9:return this.c||(this.c=new FQ(e6x,this,9,9)),edF(this.c,e,n);case 10:return this.a||(this.a=new FQ(e6k,this,10,11)),edF(this.a,e,n);case 11:return this.Cb&&(n=(r=this.Db>>16)>=0?evs(this,n):this.Cb.ih(this,-1-r,null,n)),C4(this,Pp(e,33),n);case 12:return this.b||(this.b=new FQ(e6g,this,12,3)),edF(this.b,e,n)}return evZ(this,e,t,n)},eUe.jh=function(e,t,n){switch(t){case 9:return this.c||(this.c=new FQ(e6x,this,9,9)),ep6(this.c,e,n);case 10:return this.a||(this.a=new FQ(e6k,this,10,11)),ep6(this.a,e,n);case 11:return C4(this,null,n);case 12:return this.b||(this.b=new FQ(e6g,this,12,3)),ep6(this.b,e,n)}return evX(this,e,t,n)},eUe.lh=function(e){switch(e){case 9:return!!this.c&&0!=this.c.i;case 10:return!!this.a&&0!=this.a.i;case 11:return!!z$(this);case 12:return!!this.b&&0!=this.b.i;case 13:return this.a||(this.a=new FQ(e6k,this,10,11)),this.a.i>0}return esM(this,e)},eUe.sh=function(e,t){switch(e){case 9:this.c||(this.c=new FQ(e6x,this,9,9)),eRT(this.c),this.c||(this.c=new FQ(e6x,this,9,9)),Y4(this.c,Pp(t,14));return;case 10:this.a||(this.a=new FQ(e6k,this,10,11)),eRT(this.a),this.a||(this.a=new FQ(e6k,this,10,11)),Y4(this.a,Pp(t,14));return;case 11:eO$(this,Pp(t,33));return;case 12:this.b||(this.b=new FQ(e6g,this,12,3)),eRT(this.b),this.b||(this.b=new FQ(e6g,this,12,3)),Y4(this.b,Pp(t,14));return}eTH(this,e,t)},eUe.zh=function(){return eBa(),tmg},eUe.Bh=function(e){switch(e){case 9:this.c||(this.c=new FQ(e6x,this,9,9)),eRT(this.c);return;case 10:this.a||(this.a=new FQ(e6k,this,10,11)),eRT(this.a);return;case 11:eO$(this,null);return;case 12:this.b||(this.b=new FQ(e6g,this,12,3)),eRT(this.b);return}ep2(this,e)},eUe.Ib=function(){return eC4(this)},Y5(eZ3,"ElkNodeImpl",239),eTS(186,725,{105:1,413:1,82:1,160:1,118:1,470:1,186:1,94:1,92:1,90:1,56:1,108:1,49:1,97:1,114:1,115:1},mk),eUe.Qg=function(e){return eg2(this,e)},eUe._g=function(e,t,n){return 9==e?zY(this):ebQ(this,e,t,n)},eUe.hh=function(e,t,n){var r;return 9===t?(this.Cb&&(n=(r=this.Db>>16)>=0?eg2(this,n):this.Cb.ih(this,-1-r,null,n)),Cl(this,Pp(e,33),n)):evZ(this,e,t,n)},eUe.jh=function(e,t,n){return 9==t?Cl(this,null,n):evX(this,e,t,n)},eUe.lh=function(e){return 9==e?!!zY(this):esM(this,e)},eUe.sh=function(e,t){if(9===e){eOL(this,Pp(t,33));return}eTH(this,e,t)},eUe.zh=function(){return eBa(),tmv},eUe.Bh=function(e){if(9===e){eOL(this,null);return}ep2(this,e)},eUe.Ib=function(){return eC5(this)},Y5(eZ3,"ElkPortImpl",186);var e6M=RL(eX_,"BasicEMap/Entry");eTS(1092,115,{105:1,42:1,92:1,90:1,133:1,56:1,108:1,49:1,97:1,114:1,115:1},o3),eUe.Fb=function(e){return this===e},eUe.cd=function(){return this.b},eUe.Hb=function(){return Ao(this)},eUe.Uh=function(e){era(this,Pp(e,146))},eUe._g=function(e,t,n){switch(e){case 0:return this.b;case 1:return this.c}return ebl(this,e,t,n)},eUe.lh=function(e){switch(e){case 0:return!!this.b;case 1:return null!=this.c}return epY(this,e)},eUe.sh=function(e,t){switch(e){case 0:era(this,Pp(t,146));return;case 1:eru(this,t);return}eS5(this,e,t)},eUe.zh=function(){return eBa(),tmy},eUe.Bh=function(e){switch(e){case 0:era(this,null);return;case 1:eru(this,null);return}eSi(this,e)},eUe.Sh=function(){var e;return -1==this.a&&(e=this.b,this.a=e?esj(e):0),this.a},eUe.dd=function(){return this.c},eUe.Th=function(e){this.a=e},eUe.ed=function(e){var t;return t=this.c,eru(this,e),t},eUe.Ib=function(){var e;return(64&this.Db)!=0?eMT(this):(xM(xM(xM(e=new vc,this.b?this.b.tg():eUg),eGH),Ae(this.c)),e.a)},eUe.a=-1,eUe.c=null;var e6O=Y5(eZ3,"ElkPropertyToValueMapEntryImpl",1092);eTS(984,1,{},o6),Y5(eXk,"JsonAdapter",984),eTS(210,60,eHr,gK),Y5(eXk,"JsonImportException",210),eTS(857,1,{},eg6),Y5(eXk,"JsonImporter",857),eTS(891,1,{},kP),Y5(eXk,"JsonImporter/lambda$0$Type",891),eTS(892,1,{},kR),Y5(eXk,"JsonImporter/lambda$1$Type",892),eTS(900,1,{},h7),Y5(eXk,"JsonImporter/lambda$10$Type",900),eTS(902,1,{},kj),Y5(eXk,"JsonImporter/lambda$11$Type",902),eTS(903,1,{},kF),Y5(eXk,"JsonImporter/lambda$12$Type",903),eTS(909,1,{},HE),Y5(eXk,"JsonImporter/lambda$13$Type",909),eTS(908,1,{},H_),Y5(eXk,"JsonImporter/lambda$14$Type",908),eTS(904,1,{},kY),Y5(eXk,"JsonImporter/lambda$15$Type",904),eTS(905,1,{},kB),Y5(eXk,"JsonImporter/lambda$16$Type",905),eTS(906,1,{},kU),Y5(eXk,"JsonImporter/lambda$17$Type",906),eTS(907,1,{},kH),Y5(eXk,"JsonImporter/lambda$18$Type",907),eTS(912,1,{},pe),Y5(eXk,"JsonImporter/lambda$19$Type",912),eTS(893,1,{},pt),Y5(eXk,"JsonImporter/lambda$2$Type",893),eTS(910,1,{},pn),Y5(eXk,"JsonImporter/lambda$20$Type",910),eTS(911,1,{},pr),Y5(eXk,"JsonImporter/lambda$21$Type",911),eTS(915,1,{},pi),Y5(eXk,"JsonImporter/lambda$22$Type",915),eTS(913,1,{},pa),Y5(eXk,"JsonImporter/lambda$23$Type",913),eTS(914,1,{},po),Y5(eXk,"JsonImporter/lambda$24$Type",914),eTS(917,1,{},ps),Y5(eXk,"JsonImporter/lambda$25$Type",917),eTS(916,1,{},pu),Y5(eXk,"JsonImporter/lambda$26$Type",916),eTS(918,1,eUF,k$),eUe.td=function(e){JH(this.b,this.a,Lq(e))},Y5(eXk,"JsonImporter/lambda$27$Type",918),eTS(919,1,eUF,kz),eUe.td=function(e){J$(this.b,this.a,Lq(e))},Y5(eXk,"JsonImporter/lambda$28$Type",919),eTS(920,1,{},kG),Y5(eXk,"JsonImporter/lambda$29$Type",920),eTS(896,1,{},pc),Y5(eXk,"JsonImporter/lambda$3$Type",896),eTS(921,1,{},kW),Y5(eXk,"JsonImporter/lambda$30$Type",921),eTS(922,1,{},pl),Y5(eXk,"JsonImporter/lambda$31$Type",922),eTS(923,1,{},pf),Y5(eXk,"JsonImporter/lambda$32$Type",923),eTS(924,1,{},pd),Y5(eXk,"JsonImporter/lambda$33$Type",924),eTS(925,1,{},ph),Y5(eXk,"JsonImporter/lambda$34$Type",925),eTS(859,1,{},pp),Y5(eXk,"JsonImporter/lambda$35$Type",859),eTS(929,1,{},N8),Y5(eXk,"JsonImporter/lambda$36$Type",929),eTS(926,1,eUF,pb),eUe.td=function(e){qW(this.a,Pp(e,469))},Y5(eXk,"JsonImporter/lambda$37$Type",926),eTS(927,1,eUF,k0),eUe.td=function(e){xC(this.a,this.b,Pp(e,202))},Y5(eXk,"JsonImporter/lambda$38$Type",927),eTS(928,1,eUF,k2),eUe.td=function(e){xI(this.a,this.b,Pp(e,202))},Y5(eXk,"JsonImporter/lambda$39$Type",928),eTS(894,1,{},pm),Y5(eXk,"JsonImporter/lambda$4$Type",894),eTS(930,1,eUF,pg),eUe.td=function(e){qK(this.a,Pp(e,8))},Y5(eXk,"JsonImporter/lambda$40$Type",930),eTS(895,1,{},pv),Y5(eXk,"JsonImporter/lambda$5$Type",895),eTS(899,1,{},py),Y5(eXk,"JsonImporter/lambda$6$Type",899),eTS(897,1,{},pw),Y5(eXk,"JsonImporter/lambda$7$Type",897),eTS(898,1,{},p_),Y5(eXk,"JsonImporter/lambda$8$Type",898),eTS(901,1,{},pE),Y5(eXk,"JsonImporter/lambda$9$Type",901),eTS(948,1,eUF,pS),eUe.td=function(e){BC(this.a,new B_(Lq(e)))},Y5(eXk,"JsonMetaDataConverter/lambda$0$Type",948),eTS(949,1,eUF,pk),eUe.td=function(e){Bm(this.a,Pp(e,237))},Y5(eXk,"JsonMetaDataConverter/lambda$1$Type",949),eTS(950,1,eUF,px),eUe.td=function(e){GR(this.a,Pp(e,149))},Y5(eXk,"JsonMetaDataConverter/lambda$2$Type",950),eTS(951,1,eUF,pT),eUe.td=function(e){Bg(this.a,Pp(e,175))},Y5(eXk,"JsonMetaDataConverter/lambda$3$Type",951),eTS(237,22,{3:1,35:1,22:1,237:1},k1);var e6A=enw(ezx,"GraphFeature",237,e1G,etM,N1);eTS(13,1,{35:1,146:1},pO,Cm,xX,T2),eUe.wd=function(e){return Oo(this,Pp(e,146))},eUe.Fb=function(e){return $k(this,e)},eUe.wg=function(){return epB(this)},eUe.tg=function(){return this.b},eUe.Hb=function(){return ebA(this.b)},eUe.Ib=function(){return this.b},Y5(ezx,"Property",13),eTS(818,1,e$C,pM),eUe.ue=function(e,t){return elW(this,Pp(e,94),Pp(t,94))},eUe.Fb=function(e){return this===e},eUe.ve=function(){return new fZ(this)},Y5(ezx,"PropertyHolderComparator",818),eTS(695,1,eUE,pL),eUe.Nb=function(e){F8(this,e)},eUe.Pb=function(){return JZ(this)},eUe.Qb=function(){yI()},eUe.Ob=function(){return!!this.a},Y5(eXY,"ElkGraphUtil/AncestorIterator",695);var e6L=RL(eX_,"EList");eTS(67,52,{20:1,28:1,52:1,14:1,15:1,67:1,58:1}),eUe.Vc=function(e,t){elm(this,e,t)},eUe.Fc=function(e){return JL(this,e)},eUe.Wc=function(e,t){return eo0(this,e,t)},eUe.Gc=function(e){return Y4(this,e)},eUe.Zh=function(){return new AY(this)},eUe.$h=function(){return new AB(this)},eUe._h=function(e){return enH(this,e)},eUe.ai=function(){return!0},eUe.bi=function(e,t){},eUe.ci=function(){},eUe.di=function(e,t){X8(this,e,t)},eUe.ei=function(e,t,n){},eUe.fi=function(e,t){},eUe.gi=function(e,t,n){},eUe.Fb=function(e){return eCc(this,e)},eUe.Hb=function(){return eov(this)},eUe.hi=function(){return!1},eUe.Kc=function(){return new Ow(this)},eUe.Yc=function(){return new AF(this)},eUe.Zc=function(e){var t;if(t=this.gc(),e<0||e>t)throw p7(new Ii(e,t));return new YC(this,e)},eUe.ji=function(e,t){this.ii(e,this.Xc(t))},eUe.Mc=function(e){return eeu(this,e)},eUe.li=function(e,t){return t},eUe._c=function(e,t){return eby(this,e,t)},eUe.Ib=function(){return efq(this)},eUe.ni=function(){return!0},eUe.oi=function(e,t){return euu(this,t)},Y5(eX_,"AbstractEList",67),eTS(63,67,eXz,o7,eta,eiP),eUe.Vh=function(e,t){return ew2(this,e,t)},eUe.Wh=function(e){return emp(this,e)},eUe.Xh=function(e,t){ecW(this,e,t)},eUe.Yh=function(e){Zz(this,e)},eUe.pi=function(e){return J5(this,e)},eUe.$b=function(){ZG(this)},eUe.Hc=function(e){return ev9(this,e)},eUe.Xb=function(e){return etj(this,e)},eUe.qi=function(e){var t,n,r;++this.j,e>(n=null==this.g?0:this.g.length)&&(r=this.g,(t=n+(n/2|0)+4)=0&&(this.$c(t),!0)},eUe.mi=function(e,t){return this.Ui(e,this.oi(e,t))},eUe.gc=function(){return this.Vi()},eUe.Pc=function(){return this.Wi()},eUe.Qc=function(e){return this.Xi(e)},eUe.Ib=function(){return this.Yi()},Y5(eX_,"DelegatingEList",1995),eTS(1996,1995,eJk),eUe.Vh=function(e,t){return eD1(this,e,t)},eUe.Wh=function(e){return this.Vh(this.Vi(),e)},eUe.Xh=function(e,t){eTf(this,e,t)},eUe.Yh=function(e){exq(this,e)},eUe.ai=function(){return!this.bj()},eUe.$b=function(){eRP(this)},eUe.Zi=function(e,t,n,r,i){return new $P(this,e,t,n,r,i)},eUe.$i=function(e){eam(this.Ai(),e)},eUe._i=function(){return null},eUe.aj=function(){return -1},eUe.Ai=function(){return null},eUe.bj=function(){return!1},eUe.cj=function(e,t){return t},eUe.dj=function(e,t){return t},eUe.ej=function(){return!1},eUe.fj=function(){return!this.Ri()},eUe.ii=function(e,t){var n,r;return this.ej()?(r=this.fj(),n=e_R(this,e,t),this.$i(this.Zi(7,ell(t),n,e,r)),n):e_R(this,e,t)},eUe.$c=function(e){var t,n,r,i;return this.ej()?(n=null,r=this.fj(),t=this.Zi(4,i=RC(this,e),null,e,r),this.bj()&&i?(n=this.dj(i,n))?(n.Ei(t),n.Fi()):this.$i(t):n?(n.Ei(t),n.Fi()):this.$i(t),i):(i=RC(this,e),this.bj()&&i&&(n=this.dj(i,null))&&n.Fi(),i)},eUe.mi=function(e,t){return eD0(this,e,t)},Y5(eZK,"DelegatingNotifyingListImpl",1996),eTS(143,1,eJx),eUe.Ei=function(e){return ey7(this,e)},eUe.Fi=function(){QU(this)},eUe.xi=function(){return this.d},eUe._i=function(){return null},eUe.gj=function(){return null},eUe.yi=function(e){return -1},eUe.zi=function(){return eLo(this)},eUe.Ai=function(){return null},eUe.Bi=function(){return eLs(this)},eUe.Ci=function(){return this.o<0?this.o<-2?-2-this.o-1:-1:this.o},eUe.hj=function(){return!1},eUe.Di=function(e){var t,n,r,i,a,o,s,u,c,l,f;switch(this.d){case 1:case 2:switch(i=e.xi()){case 1:case 2:if(xc(a=e.Ai())===xc(this.Ai())&&this.yi(null)==e.yi(null))return this.g=e.zi(),1==e.xi()&&(this.d=1),!0}case 4:if(4===(i=e.xi())&&xc(a=e.Ai())===xc(this.Ai())&&this.yi(null)==e.yi(null))return c=eju(this),u=this.o<0?this.o<-2?-2-this.o-1:-1:this.o,o=e.Ci(),this.d=6,f=new eta(2),u<=o?(JL(f,this.n),JL(f,e.Bi()),this.g=eow(vx(ty_,1),eHT,25,15,[this.o=u,o+1])):(JL(f,e.Bi()),JL(f,this.n),this.g=eow(vx(ty_,1),eHT,25,15,[this.o=o,u])),this.n=f,c||(this.o=-2-this.o-1),!0;break;case 6:if(4===(i=e.xi())&&xc(a=e.Ai())===xc(this.Ai())&&this.yi(null)==e.yi(null)){for(c=eju(this),o=e.Ci(),r=Je(ty_,eHT,25,(l=Pp(this.g,48)).length+1,15,1),t=0;t>>0).toString(16)),r.a+=" (eventType: ",this.d){case 1:r.a+="SET";break;case 2:r.a+="UNSET";break;case 3:r.a+="ADD";break;case 5:r.a+="ADD_MANY";break;case 4:r.a+="REMOVE";break;case 6:r.a+="REMOVE_MANY";break;case 7:r.a+="MOVE";break;case 8:r.a+="REMOVING_ADAPTER";break;case 9:r.a+="RESOLVE";break;default:yz(r,this.d)}if(eIb(this)&&(r.a+=", touch: true"),r.a+=", position: ",yz(r,this.o<0?this.o<-2?-2-this.o-1:-1:this.o),r.a+=", notifier: ",xS(r,this.Ai()),r.a+=", feature: ",xS(r,this._i()),r.a+=", oldValue: ",xS(r,eLs(this)),r.a+=", newValue: ",6==this.d&&M4(this.g,48)){for(n=Pp(this.g,48),r.a+="[",e=0;e10?(this.b&&this.c.j==this.a||(this.b=new Rq(this),this.a=this.j),w0(this.b,e)):ev9(this,e)},eUe.ni=function(){return!0},eUe.a=0,Y5(eX_,"AbstractEList/1",953),eTS(295,73,eHZ,Ii),Y5(eX_,"AbstractEList/BasicIndexOutOfBoundsException",295),eTS(40,1,eUE,Ow),eUe.Nb=function(e){F8(this,e)},eUe.mj=function(){if(this.i.j!=this.f)throw p7(new bA)},eUe.nj=function(){return epH(this)},eUe.Ob=function(){return this.e!=this.i.gc()},eUe.Pb=function(){return this.nj()},eUe.Qb=function(){ey_(this)},eUe.e=0,eUe.f=0,eUe.g=-1,Y5(eX_,"AbstractEList/EIterator",40),eTS(278,40,eUC,AF,YC),eUe.Qb=function(){ey_(this)},eUe.Rb=function(e){edq(this,e)},eUe.oj=function(){var e;try{return e=this.d.Xb(--this.e),this.mj(),this.g=this.e,e}catch(t){if(t=eoa(t),M4(t,73))throw this.mj(),p7(new bC);throw p7(t)}},eUe.pj=function(e){emE(this,e)},eUe.Sb=function(){return 0!=this.e},eUe.Tb=function(){return this.e},eUe.Ub=function(){return this.oj()},eUe.Vb=function(){return this.e-1},eUe.Wb=function(e){this.pj(e)},Y5(eX_,"AbstractEList/EListIterator",278),eTS(341,40,eUE,AY),eUe.nj=function(){return ep$(this)},eUe.Qb=function(){throw p7(new bO)},Y5(eX_,"AbstractEList/NonResolvingEIterator",341),eTS(385,278,eUC,AB,IB),eUe.Rb=function(e){throw p7(new bO)},eUe.nj=function(){var e;try{return e=this.c.ki(this.e),this.mj(),this.g=this.e++,e}catch(t){if(t=eoa(t),M4(t,73))throw this.mj(),p7(new bC);throw p7(t)}},eUe.oj=function(){var e;try{return e=this.c.ki(--this.e),this.mj(),this.g=this.e,e}catch(t){if(t=eoa(t),M4(t,73))throw this.mj(),p7(new bC);throw p7(t)}},eUe.Qb=function(){throw p7(new bO)},eUe.Wb=function(e){throw p7(new bO)},Y5(eX_,"AbstractEList/NonResolvingEListIterator",385),eTS(1982,67,eJO),eUe.Vh=function(e,t){var n,r,i,a,o,s,u,c,l,f,d;if(0==(i=t.gc()))return++this.j,!1;for(r=eue(this,d=(l=null==(c=Pp(eaS(this.a,4),126))?0:c.length)+i),(f=l-e)>0&&ePD(c,e,r,e+i,f),u=t.Kc(),o=0;on)throw p7(new Ii(e,n));return new Uu(this,e)},eUe.$b=function(){var e,t;++this.j,t=null==(e=Pp(eaS(this.a,4),126))?0:e.length,eps(this,null),X8(this,t,e)},eUe.Hc=function(e){var t,n,r,i,a;if(null!=(t=Pp(eaS(this.a,4),126))){if(null!=e){for(i=0,a=(r=t).length;i=(n=null==(t=Pp(eaS(this.a,4),126))?0:t.length))throw p7(new Ii(e,n));return t[e]},eUe.Xc=function(e){var t,n,r;if(null!=(t=Pp(eaS(this.a,4),126))){if(null!=e){for(n=0,r=t.length;nn)throw p7(new Ii(e,n));return new Us(this,e)},eUe.ii=function(e,t){var n,r,i;if(i=null==(n=ehc(this))?0:n.length,e>=i)throw p7(new gE(eXU+e+eXH+i));if(t>=i)throw p7(new gE(eX$+t+eXH+i));return r=n[t],e!=t&&(e0&&ePD(e,0,t,0,n),t},eUe.Qc=function(e){var t,n,r;return(r=null==(t=Pp(eaS(this.a,4),126))?0:t.length)>0&&(e.lengthr&&Bc(e,r,null),e},Y5(eX_,"ArrayDelegatingEList",1982),eTS(1038,40,eUE,Zl),eUe.mj=function(){if(this.b.j!=this.f||xc(Pp(eaS(this.b.a,4),126))!==xc(this.a))throw p7(new bA)},eUe.Qb=function(){ey_(this),this.a=Pp(eaS(this.b.a,4),126)},Y5(eX_,"ArrayDelegatingEList/EIterator",1038),eTS(706,278,eUC,FK,Us),eUe.mj=function(){if(this.b.j!=this.f||xc(Pp(eaS(this.b.a,4),126))!==xc(this.a))throw p7(new bA)},eUe.pj=function(e){emE(this,e),this.a=Pp(eaS(this.b.a,4),126)},eUe.Qb=function(){ey_(this),this.a=Pp(eaS(this.b.a,4),126)},Y5(eX_,"ArrayDelegatingEList/EListIterator",706),eTS(1039,341,eUE,Zf),eUe.mj=function(){if(this.b.j!=this.f||xc(Pp(eaS(this.b.a,4),126))!==xc(this.a))throw p7(new bA)},Y5(eX_,"ArrayDelegatingEList/NonResolvingEIterator",1039),eTS(707,385,eUC,FV,Uu),eUe.mj=function(){if(this.b.j!=this.f||xc(Pp(eaS(this.b.a,4),126))!==xc(this.a))throw p7(new bA)},Y5(eX_,"ArrayDelegatingEList/NonResolvingEListIterator",707),eTS(606,295,eHZ,xJ),Y5(eX_,"BasicEList/BasicIndexOutOfBoundsException",606),eTS(696,63,eXz,xt),eUe.Vc=function(e,t){throw p7(new bO)},eUe.Fc=function(e){throw p7(new bO)},eUe.Wc=function(e,t){throw p7(new bO)},eUe.Gc=function(e){throw p7(new bO)},eUe.$b=function(){throw p7(new bO)},eUe.qi=function(e){throw p7(new bO)},eUe.Kc=function(){return this.Zh()},eUe.Yc=function(){return this.$h()},eUe.Zc=function(e){return this._h(e)},eUe.ii=function(e,t){throw p7(new bO)},eUe.ji=function(e,t){throw p7(new bO)},eUe.$c=function(e){throw p7(new bO)},eUe.Mc=function(e){throw p7(new bO)},eUe._c=function(e,t){throw p7(new bO)},Y5(eX_,"BasicEList/UnmodifiableEList",696),eTS(705,1,{3:1,20:1,14:1,15:1,58:1,589:1}),eUe.Vc=function(e,t){Mq(this,e,Pp(t,42))},eUe.Fc=function(e){return LA(this,Pp(e,42))},eUe.Jc=function(e){qX(this,e)},eUe.Xb=function(e){return Pp(etj(this.c,e),133)},eUe.ii=function(e,t){return Pp(this.c.ii(e,t),42)},eUe.ji=function(e,t){MZ(this,e,Pp(t,42))},eUe.Lc=function(){return new R1(null,new Gq(this,16))},eUe.$c=function(e){return Pp(this.c.$c(e),42)},eUe._c=function(e,t){return YV(this,e,Pp(t,42))},eUe.ad=function(e){er8(this,e)},eUe.Nc=function(){return new Gq(this,16)},eUe.Oc=function(){return new R1(null,new Gq(this,16))},eUe.Wc=function(e,t){return this.c.Wc(e,t)},eUe.Gc=function(e){return this.c.Gc(e)},eUe.$b=function(){this.c.$b()},eUe.Hc=function(e){return this.c.Hc(e)},eUe.Ic=function(e){return eot(this.c,e)},eUe.qj=function(){var e,t,n;if(null==this.d){for(this.d=Je(e6C,eJA,63,2*this.f+1,0,1),n=this.e,this.f=0,t=this.c.Kc();t.e!=t.i.gc();)ebB(this,e=Pp(t.nj(),133));this.e=n}},eUe.Fb=function(e){return Ij(this,e)},eUe.Hb=function(){return eov(this.c)},eUe.Xc=function(e){return this.c.Xc(e)},eUe.rj=function(){this.c=new pC(this)},eUe.dc=function(){return 0==this.f},eUe.Kc=function(){return this.c.Kc()},eUe.Yc=function(){return this.c.Yc()},eUe.Zc=function(e){return this.c.Zc(e)},eUe.sj=function(){return X6(this)},eUe.tj=function(e,t,n){return new N7(e,t,n)},eUe.uj=function(){return new st},eUe.Mc=function(e){return en$(this,e)},eUe.gc=function(){return this.f},eUe.bd=function(e,t){return new Gz(this.c,e,t)},eUe.Pc=function(){return this.c.Pc()},eUe.Qc=function(e){return this.c.Qc(e)},eUe.Ib=function(){return efq(this.c)},eUe.e=0,eUe.f=0,Y5(eX_,"BasicEMap",705),eTS(1033,63,eXz,pC),eUe.bi=function(e,t){bH(this,Pp(t,133))},eUe.ei=function(e,t,n){var r;++(r=this,Pp(t,133),r).a.e},eUe.fi=function(e,t){b$(this,Pp(t,133))},eUe.gi=function(e,t,n){AO(this,Pp(t,133),Pp(n,133))},eUe.di=function(e,t){eac(this.a)},Y5(eX_,"BasicEMap/1",1033),eTS(1034,63,eXz,st),eUe.ri=function(e){return Je(e6R,eJL,612,e,0,1)},Y5(eX_,"BasicEMap/2",1034),eTS(1035,eUT,eUM,pI),eUe.$b=function(){this.a.c.$b()},eUe.Hc=function(e){return edG(this.a,e)},eUe.Kc=function(){return 0==this.a.f?(LF(),tmB.a):new yd(this.a)},eUe.Mc=function(e){var t;return t=this.a.f,ehx(this.a,e),this.a.f!=t},eUe.gc=function(){return this.a.f},Y5(eX_,"BasicEMap/3",1035),eTS(1036,28,eUx,pD),eUe.$b=function(){this.a.c.$b()},eUe.Hc=function(e){return eCl(this.a,e)},eUe.Kc=function(){return 0==this.a.f?(LF(),tmB.a):new yh(this.a)},eUe.gc=function(){return this.a.f},Y5(eX_,"BasicEMap/4",1036),eTS(1037,eUT,eUM,pN),eUe.$b=function(){this.a.c.$b()},eUe.Hc=function(e){var t,n,r,i,a,o,s,u,c;if(this.a.f>0&&M4(e,42)&&(this.a.qj(),i=null==(s=(u=Pp(e,42)).cd())?0:esj(s),a=Cb(this.a,i),t=this.a.d[a])){for(o=0,n=Pp(t.g,367),c=t.i;o"+this.c},eUe.a=0;var e6R=Y5(eX_,"BasicEMap/EntryImpl",612);eTS(536,1,{},o2),Y5(eX_,"BasicEMap/View",536),eTS(768,1,{}),eUe.Fb=function(e){return eT$((Hj(),e2r),e)},eUe.Hb=function(){return esS((Hj(),e2r))},eUe.Ib=function(){return e_F((Hj(),e2r))},Y5(eX_,"ECollections/BasicEmptyUnmodifiableEList",768),eTS(1312,1,eUC,sn),eUe.Nb=function(e){F8(this,e)},eUe.Rb=function(e){throw p7(new bO)},eUe.Ob=function(){return!1},eUe.Sb=function(){return!1},eUe.Pb=function(){throw p7(new bC)},eUe.Tb=function(){return 0},eUe.Ub=function(){throw p7(new bC)},eUe.Vb=function(){return -1},eUe.Qb=function(){throw p7(new bO)},eUe.Wb=function(e){throw p7(new bO)},Y5(eX_,"ECollections/BasicEmptyUnmodifiableEList/1",1312),eTS(1310,768,{20:1,14:1,15:1,58:1},mx),eUe.Vc=function(e,t){y5()},eUe.Fc=function(e){return y6()},eUe.Wc=function(e,t){return y9()},eUe.Gc=function(e){return y8()},eUe.$b=function(){y7()},eUe.Hc=function(e){return!1},eUe.Ic=function(e){return!1},eUe.Jc=function(e){qX(this,e)},eUe.Xb=function(e){return xY((Hj(),e)),null},eUe.Xc=function(e){return -1},eUe.dc=function(){return!0},eUe.Kc=function(){return this.a},eUe.Yc=function(){return this.a},eUe.Zc=function(e){return this.a},eUe.ii=function(e,t){return we()},eUe.ji=function(e,t){wt()},eUe.Lc=function(){return new R1(null,new Gq(this,16))},eUe.$c=function(e){return wn()},eUe.Mc=function(e){return wr()},eUe._c=function(e,t){return wi()},eUe.gc=function(){return 0},eUe.ad=function(e){er8(this,e)},eUe.Nc=function(){return new Gq(this,16)},eUe.Oc=function(){return new R1(null,new Gq(this,16))},eUe.bd=function(e,t){return Hj(),new Gz(e2r,e,t)},eUe.Pc=function(){return Fn((Hj(),e2r))},eUe.Qc=function(e){return Hj(),emk(e2r,e)},Y5(eX_,"ECollections/EmptyUnmodifiableEList",1310),eTS(1311,768,{20:1,14:1,15:1,58:1,589:1},mT),eUe.Vc=function(e,t){y5()},eUe.Fc=function(e){return y6()},eUe.Wc=function(e,t){return y9()},eUe.Gc=function(e){return y8()},eUe.$b=function(){y7()},eUe.Hc=function(e){return!1},eUe.Ic=function(e){return!1},eUe.Jc=function(e){qX(this,e)},eUe.Xb=function(e){return xY((Hj(),e)),null},eUe.Xc=function(e){return -1},eUe.dc=function(){return!0},eUe.Kc=function(){return this.a},eUe.Yc=function(){return this.a},eUe.Zc=function(e){return this.a},eUe.ii=function(e,t){return we()},eUe.ji=function(e,t){wt()},eUe.Lc=function(){return new R1(null,new Gq(this,16))},eUe.$c=function(e){return wn()},eUe.Mc=function(e){return wr()},eUe._c=function(e,t){return wi()},eUe.gc=function(){return 0},eUe.ad=function(e){er8(this,e)},eUe.Nc=function(){return new Gq(this,16)},eUe.Oc=function(){return new R1(null,new Gq(this,16))},eUe.bd=function(e,t){return Hj(),new Gz(e2r,e,t)},eUe.Pc=function(){return Fn((Hj(),e2r))},eUe.Qc=function(e){return Hj(),emk(e2r,e)},eUe.sj=function(){return Hj(),Hj(),e2i},Y5(eX_,"ECollections/EmptyUnmodifiableEMap",1311);var e6j=RL(eX_,"Enumerator");eTS(281,1,{281:1},eCg),eUe.Fb=function(e){var t;return this===e||!!M4(e,281)&&(t=Pp(e,281),this.f==t.f&&jx(this.i,t.i)&&jk(this.a,(256&this.f)!=0?(256&t.f)!=0?t.a:null:(256&t.f)!=0?null:t.a)&&jk(this.d,t.d)&&jk(this.g,t.g)&&jk(this.e,t.e)&&epK(this,t))},eUe.Hb=function(){return this.f},eUe.Ib=function(){return eDv(this)},eUe.f=0;var e6F,e6Y,e6B,e6U,e6H,e6$,e6z,e6G,e6W,e6K,e6V,e6q,e6Z,e6X,e6J,e6Q,e61,e60,e62,e63,e64,e65,e66,e69,e68,e67,e9e,e9t,e9n,e9r,e9i,e9a,e9o,e9s,e9u,e9c,e9l,e9f,e9d,e9h,e9p,e9b,e9m,e9g,e9v,e9y,e9w,e9_,e9E,e9S,e9k,e9x,e9T,e9M,e9O,e9A,e9L,e9C,e9I,e9D,e9N,e9P,e9R,e9j,e9F,e9Y,e9B,e9U,e9H,e9$,e9z,e9G,e9W,e9K,e9V,e9q,e9Z,e9X,e9J,e9Q,e91,e90,e92,e93,e94,e95,e96,e99,e98,e97,e8e,e8t,e8n,e8r,e8i,e8a,e8o,e8s,e8u,e8c,e8l,e8f,e8d,e8h,e8p,e8b,e8m,e8g,e8v,e8y,e8w,e8_,e8E,e8S,e8k,e8x,e8T,e8M,e8O,e8A,e8L,e8C,e8I,e8D,e8N,e8P,e8R,e8j,e8F,e8Y,e8B,e8U,e8H,e8$,e8z,e8G,e8W,e8K,e8V,e8q,e8Z,e8X,e8J,e8Q,e81,e80,e82,e83,e84,e85,e86,e89,e88,e87,e7e,e7t,e7n,e7r,e7i,e7a,e7o,e7s,e7u,e7c,e7l,e7f,e7d,e7h,e7p,e7b,e7m,e7g,e7v,e7y,e7w,e7_,e7E,e7S,e7k,e7x,e7T,e7M,e7O,e7A,e7L,e7C,e7I,e7D,e7N,e7P,e7R,e7j,e7F,e7Y,e7B,e7U,e7H,e7$,e7z,e7G,e7W,e7K,e7V,e7q,e7Z,e7X,e7J,e7Q,e71,e70,e72,e73,e74,e75,e76,e79,e78,e77,tee,tet,ten,ter,tei,tea,teo,tes,teu,tec,tel,tef,ted,teh,tep,teb,tem,teg,tev,tey,tew,te_,teE,teS,tek,tex,teT,teM,teO,teA,teL,teC,teI,teD,teN,teP,teR,tej,teF,teY,teB,teU,teH,te$,tez,teG,teW,teK,teV,teq,teZ,teX,teJ,teQ,te1,te0,te2,te3,te4,te5,te6,te9,te8,te7,tte,ttt,ttn,ttr,tti,tta,tto,tts,ttu,ttc,ttl,ttf,ttd,tth,ttp,ttb,ttm,ttg,ttv,tty,ttw,tt_,ttE,ttS,ttk,ttx,ttT,ttM,ttO,ttA,ttL,ttC,ttI,ttD,ttN,ttP,ttR,ttj,ttF,ttY,ttB,ttU,ttH,tt$,ttz,ttG,ttW,ttK,ttV,ttq,ttZ,ttX,ttJ,ttQ,tt1,tt0,tt2,tt3,tt4,tt5,tt6,tt9,tt8,tt7,tne,tnt,tnn,tnr,tni,tna,tno,tns,tnu,tnc,tnl,tnf,tnd,tnh,tnp,tnb,tnm,tng,tnv,tny,tnw,tn_,tnE,tnS,tnk,tnx,tnT,tnM,tnO,tnA,tnL,tnC,tnI,tnD,tnN,tnP,tnR,tnj,tnF,tnY,tnB,tnU,tnH,tn$,tnz,tnG,tnW,tnK,tnV,tnq,tnZ,tnX,tnJ,tnQ,tn1,tn0,tn2,tn3,tn4,tn5,tn6,tn9,tn8,tn7,tre,trt,trn,trr,tri,tra,tro,trs,tru,trc,trl,trf,trd,trh,trp,trb,trm,trg,trv,trw,tr_,trE,trS,trk,trx,trT,trM,trO,trA,trL,trC,trI,trD,trN,trP,trR,trj,trF,trY,trB,trU,trH,tr$,trz,trG,trW,trK,trV,trq,trZ,trX,trJ,trQ,tr1,tr0,tr2,tr3,tr4,tr5,tr6,tr9,tr8,tr7,tie,tit,tin,tir,tii,tia,tio,tis,tiu,tic,til,tif,tid,tih,tip,tib,tim,tig,tiv,tiy,tiw,ti_,tiE,tiS,tik,tix,tiT,tiM,tiO,tiA,tiL,tiC,tiI,tiD,tiN,tiP,tiR,tij,tiF,tiY,tiB,tiU,tiH,ti$,tiz,tiG,tiW,tiK,tiV,tiq,tiZ,tiX,tiJ,tiQ,ti1,ti0,ti2,ti3,ti4,ti5,ti6,ti9,ti8,ti7,tae,tat,tan,tar,tai,taa,tao,tas,tau,tac,tal,taf,tad,tah,tap,tab,tam,tag,tav,tay,taw,ta_,taE,taS,tak,tax,taT,taM,taO,taA,taL,taC,taI,taD,taN,taP,taR,taj,taF,taY,taB,taU,taH,ta$,taz,taG,taW,taK,taV,taq,taZ,taX,taJ,taQ,ta1,ta0,ta2,ta3,ta4,ta5,ta6,ta9,ta8,ta7,toe,tot,ton,tor,toi,toa,too,tos,tou,toc,tol,tof,tod,toh,top,tob,tom,tog,tov,toy,tow,to_,toE,toS,tok,tox,toT,toM,toO,toA,toL,toC,toI,toD,toN,toP,toR,toj,toF,toY,toB,toU,toH,to$,toz,toG,toW,toK,toV,toq,toZ,toX,toJ,toQ,to1,to0,to2,to3,to4,to5,to6,to9,to8,to7,tse,tst,tsn,tsr,tsi,tsa,tso,tss,tsu,tsc,tsl,tsf,tsd,tsh,tsp,tsb,tsm,tsg,tsv,tsy,tsw,ts_,tsE,tsS,tsk,tsx,tsT,tsM,tsO,tsA,tsL,tsC,tsI,tsD,tsN,tsP,tsR,tsj,tsF,tsY,tsB,tsU,tsH,ts$,tsz,tsG,tsW,tsK,tsV,tsq,tsZ,tsX,tsJ,tsQ,ts1,ts0,ts2,ts3,ts4,ts5,ts6,ts9,ts8,ts7,tue,tut,tun,tur,tui,tua,tuo,tus,tuu,tuc,tul,tuf,tud,tuh,tup,tub,tum,tug,tuv,tuy,tuw,tu_,tuE,tuS,tuk,tux,tuT,tuM,tuO,tuA,tuL,tuC,tuI,tuD,tuN,tuP,tuR,tuj,tuF,tuY,tuB,tuU,tuH,tu$,tuz,tuG,tuW,tuK,tuV,tuq,tuZ,tuX,tuJ,tuQ,tu1,tu0,tu2,tu3,tu4,tu5,tu6,tu9,tu8,tu7,tce,tct,tcn,tcr,tci,tca,tco,tcs,tcu,tcc,tcl,tcf,tcd,tch,tcp,tcb,tcm,tcg,tcv,tcy,tcw,tc_,tcE,tcS,tck,tcx,tcT,tcM,tcO,tcA,tcL,tcC,tcI,tcD,tcN,tcP,tcR,tcj,tcF,tcY,tcB,tcU,tcH,tc$,tcz,tcG,tcW,tcK,tcV,tcq,tcZ,tcX,tcJ,tcQ,tc1,tc0,tc2,tc3,tc4,tc5,tc6,tc9,tc8,tc7,tle,tlt,tln,tlr,tli,tla,tlo,tls,tlu,tlc,tll,tlf,tld,tlh,tlp,tlb,tlm,tlg,tlv,tly,tlw,tl_,tlE,tlS,tlk,tlx,tlT,tlM,tlO,tlA,tlL,tlC,tlI,tlD,tlN,tlP,tlR,tlj,tlF,tlY,tlB,tlU,tlH,tl$,tlz,tlG,tlW,tlK,tlV,tlq,tlZ,tlX,tlJ,tlQ,tl1,tl0,tl2,tl3,tl4,tl5,tl6,tl9,tl8,tl7,tfe,tft,tfn,tfr,tfi,tfa,tfo,tfs,tfu,tfc,tfl,tff,tfd,tfh,tfp,tfb,tfm,tfg,tfv,tfy,tfw,tf_,tfE,tfS,tfk,tfx,tfT,tfM,tfO,tfA,tfL,tfC,tfI,tfD,tfN,tfP,tfR,tfj,tfF,tfY,tfB,tfU,tfH,tf$,tfz,tfG,tfW,tfK,tfV,tfq,tfZ,tfX,tfJ,tfQ,tf1,tf0,tf2,tf3,tf4,tf5,tf6,tf9,tf8,tf7,tde,tdt,tdn,tdr,tdi,tda,tdo,tds,tdu,tdc,tdl,tdf,tdd,tdh,tdp,tdb,tdm,tdg,tdv,tdy,tdw,td_,tdE,tdS,tdk,tdx,tdT,tdM,tdO,tdA,tdL,tdC,tdI,tdD,tdN,tdP,tdR,tdj,tdF,tdY,tdB,tdU,tdH,td$,tdz,tdG,tdW,tdK,tdV,tdq,tdZ,tdX,tdJ,tdQ,td1,td0,td2,td3,td4,td5,td6,td9,td8,td7,the,tht,thn,thr,thi,tha,tho,ths,thu,thc,thl,thf,thd,thh,thp,thb,thm,thg,thv,thy,thw,th_,thE,thS,thk,thx,thT,thM,thO,thA,thL,thC,thI,thD,thN,thP,thR,thj,thF,thY,thB,thU,thH,th$,thz,thG,thW,thK,thV,thq,thZ,thX,thJ,thQ,th1,th0,th2,th3,th4,th5,th6,th9,th8,th7,tpe,tpt,tpn,tpr,tpi,tpa,tpo,tps,tpu,tpc,tpl,tpf,tpd,tph,tpp,tpb,tpm,tpg,tpv,tpy,tpw,tp_,tpE,tpS,tpk,tpx,tpT,tpM,tpO,tpA,tpL,tpC,tpI,tpD,tpN,tpP,tpR,tpj,tpF,tpY,tpB,tpU,tpH,tp$,tpz,tpG,tpW,tpK,tpV,tpq,tpZ,tpX,tpJ,tpQ,tp1,tp0,tp2,tp3,tp4,tp5,tp6,tp9,tp8,tp7,tbe,tbt,tbn,tbr,tbi,tba,tbo,tbs,tbu,tbc,tbl,tbf,tbd,tbh,tbp,tbb,tbm,tbg,tbv,tby,tbw,tb_,tbE,tbS,tbk,tbx,tbT,tbM,tbO,tbA,tbL,tbC,tbI,tbD,tbN,tbP,tbR,tbj,tbF,tbY,tbB,tbU,tbH,tb$,tbz,tbG,tbW,tbK,tbV,tbq,tbZ,tbX,tbJ,tbQ,tb1,tb0,tb2,tb3,tb4,tb5,tb6,tb9,tb8,tb7,tme,tmt,tmn,tmr,tmi,tma,tmo,tms,tmu,tmc,tml,tmf,tmd,tmh,tmp,tmb,tmm,tmg,tmv,tmy,tmw,tm_,tmE,tmS,tmk,tmx,tmT,tmM,tmO,tmA,tmL,tmC,tmI,tmD,tmN,tmP,tmR,tmj,tmF,tmY,tmB,tmU,tmH,tm$,tmz,tmG=0,tmW=0,tmK=0,tmV=0,tmq=0,tmZ=0,tmX=0,tmJ=0,tmQ=0,tm1=0,tm0=0,tm2=0,tm3=0;Y5(eX_,"URI",281),eTS(1091,43,e$s,mM),eUe.zc=function(e,t){return Pp(Ge(this,Lq(e),Pp(t,281)),281)},Y5(eX_,"URI/URICache",1091),eTS(497,63,eXz,o5,jf),eUe.hi=function(){return!0},Y5(eX_,"UniqueEList",497),eTS(581,60,eHr,QH),Y5(eX_,"WrappedException",581);var tm4=RL(eZD,eJD),tm5=RL(eZD,eJN),tm6=RL(eZD,eJP),tm9=RL(eZD,eJR),tm8=RL(eZD,eJj),tm7=RL(eZD,"EClass"),tge=RL(eZD,"EDataType");eTS(1183,43,e$s,mO),eUe.xc=function(e){return xd(e)?zg(this,e):xu($I(this.f,e))},Y5(eZD,"EDataType/Internal/ConversionDelegate/Factory/Registry/Impl",1183);var tgt=RL(eZD,"EEnum"),tgn=RL(eZD,eJF),tgr=RL(eZD,eJY),tgi=RL(eZD,eJB),tga=RL(eZD,eJU),tgo=RL(eZD,eJH);eTS(1029,1,{},o4),eUe.Ib=function(){return"NIL"},Y5(eZD,"EStructuralFeature/Internal/DynamicValueHolder/1",1029),eTS(1028,43,e$s,mA),eUe.xc=function(e){return xd(e)?zg(this,e):xu($I(this.f,e))},Y5(eZD,"EStructuralFeature/Internal/SettingDelegate/Factory/Registry/Impl",1028);var tgs=RL(eZD,eJ$),tgu=RL(eZD,"EValidator/PatternMatcher"),tgc=RL(eJz,"FeatureMap/Entry");eTS(535,1,{72:1},k3),eUe.ak=function(){return this.a},eUe.dd=function(){return this.b},Y5(eZ2,"BasicEObjectImpl/1",535),eTS(1027,1,eJG,k4),eUe.Wj=function(e){return ZN(this.a,this.b,e)},eUe.fj=function(){return zz(this.a,this.b)},eUe.Wb=function(e){zx(this.a,this.b,e)},eUe.Xj=function(){B4(this.a,this.b)},Y5(eZ2,"BasicEObjectImpl/4",1027),eTS(1983,1,{108:1}),eUe.bk=function(e){this.e=0==e?tgH:Je(e1R,eUp,1,e,5,1)},eUe.Ch=function(e){return this.e[e]},eUe.Dh=function(e,t){this.e[e]=t},eUe.Eh=function(e){this.e[e]=null},eUe.ck=function(){return this.c},eUe.dk=function(){throw p7(new bO)},eUe.ek=function(){throw p7(new bO)},eUe.fk=function(){return this.d},eUe.gk=function(){return null!=this.e},eUe.hk=function(e){this.c=e},eUe.ik=function(e){throw p7(new bO)},eUe.jk=function(e){throw p7(new bO)},eUe.kk=function(e){this.d=e},Y5(eZ2,"BasicEObjectImpl/EPropertiesHolderBaseImpl",1983),eTS(185,1983,{108:1},c1),eUe.dk=function(){return this.a},eUe.ek=function(){return this.b},eUe.ik=function(e){this.a=e},eUe.jk=function(e){this.b=e},Y5(eZ2,"BasicEObjectImpl/EPropertiesHolderImpl",185),eTS(506,97,eZ0,sr),eUe.Kg=function(){return this.f},eUe.Pg=function(){return this.k},eUe.Rg=function(e,t){this.g=e,this.i=t},eUe.Tg=function(){return(2&this.j)==0?this.zh():this.ph().ck()},eUe.Vg=function(){return this.i},eUe.Mg=function(){return(1&this.j)!=0},eUe.eh=function(){return this.g},eUe.kh=function(){return(4&this.j)!=0},eUe.ph=function(){return this.k||(this.k=new c1),this.k},eUe.th=function(e){this.ph().hk(e),e?this.j|=2:this.j&=-3},eUe.vh=function(e){this.ph().jk(e),e?this.j|=4:this.j&=-5},eUe.zh=function(){return(BM(),tgv).S},eUe.i=0,eUe.j=1,Y5(eZ2,"EObjectImpl",506),eTS(780,506,{105:1,92:1,90:1,56:1,108:1,49:1,97:1},Pq),eUe.Ch=function(e){return this.e[e]},eUe.Dh=function(e,t){this.e[e]=t},eUe.Eh=function(e){this.e[e]=null},eUe.Tg=function(){return this.d},eUe.Yg=function(e){return edv(this.d,e)},eUe.$g=function(){return this.d},eUe.dh=function(){return null!=this.e},eUe.ph=function(){return this.k||(this.k=new si),this.k},eUe.th=function(e){this.d=e},eUe.yh=function(){var e;return null==this.e&&(e=Y1(this.d),this.e=0==e?tg$:Je(e1R,eUp,1,e,5,1)),this},eUe.Ah=function(){return 0},Y5(eZ2,"DynamicEObjectImpl",780),eTS(1376,780,{105:1,42:1,92:1,90:1,133:1,56:1,108:1,49:1,97:1},RO),eUe.Fb=function(e){return this===e},eUe.Hb=function(){return Ao(this)},eUe.th=function(e){this.d=e,this.b=eAh(e,"key"),this.c=eAh(e,eXr)},eUe.Sh=function(){var e;return -1==this.a&&(e=Q9(this,this.b),this.a=null==e?0:esj(e)),this.a},eUe.cd=function(){return Q9(this,this.b)},eUe.dd=function(){return Q9(this,this.c)},eUe.Th=function(e){this.a=e},eUe.Uh=function(e){zx(this,this.b,e)},eUe.ed=function(e){var t;return t=Q9(this,this.c),zx(this,this.c,e),t},eUe.a=0,Y5(eZ2,"DynamicEObjectImpl/BasicEMapEntry",1376),eTS(1377,1,{108:1},si),eUe.bk=function(e){throw p7(new bO)},eUe.Ch=function(e){throw p7(new bO)},eUe.Dh=function(e,t){throw p7(new bO)},eUe.Eh=function(e){throw p7(new bO)},eUe.ck=function(){throw p7(new bO)},eUe.dk=function(){return this.a},eUe.ek=function(){return this.b},eUe.fk=function(){return this.c},eUe.gk=function(){throw p7(new bO)},eUe.hk=function(e){throw p7(new bO)},eUe.ik=function(e){this.a=e},eUe.jk=function(e){this.b=e},eUe.kk=function(e){this.c=e},Y5(eZ2,"DynamicEObjectImpl/DynamicEPropertiesHolderImpl",1377),eTS(510,150,{105:1,92:1,90:1,590:1,147:1,56:1,108:1,49:1,97:1,510:1,150:1,114:1,115:1},sa),eUe.Qg=function(e){return eg4(this,e)},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.d;case 2:return n?(this.b||(this.b=new L_((eBK(),tgF),tgf,this)),this.b):(this.b||(this.b=new L_((eBK(),tgF),tgf,this)),X6(this.b));case 3:return z4(this);case 4:return this.a||(this.a=new O_(e6f,this,4)),this.a;case 5:return this.c||(this.c=new OT(e6f,this,5)),this.c}return Qt(this,e-Y1((eBK(),tgy)),ee2((r=Pp(eaS(this,16),26))||tgy,e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 3:return this.Cb&&(n=(i=this.Db>>16)>=0?eg4(this,n):this.Cb.ih(this,-1-i,null,n)),j3(this,Pp(e,147),n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgy),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tgy)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 2:return this.b||(this.b=new L_((eBK(),tgF),tgf,this)),Iz(this.b,e,n);case 3:return j3(this,null,n);case 4:return this.a||(this.a=new O_(e6f,this,4)),ep6(this.a,e,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgy),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgy)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.d;case 2:return!!this.b&&0!=this.b.f;case 3:return!!z4(this);case 4:return!!this.a&&0!=this.a.i;case 5:return!!this.c&&0!=this.c.i}return VP(this,e-Y1((eBK(),tgy)),ee2((t=Pp(eaS(this,16),26))||tgy,e))},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:RN(this,Lq(t));return;case 2:this.b||(this.b=new L_((eBK(),tgF),tgf,this)),eai(this.b,t);return;case 3:eAc(this,Pp(t,147));return;case 4:this.a||(this.a=new O_(e6f,this,4)),eRT(this.a),this.a||(this.a=new O_(e6f,this,4)),Y4(this.a,Pp(t,14));return;case 5:this.c||(this.c=new OT(e6f,this,5)),eRT(this.c),this.c||(this.c=new OT(e6f,this,5)),Y4(this.c,Pp(t,14));return}efL(this,e-Y1((eBK(),tgy)),ee2((n=Pp(eaS(this,16),26))||tgy,e),t)},eUe.zh=function(){return eBK(),tgy},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:erl(this,null);return;case 2:this.b||(this.b=new L_((eBK(),tgF),tgf,this)),this.b.c.$b();return;case 3:eAc(this,null);return;case 4:this.a||(this.a=new O_(e6f,this,4)),eRT(this.a);return;case 5:this.c||(this.c=new OT(e6f,this,5)),eRT(this.c);return}ec6(this,e-Y1((eBK(),tgy)),ee2((t=Pp(eaS(this,16),26))||tgy,e))},eUe.Ib=function(){return eln(this)},eUe.d=null,Y5(eZ2,"EAnnotationImpl",510),eTS(151,705,eJW,JY),eUe.Xh=function(e,t){T7(this,e,Pp(t,42))},eUe.lk=function(e,t){return I$(this,Pp(e,42),t)},eUe.pi=function(e){return Pp(Pp(this.c,69).pi(e),133)},eUe.Zh=function(){return Pp(this.c,69).Zh()},eUe.$h=function(){return Pp(this.c,69).$h()},eUe._h=function(e){return Pp(this.c,69)._h(e)},eUe.mk=function(e,t){return Iz(this,e,t)},eUe.Wj=function(e){return Pp(this.c,76).Wj(e)},eUe.rj=function(){},eUe.fj=function(){return Pp(this.c,76).fj()},eUe.tj=function(e,t,n){var r;return(r=Pp(etP(this.b).Nh().Jh(this.b),133)).Th(e),r.Uh(t),r.ed(n),r},eUe.uj=function(){return new pZ(this)},eUe.Wb=function(e){eai(this,e)},eUe.Xj=function(){Pp(this.c,76).Xj()},Y5(eJz,"EcoreEMap",151),eTS(158,151,eJW,L_),eUe.qj=function(){var e,t,n,r,i,a;if(null==this.d){for(a=Je(e6C,eJA,63,2*this.f+1,0,1),n=this.c.Kc();n.e!=n.i.gc();)(e=a[i=((r=(t=Pp(n.nj(),133)).Sh())&eUu)%a.length])||(e=a[i]=new pZ(this)),e.Fc(t);this.d=a}},Y5(eZ2,"EAnnotationImpl/1",158),eTS(284,438,{105:1,92:1,90:1,147:1,191:1,56:1,108:1,472:1,49:1,97:1,150:1,284:1,114:1,115:1}),eUe._g=function(e,t,n){var r,i;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return OQ(),(256&this.Bb)!=0;case 3:return OQ(),(512&this.Bb)!=0;case 4:return ell(this.s);case 5:return ell(this.t);case 6:return OQ(),!!this.$j();case 7:return OQ(),(i=this.s)>=1;case 8:if(t)return evl(this);return this.r;case 9:return this.q}return Qt(this,e-Y1(this.zh()),ee2((r=Pp(eaS(this,16),26))||this.zh(),e),t,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 9:return Y3(this,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||this.zh(),t),66)).Nj().Rj(this,ehH(this),t-Y1(this.zh()),e,n)},eUe.lh=function(e){var t,n;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return(256&this.Bb)==0;case 3:return(512&this.Bb)==0;case 4:return 0!=this.s;case 5:return 1!=this.t;case 6:return this.$j();case 7:return(n=this.s)>=1;case 8:return!!this.r&&!this.q.e&&0==BX(this.q).i;case 9:return!!this.q&&!(this.r&&!this.q.e&&0==BX(this.q).i)}return VP(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.sh=function(e,t){var n,r;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:this.Lh(Lq(t));return;case 2:eli(this,gN(LK(t)));return;case 3:els(this,gN(LK(t)));return;case 4:end(this,Pp(t,19).a);return;case 5:this.ok(Pp(t,19).a);return;case 8:eu2(this,Pp(t,138));return;case 9:(r=ew3(this,Pp(t,87),null))&&r.Fi();return}efL(this,e-Y1(this.zh()),ee2((n=Pp(eaS(this,16),26))||this.zh(),e),t)},eUe.zh=function(){return eBK(),tgB},eUe.Bh=function(e){var t,n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:this.Lh(null);return;case 2:eli(this,!0);return;case 3:els(this,!0);return;case 4:end(this,0);return;case 5:this.ok(1);return;case 8:eu2(this,null);return;case 9:(n=ew3(this,null,null))&&n.Fi();return}ec6(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.Gh=function(){evl(this),this.Bb|=1},eUe.Yj=function(){return evl(this)},eUe.Zj=function(){return this.t},eUe.$j=function(){var e;return(e=this.t)>1||-1==e},eUe.hi=function(){return(512&this.Bb)!=0},eUe.nk=function(e,t){return ecz(this,e,t)},eUe.ok=function(e){enh(this,e)},eUe.Ib=function(){return ex3(this)},eUe.s=0,eUe.t=1,Y5(eZ2,"ETypedElementImpl",284),eTS(449,284,{105:1,92:1,90:1,147:1,191:1,56:1,170:1,66:1,108:1,472:1,49:1,97:1,150:1,449:1,284:1,114:1,115:1,677:1}),eUe.Qg=function(e){return egx(this,e)},eUe._g=function(e,t,n){var r,i;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return OQ(),(256&this.Bb)!=0;case 3:return OQ(),(512&this.Bb)!=0;case 4:return ell(this.s);case 5:return ell(this.t);case 6:return OQ(),!!this.$j();case 7:return OQ(),(i=this.s)>=1;case 8:if(t)return evl(this);return this.r;case 9:return this.q;case 10:return OQ(),(this.Bb&eXt)!=0;case 11:return OQ(),(this.Bb&eJq)!=0;case 12:return OQ(),(this.Bb&eH0)!=0;case 13:return this.j;case 14:return eOI(this);case 15:return OQ(),(this.Bb&eJV)!=0;case 16:return OQ(),(this.Bb&eUR)!=0;case 17:return z6(this)}return Qt(this,e-Y1(this.zh()),ee2((r=Pp(eaS(this,16),26))||this.zh(),e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 17:return this.Cb&&(n=(i=this.Db>>16)>=0?egx(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,17,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||this.zh(),t),66)).Nj().Qj(this,ehH(this),t-Y1(this.zh()),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 9:return Y3(this,n);case 17:return eDg(this,null,17,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||this.zh(),t),66)).Nj().Rj(this,ehH(this),t-Y1(this.zh()),e,n)},eUe.lh=function(e){var t,n;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return(256&this.Bb)==0;case 3:return(512&this.Bb)==0;case 4:return 0!=this.s;case 5:return 1!=this.t;case 6:return this.$j();case 7:return(n=this.s)>=1;case 8:return!!this.r&&!this.q.e&&0==BX(this.q).i;case 9:return!!this.q&&!(this.r&&!this.q.e&&0==BX(this.q).i);case 10:return(this.Bb&eXt)==0;case 11:return(this.Bb&eJq)!=0;case 12:return(this.Bb&eH0)!=0;case 13:return null!=this.j;case 14:return null!=eOI(this);case 15:return(this.Bb&eJV)!=0;case 16:return(this.Bb&eUR)!=0;case 17:return!!z6(this)}return VP(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.sh=function(e,t){var n,r;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:GD(this,Lq(t));return;case 2:eli(this,gN(LK(t)));return;case 3:els(this,gN(LK(t)));return;case 4:end(this,Pp(t,19).a);return;case 5:this.ok(Pp(t,19).a);return;case 8:eu2(this,Pp(t,138));return;case 9:(r=ew3(this,Pp(t,87),null))&&r.Fi();return;case 10:elF(this,gN(LK(t)));return;case 11:elU(this,gN(LK(t)));return;case 12:elY(this,gN(LK(t)));return;case 13:xi(this,Lq(t));return;case 15:elB(this,gN(LK(t)));return;case 16:elZ(this,gN(LK(t)));return}efL(this,e-Y1(this.zh()),ee2((n=Pp(eaS(this,16),26))||this.zh(),e),t)},eUe.zh=function(){return eBK(),tgY},eUe.Bh=function(e){var t,n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:M4(this.Cb,88)&&eko(Zd(Pp(this.Cb,88)),4),er3(this,null);return;case 2:eli(this,!0);return;case 3:els(this,!0);return;case 4:end(this,0);return;case 5:this.ok(1);return;case 8:eu2(this,null);return;case 9:(n=ew3(this,null,null))&&n.Fi();return;case 10:elF(this,!0);return;case 11:elU(this,!1);return;case 12:elY(this,!1);return;case 13:this.i=null,erA(this,null);return;case 15:elB(this,!1);return;case 16:elZ(this,!1);return}ec6(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.Gh=function(){UH(QZ((eSp(),tvc),this)),evl(this),this.Bb|=1},eUe.Gj=function(){return this.f},eUe.zj=function(){return eOI(this)},eUe.Hj=function(){return z6(this)},eUe.Lj=function(){return null},eUe.pk=function(){return this.k},eUe.aj=function(){return this.n},eUe.Mj=function(){return eyD(this)},eUe.Nj=function(){var e,t,n,r,i,a,o,s,u;return this.p||((null==(n=z6(this)).i&&eNT(n),n.i).length,(r=this.Lj())&&Y1(z6(r)),e=(o=(i=evl(this)).Bj())?(1&o.i)!=0?o==tyE?e11:o==ty_?e15:o==tyT?e14:o==tyx?e13:o==tyS?e16:o==tyM?e19:o==tyk?e10:e12:o:null,t=eOI(this),s=i.zj(),efl(this),(this.Bb&eUR)!=0&&((a=ev1((eSp(),tvc),n))&&a!=this||(a=Wk(QZ(tvc,this))))?this.p=new k6(this,a):this.$j()?this.rk()?r?(this.Bb&eJV)!=0?e?this.sk()?this.p=new HS(47,e,this,r):this.p=new HS(5,e,this,r):this.sk()?this.p=new qc(46,this,r):this.p=new qc(4,this,r):e?this.sk()?this.p=new HS(49,e,this,r):this.p=new HS(7,e,this,r):this.sk()?this.p=new qc(48,this,r):this.p=new qc(6,this,r):(this.Bb&eJV)!=0?e?e==e1$?this.p=new Pe(50,e6M,this):this.sk()?this.p=new Pe(43,e,this):this.p=new Pe(1,e,this):this.sk()?this.p=new $F(42,this):this.p=new $F(0,this):e?e==e1$?this.p=new Pe(41,e6M,this):this.sk()?this.p=new Pe(45,e,this):this.p=new Pe(3,e,this):this.sk()?this.p=new $F(44,this):this.p=new $F(2,this):M4(i,148)?e==tgc?this.p=new $F(40,this):(512&this.Bb)!=0?(this.Bb&eJV)!=0?e?this.p=new Pe(9,e,this):this.p=new $F(8,this):e?this.p=new Pe(11,e,this):this.p=new $F(10,this):(this.Bb&eJV)!=0?e?this.p=new Pe(13,e,this):this.p=new $F(12,this):e?this.p=new Pe(15,e,this):this.p=new $F(14,this):r?(u=r.t)>1||-1==u?this.sk()?(this.Bb&eJV)!=0?e?this.p=new HS(25,e,this,r):this.p=new qc(24,this,r):e?this.p=new HS(27,e,this,r):this.p=new qc(26,this,r):(this.Bb&eJV)!=0?e?this.p=new HS(29,e,this,r):this.p=new qc(28,this,r):e?this.p=new HS(31,e,this,r):this.p=new qc(30,this,r):this.sk()?(this.Bb&eJV)!=0?e?this.p=new HS(33,e,this,r):this.p=new qc(32,this,r):e?this.p=new HS(35,e,this,r):this.p=new qc(34,this,r):(this.Bb&eJV)!=0?e?this.p=new HS(37,e,this,r):this.p=new qc(36,this,r):e?this.p=new HS(39,e,this,r):this.p=new qc(38,this,r):this.sk()?(this.Bb&eJV)!=0?e?this.p=new Pe(17,e,this):this.p=new $F(16,this):e?this.p=new Pe(19,e,this):this.p=new $F(18,this):(this.Bb&eJV)!=0?e?this.p=new Pe(21,e,this):this.p=new $F(20,this):e?this.p=new Pe(23,e,this):this.p=new $F(22,this):this.qk()?this.sk()?this.p=new Pt(Pp(i,26),this,r):this.p=new zl(Pp(i,26),this,r):M4(i,148)?e==tgc?this.p=new $F(40,this):(this.Bb&eJV)!=0?e?this.p=new j9(t,s,this,(edO(),o==ty_?tg2:o==tyE?tgX:o==tyS?tg3:o==tyT?tg0:o==tyx?tg1:o==tyM?tg5:o==tyk?tgJ:o==tyw?tgQ:tg4)):this.p=new HT(Pp(i,148),t,s,this):e?this.p=new j6(t,s,this,(edO(),o==ty_?tg2:o==tyE?tgX:o==tyS?tg3:o==tyT?tg0:o==tyx?tg1:o==tyM?tg5:o==tyk?tgJ:o==tyw?tgQ:tg4)):this.p=new Hx(Pp(i,148),t,s,this):this.rk()?r?(this.Bb&eJV)!=0?this.sk()?this.p=new Ps(Pp(i,26),this,r):this.p=new Po(Pp(i,26),this,r):this.sk()?this.p=new Pa(Pp(i,26),this,r):this.p=new Pn(Pp(i,26),this,r):(this.Bb&eJV)!=0?this.sk()?this.p=new Lx(Pp(i,26),this):this.p=new Lk(Pp(i,26),this):this.sk()?this.p=new LS(Pp(i,26),this):this.p=new LE(Pp(i,26),this):this.sk()?r?(this.Bb&eJV)!=0?this.p=new Pu(Pp(i,26),this,r):this.p=new Pr(Pp(i,26),this,r):(this.Bb&eJV)!=0?this.p=new LM(Pp(i,26),this):this.p=new LT(Pp(i,26),this):r?(this.Bb&eJV)!=0?this.p=new Pc(Pp(i,26),this,r):this.p=new Pi(Pp(i,26),this,r):(this.Bb&eJV)!=0?this.p=new LO(Pp(i,26),this):this.p=new jd(Pp(i,26),this)),this.p},eUe.Ij=function(){return(this.Bb&eXt)!=0},eUe.qk=function(){return!1},eUe.rk=function(){return!1},eUe.Jj=function(){return(this.Bb&eUR)!=0},eUe.Oj=function(){return eec(this)},eUe.sk=function(){return!1},eUe.Kj=function(){return(this.Bb&eJV)!=0},eUe.tk=function(e){this.k=e},eUe.Lh=function(e){GD(this,e)},eUe.Ib=function(){return eCR(this)},eUe.e=!1,eUe.n=0,Y5(eZ2,"EStructuralFeatureImpl",449),eTS(322,449,{105:1,92:1,90:1,34:1,147:1,191:1,56:1,170:1,66:1,108:1,472:1,49:1,97:1,322:1,150:1,449:1,284:1,114:1,115:1,677:1},mC),eUe._g=function(e,t,n){var r,i;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return OQ(),(256&this.Bb)!=0;case 3:return OQ(),(512&this.Bb)!=0;case 4:return ell(this.s);case 5:return ell(this.t);case 6:return OQ(),!!ek7(this);case 7:return OQ(),(i=this.s)>=1;case 8:if(t)return evl(this);return this.r;case 9:return this.q;case 10:return OQ(),(this.Bb&eXt)!=0;case 11:return OQ(),(this.Bb&eJq)!=0;case 12:return OQ(),(this.Bb&eH0)!=0;case 13:return this.j;case 14:return eOI(this);case 15:return OQ(),(this.Bb&eJV)!=0;case 16:return OQ(),(this.Bb&eUR)!=0;case 17:return z6(this);case 18:return OQ(),(this.Bb&eZ1)!=0;case 19:if(t)return eoe(this);return Xl(this)}return Qt(this,e-Y1((eBK(),tgw)),ee2((r=Pp(eaS(this,16),26))||tgw,e),t,n)},eUe.lh=function(e){var t,n;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return(256&this.Bb)==0;case 3:return(512&this.Bb)==0;case 4:return 0!=this.s;case 5:return 1!=this.t;case 6:return ek7(this);case 7:return(n=this.s)>=1;case 8:return!!this.r&&!this.q.e&&0==BX(this.q).i;case 9:return!!this.q&&!(this.r&&!this.q.e&&0==BX(this.q).i);case 10:return(this.Bb&eXt)==0;case 11:return(this.Bb&eJq)!=0;case 12:return(this.Bb&eH0)!=0;case 13:return null!=this.j;case 14:return null!=eOI(this);case 15:return(this.Bb&eJV)!=0;case 16:return(this.Bb&eUR)!=0;case 17:return!!z6(this);case 18:return(this.Bb&eZ1)!=0;case 19:return!!Xl(this)}return VP(this,e-Y1((eBK(),tgw)),ee2((t=Pp(eaS(this,16),26))||tgw,e))},eUe.sh=function(e,t){var n,r;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:GD(this,Lq(t));return;case 2:eli(this,gN(LK(t)));return;case 3:els(this,gN(LK(t)));return;case 4:end(this,Pp(t,19).a);return;case 5:yg(this,Pp(t,19).a);return;case 8:eu2(this,Pp(t,138));return;case 9:(r=ew3(this,Pp(t,87),null))&&r.Fi();return;case 10:elF(this,gN(LK(t)));return;case 11:elU(this,gN(LK(t)));return;case 12:elY(this,gN(LK(t)));return;case 13:xi(this,Lq(t));return;case 15:elB(this,gN(LK(t)));return;case 16:elZ(this,gN(LK(t)));return;case 18:elX(this,gN(LK(t)));return}efL(this,e-Y1((eBK(),tgw)),ee2((n=Pp(eaS(this,16),26))||tgw,e),t)},eUe.zh=function(){return eBK(),tgw},eUe.Bh=function(e){var t,n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:M4(this.Cb,88)&&eko(Zd(Pp(this.Cb,88)),4),er3(this,null);return;case 2:eli(this,!0);return;case 3:els(this,!0);return;case 4:end(this,0);return;case 5:this.b=0,enh(this,1);return;case 8:eu2(this,null);return;case 9:(n=ew3(this,null,null))&&n.Fi();return;case 10:elF(this,!0);return;case 11:elU(this,!1);return;case 12:elY(this,!1);return;case 13:this.i=null,erA(this,null);return;case 15:elB(this,!1);return;case 16:elZ(this,!1);return;case 18:elX(this,!1);return}ec6(this,e-Y1((eBK(),tgw)),ee2((t=Pp(eaS(this,16),26))||tgw,e))},eUe.Gh=function(){eoe(this),UH(QZ((eSp(),tvc),this)),evl(this),this.Bb|=1},eUe.$j=function(){return ek7(this)},eUe.nk=function(e,t){return this.b=0,this.a=null,ecz(this,e,t)},eUe.ok=function(e){yg(this,e)},eUe.Ib=function(){var e;return(64&this.Db)!=0?eCR(this):(e=new O1(eCR(this)),e.a+=" (iD: ",yG(e,(this.Bb&eZ1)!=0),e.a+=")",e.a)},eUe.b=0,Y5(eZ2,"EAttributeImpl",322),eTS(351,438,{105:1,92:1,90:1,138:1,147:1,191:1,56:1,108:1,49:1,97:1,351:1,150:1,114:1,115:1,676:1}),eUe.uk=function(e){return e.Tg()==this},eUe.Qg=function(e){return egn(this,e)},eUe.Rg=function(e,t){this.w=null,this.Db=t<<16|255&this.Db,this.Cb=e},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return null!=this.D?this.D:this.B;case 3:return em4(this);case 4:return this.zj();case 5:return this.F;case 6:if(t)return etP(this);return z5(this);case 7:return this.A||(this.A=new OS(tgs,this,7)),this.A}return Qt(this,e-Y1(this.zh()),ee2((r=Pp(eaS(this,16),26))||this.zh(),e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 6:return this.Cb&&(n=(i=this.Db>>16)>=0?egn(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,6,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||this.zh(),t),66)).Nj().Qj(this,ehH(this),t-Y1(this.zh()),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 6:return eDg(this,null,6,n);case 7:return this.A||(this.A=new OS(tgs,this,7)),ep6(this.A,e,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||this.zh(),t),66)).Nj().Rj(this,ehH(this),t-Y1(this.zh()),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return null!=this.D&&this.D==this.F;case 3:return!!em4(this);case 4:return null!=this.zj();case 5:return null!=this.F&&this.F!=this.D&&this.F!=this.B;case 6:return!!z5(this);case 7:return!!this.A&&0!=this.A.i}return VP(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:GN(this,Lq(t));return;case 2:TF(this,Lq(t));return;case 5:eji(this,Lq(t));return;case 7:this.A||(this.A=new OS(tgs,this,7)),eRT(this.A),this.A||(this.A=new OS(tgs,this,7)),Y4(this.A,Pp(t,14));return}efL(this,e-Y1(this.zh()),ee2((n=Pp(eaS(this,16),26))||this.zh(),e),t)},eUe.zh=function(){return eBK(),tgE},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:M4(this.Cb,179)&&(Pp(this.Cb,179).tb=null),er3(this,null);return;case 2:euc(this,null),enp(this,this.D);return;case 5:eji(this,null);return;case 7:this.A||(this.A=new OS(tgs,this,7)),eRT(this.A);return}ec6(this,e-Y1(this.zh()),ee2((t=Pp(eaS(this,16),26))||this.zh(),e))},eUe.yj=function(){var e;return -1==this.G&&(this.G=(e=etP(this))?ebv(e.Mh(),this):-1),this.G},eUe.zj=function(){return null},eUe.Aj=function(){return etP(this)},eUe.vk=function(){return this.v},eUe.Bj=function(){return em4(this)},eUe.Cj=function(){return null!=this.D?this.D:this.B},eUe.Dj=function(){return this.F},eUe.wj=function(e){return eNc(this,e)},eUe.wk=function(e){this.v=e},eUe.xk=function(e){eia(this,e)},eUe.yk=function(e){this.C=e},eUe.Lh=function(e){GN(this,e)},eUe.Ib=function(){return edb(this)},eUe.C=null,eUe.D=null,eUe.G=-1,Y5(eZ2,"EClassifierImpl",351),eTS(88,351,{105:1,92:1,90:1,26:1,138:1,147:1,191:1,56:1,108:1,49:1,97:1,88:1,351:1,150:1,473:1,114:1,115:1,676:1},c0),eUe.uk=function(e){return C7(this,e.Tg())},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return null!=this.D?this.D:this.B;case 3:return em4(this);case 4:return null;case 5:return this.F;case 6:if(t)return etP(this);return z5(this);case 7:return this.A||(this.A=new OS(tgs,this,7)),this.A;case 8:return OQ(),(256&this.Bb)!=0;case 9:return OQ(),(512&this.Bb)!=0;case 10:return $E(this);case 11:return this.q||(this.q=new FQ(tgi,this,11,10)),this.q;case 12:return ePk(this);case 13:return ePl(this);case 14:return ePl(this),this.r;case 15:return ePk(this),this.k;case 16:return eSD(this);case 17:return eNQ(this);case 18:return eNT(this);case 19:return eOg(this);case 20:return ePk(this),this.o;case 21:return this.s||(this.s=new FQ(tm6,this,21,17)),this.s;case 22:return qt(this);case 23:return eCt(this)}return Qt(this,e-Y1((eBK(),tg_)),ee2((r=Pp(eaS(this,16),26))||tg_,e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 6:return this.Cb&&(n=(i=this.Db>>16)>=0?egn(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,6,n);case 11:return this.q||(this.q=new FQ(tgi,this,11,10)),edF(this.q,e,n);case 21:return this.s||(this.s=new FQ(tm6,this,21,17)),edF(this.s,e,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tg_),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tg_)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 6:return eDg(this,null,6,n);case 7:return this.A||(this.A=new OS(tgs,this,7)),ep6(this.A,e,n);case 11:return this.q||(this.q=new FQ(tgi,this,11,10)),ep6(this.q,e,n);case 21:return this.s||(this.s=new FQ(tm6,this,21,17)),ep6(this.s,e,n);case 22:return ep6(qt(this),e,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tg_),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tg_)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return null!=this.D&&this.D==this.F;case 3:return!!em4(this);case 4:return!1;case 5:return null!=this.F&&this.F!=this.D&&this.F!=this.B;case 6:return!!z5(this);case 7:return!!this.A&&0!=this.A.i;case 8:return(256&this.Bb)!=0;case 9:return(512&this.Bb)!=0;case 10:return!!this.u&&0!=qt(this.u.a).i&&!(this.n&&ebV(this.n));case 11:return!!this.q&&0!=this.q.i;case 12:return 0!=ePk(this).i;case 13:return 0!=ePl(this).i;case 14:return ePl(this),0!=this.r.i;case 15:return ePk(this),0!=this.k.i;case 16:return 0!=eSD(this).i;case 17:return 0!=eNQ(this).i;case 18:return 0!=eNT(this).i;case 19:return 0!=eOg(this).i;case 20:return ePk(this),!!this.o;case 21:return!!this.s&&0!=this.s.i;case 22:return!!this.n&&ebV(this.n);case 23:return 0!=eCt(this).i}return VP(this,e-Y1((eBK(),tg_)),ee2((t=Pp(eaS(this,16),26))||tg_,e))},eUe.oh=function(e){var t;return(t=null==this.i||this.q&&0!=this.q.i?null:eAh(this,e))||eF9(this,e)},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:GN(this,Lq(t));return;case 2:TF(this,Lq(t));return;case 5:eji(this,Lq(t));return;case 7:this.A||(this.A=new OS(tgs,this,7)),eRT(this.A),this.A||(this.A=new OS(tgs,this,7)),Y4(this.A,Pp(t,14));return;case 8:ela(this,gN(LK(t)));return;case 9:elu(this,gN(LK(t)));return;case 10:eRP($E(this)),Y4($E(this),Pp(t,14));return;case 11:this.q||(this.q=new FQ(tgi,this,11,10)),eRT(this.q),this.q||(this.q=new FQ(tgi,this,11,10)),Y4(this.q,Pp(t,14));return;case 21:this.s||(this.s=new FQ(tm6,this,21,17)),eRT(this.s),this.s||(this.s=new FQ(tm6,this,21,17)),Y4(this.s,Pp(t,14));return;case 22:eRT(qt(this)),Y4(qt(this),Pp(t,14));return}efL(this,e-Y1((eBK(),tg_)),ee2((n=Pp(eaS(this,16),26))||tg_,e),t)},eUe.zh=function(){return eBK(),tg_},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:M4(this.Cb,179)&&(Pp(this.Cb,179).tb=null),er3(this,null);return;case 2:euc(this,null),enp(this,this.D);return;case 5:eji(this,null);return;case 7:this.A||(this.A=new OS(tgs,this,7)),eRT(this.A);return;case 8:ela(this,!1);return;case 9:elu(this,!1);return;case 10:this.u&&eRP(this.u);return;case 11:this.q||(this.q=new FQ(tgi,this,11,10)),eRT(this.q);return;case 21:this.s||(this.s=new FQ(tm6,this,21,17)),eRT(this.s);return;case 22:this.n&&eRT(this.n);return}ec6(this,e-Y1((eBK(),tg_)),ee2((t=Pp(eaS(this,16),26))||tg_,e))},eUe.Gh=function(){var e,t;if(ePk(this),ePl(this),eSD(this),eNQ(this),eNT(this),eOg(this),eCt(this),ZG(Pw(Zd(this))),this.s)for(e=0,t=this.s.i;e=0;--t)etj(this,t);return edj(this,e)},eUe.Xj=function(){eRT(this)},eUe.oi=function(e,t){return env(this,e,t)},Y5(eJz,"EcoreEList",622),eTS(496,622,eJ9,PK),eUe.ai=function(){return!1},eUe.aj=function(){return this.c},eUe.bj=function(){return!1},eUe.Fk=function(){return!0},eUe.hi=function(){return!0},eUe.li=function(e,t){return t},eUe.ni=function(){return!1},eUe.c=0,Y5(eJz,"EObjectEList",496),eTS(85,496,eJ9,O_),eUe.bj=function(){return!0},eUe.Dk=function(){return!1},eUe.rk=function(){return!0},Y5(eJz,"EObjectContainmentEList",85),eTS(545,85,eJ9,OE),eUe.ci=function(){this.b=!0},eUe.fj=function(){return this.b},eUe.Xj=function(){var e;eRT(this),TO(this.e)?(e=this.b,this.b=!1,eam(this.e,new ZB(this.e,2,this.c,e,!1))):this.b=!1},eUe.b=!1,Y5(eJz,"EObjectContainmentEList/Unsettable",545),eTS(1140,545,eJ9,j4),eUe.ii=function(e,t){var n,r;return n=Pp(elR(this,e,t),87),TO(this.e)&&bz(this,new JU(this.a,7,(eBK(),tgS),ell(t),M4(r=n.c,88)?Pp(r,26):tgI,e)),n},eUe.jj=function(e,t){return edB(this,Pp(e,87),t)},eUe.kj=function(e,t){return edY(this,Pp(e,87),t)},eUe.lj=function(e,t,n){return eyl(this,Pp(e,87),Pp(t,87),n)},eUe.Zi=function(e,t,n,r,i){switch(e){case 3:return Gt(this,e,t,n,r,this.i>1);case 5:return Gt(this,e,t,n,r,this.i-Pp(n,15).gc()>0);default:return new Q$(this.e,e,this.c,t,n,r,!0)}},eUe.ij=function(){return!0},eUe.fj=function(){return ebV(this)},eUe.Xj=function(){eRT(this)},Y5(eZ2,"EClassImpl/1",1140),eTS(1154,1153,eJS),eUe.ui=function(e){var t,n,r,i,a,o,s;if(8!=(n=e.xi())){if(0==(r=epM(e)))switch(n){case 1:case 9:null!=(s=e.Bi())&&((t=Zd(Pp(s,473))).c||(t.c=new sk),eeu(t.c,e.Ai())),null!=(o=e.zi())&&(1&(i=Pp(o,473)).Bb)==0&&((t=Zd(i)).c||(t.c=new sk),JL(t.c,Pp(e.Ai(),26)));break;case 3:null!=(o=e.zi())&&(1&(i=Pp(o,473)).Bb)==0&&((t=Zd(i)).c||(t.c=new sk),JL(t.c,Pp(e.Ai(),26)));break;case 5:if(null!=(o=e.zi()))for(a=Pp(o,14).Kc();a.Ob();)(1&(i=Pp(a.Pb(),473)).Bb)==0&&((t=Zd(i)).c||(t.c=new sk),JL(t.c,Pp(e.Ai(),26)));break;case 4:null!=(s=e.Bi())&&(1&(i=Pp(s,473)).Bb)==0&&((t=Zd(i)).c||(t.c=new sk),eeu(t.c,e.Ai()));break;case 6:if(null!=(s=e.Bi()))for(a=Pp(s,14).Kc();a.Ob();)(1&(i=Pp(a.Pb(),473)).Bb)==0&&((t=Zd(i)).c||(t.c=new sk),eeu(t.c,e.Ai()))}this.Hk(r)}},eUe.Hk=function(e){eCO(this,e)},eUe.b=63,Y5(eZ2,"ESuperAdapter",1154),eTS(1155,1154,eJS,pR),eUe.Hk=function(e){eko(this,e)},Y5(eZ2,"EClassImpl/10",1155),eTS(1144,696,eJ9),eUe.Vh=function(e,t){return ew2(this,e,t)},eUe.Wh=function(e){return emp(this,e)},eUe.Xh=function(e,t){ecW(this,e,t)},eUe.Yh=function(e){Zz(this,e)},eUe.pi=function(e){return J5(this,e)},eUe.mi=function(e,t){return ees(this,e,t)},eUe.lk=function(e,t){throw p7(new bO)},eUe.Zh=function(){return new AY(this)},eUe.$h=function(){return new AB(this)},eUe._h=function(e){return enH(this,e)},eUe.mk=function(e,t){throw p7(new bO)},eUe.Wj=function(e){return this},eUe.fj=function(){return 0!=this.i},eUe.Wb=function(e){throw p7(new bO)},eUe.Xj=function(){throw p7(new bO)},Y5(eJz,"EcoreEList/UnmodifiableEList",1144),eTS(319,1144,eJ9,xQ),eUe.ni=function(){return!1},Y5(eJz,"EcoreEList/UnmodifiableEList/FastCompare",319),eTS(1147,319,eJ9,eo8),eUe.Xc=function(e){var t,n,r;if(M4(e,170)&&-1!=(n=(t=Pp(e,170)).aj())){for(r=this.i;n4){if(!this.wj(e))return!1;if(this.rk()){if(s=(n=(r=Pp(e,49)).Ug())==this.b&&(this.Dk()?r.Og(r.Vg(),Pp(ee2($S(this.b),this.aj()).Yj(),26).Bj())==ebY(Pp(ee2($S(this.b),this.aj()),18)).n:-1-r.Vg()==this.aj()),this.Ek()&&!s&&!n&&r.Zg()){for(i=0;i1||-1==r)},eUe.Dk=function(){var e,t,n;return t=ee2($S(this.b),this.aj()),!!M4(t,99)&&!!(n=ebY(e=Pp(t,18)))},eUe.Ek=function(){var e,t;return t=ee2($S(this.b),this.aj()),!!M4(t,99)&&((e=Pp(t,18)).Bb&eH3)!=0},eUe.Xc=function(e){var t,n,r,i;if((r=this.Qi(e))>=0)return r;if(this.Fk()){for(n=0,i=this.Vi();n=0;--e)ejc(this,e,this.Oi(e));return this.Wi()},eUe.Qc=function(e){var t;if(this.Ek())for(t=this.Vi()-1;t>=0;--t)ejc(this,t,this.Oi(t));return this.Xi(e)},eUe.Xj=function(){eRP(this)},eUe.oi=function(e,t){return J6(this,e,t)},Y5(eJz,"DelegatingEcoreEList",742),eTS(1150,742,eQn,Cw),eUe.Hi=function(e,t){LP(this,e,Pp(t,26))},eUe.Ii=function(e){Mt(this,Pp(e,26))},eUe.Oi=function(e){var t,n;return n=(t=Pp(etj(qt(this.a),e),87)).c,M4(n,88)?Pp(n,26):(eBK(),tgI)},eUe.Ti=function(e){var t,n;return n=(t=Pp(eLN(qt(this.a),e),87)).c,M4(n,88)?Pp(n,26):(eBK(),tgI)},eUe.Ui=function(e,t){return emm(this,e,Pp(t,26))},eUe.ai=function(){return!1},eUe.Zi=function(e,t,n,r,i){return null},eUe.Ji=function(){return new pF(this)},eUe.Ki=function(){eRT(qt(this.a))},eUe.Li=function(e){return ec7(this,e)},eUe.Mi=function(e){var t,n;for(n=e.Kc();n.Ob();)if(!ec7(this,t=n.Pb()))return!1;return!0},eUe.Ni=function(e){var t,n,r;if(M4(e,15)&&(r=Pp(e,15)).gc()==qt(this.a).i){for(t=r.Kc(),n=new Ow(this);t.Ob();)if(xc(t.Pb())!==xc(epH(n)))return!1;return!0}return!1},eUe.Pi=function(){var e,t,n,r,i;for(n=1,t=new Ow(qt(this.a));t.e!=t.i.gc();)e=Pp(epH(t),87),r=M4(i=e.c,88)?Pp(i,26):(eBK(),tgI),n=31*n+(r?Ao(r):0);return n},eUe.Qi=function(e){var t,n,r,i;for(r=0,n=new Ow(qt(this.a));n.e!=n.i.gc();){if(t=Pp(epH(n),87),xc(e)===xc(M4(i=t.c,88)?Pp(i,26):(eBK(),tgI)))return r;++r}return -1},eUe.Ri=function(){return 0==qt(this.a).i},eUe.Si=function(){return null},eUe.Vi=function(){return qt(this.a).i},eUe.Wi=function(){var e,t,n,r,i,a;for(a=qt(this.a).i,i=Je(e1R,eUp,1,a,5,1),n=0,t=new Ow(qt(this.a));t.e!=t.i.gc();)e=Pp(epH(t),87),i[n++]=M4(r=e.c,88)?Pp(r,26):(eBK(),tgI);return i},eUe.Xi=function(e){var t,n,r,i,a,o,s;for(s=qt(this.a).i,e.lengths&&Bc(e,s,null),r=0,n=new Ow(qt(this.a));n.e!=n.i.gc();)t=Pp(epH(n),87),a=M4(o=t.c,88)?Pp(o,26):(eBK(),tgI),Bc(e,r++,a);return e},eUe.Yi=function(){var e,t,n,r,i;for(i=new vs,i.a+="[",e=qt(this.a),t=0,r=qt(this.a).i;t>16)>=0?egn(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,6,n);case 9:return this.a||(this.a=new FQ(tgn,this,9,5)),edF(this.a,e,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgx),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tgx)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 6:return eDg(this,null,6,n);case 7:return this.A||(this.A=new OS(tgs,this,7)),ep6(this.A,e,n);case 9:return this.a||(this.a=new FQ(tgn,this,9,5)),ep6(this.a,e,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgx),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgx)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return null!=this.D&&this.D==this.F;case 3:return!!em4(this);case 4:return!!euS(this);case 5:return null!=this.F&&this.F!=this.D&&this.F!=this.B;case 6:return!!z5(this);case 7:return!!this.A&&0!=this.A.i;case 8:return(256&this.Bb)==0;case 9:return!!this.a&&0!=this.a.i}return VP(this,e-Y1((eBK(),tgx)),ee2((t=Pp(eaS(this,16),26))||tgx,e))},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:GN(this,Lq(t));return;case 2:TF(this,Lq(t));return;case 5:eji(this,Lq(t));return;case 7:this.A||(this.A=new OS(tgs,this,7)),eRT(this.A),this.A||(this.A=new OS(tgs,this,7)),Y4(this.A,Pp(t,14));return;case 8:elo(this,gN(LK(t)));return;case 9:this.a||(this.a=new FQ(tgn,this,9,5)),eRT(this.a),this.a||(this.a=new FQ(tgn,this,9,5)),Y4(this.a,Pp(t,14));return}efL(this,e-Y1((eBK(),tgx)),ee2((n=Pp(eaS(this,16),26))||tgx,e),t)},eUe.zh=function(){return eBK(),tgx},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:M4(this.Cb,179)&&(Pp(this.Cb,179).tb=null),er3(this,null);return;case 2:euc(this,null),enp(this,this.D);return;case 5:eji(this,null);return;case 7:this.A||(this.A=new OS(tgs,this,7)),eRT(this.A);return;case 8:elo(this,!0);return;case 9:this.a||(this.a=new FQ(tgn,this,9,5)),eRT(this.a);return}ec6(this,e-Y1((eBK(),tgx)),ee2((t=Pp(eaS(this,16),26))||tgx,e))},eUe.Gh=function(){var e,t;if(this.a)for(e=0,t=this.a.i;e>16==5?Pp(this.Cb,671):null}return Qt(this,e-Y1((eBK(),tgT)),ee2((r=Pp(eaS(this,16),26))||tgT,e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 5:return this.Cb&&(n=(i=this.Db>>16)>=0?eg3(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,5,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgT),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tgT)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 5:return eDg(this,null,5,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgT),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgT)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return 0!=this.d;case 3:return!!this.b;case 4:return null!=this.c;case 5:return!!(this.Db>>16==5?Pp(this.Cb,671):null)}return VP(this,e-Y1((eBK(),tgT)),ee2((t=Pp(eaS(this,16),26))||tgT,e))},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:er3(this,Lq(t));return;case 2:enf(this,Pp(t,19).a);return;case 3:exP(this,Pp(t,1940));return;case 4:erc(this,Lq(t));return}efL(this,e-Y1((eBK(),tgT)),ee2((n=Pp(eaS(this,16),26))||tgT,e),t)},eUe.zh=function(){return eBK(),tgT},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:er3(this,null);return;case 2:enf(this,0);return;case 3:exP(this,null);return;case 4:erc(this,null);return}ec6(this,e-Y1((eBK(),tgT)),ee2((t=Pp(eaS(this,16),26))||tgT,e))},eUe.Ib=function(){var e;return null==(e=this.c)?this.zb:e},eUe.b=null,eUe.c=null,eUe.d=0,Y5(eZ2,"EEnumLiteralImpl",573);var tgl=RL(eZ2,"EFactoryImpl/InternalEDateTimeFormat");eTS(489,1,{2015:1},pY),Y5(eZ2,"EFactoryImpl/1ClientInternalEDateTimeFormat",489),eTS(241,115,{105:1,92:1,90:1,87:1,56:1,108:1,49:1,97:1,241:1,114:1,115:1},p5),eUe.Sg=function(e,t,n){var r;return n=eDg(this,e,t,n),this.e&&M4(e,170)&&(r=eOl(this,this.e))!=this.c&&(n=eFr(this,r,n)),n},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.f;case 1:return this.d||(this.d=new O_(tgr,this,1)),this.d;case 2:if(t)return eD5(this);return this.c;case 3:return this.b;case 4:return this.e;case 5:if(t)return eb1(this);return this.a}return Qt(this,e-Y1((eBK(),tgO)),ee2((r=Pp(eaS(this,16),26))||tgO,e),t,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return ecg(this,null,n);case 1:return this.d||(this.d=new O_(tgr,this,1)),ep6(this.d,e,n);case 3:return ecm(this,null,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgO),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgO)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.f;case 1:return!!this.d&&0!=this.d.i;case 2:return!!this.c;case 3:return!!this.b;case 4:return!!this.e;case 5:return!!this.a}return VP(this,e-Y1((eBK(),tgO)),ee2((t=Pp(eaS(this,16),26))||tgO,e))},eUe.sh=function(e,t){var n;switch(e){case 0:eyK(this,Pp(t,87));return;case 1:this.d||(this.d=new O_(tgr,this,1)),eRT(this.d),this.d||(this.d=new O_(tgr,this,1)),Y4(this.d,Pp(t,14));return;case 3:eyW(this,Pp(t,87));return;case 4:e_U(this,Pp(t,836));return;case 5:etV(this,Pp(t,138));return}efL(this,e-Y1((eBK(),tgO)),ee2((n=Pp(eaS(this,16),26))||tgO,e),t)},eUe.zh=function(){return eBK(),tgO},eUe.Bh=function(e){var t;switch(e){case 0:eyK(this,null);return;case 1:this.d||(this.d=new O_(tgr,this,1)),eRT(this.d);return;case 3:eyW(this,null);return;case 4:e_U(this,null);return;case 5:etV(this,null);return}ec6(this,e-Y1((eBK(),tgO)),ee2((t=Pp(eaS(this,16),26))||tgO,e))},eUe.Ib=function(){var e;return e=new O0(eMT(this)),e.a+=" (expression: ",ePB(this,e),e.a+=")",e.a},Y5(eZ2,"EGenericTypeImpl",241),eTS(1969,1964,eQr),eUe.Xh=function(e,t){Ch(this,e,t)},eUe.lk=function(e,t){return Ch(this,this.gc(),e),t},eUe.pi=function(e){return ep3(this.Gi(),e)},eUe.Zh=function(){return this.$h()},eUe.Gi=function(){return new pV(this)},eUe.$h=function(){return this._h(0)},eUe._h=function(e){return this.Gi().Zc(e)},eUe.mk=function(e,t){return eds(this,e,!0),t},eUe.ii=function(e,t){var n,r;return r=egW(this,t),(n=this.Zc(e)).Rb(r),r},eUe.ji=function(e,t){var n;eds(this,t,!0),(n=this.Zc(e)).Rb(t)},Y5(eJz,"AbstractSequentialInternalEList",1969),eTS(486,1969,eQr,AA),eUe.pi=function(e){return ep3(this.Gi(),e)},eUe.Zh=function(){return null==this.b?(_2(),_2(),tgq):this.Jk()},eUe.Gi=function(){return new x0(this.a,this.b)},eUe.$h=function(){return null==this.b?(_2(),_2(),tgq):this.Jk()},eUe._h=function(e){var t,n;if(null==this.b){if(e<0||e>1)throw p7(new gE(eJT+e+", size=0"));return _2(),_2(),tgq}for(t=0,n=this.Jk();t0;)if(t=this.c[--this.d],(!this.e||t.Gj()!=e6d||0!=t.aj())&&(!this.Mk()||this.b.mh(t))){if(a=this.b.bh(t,this.Lk()),this.f=(_4(),Pp(t,66).Oj()),this.f||t.$j()){if(this.Lk()?(r=Pp(a,15),this.k=r):(r=Pp(a,69),this.k=this.j=r),M4(this.k,54)?(this.o=this.k.gc(),this.n=this.o):this.p=this.j?this.j._h(this.k.gc()):this.k.Zc(this.k.gc()),this.p?eSs(this,this.p):eSQ(this))return i=this.p?this.p.Ub():this.j?this.j.pi(--this.n):this.k.Xb(--this.n),this.f?((e=Pp(i,72)).ak(),n=e.dd(),this.i=n):(n=i,this.i=n),this.g=-3,!0}else if(null!=a)return this.k=null,this.p=null,n=a,this.i=n,this.g=-2,!0}return this.k=null,this.p=null,this.g=-1,!1}},eUe.Pb=function(){return eaO(this)},eUe.Tb=function(){return this.a},eUe.Ub=function(){var e;if(this.g<-1||this.Sb())return--this.a,this.g=0,e=this.i,this.Sb(),e;throw p7(new bC)},eUe.Vb=function(){return this.a-1},eUe.Qb=function(){throw p7(new bO)},eUe.Lk=function(){return!1},eUe.Wb=function(e){throw p7(new bO)},eUe.Mk=function(){return!0},eUe.a=0,eUe.d=0,eUe.f=!1,eUe.g=0,eUe.n=0,eUe.o=0,Y5(eJz,"EContentsEList/FeatureIteratorImpl",279),eTS(697,279,eQi,Lv),eUe.Lk=function(){return!0},Y5(eJz,"EContentsEList/ResolvingFeatureIteratorImpl",697),eTS(1157,697,eQi,Lw),eUe.Mk=function(){return!1},Y5(eZ2,"ENamedElementImpl/1/1",1157),eTS(1158,279,eQi,Ly),eUe.Mk=function(){return!1},Y5(eZ2,"ENamedElementImpl/1/2",1158),eTS(36,143,eJx,qo,qs,FX,JB,Q$,ZB,en_,WX,enE,WJ,Zj,WQ,enx,W1,ZF,W0,enS,W2,FJ,JU,H0,enk,W3,ZY,W4),eUe._i=function(){return JA(this)},eUe.gj=function(){var e;return(e=JA(this))?e.zj():null},eUe.yi=function(e){return -1==this.b&&this.a&&(this.b=this.c.Xg(this.a.aj(),this.a.Gj())),this.c.Og(this.b,e)},eUe.Ai=function(){return this.c},eUe.hj=function(){var e;return!!(e=JA(this))&&e.Kj()},eUe.b=-1,Y5(eZ2,"ENotificationImpl",36),eTS(399,284,{105:1,92:1,90:1,147:1,191:1,56:1,59:1,108:1,472:1,49:1,97:1,150:1,399:1,284:1,114:1,115:1},mD),eUe.Qg=function(e){return evu(this,e)},eUe._g=function(e,t,n){var r,i,a;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return OQ(),(256&this.Bb)!=0;case 3:return OQ(),(512&this.Bb)!=0;case 4:return ell(this.s);case 5:return ell(this.t);case 6:return OQ(),(a=this.t)>1||-1==a;case 7:return OQ(),(i=this.s)>=1;case 8:if(t)return evl(this);return this.r;case 9:return this.q;case 10:return this.Db>>16==10?Pp(this.Cb,26):null;case 11:return this.d||(this.d=new OS(tgs,this,11)),this.d;case 12:return this.c||(this.c=new FQ(tga,this,12,10)),this.c;case 13:return this.a||(this.a=new C_(this,this)),this.a;case 14:return QX(this)}return Qt(this,e-Y1((eBK(),tgD)),ee2((r=Pp(eaS(this,16),26))||tgD,e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 10:return this.Cb&&(n=(i=this.Db>>16)>=0?evu(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,10,n);case 12:return this.c||(this.c=new FQ(tga,this,12,10)),edF(this.c,e,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgD),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tgD)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 9:return Y3(this,n);case 10:return eDg(this,null,10,n);case 11:return this.d||(this.d=new OS(tgs,this,11)),ep6(this.d,e,n);case 12:return this.c||(this.c=new FQ(tga,this,12,10)),ep6(this.c,e,n);case 14:return ep6(QX(this),e,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgD),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgD)),e,n)},eUe.lh=function(e){var t,n,r;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return(256&this.Bb)==0;case 3:return(512&this.Bb)==0;case 4:return 0!=this.s;case 5:return 1!=this.t;case 6:return(r=this.t)>1||-1==r;case 7:return(n=this.s)>=1;case 8:return!!this.r&&!this.q.e&&0==BX(this.q).i;case 9:return!!this.q&&!(this.r&&!this.q.e&&0==BX(this.q).i);case 10:return!!(this.Db>>16==10?Pp(this.Cb,26):null);case 11:return!!this.d&&0!=this.d.i;case 12:return!!this.c&&0!=this.c.i;case 13:return!!this.a&&0!=QX(this.a.a).i&&!(this.b&&ebq(this.b));case 14:return!!this.b&&ebq(this.b)}return VP(this,e-Y1((eBK(),tgD)),ee2((t=Pp(eaS(this,16),26))||tgD,e))},eUe.sh=function(e,t){var n,r;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:er3(this,Lq(t));return;case 2:eli(this,gN(LK(t)));return;case 3:els(this,gN(LK(t)));return;case 4:end(this,Pp(t,19).a);return;case 5:enh(this,Pp(t,19).a);return;case 8:eu2(this,Pp(t,138));return;case 9:(r=ew3(this,Pp(t,87),null))&&r.Fi();return;case 11:this.d||(this.d=new OS(tgs,this,11)),eRT(this.d),this.d||(this.d=new OS(tgs,this,11)),Y4(this.d,Pp(t,14));return;case 12:this.c||(this.c=new FQ(tga,this,12,10)),eRT(this.c),this.c||(this.c=new FQ(tga,this,12,10)),Y4(this.c,Pp(t,14));return;case 13:this.a||(this.a=new C_(this,this)),eRP(this.a),this.a||(this.a=new C_(this,this)),Y4(this.a,Pp(t,14));return;case 14:eRT(QX(this)),Y4(QX(this),Pp(t,14));return}efL(this,e-Y1((eBK(),tgD)),ee2((n=Pp(eaS(this,16),26))||tgD,e),t)},eUe.zh=function(){return eBK(),tgD},eUe.Bh=function(e){var t,n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:er3(this,null);return;case 2:eli(this,!0);return;case 3:els(this,!0);return;case 4:end(this,0);return;case 5:enh(this,1);return;case 8:eu2(this,null);return;case 9:(n=ew3(this,null,null))&&n.Fi();return;case 11:this.d||(this.d=new OS(tgs,this,11)),eRT(this.d);return;case 12:this.c||(this.c=new FQ(tga,this,12,10)),eRT(this.c);return;case 13:this.a&&eRP(this.a);return;case 14:this.b&&eRT(this.b);return}ec6(this,e-Y1((eBK(),tgD)),ee2((t=Pp(eaS(this,16),26))||tgD,e))},eUe.Gh=function(){var e,t;if(this.c)for(e=0,t=this.c.i;es&&Bc(e,s,null),r=0,n=new Ow(QX(this.a));n.e!=n.i.gc();)a=(o=(t=Pp(epH(n),87)).c)||(eBK(),tgA),Bc(e,r++,a);return e},eUe.Yi=function(){var e,t,n,r,i;for(i=new vs,i.a+="[",e=QX(this.a),t=0,r=QX(this.a).i;t1);case 5:return Gt(this,e,t,n,r,this.i-Pp(n,15).gc()>0);default:return new Q$(this.e,e,this.c,t,n,r,!0)}},eUe.ij=function(){return!0},eUe.fj=function(){return ebq(this)},eUe.Xj=function(){eRT(this)},Y5(eZ2,"EOperationImpl/2",1341),eTS(498,1,{1938:1,498:1},k5),Y5(eZ2,"EPackageImpl/1",498),eTS(16,85,eJ9,FQ),eUe.zk=function(){return this.d},eUe.Ak=function(){return this.b},eUe.Dk=function(){return!0},eUe.b=0,Y5(eJz,"EObjectContainmentWithInverseEList",16),eTS(353,16,eJ9,Ia),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectContainmentWithInverseEList/Resolving",353),eTS(298,353,eJ9,Fq),eUe.ci=function(){this.a.tb=null},Y5(eZ2,"EPackageImpl/2",298),eTS(1228,1,{},sh),Y5(eZ2,"EPackageImpl/3",1228),eTS(718,43,e$s,mP),eUe._b=function(e){return xd(e)?$r(this,e):!!$I(this.f,e)},Y5(eZ2,"EPackageRegistryImpl",718),eTS(509,284,{105:1,92:1,90:1,147:1,191:1,56:1,2017:1,108:1,472:1,49:1,97:1,150:1,509:1,284:1,114:1,115:1},mN),eUe.Qg=function(e){return evc(this,e)},eUe._g=function(e,t,n){var r,i,a;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return OQ(),(256&this.Bb)!=0;case 3:return OQ(),(512&this.Bb)!=0;case 4:return ell(this.s);case 5:return ell(this.t);case 6:return OQ(),(a=this.t)>1||-1==a;case 7:return OQ(),(i=this.s)>=1;case 8:if(t)return evl(this);return this.r;case 9:return this.q;case 10:return this.Db>>16==10?Pp(this.Cb,59):null}return Qt(this,e-Y1((eBK(),tgR)),ee2((r=Pp(eaS(this,16),26))||tgR,e),t,n)},eUe.hh=function(e,t,n){var r,i,a;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),edF(this.Ab,e,n);case 10:return this.Cb&&(n=(i=this.Db>>16)>=0?evc(this,n):this.Cb.ih(this,-1-i,null,n)),eDg(this,e,10,n)}return(a=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgR),t),66)).Nj().Qj(this,ehH(this),t-Y1((eBK(),tgR)),e,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 9:return Y3(this,n);case 10:return eDg(this,null,10,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgR),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgR)),e,n)},eUe.lh=function(e){var t,n,r;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return(256&this.Bb)==0;case 3:return(512&this.Bb)==0;case 4:return 0!=this.s;case 5:return 1!=this.t;case 6:return(r=this.t)>1||-1==r;case 7:return(n=this.s)>=1;case 8:return!!this.r&&!this.q.e&&0==BX(this.q).i;case 9:return!!this.q&&!(this.r&&!this.q.e&&0==BX(this.q).i);case 10:return!!(this.Db>>16==10?Pp(this.Cb,59):null)}return VP(this,e-Y1((eBK(),tgR)),ee2((t=Pp(eaS(this,16),26))||tgR,e))},eUe.zh=function(){return eBK(),tgR},Y5(eZ2,"EParameterImpl",509),eTS(99,449,{105:1,92:1,90:1,147:1,191:1,56:1,18:1,170:1,66:1,108:1,472:1,49:1,97:1,150:1,99:1,449:1,284:1,114:1,115:1,677:1},LB),eUe._g=function(e,t,n){var r,i,a,o;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return OQ(),(256&this.Bb)!=0;case 3:return OQ(),(512&this.Bb)!=0;case 4:return ell(this.s);case 5:return ell(this.t);case 6:return OQ(),(o=this.t)>1||-1==o;case 7:return OQ(),(i=this.s)>=1;case 8:if(t)return evl(this);return this.r;case 9:return this.q;case 10:return OQ(),(this.Bb&eXt)!=0;case 11:return OQ(),(this.Bb&eJq)!=0;case 12:return OQ(),(this.Bb&eH0)!=0;case 13:return this.j;case 14:return eOI(this);case 15:return OQ(),(this.Bb&eJV)!=0;case 16:return OQ(),(this.Bb&eUR)!=0;case 17:return z6(this);case 18:return OQ(),(this.Bb&eZ1)!=0;case 19:return OQ(),!!(a=ebY(this))&&(a.Bb&eZ1)!=0;case 20:return OQ(),(this.Bb&eH3)!=0;case 21:if(t)return ebY(this);return this.b;case 22:if(t)return esd(this);return ZS(this);case 23:return this.a||(this.a=new OT(tm9,this,23)),this.a}return Qt(this,e-Y1((eBK(),tgj)),ee2((r=Pp(eaS(this,16),26))||tgj,e),t,n)},eUe.lh=function(e){var t,n,r,i;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return(256&this.Bb)==0;case 3:return(512&this.Bb)==0;case 4:return 0!=this.s;case 5:return 1!=this.t;case 6:return(i=this.t)>1||-1==i;case 7:return(n=this.s)>=1;case 8:return!!this.r&&!this.q.e&&0==BX(this.q).i;case 9:return!!this.q&&!(this.r&&!this.q.e&&0==BX(this.q).i);case 10:return(this.Bb&eXt)==0;case 11:return(this.Bb&eJq)!=0;case 12:return(this.Bb&eH0)!=0;case 13:return null!=this.j;case 14:return null!=eOI(this);case 15:return(this.Bb&eJV)!=0;case 16:return(this.Bb&eUR)!=0;case 17:return!!z6(this);case 18:return(this.Bb&eZ1)!=0;case 19:return!!(r=ebY(this))&&(r.Bb&eZ1)!=0;case 20:return(this.Bb&eH3)==0;case 21:return!!this.b;case 22:return!!ZS(this);case 23:return!!this.a&&0!=this.a.i}return VP(this,e-Y1((eBK(),tgj)),ee2((t=Pp(eaS(this,16),26))||tgj,e))},eUe.sh=function(e,t){var n,r;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:GD(this,Lq(t));return;case 2:eli(this,gN(LK(t)));return;case 3:els(this,gN(LK(t)));return;case 4:end(this,Pp(t,19).a);return;case 5:enh(this,Pp(t,19).a);return;case 8:eu2(this,Pp(t,138));return;case 9:(r=ew3(this,Pp(t,87),null))&&r.Fi();return;case 10:elF(this,gN(LK(t)));return;case 11:elU(this,gN(LK(t)));return;case 12:elY(this,gN(LK(t)));return;case 13:xi(this,Lq(t));return;case 15:elB(this,gN(LK(t)));return;case 16:elZ(this,gN(LK(t)));return;case 18:GI(this,gN(LK(t)));return;case 20:elQ(this,gN(LK(t)));return;case 21:erM(this,Pp(t,18));return;case 23:this.a||(this.a=new OT(tm9,this,23)),eRT(this.a),this.a||(this.a=new OT(tm9,this,23)),Y4(this.a,Pp(t,14));return}efL(this,e-Y1((eBK(),tgj)),ee2((n=Pp(eaS(this,16),26))||tgj,e),t)},eUe.zh=function(){return eBK(),tgj},eUe.Bh=function(e){var t,n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:M4(this.Cb,88)&&eko(Zd(Pp(this.Cb,88)),4),er3(this,null);return;case 2:eli(this,!0);return;case 3:els(this,!0);return;case 4:end(this,0);return;case 5:enh(this,1);return;case 8:eu2(this,null);return;case 9:(n=ew3(this,null,null))&&n.Fi();return;case 10:elF(this,!0);return;case 11:elU(this,!1);return;case 12:elY(this,!1);return;case 13:this.i=null,erA(this,null);return;case 15:elB(this,!1);return;case 16:elZ(this,!1);return;case 18:elJ(this,!1),M4(this.Cb,88)&&eko(Zd(Pp(this.Cb,88)),2);return;case 20:elQ(this,!0);return;case 21:erM(this,null);return;case 23:this.a||(this.a=new OT(tm9,this,23)),eRT(this.a);return}ec6(this,e-Y1((eBK(),tgj)),ee2((t=Pp(eaS(this,16),26))||tgj,e))},eUe.Gh=function(){esd(this),UH(QZ((eSp(),tvc),this)),evl(this),this.Bb|=1},eUe.Lj=function(){return ebY(this)},eUe.qk=function(){var e;return!!(e=ebY(this))&&(e.Bb&eZ1)!=0},eUe.rk=function(){return(this.Bb&eZ1)!=0},eUe.sk=function(){return(this.Bb&eH3)!=0},eUe.nk=function(e,t){return this.c=null,ecz(this,e,t)},eUe.Ib=function(){var e;return(64&this.Db)!=0?eCR(this):(e=new O1(eCR(this)),e.a+=" (containment: ",yG(e,(this.Bb&eZ1)!=0),e.a+=", resolveProxies: ",yG(e,(this.Bb&eH3)!=0),e.a+=")",e.a)},Y5(eZ2,"EReferenceImpl",99),eTS(548,115,{105:1,42:1,92:1,90:1,133:1,56:1,108:1,49:1,97:1,548:1,114:1,115:1},sp),eUe.Fb=function(e){return this===e},eUe.cd=function(){return this.b},eUe.dd=function(){return this.c},eUe.Hb=function(){return Ao(this)},eUe.Uh=function(e){RP(this,Lq(e))},eUe.ed=function(e){return P5(this,Lq(e))},eUe._g=function(e,t,n){var r;switch(e){case 0:return this.b;case 1:return this.c}return Qt(this,e-Y1((eBK(),tgF)),ee2((r=Pp(eaS(this,16),26))||tgF,e),t,n)},eUe.lh=function(e){var t;switch(e){case 0:return null!=this.b;case 1:return null!=this.c}return VP(this,e-Y1((eBK(),tgF)),ee2((t=Pp(eaS(this,16),26))||tgF,e))},eUe.sh=function(e,t){var n;switch(e){case 0:RR(this,Lq(t));return;case 1:ers(this,Lq(t));return}efL(this,e-Y1((eBK(),tgF)),ee2((n=Pp(eaS(this,16),26))||tgF,e),t)},eUe.zh=function(){return eBK(),tgF},eUe.Bh=function(e){var t;switch(e){case 0:ero(this,null);return;case 1:ers(this,null);return}ec6(this,e-Y1((eBK(),tgF)),ee2((t=Pp(eaS(this,16),26))||tgF,e))},eUe.Sh=function(){var e;return -1==this.a&&(e=this.b,this.a=null==e?0:ebA(e)),this.a},eUe.Th=function(e){this.a=e},eUe.Ib=function(){var e;return(64&this.Db)!=0?eMT(this):(e=new O1(eMT(this)),e.a+=" (key: ",xk(e,this.b),e.a+=", value: ",xk(e,this.c),e.a+=")",e.a)},eUe.a=-1,eUe.b=null,eUe.c=null;var tgf=Y5(eZ2,"EStringToStringMapEntryImpl",548),tgd=RL(eJz,"FeatureMap/Entry/Internal");eTS(565,1,eQa),eUe.Ok=function(e){return this.Pk(Pp(e,49))},eUe.Pk=function(e){return this.Ok(e)},eUe.Fb=function(e){var t,n;return this===e||!!M4(e,72)&&(t=Pp(e,72)).ak()==this.c&&(null==(n=this.dd())?null==t.dd():ecX(n,t.dd()))},eUe.ak=function(){return this.c},eUe.Hb=function(){var e;return e=this.dd(),esj(this.c)^(null==e?0:esj(e))},eUe.Ib=function(){var e,t;return t=etP((e=this.c).Hj()).Ph(),e.ne(),(null!=t&&0!=t.length?t+":"+e.ne():e.ne())+"="+this.dd()},Y5(eZ2,"EStructuralFeatureImpl/BasicFeatureMapEntry",565),eTS(776,565,eQa,Cg),eUe.Pk=function(e){return new Cg(this.c,e)},eUe.dd=function(){return this.a},eUe.Qk=function(e,t,n){return eiY(this,e,this.a,t,n)},eUe.Rk=function(e,t,n){return eiB(this,e,this.a,t,n)},Y5(eZ2,"EStructuralFeatureImpl/ContainmentUpdatingFeatureMapEntry",776),eTS(1314,1,{},k6),eUe.Pj=function(e,t,n,r,i){var a;return(a=Pp(JG(e,this.b),215)).nl(this.a).Wj(r)},eUe.Qj=function(e,t,n,r,i){var a;return(a=Pp(JG(e,this.b),215)).el(this.a,r,i)},eUe.Rj=function(e,t,n,r,i){var a;return(a=Pp(JG(e,this.b),215)).fl(this.a,r,i)},eUe.Sj=function(e,t,n){var r;return(r=Pp(JG(e,this.b),215)).nl(this.a).fj()},eUe.Tj=function(e,t,n,r){var i;(i=Pp(JG(e,this.b),215)).nl(this.a).Wb(r)},eUe.Uj=function(e,t,n){return Pp(JG(e,this.b),215).nl(this.a)},eUe.Vj=function(e,t,n){var r;(r=Pp(JG(e,this.b),215)).nl(this.a).Xj()},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateFeatureMapDelegator",1314),eTS(89,1,{},Pe,HS,$F,qc),eUe.Pj=function(e,t,n,r,i){var a;if(null==(a=t.Ch(n))&&t.Dh(n,a=eBN(this,e)),!i)switch(this.e){case 50:case 41:return Pp(a,589).sj();case 40:return Pp(a,215).kl()}return a},eUe.Qj=function(e,t,n,r,i){var a,o;return null==(o=t.Ch(n))&&t.Dh(n,o=eBN(this,e)),a=Pp(o,69).lk(r,i)},eUe.Rj=function(e,t,n,r,i){var a;return null!=(a=t.Ch(n))&&(i=Pp(a,69).mk(r,i)),i},eUe.Sj=function(e,t,n){var r;return null!=(r=t.Ch(n))&&Pp(r,76).fj()},eUe.Tj=function(e,t,n,r){var i;(i=Pp(t.Ch(n),76))||t.Dh(n,i=eBN(this,e)),i.Wb(r)},eUe.Uj=function(e,t,n){var r,i;return(null==(i=t.Ch(n))&&t.Dh(n,i=eBN(this,e)),M4(i,76))?Pp(i,76):(r=Pp(t.Ch(n),15),new pz(r))},eUe.Vj=function(e,t,n){var r;(r=Pp(t.Ch(n),76))||t.Dh(n,r=eBN(this,e)),r.Xj()},eUe.b=0,eUe.e=0,Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateMany",89),eTS(504,1,{}),eUe.Qj=function(e,t,n,r,i){throw p7(new bO)},eUe.Rj=function(e,t,n,r,i){throw p7(new bO)},eUe.Uj=function(e,t,n){return new Hk(this,e,t,n)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingle",504),eTS(1331,1,eJG,Hk),eUe.Wj=function(e){return this.a.Pj(this.c,this.d,this.b,e,!0)},eUe.fj=function(){return this.a.Sj(this.c,this.d,this.b)},eUe.Wb=function(e){this.a.Tj(this.c,this.d,this.b,e)},eUe.Xj=function(){this.a.Vj(this.c,this.d,this.b)},eUe.b=0,Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingle/1",1331),eTS(769,504,{},zl),eUe.Pj=function(e,t,n,r,i){return eIy(e,e.eh(),e.Vg())==this.b?this.sk()&&r?eTp(e):e.eh():null},eUe.Qj=function(e,t,n,r,i){var a,o;return e.eh()&&(i=(a=e.Vg())>=0?e.Qg(i):e.eh().ih(e,-1-a,null,i)),o=edv(e.Tg(),this.e),e.Sg(r,o,i)},eUe.Rj=function(e,t,n,r,i){var a;return a=edv(e.Tg(),this.e),e.Sg(null,a,i)},eUe.Sj=function(e,t,n){var r;return r=edv(e.Tg(),this.e),!!e.eh()&&e.Vg()==r},eUe.Tj=function(e,t,n,r){var i,a,o,s,u;if(null!=r&&!eNc(this.a,r))throw p7(new gA(eQo+(M4(r,56)?eyB(Pp(r,56).Tg()):ee6(esF(r)))+eQs+this.a+"'"));if(i=e.eh(),o=edv(e.Tg(),this.e),xc(r)!==xc(i)||e.Vg()!=o&&null!=r){if(eg7(e,Pp(r,56)))throw p7(new gL(eZ4+e.Ib()));u=null,i&&(u=(a=e.Vg())>=0?e.Qg(u):e.eh().ih(e,-1-a,null,u)),(s=Pp(r,49))&&(u=s.gh(e,edv(s.Tg(),this.b),null,u)),(u=e.Sg(s,o,u))&&u.Fi()}else e.Lg()&&e.Mg()&&eam(e,new FX(e,1,o,r,r))},eUe.Vj=function(e,t,n){var r,i,a,o;(r=e.eh())?(o=(i=e.Vg())>=0?e.Qg(null):e.eh().ih(e,-1-i,null,null),a=edv(e.Tg(),this.e),(o=e.Sg(null,a,o))&&o.Fi()):e.Lg()&&e.Mg()&&eam(e,new FJ(e,1,this.e,null,null))},eUe.sk=function(){return!1},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleContainer",769),eTS(1315,769,{},Pt),eUe.sk=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleContainerResolving",1315),eTS(563,504,{}),eUe.Pj=function(e,t,n,r,i){var a;return null==(a=t.Ch(n))?this.b:xc(a)===xc(tgZ)?null:a},eUe.Sj=function(e,t,n){var r;return null!=(r=t.Ch(n))&&(xc(r)===xc(tgZ)||!ecX(r,this.b))},eUe.Tj=function(e,t,n,r){var i,a;e.Lg()&&e.Mg()?(i=null==(a=t.Ch(n))?this.b:xc(a)===xc(tgZ)?null:a,null==r?null!=this.c?(t.Dh(n,null),r=this.b):null!=this.b?t.Dh(n,tgZ):t.Dh(n,null):(this.Sk(r),t.Dh(n,r)),eam(e,this.d.Tk(e,1,this.e,i,r))):null==r?null!=this.c?t.Dh(n,null):null!=this.b?t.Dh(n,tgZ):t.Dh(n,null):(this.Sk(r),t.Dh(n,r))},eUe.Vj=function(e,t,n){var r,i;e.Lg()&&e.Mg()?(r=null==(i=t.Ch(n))?this.b:xc(i)===xc(tgZ)?null:i,t.Eh(n),eam(e,this.d.Tk(e,1,this.e,r,this.b))):t.Eh(n)},eUe.Sk=function(e){throw p7(new bk)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData",563),eTS(eQu,1,{},sb),eUe.Tk=function(e,t,n,r,i){return new FJ(e,t,n,r,i)},eUe.Uk=function(e,t,n,r,i,a){return new H0(e,t,n,r,i,a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator",eQu),eTS(1332,eQu,{},sm),eUe.Tk=function(e,t,n,r,i){return new ZY(e,t,n,gN(LK(r)),gN(LK(i)))},eUe.Uk=function(e,t,n,r,i,a){return new W4(e,t,n,gN(LK(r)),gN(LK(i)),a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/1",1332),eTS(1333,eQu,{},sg),eUe.Tk=function(e,t,n,r,i){return new en_(e,t,n,Pp(r,217).a,Pp(i,217).a)},eUe.Uk=function(e,t,n,r,i,a){return new WX(e,t,n,Pp(r,217).a,Pp(i,217).a,a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/2",1333),eTS(1334,eQu,{},sv),eUe.Tk=function(e,t,n,r,i){return new enE(e,t,n,Pp(r,172).a,Pp(i,172).a)},eUe.Uk=function(e,t,n,r,i,a){return new WJ(e,t,n,Pp(r,172).a,Pp(i,172).a,a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/3",1334),eTS(1335,eQu,{},sy),eUe.Tk=function(e,t,n,r,i){return new Zj(e,t,n,gP(LV(r)),gP(LV(i)))},eUe.Uk=function(e,t,n,r,i,a){return new WQ(e,t,n,gP(LV(r)),gP(LV(i)),a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/4",1335),eTS(1336,eQu,{},sw),eUe.Tk=function(e,t,n,r,i){return new enx(e,t,n,Pp(r,155).a,Pp(i,155).a)},eUe.Uk=function(e,t,n,r,i,a){return new W1(e,t,n,Pp(r,155).a,Pp(i,155).a,a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/5",1336),eTS(1337,eQu,{},s_),eUe.Tk=function(e,t,n,r,i){return new ZF(e,t,n,Pp(r,19).a,Pp(i,19).a)},eUe.Uk=function(e,t,n,r,i,a){return new W0(e,t,n,Pp(r,19).a,Pp(i,19).a,a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/6",1337),eTS(1338,eQu,{},sE),eUe.Tk=function(e,t,n,r,i){return new enS(e,t,n,Pp(r,162).a,Pp(i,162).a)},eUe.Uk=function(e,t,n,r,i,a){return new W2(e,t,n,Pp(r,162).a,Pp(i,162).a,a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/7",1338),eTS(1339,eQu,{},sS),eUe.Tk=function(e,t,n,r,i){return new enk(e,t,n,Pp(r,184).a,Pp(i,184).a)},eUe.Uk=function(e,t,n,r,i,a){return new W3(e,t,n,Pp(r,184).a,Pp(i,184).a,a)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleData/NotificationCreator/8",1339),eTS(1317,563,{},Hx),eUe.Sk=function(e){if(!this.a.wj(e))throw p7(new gA(eQo+esF(e)+eQs+this.a+"'"))},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleDataDynamic",1317),eTS(1318,563,{},j6),eUe.Sk=function(e){},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleDataStatic",1318),eTS(770,563,{}),eUe.Sj=function(e,t,n){var r;return null!=(r=t.Ch(n))},eUe.Tj=function(e,t,n,r){var i,a;e.Lg()&&e.Mg()?(i=!0,null==(a=t.Ch(n))?(i=!1,a=this.b):xc(a)===xc(tgZ)&&(a=null),null==r?null!=this.c?(t.Dh(n,null),r=this.b):t.Dh(n,tgZ):(this.Sk(r),t.Dh(n,r)),eam(e,this.d.Uk(e,1,this.e,a,r,!i))):null==r?null!=this.c?t.Dh(n,null):t.Dh(n,tgZ):(this.Sk(r),t.Dh(n,r))},eUe.Vj=function(e,t,n){var r,i;e.Lg()&&e.Mg()?(r=!0,null==(i=t.Ch(n))?(r=!1,i=this.b):xc(i)===xc(tgZ)&&(i=null),t.Eh(n),eam(e,this.d.Uk(e,2,this.e,i,this.b,r))):t.Eh(n)},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleDataUnsettable",770),eTS(1319,770,{},HT),eUe.Sk=function(e){if(!this.a.wj(e))throw p7(new gA(eQo+esF(e)+eQs+this.a+"'"))},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleDataUnsettableDynamic",1319),eTS(1320,770,{},j9),eUe.Sk=function(e){},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleDataUnsettableStatic",1320),eTS(398,504,{},jd),eUe.Pj=function(e,t,n,r,i){var a,o,s,u,c;if(c=t.Ch(n),this.Kj()&&xc(c)===xc(tgZ))return null;if(!this.sk()||!r||null==c)return c;if((s=Pp(c,49)).kh()&&(u=ecv(e,s),s!=u)){if(!eNc(this.a,u))throw p7(new gA(eQo+esF(u)+eQs+this.a+"'"));t.Dh(n,c=u),this.rk()&&(a=Pp(u,49),o=s.ih(e,this.b?edv(s.Tg(),this.b):-1-edv(e.Tg(),this.e),null,null),a.eh()||(o=a.gh(e,this.b?edv(a.Tg(),this.b):-1-edv(e.Tg(),this.e),null,o)),o&&o.Fi()),e.Lg()&&e.Mg()&&eam(e,new FJ(e,9,this.e,s,u))}return c},eUe.Qj=function(e,t,n,r,i){var a,o;return xc(o=t.Ch(n))===xc(tgZ)&&(o=null),t.Dh(n,r),this.bj()?xc(o)!==xc(r)&&null!=o&&(i=(a=Pp(o,49)).ih(e,edv(a.Tg(),this.b),null,i)):this.rk()&&null!=o&&(i=Pp(o,49).ih(e,-1-edv(e.Tg(),this.e),null,i)),e.Lg()&&e.Mg()&&(i||(i=new yf(4)),i.Ei(new FJ(e,1,this.e,o,r))),i},eUe.Rj=function(e,t,n,r,i){var a;return xc(a=t.Ch(n))===xc(tgZ)&&(a=null),t.Eh(n),e.Lg()&&e.Mg()&&(i||(i=new yf(4)),this.Kj()?i.Ei(new FJ(e,2,this.e,a,null)):i.Ei(new FJ(e,1,this.e,a,null))),i},eUe.Sj=function(e,t,n){var r;return null!=(r=t.Ch(n))},eUe.Tj=function(e,t,n,r){var i,a,o,s,u;if(null!=r&&!eNc(this.a,r))throw p7(new gA(eQo+(M4(r,56)?eyB(Pp(r,56).Tg()):ee6(esF(r)))+eQs+this.a+"'"));s=null!=(u=t.Ch(n)),this.Kj()&&xc(u)===xc(tgZ)&&(u=null),o=null,this.bj()?xc(u)!==xc(r)&&(null!=u&&(o=(i=Pp(u,49)).ih(e,edv(i.Tg(),this.b),null,o)),null!=r&&(o=(i=Pp(r,49)).gh(e,edv(i.Tg(),this.b),null,o))):this.rk()&&xc(u)!==xc(r)&&(null!=u&&(o=Pp(u,49).ih(e,-1-edv(e.Tg(),this.e),null,o)),null!=r&&(o=Pp(r,49).gh(e,-1-edv(e.Tg(),this.e),null,o))),null==r&&this.Kj()?t.Dh(n,tgZ):t.Dh(n,r),e.Lg()&&e.Mg()?(a=new H0(e,1,this.e,u,r,this.Kj()&&!s),o?(o.Ei(a),o.Fi()):eam(e,a)):o&&o.Fi()},eUe.Vj=function(e,t,n){var r,i,a,o,s;o=null!=(s=t.Ch(n)),this.Kj()&&xc(s)===xc(tgZ)&&(s=null),a=null,null!=s&&(this.bj()?a=(r=Pp(s,49)).ih(e,edv(r.Tg(),this.b),null,a):this.rk()&&(a=Pp(s,49).ih(e,-1-edv(e.Tg(),this.e),null,a))),t.Eh(n),e.Lg()&&e.Mg()?(i=new H0(e,this.Kj()?2:1,this.e,s,null,o),a?(a.Ei(i),a.Fi()):eam(e,i)):a&&a.Fi()},eUe.bj=function(){return!1},eUe.rk=function(){return!1},eUe.sk=function(){return!1},eUe.Kj=function(){return!1},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObject",398),eTS(564,398,{},LE),eUe.rk=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainment",564),eTS(1323,564,{},LS),eUe.sk=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainmentResolving",1323),eTS(772,564,{},Lk),eUe.Kj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainmentUnsettable",772),eTS(1325,772,{},Lx),eUe.sk=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainmentUnsettableResolving",1325),eTS(640,564,{},Pn),eUe.bj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainmentWithInverse",640),eTS(1324,640,{},Pa),eUe.sk=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainmentWithInverseResolving",1324),eTS(773,640,{},Po),eUe.Kj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainmentWithInverseUnsettable",773),eTS(1326,773,{},Ps),eUe.sk=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectContainmentWithInverseUnsettableResolving",1326),eTS(641,398,{},LT),eUe.sk=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectResolving",641),eTS(1327,641,{},LM),eUe.Kj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectResolvingUnsettable",1327),eTS(774,641,{},Pr),eUe.bj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectResolvingWithInverse",774),eTS(1328,774,{},Pu),eUe.Kj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectResolvingWithInverseUnsettable",1328),eTS(1321,398,{},LO),eUe.Kj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectUnsettable",1321),eTS(771,398,{},Pi),eUe.bj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectWithInverse",771),eTS(1322,771,{},Pc),eUe.Kj=function(){return!0},Y5(eZ2,"EStructuralFeatureImpl/InternalSettingDelegateSingleEObjectWithInverseUnsettable",1322),eTS(775,565,eQa,Bj),eUe.Pk=function(e){return new Bj(this.a,this.c,e)},eUe.dd=function(){return this.b},eUe.Qk=function(e,t,n){return Jt(this,e,this.b,n)},eUe.Rk=function(e,t,n){return Jn(this,e,this.b,n)},Y5(eZ2,"EStructuralFeatureImpl/InverseUpdatingFeatureMapEntry",775),eTS(1329,1,eJG,pz),eUe.Wj=function(e){return this.a},eUe.fj=function(){return M4(this.a,95)?Pp(this.a,95).fj():!this.a.dc()},eUe.Wb=function(e){this.a.$b(),this.a.Gc(Pp(e,15))},eUe.Xj=function(){M4(this.a,95)?Pp(this.a,95).Xj():this.a.$b()},Y5(eZ2,"EStructuralFeatureImpl/SettingMany",1329),eTS(1330,565,eQa,qf),eUe.Ok=function(e){return new Cv((eR7(),tvK),this.b.Ih(this.a,e))},eUe.dd=function(){return null},eUe.Qk=function(e,t,n){return n},eUe.Rk=function(e,t,n){return n},Y5(eZ2,"EStructuralFeatureImpl/SimpleContentFeatureMapEntry",1330),eTS(642,565,eQa,Cv),eUe.Ok=function(e){return new Cv(this.c,e)},eUe.dd=function(){return this.a},eUe.Qk=function(e,t,n){return n},eUe.Rk=function(e,t,n){return n},Y5(eZ2,"EStructuralFeatureImpl/SimpleFeatureMapEntry",642),eTS(391,497,eXz,sk),eUe.ri=function(e){return Je(tm7,eUp,26,e,0,1)},eUe.ni=function(){return!1},Y5(eZ2,"ESuperAdapter/1",391),eTS(444,438,{105:1,92:1,90:1,147:1,191:1,56:1,108:1,836:1,49:1,97:1,150:1,444:1,114:1,115:1},sx),eUe._g=function(e,t,n){var r;switch(e){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),this.Ab;case 1:return this.zb;case 2:return this.a||(this.a=new jh(this,tgr,this)),this.a}return Qt(this,e-Y1((eBK(),tgU)),ee2((r=Pp(eaS(this,16),26))||tgU,e),t,n)},eUe.jh=function(e,t,n){var r,i;switch(t){case 0:return this.Ab||(this.Ab=new FQ(tm4,this,0,3)),ep6(this.Ab,e,n);case 2:return this.a||(this.a=new jh(this,tgr,this)),ep6(this.a,e,n)}return(i=Pp(ee2((r=Pp(eaS(this,16),26))||(eBK(),tgU),t),66)).Nj().Rj(this,ehH(this),t-Y1((eBK(),tgU)),e,n)},eUe.lh=function(e){var t;switch(e){case 0:return!!this.Ab&&0!=this.Ab.i;case 1:return null!=this.zb;case 2:return!!this.a&&0!=this.a.i}return VP(this,e-Y1((eBK(),tgU)),ee2((t=Pp(eaS(this,16),26))||tgU,e))},eUe.sh=function(e,t){var n;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab),this.Ab||(this.Ab=new FQ(tm4,this,0,3)),Y4(this.Ab,Pp(t,14));return;case 1:er3(this,Lq(t));return;case 2:this.a||(this.a=new jh(this,tgr,this)),eRT(this.a),this.a||(this.a=new jh(this,tgr,this)),Y4(this.a,Pp(t,14));return}efL(this,e-Y1((eBK(),tgU)),ee2((n=Pp(eaS(this,16),26))||tgU,e),t)},eUe.zh=function(){return eBK(),tgU},eUe.Bh=function(e){var t;switch(e){case 0:this.Ab||(this.Ab=new FQ(tm4,this,0,3)),eRT(this.Ab);return;case 1:er3(this,null);return;case 2:this.a||(this.a=new jh(this,tgr,this)),eRT(this.a);return}ec6(this,e-Y1((eBK(),tgU)),ee2((t=Pp(eaS(this,16),26))||tgU,e))},Y5(eZ2,"ETypeParameterImpl",444),eTS(445,85,eJ9,jh),eUe.cj=function(e,t){return ewV(this,Pp(e,87),t)},eUe.dj=function(e,t){return ewq(this,Pp(e,87),t)},Y5(eZ2,"ETypeParameterImpl/1",445),eTS(634,43,e$s,mR),eUe.ec=function(){return new pG(this)},Y5(eZ2,"ETypeParameterImpl/2",634),eTS(556,eUT,eUM,pG),eUe.Fc=function(e){return Ie(this,Pp(e,87))},eUe.Gc=function(e){var t,n,r;for(r=!1,n=e.Kc();n.Ob();)t=Pp(n.Pb(),87),null==Um(this.a,t,"")&&(r=!0);return r},eUe.$b=function(){Yy(this.a)},eUe.Hc=function(e){return F9(this.a,e)},eUe.Kc=function(){var e;return e=new esz(new fS(this.a).a),new pW(e)},eUe.Mc=function(e){return Xp(this,e)},eUe.gc=function(){return wq(this.a)},Y5(eZ2,"ETypeParameterImpl/2/1",556),eTS(557,1,eUE,pW),eUe.Nb=function(e){F8(this,e)},eUe.Pb=function(){return Pp(etz(this.a).cd(),87)},eUe.Ob=function(){return this.a.b},eUe.Qb=function(){JM(this.a)},Y5(eZ2,"ETypeParameterImpl/2/1/1",557),eTS(1276,43,e$s,mj),eUe._b=function(e){return xd(e)?$r(this,e):!!$I(this.f,e)},eUe.xc=function(e){var t,n;return M4(t=xd(e)?zg(this,e):xu($I(this.f,e)),837)?(t=(n=Pp(t,837))._j(),Um(this,Pp(e,235),t),t):null!=t?t:null==e?(_3(),tvh):null},Y5(eZ2,"EValidatorRegistryImpl",1276),eTS(1313,704,{105:1,92:1,90:1,471:1,147:1,56:1,108:1,1941:1,49:1,97:1,150:1,114:1,115:1},sT),eUe.Ih=function(e,t){switch(e.yj()){case 21:case 22:case 23:case 24:case 26:case 31:case 32:case 37:case 38:case 39:case 40:case 43:case 44:case 48:case 49:case 20:return null==t?null:efF(t);case 25:return etR(t);case 27:return Qn(t);case 28:return Qr(t);case 29:return null==t?null:MU(tmS[0],Pp(t,199));case 41:return null==t?"":yx(Pp(t,290));case 42:return efF(t);case 50:return Lq(t);default:throw p7(new gL(eZ5+e.ne()+eZ6))}},eUe.Jh=function(e){var t;switch(-1==e.G&&(e.G=(t=etP(e))?ebv(t.Mh(),e):-1),e.G){case 0:return new mC;case 1:return new sa;case 2:return new c0;case 4:return new bN;case 5:return new mI;case 6:return new bD;case 7:return new cQ;case 10:return new sr;case 11:return new mD;case 12:return new $y;case 13:return new mN;case 14:return new LB;case 17:return new sp;case 18:return new p5;case 19:return new sx;default:throw p7(new gL(eZ7+e.zb+eZ6))}},eUe.Kh=function(e,t){switch(e.yj()){case 20:return null==t?null:new yY(t);case 21:return null==t?null:new TU(t);case 23:case 22:return null==t?null:ehL(t);case 26:case 24:return null==t?null:eeT(eDa(t,-128,127)<<24>>24);case 25:return eMp(t);case 27:return egg(t);case 28:return egv(t);case 29:return e__(t);case 32:case 31:return null==t?null:eEu(t);case 38:case 37:return null==t?null:new bK(t);case 40:case 39:return null==t?null:ell(eDa(t,eHt,eUu));case 41:case 42:return null;case 44:case 43:return null==t?null:ehQ(eF0(t));case 49:case 48:return null==t?null:elf(eDa(t,eQl,32767)<<16>>16);case 50:return t;default:throw p7(new gL(eZ5+e.ne()+eZ6))}},Y5(eZ2,"EcoreFactoryImpl",1313),eTS(547,179,{105:1,92:1,90:1,147:1,191:1,56:1,235:1,108:1,1939:1,49:1,97:1,150:1,179:1,547:1,114:1,115:1,675:1},Uh),eUe.gb=!1,eUe.hb=!1;var tgh,tgp,tgb,tgm,tgg,tgv,tgy,tgw,tg_,tgE,tgS,tgk,tgx,tgT,tgM,tgO,tgA,tgL,tgC,tgI,tgD,tgN,tgP,tgR,tgj,tgF,tgY,tgB,tgU,tgH,tg$,tgz,tgG,tgW,tgK,tgV,tgq,tgZ,tgX,tgJ,tgQ,tg1,tg0,tg2,tg3,tg4,tg5,tg6,tg9=!1;Y5(eZ2,"EcorePackageImpl",547),eTS(1184,1,{837:1},sM),eUe._j=function(){return OJ(),tvp},Y5(eZ2,"EcorePackageImpl/1",1184),eTS(1193,1,eQS,sO),eUe.wj=function(e){return M4(e,147)},eUe.xj=function(e){return Je(e6y,eUp,147,e,0,1)},Y5(eZ2,"EcorePackageImpl/10",1193),eTS(1194,1,eQS,sA),eUe.wj=function(e){return M4(e,191)},eUe.xj=function(e){return Je(e6_,eUp,191,e,0,1)},Y5(eZ2,"EcorePackageImpl/11",1194),eTS(1195,1,eQS,sL),eUe.wj=function(e){return M4(e,56)},eUe.xj=function(e){return Je(e6f,eUp,56,e,0,1)},Y5(eZ2,"EcorePackageImpl/12",1195),eTS(1196,1,eQS,sC),eUe.wj=function(e){return M4(e,399)},eUe.xj=function(e){return Je(tgi,eJ5,59,e,0,1)},Y5(eZ2,"EcorePackageImpl/13",1196),eTS(1197,1,eQS,sI),eUe.wj=function(e){return M4(e,235)},eUe.xj=function(e){return Je(e6E,eUp,235,e,0,1)},Y5(eZ2,"EcorePackageImpl/14",1197),eTS(1198,1,eQS,sD),eUe.wj=function(e){return M4(e,509)},eUe.xj=function(e){return Je(tga,eUp,2017,e,0,1)},Y5(eZ2,"EcorePackageImpl/15",1198),eTS(1199,1,eQS,sN),eUe.wj=function(e){return M4(e,99)},eUe.xj=function(e){return Je(tgo,eJ4,18,e,0,1)},Y5(eZ2,"EcorePackageImpl/16",1199),eTS(1200,1,eQS,sP),eUe.wj=function(e){return M4(e,170)},eUe.xj=function(e){return Je(tm6,eJ4,170,e,0,1)},Y5(eZ2,"EcorePackageImpl/17",1200),eTS(1201,1,eQS,sR),eUe.wj=function(e){return M4(e,472)},eUe.xj=function(e){return Je(tm5,eUp,472,e,0,1)},Y5(eZ2,"EcorePackageImpl/18",1201),eTS(1202,1,eQS,sj),eUe.wj=function(e){return M4(e,548)},eUe.xj=function(e){return Je(tgf,eJL,548,e,0,1)},Y5(eZ2,"EcorePackageImpl/19",1202),eTS(1185,1,eQS,sF),eUe.wj=function(e){return M4(e,322)},eUe.xj=function(e){return Je(tm9,eJ4,34,e,0,1)},Y5(eZ2,"EcorePackageImpl/2",1185),eTS(1203,1,eQS,sY),eUe.wj=function(e){return M4(e,241)},eUe.xj=function(e){return Je(tgr,eQt,87,e,0,1)},Y5(eZ2,"EcorePackageImpl/20",1203),eTS(1204,1,eQS,sB),eUe.wj=function(e){return M4(e,444)},eUe.xj=function(e){return Je(tgs,eUp,836,e,0,1)},Y5(eZ2,"EcorePackageImpl/21",1204),eTS(1205,1,eQS,sU),eUe.wj=function(e){return xl(e)},eUe.xj=function(e){return Je(e11,eUP,476,e,8,1)},Y5(eZ2,"EcorePackageImpl/22",1205),eTS(1206,1,eQS,sH),eUe.wj=function(e){return M4(e,190)},eUe.xj=function(e){return Je(tyk,eUP,190,e,0,2)},Y5(eZ2,"EcorePackageImpl/23",1206),eTS(1207,1,eQS,s$),eUe.wj=function(e){return M4(e,217)},eUe.xj=function(e){return Je(e10,eUP,217,e,0,1)},Y5(eZ2,"EcorePackageImpl/24",1207),eTS(1208,1,eQS,sz),eUe.wj=function(e){return M4(e,172)},eUe.xj=function(e){return Je(e12,eUP,172,e,0,1)},Y5(eZ2,"EcorePackageImpl/25",1208),eTS(1209,1,eQS,sG),eUe.wj=function(e){return M4(e,199)},eUe.xj=function(e){return Je(e1Q,eUP,199,e,0,1)},Y5(eZ2,"EcorePackageImpl/26",1209),eTS(1210,1,eQS,sW),eUe.wj=function(e){return!1},eUe.xj=function(e){return Je(tyA,eUp,2110,e,0,1)},Y5(eZ2,"EcorePackageImpl/27",1210),eTS(1211,1,eQS,sK),eUe.wj=function(e){return xf(e)},eUe.xj=function(e){return Je(e13,eUP,333,e,7,1)},Y5(eZ2,"EcorePackageImpl/28",1211),eTS(1212,1,eQS,sV),eUe.wj=function(e){return M4(e,58)},eUe.xj=function(e){return Je(e6L,ezZ,58,e,0,1)},Y5(eZ2,"EcorePackageImpl/29",1212),eTS(1186,1,eQS,sq),eUe.wj=function(e){return M4(e,510)},eUe.xj=function(e){return Je(tm4,{3:1,4:1,5:1,1934:1},590,e,0,1)},Y5(eZ2,"EcorePackageImpl/3",1186),eTS(1213,1,eQS,sZ),eUe.wj=function(e){return M4(e,573)},eUe.xj=function(e){return Je(e6j,eUp,1940,e,0,1)},Y5(eZ2,"EcorePackageImpl/30",1213),eTS(1214,1,eQS,sX),eUe.wj=function(e){return M4(e,153)},eUe.xj=function(e){return Je(tg7,ezZ,153,e,0,1)},Y5(eZ2,"EcorePackageImpl/31",1214),eTS(1215,1,eQS,sJ),eUe.wj=function(e){return M4(e,72)},eUe.xj=function(e){return Je(tgc,eQk,72,e,0,1)},Y5(eZ2,"EcorePackageImpl/32",1215),eTS(1216,1,eQS,sQ),eUe.wj=function(e){return M4(e,155)},eUe.xj=function(e){return Je(e14,eUP,155,e,0,1)},Y5(eZ2,"EcorePackageImpl/33",1216),eTS(1217,1,eQS,s1),eUe.wj=function(e){return M4(e,19)},eUe.xj=function(e){return Je(e15,eUP,19,e,0,1)},Y5(eZ2,"EcorePackageImpl/34",1217),eTS(1218,1,eQS,s0),eUe.wj=function(e){return M4(e,290)},eUe.xj=function(e){return Je(e1j,eUp,290,e,0,1)},Y5(eZ2,"EcorePackageImpl/35",1218),eTS(1219,1,eQS,s2),eUe.wj=function(e){return M4(e,162)},eUe.xj=function(e){return Je(e16,eUP,162,e,0,1)},Y5(eZ2,"EcorePackageImpl/36",1219),eTS(1220,1,eQS,s3),eUe.wj=function(e){return M4(e,83)},eUe.xj=function(e){return Je(e1Y,eUp,83,e,0,1)},Y5(eZ2,"EcorePackageImpl/37",1220),eTS(1221,1,eQS,s4),eUe.wj=function(e){return M4(e,591)},eUe.xj=function(e){return Je(tg8,eUp,591,e,0,1)},Y5(eZ2,"EcorePackageImpl/38",1221),eTS(1222,1,eQS,s5),eUe.wj=function(e){return!1},eUe.xj=function(e){return Je(tyL,eUp,2111,e,0,1)},Y5(eZ2,"EcorePackageImpl/39",1222),eTS(1187,1,eQS,s6),eUe.wj=function(e){return M4(e,88)},eUe.xj=function(e){return Je(tm7,eUp,26,e,0,1)},Y5(eZ2,"EcorePackageImpl/4",1187),eTS(1223,1,eQS,s9),eUe.wj=function(e){return M4(e,184)},eUe.xj=function(e){return Je(e19,eUP,184,e,0,1)},Y5(eZ2,"EcorePackageImpl/40",1223),eTS(1224,1,eQS,s8),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eZ2,"EcorePackageImpl/41",1224),eTS(1225,1,eQS,s7),eUe.wj=function(e){return M4(e,588)},eUe.xj=function(e){return Je(e6I,eUp,588,e,0,1)},Y5(eZ2,"EcorePackageImpl/42",1225),eTS(1226,1,eQS,ue),eUe.wj=function(e){return!1},eUe.xj=function(e){return Je(tyC,eUP,2112,e,0,1)},Y5(eZ2,"EcorePackageImpl/43",1226),eTS(1227,1,eQS,ut),eUe.wj=function(e){return M4(e,42)},eUe.xj=function(e){return Je(e1$,eUK,42,e,0,1)},Y5(eZ2,"EcorePackageImpl/44",1227),eTS(1188,1,eQS,un),eUe.wj=function(e){return M4(e,138)},eUe.xj=function(e){return Je(tm8,eUp,138,e,0,1)},Y5(eZ2,"EcorePackageImpl/5",1188),eTS(1189,1,eQS,ur),eUe.wj=function(e){return M4(e,148)},eUe.xj=function(e){return Je(tge,eUp,148,e,0,1)},Y5(eZ2,"EcorePackageImpl/6",1189),eTS(1190,1,eQS,ui),eUe.wj=function(e){return M4(e,457)},eUe.xj=function(e){return Je(tgt,eUp,671,e,0,1)},Y5(eZ2,"EcorePackageImpl/7",1190),eTS(1191,1,eQS,ua),eUe.wj=function(e){return M4(e,573)},eUe.xj=function(e){return Je(tgn,eUp,678,e,0,1)},Y5(eZ2,"EcorePackageImpl/8",1191),eTS(1192,1,eQS,uo),eUe.wj=function(e){return M4(e,471)},eUe.xj=function(e){return Je(e6w,eUp,471,e,0,1)},Y5(eZ2,"EcorePackageImpl/9",1192),eTS(1025,1982,eJO,gT),eUe.bi=function(e,t){ecV(this,Pp(t,415))},eUe.fi=function(e,t){eSU(this,e,Pp(t,415))},Y5(eZ2,"MinimalEObjectImpl/1ArrayDelegatingAdapterList",1025),eTS(1026,143,eJx,BF),eUe.Ai=function(){return this.a.a},Y5(eZ2,"MinimalEObjectImpl/1ArrayDelegatingAdapterList/1",1026),eTS(1053,1052,{},Ms),Y5("org.eclipse.emf.ecore.plugin","EcorePlugin",1053);var tg8=RL(eQx,"Resource");eTS(781,1378,eQT),eUe.Yk=function(e){},eUe.Zk=function(e){},eUe.Vk=function(){return this.a||(this.a=new pK(this)),this.a},eUe.Wk=function(e){var t,n,r,i,a;if((r=e.length)>0){if(GV(0,e.length),47==e.charCodeAt(0)){for(t=1,a=new XM(4),i=1;t0&&(e=e.substr(0,n))}return ekX(this,e)},eUe.Xk=function(){return this.c},eUe.Ib=function(){var e;return yx(this.gm)+"@"+(e=esj(this)>>>0).toString(16)+" uri='"+this.d+"'"},eUe.b=!1,Y5(eQM,"ResourceImpl",781),eTS(1379,781,eQT,pq),Y5(eQM,"BinaryResourceImpl",1379),eTS(1169,694,eXG),eUe.si=function(e){return M4(e,56)?$x(this,Pp(e,56)):M4(e,591)?new Ow(Pp(e,591).Vk()):xc(e)===xc(this.f)?Pp(e,14).Kc():(LF(),tmB.a)},eUe.Ob=function(){return exI(this)},eUe.a=!1,Y5(eJz,"EcoreUtil/ContentTreeIterator",1169),eTS(1380,1169,eXG,F0),eUe.si=function(e){return xc(e)===xc(this.f)?Pp(e,15).Kc():new K0(Pp(e,56))},Y5(eQM,"ResourceImpl/5",1380),eTS(648,1994,eJ6,pK),eUe.Hc=function(e){return this.i<=4?ev9(this,e):M4(e,49)&&Pp(e,49).Zg()==this.a},eUe.bi=function(e,t){e==this.i-1&&(this.a.b||(this.a.b=!0))},eUe.di=function(e,t){0==e?this.a.b||(this.a.b=!0):X8(this,e,t)},eUe.fi=function(e,t){},eUe.gi=function(e,t,n){},eUe.aj=function(){return 2},eUe.Ai=function(){return this.a},eUe.bj=function(){return!0},eUe.cj=function(e,t){var n;return t=(n=Pp(e,49)).wh(this.a,t)},eUe.dj=function(e,t){var n;return(n=Pp(e,49)).wh(null,t)},eUe.ej=function(){return!1},eUe.hi=function(){return!0},eUe.ri=function(e){return Je(e6f,eUp,56,e,0,1)},eUe.ni=function(){return!1},Y5(eQM,"ResourceImpl/ContentsEList",648),eTS(957,1964,eU5,pV),eUe.Zc=function(e){return this.a._h(e)},eUe.gc=function(){return this.a.gc()},Y5(eJz,"AbstractSequentialInternalEList/1",957),eTS(624,1,{},PQ),Y5(eJz,"BasicExtendedMetaData",624),eTS(1160,1,{},k9),eUe.$k=function(){return null},eUe._k=function(){return -2==this.a&&fi(this,e_f(this.d,this.b)),this.a},eUe.al=function(){return null},eUe.bl=function(){return Hj(),Hj(),e2r},eUe.ne=function(){return this.c==eQH&&fo(this,eh1(this.d,this.b)),this.c},eUe.cl=function(){return 0},eUe.a=-2,eUe.c=eQH,Y5(eJz,"BasicExtendedMetaData/EClassExtendedMetaDataImpl",1160),eTS(1161,1,{},Ke),eUe.$k=function(){return this.a==(ZE(),tvf)&&fa(this,eO9(this.f,this.b)),this.a},eUe._k=function(){return 0},eUe.al=function(){return this.c==(ZE(),tvf)&&fs(this,eO8(this.f,this.b)),this.c},eUe.bl=function(){return this.d||fu(this,eIA(this.f,this.b)),this.d},eUe.ne=function(){return this.e==eQH&&fc(this,eh1(this.f,this.b)),this.e},eUe.cl=function(){return -2==this.g&&fl(this,ewd(this.f,this.b)),this.g},eUe.e=eQH,eUe.g=-2,Y5(eJz,"BasicExtendedMetaData/EDataTypeExtendedMetaDataImpl",1161),eTS(1159,1,{},xn),eUe.b=!1,eUe.c=!1,Y5(eJz,"BasicExtendedMetaData/EPackageExtendedMetaDataImpl",1159),eTS(1162,1,{},W7),eUe.c=-2,eUe.e=eQH,eUe.f=eQH,Y5(eJz,"BasicExtendedMetaData/EStructuralFeatureExtendedMetaDataImpl",1162),eTS(585,622,eJ9,PJ),eUe.aj=function(){return this.c},eUe.Fk=function(){return!1},eUe.li=function(e,t){return t},eUe.c=0,Y5(eJz,"EDataTypeEList",585);var tg7=RL(eJz,"FeatureMap");eTS(75,585,{3:1,4:1,20:1,28:1,52:1,14:1,15:1,54:1,67:1,63:1,58:1,76:1,153:1,215:1,1937:1,69:1,95:1},eiR),eUe.Vc=function(e,t){eO0(this,e,Pp(t,72))},eUe.Fc=function(e){return eM6(this,Pp(e,72))},eUe.Yh=function(e){Y2(this,Pp(e,72))},eUe.cj=function(e,t){return IG(this,Pp(e,72),t)},eUe.dj=function(e,t){return IW(this,Pp(e,72),t)},eUe.ii=function(e,t){return eI7(this,e,t)},eUe.li=function(e,t){return ejg(this,e,Pp(t,72))},eUe._c=function(e,t){return eA6(this,e,Pp(t,72))},eUe.jj=function(e,t){return IK(this,Pp(e,72),t)},eUe.kj=function(e,t){return IV(this,Pp(e,72),t)},eUe.lj=function(e,t,n){return eyU(this,Pp(e,72),Pp(t,72),n)},eUe.oi=function(e,t){return ewk(this,e,Pp(t,72))},eUe.dl=function(e,t){return eIF(this,e,t)},eUe.Wc=function(e,t){var n,r,i,a,o,s,u,c,l;for(c=new eta(t.gc()),i=t.Kc();i.Ob();)if(a=(r=Pp(i.Pb(),72)).ak(),eLt(this.e,a))a.hi()&&(Vq(this,a,r.dd())||ev9(c,r))||JL(c,r);else{for(s=0,l=eAY(this.e.Tg(),a),n=Pp(this.g,119),o=!0;s=0;)if(t=e[this.c],this.k.rl(t.ak()))return this.j=this.f?t:t.dd(),this.i=-2,!0;return this.i=-1,this.g=-1,!1},Y5(eJz,"BasicFeatureMap/FeatureEIterator",410),eTS(662,410,eUC,x1),eUe.Lk=function(){return!0},Y5(eJz,"BasicFeatureMap/ResolvingFeatureEIterator",662),eTS(955,486,eQr,Mz),eUe.Gi=function(){return this},Y5(eJz,"EContentsEList/1",955),eTS(956,486,eQr,x0),eUe.Lk=function(){return!1},Y5(eJz,"EContentsEList/2",956),eTS(954,279,eQi,MG),eUe.Nk=function(e){},eUe.Ob=function(){return!1},eUe.Sb=function(){return!1},Y5(eJz,"EContentsEList/FeatureIteratorImpl/1",954),eTS(825,585,eJ9,OM),eUe.ci=function(){this.a=!0},eUe.fj=function(){return this.a},eUe.Xj=function(){var e;eRT(this),TO(this.e)?(e=this.a,this.a=!1,eam(this.e,new ZB(this.e,2,this.c,e,!1))):this.a=!1},eUe.a=!1,Y5(eJz,"EDataTypeEList/Unsettable",825),eTS(1849,585,eJ9,OO),eUe.hi=function(){return!0},Y5(eJz,"EDataTypeUniqueEList",1849),eTS(1850,825,eJ9,OA),eUe.hi=function(){return!0},Y5(eJz,"EDataTypeUniqueEList/Unsettable",1850),eTS(139,85,eJ9,OS),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectContainmentEList/Resolving",139),eTS(1163,545,eJ9,Ok),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectContainmentEList/Unsettable/Resolving",1163),eTS(748,16,eJ9,Io),eUe.ci=function(){this.a=!0},eUe.fj=function(){return this.a},eUe.Xj=function(){var e;eRT(this),TO(this.e)?(e=this.a,this.a=!1,eam(this.e,new ZB(this.e,2,this.c,e,!1))):this.a=!1},eUe.a=!1,Y5(eJz,"EObjectContainmentWithInverseEList/Unsettable",748),eTS(1173,748,eJ9,Is),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectContainmentWithInverseEList/Unsettable/Resolving",1173),eTS(743,496,eJ9,Ox),eUe.ci=function(){this.a=!0},eUe.fj=function(){return this.a},eUe.Xj=function(){var e;eRT(this),TO(this.e)?(e=this.a,this.a=!1,eam(this.e,new ZB(this.e,2,this.c,e,!1))):this.a=!1},eUe.a=!1,Y5(eJz,"EObjectEList/Unsettable",743),eTS(328,496,eJ9,OT),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectResolvingEList",328),eTS(1641,743,eJ9,OL),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectResolvingEList/Unsettable",1641),eTS(1381,1,{},us),Y5(eJz,"EObjectValidator",1381),eTS(546,496,eJ9,F1),eUe.zk=function(){return this.d},eUe.Ak=function(){return this.b},eUe.bj=function(){return!0},eUe.Dk=function(){return!0},eUe.b=0,Y5(eJz,"EObjectWithInverseEList",546),eTS(1176,546,eJ9,Iu),eUe.Ck=function(){return!0},Y5(eJz,"EObjectWithInverseEList/ManyInverse",1176),eTS(625,546,eJ9,Ic),eUe.ci=function(){this.a=!0},eUe.fj=function(){return this.a},eUe.Xj=function(){var e;eRT(this),TO(this.e)?(e=this.a,this.a=!1,eam(this.e,new ZB(this.e,2,this.c,e,!1))):this.a=!1},eUe.a=!1,Y5(eJz,"EObjectWithInverseEList/Unsettable",625),eTS(1175,625,eJ9,If),eUe.Ck=function(){return!0},Y5(eJz,"EObjectWithInverseEList/Unsettable/ManyInverse",1175),eTS(749,546,eJ9,Il),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectWithInverseResolvingEList",749),eTS(31,749,eJ9,Ih),eUe.Ck=function(){return!0},Y5(eJz,"EObjectWithInverseResolvingEList/ManyInverse",31),eTS(750,625,eJ9,Id),eUe.Ek=function(){return!0},eUe.li=function(e,t){return ex7(this,e,Pp(t,56))},Y5(eJz,"EObjectWithInverseResolvingEList/Unsettable",750),eTS(1174,750,eJ9,Ip),eUe.Ck=function(){return!0},Y5(eJz,"EObjectWithInverseResolvingEList/Unsettable/ManyInverse",1174),eTS(1164,622,eJ9),eUe.ai=function(){return(1792&this.b)==0},eUe.ci=function(){this.b|=1},eUe.Bk=function(){return(4&this.b)!=0},eUe.bj=function(){return(40&this.b)!=0},eUe.Ck=function(){return(16&this.b)!=0},eUe.Dk=function(){return(8&this.b)!=0},eUe.Ek=function(){return(this.b&eJq)!=0},eUe.rk=function(){return(32&this.b)!=0},eUe.Fk=function(){return(this.b&eXt)!=0},eUe.wj=function(e){return this.d?VB(this.d,e):this.ak().Yj().wj(e)},eUe.fj=function(){return(2&this.b)!=0?(1&this.b)!=0:0!=this.i},eUe.hi=function(){return(128&this.b)!=0},eUe.Xj=function(){var e;eRT(this),(2&this.b)!=0&&(TO(this.e)?(e=(1&this.b)!=0,this.b&=-2,bz(this,new ZB(this.e,2,edv(this.e.Tg(),this.ak()),e,!1))):this.b&=-2)},eUe.ni=function(){return(1536&this.b)==0},eUe.b=0,Y5(eJz,"EcoreEList/Generic",1164),eTS(1165,1164,eJ9,H2),eUe.ak=function(){return this.a},Y5(eJz,"EcoreEList/Dynamic",1165),eTS(747,63,eXz,pZ),eUe.ri=function(e){return enb(this.a.a,e)},Y5(eJz,"EcoreEMap/1",747),eTS(746,85,eJ9,FZ),eUe.bi=function(e,t){ebB(this.b,Pp(t,133))},eUe.di=function(e,t){eac(this.b)},eUe.ei=function(e,t,n){var r;++(r=this.b,Pp(t,133),r).e},eUe.fi=function(e,t){elj(this.b,Pp(t,133))},eUe.gi=function(e,t,n){elj(this.b,Pp(n,133)),xc(n)===xc(t)&&Pp(n,133).Th(Mi(Pp(t,133).cd())),ebB(this.b,Pp(t,133))},Y5(eJz,"EcoreEMap/DelegateEObjectContainmentEList",746),eTS(1171,151,eJW,enQ),Y5(eJz,"EcoreEMap/Unsettable",1171),eTS(1172,746,eJ9,Ib),eUe.ci=function(){this.a=!0},eUe.fj=function(){return this.a},eUe.Xj=function(){var e;eRT(this),TO(this.e)?(e=this.a,this.a=!1,eam(this.e,new ZB(this.e,2,this.c,e,!1))):this.a=!1},eUe.a=!1,Y5(eJz,"EcoreEMap/Unsettable/UnsettableDelegateEObjectContainmentEList",1172),eTS(1168,228,e$s,YQ),eUe.a=!1,eUe.b=!1,Y5(eJz,"EcoreUtil/Copier",1168),eTS(745,1,eUE,K0),eUe.Nb=function(e){F8(this,e)},eUe.Ob=function(){return edV(this)},eUe.Pb=function(){var e;return edV(this),e=this.b,this.b=null,e},eUe.Qb=function(){this.a.Qb()},Y5(eJz,"EcoreUtil/ProperContentIterator",745),eTS(1382,1381,{},c2),Y5(eJz,"EcoreValidator",1382),RL(eJz,"FeatureMapUtil/Validator"),eTS(1260,1,{1942:1},uu),eUe.rl=function(e){return!0},Y5(eJz,"FeatureMapUtil/1",1260),eTS(757,1,{1942:1},eF2),eUe.rl=function(e){var t;return this.c==e||(null!=(t=LK(Bp(this.a,e)))?t==(OQ(),e0P):eCV(this,e)?(Z$(this.a,e,(OQ(),e0P)),!0):(Z$(this.a,e,(OQ(),e0N)),!1))},eUe.e=!1,Y5(eJz,"FeatureMapUtil/BasicValidator",757),eTS(758,43,e$s,MW),Y5(eJz,"FeatureMapUtil/BasicValidator/Cache",758),eTS(501,52,{20:1,28:1,52:1,14:1,15:1,58:1,76:1,69:1,95:1},xe),eUe.Vc=function(e,t){eLe(this.c,this.b,e,t)},eUe.Fc=function(e){return eIF(this.c,this.b,e)},eUe.Wc=function(e,t){return ePq(this.c,this.b,e,t)},eUe.Gc=function(e){return MJ(this,e)},eUe.Xh=function(e,t){ee7(this.c,this.b,e,t)},eUe.lk=function(e,t){return eCB(this.c,this.b,e,t)},eUe.pi=function(e){return ePL(this.c,this.b,e,!1)},eUe.Zh=function(){return TC(this.c,this.b)},eUe.$h=function(){return TI(this.c,this.b)},eUe._h=function(e){return X9(this.c,this.b,e)},eUe.mk=function(e,t){return Cp(this,e,t)},eUe.$b=function(){bG(this)},eUe.Hc=function(e){return Vq(this.c,this.b,e)},eUe.Ic=function(e){return eiF(this.c,this.b,e)},eUe.Xb=function(e){return ePL(this.c,this.b,e,!0)},eUe.Wj=function(e){return this},eUe.Xc=function(e){return VZ(this.c,this.b,e)},eUe.dc=function(){return xs(this)},eUe.fj=function(){return!edK(this.c,this.b)},eUe.Kc=function(){return eei(this.c,this.b)},eUe.Yc=function(){return eea(this.c,this.b)},eUe.Zc=function(e){return ely(this.c,this.b,e)},eUe.ii=function(e,t){return eNn(this.c,this.b,e,t)},eUe.ji=function(e,t){Xx(this.c,this.b,e,t)},eUe.$c=function(e){return eE0(this.c,this.b,e)},eUe.Mc=function(e){return eIC(this.c,this.b,e)},eUe._c=function(e,t){return eNL(this.c,this.b,e,t)},eUe.Wb=function(e){exZ(this.c,this.b),MJ(this,Pp(e,15))},eUe.gc=function(){return elG(this.c,this.b)},eUe.Pc=function(){return Wb(this.c,this.b)},eUe.Qc=function(e){return VX(this.c,this.b,e)},eUe.Ib=function(){var e,t;for(t=new vs,t.a+="[",e=TC(this.c,this.b);euf(e);)xk(t,Ae(ebm(e))),euf(e)&&(t.a+=eUd);return t.a+="]",t.a},eUe.Xj=function(){exZ(this.c,this.b)},Y5(eJz,"FeatureMapUtil/FeatureEList",501),eTS(627,36,eJx,qu),eUe.yi=function(e){return elc(this,e)},eUe.Di=function(e){var t,n,r,i,a,o,s;switch(this.d){case 1:case 2:if(xc(a=e.Ai())===xc(this.c)&&elc(this,null)==e.yi(null))return this.g=e.zi(),1==e.xi()&&(this.d=1),!0;break;case 3:if(3===(i=e.xi())&&xc(a=e.Ai())===xc(this.c)&&elc(this,null)==e.yi(null))return this.d=5,JL(t=new eta(2),this.g),JL(t,e.zi()),this.g=t,!0;break;case 5:if(3===(i=e.xi())&&xc(a=e.Ai())===xc(this.c)&&elc(this,null)==e.yi(null))return(n=Pp(this.g,14)).Fc(e.zi()),!0;break;case 4:switch(i=e.xi()){case 3:if(xc(a=e.Ai())===xc(this.c)&&elc(this,null)==e.yi(null))return this.d=1,this.g=e.zi(),!0;break;case 4:if(xc(a=e.Ai())===xc(this.c)&&elc(this,null)==e.yi(null))return this.d=6,JL(s=new eta(2),this.n),JL(s,e.Bi()),this.n=s,o=eow(vx(ty_,1),eHT,25,15,[this.o,e.Ci()]),this.g=o,!0}break;case 6:if(4===(i=e.xi())&&xc(a=e.Ai())===xc(this.c)&&elc(this,null)==e.yi(null))return(n=Pp(this.n,14)).Fc(e.Bi()),r=Je(ty_,eHT,25,(o=Pp(this.g,48)).length+1,15,1),ePD(o,0,r,0,o.length),r[o.length]=e.Ci(),this.g=r,!0}return!1},Y5(eJz,"FeatureMapUtil/FeatureENotificationImpl",627),eTS(552,501,{20:1,28:1,52:1,14:1,15:1,58:1,76:1,153:1,215:1,1937:1,69:1,95:1},RA),eUe.dl=function(e,t){return eIF(this.c,e,t)},eUe.el=function(e,t,n){return eCB(this.c,e,t,n)},eUe.fl=function(e,t,n){return ePT(this.c,e,t,n)},eUe.gl=function(){return this},eUe.hl=function(e,t){return ePC(this.c,e,t)},eUe.il=function(e){return Pp(ePL(this.c,this.b,e,!1),72).ak()},eUe.jl=function(e){return Pp(ePL(this.c,this.b,e,!1),72).dd()},eUe.kl=function(){return this.a},eUe.ll=function(e){return!edK(this.c,e)},eUe.ml=function(e,t){ePJ(this.c,e,t)},eUe.nl=function(e){return erp(this.c,e)},eUe.ol=function(e){emY(this.c,e)},Y5(eJz,"FeatureMapUtil/FeatureFeatureMap",552),eTS(1259,1,eJG,xr),eUe.Wj=function(e){return ePL(this.b,this.a,-1,e)},eUe.fj=function(){return!edK(this.b,this.a)},eUe.Wb=function(e){ePJ(this.b,this.a,e)},eUe.Xj=function(){exZ(this.b,this.a)},Y5(eJz,"FeatureMapUtil/FeatureValue",1259);var tve=RL(eQz,"AnyType");eTS(666,60,eHr,gV),Y5(eQz,"InvalidDatatypeValueException",666);var tvt=RL(eQz,eQG),tvn=RL(eQz,eQW),tvr=RL(eQz,eQK);eTS(830,506,{105:1,92:1,90:1,56:1,49:1,97:1,843:1},mF),eUe._g=function(e,t,n){switch(e){case 0:if(n)return this.c||(this.c=new eiR(this,0)),this.c;return this.c||(this.c=new eiR(this,0)),this.c.b;case 1:if(n)return this.c||(this.c=new eiR(this,0)),Pp(GP(this.c,(eR7(),tvx)),153);return(this.c||(this.c=new eiR(this,0)),Pp(Pp(GP(this.c,(eR7(),tvx)),153),215)).kl();case 2:if(n)return this.b||(this.b=new eiR(this,2)),this.b;return this.b||(this.b=new eiR(this,2)),this.b.b}return Qt(this,e-Y1(this.zh()),ee2((2&this.j)==0?this.zh():(this.k||(this.k=new c1),this.k).ck(),e),t,n)},eUe.jh=function(e,t,n){var r;switch(t){case 0:return this.c||(this.c=new eiR(this,0)),eIM(this.c,e,n);case 1:return(this.c||(this.c=new eiR(this,0)),Pp(Pp(GP(this.c,(eR7(),tvx)),153),69)).mk(e,n);case 2:return this.b||(this.b=new eiR(this,2)),eIM(this.b,e,n)}return(r=Pp(ee2((2&this.j)==0?this.zh():(this.k||(this.k=new c1),this.k).ck(),t),66)).Nj().Rj(this,Q5(this),t-Y1(this.zh()),e,n)},eUe.lh=function(e){switch(e){case 0:return!!this.c&&0!=this.c.i;case 1:return!(this.c||(this.c=new eiR(this,0)),Pp(GP(this.c,(eR7(),tvx)),153)).dc();case 2:return!!this.b&&0!=this.b.i}return VP(this,e-Y1(this.zh()),ee2((2&this.j)==0?this.zh():(this.k||(this.k=new c1),this.k).ck(),e))},eUe.sh=function(e,t){switch(e){case 0:this.c||(this.c=new eiR(this,0)),YH(this.c,t);return;case 1:(this.c||(this.c=new eiR(this,0)),Pp(Pp(GP(this.c,(eR7(),tvx)),153),215)).Wb(t);return;case 2:this.b||(this.b=new eiR(this,2)),YH(this.b,t);return}efL(this,e-Y1(this.zh()),ee2((2&this.j)==0?this.zh():(this.k||(this.k=new c1),this.k).ck(),e),t)},eUe.zh=function(){return eR7(),tvk},eUe.Bh=function(e){switch(e){case 0:this.c||(this.c=new eiR(this,0)),eRT(this.c);return;case 1:(this.c||(this.c=new eiR(this,0)),Pp(GP(this.c,(eR7(),tvx)),153)).$b();return;case 2:this.b||(this.b=new eiR(this,2)),eRT(this.b);return}ec6(this,e-Y1(this.zh()),ee2((2&this.j)==0?this.zh():(this.k||(this.k=new c1),this.k).ck(),e))},eUe.Ib=function(){var e;return(4&this.j)!=0?eMT(this):(e=new O1(eMT(this)),e.a+=" (mixed: ",xS(e,this.c),e.a+=", anyAttribute: ",xS(e,this.b),e.a+=")",e.a)},Y5(eQV,"AnyTypeImpl",830),eTS(667,506,{105:1,92:1,90:1,56:1,49:1,97:1,2021:1,667:1},ul),eUe._g=function(e,t,n){switch(e){case 0:return this.a;case 1:return this.b}return Qt(this,e-Y1((eR7(),tvj)),ee2((2&this.j)==0?tvj:(this.k||(this.k=new c1),this.k).ck(),e),t,n)},eUe.lh=function(e){switch(e){case 0:return null!=this.a;case 1:return null!=this.b}return VP(this,e-Y1((eR7(),tvj)),ee2((2&this.j)==0?tvj:(this.k||(this.k=new c1),this.k).ck(),e))},eUe.sh=function(e,t){switch(e){case 0:fg(this,Lq(t));return;case 1:fv(this,Lq(t));return}efL(this,e-Y1((eR7(),tvj)),ee2((2&this.j)==0?tvj:(this.k||(this.k=new c1),this.k).ck(),e),t)},eUe.zh=function(){return eR7(),tvj},eUe.Bh=function(e){switch(e){case 0:this.a=null;return;case 1:this.b=null;return}ec6(this,e-Y1((eR7(),tvj)),ee2((2&this.j)==0?tvj:(this.k||(this.k=new c1),this.k).ck(),e))},eUe.Ib=function(){var e;return(4&this.j)!=0?eMT(this):(e=new O1(eMT(this)),e.a+=" (data: ",xk(e,this.a),e.a+=", target: ",xk(e,this.b),e.a+=")",e.a)},eUe.a=null,eUe.b=null,Y5(eQV,"ProcessingInstructionImpl",667),eTS(668,830,{105:1,92:1,90:1,56:1,49:1,97:1,843:1,2022:1,668:1},mB),eUe._g=function(e,t,n){switch(e){case 0:if(n)return this.c||(this.c=new eiR(this,0)),this.c;return this.c||(this.c=new eiR(this,0)),this.c.b;case 1:if(n)return this.c||(this.c=new eiR(this,0)),Pp(GP(this.c,(eR7(),tvx)),153);return(this.c||(this.c=new eiR(this,0)),Pp(Pp(GP(this.c,(eR7(),tvx)),153),215)).kl();case 2:if(n)return this.b||(this.b=new eiR(this,2)),this.b;return this.b||(this.b=new eiR(this,2)),this.b.b;case 3:return this.c||(this.c=new eiR(this,0)),Lq(ePC(this.c,(eR7(),tvB),!0));case 4:return Iy(this.a,(this.c||(this.c=new eiR(this,0)),Lq(ePC(this.c,(eR7(),tvB),!0))));case 5:return this.a}return Qt(this,e-Y1((eR7(),tvY)),ee2((2&this.j)==0?tvY:(this.k||(this.k=new c1),this.k).ck(),e),t,n)},eUe.lh=function(e){switch(e){case 0:return!!this.c&&0!=this.c.i;case 1:return!(this.c||(this.c=new eiR(this,0)),Pp(GP(this.c,(eR7(),tvx)),153)).dc();case 2:return!!this.b&&0!=this.b.i;case 3:return this.c||(this.c=new eiR(this,0)),null!=Lq(ePC(this.c,(eR7(),tvB),!0));case 4:return null!=Iy(this.a,(this.c||(this.c=new eiR(this,0)),Lq(ePC(this.c,(eR7(),tvB),!0))));case 5:return!!this.a}return VP(this,e-Y1((eR7(),tvY)),ee2((2&this.j)==0?tvY:(this.k||(this.k=new c1),this.k).ck(),e))},eUe.sh=function(e,t){switch(e){case 0:this.c||(this.c=new eiR(this,0)),YH(this.c,t);return;case 1:(this.c||(this.c=new eiR(this,0)),Pp(Pp(GP(this.c,(eR7(),tvx)),153),215)).Wb(t);return;case 2:this.b||(this.b=new eiR(this,2)),YH(this.b,t);return;case 3:Kt(this,Lq(t));return;case 4:Kt(this,Iw(this.a,t));return;case 5:fy(this,Pp(t,148));return}efL(this,e-Y1((eR7(),tvY)),ee2((2&this.j)==0?tvY:(this.k||(this.k=new c1),this.k).ck(),e),t)},eUe.zh=function(){return eR7(),tvY},eUe.Bh=function(e){switch(e){case 0:this.c||(this.c=new eiR(this,0)),eRT(this.c);return;case 1:(this.c||(this.c=new eiR(this,0)),Pp(GP(this.c,(eR7(),tvx)),153)).$b();return;case 2:this.b||(this.b=new eiR(this,2)),eRT(this.b);return;case 3:this.c||(this.c=new eiR(this,0)),ePJ(this.c,(eR7(),tvB),null);return;case 4:Kt(this,Iw(this.a,null));return;case 5:this.a=null;return}ec6(this,e-Y1((eR7(),tvY)),ee2((2&this.j)==0?tvY:(this.k||(this.k=new c1),this.k).ck(),e))},Y5(eQV,"SimpleAnyTypeImpl",668),eTS(669,506,{105:1,92:1,90:1,56:1,49:1,97:1,2023:1,669:1},mY),eUe._g=function(e,t,n){switch(e){case 0:if(n)return this.a||(this.a=new eiR(this,0)),this.a;return this.a||(this.a=new eiR(this,0)),this.a.b;case 1:return n?(this.b||(this.b=new JY((eBK(),tgF),tgf,this,1)),this.b):(this.b||(this.b=new JY((eBK(),tgF),tgf,this,1)),X6(this.b));case 2:return n?(this.c||(this.c=new JY((eBK(),tgF),tgf,this,2)),this.c):(this.c||(this.c=new JY((eBK(),tgF),tgf,this,2)),X6(this.c));case 3:return this.a||(this.a=new eiR(this,0)),GP(this.a,(eR7(),tv$));case 4:return this.a||(this.a=new eiR(this,0)),GP(this.a,(eR7(),tvz));case 5:return this.a||(this.a=new eiR(this,0)),GP(this.a,(eR7(),tvW));case 6:return this.a||(this.a=new eiR(this,0)),GP(this.a,(eR7(),tvK))}return Qt(this,e-Y1((eR7(),tvH)),ee2((2&this.j)==0?tvH:(this.k||(this.k=new c1),this.k).ck(),e),t,n)},eUe.jh=function(e,t,n){var r;switch(t){case 0:return this.a||(this.a=new eiR(this,0)),eIM(this.a,e,n);case 1:return this.b||(this.b=new JY((eBK(),tgF),tgf,this,1)),Iz(this.b,e,n);case 2:return this.c||(this.c=new JY((eBK(),tgF),tgf,this,2)),Iz(this.c,e,n);case 5:return this.a||(this.a=new eiR(this,0)),Cp(GP(this.a,(eR7(),tvW)),e,n)}return(r=Pp(ee2((2&this.j)==0?(eR7(),tvH):(this.k||(this.k=new c1),this.k).ck(),t),66)).Nj().Rj(this,Q5(this),t-Y1((eR7(),tvH)),e,n)},eUe.lh=function(e){switch(e){case 0:return!!this.a&&0!=this.a.i;case 1:return!!this.b&&0!=this.b.f;case 2:return!!this.c&&0!=this.c.f;case 3:return this.a||(this.a=new eiR(this,0)),!xs(GP(this.a,(eR7(),tv$)));case 4:return this.a||(this.a=new eiR(this,0)),!xs(GP(this.a,(eR7(),tvz)));case 5:return this.a||(this.a=new eiR(this,0)),!xs(GP(this.a,(eR7(),tvW)));case 6:return this.a||(this.a=new eiR(this,0)),!xs(GP(this.a,(eR7(),tvK)))}return VP(this,e-Y1((eR7(),tvH)),ee2((2&this.j)==0?tvH:(this.k||(this.k=new c1),this.k).ck(),e))},eUe.sh=function(e,t){switch(e){case 0:this.a||(this.a=new eiR(this,0)),YH(this.a,t);return;case 1:this.b||(this.b=new JY((eBK(),tgF),tgf,this,1)),eai(this.b,t);return;case 2:this.c||(this.c=new JY((eBK(),tgF),tgf,this,2)),eai(this.c,t);return;case 3:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tv$))),this.a||(this.a=new eiR(this,0)),MJ(GP(this.a,tv$),Pp(t,14));return;case 4:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tvz))),this.a||(this.a=new eiR(this,0)),MJ(GP(this.a,tvz),Pp(t,14));return;case 5:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tvW))),this.a||(this.a=new eiR(this,0)),MJ(GP(this.a,tvW),Pp(t,14));return;case 6:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tvK))),this.a||(this.a=new eiR(this,0)),MJ(GP(this.a,tvK),Pp(t,14));return}efL(this,e-Y1((eR7(),tvH)),ee2((2&this.j)==0?tvH:(this.k||(this.k=new c1),this.k).ck(),e),t)},eUe.zh=function(){return eR7(),tvH},eUe.Bh=function(e){switch(e){case 0:this.a||(this.a=new eiR(this,0)),eRT(this.a);return;case 1:this.b||(this.b=new JY((eBK(),tgF),tgf,this,1)),this.b.c.$b();return;case 2:this.c||(this.c=new JY((eBK(),tgF),tgf,this,2)),this.c.c.$b();return;case 3:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tv$)));return;case 4:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tvz)));return;case 5:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tvW)));return;case 6:this.a||(this.a=new eiR(this,0)),bG(GP(this.a,(eR7(),tvK)));return}ec6(this,e-Y1((eR7(),tvH)),ee2((2&this.j)==0?tvH:(this.k||(this.k=new c1),this.k).ck(),e))},eUe.Ib=function(){var e;return(4&this.j)!=0?eMT(this):(e=new O1(eMT(this)),e.a+=" (mixed: ",xS(e,this.a),e.a+=")",e.a)},Y5(eQV,"XMLTypeDocumentRootImpl",669),eTS(1919,704,{105:1,92:1,90:1,471:1,147:1,56:1,108:1,49:1,97:1,150:1,114:1,115:1,2024:1},uc),eUe.Ih=function(e,t){switch(e.yj()){case 7:case 8:case 9:case 10:case 16:case 22:case 23:case 24:case 25:case 26:case 32:case 33:case 34:case 36:case 37:case 44:case 45:case 50:case 51:case 53:case 55:case 56:case 57:case 58:case 60:case 61:case 4:return null==t?null:efF(t);case 19:case 28:case 29:case 35:case 38:case 39:case 41:case 46:case 52:case 54:case 5:return Lq(t);case 6:return LH(Pp(t,190));case 12:case 47:case 49:case 11:return ejZ(this,e,t);case 13:return null==t?null:ePg(Pp(t,240));case 15:case 14:return null==t?null:Yk(gP(LV(t)));case 17:return eyV((eR7(),t));case 18:return eyV(t);case 21:case 20:return null==t?null:Yx(Pp(t,155).a);case 27:return L$(Pp(t,190));case 30:return emB((eR7(),Pp(t,15)));case 31:return emB(Pp(t,15));case 40:return LG((eR7(),t));case 42:return eyq((eR7(),t));case 43:return eyq(t);case 59:case 48:return Lz((eR7(),t));default:throw p7(new gL(eZ5+e.ne()+eZ6))}},eUe.Jh=function(e){var t;switch(-1==e.G&&(e.G=(t=etP(e))?ebv(t.Mh(),e):-1),e.G){case 0:return new mF;case 1:return new ul;case 2:return new mB;case 3:return new mY;default:throw p7(new gL(eZ7+e.zb+eZ6))}},eUe.Kh=function(e,t){var n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g;switch(e.yj()){case 5:case 52:case 4:return t;case 6:return epU(t);case 8:case 7:return null==t?null:ewe(t);case 9:return null==t?null:eeT(eDa((r=ePh(t,!0)).length>0&&(GV(0,r.length),43==r.charCodeAt(0))?r.substr(1):r,-128,127)<<24>>24);case 10:return null==t?null:eeT(eDa((i=ePh(t,!0)).length>0&&(GV(0,i.length),43==i.charCodeAt(0))?i.substr(1):i,-128,127)<<24>>24);case 11:return Lq(eBd(this,(eR7(),tvO),t));case 12:return Lq(eBd(this,(eR7(),tvA),t));case 13:return null==t?null:new yY(ePh(t,!0));case 15:case 14:return eOa(t);case 16:return Lq(eBd(this,(eR7(),tvL),t));case 17:return ehy((eR7(),t));case 18:return ehy(t);case 28:case 29:case 35:case 38:case 39:case 41:case 54:case 19:return ePh(t,!0);case 21:case 20:return eOv(t);case 22:return Lq(eBd(this,(eR7(),tvC),t));case 23:return Lq(eBd(this,(eR7(),tvI),t));case 24:return Lq(eBd(this,(eR7(),tvD),t));case 25:return Lq(eBd(this,(eR7(),tvN),t));case 26:return Lq(eBd(this,(eR7(),tvP),t));case 27:return epw(t);case 30:return ehw((eR7(),t));case 31:return ehw(t);case 32:return null==t?null:ell(eDa((l=ePh(t,!0)).length>0&&(GV(0,l.length),43==l.charCodeAt(0))?l.substr(1):l,eHt,eUu));case 33:return null==t?null:new TU((f=ePh(t,!0)).length>0&&(GV(0,f.length),43==f.charCodeAt(0))?f.substr(1):f);case 34:return null==t?null:ell(eDa((d=ePh(t,!0)).length>0&&(GV(0,d.length),43==d.charCodeAt(0))?d.substr(1):d,eHt,eUu));case 36:return null==t?null:ehQ(eF0((h=ePh(t,!0)).length>0&&(GV(0,h.length),43==h.charCodeAt(0))?h.substr(1):h));case 37:return null==t?null:ehQ(eF0((p=ePh(t,!0)).length>0&&(GV(0,p.length),43==p.charCodeAt(0))?p.substr(1):p));case 40:return edR((eR7(),t));case 42:return eh_((eR7(),t));case 43:return eh_(t);case 44:return null==t?null:new TU((b=ePh(t,!0)).length>0&&(GV(0,b.length),43==b.charCodeAt(0))?b.substr(1):b);case 45:return null==t?null:new TU((m=ePh(t,!0)).length>0&&(GV(0,m.length),43==m.charCodeAt(0))?m.substr(1):m);case 46:return ePh(t,!1);case 47:return Lq(eBd(this,(eR7(),tvR),t));case 59:case 48:return edP((eR7(),t));case 49:return Lq(eBd(this,(eR7(),tvF),t));case 50:return null==t?null:elf(eDa((g=ePh(t,!0)).length>0&&(GV(0,g.length),43==g.charCodeAt(0))?g.substr(1):g,eQl,32767)<<16>>16);case 51:return null==t?null:elf(eDa((a=ePh(t,!0)).length>0&&(GV(0,a.length),43==a.charCodeAt(0))?a.substr(1):a,eQl,32767)<<16>>16);case 53:return Lq(eBd(this,(eR7(),tvU),t));case 55:return null==t?null:elf(eDa((o=ePh(t,!0)).length>0&&(GV(0,o.length),43==o.charCodeAt(0))?o.substr(1):o,eQl,32767)<<16>>16);case 56:return null==t?null:elf(eDa((s=ePh(t,!0)).length>0&&(GV(0,s.length),43==s.charCodeAt(0))?s.substr(1):s,eQl,32767)<<16>>16);case 57:return null==t?null:ehQ(eF0((u=ePh(t,!0)).length>0&&(GV(0,u.length),43==u.charCodeAt(0))?u.substr(1):u));case 58:return null==t?null:ehQ(eF0((c=ePh(t,!0)).length>0&&(GV(0,c.length),43==c.charCodeAt(0))?c.substr(1):c));case 60:return null==t?null:ell(eDa((n=ePh(t,!0)).length>0&&(GV(0,n.length),43==n.charCodeAt(0))?n.substr(1):n,eHt,eUu));case 61:return null==t?null:ell(eDa(ePh(t,!0),eHt,eUu));default:throw p7(new gL(eZ5+e.ne()+eZ6))}},Y5(eQV,"XMLTypeFactoryImpl",1919),eTS(586,179,{105:1,92:1,90:1,147:1,191:1,56:1,235:1,108:1,49:1,97:1,150:1,179:1,114:1,115:1,675:1,1945:1,586:1},Ud),eUe.N=!1,eUe.O=!1;var tvi=!1;Y5(eQV,"XMLTypePackageImpl",586),eTS(1852,1,{837:1},uf),eUe._j=function(){return eD4(),eB2},Y5(eQV,"XMLTypePackageImpl/1",1852),eTS(1861,1,eQS,ud),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/10",1861),eTS(1862,1,eQS,uh),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/11",1862),eTS(1863,1,eQS,up),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/12",1863),eTS(1864,1,eQS,ub),eUe.wj=function(e){return xf(e)},eUe.xj=function(e){return Je(e13,eUP,333,e,7,1)},Y5(eQV,"XMLTypePackageImpl/13",1864),eTS(1865,1,eQS,um),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/14",1865),eTS(1866,1,eQS,ug),eUe.wj=function(e){return M4(e,15)},eUe.xj=function(e){return Je(e1H,ezZ,15,e,0,1)},Y5(eQV,"XMLTypePackageImpl/15",1866),eTS(1867,1,eQS,uv),eUe.wj=function(e){return M4(e,15)},eUe.xj=function(e){return Je(e1H,ezZ,15,e,0,1)},Y5(eQV,"XMLTypePackageImpl/16",1867),eTS(1868,1,eQS,uy),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/17",1868),eTS(1869,1,eQS,uw),eUe.wj=function(e){return M4(e,155)},eUe.xj=function(e){return Je(e14,eUP,155,e,0,1)},Y5(eQV,"XMLTypePackageImpl/18",1869),eTS(1870,1,eQS,u_),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/19",1870),eTS(1853,1,eQS,uE),eUe.wj=function(e){return M4(e,843)},eUe.xj=function(e){return Je(tve,eUp,843,e,0,1)},Y5(eQV,"XMLTypePackageImpl/2",1853),eTS(1871,1,eQS,uS),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/20",1871),eTS(1872,1,eQS,uk),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/21",1872),eTS(1873,1,eQS,ux),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/22",1873),eTS(1874,1,eQS,uT),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/23",1874),eTS(1875,1,eQS,uM),eUe.wj=function(e){return M4(e,190)},eUe.xj=function(e){return Je(tyk,eUP,190,e,0,2)},Y5(eQV,"XMLTypePackageImpl/24",1875),eTS(1876,1,eQS,uO),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/25",1876),eTS(1877,1,eQS,uA),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/26",1877),eTS(1878,1,eQS,uL),eUe.wj=function(e){return M4(e,15)},eUe.xj=function(e){return Je(e1H,ezZ,15,e,0,1)},Y5(eQV,"XMLTypePackageImpl/27",1878),eTS(1879,1,eQS,uC),eUe.wj=function(e){return M4(e,15)},eUe.xj=function(e){return Je(e1H,ezZ,15,e,0,1)},Y5(eQV,"XMLTypePackageImpl/28",1879),eTS(1880,1,eQS,uI),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/29",1880),eTS(1854,1,eQS,uD),eUe.wj=function(e){return M4(e,667)},eUe.xj=function(e){return Je(tvt,eUp,2021,e,0,1)},Y5(eQV,"XMLTypePackageImpl/3",1854),eTS(1881,1,eQS,uN),eUe.wj=function(e){return M4(e,19)},eUe.xj=function(e){return Je(e15,eUP,19,e,0,1)},Y5(eQV,"XMLTypePackageImpl/30",1881),eTS(1882,1,eQS,uP),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/31",1882),eTS(1883,1,eQS,uR),eUe.wj=function(e){return M4(e,162)},eUe.xj=function(e){return Je(e16,eUP,162,e,0,1)},Y5(eQV,"XMLTypePackageImpl/32",1883),eTS(1884,1,eQS,uj),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/33",1884),eTS(1885,1,eQS,uF),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/34",1885),eTS(1886,1,eQS,uY),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/35",1886),eTS(1887,1,eQS,uB),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/36",1887),eTS(1888,1,eQS,uU),eUe.wj=function(e){return M4(e,15)},eUe.xj=function(e){return Je(e1H,ezZ,15,e,0,1)},Y5(eQV,"XMLTypePackageImpl/37",1888),eTS(1889,1,eQS,uH),eUe.wj=function(e){return M4(e,15)},eUe.xj=function(e){return Je(e1H,ezZ,15,e,0,1)},Y5(eQV,"XMLTypePackageImpl/38",1889),eTS(1890,1,eQS,u$),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/39",1890),eTS(1855,1,eQS,uz),eUe.wj=function(e){return M4(e,668)},eUe.xj=function(e){return Je(tvn,eUp,2022,e,0,1)},Y5(eQV,"XMLTypePackageImpl/4",1855),eTS(1891,1,eQS,uG),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/40",1891),eTS(1892,1,eQS,uW),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/41",1892),eTS(1893,1,eQS,uK),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/42",1893),eTS(1894,1,eQS,uV),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/43",1894),eTS(1895,1,eQS,uq),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/44",1895),eTS(1896,1,eQS,uZ),eUe.wj=function(e){return M4(e,184)},eUe.xj=function(e){return Je(e19,eUP,184,e,0,1)},Y5(eQV,"XMLTypePackageImpl/45",1896),eTS(1897,1,eQS,uX),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/46",1897),eTS(1898,1,eQS,uJ),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/47",1898),eTS(1899,1,eQS,uQ),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/48",1899),eTS(eHx,1,eQS,u1),eUe.wj=function(e){return M4(e,184)},eUe.xj=function(e){return Je(e19,eUP,184,e,0,1)},Y5(eQV,"XMLTypePackageImpl/49",eHx),eTS(1856,1,eQS,u0),eUe.wj=function(e){return M4(e,669)},eUe.xj=function(e){return Je(tvr,eUp,2023,e,0,1)},Y5(eQV,"XMLTypePackageImpl/5",1856),eTS(1901,1,eQS,u2),eUe.wj=function(e){return M4(e,162)},eUe.xj=function(e){return Je(e16,eUP,162,e,0,1)},Y5(eQV,"XMLTypePackageImpl/50",1901),eTS(1902,1,eQS,u3),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/51",1902),eTS(1903,1,eQS,u4),eUe.wj=function(e){return M4(e,19)},eUe.xj=function(e){return Je(e15,eUP,19,e,0,1)},Y5(eQV,"XMLTypePackageImpl/52",1903),eTS(1857,1,eQS,u5),eUe.wj=function(e){return xd(e)},eUe.xj=function(e){return Je(e17,eUP,2,e,6,1)},Y5(eQV,"XMLTypePackageImpl/6",1857),eTS(1858,1,eQS,u6),eUe.wj=function(e){return M4(e,190)},eUe.xj=function(e){return Je(tyk,eUP,190,e,0,2)},Y5(eQV,"XMLTypePackageImpl/7",1858),eTS(1859,1,eQS,u9),eUe.wj=function(e){return xl(e)},eUe.xj=function(e){return Je(e11,eUP,476,e,8,1)},Y5(eQV,"XMLTypePackageImpl/8",1859),eTS(1860,1,eQS,u8),eUe.wj=function(e){return M4(e,217)},eUe.xj=function(e){return Je(e10,eUP,217,e,0,1)},Y5(eQV,"XMLTypePackageImpl/9",1860),eTS(50,60,eHr,gX),Y5(e1l,"RegEx/ParseException",50),eTS(820,1,{},u7),eUe.sl=function(e){return e16*n)throw p7(new gX(eBJ((Mo(),eJd))));n=16*n+i}if(125!=this.a)throw p7(new gX(eBJ((Mo(),eJh))));if(n>e1f)throw p7(new gX(eBJ((Mo(),eJp))));e=n}else{if(i=0,0!=this.c||(i=eb0(this.a))<0||(n=i,eBM(this),0!=this.c||(i=eb0(this.a))<0))throw p7(new gX(eBJ((Mo(),eJf))));e=n=16*n+i}break;case 117:if(r=0,eBM(this),0!=this.c||(r=eb0(this.a))<0||(t=r,eBM(this),0!=this.c||(r=eb0(this.a))<0)||(t=16*t+r,eBM(this),0!=this.c||(r=eb0(this.a))<0)||(t=16*t+r,eBM(this),0!=this.c||(r=eb0(this.a))<0))throw p7(new gX(eBJ((Mo(),eJf))));e=t=16*t+r;break;case 118:if(eBM(this),0!=this.c||(r=eb0(this.a))<0||(t=r,eBM(this),0!=this.c||(r=eb0(this.a))<0)||(t=16*t+r,eBM(this),0!=this.c||(r=eb0(this.a))<0)||(t=16*t+r,eBM(this),0!=this.c||(r=eb0(this.a))<0)||(t=16*t+r,eBM(this),0!=this.c||(r=eb0(this.a))<0)||(t=16*t+r,eBM(this),0!=this.c||(r=eb0(this.a))<0))throw p7(new gX(eBJ((Mo(),eJf))));if((t=16*t+r)>e1f)throw p7(new gX(eBJ((Mo(),"parser.descappe.4"))));e=t;break;case 65:case 90:case 122:throw p7(new gX(eBJ((Mo(),eJb))))}return e},eUe.ul=function(e){var t,n;switch(e){case 100:n=(32&this.e)==32?eYB("Nd",!0):(eBG(),tv8);break;case 68:n=(32&this.e)==32?eYB("Nd",!1):(eBG(),tyr);break;case 119:n=(32&this.e)==32?eYB("IsWord",!0):(eBG(),tyd);break;case 87:n=(32&this.e)==32?eYB("IsWord",!1):(eBG(),tya);break;case 115:n=(32&this.e)==32?eYB("IsSpace",!0):(eBG(),tys);break;case 83:n=(32&this.e)==32?eYB("IsSpace",!1):(eBG(),tyi);break;default:throw p7(new go(e1d+(t=e).toString(16)))}return n},eUe.vl=function(e){var t,n,r,i,a,o,s,u,c,l,f,d;for(this.b=1,eBM(this),t=null,0==this.c&&94==this.a?(eBM(this),e?l=(eBG(),eBG(),++tyv,new WZ(5)):(t=(eBG(),eBG(),++tyv,new WZ(4)),eLw(t,0,e1f),l=(++tyv,new WZ(4)))):l=(eBG(),eBG(),++tyv,new WZ(4)),i=!0;1!=(d=this.c)&&(0!=d||93!=this.a||i);){if(i=!1,n=this.a,r=!1,10==d)switch(n){case 100:case 68:case 119:case 87:case 115:case 83:ePR(l,this.ul(n)),r=!0;break;case 105:case 73:case 99:case 67:(n=this.Ll(l,n))<0&&(r=!0);break;case 112:case 80:if(!(f=ext(this,n)))throw p7(new gX(eBJ((Mo(),eJe))));ePR(l,f),r=!0;break;default:n=this.tl()}else if(20==d){if((o=AG(this.i,58,this.d))<0)throw p7(new gX(eBJ((Mo(),eJt))));if(s=!0,94==UI(this.i,this.d)&&(++this.d,s=!1),!(u=JI(a=Az(this.i,this.d,o),s,(512&this.e)==512)))throw p7(new gX(eBJ((Mo(),eJr))));if(ePR(l,u),r=!0,o+1>=this.j||93!=UI(this.i,o+1))throw p7(new gX(eBJ((Mo(),eJt))));this.d=o+2}if(eBM(this),!r){if(0!=this.c||45!=this.a)eLw(l,n,n);else{if(eBM(this),1==(d=this.c))throw p7(new gX(eBJ((Mo(),eJn))));0==d&&93==this.a?(eLw(l,n,n),eLw(l,45,45)):(c=this.a,10==d&&(c=this.tl()),eBM(this),eLw(l,n,c))}}(this.e&eXt)==eXt&&0==this.c&&44==this.a&&eBM(this)}if(1==this.c)throw p7(new gX(eBJ((Mo(),eJn))));return t&&(ej0(t,l),l=t),eMS(l),eRo(l),this.b=0,eBM(this),l},eUe.wl=function(){var e,t,n,r;for(n=this.vl(!1);7!=(r=this.c);)if(e=this.a,0==r&&(45==e||38==e)||4==r){if(eBM(this),9!=this.c)throw p7(new gX(eBJ((Mo(),eJu))));if(t=this.vl(!1),4==r)ePR(n,t);else if(45==e)ej0(n,t);else if(38==e)ejO(n,t);else throw p7(new go("ASSERT"))}else throw p7(new gX(eBJ((Mo(),eJc))));return eBM(this),n},eUe.xl=function(){var e,t;return e=this.a-48,t=(eBG(),eBG(),++tyv,new zc(12,null,e)),this.g||(this.g=new bZ),bY(this.g,new pX(e)),eBM(this),t},eUe.yl=function(){return eBM(this),eBG(),tyu},eUe.zl=function(){return eBM(this),eBG(),tyo},eUe.Al=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Bl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Cl=function(){return eBM(this),esV()},eUe.Dl=function(){return eBM(this),eBG(),tyl},eUe.El=function(){return eBM(this),eBG(),tyh},eUe.Fl=function(){var e;if(this.d>=this.j||(65504&(e=UI(this.i,this.d++)))!=64)throw p7(new gX(eBJ((Mo(),eX6))));return eBM(this),eBG(),eBG(),++tyv,new jb(0,e-64)},eUe.Gl=function(){return eBM(this),eNw()},eUe.Hl=function(){return eBM(this),eBG(),typ},eUe.Il=function(){var e;return e=(eBG(),eBG(),++tyv,new jb(0,105)),eBM(this),e},eUe.Jl=function(){return eBM(this),eBG(),tyf},eUe.Kl=function(){return eBM(this),eBG(),tyc},eUe.Ll=function(e,t){return this.tl()},eUe.Ml=function(){return eBM(this),eBG(),tyt},eUe.Nl=function(){var e,t,n,r,i;if(this.d+1>=this.j)throw p7(new gX(eBJ((Mo(),eX3))));if(r=-1,t=null,49<=(e=UI(this.i,this.d))&&e<=57){if(r=e-48,this.g||(this.g=new bZ),bY(this.g,new pX(r)),++this.d,41!=UI(this.i,this.d))throw p7(new gX(eBJ((Mo(),eX1))));++this.d}else switch(63==e&&--this.d,eBM(this),(t=eBs(this)).e){case 20:case 21:case 22:case 23:break;case 8:if(7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));break;default:throw p7(new gX(eBJ((Mo(),eX4))))}if(eBM(this),i=ehT(this),n=null,2==i.e){if(2!=i.em())throw p7(new gX(eBJ((Mo(),eX5))));n=i.am(1),i=i.am(0)}if(7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),eBG(),eBG(),++tyv,new ee_(r,t,i,n)},eUe.Ol=function(){return eBM(this),eBG(),tyn},eUe.Pl=function(){var e;if(eBM(this),e=F4(24,ehT(this)),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),e},eUe.Ql=function(){var e;if(eBM(this),e=F4(20,ehT(this)),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),e},eUe.Rl=function(){var e;if(eBM(this),e=F4(22,ehT(this)),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),e},eUe.Sl=function(){var e,t,n,r,i;for(e=0,n=0,t=-1;this.d=this.j)throw p7(new gX(eBJ((Mo(),eX0))));if(45==t){for(++this.d;this.d=this.j)throw p7(new gX(eBJ((Mo(),eX0))))}if(58==t){if(++this.d,eBM(this),r=Bu(ehT(this),e,n),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));eBM(this)}else if(41==t)++this.d,eBM(this),r=Bu(ehT(this),e,n);else throw p7(new gX(eBJ((Mo(),eX2))));return r},eUe.Tl=function(){var e;if(eBM(this),e=F4(21,ehT(this)),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),e},eUe.Ul=function(){var e;if(eBM(this),e=F4(23,ehT(this)),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),e},eUe.Vl=function(){var e,t;if(eBM(this),e=this.f++,t=F5(ehT(this),e),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),t},eUe.Wl=function(){var e;if(eBM(this),e=F5(ehT(this),0),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),e},eUe.Xl=function(e){return(eBM(this),5==this.c)?(eBM(this),jS(e,(eBG(),eBG(),++tyv,new qa(9,e)))):jS(e,(eBG(),eBG(),++tyv,new qa(3,e)))},eUe.Yl=function(e){var t;return eBM(this),t=(eBG(),eBG(),++tyv,new Mr(2)),5==this.c?(eBM(this),eRv(t,tye),eRv(t,e)):(eRv(t,e),eRv(t,tye)),t},eUe.Zl=function(e){return(eBM(this),5==this.c)?(eBM(this),eBG(),eBG(),++tyv,new qa(9,e)):(eBG(),eBG(),++tyv,new qa(3,e))},eUe.a=0,eUe.b=0,eUe.c=0,eUe.d=0,eUe.e=0,eUe.f=1,eUe.g=null,eUe.j=0,Y5(e1l,"RegEx/RegexParser",820),eTS(1824,820,{},mU),eUe.sl=function(e){return!1},eUe.tl=function(){return eCn(this)},eUe.ul=function(e){return eDu(e)},eUe.vl=function(e){return eBL(this)},eUe.wl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.xl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.yl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.zl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Al=function(){return eBM(this),eDu(67)},eUe.Bl=function(){return eBM(this),eDu(73)},eUe.Cl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Dl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.El=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Fl=function(){return eBM(this),eDu(99)},eUe.Gl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Hl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Il=function(){return eBM(this),eDu(105)},eUe.Jl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Kl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Ll=function(e,t){return ePR(e,eDu(t)),-1},eUe.Ml=function(){return eBM(this),eBG(),eBG(),++tyv,new jb(0,94)},eUe.Nl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Ol=function(){return eBM(this),eBG(),eBG(),++tyv,new jb(0,36)},eUe.Pl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Ql=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Rl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Sl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Tl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Ul=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Vl=function(){var e;if(eBM(this),e=F5(ehT(this),0),7!=this.c)throw p7(new gX(eBJ((Mo(),eX1))));return eBM(this),e},eUe.Wl=function(){throw p7(new gX(eBJ((Mo(),eJm))))},eUe.Xl=function(e){return eBM(this),jS(e,(eBG(),eBG(),++tyv,new qa(3,e)))},eUe.Yl=function(e){var t;return eBM(this),t=(eBG(),eBG(),++tyv,new Mr(2)),eRv(t,e),eRv(t,tye),t},eUe.Zl=function(e){return eBM(this),eBG(),eBG(),++tyv,new qa(3,e)};var tva=null,tvo=null;Y5(e1l,"RegEx/ParserForXMLSchema",1824),eTS(117,1,e1k,pJ),eUe.$l=function(e){throw p7(new go("Not supported."))},eUe._l=function(){return -1},eUe.am=function(e){return null},eUe.bm=function(){return null},eUe.cm=function(e){},eUe.dm=function(e){},eUe.em=function(){return 0},eUe.Ib=function(){return this.fm(0)},eUe.fm=function(e){return 11==this.e?".":""},eUe.e=0;var tvs,tvu,tvc,tvl,tvf,tvd,tvh,tvp,tvb,tvm,tvg,tvv,tvy,tvw,tv_,tvE,tvS,tvk,tvx,tvT,tvM,tvO,tvA,tvL,tvC,tvI,tvD,tvN,tvP,tvR,tvj,tvF,tvY,tvB,tvU,tvH,tv$,tvz,tvG,tvW,tvK,tvV,tvq,tvZ,tvX,tvJ,tvQ,tv1,tv0,tv2,tv3,tv4,tv5,tv6,tv9,tv8,tv7,tye,tyt,tyn,tyr,tyi,tya,tyo,tys,tyu,tyc,tyl,tyf,tyd,tyh,typ,tyb=null,tym=null,tyg=null,tyv=0,tyy=Y5(e1l,"RegEx/Token",117);eTS(136,117,{3:1,136:1,117:1},WZ),eUe.fm=function(e){var t,n,r;if(4==this.e){if(this==tv7)n=".";else if(this==tv8)n="\\d";else if(this==tyd)n="\\w";else if(this==tys)n="\\s";else{for(r=new vs,r.a+="[",t=0;t0&&(r.a+=","),this.b[t]===this.b[t+1]?xk(r,eN$(this.b[t])):(xk(r,eN$(this.b[t])),r.a+="-",xk(r,eN$(this.b[t+1])));r.a+="]",n=r.a}}else if(this==tyr)n="\\D";else if(this==tya)n="\\W";else if(this==tyi)n="\\S";else{for(r=new vs,r.a+="[^",t=0;t0&&(r.a+=","),this.b[t]===this.b[t+1]?xk(r,eN$(this.b[t])):(xk(r,eN$(this.b[t])),r.a+="-",xk(r,eN$(this.b[t+1])));r.a+="]",n=r.a}return n},eUe.a=!1,eUe.c=!1,Y5(e1l,"RegEx/RangeToken",136),eTS(584,1,{584:1},pX),eUe.a=0,Y5(e1l,"RegEx/RegexParser/ReferencePosition",584),eTS(583,1,{3:1,583:1},wu),eUe.Fb=function(e){var t;return!!(null!=e&&M4(e,583))&&(t=Pp(e,583),IE(this.b,t.b)&&this.a==t.a)},eUe.Hb=function(){return ebA(this.b+"/"+eAN(this.a))},eUe.Ib=function(){return this.c.fm(this.a)},eUe.a=0,Y5(e1l,"RegEx/RegularExpression",583),eTS(223,117,e1k,jb),eUe._l=function(){return this.a},eUe.fm=function(e){var t,n,r;switch(this.e){case 0:switch(this.a){case 124:case 42:case 43:case 63:case 40:case 41:case 46:case 91:case 123:case 92:r="\\"+CB(this.a&eHd);break;case 12:r="\\f";break;case 10:r="\\n";break;case 13:r="\\r";break;case 9:r="\\t";break;case 27:r="\\e";break;default:r=this.a>=eH3?"\\v"+Az(n="0"+(t=this.a>>>0).toString(16),n.length-6,n.length):""+CB(this.a&eHd)}break;case 8:r=this==tyt||this==tyn?""+CB(this.a&eHd):"\\"+CB(this.a&eHd);break;default:r=null}return r},eUe.a=0,Y5(e1l,"RegEx/Token/CharToken",223),eTS(309,117,e1k,qa),eUe.am=function(e){return this.a},eUe.cm=function(e){this.b=e},eUe.dm=function(e){this.c=e},eUe.em=function(){return 1},eUe.fm=function(e){var t;if(3==this.e){if(this.c<0&&this.b<0)t=this.a.fm(e)+"*";else if(this.c==this.b)t=this.a.fm(e)+"{"+this.c+"}";else if(this.c>=0&&this.b>=0)t=this.a.fm(e)+"{"+this.c+","+this.b+"}";else if(this.c>=0&&this.b<0)t=this.a.fm(e)+"{"+this.c+",}";else throw p7(new go("Token#toString(): CLOSURE "+this.c+eUd+this.b))}else if(this.c<0&&this.b<0)t=this.a.fm(e)+"*?";else if(this.c==this.b)t=this.a.fm(e)+"{"+this.c+"}?";else if(this.c>=0&&this.b>=0)t=this.a.fm(e)+"{"+this.c+","+this.b+"}?";else if(this.c>=0&&this.b<0)t=this.a.fm(e)+"{"+this.c+",}?";else throw p7(new go("Token#toString(): NONGREEDYCLOSURE "+this.c+eUd+this.b));return t},eUe.b=0,eUe.c=0,Y5(e1l,"RegEx/Token/ClosureToken",309),eTS(821,117,e1k,YD),eUe.am=function(e){return 0==e?this.a:this.b},eUe.em=function(){return 2},eUe.fm=function(e){var t;return 3==this.b.e&&this.b.am(0)==this.a?this.a.fm(e)+"+":9==this.b.e&&this.b.am(0)==this.a?this.a.fm(e)+"+?":this.a.fm(e)+""+this.b.fm(e)},Y5(e1l,"RegEx/Token/ConcatToken",821),eTS(1822,117,e1k,ee_),eUe.am=function(e){if(0==e)return this.d;if(1==e)return this.b;throw p7(new go("Internal Error: "+e))},eUe.em=function(){return this.b?2:1},eUe.fm=function(e){var t;return t=this.c>0?"(?("+this.c+")":8==this.a.e?"(?("+this.a+")":"(?"+this.a,this.b?t+=this.d+"|"+this.b+")":t+=this.d+")",t},eUe.c=0,Y5(e1l,"RegEx/Token/ConditionToken",1822),eTS(1823,117,e1k,Wq),eUe.am=function(e){return this.b},eUe.em=function(){return 1},eUe.fm=function(e){return"(?"+(0==this.a?"":eAN(this.a))+(0==this.c?"":eAN(this.c))+":"+this.b.fm(e)+")"},eUe.a=0,eUe.c=0,Y5(e1l,"RegEx/Token/ModifierToken",1823),eTS(822,117,e1k,BR),eUe.am=function(e){return this.a},eUe.em=function(){return 1},eUe.fm=function(e){var t;switch(t=null,this.e){case 6:t=0==this.b?"(?:"+this.a.fm(e)+")":"("+this.a.fm(e)+")";break;case 20:t="(?="+this.a.fm(e)+")";break;case 21:t="(?!"+this.a.fm(e)+")";break;case 22:t="(?<="+this.a.fm(e)+")";break;case 23:t="(?"+this.a.fm(e)+")"}return t},eUe.b=0,Y5(e1l,"RegEx/Token/ParenToken",822),eTS(521,117,{3:1,117:1,521:1},zc),eUe.bm=function(){return this.b},eUe.fm=function(e){return 12==this.e?"\\"+this.a:eTd(this.b)},eUe.a=0,Y5(e1l,"RegEx/Token/StringToken",521),eTS(465,117,e1k,Mr),eUe.$l=function(e){eRv(this,e)},eUe.am=function(e){return Pp(Bz(this.a,e),117)},eUe.em=function(){return this.a?this.a.a.c.length:0},eUe.fm=function(e){var t,n,r,i,a;if(1==this.e){if(2==this.a.a.c.length)t=Pp(Bz(this.a,0),117),i=3==(n=Pp(Bz(this.a,1),117)).e&&n.am(0)==t?t.fm(e)+"+":9==n.e&&n.am(0)==t?t.fm(e)+"+?":t.fm(e)+""+n.fm(e);else{for(r=0,a=new vs;r=this.c.b:this.a<=this.c.b},eUe.Sb=function(){return this.b>0},eUe.Tb=function(){return this.b},eUe.Vb=function(){return this.b-1},eUe.Qb=function(){throw p7(new gW(e1L))},eUe.a=0,eUe.b=0,Y5(e1M,"ExclusiveRange/RangeIterator",254);var tyw=Ui(eJX,"C"),ty_=Ui(eJ1,"I"),tyE=Ui(eUi,"Z"),tyS=Ui(eJ0,"J"),tyk=Ui(eJZ,"B"),tyx=Ui(eJJ,"D"),tyT=Ui(eJQ,"F"),tyM=Ui(eJ2,"S"),tyO=RL("org.eclipse.elk.core.labels","ILabelManager"),tyA=RL(eX_,"DiagnosticChain"),tyL=RL(eQx,"ResourceSet"),tyC=Y5(eX_,"InvocationTargetException",null),tyI=(vg(),q6),tyD=tyD=eyP;enI(bs),eiE("permProps",[[[e1C,e1I],[e1D,"gecko1_8"]],[[e1C,e1I],[e1D,"ie10"]],[[e1C,e1I],[e1D,"ie8"]],[[e1C,e1I],[e1D,"ie9"]],[[e1C,e1I],[e1D,"safari"]]]),tyD(null,"elk",null)},3379(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return t&&("object"==typeof t||"function"==typeof t)?t:e}function a(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var o=function(e){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};r(this,t);var a=Object.assign({},e),o=!1;try{o=!0}catch(s){}if(e.workerUrl){if(o){var u=n(84763);a.workerFactory=function(e){return new u(e)}}else console.warn("Web worker requested but 'web-worker' package not installed. \nConsider installing the package or pass your own 'workerFactory' to ELK's constructor.\n... Falling back to non-web worker version.")}if(!a.workerFactory){var c=n(55273).Worker;a.workerFactory=function(e){return new c(e)}}return i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,a))}return a(t,e),t}(n(4005).default);Object.defineProperty(e.exports,"__esModule",{value:!0}),e.exports=o,o.default=o},17187(e){"use strict";var t,n="object"==typeof Reflect?Reflect:null,r=n&&"function"==typeof n.apply?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};function i(e){console&&console.warn&&console.warn(e)}t=n&&"function"==typeof n.ownKeys?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var a=Number.isNaN||function(e){return e!=e};function o(){o.init.call(this)}e.exports=o,e.exports.once=v,o.EventEmitter=o,o.prototype._events=void 0,o.prototype._eventsCount=0,o.prototype._maxListeners=void 0;var s=10;function u(e){if("function"!=typeof e)throw TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function c(e){return void 0===e._maxListeners?o.defaultMaxListeners:e._maxListeners}function l(e,t,n,r){if(u(n),void 0===(o=e._events)?(o=e._events=Object.create(null),e._eventsCount=0):(void 0!==o.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),o=e._events),s=o[t]),void 0===s)s=o[t]=n,++e._eventsCount;else if("function"==typeof s?s=o[t]=r?[n,s]:[s,n]:r?s.unshift(n):s.push(n),(a=c(e))>0&&s.length>a&&!s.warned){s.warned=!0;var a,o,s,l=Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");l.name="MaxListenersExceededWarning",l.emitter=e,l.type=t,l.count=s.length,i(l)}return e}function f(){if(!this.fired)return(this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length)?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function d(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=f.bind(r);return i.listener=n,r.wrapFn=i,i}function h(e,t,n){var r=e._events;if(void 0===r)return[];var i=r[t];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?g(i):b(i,i.length)}function p(e){var t=this._events;if(void 0!==t){var n=t[e];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function b(e,t){for(var n=Array(t),r=0;r0&&(o=t[0]),o instanceof Error)throw o;var o,s=Error("Unhandled error."+(o?" ("+o.message+")":""));throw s.context=o,s}var u=a[e];if(void 0===u)return!1;if("function"==typeof u)r(u,this,t);else for(var c=u.length,l=b(u,c),n=0;n=0;a--)if(n[a]===t||n[a].listener===t){o=n[a].listener,i=a;break}if(i<0)return this;0===i?n.shift():m(n,i),1===n.length&&(r[e]=n[0]),void 0!==r.removeListener&&this.emit("removeListener",e,o||t)}return this},o.prototype.off=o.prototype.removeListener,o.prototype.removeAllListeners=function(e){var t,n,r;if(void 0===(n=this._events))return this;if(void 0===n.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==n[e]&&(0==--this._eventsCount?this._events=Object.create(null):delete n[e]),this;if(0===arguments.length){var i,a=Object.keys(n);for(r=0;r=0;r--)this.removeListener(e,t[r]);return this},o.prototype.listeners=function(e){return h(this,e,!0)},o.prototype.rawListeners=function(e){return h(this,e,!1)},o.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):p.call(e,t)},o.prototype.listenerCount=p,o.prototype.eventNames=function(){return this._eventsCount>0?t(this._events):[]}},16839(e,t,n){var r=n(25323),i=n(31744),a=n(98361),o=n(4514);e.exports={graphlib:n(32478),read:r,readMany:i,write:a,version:o,type:"dot",buffer:!1}},11100(e,t,n){"use strict";var r=n(47755),i=n(32478).Graph;function a(e){var t="graph"!==e.type,n=!e.strict,a=[{node:{},edge:{}}],s=e.id,u=new i({directed:t,multigraph:n,compound:!0});return u.setGraph(null===s?{}:{id:s}),r.each(e.stmts,function(e){o(u,e,a)}),u}function o(e,t,n,r){switch(t.type){case"node":s(e,t,n,r);break;case"edge":u(e,t,n,r);break;case"subgraph":c(e,t,n,r);break;case"attr":l(e,t,n);break;case"inlineAttr":f(e,t,n,r)}}function s(e,t,n,i){var a=t.id,o=t.attrs;h(e,a,n,i),r.merge(e.node(a),o)}function u(e,t,n,i){var a,s,u=t.attrs;r.each(t.elems,function(t){switch(o(e,t,n,i),t.type){case"node":s=[t.id];break;case"subgraph":s=p(t)}r.each(a,function(t){r.each(s,function(i){var a;e.hasEdge(t,i)&&e.isMultigraph()&&(a=r.uniqueId("edge")),e.hasEdge(t,i,a)||e.setEdge(t,i,r.clone(r.last(n).edge),a),r.merge(e.edge(t,i,a),u)})}),a=s})}function c(e,t,n,i){var a=t.id;void 0===a&&(a=d(e)),n.push(r.clone(r.last(n))),h(e,a,n,i),r.each(t.stmts,function(t){o(e,t,n,a)}),e.children(a).length||e.removeNode(a),n.pop()}function l(e,t,n){r.merge(r.last(n)[t.attrType],t.attrs)}function f(e,t,n,i){r.merge(i?e.node(i):e.graph(),t.attrs)}function d(e){var t;do t=r.uniqueId("sg");while(e.hasNode(t))return t}function h(e,t,n,i){e.hasNode(t)||(e.setNode(t,r.clone(r.last(n).node)),e.setParent(t,i))}function p(e){var t,n={},i=[],a=i.push.bind(i);for(a(e);i.length;)switch((t=i.pop()).type){case"node":n[t.id]=!0;break;case"edge":r.each(t.elems,a);break;case"subgraph":r.each(t.stmts,a)}return r.keys(n)}e.exports=a},4644(e,t,n){e.exports=function(){function e(e,t){function n(){this.constructor=e}n.prototype=t.prototype,e.prototype=new n}function t(e,t,n,r,i,a){this.message=e,this.expected=t,this.found=n,this.offset=r,this.line=i,this.column=a,this.name="SyntaxError"}function r(e){var r,i,a=arguments.length>1?arguments[1]:{},o={},s={start:tf,graphStmt:td},u=tf,c=o,l=null,f="{",d={type:"literal",value:"{",description:'"{"'},h="}",p={type:"literal",value:"}",description:'"}"'},b=function(e,t,n,r){return{type:t,id:n,strict:null!==e,stmts:r}},m=";",g={type:"literal",value:";",description:'";"'},v=function(e,t){for(var n=[e],r=0;r",description:'"->"'},U=function(e,t){var n=[e];if(t)for(var r=0;rt&&(tr=0,ti={line:1,column:1,seenCR:!1}),n(ti,tr,t),tr=t),ti}function tc(e){!(ttta&&(ta=tt,to=[]),to.push(e))}function tl(n,r,i){function a(e){var t=1;for(e.sort(function(e,t){return e.descriptiont.description?1:0});t1?o.slice(0,-1).join(", ")+" or "+o[e.length-1]:o[0])+" but "+(i=t?'"'+n(t)+'"':"end of input")+" found."}var s=tu(i),u=itt?(s=e.charAt(tt),tt++):(s=o,0===ts&&tc(te)),s!==o?i=a=[a,s]:(tt=i,i=c)):(tt=i,i=c);i!==o;)r.push(i),i=tt,a=tt,ts++,e.substr(tt,2)===e8?(s=e8,tt+=2):(s=o,0===ts&&tc(e7)),ts--,s===o?a=F:(tt=a,a=c),a!==o?(e.length>tt?(s=e.charAt(tt),tt++):(s=o,0===ts&&tc(te)),s!==o?i=a=[a,s]:(tt=i,i=c)):(tt=i,i=c);r!==o?(e.substr(tt,2)===e8?(i=e8,tt+=2):(i=o,0===ts&&tc(e7)),i!==o?t=n=[n,r,i]:(tt=t,t=c)):(tt=t,t=c)}else tt=t,t=c}return ts--,t===o&&(n=o,0===ts&&tc(e0)),t}function tY(){var e;return(e=tj())===o&&(e=tF()),e}var tB=n(47755);if((i=u())!==o&&tt===e.length)return i;throw i!==o&&tt":"--",n=new f;e.isMultigraph()||n.write("strict "),n.writeLine((e.isDirected()?"digraph":"graph")+" {"),n.indent();var i=e.graph();return r.isObject(i)&&r.each(i,function(e,t){n.writeLine(l(t)+"="+l(e)+";")}),o(e,void 0,n),e.edges().forEach(function(r){u(e,r,t,n)}),n.unindent(),n.writeLine("}"),n.toString()}function o(e,t,n){var i=e.isCompound()?e.children(t):e.nodes();r.each(i,function(t){e.isCompound()&&e.children(t).length?(n.writeLine("subgraph "+l(t)+" {"),n.indent(),r.isObject(e.node(t))&&r.map(e.node(t),function(e,t){n.writeLine(l(t)+"="+l(e)+";")}),o(e,t,n),n.unindent(),n.writeLine("}")):s(e,t,n)})}function s(e,t,n){n.write(l(t)),c(e.node(t),n),n.writeLine()}function u(e,t,n,r){var i=t.v,a=t.w,o=e.edge(t);r.write(l(i)+" "+n+" "+l(a)),c(o,r),r.writeLine()}function c(e,t){if(r.isObject(e)){var n=r.map(e,function(e,t){return l(t)+"="+l(e)});n.length&&t.write(" ["+n.join(",")+"]")}}function l(e){return"number"==typeof e||e.toString().match(i)?e:'"'+e.toString().replace(/"/g,'\\"')+'"'}function f(){this._indent="",this._content="",this._shouldIndent=!0}f.prototype.INDENT=" ",f.prototype.indent=function(){this._indent+=this.INDENT},f.prototype.unindent=function(){this._indent=this._indent.slice(this.INDENT.length)},f.prototype.writeLine=function(e){this.write((e||"")+"\n"),this._shouldIndent=!0},f.prototype.write=function(e){this._shouldIndent&&(this._shouldIndent=!1,this._content+=this._indent),this._content+=e},f.prototype.toString=function(){return this._content}},28282(e,t,n){var r=n(82354);e.exports={Graph:r.Graph,json:n(28974),alg:n(12440),version:r.version}},2842(e,t,n){var r=n(89126);function i(e){var t,n={},i=[];function a(i){r.has(n,i)||(n[i]=!0,t.push(i),r.each(e.successors(i),a),r.each(e.predecessors(i),a))}return r.each(e.nodes(),function(e){t=[],a(e),t.length&&i.push(t)}),i}e.exports=i},53984(e,t,n){var r=n(89126);function i(e,t,n){r.isArray(t)||(t=[t]);var i=(e.isDirected()?e.successors:e.neighbors).bind(e),o=[],s={};return r.each(t,function(t){if(!e.hasNode(t))throw Error("Graph does not have node: "+t);a(e,t,"post"===n,s,i,o)}),o}function a(e,t,n,i,o,s){!r.has(i,t)&&(i[t]=!0,n||s.push(t),r.each(o(t),function(t){a(e,t,n,i,o,s)}),n&&s.push(t))}e.exports=i},84847(e,t,n){var r=n(63763),i=n(89126);function a(e,t,n){return i.transform(e.nodes(),function(i,a){i[a]=r(e,a,t,n)},{})}e.exports=a},63763(e,t,n){var r=n(89126),i=n(75639);e.exports=o;var a=r.constant(1);function o(e,t,n,r){return s(e,String(t),n||a,r||function(t){return e.outEdges(t)})}function s(e,t,n,r){var a,o,s={},u=new i,c=function(e){var t=e.v!==a?e.v:e.w,r=s[t],i=n(e),c=o.distance+i;if(i<0)throw Error("dijkstra does not allow negative edge weights. Bad edge: "+e+" Weight: "+i);c0&&(o=s[a=u.removeMin()]).distance!==Number.POSITIVE_INFINITY;)r(a).forEach(c);return s}},9096(e,t,n){var r=n(89126),i=n(5023);function a(e){return r.filter(i(e),function(t){return t.length>1||1===t.length&&e.hasEdge(t[0],t[0])})}e.exports=a},38924(e,t,n){var r=n(89126);e.exports=a;var i=r.constant(1);function a(e,t,n){return o(e,t||i,n||function(t){return e.outEdges(t)})}function o(e,t,n){var r={},i=e.nodes();return i.forEach(function(e){r[e]={},r[e][e]={distance:0},i.forEach(function(t){e!==t&&(r[e][t]={distance:Number.POSITIVE_INFINITY})}),n(e).forEach(function(n){var i=n.v===e?n.w:n.v,a=t(n);r[e][i]={distance:a,predecessor:e}})}),i.forEach(function(e){var t=r[e];i.forEach(function(n){var a=r[n];i.forEach(function(n){var r=a[e],i=t[n],o=a[n],s=r.distance+i.distance;s0;){if(n=u.removeMin(),r.has(s,n))o.setEdge(n,s[n]);else if(l)throw Error("Input graph is not connected: "+e);else l=!0;e.nodeEdges(n).forEach(c)}return o}e.exports=o},5023(e,t,n){var r=n(89126);function i(e){var t=0,n=[],i={},a=[];function o(s){var u=i[s]={onStack:!0,lowlink:t,index:t++};if(n.push(s),e.successors(s).forEach(function(e){r.has(i,e)?i[e].onStack&&(u.lowlink=Math.min(u.lowlink,i[e].index)):(o(e),u.lowlink=Math.min(u.lowlink,i[e].lowlink))}),u.lowlink===u.index){var c,l=[];do i[c=n.pop()].onStack=!1,l.push(c);while(s!==c)a.push(l)}}return e.nodes().forEach(function(e){r.has(i,e)||o(e)}),a}e.exports=i},2166(e,t,n){var r=n(89126);function i(e){var t={},n={},i=[];function o(s){if(r.has(n,s))throw new a;r.has(t,s)||(n[s]=!0,t[s]=!0,r.each(e.predecessors(s),o),delete n[s],i.push(s))}if(r.each(e.sinks(),o),r.size(t)!==e.nodeCount())throw new a;return i}function a(){}e.exports=i,i.CycleException=a,a.prototype=Error()},75639(e,t,n){var r=n(89126);function i(){this._arr=[],this._keyIndices={}}e.exports=i,i.prototype.size=function(){return this._arr.length},i.prototype.keys=function(){return this._arr.map(function(e){return e.key})},i.prototype.has=function(e){return r.has(this._keyIndices,e)},i.prototype.priority=function(e){var t=this._keyIndices[e];if(void 0!==t)return this._arr[t].priority},i.prototype.min=function(){if(0===this.size())throw Error("Queue underflow");return this._arr[0].key},i.prototype.add=function(e,t){var n=this._keyIndices;if(e=String(e),!r.has(n,e)){var i=this._arr,a=i.length;return n[e]=a,i.push({key:e,priority:t}),this._decrease(a),!0}return!1},i.prototype.removeMin=function(){this._swap(0,this._arr.length-1);var e=this._arr.pop();return delete this._keyIndices[e.key],this._heapify(0),e.key},i.prototype.decrease=function(e,t){var n=this._keyIndices[e];if(t>this._arr[n].priority)throw Error("New priority is greater than current priority. Key: "+e+" Old: "+this._arr[n].priority+" New: "+t);this._arr[n].priority=t,this._decrease(n)},i.prototype._heapify=function(e){var t=this._arr,n=2*e,r=n+1,i=e;n>1].priorityu){var c=s;s=u,u=c}return s+o+u+o+(r.isUndefined(a)?i:a)}function f(e,t,n,r){var i=""+t,a=""+n;if(!e&&i>a){var o=i;i=a,a=o}var s={v:i,w:a};return r&&(s.name=r),s}function d(e,t){return l(e,t.v,t.w,t.name)}s.prototype._nodeCount=0,s.prototype._edgeCount=0,s.prototype.isDirected=function(){return this._isDirected},s.prototype.isMultigraph=function(){return this._isMultigraph},s.prototype.isCompound=function(){return this._isCompound},s.prototype.setGraph=function(e){return this._label=e,this},s.prototype.graph=function(){return this._label},s.prototype.setDefaultNodeLabel=function(e){return r.isFunction(e)||(e=r.constant(e)),this._defaultNodeLabelFn=e,this},s.prototype.nodeCount=function(){return this._nodeCount},s.prototype.nodes=function(){return r.keys(this._nodes)},s.prototype.sources=function(){var e=this;return r.filter(this.nodes(),function(t){return r.isEmpty(e._in[t])})},s.prototype.sinks=function(){var e=this;return r.filter(this.nodes(),function(t){return r.isEmpty(e._out[t])})},s.prototype.setNodes=function(e,t){var n=arguments,i=this;return r.each(e,function(e){n.length>1?i.setNode(e,t):i.setNode(e)}),this},s.prototype.setNode=function(e,t){return r.has(this._nodes,e)?(arguments.length>1&&(this._nodes[e]=t),this):(this._nodes[e]=arguments.length>1?t:this._defaultNodeLabelFn(e),this._isCompound&&(this._parent[e]=a,this._children[e]={},this._children[a][e]=!0),this._in[e]={},this._preds[e]={},this._out[e]={},this._sucs[e]={},++this._nodeCount,this)},s.prototype.node=function(e){return this._nodes[e]},s.prototype.hasNode=function(e){return r.has(this._nodes,e)},s.prototype.removeNode=function(e){var t=this;if(r.has(this._nodes,e)){var n=function(e){t.removeEdge(t._edgeObjs[e])};delete this._nodes[e],this._isCompound&&(this._removeFromParentsChildList(e),delete this._parent[e],r.each(this.children(e),function(e){t.setParent(e)}),delete this._children[e]),r.each(r.keys(this._in[e]),n),delete this._in[e],delete this._preds[e],r.each(r.keys(this._out[e]),n),delete this._out[e],delete this._sucs[e],--this._nodeCount}return this},s.prototype.setParent=function(e,t){if(!this._isCompound)throw Error("Cannot set parent in a non-compound graph");if(r.isUndefined(t))t=a;else{t+="";for(var n=t;!r.isUndefined(n);n=this.parent(n))if(n===e)throw Error("Setting "+t+" as parent of "+e+" would create a cycle");this.setNode(t)}return this.setNode(e),this._removeFromParentsChildList(e),this._parent[e]=t,this._children[t][e]=!0,this},s.prototype._removeFromParentsChildList=function(e){delete this._children[this._parent[e]][e]},s.prototype.parent=function(e){if(this._isCompound){var t=this._parent[e];if(t!==a)return t}},s.prototype.children=function(e){if(r.isUndefined(e)&&(e=a),this._isCompound){var t=this._children[e];if(t)return r.keys(t)}else if(e===a)return this.nodes();else if(this.hasNode(e))return[]},s.prototype.predecessors=function(e){var t=this._preds[e];if(t)return r.keys(t)},s.prototype.successors=function(e){var t=this._sucs[e];if(t)return r.keys(t)},s.prototype.neighbors=function(e){var t=this.predecessors(e);if(t)return r.union(t,this.successors(e))},s.prototype.isLeaf=function(e){var t;return 0===(t=this.isDirected()?this.successors(e):this.neighbors(e)).length},s.prototype.filterNodes=function(e){var t=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});t.setGraph(this.graph());var n=this;r.each(this._nodes,function(n,r){e(r)&&t.setNode(r,n)}),r.each(this._edgeObjs,function(e){t.hasNode(e.v)&&t.hasNode(e.w)&&t.setEdge(e,n.edge(e))});var i={};function a(e){var r=n.parent(e);return void 0===r||t.hasNode(r)?(i[e]=r,r):r in i?i[r]:a(r)}return this._isCompound&&r.each(t.nodes(),function(e){t.setParent(e,a(e))}),t},s.prototype.setDefaultEdgeLabel=function(e){return r.isFunction(e)||(e=r.constant(e)),this._defaultEdgeLabelFn=e,this},s.prototype.edgeCount=function(){return this._edgeCount},s.prototype.edges=function(){return r.values(this._edgeObjs)},s.prototype.setPath=function(e,t){var n=this,i=arguments;return r.reduce(e,function(e,r){return i.length>1?n.setEdge(e,r,t):n.setEdge(e,r),r}),this},s.prototype.setEdge=function(){var e,t,n,i,a=!1,o=arguments[0];"object"==typeof o&&null!==o&&"v"in o?(e=o.v,t=o.w,n=o.name,2===arguments.length&&(i=arguments[1],a=!0)):(e=o,t=arguments[1],n=arguments[3],arguments.length>2&&(i=arguments[2],a=!0)),e=""+e,t=""+t,r.isUndefined(n)||(n=""+n);var s=l(this._isDirected,e,t,n);if(r.has(this._edgeLabels,s))return a&&(this._edgeLabels[s]=i),this;if(!r.isUndefined(n)&&!this._isMultigraph)throw Error("Cannot set a named edge when isMultigraph = false");this.setNode(e),this.setNode(t),this._edgeLabels[s]=a?i:this._defaultEdgeLabelFn(e,t,n);var c=f(this._isDirected,e,t,n);return e=c.v,t=c.w,Object.freeze(c),this._edgeObjs[s]=c,u(this._preds[t],e),u(this._sucs[e],t),this._in[t][s]=c,this._out[e][s]=c,this._edgeCount++,this},s.prototype.edge=function(e,t,n){var r=1===arguments.length?d(this._isDirected,arguments[0]):l(this._isDirected,e,t,n);return this._edgeLabels[r]},s.prototype.hasEdge=function(e,t,n){var i=1===arguments.length?d(this._isDirected,arguments[0]):l(this._isDirected,e,t,n);return r.has(this._edgeLabels,i)},s.prototype.removeEdge=function(e,t,n){var r=1===arguments.length?d(this._isDirected,arguments[0]):l(this._isDirected,e,t,n),i=this._edgeObjs[r];return i&&(e=i.v,t=i.w,delete this._edgeLabels[r],delete this._edgeObjs[r],c(this._preds[t],e),c(this._sucs[e],t),delete this._in[t][r],delete this._out[e][r],this._edgeCount--),this},s.prototype.inEdges=function(e,t){var n=this._in[e];if(n){var i=r.values(n);return t?r.filter(i,function(e){return e.v===t}):i}},s.prototype.outEdges=function(e,t){var n=this._out[e];if(n){var i=r.values(n);return t?r.filter(i,function(e){return e.w===t}):i}},s.prototype.nodeEdges=function(e,t){var n=this.inEdges(e,t);if(n)return n.concat(this.outEdges(e,t))}},82354(e,t,n){e.exports={Graph:n(30771),version:n(49631)}},28974(e,t,n){var r=n(89126),i=n(30771);function a(e){var t={options:{directed:e.isDirected(),multigraph:e.isMultigraph(),compound:e.isCompound()},nodes:o(e),edges:s(e)};return r.isUndefined(e.graph())||(t.value=r.clone(e.graph())),t}function o(e){return r.map(e.nodes(),function(t){var n=e.node(t),i=e.parent(t),a={v:t};return r.isUndefined(n)||(a.value=n),r.isUndefined(i)||(a.parent=i),a})}function s(e){return r.map(e.edges(),function(t){var n=e.edge(t),i={v:t.v,w:t.w};return r.isUndefined(t.name)||(i.name=t.name),r.isUndefined(n)||(i.value=n),i})}function u(e){var t=new i(e.options).setGraph(e.value);return r.each(e.nodes,function(e){t.setNode(e.v,e.value),e.parent&&t.setParent(e.v,e.parent)}),r.each(e.edges,function(e){t.setEdge({v:e.v,w:e.w,name:e.name},e.value)}),t}e.exports={write:a,read:u}},89126(e,t,n){var r;try{r={clone:n(66678),constant:n(75703),each:n(66073),filter:n(63105),has:n(18721),isArray:n(1469),isEmpty:n(41609),isFunction:n(23560),isUndefined:n(52353),keys:n(3674),map:n(35161),reduce:n(54061),size:n(84238),transform:n(68718),union:n(93386),values:n(52628)}}catch(i){}r||(r=window._),e.exports=r},49631(e){e.exports="2.1.8"},78892(e){"use strict";e.exports=n;var t=/[#.]/g;function n(e,n){for(var r,i,a,o=e||"",s=n||"div",u={},c=0;cC,q_:()=>F,ob:()=>y,PP:()=>B,Ep:()=>v,Hp:()=>w});var r=n(87462);function i(e){return"/"===e.charAt(0)}function a(e,t){for(var n=t,r=n+1,i=e.length;r=0;d--){var h=o[d];"."===h?a(o,d):".."===h?(a(o,d),f++):f&&(a(o,d),f--)}if(!c)for(;f--;f)o.unshift("..");!c||""===o[0]||o[0]&&i(o[0])||o.unshift("");var p=o.join("/");return n&&"/"!==p.substr(-1)&&(p+="/"),p}let s=o;function u(e){return e.valueOf?e.valueOf():Object.prototype.valueOf.call(e)}function c(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if(Array.isArray(e))return Array.isArray(t)&&e.length===t.length&&e.every(function(e,n){return c(e,t[n])});if("object"==typeof e||"object"==typeof t){var n=u(e),r=u(t);return n!==e||r!==t?c(n,r):Object.keys(Object.assign({},e,t)).every(function(n){return c(e[n],t[n])})}return!1}let l=c;var f=n(2177);function d(e){return"/"===e.charAt(0)?e:"/"+e}function h(e){return"/"===e.charAt(0)?e.substr(1):e}function p(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}function b(e,t){return p(e,t)?e.substr(t.length):e}function m(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function g(e){var t=e||"/",n="",r="",i=t.indexOf("#");-1!==i&&(r=t.substr(i),t=t.substr(0,i));var a=t.indexOf("?");return -1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}function v(e){var t=e.pathname,n=e.search,r=e.hash,i=t||"/";return n&&"?"!==n&&(i+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(i+="#"===r.charAt(0)?r:"#"+r),i}function y(e,t,n,i){var a;"string"==typeof e?(a=g(e)).state=t:(void 0===(a=(0,r.Z)({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(o){if(o instanceof URIError)throw URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.');throw o}return n&&(a.key=n),i?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=s(a.pathname,i.pathname)):a.pathname=i.pathname:a.pathname||(a.pathname="/"),a}function w(e,t){return e.pathname===t.pathname&&e.search===t.search&&e.hash===t.hash&&e.key===t.key&&l(e.state,t.state)}function _(){var e=null;function t(t){return e=t,function(){e===t&&(e=null)}}function n(t,n,r,i){if(null!=e){var a="function"==typeof e?e(t,n):e;"string"==typeof a?"function"==typeof r?r(a,i):i(!0):i(!1!==a)}else i(!0)}var r=[];function i(e){var t=!0;function n(){t&&e.apply(void 0,arguments)}return r.push(n),function(){t=!1,r=r.filter(function(e){return e!==n})}}function a(){for(var e=arguments.length,t=Array(e),n=0;nn?a.splice(n,a.length-n,i):a.push(i),f({action:r,location:i,index:n,entries:a})}})}function g(e,t){var r="REPLACE",i=y(e,t,d(),M.location);l.confirmTransitionTo(i,r,n,function(e){e&&(M.entries[M.index]=i,f({action:r,location:i}))})}function w(e){var t=Y(M.index+e,0,M.entries.length-1),r="POP",i=M.entries[t];l.confirmTransitionTo(i,r,n,function(e){e?f({action:r,location:i,index:t}):f()})}function E(){w(-1)}function S(){w(1)}function k(e){var t=M.index+e;return t>=0&&tu});var r=/[A-Z]/g,i=/^ms-/,a={};function o(e){return"-"+e.toLowerCase()}function s(e){if(a.hasOwnProperty(e))return a[e];var t=e.replace(r,o);return a[e]=i.test(t)?"-"+t:t}let u=s},80645(e,t){/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ t.read=function(e,t,n,r,i){var a,o,s=8*i-r-1,u=(1<>1,l=-7,f=n?i-1:0,d=n?-1:1,h=e[t+f];for(f+=d,a=h&(1<<-l)-1,h>>=-l,l+=s;l>0;a=256*a+e[t+f],f+=d,l-=8);for(o=a&(1<<-l)-1,a>>=-l,l+=r;l>0;o=256*o+e[t+f],f+=d,l-=8);if(0===a)a=1-c;else{if(a===u)return o?NaN:(h?-1:1)*(1/0);o+=Math.pow(2,r),a-=c}return(h?-1:1)*o*Math.pow(2,a-r)},t.write=function(e,t,n,r,i,a){var o,s,u,c=8*a-i-1,l=(1<>1,d=23===i?5960464477539062e-23:0,h=r?0:a-1,p=r?1:-1,b=t<0||0===t&&1/t<0?1:0;for(isNaN(t=Math.abs(t))||t===1/0?(s=isNaN(t)?1:0,o=l):(o=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-o))<1&&(o--,u*=2),o+f>=1?t+=d/u:t+=d*Math.pow(2,1-f),t*u>=2&&(o++,u/=2),o+f>=l?(s=0,o=l):o+f>=1?(s=(t*u-1)*Math.pow(2,i),o+=f):(s=t*Math.pow(2,f-1)*Math.pow(2,i),o=0));i>=8;e[n+h]=255&s,h+=p,s/=256,i-=8);for(o=o<0;e[n+h]=255&o,h+=p,o/=256,c-=8);e[n+h-p]|=128*b}},35717(e){"function"==typeof Object.create?e.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}},46260(e){"use strict";function t(e){var t="string"==typeof e?e.charCodeAt(0):e;return t>=97&&t<=122||t>=65&&t<=90}e.exports=t},7961(e,t,n){"use strict";var r=n(46260),i=n(46195);function a(e){return r(e)||i(e)}e.exports=a},46195(e){"use strict";function t(e){var t="string"==typeof e?e.charCodeAt(0):e;return t>=48&&t<=57}e.exports=t},79480(e){"use strict";function t(e){var t="string"==typeof e?e.charCodeAt(0):e;return t>=97&&t<=102||t>=65&&t<=70||t>=48&&t<=57}e.exports=t},33827(e,t,n){"use strict";n.r(t),n.d(t,{default:()=>a,isBrowser:()=>i});var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i=("undefined"==typeof window?"undefined":r(window))==="object"&&("undefined"==typeof document?"undefined":r(document))==="object"&&9===document.nodeType;let a=i},5826(e){e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},47798(e){"use strict";/*! + * isobject + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ e.exports=function(e){return null!=e&&"object"==typeof e&&!1===Array.isArray(e)}},80204(e,t,n){e.exports=self.fetch||(self.fetch=n(25869).default||n(25869))},5690(e,t,n){e.exports=n(67946)},8126(e,t,n){"use strict";n.d(t,{Z:()=>tl});var r,i="en",a={},o={};function s(){return i}function u(e){i=e}function c(e){return a[e]}function l(e){if(!e)throw Error("No locale data passed");a[e.locale]=e,o[e.locale.toLowerCase()]=e.locale}function f(e){return a[e]?e:o[e.toLowerCase()]?o[e.toLowerCase()]:void 0}function d(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.localeMatcher||"lookup";switch(n){case"lookup":case"best fit":return h(e);default:throw RangeError('Invalid "localeMatcher" option: '.concat(n))}}function h(e){var t=f(e);if(t)return t;for(var n=e.split("-");e.length>1;){n.pop();var r=f(e=n.join("-"));if(r)return r}}var p={af:function(e){return 1==e?"one":"other"},am:function(e){return e>=0&&e<=1?"one":"other"},ar:function(e){var t=String(e).split("."),n=Number(t[0])==e&&t[0].slice(-2);return 0==e?"zero":1==e?"one":2==e?"two":n>=3&&n<=10?"few":n>=11&&n<=99?"many":"other"},ast:function(e){var t=!String(e).split(".")[1];return 1==e&&t?"one":"other"},be:function(e){var t=String(e).split("."),n=Number(t[0])==e,r=n&&t[0].slice(-1),i=n&&t[0].slice(-2);return 1==r&&11!=i?"one":r>=2&&r<=4&&(i<12||i>14)?"few":n&&0==r||r>=5&&r<=9||i>=11&&i<=14?"many":"other"},br:function(e){var t=String(e).split("."),n=Number(t[0])==e,r=n&&t[0].slice(-1),i=n&&t[0].slice(-2),a=n&&t[0].slice(-6);return 1==r&&11!=i&&71!=i&&91!=i?"one":2==r&&12!=i&&72!=i&&92!=i?"two":(3==r||4==r||9==r)&&(i<10||i>19)&&(i<70||i>79)&&(i<90||i>99)?"few":0!=e&&n&&0==a?"many":"other"},bs:function(e){var t=String(e).split("."),n=t[0],r=t[1]||"",i=!t[1],a=n.slice(-1),o=n.slice(-2),s=r.slice(-1),u=r.slice(-2);return i&&1==a&&11!=o||1==s&&11!=u?"one":i&&a>=2&&a<=4&&(o<12||o>14)||s>=2&&s<=4&&(u<12||u>14)?"few":"other"},cs:function(e){var t=String(e).split("."),n=t[0],r=!t[1];return 1==e&&r?"one":n>=2&&n<=4&&r?"few":r?"other":"many"},cy:function(e){return 0==e?"zero":1==e?"one":2==e?"two":3==e?"few":6==e?"many":"other"},da:function(e){var t=String(e).split("."),n=t[0],r=Number(t[0])==e;return 1!=e&&(r||0!=n&&1!=n)?"other":"one"},dsb:function(e){var t=String(e).split("."),n=t[0],r=t[1]||"",i=!t[1],a=n.slice(-2),o=r.slice(-2);return i&&1==a||1==o?"one":i&&2==a||2==o?"two":i&&(3==a||4==a)||3==o||4==o?"few":"other"},dz:function(e){return"other"},fil:function(e){var t=String(e).split("."),n=t[0],r=t[1]||"",i=!t[1],a=n.slice(-1),o=r.slice(-1);return i&&(1==n||2==n||3==n)||i&&4!=a&&6!=a&&9!=a||!i&&4!=o&&6!=o&&9!=o?"one":"other"},fr:function(e){return e>=0&&e<2?"one":"other"},ga:function(e){var t=Number(String(e).split(".")[0])==e;return 1==e?"one":2==e?"two":t&&e>=3&&e<=6?"few":t&&e>=7&&e<=10?"many":"other"},gd:function(e){var t=Number(String(e).split(".")[0])==e;return 1==e||11==e?"one":2==e||12==e?"two":t&&e>=3&&e<=10||t&&e>=13&&e<=19?"few":"other"},he:function(e){var t=String(e).split("."),n=t[0],r=!t[1],i=Number(t[0])==e,a=i&&t[0].slice(-1);return 1==e&&r?"one":2==n&&r?"two":r&&(e<0||e>10)&&i&&0==a?"many":"other"},is:function(e){var t=String(e).split("."),n=t[0],r=Number(t[0])==e,i=n.slice(-1),a=n.slice(-2);return r&&1==i&&11!=a||!r?"one":"other"},ksh:function(e){return 0==e?"zero":1==e?"one":"other"},lt:function(e){var t=String(e).split("."),n=t[1]||"",r=Number(t[0])==e,i=r&&t[0].slice(-1),a=r&&t[0].slice(-2);return 1==i&&(a<11||a>19)?"one":i>=2&&i<=9&&(a<11||a>19)?"few":0!=n?"many":"other"},lv:function(e){var t=String(e).split("."),n=t[1]||"",r=n.length,i=Number(t[0])==e,a=i&&t[0].slice(-1),o=i&&t[0].slice(-2),s=n.slice(-2),u=n.slice(-1);return i&&0==a||o>=11&&o<=19||2==r&&s>=11&&s<=19?"zero":1==a&&11!=o||2==r&&1==u&&11!=s||2!=r&&1==u?"one":"other"},mk:function(e){var t=String(e).split("."),n=t[0],r=t[1]||"",i=!t[1],a=n.slice(-1),o=n.slice(-2),s=r.slice(-1),u=r.slice(-2);return i&&1==a&&11!=o||1==s&&11!=u?"one":"other"},mt:function(e){var t=String(e).split("."),n=Number(t[0])==e&&t[0].slice(-2);return 1==e?"one":0==e||n>=2&&n<=10?"few":n>=11&&n<=19?"many":"other"},pa:function(e){return 0==e||1==e?"one":"other"},pl:function(e){var t=String(e).split("."),n=t[0],r=!t[1],i=n.slice(-1),a=n.slice(-2);return 1==e&&r?"one":r&&i>=2&&i<=4&&(a<12||a>14)?"few":r&&1!=n&&(0==i||1==i)||r&&i>=5&&i<=9||r&&a>=12&&a<=14?"many":"other"},pt:function(e){var t=String(e).split(".")[0];return 0==t||1==t?"one":"other"},ro:function(e){var t=String(e).split("."),n=!t[1],r=Number(t[0])==e&&t[0].slice(-2);return 1==e&&n?"one":!n||0==e||1!=e&&r>=1&&r<=19?"few":"other"},ru:function(e){var t=String(e).split("."),n=t[0],r=!t[1],i=n.slice(-1),a=n.slice(-2);return r&&1==i&&11!=a?"one":r&&i>=2&&i<=4&&(a<12||a>14)?"few":r&&0==i||r&&i>=5&&i<=9||r&&a>=11&&a<=14?"many":"other"},se:function(e){return 1==e?"one":2==e?"two":"other"},si:function(e){var t=String(e).split("."),n=t[0],r=t[1]||"";return 0==e||1==e||0==n&&1==r?"one":"other"},sl:function(e){var t=String(e).split("."),n=t[0],r=!t[1],i=n.slice(-2);return r&&1==i?"one":r&&2==i?"two":r&&(3==i||4==i)||!r?"few":"other"}};p.as=p.am,p.az=p.af,p.bg=p.af,p.bn=p.am,p.ca=p.ast,p.ce=p.af,p.chr=p.af,p.de=p.ast,p.ee=p.af,p.el=p.af,p.en=p.ast,p.es=p.af,p.et=p.ast,p.eu=p.af,p.fa=p.am,p.fi=p.ast,p.fo=p.af,p.fur=p.af,p.fy=p.ast,p.gl=p.ast,p.gu=p.am,p.hi=p.am,p.hr=p.bs,p.hsb=p.dsb,p.hu=p.af,p.hy=p.fr,p.ia=p.ast,p.id=p.dz,p.it=p.ast,p.ja=p.dz,p.jgo=p.af,p.jv=p.dz,p.ka=p.af,p.kea=p.dz,p.kk=p.af,p.kl=p.af,p.km=p.dz,p.kn=p.am,p.ko=p.dz,p.ku=p.af,p.ky=p.af,p.lb=p.af,p.lkt=p.dz,p.lo=p.dz,p.ml=p.af,p.mn=p.af,p.mr=p.am,p.ms=p.dz,p.my=p.dz,p.nb=p.af,p.ne=p.af,p.nl=p.ast,p.nn=p.af,p.or=p.af,p.ps=p.af,p["pt-PT"]=p.ast,p.sah=p.dz,p.sd=p.af,p.sk=p.cs,p.so=p.af,p.sq=p.af,p.sr=p.bs,p.sv=p.ast,p.sw=p.ast,p.ta=p.af,p.te=p.af,p.th=p.dz,p.ti=p.pa,p.tk=p.af,p.to=p.dz,p.tr=p.af,p.ug=p.af,p.uk=p.ru,p.ur=p.ast,p.uz=p.af,p.vi=p.dz,p.wae=p.af,p.yi=p.ast,p.yue=p.dz,p.zh=p.dz,p.zu=p.am;let b=p;function m(e){return"pt-PT"===e?e:v(e)}var g=/^([a-z0-9]+)/i;function v(e){var t=e.match(g);if(!t)throw TypeError("Invalid locale: ".concat(e));return t[1]}function y(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function w(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};A(this,e),I(this,"numeric","always"),I(this,"style","long"),I(this,"localeMatcher","lookup");var r=n.numeric,i=n.style,a=n.localeMatcher;if(void 0!==r){if(0>N.indexOf(r))throw RangeError('Invalid "numeric" option: '.concat(r));this.numeric=r}if(void 0!==i){if(0>P.indexOf(i))throw RangeError('Invalid "style" option: '.concat(i));this.style=i}if(void 0!==a){if(0>R.indexOf(a))throw RangeError('Invalid "localeMatcher" option: '.concat(a));this.localeMatcher=a}if("string"==typeof t&&(t=[t]),t.push(s()),this.locale=e.supportedLocalesOf(t,{localeMatcher:this.localeMatcher})[0],!this.locale)throw Error("No supported locale was found");E.supportedLocalesOf(this.locale).length>0?this.pluralRules=new E(this.locale):console.warn('"'.concat(this.locale,'" locale is not supported')),"undefined"!=typeof Intl&&Intl.NumberFormat?(this.numberFormat=new Intl.NumberFormat(this.locale),this.numberingSystem=this.numberFormat.resolvedOptions().numberingSystem):this.numberingSystem="latn",this.locale=d(this.locale,{localeMatcher:this.localeMatcher})}return C(e,[{key:"format",value:function(){var e=z(arguments),t=x(e,2),n=t[0],r=t[1];return this.getRule(n,r).replace("{0}",this.formatNumber(Math.abs(n)))}},{key:"formatToParts",value:function(){var e=z(arguments),t=x(e,2),n=t[0],r=t[1],i=this.getRule(n,r),a=i.indexOf("{0}");if(a<0)return[{type:"literal",value:i}];var o=[];return a>0&&o.push({type:"literal",value:i.slice(0,a)}),o=o.concat(this.formatNumberToParts(Math.abs(n)).map(function(e){return k({},e,{unit:r})})),a+31&&void 0!==arguments[1]?arguments[1]:{};if("string"==typeof e)e=[e];else if(!Array.isArray(e))throw TypeError('Invalid "locales" argument');return e.filter(function(e){return d(e,t)})},j.addLocale=l,j.setDefaultLocale=u,j.getDefaultLocale=s,j.PluralRules=E;var F='Invalid "unit" argument';function Y(e){if("symbol"===S(e))throw TypeError(F);if("string"!=typeof e||("s"===e[e.length-1]&&(e=e.slice(0,e.length-1)),0>D.indexOf(e)))throw RangeError("".concat(F,": ").concat(e));return e}var B='Invalid "number" argument';function U(e){if(e=Number(e),Number.isFinite&&!Number.isFinite(e))throw RangeError("".concat(B,": ").concat(e));return e}function H(e){return 1/e==-1/0}function $(e){return e<0||0===e&&H(e)}function z(e){if(e.length<2)throw TypeError('"unit" argument is required');return[U(e[0]),Y(e[1])]}function G(e){return(G="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function W(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function K(e,t){for(var n=0;n=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;if(t(o))return o;for(var s=o.split("-");s.length>1;)if(s.pop(),t(o=s.join("-")))return o}throw Error("No locale data has been registered for any of the locales: ".concat(e.join(", ")))}function Q(){return("undefined"==typeof Intl?"undefined":X(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var ee=60,et=60*ee,en=24*et,er=7*en,ei=30.44*en,ea=365.2425*en;function eo(e){switch(e){case"second":return 1;case"minute":return ee;case"hour":return et;case"day":return en;case"week":return er;case"month":return ei;case"year":return ea}}function es(e){return void 0!==e.factor?e.factor:eo(e.unit||e.formatAs)||1}function eu(e){return"floor"===e?Math.floor:(0,Math.round)}function ec(e){return"floor"===e?1:.5}function el(e){return(el="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function ef(e,t){var n,r=t.prevStep,i=t.timestamp,a=t.now,o=t.future,s=t.round;return r&&(r.id||r.unit)&&(n=e["threshold_for_".concat(r.id||r.unit)]),void 0===n&&void 0!==e.threshold&&"function"==typeof(n=e.threshold)&&(n=n(a,o)),void 0===n&&(n=e.minTime),"object"===el(n)&&(n=r&&r.id&&void 0!==n[r.id]?n[r.id]:n.default),"function"==typeof n&&(n=n(i,{future:o,getMinTimeForUnit:function(e,t){return ed(e,t||r&&r.formatAs,{round:s})}})),void 0===n&&e.test&&(n=e.test(i,{now:a,future:o})?0:9007199254740991),void 0===n&&(r?e.formatAs&&r.formatAs&&(n=ed(e.formatAs,r.formatAs,{round:s})):n=0),void 0===n&&console.warn("[javascript-time-ago] A step should specify `minTime`:\n"+JSON.stringify(e,null,2)),n}function ed(e,t,n){var r,i=n.round,a=eo(e);if(r="now"===t?eo(e):eo(t),void 0!==a&&void 0!==r)return a-r*(1-ec(i))}function eh(e){for(var t=1;t0?e[o-1]:s}}}function eg(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=ef(e[r],eh({prevStep:e[r-1],timestamp:n.now-1e3*t},n));return void 0===i||Math.abs(t)=0})}function ey(e,t,n){var r=n.now,i=n.round;if(eo(e)){var a=1e3*eo(e),o=t>r,s=Math.abs(t-r),u=eu(i)(s/a)*a;return o?u>0?s-u+e_(i,a):s-u+1:-(s-u)+ew(i,a)}}function ew(e,t){return ec(e)*t}function e_(e,t){return(1-ec(e))*t+1}var eE=31536e9;function eS(e,t,n){var r,i=n.prevStep,a=n.nextStep,o=n.now,s=n.future,u=n.round,c=e.getTime?e.getTime():e,l=function(e){return ey(e,c,{now:o,round:u})},f=ex(s?t:a,c,{future:s,now:o,round:u,prevStep:s?i:t});if(void 0!==f){if(t&&(t.getTimeToNextUpdate&&(r=t.getTimeToNextUpdate(c,{getTimeToNextUpdateForUnit:l,getRoundFunction:eu,now:o,future:s,round:u})),void 0===r)){var d=t.unit||t.formatAs;d&&(r=l(d))}return void 0===r?f:Math.min(r,f)}}function ek(e,t,n){var r,i=n.now,a=n.future,o=ef(e,{timestamp:t,now:i,future:a,round:n.round,prevStep:n.prevStep});return void 0===o?void 0:a?t-1e3*o+1:0===o&&t===i?eE:t+1e3*o}function ex(e,t,n){var r=n.now,i=n.future,a=n.round,o=n.prevStep;if(e){var s=ek(e,t,{now:r,future:i,round:a,prevStep:o});if(void 0===s)return;return s-r}return i?t-r+1:eE}var eT={};function eM(e){return eT[e]}function eO(e){if(!e)throw Error("[javascript-time-ago] No locale data passed.");eT[e.locale]=e}let eA=[{formatAs:"now"},{formatAs:"second"},{formatAs:"minute"},{formatAs:"hour"},{formatAs:"day"},{formatAs:"week"},{formatAs:"month"},{formatAs:"year"}],eL={steps:eA,labels:"long"};function eC(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.polyfill;ts(this,e),"string"==typeof t&&(t=[t]),this.locale=J(t.concat(e.getDefaultLocale()),eM),"undefined"!=typeof Intl&&Intl.NumberFormat&&(this.numberFormat=new Intl.NumberFormat(this.locale)),!1===r?(this.IntlRelativeTimeFormat=Intl.RelativeTimeFormat,this.IntlPluralRules=Intl.PluralRules):(this.IntlRelativeTimeFormat=j,this.IntlPluralRules=j.PluralRules),this.relativeTimeFormatCache=new Z,this.pluralRulesCache=new Z}return tc(e,[{key:"format",value:function(e,t,n){n||(t&&!tv(t)?(n=t,t=void 0):n={}),t||(t=eD),"string"==typeof t&&(t=tt(t));var r,i=td(e),a=this.getLabels(t.flavour||t.labels),o=a.labels,s=a.labelsType;void 0!==t.now&&(r=t.now),void 0===r&&void 0!==n.now&&(r=n.now),void 0===r&&(r=Date.now());var u=(r-i)/1e3,c=n.future||u<0,l=tb(o,eM(this.locale).now,eM(this.locale).long,c);if(t.custom){var f=t.custom({now:r,date:new Date(i),time:i,elapsed:u,locale:this.locale});if(void 0!==f)return f}var d=tp(t.units,o,l),h=n.round||t.round,p=eb(t.gradation||t.steps||eD.steps,u,{now:r,units:d,round:h,future:c,getNextStep:!0}),b=tr(p,3),m=b[0],g=b[1],v=b[2],y=this.formatDateForStep(i,g,u,{labels:o,labelsType:s,nowLabel:l,now:r,future:c,round:h})||"";if(n.getTimeToNextUpdate){var w=eS(i,g,{nextStep:v,prevStep:m,now:r,future:c,round:h});return[y,w]}return y}},{key:"formatDateForStep",value:function(e,t,n,r){var i=this,a=r.labels,o=r.labelsType,s=r.nowLabel,u=r.now,c=r.future,l=r.round;if(t){if(t.format)return t.format(e,this.locale,{formatAs:function(e,t){return i.formatValue(t,e,{labels:a,future:c})},now:u,future:c});var f=t.unit||t.formatAs;if(!f)throw Error("[javascript-time-ago] Each step must define either `formatAs` or `format()`. Step: ".concat(JSON.stringify(t)));if("now"===f)return s;var d=Math.abs(n)/es(t);t.granularity&&(d=eu(l)(d/t.granularity)*t.granularity);var h=-1*Math.sign(n)*eu(l)(d);switch(0===h&&(h=0),o){case"long":case"short":case"narrow":return this.getFormatter(o).format(h,f);default:return this.formatValue(h,f,{labels:a,future:c})}}}},{key:"formatValue",value:function(e,t,n){var r=n.labels,i=n.future;return this.getFormattingRule(r,t,e,{future:i}).replace("{0}",this.formatNumber(Math.abs(e)))}},{key:"getFormattingRule",value:function(e,t,n,r){var i=r.future;if(this.locale,"string"==typeof(e=e[t]))return e;var a=e[0===n?i?"future":"past":n<0?"past":"future"]||e;return"string"==typeof a?a:a[this.getPluralRules().select(Math.abs(n))]||a.other}},{key:"formatNumber",value:function(e){return this.numberFormat?this.numberFormat.format(e):String(e)}},{key:"getFormatter",value:function(e){return this.relativeTimeFormatCache.get(this.locale,e)||this.relativeTimeFormatCache.put(this.locale,e,new this.IntlRelativeTimeFormat(this.locale,{style:e}))}},{key:"getPluralRules",value:function(){return this.pluralRulesCache.get(this.locale)||this.pluralRulesCache.put(this.locale,new this.IntlPluralRules(this.locale))}},{key:"getLabels",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];"string"==typeof e&&(e=[e]),e=(e=e.map(function(e){switch(e){case"tiny":case"mini-time":return"mini";default:return e}})).concat("long");for(var t=eM(this.locale),n=e,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;if(t[o])return{labelsType:o,labels:t[o]}}}}]),e}(),tf="en";function td(e){if(e.constructor===Date||th(e))return e.getTime();if("number"==typeof e)return e;throw Error("Unsupported relative time formatter input: ".concat(tn(e),", ").concat(e))}function th(e){return"object"===tn(e)&&"function"==typeof e.getTime}function tp(e,t,n){var r=Object.keys(t);return n&&r.push("now"),e&&(r=e.filter(function(e){return"now"===e||r.indexOf(e)>=0})),r}function tb(e,t,n,r){var i=e.now||t&&t.now;return i?"string"==typeof i?i:r?i.future:i.past:n&&n.second&&n.second.current?n.second.current:void 0}tl.getDefaultLocale=function(){return tf},tl.setDefaultLocale=function(e){return tf=e},tl.addDefaultLocale=function(e){if(r)throw Error("[javascript-time-ago] `TimeAgo.addDefaultLocale()` can only be called once. To add other locales, use `TimeAgo.addLocale()`.");r=!0,tl.setDefaultLocale(e.locale),tl.addLocale(e)},tl.addLocale=function(e){eO(e),j.addLocale(e)},tl.locale=tl.addLocale,tl.addLabels=function(e,t,n){var r=eM(e);r||(eO({locale:e}),r=eM(e)),r[t]=n};var tm={}.constructor;function tg(e){return void 0!==tn(e)&&null!==e&&e.constructor===tm}function tv(e){return"string"==typeof e||ty(e)}function ty(e){return tg(e)&&(Array.isArray(e.steps)||Array.isArray(e.gradation)||Array.isArray(e.flavour)||"string"==typeof e.flavour||Array.isArray(e.labels)||"string"==typeof e.labels||Array.isArray(e.units)||"function"==typeof e.custom)}},41800(e,t,n){e.exports=function(){"use strict";var e={121:function(e,t,r){r.r(t),r.d(t,{default:function(){return E}}),n(41539),n(21249),n(54747),n(15306),n(74916),n(47042),n(82526),n(41817),n(32165),n(78783),n(66992),n(33948),n(81486);var i=n(68929),a=r.n(i),o=n(1469),s=r.n(o),u=n(45220),c=r.n(u),l=n(3674),f=r.n(l),d=n(82492),h=r.n(d);function p(e){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function b(e){return s()(e)?e:[e]}function m(e){if(null===e||"object"!==p(e)||(t=e,"[object Date]"===Object.prototype.toString.call(t)))return e;if(s()(e))return e.map(m);var t,n={};return f()(e).forEach(function(t){n[a()(t)]=m(e[t])}),n}function g(e,t){var n=t.camelizeKeys,r=t.camelizeTypeValues,i={};return f()(e).forEach(function(t){var o=e[t],u=n?a()(t):t;i[u]={},void 0!==o.data&&(s()(o.data)?i[u].data=o.data.map(function(e){return{id:e.id,type:r?a()(e.type):e.type}}):c()(o.data)?i[u].data=o.data:i[u].data={id:o.data.id,type:r?a()(o.data.type):o.data.type}),o.links&&(i[u].links=n?m(o.links):o.links),o.meta&&(i[u].meta=n?m(o.meta):o.meta)}),i}function v(e,t){if(t.camelizeKeys){var n={};return f()(e).forEach(function(t){n[a()(t)]=m(e[t])}),n}return e}function y(e,t){var n=t.camelizeKeys,r=t.camelizeTypeValues,i={};return b(e).forEach(function(e){var t=n?a()(e.type):e.type;i[t]=i[t]||{},i[t][e.id]=i[t][e.id]||{id:e.id},i[t][e.id].type=r?a()(e.type):e.type,n?(i[t][e.id].attributes={},f()(e.attributes).forEach(function(n){i[t][e.id].attributes[a()(n)]=m(e.attributes[n])})):i[t][e.id].attributes=e.attributes,e.links&&(i[t][e.id].links={},f()(e.links).forEach(function(r){var o=n?a()(r):r;i[t][e.id].links[o]=e.links[r]})),e.relationships&&(i[t][e.id].relationships=g(e.relationships,{camelizeKeys:n,camelizeTypeValues:r})),e.meta&&(i[t][e.id].meta=v(e.meta,{camelizeKeys:n}))}),i}function w(e){return e.replace(/\?.*$/,"")}function _(e,t,n){var r,i=n.camelizeKeys,o=n.camelizeTypeValues,s={meta:{}};if(n.filterEndpoint)s.meta[t]={},r=s.meta[t];else{var u=w(t);s.meta[u]={},s.meta[u][t.slice(u.length)]={},r=s.meta[u][t.slice(u.length)]}if(r.data={},e.data){var c=[];b(e.data).forEach(function(e){var t={id:e.id,type:o?a()(e.type):e.type};e.relationships&&(t.relationships=g(e.relationships,{camelizeKeys:i,camelizeTypeValues:o})),c.push(t)}),r.data=c}return e.links&&(r.links=e.links,s.meta[w(t)].links=e.links),e.meta&&(r.meta=v(e.meta,{camelizeKeys:i})),s}function E(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.filterEndpoint,r=void 0===n||n,i=t.camelizeKeys,a=void 0===i||i,o=t.camelizeTypeValues,s=void 0===o||o,u=t.endpoint,c={};if(e.data&&h()(c,y(e.data,{camelizeKeys:a,camelizeTypeValues:s})),e.included&&h()(c,y(e.included,{camelizeKeys:a,camelizeTypeValues:s})),u){var l=r?w(u):u;h()(c,_(e,l,{camelizeKeys:a,camelizeTypeValues:s,filterEndpoint:r}))}return c}}},t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={exports:{}};return e[n](i,i.exports,r),i.exports}return r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,{a:t}),t},r.d=function(e,t){for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r(121)}()},63731:function(e){var t,n;t="undefined"!=typeof self?self:this,n=function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t||4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,(function(t){return e[t]}).bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(1),i=/["'&<>]/,a=function(e){var t=i.exec(e);if(null!==t){var n,r="",a=void 0,o=0;for(a=t.index;a")},e.prototype.space=function(){this.buffer.push(" ")},e.prototype.indent=function(e){if(e>0){for(var t="",n=0;n'+a(e)+""),this.buffer.push('"')},e.prototype.printString=function(e){this.buffer.push('"'),this.buffer.push(''+a(e)+""),this.buffer.push('"')},e.prototype.printBoolean=function(e){this.buffer.push(''+e+"")},e.prototype.printNumber=function(e){this.buffer.push(''+e+"")},e.prototype.printSelectionStart=function(){this.buffer.push(""),this.buffer.push('
')},e.prototype.printSelectionEnd=function(){this.buffer.push("
"),this.buffer.push('
')},Object.defineProperty(e.prototype,"printSelectionEndAtNewLine",{set:function(e){this._printSelectionEndAtNewLine=e},enumerable:!0,configurable:!0}),e.prototype.toString=function(){return this.buffer.join("")},e}(),s=function(e,t,n,r,i){t.checkCircular(e),t.print("{"),t.newLine();for(var a=Object.keys(e),o=0;o'):a.print('
'),Array.isArray(e)?u(e,a,0,t,i):s(e,a,0,t,i),a.print("
"),a.toString()}return""}},function(e,t,n){"use strict";n.r(t),n.d(t,"__extends",function(){return i}),n.d(t,"__assign",function(){return a}),n.d(t,"__rest",function(){return o}),n.d(t,"__decorate",function(){return s}),n.d(t,"__param",function(){return u}),n.d(t,"__metadata",function(){return c}),n.d(t,"__awaiter",function(){return l}),n.d(t,"__generator",function(){return f}),n.d(t,"__exportStar",function(){return d}),n.d(t,"__values",function(){return h}),n.d(t,"__read",function(){return p}),n.d(t,"__spread",function(){return b}),n.d(t,"__await",function(){return m}),n.d(t,"__asyncGenerator",function(){return g}),n.d(t,"__asyncDelegator",function(){return v}),n.d(t,"__asyncValues",function(){return y}),n.d(t,"__makeTemplateObject",function(){return w}),n.d(t,"__importStar",function(){return _}),n.d(t,"__importDefault",function(){return E});/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ var r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])};function i(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]])}return n}function s(e,t,n,r){var i,a=arguments.length,o=a<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o}function u(e,t){return function(n,r){t(n,r,e)}}function c(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function l(e,t,n,r){return new(n||(n=Promise))(function(i,a){function o(e){try{u(r.next(e))}catch(t){a(t)}}function s(e){try{u(r.throw(e))}catch(t){a(t)}}function u(e){e.done?i(e.value):new n(function(t){t(e.value)}).then(o,s)}u((r=r.apply(e,t||[])).next())})}function f(e,t){var n,r,i,a,o={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return a={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function s(a){return function(s){return function(a){if(n)throw TypeError("Generator is already executing.");for(;o;)try{if(n=1,r&&(i=r[2&a[0]?"return":a[0]?"throw":"next"])&&!(i=i.call(r,a[1])).done)return i;switch(r=0,i&&(a=[0,i.value]),a[0]){case 0:case 1:i=a;break;case 4:return o.label++,{value:a[1],done:!1};case 5:o.label++,r=a[1],a=[0];continue;case 7:a=o.ops.pop(),o.trys.pop();continue;default:if(!(i=(i=o.trys).length>0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}}}function p(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,i,a=n.call(e),o=[];try{for(;(void 0===t||t-- >0)&&!(r=a.next()).done;)o.push(r.value)}catch(s){i={error:s}}finally{try{r&&!r.done&&(n=a.return)&&n.call(a)}finally{if(i)throw i.error}}return o}function b(){for(var e=[],t=0;t1||s(e,t)})})}function s(e,t){try{var n;(n=i[e](t)).value instanceof m?Promise.resolve(n.value.v).then(u,c):l(a[0][2],n)}catch(r){l(a[0][3],r)}}function u(e){s("next",e)}function c(e){s("throw",e)}function l(e,t){e(t),a.shift(),a.length&&s(a[0][0],a[0][1])}}function v(e){var t,n;return t={},r("next"),r("throw",function(e){throw e}),r("return"),t[Symbol.iterator]=function(){return this},t;function r(r,i){e[r]&&(t[r]=function(t){return(n=!n)?{value:m(e[r](t)),done:"return"===r}:i?i(t):t})}}function y(e){if(!Symbol.asyncIterator)throw TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator];return t?t.call(e):h(e)}function w(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e}function _(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}function E(e){return e&&e.__esModule?e:{default:e}}}])},e.exports=n()},35828(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=s;var r=n(25477),i=a(r);function a(e){return e&&e.__esModule?e:{default:e}}function o(e){var t={};for(var n in e)t[(0,i.default)(n)]=e[n];return e.fallbacks&&(Array.isArray(e.fallbacks)?t.fallbacks=e.fallbacks.map(o):t.fallbacks=o(e.fallbacks)),t}function s(){function e(e){if(Array.isArray(e)){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{},t=s(e);function n(e,n){if("style"!==n.type)return e;for(var r in e)e[r]=c(r,e[r],t);return e}function r(e,n){return c(n,e,t)}return{onProcessStyle:n,onChangeValue:r}}},29059(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{};return e.createGenerateClassName&&(this.options.createGenerateClassName=e.createGenerateClassName,this.generateClassName=e.createGenerateClassName()),null!=e.insertionPoint&&(this.options.insertionPoint=e.insertionPoint),(e.virtual||e.Renderer)&&(this.options.Renderer=e.Renderer||(e.virtual?A.default:M.default)),e.plugins&&this.use.apply(this,e.plugins),this}},{key:"createStyleSheet",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.index;"number"!=typeof n&&(n=0===y.default.index?0:y.default.index+1);var r=new c.default(e,i({},t,{jss:this,generateClassName:t.generateClassName||this.generateClassName,insertionPoint:this.options.insertionPoint,Renderer:this.options.Renderer,index:n}));return this.plugins.onProcessSheet(r),r}},{key:"removeStyleSheet",value:function(e){return e.detach(),y.default.remove(e),this}},{key:"createRule",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};(void 0===e?"undefined":r(e))==="object"&&(n=t,t=e,e=void 0);var i=n;i.jss=this,i.Renderer=this.options.Renderer,i.generateClassName||(i.generateClassName=this.generateClassName),i.classes||(i.classes={});var a=(0,x.default)(e,t,i);return!i.selector&&a instanceof _.default&&(a.selector="."+i.generateClassName(a)),this.plugins.onProcessRule(a),a}},{key:"use",value:function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r0&&(this.refs[t]--,0===this.refs[t]&&this.sheets[t].detach())}},{key:"size",get:function(){return this.keys.length}}]),e}();t.default=u},92122(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t){for(var n=0;n=this.index){t.push(e);return}for(var r=0;rn){t.splice(r,0,e);return}}}},{key:"reset",value:function(){this.registry=[]}},{key:"remove",value:function(e){var t=this.registry.indexOf(e);this.registry.splice(t,1)}},{key:"toString",value:function(e){return this.registry.filter(function(e){return e.attached}).map(function(t){return t.toString(e)}).join("\n")}},{key:"index",get:function(){return 0===this.registry.length?0:this.registry[this.registry.length-1].options.index}}]),e}();t.default=i},26899(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:0;return e.substr(t,e.indexOf("{")-1)},function(e){if(e.type===y.STYLE_RULE)return e.selectorText;if(e.type===y.KEYFRAMES_RULE){var t=e.name;if(t)return"@keyframes "+t;var n=e.cssText;return"@"+v(n,n.indexOf("keyframes"))}return v(e.cssText)});function _(e,t){return e.selectorText=t,e.selectorText===t}var E,S,k=p(function(){return document.head||document.getElementsByTagName("head")[0]}),x=(E=void 0,S=!1,function(e){var t={};E||(E=document.createElement("style"));for(var n=0;nt.index&&r.options.insertionPoint===t.insertionPoint)return r}return null}function M(e,t){for(var n=e.length-1;n>=0;n--){var r=e[n];if(r.attached&&r.options.insertionPoint===t.insertionPoint)return r}return null}function O(e){for(var t=k(),n=0;n0){var n=T(t,e);if(n)return n.renderer.element;if(n=M(t,e))return n.renderer.element.nextElementSibling}var r=e.insertionPoint;if(r&&"string"==typeof r){var i=O(r);if(i)return i.nextSibling;(0,a.default)("jss"===r,'[JSS] Insertion point "%s" not found.',r)}return null}function L(e,t){var n=t.insertionPoint,r=A(t);if(r){var i=r.parentNode;i&&i.insertBefore(e,r);return}if(n&&"number"==typeof n.nodeType){var o=n,s=o.parentNode;s?s.insertBefore(e,o.nextSibling):(0,a.default)(!1,"[JSS] Insertion point is not in the DOM.");return}k().insertBefore(e,r)}var C=p(function(){var e=document.querySelector('meta[property="csp-nonce"]');return e?e.getAttribute("content"):null}),I=function(){function e(t){h(this,e),this.getPropertyValue=b,this.setProperty=m,this.removeProperty=g,this.setSelector=_,this.getKey=w,this.getUnescapedKeysMap=x,this.hasInsertedRules=!1,t&&s.default.add(t),this.sheet=t;var n=this.sheet?this.sheet.options:{},r=n.media,i=n.meta,a=n.element;this.element=a||document.createElement("style"),this.element.setAttribute("data-jss",""),r&&this.element.setAttribute("media",r),i&&this.element.setAttribute("data-meta",i);var o=C();o&&this.element.setAttribute("nonce",o)}return r(e,[{key:"attach",value:function(){!this.element.parentNode&&this.sheet&&(this.hasInsertedRules&&(this.deploy(),this.hasInsertedRules=!1),L(this.element,this.sheet.options))}},{key:"detach",value:function(){this.element.parentNode.removeChild(this.element)}},{key:"deploy",value:function(){this.sheet&&(this.element.textContent="\n"+this.sheet.toString()+"\n")}},{key:"insertRule",value:function(e,t){var n=this.element.sheet,r=n.cssRules,i=e.toString();if(t||(t=r.length),!i)return!1;try{n.insertRule(i,t)}catch(o){return(0,a.default)(!1,"[JSS] Can not insert an unsupported rule \n\r%s",e),!1}return this.hasInsertedRules=!0,r[t]}},{key:"deleteRule",value:function(e){var t=this.element.sheet,n=this.indexOf(e);return -1!==n&&(t.deleteRule(n),!0)}},{key:"indexOf",value:function(e){for(var t=this.element.sheet.cssRules,n=0;n0&&void 0!==arguments[0]?arguments[0]:{indent:1},t=this.rules.toString(e);return t?this.key+" {\n"+t+"\n}":""}}]),e}();t.default=c},12398(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{indent:1},t=this.rules.toString(e);return t&&(t+="\n"),this.key+" {\n"+t+"}"}}]),e}();t.default=c},3486(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t){for(var n=0;nc&&(0,i.default)(!1,"[JSS] You might have a memory leak. Rule counter is at %s.",e);var a=t,o="";return(r&&(a=r.options.classNamePrefix||t,null!=r.options.jss.id&&(o+=r.options.jss.id)),"production"===l)?""+a+s.default+o+e:a+n.key+"-"+s.default+(o&&"-"+o)+"-"+e}}},89380(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=l;var r=n(63189),i=c(r),a=n(15803),o=c(a),s=n(2808),u=c(s);function c(e){return e&&e.__esModule?e:{default:e}}function l(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"unnamed",t=arguments[1],n=arguments[2],r=n.jss,a=(0,u.default)(t),s=r.plugins.onCreateRule(e,a,n);return s||("@"===e[0]&&(0,i.default)(!1,"[JSS] Unknown at-rule %s",e),new o.default(e,a,n))}},55878(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n.g.CSS,i="production",a=/([[\].#*$><+~=|^:(),"'`])/g;t.default=function(e){return"production"===i?e:r&&r.escape?r.escape(e):e.replace(a,"\\$1")}},27343(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function r(e){var t=null;for(var i in e){var a=e[i],o=void 0===a?"undefined":n(a);if("function"===o)t||(t={}),t[i]=a;else if("object"===o&&null!==a&&!Array.isArray(a)){var s=r(a);s&&(t||(t={}),t[i]=s)}}return t}t.default=r},97628(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(67121),i=a(r);function a(e){return e&&e.__esModule?e:{default:e}}t.default=function(e){return e&&e[i.default]&&e===e[i.default]()}},94229(e,t){"use strict";function n(e,t){e.renderable=t,e.rules&&t.cssRules&&e.rules.link(t.cssRules)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},141(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r="2f1acc6c3a606b082e5eef5e54414ffb";null==n.g[r]&&(n.g[r]=0),t.default=n.g[r]++},70084(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=s;var r=n(16229),i=a(r);function a(e){return e&&e.__esModule?e:{default:e}}function o(e,t){for(var n="",r=0;r2&&void 0!==arguments[2]?arguments[2]:{},r="";if(!t)return r;var a=n.indent,s=void 0===a?0:a,u=t.fallbacks;if(s++,u){if(Array.isArray(u))for(var c=0;c1&&void 0!==arguments[1]&&arguments[1];if(!Array.isArray(e))return e;var r="";if(Array.isArray(e[0]))for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:{};s(this,e),this.cookieOptions=Object.assign({path:"/"},t),u=void 0===t.prefix?u:t.prefix}return r(e,[{key:"getItem",value:function(e){var t=a.default.parse(document.cookie);return t&&t.hasOwnProperty(u+e)?t[u+e]:null}},{key:"setItem",value:function(e,t){return document.cookie=a.default.serialize(u+e,t,this.cookieOptions),t}},{key:"removeItem",value:function(e){var t=Object.assign({},this.cookieOptions,{maxAge:-1});return document.cookie=a.default.serialize(u+e,"",t),null}},{key:"clear",value:function(){var e=a.default.parse(document.cookie);for(var t in e)0===t.indexOf(u)&&this.removeItem(t.substr(u.length));return null}}]),e}();function l(){var e=new c;try{var t="__test";e.setItem(t,"1");var n=e.getItem(t);return e.removeItem(t),"1"===n}catch(r){return!1}}t.default=c},90145(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"localStorage",t=String(e).replace(/storage$/i,"").toLowerCase();if("local"===t)return a("localStorage");if("session"===t)return a("sessionStorage");if("cookie"===t)return(0,r.hasCookies)();if("memory"===t)return!0;throw Error("Storage method `"+e+"` is not available.\n Please use one of the following: localStorage, sessionStorage, cookieStorage, memoryStorage.")}},72426(e,t){"use strict";/*! + * cookie + * Copyright(c) 2012-2014 Roman Shtylman + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ t.parse=o,t.serialize=s;var n=decodeURIComponent,r=encodeURIComponent,i=/; */,a=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function o(e,t){if("string"!=typeof e)throw TypeError("argument str must be a string");for(var r={},a=t||{},o=e.split(i),s=a.decode||n,c=0;cc});var r=n(56169);e=n.hmd(e);var i="object"==typeof exports&&exports&&!exports.nodeType&&exports,a=i&&e&&!e.nodeType&&e,o=a&&a.exports===i?r.Z.Buffer:void 0,s=o?o.allocUnsafe:void 0;function u(e,t){if(t)return e.slice();var n=e.length,r=s?s(n):new e.constructor(n);return e.copy(r),r}let c=u},48277(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="object"==typeof n.g&&n.g&&n.g.Object===Object&&n.g;let i=r},79730(e,t,n){"use strict";n.d(t,{Z:()=>u});var r=n(48277);e=n.hmd(e);var i="object"==typeof exports&&exports&&!exports.nodeType&&exports,a=i&&e&&!e.nodeType&&e,o=a&&a.exports===i&&r.Z.process,s=function(){try{var e=a&&a.require&&a.require("util").types;if(e)return e;return o&&o.binding&&o.binding("util")}catch(t){}}();let u=s},56169(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=n(48277),i="object"==typeof self&&self&&self.Object===Object&&self,a=r.Z||i||Function("return this")();let o=a},29710(e,t,n){"use strict";n.d(t,{Z:()=>l});var r=n(56169);function i(){return!1}let a=i;e=n.hmd(e);var o="object"==typeof exports&&exports&&!exports.nodeType&&exports,s=o&&e&&!e.nodeType&&e,u=s&&s.exports===o?r.Z.Buffer:void 0,c=(u?u.isBuffer:void 0)||a;let l=c},18552(e,t,n){var r=n(10852),i=n(55639),a=r(i,"DataView");e.exports=a},1989(e,t,n){var r=n(51789),i=n(80401),a=n(57667),o=n(21327),s=n(81866);function u(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1}e.exports=i},1196(e){function t(e,t,n){for(var r=-1,i=null==e?0:e.length;++r0&&n(l)?t>1?a(l,t-1,n,o,s):r(s,l):o||(s[s.length]=l)}return s}e.exports=a},28483(e,t,n){var r=n(25063)();e.exports=r},47816(e,t,n){var r=n(28483),i=n(3674);function a(e,t){return e&&r(e,t,i)}e.exports=a},97786(e,t,n){var r=n(71811),i=n(40327);function a(e,t){t=r(t,e);for(var n=0,a=t.length;null!=e&&ni?0:i+t),(n=n>i?i:n)<0&&(n+=i),i=t>n?0:n-t>>>0,t>>>=0;for(var a=Array(i);++r=c){var m=t?null:s(e);if(m)return u(m);h=!1,f=o,b=new r}else b=t?[]:p;outer:for(;++l=i?e:r(e,t,n)}e.exports=i},74318(e,t,n){var r=n(11149);function i(e){var t=new e.constructor(e.byteLength);return new r(t).set(new r(e)),t}e.exports=i},64626(e,t,n){e=n.nmd(e);var r=n(55639),i=t&&!t.nodeType&&t,a=i&&e&&!e.nodeType&&e,o=a&&a.exports===i?r.Buffer:void 0,s=o?o.allocUnsafe:void 0;function u(e,t){if(t)return e.slice();var n=e.length,r=s?s(n):new e.constructor(n);return e.copy(r),r}e.exports=u},57157(e,t,n){var r=n(74318);function i(e,t){var n=t?r(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}e.exports=i},93147(e){var t=/\w*$/;function n(e){var n=new e.constructor(e.source,t.exec(e));return n.lastIndex=e.lastIndex,n}e.exports=n},40419(e,t,n){var r=n(62705),i=r?r.prototype:void 0,a=i?i.valueOf:void 0;function o(e){return a?Object(a.call(e)):{}}e.exports=o},77133(e,t,n){var r=n(74318);function i(e,t){var n=t?r(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}e.exports=i},278(e){function t(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n1?n[a-1]:void 0,s=a>2?n[2]:void 0;for(o=e.length>3&&"function"==typeof o?(a--,o):void 0,s&&i(n[0],n[1],s)&&(o=a<3?void 0:o,a=1),t=Object(t);++rd))return!1;var p=l.get(e),b=l.get(t);if(p&&b)return p==t&&b==e;var m=-1,g=!0,v=n&s?new r:void 0;for(l.set(e,t),l.set(t,e);++m-1&&e%1==0&&e-1}e.exports=i},13399(e,t,n){var r=n(18470);function i(e,t){var n=this.__data__,i=r(n,e);return i<0?(++this.size,n.push([e,t])):n[i][1]=t,this}e.exports=i},24785(e,t,n){var r=n(1989),i=n(38407),a=n(57071);function o(){this.size=0,this.__data__={hash:new r,map:new(a||i),string:new r}}e.exports=o},11285(e,t,n){var r=n(45050);function i(e){var t=r(this,e).delete(e);return this.size-=t?1:0,t}e.exports=i},96e3(e,t,n){var r=n(45050);function i(e){return r(this,e).get(e)}e.exports=i},49916(e,t,n){var r=n(45050);function i(e){return r(this,e).has(e)}e.exports=i},95265(e,t,n){var r=n(45050);function i(e,t){var n=r(this,e),i=n.size;return n.set(e,t),this.size+=n.size==i?0:1,this}e.exports=i},68776(e){function t(e){var t=-1,n=Array(e.size);return e.forEach(function(e,r){n[++t]=[r,e]}),n}e.exports=t},42634(e){function t(e,t){return function(n){return null!=n&&n[e]===t&&(void 0!==t||e in Object(n))}}e.exports=t},24523(e,t,n){var r=n(88306),i=500;function a(e){var t=r(e,function(e){return n.size===i&&n.clear(),e}),n=t.cache;return t}e.exports=a},94536(e,t,n){var r=n(10852)(Object,"create");e.exports=r},86916(e,t,n){var r=n(5569)(Object.keys,Object);e.exports=r},33498(e){function t(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}e.exports=t},31167(e,t,n){e=n.nmd(e);var r=n(31957),i=t&&!t.nodeType&&t,a=i&&e&&!e.nodeType&&e,o=a&&a.exports===i&&r.process,s=function(){try{var e=a&&a.require&&a.require("util").types;if(e)return e;return o&&o.binding&&o.binding("util")}catch(t){}}();e.exports=s},2333(e){var t=Object.prototype.toString;function n(e){return t.call(e)}e.exports=n},5569(e){function t(e,t){return function(n){return e(t(n))}}e.exports=t},45357(e,t,n){var r=n(96874),i=Math.max;function a(e,t,n){return t=i(void 0===t?e.length-1:t,0),function(){for(var a=arguments,o=-1,s=i(a.length-t,0),u=Array(s);++o0){if(++i>=t)return arguments[0]}else i=0;return e.apply(void 0,arguments)}}e.exports=i},37465(e,t,n){var r=n(38407);function i(){this.__data__=new r,this.size=0}e.exports=i},63779(e){function t(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n}e.exports=t},67599(e){function t(e){return this.__data__.get(e)}e.exports=t},44758(e){function t(e){return this.__data__.has(e)}e.exports=t},34309(e,t,n){var r=n(38407),i=n(57071),a=n(83369),o=200;function s(e,t){var n=this.__data__;if(n instanceof r){var s=n.__data__;if(!i||s.length=t||n<0||g&&r>=f}function S(){var e=i();if(E(e))return k(e);h=setTimeout(S,_(e))}function k(e){return(h=void 0,v&&c)?y(e):(c=l=void 0,d)}function x(){void 0!==h&&clearTimeout(h),b=0,c=p=l=h=void 0}function T(){return void 0===h?d:k(i())}function M(){var e=i(),n=E(e);if(c=arguments,l=this,p=e,n){if(void 0===h)return w(p);if(g)return clearTimeout(h),h=setTimeout(S,t),y(p)}return void 0===h&&(h=setTimeout(S,t)),d}return t=a(t)||0,r(n)&&(m=!!n.leading,f=(g="maxWait"in n)?s(a(n.maxWait)||0,t):f,v="trailing"in n?!!n.trailing:v),M.cancel=x,M.flush=T,M}e.exports=c},53816(e,t,n){var r=n(69389),i=n(79833),a=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,o=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g");function s(e){return(e=i(e))&&e.replace(a,r).replace(o,"")}e.exports=s},66073(e,t,n){e.exports=n(84486)},77813(e){function t(e,t){return e===t||e!=e&&t!=t}e.exports=t},63105(e,t,n){var r=n(34963),i=n(80760),a=n(67206),o=n(1469);function s(e,t){return(o(e)?r:i)(e,a(t,3))}e.exports=s},85564(e,t,n){var r=n(21078);function i(e){return(null==e?0:e.length)?r(e,1):[]}e.exports=i},84486(e,t,n){var r=n(77412),i=n(89881),a=n(54290),o=n(1469);function s(e,t){return(o(e)?r:i)(e,a(t))}e.exports=s},27361(e,t,n){var r=n(97786);function i(e,t,n){var i=null==e?void 0:r(e,t);return void 0===i?n:i}e.exports=i},18721(e,t,n){var r=n(78565),i=n(222);function a(e,t){return null!=e&&i(e,t,r)}e.exports=a},79095(e,t,n){var r=n(13),i=n(222);function a(e,t){return null!=e&&i(e,t,r)}e.exports=a},6557(e){function t(e){return e}e.exports=t},35694(e,t,n){var r=n(9454),i=n(37005),a=Object.prototype,o=a.hasOwnProperty,s=a.propertyIsEnumerable,u=r(function(){return arguments}())?r:function(e){return i(e)&&o.call(e,"callee")&&!s.call(e,"callee")};e.exports=u},1469(e){var t=Array.isArray;e.exports=t},98612(e,t,n){var r=n(23560),i=n(41780);function a(e){return null!=e&&i(e.length)&&!r(e)}e.exports=a},29246(e,t,n){var r=n(98612),i=n(37005);function a(e){return i(e)&&r(e)}e.exports=a},44144(e,t,n){e=n.nmd(e);var r=n(55639),i=n(95062),a=t&&!t.nodeType&&t,o=a&&e&&!e.nodeType&&e,s=o&&o.exports===a?r.Buffer:void 0,u=(s?s.isBuffer:void 0)||i;e.exports=u},41609(e,t,n){var r=n(280),i=n(64160),a=n(35694),o=n(1469),s=n(98612),u=n(44144),c=n(25726),l=n(36719),f="[object Map]",d="[object Set]",h=Object.prototype.hasOwnProperty;function p(e){if(null==e)return!0;if(s(e)&&(o(e)||"string"==typeof e||"function"==typeof e.splice||u(e)||l(e)||a(e)))return!e.length;var t=i(e);if(t==f||t==d)return!e.size;if(c(e))return!r(e).length;for(var n in e)if(h.call(e,n))return!1;return!0}e.exports=p},23560(e,t,n){var r=n(44239),i=n(13218),a="[object AsyncFunction]",o="[object Function]",s="[object GeneratorFunction]",u="[object Proxy]";function c(e){if(!i(e))return!1;var t=r(e);return t==o||t==s||t==a||t==u}e.exports=c},41780(e){var t=9007199254740991;function n(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=t}e.exports=n},56688(e,t,n){var r=n(25588),i=n(7518),a=n(31167),o=a&&a.isMap,s=o?i(o):r;e.exports=s},45220(e){function t(e){return null===e}e.exports=t},13218(e){function t(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}e.exports=t},37005(e){function t(e){return null!=e&&"object"==typeof e}e.exports=t},68630(e,t,n){var r=n(44239),i=n(85924),a=n(37005),o="[object Object]",s=Function.prototype,u=Object.prototype,c=s.toString,l=u.hasOwnProperty,f=c.call(Object);function d(e){if(!a(e)||r(e)!=o)return!1;var t=i(e);if(null===t)return!0;var n=l.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&c.call(n)==f}e.exports=d},72928(e,t,n){var r=n(29221),i=n(7518),a=n(31167),o=a&&a.isSet,s=o?i(o):r;e.exports=s},47037(e,t,n){var r=n(44239),i=n(1469),a=n(37005),o="[object String]";function s(e){return"string"==typeof e||!i(e)&&a(e)&&r(e)==o}e.exports=s},33448(e,t,n){var r=n(44239),i=n(37005),a="[object Symbol]";function o(e){return"symbol"==typeof e||i(e)&&r(e)==a}e.exports=o},36719(e,t,n){var r=n(38749),i=n(7518),a=n(31167),o=a&&a.isTypedArray,s=o?i(o):r;e.exports=s},52353(e){function t(e){return void 0===e}e.exports=t},3674(e,t,n){var r=n(14636),i=n(280),a=n(98612);function o(e){return a(e)?r(e):i(e)}e.exports=o},81704(e,t,n){var r=n(14636),i=n(35014),a=n(98612);function o(e){return a(e)?r(e,!0):i(e)}e.exports=o},96486:function(e,t,n){var r;e=n.nmd(e),(function(){var i,a="4.17.21",o=200,s="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",u="Expected a function",c="Invalid `variable` option passed into `_.template`",l="__lodash_hash_undefined__",f=500,d="__lodash_placeholder__",h=1,p=2,b=4,m=1,g=2,v=1,y=2,w=4,_=8,E=16,S=32,k=64,x=128,T=256,M=512,O=30,A="...",L=800,C=16,I=1,D=2,N=3,P=1/0,R=9007199254740991,j=17976931348623157e292,F=0/0,Y=4294967295,B=Y-1,U=Y>>>1,H=[["ary",x],["bind",v],["bindKey",y],["curry",_],["curryRight",E],["flip",M],["partial",S],["partialRight",k],["rearg",T]],$="[object Arguments]",z="[object Array]",G="[object AsyncFunction]",W="[object Boolean]",K="[object Date]",V="[object DOMException]",q="[object Error]",Z="[object Function]",X="[object GeneratorFunction]",J="[object Map]",Q="[object Number]",ee="[object Null]",et="[object Object]",en="[object Promise]",er="[object Proxy]",ei="[object RegExp]",ea="[object Set]",eo="[object String]",es="[object Symbol]",eu="[object Undefined]",ec="[object WeakMap]",el="[object WeakSet]",ef="[object ArrayBuffer]",ed="[object DataView]",eh="[object Float32Array]",ep="[object Float64Array]",eb="[object Int8Array]",em="[object Int16Array]",eg="[object Int32Array]",ev="[object Uint8Array]",ey="[object Uint8ClampedArray]",ew="[object Uint16Array]",e_="[object Uint32Array]",eE=/\b__p \+= '';/g,eS=/\b(__p \+=) '' \+/g,ek=/(__e\(.*?\)|\b__t\)) \+\n'';/g,ex=/&(?:amp|lt|gt|quot|#39);/g,eT=/[&<>"']/g,eM=RegExp(ex.source),eO=RegExp(eT.source),eA=/<%-([\s\S]+?)%>/g,eL=/<%([\s\S]+?)%>/g,eC=/<%=([\s\S]+?)%>/g,eI=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,eD=/^\w*$/,eN=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,eP=/[\\^$.*+?()[\]{}|]/g,eR=RegExp(eP.source),ej=/^\s+/,eF=/\s/,eY=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,eB=/\{\n\/\* \[wrapped with (.+)\] \*/,eU=/,? & /,eH=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,e$=/[()=,{}\[\]\/\s]/,ez=/\\(\\)?/g,eG=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,eW=/\w*$/,eK=/^[-+]0x[0-9a-f]+$/i,eV=/^0b[01]+$/i,eq=/^\[object .+?Constructor\]$/,eZ=/^0o[0-7]+$/i,eX=/^(?:0|[1-9]\d*)$/,eJ=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,eQ=/($^)/,e1=/['\n\r\u2028\u2029\\]/g,e0="\ud800-\udfff",e2="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",e3="\\u2700-\\u27bf",e4="a-z\\xdf-\\xf6\\xf8-\\xff",e5="A-Z\\xc0-\\xd6\\xd8-\\xde",e6="\\ufe0e\\ufe0f",e9="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",e8="['’]",e7="["+e0+"]",te="["+e9+"]",tt="["+e2+"]",tn="\\d+",tr="["+e3+"]",ti="["+e4+"]",ta="[^"+e0+e9+tn+e3+e4+e5+"]",to="\ud83c[\udffb-\udfff]",ts="[^"+e0+"]",tu="(?:\ud83c[\udde6-\uddff]){2}",tc="[\ud800-\udbff][\udc00-\udfff]",tl="["+e5+"]",tf="\\u200d",td="(?:"+ti+"|"+ta+")",th="(?:"+tl+"|"+ta+")",tp="(?:"+e8+"(?:d|ll|m|re|s|t|ve))?",tb="(?:"+e8+"(?:D|LL|M|RE|S|T|VE))?",tm="(?:"+tt+"|"+to+")?",tg="["+e6+"]?",tv="(?:"+tf+"(?:"+[ts,tu,tc].join("|")+")"+tg+tm+")*",ty="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",tw="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",t_=tg+tm+tv,tE="(?:"+[tr,tu,tc].join("|")+")"+t_,tS="(?:"+[ts+tt+"?",tt,tu,tc,e7].join("|")+")",tk=RegExp(e8,"g"),tx=RegExp(tt,"g"),tT=RegExp(to+"(?="+to+")|"+tS+t_,"g"),tM=RegExp([tl+"?"+ti+"+"+tp+"(?="+[te,tl,"$"].join("|")+")",th+"+"+tb+"(?="+[te,tl+td,"$"].join("|")+")",tl+"?"+td+"+"+tp,tl+"+"+tb,tw,ty,tn,tE].join("|"),"g"),tO=RegExp("["+tf+e0+e2+e6+"]"),tA=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,tL=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],tC=-1,tI={};tI[eh]=tI[ep]=tI[eb]=tI[em]=tI[eg]=tI[ev]=tI[ey]=tI[ew]=tI[e_]=!0,tI[$]=tI[z]=tI[ef]=tI[W]=tI[ed]=tI[K]=tI[q]=tI[Z]=tI[J]=tI[Q]=tI[et]=tI[ei]=tI[ea]=tI[eo]=tI[ec]=!1;var tD={};tD[$]=tD[z]=tD[ef]=tD[ed]=tD[W]=tD[K]=tD[eh]=tD[ep]=tD[eb]=tD[em]=tD[eg]=tD[J]=tD[Q]=tD[et]=tD[ei]=tD[ea]=tD[eo]=tD[es]=tD[ev]=tD[ey]=tD[ew]=tD[e_]=!0,tD[q]=tD[Z]=tD[ec]=!1;var tN={À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"},tP={"&":"&","<":"<",">":">",'"':""","'":"'"},tR={"&":"&","<":"<",">":">",""":'"',"'":"'"},tj={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},tF=parseFloat,tY=parseInt,tB="object"==typeof n.g&&n.g&&n.g.Object===Object&&n.g,tU="object"==typeof self&&self&&self.Object===Object&&self,tH=tB||tU||Function("return this")(),t$=t&&!t.nodeType&&t,tz=t$&&e&&!e.nodeType&&e,tG=tz&&tz.exports===t$,tW=tG&&tB.process,tK=function(){try{var e=tz&&tz.require&&tz.require("util").types;if(e)return e;return tW&&tW.binding&&tW.binding("util")}catch(t){}}(),tV=tK&&tK.isArrayBuffer,tq=tK&&tK.isDate,tZ=tK&&tK.isMap,tX=tK&&tK.isRegExp,tJ=tK&&tK.isSet,tQ=tK&&tK.isTypedArray;function t1(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function t0(e,t,n,r){for(var i=-1,a=null==e?0:e.length;++i-1}function t9(e,t,n){for(var r=-1,i=null==e?0:e.length;++r-1;);return n}function nk(e,t){for(var n=e.length;n--&&nu(t,e[n],0)>-1;);return n}function nx(e,t){for(var n=e.length,r=0;n--;)e[n]===t&&++r;return r}var nT=nh(tN),nM=nh(tP);function nO(e){return"\\"+tj[e]}function nA(e,t){return null==e?i:e[t]}function nL(e){return tO.test(e)}function nC(e){return tA.test(e)}function nI(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}function nD(e){var t=-1,n=Array(e.size);return e.forEach(function(e,r){n[++t]=[r,e]}),n}function nN(e,t){return function(n){return e(t(n))}}function nP(e,t){for(var n=-1,r=e.length,i=0,a=[];++n-1}function rh(e,t){var n=this.__data__,r=rP(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}function rp(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t=t?e:t)),e}function rH(e,t,n,r,a,o){var s,u=t&h,c=t&p,l=t&b;if(n&&(s=a?n(e,r,a,o):n(e)),s!==i)return s;if(!u1(e))return e;var f=uF(e);if(f){if(s=a9(e),!u)return al(e,s)}else{var d=a3(e),m=d==Z||d==X;if(u$(e))return ae(e,u);if(d==et||d==$||m&&!a){if(s=c||m?{}:a8(e),!u)return c?ah(e,rF(s,e)):ad(e,rj(s,e))}else{if(!tD[d])return a?e:{};s=a7(e,d,u)}}o||(o=new rS);var g=o.get(e);if(g)return g;o.set(e,s),cr(e)?e.forEach(function(r){s.add(rH(r,t,n,r,e,o))}):u2(e)&&e.forEach(function(r,i){s.set(i,rH(r,t,n,i,e,o))});var v=l?c?aW:aG:c?c$:cH,y=f?i:v(e);return t2(y||e,function(r,i){y&&(r=e[i=r]),rN(s,i,rH(r,t,n,i,e,o))}),s}function r$(e){var t=cH(e);return function(n){return rz(n,e,t)}}function rz(e,t,n){var r=n.length;if(null==e)return!r;for(e=e4(e);r--;){var a=n[r],o=t[a],s=e[a];if(s===i&&!(a in e)||!o(s))return!1}return!0}function rG(e,t,n){if("function"!=typeof e)throw new e9(u);return o_(function(){e.apply(i,n)},t)}function rW(e,t,n,r){var i=-1,a=t6,s=!0,u=e.length,c=[],l=t.length;if(!u)return c;n&&(t=t8(t,nw(n))),r?(a=t9,s=!1):t.length>=o&&(a=nE,s=!1,t=new rw(t));outer:for(;++ia?0:a+n),(r=r===i||r>a?a:cp(r))<0&&(r+=a),r=n>r?0:cb(r);n0&&n(s)?t>1?rQ(s,t-1,n,r,i):t7(i,s):r||(i[i.length]=s)}return i}var r1=ag(),r0=ag(!0);function r2(e,t){return e&&r1(e,t,cH)}function r3(e,t){return e&&r0(e,t,cH)}function r4(e,t){return t5(t,function(t){return uX(e[t])})}function r5(e,t){t=i6(t,e);for(var n=0,r=t.length;null!=e&&nt}function r7(e,t){return null!=e&&tr.call(e,t)}function ie(e,t){return null!=e&&t in e4(e)}function it(e,t,n){return e>=tU(t,n)&&e=120&&f.length>=120)?new rw(s&&f):i}f=e[0];var d=-1,h=u[0];outer:for(;++d-1;)s!==e&&tg.call(s,u,1),tg.call(e,u,1);return e}function iD(e,t){for(var n=e?t.length:0,r=n-1;n--;){var i=t[n];if(n==r||i!==a){var a=i;on(i)?tg.call(e,i,1):iJ(e,i)}}return e}function iN(e,t){return e+tO(tW()*(t-e+1))}function iP(e,t,n,r){for(var i=-1,a=tB(tM((t-e)/(n||1)),0),o=eF(a);a--;)o[r?a:++i]=e,e+=n;return o}function iR(e,t){var n="";if(!e||t<1||t>R)return n;do t%2&&(n+=e),(t=tO(t/2))&&(e+=e);while(t)return n}function ij(e,t){return oE(om(e,t,lB),e+"")}function iF(e){return rL(c9(e))}function iY(e,t){var n=c9(e);return ox(n,rU(t,0,n.length))}function iB(e,t,n,r){if(!u1(e))return e;t=i6(t,e);for(var a=-1,o=t.length,s=o-1,u=e;null!=u&&++ai?0:i+t),(n=n>i?i:n)<0&&(n+=i),i=t>n?0:n-t>>>0,t>>>=0;for(var a=eF(i);++r>>1,o=e[a];null!==o&&!ca(o)&&(n?o<=t:o=o){var l=t?null:aP(e);if(l)return nR(l);s=!1,i=nE,c=new rw}else c=t?[]:u;outer:for(;++r=r?e:iz(e,t,n)}var i7=tE||function(e){return tH.clearTimeout(e)};function ae(e,t){if(t)return e.slice();var n=e.length,r=th?th(n):new e.constructor(n);return e.copy(r),r}function at(e){var t=new e.constructor(e.byteLength);return new td(t).set(new td(e)),t}function an(e,t){var n=t?at(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}function ar(e){var t=new e.constructor(e.source,eW.exec(e));return t.lastIndex=e.lastIndex,t}function ai(e){return n2?e4(n2.call(e)):{}}function aa(e,t){var n=t?at(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}function ao(e,t){if(e!==t){var n=e!==i,r=null===e,a=e==e,o=ca(e),s=t!==i,u=null===t,c=t==t,l=ca(t);if(!u&&!l&&!o&&e>t||o&&s&&c&&!u&&!l||r&&s&&c||!n&&c||!a)return 1;if(!r&&!o&&!l&&e=s)return u;return u*("desc"==n[r]?-1:1)}}return e.index-t.index}function au(e,t,n,r){for(var i=-1,a=e.length,o=n.length,s=-1,u=t.length,c=tB(a-o,0),l=eF(u+c),f=!r;++s1?n[a-1]:i,s=a>2?n[2]:i;for(o=e.length>3&&"function"==typeof o?(a--,o):i,s&&or(n[0],n[1],s)&&(o=a<3?i:o,a=1),t=e4(t);++r-1?a[o?t[s]:s]:i}}function ak(e){return az(function(t){var n=t.length,r=n,a=n9.prototype.thru;for(e&&t.reverse();r--;){var o=t[r];if("function"!=typeof o)throw new e9(u);if(a&&!s&&"wrapper"==aV(o))var s=new n9([],!0)}for(r=s?r:n;++r1&&v.reverse(),f&&cu))return!1;var l=o.get(e),f=o.get(t);if(l&&f)return l==t&&f==e;var d=-1,h=!0,p=n&g?new rw:i;for(o.set(e,t),o.set(t,e);++d1?"& ":"")+t[r],t=t.join(n>2?", ":" "),e.replace(eY,"{\n/* [wrapped with "+t+"] */\n")}function ot(e){return uF(e)||uj(e)||!!(tv&&e&&e[tv])}function on(e,t){var n=typeof e;return!!(t=null==t?R:t)&&("number"==n||"symbol"!=n&&eX.test(e))&&e>-1&&e%1==0&&e0){if(++t>=L)return arguments[0]}else t=0;return e.apply(i,arguments)}}function ox(e,t){var n=-1,r=e.length,a=r-1;for(t=t===i?r:t;++n1?e[t-1]:i;return n="function"==typeof n?(e.pop(),n):i,sE(e,n)});function sC(e){var t=n4(e);return t.__chain__=!0,t}function sI(e,t){return t(e),e}function sD(e,t){return t(e)}var sN=az(function(e){var t=e.length,n=t?e[0]:0,r=this.__wrapped__,a=function(t){return rB(t,e)};return!(t>1)&&!this.__actions__.length&&r instanceof n8&&on(n)?((r=r.slice(n,+n+(t?1:0))).__actions__.push({func:sD,args:[a],thisArg:i}),new n9(r,this.__chain__).thru(function(e){return t&&!e.length&&e.push(i),e})):this.thru(a)});function sP(){return sC(this)}function sR(){return new n9(this.value(),this.__chain__)}function sj(){i===this.__values__&&(this.__values__=cd(this.value()));var e=this.__index__>=this.__values__.length,t=e?i:this.__values__[this.__index__++];return{done:e,value:t}}function sF(){return this}function sY(e){for(var t,n=this;n instanceof n6;){var r=oL(n);r.__index__=0,r.__values__=i,t?a.__wrapped__=r:t=r;var a=r;n=n.__wrapped__}return a.__wrapped__=e,t}function sB(){var e=this.__wrapped__;if(e instanceof n8){var t=e;return this.__actions__.length&&(t=new n8(this)),(t=t.reverse()).__actions__.push({func:sD,args:[se],thisArg:i}),new n9(t,this.__chain__)}return this.thru(se)}function sU(){return i0(this.__wrapped__,this.__actions__)}var sH=ap(function(e,t,n){tr.call(e,n)?++e[n]:rY(e,n,1)});function s$(e,t,n){var r=uF(e)?t4:rq;return n&&or(e,t,n)&&(t=i),r(e,aZ(t,3))}function sz(e,t){return(uF(e)?t5:rJ)(e,aZ(t,3))}var sG=aS(oH),sW=aS(o$);function sK(e,t){return rQ(s2(e,t),1)}function sV(e,t){return rQ(s2(e,t),P)}function sq(e,t,n){return n=n===i?1:cp(n),rQ(s2(e,t),n)}function sZ(e,t){return(uF(e)?t2:rK)(e,aZ(t,3))}function sX(e,t){return(uF(e)?t3:rV)(e,aZ(t,3))}var sJ=ap(function(e,t,n){tr.call(e,n)?e[n].push(t):rY(e,n,[t])});function sQ(e,t,n,r){e=uB(e)?e:c9(e),n=n&&!r?cp(n):0;var i=e.length;return n<0&&(n=tB(i+n,0)),ci(e)?n<=i&&e.indexOf(t,n)>-1:!!i&&nu(e,t,n)>-1}var s1=ij(function(e,t,n){var r=-1,i="function"==typeof t,a=uB(e)?eF(e.length):[];return rK(e,function(e){a[++r]=i?t1(t,e,n):ia(e,t,n)}),a}),s0=ap(function(e,t,n){rY(e,n,t)});function s2(e,t){return(uF(e)?t8:iE)(e,aZ(t,3))}function s3(e,t,n,r){return null==e?[]:(uF(t)||(t=null==t?[]:[t]),n=r?i:n,uF(n)||(n=null==n?[]:[n]),iO(e,t,n))}var s4=ap(function(e,t,n){e[n?0:1].push(t)},function(){return[[],[]]});function s5(e,t,n){var r=uF(e)?ne:np,i=arguments.length<3;return r(e,aZ(t,4),n,i,rK)}function s6(e,t,n){var r=uF(e)?nt:np,i=arguments.length<3;return r(e,aZ(t,4),n,i,rV)}function s9(e,t){return(uF(e)?t5:rJ)(e,ug(aZ(t,3)))}function s8(e){return(uF(e)?rL:iF)(e)}function s7(e,t,n){return t=(n?or(e,t,n):t===i)?1:cp(t),(uF(e)?rC:iY)(e,t)}function ue(e){return(uF(e)?rI:i$)(e)}function ut(e){if(null==e)return 0;if(uB(e))return ci(e)?nB(e):e.length;var t=a3(e);return t==J||t==ea?e.size:iy(e).length}function un(e,t,n){var r=uF(e)?nn:iG;return n&&or(e,t,n)&&(t=i),r(e,aZ(t,3))}var ur=ij(function(e,t){if(null==e)return[];var n=t.length;return n>1&&or(e,t[0],t[1])?t=[]:n>2&&or(t[0],t[1],t[2])&&(t=[t[0]]),iO(e,rQ(t,1),[])}),ui=tS||function(){return tH.Date.now()};function ua(e,t){if("function"!=typeof t)throw new e9(u);return e=cp(e),function(){if(--e<1)return t.apply(this,arguments)}}function uo(e,t,n){return t=n?i:t,t=e&&null==t?e.length:t,aj(e,x,i,i,i,i,t)}function us(e,t){var n;if("function"!=typeof t)throw new e9(u);return e=cp(e),function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=i),n}}var uu=ij(function(e,t,n){var r=v;if(n.length){var i=nP(n,aq(uu));r|=S}return aj(e,r,t,n,i)}),uc=ij(function(e,t,n){var r=v|y;if(n.length){var i=nP(n,aq(uc));r|=S}return aj(t,r,e,n,i)});function ul(e,t,n){t=n?i:t;var r=aj(e,_,i,i,i,i,i,t);return r.placeholder=ul.placeholder,r}function uf(e,t,n){t=n?i:t;var r=aj(e,E,i,i,i,i,i,t);return r.placeholder=uf.placeholder,r}function ud(e,t,n){var r,a,o,s,c,l,f=0,d=!1,h=!1,p=!0;if("function"!=typeof e)throw new e9(u);function b(t){var n=r,o=a;return r=a=i,f=t,s=e.apply(o,n)}function m(e){return f=e,c=o_(y,t),d?b(e):s}function g(e){var n=e-l,r=e-f,i=t-n;return h?tU(i,o-r):i}function v(e){var n=e-l,r=e-f;return l===i||n>=t||n<0||h&&r>=o}function y(){var e=ui();if(v(e))return w(e);c=o_(y,g(e))}function w(e){return(c=i,p&&r)?b(e):(r=a=i,s)}function _(){c!==i&&i7(c),f=0,r=l=a=c=i}function E(){return c===i?s:w(ui())}function S(){var e=ui(),n=v(e);if(r=arguments,a=this,l=e,n){if(c===i)return m(l);if(h)return i7(c),c=o_(y,t),b(l)}return c===i&&(c=o_(y,t)),s}return t=cm(t)||0,u1(n)&&(d=!!n.leading,o=(h="maxWait"in n)?tB(cm(n.maxWait)||0,t):o,p="trailing"in n?!!n.trailing:p),S.cancel=_,S.flush=E,S}var uh=ij(function(e,t){return rG(e,1,t)}),up=ij(function(e,t,n){return rG(e,cm(t)||0,n)});function ub(e){return aj(e,M)}function um(e,t){if("function"!=typeof e||null!=t&&"function"!=typeof t)throw new e9(u);var n=function(){var r=arguments,i=t?t.apply(this,r):r[0],a=n.cache;if(a.has(i))return a.get(i);var o=e.apply(this,r);return n.cache=a.set(i,o)||a,o};return n.cache=new(um.Cache||rp),n}function ug(e){if("function"!=typeof e)throw new e9(u);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}function uv(e){return us(2,e)}um.Cache=rp;var uy=i9(function(e,t){var n=(t=1==t.length&&uF(t[0])?t8(t[0],nw(aZ())):t8(rQ(t,1),nw(aZ()))).length;return ij(function(r){for(var i=-1,a=tU(r.length,n);++i=t}),uj=io(function(){return arguments}())?io:function(e){return u0(e)&&tr.call(e,"callee")&&!tm.call(e,"callee")},uF=eF.isArray,uY=tV?nw(tV):is;function uB(e){return null!=e&&uQ(e.length)&&!uX(e)}function uU(e){return u0(e)&&uB(e)}function uH(e){return!0===e||!1===e||u0(e)&&r9(e)==W}var u$=tN||l4,uz=tq?nw(tq):iu;function uG(e){return u0(e)&&1===e.nodeType&&!ce(e)}function uW(e){if(null==e)return!0;if(uB(e)&&(uF(e)||"string"==typeof e||"function"==typeof e.splice||u$(e)||co(e)||uj(e)))return!e.length;var t=a3(e);if(t==J||t==ea)return!e.size;if(oc(e))return!iy(e).length;for(var n in e)if(tr.call(e,n))return!1;return!0}function uK(e,t){return ic(e,t)}function uV(e,t,n){var r=(n="function"==typeof n?n:i)?n(e,t):i;return r===i?ic(e,t,i,n):!!r}function uq(e){if(!u0(e))return!1;var t=r9(e);return t==q||t==V||"string"==typeof e.message&&"string"==typeof e.name&&!ce(e)}function uZ(e){return"number"==typeof e&&tP(e)}function uX(e){if(!u1(e))return!1;var t=r9(e);return t==Z||t==X||t==G||t==er}function uJ(e){return"number"==typeof e&&e==cp(e)}function uQ(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=R}function u1(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}function u0(e){return null!=e&&"object"==typeof e}var u2=tZ?nw(tZ):id;function u3(e,t){return e===t||ih(e,t,aJ(t))}function u4(e,t,n){return n="function"==typeof n?n:i,ih(e,t,aJ(t),n)}function u5(e){return u7(e)&&e!=+e}function u6(e){if(ou(e))throw new e0(s);return ip(e)}function u9(e){return null===e}function u8(e){return null==e}function u7(e){return"number"==typeof e||u0(e)&&r9(e)==Q}function ce(e){if(!u0(e)||r9(e)!=et)return!1;var t=tp(e);if(null===t)return!0;var n=tr.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&tn.call(n)==ts}var ct=tX?nw(tX):ib;function cn(e){return uJ(e)&&e>=-R&&e<=R}var cr=tJ?nw(tJ):im;function ci(e){return"string"==typeof e||!uF(e)&&u0(e)&&r9(e)==eo}function ca(e){return"symbol"==typeof e||u0(e)&&r9(e)==es}var co=tQ?nw(tQ):ig;function cs(e){return e===i}function cu(e){return u0(e)&&a3(e)==ec}function cc(e){return u0(e)&&r9(e)==el}var cl=aI(i_),cf=aI(function(e,t){return e<=t});function cd(e){if(!e)return[];if(uB(e))return ci(e)?nU(e):al(e);if(ty&&e[ty])return nI(e[ty]());var t=a3(e);return(t==J?nD:t==ea?nR:c9)(e)}function ch(e){return e?(e=cm(e))===P||e===-P?(e<0?-1:1)*j:e==e?e:0:0===e?e:0}function cp(e){var t=ch(e),n=t%1;return t==t?n?t-n:t:0}function cb(e){return e?rU(cp(e),0,Y):0}function cm(e){if("number"==typeof e)return e;if(ca(e))return F;if(u1(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=u1(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=ny(e);var n=eV.test(e);return n||eZ.test(e)?tY(e.slice(2),n?2:8):eK.test(e)?F:+e}function cg(e){return af(e,c$(e))}function cv(e){return e?rU(cp(e),-R,R):0===e?e:0}function cy(e){return null==e?"":iZ(e)}var cw=ab(function(e,t){if(oc(t)||uB(t)){af(t,cH(t),e);return}for(var n in t)tr.call(t,n)&&rN(e,n,t[n])}),c_=ab(function(e,t){af(t,c$(t),e)}),cE=ab(function(e,t,n,r){af(t,c$(t),e,r)}),cS=ab(function(e,t,n,r){af(t,cH(t),e,r)}),ck=az(rB);function cx(e,t){var n=n5(e);return null==t?n:rj(n,t)}var cT=ij(function(e,t){e=e4(e);var n=-1,r=t.length,a=r>2?t[2]:i;for(a&&or(t[0],t[1],a)&&(r=1);++n1),t}),af(e,aW(e),n),r&&(n=rH(n,h|p|b,aB));for(var i=t.length;i--;)iJ(n,t[i]);return n});function cq(e,t){return cX(e,ug(aZ(t)))}var cZ=az(function(e,t){return null==e?{}:iA(e,t)});function cX(e,t){if(null==e)return{};var n=t8(aW(e),function(e){return[e]});return t=aZ(t),iL(e,n,function(e,n){return t(e,n[0])})}function cJ(e,t,n){t=i6(t,e);var r=-1,a=t.length;for(a||(a=1,e=i);++rt){var r=e;e=t,t=r}if(n||e%1||t%1){var a=tW();return tU(e+a*(t-e+tF("1e-"+((a+"").length-1))),t)}return iN(e,t)}var ln=aw(function(e,t,n){return t=t.toLowerCase(),e+(n?lr(t):t)});function lr(e){return lL(cy(e).toLowerCase())}function li(e){return(e=cy(e))&&e.replace(eJ,nT).replace(tx,"")}function la(e,t,n){e=cy(e),t=iZ(t);var r=e.length,a=n=n===i?r:rU(cp(n),0,r);return(n-=t.length)>=0&&e.slice(n,a)==t}function lo(e){return(e=cy(e))&&eO.test(e)?e.replace(eT,nM):e}function ls(e){return(e=cy(e))&&eR.test(e)?e.replace(eP,"\\$&"):e}var lu=aw(function(e,t,n){return e+(n?"-":"")+t.toLowerCase()}),lc=aw(function(e,t,n){return e+(n?" ":"")+t.toLowerCase()}),ll=ay("toLowerCase");function lf(e,t,n){e=cy(e);var r=(t=cp(t))?nB(e):0;if(!t||r>=t)return e;var i=(t-r)/2;return aA(tO(i),n)+e+aA(tM(i),n)}function ld(e,t,n){e=cy(e);var r=(t=cp(t))?nB(e):0;return t&&r>>0)?(e=cy(e))&&("string"==typeof t||null!=t&&!ct(t))&&!(t=iZ(t))&&nL(e)?i8(nU(e),0,n):e.split(t,n):[]}var ly=aw(function(e,t,n){return e+(n?" ":"")+lL(t)});function lw(e,t,n){return e=cy(e),n=null==n?0:rU(cp(n),0,e.length),t=iZ(t),e.slice(n,n+t.length)==t}function l_(e,t,n){var r=n4.templateSettings;n&&or(e,t,n)&&(t=i),e=cy(e),t=cE({},t,r,aF);var a,o,s=cE({},t.imports,r.imports,aF),u=cH(s),l=n_(s,u),f=0,d=t.interpolate||eQ,h="__p += '",p=e5((t.escape||eQ).source+"|"+d.source+"|"+(d===eC?eG:eQ).source+"|"+(t.evaluate||eQ).source+"|$","g"),b="//# sourceURL="+(tr.call(t,"sourceURL")?(t.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++tC+"]")+"\n";e.replace(p,function(t,n,r,i,s,u){return r||(r=i),h+=e.slice(f,u).replace(e1,nO),n&&(a=!0,h+="' +\n__e("+n+") +\n'"),s&&(o=!0,h+="';\n"+s+";\n__p += '"),r&&(h+="' +\n((__t = ("+r+")) == null ? '' : __t) +\n'"),f=u+t.length,t}),h+="';\n";var m=tr.call(t,"variable")&&t.variable;if(m){if(e$.test(m))throw new e0(c)}else h="with (obj) {\n"+h+"\n}\n";h=(o?h.replace(eE,""):h).replace(eS,"$1").replace(ek,"$1;"),h="function("+(m||"obj")+") {\n"+(m?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(a?", __e = _.escape":"")+(o?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+h+"return __p\n}";var g=lI(function(){return e2(u,b+"return "+h).apply(i,l)});if(g.source=h,uq(g))throw g;return g}function lE(e){return cy(e).toLowerCase()}function lS(e){return cy(e).toUpperCase()}function lk(e,t,n){if((e=cy(e))&&(n||t===i))return ny(e);if(!e||!(t=iZ(t)))return e;var r=nU(e),a=nU(t),o=nS(r,a),s=nk(r,a)+1;return i8(r,o,s).join("")}function lx(e,t,n){if((e=cy(e))&&(n||t===i))return e.slice(0,nH(e)+1);if(!e||!(t=iZ(t)))return e;var r=nU(e),a=nk(r,nU(t))+1;return i8(r,0,a).join("")}function lT(e,t,n){if((e=cy(e))&&(n||t===i))return e.replace(ej,"");if(!e||!(t=iZ(t)))return e;var r=nU(e),a=nS(r,nU(t));return i8(r,a).join("")}function lM(e,t){var n=O,r=A;if(u1(t)){var a="separator"in t?t.separator:a;n="length"in t?cp(t.length):n,r="omission"in t?iZ(t.omission):r}var o=(e=cy(e)).length;if(nL(e)){var s=nU(e);o=s.length}if(n>=o)return e;var u=n-nB(r);if(u<1)return r;var c=s?i8(s,0,u).join(""):e.slice(0,u);if(a===i)return c+r;if(s&&(u+=c.length-u),ct(a)){if(e.slice(u).search(a)){var l,f=c;for(a.global||(a=e5(a.source,cy(eW.exec(a))+"g")),a.lastIndex=0;l=a.exec(f);)var d=l.index;c=c.slice(0,d===i?u:d)}}else if(e.indexOf(iZ(a),u)!=u){var h=c.lastIndexOf(a);h>-1&&(c=c.slice(0,h))}return c+r}function lO(e){return(e=cy(e))&&eM.test(e)?e.replace(ex,n$):e}var lA=aw(function(e,t,n){return e+(n?" ":"")+t.toUpperCase()}),lL=ay("toUpperCase");function lC(e,t,n){return(e=cy(e),i===(t=n?i:t))?nC(e)?nW(e):na(e):e.match(t)||[]}var lI=ij(function(e,t){try{return t1(e,i,t)}catch(n){return uq(n)?n:new e0(n)}}),lD=az(function(e,t){return t2(t,function(t){t=oM(t),rY(e,t,uu(e[t],e))}),e});function lN(e){var t=null==e?0:e.length,n=aZ();return e=t?t8(e,function(e){if("function"!=typeof e[1])throw new e9(u);return[n(e[0]),e[1]]}):[],ij(function(n){for(var r=-1;++rR)return[];var n=Y,r=tU(e,Y);t=aZ(t),e-=Y;for(var i=ng(r,t);++n0||t<0)?new n8(n):(e<0?n=n.takeRight(-e):e&&(n=n.drop(e)),t!==i&&(n=(t=cp(t))<0?n.dropRight(-t):n.take(t-e)),n)},n8.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},n8.prototype.toArray=function(){return this.take(Y)},r2(n8.prototype,function(e,t){var n=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),a=n4[r?"take"+("last"==t?"Right":""):t],o=r||/^find/.test(t);a&&(n4.prototype[t]=function(){var t=this.__wrapped__,s=r?[1]:arguments,u=t instanceof n8,c=s[0],l=u||uF(t),f=function(e){var t=a.apply(n4,t7([e],s));return r&&d?t[0]:t};l&&n&&"function"==typeof c&&1!=c.length&&(u=l=!1);var d=this.__chain__,h=!!this.__actions__.length,p=o&&!d,b=u&&!h;if(!o&&l){t=b?t:new n8(this);var m=e.apply(t,s);return m.__actions__.push({func:sD,args:[f],thisArg:i}),new n9(m,d)}return p&&b?e.apply(this,s):(m=this.thru(f),p?r?m.value()[0]:m.value():m)})}),t2(["pop","push","shift","sort","splice","unshift"],function(e){var t=e8[e],n=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",r=/^(?:pop|shift)$/.test(e);n4.prototype[e]=function(){var e=arguments;if(r&&!this.__chain__){var i=this.value();return t.apply(uF(i)?i:[],e)}return this[n](function(n){return t.apply(uF(n)?n:[],e)})}}),r2(n8.prototype,function(e,t){var n=n4[t];if(n){var r=n.name+"";tr.call(nq,r)||(nq[r]=[]),nq[r].push({name:t,func:n})}}),nq[ax(i,y).name]=[{name:"wrapper",func:i}],n8.prototype.clone=n7,n8.prototype.reverse=re,n8.prototype.value=rt,n4.prototype.at=sN,n4.prototype.chain=sP,n4.prototype.commit=sR,n4.prototype.next=sj,n4.prototype.plant=sY,n4.prototype.reverse=sB,n4.prototype.toJSON=n4.prototype.valueOf=n4.prototype.value=sU,n4.prototype.first=n4.prototype.head,ty&&(n4.prototype[ty]=sF),n4}();tH._=nK,i!==(r=(function(){return nK}).call(t,n,t,e))&&(e.exports=r)}).call(this)},35161(e,t,n){var r=n(29932),i=n(67206),a=n(69199),o=n(1469);function s(e,t){return(o(e)?r:a)(e,i(t,3))}e.exports=s},67523(e,t,n){var r=n(89465),i=n(47816),a=n(67206);function o(e,t){var n={};return t=a(t,3),i(e,function(e,i,a){r(n,t(e,i,a),e)}),n}e.exports=o},66604(e,t,n){var r=n(89465),i=n(47816),a=n(67206);function o(e,t){var n={};return t=a(t,3),i(e,function(e,i,a){r(n,i,t(e,i,a))}),n}e.exports=o},88306(e,t,n){var r=n(83369),i="Expected a function";function a(e,t){if("function"!=typeof e||null!=t&&"function"!=typeof t)throw TypeError(i);var n=function(){var r=arguments,i=t?t.apply(this,r):r[0],a=n.cache;if(a.has(i))return a.get(i);var o=e.apply(this,r);return n.cache=a.set(i,o)||a,o};return n.cache=new(a.Cache||r),n}a.Cache=r,e.exports=a},82492(e,t,n){var r=n(42980),i=n(21463)(function(e,t,n){r(e,t,n)});e.exports=i},50308(e){function t(){}e.exports=t},7771(e,t,n){var r=n(55639),i=function(){return r.Date.now()};e.exports=i},78718(e,t,n){var r=n(25970),i=n(99021)(function(e,t){return null==e?{}:r(e,t)});e.exports=i},39601(e,t,n){var r=n(40371),i=n(79152),a=n(15403),o=n(40327);function s(e){return a(e)?r(o(e)):i(e)}e.exports=s},54061(e,t,n){var r=n(62663),i=n(89881),a=n(67206),o=n(10107),s=n(1469);function u(e,t,n){var u=s(e)?r:o,c=arguments.length<3;return u(e,a(t,4),n,c,i)}e.exports=u},84238(e,t,n){var r=n(280),i=n(64160),a=n(98612),o=n(47037),s=n(88016),u="[object Map]",c="[object Set]";function l(e){if(null==e)return 0;if(a(e))return o(e)?s(e):e.length;var t=i(e);return t==u||t==c?e.size:r(e).length}e.exports=l},11865(e,t,n){var r=n(35393)(function(e,t,n){return e+(n?"_":"")+t.toLowerCase()});e.exports=r},70479(e){function t(){return[]}e.exports=t},95062(e){function t(){return!1}e.exports=t},14841(e,t,n){var r=n(27561),i=n(13218),a=n(33448),o=0/0,s=/^[-+]0x[0-9a-f]+$/i,u=/^0b[01]+$/i,c=/^0o[0-7]+$/i,l=parseInt;function f(e){if("number"==typeof e)return e;if(a(e))return o;if(i(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=i(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=r(e);var n=u.test(e);return n||c.test(e)?l(e.slice(2),n?2:8):s.test(e)?o:+e}e.exports=f},59881(e,t,n){var r=n(98363),i=n(81704);function a(e){return r(e,i(e))}e.exports=a},79833(e,t,n){var r=n(80531);function i(e){return null==e?"":r(e)}e.exports=i},68718(e,t,n){var r=n(77412),i=n(3118),a=n(47816),o=n(67206),s=n(85924),u=n(1469),c=n(44144),l=n(23560),f=n(13218),d=n(36719);function h(e,t,n){var h=u(e),p=h||c(e)||d(e);if(t=o(t,4),null==n){var b=e&&e.constructor;n=p?h?new b:[]:f(e)&&l(b)?i(s(e)):{}}return(p?r:a)(e,function(e,r,i){return t(n,e,r,i)}),n}e.exports=h},93386(e,t,n){var r=n(21078),i=n(5976),a=n(45652),o=n(29246),s=i(function(e){return a(r(e,1,o,!0))});e.exports=s},11700(e,t,n){var r=n(98805)("toUpperCase");e.exports=r},52628(e,t,n){var r=n(47415),i=n(3674);function a(e){return null==e?[]:r(e,i(e))}e.exports=a},58748(e,t,n){var r=n(49029),i=n(93157),a=n(79833),o=n(2757);function s(e,t,n){return(e=a(e),void 0===(t=n?void 0:t))?i(e)?o(e):r(e):e.match(t)||[]}e.exports=s},42786:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"),weekdays:"Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"),weekdaysShort:"Son_Maa_Din_Woe_Don_Vry_Sat".split("_"),weekdaysMin:"So_Ma_Di_Wo_Do_Vr_Sa".split("_"),meridiemParse:/vm|nm/i,isPM:function(e){return/^nm$/i.test(e)},meridiem:function(e,t,n){return e<12?n?"vm":"VM":n?"nm":"NM"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Vandag om] LT",nextDay:"[M\xf4re om] LT",nextWeek:"dddd [om] LT",lastDay:"[Gister om] LT",lastWeek:"[Laas] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oor %s",past:"%s gelede",s:"'n paar sekondes",ss:"%d sekondes",m:"'n minuut",mm:"%d minute",h:"'n uur",hh:"%d ure",d:"'n dag",dd:"%d dae",M:"'n maand",MM:"%d maande",y:"'n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})})(n(30381))},14130:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},n={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية",],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة",],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة",],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم",],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر",],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام",]},r=function(e){return function(r,i,a,o){var s=t(r),u=n[e][t(r)];return 2===s&&(u=u[i?0:1]),u.replace(/%d/i,r)}},i=["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويلية","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر",];return e.defineLocale("ar-dz",{months:i,monthsShort:i,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,n){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:r("s"),ss:r("s"),m:r("m"),mm:r("m"),h:r("h"),hh:r("h"),d:r("d"),dd:r("d"),M:r("M"),MM:r("M"),y:r("y"),yy:r("y")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:0,doy:4}})})(n(30381))},96135:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ar-kw",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:0,doy:12}})})(n(30381))},56440:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",0:"0"},n=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},r={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية",],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة",],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة",],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم",],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر",],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام",]},i=function(e){return function(t,i,a,o){var s=n(t),u=r[e][n(t)];return 2===s&&(u=u[i?0:1]),u.replace(/%d/i,t)}},a=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",];return e.defineLocale("ar-ly",{months:a,monthsShort:a,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,n){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:i("s"),ss:i("s"),m:i("m"),mm:i("m"),h:i("h"),hh:i("h"),d:i("d"),dd:i("d"),M:i("M"),MM:i("M"),y:i("y"),yy:i("y")},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]}).replace(/,/g,"،")},week:{dow:6,doy:12}})})(n(30381))},47702:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ar-ma",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})})(n(30381))},16040:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},n={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};return e.defineLocale("ar-sa",{months:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,n){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,function(e){return n[e]}).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]}).replace(/,/g,"،")},week:{dow:0,doy:6}})})(n(30381))},37100:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ar-tn",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})})(n(30381))},30867:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},n={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},r=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},i={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية",],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة",],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة",],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم",],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر",],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام",]},a=function(e){return function(t,n,a,o){var s=r(t),u=i[e][r(t)];return 2===s&&(u=u[n?0:1]),u.replace(/%d/i,t)}},o=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",];return e.defineLocale("ar",{months:o,monthsShort:o,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,n){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:a("s"),ss:a("s"),m:a("m"),mm:a("m"),h:a("h"),hh:a("h"),d:a("d"),dd:a("d"),M:a("M"),MM:a("M"),y:a("y"),yy:a("y")},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,function(e){return n[e]}).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]}).replace(/,/g,"،")},week:{dow:6,doy:12}})})(n(30381))},31083:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"-inci",5:"-inci",8:"-inci",70:"-inci",80:"-inci",2:"-nci",7:"-nci",20:"-nci",50:"-nci",3:"-\xfcnc\xfc",4:"-\xfcnc\xfc",100:"-\xfcnc\xfc",6:"-ncı",9:"-uncu",10:"-uncu",30:"-uncu",60:"-ıncı",90:"-ıncı"};return e.defineLocale("az",{months:"yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"),monthsShort:"yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"),weekdays:"Bazar_Bazar ertəsi_\xc7ərşənbə axşamı_\xc7ərşənbə_C\xfcmə axşamı_C\xfcmə_Şənbə".split("_"),weekdaysShort:"Baz_BzE_\xc7Ax_\xc7ər_CAx_C\xfcm_Şən".split("_"),weekdaysMin:"Bz_BE_\xc7A_\xc7ə_CA_C\xfc_Şə".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bug\xfcn saat] LT",nextDay:"[sabah saat] LT",nextWeek:"[gələn həftə] dddd [saat] LT",lastDay:"[d\xfcnən] LT",lastWeek:"[ke\xe7ən həftə] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s əvvəl",s:"bir ne\xe7ə saniyə",ss:"%d saniyə",m:"bir dəqiqə",mm:"%d dəqiqə",h:"bir saat",hh:"%d saat",d:"bir g\xfcn",dd:"%d g\xfcn",M:"bir ay",MM:"%d ay",y:"bir il",yy:"%d il"},meridiemParse:/gecə|səhər|gündüz|axşam/,isPM:function(e){return/^(gündüz|axşam)$/.test(e)},meridiem:function(e,t,n){return e<4?"gecə":e<12?"səhər":e<17?"g\xfcnd\xfcz":"axşam"},dayOfMonthOrdinalParse:/\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,ordinal:function(e){if(0===e)return e+"-ıncı";var n=e%10,r=e%100-n,i=e>=100?100:null;return e+(t[n]||t[r]||t[i])},week:{dow:1,doy:7}})})(n(30381))},9808:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t){var n=e.split("_");return t%10==1&&t%100!=11?n[0]:t%10>=2&&t%10<=4&&(t%100<10||t%100>=20)?n[1]:n[2]}function n(e,n,r){var i={ss:n?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:n?"хвіліна_хвіліны_хвілін":"хвіліну_хвіліны_хвілін",hh:n?"гадзіна_гадзіны_гадзін":"гадзіну_гадзіны_гадзін",dd:"дзень_дні_дзён",MM:"месяц_месяцы_месяцаў",yy:"год_гады_гадоў"};return"m"===r?n?"хвіліна":"хвіліну":"h"===r?n?"гадзіна":"гадзіну":e+" "+t(i[r],+e)}return e.defineLocale("be",{months:{format:"студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня".split("_"),standalone:"студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань".split("_")},monthsShort:"студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж".split("_"),weekdays:{format:"нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу".split("_"),standalone:"нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота".split("_"),isFormat:/\[ ?[Ууў] ?(?:мінулую|наступную)? ?\] ?dddd/},weekdaysShort:"нд_пн_ат_ср_чц_пт_сб".split("_"),weekdaysMin:"нд_пн_ат_ср_чц_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сёння ў] LT",nextDay:"[Заўтра ў] LT",lastDay:"[Учора ў] LT",nextWeek:function(){return"[У] dddd [ў] LT"},lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return"[У мінулую] dddd [ў] LT";case 1:case 2:case 4:return"[У мінулы] dddd [ў] LT"}},sameElse:"L"},relativeTime:{future:"праз %s",past:"%s таму",s:"некалькі секунд",m:n,mm:n,h:n,hh:n,d:"дзень",dd:n,M:"месяц",MM:n,y:"год",yy:n},meridiemParse:/ночы|раніцы|дня|вечара/,isPM:function(e){return/^(дня|вечара)$/.test(e)},meridiem:function(e,t,n){return e<4?"ночы":e<12?"раніцы":e<17?"дня":"вечара"},dayOfMonthOrdinalParse:/\d{1,2}-(і|ы|га)/,ordinal:function(e,t){switch(t){case"M":case"d":case"DDD":case"w":case"W":return(e%10==2||e%10==3)&&e%100!=12&&e%100!=13?e+"-і":e+"-ы";case"D":return e+"-га";default:return e}},week:{dow:1,doy:7}})})(n(30381))},68338:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("bg",{months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"яну_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Днес в] LT",nextDay:"[Утре в] LT",nextWeek:"dddd [в] LT",lastDay:"[Вчера в] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Миналата] dddd [в] LT";case 1:case 2:case 4:case 5:return"[Миналия] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",ss:"%d секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",w:"седмица",ww:"%d седмици",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var t=e%10,n=e%100;if(0===e)return e+"-ев";if(0===n)return e+"-ен";if(n>10&&n<20)return e+"-ти";if(1===t)return e+"-ви";if(2===t)return e+"-ри";else if(7===t||8===t)return e+"-ми";else return e+"-ти"},week:{dow:1,doy:7}})})(n(30381))},67438:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("bm",{months:"Zanwuyekalo_Fewuruyekalo_Marisikalo_Awirilikalo_Mɛkalo_Zuwɛnkalo_Zuluyekalo_Utikalo_Sɛtanburukalo_ɔkutɔburukalo_Nowanburukalo_Desanburukalo".split("_"),monthsShort:"Zan_Few_Mar_Awi_Mɛ_Zuw_Zul_Uti_Sɛt_ɔku_Now_Des".split("_"),weekdays:"Kari_Ntɛnɛn_Tarata_Araba_Alamisa_Juma_Sibiri".split("_"),weekdaysShort:"Kar_Ntɛ_Tar_Ara_Ala_Jum_Sib".split("_"),weekdaysMin:"Ka_Nt_Ta_Ar_Al_Ju_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"MMMM [tile] D [san] YYYY",LLL:"MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm",LLLL:"dddd MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm"},calendar:{sameDay:"[Bi lɛrɛ] LT",nextDay:"[Sini lɛrɛ] LT",nextWeek:"dddd [don lɛrɛ] LT",lastDay:"[Kunu lɛrɛ] LT",lastWeek:"dddd [tɛmɛnen lɛrɛ] LT",sameElse:"L"},relativeTime:{future:"%s kɔnɔ",past:"a bɛ %s bɔ",s:"sanga dama dama",ss:"sekondi %d",m:"miniti kelen",mm:"miniti %d",h:"lɛrɛ kelen",hh:"lɛrɛ %d",d:"tile kelen",dd:"tile %d",M:"kalo kelen",MM:"kalo %d",y:"san kelen",yy:"san %d"},week:{dow:1,doy:4}})})(n(30381))},76225:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},n={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};return e.defineLocale("bn-bd",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/রাত|ভোর|সকাল|দুপুর|বিকাল|সন্ধ্যা|রাত/,meridiemHour:function(e,t){if(12===e&&(e=0),"রাত"===t)return e<4?e:e+12;if("ভোর"===t)return e;if("সকাল"===t)return e;if("দুপুর"===t)return e>=3?e:e+12;if("বিকাল"===t)return e+12;else if("সন্ধ্যা"===t)return e+12},meridiem:function(e,t,n){if(e<4)return"রাত";if(e<6)return"ভোর";if(e<12)return"সকাল";if(e<15)return"দুপুর";if(e<18)return"বিকাল";else if(e<20)return"সন্ধ্যা";else return"রাত"},week:{dow:0,doy:6}})})(n(30381))},8905:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},n={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};return e.defineLocale("bn",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/রাত|সকাল|দুপুর|বিকাল|রাত/,meridiemHour:function(e,t){return(12===e&&(e=0),"রাত"===t&&e>=4||"দুপুর"===t&&e<5||"বিকাল"===t)?e+12:e},meridiem:function(e,t,n){return e<4?"রাত":e<10?"সকাল":e<17?"দুপুর":e<20?"বিকাল":"রাত"},week:{dow:0,doy:6}})})(n(30381))},11560:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"༡",2:"༢",3:"༣",4:"༤",5:"༥",6:"༦",7:"༧",8:"༨",9:"༩",0:"༠"},n={"༡":"1","༢":"2","༣":"3","༤":"4","༥":"5","༦":"6","༧":"7","༨":"8","༩":"9","༠":"0"};return e.defineLocale("bo",{months:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),monthsShort:"ཟླ་1_ཟླ་2_ཟླ་3_ཟླ་4_ཟླ་5_ཟླ་6_ཟླ་7_ཟླ་8_ཟླ་9_ཟླ་10_ཟླ་11_ཟླ་12".split("_"),monthsShortRegex:/^(ཟླ་\d{1,2})/,monthsParseExact:!0,weekdays:"གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་".split("_"),weekdaysShort:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),weekdaysMin:"ཉི_ཟླ_མིག_ལྷག_ཕུར_སངས_སྤེན".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[དི་རིང] LT",nextDay:"[སང་ཉིན] LT",nextWeek:"[བདུན་ཕྲག་རྗེས་མ], LT",lastDay:"[ཁ་སང] LT",lastWeek:"[བདུན་ཕྲག་མཐའ་མ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ལ་",past:"%s སྔན་ལ",s:"ལམ་སང",ss:"%d སྐར་ཆ།",m:"སྐར་མ་གཅིག",mm:"%d སྐར་མ",h:"ཆུ་ཚོད་གཅིག",hh:"%d ཆུ་ཚོད",d:"ཉིན་གཅིག",dd:"%d ཉིན་",M:"ཟླ་བ་གཅིག",MM:"%d ཟླ་བ",y:"ལོ་གཅིག",yy:"%d ལོ"},preparse:function(e){return e.replace(/[༡༢༣༤༥༦༧༨༩༠]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,meridiemHour:function(e,t){return(12===e&&(e=0),"མཚན་མོ"===t&&e>=4||"ཉིན་གུང"===t&&e<5||"དགོང་དག"===t)?e+12:e},meridiem:function(e,t,n){return e<4?"མཚན་མོ":e<10?"ཞོགས་ཀས":e<17?"ཉིན་གུང":e<20?"དགོང་དག":"མཚན་མོ"},week:{dow:0,doy:6}})})(n(30381))},1278:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n){return e+" "+i({mm:"munutenn",MM:"miz",dd:"devezh"}[n],e)}function n(e){switch(r(e)){case 1:case 3:case 4:case 5:case 9:return e+" bloaz";default:return e+" vloaz"}}function r(e){return e>9?r(e%10):e}function i(e,t){return 2===t?a(e):e}function a(e){var t={m:"v",b:"v",d:"z"};return void 0===t[e.charAt(0)]?e:t[e.charAt(0)]+e.substring(1)}var o=[/^gen/i,/^c[ʼ\']hwe/i,/^meu/i,/^ebr/i,/^mae/i,/^(mez|eve)/i,/^gou/i,/^eos/i,/^gwe/i,/^her/i,/^du/i,/^ker/i,],s=/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu|gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,u=/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu)/i,c=/^(gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,l=[/^sul/i,/^lun/i,/^meurzh/i,/^merc[ʼ\']her/i,/^yaou/i,/^gwener/i,/^sadorn/i,],f=[/^Sul/i,/^Lun/i,/^Meu/i,/^Mer/i,/^Yao/i,/^Gwe/i,/^Sad/i,],d=[/^Su/i,/^Lu/i,/^Me([^r]|$)/i,/^Mer/i,/^Ya/i,/^Gw/i,/^Sa/i,];return e.defineLocale("br",{months:"Genver_Cʼhwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"),monthsShort:"Gen_Cʼhwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"),weekdays:"Sul_Lun_Meurzh_Mercʼher_Yaou_Gwener_Sadorn".split("_"),weekdaysShort:"Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"),weekdaysMin:"Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"),weekdaysParse:d,fullWeekdaysParse:l,shortWeekdaysParse:f,minWeekdaysParse:d,monthsRegex:s,monthsShortRegex:s,monthsStrictRegex:u,monthsShortStrictRegex:c,monthsParse:o,longMonthsParse:o,shortMonthsParse:o,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [a viz] MMMM YYYY",LLL:"D [a viz] MMMM YYYY HH:mm",LLLL:"dddd, D [a viz] MMMM YYYY HH:mm"},calendar:{sameDay:"[Hiziv da] LT",nextDay:"[Warcʼhoazh da] LT",nextWeek:"dddd [da] LT",lastDay:"[Decʼh da] LT",lastWeek:"dddd [paset da] LT",sameElse:"L"},relativeTime:{future:"a-benn %s",past:"%s ʼzo",s:"un nebeud segondenno\xf9",ss:"%d eilenn",m:"ur vunutenn",mm:t,h:"un eur",hh:"%d eur",d:"un devezh",dd:t,M:"ur miz",MM:t,y:"ur bloaz",yy:n},dayOfMonthOrdinalParse:/\d{1,2}(añ|vet)/,ordinal:function(e){var t=1===e?"a\xf1":"vet";return e+t},week:{dow:1,doy:4},meridiemParse:/a.m.|g.m./,isPM:function(e){return"g.m."===e},meridiem:function(e,t,n){return e<12?"a.m.":"g.m."}})})(n(30381))},80622:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n){var r=e+" ";switch(n){case"ss":return 1===e?r+="sekunda":2===e||3===e||4===e?r+="sekunde":r+="sekundi",r;case"m":return t?"jedna minuta":"jedne minute";case"mm":return 1===e?r+="minuta":2===e||3===e||4===e?r+="minute":r+="minuta",r;case"h":return t?"jedan sat":"jednog sata";case"hh":return 1===e?r+="sat":2===e||3===e||4===e?r+="sata":r+="sati",r;case"dd":return 1===e?r+="dan":r+="dana",r;case"MM":return 1===e?r+="mjesec":2===e||3===e||4===e?r+="mjeseca":r+="mjeseci",r;case"yy":return 1===e?r+="godina":2===e||3===e||4===e?r+="godine":r+="godina",r}}return e.defineLocale("bs",{months:"januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:t,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})})(n(30381))},2468:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ca",{months:{standalone:"gener_febrer_mar\xe7_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"),format:"de gener_de febrer_de mar\xe7_d'abril_de maig_de juny_de juliol_d'agost_de setembre_d'octubre_de novembre_de desembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._mar\xe7_abr._maig_juny_jul._ag._set._oct._nov._des.".split("_"),monthsParseExact:!0,weekdays:"diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dt._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dt_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a les] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a les] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:function(){return"[avui a "+(1!==this.hours()?"les":"la")+"] LT"},nextDay:function(){return"[dem\xe0 a "+(1!==this.hours()?"les":"la")+"] LT"},nextWeek:function(){return"dddd [a "+(1!==this.hours()?"les":"la")+"] LT"},lastDay:function(){return"[ahir a "+(1!==this.hours()?"les":"la")+"] LT"},lastWeek:function(){return"[el] dddd [passat a "+(1!==this.hours()?"les":"la")+"] LT"},sameElse:"L"},relativeTime:{future:"d'aqu\xed %s",past:"fa %s",s:"uns segons",ss:"%d segons",m:"un minut",mm:"%d minuts",h:"una hora",hh:"%d hores",d:"un dia",dd:"%d dies",M:"un mes",MM:"%d mesos",y:"un any",yy:"%d anys"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,t){var n=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"\xe8";return("w"===t||"W"===t)&&(n="a"),e+n},week:{dow:1,doy:4}})})(n(30381))},5822:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="leden_\xfanor_březen_duben_květen_červen_červenec_srpen_z\xe1ř\xed_ř\xedjen_listopad_prosinec".split("_"),n="led_\xfano_bře_dub_kvě_čvn_čvc_srp_z\xe1ř_ř\xedj_lis_pro".split("_"),r=[/^led/i,/^úno/i,/^bře/i,/^dub/i,/^kvě/i,/^(čvn|červen$|června)/i,/^(čvc|červenec|července)/i,/^srp/i,/^zář/i,/^říj/i,/^lis/i,/^pro/i,],i=/^(leden|únor|březen|duben|květen|červenec|července|červen|června|srpen|září|říjen|listopad|prosinec|led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i;function a(e){return e>1&&e<5&&1!=~~(e/10)}function o(e,t,n,r){var i=e+" ";switch(n){case"s":return t||r?"p\xe1r sekund":"p\xe1r sekundami";case"ss":if(t||r)return i+(a(e)?"sekundy":"sekund");return i+"sekundami";case"m":return t?"minuta":r?"minutu":"minutou";case"mm":if(t||r)return i+(a(e)?"minuty":"minut");return i+"minutami";case"h":return t?"hodina":r?"hodinu":"hodinou";case"hh":if(t||r)return i+(a(e)?"hodiny":"hodin");return i+"hodinami";case"d":return t||r?"den":"dnem";case"dd":if(t||r)return i+(a(e)?"dny":"dn\xed");return i+"dny";case"M":return t||r?"měs\xedc":"měs\xedcem";case"MM":if(t||r)return i+(a(e)?"měs\xedce":"měs\xedců");return i+"měs\xedci";case"y":return t||r?"rok":"rokem";case"yy":if(t||r)return i+(a(e)?"roky":"let");return i+"lety"}}return e.defineLocale("cs",{months:t,monthsShort:n,monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(leden|ledna|února|únor|březen|března|duben|dubna|květen|května|červenec|července|červen|června|srpen|srpna|září|říjen|října|listopadu|listopad|prosinec|prosince)/i,monthsShortStrictRegex:/^(led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i,monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"neděle_ponděl\xed_\xfater\xfd_středa_čtvrtek_p\xe1tek_sobota".split("_"),weekdaysShort:"ne_po_\xfat_st_čt_p\xe1_so".split("_"),weekdaysMin:"ne_po_\xfat_st_čt_p\xe1_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm",l:"D. M. YYYY"},calendar:{sameDay:"[dnes v] LT",nextDay:"[z\xedtra v] LT",nextWeek:function(){switch(this.day()){case 0:return"[v neděli v] LT";case 1:case 2:return"[v] dddd [v] LT";case 3:return"[ve středu v] LT";case 4:return"[ve čtvrtek v] LT";case 5:return"[v p\xe1tek v] LT";case 6:return"[v sobotu v] LT"}},lastDay:"[včera v] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulou neděli v] LT";case 1:case 2:return"[minul\xe9] dddd [v] LT";case 3:return"[minulou středu v] LT";case 4:case 5:return"[minul\xfd] dddd [v] LT";case 6:return"[minulou sobotu v] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"před %s",s:o,ss:o,m:o,mm:o,h:o,hh:o,d:o,dd:o,M:o,MM:o,y:o,yy:o},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},50877:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("cv",{months:"кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав".split("_"),monthsShort:"кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш".split("_"),weekdays:"вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун".split("_"),weekdaysShort:"выр_тун_ытл_юн_кӗҫ_эрн_шӑм".split("_"),weekdaysMin:"вр_тн_ыт_юн_кҫ_эр_шм".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]",LLL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm",LLLL:"dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm"},calendar:{sameDay:"[Паян] LT [сехетре]",nextDay:"[Ыран] LT [сехетре]",lastDay:"[Ӗнер] LT [сехетре]",nextWeek:"[Ҫитес] dddd LT [сехетре]",lastWeek:"[Иртнӗ] dddd LT [сехетре]",sameElse:"L"},relativeTime:{future:function(e){var t=/сехет$/i.exec(e)?"рен":/ҫул$/i.exec(e)?"тан":"ран";return e+t},past:"%s каялла",s:"пӗр-ик ҫеккунт",ss:"%d ҫеккунт",m:"пӗр минут",mm:"%d минут",h:"пӗр сехет",hh:"%d сехет",d:"пӗр кун",dd:"%d кун",M:"пӗр уйӑх",MM:"%d уйӑх",y:"пӗр ҫул",yy:"%d ҫул"},dayOfMonthOrdinalParse:/\d{1,2}-мӗш/,ordinal:"%d-мӗш",week:{dow:1,doy:7}})})(n(30381))},47373:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("cy",{months:"Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr".split("_"),monthsShort:"Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag".split("_"),weekdays:"Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn".split("_"),weekdaysShort:"Sul_Llun_Maw_Mer_Iau_Gwe_Sad".split("_"),weekdaysMin:"Su_Ll_Ma_Me_Ia_Gw_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Heddiw am] LT",nextDay:"[Yfory am] LT",nextWeek:"dddd [am] LT",lastDay:"[Ddoe am] LT",lastWeek:"dddd [diwethaf am] LT",sameElse:"L"},relativeTime:{future:"mewn %s",past:"%s yn \xf4l",s:"ychydig eiliadau",ss:"%d eiliad",m:"munud",mm:"%d munud",h:"awr",hh:"%d awr",d:"diwrnod",dd:"%d diwrnod",M:"mis",MM:"%d mis",y:"blwyddyn",yy:"%d flynedd"},dayOfMonthOrdinalParse:/\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,ordinal:function(e){var t=e,n="",r=["","af","il","ydd","ydd","ed","ed","ed","fed","fed","fed","eg","fed","eg","eg","fed","eg","eg","fed","eg","fed"];return t>20?n=40===t||50===t||60===t||80===t||100===t?"fed":"ain":t>0&&(n=r[t]),e+n},week:{dow:1,doy:4}})})(n(30381))},24780:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("da",{months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"s\xf8ndag_mandag_tirsdag_onsdag_torsdag_fredag_l\xf8rdag".split("_"),weekdaysShort:"s\xf8n_man_tir_ons_tor_fre_l\xf8r".split("_"),weekdaysMin:"s\xf8_ma_ti_on_to_fr_l\xf8".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"p\xe5 dddd [kl.] LT",lastDay:"[i g\xe5r kl.] LT",lastWeek:"[i] dddd[s kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"f\xe5 sekunder",ss:"%d sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en m\xe5ned",MM:"%d m\xe5neder",y:"et \xe5r",yy:"%d \xe5r"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},60217:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return t?i[n][0]:i[n][1]}return e.defineLocale("de-at",{months:"J\xe4nner_Februar_M\xe4rz_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"J\xe4n._Feb._M\xe4rz_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:t,mm:"%d Minuten",h:t,hh:"%d Stunden",d:t,dd:t,w:t,ww:"%d Wochen",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},60894:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return t?i[n][0]:i[n][1]}return e.defineLocale("de-ch",{months:"Januar_Februar_M\xe4rz_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._M\xe4rz_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:t,mm:"%d Minuten",h:t,hh:"%d Stunden",d:t,dd:t,w:t,ww:"%d Wochen",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},59740:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return t?i[n][0]:i[n][1]}return e.defineLocale("de",{months:"Januar_Februar_M\xe4rz_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._M\xe4rz_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:t,mm:"%d Minuten",h:t,hh:"%d Stunden",d:t,dd:t,w:t,ww:"%d Wochen",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},5300:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=["ޖެނުއަރީ","ފެބްރުއަރީ","މާރިޗު","އޭޕްރީލު","މޭ","ޖޫން","ޖުލައި","އޯގަސްޓު","ސެޕްޓެމްބަރު","އޮކްޓޯބަރު","ނޮވެމްބަރު","ޑިސެމްބަރު",],n=["އާދިއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު",];return e.defineLocale("dv",{months:t,monthsShort:t,weekdays:n,weekdaysShort:n,weekdaysMin:"އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/M/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/މކ|މފ/,isPM:function(e){return"މފ"===e},meridiem:function(e,t,n){return e<12?"މކ":"މފ"},calendar:{sameDay:"[މިއަދު] LT",nextDay:"[މާދަމާ] LT",nextWeek:"dddd LT",lastDay:"[އިއްޔެ] LT",lastWeek:"[ފާއިތުވި] dddd LT",sameElse:"L"},relativeTime:{future:"ތެރޭގައި %s",past:"ކުރިން %s",s:"ސިކުންތުކޮޅެއް",ss:"d% ސިކުންތު",m:"މިނިޓެއް",mm:"މިނިޓު %d",h:"ގަޑިއިރެއް",hh:"ގަޑިއިރު %d",d:"ދުވަހެއް",dd:"ދުވަސް %d",M:"މަހެއް",MM:"މަސް %d",y:"އަހަރެއް",yy:"އަހަރު %d"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:7,doy:12}})})(n(30381))},50837:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e){return"undefined"!=typeof Function&&e instanceof Function||"[object Function]"===Object.prototype.toString.call(e)}return e.defineLocale("el",{monthsNominativeEl:"Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος".split("_"),monthsGenitiveEl:"Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου".split("_"),months:function(e,t){return e?"string"==typeof t&&/D/.test(t.substring(0,t.indexOf("MMMM")))?this._monthsGenitiveEl[e.month()]:this._monthsNominativeEl[e.month()]:this._monthsNominativeEl},monthsShort:"Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ".split("_"),weekdays:"Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο".split("_"),weekdaysShort:"Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ".split("_"),weekdaysMin:"Κυ_Δε_Τρ_Τε_Πε_Πα_Σα".split("_"),meridiem:function(e,t,n){return e>11?n?"μμ":"ΜΜ":n?"πμ":"ΠΜ"},isPM:function(e){return"μ"===(e+"").toLowerCase()[0]},meridiemParse:/[ΠΜ]\.?Μ?\.?/i,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendarEl:{sameDay:"[Σήμερα {}] LT",nextDay:"[Αύριο {}] LT",nextWeek:"dddd [{}] LT",lastDay:"[Χθες {}] LT",lastWeek:function(){return 6===this.day()?"[το προηγούμενο] dddd [{}] LT":"[την προηγούμενη] dddd [{}] LT"},sameElse:"L"},calendar:function(e,n){var r=this._calendarEl[e],i=n&&n.hours();return t(r)&&(r=r.apply(n)),r.replace("{}",i%12==1?"στη":"στις")},relativeTime:{future:"σε %s",past:"%s πριν",s:"λίγα δευτερόλεπτα",ss:"%d δευτερόλεπτα",m:"ένα λεπτό",mm:"%d λεπτά",h:"μία ώρα",hh:"%d ώρες",d:"μία μέρα",dd:"%d μέρες",M:"ένας μήνας",MM:"%d μήνες",y:"ένας χρόνος",yy:"%d χρόνια"},dayOfMonthOrdinalParse:/\d{1,2}η/,ordinal:"%dη",week:{dow:1,doy:4}})})(n(30381))},78348:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-au",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:0,doy:4}})})(n(30381))},77925:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-ca",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"YYYY-MM-DD",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n}})})(n(30381))},22243:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:1,doy:4}})})(n(30381))},46436:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-ie",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:1,doy:4}})})(n(30381))},47207:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-il",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n}})})(n(30381))},44175:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-in",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:0,doy:6}})})(n(30381))},76319:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-nz",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:1,doy:4}})})(n(30381))},31662:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("en-sg",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:1,doy:4}})})(n(30381))},92915:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("eo",{months:"januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro".split("_"),monthsShort:"jan_feb_mart_apr_maj_jun_jul_aŭg_sept_okt_nov_dec".split("_"),weekdays:"dimanĉo_lundo_mardo_merkredo_ĵaŭdo_vendredo_sabato".split("_"),weekdaysShort:"dim_lun_mard_merk_ĵaŭ_ven_sab".split("_"),weekdaysMin:"di_lu_ma_me_ĵa_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"[la] D[-an de] MMMM, YYYY",LLL:"[la] D[-an de] MMMM, YYYY HH:mm",LLLL:"dddd[n], [la] D[-an de] MMMM, YYYY HH:mm",llll:"ddd, [la] D[-an de] MMM, YYYY HH:mm"},meridiemParse:/[ap]\.t\.m/i,isPM:function(e){return"p"===e.charAt(0).toLowerCase()},meridiem:function(e,t,n){return e>11?n?"p.t.m.":"P.T.M.":n?"a.t.m.":"A.T.M."},calendar:{sameDay:"[Hodiaŭ je] LT",nextDay:"[Morgaŭ je] LT",nextWeek:"dddd[n je] LT",lastDay:"[Hieraŭ je] LT",lastWeek:"[pasintan] dddd[n je] LT",sameElse:"L"},relativeTime:{future:"post %s",past:"antaŭ %s",s:"kelkaj sekundoj",ss:"%d sekundoj",m:"unu minuto",mm:"%d minutoj",h:"unu horo",hh:"%d horoj",d:"unu tago",dd:"%d tagoj",M:"unu monato",MM:"%d monatoj",y:"unu jaro",yy:"%d jaroj"},dayOfMonthOrdinalParse:/\d{1,2}a/,ordinal:"%da",week:{dow:1,doy:7}})})(n(30381))},55251:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),n="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),r=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i,],i=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;return e.defineLocale("es-do",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,r){return e?/-MMM-/.test(r)?n[e.month()]:t[e.month()]:t},monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"domingo_lunes_martes_mi\xe9rcoles_jueves_viernes_s\xe1bado".split("_"),weekdaysShort:"dom._lun._mar._mi\xe9._jue._vie._s\xe1b.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[ma\xf1ana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un d\xeda",dd:"%d d\xedas",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un a\xf1o",yy:"%d a\xf1os"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4}})})(n(30381))},96112:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),n="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),r=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i,],i=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;return e.defineLocale("es-mx",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,r){return e?/-MMM-/.test(r)?n[e.month()]:t[e.month()]:t},monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"domingo_lunes_martes_mi\xe9rcoles_jueves_viernes_s\xe1bado".split("_"),weekdaysShort:"dom._lun._mar._mi\xe9._jue._vie._s\xe1b.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[ma\xf1ana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un d\xeda",dd:"%d d\xedas",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un a\xf1o",yy:"%d a\xf1os"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:0,doy:4},invalidDate:"Fecha inv\xe1lida"})})(n(30381))},71146:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),n="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),r=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i,],i=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;return e.defineLocale("es-us",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,r){return e?/-MMM-/.test(r)?n[e.month()]:t[e.month()]:t},monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"domingo_lunes_martes_mi\xe9rcoles_jueves_viernes_s\xe1bado".split("_"),weekdaysShort:"dom._lun._mar._mi\xe9._jue._vie._s\xe1b.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"MM/DD/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[ma\xf1ana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un d\xeda",dd:"%d d\xedas",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un a\xf1o",yy:"%d a\xf1os"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:0,doy:6}})})(n(30381))},55655:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),n="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),r=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i,],i=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;return e.defineLocale("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,r){return e?/-MMM-/.test(r)?n[e.month()]:t[e.month()]:t},monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"domingo_lunes_martes_mi\xe9rcoles_jueves_viernes_s\xe1bado".split("_"),weekdaysShort:"dom._lun._mar._mi\xe9._jue._vie._s\xe1b.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[ma\xf1ana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un d\xeda",dd:"%d d\xedas",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un a\xf1o",yy:"%d a\xf1os"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4},invalidDate:"Fecha inv\xe1lida"})})(n(30381))},5603:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i={s:["m\xf5ne sekundi","m\xf5ni sekund","paar sekundit"],ss:[e+"sekundi",e+"sekundit"],m:["\xfche minuti","\xfcks minut"],mm:[e+" minuti",e+" minutit"],h:["\xfche tunni","tund aega","\xfcks tund"],hh:[e+" tunni",e+" tundi"],d:["\xfche p\xe4eva","\xfcks p\xe4ev"],M:["kuu aja","kuu aega","\xfcks kuu"],MM:[e+" kuu",e+" kuud"],y:["\xfche aasta","aasta","\xfcks aasta"],yy:[e+" aasta",e+" aastat"]};return t?i[n][2]?i[n][2]:i[n][1]:r?i[n][0]:i[n][1]}return e.defineLocale("et",{months:"jaanuar_veebruar_m\xe4rts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"),monthsShort:"jaan_veebr_m\xe4rts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"),weekdays:"p\xfchap\xe4ev_esmasp\xe4ev_teisip\xe4ev_kolmap\xe4ev_neljap\xe4ev_reede_laup\xe4ev".split("_"),weekdaysShort:"P_E_T_K_N_R_L".split("_"),weekdaysMin:"P_E_T_K_N_R_L".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[T\xe4na,] LT",nextDay:"[Homme,] LT",nextWeek:"[J\xe4rgmine] dddd LT",lastDay:"[Eile,] LT",lastWeek:"[Eelmine] dddd LT",sameElse:"L"},relativeTime:{future:"%s p\xe4rast",past:"%s tagasi",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:"%d p\xe4eva",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},77763:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("eu",{months:"urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"),monthsShort:"urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"),monthsParseExact:!0,weekdays:"igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"),weekdaysShort:"ig._al._ar._az._og._ol._lr.".split("_"),weekdaysMin:"ig_al_ar_az_og_ol_lr".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY[ko] MMMM[ren] D[a]",LLL:"YYYY[ko] MMMM[ren] D[a] HH:mm",LLLL:"dddd, YYYY[ko] MMMM[ren] D[a] HH:mm",l:"YYYY-M-D",ll:"YYYY[ko] MMM D[a]",lll:"YYYY[ko] MMM D[a] HH:mm",llll:"ddd, YYYY[ko] MMM D[a] HH:mm"},calendar:{sameDay:"[gaur] LT[etan]",nextDay:"[bihar] LT[etan]",nextWeek:"dddd LT[etan]",lastDay:"[atzo] LT[etan]",lastWeek:"[aurreko] dddd LT[etan]",sameElse:"L"},relativeTime:{future:"%s barru",past:"duela %s",s:"segundo batzuk",ss:"%d segundo",m:"minutu bat",mm:"%d minutu",h:"ordu bat",hh:"%d ordu",d:"egun bat",dd:"%d egun",M:"hilabete bat",MM:"%d hilabete",y:"urte bat",yy:"%d urte"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})})(n(30381))},76959:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"۱",2:"۲",3:"۳",4:"۴",5:"۵",6:"۶",7:"۷",8:"۸",9:"۹",0:"۰"},n={"۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","۰":"0"};return e.defineLocale("fa",{months:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),monthsShort:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),weekdays:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysShort:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysMin:"ی_د_س_چ_پ_ج_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/قبل از ظهر|بعد از ظهر/,isPM:function(e){return/بعد از ظهر/.test(e)},meridiem:function(e,t,n){return e<12?"قبل از ظهر":"بعد از ظهر"},calendar:{sameDay:"[امروز ساعت] LT",nextDay:"[فردا ساعت] LT",nextWeek:"dddd [ساعت] LT",lastDay:"[دیروز ساعت] LT",lastWeek:"dddd [پیش] [ساعت] LT",sameElse:"L"},relativeTime:{future:"در %s",past:"%s پیش",s:"چند ثانیه",ss:"%d ثانیه",m:"یک دقیقه",mm:"%d دقیقه",h:"یک ساعت",hh:"%d ساعت",d:"یک روز",dd:"%d روز",M:"یک ماه",MM:"%d ماه",y:"یک سال",yy:"%d سال"},preparse:function(e){return e.replace(/[۰-۹]/g,function(e){return n[e]}).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]}).replace(/,/g,"،")},dayOfMonthOrdinalParse:/\d{1,2}م/,ordinal:"%dم",week:{dow:6,doy:12}})})(n(30381))},11897:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="nolla yksi kaksi kolme nelj\xe4 viisi kuusi seitsem\xe4n kahdeksan yhdeks\xe4n".split(" "),n=["nolla","yhden","kahden","kolmen","nelj\xe4n","viiden","kuuden",t[7],t[8],t[9],];function r(e,t,n,r){var a="";switch(n){case"s":return r?"muutaman sekunnin":"muutama sekunti";case"ss":a=r?"sekunnin":"sekuntia";break;case"m":return r?"minuutin":"minuutti";case"mm":a=r?"minuutin":"minuuttia";break;case"h":return r?"tunnin":"tunti";case"hh":a=r?"tunnin":"tuntia";break;case"d":return r?"p\xe4iv\xe4n":"p\xe4iv\xe4";case"dd":a=r?"p\xe4iv\xe4n":"p\xe4iv\xe4\xe4";break;case"M":return r?"kuukauden":"kuukausi";case"MM":a=r?"kuukauden":"kuukautta";break;case"y":return r?"vuoden":"vuosi";case"yy":a=r?"vuoden":"vuotta"}return i(e,r)+" "+a}function i(e,r){return e<10?r?n[e]:t[e]:e}return e.defineLocale("fi",{months:"tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kes\xe4kuu_hein\xe4kuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu".split("_"),monthsShort:"tammi_helmi_maalis_huhti_touko_kes\xe4_hein\xe4_elo_syys_loka_marras_joulu".split("_"),weekdays:"sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai".split("_"),weekdaysShort:"su_ma_ti_ke_to_pe_la".split("_"),weekdaysMin:"su_ma_ti_ke_to_pe_la".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"Do MMMM[ta] YYYY",LLL:"Do MMMM[ta] YYYY, [klo] HH.mm",LLLL:"dddd, Do MMMM[ta] YYYY, [klo] HH.mm",l:"D.M.YYYY",ll:"Do MMM YYYY",lll:"Do MMM YYYY, [klo] HH.mm",llll:"ddd, Do MMM YYYY, [klo] HH.mm"},calendar:{sameDay:"[t\xe4n\xe4\xe4n] [klo] LT",nextDay:"[huomenna] [klo] LT",nextWeek:"dddd [klo] LT",lastDay:"[eilen] [klo] LT",lastWeek:"[viime] dddd[na] [klo] LT",sameElse:"L"},relativeTime:{future:"%s p\xe4\xe4st\xe4",past:"%s sitten",s:r,ss:r,m:r,mm:r,h:r,hh:r,d:r,dd:r,M:r,MM:r,y:r,yy:r},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},42549:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("fil",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})})(n(30381))},94694:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("fo",{months:"januar_februar_mars_apr\xedl_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sunnudagur_m\xe1nadagur_t\xfdsdagur_mikudagur_h\xf3sdagur_fr\xedggjadagur_leygardagur".split("_"),weekdaysShort:"sun_m\xe1n_t\xfds_mik_h\xf3s_fr\xed_ley".split("_"),weekdaysMin:"su_m\xe1_t\xfd_mi_h\xf3_fr_le".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D. MMMM, YYYY HH:mm"},calendar:{sameDay:"[\xcd dag kl.] LT",nextDay:"[\xcd morgin kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[\xcd gj\xe1r kl.] LT",lastWeek:"[s\xed\xf0stu] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"um %s",past:"%s s\xed\xf0ani",s:"f\xe1 sekund",ss:"%d sekundir",m:"ein minuttur",mm:"%d minuttir",h:"ein t\xedmi",hh:"%d t\xedmar",d:"ein dagur",dd:"%d dagar",M:"ein m\xe1na\xf0ur",MM:"%d m\xe1na\xf0ir",y:"eitt \xe1r",yy:"%d \xe1r"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},63049:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("fr-ca",{months:"janvier_f\xe9vrier_mars_avril_mai_juin_juillet_ao\xfbt_septembre_octobre_novembre_d\xe9cembre".split("_"),monthsShort:"janv._f\xe9vr._mars_avr._mai_juin_juil._ao\xfbt_sept._oct._nov._d\xe9c.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui \xe0] LT",nextDay:"[Demain \xe0] LT",nextWeek:"dddd [\xe0] LT",lastDay:"[Hier \xe0] LT",lastWeek:"dddd [dernier \xe0] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,t){switch(t){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}}})})(n(30381))},52330:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("fr-ch",{months:"janvier_f\xe9vrier_mars_avril_mai_juin_juillet_ao\xfbt_septembre_octobre_novembre_d\xe9cembre".split("_"),monthsShort:"janv._f\xe9vr._mars_avr._mai_juin_juil._ao\xfbt_sept._oct._nov._d\xe9c.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui \xe0] LT",nextDay:"[Demain \xe0] LT",nextWeek:"dddd [\xe0] LT",lastDay:"[Hier \xe0] LT",lastWeek:"dddd [dernier \xe0] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,t){switch(t){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})})(n(30381))},94470:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=/^(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,n=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?)/i,r=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?|janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,i=[/^janv/i,/^févr/i,/^mars/i,/^avr/i,/^mai/i,/^juin/i,/^juil/i,/^août/i,/^sept/i,/^oct/i,/^nov/i,/^déc/i,];return e.defineLocale("fr",{months:"janvier_f\xe9vrier_mars_avril_mai_juin_juillet_ao\xfbt_septembre_octobre_novembre_d\xe9cembre".split("_"),monthsShort:"janv._f\xe9vr._mars_avr._mai_juin_juil._ao\xfbt_sept._oct._nov._d\xe9c.".split("_"),monthsRegex:r,monthsShortRegex:r,monthsStrictRegex:t,monthsShortStrictRegex:n,monthsParse:i,longMonthsParse:i,shortMonthsParse:i,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui \xe0] LT",nextDay:"[Demain \xe0] LT",nextWeek:"dddd [\xe0] LT",lastDay:"[Hier \xe0] LT",lastWeek:"dddd [dernier \xe0] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",w:"une semaine",ww:"%d semaines",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|)/,ordinal:function(e,t){switch(t){case"D":return e+(1===e?"er":"");default:case"M":case"Q":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})})(n(30381))},5044:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_"),n="jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_");return e.defineLocale("fy",{months:"jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"),monthsShort:function(e,r){return e?/-MMM-/.test(r)?n[e.month()]:t[e.month()]:t},monthsParseExact:!0,weekdays:"snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"),weekdaysShort:"si._mo._ti._wo._to._fr._so.".split("_"),weekdaysMin:"Si_Mo_Ti_Wo_To_Fr_So".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[hjoed om] LT",nextDay:"[moarn om] LT",nextWeek:"dddd [om] LT",lastDay:"[juster om] LT",lastWeek:"[\xf4fr\xfbne] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oer %s",past:"%s lyn",s:"in pear sekonden",ss:"%d sekonden",m:"ien min\xfat",mm:"%d minuten",h:"ien oere",hh:"%d oeren",d:"ien dei",dd:"%d dagen",M:"ien moanne",MM:"%d moannen",y:"ien jier",yy:"%d jierren"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})})(n(30381))},29295:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=["Ean\xe1ir","Feabhra","M\xe1rta","Aibre\xe1n","Bealtaine","Meitheamh","I\xfail","L\xfanasa","Me\xe1n F\xf3mhair","Deireadh F\xf3mhair","Samhain","Nollaig",],n=["Ean","Feabh","M\xe1rt","Aib","Beal","Meith","I\xfail","L\xfan","M.F.","D.F.","Samh","Noll",],r=["D\xe9 Domhnaigh","D\xe9 Luain","D\xe9 M\xe1irt","D\xe9 C\xe9adaoin","D\xe9ardaoin","D\xe9 hAoine","D\xe9 Sathairn",],i=["Domh","Luan","M\xe1irt","C\xe9ad","D\xe9ar","Aoine","Sath"],a=["Do","Lu","M\xe1","C\xe9","D\xe9","A","Sa"];return e.defineLocale("ga",{months:t,monthsShort:n,monthsParseExact:!0,weekdays:r,weekdaysShort:i,weekdaysMin:a,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Inniu ag] LT",nextDay:"[Am\xe1rach ag] LT",nextWeek:"dddd [ag] LT",lastDay:"[Inn\xe9 ag] LT",lastWeek:"dddd [seo caite] [ag] LT",sameElse:"L"},relativeTime:{future:"i %s",past:"%s \xf3 shin",s:"c\xfapla soicind",ss:"%d soicind",m:"n\xf3im\xe9ad",mm:"%d n\xf3im\xe9ad",h:"uair an chloig",hh:"%d uair an chloig",d:"l\xe1",dd:"%d l\xe1",M:"m\xed",MM:"%d m\xedonna",y:"bliain",yy:"%d bliain"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){var t=1===e?"d":e%10==2?"na":"mh";return e+t},week:{dow:1,doy:4}})})(n(30381))},2101:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=["Am Faoilleach","An Gearran","Am M\xe0rt","An Giblean","An C\xe8itean","An t-\xd2gmhios","An t-Iuchar","An L\xf9nastal","An t-Sultain","An D\xe0mhair","An t-Samhain","An D\xf9bhlachd",],n=["Faoi","Gear","M\xe0rt","Gibl","C\xe8it","\xd2gmh","Iuch","L\xf9n","Sult","D\xe0mh","Samh","D\xf9bh",],r=["Did\xf2mhnaich","Diluain","Dim\xe0irt","Diciadain","Diardaoin","Dihaoine","Disathairne",],i=["Did","Dil","Dim","Dic","Dia","Dih","Dis"],a=["D\xf2","Lu","M\xe0","Ci","Ar","Ha","Sa"];return e.defineLocale("gd",{months:t,monthsShort:n,monthsParseExact:!0,weekdays:r,weekdaysShort:i,weekdaysMin:a,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[An-diugh aig] LT",nextDay:"[A-m\xe0ireach aig] LT",nextWeek:"dddd [aig] LT",lastDay:"[An-d\xe8 aig] LT",lastWeek:"dddd [seo chaidh] [aig] LT",sameElse:"L"},relativeTime:{future:"ann an %s",past:"bho chionn %s",s:"beagan diogan",ss:"%d diogan",m:"mionaid",mm:"%d mionaidean",h:"uair",hh:"%d uairean",d:"latha",dd:"%d latha",M:"m\xecos",MM:"%d m\xecosan",y:"bliadhna",yy:"%d bliadhna"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){var t=1===e?"d":e%10==2?"na":"mh";return e+t},week:{dow:1,doy:4}})})(n(30381))},38794:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("gl",{months:"xaneiro_febreiro_marzo_abril_maio_xu\xf1o_xullo_agosto_setembro_outubro_novembro_decembro".split("_"),monthsShort:"xan._feb._mar._abr._mai._xu\xf1._xul._ago._set._out._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"domingo_luns_martes_m\xe9rcores_xoves_venres_s\xe1bado".split("_"),weekdaysShort:"dom._lun._mar._m\xe9r._xov._ven._s\xe1b.".split("_"),weekdaysMin:"do_lu_ma_m\xe9_xo_ve_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoxe "+(1!==this.hours()?"\xe1s":"\xe1")+"] LT"},nextDay:function(){return"[ma\xf1\xe1 "+(1!==this.hours()?"\xe1s":"\xe1")+"] LT"},nextWeek:function(){return"dddd ["+(1!==this.hours()?"\xe1s":"a")+"] LT"},lastDay:function(){return"[onte "+(1!==this.hours()?"\xe1":"a")+"] LT"},lastWeek:function(){return"[o] dddd [pasado "+(1!==this.hours()?"\xe1s":"a")+"] LT"},sameElse:"L"},relativeTime:{future:function(e){return 0===e.indexOf("un")?"n"+e:"en "+e},past:"hai %s",s:"uns segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"unha hora",hh:"%d horas",d:"un d\xeda",dd:"%d d\xedas",M:"un mes",MM:"%d meses",y:"un ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4}})})(n(30381))},27884:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i={s:["थोडया सॅकंडांनी","थोडे सॅकंड"],ss:[e+" सॅकंडांनी",e+" सॅकंड"],m:["एका मिणटान","एक मिनूट"],mm:[e+" मिणटांनी",e+" मिणटां"],h:["एका वरान","एक वर"],hh:[e+" वरांनी",e+" वरां"],d:["एका दिसान","एक दीस"],dd:[e+" दिसांनी",e+" दीस"],M:["एका म्हयन्यान","एक म्हयनो"],MM:[e+" म्हयन्यानी",e+" म्हयने"],y:["एका वर्सान","एक वर्स"],yy:[e+" वर्सांनी",e+" वर्सां"]};return r?i[n][0]:i[n][1]}return e.defineLocale("gom-deva",{months:{standalone:"जानेवारी_फेब्रुवारी_मार्च_एप्रील_मे_जून_जुलय_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),format:"जानेवारीच्या_फेब्रुवारीच्या_मार्चाच्या_एप्रीलाच्या_मेयाच्या_जूनाच्या_जुलयाच्या_ऑगस्टाच्या_सप्टेंबराच्या_ऑक्टोबराच्या_नोव्हेंबराच्या_डिसेंबराच्या".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"जाने._फेब्रु._मार्च_एप्री._मे_जून_जुल._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"आयतार_सोमार_मंगळार_बुधवार_बिरेस्तार_सुक्रार_शेनवार".split("_"),weekdaysShort:"आयत._सोम._मंगळ._बुध._ब्रेस्त._सुक्र._शेन.".split("_"),weekdaysMin:"आ_सो_मं_बु_ब्रे_सु_शे".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [वाजतां]",LTS:"A h:mm:ss [वाजतां]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [वाजतां]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [वाजतां]",llll:"ddd, D MMM YYYY, A h:mm [वाजतां]"},calendar:{sameDay:"[आयज] LT",nextDay:"[फाल्यां] LT",nextWeek:"[फुडलो] dddd[,] LT",lastDay:"[काल] LT",lastWeek:"[फाटलो] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s आदीं",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}(वेर)/,ordinal:function(e,t){return"D"===t?e+"वेर":e},week:{dow:0,doy:3},meridiemParse:/राती|सकाळीं|दनपारां|सांजे/,meridiemHour:function(e,t){return(12===e&&(e=0),"राती"===t)?e<4?e:e+12:"सकाळीं"===t?e:"दनपारां"===t?e>12?e:e+12:"सांजे"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"राती":e<12?"सकाळीं":e<16?"दनपारां":e<20?"सांजे":"राती"}})})(n(30381))},23168:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i={s:["thoddea sekondamni","thodde sekond"],ss:[e+" sekondamni",e+" sekond"],m:["eka mintan","ek minut"],mm:[e+" mintamni",e+" mintam"],h:["eka voran","ek vor"],hh:[e+" voramni",e+" voram"],d:["eka disan","ek dis"],dd:[e+" disamni",e+" dis"],M:["eka mhoinean","ek mhoino"],MM:[e+" mhoineamni",e+" mhoine"],y:["eka vorsan","ek voros"],yy:[e+" vorsamni",e+" vorsam"]};return r?i[n][0]:i[n][1]}return e.defineLocale("gom-latn",{months:{standalone:"Janer_Febrer_Mars_Abril_Mai_Jun_Julai_Agost_Setembr_Otubr_Novembr_Dezembr".split("_"),format:"Janerachea_Febrerachea_Marsachea_Abrilachea_Maiachea_Junachea_Julaiachea_Agostachea_Setembrachea_Otubrachea_Novembrachea_Dezembrachea".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"Jan._Feb._Mars_Abr._Mai_Jun_Jul._Ago._Set._Otu._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Aitar_Somar_Mongllar_Budhvar_Birestar_Sukrar_Son'var".split("_"),weekdaysShort:"Ait._Som._Mon._Bud._Bre._Suk._Son.".split("_"),weekdaysMin:"Ai_Sm_Mo_Bu_Br_Su_Sn".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [vazta]",LTS:"A h:mm:ss [vazta]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [vazta]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [vazta]",llll:"ddd, D MMM YYYY, A h:mm [vazta]"},calendar:{sameDay:"[Aiz] LT",nextDay:"[Faleam] LT",nextWeek:"[Fuddlo] dddd[,] LT",lastDay:"[Kal] LT",lastWeek:"[Fattlo] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s adim",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}(er)/,ordinal:function(e,t){return"D"===t?e+"er":e},week:{dow:0,doy:3},meridiemParse:/rati|sokallim|donparam|sanje/,meridiemHour:function(e,t){return(12===e&&(e=0),"rati"===t)?e<4?e:e+12:"sokallim"===t?e:"donparam"===t?e>12?e:e+12:"sanje"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"rati":e<12?"sokallim":e<16?"donparam":e<20?"sanje":"rati"}})})(n(30381))},95349:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"૧",2:"૨",3:"૩",4:"૪",5:"૫",6:"૬",7:"૭",8:"૮",9:"૯",0:"૦"},n={"૧":"1","૨":"2","૩":"3","૪":"4","૫":"5","૬":"6","૭":"7","૮":"8","૯":"9","૦":"0"};return e.defineLocale("gu",{months:"જાન્યુઆરી_ફેબ્રુઆરી_માર્ચ_એપ્રિલ_મે_જૂન_જુલાઈ_ઑગસ્ટ_સપ્ટેમ્બર_ઑક્ટ્બર_નવેમ્બર_ડિસેમ્બર".split("_"),monthsShort:"જાન્યુ._ફેબ્રુ._માર્ચ_એપ્રિ._મે_જૂન_જુલા._ઑગ._સપ્ટે._ઑક્ટ્._નવે._ડિસે.".split("_"),monthsParseExact:!0,weekdays:"રવિવાર_સોમવાર_મંગળવાર_બુધ્વાર_ગુરુવાર_શુક્રવાર_શનિવાર".split("_"),weekdaysShort:"રવિ_સોમ_મંગળ_બુધ્_ગુરુ_શુક્ર_શનિ".split("_"),weekdaysMin:"ર_સો_મં_બુ_ગુ_શુ_શ".split("_"),longDateFormat:{LT:"A h:mm વાગ્યે",LTS:"A h:mm:ss વાગ્યે",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm વાગ્યે",LLLL:"dddd, D MMMM YYYY, A h:mm વાગ્યે"},calendar:{sameDay:"[આજ] LT",nextDay:"[કાલે] LT",nextWeek:"dddd, LT",lastDay:"[ગઇકાલે] LT",lastWeek:"[પાછલા] dddd, LT",sameElse:"L"},relativeTime:{future:"%s મા",past:"%s પહેલા",s:"અમુક પળો",ss:"%d સેકંડ",m:"એક મિનિટ",mm:"%d મિનિટ",h:"એક કલાક",hh:"%d કલાક",d:"એક દિવસ",dd:"%d દિવસ",M:"એક મહિનો",MM:"%d મહિનો",y:"એક વર્ષ",yy:"%d વર્ષ"},preparse:function(e){return e.replace(/[૧૨૩૪૫૬૭૮૯૦]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/રાત|બપોર|સવાર|સાંજ/,meridiemHour:function(e,t){return(12===e&&(e=0),"રાત"===t)?e<4?e:e+12:"સવાર"===t?e:"બપોર"===t?e>=10?e:e+12:"સાંજ"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"રાત":e<10?"સવાર":e<17?"બપોર":e<20?"સાંજ":"રાત"},week:{dow:0,doy:6}})})(n(30381))},24206:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("he",{months:"ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר".split("_"),monthsShort:"ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳".split("_"),weekdays:"ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת".split("_"),weekdaysShort:"א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳".split("_"),weekdaysMin:"א_ב_ג_ד_ה_ו_ש".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [ב]MMMM YYYY",LLL:"D [ב]MMMM YYYY HH:mm",LLLL:"dddd, D [ב]MMMM YYYY HH:mm",l:"D/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[היום ב־]LT",nextDay:"[מחר ב־]LT",nextWeek:"dddd [בשעה] LT",lastDay:"[אתמול ב־]LT",lastWeek:"[ביום] dddd [האחרון בשעה] LT",sameElse:"L"},relativeTime:{future:"בעוד %s",past:"לפני %s",s:"מספר שניות",ss:"%d שניות",m:"דקה",mm:"%d דקות",h:"שעה",hh:function(e){return 2===e?"שעתיים":e+" שעות"},d:"יום",dd:function(e){return 2===e?"יומיים":e+" ימים"},M:"חודש",MM:function(e){return 2===e?"חודשיים":e+" חודשים"},y:"שנה",yy:function(e){return 2===e?"שנתיים":e%10==0&&10!==e?e+" שנה":e+" שנים"}},meridiemParse:/אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,isPM:function(e){return/^(אחה"צ|אחרי הצהריים|בערב)$/.test(e)},meridiem:function(e,t,n){return e<5?"לפנות בוקר":e<10?"בבוקר":e<12?n?'לפנה"צ':"לפני הצהריים":e<18?n?'אחה"צ':"אחרי הצהריים":"בערב"}})})(n(30381))},30094:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},n={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"},r=[/^जन/i,/^फ़र|फर/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सितं|सित/i,/^अक्टू/i,/^नव|नवं/i,/^दिसं|दिस/i,],i=[/^जन/i,/^फ़र/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सित/i,/^अक्टू/i,/^नव/i,/^दिस/i,];return e.defineLocale("hi",{months:{format:"जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर".split("_"),standalone:"जनवरी_फरवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितंबर_अक्टूबर_नवंबर_दिसंबर".split("_")},monthsShort:"जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.".split("_"),weekdays:"रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm बजे",LTS:"A h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm बजे",LLLL:"dddd, D MMMM YYYY, A h:mm बजे"},monthsParse:r,longMonthsParse:r,shortMonthsParse:i,monthsRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsShortRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsStrictRegex:/^(जनवरी?|फ़रवरी|फरवरी?|मार्च?|अप्रैल?|मई?|जून?|जुलाई?|अगस्त?|सितम्बर|सितंबर|सित?\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर?|दिसम्बर|दिसंबर?)/i,monthsShortStrictRegex:/^(जन\.?|फ़र\.?|मार्च?|अप्रै\.?|मई?|जून?|जुल\.?|अग\.?|सित\.?|अक्टू\.?|नव\.?|दिस\.?)/i,calendar:{sameDay:"[आज] LT",nextDay:"[कल] LT",nextWeek:"dddd, LT",lastDay:"[कल] LT",lastWeek:"[पिछले] dddd, LT",sameElse:"L"},relativeTime:{future:"%s में",past:"%s पहले",s:"कुछ ही क्षण",ss:"%d सेकंड",m:"एक मिनट",mm:"%d मिनट",h:"एक घंटा",hh:"%d घंटे",d:"एक दिन",dd:"%d दिन",M:"एक महीने",MM:"%d महीने",y:"एक वर्ष",yy:"%d वर्ष"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/रात|सुबह|दोपहर|शाम/,meridiemHour:function(e,t){return(12===e&&(e=0),"रात"===t)?e<4?e:e+12:"सुबह"===t?e:"दोपहर"===t?e>=10?e:e+12:"शाम"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"रात":e<10?"सुबह":e<17?"दोपहर":e<20?"शाम":"रात"},week:{dow:0,doy:6}})})(n(30381))},30316:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n){var r=e+" ";switch(n){case"ss":return 1===e?r+="sekunda":2===e||3===e||4===e?r+="sekunde":r+="sekundi",r;case"m":return t?"jedna minuta":"jedne minute";case"mm":return 1===e?r+="minuta":2===e||3===e||4===e?r+="minute":r+="minuta",r;case"h":return t?"jedan sat":"jednog sata";case"hh":return 1===e?r+="sat":2===e||3===e||4===e?r+="sata":r+="sati",r;case"dd":return 1===e?r+="dan":r+="dana",r;case"MM":return 1===e?r+="mjesec":2===e||3===e||4===e?r+="mjeseca":r+="mjeseci",r;case"yy":return 1===e?r+="godina":2===e||3===e||4===e?r+="godine":r+="godina",r}}return e.defineLocale("hr",{months:{format:"siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"),standalone:"siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_")},monthsShort:"sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"Do MMMM YYYY",LLL:"Do MMMM YYYY H:mm",LLLL:"dddd, Do MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:return"[prošlu] [nedjelju] [u] LT";case 3:return"[prošlu] [srijedu] [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:t,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})})(n(30381))},22138:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="vas\xe1rnap h\xe9tfőn kedden szerd\xe1n cs\xfct\xf6rt\xf6k\xf6n p\xe9nteken szombaton".split(" ");function n(e,t,n,r){var i=e;switch(n){case"s":return r||t?"n\xe9h\xe1ny m\xe1sodperc":"n\xe9h\xe1ny m\xe1sodperce";case"ss":return i+(r||t)?" m\xe1sodperc":" m\xe1sodperce";case"m":return"egy"+(r||t?" perc":" perce");case"mm":return i+(r||t?" perc":" perce");case"h":return"egy"+(r||t?" \xf3ra":" \xf3r\xe1ja");case"hh":return i+(r||t?" \xf3ra":" \xf3r\xe1ja");case"d":return"egy"+(r||t?" nap":" napja");case"dd":return i+(r||t?" nap":" napja");case"M":return"egy"+(r||t?" h\xf3nap":" h\xf3napja");case"MM":return i+(r||t?" h\xf3nap":" h\xf3napja");case"y":return"egy"+(r||t?" \xe9v":" \xe9ve");case"yy":return i+(r||t?" \xe9v":" \xe9ve")}return""}function r(e){return(e?"":"[m\xfalt] ")+"["+t[this.day()]+"] LT[-kor]"}return e.defineLocale("hu",{months:"janu\xe1r_febru\xe1r_m\xe1rcius_\xe1prilis_m\xe1jus_j\xfanius_j\xfalius_augusztus_szeptember_okt\xf3ber_november_december".split("_"),monthsShort:"jan._feb._m\xe1rc._\xe1pr._m\xe1j._j\xfan._j\xfal._aug._szept._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"vas\xe1rnap_h\xe9tfő_kedd_szerda_cs\xfct\xf6rt\xf6k_p\xe9ntek_szombat".split("_"),weekdaysShort:"vas_h\xe9t_kedd_sze_cs\xfct_p\xe9n_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(e){return"u"===e.charAt(1).toLowerCase()},meridiem:function(e,t,n){return e<12?!0===n?"de":"DE":!0===n?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return r.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return r.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s m\xfalva",past:"%s",s:n,ss:n,m:n,mm:n,h:n,hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},11423:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("hy-am",{months:{format:"հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի".split("_"),standalone:"հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր".split("_")},monthsShort:"հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ".split("_"),weekdays:"կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ".split("_"),weekdaysShort:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),weekdaysMin:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY թ.",LLL:"D MMMM YYYY թ., HH:mm",LLLL:"dddd, D MMMM YYYY թ., HH:mm"},calendar:{sameDay:"[այսօր] LT",nextDay:"[վաղը] LT",lastDay:"[երեկ] LT",nextWeek:function(){return"dddd [օրը ժամը] LT"},lastWeek:function(){return"[անցած] dddd [օրը ժամը] LT"},sameElse:"L"},relativeTime:{future:"%s հետո",past:"%s առաջ",s:"մի քանի վայրկյան",ss:"%d վայրկյան",m:"րոպե",mm:"%d րոպե",h:"ժամ",hh:"%d ժամ",d:"օր",dd:"%d օր",M:"ամիս",MM:"%d ամիս",y:"տարի",yy:"%d տարի"},meridiemParse:/գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,isPM:function(e){return/^(ցերեկվա|երեկոյան)$/.test(e)},meridiem:function(e){return e<4?"գիշերվա":e<12?"առավոտվա":e<17?"ցերեկվա":"երեկոյան"},dayOfMonthOrdinalParse:/\d{1,2}|\d{1,2}-(ին|րդ)/,ordinal:function(e,t){switch(t){case"DDD":case"w":case"W":case"DDDo":if(1===e)return e+"-ին";return e+"-րդ";default:return e}},week:{dow:1,doy:7}})})(n(30381))},29218:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Agt_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(e,t){return(12===e&&(e=0),"pagi"===t)?e:"siang"===t?e>=11?e:e+12:"sore"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,n){return e<11?"pagi":e<15?"siang":e<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",ss:"%d detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:0,doy:6}})})(n(30381))},90135:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e){if(e%100==11);else if(e%10==1)return!1;return!0}function n(e,n,r,i){var a=e+" ";switch(r){case"s":return n||i?"nokkrar sek\xfandur":"nokkrum sek\xfandum";case"ss":if(t(e))return a+(n||i?"sek\xfandur":"sek\xfandum");return a+"sek\xfanda";case"m":return n?"m\xedn\xfata":"m\xedn\xfatu";case"mm":if(t(e))return a+(n||i?"m\xedn\xfatur":"m\xedn\xfatum");if(n)return a+"m\xedn\xfata";return a+"m\xedn\xfatu";case"hh":if(t(e))return a+(n||i?"klukkustundir":"klukkustundum");return a+"klukkustund";case"d":if(n)return"dagur";return i?"dag":"degi";case"dd":if(t(e)){if(n)return a+"dagar";return a+(i?"daga":"d\xf6gum")}if(n)return a+"dagur";return a+(i?"dag":"degi");case"M":if(n)return"m\xe1nu\xf0ur";return i?"m\xe1nu\xf0":"m\xe1nu\xf0i";case"MM":if(t(e)){if(n)return a+"m\xe1nu\xf0ir";return a+(i?"m\xe1nu\xf0i":"m\xe1nu\xf0um")}if(n)return a+"m\xe1nu\xf0ur";return a+(i?"m\xe1nu\xf0":"m\xe1nu\xf0i");case"y":return n||i?"\xe1r":"\xe1ri";case"yy":if(t(e))return a+(n||i?"\xe1r":"\xe1rum");return a+(n||i?"\xe1r":"\xe1ri")}}return e.defineLocale("is",{months:"jan\xfaar_febr\xfaar_mars_apr\xedl_ma\xed_j\xfan\xed_j\xfal\xed_\xe1g\xfast_september_okt\xf3ber_n\xf3vember_desember".split("_"),monthsShort:"jan_feb_mar_apr_ma\xed_j\xfan_j\xfal_\xe1g\xfa_sep_okt_n\xf3v_des".split("_"),weekdays:"sunnudagur_m\xe1nudagur_\xferi\xf0judagur_mi\xf0vikudagur_fimmtudagur_f\xf6studagur_laugardagur".split("_"),weekdaysShort:"sun_m\xe1n_\xferi_mi\xf0_fim_f\xf6s_lau".split("_"),weekdaysMin:"Su_M\xe1_\xder_Mi_Fi_F\xf6_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[\xed dag kl.] LT",nextDay:"[\xe1 morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[\xed g\xe6r kl.] LT",lastWeek:"[s\xed\xf0asta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s s\xed\xf0an",s:n,ss:n,m:n,mm:n,h:"klukkustund",hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},10150:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("it-ch",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_luned\xec_marted\xec_mercoled\xec_gioved\xec_venerd\xec_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){return 0===this.day()?"[la scorsa] dddd [alle] LT":"[lo scorso] dddd [alle] LT"},sameElse:"L"},relativeTime:{future:function(e){return(/^[0-9].+$/.test(e)?"tra":"in")+" "+e},past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4}})})(n(30381))},90626:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_luned\xec_marted\xec_mercoled\xec_gioved\xec_venerd\xec_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:function(){return"[Oggi a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextDay:function(){return"[Domani a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextWeek:function(){return"dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastDay:function(){return"[Ieri a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastWeek:function(){return 0===this.day()?"[La scorsa] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT":"[Lo scorso] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},sameElse:"L"},relativeTime:{future:"tra %s",past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",w:"una settimana",ww:"%d settimane",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4}})})(n(30381))},39183:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ja",{eras:[{since:"2019-05-01",offset:1,name:"令和",narrow:"㋿",abbr:"R"},{since:"1989-01-08",until:"2019-04-30",offset:1,name:"平成",narrow:"㍻",abbr:"H"},{since:"1926-12-25",until:"1989-01-07",offset:1,name:"昭和",narrow:"㍼",abbr:"S"},{since:"1912-07-30",until:"1926-12-24",offset:1,name:"大正",narrow:"㍽",abbr:"T"},{since:"1873-01-01",until:"1912-07-29",offset:6,name:"明治",narrow:"㍾",abbr:"M"},{since:"0001-01-01",until:"1873-12-31",offset:1,name:"西暦",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"紀元前",narrow:"BC",abbr:"BC"},],eraYearOrdinalRegex:/(元|\d+)年/,eraYearOrdinalParse:function(e,t){return"元"===t[1]?1:parseInt(t[1]||e,10)},months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"),weekdaysShort:"日_月_火_水_木_金_土".split("_"),weekdaysMin:"日_月_火_水_木_金_土".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日 dddd HH:mm",l:"YYYY/MM/DD",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日(ddd) HH:mm"},meridiemParse:/午前|午後/i,isPM:function(e){return"午後"===e},meridiem:function(e,t,n){return e<12?"午前":"午後"},calendar:{sameDay:"[今日] LT",nextDay:"[明日] LT",nextWeek:function(e){return e.week()!==this.week()?"[来週]dddd LT":"dddd LT"},lastDay:"[昨日] LT",lastWeek:function(e){return this.week()!==e.week()?"[先週]dddd LT":"dddd LT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}日/,ordinal:function(e,t){switch(t){case"y":return 1===e?"元年":e+"年";case"d":case"D":case"DDD":return e+"日";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"数秒",ss:"%d秒",m:"1分",mm:"%d分",h:"1時間",hh:"%d時間",d:"1日",dd:"%d日",M:"1ヶ月",MM:"%dヶ月",y:"1年",yy:"%d年"}})})(n(30381))},24286:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("jv",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des".split("_"),weekdays:"Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu".split("_"),weekdaysShort:"Min_Sen_Sel_Reb_Kem_Jem_Sep".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sp".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/enjing|siyang|sonten|ndalu/,meridiemHour:function(e,t){return(12===e&&(e=0),"enjing"===t)?e:"siyang"===t?e>=11?e:e+12:"sonten"===t||"ndalu"===t?e+12:void 0},meridiem:function(e,t,n){return e<11?"enjing":e<15?"siyang":e<19?"sonten":"ndalu"},calendar:{sameDay:"[Dinten puniko pukul] LT",nextDay:"[Mbenjang pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kala wingi pukul] LT",lastWeek:"dddd [kepengker pukul] LT",sameElse:"L"},relativeTime:{future:"wonten ing %s",past:"%s ingkang kepengker",s:"sawetawis detik",ss:"%d detik",m:"setunggal menit",mm:"%d menit",h:"setunggal jam",hh:"%d jam",d:"sedinten",dd:"%d dinten",M:"sewulan",MM:"%d wulan",y:"setaun",yy:"%d taun"},week:{dow:1,doy:7}})})(n(30381))},12105:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ka",{months:"იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი".split("_"),monthsShort:"იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ".split("_"),weekdays:{standalone:"კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი".split("_"),format:"კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს".split("_"),isFormat:/(წინა|შემდეგ)/},weekdaysShort:"კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ".split("_"),weekdaysMin:"კვ_ორ_სა_ოთ_ხუ_პა_შა".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[დღეს] LT[-ზე]",nextDay:"[ხვალ] LT[-ზე]",lastDay:"[გუშინ] LT[-ზე]",nextWeek:"[შემდეგ] dddd LT[-ზე]",lastWeek:"[წინა] dddd LT-ზე",sameElse:"L"},relativeTime:{future:function(e){return e.replace(/(წამ|წუთ|საათ|წელ|დღ|თვ)(ი|ე)/,function(e,t,n){return"ი"===n?t+"ში":t+n+"ში"})},past:function(e){return/(წამი|წუთი|საათი|დღე|თვე)/.test(e)?e.replace(/(ი|ე)$/,"ის წინ"):/წელი/.test(e)?e.replace(/წელი$/,"წლის წინ"):e},s:"რამდენიმე წამი",ss:"%d წამი",m:"წუთი",mm:"%d წუთი",h:"საათი",hh:"%d საათი",d:"დღე",dd:"%d დღე",M:"თვე",MM:"%d თვე",y:"წელი",yy:"%d წელი"},dayOfMonthOrdinalParse:/0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,ordinal:function(e){return 0===e?e:1===e?e+"-ლი":e<20||e<=100&&e%20==0||e%100==0?"მე-"+e:e+"-ე"},week:{dow:1,doy:7}})})(n(30381))},47772:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={0:"-ші",1:"-ші",2:"-ші",3:"-ші",4:"-ші",5:"-ші",6:"-шы",7:"-ші",8:"-ші",9:"-шы",10:"-шы",20:"-шы",30:"-шы",40:"-шы",50:"-ші",60:"-шы",70:"-ші",80:"-ші",90:"-шы",100:"-ші"};return e.defineLocale("kk",{months:"қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан".split("_"),monthsShort:"қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел".split("_"),weekdays:"жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі".split("_"),weekdaysShort:"жек_дүй_сей_сәр_бей_жұм_сен".split("_"),weekdaysMin:"жк_дй_сй_ср_бй_жм_сн".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгін сағат] LT",nextDay:"[Ертең сағат] LT",nextWeek:"dddd [сағат] LT",lastDay:"[Кеше сағат] LT",lastWeek:"[Өткен аптаның] dddd [сағат] LT",sameElse:"L"},relativeTime:{future:"%s ішінде",past:"%s бұрын",s:"бірнеше секунд",ss:"%d секунд",m:"бір минут",mm:"%d минут",h:"бір сағат",hh:"%d сағат",d:"бір күн",dd:"%d күн",M:"бір ай",MM:"%d ай",y:"бір жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(ші|шы)/,ordinal:function(e){var n=e%10,r=e>=100?100:null;return e+(t[e]||t[n]||t[r])},week:{dow:1,doy:7}})})(n(30381))},18758:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"១",2:"២",3:"៣",4:"៤",5:"៥",6:"៦",7:"៧",8:"៨",9:"៩",0:"០"},n={"១":"1","២":"2","៣":"3","៤":"4","៥":"5","៦":"6","៧":"7","៨":"8","៩":"9","០":"0"};return e.defineLocale("km",{months:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),monthsShort:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),weekdays:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysShort:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysMin:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ព្រឹក|ល្ងាច/,isPM:function(e){return"ល្ងាច"===e},meridiem:function(e,t,n){return e<12?"ព្រឹក":"ល្ងាច"},calendar:{sameDay:"[ថ្ងៃនេះ ម៉ោង] LT",nextDay:"[ស្អែក ម៉ោង] LT",nextWeek:"dddd [ម៉ោង] LT",lastDay:"[ម្សិលមិញ ម៉ោង] LT",lastWeek:"dddd [សប្តាហ៍មុន] [ម៉ោង] LT",sameElse:"L"},relativeTime:{future:"%sទៀត",past:"%sមុន",s:"ប៉ុន្មានវិនាទី",ss:"%d វិនាទី",m:"មួយនាទី",mm:"%d នាទី",h:"មួយម៉ោង",hh:"%d ម៉ោង",d:"មួយថ្ងៃ",dd:"%d ថ្ងៃ",M:"មួយខែ",MM:"%d ខែ",y:"មួយឆ្នាំ",yy:"%d ឆ្នាំ"},dayOfMonthOrdinalParse:/ទី\d{1,2}/,ordinal:"ទី%d",preparse:function(e){return e.replace(/[១២៣៤៥៦៧៨៩០]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},week:{dow:1,doy:4}})})(n(30381))},79282:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"೧",2:"೨",3:"೩",4:"೪",5:"೫",6:"೬",7:"೭",8:"೮",9:"೯",0:"೦"},n={"೧":"1","೨":"2","೩":"3","೪":"4","೫":"5","೬":"6","೭":"7","೮":"8","೯":"9","೦":"0"};return e.defineLocale("kn",{months:"ಜನವರಿ_ಫೆಬ್ರವರಿ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂಬರ್_ಅಕ್ಟೋಬರ್_ನವೆಂಬರ್_ಡಿಸೆಂಬರ್".split("_"),monthsShort:"ಜನ_ಫೆಬ್ರ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂ_ಅಕ್ಟೋ_ನವೆಂ_ಡಿಸೆಂ".split("_"),monthsParseExact:!0,weekdays:"ಭಾನುವಾರ_ಸೋಮವಾರ_ಮಂಗಳವಾರ_ಬುಧವಾರ_ಗುರುವಾರ_ಶುಕ್ರವಾರ_ಶನಿವಾರ".split("_"),weekdaysShort:"ಭಾನು_ಸೋಮ_ಮಂಗಳ_ಬುಧ_ಗುರು_ಶುಕ್ರ_ಶನಿ".split("_"),weekdaysMin:"ಭಾ_ಸೋ_ಮಂ_ಬು_ಗು_ಶು_ಶ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[ಇಂದು] LT",nextDay:"[ನಾಳೆ] LT",nextWeek:"dddd, LT",lastDay:"[ನಿನ್ನೆ] LT",lastWeek:"[ಕೊನೆಯ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ನಂತರ",past:"%s ಹಿಂದೆ",s:"ಕೆಲವು ಕ್ಷಣಗಳು",ss:"%d ಸೆಕೆಂಡುಗಳು",m:"ಒಂದು ನಿಮಿಷ",mm:"%d ನಿಮಿಷ",h:"ಒಂದು ಗಂಟೆ",hh:"%d ಗಂಟೆ",d:"ಒಂದು ದಿನ",dd:"%d ದಿನ",M:"ಒಂದು ತಿಂಗಳು",MM:"%d ತಿಂಗಳು",y:"ಒಂದು ವರ್ಷ",yy:"%d ವರ್ಷ"},preparse:function(e){return e.replace(/[೧೨೩೪೫೬೭೮೯೦]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/ರಾತ್ರಿ|ಬೆಳಿಗ್ಗೆ|ಮಧ್ಯಾಹ್ನ|ಸಂಜೆ/,meridiemHour:function(e,t){return(12===e&&(e=0),"ರಾತ್ರಿ"===t)?e<4?e:e+12:"ಬೆಳಿಗ್ಗೆ"===t?e:"ಮಧ್ಯಾಹ್ನ"===t?e>=10?e:e+12:"ಸಂಜೆ"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"ರಾತ್ರಿ":e<10?"ಬೆಳಿಗ್ಗೆ":e<17?"ಮಧ್ಯಾಹ್ನ":e<20?"ಸಂಜೆ":"ರಾತ್ರಿ"},dayOfMonthOrdinalParse:/\d{1,2}(ನೇ)/,ordinal:function(e){return e+"ನೇ"},week:{dow:0,doy:6}})})(n(30381))},33730:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ko",{months:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),monthsShort:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),weekdays:"일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"),weekdaysShort:"일_월_화_수_목_금_토".split("_"),weekdaysMin:"일_월_화_수_목_금_토".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY년 MMMM D일",LLL:"YYYY년 MMMM D일 A h:mm",LLLL:"YYYY년 MMMM D일 dddd A h:mm",l:"YYYY.MM.DD.",ll:"YYYY년 MMMM D일",lll:"YYYY년 MMMM D일 A h:mm",llll:"YYYY년 MMMM D일 dddd A h:mm"},calendar:{sameDay:"오늘 LT",nextDay:"내일 LT",nextWeek:"dddd LT",lastDay:"어제 LT",lastWeek:"지난주 dddd LT",sameElse:"L"},relativeTime:{future:"%s 후",past:"%s 전",s:"몇 초",ss:"%d초",m:"1분",mm:"%d분",h:"한 시간",hh:"%d시간",d:"하루",dd:"%d일",M:"한 달",MM:"%d달",y:"일 년",yy:"%d년"},dayOfMonthOrdinalParse:/\d{1,2}(일|월|주)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"일";case"M":return e+"월";case"w":case"W":return e+"주";default:return e}},meridiemParse:/오전|오후/,isPM:function(e){return"오후"===e},meridiem:function(e,t,n){return e<12?"오전":"오후"}})})(n(30381))},1408:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},n={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},r=["کانونی دووەم","شوبات","ئازار","نیسان","ئایار","حوزەیران","تەمموز","ئاب","ئەیلوول","تشرینی یەكەم","تشرینی دووەم","كانونی یەکەم",];return e.defineLocale("ku",{months:r,monthsShort:r,weekdays:"یه‌كشه‌ممه‌_دووشه‌ممه‌_سێشه‌ممه‌_چوارشه‌ممه‌_پێنجشه‌ممه‌_هه‌ینی_شه‌ممه‌".split("_"),weekdaysShort:"یه‌كشه‌م_دووشه‌م_سێشه‌م_چوارشه‌م_پێنجشه‌م_هه‌ینی_شه‌ممه‌".split("_"),weekdaysMin:"ی_د_س_چ_پ_ه_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ئێواره‌|به‌یانی/,isPM:function(e){return/ئێواره‌/.test(e)},meridiem:function(e,t,n){return e<12?"به‌یانی":"ئێواره‌"},calendar:{sameDay:"[ئه‌مرۆ كاتژمێر] LT",nextDay:"[به‌یانی كاتژمێر] LT",nextWeek:"dddd [كاتژمێر] LT",lastDay:"[دوێنێ كاتژمێر] LT",lastWeek:"dddd [كاتژمێر] LT",sameElse:"L"},relativeTime:{future:"له‌ %s",past:"%s",s:"چه‌ند چركه‌یه‌ك",ss:"چركه‌ %d",m:"یه‌ك خوله‌ك",mm:"%d خوله‌ك",h:"یه‌ك كاتژمێر",hh:"%d كاتژمێر",d:"یه‌ك ڕۆژ",dd:"%d ڕۆژ",M:"یه‌ك مانگ",MM:"%d مانگ",y:"یه‌ك ساڵ",yy:"%d ساڵ"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,function(e){return n[e]}).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]}).replace(/,/g,"،")},week:{dow:6,doy:12}})})(n(30381))},33291:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={0:"-чү",1:"-чи",2:"-чи",3:"-чү",4:"-чү",5:"-чи",6:"-чы",7:"-чи",8:"-чи",9:"-чу",10:"-чу",20:"-чы",30:"-чу",40:"-чы",50:"-чү",60:"-чы",70:"-чи",80:"-чи",90:"-чу",100:"-чү"};return e.defineLocale("ky",{months:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_"),monthsShort:"янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек".split("_"),weekdays:"Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби".split("_"),weekdaysShort:"Жек_Дүй_Шей_Шар_Бей_Жум_Ише".split("_"),weekdaysMin:"Жк_Дй_Шй_Шр_Бй_Жм_Иш".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгүн саат] LT",nextDay:"[Эртең саат] LT",nextWeek:"dddd [саат] LT",lastDay:"[Кечээ саат] LT",lastWeek:"[Өткөн аптанын] dddd [күнү] [саат] LT",sameElse:"L"},relativeTime:{future:"%s ичинде",past:"%s мурун",s:"бирнече секунд",ss:"%d секунд",m:"бир мүнөт",mm:"%d мүнөт",h:"бир саат",hh:"%d саат",d:"бир күн",dd:"%d күн",M:"бир ай",MM:"%d ай",y:"бир жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(чи|чы|чү|чу)/,ordinal:function(e){var n=e%10,r=e>=100?100:null;return e+(t[e]||t[n]||t[r])},week:{dow:1,doy:7}})})(n(30381))},36841:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return t?i[n][0]:i[n][1]}function n(e){return i(e.substr(0,e.indexOf(" ")))?"a "+e:"an "+e}function r(e){return i(e.substr(0,e.indexOf(" ")))?"viru "+e:"virun "+e}function i(e){if(e=parseInt(e,10),isNaN(e))return!1;if(e<0)return!0;if(e<10)return!!(4<=e)&&!!(e<=7);if(e<100){var t=e%10,n=e/10;return 0===t?i(n):i(t)}if(!(e<1e4))return i(e/=1e3);for(;e>=10;)e/=10;return i(e)}return e.defineLocale("lb",{months:"Januar_Februar_M\xe4erz_Abr\xebll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_M\xe9indeg_D\xebnschdeg_M\xebttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._M\xe9._D\xeb._M\xeb._Do._Fr._Sa.".split("_"),weekdaysMin:"So_M\xe9_D\xeb_M\xeb_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[G\xebschter um] LT",lastWeek:function(){switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:n,past:r,s:"e puer Sekonnen",ss:"%d Sekonnen",m:t,mm:"%d Minutten",h:t,hh:"%d Stonnen",d:t,dd:"%d Deeg",M:t,MM:"%d M\xe9int",y:t,yy:"%d Joer"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},55466:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("lo",{months:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),monthsShort:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),weekdays:"ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysShort:"ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysMin:"ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"ວັນdddd D MMMM YYYY HH:mm"},meridiemParse:/ຕອນເຊົ້າ|ຕອນແລງ/,isPM:function(e){return"ຕອນແລງ"===e},meridiem:function(e,t,n){return e<12?"ຕອນເຊົ້າ":"ຕອນແລງ"},calendar:{sameDay:"[ມື້ນີ້ເວລາ] LT",nextDay:"[ມື້ອື່ນເວລາ] LT",nextWeek:"[ວັນ]dddd[ໜ້າເວລາ] LT",lastDay:"[ມື້ວານນີ້ເວລາ] LT",lastWeek:"[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT",sameElse:"L"},relativeTime:{future:"ອີກ %s",past:"%sຜ່ານມາ",s:"ບໍ່ເທົ່າໃດວິນາທີ",ss:"%d ວິນາທີ",m:"1 ນາທີ",mm:"%d ນາທີ",h:"1 ຊົ່ວໂມງ",hh:"%d ຊົ່ວໂມງ",d:"1 ມື້",dd:"%d ມື້",M:"1 ເດືອນ",MM:"%d ເດືອນ",y:"1 ປີ",yy:"%d ປີ"},dayOfMonthOrdinalParse:/(ທີ່)\d{1,2}/,ordinal:function(e){return"ທີ່"+e}})})(n(30381))},57010:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={ss:"sekundė_sekundžių_sekundes",m:"minutė_minutės_minutę",mm:"minutės_minučių_minutes",h:"valanda_valandos_valandą",hh:"valandos_valandų_valandas",d:"diena_dienos_dieną",dd:"dienos_dienų_dienas",M:"mėnuo_mėnesio_mėnesį",MM:"mėnesiai_mėnesių_mėnesius",y:"metai_metų_metus",yy:"metai_metų_metus"};function n(e,t,n,r){return t?"kelios sekundės":r?"kelių sekundžių":"kelias sekundes"}function r(e,t,n,r){return t?a(n)[0]:r?a(n)[1]:a(n)[2]}function i(e){return e%10==0||e>10&&e<20}function a(e){return t[e].split("_")}function o(e,t,n,o){var s=e+" ";return 1===e?s+r(e,t,n[0],o):t?s+(i(e)?a(n)[1]:a(n)[0]):o?s+a(n)[1]:s+(i(e)?a(n)[1]:a(n)[2])}return e.defineLocale("lt",{months:{format:"sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"),weekdaysMin:"S_P_A_T_K_Pn_Š".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[Šiandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Praėjusį] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prieš %s",s:n,ss:o,m:r,mm:o,h:r,hh:o,d:r,dd:o,M:r,MM:o,y:r,yy:o},dayOfMonthOrdinalParse:/\d{1,2}-oji/,ordinal:function(e){return e+"-oji"},week:{dow:1,doy:4}})})(n(30381))},37595:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={ss:"sekundes_sekundēm_sekunde_sekundes".split("_"),m:"minūtes_minūtēm_minūte_minūtes".split("_"),mm:"minūtes_minūtēm_minūte_minūtes".split("_"),h:"stundas_stundām_stunda_stundas".split("_"),hh:"stundas_stundām_stunda_stundas".split("_"),d:"dienas_dienām_diena_dienas".split("_"),dd:"dienas_dienām_diena_dienas".split("_"),M:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),MM:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),y:"gada_gadiem_gads_gadi".split("_"),yy:"gada_gadiem_gads_gadi".split("_")};function n(e,t,n){return n?t%10==1&&t%100!=11?e[2]:e[3]:t%10==1&&t%100!=11?e[0]:e[1]}function r(e,r,i){return e+" "+n(t[i],e,r)}function i(e,r,i){return n(t[i],e,r)}function a(e,t){return t?"dažas sekundes":"dažām sekundēm"}return e.defineLocale("lv",{months:"janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"),monthsShort:"jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"),weekdays:"svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"),weekdaysShort:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysMin:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY.",LL:"YYYY. [gada] D. MMMM",LLL:"YYYY. [gada] D. MMMM, HH:mm",LLLL:"YYYY. [gada] D. MMMM, dddd, HH:mm"},calendar:{sameDay:"[Šodien pulksten] LT",nextDay:"[Rīt pulksten] LT",nextWeek:"dddd [pulksten] LT",lastDay:"[Vakar pulksten] LT",lastWeek:"[Pagājušā] dddd [pulksten] LT",sameElse:"L"},relativeTime:{future:"pēc %s",past:"pirms %s",s:a,ss:r,m:i,mm:r,h:i,hh:r,d:i,dd:r,M:i,MM:r,y:i,yy:r},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},39861:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={words:{ss:["sekund","sekunda","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mjesec","mjeseca","mjeseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(e,t){return 1===e?t[0]:e>=2&&e<=4?t[1]:t[2]},translate:function(e,n,r){var i=t.words[r];return 1===r.length?n?i[0]:i[1]:e+" "+t.correctGrammaticalCase(e,i)}};return e.defineLocale("me",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sjutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedjelje] [u] LT","[prošlog] [ponedjeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srijede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT",][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"nekoliko sekundi",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:"dan",dd:t.translate,M:"mjesec",MM:t.translate,y:"godinu",yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})})(n(30381))},35493:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("mi",{months:"Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea".split("_"),monthsShort:"Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki".split("_"),monthsRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,weekdays:"Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei".split("_"),weekdaysShort:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),weekdaysMin:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [i] HH:mm",LLLL:"dddd, D MMMM YYYY [i] HH:mm"},calendar:{sameDay:"[i teie mahana, i] LT",nextDay:"[apopo i] LT",nextWeek:"dddd [i] LT",lastDay:"[inanahi i] LT",lastWeek:"dddd [whakamutunga i] LT",sameElse:"L"},relativeTime:{future:"i roto i %s",past:"%s i mua",s:"te hēkona ruarua",ss:"%d hēkona",m:"he meneti",mm:"%d meneti",h:"te haora",hh:"%d haora",d:"he ra",dd:"%d ra",M:"he marama",MM:"%d marama",y:"he tau",yy:"%d tau"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4}})})(n(30381))},95966:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("mk",{months:"јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"),monthsShort:"јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"),weekdays:"недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"),weekdaysShort:"нед_пон_вто_сре_чет_пет_саб".split("_"),weekdaysMin:"нe_пo_вт_ср_че_пе_сa".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Денес во] LT",nextDay:"[Утре во] LT",nextWeek:"[Во] dddd [во] LT",lastDay:"[Вчера во] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Изминатата] dddd [во] LT";case 1:case 2:case 4:case 5:return"[Изминатиот] dddd [во] LT"}},sameElse:"L"},relativeTime:{future:"за %s",past:"пред %s",s:"неколку секунди",ss:"%d секунди",m:"една минута",mm:"%d минути",h:"еден час",hh:"%d часа",d:"еден ден",dd:"%d дена",M:"еден месец",MM:"%d месеци",y:"една година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var t=e%10,n=e%100;if(0===e)return e+"-ев";if(0===n)return e+"-ен";if(n>10&&n<20)return e+"-ти";if(1===t)return e+"-ви";if(2===t)return e+"-ри";else if(7===t||8===t)return e+"-ми";else return e+"-ти"},week:{dow:1,doy:7}})})(n(30381))},87341:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ml",{months:"ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ".split("_"),monthsShort:"ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.".split("_"),monthsParseExact:!0,weekdays:"ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച".split("_"),weekdaysShort:"ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി".split("_"),weekdaysMin:"ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ".split("_"),longDateFormat:{LT:"A h:mm -നു",LTS:"A h:mm:ss -നു",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm -നു",LLLL:"dddd, D MMMM YYYY, A h:mm -നു"},calendar:{sameDay:"[ഇന്ന്] LT",nextDay:"[നാളെ] LT",nextWeek:"dddd, LT",lastDay:"[ഇന്നലെ] LT",lastWeek:"[കഴിഞ്ഞ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s കഴിഞ്ഞ്",past:"%s മുൻപ്",s:"അൽപ നിമിഷങ്ങൾ",ss:"%d സെക്കൻഡ്",m:"ഒരു മിനിറ്റ്",mm:"%d മിനിറ്റ്",h:"ഒരു മണിക്കൂർ",hh:"%d മണിക്കൂർ",d:"ഒരു ദിവസം",dd:"%d ദിവസം",M:"ഒരു മാസം",MM:"%d മാസം",y:"ഒരു വർഷം",yy:"%d വർഷം"},meridiemParse:/രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,meridiemHour:function(e,t){return(12===e&&(e=0),"രാത്രി"===t&&e>=4||"ഉച്ച കഴിഞ്ഞ്"===t||"വൈകുന്നേരം"===t)?e+12:e},meridiem:function(e,t,n){return e<4?"രാത്രി":e<12?"രാവിലെ":e<17?"ഉച്ച കഴിഞ്ഞ്":e<20?"വൈകുന്നേരം":"രാത്രി"}})})(n(30381))},5115:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){switch(n){case"s":return t?"хэдхэн секунд":"хэдхэн секундын";case"ss":return e+(t?" секунд":" секундын");case"m":case"mm":return e+(t?" минут":" минутын");case"h":case"hh":return e+(t?" цаг":" цагийн");case"d":case"dd":return e+(t?" өдөр":" өдрийн");case"M":case"MM":return e+(t?" сар":" сарын");case"y":case"yy":return e+(t?" жил":" жилийн");default:return e}}return e.defineLocale("mn",{months:"Нэгдүгээр сар_Хоёрдугаар сар_Гуравдугаар сар_Дөрөвдүгээр сар_Тавдугаар сар_Зургадугаар сар_Долдугаар сар_Наймдугаар сар_Есдүгээр сар_Аравдугаар сар_Арван нэгдүгээр сар_Арван хоёрдугаар сар".split("_"),monthsShort:"1 сар_2 сар_3 сар_4 сар_5 сар_6 сар_7 сар_8 сар_9 сар_10 сар_11 сар_12 сар".split("_"),monthsParseExact:!0,weekdays:"Ням_Даваа_Мягмар_Лхагва_Пүрэв_Баасан_Бямба".split("_"),weekdaysShort:"Ням_Дав_Мяг_Лха_Пүр_Баа_Бям".split("_"),weekdaysMin:"Ня_Да_Мя_Лх_Пү_Ба_Бя".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY оны MMMMын D",LLL:"YYYY оны MMMMын D HH:mm",LLLL:"dddd, YYYY оны MMMMын D HH:mm"},meridiemParse:/ҮӨ|ҮХ/i,isPM:function(e){return"ҮХ"===e},meridiem:function(e,t,n){return e<12?"ҮӨ":"ҮХ"},calendar:{sameDay:"[Өнөөдөр] LT",nextDay:"[Маргааш] LT",nextWeek:"[Ирэх] dddd LT",lastDay:"[Өчигдөр] LT",lastWeek:"[Өнгөрсөн] dddd LT",sameElse:"L"},relativeTime:{future:"%s дараа",past:"%s өмнө",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2} өдөр/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+" өдөр";default:return e}}})})(n(30381))},10370:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},n={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};function r(e,t,n,r){var i="";if(t)switch(n){case"s":i="काही सेकंद";break;case"ss":i="%d सेकंद";break;case"m":i="एक मिनिट";break;case"mm":i="%d मिनिटे";break;case"h":i="एक तास";break;case"hh":i="%d तास";break;case"d":i="एक दिवस";break;case"dd":i="%d दिवस";break;case"M":i="एक महिना";break;case"MM":i="%d महिने";break;case"y":i="एक वर्ष";break;case"yy":i="%d वर्षे"}else switch(n){case"s":i="काही सेकंदां";break;case"ss":i="%d सेकंदां";break;case"m":i="एका मिनिटा";break;case"mm":i="%d मिनिटां";break;case"h":i="एका तासा";break;case"hh":i="%d तासां";break;case"d":i="एका दिवसा";break;case"dd":i="%d दिवसां";break;case"M":i="एका महिन्या";break;case"MM":i="%d महिन्यां";break;case"y":i="एका वर्षा";break;case"yy":i="%d वर्षां"}return i.replace(/%d/i,e)}return e.defineLocale("mr",{months:"जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),monthsShort:"जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm वाजता",LTS:"A h:mm:ss वाजता",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm वाजता",LLLL:"dddd, D MMMM YYYY, A h:mm वाजता"},calendar:{sameDay:"[आज] LT",nextDay:"[उद्या] LT",nextWeek:"dddd, LT",lastDay:"[काल] LT",lastWeek:"[मागील] dddd, LT",sameElse:"L"},relativeTime:{future:"%sमध्ये",past:"%sपूर्वी",s:r,ss:r,m:r,mm:r,h:r,hh:r,d:r,dd:r,M:r,MM:r,y:r,yy:r},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/पहाटे|सकाळी|दुपारी|सायंकाळी|रात्री/,meridiemHour:function(e,t){return(12===e&&(e=0),"पहाटे"===t||"सकाळी"===t)?e:"दुपारी"===t||"सायंकाळी"===t||"रात्री"===t?e>=12?e:e+12:void 0},meridiem:function(e,t,n){return e>=0&&e<6?"पहाटे":e<12?"सकाळी":e<17?"दुपारी":e<20?"सायंकाळी":"रात्री"},week:{dow:0,doy:6}})})(n(30381))},41237:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,t){return(12===e&&(e=0),"pagi"===t)?e:"tengahari"===t?e>=11?e:e+12:"petang"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,n){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})})(n(30381))},9847:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,t){return(12===e&&(e=0),"pagi"===t)?e:"tengahari"===t?e>=11?e:e+12:"petang"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,n){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})})(n(30381))},72126:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("mt",{months:"Jannar_Frar_Marzu_April_Mejju_Ġunju_Lulju_Awwissu_Settembru_Ottubru_Novembru_Diċembru".split("_"),monthsShort:"Jan_Fra_Mar_Apr_Mej_Ġun_Lul_Aww_Set_Ott_Nov_Diċ".split("_"),weekdays:"Il-Ħadd_It-Tnejn_It-Tlieta_L-Erbgħa_Il-Ħamis_Il-Ġimgħa_Is-Sibt".split("_"),weekdaysShort:"Ħad_Tne_Tli_Erb_Ħam_Ġim_Sib".split("_"),weekdaysMin:"Ħa_Tn_Tl_Er_Ħa_Ġi_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Illum fil-]LT",nextDay:"[Għada fil-]LT",nextWeek:"dddd [fil-]LT",lastDay:"[Il-bieraħ fil-]LT",lastWeek:"dddd [li għadda] [fil-]LT",sameElse:"L"},relativeTime:{future:"f’ %s",past:"%s ilu",s:"ftit sekondi",ss:"%d sekondi",m:"minuta",mm:"%d minuti",h:"siegħa",hh:"%d siegħat",d:"ġurnata",dd:"%d ġranet",M:"xahar",MM:"%d xhur",y:"sena",yy:"%d sni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4}})})(n(30381))},56165:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"၁",2:"၂",3:"၃",4:"၄",5:"၅",6:"၆",7:"၇",8:"၈",9:"၉",0:"၀"},n={"၁":"1","၂":"2","၃":"3","၄":"4","၅":"5","၆":"6","၇":"7","၈":"8","၉":"9","၀":"0"};return e.defineLocale("my",{months:"ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ".split("_"),monthsShort:"ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ".split("_"),weekdays:"တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ".split("_"),weekdaysShort:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),weekdaysMin:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ယနေ.] LT [မှာ]",nextDay:"[မနက်ဖြန်] LT [မှာ]",nextWeek:"dddd LT [မှာ]",lastDay:"[မနေ.က] LT [မှာ]",lastWeek:"[ပြီးခဲ့သော] dddd LT [မှာ]",sameElse:"L"},relativeTime:{future:"လာမည့် %s မှာ",past:"လွန်ခဲ့သော %s က",s:"စက္ကန်.အနည်းငယ်",ss:"%d စက္ကန့်",m:"တစ်မိနစ်",mm:"%d မိနစ်",h:"တစ်နာရီ",hh:"%d နာရီ",d:"တစ်ရက်",dd:"%d ရက်",M:"တစ်လ",MM:"%d လ",y:"တစ်နှစ်",yy:"%d နှစ်"},preparse:function(e){return e.replace(/[၁၂၃၄၅၆၇၈၉၀]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},week:{dow:1,doy:4}})})(n(30381))},64924:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"s\xf8ndag_mandag_tirsdag_onsdag_torsdag_fredag_l\xf8rdag".split("_"),weekdaysShort:"s\xf8._ma._ti._on._to._fr._l\xf8.".split("_"),weekdaysMin:"s\xf8_ma_ti_on_to_fr_l\xf8".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i g\xe5r kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",ss:"%d sekunder",m:"ett minutt",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dager",w:"en uke",ww:"%d uker",M:"en m\xe5ned",MM:"%d m\xe5neder",y:"ett \xe5r",yy:"%d \xe5r"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},16744:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},n={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};return e.defineLocale("ne",{months:"जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर".split("_"),monthsShort:"जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.".split("_"),monthsParseExact:!0,weekdays:"आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार".split("_"),weekdaysShort:"आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.".split("_"),weekdaysMin:"आ._सो._मं._बु._बि._शु._श.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"Aको h:mm बजे",LTS:"Aको h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, Aको h:mm बजे",LLLL:"dddd, D MMMM YYYY, Aको h:mm बजे"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/राति|बिहान|दिउँसो|साँझ/,meridiemHour:function(e,t){return(12===e&&(e=0),"राति"===t)?e<4?e:e+12:"बिहान"===t?e:"दिउँसो"===t?e>=10?e:e+12:"साँझ"===t?e+12:void 0},meridiem:function(e,t,n){return e<3?"राति":e<12?"बिहान":e<16?"दिउँसो":e<20?"साँझ":"राति"},calendar:{sameDay:"[आज] LT",nextDay:"[भोलि] LT",nextWeek:"[आउँदो] dddd[,] LT",lastDay:"[हिजो] LT",lastWeek:"[गएको] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%sमा",past:"%s अगाडि",s:"केही क्षण",ss:"%d सेकेण्ड",m:"एक मिनेट",mm:"%d मिनेट",h:"एक घण्टा",hh:"%d घण्टा",d:"एक दिन",dd:"%d दिन",M:"एक महिना",MM:"%d महिना",y:"एक बर्ष",yy:"%d बर्ष"},week:{dow:0,doy:6}})})(n(30381))},59814:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),n="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),r=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i,],i=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;return e.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,r){return e?/-MMM-/.test(r)?n[e.month()]:t[e.month()]:t},monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"\xe9\xe9n minuut",mm:"%d minuten",h:"\xe9\xe9n uur",hh:"%d uur",d:"\xe9\xe9n dag",dd:"%d dagen",M:"\xe9\xe9n maand",MM:"%d maanden",y:"\xe9\xe9n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})})(n(30381))},93901:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),n="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),r=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i,],i=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;return e.defineLocale("nl",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,r){return e?/-MMM-/.test(r)?n[e.month()]:t[e.month()]:t},monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"\xe9\xe9n minuut",mm:"%d minuten",h:"\xe9\xe9n uur",hh:"%d uur",d:"\xe9\xe9n dag",dd:"%d dagen",w:"\xe9\xe9n week",ww:"%d weken",M:"\xe9\xe9n maand",MM:"%d maanden",y:"\xe9\xe9n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})})(n(30381))},83877:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("nn",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"sundag_m\xe5ndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"),weekdaysShort:"su._m\xe5._ty._on._to._fr._lau.".split("_"),weekdaysMin:"su_m\xe5_ty_on_to_fr_la".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[I dag klokka] LT",nextDay:"[I morgon klokka] LT",nextWeek:"dddd [klokka] LT",lastDay:"[I g\xe5r klokka] LT",lastWeek:"[F\xf8reg\xe5ande] dddd [klokka] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s sidan",s:"nokre sekund",ss:"%d sekund",m:"eit minutt",mm:"%d minutt",h:"ein time",hh:"%d timar",d:"ein dag",dd:"%d dagar",w:"ei veke",ww:"%d veker",M:"ein m\xe5nad",MM:"%d m\xe5nader",y:"eit \xe5r",yy:"%d \xe5r"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},92135:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("oc-lnc",{months:{standalone:"geni\xe8r_febri\xe8r_mar\xe7_abril_mai_junh_julhet_agost_setembre_oct\xf2bre_novembre_decembre".split("_"),format:"de geni\xe8r_de febri\xe8r_de mar\xe7_d'abril_de mai_de junh_de julhet_d'agost_de setembre_d'oct\xf2bre_de novembre_de decembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._mar\xe7_abr._mai_junh_julh._ago._set._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"dimenge_diluns_dimars_dim\xe8cres_dij\xf2us_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dm._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dm_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:"[u\xe8i a] LT",nextDay:"[deman a] LT",nextWeek:"dddd [a] LT",lastDay:"[i\xe8r a] LT",lastWeek:"dddd [passat a] LT",sameElse:"L"},relativeTime:{future:"d'aqu\xed %s",past:"fa %s",s:"unas segondas",ss:"%d segondas",m:"una minuta",mm:"%d minutas",h:"una ora",hh:"%d oras",d:"un jorn",dd:"%d jorns",M:"un mes",MM:"%d meses",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,t){var n=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"\xe8";return("w"===t||"W"===t)&&(n="a"),e+n},week:{dow:1,doy:4}})})(n(30381))},15858:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"੧",2:"੨",3:"੩",4:"੪",5:"੫",6:"੬",7:"੭",8:"੮",9:"੯",0:"੦"},n={"੧":"1","੨":"2","੩":"3","੪":"4","੫":"5","੬":"6","੭":"7","੮":"8","੯":"9","੦":"0"};return e.defineLocale("pa-in",{months:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),monthsShort:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),weekdays:"ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ".split("_"),weekdaysShort:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),weekdaysMin:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),longDateFormat:{LT:"A h:mm ਵਜੇ",LTS:"A h:mm:ss ਵਜੇ",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm ਵਜੇ",LLLL:"dddd, D MMMM YYYY, A h:mm ਵਜੇ"},calendar:{sameDay:"[ਅਜ] LT",nextDay:"[ਕਲ] LT",nextWeek:"[ਅਗਲਾ] dddd, LT",lastDay:"[ਕਲ] LT",lastWeek:"[ਪਿਛਲੇ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ਵਿੱਚ",past:"%s ਪਿਛਲੇ",s:"ਕੁਝ ਸਕਿੰਟ",ss:"%d ਸਕਿੰਟ",m:"ਇਕ ਮਿੰਟ",mm:"%d ਮਿੰਟ",h:"ਇੱਕ ਘੰਟਾ",hh:"%d ਘੰਟੇ",d:"ਇੱਕ ਦਿਨ",dd:"%d ਦਿਨ",M:"ਇੱਕ ਮਹੀਨਾ",MM:"%d ਮਹੀਨੇ",y:"ਇੱਕ ਸਾਲ",yy:"%d ਸਾਲ"},preparse:function(e){return e.replace(/[੧੨੩੪੫੬੭੮੯੦]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,meridiemHour:function(e,t){return(12===e&&(e=0),"ਰਾਤ"===t)?e<4?e:e+12:"ਸਵੇਰ"===t?e:"ਦੁਪਹਿਰ"===t?e>=10?e:e+12:"ਸ਼ਾਮ"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"ਰਾਤ":e<10?"ਸਵੇਰ":e<17?"ਦੁਪਹਿਰ":e<20?"ਸ਼ਾਮ":"ਰਾਤ"},week:{dow:0,doy:6}})})(n(30381))},64495:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_"),n="stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_"),r=[/^sty/i,/^lut/i,/^mar/i,/^kwi/i,/^maj/i,/^cze/i,/^lip/i,/^sie/i,/^wrz/i,/^paź/i,/^lis/i,/^gru/i,];function i(e){return e%10<5&&e%10>1&&~~(e/10)%10!=1}function a(e,t,n){var r=e+" ";switch(n){case"ss":return r+(i(e)?"sekundy":"sekund");case"m":return t?"minuta":"minutę";case"mm":return r+(i(e)?"minuty":"minut");case"h":return t?"godzina":"godzinę";case"hh":return r+(i(e)?"godziny":"godzin");case"ww":return r+(i(e)?"tygodnie":"tygodni");case"MM":return r+(i(e)?"miesiące":"miesięcy");case"yy":return r+(i(e)?"lata":"lat")}}return e.defineLocale("pl",{months:function(e,r){return e?/D MMMM/.test(r)?n[e.month()]:t[e.month()]:t},monthsShort:"sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"),monthsParse:r,longMonthsParse:r,shortMonthsParse:r,weekdays:"niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"),weekdaysShort:"ndz_pon_wt_śr_czw_pt_sob".split("_"),weekdaysMin:"Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Dziś o] LT",nextDay:"[Jutro o] LT",nextWeek:function(){switch(this.day()){case 0:return"[W niedzielę o] LT";case 2:return"[We wtorek o] LT";case 3:return"[W środę o] LT";case 6:return"[W sobotę o] LT";default:return"[W] dddd [o] LT"}},lastDay:"[Wczoraj o] LT",lastWeek:function(){switch(this.day()){case 0:return"[W zeszłą niedzielę o] LT";case 3:return"[W zeszłą środę o] LT";case 6:return"[W zeszłą sobotę o] LT";default:return"[W zeszły] dddd [o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"%s temu",s:"kilka sekund",ss:a,m:a,mm:a,h:a,hh:a,d:"1 dzień",dd:"%d dni",w:"tydzień",ww:a,M:"miesiąc",MM:a,y:"rok",yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},57971:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("pt-br",{months:"janeiro_fevereiro_mar\xe7o_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"domingo_segunda-feira_ter\xe7a-feira_quarta-feira_quinta-feira_sexta-feira_s\xe1bado".split("_"),weekdaysShort:"dom_seg_ter_qua_qui_sex_s\xe1b".split("_"),weekdaysMin:"do_2\xaa_3\xaa_4\xaa_5\xaa_6\xaa_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [\xe0s] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [\xe0s] HH:mm"},calendar:{sameDay:"[Hoje \xe0s] LT",nextDay:"[Amanh\xe3 \xe0s] LT",nextWeek:"dddd [\xe0s] LT",lastDay:"[Ontem \xe0s] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[\xdaltimo] dddd [\xe0s] LT":"[\xdaltima] dddd [\xe0s] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"h\xe1 %s",s:"poucos segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um m\xeas",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",invalidDate:"Data inv\xe1lida"})})(n(30381))},89520:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("pt",{months:"janeiro_fevereiro_mar\xe7o_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"Domingo_Segunda-feira_Ter\xe7a-feira_Quarta-feira_Quinta-feira_Sexta-feira_S\xe1bado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_S\xe1b".split("_"),weekdaysMin:"Do_2\xaa_3\xaa_4\xaa_5\xaa_6\xaa_S\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje \xe0s] LT",nextDay:"[Amanh\xe3 \xe0s] LT",nextWeek:"dddd [\xe0s] LT",lastDay:"[Ontem \xe0s] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[\xdaltimo] dddd [\xe0s] LT":"[\xdaltima] dddd [\xe0s] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"h\xe1 %s",s:"segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",w:"uma semana",ww:"%d semanas",M:"um m\xeas",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%d\xba",week:{dow:1,doy:4}})})(n(30381))},96459:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n){var r=" ";return(e%100>=20||e>=100&&e%100==0)&&(r=" de "),e+r+({ss:"secunde",mm:"minute",hh:"ore",dd:"zile",ww:"săptăm\xe2ni",MM:"luni",yy:"ani"})[n]}return e.defineLocale("ro",{months:"ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"),monthsShort:"ian._feb._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"duminică_luni_marți_miercuri_joi_vineri_s\xe2mbătă".split("_"),weekdaysShort:"Dum_Lun_Mar_Mie_Joi_Vin_S\xe2m".split("_"),weekdaysMin:"Du_Lu_Ma_Mi_Jo_Vi_S\xe2".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[azi la] LT",nextDay:"[m\xe2ine la] LT",nextWeek:"dddd [la] LT",lastDay:"[ieri la] LT",lastWeek:"[fosta] dddd [la] LT",sameElse:"L"},relativeTime:{future:"peste %s",past:"%s \xeen urmă",s:"c\xe2teva secunde",ss:t,m:"un minut",mm:t,h:"o oră",hh:t,d:"o zi",dd:t,w:"o săptăm\xe2nă",ww:t,M:"o lună",MM:t,y:"un an",yy:t},week:{dow:1,doy:7}})})(n(30381))},21793:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t){var n=e.split("_");return t%10==1&&t%100!=11?n[0]:t%10>=2&&t%10<=4&&(t%100<10||t%100>=20)?n[1]:n[2]}function n(e,n,r){var i={ss:n?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:n?"минута_минуты_минут":"минуту_минуты_минут",hh:"час_часа_часов",dd:"день_дня_дней",ww:"неделя_недели_недель",MM:"месяц_месяца_месяцев",yy:"год_года_лет"};return"m"===r?n?"минута":"минуту":e+" "+t(i[r],+e)}var r=[/^янв/i,/^фев/i,/^мар/i,/^апр/i,/^ма[йя]/i,/^июн/i,/^июл/i,/^авг/i,/^сен/i,/^окт/i,/^ноя/i,/^дек/i,];return e.defineLocale("ru",{months:{format:"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"),standalone:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_")},monthsShort:{format:"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.".split("_"),standalone:"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.".split("_")},weekdays:{standalone:"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"),format:"воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"),isFormat:/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?] ?dddd/},weekdaysShort:"вс_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"вс_пн_вт_ср_чт_пт_сб".split("_"),monthsParse:r,longMonthsParse:r,shortMonthsParse:r,monthsRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsShortRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsStrictRegex:/^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,monthsShortStrictRegex:/^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., H:mm",LLLL:"dddd, D MMMM YYYY г., H:mm"},calendar:{sameDay:"[Сегодня, в] LT",nextDay:"[Завтра, в] LT",lastDay:"[Вчера, в] LT",nextWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В следующее] dddd, [в] LT";case 1:case 2:case 4:return"[В следующий] dddd, [в] LT";case 3:case 5:case 6:return"[В следующую] dddd, [в] LT"}},lastWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В прошлое] dddd, [в] LT";case 1:case 2:case 4:return"[В прошлый] dddd, [в] LT";case 3:case 5:case 6:return"[В прошлую] dddd, [в] LT"}},sameElse:"L"},relativeTime:{future:"через %s",past:"%s назад",s:"несколько секунд",ss:n,m:n,mm:n,h:"час",hh:n,d:"день",dd:n,w:"неделя",ww:n,M:"месяц",MM:n,y:"год",yy:n},meridiemParse:/ночи|утра|дня|вечера/i,isPM:function(e){return/^(дня|вечера)$/.test(e)},meridiem:function(e,t,n){return e<4?"ночи":e<12?"утра":e<17?"дня":"вечера"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го|я)/,ordinal:function(e,t){switch(t){case"M":case"d":case"DDD":return e+"-й";case"D":return e+"-го";case"w":case"W":return e+"-я";default:return e}},week:{dow:1,doy:4}})})(n(30381))},40950:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=["جنوري","فيبروري","مارچ","اپريل","مئي","جون","جولاءِ","آگسٽ","سيپٽمبر","آڪٽوبر","نومبر","ڊسمبر",],n=["آچر","سومر","اڱارو","اربع","خميس","جمع","ڇنڇر"];return e.defineLocale("sd",{months:t,monthsShort:t,weekdays:n,weekdaysShort:n,weekdaysMin:n,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,t,n){return e<12?"صبح":"شام"},calendar:{sameDay:"[اڄ] LT",nextDay:"[سڀاڻي] LT",nextWeek:"dddd [اڳين هفتي تي] LT",lastDay:"[ڪالهه] LT",lastWeek:"[گزريل هفتي] dddd [تي] LT",sameElse:"L"},relativeTime:{future:"%s پوء",past:"%s اڳ",s:"چند سيڪنڊ",ss:"%d سيڪنڊ",m:"هڪ منٽ",mm:"%d منٽ",h:"هڪ ڪلاڪ",hh:"%d ڪلاڪ",d:"هڪ ڏينهن",dd:"%d ڏينهن",M:"هڪ مهينو",MM:"%d مهينا",y:"هڪ سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})})(n(30381))},10490:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("se",{months:"ođđajagem\xe1nnu_guovvam\xe1nnu_njukčam\xe1nnu_cuoŋom\xe1nnu_miessem\xe1nnu_geassem\xe1nnu_suoidnem\xe1nnu_borgem\xe1nnu_čakčam\xe1nnu_golggotm\xe1nnu_sk\xe1bmam\xe1nnu_juovlam\xe1nnu".split("_"),monthsShort:"ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_sk\xe1b_juov".split("_"),weekdays:"sotnabeaivi_vuoss\xe1rga_maŋŋeb\xe1rga_gaskavahkku_duorastat_bearjadat_l\xe1vvardat".split("_"),weekdaysShort:"sotn_vuos_maŋ_gask_duor_bear_l\xe1v".split("_"),weekdaysMin:"s_v_m_g_d_b_L".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"MMMM D. [b.] YYYY",LLL:"MMMM D. [b.] YYYY [ti.] HH:mm",LLLL:"dddd, MMMM D. [b.] YYYY [ti.] HH:mm"},calendar:{sameDay:"[otne ti] LT",nextDay:"[ihttin ti] LT",nextWeek:"dddd [ti] LT",lastDay:"[ikte ti] LT",lastWeek:"[ovddit] dddd [ti] LT",sameElse:"L"},relativeTime:{future:"%s geažes",past:"maŋit %s",s:"moadde sekunddat",ss:"%d sekunddat",m:"okta minuhta",mm:"%d minuhtat",h:"okta diimmu",hh:"%d diimmut",d:"okta beaivi",dd:"%d beaivvit",M:"okta m\xe1nnu",MM:"%d m\xe1nut",y:"okta jahki",yy:"%d jagit"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},90124:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("si",{months:"ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්".split("_"),monthsShort:"ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ".split("_"),weekdays:"ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා".split("_"),weekdaysShort:"ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන".split("_"),weekdaysMin:"ඉ_ස_අ_බ_බ්‍ර_සි_සෙ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"a h:mm",LTS:"a h:mm:ss",L:"YYYY/MM/DD",LL:"YYYY MMMM D",LLL:"YYYY MMMM D, a h:mm",LLLL:"YYYY MMMM D [වැනි] dddd, a h:mm:ss"},calendar:{sameDay:"[අද] LT[ට]",nextDay:"[හෙට] LT[ට]",nextWeek:"dddd LT[ට]",lastDay:"[ඊයේ] LT[ට]",lastWeek:"[පසුගිය] dddd LT[ට]",sameElse:"L"},relativeTime:{future:"%sකින්",past:"%sකට පෙර",s:"තත්පර කිහිපය",ss:"තත්පර %d",m:"මිනිත්තුව",mm:"මිනිත්තු %d",h:"පැය",hh:"පැය %d",d:"දිනය",dd:"දින %d",M:"මාසය",MM:"මාස %d",y:"වසර",yy:"වසර %d"},dayOfMonthOrdinalParse:/\d{1,2} වැනි/,ordinal:function(e){return e+" වැනි"},meridiemParse:/පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,isPM:function(e){return"ප.ව."===e||"පස් වරු"===e},meridiem:function(e,t,n){return e>11?n?"ප.ව.":"පස් වරු":n?"පෙ.ව.":"පෙර වරු"}})})(n(30381))},64249:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="janu\xe1r_febru\xe1r_marec_apr\xedl_m\xe1j_j\xfan_j\xfal_august_september_okt\xf3ber_november_december".split("_"),n="jan_feb_mar_apr_m\xe1j_j\xfan_j\xfal_aug_sep_okt_nov_dec".split("_");function r(e){return e>1&&e<5}function i(e,t,n,i){var a=e+" ";switch(n){case"s":return t||i?"p\xe1r sek\xfand":"p\xe1r sekundami";case"ss":if(t||i)return a+(r(e)?"sekundy":"sek\xfand");return a+"sekundami";case"m":return t?"min\xfata":i?"min\xfatu":"min\xfatou";case"mm":if(t||i)return a+(r(e)?"min\xfaty":"min\xfat");return a+"min\xfatami";case"h":return t?"hodina":i?"hodinu":"hodinou";case"hh":if(t||i)return a+(r(e)?"hodiny":"hod\xedn");return a+"hodinami";case"d":return t||i?"deň":"dňom";case"dd":if(t||i)return a+(r(e)?"dni":"dn\xed");return a+"dňami";case"M":return t||i?"mesiac":"mesiacom";case"MM":if(t||i)return a+(r(e)?"mesiace":"mesiacov");return a+"mesiacmi";case"y":return t||i?"rok":"rokom";case"yy":if(t||i)return a+(r(e)?"roky":"rokov");return a+"rokmi"}}return e.defineLocale("sk",{months:t,monthsShort:n,weekdays:"nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_št_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_št_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nedeľu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo štvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[včera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minul\xfa nedeľu o] LT";case 1:case 2:case 4:case 5:return"[minul\xfd] dddd [o] LT";case 3:return"[minul\xfa stredu o] LT";case 6:return"[minul\xfa sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:i,ss:i,m:i,mm:i,h:i,hh:i,d:i,dd:i,M:i,MM:i,y:i,yy:i},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},14985:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t,n,r){var i=e+" ";switch(n){case"s":return t||r?"nekaj sekund":"nekaj sekundami";case"ss":return 1===e?i+=t?"sekundo":"sekundi":2===e?i+=t||r?"sekundi":"sekundah":e<5?i+=t||r?"sekunde":"sekundah":i+="sekund",i;case"m":return t?"ena minuta":"eno minuto";case"mm":return 1===e?i+=t?"minuta":"minuto":2===e?i+=t||r?"minuti":"minutama":e<5?i+=t||r?"minute":"minutami":i+=t||r?"minut":"minutami",i;case"h":return t?"ena ura":"eno uro";case"hh":return 1===e?i+=t?"ura":"uro":2===e?i+=t||r?"uri":"urama":e<5?i+=t||r?"ure":"urami":i+=t||r?"ur":"urami",i;case"d":return t||r?"en dan":"enim dnem";case"dd":return 1===e?i+=t||r?"dan":"dnem":2===e?i+=t||r?"dni":"dnevoma":i+=t||r?"dni":"dnevi",i;case"M":return t||r?"en mesec":"enim mesecem";case"MM":return 1===e?i+=t||r?"mesec":"mesecem":2===e?i+=t||r?"meseca":"mesecema":e<5?i+=t||r?"mesece":"meseci":i+=t||r?"mesecev":"meseci",i;case"y":return t||r?"eno leto":"enim letom";case"yy":return 1===e?i+=t||r?"leto":"letom":2===e?i+=t||r?"leti":"letoma":e<5?i+=t||r?"leta":"leti":i+=t||r?"let":"leti",i}}return e.defineLocale("sl",{months:"januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"),weekdaysShort:"ned._pon._tor._sre._čet._pet._sob.".split("_"),weekdaysMin:"ne_po_to_sr_če_pe_so".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD. MM. YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danes ob] LT",nextDay:"[jutri ob] LT",nextWeek:function(){switch(this.day()){case 0:return"[v] [nedeljo] [ob] LT";case 3:return"[v] [sredo] [ob] LT";case 6:return"[v] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[v] dddd [ob] LT"}},lastDay:"[včeraj ob] LT",lastWeek:function(){switch(this.day()){case 0:return"[prejšnjo] [nedeljo] [ob] LT";case 3:return"[prejšnjo] [sredo] [ob] LT";case 6:return"[prejšnjo] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[prejšnji] dddd [ob] LT"}},sameElse:"L"},relativeTime:{future:"čez %s",past:"pred %s",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})})(n(30381))},51104:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("sq",{months:"Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_N\xebntor_Dhjetor".split("_"),monthsShort:"Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_N\xebn_Dhj".split("_"),weekdays:"E Diel_E H\xebn\xeb_E Mart\xeb_E M\xebrkur\xeb_E Enjte_E Premte_E Shtun\xeb".split("_"),weekdaysShort:"Die_H\xebn_Mar_M\xebr_Enj_Pre_Sht".split("_"),weekdaysMin:"D_H_Ma_M\xeb_E_P_Sh".split("_"),weekdaysParseExact:!0,meridiemParse:/PD|MD/,isPM:function(e){return"M"===e.charAt(0)},meridiem:function(e,t,n){return e<12?"PD":"MD"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Sot n\xeb] LT",nextDay:"[Nes\xebr n\xeb] LT",nextWeek:"dddd [n\xeb] LT",lastDay:"[Dje n\xeb] LT",lastWeek:"dddd [e kaluar n\xeb] LT",sameElse:"L"},relativeTime:{future:"n\xeb %s",past:"%s m\xeb par\xeb",s:"disa sekonda",ss:"%d sekonda",m:"nj\xeb minut\xeb",mm:"%d minuta",h:"nj\xeb or\xeb",hh:"%d or\xeb",d:"nj\xeb dit\xeb",dd:"%d dit\xeb",M:"nj\xeb muaj",MM:"%d muaj",y:"nj\xeb vit",yy:"%d vite"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},79915:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={words:{ss:["секунда","секунде","секунди"],m:["један минут","једне минуте"],mm:["минут","минуте","минута"],h:["један сат","једног сата"],hh:["сат","сата","сати"],dd:["дан","дана","дана"],MM:["месец","месеца","месеци"],yy:["година","године","година"]},correctGrammaticalCase:function(e,t){return 1===e?t[0]:e>=2&&e<=4?t[1]:t[2]},translate:function(e,n,r){var i=t.words[r];return 1===r.length?n?i[0]:i[1]:e+" "+t.correctGrammaticalCase(e,i)}};return e.defineLocale("sr-cyrl",{months:"јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар".split("_"),monthsShort:"јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.".split("_"),monthsParseExact:!0,weekdays:"недеља_понедељак_уторак_среда_четвртак_петак_субота".split("_"),weekdaysShort:"нед._пон._уто._сре._чет._пет._суб.".split("_"),weekdaysMin:"не_по_ут_ср_че_пе_су".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[данас у] LT",nextDay:"[сутра у] LT",nextWeek:function(){switch(this.day()){case 0:return"[у] [недељу] [у] LT";case 3:return"[у] [среду] [у] LT";case 6:return"[у] [суботу] [у] LT";case 1:case 2:case 4:case 5:return"[у] dddd [у] LT"}},lastDay:"[јуче у] LT",lastWeek:function(){return["[прошле] [недеље] [у] LT","[прошлог] [понедељка] [у] LT","[прошлог] [уторка] [у] LT","[прошле] [среде] [у] LT","[прошлог] [четвртка] [у] LT","[прошлог] [петка] [у] LT","[прошле] [суботе] [у] LT",][this.day()]},sameElse:"L"},relativeTime:{future:"за %s",past:"пре %s",s:"неколико секунди",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:"дан",dd:t.translate,M:"месец",MM:t.translate,y:"годину",yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})})(n(30381))},49131:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={words:{ss:["sekunda","sekunde","sekundi"],m:["jedan minut","jedne minute"],mm:["minut","minute","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mesec","meseca","meseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(e,t){return 1===e?t[0]:e>=2&&e<=4?t[1]:t[2]},translate:function(e,n,r){var i=t.words[r];return 1===r.length?n?i[0]:i[1]:e+" "+t.correctGrammaticalCase(e,i)}};return e.defineLocale("sr",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sre._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedelju] [u] LT";case 3:return"[u] [sredu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedelje] [u] LT","[prošlog] [ponedeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT",][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"pre %s",s:"nekoliko sekundi",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:"dan",dd:t.translate,M:"mesec",MM:t.translate,y:"godinu",yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})})(n(30381))},85893:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ss",{months:"Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split("_"),monthsShort:"Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo".split("_"),weekdays:"Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo".split("_"),weekdaysShort:"Lis_Umb_Lsb_Les_Lsi_Lsh_Umg".split("_"),weekdaysMin:"Li_Us_Lb_Lt_Ls_Lh_Ug".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Namuhla nga] LT",nextDay:"[Kusasa nga] LT",nextWeek:"dddd [nga] LT",lastDay:"[Itolo nga] LT",lastWeek:"dddd [leliphelile] [nga] LT",sameElse:"L"},relativeTime:{future:"nga %s",past:"wenteka nga %s",s:"emizuzwana lomcane",ss:"%d mzuzwana",m:"umzuzu",mm:"%d emizuzu",h:"lihora",hh:"%d emahora",d:"lilanga",dd:"%d emalanga",M:"inyanga",MM:"%d tinyanga",y:"umnyaka",yy:"%d iminyaka"},meridiemParse:/ekuseni|emini|entsambama|ebusuku/,meridiem:function(e,t,n){return e<11?"ekuseni":e<15?"emini":e<19?"entsambama":"ebusuku"},meridiemHour:function(e,t){return(12===e&&(e=0),"ekuseni"===t)?e:"emini"===t?e>=11?e:e+12:"entsambama"===t||"ebusuku"===t?0===e?0:e+12:void 0},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:"%d",week:{dow:1,doy:4}})})(n(30381))},98760:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"s\xf6ndag_m\xe5ndag_tisdag_onsdag_torsdag_fredag_l\xf6rdag".split("_"),weekdaysShort:"s\xf6n_m\xe5n_tis_ons_tor_fre_l\xf6r".split("_"),weekdaysMin:"s\xf6_m\xe5_ti_on_to_fr_l\xf6".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Ig\xe5r] LT",nextWeek:"[P\xe5] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"f\xf6r %s sedan",s:"n\xe5gra sekunder",ss:"%d sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en m\xe5nad",MM:"%d m\xe5nader",y:"ett \xe5r",yy:"%d \xe5r"},dayOfMonthOrdinalParse:/\d{1,2}(\:e|\:a)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?":e":1===t?":a":2===t?":a":":e";return e+n},week:{dow:1,doy:4}})})(n(30381))},91172:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("sw",{months:"Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"),weekdays:"Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"),weekdaysShort:"Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"),weekdaysMin:"J2_J3_J4_J5_Al_Ij_J1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"hh:mm A",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[leo saa] LT",nextDay:"[kesho saa] LT",nextWeek:"[wiki ijayo] dddd [saat] LT",lastDay:"[jana] LT",lastWeek:"[wiki iliyopita] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s baadaye",past:"tokea %s",s:"hivi punde",ss:"sekunde %d",m:"dakika moja",mm:"dakika %d",h:"saa limoja",hh:"masaa %d",d:"siku moja",dd:"siku %d",M:"mwezi mmoja",MM:"miezi %d",y:"mwaka mmoja",yy:"miaka %d"},week:{dow:1,doy:7}})})(n(30381))},27333:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"௧",2:"௨",3:"௩",4:"௪",5:"௫",6:"௬",7:"௭",8:"௮",9:"௯",0:"௦"},n={"௧":"1","௨":"2","௩":"3","௪":"4","௫":"5","௬":"6","௭":"7","௮":"8","௯":"9","௦":"0"};return e.defineLocale("ta",{months:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),monthsShort:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),weekdays:"ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை".split("_"),weekdaysShort:"ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி".split("_"),weekdaysMin:"ஞா_தி_செ_பு_வி_வெ_ச".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, HH:mm",LLLL:"dddd, D MMMM YYYY, HH:mm"},calendar:{sameDay:"[இன்று] LT",nextDay:"[நாளை] LT",nextWeek:"dddd, LT",lastDay:"[நேற்று] LT",lastWeek:"[கடந்த வாரம்] dddd, LT",sameElse:"L"},relativeTime:{future:"%s இல்",past:"%s முன்",s:"ஒரு சில விநாடிகள்",ss:"%d விநாடிகள்",m:"ஒரு நிமிடம்",mm:"%d நிமிடங்கள்",h:"ஒரு மணி நேரம்",hh:"%d மணி நேரம்",d:"ஒரு நாள்",dd:"%d நாட்கள்",M:"ஒரு மாதம்",MM:"%d மாதங்கள்",y:"ஒரு வருடம்",yy:"%d ஆண்டுகள்"},dayOfMonthOrdinalParse:/\d{1,2}வது/,ordinal:function(e){return e+"வது"},preparse:function(e){return e.replace(/[௧௨௩௪௫௬௭௮௯௦]/g,function(e){return n[e]})},postformat:function(e){return e.replace(/\d/g,function(e){return t[e]})},meridiemParse:/யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,meridiem:function(e,t,n){if(e<2)return" யாமம்";if(e<6)return" வைகறை";if(e<10)return" காலை";if(e<14)return" நண்பகல்";if(e<18)return" எற்பாடு";else if(e<22)return" மாலை";else return" யாமம்"},meridiemHour:function(e,t){return(12===e&&(e=0),"யாமம்"===t)?e<2?e:e+12:"வைகறை"===t||"காலை"===t?e:"நண்பகல்"===t?e>=10?e:e+12:e+12},week:{dow:0,doy:6}})})(n(30381))},23110:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("te",{months:"జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జులై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్".split("_"),monthsShort:"జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జులై_ఆగ._సెప్._అక్టో._నవ._డిసె.".split("_"),monthsParseExact:!0,weekdays:"ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం".split("_"),weekdaysShort:"ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని".split("_"),weekdaysMin:"ఆ_సో_మం_బు_గు_శు_శ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[నేడు] LT",nextDay:"[రేపు] LT",nextWeek:"dddd, LT",lastDay:"[నిన్న] LT",lastWeek:"[గత] dddd, LT",sameElse:"L"},relativeTime:{future:"%s లో",past:"%s క్రితం",s:"కొన్ని క్షణాలు",ss:"%d సెకన్లు",m:"ఒక నిమిషం",mm:"%d నిమిషాలు",h:"ఒక గంట",hh:"%d గంటలు",d:"ఒక రోజు",dd:"%d రోజులు",M:"ఒక నెల",MM:"%d నెలలు",y:"ఒక సంవత్సరం",yy:"%d సంవత్సరాలు"},dayOfMonthOrdinalParse:/\d{1,2}వ/,ordinal:"%dవ",meridiemParse:/రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,meridiemHour:function(e,t){return(12===e&&(e=0),"రాత్రి"===t)?e<4?e:e+12:"ఉదయం"===t?e:"మధ్యాహ్నం"===t?e>=10?e:e+12:"సాయంత్రం"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"రాత్రి":e<10?"ఉదయం":e<17?"మధ్యాహ్నం":e<20?"సాయంత్రం":"రాత్రి"},week:{dow:0,doy:6}})})(n(30381))},52095:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("tet",{months:"Janeiru_Fevereiru_Marsu_Abril_Maiu_Ju\xf1u_Jullu_Agustu_Setembru_Outubru_Novembru_Dezembru".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingu_Segunda_Tersa_Kuarta_Kinta_Sesta_Sabadu".split("_"),weekdaysShort:"Dom_Seg_Ters_Kua_Kint_Sest_Sab".split("_"),weekdaysMin:"Do_Seg_Te_Ku_Ki_Ses_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Ohin iha] LT",nextDay:"[Aban iha] LT",nextWeek:"dddd [iha] LT",lastDay:"[Horiseik iha] LT",lastWeek:"dddd [semana kotuk] [iha] LT",sameElse:"L"},relativeTime:{future:"iha %s",past:"%s liuba",s:"segundu balun",ss:"segundu %d",m:"minutu ida",mm:"minutu %d",h:"oras ida",hh:"oras %d",d:"loron ida",dd:"loron %d",M:"fulan ida",MM:"fulan %d",y:"tinan ida",yy:"tinan %d"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:1,doy:4}})})(n(30381))},27321:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={0:"-ум",1:"-ум",2:"-юм",3:"-юм",4:"-ум",5:"-ум",6:"-ум",7:"-ум",8:"-ум",9:"-ум",10:"-ум",12:"-ум",13:"-ум",20:"-ум",30:"-юм",40:"-ум",50:"-ум",60:"-ум",70:"-ум",80:"-ум",90:"-ум",100:"-ум"};return e.defineLocale("tg",{months:{format:"январи_феврали_марти_апрели_майи_июни_июли_августи_сентябри_октябри_ноябри_декабри".split("_"),standalone:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_")},monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"якшанбе_душанбе_сешанбе_чоршанбе_панҷшанбе_ҷумъа_шанбе".split("_"),weekdaysShort:"яшб_дшб_сшб_чшб_пшб_ҷум_шнб".split("_"),weekdaysMin:"яш_дш_сш_чш_пш_ҷм_шб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Имрӯз соати] LT",nextDay:"[Фардо соати] LT",lastDay:"[Дирӯз соати] LT",nextWeek:"dddd[и] [ҳафтаи оянда соати] LT",lastWeek:"dddd[и] [ҳафтаи гузашта соати] LT",sameElse:"L"},relativeTime:{future:"баъди %s",past:"%s пеш",s:"якчанд сония",m:"як дақиқа",mm:"%d дақиқа",h:"як соат",hh:"%d соат",d:"як рӯз",dd:"%d рӯз",M:"як моҳ",MM:"%d моҳ",y:"як сол",yy:"%d сол"},meridiemParse:/шаб|субҳ|рӯз|бегоҳ/,meridiemHour:function(e,t){return(12===e&&(e=0),"шаб"===t)?e<4?e:e+12:"субҳ"===t?e:"рӯз"===t?e>=11?e:e+12:"бегоҳ"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"шаб":e<11?"субҳ":e<16?"рӯз":e<19?"бегоҳ":"шаб"},dayOfMonthOrdinalParse:/\d{1,2}-(ум|юм)/,ordinal:function(e){var n=e%10,r=e>=100?100:null;return e+(t[e]||t[n]||t[r])},week:{dow:1,doy:7}})})(n(30381))},9041:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("th",{months:"มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"),monthsShort:"ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.".split("_"),monthsParseExact:!0,weekdays:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"),weekdaysShort:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"),weekdaysMin:"อา._จ._อ._พ._พฤ._ศ._ส.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY เวลา H:mm",LLLL:"วันddddที่ D MMMM YYYY เวลา H:mm"},meridiemParse:/ก่อนเที่ยง|หลังเที่ยง/,isPM:function(e){return"หลังเที่ยง"===e},meridiem:function(e,t,n){return e<12?"ก่อนเที่ยง":"หลังเที่ยง"},calendar:{sameDay:"[วันนี้ เวลา] LT",nextDay:"[พรุ่งนี้ เวลา] LT",nextWeek:"dddd[หน้า เวลา] LT",lastDay:"[เมื่อวานนี้ เวลา] LT",lastWeek:"[วัน]dddd[ที่แล้ว เวลา] LT",sameElse:"L"},relativeTime:{future:"อีก %s",past:"%sที่แล้ว",s:"ไม่กี่วินาที",ss:"%d วินาที",m:"1 นาที",mm:"%d นาที",h:"1 ชั่วโมง",hh:"%d ชั่วโมง",d:"1 วัน",dd:"%d วัน",w:"1 สัปดาห์",ww:"%d สัปดาห์",M:"1 เดือน",MM:"%d เดือน",y:"1 ปี",yy:"%d ปี"}})})(n(30381))},19005:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"'inji",5:"'inji",8:"'inji",70:"'inji",80:"'inji",2:"'nji",7:"'nji",20:"'nji",50:"'nji",3:"'\xfcnji",4:"'\xfcnji",100:"'\xfcnji",6:"'njy",9:"'unjy",10:"'unjy",30:"'unjy",60:"'ynjy",90:"'ynjy"};return e.defineLocale("tk",{months:"\xddanwar_Fewral_Mart_Aprel_Ma\xfd_I\xfdun_I\xfdul_Awgust_Sent\xfdabr_Okt\xfdabr_No\xfdabr_Dekabr".split("_"),monthsShort:"\xddan_Few_Mar_Apr_Ma\xfd_I\xfdn_I\xfdl_Awg_Sen_Okt_No\xfd_Dek".split("_"),weekdays:"\xddekşenbe_Duşenbe_Sişenbe_\xc7arşenbe_Penşenbe_Anna_Şenbe".split("_"),weekdaysShort:"\xddek_Duş_Siş_\xc7ar_Pen_Ann_Şen".split("_"),weekdaysMin:"\xddk_Dş_Sş_\xc7r_Pn_An_Şn".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bug\xfcn sagat] LT",nextDay:"[ertir sagat] LT",nextWeek:"[indiki] dddd [sagat] LT",lastDay:"[d\xfc\xfdn] LT",lastWeek:"[ge\xe7en] dddd [sagat] LT",sameElse:"L"},relativeTime:{future:"%s soň",past:"%s \xf6ň",s:"birn\xe4\xe7e sekunt",m:"bir minut",mm:"%d minut",h:"bir sagat",hh:"%d sagat",d:"bir g\xfcn",dd:"%d g\xfcn",M:"bir a\xfd",MM:"%d a\xfd",y:"bir \xfdyl",yy:"%d \xfdyl"},ordinal:function(e,n){switch(n){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'unjy";var r=e%10,i=e%100-r,a=e>=100?100:null;return e+(t[r]||t[i]||t[a])}},week:{dow:1,doy:7}})})(n(30381))},75768:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("tl-ph",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})})(n(30381))},89444:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t="pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut".split("_");function n(e){var t=e;return -1!==e.indexOf("jaj")?t.slice(0,-3)+"leS":-1!==e.indexOf("jar")?t.slice(0,-3)+"waQ":-1!==e.indexOf("DIS")?t.slice(0,-3)+"nem":t+" pIq"}function r(e){var t=e;return -1!==e.indexOf("jaj")?t.slice(0,-3)+"Hu’":-1!==e.indexOf("jar")?t.slice(0,-3)+"wen":-1!==e.indexOf("DIS")?t.slice(0,-3)+"ben":t+" ret"}function i(e,t,n,r){var i=a(e);switch(n){case"ss":return i+" lup";case"mm":return i+" tup";case"hh":return i+" rep";case"dd":return i+" jaj";case"MM":return i+" jar";case"yy":return i+" DIS"}}function a(e){var n=Math.floor(e%1e3/100),r=Math.floor(e%100/10),i=e%10,a="";return n>0&&(a+=t[n]+"vatlh"),r>0&&(a+=(""!==a?" ":"")+t[r]+"maH"),i>0&&(a+=(""!==a?" ":"")+t[i]),""===a?"pagh":a}return e.defineLocale("tlh",{months:"tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’".split("_"),monthsShort:"jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’".split("_"),monthsParseExact:!0,weekdays:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysShort:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysMin:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[DaHjaj] LT",nextDay:"[wa’leS] LT",nextWeek:"LLL",lastDay:"[wa’Hu’] LT",lastWeek:"LLL",sameElse:"L"},relativeTime:{future:n,past:r,s:"puS lup",ss:i,m:"wa’ tup",mm:i,h:"wa’ rep",hh:i,d:"wa’ jaj",dd:i,M:"wa’ jar",MM:i,y:"wa’ DIS",yy:i},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})})(n(30381))},72397:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'\xfcnc\xfc",4:"'\xfcnc\xfc",100:"'\xfcnc\xfc",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"};return e.defineLocale("tr",{months:"Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eyl\xfcl_Ekim_Kasım_Aralık".split("_"),monthsShort:"Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"),weekdays:"Pazar_Pazartesi_Salı_\xc7arşamba_Perşembe_Cuma_Cumartesi".split("_"),weekdaysShort:"Paz_Pts_Sal_\xc7ar_Per_Cum_Cts".split("_"),weekdaysMin:"Pz_Pt_Sa_\xc7a_Pe_Cu_Ct".split("_"),meridiem:function(e,t,n){return e<12?n?"\xf6\xf6":"\xd6\xd6":n?"\xf6s":"\xd6S"},meridiemParse:/öö|ÖÖ|ös|ÖS/,isPM:function(e){return"\xf6s"===e||"\xd6S"===e},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bug\xfcn saat] LT",nextDay:"[yarın saat] LT",nextWeek:"[gelecek] dddd [saat] LT",lastDay:"[d\xfcn] LT",lastWeek:"[ge\xe7en] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s \xf6nce",s:"birka\xe7 saniye",ss:"%d saniye",m:"bir dakika",mm:"%d dakika",h:"bir saat",hh:"%d saat",d:"bir g\xfcn",dd:"%d g\xfcn",w:"bir hafta",ww:"%d hafta",M:"bir ay",MM:"%d ay",y:"bir yıl",yy:"%d yıl"},ordinal:function(e,n){switch(n){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'ıncı";var r=e%10,i=e%100-r,a=e>=100?100:null;return e+(t[r]||t[i]||t[a])}},week:{dow:1,doy:7}})})(n(30381))},28254:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=e.defineLocale("tzl",{months:"Januar_Fevraglh_Mar\xe7_Avr\xefu_Mai_G\xfcn_Julia_Guscht_Setemvar_Listop\xe4ts_Noemvar_Zecemvar".split("_"),monthsShort:"Jan_Fev_Mar_Avr_Mai_G\xfcn_Jul_Gus_Set_Lis_Noe_Zec".split("_"),weekdays:"S\xfaladi_L\xfane\xe7i_Maitzi_M\xe1rcuri_Xh\xfaadi_Vi\xe9ner\xe7i_S\xe1turi".split("_"),weekdaysShort:"S\xfal_L\xfan_Mai_M\xe1r_Xh\xfa_Vi\xe9_S\xe1t".split("_"),weekdaysMin:"S\xfa_L\xfa_Ma_M\xe1_Xh_Vi_S\xe1".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"D. MMMM [dallas] YYYY",LLL:"D. MMMM [dallas] YYYY HH.mm",LLLL:"dddd, [li] D. MMMM [dallas] YYYY HH.mm"},meridiemParse:/d\'o|d\'a/i,isPM:function(e){return"d'o"===e.toLowerCase()},meridiem:function(e,t,n){return e>11?n?"d'o":"D'O":n?"d'a":"D'A"},calendar:{sameDay:"[oxhi \xe0] LT",nextDay:"[dem\xe0 \xe0] LT",nextWeek:"dddd [\xe0] LT",lastDay:"[ieiri \xe0] LT",lastWeek:"[s\xfcr el] dddd [lasteu \xe0] LT",sameElse:"L"},relativeTime:{future:"osprei %s",past:"ja%s",s:n,ss:n,m:n,mm:n,h:n,hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});function n(e,t,n,r){var i={s:["viensas secunds","'iensas secunds"],ss:[e+" secunds",""+e+" secunds"],m:["'n m\xedut","'iens m\xedut"],mm:[e+" m\xeduts",""+e+" m\xeduts"],h:["'n \xfeora","'iensa \xfeora"],hh:[e+" \xfeoras",""+e+" \xfeoras"],d:["'n ziua","'iensa ziua"],dd:[e+" ziuas",""+e+" ziuas"],M:["'n mes","'iens mes"],MM:[e+" mesen",""+e+" mesen"],y:["'n ar","'iens ar"],yy:[e+" ars",""+e+" ars"]};return r?i[n][0]:t?i[n][0]:i[n][1]}return t})(n(30381))},30699:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("tzm-latn",{months:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),monthsShort:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),weekdays:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysShort:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysMin:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[asdkh g] LT",nextDay:"[aska g] LT",nextWeek:"dddd [g] LT",lastDay:"[assant g] LT",lastWeek:"dddd [g] LT",sameElse:"L"},relativeTime:{future:"dadkh s yan %s",past:"yan %s",s:"imik",ss:"%d imik",m:"minuḍ",mm:"%d minuḍ",h:"saɛa",hh:"%d tassaɛin",d:"ass",dd:"%d ossan",M:"ayowr",MM:"%d iyyirn",y:"asgas",yy:"%d isgasn"},week:{dow:6,doy:12}})})(n(30381))},51106:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("tzm",{months:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),monthsShort:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),weekdays:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysShort:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysMin:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ⴰⵙⴷⵅ ⴴ] LT",nextDay:"[ⴰⵙⴽⴰ ⴴ] LT",nextWeek:"dddd [ⴴ] LT",lastDay:"[ⴰⵚⴰⵏⵜ ⴴ] LT",lastWeek:"dddd [ⴴ] LT",sameElse:"L"},relativeTime:{future:"ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s",past:"ⵢⴰⵏ %s",s:"ⵉⵎⵉⴽ",ss:"%d ⵉⵎⵉⴽ",m:"ⵎⵉⵏⵓⴺ",mm:"%d ⵎⵉⵏⵓⴺ",h:"ⵙⴰⵄⴰ",hh:"%d ⵜⴰⵙⵙⴰⵄⵉⵏ",d:"ⴰⵙⵙ",dd:"%d oⵙⵙⴰⵏ",M:"ⴰⵢoⵓⵔ",MM:"%d ⵉⵢⵢⵉⵔⵏ",y:"ⴰⵙⴳⴰⵙ",yy:"%d ⵉⵙⴳⴰⵙⵏ"},week:{dow:6,doy:12}})})(n(30381))},9288:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("ug-cn",{months:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),monthsShort:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),weekdays:"يەكشەنبە_دۈشەنبە_سەيشەنبە_چارشەنبە_پەيشەنبە_جۈمە_شەنبە".split("_"),weekdaysShort:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),weekdaysMin:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY-يىلىM-ئاينىڭD-كۈنى",LLL:"YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm",LLLL:"dddd، YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm"},meridiemParse:/يېرىم كېچە|سەھەر|چۈشتىن بۇرۇن|چۈش|چۈشتىن كېيىن|كەچ/,meridiemHour:function(e,t){return(12===e&&(e=0),"يېرىم كېچە"===t||"سەھەر"===t||"چۈشتىن بۇرۇن"===t)?e:"چۈشتىن كېيىن"===t||"كەچ"===t?e+12:e>=11?e:e+12},meridiem:function(e,t,n){var r=100*e+t;if(r<600)return"يېرىم كېچە";if(r<900)return"سەھەر";if(r<1130)return"چۈشتىن بۇرۇن";if(r<1230)return"چۈش";if(r<1800)return"چۈشتىن كېيىن";else return"كەچ"},calendar:{sameDay:"[بۈگۈن سائەت] LT",nextDay:"[ئەتە سائەت] LT",nextWeek:"[كېلەركى] dddd [سائەت] LT",lastDay:"[تۆنۈگۈن] LT",lastWeek:"[ئالدىنقى] dddd [سائەت] LT",sameElse:"L"},relativeTime:{future:"%s كېيىن",past:"%s بۇرۇن",s:"نەچچە سېكونت",ss:"%d سېكونت",m:"بىر مىنۇت",mm:"%d مىنۇت",h:"بىر سائەت",hh:"%d سائەت",d:"بىر كۈن",dd:"%d كۈن",M:"بىر ئاي",MM:"%d ئاي",y:"بىر يىل",yy:"%d يىل"},dayOfMonthOrdinalParse:/\d{1,2}(-كۈنى|-ئاي|-ھەپتە)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"-كۈنى";case"w":case"W":return e+"-ھەپتە";default:return e}},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:7}})})(n(30381))},67691:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +function t(e,t){var n=e.split("_");return t%10==1&&t%100!=11?n[0]:t%10>=2&&t%10<=4&&(t%100<10||t%100>=20)?n[1]:n[2]}function n(e,n,r){var i={ss:n?"секунда_секунди_секунд":"секунду_секунди_секунд",mm:n?"хвилина_хвилини_хвилин":"хвилину_хвилини_хвилин",hh:n?"година_години_годин":"годину_години_годин",dd:"день_дні_днів",MM:"місяць_місяці_місяців",yy:"рік_роки_років"};return"m"===r?n?"хвилина":"хвилину":"h"===r?n?"година":"годину":e+" "+t(i[r],+e)}function r(e,t){var n,r={nominative:"неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"),accusative:"неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"),genitive:"неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_")};return!0===e?r.nominative.slice(1,7).concat(r.nominative.slice(0,1)):e?r[n=/(\[[ВвУу]\]) ?dddd/.test(t)?"accusative":/\[?(?:минулої|наступної)? ?\] ?dddd/.test(t)?"genitive":"nominative"][e.day()]:r.nominative}function i(e){return function(){return e+"о"+(11===this.hours()?"б":"")+"] LT"}}return e.defineLocale("uk",{months:{format:"січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"),standalone:"січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_")},monthsShort:"січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"),weekdays:r,weekdaysShort:"нд_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY р.",LLL:"D MMMM YYYY р., HH:mm",LLLL:"dddd, D MMMM YYYY р., HH:mm"},calendar:{sameDay:i("[Сьогодні "),nextDay:i("[Завтра "),lastDay:i("[Вчора "),nextWeek:i("[У] dddd ["),lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return i("[Минулої] dddd [").call(this);case 1:case 2:case 4:return i("[Минулого] dddd [").call(this)}},sameElse:"L"},relativeTime:{future:"за %s",past:"%s тому",s:"декілька секунд",ss:n,m:n,mm:n,h:"годину",hh:n,d:"день",dd:n,M:"місяць",MM:n,y:"рік",yy:n},meridiemParse:/ночі|ранку|дня|вечора/,isPM:function(e){return/^(дня|вечора)$/.test(e)},meridiem:function(e,t,n){return e<4?"ночі":e<12?"ранку":e<17?"дня":"вечора"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го)/,ordinal:function(e,t){switch(t){case"M":case"d":case"DDD":case"w":case"W":return e+"-й";case"D":return e+"-го";default:return e}},week:{dow:1,doy:7}})})(n(30381))},13795:function(e,t,n){var r,i;r=this,(i=function(e){"use strict";//! moment.js locale configuration +var t=["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",],n=["اتوار","پیر","منگل","بدھ","جمعرات","جمعہ","ہفتہ"];return e.defineLocale("ur",{months:t,monthsShort:t,weekdays:n,weekdaysShort:n,weekdaysMin:n,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,t,n){return e<12?"صبح":"شام"},calendar:{sameDay:"[آج بوقت] LT",nextDay:"[کل بوقت] LT",nextWeek:"dddd [بوقت] LT",lastDay:"[گذشتہ روز بوقت] LT",lastWeek:"[گذشتہ] dddd [بوقت] LT",sameElse:"L"},relativeTime:{future:"%s بعد",past:"%s قبل",s:"چند سیکنڈ",ss:"%d سیکنڈ",m:"ایک منٹ",mm:"%d منٹ",h:"ایک گھنٹہ",hh:"%d گھنٹے",d:"ایک دن",dd:"%d دن",M:"ایک ماہ",MM:"%d ماہ",y:"ایک سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})})(n(30381))},60588:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("uz-latn",{months:"Yanvar_Fevral_Mart_Aprel_May_Iyun_Iyul_Avgust_Sentabr_Oktabr_Noyabr_Dekabr".split("_"),monthsShort:"Yan_Fev_Mar_Apr_May_Iyun_Iyul_Avg_Sen_Okt_Noy_Dek".split("_"),weekdays:"Yakshanba_Dushanba_Seshanba_Chorshanba_Payshanba_Juma_Shanba".split("_"),weekdaysShort:"Yak_Dush_Sesh_Chor_Pay_Jum_Shan".split("_"),weekdaysMin:"Ya_Du_Se_Cho_Pa_Ju_Sha".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Bugun soat] LT [da]",nextDay:"[Ertaga] LT [da]",nextWeek:"dddd [kuni soat] LT [da]",lastDay:"[Kecha soat] LT [da]",lastWeek:"[O'tgan] dddd [kuni soat] LT [da]",sameElse:"L"},relativeTime:{future:"Yaqin %s ichida",past:"Bir necha %s oldin",s:"soniya",ss:"%d soniya",m:"bir daqiqa",mm:"%d daqiqa",h:"bir soat",hh:"%d soat",d:"bir kun",dd:"%d kun",M:"bir oy",MM:"%d oy",y:"bir yil",yy:"%d yil"},week:{dow:1,doy:7}})})(n(30381))},6791:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("uz",{months:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_"),monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба".split("_"),weekdaysShort:"Якш_Душ_Сеш_Чор_Пай_Жум_Шан".split("_"),weekdaysMin:"Як_Ду_Се_Чо_Па_Жу_Ша".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Бугун соат] LT [да]",nextDay:"[Эртага] LT [да]",nextWeek:"dddd [куни соат] LT [да]",lastDay:"[Кеча соат] LT [да]",lastWeek:"[Утган] dddd [куни соат] LT [да]",sameElse:"L"},relativeTime:{future:"Якин %s ичида",past:"Бир неча %s олдин",s:"фурсат",ss:"%d фурсат",m:"бир дакика",mm:"%d дакика",h:"бир соат",hh:"%d соат",d:"бир кун",dd:"%d кун",M:"бир ой",MM:"%d ой",y:"бир йил",yy:"%d йил"},week:{dow:1,doy:7}})})(n(30381))},65666:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("vi",{months:"th\xe1ng 1_th\xe1ng 2_th\xe1ng 3_th\xe1ng 4_th\xe1ng 5_th\xe1ng 6_th\xe1ng 7_th\xe1ng 8_th\xe1ng 9_th\xe1ng 10_th\xe1ng 11_th\xe1ng 12".split("_"),monthsShort:"Thg 01_Thg 02_Thg 03_Thg 04_Thg 05_Thg 06_Thg 07_Thg 08_Thg 09_Thg 10_Thg 11_Thg 12".split("_"),monthsParseExact:!0,weekdays:"chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ s\xe1u_thứ bảy".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(e){return/^ch$/i.test(e)},meridiem:function(e,t,n){return e<12?n?"sa":"SA":n?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [năm] YYYY",LLL:"D MMMM [năm] YYYY HH:mm",LLLL:"dddd, D MMMM [năm] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[H\xf4m nay l\xfac] LT",nextDay:"[Ng\xe0y mai l\xfac] LT",nextWeek:"dddd [tuần tới l\xfac] LT",lastDay:"[H\xf4m qua l\xfac] LT",lastWeek:"dddd [tuần trước l\xfac] LT",sameElse:"L"},relativeTime:{future:"%s tới",past:"%s trước",s:"v\xe0i gi\xe2y",ss:"%d gi\xe2y",m:"một ph\xfat",mm:"%d ph\xfat",h:"một giờ",hh:"%d giờ",d:"một ng\xe0y",dd:"%d ng\xe0y",w:"một tuần",ww:"%d tuần",M:"một th\xe1ng",MM:"%d th\xe1ng",y:"một năm",yy:"%d năm"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})})(n(30381))},14378:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("x-pseudo",{months:"J~\xe1\xf1\xfa\xe1~r\xfd_F~\xe9br\xfa~\xe1r\xfd_~M\xe1rc~h_\xc1p~r\xedl_~M\xe1\xfd_~J\xfa\xf1\xe9~_J\xfal~\xfd_\xc1\xfa~g\xfast~_S\xe9p~t\xe9mb~\xe9r_\xd3~ct\xf3b~\xe9r_\xd1~\xf3v\xe9m~b\xe9r_~D\xe9c\xe9~mb\xe9r".split("_"),monthsShort:"J~\xe1\xf1_~F\xe9b_~M\xe1r_~\xc1pr_~M\xe1\xfd_~J\xfa\xf1_~J\xfal_~\xc1\xfag_~S\xe9p_~\xd3ct_~\xd1\xf3v_~D\xe9c".split("_"),monthsParseExact:!0,weekdays:"S~\xfa\xf1d\xe1~\xfd_M\xf3~\xf1d\xe1\xfd~_T\xfa\xe9~sd\xe1\xfd~_W\xe9d~\xf1\xe9sd~\xe1\xfd_T~h\xfars~d\xe1\xfd_~Fr\xedd~\xe1\xfd_S~\xe1t\xfar~d\xe1\xfd".split("_"),weekdaysShort:"S~\xfa\xf1_~M\xf3\xf1_~T\xfa\xe9_~W\xe9d_~Th\xfa_~Fr\xed_~S\xe1t".split("_"),weekdaysMin:"S~\xfa_M\xf3~_T\xfa_~W\xe9_T~h_Fr~_S\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[T~\xf3d\xe1~\xfd \xe1t] LT",nextDay:"[T~\xf3m\xf3~rr\xf3~w \xe1t] LT",nextWeek:"dddd [\xe1t] LT",lastDay:"[\xdd~\xe9st~\xe9rd\xe1~\xfd \xe1t] LT",lastWeek:"[L~\xe1st] dddd [\xe1t] LT",sameElse:"L"},relativeTime:{future:"\xed~\xf1 %s",past:"%s \xe1~g\xf3",s:"\xe1 ~f\xe9w ~s\xe9c\xf3~\xf1ds",ss:"%d s~\xe9c\xf3\xf1~ds",m:"\xe1 ~m\xed\xf1~\xfat\xe9",mm:"%d m~\xed\xf1\xfa~t\xe9s",h:"\xe1~\xf1 h\xf3~\xfar",hh:"%d h~\xf3\xfars",d:"\xe1 ~d\xe1\xfd",dd:"%d d~\xe1\xfds",M:"\xe1 ~m\xf3\xf1~th",MM:"%d m~\xf3\xf1t~hs",y:"\xe1 ~\xfd\xe9\xe1r",yy:"%d \xfd~\xe9\xe1rs"},dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10,n=1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n},week:{dow:1,doy:4}})})(n(30381))},75805:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("yo",{months:"Sẹ́rẹ́_Èrèlè_Ẹrẹ̀nà_Ìgbé_Èbibi_Òkùdu_Agẹmo_Ògún_Owewe_Ọ̀wàrà_Bélú_Ọ̀pẹ̀̀".split("_"),monthsShort:"Sẹ́r_Èrl_Ẹrn_Ìgb_Èbi_Òkù_Agẹ_Ògú_Owe_Ọ̀wà_Bél_Ọ̀pẹ̀̀".split("_"),weekdays:"Àìkú_Ajé_Ìsẹ́gun_Ọjọ́rú_Ọjọ́bọ_Ẹtì_Àbámẹ́ta".split("_"),weekdaysShort:"Àìk_Ajé_Ìsẹ́_Ọjr_Ọjb_Ẹtì_Àbá".split("_"),weekdaysMin:"Àì_Aj_Ìs_Ọr_Ọb_Ẹt_Àb".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Ònì ni] LT",nextDay:"[Ọ̀la ni] LT",nextWeek:"dddd [Ọsẹ̀ tón'bọ] [ni] LT",lastDay:"[Àna ni] LT",lastWeek:"dddd [Ọsẹ̀ tólọ́] [ni] LT",sameElse:"L"},relativeTime:{future:"ní %s",past:"%s kọjá",s:"ìsẹjú aayá die",ss:"aayá %d",m:"ìsẹjú kan",mm:"ìsẹjú %d",h:"wákati kan",hh:"wákati %d",d:"ọjọ́ kan",dd:"ọjọ́ %d",M:"osù kan",MM:"osù %d",y:"ọdún kan",yy:"ọdún %d"},dayOfMonthOrdinalParse:/ọjọ́\s\d{1,2}/,ordinal:"ọjọ́ %d",week:{dow:1,doy:4}})})(n(30381))},83839:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("zh-cn",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return(12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t)?e:"下午"===t||"晚上"===t?e+12:e>=11?e:e+12},meridiem:function(e,t,n){var r=100*e+t;if(r<600)return"凌晨";if(r<900)return"早上";if(r<1130)return"上午";if(r<1230)return"中午";if(r<1800)return"下午";else return"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:function(e){return e.week()!==this.week()?"[下]dddLT":"[本]dddLT"},lastDay:"[昨天]LT",lastWeek:function(e){return this.week()!==e.week()?"[上]dddLT":"[本]dddLT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|周)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"周";default:return e}},relativeTime:{future:"%s后",past:"%s前",s:"几秒",ss:"%d 秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",w:"1 周",ww:"%d 周",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{dow:1,doy:4}})})(n(30381))},55726:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("zh-hk",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return(12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t)?e:"中午"===t?e>=11?e:e+12:"下午"===t||"晚上"===t?e+12:void 0},meridiem:function(e,t,n){var r=100*e+t;if(r<600)return"凌晨";if(r<900)return"早上";if(r<1200)return"上午";if(1200===r)return"中午";if(r<1800)return"下午";else return"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})})(n(30381))},99807:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("zh-mo",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"D/M/YYYY",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return(12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t)?e:"中午"===t?e>=11?e:e+12:"下午"===t||"晚上"===t?e+12:void 0},meridiem:function(e,t,n){var r=100*e+t;if(r<600)return"凌晨";if(r<900)return"早上";if(r<1130)return"上午";if(r<1230)return"中午";if(r<1800)return"下午";else return"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})})(n(30381))},74152:function(e,t,n){var r,i;r=this,(i=function(e){return e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return(12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t)?e:"中午"===t?e>=11?e:e+12:"下午"===t||"晚上"===t?e+12:void 0},meridiem:function(e,t,n){var r=100*e+t;if(r<600)return"凌晨";if(r<900)return"早上";if(r<1130)return"上午";if(r<1230)return"中午";if(r<1800)return"下午";else return"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})})(n(30381))},46700(e,t,n){var r={"./af":42786,"./af.js":42786,"./ar":30867,"./ar-dz":14130,"./ar-dz.js":14130,"./ar-kw":96135,"./ar-kw.js":96135,"./ar-ly":56440,"./ar-ly.js":56440,"./ar-ma":47702,"./ar-ma.js":47702,"./ar-sa":16040,"./ar-sa.js":16040,"./ar-tn":37100,"./ar-tn.js":37100,"./ar.js":30867,"./az":31083,"./az.js":31083,"./be":9808,"./be.js":9808,"./bg":68338,"./bg.js":68338,"./bm":67438,"./bm.js":67438,"./bn":8905,"./bn-bd":76225,"./bn-bd.js":76225,"./bn.js":8905,"./bo":11560,"./bo.js":11560,"./br":1278,"./br.js":1278,"./bs":80622,"./bs.js":80622,"./ca":2468,"./ca.js":2468,"./cs":5822,"./cs.js":5822,"./cv":50877,"./cv.js":50877,"./cy":47373,"./cy.js":47373,"./da":24780,"./da.js":24780,"./de":59740,"./de-at":60217,"./de-at.js":60217,"./de-ch":60894,"./de-ch.js":60894,"./de.js":59740,"./dv":5300,"./dv.js":5300,"./el":50837,"./el.js":50837,"./en-au":78348,"./en-au.js":78348,"./en-ca":77925,"./en-ca.js":77925,"./en-gb":22243,"./en-gb.js":22243,"./en-ie":46436,"./en-ie.js":46436,"./en-il":47207,"./en-il.js":47207,"./en-in":44175,"./en-in.js":44175,"./en-nz":76319,"./en-nz.js":76319,"./en-sg":31662,"./en-sg.js":31662,"./eo":92915,"./eo.js":92915,"./es":55655,"./es-do":55251,"./es-do.js":55251,"./es-mx":96112,"./es-mx.js":96112,"./es-us":71146,"./es-us.js":71146,"./es.js":55655,"./et":5603,"./et.js":5603,"./eu":77763,"./eu.js":77763,"./fa":76959,"./fa.js":76959,"./fi":11897,"./fi.js":11897,"./fil":42549,"./fil.js":42549,"./fo":94694,"./fo.js":94694,"./fr":94470,"./fr-ca":63049,"./fr-ca.js":63049,"./fr-ch":52330,"./fr-ch.js":52330,"./fr.js":94470,"./fy":5044,"./fy.js":5044,"./ga":29295,"./ga.js":29295,"./gd":2101,"./gd.js":2101,"./gl":38794,"./gl.js":38794,"./gom-deva":27884,"./gom-deva.js":27884,"./gom-latn":23168,"./gom-latn.js":23168,"./gu":95349,"./gu.js":95349,"./he":24206,"./he.js":24206,"./hi":30094,"./hi.js":30094,"./hr":30316,"./hr.js":30316,"./hu":22138,"./hu.js":22138,"./hy-am":11423,"./hy-am.js":11423,"./id":29218,"./id.js":29218,"./is":90135,"./is.js":90135,"./it":90626,"./it-ch":10150,"./it-ch.js":10150,"./it.js":90626,"./ja":39183,"./ja.js":39183,"./jv":24286,"./jv.js":24286,"./ka":12105,"./ka.js":12105,"./kk":47772,"./kk.js":47772,"./km":18758,"./km.js":18758,"./kn":79282,"./kn.js":79282,"./ko":33730,"./ko.js":33730,"./ku":1408,"./ku.js":1408,"./ky":33291,"./ky.js":33291,"./lb":36841,"./lb.js":36841,"./lo":55466,"./lo.js":55466,"./lt":57010,"./lt.js":57010,"./lv":37595,"./lv.js":37595,"./me":39861,"./me.js":39861,"./mi":35493,"./mi.js":35493,"./mk":95966,"./mk.js":95966,"./ml":87341,"./ml.js":87341,"./mn":5115,"./mn.js":5115,"./mr":10370,"./mr.js":10370,"./ms":9847,"./ms-my":41237,"./ms-my.js":41237,"./ms.js":9847,"./mt":72126,"./mt.js":72126,"./my":56165,"./my.js":56165,"./nb":64924,"./nb.js":64924,"./ne":16744,"./ne.js":16744,"./nl":93901,"./nl-be":59814,"./nl-be.js":59814,"./nl.js":93901,"./nn":83877,"./nn.js":83877,"./oc-lnc":92135,"./oc-lnc.js":92135,"./pa-in":15858,"./pa-in.js":15858,"./pl":64495,"./pl.js":64495,"./pt":89520,"./pt-br":57971,"./pt-br.js":57971,"./pt.js":89520,"./ro":96459,"./ro.js":96459,"./ru":21793,"./ru.js":21793,"./sd":40950,"./sd.js":40950,"./se":10490,"./se.js":10490,"./si":90124,"./si.js":90124,"./sk":64249,"./sk.js":64249,"./sl":14985,"./sl.js":14985,"./sq":51104,"./sq.js":51104,"./sr":49131,"./sr-cyrl":79915,"./sr-cyrl.js":79915,"./sr.js":49131,"./ss":85893,"./ss.js":85893,"./sv":98760,"./sv.js":98760,"./sw":91172,"./sw.js":91172,"./ta":27333,"./ta.js":27333,"./te":23110,"./te.js":23110,"./tet":52095,"./tet.js":52095,"./tg":27321,"./tg.js":27321,"./th":9041,"./th.js":9041,"./tk":19005,"./tk.js":19005,"./tl-ph":75768,"./tl-ph.js":75768,"./tlh":89444,"./tlh.js":89444,"./tr":72397,"./tr.js":72397,"./tzl":28254,"./tzl.js":28254,"./tzm":51106,"./tzm-latn":30699,"./tzm-latn.js":30699,"./tzm.js":51106,"./ug-cn":9288,"./ug-cn.js":9288,"./uk":67691,"./uk.js":67691,"./ur":13795,"./ur.js":13795,"./uz":6791,"./uz-latn":60588,"./uz-latn.js":60588,"./uz.js":6791,"./vi":65666,"./vi.js":65666,"./x-pseudo":14378,"./x-pseudo.js":14378,"./yo":75805,"./yo.js":75805,"./zh-cn":83839,"./zh-cn.js":83839,"./zh-hk":55726,"./zh-hk.js":55726,"./zh-mo":99807,"./zh-mo.js":99807,"./zh-tw":74152,"./zh-tw.js":74152};function i(e){return n(a(e))}function a(e){if(!n.o(r,e)){var t=Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}i.keys=function(){return Object.keys(r)},i.resolve=a,e.exports=i,i.id=46700},30381:function(e,t,n){var r,i;e=n.nmd(e),r=this,i=function(){"use strict";function t(){return em.apply(null,arguments)}function r(e){em=e}function i(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function a(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function o(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function s(e){var t;if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;for(t in e)if(o(e,t))return!1;return!0}function u(e){return void 0===e}function c(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function l(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function f(e,t){var n,r=[];for(n=0;n>>0;for(t=0;t0)for(n=0;n=0?n?"+":"":"-")+Math.pow(10,Math.max(0,t-i.length)).toString().substr(1)+i}var R=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,j=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,F={},Y={};function B(e,t,n,r){var i=r;"string"==typeof r&&(i=function(){return this[r]()}),e&&(Y[e]=i),t&&(Y[t[0]]=function(){return P(i.apply(this,arguments),t[1],t[2])}),n&&(Y[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),e)})}function U(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function H(e){var t,n,r=e.match(R);for(t=0,n=r.length;t=0&&j.test(e);)e=e.replace(j,r),j.lastIndex=0,n-=1;return e}var G={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};function W(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];return t||!n?t:(this._longDateFormat[e]=n.match(R).map(function(e){return"MMMM"===e||"MM"===e||"DD"===e||"dddd"===e?e.slice(1):e}).join(""),this._longDateFormat[e])}var K="Invalid date";function V(){return this._invalidDate}var q="%d",Z=/\d{1,2}/;function X(e){return this._ordinal.replace("%d",e)}var J={future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function Q(e,t,n,r){var i=this._relativeTime[n];return A(i)?i(e,t,n,r):i.replace(/%d/i,e)}function ee(e,t){var n=this._relativeTime[e>0?"future":"past"];return A(n)?n(t):n.replace(/%s/i,t)}var et={};function en(e,t){var n=e.toLowerCase();et[n]=et[n+"s"]=et[t]=e}function er(e){return"string"==typeof e?et[e]||et[e.toLowerCase()]:void 0}function ei(e){var t,n,r={};for(n in e)o(e,n)&&(t=er(n))&&(r[t]=e[n]);return r}var ea={};function eo(e,t){ea[e]=t}function es(e){var t,n=[];for(t in e)o(e,t)&&n.push({unit:t,priority:ea[t]});return n.sort(function(e,t){return e.priority-t.priority}),n}function eu(e){return e%4==0&&e%100!=0||e%400==0}function ec(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function el(e){var t=+e,n=0;return 0!==t&&isFinite(t)&&(n=ec(t)),n}function ef(e,n){return function(r){return null!=r?(eh(this,e,r),t.updateOffset(this,n),this):ed(this,e)}}function ed(e,t){return e.isValid()?e._d["get"+(e._isUTC?"UTC":"")+t]():NaN}function eh(e,t,n){e.isValid()&&!isNaN(n)&&("FullYear"===t&&eu(e.year())&&1===e.month()&&29===e.date()?(n=el(n),e._d["set"+(e._isUTC?"UTC":"")+t](n,e.month(),e0(n,e.month()))):e._d["set"+(e._isUTC?"UTC":"")+t](n))}function ep(e){return A(this[e=er(e)])?this[e]():this}function eb(e,t){if("object"==typeof e){e=ei(e);var n,r=es(e);for(n=0;n68?1900:2e3)};var tu=ef("FullYear",!0);function tc(){return eu(this.year())}function tl(e,t,n,r,i,a,o){var s;return e<100&&e>=0?(s=new Date(e+400,t,n,r,i,a,o),isFinite(s.getFullYear())&&s.setFullYear(e)):s=new Date(e,t,n,r,i,a,o),s}function tf(e){var t,n;return e<100&&e>=0?(n=Array.prototype.slice.call(arguments),n[0]=e+400,t=new Date(Date.UTC.apply(null,n)),isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e)):t=new Date(Date.UTC.apply(null,arguments)),t}function td(e,t,n){var r=7+t-n;return-((7+tf(e,0,r).getUTCDay()-t)%7)+r-1}function th(e,t,n,r,i){var a,o,s=(7+n-r)%7,u=td(e,r,i),c=1+7*(t-1)+s+u;return c<=0?o=ts(a=e-1)+c:c>ts(e)?(a=e+1,o=c-ts(e)):(a=e,o=c),{year:a,dayOfYear:o}}function tp(e,t,n){var r,i,a=td(e.year(),t,n),o=Math.floor((e.dayOfYear()-a-1)/7)+1;return o<1?r=o+tb(i=e.year()-1,t,n):o>tb(e.year(),t,n)?(r=o-tb(e.year(),t,n),i=e.year()+1):(i=e.year(),r=o),{week:r,year:i}}function tb(e,t,n){var r=td(e,t,n),i=td(e+1,t,n);return(ts(e)-r+i)/7}function tm(e){return tp(e,this._week.dow,this._week.doy).week}B("w",["ww",2],"wo","week"),B("W",["WW",2],"Wo","isoWeek"),en("week","w"),en("isoWeek","W"),eo("week",5),eo("isoWeek",5),ej("w",ex),ej("ww",ex,e_),ej("W",ex),ej("WW",ex,e_),e$(["w","ww","W","WW"],function(e,t,n,r){t[r.substr(0,1)]=el(e)});var tg={dow:0,doy:6};function tv(){return this._week.dow}function ty(){return this._week.doy}function tw(e){var t=this.localeData().week(this);return null==e?t:this.add((e-t)*7,"d")}function t_(e){var t=tp(this,1,4).week;return null==e?t:this.add((e-t)*7,"d")}function tE(e,t){return"string"!=typeof e?e:isNaN(e)?"number"==typeof(e=t.weekdaysParse(e))?e:null:parseInt(e,10)}function tS(e,t){return"string"==typeof e?t.weekdaysParse(e)%7||7:isNaN(e)?null:e}function tk(e,t){return e.slice(t,7).concat(e.slice(0,t))}B("d",0,"do","day"),B("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),B("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),B("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),B("e",0,0,"weekday"),B("E",0,0,"isoWeekday"),en("day","d"),en("weekday","e"),en("isoWeekday","E"),eo("day",11),eo("weekday",11),eo("isoWeekday",11),ej("d",ex),ej("e",ex),ej("E",ex),ej("dd",function(e,t){return t.weekdaysMinRegex(e)}),ej("ddd",function(e,t){return t.weekdaysShortRegex(e)}),ej("dddd",function(e,t){return t.weekdaysRegex(e)}),e$(["dd","ddd","dddd"],function(e,t,n,r){var i=n._locale.weekdaysParse(e,r,n._strict);null!=i?t.d=i:b(n).invalidWeekday=e}),e$(["d","e","E"],function(e,t,n,r){t[r]=el(e)});var tx="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),tT="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),tM="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),tO=eR,tA=eR,tL=eR;function tC(e,t){var n=i(this._weekdays)?this._weekdays:this._weekdays[e&&!0!==e&&this._weekdays.isFormat.test(t)?"format":"standalone"];return!0===e?tk(n,this._week.dow):e?n[e.day()]:n}function tI(e){return!0===e?tk(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort}function tD(e){return!0===e?tk(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin}function tN(e,t,n){var r,i,a,o=e.toLocaleLowerCase();if(!this._weekdaysParse)for(r=0,this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[];r<7;++r)a=h([2e3,1]).day(r),this._minWeekdaysParse[r]=this.weekdaysMin(a,"").toLocaleLowerCase(),this._shortWeekdaysParse[r]=this.weekdaysShort(a,"").toLocaleLowerCase(),this._weekdaysParse[r]=this.weekdays(a,"").toLocaleLowerCase();return n?"dddd"===t?-1!==(i=tX.call(this._weekdaysParse,o))?i:null:"ddd"===t?-1!==(i=tX.call(this._shortWeekdaysParse,o))?i:null:-1!==(i=tX.call(this._minWeekdaysParse,o))?i:null:"dddd"===t?-1!==(i=tX.call(this._weekdaysParse,o))||-1!==(i=tX.call(this._shortWeekdaysParse,o))?i:-1!==(i=tX.call(this._minWeekdaysParse,o))?i:null:"ddd"===t?-1!==(i=tX.call(this._shortWeekdaysParse,o))||-1!==(i=tX.call(this._weekdaysParse,o))?i:-1!==(i=tX.call(this._minWeekdaysParse,o))?i:null:-1!==(i=tX.call(this._minWeekdaysParse,o))||-1!==(i=tX.call(this._weekdaysParse,o))?i:-1!==(i=tX.call(this._shortWeekdaysParse,o))?i:null}function tP(e,t,n){var r,i,a;if(this._weekdaysParseExact)return tN.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),r=0;r<7;r++){if(i=h([2e3,1]).day(r),n&&!this._fullWeekdaysParse[r]&&(this._fullWeekdaysParse[r]=RegExp("^"+this.weekdays(i,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[r]=RegExp("^"+this.weekdaysShort(i,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[r]=RegExp("^"+this.weekdaysMin(i,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[r]||(a="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[r]=RegExp(a.replace(".",""),"i")),n&&"dddd"===t&&this._fullWeekdaysParse[r].test(e))return r;if(n&&"ddd"===t&&this._shortWeekdaysParse[r].test(e))return r;if(n&&"dd"===t&&this._minWeekdaysParse[r].test(e))return r;else if(!n&&this._weekdaysParse[r].test(e))return r}}function tR(e){if(!this.isValid())return null!=e?this:NaN;var t=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=e?(e=tE(e,this.localeData()),this.add(e-t,"d")):t}function tj(e){if(!this.isValid())return null!=e?this:NaN;var t=(this.day()+7-this.localeData()._week.dow)%7;return null==e?t:this.add(e-t,"d")}function tF(e){if(!this.isValid())return null!=e?this:NaN;if(null==e)return this.day()||7;var t=tS(e,this.localeData());return this.day(this.day()%7?t:t-7)}function tY(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||tH.call(this),e)?this._weekdaysStrictRegex:this._weekdaysRegex:(o(this,"_weekdaysRegex")||(this._weekdaysRegex=tO),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)}function tB(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||tH.call(this),e)?this._weekdaysShortStrictRegex:this._weekdaysShortRegex:(o(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=tA),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function tU(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||tH.call(this),e)?this._weekdaysMinStrictRegex:this._weekdaysMinRegex:(o(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=tL),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function tH(){function e(e,t){return t.length-e.length}var t,n,r,i,a,o=[],s=[],u=[],c=[];for(t=0;t<7;t++)n=h([2e3,1]).day(t),r=eB(this.weekdaysMin(n,"")),i=eB(this.weekdaysShort(n,"")),a=eB(this.weekdays(n,"")),o.push(r),s.push(i),u.push(a),c.push(r),c.push(i),c.push(a);o.sort(e),s.sort(e),u.sort(e),c.sort(e),this._weekdaysRegex=RegExp("^("+c.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=RegExp("^("+u.join("|")+")","i"),this._weekdaysShortStrictRegex=RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=RegExp("^("+o.join("|")+")","i")}function t$(){return this.hours()%12||12}function tz(){return this.hours()||24}function tG(e,t){B(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function tW(e,t){return t._meridiemParse}function tK(e){return"p"===(e+"").toLowerCase().charAt(0)}B("H",["HH",2],0,"hour"),B("h",["hh",2],0,t$),B("k",["kk",2],0,tz),B("hmm",0,0,function(){return""+t$.apply(this)+P(this.minutes(),2)}),B("hmmss",0,0,function(){return""+t$.apply(this)+P(this.minutes(),2)+P(this.seconds(),2)}),B("Hmm",0,0,function(){return""+this.hours()+P(this.minutes(),2)}),B("Hmmss",0,0,function(){return""+this.hours()+P(this.minutes(),2)+P(this.seconds(),2)}),tG("a",!0),tG("A",!1),en("hour","h"),eo("hour",13),ej("a",tW),ej("A",tW),ej("H",ex),ej("h",ex),ej("k",ex),ej("HH",ex,e_),ej("hh",ex,e_),ej("kk",ex,e_),ej("hmm",eT),ej("hmmss",eM),ej("Hmm",eT),ej("Hmmss",eM),eH(["H","HH"],eV),eH(["k","kk"],function(e,t,n){var r=el(e);t[eV]=24===r?0:r}),eH(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),eH(["h","hh"],function(e,t,n){t[eV]=el(e),b(n).bigHour=!0}),eH("hmm",function(e,t,n){var r=e.length-2;t[eV]=el(e.substr(0,r)),t[eq]=el(e.substr(r)),b(n).bigHour=!0}),eH("hmmss",function(e,t,n){var r=e.length-4,i=e.length-2;t[eV]=el(e.substr(0,r)),t[eq]=el(e.substr(r,2)),t[eZ]=el(e.substr(i)),b(n).bigHour=!0}),eH("Hmm",function(e,t,n){var r=e.length-2;t[eV]=el(e.substr(0,r)),t[eq]=el(e.substr(r))}),eH("Hmmss",function(e,t,n){var r=e.length-4,i=e.length-2;t[eV]=el(e.substr(0,r)),t[eq]=el(e.substr(r,2)),t[eZ]=el(e.substr(i))});var tV=/[ap]\.?m?\.?/i,tq=ef("Hours",!0);function tZ(e,t,n){return e>11?n?"pm":"PM":n?"am":"AM"}var tX,tJ,tQ={calendar:D,longDateFormat:G,invalidDate:K,ordinal:q,dayOfMonthOrdinalParse:Z,relativeTime:J,months:e2,monthsShort:e3,week:tg,weekdays:tx,weekdaysMin:tM,weekdaysShort:tT,meridiemParse:tV},t1={},t0={};function t2(e,t){var n,r=Math.min(e.length,t.length);for(n=0;n0;){if(r=t5(i.slice(0,t).join("-")))return r;if(n&&n.length>=t&&t2(i,n)>=t-1)break;t--}a++}return tJ}function t5(t){var r,i=null;if(void 0===t1[t]&&e&&e.exports)try{i=tJ._abbr,r=void 0,n(46700)("./"+t),t6(i)}catch(a){t1[t]=null}return t1[t]}function t6(e,t){var n;return e&&((n=u(t)?t7(e):t9(e,t))?tJ=n:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),tJ._abbr}function t9(e,t){if(null===t)return delete t1[e],null;var n,r=tQ;if(t.abbr=e,null!=t1[e])O("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),r=t1[e]._config;else if(null!=t.parentLocale){if(null!=t1[t.parentLocale])r=t1[t.parentLocale]._config;else{if(null==(n=t5(t.parentLocale)))return t0[t.parentLocale]||(t0[t.parentLocale]=[]),t0[t.parentLocale].push({name:e,config:t}),null;r=n._config}}return t1[e]=new I(C(r,t)),t0[e]&&t0[e].forEach(function(e){t9(e.name,e.config)}),t6(e),t1[e]}function t8(e,t){if(null!=t){var n,r,i=tQ;null!=t1[e]&&null!=t1[e].parentLocale?t1[e].set(C(t1[e]._config,t)):(null!=(r=t5(e))&&(i=r._config),t=C(i,t),null==r&&(t.abbr=e),(n=new I(t)).parentLocale=t1[e],t1[e]=n),t6(e)}else null!=t1[e]&&(null!=t1[e].parentLocale?(t1[e]=t1[e].parentLocale,e===t6()&&t6(e)):null!=t1[e]&&delete t1[e]);return t1[e]}function t7(e){var t;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return tJ;if(!i(e)){if(t=t5(e))return t;e=[e]}return t4(e)}function ne(){return ev(t1)}function nt(e){var t,n=e._a;return n&&-2===b(e).overflow&&(t=n[eW]<0||n[eW]>11?eW:n[eK]<1||n[eK]>e0(n[eG],n[eW])?eK:n[eV]<0||n[eV]>24||24===n[eV]&&(0!==n[eq]||0!==n[eZ]||0!==n[eX])?eV:n[eq]<0||n[eq]>59?eq:n[eZ]<0||n[eZ]>59?eZ:n[eX]<0||n[eX]>999?eX:-1,b(e)._overflowDayOfYear&&(teK)&&(t=eK),b(e)._overflowWeeks&&-1===t&&(t=eJ),b(e)._overflowWeekday&&-1===t&&(t=eQ),b(e).overflow=t),e}var nn=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,nr=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,ni=/Z|[+-]\d\d(?::?\d\d)?/,na=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1],],no=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/],],ns=/^\/?Date\((-?\d+)/i,nu=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,nc={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function nl(e){var t,n,r,i,a,o,s=e._i,u=nn.exec(s)||nr.exec(s);if(u){for(t=0,b(e).iso=!0,n=na.length;tts(a)||0===e._dayOfYear)&&(b(e)._overflowDayOfYear=!0),n=tf(a,0,e._dayOfYear),e._a[eW]=n.getUTCMonth(),e._a[eK]=n.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=o[t]=r[t];for(;t<7;t++)e._a[t]=o[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[eV]&&0===e._a[eq]&&0===e._a[eZ]&&0===e._a[eX]&&(e._nextDay=!0,e._a[eV]=0),e._d=(e._useUTC?tf:tl).apply(null,o),i=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[eV]=24),e._w&&void 0!==e._w.d&&e._w.d!==i&&(b(e).weekdayMismatch=!0)}}function n_(e){var t,n,r,i,a,o,s,u,c;null!=(t=e._w).GG||null!=t.W||null!=t.E?(a=1,o=4,n=nv(t.GG,e._a[eG],tp(nL(),1,4).year),r=nv(t.W,1),((i=nv(t.E,1))<1||i>7)&&(u=!0)):(a=e._locale._week.dow,o=e._locale._week.doy,c=tp(nL(),a,o),n=nv(t.gg,e._a[eG],c.year),r=nv(t.w,c.week),null!=t.d?((i=t.d)<0||i>6)&&(u=!0):null!=t.e?(i=t.e+a,(t.e<0||t.e>6)&&(u=!0)):i=a),r<1||r>tb(n,a,o)?b(e)._overflowWeeks=!0:null!=u?b(e)._overflowWeekday=!0:(s=th(n,r,i,a,o),e._a[eG]=s.year,e._dayOfYear=s.dayOfYear)}function nE(e){if(e._f===t.ISO_8601){nl(e);return}if(e._f===t.RFC_2822){nm(e);return}e._a=[],b(e).empty=!0;var n,r,i,a,o,s,u=""+e._i,c=u.length,l=0;for(n=0,i=z(e._f,e._locale).match(R)||[];n0&&b(e).unusedInput.push(o),u=u.slice(u.indexOf(r)+r.length),l+=r.length),Y[a]?(r?b(e).empty=!1:b(e).unusedTokens.push(a),ez(a,r,e)):e._strict&&!r&&b(e).unusedTokens.push(a);b(e).charsLeftOver=c-l,u.length>0&&b(e).unusedInput.push(u),e._a[eV]<=12&&!0===b(e).bigHour&&e._a[eV]>0&&(b(e).bigHour=void 0),b(e).parsedDateParts=e._a.slice(0),b(e).meridiem=e._meridiem,e._a[eV]=nS(e._locale,e._a[eV],e._meridiem),null!==(s=b(e).era)&&(e._a[eG]=e._locale.erasConvertYear(s,e._a[eG])),nw(e),nt(e)}function nS(e,t,n){var r;return null==n?t:null!=e.meridiemHour?e.meridiemHour(t,n):(null!=e.isPM&&((r=e.isPM(n))&&t<12&&(t+=12),r||12!==t||(t=0)),t)}function nk(e){var t,n,r,i,a,o,s=!1;if(0===e._f.length){b(e).invalidFormat=!0,e._d=new Date(NaN);return}for(i=0;ithis?this:e:g()});function nD(e,t){var n,r;if(1===t.length&&i(t[0])&&(t=t[0]),!t.length)return nL();for(r=1,n=t[0];rMath.abs(e)&&!r&&(e*=60);return!this._isUTC&&n&&(i=nq(this)),this._offset=e,this._isUTC=!0,null!=i&&this.add(i,"m"),a===e||(!n||this._changeInProgress?ri(this,n7(e-a,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,t.updateOffset(this,!0),this._changeInProgress=null)),this}function nX(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}function nJ(e){return this.utcOffset(0,e)}function nQ(e){return this._isUTC&&(this.utcOffset(0,e),this._isUTC=!1,e&&this.subtract(nq(this),"m")),this}function n1(){if(null!=this._tzm)this.utcOffset(this._tzm,!1,!0);else if("string"==typeof this._i){var e=nK(eD,this._i);null!=e?this.utcOffset(e):this.utcOffset(0,!0)}return this}function n0(e){return!!this.isValid()&&(e=e?nL(e).utcOffset():0,(this.utcOffset()-e)%60==0)}function n2(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function n3(){if(!u(this._isDSTShifted))return this._isDSTShifted;var e,t={};return E(t,this),(t=nM(t))._a?(e=t._isUTC?h(t._a):nL(t._a),this._isDSTShifted=this.isValid()&&nz(t._a,e.toArray())>0):this._isDSTShifted=!1,this._isDSTShifted}function n4(){return!!this.isValid()&&!this._isUTC}function n5(){return!!this.isValid()&&this._isUTC}function n6(){return!!this.isValid()&&this._isUTC&&0===this._offset}t.updateOffset=function(){};var n9=/^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,n8=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function n7(e,t){var n,r,i,a=e,s=null;return nH(e)?a={ms:e._milliseconds,d:e._days,M:e._months}:c(e)||!isNaN(+e)?(a={},t?a[t]=+e:a.milliseconds=+e):(s=n9.exec(e))?(n="-"===s[1]?-1:1,a={y:0,d:el(s[eK])*n,h:el(s[eV])*n,m:el(s[eq])*n,s:el(s[eZ])*n,ms:el(n$(1e3*s[eX]))*n}):(s=n8.exec(e))?(n="-"===s[1]?-1:1,a={y:re(s[2],n),M:re(s[3],n),w:re(s[4],n),d:re(s[5],n),h:re(s[6],n),m:re(s[7],n),s:re(s[8],n)}):null==a?a={}:"object"==typeof a&&("from"in a||"to"in a)&&(i=rn(nL(a.from),nL(a.to)),(a={}).ms=i.milliseconds,a.M=i.months),r=new nU(a),nH(e)&&o(e,"_locale")&&(r._locale=e._locale),nH(e)&&o(e,"_isValid")&&(r._isValid=e._isValid),r}function re(e,t){var n=e&&parseFloat(e.replace(",","."));return(isNaN(n)?0:n)*t}function rt(e,t){var n={};return n.months=t.month()-e.month()+(t.year()-e.year())*12,e.clone().add(n.months,"M").isAfter(t)&&--n.months,n.milliseconds=+t-+e.clone().add(n.months,"M"),n}function rn(e,t){var n;return e.isValid()&&t.isValid()?(t=nV(t,e),e.isBefore(t)?n=rt(e,t):((n=rt(t,e)).milliseconds=-n.milliseconds,n.months=-n.months),n):{milliseconds:0,months:0}}function rr(e,t){return function(n,r){var i,a;return null===r||isNaN(+r)||(O(t,"moment()."+t+"(period, number) is deprecated. Please use moment()."+t+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),a=n,n=r,r=a),i=n7(n,r),ri(this,i,e),this}}function ri(e,n,r,i){var a=n._milliseconds,o=n$(n._days),s=n$(n._months);e.isValid()&&(i=null==i||i,s&&tt(e,ed(e,"Month")+s*r),o&&eh(e,"Date",ed(e,"Date")+o*r),a&&e._d.setTime(e._d.valueOf()+a*r),i&&t.updateOffset(e,o||s))}n7.fn=nU.prototype,n7.invalid=nB;var ra=rr(1,"add"),ro=rr(-1,"subtract");function rs(e){return"string"==typeof e||e instanceof String}function ru(e){return k(e)||l(e)||rs(e)||c(e)||rl(e)||rc(e)||null==e}function rc(e){var t,n,r=a(e)&&!s(e),i=!1,u=["years","year","y","months","month","M","days","day","d","dates","date","D","hours","hour","h","minutes","minute","m","seconds","second","s","milliseconds","millisecond","ms",];for(t=0;tn.valueOf():n.valueOf()n.year()||n.year()>9999?$(n,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):A(Date.prototype.toISOString)?t?this.toDate().toISOString():new Date(this.valueOf()+6e4*this.utcOffset()).toISOString().replace("Z",$(n,"Z")):$(n,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")}function rx(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e,t,n,r,i="moment",a="";return this.isLocal()||(i=0===this.utcOffset()?"moment.utc":"moment.parseZone",a="Z"),e="["+i+'("]',t=0<=this.year()&&9999>=this.year()?"YYYY":"YYYYYY",n="-MM-DD[T]HH:mm:ss.SSS",r=a+'[")]',this.format(e+t+n+r)}function rT(e){e||(e=this.isUtc()?t.defaultFormatUtc:t.defaultFormat);var n=$(this,e);return this.localeData().postformat(n)}function rM(e,t){return this.isValid()&&(k(e)&&e.isValid()||nL(e).isValid())?n7({to:this,from:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()}function rO(e){return this.from(nL(),e)}function rA(e,t){return this.isValid()&&(k(e)&&e.isValid()||nL(e).isValid())?n7({from:this,to:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()}function rL(e){return this.to(nL(),e)}function rC(e){var t;return void 0===e?this._locale._abbr:(null!=(t=t7(e))&&(this._locale=t),this)}t.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",t.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var rI=T("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(e){return void 0===e?this.localeData():this.locale(e)});function rD(){return this._locale}var rN=1e3,rP=60*rN,rR=60*rP,rj=3506328*rR;function rF(e,t){return(e%t+t)%t}function rY(e,t,n){return e<100&&e>=0?new Date(e+400,t,n)-rj:new Date(e,t,n).valueOf()}function rB(e,t,n){return e<100&&e>=0?Date.UTC(e+400,t,n)-rj:Date.UTC(e,t,n)}function rU(e){var n,r;if(void 0===(e=er(e))||"millisecond"===e||!this.isValid())return this;switch(r=this._isUTC?rB:rY,e){case"year":n=r(this.year(),0,1);break;case"quarter":n=r(this.year(),this.month()-this.month()%3,1);break;case"month":n=r(this.year(),this.month(),1);break;case"week":n=r(this.year(),this.month(),this.date()-this.weekday());break;case"isoWeek":n=r(this.year(),this.month(),this.date()-(this.isoWeekday()-1));break;case"day":case"date":n=r(this.year(),this.month(),this.date());break;case"hour":n=this._d.valueOf(),n-=rF(n+(this._isUTC?0:this.utcOffset()*rP),rR);break;case"minute":n=this._d.valueOf(),n-=rF(n,rP);break;case"second":n=this._d.valueOf(),n-=rF(n,rN)}return this._d.setTime(n),t.updateOffset(this,!0),this}function rH(e){var n,r;if(void 0===(e=er(e))||"millisecond"===e||!this.isValid())return this;switch(r=this._isUTC?rB:rY,e){case"year":n=r(this.year()+1,0,1)-1;break;case"quarter":n=r(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":n=r(this.year(),this.month()+1,1)-1;break;case"week":n=r(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":n=r(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":n=r(this.year(),this.month(),this.date()+1)-1;break;case"hour":n=this._d.valueOf(),n+=rR-rF(n+(this._isUTC?0:this.utcOffset()*rP),rR)-1;break;case"minute":n=this._d.valueOf(),n+=rP-rF(n,rP)-1;break;case"second":n=this._d.valueOf(),n+=rN-rF(n,rN)-1}return this._d.setTime(n),t.updateOffset(this,!0),this}function r$(){return this._d.valueOf()-6e4*(this._offset||0)}function rz(){return Math.floor(this.valueOf()/1e3)}function rG(){return new Date(this.valueOf())}function rW(){var e=this;return[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second(),e.millisecond(),]}function rK(){var e=this;return{years:e.year(),months:e.month(),date:e.date(),hours:e.hours(),minutes:e.minutes(),seconds:e.seconds(),milliseconds:e.milliseconds()}}function rV(){return this.isValid()?this.toISOString():null}function rq(){return m(this)}function rZ(){return d({},b(this))}function rX(){return b(this).overflow}function rJ(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function rQ(e,n){var r,i,a,o=this._eras||t7("en")._eras;for(r=0,i=o.length;r=0)return u[r]}function r0(e,n){var r=e.since<=e.until?1:-1;return void 0===n?t(e.since).year():t(e.since).year()+(n-e.offset)*r}function r2(){var e,t,n,r=this.localeData().eras();for(e=0,t=r.length;ea&&(t=a),ip.call(this,e,t,n,r,i))}function ip(e,t,n,r,i){var a=th(e,t,n,r,i),o=tf(a.year,0,a.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}function ib(e){return null==e?Math.ceil((this.month()+1)/3):this.month((e-1)*3+this.month()%3)}B("N",0,0,"eraAbbr"),B("NN",0,0,"eraAbbr"),B("NNN",0,0,"eraAbbr"),B("NNNN",0,0,"eraName"),B("NNNNN",0,0,"eraNarrow"),B("y",["y",1],"yo","eraYear"),B("y",["yy",2],0,"eraYear"),B("y",["yyy",3],0,"eraYear"),B("y",["yyyy",4],0,"eraYear"),ej("N",r7),ej("NN",r7),ej("NNN",r7),ej("NNNN",ie),ej("NNNNN",it),eH(["N","NN","NNN","NNNN","NNNNN"],function(e,t,n,r){var i=n._locale.erasParse(e,r,n._strict);i?b(n).era=i:b(n).invalidEra=e}),ej("y",eC),ej("yy",eC),ej("yyy",eC),ej("yyyy",eC),ej("yo",ir),eH(["y","yy","yyy","yyyy"],eG),eH(["yo"],function(e,t,n,r){var i;n._locale._eraYearOrdinalRegex&&(i=e.match(n._locale._eraYearOrdinalRegex)),n._locale.eraYearOrdinalParse?t[eG]=n._locale.eraYearOrdinalParse(e,i):t[eG]=parseInt(e,10)}),B(0,["gg",2],0,function(){return this.weekYear()%100}),B(0,["GG",2],0,function(){return this.isoWeekYear()%100}),ia("gggg","weekYear"),ia("ggggg","weekYear"),ia("GGGG","isoWeekYear"),ia("GGGGG","isoWeekYear"),en("weekYear","gg"),en("isoWeekYear","GG"),eo("weekYear",1),eo("isoWeekYear",1),ej("G",eI),ej("g",eI),ej("GG",ex,e_),ej("gg",ex,e_),ej("GGGG",eA,eS),ej("gggg",eA,eS),ej("GGGGG",eL,ek),ej("ggggg",eL,ek),e$(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,r){t[r.substr(0,2)]=el(e)}),e$(["gg","GG"],function(e,n,r,i){n[i]=t.parseTwoDigitYear(e)}),B("Q",0,"Qo","quarter"),en("quarter","Q"),eo("quarter",7),ej("Q",ew),eH("Q",function(e,t){t[eW]=(el(e)-1)*3}),B("D",["DD",2],"Do","date"),en("date","D"),eo("date",9),ej("D",ex),ej("DD",ex,e_),ej("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),eH(["D","DD"],eK),eH("Do",function(e,t){t[eK]=el(e.match(ex)[0])});var im=ef("Date",!0);function ig(e){var t=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==e?t:this.add(e-t,"d")}B("DDD",["DDDD",3],"DDDo","dayOfYear"),en("dayOfYear","DDD"),eo("dayOfYear",4),ej("DDD",eO),ej("DDDD",eE),eH(["DDD","DDDD"],function(e,t,n){n._dayOfYear=el(e)}),B("m",["mm",2],0,"minute"),en("minute","m"),eo("minute",14),ej("m",ex),ej("mm",ex,e_),eH(["m","mm"],eq);var iv=ef("Minutes",!1);B("s",["ss",2],0,"second"),en("second","s"),eo("second",15),ej("s",ex),ej("ss",ex,e_),eH(["s","ss"],eZ);var iy=ef("Seconds",!1);for(B("S",0,0,function(){return~~(this.millisecond()/100)}),B(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),B(0,["SSS",3],0,"millisecond"),B(0,["SSSS",4],0,function(){return 10*this.millisecond()}),B(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),B(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),B(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),B(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),B(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),en("millisecond","ms"),eo("millisecond",16),ej("S",eO,ew),ej("SS",eO,e_),ej("SSS",eO,eE),v="SSSS";v.length<=9;v+="S")ej(v,eC);function iw(e,t){t[eX]=el(("0."+e)*1e3)}for(v="S";v.length<=9;v+="S")eH(v,iw);function i_(){return this._isUTC?"UTC":""}function iE(){return this._isUTC?"Coordinated Universal Time":""}y=ef("Milliseconds",!1),B("z",0,0,"zoneAbbr"),B("zz",0,0,"zoneName");var iS=S.prototype;function ik(e){return nL(1e3*e)}function ix(){return nL.apply(null,arguments).parseZone()}function iT(e){return e}iS.add=ra,iS.calendar=rh,iS.clone=rp,iS.diff=r_,iS.endOf=rH,iS.format=rT,iS.from=rM,iS.fromNow=rO,iS.to=rA,iS.toNow=rL,iS.get=ep,iS.invalidAt=rX,iS.isAfter=rb,iS.isBefore=rm,iS.isBetween=rg,iS.isSame=rv,iS.isSameOrAfter=ry,iS.isSameOrBefore=rw,iS.isValid=rq,iS.lang=rI,iS.locale=rC,iS.localeData=rD,iS.max=nI,iS.min=nC,iS.parsingFlags=rZ,iS.set=eb,iS.startOf=rU,iS.subtract=ro,iS.toArray=rW,iS.toObject=rK,iS.toDate=rG,iS.toISOString=rk,iS.inspect=rx,"undefined"!=typeof Symbol&&null!=Symbol.for&&(iS[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),iS.toJSON=rV,iS.toString=rS,iS.unix=rz,iS.valueOf=r$,iS.creationData=rJ,iS.eraName=r2,iS.eraNarrow=r3,iS.eraAbbr=r4,iS.eraYear=r5,iS.year=tu,iS.isLeapYear=tc,iS.weekYear=io,iS.isoWeekYear=is,iS.quarter=iS.quarters=ib,iS.month=tn,iS.daysInMonth=tr,iS.week=iS.weeks=tw,iS.isoWeek=iS.isoWeeks=t_,iS.weeksInYear=il,iS.weeksInWeekYear=id,iS.isoWeeksInYear=iu,iS.isoWeeksInISOWeekYear=ic,iS.date=im,iS.day=iS.days=tR,iS.weekday=tj,iS.isoWeekday=tF,iS.dayOfYear=ig,iS.hour=iS.hours=tq,iS.minute=iS.minutes=iv,iS.second=iS.seconds=iy,iS.millisecond=iS.milliseconds=y,iS.utcOffset=nZ,iS.utc=nJ,iS.local=nQ,iS.parseZone=n1,iS.hasAlignedHourOffset=n0,iS.isDST=n2,iS.isLocal=n4,iS.isUtcOffset=n5,iS.isUtc=n6,iS.isUTC=n6,iS.zoneAbbr=i_,iS.zoneName=iE,iS.dates=T("dates accessor is deprecated. Use date instead.",im),iS.months=T("months accessor is deprecated. Use month instead",tn),iS.years=T("years accessor is deprecated. Use year instead",tu),iS.zone=T("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",nX),iS.isDSTShifted=T("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",n3);var iM=I.prototype;function iO(e,t,n,r){var i=t7(),a=h().set(r,t);return i[n](a,e)}function iA(e,t,n){if(c(e)&&(t=e,e=void 0),e=e||"",null!=t)return iO(e,t,n,"month");var r,i=[];for(r=0;r<12;r++)i[r]=iO(e,r,n,"month");return i}function iL(e,t,n,r){"boolean"==typeof e?(c(t)&&(n=t,t=void 0),t=t||""):(n=t=e,e=!1,c(t)&&(n=t,t=void 0),t=t||"");var i,a=t7(),o=e?a._week.dow:0,s=[];if(null!=n)return iO(t,(n+o)%7,r,"day");for(i=0;i<7;i++)s[i]=iO(t,(i+o)%7,r,"day");return s}function iC(e,t){return iA(e,t,"months")}function iI(e,t){return iA(e,t,"monthsShort")}function iD(e,t,n){return iL(e,t,n,"weekdays")}function iN(e,t,n){return iL(e,t,n,"weekdaysShort")}function iP(e,t,n){return iL(e,t,n,"weekdaysMin")}iM.calendar=N,iM.longDateFormat=W,iM.invalidDate=V,iM.ordinal=X,iM.preparse=iT,iM.postformat=iT,iM.relativeTime=Q,iM.pastFuture=ee,iM.set=L,iM.eras=rQ,iM.erasParse=r1,iM.erasConvertYear=r0,iM.erasAbbrRegex=r9,iM.erasNameRegex=r6,iM.erasNarrowRegex=r8,iM.months=e9,iM.monthsShort=e8,iM.monthsParse=te,iM.monthsRegex=ta,iM.monthsShortRegex=ti,iM.week=tm,iM.firstDayOfYear=ty,iM.firstDayOfWeek=tv,iM.weekdays=tC,iM.weekdaysMin=tD,iM.weekdaysShort=tI,iM.weekdaysParse=tP,iM.weekdaysRegex=tY,iM.weekdaysShortRegex=tB,iM.weekdaysMinRegex=tU,iM.isPM=tK,iM.meridiem=tZ,t6("en",{eras:[{since:"0001-01-01",until:Infinity,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"},],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10,n=1===el(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th";return e+n}}),t.lang=T("moment.lang is deprecated. Use moment.locale instead.",t6),t.langData=T("moment.langData is deprecated. Use moment.localeData instead.",t7);var iR=Math.abs;function ij(){var e=this._data;return this._milliseconds=iR(this._milliseconds),this._days=iR(this._days),this._months=iR(this._months),e.milliseconds=iR(e.milliseconds),e.seconds=iR(e.seconds),e.minutes=iR(e.minutes),e.hours=iR(e.hours),e.months=iR(e.months),e.years=iR(e.years),this}function iF(e,t,n,r){var i=n7(t,n);return e._milliseconds+=r*i._milliseconds,e._days+=r*i._days,e._months+=r*i._months,e._bubble()}function iY(e,t){return iF(this,e,t,1)}function iB(e,t){return iF(this,e,t,-1)}function iU(e){return e<0?Math.floor(e):Math.ceil(e)}function iH(){var e,t,n,r,i,a=this._milliseconds,o=this._days,s=this._months,u=this._data;return a>=0&&o>=0&&s>=0||a<=0&&o<=0&&s<=0||(a+=864e5*iU(iz(s)+o),o=0,s=0),u.milliseconds=a%1e3,e=ec(a/1e3),u.seconds=e%60,t=ec(e/60),u.minutes=t%60,n=ec(t/60),u.hours=n%24,o+=ec(n/24),s+=i=ec(i$(o)),o-=iU(iz(i)),r=ec(s/12),s%=12,u.days=o,u.months=s,u.years=r,this}function i$(e){return 4800*e/146097}function iz(e){return 146097*e/4800}function iG(e){if(!this.isValid())return NaN;var t,n,r=this._milliseconds;if("month"===(e=er(e))||"quarter"===e||"year"===e)switch(t=this._days+r/864e5,n=this._months+i$(t),e){case"month":return n;case"quarter":return n/3;case"year":return n/12}else switch(t=this._days+Math.round(iz(this._months)),e){case"week":return t/7+r/6048e5;case"day":return t+r/864e5;case"hour":return 24*t+r/36e5;case"minute":return 1440*t+r/6e4;case"second":return 86400*t+r/1e3;case"millisecond":return Math.floor(864e5*t)+r;default:throw Error("Unknown unit "+e)}}function iW(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*el(this._months/12):NaN}function iK(e){return function(){return this.as(e)}}var iV=iK("ms"),iq=iK("s"),iZ=iK("m"),iX=iK("h"),iJ=iK("d"),iQ=iK("w"),i1=iK("M"),i0=iK("Q"),i2=iK("y");function i3(){return n7(this)}function i4(e){return e=er(e),this.isValid()?this[e+"s"]():NaN}function i5(e){return function(){return this.isValid()?this._data[e]:NaN}}var i6=i5("milliseconds"),i9=i5("seconds"),i8=i5("minutes"),i7=i5("hours"),ae=i5("days"),at=i5("months"),an=i5("years");function ar(){return ec(this.days()/7)}var ai=Math.round,aa={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function ao(e,t,n,r,i){return i.relativeTime(t||1,!!n,e,r)}function as(e,t,n,r){var i=n7(e).abs(),a=ai(i.as("s")),o=ai(i.as("m")),s=ai(i.as("h")),u=ai(i.as("d")),c=ai(i.as("M")),l=ai(i.as("w")),f=ai(i.as("y")),d=a<=n.ss&&["s",a]||a0,d[4]=r,ao.apply(null,d)}function au(e){return void 0===e?ai:"function"==typeof e&&(ai=e,!0)}function ac(e,t){return void 0!==aa[e]&&(void 0===t?aa[e]:(aa[e]=t,"s"===e&&(aa.ss=t-1),!0))}function al(e,t){if(!this.isValid())return this.localeData().invalidDate();var n,r,i=!1,a=aa;return"object"==typeof e&&(t=e,e=!1),"boolean"==typeof e&&(i=e),"object"==typeof t&&(a=Object.assign({},aa,t),null!=t.s&&null==t.ss&&(a.ss=t.s-1)),r=as(this,!i,a,n=this.localeData()),i&&(r=n.pastFuture(+this,r)),n.postformat(r)}var af=Math.abs;function ad(e){return(e>0)-(e<0)||+e}function ah(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n,r,i,a,o,s,u=af(this._milliseconds)/1e3,c=af(this._days),l=af(this._months),f=this.asSeconds();return f?(e=ec(u/60),t=ec(e/60),u%=60,e%=60,n=ec(l/12),l%=12,r=u?u.toFixed(3).replace(/\.?0+$/,""):"",i=f<0?"-":"",a=ad(this._months)!==ad(f)?"-":"",o=ad(this._days)!==ad(f)?"-":"",s=ad(this._milliseconds)!==ad(f)?"-":"",i+"P"+(n?a+n+"Y":"")+(l?a+l+"M":"")+(c?o+c+"D":"")+(t||e||u?"T":"")+(t?s+t+"H":"")+(e?s+e+"M":"")+(u?s+r+"S":"")):"P0D"}var ap=nU.prototype;return ap.isValid=nY,ap.abs=ij,ap.add=iY,ap.subtract=iB,ap.as=iG,ap.asMilliseconds=iV,ap.asSeconds=iq,ap.asMinutes=iZ,ap.asHours=iX,ap.asDays=iJ,ap.asWeeks=iQ,ap.asMonths=i1,ap.asQuarters=i0,ap.asYears=i2,ap.valueOf=iW,ap._bubble=iH,ap.clone=i3,ap.get=i4,ap.milliseconds=i6,ap.seconds=i9,ap.minutes=i8,ap.hours=i7,ap.days=ae,ap.weeks=ar,ap.months=at,ap.years=an,ap.humanize=al,ap.toISOString=ah,ap.toString=ah,ap.toJSON=ah,ap.locale=rC,ap.localeData=rD,ap.toIsoString=T("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ah),ap.lang=rI,B("X",0,0,"unix"),B("x",0,0,"valueOf"),ej("x",eI),ej("X",eP),eH("X",function(e,t,n){n._d=new Date(1e3*parseFloat(e))}),eH("x",function(e,t,n){n._d=new Date(el(e))}),//! moment.js +t.version="2.29.1",r(nL),t.fn=iS,t.min=nN,t.max=nP,t.now=nR,t.utc=h,t.unix=ik,t.months=iC,t.isDate=l,t.locale=t6,t.invalid=g,t.duration=n7,t.isMoment=k,t.weekdays=iD,t.parseZone=ix,t.localeData=t7,t.isDuration=nH,t.monthsShort=iI,t.weekdaysMin=iP,t.defineLocale=t9,t.updateLocale=t8,t.locales=ne,t.weekdaysShort=iN,t.normalizeUnits=er,t.relativeTimeRounding=au,t.relativeTimeThreshold=ac,t.calendarFormat=rd,t.prototype=iS,t.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},t},e.exports=i()},46417(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n,r=!!("undefined"!=typeof window&&window.document&&window.document.createElement);function i(e){n=e}function a(){if(n)return n;if(!r||!window.document.body)return"indeterminate";var e=window.document.createElement("div");return e.appendChild(document.createTextNode("ABCD")),e.dir="rtl",e.style.fontSize="14px",e.style.width="4px",e.style.height="1px",e.style.position="absolute",e.style.top="-1000px",e.style.overflow="scroll",document.body.appendChild(e),n="reverse",e.scrollLeft>0?n="default":(e.scrollLeft=1,0===e.scrollLeft&&(n="negative")),document.body.removeChild(e),n}function o(e,t){var n=e.scrollLeft;if("rtl"!==t)return n;var r=a();if("indeterminate"===r)return Number.NaN;switch(r){case"negative":return e.scrollWidth-e.clientWidth+n;case"reverse":return e.scrollWidth-e.clientWidth-n}return n}function s(e,t,n){if("rtl"!==n){e.scrollLeft=t;return}var r=a();if("indeterminate"!==r)switch(r){case"negative":e.scrollLeft=e.clientWidth-e.scrollWidth+t;break;case"reverse":e.scrollLeft=e.scrollWidth-e.clientWidth-t;break;default:e.scrollLeft=t}}t._setScrollType=i,t.detectScrollType=a,t.getNormalizedScrollLeft=o,t.setNormalizedScrollLeft=s},27418(e){"use strict";/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;function i(e){if(null==e)throw TypeError("Object.assign cannot be called with null or undefined");return Object(e)}function a(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;var r=Object.getOwnPropertyNames(t).map(function(e){return t[e]});if("0123456789"!==r.join(""))return!1;var i={};if("abcdefghijklmnopqrst".split("").forEach(function(e){i[e]=e}),"abcdefghijklmnopqrst"!==Object.keys(Object.assign({},i)).join(""))return!1;return!0}catch(a){return!1}}e.exports=a()?Object.assign:function(e,a){for(var o,s,u=i(e),c=1;c65535&&(Y-=65536,G+=l(Y>>>10|55296),Y=56320|1023&Y),Y=G+l(Y))):q!==x&&$(D,Q)),Y?(ew(),X=ev(),ed=ee-1,ep+=ee-V+1,eg.push(Y),J=ev(),J.offset++,ei&&ei.call(es,Y,{start:X,end:J},e.slice(V-1,ee)),X=J):(em+=d=e.slice(V-1,ee),ep+=d.length,ed=ee-1)}else 10===F&&(eb++,eh++,ep=0),F==F?(em+=l(F),ep++):ew();return eg.join("");function ev(){return{line:eb,column:ep,offset:ed+(ec.offset||0)}}function ey(e,t){var n=ev();n.column+=t,n.offset+=t,ea.call(eu,j[e],n,e)}function ew(){em&&(eg.push(em),er&&er.call(eo,em,{start:X,end:ev()}),em="")}}function B(e){return e>=55296&&e<=57343||e>1114111}function U(e){return e>=1&&e<=8||11===e||e>=13&&e<=31||e>=127&&e<=159||e>=64976&&e<=65007||(65535&e)==65535||(65535&e)==65534}j[L]="Named character references must be terminated by a semicolon",j[C]="Numeric character references must be terminated by a semicolon",j[I]="Named character references cannot be empty",j[D]="Numeric character references cannot be empty",j[N]="Named character references must be known",j[P]="Numeric character references cannot be disallowed",j[R]="Numeric character references cannot be outside the permissible Unicode range"},14779(e){e.exports=b,e.exports.match=a,e.exports.regexpToFunction=o,e.exports.parse=r,e.exports.compile=i,e.exports.tokensToFunction=s,e.exports.tokensToRegExp=p;var t="/",n=RegExp("(\\\\.)|(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?","g");function r(e,r){for(var i,a=[],o=0,s=0,l="",f=r&&r.delimiter||t,d=r&&r.whitelist||void 0,h=!1;null!==(i=n.exec(e));){var p=i[0],b=i[1],m=i.index;if(l+=e.slice(s,m),s=m+p.length,b){l+=b[1],h=!0;continue}var g="",v=i[2],y=i[3],w=i[4],_=i[5];if(!h&&l.length){var E=l.length-1,S=l[E];(!d||d.indexOf(S)>-1)&&(g=S,l=l.slice(0,E))}l&&(a.push(l),l="",h=!1);var k="+"===_||"*"===_,x="?"===_||"*"===_,T=y||w,M=g||f;a.push({name:v||o++,prefix:g,delimiter:M,optional:x,repeat:k,pattern:T?c(T):"[^"+u(M===f?M:M+f)+"]+?"})}return(l||seM});/**! + * @fileOverview Kickass library to create and place poppers near their reference elements. + * @version 1.16.0 + * @license + * Copyright (c) 2016 Federico Zivolo and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ var r="undefined"!=typeof window&&"undefined"!=typeof document&&"undefined"!=typeof navigator,i=function(){for(var e=["Edge","Trident","Firefox"],t=0;t=0)return 1;return 0}();function a(e){var t=!1;return function(){!t&&(t=!0,window.Promise.resolve().then(function(){t=!1,e()}))}}function o(e){var t=!1;return function(){t||(t=!0,setTimeout(function(){t=!1,e()},i))}}var s=r&&window.Promise?a:o;function u(e){var t={};return e&&"[object Function]"===t.toString.call(e)}function c(e,t){if(1!==e.nodeType)return[];var n=e.ownerDocument.defaultView.getComputedStyle(e,null);return t?n[t]:n}function l(e){return"HTML"===e.nodeName?e:e.parentNode||e.host}function f(e){if(!e)return document.body;switch(e.nodeName){case"HTML":case"BODY":return e.ownerDocument.body;case"#document":return e.body}var t=c(e),n=t.overflow,r=t.overflowX,i=t.overflowY;return/(auto|scroll|overlay)/.test(n+i+r)?e:f(l(e))}function d(e){return e&&e.referenceNode?e.referenceNode:e}var h=r&&!!(window.MSInputMethodContext&&document.documentMode),p=r&&/MSIE 10/.test(navigator.userAgent);function b(e){return 11===e?h:10===e?p:h||p}function m(e){if(!e)return document.documentElement;for(var t=b(10)?document.body:null,n=e.offsetParent||null;n===t&&e.nextElementSibling;)n=(e=e.nextElementSibling).offsetParent;var r=n&&n.nodeName;return r&&"BODY"!==r&&"HTML"!==r?-1!==["TH","TD","TABLE"].indexOf(n.nodeName)&&"static"===c(n,"position")?m(n):n:e?e.ownerDocument.documentElement:document.documentElement}function g(e){var t=e.nodeName;return"BODY"!==t&&("HTML"===t||m(e.firstElementChild)===e)}function v(e){return null!==e.parentNode?v(e.parentNode):e}function y(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var n=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,r=n?e:t,i=n?t:e,a=document.createRange();a.setStart(r,0),a.setEnd(i,0);var o=a.commonAncestorContainer;if(e!==o&&t!==o||r.contains(i))return g(o)?o:m(o);var s=v(e);return s.host?y(s.host,t):y(e,v(t).host)}function w(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"top",n="top"===t?"scrollTop":"scrollLeft",r=e.nodeName;if("BODY"===r||"HTML"===r){var i=e.ownerDocument.documentElement;return(e.ownerDocument.scrollingElement||i)[n]}return e[n]}function _(e,t){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=w(t,"top"),i=w(t,"left"),a=n?-1:1;return e.top+=r*a,e.bottom+=r*a,e.left+=i*a,e.right+=i*a,e}function E(e,t){var n="x"===t?"Left":"Top",r="Left"===n?"Right":"Bottom";return parseFloat(e["border"+n+"Width"],10)+parseFloat(e["border"+r+"Width"],10)}function S(e,t,n,r){return Math.max(t["offset"+e],t["scroll"+e],n["client"+e],n["offset"+e],n["scroll"+e],b(10)?parseInt(n["offset"+e])+parseInt(r["margin"+("Height"===e?"Top":"Left")])+parseInt(r["margin"+("Height"===e?"Bottom":"Right")]):0)}function k(e){var t=e.body,n=e.documentElement,r=b(10)&&getComputedStyle(n);return{height:S("Height",t,n,r),width:S("Width",t,n,r)}}var x=function(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")},T=function(){function e(e,t){for(var n=0;n2&&void 0!==arguments[2]&&arguments[2],r=b(10),i="HTML"===t.nodeName,a=L(e),o=L(t),s=f(e),u=c(t),l=parseFloat(u.borderTopWidth,10),d=parseFloat(u.borderLeftWidth,10);n&&i&&(o.top=Math.max(o.top,0),o.left=Math.max(o.left,0));var h=A({top:a.top-o.top-l,left:a.left-o.left-d,width:a.width,height:a.height});if(h.marginTop=0,h.marginLeft=0,!r&&i){var p=parseFloat(u.marginTop,10),m=parseFloat(u.marginLeft,10);h.top-=l-p,h.bottom-=l-p,h.left-=d-m,h.right-=d-m,h.marginTop=p,h.marginLeft=m}return(r&&!n?t.contains(s):t===s&&"BODY"!==s.nodeName)&&(h=_(h,t)),h}function I(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=e.ownerDocument.documentElement,r=C(e,n),i=Math.max(n.clientWidth,window.innerWidth||0),a=Math.max(n.clientHeight,window.innerHeight||0),o=t?0:w(n),s=t?0:w(n,"left");return A({top:o-r.top+r.marginTop,left:s-r.left+r.marginLeft,width:i,height:a})}function D(e){var t=e.nodeName;if("BODY"===t||"HTML"===t)return!1;if("fixed"===c(e,"position"))return!0;var n=l(e);return!!n&&D(n)}function N(e){if(!e||!e.parentElement||b())return document.documentElement;for(var t=e.parentElement;t&&"none"===c(t,"transform");)t=t.parentElement;return t||document.documentElement}function P(e,t,n,r){var i=arguments.length>4&&void 0!==arguments[4]&&arguments[4],a={top:0,left:0},o=i?N(e):y(e,d(t));if("viewport"===r)a=I(o,i);else{var s=void 0;"scrollParent"===r?"BODY"===(s=f(l(t))).nodeName&&(s=e.ownerDocument.documentElement):s="window"===r?e.ownerDocument.documentElement:r;var u=C(s,o,i);if("HTML"!==s.nodeName||D(o))a=u;else{var c=k(e.ownerDocument),h=c.height,p=c.width;a.top+=u.top-u.marginTop,a.bottom=h+u.top,a.left+=u.left-u.marginLeft,a.right=p+u.left}}var b="number"==typeof(n=n||0);return a.left+=b?n:n.left||0,a.top+=b?n:n.top||0,a.right-=b?n:n.right||0,a.bottom-=b?n:n.bottom||0,a}function R(e){var t;return e.width*e.height}function j(e,t,n,r,i){var a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;if(-1===e.indexOf("auto"))return e;var o=P(n,r,a,i),s={top:{width:o.width,height:t.top-o.top},right:{width:o.right-t.right,height:o.height},bottom:{width:o.width,height:o.bottom-t.bottom},left:{width:t.left-o.left,height:o.height}},u=Object.keys(s).map(function(e){return O({key:e},s[e],{area:R(s[e])})}).sort(function(e,t){return t.area-e.area}),c=u.filter(function(e){var t=e.width,r=e.height;return t>=n.clientWidth&&r>=n.clientHeight}),l=c.length>0?c[0].key:u[0].key,f=e.split("-")[1];return l+(f?"-"+f:"")}function F(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,i=r?N(t):y(t,d(n));return C(n,i,r)}function Y(e){var t=e.ownerDocument.defaultView.getComputedStyle(e),n=parseFloat(t.marginTop||0)+parseFloat(t.marginBottom||0),r=parseFloat(t.marginLeft||0)+parseFloat(t.marginRight||0);return{width:e.offsetWidth+r,height:e.offsetHeight+n}}function B(e){var t={left:"right",right:"left",bottom:"top",top:"bottom"};return e.replace(/left|right|bottom|top/g,function(e){return t[e]})}function U(e,t,n){n=n.split("-")[0];var r=Y(e),i={width:r.width,height:r.height},a=-1!==["right","left"].indexOf(n),o=a?"top":"left",s=a?"left":"top",u=a?"height":"width",c=a?"width":"height";return i[o]=t[o]+t[u]/2-r[u]/2,n===s?i[s]=t[s]-r[c]:i[s]=t[B(s)],i}function H(e,t){return Array.prototype.find?e.find(t):e.filter(t)[0]}function $(e,t,n){if(Array.prototype.findIndex)return e.findIndex(function(e){return e[t]===n});var r=H(e,function(e){return e[t]===n});return e.indexOf(r)}function z(e,t,n){return(void 0===n?e:e.slice(0,$(e,"name",n))).forEach(function(e){e.function&&console.warn("`modifier.function` is deprecated, use `modifier.fn`!");var n=e.function||e.fn;e.enabled&&u(n)&&(t.offsets.popper=A(t.offsets.popper),t.offsets.reference=A(t.offsets.reference),t=n(t,e))}),t}function G(){if(!this.state.isDestroyed){var e={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};e.offsets.reference=F(this.state,this.popper,this.reference,this.options.positionFixed),e.placement=j(this.options.placement,e.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),e.originalPlacement=e.placement,e.positionFixed=this.options.positionFixed,e.offsets.popper=U(this.popper,e.offsets.reference,e.placement),e.offsets.popper.position=this.options.positionFixed?"fixed":"absolute",e=z(this.modifiers,e),this.state.isCreated?this.options.onUpdate(e):(this.state.isCreated=!0,this.options.onCreate(e))}}function W(e,t){return e.some(function(e){var n=e.name;return e.enabled&&n===t})}function K(e){for(var t=[!1,"ms","Webkit","Moz","O"],n=e.charAt(0).toUpperCase()+e.slice(1),r=0;ro[p]&&(e.offsets.popper[d]+=s[d]+b-o[p]),e.offsets.popper=A(e.offsets.popper);var m=s[d]+s[l]/2-b/2,g=c(e.instance.popper),v=parseFloat(g["margin"+f],10),y=parseFloat(g["border"+f+"Width"],10),w=m-e.offsets.popper[d]-v-y;return w=Math.max(Math.min(o[l]-b,w),0),e.arrowElement=r,e.offsets.arrow=(M(n={},d,Math.round(w)),M(n,h,""),n),e}function ef(e){return"end"===e?"start":"start"===e?"end":e}var ed=["auto-start","auto","auto-end","top-start","top","top-end","right-start","right","right-end","bottom-end","bottom","bottom-start","left-end","left","left-start"],eh=ed.slice(3);function ep(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=eh.indexOf(e),r=eh.slice(n+1).concat(eh.slice(0,n));return t?r.reverse():r}var eb={FLIP:"flip",CLOCKWISE:"clockwise",COUNTERCLOCKWISE:"counterclockwise"};function em(e,t){if(W(e.instance.modifiers,"inner")||e.flipped&&e.placement===e.originalPlacement)return e;var n=P(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),r=e.placement.split("-")[0],i=B(r),a=e.placement.split("-")[1]||"",o=[];switch(t.behavior){case eb.FLIP:o=[r,i];break;case eb.CLOCKWISE:o=ep(r);break;case eb.COUNTERCLOCKWISE:o=ep(r,!0);break;default:o=t.behavior}return o.forEach(function(s,u){if(r!==s||o.length===u+1)return e;i=B(r=e.placement.split("-")[0]);var c=e.offsets.popper,l=e.offsets.reference,f=Math.floor,d="left"===r&&f(c.right)>f(l.left)||"right"===r&&f(c.left)f(l.top)||"bottom"===r&&f(c.top)f(n.right),b=f(c.top)f(n.bottom),g="left"===r&&h||"right"===r&&p||"top"===r&&b||"bottom"===r&&m,v=-1!==["top","bottom"].indexOf(r),y=!!t.flipVariations&&(v&&"start"===a&&h||v&&"end"===a&&p||!v&&"start"===a&&b||!v&&"end"===a&&m),w=!!t.flipVariationsByContent&&(v&&"start"===a&&p||v&&"end"===a&&h||!v&&"start"===a&&m||!v&&"end"===a&&b),_=y||w;(d||g||_)&&(e.flipped=!0,(d||g)&&(r=o[u+1]),_&&(a=ef(a)),e.placement=r+(a?"-"+a:""),e.offsets.popper=O({},e.offsets.popper,U(e.instance.popper,e.offsets.reference,e.placement)),e=z(e.instance.modifiers,e,"flip"))}),e}function eg(e){var t=e.offsets,n=t.popper,r=t.reference,i=e.placement.split("-")[0],a=Math.floor,o=-1!==["top","bottom"].indexOf(i),s=o?"right":"bottom",u=o?"left":"top",c=o?"width":"height";return n[s]a(r[s])&&(e.offsets.popper[u]=a(r[s])),e}function ev(e,t,n,r){var i=e.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),a=+i[1],o=i[2];if(!a)return e;if(0===o.indexOf("%")){var s=void 0;return A(s="%p"===o?n:r)[t]/100*a}if("vh"!==o&&"vw"!==o)return a;var u=void 0;return(u="vh"===o?Math.max(document.documentElement.clientHeight,window.innerHeight||0):Math.max(document.documentElement.clientWidth,window.innerWidth||0))/100*a}function ey(e,t,n,r){var i=[0,0],a=-1!==["right","left"].indexOf(r),o=e.split(/(\+|\-)/).map(function(e){return e.trim()}),s=o.indexOf(H(o,function(e){return -1!==e.search(/,|\s/)}));o[s]&&-1===o[s].indexOf(",")&&console.warn("Offsets separated by white space(s) are deprecated, use a comma (,) instead.");var u=/\s*,\s*|\s+/,c=-1!==s?[o.slice(0,s).concat([o[s].split(u)[0]]),[o[s].split(u)[1]].concat(o.slice(s+1))]:[o];return(c=c.map(function(e,r){var i=(1===r?!a:a)?"height":"width",o=!1;return e.reduce(function(e,t){return""===e[e.length-1]&&-1!==["+","-"].indexOf(t)?(e[e.length-1]=t,o=!0,e):o?(e[e.length-1]+=t,o=!1,e):e.concat(t)},[]).map(function(e){return ev(e,i,t,n)})})).forEach(function(e,t){e.forEach(function(n,r){et(n)&&(i[t]+=n*("-"===e[r-1]?-1:1))})}),i}function ew(e,t){var n=t.offset,r=e.placement,i=e.offsets,a=i.popper,o=i.reference,s=r.split("-")[0],u=void 0;return u=et(+n)?[+n,0]:ey(n,a,o,s),"left"===s?(a.top+=u[0],a.left-=u[1]):"right"===s?(a.top+=u[0],a.left+=u[1]):"top"===s?(a.left+=u[0],a.top-=u[1]):"bottom"===s&&(a.left+=u[0],a.top+=u[1]),e.popper=a,e}function e_(e,t){var n=t.boundariesElement||m(e.instance.popper);e.instance.reference===n&&(n=m(n));var r=K("transform"),i=e.instance.popper.style,a=i.top,o=i.left,s=i[r];i.top="",i.left="",i[r]="";var u=P(e.instance.popper,e.instance.reference,t.padding,n,e.positionFixed);i.top=a,i.left=o,i[r]=s,t.boundaries=u;var c=t.priority,l=e.offsets.popper,f={primary:function(e){var n=l[e];return l[e]u[e]&&!t.escapeWithReference&&(r=Math.min(l[n],u[e]-("right"===e?l.width:l.height))),M({},n,r)}};return c.forEach(function(e){l=O({},l,f[-1!==["left","top"].indexOf(e)?"primary":"secondary"](e))}),e.offsets.popper=l,e}function eE(e){var t=e.placement,n=t.split("-")[0],r=t.split("-")[1];if(r){var i=e.offsets,a=i.reference,o=i.popper,s=-1!==["bottom","top"].indexOf(n),u=s?"left":"top",c=s?"width":"height",l={start:M({},u,a[u]),end:M({},u,a[u]+a[c]-o[c])};e.offsets.popper=O({},o,l[r])}return e}function eS(e){if(!ec(e.instance.modifiers,"hide","preventOverflow"))return e;var t=e.offsets.reference,n=H(e.instance.modifiers,function(e){return"preventOverflow"===e.name}).boundaries;if(t.bottomn.right||t.top>n.bottom||t.right2&&void 0!==arguments[2]?arguments[2]:{};x(this,e),this.scheduleUpdate=function(){return requestAnimationFrame(r.update)},this.update=s(this.update.bind(this)),this.options=O({},e.Defaults,i),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=t&&t.jquery?t[0]:t,this.popper=n&&n.jquery?n[0]:n,this.options.modifiers={},Object.keys(O({},e.Defaults.modifiers,i.modifiers)).forEach(function(t){r.options.modifiers[t]=O({},e.Defaults.modifiers[t]||{},i.modifiers?i.modifiers[t]:{})}),this.modifiers=Object.keys(this.options.modifiers).map(function(e){return O({name:e},r.options.modifiers[e])}).sort(function(e,t){return e.order-t.order}),this.modifiers.forEach(function(e){e.enabled&&u(e.onLoad)&&e.onLoad(r.reference,r.popper,r.options,e,r.state)}),this.update();var a=this.options.eventsEnabled;a&&this.enableEventListeners(),this.state.eventsEnabled=a}return T(e,[{key:"update",value:function(){return G.call(this)}},{key:"destroy",value:function(){return V.call(this)}},{key:"enableEventListeners",value:function(){return J.call(this)}},{key:"disableEventListeners",value:function(){return ee.call(this)}}]),e}();eT.Utils=("undefined"!=typeof window?window:n.g).PopperUtils,eT.placements=ed,eT.Defaults=ex;let eM=eT},92703(e,t,n){"use strict";var r=n(50414);function i(){}function a(){}a.resetWarningCache=i,e.exports=function(){function e(e,t,n,i,a,o){if(o!==r){var s=Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw s.name="Invariant Violation",s}}function t(){return e}e.isRequired=e;var n={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:i};return n.PropTypes=n,n}},45697(e,t,n){e.exports=n(92703)()},50414(e){"use strict";var t="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";e.exports=t},55760(e){"use strict";function t(e){this._maxSize=e,this.clear()}t.prototype.clear=function(){this._size=0,this._values=Object.create(null)},t.prototype.get=function(e){return this._values[e]},t.prototype.set=function(e,t){return this._size>=this._maxSize&&this.clear(),!(e in this._values)&&this._size++,this._values[e]=t};var n=/[^.^\]^[]+|(?=\[\]|\.\.)/g,r=/^\d+$/,i=/^\d/,a=/[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g,o=/^\s*(['"]?)(.*?)(\1)\s*$/,s=512,u=new t(s),c=new t(s),l=new t(s);function f(e){return u.get(e)||u.set(e,d(e).map(function(e){return e.replace(o,"$2")}))}function d(e){return e.match(n)}function h(e,t,n){var r,i,a,o,s=e.length;for(i=0;i4&&n.slice(0,4)===o&&s.test(t)&&("-"===t.charAt(4)?u=f(t):t=d(t),c=i),new c(u,t))}function f(e){var t=e.slice(5).replace(u,p);return o+t.charAt(0).toUpperCase()+t.slice(1)}function d(e){var t=e.slice(4);return u.test(t)?e:("-"!==(t=t.replace(c,h)).charAt(0)&&(t="-"+t),o+t)}function h(e){return"-"+e.toLowerCase()}function p(e){return e.charAt(1).toUpperCase()}},97247(e,t,n){"use strict";var r=n(19940),i=n(8289),a=n(5812),o=n(94397),s=n(67716),u=n(61805);e.exports=r([a,i,o,s,u])},67716(e,t,n){"use strict";var r=n(17e3),i=n(17596),a=r.booleanish,o=r.number,s=r.spaceSeparated;function u(e,t){return"role"===t?t:"aria-"+t.slice(4).toLowerCase()}e.exports=i({transform:u,properties:{ariaActiveDescendant:null,ariaAtomic:a,ariaAutoComplete:null,ariaBusy:a,ariaChecked:a,ariaColCount:o,ariaColIndex:o,ariaColSpan:o,ariaControls:s,ariaCurrent:null,ariaDescribedBy:s,ariaDetails:null,ariaDisabled:a,ariaDropEffect:s,ariaErrorMessage:null,ariaExpanded:a,ariaFlowTo:s,ariaGrabbed:a,ariaHasPopup:null,ariaHidden:a,ariaInvalid:null,ariaKeyShortcuts:null,ariaLabel:null,ariaLabelledBy:s,ariaLevel:o,ariaLive:null,ariaModal:a,ariaMultiLine:a,ariaMultiSelectable:a,ariaOrientation:null,ariaOwns:s,ariaPlaceholder:null,ariaPosInSet:o,ariaPressed:a,ariaReadOnly:a,ariaRelevant:null,ariaRequired:a,ariaRoleDescription:s,ariaRowCount:o,ariaRowIndex:o,ariaRowSpan:o,ariaSelected:a,ariaSetSize:o,ariaSort:null,ariaValueMax:o,ariaValueMin:o,ariaValueNow:o,ariaValueText:null,role:null}})},61805(e,t,n){"use strict";var r=n(17e3),i=n(17596),a=n(10855),o=r.boolean,s=r.overloadedBoolean,u=r.booleanish,c=r.number,l=r.spaceSeparated,f=r.commaSeparated;e.exports=i({space:"html",attributes:{acceptcharset:"accept-charset",classname:"class",htmlfor:"for",httpequiv:"http-equiv"},transform:a,mustUseProperty:["checked","multiple","muted","selected"],properties:{abbr:null,accept:f,acceptCharset:l,accessKey:l,action:null,allow:null,allowFullScreen:o,allowPaymentRequest:o,allowUserMedia:o,alt:null,as:null,async:o,autoCapitalize:null,autoComplete:l,autoFocus:o,autoPlay:o,capture:o,charSet:null,checked:o,cite:null,className:l,cols:c,colSpan:null,content:null,contentEditable:u,controls:o,controlsList:l,coords:c|f,crossOrigin:null,data:null,dateTime:null,decoding:null,default:o,defer:o,dir:null,dirName:null,disabled:o,download:s,draggable:u,encType:null,enterKeyHint:null,form:null,formAction:null,formEncType:null,formMethod:null,formNoValidate:o,formTarget:null,headers:l,height:c,hidden:o,high:c,href:null,hrefLang:null,htmlFor:l,httpEquiv:l,id:null,imageSizes:null,imageSrcSet:f,inputMode:null,integrity:null,is:null,isMap:o,itemId:null,itemProp:l,itemRef:l,itemScope:o,itemType:l,kind:null,label:null,lang:null,language:null,list:null,loading:null,loop:o,low:c,manifest:null,max:null,maxLength:c,media:null,method:null,min:null,minLength:c,multiple:o,muted:o,name:null,nonce:null,noModule:o,noValidate:o,onAbort:null,onAfterPrint:null,onAuxClick:null,onBeforePrint:null,onBeforeUnload:null,onBlur:null,onCancel:null,onCanPlay:null,onCanPlayThrough:null,onChange:null,onClick:null,onClose:null,onContextMenu:null,onCopy:null,onCueChange:null,onCut:null,onDblClick:null,onDrag:null,onDragEnd:null,onDragEnter:null,onDragExit:null,onDragLeave:null,onDragOver:null,onDragStart:null,onDrop:null,onDurationChange:null,onEmptied:null,onEnded:null,onError:null,onFocus:null,onFormData:null,onHashChange:null,onInput:null,onInvalid:null,onKeyDown:null,onKeyPress:null,onKeyUp:null,onLanguageChange:null,onLoad:null,onLoadedData:null,onLoadedMetadata:null,onLoadEnd:null,onLoadStart:null,onMessage:null,onMessageError:null,onMouseDown:null,onMouseEnter:null,onMouseLeave:null,onMouseMove:null,onMouseOut:null,onMouseOver:null,onMouseUp:null,onOffline:null,onOnline:null,onPageHide:null,onPageShow:null,onPaste:null,onPause:null,onPlay:null,onPlaying:null,onPopState:null,onProgress:null,onRateChange:null,onRejectionHandled:null,onReset:null,onResize:null,onScroll:null,onSecurityPolicyViolation:null,onSeeked:null,onSeeking:null,onSelect:null,onSlotChange:null,onStalled:null,onStorage:null,onSubmit:null,onSuspend:null,onTimeUpdate:null,onToggle:null,onUnhandledRejection:null,onUnload:null,onVolumeChange:null,onWaiting:null,onWheel:null,open:o,optimum:c,pattern:null,ping:l,placeholder:null,playsInline:o,poster:null,preload:null,readOnly:o,referrerPolicy:null,rel:l,required:o,reversed:o,rows:c,rowSpan:c,sandbox:l,scope:null,scoped:o,seamless:o,selected:o,shape:null,size:c,sizes:null,slot:null,span:c,spellCheck:u,src:null,srcDoc:null,srcLang:null,srcSet:f,start:c,step:null,style:null,tabIndex:c,target:null,title:null,translate:null,type:null,typeMustMatch:o,useMap:null,value:u,width:c,wrap:null,align:null,aLink:null,archive:l,axis:null,background:null,bgColor:null,border:c,borderColor:null,bottomMargin:c,cellPadding:null,cellSpacing:null,char:null,charOff:null,classId:null,clear:null,code:null,codeBase:null,codeType:null,color:null,compact:o,declare:o,event:null,face:null,frame:null,frameBorder:null,hSpace:c,leftMargin:c,link:null,longDesc:null,lowSrc:null,marginHeight:c,marginWidth:c,noResize:o,noHref:o,noShade:o,noWrap:o,object:null,profile:null,prompt:null,rev:null,rightMargin:c,rules:null,scheme:null,scrolling:u,standby:null,summary:null,text:null,topMargin:c,valueType:null,version:null,vAlign:null,vLink:null,vSpace:c,allowTransparency:null,autoCorrect:null,autoSave:null,disablePictureInPicture:o,disableRemotePlayback:o,prefix:null,property:null,results:c,security:null,unselectable:null}})},10855(e,t,n){"use strict";var r=n(28740);function i(e,t){return r(e,t.toLowerCase())}e.exports=i},28740(e){"use strict";function t(e,t){return t in e?e[t]:t}e.exports=t},17596(e,t,n){"use strict";var r=n(66632),i=n(99607),a=n(81674);function o(e){var t,n,o=e.space,s=e.mustUseProperty||[],u=e.attributes||{},c=e.properties,l=e.transform,f={},d={};for(t in c)n=new a(t,l(u,t),c[t],o),-1!==s.indexOf(t)&&(n.mustUseProperty=!0),f[t]=n,d[r(t)]=t,d[r(n.attribute)]=t;return new i(f,d,o)}e.exports=o},81674(e,t,n){"use strict";var r=n(57643),i=n(17e3);e.exports=s,s.prototype=new r,s.prototype.defined=!0;var a=["boolean","booleanish","overloadedBoolean","number","commaSeparated","spaceSeparated","commaOrSpaceSeparated"],o=a.length;function s(e,t,n,s){var c,l=-1;for(u(this,"space",s),r.call(this,e,t);++l=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function l(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function d(e,t){for(var n=0;n1&&void 0!==arguments[1]&&arguments[1];return n._tick((0,d.updateNodeHighlightedValue)(n.state.nodes,n.state.links,n.state.config,e,t))}),O(S(n),"_tick",function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=arguments.length>1?arguments[1]:void 0;return t?n.setState(e,t):n.setState(e)}),O(S(n),"_zoomConfig",function(){var e=(0,o.select)("#".concat(n.state.id,"-").concat(u.default.GRAPH_WRAPPER_ID)),t=(0,s.zoom)().scaleExtent([n.state.config.minZoom,n.state.config.maxZoom]);n.state.config.freezeAllDragEvents||t.on("zoom",n._zoomed),null!==n.state.config.initialZoom&&t.scaleTo(e,n.state.config.initialZoom),e.call(t).on("dblclick.zoom",null)}),O(S(n),"_zoomed",function(){var e=o.event.transform;(0,o.selectAll)("#".concat(n.state.id,"-").concat(u.default.GRAPH_CONTAINER_ID)).attr("transform",e),n.state.config.panAndZoom&&n.setState({transform:e.k}),n.debouncedOnZoomChange&&n.state.previousZoom!==e.k&&(n.debouncedOnZoomChange(n.state.previousZoom,e.k),n.setState({previousZoom:e.k}))}),O(S(n),"onClickGraph",function(e){n.state.enableFocusAnimation&&n.setState({enableFocusAnimation:!1});var t,r,i,a=e.target&&e.target.tagName,o=null==e?void 0:null===(t=e.target)||void 0===t?void 0:null===(r=t.attributes)||void 0===r?void 0:null===(i=r.name)||void 0===i?void 0:i.value,s="svg-container-".concat(n.state.id);"SVG"===a.toUpperCase()&&o===s&&n.props.onClickGraph&&n.props.onClickGraph(e)}),O(S(n),"onClickNode",function(e){var t=n.state.nodes[e];if(n.state.config.collapsible){var r=(0,f.getTargetLeafConnections)(e,n.state.links,n.state.config),i=(0,f.toggleLinksMatrixConnections)(n.state.links,r,n.state.config),a=(0,f.toggleLinksConnections)(n.state.d3Links,i),o=null==r?void 0:r["0"],s=!1;o&&(s=1===i[o.source][o.target]),n._tick({links:i,d3Links:a},function(){n.props.onClickNode&&n.props.onClickNode(e,t),s&&n._graphNodeDragConfig()})}else n.nodeClickTimer?(n.props.onDoubleClickNode&&n.props.onDoubleClickNode(e,t),n.nodeClickTimer=clearTimeout(n.nodeClickTimer)):n.nodeClickTimer=setTimeout(function(){n.props.onClickNode&&n.props.onClickNode(e,t),n.nodeClickTimer=null},u.default.TTL_DOUBLE_CLICK_IN_MS)}),O(S(n),"onRightClickNode",function(e,t){var r=n.state.nodes[t];n.props.onRightClickNode&&n.props.onRightClickNode(e,t,r)}),O(S(n),"onMouseOverNode",function(e){if(!n.isDraggingNode){var t=n.state.nodes[e];n.props.onMouseOverNode&&n.props.onMouseOverNode(e,t),n.state.config.nodeHighlightBehavior&&n._setNodeHighlightedValue(e,!0)}}),O(S(n),"onMouseOutNode",function(e){if(!n.isDraggingNode){var t=n.state.nodes[e];n.props.onMouseOutNode&&n.props.onMouseOutNode(e,t),n.state.config.nodeHighlightBehavior&&n._setNodeHighlightedValue(e,!1)}}),O(S(n),"onMouseOverLink",function(e,t){if(n.props.onMouseOverLink&&n.props.onMouseOverLink(e,t),n.state.config.linkHighlightBehavior){var r={source:e,target:t};n._tick({highlightedLink:r})}}),O(S(n),"onMouseOutLink",function(e,t){if(n.props.onMouseOutLink&&n.props.onMouseOutLink(e,t),n.state.config.linkHighlightBehavior){var r=void 0;n._tick({highlightedLink:r})}}),O(S(n),"onNodePositionChange",function(e){if(n.props.onNodePositionChange){var t=e.id,r=e.x,i=e.y;n.props.onNodePositionChange(t,r,i)}}),O(S(n),"pauseSimulation",function(){return n.state.simulation.stop()}),O(S(n),"resetNodesPositions",function(){if(!n.state.config.staticGraph){var e=(0,d.initializeNodes)(n.props.data.nodes);for(var t in n.state.nodes){var r=n.state.nodes[t];if(r.fx&&r.fy&&(Reflect.deleteProperty(r,"fx"),Reflect.deleteProperty(r,"fy")),t in e){var i=e[t];r.x=i.x,r.y=i.y}}n.state.simulation.alphaTarget(n.state.config.d3.alphaTarget).restart(),n._tick()}}),O(S(n),"restartSimulation",function(){return!n.state.config.staticGraph&&n.state.simulation.restart()}),n.props.id||(0,p.throwErr)(n.constructor.name,l.default.GRAPH_NO_ID_PROP),n.focusAnimationTimeout=null,n.nodeClickTimer=null,n.isDraggingNode=!1,n.state=(0,d.initializeGraphState)(n.props,n.state),n.debouncedOnZoomChange=n.props.onZoomChange?(0,p.debounce)(n.props.onZoomChange,100):null,n}return T(t,e),x(t,[{key:"_graphLinkForceConfig",value:function(){var e=(0,a.forceLink)(this.state.d3Links).id(function(e){return e.id}).distance(this.state.config.d3.linkLength).strength(this.state.config.d3.linkStrength);this.state.simulation.force(u.default.LINK_CLASS_NAME,e)}},{key:"_graphNodeDragConfig",value:function(){var e=(0,i.drag)().on("start",this._onDragStart).on("drag",this._onDragMove).on("end",this._onDragEnd);(0,o.select)("#".concat(this.state.id,"-").concat(u.default.GRAPH_WRAPPER_ID)).selectAll(".node").call(e)}},{key:"_graphBindD3ToReactComponent",value:function(){this.state.config.d3.disableLinkForce||(this.state.simulation.nodes(this.state.d3Nodes).on("tick",this._tick),this._graphLinkForceConfig()),this.state.config.freezeAllDragEvents||this._graphNodeDragConfig()}}]),x(t,[{key:"UNSAFE_componentWillReceiveProps",value:function(e){var t=(0,d.checkForGraphElementsChanges)(e,this.state),n=t.graphElementsUpdated,r=t.newGraphElements,i=n?(0,d.initializeGraphState)(e,this.state):this.state,a=e.config||{},o=(0,d.checkForGraphConfigChanges)(e,this.state),s=o.configUpdated,l=o.d3ConfigUpdated,f=s?(0,p.merge)(c.default,a):this.state.config;r&&this.pauseSimulation();var h=a.panAndZoom!==this.state.config.panAndZoom?1:this.state.transform,b=e.data.focusedNodeId,m=this.state.d3Nodes.find(function(e){return"".concat(e.id)==="".concat(b)}),g="".concat(this.state.id,"-").concat(u.default.GRAPH_WRAPPER_ID),v=(0,d.getCenterAndZoomTransformation)(m,this.state.config,g)||this.state.focusTransformation,w=this.props.data.focusedNodeId!==e.data.focusedNodeId;e.onZoomChange&&(this.debouncedOnZoomChange=(0,p.debounce)(e.onZoomChange,100)),this.setState(y({},i,{config:f,configUpdated:s,d3ConfigUpdated:l,newGraphElements:r,transform:h,focusedNodeId:b,enableFocusAnimation:w,focusTransformation:v}))}},{key:"componentDidUpdate",value:function(){(this.state.config.staticGraph||this.state.config.staticGraphWithDragAndDrop)&&this.pauseSimulation(),!this.state.config.staticGraph&&(this.state.newGraphElements||this.state.d3ConfigUpdated)?(this._graphBindD3ToReactComponent(),this.state.config.staticGraphWithDragAndDrop||this.restartSimulation(),this.setState({newGraphElements:!1,d3ConfigUpdated:!1})):this.state.configUpdated&&this._graphNodeDragConfig(),this.state.configUpdated&&(this._zoomConfig(),this.setState({configUpdated:!1}))}},{key:"componentDidMount",value:function(){this.state.config.staticGraph||this._graphBindD3ToReactComponent(),this._zoomConfig()}},{key:"componentWillUnmount",value:function(){this.pauseSimulation(),this.nodeClickTimer&&(clearTimeout(this.nodeClickTimer),this.nodeClickTimer=null),this.focusAnimationTimeout&&(clearTimeout(this.focusAnimationTimeout),this.focusAnimationTimeout=null)}},{key:"render",value:function(){var e=(0,h.renderGraph)(this.state.nodes,{onClickNode:this.onClickNode,onDoubleClickNode:this.onDoubleClickNode,onRightClickNode:this.onRightClickNode,onMouseOverNode:this.onMouseOverNode,onMouseOut:this.onMouseOutNode},this.state.d3Links,this.state.links,{onClickLink:this.props.onClickLink,onRightClickLink:this.props.onRightClickLink,onMouseOverLink:this.onMouseOverLink,onMouseOutLink:this.onMouseOutLink},this.state.config,this.state.highlightedNode,this.state.highlightedLink,this.state.transform),t=e.nodes,n=e.links,i=e.defs,a={height:this.state.config.height,width:this.state.config.width},o=this._generateFocusAnimationProps();return r.default.createElement("div",{id:"".concat(this.state.id,"-").concat(u.default.GRAPH_WRAPPER_ID)},r.default.createElement("svg",{name:"svg-container-".concat(this.state.id),style:a,onClick:this.onClickGraph},i,r.default.createElement("g",g({id:"".concat(this.state.id,"-").concat(u.default.GRAPH_CONTAINER_ID)},o),n,t)))}}]),t}(r.default.Component);t.default=A},37973(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.computeNodeDegree=l,t.getTargetLeafConnections=f,t.isNodeVisible=d,t.toggleLinksConnections=h,t.toggleLinksMatrixConnections=p;var r=n(52694);function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function a(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(t).reduce(function(n,r){return t[r]?Object.keys(t[r]).reduce(function(n,i){return e===r&&(n.outDegree+=t[e][i]),e===i&&(n.inDegree+=t[r][e]),n},n):n},{inDegree:0,outDegree:0})}function f(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,r=n.directed;return(t[e]?Object.keys(t[e]):[]).reduce(function(n,i){return c(i,t,r)&&n.push({source:e,target:i}),n},[])}function d(e,t,n){if(!t[e])return!1;if(t[e]._orphan)return!0;var r=l(e,n),i=r.inDegree,a=r.outDegree;return i>0||a>0}function h(e,t){return e.map(function(e){var n=e.source,i=e.target,o=(0,r.getId)(n),s=(0,r.getId)(i);return a({},e,{isHidden:!(t&&t[o]&&t[o][s])})})}function p(e,t,n){var r=n.directed;return t.reduce(function(e,t){e[t.source]||(e[t.source]={}),e[t.source][t.target]||(e[t.source][t.target]=0);var n=0===e[t.source][t.target]?1:0;return e[t.source][t.target]=n,r||(e[t.target][t.source]=n),e},a({},e))}n(69901)},99182(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.buildLinkProps=h,t.buildNodeProps=p;var r=s(n(53880)),i=n(37109),a=n(80362),o=n(52694);function s(e){return e&&e.__esModule?e:{default:e}}function u(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function c(e){for(var t=1;t2&&void 0!==arguments[2]?arguments[2]:{},i=arguments.length>3?arguments[3]:void 0,a=arguments.length>4?arguments[4]:void 0,o=arguments.length>5?arguments[5]:void 0,s=e.highlighted||e.id===(a&&a.source)||e.id===(a&&a.target),u=d(e,i,a,t),l=e.color||t.node.color;s&&t.node.highlightColor!==r.default.KEYWORDS.SAME&&(l=t.node.highlightColor);var h=e.strokeColor||t.node.strokeColor;s&&t.node.highlightStrokeColor!==r.default.KEYWORDS.SAME&&(h=t.node.highlightStrokeColor);var p=e[t.node.labelProperty]||e.id;"function"==typeof t.node.labelProperty&&(p=t.node.labelProperty(e));var b=e.labelPosition||t.node.labelPosition,m=e.strokeWidth||t.node.strokeWidth;s&&t.node.highlightStrokeWidth!==r.default.KEYWORDS.SAME&&(m=t.node.highlightStrokeWidth);var g=1/o,v=e.size||t.node.size,y="object"!==f(v),w=0;y?w=v:"top"===b||"bottom"===b?w=v.height:("right"===b||"left"===b)&&(w=v.width);var _=e.fontSize||t.node.fontSize,E=e.highlightFontSize||t.node.highlightFontSize,S=s?E:_,k=S*g+w/100+1.5,x=e.svg||t.node.svg,T=e.fontColor||t.node.fontColor,M=t.node.renderLabel;return void 0!==e.renderLabel&&"boolean"==typeof e.renderLabel&&(M=e.renderLabel),c({},e,{className:r.default.NODE_CLASS_NAME,cursor:t.node.mouseCursor,cx:(null==e?void 0:e.x)||"0",cy:(null==e?void 0:e.y)||"0",dx:k,fill:l,fontColor:T,fontSize:S*g,fontWeight:s?t.node.highlightFontWeight:t.node.fontWeight,id:e.id,label:p,labelPosition:b,opacity:u,overrideGlobalViewGenerator:!e.viewGenerator&&e.svg,renderLabel:M,size:y?v*g:{height:v.height*g,width:v.width*g},stroke:h,strokeWidth:m*g,svg:x,type:e.symbolType||t.node.symbolType,viewGenerator:e.viewGenerator||t.node.viewGenerator,onClickNode:n.onClickNode,onMouseOut:n.onMouseOut,onMouseOverNode:n.onMouseOverNode,onRightClickNode:n.onRightClickNode})}},98510(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={automaticRearrangeAfterDropNode:!1,collapsible:!1,directed:!1,focusAnimationDuration:.75,focusZoom:1,freezeAllDragEvents:!1,height:400,highlightDegree:1,highlightOpacity:1,linkHighlightBehavior:!1,maxZoom:8,minZoom:.1,initialZoom:null,nodeHighlightBehavior:!1,panAndZoom:!1,staticGraph:!1,staticGraphWithDragAndDrop:!1,width:800,d3:{alphaTarget:.05,gravity:-100,linkLength:100,linkStrength:1,disableLinkForce:!1},node:{color:"#d3d3d3",fontColor:"black",fontSize:8,fontWeight:"normal",highlightColor:"SAME",highlightFontSize:8,highlightFontWeight:"normal",highlightStrokeColor:"SAME",highlightStrokeWidth:"SAME",labelProperty:"id",labelPosition:null,mouseCursor:"pointer",opacity:1,renderLabel:!0,size:200,strokeColor:"none",strokeWidth:1.5,svg:"",symbolType:"circle",viewGenerator:null},link:{color:"#d3d3d3",fontColor:"black",fontSize:8,fontWeight:"normal",highlightColor:"SAME",highlightFontSize:8,highlightFontWeight:"normal",labelProperty:"label",mouseCursor:"pointer",opacity:1,renderLabel:!1,semanticStrokeWidth:!1,strokeWidth:1.5,markerHeight:6,markerWidth:6,type:"STRAIGHT",strokeDasharray:0,strokeDashoffset:0,strokeLinecap:"butt"}};t.default=n},53880(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=i(n(11041));function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function o(e){for(var t=1;t2&&void 0!==arguments[2]?arguments[2]:[],r=arguments.length>3?arguments[3]:void 0,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},a=n.find(function(t){return t.source.id===e.source&&t.target.id===e.target}),o=a&&(0,c.pick)(a,m),s=(0,c.antiPick)(e,["source","target"]);if(o){var u=i.config&&Object.prototype.hasOwnProperty.call(i.config,"directed")&&r.directed!==i.config.directed,l=h({index:t},o,{},s);return u?h({},l,{isHidden:!1}):r.collapsible?l:h({},l,{isHidden:!1})}var f=!1,d={id:e.source,highlighted:f},p={id:e.target,highlighted:f};return h({index:t,source:d,target:p},s)}function _(e,t){return Object.keys(e).reduce(function(n,r){var i=(0,l.computeNodeDegree)(r,t),a=i.inDegree,o=i.outDegree,s=e[r],u=0===a&&0===o?h({},s,{_orphan:!0}):s;return n[r]=u,n},{})}function E(e){e.nodes&&e.nodes.length||((0,c.logWarning)("Graph",u.default.INSUFFICIENT_DATA),e.nodes=[]),e.links||((0,c.logWarning)("Graph",u.default.INSUFFICIENT_LINKS),e.links=[]);for(var t=e.links.length,n=function(t){var n=e.links[t];e.nodes.find(function(e){return e.id===n.source})||(0,c.throwErr)("Graph","".concat(u.default.INVALID_LINKS,' - "').concat(n.source,'" is not a valid source node id')),e.nodes.find(function(e){return e.id===n.target})||(0,c.throwErr)("Graph","".concat(u.default.INVALID_LINKS,' - "').concat(n.target,'" is not a valid target node id')),n&&void 0!==n.value&&"number"!=typeof n.value&&(0,c.throwErr)("Graph","".concat(u.default.INVALID_LINK_VALUE,' - found in link with source "').concat(n.source,'" and target "').concat(n.target,'"'))},r=0;rx?o.focusZoom=x:T4&&void 0!==arguments[4]&&arguments[4],a=i?r:"",o=h({},e[r],{highlighted:i}),s=h({},e,p({},r,o));return t[r]&&0!==n.highlightDegree&&(s=Object.keys(t[r]).reduce(function(e,t){var n=h({},s[t],{highlighted:i});return e[t]=n,e},s)),{nodes:s,highlightedNode:a}}function I(e){var t=Math.sqrt(Math.pow(e.x,2)+Math.pow(e.y,2));return 0===t?e:{x:e.x/t,y:e.y/t}}var D=new Set([o.default.SYMBOLS.CIRCLE]);function N(e,t,n,r){var i=e.sourceId,a=e.targetId,s=e.sourceCoords,u=void 0===s?{}:s,c=e.targetCoords,l=void 0===c?{}:c,f=null==t?void 0:t[i],d=null==t?void 0:t[a];if(!f||!d||(null===(_=n.node)||void 0===_?void 0:_.viewGenerator)||(null==f?void 0:f.viewGenerator)||(null==d?void 0:d.viewGenerator))return{sourceCoords:u,targetCoords:l};var h=f.symbolType||(null===(E=n.node)||void 0===E?void 0:E.symbolType),p=d.symbolType||(null===(S=n.node)||void 0===S?void 0:S.symbolType);if(!D.has(h)&&!D.has(p))return{sourceCoords:u,targetCoords:l};var b=u.x,m=u.y,g=l.x,v=l.y,y=I({x:g-b,y:v-m});if(h===o.default.SYMBOLS.CIRCLE){var w=(null==f?void 0:f.size)||n.node.size;b+=(w=.95*Math.sqrt(w/Math.PI))*y.x,m+=w*y.y}if(p===o.default.SYMBOLS.CIRCLE){var _,E,S,k,x,T=r*Math.min((null===(k=n.link)||void 0===k?void 0:k.markerWidth)||0,(null===(x=n.link)||void 0===x?void 0:x.markerHeight)||0),M=(null==d?void 0:d.size)||n.node.size;g-=((M=.95*Math.sqrt(M/Math.PI))+(n.directed?T:0))*y.x,v-=(M+(n.directed?T:0))*y.y}return{sourceCoords:{x:b,y:m},targetCoords:{x:g,y:v}}}},75791(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.renderGraph=E;var r=h(n(67294)),i=h(n(53880)),a=n(7619),o=h(n(33938)),s=h(n(61740)),u=h(n(28017)),c=n(99182),l=n(52694),f=n(37973),d=n(80362);function h(e){return e&&e.__esModule?e:{default:e}}function p(){return(p=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{},t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:i.LINE_TYPES.STRAIGHT,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[],o=e.x,s=e.y,u=p(i.LINE_TYPES[n]||i.LINE_TYPES.STRAIGHT),c=[].concat(a(r),[t]),l=c.map(function(t,n){var r,i=t.x,a=t.y,o=n>0?c[n-1]:e,s=u(o.x,o.y,i,a);return" A".concat(s,",").concat(s," 0 0,1 ").concat(i,",").concat(a)}).join("");return"M".concat(o,",").concat(s).concat(l)}},28017(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=i(n(67294));function i(e){return e&&e.__esModule?e:{default:e}}function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function o(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function s(e,t){for(var n=0;n=t&&e0&&void 0!==arguments[0]?arguments[0]:i.default.DEFAULT_NODE_SIZE,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:i.default.SYMBOLS.CIRCLE;return(0,r.symbol)().size(function(){return e}).type(function(){return o(t)})()}function u(e,t){switch(t){case"right":return{dx:e?"".concat(e):i.default.NODE_LABEL_DX,dy:"0",dominantBaseline:"middle",textAnchor:"start"};case"left":return{dx:e?"".concat(-e):"-".concat(i.default.NODE_LABEL_DX),dy:"0",dominantBaseline:"middle",textAnchor:"end"};case"top":return{dx:"0",dy:e?"".concat(-e):"-".concat(i.default.NODE_LABEL_DX),dominantBaseline:"baseline",textAnchor:"middle"};case"bottom":return{dx:"0",dy:e?"".concat(e):i.default.NODE_LABEL_DX,dominantBaseline:"hanging",textAnchor:"middle"};case"center":return{dx:"0",dy:"0",dominantBaseline:"middle",textAnchor:"middle"};default:return{dx:e?"".concat(e):i.default.NODE_LABEL_DX,dy:i.default.NODE_LABEL_DY}}}var c={buildSvgSymbol:s,getLabelPlacementProps:u};t.default=c},11041(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={SYMBOLS:{CIRCLE:"circle",CROSS:"cross",DIAMOND:"diamond",SQUARE:"square",STAR:"star",TRIANGLE:"triangle",WYE:"wye"}};t.default=n},34214(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={GRAPH_NO_ID_PROP:"id prop not defined! id property is mandatory and it should be unique.",INSUFFICIENT_LINKS:"you are passing invalid data to react-d3-graph. You must include a links array, even if empty, in the data object you're passing down to the component.",INVALID_LINKS:"you provided a invalid links data structure. Links source and target attributes must point to an existent node",INSUFFICIENT_DATA:"you have not provided enough data for react-d3-graph to render something. You need to provide at least one node",INVALID_LINK_VALUE:"links 'value' attribute must be of type number"};t.default=n},94164(e,t,n){"use strict";r={value:!0},Object.defineProperty(t,"kJ",{enumerable:!0,get:function(){return i.default}}),r={enumerable:!0,get:function(){return a.default}},r={enumerable:!0,get:function(){return o.default}};var r,i=s(n(82623)),a=s(n(61740)),o=s(n(33938));function s(e){return e&&e.__esModule?e:{default:e}}},69901(e,t){"use strict";function n(e){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.isDeepEqual=a,t.isEmptyObject=o,t.deepClone=s,t.merge=u,t.pick=c,t.antiPick=l,t.debounce=f,t.throwErr=h,t.logError=p,t.logWarning=b;var r=20;function i(e,t){return!!e&&Object.prototype.hasOwnProperty.call(e,t)&&"object"===n(e[t])&&null!==e[t]&&!o(e[t])}function a(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,s=[];if(0===n&&e===t)return!0;if(o(e)&&!o(t)||!o(e)&&o(t))return!1;var u=Object.keys(e),c=Object.keys(t);if(u.length!==c.length)return!1;for(var l=0,f=u;l1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,a=Object.keys(e),o=0,u=a;o0&&void 0!==arguments[0]?arguments[0]:{},t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,a={};if(0===Object.keys(e||{}).length)return t&&!o(t)?t:{};for(var s=0,c=Object.keys(e);s1&&void 0!==arguments[1]?arguments[1]:[];return t.reduce(function(t,n){return Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]),t},{})}function l(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=Object.keys(e).filter(function(e){return!t.includes(e)});return c(e,n)}function f(e,t){var n;return function(){for(var r=arguments.length,i=Array(r),a=0;a0&&void 0!==arguments[0]?arguments[0]:"N/A",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"N/A";return"react-d3-graph :: ".concat(e," :: ").concat(t)}function h(e,t){throw Error(d(e,t))}function p(e,t){console.error(d(e,t))}function b(e,t){var n="react-d3-graph :: ".concat(e," :: ").concat(t);console.warn(n)}},64448(e,t,n){"use strict";/** @license React v16.12.0 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ var r,i,a,o,s,u=n(67294),c=n(27418),l=n(63840);function f(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;nt}return!1}function eM(e,t,n,r,i,a){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=i,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a}var eO={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){eO[e]=new eM(e,0,!1,e,null,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];eO[t]=new eM(t,1,!1,e[1],null,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){eO[e]=new eM(e,2,!1,e.toLowerCase(),null,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){eO[e]=new eM(e,2,!1,e,null,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){eO[e]=new eM(e,3,!1,e.toLowerCase(),null,!1)}),["checked","multiple","muted","selected"].forEach(function(e){eO[e]=new eM(e,3,!0,e,null,!1)}),["capture","download"].forEach(function(e){eO[e]=new eM(e,4,!1,e,null,!1)}),["cols","rows","size","span"].forEach(function(e){eO[e]=new eM(e,6,!1,e,null,!1)}),["rowSpan","start"].forEach(function(e){eO[e]=new eM(e,5,!1,e.toLowerCase(),null,!1)});var eA=/[\-:]([a-z])/g;function eL(e){return e[1].toUpperCase()}function eC(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function eI(e,t,n,r){var i=eO.hasOwnProperty(t)?eO[t]:null;(null!==i?0===i.type:!r&&2=t.length))throw Error(f(93));t=t[0]}n=t}null==n&&(n="")}e._wrapperState={initialValue:eC(n)}}function eV(e,t){var n=eC(t.value),r=eC(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function eq(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(eA,eL);eO[t]=new eM(t,1,!1,e,null,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(eA,eL);eO[t]=new eM(t,1,!1,e,"http://www.w3.org/1999/xlink",!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(eA,eL);eO[t]=new eM(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1)}),["tabIndex","crossOrigin"].forEach(function(e){eO[e]=new eM(e,1,!1,e.toLowerCase(),null,!1)}),eO.xlinkHref=new eM("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0),["src","href","action","formAction"].forEach(function(e){eO[e]=new eM(e,1,!1,e.toLowerCase(),null,!0)});var eZ={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};function eX(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function eJ(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?eX(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var eQ,e1,e0=(eQ=function(e,t){if(e.namespaceURI!==eZ.svg||"innerHTML"in e)e.innerHTML=t;else{for((e1=e1||document.createElement("div")).innerHTML=""+t.valueOf().toString()+"",t=e1.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction(function(){return eQ(e,t,n,r)})}:eQ);function e2(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType){n.nodeValue=t;return}}e.textContent=t}function e3(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var e4={animationend:e3("Animation","AnimationEnd"),animationiteration:e3("Animation","AnimationIteration"),animationstart:e3("Animation","AnimationStart"),transitionend:e3("Transition","TransitionEnd")},e5={},e6={};function e9(e){if(e5[e])return e5[e];if(!e4[e])return e;var t,n=e4[e];for(t in n)if(n.hasOwnProperty(t)&&t in e6)return e5[e]=n[t];return e}eo&&(e6=document.createElement("div").style,"AnimationEvent"in window||(delete e4.animationend.animation,delete e4.animationiteration.animation,delete e4.animationstart.animation),"TransitionEvent"in window||delete e4.transitionend.transition);var e8=e9("animationend"),e7=e9("animationiteration"),te=e9("animationstart"),tt=e9("transitionend"),tn="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" ");function tr(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do 0!=(1026&(t=e).effectTag)&&(n=t.return),e=t.return;while(e)}return 3===t.tag?n:null}function ti(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&null!==(e=e.alternate)&&(t=e.memoizedState),null!==t)return t.dehydrated}return null}function ta(e){if(tr(e)!==e)throw Error(f(188))}function to(e){var t=e.alternate;if(!t){if(null===(t=tr(e)))throw Error(f(188));return t!==e?null:e}for(var n=e,r=t;;){var i=n.return;if(null===i)break;var a=i.alternate;if(null===a){if(null!==(r=i.return)){n=r;continue}break}if(i.child===a.child){for(a=i.child;a;){if(a===n)return ta(i),e;if(a===r)return ta(i),t;a=a.sibling}throw Error(f(188))}if(n.return!==r.return)n=i,r=a;else{for(var o=!1,s=i.child;s;){if(s===n){o=!0,n=i,r=a;break}if(s===r){o=!0,r=i,n=a;break}s=s.sibling}if(!o){for(s=a.child;s;){if(s===n){o=!0,n=a,r=i;break}if(s===r){o=!0,r=a,n=i;break}s=s.sibling}if(!o)throw Error(f(189))}}if(n.alternate!==r)throw Error(f(190))}if(3!==n.tag)throw Error(f(188));return n.stateNode.current===n?e:t}function ts(e){if(!(e=to(e)))return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}var tu,tc,tl,tf=!1,td=[],th=null,tp=null,tb=null,tm=new Map,tg=new Map,tv=[],ty="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput close cancel copy cut paste click change contextmenu reset submit".split(" "),tw="focus blur dragenter dragleave mouseover mouseout pointerover pointerout gotpointercapture lostpointercapture".split(" ");function t_(e){var t=nA(e);ty.forEach(function(n){nL(n,e,t)}),tw.forEach(function(n){nL(n,e,t)})}function tE(e,t,n,r){return{blockedOn:e,topLevelType:t,eventSystemFlags:32|n,nativeEvent:r}}function tS(e,t){switch(e){case"focus":case"blur":th=null;break;case"dragenter":case"dragleave":tp=null;break;case"mouseover":case"mouseout":tb=null;break;case"pointerover":case"pointerout":tm.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":tg.delete(t.pointerId)}}function tk(e,t,n,r,i){return null===e||e.nativeEvent!==i?(e=tE(t,n,r,i),null!==t&&null!==(t=n7(t))&&tc(t),e):(e.eventSystemFlags|=r,e)}function tx(e,t,n,r){switch(t){case"focus":return th=tk(th,e,t,n,r),!0;case"dragenter":return tp=tk(tp,e,t,n,r),!0;case"mouseover":return tb=tk(tb,e,t,n,r),!0;case"pointerover":var i=r.pointerId;return tm.set(i,tk(tm.get(i)||null,e,t,n,r)),!0;case"gotpointercapture":return i=r.pointerId,tg.set(i,tk(tg.get(i)||null,e,t,n,r)),!0}return!1}function tT(e){var t=n8(e.target);if(null!==t){var n=tr(t);if(null!==n){if(13===(t=n.tag)){if(null!==(t=ti(n))){e.blockedOn=t,l.unstable_runWithPriority(e.priority,function(){tl(n)});return}}else if(3===t&&n.stateNode.hydrate){e.blockedOn=3===n.tag?n.stateNode.containerInfo:null;return}}}e.blockedOn=null}function tM(e){if(null!==e.blockedOn)return!1;var t=nT(e.topLevelType,e.eventSystemFlags,e.nativeEvent);if(null!==t){var n=n7(t);return null!==n&&tc(n),e.blockedOn=t,!1}return!0}function tO(e,t,n){tM(e)&&n.delete(t)}function tA(){for(tf=!1;0this.eventPool.length&&this.eventPool.push(e)}function tz(e){e.eventPool=[],e.getPooled=tH,e.release=t$}c(tU.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=tY)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=tY)},persist:function(){this.isPersistent=tY},isPersistent:tB,destructor:function(){var e,t=this.constructor.Interface;for(e in t)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=tB,this._dispatchInstances=this._dispatchListeners=null}}),tU.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},tU.extend=function(e){function t(){}function n(){return r.apply(this,arguments)}var r=this;t.prototype=r.prototype;var i=new t;return c(i,n.prototype),n.prototype=i,n.prototype.constructor=n,n.Interface=c({},r.Interface,e),n.extend=r.extend,tz(n),n},tz(tU);var tG=tU.extend({animationName:null,elapsedTime:null,pseudoElement:null}),tW=tU.extend({clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),tK=tU.extend({view:null,detail:null}),tV=tK.extend({relatedTarget:null});function tq(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}var tZ={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},tX={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},tJ={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function tQ(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=tJ[e])&&!!t[e]}function t1(){return tQ}for(var t0=tK.extend({key:function(e){if(e.key){var t=tZ[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=tq(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?tX[e.keyCode]||"Unidentified":""},location:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,repeat:null,locale:null,getModifierState:t1,charCode:function(e){return"keypress"===e.type?tq(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?tq(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),t2=0,t3=0,t4=!1,t5=!1,t6=tK.extend({screenX:null,screenY:null,clientX:null,clientY:null,pageX:null,pageY:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,getModifierState:t1,button:null,buttons:null,relatedTarget:function(e){return e.relatedTarget||(e.fromElement===e.srcElement?e.toElement:e.fromElement)},movementX:function(e){if(("movementX"in e))return e.movementX;var t=t2;return t2=e.screenX,t4?"mousemove"===e.type?e.screenX-t:0:(t4=!0,0)},movementY:function(e){if(("movementY"in e))return e.movementY;var t=t3;return t3=e.screenY,t5?"mousemove"===e.type?e.screenY-t:0:(t5=!0,0)}}),t9=t6.extend({pointerId:null,width:null,height:null,pressure:null,tangentialPressure:null,tiltX:null,tiltY:null,twist:null,pointerType:null,isPrimary:null}),t8=t6.extend({dataTransfer:null}),t7=tK.extend({touches:null,targetTouches:null,changedTouches:null,altKey:null,metaKey:null,ctrlKey:null,shiftKey:null,getModifierState:t1}),ne=tU.extend({propertyName:null,elapsedTime:null,pseudoElement:null}),nt=t6.extend({deltaX:function(e){return("deltaX"in e)?e.deltaX:("wheelDeltaX"in e)?-e.wheelDeltaX:0},deltaY:function(e){return("deltaY"in e)?e.deltaY:("wheelDeltaY"in e)?-e.wheelDeltaY:("wheelDelta"in e)?-e.wheelDelta:0},deltaZ:null,deltaMode:null}),nn=[["blur","blur",0],["cancel","cancel",0],["click","click",0],["close","close",0],["contextmenu","contextMenu",0],["copy","copy",0],["cut","cut",0],["auxclick","auxClick",0],["dblclick","doubleClick",0],["dragend","dragEnd",0],["dragstart","dragStart",0],["drop","drop",0],["focus","focus",0],["input","input",0],["invalid","invalid",0],["keydown","keyDown",0],["keypress","keyPress",0],["keyup","keyUp",0],["mousedown","mouseDown",0],["mouseup","mouseUp",0],["paste","paste",0],["pause","pause",0],["play","play",0],["pointercancel","pointerCancel",0],["pointerdown","pointerDown",0],["pointerup","pointerUp",0],["ratechange","rateChange",0],["reset","reset",0],["seeked","seeked",0],["submit","submit",0],["touchcancel","touchCancel",0],["touchend","touchEnd",0],["touchstart","touchStart",0],["volumechange","volumeChange",0],["drag","drag",1],["dragenter","dragEnter",1],["dragexit","dragExit",1],["dragleave","dragLeave",1],["dragover","dragOver",1],["mousemove","mouseMove",1],["mouseout","mouseOut",1],["mouseover","mouseOver",1],["pointermove","pointerMove",1],["pointerout","pointerOut",1],["pointerover","pointerOver",1],["scroll","scroll",1],["toggle","toggle",1],["touchmove","touchMove",1],["wheel","wheel",1],["abort","abort",2],[e8,"animationEnd",2],[e7,"animationIteration",2],[te,"animationStart",2],["canplay","canPlay",2],["canplaythrough","canPlayThrough",2],["durationchange","durationChange",2],["emptied","emptied",2],["encrypted","encrypted",2],["ended","ended",2],["error","error",2],["gotpointercapture","gotPointerCapture",2],["load","load",2],["loadeddata","loadedData",2],["loadedmetadata","loadedMetadata",2],["loadstart","loadStart",2],["lostpointercapture","lostPointerCapture",2],["playing","playing",2],["progress","progress",2],["seeking","seeking",2],["stalled","stalled",2],["suspend","suspend",2],["timeupdate","timeUpdate",2],[tt,"transitionEnd",2],["waiting","waiting",2]],nr={},ni={},na=0;na=t)return{node:r,offset:t-e};e=n}a:{for(;r;){if(r.nextSibling){r=r.nextSibling;break a}r=r.parentNode}r=void 0}r=nU(r)}}function n$(e,t){return!!e&&!!t&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?n$(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function nz(){for(var e=window,t=nB();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(n)e=t.contentWindow;else break;t=nB(e.document)}return t}function nG(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var nW="$",nK="/$",nV="$?",nq="$!",nZ=null,nX=null;function nJ(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function nQ(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var n1="function"==typeof setTimeout?setTimeout:void 0,n0="function"==typeof clearTimeout?clearTimeout:void 0;function n2(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function n3(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if(n===nW||n===nq||n===nV){if(0===t)return e;t--}else n===nK&&t++}e=e.previousSibling}return null}var n4=Math.random().toString(36).slice(2),n5="__reactInternalInstance$"+n4,n6="__reactEventHandlers$"+n4,n9="__reactContainere$"+n4;function n8(e){var t=e[n5];if(t)return t;for(var n=e.parentNode;n;){if(t=n[n9]||n[n5]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=n3(e);null!==e;){if(n=e[n5])return n;e=n3(e)}return t}n=(e=n).parentNode}return null}function n7(e){return(e=e[n5]||e[n9])&&(5===e.tag||6===e.tag||13===e.tag||3===e.tag)?e:null}function re(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(f(33))}function rt(e){return e[n6]||null}var rn=null,rr=null,ri=null;function ra(){if(ri)return ri;var e,t,n=rr,r=n.length,i="value"in rn?rn.value:rn.textContent,a=i.length;for(e=0;e=rl),rh=" ",rp={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},rb=!1;function rm(e,t){switch(e){case"keyup":return -1!==ru.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"blur":return!0;default:return!1}}function rg(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var rv=!1;function ry(e,t){switch(e){case"compositionend":return rg(t);case"keypress":if(32!==t.which)return null;return rb=!0,rh;case"textInput":return(e=t.data)===rh&&rb?null:e;default:return null}}function rw(e,t){if(rv)return"compositionend"===e||!rc&&rm(e,t)?(e=ra(),ri=rr=rn=null,rv=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=document.documentMode,rK={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"blur contextmenu dragend focus keydown keyup mousedown mouseup selectionchange".split(" ")}},rV=null,rq=null,rZ=null,rX=!1;function rJ(e,t){var n=t.window===t?t.document:9===t.nodeType?t:t.ownerDocument;return rX||null==rV||rV!==nB(n)?null:(n="selectionStart"in(n=rV)&&nG(n)?{start:n.selectionStart,end:n.selectionEnd}:{anchorNode:(n=(n.ownerDocument&&n.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset},rZ&&rG(rZ,n)?null:(rZ=n,(e=tU.getPooled(rK.select,rq,e,t)).type="select",e.target=rV,tF(e),e))}var rQ={eventTypes:rK,extractEvents:function(e,t,n,r){var i,a=r.window===r?r.document:9===r.nodeType?r:r.ownerDocument;if(!(i=!a)){a:{a=nA(a),i=y.onSelect;for(var o=0;or2||(e.current=r0[r2],r0[r2]=null,r2--)}function r4(e,t){r0[++r2]=e.current,e.current=t}var r5={},r6={current:r5},r9={current:!1},r8=r5;function r7(e,t){var n=e.type.contextTypes;if(!n)return r5;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var i,a={};for(i in n)a[i]=t[i];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=a),a}function ie(e){return null!=(e=e.childContextTypes)}function it(e){r3(r9,e),r3(r6,e)}function ir(e){r3(r9,e),r3(r6,e)}function ii(e,t,n){if(r6.current!==r5)throw Error(f(168));r4(r6,t,e),r4(r9,n,e)}function ia(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var i in r=r.getChildContext())if(!(i in e))throw Error(f(108,ei(t)||"Unknown",i));return c({},n,{},r)}function io(e){var t=e.stateNode;return t=t&&t.__reactInternalMemoizedMergedChildContext||r5,r8=r6.current,r4(r6,t,e),r4(r9,r9.current,e),!0}function is(e,t,n){var r=e.stateNode;if(!r)throw Error(f(169));n?(t=ia(e,t,r8),r.__reactInternalMemoizedMergedChildContext=t,r3(r9,e),r3(r6,e),r4(r6,t,e)):r3(r9,e),r4(r9,n,e)}var iu=l.unstable_runWithPriority,ic=l.unstable_scheduleCallback,il=l.unstable_cancelCallback,id=l.unstable_shouldYield,ih=l.unstable_requestPaint,ip=l.unstable_now,ib=l.unstable_getCurrentPriorityLevel,im=l.unstable_ImmediatePriority,ig=l.unstable_UserBlockingPriority,iv=l.unstable_NormalPriority,iy=l.unstable_LowPriority,iw=l.unstable_IdlePriority,i_={},iE=void 0!==ih?ih:function(){},iS=null,ik=null,ix=!1,iT=ip(),iM=1e4>iT?ip:function(){return ip()-iT};function iO(){switch(ib()){case im:return 99;case ig:return 98;case iv:return 97;case iy:return 96;case iw:return 95;default:throw Error(f(332))}}function iA(e){switch(e){case 99:return im;case 98:return ig;case 97:return iv;case 96:return iy;case 95:return iw;default:throw Error(f(332))}}function iL(e,t){return e=iA(e),iu(e,t)}function iC(e,t,n){return e=iA(e),ic(e,t,n)}function iI(e){return null===iS?(iS=[e],ik=ic(im,iN)):iS.push(e),i_}function iD(){if(null!==ik){var e=ik;ik=null,il(e)}iN()}function iN(){if(!ix&&null!==iS){ix=!0;var e=0;try{var t=iS;iL(99,function(){for(;e=t&&(oo=!0),e.firstContext=null)}function iK(e,t){if(iU!==e&&!1!==t&&0!==t){if(("number"!=typeof t||1073741823===t)&&(iU=e,t=1073741823),t={context:e,observedBits:t,next:null},null===iB){if(null===iY)throw Error(f(308));iB=t,iY.dependencies={expirationTime:0,firstContext:t,responders:null}}else iB=iB.next=t}return e._currentValue}var iV=!1;function iq(e){return{baseState:e,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function iZ(e){return{baseState:e.baseState,firstUpdate:e.firstUpdate,lastUpdate:e.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function iX(e,t){return{expirationTime:e,suspenseConfig:t,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function iJ(e,t){null===e.lastUpdate?e.firstUpdate=e.lastUpdate=t:(e.lastUpdate.next=t,e.lastUpdate=t)}function iQ(e,t){var n=e.alternate;if(null===n){var r=e.updateQueue,i=null;null===r&&(r=e.updateQueue=iq(e.memoizedState))}else r=e.updateQueue,i=n.updateQueue,null===r?null===i?(r=e.updateQueue=iq(e.memoizedState),i=n.updateQueue=iq(n.memoizedState)):r=e.updateQueue=iZ(i):null===i&&(i=n.updateQueue=iZ(r));null===i||r===i?iJ(r,t):null===r.lastUpdate||null===i.lastUpdate?(iJ(r,t),iJ(i,t)):(iJ(r,t),i.lastUpdate=t)}function i1(e,t){var n=e.updateQueue;null===(n=null===n?e.updateQueue=iq(e.memoizedState):i0(e,n)).lastCapturedUpdate?n.firstCapturedUpdate=n.lastCapturedUpdate=t:(n.lastCapturedUpdate.next=t,n.lastCapturedUpdate=t)}function i0(e,t){var n=e.alternate;return null!==n&&t===n.updateQueue&&(t=e.updateQueue=iZ(t)),t}function i2(e,t,n,r,i,a){switch(n.tag){case 1:return"function"==typeof(e=n.payload)?e.call(a,r,i):e;case 3:e.effectTag=-4097&e.effectTag|64;case 0:if(null==(i="function"==typeof(e=n.payload)?e.call(a,r,i):e))break;return c({},r,i);case 2:iV=!0}return r}function i3(e,t,n,r,i){iV=!1,t=i0(e,t);for(var a=t.baseState,o=null,s=0,u=t.firstUpdate,c=a;null!==u;){var l=u.expirationTime;lb?(m=f,f=null):m=f.sibling;var g=h(i,f,s[b],u);if(null===g){null===f&&(f=m);break}e&&f&&null===g.alternate&&t(i,f),o=a(g,o,b),null===l?c=g:l.sibling=g,l=g,f=m}if(b===s.length)return n(i,f),c;if(null===f){for(;bm?(g=b,b=null):g=b.sibling;var y=h(i,b,v.value,u);if(null===y){null===b&&(b=g);break}e&&b&&null===y.alternate&&t(i,b),o=a(y,o,m),null===l?c=y:l.sibling=y,l=y,b=g}if(v.done)return n(i,b),c;if(null===b){for(;!v.done;m++,v=s.next())null!==(v=d(i,v.value,u))&&(o=a(v,o,m),null===l?c=v:l.sibling=v,l=v);return c}for(b=r(i,b);!v.done;m++,v=s.next())null!==(v=p(b,i,m,v.value,u))&&(e&&null!==v.alternate&&b.delete(null===v.key?m:v.key),o=a(v,o,m),null===l?c=v:l.sibling=v,l=v);return e&&b.forEach(function(e){return t(i,e)}),c}return function(e,r,a,s){var u="object"==typeof a&&null!==a&&a.type===z&&null===a.key;u&&(a=a.props.children);var c="object"==typeof a&&null!==a;if(c)switch(a.$$typeof){case H:a:{for(c=a.key,u=r;null!==u;){if(u.key===c){if(7===u.tag?a.type===z:u.elementType===a.type){n(e,u.sibling),(r=i(u,a.type===z?a.props.children:a.props,s)).ref=aa(e,u,a),r.return=e,e=r;break a}n(e,u);break}t(e,u),u=u.sibling}a.type===z?((r=s1(a.props.children,e.mode,s,a.key)).return=e,e=r):((s=sQ(a.type,a.key,a.props,null,e.mode,s)).ref=aa(e,r,a),s.return=e,e=s)}return o(e);case $:a:{for(u=a.key;null!==r;){if(r.key===u){if(4===r.tag&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){n(e,r.sibling),(r=i(r,a.children||[],s)).return=e,e=r;break a}n(e,r);break}t(e,r),r=r.sibling}(r=s2(a,e.mode,s)).return=e,e=r}return o(e)}if("string"==typeof a||"number"==typeof a)return a=""+a,null!==r&&6===r.tag?(n(e,r.sibling),(r=i(r,a,s)).return=e,e=r):(n(e,r),(r=s0(a,e.mode,s)).return=e,e=r),o(e);if(ai(a))return b(e,r,a,s);if(en(a))return m(e,r,a,s);if(c&&ao(e,a),void 0===a&&!u)switch(e.tag){case 1:case 0:throw Error(f(152,(e=e.type).displayName||e.name||"Component"))}return n(e,r)}}var au=as(!0),ac=as(!1),al={},af={current:al},ad={current:al},ah={current:al};function ap(e){if(e===al)throw Error(f(174));return e}function ab(e,t){r4(ah,t,e),r4(ad,e,e),r4(af,al,e);var n=t.nodeType;switch(n){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:eJ(null,"");break;default:t=eJ(t=(n=8===n?t.parentNode:t).namespaceURI||null,n=n.tagName)}r3(af,e),r4(af,t,e)}function am(e){r3(af,e),r3(ad,e),r3(ah,e)}function ag(e){ap(ah.current);var t=ap(af.current),n=eJ(t,e.type);t!==n&&(r4(ad,e,e),r4(af,n,e))}function av(e){ad.current===e&&(r3(af,e),r3(ad,e))}var ay={current:0};function aw(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||n.data===nV||n.data===nq))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(64&t.effectTag))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function a_(e,t){return{responder:e,props:t}}var aE=Y.ReactCurrentDispatcher,aS=Y.ReactCurrentBatchConfig,ak=0,ax=null,aT=null,aM=null,aO=null,aA=null,aL=null,aC=0,aI=null,aD=0,aN=!1,aP=null,aR=0;function aj(){throw Error(f(321))}function aF(e,t){if(null===t)return!1;for(var n=0;naC&&sL(aC=l)):(sA(l,u.suspenseConfig),a=u.eagerReducer===e?u.eagerState:e(a,u.action)),o=u,u=u.next}while(null!==u&&u!==r)c||(s=o,i=a),r$(a,t.memoizedState)||(oo=!0),t.memoizedState=a,t.baseUpdate=s,t.baseState=i,n.lastRenderedState=a}return[t.memoizedState,n.dispatch]}function aG(e){var t=aU();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={last:null,dispatch:null,lastRenderedReducer:a$,lastRenderedState:e}).dispatch=a2.bind(null,ax,e),[t.memoizedState,e]}function aW(e){return az(a$,e)}function aK(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===aI?(aI={lastEffect:null}).lastEffect=e.next=e:null===(t=aI.lastEffect)?aI.lastEffect=e.next=e:(n=t.next,t.next=e,e.next=n,aI.lastEffect=e),e}function aV(e,t,n,r){var i=aU();aD|=e,i.memoizedState=aK(t,n,void 0,void 0===r?null:r)}function aq(e,t,n,r){var i=aH();r=void 0===r?null:r;var a=void 0;if(null!==aT){var o=aT.memoizedState;if(a=o.destroy,null!==r&&aF(r,o.deps)){aK(0,n,a,r);return}}aD|=e,i.memoizedState=aK(t,n,a,r)}function aZ(e,t){return aV(516,192,e,t)}function aX(e,t){return aq(516,192,e,t)}function aJ(e,t){return"function"==typeof t?(t(e=e()),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function aQ(){}function a1(e,t){return aU().memoizedState=[e,void 0===t?null:t],e}function a0(e,t){var n=aH();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&aF(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function a2(e,t,n){if(!(25>aR))throw Error(f(301));var r=e.alternate;if(e===ax||null!==r&&r===ax){if(aN=!0,e={expirationTime:ak,suspenseConfig:null,action:n,eagerReducer:null,eagerState:null,next:null},null===aP&&(aP=new Map),void 0===(n=aP.get(t)))aP.set(t,e);else{for(t=n;null!==t.next;)t=t.next;t.next=e}}else{var i=sb(),a=i6.suspense;a={expirationTime:i=sm(i,e,a),suspenseConfig:a,action:n,eagerReducer:null,eagerState:null,next:null};var o=t.last;if(null===o)a.next=a;else{var s=o.next;null!==s&&(a.next=s),o.next=a}if(t.last=a,0===e.expirationTime&&(null===r||0===r.expirationTime)&&null!==(r=t.lastRenderedReducer))try{var u=t.lastRenderedState,c=r(u,n);if(a.eagerReducer=r,a.eagerState=c,r$(c,u))return}catch(l){}finally{}sg(e,i)}}var a3={readContext:iK,useCallback:aj,useContext:aj,useEffect:aj,useImperativeHandle:aj,useLayoutEffect:aj,useMemo:aj,useReducer:aj,useRef:aj,useState:aj,useDebugValue:aj,useResponder:aj,useDeferredValue:aj,useTransition:aj},a4={readContext:iK,useCallback:a1,useContext:iK,useEffect:aZ,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,aV(4,36,aJ.bind(null,t,e),n)},useLayoutEffect:function(e,t){return aV(4,36,e,t)},useMemo:function(e,t){var n=aU();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=aU();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={last:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=a2.bind(null,ax,e),[r.memoizedState,e]},useRef:function(e){var t=aU();return e={current:e},t.memoizedState=e},useState:aG,useDebugValue:aQ,useResponder:a_,useDeferredValue:function(e,t){var n=aG(e),r=n[0],i=n[1];return aZ(function(){l.unstable_next(function(){var n=aS.suspense;aS.suspense=void 0===t?null:t;try{i(e)}finally{aS.suspense=n}})},[e,t]),r},useTransition:function(e){var t=aG(!1),n=t[0],r=t[1];return[a1(function(t){r(!0),l.unstable_next(function(){var n=aS.suspense;aS.suspense=void 0===e?null:e;try{r(!1),t()}finally{aS.suspense=n}})},[e,n]),n]}},a5={readContext:iK,useCallback:a0,useContext:iK,useEffect:aX,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,aq(4,36,aJ.bind(null,t,e),n)},useLayoutEffect:function(e,t){return aq(4,36,e,t)},useMemo:function(e,t){var n=aH();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&aF(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)},useReducer:az,useRef:function(){return aH().memoizedState},useState:aW,useDebugValue:aQ,useResponder:a_,useDeferredValue:function(e,t){var n=aW(e),r=n[0],i=n[1];return aX(function(){l.unstable_next(function(){var n=aS.suspense;aS.suspense=void 0===t?null:t;try{i(e)}finally{aS.suspense=n}})},[e,t]),r},useTransition:function(e){var t=aW(!1),n=t[0],r=t[1];return[a0(function(t){r(!0),l.unstable_next(function(){var n=aS.suspense;aS.suspense=void 0===e?null:e;try{r(!1),t()}finally{aS.suspense=n}})},[e,n]),n]}},a6=null,a9=null,a8=!1;function a7(e,t){var n=sq(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.effectTag=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function oe(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function ot(e){if(a8){var t=a9;if(t){var n=t;if(!oe(e,t)){if(!(t=n2(n.nextSibling))||!oe(e,t)){e.effectTag=-1025&e.effectTag|2,a8=!1,a6=e;return}a7(a6,n)}a6=e,a9=n2(t.firstChild)}else e.effectTag=-1025&e.effectTag|2,a8=!1,a6=e}}function on(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;a6=e}function or(e){if(e!==a6)return!1;if(!a8)return on(e),a8=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!nQ(t,e.memoizedProps))for(t=a9;t;)a7(e,t),t=n2(t.nextSibling);if(on(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(f(317));a:{for(t=0,e=e.nextSibling;e;){if(8===e.nodeType){var n=e.data;if(n===nK){if(0===t){a9=n2(e.nextSibling);break a}t--}else n!==nW&&n!==nq&&n!==nV||t++}e=e.nextSibling}a9=null}}else a9=a6?n2(e.stateNode.nextSibling):null;return!0}function oi(){a9=a6=null,a8=!1}var oa=Y.ReactCurrentOwner,oo=!1;function os(e,t,n,r){t.child=null===e?ac(t,null,n,r):au(t,e.child,n,r)}function ou(e,t,n,r,i){n=n.render;var a=t.ref;return(iW(t,i),r=aY(e,t,n,r,a,i),null===e||oo)?(t.effectTag|=1,os(e,t,r,i),t.child):(t.updateQueue=e.updateQueue,t.effectTag&=-517,e.expirationTime<=i&&(e.expirationTime=0),o_(e,t,i))}function oc(e,t,n,r,i,a){if(null===e){var o=n.type;return"function"!=typeof o||sZ(o)||void 0!==o.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=sQ(n.type,null,r,null,t.mode,a)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=o,ol(e,t,o,r,i,a))}return(o=e.child,it)&&sf.set(e,t))}}function sv(e,t){e.expirationTime(e=e.nextKnownPendingLevel)?t:e:t}function sw(e){if(0!==e.lastExpiredTime)e.callbackExpirationTime=1073741823,e.callbackPriority=99,e.callbackNode=iI(sE.bind(null,e));else{var t=sy(e),n=e.callbackNode;if(0===t)null!==n&&(e.callbackNode=null,e.callbackExpirationTime=0,e.callbackPriority=90);else{var r=sb();if(r=1073741823===t?99:1===t||2===t?95:0>=(r=10*(1073741821-t)-10*(1073741821-r))?99:250>=r?98:5250>=r?97:95,null!==n){var i=e.callbackPriority;if(e.callbackExpirationTime===t&&i>=r)return;n!==i_&&il(n)}e.callbackExpirationTime=t,e.callbackPriority=r,t=1073741823===t?iI(sE.bind(null,e)):iC(r,s_.bind(null,e),{timeout:10*(1073741821-t)-iM()}),e.callbackNode=t}}}function s_(e,t){if(sp=0,t)return t=sb(),s9(e,t),sw(e),null;var n=sy(e);if(0!==n){if(t=e.callbackNode,(o0&(oK|oV))!==oG)throw Error(f(327));if(sY(),e===o2&&n===o4||sT(e,n),null!==o3){var r=o0;o0|=oK;for(var i=sO(e);;)try{sI();break}catch(a){sM(e,a)}if(iH(),o0=r,o$.current=i,o5===oZ)throw t=o6,sT(e,n),s5(e,n),sw(e),t;if(null===o3)switch(i=e.finishedWork=e.current.alternate,e.finishedExpirationTime=n,o2=null,r=o5){case oq:case oZ:throw Error(f(345));case oX:s9(e,2=n){e.lastPingedTime=n,sT(e,n);break}}if(0!==(o=sy(e))&&o!==n)break;if(0!==r&&r!==n){e.lastPingedTime=r;break}e.timeoutHandle=n1(sR.bind(null,e),i);break}sR(e);break;case oQ:if(s5(e,n),n===(r=e.lastSuspendedTime)&&(e.nextKnownPendingLevel=sP(i)),st&&(0===(i=e.lastPingedTime)||i>=n)){e.lastPingedTime=n,sT(e,n);break}if(0!==(i=sy(e))&&i!==n)break;if(0!==r&&r!==n){e.lastPingedTime=r;break}if(1073741823!==o8?r=10*(1073741821-o8)-iM():1073741823===o9?r=0:(r=10*(1073741821-o9)-5e3,n=10*(1073741821-n)-(i=iM()),0>(r=i-r)&&(r=0),n<(r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*oH(r/1960))-r)&&(r=n)),10=(r=0|s.busyMinDurationMs)?r=0:(i=0|s.busyDelayMs,r=(o=iM()-(10*(1073741821-o)-(0|s.timeoutMs||5e3)))<=i?0:i+r-o),10 component higher in the tree to provide a loading indicator or placeholder to display."+ea(i))}o5!==o1&&(o5=oX),a=ox(a,i),c=r;do{switch(c.tag){case 3:s=a,c.effectTag|=4096,c.expirationTime=t;var g=oB(c,s,t);i1(c,g);break a;case 1:s=a;var v=c.type,y=c.stateNode;if(0==(64&c.effectTag)&&("function"==typeof v.getDerivedStateFromError||null!==y&&"function"==typeof y.componentDidCatch&&(null===ss||!ss.has(y)))){c.effectTag|=4096,c.expirationTime=t;var w=oU(c,s,t);i1(c,w);break a}}c=c.return}while(null!==c)}o3=sN(o3)}catch(_){t=_;continue}break}}function sO(){var e=o$.current;return o$.current=a3,null===e?a3:e}function sA(e,t){ese&&(se=e)}function sC(){for(;null!==o3;)o3=sD(o3)}function sI(){for(;null!==o3&&!id();)o3=sD(o3)}function sD(e){var t=s(e.alternate,e,o4);return e.memoizedProps=e.pendingProps,null===t&&(t=sN(e)),oz.current=null,t}function sN(e){o3=e;do{var t=o3.alternate;if(e=o3.return,0==(2048&o3.effectTag)){a:{var n=t;t=o3;var s=o4,u=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:case 20:case 21:break;case 1:case 17:ie(t.type)&&it(t);break;case 3:am(t),ir(t),(u=t.stateNode).pendingContext&&(u.context=u.pendingContext,u.pendingContext=null),(null===n||null===n.child)&&or(t)&&oE(t),i(t);break;case 5:av(t),s=ap(ah.current);var l=t.type;if(null!==n&&null!=t.stateNode)a(n,t,l,u,s),n.ref!==t.ref&&(t.effectTag|=128);else if(u){var d=ap(af.current);if(or(t)){var h=(u=t).stateNode;n=u.type;var p=u.memoizedProps,b=s;switch(h[n5]=u,h[n6]=p,l=void 0,s=h,n){case"iframe":case"object":case"embed":nw("load",s);break;case"video":case"audio":for(h=0;h",h=p.removeChild(p.firstChild)):"string"==typeof p.is?h=h.createElement(b,{is:p.is}):(h=h.createElement(b),"select"===b&&(b=h,p.multiple?b.multiple=!0:p.size&&(b.size=p.size))):h=h.createElementNS(d,b),(p=h)[n5]=n,p[n6]=u,r(p,t,!1,!1),t.stateNode=p,b=l;var m=s,g=nj(b,n=u);switch(b){case"iframe":case"object":case"embed":nw("load",p),s=n;break;case"video":case"audio":for(s=0;su.tailExpiration&&1l&&(l=n),p>l&&(l=p),s=s.sibling;u.childExpirationTime=l}if(null!==t)return t;null!==e&&0==(2048&e.effectTag)&&(null===e.firstEffect&&(e.firstEffect=o3.firstEffect),null!==o3.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=o3.firstEffect),e.lastEffect=o3.lastEffect),1(e=e.childExpirationTime)?t:e}function sR(e){var t=iO();return iL(99,sj.bind(null,e,t)),null}function sj(e,t){do sY();while(null!==sc)if((o0&(oK|oV))!==oG)throw Error(f(327));var n=e.finishedWork,r=e.finishedExpirationTime;if(null===n)return null;if(e.finishedWork=null,e.finishedExpirationTime=0,n===e.current)throw Error(f(177));e.callbackNode=null,e.callbackExpirationTime=0,e.callbackPriority=90,e.nextKnownPendingLevel=0;var i=sP(n);if(e.firstPendingTime=i,r<=e.lastSuspendedTime?e.firstSuspendedTime=e.lastSuspendedTime=e.nextKnownPendingLevel=0:r<=e.firstSuspendedTime&&(e.firstSuspendedTime=r-1),r<=e.lastPingedTime&&(e.lastPingedTime=0),r<=e.lastExpiredTime&&(e.lastExpiredTime=0),e===o2&&(o3=o2=null,o4=0),1s&&(l=s,s=o,o=l),l=nH(E,o),d=nH(E,s),l&&d&&(1!==k.rangeCount||k.anchorNode!==l.node||k.anchorOffset!==l.offset||k.focusNode!==d.node||k.focusOffset!==d.offset)&&((S=S.createRange()).setStart(l.node,l.offset),k.removeAllRanges(),o>s?(k.addRange(S),k.extend(d.node,d.offset)):(S.setEnd(d.node,d.offset),k.addRange(S))))),S=[],k=E;k=k.parentNode;)1===k.nodeType&&S.push({element:k,left:k.scrollLeft,top:k.scrollTop});for("function"==typeof E.focus&&E.focus(),E=0;E=n)return og(e,t,n);return r4(ay,1&ay.current,t),null!==(t=o_(e,t,n))?t.sibling:null}r4(ay,1&ay.current,t);break;case 19:if(r=t.childExpirationTime>=n,0!=(64&e.effectTag)){if(r)return ow(e,t,n);t.effectTag|=64}if(null!==(i=t.memoizedState)&&(i.rendering=null,i.tail=null),r4(ay,ay.current,t),!r)return null}return o_(e,t,n)}oo=!1}}else oo=!1;switch(t.expirationTime=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),e=t.pendingProps,i=r7(t,r6.current),iW(t,n),i=aY(null,t,r,e,i,n),t.effectTag|=1,"object"==typeof i&&null!==i&&"function"==typeof i.render&&void 0===i.$$typeof){if(t.tag=1,aB(),ie(r)){var a=!0;io(t)}else a=!1;t.memoizedState=null!==i.state&&void 0!==i.state?i.state:null;var o=r.getDerivedStateFromProps;"function"==typeof o&&i8(t,r,o,e),i.updater=i7,t.stateNode=i,i._reactInternalFiber=t,ar(t,r,e,n),t=op(null,t,r,!0,a,n)}else t.tag=0,os(null,t,i,n),t=t.child;return t;case 16:if(i=t.elementType,null!==e&&(e.alternate=null,t.alternate=null,t.effectTag|=2),e=t.pendingProps,er(i),1!==i._status)throw i._result;switch(i=i._result,t.type=i,a=t.tag=sX(i),e=ij(i,e),a){case 0:t=od(null,t,i,e,n);break;case 1:t=oh(null,t,i,e,n);break;case 11:t=ou(null,t,i,e,n);break;case 14:t=oc(null,t,i,ij(i.type,e),r,n);break;default:throw Error(f(306,i,""))}return t;case 0:return r=t.type,i=t.pendingProps,i=t.elementType===r?i:ij(r,i),od(e,t,r,i,n);case 1:return r=t.type,i=t.pendingProps,i=t.elementType===r?i:ij(r,i),oh(e,t,r,i,n);case 3:if(ob(t),null===(r=t.updateQueue))throw Error(f(282));if(i=null!==(i=t.memoizedState)?i.element:null,i3(t,r,t.pendingProps,null,n),(r=t.memoizedState.element)===i)oi(),t=o_(e,t,n);else{if((i=t.stateNode.hydrate)&&(a9=n2(t.stateNode.containerInfo.firstChild),a6=t,i=a8=!0),i)for(n=ac(t,null,r,n),t.child=n;n;)n.effectTag=-3&n.effectTag|1024,n=n.sibling;else os(e,t,r,n),oi();t=t.child}return t;case 5:return ag(t),null===e&&ot(t),r=t.type,i=t.pendingProps,a=null!==e?e.memoizedProps:null,o=i.children,nQ(r,i)?o=null:null!==a&&nQ(r,a)&&(t.effectTag|=16),of(e,t),4&t.mode&&1!==n&&i.hidden?(t.expirationTime=t.childExpirationTime=1,t=null):(os(e,t,o,n),t=t.child),t;case 6:return null===e&&ot(t),null;case 13:return og(e,t,n);case 4:return ab(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=au(t,null,r,n):os(e,t,r,n),t.child;case 11:return r=t.type,i=t.pendingProps,i=t.elementType===r?i:ij(r,i),ou(e,t,r,i,n);case 7:return os(e,t,t.pendingProps,n),t.child;case 8:case 12:return os(e,t,t.pendingProps.children,n),t.child;case 10:a:{if(r=t.type._context,i=t.pendingProps,o=t.memoizedProps,i$(t,a=i.value),null!==o){var s=o.value;if(0==(a=r$(s,a)?0:("function"==typeof r._calculateChangedBits?r._calculateChangedBits(s,a):1073741823)|0)){if(o.children===i.children&&!r9.current){t=o_(e,t,n);break a}}else for(null!==(s=t.child)&&(s.return=t);null!==s;){var u=s.dependencies;if(null!==u){o=s.child;for(var c=u.firstContext;null!==c;){if(c.context===r&&0!=(c.observedBits&a)){1===s.tag&&((c=iX(n,null)).tag=2,iQ(s,c)),s.expirationTime=t&&e<=t}function s5(e,t){var n=e.firstSuspendedTime,r=e.lastSuspendedTime;nt||0===n)&&(e.lastSuspendedTime=t),t<=e.lastPingedTime&&(e.lastPingedTime=0),t<=e.lastExpiredTime&&(e.lastExpiredTime=0)}function s6(e,t){t>e.firstPendingTime&&(e.firstPendingTime=t);var n=e.firstSuspendedTime;0!==n&&(t>=n?e.firstSuspendedTime=e.lastSuspendedTime=e.nextKnownPendingLevel=0:t>=e.lastSuspendedTime&&(e.lastSuspendedTime=t+1),t>e.nextKnownPendingLevel&&(e.nextKnownPendingLevel=t))}function s9(e,t){var n=e.lastExpiredTime;(0===n||n>t)&&(e.lastExpiredTime=t)}function s8(e,t,n,r){var i=t.current,a=sb(),o=i6.suspense;a=sm(a,i,o);a:if(n){n=n._reactInternalFiber;b:{if(tr(n)!==n||1!==n.tag)throw Error(f(170));var s=n;do{switch(s.tag){case 3:s=s.stateNode.context;break b;case 1:if(ie(s.type)){s=s.stateNode.__reactInternalMemoizedMergedChildContext;break b}}s=s.return}while(null!==s)throw Error(f(171))}if(1===n.tag){var u=n.type;if(ie(u)){n=ia(n,u,s);break a}}n=s}else n=r5;return null===t.context?t.context=n:t.pendingContext=n,(t=iX(a,o)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),iQ(i,t),sg(i,a),a}function s7(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function ue(e,t){null!==(e=e.memoizedState)&&null!==e.dehydrated&&e.retryTime1&&void 0!==arguments[1]?arguments[1]:this.props,n=t.target;if(n){var r=n;"string"==typeof n&&(r=window[n]),_(t,e.bind(null,r))}}},{key:"render",value:function(){return this.props.children||null}}]),t}(h.PureComponent);S.propTypes={},t.withOptions=E,t.default=S},69590(e){"use strict";var t=Array.isArray,n=Object.keys,r=Object.prototype.hasOwnProperty,i="undefined"!=typeof Element;function a(e,o){if(e===o)return!0;if(e&&o&&"object"==typeof e&&"object"==typeof o){var s,u,c,l=t(e),f=t(o);if(l&&f){if((u=e.length)!=o.length)return!1;for(s=u;0!=s--;)if(!a(e[s],o[s]))return!1;return!0}if(l!=f)return!1;var d=e instanceof Date,h=o instanceof Date;if(d!=h)return!1;if(d&&h)return e.getTime()==o.getTime();var p=e instanceof RegExp,b=o instanceof RegExp;if(p!=b)return!1;if(p&&b)return e.toString()==o.toString();var m=n(e);if((u=m.length)!==n(o).length)return!1;for(s=u;0!=s--;)if(!r.call(o,m[s]))return!1;if(i&&e instanceof Element&&o instanceof Element)return e===o;for(s=u;0!=s--;)if(("_owner"!==(c=m[s])||!e.$$typeof)&&!a(e[c],o[c]))return!1;return!0}return e!=e&&o!=o}e.exports=function(e,t){try{return a(e,t)}catch(n){if(n.message&&n.message.match(/stack|recursion/i)||-2146828260===n.number)return console.warn("Warning: react-fast-compare does not handle circular references.",n.name,n.message),!1;throw n}}},57209(e,t,n){"use strict";function r(e){return e&&"object"==typeof e&&"default"in e?e.default:e}i={value:!0};var i,a=r(n(67294));function o(e){return o.warnAboutHMRDisabled&&(o.warnAboutHMRDisabled=!0,console.error("React-Hot-Loader: misconfiguration detected, using production version in non-production environment."),console.error("React-Hot-Loader: Hot Module Replacement is not enabled.")),a.Children.only(e.children)}o.warnAboutHMRDisabled=!1;var s=function e(){return e.shouldWrapWithAppContainer?function(e){return function(t){return a.createElement(o,null,a.createElement(e,t))}}:function(e){return e}};s.shouldWrapWithAppContainer=!1;var u=function(e,t){return e===t},c=function(){},l=function(e){return e},f=function(){};t.zj=o,t.wU=s,i=u,i=c,i=l,i=f},69921(e,t){"use strict";/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,i=n?Symbol.for("react.portal"):60106,a=n?Symbol.for("react.fragment"):60107,o=n?Symbol.for("react.strict_mode"):60108,s=n?Symbol.for("react.profiler"):60114,u=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,l=n?Symbol.for("react.async_mode"):60111,f=n?Symbol.for("react.concurrent_mode"):60111,d=n?Symbol.for("react.forward_ref"):60112,h=n?Symbol.for("react.suspense"):60113,p=n?Symbol.for("react.suspense_list"):60120,b=n?Symbol.for("react.memo"):60115,m=n?Symbol.for("react.lazy"):60116,g=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function _(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case l:case f:case a:case s:case o:case h:return e;default:switch(e=e&&e.$$typeof){case c:case d:case m:case b:case u:return e;default:return t}}case i:return t}}}function E(e){return _(e)===f}t.AsyncMode=l,t.ConcurrentMode=f,t.ContextConsumer=c,t.ContextProvider=u,t.Element=r,t.ForwardRef=d,t.Fragment=a,t.Lazy=m,t.Memo=b,t.Portal=i,t.Profiler=s,t.StrictMode=o,t.Suspense=h,t.isAsyncMode=function(e){return E(e)||_(e)===l},t.isConcurrentMode=E,t.isContextConsumer=function(e){return _(e)===c},t.isContextProvider=function(e){return _(e)===u},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return _(e)===d},t.isFragment=function(e){return _(e)===a},t.isLazy=function(e){return _(e)===m},t.isMemo=function(e){return _(e)===b},t.isPortal=function(e){return _(e)===i},t.isProfiler=function(e){return _(e)===s},t.isStrictMode=function(e){return _(e)===o},t.isSuspense=function(e){return _(e)===h},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===a||e===f||e===s||e===o||e===h||e===p||"object"==typeof e&&null!==e&&(e.$$typeof===m||e.$$typeof===b||e.$$typeof===u||e.$$typeof===c||e.$$typeof===d||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===g)},t.typeOf=_},59864(e,t,n){"use strict";e.exports=n(69921)},46871(e,t,n){"use strict";function r(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);null!=e&&this.setState(e)}function i(e){function t(t){var n=this.constructor.getDerivedStateFromProps(e,t);return null!=n?n:null}this.setState(t.bind(this))}function a(e,t){try{var n=this.props,r=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,r)}finally{this.props=n,this.state=r}}function o(e){var t,n=e.prototype;if(!n||!n.isReactComponent)throw Error("Can only polyfill class components");if("function"!=typeof e.getDerivedStateFromProps&&"function"!=typeof n.getSnapshotBeforeUpdate)return e;var o=null,s=null,u=null;if("function"==typeof n.componentWillMount?o="componentWillMount":"function"==typeof n.UNSAFE_componentWillMount&&(o="UNSAFE_componentWillMount"),"function"==typeof n.componentWillReceiveProps?s="componentWillReceiveProps":"function"==typeof n.UNSAFE_componentWillReceiveProps&&(s="UNSAFE_componentWillReceiveProps"),"function"==typeof n.componentWillUpdate?u="componentWillUpdate":"function"==typeof n.UNSAFE_componentWillUpdate&&(u="UNSAFE_componentWillUpdate"),null!==o||null!==s||null!==u){throw Error("Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n"+(e.displayName||e.name)+" uses "+("function"==typeof e.getDerivedStateFromProps?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()")+" but also contains the following legacy lifecycles:"+(null!==o?"\n "+o:"")+(null!==s?"\n "+s:"")+(null!==u?"\n "+u:"")+"\n\nThe above lifecycles should be removed. Learn more about this warning here:\nhttps://fb.me/react-async-component-lifecycle-hooks")}if("function"==typeof e.getDerivedStateFromProps&&(n.componentWillMount=r,n.componentWillReceiveProps=i),"function"==typeof n.getSnapshotBeforeUpdate){if("function"!=typeof n.componentDidUpdate)throw Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");n.componentWillUpdate=a;var c=n.componentDidUpdate;n.componentDidUpdate=function(e,t,n){var r=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:n;c.call(this,e,t,r)}}return e}n.r(t),n.d(t,{polyfill:()=>o}),r.__suppressDeprecationWarning=!0,i.__suppressDeprecationWarning=!0,a.__suppressDeprecationWarning=!0},55977(e,t,n){"use strict";n.d(t,{zt:()=>h,$j:()=>J,wU:()=>A,I0:()=>er,v9:()=>es});var r=n(67294);n(45697);var i=r.createContext(null);function a(e){e()}var o=a,s=function(e){return o=e},u=function(){return o},c={notify:function(){}};function l(){var e=u(),t=null,n=null;return{clear:function(){t=null,n=null},notify:function(){e(function(){for(var e=t;e;)e.callback(),e=e.next})},get:function(){for(var e=[],n=t;n;)e.push(n),n=n.next;return e},subscribe:function(e){var r=!0,i=n={callback:e,next:null,prev:n};return i.prev?i.prev.next=i:t=i,function(){r&&null!==t&&(r=!1,i.next?i.next.prev=i.prev:n=i.prev,i.prev?i.prev.next=i.next:t=i.next)}}}}var f=function(){function e(e,t){this.store=e,this.parentSub=t,this.unsubscribe=null,this.listeners=c,this.handleChangeWrapper=this.handleChangeWrapper.bind(this)}var t=e.prototype;return t.addNestedSub=function(e){return this.trySubscribe(),this.listeners.subscribe(e)},t.notifyNestedSubs=function(){this.listeners.notify()},t.handleChangeWrapper=function(){this.onStateChange&&this.onStateChange()},t.isSubscribed=function(){return Boolean(this.unsubscribe)},t.trySubscribe=function(){this.unsubscribe||(this.unsubscribe=this.parentSub?this.parentSub.addNestedSub(this.handleChangeWrapper):this.store.subscribe(this.handleChangeWrapper),this.listeners=l())},t.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null,this.listeners.clear(),this.listeners=c)},e}();function d(e){var t=e.store,n=e.context,a=e.children,o=(0,r.useMemo)(function(){var e=new f(t);return e.onStateChange=e.notifyNestedSubs,{store:t,subscription:e}},[t]),s=(0,r.useMemo)(function(){return t.getState()},[t]);(0,r.useEffect)(function(){var e=o.subscription;return e.trySubscribe(),s!==t.getState()&&e.notifyNestedSubs(),function(){e.tryUnsubscribe(),e.onStateChange=null}},[o,s]);var u=n||i;return r.createElement(u.Provider,{value:o},a)}let h=d;var p=n(87462);function b(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var m=n(8679),g=n.n(m),v=n(59864),y="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?r.useLayoutEffect:r.useEffect,w=[],_=[null,null];function E(e,t){var n=e[1];return[t.payload,n+1]}function S(e,t,n){y(function(){return e.apply(void 0,t)},n)}function k(e,t,n,r,i,a,o){e.current=r,t.current=i,n.current=!1,a.current&&(a.current=null,o())}function x(e,t,n,r,i,a,o,s,u,c){if(e){var l,f=!1,d=null,h=function(){if(!f){var e,n,l=t.getState();try{e=r(l,i.current)}catch(h){n=h,d=h}n||(d=null),e===a.current?o.current||u():(a.current=e,s.current=e,o.current=!0,c({type:"STORE_UPDATED",payload:{error:n}}))}};return n.onStateChange=h,n.trySubscribe(),h(),function(){if(f=!0,n.tryUnsubscribe(),n.onStateChange=null,d)throw d}}}var T=function(){return[null,0]};function M(e,t){void 0===t&&(t={});var n=t,a=n.getDisplayName,o=void 0===a?function(e){return"ConnectAdvanced("+e+")"}:a,s=n.methodName,u=void 0===s?"connectAdvanced":s,c=n.renderCountProp,l=void 0===c?void 0:c,d=n.shouldHandleStateChanges,h=void 0===d||d,m=n.storeKey,y=void 0===m?"store":m,M=(n.withRef,n.forwardRef),O=void 0!==M&&M,A=n.context,L=void 0===A?i:A,C=b(n,["getDisplayName","methodName","renderCountProp","shouldHandleStateChanges","storeKey","withRef","forwardRef","context"]),I=L;return function(t){var n=t.displayName||t.name||"Component",i=o(n),a=(0,p.Z)({},C,{getDisplayName:o,methodName:u,renderCountProp:l,shouldHandleStateChanges:h,storeKey:y,displayName:i,wrappedComponentName:n,WrappedComponent:t}),s=C.pure;function c(t){return e(t.dispatch,a)}var d=s?r.useMemo:function(e){return e()};function m(e){var n=(0,r.useMemo)(function(){var t=e.reactReduxForwardedRef,n=b(e,["reactReduxForwardedRef"]);return[e.context,t,n]},[e]),i=n[0],a=n[1],o=n[2],s=(0,r.useMemo)(function(){return i&&i.Consumer&&(0,v.isContextConsumer)(r.createElement(i.Consumer,null))?i:I},[i,I]),u=(0,r.useContext)(s),l=Boolean(e.store)&&Boolean(e.store.getState)&&Boolean(e.store.dispatch);Boolean(u)&&u.store;var m=l?e.store:u.store,g=(0,r.useMemo)(function(){return c(m)},[m]),y=(0,r.useMemo)(function(){if(!h)return _;var e=new f(m,l?null:u.subscription),t=e.notifyNestedSubs.bind(e);return[e,t]},[m,l,u]),M=y[0],O=y[1],A=(0,r.useMemo)(function(){return l?u:(0,p.Z)({},u,{subscription:M})},[l,u,M]),L=(0,r.useReducer)(E,w,T),C=L[0][0],D=L[1];if(C&&C.error)throw C.error;var N=(0,r.useRef)(),P=(0,r.useRef)(o),R=(0,r.useRef)(),j=(0,r.useRef)(!1),F=d(function(){return R.current&&o===P.current?R.current:g(m.getState(),o)},[m,C,o]);S(k,[P,N,j,o,F,R,O]),S(x,[h,m,M,g,P,N,j,R,O,D],[m,M,g]);var Y=(0,r.useMemo)(function(){return r.createElement(t,(0,p.Z)({},F,{ref:a}))},[a,t,F]);return(0,r.useMemo)(function(){return h?r.createElement(s.Provider,{value:A},Y):Y},[s,Y,A])}var M=s?r.memo(m):m;if(M.WrappedComponent=t,M.displayName=i,O){var A=r.forwardRef(function(e,t){return r.createElement(M,(0,p.Z)({},e,{reactReduxForwardedRef:t}))});return A.displayName=i,A.WrappedComponent=t,g()(A,t)}return g()(M,t)}}function O(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!=e&&t!=t}function A(e,t){if(O(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(var i=0;i=0;r--){var i=t[r](e);if(i)return i}return function(t,r){throw Error("Invalid value of type "+typeof e+" for "+n+" argument when connecting component "+r.wrappedComponentName+".")}}function Z(e,t){return e===t}function X(e){var t=void 0===e?{}:e,n=t.connectHOC,r=void 0===n?M:n,i=t.mapStateToPropsFactories,a=void 0===i?B:i,o=t.mapDispatchToPropsFactories,s=void 0===o?j:o,u=t.mergePropsFactories,c=void 0===u?G:u,l=t.selectorFactory,f=void 0===l?V:l;return function(e,t,n,i){void 0===i&&(i={});var o=i,u=o.pure,l=void 0===u||u,d=o.areStatesEqual,h=void 0===d?Z:d,m=o.areOwnPropsEqual,g=void 0===m?A:m,v=o.areStatePropsEqual,y=void 0===v?A:v,w=o.areMergedPropsEqual,_=void 0===w?A:w,E=b(o,["pure","areStatesEqual","areOwnPropsEqual","areStatePropsEqual","areMergedPropsEqual"]),S=q(e,a,"mapStateToProps"),k=q(t,s,"mapDispatchToProps"),x=q(n,c,"mergeProps");return r(f,(0,p.Z)({methodName:"connect",getDisplayName:function(e){return"Connect("+e+")"},shouldHandleStateChanges:Boolean(e),initMapStateToProps:S,initMapDispatchToProps:k,initMergeProps:x,pure:l,areStatesEqual:h,areOwnPropsEqual:g,areStatePropsEqual:y,areMergedPropsEqual:_},E))}}let J=X();function Q(){var e;return(0,r.useContext)(i)}function ee(e){void 0===e&&(e=i);var t=e===i?Q:function(){return(0,r.useContext)(e)};return function(){return t().store}}var et=ee();function en(e){void 0===e&&(e=i);var t=e===i?et:ee(e);return function(){return t().dispatch}}var er=en(),ei=function(e,t){return e===t};function ea(e,t,n,i){var a,o=(0,r.useReducer)(function(e){return e+1},0)[1],s=(0,r.useMemo)(function(){return new f(n,i)},[n,i]),u=(0,r.useRef)(),c=(0,r.useRef)(),l=(0,r.useRef)(),d=(0,r.useRef)(),h=n.getState();try{a=e!==c.current||h!==l.current||u.current?e(h):d.current}catch(p){throw u.current&&(p.message+="\nThe error may be correlated with this previous error:\n"+u.current.stack+"\n\n"),p}return y(function(){c.current=e,l.current=h,d.current=a,u.current=void 0}),y(function(){function e(){try{var e=c.current(n.getState());if(t(e,d.current))return;d.current=e}catch(r){u.current=r}o()}return s.onStateChange=e,s.trySubscribe(),e(),function(){return s.tryUnsubscribe()}},[n,s]),a}function eo(e){void 0===e&&(e=i);var t=e===i?Q:function(){return(0,r.useContext)(e)};return function(e,n){void 0===n&&(n=ei);var i,a=t(),o=ea(e,n,a.store,a.subscription);return(0,r.useDebugValue)(o),o}}var es=eo();s(n(73935).unstable_batchedUpdates)},76(e,t,n){"use strict";n.d(t,{VK:()=>f,rU:()=>v});var r=n(47886);function i(e,t){return(i=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,i(e,t)}var o=n(67294),s=n(90071);function u(){return(u=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}n(45697);var l=n(2177),f=function(e){function t(){for(var t,n=arguments.length,r=Array(n),i=0;iN,AW:()=>U,F0:()=>M,rs:()=>$,s6:()=>T,LX:()=>Y,k6:()=>G,TH:()=>W,UO:()=>K,$B:()=>V});var a=n(67294),o=n(45697),s=n.n(o),u=n(90071);function c(e,t){return(c=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function l(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,c(e,t)}var f=1073741823,d="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};function h(){var e="__global_unique_id__";return d[e]=(d[e]||0)+1}function p(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}function b(e){var t=[];return{on:function(e){t.push(e)},off:function(e){t=t.filter(function(t){return t!==e})},get:function(){return e},set:function(n,r){e=n,t.forEach(function(t){return t(e,r)})}}}function m(e){return Array.isArray(e)?e[0]:e}function g(e,t){var n,r,i="__create-react-context-"+h()+"__",o=function(e){function n(){var t;return t=e.apply(this,arguments)||this,t.emitter=b(t.props.value),t}l(n,e);var r=n.prototype;return r.getChildContext=function(){var e;return(e={})[i]=this.emitter,e},r.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,i=e.value;p(r,i)?n=0:(n="function"==typeof t?t(r,i):f,0!=(n|=0)&&this.emitter.set(e.value,n))}},r.render=function(){return this.props.children},n}(a.Component);o.childContextTypes=((n={})[i]=s().object.isRequired,n);var u=function(t){function n(){var e;return e=t.apply(this,arguments)||this,e.state={value:e.getValue()},e.onUpdate=function(t,n){((0|e.observedBits)&n)!=0&&e.setState({value:e.getValue()})},e}l(n,t);var r=n.prototype;return r.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},r.componentDidMount=function(){this.context[i]&&this.context[i].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},r.componentWillUnmount=function(){this.context[i]&&this.context[i].off(this.onUpdate)},r.getValue=function(){return this.context[i]?this.context[i].get():e},r.render=function(){return m(this.props.children)(this.state.value)},n}(a.Component);return u.contextTypes=((r={})[i]=s().object,r),{Provider:o,Consumer:u}}var v=a.createContext||g;let y=v;var w=n(2177);function _(){return(_=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}function l(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}n(54726);var f="unmounted";t.UNMOUNTED=f;var d="exited";t.EXITED=d;var h="entering";t.ENTERING=h;var p="entered";t.ENTERED=p;var b="exiting";t.EXITING=b;var m=function(e){function t(t,n){r=e.call(this,t,n)||this;var r,i,a=n.transitionGroup,o=a&&!a.isMounting?t.enter:t.appear;return r.appearStatus=null,t.in?o?(i=d,r.appearStatus=h):i=p:i=t.unmountOnExit||t.mountOnEnter?f:d,r.state={status:i},r.nextCallback=null,r}l(t,e);var n=t.prototype;return n.getChildContext=function(){return{transitionGroup:null}},t.getDerivedStateFromProps=function(e,t){return e.in&&t.status===f?{status:d}:null},n.componentDidMount=function(){this.updateStatus(!0,this.appearStatus)},n.componentDidUpdate=function(e){var t=null;if(e!==this.props){var n=this.state.status;this.props.in?n!==h&&n!==p&&(t=h):(n===h||n===p)&&(t=b)}this.updateStatus(!1,t)},n.componentWillUnmount=function(){this.cancelNextCallback()},n.getTimeouts=function(){var e,t,n,r=this.props.timeout;return e=t=n=r,null!=r&&"number"!=typeof r&&(e=r.exit,t=r.enter,n=void 0!==r.appear?r.appear:t),{exit:e,enter:t,appear:n}},n.updateStatus=function(e,t){if(void 0===e&&(e=!1),null!==t){this.cancelNextCallback();var n=a.default.findDOMNode(this);t===h?this.performEnter(n,e):this.performExit(n)}else this.props.unmountOnExit&&this.state.status===d&&this.setState({status:f})},n.performEnter=function(e,t){var n=this,r=this.props.enter,i=this.context.transitionGroup?this.context.transitionGroup.isMounting:t,a=this.getTimeouts(),o=i?a.appear:a.enter;if(!t&&!r){this.safeSetState({status:p},function(){n.props.onEntered(e)});return}this.props.onEnter(e,i),this.safeSetState({status:h},function(){n.props.onEntering(e,i),n.onTransitionEnd(e,o,function(){n.safeSetState({status:p},function(){n.props.onEntered(e,i)})})})},n.performExit=function(e){var t=this,n=this.props.exit,r=this.getTimeouts();if(!n){this.safeSetState({status:d},function(){t.props.onExited(e)});return}this.props.onExit(e),this.safeSetState({status:b},function(){t.props.onExiting(e),t.onTransitionEnd(e,r.exit,function(){t.safeSetState({status:d},function(){t.props.onExited(e)})})})},n.cancelNextCallback=function(){null!==this.nextCallback&&(this.nextCallback.cancel(),this.nextCallback=null)},n.safeSetState=function(e,t){t=this.setNextCallback(t),this.setState(e,t)},n.setNextCallback=function(e){var t=this,n=!0;return this.nextCallback=function(r){n&&(n=!1,t.nextCallback=null,e(r))},this.nextCallback.cancel=function(){n=!1},this.nextCallback},n.onTransitionEnd=function(e,t,n){this.setNextCallback(n);var r=null==t&&!this.props.addEndListener;if(!e||r){setTimeout(this.nextCallback,0);return}this.props.addEndListener&&this.props.addEndListener(e,this.nextCallback),null!=t&&setTimeout(this.nextCallback,t)},n.render=function(){var e=this.state.status;if(e===f)return null;var t=this.props,n=t.children,r=c(t,["children"]);if(delete r.in,delete r.mountOnEnter,delete r.unmountOnExit,delete r.appear,delete r.enter,delete r.exit,delete r.timeout,delete r.addEndListener,delete r.onEnter,delete r.onEntering,delete r.onEntered,delete r.onExit,delete r.onExiting,delete r.onExited,"function"==typeof n)return n(e,r);var a=i.default.Children.only(n);return i.default.cloneElement(a,r)},t}(i.default.Component);function g(){}m.contextTypes={transitionGroup:r.object},m.childContextTypes={transitionGroup:function(){}},m.propTypes={},m.defaultProps={in:!1,mountOnEnter:!1,unmountOnExit:!1,appear:!1,enter:!0,exit:!0,onEnter:g,onEntering:g,onEntered:g,onExit:g,onExiting:g,onExited:g},m.UNMOUNTED=0,m.EXITED=1,m.ENTERING=2,m.ENTERED=3,m.EXITING=4;var v=(0,o.polyfill)(m);t.default=v},92381(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r=s(n(45697)),i=s(n(67294)),a=n(46871),o=n(40537);function s(e){return e&&e.__esModule?e:{default:e}}function u(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function c(){return(c=Object.assign||function(e){for(var t=1;tI.length&&I.push(e)}function P(e,t,n,r){var i=typeof e;("undefined"===i||"boolean"===i)&&(e=null);var s=!1;if(null===e)s=!0;else switch(i){case"string":case"number":s=!0;break;case"object":switch(e.$$typeof){case a:case o:s=!0}}if(s)return n(r,e,""===t?"."+j(e,0):t),1;if(s=0,t=""===t?".":t+":",Array.isArray(e))for(var u=0;u2)?"one of ".concat(t," ").concat(e.slice(0,n-1).join(", "),", or ")+e[n-1]:2===n?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}function a(e,t,n){return e.substr(!n||n<0?0:+n,t.length)===t}function o(e,t,n){return(void 0===n||n>e.length)&&(n=e.length),e.substring(n-t.length,n)===t}function s(e,t,n){return"number"!=typeof n&&(n=0),!(n+t.length>e.length)&&-1!==e.indexOf(t,n)}r("ERR_INVALID_OPT_VALUE",function(e,t){return'The value "'+t+'" is invalid for option "'+e+'"'},TypeError),r("ERR_INVALID_ARG_TYPE",function(e,t,n){if("string"==typeof t&&a(t,"not ")?(r="must not be",t=t.replace(/^not /,"")):r="must be",o(e," argument"))u="The ".concat(e," ").concat(r," ").concat(i(t,"type"));else{var r,u,c=s(e,".")?"property":"argument";u='The "'.concat(e,'" ').concat(c," ").concat(r," ").concat(i(t,"type"))}return u+". Received type ".concat(typeof n)},TypeError),r("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF"),r("ERR_METHOD_NOT_IMPLEMENTED",function(e){return"The "+e+" method is not implemented"}),r("ERR_STREAM_PREMATURE_CLOSE","Premature close"),r("ERR_STREAM_DESTROYED",function(e){return"Cannot call "+e+" after a stream was destroyed"}),r("ERR_MULTIPLE_CALLBACK","Callback called multiple times"),r("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable"),r("ERR_STREAM_WRITE_AFTER_END","write after end"),r("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError),r("ERR_UNKNOWN_ENCODING",function(e){return"Unknown encoding: "+e},TypeError),r("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event"),e.exports.q=n},56753(e,t,n){"use strict";var r=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};e.exports=c;var i=n(79481),a=n(64229);n(35717)(c,i);for(var o=r(a.prototype),s=0;s0){if("string"==typeof t||u.objectMode||Object.getPrototypeOf(t)===a.prototype||(t=s(t)),r)u.endEmitted?S(e,new E):A(e,u,t,!0);else if(u.ended)S(e,new w);else{if(u.destroyed)return!1;u.reading=!1,u.decoder&&!n?(t=u.decoder.write(t),u.objectMode||0!==t.length?A(e,u,t,!1):j(e,u)):A(e,u,t,!1)}}else r||(u.reading=!1,j(e,u));return!u.ended&&(u.length=C?e=C:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function D(e,t){return e<=0||0===t.length&&t.ended?0:t.objectMode?1:e!=e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=I(e)),e<=t.length)?e:t.ended?t.length:(t.needReadable=!0,0)}function N(e,t){if(f("onEofChunk"),!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,t.sync?P(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,R(e)))}}function P(e){var t=e._readableState;f("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(f("emitReadable",t.flowing),t.emittedReadable=!0,process.nextTick(R,e))}function R(e){var t=e._readableState;f("emitReadable_",t.destroyed,t.length,t.ended),!t.destroyed&&(t.length||t.ended)&&(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,z(e)}function j(e,t){t.readingMore||(t.readingMore=!0,process.nextTick(F,e,t))}function F(e,t){for(;!t.reading&&!t.ended&&(t.length0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount("data")>0&&e.resume()}function U(e){f("readable nexttick read 0"),e.read(0)}function H(e,t){t.resumeScheduled||(t.resumeScheduled=!0,process.nextTick($,e,t))}function $(e,t){f("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),z(e),t.flowing&&!t.reading&&e.read(0)}function z(e){var t=e._readableState;for(f("flow",t.flowing);t.flowing&&null!==e.read(););}function G(e,t){var n;return 0===t.length?null:(t.objectMode?n=t.buffer.shift():!e||e>=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):n=t.buffer.consume(e,t.decoder),n)}function W(e){var t=e._readableState;f("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,process.nextTick(K,t,e))}function K(e,t){if(f("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&0===e.length&&(e.endEmitted=!0,t.readable=!1,t.emit("end"),e.autoDestroy)){var n=t._writableState;(!n||n.autoDestroy&&n.finished)&&t.destroy()}}function V(e,t){for(var n=0,r=e.length;n=n.highWaterMark:n.length>0)||n.ended))return f("read: emitReadable",n.length,n.ended),0===n.length&&n.ended?W(this):P(this),null;if(0===(e=D(e,n))&&n.ended)return 0===n.length&&W(this),null;var i=n.needReadable;return f("need readable",i),(0===n.length||n.length-e0?G(e,n):null)?(n.needReadable=n.length<=n.highWaterMark,e=0):(n.length-=e,n.awaitDrain=0),0===n.length&&(n.ended||(n.needReadable=!0),r!==e&&n.ended&&W(this)),null!==t&&this.emit("data",t),t},M.prototype._read=function(e){S(this,new _("_read()"))},M.prototype.pipe=function(e,t){var n=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,f("pipe count=%d opts=%j",i.pipesCount,t);var a=t&&!1===t.end||e===process.stdout||e===process.stderr?m:s;function o(e,t){f("onunpipe"),e===n&&t&&!1===t.hasUnpiped&&(t.hasUnpiped=!0,l())}function s(){f("onend"),e.end()}i.endEmitted?process.nextTick(a):n.once("end",a),e.on("unpipe",o);var u=Y(n);e.on("drain",u);var c=!1;function l(){f("cleanup"),e.removeListener("close",p),e.removeListener("finish",b),e.removeListener("drain",u),e.removeListener("error",h),e.removeListener("unpipe",o),n.removeListener("end",s),n.removeListener("end",m),n.removeListener("data",d),c=!0,i.awaitDrain&&(!e._writableState||e._writableState.needDrain)&&u()}function d(t){f("ondata");var r=e.write(t);f("dest.write",r),!1===r&&((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==V(i.pipes,e))&&!c&&(f("false write response, pause",i.awaitDrain),i.awaitDrain++),n.pause())}function h(t){f("onerror",t),m(),e.removeListener("error",h),0===r(e,"error")&&S(e,t)}function p(){e.removeListener("finish",b),m()}function b(){f("onfinish"),e.removeListener("close",p),m()}function m(){f("unpipe"),n.unpipe(e)}return n.on("data",d),x(e,"error",h),e.once("close",p),e.once("finish",b),e.emit("pipe",n),i.flowing||(f("pipe resume"),n.resume()),e},M.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n)),this;if(!e){var r=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;a0,!1!==r.flowing&&this.resume()):"readable"!==e||r.endEmitted||r.readableListening||(r.readableListening=r.needReadable=!0,r.flowing=!1,r.emittedReadable=!1,f("on readable",r.length,r.reading),r.length?P(this):r.reading||process.nextTick(U,this)),n},M.prototype.addListener=M.prototype.on,M.prototype.removeListener=function(e,t){var n=i.prototype.removeListener.call(this,e,t);return"readable"===e&&process.nextTick(B,this),n},M.prototype.removeAllListeners=function(e){var t=i.prototype.removeAllListeners.apply(this,arguments);return("readable"===e||void 0===e)&&process.nextTick(B,this),t},M.prototype.resume=function(){var e=this._readableState;return e.flowing||(f("resume"),e.flowing=!e.readableListening,H(this,e)),e.paused=!1,this},M.prototype.pause=function(){return f("call pause flowing=%j",this._readableState.flowing),!1!==this._readableState.flowing&&(f("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this},M.prototype.wrap=function(e){var t=this,n=this._readableState,r=!1;for(var i in e.on("end",function(){if(f("wrapped end"),n.decoder&&!n.ended){var e=n.decoder.end();e&&e.length&&t.push(e)}t.push(null)}),e.on("data",function(i){if(f("wrapped data"),n.decoder&&(i=n.decoder.write(i)),!n.objectMode||null!=i)(n.objectMode||i&&i.length)&&(t.push(i)||(r=!0,e.pause()))}),e)void 0===this[i]&&"function"==typeof e[i]&&(this[i]=function(t){return function(){return e[t].apply(e,arguments)}}(i));for(var a=0;a-1))throw new E(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(T.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}}),Object.defineProperty(T.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),T.prototype._write=function(e,t,n){n(new m("_write()"))},T.prototype._writev=null,T.prototype.end=function(e,t,n){var r=this._writableState;return"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!=e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||H(this,r,n),this},Object.defineProperty(T.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}}),Object.defineProperty(T.prototype,"destroyed",{enumerable:!1,get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),T.prototype.destroy=d.destroy,T.prototype._undestroy=d.undestroy,T.prototype._destroy=function(e,t){t(e)}},45850(e,t,n){"use strict";function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var i,a=n(8610),o=Symbol("lastResolve"),s=Symbol("lastReject"),u=Symbol("error"),c=Symbol("ended"),l=Symbol("lastPromise"),f=Symbol("handlePromise"),d=Symbol("stream");function h(e,t){return{value:e,done:t}}function p(e){var t=e[o];if(null!==t){var n=e[d].read();null!==n&&(e[l]=null,e[o]=null,e[s]=null,t(h(n,!1)))}}function b(e){process.nextTick(p,e)}function m(e,t){return function(n,r){e.then(function(){if(t[c]){n(h(void 0,!0));return}t[f](n,r)},r)}}var g=Object.getPrototypeOf(function(){}),v=Object.setPrototypeOf((i={get stream(){return this[d]},next:function(){var e,t=this,n=this[u];if(null!==n)return Promise.reject(n);if(this[c])return Promise.resolve(h(void 0,!0));if(this[d].destroyed)return new Promise(function(e,n){process.nextTick(function(){t[u]?n(t[u]):e(h(void 0,!0))})});var r=this[l];if(r)e=new Promise(m(r,this));else{var i=this[d].read();if(null!==i)return Promise.resolve(h(i,!1));e=new Promise(this[f])}return this[l]=e,e}},r(i,Symbol.asyncIterator,function(){return this}),r(i,"return",function(){var e=this;return new Promise(function(t,n){e[d].destroy(null,function(e){if(e){n(e);return}t(h(void 0,!0))})})}),i),g),y=function(e){var t,n=Object.create(v,(r(t={},d,{value:e,writable:!0}),r(t,o,{value:null,writable:!0}),r(t,s,{value:null,writable:!0}),r(t,u,{value:null,writable:!0}),r(t,c,{value:e._readableState.endEmitted,writable:!0}),r(t,f,{value:function(e,t){var r=n[d].read();r?(n[l]=null,n[o]=null,n[s]=null,e(h(r,!1))):(n[o]=e,n[s]=t)},writable:!0}),t));return n[l]=null,a(e,function(e){if(e&&"ERR_STREAM_PREMATURE_CLOSE"!==e.code){var t=n[s];null!==t&&(n[l]=null,n[o]=null,n[s]=null,t(e)),n[u]=e;return}var r=n[o];null!==r&&(n[l]=null,n[o]=null,n[s]=null,r(h(void 0,!0))),n[c]=!0}),e.on("readable",b.bind(null,n)),n};e.exports=y},77086(e,t,n){"use strict";function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function i(e){for(var t=1;t0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:"unshift",value:function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length}},{key:"shift",value:function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(e){if(0===this.length)return"";for(var t=this.head,n=""+t.data;t=t.next;)n+=e+t.data;return n}},{key:"concat",value:function(e){if(0===this.length)return c.alloc(0);for(var t=c.allocUnsafe(e>>>0),n=this.head,r=0;n;)d(n.data,t,r),r+=n.data.length,n=n.next;return t}},{key:"consume",value:function(e,t){var n;return ei.length?i.length:e;if(a===i.length?r+=i:r+=i.slice(0,e),0==(e-=a)){a===i.length?(++n,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=i.slice(a));break}++n}return this.length-=n,r}},{key:"_getBuffer",value:function(e){var t=c.allocUnsafe(e),n=this.head,r=1;for(n.data.copy(t),e-=n.data.length;n=n.next;){var i=n.data,a=e>i.length?i.length:e;if(i.copy(t,t.length-e,0,a),0==(e-=a)){a===i.length?(++r,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=i.slice(a));break}++r}return this.length-=r,t}},{key:f,value:function(e,t){return l(this,i({},t,{depth:0,customInspect:!1}))}}]),e}()},61195(e){"use strict";function t(e,t){var i=this,o=this._readableState&&this._readableState.destroyed,s=this._writableState&&this._writableState.destroyed;return o||s?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(a,this,e)):process.nextTick(a,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?i._writableState?i._writableState.errorEmitted?process.nextTick(r,i):(i._writableState.errorEmitted=!0,process.nextTick(n,i,e)):process.nextTick(n,i,e):t?(process.nextTick(r,i),t(e)):process.nextTick(r,i)}),this)}function n(e,t){a(e,t),r(e)}function r(e){(!e._writableState||e._writableState.emitClose)&&(!e._readableState||e._readableState.emitClose)&&e.emit("close")}function i(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function a(e,t){e.emit("error",t)}function o(e,t){var n=e._readableState,r=e._writableState;n&&n.autoDestroy||r&&r.autoDestroy?e.destroy(t):e.emit("error",t)}e.exports={destroy:t,undestroy:i,errorOrDestroy:o}},8610(e,t,n){"use strict";var r=n(94281).q.ERR_STREAM_PREMATURE_CLOSE;function i(e){var t=!1;return function(){if(!t){t=!0;for(var n=arguments.length,r=Array(n),i=0;i0,function(t){e||(e=t),t&&a.forEach(f),o||(a.forEach(f),i(e))})});return n.reduce(d)}e.exports=p},82457(e,t,n){"use strict";var r=n(94281).q.ERR_INVALID_OPT_VALUE;function i(e,t,n){return null!=e.highWaterMark?e.highWaterMark:t?e[n]:null}function a(e,t,n,a){var o=i(t,a,n);if(null!=o){if(!(isFinite(o)&&Math.floor(o)===o)||o<0){var s=a?n:"highWaterMark";throw new r(s,o)}return Math.floor(o)}return e.objectMode?16:16384}e.exports={getHighWaterMark:a}},22503(e,t,n){e.exports=n(17187).EventEmitter},61566(e,t){"use strict";t.__esModule=!0,t.default=void 0;var n=function(e){return"string"==typeof e?e:e?e.displayName||e.name||"Component":void 0};t.default=n},60375(e){"use strict";var t=Object.prototype.hasOwnProperty;function n(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!=e&&t!=t}function r(e,r){if(n(e,r))return!0;if("object"!=typeof e||null===e||"object"!=typeof r||null===r)return!1;var i=Object.keys(e),a=Object.keys(r);if(i.length!==a.length)return!1;for(var o=0;og,DE:()=>b,UY:()=>h,qC:()=>m,MT:()=>f});var s="function"==typeof Symbol&&Symbol.observable||"@@observable",u=function(){return Math.random().toString(36).substring(7).split("").join(".")},c={INIT:"@@redux/INIT"+u(),REPLACE:"@@redux/REPLACE"+u(),PROBE_UNKNOWN_ACTION:function(){return"@@redux/PROBE_UNKNOWN_ACTION"+u()}};function l(e){if("object"!=typeof e||null===e)return!1;for(var t=e;null!==Object.getPrototypeOf(t);)t=Object.getPrototypeOf(t);return Object.getPrototypeOf(e)===t}function f(e,t,n){if("function"==typeof t&&"function"==typeof n||"function"==typeof n&&"function"==typeof arguments[3])throw Error(o(0));if("function"==typeof t&&void 0===n&&(n=t,t=void 0),void 0!==n){if("function"!=typeof n)throw Error(o(1));return n(f)(e,t)}if("function"!=typeof e)throw Error(o(2));var r,i=e,a=t,u=[],d=u,h=!1;function p(){d===u&&(d=u.slice())}function b(){if(h)throw Error(o(3));return a}function m(e){if("function"!=typeof e)throw Error(o(4));if(h)throw Error(o(5));var t=!0;return p(),d.push(e),function(){if(t){if(h)throw Error(o(6));t=!1,p();var n=d.indexOf(e);d.splice(n,1),u=null}}}function g(e){if(!l(e))throw Error(o(7));if(void 0===e.type)throw Error(o(8));if(h)throw Error(o(9));try{h=!0,a=i(a,e)}finally{h=!1}for(var t=u=d,n=0;n]?|>=?|\?=|[-+\/=])(?=\s)/,lookbehind:!0},"string-operator":{pattern:/(\s)&&?(?=\s)/,lookbehind:!0,alias:"keyword"},"token-operator":[{pattern:/(\w)(?:->?|=>|[~|{}])(?=\w)/,lookbehind:!0,alias:"punctuation"},{pattern:/[|{}]/,alias:"punctuation"}],punctuation:/[,.:()]/}}e.exports=t,t.displayName="abap",t.aliases=[]},68313(e){"use strict";function t(e){var t,n;n="(?:ALPHA|BIT|CHAR|CR|CRLF|CTL|DIGIT|DQUOTE|HEXDIG|HTAB|LF|LWSP|OCTET|SP|VCHAR|WSP)",(t=e).languages.abnf={comment:/;.*/,string:{pattern:/(?:%[is])?"[^"\n\r]*"/,greedy:!0,inside:{punctuation:/^%[is]/}},range:{pattern:/%(?:b[01]+-[01]+|d\d+-\d+|x[A-F\d]+-[A-F\d]+)/i,alias:"number"},terminal:{pattern:/%(?:b[01]+(?:\.[01]+)*|d\d+(?:\.\d+)*|x[A-F\d]+(?:\.[A-F\d]+)*)/i,alias:"number"},repetition:{pattern:/(^|[^\w-])(?:\d*\*\d*|\d+)/,lookbehind:!0,alias:"operator"},definition:{pattern:/(^[ \t]*)(?:[a-z][\w-]*|<[^<>\r\n]*>)(?=\s*=)/m,lookbehind:!0,alias:"keyword",inside:{punctuation:/<|>/}},"core-rule":{pattern:RegExp("(?:(^|[^<\\w-])"+n+"|<"+n+">)(?![\\w-])","i"),lookbehind:!0,alias:["rule","constant"],inside:{punctuation:/<|>/}},rule:{pattern:/(^|[^<\w-])[a-z][\w-]*|<[^<>\r\n]*>/i,lookbehind:!0,inside:{punctuation:/<|>/}},operator:/=\/?|\//,punctuation:/[()\[\]]/}}e.exports=t,t.displayName="abnf",t.aliases=[]},5199(e){"use strict";function t(e){e.languages.actionscript=e.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|else|extends|finally|for|function|if|implements|import|in|instanceof|interface|internal|is|native|new|null|package|private|protected|public|return|super|switch|this|throw|try|typeof|use|var|void|while|with|dynamic|each|final|get|include|namespace|override|set|static)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<>?>?|[!=]=?)=?|[~?@]/}),e.languages.actionscript["class-name"].alias="function",e.languages.markup&&e.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:e.languages.markup}})}e.exports=t,t.displayName="actionscript",t.aliases=[]},89693(e){"use strict";function t(e){e.languages.ada={comment:/--.*/,string:/"(?:""|[^"\r\f\n])*"/i,number:[{pattern:/\b\d(?:_?\d)*#[\dA-F](?:_?[\dA-F])*(?:\.[\dA-F](?:_?[\dA-F])*)?#(?:E[+-]?\d(?:_?\d)*)?/i},{pattern:/\b\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:E[+-]?\d(?:_?\d)*)?\b/i}],"attr-name":/\b'\w+/i,keyword:/\b(?:abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|new|return|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|interface|is|limited|loop|mod|not|null|of|others|out|overriding|package|pragma|private|procedure|protected|raise|range|record|rem|renames|requeue|reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until|use|when|while|with|xor)\b/i,boolean:/\b(?:true|false)\b/i,operator:/<[=>]?|>=?|=>?|:=|\/=?|\*\*?|[&+-]/,punctuation:/\.\.?|[,;():]/,char:/'.'/,variable:/\b[a-z](?:\w)*\b/i}}e.exports=t,t.displayName="ada",t.aliases=[]},24001(e){"use strict";function t(e){var t;(t=e).languages.agda={comment:/\{-[\s\S]*?(?:-\}|$)|--.*/,string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},punctuation:/[(){}⦃⦄.;@]/,"class-name":{pattern:/((?:data|record) +)\S+/,lookbehind:!0},function:{pattern:/(^[ \t]*)(?!\s)[^:\r\n]+(?=:)/m,lookbehind:!0},operator:{pattern:/(^\s*|\s)(?:[=|:∀→λ\\?_]|->)(?=\s)/,lookbehind:!0},keyword:/\b(?:Set|abstract|constructor|data|eta-equality|field|forall|hiding|import|in|inductive|infix|infixl|infixr|instance|let|macro|module|mutual|no-eta-equality|open|overlap|pattern|postulate|primitive|private|public|quote|quoteContext|quoteGoal|quoteTerm|record|renaming|rewrite|syntax|tactic|unquote|unquoteDecl|unquoteDef|using|variable|where|with)\b/}}e.exports=t,t.displayName="agda",t.aliases=[]},18018(e){"use strict";function t(e){e.languages.al={comment:/\/\/.*|\/\*[\s\S]*?\*\//,string:{pattern:/'(?:''|[^'\r\n])*'(?!')|"(?:""|[^"\r\n])*"(?!")/,greedy:!0},function:{pattern:/(\b(?:event|procedure|trigger)\s+|(?:^|[^.])\.\s*)[a-z_]\w*(?=\s*\()/i,lookbehind:!0},keyword:[/\b(?:array|asserterror|begin|break|case|do|downto|else|end|event|exit|for|foreach|function|if|implements|in|indataset|interface|internal|local|of|procedure|program|protected|repeat|runonclient|securityfiltering|suppressdispose|temporary|then|to|trigger|until|var|while|with|withevents)\b/i,/\b(?:action|actions|addafter|addbefore|addfirst|addlast|area|assembly|chartpart|codeunit|column|controladdin|cuegroup|customizes|dataitem|dataset|dotnet|elements|enum|enumextension|extends|field|fieldattribute|fieldelement|fieldgroup|fieldgroups|fields|filter|fixed|grid|group|key|keys|label|labels|layout|modify|moveafter|movebefore|movefirst|movelast|page|pagecustomization|pageextension|part|profile|query|repeater|report|requestpage|schema|separator|systempart|table|tableelement|tableextension|textattribute|textelement|type|usercontrol|value|xmlport)\b/i],number:/\b(?:0x[\da-f]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)(?:F|U(?:LL?)?|LL?)?\b/i,boolean:/\b(?:false|true)\b/i,variable:/\b(?:Curr(?:FieldNo|Page|Report)|RequestOptionsPage|x?Rec)\b/,"class-name":/\b(?:automation|biginteger|bigtext|blob|boolean|byte|char|clienttype|code|completiontriggererrorlevel|connectiontype|database|dataclassification|datascope|date|dateformula|datetime|decimal|defaultlayout|dialog|dictionary|dotnetassembly|dotnettypedeclaration|duration|errorinfo|errortype|executioncontext|executionmode|fieldclass|fieldref|fieldtype|file|filterpagebuilder|guid|httpclient|httpcontent|httpheaders|httprequestmessage|httpresponsemessage|instream|integer|joker|jsonarray|jsonobject|jsontoken|jsonvalue|keyref|list|moduledependencyinfo|moduleinfo|none|notification|notificationscope|objecttype|option|outstream|pageresult|record|recordid|recordref|reportformat|securityfilter|sessionsettings|tableconnectiontype|tablefilter|testaction|testfield|testfilterfield|testpage|testpermissions|testrequestpage|text|textbuilder|textconst|textencoding|time|transactionmodel|transactiontype|variant|verbosity|version|view|views|webserviceactioncontext|webserviceactionresultcode|xmlattribute|xmlattributecollection|xmlcdata|xmlcomment|xmldeclaration|xmldocument|xmldocumenttype|xmlelement|xmlnamespacemanager|xmlnametable|xmlnode|xmlnodelist|xmlprocessinginstruction|xmlreadoptions|xmltext|xmlwriteoptions)\b/i,operator:/\.\.|:[=:]|[-+*/]=?|<>|[<>]=?|=|\b(?:and|div|mod|not|or|xor)\b/i,punctuation:/[()\[\]{}:.;,]/}}e.exports=t,t.displayName="al",t.aliases=[]},36363(e){"use strict";function t(e){e.languages.antlr4={comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,string:{pattern:/'(?:\\.|[^\\'\r\n])*'/,greedy:!0},"character-class":{pattern:/\[(?:\\.|[^\\\]\r\n])*\]/,greedy:!0,alias:"regex",inside:{range:{pattern:/([^[]|(?:^|[^\\])(?:\\\\)*\\\[)-(?!\])/,lookbehind:!0,alias:"punctuation"},escape:/\\(?:u(?:[a-fA-F\d]{4}|\{[a-fA-F\d]+\})|[pP]\{[=\w-]+\}|[^\r\nupP])/,punctuation:/[\[\]]/}},action:{pattern:/\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\}/,greedy:!0,inside:{content:{pattern:/(\{)[\s\S]+(?=\})/,lookbehind:!0},punctuation:/[{}]/}},command:{pattern:/(->\s*(?!\s))(?:\s*(?:,\s*)?\b[a-z]\w*(?:\s*\([^()\r\n]*\))?)+(?=\s*;)/i,lookbehind:!0,inside:{function:/\b\w+(?=\s*(?:[,(]|$))/,punctuation:/[,()]/}},annotation:{pattern:/@\w+(?:::\w+)*/,alias:"keyword"},label:{pattern:/#[ \t]*\w+/,alias:"punctuation"},keyword:/\b(?:catch|channels|finally|fragment|grammar|import|lexer|locals|mode|options|parser|returns|throws|tokens)\b/,definition:[{pattern:/\b[a-z]\w*(?=\s*:)/,alias:["rule","class-name"]},{pattern:/\b[A-Z]\w*(?=\s*:)/,alias:["token","constant"]}],constant:/\b[A-Z][A-Z_]*\b/,operator:/\.\.|->|[|~]|[*+?]\??/,punctuation:/[;:()=]/},e.languages.g4=e.languages.antlr4}e.exports=t,t.displayName="antlr4",t.aliases=["g4"]},35281(e){"use strict";function t(e){e.languages.apacheconf={comment:/#.*/,"directive-inline":{pattern:/(^[\t ]*)\b(?:AcceptFilter|AcceptPathInfo|AccessFileName|Action|Add(?:Alt|AltByEncoding|AltByType|Charset|DefaultCharset|Description|Encoding|Handler|Icon|IconByEncoding|IconByType|InputFilter|Language|ModuleInfo|OutputFilter|OutputFilterByType|Type)|Alias|AliasMatch|Allow(?:CONNECT|EncodedSlashes|Methods|Override|OverrideList)?|Anonymous(?:_LogEmail|_MustGiveEmail|_NoUserID|_VerifyEmail)?|AsyncRequestWorkerFactor|Auth(?:BasicAuthoritative|BasicFake|BasicProvider|BasicUseDigestAlgorithm|DBDUserPWQuery|DBDUserRealmQuery|DBMGroupFile|DBMType|DBMUserFile|Digest(?:Algorithm|Domain|NonceLifetime|Provider|Qop|ShmemSize)|Form(?:Authoritative|Body|DisableNoStore|FakeBasicAuth|Location|LoginRequiredLocation|LoginSuccessLocation|LogoutLocation|Method|Mimetype|Password|Provider|SitePassphrase|Size|Username)|GroupFile|LDAP(?:AuthorizePrefix|BindAuthoritative|BindDN|BindPassword|CharsetConfig|CompareAsUser|CompareDNOnServer|DereferenceAliases|GroupAttribute|GroupAttributeIsDN|InitialBindAsUser|InitialBindPattern|MaxSubGroupDepth|RemoteUserAttribute|RemoteUserIsDN|SearchAsUser|SubGroupAttribute|SubGroupClass|Url)|Merging|Name|Type|UserFile|nCache(?:Context|Enable|ProvideFor|SOCache|Timeout)|nzFcgiCheckAuthnProvider|nzFcgiDefineProvider|zDBDLoginToReferer|zDBDQuery|zDBDRedirectQuery|zDBMType|zSendForbiddenOnFailure)|BalancerGrowth|BalancerInherit|BalancerMember|BalancerPersist|BrowserMatch|BrowserMatchNoCase|BufferSize|BufferedLogs|CGIDScriptTimeout|CGIMapExtension|Cache(?:DefaultExpire|DetailHeader|DirLength|DirLevels|Disable|Enable|File|Header|IgnoreCacheControl|IgnoreHeaders|IgnoreNoLastMod|IgnoreQueryString|IgnoreURLSessionIdentifiers|KeyBaseURL|LastModifiedFactor|Lock|LockMaxAge|LockPath|MaxExpire|MaxFileSize|MinExpire|MinFileSize|NegotiatedDocs|QuickHandler|ReadSize|ReadTime|Root|Socache(?:MaxSize|MaxTime|MinTime|ReadSize|ReadTime)?|StaleOnError|StoreExpired|StoreNoStore|StorePrivate)|CharsetDefault|CharsetOptions|CharsetSourceEnc|CheckCaseOnly|CheckSpelling|ChrootDir|ContentDigest|CookieDomain|CookieExpires|CookieName|CookieStyle|CookieTracking|CoreDumpDirectory|CustomLog|DBDExptime|DBDInitSQL|DBDKeep|DBDMax|DBDMin|DBDParams|DBDPersist|DBDPrepareSQL|DBDriver|DTracePrivileges|Dav|DavDepthInfinity|DavGenericLockDB|DavLockDB|DavMinTimeout|DefaultIcon|DefaultLanguage|DefaultRuntimeDir|DefaultType|Define|Deflate(?:BufferSize|CompressionLevel|FilterNote|InflateLimitRequestBody|InflateRatio(?:Burst|Limit)|MemLevel|WindowSize)|Deny|DirectoryCheckHandler|DirectoryIndex|DirectoryIndexRedirect|DirectorySlash|DocumentRoot|DumpIOInput|DumpIOOutput|EnableExceptionHook|EnableMMAP|EnableSendfile|Error|ErrorDocument|ErrorLog|ErrorLogFormat|Example|ExpiresActive|ExpiresByType|ExpiresDefault|ExtFilterDefine|ExtFilterOptions|ExtendedStatus|FallbackResource|FileETag|FilterChain|FilterDeclare|FilterProtocol|FilterProvider|FilterTrace|ForceLanguagePriority|ForceType|ForensicLog|GprofDir|GracefulShutdownTimeout|Group|Header|HeaderName|Heartbeat(?:Address|Listen|MaxServers|Storage)|HostnameLookups|ISAPI(?:AppendLogToErrors|AppendLogToQuery|CacheFile|FakeAsync|LogNotSupported|ReadAheadBuffer)|IdentityCheck|IdentityCheckTimeout|ImapBase|ImapDefault|ImapMenu|Include|IncludeOptional|Index(?:HeadInsert|Ignore|IgnoreReset|Options|OrderDefault|StyleSheet)|InputSed|KeepAlive|KeepAliveTimeout|KeptBodySize|LDAP(?:CacheEntries|CacheTTL|ConnectionPoolTTL|ConnectionTimeout|LibraryDebug|OpCacheEntries|OpCacheTTL|ReferralHopLimit|Referrals|Retries|RetryDelay|SharedCacheFile|SharedCacheSize|Timeout|TrustedClientCert|TrustedGlobalCert|TrustedMode|VerifyServerCert)|LanguagePriority|Limit(?:InternalRecursion|Request(?:Body|FieldSize|Fields|Line)|XMLRequestBody)|Listen|ListenBackLog|LoadFile|LoadModule|LogFormat|LogLevel|LogMessage|LuaAuthzProvider|LuaCodeCache|Lua(?:Hook(?:AccessChecker|AuthChecker|CheckUserID|Fixups|InsertFilter|Log|MapToStorage|TranslateName|TypeChecker)|Inherit|InputFilter|MapHandler|OutputFilter|PackageCPath|PackagePath|QuickHandler|Root|Scope)|MMapFile|Max(?:ConnectionsPerChild|KeepAliveRequests|MemFree|RangeOverlaps|RangeReversals|Ranges|RequestWorkers|SpareServers|SpareThreads|Threads)|MergeTrailers|MetaDir|MetaFiles|MetaSuffix|MimeMagicFile|MinSpareServers|MinSpareThreads|ModMimeUsePathInfo|ModemStandard|MultiviewsMatch|Mutex|NWSSLTrustedCerts|NWSSLUpgradeable|NameVirtualHost|NoProxy|Options|Order|OutputSed|PassEnv|PidFile|PrivilegesMode|Protocol|ProtocolEcho|Proxy(?:AddHeaders|BadHeader|Block|Domain|ErrorOverride|ExpressDBMFile|ExpressDBMType|ExpressEnable|FtpDirCharset|FtpEscapeWildcards|FtpListOnWildcard|HTML(?:BufSize|CharsetOut|DocType|Enable|Events|Extended|Fixups|Interp|Links|Meta|StripComments|URLMap)|IOBufferSize|MaxForwards|Pass(?:Inherit|InterpolateEnv|Match|Reverse|ReverseCookieDomain|ReverseCookiePath)?|PreserveHost|ReceiveBufferSize|Remote|RemoteMatch|Requests|SCGIInternalRedirect|SCGISendfile|Set|SourceAddress|Status|Timeout|Via)|RLimitCPU|RLimitMEM|RLimitNPROC|ReadmeName|ReceiveBufferSize|Redirect|RedirectMatch|RedirectPermanent|RedirectTemp|ReflectorHeader|RemoteIP(?:Header|InternalProxy|InternalProxyList|ProxiesHeader|TrustedProxy|TrustedProxyList)|RemoveCharset|RemoveEncoding|RemoveHandler|RemoveInputFilter|RemoveLanguage|RemoveOutputFilter|RemoveType|RequestHeader|RequestReadTimeout|Require|Rewrite(?:Base|Cond|Engine|Map|Options|Rule)|SSIETag|SSIEndTag|SSIErrorMsg|SSILastModified|SSILegacyExprParser|SSIStartTag|SSITimeFormat|SSIUndefinedEcho|SSL(?:CACertificateFile|CACertificatePath|CADNRequestFile|CADNRequestPath|CARevocationCheck|CARevocationFile|CARevocationPath|CertificateChainFile|CertificateFile|CertificateKeyFile|CipherSuite|Compression|CryptoDevice|Engine|FIPS|HonorCipherOrder|InsecureRenegotiation|OCSP(?:DefaultResponder|Enable|OverrideResponder|ResponderTimeout|ResponseMaxAge|ResponseTimeSkew|UseRequestNonce)|OpenSSLConfCmd|Options|PassPhraseDialog|Protocol|Proxy(?:CACertificateFile|CACertificatePath|CARevocation(?:Check|File|Path)|CheckPeer(?:CN|Expire|Name)|CipherSuite|Engine|MachineCertificate(?:ChainFile|File|Path)|Protocol|Verify|VerifyDepth)|RandomSeed|RenegBufferSize|Require|RequireSSL|SRPUnknownUserSeed|SRPVerifierFile|Session(?:Cache|CacheTimeout|TicketKeyFile|Tickets)|Stapling(?:Cache|ErrorCacheTimeout|FakeTryLater|ForceURL|ResponderTimeout|ResponseMaxAge|ResponseTimeSkew|ReturnResponderErrors|StandardCacheTimeout)|StrictSNIVHostCheck|UseStapling|UserName|VerifyClient|VerifyDepth)|Satisfy|ScoreBoardFile|Script(?:Alias|AliasMatch|InterpreterSource|Log|LogBuffer|LogLength|Sock)?|SecureListen|SeeRequestTail|SendBufferSize|Server(?:Admin|Alias|Limit|Name|Path|Root|Signature|Tokens)|Session(?:Cookie(?:Name|Name2|Remove)|Crypto(?:Cipher|Driver|Passphrase|PassphraseFile)|DBD(?:CookieName|CookieName2|CookieRemove|DeleteLabel|InsertLabel|PerUser|SelectLabel|UpdateLabel)|Env|Exclude|Header|Include|MaxAge)?|SetEnv|SetEnvIf|SetEnvIfExpr|SetEnvIfNoCase|SetHandler|SetInputFilter|SetOutputFilter|StartServers|StartThreads|Substitute|Suexec|SuexecUserGroup|ThreadLimit|ThreadStackSize|ThreadsPerChild|TimeOut|TraceEnable|TransferLog|TypesConfig|UnDefine|UndefMacro|UnsetEnv|Use|UseCanonicalName|UseCanonicalPhysicalPort|User|UserDir|VHostCGIMode|VHostCGIPrivs|VHostGroup|VHostPrivs|VHostSecure|VHostUser|Virtual(?:DocumentRoot|ScriptAlias)(?:IP)?|WatchdogInterval|XBitHack|xml2EncAlias|xml2EncDefault|xml2StartParse)\b/im,lookbehind:!0,alias:"property"},"directive-block":{pattern:/<\/?\b(?:Auth[nz]ProviderAlias|Directory|DirectoryMatch|Else|ElseIf|Files|FilesMatch|If|IfDefine|IfModule|IfVersion|Limit|LimitExcept|Location|LocationMatch|Macro|Proxy|Require(?:All|Any|None)|VirtualHost)\b.*>/i,inside:{"directive-block":{pattern:/^<\/?\w+/,inside:{punctuation:/^<\/?/},alias:"tag"},"directive-block-parameter":{pattern:/.*[^>]/,inside:{punctuation:/:/,string:{pattern:/("|').*\1/,inside:{variable:/[$%]\{?(?:\w\.?[-+:]?)+\}?/}}},alias:"attr-value"},punctuation:/>/},alias:"tag"},"directive-flags":{pattern:/\[(?:[\w=],?)+\]/,alias:"keyword"},string:{pattern:/("|').*\1/,inside:{variable:/[$%]\{?(?:\w\.?[-+:]?)+\}?/}},variable:/[$%]\{?(?:\w\.?[-+:]?)+\}?/,regex:/\^?.*\$|\^.*\$?/}}e.exports=t,t.displayName="apacheconf",t.aliases=[]},10433(e,t,n){"use strict";var r=n(11114);function i(e){e.register(r),function(e){var t=/\b(?:abstract|activate|and|any|array|as|asc|autonomous|begin|bigdecimal|blob|boolean|break|bulk|by|byte|case|cast|catch|char|class|collect|commit|const|continue|currency|date|datetime|decimal|default|delete|desc|do|double|else|end|enum|exception|exit|export|extends|final|finally|float|for|from|global|goto|group|having|hint|if|implements|import|in|inner|insert|instanceof|int|integer|interface|into|join|like|limit|list|long|loop|map|merge|new|not|null|nulls|number|object|of|on|or|outer|override|package|parallel|pragma|private|protected|public|retrieve|return|rollback|select|set|short|sObject|sort|static|string|super|switch|synchronized|system|testmethod|then|this|throw|time|transaction|transient|trigger|try|undelete|update|upsert|using|virtual|void|webservice|when|where|while|get(?=\s*[{};])|(?:after|before)(?=\s+[a-z])|(?:inherited|with|without)\s+sharing)\b/i,n=/\b(?:(?=[a-z_]\w*\s*[<\[])|(?!))[A-Z_]\w*(?:\s*\.\s*[A-Z_]\w*)*\b(?:\s*(?:\[\s*\]|<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>))*/.source.replace(//g,function(){return t.source});function r(e){return RegExp(e.replace(//g,function(){return n}),"i")}var i={keyword:t,punctuation:/[()\[\]{};,:.<>]/};e.languages.apex={comment:e.languages.clike.comment,string:e.languages.clike.string,sql:{pattern:/((?:[=,({:]|\breturn)\s*)\[[^\[\]]*\]/i,lookbehind:!0,greedy:!0,alias:"language-sql",inside:e.languages.sql},annotation:{pattern:/@\w+\b/,alias:"punctuation"},"class-name":[{pattern:r(/(\b(?:class|enum|extends|implements|instanceof|interface|new|trigger\s+\w+\s+on)\s+)/.source),lookbehind:!0,inside:i},{pattern:r(/(\(\s*)(?=\s*\)\s*[\w(])/.source),lookbehind:!0,inside:i},{pattern:r(/(?=\s*\w+\s*[;=,(){:])/.source),inside:i}],trigger:{pattern:/(\btrigger\s+)\w+\b/i,lookbehind:!0,alias:"class-name"},keyword:t,function:/\b[a-z_]\w*(?=\s*\()/i,boolean:/\b(?:false|true)\b/i,number:/(?:\B\.\d+|\b\d+(?:\.\d+|L)?)\b/i,operator:/[!=](?:==?)?|\?\.?|&&|\|\||--|\+\+|[-+*/^&|]=?|:|<{1,3}=?/,punctuation:/[()\[\]{};,.]/}}(e)}e.exports=i,i.displayName="apex",i.aliases=[]},84039(e){"use strict";function t(e){e.languages.apl={comment:/(?:⍝|#[! ]).*$/m,string:{pattern:/'(?:[^'\r\n]|'')*'/,greedy:!0},number:/¯?(?:\d*\.?\b\d+(?:e[+¯]?\d+)?|¯|∞)(?:j¯?(?:(?:\d+(?:\.\d+)?|\.\d+)(?:e[+¯]?\d+)?|¯|∞))?/i,statement:/:[A-Z][a-z][A-Za-z]*\b/,"system-function":{pattern:/⎕[A-Z]+/i,alias:"function"},constant:/[⍬⌾#⎕⍞]/,function:/[-+×÷⌈⌊∣|⍳⍸?*⍟○!⌹<≤=>≥≠≡≢∊⍷∪∩~∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⊆⊇⌷⍋⍒⊤⊥⍕⍎⊣⊢⍁⍂≈⍯↗¤→]/,"monadic-operator":{pattern:/[\\\/⌿⍀¨⍨⌶&∥]/,alias:"operator"},"dyadic-operator":{pattern:/[.⍣⍠⍤∘⌸@⌺⍥]/,alias:"operator"},assignment:{pattern:/←/,alias:"keyword"},punctuation:/[\[;\]()◇⋄]/,dfn:{pattern:/[{}⍺⍵⍶⍹∇⍫:]/,alias:"builtin"}}}e.exports=t,t.displayName="apl",t.aliases=[]},71336(e){"use strict";function t(e){e.languages.applescript={comment:[/\(\*(?:\(\*(?:[^*]|\*(?!\)))*\*\)|(?!\(\*)[\s\S])*?\*\)/,/--.+/,/#.+/],string:/"(?:\\.|[^"\\\r\n])*"/,number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e-?\d+)?\b/i,operator:[/[&=≠≤≥*+\-\/÷^]|[<>]=?/,/\b(?:(?:start|begin|end)s? with|(?:(?:does not|doesn't) contain|contains?)|(?:is|isn't|is not) (?:in|contained by)|(?:(?:is|isn't|is not) )?(?:greater|less) than(?: or equal)?(?: to)?|(?:(?:does not|doesn't) come|comes) (?:before|after)|(?:is|isn't|is not) equal(?: to)?|(?:(?:does not|doesn't) equal|equals|equal to|isn't|is not)|(?:a )?(?:ref(?: to)?|reference to)|(?:and|or|div|mod|as|not))\b/],keyword:/\b(?:about|above|after|against|apart from|around|aside from|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|continue|copy|does|eighth|else|end|equal|error|every|exit|false|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|instead of|into|is|it|its|last|local|me|middle|my|ninth|of|on|onto|out of|over|prop|property|put|repeat|return|returning|second|set|seventh|since|sixth|some|tell|tenth|that|the|then|third|through|thru|timeout|times|to|transaction|true|try|until|where|while|whose|with|without)\b/,class:{pattern:/\b(?:alias|application|boolean|class|constant|date|file|integer|list|number|POSIX file|real|record|reference|RGB color|script|text|centimetres|centimeters|feet|inches|kilometres|kilometers|metres|meters|miles|yards|square feet|square kilometres|square kilometers|square metres|square meters|square miles|square yards|cubic centimetres|cubic centimeters|cubic feet|cubic inches|cubic metres|cubic meters|cubic yards|gallons|litres|liters|quarts|grams|kilograms|ounces|pounds|degrees Celsius|degrees Fahrenheit|degrees Kelvin)\b/,alias:"builtin"},punctuation:/[{}():,¬«»《》]/}}e.exports=t,t.displayName="applescript",t.aliases=[]},4481(e){"use strict";function t(e){e.languages.aql={comment:/\/\/.*|\/\*[\s\S]*?\*\//,property:{pattern:/([{,]\s*)(?:(?!\d)\w+|(["'´`])(?:(?!\2)[^\\\r\n]|\\.)*\2)(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(["'´`])(?:(?!\1)[^\\\r\n]|\\.)*\1/,greedy:!0},variable:/@@?\w+/,keyword:[{pattern:/(\bWITH\s+)COUNT(?=\s+INTO\b)/i,lookbehind:!0},/\b(?:AGGREGATE|ALL|AND|ANY|ASC|COLLECT|DESC|DISTINCT|FILTER|FOR|GRAPH|IN|INBOUND|INSERT|INTO|K_PATHS|K_SHORTEST_PATHS|LET|LIKE|LIMIT|NONE|NOT|NULL|OR|OUTBOUND|REMOVE|REPLACE|RETURN|SHORTEST_PATH|SORT|UPDATE|UPSERT|WINDOW|WITH)\b/i,{pattern:/(^|[^\w.[])(?:KEEP|PRUNE|SEARCH|TO)\b/i,lookbehind:!0},{pattern:/(^|[^\w.[])(?:CURRENT|NEW|OLD)\b/,lookbehind:!0},{pattern:/\bOPTIONS(?=\s*\{)/i}],function:/\b(?!\d)\w+(?=\s*\()/,boolean:/\b(?:true|false)\b/i,range:{pattern:/\.\./,alias:"operator"},number:[/\b0b[01]+/i,/\b0x[0-9a-f]+/i,/(?:\B\.\d+|\b(?:0|[1-9]\d*)(?:\.\d+)?)(?:e[+-]?\d+)?/i],operator:/\*{2,}|[=!]~|[!=<>]=?|&&|\|\||[-+*/%]/,punctuation:/::|[?.:,;()[\]{}]/}}e.exports=t,t.displayName="aql",t.aliases=[]},2159(e,t,n){"use strict";var r=n(80096);function i(e){e.register(r),e.languages.arduino=e.languages.extend("cpp",{constant:/\b(?:DIGITAL_MESSAGE|FIRMATA_STRING|ANALOG_MESSAGE|REPORT_DIGITAL|REPORT_ANALOG|INPUT_PULLUP|SET_PIN_MODE|INTERNAL2V56|SYSTEM_RESET|LED_BUILTIN|INTERNAL1V1|SYSEX_START|INTERNAL|EXTERNAL|DEFAULT|OUTPUT|INPUT|HIGH|LOW)\b/,keyword:/\b(?:setup|if|else|while|do|for|return|in|instanceof|default|function|loop|goto|switch|case|new|try|throw|catch|finally|null|break|continue|boolean|bool|void|byte|word|string|String|array|int|long|integer|double)\b/,builtin:/\b(?:KeyboardController|MouseController|SoftwareSerial|EthernetServer|EthernetClient|LiquidCrystal|LiquidCrystal_I2C|RobotControl|GSMVoiceCall|EthernetUDP|EsploraTFT|HttpClient|RobotMotor|WiFiClient|GSMScanner|FileSystem|Scheduler|GSMServer|YunClient|YunServer|IPAddress|GSMClient|GSMModem|Keyboard|Ethernet|Console|GSMBand|Esplora|Stepper|Process|WiFiUDP|GSM_SMS|Mailbox|USBHost|Firmata|PImage|Client|Server|GSMPIN|FileIO|Bridge|Serial|EEPROM|Stream|Mouse|Audio|Servo|File|Task|GPRS|WiFi|Wire|TFT|GSM|SPI|SD|runShellCommandAsynchronously|analogWriteResolution|retrieveCallingNumber|printFirmwareVersion|analogReadResolution|sendDigitalPortPair|noListenOnLocalhost|readJoystickButton|setFirmwareVersion|readJoystickSwitch|scrollDisplayRight|getVoiceCallStatus|scrollDisplayLeft|writeMicroseconds|delayMicroseconds|beginTransmission|getSignalStrength|runAsynchronously|getAsynchronously|listenOnLocalhost|getCurrentCarrier|readAccelerometer|messageAvailable|sendDigitalPorts|lineFollowConfig|countryNameWrite|runShellCommand|readStringUntil|rewindDirectory|readTemperature|setClockDivider|readLightSensor|endTransmission|analogReference|detachInterrupt|countryNameRead|attachInterrupt|encryptionType|readBytesUntil|robotNameWrite|readMicrophone|robotNameRead|cityNameWrite|userNameWrite|readJoystickY|readJoystickX|mouseReleased|openNextFile|scanNetworks|noInterrupts|digitalWrite|beginSpeaker|mousePressed|isActionDone|mouseDragged|displayLogos|noAutoscroll|addParameter|remoteNumber|getModifiers|keyboardRead|userNameRead|waitContinue|processInput|parseCommand|printVersion|readNetworks|writeMessage|blinkVersion|cityNameRead|readMessage|setDataMode|parsePacket|isListening|setBitOrder|beginPacket|isDirectory|motorsWrite|drawCompass|digitalRead|clearScreen|serialEvent|rightToLeft|setTextSize|leftToRight|requestFrom|keyReleased|compassRead|analogWrite|interrupts|WiFiServer|disconnect|playMelody|parseFloat|autoscroll|getPINUsed|setPINUsed|setTimeout|sendAnalog|readSlider|analogRead|beginWrite|createChar|motorsStop|keyPressed|tempoWrite|readButton|subnetMask|debugPrint|macAddress|writeGreen|randomSeed|attachGPRS|readString|sendString|remotePort|releaseAll|mouseMoved|background|getXChange|getYChange|answerCall|getResult|voiceCall|endPacket|constrain|getSocket|writeJSON|getButton|available|connected|findUntil|readBytes|exitValue|readGreen|writeBlue|startLoop|isPressed|sendSysex|pauseMode|gatewayIP|setCursor|getOemKey|tuneWrite|noDisplay|loadImage|switchPIN|onRequest|onReceive|changePIN|playFile|noBuffer|parseInt|overflow|checkPIN|knobRead|beginTFT|bitClear|updateIR|bitWrite|position|writeRGB|highByte|writeRed|setSpeed|readBlue|noStroke|remoteIP|transfer|shutdown|hangCall|beginSMS|endWrite|attached|maintain|noCursor|checkReg|checkPUK|shiftOut|isValid|shiftIn|pulseIn|connect|println|localIP|pinMode|getIMEI|display|noBlink|process|getBand|running|beginSD|drawBMP|lowByte|setBand|release|bitRead|prepare|pointTo|readRed|setMode|noFill|remove|listen|stroke|detach|attach|noTone|exists|buffer|height|bitSet|circle|config|cursor|random|IRread|setDNS|endSMS|getKey|micros|millis|begin|print|write|ready|flush|width|isPIN|blink|clear|press|mkdir|rmdir|close|point|yield|image|BSSID|click|delay|read|text|move|peek|beep|rect|line|open|seek|fill|size|turn|stop|home|find|step|tone|sqrt|RSSI|SSID|end|bit|tan|cos|sin|pow|map|abs|max|min|get|run|put)\b/})}e.exports=i,i.displayName="arduino",i.aliases=[]},60274(e){"use strict";function t(e){e.languages.arff={comment:/%.*/,string:{pattern:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},keyword:/@(?:attribute|data|end|relation)\b/i,number:/\b\d+(?:\.\d+)?\b/,punctuation:/[{},]/}}e.exports=t,t.displayName="arff",t.aliases=[]},18738(e){"use strict";function t(e){!function(e){var t={pattern:/(^[ \t]*)\[(?!\[)(?:(["'$`])(?:(?!\2)[^\\]|\\.)*\2|\[(?:[^\[\]\\]|\\.)*\]|[^\[\]\\"'$`]|\\.)*\]/m,lookbehind:!0,inside:{quoted:{pattern:/([$`])(?:(?!\1)[^\\]|\\.)*\1/,inside:{punctuation:/^[$`]|[$`]$/}},interpreted:{pattern:/'(?:[^'\\]|\\.)*'/,inside:{punctuation:/^'|'$/}},string:/"(?:[^"\\]|\\.)*"/,variable:/\w+(?==)/,punctuation:/^\[|\]$|,/,operator:/=/,"attr-value":/(?!^\s+$).+/}},n=e.languages.asciidoc={"comment-block":{pattern:/^(\/{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1/m,alias:"comment"},table:{pattern:/^\|={3,}(?:(?:\r?\n|\r(?!\n)).*)*?(?:\r?\n|\r)\|={3,}$/m,inside:{specifiers:{pattern:/(?!\|)(?:(?:(?:\d+(?:\.\d+)?|\.\d+)[+*])?(?:[<^>](?:\.[<^>])?|\.[<^>])?[a-z]*)(?=\|)/,alias:"attr-value"},punctuation:{pattern:/(^|[^\\])[|!]=*/,lookbehind:!0}}},"passthrough-block":{pattern:/^(\+{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,inside:{punctuation:/^\++|\++$/}},"literal-block":{pattern:/^(-{4,}|\.{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,inside:{punctuation:/^(?:-+|\.+)|(?:-+|\.+)$/}},"other-block":{pattern:/^(--|\*{4,}|_{4,}|={4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,inside:{punctuation:/^(?:-+|\*+|_+|=+)|(?:-+|\*+|_+|=+)$/}},"list-punctuation":{pattern:/(^[ \t]*)(?:-|\*{1,5}|\.{1,5}|(?:[a-z]|\d+)\.|[xvi]+\))(?= )/im,lookbehind:!0,alias:"punctuation"},"list-label":{pattern:/(^[ \t]*)[a-z\d].+(?::{2,4}|;;)(?=\s)/im,lookbehind:!0,alias:"symbol"},"indented-block":{pattern:/((\r?\n|\r)\2)([ \t]+)\S.*(?:(?:\r?\n|\r)\3.+)*(?=\2{2}|$)/,lookbehind:!0},comment:/^\/\/.*/m,title:{pattern:/^.+(?:\r?\n|\r)(?:={3,}|-{3,}|~{3,}|\^{3,}|\+{3,})$|^={1,5} .+|^\.(?![\s.]).*/m,alias:"important",inside:{punctuation:/^(?:\.|=+)|(?:=+|-+|~+|\^+|\++)$/}},"attribute-entry":{pattern:/^:[^:\r\n]+:(?: .*?(?: \+(?:\r?\n|\r).*?)*)?$/m,alias:"tag"},attributes:t,hr:{pattern:/^'{3,}$/m,alias:"punctuation"},"page-break":{pattern:/^<{3,}$/m,alias:"punctuation"},admonition:{pattern:/^(?:TIP|NOTE|IMPORTANT|WARNING|CAUTION):/m,alias:"keyword"},callout:[{pattern:/(^[ \t]*)/m,lookbehind:!0,alias:"symbol"},{pattern:/<\d+>/,alias:"symbol"}],macro:{pattern:/\b[a-z\d][a-z\d-]*::?(?:[^\s\[\]]*\[(?:[^\]\\"']|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,inside:{function:/^[a-z\d-]+(?=:)/,punctuation:/^::?/,attributes:{pattern:/(?:\[(?:[^\]\\"']|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,inside:t.inside}}},inline:{pattern:/(^|[^\\])(?:(?:\B\[(?:[^\]\\"']|(["'])(?:(?!\2)[^\\]|\\.)*\2|\\.)*\])?(?:\b_(?!\s)(?: _|[^_\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: _|[^_\\\r\n]|\\.)+)*_\b|\B``(?!\s).+?(?:(?:\r?\n|\r).+?)*''\B|\B`(?!\s)(?:[^`'\s]|\s+\S)+['`]\B|\B(['*+#])(?!\s)(?: \3|(?!\3)[^\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: \3|(?!\3)[^\\\r\n]|\\.)+)*\3\B)|(?:\[(?:[^\]\\"']|(["'])(?:(?!\4)[^\\]|\\.)*\4|\\.)*\])?(?:(__|\*\*|\+\+\+?|##|\$\$|[~^]).+?(?:(?:\r?\n|\r).+?)*\5|\{[^}\r\n]+\}|\[\[\[?.+?(?:(?:\r?\n|\r).+?)*\]?\]\]|<<.+?(?:(?:\r?\n|\r).+?)*>>|\(\(\(?.+?(?:(?:\r?\n|\r).+?)*\)?\)\)))/m,lookbehind:!0,inside:{attributes:t,url:{pattern:/^(?:\[\[\[?.+?\]?\]\]|<<.+?>>)$/,inside:{punctuation:/^(?:\[\[\[?|<<)|(?:\]\]\]?|>>)$/}},"attribute-ref":{pattern:/^\{.+\}$/,inside:{variable:{pattern:/(^\{)[a-z\d,+_-]+/,lookbehind:!0},operator:/^[=?!#%@$]|!(?=[:}])/,punctuation:/^\{|\}$|::?/}},italic:{pattern:/^(['_])[\s\S]+\1$/,inside:{punctuation:/^(?:''?|__?)|(?:''?|__?)$/}},bold:{pattern:/^\*[\s\S]+\*$/,inside:{punctuation:/^\*\*?|\*\*?$/}},punctuation:/^(?:``?|\+{1,3}|##?|\$\$|[~^]|\(\(\(?)|(?:''?|\+{1,3}|##?|\$\$|[~^`]|\)?\)\))$/}},replacement:{pattern:/\((?:C|TM|R)\)/,alias:"builtin"},entity:/&#?[\da-z]{1,8};/i,"line-continuation":{pattern:/(^| )\+$/m,lookbehind:!0,alias:"punctuation"}};function r(e){e=e.split(" ");for(var t={},r=0,i=e.length;r/i,alias:"tag",inside:{"page-directive":{pattern:/<%\s*@\s*(?:Assembly|Control|Implements|Import|Master(?:Type)?|OutputCache|Page|PreviousPageType|Reference|Register)?|%>/i,alias:"tag"},rest:e.languages.markup.tag.inside}},directive:{pattern:/<%.*%>/i,alias:"tag",inside:{directive:{pattern:/<%\s*?[$=%#:]{0,2}|%>/i,alias:"tag"},rest:e.languages.csharp}}}),e.languages.aspnet.tag.pattern=/<(?!%)\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,e.languages.insertBefore("inside","punctuation",{directive:e.languages.aspnet.directive},e.languages.aspnet.tag.inside["attr-value"]),e.languages.insertBefore("aspnet","comment",{"asp-comment":{pattern:/<%--[\s\S]*?--%>/,alias:["asp","comment"]}}),e.languages.insertBefore("aspnet",e.languages.javascript?"script":"tag",{"asp-script":{pattern:/(]*>)[\s\S]*?(?=<\/script>)/i,lookbehind:!0,alias:["asp","script"],inside:e.languages.csharp||{}}})}e.exports=i,i.displayName="aspnet",i.aliases=[]},6681(e){"use strict";function t(e){e.languages.autohotkey={comment:[{pattern:/(^|\s);.*/,lookbehind:!0},{pattern:/(^[\t ]*)\/\*(?:[\r\n](?![ \t]*\*\/)|[^\r\n])*(?:[\r\n][ \t]*\*\/)?/m,lookbehind:!0,greedy:!0}],tag:{pattern:/^([ \t]*)[^\s,`":]+(?=:[ \t]*$)/m,lookbehind:!0},string:/"(?:[^"\n\r]|"")*"/m,variable:/%\w+%/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/\?|\/\/?=?|:=|\|[=|]?|&[=&]?|\+[=+]?|-[=-]?|\*[=*]?|<(?:<=?|>|=)?|>>?=?|[.^!=~]=?|\b(?:AND|NOT|OR)\b/,boolean:/\b(?:true|false)\b/,selector:/\b(?:AutoTrim|BlockInput|Break|Click|ClipWait|Continue|Control|ControlClick|ControlFocus|ControlGet|ControlGetFocus|ControlGetPos|ControlGetText|ControlMove|ControlSend|ControlSendRaw|ControlSetText|CoordMode|Critical|DetectHiddenText|DetectHiddenWindows|Drive|DriveGet|DriveSpaceFree|EnvAdd|EnvDiv|EnvGet|EnvMult|EnvSet|EnvSub|EnvUpdate|Exit|ExitApp|FileAppend|FileCopy|FileCopyDir|FileCreateDir|FileCreateShortcut|FileDelete|FileEncoding|FileGetAttrib|FileGetShortcut|FileGetSize|FileGetTime|FileGetVersion|FileInstall|FileMove|FileMoveDir|FileRead|FileReadLine|FileRecycle|FileRecycleEmpty|FileRemoveDir|FileSelectFile|FileSelectFolder|FileSetAttrib|FileSetTime|FormatTime|GetKeyState|Gosub|Goto|GroupActivate|GroupAdd|GroupClose|GroupDeactivate|Gui|GuiControl|GuiControlGet|Hotkey|ImageSearch|IniDelete|IniRead|IniWrite|Input|InputBox|KeyWait|ListHotkeys|ListLines|ListVars|Loop|Menu|MouseClick|MouseClickDrag|MouseGetPos|MouseMove|MsgBox|OnExit|OutputDebug|Pause|PixelGetColor|PixelSearch|PostMessage|Process|Progress|Random|RegDelete|RegRead|RegWrite|Reload|Repeat|Return|Run|RunAs|RunWait|Send|SendEvent|SendInput|SendMessage|SendMode|SendPlay|SendRaw|SetBatchLines|SetCapslockState|SetControlDelay|SetDefaultMouseSpeed|SetEnv|SetFormat|SetKeyDelay|SetMouseDelay|SetNumlockState|SetRegView|SetScrollLockState|SetStoreCapslockMode|SetTimer|SetTitleMatchMode|SetWinDelay|SetWorkingDir|Shutdown|Sleep|Sort|SoundBeep|SoundGet|SoundGetWaveVolume|SoundPlay|SoundSet|SoundSetWaveVolume|SplashImage|SplashTextOff|SplashTextOn|SplitPath|StatusBarGetText|StatusBarWait|StringCaseSense|StringGetPos|StringLeft|StringLen|StringLower|StringMid|StringReplace|StringRight|StringSplit|StringTrimLeft|StringTrimRight|StringUpper|Suspend|SysGet|Thread|ToolTip|Transform|TrayTip|URLDownloadToFile|WinActivate|WinActivateBottom|WinClose|WinGet|WinGetActiveStats|WinGetActiveTitle|WinGetClass|WinGetPos|WinGetText|WinGetTitle|WinHide|WinKill|WinMaximize|WinMenuSelectItem|WinMinimize|WinMinimizeAll|WinMinimizeAllUndo|WinMove|WinRestore|WinSet|WinSetTitle|WinShow|WinWait|WinWaitActive|WinWaitClose|WinWaitNotActive)\b/i,constant:/\b(?:a_ahkpath|a_ahkversion|a_appdata|a_appdatacommon|a_autotrim|a_batchlines|a_caretx|a_carety|a_computername|a_controldelay|a_cursor|a_dd|a_ddd|a_dddd|a_defaultmousespeed|a_desktop|a_desktopcommon|a_detecthiddentext|a_detecthiddenwindows|a_endchar|a_eventinfo|a_exitreason|a_fileencoding|a_formatfloat|a_formatinteger|a_gui|a_guievent|a_guicontrol|a_guicontrolevent|a_guiheight|a_guiwidth|a_guix|a_guiy|a_hour|a_iconfile|a_iconhidden|a_iconnumber|a_icontip|a_index|a_ipaddress1|a_ipaddress2|a_ipaddress3|a_ipaddress4|a_is64bitos|a_isadmin|a_iscompiled|a_iscritical|a_ispaused|a_issuspended|a_isunicode|a_keydelay|a_language|a_lasterror|a_linefile|a_linenumber|a_loopfield|a_loopfileattrib|a_loopfiledir|a_loopfileext|a_loopfilefullpath|a_loopfilelongpath|a_loopfilename|a_loopfileshortname|a_loopfileshortpath|a_loopfilesize|a_loopfilesizekb|a_loopfilesizemb|a_loopfiletimeaccessed|a_loopfiletimecreated|a_loopfiletimemodified|a_loopreadline|a_loopregkey|a_loopregname|a_loopregsubkey|a_loopregtimemodified|a_loopregtype|a_mday|a_min|a_mm|a_mmm|a_mmmm|a_mon|a_mousedelay|a_msec|a_mydocuments|a_now|a_nowutc|a_numbatchlines|a_ostype|a_osversion|a_priorhotkey|a_priorkey|programfiles|a_programfiles|a_programs|a_programscommon|a_ptrsize|a_regview|a_screendpi|a_screenheight|a_screenwidth|a_scriptdir|a_scriptfullpath|a_scripthwnd|a_scriptname|a_sec|a_space|a_startmenu|a_startmenucommon|a_startup|a_startupcommon|a_stringcasesense|a_tab|a_temp|a_thisfunc|a_thishotkey|a_thislabel|a_thismenu|a_thismenuitem|a_thismenuitempos|a_tickcount|a_timeidle|a_timeidlephysical|a_timesincepriorhotkey|a_timesincethishotkey|a_titlematchmode|a_titlematchmodespeed|a_username|a_wday|a_windelay|a_windir|a_workingdir|a_yday|a_year|a_yweek|a_yyyy|clipboard|clipboardall|comspec|errorlevel)\b/i,builtin:/\b(?:abs|acos|asc|asin|atan|ceil|chr|class|comobjactive|comobjarray|comobjconnect|comobjcreate|comobjerror|comobjflags|comobjget|comobjquery|comobjtype|comobjvalue|cos|dllcall|exp|fileexist|Fileopen|floor|format|il_add|il_create|il_destroy|instr|substr|isfunc|islabel|IsObject|ln|log|lv_add|lv_delete|lv_deletecol|lv_getcount|lv_getnext|lv_gettext|lv_insert|lv_insertcol|lv_modify|lv_modifycol|lv_setimagelist|ltrim|rtrim|mod|onmessage|numget|numput|registercallback|regexmatch|regexreplace|round|sin|tan|sqrt|strlen|strreplace|sb_seticon|sb_setparts|sb_settext|strsplit|tv_add|tv_delete|tv_getchild|tv_getcount|tv_getnext|tv_get|tv_getparent|tv_getprev|tv_getselection|tv_gettext|tv_modify|varsetcapacity|winactive|winexist|__New|__Call|__Get|__Set)\b/i,symbol:/\b(?:alt|altdown|altup|appskey|backspace|browser_back|browser_favorites|browser_forward|browser_home|browser_refresh|browser_search|browser_stop|bs|capslock|ctrl|ctrlbreak|ctrldown|ctrlup|del|delete|down|end|enter|esc|escape|f1|f10|f11|f12|f13|f14|f15|f16|f17|f18|f19|f2|f20|f21|f22|f23|f24|f3|f4|f5|f6|f7|f8|f9|home|ins|insert|joy1|joy10|joy11|joy12|joy13|joy14|joy15|joy16|joy17|joy18|joy19|joy2|joy20|joy21|joy22|joy23|joy24|joy25|joy26|joy27|joy28|joy29|joy3|joy30|joy31|joy32|joy4|joy5|joy6|joy7|joy8|joy9|joyaxes|joybuttons|joyinfo|joyname|joypov|joyr|joyu|joyv|joyx|joyy|joyz|lalt|launch_app1|launch_app2|launch_mail|launch_media|lbutton|lcontrol|lctrl|left|lshift|lwin|lwindown|lwinup|mbutton|media_next|media_play_pause|media_prev|media_stop|numlock|numpad0|numpad1|numpad2|numpad3|numpad4|numpad5|numpad6|numpad7|numpad8|numpad9|numpadadd|numpadclear|numpaddel|numpaddiv|numpaddot|numpaddown|numpadend|numpadenter|numpadhome|numpadins|numpadleft|numpadmult|numpadpgdn|numpadpgup|numpadright|numpadsub|numpadup|pgdn|pgup|printscreen|ralt|rbutton|rcontrol|rctrl|right|rshift|rwin|rwindown|rwinup|scrolllock|shift|shiftdown|shiftup|space|tab|up|volume_down|volume_mute|volume_up|wheeldown|wheelleft|wheelright|wheelup|xbutton1|xbutton2)\b/i,important:/#\b(?:AllowSameLineComments|ClipboardTimeout|CommentFlag|DerefChar|ErrorStdOut|EscapeChar|HotkeyInterval|HotkeyModifierTimeout|Hotstring|If|IfTimeout|IfWinActive|IfWinExist|IfWinNotActive|IfWinNotExist|Include|IncludeAgain|InputLevel|InstallKeybdHook|InstallMouseHook|KeyHistory|MaxHotkeysPerInterval|MaxMem|MaxThreads|MaxThreadsBuffer|MaxThreadsPerHotkey|MenuMaskKey|NoEnv|NoTrayIcon|Persistent|SingleInstance|UseHook|Warn|WinActivateForce)\b/i,keyword:/\b(?:Abort|AboveNormal|Add|ahk_class|ahk_exe|ahk_group|ahk_id|ahk_pid|All|Alnum|Alpha|AltSubmit|AltTab|AltTabAndMenu|AltTabMenu|AltTabMenuDismiss|AlwaysOnTop|AutoSize|Background|BackgroundTrans|BelowNormal|between|BitAnd|BitNot|BitOr|BitShiftLeft|BitShiftRight|BitXOr|Bold|Border|Button|ByRef|Checkbox|Checked|CheckedGray|Choose|ChooseString|Close|Color|ComboBox|Contains|ControlList|Count|Date|DateTime|Days|DDL|Default|DeleteAll|Delimiter|Deref|Destroy|Digit|Disable|Disabled|DropDownList|Edit|Eject|Else|Enable|Enabled|Error|Exist|Expand|ExStyle|FileSystem|First|Flash|Float|FloatFast|Focus|Font|for|global|Grid|Group|GroupBox|GuiClose|GuiContextMenu|GuiDropFiles|GuiEscape|GuiSize|Hdr|Hidden|Hide|High|HKCC|HKCR|HKCU|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_LOCAL_MACHINE|HKEY_USERS|HKLM|HKU|Hours|HScroll|Icon|IconSmall|ID|IDLast|If|IfEqual|IfExist|IfGreater|IfGreaterOrEqual|IfInString|IfLess|IfLessOrEqual|IfMsgBox|IfNotEqual|IfNotExist|IfNotInString|IfWinActive|IfWinExist|IfWinNotActive|IfWinNotExist|Ignore|ImageList|in|Integer|IntegerFast|Interrupt|is|italic|Join|Label|LastFound|LastFoundExist|Limit|Lines|List|ListBox|ListView|local|Lock|Logoff|Low|Lower|Lowercase|MainWindow|Margin|Maximize|MaximizeBox|MaxSize|Minimize|MinimizeBox|MinMax|MinSize|Minutes|MonthCal|Mouse|Move|Multi|NA|No|NoActivate|NoDefault|NoHide|NoIcon|NoMainWindow|norm|Normal|NoSort|NoSortHdr|NoStandard|Not|NoTab|NoTimers|Number|Off|Ok|On|OwnDialogs|Owner|Parse|Password|Picture|Pixel|Pos|Pow|Priority|ProcessName|Radio|Range|Read|ReadOnly|Realtime|Redraw|REG_BINARY|REG_DWORD|REG_EXPAND_SZ|REG_MULTI_SZ|REG_SZ|Region|Relative|Rename|Report|Resize|Restore|Retry|RGB|Screen|Seconds|Section|Serial|SetLabel|ShiftAltTab|Show|Single|Slider|SortDesc|Standard|static|Status|StatusBar|StatusCD|strike|Style|Submit|SysMenu|Tab2|TabStop|Text|Theme|Tile|ToggleCheck|ToggleEnable|ToolWindow|Top|Topmost|TransColor|Transparent|Tray|TreeView|TryAgain|Throw|Try|Catch|Finally|Type|UnCheck|underline|Unicode|Unlock|Until|UpDown|Upper|Uppercase|UseErrorLevel|Vis|VisFirst|Visible|VScroll|Wait|WaitClose|WantCtrlA|WantF2|WantReturn|While|Wrap|Xdigit|xm|xp|xs|Yes|ym|yp|ys)\b/i,function:/[^(); \t,\n+*\-=?>:\\\/<&%\[\]]+(?=\()/m,punctuation:/[{}[\]():,]/}}e.exports=t,t.displayName="autohotkey",t.aliases=[]},53358(e){"use strict";function t(e){e.languages.autoit={comment:[/;.*/,{pattern:/(^[\t ]*)#(?:comments-start|cs)[\s\S]*?^[ \t]*#(?:comments-end|ce)/m,lookbehind:!0}],url:{pattern:/(^[\t ]*#include\s+)(?:<[^\r\n>]+>|"[^\r\n"]+")/m,lookbehind:!0},string:{pattern:/(["'])(?:\1\1|(?!\1)[^\r\n])*\1/,greedy:!0,inside:{variable:/([%$@])\w+\1/}},directive:{pattern:/(^[\t ]*)#\w+/m,lookbehind:!0,alias:"keyword"},function:/\b\w+(?=\()/,variable:/[$@]\w+/,keyword:/\b(?:Case|Const|Continue(?:Case|Loop)|Default|Dim|Do|Else(?:If)?|End(?:Func|If|Select|Switch|With)|Enum|Exit(?:Loop)?|For|Func|Global|If|In|Local|Next|Null|ReDim|Select|Static|Step|Switch|Then|To|Until|Volatile|WEnd|While|With)\b/i,number:/\b(?:0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/i,boolean:/\b(?:True|False)\b/i,operator:/<[=>]?|[-+*\/=&>]=?|[?^]|\b(?:And|Or|Not)\b/i,punctuation:/[\[\]().,:]/}}e.exports=t,t.displayName="autoit",t.aliases=[]},6979(e){"use strict";function t(e){!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|aptitude|apt-cache|apt-get|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:if|then|else|elif|fi|for|while|in|case|esac|function|select|do|done|until)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|break|cd|continue|eval|exec|exit|export|getopts|hash|pwd|readonly|return|shift|test|times|trap|umask|unset|alias|bind|builtin|caller|command|declare|echo|enable|help|let|local|logout|mapfile|printf|read|readarray|source|type|typeset|ulimit|unalias|set|shopt)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:true|false)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var i=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],a=r.variable[1].inside,o=0;o?^\w +\-.])*"/i,greedy:!0},number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?/i,keyword:/\b(?:AS|BEEP|BLOAD|BSAVE|CALL(?: ABSOLUTE)?|CASE|CHAIN|CHDIR|CLEAR|CLOSE|CLS|COM|COMMON|CONST|DATA|DECLARE|DEF(?: FN| SEG|DBL|INT|LNG|SNG|STR)|DIM|DO|DOUBLE|ELSE|ELSEIF|END|ENVIRON|ERASE|ERROR|EXIT|FIELD|FILES|FOR|FUNCTION|GET|GOSUB|GOTO|IF|INPUT|INTEGER|IOCTL|KEY|KILL|LINE INPUT|LOCATE|LOCK|LONG|LOOP|LSET|MKDIR|NAME|NEXT|OFF|ON(?: COM| ERROR| KEY| TIMER)?|OPEN|OPTION BASE|OUT|POKE|PUT|READ|REDIM|REM|RESTORE|RESUME|RETURN|RMDIR|RSET|RUN|SHARED|SINGLE|SELECT CASE|SHELL|SLEEP|STATIC|STEP|STOP|STRING|SUB|SWAP|SYSTEM|THEN|TIMER|TO|TROFF|TRON|TYPE|UNLOCK|UNTIL|USING|VIEW PRINT|WAIT|WEND|WHILE|WRITE)(?:\$|\b)/i,function:/\b(?:ABS|ACCESS|ACOS|ANGLE|AREA|ARITHMETIC|ARRAY|ASIN|ASK|AT|ATN|BASE|BEGIN|BREAK|CAUSE|CEIL|CHR|CLIP|COLLATE|COLOR|CON|COS|COSH|COT|CSC|DATE|DATUM|DEBUG|DECIMAL|DEF|DEG|DEGREES|DELETE|DET|DEVICE|DISPLAY|DOT|ELAPSED|EPS|ERASABLE|EXLINE|EXP|EXTERNAL|EXTYPE|FILETYPE|FIXED|FP|GO|GRAPH|HANDLER|IDN|IMAGE|IN|INT|INTERNAL|IP|IS|KEYED|LBOUND|LCASE|LEFT|LEN|LENGTH|LET|LINE|LINES|LOG|LOG10|LOG2|LTRIM|MARGIN|MAT|MAX|MAXNUM|MID|MIN|MISSING|MOD|NATIVE|NUL|NUMERIC|OF|OPTION|ORD|ORGANIZATION|OUTIN|OUTPUT|PI|POINT|POINTER|POINTS|POS|PRINT|PROGRAM|PROMPT|RAD|RADIANS|RANDOMIZE|RECORD|RECSIZE|RECTYPE|RELATIVE|REMAINDER|REPEAT|REST|RETRY|REWRITE|RIGHT|RND|ROUND|RTRIM|SAME|SEC|SELECT|SEQUENTIAL|SET|SETTER|SGN|SIN|SINH|SIZE|SKIP|SQR|STANDARD|STATUS|STR|STREAM|STYLE|TAB|TAN|TANH|TEMPLATE|TEXT|THERE|TIME|TIMEOUT|TRACE|TRANSFORM|TRUNCATE|UBOUND|UCASE|USE|VAL|VARIABLE|VIEWPORT|WHEN|WINDOW|WITH|ZER|ZONEWIDTH)(?:\$|\b)/i,operator:/<[=>]?|>=?|[+\-*\/^=&]|\b(?:AND|EQV|IMP|NOT|OR|XOR)\b/i,punctuation:/[,;:()]/}}e.exports=t,t.displayName="basic",t.aliases=[]},94781(e){"use strict";function t(e){var t,n,r,i,a;n=/%%?[~:\w]+%?|!\S+!/,r={pattern:/\/[a-z?]+(?=[ :]|$):?|-[a-z]\b|--[a-z-]+\b/im,alias:"attr-name",inside:{punctuation:/:/}},i=/"(?:[\\"]"|[^"])*"(?!")/,a=/(?:\b|-)\d+\b/,(t=e).languages.batch={comment:[/^::.*/m,{pattern:/((?:^|[&(])[ \t]*)rem\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0}],label:{pattern:/^:.*/m,alias:"property"},command:[{pattern:/((?:^|[&(])[ \t]*)for(?: \/[a-z?](?:[ :](?:"[^"]*"|[^\s"/]\S*))?)* \S+ in \([^)]+\) do/im,lookbehind:!0,inside:{keyword:/^for\b|\b(?:in|do)\b/i,string:i,parameter:r,variable:n,number:a,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*)if(?: \/[a-z?](?:[ :](?:"[^"]*"|[^\s"/]\S*))?)* (?:not )?(?:cmdextversion \d+|defined \w+|errorlevel \d+|exist \S+|(?:"[^"]*"|(?!")(?:(?!==)\S)+)?(?:==| (?:equ|neq|lss|leq|gtr|geq) )(?:"[^"]*"|[^\s"]\S*))/im,lookbehind:!0,inside:{keyword:/^if\b|\b(?:not|cmdextversion|defined|errorlevel|exist)\b/i,string:i,parameter:r,variable:n,number:a,operator:/\^|==|\b(?:equ|neq|lss|leq|gtr|geq)\b/i}},{pattern:/((?:^|[&()])[ \t]*)else\b/im,lookbehind:!0,inside:{keyword:/^else\b/i}},{pattern:/((?:^|[&(])[ \t]*)set(?: \/[a-z](?:[ :](?:"[^"]*"|[^\s"/]\S*))?)* (?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^set\b/i,string:i,parameter:r,variable:[n,/\w+(?=(?:[*\/%+\-&^|]|<<|>>)?=)/],number:a,operator:/[*\/%+\-&^|]=?|<<=?|>>=?|[!~_=]/,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*@?)\w+\b(?:"(?:[\\"]"|[^"])*"(?!")|[^"^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^\w+\b/i,string:i,parameter:r,label:{pattern:/(^\s*):\S+/m,lookbehind:!0,alias:"property"},variable:n,number:a,operator:/\^/}}],operator:/[&@]/,punctuation:/[()']/}}e.exports=t,t.displayName="batch",t.aliases=[]},62260(e){"use strict";function t(e){e.languages.bbcode={tag:{pattern:/\[\/?[^\s=\]]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'"\]=]+))?(?:\s+[^\s=\]]+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'"\]=]+))*\s*\]/,inside:{tag:{pattern:/^\[\/?[^\s=\]]+/,inside:{punctuation:/^\[\/?/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'"\]=]+)/i,inside:{punctuation:[/^=/,{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\]/,"attr-name":/[^\s=\]]+/}}},e.languages.shortcode=e.languages.bbcode}e.exports=t,t.displayName="bbcode",t.aliases=["shortcode"]},59258(e){"use strict";function t(e){e.languages.birb=e.languages.extend("clike",{string:{pattern:/r?("|')(?:\\.|(?!\1)[^\\])*\1/,greedy:!0},"class-name":[/\b[A-Z](?:[\d_]*[a-zA-Z]\w*)?\b/,/\b[A-Z]\w*(?=\s+\w+\s*[;,=()])/],keyword:/\b(?:assert|break|case|class|const|default|else|enum|final|follows|for|grab|if|nest|next|new|noSeeb|return|static|switch|throw|var|void|while)\b/,operator:/\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?|:/,variable:/\b[a-z_]\w*\b/}),e.languages.insertBefore("birb","function",{metadata:{pattern:/<\w+>/,greedy:!0,alias:"symbol"}})}e.exports=t,t.displayName="birb",t.aliases=[]},62890(e,t,n){"use strict";var r=n(65806);function i(e){e.register(r),e.languages.bison=e.languages.extend("c",{}),e.languages.insertBefore("bison","comment",{bison:{pattern:/^(?:[^%]|%(?!%))*%%[\s\S]*?%%/,inside:{c:{pattern:/%\{[\s\S]*?%\}|\{(?:\{[^}]*\}|[^{}])*\}/,inside:{delimiter:{pattern:/^%?\{|%?\}$/,alias:"punctuation"},"bison-variable":{pattern:/[$@](?:<[^\s>]+>)?[\w$]+/,alias:"variable",inside:{punctuation:/<|>/}},rest:e.languages.c}},comment:e.languages.c.comment,string:e.languages.c.string,property:/\S+(?=:)/,keyword:/%\w+/,number:{pattern:/(^|[^@])\b(?:0x[\da-f]+|\d+)/i,lookbehind:!0},punctuation:/%[%?]|[|:;\[\]<>]/}}})}e.exports=i,i.displayName="bison",i.aliases=[]},15958(e){"use strict";function t(e){e.languages.bnf={string:{pattern:/"[^\r\n"]*"|'[^\r\n']*'/},definition:{pattern:/<[^<>\r\n\t]+>(?=\s*::=)/,alias:["rule","keyword"],inside:{punctuation:/^<|>$/}},rule:{pattern:/<[^<>\r\n\t]+>/,inside:{punctuation:/^<|>$/}},operator:/::=|[|()[\]{}*+?]|\.{3}/},e.languages.rbnf=e.languages.bnf}e.exports=t,t.displayName="bnf",t.aliases=["rbnf"]},61321(e){"use strict";function t(e){e.languages.brainfuck={pointer:{pattern:/<|>/,alias:"keyword"},increment:{pattern:/\+/,alias:"inserted"},decrement:{pattern:/-/,alias:"deleted"},branching:{pattern:/\[|\]/,alias:"important"},operator:/[.,]/,comment:/\S+/}}e.exports=t,t.displayName="brainfuck",t.aliases=[]},77856(e){"use strict";function t(e){e.languages.brightscript={comment:/(?:\brem|').*/i,"directive-statement":{pattern:/(^[\t ]*)#(?:const|else(?:[\t ]+if)?|end[\t ]+if|error|if).*/im,lookbehind:!0,alias:"property",inside:{"error-message":{pattern:/(^#error).+/,lookbehind:!0},directive:{pattern:/^#(?:const|else(?:[\t ]+if)?|end[\t ]+if|error|if)/,alias:"keyword"},expression:{pattern:/[\s\S]+/,inside:null}}},property:{pattern:/([\r\n{,][\t ]*)(?:(?!\d)\w+|"(?:[^"\r\n]|"")*"(?!"))(?=[ \t]*:)/,lookbehind:!0,greedy:!0},string:{pattern:/"(?:[^"\r\n]|"")*"(?!")/,greedy:!0},"class-name":{pattern:/(\bAs[\t ]+)\w+/i,lookbehind:!0},keyword:/\b(?:As|Dim|Each|Else|Elseif|End|Exit|For|Function|Goto|If|In|Print|Return|Step|Stop|Sub|Then|To|While)\b/i,boolean:/\b(?:true|false)\b/i,function:/\b(?!\d)\w+(?=[\t ]*\()/i,number:/(?:\b\d+(?:\.\d+)?(?:[ed][+-]\d+)?|&h[a-f\d]+)\b[%&!#]?/i,operator:/--|\+\+|>>=?|<<=?|<>|[-+*/\\<>]=?|[:^=?]|\b(?:and|mod|not|or)\b/i,punctuation:/[.,;()[\]{}]/,constant:/\b(?:LINE_NUM)\b/i},e.languages.brightscript["directive-statement"].inside.expression.inside=e.languages.brightscript}e.exports=t,t.displayName="brightscript",t.aliases=[]},90741(e){"use strict";function t(e){e.languages.bro={comment:{pattern:/(^|[^\\$])#.*/,lookbehind:!0,inside:{italic:/\b(?:TODO|FIXME|XXX)\b/}},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},boolean:/\b[TF]\b/,function:{pattern:/(?:function|hook|event) \w+(?:::\w+)?/,inside:{keyword:/^(?:function|hook|event)/}},variable:{pattern:/(?:global|local) \w+/i,inside:{keyword:/(?:global|local)/}},builtin:/(?:@(?:load(?:-(?:sigs|plugin))?|unload|prefixes|ifn?def|else|(?:end)?if|DIR|FILENAME))|(?:&?(?:redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,constant:{pattern:/const \w+/i,inside:{keyword:/const/}},keyword:/\b(?:break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module|function)\b/,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,punctuation:/[{}[\];(),.:]/}}e.exports=t,t.displayName="bro",t.aliases=[]},83410(e){"use strict";function t(e){e.languages.bsl={comment:/\/\/.*/,string:[{pattern:/"(?:[^"]|"")*"(?!")/,greedy:!0},{pattern:/'(?:[^'\r\n\\]|\\.)*'/}],keyword:[{pattern:/(^|[^\w\u0400-\u0484\u0487-\u052f\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f])(?:пока|для|новый|прервать|попытка|исключение|вызватьисключение|иначе|конецпопытки|неопределено|функция|перем|возврат|конецфункции|если|иначеесли|процедура|конецпроцедуры|тогда|знач|экспорт|конецесли|из|каждого|истина|ложь|по|цикл|конеццикла|выполнить)(?![\w\u0400-\u0484\u0487-\u052f\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f])/i,lookbehind:!0},{pattern:/\b(?:while|for|new|break|try|except|raise|else|endtry|undefined|function|var|return|endfunction|null|if|elseif|procedure|endprocedure|then|val|export|endif|in|each|true|false|to|do|enddo|execute)\b/i}],number:{pattern:/(^(?=\d)|[^\w\u0400-\u0484\u0487-\u052f\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f])(?:\d+(?:\.\d*)?|\.\d+)(?:E[+-]?\d+)?/i,lookbehind:!0},operator:[/[<>+\-*/]=?|[%=]/,{pattern:/(^|[^\w\u0400-\u0484\u0487-\u052f\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f])(?:и|или|не)(?![\w\u0400-\u0484\u0487-\u052f\u1d2b\u1d78\u2de0-\u2dff\ua640-\ua69f\ufe2e\ufe2f])/i,lookbehind:!0},{pattern:/\b(?:and|or|not)\b/i}],punctuation:/\(\.|\.\)|[()\[\]:;,.]/,directive:[{pattern:/^(\s*)&.*/m,lookbehind:!0,alias:"important"},{pattern:/^\s*#.*/gm,alias:"important"}]},e.languages.oscript=e.languages.bsl}e.exports=t,t.displayName="bsl",t.aliases=[]},65806(e){"use strict";function t(e){e.languages.c=e.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:__attribute__|_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),e.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},e.languages.c.string],comment:e.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:e.languages.c}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete e.languages.c.boolean}e.exports=t,t.displayName="c",t.aliases=[]},33039(e){"use strict";function t(e){e.languages.cfscript=e.languages.extend("clike",{comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,inside:{annotation:{pattern:/(?:^|[^.])@[\w\.]+/,alias:"punctuation"}}},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],keyword:/\b(?:abstract|break|catch|component|continue|default|do|else|extends|final|finally|for|function|if|in|include|package|private|property|public|remote|required|rethrow|return|static|switch|throw|try|var|while|xml)\b(?!\s*=)/,operator:[/\+\+|--|&&|\|\||::|=>|[!=]==|<=?|>=?|[-+*/%&|^!=<>]=?|\?(?:\.|:)?|[?:]/,/\b(?:and|contains|eq|equal|eqv|gt|gte|imp|is|lt|lte|mod|not|or|xor)\b/],scope:{pattern:/\b(?:application|arguments|cgi|client|cookie|local|session|super|this|variables)\b/,alias:"global"},type:{pattern:/\b(?:any|array|binary|boolean|date|guid|numeric|query|string|struct|uuid|void|xml)\b/,alias:"builtin"}}),e.languages.insertBefore("cfscript","keyword",{"function-variable":{pattern:/[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"}}),delete e.languages.cfscript["class-name"],e.languages.cfc=e.languages.cfscript}e.exports=t,t.displayName="cfscript",t.aliases=[]},85082(e,t,n){"use strict";var r=n(80096);function i(e){e.register(r),e.languages.chaiscript=e.languages.extend("clike",{string:{pattern:/(^|[^\\])'(?:[^'\\]|\\[\s\S])*'/,lookbehind:!0,greedy:!0},"class-name":[{pattern:/(\bclass\s+)\w+/,lookbehind:!0},{pattern:/(\b(?:attr|def)\s+)\w+(?=\s*::)/,lookbehind:!0}],keyword:/\b(?:attr|auto|break|case|catch|class|continue|def|default|else|finally|for|fun|global|if|return|switch|this|try|var|while)\b/,number:[e.languages.cpp.number,/\b(?:Infinity|NaN)\b/],operator:/>>=?|<<=?|\|\||&&|:[:=]?|--|\+\+|[=!<>+\-*/%|&^]=?|[?~]|`[^`\r\n]{1,4}`/}),e.languages.insertBefore("chaiscript","operator",{"parameter-type":{pattern:/([,(]\s*)\w+(?=\s+\w)/,lookbehind:!0,alias:"class-name"}}),e.languages.insertBefore("chaiscript","string",{"string-interpolation":{pattern:/(^|[^\\])"(?:[^"$\\]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*"/,lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}/,lookbehind:!0,inside:{"interpolation-expression":{pattern:/(^\$\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:e.languages.chaiscript},"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"}}},string:/[\s\S]+/}}})}e.exports=i,i.displayName="chaiscript",i.aliases=[]},79415(e){"use strict";function t(e){e.languages.cil={comment:/\/\/.*/,string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},directive:{pattern:/(^|\W)\.[a-z]+(?=\s)/,lookbehind:!0,alias:"class-name"},variable:/\[[\w\.]+\]/,keyword:/\b(?:abstract|ansi|assembly|auto|autochar|beforefieldinit|bool|bstr|byvalstr|catch|char|cil|class|currency|date|decimal|default|enum|error|explicit|extends|extern|famandassem|family|famorassem|final(?:ly)?|float32|float64|hidebysig|iant|idispatch|implements|import|initonly|instance|u?int(?:8|16|32|64)?|interface|iunknown|literal|lpstr|lpstruct|lptstr|lpwstr|managed|method|native(?:Type)?|nested|newslot|object(?:ref)?|pinvokeimpl|private|privatescope|public|reqsecobj|rtspecialname|runtime|sealed|sequential|serializable|specialname|static|string|struct|syschar|tbstr|unicode|unmanagedexp|unsigned|value(?:type)?|variant|virtual|void)\b/,function:/\b(?:(?:constrained|unaligned|volatile|readonly|tail|no)\.)?(?:conv\.(?:[iu][1248]?|ovf\.[iu][1248]?(?:\.un)?|r\.un|r4|r8)|ldc\.(?:i4(?:\.[0-9]+|\.[mM]1|\.s)?|i8|r4|r8)|ldelem(?:\.[iu][1248]?|\.r[48]|\.ref|a)?|ldind\.(?:[iu][1248]?|r[48]|ref)|stelem\.?(?:i[1248]?|r[48]|ref)?|stind\.(?:i[1248]?|r[48]|ref)?|end(?:fault|filter|finally)|ldarg(?:\.[0-3s]|a(?:\.s)?)?|ldloc(?:\.[0-9]+|\.s)?|sub(?:\.ovf(?:\.un)?)?|mul(?:\.ovf(?:\.un)?)?|add(?:\.ovf(?:\.un)?)?|stloc(?:\.[0-3s])?|refany(?:type|val)|blt(?:\.un)?(?:\.s)?|ble(?:\.un)?(?:\.s)?|bgt(?:\.un)?(?:\.s)?|bge(?:\.un)?(?:\.s)?|unbox(?:\.any)?|init(?:blk|obj)|call(?:i|virt)?|brfalse(?:\.s)?|bne\.un(?:\.s)?|ldloca(?:\.s)?|brzero(?:\.s)?|brtrue(?:\.s)?|brnull(?:\.s)?|brinst(?:\.s)?|starg(?:\.s)?|leave(?:\.s)?|shr(?:\.un)?|rem(?:\.un)?|div(?:\.un)?|clt(?:\.un)?|alignment|ldvirtftn|castclass|beq(?:\.s)?|mkrefany|localloc|ckfinite|rethrow|ldtoken|ldsflda|cgt\.un|arglist|switch|stsfld|sizeof|newobj|newarr|ldsfld|ldnull|ldflda|isinst|throw|stobj|stfld|ldstr|ldobj|ldlen|ldftn|ldfld|cpobj|cpblk|break|br\.s|xor|shl|ret|pop|not|nop|neg|jmp|dup|cgt|ceq|box|and|or|br)\b/,boolean:/\b(?:true|false)\b/,number:/\b-?(?:0x[0-9a-f]+|[0-9]+)(?:\.[0-9a-f]+)?\b/i,punctuation:/[{}[\];(),:=]|IL_[0-9A-Za-z]+/}}e.exports=t,t.displayName="cil",t.aliases=[]},29726(e){"use strict";function t(e){e.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/}}e.exports=t,t.displayName="clike",t.aliases=[]},62849(e){"use strict";function t(e){e.languages.clojure={comment:/;.*/,string:{pattern:/"(?:[^"\\]|\\.)*"/,greedy:!0},operator:/(?:::|[:|'])\b[a-z][\w*+!?-]*\b/i,keyword:{pattern:/([^\w+*'?-])(?:def|if|do|let|\.\.|quote|var|->>|->|fn|loop|recur|throw|try|monitor-enter|\.|new|set!|def-|defn|defn-|defmacro|defmulti|defmethod|defstruct|defonce|declare|definline|definterface|defprotocol|==|defrecord|>=|deftype|<=|defproject|ns|\*|\+|-|\/|<|=|>|accessor|agent|agent-errors|aget|alength|all-ns|alter|and|append-child|apply|array-map|aset|aset-boolean|aset-byte|aset-char|aset-double|aset-float|aset-int|aset-long|aset-short|assert|assoc|await|await-for|bean|binding|bit-and|bit-not|bit-or|bit-shift-left|bit-shift-right|bit-xor|boolean|branch\?|butlast|byte|cast|char|children|class|clear-agent-errors|comment|commute|comp|comparator|complement|concat|conj|cons|constantly|cond|if-not|construct-proxy|contains\?|count|create-ns|create-struct|cycle|dec|deref|difference|disj|dissoc|distinct|doall|doc|dorun|doseq|dosync|dotimes|doto|double|down|drop|drop-while|edit|end\?|ensure|eval|every\?|false\?|ffirst|file-seq|filter|find|find-doc|find-ns|find-var|first|float|flush|for|fnseq|frest|gensym|get-proxy-class|get|hash-map|hash-set|identical\?|identity|if-let|import|in-ns|inc|index|insert-child|insert-left|insert-right|inspect-table|inspect-tree|instance\?|int|interleave|intersection|into|into-array|iterate|join|key|keys|keyword|keyword\?|last|lazy-cat|lazy-cons|left|lefts|line-seq|list\*|list|load|load-file|locking|long|macroexpand|macroexpand-1|make-array|make-node|map|map-invert|map\?|mapcat|max|max-key|memfn|merge|merge-with|meta|min|min-key|name|namespace|neg\?|newline|next|nil\?|node|not|not-any\?|not-every\?|not=|ns-imports|ns-interns|ns-map|ns-name|ns-publics|ns-refers|ns-resolve|ns-unmap|nth|nthrest|or|parse|partial|path|peek|pop|pos\?|pr|pr-str|print|print-str|println|println-str|prn|prn-str|project|proxy|proxy-mappings|quot|rand|rand-int|range|re-find|re-groups|re-matcher|re-matches|re-pattern|re-seq|read|read-line|reduce|ref|ref-set|refer|rem|remove|remove-method|remove-ns|rename|rename-keys|repeat|replace|replicate|resolve|rest|resultset-seq|reverse|rfirst|right|rights|root|rrest|rseq|second|select|select-keys|send|send-off|seq|seq-zip|seq\?|set|short|slurp|some|sort|sort-by|sorted-map|sorted-map-by|sorted-set|special-symbol\?|split-at|split-with|str|string\?|struct|struct-map|subs|subvec|symbol|symbol\?|sync|take|take-nth|take-while|test|time|to-array|to-array-2d|tree-seq|true\?|union|up|update-proxy|val|vals|var-get|var-set|var\?|vector|vector-zip|vector\?|when|when-first|when-let|when-not|with-local-vars|with-meta|with-open|with-out-str|xml-seq|xml-zip|zero\?|zipmap|zipper)(?=[^\w+*'?-])/,lookbehind:!0},boolean:/\b(?:true|false|nil)\b/,number:/\b[\da-f]+\b/i,punctuation:/[{}\[\](),]/}}e.exports=t,t.displayName="clojure",t.aliases=[]},55773(e){"use strict";function t(e){e.languages.cmake={comment:/#.*/,string:{pattern:/"(?:[^\\"]|\\.)*"/,greedy:!0,inside:{interpolation:{pattern:/\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/,inside:{punctuation:/\$\{|\}/,variable:/\w+/}}}},variable:/\b(?:CMAKE_\w+|\w+_(?:VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?|(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_(?:BINARY_DIR|DESCRIPTION|HOMEPAGE_URL|NAME|SOURCE_DIR|VERSION|VERSION_(?:MAJOR|MINOR|PATCH|TWEAK))|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE|XCODE_VERSION))\b/,property:/\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|GLOBAL_KEYWORD|GLOBAL_PROJECT_TYPES|GLOBAL_ROOTNAMESPACE|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/,keyword:/\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/,boolean:/\b(?:ON|OFF|TRUE|FALSE)\b/,namespace:/\b(?:PROPERTIES|SHARED|PRIVATE|STATIC|PUBLIC|INTERFACE|TARGET_OBJECTS)\b/,operator:/\b(?:NOT|AND|OR|MATCHES|LESS|GREATER|EQUAL|STRLESS|STRGREATER|STREQUAL|VERSION_LESS|VERSION_EQUAL|VERSION_GREATER|DEFINED)\b/,inserted:{pattern:/\b\w+::\w+\b/,alias:"class-name"},number:/\b\d+(?:\.\d+)*\b/,function:/\b[a-z_]\w*(?=\s*\()\b/i,punctuation:/[()>}]|\$[<{]/}}e.exports=t,t.displayName="cmake",t.aliases=[]},32762(e){"use strict";function t(e){e.languages.cobol={comment:{pattern:/\*>.*|(^[ \t]*)\*.*/m,lookbehind:!0,greedy:!0},string:{pattern:/[xzgn]?(?:"(?:[^\r\n"]|"")*"(?!")|'(?:[^\r\n']|'')*'(?!'))/i,greedy:!0},level:{pattern:/(^[ \t]*)\d+\b/m,lookbehind:!0,greedy:!0,alias:"number"},"class-name":{pattern:/(\bpic(?:ture)?\s+)(?:(?:[-\w$/,:*+<>]|\.(?!\s|$))(?:\(\d+\))?)+/i,lookbehind:!0,inside:{number:{pattern:/(\()\d+/,lookbehind:!0},punctuation:/[()]/}},keyword:{pattern:/(^|[^\w-])(?:ABORT|ACCEPT|ACCESS|ADD|ADDRESS|ADVANCING|AFTER|ALIGNED|ALL|ALPHABET|ALPHABETIC|ALPHABETIC-LOWER|ALPHABETIC-UPPER|ALPHANUMERIC|ALPHANUMERIC-EDITED|ALSO|ALTER|ALTERNATE|ANY|ARE|AREA|AREAS|AS|ASCENDING|ASCII|ASSIGN|ASSOCIATED-DATA|ASSOCIATED-DATA-LENGTH|AT|ATTRIBUTE|AUTHOR|AUTO|AUTO-SKIP|BACKGROUND-COLOR|BACKGROUND-COLOUR|BASIS|BEEP|BEFORE|BEGINNING|BELL|BINARY|BIT|BLANK|BLINK|BLOCK|BOUNDS|BOTTOM|BY|BYFUNCTION|BYTITLE|CALL|CANCEL|CAPABLE|CCSVERSION|CD|CF|CH|CHAINING|CHANGED|CHANNEL|CHARACTER|CHARACTERS|CLASS|CLASS-ID|CLOCK-UNITS|CLOSE|CLOSE-DISPOSITION|COBOL|CODE|CODE-SET|COLLATING|COL|COLUMN|COM-REG|COMMA|COMMITMENT|COMMON|COMMUNICATION|COMP|COMP-1|COMP-2|COMP-3|COMP-4|COMP-5|COMPUTATIONAL|COMPUTATIONAL-1|COMPUTATIONAL-2|COMPUTATIONAL-3|COMPUTATIONAL-4|COMPUTATIONAL-5|COMPUTE|CONFIGURATION|CONTAINS|CONTENT|CONTINUE|CONTROL|CONTROL-POINT|CONTROLS|CONVENTION|CONVERTING|COPY|CORR|CORRESPONDING|COUNT|CRUNCH|CURRENCY|CURSOR|DATA|DATA-BASE|DATE|DATE-COMPILED|DATE-WRITTEN|DAY|DAY-OF-WEEK|DBCS|DE|DEBUG-CONTENTS|DEBUG-ITEM|DEBUG-LINE|DEBUG-NAME|DEBUG-SUB-1|DEBUG-SUB-2|DEBUG-SUB-3|DEBUGGING|DECIMAL-POINT|DECLARATIVES|DEFAULT|DEFAULT-DISPLAY|DEFINITION|DELETE|DELIMITED|DELIMITER|DEPENDING|DESCENDING|DESTINATION|DETAIL|DFHRESP|DFHVALUE|DISABLE|DISK|DISPLAY|DISPLAY-1|DIVIDE|DIVISION|DONTCARE|DOUBLE|DOWN|DUPLICATES|DYNAMIC|EBCDIC|EGCS|EGI|ELSE|EMI|EMPTY-CHECK|ENABLE|END|END-ACCEPT|END-ADD|END-CALL|END-COMPUTE|END-DELETE|END-DIVIDE|END-EVALUATE|END-IF|END-MULTIPLY|END-OF-PAGE|END-PERFORM|END-READ|END-RECEIVE|END-RETURN|END-REWRITE|END-SEARCH|END-START|END-STRING|END-SUBTRACT|END-UNSTRING|END-WRITE|ENDING|ENTER|ENTRY|ENTRY-PROCEDURE|ENVIRONMENT|EOP|ERASE|ERROR|EOL|EOS|ESCAPE|ESI|EVALUATE|EVENT|EVERY|EXCEPTION|EXCLUSIVE|EXHIBIT|EXIT|EXPORT|EXTEND|EXTENDED|EXTERNAL|FD|FILE|FILE-CONTROL|FILLER|FINAL|FIRST|FOOTING|FOR|FOREGROUND-COLOR|FOREGROUND-COLOUR|FROM|FULL|FUNCTION|FUNCTIONNAME|FUNCTION-POINTER|GENERATE|GOBACK|GIVING|GLOBAL|GO|GRID|GROUP|HEADING|HIGHLIGHT|HIGH-VALUE|HIGH-VALUES|I-O|I-O-CONTROL|ID|IDENTIFICATION|IF|IMPLICIT|IMPORT|IN|INDEX|INDEXED|INDICATE|INITIAL|INITIALIZE|INITIATE|INPUT|INPUT-OUTPUT|INSPECT|INSTALLATION|INTEGER|INTO|INVALID|INVOKE|IS|JUST|JUSTIFIED|KANJI|KEPT|KEY|KEYBOARD|LABEL|LANGUAGE|LAST|LB|LD|LEADING|LEFT|LEFTLINE|LENGTH|LENGTH-CHECK|LIBACCESS|LIBPARAMETER|LIBRARY|LIMIT|LIMITS|LINAGE|LINAGE-COUNTER|LINE|LINES|LINE-COUNTER|LINKAGE|LIST|LOCAL|LOCAL-STORAGE|LOCK|LONG-DATE|LONG-TIME|LOWER|LOWLIGHT|LOW-VALUE|LOW-VALUES|MEMORY|MERGE|MESSAGE|MMDDYYYY|MODE|MODULES|MORE-LABELS|MOVE|MULTIPLE|MULTIPLY|NAMED|NATIONAL|NATIONAL-EDITED|NATIVE|NEGATIVE|NETWORK|NEXT|NO|NO-ECHO|NULL|NULLS|NUMBER|NUMERIC|NUMERIC-DATE|NUMERIC-EDITED|NUMERIC-TIME|OBJECT-COMPUTER|OCCURS|ODT|OF|OFF|OMITTED|ON|OPEN|OPTIONAL|ORDER|ORDERLY|ORGANIZATION|OTHER|OUTPUT|OVERFLOW|OVERLINE|OWN|PACKED-DECIMAL|PADDING|PAGE|PAGE-COUNTER|PASSWORD|PERFORM|PF|PH|PIC|PICTURE|PLUS|POINTER|POSITION|POSITIVE|PORT|PRINTER|PRINTING|PRIVATE|PROCEDURE|PROCEDURE-POINTER|PROCEDURES|PROCEED|PROCESS|PROGRAM|PROGRAM-ID|PROGRAM-LIBRARY|PROMPT|PURGE|QUEUE|QUOTE|QUOTES|RANDOM|READER|REMOTE|RD|REAL|READ|RECEIVE|RECEIVED|RECORD|RECORDING|RECORDS|RECURSIVE|REDEFINES|REEL|REF|REFERENCE|REFERENCES|RELATIVE|RELEASE|REMAINDER|REMARKS|REMOVAL|REMOVE|RENAMES|REPLACE|REPLACING|REPORT|REPORTING|REPORTS|REQUIRED|RERUN|RESERVE|REVERSE-VIDEO|RESET|RETURN|RETURN-CODE|RETURNING|REVERSED|REWIND|REWRITE|RF|RH|RIGHT|ROUNDED|RUN|SAME|SAVE|SCREEN|SD|SEARCH|SECTION|SECURE|SECURITY|SEGMENT|SEGMENT-LIMIT|SELECT|SEND|SENTENCE|SEPARATE|SEQUENCE|SEQUENTIAL|SET|SHARED|SHAREDBYALL|SHAREDBYRUNUNIT|SHARING|SHIFT-IN|SHIFT-OUT|SHORT-DATE|SIGN|SIZE|SORT|SORT-CONTROL|SORT-CORE-SIZE|SORT-FILE-SIZE|SORT-MERGE|SORT-MESSAGE|SORT-MODE-SIZE|SORT-RETURN|SOURCE|SOURCE-COMPUTER|SPACE|SPACES|SPECIAL-NAMES|STANDARD|STANDARD-1|STANDARD-2|START|STATUS|STOP|STRING|SUB-QUEUE-1|SUB-QUEUE-2|SUB-QUEUE-3|SUBTRACT|SUM|SUPPRESS|SYMBOL|SYMBOLIC|SYNC|SYNCHRONIZED|TABLE|TALLY|TALLYING|TASK|TAPE|TERMINAL|TERMINATE|TEST|TEXT|THEN|THREAD|THREAD-LOCAL|THROUGH|THRU|TIME|TIMER|TIMES|TITLE|TO|TODAYS-DATE|TODAYS-NAME|TOP|TRAILING|TRUNCATED|TYPE|TYPEDEF|UNDERLINE|UNIT|UNSTRING|UNTIL|UP|UPON|USAGE|USE|USING|VALUE|VALUES|VARYING|VIRTUAL|WAIT|WHEN|WHEN-COMPILED|WITH|WORDS|WORKING-STORAGE|WRITE|YEAR|YYYYMMDD|YYYYDDD|ZERO-FILL|ZEROS|ZEROES)(?![\w-])/i,lookbehind:!0},boolean:{pattern:/(^|[^\w-])(?:false|true)(?![\w-])/i,lookbehind:!0},number:{pattern:/(^|[^\w-])(?:[+-]?(?:(?:\d+(?:[.,]\d+)?|[.,]\d+)(?:e[+-]?\d+)?|zero))(?![\w-])/i,lookbehind:!0},operator:[/<>|[<>]=?|[=+*/&]/,{pattern:/(^|[^\w-])(?:-|and|equal|greater|less|not|or|than)(?![\w-])/i,lookbehind:!0}],punctuation:/[.:,()]/}}e.exports=t,t.displayName="cobol",t.aliases=[]},43576(e){"use strict";function t(e){var t,n,r;n=/#(?!\{).+/,r={pattern:/#\{[^}]+\}/,alias:"variable"},(t=e).languages.coffeescript=t.languages.extend("javascript",{comment:n,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:r}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),t.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:n,interpolation:r}}}),t.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:t.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:r}}]}),t.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete t.languages.coffeescript["template-string"],t.languages.coffee=t.languages.coffeescript}e.exports=t,t.displayName="coffeescript",t.aliases=["coffee"]},71794(e){"use strict";function t(e){e.languages.concurnas={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],langext:{pattern:/\b\w+\s*\|\|[\s\S]+?\|\|/,greedy:!0,alias:"string"},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/,lookbehind:!0},keyword:/\b(?:abstract|actor|also|annotation|assert|async|await|bool|boolean|break|byte|case|catch|changed|char|class|closed|constant|continue|def|default|del|double|elif|else|enum|every|extends|false|finally|float|for|from|global|gpudef|gpukernel|if|import|in|init|inject|int|lambda|local|long|loop|match|new|nodefault|null|of|onchange|open|out|override|package|parfor|parforsync|post|pre|private|protected|provide|provider|public|return|shared|short|single|size_t|sizeof|super|sync|this|throw|trait|trans|transient|true|try|typedef|unchecked|using|val|var|void|while|with)\b/,boolean:/\b(?:false|true)\b/,number:/\b0b[01][01_]*L?\b|\b0x(?:[\da-f_]*\.)?[\da-f_p+-]+\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfls]?/i,punctuation:/[{}[\];(),.:]/,operator:/<==|>==|=>|->|<-|<>|\^|&==|&<>|!|\?:?|\.\?|\+\+|--|[-+*/=<>]=?|\b(?:and|as|band|bor|bxor|comp|is|isnot|mod|or)\b=?/,annotation:{pattern:/@(?:\w+:)?(?:\w+|\[[^\]]+\])?/,alias:"builtin"}},e.languages.insertBefore("concurnas","langext",{string:{pattern:/[rs]?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:e.languages.concurnas},string:/[\s\S]+/}}}),e.languages.conc=e.languages.concurnas}e.exports=t,t.displayName="concurnas",t.aliases=["conc"]},1315(e){"use strict";function t(e){!function(e){for(var t=/\(\*(?:[^(*]|\((?!\*)|\*(?!\))|)*\*\)/.source,n=0;n<2;n++)t=t.replace(//g,function(){return t});t=t.replace(//g,"[]"),e.languages.coq={comment:RegExp(t),string:{pattern:/"(?:[^"]|"")*"(?!")/,greedy:!0},attribute:[{pattern:RegExp(/#\[(?:[^\]("]|"(?:[^"]|"")*"(?!")|\((?!\*)|)*\]/.source.replace(//g,function(){return t})),greedy:!0,alias:"attr-name",inside:{comment:RegExp(t),string:{pattern:/"(?:[^"]|"")*"(?!")/,greedy:!0},operator:/=/,punctuation:/^#\[|\]$|[,()]/}},{pattern:/\b(?:Cumulative|Global|Local|Monomorphic|NonCumulative|Polymorphic|Private|Program)\b/,alias:"attr-name"}],keyword:/\b(?:_|Abort|About|Add|Admit|Admitted|All|apply|Arguments|as|As|Assumptions|at|Axiom|Axioms|Back|BackTo|Backtrace|Bind|BinOp|BinOpSpec|BinRel|Blacklist|by|Canonical|Case|Cd|Check|Class|Classes|Close|Coercion|Coercions|cofix|CoFixpoint|CoInductive|Collection|Combined|Compute|Conjecture|Conjectures|Constant|Constants|Constraint|Constructors|Context|Corollary|Create|CstOp|Custom|Cut|Debug|Declare|Defined|Definition|Delimit|Dependencies|Dependent|Derive|Diffs|Drop|Elimination|else|end|End|Entry|Equality|Eval|Example|Existential|Existentials|Existing|exists|exists2|Export|Extern|Extraction|Fact|Fail|Field|File|Firstorder|fix|Fixpoint|Flags|Focus|for|forall|From|fun|Funclass|Function|Functional|GC|Generalizable|Goal|Grab|Grammar|Graph|Guarded|Haskell|Heap|Hide|Hint|HintDb|Hints|Hypotheses|Hypothesis|Identity|if|IF|Immediate|Implicit|Implicits|Import|in|Include|Induction|Inductive|Infix|Info|Initial|InjTyp|Inline|Inspect|Instance|Instances|Intro|Intros|Inversion|Inversion_clear|JSON|Language|Left|Lemma|let|Let|Lia|Libraries|Library|Load|LoadPath|Locate|Ltac|Ltac2|match|Match|measure|Method|Minimality|ML|Module|Modules|Morphism|move|Next|NoInline|Notation|Number|Obligation|Obligations|OCaml|Opaque|Open|Optimize|Parameter|Parameters|Parametric|Path|Paths|Prenex|Preterm|Primitive|Print|Profile|Projections|Proof|Prop|PropBinOp|Property|PropOp|Proposition|PropUOp|Pwd|Qed|Quit|Rec|Record|Recursive|Redirect|Reduction|Register|Relation|Remark|Remove|removed|Require|Reserved|Reset|Resolve|Restart|return|Rewrite|Right|Ring|Rings|Saturate|Save|Scheme|Scope|Scopes|Search|SearchHead|SearchPattern|SearchRewrite|Section|Separate|Set|Setoid|Show|Signatures|Solve|Solver|Sort|Sortclass|Sorted|Spec|SProp|Step|Strategies|Strategy|String|struct|Structure|SubClass|Subgraph|SuchThat|Tactic|Term|TestCompile|then|Theorem|Time|Timeout|To|Transparent|Type|Typeclasses|Types|Typing|Undelimit|Undo|Unfocus|Unfocused|Unfold|Universe|Universes|UnOp|UnOpSpec|Unshelve|using|Variable|Variables|Variant|Verbose|View|Visibility|wf|where|with|Zify)\b/,number:/\b(?:0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]+)?(?:p[+-]?\d[\d_]*)?|\d[\d_]*(?:\.[\d_]+)?(?:e[+-]?\d[\d_]*)?)\b/i,punct:{pattern:/@\{|\{\||\[=|:>/,alias:"punctuation"},operator:/\/\\|\\\/|\.{2,3}|:{1,2}=|\*\*|[-=]>|<(?:->?|[+:=>]|<:)|>(?:=|->)|\|[-|]?|[-!%&*+/<=>?@^~']/,punctuation:/\.\(|`\(|@\{|`\{|\{\||\[=|:>|[:.,;(){}\[\]]/}}(e)}e.exports=t,t.displayName="coq",t.aliases=[]},80096(e,t,n){"use strict";var r=n(65806);function i(e){var t,n,i;e.register(r),t=e,n=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,i=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,function(){return n.source}),t.languages.cpp=t.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,function(){return n.source})),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:n,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),t.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:module|import)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,function(){return i})+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),t.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b[a-z_]\w*\s*<(?:[^<>]|<(?:[^<>])*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t.languages.cpp}}}}),t.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),t.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:t.languages.extend("cpp",{})}}),t.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},t.languages.cpp["base-clause"])}e.exports=i,i.displayName="cpp",i.aliases=[]},99176(e,t,n){"use strict";var r=n(56939);function i(e){var t;e.register(r),(t=e).languages.crystal=t.languages.extend("ruby",{keyword:[/\b(?:abstract|alias|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|include|instance_sizeof|lib|macro|module|next|of|out|pointerof|private|protected|rescue|return|require|select|self|sizeof|struct|super|then|type|typeof|uninitialized|union|unless|until|when|while|with|yield|__DIR__|__END_LINE__|__FILE__|__LINE__)\b/,{pattern:/(\.\s*)(?:is_a|responds_to)\?/,lookbehind:!0}],number:/\b(?:0b[01_]*[01]|0o[0-7_]*[0-7]|0x[\da-fA-F_]*[\da-fA-F]|(?:\d(?:[\d_]*\d)?)(?:\.[\d_]*\d)?(?:[eE][+-]?[\d_]*\d)?)(?:_(?:[uif](?:8|16|32|64))?)?\b/}),t.languages.insertBefore("crystal","string",{attribute:{pattern:/@\[.+?\]/,alias:"attr-name",inside:{delimiter:{pattern:/^@\[|\]$/,alias:"tag"},rest:t.languages.crystal}},expansion:[{pattern:/\{\{.+?\}\}/,inside:{delimiter:{pattern:/^\{\{|\}\}$/,alias:"tag"},rest:t.languages.crystal}},{pattern:/\{%.+?%\}/,inside:{delimiter:{pattern:/^\{%|%\}$/,alias:"tag"},rest:t.languages.crystal}}]})}e.exports=i,i.displayName="crystal",i.aliases=[]},61958(e){"use strict";function t(e){!function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,function(e,n){return"(?:"+t[+n]+")"})}function n(e,n,r){return RegExp(t(e,n),r||"")}function r(e,t){for(var n=0;n>/g,function(){return"(?:"+e+")"});return e.replace(/<>/g,"[^\\s\\S]")}var i={type:"bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",typeDeclaration:"class enum interface struct",contextual:"add alias and ascending async await by descending from get global group into join let nameof not notnull on or orderby partial remove select set unmanaged value when where",other:"abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield"};function a(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var o=a(i.typeDeclaration),s=RegExp(a(i.type+" "+i.typeDeclaration+" "+i.contextual+" "+i.other)),u=a(i.typeDeclaration+" "+i.contextual+" "+i.other),c=a(i.type+" "+i.typeDeclaration+" "+i.other),l=r(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source,2),f=r(/\((?:[^()]|<>)*\)/.source,2),d=/@?\b[A-Za-z_]\w*\b/.source,h=t(/<<0>>(?:\s*<<1>>)?/.source,[d,l]),p=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[u,h]),b=/\[\s*(?:,\s*)*\]/.source,m=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[p,b]),g=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[l,f,b]),v=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[g]),y=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[v,p,b]),w={keyword:s,punctuation:/[<>()?,.:[\]]/},_=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,E=/"(?:\\.|[^\\"\r\n])*"/.source,S=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[S]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[E]),lookbehind:!0,greedy:!0},{pattern:RegExp(_),greedy:!0,alias:"character"}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[p]),lookbehind:!0,inside:w},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[d,y]),lookbehind:!0,inside:w},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[d]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[o,h]),lookbehind:!0,inside:w},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[p]),lookbehind:!0,inside:w},{pattern:n(/(\bwhere\s+)<<0>>/.source,[d]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[m]),lookbehind:!0,inside:w},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[y,c,d]),inside:w}],keyword:s,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:ul|lu|[dflmu])?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[d]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[d]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|typeof|sizeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[f]),lookbehind:!0,alias:"class-name",inside:w},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[y,p]),inside:w,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[y]),lookbehind:!0,inside:w,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[d,l]),inside:{function:n(/^<<0>>/.source,[d]),generic:{pattern:RegExp(l),alias:"class-name",inside:w}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>)(?:\s*,\s*(?:<<3>>|<<4>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[o,h,d,y,s.source]),lookbehind:!0,inside:{keyword:s,"class-name":{pattern:RegExp(y),greedy:!0,inside:w},punctuation:/,/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var k=E+"|"+_,x=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[k]),T=r(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[x]),2),M=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,O=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[p,T]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[M,O]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[M]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[T]),inside:e.languages.csharp},"class-name":{pattern:RegExp(p),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var A=/:[^}\r\n]+/.source,L=r(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[x]),2),C=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[L,A]),I=r(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source,[k]),2),D=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[I,A]);function N(t,r){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[r,A]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[C]),lookbehind:!0,greedy:!0,inside:N(C,L)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[D]),lookbehind:!0,greedy:!0,inside:N(D,I)}]})}(e),e.languages.dotnet=e.languages.cs=e.languages.csharp}e.exports=t,t.displayName="csharp",t.aliases=["dotnet","cs"]},65447(e){"use strict";function t(e){e.languages.csp={directive:{pattern:/(^|[^-\da-z])(?:base-uri|block-all-mixed-content|(?:child|connect|default|font|frame|img|manifest|media|object|prefetch|script|style|worker)-src|disown-opener|form-action|frame-(?:ancestors|options)|input-protection(?:-(?:clip|selectors))?|navigate-to|plugin-types|policy-uri|referrer|reflected-xss|report-(?:to|uri)|require-sri-for|sandbox|(?:script|style)-src-(?:attr|elem)|upgrade-insecure-requests)(?=[^-\da-z]|$)/i,lookbehind:!0,alias:"keyword"},safe:{pattern:/'(?:deny|none|report-sample|self|strict-dynamic|top-only|(?:nonce|sha(?:256|384|512))-[-+/\w=]+)'/i,alias:"selector"},unsafe:{pattern:/(?:'unsafe-(?:allow-redirects|dynamic|eval|hash-attributes|hashed-attributes|hashes|inline)'|\*)/i,alias:"function"}}}e.exports=t,t.displayName="csp",t.aliases=[]},4762(e){"use strict";function t(e){var t,n,r,i,a;r=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,(t=e).languages.css.selector={pattern:t.languages.css.selector.pattern,lookbehind:!0,inside:n={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+r.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[r,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},t.languages.css.atrule.inside["selector-function-argument"].inside=n,t.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}}),i={pattern:/(\b\d+)(?:%|[a-z]+\b)/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},t.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:rgb|hsl)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:rgb|hsl)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:i,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:i,number:a})}e.exports=t,t.displayName="cssExtras",t.aliases=[]},12049(e){"use strict";function t(e){var t,n,r;n=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/,(t=e).languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+n.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+n.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+n.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:n,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},t.languages.css.atrule.inside.rest=t.languages.css,(r=t.languages.markup)&&(r.tag.addInlined("style","css"),r.tag.addAttribute("style","css"))}e.exports=t,t.displayName="css",t.aliases=[]},78090(e){"use strict";function t(e){e.languages.csv={value:/[^\r\n,"]+|"(?:[^"]|"")*"(?!")/,punctuation:/,/}}e.exports=t,t.displayName="csv",t.aliases=[]},40315(e){"use strict";function t(e){e.languages.cypher={comment:/\/\/.*/,string:{pattern:/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/,greedy:!0},"class-name":{pattern:/(:\s*)(?:\w+|`(?:[^`\\\r\n])*`)(?=\s*[{):])/,lookbehind:!0,greedy:!0},relationship:{pattern:/(-\[\s*(?:\w+\s*|`(?:[^`\\\r\n])*`\s*)?:\s*|\|\s*:\s*)(?:\w+|`(?:[^`\\\r\n])*`)/,lookbehind:!0,greedy:!0,alias:"property"},identifier:{pattern:/`(?:[^`\\\r\n])*`/,greedy:!0,alias:"symbol"},variable:/\$\w+/,keyword:/\b(?:ADD|ALL|AND|AS|ASC|ASCENDING|ASSERT|BY|CALL|CASE|COMMIT|CONSTRAINT|CONTAINS|CREATE|CSV|DELETE|DESC|DESCENDING|DETACH|DISTINCT|DO|DROP|ELSE|END|ENDS|EXISTS|FOR|FOREACH|IN|INDEX|IS|JOIN|KEY|LIMIT|LOAD|MANDATORY|MATCH|MERGE|NODE|NOT|OF|ON|OPTIONAL|OR|ORDER(?=\s+BY)|PERIODIC|REMOVE|REQUIRE|RETURN|SCALAR|SCAN|SET|SKIP|START|STARTS|THEN|UNION|UNIQUE|UNWIND|USING|WHEN|WHERE|WITH|XOR|YIELD)\b/i,function:/\b\w+\b(?=\s*\()/,boolean:/\b(?:true|false|null)\b/i,number:/\b(?:0x[\da-fA-F]+|\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\b/,operator:/:|<--?|--?>?|<>|=~?|[<>]=?|[+*/%^|]|\.\.\.?/,punctuation:/[()[\]{},;.]/}}e.exports=t,t.displayName="cypher",t.aliases=[]},7902(e){"use strict";function t(e){e.languages.d=e.languages.extend("clike",{comment:[{pattern:/^\s*#!.+/,greedy:!0},{pattern:RegExp(/(^|[^\\])/.source+"(?:"+[/\/\+(?:\/\+(?:[^+]|\+(?!\/))*\+\/|(?!\/\+)[\s\S])*?\+\//.source,/\/\/.*/.source,/\/\*[\s\S]*?\*\//.source].join("|")+")"),lookbehind:!0,greedy:!0}],string:[{pattern:RegExp([/\b[rx]"(?:\\[\s\S]|[^\\"])*"[cwd]?/.source,/\bq"(?:\[[\s\S]*?\]|\([\s\S]*?\)|<[\s\S]*?>|\{[\s\S]*?\})"/.source,/\bq"((?!\d)\w+)$[\s\S]*?^\1"/.source,/\bq"(.)[\s\S]*?\2"/.source,/'(?:\\(?:\W|\w+)|[^\\])'/.source,/(["`])(?:\\[\s\S]|(?!\3)[^\\])*\3[cwd]?/.source].join("|"),"m"),greedy:!0},{pattern:/\bq\{(?:\{[^{}]*\}|[^{}])*\}/,greedy:!0,alias:"token-string"}],keyword:/\$|\b(?:abstract|alias|align|asm|assert|auto|body|bool|break|byte|case|cast|catch|cdouble|cent|cfloat|char|class|const|continue|creal|dchar|debug|default|delegate|delete|deprecated|do|double|else|enum|export|extern|false|final|finally|float|for|foreach|foreach_reverse|function|goto|idouble|if|ifloat|immutable|import|inout|int|interface|invariant|ireal|lazy|long|macro|mixin|module|new|nothrow|null|out|override|package|pragma|private|protected|public|pure|real|ref|return|scope|shared|short|static|struct|super|switch|synchronized|template|this|throw|true|try|typedef|typeid|typeof|ubyte|ucent|uint|ulong|union|unittest|ushort|version|void|volatile|wchar|while|with|__(?:(?:FILE|MODULE|LINE|FUNCTION|PRETTY_FUNCTION|DATE|EOF|TIME|TIMESTAMP|VENDOR|VERSION)__|gshared|traits|vector|parameters)|string|wstring|dstring|size_t|ptrdiff_t)\b/,number:[/\b0x\.?[a-f\d_]+(?:(?!\.\.)\.[a-f\d_]*)?(?:p[+-]?[a-f\d_]+)?[ulfi]{0,4}/i,{pattern:/((?:\.\.)?)(?:\b0b\.?|\b|\.)\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:e[+-]?\d[\d_]*)?[ulfi]{0,4}/i,lookbehind:!0}],operator:/\|[|=]?|&[&=]?|\+[+=]?|-[-=]?|\.?\.\.|=[>=]?|!(?:i[ns]\b|<>?=?|>=?|=)?|\bi[ns]\b|(?:<[<>]?|>>?>?|\^\^|[*\/%^~])=?/}),e.languages.insertBefore("d","keyword",{property:/\B@\w*/}),e.languages.insertBefore("d","function",{register:{pattern:/\b(?:[ABCD][LHX]|E[ABCD]X|E?(?:BP|SP|DI|SI)|[ECSDGF]S|CR[0234]|DR[012367]|TR[3-7]|X?MM[0-7]|R[ABCD]X|[BS]PL|R[BS]P|[DS]IL|R[DS]I|R(?:[89]|1[0-5])[BWD]?|XMM(?:[89]|1[0-5])|YMM(?:1[0-5]|\d))\b|\bST(?:\([0-7]\)|\b)/,alias:"variable"}})}e.exports=t,t.displayName="d",t.aliases=[]},28651(e){"use strict";function t(e){var t,n,r,i;t=e,n=[/\b(?:async|sync|yield)\*/,/\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|covariant|default|deferred|do|dynamic|else|enum|export|extension|external|extends|factory|final|finally|for|get|hide|if|implements|interface|import|in|library|mixin|new|null|on|operator|part|rethrow|return|set|show|static|super|switch|sync|this|throw|try|typedef|var|void|while|with|yield)\b/],i={pattern:RegExp((r=/(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source)+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}}}},t.languages.dart=t.languages.extend("clike",{string:[{pattern:/r?("""|''')[\s\S]*?\1/,greedy:!0},{pattern:/r?(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0}],"class-name":[i,{pattern:RegExp(r+/[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),lookbehind:!0,inside:i.inside}],keyword:n,operator:/\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/}),t.languages.insertBefore("dart","function",{metadata:{pattern:/@\w+/,alias:"symbol"}}),t.languages.insertBefore("dart","class-name",{generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":i,keyword:n,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}e.exports=t,t.displayName="dart",t.aliases=[]},55579(e){"use strict";function t(e){var t;(t=e).languages.dataweave={url:/\b[A-Za-z]+:\/\/[\w/:.?=&-]+|\burn:[\w:.?=&-]+/,property:{pattern:/(?:\b\w+#)?(?:"(?:\\.|[^\\"\r\n])*"|\b\w+)(?=\s*[:@])/,greedy:!0},string:{pattern:/(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0},"mime-type":/\b(?:text|audio|video|application|multipart|image)\/[\w+-]+/,date:{pattern:/\|[\w:+-]+\|/,greedy:!0},comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],regex:{pattern:/\/(?:[^\\\/\r\n]|\\[^\r\n])+\//,greedy:!0},function:/\b[A-Z_]\w*(?=\s*\()/i,number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\];(),.:@]/,operator:/<<|>>|->|[<>~=]=?|!=|--?-?|\+\+?|!|\?/,boolean:/\b(?:true|false)\b/,keyword:/\b(?:match|input|output|ns|type|update|null|if|else|using|unless|at|is|as|case|do|fun|var|not|and|or)\b/}}e.exports=t,t.displayName="dataweave",t.aliases=[]},93685(e){"use strict";function t(e){e.languages.dax={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/).*)/,lookbehind:!0},"data-field":{pattern:/'(?:[^']|'')*'(?!')(?:\[[ \w\xA0-\uFFFF]+\])?|\w+\[[ \w\xA0-\uFFFF]+\]/,alias:"symbol"},measure:{pattern:/\[[ \w\xA0-\uFFFF]+\]/,alias:"constant"},string:{pattern:/"(?:[^"]|"")*"(?!")/,greedy:!0},function:/\b(?:ABS|ACOS|ACOSH|ACOT|ACOTH|ADDCOLUMNS|ADDMISSINGITEMS|ALL|ALLCROSSFILTERED|ALLEXCEPT|ALLNOBLANKROW|ALLSELECTED|AND|APPROXIMATEDISTINCTCOUNT|ASIN|ASINH|ATAN|ATANH|AVERAGE|AVERAGEA|AVERAGEX|BETA\.DIST|BETA\.INV|BLANK|CALCULATE|CALCULATETABLE|CALENDAR|CALENDARAUTO|CEILING|CHISQ\.DIST|CHISQ\.DIST\.RT|CHISQ\.INV|CHISQ\.INV\.RT|CLOSINGBALANCEMONTH|CLOSINGBALANCEQUARTER|CLOSINGBALANCEYEAR|COALESCE|COMBIN|COMBINA|COMBINEVALUES|CONCATENATE|CONCATENATEX|CONFIDENCE\.NORM|CONFIDENCE\.T|CONTAINS|CONTAINSROW|CONTAINSSTRING|CONTAINSSTRINGEXACT|CONVERT|COS|COSH|COT|COTH|COUNT|COUNTA|COUNTAX|COUNTBLANK|COUNTROWS|COUNTX|CROSSFILTER|CROSSJOIN|CURRENCY|CURRENTGROUP|CUSTOMDATA|DATATABLE|DATE|DATEADD|DATEDIFF|DATESBETWEEN|DATESINPERIOD|DATESMTD|DATESQTD|DATESYTD|DATEVALUE|DAY|DEGREES|DETAILROWS|DISTINCT|DISTINCTCOUNT|DISTINCTCOUNTNOBLANK|DIVIDE|EARLIER|EARLIEST|EDATE|ENDOFMONTH|ENDOFQUARTER|ENDOFYEAR|EOMONTH|ERROR|EVEN|EXACT|EXCEPT|EXP|EXPON\.DIST|FACT|FALSE|FILTER|FILTERS|FIND|FIRSTDATE|FIRSTNONBLANK|FIRSTNONBLANKVALUE|FIXED|FLOOR|FORMAT|GCD|GENERATE|GENERATEALL|GENERATESERIES|GEOMEAN|GEOMEANX|GROUPBY|HASONEFILTER|HASONEVALUE|HOUR|IF|IF\.EAGER|IFERROR|IGNORE|INT|INTERSECT|ISBLANK|ISCROSSFILTERED|ISEMPTY|ISERROR|ISEVEN|ISFILTERED|ISINSCOPE|ISLOGICAL|ISNONTEXT|ISNUMBER|ISO\.CEILING|ISODD|ISONORAFTER|ISSELECTEDMEASURE|ISSUBTOTAL|ISTEXT|KEEPFILTERS|KEYWORDMATCH|LASTDATE|LASTNONBLANK|LASTNONBLANKVALUE|LCM|LEFT|LEN|LN|LOG|LOG10|LOOKUPVALUE|LOWER|MAX|MAXA|MAXX|MEDIAN|MEDIANX|MID|MIN|MINA|MINUTE|MINX|MOD|MONTH|MROUND|NATURALINNERJOIN|NATURALLEFTOUTERJOIN|NEXTDAY|NEXTMONTH|NEXTQUARTER|NEXTYEAR|NONVISUAL|NORM\.DIST|NORM\.INV|NORM\.S\.DIST|NORM\.S\.INV|NOT|NOW|ODD|OPENINGBALANCEMONTH|OPENINGBALANCEQUARTER|OPENINGBALANCEYEAR|OR|PARALLELPERIOD|PATH|PATHCONTAINS|PATHITEM|PATHITEMREVERSE|PATHLENGTH|PERCENTILE\.EXC|PERCENTILE\.INC|PERCENTILEX\.EXC|PERCENTILEX\.INC|PERMUT|PI|POISSON\.DIST|POWER|PREVIOUSDAY|PREVIOUSMONTH|PREVIOUSQUARTER|PREVIOUSYEAR|PRODUCT|PRODUCTX|QUARTER|QUOTIENT|RADIANS|RAND|RANDBETWEEN|RANK\.EQ|RANKX|RELATED|RELATEDTABLE|REMOVEFILTERS|REPLACE|REPT|RIGHT|ROLLUP|ROLLUPADDISSUBTOTAL|ROLLUPGROUP|ROLLUPISSUBTOTAL|ROUND|ROUNDDOWN|ROUNDUP|ROW|SAMEPERIODLASTYEAR|SAMPLE|SEARCH|SECOND|SELECTCOLUMNS|SELECTEDMEASURE|SELECTEDMEASUREFORMATSTRING|SELECTEDMEASURENAME|SELECTEDVALUE|SIGN|SIN|SINH|SQRT|SQRTPI|STARTOFMONTH|STARTOFQUARTER|STARTOFYEAR|STDEV\.P|STDEV\.S|STDEVX\.P|STDEVX\.S|SUBSTITUTE|SUBSTITUTEWITHINDEX|SUM|SUMMARIZE|SUMMARIZECOLUMNS|SUMX|SWITCH|T\.DIST|T\.DIST\.2T|T\.DIST\.RT|T\.INV|T\.INV\.2T|TAN|TANH|TIME|TIMEVALUE|TODAY|TOPN|TOPNPERLEVEL|TOPNSKIP|TOTALMTD|TOTALQTD|TOTALYTD|TREATAS|TRIM|TRUE|TRUNC|UNICHAR|UNICODE|UNION|UPPER|USERELATIONSHIP|USERNAME|USEROBJECTID|USERPRINCIPALNAME|UTCNOW|UTCTODAY|VALUE|VALUES|VAR\.P|VAR\.S|VARX\.P|VARX\.S|WEEKDAY|WEEKNUM|XIRR|XNPV|YEAR|YEARFRAC)(?=\s*\()/i,keyword:/\b(?:DEFINE|MEASURE|EVALUATE|ORDER\s+BY|RETURN|VAR|START\s+AT|ASC|DESC)\b/i,boolean:{pattern:/\b(?:TRUE|FALSE|NULL)\b/i,alias:"constant"},number:/\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/:=|[-+*\/=^]|&&?|\|\||<(?:=>?|<|>)?|>[>=]?|\b(?:IN|NOT)\b/i,punctuation:/[;\[\](){}`,.]/}}e.exports=t,t.displayName="dax",t.aliases=[]},13934(e){"use strict";function t(e){e.languages.dhall={comment:/--.*|\{-(?:[^-{]|-(?!\})|\{(?!-)|\{-(?:[^-{]|-(?!\})|\{(?!-))*-\})*-\}/,string:{pattern:/"(?:[^"\\]|\\.)*"|''(?:[^']|'(?!')|'''|''\$\{)*''(?!'|\$)/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^{}]*\}/,inside:{expression:{pattern:/(^\$\{)[\s\S]+(?=\}$)/,lookbehind:!0,alias:"language-dhall",inside:null},punctuation:/\$\{|\}/}}}},label:{pattern:/`[^`]*`/,greedy:!0},url:{pattern:/\bhttps?:\/\/[\w.:%!$&'*+;=@~-]+(?:\/[\w.:%!$&'*+;=@~-]*)*(?:\?[/?\w.:%!$&'*+;=@~-]*)?/,greedy:!0},env:{pattern:/\benv:(?:(?!\d)\w+|"(?:[^"\\=]|\\.)*")/,greedy:!0,inside:{function:/^env/,operator:/^:/,variable:/[\s\S]+/}},hash:{pattern:/\bsha256:[\da-fA-F]{64}\b/,inside:{function:/sha256/,operator:/:/,number:/[\da-fA-F]{64}/}},keyword:/\b(?:as|assert|else|forall|if|in|let|merge|missing|then|toMap|using|with)\b|\u2200/,builtin:/\b(?:Some|None)\b/,boolean:/\b(?:False|True)\b/,number:/\bNaN\b|-?\bInfinity\b|[+-]?\b(?:0x[\da-fA-F]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/,operator:/\/\\|\/\/\\\\|&&|\|\||===|[!=]=|\/\/|->|\+\+|::|[+*#@=:?<>|\\\u2227\u2a53\u2261\u2afd\u03bb\u2192]/,punctuation:/\.\.|[{}\[\](),./]/,"class-name":/\b[A-Z]\w*\b/},e.languages.dhall.string.inside.interpolation.inside.expression.inside=e.languages.dhall}e.exports=t,t.displayName="dhall",t.aliases=[]},93336(e){"use strict";function t(e){var t,n;(t=e).languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]},Object.keys(n={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"}).forEach(function(e){var r=n[e],i=[];/^\w+$/.test(e)||i.push(/\w+/.exec(e)[0]),"diff"===e&&i.push("bold"),t.languages.diff[e]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:i,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(e)[0]}}}}),Object.defineProperty(t.languages.diff,"PREFIXES",{value:n})}e.exports=t,t.displayName="diff",t.aliases=[]},13294(e,t,n){"use strict";var r=n(93205);function i(e){var t,n,i;e.register(r),(t=e).languages.django={comment:/^\{#[\s\S]*?#\}$/,tag:{pattern:/(^\{%[+-]?\s*)\w+/,lookbehind:!0,alias:"keyword"},delimiter:{pattern:/^\{[{%][+-]?|[+-]?[}%]\}$/,alias:"punctuation"},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},filter:{pattern:/(\|)\w+/,lookbehind:!0,alias:"function"},test:{pattern:/(\bis\s+(?:not\s+)?)(?!not\b)\w+/,lookbehind:!0,alias:"function"},function:/\b[a-z_]\w+(?=\s*\()/i,keyword:/\b(?:and|as|by|else|for|if|import|in|is|loop|not|or|recursive|with|without)\b/,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,number:/\b\d+(?:\.\d+)?\b/,boolean:/[Tt]rue|[Ff]alse|[Nn]one/,variable:/\b\w+?\b/,punctuation:/[{}[\](),.:;]/},n=/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}|\{#[\s\S]*?#\}/g,i=t.languages["markup-templating"],t.hooks.add("before-tokenize",function(e){i.buildPlaceholders(e,"django",n)}),t.hooks.add("after-tokenize",function(e){i.tokenizePlaceholders(e,"django")}),t.languages.jinja2=t.languages.django,t.hooks.add("before-tokenize",function(e){i.buildPlaceholders(e,"jinja2",n)}),t.hooks.add("after-tokenize",function(e){i.tokenizePlaceholders(e,"jinja2")})}e.exports=i,i.displayName="django",i.aliases=["jinja2"]},38223(e){"use strict";function t(e){e.languages["dns-zone-file"]={comment:/;.*/,string:{pattern:/"(?:\\.|[^"\\\r\n])*"/,greedy:!0},variable:[{pattern:/(^\$ORIGIN[ \t]+)\S+/m,lookbehind:!0},{pattern:/(^|\s)@(?=\s|$)/,lookbehind:!0}],keyword:/^\$(?:ORIGIN|INCLUDE|TTL)(?=\s|$)/m,class:{pattern:/(^|\s)(?:IN|CH|CS|HS)(?=\s|$)/,lookbehind:!0,alias:"keyword"},type:{pattern:/(^|\s)(?:A|A6|AAAA|AFSDB|APL|ATMA|CAA|CDNSKEY|CDS|CERT|CNAME|DHCID|DLV|DNAME|DNSKEY|DS|EID|GID|GPOS|HINFO|HIP|IPSECKEY|ISDN|KEY|KX|LOC|MAILA|MAILB|MB|MD|MF|MG|MINFO|MR|MX|NAPTR|NB|NBSTAT|NIMLOC|NINFO|NS|NSAP|NSAP-PTR|NSEC|NSEC3|NSEC3PARAM|NULL|NXT|OPENPGPKEY|PTR|PX|RKEY|RP|RRSIG|RT|SIG|SINK|SMIMEA|SOA|SPF|SRV|SSHFP|TA|TKEY|TLSA|TSIG|TXT|UID|UINFO|UNSPEC|URI|WKS|X25)(?=\s|$)/,lookbehind:!0,alias:"keyword"},punctuation:/[()]/},e.languages["dns-zone"]=e.languages["dns-zone-file"]}e.exports=t,t.displayName="dnsZoneFile",t.aliases=[]},97266(e){"use strict";function t(e){!function(e){var t=/\\[\r\n](?:\s|\\[\r\n]|#.*(?!.))*(?![\s#]|\\[\r\n])/.source,n=/(?:[ \t]+(?![ \t])(?:)?|)/.source.replace(//g,function(){return t}),r=/"(?:[^"\\\r\n]|\\(?:\r\n|[\s\S]))*"|'(?:[^'\\\r\n]|\\(?:\r\n|[\s\S]))*'/.source,i=/--[\w-]+=(?:|(?!["'])(?:[^\s\\]|\\.)+)/.source.replace(//g,function(){return r}),a={pattern:RegExp(r),greedy:!0},o={pattern:/(^[ \t]*)#.*/m,lookbehind:!0,greedy:!0};function s(e,t){return e=e.replace(//g,function(){return i}).replace(//g,function(){return n}),RegExp(e,t)}e.languages.docker={instruction:{pattern:/(^[ \t]*)(?:ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|ONBUILD|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)(?=\s)(?:\\.|[^\r\n\\])*(?:\\$(?:\s|#.*$)*(?![\s#])(?:\\.|[^\r\n\\])*)*/im,lookbehind:!0,greedy:!0,inside:{options:{pattern:s(/(^(?:ONBUILD)?\w+)(?:)*/.source,"i"),lookbehind:!0,greedy:!0,inside:{property:{pattern:/(^|\s)--[\w-]+/,lookbehind:!0},string:[a,{pattern:/(=)(?!["'])(?:[^\s\\]|\\.)+/,lookbehind:!0}],operator:/\\$/m,punctuation:/=/}},keyword:[{pattern:s(/(^(?:ONBUILD)?HEALTHCHECK(?:)*)(?:CMD|NONE)\b/.source,"i"),lookbehind:!0,greedy:!0},{pattern:s(/(^(?:ONBUILD)?FROM(?:)*(?!--)[^ \t\\]+)AS/.source,"i"),lookbehind:!0,greedy:!0},{pattern:s(/(^ONBUILD)\w+/.source,"i"),lookbehind:!0,greedy:!0},{pattern:/^\w+/,greedy:!0}],comment:o,string:a,variable:/\$(?:\w+|\{[^{}"'\\]*\})/,operator:/\\$/m}},comment:o},e.languages.dockerfile=e.languages.docker}(e)}e.exports=t,t.displayName="docker",t.aliases=["dockerfile"]},80636(e){"use strict";function t(e){!function(e){var t="(?:"+[/[a-zA-Z_\x80-\uFFFF][\w\x80-\uFFFF]*/.source,/-?(?:\.\d+|\d+(?:\.\d*)?)/.source,/"[^"\\]*(?:\\[\s\S][^"\\]*)*"/.source,/<(?:[^<>]|(?!)*>/.source].join("|")+")",n={markup:{pattern:/(^<)[\s\S]+(?=>$)/,lookbehind:!0,alias:["language-markup","language-html","language-xml"],inside:e.languages.markup}};function r(e,n){return RegExp(e.replace(//g,function(){return t}),n)}e.languages.dot={comment:{pattern:/\/\/.*|\/\*[\s\S]*?\*\/|^#.*/m,greedy:!0},"graph-name":{pattern:r(/(\b(?:digraph|graph|subgraph)[ \t\r\n]+)/.source,"i"),lookbehind:!0,greedy:!0,alias:"class-name",inside:n},"attr-value":{pattern:r(/(=[ \t\r\n]*)/.source),lookbehind:!0,greedy:!0,inside:n},"attr-name":{pattern:r(/([\[;, \t\r\n])(?=[ \t\r\n]*=)/.source),lookbehind:!0,greedy:!0,inside:n},keyword:/\b(?:digraph|edge|graph|node|strict|subgraph)\b/i,"compass-point":{pattern:/(:[ \t\r\n]*)(?:[ns][ew]?|[ewc_])(?![\w\x80-\uFFFF])/,lookbehind:!0,alias:"builtin"},node:{pattern:r(/(^|[^-.\w\x80-\uFFFF\\])/.source),lookbehind:!0,greedy:!0,inside:n},operator:/[=:]|-[->]/,punctuation:/[\[\]{};,]/},e.languages.gv=e.languages.dot}(e)}e.exports=t,t.displayName="dot",t.aliases=["gv"]},36500(e){"use strict";function t(e){e.languages.ebnf={comment:/\(\*[\s\S]*?\*\)/,string:{pattern:/"[^"\r\n]*"|'[^'\r\n]*'/,greedy:!0},special:{pattern:/\?[^?\r\n]*\?/,greedy:!0,alias:"class-name"},definition:{pattern:/^([\t ]*)[a-z]\w*(?:[ \t]+[a-z]\w*)*(?=\s*=)/im,lookbehind:!0,alias:["rule","keyword"]},rule:/\b[a-z]\w*(?:[ \t]+[a-z]\w*)*\b/i,punctuation:/\([:/]|[:/]\)|[.,;()[\]{}]/,operator:/[-=|*/!]/}}e.exports=t,t.displayName="ebnf",t.aliases=[]},30296(e){"use strict";function t(e){e.languages.editorconfig={comment:/[;#].*/,section:{pattern:/(^[ \t]*)\[.+\]/m,lookbehind:!0,alias:"keyword",inside:{regex:/\\\\[\[\]{},!?.*]/,operator:/[!?]|\.\.|\*{1,2}/,punctuation:/[\[\]{},]/}},property:{pattern:/(^[ \t]*)[^\s=]+(?=[ \t]*=)/m,lookbehind:!0},value:{pattern:/=.*/,alias:"string",inside:{punctuation:/^=/}}}}e.exports=t,t.displayName="editorconfig",t.aliases=[]},50115(e){"use strict";function t(e){e.languages.eiffel={comment:/--.*/,string:[{pattern:/"([^[]*)\[[\s\S]*?\]\1"/,greedy:!0},{pattern:/"([^{]*)\{[\s\S]*?\}\1"/,greedy:!0},{pattern:/"(?:%(?:(?!\n)\s)*\n\s*%|%\S|[^%"\r\n])*"/,greedy:!0}],char:/'(?:%.|[^%'\r\n])+'/,keyword:/\b(?:across|agent|alias|all|and|attached|as|assign|attribute|check|class|convert|create|Current|debug|deferred|detachable|do|else|elseif|end|ensure|expanded|export|external|feature|from|frozen|if|implies|inherit|inspect|invariant|like|local|loop|not|note|obsolete|old|once|or|Precursor|redefine|rename|require|rescue|Result|retry|select|separate|some|then|undefine|until|variant|Void|when|xor)\b/i,boolean:/\b(?:True|False)\b/i,"class-name":{pattern:/\b[A-Z][\dA-Z_]*\b/,alias:"builtin"},number:[/\b0[xcb][\da-f](?:_*[\da-f])*\b/i,/(?:\b\d(?:_*\d)*)?\.(?:(?:\d(?:_*\d)*)?e[+-]?)?\d(?:_*\d)*\b|\b\d(?:_*\d)*\b\.?/i],punctuation:/:=|<<|>>|\(\||\|\)|->|\.(?=\w)|[{}[\];(),:?]/,operator:/\\\\|\|\.\.\||\.\.|\/[~\/=]?|[><]=?|[-+*^=~]/}}e.exports=t,t.displayName="eiffel",t.aliases=[]},20791(e,t,n){"use strict";var r=n(93205);function i(e){var t;e.register(r),(t=e).languages.ejs={delimiter:{pattern:/^<%[-_=]?|[-_]?%>$/,alias:"punctuation"},comment:/^#[\s\S]*/,"language-javascript":{pattern:/[\s\S]+/,inside:t.languages.javascript}},t.hooks.add("before-tokenize",function(e){var n=/<%(?!%)[\s\S]+?%>/g;t.languages["markup-templating"].buildPlaceholders(e,"ejs",n)}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"ejs")}),t.languages.eta=t.languages.ejs}e.exports=i,i.displayName="ejs",i.aliases=["eta"]},11974(e){"use strict";function t(e){e.languages.elixir={doc:{pattern:/@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/,inside:{attribute:/^@\w+/,string:/['"][\s\S]+/}},comment:{pattern:/#.*/m,greedy:!0},regex:{pattern:/~[rR](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|[^\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[uismxfr]*/,greedy:!0},string:[{pattern:/~[cCsSwW](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|#\{[^}]+\}|#(?!\{)|[^#\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[csa]?/,greedy:!0,inside:{}},{pattern:/("""|''')[\s\S]*?\1/,greedy:!0,inside:{}},{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{}}],atom:{pattern:/(^|[^:]):\w+/,lookbehind:!0,alias:"symbol"},module:{pattern:/\b[A-Z]\w*\b/,alias:"class-name"},"attr-name":/\b\w+\??:(?!:)/,argument:{pattern:/(^|[^&])&\d+/,lookbehind:!0,alias:"variable"},attribute:{pattern:/@\w+/,alias:"variable"},function:/\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d))/,number:/\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,keyword:/\b(?:after|alias|and|case|catch|cond|def(?:callback|delegate|exception|impl|macro|module|n|np|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|quote|raise|require|rescue|try|unless|unquote|use|when)\b/,boolean:/\b(?:true|false|nil)\b/,operator:[/\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,{pattern:/([^<])<(?!<)/,lookbehind:!0},{pattern:/([^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,%\[\]{}()]/},e.languages.elixir.string.forEach(function(t){t.inside={interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"},rest:e.languages.elixir}}}})}e.exports=t,t.displayName="elixir",t.aliases=[]},8645(e){"use strict";function t(e){e.languages.elm={comment:/--.*|\{-[\s\S]*?-\}/,char:{pattern:/'(?:[^\\'\r\n]|\\(?:[abfnrtv\\']|\d+|x[0-9a-fA-F]+))'/,greedy:!0},string:[{pattern:/"""[\s\S]*?"""/,greedy:!0},{pattern:/"(?:[^\\"\r\n]|\\.)*"/,greedy:!0}],"import-statement":{pattern:/(^[\t ]*)import\s+[A-Z]\w*(?:\.[A-Z]\w*)*(?:\s+as\s+(?:[A-Z]\w*)(?:\.[A-Z]\w*)*)?(?:\s+exposing\s+)?/m,lookbehind:!0,inside:{keyword:/\b(?:import|as|exposing)\b/}},keyword:/\b(?:alias|as|case|else|exposing|if|in|infixl|infixr|let|module|of|then|type)\b/,builtin:/\b(?:abs|acos|always|asin|atan|atan2|ceiling|clamp|compare|cos|curry|degrees|e|flip|floor|fromPolar|identity|isInfinite|isNaN|logBase|max|min|negate|never|not|pi|radians|rem|round|sin|sqrt|tan|toFloat|toPolar|toString|truncate|turns|uncurry|xor)\b/,number:/\b(?:\d+(?:\.\d+)?(?:e[+-]?\d+)?|0x[0-9a-f]+)\b/i,operator:/\s\.\s|[+\-/*=.$<>:&|^?%#@~!]{2,}|[+\-/*=$<>:&|^?%#@~!]/,hvariable:/\b(?:[A-Z]\w*\.)*[a-z]\w*\b/,constant:/\b(?:[A-Z]\w*\.)*[A-Z]\w*\b/,punctuation:/[{}[\]|(),.:]/}}e.exports=t,t.displayName="elm",t.aliases=[]},84790(e,t,n){"use strict";var r=n(56939),i=n(93205);function a(e){var t;e.register(r),e.register(i),(t=e).languages.erb=t.languages.extend("ruby",{}),t.languages.insertBefore("erb","comment",{delimiter:{pattern:/^<%=?|%>$/,alias:"punctuation"}}),t.hooks.add("before-tokenize",function(e){var n=/<%=?(?:[^\r\n]|[\r\n](?!=begin)|[\r\n]=begin\s(?:[^\r\n]|[\r\n](?!=end))*[\r\n]=end)+?%>/gm;t.languages["markup-templating"].buildPlaceholders(e,"erb",n)}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"erb")})}e.exports=a,a.displayName="erb",a.aliases=[]},4502(e){"use strict";function t(e){e.languages.erlang={comment:/%.+/,string:{pattern:/"(?:\\.|[^\\"\r\n])*"/,greedy:!0},"quoted-function":{pattern:/'(?:\\.|[^\\'\r\n])+'(?=\()/,alias:"function"},"quoted-atom":{pattern:/'(?:\\.|[^\\'\r\n])+'/,alias:"atom"},boolean:/\b(?:true|false)\b/,keyword:/\b(?:fun|when|case|of|end|if|receive|after|try|catch)\b/,number:[/\$\\?./,/\b\d+#[a-z0-9]+/i,/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i],function:/\b[a-z][\w@]*(?=\()/,variable:{pattern:/(^|[^@])(?:\b|\?)[A-Z_][\w@]*/,lookbehind:!0},operator:[/[=\/<>:]=|=[:\/]=|\+\+?|--?|[=*\/!]|\b(?:bnot|div|rem|band|bor|bxor|bsl|bsr|not|and|or|xor|orelse|andalso)\b/,{pattern:/(^|[^<])<(?!<)/,lookbehind:!0},{pattern:/(^|[^>])>(?!>)/,lookbehind:!0}],atom:/\b[a-z][\w@]*/,punctuation:/[()[\]{}:;,.#|]|<<|>>/}}e.exports=t,t.displayName="erlang",t.aliases=[]},66055(e,t,n){"use strict";var r=n(59803),i=n(93205);function a(e){var t;e.register(r),e.register(i),(t=e).languages.etlua={delimiter:{pattern:/^<%[-=]?|-?%>$/,alias:"punctuation"},"language-lua":{pattern:/[\s\S]+/,inside:t.languages.lua}},t.hooks.add("before-tokenize",function(e){var n=/<%[\s\S]+?%>/g;t.languages["markup-templating"].buildPlaceholders(e,"etlua",n)}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"etlua")})}e.exports=a,a.displayName="etlua",a.aliases=[]},68876(e){"use strict";function t(e){e.languages["excel-formula"]={comment:{pattern:/(\bN\(\s*)"(?:[^"]|"")*"(?=\s*\))/i,lookbehind:!0,greedy:!0},string:{pattern:/"(?:[^"]|"")*"(?!")/,greedy:!0},reference:{pattern:/(?:'[^']*'|(?:[^\s()[\]{}<>*?"';,$&]*\[[^^\s()[\]{}<>*?"']+\])?\w+)!/,greedy:!0,alias:"string",inside:{operator:/!$/,punctuation:/'/,sheet:{pattern:/[^[\]]+$/,alias:"function"},file:{pattern:/\[[^[\]]+\]$/,inside:{punctuation:/[[\]]/}},path:/[\s\S]+/}},"function-name":{pattern:/\b[A-Z]\w*(?=\()/i,alias:"keyword"},range:{pattern:/\$?\b(?:[A-Z]+\$?\d+:\$?[A-Z]+\$?\d+|[A-Z]+:\$?[A-Z]+|\d+:\$?\d+)\b/i,alias:"property",inside:{operator:/:/,cell:/\$?[A-Z]+\$?\d+/i,column:/\$?[A-Z]+/i,row:/\$?\d+/}},cell:{pattern:/\b[A-Z]+\d+\b|\$[A-Za-z]+\$?\d+\b|\b[A-Za-z]+\$\d+\b/,alias:"property"},number:/(?:\b\d+(?:\.\d+)?|\B\.\d+)(?:e[+-]?\d+)?\b/i,boolean:/\b(?:TRUE|FALSE)\b/i,operator:/[-+*/^%=&,]|<[=>]?|>=?/,punctuation:/[[\]();{}|]/},e.languages.xlsx=e.languages.xls=e.languages["excel-formula"]}e.exports=t,t.displayName="excelFormula",t.aliases=[]},95126(e){"use strict";function t(e){var t,n,r,i,a,o,s,u;t=e,i={comment:[{pattern:/(^|\s)(?:! .*|!$)/,lookbehind:!0,inside:n={function:/\b(?:TODOS?|FIX(?:MES?)?|NOTES?|BUGS?|XX+|HACKS?|WARN(?:ING)?|\?{2,}|!{2,})\b/}},{pattern:/(^|\s)\/\*\s[\s\S]*?\*\/(?=\s|$)/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|\s)!\[(={0,6})\[\s[\s\S]*?\]\2\](?=\s|$)/,lookbehind:!0,greedy:!0,inside:n}],number:[{pattern:/(^|\s)[+-]?\d+(?=\s|$)/,lookbehind:!0},{pattern:/(^|\s)[+-]?0(?:b[01]+|o[0-7]+|d\d+|x[\dA-F]+)(?=\s|$)/i,lookbehind:!0},{pattern:/(^|\s)[+-]?\d+\/\d+\.?(?=\s|$)/,lookbehind:!0},{pattern:/(^|\s)\+?\d+\+\d+\/\d+(?=\s|$)/,lookbehind:!0},{pattern:/(^|\s)-\d+-\d+\/\d+(?=\s|$)/,lookbehind:!0},{pattern:/(^|\s)[+-]?(?:\d*\.\d+|\d+\.\d*|\d+)(?:e[+-]?\d+)?(?=\s|$)/i,lookbehind:!0},{pattern:/(^|\s)NAN:\s+[\da-fA-F]+(?=\s|$)/,lookbehind:!0},{pattern:/(^|\s)[+-]?0(?:b1\.[01]*|o1\.[0-7]*|d1\.\d*|x1\.[\dA-F]*)p\d+(?=\s|$)/i,lookbehind:!0}],regexp:{pattern:/(^|\s)R\/\s(?:\\\S|[^\\/])*\/(?:[idmsr]*|[idmsr]+-[idmsr]+)(?=\s|$)/,lookbehind:!0,alias:"number",inside:{variable:/\\\S/,keyword:/[+?*\[\]^$(){}.|]/,operator:{pattern:/(\/)[idmsr]+(?:-[idmsr]+)?/,lookbehind:!0}}},boolean:{pattern:/(^|\s)[tf](?=\s|$)/,lookbehind:!0},"custom-string":{pattern:/(^|\s)[A-Z0-9\-]+"\s(?:\\\S|[^"\\])*"/,lookbehind:!0,greedy:!0,alias:"string",inside:{number:/\\\S|%\w|\//}},"multiline-string":[{pattern:/(^|\s)STRING:\s+\S+(?:\n|\r\n).*(?:\n|\r\n)\s*;(?=\s|$)/,lookbehind:!0,greedy:!0,alias:"string",inside:{number:(r={number:/\\[^\s']|%\w/}).number,"semicolon-or-setlocal":{pattern:/([\r\n][ \t]*);(?=\s|$)/,lookbehind:!0,alias:"function"}}},{pattern:/(^|\s)HEREDOC:\s+\S+(?:\n|\r\n).*(?:\n|\r\n)\s*\S+(?=\s|$)/,lookbehind:!0,greedy:!0,alias:"string",inside:r},{pattern:/(^|\s)\[(={0,6})\[\s[\s\S]*?\]\2\](?=\s|$)/,lookbehind:!0,greedy:!0,alias:"string",inside:r}],"special-using":{pattern:/(^|\s)USING:(?:\s\S+)*(?=\s+;(?:\s|$))/,lookbehind:!0,alias:"function",inside:{string:{pattern:/(\s)[^:\s]+/,lookbehind:!0}}},"stack-effect-delimiter":[{pattern:/(^|\s)(?:call|execute|eval)?\((?=\s)/,lookbehind:!0,alias:"operator"},{pattern:/(\s)--(?=\s)/,lookbehind:!0,alias:"operator"},{pattern:/(\s)\)(?=\s|$)/,lookbehind:!0,alias:"operator"}],combinators:{pattern:null,lookbehind:!0,alias:"keyword"},"kernel-builtin":{pattern:null,lookbehind:!0,alias:"variable"},"sequences-builtin":{pattern:null,lookbehind:!0,alias:"variable"},"math-builtin":{pattern:null,lookbehind:!0,alias:"variable"},"constructor-word":{pattern:/(^|\s)<(?!=+>|-+>)\S+>(?=\s|$)/,lookbehind:!0,alias:"keyword"},"other-builtin-syntax":{pattern:null,lookbehind:!0,alias:"operator"},"conventionally-named-word":{pattern:/(^|\s)(?!")(?:(?:set|change|with|new)-\S+|\$\S+|>[^>\s]+|[^:>\s]+>|[^>\s]+>[^>\s]+|\+[^+\s]+\+|[^?\s]+\?|\?[^?\s]+|[^>\s]+>>|>>[^>\s]+|[^<\s]+<<|\([^()\s]+\)|[^!\s]+!|[^*\s]\S*\*|[^.\s]\S*\.)(?=\s|$)/,lookbehind:!0,alias:"keyword"},"colon-syntax":{pattern:/(^|\s)(?:[A-Z0-9\-]+#?)?:{1,2}\s+(?:;\S+|(?!;)\S+)(?=\s|$)/,lookbehind:!0,greedy:!0,alias:"function"},"semicolon-or-setlocal":{pattern:/(\s)(?:;|:>)(?=\s|$)/,lookbehind:!0,alias:"function"},"curly-brace-literal-delimiter":[{pattern:/(^|\s)[a-z]*\{(?=\s)/i,lookbehind:!0,alias:"operator"},{pattern:/(\s)\}(?=\s|$)/,lookbehind:!0,alias:"operator"}],"quotation-delimiter":[{pattern:/(^|\s)\[(?=\s)/,lookbehind:!0,alias:"operator"},{pattern:/(\s)\](?=\s|$)/,lookbehind:!0,alias:"operator"}],"normal-word":{pattern:/(^|\s)[^"\s]\S*(?=\s|$)/,lookbehind:!0},string:{pattern:/"(?:\\\S|[^"\\])*"/,greedy:!0,inside:r}},a=function(e){return(e+"").replace(/([.?*+\^$\[\]\\(){}|\-])/g,"\\$1")},o=function(e){return RegExp("(^|\\s)(?:"+e.map(a).join("|")+")(?=\\s|$)")},Object.keys(s={"kernel-builtin":["or","2nipd","4drop","tuck","wrapper","nip","wrapper?","callstack>array","die","dupd","callstack","callstack?","3dup","hashcode","pick","4nip","build",">boolean","nipd","clone","5nip","eq?","?","=","swapd","2over","clear","2dup","get-retainstack","not","tuple?","dup","3nipd","call","-rotd","object","drop","assert=","assert?","-rot","execute","boa","get-callstack","curried?","3drop","pickd","overd","over","roll","3nip","swap","and","2nip","rotd","throw","(clone)","hashcode*","spin","reach","4dup","equal?","get-datastack","assert","2drop","","boolean?","identity-hashcode","identity-tuple?","null","composed?","new","5drop","rot","-roll","xor","identity-tuple","boolean"],"other-builtin-syntax":["=======","recursive","flushable",">>","<<<<<<","M\\","B","PRIVATE>","\\","======","final","inline","delimiter","deprecated",">>>>>","<<<<<<<","parse-complex","malformed-complex","read-only",">>>>>>>","call-next-method","<<","foldable","$","$[","${"],"sequences-builtin":["member-eq?","mismatch","append","assert-sequence=","longer","repetition","clone-like","3sequence","assert-sequence?","last-index-from","reversed","index-from","cut*","pad-tail","join-as","remove-eq!","concat-as","but-last","snip","nths","nth","sequence","longest","slice?","","remove-nth","tail-slice","empty?","tail*","member?","virtual-sequence?","set-length","drop-prefix","iota","unclip","bounds-error?","unclip-last-slice","non-negative-integer-expected","non-negative-integer-expected?","midpoint@","longer?","?set-nth","?first","rest-slice","prepend-as","prepend","fourth","sift","subseq-start","new-sequence","?last","like","first4","1sequence","reverse","slice","virtual@","repetition?","set-last","index","4sequence","max-length","set-second","immutable-sequence","first2","first3","supremum","unclip-slice","suffix!","insert-nth","tail","3append","short","suffix","concat","flip","immutable?","reverse!","2sequence","sum","delete-all","indices","snip-slice","","check-slice","sequence?","head","append-as","halves","sequence=","collapse-slice","?second","slice-error?","product","bounds-check?","bounds-check","immutable","virtual-exemplar","harvest","remove","pad-head","last","set-fourth","cartesian-product","remove-eq","shorten","shorter","reversed?","shorter?","shortest","head-slice","pop*","tail-slice*","but-last-slice","iota?","append!","cut-slice","new-resizable","head-slice*","sequence-hashcode","pop","set-nth","?nth","second","join","immutable-sequence?","","3append-as","virtual-sequence","subseq?","remove-nth!","length","last-index","lengthen","assert-sequence","copy","move","third","first","tail?","set-first","prefix","bounds-error","","exchange","surround","cut","min-length","set-third","push-all","head?","subseq-start-from","delete-slice","rest","sum-lengths","head*","infimum","remove!","glue","slice-error","subseq","push","replace-slice","subseq-as","unclip-last"],"math-builtin":["number=","next-power-of-2","?1+","fp-special?","imaginary-part","float>bits","number?","fp-infinity?","bignum?","fp-snan?","denominator","gcd","*","+","fp-bitwise=","-","u>=","/",">=","bitand","power-of-2?","log2-expects-positive","neg?","<","log2",">","integer?","number","bits>double","2/","zero?","bits>float","float?","shift","ratio?","rect>","even?","ratio","fp-sign","bitnot",">fixnum","complex?","/i","integer>fixnum","/f","sgn",">bignum","next-float","u<","u>","mod","recip","rational",">float","2^","integer","fixnum?","neg","fixnum","sq","bignum",">rect","bit?","fp-qnan?","simple-gcd","complex","","real",">fraction","double>bits","bitor","rem","fp-nan-payload","real-part","log2-expects-positive?","prev-float","align","unordered?","float","fp-nan?","abs","bitxor","integer>fixnum-strict","u<=","odd?","<=","/mod",">integer","real?","rational?","numerator"]}).forEach(function(e){i[e].pattern=o(s[e])}),u=["2bi","while","2tri","bi*","4dip","both?","same?","tri@","curry","prepose","3bi","?if","tri*","2keep","3keep","curried","2keepd","when","2bi*","2tri*","4keep","bi@","keepdd","do","unless*","tri-curry","if*","loop","bi-curry*","when*","2bi@","2tri@","with","2with","either?","bi","until","3dip","3curry","tri-curry*","tri-curry@","bi-curry","keepd","compose","2dip","if","3tri","unless","tuple","keep","2curry","tri","most","while*","dip","composed","bi-curry@","find-last-from","trim-head-slice","map-as","each-from","none?","trim-tail","partition","if-empty","accumulate*","reject!","find-from","accumulate-as","collector-for-as","reject","map","map-sum","accumulate!","2each-from","follow","supremum-by","map!","unless-empty","collector","padding","reduce-index","replicate-as","infimum-by","trim-tail-slice","count","find-index","filter","accumulate*!","reject-as","map-integers","map-find","reduce","selector","interleave","2map","filter-as","binary-reduce","map-index-as","find","produce","filter!","replicate","cartesian-map","cartesian-each","find-index-from","map-find-last","3map-as","3map","find-last","selector-as","2map-as","2map-reduce","accumulate","each","each-index","accumulate*-as","when-empty","all?","collector-as","push-either","new-like","collector-for","2selector","push-if","2all?","map-reduce","3each","any?","trim-slice","2reduce","change-nth","produce-as","2each","trim","trim-head","cartesian-find","map-index","if-zero","each-integer","unless-zero","(find-integer)","when-zero","find-last-integer","(all-integers?)","times","(each-integer)","find-integer","all-integers?","unless-negative","if-positive","when-positive","when-negative","unless-positive","if-negative","case","2cleave","cond>quot","case>quot","3cleave","wrong-values","to-fixed-point","alist>quot","cond","cleave","call-effect","recursive-hashcode","spread","deep-spread>quot","2||","0||","n||","0&&","2&&","3||","1||","1&&","n&&","3&&","smart-unless*","keep-inputs","reduce-outputs","smart-when*","cleave>array","smart-with","smart-apply","smart-if","inputs/outputs","output>sequence-n","map-outputs","map-reduce-outputs","dropping","output>array","smart-map-reduce","smart-2map-reduce","output>array-n","nullary","inputsequence"],i.combinators.pattern=o(u),t.languages.factor=i}e.exports=t,t.displayName="factor",t.aliases=[]},74644(e){"use strict";function t(e){var t;(t=e).languages.false={comment:{pattern:/\{[^}]*\}/},string:{pattern:/"[^"]*"/,greedy:!0},"character-code":{pattern:/'(?:[^\r]|\r\n?)/,alias:"number"},"assembler-code":{pattern:/\d+`/,alias:"important"},number:/\d+/,operator:/[-!#$%&'*+,./:;=>?@\\^_`|~ßø]/,punctuation:/\[|\]/,variable:/[a-z]/,"non-standard":{pattern:/[()!=]=?|[-+*/%]|\b(?:in|is)\b/}),delete e.languages["firestore-security-rules"]["class-name"],e.languages.insertBefore("firestore-security-rules","keyword",{path:{pattern:/(^|[\s(),])(?:\/(?:[\w\xA0-\uFFFF]+|\{[\w\xA0-\uFFFF]+(?:=\*\*)?\}|\$\([\w\xA0-\uFFFF.]+\)))+/,lookbehind:!0,greedy:!0,inside:{variable:{pattern:/\{[\w\xA0-\uFFFF]+(?:=\*\*)?\}|\$\([\w\xA0-\uFFFF.]+\)/,inside:{operator:/=/,keyword:/\*\*/,punctuation:/[.$(){}]/}},punctuation:/\//}},method:{pattern:/(\ballow\s+)[a-z]+(?:\s*,\s*[a-z]+)*(?=\s*[:;])/,lookbehind:!0,alias:"builtin",inside:{punctuation:/,/}}})}e.exports=t,t.displayName="firestoreSecurityRules",t.aliases=[]},37225(e){"use strict";function t(e){var t;(t=e).languages.flow=t.languages.extend("javascript",{}),t.languages.insertBefore("flow","keyword",{type:[{pattern:/\b(?:[Nn]umber|[Ss]tring|[Bb]oolean|Function|any|mixed|null|void)\b/,alias:"tag"}]}),t.languages.flow["function-variable"].pattern=/(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=\s*(?:function\b|(?:\([^()]*\)(?:\s*:\s*\w+)?|(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/i,delete t.languages.flow.parameter,t.languages.insertBefore("flow","operator",{"flow-punctuation":{pattern:/\{\||\|\}/,alias:"punctuation"}}),Array.isArray(t.languages.flow.keyword)||(t.languages.flow.keyword=[t.languages.flow.keyword]),t.languages.flow.keyword.unshift({pattern:/(^|[^$]\b)(?:type|opaque|declare|Class)\b(?!\$)/,lookbehind:!0},{pattern:/(^|[^$]\B)\$(?:await|Diff|Exact|Keys|ObjMap|PropertyType|Shape|Record|Supertype|Subtype|Enum)\b(?!\$)/,lookbehind:!0})}e.exports=t,t.displayName="flow",t.aliases=[]},16725(e){"use strict";function t(e){e.languages.fortran={"quoted-number":{pattern:/[BOZ](['"])[A-F0-9]+\1/i,alias:"number"},string:{pattern:/(?:\b\w+_)?(['"])(?:\1\1|&(?:\r\n?|\n)(?:[ \t]*!.*(?:\r\n?|\n)|(?![ \t]*!))|(?!\1).)*(?:\1|&)/,inside:{comment:{pattern:/(&(?:\r\n?|\n)\s*)!.*/,lookbehind:!0}}},comment:{pattern:/!.*/,greedy:!0},boolean:/\.(?:TRUE|FALSE)\.(?:_\w+)?/i,number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[ED][+-]?\d+)?(?:_\w+)?/i,keyword:[/\b(?:INTEGER|REAL|DOUBLE ?PRECISION|COMPLEX|CHARACTER|LOGICAL)\b/i,/\b(?:END ?)?(?:BLOCK ?DATA|DO|FILE|FORALL|FUNCTION|IF|INTERFACE|MODULE(?! PROCEDURE)|PROGRAM|SELECT|SUBROUTINE|TYPE|WHERE)\b/i,/\b(?:ALLOCATABLE|ALLOCATE|BACKSPACE|CALL|CASE|CLOSE|COMMON|CONTAINS|CONTINUE|CYCLE|DATA|DEALLOCATE|DIMENSION|DO|END|EQUIVALENCE|EXIT|EXTERNAL|FORMAT|GO ?TO|IMPLICIT(?: NONE)?|INQUIRE|INTENT|INTRINSIC|MODULE PROCEDURE|NAMELIST|NULLIFY|OPEN|OPTIONAL|PARAMETER|POINTER|PRINT|PRIVATE|PUBLIC|READ|RETURN|REWIND|SAVE|SELECT|STOP|TARGET|WHILE|WRITE)\b/i,/\b(?:ASSIGNMENT|DEFAULT|ELEMENTAL|ELSE|ELSEWHERE|ELSEIF|ENTRY|IN|INCLUDE|INOUT|KIND|NULL|ONLY|OPERATOR|OUT|PURE|RECURSIVE|RESULT|SEQUENCE|STAT|THEN|USE)\b/i],operator:[/\*\*|\/\/|=>|[=\/]=|[<>]=?|::|[+\-*=%]|\.[A-Z]+\./i,{pattern:/(^|(?!\().)\/(?!\))/,lookbehind:!0}],punctuation:/\(\/|\/\)|[(),;:&]/}}e.exports=t,t.displayName="fortran",t.aliases=[]},95559(e){"use strict";function t(e){e.languages.fsharp=e.languages.extend("clike",{comment:[{pattern:/(^|[^\\])\(\*(?!\))[\s\S]*?\*\)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(?:"""[\s\S]*?"""|@"(?:""|[^"])*"|"(?:\\[\s\S]|[^\\"])*")B?|'(?:[^\\']|\\(?:.|\d{3}|x[a-fA-F\d]{2}|u[a-fA-F\d]{4}|U[a-fA-F\d]{8}))'B?/,greedy:!0},"class-name":{pattern:/(\b(?:exception|inherit|interface|new|of|type)\s+|\w\s*:\s*|\s:\??>\s*)[.\w]+\b(?:\s*(?:->|\*)\s*[.\w]+\b)*(?!\s*[:.])/,lookbehind:!0,inside:{operator:/->|\*/,punctuation:/\./}},keyword:/\b(?:let|return|use|yield)(?:!\B|\b)|\b(?:abstract|and|as|assert|base|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|global|if|in|inherit|inline|interface|internal|lazy|match|member|module|mutable|namespace|new|not|null|of|open|or|override|private|public|rec|select|static|struct|then|to|true|try|type|upcast|val|void|when|while|with|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|include|method|mixin|object|parallel|process|protected|pure|sealed|tailcall|trait|virtual|volatile)\b/,number:[/\b0x[\da-fA-F]+(?:un|lf|LF)?\b/,/\b0b[01]+(?:y|uy)?\b/,/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[fm]|e[+-]?\d+)?\b/i,/\b\d+(?:[IlLsy]|u[lsy]?|UL)?\b/],operator:/([<>~&^])\1\1|([*.:<>&])\2|<-|->|[!=:]=|?|\??(?:<=|>=|<>|[-+*/%=<>])\??|[!?^&]|~[+~-]|:>|:\?>?/}),e.languages.insertBefore("fsharp","keyword",{preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(^#)\b(?:else|endif|if|light|line|nowarn)\b/,lookbehind:!0,alias:"keyword"}}}}),e.languages.insertBefore("fsharp","punctuation",{"computation-expression":{pattern:/\b[_a-z]\w*(?=\s*\{)/i,alias:"keyword"}}),e.languages.insertBefore("fsharp","string",{annotation:{pattern:/\[<.+?>\]/,inside:{punctuation:/^\[<|>\]$/,"class-name":{pattern:/^\w+$|(^|;\s*)[A-Z]\w*(?=\()/,lookbehind:!0},"annotation-content":{pattern:/[\s\S]+/,inside:e.languages.fsharp}}}})}e.exports=t,t.displayName="fsharp",t.aliases=[]},82114(e,t,n){"use strict";var r=n(93205);function i(e){e.register(r),function(e){for(var t=/[^<()"']|\((?:)*\)|<(?!#--)|<#--(?:[^-]|-(?!->))*-->|"(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*'/.source,n=0;n<2;n++)t=t.replace(//g,function(){return t});t=t.replace(//g,/[^\s\S]/.source);var r={comment:/<#--[\s\S]*?-->/,string:[{pattern:/\br("|')(?:(?!\1)[^\\]|\\.)*\1/,greedy:!0},{pattern:RegExp(/("|')(?:(?!\1|\$\{)[^\\]|\\.|\$\{(?:(?!\})(?:))*\})*\1/.source.replace(//g,function(){return t})),greedy:!0,inside:{interpolation:{pattern:RegExp(/((?:^|[^\\])(?:\\\\)*)\$\{(?:(?!\})(?:))*\}/.source.replace(//g,function(){return t})),lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:null}}}}],keyword:/\b(?:as)\b/,boolean:/\b(?:true|false)\b/,"builtin-function":{pattern:/((?:^|[^?])\?\s*)\w+/,lookbehind:!0,alias:"function"},function:/\b\w+(?=\s*\()/,number:/\b\d+(?:\.\d+)?\b/,operator:/\.\.[<*!]?|->|--|\+\+|&&|\|\||\?{1,2}|[-+*/%!=<>]=?|\b(?:gt|gte|lt|lte)\b/,punctuation:/[,;.:()[\]{}]/};r.string[1].inside.interpolation.inside.rest=r,e.languages.ftl={"ftl-comment":{pattern:/^<#--[\s\S]*/,alias:"comment"},"ftl-directive":{pattern:/^<[\s\S]+>$/,inside:{directive:{pattern:/(^<\/?)[#@][a-z]\w*/i,lookbehind:!0,alias:"keyword"},punctuation:/^<\/?|\/?>$/,content:{pattern:/\s*\S[\s\S]*/,alias:"ftl",inside:r}}},"ftl-interpolation":{pattern:/^\$\{[\s\S]*\}$/,inside:{punctuation:/^\$\{|\}$/,content:{pattern:/\s*\S[\s\S]*/,alias:"ftl",inside:r}}}},e.hooks.add("before-tokenize",function(n){var r=RegExp(/<#--[\s\S]*?-->|<\/?[#@][a-zA-Z](?:)*?>|\$\{(?:)*?\}/.source.replace(//g,function(){return t}),"gi");e.languages["markup-templating"].buildPlaceholders(n,"ftl",r)}),e.hooks.add("after-tokenize",function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"ftl")})}(e)}e.exports=i,i.displayName="ftl",i.aliases=[]},12208(e){"use strict";function t(e){e.languages.gcode={comment:/;.*|\B\(.*?\)\B/,string:{pattern:/"(?:""|[^"])*"/,greedy:!0},keyword:/\b[GM]\d+(?:\.\d+)?\b/,property:/\b[A-Z]/,checksum:{pattern:/\*\d+/,alias:"punctuation"},punctuation:/:/}}e.exports=t,t.displayName="gcode",t.aliases=[]},62728(e){"use strict";function t(e){e.languages.gdscript={comment:/#.*/,string:{pattern:/@?(?:("|')(?:(?!\1)[^\n\\]|\\[\s\S])*\1(?!"|')|"""(?:[^\\]|\\[\s\S])*?""")/,greedy:!0},"class-name":{pattern:/(^(?:class_name|class|extends)[ \t]+|^export\([ \t]*|\bas[ \t]+|(?:\b(?:const|var)[ \t]|[,(])[ \t]*\w+[ \t]*:[ \t]*|->[ \t]*)[a-zA-Z_]\w*/m,lookbehind:!0},keyword:/\b(?:and|as|assert|break|breakpoint|class|class_name|const|continue|elif|else|enum|export|extends|for|func|if|in|is|master|mastersync|match|not|null|onready|or|pass|preload|puppet|puppetsync|remote|remotesync|return|self|setget|signal|static|tool|var|while|yield)\b/,function:/\b[a-z_]\w*(?=[ \t]*\()/i,variable:/\$\w+/,number:[/\b0b[01_]+\b|\b0x[\da-fA-F_]+\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.[\d_]+)(?:e[+-]?[\d_]+)?\b/,/\b(?:INF|NAN|PI|TAU)\b/],constant:/\b[A-Z][A-Z_\d]*\b/,boolean:/\b(?:false|true)\b/,operator:/->|:=|&&|\|\||<<|>>|[-+*/%&|!<>=]=?|[~^]/,punctuation:/[.:,;()[\]{}]/}}e.exports=t,t.displayName="gdscript",t.aliases=[]},81549(e){"use strict";function t(e){e.languages.gedcom={"line-value":{pattern:/(^[\t ]*\d+ +(?:@\w[\w!"$%&'()*+,\-./:;<=>?[\\\]^`{|}~\x80-\xfe #]*@ +)?\w+ ).+/m,lookbehind:!0,inside:{pointer:{pattern:/^@\w[\w!"$%&'()*+,\-./:;<=>?[\\\]^`{|}~\x80-\xfe #]*@$/,alias:"variable"}}},tag:{pattern:/(^[\t ]*\d+ +(?:@\w[\w!"$%&'()*+,\-./:;<=>?[\\\]^`{|}~\x80-\xfe #]*@ +)?)\w+/m,lookbehind:!0,alias:"string"},level:{pattern:/(^[\t ]*)\d+/m,lookbehind:!0,alias:"number"},pointer:{pattern:/@\w[\w!"$%&'()*+,\-./:;<=>?[\\\]^`{|}~\x80-\xfe #]*@/,alias:"variable"}}}e.exports=t,t.displayName="gedcom",t.aliases=[]},6024(e){"use strict";function t(e){var t,n;n=/(?:\r?\n|\r)[ \t]*\|.+\|(?:(?!\|).)*/.source,(t=e).languages.gherkin={pystring:{pattern:/("""|''')[\s\S]+?\1/,alias:"string"},comment:{pattern:/(^[ \t]*)#.*/m,lookbehind:!0},tag:{pattern:/(^[ \t]*)@\S*/m,lookbehind:!0},feature:{pattern:/((?:^|\r?\n|\r)[ \t]*)(?:Ability|Ahoy matey!|Arwedd|Aspekt|Besigheid Behoefte|Business Need|Caracteristica|Característica|Egenskab|Egenskap|Eiginleiki|Feature|Fīča|Fitur|Fonctionnalité|Fonksyonalite|Funcionalidade|Funcionalitat|Functionalitate|Funcţionalitate|Funcționalitate|Functionaliteit|Fungsi|Funkcia|Funkcija|Funkcionalitāte|Funkcionalnost|Funkcja|Funksie|Funktionalität|Funktionalitéit|Funzionalità|Hwaet|Hwæt|Jellemző|Karakteristik|laH|Lastnost|Mak|Mogucnost|Mogućnost|Moznosti|Možnosti|OH HAI|Omadus|Ominaisuus|Osobina|Özellik|perbogh|poQbogh malja'|Potrzeba biznesowa|Požadavek|Požiadavka|Pretty much|Qap|Qu'meH 'ut|Savybė|Tính năng|Trajto|Vermoë|Vlastnosť|Właściwość|Značilnost|Δυνατότητα|Λειτουργία|Могућност|Мөмкинлек|Особина|Свойство|Үзенчәлеклелек|Функционал|Функционалност|Функция|Функціонал|תכונה|خاصية|خصوصیت|صلاحیت|کاروبار کی ضرورت|وِیژگی|रूप लेख|ਖਾਸੀਅਤ|ਨਕਸ਼ ਨੁਹਾਰ|ਮੁਹਾਂਦਰਾ|గుణము|ಹೆಚ್ಚಳ|ความต้องการทางธุรกิจ|ความสามารถ|โครงหลัก|기능|フィーチャ|功能|機能):(?:[^:\r\n]+(?:\r?\n|\r|$))*/,lookbehind:!0,inside:{important:{pattern:/(:)[^\r\n]+/,lookbehind:!0},keyword:/[^:\r\n]+:/}},scenario:{pattern:/(^[ \t]*)(?:Abstract Scenario|Abstrakt Scenario|Achtergrond|Aer|Ær|Agtergrond|All y'all|Antecedentes|Antecedents|Atburðarás|Atburðarásir|Awww, look mate|B4|Background|Baggrund|Bakgrund|Bakgrunn|Bakgrunnur|Beispiele|Beispiller|Bối cảnh|Cefndir|Cenario|Cenário|Cenario de Fundo|Cenário de Fundo|Cenarios|Cenários|Contesto|Context|Contexte|Contexto|Conto|Contoh|Contone|Dæmi|Dasar|Dead men tell no tales|Delineacao do Cenario|Delineação do Cenário|Dis is what went down|Dữ liệu|Dyagram senaryo|Dyagram Senaryo|Egzanp|Ejemplos|Eksempler|Ekzemploj|Enghreifftiau|Esbozo do escenario|Escenari|Escenario|Esempi|Esquema de l'escenari|Esquema del escenario|Esquema do Cenario|Esquema do Cenário|Examples|EXAMPLZ|Exempel|Exemple|Exemples|Exemplos|First off|Fono|Forgatókönyv|Forgatókönyv vázlat|Fundo|Geçmiş|ghantoH|Grundlage|Hannergrond|Háttér|Heave to|Istorik|Juhtumid|Keadaan|Khung kịch bản|Khung tình huống|Kịch bản|Koncept|Konsep skenario|Kontèks|Kontekst|Kontekstas|Konteksts|Kontext|Konturo de la scenaro|Latar Belakang|lut|lut chovnatlh|lutmey|Lýsing Atburðarásar|Lýsing Dæma|Menggariskan Senario|MISHUN|MISHUN SRSLY|mo'|Náčrt Scenára|Náčrt Scénáře|Náčrt Scenáru|Oris scenarija|Örnekler|Osnova|Osnova Scenára|Osnova scénáře|Osnutek|Ozadje|Paraugs|Pavyzdžiai|Példák|Piemēri|Plan du scénario|Plan du Scénario|Plan senaryo|Plan Senaryo|Plang vum Szenario|Pozadí|Pozadie|Pozadina|Príklady|Příklady|Primer|Primeri|Primjeri|Przykłady|Raamstsenaarium|Reckon it's like|Rerefons|Scenár|Scénář|Scenarie|Scenarij|Scenarijai|Scenarijaus šablonas|Scenariji|Scenārijs|Scenārijs pēc parauga|Scenarijus|Scenario|Scénario|Scenario Amlinellol|Scenario Outline|Scenario Template|Scenariomal|Scenariomall|Scenarios|Scenariu|Scenariusz|Scenaro|Schema dello scenario|Se ðe|Se the|Se þe|Senario|Senaryo|Senaryo deskripsyon|Senaryo Deskripsyon|Senaryo taslağı|Shiver me timbers|Situācija|Situai|Situasie|Situasie Uiteensetting|Skenario|Skenario konsep|Skica|Structura scenariu|Structură scenariu|Struktura scenarija|Stsenaarium|Swa|Swa hwaer swa|Swa hwær swa|Szablon scenariusza|Szenario|Szenariogrundriss|Tapaukset|Tapaus|Tapausaihio|Taust|Tausta|Template Keadaan|Template Senario|Template Situai|The thing of it is|Tình huống|Variantai|Voorbeelde|Voorbeelden|Wharrimean is|Yo-ho-ho|You'll wanna|Założenia|Παραδείγματα|Περιγραφή Σεναρίου|Σενάρια|Σενάριο|Υπόβαθρο|Кереш|Контекст|Концепт|Мисаллар|Мисоллар|Основа|Передумова|Позадина|Предистория|Предыстория|Приклади|Пример|Примери|Примеры|Рамка на сценарий|Скица|Структура сценарија|Структура сценария|Структура сценарію|Сценарий|Сценарий структураси|Сценарийның төзелеше|Сценарији|Сценарио|Сценарій|Тарих|Үрнәкләр|דוגמאות|רקע|תבנית תרחיש|תרחיש|الخلفية|الگوی سناریو|امثلة|پس منظر|زمینه|سناریو|سيناريو|سيناريو مخطط|مثالیں|منظر نامے کا خاکہ|منظرنامہ|نمونه ها|उदाहरण|परिदृश्य|परिदृश्य रूपरेखा|पृष्ठभूमि|ਉਦਾਹਰਨਾਂ|ਪਟਕਥਾ|ਪਟਕਥਾ ਢਾਂਚਾ|ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ|ਪਿਛੋਕੜ|ఉదాహరణలు|కథనం|నేపథ్యం|సన్నివేశం|ಉದಾಹರಣೆಗಳು|ಕಥಾಸಾರಾಂಶ|ವಿವರಣೆ|ಹಿನ್ನೆಲೆ|โครงสร้างของเหตุการณ์|ชุดของตัวอย่าง|ชุดของเหตุการณ์|แนวคิด|สรุปเหตุการณ์|เหตุการณ์|배경|시나리오|시나리오 개요|예|サンプル|シナリオ|シナリオアウトライン|シナリオテンプレ|シナリオテンプレート|テンプレ|例|例子|剧本|剧本大纲|劇本|劇本大綱|场景|场景大纲|場景|場景大綱|背景):[^:\r\n]*/m,lookbehind:!0,inside:{important:{pattern:/(:)[^\r\n]*/,lookbehind:!0},keyword:/[^:\r\n]+:/}},"table-body":{pattern:RegExp("("+n+")(?:"+n+")+"),lookbehind:!0,inside:{outline:{pattern:/<[^>]+>/,alias:"variable"},td:{pattern:/\s*[^\s|][^|]*/,alias:"string"},punctuation:/\|/}},"table-head":{pattern:RegExp(n),inside:{th:{pattern:/\s*[^\s|][^|]*/,alias:"variable"},punctuation:/\|/}},atrule:{pattern:/(^[ \t]+)(?:'ach|'a|'ej|7|a|A také|A taktiež|A tiež|A zároveň|Aber|Ac|Adott|Akkor|Ak|Aleshores|Ale|Ali|Allora|Alors|Als|Ama|Amennyiben|Amikor|Ampak|an|AN|Ananging|And y'all|And|Angenommen|Anrhegedig a|An|Apabila|Atès|Atesa|Atunci|Avast!|Aye|A|awer|Bagi|Banjur|Bet|Biết|Blimey!|Buh|But at the end of the day I reckon|But y'all|But|BUT|Cal|Când|Cando|Cand|Ce|Cuando|Če|Ða ðe|Ða|Dadas|Dada|Dados|Dado|DaH ghu' bejlu'|dann|Dann|Dano|Dan|Dar|Dat fiind|Data|Date fiind|Date|Dati fiind|Dati|Daţi fiind|Dați fiind|Dato|DEN|Den youse gotta|Dengan|De|Diberi|Diyelim ki|Donada|Donat|Donitaĵo|Do|Dun|Duota|Ðurh|Eeldades|Ef|Eğer ki|Entao|Então|Entón|Entonces|En|Epi|E|És|Etant donnée|Etant donné|Et|Étant données|Étant donnée|Étant donné|Etant données|Etant donnés|Étant donnés|Fakat|Gangway!|Gdy|Gegeben seien|Gegeben sei|Gegeven|Gegewe|ghu' noblu'|Gitt|Given y'all|Given|Givet|Givun|Ha|Cho|I CAN HAZ|In|Ir|It's just unbelievable|I|Ja|Jeśli|Jeżeli|Kadar|Kada|Kad|Kai|Kaj|Když|Keď|Kemudian|Ketika|Khi|Kiedy|Ko|Kuid|Kui|Kun|Lan|latlh|Le sa a|Let go and haul|Le|Lè sa a|Lè|Logo|Lorsqu'<|Lorsque|mä|Maar|Mais|Mając|Majd|Maka|Manawa|Mas|Ma|Menawa|Men|Mutta|Nalikaning|Nalika|Nanging|Når|När|Nato|Nhưng|Niin|Njuk|O zaman|Og|Och|Oletetaan|Onda|Ond|Oraz|Pak|Pero|Però|Podano|Pokiaľ|Pokud|Potem|Potom|Privzeto|Pryd|qaSDI'|Quando|Quand|Quan|Så|Sed|Se|Siis|Sipoze ke|Sipoze Ke|Sipoze|Si|Şi|Și|Soit|Stel|Tada|Tad|Takrat|Tak|Tapi|Ter|Tetapi|Tha the|Tha|Then y'all|Then|Thì|Thurh|Toda|Too right|ugeholl|Und|Un|Và|vaj|Vendar|Ve|wann|Wanneer|WEN|Wenn|When y'all|When|Wtedy|Wun|Y'know|Yeah nah|Yna|Youse know like when|Youse know when youse got|Y|Za predpokladu|Za předpokladu|Zadani|Zadano|Zadan|Zadate|Zadato|Zakładając|Zaradi|Zatati|Þa þe|Þa|Þá|Þegar|Þurh|Αλλά|Δεδομένου|Και|Όταν|Τότε|А також|Агар|Але|Али|Аммо|А|Әгәр|Әйтик|Әмма|Бирок|Ва|Вә|Дадено|Дано|Допустим|Если|Задате|Задати|Задато|И|І|К тому же|Када|Кад|Когато|Когда|Коли|Ләкин|Лекин|Нәтиҗәдә|Нехай|Но|Онда|Припустимо, що|Припустимо|Пусть|Также|Та|Тогда|Тоді|То|Унда|Һәм|Якщо|אבל|אזי|אז|בהינתן|וגם|כאשר|آنگاه|اذاً|اگر|اما|اور|با فرض|بالفرض|بفرض|پھر|تب|ثم|جب|عندما|فرض کیا|لكن|لیکن|متى|هنگامی|و|अगर|और|कदा|किन्तु|चूंकि|जब|तथा|तदा|तब|परन्तु|पर|यदि|ਅਤੇ|ਜਦੋਂ|ਜਿਵੇਂ ਕਿ|ਜੇਕਰ|ਤਦ|ਪਰ|అప్పుడు|ఈ పరిస్థితిలో|కాని|చెప్పబడినది|మరియు|ಆದರೆ|ನಂತರ|ನೀಡಿದ|ಮತ್ತು|ಸ್ಥಿತಿಯನ್ನು|กำหนดให้|ดังนั้น|แต่|เมื่อ|และ|그러면<|그리고<|단<|만약<|만일<|먼저<|조건<|하지만<|かつ<|しかし<|ただし<|ならば<|もし<|並且<|但し<|但是<|假如<|假定<|假設<|假设<|前提<|同时<|同時<|并且<|当<|當<|而且<|那么<|那麼<)(?=[ \t])/m,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\\r\n])*"|'(?:\\.|[^'\\\r\n])*'/,inside:{outline:{pattern:/<[^>]+>/,alias:"variable"}}},outline:{pattern:/<[^>]+>/,alias:"variable"}}}e.exports=t,t.displayName="gherkin",t.aliases=[]},13600(e){"use strict";function t(e){e.languages.git={comment:/^#.*/m,deleted:/^[-–].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/m,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/m}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m}}e.exports=t,t.displayName="git",t.aliases=[]},3322(e,t,n){"use strict";var r=n(65806);function i(e){e.register(r),e.languages.glsl=e.languages.extend("c",{keyword:/\b(?:attribute|const|uniform|varying|buffer|shared|coherent|volatile|restrict|readonly|writeonly|atomic_uint|layout|centroid|flat|smooth|noperspective|patch|sample|break|continue|do|for|while|switch|case|default|if|else|subroutine|in|out|inout|float|double|int|void|bool|true|false|invariant|precise|discard|return|d?mat[234](?:x[234])?|[ibdu]?vec[234]|uint|lowp|mediump|highp|precision|[iu]?sampler[123]D|[iu]?samplerCube|sampler[12]DShadow|samplerCubeShadow|[iu]?sampler[12]DArray|sampler[12]DArrayShadow|[iu]?sampler2DRect|sampler2DRectShadow|[iu]?samplerBuffer|[iu]?sampler2DMS(?:Array)?|[iu]?samplerCubeArray|samplerCubeArrayShadow|[iu]?image[123]D|[iu]?image2DRect|[iu]?imageCube|[iu]?imageBuffer|[iu]?image[12]DArray|[iu]?imageCubeArray|[iu]?image2DMS(?:Array)?|struct|common|partition|active|asm|class|union|enum|typedef|template|this|resource|goto|inline|noinline|public|static|extern|external|interface|long|short|half|fixed|unsigned|superp|input|output|hvec[234]|fvec[234]|sampler3DRect|filter|sizeof|cast|namespace|using)\b/})}e.exports=i,i.displayName="glsl",i.aliases=[]},53877(e){"use strict";function t(e){e.languages.gamemakerlanguage=e.languages.gml=e.languages.extend("clike",{keyword:/\b(?:if|else|switch|case|default|break|for|repeat|while|do|until|continue|exit|return|globalvar|var|enum)\b/,number:/(?:\b0x[\da-f]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ulf]{0,4}/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not|with|at|xor)\b/,constant:/\b(?:self|other|all|noone|global|local|undefined|pointer_(?:invalid|null)|action_(?:stop|restart|continue|reverse)|pi|GM_build_date|GM_version|timezone_(?:local|utc)|gamespeed_(?:fps|microseconds)|ev_(?:create|destroy|step|alarm|keyboard|mouse|collision|other|draw|draw_(?:begin|end|pre|post)|keypress|keyrelease|trigger|(?:left|right|middle|no)_button|(?:left|right|middle)_press|(?:left|right|middle)_release|mouse_(?:enter|leave|wheel_up|wheel_down)|global_(?:left|right|middle)_button|global_(?:left|right|middle)_press|global_(?:left|right|middle)_release|joystick(?:1|2)_(?:left|right|up|down|button1|button2|button3|button4|button5|button6|button7|button8)|outside|boundary|game_start|game_end|room_start|room_end|no_more_lives|animation_end|end_of_path|no_more_health|user\d|step_(?:normal|begin|end)|gui|gui_begin|gui_end)|vk_(?:nokey|anykey|enter|return|shift|control|alt|escape|space|backspace|tab|pause|printscreen|left|right|up|down|home|end|delete|insert|pageup|pagedown|f\d|numpad\d|divide|multiply|subtract|add|decimal|lshift|lcontrol|lalt|rshift|rcontrol|ralt)|mb_(?:any|none|left|right|middle)|c_(?:aqua|black|blue|dkgray|fuchsia|gray|green|lime|ltgray|maroon|navy|olive|purple|red|silver|teal|white|yellow|orange)|fa_(?:left|center|right|top|middle|bottom|readonly|hidden|sysfile|volumeid|directory|archive)|pr_(?:pointlist|linelist|linestrip|trianglelist|trianglestrip|trianglefan)|bm_(?:complex|normal|add|max|subtract|zero|one|src_colour|inv_src_colour|src_color|inv_src_color|src_alpha|inv_src_alpha|dest_alpha|inv_dest_alpha|dest_colour|inv_dest_colour|dest_color|inv_dest_color|src_alpha_sat)|audio_(?:falloff_(?:none|inverse_distance|inverse_distance_clamped|linear_distance|linear_distance_clamped|exponent_distance|exponent_distance_clamped)|old_system|new_system|mono|stereo|3d)|cr_(?:default|none|arrow|cross|beam|size_nesw|size_ns|size_nwse|size_we|uparrow|hourglass|drag|appstart|handpoint|size_all)|asset_(?:object|unknown|sprite|sound|room|path|script|font|timeline|tiles|shader)|ds_type_(?:map|list|stack|queue|grid|priority)|ef_(?:explosion|ring|ellipse|firework|smoke|smokeup|star|spark|flare|cloud|rain|snow)|pt_shape_(?:pixel|disk|square|line|star|circle|ring|sphere|flare|spark|explosion|cloud|smoke|snow)|ps_(?:distr|shape)_(?:linear|gaussian|invgaussian|rectangle|ellipse|diamond|line)|ty_(?:real|string)|dll_(?:cdel|cdecl|stdcall)|matrix_(?:view|projection|world)|os_(?:win32|windows|macosx|ios|android|linux|unknown|winphone|win8native|psvita|ps4|xboxone|ps3|uwp)|browser_(?:not_a_browser|unknown|ie|firefox|chrome|safari|safari_mobile|opera|tizen|windows_store|ie_mobile)|device_ios_(?:unknown|iphone|iphone_retina|ipad|ipad_retina|iphone5|iphone6|iphone6plus)|device_(?:emulator|tablet)|display_(?:landscape|landscape_flipped|portrait|portrait_flipped)|of_challenge_(?:win|lose|tie)|leaderboard_type_(?:number|time_mins_secs)|cmpfunc_(?:never|less|equal|lessequal|greater|notequal|greaterequal|always)|cull_(?:noculling|clockwise|counterclockwise)|lighttype_(?:dir|point)|iap_(?:ev_storeload|ev_product|ev_purchase|ev_consume|ev_restore|storeload_ok|storeload_failed|status_uninitialised|status_unavailable|status_loading|status_available|status_processing|status_restoring|failed|unavailable|available|purchased|canceled|refunded)|fb_login_(?:default|fallback_to_webview|no_fallback_to_webview|forcing_webview|use_system_account|forcing_safari)|phy_joint_(?:anchor_1_x|anchor_1_y|anchor_2_x|anchor_2_y|reaction_force_x|reaction_force_y|reaction_torque|motor_speed|angle|motor_torque|max_motor_torque|translation|speed|motor_force|max_motor_force|length_1|length_2|damping_ratio|frequency|lower_angle_limit|upper_angle_limit|angle_limits|max_length|max_torque|max_force)|phy_debug_render_(?:aabb|collision_pairs|coms|core_shapes|joints|obb|shapes)|phy_particle_flag_(?:water|zombie|wall|spring|elastic|viscous|powder|tensile|colourmixing|colormixing)|phy_particle_group_flag_(?:solid|rigid)|phy_particle_data_flag_(?:typeflags|position|velocity|colour|color|category)|achievement_(?:our_info|friends_info|leaderboard_info|info|filter_(?:all_players|friends_only|favorites_only)|type_challenge|type_score_challenge|pic_loaded|show_(?:ui|profile|leaderboard|achievement|bank|friend_picker|purchase_prompt))|network_(?:socket_(?:tcp|udp|bluetooth)|type_(?:connect|disconnect|data|non_blocking_connect)|config_(?:connect_timeout|use_non_blocking_socket|enable_reliable_udp|disable_reliable_udp))|buffer_(?:fixed|grow|wrap|fast|vbuffer|network|u8|s8|u16|s16|u32|s32|u64|f16|f32|f64|bool|text|string|seek_start|seek_relative|seek_end|generalerror|outofspace|outofbounds|invalidtype)|gp_(?:face\d|shoulderl|shoulderr|shoulderlb|shoulderrb|select|start|stickl|stickr|padu|padd|padl|padr|axislh|axislv|axisrh|axisrv)|ov_(?:friends|community|players|settings|gamegroup|achievements)|lb_sort_(?:none|ascending|descending)|lb_disp_(?:none|numeric|time_sec|time_ms)|ugc_(?:result_success|filetype_(?:community|microtrans)|visibility_(?:public|friends_only|private)|query_RankedBy(?:Vote|PublicationDate|Trend|NumTimesReported|TotalVotesAsc|VotesUp|TextSearch)|query_(?:AcceptedForGameRankedByAcceptanceDate|FavoritedByFriendsRankedByPublicationDate|CreatedByFriendsRankedByPublicationDate|NotYetRated)|sortorder_CreationOrder(?:Desc|Asc)|sortorder_(?:TitleAsc|LastUpdatedDesc|SubscriptionDateDesc|VoteScoreDesc|ForModeration)|list_(?:Published|VotedOn|VotedUp|VotedDown|WillVoteLater|Favorited|Subscribed|UsedOrPlayed|Followed)|match_(?:Items|Items_Mtx|Items_ReadyToUse|Collections|Artwork|Videos|Screenshots|AllGuides|WebGuides|IntegratedGuides|UsableInGame|ControllerBindings))|vertex_usage_(?:position|colour|color|normal|texcoord|textcoord|blendweight|blendindices|psize|tangent|binormal|fog|depth|sample)|vertex_type_(?:float\d|colour|color|ubyte4)|layerelementtype_(?:undefined|background|instance|oldtilemap|sprite|tilemap|particlesystem|tile)|tile_(?:rotate|flip|mirror|index_mask)|input_type|se_(?:chorus|compressor|echo|equalizer|flanger|gargle|none|reverb)|text_type|(?:obj|scr|spr|rm)\w+)\b/,variable:/\b(?:x|y|(?:x|y)(?:previous|start)|(?:h|v)speed|direction|speed|friction|gravity|gravity_direction|path_(?:index|position|positionprevious|speed|scale|orientation|endaction)|object_index|id|solid|persistent|mask_index|instance_(?:count|id)|alarm|timeline_(?:index|position|speed|running|loop)|visible|sprite_(?:index|width|height|xoffset|yoffset)|image_(?:number|index|speed|depth|xscale|yscale|angle|alpha|blend)|bbox_(?:left|right|top|bottom)|layer|phy_(?:rotation|(?:position|linear_velocity|speed|com|collision|col_normal)_(?:x|y)|angular_(?:velocity|damping)|position_(?:x|y)previous|speed|linear_damping|bullet|fixed_rotation|active|mass|inertia|dynamic|kinematic|sleeping|collision_points)|working_directory|webgl_enabled|view_(?:(?:y|x|w|h)view|(?:y|x|w|h)port|(?:v|h)(?:speed|border)|visible|surface_id|object|enabled|current|angle)|undefined|transition_(?:steps|kind|color)|temp_directory|show_(?:score|lives|health)|secure_mode|score|room_(?:width|speed|persistent|last|height|first|caption)|room|pointer_(?:null|invalid)|os_(?:version|type|device|browser)|mouse_(?:y|x|lastbutton|button)|lives|keyboard_(?:string|lastkey|lastchar|key)|iap_data|health|gamemaker_(?:version|registered|pro)|game_(?:save|project|display)_(?:id|name)|fps_real|fps|event_(?:type|object|number|action)|error_(?:occurred|last)|display_aa|delta_time|debug_mode|cursor_sprite|current_(?:year|weekday|time|second|month|minute|hour|day)|caption_(?:score|lives|health)|browser_(?:width|height)|background_(?:yscale|y|xscale|x|width|vtiled|vspeed|visible|showcolour|showcolor|index|htiled|hspeed|height|foreground|colour|color|blend|alpha)|async_load|application_surface|argument(?:_relitive|_count|\d)|argument|global|local|self|other)\b/})}e.exports=t,t.displayName="gml",t.aliases=[]},51519(e){"use strict";function t(e){e.languages.go=e.languages.extend("clike",{string:{pattern:/(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|iota|nil|true|false)\b/,number:/(?:\b0x[a-f\d]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[-+]?\d+)?)i?/i,operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:bool|byte|complex(?:64|128)|error|float(?:32|64)|rune|string|u?int(?:8|16|32|64)?|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(?:ln)?|real|recover)\b/}),delete e.languages.go["class-name"]}e.exports=t,t.displayName="go",t.aliases=[]},94055(e){"use strict";function t(e){e.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:e.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:true|false)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/[A-Z]\w*Input(?=!?.*$)/m,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},e.hooks.add("after-tokenize",function(e){if("graphql"===e.language){for(var t=e.tokens.filter(function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type}),n=0;n0)){var s=d(/^\{$/,/^\}$/);if(-1===s)continue;for(var u=n;u=0&&h(c,"variable-input")}}}}}function l(e){return t[n+e]}function f(e,t){t=t||0;for(var n=0;n]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,lookbehind:!0},punctuation:/\.+|[{}[\];(),:$]/}),e.languages.insertBefore("groovy","string",{shebang:{pattern:/#!.+/,alias:"comment"}}),e.languages.insertBefore("groovy","punctuation",{"spock-block":/\b(?:setup|given|when|then|and|cleanup|expect|where):/}),e.languages.insertBefore("groovy","function",{annotation:{pattern:/(^|[^.])@\w+/,lookbehind:!0,alias:"punctuation"}}),e.hooks.add("wrap",function(t){if("groovy"===t.language&&"string"===t.type){var n=t.content.value[0];if("'"!=n){var r=/([^\\])(?:\$(?:\{.*?\}|[\w.]+))/;"$"===n&&(r=/([^\$])(?:\$(?:\{.*?\}|[\w.]+))/),t.content.value=t.content.value.replace(/</g,"<").replace(/&/g,"&"),t.content=e.highlight(t.content.value,{expression:{pattern:r,lookbehind:!0,inside:e.languages.groovy}}),t.classes.push("/"===n?"regex":"gstring")}}})}e.exports=t,t.displayName="groovy",t.aliases=[]},29536(e,t,n){"use strict";var r=n(56939);function i(e){e.register(r),function(e){e.languages.haml={"multiline-comment":{pattern:/((?:^|\r?\n|\r)([\t ]*))(?:\/|-#).*(?:(?:\r?\n|\r)\2[\t ].+)*/,lookbehind:!0,alias:"comment"},"multiline-code":[{pattern:/((?:^|\r?\n|\r)([\t ]*)(?:[~-]|[&!]?=)).*,[\t ]*(?:(?:\r?\n|\r)\2[\t ].*,[\t ]*)*(?:(?:\r?\n|\r)\2[\t ].+)/,lookbehind:!0,inside:e.languages.ruby},{pattern:/((?:^|\r?\n|\r)([\t ]*)(?:[~-]|[&!]?=)).*\|[\t ]*(?:(?:\r?\n|\r)\2[\t ].*\|[\t ]*)*/,lookbehind:!0,inside:e.languages.ruby}],filter:{pattern:/((?:^|\r?\n|\r)([\t ]*)):[\w-]+(?:(?:\r?\n|\r)(?:\2[\t ].+|\s*?(?=\r?\n|\r)))+/,lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"}}},markup:{pattern:/((?:^|\r?\n|\r)[\t ]*)<.+/,lookbehind:!0,inside:e.languages.markup},doctype:{pattern:/((?:^|\r?\n|\r)[\t ]*)!!!(?: .+)?/,lookbehind:!0},tag:{pattern:/((?:^|\r?\n|\r)[\t ]*)[%.#][\w\-#.]*[\w\-](?:\([^)]+\)|\{(?:\{[^}]+\}|[^{}])+\}|\[[^\]]+\])*[\/<>]*/,lookbehind:!0,inside:{attributes:[{pattern:/(^|[^#])\{(?:\{[^}]+\}|[^{}])+\}/,lookbehind:!0,inside:e.languages.ruby},{pattern:/\([^)]+\)/,inside:{"attr-value":{pattern:/(=\s*)(?:"(?:\\.|[^\\"\r\n])*"|[^)\s]+)/,lookbehind:!0},"attr-name":/[\w:-]+(?=\s*!?=|\s*[,)])/,punctuation:/[=(),]/}},{pattern:/\[[^\]]+\]/,inside:e.languages.ruby}],punctuation:/[<>]/}},code:{pattern:/((?:^|\r?\n|\r)[\t ]*(?:[~-]|[&!]?=)).+/,lookbehind:!0,inside:e.languages.ruby},interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"},rest:e.languages.ruby}},punctuation:{pattern:/((?:^|\r?\n|\r)[\t ]*)[~=\-&!]+/,lookbehind:!0}};for(var t="((?:^|\\r?\\n|\\r)([\\t ]*)):{{filter_name}}(?:(?:\\r?\\n|\\r)(?:\\2[\\t ].+|\\s*?(?=\\r?\\n|\\r)))+",n=["css",{filter:"coffee",language:"coffeescript"},"erb","javascript","less","markdown","ruby","scss","textile"],r={},i=0,a=n.length;i@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},t.hooks.add("before-tokenize",function(e){var n=/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g;t.languages["markup-templating"].buildPlaceholders(e,"handlebars",n)}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"handlebars")}),t.languages.hbs=t.languages.handlebars}e.exports=i,i.displayName="handlebars",i.aliases=["hbs"]},58090(e){"use strict";function t(e){e.languages.haskell={comment:{pattern:/(^|[^-!#$%*+=?&@|~.:<>^\\\/])(?:--(?:(?=.)[^-!#$%*+=?&@|~.:<>^\\\/].*|$)|\{-[\s\S]*?-\})/m,lookbehind:!0},char:{pattern:/'(?:[^\\']|\\(?:[abfnrtv\\"'&]|\^[A-Z@[\]^_]|NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC1|DC2|DC3|DC4|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL|\d+|o[0-7]+|x[0-9a-fA-F]+))'/,alias:"string"},string:{pattern:/"(?:[^\\"]|\\(?:\S|\s+\\))*"/,greedy:!0},keyword:/\b(?:case|class|data|deriving|do|else|if|in|infixl|infixr|instance|let|module|newtype|of|primitive|then|type|where)\b/,"import-statement":{pattern:/(^[\t ]*)import\s+(?:qualified\s+)?(?:[A-Z][\w']*)(?:\.[A-Z][\w']*)*(?:\s+as\s+(?:[A-Z][\w']*)(?:\.[A-Z][\w']*)*)?(?:\s+hiding\b)?/m,lookbehind:!0,inside:{keyword:/\b(?:import|qualified|as|hiding)\b/}},builtin:/\b(?:abs|acos|acosh|all|and|any|appendFile|approxRational|asTypeOf|asin|asinh|atan|atan2|atanh|basicIORun|break|catch|ceiling|chr|compare|concat|concatMap|const|cos|cosh|curry|cycle|decodeFloat|denominator|digitToInt|div|divMod|drop|dropWhile|either|elem|encodeFloat|enumFrom|enumFromThen|enumFromThenTo|enumFromTo|error|even|exp|exponent|fail|filter|flip|floatDigits|floatRadix|floatRange|floor|fmap|foldl|foldl1|foldr|foldr1|fromDouble|fromEnum|fromInt|fromInteger|fromIntegral|fromRational|fst|gcd|getChar|getContents|getLine|group|head|id|inRange|index|init|intToDigit|interact|ioError|isAlpha|isAlphaNum|isAscii|isControl|isDenormalized|isDigit|isHexDigit|isIEEE|isInfinite|isLower|isNaN|isNegativeZero|isOctDigit|isPrint|isSpace|isUpper|iterate|last|lcm|length|lex|lexDigits|lexLitChar|lines|log|logBase|lookup|map|mapM|mapM_|max|maxBound|maximum|maybe|min|minBound|minimum|mod|negate|not|notElem|null|numerator|odd|or|ord|otherwise|pack|pi|pred|primExitWith|print|product|properFraction|putChar|putStr|putStrLn|quot|quotRem|range|rangeSize|read|readDec|readFile|readFloat|readHex|readIO|readInt|readList|readLitChar|readLn|readOct|readParen|readSigned|reads|readsPrec|realToFrac|recip|rem|repeat|replicate|return|reverse|round|scaleFloat|scanl|scanl1|scanr|scanr1|seq|sequence|sequence_|show|showChar|showInt|showList|showLitChar|showParen|showSigned|showString|shows|showsPrec|significand|signum|sin|sinh|snd|sort|span|splitAt|sqrt|subtract|succ|sum|tail|take|takeWhile|tan|tanh|threadToIOResult|toEnum|toInt|toInteger|toLower|toRational|toUpper|truncate|uncurry|undefined|unlines|until|unwords|unzip|unzip3|userError|words|writeFile|zip|zip3|zipWith|zipWith3)\b/,number:/\b(?:\d+(?:\.\d+)?(?:e[+-]?\d+)?|0o[0-7]+|0x[0-9a-f]+)\b/i,operator:/\s\.\s|[-!#$%*+=?&@|~:<>^\\\/]*\.[-!#$%*+=?&@|~.:<>^\\\/]+|[-!#$%*+=?&@|~.:<>^\\\/]+\.[-!#$%*+=?&@|~:<>^\\\/]*|[-!#$%*+=?&@|~:<>^\\\/]+|`(?:[A-Z][\w']*\.)*[_a-z][\w']*`/,hvariable:/\b(?:[A-Z][\w']*\.)*[_a-z][\w']*\b/,constant:/\b(?:[A-Z][\w']*\.)*[A-Z][\w']*\b/,punctuation:/[{}[\];(),.:]/},e.languages.hs=e.languages.haskell}e.exports=t,t.displayName="haskell",t.aliases=["hs"]},95121(e){"use strict";function t(e){e.languages.haxe=e.languages.extend("clike",{string:{pattern:/(["'])(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0,inside:{interpolation:{pattern:/(^|[^\\])\$(?:\w+|\{[^}]+\})/,lookbehind:!0,inside:{interpolation:{pattern:/^\$\w*/,alias:"variable"}}}}},keyword:/\bthis\b|\b(?:abstract|as|break|case|cast|catch|class|continue|default|do|dynamic|else|enum|extends|extern|from|for|function|if|implements|import|in|inline|interface|macro|new|null|override|public|private|return|static|super|switch|throw|to|try|typedef|using|var|while)(?!\.)\b/,operator:/\.{3}|\+\+?|-[->]?|[=!]=?|&&?|\|\|?|<[<=]?|>[>=]?|[*\/%~^]/}),e.languages.insertBefore("haxe","class-name",{regex:{pattern:/~\/(?:[^\/\\\r\n]|\\.)+\/[igmsu]*/,greedy:!0}}),e.languages.insertBefore("haxe","keyword",{preprocessor:{pattern:/#\w+/,alias:"builtin"},metadata:{pattern:/@:?\w+/,alias:"symbol"},reification:{pattern:/\$(?:\w+|(?=\{))/,alias:"variable"}}),e.languages.haxe.string.inside.interpolation.inside.rest=e.languages.haxe,delete e.languages.haxe["class-name"]}e.exports=t,t.displayName="haxe",t.aliases=[]},59904(e){"use strict";function t(e){e.languages.hcl={comment:/(?:\/\/|#).*|\/\*[\s\S]*?(?:\*\/|$)/,heredoc:{pattern:/<<-?(\w+\b)[\s\S]*?^[ \t]*\1/m,greedy:!0,alias:"string"},keyword:[{pattern:/(?:resource|data)\s+(?:"(?:\\[\s\S]|[^\\"])*")(?=\s+"[\w-]+"\s+\{)/i,inside:{type:{pattern:/(resource|data|\s+)(?:"(?:\\[\s\S]|[^\\"])*")/i,lookbehind:!0,alias:"variable"}}},{pattern:/(?:provider|provisioner|variable|output|module|backend)\s+(?:[\w-]+|"(?:\\[\s\S]|[^\\"])*")\s+(?=\{)/i,inside:{type:{pattern:/(provider|provisioner|variable|output|module|backend)\s+(?:[\w-]+|"(?:\\[\s\S]|[^\\"])*")\s+/i,lookbehind:!0,alias:"variable"}}},/[\w-]+(?=\s+\{)/],property:[/[-\w\.]+(?=\s*=(?!=))/,/"(?:\\[\s\S]|[^\\"])+"(?=\s*[:=])/],string:{pattern:/"(?:[^\\$"]|\\[\s\S]|\$(?:(?=")|\$+(?!\$)|[^"${])|\$\{(?:[^{}"]|"(?:[^\\"]|\\[\s\S])*")*\})*"/,greedy:!0,inside:{interpolation:{pattern:/(^|[^$])\$\{(?:[^{}"]|"(?:[^\\"]|\\[\s\S])*")*\}/,lookbehind:!0,inside:{type:{pattern:/(\b(?:terraform|var|self|count|module|path|data|local)\b\.)[\w\*]+/i,lookbehind:!0,alias:"variable"},keyword:/\b(?:terraform|var|self|count|module|path|data|local)\b/i,function:/\w+(?=\()/,string:{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0},number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i,punctuation:/[!\$#%&'()*+,.\/;<=>@\[\\\]^`{|}~?:]/}}}},number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i,boolean:/\b(?:true|false)\b/i,punctuation:/[=\[\]{}]/}}e.exports=t,t.displayName="hcl",t.aliases=[]},9436(e,t,n){"use strict";var r=n(65806);function i(e){e.register(r),e.languages.hlsl=e.languages.extend("c",{"class-name":[e.languages.c["class-name"],/\b(?:AppendStructuredBuffer|BlendState|Buffer|ByteAddressBuffer|CompileShader|ComputeShader|ConsumeStructuredBuffer|DepthStencilState|DepthStencilView|DomainShader|GeometryShader|Hullshader|InputPatch|LineStream|OutputPatch|PixelShader|PointStream|RasterizerState|RenderTargetView|RWBuffer|RWByteAddressBuffer|RWStructuredBuffer|RWTexture(?:1D|1DArray|2D|2DArray|3D)|SamplerComparisonState|SamplerState|StructuredBuffer|Texture(?:1D|1DArray|2D|2DArray|2DMS|2DMSArray|3D|Cube|CubeArray)|TriangleStream|VertexShader)\b/],keyword:[/\b(?:asm|asm_fragment|auto|break|case|catch|cbuffer|centroid|char|class|column_major|compile|compile_fragment|const|const_cast|continue|default|delete|discard|do|dynamic_cast|else|enum|explicit|export|extern|for|friend|fxgroup|goto|groupshared|if|in|inline|inout|interface|line|lineadj|linear|long|matrix|mutable|namespace|new|nointerpolation|noperspective|operator|out|packoffset|pass|pixelfragment|point|precise|private|protected|public|register|reinterpret_cast|return|row_major|sample|sampler|shared|short|signed|sizeof|snorm|stateblock|stateblock_state|static|static_cast|string|struct|switch|tbuffer|technique|technique10|technique11|template|texture|this|throw|triangle|triangleadj|try|typedef|typename|uniform|union|unorm|unsigned|using|vector|vertexfragment|virtual|void|volatile|while)\b/,/\b(?:bool|double|dword|float|half|int|min(?:10float|12int|16(?:float|int|uint))|uint)(?:[1-4](?:x[1-4])?)?\b/],number:/(?:(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[eE][+-]?\d+)?|\b0x[\da-fA-F]+)[fFhHlLuU]?\b/,boolean:/\b(?:false|true)\b/})}e.exports=i,i.displayName="hlsl",i.aliases=[]},76942(e){"use strict";function t(e){e.languages.hpkp={directive:{pattern:/\b(?:(?:includeSubDomains|preload|strict)(?: |;)|pin-sha256="[a-zA-Z\d+=/]+"|(?:max-age|report-uri)=|report-to )/,alias:"keyword"},safe:{pattern:/\b\d{7,}\b/,alias:"selector"},unsafe:{pattern:/\b\d{1,6}\b/,alias:"function"}}}e.exports=t,t.displayName="hpkp",t.aliases=[]},60561(e){"use strict";function t(e){e.languages.hsts={directive:{pattern:/\b(?:max-age=|includeSubDomains|preload)/,alias:"keyword"},safe:{pattern:/\b\d{8,}\b/,alias:"selector"},unsafe:{pattern:/\b\d{1,7}\b/,alias:"function"}}}e.exports=t,t.displayName="hsts",t.aliases=[]},49660(e){"use strict";function t(e){!function(e){e.languages.http={"request-line":{pattern:/^(?:GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH|PRI|SEARCH)\s(?:https?:\/\/|\/)\S*\sHTTP\/[0-9.]+/m,inside:{method:{pattern:/^[A-Z]+\b/,alias:"property"},"request-target":{pattern:/^(\s)(?:https?:\/\/|\/)\S*(?=\s)/,lookbehind:!0,alias:"url",inside:e.languages.uri},"http-version":{pattern:/^(\s)HTTP\/[0-9.]+/,lookbehind:!0,alias:"property"}}},"response-status":{pattern:/^HTTP\/[0-9.]+ \d+ .+/m,inside:{"http-version":{pattern:/^HTTP\/[0-9.]+/,alias:"property"},"status-code":{pattern:/^(\s)\d+(?=\s)/,lookbehind:!0,alias:"number"},"reason-phrase":{pattern:/^(\s).+/,lookbehind:!0,alias:"string"}}},"header-name":{pattern:/^[\w-]+:(?=.)/m,alias:"keyword"}};var t,n=e.languages,r={"application/javascript":n.javascript,"application/json":n.json||n.javascript,"application/xml":n.xml,"text/xml":n.xml,"text/html":n.html,"text/css":n.css},i={"application/json":!0,"application/xml":!0};function a(e){var t="\\w+/(?:[\\w.-]+\\+)+"+e.replace(/^[a-z]+\//,"")+"(?![+\\w.-])";return"(?:"+e+"|"+t+")"}for(var o in r)if(r[o]){t=t||{};var s=i[o]?a(o):o;t[o.replace(/\//g,"-")]={pattern:RegExp("(content-type:\\s*"+s+"(?:(?:\\r\\n?|\\n).+)*)(?:\\r?\\n|\\r){2}[\\s\\S]*","i"),lookbehind:!0,inside:r[o]}}t&&e.languages.insertBefore("http","header-name",t)}(e)}e.exports=t,t.displayName="http",t.aliases=[]},30615(e){"use strict";function t(e){e.languages.ichigojam={comment:/(?:\B'|REM)(?:[^\n\r]*)/i,string:{pattern:/"(?:""|[!#$%&'()*,\/:;<=>?^\w +\-.])*"/i,greedy:!0},number:/\B#[0-9A-F]+|\B`[01]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?/i,keyword:/\b(?:BEEP|BPS|CASE|CLEAR|CLK|CLO|CLP|CLS|CLT|CLV|CONT|COPY|ELSE|END|FILE|FILES|FOR|GOSUB|GSB|GOTO|IF|INPUT|KBD|LED|LET|LIST|LOAD|LOCATE|LRUN|NEW|NEXT|OUT|RIGHT|PLAY|POKE|PRINT|PWM|REM|RENUM|RESET|RETURN|RTN|RUN|SAVE|SCROLL|SLEEP|SRND|STEP|STOP|SUB|TEMPO|THEN|TO|UART|VIDEO|WAIT)(?:\$|\b)/i,function:/\b(?:ABS|ANA|ASC|BIN|BTN|DEC|END|FREE|HELP|HEX|I2CR|I2CW|IN|INKEY|LEN|LINE|PEEK|RND|SCR|SOUND|STR|TICK|USR|VER|VPEEK|ZER)(?:\$|\b)/i,label:/(?:\B@\S+)/i,operator:/<[=>]?|>=?|\|\||&&|[+\-*\/=|&^~!]|\b(?:AND|NOT|OR)\b/i,punctuation:/[\[,;:()\]]/}}e.exports=t,t.displayName="ichigojam",t.aliases=[]},93865(e){"use strict";function t(e){e.languages.icon={comment:/#.*/,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n_]|\\.|_(?!\1)(?:\r\n|[\s\S]))*\1/,greedy:!0},number:/\b(?:\d+r[a-z\d]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b|\.\d+\b/i,"builtin-keyword":{pattern:/&(?:allocated|ascii|clock|collections|cset|current|date|dateline|digits|dump|e|error(?:number|text|value)?|errout|fail|features|file|host|input|lcase|letters|level|line|main|null|output|phi|pi|pos|progname|random|regions|source|storage|subject|time|trace|ucase|version)\b/,alias:"variable"},directive:{pattern:/\$\w+/,alias:"builtin"},keyword:/\b(?:break|by|case|create|default|do|else|end|every|fail|global|if|initial|invocable|link|local|next|not|of|procedure|record|repeat|return|static|suspend|then|to|until|while)\b/,function:/\b(?!\d)\w+(?=\s*[({]|\s*!\s*\[)/,operator:/[+-]:(?!=)|(?:[\/?@^%&]|\+\+?|--?|==?=?|~==?=?|\*\*?|\|\|\|?|<(?:->?|>?=?)(?::=)?|:(?:=:?)?|[!.\\|~]/,punctuation:/[\[\](){},;]/}}e.exports=t,t.displayName="icon",t.aliases=[]},51078(e){"use strict";function t(e){!function(e){function t(e,n){return n<=0?/[]/.source:e.replace(//g,function(){return t(e,n-1)})}var n=/'[{}:=,](?:[^']|'')*'(?!')/,r={pattern:/''/,greedy:!0,alias:"operator"},i={pattern:n,greedy:!0,inside:{escape:r}},a=t(/\{(?:[^{}']|'(?![{},'])|''||)*\}/.source.replace(//g,function(){return n.source}),8),o={pattern:RegExp(a),inside:{message:{pattern:/^(\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:null},"message-delimiter":{pattern:/./,alias:"punctuation"}}};e.languages["icu-message-format"]={argument:{pattern:RegExp(a),greedy:!0,inside:{content:{pattern:/^(\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:{"argument-name":{pattern:/^(\s*)[^{}:=,\s]+/,lookbehind:!0},"choice-style":{pattern:/^(\s*,\s*choice\s*,\s*)\S(?:[\s\S]*\S)?/,lookbehind:!0,inside:{punctuation:/\|/,range:{pattern:/^(\s*)[+-]?(?:\d+(?:\.\d*)?|\u221e)\s*[<#\u2264]/,lookbehind:!0,inside:{operator:/[<#\u2264]/,number:/\S+/}},rest:null}},"plural-style":{pattern:/^(\s*,\s*(?:plural|selectordinal)\s*,\s*)\S(?:[\s\S]*\S)?/,lookbehind:!0,inside:{offset:/^offset:\s*\d+/,"nested-message":o,selector:{pattern:/=\d+|[^{}:=,\s]+/,inside:{keyword:/^(?:zero|one|two|few|many|other)$/}}}},"select-style":{pattern:/^(\s*,\s*select\s*,\s*)\S(?:[\s\S]*\S)?/,lookbehind:!0,inside:{"nested-message":o,selector:{pattern:/[^{}:=,\s]+/,inside:{keyword:/^other$/}}}},keyword:/\b(?:choice|plural|select|selectordinal)\b/,"arg-type":{pattern:/\b(?:number|date|time|spellout|ordinal|duration)\b/,alias:"keyword"},"arg-skeleton":{pattern:/(,\s*)::[^{}:=,\s]+/,lookbehind:!0},"arg-style":{pattern:/(,\s*)(?:short|medium|long|full|integer|currency|percent)(?=\s*$)/,lookbehind:!0},"arg-style-text":{pattern:RegExp(/(^\s*,\s*(?=\S))/.source+t(/(?:[^{}']|'[^']*'|\{(?:)?\})+/.source,8)+"$"),lookbehind:!0,alias:"string"},punctuation:/,/}},"argument-delimiter":{pattern:/./,alias:"operator"}}},escape:r,string:i},o.inside.message.inside=e.languages["icu-message-format"],e.languages["icu-message-format"].argument.inside.content.inside["choice-style"].inside.rest=e.languages["icu-message-format"]}(e)}e.exports=t,t.displayName="icuMessageFormat",t.aliases=[]},91178(e,t,n){"use strict";var r=n(58090);function i(e){e.register(r),e.languages.idris=e.languages.extend("haskell",{comment:{pattern:/(?:(?:--|\|\|\|).*$|\{-[\s\S]*?-\})/m},keyword:/\b(?:Type|case|class|codata|constructor|corecord|data|do|dsl|else|export|if|implementation|implicit|import|impossible|in|infix|infixl|infixr|instance|interface|let|module|mutual|namespace|of|parameters|partial|postulate|private|proof|public|quoteGoal|record|rewrite|syntax|then|total|using|where|with)\b/,"import-statement":{pattern:/(^\s*)import\s+(?:[A-Z][\w']*)(?:\.[A-Z][\w']*)*/m,lookbehind:!0},builtin:void 0}),e.languages.idr=e.languages.idris}e.exports=i,i.displayName="idris",i.aliases=["idr"]},40011(e){"use strict";function t(e){e.languages.iecst={comment:[{pattern:/(^|[^\\])(?:\/\*[\s\S]*?(?:\*\/|$)|\(\*[\s\S]*?(?:\*\)|$)|\{[\s\S]*?(?:\}|$))/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":/\b(?:END_)?(?:PROGRAM|CONFIGURATION|INTERFACE|FUNCTION_BLOCK|FUNCTION|ACTION|TRANSITION|TYPE|STRUCT|(?:INITIAL_)?STEP|NAMESPACE|LIBRARY|CHANNEL|FOLDER|RESOURCE|VAR_(?:GLOBAL|INPUT|PUTPUT|IN_OUT|ACCESS|TEMP|EXTERNAL|CONFIG)|VAR|METHOD|PROPERTY)\b/i,keyword:/\b(?:(?:END_)?(?:IF|WHILE|REPEAT|CASE|FOR)|ELSE|FROM|THEN|ELSIF|DO|TO|BY|PRIVATE|PUBLIC|PROTECTED|CONSTANT|RETURN|EXIT|CONTINUE|GOTO|JMP|AT|RETAIN|NON_RETAIN|TASK|WITH|UNTIL|USING|EXTENDS|IMPLEMENTS|GET|SET|__TRY|__CATCH|__FINALLY|__ENDTRY)\b/,variable:/\b(?:AT|BOOL|BYTE|(?:D|L)?WORD|U?(?:S|D|L)?INT|L?REAL|TIME(?:_OF_DAY)?|TOD|DT|DATE(?:_AND_TIME)?|STRING|ARRAY|ANY|POINTER)\b/,symbol:/%[IQM][XBWDL][\d.]*|%[IQ][\d.]*/,number:/\b(?:16#[\da-f]+|2#[01_]+|0x[\da-f]+)\b|\b(?:T|D|DT|TOD)#[\d_shmd:]*|\b[A-Z]*#[\d.,_]*|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,boolean:/\b(?:TRUE|FALSE|NULL)\b/,function:/\w+(?=\()/,operator:/(?:S?R?:?=>?|&&?|\*\*?|<=?|>=?|[-:^/+])|\b(?:OR|AND|MOD|NOT|XOR|LE|GE|EQ|NE|GT|LT)\b/,punctuation:/[();]/,type:{pattern:/#/,alias:"selector"}}}e.exports=t,t.displayName="iecst",t.aliases=[]},12017(e){"use strict";function t(e){var t;(t=e).languages.ignore={comment:/^#.*/m,entry:{pattern:/\S(?:.*(?:(?:\\ )|\S))?/,alias:"string",inside:{operator:/^!|\*\*?|\?/,regex:{pattern:/(^|[^\\])\[[^\[\]]*\]/,lookbehind:!0},punctuation:/\//}}},t.languages.gitignore=t.languages.ignore,t.languages.hgignore=t.languages.ignore,t.languages.npmignore=t.languages.ignore}e.exports=t,t.displayName="ignore",t.aliases=["gitignore","hgignore","npmignore"]},65175(e){"use strict";function t(e){e.languages.inform7={string:{pattern:/"[^"]*"/,inside:{substitution:{pattern:/\[[^\[\]]+\]/,inside:{delimiter:{pattern:/\[|\]/,alias:"punctuation"}}}}},comment:{pattern:/\[[^\[\]]+\]/,greedy:!0},title:{pattern:/^[ \t]*(?:volume|book|part(?! of)|chapter|section|table)\b.+/im,alias:"important"},number:{pattern:/(^|[^-])(?:\b\d+(?:\.\d+)?(?:\^\d+)?(?:(?!\d)\w+)?|\b(?:one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve))\b(?!-)/i,lookbehind:!0},verb:{pattern:/(^|[^-])\b(?:applying to|are|attacking|answering|asking|be(?:ing)?|burning|buying|called|carries|carry(?! out)|carrying|climbing|closing|conceal(?:s|ing)?|consulting|contain(?:s|ing)?|cutting|drinking|dropping|eating|enclos(?:es?|ing)|entering|examining|exiting|getting|giving|going|ha(?:ve|s|ving)|hold(?:s|ing)?|impl(?:y|ies)|incorporat(?:es?|ing)|inserting|is|jumping|kissing|listening|locking|looking|mean(?:s|ing)?|opening|provid(?:es?|ing)|pulling|pushing|putting|relat(?:es?|ing)|removing|searching|see(?:s|ing)?|setting|showing|singing|sleeping|smelling|squeezing|switching|support(?:s|ing)?|swearing|taking|tasting|telling|thinking|throwing|touching|turning|tying|unlock(?:s|ing)?|var(?:y|ies|ying)|waiting|waking|waving|wear(?:s|ing)?)\b(?!-)/i,lookbehind:!0,alias:"operator"},keyword:{pattern:/(^|[^-])\b(?:after|before|carry out|check|continue the action|definition(?= *:)|do nothing|else|end (?:if|unless|the story)|every turn|if|include|instead(?: of)?|let|move|no|now|otherwise|repeat|report|resume the story|rule for|running through|say(?:ing)?|stop the action|test|try(?:ing)?|understand|unless|use|when|while|yes)\b(?!-)/i,lookbehind:!0},property:{pattern:/(^|[^-])\b(?:adjacent(?! to)|carried|closed|concealed|contained|dark|described|edible|empty|enclosed|enterable|even|female|fixed in place|full|handled|held|improper-named|incorporated|inedible|invisible|lighted|lit|lock(?:able|ed)|male|marked for listing|mentioned|negative|neuter|non-(?:empty|full|recurring)|odd|opaque|open(?:able)?|plural-named|portable|positive|privately-named|proper-named|provided|publically-named|pushable between rooms|recurring|related|rubbing|scenery|seen|singular-named|supported|swinging|switch(?:able|ed(?: on| off)?)|touch(?:able|ed)|transparent|unconcealed|undescribed|unlit|unlocked|unmarked for listing|unmentioned|unopenable|untouchable|unvisited|variable|visible|visited|wearable|worn)\b(?!-)/i,lookbehind:!0,alias:"symbol"},position:{pattern:/(^|[^-])\b(?:above|adjacent to|back side of|below|between|down|east|everywhere|front side|here|in|inside(?: from)?|north(?:east|west)?|nowhere|on(?: top of)?|other side|outside(?: from)?|parts? of|regionally in|south(?:east|west)?|through|up|west|within)\b(?!-)/i,lookbehind:!0,alias:"keyword"},type:{pattern:/(^|[^-])\b(?:actions?|activit(?:y|ies)|actors?|animals?|backdrops?|containers?|devices?|directions?|doors?|holders?|kinds?|lists?|m[ae]n|nobody|nothing|nouns?|numbers?|objects?|people|persons?|player(?:'s holdall)?|regions?|relations?|rooms?|rule(?:book)?s?|scenes?|someone|something|supporters?|tables?|texts?|things?|time|vehicles?|wom[ae]n)\b(?!-)/i,lookbehind:!0,alias:"variable"},punctuation:/[.,:;(){}]/},e.languages.inform7.string.inside.substitution.inside.rest=e.languages.inform7,e.languages.inform7.string.inside.substitution.inside.rest.text={pattern:/\S(?:\s*\S)*/,alias:"comment"}}e.exports=t,t.displayName="inform7",t.aliases=[]},14970(e){"use strict";function t(e){e.languages.ini={comment:{pattern:/(^[ \f\t\v]*)[#;][^\n\r]*/m,lookbehind:!0},header:{pattern:/(^[ \f\t\v]*)\[[^\n\r\]]*\]?/m,lookbehind:!0,inside:{"section-name":{pattern:/(^\[[ \f\t\v]*)[^ \f\t\v\]]+(?:[ \f\t\v]+[^ \f\t\v\]]+)*/,lookbehind:!0,alias:"selector"},punctuation:/\[|\]/}},key:{pattern:/(^[ \f\t\v]*)[^ \f\n\r\t\v=]+(?:[ \f\t\v]+[^ \f\n\r\t\v=]+)*(?=[ \f\t\v]*=)/m,lookbehind:!0,alias:"attr-name"},value:{pattern:/(=[ \f\t\v]*)[^ \f\n\r\t\v]+(?:[ \f\t\v]+[^ \f\n\r\t\v]+)*/,lookbehind:!0,alias:"attr-value",inside:{"inner-value":{pattern:/^("|').+(?=\1$)/,lookbehind:!0}}},punctuation:/=/}}e.exports=t,t.displayName="ini",t.aliases=[]},30764(e){"use strict";function t(e){e.languages.io={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0},{pattern:/(^|[^\\])#.*/,lookbehind:!0}],"triple-quoted-string":{pattern:/"""(?:\\[\s\S]|(?!""")[^\\])*"""/,greedy:!0,alias:"string"},string:{pattern:/"(?:\\.|[^\\\r\n"])*"/,greedy:!0},keyword:/\b(?:activate|activeCoroCount|asString|block|break|catch|clone|collectGarbage|compileString|continue|do|doFile|doMessage|doString|else|elseif|exit|for|foreach|forward|getSlot|getEnvironmentVariable|hasSlot|if|ifFalse|ifNil|ifNilEval|ifTrue|isActive|isNil|isResumable|list|message|method|parent|pass|pause|perform|performWithArgList|print|println|proto|raise|raiseResumable|removeSlot|resend|resume|schedulerSleepSeconds|self|sender|setSchedulerSleepSeconds|setSlot|shallowCopy|slotNames|super|system|then|thisBlock|thisContext|call|try|type|uniqueId|updateSlot|wait|while|write|yield)\b/,builtin:/\b(?:Array|AudioDevice|AudioMixer|Block|Box|Buffer|CFunction|CGI|Color|Curses|DBM|DNSResolver|DOConnection|DOProxy|DOServer|Date|Directory|Duration|DynLib|Error|Exception|FFT|File|Fnmatch|Font|Future|GL|GLE|GLScissor|GLU|GLUCylinder|GLUQuadric|GLUSphere|GLUT|Host|Image|Importer|LinkList|List|Lobby|Locals|MD5|MP3Decoder|MP3Encoder|Map|Message|Movie|Notification|Number|Object|OpenGL|Point|Protos|Regex|SGML|SGMLElement|SGMLParser|SQLite|Server|Sequence|ShowMessage|SleepyCat|SleepyCatCursor|Socket|SocketManager|Sound|Soup|Store|String|Tree|UDPSender|UPDReceiver|URL|User|Warning|WeakLink|Random|BigNum)\b/,boolean:/\b(?:true|false|nil)\b/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e-?\d+)?/i,operator:/[=!*/%+\-^&|]=|>>?=?|<+*\-%$|,#][.:]?|[?^]\.?|[;\[]:?|[~}"i][.:]|[ACeEIjLor]\.|(?:[_\/\\qsux]|_?\d):)/,alias:"keyword"},number:/\b_?(?:(?!\d:)\d+(?:\.\d+)?(?:(?:[ejpx]|ad|ar)_?\d+(?:\.\d+)?)*(?:b_?[\da-z]+(?:\.[\da-z]+)?)?|_\b(?!\.))/,adverb:{pattern:/[~}]|[\/\\]\.?|[bfM]\.|t[.:]/,alias:"builtin"},operator:/[=a][.:]|_\./,conjunction:{pattern:/&(?:\.:?|:)?|[.:@][.:]?|[!D][.:]|[;dHT]\.|`:?|[\^LS]:|"/,alias:"variable"},punctuation:/[()]/}}e.exports=t,t.displayName="j",t.aliases=[]},15909(e){"use strict";function t(e){var t,n,r,i;t=e,n=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,i={pattern:RegExp((r=/(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source)+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}},t.languages.java=t.languages.extend("clike",{"class-name":[i,{pattern:RegExp(r+/[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),lookbehind:!0,inside:i.inside}],keyword:n,function:[t.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),t.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),t.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":i,keyword:n,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,function(){return n.source})),lookbehind:!0,inside:{punctuation:/\./}}})}e.exports=t,t.displayName="java",t.aliases=[]},36553(e,t,n){"use strict";var r=n(15909),i=n(9858);function a(e){var t,n,a,o;e.register(r),e.register(i),t=e,n=/(^(?:[\t ]*(?:\*\s*)*))[^*\s].*$/m,a=/#\s*\w+(?:\s*\([^()]*\))?/.source,o=/(?:\b[a-zA-Z]\w+\s*\.\s*)*\b[A-Z]\w*(?:\s*)?|/.source.replace(//g,function(){return a}),t.languages.javadoc=t.languages.extend("javadoclike",{}),t.languages.insertBefore("javadoc","keyword",{reference:{pattern:RegExp(/(@(?:exception|throws|see|link|linkplain|value)\s+(?:\*\s*)?)/.source+"(?:"+o+")"),lookbehind:!0,inside:{function:{pattern:/(#\s*)\w+(?=\s*\()/,lookbehind:!0},field:{pattern:/(#\s*)\w+/,lookbehind:!0},namespace:{pattern:/\b(?:[a-z]\w*\s*\.\s*)+/,inside:{punctuation:/\./}},"class-name":/\b[A-Z]\w*/,keyword:t.languages.java.keyword,punctuation:/[#()[\],.]/}},"class-name":{pattern:/(@param\s+)<[A-Z]\w*>/,lookbehind:!0,inside:{punctuation:/[.<>]/}},"code-section":[{pattern:/(\{@code\s+(?!\s))(?:[^\s{}]|\s+(?![\s}])|\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\})+(?=\s*\})/,lookbehind:!0,inside:{code:{pattern:n,lookbehind:!0,inside:t.languages.java,alias:"language-java"}}},{pattern:/(<(code|pre|tt)>(?!)\s*)\S(?:\S|\s+\S)*?(?=\s*<\/\2>)/,lookbehind:!0,inside:{line:{pattern:n,lookbehind:!0,inside:{tag:t.languages.markup.tag,entity:t.languages.markup.entity,code:{pattern:/.+/,inside:t.languages.java,alias:"language-java"}}}}}],tag:t.languages.markup.tag,entity:t.languages.markup.entity}),t.languages.javadoclike.addSupport("java",t.languages.javadoc)}e.exports=a,a.displayName="javadoc",a.aliases=[]},9858(e){"use strict";function t(e){!function(e){var t=e.languages.javadoclike={parameter:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*@(?:param|arg|arguments)\s+)\w+/m,lookbehind:!0},keyword:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*|\{)@[a-z][a-zA-Z-]+\b/m,lookbehind:!0},punctuation:/[{}]/};function n(t,n){var r="doc-comment",i=e.languages[t];if(i){var a=i[r];if(!a){var o={};o[r]={pattern:/(^|[^\\])\/\*\*[^/][\s\S]*?(?:\*\/|$)/,lookbehind:!0,alias:"comment"},a=(i=e.languages.insertBefore(t,"comment",o))[r]}if(a instanceof RegExp&&(a=i[r]={pattern:a}),Array.isArray(a))for(var s=0,u=a.length;s|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),e.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,e.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:e.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:e.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:e.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:e.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:e.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),e.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:e.languages.javascript}},string:/[\s\S]+/}}}),e.languages.markup&&(e.languages.markup.tag.addInlined("script","javascript"),e.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),e.languages.js=e.languages.javascript}e.exports=t,t.displayName="javascript",t.aliases=["js"]},11223(e){"use strict";function t(e){e.languages.javastacktrace={summary:{pattern:/^[\t ]*(?:(?:Caused by:|Suppressed:|Exception in thread "[^"]*")[\t ]+)?[\w$.]+(?::.*)?$/m,inside:{keyword:{pattern:/^(\s*)(?:(?:Caused by|Suppressed)(?=:)|Exception in thread)/m,lookbehind:!0},string:{pattern:/^(\s*)"[^"]*"/,lookbehind:!0},exceptions:{pattern:/^(:?\s*)[\w$.]+(?=:|$)/,lookbehind:!0,inside:{"class-name":/[\w$]+(?=$|:)/,namespace:/[a-z]\w*/,punctuation:/[.:]/}},message:{pattern:/(:\s*)\S.*/,lookbehind:!0,alias:"string"},punctuation:/:/}},"stack-frame":{pattern:/^[\t ]*at (?:[\w$./]|@[\w$.+-]*\/)+(?:)?\([^()]*\)/m,inside:{keyword:{pattern:/^(\s*)at(?= )/,lookbehind:!0},source:[{pattern:/(\()\w+\.\w+:\d+(?=\))/,lookbehind:!0,inside:{file:/^\w+\.\w+/,punctuation:/:/,"line-number":{pattern:/\d+/,alias:"number"}}},{pattern:/(\()[^()]*(?=\))/,lookbehind:!0,inside:{keyword:/^(?:Unknown Source|Native Method)$/}}],"class-name":/[\w$]+(?=\.(?:|[\w$]+)\()/,function:/(?:|[\w$]+)(?=\()/,"class-loader":{pattern:/(\s)[a-z]\w*(?:\.[a-z]\w*)*(?=\/[\w@$.]*\/)/,lookbehind:!0,alias:"namespace",inside:{punctuation:/\./}},module:{pattern:/([\s/])[a-z]\w*(?:\.[a-z]\w*)*(?:@[\w$.+-]*)?(?=\/)/,lookbehind:!0,inside:{version:{pattern:/(@)[\s\S]+/,lookbehind:!0,alias:"number"},punctuation:/[@.]/}},namespace:{pattern:/(?:[a-z]\w*\.)+/,inside:{punctuation:/\./}},punctuation:/[()/.]/}},more:{pattern:/^[\t ]*\.{3} \d+ [a-z]+(?: [a-z]+)*/m,inside:{punctuation:/\.{3}/,number:/\d+/,keyword:/\b[a-z]+(?: [a-z]+)*\b/}}}}e.exports=t,t.displayName="javastacktrace",t.aliases=[]},57957(e){"use strict";function t(e){e.languages.jexl={string:/(["'])(?:\\[\s\S]|(?!\1)[^\\])*\1/,transform:{pattern:/(\|\s*)[a-zA-Zа-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF$][\wа-яА-Я\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF$]*/,alias:"function",lookbehind:!0},function:/[a-zA-Zа-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF$][\wа-яА-Я\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF$]*\s*(?=\()/,number:/\b\d+(?:\.\d+)?\b|\B\.\d+\b/,operator:/[<>!]=?|-|\+|&&|==|\|\|?|\/\/?|[?:*^%]/,boolean:/\b(?:true|false)\b/,keyword:/\bin\b/,punctuation:/[{}[\](),.]/}}e.exports=t,t.displayName="jexl",t.aliases=[]},75807(e){"use strict";function t(e){e.languages.jolie=e.languages.extend("clike",{string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},keyword:/\b(?:include|define|is_defined|undef|main|init|outputPort|inputPort|Location|Protocol|Interfaces|RequestResponse|OneWay|type|interface|extender|throws|cset|csets|forward|Aggregates|Redirects|embedded|courier|execution|sequential|concurrent|single|scope|install|throw|comp|cH|default|global|linkIn|linkOut|synchronized|this|new|for|if|else|while|in|Jolie|Java|Javascript|nullProcess|spawn|constants|with|provide|until|exit|foreach|instanceof|over|service)\b/,number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?l?/i,operator:/-[-=>]?|\+[+=]?|<[<=]?|[>=*!]=?|&&|\|\||[:?\/%^]/,punctuation:/[,.]/,builtin:/\b(?:undefined|string|int|void|long|Byte|bool|double|float|char|any)\b/,symbol:/[|;@]/}),delete e.languages.jolie["class-name"],e.languages.insertBefore("jolie","keyword",{function:{pattern:/((?:\b(?:outputPort|inputPort|in|service|courier)\b|@)\s*)\w+/,lookbehind:!0},aggregates:{pattern:/(\bAggregates\s*:\s*)(?:\w+(?:\s+with\s+\w+)?\s*,\s*)*\w+(?:\s+with\s+\w+)?/,lookbehind:!0,inside:{"with-extension":{pattern:/\bwith\s+\w+/,inside:{keyword:/\bwith\b/}},function:{pattern:/\w+/},punctuation:{pattern:/,/}}},redirects:{pattern:/(\bRedirects\s*:\s*)(?:\w+\s*=>\s*\w+\s*,\s*)*(?:\w+\s*=>\s*\w+)/,lookbehind:!0,inside:{punctuation:{pattern:/,/},function:{pattern:/\w+/},symbol:{pattern:/=>/}}}})}e.exports=t,t.displayName="jolie",t.aliases=[]},77935(e){"use strict";function t(e){var t,n,r,i,a;t=e,n=/\\\((?:[^()]|\([^()]*\))*\)/.source,r=RegExp(/"(?:[^"\r\n\\]|\\[^\r\n(]|__)*"/.source.replace(/__/g,function(){return n})),i={interpolation:{pattern:RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+n),lookbehind:!0,inside:{content:{pattern:/^(\\\()[\s\S]+(?=\)$)/,lookbehind:!0,inside:null},punctuation:/^\\\(|\)$/}}},a=t.languages.jq={comment:/#.*/,property:{pattern:RegExp(r.source+/(?=\s*:(?!:))/.source),greedy:!0,inside:i},string:{pattern:r,greedy:!0,inside:i},function:{pattern:/(\bdef\s+)[a-z_]\w+/i,lookbehind:!0},variable:/\B\$\w+/,"property-literal":{pattern:/\b[a-z_]\w*(?=\s*:(?!:))/i,alias:"property"},keyword:/\b(?:as|break|catch|def|elif|else|end|foreach|if|import|include|label|module|modulemeta|null|reduce|then|try|while)\b/,boolean:/\b(?:true|false)\b/,number:/(?:\b\d+\.|\B\.)?\b\d+(?:[eE][+-]?\d+)?\b/,operator:[{pattern:/\|=?/,alias:"pipe"},/\.\.|[!=<>]?=|\?\/\/|\/\/=?|[-+*/%]=?|[<>?]|\b(?:and|or|not)\b/],"c-style-function":{pattern:/\b[a-z_]\w*(?=\s*\()/i,alias:"function"},punctuation:/::|[()\[\]{},:;]|\.(?=\s*[\[\w$])/,dot:{pattern:/\./,alias:"important"}},i.interpolation.inside.content.inside=a}e.exports=t,t.displayName="jq",t.aliases=[]},46155(e){"use strict";function t(e){!function(e){function t(e,t){return RegExp(e.replace(//g,function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source}),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:(?:Uint|Int)(?:8|16|32)|Uint8Clamped|Float(?:32|64))?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|(?:Weak)?(?:Set|Map)|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:(?:\s*,\s*(?:\*\s*as\s+|\{[^{}]*\}))?|\*\s*as\s+|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|for|finally|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|location|navigator|performance|(?:local|session)Storage|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r=h.length)return;var n=e[t];if("string"==typeof n||"string"==typeof n.content){var r=h[o],i="string"==typeof n?n:n.content,a=i.indexOf(r);if(-1!==a){++o;var s=i.substring(0,a),u=c(l[r]),f=i.substring(a+r.length),d=[];if(s&&d.push(s),d.push(u),f){var b=[f];p(b),d.push.apply(d,b)}"string"==typeof n?(e.splice.apply(e,[t,1].concat(d)),t+=d.length-1):n.content=d}}else{var m=n.content;Array.isArray(m)?p(m):p([m])}}}return o=0,p(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[o("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),o("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),o("svg",/\bsvg/.source),o("markdown",/\b(?:md|markdown)/.source),o("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),o("sql",/\bsql/.source),t].filter(Boolean);var f={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function d(e){return"string"==typeof e?e:Array.isArray(e)?e.map(d).join(""):d(e.content)}e.hooks.add("after-tokenize",function(t){t.language in f&&n(t.tokens);function n(t){for(var r=0,i=t.length;r\s+)?)[A-Z]\w*(?:\.[A-Z]\w*)*/.source.replace(//g,function(){return a})),lookbehind:!0,inside:{punctuation:/\./}},{pattern:RegExp("(@[a-z]+\\s+)"+a),lookbehind:!0,inside:{string:n.string,number:n.number,boolean:n.boolean,keyword:t.languages.typescript.keyword,operator:/=>|\.\.\.|[&|?:*]/,punctuation:/[.,;=<>{}()[\]]/}}],example:{pattern:/(@example\s+(?!\s))(?:[^@\s]|\s+(?!\s))+?(?=\s*(?:\*\s*)?(?:@\w|\*\/))/,lookbehind:!0,inside:{code:{pattern:/^([\t ]*(?:\*\s*)?)\S.*$/m,lookbehind:!0,inside:n,alias:"language-javascript"}}}}),t.languages.javadoclike.addSupport("javascript",t.languages.jsdoc)}e.exports=a,a.displayName="jsdoc",a.aliases=[]},45950(e){"use strict";function t(e){e.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},e.languages.webmanifest=e.languages.json}e.exports=t,t.displayName="json",t.aliases=["webmanifest"]},50235(e,t,n){"use strict";var r=n(45950);function i(e){var t,n;e.register(r),n=/("|')(?:\\(?:\r\n?|\n|.)|(?!\1)[^\\\r\n])*\1/,(t=e).languages.json5=t.languages.extend("json",{property:[{pattern:RegExp(n.source+"(?=\\s*:)"),greedy:!0},{pattern:/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/,alias:"unquoted"}],string:{pattern:n,greedy:!0},number:/[+-]?\b(?:NaN|Infinity|0x[a-fA-F\d]+)\b|[+-]?(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[eE][+-]?\d+\b)?/})}e.exports=i,i.displayName="json5",i.aliases=[]},80963(e,t,n){"use strict";var r=n(45950);function i(e){e.register(r),e.languages.jsonp=e.languages.extend("json",{punctuation:/[{}[\]();,.]/}),e.languages.insertBefore("jsonp","punctuation",{function:/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*\()/})}e.exports=i,i.displayName="jsonp",i.aliases=[]},79358(e){"use strict";function t(e){e.languages.jsstacktrace={"error-message":{pattern:/^\S.*/m,alias:"string"},"stack-frame":{pattern:/(^[ \t]+)at[ \t].*/m,lookbehind:!0,inside:{"not-my-code":{pattern:/^at[ \t]+(?!\s)(?:node\.js||.*(?:node_modules|\(\)|\(|$|\(internal\/|\(node\.js)).*/m,alias:"comment"},filename:{pattern:/(\bat\s+(?!\s)|\()(?:[a-zA-Z]:)?[^():]+(?=:)/,lookbehind:!0,alias:"url"},function:{pattern:/(at\s+(?:new\s+)?)(?!\s)[_$a-zA-Z\xA0-\uFFFF<][.$\w\xA0-\uFFFF<>]*/,lookbehind:!0,inside:{punctuation:/\./}},punctuation:/[()]/,keyword:/\b(?:at|new)\b/,alias:{pattern:/\[(?:as\s+)?(?!\s)[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\]/,alias:"variable"},"line-number":{pattern:/:[0-9]+(?::[0-9]+)?\b/,alias:"number",inside:{punctuation:/:/}}}}}}e.exports=t,t.displayName="jsstacktrace",t.aliases=[]},96412(e){"use strict";function t(e){!function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,i=/(?:\{*\.{3}(?:[^{}]|)*\})/.source;function a(e,t){return RegExp(e=e.replace(//g,function(){return n}).replace(//g,function(){return r}).replace(//g,function(){return i}),t)}i=a(i).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=a(/<\/?(?:[\w.:-]+(?:+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|))?|))**\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/i,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/i,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:a(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:a(/=/.source),inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx},alias:"language-javascript"}},e.languages.jsx.tag);var o=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(o).join(""):""},s=function(t){for(var n=[],r=0;r0&&n[n.length-1].tagName===o(i.content[0].content[1])&&n.pop():"/>"===i.content[i.content.length-1].content||n.push({tagName:o(i.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===i.type&&"{"===i.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===i.type&&"}"===i.content?n[n.length-1].openedBraces--:a=!0),(a||"string"==typeof i)&&n.length>0&&0===n[n.length-1].openedBraces){var u=o(i);r0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(u=o(t[r-1])+u,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",u,null,u)}i.content&&"string"!=typeof i.content&&s(i.content)}};e.hooks.add("after-tokenize",function(e){("jsx"===e.language||"tsx"===e.language)&&s(e.tokens)})}(e)}e.exports=t,t.displayName="jsx",t.aliases=[]},39259(e){"use strict";function t(e){e.languages.julia={comment:{pattern:/(^|[^\\])(?:#=(?:[^#=]|=(?!#)|#(?!=)|#=(?:[^#=]|=(?!#)|#(?!=))*=#)*=#|#.*)/,lookbehind:!0},regex:{pattern:/r"(?:\\.|[^"\\\r\n])*"[imsx]{0,4}/,greedy:!0},string:{pattern:/"""[\s\S]+?"""|(?:\b\w+)?"(?:\\.|[^"\\\r\n])*"|(^|[^\w'])'(?:\\[^\r\n][^'\r\n]*|[^\\\r\n])'|`(?:[^\\`\r\n]|\\.)*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:abstract|baremodule|begin|bitstype|break|catch|ccall|const|continue|do|else|elseif|end|export|finally|for|function|global|if|immutable|import|importall|in|let|local|macro|module|print|println|quote|return|struct|try|type|typealias|using|while)\b/,boolean:/\b(?:true|false)\b/,number:/(?:\b(?=\d)|\B(?=\.))(?:0[box])?(?:[\da-f]+(?:_[\da-f]+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[efp][+-]?\d+(?:_\d+)*)?j?/i,operator:/&&|\|\||[-+*^%÷⊻&$\\]=?|\/[\/=]?|!=?=?|\|[=>]?|<(?:<=?|[=:|])?|>(?:=|>>?=?)?|==?=?|[~≠≤≥'√∛]/,punctuation:/::?|[{}[\]();,.?]/,constant:/\b(?:(?:NaN|Inf)(?:16|32|64)?|im|pi)\b|[πℯ]/}}e.exports=t,t.displayName="julia",t.aliases=[]},35760(e){"use strict";function t(e){e.languages.keyman={comment:/\bc\s.*/i,function:/\[\s*(?:(?:CTRL|SHIFT|ALT|LCTRL|RCTRL|LALT|RALT|CAPS|NCAPS)\s+)*(?:[TKU]_[\w?]+|".+?"|'.+?')\s*\]/i,string:/("|').*?\1/,bold:[/&(?:baselayout|bitmap|capsononly|capsalwaysoff|shiftfreescaps|copyright|ethnologuecode|hotkey|includecodes|keyboardversion|kmw_embedcss|kmw_embedjs|kmw_helpfile|kmw_helptext|kmw_rtl|language|layer|layoutfile|message|mnemoniclayout|name|oldcharposmatching|platform|targets|version|visualkeyboard|windowslanguages)\b/i,/\b(?:bitmap|bitmaps|caps on only|caps always off|shift frees caps|copyright|hotkey|language|layout|message|name|version)\b/i],keyword:/\b(?:any|baselayout|beep|call|context|deadkey|dk|if|index|layer|notany|nul|outs|platform|return|reset|save|set|store|use)\b/i,atrule:/\b(?:ansi|begin|unicode|group|using keys|match|nomatch)\b/i,number:/\b(?:U\+[\dA-F]+|d\d+|x[\da-f]+|\d+)\b/i,operator:/[+>\\,()]/,tag:/\$(?:keyman|kmfl|weaver|keymanweb|keymanonly):/i}}e.exports=t,t.displayName="keyman",t.aliases=[]},19715(e){"use strict";function t(e){var t,n;(t=e).languages.kotlin=t.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete t.languages.kotlin["class-name"],t.languages.insertBefore("kotlin","string",{"raw-string":{pattern:/("""|''')[\s\S]*?\1/,alias:"string"}}),t.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),t.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),n=[{pattern:/\$\{[^}]+\}/,inside:{delimiter:{pattern:/^\$\{|\}$/,alias:"variable"},rest:t.languages.kotlin}},{pattern:/\$\w+/,alias:"variable"}],t.languages.kotlin.string.inside=t.languages.kotlin["raw-string"].inside={interpolation:n},t.languages.kt=t.languages.kotlin,t.languages.kts=t.languages.kotlin}e.exports=t,t.displayName="kotlin",t.aliases=["kt","kts"]},27614(e){"use strict";function t(e){!function(e){var t=/\s\x00-\x1f\x22-\x2f\x3a-\x3f\x5b-\x5e\x60\x7b-\x7e/.source;function n(e,n){return RegExp(e.replace(//g,t),n)}e.languages.kumir={comment:{pattern:/\|.*/},prolog:{pattern:/#.*/,greedy:!0},string:{pattern:/"[^\n\r"]*"|'[^\n\r']*'/,greedy:!0},boolean:{pattern:n(/(^|[])(?:да|нет)(?=[]|$)/.source),lookbehind:!0},"operator-word":{pattern:n(/(^|[])(?:и|или|не)(?=[]|$)/.source),lookbehind:!0,alias:"keyword"},"system-variable":{pattern:n(/(^|[])знач(?=[]|$)/.source),lookbehind:!0,alias:"keyword"},type:[{pattern:n(/(^|[])(?:вещ|лит|лог|сим|цел)(?:\x20*таб)?(?=[]|$)/.source),lookbehind:!0,alias:"builtin"},{pattern:n(/(^|[])(?:компл|сканкод|файл|цвет)(?=[]|$)/.source),lookbehind:!0,alias:"important"}],keyword:{pattern:n(/(^|[])(?:алг|арг(?:\x20*рез)?|ввод|ВКЛЮЧИТЬ|вс[её]|выбор|вывод|выход|дано|для|до|дс|если|иначе|исп|использовать|кон(?:(?:\x20+|_)исп)?|кц(?:(?:\x20+|_)при)?|надо|нач|нс|нц|от|пауза|пока|при|раза?|рез|стоп|таб|то|утв|шаг)(?=[]|$)/.source),lookbehind:!0},name:{pattern:n(/(^|[])[^\d][^]*(?:\x20+[^]+)*(?=[]|$)/.source),lookbehind:!0},number:{pattern:n(/(^|[])(?:\B\$[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)(?=[]|$)/.source,"i"),lookbehind:!0},punctuation:/:=|[(),:;\[\]]/,"operator-char":{pattern:/\*\*?|<[=>]?|>=?|[-+/=]/,alias:"operator"}},e.languages.kum=e.languages.kumir}(e)}e.exports=t,t.displayName="kumir",t.aliases=["kum"]},42876(e){"use strict";function t(e){var t,n,r;t=e,r={"equation-command":{pattern:n=/\\(?:[^a-z()[\]]|[a-z*]+)/i,alias:"regex"}},t.languages.latex={comment:/%.*/m,cdata:{pattern:/(\\begin\{((?:verbatim|lstlisting)\*?)\})[\s\S]*?(?=\\end\{\2\})/,lookbehind:!0},equation:[{pattern:/\$\$(?:\\[\s\S]|[^\\$])+\$\$|\$(?:\\[\s\S]|[^\\$])+\$|\\\([\s\S]*?\\\)|\\\[[\s\S]*?\\\]/,inside:r,alias:"string"},{pattern:/(\\begin\{((?:equation|math|eqnarray|align|multline|gather)\*?)\})[\s\S]*?(?=\\end\{\2\})/,lookbehind:!0,inside:r,alias:"string"}],keyword:{pattern:/(\\(?:begin|end|ref|cite|label|usepackage|documentclass)(?:\[[^\]]+\])?\{)[^}]+(?=\})/,lookbehind:!0},url:{pattern:/(\\url\{)[^}]+(?=\})/,lookbehind:!0},headline:{pattern:/(\\(?:part|chapter|section|subsection|frametitle|subsubsection|paragraph|subparagraph|subsubparagraph|subsubsubparagraph)\*?(?:\[[^\]]+\])?\{)[^}]+(?=\})/,lookbehind:!0,alias:"class-name"},function:{pattern:n,alias:"selector"},punctuation:/[[\]{}&]/},t.languages.tex=t.languages.latex,t.languages.context=t.languages.latex}e.exports=t,t.displayName="latex",t.aliases=["tex","context"]},2980(e,t,n){"use strict";var r=n(93205),i=n(88262);function a(e){var t,n;e.register(r),e.register(i),(t=e).languages.latte={comment:/^\{\*[\s\S]*/,ld:{pattern:/^\{(?:[=_]|\/?(?!\d|\w+\()\w+)?/,inside:{punctuation:/^\{\/?/,tag:{pattern:/.+/,alias:"important"}}},rd:{pattern:/\}$/,inside:{punctuation:/.+/}},php:{pattern:/\S(?:[\s\S]*\S)?/,alias:"language-php",inside:t.languages.php}},n=t.languages.extend("markup",{}),t.languages.insertBefore("inside","attr-value",{"n-attr":{pattern:/n:[\w-]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+))?/,inside:{"attr-name":{pattern:/^[^\s=]+/,alias:"important"},"attr-value":{pattern:/=[\s\S]+/,inside:{punctuation:[/^=/,{pattern:/^(\s*)["']|["']$/,lookbehind:!0}],php:{pattern:/\S(?:[\s\S]*\S)?/,inside:t.languages.php}}}}}},n.tag),t.hooks.add("before-tokenize",function(e){if("latte"===e.language){var r=/\{\*[\s\S]*?\*\}|\{[^'"\s{}*](?:[^"'/{}]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|\/\*(?:[^*]|\*(?!\/))*\*\/)*?\}/g;t.languages["markup-templating"].buildPlaceholders(e,"latte",r),e.grammar=n}}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"latte")})}e.exports=a,a.displayName="latte",a.aliases=[]},41701(e){"use strict";function t(e){e.languages.less=e.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/i,operator:/[+\-*\/]/}),e.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}})}e.exports=t,t.displayName="less",t.aliases=[]},42491(e,t,n){"use strict";var r=n(9997);function i(e){e.register(r),function(e){for(var t=/\((?:[^();"#\\]|\\[\s\S]|;.*(?!.)|"(?:[^"\\]|\\.)*"|#(?:\{(?:(?!#\})[\s\S])*#\}|[^{])|)*\)/.source,n=5,r=0;r/g,function(){return t});t=t.replace(//g,/[^\s\S]/.source);var i=e.languages.lilypond={comment:/%(?:(?!\{).*|\{[\s\S]*?%\})/,"embedded-scheme":{pattern:RegExp(/(^|[=\s])#(?:"(?:[^"\\]|\\.)*"|[^\s()"]*(?:[^\s()]|))/.source.replace(//g,function(){return t}),"m"),lookbehind:!0,greedy:!0,inside:{scheme:{pattern:/^(#)[\s\S]+$/,lookbehind:!0,alias:"language-scheme",inside:{"embedded-lilypond":{pattern:/#\{[\s\S]*?#\}/,greedy:!0,inside:{punctuation:/^#\{|#\}$/,lilypond:{pattern:/[\s\S]+/,alias:"language-lilypond",inside:null}}},rest:e.languages.scheme}},punctuation:/#/}},string:{pattern:/"(?:[^"\\]|\\.)*"/,greedy:!0},"class-name":{pattern:/(\\new\s+)[\w-]+/,lookbehind:!0},keyword:{pattern:/\\[a-z][-\w]*/i,inside:{punctuation:/^\\/}},operator:/[=|]|<<|>>/,punctuation:{pattern:/(^|[a-z\d])(?:'+|,+|[_^]?-[_^]?(?:[-+^!>._]|(?=\d))|[_^]\.?|[.!])|[{}()[\]<>^~]|\\[()[\]<>\\!]|--|__/,lookbehind:!0},number:/\b\d+(?:\/\d+)?\b/};i["embedded-scheme"].inside.scheme.inside["embedded-lilypond"].inside.lilypond.inside=i,e.languages.ly=i}(e)}e.exports=i,i.displayName="lilypond",i.aliases=[]},34927(e,t,n){"use strict";var r=n(93205);function i(e){e.register(r),e.languages.liquid={comment:{pattern:/(^\{%\s*comment\s*%\})[\s\S]+(?=\{%\s*endcomment\s*%\}$)/,lookbehind:!0},delimiter:{pattern:/^\{(?:\{\{|[%\{])-?|-?(?:\}\}|[%\}])\}$/,alias:"punctuation"},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},keyword:/\b(?:as|assign|break|continue|cycle|decrement|echo|else|elsif|(?:end)?(?:capture|case|comment|for|form|if|paginate|style|raw|tablerow|unless)|in|include|increment|limit|liquid|offset|range|render|reversed|section|when|with)\b/,function:[{pattern:/(\|\s*)\w+/,lookbehind:!0,alias:"filter"},{pattern:/(\.\s*)(?:first|last|size)/,lookbehind:!0}],boolean:/\b(?:true|false|nil)\b/,range:{pattern:/\.\./,alias:"operator"},number:/\b\d+(?:\.\d+)?\b/,operator:/[!=]=|<>|[<>]=?|[|?:=-]|\b(?:and|or|contains(?=\s))\b/,punctuation:/[.,\[\]()]/},e.hooks.add("before-tokenize",function(t){var n=/\{%\s*comment\s*%\}[\s\S]*?\{%\s*endcomment\s*%\}|\{(?:%[\s\S]*?%|\{\{[\s\S]*?\}\}|\{[\s\S]*?\})\}/g,r=!1;e.languages["markup-templating"].buildPlaceholders(t,"liquid",n,function(e){var t=/^\{%-?\s*(\w+)/.exec(e);if(t){var n=t[1];if("raw"===n&&!r)return r=!0,!0;if("endraw"===n)return r=!1,!0}return!r})}),e.hooks.add("after-tokenize",function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"liquid")})}e.exports=i,i.displayName="liquid",i.aliases=[]},3848(e){"use strict";function t(e){!function(e){function t(e){return RegExp("(\\()"+e+"(?=[\\s\\)])")}function n(e){return RegExp("([\\s([])"+e+"(?=[\\s)])")}var r="[-+*/_~!@$%^=<>{}\\w]+",i="&"+r,a="(\\()",o="(?=\\))",s="(?=\\s)",u={heading:{pattern:/;;;.*/,alias:["comment","title"]},comment:/;.*/,string:{pattern:/"(?:[^"\\]|\\.)*"/,greedy:!0,inside:{argument:/[-A-Z]+(?=[.,\s])/,symbol:RegExp("`"+r+"'")}},"quoted-symbol":{pattern:RegExp("#?'"+r),alias:["variable","symbol"]},"lisp-property":{pattern:RegExp(":"+r),alias:"property"},splice:{pattern:RegExp(",@?"+r),alias:["symbol","variable"]},keyword:[{pattern:RegExp(a+"(?:(?:lexical-)?let\\*?|(?:cl-)?letf|if|when|while|unless|cons|cl-loop|and|or|not|cond|setq|error|message|null|require|provide|use-package)"+s),lookbehind:!0},{pattern:RegExp(a+"(?:for|do|collect|return|finally|append|concat|in|by)"+s),lookbehind:!0}],declare:{pattern:t("declare"),lookbehind:!0,alias:"keyword"},interactive:{pattern:t("interactive"),lookbehind:!0,alias:"keyword"},boolean:{pattern:n("(?:t|nil)"),lookbehind:!0},number:{pattern:n("[-+]?\\d+(?:\\.\\d*)?"),lookbehind:!0},defvar:{pattern:RegExp(a+"def(?:var|const|custom|group)\\s+"+r),lookbehind:!0,inside:{keyword:/^def[a-z]+/,variable:RegExp(r)}},defun:{pattern:RegExp(a+"(?:cl-)?(?:defun\\*?|defmacro)\\s+"+r+"\\s+\\([\\s\\S]*?\\)"),lookbehind:!0,inside:{keyword:/^(?:cl-)?def\S+/,arguments:null,function:{pattern:RegExp("(^\\s)"+r),lookbehind:!0},punctuation:/[()]/}},lambda:{pattern:RegExp(a+"lambda\\s+\\(\\s*(?:&?"+r+"(?:\\s+&?"+r+")*\\s*)?\\)"),lookbehind:!0,inside:{keyword:/^lambda/,arguments:null,punctuation:/[()]/}},car:{pattern:RegExp(a+r),lookbehind:!0},punctuation:[/(?:['`,]?\(|[)\[\]])/,{pattern:/(\s)\.(?=\s)/,lookbehind:!0}]},c={"lisp-marker":RegExp(i),rest:{argument:{pattern:RegExp(r),alias:"variable"},varform:{pattern:RegExp(a+r+"\\s+\\S[\\s\\S]*"+o),lookbehind:!0,inside:{string:u.string,boolean:u.boolean,number:u.number,symbol:u.symbol,punctuation:/[()]/}}}},l="\\S+(?:\\s+\\S+)*",f={pattern:RegExp(a+"[\\s\\S]*"+o),lookbehind:!0,inside:{"rest-vars":{pattern:RegExp("&(?:rest|body)\\s+"+l),inside:c},"other-marker-vars":{pattern:RegExp("&(?:optional|aux)\\s+"+l),inside:c},keys:{pattern:RegExp("&key\\s+"+l+"(?:\\s+&allow-other-keys)?"),inside:c},argument:{pattern:RegExp(r),alias:"variable"},punctuation:/[()]/}};u.lambda.inside.arguments=f,u.defun.inside.arguments=e.util.clone(f),u.defun.inside.arguments.inside.sublist=f,e.languages.lisp=u,e.languages.elisp=u,e.languages.emacs=u,e.languages["emacs-lisp"]=u}(e)}e.exports=t,t.displayName="lisp",t.aliases=[]},41469(e){"use strict";function t(e){e.languages.livescript={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\])#.*/,lookbehind:!0}],"interpolated-string":{pattern:/(^|[^"])("""|")(?:\\[\s\S]|(?!\2)[^\\])*\2(?!")/,lookbehind:!0,greedy:!0,inside:{variable:{pattern:/(^|[^\\])#[a-z_](?:-?[a-z]|[\d_])*/m,lookbehind:!0},interpolation:{pattern:/(^|[^\\])#\{[^}]+\}/m,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^#\{|\}$/,alias:"variable"}}},string:/[\s\S]+/}},string:[{pattern:/('''|')(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0},{pattern:/<\[[\s\S]*?\]>/,greedy:!0},/\\[^\s,;\])}]+/],regex:[{pattern:/\/\/(?:\[[^\r\n\]]*\]|\\.|(?!\/\/)[^\\\[])+\/\/[gimyu]{0,5}/,greedy:!0,inside:{comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0}}},{pattern:/\/(?:\[[^\r\n\]]*\]|\\.|[^/\\\r\n\[])+\/[gimyu]{0,5}/,greedy:!0}],keyword:{pattern:/(^|(?!-).)\b(?:break|case|catch|class|const|continue|default|do|else|extends|fallthrough|finally|for(?: ever)?|function|if|implements|it|let|loop|new|null|otherwise|own|return|super|switch|that|then|this|throw|try|unless|until|var|void|when|while|yield)(?!-)\b/m,lookbehind:!0},"keyword-operator":{pattern:/(^|[^-])\b(?:(?:delete|require|typeof)!|(?:and|by|delete|export|from|import(?: all)?|in|instanceof|is(?:nt| not)?|not|of|or|til|to|typeof|with|xor)(?!-)\b)/m,lookbehind:!0,alias:"operator"},boolean:{pattern:/(^|[^-])\b(?:false|no|off|on|true|yes)(?!-)\b/m,lookbehind:!0},argument:{pattern:/(^|(?!\.&\.)[^&])&(?!&)\d*/m,lookbehind:!0,alias:"variable"},number:/\b(?:\d+~[\da-z]+|\d[\d_]*(?:\.\d[\d_]*)?(?:[a-z]\w*)?)/i,identifier:/[a-z_](?:-?[a-z]|[\d_])*/i,operator:[{pattern:/( )\.(?= )/,lookbehind:!0},/\.(?:[=~]|\.\.?)|\.(?:[&|^]|<<|>>>?)\.|:(?:=|:=?)|&&|\|[|>]|<(?:<[>=?]?|-(?:->?|>)?|\+\+?|@@?|%%?|\*\*?|!(?:~?=|--?>|~?~>)?|~(?:~?>|=)?|==?|\^\^?|[\/?]/],punctuation:/[(){}\[\]|.,:;`]/},e.languages.livescript["interpolated-string"].inside.interpolation.inside.rest=e.languages.livescript}e.exports=t,t.displayName="livescript",t.aliases=[]},73070(e){"use strict";function t(e){var t;(t=e).languages.llvm={comment:/;.*/,string:{pattern:/"[^"]*"/,greedy:!0},boolean:/\b(?:true|false)\b/,variable:/[%@!#](?:(?!\d)(?:[-$.\w]|\\[a-f\d]{2})+|\d+)/i,label:/(?!\d)(?:[-$.\w]|\\[a-f\d]{2})+:/i,type:{pattern:/\b(?:double|float|fp128|half|i[1-9]\d*|label|metadata|ppc_fp128|token|void|x86_fp80|x86_mmx)\b/,alias:"class-name"},keyword:/\b[a-z_][a-z_0-9]*\b/,number:/[+-]?\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b|\b0x[\dA-Fa-f]+\b|\b0xK[\dA-Fa-f]{20}\b|\b0x[ML][\dA-Fa-f]{32}\b|\b0xH[\dA-Fa-f]{4}\b/,punctuation:/[{}[\];(),.!*=<>]/}}e.exports=t,t.displayName="llvm",t.aliases=[]},35049(e){"use strict";function t(e){e.languages.log={string:{pattern:/"(?:[^"\\\r\n]|\\.)*"|'(?![st] | \w)(?:[^'\\\r\n]|\\.)*'/,greedy:!0},level:[{pattern:/\b(?:ALERT|CRIT|CRITICAL|EMERG|EMERGENCY|ERR|ERROR|FAILURE|FATAL|SEVERE)\b/,alias:["error","important"]},{pattern:/\b(?:WARN|WARNING|WRN)\b/,alias:["warning","important"]},{pattern:/\b(?:DISPLAY|INF|INFO|NOTICE|STATUS)\b/,alias:["info","keyword"]},{pattern:/\b(?:DBG|DEBUG|FINE)\b/,alias:["debug","keyword"]},{pattern:/\b(?:FINER|FINEST|TRACE|TRC|VERBOSE|VRB)\b/,alias:["trace","comment"]}],property:{pattern:/((?:^|[\]|])[ \t]*)[a-z_](?:[\w-]|\b\/\b)*(?:[. ]\(?\w(?:[\w-]|\b\/\b)*\)?)*:(?=\s)/im,lookbehind:!0},separator:{pattern:/(^|[^-+])-{3,}|={3,}|\*{3,}|- - /m,lookbehind:!0,alias:"comment"},url:/\b(?:https?|ftp|file):\/\/[^\s|,;'"]*[^\s|,;'">.]/,email:{pattern:/(^|\s)[-\w+.]+@[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+(?=\s)/,lookbehind:!0,alias:"url"},"ip-address":{pattern:/\b(?:\d{1,3}(?:\.\d{1,3}){3})\b/i,alias:"constant"},"mac-address":{pattern:/\b[a-f0-9]{2}(?::[a-f0-9]{2}){5}\b/i,alias:"constant"},domain:{pattern:/(^|\s)[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)*\.[a-z][a-z0-9-]+(?=\s)/,lookbehind:!0,alias:"constant"},uuid:{pattern:/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i,alias:"constant"},hash:{pattern:/\b(?:[a-f0-9]{32}){1,2}\b/i,alias:"constant"},"file-path":{pattern:/\b[a-z]:[\\/][^\s|,;:(){}\[\]"']+|(^|[\s:\[\](>|])\.{0,2}\/\w[^\s|,;:(){}\[\]"']*/i,lookbehind:!0,greedy:!0,alias:"string"},date:{pattern:RegExp(/\b\d{4}[-/]\d{2}[-/]\d{2}(?:T(?=\d{1,2}:)|(?=\s\d{1,2}:))/.source+"|"+/\b\d{1,4}[-/ ](?:\d{1,2}|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[-/ ]\d{2,4}T?\b/.source+"|"+/\b(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)(?:\s{1,2}(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))?|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s{1,2}\d{1,2}\b/.source,"i"),alias:"number"},time:{pattern:/\b\d{1,2}:\d{1,2}:\d{1,2}(?:[.,:]\d+)?(?:\s?[+-]\d{2}:?\d{2}|Z)?\b/,alias:"number"},boolean:/\b(?:true|false|null)\b/i,number:{pattern:/(^|[^.\w])(?:0x[a-f0-9]+|0o[0-7]+|0b[01]+|v?\d[\da-f]*(?:\.\d+)*(?:e[+-]?\d+)?[a-z]{0,3}\b)\b(?!\.\w)/i,lookbehind:!0},operator:/[;:?<=>~/@!$%&+\-|^(){}*#]/,punctuation:/[\[\].,]/}}e.exports=t,t.displayName="log",t.aliases=[]},8789(e){"use strict";function t(e){e.languages.lolcode={comment:[/\bOBTW\s[\s\S]*?\sTLDR\b/,/\bBTW.+/],string:{pattern:/"(?::.|[^":])*"/,inside:{variable:/:\{[^}]+\}/,symbol:[/:\([a-f\d]+\)/i,/:\[[^\]]+\]/,/:[)>o":]/]},greedy:!0},number:/(?:\B-)?(?:\b\d+(?:\.\d*)?|\B\.\d+)/,symbol:{pattern:/(^|\s)(?:A )?(?:YARN|NUMBR|NUMBAR|TROOF|BUKKIT|NOOB)(?=\s|,|$)/,lookbehind:!0,inside:{keyword:/A(?=\s)/}},label:{pattern:/((?:^|\s)(?:IM IN YR|IM OUTTA YR) )[a-zA-Z]\w*/,lookbehind:!0,alias:"string"},function:{pattern:/((?:^|\s)(?:I IZ|HOW IZ I|IZ) )[a-zA-Z]\w*/,lookbehind:!0},keyword:[{pattern:/(^|\s)(?:O HAI IM|KTHX|HAI|KTHXBYE|I HAS A|ITZ(?: A)?|R|AN|MKAY|SMOOSH|MAEK|IS NOW(?: A)?|VISIBLE|GIMMEH|O RLY\?|YA RLY|NO WAI|OIC|MEBBE|WTF\?|OMG|OMGWTF|GTFO|IM IN YR|IM OUTTA YR|FOUND YR|YR|TIL|WILE|UPPIN|NERFIN|I IZ|HOW IZ I|IF U SAY SO|SRS|HAS A|LIEK(?: A)?|IZ)(?=\s|,|$)/,lookbehind:!0},/'Z(?=\s|,|$)/],boolean:{pattern:/(^|\s)(?:WIN|FAIL)(?=\s|,|$)/,lookbehind:!0},variable:{pattern:/(^|\s)IT(?=\s|,|$)/,lookbehind:!0},operator:{pattern:/(^|\s)(?:NOT|BOTH SAEM|DIFFRINT|(?:SUM|DIFF|PRODUKT|QUOSHUNT|MOD|BIGGR|SMALLR|BOTH|EITHER|WON|ALL|ANY) OF)(?=\s|,|$)/,lookbehind:!0},punctuation:/\.{3}|…|,|!/}}e.exports=t,t.displayName="lolcode",t.aliases=[]},59803(e){"use strict";function t(e){e.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}}e.exports=t,t.displayName="lua",t.aliases=[]},33055(e){"use strict";function t(e){e.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},builtin:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,symbol:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:[/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,{pattern:/(\()(?:addsuffix|abspath|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:s|list)?)(?=[ \t])/,lookbehind:!0}],operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/}}e.exports=t,t.displayName="makefile",t.aliases=[]},90542(e){"use strict";function t(e){!function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(//g,function(){return t}),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,i=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,function(){return r}),a=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"font-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+i+a+"(?:"+i+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+i+a+")(?:"+i+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+i+")"+a+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+i+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)|_(?:(?!_))+_)+__\b|\*\*(?:(?!\*)|\*(?:(?!\*))+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)|__(?:(?!_))+__)+_\b|\*(?:(?!\*)|\*\*(?:(?!\*))+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~))+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\]))+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\]))+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach(function(t){["url","bold","italic","strike","code-snippet"].forEach(function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])})}),e.hooks.add("after-tokenize",function(e){("markdown"===e.language||"md"===e.language)&&t(e.tokens);function t(e){if(e&&"string"!=typeof e)for(var n=0,r=e.length;n=a.length);u++){var c=s[u];if("string"==typeof c||c.content&&"string"==typeof c.content){var l=a[i],f=n.tokenStack[l],d="string"==typeof c?c:c.content,h=t(r,l),p=d.indexOf(h);if(p>-1){++i;var b=d.substring(0,p),m=new e.Token(r,e.tokenize(f,n.grammar),"language-"+r,f),g=d.substring(p+h.length),v=[];b&&v.push.apply(v,o([b])),v.push(m),g&&v.push.apply(v,o([g])),"string"==typeof c?s.splice.apply(s,[u,1].concat(v)):c.content=v}}else c.content&&o(c.content)}return s}}}})}(e)}e.exports=t,t.displayName="markupTemplating",t.aliases=[]},2717(e){"use strict";function t(e){e.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/,name:/[^\s<>'"]+/}},cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},e.languages.markup.tag.inside["attr-value"].inside.entity=e.languages.markup.entity,e.languages.markup.doctype.inside["internal-subset"].inside=e.languages.markup,e.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.value.replace(/&/,"&"))}),Object.defineProperty(e.languages.markup.tag,"addInlined",{value:function(t,n){var r={};r["language-"+n]={pattern:/(^$)/i,lookbehind:!0,inside:e.languages[n]},r.cdata=/^$/i;var i={"included-cdata":{pattern://i,inside:r}};i["language-"+n]={pattern:/[\s\S]+/,inside:e.languages[n]};var a={};a[t]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,function(){return t}),"i"),lookbehind:!0,greedy:!0,inside:i},e.languages.insertBefore("markup","cdata",a)}}),Object.defineProperty(e.languages.markup.tag,"addAttribute",{value:function(t,n){e.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+t+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[n,"language-"+n],inside:e.languages[n]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),e.languages.html=e.languages.markup,e.languages.mathml=e.languages.markup,e.languages.svg=e.languages.markup,e.languages.xml=e.languages.extend("markup",{}),e.languages.ssml=e.languages.xml,e.languages.atom=e.languages.xml,e.languages.rss=e.languages.xml}e.exports=t,t.displayName="markup",t.aliases=["html","mathml","svg","xml","ssml","atom","rss"]},27992(e){"use strict";function t(e){e.languages.matlab={comment:[/%\{[\s\S]*?\}%/,/%.+/],string:{pattern:/\B'(?:''|[^'\r\n])*'/,greedy:!0},number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[eE][+-]?\d+)?(?:[ij])?|\b[ij]\b/,keyword:/\b(?:break|case|catch|continue|else|elseif|end|for|function|if|inf|NaN|otherwise|parfor|pause|pi|return|switch|try|while)\b/,function:/\b(?!\d)\w+(?=\s*\()/,operator:/\.?[*^\/\\']|[+\-:@]|[<>=~]=?|&&?|\|\|?/,punctuation:/\.{3}|[.,;\[\](){}!]/}}e.exports=t,t.displayName="matlab",t.aliases=[]},606(e){"use strict";function t(e){e.languages.mel={comment:/\/\/.*/,code:{pattern:/`(?:\\.|[^\\`\r\n])*`/,greedy:!0,alias:"italic",inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"}}},string:{pattern:/"(?:\\.|[^\\"\r\n])*"/,greedy:!0},variable:/\$\w+/,number:/\b0x[\da-fA-F]+\b|\b\d+(?:\.\d*)?|\B\.\d+/,flag:{pattern:/-[^\d\W]\w*/,alias:"operator"},keyword:/\b(?:break|case|continue|default|do|else|float|for|global|if|in|int|matrix|proc|return|string|switch|vector|while)\b/,function:/\b\w+(?=\()|\b(?:about|abs|addAttr|addAttributeEditorNodeHelp|addDynamic|addNewShelfTab|addPP|addPanelCategory|addPrefixToName|advanceToNextDrivenKey|affectedNet|affects|aimConstraint|air|alias|aliasAttr|align|alignCtx|alignCurve|alignSurface|allViewFit|ambientLight|angle|angleBetween|animCone|animCurveEditor|animDisplay|animView|annotate|appendStringArray|applicationName|applyAttrPreset|applyTake|arcLenDimContext|arcLengthDimension|arclen|arrayMapper|art3dPaintCtx|artAttrCtx|artAttrPaintVertexCtx|artAttrSkinPaintCtx|artAttrTool|artBuildPaintMenu|artFluidAttrCtx|artPuttyCtx|artSelectCtx|artSetPaintCtx|artUserPaintCtx|assignCommand|assignInputDevice|assignViewportFactories|attachCurve|attachDeviceAttr|attachSurface|attrColorSliderGrp|attrCompatibility|attrControlGrp|attrEnumOptionMenu|attrEnumOptionMenuGrp|attrFieldGrp|attrFieldSliderGrp|attrNavigationControlGrp|attrPresetEditWin|attributeExists|attributeInfo|attributeMenu|attributeQuery|autoKeyframe|autoPlace|bakeClip|bakeFluidShading|bakePartialHistory|bakeResults|bakeSimulation|basename|basenameEx|batchRender|bessel|bevel|bevelPlus|binMembership|bindSkin|blend2|blendShape|blendShapeEditor|blendShapePanel|blendTwoAttr|blindDataType|boneLattice|boundary|boxDollyCtx|boxZoomCtx|bufferCurve|buildBookmarkMenu|buildKeyframeMenu|button|buttonManip|CBG|cacheFile|cacheFileCombine|cacheFileMerge|cacheFileTrack|camera|cameraView|canCreateManip|canvas|capitalizeString|catch|catchQuiet|ceil|changeSubdivComponentDisplayLevel|changeSubdivRegion|channelBox|character|characterMap|characterOutlineEditor|characterize|chdir|checkBox|checkBoxGrp|checkDefaultRenderGlobals|choice|circle|circularFillet|clamp|clear|clearCache|clip|clipEditor|clipEditorCurrentTimeCtx|clipSchedule|clipSchedulerOutliner|clipTrimBefore|closeCurve|closeSurface|cluster|cmdFileOutput|cmdScrollFieldExecuter|cmdScrollFieldReporter|cmdShell|coarsenSubdivSelectionList|collision|color|colorAtPoint|colorEditor|colorIndex|colorIndexSliderGrp|colorSliderButtonGrp|colorSliderGrp|columnLayout|commandEcho|commandLine|commandPort|compactHairSystem|componentEditor|compositingInterop|computePolysetVolume|condition|cone|confirmDialog|connectAttr|connectControl|connectDynamic|connectJoint|connectionInfo|constrain|constrainValue|constructionHistory|container|containsMultibyte|contextInfo|control|convertFromOldLayers|convertIffToPsd|convertLightmap|convertSolidTx|convertTessellation|convertUnit|copyArray|copyFlexor|copyKey|copySkinWeights|cos|cpButton|cpCache|cpClothSet|cpCollision|cpConstraint|cpConvClothToMesh|cpForces|cpGetSolverAttr|cpPanel|cpProperty|cpRigidCollisionFilter|cpSeam|cpSetEdit|cpSetSolverAttr|cpSolver|cpSolverTypes|cpTool|cpUpdateClothUVs|createDisplayLayer|createDrawCtx|createEditor|createLayeredPsdFile|createMotionField|createNewShelf|createNode|createRenderLayer|createSubdivRegion|cross|crossProduct|ctxAbort|ctxCompletion|ctxEditMode|ctxTraverse|currentCtx|currentTime|currentTimeCtx|currentUnit|curve|curveAddPtCtx|curveCVCtx|curveEPCtx|curveEditorCtx|curveIntersect|curveMoveEPCtx|curveOnSurface|curveSketchCtx|cutKey|cycleCheck|cylinder|dagPose|date|defaultLightListCheckBox|defaultNavigation|defineDataServer|defineVirtualDevice|deformer|deg_to_rad|delete|deleteAttr|deleteShadingGroupsAndMaterials|deleteShelfTab|deleteUI|deleteUnusedBrushes|delrandstr|detachCurve|detachDeviceAttr|detachSurface|deviceEditor|devicePanel|dgInfo|dgdirty|dgeval|dgtimer|dimWhen|directKeyCtx|directionalLight|dirmap|dirname|disable|disconnectAttr|disconnectJoint|diskCache|displacementToPoly|displayAffected|displayColor|displayCull|displayLevelOfDetail|displayPref|displayRGBColor|displaySmoothness|displayStats|displayString|displaySurface|distanceDimContext|distanceDimension|doBlur|dolly|dollyCtx|dopeSheetEditor|dot|dotProduct|doubleProfileBirailSurface|drag|dragAttrContext|draggerContext|dropoffLocator|duplicate|duplicateCurve|duplicateSurface|dynCache|dynControl|dynExport|dynExpression|dynGlobals|dynPaintEditor|dynParticleCtx|dynPref|dynRelEdPanel|dynRelEditor|dynamicLoad|editAttrLimits|editDisplayLayerGlobals|editDisplayLayerMembers|editRenderLayerAdjustment|editRenderLayerGlobals|editRenderLayerMembers|editor|editorTemplate|effector|emit|emitter|enableDevice|encodeString|endString|endsWith|env|equivalent|equivalentTol|erf|error|eval|evalDeferred|evalEcho|event|exactWorldBoundingBox|exclusiveLightCheckBox|exec|executeForEachObject|exists|exp|expression|expressionEditorListen|extendCurve|extendSurface|extrude|fcheck|fclose|feof|fflush|fgetline|fgetword|file|fileBrowserDialog|fileDialog|fileExtension|fileInfo|filetest|filletCurve|filter|filterCurve|filterExpand|filterStudioImport|findAllIntersections|findAnimCurves|findKeyframe|findMenuItem|findRelatedSkinCluster|finder|firstParentOf|fitBspline|flexor|floatEq|floatField|floatFieldGrp|floatScrollBar|floatSlider|floatSlider2|floatSliderButtonGrp|floatSliderGrp|floor|flow|fluidCacheInfo|fluidEmitter|fluidVoxelInfo|flushUndo|fmod|fontDialog|fopen|formLayout|format|fprint|frameLayout|fread|freeFormFillet|frewind|fromNativePath|fwrite|gamma|gauss|geometryConstraint|getApplicationVersionAsFloat|getAttr|getClassification|getDefaultBrush|getFileList|getFluidAttr|getInputDeviceRange|getMayaPanelTypes|getModifiers|getPanel|getParticleAttr|getPluginResource|getenv|getpid|glRender|glRenderEditor|globalStitch|gmatch|goal|gotoBindPose|grabColor|gradientControl|gradientControlNoAttr|graphDollyCtx|graphSelectContext|graphTrackCtx|gravity|grid|gridLayout|group|groupObjectsByName|HfAddAttractorToAS|HfAssignAS|HfBuildEqualMap|HfBuildFurFiles|HfBuildFurImages|HfCancelAFR|HfConnectASToHF|HfCreateAttractor|HfDeleteAS|HfEditAS|HfPerformCreateAS|HfRemoveAttractorFromAS|HfSelectAttached|HfSelectAttractors|HfUnAssignAS|hardenPointCurve|hardware|hardwareRenderPanel|headsUpDisplay|headsUpMessage|help|helpLine|hermite|hide|hilite|hitTest|hotBox|hotkey|hotkeyCheck|hsv_to_rgb|hudButton|hudSlider|hudSliderButton|hwReflectionMap|hwRender|hwRenderLoad|hyperGraph|hyperPanel|hyperShade|hypot|iconTextButton|iconTextCheckBox|iconTextRadioButton|iconTextRadioCollection|iconTextScrollList|iconTextStaticLabel|ikHandle|ikHandleCtx|ikHandleDisplayScale|ikSolver|ikSplineHandleCtx|ikSystem|ikSystemInfo|ikfkDisplayMethod|illustratorCurves|image|imfPlugins|inheritTransform|insertJoint|insertJointCtx|insertKeyCtx|insertKnotCurve|insertKnotSurface|instance|instanceable|instancer|intField|intFieldGrp|intScrollBar|intSlider|intSliderGrp|interToUI|internalVar|intersect|iprEngine|isAnimCurve|isConnected|isDirty|isParentOf|isSameObject|isTrue|isValidObjectName|isValidString|isValidUiName|isolateSelect|itemFilter|itemFilterAttr|itemFilterRender|itemFilterType|joint|jointCluster|jointCtx|jointDisplayScale|jointLattice|keyTangent|keyframe|keyframeOutliner|keyframeRegionCurrentTimeCtx|keyframeRegionDirectKeyCtx|keyframeRegionDollyCtx|keyframeRegionInsertKeyCtx|keyframeRegionMoveKeyCtx|keyframeRegionScaleKeyCtx|keyframeRegionSelectKeyCtx|keyframeRegionSetKeyCtx|keyframeRegionTrackCtx|keyframeStats|lassoContext|lattice|latticeDeformKeyCtx|launch|launchImageEditor|layerButton|layeredShaderPort|layeredTexturePort|layout|layoutDialog|lightList|lightListEditor|lightListPanel|lightlink|lineIntersection|linearPrecision|linstep|listAnimatable|listAttr|listCameras|listConnections|listDeviceAttachments|listHistory|listInputDeviceAxes|listInputDeviceButtons|listInputDevices|listMenuAnnotation|listNodeTypes|listPanelCategories|listRelatives|listSets|listTransforms|listUnselected|listerEditor|loadFluid|loadNewShelf|loadPlugin|loadPluginLanguageResources|loadPrefObjects|localizedPanelLabel|lockNode|loft|log|longNameOf|lookThru|ls|lsThroughFilter|lsType|lsUI|Mayatomr|mag|makeIdentity|makeLive|makePaintable|makeRoll|makeSingleSurface|makeTubeOn|makebot|manipMoveContext|manipMoveLimitsCtx|manipOptions|manipRotateContext|manipRotateLimitsCtx|manipScaleContext|manipScaleLimitsCtx|marker|match|max|memory|menu|menuBarLayout|menuEditor|menuItem|menuItemToShelf|menuSet|menuSetPref|messageLine|min|minimizeApp|mirrorJoint|modelCurrentTimeCtx|modelEditor|modelPanel|mouse|movIn|movOut|move|moveIKtoFK|moveKeyCtx|moveVertexAlongDirection|multiProfileBirailSurface|mute|nParticle|nameCommand|nameField|namespace|namespaceInfo|newPanelItems|newton|nodeCast|nodeIconButton|nodeOutliner|nodePreset|nodeType|noise|nonLinear|normalConstraint|normalize|nurbsBoolean|nurbsCopyUVSet|nurbsCube|nurbsEditUV|nurbsPlane|nurbsSelect|nurbsSquare|nurbsToPoly|nurbsToPolygonsPref|nurbsToSubdiv|nurbsToSubdivPref|nurbsUVSet|nurbsViewDirectionVector|objExists|objectCenter|objectLayer|objectType|objectTypeUI|obsoleteProc|oceanNurbsPreviewPlane|offsetCurve|offsetCurveOnSurface|offsetSurface|openGLExtension|openMayaPref|optionMenu|optionMenuGrp|optionVar|orbit|orbitCtx|orientConstraint|outlinerEditor|outlinerPanel|overrideModifier|paintEffectsDisplay|pairBlend|palettePort|paneLayout|panel|panelConfiguration|panelHistory|paramDimContext|paramDimension|paramLocator|parent|parentConstraint|particle|particleExists|particleInstancer|particleRenderInfo|partition|pasteKey|pathAnimation|pause|pclose|percent|performanceOptions|pfxstrokes|pickWalk|picture|pixelMove|planarSrf|plane|play|playbackOptions|playblast|plugAttr|plugNode|pluginInfo|pluginResourceUtil|pointConstraint|pointCurveConstraint|pointLight|pointMatrixMult|pointOnCurve|pointOnSurface|pointPosition|poleVectorConstraint|polyAppend|polyAppendFacetCtx|polyAppendVertex|polyAutoProjection|polyAverageNormal|polyAverageVertex|polyBevel|polyBlendColor|polyBlindData|polyBoolOp|polyBridgeEdge|polyCacheMonitor|polyCheck|polyChipOff|polyClipboard|polyCloseBorder|polyCollapseEdge|polyCollapseFacet|polyColorBlindData|polyColorDel|polyColorPerVertex|polyColorSet|polyCompare|polyCone|polyCopyUV|polyCrease|polyCreaseCtx|polyCreateFacet|polyCreateFacetCtx|polyCube|polyCut|polyCutCtx|polyCylinder|polyCylindricalProjection|polyDelEdge|polyDelFacet|polyDelVertex|polyDuplicateAndConnect|polyDuplicateEdge|polyEditUV|polyEditUVShell|polyEvaluate|polyExtrudeEdge|polyExtrudeFacet|polyExtrudeVertex|polyFlipEdge|polyFlipUV|polyForceUV|polyGeoSampler|polyHelix|polyInfo|polyInstallAction|polyLayoutUV|polyListComponentConversion|polyMapCut|polyMapDel|polyMapSew|polyMapSewMove|polyMergeEdge|polyMergeEdgeCtx|polyMergeFacet|polyMergeFacetCtx|polyMergeUV|polyMergeVertex|polyMirrorFace|polyMoveEdge|polyMoveFacet|polyMoveFacetUV|polyMoveUV|polyMoveVertex|polyNormal|polyNormalPerVertex|polyNormalizeUV|polyOptUvs|polyOptions|polyOutput|polyPipe|polyPlanarProjection|polyPlane|polyPlatonicSolid|polyPoke|polyPrimitive|polyPrism|polyProjection|polyPyramid|polyQuad|polyQueryBlindData|polyReduce|polySelect|polySelectConstraint|polySelectConstraintMonitor|polySelectCtx|polySelectEditCtx|polySeparate|polySetToFaceNormal|polySewEdge|polyShortestPathCtx|polySmooth|polySoftEdge|polySphere|polySphericalProjection|polySplit|polySplitCtx|polySplitEdge|polySplitRing|polySplitVertex|polyStraightenUVBorder|polySubdivideEdge|polySubdivideFacet|polyToSubdiv|polyTorus|polyTransfer|polyTriangulate|polyUVSet|polyUnite|polyWedgeFace|popen|popupMenu|pose|pow|preloadRefEd|print|progressBar|progressWindow|projFileViewer|projectCurve|projectTangent|projectionContext|projectionManip|promptDialog|propModCtx|propMove|psdChannelOutliner|psdEditTextureFile|psdExport|psdTextureFile|putenv|pwd|python|querySubdiv|quit|rad_to_deg|radial|radioButton|radioButtonGrp|radioCollection|radioMenuItemCollection|rampColorPort|rand|randomizeFollicles|randstate|rangeControl|readTake|rebuildCurve|rebuildSurface|recordAttr|recordDevice|redo|reference|referenceEdit|referenceQuery|refineSubdivSelectionList|refresh|refreshAE|registerPluginResource|rehash|reloadImage|removeJoint|removeMultiInstance|removePanelCategory|rename|renameAttr|renameSelectionList|renameUI|render|renderGlobalsNode|renderInfo|renderLayerButton|renderLayerParent|renderLayerPostProcess|renderLayerUnparent|renderManip|renderPartition|renderQualityNode|renderSettings|renderThumbnailUpdate|renderWindowEditor|renderWindowSelectContext|renderer|reorder|reorderDeformers|requires|reroot|resampleFluid|resetAE|resetPfxToPolyCamera|resetTool|resolutionNode|retarget|reverseCurve|reverseSurface|revolve|rgb_to_hsv|rigidBody|rigidSolver|roll|rollCtx|rootOf|rot|rotate|rotationInterpolation|roundConstantRadius|rowColumnLayout|rowLayout|runTimeCommand|runup|sampleImage|saveAllShelves|saveAttrPreset|saveFluid|saveImage|saveInitialState|saveMenu|savePrefObjects|savePrefs|saveShelf|saveToolSettings|scale|scaleBrushBrightness|scaleComponents|scaleConstraint|scaleKey|scaleKeyCtx|sceneEditor|sceneUIReplacement|scmh|scriptCtx|scriptEditorInfo|scriptJob|scriptNode|scriptTable|scriptToShelf|scriptedPanel|scriptedPanelType|scrollField|scrollLayout|sculpt|searchPathArray|seed|selLoadSettings|select|selectContext|selectCurveCV|selectKey|selectKeyCtx|selectKeyframeRegionCtx|selectMode|selectPref|selectPriority|selectType|selectedNodes|selectionConnection|separator|setAttr|setAttrEnumResource|setAttrMapping|setAttrNiceNameResource|setConstraintRestPosition|setDefaultShadingGroup|setDrivenKeyframe|setDynamic|setEditCtx|setEditor|setFluidAttr|setFocus|setInfinity|setInputDeviceMapping|setKeyCtx|setKeyPath|setKeyframe|setKeyframeBlendshapeTargetWts|setMenuMode|setNodeNiceNameResource|setNodeTypeFlag|setParent|setParticleAttr|setPfxToPolyCamera|setPluginResource|setProject|setStampDensity|setStartupMessage|setState|setToolTo|setUITemplate|setXformManip|sets|shadingConnection|shadingGeometryRelCtx|shadingLightRelCtx|shadingNetworkCompare|shadingNode|shapeCompare|shelfButton|shelfLayout|shelfTabLayout|shellField|shortNameOf|showHelp|showHidden|showManipCtx|showSelectionInTitle|showShadingGroupAttrEditor|showWindow|sign|simplify|sin|singleProfileBirailSurface|size|sizeBytes|skinCluster|skinPercent|smoothCurve|smoothTangentSurface|smoothstep|snap2to2|snapKey|snapMode|snapTogetherCtx|snapshot|soft|softMod|softModCtx|sort|sound|soundControl|source|spaceLocator|sphere|sphrand|spotLight|spotLightPreviewPort|spreadSheetEditor|spring|sqrt|squareSurface|srtContext|stackTrace|startString|startsWith|stitchAndExplodeShell|stitchSurface|stitchSurfacePoints|strcmp|stringArrayCatenate|stringArrayContains|stringArrayCount|stringArrayInsertAtIndex|stringArrayIntersector|stringArrayRemove|stringArrayRemoveAtIndex|stringArrayRemoveDuplicates|stringArrayRemoveExact|stringArrayToString|stringToStringArray|strip|stripPrefixFromName|stroke|subdAutoProjection|subdCleanTopology|subdCollapse|subdDuplicateAndConnect|subdEditUV|subdListComponentConversion|subdMapCut|subdMapSewMove|subdMatchTopology|subdMirror|subdToBlind|subdToPoly|subdTransferUVsToCache|subdiv|subdivCrease|subdivDisplaySmoothness|substitute|substituteAllString|substituteGeometry|substring|surface|surfaceSampler|surfaceShaderList|swatchDisplayPort|switchTable|symbolButton|symbolCheckBox|sysFile|system|tabLayout|tan|tangentConstraint|texLatticeDeformContext|texManipContext|texMoveContext|texMoveUVShellContext|texRotateContext|texScaleContext|texSelectContext|texSelectShortestPathCtx|texSmudgeUVContext|texWinToolCtx|text|textCurves|textField|textFieldButtonGrp|textFieldGrp|textManip|textScrollList|textToShelf|textureDisplacePlane|textureHairColor|texturePlacementContext|textureWindow|threadCount|threePointArcCtx|timeControl|timePort|timerX|toNativePath|toggle|toggleAxis|toggleWindowVisibility|tokenize|tokenizeList|tolerance|tolower|toolButton|toolCollection|toolDropped|toolHasOptions|toolPropertyWindow|torus|toupper|trace|track|trackCtx|transferAttributes|transformCompare|transformLimits|translator|trim|trunc|truncateFluidCache|truncateHairCache|tumble|tumbleCtx|turbulence|twoPointArcCtx|uiRes|uiTemplate|unassignInputDevice|undo|undoInfo|ungroup|uniform|unit|unloadPlugin|untangleUV|untitledFileName|untrim|upAxis|updateAE|userCtx|uvLink|uvSnapshot|validateShelfName|vectorize|view2dToolCtx|viewCamera|viewClipPlane|viewFit|viewHeadOn|viewLookAt|viewManip|viewPlace|viewSet|visor|volumeAxis|vortex|waitCursor|warning|webBrowser|webBrowserPrefs|whatIs|window|windowPref|wire|wireContext|workspace|wrinkle|wrinkleContext|writeTake|xbmLangPathList|xform)\b/,operator:[/\+[+=]?|-[-=]?|&&|\|\||[<>]=|[*\/!=]=?|[%^]/,{pattern:/(^|[^<])<(?!<)/,lookbehind:!0},{pattern:/(^|[^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,:;?\[\](){}]/},e.languages.mel.code.inside.rest=e.languages.mel}e.exports=t,t.displayName="mel",t.aliases=[]},23388(e){"use strict";function t(e){e.languages.mizar={comment:/::.+/,keyword:/@proof\b|\b(?:according|aggregate|all|and|antonym|are|as|associativity|assume|asymmetry|attr|be|begin|being|by|canceled|case|cases|clusters?|coherence|commutativity|compatibility|connectedness|consider|consistency|constructors|contradiction|correctness|def|deffunc|define|definitions?|defpred|do|does|equals|end|environ|ex|exactly|existence|for|from|func|given|hence|hereby|holds|idempotence|identity|iff?|implies|involutiveness|irreflexivity|is|it|let|means|mode|non|not|notations?|now|of|or|otherwise|over|per|pred|prefix|projectivity|proof|provided|qua|reconsider|redefine|reduce|reducibility|reflexivity|registrations?|requirements|reserve|sch|schemes?|section|selector|set|sethood|st|struct|such|suppose|symmetry|synonym|take|that|the|then|theorems?|thesis|thus|to|transitivity|uniqueness|vocabular(?:y|ies)|when|where|with|wrt)\b/,parameter:{pattern:/\$(?:10|\d)/,alias:"variable"},variable:/\b\w+(?=:)/,number:/(?:\b|-)\d+\b/,operator:/\.\.\.|->|&|\.?=/,punctuation:/\(#|#\)|[,:;\[\](){}]/}}e.exports=t,t.displayName="mizar",t.aliases=[]},90596(e){"use strict";function t(e){var t,n,r,i;t=e,r=["ObjectId","Code","BinData","DBRef","Timestamp","NumberLong","NumberDecimal","MaxKey","MinKey","RegExp","ISODate","UUID"],i="(?:"+(n=(n=["$eq","$gt","$gte","$in","$lt","$lte","$ne","$nin","$and","$not","$nor","$or","$exists","$type","$expr","$jsonSchema","$mod","$regex","$text","$where","$geoIntersects","$geoWithin","$near","$nearSphere","$all","$elemMatch","$size","$bitsAllClear","$bitsAllSet","$bitsAnyClear","$bitsAnySet","$comment","$elemMatch","$meta","$slice","$currentDate","$inc","$min","$max","$mul","$rename","$set","$setOnInsert","$unset","$addToSet","$pop","$pull","$push","$pullAll","$each","$position","$slice","$sort","$bit","$addFields","$bucket","$bucketAuto","$collStats","$count","$currentOp","$facet","$geoNear","$graphLookup","$group","$indexStats","$limit","$listLocalSessions","$listSessions","$lookup","$match","$merge","$out","$planCacheStats","$project","$redact","$replaceRoot","$replaceWith","$sample","$set","$skip","$sort","$sortByCount","$unionWith","$unset","$unwind","$abs","$accumulator","$acos","$acosh","$add","$addToSet","$allElementsTrue","$and","$anyElementTrue","$arrayElemAt","$arrayToObject","$asin","$asinh","$atan","$atan2","$atanh","$avg","$binarySize","$bsonSize","$ceil","$cmp","$concat","$concatArrays","$cond","$convert","$cos","$dateFromParts","$dateToParts","$dateFromString","$dateToString","$dayOfMonth","$dayOfWeek","$dayOfYear","$degreesToRadians","$divide","$eq","$exp","$filter","$first","$floor","$function","$gt","$gte","$hour","$ifNull","$in","$indexOfArray","$indexOfBytes","$indexOfCP","$isArray","$isNumber","$isoDayOfWeek","$isoWeek","$isoWeekYear","$last","$last","$let","$literal","$ln","$log","$log10","$lt","$lte","$ltrim","$map","$max","$mergeObjects","$meta","$min","$millisecond","$minute","$mod","$month","$multiply","$ne","$not","$objectToArray","$or","$pow","$push","$radiansToDegrees","$range","$reduce","$regexFind","$regexFindAll","$regexMatch","$replaceOne","$replaceAll","$reverseArray","$round","$rtrim","$second","$setDifference","$setEquals","$setIntersection","$setIsSubset","$setUnion","$size","$sin","$slice","$split","$sqrt","$stdDevPop","$stdDevSamp","$strcasecmp","$strLenBytes","$strLenCP","$substr","$substrBytes","$substrCP","$subtract","$sum","$switch","$tan","$toBool","$toDate","$toDecimal","$toDouble","$toInt","$toLong","$toObjectId","$toString","$toLower","$toUpper","$trim","$trunc","$type","$week","$year","$zip","$comment","$explain","$hint","$max","$maxTimeMS","$min","$orderby","$query","$returnKey","$showDiskLoc","$natural"]).map(function(e){return e.replace("$","\\$")})).join("|")+")\\b",t.languages.mongodb=t.languages.extend("javascript",{}),t.languages.insertBefore("mongodb","string",{property:{pattern:/(?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)(?=\s*:)/,greedy:!0,inside:{keyword:RegExp("^(['\"])?"+i+"(?:\\1)?$")}}}),t.languages.mongodb.string.inside={url:{pattern:/https?:\/\/[-\w@:%.+~#=]{1,256}\.[a-z0-9()]{1,6}\b[-\w()@:%+.~#?&/=]*/i,greedy:!0},entity:{pattern:/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/,greedy:!0}},t.languages.insertBefore("mongodb","constant",{builtin:{pattern:RegExp("\\b(?:"+r.join("|")+")\\b"),alias:"keyword"}})}e.exports=t,t.displayName="mongodb",t.aliases=[]},95721(e){"use strict";function t(e){e.languages.monkey={string:/"[^"\r\n]*"/,comment:[{pattern:/^#Rem\s[\s\S]*?^#End/im,greedy:!0},{pattern:/'.+/,greedy:!0}],preprocessor:{pattern:/(^[ \t]*)#.+/m,lookbehind:!0,alias:"comment"},function:/\b\w+(?=\()/,"type-char":{pattern:/(\w)[?%#$]/,lookbehind:!0,alias:"variable"},number:{pattern:/((?:\.\.)?)(?:(?:\b|\B-\.?|\B\.)\d+(?:(?!\.\.)\.\d*)?|\$[\da-f]+)/i,lookbehind:!0},keyword:/\b(?:Void|Strict|Public|Private|Property|Bool|Int|Float|String|Array|Object|Continue|Exit|Import|Extern|New|Self|Super|Try|Catch|Eachin|True|False|Extends|Abstract|Final|Select|Case|Default|Const|Local|Global|Field|Method|Function|Class|End|If|Then|Else|ElseIf|EndIf|While|Wend|Repeat|Until|Forever|For|To|Step|Next|Return|Module|Interface|Implements|Inline|Throw|Null)\b/i,operator:/\.\.|<[=>]?|>=?|:?=|(?:[+\-*\/&~|]|\b(?:Mod|Shl|Shr)\b)=?|\b(?:And|Not|Or)\b/i,punctuation:/[.,:;()\[\]]/}}e.exports=t,t.displayName="monkey",t.aliases=[]},64262(e){"use strict";function t(e){e.languages.moonscript={comment:/--.*/,string:[{pattern:/'[^']*'|\[(=*)\[[\s\S]*?\]\1\]/,greedy:!0},{pattern:/"[^"]*"/,greedy:!0,inside:{interpolation:{pattern:/#\{[^{}]*\}/,inside:{moonscript:{pattern:/(^#\{)[\s\S]+(?=\})/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/#\{|\}/,alias:"punctuation"}}}}}],"class-name":[{pattern:/(\b(?:class|extends)[ \t]+)\w+/,lookbehind:!0},/\b[A-Z]\w*/],keyword:/\b(?:class|continue|do|else|elseif|export|extends|for|from|if|import|in|local|nil|return|self|super|switch|then|unless|using|when|while|with)\b/,variable:/@@?\w*/,property:{pattern:/\b(?!\d)\w+(?=:)|(:)(?!\d)\w+/,lookbehind:!0},function:{pattern:/\b(?:_G|_VERSION|assert|collectgarbage|coroutine\.(?:running|create|resume|status|wrap|yield)|debug\.(?:debug|gethook|getinfo|getlocal|getupvalue|setlocal|setupvalue|sethook|traceback|getfenv|getmetatable|getregistry|setfenv|setmetatable)|dofile|error|getfenv|getmetatable|io\.(?:stdin|stdout|stderr|close|flush|input|lines|open|output|popen|read|tmpfile|type|write)|ipairs|load|loadfile|loadstring|math\.(?:abs|acos|asin|atan|atan2|ceil|sin|cos|tan|deg|exp|floor|log|log10|max|min|fmod|modf|cosh|sinh|tanh|pow|rad|sqrt|frexp|ldexp|random|randomseed|pi)|module|next|os\.(?:clock|date|difftime|execute|exit|getenv|remove|rename|setlocale|time|tmpname)|package\.(?:cpath|loaded|loadlib|path|preload|seeall)|pairs|pcall|print|rawequal|rawget|rawset|require|select|setfenv|setmetatable|string\.(?:byte|char|dump|find|len|lower|rep|sub|upper|format|gsub|gmatch|match|reverse)|table\.(?:maxn|concat|sort|insert|remove)|tonumber|tostring|type|unpack|xpcall)\b/,inside:{punctuation:/\./}},boolean:/\b(?:false|true)\b/,number:/(?:\B\.\d+|\b\d+\.\d+|\b\d+(?=[eE]))(?:[eE][-+]?\d+)?\b|\b(?:0x[a-fA-F\d]+|\d+)(?:U?LL)?\b/,operator:/\.{3}|[-=]>|~=|(?:[-+*/%<>!=]|\.\.)=?|[:#^]|\b(?:and|or)\b=?|\b(?:not)\b/,punctuation:/[.,()[\]{}\\]/},e.languages.moonscript.string[1].inside.interpolation.inside.moonscript.inside=e.languages.moonscript,e.languages.moon=e.languages.moonscript}e.exports=t,t.displayName="moonscript",t.aliases=["moon"]},18190(e){"use strict";function t(e){e.languages.n1ql={comment:/\/\*[\s\S]*?(?:$|\*\/)/,parameter:/\$[\w.]+/,string:{pattern:/(["'])(?:\\[\s\S]|(?!\1)[^\\]|\1\1)*\1/,greedy:!0},identifier:{pattern:/`(?:\\[\s\S]|[^\\`]|``)*`/,greedy:!0},function:/\b(?:ABS|ACOS|ARRAY_AGG|ARRAY_APPEND|ARRAY_AVG|ARRAY_CONCAT|ARRAY_CONTAINS|ARRAY_COUNT|ARRAY_DISTINCT|ARRAY_FLATTEN|ARRAY_IFNULL|ARRAY_INSERT|ARRAY_INTERSECT|ARRAY_LENGTH|ARRAY_MAX|ARRAY_MIN|ARRAY_POSITION|ARRAY_PREPEND|ARRAY_PUT|ARRAY_RANGE|ARRAY_REMOVE|ARRAY_REPEAT|ARRAY_REPLACE|ARRAY_REVERSE|ARRAY_SORT|ARRAY_STAR|ARRAY_SUM|ARRAY_SYMDIFF|ARRAY_SYMDIFFN|ARRAY_UNION|ASIN|ATAN|ATAN2|AVG|BASE64|BASE64_DECODE|BASE64_ENCODE|BITAND|BITCLEAR|BITNOT|BITOR|BITSET|BITSHIFT|BITTEST|BITXOR|CEIL|CLOCK_LOCAL|CLOCK_MILLIS|CLOCK_STR|CLOCK_TZ|CLOCK_UTC|CONTAINS|CONTAINS_TOKEN|CONTAINS_TOKEN_LIKE|CONTAINS_TOKEN_REGEXP|COS|COUNT|CURL|DATE_ADD_MILLIS|DATE_ADD_STR|DATE_DIFF_MILLIS|DATE_DIFF_STR|DATE_FORMAT_STR|DATE_PART_MILLIS|DATE_PART_STR|DATE_RANGE_MILLIS|DATE_RANGE_STR|DATE_TRUNC_MILLIS|DATE_TRUNC_STR|DECODE_JSON|DEGREES|DURATION_TO_STR|E|ENCODED_SIZE|ENCODE_JSON|EXP|FLOOR|GREATEST|HAS_TOKEN|IFINF|IFMISSING|IFMISSINGORNULL|IFNAN|IFNANORINF|IFNULL|INITCAP|ISARRAY|ISATOM|ISBOOLEAN|ISNUMBER|ISOBJECT|ISSTRING|IsBitSET|LEAST|LENGTH|LN|LOG|LOWER|LTRIM|MAX|META|MILLIS|MILLIS_TO_LOCAL|MILLIS_TO_STR|MILLIS_TO_TZ|MILLIS_TO_UTC|MILLIS_TO_ZONE_NAME|MIN|MISSINGIF|NANIF|NEGINFIF|NOW_LOCAL|NOW_MILLIS|NOW_STR|NOW_TZ|NOW_UTC|NULLIF|OBJECT_ADD|OBJECT_CONCAT|OBJECT_INNER_PAIRS|OBJECT_INNER_VALUES|OBJECT_LENGTH|OBJECT_NAMES|OBJECT_PAIRS|OBJECT_PUT|OBJECT_REMOVE|OBJECT_RENAME|OBJECT_REPLACE|OBJECT_UNWRAP|OBJECT_VALUES|PAIRS|PI|POLY_LENGTH|POSINFIF|POSITION|POWER|RADIANS|RANDOM|REGEXP_CONTAINS|REGEXP_LIKE|REGEXP_POSITION|REGEXP_REPLACE|REPEAT|REPLACE|REVERSE|ROUND|RTRIM|SIGN|SIN|SPLIT|SQRT|STR_TO_DURATION|STR_TO_MILLIS|STR_TO_TZ|STR_TO_UTC|STR_TO_ZONE_NAME|SUBSTR|SUFFIXES|SUM|TAN|TITLE|TOARRAY|TOATOM|TOBOOLEAN|TOKENS|TONUMBER|TOOBJECT|TOSTRING|TRIM|TRUNC|TYPE|UPPER|WEEKDAY_MILLIS|WEEKDAY_STR)(?=\s*\()/i,keyword:/\b(?:ALL|ALTER|ANALYZE|AS|ASC|BEGIN|BINARY|BOOLEAN|BREAK|BUCKET|BUILD|BY|CALL|CAST|CLUSTER|COLLATE|COLLECTION|COMMIT|CONNECT|CONTINUE|CORRELATE|COVER|CREATE|DATABASE|DATASET|DATASTORE|DECLARE|DECREMENT|DELETE|DERIVED|DESC|DESCRIBE|DISTINCT|DO|DROP|EACH|ELEMENT|EXCEPT|EXCLUDE|EXECUTE|EXPLAIN|FETCH|FLATTEN|FOR|FORCE|FROM|FUNCTION|GRANT|GROUP|GSI|HAVING|IF|IGNORE|ILIKE|INCLUDE|INCREMENT|INDEX|INFER|INLINE|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KEYS|KEYSPACE|KNOWN|LAST|LEFT|LET|LETTING|LIMIT|LSM|MAP|MAPPING|MATCHED|MATERIALIZED|MERGE|MINUS|MISSING|NAMESPACE|NEST|NULL|NUMBER|OBJECT|OFFSET|ON|OPTION|ORDER|OUTER|OVER|PARSE|PARTITION|PASSWORD|PATH|POOL|PREPARE|PRIMARY|PRIVATE|PRIVILEGE|PROCEDURE|PUBLIC|RAW|REALM|REDUCE|RENAME|RETURN|RETURNING|REVOKE|RIGHT|ROLE|ROLLBACK|SATISFIES|SCHEMA|SELECT|SELF|SEMI|SET|SHOW|SOME|START|STATISTICS|STRING|SYSTEM|TO|TRANSACTION|TRIGGER|TRUNCATE|UNDER|UNION|UNIQUE|UNKNOWN|UNNEST|UNSET|UPDATE|UPSERT|USE|USER|USING|VALIDATE|VALUE|VALUES|VIA|VIEW|WHERE|WHILE|WITH|WORK|XOR)\b/i,boolean:/\b(?:TRUE|FALSE)\b/i,number:/(?:\b\d+\.|\B\.)\d+e[+\-]?\d+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/%]|!=|==?|\|\||<[>=]?|>=?|\b(?:AND|ANY|ARRAY|BETWEEN|CASE|ELSE|END|EVERY|EXISTS|FIRST|IN|LIKE|NOT|OR|THEN|VALUED|WHEN|WITHIN)\b/i,punctuation:/[;[\](),.{}:]/}}e.exports=t,t.displayName="n1ql",t.aliases=[]},70896(e){"use strict";function t(e){e.languages.n4js=e.languages.extend("javascript",{keyword:/\b(?:any|Array|boolean|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|module|new|null|number|package|private|protected|public|return|set|static|string|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/}),e.languages.insertBefore("n4js","constant",{annotation:{pattern:/@+\w+/,alias:"operator"}}),e.languages.n4jsd=e.languages.n4js}e.exports=t,t.displayName="n4js",t.aliases=["n4jsd"]},42242(e){"use strict";function t(e){e.languages["nand2tetris-hdl"]={comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,keyword:/\b(?:CHIP|IN|OUT|PARTS|BUILTIN|CLOCKED)\b/,boolean:/\b(?:true|false)\b/,function:/\b[A-Za-z][A-Za-z0-9]*(?=\()/,number:/\b\d+\b/,operator:/=|\.\./,punctuation:/[{}[\];(),:]/}}e.exports=t,t.displayName="nand2tetrisHdl",t.aliases=[]},37943(e){"use strict";function t(e){!function(e){var t=/\{[^\r\n\[\]{}]*\}/,n={"quoted-string":{pattern:/"(?:[^"\\]|\\.)*"/,alias:"operator"},"command-param-id":{pattern:/(\s)\w+:/,lookbehind:!0,alias:"property"},"command-param-value":[{pattern:t,alias:"selector"},{pattern:/([\t ])\S+/,lookbehind:!0,greedy:!0,alias:"operator"},{pattern:/\S(?:.*\S)?/,alias:"operator"}]};function r(e){for(var t="[]{}",n=[],r=0;r.+/m,alias:"tag",inside:{value:{pattern:/(^>\w+[\t ]+)(?!\s)[^{}\r\n]+/,lookbehind:!0,alias:"operator"},key:{pattern:/(^>)\w+/,lookbehind:!0}}},label:{pattern:/^([\t ]*)#[\t ]*\w+[\t ]*$/m,lookbehind:!0,alias:"regex"},command:{pattern:/^([\t ]*)@\w+(?=[\t ]|$).*/m,lookbehind:!0,alias:"function",inside:{"command-name":/^@\w+/,expression:{pattern:t,greedy:!0,alias:"selector"},"command-params":{pattern:/\s*\S[\s\S]*/,inside:n}}},"generic-text":{pattern:/(^[ \t]*)[^#@>;\s].*/m,lookbehind:!0,alias:"punctuation",inside:{"escaped-char":/\\[{}\[\]"]/,expression:{pattern:t,greedy:!0,alias:"selector"},"inline-command":{pattern:/\[[\t ]*\w[^\r\n\[\]]*\]/,greedy:!0,alias:"function",inside:{"command-params":{pattern:/(^\[[\t ]*\w+\b)[\s\S]+(?=\]$)/,lookbehind:!0,inside:n},"command-param-name":{pattern:/^(\[[\t ]*)\w+/,lookbehind:!0,alias:"name"},"start-stop-char":/[\[\]]/}}}}},e.languages.nani=e.languages.naniscript,e.hooks.add("after-tokenize",function(e){e.tokens.forEach(function(e){if("string"!=typeof e&&"generic-text"===e.type){var t=i(e);r(t)||(e.type="bad-line",e.content=t)}})})}(e)}e.exports=t,t.displayName="naniscript",t.aliases=[]},293(e){"use strict";function t(e){e.languages.nasm={comment:/;.*$/m,string:/(["'`])(?:\\.|(?!\1)[^\\\r\n])*\1/,label:{pattern:/(^\s*)[A-Za-z._?$][\w.?$@~#]*:/m,lookbehind:!0,alias:"function"},keyword:[/\[?BITS (?:16|32|64)\]?/,{pattern:/(^\s*)section\s*[a-z.]+:?/im,lookbehind:!0},/(?:extern|global)[^;\r\n]*/i,/(?:CPU|FLOAT|DEFAULT).*$/m],register:{pattern:/\b(?:st\d|[xyz]mm\d\d?|[cdt]r\d|r\d\d?[bwd]?|[er]?[abcd]x|[abcd][hl]|[er]?(?:bp|sp|si|di)|[cdefgs]s)\b/i,alias:"variable"},number:/(?:\b|(?=\$))(?:0[hx](?:\.[\da-f]+|[\da-f]+(?:\.[\da-f]+)?)(?:p[+-]?\d+)?|\d[\da-f]+[hx]|\$\d[\da-f]*|0[oq][0-7]+|[0-7]+[oq]|0[by][01]+|[01]+[by]|0[dt]\d+|(?:\d+(?:\.\d+)?|\.\d+)(?:\.?e[+-]?\d+)?[dt]?)\b/i,operator:/[\[\]*+\-\/%<>=&|$!]/}}e.exports=t,t.displayName="nasm",t.aliases=[]},83873(e){"use strict";function t(e){e.languages.neon={comment:{pattern:/#.*/,greedy:!0},datetime:{pattern:/(^|[[{(=:,\s])\d\d\d\d-\d\d?-\d\d?(?:(?:[Tt]| +)\d\d?:\d\d:\d\d(?:\.\d*)? *(?:Z|[-+]\d\d?(?::?\d\d)?)?)?(?=$|[\]}),\s])/,lookbehind:!0,alias:"number"},key:{pattern:/(^|[[{(,\s])[^,:=[\]{}()'"\s]+(?=\s*:(?:$|[\]}),\s])|\s*=)/,lookbehind:!0,alias:"atrule"},number:{pattern:/(^|[[{(=:,\s])[+-]?(?:0x[\da-fA-F]+|0o[0-7]+|0b[01]+|(?:\d+(?:\.\d*)?|\.?\d+)(?:[eE][+-]?\d+)?)(?=$|[\]}),:=\s])/,lookbehind:!0},boolean:{pattern:/(^|[[{(=:,\s])(?:true|false|yes|no)(?=$|[\]}),:=\s])/i,lookbehind:!0},null:{pattern:/(^|[[{(=:,\s])(?:null)(?=$|[\]}),:=\s])/i,lookbehind:!0,alias:"keyword"},string:{pattern:/(^|[[{(=:,\s])(?:('''|""")\r?\n(?:(?:[^\r\n]|\r?\n(?![\t ]*\2))*\r?\n)?[\t ]*\2|'[^'\r\n]*'|"(?:\\.|[^\\"\r\n])*")/,lookbehind:!0,greedy:!0},literal:{pattern:/(^|[[{(=:,\s])(?:[^#"',:=[\]{}()\s`-]|[:-][^"',=[\]{}()\s])(?:[^,:=\]})(\s]|:(?![\s,\]})]|$)|[ \t]+[^#,:=\]})(\s])*/,lookbehind:!0,alias:"string"},punctuation:/[,:=[\]{}()-]/}}e.exports=t,t.displayName="neon",t.aliases=[]},75932(e){"use strict";function t(e){e.languages.nevod={comment:/\/\/.*|(?:\/\*[\s\S]*?(?:\*\/|$))/,string:{pattern:/(?:"(?:""|[^"])*"(?!")|'(?:''|[^'])*'(?!'))!?\*?/,greedy:!0,inside:{"string-attrs":/!$|!\*$|\*$/}},namespace:{pattern:/(@namespace\s+)[a-zA-Z0-9\-.]+(?=\s*\{)/,lookbehind:!0},pattern:{pattern:/(@pattern\s+)?#?[a-zA-Z0-9\-.]+(?:\s*\(\s*(?:~\s*)?[a-zA-Z0-9\-.]+\s*(?:,\s*(?:~\s*)?[a-zA-Z0-9\-.]*)*\))?(?=\s*=)/,lookbehind:!0,inside:{"pattern-name":{pattern:/^#?[a-zA-Z0-9\-.]+/,alias:"class-name"},fields:{pattern:/\(.*\)/,inside:{"field-name":{pattern:/[a-zA-Z0-9\-.]+/,alias:"variable"},punctuation:/[,()]/,operator:{pattern:/~/,alias:"field-hidden-mark"}}}}},search:{pattern:/(@search\s+|#)[a-zA-Z0-9\-.]+(?:\.\*)?(?=\s*;)/,alias:"function",lookbehind:!0},keyword:/@(?:require|namespace|pattern|search|inside|outside|having|where)\b/,"standard-pattern":{pattern:/\b(?:Word|Punct|Symbol|Space|LineBreak|Start|End|Alpha|AlphaNum|Num|NumAlpha|Blank|WordBreak|Any)(?:\([a-zA-Z0-9\-.,\s+]*\))?/,inside:{"standard-pattern-name":{pattern:/^[a-zA-Z0-9\-.]+/,alias:"builtin"},quantifier:{pattern:/\b\d+(?:\s*\+|\s*-\s*\d+)?(?!\w)/,alias:"number"},"standard-pattern-attr":{pattern:/[a-zA-Z0-9\-.]+/,alias:"builtin"},punctuation:/[,()]/}},quantifier:{pattern:/\b\d+(?:\s*\+|\s*-\s*\d+)?(?!\w)/,alias:"number"},operator:[{pattern:/=/,alias:"pattern-def"},{pattern:/&/,alias:"conjunction"},{pattern:/~/,alias:"exception"},{pattern:/\?/,alias:"optionality"},{pattern:/[[\]]/,alias:"repetition"},{pattern:/[{}]/,alias:"variation"},{pattern:/[+_]/,alias:"sequence"},{pattern:/\.{2,3}/,alias:"span"}],"field-capture":[{pattern:/([a-zA-Z0-9\-.]+\s*\()\s*[a-zA-Z0-9\-.]+\s*:\s*[a-zA-Z0-9\-.]+(?:\s*,\s*[a-zA-Z0-9\-.]+\s*:\s*[a-zA-Z0-9\-.]+)*(?=\s*\))/,lookbehind:!0,inside:{"field-name":{pattern:/[a-zA-Z0-9\-.]+/,alias:"variable"},colon:/:/}},{pattern:/[a-zA-Z0-9\-.]+\s*:/,inside:{"field-name":{pattern:/[a-zA-Z0-9\-.]+/,alias:"variable"},colon:/:/}}],punctuation:/[:;,()]/,name:/[a-zA-Z0-9\-.]+/}}e.exports=t,t.displayName="nevod",t.aliases=[]},60221(e){"use strict";function t(e){var t,n;n=/\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i,(t=e).languages.nginx={comment:{pattern:/(^|[\s{};])#.*/,lookbehind:!0},directive:{pattern:/(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:{string:{pattern:/((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,lookbehind:!0,inside:{escape:{pattern:/\\["'\\nrt]/,alias:"entity"},variable:n}},comment:{pattern:/(\s)#.*/,lookbehind:!0,greedy:!0},keyword:{pattern:/^\S+/,greedy:!0},boolean:{pattern:/(\s)(?:off|on)(?!\S)/,lookbehind:!0},number:{pattern:/(\s)\d+[a-z]*(?!\S)/i,lookbehind:!0},variable:n}},punctuation:/[{};]/}}e.exports=t,t.displayName="nginx",t.aliases=[]},44188(e){"use strict";function t(e){e.languages.nim={comment:/#.*/,string:{pattern:/(?:(?:\b(?!\d)(?:\w|\\x[8-9a-fA-F][0-9a-fA-F])+)?(?:"""[\s\S]*?"""(?!")|"(?:\\[\s\S]|""|[^"\\])*")|'(?:\\(?:\d+|x[\da-fA-F]{2}|.)|[^'])')/,greedy:!0},number:/\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)(?:'?[iuf]\d*)?/,keyword:/\b(?:addr|as|asm|atomic|bind|block|break|case|cast|concept|const|continue|converter|defer|discard|distinct|do|elif|else|end|enum|except|export|finally|for|from|func|generic|if|import|include|interface|iterator|let|macro|method|mixin|nil|object|out|proc|ptr|raise|ref|return|static|template|try|tuple|type|using|var|when|while|with|without|yield)\b/,function:{pattern:/(?:(?!\d)(?:\w|\\x[8-9a-fA-F][0-9a-fA-F])+|`[^`\r\n]+`)\*?(?:\[[^\]]+\])?(?=\s*\()/,inside:{operator:/\*$/}},ignore:{pattern:/`[^`\r\n]+`/,inside:{punctuation:/`/}},operator:{pattern:/(^|[({\[](?=\.\.)|(?![({\[]\.).)(?:(?:[=+\-*\/<>@$~&%|!?^:\\]|\.\.|\.(?![)}\]]))+|\b(?:and|div|of|or|in|is|isnot|mod|not|notin|shl|shr|xor)\b)/m,lookbehind:!0},punctuation:/[({\[]\.|\.[)}\]]|[`(){}\[\],:]/}}e.exports=t,t.displayName="nim",t.aliases=[]},74426(e){"use strict";function t(e){e.languages.nix={comment:/\/\*[\s\S]*?\*\/|#.*/,string:{pattern:/"(?:[^"\\]|\\[\s\S])*"|''(?:(?!'')[\s\S]|''(?:'|\\|\$\{))*''/,greedy:!0,inside:{interpolation:{pattern:/(^|(?:^|(?!'').)[^\\])\$\{(?:[^{}]|\{[^}]*\})*\}/,lookbehind:!0,inside:{antiquotation:{pattern:/^\$(?=\{)/,alias:"variable"}}}}},url:[/\b(?:[a-z]{3,7}:\/\/)[\w\-+%~\/.:#=?&]+/,{pattern:/([^\/])(?:[\w\-+%~.:#=?&]*(?!\/\/)[\w\-+%~\/.:#=?&])?(?!\/\/)\/[\w\-+%~\/.:#=?&]*/,lookbehind:!0}],antiquotation:{pattern:/\$(?=\{)/,alias:"variable"},number:/\b\d+\b/,keyword:/\b(?:assert|builtins|else|if|in|inherit|let|null|or|then|with)\b/,function:/\b(?:abort|add|all|any|attrNames|attrValues|baseNameOf|compareVersions|concatLists|currentSystem|deepSeq|derivation|dirOf|div|elem(?:At)?|fetch(?:url|Tarball)|filter(?:Source)?|fromJSON|genList|getAttr|getEnv|hasAttr|hashString|head|import|intersectAttrs|is(?:Attrs|Bool|Function|Int|List|Null|String)|length|lessThan|listToAttrs|map|mul|parseDrvName|pathExists|read(?:Dir|File)|removeAttrs|replaceStrings|seq|sort|stringLength|sub(?:string)?|tail|throw|to(?:File|JSON|Path|String|XML)|trace|typeOf)\b|\bfoldl'\B/,boolean:/\b(?:true|false)\b/,operator:/[=!<>]=?|\+\+?|\|\||&&|\/\/|->?|[?@]/,punctuation:/[{}()[\].,:;]/},e.languages.nix.string.inside.interpolation.inside.rest=e.languages.nix}e.exports=t,t.displayName="nix",t.aliases=[]},88447(e){"use strict";function t(e){e.languages.nsis={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|[#;].*)/,lookbehind:!0},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},keyword:{pattern:/(^[\t ]*)(?:Abort|Add(?:BrandingImage|Size)|AdvSplash|Allow(?:RootDirInstall|SkipFiles)|AutoCloseWindow|Banner|BG(?:Font|Gradient|Image)|BrandingText|BringToFront|Call(?:InstDLL)?|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|Create(?:Directory|Font|ShortCut)|Delete(?:INISec|INIStr|RegKey|RegValue)?|Detail(?:Print|sButtonText)|Dialer|Dir(?:Text|Var|Verify)|EnableWindow|Enum(?:RegKey|RegValue)|Exch|Exec(?:Shell(?:Wait)?|Wait)?|ExpandEnvStrings|File(?:BufSize|Close|ErrorText|Open|Read|ReadByte|ReadUTF16LE|ReadWord|WriteUTF16LE|Seek|Write|WriteByte|WriteWord)?|Find(?:Close|First|Next|Window)|FlushINI|Get(?:CurInstType|CurrentAddress|DlgItem|DLLVersion(?:Local)?|ErrorLevel|FileTime(?:Local)?|FullPathName|Function(?:Address|End)?|InstDirError|LabelAddress|TempFileName)|Goto|HideWindow|Icon|If(?:Abort|Errors|FileExists|RebootFlag|Silent)|InitPluginsDir|Install(?:ButtonText|Colors|Dir(?:RegKey)?)|InstProgressFlags|Inst(?:Type(?:GetText|SetText)?)|Int(?:64|Ptr)?CmpU?|Int(?:64)?Fmt|Int(?:Ptr)?Op|IsWindow|Lang(?:DLL|String)|License(?:BkColor|Data|ForceSelection|LangString|Text)|LoadLanguageFile|LockWindow|Log(?:Set|Text)|Manifest(?:DPIAware|SupportedOS)|Math|MessageBox|MiscButtonText|Name|Nop|ns(?:Dialogs|Exec)|NSISdl|OutFile|Page(?:Callbacks)?|PE(?:DllCharacteristics|SubsysVer)|Pop|Push|Quit|Read(?:EnvStr|INIStr|RegDWORD|RegStr)|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|Section(?:End|GetFlags|GetInstTypes|GetSize|GetText|Group|In|SetFlags|SetInstTypes|SetSize|SetText)?|SendMessage|Set(?:AutoClose|BrandingImage|Compress|Compressor(?:DictSize)?|CtlColors|CurInstType|DatablockOptimize|DateSave|Details(?:Print|View)|ErrorLevel|Errors|FileAttributes|Font|OutPath|Overwrite|PluginUnload|RebootFlag|RegView|ShellVarContext|Silent)|Show(?:InstDetails|UninstDetails|Window)|Silent(?:Install|UnInstall)|Sleep|SpaceTexts|Splash|StartMenu|Str(?:CmpS?|Cpy|Len)|SubCaption|System|Unicode|Uninstall(?:ButtonText|Caption|Icon|SubCaption|Text)|UninstPage|UnRegDLL|UserInfo|Var|VI(?:AddVersionKey|FileVersion|ProductVersion)|VPatch|WindowIcon|Write(?:INIStr|Reg(?:Bin|DWORD|ExpandStr|MultiStr|None|Str)|Uninstaller)|XPStyle)\b/m,lookbehind:!0},property:/\b(?:admin|all|auto|both|colored|false|force|hide|highest|lastused|leave|listonly|none|normal|notset|off|on|open|print|show|silent|silentlog|smooth|textonly|true|user|ARCHIVE|FILE_(?:ATTRIBUTE_ARCHIVE|ATTRIBUTE_NORMAL|ATTRIBUTE_OFFLINE|ATTRIBUTE_READONLY|ATTRIBUTE_SYSTEM|ATTRIBUTE_TEMPORARY)|HK(?:(?:CR|CU|LM)(?:32|64)?|DD|PD|U)|HKEY_(?:CLASSES_ROOT|CURRENT_CONFIG|CURRENT_USER|DYN_DATA|LOCAL_MACHINE|PERFORMANCE_DATA|USERS)|ID(?:ABORT|CANCEL|IGNORE|NO|OK|RETRY|YES)|MB_(?:ABORTRETRYIGNORE|DEFBUTTON1|DEFBUTTON2|DEFBUTTON3|DEFBUTTON4|ICONEXCLAMATION|ICONINFORMATION|ICONQUESTION|ICONSTOP|OK|OKCANCEL|RETRYCANCEL|RIGHT|RTLREADING|SETFOREGROUND|TOPMOST|USERICON|YESNO)|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SYSTEM|TEMPORARY)\b/,constant:/\$\{[\w\.:\^-]+\}|\$\([\w\.:\^-]+\)/i,variable:/\$\w+/i,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|\+\+?|<=?|>=?|==?=?|&&?|\|\|?|[?*\/~^%]/,punctuation:/[{}[\];(),.:]/,important:{pattern:/(^[\t ]*)!(?:addincludedir|addplugindir|appendfile|cd|define|delfile|echo|else|endif|error|execute|finalize|getdllversion|gettlbversion|ifdef|ifmacrodef|ifmacrondef|ifndef|if|include|insertmacro|macroend|macro|makensis|packhdr|pragma|searchparse|searchreplace|system|tempfile|undef|verbose|warning)\b/im,lookbehind:!0}}}e.exports=t,t.displayName="nsis",t.aliases=[]},16032(e,t,n){"use strict";var r=n(65806);function i(e){e.register(r),e.languages.objectivec=e.languages.extend("c",{string:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|@"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,keyword:/\b(?:asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|in|self|super)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete e.languages.objectivec["class-name"],e.languages.objc=e.languages.objectivec}e.exports=i,i.displayName="objectivec",i.aliases=["objc"]},33607(e){"use strict";function t(e){e.languages.ocaml={comment:/\(\*[\s\S]*?\*\)/,string:[{pattern:/"(?:\\.|[^\\\r\n"])*"/,greedy:!0},{pattern:/(['`])(?:\\(?:\d+|x[\da-f]+|.)|(?!\1)[^\\\r\n])\1/i,greedy:!0}],number:/\b(?:0x[\da-f][\da-f_]+|(?:0[bo])?\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?[\d_]+)?)/i,directive:{pattern:/\B#\w+/,alias:"important"},label:{pattern:/\B~\w+/,alias:"function"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"variable"},module:{pattern:/\b[A-Z]\w+/,alias:"variable"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,operator:/:=|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/[(){}\[\]|.,:;]|\b_\b/}}e.exports=t,t.displayName="ocaml",t.aliases=[]},22001(e,t,n){"use strict";var r=n(65806);function i(e){var t,n;e.register(r),(t=e).languages.opencl=t.languages.extend("c",{keyword:/\b(?:__attribute__|(?:__)?(?:constant|global|kernel|local|private|read_only|read_write|write_only)|auto|break|case|complex|const|continue|default|do|(?:float|double)(?:16(?:x(?:1|16|2|4|8))?|1x(?:1|16|2|4|8)|2(?:x(?:1|16|2|4|8))?|3|4(?:x(?:1|16|2|4|8))?|8(?:x(?:1|16|2|4|8))?)?|else|enum|extern|for|goto|(?:u?(?:char|short|int|long)|half|quad|bool)(?:2|3|4|8|16)?|if|imaginary|inline|packed|pipe|register|restrict|return|signed|sizeof|static|struct|switch|typedef|uniform|union|unsigned|void|volatile|while)\b/,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[fuhl]{0,4}/i,boolean:/\b(?:false|true)\b/,"constant-opencl-kernel":{pattern:/\b(?:CHAR_(?:BIT|MAX|MIN)|CLK_(?:ADDRESS_(?:CLAMP(?:_TO_EDGE)?|NONE|REPEAT)|FILTER_(?:LINEAR|NEAREST)|(?:LOCAL|GLOBAL)_MEM_FENCE|NORMALIZED_COORDS_(?:FALSE|TRUE))|CL_(?:BGRA|(?:HALF_)?FLOAT|INTENSITY|LUMINANCE|A?R?G?B?[Ax]?|(?:(?:UN)?SIGNED|[US]NORM)_(?:INT(?:8|16|32))|UNORM_(?:INT_101010|SHORT_(?:555|565)))|(?:DBL|FLT|HALF)_(?:DIG|EPSILON|MANT_DIG|(?:MIN|MAX)(?:(?:_10)?_EXP)?)|FLT_RADIX|HUGE_VALF?|INFINITY|(?:INT|LONG|SCHAR|SHRT)_(?:MAX|MIN)|(?:UCHAR|USHRT|UINT|ULONG)_MAX|MAXFLOAT|M_(?:[12]_PI|2_SQRTPI|E|LN(?:2|10)|LOG(?:10|2)E?|PI(?:_[24])?|SQRT(?:1_2|2))(?:_F|_H)?|NAN)\b/,alias:"constant"}}),t.languages.insertBefore("opencl","class-name",{"builtin-type":{pattern:/\b(?:_cl_(?:command_queue|context|device_id|event|kernel|mem|platform_id|program|sampler)|cl_(?:image_format|mem_fence_flags)|clk_event_t|event_t|image(?:1d_(?:array_|buffer_)?t|2d_(?:array_(?:depth_|msaa_depth_|msaa_)?|depth_|msaa_depth_|msaa_)?t|3d_t)|intptr_t|ndrange_t|ptrdiff_t|queue_t|reserve_id_t|sampler_t|size_t|uintptr_t)\b/,alias:"keyword"}}),n={"type-opencl-host":{pattern:/\b(?:cl_(?:GLenum|GLint|GLuin|addressing_mode|bitfield|bool|buffer_create_type|build_status|channel_(?:order|type)|(?:u?(?:char|short|int|long)|float|double)(?:2|3|4|8|16)?|command_(?:queue(?:_info|_properties)?|type)|context(?:_info|_properties)?|device_(?:exec_capabilities|fp_config|id|info|local_mem_type|mem_cache_type|type)|(?:event|sampler)(?:_info)?|filter_mode|half|image_info|kernel(?:_info|_work_group_info)?|map_flags|mem(?:_flags|_info|_object_type)?|platform_(?:id|info)|profiling_info|program(?:_build_info|_info)?))\b/,alias:"keyword"},"boolean-opencl-host":{pattern:/\bCL_(?:TRUE|FALSE)\b/,alias:"boolean"},"constant-opencl-host":{pattern:/\bCL_(?:A|ABGR|ADDRESS_(?:CLAMP(?:_TO_EDGE)?|MIRRORED_REPEAT|NONE|REPEAT)|ARGB|BGRA|BLOCKING|BUFFER_CREATE_TYPE_REGION|BUILD_(?:ERROR|IN_PROGRESS|NONE|PROGRAM_FAILURE|SUCCESS)|COMMAND_(?:ACQUIRE_GL_OBJECTS|BARRIER|COPY_(?:BUFFER(?:_RECT|_TO_IMAGE)?|IMAGE(?:_TO_BUFFER)?)|FILL_(?:BUFFER|IMAGE)|MAP(?:_BUFFER|_IMAGE)|MARKER|MIGRATE(?:_SVM)?_MEM_OBJECTS|NATIVE_KERNEL|NDRANGE_KERNEL|READ_(?:BUFFER(?:_RECT)?|IMAGE)|RELEASE_GL_OBJECTS|SVM_(?:FREE|MAP|MEMCPY|MEMFILL|UNMAP)|TASK|UNMAP_MEM_OBJECT|USER|WRITE_(?:BUFFER(?:_RECT)?|IMAGE))|COMPILER_NOT_AVAILABLE|COMPILE_PROGRAM_FAILURE|COMPLETE|CONTEXT_(?:DEVICES|INTEROP_USER_SYNC|NUM_DEVICES|PLATFORM|PROPERTIES|REFERENCE_COUNT)|DEPTH(?:_STENCIL)?|DEVICE_(?:ADDRESS_BITS|AFFINITY_DOMAIN_(?:L[1-4]_CACHE|NEXT_PARTITIONABLE|NUMA)|AVAILABLE|BUILT_IN_KERNELS|COMPILER_AVAILABLE|DOUBLE_FP_CONFIG|ENDIAN_LITTLE|ERROR_CORRECTION_SUPPORT|EXECUTION_CAPABILITIES|EXTENSIONS|GLOBAL_(?:MEM_(?:CACHELINE_SIZE|CACHE_SIZE|CACHE_TYPE|SIZE)|VARIABLE_PREFERRED_TOTAL_SIZE)|HOST_UNIFIED_MEMORY|IL_VERSION|IMAGE(?:2D_MAX_(?:HEIGHT|WIDTH)|3D_MAX_(?:DEPTH|HEIGHT|WIDTH)|_BASE_ADDRESS_ALIGNMENT|_MAX_ARRAY_SIZE|_MAX_BUFFER_SIZE|_PITCH_ALIGNMENT|_SUPPORT)|LINKER_AVAILABLE|LOCAL_MEM_SIZE|LOCAL_MEM_TYPE|MAX_(?:CLOCK_FREQUENCY|COMPUTE_UNITS|CONSTANT_ARGS|CONSTANT_BUFFER_SIZE|GLOBAL_VARIABLE_SIZE|MEM_ALLOC_SIZE|NUM_SUB_GROUPS|ON_DEVICE_(?:EVENTS|QUEUES)|PARAMETER_SIZE|PIPE_ARGS|READ_IMAGE_ARGS|READ_WRITE_IMAGE_ARGS|SAMPLERS|WORK_GROUP_SIZE|WORK_ITEM_DIMENSIONS|WORK_ITEM_SIZES|WRITE_IMAGE_ARGS)|MEM_BASE_ADDR_ALIGN|MIN_DATA_TYPE_ALIGN_SIZE|NAME|NATIVE_VECTOR_WIDTH_(?:CHAR|DOUBLE|FLOAT|HALF|INT|LONG|SHORT)|NOT_(?:AVAILABLE|FOUND)|OPENCL_C_VERSION|PARENT_DEVICE|PARTITION_(?:AFFINITY_DOMAIN|BY_AFFINITY_DOMAIN|BY_COUNTS|BY_COUNTS_LIST_END|EQUALLY|FAILED|MAX_SUB_DEVICES|PROPERTIES|TYPE)|PIPE_MAX_(?:ACTIVE_RESERVATIONS|PACKET_SIZE)|PLATFORM|PREFERRED_(?:GLOBAL_ATOMIC_ALIGNMENT|INTEROP_USER_SYNC|LOCAL_ATOMIC_ALIGNMENT|PLATFORM_ATOMIC_ALIGNMENT|VECTOR_WIDTH_(?:CHAR|DOUBLE|FLOAT|HALF|INT|LONG|SHORT))|PRINTF_BUFFER_SIZE|PROFILE|PROFILING_TIMER_RESOLUTION|QUEUE_(?:ON_(?:DEVICE_(?:MAX_SIZE|PREFERRED_SIZE|PROPERTIES)|HOST_PROPERTIES)|PROPERTIES)|REFERENCE_COUNT|SINGLE_FP_CONFIG|SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS|SVM_(?:ATOMICS|CAPABILITIES|COARSE_GRAIN_BUFFER|FINE_GRAIN_BUFFER|FINE_GRAIN_SYSTEM)|TYPE(?:_ACCELERATOR|_ALL|_CPU|_CUSTOM|_DEFAULT|_GPU)?|VENDOR(?:_ID)?|VERSION)|DRIVER_VERSION|EVENT_(?:COMMAND_(?:EXECUTION_STATUS|QUEUE|TYPE)|CONTEXT|REFERENCE_COUNT)|EXEC_(?:KERNEL|NATIVE_KERNEL|STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST)|FILTER_(?:LINEAR|NEAREST)|FLOAT|FP_(?:CORRECTLY_ROUNDED_DIVIDE_SQRT|DENORM|FMA|INF_NAN|ROUND_TO_INF|ROUND_TO_NEAREST|ROUND_TO_ZERO|SOFT_FLOAT)|GLOBAL|HALF_FLOAT|IMAGE_(?:ARRAY_SIZE|BUFFER|DEPTH|ELEMENT_SIZE|FORMAT|FORMAT_MISMATCH|FORMAT_NOT_SUPPORTED|HEIGHT|NUM_MIP_LEVELS|NUM_SAMPLES|ROW_PITCH|SLICE_PITCH|WIDTH)|INTENSITY|INVALID_(?:ARG_INDEX|ARG_SIZE|ARG_VALUE|BINARY|BUFFER_SIZE|BUILD_OPTIONS|COMMAND_QUEUE|COMPILER_OPTIONS|CONTEXT|DEVICE|DEVICE_PARTITION_COUNT|DEVICE_QUEUE|DEVICE_TYPE|EVENT|EVENT_WAIT_LIST|GLOBAL_OFFSET|GLOBAL_WORK_SIZE|GL_OBJECT|HOST_PTR|IMAGE_DESCRIPTOR|IMAGE_FORMAT_DESCRIPTOR|IMAGE_SIZE|KERNEL|KERNEL_ARGS|KERNEL_DEFINITION|KERNEL_NAME|LINKER_OPTIONS|MEM_OBJECT|MIP_LEVEL|OPERATION|PIPE_SIZE|PLATFORM|PROGRAM|PROGRAM_EXECUTABLE|PROPERTY|QUEUE_PROPERTIES|SAMPLER|VALUE|WORK_DIMENSION|WORK_GROUP_SIZE|WORK_ITEM_SIZE)|KERNEL_(?:ARG_(?:ACCESS_(?:NONE|QUALIFIER|READ_ONLY|READ_WRITE|WRITE_ONLY)|ADDRESS_(?:CONSTANT|GLOBAL|LOCAL|PRIVATE|QUALIFIER)|INFO_NOT_AVAILABLE|NAME|TYPE_(?:CONST|NAME|NONE|PIPE|QUALIFIER|RESTRICT|VOLATILE))|ATTRIBUTES|COMPILE_NUM_SUB_GROUPS|COMPILE_WORK_GROUP_SIZE|CONTEXT|EXEC_INFO_SVM_FINE_GRAIN_SYSTEM|EXEC_INFO_SVM_PTRS|FUNCTION_NAME|GLOBAL_WORK_SIZE|LOCAL_MEM_SIZE|LOCAL_SIZE_FOR_SUB_GROUP_COUNT|MAX_NUM_SUB_GROUPS|MAX_SUB_GROUP_SIZE_FOR_NDRANGE|NUM_ARGS|PREFERRED_WORK_GROUP_SIZE_MULTIPLE|PRIVATE_MEM_SIZE|PROGRAM|REFERENCE_COUNT|SUB_GROUP_COUNT_FOR_NDRANGE|WORK_GROUP_SIZE)|LINKER_NOT_AVAILABLE|LINK_PROGRAM_FAILURE|LOCAL|LUMINANCE|MAP_(?:FAILURE|READ|WRITE|WRITE_INVALIDATE_REGION)|MEM_(?:ALLOC_HOST_PTR|ASSOCIATED_MEMOBJECT|CONTEXT|COPY_HOST_PTR|COPY_OVERLAP|FLAGS|HOST_NO_ACCESS|HOST_PTR|HOST_READ_ONLY|HOST_WRITE_ONLY|KERNEL_READ_AND_WRITE|MAP_COUNT|OBJECT_(?:ALLOCATION_FAILURE|BUFFER|IMAGE1D|IMAGE1D_ARRAY|IMAGE1D_BUFFER|IMAGE2D|IMAGE2D_ARRAY|IMAGE3D|PIPE)|OFFSET|READ_ONLY|READ_WRITE|REFERENCE_COUNT|SIZE|SVM_ATOMICS|SVM_FINE_GRAIN_BUFFER|TYPE|USES_SVM_POINTER|USE_HOST_PTR|WRITE_ONLY)|MIGRATE_MEM_OBJECT_(?:CONTENT_UNDEFINED|HOST)|MISALIGNED_SUB_BUFFER_OFFSET|NONE|NON_BLOCKING|OUT_OF_(?:HOST_MEMORY|RESOURCES)|PIPE_(?:MAX_PACKETS|PACKET_SIZE)|PLATFORM_(?:EXTENSIONS|HOST_TIMER_RESOLUTION|NAME|PROFILE|VENDOR|VERSION)|PROFILING_(?:COMMAND_(?:COMPLETE|END|QUEUED|START|SUBMIT)|INFO_NOT_AVAILABLE)|PROGRAM_(?:BINARIES|BINARY_SIZES|BINARY_TYPE(?:_COMPILED_OBJECT|_EXECUTABLE|_LIBRARY|_NONE)?|BUILD_(?:GLOBAL_VARIABLE_TOTAL_SIZE|LOG|OPTIONS|STATUS)|CONTEXT|DEVICES|IL|KERNEL_NAMES|NUM_DEVICES|NUM_KERNELS|REFERENCE_COUNT|SOURCE)|QUEUED|QUEUE_(?:CONTEXT|DEVICE|DEVICE_DEFAULT|ON_DEVICE|ON_DEVICE_DEFAULT|OUT_OF_ORDER_EXEC_MODE_ENABLE|PROFILING_ENABLE|PROPERTIES|REFERENCE_COUNT|SIZE)|R|RA|READ_(?:ONLY|WRITE)_CACHE|RG|RGB|RGBA|RGBx|RGx|RUNNING|Rx|SAMPLER_(?:ADDRESSING_MODE|CONTEXT|FILTER_MODE|LOD_MAX|LOD_MIN|MIP_FILTER_MODE|NORMALIZED_COORDS|REFERENCE_COUNT)|(?:UN)?SIGNED_INT(?:8|16|32)|SNORM_INT(?:8|16)|SUBMITTED|SUCCESS|UNORM_INT(?:16|24|8|_101010|_101010_2)|UNORM_SHORT_(?:555|565)|VERSION_(?:1_0|1_1|1_2|2_0|2_1)|sBGRA|sRGB|sRGBA|sRGBx)\b/,alias:"constant"},"function-opencl-host":{pattern:/\bcl(?:BuildProgram|CloneKernel|CompileProgram|Create(?:Buffer|CommandQueue(?:WithProperties)?|Context|ContextFromType|Image|Image2D|Image3D|Kernel|KernelsInProgram|Pipe|ProgramWith(?:Binary|BuiltInKernels|IL|Source)|Sampler|SamplerWithProperties|SubBuffer|SubDevices|UserEvent)|Enqueue(?:(?:Barrier|Marker)(?:WithWaitList)?|Copy(?:Buffer(?:Rect|ToImage)?|Image(?:ToBuffer)?)|(?:Fill|Map)(?:Buffer|Image)|MigrateMemObjects|NDRangeKernel|NativeKernel|(?:Read|Write)(?:Buffer(?:Rect)?|Image)|SVM(?:Free|Map|MemFill|Memcpy|MigrateMem|Unmap)|Task|UnmapMemObject|WaitForEvents)|Finish|Flush|Get(?:CommandQueueInfo|ContextInfo|Device(?:AndHostTimer|IDs|Info)|Event(?:Profiling)?Info|ExtensionFunctionAddress(?:ForPlatform)?|HostTimer|ImageInfo|Kernel(?:ArgInfo|Info|SubGroupInfo|WorkGroupInfo)|MemObjectInfo|PipeInfo|Platform(?:IDs|Info)|Program(?:Build)?Info|SamplerInfo|SupportedImageFormats)|LinkProgram|(?:Release|Retain)(?:CommandQueue|Context|Device|Event|Kernel|MemObject|Program|Sampler)|SVM(?:Alloc|Free)|Set(?:CommandQueueProperty|DefaultDeviceCommandQueue|EventCallback|Kernel(?:Arg(?:SVMPointer)?|ExecInfo)|Kernel|MemObjectDestructorCallback|UserEventStatus)|Unload(?:Platform)?Compiler|WaitForEvents)\b/,alias:"function"}},t.languages.insertBefore("c","keyword",n),t.languages.cpp&&(n["type-opencl-host-cpp"]={pattern:/\b(?:Buffer|BufferGL|BufferRenderGL|CommandQueue|Context|Device|DeviceCommandQueue|EnqueueArgs|Event|Image|Image1D|Image1DArray|Image1DBuffer|Image2D|Image2DArray|Image2DGL|Image3D|Image3DGL|ImageFormat|ImageGL|Kernel|KernelFunctor|LocalSpaceArg|Memory|NDRange|Pipe|Platform|Program|Sampler|SVMAllocator|SVMTraitAtomic|SVMTraitCoarse|SVMTraitFine|SVMTraitReadOnly|SVMTraitReadWrite|SVMTraitWriteOnly|UserEvent)\b/,alias:"keyword"},t.languages.insertBefore("cpp","keyword",n))}e.exports=i,i.displayName="opencl",i.aliases=[]},22950(e){"use strict";function t(e){e.languages.openqasm={comment:/\/\*[\s\S]*?\*\/|\/\/.*/,string:{pattern:/"[^"\r\n\t]*"|'[^'\r\n\t]*'/,greedy:!0},keyword:/\b(?:barrier|boxas|boxto|break|const|continue|ctrl|def|defcal|defcalgrammar|delay|else|end|for|gate|gphase|if|in|include|inv|kernel|lengthof|let|measure|pow|reset|return|rotary|stretchinf|while|CX|OPENQASM|U)\b|#pragma\b/,"class-name":/\b(?:angle|bit|bool|creg|fixed|float|int|length|qreg|qubit|stretch|uint)\b/,function:/\b(?:sin|cos|tan|exp|ln|sqrt|rotl|rotr|popcount)\b(?=\s*\()/,constant:/\b(?:pi|tau|euler)\b|π|𝜏|ℇ/,number:{pattern:/(^|[^.\w$])(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?(?:dt|ns|us|µs|ms|s)?/i,lookbehind:!0},operator:/->|>>=?|<<=?|&&|\|\||\+\+|--|[!=<>&|~^+\-*/%]=?|@/,punctuation:/[(){}\[\];,:.]/},e.languages.qasm=e.languages.openqasm}e.exports=t,t.displayName="openqasm",t.aliases=["qasm"]},23254(e){"use strict";function t(e){e.languages.oz={comment:/\/\*[\s\S]*?\*\/|%.*/,string:{pattern:/"(?:[^"\\]|\\[\s\S])*"/,greedy:!0},atom:{pattern:/'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,alias:"builtin"},keyword:/\$|\[\]|\b(?:_|at|attr|case|catch|choice|class|cond|declare|define|dis|else(?:case|if)?|end|export|fail|false|feat|finally|from|fun|functor|if|import|in|local|lock|meth|nil|not|of|or|prepare|proc|prop|raise|require|self|skip|then|thread|true|try|unit)\b/,function:[/\b[a-z][A-Za-z\d]*(?=\()/,{pattern:/(\{)[A-Z][A-Za-z\d]*\b/,lookbehind:!0}],number:/\b(?:0[bx][\da-f]+|\d+(?:\.\d*)?(?:e~?\d+)?)\b|&(?:[^\\]|\\(?:\d{3}|.))/i,variable:/\b[A-Z][A-Za-z\d]*|`(?:[^`\\]|\\.)+`/,"attr-name":/\b\w+(?=:)/,operator:/:(?:=|::?)|<[-:=]?|=(?:=|=?:?|\\=:?|!!?|[|#+\-*\/,~^@]|\b(?:andthen|div|mod|orelse)\b/,punctuation:/[\[\](){}.:;?]/}}e.exports=t,t.displayName="oz",t.aliases=[]},92694(e){"use strict";function t(e){var t;e.languages.parigp={comment:/\/\*[\s\S]*?\*\/|\\\\.*/,string:{pattern:/"(?:[^"\\\r\n]|\\.)*"/,greedy:!0},keyword:RegExp("\\b(?:"+(t=(t=["breakpoint","break","dbg_down","dbg_err","dbg_up","dbg_x","forcomposite","fordiv","forell","forpart","forprime","forstep","forsubgroup","forvec","for","iferr","if","local","my","next","return","until","while"]).map(function(e){return e.split("").join(" *")}).join("|"))+")\\b"),function:/\b\w(?:[\w ]*\w)?(?= *\()/,number:{pattern:/((?:\. *\. *)?)(?:\b\d(?: *\d)*(?: *(?!\. *\.)\.(?: *\d)*)?|\. *\d(?: *\d)*)(?: *e *(?:[+-] *)?\d(?: *\d)*)?/i,lookbehind:!0},operator:/\. *\.|[*\/!](?: *=)?|%(?: *=|(?: *#)?(?: *')*)?|\+(?: *[+=])?|-(?: *[-=>])?|<(?: *>|(?: *<)?(?: *=)?)?|>(?: *>)?(?: *=)?|=(?: *=){0,2}|\\(?: *\/)?(?: *=)?|&(?: *&)?|\| *\||['#~^]/,punctuation:/[\[\]{}().,:;|]/}}e.exports=t,t.displayName="parigp",t.aliases=[]},43273(e){"use strict";function t(e){var t,n;n=(t=e).languages.parser=t.languages.extend("markup",{keyword:{pattern:/(^|[^^])(?:\^(?:case|eval|for|if|switch|throw)\b|@(?:BASE|CLASS|GET(?:_DEFAULT)?|OPTIONS|SET_DEFAULT|USE)\b)/,lookbehind:!0},variable:{pattern:/(^|[^^])\B\$(?:\w+|(?=[.{]))(?:(?:\.|::?)\w+)*(?:\.|::?)?/,lookbehind:!0,inside:{punctuation:/\.|:+/}},function:{pattern:/(^|[^^])\B[@^]\w+(?:(?:\.|::?)\w+)*(?:\.|::?)?/,lookbehind:!0,inside:{keyword:{pattern:/(^@)(?:GET_|SET_)/,lookbehind:!0},punctuation:/\.|:+/}},escape:{pattern:/\^(?:[$^;@()\[\]{}"':]|#[a-f\d]*)/i,alias:"builtin"},punctuation:/[\[\](){};]/}),n=t.languages.insertBefore("parser","keyword",{"parser-comment":{pattern:/(\s)#.*/,lookbehind:!0,alias:"comment"},expression:{pattern:/(^|[^^])\((?:[^()]|\((?:[^()]|\((?:[^()])*\))*\))*\)/,greedy:!0,lookbehind:!0,inside:{string:{pattern:/(^|[^^])(["'])(?:(?!\2)[^^]|\^[\s\S])*\2/,lookbehind:!0},keyword:n.keyword,variable:n.variable,function:n.function,boolean:/\b(?:true|false)\b/,number:/\b(?:0x[a-f\d]+|\d+(?:\.\d*)?(?:e[+-]?\d+)?)\b/i,escape:n.escape,operator:/[~+*\/\\%]|!(?:\|\|?|=)?|&&?|\|\|?|==|<[<=]?|>[>=]?|-[fd]?|\b(?:def|eq|ge|gt|in|is|le|lt|ne)\b/,punctuation:n.punctuation}}}),t.languages.insertBefore("inside","punctuation",{expression:n.expression,keyword:n.keyword,variable:n.variable,function:n.function,escape:n.escape,"parser-punctuation":{pattern:n.punctuation,alias:"punctuation"}},n.tag.inside["attr-value"])}e.exports=t,t.displayName="parser",t.aliases=[]},60718(e){"use strict";function t(e){e.languages.pascal={comment:[/\(\*[\s\S]+?\*\)/,/\{[\s\S]+?\}/,/\/\/.*/],string:{pattern:/(?:'(?:''|[^'\r\n])*'(?!')|#[&$%]?[a-f\d]+)+|\^[a-z]/i,greedy:!0},keyword:[{pattern:/(^|[^&])\b(?:absolute|array|asm|begin|case|const|constructor|destructor|do|downto|else|end|file|for|function|goto|if|implementation|inherited|inline|interface|label|nil|object|of|operator|packed|procedure|program|record|reintroduce|repeat|self|set|string|then|to|type|unit|until|uses|var|while|with)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:dispose|exit|false|new|true)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:class|dispinterface|except|exports|finalization|finally|initialization|inline|library|on|out|packed|property|raise|resourcestring|threadvar|try)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:absolute|abstract|alias|assembler|bitpacked|break|cdecl|continue|cppdecl|cvar|default|deprecated|dynamic|enumerator|experimental|export|external|far|far16|forward|generic|helper|implements|index|interrupt|iochecks|local|message|name|near|nodefault|noreturn|nostackframe|oldfpccall|otherwise|overload|override|pascal|platform|private|protected|public|published|read|register|reintroduce|result|safecall|saveregisters|softfloat|specialize|static|stdcall|stored|strict|unaligned|unimplemented|varargs|virtual|write)\b/i,lookbehind:!0}],number:[/(?:[&%]\d+|\$[a-f\d]+)/i,/\b\d+(?:\.\d+)?(?:e[+-]?\d+)?/i],operator:[/\.\.|\*\*|:=|<[<=>]?|>[>=]?|[+\-*\/]=?|[@^=]/i,{pattern:/(^|[^&])\b(?:and|as|div|exclude|in|include|is|mod|not|or|shl|shr|xor)\b/,lookbehind:!0}],punctuation:/\(\.|\.\)|[()\[\]:;,.]/},e.languages.objectpascal=e.languages.pascal}e.exports=t,t.displayName="pascal",t.aliases=["objectpascal"]},39303(e){"use strict";function t(e){var t,n,r,i,a;t=e,n=/\((?:[^()]|\((?:[^()]|\([^()]*\))*\))*\)/.source,r=/(?:\b\w+(?:)?|)/.source.replace(//g,function(){return n}),i=t.languages.pascaligo={comment:/\(\*[\s\S]+?\*\)|\/\/.*/,string:{pattern:/(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1|\^[a-z]/i,greedy:!0},"class-name":[{pattern:RegExp(/(\btype\s+\w+\s+is\s+)/.source.replace(//g,function(){return r}),"i"),lookbehind:!0,inside:null},{pattern:RegExp(/(?=\s+is\b)/.source.replace(//g,function(){return r}),"i"),inside:null},{pattern:RegExp(/(:\s*)/.source.replace(//g,function(){return r})),lookbehind:!0,inside:null}],keyword:{pattern:/(^|[^&])\b(?:begin|block|case|const|else|end|fail|for|from|function|if|is|nil|of|remove|return|skip|then|type|var|while|with)\b/i,lookbehind:!0},boolean:{pattern:/(^|[^&])\b(?:True|False)\b/i,lookbehind:!0},builtin:{pattern:/(^|[^&])\b(?:bool|int|list|map|nat|record|string|unit)\b/i,lookbehind:!0},function:/\b\w+(?=\s*\()/i,number:[/%[01]+|&[0-7]+|\$[a-f\d]+/i,/\b\d+(?:\.\d+)?(?:e[+-]?\d+)?(?:mtz|n)?/i],operator:/->|=\/=|\.\.|\*\*|:=|<[<=>]?|>[>=]?|[+\-*\/]=?|[@^=|]|\b(?:and|mod|or)\b/,punctuation:/\(\.|\.\)|[()\[\]:;,.{}]/},a=["comment","keyword","builtin","operator","punctuation"].reduce(function(e,t){return e[t]=i[t],e},{}),i["class-name"].forEach(function(e){e.inside=a})}e.exports=t,t.displayName="pascaligo",t.aliases=[]},77393(e){"use strict";function t(e){e.languages.pcaxis={string:/"[^"]*"/,keyword:{pattern:/((?:^|;)\s*)[-A-Z\d]+(?:\s*\[[-\w]+\])?(?:\s*\("[^"]*"(?:,\s*"[^"]*")*\))?(?=\s*=)/,lookbehind:!0,greedy:!0,inside:{keyword:/^[-A-Z\d]+/,language:{pattern:/^(\s*)\[[-\w]+\]/,lookbehind:!0,inside:{punctuation:/^\[|\]$/,property:/[-\w]+/}},"sub-key":{pattern:/^(\s*)\S[\s\S]*/,lookbehind:!0,inside:{parameter:{pattern:/"[^"]*"/,alias:"property"},punctuation:/^\(|\)$|,/}}}},operator:/=/,tlist:{pattern:/TLIST\s*\(\s*\w+(?:(?:\s*,\s*"[^"]*")+|\s*,\s*"[^"]*"-"[^"]*")?\s*\)/,greedy:!0,inside:{function:/^TLIST/,property:{pattern:/^(\s*\(\s*)\w+/,lookbehind:!0},string:/"[^"]*"/,punctuation:/[(),]/,operator:/-/}},punctuation:/[;,]/,number:{pattern:/(^|\s)\d+(?:\.\d+)?(?!\S)/,lookbehind:!0},boolean:/YES|NO/},e.languages.px=e.languages.pcaxis}e.exports=t,t.displayName="pcaxis",t.aliases=["px"]},19023(e){"use strict";function t(e){e.languages.peoplecode={comment:RegExp([/\/\*[\s\S]*?\*\//.source,/\bREM[^;]*;/.source,/<\*(?:[^<*]|\*(?!>)|<(?!\*)|<\*(?:(?!\*>)[\s\S])*\*>)*\*>/.source,/\/\+[\s\S]*?\+\//.source].join("|")),string:{pattern:/'(?:''|[^'\r\n])*'(?!')|"(?:""|[^"\r\n])*"(?!")/,greedy:!0},variable:/%\w+/,"function-definition":{pattern:/((?:^|[^\w-])(?:function|method)\s+)\w+/i,lookbehind:!0,alias:"function"},"class-name":{pattern:/((?:^|[^-\w])(?:as|catch|class|component|create|extends|global|implements|instance|local|of|property|returns)\s+)\w+(?::\w+)*/i,lookbehind:!0,inside:{punctuation:/:/}},keyword:/\b(?:abstract|alias|as|catch|class|component|constant|create|declare|else|end-(?:class|evaluate|for|function|get|if|method|set|try|while)|evaluate|extends|for|function|get|global|implements|import|instance|if|library|local|method|null|of|out|peopleCode|private|program|property|protected|readonly|ref|repeat|returns?|set|step|then|throw|to|try|until|value|when(?:-other)?|while)\b/i,"operator-keyword":{pattern:/\b(?:and|not|or)\b/i,alias:"operator"},function:/[_a-z]\w*(?=\s*\()/i,boolean:/\b(?:false|true)\b/i,number:/\b\d+(?:\.\d+)?\b/,operator:/<>|[<>]=?|!=|\*\*|[-+*/|=@]/,punctuation:/[:.;,()[\]]/},e.languages.pcode=e.languages.peoplecode}e.exports=t,t.displayName="peoplecode",t.aliases=["pcode"]},74212(e){"use strict";function t(e){e.languages.perl={comment:[{pattern:/(^\s*)=\w[\s\S]*?=cut.*/m,lookbehind:!0},{pattern:/(^|[^\\$])#.*/,lookbehind:!0}],string:[{pattern:/\b(?:q|qq|qx|qw)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s+([a-zA-Z0-9])(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*\((?:[^()\\]|\\[\s\S])*\)/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*\{(?:[^{}\\]|\\[\s\S])*\}/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*\[(?:[^[\]\\]|\\[\s\S])*\]/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*<(?:[^<>\\]|\\[\s\S])*>/,greedy:!0},{pattern:/("|`)(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0},{pattern:/'(?:[^'\\\r\n]|\\.)*'/,greedy:!0}],regex:[{pattern:/\b(?:m|qr)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s+([a-zA-Z0-9])(?:(?!\1)[^\\]|\\[\s\S])*\1[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngc]*/,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s+([a-zA-Z0-9])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\((?:[^()\\]|\\[\s\S])*\)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\{(?:[^{}\\]|\\[\s\S])*\}\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\[(?:[^[\]\\]|\\[\s\S])*\]\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*<(?:[^<>\\]|\\[\s\S])*>\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/\/(?:[^\/\\\r\n]|\\.)*\/[msixpodualngc]*(?=\s*(?:$|[\r\n,.;})&|\-+*~<>!?^]|(?:lt|gt|le|ge|eq|ne|cmp|not|and|or|xor|x)\b))/,greedy:!0}],variable:[/[&*$@%]\{\^[A-Z]+\}/,/[&*$@%]\^[A-Z_]/,/[&*$@%]#?(?=\{)/,/[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+(?![\w$]))+(?:::)*/i,/[&*$@%]\d+/,/(?!%=)[$@%][!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/],filehandle:{pattern:/<(?![<=])\S*>|\b_\b/,alias:"symbol"},vstring:{pattern:/v\d+(?:\.\d+)*|\d+(?:\.\d+){2,}/,alias:"string"},function:{pattern:/sub \w+/i,inside:{keyword:/sub/}},keyword:/\b(?:any|break|continue|default|delete|die|do|else|elsif|eval|for|foreach|given|goto|if|last|local|my|next|our|package|print|redo|require|return|say|state|sub|switch|undef|unless|until|use|when|while)\b/,number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)\b/,operator:/-[rwxoRWXOezsfdlpSbctugkTBMAC]\b|\+[+=]?|-[-=>]?|\*\*?=?|\/\/?=?|=[=~>]?|~[~=]?|\|\|?=?|&&?=?|<(?:=>?|<=?)?|>>?=?|![~=]?|[%^]=?|\.(?:=|\.\.?)?|[\\?]|\bx(?:=|\b)|\b(?:lt|gt|le|ge|eq|ne|cmp|not|and|or|xor)\b/,punctuation:/[{}[\];(),:]/}}e.exports=t,t.displayName="perl",t.aliases=[]},5137(e,t,n){"use strict";var r=n(88262);function i(e){e.register(r),e.languages.insertBefore("php","variable",{this:/\$this\b/,global:/\$(?:_(?:SERVER|GET|POST|FILES|REQUEST|SESSION|ENV|COOKIE)|GLOBALS|HTTP_RAW_POST_DATA|argc|argv|php_errormsg|http_response_header)\b/,scope:{pattern:/\b[\w\\]+::/,inside:{keyword:/static|self|parent/,punctuation:/::|\\/}}})}e.exports=i,i.displayName="phpExtras",i.aliases=[]},88262(e,t,n){"use strict";var r=n(93205);function i(e){var t,n,i,a,o,s,u,c;e.register(r),n=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,i=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,o=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,s=/[{}\[\](),:;]/,(t=e).languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:n,variable:/\$+(?:\w+\b|(?=\{))/i,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:bool|int|float|string|object|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*[\w|]\|\s*)(?:null|false)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?[\w|]\|\s*)(?:null|false)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|iterable|(?:null|false)(?=\s*\|))\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:null|false)\b/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:i,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:o,punctuation:s},c=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:u={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:t.languages.php}}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:u}}],t.languages.insertBefore("php","variable",{string:c,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:n,string:c,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:i,number:a,operator:o,punctuation:s}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),t.hooks.add("before-tokenize",function(e){if(/<\?/.test(e.code)){var n=/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/gi;t.languages["markup-templating"].buildPlaceholders(e,"php",n)}}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"php")})}e.exports=i,i.displayName="php",i.aliases=[]},63632(e,t,n){"use strict";var r=n(88262),i=n(9858);function a(e){var t,n;e.register(r),e.register(i),n=/(?:\b[a-zA-Z]\w*|[|\\[\]])+/.source,(t=e).languages.phpdoc=t.languages.extend("javadoclike",{parameter:{pattern:RegExp("(@(?:global|param|property(?:-read|-write)?|var)\\s+(?:"+n+"\\s+)?)\\$\\w+"),lookbehind:!0}}),t.languages.insertBefore("phpdoc","keyword",{"class-name":[{pattern:RegExp("(@(?:global|package|param|property(?:-read|-write)?|return|subpackage|throws|var)\\s+)"+n),lookbehind:!0,inside:{keyword:/\b(?:callback|resource|boolean|integer|double|object|string|array|false|float|mixed|bool|null|self|true|void|int)\b/,punctuation:/[|\\[\]()]/}}]}),t.languages.javadoclike.addSupport("php",t.languages.phpdoc)}e.exports=a,a.displayName="phpdoc",a.aliases=[]},59149(e,t,n){"use strict";var r=n(11114);function i(e){var t,n,i,a;e.register(r),Array.isArray(i=(n=(t=e).languages.plsql=t.languages.extend("sql",{comment:[/\/\*[\s\S]*?\*\//,/--.*/]})).keyword)||(i=n.keyword=[i]),i.unshift(/\b(?:ACCESS|AGENT|AGGREGATE|ARRAY|ARROW|AT|ATTRIBUTE|AUDIT|AUTHID|BFILE_BASE|BLOB_BASE|BLOCK|BODY|BOTH|BOUND|BYTE|CALLING|CHAR_BASE|CHARSET(?:FORM|ID)|CLOB_BASE|COLAUTH|COLLECT|CLUSTERS?|COMPILED|COMPRESS|CONSTANT|CONSTRUCTOR|CONTEXT|CRASH|CUSTOMDATUM|DANGLING|DATE_BASE|DEFINE|DETERMINISTIC|DURATION|ELEMENT|EMPTY|EXCEPTIONS?|EXCLUSIVE|EXTERNAL|FINAL|FORALL|FORM|FOUND|GENERAL|HEAP|HIDDEN|IDENTIFIED|IMMEDIATE|INCLUDING|INCREMENT|INDICATOR|INDEXES|INDICES|INFINITE|INITIAL|ISOPEN|INSTANTIABLE|INTERFACE|INVALIDATE|JAVA|LARGE|LEADING|LENGTH|LIBRARY|LIKE[24C]|LIMITED|LONG|LOOP|MAP|MAXEXTENTS|MAXLEN|MEMBER|MINUS|MLSLABEL|MULTISET|NAME|NAN|NATIVE|NEW|NOAUDIT|NOCOMPRESS|NOCOPY|NOTFOUND|NOWAIT|NUMBER(?:_BASE)?|OBJECT|OCI(?:COLL|DATE|DATETIME|DURATION|INTERVAL|LOBLOCATOR|NUMBER|RAW|REF|REFCURSOR|ROWID|STRING|TYPE)|OFFLINE|ONLINE|ONLY|OPAQUE|OPERATOR|ORACLE|ORADATA|ORGANIZATION|ORL(?:ANY|VARY)|OTHERS|OVERLAPS|OVERRIDING|PACKAGE|PARALLEL_ENABLE|PARAMETERS?|PASCAL|PCTFREE|PIPE(?:LINED)?|PRAGMA|PRIOR|PRIVATE|RAISE|RANGE|RAW|RECORD|REF|REFERENCE|REM|REMAINDER|RESULT|RESOURCE|RETURNING|REVERSE|ROW(?:ID|NUM|TYPE)|SAMPLE|SB[124]|SEGMENT|SELF|SEPARATE|SEQUENCE|SHORT|SIZE(?:_T)?|SPARSE|SQL(?:CODE|DATA|NAME|STATE)|STANDARD|STATIC|STDDEV|STORED|STRING|STRUCT|STYLE|SUBMULTISET|SUBPARTITION|SUBSTITUTABLE|SUBTYPE|SUCCESSFUL|SYNONYM|SYSDATE|TABAUTH|TDO|THE|TIMEZONE_(?:ABBR|HOUR|MINUTE|REGION)|TRAILING|TRANSAC(?:TIONAL)?|TRUSTED|UB[124]|UID|UNDER|UNTRUSTED|VALIDATE|VALIST|VARCHAR2|VARIABLE|VARIANCE|VARRAY|VIEWS|VOID|WHENEVER|WRAPPED|ZONE)\b/i),Array.isArray(a=n.operator)||(a=n.operator=[a]),a.unshift(/:=/)}e.exports=i,i.displayName="plsql",i.aliases=[]},50256(e){"use strict";function t(e){e.languages.powerquery={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:\/\/).*)/,lookbehind:!0},"quoted-identifier":{pattern:/#"(?:[^"\r\n]|"")*"(?!")/,greedy:!0,alias:"variable"},string:{pattern:/"(?:[^"\r\n]|"")*"(?!")/,greedy:!0},constant:[/\bDay\.(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\b/,/\bTraceLevel\.(?:Critical|Error|Information|Verbose|Warning)\b/,/\bOccurrence\.(?:First|Last|All)\b/,/\bOrder\.(?:Ascending|Descending)\b/,/\bRoundingMode\.(?:AwayFromZero|Down|ToEven|TowardZero|Up)\b/,/\bMissingField\.(?:Error|Ignore|UseNull)\b/,/\bQuoteStyle\.(?:Csv|None)\b/,/\bJoinKind\.(?:Inner|LeftOuter|RightOuter|FullOuter|LeftAnti|RightAnti)\b/,/\bGroupKind\.(?:Global|Local)\b/,/\bExtraValues\.(?:List|Ignore|Error)\b/,/\bJoinAlgorithm\.(?:Dynamic|PairwiseHash|SortMerge|LeftHash|RightHash|LeftIndex|RightIndex)\b/,/\bJoinSide\.(?:Left|Right)\b/,/\bPrecision\.(?:Double|Decimal)\b/,/\bRelativePosition\.From(?:End|Start)\b/,/\bTextEncoding\.(?:Ascii|BigEndianUnicode|Unicode|Utf8|Utf16|Windows)\b/,/\b(?:Any|Binary|Date|DateTime|DateTimeZone|Duration|Int8|Int16|Int32|Int64|Function|List|Logical|None|Number|Record|Table|Text|Time)\.Type\b/,/\bnull\b/],boolean:/\b(?:true|false)\b/,keyword:/\b(?:and|as|each|else|error|if|in|is|let|meta|not|nullable|optional|or|otherwise|section|shared|then|try|type)\b|#(?:binary|date|datetime|datetimezone|duration|infinity|nan|sections|shared|table|time)\b/,function:{pattern:/(^|[^#\w.])(?!\d)[\w.]+(?=\s*\()/,lookbehind:!0},"data-type":{pattern:/\b(?:any|anynonnull|binary|date|datetime|datetimezone|duration|function|list|logical|none|number|record|table|text|time|type)\b/,alias:"variable"},number:{pattern:/\b0x[\da-f]+\b|(?:[+-]?(?:\b\d+\.)?\b\d+|[+-]\.\d+|(^|[^.])\B\.\d+)(?:e[+-]?\d+)?\b/i,lookbehind:!0},operator:/[-+*\/&?@^]|<(?:=>?|>)?|>=?|=>?|\.\.\.?/,punctuation:/[,;\[\](){}]/},e.languages.pq=e.languages.powerquery,e.languages.mscript=e.languages.powerquery}e.exports=t,t.displayName="powerquery",t.aliases=[]},61777(e){"use strict";function t(e){var t,n,r;(r=(n=(t=e).languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:{function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:{}}}},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:true|false)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(\W?)(?:!|-(?:eq|ne|gt|ge|lt|le|sh[lr]|not|b?(?:and|x?or)|(?:Not)?(?:Like|Match|Contains|In)|Replace|Join|is(?:Not)?|as)\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/}).string[0].inside).boolean=n.boolean,r.variable=n.variable,r.function.inside=n}e.exports=t,t.displayName="powershell",t.aliases=[]},3623(e){"use strict";function t(e){e.languages.processing=e.languages.extend("clike",{keyword:/\b(?:break|catch|case|class|continue|default|else|extends|final|for|if|implements|import|new|null|private|public|return|static|super|switch|this|try|void|while)\b/,operator:/<[<=]?|>[>=]?|&&?|\|\|?|[%?]|[!=+\-*\/]=?/}),e.languages.insertBefore("processing","number",{constant:/\b(?!XML\b)[A-Z][A-Z\d_]+\b/,type:{pattern:/\b(?:boolean|byte|char|color|double|float|int|[A-Z]\w*)\b/,alias:"variable"}}),e.languages.processing.function=/\b\w+(?=\s*\()/,e.languages.processing["class-name"].alias="variable"}e.exports=t,t.displayName="processing",t.aliases=[]},82707(e){"use strict";function t(e){e.languages.prolog={comment:[/%.+/,/\/\*[\s\S]*?\*\//],string:{pattern:/(["'])(?:\1\1|\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},builtin:/\b(?:fx|fy|xf[xy]?|yfx?)\b/,variable:/\b[A-Z_]\w*/,function:/\b[a-z]\w*(?:(?=\()|\/\d+)/,number:/\b\d+(?:\.\d*)?/,operator:/[:\\=><\-?*@\/;+^|!$.]+|\b(?:is|mod|not|xor)\b/,punctuation:/[(){}\[\],]/}}e.exports=t,t.displayName="prolog",t.aliases=[]},59338(e){"use strict";function t(e){var t,n,r;t=e,r=["sum","min","max","avg","group","stddev","stdvar","count","count_values","bottomk","topk","quantile"].concat(n=["on","ignoring","group_right","group_left","by","without"],["offset"]),t.languages.promql={comment:{pattern:/(^[ \t]*)#.*/m,lookbehind:!0},"vector-match":{pattern:RegExp("((?:"+n.join("|")+")\\s*)\\([^)]*\\)"),lookbehind:!0,inside:{"label-key":{pattern:/\b[^,]*\b/,alias:"attr-name"},punctuation:/[(),]/}},"context-labels":{pattern:/\{[^{}]*\}/,inside:{"label-key":{pattern:/\b[a-z_]\w*(?=\s*(?:=|![=~]))/,alias:"attr-name"},"label-value":{pattern:/(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0,alias:"attr-value"},punctuation:/\{|\}|=~?|![=~]|,/}},"context-range":[{pattern:/\[[\w\s:]+\]/,inside:{punctuation:/\[|\]|:/,"range-duration":{pattern:/\b(?:\d+(?:[smhdwy]|ms))+\b/i,alias:"number"}}},{pattern:/(\boffset\s+)\w+/,lookbehind:!0,inside:{"range-duration":{pattern:/\b(?:\d+(?:[smhdwy]|ms))+\b/i,alias:"number"}}}],keyword:RegExp("\\b(?:"+r.join("|")+")\\b","i"),function:/\b[a-z_]\w*(?=\s*\()/i,number:/[-+]?(?:(?:\b\d+(?:\.\d+)?|\B\.\d+)(?:e[-+]?\d+)?\b|\b(?:0x[0-9a-f]+|nan|inf)\b)/i,operator:/[\^*/%+-]|==|!=|<=|<|>=|>|\b(?:and|unless|or)\b/i,punctuation:/[{};()`,.[\]]/}}e.exports=t,t.displayName="promql",t.aliases=[]},56267(e){"use strict";function t(e){e.languages.properties={comment:/^[ \t]*[#!].*$/m,"attr-value":{pattern:/(^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?: *[=:] *(?! )| ))(?:\\(?:\r\n|[\s\S])|[^\\\r\n])+/m,lookbehind:!0},"attr-name":/^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?= *[=:]| )/m,punctuation:/[=:]/}}e.exports=t,t.displayName="properties",t.aliases=[]},98809(e){"use strict";function t(e){var t,n;n=/\b(?:double|float|[su]?int(?:32|64)|s?fixed(?:32|64)|bool|string|bytes)\b/,(t=e).languages.protobuf=t.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),t.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:n}},builtin:n,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}e.exports=t,t.displayName="protobuf",t.aliases=[]},37548(e){"use strict";function t(e){e.languages.psl={comment:{pattern:/#.*/,greedy:!0},string:{pattern:/"(?:\\.|[^\\"])*"/,greedy:!0,inside:{symbol:/\\[ntrbA-Z"\\]/}},"heredoc-string":{pattern:/<<<([a-zA-Z_]\w*)[\r\n](?:.*[\r\n])*?\1\b/,alias:"string",greedy:!0},keyword:/\b(?:__multi|__single|case|default|do|else|elsif|exit|export|for|foreach|function|if|last|line|local|next|requires|return|switch|until|while|word)\b/,constant:/\b(?:ALARM|CHART_ADD_GRAPH|CHART_DELETE_GRAPH|CHART_DESTROY|CHART_LOAD|CHART_PRINT|EOF|FALSE|False|false|NO|No|no|OFFLINE|OK|PSL_PROF_LOG|R_CHECK_HORIZ|R_CHECK_VERT|R_CLICKER|R_COLUMN|R_FRAME|R_ICON|R_LABEL|R_LABEL_CENTER|R_LIST_MULTIPLE|R_LIST_MULTIPLE_ND|R_LIST_SINGLE|R_LIST_SINGLE_ND|R_MENU|R_POPUP|R_POPUP_SCROLLED|R_RADIO_HORIZ|R_RADIO_VERT|R_ROW|R_SCALE_HORIZ|R_SCALE_VERT|R_SPINNER|R_TEXT_FIELD|R_TEXT_FIELD_LABEL|R_TOGGLE|TRIM_LEADING|TRIM_LEADING_AND_TRAILING|TRIM_REDUNDANT|TRIM_TRAILING|TRUE|True|true|VOID|WARN)\b/,variable:/\b(?:errno|exit_status|PslDebug)\b/,builtin:{pattern:/\b(?:acos|add_diary|annotate|annotate_get|asctime|asin|atan|atexit|ascii_to_ebcdic|batch_set|blackout|cat|ceil|chan_exists|change_state|close|code_cvt|cond_signal|cond_wait|console_type|convert_base|convert_date|convert_locale_date|cos|cosh|create|destroy_lock|dump_hist|date|destroy|difference|dget_text|dcget_text|ebcdic_to_ascii|encrypt|event_archive|event_catalog_get|event_check|event_query|event_range_manage|event_range_query|event_report|event_schedule|event_trigger|event_trigger2|execute|exists|exp|fabs|floor|fmod|full_discovery|file|fopen|ftell|fseek|grep|get_vars|getenv|get|get_chan_info|get_ranges|get_text|gethostinfo|getpid|getpname|history_get_retention|history|index|int|is_var|intersection|isnumber|internal|in_transition|join|kill|length|lines|lock|lock_info|log|loge|log10|matchline|msg_check|msg_get_format|msg_get_severity|msg_printf|msg_sprintf|ntharg|num_consoles|nthargf|nthline|nthlinef|num_bytes|print|proc_exists|process|popen|printf|pconfig|poplines|pow|PslExecute|PslFunctionCall|PslFunctionExists|PslSetOptions|random|read|readln|refresh_parameters|remote_check|remote_close|remote_event_query|remote_event_trigger|remote_file_send|remote_open|remove|replace|rindex|sec_check_priv|sec_store_get|sec_store_set|set_alarm_ranges|set_locale|share|sin|sinh|sleep|sopen|sqrt|srandom|subset|set|substr|system|sprintf|sort|snmp_agent_config|_snmp_debug|snmp_agent_stop|snmp_agent_start|snmp_h_set|snmp_h_get_next|snmp_h_get|snmp_set|snmp_walk|snmp_get_next|snmp_get|snmp_config|snmp_close|snmp_open|snmp_trap_receive|snmp_trap_ignore|snmp_trap_listen|snmp_trap_send|snmp_trap_raise_std_trap|snmp_trap_register_im|splitline|strcasecmp|str_repeat|trim|tail|tan|tanh|time|tmpnam|tolower|toupper|trace_psl_process|text_domain|unlock|unique|union|unset|va_arg|va_start|write)\b/,alias:"builtin-function"},"foreach-variable":{pattern:/(\bforeach\s+(?:(?:\w+\b|"(?:\\.|[^\\"])*")\s+){0,2})[_a-zA-Z]\w*(?=\s*\()/,lookbehind:!0,greedy:!0},function:{pattern:/\b[_a-z]\w*\b(?=\s*\()/i},number:/\b(?:0x[0-9a-f]+|[0-9]+(?:\.[0-9]+)?)\b/i,operator:/--|\+\+|&&=?|\|\|=?|<<=?|>>=?|[=!]~|[-+*/%&|^!=<>]=?|\.|[:?]/,punctuation:/[(){}\[\];,]/}}e.exports=t,t.displayName="psl",t.aliases=[]},82161(e){"use strict";function t(e){!function(e){e.languages.pug={comment:{pattern:/(^([\t ]*))\/\/.*(?:(?:\r?\n|\r)\2[\t ].+)*/m,lookbehind:!0},"multiline-script":{pattern:/(^([\t ]*)script\b.*\.[\t ]*)(?:(?:\r?\n|\r(?!\n))(?:\2[\t ].+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:e.languages.javascript},filter:{pattern:/(^([\t ]*)):.+(?:(?:\r?\n|\r(?!\n))(?:\2[\t ].+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"}}},"multiline-plain-text":{pattern:/(^([\t ]*)[\w\-#.]+\.[\t ]*)(?:(?:\r?\n|\r(?!\n))(?:\2[\t ].+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0},markup:{pattern:/(^[\t ]*)<.+/m,lookbehind:!0,inside:e.languages.markup},doctype:{pattern:/((?:^|\n)[\t ]*)doctype(?: .+)?/,lookbehind:!0},"flow-control":{pattern:/(^[\t ]*)(?:if|unless|else|case|when|default|each|while)\b(?: .+)?/m,lookbehind:!0,inside:{each:{pattern:/^each .+? in\b/,inside:{keyword:/\b(?:each|in)\b/,punctuation:/,/}},branch:{pattern:/^(?:if|unless|else|case|when|default|while)\b/,alias:"keyword"},rest:e.languages.javascript}},keyword:{pattern:/(^[\t ]*)(?:block|extends|include|append|prepend)\b.+/m,lookbehind:!0},mixin:[{pattern:/(^[\t ]*)mixin .+/m,lookbehind:!0,inside:{keyword:/^mixin/,function:/\w+(?=\s*\(|\s*$)/,punctuation:/[(),.]/}},{pattern:/(^[\t ]*)\+.+/m,lookbehind:!0,inside:{name:{pattern:/^\+\w+/,alias:"function"},rest:e.languages.javascript}}],script:{pattern:/(^[\t ]*script(?:(?:&[^(]+)?\([^)]+\))*[\t ]).+/m,lookbehind:!0,inside:e.languages.javascript},"plain-text":{pattern:/(^[\t ]*(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?[\t ]).+/m,lookbehind:!0},tag:{pattern:/(^[\t ]*)(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?:?/m,lookbehind:!0,inside:{attributes:[{pattern:/&[^(]+\([^)]+\)/,inside:e.languages.javascript},{pattern:/\([^)]+\)/,inside:{"attr-value":{pattern:/(=\s*(?!\s))(?:\{[^}]*\}|[^,)\r\n]+)/,lookbehind:!0,inside:e.languages.javascript},"attr-name":/[\w-]+(?=\s*!?=|\s*[,)])/,punctuation:/[!=(),]+/}}],punctuation:/:/,"attr-id":/#[\w\-]+/,"attr-class":/\.[\w\-]+/}},code:[{pattern:/(^[\t ]*(?:-|!?=)).+/m,lookbehind:!0,inside:e.languages.javascript}],punctuation:/[.\-!=|]+/};for(var t=/(^([\t ]*)):(?:(?:\r?\n|\r(?!\n))(?:\2[\t ].+|\s*?(?=\r?\n|\r)))+/.source,n=[{filter:"atpl",language:"twig"},{filter:"coffee",language:"coffeescript"},"ejs","handlebars","less","livescript","markdown",{filter:"sass",language:"scss"},"stylus"],r={},i=0,a=n.length;i",function(){return o.filter}),"m"),lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"},rest:e.languages[o.language]}})}e.languages.insertBefore("pug","filter",r)}(e)}e.exports=t,t.displayName="pug",t.aliases=[]},80625(e){"use strict";function t(e){var t,n;(t=e).languages.puppet={heredoc:[{pattern:/(@\("([^"\r\n\/):]+)"(?:\/[nrts$uL]*)?\).*(?:\r?\n|\r))(?:.*(?:\r?\n|\r(?!\n)))*?[ \t]*(?:\|[ \t]*)?(?:-[ \t]*)?\2/,lookbehind:!0,alias:"string",inside:{punctuation:/(?=\S).*\S(?= *$)/}},{pattern:/(@\(([^"\r\n\/):]+)(?:\/[nrts$uL]*)?\).*(?:\r?\n|\r))(?:.*(?:\r?\n|\r(?!\n)))*?[ \t]*(?:\|[ \t]*)?(?:-[ \t]*)?\2/,lookbehind:!0,greedy:!0,alias:"string",inside:{punctuation:/(?=\S).*\S(?= *$)/}},{pattern:/@\("?(?:[^"\r\n\/):]+)"?(?:\/[nrts$uL]*)?\)/,alias:"string",inside:{punctuation:{pattern:/(\().+?(?=\))/,lookbehind:!0}}}],"multiline-comment":{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0,greedy:!0,alias:"comment"},regex:{pattern:/((?:\bnode\s+|[~=\(\[\{,]\s*|[=+]>\s*|^\s*))\/(?:[^\/\\]|\\[\s\S])+\/(?:[imx]+\b|\B)/,lookbehind:!0,greedy:!0,inside:{"extended-regex":{pattern:/^\/(?:[^\/\\]|\\[\s\S])+\/[im]*x[im]*$/,inside:{comment:/#.*/}}}},comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},string:{pattern:/(["'])(?:\$\{(?:[^'"}]|(["'])(?:(?!\2)[^\\]|\\[\s\S])*\2)+\}|\$(?!\{)|(?!\1)[^\\$]|\\[\s\S])*\1/,greedy:!0,inside:{"double-quoted":{pattern:/^"[\s\S]*"$/,inside:{}}}},variable:{pattern:/\$(?:::)?\w+(?:::\w+)*/,inside:{punctuation:/::/}},"attr-name":/(?:\b\w+|\*)(?=\s*=>)/,function:[{pattern:/(\.)(?!\d)\w+/,lookbehind:!0},/\b(?:contain|debug|err|fail|include|info|notice|realize|require|tag|warning)\b|\b(?!\d)\w+(?=\()/],number:/\b(?:0x[a-f\d]+|\d+(?:\.\d+)?(?:e-?\d+)?)\b/i,boolean:/\b(?:true|false)\b/,keyword:/\b(?:application|attr|case|class|consumes|default|define|else|elsif|function|if|import|inherits|node|private|produces|type|undef|unless)\b/,datatype:{pattern:/\b(?:Any|Array|Boolean|Callable|Catalogentry|Class|Collection|Data|Default|Enum|Float|Hash|Integer|NotUndef|Numeric|Optional|Pattern|Regexp|Resource|Runtime|Scalar|String|Struct|Tuple|Type|Undef|Variant)\b/,alias:"symbol"},operator:/=[=~>]?|![=~]?|<(?:<\|?|[=~|-])?|>[>=]?|->?|~>|\|>?>?|[*\/%+?]|\b(?:and|in|or)\b/,punctuation:/[\[\]{}().,;]|:+/},n=[{pattern:/(^|[^\\])\$\{(?:[^'"{}]|\{[^}]*\}|(["'])(?:(?!\2)[^\\]|\\[\s\S])*\2)+\}/,lookbehind:!0,inside:{"short-variable":{pattern:/(^\$\{)(?!\w+\()(?:::)?\w+(?:::\w+)*/,lookbehind:!0,alias:"variable",inside:{punctuation:/::/}},delimiter:{pattern:/^\$/,alias:"variable"},rest:t.languages.puppet}},{pattern:/(^|[^\\])\$(?:::)?\w+(?:::\w+)*/,lookbehind:!0,alias:"variable",inside:{punctuation:/::/}}],t.languages.puppet.heredoc[0].inside.interpolation=n,t.languages.puppet.string.inside["double-quoted"].inside.interpolation=n}e.exports=t,t.displayName="puppet",t.aliases=[]},88393(e){"use strict";function t(e){var t,n,r;(t=e).languages.pure={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0},/#!.+/],"inline-lang":{pattern:/%<[\s\S]+?%>/,greedy:!0,inside:{lang:{pattern:/(^%< *)-\*-.+?-\*-/,lookbehind:!0,alias:"comment"},delimiter:{pattern:/^%<.*|%>$/,alias:"punctuation"}}},string:{pattern:/"(?:\\.|[^"\\\r\n])*"/,greedy:!0},number:{pattern:/((?:\.\.)?)(?:\b(?:inf|nan)\b|\b0x[\da-f]+|(?:\b(?:0b)?\d+(?:\.\d+)?|\B\.\d+)(?:e[+-]?\d+)?L?)/i,lookbehind:!0},keyword:/\b(?:ans|break|bt|case|catch|cd|clear|const|def|del|dump|else|end|exit|extern|false|force|help|if|infix[lr]?|interface|let|ls|mem|namespace|nonfix|NULL|of|otherwise|outfix|override|postfix|prefix|private|public|pwd|quit|run|save|show|stats|then|throw|trace|true|type|underride|using|when|with)\b/,function:/\b(?:abs|add_(?:(?:fundef|interface|macdef|typedef)(?:_at)?|addr|constdef|vardef)|all|any|applp?|arity|bigintp?|blob(?:_crc|_size|p)?|boolp?|byte_(?:matrix|pointer)|byte_c?string(?:_pointer)?|calloc|cat|catmap|ceil|char[ps]?|check_ptrtag|chr|clear_sentry|clearsym|closurep?|cmatrixp?|cols?|colcat(?:map)?|colmap|colrev|colvector(?:p|seq)?|complex(?:_float_(?:matrix|pointer)|_matrix(?:_view)?|_pointer|p)?|conj|cookedp?|cst|cstring(?:_(?:dup|list|vector))?|curry3?|cyclen?|del_(?:constdef|fundef|interface|macdef|typedef|vardef)|delete|diag(?:mat)?|dim|dmatrixp?|do|double(?:_matrix(?:_view)?|_pointer|p)?|dowith3?|drop|dropwhile|eval(?:cmd)?|exactp|filter|fix|fixity|flip|float(?:_matrix|_pointer)|floor|fold[lr]1?|frac|free|funp?|functionp?|gcd|get(?:_(?:byte|constdef|double|float|fundef|int(?:64)?|interface(?:_typedef)?|long|macdef|pointer|ptrtag|short|sentry|string|typedef|vardef))?|globsym|hash|head|id|im|imatrixp?|index|inexactp|infp|init|insert|int(?:_matrix(?:_view)?|_pointer|p)?|int64_(?:matrix|pointer)|integerp?|iteraten?|iterwhile|join|keys?|lambdap?|last(?:err(?:pos)?)?|lcd|list[2p]?|listmap|make_ptrtag|malloc|map|matcat|matrixp?|max|member|min|nanp|nargs|nmatrixp?|null|numberp?|ord|pack(?:ed)?|pointer(?:_cast|_tag|_type|p)?|pow|pred|ptrtag|put(?:_(?:byte|double|float|int(?:64)?|long|pointer|short|string))?|rationalp?|re|realp?|realloc|recordp?|redim|reduce(?:_with)?|refp?|repeatn?|reverse|rlistp?|round|rows?|rowcat(?:map)?|rowmap|rowrev|rowvector(?:p|seq)?|same|scan[lr]1?|sentry|sgn|short_(?:matrix|pointer)|slice|smatrixp?|sort|split|str|strcat|stream|stride|string(?:_(?:dup|list|vector)|p)?|subdiag(?:mat)?|submat|subseq2?|substr|succ|supdiag(?:mat)?|symbolp?|tail|take|takewhile|thunkp?|transpose|trunc|tuplep?|typep|ubyte|uint(?:64)?|ulong|uncurry3?|unref|unzip3?|update|ushort|vals?|varp?|vector(?:p|seq)?|void|zip3?|zipwith3?)\b/,special:{pattern:/\b__[a-z]+__\b/i,alias:"builtin"},operator:/(?:[!"#$%&'*+,\-.\/:<=>?@\\^`|~\u00a1-\u00bf\u00d7-\u00f7\u20d0-\u2bff]|\b_+\b)+|\b(?:and|div|mod|not|or)\b/,punctuation:/[(){}\[\];,|]/},r=/%< *-\*- *\d* *-\*-[\s\S]+?%>/.source,(n=["c",{lang:"c++",alias:"cpp"},"fortran"]).forEach(function(e){var n=e;if("string"!=typeof e&&(n=e.alias,e=e.lang),t.languages[n]){var i={};i["inline-lang-"+n]={pattern:RegExp(r.replace("",e.replace(/([.+*?\/\\(){}\[\]])/g,"\\$1")),"i"),inside:t.util.clone(t.languages.pure["inline-lang"].inside)},i["inline-lang-"+n].inside.rest=t.util.clone(t.languages[n]),t.languages.insertBefore("pure","inline-lang",i)}}),t.languages.c&&(t.languages.pure["inline-lang"].inside.rest=t.util.clone(t.languages.c))}e.exports=t,t.displayName="pure",t.aliases=[]},78404(e){"use strict";function t(e){e.languages.purebasic=e.languages.extend("clike",{comment:/;.*/,keyword:/\b(?:declarecdll|declaredll|compilerselect|compilercase|compilerdefault|compilerendselect|compilererror|enableexplicit|disableexplicit|not|and|or|xor|calldebugger|debuglevel|enabledebugger|disabledebugger|restore|read|includepath|includebinary|threaded|runtime|with|endwith|structureunion|endstructureunion|align|newlist|newmap|interface|endinterface|extends|enumeration|endenumeration|swap|foreach|continue|fakereturn|goto|gosub|return|break|module|endmodule|declaremodule|enddeclaremodule|declare|declarec|prototype|prototypec|enableasm|disableasm|dim|redim|data|datasection|enddatasection|to|procedurereturn|debug|default|case|select|endselect|as|import|endimport|importc|compilerif|compilerelse|compilerendif|compilerelseif|end|structure|endstructure|while|wend|for|next|step|if|else|elseif|endif|repeat|until|procedure|proceduredll|procedurec|procedurecdll|endprocedure|protected|shared|static|global|define|includefile|xincludefile|macro|endmacro)\b/i,function:/\b\w+(?:\.\w+)?\s*(?=\()/,number:/(?:\$[\da-f]+|\b-?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)\b/i,operator:/(?:@\*?|\?|\*)\w+|-[>-]?|\+\+?|!=?|<>?=?|==?|&&?|\|?\||[~^%?*/@]/}),e.languages.insertBefore("purebasic","keyword",{tag:/#\w+/,asm:{pattern:/(^[\t ]*)!.*/m,lookbehind:!0,alias:"tag",inside:{comment:/;.*/,string:{pattern:/(["'`])(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},"label-reference-anonymous":{pattern:/(!\s*j[a-z]+\s+)@[fb]/i,lookbehind:!0,alias:"fasm-label"},"label-reference-addressed":{pattern:/(!\s*j[a-z]+\s+)[A-Z._?$@][\w.?$@~#]*/i,lookbehind:!0,alias:"fasm-label"},function:{pattern:/^([\t ]*!\s*)[\da-z]+(?=\s|$)/im,lookbehind:!0},"function-inline":{pattern:/(:\s*)[\da-z]+(?=\s)/i,lookbehind:!0,alias:"function"},label:{pattern:/^([\t ]*!\s*)[A-Za-z._?$@][\w.?$@~#]*(?=:)/m,lookbehind:!0,alias:"fasm-label"},keyword:[/\b(?:extern|global)\b[^;\r\n]*/i,/\b(?:CPU|FLOAT|DEFAULT)\b.*/],register:/\b(?:st\d|[xyz]mm\d\d?|[cdt]r\d|r\d\d?[bwd]?|[er]?[abcd]x|[abcd][hl]|[er]?(?:bp|sp|si|di)|[cdefgs]s|mm\d+)\b/i,number:/(?:\b|-|(?=\$))(?:0[hx](?:[\da-f]*\.)?[\da-f]+(?:p[+-]?\d+)?|\d[\da-f]+[hx]|\$\d[\da-f]*|0[oq][0-7]+|[0-7]+[oq]|0[by][01]+|[01]+[by]|0[dt]\d+|(?:\d+(?:\.\d+)?|\.\d+)(?:\.?e[+-]?\d+)?[dt]?)\b/i,operator:/[\[\]*+\-/%<>=&|$!,.:]/}}}),delete e.languages.purebasic["class-name"],delete e.languages.purebasic.boolean,e.languages.pbfasm=e.languages.purebasic}e.exports=t,t.displayName="purebasic",t.aliases=[]},92923(e,t,n){"use strict";var r=n(58090);function i(e){e.register(r),e.languages.purescript=e.languages.extend("haskell",{keyword:/\b(?:ado|case|class|data|derive|do|else|forall|if|in|infixl|infixr|instance|let|module|newtype|of|primitive|then|type|where)\b/,"import-statement":{pattern:/(^[\t ]*)import\s+[A-Z][\w']*(?:\.[A-Z][\w']*)*(?:\s+as\s+[A-Z][\w']*(?:\.[A-Z][\w']*)*)?(?:\s+hiding\b)?/m,lookbehind:!0,inside:{keyword:/\b(?:import|as|hiding)\b/}},builtin:/\b(?:absurd|add|ap|append|apply|between|bind|bottom|clamp|compare|comparing|compose|conj|const|degree|discard|disj|div|eq|flap|flip|gcd|identity|ifM|join|lcm|liftA1|liftM1|map|max|mempty|min|mod|mul|negate|not|notEq|one|otherwise|recip|show|sub|top|unit|unless|unlessM|void|when|whenM|zero)\b/}),e.languages.purs=e.languages.purescript}e.exports=i,i.displayName="purescript",i.aliases=["purs"]},52992(e){"use strict";function t(e){e.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},"string-interpolation":{pattern:/(?:f|rf|fr)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|rb|br)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|rb|br)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/im,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:True|False|None)\b/,number:/(?:\b(?=\d)|\B(?=\.))(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},e.languages.python["string-interpolation"].inside.interpolation.inside.rest=e.languages.python,e.languages.py=e.languages.python}e.exports=t,t.displayName="python",t.aliases=["py"]},55762(e){"use strict";function t(e){e.languages.q={string:/"(?:\\.|[^"\\\r\n])*"/,comment:[{pattern:/([\t )\]}])\/.*/,lookbehind:!0,greedy:!0},{pattern:/(^|\r?\n|\r)\/[\t ]*(?:(?:\r?\n|\r)(?:.*(?:\r?\n|\r(?!\n)))*?(?:\\(?=[\t ]*(?:\r?\n|\r))|$)|\S.*)/,lookbehind:!0,greedy:!0},{pattern:/^\\[\t ]*(?:\r?\n|\r)[\s\S]+/m,greedy:!0},{pattern:/^#!.+/m,greedy:!0}],symbol:/`(?::\S+|[\w.]*)/,datetime:{pattern:/0N[mdzuvt]|0W[dtz]|\d{4}\.\d\d(?:m|\.\d\d(?:T(?:\d\d(?::\d\d(?::\d\d(?:[.:]\d\d\d)?)?)?)?)?[dz]?)|\d\d:\d\d(?::\d\d(?:[.:]\d\d\d)?)?[uvt]?/,alias:"number"},number:/\b(?![01]:)(?:0[wn]|0W[hj]?|0N[hje]?|0x[\da-fA-F]+|\d+(?:\.\d*)?(?:e[+-]?\d+)?[hjfeb]?)/,keyword:/\\\w+\b|\b(?:abs|acos|aj0?|all|and|any|asc|asin|asof|atan|attr|avgs?|binr?|by|ceiling|cols|cor|cos|count|cov|cross|csv|cut|delete|deltas|desc|dev|differ|distinct|div|do|dsave|ej|enlist|eval|except|exec|exit|exp|fby|fills|first|fkeys|flip|floor|from|get|getenv|group|gtime|hclose|hcount|hdel|hopen|hsym|iasc|identity|idesc|if|ij|in|insert|inter|inv|keys?|last|like|list|ljf?|load|log|lower|lsq|ltime|ltrim|mavg|maxs?|mcount|md5|mdev|med|meta|mins?|mmax|mmin|mmu|mod|msum|neg|next|not|null|or|over|parse|peach|pj|plist|prds?|prev|prior|rand|rank|ratios|raze|read0|read1|reciprocal|reval|reverse|rload|rotate|rsave|rtrim|save|scan|scov|sdev|select|set|setenv|show|signum|sin|sqrt|ssr?|string|sublist|sums?|sv|svar|system|tables|tan|til|trim|txf|type|uj|ungroup|union|update|upper|upsert|value|var|views?|vs|wavg|where|while|within|wj1?|wsum|ww|xasc|xbar|xcols?|xdesc|xexp|xgroup|xkey|xlog|xprev|xrank)\b/,adverb:{pattern:/['\/\\]:?|\beach\b/,alias:"function"},verb:{pattern:/(?:\B\.\B|\b[01]:|<[=>]?|>=?|[:+\-*%,!?~=|$&#@^]):?|\b_\b:?/,alias:"operator"},punctuation:/[(){}\[\];.]/}}e.exports=t,t.displayName="q",t.aliases=[]},4137(e){"use strict";function t(e){!function(e){for(var t=/"(?:\\.|[^\\"\r\n])*"|'(?:\\.|[^\\'\r\n])*'/.source,n=/\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))*\*\//.source,r=/(?:[^\\()[\]{}"'/]||\/(?![*/])||\(*\)|\[*\]|\{*\}|\\[\s\S])/.source.replace(//g,function(){return t}).replace(//g,function(){return n}),i=0;i<2;i++)r=r.replace(//g,function(){return r});r=r.replace(//g,"[^\\s\\S]"),e.languages.qml={comment:{pattern:/\/\/.*|\/\*[\s\S]*?\*\//,greedy:!0},"javascript-function":{pattern:RegExp(/((?:^|;)[ \t]*)function\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*\(*\)\s*\{*\}/.source.replace(//g,function(){return r}),"m"),lookbehind:!0,greedy:!0,alias:"language-javascript",inside:e.languages.javascript},"class-name":{pattern:/((?:^|[:;])[ \t]*)(?!\d)\w+(?=[ \t]*\{|[ \t]+on\b)/m,lookbehind:!0},property:[{pattern:/((?:^|[;{])[ \t]*)(?!\d)\w+(?:\.\w+)*(?=[ \t]*:)/m,lookbehind:!0},{pattern:/((?:^|[;{])[ \t]*)property[ \t]+(?!\d)\w+(?:\.\w+)*[ \t]+(?!\d)\w+(?:\.\w+)*(?=[ \t]*:)/m,lookbehind:!0,inside:{keyword:/^property/,property:/\w+(?:\.\w+)*/}}],"javascript-expression":{pattern:RegExp(/(:[ \t]*)(?![\s;}[])(?:(?!$|[;}]))+/.source.replace(//g,function(){return r}),"m"),lookbehind:!0,greedy:!0,alias:"language-javascript",inside:e.languages.javascript},string:/"(?:\\.|[^\\"\r\n])*"/,keyword:/\b(?:as|import|on)\b/,punctuation:/[{}[\]:;,]/}}(e)}e.exports=t,t.displayName="qml",t.aliases=[]},28260(e){"use strict";function t(e){e.languages.qore=e.languages.extend("clike",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:\/\/|#).*)/,lookbehind:!0},string:{pattern:/("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0},keyword:/\b(?:abstract|any|assert|binary|bool|boolean|break|byte|case|catch|char|class|code|const|continue|data|default|do|double|else|enum|extends|final|finally|float|for|goto|hash|if|implements|import|inherits|instanceof|int|interface|long|my|native|new|nothing|null|object|our|own|private|reference|rethrow|return|short|soft(?:int|float|number|bool|string|date|list)|static|strictfp|string|sub|super|switch|synchronized|this|throw|throws|transient|try|void|volatile|while)\b/,boolean:/\b(?:true|false)\b/i,function:/\$?\b(?!\d)\w+(?=\()/,number:/\b(?:0b[01]+|0x(?:[\da-f]*\.)?[\da-fp\-]+|(?:\d+(?:\.\d+)?|\.\d+)(?:e\d+)?[df]|(?:\d+(?:\.\d+)?|\.\d+))\b/i,operator:{pattern:/(^|[^.])(?:\+[+=]?|-[-=]?|[!=](?:==?|~)?|>>?=?|<(?:=>?|<=?)?|&[&=]?|\|[|=]?|[*\/%^]=?|[~?])/,lookbehind:!0},variable:/\$(?!\d)\w+\b/})}e.exports=t,t.displayName="qore",t.aliases=[]},71360(e){"use strict";function t(e){!function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,function(e,n){return"(?:"+t[+n]+")"})}function n(e,n,r){return RegExp(t(e,n),r||"")}function r(e,t){for(var n=0;n>/g,function(){return"(?:"+e+")"});return e.replace(/<>/g,"[^\\s\\S]")}var i={type:"Adj BigInt Bool Ctl Double false Int One Pauli PauliI PauliX PauliY PauliZ Qubit Range Result String true Unit Zero",other:"Adjoint adjoint apply as auto body borrow borrowing Controlled controlled distribute elif else fail fixup for function if in internal intrinsic invert is let mutable namespace new newtype open operation repeat return self set until use using while within"};function a(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var o=RegExp(a(i.type+" "+i.other)),s=/\b[A-Za-z_]\w*\b/.source,u=t(/<<0>>(?:\s*\.\s*<<0>>)*/.source,[s]),c={keyword:o,punctuation:/[<>()?,.:[\]]/},l=/"(?:\\.|[^\\"])*"/.source;e.languages.qsharp=e.languages.extend("clike",{comment:/\/\/.*/,string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[l]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\b(?:as|open)\s+)<<0>>(?=\s*(?:;|as\b))/.source,[u]),lookbehind:!0,inside:c},{pattern:n(/(\bnamespace\s+)<<0>>(?=\s*\{)/.source,[u]),lookbehind:!0,inside:c}],keyword:o,number:/(?:\b0(?:x[\da-f]+|b[01]+|o[0-7]+)|(?:\B\.\d+|\b\d+(?:\.\d*)?)(?:e[-+]?\d+)?)l?\b/i,operator:/\band=|\bor=|\band\b|\bor\b|\bnot\b|<[-=]|[-=]>|>>>=?|<<<=?|\^\^\^=?|\|\|\|=?|&&&=?|w\/=?|~~~|[*\/+\-^=!%]=?/,punctuation:/::|[{}[\];(),.:]/}),e.languages.insertBefore("qsharp","number",{range:{pattern:/\.\./,alias:"operator"}});var f=r(t(/\{(?:[^"{}]|<<0>>|<>)*\}/.source,[l]),2);e.languages.insertBefore("qsharp","string",{"interpolation-string":{pattern:n(/\$"(?:\\.|<<0>>|[^\\"{])*"/.source,[f]),greedy:!0,inside:{interpolation:{pattern:n(/((?:^|[^\\])(?:\\\\)*)<<0>>/.source,[f]),lookbehind:!0,inside:{punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-qsharp",inside:e.languages.qsharp}}},string:/[\s\S]+/}}})}(e),e.languages.qs=e.languages.qsharp}e.exports=t,t.displayName="qsharp",t.aliases=["qs"]},29308(e){"use strict";function t(e){e.languages.r={comment:/#.*/,string:{pattern:/(['"])(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},"percent-operator":{pattern:/%[^%\s]*%/,alias:"operator"},boolean:/\b(?:TRUE|FALSE)\b/,ellipsis:/\.\.(?:\.|\d+)/,number:[/\b(?:NaN|Inf)\b/,/(?:\b0x[\dA-Fa-f]+(?:\.\d*)?|\b\d+(?:\.\d*)?|\B\.\d+)(?:[EePp][+-]?\d+)?[iL]?/],keyword:/\b(?:if|else|repeat|while|function|for|in|next|break|NULL|NA|NA_integer_|NA_real_|NA_complex_|NA_character_)\b/,operator:/->?>?|<(?:=|=!]=?|::?|&&?|\|\|?|[+*\/^$@~]/,punctuation:/[(){}\[\],;]/}}e.exports=t,t.displayName="r",t.aliases=[]},32168(e,t,n){"use strict";var r=n(9997);function i(e){e.register(r),e.languages.racket=e.languages.extend("scheme",{"lambda-parameter":{pattern:/([(\[]lambda\s+[(\[])[^()\[\]'\s]+/,lookbehind:!0}}),e.languages.insertBefore("racket","string",{lang:{pattern:/^#lang.+/m,greedy:!0,alias:"keyword"}}),e.languages.rkt=e.languages.racket}e.exports=i,i.displayName="racket",i.aliases=["rkt"]},5755(e){"use strict";function t(e){e.languages.reason=e.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:mod|land|lor|lxor|lsl|lsr|asr)\b/}),e.languages.insertBefore("reason","class-name",{character:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,alias:"string"},constructor:{pattern:/\b[A-Z]\w*\b(?!\s*\.)/,alias:"variable"},label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete e.languages.reason.function}e.exports=t,t.displayName="reason",t.aliases=[]},54105(e){"use strict";function t(e){var t,n,r,i,a,o,s,u;t=e,n={pattern:/\\[\\(){}[\]^$+*?|.]/,alias:"escape"},i={pattern:/\.|\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},a={pattern:/\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},s=RegExp((o="(?:[^\\\\-]|"+(r=/\\(?:x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]+\}|c[a-zA-Z]|0[0-7]{0,2}|[123][0-7]{2}|.)/).source+")")+"-"+o),u={pattern:/(<|')[^<>']+(?=[>']$)/,lookbehind:!0,alias:"variable"},t.languages.regex={charset:{pattern:/((?:^|[^\\])(?:\\\\)*)\[(?:[^\\\]]|\\[\s\S])*\]/,lookbehind:!0,inside:{"charset-negation":{pattern:/(^\[)\^/,lookbehind:!0,alias:"operator"},"charset-punctuation":{pattern:/^\[|\]$/,alias:"punctuation"},range:{pattern:s,inside:{escape:r,"range-punctuation":{pattern:/-/,alias:"operator"}}},"special-escape":n,charclass:a,escape:r}},"special-escape":n,charclass:i,backreference:[{pattern:/\\(?![123][0-7]{2})[1-9]/,alias:"keyword"},{pattern:/\\k<[^<>']+>/,alias:"keyword",inside:{"group-name":u}}],anchor:{pattern:/[$^]|\\[ABbGZz]/,alias:"function"},escape:r,group:[{pattern:/\((?:\?(?:<[^<>']+>|'[^<>']+'|[>:]|:=]=?|!=|\b_\b/,punctuation:/[,;.\[\]{}()]/}}e.exports=t,t.displayName="rego",t.aliases=[]},35108(e){"use strict";function t(e){e.languages.renpy={comment:{pattern:/(^|[^\\])#.+/,lookbehind:!0},string:{pattern:/("""|''')[\s\S]+?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2|(?:^#?(?:[0-9a-fA-F]{6}|(?:[0-9a-fA-F]){3})$)/m,greedy:!0},function:/\b[a-z_]\w*(?=\()/i,property:/\b(?:insensitive|idle|hover|selected_idle|selected_hover|background|position|alt|xpos|ypos|pos|xanchor|yanchor|anchor|xalign|yalign|align|xcenter|ycenter|xofsset|yoffset|ymaximum|maximum|xmaximum|xminimum|yminimum|minimum|xsize|ysizexysize|xfill|yfill|area|antialias|black_color|bold|caret|color|first_indent|font|size|italic|justify|kerning|language|layout|line_leading|line_overlap_split|line_spacing|min_width|newline_indent|outlines|rest_indent|ruby_style|slow_cps|slow_cps_multiplier|strikethrough|text_align|underline|hyperlink_functions|vertical|hinting|foreground|left_margin|xmargin|top_margin|bottom_margin|ymargin|left_padding|right_padding|xpadding|top_padding|bottom_padding|ypadding|size_group|child|hover_sound|activate_sound|mouse|focus_mask|keyboard_focus|bar_vertical|bar_invert|bar_resizing|left_gutter|right_gutter|top_gutter|bottom_gutter|left_bar|right_bar|top_bar|bottom_bar|thumb|thumb_shadow|thumb_offset|unscrollable|spacing|first_spacing|box_reverse|box_wrap|order_reverse|fit_first|ysize|thumbnail_width|thumbnail_height|help|text_ypos|text_xpos|idle_color|hover_color|selected_idle_color|selected_hover_color|insensitive_color|alpha|insensitive_background|hover_background|zorder|value|width|xadjustment|xanchoraround|xaround|xinitial|xoffset|xzoom|yadjustment|yanchoraround|yaround|yinitial|yzoom|zoom|ground|height|text_style|text_y_fudge|selected_insensitive|has_sound|has_music|has_voice|focus|hovered|image_style|length|minwidth|mousewheel|offset|prefix|radius|range|right_margin|rotate|rotate_pad|developer|screen_width|screen_height|window_title|name|version|windows_icon|default_fullscreen|default_text_cps|default_afm_time|main_menu_music|sample_sound|enter_sound|exit_sound|save_directory|enter_transition|exit_transition|intra_transition|main_game_transition|game_main_transition|end_splash_transition|end_game_transition|after_load_transition|window_show_transition|window_hide_transition|adv_nvl_transition|nvl_adv_transition|enter_yesno_transition|exit_yesno_transition|enter_replay_transition|exit_replay_transition|say_attribute_transition|directory_name|executable_name|include_update|window_icon|modal|google_play_key|google_play_salt|drag_name|drag_handle|draggable|dragged|droppable|dropped|narrator_menu|action|default_afm_enable|version_name|version_tuple|inside|fadeout|fadein|layers|layer_clipping|linear|scrollbars|side_xpos|side_ypos|side_spacing|edgescroll|drag_joined|drag_raise|drop_shadow|drop_shadow_color|subpixel|easein|easeout|time|crop|auto|update|get_installed_packages|can_update|UpdateVersion|Update|overlay_functions|translations|window_left_padding|show_side_image|show_two_window)\b/,tag:/\b(?:label|image|menu|[hv]box|frame|text|imagemap|imagebutton|bar|vbar|screen|textbutton|buttoscreenn|fixed|grid|input|key|mousearea|side|timer|viewport|window|hotspot|hotbar|self|button|drag|draggroup|tag|mm_menu_frame|nvl|block|parallel)\b|\$/,keyword:/\b(?:as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|yield|adjustment|alignaround|allow|angle|around|box_layout|cache|changed|child_size|clicked|clipping|corner1|corner2|default|delay|exclude|scope|slow|slow_abortable|slow_done|sound|style_group|substitute|suffix|transform_anchor|transpose|unhovered|config|theme|mm_root|gm_root|rounded_window|build|disabled_text|disabled|widget_selected|widget_text|widget_hover|widget|updater|behind|call|expression|hide|init|jump|onlayer|python|renpy|scene|set|show|transform|play|queue|stop|pause|define|window|repeat|contains|choice|on|function|event|animation|clockwise|counterclockwise|circles|knot|null|None|random|has|add|use|fade|dissolve|style|store|id|voice|center|left|right|less_rounded|music|movie|clear|persistent|ui)\b/,boolean:/\b(?:[Tt]rue|[Ff]alse)\b/,number:/(?:\b(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*(?:\.\d*)?)|\B\.\d+)(?:e[+-]?\d+)?j?/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not|with|at)\b/,punctuation:/[{}[\];(),.:]/},e.languages.rpy=e.languages.renpy}e.exports=t,t.displayName="renpy",t.aliases=["rpy"]},46678(e){"use strict";function t(e){e.languages.rest={table:[{pattern:/(^[\t ]*)(?:\+[=-]+)+\+(?:\r?\n|\r)(?:\1[+|].+[+|](?:\r?\n|\r))+\1(?:\+[=-]+)+\+/m,lookbehind:!0,inside:{punctuation:/\||(?:\+[=-]+)+\+/}},{pattern:/(^[\t ]*)=+ [ =]*=(?:(?:\r?\n|\r)\1.+)+(?:\r?\n|\r)\1=+ [ =]*=(?=(?:\r?\n|\r){2}|\s*$)/m,lookbehind:!0,inside:{punctuation:/[=-]+/}}],"substitution-def":{pattern:/(^[\t ]*\.\. )\|(?:[^|\s](?:[^|]*[^|\s])?)\| [^:]+::/m,lookbehind:!0,inside:{substitution:{pattern:/^\|(?:[^|\s]|[^|\s][^|]*[^|\s])\|/,alias:"attr-value",inside:{punctuation:/^\||\|$/}},directive:{pattern:/( )(?! )[^:]+::/,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}}}},"link-target":[{pattern:/(^[\t ]*\.\. )\[[^\]]+\]/m,lookbehind:!0,alias:"string",inside:{punctuation:/^\[|\]$/}},{pattern:/(^[\t ]*\.\. )_(?:`[^`]+`|(?:[^:\\]|\\.)+):/m,lookbehind:!0,alias:"string",inside:{punctuation:/^_|:$/}}],directive:{pattern:/(^[\t ]*\.\. )[^:]+::/m,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}},comment:{pattern:/(^[\t ]*\.\.)(?:(?: .+)?(?:(?:\r?\n|\r).+)+| .+)(?=(?:\r?\n|\r){2}|$)/m,lookbehind:!0},title:[{pattern:/^(([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+)(?:\r?\n|\r).+(?:\r?\n|\r)\1$/m,inside:{punctuation:/^[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+|[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}},{pattern:/(^|(?:\r?\n|\r){2}).+(?:\r?\n|\r)([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+(?=\r?\n|\r|$)/,lookbehind:!0,inside:{punctuation:/[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}}],hr:{pattern:/((?:\r?\n|\r){2})([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2{3,}(?=(?:\r?\n|\r){2})/,lookbehind:!0,alias:"punctuation"},field:{pattern:/(^[\t ]*):[^:\r\n]+:(?= )/m,lookbehind:!0,alias:"attr-name"},"command-line-option":{pattern:/(^[\t ]*)(?:[+-][a-z\d]|(?:--|\/)[a-z\d-]+)(?:[ =](?:[a-z][\w-]*|<[^<>]+>))?(?:, (?:[+-][a-z\d]|(?:--|\/)[a-z\d-]+)(?:[ =](?:[a-z][\w-]*|<[^<>]+>))?)*(?=(?:\r?\n|\r)? {2,}\S)/im,lookbehind:!0,alias:"symbol"},"literal-block":{pattern:/::(?:\r?\n|\r){2}([ \t]+)(?![ \t]).+(?:(?:\r?\n|\r)\1.+)*/,inside:{"literal-block-punctuation":{pattern:/^::/,alias:"punctuation"}}},"quoted-literal-block":{pattern:/::(?:\r?\n|\r){2}([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]).*(?:(?:\r?\n|\r)\1.*)*/,inside:{"literal-block-punctuation":{pattern:/^(?:::|([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\1*)/m,alias:"punctuation"}}},"list-bullet":{pattern:/(^[\t ]*)(?:[*+\-•‣⁃]|\(?(?:\d+|[a-z]|[ivxdclm]+)\)|(?:\d+|[a-z]|[ivxdclm]+)\.)(?= )/im,lookbehind:!0,alias:"punctuation"},"doctest-block":{pattern:/(^[\t ]*)>>> .+(?:(?:\r?\n|\r).+)*/m,lookbehind:!0,inside:{punctuation:/^>>>/}},inline:[{pattern:/(^|[\s\-:\/'"<(\[{])(?::[^:]+:`.*?`|`.*?`:[^:]+:|(\*\*?|``?|\|)(?!\s)(?:(?!\2).)*\S\2(?=[\s\-.,:;!?\\\/'")\]}]|$))/m,lookbehind:!0,inside:{bold:{pattern:/(^\*\*).+(?=\*\*$)/,lookbehind:!0},italic:{pattern:/(^\*).+(?=\*$)/,lookbehind:!0},"inline-literal":{pattern:/(^``).+(?=``$)/,lookbehind:!0,alias:"symbol"},role:{pattern:/^:[^:]+:|:[^:]+:$/,alias:"function",inside:{punctuation:/^:|:$/}},"interpreted-text":{pattern:/(^`).+(?=`$)/,lookbehind:!0,alias:"attr-value"},substitution:{pattern:/(^\|).+(?=\|$)/,lookbehind:!0,alias:"attr-value"},punctuation:/\*\*?|``?|\|/}}],link:[{pattern:/\[[^\[\]]+\]_(?=[\s\-.,:;!?\\\/'")\]}]|$)/,alias:"string",inside:{punctuation:/^\[|\]_$/}},{pattern:/(?:\b[a-z\d]+(?:[_.:+][a-z\d]+)*_?_|`[^`]+`_?_|_`[^`]+`)(?=[\s\-.,:;!?\\\/'")\]}]|$)/i,alias:"string",inside:{punctuation:/^_?`|`$|`?_?_$/}}],punctuation:{pattern:/(^[\t ]*)(?:\|(?= |$)|(?:---?|—|\.\.|__)(?= )|\.\.$)/m,lookbehind:!0}}}e.exports=t,t.displayName="rest",t.aliases=[]},47496(e){"use strict";function t(e){e.languages.rip={comment:/#.*/,keyword:/(?:=>|->)|\b(?:class|if|else|switch|case|return|exit|try|catch|finally|raise)\b/,builtin:/@|\bSystem\b/,boolean:/\b(?:true|false)\b/,date:/\b\d{4}-\d{2}-\d{2}\b/,time:/\b\d{2}:\d{2}:\d{2}\b/,datetime:/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\b/,character:/\B`[^\s`'",.:;#\/\\()<>\[\]{}]\b/,regex:{pattern:/(^|[^/])\/(?!\/)(?:\[[^\n\r\]]*\]|\\.|[^/\\\r\n\[])+\/(?=\s*(?:$|[\r\n,.;})]))/,lookbehind:!0,greedy:!0},symbol:/:[^\d\s`'",.:;#\/\\()<>\[\]{}][^\s`'",.:;#\/\\()<>\[\]{}]*/,string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},number:/[+-]?\b(?:\d+\.\d+|\d+)\b/,punctuation:/(?:\.{2,3})|[`,.:;=\/\\()<>\[\]{}]/,reference:/[^\d\s`'",.:;#\/\\()<>\[\]{}][^\s`'",.:;#\/\\()<>\[\]{}]*/}}e.exports=t,t.displayName="rip",t.aliases=[]},30527(e){"use strict";function t(e){e.languages.roboconf={comment:/#.*/,keyword:{pattern:/(^|\s)(?:(?:facet|instance of)(?=[ \t]+[\w-]+[ \t]*\{)|(?:external|import)\b)/,lookbehind:!0},component:{pattern:/[\w-]+(?=[ \t]*\{)/,alias:"variable"},property:/[\w.-]+(?=[ \t]*:)/,value:{pattern:/(=[ \t]*(?![ \t]))[^,;]+/,lookbehind:!0,alias:"attr-value"},optional:{pattern:/\(optional\)/,alias:"builtin"},wildcard:{pattern:/(\.)\*/,lookbehind:!0,alias:"operator"},punctuation:/[{},.;:=]/}}e.exports=t,t.displayName="roboconf",t.aliases=[]},5261(e){"use strict";function t(e){!function(e){var t={pattern:/(^[ \t]*| {2}|\t)#.*/m,lookbehind:!0,greedy:!0},n={pattern:/((?:^|[^\\])(?:\\{2})*)[$@&%]\{(?:[^{}\r\n]|\{[^{}\r\n]*\})*\}/,lookbehind:!0,inside:{punctuation:/^[$@&%]\{|\}$/}};function r(e,r){var i={};for(var a in i["section-header"]={pattern:/^ ?\*{3}.+?\*{3}/,alias:"keyword"},r)i[a]=r[a];return i.tag={pattern:/([\r\n](?: {2}|\t)[ \t]*)\[[-\w]+\]/,lookbehind:!0,inside:{punctuation:/\[|\]/}},i.variable=n,i.comment=t,{pattern:RegExp(/^ ?\*{3}[ \t]*[ \t]*\*{3}(?:.|[\r\n](?!\*{3}))*/.source.replace(//g,function(){return e}),"im"),alias:"section",inside:i}}var i={pattern:/(\[Documentation\](?: {2}|\t)[ \t]*)(?![ \t]|#)(?:.|(?:\r\n?|\n)[ \t]*\.{3})+/,lookbehind:!0,alias:"string"},a={pattern:/([\r\n] ?)(?!#)(?:\S(?:[ \t]\S)*)+/,lookbehind:!0,alias:"function",inside:{variable:n}},o={pattern:/([\r\n](?: {2}|\t)[ \t]*)(?!\[|\.{3}|#)(?:\S(?:[ \t]\S)*)+/,lookbehind:!0,inside:{variable:n}};e.languages.robotframework={settings:r("Settings",{documentation:{pattern:/([\r\n] ?Documentation(?: {2}|\t)[ \t]*)(?![ \t]|#)(?:.|(?:\r\n?|\n)[ \t]*\.{3})+/,lookbehind:!0,alias:"string"},property:{pattern:/([\r\n] ?)(?!\.{3}|#)(?:\S(?:[ \t]\S)*)+/,lookbehind:!0}}),variables:r("Variables"),"test-cases":r("Test Cases",{"test-name":a,documentation:i,property:o}),keywords:r("Keywords",{"keyword-name":a,documentation:i,property:o}),tasks:r("Tasks",{"task-name":a,documentation:i,property:o}),comment:t},e.languages.robot=e.languages.robotframework}(e)}e.exports=t,t.displayName="robotframework",t.aliases=[]},56939(e){"use strict";function t(e){var t,n;(t=e).languages.ruby=t.languages.extend("clike",{comment:[/#.*/,{pattern:/^=begin\s[\s\S]*?^=end/m,greedy:!0}],"class-name":{pattern:/(\b(?:class)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/}),n={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:t.languages.ruby}},delete t.languages.ruby.function,t.languages.insertBefore("ruby","keyword",{regex:[{pattern:RegExp(/%r/.source+"(?:"+[/([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S])*\)/.source,/\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S])*\]/.source,/<(?:[^<>\\]|\\[\s\S])*>/.source].join("|")+")"+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:n}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:n}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:{pattern:/(^|[^:]):[a-zA-Z_]\w*(?:[?!]|\b)/,lookbehind:!0},"method-definition":{pattern:/(\bdef\s+)[\w.]+/,lookbehind:!0,inside:{function:/\w+$/,rest:t.languages.ruby}}}),t.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|Fixnum|Float|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z]\w*(?:[?!]|\b)/}),t.languages.ruby.string=[{pattern:RegExp(/%[qQiIwWxs]?/.source+"(?:"+[/([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S])*\)/.source,/\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S])*\]/.source,/<(?:[^<>\\]|\\[\s\S])*>/.source].join("|")+")"),greedy:!0,inside:{interpolation:n}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:n}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|[a-z_]\w*$/i,alias:"symbol",inside:{punctuation:/^<<[-~]?/}},interpolation:n}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|[a-z_]\w*$/i,alias:"symbol",inside:{punctuation:/^<<[-~]?'|'$/}}}}],t.languages.rb=t.languages.ruby}e.exports=t,t.displayName="ruby",t.aliases=["rb"]},83648(e){"use strict";function t(e){!function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|)*\*\//.source,n=0;n<2;n++)t=t.replace(//g,function(){return t});t=t.replace(//g,function(){return/[^\s\S]/.source}),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0,alias:"string"},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|Self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:[ui](?:8|16|32|64|128|size)|f(?:32|64)|bool|char|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:[iu](?:8|16|32|64|size)?|f32|f64))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(e)}e.exports=t,t.displayName="rust",t.aliases=[]},16009(e){"use strict";function t(e){var t,n,r,i,a,o,s,u,c,l,f,d,h,p,b,m,g,v,y;t=e,n=/(?:"(?:""|[^"])*"(?!")|'(?:''|[^'])*'(?!'))/.source,r=/\b(?:\d[\da-f]*x|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/i,i={pattern:RegExp(n+"[bx]"),alias:"number"},a={pattern:/&[a-z_]\w*/i},o={pattern:/((?:^|\s|=|\())%(?:ABORT|BY|CMS|COPY|DISPLAY|DO|ELSE|END|EVAL|GLOBAL|GO|GOTO|IF|INC|INCLUDE|INDEX|INPUT|KTRIM|LENGTH|LET|LIST|LOCAL|PUT|QKTRIM|QSCAN|QSUBSTR|QSYSFUNC|QUPCASE|RETURN|RUN|SCAN|SUBSTR|SUPERQ|SYMDEL|SYMGLOBL|SYMLOCAL|SYMEXIST|SYSCALL|SYSEVALF|SYSEXEC|SYSFUNC|SYSGET|SYSRPUT|THEN|TO|TSO|UNQUOTE|UNTIL|UPCASE|WHILE|WINDOW)\b/i,lookbehind:!0,alias:"keyword"},s={pattern:/(^|\s)(?:proc\s+\w+|quit|run|data(?!=))\b/i,alias:"keyword",lookbehind:!0},u=[/\/\*[\s\S]*?\*\//,{pattern:/(^[ \t]*|;\s*)\*[^;]*;/m,lookbehind:!0}],c={pattern:RegExp(n),greedy:!0},d={function:f={pattern:/%?\b\w+(?=\()/,alias:"keyword"},"arg-value":{pattern:/(=\s*)[A-Z\.]+/i,lookbehind:!0},operator:/=/,"macro-variable":a,arg:{pattern:/[A-Z]+/i,alias:"keyword"},number:r,"numeric-constant":i,punctuation:l=/[$%@.(){}\[\];,\\]/,string:c},h={pattern:/\b(?:format|put)\b=?[\w'$.]+/im,inside:{keyword:/^(?:format|put)(?==)/i,equals:/=/,format:{pattern:/(?:\w|\$\d)+\.\d?/i,alias:"number"}}},p={pattern:/\b(?:format|put)\s+[\w']+(?:\s+[$.\w]+)+(?=;)/i,inside:{keyword:/^(?:format|put)/i,format:{pattern:/[\w$]+\.\d?/,alias:"number"}}},b={pattern:/((?:^|\s)=?)(?:catname|checkpoint execute_always|dm|endsas|filename|footnote|%include|libname|%list|lock|missing|options|page|resetline|%run|sasfile|skip|sysecho|title\d?)\b/i,lookbehind:!0,alias:"keyword"},m={pattern:/(^|\s)(?:submit(?:\s+(?:load|parseonly|norun))?|endsubmit)\b/i,lookbehind:!0,alias:"keyword"},g=/accessControl|cdm|aggregation|aStore|ruleMining|audio|autotune|bayesianNetClassifier|bioMedImage|boolRule|builtins|cardinality|sccasl|clustering|copula|countreg|dataDiscovery|dataPreprocess|dataSciencePilot|dataStep|decisionTree|deepLearn|deepNeural|varReduce|simSystem|ds2|deduplication|ecm|entityRes|espCluster|explainModel|factmac|fastKnn|fcmpact|fedSql|freqTab|gam|gleam|graphSemiSupLearn|gVarCluster|hiddenMarkovModel|hyperGroup|image|iml|ica|kernalPca|langModel|ldaTopic|sparseML|mlTools|mixed|modelPublishing|mbc|network|optNetwork|neuralNet|nonlinear|nmf|nonParametricBayes|optimization|panel|pls|percentile|pca|phreg|qkb|qlim|quantreg|recommend|tsReconcile|deepRnn|regression|reinforcementLearn|robustPca|sampling|sparkEmbeddedProcess|search(?:Analytics)?|sentimentAnalysis|sequence|configuration|session(?:Prop)?|severity|simple|smartData|sandwich|spatialreg|stabilityMonitoring|spc|loadStreams|svDataDescription|svm|table|conditionalRandomFields|text(?:Rule(?:Develop|Score)|Mining|Parse|Topic|Util|Filters|Frequency)|tsInfo|timeData|transpose|uniTimeSeries/.source,v={pattern:RegExp(/(^|\s)(?:action\s+)?(?:)\.[a-z]+\b[^;]+/.source.replace(//g,function(){return g}),"i"),lookbehind:!0,inside:{keyword:RegExp(/(?:)\.[a-z]+\b/.source.replace(//g,function(){return g}),"i"),action:{pattern:/(?:action)/i,alias:"keyword"},comment:u,function:f,"arg-value":d["arg-value"],operator:d.operator,argument:d.arg,number:r,"numeric-constant":i,punctuation:l,string:c}},y={pattern:/((?:^|\s)=?)(?:after|analysis|and|array|barchart|barwidth|begingraph|by|call|cas|cbarline|cfill|class(?:lev)?|close|column|computed?|contains|continue|data(?==)|define|delete|describe|document|do\s+over|do|dol|drop|dul|end(?:source|comp)?|entryTitle|else|eval(?:uate)?|exec(?:ute)?|exit|fill(?:attrs)?|file(?:name)?|flist|fnc|function(?:list)?|goto|global|group(?:by)?|headline|headskip|histogram|if|infile|keep|keylabel|keyword|label|layout|leave|legendlabel|length|libname|loadactionset|merge|midpoints|name|noobs|nowd|_?null_|ods|options|or|otherwise|out(?:put)?|over(?:lay)?|plot|put|print|raise|ranexp|rannor|rbreak|retain|return|select|set|session|sessref|source|statgraph|sum|summarize|table|temp|terminate|then\s+do|then|title\d?|to|var|when|where|xaxisopts|yaxisopts|y2axisopts)\b/i,lookbehind:!0},t.languages.sas={datalines:{pattern:/^([ \t]*)(?:(?:data)?lines|cards);[\s\S]+?^[ \t]*;/im,lookbehind:!0,alias:"string",inside:{keyword:{pattern:/^(?:(?:data)?lines|cards)/i},punctuation:/;/}},"proc-sql":{pattern:/(^proc\s+(?:fed)?sql(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{sql:{pattern:RegExp(/^[ \t]*(?:select|alter\s+table|(?:create|describe|drop)\s+(?:index|table(?:\s+constraints)?|view)|create\s+unique\s+index|insert\s+into|update)(?:|[^;"'])+;/.source.replace(//g,function(){return n}),"im"),alias:"language-sql",inside:t.languages.sql},"global-statements":b,"sql-statements":{pattern:/(^|\s)(?:disconnect\s+from|exec(?:ute)?|begin|commit|rollback|reset|validate)\b/i,lookbehind:!0,alias:"keyword"},number:r,"numeric-constant":i,punctuation:l,string:c}},"proc-groovy":{pattern:/(^proc\s+groovy(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{comment:u,groovy:{pattern:RegExp(/(^[ \t]*submit(?:\s+(?:load|parseonly|norun))?)(?:|[^"'])+?(?=endsubmit;)/.source.replace(//g,function(){return n}),"im"),lookbehind:!0,alias:"language-groovy",inside:t.languages.groovy},keyword:y,"submit-statement":m,"global-statements":b,number:r,"numeric-constant":i,punctuation:l,string:c}},"proc-lua":{pattern:/(^proc\s+lua(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{comment:u,lua:{pattern:RegExp(/(^[ \t]*submit(?:\s+(?:load|parseonly|norun))?)(?:|[^"'])+?(?=endsubmit;)/.source.replace(//g,function(){return n}),"im"),lookbehind:!0,alias:"language-lua",inside:t.languages.lua},keyword:y,"submit-statement":m,"global-statements":b,number:r,"numeric-constant":i,punctuation:l,string:c}},"proc-cas":{pattern:/(^proc\s+cas(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|data);|(?![\s\S]))/im,lookbehind:!0,inside:{comment:u,"statement-var":{pattern:/((?:^|\s)=?)saveresult\s[^;]+/im,lookbehind:!0,inside:{statement:{pattern:/^saveresult\s+\S+/i,inside:{keyword:/^(?:saveresult)/i}},rest:d}},"cas-actions":v,statement:{pattern:/((?:^|\s)=?)(?:default|(?:un)?set|on|output|upload)[^;]+/im,lookbehind:!0,inside:d},step:s,keyword:y,function:f,format:h,altformat:p,"global-statements":b,number:r,"numeric-constant":i,punctuation:l,string:c}},"proc-args":{pattern:RegExp(/(^proc\s+\w+\s+)(?!\s)(?:[^;"']|)+;/.source.replace(//g,function(){return n}),"im"),lookbehind:!0,inside:d},"macro-keyword":o,"macro-variable":a,"macro-string-functions":{pattern:/((?:^|\s|=))%(?:NRBQUOTE|NRQUOTE|NRSTR|BQUOTE|QUOTE|STR)\(.*?(?:[^%]\))/i,lookbehind:!0,inside:{function:{pattern:/%(?:NRBQUOTE|NRQUOTE|NRSTR|BQUOTE|QUOTE|STR)/i,alias:"keyword"},"macro-keyword":o,"macro-variable":a,"escaped-char":{pattern:/%['"()<>=¬^~;,#]/i},punctuation:l}},"macro-declaration":{pattern:/^%macro[^;]+(?=;)/im,inside:{keyword:/%macro/i}},"macro-end":{pattern:/^%mend[^;]+(?=;)/im,inside:{keyword:/%mend/i}},macro:{pattern:/%_\w+(?=\()/,alias:"keyword"},input:{pattern:/\binput\s[-\w\s/*.$&]+;/i,inside:{input:{alias:"keyword",pattern:/^input/i},comment:u,number:r,"numeric-constant":i}},"options-args":{pattern:/(^options)[-'"|/\\<>*+=:()\w\s]*(?=;)/im,lookbehind:!0,inside:d},"cas-actions":v,comment:u,function:f,format:h,altformat:p,"numeric-constant":i,datetime:{pattern:RegExp(n+"(?:dt?|t)"),alias:"number"},string:c,step:s,keyword:y,"operator-keyword":{pattern:/\b(?:eq|ne|gt|lt|ge|le|in|not)\b/i,alias:"operator"},number:r,operator:/\*\*?|\|\|?|!!?|¦¦?|<[>=]?|>[<=]?|[-+\/=&]|[~¬^]=?/i,punctuation:l}}e.exports=t,t.displayName="sas",t.aliases=[]},41720(e){"use strict";function t(e){var t,n,r;(t=e).languages.sass=t.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0}}),t.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,inside:{atrule:/(?:@[\w-]+|[+=])/m}}}),delete t.languages.sass.atrule,n=/\$[-\w]+|#\{\$[-\w]+\}/,r=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|or|not)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}],t.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,inside:{punctuation:/:/,variable:n,operator:r}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:n,operator:r,important:t.languages.sass.important}}}),delete t.languages.sass.property,delete t.languages.sass.important,t.languages.insertBefore("sass","punctuation",{selector:{pattern:/([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/,lookbehind:!0}})}e.exports=t,t.displayName="sass",t.aliases=[]},6054(e,t,n){"use strict";var r=n(15909);function i(e){e.register(r),e.languages.scala=e.languages.extend("java",{"triple-quoted-string":{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string"},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},keyword:/<-|=>|\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\b/,number:/\b0x(?:[\da-f]*\.)?[\da-f]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e\d+)?[dfl]?/i,builtin:/\b(?:String|Int|Long|Short|Byte|Boolean|Double|Float|Char|Any|AnyRef|AnyVal|Unit|Nothing)\b/,symbol:/'[^\d\s\\]\w*/}),delete e.languages.scala["class-name"],delete e.languages.scala.function}e.exports=i,i.displayName="scala",i.aliases=[]},9997(e){"use strict";function t(e){!function(e){e.languages.scheme={comment:/;.*|#;\s*(?:\((?:[^()]|\([^()]*\))*\)|\[(?:[^\[\]]|\[[^\[\]]*\])*\])|#\|(?:[^#|]|#(?!\|)|\|(?!#)|#\|(?:[^#|]|#(?!\|)|\|(?!#))*\|#)*\|#/,string:{pattern:/"(?:[^"\\]|\\.)*"/,greedy:!0},symbol:{pattern:/'[^()\[\]#'\s]+/,greedy:!0},character:{pattern:/#\\(?:[ux][a-fA-F\d]+\b|[-a-zA-Z]+\b|[\uD800-\uDBFF][\uDC00-\uDFFF]|\S)/,greedy:!0,alias:"string"},"lambda-parameter":[{pattern:/((?:^|[^'`#])[(\[]lambda\s+)(?:[^|()\[\]'\s]+|\|(?:[^\\|]|\\.)*\|)/,lookbehind:!0},{pattern:/((?:^|[^'`#])[(\[]lambda\s+[(\[])[^()\[\]']+/,lookbehind:!0}],keyword:{pattern:/((?:^|[^'`#])[(\[])(?:begin|case(?:-lambda)?|cond(?:-expand)?|define(?:-library|-macro|-record-type|-syntax|-values)?|defmacro|delay(?:-force)?|do|else|export|except|guard|if|import|include(?:-ci|-library-declarations)?|lambda|let(?:rec)?(?:-syntax|-values|\*)?|let\*-values|only|parameterize|prefix|(?:quasi-?)?quote|rename|set!|syntax-(?:case|rules)|unless|unquote(?:-splicing)?|when)(?=[()\[\]\s]|$)/,lookbehind:!0},builtin:{pattern:/((?:^|[^'`#])[(\[])(?:abs|and|append|apply|assoc|ass[qv]|binary-port\?|boolean=?\?|bytevector(?:-append|-copy|-copy!|-length|-u8-ref|-u8-set!|\?)?|caar|cadr|call-with-(?:current-continuation|port|values)|call\/cc|car|cdar|cddr|cdr|ceiling|char(?:->integer|-ready\?|\?|<\?|<=\?|=\?|>\?|>=\?)|close-(?:input-port|output-port|port)|complex\?|cons|current-(?:error|input|output)-port|denominator|dynamic-wind|eof-object\??|eq\?|equal\?|eqv\?|error|error-object(?:-irritants|-message|\?)|eval|even\?|exact(?:-integer-sqrt|-integer\?|\?)?|expt|features|file-error\?|floor(?:-quotient|-remainder|\/)?|flush-output-port|for-each|gcd|get-output-(?:bytevector|string)|inexact\??|input-port(?:-open\?|\?)|integer(?:->char|\?)|lcm|length|list(?:->string|->vector|-copy|-ref|-set!|-tail|\?)?|make-(?:bytevector|list|parameter|string|vector)|map|max|member|memq|memv|min|modulo|negative\?|newline|not|null\?|number(?:->string|\?)|numerator|odd\?|open-(?:input|output)-(?:bytevector|string)|or|output-port(?:-open\?|\?)|pair\?|peek-char|peek-u8|port\?|positive\?|procedure\?|quotient|raise|raise-continuable|rational\?|rationalize|read-(?:bytevector|bytevector!|char|error\?|line|string|u8)|real\?|remainder|reverse|round|set-c[ad]r!|square|string(?:->list|->number|->symbol|->utf8|->vector|-append|-copy|-copy!|-fill!|-for-each|-length|-map|-ref|-set!|\?|<\?|<=\?|=\?|>\?|>=\?)?|substring|symbol(?:->string|\?|=\?)|syntax-error|textual-port\?|truncate(?:-quotient|-remainder|\/)?|u8-ready\?|utf8->string|values|vector(?:->list|->string|-append|-copy|-copy!|-fill!|-for-each|-length|-map|-ref|-set!|\?)?|with-exception-handler|write-(?:bytevector|char|string|u8)|zero\?)(?=[()\[\]\s]|$)/,lookbehind:!0},operator:{pattern:/((?:^|[^'`#])[(\[])(?:[-+*%/]|[<>]=?|=>?)(?=[()\[\]\s]|$)/,lookbehind:!0},number:{pattern:RegExp(t({"":/\d+(?:\/\d+)|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/.source,"":/[+-]?|[+-](?:inf|nan)\.0/.source,"":/[+-](?:|(?:inf|nan)\.0)?i/.source,"":/(?:@|)?|/.source,"":/(?:#d(?:#[ei])?|#[ei](?:#d)?)?/.source,"":/[0-9a-f]+(?:\/[0-9a-f]+)?/.source,"":/[+-]?|[+-](?:inf|nan)\.0/.source,"":/[+-](?:|(?:inf|nan)\.0)?i/.source,"":/(?:@|)?|/.source,"":/#[box](?:#[ei])?|(?:#[ei])?#[box]/.source,"":/(^|[()\[\]\s])(?:|)(?=[()\[\]\s]|$)/.source}),"i"),lookbehind:!0},boolean:{pattern:/(^|[()\[\]\s])#(?:[ft]|false|true)(?=[()\[\]\s]|$)/,lookbehind:!0},function:{pattern:/((?:^|[^'`#])[(\[])(?:[^|()\[\]'\s]+|\|(?:[^\\|]|\\.)*\|)(?=[()\[\]\s]|$)/,lookbehind:!0},identifier:{pattern:/(^|[()\[\]\s])\|(?:[^\\|]|\\.)*\|(?=[()\[\]\s]|$)/,lookbehind:!0,greedy:!0},punctuation:/[()\[\]']/};function t(e){for(var t in e)e[t]=e[t].replace(/<[\w\s]+>/g,function(t){return"(?:"+e[t].trim()+")"});return e[t]}}(e)}e.exports=t,t.displayName="scheme",t.aliases=[]},24296(e){"use strict";function t(e){e.languages.scss=e.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/m,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),e.languages.insertBefore("scss","atrule",{keyword:[/@(?:if|else(?: if)?|forward|for|each|while|import|use|extend|debug|warn|mixin|include|function|return|content)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),e.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),e.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|with|show|hide)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,lookbehind:!0}}),e.languages.scss.atrule.inside.rest=e.languages.scss}e.exports=t,t.displayName="scss",t.aliases=[]},49246(e,t,n){"use strict";var r=n(6979);function i(e){var t,n;e.register(r),n=[/"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source,/'[^']*'/.source,/\$'(?:[^'\\]|\\[\s\S])*'/.source,/<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source].join("|"),(t=e).languages["shell-session"]={command:{pattern:RegExp(/^(?:[^\s@:$#*!/\\]+@[^\r\n@:$#*!/\\]+(?::[^\0-\x1F$#*?"<>:;|]+)?|[^\0-\x1F$#*?"<>@:;|]+)?/.source+/[$#]/.source+/(?:[^\\\r\n'"<$]|\\(?:[^\r]|\r\n?)|\$(?!')|<>)+/.source.replace(/<>/g,function(){return n}),"m"),greedy:!0,inside:{info:{pattern:/^[^#$]+/,alias:"punctuation",inside:{user:/^[^\s@:$#*!/\\]+@[^\r\n@:$#*!/\\]+/,punctuation:/:/,path:/[\s\S]+/}},bash:{pattern:/(^[$#]\s*)\S[\s\S]*/,lookbehind:!0,alias:"language-bash",inside:t.languages.bash},"shell-symbol":{pattern:/^[$#]/,alias:"important"}}},output:/.(?:.*(?:[\r\n]|.$))*/},t.languages["sh-session"]=t.languages.shellsession=t.languages["shell-session"]}e.exports=i,i.displayName="shellSession",i.aliases=[]},18890(e){"use strict";function t(e){e.languages.smali={comment:/#.*/,string:{pattern:/"(?:[^\r\n\\"]|\\.)*"|'(?:[^\r\n\\']|\\(?:.|u[\da-fA-F]{4}))'/,greedy:!0},"class-name":{pattern:/(^|[^L])L(?:(?:\w+|`[^`\r\n]*`)\/)*(?:[\w$]+|`[^`\r\n]*`)(?=\s*;)/,lookbehind:!0,inside:{"class-name":{pattern:/(^L|\/)(?:[\w$]+|`[^`\r\n]*`)$/,lookbehind:!0},namespace:{pattern:/^(L)(?:(?:\w+|`[^`\r\n]*`)\/)+/,lookbehind:!0,inside:{punctuation:/\//}},builtin:/^L/}},builtin:[{pattern:/([();\[])[BCDFIJSVZ]+/,lookbehind:!0},{pattern:/([\w$>]:)[BCDFIJSVZ]/,lookbehind:!0}],keyword:[{pattern:/(\.end\s+)[\w-]+/,lookbehind:!0},{pattern:/(^|[^\w.-])\.(?!\d)[\w-]+/,lookbehind:!0},{pattern:/(^|[^\w.-])(?:abstract|annotation|bridge|constructor|enum|final|interface|private|protected|public|runtime|static|synthetic|system|transient)(?![\w.-])/,lookbehind:!0}],function:{pattern:/(^|[^\w.-])(?:\w+|<[\w$-]+>)(?=\()/,lookbehind:!0},field:{pattern:/[\w$]+(?=:)/,alias:"variable"},register:{pattern:/(^|[^\w.-])[vp]\d(?![\w.-])/,lookbehind:!0,alias:"variable"},boolean:{pattern:/(^|[^\w.-])(?:true|false)(?![\w.-])/,lookbehind:!0},number:{pattern:/(^|[^/\w.-])-?(?:NAN|INFINITY|0x(?:[\dA-F]+(?:\.[\dA-F]*)?|\.[\dA-F]+)(?:p[+-]?[\dA-F]+)?|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)[dflst]?(?![\w.-])/i,lookbehind:!0},label:{pattern:/(:)\w+/,lookbehind:!0,alias:"property"},operator:/->|\.\.|[\[=]/,punctuation:/[{}(),;:]/}}e.exports=t,t.displayName="smali",t.aliases=[]},11037(e){"use strict";function t(e){e.languages.smalltalk={comment:/"(?:""|[^"])*"/,character:{pattern:/\$./,alias:"string"},string:/'(?:''|[^'])*'/,symbol:/#[\da-z]+|#(?:-|([+\/\\*~<>=@%|&?!])\1?)|#(?=\()/i,"block-arguments":{pattern:/(\[\s*):[^\[|]*\|/,lookbehind:!0,inside:{variable:/:[\da-z]+/i,punctuation:/\|/}},"temporary-variables":{pattern:/\|[^|]+\|/,inside:{variable:/[\da-z]+/i,punctuation:/\|/}},keyword:/\b(?:nil|true|false|self|super|new)\b/,number:[/\d+r-?[\dA-Z]+(?:\.[\dA-Z]+)?(?:e-?\d+)?/,/\b\d+(?:\.\d+)?(?:e-?\d+)?/],operator:/[<=]=?|:=|~[~=]|\/\/?|\\\\|>[>=]?|[!^+\-*&|,@]/,punctuation:/[.;:?\[\](){}]/}}e.exports=t,t.displayName="smalltalk",t.aliases=[]},64020(e,t,n){"use strict";var r=n(93205);function i(e){var t;e.register(r),(t=e).languages.smarty={comment:/\{\*[\s\S]*?\*\}/,delimiter:{pattern:/^\{|\}$/i,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][-+]?\d+)?/,variable:[/\$(?!\d)\w+/,/#(?!\d)\w+#/,{pattern:/(\.|->)(?!\d)\w+/,lookbehind:!0},{pattern:/(\[)(?!\d)\w+(?=\])/,lookbehind:!0}],function:[{pattern:/(\|\s*)@?(?!\d)\w+/,lookbehind:!0},/^\/?(?!\d)\w+/,/(?!\d)\w+(?=\()/],"attr-name":{pattern:/\w+\s*=\s*(?:(?!\d)\w+)?/,inside:{variable:{pattern:/(=\s*)(?!\d)\w+/,lookbehind:!0},operator:/=/}},punctuation:[/[\[\]().,:`]|->/],operator:[/[+\-*\/%]|==?=?|[!<>]=?|&&|\|\|?/,/\bis\s+(?:not\s+)?(?:div|even|odd)(?:\s+by)?\b/,/\b(?:eq|neq?|gt|lt|gt?e|lt?e|not|mod|or|and)\b/],keyword:/\b(?:false|off|on|no|true|yes)\b/},t.hooks.add("before-tokenize",function(e){var n=/\{\*[\s\S]*?\*\}|\{[\s\S]+?\}/g,r="{literal}",i="{/literal}",a=!1;t.languages["markup-templating"].buildPlaceholders(e,"smarty",n,function(e){return e===i&&(a=!1),!a&&(e===r&&(a=!0),!0)})}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"smarty")})}e.exports=i,i.displayName="smarty",i.aliases=[]},49760(e){"use strict";function t(e){var t,n;n=/\b(?:abstype|and|andalso|as|case|datatype|do|else|end|eqtype|exception|fn|fun|functor|handle|if|in|include|infix|infixr|let|local|nonfix|of|op|open|orelse|raise|rec|sharing|sig|signature|struct|structure|then|type|val|where|while|with|withtype)\b/i,(t=e).languages.sml={comment:/\(\*(?:[^*(]|\*(?!\))|\((?!\*)|\(\*(?:[^*(]|\*(?!\))|\((?!\*))*\*\))*\*\)/,string:{pattern:/#?"(?:[^"\\]|\\.)*"/,greedy:!0},"class-name":[{pattern:RegExp(/((?:^|[^:]):\s*)(?:\s*(?:(?:\*|->)\s*|,\s*(?:(?=)|(?!)\s+)))*/.source.replace(//g,function(){return/\s*(?:[*,]|->)/.source}).replace(//g,function(){return/(?:'[\w']*||\((?:[^()]|\([^()]*\))*\)|\{(?:[^{}]|\{[^{}]*\})*\})(?:\s+)*/.source}).replace(//g,function(){return/(?!)[a-z\d_][\w'.]*/.source}).replace(//g,function(){return n.source}),"i"),lookbehind:!0,greedy:!0,inside:null},{pattern:/((?:^|[^\w'])(?:datatype|exception|functor|signature|structure|type)\s+)[a-z_][\w'.]*/i,lookbehind:!0}],function:{pattern:/((?:^|[^\w'])fun\s+)[a-z_][\w'.]*/i,lookbehind:!0},keyword:n,variable:{pattern:/(^|[^\w'])'[\w']*/,lookbehind:!0},number:/~?\b(?:\d+(?:\.\d+)?(?:e~?\d+)?|0x[\da-f]+)\b/i,word:{pattern:/\b0w(?:\d+|x[\da-f]+)\b/i,alias:"constant"},boolean:/\b(?:false|true)\b/i,operator:/\.\.\.|:[>=:]|=>?|->|[<>]=?|[!+\-*/^#|@~]/,punctuation:/[(){}\[\].:,;]/},t.languages.sml["class-name"][0].inside=t.languages.sml,t.languages.smlnj=t.languages.sml}e.exports=t,t.displayName="sml",t.aliases=["smlnj"]},33351(e){"use strict";function t(e){e.languages.solidity=e.languages.extend("clike",{"class-name":{pattern:/(\b(?:contract|enum|interface|library|new|struct|using)\s+)(?!\d)[\w$]+/,lookbehind:!0},keyword:/\b(?:_|anonymous|as|assembly|assert|break|calldata|case|constant|constructor|continue|contract|default|delete|do|else|emit|enum|event|external|for|from|function|if|import|indexed|inherited|interface|internal|is|let|library|mapping|memory|modifier|new|payable|pragma|private|public|pure|require|returns?|revert|selfdestruct|solidity|storage|struct|suicide|switch|this|throw|using|var|view|while)\b/,operator:/=>|->|:=|=:|\*\*|\+\+|--|\|\||&&|<<=?|>>=?|[-+*/%^&|<>!=]=?|[~?]/}),e.languages.insertBefore("solidity","keyword",{builtin:/\b(?:address|bool|string|u?int(?:8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?|byte|bytes(?:[1-9]|[12]\d|3[0-2])?)\b/}),e.languages.insertBefore("solidity","number",{version:{pattern:/([<>]=?|\^)\d+\.\d+\.\d+\b/,lookbehind:!0,alias:"number"}}),e.languages.sol=e.languages.solidity}e.exports=t,t.displayName="solidity",t.aliases=["sol"]},13570(e){"use strict";function t(e){var t,n;n={pattern:/\{[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\}/i,alias:"constant",inside:{punctuation:/[{}]/}},(t=e).languages["solution-file"]={comment:{pattern:/#.*/,greedy:!0},string:{pattern:/"[^"\r\n]*"|'[^'\r\n]*'/,greedy:!0,inside:{guid:n}},object:{pattern:/^([ \t]*)(?:([A-Z]\w*)\b(?=.*(?:\r\n?|\n)(?:\1[ \t].*(?:\r\n?|\n))*\1End\2(?=[ \t]*$))|End[A-Z]\w*(?=[ \t]*$))/m,lookbehind:!0,greedy:!0,alias:"keyword"},property:{pattern:/^([ \t]*)(?!\s)[^\r\n"#=()]*[^\s"#=()](?=\s*=)/m,lookbehind:!0,inside:{guid:n}},guid:n,number:/\b\d+(?:\.\d+)*\b/,boolean:/\b(?:FALSE|TRUE)\b/,operator:/=/,punctuation:/[(),]/},t.languages.sln=t.languages["solution-file"]}e.exports=t,t.displayName="solutionFile",t.aliases=[]},38181(e,t,n){"use strict";var r=n(93205);function i(e){var t,n,i;e.register(r),n=/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,i=/\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b|\b0x[\dA-F]+\b/,(t=e).languages.soy={comment:[/\/\*[\s\S]*?\*\//,{pattern:/(\s)\/\/.*/,lookbehind:!0,greedy:!0}],"command-arg":{pattern:/(\{+\/?\s*(?:alias|call|delcall|delpackage|deltemplate|namespace|template)\s+)\.?[\w.]+/,lookbehind:!0,alias:"string",inside:{punctuation:/\./}},parameter:{pattern:/(\{+\/?\s*@?param\??\s+)\.?[\w.]+/,lookbehind:!0,alias:"variable"},keyword:[{pattern:/(\{+\/?[^\S\r\n]*)(?:\\[nrt]|alias|call|case|css|default|delcall|delpackage|deltemplate|else(?:if)?|fallbackmsg|for(?:each)?|if(?:empty)?|lb|let|literal|msg|namespace|nil|@?param\??|rb|sp|switch|template|xid)/,lookbehind:!0},/\b(?:any|as|attributes|bool|css|float|in|int|js|html|list|map|null|number|string|uri)\b/],delimiter:{pattern:/^\{+\/?|\/?\}+$/,alias:"punctuation"},property:/\w+(?==)/,variable:{pattern:/\$[^\W\d]\w*(?:\??(?:\.\w+|\[[^\]]+\]))*/,inside:{string:{pattern:n,greedy:!0},number:i,punctuation:/[\[\].?]/}},string:{pattern:n,greedy:!0},function:[/\w+(?=\()/,{pattern:/(\|[^\S\r\n]*)\w+/,lookbehind:!0}],boolean:/\b(?:true|false)\b/,number:i,operator:/\?:?|<=?|>=?|==?|!=|[+*/%-]|\b(?:and|not|or)\b/,punctuation:/[{}()\[\]|.,:]/},t.hooks.add("before-tokenize",function(e){var n=/\{\{.+?\}\}|\{.+?\}|\s\/\/.*|\/\*[\s\S]*?\*\//g,r="{literal}",i="{/literal}",a=!1;t.languages["markup-templating"].buildPlaceholders(e,"soy",n,function(e){return e===i&&(a=!1),!a&&(e===r&&(a=!0),!0)})}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"soy")})}e.exports=i,i.displayName="soy",i.aliases=[]},98774(e,t,n){"use strict";var r=n(24691);function i(e){e.register(r),e.languages.sparql=e.languages.extend("turtle",{boolean:/\b(?:true|false)\b/i,variable:{pattern:/[?$]\w+/,greedy:!0}}),e.languages.insertBefore("sparql","punctuation",{keyword:[/\b(?:A|ADD|ALL|AS|ASC|ASK|BNODE|BY|CLEAR|CONSTRUCT|COPY|CREATE|DATA|DEFAULT|DELETE|DESC|DESCRIBE|DISTINCT|DROP|EXISTS|FILTER|FROM|GROUP|HAVING|INSERT|INTO|LIMIT|LOAD|MINUS|MOVE|NAMED|NOT|NOW|OFFSET|OPTIONAL|ORDER|RAND|REDUCED|SELECT|SEPARATOR|SERVICE|SILENT|STRUUID|UNION|USING|UUID|VALUES|WHERE)\b/i,/\b(?:ABS|AVG|BIND|BOUND|CEIL|COALESCE|CONCAT|CONTAINS|COUNT|DATATYPE|DAY|ENCODE_FOR_URI|FLOOR|GROUP_CONCAT|HOURS|IF|IRI|isBLANK|isIRI|isLITERAL|isNUMERIC|isURI|LANG|LANGMATCHES|LCASE|MAX|MD5|MIN|MINUTES|MONTH|ROUND|REGEX|REPLACE|sameTerm|SAMPLE|SECONDS|SHA1|SHA256|SHA384|SHA512|STR|STRAFTER|STRBEFORE|STRDT|STRENDS|STRLANG|STRLEN|STRSTARTS|SUBSTR|SUM|TIMEZONE|TZ|UCASE|URI|YEAR)\b(?=\s*\()/i,/\b(?:GRAPH|BASE|PREFIX)\b/i]}),e.languages.rq=e.languages.sparql}e.exports=i,i.displayName="sparql",i.aliases=["rq"]},22855(e){"use strict";function t(e){e.languages["splunk-spl"]={comment:/`comment\("(?:\\.|[^\\"])*"\)`/,string:{pattern:/"(?:\\.|[^\\"])*"/,greedy:!0},keyword:/\b(?:abstract|accum|addcoltotals|addinfo|addtotals|analyzefields|anomalies|anomalousvalue|anomalydetection|append|appendcols|appendcsv|appendlookup|appendpipe|arules|associate|audit|autoregress|bin|bucket|bucketdir|chart|cluster|cofilter|collect|concurrency|contingency|convert|correlate|datamodel|dbinspect|dedup|delete|delta|diff|erex|eval|eventcount|eventstats|extract|fieldformat|fields|fieldsummary|filldown|fillnull|findtypes|folderize|foreach|format|from|gauge|gentimes|geom|geomfilter|geostats|head|highlight|history|iconify|input|inputcsv|inputlookup|iplocation|join|kmeans|kv|kvform|loadjob|localize|localop|lookup|makecontinuous|makemv|makeresults|map|mcollect|metadata|metasearch|meventcollect|mstats|multikv|multisearch|mvcombine|mvexpand|nomv|outlier|outputcsv|outputlookup|outputtext|overlap|pivot|predict|rangemap|rare|regex|relevancy|reltime|rename|replace|rest|return|reverse|rex|rtorder|run|savedsearch|script|scrub|search|searchtxn|selfjoin|sendemail|set|setfields|sichart|sirare|sistats|sitimechart|sitop|sort|spath|stats|strcat|streamstats|table|tags|tail|timechart|timewrap|top|transaction|transpose|trendline|tscollect|tstats|typeahead|typelearner|typer|union|uniq|untable|where|x11|xmlkv|xmlunescape|xpath|xyseries)\b/i,"operator-word":{pattern:/\b(?:and|as|by|not|or|xor)\b/i,alias:"operator"},function:/\b\w+(?=\s*\()/,property:/\b\w+(?=\s*=(?!=))/,date:{pattern:/\b\d{1,2}\/\d{1,2}\/\d{1,4}(?:(?::\d{1,2}){3})?\b/,alias:"number"},number:/\b\d+(?:\.\d+)?\b/,boolean:/\b(?:f|false|t|true)\b/i,operator:/[<>=]=?|[-+*/%|]/,punctuation:/[()[\],]/}}e.exports=t,t.displayName="splunkSpl",t.aliases=[]},29611(e){"use strict";function t(e){e.languages.sqf=e.languages.extend("clike",{string:{pattern:/"(?:(?:"")?[^"])*"(?!")|'(?:[^'])*'/,greedy:!0},keyword:/\b(?:breakOut|breakTo|call|case|catch|default|do|echo|else|execVM|execFSM|exitWith|for|forEach|forEachMember|forEachMemberAgent|forEachMemberTeam|from|goto|if|nil|preprocessFile|preprocessFileLineNumbers|private|scopeName|spawn|step|switch|then|throw|to|try|while|with)\b/i,boolean:/\b(?:true|false)\b/i,function:/\b(?:abs|accTime|acos|action|actionIDs|actionKeys|actionKeysImages|actionKeysNames|actionKeysNamesArray|actionName|actionParams|activateAddons|activatedAddons|activateKey|add3DENConnection|add3DENEventHandler|add3DENLayer|addAction|addBackpack|addBackpackCargo|addBackpackCargoGlobal|addBackpackGlobal|addCamShake|addCuratorAddons|addCuratorCameraArea|addCuratorEditableObjects|addCuratorEditingArea|addCuratorPoints|addEditorObject|addEventHandler|addForce|addForceGeneratorRTD|addGoggles|addGroupIcon|addHandgunItem|addHeadgear|addItem|addItemCargo|addItemCargoGlobal|addItemPool|addItemToBackpack|addItemToUniform|addItemToVest|addLiveStats|addMagazine|addMagazineAmmoCargo|addMagazineCargo|addMagazineCargoGlobal|addMagazineGlobal|addMagazinePool|addMagazines|addMagazineTurret|addMenu|addMenuItem|addMissionEventHandler|addMPEventHandler|addMusicEventHandler|addOwnedMine|addPlayerScores|addPrimaryWeaponItem|addPublicVariableEventHandler|addRating|addResources|addScore|addScoreSide|addSecondaryWeaponItem|addSwitchableUnit|addTeamMember|addToRemainsCollector|addTorque|addUniform|addVehicle|addVest|addWaypoint|addWeapon|addWeaponCargo|addWeaponCargoGlobal|addWeaponGlobal|addWeaponItem|addWeaponPool|addWeaponTurret|admin|agent|agents|AGLToASL|aimedAtTarget|aimPos|airDensityCurveRTD|airDensityRTD|airplaneThrottle|airportSide|AISFinishHeal|alive|all3DENEntities|allAirports|allControls|allCurators|allCutLayers|allDead|allDeadMen|allDisplays|allGroups|allMapMarkers|allMines|allMissionObjects|allow3DMode|allowCrewInImmobile|allowCuratorLogicIgnoreAreas|allowDamage|allowDammage|allowFileOperations|allowFleeing|allowGetIn|allowSprint|allPlayers|allSimpleObjects|allSites|allTurrets|allUnits|allUnitsUAV|allVariables|ammo|ammoOnPylon|animate|animateBay|animateDoor|animatePylon|animateSource|animationNames|animationPhase|animationSourcePhase|animationState|append|apply|armoryPoints|arrayIntersect|asin|ASLToAGL|ASLToATL|assert|assignAsCargo|assignAsCargoIndex|assignAsCommander|assignAsDriver|assignAsGunner|assignAsTurret|assignCurator|assignedCargo|assignedCommander|assignedDriver|assignedGunner|assignedItems|assignedTarget|assignedTeam|assignedVehicle|assignedVehicleRole|assignItem|assignTeam|assignToAirport|atan|atan2|atg|ATLToASL|attachedObject|attachedObjects|attachedTo|attachObject|attachTo|attackEnabled|backpack|backpackCargo|backpackContainer|backpackItems|backpackMagazines|backpackSpaceFor|behaviour|benchmark|binocular|blufor|boundingBox|boundingBoxReal|boundingCenter|briefingName|buildingExit|buildingPos|buldozer_EnableRoadDiag|buldozer_IsEnabledRoadDiag|buldozer_LoadNewRoads|buldozer_reloadOperMap|buttonAction|buttonSetAction|cadetMode|callExtension|camCommand|camCommit|camCommitPrepared|camCommitted|camConstuctionSetParams|camCreate|camDestroy|cameraEffect|cameraEffectEnableHUD|cameraInterest|cameraOn|cameraView|campaignConfigFile|camPreload|camPreloaded|camPrepareBank|camPrepareDir|camPrepareDive|camPrepareFocus|camPrepareFov|camPrepareFovRange|camPreparePos|camPrepareRelPos|camPrepareTarget|camSetBank|camSetDir|camSetDive|camSetFocus|camSetFov|camSetFovRange|camSetPos|camSetRelPos|camSetTarget|camTarget|camUseNVG|canAdd|canAddItemToBackpack|canAddItemToUniform|canAddItemToVest|cancelSimpleTaskDestination|canFire|canMove|canSlingLoad|canStand|canSuspend|canTriggerDynamicSimulation|canUnloadInCombat|canVehicleCargo|captive|captiveNum|cbChecked|cbSetChecked|ceil|channelEnabled|cheatsEnabled|checkAIFeature|checkVisibility|civilian|className|clear3DENAttribute|clear3DENInventory|clearAllItemsFromBackpack|clearBackpackCargo|clearBackpackCargoGlobal|clearForcesRTD|clearGroupIcons|clearItemCargo|clearItemCargoGlobal|clearItemPool|clearMagazineCargo|clearMagazineCargoGlobal|clearMagazinePool|clearOverlay|clearRadio|clearVehicleInit|clearWeaponCargo|clearWeaponCargoGlobal|clearWeaponPool|clientOwner|closeDialog|closeDisplay|closeOverlay|collapseObjectTree|collect3DENHistory|collectiveRTD|combatMode|commandArtilleryFire|commandChat|commander|commandFire|commandFollow|commandFSM|commandGetOut|commandingMenu|commandMove|commandRadio|commandStop|commandSuppressiveFire|commandTarget|commandWatch|comment|commitOverlay|compile|compileFinal|completedFSM|composeText|configClasses|configFile|configHierarchy|configName|configNull|configProperties|configSourceAddonList|configSourceMod|configSourceModList|confirmSensorTarget|connectTerminalToUAV|controlNull|controlsGroupCtrl|copyFromClipboard|copyToClipboard|copyWaypoints|cos|count|countEnemy|countFriendly|countSide|countType|countUnknown|create3DENComposition|create3DENEntity|createAgent|createCenter|createDialog|createDiaryLink|createDiaryRecord|createDiarySubject|createDisplay|createGearDialog|createGroup|createGuardedPoint|createLocation|createMarker|createMarkerLocal|createMenu|createMine|createMissionDisplay|createMPCampaignDisplay|createSimpleObject|createSimpleTask|createSite|createSoundSource|createTask|createTeam|createTrigger|createUnit|createVehicle|createVehicleCrew|createVehicleLocal|crew|ctAddHeader|ctAddRow|ctClear|ctCurSel|ctData|ctFindHeaderRows|ctFindRowHeader|ctHeaderControls|ctHeaderCount|ctRemoveHeaders|ctRemoveRows|ctrlActivate|ctrlAddEventHandler|ctrlAngle|ctrlAutoScrollDelay|ctrlAutoScrollRewind|ctrlAutoScrollSpeed|ctrlChecked|ctrlClassName|ctrlCommit|ctrlCommitted|ctrlCreate|ctrlDelete|ctrlEnable|ctrlEnabled|ctrlFade|ctrlHTMLLoaded|ctrlIDC|ctrlIDD|ctrlMapAnimAdd|ctrlMapAnimClear|ctrlMapAnimCommit|ctrlMapAnimDone|ctrlMapCursor|ctrlMapMouseOver|ctrlMapScale|ctrlMapScreenToWorld|ctrlMapWorldToScreen|ctrlModel|ctrlModelDirAndUp|ctrlModelScale|ctrlParent|ctrlParentControlsGroup|ctrlPosition|ctrlRemoveAllEventHandlers|ctrlRemoveEventHandler|ctrlScale|ctrlSetActiveColor|ctrlSetAngle|ctrlSetAutoScrollDelay|ctrlSetAutoScrollRewind|ctrlSetAutoScrollSpeed|ctrlSetBackgroundColor|ctrlSetChecked|ctrlSetDisabledColor|ctrlSetEventHandler|ctrlSetFade|ctrlSetFocus|ctrlSetFont|ctrlSetFontH1|ctrlSetFontH1B|ctrlSetFontH2|ctrlSetFontH2B|ctrlSetFontH3|ctrlSetFontH3B|ctrlSetFontH4|ctrlSetFontH4B|ctrlSetFontH5|ctrlSetFontH5B|ctrlSetFontH6|ctrlSetFontH6B|ctrlSetFontHeight|ctrlSetFontHeightH1|ctrlSetFontHeightH2|ctrlSetFontHeightH3|ctrlSetFontHeightH4|ctrlSetFontHeightH5|ctrlSetFontHeightH6|ctrlSetFontHeightSecondary|ctrlSetFontP|ctrlSetFontPB|ctrlSetFontSecondary|ctrlSetForegroundColor|ctrlSetModel|ctrlSetModelDirAndUp|ctrlSetModelScale|ctrlSetPixelPrecision|ctrlSetPosition|ctrlSetScale|ctrlSetStructuredText|ctrlSetText|ctrlSetTextColor|ctrlSetTextColorSecondary|ctrlSetTextSecondary|ctrlSetTooltip|ctrlSetTooltipColorBox|ctrlSetTooltipColorShade|ctrlSetTooltipColorText|ctrlShow|ctrlShown|ctrlText|ctrlTextHeight|ctrlTextSecondary|ctrlTextWidth|ctrlType|ctrlVisible|ctRowControls|ctRowCount|ctSetCurSel|ctSetData|ctSetHeaderTemplate|ctSetRowTemplate|ctSetValue|ctValue|curatorAddons|curatorCamera|curatorCameraArea|curatorCameraAreaCeiling|curatorCoef|curatorEditableObjects|curatorEditingArea|curatorEditingAreaType|curatorMouseOver|curatorPoints|curatorRegisteredObjects|curatorSelected|curatorWaypointCost|current3DENOperation|currentChannel|currentCommand|currentMagazine|currentMagazineDetail|currentMagazineDetailTurret|currentMagazineTurret|currentMuzzle|currentNamespace|currentTask|currentTasks|currentThrowable|currentVisionMode|currentWaypoint|currentWeapon|currentWeaponMode|currentWeaponTurret|currentZeroing|cursorObject|cursorTarget|customChat|customRadio|cutFadeOut|cutObj|cutRsc|cutText|damage|date|dateToNumber|daytime|deActivateKey|debriefingText|debugFSM|debugLog|deg|delete3DENEntities|deleteAt|deleteCenter|deleteCollection|deleteEditorObject|deleteGroup|deleteGroupWhenEmpty|deleteIdentity|deleteLocation|deleteMarker|deleteMarkerLocal|deleteRange|deleteResources|deleteSite|deleteStatus|deleteTeam|deleteVehicle|deleteVehicleCrew|deleteWaypoint|detach|detectedMines|diag_activeMissionFSMs|diag_activeScripts|diag_activeSQFScripts|diag_activeSQSScripts|diag_captureFrame|diag_captureFrameToFile|diag_captureSlowFrame|diag_codePerformance|diag_drawMode|diag_dynamicSimulationEnd|diag_enable|diag_enabled|diag_fps|diag_fpsMin|diag_frameNo|diag_lightNewLoad|diag_list|diag_log|diag_logSlowFrame|diag_mergeConfigFile|diag_recordTurretLimits|diag_setLightNew|diag_tickTime|diag_toggle|dialog|diarySubjectExists|didJIP|didJIPOwner|difficulty|difficultyEnabled|difficultyEnabledRTD|difficultyOption|direction|directSay|disableAI|disableCollisionWith|disableConversation|disableDebriefingStats|disableMapIndicators|disableNVGEquipment|disableRemoteSensors|disableSerialization|disableTIEquipment|disableUAVConnectability|disableUserInput|displayAddEventHandler|displayCtrl|displayNull|displayParent|displayRemoveAllEventHandlers|displayRemoveEventHandler|displaySetEventHandler|dissolveTeam|distance|distance2D|distanceSqr|distributionRegion|do3DENAction|doArtilleryFire|doFire|doFollow|doFSM|doGetOut|doMove|doorPhase|doStop|doSuppressiveFire|doTarget|doWatch|drawArrow|drawEllipse|drawIcon|drawIcon3D|drawLine|drawLine3D|drawLink|drawLocation|drawPolygon|drawRectangle|drawTriangle|driver|drop|dynamicSimulationDistance|dynamicSimulationDistanceCoef|dynamicSimulationEnabled|dynamicSimulationSystemEnabled|east|edit3DENMissionAttributes|editObject|editorSetEventHandler|effectiveCommander|emptyPositions|enableAI|enableAIFeature|enableAimPrecision|enableAttack|enableAudioFeature|enableAutoStartUpRTD|enableAutoTrimRTD|enableCamShake|enableCaustics|enableChannel|enableCollisionWith|enableCopilot|enableDebriefingStats|enableDiagLegend|enableDynamicSimulation|enableDynamicSimulationSystem|enableEndDialog|enableEngineArtillery|enableEnvironment|enableFatigue|enableGunLights|enableInfoPanelComponent|enableIRLasers|enableMimics|enablePersonTurret|enableRadio|enableReload|enableRopeAttach|enableSatNormalOnDetail|enableSaving|enableSentences|enableSimulation|enableSimulationGlobal|enableStamina|enableStressDamage|enableTeamSwitch|enableTraffic|enableUAVConnectability|enableUAVWaypoints|enableVehicleCargo|enableVehicleSensor|enableWeaponDisassembly|endl|endLoadingScreen|endMission|engineOn|enginesIsOnRTD|enginesPowerRTD|enginesRpmRTD|enginesTorqueRTD|entities|environmentEnabled|estimatedEndServerTime|estimatedTimeLeft|evalObjectArgument|everyBackpack|everyContainer|exec|execEditorScript|exp|expectedDestination|exportJIPMessages|eyeDirection|eyePos|face|faction|fadeMusic|fadeRadio|fadeSound|fadeSpeech|failMission|fillWeaponsFromPool|find|findCover|findDisplay|findEditorObject|findEmptyPosition|findEmptyPositionReady|findIf|findNearestEnemy|finishMissionInit|finite|fire|fireAtTarget|firstBackpack|flag|flagAnimationPhase|flagOwner|flagSide|flagTexture|fleeing|floor|flyInHeight|flyInHeightASL|fog|fogForecast|fogParams|forceAddUniform|forceAtPositionRTD|forcedMap|forceEnd|forceFlagTexture|forceFollowRoad|forceGeneratorRTD|forceMap|forceRespawn|forceSpeed|forceWalk|forceWeaponFire|forceWeatherChange|forgetTarget|format|formation|formationDirection|formationLeader|formationMembers|formationPosition|formationTask|formatText|formLeader|freeLook|fromEditor|fuel|fullCrew|gearIDCAmmoCount|gearSlotAmmoCount|gearSlotData|get3DENActionState|get3DENAttribute|get3DENCamera|get3DENConnections|get3DENEntity|get3DENEntityID|get3DENGrid|get3DENIconsVisible|get3DENLayerEntities|get3DENLinesVisible|get3DENMissionAttribute|get3DENMouseOver|get3DENSelected|getAimingCoef|getAllEnvSoundControllers|getAllHitPointsDamage|getAllOwnedMines|getAllSoundControllers|getAmmoCargo|getAnimAimPrecision|getAnimSpeedCoef|getArray|getArtilleryAmmo|getArtilleryComputerSettings|getArtilleryETA|getAssignedCuratorLogic|getAssignedCuratorUnit|getBackpackCargo|getBleedingRemaining|getBurningValue|getCameraViewDirection|getCargoIndex|getCenterOfMass|getClientState|getClientStateNumber|getCompatiblePylonMagazines|getConnectedUAV|getContainerMaxLoad|getCursorObjectParams|getCustomAimCoef|getDammage|getDescription|getDir|getDirVisual|getDLCAssetsUsage|getDLCAssetsUsageByName|getDLCs|getDLCUsageTime|getEditorCamera|getEditorMode|getEditorObjectScope|getElevationOffset|getEngineTargetRpmRTD|getEnvSoundController|getFatigue|getFieldManualStartPage|getForcedFlagTexture|getFriend|getFSMVariable|getFuelCargo|getGroupIcon|getGroupIconParams|getGroupIcons|getHideFrom|getHit|getHitIndex|getHitPointDamage|getItemCargo|getMagazineCargo|getMarkerColor|getMarkerPos|getMarkerSize|getMarkerType|getMass|getMissionConfig|getMissionConfigValue|getMissionDLCs|getMissionLayerEntities|getMissionLayers|getModelInfo|getMousePosition|getMusicPlayedTime|getNumber|getObjectArgument|getObjectChildren|getObjectDLC|getObjectMaterials|getObjectProxy|getObjectTextures|getObjectType|getObjectViewDistance|getOxygenRemaining|getPersonUsedDLCs|getPilotCameraDirection|getPilotCameraPosition|getPilotCameraRotation|getPilotCameraTarget|getPlateNumber|getPlayerChannel|getPlayerScores|getPlayerUID|getPlayerUIDOld|getPos|getPosASL|getPosASLVisual|getPosASLW|getPosATL|getPosATLVisual|getPosVisual|getPosWorld|getPylonMagazines|getRelDir|getRelPos|getRemoteSensorsDisabled|getRepairCargo|getResolution|getRotorBrakeRTD|getShadowDistance|getShotParents|getSlingLoad|getSoundController|getSoundControllerResult|getSpeed|getStamina|getStatValue|getSuppression|getTerrainGrid|getTerrainHeightASL|getText|getTotalDLCUsageTime|getTrimOffsetRTD|getUnitLoadout|getUnitTrait|getUserMFDText|getUserMFDValue|getVariable|getVehicleCargo|getWeaponCargo|getWeaponSway|getWingsOrientationRTD|getWingsPositionRTD|getWPPos|glanceAt|globalChat|globalRadio|goggles|group|groupChat|groupFromNetId|groupIconSelectable|groupIconsVisible|groupId|groupOwner|groupRadio|groupSelectedUnits|groupSelectUnit|grpNull|gunner|gusts|halt|handgunItems|handgunMagazine|handgunWeapon|handsHit|hasInterface|hasPilotCamera|hasWeapon|hcAllGroups|hcGroupParams|hcLeader|hcRemoveAllGroups|hcRemoveGroup|hcSelected|hcSelectGroup|hcSetGroup|hcShowBar|hcShownBar|headgear|hideBody|hideObject|hideObjectGlobal|hideSelection|hint|hintC|hintCadet|hintSilent|hmd|hostMission|htmlLoad|HUDMovementLevels|humidity|image|importAllGroups|importance|in|inArea|inAreaArray|incapacitatedState|independent|inflame|inflamed|infoPanel|infoPanelComponentEnabled|infoPanelComponents|infoPanels|inGameUISetEventHandler|inheritsFrom|initAmbientLife|inPolygon|inputAction|inRangeOfArtillery|insertEditorObject|intersect|is3DEN|is3DENMultiplayer|isAbleToBreathe|isAgent|isAimPrecisionEnabled|isArray|isAutoHoverOn|isAutonomous|isAutoStartUpEnabledRTD|isAutotest|isAutoTrimOnRTD|isBleeding|isBurning|isClass|isCollisionLightOn|isCopilotEnabled|isDamageAllowed|isDedicated|isDLCAvailable|isEngineOn|isEqualTo|isEqualType|isEqualTypeAll|isEqualTypeAny|isEqualTypeArray|isEqualTypeParams|isFilePatchingEnabled|isFlashlightOn|isFlatEmpty|isForcedWalk|isFormationLeader|isGroupDeletedWhenEmpty|isHidden|isInRemainsCollector|isInstructorFigureEnabled|isIRLaserOn|isKeyActive|isKindOf|isLaserOn|isLightOn|isLocalized|isManualFire|isMarkedForCollection|isMultiplayer|isMultiplayerSolo|isNil|isNull|isNumber|isObjectHidden|isObjectRTD|isOnRoad|isPipEnabled|isPlayer|isRealTime|isRemoteExecuted|isRemoteExecutedJIP|isServer|isShowing3DIcons|isSimpleObject|isSprintAllowed|isStaminaEnabled|isSteamMission|isStreamFriendlyUIEnabled|isStressDamageEnabled|isText|isTouchingGround|isTurnedOut|isTutHintsEnabled|isUAVConnectable|isUAVConnected|isUIContext|isUniformAllowed|isVehicleCargo|isVehicleRadarOn|isVehicleSensorEnabled|isWalking|isWeaponDeployed|isWeaponRested|itemCargo|items|itemsWithMagazines|join|joinAs|joinAsSilent|joinSilent|joinString|kbAddDatabase|kbAddDatabaseTargets|kbAddTopic|kbHasTopic|kbReact|kbRemoveTopic|kbTell|kbWasSaid|keyImage|keyName|knowsAbout|land|landAt|landResult|language|laserTarget|lbAdd|lbClear|lbColor|lbColorRight|lbCurSel|lbData|lbDelete|lbIsSelected|lbPicture|lbPictureRight|lbSelection|lbSetColor|lbSetColorRight|lbSetCurSel|lbSetData|lbSetPicture|lbSetPictureColor|lbSetPictureColorDisabled|lbSetPictureColorSelected|lbSetPictureRight|lbSetPictureRightColor|lbSetPictureRightColorDisabled|lbSetPictureRightColorSelected|lbSetSelectColor|lbSetSelectColorRight|lbSetSelected|lbSetText|lbSetTextRight|lbSetTooltip|lbSetValue|lbSize|lbSort|lbSortByValue|lbText|lbTextRight|lbValue|leader|leaderboardDeInit|leaderboardGetRows|leaderboardInit|leaderboardRequestRowsFriends|leaderboardRequestRowsGlobal|leaderboardRequestRowsGlobalAroundUser|leaderboardsRequestUploadScore|leaderboardsRequestUploadScoreKeepBest|leaderboardState|leaveVehicle|libraryCredits|libraryDisclaimers|lifeState|lightAttachObject|lightDetachObject|lightIsOn|lightnings|limitSpeed|linearConversion|lineBreak|lineIntersects|lineIntersectsObjs|lineIntersectsSurfaces|lineIntersectsWith|linkItem|list|listObjects|listRemoteTargets|listVehicleSensors|ln|lnbAddArray|lnbAddColumn|lnbAddRow|lnbClear|lnbColor|lnbColorRight|lnbCurSelRow|lnbData|lnbDeleteColumn|lnbDeleteRow|lnbGetColumnsPosition|lnbPicture|lnbPictureRight|lnbSetColor|lnbSetColorRight|lnbSetColumnsPos|lnbSetCurSelRow|lnbSetData|lnbSetPicture|lnbSetPictureColor|lnbSetPictureColorRight|lnbSetPictureColorSelected|lnbSetPictureColorSelectedRight|lnbSetPictureRight|lnbSetText|lnbSetTextRight|lnbSetValue|lnbSize|lnbSort|lnbSortByValue|lnbText|lnbTextRight|lnbValue|load|loadAbs|loadBackpack|loadFile|loadGame|loadIdentity|loadMagazine|loadOverlay|loadStatus|loadUniform|loadVest|local|localize|locationNull|locationPosition|lock|lockCameraTo|lockCargo|lockDriver|locked|lockedCargo|lockedDriver|lockedTurret|lockIdentity|lockTurret|lockWP|log|logEntities|logNetwork|logNetworkTerminate|lookAt|lookAtPos|magazineCargo|magazines|magazinesAllTurrets|magazinesAmmo|magazinesAmmoCargo|magazinesAmmoFull|magazinesDetail|magazinesDetailBackpack|magazinesDetailUniform|magazinesDetailVest|magazinesTurret|magazineTurretAmmo|mapAnimAdd|mapAnimClear|mapAnimCommit|mapAnimDone|mapCenterOnCamera|mapGridPosition|markAsFinishedOnSteam|markerAlpha|markerBrush|markerColor|markerDir|markerPos|markerShape|markerSize|markerText|markerType|max|members|menuAction|menuAdd|menuChecked|menuClear|menuCollapse|menuData|menuDelete|menuEnable|menuEnabled|menuExpand|menuHover|menuPicture|menuSetAction|menuSetCheck|menuSetData|menuSetPicture|menuSetValue|menuShortcut|menuShortcutText|menuSize|menuSort|menuText|menuURL|menuValue|min|mineActive|mineDetectedBy|missionConfigFile|missionDifficulty|missionName|missionNamespace|missionStart|missionVersion|modelToWorld|modelToWorldVisual|modelToWorldVisualWorld|modelToWorldWorld|modParams|moonIntensity|moonPhase|morale|move|move3DENCamera|moveInAny|moveInCargo|moveInCommander|moveInDriver|moveInGunner|moveInTurret|moveObjectToEnd|moveOut|moveTime|moveTo|moveToCompleted|moveToFailed|musicVolume|name|nameSound|nearEntities|nearestBuilding|nearestLocation|nearestLocations|nearestLocationWithDubbing|nearestObject|nearestObjects|nearestTerrainObjects|nearObjects|nearObjectsReady|nearRoads|nearSupplies|nearTargets|needReload|netId|netObjNull|newOverlay|nextMenuItemIndex|nextWeatherChange|nMenuItems|numberOfEnginesRTD|numberToDate|objectCurators|objectFromNetId|objectParent|objNull|objStatus|onBriefingGear|onBriefingGroup|onBriefingNotes|onBriefingPlan|onBriefingTeamSwitch|onCommandModeChanged|onDoubleClick|onEachFrame|onGroupIconClick|onGroupIconOverEnter|onGroupIconOverLeave|onHCGroupSelectionChanged|onMapSingleClick|onPlayerConnected|onPlayerDisconnected|onPreloadFinished|onPreloadStarted|onShowNewObject|onTeamSwitch|openCuratorInterface|openDLCPage|openDSInterface|openMap|openSteamApp|openYoutubeVideo|opfor|orderGetIn|overcast|overcastForecast|owner|param|params|parseNumber|parseSimpleArray|parseText|parsingNamespace|particlesQuality|pi|pickWeaponPool|pitch|pixelGrid|pixelGridBase|pixelGridNoUIScale|pixelH|pixelW|playableSlotsNumber|playableUnits|playAction|playActionNow|player|playerRespawnTime|playerSide|playersNumber|playGesture|playMission|playMove|playMoveNow|playMusic|playScriptedMission|playSound|playSound3D|position|positionCameraToWorld|posScreenToWorld|posWorldToScreen|ppEffectAdjust|ppEffectCommit|ppEffectCommitted|ppEffectCreate|ppEffectDestroy|ppEffectEnable|ppEffectEnabled|ppEffectForceInNVG|precision|preloadCamera|preloadObject|preloadSound|preloadTitleObj|preloadTitleRsc|primaryWeapon|primaryWeaponItems|primaryWeaponMagazine|priority|processDiaryLink|processInitCommands|productVersion|profileName|profileNamespace|profileNameSteam|progressLoadingScreen|progressPosition|progressSetPosition|publicVariable|publicVariableClient|publicVariableServer|pushBack|pushBackUnique|putWeaponPool|queryItemsPool|queryMagazinePool|queryWeaponPool|rad|radioChannelAdd|radioChannelCreate|radioChannelRemove|radioChannelSetCallSign|radioChannelSetLabel|radioVolume|rain|rainbow|random|rank|rankId|rating|rectangular|registeredTasks|registerTask|reload|reloadEnabled|remoteControl|remoteExec|remoteExecCall|remoteExecutedOwner|remove3DENConnection|remove3DENEventHandler|remove3DENLayer|removeAction|removeAll3DENEventHandlers|removeAllActions|removeAllAssignedItems|removeAllContainers|removeAllCuratorAddons|removeAllCuratorCameraAreas|removeAllCuratorEditingAreas|removeAllEventHandlers|removeAllHandgunItems|removeAllItems|removeAllItemsWithMagazines|removeAllMissionEventHandlers|removeAllMPEventHandlers|removeAllMusicEventHandlers|removeAllOwnedMines|removeAllPrimaryWeaponItems|removeAllWeapons|removeBackpack|removeBackpackGlobal|removeCuratorAddons|removeCuratorCameraArea|removeCuratorEditableObjects|removeCuratorEditingArea|removeDrawIcon|removeDrawLinks|removeEventHandler|removeFromRemainsCollector|removeGoggles|removeGroupIcon|removeHandgunItem|removeHeadgear|removeItem|removeItemFromBackpack|removeItemFromUniform|removeItemFromVest|removeItems|removeMagazine|removeMagazineGlobal|removeMagazines|removeMagazinesTurret|removeMagazineTurret|removeMenuItem|removeMissionEventHandler|removeMPEventHandler|removeMusicEventHandler|removeOwnedMine|removePrimaryWeaponItem|removeSecondaryWeaponItem|removeSimpleTask|removeSwitchableUnit|removeTeamMember|removeUniform|removeVest|removeWeapon|removeWeaponAttachmentCargo|removeWeaponCargo|removeWeaponGlobal|removeWeaponTurret|reportRemoteTarget|requiredVersion|resetCamShake|resetSubgroupDirection|resistance|resize|resources|respawnVehicle|restartEditorCamera|reveal|revealMine|reverse|reversedMouseY|roadAt|roadsConnectedTo|roleDescription|ropeAttachedObjects|ropeAttachedTo|ropeAttachEnabled|ropeAttachTo|ropeCreate|ropeCut|ropeDestroy|ropeDetach|ropeEndPosition|ropeLength|ropes|ropeUnwind|ropeUnwound|rotorsForcesRTD|rotorsRpmRTD|round|runInitScript|safeZoneH|safeZoneW|safeZoneWAbs|safeZoneX|safeZoneXAbs|safeZoneY|save3DENInventory|saveGame|saveIdentity|saveJoysticks|saveOverlay|saveProfileNamespace|saveStatus|saveVar|savingEnabled|say|say2D|say3D|score|scoreSide|screenshot|screenToWorld|scriptDone|scriptName|scriptNull|scudState|secondaryWeapon|secondaryWeaponItems|secondaryWeaponMagazine|select|selectBestPlaces|selectDiarySubject|selectedEditorObjects|selectEditorObject|selectionNames|selectionPosition|selectLeader|selectMax|selectMin|selectNoPlayer|selectPlayer|selectRandom|selectRandomWeighted|selectWeapon|selectWeaponTurret|sendAUMessage|sendSimpleCommand|sendTask|sendTaskResult|sendUDPMessage|serverCommand|serverCommandAvailable|serverCommandExecutable|serverName|serverTime|set|set3DENAttribute|set3DENAttributes|set3DENGrid|set3DENIconsVisible|set3DENLayer|set3DENLinesVisible|set3DENLogicType|set3DENMissionAttribute|set3DENMissionAttributes|set3DENModelsVisible|set3DENObjectType|set3DENSelected|setAccTime|setActualCollectiveRTD|setAirplaneThrottle|setAirportSide|setAmmo|setAmmoCargo|setAmmoOnPylon|setAnimSpeedCoef|setAperture|setApertureNew|setArmoryPoints|setAttributes|setAutonomous|setBehaviour|setBleedingRemaining|setBrakesRTD|setCameraInterest|setCamShakeDefParams|setCamShakeParams|setCamUseTI|setCaptive|setCenterOfMass|setCollisionLight|setCombatMode|setCompassOscillation|setConvoySeparation|setCuratorCameraAreaCeiling|setCuratorCoef|setCuratorEditingAreaType|setCuratorWaypointCost|setCurrentChannel|setCurrentTask|setCurrentWaypoint|setCustomAimCoef|setCustomWeightRTD|setDamage|setDammage|setDate|setDebriefingText|setDefaultCamera|setDestination|setDetailMapBlendPars|setDir|setDirection|setDrawIcon|setDriveOnPath|setDropInterval|setDynamicSimulationDistance|setDynamicSimulationDistanceCoef|setEditorMode|setEditorObjectScope|setEffectCondition|setEngineRpmRTD|setFace|setFaceAnimation|setFatigue|setFeatureType|setFlagAnimationPhase|setFlagOwner|setFlagSide|setFlagTexture|setFog|setForceGeneratorRTD|setFormation|setFormationTask|setFormDir|setFriend|setFromEditor|setFSMVariable|setFuel|setFuelCargo|setGroupIcon|setGroupIconParams|setGroupIconsSelectable|setGroupIconsVisible|setGroupId|setGroupIdGlobal|setGroupOwner|setGusts|setHideBehind|setHit|setHitIndex|setHitPointDamage|setHorizonParallaxCoef|setHUDMovementLevels|setIdentity|setImportance|setInfoPanel|setLeader|setLightAmbient|setLightAttenuation|setLightBrightness|setLightColor|setLightDayLight|setLightFlareMaxDistance|setLightFlareSize|setLightIntensity|setLightnings|setLightUseFlare|setLocalWindParams|setMagazineTurretAmmo|setMarkerAlpha|setMarkerAlphaLocal|setMarkerBrush|setMarkerBrushLocal|setMarkerColor|setMarkerColorLocal|setMarkerDir|setMarkerDirLocal|setMarkerPos|setMarkerPosLocal|setMarkerShape|setMarkerShapeLocal|setMarkerSize|setMarkerSizeLocal|setMarkerText|setMarkerTextLocal|setMarkerType|setMarkerTypeLocal|setMass|setMimic|setMousePosition|setMusicEffect|setMusicEventHandler|setName|setNameSound|setObjectArguments|setObjectMaterial|setObjectMaterialGlobal|setObjectProxy|setObjectTexture|setObjectTextureGlobal|setObjectViewDistance|setOvercast|setOwner|setOxygenRemaining|setParticleCircle|setParticleClass|setParticleFire|setParticleParams|setParticleRandom|setPilotCameraDirection|setPilotCameraRotation|setPilotCameraTarget|setPilotLight|setPiPEffect|setPitch|setPlateNumber|setPlayable|setPlayerRespawnTime|setPos|setPosASL|setPosASL2|setPosASLW|setPosATL|setPosition|setPosWorld|setPylonLoadOut|setPylonsPriority|setRadioMsg|setRain|setRainbow|setRandomLip|setRank|setRectangular|setRepairCargo|setRotorBrakeRTD|setShadowDistance|setShotParents|setSide|setSimpleTaskAlwaysVisible|setSimpleTaskCustomData|setSimpleTaskDescription|setSimpleTaskDestination|setSimpleTaskTarget|setSimpleTaskType|setSimulWeatherLayers|setSize|setSkill|setSlingLoad|setSoundEffect|setSpeaker|setSpeech|setSpeedMode|setStamina|setStaminaScheme|setStatValue|setSuppression|setSystemOfUnits|setTargetAge|setTaskMarkerOffset|setTaskResult|setTaskState|setTerrainGrid|setText|setTimeMultiplier|setTitleEffect|setToneMapping|setToneMappingParams|setTrafficDensity|setTrafficDistance|setTrafficGap|setTrafficSpeed|setTriggerActivation|setTriggerArea|setTriggerStatements|setTriggerText|setTriggerTimeout|setTriggerType|setType|setUnconscious|setUnitAbility|setUnitLoadout|setUnitPos|setUnitPosWeak|setUnitRank|setUnitRecoilCoefficient|setUnitTrait|setUnloadInCombat|setUserActionText|setUserMFDText|setUserMFDValue|setVariable|setVectorDir|setVectorDirAndUp|setVectorUp|setVehicleAmmo|setVehicleAmmoDef|setVehicleArmor|setVehicleCargo|setVehicleId|setVehicleInit|setVehicleLock|setVehiclePosition|setVehicleRadar|setVehicleReceiveRemoteTargets|setVehicleReportOwnPosition|setVehicleReportRemoteTargets|setVehicleTIPars|setVehicleVarName|setVelocity|setVelocityModelSpace|setVelocityTransformation|setViewDistance|setVisibleIfTreeCollapsed|setWantedRpmRTD|setWaves|setWaypointBehaviour|setWaypointCombatMode|setWaypointCompletionRadius|setWaypointDescription|setWaypointForceBehaviour|setWaypointFormation|setWaypointHousePosition|setWaypointLoiterRadius|setWaypointLoiterType|setWaypointName|setWaypointPosition|setWaypointScript|setWaypointSpeed|setWaypointStatements|setWaypointTimeout|setWaypointType|setWaypointVisible|setWeaponReloadingTime|setWind|setWindDir|setWindForce|setWindStr|setWingForceScaleRTD|setWPPos|show3DIcons|showChat|showCinemaBorder|showCommandingMenu|showCompass|showCuratorCompass|showGPS|showHUD|showLegend|showMap|shownArtilleryComputer|shownChat|shownCompass|shownCuratorCompass|showNewEditorObject|shownGPS|shownHUD|shownMap|shownPad|shownRadio|shownScoretable|shownUAVFeed|shownWarrant|shownWatch|showPad|showRadio|showScoretable|showSubtitles|showUAVFeed|showWarrant|showWatch|showWaypoint|showWaypoints|side|sideAmbientLife|sideChat|sideEmpty|sideEnemy|sideFriendly|sideLogic|sideRadio|sideUnknown|simpleTasks|simulationEnabled|simulCloudDensity|simulCloudOcclusion|simulInClouds|simulWeatherSync|sin|size|sizeOf|skill|skillFinal|skipTime|sleep|sliderPosition|sliderRange|sliderSetPosition|sliderSetRange|sliderSetSpeed|sliderSpeed|slingLoadAssistantShown|soldierMagazines|someAmmo|sort|soundVolume|speaker|speed|speedMode|splitString|sqrt|squadParams|stance|startLoadingScreen|stop|stopEngineRTD|stopped|str|sunOrMoon|supportInfo|suppressFor|surfaceIsWater|surfaceNormal|surfaceType|swimInDepth|switchableUnits|switchAction|switchCamera|switchGesture|switchLight|switchMove|synchronizedObjects|synchronizedTriggers|synchronizedWaypoints|synchronizeObjectsAdd|synchronizeObjectsRemove|synchronizeTrigger|synchronizeWaypoint|systemChat|systemOfUnits|tan|targetKnowledge|targets|targetsAggregate|targetsQuery|taskAlwaysVisible|taskChildren|taskCompleted|taskCustomData|taskDescription|taskDestination|taskHint|taskMarkerOffset|taskNull|taskParent|taskResult|taskState|taskType|teamMember|teamMemberNull|teamName|teams|teamSwitch|teamSwitchEnabled|teamType|terminate|terrainIntersect|terrainIntersectASL|terrainIntersectAtASL|text|textLog|textLogFormat|tg|time|timeMultiplier|titleCut|titleFadeOut|titleObj|titleRsc|titleText|toArray|toFixed|toLower|toString|toUpper|triggerActivated|triggerActivation|triggerArea|triggerAttachedVehicle|triggerAttachObject|triggerAttachVehicle|triggerDynamicSimulation|triggerStatements|triggerText|triggerTimeout|triggerTimeoutCurrent|triggerType|turretLocal|turretOwner|turretUnit|tvAdd|tvClear|tvCollapse|tvCollapseAll|tvCount|tvCurSel|tvData|tvDelete|tvExpand|tvExpandAll|tvPicture|tvPictureRight|tvSetColor|tvSetCurSel|tvSetData|tvSetPicture|tvSetPictureColor|tvSetPictureColorDisabled|tvSetPictureColorSelected|tvSetPictureRight|tvSetPictureRightColor|tvSetPictureRightColorDisabled|tvSetPictureRightColorSelected|tvSetSelectColor|tvSetText|tvSetTooltip|tvSetValue|tvSort|tvSortByValue|tvText|tvTooltip|tvValue|type|typeName|typeOf|UAVControl|uiNamespace|uiSleep|unassignCurator|unassignItem|unassignTeam|unassignVehicle|underwater|uniform|uniformContainer|uniformItems|uniformMagazines|unitAddons|unitAimPosition|unitAimPositionVisual|unitBackpack|unitIsUAV|unitPos|unitReady|unitRecoilCoefficient|units|unitsBelowHeight|unlinkItem|unlockAchievement|unregisterTask|updateDrawIcon|updateMenuItem|updateObjectTree|useAIOperMapObstructionTest|useAISteeringComponent|useAudioTimeForMoves|userInputDisabled|vectorAdd|vectorCos|vectorCrossProduct|vectorDiff|vectorDir|vectorDirVisual|vectorDistance|vectorDistanceSqr|vectorDotProduct|vectorFromTo|vectorMagnitude|vectorMagnitudeSqr|vectorModelToWorld|vectorModelToWorldVisual|vectorMultiply|vectorNormalized|vectorUp|vectorUpVisual|vectorWorldToModel|vectorWorldToModelVisual|vehicle|vehicleCargoEnabled|vehicleChat|vehicleRadio|vehicleReceiveRemoteTargets|vehicleReportOwnPosition|vehicleReportRemoteTargets|vehicles|vehicleVarName|velocity|velocityModelSpace|verifySignature|vest|vestContainer|vestItems|vestMagazines|viewDistance|visibleCompass|visibleGPS|visibleMap|visiblePosition|visiblePositionASL|visibleScoretable|visibleWatch|waitUntil|waves|waypointAttachedObject|waypointAttachedVehicle|waypointAttachObject|waypointAttachVehicle|waypointBehaviour|waypointCombatMode|waypointCompletionRadius|waypointDescription|waypointForceBehaviour|waypointFormation|waypointHousePosition|waypointLoiterRadius|waypointLoiterType|waypointName|waypointPosition|waypoints|waypointScript|waypointsEnabledUAV|waypointShow|waypointSpeed|waypointStatements|waypointTimeout|waypointTimeoutCurrent|waypointType|waypointVisible|weaponAccessories|weaponAccessoriesCargo|weaponCargo|weaponDirection|weaponInertia|weaponLowered|weapons|weaponsItems|weaponsItemsCargo|weaponState|weaponsTurret|weightRTD|west|WFSideText|wind|windDir|windRTD|windStr|wingsForcesRTD|worldName|worldSize|worldToModel|worldToModelVisual|worldToScreen)\b/i,number:/(?:\$|\b0x)[\da-f]+\b|(?:\B\.\d+|\b\d+(?:\.\d+)?)(?:e[+-]?\d+)?\b/i,operator:/##|>>|&&|\|\||[!=<>]=?|[-+*/%#^]|\b(?:and|mod|not|or)\b/i,"magic-variable":{pattern:/\b(?:_exception|_fnc_scriptName|_fnc_scriptNameParent|_forEachIndex|_this|_thisEventHandler|_thisFSM|_thisScript|_x|this|thisList|thisTrigger)\b/i,alias:"keyword"},constant:/\bDIK(?:_[a-z\d]+)+\b/i}),e.languages.insertBefore("sqf","string",{macro:{pattern:/(^[ \t]*)#[a-z](?:[^\r\n\\]|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{directive:{pattern:/#[a-z]+\b/i,alias:"keyword"},comment:e.languages.sqf.comment}}}),delete e.languages.sqf["class-name"]}e.exports=t,t.displayName="sqf",t.aliases=[]},11114(e){"use strict";function t(e){e.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:S|ING)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|IN|ILIKE|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/}}e.exports=t,t.displayName="sql",t.aliases=[]},67386(e){"use strict";function t(e){e.languages.squirrel=e.languages.extend("clike",{comment:[e.languages.clike.comment[0],{pattern:/(^|[^\\:])(?:\/\/|#).*/,lookbehind:!0,greedy:!0}],string:[{pattern:/(^|[^\\"'@])(?:@"(?:[^"]|"")*"(?!")|"(?:[^\\\r\n"]|\\.)*")/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\"'])'(?:[^\\']|\\(?:[xuU][0-9a-fA-F]{0,8}|[\s\S]))'/,lookbehind:!0,greedy:!0}],"class-name":{pattern:/(\b(?:class|enum|extends|instanceof)\s+)\w+(?:\.\w+)*/,lookbehind:!0,inside:{punctuation:/\./}},keyword:/\b(?:base|break|case|catch|class|clone|const|constructor|continue|default|delete|else|enum|extends|for|foreach|function|if|in|instanceof|local|null|resume|return|static|switch|this|throw|try|typeof|while|yield|__LINE__|__FILE__)\b/,number:/\b(?:0x[0-9a-fA-F]+|\d+(?:\.(?:\d+|[eE][+-]?\d+))?)\b/,operator:/\+\+|--|<=>|<[-<]|>>>?|&&?|\|\|?|[-+*/%!=<>]=?|[~^]|::?/,punctuation:/[(){}\[\],;.]/}),e.languages.insertBefore("squirrel","operator",{"attribute-punctuation":{pattern:/<\/|\/>/,alias:"important"},lambda:{pattern:/@(?=\()/,alias:"operator"}})}e.exports=t,t.displayName="squirrel",t.aliases=[]},28067(e){"use strict";function t(e){e.languages.stan={comment:/\/\/.*|\/\*[\s\S]*?\*\/|#(?!include).*/,string:{pattern:/"[\x20\x21\x23-\x5B\x5D-\x7E]*"/,greedy:!0},directive:{pattern:/^([ \t]*)#include\b.*/m,lookbehind:!0,alias:"property"},"function-arg":{pattern:/(\b(?:algebra_solver|integrate_1d|integrate_ode|integrate_ode_bdf|integrate_ode_rk45|map_rect)\s*\(\s*)[a-zA-Z]\w*/,lookbehind:!0,alias:"function"},constraint:{pattern:/(\b(?:int|matrix|real|row_vector|vector)\s*)<[^<>]*>/,lookbehind:!0,inside:{expression:{pattern:/(=\s*)\S(?:\S|\s+(?!\s))*?(?=\s*(?:>$|,\s*\w+\s*=))/,lookbehind:!0,inside:null},property:/\b[a-z]\w*(?=\s*=)/i,operator:/=/,punctuation:/^<|>$|,/}},keyword:[/\b(?:break|cholesky_factor_corr|cholesky_factor_cov|continue|corr_matrix|cov_matrix|data|else|for|functions|generated|if|in|increment_log_prob|int|matrix|model|ordered|parameters|positive_ordered|print|quantities|real|reject|return|row_vector|simplex|target|transformed|unit_vector|vector|void|while)\b/,/\b(?:algebra_solver|integrate_1d|integrate_ode|integrate_ode_bdf|integrate_ode_rk45|map_rect)\b/],function:/\b[a-z]\w*(?=\s*\()/i,number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,operator:/<-|\.[*/]=?|\|\|?|&&|[!=<>+\-*/]=?|['^%~?:]/,punctuation:/[()\[\]{},;]/},e.languages.stan.constraint.inside.expression.inside=e.languages.stan}e.exports=t,t.displayName="stan",t.aliases=[]},49168(e){"use strict";function t(e){var t,n,r,i;t=e,(i={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:if|else|for|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:rgb|hsl)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:rgb|hsl)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:n={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},number:r={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:n,boolean:/\b(?:true|false)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:r,punctuation:/[{}()\[\];:,]/}).interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:i}},i.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:i}},t.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:i}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:i}},statement:{pattern:/(^[ \t]*)(?:if|else|for|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:i}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:i.interpolation}},rest:i}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:i.interpolation,comment:i.comment,punctuation:/[{},]/}},func:i.func,string:i.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:i.interpolation,punctuation:/[{}()\[\];:.]/}}e.exports=t,t.displayName="stylus",t.aliases=[]},23651(e){"use strict";function t(e){e.languages.swift=e.languages.extend("clike",{string:{pattern:/("|')(?:\\(?:\((?:[^()]|\([^)]+\))+\)|\r\n|[^(])|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{interpolation:{pattern:/\\\((?:[^()]|\([^)]+\))+\)/,inside:{delimiter:{pattern:/^\\\(|\)$/,alias:"variable"}}}}},keyword:/\b(?:as|associativity|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic(?:Type)?|else|enum|extension|fallthrough|final|for|func|get|guard|if|import|in|infix|init|inout|internal|is|lazy|left|let|mutating|new|none|nonmutating|operator|optional|override|postfix|precedence|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|Self|set|some|static|struct|subscript|super|switch|throws?|try|Type|typealias|unowned|unsafe|var|weak|where|while|willSet|__(?:COLUMN__|FILE__|FUNCTION__|LINE__))\b/,number:/\b(?:[\d_]+(?:\.[\de_]+)?|0x[a-f0-9_]+(?:\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i,constant:/\b(?:nil|[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/,atrule:/@\b(?:IB(?:Outlet|Designable|Action|Inspectable)|class_protocol|exported|noreturn|NS(?:Copying|Managed)|objc|UIApplicationMain|auto_closure)\b/,builtin:/\b(?:[A-Z]\S+|abs|advance|alignof(?:Value)?|assert|contains|count(?:Elements)?|debugPrint(?:ln)?|distance|drop(?:First|Last)|dump|enumerate|equal|filter|find|first|getVaList|indices|isEmpty|join|last|lexicographicalCompare|map|max(?:Element)?|min(?:Element)?|numericCast|overlaps|partition|print(?:ln)?|reduce|reflect|reverse|sizeof(?:Value)?|sort(?:ed)?|split|startsWith|stride(?:of(?:Value)?)?|suffix|swap|toDebugString|toString|transcode|underestimateCount|unsafeBitCast|with(?:ExtendedLifetime|Unsafe(?:MutablePointers?|Pointers?)|VaList))\b/}),e.languages.swift.string.inside.interpolation.inside.rest=e.languages.swift}e.exports=t,t.displayName="swift",t.aliases=[]},32268(e,t,n){"use strict";var r=n(2329),i=n(61958);function a(e){e.register(r),e.register(i),e.languages.t4=e.languages["t4-cs"]=e.languages["t4-templating"].createT4("csharp")}e.exports=a,a.displayName="t4Cs",a.aliases=[]},2329(e){"use strict";function t(e){!function(e){function t(e,t,n){return{pattern:RegExp("<#"+e+"[\\s\\S]*?#>"),alias:"block",inside:{delimiter:{pattern:RegExp("^<#"+e+"|#>$"),alias:"important"},content:{pattern:/[\s\S]+/,inside:t,alias:n}}}}function n(n){var r=e.languages[n],i="language-"+n;return{block:{pattern:/<#[\s\S]+?#>/,inside:{directive:t("@",{"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/,inside:{punctuation:/^=|^["']|["']$/}},keyword:/\b\w+(?=\s)/,"attr-name":/\b\w+/}),expression:t("=",r,i),"class-feature":t("\\+",r,i),standard:t("",r,i)}}}}e.languages["t4-templating"]=Object.defineProperty({},"createT4",{value:n})}(e)}e.exports=t,t.displayName="t4Templating",t.aliases=[]},82996(e,t,n){"use strict";var r=n(2329),i=n(53813);function a(e){e.register(r),e.register(i),e.languages["t4-vb"]=e.languages["t4-templating"].createT4("vbnet")}e.exports=a,a.displayName="t4Vb",a.aliases=[]},17290(e,t,n){"use strict";var r=n(65039);function i(e){e.register(r),e.languages.tap={fail:/not ok[^#{\n\r]*/,pass:/ok[^#{\n\r]*/,pragma:/pragma [+-][a-z]+/,bailout:/bail out!.*/i,version:/TAP version \d+/i,plan:/\b\d+\.\.\d+(?: +#.*)?/,subtest:{pattern:/# Subtest(?:: .*)?/,greedy:!0},punctuation:/[{}]/,directive:/#.*/,yamlish:{pattern:/(^[ \t]*)---[\s\S]*?[\r\n][ \t]*\.\.\.$/m,lookbehind:!0,inside:e.languages.yaml,alias:"language-yaml"}}}e.exports=i,i.displayName="tap",i.aliases=[]},67989(e){"use strict";function t(e){e.languages.tcl={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:{pattern:/"(?:[^"\\\r\n]|\\(?:\r\n|[\s\S]))*"/,greedy:!0},variable:[{pattern:/(\$)(?:::)?(?:[a-zA-Z0-9]+::)*\w+/,lookbehind:!0},{pattern:/(\$)\{[^}]+\}/,lookbehind:!0},{pattern:/(^[\t ]*set[ \t]+)(?:::)?(?:[a-zA-Z0-9]+::)*\w+/m,lookbehind:!0}],function:{pattern:/(^[\t ]*proc[ \t]+)\S+/m,lookbehind:!0},builtin:[{pattern:/(^[\t ]*)(?:proc|return|class|error|eval|exit|for|foreach|if|switch|while|break|continue)\b/m,lookbehind:!0},/\b(?:elseif|else)\b/],scope:{pattern:/(^[\t ]*)(?:global|upvar|variable)\b/m,lookbehind:!0,alias:"constant"},keyword:{pattern:/(^[\t ]*|\[)(?:after|append|apply|array|auto_(?:execok|import|load|mkindex|qualify|reset)|automkindex_old|bgerror|binary|catch|cd|chan|clock|close|concat|dde|dict|encoding|eof|exec|expr|fblocked|fconfigure|fcopy|file(?:event|name)?|flush|gets|glob|history|http|incr|info|interp|join|lappend|lassign|lindex|linsert|list|llength|load|lrange|lrepeat|lreplace|lreverse|lsearch|lset|lsort|math(?:func|op)|memory|msgcat|namespace|open|package|parray|pid|pkg_mkIndex|platform|puts|pwd|re_syntax|read|refchan|regexp|registry|regsub|rename|Safe_Base|scan|seek|set|socket|source|split|string|subst|Tcl|tcl(?:_endOfWord|_findLibrary|startOf(?:Next|Previous)Word|wordBreak(?:After|Before)|test|vars)|tell|time|tm|trace|unknown|unload|unset|update|uplevel|vwait)\b/m,lookbehind:!0},operator:/!=?|\*\*?|==|&&?|\|\|?|<[=<]?|>[=>]?|[-+~\/%?^]|\b(?:eq|ne|in|ni)\b/,punctuation:/[{}()\[\]]/}}e.exports=t,t.displayName="tcl",t.aliases=[]},31065(e){"use strict";function t(e){!function(e){var t=/\([^|()\n]+\)|\[[^\]\n]+\]|\{[^}\n]+\}/.source,n=/\)|\((?![^|()\n]+\))/.source;function r(e,r){return RegExp(e.replace(//g,function(){return"(?:"+t+")"}).replace(//g,function(){return"(?:"+n+")"}),r||"")}var i={css:{pattern:/\{[^{}]+\}/,inside:{rest:e.languages.css}},"class-id":{pattern:/(\()[^()]+(?=\))/,lookbehind:!0,alias:"attr-value"},lang:{pattern:/(\[)[^\[\]]+(?=\])/,lookbehind:!0,alias:"attr-value"},punctuation:/[\\\/]\d+|\S/},a=e.languages.textile=e.languages.extend("markup",{phrase:{pattern:/(^|\r|\n)\S[\s\S]*?(?=$|\r?\n\r?\n|\r\r)/,lookbehind:!0,inside:{"block-tag":{pattern:r(/^[a-z]\w*(?:||[<>=])*\./.source),inside:{modifier:{pattern:r(/(^[a-z]\w*)(?:||[<>=])+(?=\.)/.source),lookbehind:!0,inside:i},tag:/^[a-z]\w*/,punctuation:/\.$/}},list:{pattern:r(/^[*#]+*\s+\S.*/.source,"m"),inside:{modifier:{pattern:r(/(^[*#]+)+/.source),lookbehind:!0,inside:i},punctuation:/^[*#]+/}},table:{pattern:r(/^(?:(?:||[<>=^~])+\.\s*)?(?:\|(?:(?:||[<>=^~_]|[\\/]\d+)+\.|(?!(?:||[<>=^~_]|[\\/]\d+)+\.))[^|]*)+\|/.source,"m"),inside:{modifier:{pattern:r(/(^|\|(?:\r?\n|\r)?)(?:||[<>=^~_]|[\\/]\d+)+(?=\.)/.source),lookbehind:!0,inside:i},punctuation:/\||^\./}},inline:{pattern:r(/(^|[^a-zA-Z\d])(\*\*|__|\?\?|[*_%@+\-^~])*.+?\2(?![a-zA-Z\d])/.source),lookbehind:!0,inside:{bold:{pattern:r(/(^(\*\*?)*).+?(?=\2)/.source),lookbehind:!0},italic:{pattern:r(/(^(__?)*).+?(?=\2)/.source),lookbehind:!0},cite:{pattern:r(/(^\?\?*).+?(?=\?\?)/.source),lookbehind:!0,alias:"string"},code:{pattern:r(/(^@*).+?(?=@)/.source),lookbehind:!0,alias:"keyword"},inserted:{pattern:r(/(^\+*).+?(?=\+)/.source),lookbehind:!0},deleted:{pattern:r(/(^-*).+?(?=-)/.source),lookbehind:!0},span:{pattern:r(/(^%*).+?(?=%)/.source),lookbehind:!0},modifier:{pattern:r(/(^\*\*|__|\?\?|[*_%@+\-^~])+/.source),lookbehind:!0,inside:i},punctuation:/[*_%?@+\-^~]+/}},"link-ref":{pattern:/^\[[^\]]+\]\S+$/m,inside:{string:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0},url:{pattern:/(^\])\S+$/,lookbehind:!0},punctuation:/[\[\]]/}},link:{pattern:r(/"*[^"]+":.+?(?=[^\w/]?(?:\s|$))/.source),inside:{text:{pattern:r(/(^"*)[^"]+(?=")/.source),lookbehind:!0},modifier:{pattern:r(/(^")+/.source),lookbehind:!0,inside:i},url:{pattern:/(:).+/,lookbehind:!0},punctuation:/[":]/}},image:{pattern:r(/!(?:||[<>=])*(?![<>=])[^!\s()]+(?:\([^)]+\))?!(?::.+?(?=[^\w/]?(?:\s|$)))?/.source),inside:{source:{pattern:r(/(^!(?:||[<>=])*)(?![<>=])[^!\s()]+(?:\([^)]+\))?(?=!)/.source),lookbehind:!0,alias:"url"},modifier:{pattern:r(/(^!)(?:||[<>=])+/.source),lookbehind:!0,inside:i},url:{pattern:/(:).+/,lookbehind:!0},punctuation:/[!:]/}},footnote:{pattern:/\b\[\d+\]/,alias:"comment",inside:{punctuation:/\[|\]/}},acronym:{pattern:/\b[A-Z\d]+\([^)]+\)/,inside:{comment:{pattern:/(\()[^()]+(?=\))/,lookbehind:!0},punctuation:/[()]/}},mark:{pattern:/\b\((?:TM|R|C)\)/,alias:"comment",inside:{punctuation:/[()]/}}}}}),o=a.phrase.inside,s={inline:o.inline,link:o.link,image:o.image,footnote:o.footnote,acronym:o.acronym,mark:o.mark};a.tag.pattern=/<\/?(?!\d)[a-z0-9]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i;var u=o.inline.inside;u.bold.inside=s,u.italic.inside=s,u.inserted.inside=s,u.deleted.inside=s,u.span.inside=s;var c=o.table.inside;c.inline=s.inline,c.link=s.link,c.image=s.image,c.footnote=s.footnote,c.acronym=s.acronym,c.mark=s.mark}(e)}e.exports=t,t.displayName="textile",t.aliases=[]},85572(e){"use strict";function t(e){!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,function(){return t})}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:true|false)\b/,punctuation:/[.,=[\]{}]/}}(e)}e.exports=t,t.displayName="toml",t.aliases=[]},87041(e,t,n){"use strict";var r=n(96412),i=n(4979);function a(e){var t,n,a;e.register(r),e.register(i),n=(t=e).util.clone(t.languages.typescript),t.languages.tsx=t.languages.extend("jsx",n),(a=t.languages.tsx.tag).pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+a.pattern.source+")",a.pattern.flags),a.lookbehind=!0}e.exports=a,a.displayName="tsx",a.aliases=[]},61028(e,t,n){"use strict";var r=n(93205);function i(e){var t;e.register(r),(t=e).languages.tt2=t.languages.extend("clike",{comment:/#.*|\[%#[\s\S]*?%\]/,keyword:/\b(?:BLOCK|CALL|CASE|CATCH|CLEAR|DEBUG|DEFAULT|ELSE|ELSIF|END|FILTER|FINAL|FOREACH|GET|IF|IN|INCLUDE|INSERT|LAST|MACRO|META|NEXT|PERL|PROCESS|RAWPERL|RETURN|SET|STOP|TAGS|THROW|TRY|SWITCH|UNLESS|USE|WHILE|WRAPPER)\b/,punctuation:/[[\]{},()]/}),t.languages.insertBefore("tt2","number",{operator:/=[>=]?|!=?|<=?|>=?|&&|\|\|?|\b(?:and|or|not)\b/,variable:{pattern:/\b[a-z]\w*(?:\s*\.\s*(?:\d+|\$?[a-z]\w*))*\b/i}}),t.languages.insertBefore("tt2","keyword",{delimiter:{pattern:/^(?:\[%|%%)-?|-?%\]$/,alias:"punctuation"}}),t.languages.insertBefore("tt2","string",{"single-quoted-string":{pattern:/'[^\\']*(?:\\[\s\S][^\\']*)*'/,greedy:!0,alias:"string"},"double-quoted-string":{pattern:/"[^\\"]*(?:\\[\s\S][^\\"]*)*"/,greedy:!0,alias:"string",inside:{variable:{pattern:/\$(?:[a-z]\w*(?:\.(?:\d+|\$?[a-z]\w*))*)/i}}}}),delete t.languages.tt2.string,t.hooks.add("before-tokenize",function(e){var n=/\[%[\s\S]+?%\]/g;t.languages["markup-templating"].buildPlaceholders(e,"tt2",n)}),t.hooks.add("after-tokenize",function(e){t.languages["markup-templating"].tokenizePlaceholders(e,"tt2")})}e.exports=i,i.displayName="tt2",i.aliases=[]},24691(e){"use strict";function t(e){e.languages.turtle={comment:{pattern:/#.*/,greedy:!0},"multiline-string":{pattern:/"""(?:(?:""?)?(?:[^"\\]|\\.))*"""|'''(?:(?:''?)?(?:[^'\\]|\\.))*'''/,greedy:!0,alias:"string",inside:{comment:/#.*/}},string:{pattern:/"(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*'/,greedy:!0},url:{pattern:/<(?:[^\x00-\x20<>"{}|^`\\]|\\(?:u[\da-fA-F]{4}|U[\da-fA-F]{8}))*>/,greedy:!0,inside:{punctuation:/[<>]/}},function:{pattern:/(?:(?![-.\d\xB7])[-.\w\xB7\xC0-\uFFFD]+)?:(?:(?![-.])(?:[-.:\w\xC0-\uFFFD]|%[\da-f]{2}|\\.)+)?/i,inside:{"local-name":{pattern:/([^:]*:)[\s\S]+/,lookbehind:!0},prefix:{pattern:/[\s\S]+/,inside:{punctuation:/:/}}}},number:/[+-]?\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i,punctuation:/[{}.,;()[\]]|\^\^/,boolean:/\b(?:true|false)\b/,keyword:[/(?:\ba|@prefix|@base)\b|=/,/\b(?:graph|base|prefix)\b/i],tag:{pattern:/@[a-z]+(?:-[a-z\d]+)*/i,inside:{punctuation:/@/}}},e.languages.trig=e.languages.turtle}e.exports=t,t.displayName="turtle",t.aliases=[]},19892(e){"use strict";function t(e){e.languages.twig={comment:/\{#[\s\S]*?#\}/,tag:{pattern:/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}/,inside:{ld:{pattern:/^(?:\{\{-?|\{%-?\s*\w+)/,inside:{punctuation:/^(?:\{\{|\{%)-?/,keyword:/\w+/}},rd:{pattern:/-?(?:%\}|\}\})$/,inside:{punctuation:/.+/}},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,inside:{punctuation:/^['"]|['"]$/}},keyword:/\b(?:even|if|odd)\b/,boolean:/\b(?:true|false|null)\b/,number:/\b0x[\dA-Fa-f]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][-+]?\d+)?/,operator:[{pattern:/(\s)(?:and|b-and|b-xor|b-or|ends with|in|is|matches|not|or|same as|starts with)(?=\s)/,lookbehind:!0},/[=<>]=?|!=|\*\*?|\/\/?|\?:?|[-+~%|]/],property:/\b[a-zA-Z_]\w*\b/,punctuation:/[()\[\]{}:.,]/}},other:{pattern:/\S(?:[\s\S]*\S)?/,inside:e.languages.markup}}}e.exports=t,t.displayName="twig",t.aliases=[]},4979(e){"use strict";function t(e){var t,n;(t=e).languages.typescript=t.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/}),t.languages.typescript.keyword.push(/\b(?:abstract|as|declare|implements|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)(?!\s*[^\s_${}*a-zA-Z\xA0-\uFFFF])/),delete t.languages.typescript.parameter,delete(n=t.languages.extend("typescript",{}))["class-name"],t.languages.typescript["class-name"].inside=n,t.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:n}}}}),t.languages.ts=t.languages.typescript}e.exports=t,t.displayName="typescript",t.aliases=["ts"]},23159(e){"use strict";function t(e){var t,n;n=/\b(?:ACT|ACTIFSUB|CARRAY|CASE|CLEARGIF|COA|COA_INT|CONSTANTS|CONTENT|CUR|EDITPANEL|EFFECT|EXT|FILE|FLUIDTEMPLATE|FORM|FRAME|FRAMESET|GIFBUILDER|GMENU|GMENU_FOLDOUT|GMENU_LAYERS|GP|HMENU|HRULER|HTML|IENV|IFSUB|IMAGE|IMGMENU|IMGMENUITEM|IMGTEXT|IMG_RESOURCE|INCLUDE_TYPOSCRIPT|JSMENU|JSMENUITEM|LLL|LOAD_REGISTER|NO|PAGE|RECORDS|RESTORE_REGISTER|TEMPLATE|TEXT|TMENU|TMENUITEM|TMENU_LAYERS|USER|USER_INT|_GIFBUILDER|global|globalString|globalVar)\b/,(t=e).languages.typoscript={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:= \t]|(?:^|[^= \t])[ \t]+)\/\/.*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^"'])#.*/,lookbehind:!0,greedy:!0}],function:[{pattern://,inside:{string:{pattern:/"[^"\r\n]*"|'[^'\r\n]*'/,inside:{keyword:n}},keyword:{pattern:/INCLUDE_TYPOSCRIPT/}}},{pattern:/@import\s*(?:"[^"\r\n]*"|'[^'\r\n]*')/,inside:{string:/"[^"\r\n]*"|'[^'\r\n]*'/}}],string:{pattern:/^([^=]*=[< ]?)(?:(?!\]\n).)*/,lookbehind:!0,inside:{function:/\{\$.*\}/,keyword:n,number:/^[0-9]+$/,punctuation:/[,|:]/}},keyword:n,number:{pattern:/\b[0-9]+\s*[.{=]/,inside:{operator:/[.{=]/}},tag:{pattern:/\.?[-\w\\]+\.?/,inside:{punctuation:/\./}},punctuation:/[{}[\];(),.:|]/,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/},t.languages.tsconfig=t.languages.typoscript}e.exports=t,t.displayName="typoscript",t.aliases=["tsconfig"]},34966(e){"use strict";function t(e){e.languages.unrealscript={comment:/\/\/.*|\/\*[\s\S]*?\*\//,string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},category:{pattern:/(\b(?:(?:autoexpand|hide|show)categories|var)\s*\()[^()]+(?=\))/,lookbehind:!0,greedy:!0,alias:"property"},metadata:{pattern:/(\w\s*)<\s*\w+\s*=[^<>|=\r\n]+(?:\|\s*\w+\s*=[^<>|=\r\n]+)*>/,lookbehind:!0,greedy:!0,inside:{property:/\b\w+(?=\s*=)/,operator:/=/,punctuation:/[<>|]/}},macro:{pattern:/`\w+/,alias:"property"},"class-name":{pattern:/(\b(?:class|enum|extends|interface|state(?:\(\))?|struct|within)\s+)\w+/,lookbehind:!0},keyword:/\b(?:abstract|actor|array|auto|autoexpandcategories|bool|break|byte|case|class|classgroup|client|coerce|collapsecategories|config|const|continue|default|defaultproperties|delegate|dependson|deprecated|do|dontcollapsecategories|editconst|editinlinenew|else|enum|event|exec|export|extends|final|float|for|forcescriptorder|foreach|function|goto|guid|hidecategories|hidedropdown|if|ignores|implements|inherits|input|int|interface|iterator|latent|local|material|name|native|nativereplication|noexport|nontransient|noteditinlinenew|notplaceable|operator|optional|out|pawn|perobjectconfig|perobjectlocalized|placeable|postoperator|preoperator|private|protected|reliable|replication|return|server|showcategories|simulated|singular|state|static|string|struct|structdefault|structdefaultproperties|switch|texture|transient|travel|unreliable|until|var|vector|while|within)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,boolean:/\b(?:false|true)\b/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/>>|<<|--|\+\+|\*\*|[-+*/~!=<>$@]=?|&&?|\|\|?|\^\^?|[?:%]|\b(?:Cross|Dot|ClockwiseFrom)\b/,punctuation:/[()[\]{};,.]/},e.languages.uc=e.languages.uscript=e.languages.unrealscript}e.exports=t,t.displayName="unrealscript",t.aliases=["uc","uscript"]},38521(e){"use strict";function t(e){e.languages.uri={scheme:{pattern:/^[a-z][a-z0-9+.-]*:/im,greedy:!0,inside:{"scheme-delimiter":/:$/}},fragment:{pattern:/#[\w\-.~!$&'()*+,;=%:@/?]*/,inside:{"fragment-delimiter":/^#/}},query:{pattern:/\?[\w\-.~!$&'()*+,;=%:@/?]*/,inside:{"query-delimiter":{pattern:/^\?/,greedy:!0},"pair-delimiter":/[&;]/,pair:{pattern:/^[^=][\s\S]*/,inside:{key:/^[^=]+/,value:{pattern:/(^=)[\s\S]+/,lookbehind:!0}}}}},authority:{pattern:RegExp(/^\/\//.source+/(?:[\w\-.~!$&'()*+,;=%:]*@)?/.source+("(?:"+/\[(?:[0-9a-fA-F:.]{2,48}|v[0-9a-fA-F]+\.[\w\-.~!$&'()*+,;=]+)\]/.source+"|")+/[\w\-.~!$&'()*+,;=%]*/.source+")"+/(?::\d*)?/.source,"m"),inside:{"authority-delimiter":/^\/\//,"user-info-segment":{pattern:/^[\w\-.~!$&'()*+,;=%:]*@/,inside:{"user-info-delimiter":/@$/,"user-info":/^[\w\-.~!$&'()*+,;=%:]+/}},"port-segment":{pattern:/:\d*$/,inside:{"port-delimiter":/^:/,port:/^\d+/}},host:{pattern:/[\s\S]+/,inside:{"ip-literal":{pattern:/^\[[\s\S]+\]$/,inside:{"ip-literal-delimiter":/^\[|\]$/,"ipv-future":/^v[\s\S]+/,"ipv6-address":/^[\s\S]+/}},"ipv4-address":/^(?:(?:[03-9]\d?|[12]\d{0,2})\.){3}(?:[03-9]\d?|[12]{0,2})$/}}}},path:{pattern:/^[\w\-.~!$&'()*+,;=%:@/]+/m,inside:{"path-separator":/\//}}},e.languages.url=e.languages.uri}e.exports=t,t.displayName="uri",t.aliases=["url"]},7255(e){"use strict";function t(e){var t,n;n={pattern:/[\s\S]+/,inside:null},(t=e).languages.v=t.languages.extend("clike",{string:[{pattern:/`(?:\\`|\\?[^`]{1,2})`/,alias:"rune"},{pattern:/r?(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,alias:"quoted-string",greedy:!0,inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:\{[^{}]*\}|\w+(?:\.\w+(?:\([^\(\)]*\))?|\[[^\[\]]+\])*)/,lookbehind:!0,inside:{"interpolation-variable":{pattern:/^\$\w[\s\S]*$/,alias:"variable"},"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},"interpolation-expression":n}}}}],"class-name":{pattern:/(\b(?:enum|interface|struct|type)\s+)(?:C\.)?\w+/,lookbehind:!0},keyword:/(?:\b(?:as|asm|assert|atomic|break|chan|const|continue|defer|else|embed|enum|fn|for|__global|go(?:to)?|if|import|in|interface|is|lock|match|module|mut|none|or|pub|return|rlock|select|shared|sizeof|static|struct|type(?:of)?|union|unsafe)|\$(?:if|else|for)|#(?:include|flag))\b/,number:/\b(?:0x[a-f\d]+(?:_[a-f\d]+)*|0b[01]+(?:_[01]+)*|0o[0-7]+(?:_[0-7]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?)\b/i,operator:/~|\?|[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\.?/,builtin:/\b(?:any(?:_int|_float)?|bool|byte(?:ptr)?|charptr|f(?:32|64)|i(?:8|16|nt|64|128)|rune|size_t|string|u(?:16|32|64|128)|voidptr)\b/}),n.inside=t.languages.v,t.languages.insertBefore("v","operator",{attribute:{pattern:/(^[\t ]*)\[(?:deprecated|unsafe_fn|typedef|live|inline|flag|ref_only|windows_stdcall|direct_array_access)\]/m,lookbehind:!0,alias:"annotation",inside:{punctuation:/[\[\]]/,keyword:/\w+/}},generic:{pattern:/<\w+>(?=\s*[\)\{])/,inside:{punctuation:/[<>]/,"class-name":/\w+/}}}),t.languages.insertBefore("v","function",{"generic-function":{pattern:/\b\w+\s*<\w+>(?=\()/,inside:{function:/^\w+/,generic:{pattern:/<\w+>/,inside:t.languages.v.generic.inside}}}})}e.exports=t,t.displayName="v",t.aliases=[]},28173(e){"use strict";function t(e){e.languages.vala=e.languages.extend("clike",{"class-name":[{pattern:/\b[A-Z]\w*(?:\.\w+)*\b(?=(?:\?\s+|\*?\s+\*?)\w)/,inside:{punctuation:/\./}},{pattern:/(\[)[A-Z]\w*(?:\.\w+)*\b/,lookbehind:!0,inside:{punctuation:/\./}},{pattern:/(\b(?:class|interface)\s+[A-Z]\w*(?:\.\w+)*\s*:\s*)[A-Z]\w*(?:\.\w+)*\b/,lookbehind:!0,inside:{punctuation:/\./}},{pattern:/((?:\b(?:class|interface|new|struct|enum)\s+)|(?:catch\s+\())[A-Z]\w*(?:\.\w+)*\b/,lookbehind:!0,inside:{punctuation:/\./}}],keyword:/\b(?:bool|char|double|float|null|size_t|ssize_t|string|unichar|void|int|int8|int16|int32|int64|long|short|uchar|uint|uint8|uint16|uint32|uint64|ulong|ushort|class|delegate|enum|errordomain|interface|namespace|struct|break|continue|do|for|foreach|return|while|else|if|switch|assert|case|default|abstract|const|dynamic|ensures|extern|inline|internal|override|private|protected|public|requires|signal|static|virtual|volatile|weak|async|owned|unowned|try|catch|finally|throw|as|base|construct|delete|get|in|is|lock|new|out|params|ref|sizeof|set|this|throws|typeof|using|value|var|yield)\b/i,function:/\b\w+(?=\s*\()/,number:/(?:\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)(?:f|u?l?)?/i,operator:/\+\+|--|&&|\|\||<<=?|>>=?|=>|->|~|[+\-*\/%&^|=!<>]=?|\?\??|\.\.\./,punctuation:/[{}[\];(),.:]/,constant:/\b[A-Z0-9_]+\b/}),e.languages.insertBefore("vala","string",{"raw-string":{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string"},"template-string":{pattern:/@"[\s\S]*?"/,greedy:!0,inside:{interpolation:{pattern:/\$(?:\([^)]*\)|[a-zA-Z]\w*)/,inside:{delimiter:{pattern:/^\$\(?|\)$/,alias:"punctuation"},rest:e.languages.vala}},string:/[\s\S]+/}}}),e.languages.insertBefore("vala","keyword",{regex:{pattern:/\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[imsx]{0,4}(?=\s*(?:$|[\r\n,.;})\]]))/,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:e.languages.regex},"regex-delimiter":/^\//,"regex-flags":/^[a-z]+$/}}})}e.exports=t,t.displayName="vala",t.aliases=[]},53813(e,t,n){"use strict";var r=n(46241);function i(e){e.register(r),e.languages.vbnet=e.languages.extend("basic",{comment:[{pattern:/(?:!|REM\b).+/i,inside:{keyword:/^REM/i}},{pattern:/(^|[^\\:])'.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(^|[^"])"(?:""|[^"])*"(?!")/i,lookbehind:!0,greedy:!0},keyword:/(?:\b(?:ADDHANDLER|ADDRESSOF|ALIAS|AND|ANDALSO|AS|BEEP|BLOAD|BOOLEAN|BSAVE|BYREF|BYTE|BYVAL|CALL(?: ABSOLUTE)?|CASE|CATCH|CBOOL|CBYTE|CCHAR|CDATE|CDEC|CDBL|CHAIN|CHAR|CHDIR|CINT|CLASS|CLEAR|CLNG|CLOSE|CLS|COBJ|COM|COMMON|CONST|CONTINUE|CSBYTE|CSHORT|CSNG|CSTR|CTYPE|CUINT|CULNG|CUSHORT|DATA|DATE|DECIMAL|DECLARE|DEFAULT|DEF(?: FN| SEG|DBL|INT|LNG|SNG|STR)|DELEGATE|DIM|DIRECTCAST|DO|DOUBLE|ELSE|ELSEIF|END|ENUM|ENVIRON|ERASE|ERROR|EVENT|EXIT|FALSE|FIELD|FILES|FINALLY|FOR(?: EACH)?|FRIEND|FUNCTION|GET|GETTYPE|GETXMLNAMESPACE|GLOBAL|GOSUB|GOTO|HANDLES|IF|IMPLEMENTS|IMPORTS|IN|INHERITS|INPUT|INTEGER|INTERFACE|IOCTL|IS|ISNOT|KEY|KILL|LINE INPUT|LET|LIB|LIKE|LOCATE|LOCK|LONG|LOOP|LSET|ME|MKDIR|MOD|MODULE|MUSTINHERIT|MUSTOVERRIDE|MYBASE|MYCLASS|NAME|NAMESPACE|NARROWING|NEW|NEXT|NOT|NOTHING|NOTINHERITABLE|NOTOVERRIDABLE|OBJECT|OF|OFF|ON(?: COM| ERROR| KEY| TIMER)?|OPERATOR|OPEN|OPTION(?: BASE)?|OPTIONAL|OR|ORELSE|OUT|OVERLOADS|OVERRIDABLE|OVERRIDES|PARAMARRAY|PARTIAL|POKE|PRIVATE|PROPERTY|PROTECTED|PUBLIC|PUT|RAISEEVENT|READ|READONLY|REDIM|REM|REMOVEHANDLER|RESTORE|RESUME|RETURN|RMDIR|RSET|RUN|SBYTE|SELECT(?: CASE)?|SET|SHADOWS|SHARED|SHORT|SINGLE|SHELL|SLEEP|STATIC|STEP|STOP|STRING|STRUCTURE|SUB|SYNCLOCK|SWAP|SYSTEM|THEN|THROW|TIMER|TO|TROFF|TRON|TRUE|TRY|TRYCAST|TYPE|TYPEOF|UINTEGER|ULONG|UNLOCK|UNTIL|USHORT|USING|VIEW PRINT|WAIT|WEND|WHEN|WHILE|WIDENING|WITH|WITHEVENTS|WRITE|WRITEONLY|XOR)|\B(?:#CONST|#ELSE|#ELSEIF|#END|#IF))(?:\$|\b)/i,punctuation:/[,;:(){}]/})}e.exports=i,i.displayName="vbnet",i.aliases=[]},46891(e){"use strict";function t(e){var t,n;(t=e).languages.velocity=t.languages.extend("markup",{}),(n={variable:{pattern:/(^|[^\\](?:\\\\)*)\$!?(?:[a-z][\w-]*(?:\([^)]*\))?(?:\.[a-z][\w-]*(?:\([^)]*\))?|\[[^\]]+\])*|\{[^}]+\})/i,lookbehind:!0,inside:{}},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},number:/\b\d+\b/,boolean:/\b(?:true|false)\b/,operator:/[=!<>]=?|[+*/%-]|&&|\|\||\.\.|\b(?:eq|g[et]|l[et]|n(?:e|ot))\b/,punctuation:/[(){}[\]:,.]/}).variable.inside={string:n.string,function:{pattern:/([^\w-])[a-z][\w-]*(?=\()/,lookbehind:!0},number:n.number,boolean:n.boolean,punctuation:n.punctuation},t.languages.insertBefore("velocity","comment",{unparsed:{pattern:/(^|[^\\])#\[\[[\s\S]*?\]\]#/,lookbehind:!0,greedy:!0,inside:{punctuation:/^#\[\[|\]\]#$/}},"velocity-comment":[{pattern:/(^|[^\\])#\*[\s\S]*?\*#/,lookbehind:!0,greedy:!0,alias:"comment"},{pattern:/(^|[^\\])##.*/,lookbehind:!0,greedy:!0,alias:"comment"}],directive:{pattern:/(^|[^\\](?:\\\\)*)#@?(?:[a-z][\w-]*|\{[a-z][\w-]*\})(?:\s*\((?:[^()]|\([^()]*\))*\))?/i,lookbehind:!0,inside:{keyword:{pattern:/^#@?(?:[a-z][\w-]*|\{[a-z][\w-]*\})|\bin\b/,inside:{punctuation:/[{}]/}},rest:n}},variable:n.variable}),t.languages.velocity.tag.inside["attr-value"].inside.rest=t.languages.velocity}e.exports=t,t.displayName="velocity",t.aliases=[]},91824(e){"use strict";function t(e){e.languages.verilog={comment:/\/\/.*|\/\*[\s\S]*?\*\//,string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},property:/\B\$\w+\b/,constant:/\B`\w+\b/,function:/\b\w+(?=\()/,keyword:/\b(?:alias|and|assert|assign|assume|automatic|before|begin|bind|bins|binsof|bit|break|buf|bufif0|bufif1|byte|class|case|casex|casez|cell|chandle|clocking|cmos|config|const|constraint|context|continue|cover|covergroup|coverpoint|cross|deassign|default|defparam|design|disable|dist|do|edge|else|end|endcase|endclass|endclocking|endconfig|endfunction|endgenerate|endgroup|endinterface|endmodule|endpackage|endprimitive|endprogram|endproperty|endspecify|endsequence|endtable|endtask|enum|event|expect|export|extends|extern|final|first_match|for|force|foreach|forever|fork|forkjoin|function|generate|genvar|highz0|highz1|if|iff|ifnone|ignore_bins|illegal_bins|import|incdir|include|initial|inout|input|inside|instance|int|integer|interface|intersect|join|join_any|join_none|large|liblist|library|local|localparam|logic|longint|macromodule|matches|medium|modport|module|nand|negedge|new|nmos|nor|noshowcancelled|not|notif0|notif1|null|or|output|package|packed|parameter|pmos|posedge|primitive|priority|program|property|protected|pull0|pull1|pulldown|pullup|pulsestyle_onevent|pulsestyle_ondetect|pure|rand|randc|randcase|randsequence|rcmos|real|realtime|ref|reg|release|repeat|return|rnmos|rpmos|rtran|rtranif0|rtranif1|scalared|sequence|shortint|shortreal|showcancelled|signed|small|solve|specify|specparam|static|string|strong0|strong1|struct|super|supply0|supply1|table|tagged|task|this|throughout|time|timeprecision|timeunit|tran|tranif0|tranif1|tri|tri0|tri1|triand|trior|trireg|type|typedef|union|unique|unsigned|use|uwire|var|vectored|virtual|void|wait|wait_order|wand|weak0|weak1|while|wildcard|wire|with|within|wor|xnor|xor)\b/,important:/\b(?:always_latch|always_comb|always_ff|always)\b ?@?/,number:/\B##?\d+|(?:\b\d+)?'[odbh] ?[\da-fzx_?]+|\b(?:\d*[._])?\d+(?:e[-+]?\d+)?/i,operator:/[-+{}^~%*\/?=!<>&|]+/,punctuation:/[[\];(),.:]/}}e.exports=t,t.displayName="verilog",t.aliases=[]},9447(e){"use strict";function t(e){e.languages.vhdl={comment:/--.+/,"vhdl-vectors":{pattern:/\b[oxb]"[\da-f_]+"|"[01uxzwlh-]+"/i,alias:"number"},"quoted-function":{pattern:/"\S+?"(?=\()/,alias:"function"},string:/"(?:[^\\"\r\n]|\\(?:\r\n|[\s\S]))*"/,constant:/\b(?:use|library)\b/i,keyword:/\b(?:'active|'ascending|'base|'delayed|'driving|'driving_value|'event|'high|'image|'instance_name|'last_active|'last_event|'last_value|'left|'leftof|'length|'low|'path_name|'pos|'pred|'quiet|'range|'reverse_range|'right|'rightof|'simple_name|'stable|'succ|'transaction|'val|'value|access|after|alias|all|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|new|next|null|of|on|open|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|report|return|select|severity|shared|signal|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with)\b/i,boolean:/\b(?:true|false)\b/i,function:/\w+(?=\()/,number:/'[01uxzwlh-]'|\b(?:\d+#[\da-f_.]+#|\d[\d_.]*)(?:e[-+]?\d+)?/i,operator:/[<>]=?|:=|[-+*/&=]|\b(?:abs|not|mod|rem|sll|srl|sla|sra|rol|ror|and|or|nand|xnor|xor|nor)\b/i,punctuation:/[{}[\];(),.:]/}}e.exports=t,t.displayName="vhdl",t.aliases=[]},53062(e){"use strict";function t(e){e.languages.vim={string:/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\r\n]|'')*'/,comment:/".*/,function:/\b\w+(?=\()/,keyword:/\b(?:ab|abbreviate|abc|abclear|abo|aboveleft|al|all|arga|argadd|argd|argdelete|argdo|arge|argedit|argg|argglobal|argl|arglocal|ar|args|argu|argument|as|ascii|bad|badd|ba|ball|bd|bdelete|be|bel|belowright|bf|bfirst|bl|blast|bm|bmodified|bn|bnext|bN|bNext|bo|botright|bp|bprevious|brea|break|breaka|breakadd|breakd|breakdel|breakl|breaklist|br|brewind|bro|browse|bufdo|b|buffer|buffers|bun|bunload|bw|bwipeout|ca|cabbrev|cabc|cabclear|caddb|caddbuffer|cad|caddexpr|caddf|caddfile|cal|call|cat|catch|cb|cbuffer|cc|ccl|cclose|cd|ce|center|cex|cexpr|cf|cfile|cfir|cfirst|cgetb|cgetbuffer|cgete|cgetexpr|cg|cgetfile|c|change|changes|chd|chdir|che|checkpath|checkt|checktime|cla|clast|cl|clist|clo|close|cmapc|cmapclear|cnew|cnewer|cn|cnext|cN|cNext|cnf|cnfile|cNfcNfile|cnorea|cnoreabbrev|col|colder|colo|colorscheme|comc|comclear|comp|compiler|conf|confirm|con|continue|cope|copen|co|copy|cpf|cpfile|cp|cprevious|cq|cquit|cr|crewind|cuna|cunabbrev|cu|cunmap|cw|cwindow|debugg|debuggreedy|delc|delcommand|d|delete|delf|delfunction|delm|delmarks|diffg|diffget|diffoff|diffpatch|diffpu|diffput|diffsplit|diffthis|diffu|diffupdate|dig|digraphs|di|display|dj|djump|dl|dlist|dr|drop|ds|dsearch|dsp|dsplit|earlier|echoe|echoerr|echom|echomsg|echon|e|edit|el|else|elsei|elseif|em|emenu|endfo|endfor|endf|endfunction|endfun|en|endif|endt|endtry|endw|endwhile|ene|enew|ex|exi|exit|exu|exusage|f|file|files|filetype|fina|finally|fin|find|fini|finish|fir|first|fix|fixdel|fo|fold|foldc|foldclose|folddoc|folddoclosed|foldd|folddoopen|foldo|foldopen|for|fu|fun|function|go|goto|gr|grep|grepa|grepadd|ha|hardcopy|h|help|helpf|helpfind|helpg|helpgrep|helpt|helptags|hid|hide|his|history|ia|iabbrev|iabc|iabclear|if|ij|ijump|il|ilist|imapc|imapclear|in|inorea|inoreabbrev|isearch|isp|isplit|iuna|iunabbrev|iu|iunmap|j|join|ju|jumps|k|keepalt|keepj|keepjumps|kee|keepmarks|laddb|laddbuffer|lad|laddexpr|laddf|laddfile|lan|language|la|last|later|lb|lbuffer|lc|lcd|lch|lchdir|lcl|lclose|let|left|lefta|leftabove|lex|lexpr|lf|lfile|lfir|lfirst|lgetb|lgetbuffer|lgete|lgetexpr|lg|lgetfile|lgr|lgrep|lgrepa|lgrepadd|lh|lhelpgrep|l|list|ll|lla|llast|lli|llist|lmak|lmake|lm|lmap|lmapc|lmapclear|lnew|lnewer|lne|lnext|lN|lNext|lnf|lnfile|lNf|lNfile|ln|lnoremap|lo|loadview|loc|lockmarks|lockv|lockvar|lol|lolder|lop|lopen|lpf|lpfile|lp|lprevious|lr|lrewind|ls|lt|ltag|lu|lunmap|lv|lvimgrep|lvimgrepa|lvimgrepadd|lw|lwindow|mak|make|ma|mark|marks|mat|match|menut|menutranslate|mk|mkexrc|mks|mksession|mksp|mkspell|mkvie|mkview|mkv|mkvimrc|mod|mode|m|move|mzf|mzfile|mz|mzscheme|nbkey|new|n|next|N|Next|nmapc|nmapclear|noh|nohlsearch|norea|noreabbrev|nu|number|nun|nunmap|omapc|omapclear|on|only|o|open|opt|options|ou|ounmap|pc|pclose|ped|pedit|pe|perl|perld|perldo|po|pop|popu|popup|pp|ppop|pre|preserve|prev|previous|p|print|P|Print|profd|profdel|prof|profile|promptf|promptfind|promptr|promptrepl|ps|psearch|pta|ptag|ptf|ptfirst|ptj|ptjump|ptl|ptlast|ptn|ptnext|ptN|ptNext|ptp|ptprevious|ptr|ptrewind|pts|ptselect|pu|put|pw|pwd|pyf|pyfile|py|python|qa|qall|q|quit|quita|quitall|r|read|rec|recover|redi|redir|red|redo|redr|redraw|redraws|redrawstatus|reg|registers|res|resize|ret|retab|retu|return|rew|rewind|ri|right|rightb|rightbelow|rub|ruby|rubyd|rubydo|rubyf|rubyfile|ru|runtime|rv|rviminfo|sal|sall|san|sandbox|sa|sargument|sav|saveas|sba|sball|sbf|sbfirst|sbl|sblast|sbm|sbmodified|sbn|sbnext|sbN|sbNext|sbp|sbprevious|sbr|sbrewind|sb|sbuffer|scripte|scriptencoding|scrip|scriptnames|se|set|setf|setfiletype|setg|setglobal|setl|setlocal|sf|sfind|sfir|sfirst|sh|shell|sign|sil|silent|sim|simalt|sla|slast|sl|sleep|sm|smagic|smap|smapc|smapclear|sme|smenu|sn|snext|sN|sNext|sni|sniff|sno|snomagic|snor|snoremap|snoreme|snoremenu|sor|sort|so|source|spelld|spelldump|spe|spellgood|spelli|spellinfo|spellr|spellrepall|spellu|spellundo|spellw|spellwrong|sp|split|spr|sprevious|sre|srewind|sta|stag|startg|startgreplace|star|startinsert|startr|startreplace|stj|stjump|st|stop|stopi|stopinsert|sts|stselect|sun|sunhide|sunm|sunmap|sus|suspend|sv|sview|syncbind|t|tab|tabc|tabclose|tabd|tabdo|tabe|tabedit|tabf|tabfind|tabfir|tabfirst|tabl|tablast|tabm|tabmove|tabnew|tabn|tabnext|tabN|tabNext|tabo|tabonly|tabp|tabprevious|tabr|tabrewind|tabs|ta|tag|tags|tc|tcl|tcld|tcldo|tclf|tclfile|te|tearoff|tf|tfirst|th|throw|tj|tjump|tl|tlast|tm|tmenu|tn|tnext|tN|tNext|to|topleft|tp|tprevious|tr|trewind|try|ts|tselect|tu|tunmenu|una|unabbreviate|u|undo|undoj|undojoin|undol|undolist|unh|unhide|unlet|unlo|unlockvar|unm|unmap|up|update|verb|verbose|ve|version|vert|vertical|vie|view|vim|vimgrep|vimgrepa|vimgrepadd|vi|visual|viu|viusage|vmapc|vmapclear|vne|vnew|vs|vsplit|vu|vunmap|wa|wall|wh|while|winc|wincmd|windo|winp|winpos|win|winsize|wn|wnext|wN|wNext|wp|wprevious|wq|wqa|wqall|w|write|ws|wsverb|wv|wviminfo|X|xa|xall|x|xit|xm|xmap|xmapc|xmapclear|xme|xmenu|XMLent|XMLns|xn|xnoremap|xnoreme|xnoremenu|xu|xunmap|y|yank)\b/,builtin:/\b(?:autocmd|acd|ai|akm|aleph|allowrevins|altkeymap|ambiwidth|ambw|anti|antialias|arab|arabic|arabicshape|ari|arshape|autochdir|autoindent|autoread|autowrite|autowriteall|aw|awa|background|backspace|backup|backupcopy|backupdir|backupext|backupskip|balloondelay|ballooneval|balloonexpr|bdir|bdlay|beval|bex|bexpr|bg|bh|bin|binary|biosk|bioskey|bk|bkc|bomb|breakat|brk|browsedir|bs|bsdir|bsk|bt|bufhidden|buflisted|buftype|casemap|ccv|cdpath|cedit|cfu|ch|charconvert|ci|cin|cindent|cink|cinkeys|cino|cinoptions|cinw|cinwords|clipboard|cmdheight|cmdwinheight|cmp|cms|columns|com|comments|commentstring|compatible|complete|completefunc|completeopt|consk|conskey|copyindent|cot|cpo|cpoptions|cpt|cscopepathcomp|cscopeprg|cscopequickfix|cscopetag|cscopetagorder|cscopeverbose|cspc|csprg|csqf|cst|csto|csverb|cuc|cul|cursorcolumn|cursorline|cwh|debug|deco|def|define|delcombine|dex|dg|dict|dictionary|diff|diffexpr|diffopt|digraph|dip|dir|directory|dy|ea|ead|eadirection|eb|ed|edcompatible|ef|efm|ei|ek|enc|encoding|endofline|eol|ep|equalalways|equalprg|errorbells|errorfile|errorformat|esckeys|et|eventignore|expandtab|exrc|fcl|fcs|fdc|fde|fdi|fdl|fdls|fdm|fdn|fdo|fdt|fen|fenc|fencs|fex|ff|ffs|fileencoding|fileencodings|fileformat|fileformats|fillchars|fk|fkmap|flp|fml|fmr|foldcolumn|foldenable|foldexpr|foldignore|foldlevel|foldlevelstart|foldmarker|foldmethod|foldminlines|foldnestmax|foldtext|formatexpr|formatlistpat|formatoptions|formatprg|fp|fs|fsync|ft|gcr|gd|gdefault|gfm|gfn|gfs|gfw|ghr|gp|grepformat|grepprg|gtl|gtt|guicursor|guifont|guifontset|guifontwide|guiheadroom|guioptions|guipty|guitablabel|guitabtooltip|helpfile|helpheight|helplang|hf|hh|hi|hidden|highlight|hk|hkmap|hkmapp|hkp|hl|hlg|hls|hlsearch|ic|icon|iconstring|ignorecase|im|imactivatekey|imak|imc|imcmdline|imd|imdisable|imi|iminsert|ims|imsearch|inc|include|includeexpr|incsearch|inde|indentexpr|indentkeys|indk|inex|inf|infercase|insertmode|isf|isfname|isi|isident|isk|iskeyword|isprint|joinspaces|js|key|keymap|keymodel|keywordprg|km|kmp|kp|langmap|langmenu|laststatus|lazyredraw|lbr|lcs|linebreak|lines|linespace|lisp|lispwords|listchars|loadplugins|lpl|lsp|lz|macatsui|magic|makeef|makeprg|matchpairs|matchtime|maxcombine|maxfuncdepth|maxmapdepth|maxmem|maxmempattern|maxmemtot|mco|mef|menuitems|mfd|mh|mis|mkspellmem|ml|mls|mm|mmd|mmp|mmt|modeline|modelines|modifiable|modified|more|mouse|mousef|mousefocus|mousehide|mousem|mousemodel|mouses|mouseshape|mouset|mousetime|mp|mps|msm|mzq|mzquantum|nf|nrformats|numberwidth|nuw|odev|oft|ofu|omnifunc|opendevice|operatorfunc|opfunc|osfiletype|pa|para|paragraphs|paste|pastetoggle|patchexpr|patchmode|path|pdev|penc|pex|pexpr|pfn|ph|pheader|pi|pm|pmbcs|pmbfn|popt|preserveindent|previewheight|previewwindow|printdevice|printencoding|printexpr|printfont|printheader|printmbcharset|printmbfont|printoptions|prompt|pt|pumheight|pvh|pvw|qe|quoteescape|readonly|remap|report|restorescreen|revins|rightleft|rightleftcmd|rl|rlc|ro|rs|rtp|ruf|ruler|rulerformat|runtimepath|sbo|sc|scb|scr|scroll|scrollbind|scrolljump|scrolloff|scrollopt|scs|sect|sections|secure|sel|selection|selectmode|sessionoptions|sft|shcf|shellcmdflag|shellpipe|shellquote|shellredir|shellslash|shelltemp|shelltype|shellxquote|shiftround|shiftwidth|shm|shortmess|shortname|showbreak|showcmd|showfulltag|showmatch|showmode|showtabline|shq|si|sidescroll|sidescrolloff|siso|sj|slm|smartcase|smartindent|smarttab|smc|smd|softtabstop|sol|spc|spell|spellcapcheck|spellfile|spelllang|spellsuggest|spf|spl|splitbelow|splitright|sps|sr|srr|ss|ssl|ssop|stal|startofline|statusline|stl|stmp|su|sua|suffixes|suffixesadd|sw|swapfile|swapsync|swb|swf|switchbuf|sws|sxq|syn|synmaxcol|syntax|tabline|tabpagemax|tabstop|tagbsearch|taglength|tagrelative|tagstack|tal|tb|tbi|tbidi|tbis|tbs|tenc|term|termbidi|termencoding|terse|textauto|textmode|textwidth|tgst|thesaurus|tildeop|timeout|timeoutlen|title|titlelen|titleold|titlestring|toolbar|toolbariconsize|top|tpm|tsl|tsr|ttimeout|ttimeoutlen|ttm|tty|ttybuiltin|ttyfast|ttym|ttymouse|ttyscroll|ttytype|tw|tx|uc|ul|undolevels|updatecount|updatetime|ut|vb|vbs|vdir|verbosefile|vfile|viewdir|viewoptions|viminfo|virtualedit|visualbell|vop|wak|warn|wb|wc|wcm|wd|weirdinvert|wfh|wfw|whichwrap|wi|wig|wildchar|wildcharm|wildignore|wildmenu|wildmode|wildoptions|wim|winaltkeys|window|winfixheight|winfixwidth|winheight|winminheight|winminwidth|winwidth|wiv|wiw|wm|wmh|wmnu|wmw|wop|wrap|wrapmargin|wrapscan|writeany|writebackup|writedelay|ww|noacd|noai|noakm|noallowrevins|noaltkeymap|noanti|noantialias|noar|noarab|noarabic|noarabicshape|noari|noarshape|noautochdir|noautoindent|noautoread|noautowrite|noautowriteall|noaw|noawa|nobackup|noballooneval|nobeval|nobin|nobinary|nobiosk|nobioskey|nobk|nobl|nobomb|nobuflisted|nocf|noci|nocin|nocindent|nocompatible|noconfirm|noconsk|noconskey|nocopyindent|nocp|nocscopetag|nocscopeverbose|nocst|nocsverb|nocuc|nocul|nocursorcolumn|nocursorline|nodeco|nodelcombine|nodg|nodiff|nodigraph|nodisable|noea|noeb|noed|noedcompatible|noek|noendofline|noeol|noequalalways|noerrorbells|noesckeys|noet|noex|noexpandtab|noexrc|nofen|nofk|nofkmap|nofoldenable|nogd|nogdefault|noguipty|nohid|nohidden|nohk|nohkmap|nohkmapp|nohkp|nohls|noic|noicon|noignorecase|noim|noimc|noimcmdline|noimd|noincsearch|noinf|noinfercase|noinsertmode|nois|nojoinspaces|nojs|nolazyredraw|nolbr|nolinebreak|nolisp|nolist|noloadplugins|nolpl|nolz|noma|nomacatsui|nomagic|nomh|noml|nomod|nomodeline|nomodifiable|nomodified|nomore|nomousef|nomousefocus|nomousehide|nonu|nonumber|noodev|noopendevice|nopaste|nopi|nopreserveindent|nopreviewwindow|noprompt|nopvw|noreadonly|noremap|norestorescreen|norevins|nori|norightleft|norightleftcmd|norl|norlc|noro|nors|noru|noruler|nosb|nosc|noscb|noscrollbind|noscs|nosecure|nosft|noshellslash|noshelltemp|noshiftround|noshortname|noshowcmd|noshowfulltag|noshowmatch|noshowmode|nosi|nosm|nosmartcase|nosmartindent|nosmarttab|nosmd|nosn|nosol|nospell|nosplitbelow|nosplitright|nospr|nosr|nossl|nosta|nostartofline|nostmp|noswapfile|noswf|nota|notagbsearch|notagrelative|notagstack|notbi|notbidi|notbs|notermbidi|noterse|notextauto|notextmode|notf|notgst|notildeop|notimeout|notitle|noto|notop|notr|nottimeout|nottybuiltin|nottyfast|notx|novb|novisualbell|nowa|nowarn|nowb|noweirdinvert|nowfh|nowfw|nowildmenu|nowinfixheight|nowinfixwidth|nowiv|nowmnu|nowrap|nowrapscan|nowrite|nowriteany|nowritebackup|nows|invacd|invai|invakm|invallowrevins|invaltkeymap|invanti|invantialias|invar|invarab|invarabic|invarabicshape|invari|invarshape|invautochdir|invautoindent|invautoread|invautowrite|invautowriteall|invaw|invawa|invbackup|invballooneval|invbeval|invbin|invbinary|invbiosk|invbioskey|invbk|invbl|invbomb|invbuflisted|invcf|invci|invcin|invcindent|invcompatible|invconfirm|invconsk|invconskey|invcopyindent|invcp|invcscopetag|invcscopeverbose|invcst|invcsverb|invcuc|invcul|invcursorcolumn|invcursorline|invdeco|invdelcombine|invdg|invdiff|invdigraph|invdisable|invea|inveb|inved|invedcompatible|invek|invendofline|inveol|invequalalways|inverrorbells|invesckeys|invet|invex|invexpandtab|invexrc|invfen|invfk|invfkmap|invfoldenable|invgd|invgdefault|invguipty|invhid|invhidden|invhk|invhkmap|invhkmapp|invhkp|invhls|invhlsearch|invic|invicon|invignorecase|invim|invimc|invimcmdline|invimd|invincsearch|invinf|invinfercase|invinsertmode|invis|invjoinspaces|invjs|invlazyredraw|invlbr|invlinebreak|invlisp|invlist|invloadplugins|invlpl|invlz|invma|invmacatsui|invmagic|invmh|invml|invmod|invmodeline|invmodifiable|invmodified|invmore|invmousef|invmousefocus|invmousehide|invnu|invnumber|invodev|invopendevice|invpaste|invpi|invpreserveindent|invpreviewwindow|invprompt|invpvw|invreadonly|invremap|invrestorescreen|invrevins|invri|invrightleft|invrightleftcmd|invrl|invrlc|invro|invrs|invru|invruler|invsb|invsc|invscb|invscrollbind|invscs|invsecure|invsft|invshellslash|invshelltemp|invshiftround|invshortname|invshowcmd|invshowfulltag|invshowmatch|invshowmode|invsi|invsm|invsmartcase|invsmartindent|invsmarttab|invsmd|invsn|invsol|invspell|invsplitbelow|invsplitright|invspr|invsr|invssl|invsta|invstartofline|invstmp|invswapfile|invswf|invta|invtagbsearch|invtagrelative|invtagstack|invtbi|invtbidi|invtbs|invtermbidi|invterse|invtextauto|invtextmode|invtf|invtgst|invtildeop|invtimeout|invtitle|invto|invtop|invtr|invttimeout|invttybuiltin|invttyfast|invtx|invvb|invvisualbell|invwa|invwarn|invwb|invweirdinvert|invwfh|invwfw|invwildmenu|invwinfixheight|invwinfixwidth|invwiv|invwmnu|invwrap|invwrapscan|invwrite|invwriteany|invwritebackup|invws|t_AB|t_AF|t_al|t_AL|t_bc|t_cd|t_ce|t_Ce|t_cl|t_cm|t_Co|t_cs|t_Cs|t_CS|t_CV|t_da|t_db|t_dl|t_DL|t_EI|t_F1|t_F2|t_F3|t_F4|t_F5|t_F6|t_F7|t_F8|t_F9|t_fs|t_IE|t_IS|t_k1|t_K1|t_k2|t_k3|t_K3|t_k4|t_K4|t_k5|t_K5|t_k6|t_K6|t_k7|t_K7|t_k8|t_K8|t_k9|t_K9|t_KA|t_kb|t_kB|t_KB|t_KC|t_kd|t_kD|t_KD|t_ke|t_KE|t_KF|t_KG|t_kh|t_KH|t_kI|t_KI|t_KJ|t_KK|t_kl|t_KL|t_kN|t_kP|t_kr|t_ks|t_ku|t_le|t_mb|t_md|t_me|t_mr|t_ms|t_nd|t_op|t_RI|t_RV|t_Sb|t_se|t_Sf|t_SI|t_so|t_sr|t_te|t_ti|t_ts|t_ue|t_us|t_ut|t_vb|t_ve|t_vi|t_vs|t_WP|t_WS|t_xs|t_ZH|t_ZR)\b/,number:/\b(?:0x[\da-f]+|\d+(?:\.\d+)?)\b/i,operator:/\|\||&&|[-+.]=?|[=!](?:[=~][#?]?)?|[<>]=?[#?]?|[*\/%?]|\b(?:is(?:not)?)\b/,punctuation:/[{}[\](),;:]/}}e.exports=t,t.displayName="vim",t.aliases=[]},46215(e){"use strict";function t(e){e.languages["visual-basic"]={comment:{pattern:/(?:['‘’]|REM\b)(?:[^\r\n_]|_(?:\r\n?|\n)?)*/i,inside:{keyword:/^REM/i}},directive:{pattern:/#(?:Const|Else|ElseIf|End|ExternalChecksum|ExternalSource|If|Region)(?:[^\S\r\n]_[^\S\r\n]*(?:\r\n?|\n)|.)+/i,alias:"comment",greedy:!0},string:{pattern:/\$?["“”](?:["“”]{2}|[^"“”])*["“”]C?/i,greedy:!0},date:{pattern:/#[^\S\r\n]*(?:\d+([/-])\d+\1\d+(?:[^\S\r\n]+(?:\d+[^\S\r\n]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[^\S\r\n]*(?:AM|PM))?))?|\d+[^\S\r\n]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[^\S\r\n]*(?:AM|PM))?)[^\S\r\n]*#/i,alias:"builtin"},number:/(?:(?:\b\d+(?:\.\d+)?|\.\d+)(?:E[+-]?\d+)?|&[HO][\dA-F]+)(?:U?[ILS]|[FRD])?/i,boolean:/\b(?:True|False|Nothing)\b/i,keyword:/\b(?:AddHandler|AddressOf|Alias|And(?:Also)?|As|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|C(?:Bool|Byte|Char|Date|Dbl|Dec|Int|Lng|Obj|SByte|Short|Sng|Str|Type|UInt|ULng|UShort)|Char|Class|Const|Continue|Currency|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else(?:If)?|End(?:If)?|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get(?:Type|XMLNamespace)?|Global|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|IsNot|Let|Lib|Like|Long|Loop|Me|Mod|Module|Must(?:Inherit|Override)|My(?:Base|Class)|Namespace|Narrowing|New|Next|Not(?:Inheritable|Overridable)?|Object|Of|On|Operator|Option(?:al)?|Or(?:Else)?|Out|Overloads|Overridable|Overrides|ParamArray|Partial|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|SByte|Select|Set|Shadows|Shared|short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TryCast|Type|TypeOf|U(?:Integer|Long|Short)|Using|Variant|Wend|When|While|Widening|With(?:Events)?|WriteOnly|Until|Xor)\b/i,operator:[/[+\-*/\\^<=>&#@$%!]/,{pattern:/([^\S\r\n])_(?=[^\S\r\n]*[\r\n])/,lookbehind:!0}],punctuation:/[{}().,:?]/},e.languages.vb=e.languages["visual-basic"],e.languages.vba=e.languages["visual-basic"]}e.exports=t,t.displayName="visualBasic",t.aliases=[]},10784(e){"use strict";function t(e){e.languages.warpscript={comment:/#.*|\/\/.*|\/\*[\s\S]*?\*\//,string:{pattern:/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'|<'(?:[^\\']|'(?!>)|\\.)*'>/,greedy:!0},variable:/\$\S+/,macro:{pattern:/@\S+/,alias:"property"},keyword:/\b(?:BREAK|CHECKMACRO|CONTINUE|CUDF|DEFINED|DEFINEDMACRO|EVAL|FAIL|FOR|FOREACH|FORSTEP|IFT|IFTE|MSGFAIL|NRETURN|RETHROW|RETURN|SWITCH|TRY|UDF|UNTIL|WHILE)\b/,number:/[+-]?\b(?:NaN|Infinity|\d+(?:\.\d*)?(?:[Ee][+-]?\d+)?|0x[\da-fA-F]+|0b[01]+)\b/,boolean:/\b(?:false|true|F|T)\b/,punctuation:/<%|%>|[{}[\]()]/,operator:/==|&&?|\|\|?|\*\*?|>>>?|<<|[<>!~]=?|[-/%^]|\+!?|\b(?:AND|NOT|OR)\b/}}e.exports=t,t.displayName="warpscript",t.aliases=[]},17684(e){"use strict";function t(e){e.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/i,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/}}e.exports=t,t.displayName="wasm",t.aliases=[]},18191(e){"use strict";function t(e){e.languages.wiki=e.languages.extend("markup",{"block-comment":{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0,alias:"comment"},heading:{pattern:/^(=+)[^=\r\n].*?\1/m,inside:{punctuation:/^=+|=+$/,important:/.+/}},emphasis:{pattern:/('{2,5}).+?\1/,inside:{"bold-italic":{pattern:/(''''').+?(?=\1)/,lookbehind:!0,alias:["bold","italic"]},bold:{pattern:/(''')[^'](?:.*?[^'])?(?=\1)/,lookbehind:!0},italic:{pattern:/('')[^'](?:.*?[^'])?(?=\1)/,lookbehind:!0},punctuation:/^''+|''+$/}},hr:{pattern:/^-{4,}/m,alias:"punctuation"},url:[/ISBN +(?:97[89][ -]?)?(?:\d[ -]?){9}[\dx]\b|(?:RFC|PMID) +\d+/i,/\[\[.+?\]\]|\[.+?\]/],variable:[/__[A-Z]+__/,/\{{3}.+?\}{3}/,/\{\{.+?\}\}/],symbol:[/^#redirect/im,/~{3,5}/],"table-tag":{pattern:/((?:^|[|!])[|!])[^|\r\n]+\|(?!\|)/m,lookbehind:!0,inside:{"table-bar":{pattern:/\|$/,alias:"punctuation"},rest:e.languages.markup.tag.inside}},punctuation:/^(?:\{\||\|\}|\|-|[*#:;!|])|\|\||!!/m}),e.languages.insertBefore("wiki","tag",{nowiki:{pattern:/<(nowiki|pre|source)\b[^>]*>[\s\S]*?<\/\1>/i,inside:{tag:{pattern:/<(?:nowiki|pre|source)\b[^>]*>|<\/(?:nowiki|pre|source)>/i,inside:e.languages.markup.tag.inside}}}})}e.exports=t,t.displayName="wiki",t.aliases=[]},75242(e){"use strict";function t(e){e.languages.wolfram={comment:/\(\*(?:\(\*(?:[^*]|\*(?!\)))*\*\)|(?!\(\*)[\s\S])*?\*\)/,string:{pattern:/"(?:\\.|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:Abs|AbsArg|Accuracy|Block|Do|For|Function|If|Manipulate|Module|Nest|NestList|None|Return|Switch|Table|Which|While)\b/,context:{pattern:/\w+`+\w*/,alias:"class-name"},blank:{pattern:/\b\w+_\b/,alias:"regex"},"global-variable":{pattern:/\$\w+/,alias:"variable"},boolean:/\b(?:True|False)\b/,number:/(?:\b(?=\d)|\B(?=\.))(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/\/\.|;|=\.|\^=|\^:=|:=|<<|>>|<\||\|>|:>|\|->|->|<-|@@@|@@|@|\/@|=!=|===|==|=|\+|-|\^|\[\/-+%=\]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[\|{}[\];(),.:]/},e.languages.mathematica=e.languages.wolfram,e.languages.wl=e.languages.wolfram,e.languages.nb=e.languages.wolfram}e.exports=t,t.displayName="wolfram",t.aliases=["mathematica","wl","nb"]},97202(e){"use strict";function t(e){var t;(t=e).languages.xeora=t.languages.extend("markup",{constant:{pattern:/\$(?:DomainContents|PageRenderDuration)\$/,inside:{punctuation:{pattern:/\$/}}},variable:{pattern:/\$@?(?:#+|[-+*~=^])?[\w.]+\$/,inside:{punctuation:{pattern:/[$.]/},operator:{pattern:/#+|[-+*~=^@]/}}},"function-inline":{pattern:/\$F:[-\w.]+\?[-\w.]+(?:,(?:(?:@[-#]*\w+\.[\w+.]\.*)*\|)*(?:(?:[\w+]|[-#*.~^]+[\w+]|=\S)(?:[^$=]|=+[^=])*=*|(?:@[-#]*\w+\.[\w+.]\.*)+(?:(?:[\w+]|[-#*~^][-#*.~^]*[\w+]|=\S)(?:[^$=]|=+[^=])*=*)?)?)?\$/,inside:{variable:{pattern:/(?:[,|])@?(?:#+|[-+*~=^])?[\w.]+/,inside:{punctuation:{pattern:/[,.|]/},operator:{pattern:/#+|[-+*~=^@]/}}},punctuation:{pattern:/\$\w:|[$:?.,|]/}},alias:"function"},"function-block":{pattern:/\$XF:\{[-\w.]+\?[-\w.]+(?:,(?:(?:@[-#]*\w+\.[\w+.]\.*)*\|)*(?:(?:[\w+]|[-#*.~^]+[\w+]|=\S)(?:[^$=]|=+[^=])*=*|(?:@[-#]*\w+\.[\w+.]\.*)+(?:(?:[\w+]|[-#*~^][-#*.~^]*[\w+]|=\S)(?:[^$=]|=+[^=])*=*)?)?)?\}:XF\$/,inside:{punctuation:{pattern:/[$:{}?.,|]/}},alias:"function"},"directive-inline":{pattern:/\$\w(?:#\d+\+?)?(?:\[[-\w.]+\])?:[-\/\w.]+\$/,inside:{punctuation:{pattern:/\$(?:\w:|C(?:\[|#\d))?|[:{[\]]/,inside:{tag:{pattern:/#\d/}}}},alias:"function"},"directive-block-open":{pattern:/\$\w+:\{|\$\w(?:#\d+\+?)?(?:\[[-\w.]+\])?:[-\w.]+:\{(?:![A-Z]+)?/,inside:{punctuation:{pattern:/\$(?:\w:|C(?:\[|#\d))?|[:{[\]]/,inside:{tag:{pattern:/#\d/}}},attribute:{pattern:/![A-Z]+$/,inside:{punctuation:{pattern:/!/}},alias:"keyword"}},alias:"function"},"directive-block-separator":{pattern:/\}:[-\w.]+:\{/,inside:{punctuation:{pattern:/[:{}]/}},alias:"function"},"directive-block-close":{pattern:/\}:[-\w.]+\$/,inside:{punctuation:{pattern:/[:{}$]/}},alias:"function"}}),t.languages.insertBefore("inside","punctuation",{variable:t.languages.xeora["function-inline"].inside.variable},t.languages.xeora["function-block"]),t.languages.xeoracube=t.languages.xeora}e.exports=t,t.displayName="xeora",t.aliases=["xeoracube"]},13808(e){"use strict";function t(e){!function(e){function t(t,n){e.languages[t]&&e.languages.insertBefore(t,"comment",{"doc-comment":n})}var n=e.languages.markup.tag,r={pattern:/\/\/\/.*/,greedy:!0,alias:"comment",inside:{tag:n}},i={pattern:/'''.*/,greedy:!0,alias:"comment",inside:{tag:n}};t("csharp",r),t("fsharp",r),t("vbnet",i)}(e)}e.exports=t,t.displayName="xmlDoc",t.aliases=[]},21301(e){"use strict";function t(e){e.languages.xojo={comment:{pattern:/(?:'|\/\/|Rem\b).+/i},string:{pattern:/"(?:""|[^"])*"/,greedy:!0},number:[/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?/i,/&[bchou][a-z\d]+/i],symbol:/#(?:If|Else|ElseIf|Endif|Pragma)\b/i,keyword:/\b(?:AddHandler|App|Array|As(?:signs)?|Auto|By(?:Ref|Val)|Boolean|Break|Byte|Call|Case|Catch|CFStringRef|CGFloat|Class|Color|Const|Continue|CString|Currency|CurrentMethodName|Declare|Delegate|Dim|Do(?:uble|wnTo)?|Each|Else(?:If)?|End|Enumeration|Event|Exception|Exit|Extends|False|Finally|For|Function|Get|GetTypeInfo|Global|GOTO|If|Implements|In|Inherits|Int(?:erface|eger|8|16|32|64)?|Lib|Loop|Me|Module|Next|Nil|Object|Optional|OSType|ParamArray|Private|Property|Protected|PString|Ptr|Raise(?:Event)?|ReDim|RemoveHandler|Return|Select(?:or)?|Self|Set|Single|Shared|Short|Soft|Static|Step|String|Sub|Super|Text|Then|To|True|Try|Ubound|UInt(?:eger|8|16|32|64)?|Until|Using|Var(?:iant)?|Wend|While|WindowPtr|WString)\b/i,operator:/<[=>]?|>=?|[+\-*\/\\^=]|\b(?:AddressOf|And|Ctype|IsA?|Mod|New|Not|Or|Xor|WeakAddressOf)\b/i,punctuation:/[.,;:()]/}}e.exports=t,t.displayName="xojo",t.aliases=[]},20349(e){"use strict";function t(e){var t,n,r;(t=e).languages.xquery=t.languages.extend("markup",{"xquery-comment":{pattern:/\(:[\s\S]*?:\)/,greedy:!0,alias:"comment"},string:{pattern:/(["'])(?:\1\1|(?!\1)[\s\S])*\1/,greedy:!0},extension:{pattern:/\(#.+?#\)/,alias:"symbol"},variable:/\$[-\w:]+/,axis:{pattern:/(^|[^-])(?:ancestor(?:-or-self)?|attribute|child|descendant(?:-or-self)?|following(?:-sibling)?|parent|preceding(?:-sibling)?|self)(?=::)/,lookbehind:!0,alias:"operator"},"keyword-operator":{pattern:/(^|[^:-])\b(?:and|castable as|div|eq|except|ge|gt|idiv|instance of|intersect|is|le|lt|mod|ne|or|union)\b(?=$|[^:-])/,lookbehind:!0,alias:"operator"},keyword:{pattern:/(^|[^:-])\b(?:as|ascending|at|base-uri|boundary-space|case|cast as|collation|construction|copy-namespaces|declare|default|descending|else|empty (?:greatest|least)|encoding|every|external|for|function|if|import|in|inherit|lax|let|map|module|namespace|no-inherit|no-preserve|option|order(?: by|ed|ing)?|preserve|return|satisfies|schema|some|stable|strict|strip|then|to|treat as|typeswitch|unordered|validate|variable|version|where|xquery)\b(?=$|[^:-])/,lookbehind:!0},function:/[\w-]+(?::[\w-]+)*(?=\s*\()/,"xquery-element":{pattern:/(element\s+)[\w-]+(?::[\w-]+)*/,lookbehind:!0,alias:"tag"},"xquery-attribute":{pattern:/(attribute\s+)[\w-]+(?::[\w-]+)*/,lookbehind:!0,alias:"attr-name"},builtin:{pattern:/(^|[^:-])\b(?:attribute|comment|document|element|processing-instruction|text|xs:(?:anyAtomicType|anyType|anyURI|base64Binary|boolean|byte|date|dateTime|dayTimeDuration|decimal|double|duration|ENTITIES|ENTITY|float|gDay|gMonth|gMonthDay|gYear|gYearMonth|hexBinary|ID|IDREFS?|int|integer|language|long|Name|NCName|negativeInteger|NMTOKENS?|nonNegativeInteger|nonPositiveInteger|normalizedString|NOTATION|positiveInteger|QName|short|string|time|token|unsigned(?:Byte|Int|Long|Short)|untyped(?:Atomic)?|yearMonthDuration))\b(?=$|[^:-])/,lookbehind:!0},number:/\b\d+(?:\.\d+)?(?:E[+-]?\d+)?/,operator:[/[+*=?|@]|\.\.?|:=|!=|<[=<]?|>[=>]?/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}],punctuation:/[[\](){},;:/]/}),t.languages.xquery.tag.pattern=/<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|\{(?!\{)(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\}|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,t.languages.xquery.tag.inside["attr-value"].pattern=/=(?:("|')(?:\\[\s\S]|\{(?!\{)(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\}|(?!\1)[^\\])*\1|[^\s'">=]+)/i,t.languages.xquery.tag.inside["attr-value"].inside.punctuation=/^="|"$/,t.languages.xquery.tag.inside["attr-value"].inside.expression={pattern:/\{(?!\{)(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\}/,inside:t.languages.xquery,alias:"language-xquery"},n=function(e){return"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(n).join("")},r=function(e){for(var i=[],a=0;a0&&i[i.length-1].tagName===n(o.content[0].content[1])&&i.pop():"/>"===o.content[o.content.length-1].content||i.push({tagName:n(o.content[0].content[1]),openedBraces:0}):!(i.length>0)||"punctuation"!==o.type||"{"!==o.content||e[a+1]&&"punctuation"===e[a+1].type&&"{"===e[a+1].content||e[a-1]&&"plain-text"===e[a-1].type&&"{"===e[a-1].content?i.length>0&&i[i.length-1].openedBraces>0&&"punctuation"===o.type&&"}"===o.content?i[i.length-1].openedBraces--:"comment"!==o.type&&(s=!0):i[i.length-1].openedBraces++),(s||"string"==typeof o)&&i.length>0&&0===i[i.length-1].openedBraces){var u=n(o);a0&&("string"==typeof e[a-1]||"plain-text"===e[a-1].type)&&(u=n(e[a-1])+u,e.splice(a-1,1),a--),/^\s+$/.test(u)?e[a]=u:e[a]=new t.Token("plain-text",u,null,u)}o.content&&"string"!=typeof o.content&&r(o.content)}},t.hooks.add("after-tokenize",function(e){"xquery"===e.language&&r(e.tokens)})}e.exports=t,t.displayName="xquery",t.aliases=[]},65039(e){"use strict";function t(e){!function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ ]+"+t.source+")?|"+t.source+"(?:[ ]+"+n.source+")?)",i=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source}),a=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function o(e,t){return t=(t||"").replace(/m/g,"")+"m",RegExp(/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,function(){return r}).replace(/<>/g,function(){return e}),t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,function(){return r})),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,function(){return r}).replace(/<>/g,function(){return"(?:"+i+"|"+a+")"})),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:o(/true|false/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:o(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:o(a),lookbehind:!0,greedy:!0},number:{pattern:o(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(e)}e.exports=t,t.displayName="yaml",t.aliases=["yml"]},80741(e){"use strict";function t(e){e.languages.yang={comment:/\/\*[\s\S]*?\*\/|\/\/.*/,string:{pattern:/"(?:[^\\"]|\\.)*"|'[^']*'/,greedy:!0},keyword:{pattern:/(^|[{};\r\n][ \t]*)[a-z_][\w.-]*/i,lookbehind:!0},namespace:{pattern:/(\s)[a-z_][\w.-]*(?=:)/i,lookbehind:!0},boolean:/\b(?:false|true)\b/,operator:/\+/,punctuation:/[{};:]/}}e.exports=t,t.displayName="yang",t.aliases=[]},86528(e){"use strict";function t(e){!function(e){function t(e){return function(){return e}}var n=/\b(?:align|allowzero|and|asm|async|await|break|cancel|catch|comptime|const|continue|defer|else|enum|errdefer|error|export|extern|fn|for|if|inline|linksection|nakedcc|noalias|null|or|orelse|packed|promise|pub|resume|return|stdcallcc|struct|suspend|switch|test|threadlocal|try|undefined|union|unreachable|usingnamespace|var|volatile|while)\b/,r="\\b(?!"+n.source+")(?!\\d)\\w+\\b",i=/align\s*\((?:[^()]|\([^()]*\))*\)/.source,a=/(?:\?|\bpromise->|(?:\[[^[\]]*\]|\*(?!\*)|\*\*)(?:\s*|\s*const\b|\s*volatile\b|\s*allowzero\b)*)/.source.replace(//g,t(i)),o=/(?:\bpromise\b|(?:\berror\.)?(?:\.)*(?!\s+))/.source.replace(//g,t(r)),s="(?!\\s)(?:!?\\s*(?:"+a+"\\s*)*"+o+")+";e.languages.zig={comment:[{pattern:/\/{3}.*/,alias:"doc-comment"},/\/{2}.*/],string:[{pattern:/(^|[^\\@])c?"(?:[^"\\\r\n]|\\.)*"/,lookbehind:!0,greedy:!0},{pattern:/([\r\n])([ \t]+c?\\{2}).*(?:(?:\r\n?|\n)\2.*)*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\])'(?:[^'\\\r\n]|\\(?:.|x[a-fA-F\d]{2}|u\{[a-fA-F\d]{1,6}\}))'/,lookbehind:!0,greedy:!0}],builtin:/\B@(?!\d)\w+(?=\s*\()/,label:{pattern:/(\b(?:break|continue)\s*:\s*)\w+\b|\b(?!\d)\w+\b(?=\s*:\s*(?:\{|while\b))/,lookbehind:!0},"class-name":[/\b(?!\d)\w+(?=\s*=\s*(?:(?:extern|packed)\s+)?(?:enum|struct|union)\s*[({])/,{pattern:RegExp(/(:\s*)(?=\s*(?:\s*)?[=;,)])|(?=\s*(?:\s*)?\{)/.source.replace(//g,t(s)).replace(//g,t(i))),lookbehind:!0,inside:null},{pattern:RegExp(/(\)\s*)(?=\s*(?:\s*)?;)/.source.replace(//g,t(s)).replace(//g,t(i))),lookbehind:!0,inside:null}],"builtin-types":{pattern:/\b(?:anyerror|bool|c_u?(?:short|int|long|longlong)|c_longdouble|c_void|comptime_(?:float|int)|[iu](?:8|16|32|64|128|size)|f(?:16|32|64|128)|noreturn|type|void)\b/,alias:"keyword"},keyword:n,function:/\b(?!\d)\w+(?=\s*\()/,number:/\b(?:0b[01]+|0o[0-7]+|0x[a-fA-F\d]+(?:\.[a-fA-F\d]*)?(?:[pP][+-]?[a-fA-F\d]+)?|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)\b/,boolean:/\b(?:false|true)\b/,operator:/\.[*?]|\.{2,3}|[-=]>|\*\*|\+\+|\|\||(?:<<|>>|[-+*]%|[-+*/%^&|<>!=])=?|[?~]/,punctuation:/[.:,;(){}[\]]/},e.languages.zig["class-name"].forEach(function(t){null===t.inside&&(t.inside=e.languages.zig)})}(e)}e.exports=t,t.displayName="zig",t.aliases=[]},59216(e,t,n){var r=function(e){var t=/\blang(?:uage)?-([\w-]+)\b/i,n=0,r={},i={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=f.reach));S+=E.value.length,E=E.next){var k,x=E.value;if(t.length>e.length)return;if(!(x instanceof a)){var T=1;if(v){if(!(k=o(_,S,e,g)))break;var M=k.index,O=k.index+k[0].length,A=S;for(A+=E.value.length;M>=A;)A+=(E=E.next).value.length;if(A-=E.value.length,S=A,E.value instanceof a)continue;for(var L=E;L!==t.tail&&(Af.reach&&(f.reach=N);var P=E.prev;I&&(P=c(t,P,I),S+=I.length),l(t,P,T);var R=new a(d,m?i.tokenize(C,m):C,y,C);if(E=c(t,P,R),D&&c(t,E,D),T>1){var j={cause:d+","+p,reach:N};s(e,t,n,E.prev,S,j),f&&j.reach>f.reach&&(f.reach=j.reach)}}}}}}function u(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function c(e,t,n){var r=t.next,i={value:n,prev:t,next:r};return t.next=i,r.prev=i,e.length++,i}function l(e,t,n){for(var r=t.next,i=0;i"+a.content+""},!e.document)return e.addEventListener&&(i.disableWorkerMessageHandler||e.addEventListener("message",function(t){var n=JSON.parse(t.data),r=n.language,a=n.code,o=n.immediateClose;e.postMessage(i.highlight(a,i.languages[r],r)),o&&e.close()},!1)),i;var d=i.util.currentScript();function h(){i.manual||i.highlightAll()}if(d&&(i.filename=d.src,d.hasAttribute("data-manual")&&(i.manual=!0)),!i.manual){var p=document.readyState;"loading"===p||"interactive"===p&&d&&d.defer?document.addEventListener("DOMContentLoaded",h):window.requestAnimationFrame?window.requestAnimationFrame(h):window.setTimeout(h,16)}return i}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});e.exports&&(e.exports=r),void 0!==n.g&&(n.g.Prism=r)},89509(e,t,n){/*! safe-buffer. MIT License. Feross Aboukhadijeh */ var r=n(48764),i=r.Buffer;function a(e,t){for(var n in e)t[n]=e[n]}function o(e,t,n){return i(e,t,n)}i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?e.exports=r:(a(r,t),t.Buffer=o),o.prototype=Object.create(i.prototype),a(i,o),o.from=function(e,t,n){if("number"==typeof e)throw TypeError("Argument must not be a number");return i(e,t,n)},o.alloc=function(e,t,n){if("number"!=typeof e)throw TypeError("Argument must be a number");var r=i(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},o.allocUnsafe=function(e){if("number"!=typeof e)throw TypeError("Argument must be a number");return i(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw TypeError("Argument must be a number");return r.SlowBuffer(e)}},60053(e,t){"use strict";if(/** @license React v0.18.0 + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nOB});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(97779),h=n(47886),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(55977),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e5(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e6(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n7.kG)(!!n,32),n}var rb=n(10542),rm=n(53712),rg=n(21436),rv=Object.prototype.hasOwnProperty;function ry(e,t){return void 0===t&&(t=Object.create(null)),rw(rp(t.client),e).useQuery(t)}function rw(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new r_(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var r_=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rb.J)({loading:!0,data:void 0,error:void 0,networkStatus:rc.I.loading}),this.skipStandbyResult=(0,rb.J)({loading:!1,data:void 0,error:void 0,networkStatus:rc.I.ready}),this.toQueryResultCache=new(re.mr?WeakMap:Map),rh(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n7.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,rs.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rn((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ra.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rv.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ra.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:rc.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ra.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rm.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ro.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,n8._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n7.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rg.O)(e.errors)?new ru.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,n8._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,n8.pi)((0,n8.pi)((0,n8.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rg.O)(e.errors)&&(t.error=new ru.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:rc.I.refetch}),this.observable.refetch())},e}();function rE(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return ry(i$,e)},iG=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=iz({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(ij,null):o?l.createElement(iN,{error:o}):i?l.createElement(iD,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iW=n(67932),iK=n(8126),iV="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iq(e){if(iZ())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iZ(){return("undefined"==typeof Intl?"undefined":iV(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iX="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iJ=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iX(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iX(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i0=i1;var i2=new i0;function i3(e,t){if(!iZ())return function(e){return e.toString()};var n=i5(e),r=JSON.stringify(t),i=i2.get(String(n),r)||i2.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i4={};function i5(e){var t=e.toString();return i4[t]?i4[t]:i4[t]=iq(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i9(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i7(e)}function i7(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var ae=n(54087),at=n.n(ae);function an(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)ao(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=at()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){at().cancel(this.scheduledTick)}};function aa(e){var t=ar(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function ao(e,t){aa(e),au(t,e),as(t,e)}function as(e,t){var n=ac(e,t);e.splice(n,0,t)}function au(e,t){var n=e.indexOf(t);e.splice(n,1)}function ac(e,t){var n=t.nextUpdateTime;return an(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var al=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),af=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(al).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),ad=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ab(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ap(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iK.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iK.Z(y)},[y]);t=(0,l.useMemo)(function(){return i9(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ah(u,2),l=c[0],f=c[1];return f=o?av:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ah(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ah(M,2),A=O[0],L=O[1],C=ah((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ai.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ah(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i3(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,ad({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,ad({},f,{verboseDate:I?R:void 0}),j):j}ab.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:af,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ab.defaultProps={locales:[],component:ay,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ab=l.memo(ab);let am=ab;var ag,av=31536e9;function ay(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ap(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",ad({},a,{dateTime:o,title:r?n:void 0}),i)}ay.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var aw=n(30381),a_=n.n(aw),aE=n(31657);function aS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ak(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new ru.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ra.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ra.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,n8.pi)({reset:c},a)]}var ou=n(59067),oc=n(28428),ol=n(11186),of=n(78513);function od(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var oh=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:od({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},op=(0,b.withStyles)(oh)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ia.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),ob=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},om=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},og=(0,b.withStyles)(oh)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function ov(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sZ=sq;function sX(e,t){var n=this.__data__,r=s$(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sJ=sX;function sQ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cI}let cN=cD;var cP="[object Arguments]",cR="[object Array]",cj="[object Boolean]",cF="[object Date]",cY="[object Error]",cB="[object Function]",cU="[object Map]",cH="[object Number]",c$="[object Object]",cz="[object RegExp]",cG="[object Set]",cW="[object String]",cK="[object WeakMap]",cV="[object ArrayBuffer]",cq="[object DataView]",cZ="[object Float64Array]",cX="[object Int8Array]",cJ="[object Int16Array]",cQ="[object Int32Array]",c1="[object Uint8Array]",c0="[object Uint8ClampedArray]",c2="[object Uint16Array]",c3="[object Uint32Array]",c4={};function c5(e){return eD(e)&&cN(e.length)&&!!c4[eC(e)]}c4["[object Float32Array]"]=c4[cZ]=c4[cX]=c4[cJ]=c4[cQ]=c4[c1]=c4[c0]=c4[c2]=c4[c3]=!0,c4[cP]=c4[cR]=c4[cV]=c4[cj]=c4[cq]=c4[cF]=c4[cY]=c4[cB]=c4[cU]=c4[cH]=c4[c$]=c4[cz]=c4[cG]=c4[cW]=c4[cK]=!1;let c6=c5;function c9(e){return function(t){return e(t)}}let c8=c9;var c7=n(79730),le=c7.Z&&c7.Z.isTypedArray,lt=le?c8(le):c6;let ln=lt;var lr=Object.prototype.hasOwnProperty;function li(e,t){var n=cT(e),r=!n&&ck(e),i=!n&&!r&&(0,cM.Z)(e),a=!n&&!r&&!i&&ln(e),o=n||r||i||a,s=o?cm(e.length,String):[],u=s.length;for(var c in e)(t||lr.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cC(c,u)))&&s.push(c);return s}let la=li;var lo=Object.prototype;function ls(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||lo)}let lu=ls;var lc=sM(Object.keys,Object);let ll=lc;var lf=Object.prototype.hasOwnProperty;function ld(e){if(!lu(e))return ll(e);var t=[];for(var n in Object(e))lf.call(e,n)&&"constructor"!=n&&t.push(n);return t}let lh=ld;function lp(e){return null!=e&&cN(e.length)&&!ui(e)}let lb=lp;function lm(e){return lb(e)?la(e):lh(e)}let lg=lm;function lv(e,t){return e&&cp(t,lg(t),e)}let ly=lv;function lw(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let l_=lw;var lE=Object.prototype.hasOwnProperty;function lS(e){if(!ed(e))return l_(e);var t=lu(e),n=[];for(var r in e)"constructor"==r&&(t||!lE.call(e,r))||n.push(r);return n}let lk=lS;function lx(e){return lb(e)?la(e,!0):lk(e)}let lT=lx;function lM(e,t){return e&&cp(t,lT(t),e)}let lO=lM;var lA=n(42896);function lL(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hc(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hl=function(e){return Array.isArray(e)&&0===e.length},hf=function(e){return"function"==typeof e},hd=function(e){return null!==e&&"object"==typeof e},hh=function(e){return String(Math.floor(Number(e)))===e},hp=function(e){return"[object String]"===Object.prototype.toString.call(e)},hb=function(e){return 0===l.Children.count(e)},hm=function(e){return hd(e)&&hf(e.then)};function hg(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hy(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hg(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hv(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sx.all([t,n,r],{arrayMerge:hC})})},[h.validate,h.validationSchema,T,S,k]),O=hP(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sh()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sh()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hm(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sh()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hk,E({type:"SET_ERRORS",payload:h.initialErrors||hk}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hx,E({type:"SET_TOUCHED",payload:h.initialTouched||hx}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hP(function(e){if(y.current[e]&&hf(y.current[e].validate)){var t=hg(_.values,e),n=y.current[e].validate(t);return hm(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hP(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hP(function(e,t){var r=hf(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hP(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hv(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hp(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hD(hg(_.values,r),l,c):d?hI(f):c}r&&j(r,i)},[j,_.values]),Y=hP(function(e){if(hp(e))return function(t){return F(t,e)};F(e)}),B=hP(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hP(function(e){if(hp(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hf(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hP(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hP(function(){return f(_.values,V)}),Z=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hg(_.values,e),error:hg(_.errors,e),touched:!!hg(_.touched,e),initialValue:hg(p.current,e),initialTouched:!!hg(m.current,e),initialError:hg(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hd(e),n=t?e.name:e,r=hg(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sh()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hf(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ho({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hM(e){var t=hT(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(h_,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hf(r)?r(t):hb(r)?null:l.Children.only(r):null)}function hO(e){var t={};if(e.inner){if(0===e.inner.length)return hv(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hg(t,o.path)||(t=hv(t,o.path,o.message))}}return t}function hA(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hL(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hL(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sj(e)?hL(e):""!==e?e:void 0}):sj(e[r])?t[r]=hL(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hC(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sx(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sx(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hI(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hD(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hN="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hP(e){var t=(0,l.useRef)(e);return hN(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ho({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hv(n.values,a,e(hg(n.values,a))),u=r?i(hg(n.errors,a)):void 0,c=t?o(hg(n.touched,a)):void 0;return hl(u)&&(u=void 0),hl(c)&&(c=void 0),ho({},n,{values:s,errors:r?hv(n.errors,a,u):n.errors,touched:t?hv(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hH(t),[ha(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},function(t){return hB(t,e,null)},function(t){return hB(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hU(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hc(n)),n.pop=n.pop.bind(hc(n)),n}hs(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sh()(hg(e.formik.values,e.name),hg(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hH(n):[];return t||(t=r[e]),hf(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hu(t.formik,["validate","validationSchema"]),s=ho({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hb(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var h$=n(24802),hz=n(71209),hG=n(91750),hW=n(11970),hK=n(4689),hV=n(67598),hq=function(){return(hq=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hX(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hZ(e,["disabled","field","form","onBlur","helperText"]),d=hg(u,i.name),h=hg(s,i.name)&&!!d;return hq(hq({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hJ(e){var t=e.children,n=hZ(e,["children"]);return(0,l.createElement)(i_.Z,hq({},hX(n)),t)}function hQ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h1(e){return(0,l.createElement)(h$.Z,hq({},hQ(e)))}function h0(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hZ(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h2(e){return(0,l.createElement)(hz.Z,hq({},h0(e)))}function h3(e){var t=e.Label,n=hZ(e,["Label"]);return(0,l.createElement)(hG.Z,hq({control:(0,l.createElement)(hz.Z,hq({},h0(n)))},t))}function h4(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h5(e){return(0,l.createElement)(hW.default,hq({},h4(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hZ(t,["onBlur"]),i=(e.form,e.onBlur),a=hZ(e,["field","form","onBlur"]);return hq(hq({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h9(e){return(0,l.createElement)(hK.Z,hq({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h7(e){return(0,l.createElement)(hV.default,hq({},h8(e)))}hJ.displayName="FormikMaterialUITextField",h1.displayName="FormikMaterialUISwitch",h2.displayName="FormikMaterialUICheckbox",h3.displayName="FormikMaterialUICheckboxWithLabel",h5.displayName="FormikMaterialUISelect",h9.displayName="FormikMaterialUIRadioGroup",h7.displayName="FormikMaterialUIInputBase";try{a=Map}catch(pe){}try{o=Set}catch(pt){}function pn(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pr);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pn(e[i],t,n)}return r}return e}function pr(e){return pn(e,[],[])}let pi=Object.prototype.toString,pa=Error.prototype.toString,po=RegExp.prototype.toString,ps="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",pu=/^Symbol\((.*)\)(.*)$/;function pc(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pl(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pc(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return ps.call(e).replace(pu,"Symbol($1)");let r=pi.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pa.call(e)+"]":"RegExp"===r?po.call(e):null}function pf(e,t){let n=pl(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pl(this[e],t);return null!==r?r:n},2)}let pd={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pf(n,!0)}\``+(i?` (cast from the value \`${pf(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},ph={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},pp={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pb={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pm={isValue:"${path} field must be ${value}"},pg={noUnknown:"${path} field has unspecified keys: ${unknown}"},pv={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pd,string:ph,number:pp,date:pb,object:pg,array:pv,boolean:pm});var py=n(18721),pw=n.n(py);let p_=e=>e&&e.__isYupSchema__;class pE{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!pw()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!p_(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pS=pE;function pk(e){return null==e?[]:[].concat(e)}function px(){return(px=Object.assign||function(e){for(var t=1;tpf(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pk(e).forEach(e=>{pM.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pM)}}let pO=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pA(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pO(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pM(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pj(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pR(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pN.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pC()(pP({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pM(pM.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pP({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pM.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pM.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pN.prototype.__isYupRef=!0;let pF=e=>e.substr(0,e.length-1).substr(1);function pY(e,t,n,r=n){let i,a,o;return t?((0,pI.forEach)(t,(s,u,c)=>{let l=u?pF(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pB{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pN.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pN.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pB;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pU(){return(pU=Object.assign||function(e){for(var t=1;t{this.typeError(pd.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pU({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pU({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pr(pU({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pU({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pU({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pf(e),a=pf(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". + +attempted value: ${i} +`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566),gb=n(68239);function gm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gg(){var e=gm(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gg=function(){return e},e}var gv=function(){var e="[[TelemetryIngress.Endpoints]] \nNetwork = '...' # e.g. EVM. Solana, Starknet, Cosmos \nChainID = '...' # e.g. 1, 5, devnet, mainnet-beta URL\nURL = '...'\nServerPubKey = '...'";return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Deprecation warning"}),l.createElement(aK.Z,null,l.createElement(x.default,{variant:"h5",gutterBottom:!0},"Starting in ",l.createElement("code",null,"v2.9.0"),":"),l.createElement(w.default,{dense:!0},l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"TelemetryIngress.URL")," and"," ",l.createElement("code",null,"TelemetryIngress.ServerPubKey")," will no longer be allowed. Please switch to ",l.createElement("code",null,"TelemetryIngress.Endpoints"),":",l.createElement(gh,{language:"toml",style:gu},e))),l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"P2P.V1")," will no longer be supported and must not be set in TOML configuration in order to boot. Use"," ",l.createElement("code",null,"P2P.V2")," instead. If you are using both,"," ",l.createElement("code",null,"V1")," can simply be removed.")))))},gy=n0(gg()),gw=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},g_=function(){return l.createElement(gw,null,"...")},gE=function(e){var t=e.children;return l.createElement(gw,null,t)},gS=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gE,null,i);if(t)return l.createElement(g_,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gk=function(){var e=ry(gy,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gv,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(gS,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gx=n(34823),gT=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gM=(0,b.withStyles)(gT)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gx.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gO=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gk,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gM,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gA=function(){return l.createElement(gO,null)},gL=function(){return l.createElement(gA,null)},gC=n(44431),gI=1e18,gD=function(e){return new gC.BigNumber(e).dividedBy(gI).toFixed(8)},gN=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gD(e.linkBalance):"--"}))))})),r+1s&&l.createElement(g$.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vi(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function va(){var e=vi(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return va=function(){return e},e}var vo=5,vs=n0(va(),vt),vu=function(){var e=ry(vs,{variables:{offset:0,limit:vo},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vr,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vo})},vc=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=(0,A.v9)(gx.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vf=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vd=(0,b.withStyles)(vf)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vp(){var e=vh(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vp=function(){return e},e}var vb=n0(vp()),vm=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vg=(0,b.withStyles)(vm)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gz,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vd,{job:e,key:t})}))))});function vv(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vy(){var e=vv(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vy=function(){return e},e}var vw=5,v_=n0(vy(),vb),vE=function(){var e=ry(v_,{variables:{offset:0,limit:vw},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vg,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},vS=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vu,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gH,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vE,null))))),l.createElement(vl,null))},vk=function(){return l.createElement(vS,null)},vx=function(){return l.createElement(vk,null)},vT=n(87239),vM=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vO=n(5022),vA=n(78718),vL=n.n(vA);function vC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,ym(t,e.status))},e.status.toLowerCase())))})))}),yv=n(16839),yy=n.n(yv);function yw(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yy().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var y_=n(94164),yE=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},yS=n(73343),yk=n(3379),yx=n.n(yk);function yT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(y_.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:yS.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yE,{data:e}))}))};function yD(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyH&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yU,{observationSource:n.observationSource})))});function yG(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vO.parse(e),!0}catch(t){return!1}})}),wq=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wV,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wZ=n(50109),wX="persistSpec";function wJ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wZ.t8(wX,n),{toml:n}):{toml:wZ.U2(wX)||""}}var wQ=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wJ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wZ.t8("".concat(wX),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wq,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function w1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _L(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_q,e)},_X=function(){var e=_Z({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_z,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_J=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_O,{data:t.publicKey}))))};function _Q(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _1(){var e=_Q(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _1=function(){return e},e}var _0=n0(_1()),_2=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gz,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_J,{csaKey:e,key:t})}))))};function _3(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EL,e)};function EI(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(E0,e)},E6=function(){return os(E2)},E9=function(){return os(E3)},E8=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E4,e)};function E7(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SZ,e)};function SJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kX(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kJ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kZ(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kq(kK({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(kG,{object:n})))};function kQ(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function k1(e){for(var t=1;t0&&l.createElement(ko,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kJ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kj,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k7(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xe(){var e=k7(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return xe=function(){return e},e}var xt=n0(xe(),k9),xn=function(){var e=ry(xt,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k8,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xr(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xi(){var e=xr(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xi=function(){return e},e}var xa=n0(xi()),xo=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yg,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xs(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xu(){var e=xs(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xu=function(){return e},e}var xc=n0(xu(),xa),xl=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xc,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xo,{loading:a,data:i,page:t,pageSize:n})},xf=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xl,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xn,null)))},xd=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xh=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xd,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xp=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:r,onSubmit:n})))))};function xb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xm(){var e=xb(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xm=function(){return e},e}var xg=n0(xm()),xv=function(){return ry(xg)};function xy(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xJ,e)};function x1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(Tz,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},TW={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TK=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:TW,onSubmit:t})))))};function TV(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mm(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(El.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?M_[c.action].title:"",body:c?M_[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mo,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function MS(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function Mk(){var e=MS(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return Mk=function(){return e},e}var Mx=n0(Mk(),My),MT=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(Me,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(T$,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ME,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function MM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file diff --git a/core/web/assets/main.b0b6f79f7f4a94560e37.js.gz b/core/web/assets/main.b0b6f79f7f4a94560e37.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..c505ea9eeade9a8933c1cc213f6e6d36bc873d85 GIT binary patch literal 1190421 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%0ATK8*z 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

q-69bB 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⋘9WypiZQs1-~Ge>)B|BoKah9Mm~o6rU-4 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�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 z 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

@-7&N=W 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 literal 0 HcmV?d00001 diff --git a/core/web/middleware.go b/core/web/middleware.go index 91c618cecb..17bd7e65eb 100644 --- a/core/web/middleware.go +++ b/core/web/middleware.go @@ -21,6 +21,7 @@ import ( // inside this module. To achieve this, we direct webpack to output all of the compiled assets // in this module's folder under the "assets" directory. +//go:generate ../../operator_ui/install.sh //go:embed "assets" var uiEmbedFs embed.FS From bde6a2aea2321f2dc26773f445d1cb19e2bc98e7 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 22 Nov 2023 12:58:59 -0500 Subject: [PATCH 192/327] Adding TLS connection between node and OTEL collector for traces (#11278) * feature/tracing-credentials: adding TLS connection between node and OTEL collector for traces * feature/tracing-credentials: adding Tracing.Mode to configure insecure credentials explicitly * feature/tracing-credentials: relaxing conditions for Tracing.Mode and Tracing.TLSCertPath * feature/tracing-credentials: moving make file changes to a separate PR * feature/tracing-credentials: bumping relay and lint * feature/tracing-credentials: 'secure' --> 'tls' and 'insecure' --> 'unencrypted' * feature/tracing-credentials: minor docs refactoring * feature/tracing-credentials: adding changelog --- .github/tracing/README.md | 9 +- core/config/docs/core.toml | 10 +- core/config/toml/types.go | 63 ++++- core/config/toml/types_test.go | 230 +++++++++++++++++- core/config/tracing_config.go | 4 +- core/services/chainlink/config.go | 21 ++ core/services/chainlink/config_general.go | 2 +- core/services/chainlink/config_test.go | 82 ++++++- core/services/chainlink/config_tracing.go | 16 +- .../services/chainlink/config_tracing_test.go | 8 + .../testdata/config-empty-effective.toml | 2 + .../chainlink/testdata/config-full.toml | 2 + .../config-multi-chain-effective.toml | 2 + .../testdata/config-empty-effective.toml | 2 + core/web/resolver/testdata/config-full.toml | 2 + .../config-multi-chain-effective.toml | 2 + docs/CHANGELOG.md | 1 + docs/CONFIG.md | 26 +- integration-tests/types/config/node/core.go | 5 +- plugins/loop_registry.go | 3 +- plugins/loop_registry_test.go | 11 +- testdata/scripts/node/db/help.txtar | 2 +- testdata/scripts/node/validate/default.txtar | 2 + .../disk-based-logging-disabled.txtar | 2 + .../validate/disk-based-logging-no-dir.txtar | 2 + .../node/validate/disk-based-logging.txtar | 2 + testdata/scripts/node/validate/invalid.txtar | 2 + testdata/scripts/node/validate/valid.txtar | 2 + testdata/scripts/node/validate/warnings.txtar | 21 +- 29 files changed, 497 insertions(+), 41 deletions(-) diff --git a/.github/tracing/README.md b/.github/tracing/README.md index eb75738429..feba31feb6 100644 --- a/.github/tracing/README.md +++ b/.github/tracing/README.md @@ -30,7 +30,14 @@ Another way to generate traces is by enabling traces for PRs. This will instrume 8. Run `sh replay.sh` to replay those traces to the otel-collector container that was spun up in the last step. 9. navigate to `localhost:3000/explore` in a web browser to query for traces -The artifact is not json encoded - each individual line is a well formed and complete json object. +The artifact is not json encoded - each individual line is a well formed and complete json object. + + +## Production and NOPs environments + +In a production environment, we suggest coupling the lifecycle of nodes and otel-collectors. A best practice is to deploy the otel-collector alongside your node, using infrastructure as code (IAC) to automate deployments and certificate lifecycles. While there are valid use cases for using `Tracing.Mode = unencrypted`, we have set the default encryption setting to `Tracing.Mode = tls`. Externally deployed otel-collectors can not be used with `Tracing.Mode = unencrypted`. i.e. If `Tracing.Mode = unencrypted` and an external URI is detected for `Tracing.CollectorTarget` node configuration will fail to validate and the node will not boot. The node requires a valid encryption mode and collector target to send traces. + +Once traces reach the otel-collector, the rest of the observability pipeline is flexible. We recommend deploying (through automation) centrally managed Grafana Tempo and Grafana UI instances to receive from one or many otel-collector instances. Always use networking best practices and encrypt trace data, especially at network boundaries. ## Configuration This folder contains the following config files: diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 148de90cd9..79801c2c52 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -587,13 +587,17 @@ DisableRateLimiting = false # Default # Enabled turns trace collection on or off. On requires an OTEL Tracing Collector. Enabled = false # Default # CollectorTarget is the logical address of the OTEL Tracing Collector. -CollectorTarget = "localhost:4317" # Example +CollectorTarget = 'localhost:4317' # Example # NodeID is an unique name for this node relative to any other node traces are collected for. -NodeID = "NodeID" # Example +NodeID = 'NodeID' # Example # SamplingRatio is the ratio of traces to sample for this node. SamplingRatio = 1.0 # Example +# Mode is a string value. `tls` or `unencrypted` are the only values allowed. If set to `unencrypted`, `TLSCertPath` can be unset, meaning traces will be sent over plaintext to the collector. +Mode = 'tls' # Default +# TLSCertPath is the file path to the TLS certificate used for secure communication with an OTEL Tracing Collector. +TLSCertPath = '/path/to/cert.pem' # Example # Tracing.Attributes are user specified key-value pairs to associate in the context of the traces [Tracing.Attributes] # env is an example user specified key-value pair -env = "test" # Example +env = 'test' # Example diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 61962d43e5..31076c1f1d 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -1455,6 +1455,8 @@ type Tracing struct { CollectorTarget *string NodeID *string SamplingRatio *float64 + Mode *string + TLSCertPath *string Attributes map[string]string `toml:",omitempty"` } @@ -1474,6 +1476,12 @@ func (t *Tracing) setFrom(f *Tracing) { if v := f.SamplingRatio; v != nil { t.SamplingRatio = f.SamplingRatio } + if v := f.Mode; v != nil { + t.Mode = f.Mode + } + if v := f.TLSCertPath; v != nil { + t.TLSCertPath = f.TLSCertPath + } } func (t *Tracing) ValidateConfig() (err error) { @@ -1487,10 +1495,39 @@ func (t *Tracing) ValidateConfig() (err error) { } } - if t.CollectorTarget != nil { - ok := isValidURI(*t.CollectorTarget) - if !ok { - err = multierr.Append(err, configutils.ErrInvalid{Name: "CollectorTarget", Value: *t.CollectorTarget, Msg: "must be a valid URI"}) + if t.Mode != nil { + switch *t.Mode { + case "tls": + // TLSCertPath must be set + if t.TLSCertPath == nil { + err = multierr.Append(err, configutils.ErrMissing{Name: "TLSCertPath", Msg: "must be set when Tracing.Mode is tls"}) + } else { + ok := isValidFilePath(*t.TLSCertPath) + if !ok { + err = multierr.Append(err, configutils.ErrInvalid{Name: "TLSCertPath", Value: *t.TLSCertPath, Msg: "must be a valid file path"}) + } + } + case "unencrypted": + // no-op + default: + // Mode must be either "tls" or "unencrypted" + err = multierr.Append(err, configutils.ErrInvalid{Name: "Mode", Value: *t.Mode, Msg: "must be either 'tls' or 'unencrypted'"}) + } + } + + if t.CollectorTarget != nil && t.Mode != nil { + switch *t.Mode { + case "tls": + if !isValidURI(*t.CollectorTarget) { + err = multierr.Append(err, configutils.ErrInvalid{Name: "CollectorTarget", Value: *t.CollectorTarget, Msg: "must be a valid URI"}) + } + case "unencrypted": + // Unencrypted traces can not be sent to external networks + if !isValidLocalURI(*t.CollectorTarget) { + err = multierr.Append(err, configutils.ErrInvalid{Name: "CollectorTarget", Value: *t.CollectorTarget, Msg: "must be a valid local URI"}) + } + default: + // no-op } } @@ -1499,15 +1536,19 @@ func (t *Tracing) ValidateConfig() (err error) { var hostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*$`) +// Validates uri is valid external or local URI func isValidURI(uri string) bool { if strings.Contains(uri, "://") { - // Standard URI check - _, _ = url.ParseRequestURI(uri) - // TODO: BCF-2703. Handle error. All external addresses currently fail validation until we have secure transport to external networks. - return false + _, err := url.ParseRequestURI(uri) + return err == nil } - // For URIs like "otel-collector:4317" + return isValidLocalURI(uri) +} + +// isValidLocalURI returns true if uri is a valid local URI +// External URIs (e.g. http://) are not valid local URIs, and will return false. +func isValidLocalURI(uri string) bool { parts := strings.Split(uri, ":") if len(parts) == 2 { host, port := parts[0], parts[1] @@ -1530,3 +1571,7 @@ func isValidURI(uri string) bool { func isValidHostname(hostname string) bool { return hostnameRegex.MatchString(hostname) } + +func isValidFilePath(path string) bool { + return len(path) > 0 && len(path) < 4096 +} diff --git a/core/config/toml/types_test.go b/core/config/toml/types_test.go index 92aaa02430..e16d3a864d 100644 --- a/core/config/toml/types_test.go +++ b/core/config/toml/types_test.go @@ -185,55 +185,115 @@ func TestTracing_ValidateCollectorTarget(t *testing.T) { tests := []struct { name string collectorTarget *string + mode *string wantErr bool errMsg string }{ { - name: "valid http address", + name: "valid http address in tls mode", + collectorTarget: ptr("https://testing.collector.dev"), + mode: ptr("tls"), + wantErr: false, + }, + { + name: "valid http address in unencrypted mode", collectorTarget: ptr("https://localhost:4317"), - // TODO: BCF-2703. Re-enable when we have secure transport to otel collectors in external networks - wantErr: true, - errMsg: "CollectorTarget: invalid value (https://localhost:4317): must be a valid URI", + mode: ptr("unencrypted"), + wantErr: true, + errMsg: "CollectorTarget: invalid value (https://localhost:4317): must be a valid local URI", }, + // Tracing.Mode = 'tls' { name: "valid localhost address", collectorTarget: ptr("localhost:4317"), + mode: ptr("tls"), wantErr: false, }, { name: "valid docker address", collectorTarget: ptr("otel-collector:4317"), + mode: ptr("tls"), wantErr: false, }, { name: "valid IP address", collectorTarget: ptr("192.168.1.1:4317"), + mode: ptr("tls"), wantErr: false, }, { name: "invalid port", collectorTarget: ptr("localhost:invalid"), wantErr: true, + mode: ptr("tls"), errMsg: "CollectorTarget: invalid value (localhost:invalid): must be a valid URI", }, { name: "invalid address", collectorTarget: ptr("invalid address"), wantErr: true, + mode: ptr("tls"), errMsg: "CollectorTarget: invalid value (invalid address): must be a valid URI", }, { name: "nil CollectorTarget", collectorTarget: ptr(""), wantErr: true, + mode: ptr("tls"), errMsg: "CollectorTarget: invalid value (): must be a valid URI", }, + // Tracing.Mode = 'unencrypted' + { + name: "valid localhost address", + collectorTarget: ptr("localhost:4317"), + mode: ptr("unencrypted"), + wantErr: false, + }, + { + name: "valid docker address", + collectorTarget: ptr("otel-collector:4317"), + mode: ptr("unencrypted"), + wantErr: false, + }, + { + name: "valid IP address", + collectorTarget: ptr("192.168.1.1:4317"), + mode: ptr("unencrypted"), + wantErr: false, + }, + { + name: "invalid port", + collectorTarget: ptr("localhost:invalid"), + wantErr: true, + mode: ptr("unencrypted"), + errMsg: "CollectorTarget: invalid value (localhost:invalid): must be a valid local URI", + }, + { + name: "invalid address", + collectorTarget: ptr("invalid address"), + wantErr: true, + mode: ptr("unencrypted"), + errMsg: "CollectorTarget: invalid value (invalid address): must be a valid local URI", + }, + { + name: "nil CollectorTarget", + collectorTarget: ptr(""), + wantErr: true, + mode: ptr("unencrypted"), + errMsg: "CollectorTarget: invalid value (): must be a valid local URI", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + var tlsCertPath string + if *tt.mode == "tls" { + tlsCertPath = "/path/to/cert.pem" + } tracing := &Tracing{ Enabled: ptr(true), + TLSCertPath: &tlsCertPath, + Mode: tt.mode, CollectorTarget: tt.collectorTarget, } @@ -309,5 +369,167 @@ func TestTracing_ValidateSamplingRatio(t *testing.T) { } } +func TestTracing_ValidateTLSCertPath(t *testing.T) { + // tests for Tracing.Mode = 'tls' + tls_tests := []struct { + name string + tlsCertPath *string + wantErr bool + errMsg string + }{ + { + name: "valid file path", + tlsCertPath: ptr("/etc/ssl/certs/cert.pem"), + wantErr: false, + }, + { + name: "relative file path", + tlsCertPath: ptr("certs/cert.pem"), + wantErr: false, + }, + { + name: "excessively long file path", + tlsCertPath: ptr(strings.Repeat("z", 4097)), + wantErr: true, + errMsg: "TLSCertPath: invalid value (" + strings.Repeat("z", 4097) + "): must be a valid file path", + }, + { + name: "empty file path", + tlsCertPath: ptr(""), + wantErr: true, + errMsg: "TLSCertPath: invalid value (): must be a valid file path", + }, + } + + // tests for Tracing.Mode = 'unencrypted' + unencrypted_tests := []struct { + name string + tlsCertPath *string + wantErr bool + errMsg string + }{ + { + name: "valid file path", + tlsCertPath: ptr("/etc/ssl/certs/cert.pem"), + wantErr: false, + }, + { + name: "relative file path", + tlsCertPath: ptr("certs/cert.pem"), + wantErr: false, + }, + { + name: "excessively long file path", + tlsCertPath: ptr(strings.Repeat("z", 4097)), + wantErr: false, + }, + { + name: "empty file path", + tlsCertPath: ptr(""), + wantErr: false, + }, + } + + for _, tt := range tls_tests { + t.Run(tt.name, func(t *testing.T) { + tracing := &Tracing{ + Mode: ptr("tls"), + TLSCertPath: tt.tlsCertPath, + Enabled: ptr(true), + } + + err := tracing.ValidateConfig() + + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } + + for _, tt := range unencrypted_tests { + t.Run(tt.name, func(t *testing.T) { + tracing := &Tracing{ + Mode: ptr("unencrypted"), + TLSCertPath: tt.tlsCertPath, + Enabled: ptr(true), + } + + err := tracing.ValidateConfig() + + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestTracing_ValidateMode(t *testing.T) { + tests := []struct { + name string + mode *string + tlsCertPath *string + wantErr bool + errMsg string + }{ + { + name: "tls mode with valid TLS path", + mode: ptr("tls"), + tlsCertPath: ptr("/path/to/cert.pem"), + wantErr: false, + }, + { + name: "tls mode without TLS path", + mode: ptr("tls"), + tlsCertPath: nil, + wantErr: true, + errMsg: "TLSCertPath: missing: must be set when Tracing.Mode is tls", + }, + { + name: "unencrypted mode with TLS path", + mode: ptr("unencrypted"), + tlsCertPath: ptr("/path/to/cert.pem"), + wantErr: false, + }, + { + name: "unencrypted mode without TLS path", + mode: ptr("unencrypted"), + tlsCertPath: nil, + wantErr: false, + }, + { + name: "invalid mode", + mode: ptr("unknown"), + tlsCertPath: nil, + wantErr: true, + errMsg: "Mode: invalid value (unknown): must be either 'tls' or 'unencrypted'", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tracing := &Tracing{ + Enabled: ptr(true), + Mode: tt.mode, + TLSCertPath: tt.tlsCertPath, + } + + err := tracing.ValidateConfig() + + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} + // ptr is a utility function for converting a value to a pointer to the value. func ptr[T any](t T) *T { return &t } diff --git a/core/config/tracing_config.go b/core/config/tracing_config.go index 28584a9cde..307a010c48 100644 --- a/core/config/tracing_config.go +++ b/core/config/tracing_config.go @@ -4,6 +4,8 @@ type Tracing interface { Enabled() bool CollectorTarget() string NodeID() string - Attributes() map[string]string SamplingRatio() float64 + TLSCertPath() string + Mode() string + Attributes() map[string]string } diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 10598718f9..5d8b1019e8 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -52,6 +52,27 @@ func (c *Config) TOMLString() (string, error) { return string(b), nil } +// warnings aggregates warnings from valueWarnings and deprecationWarnings +func (c *Config) warnings() (err error) { + deprecationErr := c.deprecationWarnings() + warningErr := c.valueWarnings() + err = multierr.Append(deprecationErr, warningErr) + _, list := utils.MultiErrorList(err) + return list +} + +// valueWarnings returns an error if the Config contains values that hint at misconfiguration before defaults are applied. +func (c *Config) valueWarnings() (err error) { + if c.Tracing.Enabled != nil && *c.Tracing.Enabled { + if c.Tracing.Mode != nil && *c.Tracing.Mode == "unencrypted" { + if c.Tracing.TLSCertPath != nil { + err = multierr.Append(err, config.ErrInvalid{Name: "Tracing.TLSCertPath", Value: *c.Tracing.TLSCertPath, Msg: "must be empty when Tracing.Mode is 'unencrypted'"}) + } + } + } + return +} + // deprecationWarnings returns an error if the Config contains deprecated fields. // This is typically used before defaults have been applied, with input from the user. func (c *Config) deprecationWarnings() (err error) { diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 6a835e09c8..fff7822a81 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -137,7 +137,7 @@ func (o GeneralConfigOpts) New() (GeneralConfig, error) { return nil, err } - _, warning := utils.MultiErrorList(o.Config.deprecationWarnings()) + _, warning := utils.MultiErrorList(o.Config.warnings()) o.Config.setDefaults() if !o.SkipEnv { diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 891c0a490f..33fda22128 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -227,11 +227,13 @@ func TestConfig_Marshal(t *testing.T) { Enabled: ptr(true), CollectorTarget: ptr("localhost:4317"), NodeID: ptr("clc-ocr-sol-devnet-node-1"), + SamplingRatio: ptr(1.0), + Mode: ptr("tls"), + TLSCertPath: ptr("/path/to/cert.pem"), Attributes: map[string]string{ "test": "load", "env": "dev", }, - SamplingRatio: ptr(1.0), }, }, } @@ -688,6 +690,8 @@ Enabled = true CollectorTarget = 'localhost:4317' NodeID = 'clc-ocr-sol-devnet-node-1' SamplingRatio = 1.0 +Mode = 'tls' +TLSCertPath = '/path/to/cert.pem' [Tracing.Attributes] env = 'dev' @@ -1537,4 +1541,80 @@ func TestConfig_SetFrom(t *testing.T) { } } +func TestConfig_Warnings(t *testing.T) { + tests := []struct { + name string + config Config + expectedErrors []string + }{ + { + name: "No warnings", + config: Config{}, + expectedErrors: nil, + }, + { + name: "Value warning - unencrypted mode with TLS path set", + config: Config{ + Core: toml.Core{ + Tracing: toml.Tracing{ + Enabled: ptr(true), + Mode: ptr("unencrypted"), + TLSCertPath: ptr("/path/to/cert.pem"), + }, + }, + }, + expectedErrors: []string{"Tracing.TLSCertPath: invalid value (/path/to/cert.pem): must be empty when Tracing.Mode is 'unencrypted'"}, + }, + { + name: "Deprecation warning - P2P.V1 fields set", + config: Config{ + Core: toml.Core{ + P2P: toml.P2P{ + V1: toml.P2PV1{ + Enabled: ptr(true), + }, + }, + }, + }, + expectedErrors: []string{ + "P2P.V1: is deprecated and will be removed in a future version", + }, + }, + { + name: "Value warning and deprecation warning", + config: Config{ + Core: toml.Core{ + P2P: toml.P2P{ + V1: toml.P2PV1{ + Enabled: ptr(true), + }, + }, + Tracing: toml.Tracing{ + Enabled: ptr(true), + Mode: ptr("unencrypted"), + TLSCertPath: ptr("/path/to/cert.pem"), + }, + }, + }, + expectedErrors: []string{ + "Tracing.TLSCertPath: invalid value (/path/to/cert.pem): must be empty when Tracing.Mode is 'unencrypted'", + "P2P.V1: is deprecated and will be removed in a future version", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.config.warnings() + if len(tt.expectedErrors) == 0 { + assert.NoError(t, err) + } else { + for _, expectedErr := range tt.expectedErrors { + assert.Contains(t, err.Error(), expectedErr) + } + } + }) + } +} + func ptr[T any](t T) *T { return &t } diff --git a/core/services/chainlink/config_tracing.go b/core/services/chainlink/config_tracing.go index 390645974f..36d09ae056 100644 --- a/core/services/chainlink/config_tracing.go +++ b/core/services/chainlink/config_tracing.go @@ -18,10 +18,18 @@ func (t tracingConfig) NodeID() string { return *t.s.NodeID } -func (t tracingConfig) Attributes() map[string]string { - return t.s.Attributes -} - func (t tracingConfig) SamplingRatio() float64 { return *t.s.SamplingRatio } + +func (t tracingConfig) Mode() string { + return *t.s.Mode +} + +func (t tracingConfig) TLSCertPath() string { + return *t.s.TLSCertPath +} + +func (t tracingConfig) Attributes() map[string]string { + return t.s.Attributes +} diff --git a/core/services/chainlink/config_tracing_test.go b/core/services/chainlink/config_tracing_test.go index 5968bc306a..37653729cf 100644 --- a/core/services/chainlink/config_tracing_test.go +++ b/core/services/chainlink/config_tracing_test.go @@ -14,12 +14,16 @@ func TestTracing_Config(t *testing.T) { collectorTarget := "http://localhost:9000" nodeID := "Node1" samplingRatio := 0.5 + mode := "tls" + tlsCertPath := "/path/to/cert.pem" attributes := map[string]string{"key": "value"} tracing := toml.Tracing{ Enabled: &enabled, CollectorTarget: &collectorTarget, NodeID: &nodeID, SamplingRatio: &samplingRatio, + Mode: &mode, + TLSCertPath: &tlsCertPath, Attributes: attributes, } tConfig := tracingConfig{s: tracing} @@ -28,6 +32,8 @@ func TestTracing_Config(t *testing.T) { assert.Equal(t, "http://localhost:9000", tConfig.CollectorTarget()) assert.Equal(t, "Node1", tConfig.NodeID()) assert.Equal(t, 0.5, tConfig.SamplingRatio()) + assert.Equal(t, "tls", tConfig.Mode()) + assert.Equal(t, "/path/to/cert.pem", tConfig.TLSCertPath()) assert.Equal(t, map[string]string{"key": "value"}, tConfig.Attributes()) // Test when all fields are nil @@ -38,5 +44,7 @@ func TestTracing_Config(t *testing.T) { assert.Panics(t, func() { nilConfig.CollectorTarget() }) assert.Panics(t, func() { nilConfig.NodeID() }) assert.Panics(t, func() { nilConfig.SamplingRatio() }) + assert.Panics(t, func() { nilConfig.Mode() }) + assert.Panics(t, func() { nilConfig.TLSCertPath() }) assert.Nil(t, nilConfig.Attributes()) } diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index b897fba7f1..8f3135b34e 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -232,3 +232,5 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 531c98d734..eca5f6f96d 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -238,6 +238,8 @@ Enabled = true CollectorTarget = 'localhost:4317' NodeID = 'clc-ocr-sol-devnet-node-1' SamplingRatio = 1.0 +Mode = 'tls' +TLSCertPath = '/path/to/cert.pem' [Tracing.Attributes] env = 'dev' diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index c743601ced..6a60dfd419 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -232,6 +232,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' [[EVM]] ChainID = '1' diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index b897fba7f1..8f3135b34e 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -232,3 +232,5 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 6cd6eaabc3..7e9872e955 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -238,6 +238,8 @@ Enabled = false CollectorTarget = 'localhost:4317' NodeID = 'NodeID' SamplingRatio = 1.0 +Mode = 'tls' +TLSCertPath = '/path/to/cert.pem' [Tracing.Attributes] env = 'dev' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index c743601ced..6a60dfd419 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -232,6 +232,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' [[EVM]] ChainID = '1' diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8e016347c4..265222c8be 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added distributed tracing in the OpenTelemetry trace format to the node, currently focused at the LOOPP Plugin development effort. This includes a new set of `Tracing` TOML configurations. The default for collecting traces is off - you must explicitly enable traces and setup a valid OpenTelemetry collector. Refer to `.github/tracing/README.md` for more details. - Added a new, optional WebServer authentication option that supports LDAP as a user identity provider. This enables user login access and user roles to be managed and provisioned via a centralized remote server that supports the LDAP protocol, which can be helpful when running multiple nodes. See the documentation for more information and config setup instructions. There is a new `[WebServer].AuthenticationMethod` config option, when set to `ldap` requires the new `[WebServer.LDAP]` config section to be defined, see the reference `docs/core.toml`. - New prom metrics for mercury: `mercury_transmit_queue_delete_error_count` diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 5b93c7061e..63c20bdf4a 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1595,9 +1595,11 @@ DisableRateLimiting skips ratelimiting on asset requests. ```toml [Tracing] Enabled = false # Default -CollectorTarget = "localhost:4317" # Example -NodeID = "NodeID" # Example +CollectorTarget = 'localhost:4317' # Example +NodeID = 'NodeID' # Example SamplingRatio = 1.0 # Example +Mode = 'tls' # Default +TLSCertPath = '/path/to/cert.pem' # Example ``` @@ -1609,13 +1611,13 @@ Enabled turns trace collection on or off. On requires an OTEL Tracing Collector. ### CollectorTarget ```toml -CollectorTarget = "localhost:4317" # Example +CollectorTarget = 'localhost:4317' # Example ``` CollectorTarget is the logical address of the OTEL Tracing Collector. ### NodeID ```toml -NodeID = "NodeID" # Example +NodeID = 'NodeID' # Example ``` NodeID is an unique name for this node relative to any other node traces are collected for. @@ -1625,16 +1627,28 @@ SamplingRatio = 1.0 # Example ``` SamplingRatio is the ratio of traces to sample for this node. +### Mode +```toml +Mode = 'tls' # Default +``` +Mode is a string value. `tls` or `unencrypted` are the only values allowed. If set to `unencrypted`, `TLSCertPath` can be unset, meaning traces will be sent over plaintext to the collector. + +### TLSCertPath +```toml +TLSCertPath = '/path/to/cert.pem' # Example +``` +TLSCertPath is the file path to the TLS certificate used for secure communication with an OTEL Tracing Collector. + ## Tracing.Attributes ```toml [Tracing.Attributes] -env = "test" # Example +env = 'test' # Example ``` Tracing.Attributes are user specified key-value pairs to associate in the context of the traces ### env ```toml -env = "test" # Example +env = 'test' # Example ``` env is an example user specified key-value pair diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index ad85506a04..b7f2b316aa 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -138,11 +138,12 @@ func WithTracing() NodeConfigOpt { Enabled: ptr.Ptr(true), CollectorTarget: ptr.Ptr("otel-collector:4317"), // ksortable unique id - NodeID: ptr.Ptr(ksuid.New().String()), + NodeID: ptr.Ptr(ksuid.New().String()), + SamplingRatio: ptr.Ptr(1.0), + Mode: ptr.Ptr("unencrypted"), Attributes: map[string]string{ "env": "smoke", }, - SamplingRatio: ptr.Ptr(1.0), } } } diff --git a/plugins/loop_registry.go b/plugins/loop_registry.go index 17ad7cba5a..7a5274803d 100644 --- a/plugins/loop_registry.go +++ b/plugins/loop_registry.go @@ -55,8 +55,9 @@ func (m *LoopRegistry) Register(id string) (*RegisteredLoop, error) { if m.cfgTracing != nil { envCfg.TracingEnabled = m.cfgTracing.Enabled() envCfg.TracingCollectorTarget = m.cfgTracing.CollectorTarget() - envCfg.TracingAttributes = m.cfgTracing.Attributes() envCfg.TracingSamplingRatio = m.cfgTracing.SamplingRatio() + envCfg.TracingTLSCertPath = m.cfgTracing.TLSCertPath() + envCfg.TracingAttributes = m.cfgTracing.Attributes() } m.registry[id] = &RegisteredLoop{Name: id, EnvCfg: envCfg} diff --git a/plugins/loop_registry_test.go b/plugins/loop_registry_test.go index b5da9154b6..b307469e09 100644 --- a/plugins/loop_registry_test.go +++ b/plugins/loop_registry_test.go @@ -29,13 +29,15 @@ func TestPluginPortManager(t *testing.T) { // Mock tracing config type MockCfgTracing struct{} -func (m *MockCfgTracing) Enabled() bool { return true } -func (m *MockCfgTracing) CollectorTarget() string { return "http://localhost:9000" } func (m *MockCfgTracing) Attributes() map[string]string { return map[string]string{"attribute": "value"} } -func (m *MockCfgTracing) SamplingRatio() float64 { return 0.1 } -func (m *MockCfgTracing) NodeID() string { return "" } +func (m *MockCfgTracing) Enabled() bool { return true } +func (m *MockCfgTracing) NodeID() string { return "" } +func (m *MockCfgTracing) CollectorTarget() string { return "http://localhost:9000" } +func (m *MockCfgTracing) SamplingRatio() float64 { return 0.1 } +func (m *MockCfgTracing) TLSCertPath() string { return "/path/to/cert.pem" } +func (m *MockCfgTracing) Mode() string { return "tls" } func TestLoopRegistry_Register(t *testing.T) { mockCfgTracing := &MockCfgTracing{} @@ -56,4 +58,5 @@ func TestLoopRegistry_Register(t *testing.T) { require.Equal(t, "http://localhost:9000", registeredLoop.EnvCfg.TracingCollectorTarget) require.Equal(t, map[string]string{"attribute": "value"}, registeredLoop.EnvCfg.TracingAttributes) require.Equal(t, 0.1, registeredLoop.EnvCfg.TracingSamplingRatio) + require.Equal(t, "/path/to/cert.pem", registeredLoop.EnvCfg.TracingTLSCertPath) } diff --git a/testdata/scripts/node/db/help.txtar b/testdata/scripts/node/db/help.txtar index ccdf343178..4f2fe3e076 100644 --- a/testdata/scripts/node/db/help.txtar +++ b/testdata/scripts/node/db/help.txtar @@ -20,4 +20,4 @@ COMMANDS: OPTIONS: --help, -h show help - + \ No newline at end of file diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 01e96ac944..267a760f08 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -244,6 +244,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' Invalid configuration: invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 1f6901e9ff..e6281e8d22 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -288,6 +288,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' [[EVM]] ChainID = '1' diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 4c1a1c75fc..65d832aa82 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -288,6 +288,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' [[EVM]] ChainID = '1' diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 536b7d8ac0..6b9e3d56ce 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -288,6 +288,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' [[EVM]] ChainID = '1' diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 89f59574fc..aa2036413c 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -278,6 +278,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' [[EVM]] ChainID = '1' diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 2d32b39a64..4ceb9d5df3 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -285,6 +285,8 @@ Enabled = false CollectorTarget = '' NodeID = '' SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' [[EVM]] ChainID = '1' diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index e478203e00..e4ff2aa35e 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -15,6 +15,12 @@ ListenPort = 0 NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' +[Tracing] +Enabled = true +CollectorTarget = 'otel-collector:4317' +TLSCertPath = 'something' +Mode = 'unencrypted' + -- secrets.toml -- [Database] URL = 'postgresql://user:pass1234567890abcd@localhost:5432/dbname?sslmode=disable' @@ -46,6 +52,12 @@ ListenPort = 0 NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' +[Tracing] +Enabled = true +CollectorTarget = 'otel-collector:4317' +Mode = 'unencrypted' +TLSCertPath = 'something' + # Effective Configuration, with defaults applied: InsecureFastScrypt = false RootDir = '~/.chainlink' @@ -277,13 +289,15 @@ InfiniteDepthQueries = false DisableRateLimiting = false [Tracing] -Enabled = false -CollectorTarget = '' +Enabled = true +CollectorTarget = 'otel-collector:4317' NodeID = '' SamplingRatio = 0.0 +Mode = 'unencrypted' +TLSCertPath = 'something' # Configuration warning: -2 errors: +3 errors: - P2P.V1: is deprecated and will be removed in a future version - P2P.V1: 10 errors: - AnnounceIP: is deprecated and will be removed in a future version @@ -296,4 +310,5 @@ SamplingRatio = 0.0 - ListenPort: is deprecated and will be removed in a future version - NewStreamTimeout: is deprecated and will be removed in a future version - PeerstoreWriteInterval: is deprecated and will be removed in a future version + - Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' Valid configuration. From e67a76c69689f5fa03477ba8cce39e0b2662062b Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Wed, 22 Nov 2023 19:12:54 +0100 Subject: [PATCH 193/327] Bump CTF to fix Killgrave issue (#11365) * Bump CTF to fix Killgrave issue * disable enforcing ctf version * disable enforcing ctf version 2 * Use CTF v1.19.5 * Enable enforcing CTF version * Remove old assets --- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index ba90493d29..2338c0caa5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 - github.com/smartcontractkit/chainlink-testing-framework v1.19.4 + github.com/smartcontractkit/chainlink-testing-framework v1.19.5 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 849df2afca..21be8c1f48 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2380,8 +2380,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= -github.com/smartcontractkit/chainlink-testing-framework v1.19.4 h1:a5zG5k3MNbDBWiBdxF2cBLaMyB+WD0ROWPiZ0DVJQMc= -github.com/smartcontractkit/chainlink-testing-framework v1.19.4/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= +github.com/smartcontractkit/chainlink-testing-framework v1.19.5 h1:Iq1L7wCA8IkBBtP3p6W2ttu8v9cJp95spusnozW1UrA= +github.com/smartcontractkit/chainlink-testing-framework v1.19.5/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= From 59485ffebdc8c57a0e3629fed244eb326cdb6295 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:55:12 +0400 Subject: [PATCH 194/327] [AUTO-7448] add standard actions for v2.X tests (#11363) * add standard actions for v2.X tests * remove duplicated lines * fix AddAutomationJobs --- .../actions/automationv2/actions.go | 699 ++++++++++++++++++ .../contracts/contract_deployer.go | 25 + 2 files changed, 724 insertions(+) create mode 100644 integration-tests/actions/automationv2/actions.go diff --git a/integration-tests/actions/automationv2/actions.go b/integration-tests/actions/automationv2/actions.go new file mode 100644 index 0000000000..f97c17bb94 --- /dev/null +++ b/integration-tests/actions/automationv2/actions.go @@ -0,0 +1,699 @@ +package automationv2 + +import ( + "crypto/ed25519" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "math/big" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/lib/pq" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" + "gopkg.in/guregu/null.v4" + + ocr2keepers20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" + ocr2keepers30config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registrar_wrapper2_0" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type NodeDetails struct { + P2PId string + TransmitterAddresses []string + OCR2ConfigPublicKey string + OCR2OffchainPublicKey string + OCR2OnChainPublicKey string + OCR2Id string +} + +type AutomationTest struct { + ChainClient blockchain.EVMClient + Deployer contracts.ContractDeployer + + LinkToken contracts.LinkToken + Transcoder contracts.UpkeepTranscoder + EthLinkFeed contracts.MockETHLINKFeed + GasFeed contracts.MockGasFeed + Registry contracts.KeeperRegistry + Registrar contracts.KeeperRegistrar + + RegistrySettings contracts.KeeperRegistrySettings + RegistrarSettings contracts.KeeperRegistrarSettings + PluginConfig ocr2keepers30config.OffchainConfig + PublicConfig ocr3.PublicConfig + UpkeepPrivilegeManager common.Address + UpkeepIDs []*big.Int + + IsOnk8s bool + + ChainlinkNodesk8s []*client.ChainlinkK8sClient + ChainlinkNodes []*client.ChainlinkClient + + NodeDetails []NodeDetails + DefaultP2Pv2Bootstrapper string + MercuryCredentialName string + TransmitterKeyIndex int +} + +type UpkeepConfig struct { + UpkeepName string + EncryptedEmail []byte + UpkeepContract common.Address + GasLimit uint32 + AdminAddress common.Address + TriggerType uint8 + CheckData []byte + TriggerConfig []byte + OffchainConfig []byte + FundingAmount *big.Int +} + +func NewAutomationTestK8s( + chainClient blockchain.EVMClient, + deployer contracts.ContractDeployer, + chainlinkNodes []*client.ChainlinkK8sClient, +) *AutomationTest { + return &AutomationTest{ + ChainClient: chainClient, + Deployer: deployer, + ChainlinkNodesk8s: chainlinkNodes, + IsOnk8s: true, + TransmitterKeyIndex: 0, + UpkeepPrivilegeManager: common.HexToAddress(chainClient.GetDefaultWallet().Address()), + } +} + +func NewAutomationTestDocker( + chainClient blockchain.EVMClient, + deployer contracts.ContractDeployer, + chainlinkNodes []*client.ChainlinkClient, +) *AutomationTest { + return &AutomationTest{ + ChainClient: chainClient, + Deployer: deployer, + ChainlinkNodes: chainlinkNodes, + IsOnk8s: false, + TransmitterKeyIndex: 0, + UpkeepPrivilegeManager: common.HexToAddress(chainClient.GetDefaultWallet().Address()), + } +} + +func (a *AutomationTest) SetIsOnk8s(flag bool) { + a.IsOnk8s = flag +} + +func (a *AutomationTest) SetMercuryCredentialName(name string) { + a.MercuryCredentialName = name +} + +func (a *AutomationTest) SetTransmitterKeyIndex(index int) { + a.TransmitterKeyIndex = index +} + +func (a *AutomationTest) SetUpkeepPrivilegeManager(address string) { + a.UpkeepPrivilegeManager = common.HexToAddress(address) +} + +func (a *AutomationTest) DeployLINK() error { + linkToken, err := a.Deployer.DeployLinkTokenContract() + if err != nil { + return err + } + a.LinkToken = linkToken + err = a.ChainClient.WaitForEvents() + if err != nil { + return errors.Join(err, fmt.Errorf("failed waiting for link token contract to deploy")) + } + return nil +} + +func (a *AutomationTest) LoadLINK(address string) error { + linkToken, err := a.Deployer.LoadLinkToken(common.HexToAddress(address)) + if err != nil { + return err + } + a.LinkToken = linkToken + return nil +} + +func (a *AutomationTest) DeployTranscoder() error { + transcoder, err := a.Deployer.DeployUpkeepTranscoder() + if err != nil { + return err + } + a.Transcoder = transcoder + err = a.ChainClient.WaitForEvents() + if err != nil { + return errors.Join(err, fmt.Errorf("failed waiting for transcoder contract to deploy")) + } + return nil +} + +func (a *AutomationTest) LoadTranscoder(address string) error { + transcoder, err := a.Deployer.LoadUpkeepTranscoder(common.HexToAddress(address)) + if err != nil { + return err + } + a.Transcoder = transcoder + return nil +} + +func (a *AutomationTest) DeployEthLinkFeed() error { + ethLinkFeed, err := a.Deployer.DeployMockETHLINKFeed(a.RegistrySettings.FallbackLinkPrice) + if err != nil { + return err + } + a.EthLinkFeed = ethLinkFeed + err = a.ChainClient.WaitForEvents() + if err != nil { + return errors.Join(err, fmt.Errorf("failed waiting for Mock ETH LINK feed to deploy")) + } + return nil +} + +func (a *AutomationTest) LoadEthLinkFeed(address string) error { + ethLinkFeed, err := a.Deployer.LoadETHLINKFeed(common.HexToAddress(address)) + if err != nil { + return err + } + a.EthLinkFeed = ethLinkFeed + return nil +} + +func (a *AutomationTest) DeployGasFeed() error { + gasFeed, err := a.Deployer.DeployMockGasFeed(a.RegistrySettings.FallbackGasPrice) + if err != nil { + return err + } + a.GasFeed = gasFeed + err = a.ChainClient.WaitForEvents() + if err != nil { + return errors.Join(err, fmt.Errorf("failed waiting for mock gas feed to deploy")) + } + return nil +} + +func (a *AutomationTest) LoadEthGasFeed(address string) error { + gasFeed, err := a.Deployer.LoadGasFeed(common.HexToAddress(address)) + if err != nil { + return err + } + a.GasFeed = gasFeed + return nil +} + +func (a *AutomationTest) DeployRegistry() error { + registryOpts := &contracts.KeeperRegistryOpts{ + RegistryVersion: a.RegistrySettings.RegistryVersion, + LinkAddr: a.LinkToken.Address(), + ETHFeedAddr: a.EthLinkFeed.Address(), + GasFeedAddr: a.GasFeed.Address(), + TranscoderAddr: a.Transcoder.Address(), + RegistrarAddr: utils.ZeroAddress.Hex(), + Settings: a.RegistrySettings, + } + registry, err := a.Deployer.DeployKeeperRegistry(registryOpts) + if err != nil { + return err + } + a.Registry = registry + err = a.ChainClient.WaitForEvents() + if err != nil { + return errors.Join(err, fmt.Errorf("failed waiting for registry contract to deploy")) + } + return nil +} + +func (a *AutomationTest) LoadRegistry(address string) error { + registry, err := a.Deployer.LoadKeeperRegistry(common.HexToAddress(address), a.RegistrySettings.RegistryVersion) + if err != nil { + return err + } + a.Registry = registry + return nil +} + +func (a *AutomationTest) DeployRegistrar() error { + if a.Registry == nil { + return fmt.Errorf("registry must be deployed or loaded before registrar") + } + a.RegistrarSettings.RegistryAddr = a.Registry.Address() + registrar, err := a.Deployer.DeployKeeperRegistrar(a.RegistrySettings.RegistryVersion, a.LinkToken.Address(), a.RegistrarSettings) + if err != nil { + return err + } + a.Registrar = registrar + err = a.ChainClient.WaitForEvents() + if err != nil { + return errors.Join(err, fmt.Errorf("failed waiting for registrar contract to deploy")) + } + return nil +} + +func (a *AutomationTest) LoadRegistrar(address string) error { + if a.Registry == nil { + return fmt.Errorf("registry must be deployed or loaded before registrar") + } + a.RegistrarSettings.RegistryAddr = a.Registry.Address() + registrar, err := a.Deployer.LoadKeeperRegistrar(common.HexToAddress(address), a.RegistrySettings.RegistryVersion) + if err != nil { + return err + } + a.Registrar = registrar + return nil +} + +func (a *AutomationTest) CollectNodeDetails() error { + var ( + nodes []*client.ChainlinkClient + ) + if a.IsOnk8s { + for _, node := range a.ChainlinkNodesk8s[:] { + nodes = append(nodes, node.ChainlinkClient) + } + a.ChainlinkNodes = nodes + } else { + nodes = a.ChainlinkNodes[:] + } + + nodeDetails := make([]NodeDetails, 0) + + for i, node := range nodes { + nodeDetail := NodeDetails{} + P2PIds, err := node.MustReadP2PKeys() + if err != nil { + return errors.Join(err, fmt.Errorf("failed to read P2P keys from node %d", i)) + } + nodeDetail.P2PId = P2PIds.Data[0].Attributes.PeerID + + OCR2Keys, err := node.MustReadOCR2Keys() + if err != nil { + return errors.Join(err, fmt.Errorf("failed to read OCR2 keys from node %d", i)) + } + for _, key := range OCR2Keys.Data { + if key.Attributes.ChainType == string(chaintype.EVM) { + nodeDetail.OCR2ConfigPublicKey = key.Attributes.ConfigPublicKey + nodeDetail.OCR2OffchainPublicKey = key.Attributes.OffChainPublicKey + nodeDetail.OCR2OnChainPublicKey = key.Attributes.OnChainPublicKey + nodeDetail.OCR2Id = key.ID + break + } + } + + TransmitterKeys, err := node.EthAddressesForChain(a.ChainClient.GetChainID().String()) + nodeDetail.TransmitterAddresses = make([]string, 0) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to read Transmitter keys from node %d", i)) + } + nodeDetail.TransmitterAddresses = append(nodeDetail.TransmitterAddresses, TransmitterKeys...) + nodeDetails = append(nodeDetails, nodeDetail) + } + a.NodeDetails = nodeDetails + + if a.IsOnk8s { + a.DefaultP2Pv2Bootstrapper = fmt.Sprintf("%s@%s-node-1:%d", a.NodeDetails[0].P2PId, a.ChainlinkNodesk8s[0].Name(), 6690) + } else { + a.DefaultP2Pv2Bootstrapper = fmt.Sprintf("%s@%s:%d", a.NodeDetails[0].P2PId, a.ChainlinkNodes[0].InternalIP(), 6690) + } + return nil +} + +func (a *AutomationTest) AddBootstrapJob() error { + bootstrapSpec := &client.OCR2TaskJobSpec{ + Name: "ocr2 bootstrap node " + a.Registry.Address(), + JobType: "bootstrap", + OCR2OracleSpec: job.OCR2OracleSpec{ + ContractID: a.Registry.Address(), + Relay: "evm", + RelayConfig: map[string]interface{}{ + "chainID": int(a.ChainClient.GetChainID().Int64()), + }, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second * 15), + }, + } + _, err := a.ChainlinkNodes[0].MustCreateJob(bootstrapSpec) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to create bootstrap job on bootstrap node")) + } + return nil +} + +func (a *AutomationTest) AddAutomationJobs() error { + var contractVersion string + if a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_1 { + contractVersion = "v2.1" + } else if a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_0 { + contractVersion = "v2.0" + } else { + return fmt.Errorf("v2.0 and v2.1 are the only supported versions") + } + for i := 1; i < len(a.ChainlinkNodes); i++ { + autoOCR2JobSpec := client.OCR2TaskJobSpec{ + Name: "automation-" + contractVersion + "-" + a.Registry.Address(), + JobType: "offchainreporting2", + OCR2OracleSpec: job.OCR2OracleSpec{ + PluginType: "ocr2automation", + ContractID: a.Registry.Address(), + Relay: "evm", + RelayConfig: map[string]interface{}{ + "chainID": int(a.ChainClient.GetChainID().Int64()), + }, + PluginConfig: map[string]interface{}{ + "mercuryCredentialName": "\"" + a.MercuryCredentialName + "\"", + "contractVersion": "\"" + contractVersion + "\"", + }, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second * 15), + TransmitterID: null.StringFrom(a.NodeDetails[i].TransmitterAddresses[a.TransmitterKeyIndex]), + P2PV2Bootstrappers: pq.StringArray{a.DefaultP2Pv2Bootstrapper}, + OCRKeyBundleID: null.StringFrom(a.NodeDetails[i].OCR2Id), + }, + } + _, err := a.ChainlinkNodes[i].MustCreateJob(&autoOCR2JobSpec) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to create OCR2 job on node %d", i+1)) + } + } + return nil +} + +func (a *AutomationTest) SetConfigOnRegistry() error { + donNodes := a.NodeDetails[1:] + S := make([]int, len(donNodes)) + oracleIdentities := make([]confighelper.OracleIdentityExtra, len(donNodes)) + var offC []byte + var signerOnchainPublicKeys []types.OnchainPublicKey + var transmitterAccounts []types.Account + var f uint8 + var offchainConfigVersion uint64 + var offchainConfig []byte + sharedSecretEncryptionPublicKeys := make([]types.ConfigEncryptionPublicKey, len(donNodes)) + eg := &errgroup.Group{} + for i, donNode := range donNodes { + index, chainlinkNode := i, donNode + eg.Go(func() error { + offchainPkBytes, err := hex.DecodeString(strings.TrimPrefix(chainlinkNode.OCR2OffchainPublicKey, "ocr2off_evm_")) + if err != nil { + return err + } + + offchainPkBytesFixed := [ed25519.PublicKeySize]byte{} + n := copy(offchainPkBytesFixed[:], offchainPkBytes) + if n != ed25519.PublicKeySize { + return fmt.Errorf("wrong number of elements copied") + } + + configPkBytes, err := hex.DecodeString(strings.TrimPrefix(chainlinkNode.OCR2ConfigPublicKey, "ocr2cfg_evm_")) + if err != nil { + return err + } + + configPkBytesFixed := [ed25519.PublicKeySize]byte{} + n = copy(configPkBytesFixed[:], configPkBytes) + if n != ed25519.PublicKeySize { + return fmt.Errorf("wrong number of elements copied") + } + + onchainPkBytes, err := hex.DecodeString(strings.TrimPrefix(chainlinkNode.OCR2OnChainPublicKey, "ocr2on_evm_")) + if err != nil { + return err + } + + sharedSecretEncryptionPublicKeys[index] = configPkBytesFixed + oracleIdentities[index] = confighelper.OracleIdentityExtra{ + OracleIdentity: confighelper.OracleIdentity{ + OnchainPublicKey: onchainPkBytes, + OffchainPublicKey: offchainPkBytesFixed, + PeerID: chainlinkNode.P2PId, + TransmitAccount: types.Account(chainlinkNode.TransmitterAddresses[a.TransmitterKeyIndex]), + }, + ConfigEncryptionPublicKey: configPkBytesFixed, + } + S[index] = 1 + return nil + }) + } + err := eg.Wait() + if err != nil { + return errors.Join(err, fmt.Errorf("failed to build oracle identities")) + } + + switch a.RegistrySettings.RegistryVersion { + case ethereum.RegistryVersion_2_0: + offC, err = json.Marshal(ocr2keepers20config.OffchainConfig{ + TargetProbability: a.PluginConfig.TargetProbability, + TargetInRounds: a.PluginConfig.TargetInRounds, + PerformLockoutWindow: a.PluginConfig.PerformLockoutWindow, + GasLimitPerReport: a.PluginConfig.GasLimitPerReport, + GasOverheadPerUpkeep: a.PluginConfig.GasOverheadPerUpkeep, + MinConfirmations: a.PluginConfig.MinConfirmations, + MaxUpkeepBatchSize: a.PluginConfig.MaxUpkeepBatchSize, + }) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to marshal plugin config")) + } + + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err = ocr2.ContractSetConfigArgsForTests( + a.PublicConfig.DeltaProgress, a.PublicConfig.DeltaResend, + a.PublicConfig.DeltaRound, a.PublicConfig.DeltaGrace, + a.PublicConfig.DeltaStage, uint8(a.PublicConfig.RMax), + S, oracleIdentities, offC, + a.PublicConfig.MaxDurationQuery, a.PublicConfig.MaxDurationObservation, + 1200*time.Millisecond, + a.PublicConfig.MaxDurationShouldAcceptAttestedReport, + a.PublicConfig.MaxDurationShouldTransmitAcceptedReport, + a.PublicConfig.F, a.PublicConfig.OnchainConfig, + ) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to build config args")) + } + + case ethereum.RegistryVersion_2_1: + offC, err = json.Marshal(ocr2keepers30config.OffchainConfig{ + TargetProbability: a.PluginConfig.TargetProbability, + TargetInRounds: a.PluginConfig.TargetInRounds, + PerformLockoutWindow: a.PluginConfig.PerformLockoutWindow, + GasLimitPerReport: a.PluginConfig.GasLimitPerReport, + GasOverheadPerUpkeep: a.PluginConfig.GasOverheadPerUpkeep, + MinConfirmations: a.PluginConfig.MinConfirmations, + MaxUpkeepBatchSize: a.PluginConfig.MaxUpkeepBatchSize, + }) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to marshal plugin config")) + } + + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err = ocr3.ContractSetConfigArgsForTests( + a.PublicConfig.DeltaProgress, a.PublicConfig.DeltaResend, a.PublicConfig.DeltaInitial, + a.PublicConfig.DeltaRound, a.PublicConfig.DeltaGrace, a.PublicConfig.DeltaCertifiedCommitRequest, + a.PublicConfig.DeltaStage, a.PublicConfig.RMax, + S, oracleIdentities, offC, + a.PublicConfig.MaxDurationQuery, a.PublicConfig.MaxDurationObservation, + a.PublicConfig.MaxDurationShouldAcceptAttestedReport, + a.PublicConfig.MaxDurationShouldTransmitAcceptedReport, + a.PublicConfig.F, a.PublicConfig.OnchainConfig, + ) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to build config args")) + } + default: + return fmt.Errorf("v2.0 and v2.1 are the only supported versions") + } + + var signers []common.Address + for _, signer := range signerOnchainPublicKeys { + if len(signer) != 20 { + return fmt.Errorf("OnChainPublicKey '%v' has wrong length for address", signer) + } + signers = append(signers, common.BytesToAddress(signer)) + } + + var transmitters []common.Address + for _, transmitter := range transmitterAccounts { + if !common.IsHexAddress(string(transmitter)) { + return fmt.Errorf("TransmitAccount '%s' is not a valid Ethereum address", string(transmitter)) + } + transmitters = append(transmitters, common.HexToAddress(string(transmitter))) + } + + onchainConfig, err := a.RegistrySettings.EncodeOnChainConfig(a.Registrar.Address(), a.UpkeepPrivilegeManager) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to encode onchain config")) + } + + ocrConfig := contracts.OCRv2Config{ + Signers: signers, + Transmitters: transmitters, + F: f, + OnchainConfig: onchainConfig, + OffchainConfigVersion: offchainConfigVersion, + OffchainConfig: offchainConfig, + } + + err = a.Registry.SetConfig(a.RegistrySettings, ocrConfig) + if err != nil { + return errors.Join(err, fmt.Errorf("failed to set config on registry")) + } + return nil +} + +func (a *AutomationTest) RegisterUpkeeps(upkeepConfigs []UpkeepConfig) ([]common.Hash, error) { + var registrarABI *abi.ABI + var err error + var registrationRequest []byte + registrationTxHashes := make([]common.Hash, 0) + + for _, upkeepConfig := range upkeepConfigs { + switch a.RegistrySettings.RegistryVersion { + case ethereum.RegistryVersion_2_0: + registrarABI, err = keeper_registrar_wrapper2_0.KeeperRegistrarMetaData.GetAbi() + if err != nil { + return nil, errors.Join(err, fmt.Errorf("failed to get registrar abi")) + } + registrationRequest, err = registrarABI.Pack( + "register", upkeepConfig.UpkeepName, upkeepConfig.EncryptedEmail, + upkeepConfig.UpkeepContract, upkeepConfig.GasLimit, upkeepConfig.AdminAddress, + upkeepConfig.CheckData, + upkeepConfig.OffchainConfig, upkeepConfig.FundingAmount, + common.HexToAddress(a.ChainClient.GetDefaultWallet().Address())) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("failed to pack registrar request")) + } + case ethereum.RegistryVersion_2_1: + registrarABI, err = automation_registrar_wrapper2_1.AutomationRegistrarMetaData.GetAbi() + if err != nil { + return nil, errors.Join(err, fmt.Errorf("failed to get registrar abi")) + } + registrationRequest, err = registrarABI.Pack( + "register", upkeepConfig.UpkeepName, upkeepConfig.EncryptedEmail, + upkeepConfig.UpkeepContract, upkeepConfig.GasLimit, upkeepConfig.AdminAddress, + upkeepConfig.TriggerType, upkeepConfig.CheckData, upkeepConfig.TriggerConfig, + upkeepConfig.OffchainConfig, upkeepConfig.FundingAmount, + common.HexToAddress(a.ChainClient.GetDefaultWallet().Address())) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("failed to pack registrar request")) + } + default: + return nil, fmt.Errorf("v2.0 and v2.1 are the only supported versions") + } + tx, err := a.LinkToken.TransferAndCall(a.Registrar.Address(), upkeepConfig.FundingAmount, registrationRequest) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("failed to register upkeep")) + } + registrationTxHashes = append(registrationTxHashes, tx.Hash()) + } + return registrationTxHashes, nil +} + +func (a *AutomationTest) ConfirmUpkeepsRegistered(registrationTxHashes []common.Hash) ([]*big.Int, error) { + upkeepIds := make([]*big.Int, 0) + for _, txHash := range registrationTxHashes { + receipt, err := a.ChainClient.GetTxReceipt(txHash) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("failed to confirm upkeep registration")) + } + var upkeepId *big.Int + for _, rawLog := range receipt.Logs { + parsedUpkeepId, err := a.Registry.ParseUpkeepIdFromRegisteredLog(rawLog) + if err == nil { + upkeepId = parsedUpkeepId + break + } + } + if upkeepId == nil { + return nil, fmt.Errorf("failed to parse upkeep id from registration receipt") + } + upkeepIds = append(upkeepIds, upkeepId) + } + a.UpkeepIDs = upkeepIds + return upkeepIds, nil +} + +func (a *AutomationTest) AddJobsAndSetConfig(t *testing.T) { + l := logging.GetTestLogger(t) + err := a.AddBootstrapJob() + require.NoError(t, err, "Error adding bootstrap job") + err = a.AddAutomationJobs() + require.NoError(t, err, "Error adding automation jobs") + + l.Debug(). + Interface("Plugin Config", a.PluginConfig). + Interface("Public Config", a.PublicConfig). + Interface("Registry Settings", a.RegistrySettings). + Interface("Registrar Settings", a.RegistrarSettings). + Msg("Configuring registry") + err = a.SetConfigOnRegistry() + require.NoError(t, err, "Error setting config on registry") + l.Info().Str("Registry Address", a.Registry.Address()).Msg("Successfully setConfig on registry") +} + +func (a *AutomationTest) SetupAutomationDeployment(t *testing.T) { + l := logging.GetTestLogger(t) + err := a.CollectNodeDetails() + require.NoError(t, err, "Error collecting node details") + l.Info().Msg("Collected Node Details") + l.Debug().Interface("Node Details", a.NodeDetails).Msg("Node Details") + + err = a.DeployLINK() + require.NoError(t, err, "Error deploying link token contract") + + err = a.DeployEthLinkFeed() + require.NoError(t, err, "Error deploying eth link feed contract") + err = a.DeployGasFeed() + require.NoError(t, err, "Error deploying gas feed contract") + + err = a.DeployTranscoder() + require.NoError(t, err, "Error deploying transcoder contract") + + err = a.DeployRegistry() + require.NoError(t, err, "Error deploying registry contract") + err = a.DeployRegistrar() + require.NoError(t, err, "Error deploying registrar contract") + + a.AddJobsAndSetConfig(t) +} + +func (a *AutomationTest) LoadAutomationDeployment(t *testing.T, linkTokenAddress, + ethLinkFeedAddress, gasFeedAddress, transcoderAddress, registryAddress, registrarAddress string) { + l := logging.GetTestLogger(t) + err := a.CollectNodeDetails() + require.NoError(t, err, "Error collecting node details") + l.Info().Msg("Collected Node Details") + l.Debug().Interface("Node Details", a.NodeDetails).Msg("Node Details") + + err = a.LoadLINK(linkTokenAddress) + require.NoError(t, err, "Error loading link token contract") + + err = a.LoadEthLinkFeed(ethLinkFeedAddress) + require.NoError(t, err, "Error loading eth link feed contract") + err = a.LoadEthGasFeed(gasFeedAddress) + require.NoError(t, err, "Error loading gas feed contract") + err = a.LoadTranscoder(transcoderAddress) + require.NoError(t, err, "Error loading transcoder contract") + err = a.LoadRegistry(registryAddress) + require.NoError(t, err, "Error loading registry contract") + err = a.LoadRegistrar(registrarAddress) + require.NoError(t, err, "Error loading registrar contract") + + a.AddJobsAndSetConfig(t) + +} diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 000fe7b2b8..528f07ec68 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -89,6 +89,7 @@ type ContractDeployer interface { DeployKeeperRegistrar(registryVersion eth_contracts.KeeperRegistryVersion, linkAddr string, registrarSettings KeeperRegistrarSettings) (KeeperRegistrar, error) LoadKeeperRegistrar(address common.Address, registryVersion eth_contracts.KeeperRegistryVersion) (KeeperRegistrar, error) DeployUpkeepTranscoder() (UpkeepTranscoder, error) + LoadUpkeepTranscoder(address common.Address) (UpkeepTranscoder, error) DeployKeeperRegistry(opts *KeeperRegistryOpts) (KeeperRegistry, error) LoadKeeperRegistry(address common.Address, registryVersion eth_contracts.KeeperRegistryVersion) (KeeperRegistry, error) DeployKeeperConsumer(updateInterval *big.Int) (KeeperConsumer, error) @@ -763,6 +764,25 @@ func (e *EthereumContractDeployer) DeployUpkeepTranscoder() (UpkeepTranscoder, e }, err } +func (e *EthereumContractDeployer) LoadUpkeepTranscoder(address common.Address) (UpkeepTranscoder, error) { + instance, err := e.client.LoadContract("UpkeepTranscoder", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return upkeep_transcoder.NewUpkeepTranscoder(address, backend) + }) + + if err != nil { + return nil, err + } + + return &EthereumUpkeepTranscoder{ + client: e.client, + transcoder: instance.(*upkeep_transcoder.UpkeepTranscoder), + address: &address, + }, err +} + func (e *EthereumContractDeployer) DeployKeeperRegistrar(registryVersion eth_contracts.KeeperRegistryVersion, linkAddr string, registrarSettings KeeperRegistrarSettings) (KeeperRegistrar, error) { @@ -1192,6 +1212,7 @@ func (e *EthereumContractDeployer) LoadKeeperRegistry(address common.Address, re address: &address, client: e.client, registry1_1: instance.(*keeper_registry_wrapper1_1.KeeperRegistry), + version: registryVersion, }, err case eth_contracts.RegistryVersion_1_2: instance, err := e.client.LoadContract("KeeperRegistry", address, func( @@ -1207,6 +1228,7 @@ func (e *EthereumContractDeployer) LoadKeeperRegistry(address common.Address, re address: &address, client: e.client, registry1_2: instance.(*keeper_registry_wrapper1_2.KeeperRegistry), + version: registryVersion, }, err case eth_contracts.RegistryVersion_1_3: instance, err := e.client.LoadContract("KeeperRegistry", address, func( @@ -1222,6 +1244,7 @@ func (e *EthereumContractDeployer) LoadKeeperRegistry(address common.Address, re address: &address, client: e.client, registry1_3: instance.(*keeper_registry_wrapper1_3.KeeperRegistry), + version: registryVersion, }, err case eth_contracts.RegistryVersion_2_0: instance, err := e.client.LoadContract("KeeperRegistry", address, func( @@ -1237,6 +1260,7 @@ func (e *EthereumContractDeployer) LoadKeeperRegistry(address common.Address, re address: &address, client: e.client, registry2_0: instance.(*keeper_registry_wrapper2_0.KeeperRegistry), + version: registryVersion, }, err case eth_contracts.RegistryVersion_2_1: instance, err := e.client.LoadContract("KeeperRegistry", address, func( @@ -1252,6 +1276,7 @@ func (e *EthereumContractDeployer) LoadKeeperRegistry(address common.Address, re address: &address, client: e.client, registry2_1: instance.(*iregistry21.IKeeperRegistryMaster), + version: registryVersion, }, err default: return nil, fmt.Errorf("keeper registry version %d is not supported", registryVersion) From d5b9c44fe6d61eb39ebfb29f24afbfd2915ad3a0 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Thu, 23 Nov 2023 19:46:04 +0200 Subject: [PATCH 195/327] VRF-745: refactor VRF v2 tests to match VRF v2 Plus setup (#11257) * VRF-745: refactor VRF v2 tests to match VRF v2 Plus setup * VRF-745: removing decoding tx output * VRF-745: fixing test * VRF-745: fixing Owner Canceling Sub test * VRF-745: adding VRF V2 GH Actions workflow for WASP load test * VRF-745: adding ARBITRUM_SEPOLIA to VRF Load test GH Action workflows * VRF-745: fund CL sending keys if needed in WASP test * VRF-699: downgrading wasp version * polishing up and refactoring minor issues * reverting package name rename * fixing import * fixing lint issues * fixing lint issues * removing unnecesary parameter * fixing lint --- .../on-demand-vrfv2-performance-test.yml | 136 ++++ .../on-demand-vrfv2plus-performance-test.yml | 7 +- .../vrfv2_actions/vrfv2_config/config.go | 54 ++ .../vrfv2_constants/constants.go | 34 - .../actions/vrfv2_actions/vrfv2_models.go | 20 +- .../actions/vrfv2_actions/vrfv2_steps.go | 620 ++++++++++++++---- .../vrfv2plus/vrfv2plus_config/config.go | 1 + .../actions/vrfv2plus/vrfv2plus_steps.go | 323 +++++---- .../contracts/contract_loader.go | 40 ++ .../contracts/contract_vrf_models.go | 8 +- .../contracts/ethereum_vrfv2_contracts.go | 110 +++- integration-tests/load/vrfv2/config.go | 138 +++- integration-tests/load/vrfv2/config.toml | 72 +- integration-tests/load/vrfv2/gun.go | 66 +- .../load/vrfv2/onchain_monitoring.go | 53 +- integration-tests/load/vrfv2/vrfv2_test.go | 384 +++++++++-- integration-tests/load/vrfv2/vu.go | 94 --- integration-tests/smoke/vrfv2_test.go | 156 +++-- integration-tests/smoke/vrfv2plus_test.go | 18 +- integration-tests/testreporters/vrfv2.go | 201 ++---- integration-tests/testreporters/vrfv2plus.go | 4 +- integration-tests/testsetups/vrfv2.go | 204 ------ integration-tests/types/config/node/core.go | 5 +- 23 files changed, 1738 insertions(+), 1010 deletions(-) create mode 100644 .github/workflows/on-demand-vrfv2-performance-test.yml create mode 100644 integration-tests/actions/vrfv2_actions/vrfv2_config/config.go delete mode 100644 integration-tests/actions/vrfv2_actions/vrfv2_constants/constants.go delete mode 100644 integration-tests/load/vrfv2/vu.go delete mode 100644 integration-tests/testsetups/vrfv2.go diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml new file mode 100644 index 0000000000..100fdf73e6 --- /dev/null +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -0,0 +1,136 @@ +name: On Demand VRFV2 Performance Test +on: + workflow_dispatch: + inputs: + network: + description: Network to run tests on + type: choice + options: + - "ETHEREUM_MAINNET" + - "SIMULATED" + - "SEPOLIA" + - "OPTIMISM_MAINNET" + - "OPTIMISM_GOERLI" + - "ARBITRUM_MAINNET" + - "ARBITRUM_GOERLI" + - "ARBITRUM_SEPOLIA" + - "BSC_MAINNET" + - "BSC_TESTNET" + - "POLYGON_MAINNET" + - "POLYGON_MUMBAI" + - "AVALANCHE_FUJI" + - "AVALANCHE_MAINNET" + fundingPrivateKey: + description: Private funding key (Skip for Simulated) + required: false + type: string + wsURL: + description: WS URL for the network (Skip for Simulated) + required: false + type: string + httpURL: + description: HTTP URL for the network (Skip for Simulated) + required: false + type: string + chainlinkImage: + description: Container image location for the Chainlink nodes + required: true + default: public.ecr.aws/chainlink/chainlink + chainlinkVersion: + description: Container image version for the Chainlink nodes + required: true + default: "2.6.0" + performanceTestType: + description: Performance Test Type of test to run + type: choice + options: + - "Soak" + - "Load" + - "Stress" + - "Spike" + testDuration: + description: Duration of the test (time string) + required: true + default: 5m + useExistingEnv: + description: Set `true` to use existing environment or `false` to deploy CL node and all contracts + required: false + default: false + configBase64: + description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) + required: false +jobs: + vrfv2_performance_test: + name: ${{ inputs.network }} VRFV2 Performance Test + environment: integration + runs-on: ubuntu20.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + env: + LOKI_URL: ${{ secrets.LOKI_URL }} + LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} + SELECTED_NETWORKS: ${{ inputs.network }} + TEST_TYPE: ${{ inputs.performanceTestType }} + VRFV2_TEST_DURATION: ${{ inputs.testDuration }} + VRFV2_USE_EXISTING_ENV: ${{ inputs.useExistingEnv }} + CONFIG: ${{ inputs.configBase64 }} + TEST_LOG_LEVEL: debug + REF_NAME: ${{ github.head_ref || github.ref_name }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} + SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + WASP_LOG_LEVEL: info + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ${{ inputs.network }} VRFV2 Performance Test + continue-on-error: true + - name: Setup Push Tag + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + - name: Get Inputs + run: | + EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) + EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) + EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) + + echo ::add-mask::$EVM_URLS + echo ::add-mask::$EVM_HTTP_URLS + echo ::add-mask::$EVM_KEYS + + echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV + echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV + echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV + + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + with: + test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 24h -run TestVRFV2Performance/vrfv2_performance_test ./load/vrfv2 + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ inputs.chainlinkImage }} + cl_image_tag: ${{ inputs.chainlinkVersion }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrf-test-logs + artifacts_location: ./integration-tests/load/vrfv2/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 2e765ab79b..238f40de88 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -13,10 +13,11 @@ on: - "OPTIMISM_GOERLI" - "ARBITRUM_MAINNET" - "ARBITRUM_GOERLI" + - "ARBITRUM_SEPOLIA" - "BSC_MAINNET" - "BSC_TESTNET" - "POLYGON_MAINNET" - - "MUMBAI" + - "POLYGON_MUMBAI" - "AVALANCHE_FUJI" - "AVALANCHE_MAINNET" fundingPrivateKey: @@ -120,13 +121,13 @@ jobs: - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: - test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 6h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./load/vrfv2plus + test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 24h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./load/vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ inputs.chainlinkImage }} cl_image_tag: ${{ inputs.chainlinkVersion }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: vrf-test-logs - artifacts_location: ./integration-tests/load/logs/ + artifacts_location: ./integration-tests/load/vrfv2plus/logs/ token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod should_cleanup: false diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go b/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go new file mode 100644 index 0000000000..aa2ac7f59e --- /dev/null +++ b/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go @@ -0,0 +1,54 @@ +package vrfv2_config + +import "time" + +type VRFV2Config struct { + ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with + CLNodeMaxGasPriceGWei int64 `envconfig:"MAX_GAS_PRICE_GWEI" default:"1000"` // Max gas price in GWei for the chainlink node + IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token + LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed + MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator + SubscriptionFundingAmountLink float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"5"` // Amount of LINK to fund the subscription with + NumberOfWords uint32 `envconfig:"NUMBER_OF_WORDS" default:"3"` // Number of words to request + CallbackGasLimit uint32 `envconfig:"CALLBACK_GAS_LIMIT" default:"1000000"` // Gas limit for the callback + MaxGasLimitCoordinatorConfig uint32 `envconfig:"MAX_GAS_LIMIT_COORDINATOR_CONFIG" default:"2500000"` // Max gas limit for the VRF Coordinator config + FallbackWeiPerUnitLink int64 `envconfig:"FALLBACK_WEI_PER_UNIT_LINK" default:"60000000000000000"` // Fallback wei per unit LINK for the VRF Coordinator config + StalenessSeconds uint32 `envconfig:"STALENESS_SECONDS" default:"86400"` // Staleness in seconds for the VRF Coordinator config + GasAfterPaymentCalculation uint32 `envconfig:"GAS_AFTER_PAYMENT_CALCULATION" default:"33825"` // Gas after payment calculation for the VRF Coordinator config + FulfillmentFlatFeeLinkPPMTier1 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_1" default:"500"` + FulfillmentFlatFeeLinkPPMTier2 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_2" default:"500"` + FulfillmentFlatFeeLinkPPMTier3 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_3" default:"500"` + FulfillmentFlatFeeLinkPPMTier4 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_4" default:"500"` + FulfillmentFlatFeeLinkPPMTier5 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_5" default:"500"` + ReqsForTier2 int64 `envconfig:"REQS_FOR_TIER_2" default:"0"` + ReqsForTier3 int64 `envconfig:"REQS_FOR_TIER_3" default:"0"` + ReqsForTier4 int64 `envconfig:"REQS_FOR_TIER_4" default:"0"` + ReqsForTier5 int64 `envconfig:"REQS_FOR_TIER_5" default:"0"` + + NumberOfSubToCreate int `envconfig:"NUMBER_OF_SUB_TO_CREATE" default:"1"` // Number of subscriptions to create + + RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request + RandomnessRequestCountPerRequestDeviation uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST_DEVIATION" default:"0"` // How many randomness requests to send per request + + RandomWordsFulfilledEventTimeout time.Duration `envconfig:"RANDOM_WORDS_FULFILLED_EVENT_TIMEOUT" default:"2m"` // How long to wait for the RandomWordsFulfilled event to be emitted + + //Wrapper Config + WrapperGasOverhead uint32 `envconfig:"WRAPPER_GAS_OVERHEAD" default:"50000"` + CoordinatorGasOverhead uint32 `envconfig:"COORDINATOR_GAS_OVERHEAD" default:"52000"` + WrapperPremiumPercentage uint8 `envconfig:"WRAPPER_PREMIUM_PERCENTAGE" default:"25"` + WrapperMaxNumberOfWords uint8 `envconfig:"WRAPPER_MAX_NUMBER_OF_WORDS" default:"10"` + WrapperConsumerFundingAmountNativeToken float64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_NATIVE_TOKEN" default:"1"` + WrapperConsumerFundingAmountLink int64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_LINK" default:"10"` + + //LOAD/SOAK Test Config + TestDuration time.Duration `envconfig:"TEST_DURATION" default:"3m"` // How long to run the test for + RPS int64 `envconfig:"RPS" default:"1"` // How many requests per second to send + RateLimitUnitDuration time.Duration `envconfig:"RATE_LIMIT_UNIT_DURATION" default:"1m"` + //Using existing environment and contracts + UseExistingEnv bool `envconfig:"USE_EXISTING_ENV" default:"false"` // Whether to use an existing environment or create a new one + CoordinatorAddress string `envconfig:"COORDINATOR_ADDRESS" default:""` // Coordinator address + ConsumerAddress string `envconfig:"CONSUMER_ADDRESS" default:""` // Consumer address + LinkAddress string `envconfig:"LINK_ADDRESS" default:""` // Link address + SubID uint64 `envconfig:"SUB_ID" default:""` // Subscription ID + KeyHash string `envconfig:"KEY_HASH" default:""` +} diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_constants/constants.go b/integration-tests/actions/vrfv2_actions/vrfv2_constants/constants.go deleted file mode 100644 index 2ec993e4e6..0000000000 --- a/integration-tests/actions/vrfv2_actions/vrfv2_constants/constants.go +++ /dev/null @@ -1,34 +0,0 @@ -package vrfv2_constants - -import ( - "math/big" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" -) - -var ( - LinkEthFeedResponse = big.NewInt(1e18) - MinimumConfirmations = uint16(3) - RandomnessRequestCountPerRequest = uint16(1) - //todo - get Sub id when creating subscription - need to listen for SubscriptionCreated Log - SubID = uint64(1) - VRFSubscriptionFundingAmountLink = big.NewInt(100) - ChainlinkNodeFundingAmountEth = big.NewFloat(0.1) - NumberOfWords = uint32(3) - MaxGasPriceGWei = 1000 - CallbackGasLimit = uint32(1000000) - MaxGasLimitVRFCoordinatorConfig = uint32(2.5e6) - StalenessSeconds = uint32(86400) - GasAfterPaymentCalculation = uint32(33825) - - VRFCoordinatorV2FeeConfig = vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ - FulfillmentFlatFeeLinkPPMTier1: 500, - FulfillmentFlatFeeLinkPPMTier2: 500, - FulfillmentFlatFeeLinkPPMTier3: 500, - FulfillmentFlatFeeLinkPPMTier4: 500, - FulfillmentFlatFeeLinkPPMTier5: 500, - ReqsForTier2: big.NewInt(0), - ReqsForTier3: big.NewInt(0), - ReqsForTier4: big.NewInt(0), - ReqsForTier5: big.NewInt(0)} -) diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_models.go b/integration-tests/actions/vrfv2_actions/vrfv2_models.go index 71d119e1db..0576d6f7d6 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_models.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_models.go @@ -18,7 +18,21 @@ type VRFV2JobInfo struct { } type VRFV2Contracts struct { - Coordinator contracts.VRFCoordinatorV2 - BHS contracts.BlockHashStore - LoadTestConsumer contracts.VRFv2LoadTestConsumer + Coordinator contracts.VRFCoordinatorV2 + BHS contracts.BlockHashStore + LoadTestConsumers []contracts.VRFv2LoadTestConsumer +} + +// VRFV2PlusKeyData defines a jobs into and proving key info +type VRFV2KeyData struct { + VRFKey *client.VRFKey + EncodedProvingKey VRFV2EncodedProvingKey + KeyHash [32]byte +} + +type VRFV2Data struct { + VRFV2KeyData + VRFJob *client.Job + PrimaryEthAddress string + ChainID *big.Int } diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go index a832d020b0..f565af26d9 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go @@ -4,6 +4,18 @@ import ( "context" "fmt" "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog" + + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/google/uuid" @@ -11,27 +23,37 @@ import ( chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" - vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) var ( - ErrNodePrimaryKey = "error getting node's primary ETH key" - ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" - ErrCreatingProvingKey = "error creating a keyHash from the proving key" - ErrRegisterProvingKey = "error registering proving keys" - ErrEncodingProvingKey = "error encoding proving key" - ErrCreatingVRFv2Key = "error creating VRFv2 key" - ErrDeployBlockHashStore = "error deploying blockhash store" - ErrDeployCoordinator = "error deploying VRFv2 CoordinatorV2" - ErrAdvancedConsumer = "error deploying VRFv2 Advanced Consumer" - ErrABIEncodingFunding = "error Abi encoding subscriptionID" - ErrSendingLinkToken = "error sending Link token" - ErrCreatingVRFv2Job = "error creating VRFv2 job" - ErrParseJob = "error parsing job definition" + ErrNodePrimaryKey = "error getting node's primary ETH key" + ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" + ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" + ErrRegisterProvingKey = "error registering proving keys" + ErrEncodingProvingKey = "error encoding proving key" + ErrCreatingVRFv2Key = "error creating VRFv2 key" + ErrDeployBlockHashStore = "error deploying blockhash store" + ErrDeployCoordinator = "error deploying VRF CoordinatorV2" + ErrAdvancedConsumer = "error deploying VRFv2 Advanced Consumer" + ErrABIEncodingFunding = "error Abi encoding subscriptionID" + ErrSendingLinkToken = "error sending Link token" + ErrCreatingVRFv2Job = "error creating VRFv2 job" + ErrParseJob = "error parsing job definition" + ErrDeployVRFV2Contracts = "error deploying VRFV2 contracts" + ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" + ErrCreateVRFSubscription = "error creating VRF Subscription" + ErrAddConsumerToSub = "error adding consumer to VRF Subscription" + ErrFundSubWithLinkToken = "error funding subscription with Link tokens" + ErrCreateVRFV2Jobs = "error creating VRF V2 Jobs" + ErrGetPrimaryKey = "error getting primary ETH key address" + ErrRestartCLNode = "error restarting CL node" + ErrWaitTXsComplete = "error waiting for TXs to complete" + ErrRequestRandomness = "error requesting randomness" + + ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" + ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" ) func DeployVRFV2Contracts( @@ -39,82 +61,80 @@ func DeployVRFV2Contracts( chainClient blockchain.EVMClient, linkTokenContract contracts.LinkToken, linkEthFeedContract contracts.MockETHLINKFeed, + consumerContractsAmount int, ) (*VRFV2Contracts, error) { bhs, err := contractDeployer.DeployBlockhashStore() if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } coordinator, err := contractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) } - loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinator.Address()) + err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = chainClient.WaitForEvents() + consumers, err := DeployVRFV2Consumers(contractDeployer, coordinator, consumerContractsAmount) if err != nil { return nil, err } - return &VRFV2Contracts{coordinator, bhs, loadTestConsumer}, nil + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return &VRFV2Contracts{coordinator, bhs, consumers}, nil } -func CreateVRFV2Jobs( - chainlinkNodes []*client.ChainlinkClient, - coordinator contracts.VRFCoordinatorV2, - c blockchain.EVMClient, - minIncomingConfirmations uint16, -) ([]VRFV2JobInfo, error) { - jobInfo := make([]VRFV2JobInfo, 0) - for _, chainlinkNode := range chainlinkNodes { - vrfKey, err := chainlinkNode.MustCreateVRFKey() +func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { + var consumers []contracts.VRFv2LoadTestConsumer + for i := 1; i <= consumerContractsAmount; i++ { + loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinator.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Key, err) - } - pubKeyCompressed := vrfKey.Data.ID - jobUUID := uuid.New() - os := &client.VRFV2TxPipelineSpec{ - Address: coordinator.Address(), + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) } - ost, err := os.String() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) - } - nativeTokenPrimaryKeyAddress, err := chainlinkNode.PrimaryEthAddress() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) - } - job, err := chainlinkNode.MustCreateJob(&client.VRFV2JobSpec{ - Name: fmt.Sprintf("vrf-%s", jobUUID), - CoordinatorAddress: coordinator.Address(), - FromAddresses: []string{nativeTokenPrimaryKeyAddress}, - EVMChainID: c.GetChainID().String(), - MinIncomingConfirmations: int(minIncomingConfirmations), - PublicKey: pubKeyCompressed, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - BatchFulfillmentEnabled: false, - }) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) - } - provingKey, err := VRFV2RegisterProvingKey(vrfKey, nativeTokenPrimaryKeyAddress, coordinator) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKey, err) - } - keyHash, err := coordinator.HashOfKey(context.Background(), provingKey) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) - } - ji := VRFV2JobInfo{ - Job: job, - VRFKey: vrfKey, - EncodedProvingKey: provingKey, - KeyHash: keyHash, - } - jobInfo = append(jobInfo, ji) + consumers = append(consumers, loadTestConsumer) + } + return consumers, nil +} + +func CreateVRFV2Job( + chainlinkNode *client.ChainlinkClient, + coordinatorAddress string, + nativeTokenPrimaryKeyAddress string, + pubKeyCompressed string, + chainID string, + minIncomingConfirmations uint16, +) (*client.Job, error) { + jobUUID := uuid.New() + os := &client.VRFV2TxPipelineSpec{ + Address: coordinatorAddress, + } + ost, err := os.String() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) + } + + job, err := chainlinkNode.MustCreateJob(&client.VRFV2JobSpec{ + Name: fmt.Sprintf("vrf-v2-%s", jobUUID), + CoordinatorAddress: coordinatorAddress, + FromAddresses: []string{nativeTokenPrimaryKeyAddress}, + EVMChainID: chainID, + MinIncomingConfirmations: int(minIncomingConfirmations), + PublicKey: pubKeyCompressed, + ExternalJobID: jobUUID.String(), + ObservationSource: ost, + BatchFulfillmentEnabled: false, + }) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) } - return jobInfo, nil + + return job, nil } func VRFV2RegisterProvingKey( @@ -136,98 +156,452 @@ func VRFV2RegisterProvingKey( return provingKey, nil } -func FundVRFCoordinatorV2Subscription(linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, chainClient blockchain.EVMClient, subscriptionID uint64, linkFundingAmount *big.Int) error { +func FundVRFCoordinatorV2Subscription( + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + chainClient blockchain.EVMClient, + subscriptionID uint64, + linkFundingAmountJuels *big.Int, +) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) if err != nil { return fmt.Errorf("%s, err %w", ErrABIEncodingFunding, err) } - _, err = linkToken.TransferAndCall(coordinator.Address(), big.NewInt(0).Mul(linkFundingAmount, big.NewInt(1e18)), encodedSubId) + _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) if err != nil { return fmt.Errorf("%s, err %w", ErrSendingLinkToken, err) } return chainClient.WaitForEvents() } -/* setup for load tests */ +// SetupVRFV2Environment will create specified number of subscriptions and add the same conumer/s to each of them +func SetupVRFV2Environment( + env *test_env.CLClusterTestEnv, + vrfv2Config vrfv2_config.VRFV2Config, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.MockETHLINKFeed, + registerProvingKeyAgainstAddress string, + numberOfConsumers int, + numberOfSubToCreate int, + l zerolog.Logger, +) (*VRFV2Contracts, []uint64, *VRFV2Data, error) { + l.Info().Msg("Starting VRFV2 environment setup") + l.Info().Msg("Deploying VRFV2 contracts") + vrfv2Contracts, err := DeployVRFV2Contracts( + env.ContractDeployer, + env.EVMClient, + linkToken, + mockNativeLINKFeed, + numberOfConsumers, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) + } + vrfCoordinatorV2FeeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ + FulfillmentFlatFeeLinkPPMTier1: vrfv2Config.FulfillmentFlatFeeLinkPPMTier1, + FulfillmentFlatFeeLinkPPMTier2: vrfv2Config.FulfillmentFlatFeeLinkPPMTier2, + FulfillmentFlatFeeLinkPPMTier3: vrfv2Config.FulfillmentFlatFeeLinkPPMTier3, + FulfillmentFlatFeeLinkPPMTier4: vrfv2Config.FulfillmentFlatFeeLinkPPMTier4, + FulfillmentFlatFeeLinkPPMTier5: vrfv2Config.FulfillmentFlatFeeLinkPPMTier5, + ReqsForTier2: big.NewInt(vrfv2Config.ReqsForTier2), + ReqsForTier3: big.NewInt(vrfv2Config.ReqsForTier3), + ReqsForTier4: big.NewInt(vrfv2Config.ReqsForTier4), + ReqsForTier5: big.NewInt(vrfv2Config.ReqsForTier5)} -func SetupLocalLoadTestEnv(nodesFunding *big.Float, subFundingLINK *big.Int) (*test_env.CLClusterTestEnv, *VRFV2Contracts, [32]byte, error) { - env, err := test_env.NewCLTestEnvBuilder(). - WithGeth(). - WithLogWatcher(). - WithMockAdapter(). - WithCLNodes(1). - WithFunding(nodesFunding). - WithLogWatcher(). - Build() + l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") + err = vrfv2Contracts.Coordinator.SetConfig( + vrfv2Config.MinimumConfirmations, + vrfv2Config.CallbackGasLimit, + vrfv2Config.StalenessSeconds, + vrfv2Config.GasAfterPaymentCalculation, + big.NewInt(vrfv2Config.LinkNativeFeedResponse), + vrfCoordinatorV2FeeConfig, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetVRFCoordinatorConfig, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + l.Info(). + Str("Coordinator", vrfv2Contracts.Coordinator.Address()). + Int("Number of Subs to create", numberOfSubToCreate). + Msg("Creating and funding subscriptions, adding consumers") + subIDs, err := CreateFundSubsAndAddConsumers( + env, + vrfv2Config, + linkToken, + vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, numberOfSubToCreate) if err != nil { - return nil, nil, [32]byte{}, err + return nil, nil, nil, err } - env.ParallelTransactions(true) + l.Info().Str("Node URL", env.ClCluster.NodeAPIs()[0].URL()).Msg("Creating VRF Key on the Node") + vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Key, err) + } + pubKeyCompressed := vrfKey.Data.ID - mockFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfConst.LinkEthFeedResponse) + l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Registering Proving Key") + provingKey, err := VRFV2RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2Contracts.Coordinator) if err != nil { - return nil, nil, [32]byte{}, err + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRegisteringProvingKey, err) } - lt, err := actions.DeployLINKToken(env.ContractDeployer) + keyHash, err := vrfv2Contracts.Coordinator.HashOfKey(context.Background(), provingKey) if err != nil { - return nil, nil, [32]byte{}, err + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) } - vrfv2Contracts, err := DeployVRFV2Contracts(env.ContractDeployer, env.EVMClient, lt, mockFeed) + + chainID := env.EVMClient.GetChainID() + + nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() if err != nil { - return nil, nil, [32]byte{}, err + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) } - err = env.EVMClient.WaitForEvents() + + l.Info().Msg("Creating VRFV2 Job") + vrfV2job, err := CreateVRFV2Job( + env.ClCluster.NodeAPIs()[0], + vrfv2Contracts.Coordinator.Address(), + nativeTokenPrimaryKeyAddress, + pubKeyCompressed, + chainID.String(), + vrfv2Config.MinimumConfirmations, + ) if err != nil { - return nil, nil, [32]byte{}, err + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) } - err = vrfv2Contracts.Coordinator.SetConfig( - vrfConst.MinimumConfirmations, - vrfConst.MaxGasLimitVRFCoordinatorConfig, - vrfConst.StalenessSeconds, - vrfConst.GasAfterPaymentCalculation, - vrfConst.LinkEthFeedResponse, - vrfConst.VRFCoordinatorV2FeeConfig, + + // this part is here because VRFv2 can work with only a specific key + // [[EVM.KeySpecific]] + // Key = '...' + addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrGetPrimaryKey, err) + } + nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, + node.WithVRFv2EVMEstimator(addr, vrfv2Config.CLNodeMaxGasPriceGWei), ) + l.Info().Msg("Restarting Node with new sending key PriceMax configuration") + err = env.ClCluster.Nodes[0].Restart(nodeConfig) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRestartCLNode, err) + } + + vrfv2KeyData := VRFV2KeyData{ + VRFKey: vrfKey, + EncodedProvingKey: provingKey, + KeyHash: keyHash, + } + + data := VRFV2Data{ + vrfv2KeyData, + vrfV2job, + nativeTokenPrimaryKeyAddress, + chainID, + } + + l.Info().Msg("VRFV2 environment setup is finished") + return vrfv2Contracts, subIDs, &data, nil +} + +func CreateFundSubsAndAddConsumers( + env *test_env.CLClusterTestEnv, + vrfv2Config vrfv2_config.VRFV2Config, + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + consumers []contracts.VRFv2LoadTestConsumer, + numberOfSubToCreate int, +) ([]uint64, error) { + subIDs, err := CreateSubsAndFund(env, vrfv2Config, linkToken, coordinator, numberOfSubToCreate) if err != nil { - return nil, nil, [32]byte{}, err + return nil, err + } + subToConsumersMap := map[uint64][]contracts.VRFv2LoadTestConsumer{} + + //each subscription will have the same consumers + for _, subID := range subIDs { + subToConsumersMap[subID] = consumers } + + err = AddConsumersToSubs( + subToConsumersMap, + coordinator, + ) + if err != nil { + return nil, err + } + err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, [32]byte{}, err + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = vrfv2Contracts.Coordinator.CreateSubscription() + return subIDs, nil +} + +func CreateSubsAndFund( + env *test_env.CLClusterTestEnv, + vrfv2Config vrfv2_config.VRFV2Config, + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + subAmountToCreate int, +) ([]uint64, error) { + subs, err := CreateSubs(env, coordinator, subAmountToCreate) if err != nil { - return nil, nil, [32]byte{}, err + return nil, err } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, [32]byte{}, err + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = vrfv2Contracts.Coordinator.AddConsumer(vrfConst.SubID, vrfv2Contracts.LoadTestConsumer.Address()) + err = FundSubscriptions(env, vrfv2Config, linkToken, coordinator, subs) if err != nil { - return nil, nil, [32]byte{}, err + return nil, err + } + return subs, nil +} + +func CreateSubs( + env *test_env.CLClusterTestEnv, + coordinator contracts.VRFCoordinatorV2, + subAmountToCreate int, +) ([]uint64, error) { + var subIDArr []uint64 + + for i := 0; i < subAmountToCreate; i++ { + subID, err := CreateSubAndFindSubID(env, coordinator) + if err != nil { + return nil, err + } + subIDArr = append(subIDArr, subID) + } + return subIDArr, nil +} + +func AddConsumersToSubs( + subToConsumerMap map[uint64][]contracts.VRFv2LoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, +) error { + for subID, consumers := range subToConsumerMap { + for _, consumer := range consumers { + err := coordinator.AddConsumer(subID, consumer.Address()) + if err != nil { + return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) + } + } } - err = FundVRFCoordinatorV2Subscription(lt, vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.SubID, subFundingLINK) + return nil +} + +func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2) (uint64, error) { + tx, err := coordinator.CreateSubscription() if err != nil { - return nil, nil, [32]byte{}, err + return 0, fmt.Errorf("%s, err %w", ErrCreateVRFSubscription, err) } - jobs, err := CreateVRFV2Jobs(env.ClCluster.NodeAPIs(), vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.MinimumConfirmations) + err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, [32]byte{}, err + return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - // this part is here because VRFv2 can work with only a specific key - // [[EVM.KeySpecific]] - // Key = '...' - addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() + + receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) if err != nil { - return nil, nil, [32]byte{}, err + return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(addr), + + //SubscriptionsCreated Log should be emitted with the subscription ID + subID := receipt.Logs[0].Topics[1].Big().Uint64() + + return subID, nil +} + +func FundSubscriptions( + env *test_env.CLClusterTestEnv, + vrfv2Config vrfv2_config.VRFV2Config, + linkAddress contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + subIDs []uint64, +) error { + for _, subID := range subIDs { + //Link Billing + amountJuels := conversions.EtherToWei(big.NewFloat(vrfv2Config.SubscriptionFundingAmountLink)) + err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + } + } + err := env.EVMClient.WaitForEvents() + if err != nil { + return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return nil +} + +func RequestRandomnessAndWaitForFulfillment( + consumer contracts.VRFv2LoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, + vrfv2Data *VRFV2Data, + subID uint64, + randomnessRequestCountPerRequest uint16, + vrfv2Config vrfv2_config.VRFV2Config, + randomWordsFulfilledEventTimeout time.Duration, + l zerolog.Logger, +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, vrfv2Config, l) + err := consumer.RequestRandomness( + vrfv2Data.KeyHash, + subID, + vrfv2Config.MinimumConfirmations, + vrfv2Config.CallbackGasLimit, + vrfv2Config.NumberOfWords, + randomnessRequestCountPerRequest, ) - err = env.ClCluster.Nodes[0].Restart(nodeConfig) if err != nil { - return nil, nil, [32]byte{}, err + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + } + + return WaitForRequestAndFulfillmentEvents( + consumer.Address(), + coordinator, + vrfv2Data, + subID, + randomWordsFulfilledEventTimeout, + l, + ) +} + +func WaitForRequestAndFulfillmentEvents( + consumerAddress string, + coordinator contracts.VRFCoordinatorV2, + vrfv2Data *VRFV2Data, + subID uint64, + randomWordsFulfilledEventTimeout time.Duration, + l zerolog.Logger, +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { + randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfv2Data.KeyHash}, + []uint64{subID}, + []common.Address{common.HexToAddress(consumerAddress)}, + time.Minute*1, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + } + + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + + randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( + []*big.Int{randomWordsRequestedEvent.RequestId}, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) + } + + LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) + return randomWordsFulfilledEvent, err +} + +func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2LoadTestConsumer, timeout time.Duration, wg *sync.WaitGroup) (*big.Int, *big.Int, error) { + metricsChannel := make(chan *contracts.VRFLoadTestMetrics) + metricsErrorChannel := make(chan error) + + testContext, testCancel := context.WithTimeout(context.Background(), timeout) + defer testCancel() + + ticker := time.NewTicker(time.Second * 1) + var metrics *contracts.VRFLoadTestMetrics + for { + select { + case <-testContext.Done(): + ticker.Stop() + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, + fmt.Errorf("timeout waiting for rand request and fulfilments to be equal AFTER performance test was executed. Request Count: %d, Fulfilment Count: %d", + metrics.RequestCount.Uint64(), metrics.FulfilmentCount.Uint64()) + case <-ticker.C: + go retrieveLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) + case metrics = <-metricsChannel: + if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { + ticker.Stop() + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, nil + } + case err := <-metricsErrorChannel: + ticker.Stop() + wg.Done() + return nil, nil, err + } + } +} + +func retrieveLoadTestMetrics( + consumer contracts.VRFv2LoadTestConsumer, + metricsChannel chan *contracts.VRFLoadTestMetrics, + metricsErrorChannel chan error, +) { + metrics, err := consumer.GetLoadTestMetrics(context.Background()) + if err != nil { + metricsErrorChannel <- err } - return env, vrfv2Contracts, jobs[0].KeyHash, nil + metricsChannel <- metrics +} + +func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2.GetSubscription, subID uint64, coordinator contracts.VRFCoordinatorV2) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). + Uint64("Subscription ID", subID). + Str("Subscription Owner", subscription.Owner.String()). + Interface("Subscription Consumers", subscription.Consumers). + Msg("Subscription Data") +} + +func LogRandomnessRequestedEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2, + randomWordsRequestedEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Uint64("Subscription ID", randomWordsRequestedEvent.SubId). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Interface("Keyhash", randomWordsRequestedEvent.KeyHash). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2, + randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). + Bool("Success", randomWordsFulfilledEvent.Success). + Msg("RandomWordsFulfilled Event (TX metadata)") +} + +func logRandRequest( + consumer string, + coordinator string, + subID uint64, + vrfv2Config vrfv2_config.VRFV2Config, + l zerolog.Logger, +) { + l.Debug(). + Str("Consumer", consumer). + Str("Coordinator", coordinator). + Uint64("SubID", subID). + Uint16("MinimumConfirmations", vrfv2Config.MinimumConfirmations). + Uint32("CallbackGasLimit", vrfv2Config.CallbackGasLimit). + Uint16("RandomnessRequestCountPerRequest", vrfv2Config.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2Config.RandomnessRequestCountPerRequestDeviation). + Msg("Requesting randomness") } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go index a47103a8a1..8cd6e0a8ce 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -4,6 +4,7 @@ import "time" type VRFV2PlusConfig struct { ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with + CLNodeMaxGasPriceGWei int64 `envconfig:"MAX_GAS_PRICE_GWEI" default:"1000"` // Max gas price in GWei for the chainlink node IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index fd15d51af4..d0a33948e3 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -46,7 +46,6 @@ var ( ErrDeployVRFV2_5Contracts = "error deploying VRFV2_5 contracts" ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" ErrCreateVRFSubscription = "error creating VRF Subscription" - ErrFindSubID = "error finding created subscription ID" ErrAddConsumerToSub = "error adding consumer to VRF Subscription" ErrFundSubWithNativeToken = "error funding subscription with native token" ErrSetLinkNativeLinkFeed = "error setting Link and ETH/LINK feed for VRF Coordinator contract" @@ -98,35 +97,6 @@ func DeployVRFV2_5Contracts( return &VRFV2_5Contracts{coordinator, bhs, consumers}, nil } -func DeployVRFV2PlusDirectFundingContracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, - linkTokenAddress string, - linkEthFeedAddress string, - coordinator contracts.VRFCoordinatorV2_5, - consumerContractsAmount int, -) (*VRFV2PlusWrapperContracts, error) { - - vrfv2PlusWrapper, err := contractDeployer.DeployVRFV2PlusWrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - - consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, linkTokenAddress, vrfv2PlusWrapper, consumerContractsAmount) - if err != nil { - return nil, err - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil -} - func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2_5, consumerContractsAmount int) ([]contracts.VRFv2PlusLoadTestConsumer, error) { var consumers []contracts.VRFv2PlusLoadTestConsumer for i := 1; i <= consumerContractsAmount; i++ { @@ -139,18 +109,6 @@ func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coord return consumers, nil } -func DeployVRFV2PlusWrapperConsumers(contractDeployer contracts.ContractDeployer, linkTokenAddress string, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, consumerContractsAmount int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) { - var consumers []contracts.VRFv2PlusWrapperLoadTestConsumer - for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFV2PlusWrapperLoadTestConsumer(linkTokenAddress, vrfV2PlusWrapper.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) - } - consumers = append(consumers, loadTestConsumer) - } - return consumers, nil -} - func CreateVRFV2PlusJob( chainlinkNode *client.ChainlinkClient, coordinatorAddress string, @@ -285,7 +243,10 @@ func SetupVRFV2_5Environment( if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Int("Number of Subs to create", numberOfSubToCreate).Msg("Creating and funding subscriptions, adding consumers") + l.Info(). + Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()). + Int("Number of Subs to create", numberOfSubToCreate). + Msg("Creating and funding subscriptions, adding consumers") subIDs, err := CreateFundSubsAndAddConsumers( env, vrfv2PlusConfig, @@ -339,7 +300,7 @@ func SetupVRFV2_5Environment( return nil, nil, nil, fmt.Errorf("%s, err %w", ErrGetPrimaryKey, err) } nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(addr), + node.WithVRFv2EVMEstimator(addr, vrfv2PlusConfig.CLNodeMaxGasPriceGWei), ) l.Info().Msg("Restarting Node with new sending key PriceMax configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) @@ -452,93 +413,6 @@ func AddConsumersToSubs( return nil } -func SetupVRFV2PlusWrapperEnvironment( - env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, - linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - coordinator contracts.VRFCoordinatorV2_5, - keyHash [32]byte, - wrapperConsumerContractsAmount int, -) (*VRFV2PlusWrapperContracts, *big.Int, error) { - - wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts( - env.ContractDeployer, - env.EVMClient, - linkToken.Address(), - mockNativeLINKFeed.Address(), - coordinator, - wrapperConsumerContractsAmount, - ) - if err != nil { - return nil, nil, err - } - - err = env.EVMClient.WaitForEvents() - - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - err = wrapperContracts.VRFV2PlusWrapper.SetConfig( - vrfv2PlusConfig.WrapperGasOverhead, - vrfv2PlusConfig.CoordinatorGasOverhead, - vrfv2PlusConfig.WrapperPremiumPercentage, - keyHash, - vrfv2PlusConfig.WrapperMaxNumberOfWords, - vrfv2PlusConfig.StalenessSeconds, - big.NewInt(vrfv2PlusConfig.FallbackWeiPerUnitLink), - vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, - ) - if err != nil { - return nil, nil, err - } - - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - - //fund sub - wrapperSubID, err := wrapperContracts.VRFV2PlusWrapper.GetSubID(context.Background()) - if err != nil { - return nil, nil, err - } - - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - - err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, []*big.Int{wrapperSubID}) - if err != nil { - return nil, nil, err - } - - //fund consumer with Link - err = linkToken.Transfer( - wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), - ) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - - //fund consumer with Eth - err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - return wrapperContracts, wrapperSubID, nil -} func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { tx, err := coordinator.CreateSubscription() if err != nil { @@ -557,39 +431,9 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts //SubscriptionsCreated Log should be emitted with the subscription ID subID := receipt.Logs[0].Topics[1].Big() - //verify that the subscription was created - _, err = coordinator.FindSubscriptionID(subID) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrFindSubID, err) - } - return subID, nil } -func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { - linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) - } - nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) - } - return -} - -func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { - linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) - } - nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) - } - return -} - func FundSubscriptions( env *test_env.CLClusterTestEnv, vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, @@ -621,6 +465,30 @@ func FundSubscriptions( return nil } +func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { + linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) + } + nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) + } + return +} + +func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { + linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) + } + nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) + } + return +} + func RequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2PlusLoadTestConsumer, coordinator contracts.VRFCoordinatorV2_5, @@ -705,6 +573,135 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( return randomWordsFulfilledEvent, err } +func SetupVRFV2PlusWrapperEnvironment( + env *test_env.CLClusterTestEnv, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.MockETHLINKFeed, + coordinator contracts.VRFCoordinatorV2_5, + keyHash [32]byte, + wrapperConsumerContractsAmount int, +) (*VRFV2PlusWrapperContracts, *big.Int, error) { + + wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts( + env.ContractDeployer, + env.EVMClient, + linkToken.Address(), + mockNativeLINKFeed.Address(), + coordinator, + wrapperConsumerContractsAmount, + ) + if err != nil { + return nil, nil, err + } + + err = env.EVMClient.WaitForEvents() + + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + err = wrapperContracts.VRFV2PlusWrapper.SetConfig( + vrfv2PlusConfig.WrapperGasOverhead, + vrfv2PlusConfig.CoordinatorGasOverhead, + vrfv2PlusConfig.WrapperPremiumPercentage, + keyHash, + vrfv2PlusConfig.WrapperMaxNumberOfWords, + vrfv2PlusConfig.StalenessSeconds, + big.NewInt(vrfv2PlusConfig.FallbackWeiPerUnitLink), + vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + ) + if err != nil { + return nil, nil, err + } + + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + //fund sub + wrapperSubID, err := wrapperContracts.VRFV2PlusWrapper.GetSubID(context.Background()) + if err != nil { + return nil, nil, err + } + + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, []*big.Int{wrapperSubID}) + if err != nil { + return nil, nil, err + } + + //fund consumer with Link + err = linkToken.Transfer( + wrapperContracts.LoadTestConsumers[0].Address(), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), + ) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + //fund consumer with Eth + err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return wrapperContracts, wrapperSubID, nil +} + +func DeployVRFV2PlusWrapperConsumers(contractDeployer contracts.ContractDeployer, linkTokenAddress string, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, consumerContractsAmount int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) { + var consumers []contracts.VRFv2PlusWrapperLoadTestConsumer + for i := 1; i <= consumerContractsAmount; i++ { + loadTestConsumer, err := contractDeployer.DeployVRFV2PlusWrapperLoadTestConsumer(linkTokenAddress, vrfV2PlusWrapper.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + } + consumers = append(consumers, loadTestConsumer) + } + return consumers, nil +} + +func DeployVRFV2PlusDirectFundingContracts( + contractDeployer contracts.ContractDeployer, + chainClient blockchain.EVMClient, + linkTokenAddress string, + linkEthFeedAddress string, + coordinator contracts.VRFCoordinatorV2_5, + consumerContractsAmount int, +) (*VRFV2PlusWrapperContracts, error) { + + vrfv2PlusWrapper, err := contractDeployer.DeployVRFV2PlusWrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, linkTokenAddress, vrfv2PlusWrapper, consumerContractsAmount) + if err != nil { + return nil, err + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil +} + func DirectFundingRequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2PlusWrapperLoadTestConsumer, coordinator contracts.VRFCoordinatorV2_5, @@ -804,7 +801,7 @@ func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadT fmt.Errorf("timeout waiting for rand request and fulfilments to be equal AFTER performance test was executed. Request Count: %d, Fulfilment Count: %d", metrics.RequestCount.Uint64(), metrics.FulfilmentCount.Uint64()) case <-ticker.C: - go retreiveLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) + go retrieveLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) case metrics = <-metricsChannel: if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { ticker.Stop() @@ -854,7 +851,7 @@ func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator co return nil } -func retreiveLoadTestMetrics( +func retrieveLoadTestMetrics( consumer contracts.VRFv2PlusLoadTestConsumer, metricsChannel chan *contracts.VRFLoadTestMetrics, metricsErrorChannel chan error, diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 9a2f20226d..6136e78b36 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -17,6 +17,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/fee_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/reward_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" @@ -44,6 +46,8 @@ type ContractLoader interface { LoadWERC20Mock(addr common.Address) (WERC20Mock, error) // VRF + LoadVRFCoordinatorV2(addr string) (VRFCoordinatorV2, error) + LoadVRFv2LoadTestConsumer(addr string) (VRFv2LoadTestConsumer, error) LoadVRFCoordinatorV2_5(addr string) (VRFCoordinatorV2_5, error) LoadVRFv2PlusLoadTestConsumer(addr string) (VRFv2PlusLoadTestConsumer, error) } @@ -356,3 +360,39 @@ func (e *EthereumContractLoader) LoadVRFv2PlusLoadTestConsumer(addr string) (VRF address: &address, }, err } + +func (e *EthereumContractLoader) LoadVRFCoordinatorV2(addr string) (VRFCoordinatorV2, error) { + address := common.HexToAddress(addr) + instance, err := e.client.LoadContract("VRFCoordinatorV2", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return vrf_coordinator_v2.NewVRFCoordinatorV2(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumVRFCoordinatorV2{ + address: &address, + client: e.client, + coordinator: instance.(*vrf_coordinator_v2.VRFCoordinatorV2), + }, err +} + +func (e *EthereumContractLoader) LoadVRFv2LoadTestConsumer(addr string) (VRFv2LoadTestConsumer, error) { + address := common.HexToAddress(addr) + instance, err := e.client.LoadContract("VRFV2LoadTestWithMetrics", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return vrf_load_test_with_metrics.NewVRFV2LoadTestWithMetrics(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumVRFv2LoadTestConsumer{ + client: e.client, + consumer: instance.(*vrf_load_test_with_metrics.VRFV2LoadTestWithMetrics), + address: &address, + }, err +} diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index baee2ccd92..5f850fce1a 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -49,10 +49,15 @@ type VRFCoordinatorV2 interface { publicProvingKey [2]*big.Int, ) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) - CreateSubscription() error + CreateSubscription() (*types.Transaction, error) AddConsumer(subId uint64, consumerAddress string) error Address() string GetSubscription(ctx context.Context, subID uint64) (vrf_coordinator_v2.GetSubscription, error) + PendingRequestsExist(ctx context.Context, subID uint64) (bool, error) + CancelSubscription(subID uint64, to common.Address) (*types.Transaction, error) + FindSubscriptionID(subID uint64) (uint64, error) + WaitForRandomWordsFulfilledEvent(requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) + WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []uint64, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) } type VRFCoordinatorV2_5 interface { @@ -169,6 +174,7 @@ type VRFv2LoadTestConsumer interface { GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_load_test_with_metrics.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) + ResetMetrics() error } type VRFv2PlusLoadTestConsumer interface { diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index 9c7e628dbd..ac3926fa74 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -3,7 +3,9 @@ package contracts import ( "context" "encoding/hex" + "fmt" "math/big" + "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -182,16 +184,16 @@ func (v *EthereumVRFCoordinatorV2) RegisterProvingKey( return v.client.ProcessTransaction(tx) } -func (v *EthereumVRFCoordinatorV2) CreateSubscription() error { +func (v *EthereumVRFCoordinatorV2) CreateSubscription() (*types.Transaction, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { - return err + return nil, err } tx, err := v.coordinator.CreateSubscription(opts) if err != nil { - return err + return nil, err } - return v.client.ProcessTransaction(tx) + return tx, v.client.ProcessTransaction(tx) } func (v *EthereumVRFCoordinatorV2) AddConsumer(subId uint64, consumerAddress string) error { @@ -210,6 +212,94 @@ func (v *EthereumVRFCoordinatorV2) AddConsumer(subId uint64, consumerAddress str return v.client.ProcessTransaction(tx) } +func (v *EthereumVRFCoordinatorV2) PendingRequestsExist(ctx context.Context, subID uint64) (bool, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + pendingRequestExists, err := v.coordinator.PendingRequestExists(opts, subID) + if err != nil { + return false, err + } + return pendingRequestExists, nil +} + +// CancelSubscription cancels subscription by Sub owner, +// return funds to specified address, +// checks if pending requests for a sub exist +func (v *EthereumVRFCoordinatorV2) CancelSubscription(subID uint64, to common.Address) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.coordinator.CancelSubscription( + opts, + subID, + to, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFCoordinatorV2) FindSubscriptionID(subID uint64) (uint64, error) { + owner := v.client.GetDefaultWallet().Address() + subscriptionIterator, err := v.coordinator.FilterSubscriptionCreated( + nil, + []uint64{subID}, + ) + if err != nil { + return 0, err + } + + if !subscriptionIterator.Next() { + return 0, fmt.Errorf("expected at least 1 subID for the given owner %s", owner) + } + + return subscriptionIterator.Event.SubId, nil +} + +func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsFulfilledEvent(requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { + randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled) + subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, requestID) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for RandomWordsFulfilled event") + case randomWordsFulfilledEvent := <-randomWordsFulfilledEventsChannel: + return randomWordsFulfilledEvent, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []uint64, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { + randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested) + subscription, err := v.coordinator.WatchRandomWordsRequested(nil, randomWordsFulfilledEventsChannel, keyHash, subID, sender) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for RandomWordsRequested event") + case randomWordsFulfilledEvent := <-randomWordsFulfilledEventsChannel: + return randomWordsFulfilledEvent, nil + } + } +} + // GetAllRandomWords get all VRFv2 randomness output words func (v *EthereumVRFConsumerV2) GetAllRandomWords(ctx context.Context, num int) ([]*big.Int, error) { words := make([]*big.Int, 0) @@ -392,6 +482,18 @@ func (v *EthereumVRFv2LoadTestConsumer) GetLastRequestId(ctx context.Context) (* }) } +func (v *EthereumVRFv2LoadTestConsumer) ResetMetrics() error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.consumer.Reset(opts) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFv2LoadTestConsumer) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) { requestCount, err := v.consumer.SRequestCount(&bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), diff --git a/integration-tests/load/vrfv2/config.go b/integration-tests/load/vrfv2/config.go index 0a595f753c..e23294e839 100644 --- a/integration-tests/load/vrfv2/config.go +++ b/integration-tests/load/vrfv2/config.go @@ -1,10 +1,12 @@ package loadvrfv2 import ( + "encoding/base64" "fmt" - "math/big" "os" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" @@ -13,64 +15,136 @@ import ( const ( DefaultConfigFilename = "config.toml" + SoakTestType = "Soak" + LoadTestType = "Load" + StressTestType = "Stress" + SpikeTestType = "Spike" - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" + ErrDeviationShouldBeLessThanOriginal = "`RandomnessRequestCountPerRequestDeviation` should be less than `RandomnessRequestCountPerRequest`" ) type PerformanceConfig struct { - Soak *Soak `toml:"Soak"` - Load *Load `toml:"Load"` - SoakVolume *SoakVolume `toml:"SoakVolume"` - LoadVolume *LoadVolume `toml:"LoadVolume"` - Common *Common `toml:"Common"` + Soak *Soak `toml:"Soak"` + Load *Load `toml:"Load"` + Stress *Stress `toml:"Stress"` + Spike *Spike `toml:"Spike"` + + Common *Common `toml:"Common"` + ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnvConfig"` + NewEnvConfig *NewEnvConfig `toml:"NewEnvConfig"` } -type Common struct { +type ExistingEnvConfig struct { + CoordinatorAddress string `toml:"coordinator_address"` + ConsumerAddress string `toml:"consumer_address"` + LinkAddress string `toml:"link_address"` + SubID uint64 `toml:"sub_id"` + KeyHash string `toml:"key_hash"` + Funding + CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` + NodeSendingKeys []string `toml:"node_sending_keys"` +} + +type NewEnvConfig struct { Funding } +type Common struct { + MinimumConfirmations uint16 `toml:"minimum_confirmations"` +} + type Funding struct { - NodeFunds *big.Float `toml:"node_funds"` - SubFunds *big.Int `toml:"sub_funds"` + SubFunding + NodeSendingKeyFunding float64 `toml:"node_sending_key_funding"` + NodeSendingKeyFundingMin float64 `toml:"node_sending_key_funding_min"` } -type Soak struct { - RPS int64 `toml:"rps"` - Duration *models.Duration `toml:"duration"` +type SubFunding struct { + SubFundsLink float64 `toml:"sub_funds_link"` } -type SoakVolume struct { - Products int64 `toml:"products"` - Pace *models.Duration `toml:"pace"` - Duration *models.Duration `toml:"duration"` +type Soak struct { + PerformanceTestConfig } type Load struct { - RPSFrom int64 `toml:"rps_from"` - RPSIncrease int64 `toml:"rps_increase"` - RPSSteps int `toml:"rps_steps"` - Duration *models.Duration `toml:"duration"` + PerformanceTestConfig } -type LoadVolume struct { - ProductsFrom int64 `toml:"products_from"` - ProductsIncrease int64 `toml:"products_increase"` - ProductsSteps int `toml:"products_steps"` - Pace *models.Duration `toml:"pace"` - Duration *models.Duration `toml:"duration"` +type Stress struct { + PerformanceTestConfig +} + +type Spike struct { + PerformanceTestConfig +} + +type PerformanceTestConfig struct { + NumberOfSubToCreate int `toml:"number_of_sub_to_create"` + + RPS int64 `toml:"rps"` + //Duration *models.Duration `toml:"duration"` + RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` + RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` + RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` } func ReadConfig() (*PerformanceConfig, error) { var cfg *PerformanceConfig - d, err := os.ReadFile(DefaultConfigFilename) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) + rawConfig := os.Getenv("CONFIG") + var d []byte + var err error + if rawConfig == "" { + d, err = os.ReadFile(DefaultConfigFilename) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) + } + } else { + d, err = base64.StdEncoding.DecodeString(rawConfig) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) + } } err = toml.Unmarshal(d, &cfg) if err != nil { return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) } - log.Debug().Interface("PerformanceConfig", cfg).Msg("Parsed performance config") + + if cfg.Soak.RandomnessRequestCountPerRequest <= cfg.Soak.RandomnessRequestCountPerRequestDeviation { + return nil, fmt.Errorf("%s, err: %w", ErrDeviationShouldBeLessThanOriginal, err) + } + + log.Debug().Interface("Config", cfg).Msg("Parsed config") return cfg, nil } + +func SetPerformanceTestConfig(testType string, vrfv2Config *vrfv2_config.VRFV2Config, cfg *PerformanceConfig) { + switch testType { + case SoakTestType: + vrfv2Config.NumberOfSubToCreate = cfg.Soak.NumberOfSubToCreate + vrfv2Config.RPS = cfg.Soak.RPS + vrfv2Config.RateLimitUnitDuration = cfg.Soak.RateLimitUnitDuration.Duration() + vrfv2Config.RandomnessRequestCountPerRequest = cfg.Soak.RandomnessRequestCountPerRequest + vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Soak.RandomnessRequestCountPerRequestDeviation + case LoadTestType: + vrfv2Config.NumberOfSubToCreate = cfg.Load.NumberOfSubToCreate + vrfv2Config.RPS = cfg.Load.RPS + vrfv2Config.RateLimitUnitDuration = cfg.Load.RateLimitUnitDuration.Duration() + vrfv2Config.RandomnessRequestCountPerRequest = cfg.Load.RandomnessRequestCountPerRequest + vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Load.RandomnessRequestCountPerRequestDeviation + case StressTestType: + vrfv2Config.NumberOfSubToCreate = cfg.Stress.NumberOfSubToCreate + vrfv2Config.RPS = cfg.Stress.RPS + vrfv2Config.RateLimitUnitDuration = cfg.Stress.RateLimitUnitDuration.Duration() + vrfv2Config.RandomnessRequestCountPerRequest = cfg.Stress.RandomnessRequestCountPerRequest + vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Stress.RandomnessRequestCountPerRequestDeviation + case SpikeTestType: + vrfv2Config.NumberOfSubToCreate = cfg.Spike.NumberOfSubToCreate + vrfv2Config.RPS = cfg.Spike.RPS + vrfv2Config.RateLimitUnitDuration = cfg.Spike.RateLimitUnitDuration.Duration() + vrfv2Config.RandomnessRequestCountPerRequest = cfg.Spike.RandomnessRequestCountPerRequest + vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Spike.RandomnessRequestCountPerRequestDeviation + } +} diff --git a/integration-tests/load/vrfv2/config.toml b/integration-tests/load/vrfv2/config.toml index 8917db88cc..4e82ec7aeb 100644 --- a/integration-tests/load/vrfv2/config.toml +++ b/integration-tests/load/vrfv2/config.toml @@ -1,27 +1,57 @@ -# testing one product (jobs + contracts) by varying RPS + +[Common] +minimum_confirmations = 3 + +[NewEnvConfig] +sub_funds_link = 1 +node_sending_key_funding = 10 + +[ExistingEnvConfig] +coordinator_address = "0x50d47e4142598E3411aA864e08a44284e471AC6f" +#consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" +#sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" +key_hash = "0x027f94ff1465b3525f9fc03e9ff7d6d2c0953482246dd6ae07570c45d6631414" +create_fund_subs_and_add_consumers = true +link_address = "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E" +sub_funds_link = 3 +node_sending_key_funding_min = 2 +node_sending_keys = [ + "", + "", + "", + "", + "", + "", +] + +# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds [Soak] +rate_limit_unit_duration = "6s" rps = 1 -duration = "3m" +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds [Load] -rps_from = 1 -rps_increase = 1 -rps_steps = 10 -duration = "3m" - -# testing multiple products (jobs + contracts) by varying instances, deploying more of the same type with stable RPS for each product -[SoakVolume] -products = 5 -pace = "1s" -duration = "3m" +rate_limit_unit_duration = "3s" +rps = 1 +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 -[LoadVolume] -products_from = 1 -products_increase = 1 -products_steps = 10 -pace = "1s" -duration = "3m" +# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx +[Stress] +rate_limit_unit_duration = "1s" +rps = 3 +randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 -[Common] -node_funds = 10 -sub_funds = 100 \ No newline at end of file +# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds +[Spike] +rate_limit_unit_duration = "1m" +rps = 1 +randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index 8100baaa7f..8a5eb3c66d 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -1,38 +1,78 @@ package loadvrfv2 import ( + "math/rand" + + "github.com/rs/zerolog" + "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" ) /* SingleHashGun is a gun that constantly requests randomness for one feed */ type SingleHashGun struct { - contracts *vrfv2_actions.VRFV2Contracts - keyHash [32]byte + contracts *vrfv2_actions.VRFV2Contracts + keyHash [32]byte + subIDs []uint64 + vrfv2Config vrfv2_config.VRFV2Config + logger zerolog.Logger } -func SingleFeedGun(contracts *vrfv2_actions.VRFV2Contracts, keyHash [32]byte) *SingleHashGun { +func NewSingleHashGun( + contracts *vrfv2_actions.VRFV2Contracts, + keyHash [32]byte, + subIDs []uint64, + vrfv2Config vrfv2_config.VRFV2Config, + logger zerolog.Logger, +) *SingleHashGun { return &SingleHashGun{ - contracts: contracts, - keyHash: keyHash, + contracts: contracts, + keyHash: keyHash, + subIDs: subIDs, + vrfv2Config: vrfv2Config, + logger: logger, } } // Call implements example gun call, assertions on response bodies should be done here func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { - err := m.contracts.LoadTestConsumer.RequestRandomness( - m.keyHash, - vrfConst.SubID, - vrfConst.MinimumConfirmations, - vrfConst.CallbackGasLimit, - vrfConst.NumberOfWords, - vrfConst.RandomnessRequestCountPerRequest, + //todo - should work with multiple consumers and consumers having different keyhashes and wallets + + //randomly increase/decrease randomness request count per TX + randomnessRequestCountPerRequest := deviateValue(m.vrfv2Config.RandomnessRequestCountPerRequest, m.vrfv2Config.RandomnessRequestCountPerRequestDeviation) + _, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + //the same consumer is used for all requests and in all subs + m.contracts.LoadTestConsumers[0], + m.contracts.Coordinator, + &vrfv2_actions.VRFV2Data{VRFV2KeyData: vrfv2_actions.VRFV2KeyData{KeyHash: m.keyHash}}, + //randomly pick a subID from pool of subIDs + m.subIDs[randInRange(0, len(m.subIDs)-1)], + randomnessRequestCountPerRequest, + m.vrfv2Config, + m.vrfv2Config.RandomWordsFulfilledEventTimeout, + m.logger, ) if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } return &wasp.CallResult{} } + +func deviateValue(requestCountPerTX uint16, deviation uint16) uint16 { + if randBool() && requestCountPerTX > deviation { + requestCountPerTX -= uint16(randInRange(0, int(deviation))) + } else { + requestCountPerTX += uint16(randInRange(0, int(deviation))) + } + return requestCountPerTX +} + +func randBool() bool { + return rand.Intn(2) == 1 +} +func randInRange(min int, max int) int { + return rand.Intn(max-min+1) + min +} diff --git a/integration-tests/load/vrfv2/onchain_monitoring.go b/integration-tests/load/vrfv2/onchain_monitoring.go index 66af1807ac..55975a7e42 100644 --- a/integration-tests/load/vrfv2/onchain_monitoring.go +++ b/integration-tests/load/vrfv2/onchain_monitoring.go @@ -1,15 +1,14 @@ package loadvrfv2 import ( + "context" "testing" "time" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) /* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ @@ -21,29 +20,37 @@ const ( ErrLokiPush = "failed to push monitoring metrics to Loki" ) -func MonitorLoadStats(t *testing.T, vrfv2Contracts *vrfv2_actions.VRFV2Contracts, labels map[string]string) { +func MonitorLoadStats(lc *wasp.LokiClient, consumer contracts.VRFv2LoadTestConsumer, labels map[string]string) { go func() { - updatedLabels := make(map[string]string) - for k, v := range labels { - updatedLabels[k] = v - } - updatedLabels["type"] = LokiTypeLabel - updatedLabels["go_test_name"] = t.Name() - updatedLabels["gen_name"] = "performance" - lc, err := wasp.NewLokiClient(wasp.NewEnvLokiConfig()) - if err != nil { - log.Error().Err(err).Msg(ErrLokiClient) - return - } for { time.Sleep(1 * time.Second) - metrics, err := vrfv2Contracts.LoadTestConsumer.GetLoadTestMetrics(testcontext.Get(t)) - if err != nil { - log.Error().Err(err).Msg(ErrMetrics) - } - if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), metrics); err != nil { - log.Error().Err(err).Msg(ErrLokiPush) - } + metrics := GetLoadTestMetrics(consumer) + SendMetricsToLoki(metrics, lc, labels) } }() } + +func UpdateLabels(labels map[string]string, t *testing.T) map[string]string { + updatedLabels := make(map[string]string) + for k, v := range labels { + updatedLabels[k] = v + } + updatedLabels["type"] = LokiTypeLabel + updatedLabels["go_test_name"] = t.Name() + updatedLabels["gen_name"] = "performance" + return updatedLabels +} + +func SendMetricsToLoki(metrics *contracts.VRFLoadTestMetrics, lc *wasp.LokiClient, updatedLabels map[string]string) { + if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), metrics); err != nil { + log.Error().Err(err).Msg(ErrLokiPush) + } +} + +func GetLoadTestMetrics(consumer contracts.VRFv2LoadTestConsumer) *contracts.VRFLoadTestMetrics { + metrics, err := consumer.GetLoadTestMetrics(context.Background()) + if err != nil { + log.Error().Err(err).Msg(ErrMetrics) + } + return metrics +} diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 44325965bd..37a7044289 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -1,94 +1,358 @@ package loadvrfv2 import ( + "context" + "math/big" + "os" + "sync" "testing" + "time" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/kelseyhightower/envconfig" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" ) -func TestVRFV2Load(t *testing.T) { +var ( + env *test_env.CLClusterTestEnv + vrfv2Contracts *vrfv2_actions.VRFV2Contracts + vrfv2Data *vrfv2_actions.VRFV2Data + subIDs []uint64 + eoaWalletAddress string + + labels = map[string]string{ + "branch": "vrfv2_healthcheck", + "commit": "vrfv2_healthcheck", + } + + testType = os.Getenv("TEST_TYPE") +) + +func TestVRFV2Performance(t *testing.T) { cfg, err := ReadConfig() require.NoError(t, err) - env, vrfv2Contracts, key, err := vrfv2_actions.SetupLocalLoadTestEnv(cfg.Common.NodeFunds, cfg.Common.SubFunds) + var vrfv2Config vrfv2_config.VRFV2Config + err = envconfig.Process("VRFV2", &vrfv2Config) require.NoError(t, err) - labels := map[string]string{ - "branch": "vrfv2_healthcheck", - "commit": "vrfv2_healthcheck", + testReporter := &testreporters.VRFV2TestReporter{} + + SetPerformanceTestConfig(testType, &vrfv2Config, cfg) + + l := logging.GetTestLogger(t) + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2Config.MinimumConfirmations = cfg.Common.MinimumConfirmations + + lokiConfig := wasp.NewEnvLokiConfig() + lc, err := wasp.NewLokiClient(lokiConfig) + if err != nil { + l.Error().Err(err).Msg(ErrLokiClient) + return } - singleFeedConfig := &wasp.Config{ - T: t, - LoadType: wasp.RPS, - GenName: "gun", - Gun: SingleFeedGun(vrfv2Contracts, key), - Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + updatedLabels := UpdateLabels(labels, t) + + l.Info(). + Str("Test Type", testType). + Str("Test Duration", vrfv2Config.TestDuration.Truncate(time.Second).String()). + Int64("RPS", vrfv2Config.RPS). + Str("RateLimitUnitDuration", vrfv2Config.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", vrfv2Config.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2Config.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", vrfv2Config.UseExistingEnv). + Msg("Performance Test Configuration") + + if vrfv2Config.UseExistingEnv { + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2Config.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress + vrfv2Config.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress + vrfv2Config.LinkAddress = cfg.ExistingEnvConfig.LinkAddress + vrfv2Config.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink + vrfv2Config.SubID = cfg.ExistingEnvConfig.SubID + vrfv2Config.KeyHash = cfg.ExistingEnvConfig.KeyHash + + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithCustomCleanup( + func() { + teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2Config) + if env.EVMClient.NetworkSimulated() { + l.Info(). + Str("Network Name", env.EVMClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + //cancel subs and return funds to sub owner + for _, subID := range subIDs { + l.Info(). + Uint64("Returning funds from SubID", subID). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + pendingRequestsExist, err := vrfv2Contracts.Coordinator.PendingRequestsExist(context.Background(), subID) + if err != nil { + l.Error().Err(err).Msg("Error checking if pending requests exist") + } + if !pendingRequestsExist { + _, err := vrfv2Contracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } else { + l.Error().Uint64("Sub ID", subID).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") + } + + } + } + }). + Build() + + require.NoError(t, err, "error creating test env") + + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(vrfv2Config.CoordinatorAddress) + require.NoError(t, err) + + var consumers []contracts.VRFv2LoadTestConsumer + if cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { + linkToken, err := env.ContractLoader.LoadLINKToken(vrfv2Config.LinkAddress) + require.NoError(t, err) + consumers, err = vrfv2_actions.DeployVRFV2Consumers(env.ContractDeployer, coordinator, 1) + require.NoError(t, err) + subIDs, err = vrfv2_actions.CreateFundSubsAndAddConsumers( + env, + vrfv2Config, + linkToken, + coordinator, + consumers, + vrfv2Config.NumberOfSubToCreate, + ) + require.NoError(t, err) + } else { + consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(vrfv2Config.ConsumerAddress) + require.NoError(t, err) + consumers = append(consumers, consumer) + subIDs = append(subIDs, vrfv2Config.SubID) + } + + err = FundNodesIfNeeded(cfg, env.EVMClient, l) + require.NoError(t, err) + + vrfv2Contracts = &vrfv2_actions.VRFV2Contracts{ + Coordinator: coordinator, + LoadTestConsumers: consumers, + BHS: nil, + } + + vrfv2Data = &vrfv2_actions.VRFV2Data{ + VRFV2KeyData: vrfv2_actions.VRFV2KeyData{ + VRFKey: nil, + EncodedProvingKey: [2]*big.Int{}, + KeyHash: common.HexToHash(vrfv2Config.KeyHash), + }, + VRFJob: nil, + PrimaryEthAddress: "", + ChainID: nil, + } + + } else { + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2Config.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeSendingKeyFunding + vrfv2Config.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithCLNodes(1). + WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithCustomCleanup( + func() { + teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2Config) + + if env.EVMClient.NetworkSimulated() { + l.Info(). + Str("Network Name", env.EVMClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + for _, subID := range subIDs { + l.Info(). + Uint64("Returning funds from SubID", subID). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + _, err := vrfv2Contracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } + //err = vrfv2.ReturnFundsForFulfilledRequests(env.EVMClient, vrfv2Contracts.Coordinator, l) + //l.Error().Err(err).Msg("Error returning funds for fulfilled requests") + } + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + }). + WithLogWatcher(). + Build() + + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + require.NoError(t, err, "error deploying mock ETH/LINK feed") + + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err, "error deploying LINK contract") + + vrfv2Contracts, subIDs, vrfv2Data, err = vrfv2_actions.SetupVRFV2Environment( + env, + vrfv2Config, + linkToken, + mockETHLinkFeed, + //register proving key against EOA address in order to return funds to this address + env.EVMClient.GetDefaultWallet().Address(), + 1, + vrfv2Config.NumberOfSubToCreate, + l, + ) + require.NoError(t, err, "error setting up VRF v2 env") } + eoaWalletAddress = env.EVMClient.GetDefaultWallet().Address() - multiFeedConfig := &wasp.Config{ - T: t, - LoadType: wasp.VU, - GenName: "vu", - VU: NewJobVolumeVU(cfg.SoakVolume.Pace.Duration(), 1, env.ClCluster.NodeAPIs(), env.EVMClient, vrfv2Contracts), - Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") + for _, subID := range subIDs { + subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + require.NoError(t, err, "error getting subscription information for subscription %d", subID) + vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) } - MonitorLoadStats(t, vrfv2Contracts, labels) + singleFeedConfig := &wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "gun", + RateLimitUnitDuration: vrfv2Config.RateLimitUnitDuration, + Gun: NewSingleHashGun( + vrfv2Contracts, + vrfv2Data.KeyHash, + subIDs, + vrfv2Config, + l, + ), + Labels: labels, + LokiConfig: lokiConfig, + CallTimeout: 2 * time.Minute, + } + require.Len(t, vrfv2Contracts.LoadTestConsumers, 1, "only one consumer should be created for Load Test") + consumer := vrfv2Contracts.LoadTestConsumers[0] + err = consumer.ResetMetrics() + require.NoError(t, err) + MonitorLoadStats(lc, consumer, updatedLabels) // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? - t.Run("vrfv2 soak test", func(t *testing.T) { - singleFeedConfig.Schedule = wasp.Plain( - cfg.Soak.RPS, - cfg.Soak.Duration.Duration(), - ) - _, err := wasp.NewProfile(). - Add(wasp.NewGenerator(singleFeedConfig)). - Run(true) - require.NoError(t, err) - }) + t.Run("vrfv2 performance test", func(t *testing.T) { - // what are the limits for one "job", figuring out the max/optimal performance params by increasing RPS and varying configuration - t.Run("vrfv2 load test", func(t *testing.T) { - singleFeedConfig.Schedule = wasp.Steps( - cfg.Load.RPSFrom, - cfg.Load.RPSIncrease, - cfg.Load.RPSSteps, - cfg.Load.Duration.Duration(), + singleFeedConfig.Schedule = wasp.Plain( + vrfv2Config.RPS, + vrfv2Config.TestDuration, ) _, err = wasp.NewProfile(). Add(wasp.NewGenerator(singleFeedConfig)). Run(true) require.NoError(t, err) - }) - // how many "jobs" of the same type we can run at once at a stable load with optimal configuration? - t.Run("vrfv2 volume soak test", func(t *testing.T) { - multiFeedConfig.Schedule = wasp.Plain( - cfg.SoakVolume.Products, - cfg.SoakVolume.Duration.Duration(), - ) - _, err = wasp.NewProfile(). - Add(wasp.NewGenerator(multiFeedConfig)). - Run(true) + var wg sync.WaitGroup + wg.Add(1) + //todo - timeout should be configurable depending on the perf test type + requestCount, fulfilmentCount, err := vrfv2_actions.WaitForRequestCountEqualToFulfilmentCount(consumer, 2*time.Minute, &wg) require.NoError(t, err) - }) + wg.Wait() - // what are the limits if we add more and more "jobs/products" of the same type, each "job" have a stable RPS we vary only amount of jobs - t.Run("vrfv2 volume load test", func(t *testing.T) { - multiFeedConfig.Schedule = wasp.Steps( - cfg.LoadVolume.ProductsFrom, - cfg.LoadVolume.ProductsIncrease, - cfg.LoadVolume.ProductsSteps, - cfg.LoadVolume.Duration.Duration(), - ) - _, err = wasp.NewProfile(). - Add(wasp.NewGenerator(multiFeedConfig)). - Run(true) - require.NoError(t, err) + l.Info(). + Interface("Request Count", requestCount). + Interface("Fulfilment Count", fulfilmentCount). + Msg("Final Request/Fulfilment Stats") }) + +} + +func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l zerolog.Logger) error { + if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { + for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { + address := common.HexToAddress(sendingKey) + sendingKeyBalance, err := client.BalanceAt(context.Background(), address) + if err != nil { + return err + } + fundingAtLeast := conversions.EtherToWei(big.NewFloat(cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) + fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) + fundingToSendEth := conversions.WeiToEther(fundingToSendWei) + if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { + l.Info(). + Str("Sending Key", sendingKey). + Str("Sending Key Current Balance", sendingKeyBalance.String()). + Str("Should have at least", fundingAtLeast.String()). + Str("Funding Amount in ETH", fundingToSendEth.String()). + Msg("Funding Node's Sending Key") + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &address, + }) + if err != nil { + return err + } + err = client.Fund(sendingKey, fundingToSendEth, gasEstimates) + if err != nil { + return err + } + } else { + l.Info(). + Str("Sending Key", sendingKey). + Str("Sending Key Current Balance", sendingKeyBalance.String()). + Str("Should have at least", fundingAtLeast.String()). + Msg("Skipping Node's Sending Key funding as it has enough funds") + } + } + } + return nil +} + +func teardown( + t *testing.T, + consumer contracts.VRFv2LoadTestConsumer, + lc *wasp.LokiClient, + updatedLabels map[string]string, + testReporter *testreporters.VRFV2TestReporter, + testType string, + vrfv2Config vrfv2_config.VRFV2Config, +) { + //send final results to Loki + metrics := GetLoadTestMetrics(consumer) + SendMetricsToLoki(metrics, lc, updatedLabels) + //set report data for Slack notification + testReporter.SetReportData( + testType, + metrics.RequestCount, + metrics.FulfilmentCount, + metrics.AverageFulfillmentInMillions, + metrics.SlowestFulfillment, + metrics.FastestFulfillment, + vrfv2Config, + ) + + // send Slack notification + err := testReporter.SendSlackNotification(t, nil) + if err != nil { + log.Warn().Err(err).Msg("Error sending Slack notification") + } } diff --git a/integration-tests/load/vrfv2/vu.go b/integration-tests/load/vrfv2/vu.go deleted file mode 100644 index 7eb02ae330..0000000000 --- a/integration-tests/load/vrfv2/vu.go +++ /dev/null @@ -1,94 +0,0 @@ -package loadvrfv2 - -import ( - "fmt" - "time" - - "github.com/smartcontractkit/wasp" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" - "github.com/smartcontractkit/chainlink/integration-tests/client" -) - -/* JobVolumeVU is a "virtual user" that creates a VRFv2 job and constantly requesting new randomness only for this job instance */ - -type JobVolumeVU struct { - pace time.Duration - minIncomingConfirmations uint16 - nodes []*client.ChainlinkClient - bc blockchain.EVMClient - contracts *vrfv2_actions.VRFV2Contracts - jobs []vrfv2_actions.VRFV2JobInfo - keyHash [32]byte - stop chan struct{} -} - -func NewJobVolumeVU( - pace time.Duration, - confirmations uint16, - nodes []*client.ChainlinkClient, - bc blockchain.EVMClient, - contracts *vrfv2_actions.VRFV2Contracts, -) *JobVolumeVU { - return &JobVolumeVU{ - pace: pace, - minIncomingConfirmations: confirmations, - nodes: nodes, - bc: bc, - contracts: contracts, - stop: make(chan struct{}, 1), - } -} - -func (m *JobVolumeVU) Clone(_ *wasp.Generator) wasp.VirtualUser { - return &JobVolumeVU{ - pace: m.pace, - minIncomingConfirmations: m.minIncomingConfirmations, - nodes: m.nodes, - bc: m.bc, - contracts: m.contracts, - stop: make(chan struct{}, 1), - } -} - -func (m *JobVolumeVU) Setup(_ *wasp.Generator) error { - jobs, err := vrfv2_actions.CreateVRFV2Jobs(m.nodes, m.contracts.Coordinator, m.bc, m.minIncomingConfirmations) - if err != nil { - return fmt.Errorf("failed to create VRFv2 jobs in setup: %w", err) - } - m.jobs = jobs - m.keyHash = jobs[0].KeyHash - return nil -} - -func (m *JobVolumeVU) Teardown(_ *wasp.Generator) error { - return nil -} - -func (m *JobVolumeVU) Call(l *wasp.Generator) { - time.Sleep(m.pace) - tn := time.Now() - err := m.contracts.LoadTestConsumer.RequestRandomness( - m.keyHash, - vrfConst.SubID, - vrfConst.MinimumConfirmations, - vrfConst.CallbackGasLimit, - vrfConst.NumberOfWords, - vrfConst.RandomnessRequestCountPerRequest, - ) - if err != nil { - l.ResponsesChan <- &wasp.CallResult{Duration: time.Since(tn), Error: err.Error(), Failed: true} - return - } - l.ResponsesChan <- &wasp.CallResult{Duration: time.Since(tn)} -} - -func (m *JobVolumeVU) Stop(_ *wasp.Generator) { - m.stop <- struct{}{} -} - -func (m *JobVolumeVU) StopChan() chan struct{} { - return m.stop -} diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 09024b28ba..c7b48fc3a3 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -1,115 +1,107 @@ package smoke import ( + "context" "math/big" "testing" - "time" - "github.com/onsi/gomega" + "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) func TestVRFv2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + var vrfv2Config vrfv2_config.VRFV2Config + err := envconfig.Process("VRFV2", &vrfv2Config) + require.NoError(t, err) + env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). WithCLNodes(1). - WithFunding(vrfConst.ChainlinkNodeFundingAmountEth). + WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). WithStandardCleanup(). Build() - require.NoError(t, err) - env.ParallelTransactions(true) + require.NoError(t, err, "error creating test env") - mockFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfConst.LinkEthFeedResponse) - require.NoError(t, err) - lt, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err) - vrfv2Contracts, err := vrfv2_actions.DeployVRFV2Contracts(env.ContractDeployer, env.EVMClient, lt, mockFeed) - require.NoError(t, err) - - err = env.EVMClient.WaitForEvents() - require.NoError(t, err) - - err = vrfv2Contracts.Coordinator.SetConfig( - vrfConst.MinimumConfirmations, - vrfConst.MaxGasLimitVRFCoordinatorConfig, - vrfConst.StalenessSeconds, - vrfConst.GasAfterPaymentCalculation, - vrfConst.LinkEthFeedResponse, - vrfConst.VRFCoordinatorV2FeeConfig, - ) - require.NoError(t, err) - err = env.EVMClient.WaitForEvents() - require.NoError(t, err) - - err = vrfv2Contracts.Coordinator.CreateSubscription() - require.NoError(t, err) - err = env.EVMClient.WaitForEvents() - require.NoError(t, err) - - err = vrfv2Contracts.Coordinator.AddConsumer(vrfConst.SubID, vrfv2Contracts.LoadTestConsumer.Address()) - require.NoError(t, err) - - err = vrfv2_actions.FundVRFCoordinatorV2Subscription(lt, vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.SubID, vrfConst.VRFSubscriptionFundingAmountLink) - require.NoError(t, err) + env.ParallelTransactions(true) - vrfV2jobs, err := vrfv2_actions.CreateVRFV2Jobs(env.ClCluster.NodeAPIs(), vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.MinimumConfirmations) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) require.NoError(t, err) - - // this part is here because VRFv2 can work with only a specific key - // [[EVM.KeySpecific]] - // Key = '...' - addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() - require.NoError(t, err) - nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(addr), - ) - err = env.ClCluster.Nodes[0].Restart(nodeConfig) + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err) - // test and assert - err = vrfv2Contracts.LoadTestConsumer.RequestRandomness( - vrfV2jobs[0].KeyHash, - vrfConst.SubID, - vrfConst.MinimumConfirmations, - vrfConst.CallbackGasLimit, - vrfConst.NumberOfWords, - vrfConst.RandomnessRequestCountPerRequest, + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( + env, + vrfv2Config, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + 1, + 1, + l, ) - require.NoError(t, err) - - gom := gomega.NewGomegaWithT(t) - timeout := time.Minute * 2 - var lastRequestID *big.Int - gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfV2jobs[0].Job.Data.ID) - g.Expect(err).ShouldNot(gomega.HaveOccurred()) - g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically("==", 1)) - lastRequestID, err = vrfv2Contracts.LoadTestConsumer.GetLastRequestId(testcontext.Get(t)) - l.Debug().Interface("Last Request ID", lastRequestID).Msg("Last Request ID Received") - - g.Expect(err).ShouldNot(gomega.HaveOccurred()) - status, err := vrfv2Contracts.LoadTestConsumer.GetRequestStatus(testcontext.Get(t), lastRequestID) - g.Expect(err).ShouldNot(gomega.HaveOccurred()) - g.Expect(status.Fulfilled).Should(gomega.BeTrue()) - l.Debug().Interface("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - - g.Expect(err).ShouldNot(gomega.HaveOccurred()) + require.NoError(t, err, "error setting up VRF v2 env") + + subID := subIDs[0] + + subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + + t.Run("Request Randomness", func(t *testing.T) { + testConfig := vrfv2Config + subBalanceBeforeRequest := subscription.Balance + + jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2Data.VRFJob.Data.ID) + require.NoError(t, err, "error reading job runs") + + // test and assert + randomWordsFulfilledEvent, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + vrfv2Contracts.LoadTestConsumers[0], + vrfv2Contracts.Coordinator, + vrfv2Data, + subID, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) + subscription, err = vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + require.NoError(t, err, "error getting subscription information") + subBalanceAfterRequest := subscription.Balance + require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) + + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2Data.VRFJob.Data.ID) + require.NoError(t, err, "error reading job runs") + require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) + + status, err := vrfv2Contracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + + require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { - l.Info().Uint64("Output", w.Uint64()).Msg("Randomness fulfilled") - g.Expect(w.Uint64()).Should(gomega.BeNumerically(">", 0), "Expected the VRF job give an answer bigger than 0") + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } - }, timeout, "1s").Should(gomega.Succeed()) + }) } diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index b171ea65f9..9ce9f21699 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -49,7 +49,16 @@ func TestVRFv2Plus(t *testing.T) { // register proving key against oracle address (sending key) in order to test oracleWithdraw defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkToken, mockETHLinkFeed, defaultWalletAddress, 1, 1, l) + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( + env, + vrfv2PlusConfig, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + 1, + 1, + l, + ) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] @@ -380,6 +389,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) require.False(t, pendingRequestsExist, "Pending requests should not exist") + randomWordsFulfilledEventTimeout := 5 * time.Second _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( vrfv2PlusContracts.LoadTestConsumers[0], vrfv2PlusContracts.Coordinator, @@ -388,7 +398,7 @@ func TestVRFv2Plus(t *testing.T) { false, testConfig.RandomnessRequestCountPerRequest, testConfig, - 5*time.Second, + randomWordsFulfilledEventTimeout, l, ) @@ -402,7 +412,7 @@ func TestVRFv2Plus(t *testing.T) { true, testConfig.RandomnessRequestCountPerRequest, testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + randomWordsFulfilledEventTimeout, l, ) @@ -486,7 +496,7 @@ func TestVRFv2Plus(t *testing.T) { Msg("Sub funds returned") //todo - need to use different wallet for each test to verify exact amount of Native/LINK returned - //todo - as defaultWallet is used in other tests in parallel which might affect the balance + //todo - as defaultWallet is used in other tests in parallel which might affect the balance - TT-684 //require.Equal(t, 1, walletBalanceNativeAfterSubCancelling.Cmp(walletBalanceNativeBeforeSubCancelling), "Native funds were not returned after sub cancellation") //todo - this fails on SIMULATED env as tx cost is calculated different as for testnets and it's not receipt.EffectiveGasPrice*receipt.GasUsed diff --git a/integration-tests/testreporters/vrfv2.go b/integration-tests/testreporters/vrfv2.go index c1ab816d4e..2a72e4d91d 100644 --- a/integration-tests/testreporters/vrfv2.go +++ b/integration-tests/testreporters/vrfv2.go @@ -1,173 +1,92 @@ package testreporters import ( - "encoding/csv" "fmt" + "math/big" "os" - "path/filepath" "testing" "time" - "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/slack-go/slack" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" ) -type VRFV2SoakTestReporter struct { - Reports map[string]*VRFV2SoakTestReport // contractAddress: Report - namespace string - csvLocation string -} - -type VRFV2SoakTestReport struct { - ContractAddress string - TotalRounds uint - - averageRoundTime time.Duration - LongestRoundTime time.Duration - ShortestRoundTime time.Duration - totalRoundTimes time.Duration - - averageRoundBlocks uint - LongestRoundBlocks uint - ShortestRoundBlocks uint - totalBlockLengths uint -} - -// SetNamespace sets the namespace of the report for clean reports -func (o *VRFV2SoakTestReporter) SetNamespace(namespace string) { - o.namespace = namespace +type VRFV2TestReporter struct { + TestType string + RequestCount *big.Int + FulfilmentCount *big.Int + AverageFulfillmentInMillions *big.Int + SlowestFulfillment *big.Int + FastestFulfillment *big.Int + Vrfv2Config *vrfv2_config.VRFV2Config } -// WriteReport writes VRFV2 Soak test report to logs -func (o *VRFV2SoakTestReporter) WriteReport(folderLocation string) error { - for _, report := range o.Reports { - report.averageRoundBlocks = report.totalBlockLengths / report.TotalRounds - report.averageRoundTime = time.Duration(report.totalRoundTimes.Nanoseconds() / int64(report.TotalRounds)) - } - if err := o.writeCSV(folderLocation); err != nil { - return err - } - - log.Info().Msg("VRFV2 Soak Test Report") - log.Info().Msg("--------------------") - for contractAddress, report := range o.Reports { - log.Info(). - Str("Contract Address", report.ContractAddress). - Uint("Total Rounds Processed", report.TotalRounds). - Str("Average Round Time", fmt.Sprint(report.averageRoundTime)). - Str("Longest Round Time", fmt.Sprint(report.LongestRoundTime)). - Str("Shortest Round Time", fmt.Sprint(report.ShortestRoundTime)). - Uint("Average Round Blocks", report.averageRoundBlocks). - Uint("Longest Round Blocks", report.LongestRoundBlocks). - Uint("Shortest Round Blocks", report.ShortestRoundBlocks). - Msg(contractAddress) - } - log.Info().Msg("--------------------") - return nil +func (o *VRFV2TestReporter) SetReportData( + testType string, + RequestCount *big.Int, + FulfilmentCount *big.Int, + AverageFulfillmentInMillions *big.Int, + SlowestFulfillment *big.Int, + FastestFulfillment *big.Int, + vrfv2Config vrfv2_config.VRFV2Config, +) { + o.TestType = testType + o.RequestCount = RequestCount + o.FulfilmentCount = FulfilmentCount + o.AverageFulfillmentInMillions = AverageFulfillmentInMillions + o.SlowestFulfillment = SlowestFulfillment + o.FastestFulfillment = FastestFulfillment + o.Vrfv2Config = &vrfv2Config } -// SendNotification sends a slack message to a slack webhook and uploads test artifacts -func (o *VRFV2SoakTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +// SendSlackNotification sends a slack message to a slack webhook +func (o *VRFV2TestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { if slackClient == nil { slackClient = slack.New(testreporters.SlackAPIKey) } testFailed := t.Failed() - headerText := ":white_check_mark: VRFV2 Soak Test PASSED :white_check_mark:" + headerText := fmt.Sprintf(":white_check_mark: VRF V2 %s Test PASSED :white_check_mark:", o.TestType) if testFailed { - headerText = ":x: VRFV2 Soak Test FAILED :x:" - } - messageBlocks := testreporters.CommonSlackNotificationBlocks( - headerText, o.namespace, o.csvLocation, - ) - ts, err := testreporters.SendSlackMessage(slackClient, slack.MsgOptionBlocks(messageBlocks...)) - if err != nil { - return err + headerText = fmt.Sprintf(":x: VRF V2 %s Test FAILED :x:", o.TestType) } - return testreporters.UploadSlackFile(slackClient, slack.FileUploadParameters{ - Title: fmt.Sprintf("VRFV2 Soak Test Report %s", o.namespace), - Filetype: "csv", - Filename: fmt.Sprintf("vrfv2_soak_%s.csv", o.namespace), - File: o.csvLocation, - InitialComment: fmt.Sprintf("VRFV2 Soak Test Report %s.", o.namespace), - Channels: []string{testreporters.SlackChannel}, - ThreadTimestamp: ts, + messageBlocks := testreporters.SlackNotifyBlocks(headerText, os.Getenv("SELECTED_NETWORKS"), []string{ + fmt.Sprintf( + "Summary\n"+ + "Perf Test Type: %s\n"+ + "Test Duration set in parameters: %s\n"+ + "Use Existing Env: %t\n"+ + "Request Count: %s\n"+ + "Fulfilment Count: %s\n"+ + "AverageFulfillmentInMillions: %s\n"+ + "Slowest Fulfillment: %s\n"+ + "Fastest Fulfillment: %s \n"+ + "RPS: %d\n"+ + "RateLimitUnitDuration: %s\n"+ + "RandomnessRequestCountPerRequest: %d\n"+ + "RandomnessRequestCountPerRequestDeviation: %d\n", + o.TestType, + o.Vrfv2Config.TestDuration.Truncate(time.Second).String(), + o.Vrfv2Config.UseExistingEnv, + o.RequestCount.String(), + o.FulfilmentCount.String(), + o.AverageFulfillmentInMillions.String(), + o.SlowestFulfillment.String(), + o.FastestFulfillment.String(), + o.Vrfv2Config.RPS, + o.Vrfv2Config.RateLimitUnitDuration.String(), + o.Vrfv2Config.RandomnessRequestCountPerRequest, + o.Vrfv2Config.RandomnessRequestCountPerRequestDeviation, + ), }) -} - -// UpdateReport updates the report based on the latest info -func (o *VRFV2SoakTestReport) UpdateReport(roundTime time.Duration, blockLength uint) { - // Updates min values from default 0 - if o.ShortestRoundBlocks == 0 { - o.ShortestRoundBlocks = blockLength - } - if o.ShortestRoundTime == 0 { - o.ShortestRoundTime = roundTime - } - o.TotalRounds++ - o.totalRoundTimes += roundTime - o.totalBlockLengths += blockLength - if roundTime >= o.LongestRoundTime { - o.LongestRoundTime = roundTime - } - if roundTime <= o.ShortestRoundTime { - o.ShortestRoundTime = roundTime - } - if blockLength >= o.LongestRoundBlocks { - o.LongestRoundBlocks = blockLength - } - if blockLength <= o.ShortestRoundBlocks { - o.ShortestRoundBlocks = blockLength - } -} - -// writes a CSV report on the test runner -func (o *VRFV2SoakTestReporter) writeCSV(folderLocation string) error { - reportLocation := filepath.Join(folderLocation, "./vrfv2_soak_report.csv") - log.Debug().Str("Location", reportLocation).Msg("Writing VRFV2 report") - o.csvLocation = reportLocation - vrfv2ReportFile, err := os.Create(reportLocation) - if err != nil { - return err - } - defer vrfv2ReportFile.Close() - vrfv2ReportWriter := csv.NewWriter(vrfv2ReportFile) - err = vrfv2ReportWriter.Write([]string{ - "Contract Index", - "Contract Address", - "Total Rounds Processed", - "Average Round Time", - "Longest Round Time", - "Shortest Round Time", - "Average Round Blocks", - "Longest Round Blocks", - "Shortest Round Blocks", - }) + _, err := testreporters.SendSlackMessage(slackClient, slack.MsgOptionBlocks(messageBlocks...)) if err != nil { return err } - for contractIndex, report := range o.Reports { - err = vrfv2ReportWriter.Write([]string{ - fmt.Sprint(contractIndex), - report.ContractAddress, - fmt.Sprint(report.TotalRounds), - fmt.Sprint(report.averageRoundTime), - fmt.Sprint(report.LongestRoundTime), - fmt.Sprint(report.ShortestRoundTime), - fmt.Sprint(report.averageRoundBlocks), - fmt.Sprint(report.LongestRoundBlocks), - fmt.Sprint(report.ShortestRoundBlocks), - }) - if err != nil { - return err - } - } - vrfv2ReportWriter.Flush() - - log.Info().Str("Location", reportLocation).Msg("Wrote CSV file") return nil } diff --git a/integration-tests/testreporters/vrfv2plus.go b/integration-tests/testreporters/vrfv2plus.go index 38220ca882..21e4e52695 100644 --- a/integration-tests/testreporters/vrfv2plus.go +++ b/integration-tests/testreporters/vrfv2plus.go @@ -49,9 +49,9 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient } testFailed := t.Failed() - headerText := fmt.Sprintf(":white_check_mark: VRF %s Test PASSED :white_check_mark:", o.TestType) + headerText := fmt.Sprintf(":white_check_mark: VRF V2 Plus %s Test PASSED :white_check_mark:", o.TestType) if testFailed { - headerText = fmt.Sprintf(":x: VRF %s Test FAILED :x:", o.TestType) + headerText = fmt.Sprintf(":x: VRF V2 Plus %s Test FAILED :x:", o.TestType) } messageBlocks := testreporters.SlackNotifyBlocks(headerText, os.Getenv("SELECTED_NETWORKS"), []string{ diff --git a/integration-tests/testsetups/vrfv2.go b/integration-tests/testsetups/vrfv2.go deleted file mode 100644 index ef18bd267d..0000000000 --- a/integration-tests/testsetups/vrfv2.go +++ /dev/null @@ -1,204 +0,0 @@ -package testsetups - -//revive:disable:dot-imports -import ( - "context" - "fmt" - "math/big" - "os" - "strconv" - "strings" - "testing" - "time" - - "github.com/rs/zerolog/log" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" -) - -// VRFV2SoakTest defines a typical VRFV2 soak test -type VRFV2SoakTest struct { - Inputs *VRFV2SoakTestInputs - - TestReporter testreporters.VRFV2SoakTestReporter - - testEnvironment *environment.Environment - namespace string - ChainlinkNodes []*client.ChainlinkK8sClient - chainClient blockchain.EVMClient - DefaultNetwork blockchain.EVMClient - - NumberOfRandRequests int - - ErrorOccurred error - ErrorCount int -} - -// VRFV2SoakTestTestFunc function type for the request and validation you want done on each iteration -type VRFV2SoakTestTestFunc func(t *VRFV2SoakTest, requestNumber int) error - -// VRFV2SoakTestInputs define required inputs to run a vrfv2 soak test -type VRFV2SoakTestInputs struct { - BlockchainClient blockchain.EVMClient // Client for the test to connect to the blockchain with - TestDuration time.Duration `envconfig:"TEST_DURATION" default:"15m"` // How long to run the test for (assuming things pass) - ChainlinkNodeFunding *big.Float `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of ETH to fund each chainlink node with - SubscriptionFunding *big.Int `envconfig:"SUBSCRIPTION_FUNDING" default:"100"` // Amount of Link to fund VRF Coordinator subscription - StopTestOnError bool // Do we want the test to stop after any error or just continue on - - RequestsPerMinute int `envconfig:"REQUESTS_PER_MINUTE" default:"10"` // Number of requests for randomness per minute - RandomnessRequestCountPerRequest int `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` - ConsumerContract contracts.VRFv2LoadTestConsumer - TestFunc VRFV2SoakTestTestFunc // The function that makes the request and validations wanted -} - -// NewVRFV2SoakTest creates a new vrfv2 soak test to setup and run -func NewVRFV2SoakTest(inputs *VRFV2SoakTestInputs, chainlinkNodes []*client.ChainlinkK8sClient) *VRFV2SoakTest { - return &VRFV2SoakTest{ - Inputs: inputs, - TestReporter: testreporters.VRFV2SoakTestReporter{ - Reports: make(map[string]*testreporters.VRFV2SoakTestReport), - }, - ChainlinkNodes: chainlinkNodes, - } -} - -// Setup sets up the test environment -func (v *VRFV2SoakTest) Setup(t *testing.T, env *environment.Environment) { - v.ensureInputValues(t) - v.testEnvironment = env - v.namespace = v.testEnvironment.Cfg.Namespace - v.chainClient.ParallelTransactions(true) -} - -// Run starts the VRFV2 soak test -func (v *VRFV2SoakTest) Run(t *testing.T) { - l := logging.GetTestLogger(t) - l.Info(). - Str("Test Duration", v.Inputs.TestDuration.Truncate(time.Second).String()). - Int("Max number of requests per minute wanted", v.Inputs.RequestsPerMinute). - Msg("Starting VRFV2 Soak Test") - - // set the requests to only run for a certain amount of time - ctx := testcontext.Get(t) - testContext, testCancel := context.WithTimeout(ctx, v.Inputs.TestDuration) - defer testCancel() - - v.NumberOfRandRequests = 0 - - // variables dealing with how often to tick and how to stop the ticker - stop := false - startTime := time.Now() - ticker := time.NewTicker(time.Minute / time.Duration(v.Inputs.RequestsPerMinute)) - - for { - // start the loop by checking to see if any of the TestFunc responses have returned an error - if v.Inputs.StopTestOnError { - require.NoError(t, v.ErrorOccurred, "Found error") - } - select { - case <-testContext.Done(): - // stop making requests - stop = true - ticker.Stop() - break // breaks the select block - case <-ticker.C: - // make the next request - v.NumberOfRandRequests++ - go requestAndValidate(v, v.NumberOfRandRequests) - } - if stop { - break // breaks the for loop and stops the test - } - } - - err := v.chainClient.WaitForEvents() - if err != nil { - l.Error().Err(err).Msg("Error Occurred waiting for On chain events") - } - //wait some buffer time for requests to be fulfilled - //todo - need to find better way for this - time.Sleep(1 * time.Minute) - - loadTestMetrics, err := v.Inputs.ConsumerContract.GetLoadTestMetrics(ctx) - if err != nil { - l.Error().Err(err).Msg("Error Occurred when getting Load Test Metrics from Consumer contract") - } - - averageFulfillmentInBlockTime := new(big.Float).Quo(new(big.Float).SetInt(loadTestMetrics.AverageFulfillmentInMillions), big.NewFloat(1e6)) - - l.Info().Int("Requests", v.NumberOfRandRequests).Msg("Total Completed Requests calculated from Test") - l.Info().Uint64("Requests", loadTestMetrics.RequestCount.Uint64()).Msg("Total Completed Requests calculated from Contract") - l.Info().Uint64("Fulfilments", loadTestMetrics.FulfilmentCount.Uint64()).Msg("Total Completed Fulfilments") - l.Info().Uint64("Fastest Fulfilment", loadTestMetrics.FastestFulfillment.Uint64()).Msg("Fastest Fulfilment") - l.Info().Uint64("Slowest Fulfilment", loadTestMetrics.SlowestFulfillment.Uint64()).Msg("Slowest Fulfilment") - l.Info().Interface("Average Fulfillment", averageFulfillmentInBlockTime).Msg("Average Fulfillment In Block Time") - - //todo - need to calculate 95th percentile response time in Block time and calculate how many requests breached 256 block time requirement - - l.Info().Str("Run Time", time.Since(startTime).String()).Msg("Finished VRFV2 Soak Test Requests") - require.Equal(t, 0, v.ErrorCount, "Expected 0 errors") - require.Equal(t, loadTestMetrics.RequestCount.Uint64(), loadTestMetrics.FulfilmentCount.Uint64(), "Number of Rand Requests should be equal to Number of Fulfillments") -} - -func requestAndValidate(t *VRFV2SoakTest, requestNumber int) { - - log.Info().Int("Request Number", requestNumber).Msg("Making a Request") - err := t.Inputs.TestFunc(t, requestNumber) - - // only set the error to be checked if err is not nil so we avoid race conditions with passing requests - if err != nil { - t.ErrorOccurred = err - log.Error().Err(err).Msg("Error Occurred during test") - t.ErrorCount++ - } -} - -// Networks returns the networks that the test is running on -func (v *VRFV2SoakTest) TearDownVals(t *testing.T) ( - *testing.T, - string, - []*client.ChainlinkK8sClient, - reportModel.TestReporter, - blockchain.EVMClient, -) { - return t, v.namespace, v.ChainlinkNodes, &v.TestReporter, v.chainClient -} - -// ensureValues ensures that all values needed to run the test are present -func (v *VRFV2SoakTest) ensureInputValues(t *testing.T) { - inputs := v.Inputs - require.NotNil(t, inputs.BlockchainClient, "Need a valid blockchain client for the test") - v.chainClient = inputs.BlockchainClient - require.GreaterOrEqual(t, inputs.RequestsPerMinute, 1, "Expecting at least 1 request per minute") - chainlinkNodeFunding, _ := inputs.ChainlinkNodeFunding.Float64() - subscriptionFunding := inputs.SubscriptionFunding.Int64() - require.Greater(t, chainlinkNodeFunding, float64(0), "Need some amount of funding for Chainlink nodes") - require.Greater(t, subscriptionFunding, int64(0), "Need some amount of funding for VRF V2 Coordinator Subscription nodes") - require.GreaterOrEqual(t, inputs.TestDuration, time.Minute, "Test duration should be longer than 1 minute") - require.NotNil(t, inputs.TestFunc, "Expected there to be test to run") -} - -func (i VRFV2SoakTestInputs) SetForRemoteRunner() { - os.Setenv("TEST_VRFV2_TEST_DURATION", i.TestDuration.String()) - os.Setenv("TEST_VRFV2_CHAINLINK_NODE_FUNDING", i.ChainlinkNodeFunding.String()) - os.Setenv("TEST_VRFV2_SUBSCRIPTION_FUNDING", i.SubscriptionFunding.String()) - os.Setenv("TEST_VRFV2_REQUESTS_PER_MINUTE", strconv.Itoa(i.RequestsPerMinute)) - os.Setenv("TEST_VRFV2_RANDOMNESS_REQUEST_COUNT_PER_REQUEST", strconv.Itoa(i.RandomnessRequestCountPerRequest)) - - selectedNetworks := strings.Split(os.Getenv("SELECTED_NETWORKS"), ",") - for _, networkPrefix := range selectedNetworks { - urlEnv := fmt.Sprintf("%s_URLS", networkPrefix) - httpEnv := fmt.Sprintf("%s_HTTP_URLS", networkPrefix) - os.Setenv(fmt.Sprintf("TEST_%s", urlEnv), os.Getenv(urlEnv)) - os.Setenv(fmt.Sprintf("TEST_%s", httpEnv), os.Getenv(httpEnv)) - } -} diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index b7f2b316aa..47bc8e8cc1 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -23,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/config" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) @@ -224,8 +223,8 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { } } -func WithVRFv2EVMEstimator(addr string) NodeConfigOpt { - est := assets.GWei(vrfv2_constants.MaxGasPriceGWei) +func WithVRFv2EVMEstimator(addr string, maxGasPriceGWei int64) NodeConfigOpt { + est := assets.GWei(maxGasPriceGWei) return func(c *chainlink.Config) { c.EVM[0].KeySpecific = evmcfg.KeySpecificConfig{ { From 853a6170a9cb4ef8cc81e09b4ae6d3b4f6068731 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:20:24 +0100 Subject: [PATCH 196/327] BCF-2666 Add randomisation to testdb sequenced table columns (#11312) * Add randomisation to testdb sequenced table columns * Fix wrong import in pgtest.go * Move testdb sequence randomisation to shell testdb prepare * Use crypto random instead of math rand in test db alter sequences * Satisfy linter * Fix randomiseTestDBSequences err messages * Change randomiseTestDBSequences err msg * Add Error suffix to failedToRandomiseTestDBSequences custom err * Exclude unrelated tables from test db seq randomisation just in case * Rename randomiseTestDBSequences to randomizeTestDBSequences --- core/cmd/shell_local.go | 52 ++++++++++++++++++++++-- core/internal/testutils/pgtest/pgtest.go | 1 - 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index cbd0feccbf..ada70736f4 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -2,6 +2,7 @@ package cmd import ( "context" + crand "crypto/rand" "database/sql" "fmt" "log" @@ -778,11 +779,13 @@ func (s *Shell) PrepareTestDatabase(c *cli.Context) error { if userOnly { fixturePath = "../store/fixtures/users_only_fixture.sql" } - if err := insertFixtures(dbUrl, fixturePath); err != nil { + if err = insertFixtures(dbUrl, fixturePath); err != nil { return s.errorOut(err) } - - return s.errorOut(dropDanglingTestDBs(s.Logger, db)) + if err = dropDanglingTestDBs(s.Logger, db); err != nil { + return s.errorOut(err) + } + return s.errorOut(randomizeTestDBSequences(db)) } func dropDanglingTestDBs(lggr logger.Logger, db *sqlx.DB) (err error) { @@ -822,6 +825,49 @@ func dropDanglingTestDBs(lggr logger.Logger, db *sqlx.DB) (err error) { return } +type failedToRandomizeTestDBSequencesError struct{} + +func (m *failedToRandomizeTestDBSequencesError) Error() string { + return "failed to randomize test db sequences" +} + +// randomizeTestDBSequences randomizes sequenced table columns sequence +// This is necessary as to avoid false positives in some test cases. +func randomizeTestDBSequences(db *sqlx.DB) error { + seqRows, err := db.Query(`SELECT sequence_schema, sequence_name FROM information_schema.sequences WHERE sequence_schema = $1`, "public") + if err != nil { + return fmt.Errorf("%s: error fetching sequences: %s", failedToRandomizeTestDBSequencesError{}, err) + } + + defer seqRows.Close() + for seqRows.Next() { + var sequenceSchema, sequenceName string + if err = seqRows.Scan(&sequenceSchema, &sequenceName); err != nil { + return fmt.Errorf("%s: failed scanning sequence rows: %s", failedToRandomizeTestDBSequencesError{}, err) + } + + if sequenceName == "goose_migrations_id_seq" || sequenceName == "configurations_id_seq" { + continue + } + + var randNum *big.Int + randNum, err = crand.Int(crand.Reader, utils.NewBigI(10000).ToInt()) + if err != nil { + return fmt.Errorf("%s: failed to generate random number", failedToRandomizeTestDBSequencesError{}) + } + + if _, err = db.Exec(fmt.Sprintf("ALTER SEQUENCE %s.%s RESTART WITH %d", sequenceSchema, sequenceName, randNum)); err != nil { + return fmt.Errorf("%s: failed to alter and restart %s sequence: %w", failedToRandomizeTestDBSequencesError{}, sequenceName, err) + } + } + + if err = seqRows.Err(); err != nil { + return fmt.Errorf("%s: failed to iterate through sequences: %w", failedToRandomizeTestDBSequencesError{}, err) + } + + return nil +} + // PrepareTestDatabaseUserOnly calls ResetDatabase then loads only user fixtures required for local // testing against testnets. Does not include fake chain fixtures. func (s *Shell) PrepareTestDatabaseUserOnly(c *cli.Context) error { diff --git a/core/internal/testutils/pgtest/pgtest.go b/core/internal/testutils/pgtest/pgtest.go index 1900fcc62b..01024b39c3 100644 --- a/core/internal/testutils/pgtest/pgtest.go +++ b/core/internal/testutils/pgtest/pgtest.go @@ -34,7 +34,6 @@ func NewSqlxDB(t testing.TB) *sqlx.DB { db, err := sqlx.Open(string(dialects.TransactionWrappedPostgres), uuid.New().String()) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, db.Close()) }) - db.MapperFunc(reflectx.CamelToSnakeASCII) return db From ec7c8c9fa7e6865651db624d73f399592ad03592 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Fri, 24 Nov 2023 17:48:52 +0200 Subject: [PATCH 197/327] VRF-765: make optional to cancel subs after test run for VRF WASP tests (#11379) --- integration-tests/load/vrfv2/config.go | 3 +- integration-tests/load/vrfv2/config.toml | 19 +-- integration-tests/load/vrfv2/vrfv2_test.go | 57 +++++---- integration-tests/load/vrfv2plus/config.go | 11 +- integration-tests/load/vrfv2plus/config.toml | 28 +++-- .../load/vrfv2plus/vrfv2plus_test.go | 108 +++++++++++++----- 6 files changed, 142 insertions(+), 84 deletions(-) diff --git a/integration-tests/load/vrfv2/config.go b/integration-tests/load/vrfv2/config.go index e23294e839..d5e94bb75f 100644 --- a/integration-tests/load/vrfv2/config.go +++ b/integration-tests/load/vrfv2/config.go @@ -52,7 +52,8 @@ type NewEnvConfig struct { } type Common struct { - MinimumConfirmations uint16 `toml:"minimum_confirmations"` + MinimumConfirmations uint16 `toml:"minimum_confirmations"` + CancelSubsAfterTestRun bool `toml:"cancel_subs_after_test_run"` } type Funding struct { diff --git a/integration-tests/load/vrfv2/config.toml b/integration-tests/load/vrfv2/config.toml index 4e82ec7aeb..6f54d1ec99 100644 --- a/integration-tests/load/vrfv2/config.toml +++ b/integration-tests/load/vrfv2/config.toml @@ -1,20 +1,21 @@ [Common] minimum_confirmations = 3 +cancel_subs_after_test_run = true [NewEnvConfig] -sub_funds_link = 1 -node_sending_key_funding = 10 +sub_funds_link = 1000 +node_sending_key_funding = 1000 [ExistingEnvConfig] -coordinator_address = "0x50d47e4142598E3411aA864e08a44284e471AC6f" -#consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" -#sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" -key_hash = "0x027f94ff1465b3525f9fc03e9ff7d6d2c0953482246dd6ae07570c45d6631414" +coordinator_address = "" +consumer_address = "" +sub_id = 1 +key_hash = "" create_fund_subs_and_add_consumers = true -link_address = "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E" -sub_funds_link = 3 -node_sending_key_funding_min = 2 +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 node_sending_keys = [ "", "", diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 37a7044289..8e74e3aa90 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -97,25 +97,9 @@ func TestVRFV2Performance(t *testing.T) { Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - //cancel subs and return funds to sub owner - for _, subID := range subIDs { - l.Info(). - Uint64("Returning funds from SubID", subID). - Str("Returning funds to", eoaWalletAddress). - Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfv2Contracts.Coordinator.PendingRequestsExist(context.Background(), subID) - if err != nil { - l.Error().Err(err).Msg("Error checking if pending requests exist") - } - if !pendingRequestsExist { - _, err := vrfv2Contracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) - if err != nil { - l.Error().Err(err).Msg("Error canceling subscription") - } - } else { - l.Error().Uint64("Sub ID", subID).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") - } - + if cfg.Common.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + cancelSubsAndReturnFunds(subIDs, l) } } }). @@ -186,18 +170,10 @@ func TestVRFV2Performance(t *testing.T) { Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - for _, subID := range subIDs { - l.Info(). - Uint64("Returning funds from SubID", subID). - Str("Returning funds to", eoaWalletAddress). - Msg("Canceling subscription and returning funds to subscription owner") - _, err := vrfv2Contracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) - if err != nil { - l.Error().Err(err).Msg("Error canceling subscription") - } + if cfg.Common.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + cancelSubsAndReturnFunds(subIDs, l) } - //err = vrfv2.ReturnFundsForFulfilledRequests(env.EVMClient, vrfv2Contracts.Coordinator, l) - //l.Error().Err(err).Msg("Error returning funds for fulfilled requests") } if err := env.Cleanup(); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") @@ -287,6 +263,27 @@ func TestVRFV2Performance(t *testing.T) { } +func cancelSubsAndReturnFunds(subIDs []uint64, l zerolog.Logger) { + for _, subID := range subIDs { + l.Info(). + Uint64("Returning funds from SubID", subID). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + pendingRequestsExist, err := vrfv2Contracts.Coordinator.PendingRequestsExist(context.Background(), subID) + if err != nil { + l.Error().Err(err).Msg("Error checking if pending requests exist") + } + if !pendingRequestsExist { + _, err := vrfv2Contracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } else { + l.Error().Uint64("Sub ID", subID).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") + } + } +} + func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l zerolog.Logger) error { if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index 96dbf99c6b..43bcf44d04 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -41,8 +41,9 @@ type ExistingEnvConfig struct { LinkAddress string `toml:"link_address"` SubID string `toml:"sub_id"` KeyHash string `toml:"key_hash"` - SubFunding - CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` + Funding + CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` + NodeSendingKeys []string `toml:"node_sending_keys"` } type NewEnvConfig struct { @@ -50,12 +51,14 @@ type NewEnvConfig struct { } type Common struct { - MinimumConfirmations uint16 `toml:"minimum_confirmations"` + MinimumConfirmations uint16 `toml:"minimum_confirmations"` + CancelSubsAfterTestRun bool `toml:"cancel_subs_after_test_run"` } type Funding struct { - NodeFunds float64 `toml:"node_funds"` SubFunding + NodeSendingKeyFunding float64 `toml:"node_sending_key_funding"` + NodeSendingKeyFundingMin float64 `toml:"node_sending_key_funding_min"` } type SubFunding struct { diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml index e3200fafe2..8ccf60c6d8 100644 --- a/integration-tests/load/vrfv2plus/config.toml +++ b/integration-tests/load/vrfv2plus/config.toml @@ -1,21 +1,31 @@ [Common] minimum_confirmations = 3 +cancel_subs_after_test_run = true [NewEnvConfig] sub_funds_link = 1 sub_funds_native = 1 node_funds = 10 +node_sending_key_funding = 1000 [ExistingEnvConfig] -coordinator_address = "0x27b61f155F772b291D1d9B478BeAd37B2Ae447b0" -#consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" -#sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" -key_hash = "0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae" +coordinator_address = "" +consumer_address = "" +sub_id = 1 +key_hash = "" create_fund_subs_and_add_consumers = true -link_address = "0x779877A7B0D9E8603169DdbD7836e478b4624789" -sub_funds_link = 3 -sub_funds_native = 1 +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [ + "", + "", + "", + "", + "", + "", +] # 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds [Soak] @@ -25,7 +35,7 @@ randomness_request_count_per_request = 1 # amount of randomness requests to make randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting number_of_sub_to_create = 1 -# approx 60 RPM - 1 tx request with 4 rand requests in each tx every 3 seconds +# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds [Load] rate_limit_unit_duration = "3s" rps = 1 @@ -47,4 +57,4 @@ rate_limit_unit_duration = "1m" rps = 1 randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 \ No newline at end of file +number_of_sub_to_create = 1 diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 11e160297f..ac22b5256f 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -1,19 +1,24 @@ package loadvrfv2plus import ( + "context" "math/big" "os" "sync" "testing" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" @@ -93,25 +98,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - //cancel subs and return funds to sub owner - for _, subID := range subIDs { - l.Info(). - Str("Returning funds from SubID", subID.String()). - Str("Returning funds to", eoaWalletAddress). - Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subID) - if err != nil { - l.Error().Err(err).Msg("Error checking if pending requests exist") - } - if !pendingRequestsExist { - _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) - if err != nil { - l.Error().Err(err).Msg("Error canceling subscription") - } - } else { - l.Error().Str("Sub ID", subID.String()).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") - } - + if cfg.Common.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + cancelSubsAndReturnFunds(subIDs, l) } } }). @@ -147,6 +136,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { subIDs = append(subIDs, subID) } + err = FundNodesIfNeeded(cfg, env.EVMClient, l) + require.NoError(t, err) + vrfv2PlusContracts = &vrfv2plus.VRFV2_5Contracts{ Coordinator: coordinator, LoadTestConsumers: consumers, @@ -166,7 +158,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { } else { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2PlusConfig.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeFunds + vrfv2PlusConfig.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeSendingKeyFunding vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.NewEnvConfig.Funding.SubFundsNative env, err = test_env.NewCLTestEnvBuilder(). @@ -183,18 +175,10 @@ func TestVRFV2PlusPerformance(t *testing.T) { Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - for _, subID := range subIDs { - l.Info(). - Str("Returning funds from SubID", subID.String()). - Str("Returning funds to", eoaWalletAddress). - Msg("Canceling subscription and returning funds to subscription owner") - _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) - if err != nil { - l.Error().Err(err).Msg("Error canceling subscription") - } + if cfg.Common.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + cancelSubsAndReturnFunds(subIDs, l) } - //err = vrfv2plus.ReturnFundsForFulfilledRequests(env.EVMClient, vrfv2PlusContracts.Coordinator, l) - //l.Error().Err(err).Msg("Error returning funds for fulfilled requests") } if err := env.Cleanup(); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") @@ -281,6 +265,68 @@ func TestVRFV2PlusPerformance(t *testing.T) { Interface("Fulfilment Count", fulfilmentCount). Msg("Final Request/Fulfilment Stats") }) + +} + +func cancelSubsAndReturnFunds(subIDs []*big.Int, l zerolog.Logger) { + for _, subID := range subIDs { + l.Info(). + Str("Returning funds from SubID", subID.String()). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subID) + if err != nil { + l.Error().Err(err).Msg("Error checking if pending requests exist") + } + if !pendingRequestsExist { + _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } else { + l.Error().Str("Sub ID", subID.String()).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") + } + } +} + +func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l zerolog.Logger) error { + if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { + for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { + address := common.HexToAddress(sendingKey) + sendingKeyBalance, err := client.BalanceAt(context.Background(), address) + if err != nil { + return err + } + fundingAtLeast := conversions.EtherToWei(big.NewFloat(cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) + fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) + fundingToSendEth := conversions.WeiToEther(fundingToSendWei) + if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { + l.Info(). + Str("Sending Key", sendingKey). + Str("Sending Key Current Balance", sendingKeyBalance.String()). + Str("Should have at least", fundingAtLeast.String()). + Str("Funding Amount in ETH", fundingToSendEth.String()). + Msg("Funding Node's Sending Key") + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &address, + }) + if err != nil { + return err + } + err = client.Fund(sendingKey, fundingToSendEth, gasEstimates) + if err != nil { + return err + } + } else { + l.Info(). + Str("Sending Key", sendingKey). + Str("Sending Key Current Balance", sendingKeyBalance.String()). + Str("Should have at least", fundingAtLeast.String()). + Msg("Skipping Node's Sending Key funding as it has enough funds") + } + } + } + return nil } func teardown( From b87f21eff26d1ee4f7f709ecc41580e83edd1de0 Mon Sep 17 00:00:00 2001 From: Dmytro Haidashenko <34754799+dhaidashenko@users.noreply.github.com> Date: Mon, 27 Nov 2023 14:12:58 +0100 Subject: [PATCH 198/327] Call proper loop for outOfSyncLoop exist on close test (#11384) --- core/chains/evm/client/node_lifecycle_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/chains/evm/client/node_lifecycle_test.go b/core/chains/evm/client/node_lifecycle_test.go index 9fdd9bb64e..05b8af13ec 100644 --- a/core/chains/evm/client/node_lifecycle_test.go +++ b/core/chains/evm/client/node_lifecycle_test.go @@ -521,7 +521,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { n.wg.Add(1) go func() { defer close(ch) - n.aliveLoop() + n.outOfSyncLoop(func(num int64, td *utils.Big) bool { return false }) }() assert.NoError(t, n.Close()) testutils.WaitWithTimeout(t, ch, "expected outOfSyncLoop to exit") From 9686592f6876890545841f6e740a875eec8d1338 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Mon, 27 Nov 2023 15:58:36 +0200 Subject: [PATCH 199/327] =?UTF-8?q?VRF-543:=20add=20test=20for=20verifying?= =?UTF-8?q?=20round=20robin=20for=20multiple=20sending=20keys=E2=80=A6=20(?= =?UTF-8?q?#11382)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-543: add test for verifying round robin for multiple sending keys in VRF v2 and VRF V2 Plus * VRF-543: fixing lint issue --- integration-tests/actions/actions.go | 23 ++++ .../actions/vrfv2_actions/vrfv2_steps.go | 45 +++++-- .../actions/vrfv2plus/vrfv2plus_steps.go | 42 +++++-- .../contracts/contract_vrf_models.go | 2 +- .../contracts/ethereum_vrfv2_contracts.go | 15 ++- integration-tests/go.mod | 2 +- integration-tests/load/vrfv2/vrfv2_test.go | 10 +- .../load/vrfv2plus/vrfv2plus_test.go | 1 + integration-tests/smoke/vrfv2_test.go | 93 +++++++++++++++ integration-tests/smoke/vrfv2plus_test.go | 111 +++++++++++++++++- integration-tests/types/config/node/core.go | 22 ++-- 11 files changed, 318 insertions(+), 48 deletions(-) diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 438c36a9f0..624df39c47 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum" @@ -458,3 +459,25 @@ func GenerateWallet() (common.Address, error) { } return crypto.PubkeyToAddress(*publicKeyECDSA), nil } + +// todo - move to CTF +func FundAddress(client blockchain.EVMClient, sendingKey string, fundingToSendEth *big.Float) error { + address := common.HexToAddress(sendingKey) + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &address, + }) + if err != nil { + return err + } + err = client.Fund(sendingKey, fundingToSendEth, gasEstimates) + if err != nil { + return err + } + return nil +} + +// todo - move to CTF +func GetTxFromAddress(tx *types.Transaction) (string, error) { + from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx) + return from.String(), err +} diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go index f565af26d9..4ea4a4a853 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go @@ -29,6 +29,7 @@ import ( var ( ErrNodePrimaryKey = "error getting node's primary ETH key" + ErrNodeNewTxKey = "error creating node's EVM transaction key" ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" ErrRegisterProvingKey = "error registering proving keys" @@ -105,7 +106,7 @@ func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinat func CreateVRFV2Job( chainlinkNode *client.ChainlinkClient, coordinatorAddress string, - nativeTokenPrimaryKeyAddress string, + nativeTokenKeyAddresses []string, pubKeyCompressed string, chainID string, minIncomingConfirmations uint16, @@ -122,7 +123,7 @@ func CreateVRFV2Job( job, err := chainlinkNode.MustCreateJob(&client.VRFV2JobSpec{ Name: fmt.Sprintf("vrf-v2-%s", jobUUID), CoordinatorAddress: coordinatorAddress, - FromAddresses: []string{nativeTokenPrimaryKeyAddress}, + FromAddresses: nativeTokenKeyAddresses, EVMChainID: chainID, MinIncomingConfirmations: int(minIncomingConfirmations), PublicKey: pubKeyCompressed, @@ -181,6 +182,7 @@ func SetupVRFV2Environment( linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, registerProvingKeyAgainstAddress string, + numberOfTxKeysToCreate int, numberOfConsumers int, numberOfSubToCreate int, l zerolog.Logger, @@ -254,17 +256,21 @@ func SetupVRFV2Environment( } chainID := env.EVMClient.GetChainID() - + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2Config, numberOfTxKeysToCreate, chainID) + if err != nil { + return nil, nil, nil, err + } nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) } + allNativeTokenKeyAddresses := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) l.Info().Msg("Creating VRFV2 Job") vrfV2job, err := CreateVRFV2Job( env.ClCluster.NodeAPIs()[0], vrfv2Contracts.Coordinator.Address(), - nativeTokenPrimaryKeyAddress, + allNativeTokenKeyAddresses, pubKeyCompressed, chainID.String(), vrfv2Config.MinimumConfirmations, @@ -276,12 +282,8 @@ func SetupVRFV2Environment( // this part is here because VRFv2 can work with only a specific key // [[EVM.KeySpecific]] // Key = '...' - addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrGetPrimaryKey, err) - } nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(addr, vrfv2Config.CLNodeMaxGasPriceGWei), + node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, vrfv2Config.CLNodeMaxGasPriceGWei), ) l.Info().Msg("Restarting Node with new sending key PriceMax configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) @@ -306,6 +308,25 @@ func SetupVRFV2Environment( return vrfv2Contracts, subIDs, &data, nil } +func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2Config vrfv2_config.VRFV2Config, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { + var newNativeTokenKeyAddresses []string + for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { + newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrNodeNewTxKey, err) + } + if response.StatusCode != 200 { + return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) + } + newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) + err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(vrfv2Config.ChainlinkNodeFunding)) + if err != nil { + return nil, err + } + } + return newNativeTokenKeyAddresses, nil +} + func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, vrfv2Config vrfv2_config.VRFV2Config, @@ -448,7 +469,7 @@ func RequestRandomnessAndWaitForFulfillment( l zerolog.Logger, ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { logRandRequest(consumer.Address(), coordinator.Address(), subID, vrfv2Config, l) - err := consumer.RequestRandomness( + _, err := consumer.RequestRandomness( vrfv2Data.KeyHash, subID, vrfv2Config.MinimumConfirmations, @@ -460,7 +481,7 @@ func RequestRandomnessAndWaitForFulfillment( return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) } - return WaitForRequestAndFulfillmentEvents( + fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( consumer.Address(), coordinator, vrfv2Data, @@ -468,6 +489,7 @@ func RequestRandomnessAndWaitForFulfillment( randomWordsFulfilledEventTimeout, l, ) + return fulfillmentEvents, err } func WaitForRequestAndFulfillmentEvents( @@ -489,7 +511,6 @@ func WaitForRequestAndFulfillmentEvents( } LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) - randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{randomWordsRequestedEvent.RequestId}, randomWordsFulfilledEventTimeout, diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index d0a33948e3..0e3c8096f0 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -7,9 +7,8 @@ import ( "sync" "time" - "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" @@ -31,6 +30,7 @@ import ( var ( ErrNodePrimaryKey = "error getting node's primary ETH key" + ErrNodeNewTxKey = "error creating node's EVM transaction key" ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" ErrRegisterProvingKey = "error registering proving keys" @@ -112,7 +112,7 @@ func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coord func CreateVRFV2PlusJob( chainlinkNode *client.ChainlinkClient, coordinatorAddress string, - nativeTokenPrimaryKeyAddress string, + nativeTokenKeyAddresses []string, pubKeyCompressed string, chainID string, minIncomingConfirmations uint16, @@ -129,7 +129,7 @@ func CreateVRFV2PlusJob( job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ Name: fmt.Sprintf("vrf-v2-plus-%s", jobUUID), CoordinatorAddress: coordinatorAddress, - FromAddresses: []string{nativeTokenPrimaryKeyAddress}, + FromAddresses: nativeTokenKeyAddresses, EVMChainID: chainID, MinIncomingConfirmations: int(minIncomingConfirmations), PublicKey: pubKeyCompressed, @@ -207,6 +207,7 @@ func SetupVRFV2_5Environment( linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, registerProvingKeyAgainstAddress string, + numberOfTxKeysToCreate int, numberOfConsumers int, numberOfSubToCreate int, l zerolog.Logger, @@ -273,17 +274,21 @@ func SetupVRFV2_5Environment( } chainID := env.EVMClient.GetChainID() - + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2PlusConfig, numberOfTxKeysToCreate, chainID) + if err != nil { + return nil, nil, nil, err + } nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) } + allNativeTokenKeyAddresses := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) l.Info().Msg("Creating VRFV2 Plus Job") job, err := CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], vrfv2_5Contracts.Coordinator.Address(), - nativeTokenPrimaryKeyAddress, + allNativeTokenKeyAddresses, pubKeyCompressed, chainID.String(), vrfv2PlusConfig.MinimumConfirmations, @@ -295,12 +300,8 @@ func SetupVRFV2_5Environment( // this part is here because VRFv2 can work with only a specific key // [[EVM.KeySpecific]] // Key = '...' - addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrGetPrimaryKey, err) - } nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(addr, vrfv2PlusConfig.CLNodeMaxGasPriceGWei), + node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, vrfv2PlusConfig.CLNodeMaxGasPriceGWei), ) l.Info().Msg("Restarting Node with new sending key PriceMax configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) @@ -325,6 +326,25 @@ func SetupVRFV2_5Environment( return vrfv2_5Contracts, subIDs, &data, nil } +func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { + var newNativeTokenKeyAddresses []string + for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { + newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrNodeNewTxKey, err) + } + if response.StatusCode != 200 { + return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) + } + newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) + err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)) + if err != nil { + return nil, err + } + } + return newNativeTokenKeyAddresses, nil +} + func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 5f850fce1a..548cac252b 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -170,7 +170,7 @@ type VRFv2Consumer interface { type VRFv2LoadTestConsumer interface { Address() string - RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32, requestCount uint16) error + RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_load_test_with_metrics.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index ac3926fa74..d1637c93c8 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -441,17 +441,24 @@ func (v *EthereumVRFv2LoadTestConsumer) Address() string { return v.address.Hex() } -func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness(keyHash [32]byte, subID uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) error { +func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness( + keyHash [32]byte, + subID uint64, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, +) (*types.Transaction, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { - return err + return nil, err } tx, err := v.consumer.RequestRandomWords(opts, subID, requestConfirmations, keyHash, callbackGasLimit, numWords, requestCount) if err != nil { - return err + return nil, err } - return v.client.ProcessTransaction(tx) + return tx, v.client.ProcessTransaction(tx) } func (v *EthereumVRFv2Consumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2_consumer_wrapper.GetRequestStatus, error) { diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 2338c0caa5..d0ca234663 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -11,6 +11,7 @@ require ( github.com/cli/go-gh/v2 v2.0.0 github.com/ethereum/go-ethereum v1.12.0 github.com/go-resty/resty/v2 v2.7.0 + github.com/google/go-cmp v0.5.9 github.com/google/uuid v1.3.1 github.com/jmoiron/sqlx v1.3.5 github.com/kelseyhightower/envconfig v1.4.0 @@ -191,7 +192,6 @@ require ( github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic v0.6.9 // indirect - github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 8e74e3aa90..ae109f75e2 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" "github.com/rs/zerolog" @@ -199,6 +198,7 @@ func TestVRFV2Performance(t *testing.T) { mockETHLinkFeed, //register proving key against EOA address in order to return funds to this address env.EVMClient.GetDefaultWallet().Address(), + 0, 1, vrfv2Config.NumberOfSubToCreate, l, @@ -302,13 +302,7 @@ func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l ze Str("Should have at least", fundingAtLeast.String()). Str("Funding Amount in ETH", fundingToSendEth.String()). Msg("Funding Node's Sending Key") - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ - To: &address, - }) - if err != nil { - return err - } - err = client.Fund(sendingKey, fundingToSendEth, gasEstimates) + err := actions.FundAddress(client, sendingKey, fundingToSendEth) if err != nil { return err } diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index ac22b5256f..4b6728440b 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -204,6 +204,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { mockETHLinkFeed, //register proving key against EOA address in order to return funds to this address env.EVMClient.GetDefaultWallet().Address(), + 0, 1, vrfv2PlusConfig.NumberOfSubToCreate, l, diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index c7b48fc3a3..4edb92e5df 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -5,9 +5,12 @@ import ( "math/big" "testing" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" @@ -44,12 +47,14 @@ func TestVRFv2Basic(t *testing.T) { // register proving key against oracle address (sending key) in order to test oracleWithdraw defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + numberOfTxKeysToCreate := 1 vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( env, vrfv2Config, linkToken, mockETHLinkFeed, defaultWalletAddress, + numberOfTxKeysToCreate, 1, 1, l, @@ -105,3 +110,91 @@ func TestVRFv2Basic(t *testing.T) { } }) } + +func TestVRFv2MultipleSendingKeys(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + var vrfv2Config vrfv2_config.VRFV2Config + err := envconfig.Process("VRFV2", &vrfv2Config) + require.NoError(t, err) + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithCLNodes(1). + WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + require.NoError(t, err) + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err) + + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + numberOfTxKeysToCreate := 2 + vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( + env, + vrfv2Config, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2 env") + + subID := subIDs[0] + + subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + + t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { + testConfig := vrfv2Config + txKeys, _, err := env.ClCluster.Nodes[0].API.ReadTxKeys("evm") + require.NoError(t, err, "error reading tx keys") + + require.Equal(t, numberOfTxKeysToCreate+1, len(txKeys.Data)) + + var fulfillmentTxFromAddresses []string + for i := 0; i < numberOfTxKeysToCreate+1; i++ { + randomWordsFulfilledEvent, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + vrfv2Contracts.LoadTestConsumers[0], + vrfv2Contracts.Coordinator, + vrfv2Data, + subID, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + //todo - move TransactionByHash to EVMClient in CTF + fulfillmentTx, _, err := env.EVMClient.(*blockchain.EthereumMultinodeClient).DefaultClient.(*blockchain.EthereumClient). + Client.TransactionByHash(context.Background(), randomWordsFulfilledEvent.Raw.TxHash) + require.NoError(t, err, "error getting tx from hash") + fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) + require.NoError(t, err, "error getting tx from address") + fulfillmentTxFromAddresses = append(fulfillmentTxFromAddresses, fulfillmentTxFromAddress) + } + require.Equal(t, numberOfTxKeysToCreate+1, len(fulfillmentTxFromAddresses)) + var txKeyAddresses []string + for _, txKey := range txKeys.Data { + txKeyAddresses = append(txKeyAddresses, txKey.ID) + } + less := func(a, b string) bool { return a < b } + equalIgnoreOrder := cmp.Diff(txKeyAddresses, fulfillmentTxFromAddresses, cmpopts.SortSlices(less)) == "" + require.True(t, equalIgnoreOrder) + }) +} diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 9ce9f21699..f4f52b6ee0 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -1,15 +1,19 @@ package smoke import ( + "context" "fmt" "math/big" "testing" "time" "github.com/ethereum/go-ethereum/common" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" @@ -49,12 +53,14 @@ func TestVRFv2Plus(t *testing.T) { // register proving key against oracle address (sending key) in order to test oracleWithdraw defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + numberOfTxKeysToCreate := 2 vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( env, vrfv2PlusConfig, linkToken, mockETHLinkFeed, defaultWalletAddress, + numberOfTxKeysToCreate, 1, 1, l, @@ -596,6 +602,97 @@ func TestVRFv2Plus(t *testing.T) { }) } +func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + require.NoError(t, err) + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithCLNodes(1). + WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + require.NoError(t, err, "error deploying mock ETH/LINK feed") + + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err, "error deploying LINK contract") + + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + numberOfTxKeysToCreate := 2 + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( + env, + vrfv2PlusConfig, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2_5 env") + + subID := subIDs[0] + + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) + + t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { + testConfig := vrfv2PlusConfig + var isNativeBilling = false + txKeys, _, err := env.ClCluster.Nodes[0].API.ReadTxKeys("evm") + require.NoError(t, err, "error reading tx keys") + + require.Equal(t, numberOfTxKeysToCreate+1, len(txKeys.Data)) + + var fulfillmentTxFromAddresses []string + for i := 0; i < numberOfTxKeysToCreate+1; i++ { + randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + subID, + isNativeBilling, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + //todo - move TransactionByHash to EVMClient in CTF + fulfillmentTx, _, err := env.EVMClient.(*blockchain.EthereumMultinodeClient).DefaultClient.(*blockchain.EthereumClient). + Client.TransactionByHash(context.Background(), randomWordsFulfilledEvent.Raw.TxHash) + require.NoError(t, err, "error getting tx from hash") + fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) + require.NoError(t, err, "error getting tx from address") + fulfillmentTxFromAddresses = append(fulfillmentTxFromAddresses, fulfillmentTxFromAddress) + } + require.Equal(t, numberOfTxKeysToCreate+1, len(fulfillmentTxFromAddresses)) + var txKeyAddresses []string + for _, txKey := range txKeys.Data { + txKeyAddresses = append(txKeyAddresses, txKey.ID) + } + less := func(a, b string) bool { return a < b } + equalIgnoreOrder := cmp.Diff(txKeyAddresses, fulfillmentTxFromAddresses, cmpopts.SortSlices(less)) == "" + require.True(t, equalIgnoreOrder) + }) +} + func TestVRFv2PlusMigration(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) @@ -622,7 +719,17 @@ func TestVRFv2PlusMigration(t *testing.T) { nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() require.NoError(t, err, "error getting primary eth address") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, nativeTokenPrimaryKeyAddress, 2, 1, l) + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( + env, + vrfv2PlusConfig, + linkAddress, + mockETHLinkFeedAddress, + nativeTokenPrimaryKeyAddress, + 0, + 2, + 1, + l, + ) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] @@ -671,7 +778,7 @@ func TestVRFv2PlusMigration(t *testing.T) { _, err = vrfv2plus.CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], newCoordinator.Address(), - vrfv2PlusData.PrimaryEthAddress, + []string{vrfv2PlusData.PrimaryEthAddress}, vrfv2PlusData.VRFKey.Data.ID, vrfv2PlusData.ChainID.String(), vrfv2PlusConfig.MinimumConfirmations, diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 47bc8e8cc1..5934809bac 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -223,22 +223,26 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { } } -func WithVRFv2EVMEstimator(addr string, maxGasPriceGWei int64) NodeConfigOpt { +func WithVRFv2EVMEstimator(addresses []string, maxGasPriceGWei int64) NodeConfigOpt { est := assets.GWei(maxGasPriceGWei) - return func(c *chainlink.Config) { - c.EVM[0].KeySpecific = evmcfg.KeySpecificConfig{ - { - Key: ptr.Ptr(ethkey.EIP55Address(addr)), - GasEstimator: evmcfg.KeySpecificGasEstimator{ - PriceMax: est, - }, + + var keySpecicifArr []evmcfg.KeySpecific + for _, addr := range addresses { + keySpecicifArr = append(keySpecicifArr, evmcfg.KeySpecific{ + Key: ptr.Ptr(ethkey.EIP55Address(addr)), + GasEstimator: evmcfg.KeySpecificGasEstimator{ + PriceMax: est, }, - } + }) + } + return func(c *chainlink.Config) { + c.EVM[0].KeySpecific = keySpecicifArr c.EVM[0].Chain.GasEstimator = evmcfg.GasEstimator{ LimitDefault: ptr.Ptr[uint32](3500000), } c.EVM[0].Chain.Transactions = evmcfg.Transactions{ MaxQueued: ptr.Ptr[uint32](10000), } + } } From 9f2e0d5356c13cb4a09c5baf22b816c7423fb695 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 27 Nov 2023 08:04:00 -0600 Subject: [PATCH 200/327] core/internal/cltest: simplify (#11383) --- core/chains/evm/client/client_test.go | 77 +++-- core/chains/evm/client/pool_test.go | 4 +- core/chains/evm/txmgr/broadcaster_test.go | 74 ++--- core/chains/evm/txmgr/confirmer_test.go | 156 ++++++----- core/chains/evm/txmgr/evm_tx_store_test.go | 126 ++++----- core/chains/evm/txmgr/reaper_test.go | 4 +- core/chains/evm/txmgr/txmgr_test.go | 265 +++++++++++++++++- core/cmd/admin_commands_test.go | 8 +- core/cmd/blocks_commands_test.go | 3 +- core/cmd/bridge_commands_test.go | 6 +- core/cmd/cosmos_keys_commands_test.go | 8 +- core/cmd/cosmos_transaction_commands_test.go | 3 +- core/cmd/csa_keys_commands_test.go | 6 +- core/cmd/dkgencrypt_keys_commands_test.go | 8 +- core/cmd/dkgsign_keys_commands_test.go | 8 +- core/cmd/eth_keys_commands_test.go | 28 +- core/cmd/evm_transaction_commands_test.go | 14 +- core/cmd/forwarders_commands_test.go | 8 +- core/cmd/jobs_commands_test.go | 12 +- core/cmd/ocr2_keys_commands_test.go | 10 +- core/cmd/ocr_keys_commands_test.go | 8 +- core/cmd/p2p_keys_commands_test.go | 8 +- core/cmd/shell_local_test.go | 10 +- core/cmd/shell_remote_test.go | 38 +-- core/cmd/shell_test.go | 49 ++++ core/cmd/solana_keys_commands_test.go | 8 +- core/cmd/solana_transaction_commands_test.go | 3 +- core/cmd/starknet_keys_commands_test.go | 8 +- core/cmd/vrf_keys_commands_test.go | 8 +- core/internal/cltest/cltest.go | 123 -------- .../internal/cltest/event_websocket_server.go | 154 ---------- core/internal/cltest/factories.go | 246 +--------------- core/internal/features/features_test.go | 24 +- .../ocrcommon/discoverer_database_test.go | 21 +- core/services/pg/event_broadcaster_test.go | 10 +- 35 files changed, 680 insertions(+), 866 deletions(-) delete mode 100644 core/internal/cltest/event_websocket_server.go diff --git a/core/chains/evm/client/client_test.go b/core/chains/evm/client/client_test.go index 673fe044af..631b5722de 100644 --- a/core/chains/evm/client/client_test.go +++ b/core/chains/evm/client/client_test.go @@ -89,7 +89,7 @@ func TestEthClient_TransactionReceipt(t *testing.T) { t.Run("happy path", func(t *testing.T) { result := mustReadResult(t, "../../../testdata/jsonrpc/getTransactionReceipt.json") - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -104,7 +104,7 @@ func TestEthClient_TransactionReceipt(t *testing.T) { resp.Result = string(result) } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -121,7 +121,7 @@ func TestEthClient_TransactionReceipt(t *testing.T) { t.Run("no tx hash, returns ethereum.NotFound", func(t *testing.T) { result := mustReadResult(t, "../../../testdata/jsonrpc/getTransactionReceipt_notFound.json") - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -136,7 +136,7 @@ func TestEthClient_TransactionReceipt(t *testing.T) { resp.Result = string(result) } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -155,7 +155,7 @@ func TestEthClient_PendingNonceAt(t *testing.T) { address := testutils.NewAddress() - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -174,7 +174,7 @@ func TestEthClient_PendingNonceAt(t *testing.T) { resp.Result = `"0x100"` } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -206,7 +206,7 @@ func TestEthClient_BalanceAt(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -221,7 +221,7 @@ func TestEthClient_BalanceAt(t *testing.T) { resp.Result = `"` + hexutil.EncodeBig(test.balance) + `"` } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -239,7 +239,7 @@ func TestEthClient_BalanceAt(t *testing.T) { func TestEthClient_LatestBlockHeight(t *testing.T) { t.Parallel() - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -254,7 +254,7 @@ func TestEthClient_LatestBlockHeight(t *testing.T) { } resp.Result = `"0x100"` return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -289,7 +289,7 @@ func TestEthClient_GetERC20Balance(t *testing.T) { functionSelector := evmtypes.HexToFunctionSelector(client.BALANCE_OF_ADDRESS_FUNCTION_SELECTOR) // balanceOf(address) txData := utils.ConcatBytes(functionSelector.Bytes(), common.LeftPadBytes(userAddress.Bytes(), utils.EVMWordByteLen)) - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -312,8 +312,7 @@ func TestEthClient_GetERC20Balance(t *testing.T) { resp.Result = `"` + hexutil.EncodeBig(test.balance) + `"` } return - - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -370,7 +369,7 @@ func TestEthClient_HeaderByNumber(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -392,7 +391,7 @@ func TestEthClient_HeaderByNumber(t *testing.T) { resp.Result = test.rpcResp } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -420,7 +419,7 @@ func TestEthClient_SendTransaction_NoSecondaryURL(t *testing.T) { tx := types.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -435,7 +434,7 @@ func TestEthClient_SendTransaction_NoSecondaryURL(t *testing.T) { } resp.Result = `"` + tx.Hash().Hex() + `"` return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -452,7 +451,7 @@ func TestEthClient_SendTransaction_WithSecondaryURLs(t *testing.T) { tx := types.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -465,7 +464,7 @@ func TestEthClient_SendTransaction_WithSecondaryURLs(t *testing.T) { resp.Result = `"` + tx.Hash().Hex() + `"` } return - }) + }).WSURL().String() rpcSrv := rpc.NewServer() t.Cleanup(rpcSrv.Stop) @@ -498,7 +497,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { tx := types.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) t.Run("returns Fatal error type when error message is fatal", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -512,7 +511,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "invalid sender" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -526,7 +525,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns TransactionAlreadyKnown error type when error message is nonce too low", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -540,7 +539,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "nonce too low" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -554,7 +553,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns Successful error type when there is no error message", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -567,7 +566,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Result = `"` + tx.Hash().Hex() + `"` } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -581,7 +580,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns Underpriced error type when transaction is terminally underpriced", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -595,7 +594,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "transaction underpriced" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -609,7 +608,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns Unsupported error type when error message is queue full", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -623,7 +622,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "queue full" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -637,7 +636,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns Retryable error type when there is a transaction gap", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -651,7 +650,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "NonceGap" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -665,7 +664,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns InsufficientFunds error type when the sender address doesn't have enough funds", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -679,7 +678,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "insufficient funds for transfer" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -693,7 +692,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns ExceedsFeeCap error type when gas price is too high for the node", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -707,7 +706,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "Transaction fee cap exceeded" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -721,7 +720,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { }) t.Run("returns Unknown error type when the error can't be categorized", func(t *testing.T) { - wsURL := cltest.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -735,7 +734,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { resp.Error.Message = "some random error" } return - }) + }).WSURL().String() clients := mustNewClients(t, wsURL) for _, ethClient := range clients { @@ -770,7 +769,7 @@ func TestEthClient_SubscribeNewHead(t *testing.T) { defer cancel() chainId := big.NewInt(123456) - wsURL := cltest.NewWSServer(t, chainId, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + wsURL := testutils.NewWSServer(t, chainId, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { if method == "eth_unsubscribe" { resp.Result = "true" return @@ -781,7 +780,7 @@ func TestEthClient_SubscribeNewHead(t *testing.T) { resp.Notify = headResult } return - }) + }).WSURL().String() clients := mustNewClientsWithChainID(t, wsURL, chainId) for _, ethClient := range clients { diff --git a/core/chains/evm/client/pool_test.go b/core/chains/evm/client/pool_test.go index 15a6484756..75d38d01a4 100644 --- a/core/chains/evm/client/pool_test.go +++ b/core/chains/evm/client/pool_test.go @@ -211,7 +211,7 @@ type chainIDResps struct { } func (r *chainIDResps) newNode(t *testing.T, nodeChainID int64) evmclient.Node { - ws := cltest.NewWSServer(t, big.NewInt(r.ws.chainID), func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + ws := testutils.NewWSServer(t, big.NewInt(r.ws.chainID), func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { case "eth_subscribe": resp.Result = `"0x00"` @@ -223,7 +223,7 @@ func (r *chainIDResps) newNode(t *testing.T, nodeChainID int64) evmclient.Node { } t.Errorf("Unexpected method call: %s(%s)", method, params) return - }) + }).WSURL().String() wsURL, err := url.Parse(ws) require.NoError(t, err) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index d1e26c6c96..43f2fdb8ca 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -195,7 +195,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }) t.Run("eth_txes exist for a different from address", func(t *testing.T) { - cltest.MustCreateUnstartedTx(t, txStore, otherAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, otherAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -383,7 +383,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { return tx.Nonce() == uint64(343) && tx.Value().Cmp(big.NewInt(242)) == 0 }), fromAddress).Return(commonclient.Successful, nil).Once() - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, []byte{42, 42, 0}, gasLimit, big.Int(assets.NewEthValue(242)), &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, []byte{42, 42, 0}, gasLimit, big.Int(assets.NewEthValue(242)), &cltest.FixtureChainID) // Do the thing { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -448,7 +448,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { return false }), "latest").Return(nil).Once() - ethTx := cltest.MustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, &cltest.FixtureChainID) + ethTx := mustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, &cltest.FixtureChainID) { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -470,9 +470,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { return fmt.Sprintf("%s", callarg["value"]) == "0x21e" // 542 }), "latest").Return(errors.New("this is not a revert, something unexpected went wrong")).Once() - ethTx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, - cltest.EvmTxRequestWithChecker(checker), - cltest.EvmTxRequestWithValue(big.Int(assets.NewEthValue(542)))) + ethTx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, + txRequestWithChecker(checker), + txRequestWithValue(big.Int(assets.NewEthValue(542)))) { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -495,9 +495,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { return fmt.Sprintf("%s", callarg["value"]) == "0x282" // 642 }), "latest").Return(&jerr).Once() - ethTx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, - cltest.EvmTxRequestWithChecker(checker), - cltest.EvmTxRequestWithValue(big.Int(assets.NewEthValue(642)))) + ethTx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, + txRequestWithChecker(checker), + txRequestWithValue(big.Int(assets.NewEthValue(642)))) { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -537,9 +537,9 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { return tx.Nonce() == 0 && tx.Value().Cmp(big.NewInt(442)) == 0 }), fromAddress).Return(commonclient.Successful, nil).Once() - ethTx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, - cltest.EvmTxRequestWithValue(big.Int(assets.NewEthValue(442))), - cltest.EvmTxRequestWithChecker(checker)) + ethTx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, + txRequestWithValue(big.Int(assets.NewEthValue(442))), + txRequestWithChecker(checker)) { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -560,9 +560,9 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { return tx.Nonce() == 1 && tx.Value().Cmp(big.NewInt(442)) == 0 }), fromAddress).Return(commonclient.Successful, nil).Once() - ethTx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, - cltest.EvmTxRequestWithValue(big.Int(assets.NewEthValue(442))), - cltest.EvmTxRequestWithChecker(checker)) + ethTx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, + txRequestWithValue(big.Int(assets.NewEthValue(442))), + txRequestWithChecker(checker)) { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -579,7 +579,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { // Checker will return a fatal error checkerFactory.err = errors.New("fatal checker error") - ethTx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, cltest.EvmTxRequestWithChecker(checker)) + ethTx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, txRequestWithChecker(checker)) { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -635,7 +635,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi require.NoError(t, eb.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, eb.Close()) }) - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) go func() { select { @@ -688,7 +688,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing FeeLimit: 1231, Strategy: txmgrcommon.NewSendEveryStrategy(), } - cltest.MustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, &cltest.FixtureChainID) + mustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, &cltest.FixtureChainID) // Do the thing { @@ -758,7 +758,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so evm.key_states.next_nonce has not been // incremented yet - inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) + inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) @@ -794,7 +794,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx - inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) + inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) @@ -830,7 +830,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx - inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) + inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) @@ -865,7 +865,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx - inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) + inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) @@ -902,7 +902,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx - inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) + inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(firstNonce) @@ -943,7 +943,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx - inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) + inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) require.Len(t, inProgressEthTx.TxAttempts, 1) attempt := inProgressEthTx.TxAttempts[0] @@ -1009,7 +1009,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { require.NoError(t, utils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) t.Run("if external wallet sent a transaction from the account and now the nonce is one higher than it should be and we got replacement underpriced then we assume a previous transaction of ours was the one that succeeded, and hand off to EthConfirmer", func(t *testing.T) { - cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First send, replacement underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(0) @@ -1047,7 +1047,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce := getLocalNextNonce(t, eb, fromAddress) t.Run("without callback", func(t *testing.T) { - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Fatal, errors.New(fatalErrorExample)).Once() @@ -1151,7 +1151,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("geth Client fails with error indicating that the transaction was too expensive", func(t *testing.T) { TxFeeExceedsCapError := "tx fee (1.10 ether) exceeds the configured cap (1.00 ether)" localNextNonce := getLocalNextNonce(t, eb, fromAddress) - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.ExceedsMaxFee, errors.New(TxFeeExceedsCapError)).Twice() @@ -1209,7 +1209,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was not accepted into mempool", func(t *testing.T) { retryableErrorExample := "some unknown error" localNextNonce := getLocalNextNonce(t, eb, fromAddress) - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(localNextNonce) }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() @@ -1261,7 +1261,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth client call fails with an unexpected random error, and the nonce check also subsequently fails", func(t *testing.T) { retryableErrorExample := "some unknown error" localNextNonce := getLocalNextNonce(t, eb, fromAddress) - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == uint64(localNextNonce) }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() @@ -1313,7 +1313,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was accepted into mempool", func(t *testing.T) { retryableErrorExample := "some strange RPC returns an unexpected thing" localNextNonce := getLocalNextNonce(t, eb, fromAddress) - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() @@ -1345,7 +1345,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" localNextNonce := getLocalNextNonce(t, eb, fromAddress) - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1462,7 +1462,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { })) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) - cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1482,7 +1482,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth tx is left in progress if eth node returns insufficient eth", func(t *testing.T) { insufficientEthError := "insufficient funds for transfer" localNextNonce := getLocalNextNonce(t, eb, fromAddress) - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.InsufficientFunds, errors.New(insufficientEthError)).Once() @@ -1512,7 +1512,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth tx is left in progress if nonce is too high", func(t *testing.T) { localNextNonce := getLocalNextNonce(t, eb, fromAddress) nonceGapError := "NonceGap, Future nonce. Expected nonce: " + strconv.FormatUint(localNextNonce, 10) - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Retryable, errors.New(nonceGapError)).Once() @@ -1554,7 +1554,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce := getLocalNextNonce(t, eb, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) - cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" localNextNonce = getLocalNextNonce(t, eb, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1576,7 +1576,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" localNextNonce := getLocalNextNonce(t, eb, fromAddress) - cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // Check gas tip cap verification evmcfg2 := evmtest.NewChainScopedConfig(t, configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -1650,7 +1650,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { require.NoError(t, err) t.Run("tx signing fails", func(t *testing.T) { - etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) tx := *gethTypes.NewTx(&gethTypes.LegacyTx{}) kst.On("SignTx", fromAddress, diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 60d0648a54..f5889b0664 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -38,6 +38,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -84,7 +85,7 @@ func newInProgressLegacyEthTxAttempt(t *testing.T, etxID int64, gasPrice ...int6 } func mustInsertInProgressEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress gethCommon.Address) txmgr.Tx { - etx := cltest.NewEthTx(t, fromAddress) + etx := cltest.NewEthTx(fromAddress) etx.State = txmgrcommon.TxInProgress n := evmtypes.Nonce(nonce) etx.Sequence = &n @@ -94,7 +95,7 @@ func mustInsertInProgressEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonce } func mustInsertConfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress gethCommon.Address) txmgr.Tx { - etx := cltest.NewEthTx(t, fromAddress) + etx := cltest.NewEthTx(fromAddress) etx.State = txmgrcommon.TxConfirmed n := evmtypes.Nonce(nonce) etx.Sequence = &n @@ -111,7 +112,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { db := pgtest.NewSqlxDB(t) config := newTestChainScopedConfig(t) - txStore := cltest.NewTxStore(t, db, config.Database()) + txStore := newTxStore(t, db, config.Database()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() @@ -187,21 +188,21 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) nonce := int64(0) ctx := testutils.Context(t) blockNum := int64(0) t.Run("only finds eth_txes in unconfirmed state with at least one broadcast attempt", func(t *testing.T) { - cltest.MustInsertFatalErrorEthTx(t, txStore, fromAddress) + mustInsertFatalErrorEthTx(t, txStore, fromAddress) mustInsertInProgressEthTx(t, txStore, nonce, fromAddress) nonce++ cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, nonce, 1, fromAddress) nonce++ - cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) nonce++ - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) // Do the thing require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) @@ -450,7 +451,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.Len(t, attempt3_1.Receipts, 0) }) t.Run("handles case where eth_receipt already exists somehow", func(t *testing.T) { - ethReceipt := cltest.MustInsertEthReceipt(t, txStore, 42, utils.NewHash(), attempt3_1.Hash) + ethReceipt := mustInsertEthReceipt(t, txStore, 42, utils.NewHash(), attempt3_1.Hash) txmReceipt := evmtypes.Receipt{ TxHash: attempt3_1.Hash, BlockHash: ethReceipt.BlockHash, @@ -604,7 +605,7 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -664,7 +665,7 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t * evmcfg := evmtest.NewChainScopedConfig(t, cfg) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // tx is not forwarded and doesn't have meta set. EthConfirmer should handle nil meta values etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -717,7 +718,7 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) var attempts []txmgr.TxAttempt @@ -771,7 +772,7 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) @@ -802,7 +803,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(20), nil) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -869,7 +870,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1129,7 +1130,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1137,18 +1138,18 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { // eth_txes with nonce 1 has two attempts, the later attempt with higher gas fees // eth_txes with nonce 2 has one attempt originalBroadcastAt := time.Unix(1616509100, 0) - etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempt0_2 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(2)) require.NoError(t, txStore.InsertTxAttempt(&attempt0_2)) - etx1 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx1 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 1, 1, originalBroadcastAt, fromAddress) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(2)) require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) - etx2 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx2 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 2, 1, originalBroadcastAt, fromAddress) attempt2_1 := etx2.TxAttempts[0] - etx3 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx3 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 3, 1, originalBroadcastAt, fromAddress) attempt3_1 := etx3.TxAttempts[0] @@ -1208,7 +1209,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1216,15 +1217,15 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t // eth_txes with nonce 1 has two attempts, the later attempt with higher gas fees // eth_txes with nonce 2 has one attempt originalBroadcastAt := time.Unix(1616509100, 0) - etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempt0_2 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(2)) require.NoError(t, txStore.InsertTxAttempt(&attempt0_2)) - etx1 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx1 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 1, 1, originalBroadcastAt, fromAddress) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(2)) require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) - etx2 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx2 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 2, 1, originalBroadcastAt, fromAddress) attempt2_1 := etx2.TxAttempts[0] @@ -1272,7 +1273,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1280,15 +1281,15 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa // eth_txes with nonce 1 has two attempts, the later attempt with higher gas fees // eth_txes with nonce 2 has one attempt originalBroadcastAt := time.Unix(1616509100, 0) - etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempt0_2 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(2)) require.NoError(t, txStore.InsertTxAttempt(&attempt0_2)) - etx1 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx1 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 1, 1, originalBroadcastAt, fromAddress) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(2)) require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) - etx2 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx2 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 2, 1, originalBroadcastAt, fromAddress) // Expect eth_sendRawTransaction in 3 batches. First batch will pass, 2nd will fail, 3rd never attempted. @@ -1354,7 +1355,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { lggr := logger.TestLogger(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) t.Run("returns nothing when there are no transactions", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1416,7 +1417,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { assert.Len(t, etxs, 0) }) - etxWithoutAttempts := cltest.NewEthTx(t, fromAddress) + etxWithoutAttempts := cltest.NewEthTx(fromAddress) { n := evmtypes.Nonce(nonce) etxWithoutAttempts.Sequence = &n @@ -1577,13 +1578,13 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { attempt4_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(40000)} require.NoError(t, txStore.InsertTxAttempt(&attempt4_2)) - etx5 := cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) + etx5 := mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) nonce++ // This etx has one attempt that is too new, which would exclude it from // the gas bumping query, but it should still be caught by the insufficient // eth query - etx6 := cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) + etx6 := mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) attempt6_2 := newBroadcastLegacyEthTxAttempt(t, etx3.ID) attempt6_2.BroadcastBeforeBlockNum = &tooNew attempt6_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(30001)} @@ -1696,7 +1697,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing nonce := int64(0) originalBroadcastAt := time.Unix(1616509100, 0) - etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress, originalBroadcastAt) + etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress, originalBroadcastAt) attempt1 := etx.TxAttempts[0] var dbAttempt txmgr.DbEthTxAttempt dbAttempt.FromTxAttempt(&attempt1) @@ -1735,7 +1736,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -2205,7 +2206,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60500000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + ec2 := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2235,7 +2236,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60480000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + ec2 := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2256,7 +2257,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }) // The EIP-1559 etx and attempt - etx4 := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) + etx4 := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) attempt4_1 := etx4.TxAttempts[0] require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, oldEnough, assets.GWei(35), assets.GWei(100), attempt4_1.ID)) @@ -2303,7 +2304,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.GWei(1000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + ec2 := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) // Third attempt failed to bump, resubmits old one instead ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { @@ -2389,10 +2390,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("terminally underpriced transaction with in_progress attempt is retried with more gas", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) originalBroadcastAt := time.Unix(1616509100, 0) - etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, nonce, fromAddress, txmgrtypes.TxAttemptInProgress, originalBroadcastAt) + etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, nonce, fromAddress, txmgrtypes.TxAttemptInProgress, originalBroadcastAt) require.Equal(t, originalBroadcastAt, *etx.BroadcastAt) nonce++ attempt := etx.TxAttempts[0] @@ -2413,7 +2414,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in legacy mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -2445,9 +2446,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in EIP-1559 mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) + etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) nonce++ dxFeeAttempt := etx.TxAttempts[0] var dbAttempt txmgr.DbEthTxAttempt @@ -2510,7 +2511,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { insufficientEthError := errors.New("insufficient funds for gas * price + value") t.Run("saves attempt with state 'insufficient_eth' if eth node returns this error", func(t *testing.T) { - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2536,7 +2537,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("does not bump gas when previous error was 'out of eth', instead resubmits existing transaction", func(t *testing.T) { - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2561,7 +2562,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("saves the attempt as broadcast after node wallet has been topped up with sufficient balance", func(t *testing.T) { - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2593,11 +2594,11 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { c.EVM[0].GasEstimator.BumpTxDepth = ptr(uint32(depth)) }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) for i := 0; i < etxCount; i++ { n := nonce - cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(n) }), fromAddress).Return(commonclient.Successful, nil).Once() @@ -2628,7 +2629,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) config := newTestChainScopedConfig(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) head := evmtypes.Head{ Hash: utils.NewHash(), @@ -2661,7 +2662,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { t.Run("does nothing to confirmed transactions with receipts within head height of the chain and included in the chain", func(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 2, 1, fromAddress) - cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, etx.TxAttempts[0].Hash) + mustInsertEthReceipt(t, txStore, head.Number, head.Hash, etx.TxAttempts[0].Hash) // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) @@ -2674,7 +2675,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { t.Run("does nothing to confirmed transactions that only have receipts older than the start of the chain", func(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 1, fromAddress) // Add receipt that is older than the lowest block of the chain - cltest.MustInsertEthReceipt(t, txStore, head.Parent.Parent.Number-1, utils.NewHash(), etx.TxAttempts[0].Hash) + mustInsertEthReceipt(t, txStore, head.Parent.Parent.Number-1, utils.NewHash(), etx.TxAttempts[0].Hash) // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) @@ -2688,7 +2689,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 4, 1, fromAddress) attempt := etx.TxAttempts[0] // Include one within head height but a different block hash - cltest.MustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attempt.Hash) + mustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attempt.Hash) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { atx, err := txmgr.GetGethSignedTx(attempt.SignedRawTx) @@ -2713,9 +2714,9 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { attempt := etx.TxAttempts[0] attemptHash := attempt.Hash // Add receipt that is older than the lowest block of the chain - cltest.MustInsertEthReceipt(t, txStore, head.Parent.Parent.Number-1, utils.NewHash(), attemptHash) + mustInsertEthReceipt(t, txStore, head.Parent.Parent.Number-1, utils.NewHash(), attemptHash) // Include one within head height but a different block hash - cltest.MustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attemptHash) + mustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attemptHash) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( commonclient.Successful, nil).Once() @@ -2745,9 +2746,9 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { require.NoError(t, txStore.InsertTxAttempt(&attempt3)) // Receipt is within head height but a different block hash - cltest.MustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attempt2.Hash) + mustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attempt2.Hash) // Receipt is within head height but a different block hash - cltest.MustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attempt3.Hash) + mustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attempt3.Hash) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { s, err := txmgr.GetGethSignedTx(attempt3.SignedRawTx) @@ -2774,7 +2775,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 7, 1, fromAddress) attempt := etx.TxAttempts[0] // Add receipt that is higher than head - cltest.MustInsertEthReceipt(t, txStore, head.Number+1, utils.NewHash(), attempt.Hash) + mustInsertEthReceipt(t, txStore, head.Number+1, utils.NewHash(), attempt.Hash) require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) @@ -2799,7 +2800,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) config := newTestChainScopedConfig(t) - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) mustInsertInProgressEthTx(t, txStore, 0, fromAddress) etx1 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) etx2 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress) @@ -2809,7 +2810,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts one eth_tx if it falls within in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2824,7 +2825,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("uses default gas limit if overrideGasLimit is 0", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2839,7 +2840,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts several eth_txes in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == uint64(overrideGasLimit) @@ -2853,7 +2854,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("broadcasts zero transactions if eth_tx doesn't exist for that nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(1) @@ -2879,7 +2880,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("zero transactions use default gas limit if override wasn't specified", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(0) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && uint32(tx.Gas()) == config.EVM().GasEstimator().LimitDefault() @@ -2923,7 +2924,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`) t.Run("doesn't process task runs that are not suspended (possibly already previously resumed)", func(t *testing.T) { - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) @@ -2932,7 +2933,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 1, fromAddress) - cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) + mustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) // Setting both signal_callback and callback_completed to TRUE to simulate a completed pipeline task // It would only be in a state past suspended if the resume callback was called and callback_completed was set to TRUE pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE, callback_completed = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) @@ -2942,7 +2943,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { }) t.Run("doesn't process task runs where the receipt is younger than minConfirmations", func(t *testing.T) { - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) @@ -2951,7 +2952,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 2, 1, fromAddress) - cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, etx.TxAttempts[0].Hash) + mustInsertEthReceipt(t, txStore, head.Number, head.Hash, etx.TxAttempts[0].Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) @@ -2963,7 +2964,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { ch := make(chan interface{}) nonce := evmtypes.Nonce(3) var err error - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr ch <- value return nil @@ -2975,7 +2976,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(nonce), 1, fromAddress) pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) - receipt := cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) + receipt := mustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) @@ -3007,7 +3008,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { ch := make(chan interface{}) nonce := evmtypes.Nonce(4) var err error - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr ch <- value return nil @@ -3021,7 +3022,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) // receipt is not passed through as a value since it reverted and caused an error - cltest.MustInsertRevertedEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) + mustInsertRevertedEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) @@ -3049,7 +3050,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Run("does not mark callback complete if callback fails", func(t *testing.T) { nonce := evmtypes.Nonce(5) - ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { return errors.New("error") }) @@ -3057,7 +3058,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(nonce), 1, fromAddress) - cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) + mustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) @@ -3071,3 +3072,14 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { } func ptr[T any](t T) *T { return &t } + +func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { + lggr := logger.TestLogger(t) + ge := config.EVM().GasEstimator() + estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) + ec.SetResumeCallback(fn) + require.NoError(t, ec.Start(testutils.Context(t))) + return ec +} diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 73bfc6fc85..15417a4309 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -52,7 +52,7 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { require.NoError(t, txStore.InsertTxAttempt(&attempt)) // tx 3 has no attempts - cltest.MustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) var count int err := db.Get(&count, `SELECT count(*) FROM evm.txes`) @@ -97,7 +97,7 @@ func TestORM_Transactions(t *testing.T) { require.NoError(t, txStore.InsertTxAttempt(&attempt)) // tx 3 has no attempts - cltest.MustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) var count int err := db.Get(&count, `SELECT count(*) FROM evm.txes`) @@ -125,7 +125,7 @@ func TestORM(t *testing.T) { var etx txmgr.Tx t.Run("InsertTx", func(t *testing.T) { - etx = cltest.NewEthTx(t, fromAddress) + etx = cltest.NewEthTx(fromAddress) require.NoError(t, orm.InsertTx(&etx)) assert.Greater(t, int(etx.ID), 0) cltest.AssertCount(t, db, "evm.txes", 1) @@ -147,7 +147,7 @@ func TestORM(t *testing.T) { }) var r txmgr.Receipt t.Run("InsertReceipt", func(t *testing.T) { - r = cltest.NewEthReceipt(t, 42, utils.NewHash(), attemptD.Hash, 0x1) + r = newEthReceipt(42, utils.NewHash(), attemptD.Hash, 0x1) id, err := orm.InsertReceipt(&r.Receipt) r.ID = id require.NoError(t, err) @@ -203,12 +203,12 @@ func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { require.NoError(t, orm.InsertTxAttempt(&attempt)) // add receipt for the second attempt - r := cltest.NewEthReceipt(t, 4, utils.NewHash(), attempt.Hash, 0x1) + r := newEthReceipt(4, utils.NewHash(), attempt.Hash, 0x1) _, err := orm.InsertReceipt(&r.Receipt) require.NoError(t, err) // tx 3 has no attempts - cltest.MustCreateUnstartedGeneratedTx(t, orm, from, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, orm, from, &cltest.FixtureChainID) cltest.MustInsertUnconfirmedEthTx(t, orm, 3, from) // tx4 cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, orm, 4, from) // tx5 @@ -252,7 +252,7 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { // Mix up the insert order to assure that they come out sorted by nonce not implicitly or by ID e1 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress, time.Unix(1616509200, 0)) - e3 := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 3, fromAddress, time.Unix(1616509400, 0)) + e3 := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 3, fromAddress, time.Unix(1616509400, 0)) e0 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress, time.Unix(1616509100, 0)) e2 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress, time.Unix(1616509300, 0)) @@ -331,7 +331,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { t.Run("does not update when broadcast_at is NULL", func(t *testing.T) { t.Parallel() - etx := cltest.MustCreateUnstartedGeneratedTx(t, orm, fromAddress, &cltest.FixtureChainID) + etx := mustCreateUnstartedGeneratedTx(t, orm, fromAddress, &cltest.FixtureChainID) var nullTime *time.Time assert.Equal(t, nullTime, etx.BroadcastAt) @@ -349,7 +349,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { t.Parallel() time1 := time.Now() - etx := cltest.NewEthTx(t, fromAddress) + etx := cltest.NewEthTx(fromAddress) etx.Sequence = new(evmtypes.Nonce) etx.State = txmgrcommon.TxUnconfirmed etx.BroadcastAt = &time1 @@ -446,7 +446,7 @@ func TestORM_FindTxAttemptsConfirmedMissingReceipt(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) - etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempts, err := txStore.FindTxAttemptsConfirmedMissingReceipt(testutils.Context(t), ethClient.ConfiguredChainID()) @@ -468,7 +468,7 @@ func TestORM_UpdateTxsUnconfirmed(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) - etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) assert.Equal(t, etx0.State, txmgrcommon.TxConfirmedMissingReceipt) require.NoError(t, txStore.UpdateTxsUnconfirmed(testutils.Context(t), []int64{etx0.ID})) @@ -489,7 +489,7 @@ func TestORM_FindTxAttemptsRequiringReceiptFetch(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) - etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempts, err := txStore.FindTxAttemptsRequiringReceiptFetch(testutils.Context(t), ethClient.ConfiguredChainID()) @@ -510,7 +510,7 @@ func TestORM_SaveFetchedReceipts(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) - etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) require.Len(t, etx0.TxAttempts, 1) @@ -552,7 +552,7 @@ func TestORM_MarkAllConfirmedMissingReceipt(t *testing.T) { assert.Equal(t, txmgrcommon.TxUnconfirmed, etx0.State) // create transaction 1 (nonce 1) that is confirmed (block 77) - etx1 := cltest.MustInsertConfirmedEthTxBySaveFetchedReceipts(t, txStore, fromAddress, int64(1), int64(77), *ethClient.ConfiguredChainID()) + etx1 := mustInsertConfirmedEthTxBySaveFetchedReceipts(t, txStore, fromAddress, int64(1), int64(77), *ethClient.ConfiguredChainID()) assert.Equal(t, etx1.State, txmgrcommon.TxConfirmed) // mark transaction 0 confirmed_missing_receipt @@ -608,7 +608,7 @@ func TestORM_GetInProgressTxAttempts(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // insert etx with attempt - etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, int64(7), fromAddress, txmgrtypes.TxAttemptInProgress) + etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, int64(7), fromAddress, txmgrtypes.TxAttemptInProgress) // fetch attempt attempts, err := txStore.GetInProgressTxAttempts(testutils.Context(t), fromAddress, ethClient.ConfiguredChainID()) @@ -653,7 +653,7 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { etx1 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 1, fromAddress) pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) attempt1 := etx1.TxAttempts[0] - cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt1.Hash) + mustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt1.Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr1.ID, minConfirmations, etx1.ID) // Callback to pipeline service completed. Should be ignored @@ -662,7 +662,7 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { etx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 4, 1, fromAddress) pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": false}'`) attempt2 := etx2.TxAttempts[0] - cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt2.Hash) + mustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt2.Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE, callback_completed = TRUE WHERE id = $3`, &tr2.ID, minConfirmations, etx2.ID) // Suspended run younger than minConfirmations. Should be ignored @@ -672,13 +672,13 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { etx3 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 5, 1, fromAddress) pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": false}'`) attempt3 := etx3.TxAttempts[0] - cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, attempt3.Hash) + mustInsertEthReceipt(t, txStore, head.Number, head.Hash, attempt3.Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr3.ID, minConfirmations, etx3.ID) // Tx not marked for callback. Should be ignore etx4 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 6, 1, fromAddress) attempt4 := etx4.TxAttempts[0] - cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, attempt4.Hash) + mustInsertEthReceipt(t, txStore, head.Number, head.Hash, attempt4.Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET min_confirmations = $1 WHERE id = $2`, minConfirmations, etx4.ID) // Unconfirmed Tx without receipts. Should be ignored @@ -710,8 +710,8 @@ func Test_FindTxWithIdempotencyKey(t *testing.T) { t.Run("returns transaction if it exists", func(t *testing.T) { idempotencyKey := "777" cfg.EVM().ChainID() - etx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, big.NewInt(0), - cltest.EvmTxRequestWithIdempotencyKey(idempotencyKey)) + etx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, big.NewInt(0), + txRequestWithIdempotencyKey(idempotencyKey)) require.Equal(t, idempotencyKey, *etx.IdempotencyKey) res, err := txStore.FindTxWithIdempotencyKey(testutils.Context(t), idempotencyKey, big.NewInt(0)) @@ -756,7 +756,7 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("delete all receipts for eth transaction", func(t *testing.T) { - etx := cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 1) + etx := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 1) etx, err := txStore.FindTxWithAttempts(etx.ID) assert.NoError(t, err) // assert attempt state @@ -811,8 +811,8 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { } t.Run("find all transactions confirmed in range", func(t *testing.T) { - etx_8 := cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 700, 8) - etx_9 := cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 9) + etx_8 := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 700, 8) + etx_9 := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 9) etxes, err := txStore.FindTransactionsConfirmedInBlockRange(testutils.Context(t), head.Number, 8, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -834,7 +834,7 @@ func TestORM_SaveInsufficientEthAttempt(t *testing.T) { require.NoError(t, err) t.Run("updates attempt state", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) now := time.Now() err = txStore.SaveInsufficientFundsAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) @@ -858,7 +858,7 @@ func TestORM_SaveSentAttempt(t *testing.T) { require.NoError(t, err) t.Run("updates attempt state to 'broadcast'", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) require.Nil(t, etx.BroadcastAt) now := time.Now() @@ -883,7 +883,7 @@ func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { require.NoError(t, err) t.Run("updates attempt to 'broadcast' and transaction to 'confirm_missing_receipt'", func(t *testing.T) { - etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 1, fromAddress, txmgrtypes.TxAttemptInProgress) + etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 1, fromAddress, txmgrtypes.TxAttemptInProgress) now := time.Now() err = txStore.SaveConfirmedMissingReceiptAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) @@ -906,7 +906,7 @@ func TestORM_DeleteInProgressAttempt(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("deletes in_progress attempt", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) attempt := etx.TxAttempts[0] err := txStore.DeleteInProgressAttempt(testutils.Context(t), etx.TxAttempts[0]) @@ -942,7 +942,7 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { }) t.Run("updates old attempt to in_progress when insufficient_eth", func(t *testing.T) { - etx := cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 23, fromAddress) + etx := mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 23, fromAddress) attempt := etx.TxAttempts[0] require.Equal(t, txmgrtypes.TxAttemptInsufficientFunds, attempt.State) require.NotEqual(t, 0, attempt.ID) @@ -972,7 +972,7 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { currentBlockNum := int64(10) t.Run("gets txs requiring gas bump", func(t *testing.T) { - etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 1, fromAddress, txmgrtypes.TxAttemptBroadcast) + etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 1, fromAddress, txmgrtypes.TxAttemptBroadcast) err := txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), currentBlockNum, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -985,7 +985,7 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { assert.Equal(t, currentBlockNum, *attempts[0].BroadcastBeforeBlockNum) // this tx will not require gas bump - cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 2, fromAddress, txmgrtypes.TxAttemptBroadcast) + mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 2, fromAddress, txmgrtypes.TxAttemptBroadcast) err = txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), currentBlockNum+1, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -1012,18 +1012,18 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // Insert order is mixed up to test sorting - etx2 := cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 1, fromAddress) + etx2 := mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 1, fromAddress) etx3 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress) attempt3_2 := cltest.NewLegacyEthTxAttempt(t, etx3.ID) attempt3_2.State = txmgrtypes.TxAttemptInsufficientFunds attempt3_2.TxFee.Legacy = assets.NewWeiI(100) require.NoError(t, txStore.InsertTxAttempt(&attempt3_2)) - etx1 := cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, fromAddress) + etx1 := mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, fromAddress) // These should never be returned cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 3, fromAddress) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 4, 100, fromAddress) - cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherAddress) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherAddress) t.Run("returns all eth_txes with at least one attempt that is in insufficient_eth state", func(t *testing.T) { etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(testutils.Context(t), fromAddress, &cltest.FixtureChainID) @@ -1073,7 +1073,7 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { // tx state should be confirmed missing receipt // attempt should be broadcast before cutoff time t.Run("successfully mark errored transactions", func(t *testing.T) { - etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) + etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) err := txStore.MarkOldTxesMissingReceiptAsErrored(testutils.Context(t), 10, 2, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -1084,7 +1084,7 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { }) t.Run("successfully mark errored transactions w/ qopt passing in sql.Tx", func(t *testing.T) { - etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) + etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) err := txStore.MarkOldTxesMissingReceiptAsErrored(testutils.Context(t), 10, 2, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -1105,7 +1105,7 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("load eth tx attempt", func(t *testing.T) { - etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) + etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) etx.TxAttempts = []txmgr.TxAttempt{} err := txStore.LoadTxesAttempts([]*txmgr.Tx{&etx}) @@ -1114,7 +1114,7 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { }) t.Run("load new attempt inserted in current postgres transaction", func(t *testing.T) { - etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 3, 9, time.Now(), fromAddress) + etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 3, 9, time.Now(), fromAddress) etx.TxAttempts = []txmgr.TxAttempt{} q := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) @@ -1154,7 +1154,7 @@ func TestORM_SaveReplacementInProgressAttempt(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("replace eth tx attempt", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) oldAttempt := etx.TxAttempts[0] newAttempt := cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) @@ -1180,7 +1180,7 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("cannot find unstarted tx", func(t *testing.T) { - cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) + mustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) resultEtx := new(txmgr.Tx) err := txStore.FindNextUnstartedTransactionFromAddress(testutils.Context(t), resultEtx, fromAddress, ethClient.ConfiguredChainID()) @@ -1188,7 +1188,7 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { }) t.Run("finds unstarted tx", func(t *testing.T) { - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) resultEtx := new(txmgr.Tx) err := txStore.FindNextUnstartedTransactionFromAddress(testutils.Context(t), resultEtx, fromAddress, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -1206,7 +1206,7 @@ func TestORM_UpdateTxFatalError(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update successful", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) etxPretendError := null.StringFrom("no more toilet paper") etx.Error = etxPretendError @@ -1229,7 +1229,7 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update successful", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) attempt := etx.TxAttempts[0] require.Equal(t, txmgrtypes.TxAttemptInProgress, attempt.State) @@ -1262,7 +1262,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { nonce := evmtypes.Nonce(123) t.Run("update successful", func(t *testing.T) { - etx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) + etx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) etx.Sequence = &nonce attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) @@ -1276,7 +1276,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { }) t.Run("update fails because tx is removed", func(t *testing.T) { - etx := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) + etx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) etx.Sequence = &nonce attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) @@ -1296,7 +1296,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { q = pg.NewQ(db, logger.TestLogger(t), cfg.Database()) t.Run("update replaces abandoned tx with same hash", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) require.Len(t, etx.TxAttempts, 1) zero := models.MustNewDuration(time.Duration(0)) @@ -1314,7 +1314,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { err := txMgr.XXXTestAbandon(fromAddress) // mark transaction as abandoned require.NoError(t, err) - etx2 := cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) + etx2 := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) etx2.Sequence = &nonce attempt2 := cltest.NewLegacyEthTxAttempt(t, etx2.ID) attempt2.Hash = etx.TxAttempts[0].Hash @@ -1329,7 +1329,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { // Same flow as previous test, but without calling txMgr.Abandon() t.Run("duplicate tx hash disallowed in tx_eth_attempts", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) require.Len(t, etx.TxAttempts, 1) etx.State = txmgrcommon.TxUnstarted @@ -1357,7 +1357,7 @@ func TestORM_GetTxInProgress(t *testing.T) { }) t.Run("get 1 in progress eth transaction", func(t *testing.T) { - etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) + etx := mustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) etxResult, err := txStore.GetTxInProgress(testutils.Context(t), fromAddress) require.NoError(t, err) @@ -1382,7 +1382,7 @@ func TestORM_HasInProgressTransaction(t *testing.T) { }) t.Run("has in progress eth transaction", func(t *testing.T) { - cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) + mustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) exists, err := txStore.HasInProgressTransaction(testutils.Context(t), fromAddress, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -1422,9 +1422,9 @@ func TestORM_CountUnstartedTransactions(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) - cltest.MustCreateUnstartedGeneratedTx(t, txStore, otherAddress, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) + mustCreateUnstartedGeneratedTx(t, txStore, otherAddress, &cltest.FixtureChainID) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress) count, err := txStore.CountUnstartedTransactions(testutils.Context(t), fromAddress, &cltest.FixtureChainID) @@ -1456,7 +1456,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { // deliberately one extra to exceed limit for i := 0; i <= int(maxUnconfirmedTransactions); i++ { - cltest.MustCreateUnstartedTx(t, txStore, otherAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, otherAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) } t.Run("with eth_txes from another address returns nil", func(t *testing.T) { @@ -1465,7 +1465,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { }) for i := 0; i <= int(maxUnconfirmedTransactions); i++ { - cltest.MustInsertFatalErrorEthTx(t, txStore, otherAddress) + mustInsertFatalErrorEthTx(t, txStore, otherAddress) } t.Run("ignores fatally_errored transactions", func(t *testing.T) { @@ -1474,7 +1474,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { }) var n int64 - cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(n), fromAddress) + mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(n), fromAddress) n++ cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, n, fromAddress) n++ @@ -1496,7 +1496,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { }) for i := 0; i < int(maxUnconfirmedTransactions)-1; i++ { - cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) } t.Run("with fewer unstarted eth_txes than limit returns nil", func(t *testing.T) { @@ -1504,14 +1504,14 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { require.NoError(t, err) }) - cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) t.Run("with equal or more unstarted eth_txes than limit returns error", func(t *testing.T) { err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("cannot create transaction; too many unstarted transactions in the queue (2/%d). WARNING: Hitting EVM.Transactions.MaxQueued", maxUnconfirmedTransactions)) - cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) + mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) err = txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("cannot create transaction; too many unstarted transactions in the queue (3/%d). WARNING: Hitting EVM.Transactions.MaxQueued", maxUnconfirmedTransactions)) @@ -1533,7 +1533,7 @@ func TestORM_CreateTransaction(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTxStore(t, db, cfg.Database()) + txStore := newTxStore(t, db, cfg.Database()) kst := cltest.NewKeyStore(t, db, cfg.Database()) _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) @@ -1635,7 +1635,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTxStore(t, db, cfg.Database()) + txStore := newTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1644,7 +1644,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { subject1 := uuid.New() strategy1 := txmgrcommon.NewDropOldestStrategy(subject1, uint32(5), cfg.Database().DefaultQueryTimeout()) for i := 0; i < 5; i++ { - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, cltest.EvmTxRequestWithStrategy(strategy1)) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, txRequestWithStrategy(strategy1)) } testutils.AssertCountPerSubject(t, db, int64(5), subject1) }) @@ -1653,7 +1653,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { subject2 := uuid.New() strategy2 := txmgrcommon.NewDropOldestStrategy(subject2, uint32(3), cfg.Database().DefaultQueryTimeout()) for i := 0; i < 5; i++ { - cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, cltest.EvmTxRequestWithStrategy(strategy2)) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, txRequestWithStrategy(strategy2)) } testutils.AssertCountPerSubject(t, db, int64(3), subject2) }) diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 20cc27a675..67216c9fd1 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -64,7 +64,7 @@ func TestReaper_ReapTxes(t *testing.T) { }) // Confirmed in block number 5 - cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, from, nonce, 5) + mustInsertConfirmedEthTxWithReceipt(t, txStore, from, nonce, 5) t.Run("skips if threshold=0", func(t *testing.T) { config := txmgrmocks.NewReaperConfig(t) @@ -119,7 +119,7 @@ func TestReaper_ReapTxes(t *testing.T) { cltest.AssertCount(t, db, "evm.txes", 0) }) - cltest.MustInsertFatalErrorEthTx(t, txStore, from) + mustInsertFatalErrorEthTx(t, txStore, from) t.Run("deletes errored evm.txes that exceed the age threshold", func(t *testing.T) { config := txmgrmocks.NewReaperConfig(t) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index e27cea137b..bab18f445b 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -1,6 +1,7 @@ package txmgr_test import ( + "bytes" "context" "encoding/json" "fmt" @@ -8,16 +9,19 @@ import ( "testing" "time" - gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" "github.com/jmoiron/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" + txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -26,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -34,6 +39,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -145,7 +151,7 @@ func TestTxm_CreateTransaction(t *testing.T) { assert.Equal(t, subject, etx.Subject.UUID) }) - cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, fromAddress) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, fromAddress) t.Run("with queue at capacity does not insert eth_tx", func(t *testing.T) { evmConfig.MaxQueued = uint64(1) @@ -246,8 +252,8 @@ func TestTxm_CreateTransaction(t *testing.T) { // max uint256 is 1.1579209e+77 testDefaultGlobalSubID := crypto.Keccak256Hash([]byte("sub id")).String() jobID := int32(25) - requestID := gethcommon.HexToHash("abcd") - requestTxHash := gethcommon.HexToHash("dcba") + requestID := common.HexToHash("abcd") + requestTxHash := common.HexToHash("dcba") meta := &txmgr.TxMeta{ JobID: &jobID, RequestID: &requestID, @@ -393,7 +399,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) evmConfig.MaxQueued = uint64(1) - cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherKey.Address) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherKey.Address) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) @@ -417,7 +423,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) evmConfig.MaxQueued = uint64(1) - cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, thisKey.Address) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, thisKey.Address) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) @@ -471,7 +477,7 @@ func TestTxm_Lifecycle(t *testing.T) { evmConfig.ReaperThreshold = 1 * time.Hour evmConfig.ReaperInterval = 1 * time.Hour - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return([]gethcommon.Address{}, nil) + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return([]common.Address{}, nil) keyChangeCh := make(chan struct{}) unsub := cltest.NewAwaiter() @@ -495,9 +501,9 @@ func TestTxm_Lifecycle(t *testing.T) { keyState := cltest.MustGenerateRandomKeyState(t) - addr := []gethcommon.Address{keyState.Address.Address()} + addr := []common.Address{keyState.Address.Address()} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addr, nil) - ethClient.On("PendingNonceAt", mock.AnythingOfType("*context.cancelCtx"), gethcommon.Address{}).Return(uint64(0), nil).Maybe() + ethClient.On("PendingNonceAt", mock.AnythingOfType("*context.cancelCtx"), common.Address{}).Return(uint64(0), nil).Maybe() keyChangeCh <- struct{}{} require.NoError(t, txm.Close()) @@ -568,3 +574,244 @@ func TestTxm_Reset(t *testing.T) { assert.Equal(t, 0, count) }) } + +func newTxStore(t *testing.T, db *sqlx.DB, cfg pg.QConfig) txmgr.EvmTxStore { + return txmgr.NewTxStore(db, logger.TestLogger(t), cfg) +} + +func newEthReceipt(blockNumber int64, blockHash common.Hash, txHash common.Hash, status uint64) txmgr.Receipt { + transactionIndex := uint(cltest.NewRandomPositiveInt64()) + + receipt := evmtypes.Receipt{ + BlockNumber: big.NewInt(blockNumber), + BlockHash: blockHash, + TxHash: txHash, + TransactionIndex: transactionIndex, + Status: status, + } + + r := txmgr.Receipt{ + BlockNumber: blockNumber, + BlockHash: blockHash, + TxHash: txHash, + TransactionIndex: transactionIndex, + Receipt: receipt, + } + return r +} + +func mustInsertEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, blockNumber int64, blockHash common.Hash, txHash common.Hash) txmgr.Receipt { + r := newEthReceipt(blockNumber, blockHash, txHash, 0x1) + id, err := txStore.InsertReceipt(&r.Receipt) + require.NoError(t, err) + r.ID = id + return r +} + +func mustInsertRevertedEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, blockNumber int64, blockHash common.Hash, txHash common.Hash) txmgr.Receipt { + r := newEthReceipt(blockNumber, blockHash, txHash, 0x0) + id, err := txStore.InsertReceipt(&r.Receipt) + require.NoError(t, err) + r.ID = id + return r +} + +// Inserts into evm.receipts but does not update evm.txes or evm.tx_attempts +func mustInsertConfirmedEthTxWithReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address, nonce, blockNum int64) (etx txmgr.Tx) { + etx = cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, nonce, blockNum, fromAddress) + mustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), etx.TxAttempts[0].Hash) + return etx +} + +func mustInsertConfirmedEthTxBySaveFetchedReceipts(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address, nonce int64, blockNum int64, chainID big.Int) (etx txmgr.Tx) { + etx = cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, nonce, blockNum, fromAddress) + receipt := evmtypes.Receipt{ + TxHash: etx.TxAttempts[0].Hash, + BlockHash: utils.NewHash(), + BlockNumber: big.NewInt(nonce), + TransactionIndex: uint(1), + } + err := txStore.SaveFetchedReceipts(testutils.Context(t), []*evmtypes.Receipt{&receipt}, &chainID) + require.NoError(t, err) + return etx +} + +func mustInsertFatalErrorEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address) txmgr.Tx { + etx := cltest.NewEthTx(fromAddress) + etx.Error = null.StringFrom("something exploded") + etx.State = txmgrcommon.TxFatalError + + require.NoError(t, txStore.InsertTx(&etx)) + return etx +} + +func mustInsertUnconfirmedEthTxWithAttemptState(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, txAttemptState txmgrtypes.TxAttemptState, opts ...interface{}) txmgr.Tx { + etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) + attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) + + tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + rlp := new(bytes.Buffer) + require.NoError(t, tx.EncodeRLP(rlp)) + attempt.SignedRawTx = rlp.Bytes() + + attempt.State = txAttemptState + require.NoError(t, txStore.InsertTxAttempt(&attempt)) + etx, err := txStore.FindTxWithAttempts(etx.ID) + require.NoError(t, err) + return etx +} + +func mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, opts ...interface{}) txmgr.Tx { + etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) + attempt := cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) + + addr := testutils.NewAddress() + dtx := types.DynamicFeeTx{ + ChainID: big.NewInt(0), + Nonce: uint64(nonce), + GasTipCap: big.NewInt(1), + GasFeeCap: big.NewInt(1), + Gas: 242, + To: &addr, + Value: big.NewInt(342), + Data: []byte{2, 3, 4}, + } + tx := types.NewTx(&dtx) + rlp := new(bytes.Buffer) + require.NoError(t, tx.EncodeRLP(rlp)) + attempt.SignedRawTx = rlp.Bytes() + + attempt.State = txmgrtypes.TxAttemptBroadcast + require.NoError(t, txStore.InsertTxAttempt(&attempt)) + etx, err := txStore.FindTxWithAttempts(etx.ID) + require.NoError(t, err) + return etx +} + +func mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address) txmgr.Tx { + timeNow := time.Now() + etx := cltest.NewEthTx(fromAddress) + + etx.BroadcastAt = &timeNow + etx.InitialBroadcastAt = &timeNow + n := evmtypes.Nonce(nonce) + etx.Sequence = &n + etx.State = txmgrcommon.TxUnconfirmed + require.NoError(t, txStore.InsertTx(&etx)) + attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) + + tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + rlp := new(bytes.Buffer) + require.NoError(t, tx.EncodeRLP(rlp)) + attempt.SignedRawTx = rlp.Bytes() + + attempt.State = txmgrtypes.TxAttemptInsufficientFunds + require.NoError(t, txStore.InsertTxAttempt(&attempt)) + etx, err := txStore.FindTxWithAttempts(etx.ID) + require.NoError(t, err) + return etx +} + +func mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( + t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, broadcastBeforeBlockNum int64, + broadcastAt time.Time, fromAddress common.Address) txmgr.Tx { + etx := cltest.NewEthTx(fromAddress) + + etx.BroadcastAt = &broadcastAt + etx.InitialBroadcastAt = &broadcastAt + n := evmtypes.Nonce(nonce) + etx.Sequence = &n + etx.State = txmgrcommon.TxConfirmedMissingReceipt + require.NoError(t, txStore.InsertTx(&etx)) + attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) + attempt.BroadcastBeforeBlockNum = &broadcastBeforeBlockNum + attempt.State = txmgrtypes.TxAttemptBroadcast + require.NoError(t, txStore.InsertTxAttempt(&attempt)) + etx.TxAttempts = append(etx.TxAttempts, attempt) + return etx +} + +func mustInsertInProgressEthTxWithAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce evmtypes.Nonce, fromAddress common.Address) txmgr.Tx { + etx := cltest.NewEthTx(fromAddress) + + etx.Sequence = &nonce + etx.State = txmgrcommon.TxInProgress + require.NoError(t, txStore.InsertTx(&etx)) + attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) + tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + rlp := new(bytes.Buffer) + require.NoError(t, tx.EncodeRLP(rlp)) + attempt.SignedRawTx = rlp.Bytes() + attempt.State = txmgrtypes.TxAttemptInProgress + require.NoError(t, txStore.InsertTxAttempt(&attempt)) + etx, err := txStore.FindTxWithAttempts(etx.ID) + require.NoError(t, err) + return etx +} + +func mustCreateUnstartedGeneratedTx(t testing.TB, txStore txmgr.EvmTxStore, fromAddress common.Address, chainID *big.Int, opts ...func(*txmgr.TxRequest)) (tx txmgr.Tx) { + txRequest := txmgr.TxRequest{ + FromAddress: fromAddress, + } + + // Apply the default options + withDefaults()(&txRequest) + // Apply the optional parameters + for _, opt := range opts { + opt(&txRequest) + } + return mustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, chainID) +} + +func withDefaults() func(*txmgr.TxRequest) { + return func(tx *txmgr.TxRequest) { + tx.ToAddress = testutils.NewAddress() + tx.EncodedPayload = []byte{1, 2, 3} + tx.Value = big.Int(assets.NewEthValue(142)) + tx.FeeLimit = uint32(1000000000) + tx.Strategy = txmgrcommon.NewSendEveryStrategy() + // Set default values for other fields if needed + } +} + +func mustCreateUnstartedTx(t testing.TB, txStore txmgr.EvmTxStore, fromAddress common.Address, toAddress common.Address, encodedPayload []byte, gasLimit uint32, value big.Int, chainID *big.Int, opts ...interface{}) (tx txmgr.Tx) { + txRequest := txmgr.TxRequest{ + FromAddress: fromAddress, + ToAddress: toAddress, + EncodedPayload: encodedPayload, + Value: value, + FeeLimit: gasLimit, + Strategy: txmgrcommon.NewSendEveryStrategy(), + } + + return mustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, chainID) +} + +func mustCreateUnstartedTxFromEvmTxRequest(t testing.TB, txStore txmgr.EvmTxStore, txRequest txmgr.TxRequest, chainID *big.Int) (tx txmgr.Tx) { + tx, err := txStore.CreateTransaction(testutils.Context(t), txRequest, chainID) + require.NoError(t, err) + return tx +} + +func txRequestWithStrategy(strategy txmgrtypes.TxStrategy) func(*txmgr.TxRequest) { + return func(tx *txmgr.TxRequest) { + tx.Strategy = strategy + } +} + +func txRequestWithChecker(checker txmgr.TransmitCheckerSpec) func(*txmgr.TxRequest) { + return func(tx *txmgr.TxRequest) { + tx.Checker = checker + } +} +func txRequestWithValue(value big.Int) func(*txmgr.TxRequest) { + return func(tx *txmgr.TxRequest) { + tx.Value = value + } +} + +func txRequestWithIdempotencyKey(idempotencyKey string) func(*txmgr.TxRequest) { + return func(tx *txmgr.TxRequest) { + tx.IdempotencyKey = &idempotencyKey + } +} diff --git a/core/cmd/admin_commands_test.go b/core/cmd/admin_commands_test.go index 954e3577d3..fc4c1b7e95 100644 --- a/core/cmd/admin_commands_test.go +++ b/core/cmd/admin_commands_test.go @@ -43,7 +43,7 @@ func TestShell_CreateUser(t *testing.T) { test := tt t.Run(test.name, func(t *testing.T) { set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.CreateUser, set, "") + flagSetApplyFromAction(client.CreateUser, set, "") require.NoError(t, set.Set("email", test.email)) require.NoError(t, set.Set("role", test.role)) @@ -83,7 +83,7 @@ func TestShell_ChangeRole(t *testing.T) { test := tt t.Run(test.name, func(t *testing.T) { set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ChangeRole, set, "") + flagSetApplyFromAction(client.ChangeRole, set, "") require.NoError(t, set.Set("email", test.email)) require.NoError(t, set.Set("new-role", test.role)) @@ -118,7 +118,7 @@ func TestShell_DeleteUser(t *testing.T) { test := tt t.Run(test.name, func(t *testing.T) { set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteUser, set, "") + flagSetApplyFromAction(client.DeleteUser, set, "") require.NoError(t, set.Set("email", test.email)) c := cli.NewContext(nil, set, nil) @@ -138,7 +138,7 @@ func TestShell_ListUsers(t *testing.T) { require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ListUsers, set, "") + flagSetApplyFromAction(client.ListUsers, set, "") c := cli.NewContext(nil, set, nil) buffer := bytes.NewBufferString("") diff --git a/core/cmd/blocks_commands_test.go b/core/cmd/blocks_commands_test.go index a972df67d6..d0c0e118f9 100644 --- a/core/cmd/blocks_commands_test.go +++ b/core/cmd/blocks_commands_test.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -24,7 +23,7 @@ func Test_ReplayFromBlock(t *testing.T) { client, _ := app.NewShellAndRenderer() set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ReplayFromBlock, set, "") + flagSetApplyFromAction(client.ReplayFromBlock, set, "") //Incorrect block number require.NoError(t, set.Set("block-number", "0")) diff --git a/core/cmd/bridge_commands_test.go b/core/cmd/bridge_commands_test.go index 4f043ff87e..fae5d68e67 100644 --- a/core/cmd/bridge_commands_test.go +++ b/core/cmd/bridge_commands_test.go @@ -111,7 +111,7 @@ func TestShell_ShowBridge(t *testing.T) { require.NoError(t, app.BridgeORM().CreateBridgeType(bt)) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ShowBridge, set, "") + flagSetApplyFromAction(client.ShowBridge, set, "") require.NoError(t, set.Parse([]string{bt.Name.String()})) @@ -148,7 +148,7 @@ func TestShell_CreateBridge(t *testing.T) { test := tt t.Run(test.name, func(t *testing.T) { set := flag.NewFlagSet("bridge", 0) - cltest.FlagSetApplyFromAction(client.CreateBridge, set, "") + flagSetApplyFromAction(client.CreateBridge, set, "") require.NoError(t, set.Parse([]string{test.param})) @@ -177,7 +177,7 @@ func TestShell_RemoveBridge(t *testing.T) { require.NoError(t, err) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoveBridge, set, "") + flagSetApplyFromAction(client.RemoveBridge, set, "") require.NoError(t, set.Parse([]string{bt.Name.String()})) diff --git a/core/cmd/cosmos_keys_commands_test.go b/core/cmd/cosmos_keys_commands_test.go index 05a26fe84d..2cab11379d 100644 --- a/core/cmd/cosmos_keys_commands_test.go +++ b/core/cmd/cosmos_keys_commands_test.go @@ -95,7 +95,7 @@ func TestShell_CosmosKeys(t *testing.T) { require.NoError(t, err) requireCosmosKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(cmd.NewCosmosKeysClient(client).DeleteKey, set, "cosmos") + flagSetApplyFromAction(cmd.NewCosmosKeysClient(client).DeleteKey, set, "cosmos") strID := key.ID() require.NoError(tt, set.Set("yes", "true")) @@ -121,7 +121,7 @@ func TestShell_CosmosKeys(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test Cosmos export", 0) - cltest.FlagSetApplyFromAction(cmd.NewCosmosKeysClient(client).ExportKey, set, "cosmos") + flagSetApplyFromAction(cmd.NewCosmosKeysClient(client).ExportKey, set, "cosmos") require.NoError(tt, set.Parse([]string{"0"})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -135,7 +135,7 @@ func TestShell_CosmosKeys(t *testing.T) { // Export test set = flag.NewFlagSet("test Cosmos export", 0) - cltest.FlagSetApplyFromAction(cmd.NewCosmosKeysClient(client).ExportKey, set, "cosmos") + flagSetApplyFromAction(cmd.NewCosmosKeysClient(client).ExportKey, set, "cosmos") require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -150,7 +150,7 @@ func TestShell_CosmosKeys(t *testing.T) { requireCosmosKeyCount(t, app, 0) set = flag.NewFlagSet("test Cosmos import", 0) - cltest.FlagSetApplyFromAction(cmd.NewCosmosKeysClient(client).ImportKey, set, "cosmos") + flagSetApplyFromAction(cmd.NewCosmosKeysClient(client).ImportKey, set, "cosmos") require.NoError(tt, set.Parse([]string{keyName})) require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) diff --git a/core/cmd/cosmos_transaction_commands_test.go b/core/cmd/cosmos_transaction_commands_test.go index f54ccaf4a6..5b5454eed4 100644 --- a/core/cmd/cosmos_transaction_commands_test.go +++ b/core/cmd/cosmos_transaction_commands_test.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/params" "github.com/smartcontractkit/chainlink/v2/core/cmd" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" @@ -93,7 +92,7 @@ func TestShell_SendCosmosCoins(t *testing.T) { require.NoError(t, err) set := flag.NewFlagSet("sendcosmoscoins", 0) - cltest.FlagSetApplyFromAction(client.CosmosSendNativeToken, set, "cosmos") + flagSetApplyFromAction(client.CosmosSendNativeToken, set, "cosmos") require.NoError(t, set.Set("id", chainID)) require.NoError(t, set.Parse([]string{nativeToken, tt.amount, from.Address.String(), to.Address.String()})) diff --git a/core/cmd/csa_keys_commands_test.go b/core/cmd/csa_keys_commands_test.go index 23749476ac..869608fa72 100644 --- a/core/cmd/csa_keys_commands_test.go +++ b/core/cmd/csa_keys_commands_test.go @@ -98,7 +98,7 @@ func TestShell_ImportExportCsaKey(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test CSA export", 0) - cltest.FlagSetApplyFromAction(client.ExportCSAKey, set, "") + flagSetApplyFromAction(client.ExportCSAKey, set, "") require.NoError(t, set.Parse([]string{"0"})) require.NoError(t, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -111,7 +111,7 @@ func TestShell_ImportExportCsaKey(t *testing.T) { // Export test set = flag.NewFlagSet("test CSA export", 0) - cltest.FlagSetApplyFromAction(client.ExportCSAKey, set, "") + flagSetApplyFromAction(client.ExportCSAKey, set, "") require.NoError(t, set.Parse([]string{fmt.Sprint(key.ID())})) require.NoError(t, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -127,7 +127,7 @@ func TestShell_ImportExportCsaKey(t *testing.T) { //Import test set = flag.NewFlagSet("test CSA import", 0) - cltest.FlagSetApplyFromAction(client.ImportCSAKey, set, "") + flagSetApplyFromAction(client.ImportCSAKey, set, "") require.NoError(t, set.Parse([]string{keyName})) require.NoError(t, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) diff --git a/core/cmd/dkgencrypt_keys_commands_test.go b/core/cmd/dkgencrypt_keys_commands_test.go index 61e343569c..a7505ce46d 100644 --- a/core/cmd/dkgencrypt_keys_commands_test.go +++ b/core/cmd/dkgencrypt_keys_commands_test.go @@ -94,7 +94,7 @@ func TestShell_DKGEncryptKeys(t *testing.T) { assert.NoError(tt, err) requireDKGEncryptKeyCount(tt, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).DeleteKey, set, "") + flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).DeleteKey, set, "") require.NoError(tt, set.Set("yes", "true")) @@ -122,7 +122,7 @@ func TestShell_DKGEncryptKeys(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test DKGEncrypt export", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ExportKey, set, "") + flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ExportKey, set, "") require.NoError(tt, set.Parse([]string{"0"})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -135,7 +135,7 @@ func TestShell_DKGEncryptKeys(t *testing.T) { // Export test set = flag.NewFlagSet("test DKGEncrypt export", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ExportKey, set, "") + flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ExportKey, set, "") require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -151,7 +151,7 @@ func TestShell_DKGEncryptKeys(t *testing.T) { //Import test set = flag.NewFlagSet("test DKGEncrypt import", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ImportKey, set, "") + flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ImportKey, set, "") require.NoError(tt, set.Parse([]string{keyName})) require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) diff --git a/core/cmd/dkgsign_keys_commands_test.go b/core/cmd/dkgsign_keys_commands_test.go index 27413e6ae7..1948800d67 100644 --- a/core/cmd/dkgsign_keys_commands_test.go +++ b/core/cmd/dkgsign_keys_commands_test.go @@ -94,7 +94,7 @@ func TestShell_DKGSignKeys(t *testing.T) { assert.NoError(tt, err) requireDKGSignKeyCount(tt, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).DeleteKey, set, "") + flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).DeleteKey, set, "") require.NoError(tt, set.Set("yes", "true")) strID := key.ID() @@ -121,7 +121,7 @@ func TestShell_DKGSignKeys(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test DKGSign export", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ExportKey, set, "") + flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ExportKey, set, "") require.NoError(tt, set.Parse([]string{"0"})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -134,7 +134,7 @@ func TestShell_DKGSignKeys(t *testing.T) { // Export test set = flag.NewFlagSet("test DKGSign export", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ExportKey, set, "") + flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ExportKey, set, "") require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -149,7 +149,7 @@ func TestShell_DKGSignKeys(t *testing.T) { requireDKGSignKeyCount(tt, app, 0) set = flag.NewFlagSet("test DKGSign import", 0) - cltest.FlagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ImportKey, set, "") + flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ImportKey, set, "") require.NoError(tt, set.Parse([]string{keyName})) require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index 293a2d3f6d..3eb45e27bd 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -191,7 +191,7 @@ func TestShell_CreateETHKey(t *testing.T) { id := big.NewInt(0) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.CreateETHKey, set, "") + flagSetApplyFromAction(client.CreateETHKey, set, "") require.NoError(t, set.Set("evm-chain-id", testutils.FixtureChainID.String())) @@ -224,7 +224,7 @@ func TestShell_DeleteETHKey(t *testing.T) { // Delete the key set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteETHKey, set, "") + flagSetApplyFromAction(client.DeleteETHKey, set, "") require.NoError(t, set.Set("yes", "true")) require.NoError(t, set.Parse([]string{key.Address.Hex()})) @@ -257,7 +257,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { ethKeyStore := app.GetKeyStore().Eth() set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("file", "internal/fixtures/apicredentials")) require.NoError(t, set.Set("bypass-version-check", "true")) @@ -281,7 +281,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { defer os.RemoveAll(testdir) keyfilepath := filepath.Join(testdir, "key") set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ExportETHKey, set, "") + flagSetApplyFromAction(client.ExportETHKey, set, "") require.NoError(t, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) require.NoError(t, set.Set("output", keyfilepath)) @@ -293,7 +293,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { // Delete the key set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteETHKey, set, "") + flagSetApplyFromAction(client.DeleteETHKey, set, "") require.NoError(t, set.Set("yes", "true")) require.NoError(t, set.Parse([]string{address})) @@ -308,7 +308,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { // Import the key set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ImportETHKey, set, "") + flagSetApplyFromAction(client.ImportETHKey, set, "") require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) @@ -321,7 +321,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { r.Renders = nil set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ListETHKeys, set, "") + flagSetApplyFromAction(client.ListETHKeys, set, "") c = cli.NewContext(nil, set, nil) err = client.ListETHKeys(c) require.NoError(t, err) @@ -332,7 +332,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { // Export test invalid id keyName := keyNameForTest(t) set = flag.NewFlagSet("test Eth export invalid id", 0) - cltest.FlagSetApplyFromAction(client.ExportETHKey, set, "") + flagSetApplyFromAction(client.ExportETHKey, set, "") require.NoError(t, set.Parse([]string{"999"})) require.NoError(t, set.Set("new-password", "../internal/fixtures/apicredentials")) @@ -365,7 +365,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(commonassets.NewLinkFromJuels(42), nil) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("file", "internal/fixtures/apicredentials")) require.NoError(t, set.Set("bypass-version-check", "true")) @@ -389,7 +389,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { defer os.RemoveAll(testdir) keyfilepath := filepath.Join(testdir, "key") set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ExportETHKey, set, "") + flagSetApplyFromAction(client.ExportETHKey, set, "") require.NoError(t, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) require.NoError(t, set.Set("output", keyfilepath)) @@ -401,7 +401,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { // Delete the key set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteETHKey, set, "") + flagSetApplyFromAction(client.DeleteETHKey, set, "") require.NoError(t, set.Set("yes", "true")) require.NoError(t, set.Parse([]string{address})) @@ -414,7 +414,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { // Import the key set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ImportETHKey, set, "") + flagSetApplyFromAction(client.ImportETHKey, set, "") require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) @@ -428,7 +428,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { r.Renders = nil set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.ListETHKeys, set, "") + flagSetApplyFromAction(client.ListETHKeys, set, "") c = cli.NewContext(nil, set, nil) err = client.ListETHKeys(c) require.NoError(t, err) @@ -439,7 +439,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { // Export test invalid id keyName := keyNameForTest(t) set = flag.NewFlagSet("test Eth export invalid id", 0) - cltest.FlagSetApplyFromAction(client.ExportETHKey, set, "") + flagSetApplyFromAction(client.ExportETHKey, set, "") require.NoError(t, set.Parse([]string{"999"})) require.NoError(t, set.Set("new-password", "../internal/fixtures/apicredentials")) diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index e071d875f0..6c079a1249 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -37,7 +37,7 @@ func TestShell_IndexTransactions(t *testing.T) { // page 1 set := flag.NewFlagSet("test transactions", 0) - cltest.FlagSetApplyFromAction(client.IndexTransactions, set, "") + flagSetApplyFromAction(client.IndexTransactions, set, "") require.NoError(t, set.Set("page", "1")) @@ -51,7 +51,7 @@ func TestShell_IndexTransactions(t *testing.T) { // page 2 which doesn't exist set = flag.NewFlagSet("test txattempts", 0) - cltest.FlagSetApplyFromAction(client.IndexTransactions, set, "") + flagSetApplyFromAction(client.IndexTransactions, set, "") require.NoError(t, set.Set("page", "2")) @@ -77,7 +77,7 @@ func TestShell_ShowTransaction(t *testing.T) { attempt := tx.TxAttempts[0] set := flag.NewFlagSet("test get tx", 0) - cltest.FlagSetApplyFromAction(client.ShowTransaction, set, "") + flagSetApplyFromAction(client.ShowTransaction, set, "") require.NoError(t, set.Parse([]string{attempt.Hash.String()})) @@ -101,7 +101,7 @@ func TestShell_IndexTxAttempts(t *testing.T) { // page 1 set := flag.NewFlagSet("test txattempts", 0) - cltest.FlagSetApplyFromAction(client.IndexTxAttempts, set, "") + flagSetApplyFromAction(client.IndexTxAttempts, set, "") require.NoError(t, set.Set("page", "1")) @@ -115,7 +115,7 @@ func TestShell_IndexTxAttempts(t *testing.T) { // page 2 which doesn't exist set = flag.NewFlagSet("test transactions", 0) - cltest.FlagSetApplyFromAction(client.IndexTxAttempts, set, "") + flagSetApplyFromAction(client.IndexTxAttempts, set, "") require.NoError(t, set.Set("page", "2")) @@ -158,7 +158,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { db := app.GetSqlxDB() set := flag.NewFlagSet("sendether", 0) - cltest.FlagSetApplyFromAction(client.SendEther, set, "") + flagSetApplyFromAction(client.SendEther, set, "") amount := "100.5" to := "0x342156c8d3bA54Abc67920d35ba1d1e67201aC9C" @@ -218,7 +218,7 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { db := app.GetSqlxDB() set := flag.NewFlagSet("sendether", 0) - cltest.FlagSetApplyFromAction(client.SendEther, set, "") + flagSetApplyFromAction(client.SendEther, set, "") require.NoError(t, set.Set("id", testutils.FixtureChainID.String())) require.NoError(t, set.Set("wei", "false")) diff --git a/core/cmd/forwarders_commands_test.go b/core/cmd/forwarders_commands_test.go index b08d94f64d..179216b8e4 100644 --- a/core/cmd/forwarders_commands_test.go +++ b/core/cmd/forwarders_commands_test.go @@ -73,7 +73,7 @@ func TestShell_TrackEVMForwarder(t *testing.T) { // Create the fwdr set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.TrackForwarder, set, "") + flagSetApplyFromAction(client.TrackForwarder, set, "") require.NoError(t, set.Set("address", utils.RandomAddress().Hex())) require.NoError(t, set.Set("evm-chain-id", id.String())) @@ -92,7 +92,7 @@ func TestShell_TrackEVMForwarder(t *testing.T) { // Delete fwdr set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteForwarder, set, "") + flagSetApplyFromAction(client.DeleteForwarder, set, "") require.NoError(t, set.Parse([]string{createOutput.ID})) @@ -118,7 +118,7 @@ func TestShell_TrackEVMForwarder_BadAddress(t *testing.T) { // Create the fwdr set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.TrackForwarder, set, "") + flagSetApplyFromAction(client.TrackForwarder, set, "") require.NoError(t, set.Set("address", "0xWrongFormatAddress")) require.NoError(t, set.Set("evm-chain-id", id.String())) @@ -137,7 +137,7 @@ func TestShell_DeleteEVMForwarders_MissingFwdId(t *testing.T) { // Delete fwdr without id set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteForwarder, set, "") + flagSetApplyFromAction(client.DeleteForwarder, set, "") c := cli.NewContext(nil, set, nil) require.Equal(t, "must pass the forwarder id to be archived", client.DeleteForwarder(c).Error()) diff --git a/core/cmd/jobs_commands_test.go b/core/cmd/jobs_commands_test.go index b83b17f0be..04908e18ff 100644 --- a/core/cmd/jobs_commands_test.go +++ b/core/cmd/jobs_commands_test.go @@ -313,7 +313,7 @@ func TestShell_ListFindJobs(t *testing.T) { // Create the job fs := flag.NewFlagSet("", flag.ExitOnError) - cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") + flagSetApplyFromAction(client.CreateJob, fs, "") require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) @@ -339,7 +339,7 @@ func TestShell_ShowJob(t *testing.T) { // Create the job fs := flag.NewFlagSet("", flag.ExitOnError) - cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") + flagSetApplyFromAction(client.CreateJob, fs, "") require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) @@ -382,7 +382,7 @@ func TestShell_CreateJobV2(t *testing.T) { requireJobsCount(t, app.JobORM(), 0) fs := flag.NewFlagSet("", flag.ExitOnError) - cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") + flagSetApplyFromAction(client.CreateJob, fs, "") nameAndExternalJobID := uuid.New() spec := fmt.Sprintf(ocrBootstrapSpec, nameAndExternalJobID, nameAndExternalJobID) @@ -413,7 +413,7 @@ func TestShell_DeleteJob(t *testing.T) { // Create the job fs := flag.NewFlagSet("", flag.ExitOnError) - cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") + flagSetApplyFromAction(client.CreateJob, fs, "") require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) @@ -432,12 +432,12 @@ func TestShell_DeleteJob(t *testing.T) { // Must supply job id set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteJob, set, "") + flagSetApplyFromAction(client.DeleteJob, set, "") c := cli.NewContext(nil, set, nil) require.Equal(t, "must pass the job id to be archived", client.DeleteJob(c).Error()) set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteJob, set, "") + flagSetApplyFromAction(client.DeleteJob, set, "") require.NoError(t, set.Parse([]string{output.ID})) diff --git a/core/cmd/ocr2_keys_commands_test.go b/core/cmd/ocr2_keys_commands_test.go index 88ea426747..dd2ac2544d 100644 --- a/core/cmd/ocr2_keys_commands_test.go +++ b/core/cmd/ocr2_keys_commands_test.go @@ -97,7 +97,7 @@ func TestShell_OCR2Keys(t *testing.T) { client, r := app.NewShellAndRenderer() set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.CreateOCR2KeyBundle, set, "") + flagSetApplyFromAction(client.CreateOCR2KeyBundle, set, "") require.NoError(tt, set.Parse([]string{"evm"})) @@ -119,7 +119,7 @@ func TestShell_OCR2Keys(t *testing.T) { require.NoError(t, err) requireOCR2KeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteOCR2KeyBundle, set, "") + flagSetApplyFromAction(client.DeleteOCR2KeyBundle, set, "") require.NoError(tt, set.Parse([]string{key.ID()})) require.NoError(tt, set.Set("yes", "true")) @@ -147,7 +147,7 @@ func TestShell_OCR2Keys(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test OCR2 export", 0) - cltest.FlagSetApplyFromAction(client.ExportOCR2Key, set, "") + flagSetApplyFromAction(client.ExportOCR2Key, set, "") require.NoError(tt, set.Parse([]string{"0"})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/new_password.txt")) @@ -160,7 +160,7 @@ func TestShell_OCR2Keys(t *testing.T) { // Export set = flag.NewFlagSet("test OCR2 export", 0) - cltest.FlagSetApplyFromAction(client.ExportOCR2Key, set, "") + flagSetApplyFromAction(client.ExportOCR2Key, set, "") require.NoError(tt, set.Parse([]string{key.ID()})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/new_password.txt")) @@ -175,7 +175,7 @@ func TestShell_OCR2Keys(t *testing.T) { requireOCR2KeyCount(t, app, 0) set = flag.NewFlagSet("test OCR2 import", 0) - cltest.FlagSetApplyFromAction(client.ImportOCR2Key, set, "") + flagSetApplyFromAction(client.ImportOCR2Key, set, "") require.NoError(tt, set.Parse([]string{keyName})) require.NoError(tt, set.Set("old-password", "../internal/fixtures/new_password.txt")) diff --git a/core/cmd/ocr_keys_commands_test.go b/core/cmd/ocr_keys_commands_test.go index 2ae765d4d2..aeda900661 100644 --- a/core/cmd/ocr_keys_commands_test.go +++ b/core/cmd/ocr_keys_commands_test.go @@ -111,7 +111,7 @@ func TestShell_DeleteOCRKeyBundle(t *testing.T) { requireOCRKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteOCRKeyBundle, set, "") + flagSetApplyFromAction(client.DeleteOCRKeyBundle, set, "") require.NoError(t, set.Parse([]string{key.ID()})) require.NoError(t, set.Set("yes", "true")) @@ -140,7 +140,7 @@ func TestShell_ImportExportOCRKey(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test OCR export", 0) - cltest.FlagSetApplyFromAction(client.ExportOCRKey, set, "") + flagSetApplyFromAction(client.ExportOCRKey, set, "") require.NoError(t, set.Parse([]string{"0"})) require.NoError(t, set.Set("new-password", "../internal/fixtures/new_password.txt")) @@ -153,7 +153,7 @@ func TestShell_ImportExportOCRKey(t *testing.T) { // Export set = flag.NewFlagSet("test OCR export", 0) - cltest.FlagSetApplyFromAction(client.ExportOCRKey, set, "") + flagSetApplyFromAction(client.ExportOCRKey, set, "") require.NoError(t, set.Parse([]string{key.ID()})) require.NoError(t, set.Set("new-password", "../internal/fixtures/new_password.txt")) @@ -168,7 +168,7 @@ func TestShell_ImportExportOCRKey(t *testing.T) { requireOCRKeyCount(t, app, 0) set = flag.NewFlagSet("test OCR import", 0) - cltest.FlagSetApplyFromAction(client.ImportOCRKey, set, "") + flagSetApplyFromAction(client.ImportOCRKey, set, "") require.NoError(t, set.Parse([]string{keyName})) require.NoError(t, set.Set("old-password", "../internal/fixtures/new_password.txt")) diff --git a/core/cmd/p2p_keys_commands_test.go b/core/cmd/p2p_keys_commands_test.go index 0407c92457..683129fafa 100644 --- a/core/cmd/p2p_keys_commands_test.go +++ b/core/cmd/p2p_keys_commands_test.go @@ -102,7 +102,7 @@ func TestShell_DeleteP2PKey(t *testing.T) { requireP2PKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteP2PKey, set, "") + flagSetApplyFromAction(client.DeleteP2PKey, set, "") require.NoError(t, set.Set("yes", "true")) @@ -132,7 +132,7 @@ func TestShell_ImportExportP2PKeyBundle(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test P2P export", 0) - cltest.FlagSetApplyFromAction(client.ExportP2PKey, set, "") + flagSetApplyFromAction(client.ExportP2PKey, set, "") require.NoError(t, set.Parse([]string{"0"})) require.NoError(t, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -145,7 +145,7 @@ func TestShell_ImportExportP2PKeyBundle(t *testing.T) { // Export test set = flag.NewFlagSet("test P2P export", 0) - cltest.FlagSetApplyFromAction(client.ExportP2PKey, set, "") + flagSetApplyFromAction(client.ExportP2PKey, set, "") require.NoError(t, set.Parse([]string{fmt.Sprint(key.ID())})) require.NoError(t, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -160,7 +160,7 @@ func TestShell_ImportExportP2PKeyBundle(t *testing.T) { requireP2PKeyCount(t, app, 0) set = flag.NewFlagSet("test P2P import", 0) - cltest.FlagSetApplyFromAction(client.ImportP2PKey, set, "") + flagSetApplyFromAction(client.ImportP2PKey, set, "") require.NoError(t, set.Parse([]string{keyName})) require.NoError(t, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 4d906214ef..2dc182944d 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -124,7 +124,7 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { } set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RunNode, set, "") + flagSetApplyFromAction(client.RunNode, set, "") require.NoError(t, set.Set("password", test.pwdfile)) @@ -221,7 +221,7 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { } set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RunNode, set, "") + flagSetApplyFromAction(client.RunNode, set, "") require.NoError(t, set.Set("api", test.apiFile)) @@ -318,7 +318,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { beginningNonce := uint64(7) endingNonce := uint64(10) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(c.RebroadcastTransactions, set, "") + flagSetApplyFromAction(c.RebroadcastTransactions, set, "") require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("beginningNonce", strconv.FormatUint(beginningNonce, 10))) @@ -397,7 +397,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { } set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(c.RebroadcastTransactions, set, "") + flagSetApplyFromAction(c.RebroadcastTransactions, set, "") require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("beginningNonce", strconv.FormatUint(uint64(beginningNonce), 10))) @@ -477,7 +477,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { } set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RebroadcastTransactions, set, "") + flagSetApplyFromAction(client.RebroadcastTransactions, set, "") require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("address", fromAddress.Hex())) diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 91b56ee53a..6143d678a9 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -123,7 +123,7 @@ func TestShell_ReplayBlocks(t *testing.T) { client, _ := app.NewShellAndRenderer() set := flag.NewFlagSet("flagset", 0) - cltest.FlagSetApplyFromAction(client.ReplayFromBlock, set, "") + flagSetApplyFromAction(client.ReplayFromBlock, set, "") require.NoError(t, set.Set("block-number", "42")) require.NoError(t, set.Set("evm-chain-id", "12345678")) @@ -156,7 +156,7 @@ func TestShell_CreateExternalInitiator(t *testing.T) { client, _ := app.NewShellAndRenderer() set := flag.NewFlagSet("create", 0) - cltest.FlagSetApplyFromAction(client.CreateExternalInitiator, set, "") + flagSetApplyFromAction(client.CreateExternalInitiator, set, "") assert.NoError(t, set.Parse(test.args)) c := cli.NewContext(nil, set, nil) @@ -197,7 +197,7 @@ func TestShell_CreateExternalInitiator_Errors(t *testing.T) { initialExis := len(cltest.AllExternalInitiators(t, app.GetSqlxDB())) set := flag.NewFlagSet("create", 0) - cltest.FlagSetApplyFromAction(client.CreateExternalInitiator, set, "") + flagSetApplyFromAction(client.CreateExternalInitiator, set, "") assert.NoError(t, set.Parse(test.args)) c := cli.NewContext(nil, set, nil) @@ -228,7 +228,7 @@ func TestShell_DestroyExternalInitiator(t *testing.T) { require.NoError(t, err) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteExternalInitiator, set, "") + flagSetApplyFromAction(client.DeleteExternalInitiator, set, "") require.NoError(t, set.Parse([]string{exi.Name})) @@ -246,7 +246,7 @@ func TestShell_DestroyExternalInitiator_NotFound(t *testing.T) { client, r := app.NewShellAndRenderer() set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteExternalInitiator, set, "") + flagSetApplyFromAction(client.DeleteExternalInitiator, set, "") require.NoError(t, set.Parse([]string{"bogus-ID"})) @@ -280,7 +280,7 @@ func TestShell_RemoteLogin(t *testing.T) { client := app.NewAuthenticatingShell(prompter) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("file", test.file)) require.NoError(t, set.Set("bypass-version-check", "true")) @@ -318,7 +318,7 @@ func TestShell_RemoteBuildCompatibility(t *testing.T) { // Fails without bypass set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("bypass-version-check", "false")) @@ -329,7 +329,7 @@ func TestShell_RemoteBuildCompatibility(t *testing.T) { // Defaults to false set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") c = cli.NewContext(nil, set, nil) err = client.RemoteLogin(c) assert.Error(t, err) @@ -425,7 +425,7 @@ func TestShell_ChangePassword(t *testing.T) { otherClient := app.NewAuthenticatingShell(prompter) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("file", "../internal/fixtures/apicredentials")) require.NoError(t, set.Set("bypass-version-check", "true")) @@ -473,7 +473,7 @@ func TestShell_Profile_InvalidSecondsParam(t *testing.T) { client := app.NewAuthenticatingShell(prompter) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("file", "../internal/fixtures/apicredentials")) require.NoError(t, set.Set("bypass-version-check", "true")) @@ -504,7 +504,7 @@ func TestShell_Profile(t *testing.T) { client := app.NewAuthenticatingShell(prompter) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("file", "../internal/fixtures/apicredentials")) require.NoError(t, set.Set("bypass-version-check", "true")) @@ -595,7 +595,7 @@ func TestShell_RunOCRJob_HappyPath(t *testing.T) { require.NoError(t, err) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("bypass-version-check", "true")) require.NoError(t, set.Parse([]string{strconv.FormatInt(int64(jb.ID), 10)})) @@ -613,7 +613,7 @@ func TestShell_RunOCRJob_MissingJobID(t *testing.T) { client, _ := app.NewShellAndRenderer() set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Set("bypass-version-check", "true")) @@ -630,7 +630,7 @@ func TestShell_RunOCRJob_JobNotFound(t *testing.T) { client, _ := app.NewShellAndRenderer() set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.RemoteLogin, set, "") + flagSetApplyFromAction(client.RemoteLogin, set, "") require.NoError(t, set.Parse([]string{"1"})) require.NoError(t, set.Set("bypass-version-check", "true")) @@ -659,7 +659,7 @@ func TestShell_AutoLogin(t *testing.T) { client.HTTP = cmd.NewAuthenticatedHTTPClient(app.Logger, app.NewClientOpts(), client.CookieAuthenticator, sr) fs := flag.NewFlagSet("", flag.ExitOnError) - cltest.FlagSetApplyFromAction(client.ListJobs, fs, "") + flagSetApplyFromAction(client.ListJobs, fs, "") err := client.ListJobs(cli.NewContext(nil, fs, nil)) require.NoError(t, err) @@ -687,7 +687,7 @@ func TestShell_AutoLogin_AuthFails(t *testing.T) { client.HTTP = cmd.NewAuthenticatedHTTPClient(app.Logger, app.NewClientOpts(), client.CookieAuthenticator, sr) fs := flag.NewFlagSet("", flag.ExitOnError) - cltest.FlagSetApplyFromAction(client.ListJobs, fs, "") + flagSetApplyFromAction(client.ListJobs, fs, "") err := client.ListJobs(cli.NewContext(nil, fs, nil)) require.Error(t, err) } @@ -716,7 +716,7 @@ func TestShell_SetLogConfig(t *testing.T) { logLevel := "warn" set := flag.NewFlagSet("loglevel", 0) - cltest.FlagSetApplyFromAction(client.SetLogLevel, set, "") + flagSetApplyFromAction(client.SetLogLevel, set, "") require.NoError(t, set.Set("level", logLevel)) @@ -728,7 +728,7 @@ func TestShell_SetLogConfig(t *testing.T) { sqlEnabled := true set = flag.NewFlagSet("logsql", 0) - cltest.FlagSetApplyFromAction(client.SetLogSQL, set, "") + flagSetApplyFromAction(client.SetLogSQL, set, "") require.NoError(t, set.Set("enable", strconv.FormatBool(sqlEnabled))) c = cli.NewContext(nil, set, nil) @@ -739,7 +739,7 @@ func TestShell_SetLogConfig(t *testing.T) { sqlEnabled = false set = flag.NewFlagSet("logsql", 0) - cltest.FlagSetApplyFromAction(client.SetLogSQL, set, "") + flagSetApplyFromAction(client.SetLogSQL, set, "") require.NoError(t, set.Set("disable", "true")) c = cli.NewContext(nil, set, nil) diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index 2a8c2c5586..ade14aa0d8 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -2,15 +2,20 @@ package cmd_test import ( "crypto/rand" + "flag" "fmt" "math/big" "os" "path/filepath" + "reflect" + "runtime" + "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/urfave/cli" "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" @@ -514,3 +519,47 @@ func TestSetupStarkNetRelayer(t *testing.T) { require.Error(t, err) }) } + +// flagSetApplyFromAction applies the flags from action to the flagSet. +// `parentCommand` will filter the app commands and only applies the flags if the command/subcommand has a parent with that name, if left empty no filtering is done +func flagSetApplyFromAction(action interface{}, flagSet *flag.FlagSet, parentCommand string) { + cliApp := cmd.Shell{} + app := cmd.NewApp(&cliApp) + + foundName := parentCommand == "" + actionFuncName := getFuncName(action) + + for _, command := range app.Commands { + flags := recursiveFindFlagsWithName(actionFuncName, command, parentCommand, foundName) + + for _, flag := range flags { + flag.Apply(flagSet) + } + } + +} + +func recursiveFindFlagsWithName(actionFuncName string, command cli.Command, parent string, foundName bool) []cli.Flag { + + if command.Action != nil { + if actionFuncName == getFuncName(command.Action) && foundName { + return command.Flags + } + } + + for _, subcommand := range command.Subcommands { + if !foundName { + foundName = strings.EqualFold(subcommand.Name, parent) + } + + found := recursiveFindFlagsWithName(actionFuncName, subcommand, parent, foundName) + if found != nil { + return found + } + } + return nil +} + +func getFuncName(i interface{}) string { + return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() +} diff --git a/core/cmd/solana_keys_commands_test.go b/core/cmd/solana_keys_commands_test.go index 32b44fc894..e72343be45 100644 --- a/core/cmd/solana_keys_commands_test.go +++ b/core/cmd/solana_keys_commands_test.go @@ -95,7 +95,7 @@ func TestShell_SolanaKeys(t *testing.T) { require.NoError(t, err) requireSolanaKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(cmd.NewSolanaKeysClient(client).DeleteKey, set, "solana") + flagSetApplyFromAction(cmd.NewSolanaKeysClient(client).DeleteKey, set, "solana") require.NoError(tt, set.Set("yes", "true")) @@ -122,7 +122,7 @@ func TestShell_SolanaKeys(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test Solana export", 0) - cltest.FlagSetApplyFromAction(cmd.NewSolanaKeysClient(client).ExportKey, set, "solana") + flagSetApplyFromAction(cmd.NewSolanaKeysClient(client).ExportKey, set, "solana") require.NoError(tt, set.Parse([]string{"0"})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -135,7 +135,7 @@ func TestShell_SolanaKeys(t *testing.T) { // Export test set = flag.NewFlagSet("test Solana export", 0) - cltest.FlagSetApplyFromAction(cmd.NewSolanaKeysClient(client).ExportKey, set, "solana") + flagSetApplyFromAction(cmd.NewSolanaKeysClient(client).ExportKey, set, "solana") require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -150,7 +150,7 @@ func TestShell_SolanaKeys(t *testing.T) { requireSolanaKeyCount(t, app, 0) set = flag.NewFlagSet("test Solana import", 0) - cltest.FlagSetApplyFromAction(cmd.NewSolanaKeysClient(client).ImportKey, set, "solana") + flagSetApplyFromAction(cmd.NewSolanaKeysClient(client).ImportKey, set, "solana") require.NoError(tt, set.Parse([]string{keyName})) require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) diff --git a/core/cmd/solana_transaction_commands_test.go b/core/cmd/solana_transaction_commands_test.go index f019616cb8..b190caec51 100644 --- a/core/cmd/solana_transaction_commands_test.go +++ b/core/cmd/solana_transaction_commands_test.go @@ -21,7 +21,6 @@ import ( solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" ) func TestShell_SolanaSendSol(t *testing.T) { @@ -69,7 +68,7 @@ func TestShell_SolanaSendSol(t *testing.T) { require.NoError(t, err) set := flag.NewFlagSet("sendsolcoins", 0) - cltest.FlagSetApplyFromAction(client.SolanaSendSol, set, "solana") + flagSetApplyFromAction(client.SolanaSendSol, set, "solana") require.NoError(t, set.Set("id", chainID)) require.NoError(t, set.Parse([]string{tt.amount, from.PublicKey().String(), to.PublicKey().String()})) diff --git a/core/cmd/starknet_keys_commands_test.go b/core/cmd/starknet_keys_commands_test.go index 17584eefe0..b1fa4d88f0 100644 --- a/core/cmd/starknet_keys_commands_test.go +++ b/core/cmd/starknet_keys_commands_test.go @@ -94,7 +94,7 @@ func TestShell_StarkNetKeys(t *testing.T) { require.NoError(t, err) requireStarkNetKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).DeleteKey, set, "starknet") + flagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).DeleteKey, set, "starknet") require.NoError(tt, set.Set("yes", "true")) @@ -121,7 +121,7 @@ func TestShell_StarkNetKeys(t *testing.T) { // Export test invalid id set := flag.NewFlagSet("test StarkNet export", 0) - cltest.FlagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).ExportKey, set, "starknet") + flagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).ExportKey, set, "starknet") require.NoError(tt, set.Parse([]string{"0"})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -134,7 +134,7 @@ func TestShell_StarkNetKeys(t *testing.T) { // Export test set = flag.NewFlagSet("test StarkNet export", 0) - cltest.FlagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).ExportKey, set, "starknet") + flagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).ExportKey, set, "starknet") require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) @@ -149,7 +149,7 @@ func TestShell_StarkNetKeys(t *testing.T) { requireStarkNetKeyCount(t, app, 0) set = flag.NewFlagSet("test StarkNet import", 0) - cltest.FlagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).ImportKey, set, "starknet") + flagSetApplyFromAction(cmd.NewStarkNetKeysClient(client).ImportKey, set, "starknet") require.NoError(tt, set.Parse([]string{keyName})) require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) diff --git a/core/cmd/vrf_keys_commands_test.go b/core/cmd/vrf_keys_commands_test.go index 2055260444..a061067771 100644 --- a/core/cmd/vrf_keys_commands_test.go +++ b/core/cmd/vrf_keys_commands_test.go @@ -105,7 +105,7 @@ func TestShellVRF_CRUD(t *testing.T) { // Now do a hard delete and ensure its completely removes the key set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteVRFKey, set, "") + flagSetApplyFromAction(client.DeleteVRFKey, set, "") require.NoError(t, set.Parse([]string{k2.Compressed})) require.NoError(t, set.Set("hard", "true")) @@ -141,7 +141,7 @@ func TestVRF_ImportExport(t *testing.T) { // Export it, encrypted with cltest.Password instead keyName := "vrfkey1" set := flag.NewFlagSet("test VRF export", 0) - cltest.FlagSetApplyFromAction(client.ExportVRFKey, set, "") + flagSetApplyFromAction(client.ExportVRFKey, set, "") require.NoError(t, set.Parse([]string{k1.Compressed})) // Arguments require.NoError(t, set.Set("new-password", "../internal/fixtures/correct_password.txt")) @@ -157,7 +157,7 @@ func TestVRF_ImportExport(t *testing.T) { // Should error if we try to import a duplicate key importSet := flag.NewFlagSet("test VRF import", 0) - cltest.FlagSetApplyFromAction(client.ImportVRFKey, importSet, "") + flagSetApplyFromAction(client.ImportVRFKey, importSet, "") require.NoError(t, importSet.Parse([]string{keyName})) require.NoError(t, importSet.Set("old-password", "../internal/fixtures/correct_password.txt")) @@ -167,7 +167,7 @@ func TestVRF_ImportExport(t *testing.T) { // Lets delete the key and import it set = flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.DeleteVRFKey, set, "") + flagSetApplyFromAction(client.DeleteVRFKey, set, "") require.NoError(t, set.Parse([]string{k1.Compressed})) require.NoError(t, set.Set("hard", "true")) diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index cf3f4f5c07..b1431bf059 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -6,7 +6,6 @@ import ( crand "crypto/rand" "encoding/json" "errors" - "flag" "fmt" "io" "math/big" @@ -16,8 +15,6 @@ import ( "net/url" "os" "reflect" - "runtime" - "strings" "testing" "time" @@ -29,7 +26,6 @@ import ( "github.com/google/uuid" "github.com/gorilla/securecookie" "github.com/gorilla/sessions" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/manyminds/api2go/jsonapi" "github.com/onsi/gomega" @@ -37,7 +33,6 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/urfave/cli" "github.com/jmoiron/sqlx" @@ -46,7 +41,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/common/client" - txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -55,7 +49,6 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -120,7 +113,6 @@ const ( var ( DefaultP2PPeerID p2pkey.PeerID FixtureChainID = *testutils.FixtureChainID - source rand.Source DefaultCosmosKey = cosmoskey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) DefaultCSAKey = csakey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) @@ -147,13 +139,6 @@ func init() { fmt.Printf("[gin] %-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) } - // Seed the random number generator, otherwise separate modules will take - // the same advisory locks when tested with `go test -p N` for N > 1 - seed := time.Now().UTC().UnixNano() - fmt.Printf("cltest random seed: %v\n", seed) - - // Also seed the local source - source = rand.NewSource(seed) defaultP2PPeerID, err := p2ppeer.Decode(configtest.DefaultPeerID) if err != nil { panic(err) @@ -201,22 +186,6 @@ func NewJobPipelineV2(t testing.TB, cfg pipeline.BridgeConfig, jpcfg JobPipeline } } -func NewEventBroadcaster(t testing.TB, dbURL url.URL) pg.EventBroadcaster { - lggr := logger.TestLogger(t) - return pg.NewEventBroadcaster(dbURL, 0, 0, lggr, uuid.New()) -} - -func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { - lggr := logger.TestLogger(t) - ge := config.EVM().GasEstimator() - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) - ec.SetResumeCallback(fn) - require.NoError(t, ec.Start(testutils.Context(t))) - return ec -} - // TestApplication holds the test application and test servers type TestApplication struct { t testing.TB @@ -228,13 +197,6 @@ type TestApplication struct { Keys []ethkey.KeyV2 } -// NewWSServer starts a websocket server which invokes callback for each message received. -// If chainID is set, then eth_chainId calls will be automatically handled. -func NewWSServer(t *testing.T, chainID *big.Int, callback testutils.JSONRPCHandler) string { - server := testutils.NewWSServer(t, chainID, callback) - return server.WSURL().String() -} - // NewApplicationEVMDisabled creates a new application with default config but EVM disabled // Useful for testing controllers func NewApplicationEVMDisabled(t *testing.T) *TestApplication { @@ -1578,58 +1540,17 @@ func AssertRecordEventually(t *testing.T, db *sqlx.DB, model interface{}, stmt s }, testutils.WaitTimeout(t), DBPollingInterval).Should(gomega.BeTrue()) } -func MustSendingKeyStates(t *testing.T, ethKeyStore keystore.Eth, chainID *big.Int) []ethkey.State { - keys, err := ethKeyStore.EnabledKeysForChain(chainID) - require.NoError(t, err) - states, err := ethKeyStore.GetStatesForKeys(keys) - require.NoError(t, err) - return states -} - -func MustRandomP2PPeerID(t *testing.T) p2ppeer.ID { - reader := rand.New(source) - p2pPrivkey, _, err := cryptop2p.GenerateEd25519Key(reader) - require.NoError(t, err) - id, err := p2ppeer.IDFromPrivateKey(p2pPrivkey) - require.NoError(t, err) - return id -} - func MustWebURL(t *testing.T, s string) *models.WebURL { uri, err := url.Parse(s) require.NoError(t, err) return (*models.WebURL)(uri) } -func AssertPipelineTaskRunsSuccessful(t testing.TB, runs []pipeline.TaskRun) { - t.Helper() - for i, run := range runs { - require.True(t, run.Error.IsZero(), fmt.Sprintf("pipeline.Task run failed (idx: %v, dotID: %v, error: '%v')", i, run.GetDotID(), run.Error.ValueOrZero())) - } -} - -func AssertPipelineTaskRunsErrored(t testing.TB, runs []pipeline.TaskRun) { - t.Helper() - for i, run := range runs { - require.False(t, run.Error.IsZero(), fmt.Sprintf("expected pipeline.Task run to have failed, but it succeeded (idx: %v, dotID: %v, output: '%v')", i, run.GetDotID(), run.Output)) - } -} - func NewTestChainScopedConfig(t testing.TB) evmconfig.ChainScopedConfig { cfg := configtest.NewGeneralConfig(t, nil) return evmtest.NewChainScopedConfig(t, cfg) } -func MustGetStateForKey(t testing.TB, kst keystore.Eth, key ethkey.KeyV2) ethkey.State { - state, err := kst.GetStateForKey(key) - require.NoError(t, err) - return state -} - -func NewTxStore(t *testing.T, db *sqlx.DB, cfg pg.QConfig) txmgr.EvmTxStore { - return txmgr.NewTxStore(db, logger.TestLogger(t), cfg) -} - func NewTestTxStore(t *testing.T, db *sqlx.DB, cfg pg.QConfig) txmgr.TestEvmTxStore { return txmgr.NewTxStore(db, logger.TestLogger(t), cfg) } @@ -1647,47 +1568,3 @@ func ClearDBTables(t *testing.T, db *sqlx.DB, tables ...string) { err = tx.Commit() require.NoError(t, err) } - -// FlagSetApplyFromAction applies the flags from action to the flagSet. -// `parentCommand` will filter the app commands and only applies the flags if the command/subcommand has a parent with that name, if left empty no filtering is done -func FlagSetApplyFromAction(action interface{}, flagSet *flag.FlagSet, parentCommand string) { - cliApp := cmd.Shell{} - app := cmd.NewApp(&cliApp) - - foundName := parentCommand == "" - actionFuncName := getFuncName(action) - - for _, command := range app.Commands { - flags := recursiveFindFlagsWithName(actionFuncName, command, parentCommand, foundName) - - for _, flag := range flags { - flag.Apply(flagSet) - } - } - -} - -func recursiveFindFlagsWithName(actionFuncName string, command cli.Command, parent string, foundName bool) []cli.Flag { - - if command.Action != nil { - if actionFuncName == getFuncName(command.Action) && foundName { - return command.Flags - } - } - - for _, subcommand := range command.Subcommands { - if !foundName { - foundName = strings.EqualFold(subcommand.Name, parent) - } - - found := recursiveFindFlagsWithName(actionFuncName, subcommand, parent, foundName) - if found != nil { - return found - } - } - return nil -} - -func getFuncName(i interface{}) string { - return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() -} diff --git a/core/internal/cltest/event_websocket_server.go b/core/internal/cltest/event_websocket_server.go deleted file mode 100644 index 64b3e90cd8..0000000000 --- a/core/internal/cltest/event_websocket_server.go +++ /dev/null @@ -1,154 +0,0 @@ -package cltest - -import ( - "net/http" - "net/http/httptest" - "net/url" - "sync" - "testing" - - "github.com/pkg/errors" - - "github.com/gorilla/websocket" -) - -// EventWebSocketServer is a web socket server designed specifically for testing -type EventWebSocketServer struct { - *httptest.Server - mutex *sync.RWMutex // shared mutex for safe access to arrays/maps. - t *testing.T - connections []*websocket.Conn - Connected chan struct{} - Disconnected chan struct{} - ReceivedText chan string - ReceivedBinary chan []byte - URL *url.URL -} - -// NewEventWebSocketServer returns a new EventWebSocketServer -func NewEventWebSocketServer(t *testing.T) (*EventWebSocketServer, func()) { - server := &EventWebSocketServer{ - mutex: &sync.RWMutex{}, - t: t, - Connected: make(chan struct{}, 1), // have buffer of one for easier assertions after the event - Disconnected: make(chan struct{}, 1), // have buffer of one for easier assertions after the event - ReceivedText: make(chan string, 100), - ReceivedBinary: make(chan []byte, 100), - } - - server.Server = httptest.NewServer(http.HandlerFunc(server.handler)) - u, err := url.Parse(server.Server.URL) - if err != nil { - t.Fatal("EventWebSocketServer: ", err) - } - u.Scheme = "ws" - server.URL = u - return server, func() { - server.Close() - } -} - -func (wss EventWebSocketServer) ConnectionsCount() int { - wss.mutex.RLock() - defer wss.mutex.RUnlock() - return len(wss.connections) -} - -// Broadcast sends a message to every web socket client connected to the EventWebSocketServer -func (wss *EventWebSocketServer) Broadcast(message string) error { - wss.mutex.RLock() - defer wss.mutex.RUnlock() - for _, connection := range wss.connections { - err := connection.WriteMessage(websocket.TextMessage, []byte(message)) - if err != nil { - return errors.Wrap(err, "error writing message to connection") - } - } - - return nil -} - -// WriteCloseMessage tells connected clients to disconnect. -// Useful to emulate that the websocket server is shutting down without -// actually shutting down. -// This overcomes httptest.Server's inability to restart on the same URL:port. -func (wss *EventWebSocketServer) WriteCloseMessage() { - wss.mutex.RLock() - for _, connection := range wss.connections { - err := connection.WriteMessage( - websocket.CloseMessage, - websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) - if err != nil { - wss.t.Error(err) - } - } - wss.mutex.RUnlock() -} - -var ( - upgrader = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { return true }, - } - - closeCodes = []int{websocket.CloseNormalClosure, websocket.CloseAbnormalClosure} -) - -func (wss *EventWebSocketServer) handler(w http.ResponseWriter, r *http.Request) { - var err error - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - wss.t.Fatal("EventWebSocketServer Upgrade: ", err) - } - - wss.addConnection(conn) - for { - messageType, payload, err := conn.ReadMessage() // we only read - if websocket.IsCloseError(err, closeCodes...) { - wss.removeConnection(conn) - return - } - if err != nil { - wss.t.Fatal("EventWebSocketServer ReadMessage: ", err) - } - - if messageType == websocket.TextMessage { - select { - case wss.ReceivedText <- string(payload): - default: - } - } else if messageType == websocket.BinaryMessage { - select { - case wss.ReceivedBinary <- payload: - default: - } - } else { - wss.t.Fatal("EventWebSocketServer UnsupportedMessageType: ", messageType) - } - } -} - -func (wss *EventWebSocketServer) addConnection(conn *websocket.Conn) { - wss.mutex.Lock() - wss.connections = append(wss.connections, conn) - wss.mutex.Unlock() - select { // broadcast connected event - case wss.Connected <- struct{}{}: - default: - } -} - -func (wss *EventWebSocketServer) removeConnection(conn *websocket.Conn) { - newc := []*websocket.Conn{} - wss.mutex.Lock() - for _, connection := range wss.connections { - if connection != conn { - newc = append(newc, connection) - } - } - wss.connections = newc - wss.mutex.Unlock() - select { // broadcast disconnected event - case wss.Disconnected <- struct{}{}: - default: - } -} diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 741afe828f..46014c4e04 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -134,7 +134,7 @@ func EmptyCLIContext() *cli.Context { return cli.NewContext(nil, set, nil) } -func NewEthTx(t *testing.T, fromAddress common.Address) txmgr.Tx { +func NewEthTx(fromAddress common.Address) txmgr.Tx { return txmgr.Tx{ FromAddress: fromAddress, ToAddress: testutils.NewAddress(), @@ -156,7 +156,7 @@ func MustInsertUnconfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonc chainID = v } } - etx := NewEthTx(t, fromAddress) + etx := NewEthTx(fromAddress) etx.BroadcastAt = &broadcastAt etx.InitialBroadcastAt = &broadcastAt @@ -184,95 +184,9 @@ func MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t *testing.T, txStore return etx } -func MustInsertUnconfirmedEthTxWithAttemptState(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, txAttemptState txmgrtypes.TxAttemptState, opts ...interface{}) txmgr.Tx { - etx := MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) - attempt := NewLegacyEthTxAttempt(t, etx.ID) - - tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) - rlp := new(bytes.Buffer) - require.NoError(t, tx.EncodeRLP(rlp)) - attempt.SignedRawTx = rlp.Bytes() - - attempt.State = txAttemptState - require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) - require.NoError(t, err) - return etx -} - -func MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, opts ...interface{}) txmgr.Tx { - etx := MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) - attempt := NewDynamicFeeEthTxAttempt(t, etx.ID) - - addr := testutils.NewAddress() - dtx := types.DynamicFeeTx{ - ChainID: big.NewInt(0), - Nonce: uint64(nonce), - GasTipCap: big.NewInt(1), - GasFeeCap: big.NewInt(1), - Gas: 242, - To: &addr, - Value: big.NewInt(342), - Data: []byte{2, 3, 4}, - } - tx := types.NewTx(&dtx) - rlp := new(bytes.Buffer) - require.NoError(t, tx.EncodeRLP(rlp)) - attempt.SignedRawTx = rlp.Bytes() - - attempt.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) - require.NoError(t, err) - return etx -} - -func MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address) txmgr.Tx { - timeNow := time.Now() - etx := NewEthTx(t, fromAddress) - - etx.BroadcastAt = &timeNow - etx.InitialBroadcastAt = &timeNow - n := evmtypes.Nonce(nonce) - etx.Sequence = &n - etx.State = txmgrcommon.TxUnconfirmed - require.NoError(t, txStore.InsertTx(&etx)) - attempt := NewLegacyEthTxAttempt(t, etx.ID) - - tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) - rlp := new(bytes.Buffer) - require.NoError(t, tx.EncodeRLP(rlp)) - attempt.SignedRawTx = rlp.Bytes() - - attempt.State = txmgrtypes.TxAttemptInsufficientFunds - require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) - require.NoError(t, err) - return etx -} - -func MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( - t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, broadcastBeforeBlockNum int64, - broadcastAt time.Time, fromAddress common.Address) txmgr.Tx { - etx := NewEthTx(t, fromAddress) - - etx.BroadcastAt = &broadcastAt - etx.InitialBroadcastAt = &broadcastAt - n := evmtypes.Nonce(nonce) - etx.Sequence = &n - etx.State = txmgrcommon.TxConfirmedMissingReceipt - require.NoError(t, txStore.InsertTx(&etx)) - attempt := NewLegacyEthTxAttempt(t, etx.ID) - attempt.BroadcastBeforeBlockNum = &broadcastBeforeBlockNum - attempt.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx.TxAttempts = append(etx.TxAttempts, attempt) - return etx -} - func MustInsertConfirmedEthTxWithLegacyAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, broadcastBeforeBlockNum int64, fromAddress common.Address) txmgr.Tx { timeNow := time.Now() - etx := NewEthTx(t, fromAddress) + etx := NewEthTx(fromAddress) etx.BroadcastAt = &timeNow etx.InitialBroadcastAt = &timeNow @@ -288,91 +202,6 @@ func MustInsertConfirmedEthTxWithLegacyAttempt(t *testing.T, txStore txmgr.TestE return etx } -func MustInsertInProgressEthTxWithAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce evmtypes.Nonce, fromAddress common.Address) txmgr.Tx { - etx := NewEthTx(t, fromAddress) - - etx.Sequence = &nonce - etx.State = txmgrcommon.TxInProgress - require.NoError(t, txStore.InsertTx(&etx)) - attempt := NewLegacyEthTxAttempt(t, etx.ID) - tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) - rlp := new(bytes.Buffer) - require.NoError(t, tx.EncodeRLP(rlp)) - attempt.SignedRawTx = rlp.Bytes() - attempt.State = txmgrtypes.TxAttemptInProgress - require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) - require.NoError(t, err) - return etx -} - -func MustCreateUnstartedGeneratedTx(t testing.TB, txStore txmgr.EvmTxStore, fromAddress common.Address, chainID *big.Int, opts ...func(*txmgr.TxRequest)) (tx txmgr.Tx) { - txRequest := txmgr.TxRequest{ - FromAddress: fromAddress, - } - - // Apply the default options - WithDefaults()(&txRequest) - // Apply the optional parameters - for _, opt := range opts { - opt(&txRequest) - } - return MustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, chainID) -} - -func WithDefaults() func(*txmgr.TxRequest) { - return func(tx *txmgr.TxRequest) { - tx.ToAddress = testutils.NewAddress() - tx.EncodedPayload = []byte{1, 2, 3} - tx.Value = big.Int(assets.NewEthValue(142)) - tx.FeeLimit = uint32(1000000000) - tx.Strategy = txmgrcommon.NewSendEveryStrategy() - // Set default values for other fields if needed - } -} - -func EvmTxRequestWithStrategy(strategy txmgrtypes.TxStrategy) func(*txmgr.TxRequest) { - return func(tx *txmgr.TxRequest) { - tx.Strategy = strategy - } -} - -func EvmTxRequestWithChecker(checker txmgr.TransmitCheckerSpec) func(*txmgr.TxRequest) { - return func(tx *txmgr.TxRequest) { - tx.Checker = checker - } -} -func EvmTxRequestWithValue(value big.Int) func(*txmgr.TxRequest) { - return func(tx *txmgr.TxRequest) { - tx.Value = value - } -} - -func EvmTxRequestWithIdempotencyKey(idempotencyKey string) func(*txmgr.TxRequest) { - return func(tx *txmgr.TxRequest) { - tx.IdempotencyKey = &idempotencyKey - } -} - -func MustCreateUnstartedTx(t testing.TB, txStore txmgr.EvmTxStore, fromAddress common.Address, toAddress common.Address, encodedPayload []byte, gasLimit uint32, value big.Int, chainID *big.Int, opts ...interface{}) (tx txmgr.Tx) { - txRequest := txmgr.TxRequest{ - FromAddress: fromAddress, - ToAddress: toAddress, - EncodedPayload: encodedPayload, - Value: value, - FeeLimit: gasLimit, - Strategy: txmgrcommon.NewSendEveryStrategy(), - } - - return MustCreateUnstartedTxFromEvmTxRequest(t, txStore, txRequest, chainID) -} - -func MustCreateUnstartedTxFromEvmTxRequest(t testing.TB, txStore txmgr.EvmTxStore, txRequest txmgr.TxRequest, chainID *big.Int) (tx txmgr.Tx) { - tx, err := txStore.CreateTransaction(testutils.Context(t), txRequest, chainID) - require.NoError(t, err) - return tx -} - func NewLegacyEthTxAttempt(t *testing.T, etxID int64) txmgr.TxAttempt { gasPrice := assets.NewWeiI(1) return txmgr.TxAttempt{ @@ -406,72 +235,6 @@ func NewDynamicFeeEthTxAttempt(t *testing.T, etxID int64) txmgr.TxAttempt { } } -func NewEthReceipt(t *testing.T, blockNumber int64, blockHash common.Hash, txHash common.Hash, status uint64) txmgr.Receipt { - transactionIndex := uint(NewRandomPositiveInt64()) - - receipt := evmtypes.Receipt{ - BlockNumber: big.NewInt(blockNumber), - BlockHash: blockHash, - TxHash: txHash, - TransactionIndex: transactionIndex, - Status: status, - } - - r := txmgr.Receipt{ - BlockNumber: blockNumber, - BlockHash: blockHash, - TxHash: txHash, - TransactionIndex: transactionIndex, - Receipt: receipt, - } - return r -} - -func MustInsertEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, blockNumber int64, blockHash common.Hash, txHash common.Hash) txmgr.Receipt { - r := NewEthReceipt(t, blockNumber, blockHash, txHash, 0x1) - id, err := txStore.InsertReceipt(&r.Receipt) - require.NoError(t, err) - r.ID = id - return r -} - -func MustInsertRevertedEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, blockNumber int64, blockHash common.Hash, txHash common.Hash) txmgr.Receipt { - r := NewEthReceipt(t, blockNumber, blockHash, txHash, 0x0) - id, err := txStore.InsertReceipt(&r.Receipt) - require.NoError(t, err) - r.ID = id - return r -} - -// Inserts into evm.receipts but does not update evm.txes or evm.tx_attempts -func MustInsertConfirmedEthTxWithReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address, nonce, blockNum int64) (etx txmgr.Tx) { - etx = MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, nonce, blockNum, fromAddress) - MustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), etx.TxAttempts[0].Hash) - return etx -} - -func MustInsertConfirmedEthTxBySaveFetchedReceipts(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address, nonce int64, blockNum int64, chainID big.Int) (etx txmgr.Tx) { - etx = MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, nonce, blockNum, fromAddress) - receipt := evmtypes.Receipt{ - TxHash: etx.TxAttempts[0].Hash, - BlockHash: utils.NewHash(), - BlockNumber: big.NewInt(nonce), - TransactionIndex: uint(1), - } - err := txStore.SaveFetchedReceipts(testutils.Context(t), []*evmtypes.Receipt{&receipt}, &chainID) - require.NoError(t, err) - return etx -} - -func MustInsertFatalErrorEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address) txmgr.Tx { - etx := NewEthTx(t, fromAddress) - etx.Error = null.StringFrom("something exploded") - etx.State = txmgrcommon.TxFatalError - - require.NoError(t, txStore.InsertTx(&etx)) - return etx -} - type RandomKey struct { Nonce int64 Disabled bool @@ -500,7 +263,8 @@ func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2 func (r RandomKey) MustInsertWithState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { k, address := r.MustInsert(t, keystore) - state := MustGetStateForKey(t, keystore, k) + state, err := keystore.GetStateForKey(k) + require.NoError(t, err) return state, address } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 7749b173c5..35fd3a31ff 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -429,7 +429,7 @@ func TestIntegration_DirectRequest(t *testing.T) { pipelineRuns := cltest.WaitForPipelineComplete(t, 0, j.ID, 1, 14, app.JobORM(), testutils.WaitTimeout(t)/2, time.Second) pipelineRun := pipelineRuns[0] - cltest.AssertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) + assertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) assertPricesUint256(t, big.NewInt(61464), big.NewInt(50707), big.NewInt(6381886), operatorContracts.multiWord) nameAndExternalJobID = uuid.New() @@ -454,7 +454,7 @@ func TestIntegration_DirectRequest(t *testing.T) { pipelineRuns = cltest.WaitForPipelineComplete(t, 0, jobSingleWord.ID, 1, 8, app.JobORM(), testutils.WaitTimeout(t), time.Second) pipelineRun = pipelineRuns[0] - cltest.AssertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) + assertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) v, err := operatorContracts.singleWord.CurrentPriceInt(nil) require.NoError(t, err) assert.Equal(t, big.NewInt(61464), v) @@ -535,7 +535,7 @@ observationSource = """ // The run should have succeeded but with the receipt detailing the reverted transaction pipelineRun := pipelineRuns[0] - cltest.AssertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) + assertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) outputs := pipelineRun.Outputs.Val.([]interface{}) require.Len(t, outputs, 1) @@ -581,7 +581,7 @@ observationSource = """ // The run should have failed as a revert pipelineRun := pipelineRuns[0] - cltest.AssertPipelineTaskRunsErrored(t, pipelineRun.PipelineTaskRuns) + assertPipelineTaskRunsErrored(t, pipelineRun.PipelineTaskRuns) }) t.Run("with FailOnRevert disabled, run succeeds with output being reverted receipt", func(t *testing.T) { @@ -619,7 +619,7 @@ observationSource = """ // The run should have succeeded but with the receipt detailing the reverted transaction pipelineRun := pipelineRuns[0] - cltest.AssertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) + assertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) outputs := pipelineRun.Outputs.Val.([]interface{}) require.Len(t, outputs, 1) @@ -1454,3 +1454,17 @@ func assertPricesUint256(t *testing.T, usd, eur, jpy *big.Int, consumer *multiwo } func ptr[T any](v T) *T { return &v } + +func assertPipelineTaskRunsSuccessful(t testing.TB, runs []pipeline.TaskRun) { + t.Helper() + for i, run := range runs { + require.True(t, run.Error.IsZero(), fmt.Sprintf("pipeline.Task run failed (idx: %v, dotID: %v, error: '%v')", i, run.GetDotID(), run.Error.ValueOrZero())) + } +} + +func assertPipelineTaskRunsErrored(t testing.TB, runs []pipeline.TaskRun) { + t.Helper() + for i, run := range runs { + require.False(t, run.Error.IsZero(), fmt.Sprintf("expected pipeline.Task run to have failed, but it succeeded (idx: %v, dotID: %v, output: '%v')", i, run.GetDotID(), run.Output)) + } +} diff --git a/core/services/ocrcommon/discoverer_database_test.go b/core/services/ocrcommon/discoverer_database_test.go index 2300316092..ff1a931b01 100644 --- a/core/services/ocrcommon/discoverer_database_test.go +++ b/core/services/ocrcommon/discoverer_database_test.go @@ -1,23 +1,24 @@ package ocrcommon_test import ( + "crypto/rand" "testing" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - + cryptop2p "github.com/libp2p/go-libp2p-core/crypto" + p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" ) func Test_DiscovererDatabase(t *testing.T) { db := pgtest.NewSqlDB(t) - localPeerID1 := cltest.MustRandomP2PPeerID(t) - localPeerID2 := cltest.MustRandomP2PPeerID(t) + localPeerID1 := mustRandomP2PPeerID(t) + localPeerID2 := mustRandomP2PPeerID(t) dd1 := ocrcommon.NewDiscovererDatabase(db, localPeerID1) dd2 := ocrcommon.NewDiscovererDatabase(db, localPeerID2) @@ -81,3 +82,11 @@ func Test_DiscovererDatabase(t *testing.T) { }) } + +func mustRandomP2PPeerID(t *testing.T) p2ppeer.ID { + p2pPrivkey, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + id, err := p2ppeer.IDFromPrivateKey(p2pPrivkey) + require.NoError(t, err) + return id +} diff --git a/core/services/pg/event_broadcaster_test.go b/core/services/pg/event_broadcaster_test.go index a82e26e058..41dcbb0176 100644 --- a/core/services/pg/event_broadcaster_test.go +++ b/core/services/pg/event_broadcaster_test.go @@ -5,20 +5,20 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - + "github.com/google/uuid" "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) func TestEventBroadcaster(t *testing.T) { config, _ := heavyweight.FullTestDBNoFixturesV2(t, nil) - eventBroadcaster := cltest.NewEventBroadcaster(t, config.Database().URL()) + eventBroadcaster := pg.NewEventBroadcaster(config.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) t.Cleanup(func() { require.NoError(t, eventBroadcaster.Close()) }) From 47604e288446c10f7ab5a012b6619b7436620a74 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 27 Nov 2023 10:58:28 -0600 Subject: [PATCH 201/327] bump various deps (#11357) --- core/scripts/go.mod | 71 ++++++------ core/scripts/go.sum | 226 +++++++++++++++++++++++--------------- go.mod | 69 ++++++------ go.sum | 228 ++++++++++++++++++++++++--------------- integration-tests/go.mod | 70 ++++++------ integration-tests/go.sum | 160 +++++++++++++-------------- 6 files changed, 468 insertions(+), 356 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index e9fa432d4c..1a0775bb83 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -8,11 +8,11 @@ replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( github.com/ava-labs/coreth v0.12.1 github.com/avast/retry-go v3.0.0+incompatible - github.com/docker/docker v24.0.6+incompatible + github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/ethereum/go-ethereum v1.12.0 - github.com/google/go-cmp v0.5.9 - github.com/google/uuid v1.3.1 + github.com/google/go-cmp v0.6.0 + github.com/google/uuid v1.4.0 github.com/jmoiron/sqlx v1.3.5 github.com/joho/godotenv v1.4.0 github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f @@ -56,7 +56,7 @@ require ( github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/ava-labs/avalanchego v1.10.1 // indirect - github.com/avast/retry-go/v4 v4.5.0 // indirect + github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect @@ -103,7 +103,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/esote/minmaxheap v1.0.0 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect @@ -125,21 +125,21 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.5 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/webauthn v0.8.6 // indirect + github.com/go-webauthn/webauthn v0.9.1 // indirect github.com/go-webauthn/x v0.1.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect - github.com/golang/glog v1.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -151,9 +151,9 @@ require ( github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect github.com/gorilla/context v1.1.1 // indirect - github.com/gorilla/securecookie v1.1.1 // indirect - github.com/gorilla/sessions v1.2.1 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.2.2 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/grafana/pyroscope-go v1.0.4 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/graph-gophers/dataloader v5.0.0+incompatible // indirect @@ -201,7 +201,7 @@ require ( github.com/jmhodges/levigo v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -251,7 +251,7 @@ require ( github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect @@ -285,7 +285,7 @@ require ( github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/pressly/goose/v3 v3.15.1 // indirect + github.com/pressly/goose/v3 v3.16.0 // indirect github.com/prometheus/client_golang v1.17.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect @@ -299,8 +299,9 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect + github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.9 // indirect + github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 // indirect @@ -344,33 +345,33 @@ require ( go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/sdk v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/sdk v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.15.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/term v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/guregu/null.v4 v4.0.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 3d9962474b..ef7aa735bb 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -18,23 +18,23 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= +cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.22.0 h1:cB8R6FtUtT1TYGl5R3xuxnW6OUIc/DrT2aiR16TTG7Y= -cloud.google.com/go/compute v1.22.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= +cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= +cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -87,6 +87,10 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0= +github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw= +github.com/ClickHouse/clickhouse-go/v2 v2.15.0 h1:G0hTKyO8fXXR1bGnZ0DY3vTG01xYfOGW76zgjg5tmC4= +github.com/ClickHouse/clickhouse-go/v2 v2.15.0/go.mod h1:kXt1SRq0PIRa6aKZD7TnFnY9PQKmc2b13sHtOYcK6cQ= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/CosmWasm/wasmd v0.40.1 h1:LxbO78t/6S8TkeQlUrJ0m5O87HtAwLx4RGHq3rdrOEU= @@ -133,6 +137,8 @@ github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKS github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= @@ -148,8 +154,8 @@ github.com/ava-labs/coreth v0.12.1 h1:EWSkFGHGVUxmu1pnSK/2pdcxaAVHbGspHqO3Ag+i7s github.com/ava-labs/coreth v0.12.1/go.mod h1:/5x54QlIKjlPebkdzTA5ic9wXdejbWOnQosztkv9jxo= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= -github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= -github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= +github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= +github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= @@ -246,8 +252,8 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= +github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -335,10 +341,12 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= +github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= -github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -349,6 +357,10 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T/Lao= +github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E= +github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= +github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -373,8 +385,8 @@ github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -434,6 +446,10 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= +github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= +github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI= +github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -452,8 +468,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= @@ -478,8 +494,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-webauthn/webauthn v0.8.6 h1:bKMtL1qzd2WTFkf1mFTVbreYrwn7dsYmEPjTq6QN90E= -github.com/go-webauthn/webauthn v0.8.6/go.mod h1:emwVLMCI5yx9evTTvr0r+aOZCdWJqMfbRhF0MufyUog= +github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= +github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -503,11 +519,11 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= +github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -565,8 +581,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -601,11 +618,13 @@ github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYa github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -621,14 +640,14 @@ github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= @@ -732,6 +751,8 @@ github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3 github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= @@ -832,10 +853,15 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw= +github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -860,9 +886,13 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -891,8 +921,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= @@ -1168,8 +1198,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -1326,25 +1356,29 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= -github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= -github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= +github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= +github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s= +github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -1354,6 +1388,8 @@ github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdU github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= +github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -1368,8 +1404,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= -github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= +github.com/pressly/goose/v3 v3.16.0 h1:xMJUsZdHLqSnCqESyKSqEfcYVYsUuup1nrOhaEFftQg= +github.com/pressly/goose/v3 v3.16.0/go.mod h1:JwdKVnmCRhnF6XLQs2mHEQtucFD49cQBdRM4UiwkxsM= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -1443,11 +1479,15 @@ github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtm github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec= +github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= -github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= +github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= +github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1605,6 +1645,8 @@ github.com/valyala/fastjson v1.4.1/go.mod h1:nV6MsjxL2IMJQUoHDIrjEI7oLyeqK6aBD7E github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= +github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= @@ -1617,13 +1659,21 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7V github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dzWP1Lu+A40W883dK/Mr3xyDSM/2MggS8GtHT0qgAnE= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= +github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA= +github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= @@ -1662,20 +1712,20 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1687,8 +1737,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1748,8 +1798,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1789,8 +1839,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1850,8 +1900,8 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1877,8 +1927,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1971,17 +2021,17 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1993,8 +2043,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2070,8 +2120,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2159,12 +2209,12 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 h1:+VoAg+OKmWaommL56xmZSE2sUK8A7m6SUO7X89F2tbw= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753/go.mod h1:iqkVr8IRpZ53gx1dEnWlCUIEwDWqWARWrbzpasaTNYM= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 h1:lCbbUxUDD+DiXx9Q6F/ttL0aAu7N2pz8XnmMm8ZW4NE= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 h1:XUODHrpzJEUeWmVo/jfNTLj0YyVveOo28oE6vkFbkO4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2189,8 +2239,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2265,22 +2315,24 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= +howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= -modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= -modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= +modernc.org/libc v1.32.0 h1:yXatHTrACp3WaKNRCoZwUK7qj5V8ep1XyY0ka4oYcNc= +modernc.org/libc v1.32.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= -modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= +modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/go.mod b/go.mod index e6bb7347ff..e396ba5ede 100644 --- a/go.mod +++ b/go.mod @@ -6,14 +6,14 @@ require ( github.com/Depado/ginprom v1.7.11 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/avast/retry-go/v4 v4.5.0 + github.com/avast/retry-go/v4 v4.5.1 github.com/btcsuite/btcd v0.23.4 github.com/cometbft/cometbft v0.37.2 github.com/cosmos/cosmos-sdk v0.47.4 github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e github.com/esote/minmaxheap v1.0.0 github.com/ethereum/go-ethereum v1.12.0 - github.com/fatih/color v1.15.0 + github.com/fatih/color v1.16.0 github.com/fxamacker/cbor/v2 v2.5.0 github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 github.com/getsentry/sentry-go v0.19.0 @@ -22,12 +22,12 @@ require ( github.com/gin-contrib/sessions v0.0.5 github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 github.com/gin-gonic/gin v1.9.1 - github.com/go-webauthn/webauthn v0.8.6 + github.com/go-webauthn/webauthn v0.9.1 github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 - github.com/google/uuid v1.3.1 - github.com/gorilla/securecookie v1.1.1 - github.com/gorilla/sessions v1.2.1 - github.com/gorilla/websocket v1.5.0 + github.com/google/uuid v1.4.0 + github.com/gorilla/securecookie v1.1.2 + github.com/gorilla/sessions v1.2.2 + github.com/gorilla/websocket v1.5.1 github.com/grafana/pyroscope-go v1.0.4 github.com/graph-gophers/dataloader v5.0.0+incompatible github.com/graph-gophers/graphql-go v1.3.0 @@ -49,12 +49,12 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-multiaddr v0.3.3 github.com/olekukonko/tablewriter v0.0.5 - github.com/onsi/gomega v1.27.8 + github.com/onsi/gomega v1.30.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 - github.com/pressly/goose/v3 v3.15.1 + github.com/pressly/goose/v3 v3.16.0 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.45.0 @@ -62,7 +62,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 - github.com/shirou/gopsutil/v3 v3.23.9 + github.com/shirou/gopsutil/v3 v3.23.10 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 @@ -88,15 +88,15 @@ require ( go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.14.0 + golang.org/x/crypto v0.15.0 golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 - golang.org/x/sync v0.4.0 - golang.org/x/term v0.13.0 - golang.org/x/text v0.13.0 + golang.org/x/sync v0.5.0 + golang.org/x/term v0.14.0 + golang.org/x/text v0.14.0 golang.org/x/time v0.3.0 - golang.org/x/tools v0.14.0 + golang.org/x/tools v0.15.0 gonum.org/v1/gonum v0.14.0 - google.golang.org/grpc v1.58.3 + google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 gopkg.in/guregu/null.v4 v4.0.0 @@ -174,7 +174,7 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.5 github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -187,13 +187,13 @@ require ( github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect - github.com/golang/glog v1.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -239,7 +239,7 @@ require ( github.com/jmhodges/levigo v1.0.0 // indirect github.com/jmoiron/sqlx v1.3.5 github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -284,7 +284,7 @@ require ( github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect @@ -318,6 +318,7 @@ require ( github.com/rivo/uniseg v0.4.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect @@ -352,21 +353,21 @@ require ( go.dedis.ch/protobuf v1.0.11 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/sdk v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/sdk v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/sys v0.14.0 // indirect + google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 24d662390d..0c72ac7e63 100644 --- a/go.sum +++ b/go.sum @@ -18,23 +18,23 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= +cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.22.0 h1:cB8R6FtUtT1TYGl5R3xuxnW6OUIc/DrT2aiR16TTG7Y= -cloud.google.com/go/compute v1.22.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= +cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= +cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -87,6 +87,10 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0= +github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw= +github.com/ClickHouse/clickhouse-go/v2 v2.15.0 h1:G0hTKyO8fXXR1bGnZ0DY3vTG01xYfOGW76zgjg5tmC4= +github.com/ClickHouse/clickhouse-go/v2 v2.15.0/go.mod h1:kXt1SRq0PIRa6aKZD7TnFnY9PQKmc2b13sHtOYcK6cQ= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/CosmWasm/wasmd v0.40.1 h1:LxbO78t/6S8TkeQlUrJ0m5O87HtAwLx4RGHq3rdrOEU= @@ -138,6 +142,8 @@ github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKS github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= @@ -147,8 +153,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= -github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= +github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= +github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= @@ -245,8 +251,8 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= +github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -332,8 +338,12 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= +github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -344,6 +354,10 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T/Lao= +github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E= +github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= +github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -368,8 +382,8 @@ github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -429,6 +443,10 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= +github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= +github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI= +github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -447,8 +465,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= @@ -475,8 +493,8 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-webauthn/webauthn v0.8.6 h1:bKMtL1qzd2WTFkf1mFTVbreYrwn7dsYmEPjTq6QN90E= -github.com/go-webauthn/webauthn v0.8.6/go.mod h1:emwVLMCI5yx9evTTvr0r+aOZCdWJqMfbRhF0MufyUog= +github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= +github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -500,11 +518,11 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= +github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -562,8 +580,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -598,11 +617,13 @@ github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYa github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -618,14 +639,14 @@ github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= @@ -833,10 +854,15 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw= +github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -861,9 +887,13 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -892,8 +922,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= @@ -1169,8 +1199,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -1222,6 +1252,8 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1319,8 +1351,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1329,25 +1361,29 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= -github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= -github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= +github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= +github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s= +github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -1357,6 +1393,8 @@ github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdU github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= +github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -1371,8 +1409,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= -github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= +github.com/pressly/goose/v3 v3.16.0 h1:xMJUsZdHLqSnCqESyKSqEfcYVYsUuup1nrOhaEFftQg= +github.com/pressly/goose/v3 v3.16.0/go.mod h1:JwdKVnmCRhnF6XLQs2mHEQtucFD49cQBdRM4UiwkxsM= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -1444,11 +1482,15 @@ github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtm github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec= +github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= -github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= +github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= +github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1607,6 +1649,8 @@ github.com/valyala/fastjson v1.4.1/go.mod h1:nV6MsjxL2IMJQUoHDIrjEI7oLyeqK6aBD7E github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= +github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= @@ -1619,13 +1663,21 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7V github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dzWP1Lu+A40W883dK/Mr3xyDSM/2MggS8GtHT0qgAnE= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= +github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA= +github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= @@ -1664,20 +1716,20 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1689,8 +1741,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1751,8 +1803,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1792,8 +1844,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1854,8 +1906,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1881,8 +1933,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1975,9 +2027,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1985,8 +2037,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1999,8 +2051,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2075,8 +2127,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2164,12 +2216,12 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 h1:+VoAg+OKmWaommL56xmZSE2sUK8A7m6SUO7X89F2tbw= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753/go.mod h1:iqkVr8IRpZ53gx1dEnWlCUIEwDWqWARWrbzpasaTNYM= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 h1:lCbbUxUDD+DiXx9Q6F/ttL0aAu7N2pz8XnmMm8ZW4NE= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 h1:XUODHrpzJEUeWmVo/jfNTLj0YyVveOo28oE6vkFbkO4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2194,8 +2246,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2268,22 +2320,24 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= +howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= -modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= -modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= +modernc.org/libc v1.32.0 h1:yXatHTrACp3WaKNRCoZwUK7qj5V8ep1XyY0ka4oYcNc= +modernc.org/libc v1.32.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= -modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= +modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index d0ca234663..fd167f81a9 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -11,13 +11,13 @@ require ( github.com/cli/go-gh/v2 v2.0.0 github.com/ethereum/go-ethereum v1.12.0 github.com/go-resty/resty/v2 v2.7.0 - github.com/google/go-cmp v0.5.9 - github.com/google/uuid v1.3.1 + github.com/google/go-cmp v0.6.0 + github.com/google/uuid v1.4.0 github.com/jmoiron/sqlx v1.3.5 github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.9 github.com/manifoldco/promptui v0.9.0 - github.com/onsi/gomega v1.27.8 + github.com/onsi/gomega v1.30.0 github.com/pelletier/go-toml/v2 v2.1.0 github.com/rs/zerolog v1.30.0 github.com/scylladb/go-reflectx v1.0.1 @@ -37,7 +37,7 @@ require ( github.com/umbracle/ethgo v0.1.3 go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/zap v1.26.0 - golang.org/x/sync v0.4.0 + golang.org/x/sync v0.5.0 gopkg.in/guregu/null.v4 v4.0.0 ) @@ -73,7 +73,7 @@ require ( github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/avast/retry-go/v4 v4.5.0 // indirect + github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aws/aws-sdk-go v1.44.302 // indirect github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect @@ -140,7 +140,7 @@ require ( github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/fatih/camelcase v1.0.0 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -161,7 +161,7 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.5 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.21.4 // indirect @@ -177,7 +177,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/webauthn v0.8.6 // indirect + github.com/go-webauthn/webauthn v0.9.1 // indirect github.com/go-webauthn/x v0.1.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect @@ -185,8 +185,8 @@ require ( github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect github.com/gogo/status v1.1.1 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect - github.com/golang/glog v1.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect @@ -200,9 +200,9 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/securecookie v1.1.1 // indirect - github.com/gorilla/sessions v1.2.1 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.2.2 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/gosimple/slug v1.13.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 // indirect @@ -265,7 +265,7 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -315,7 +315,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/miekg/dns v1.1.55 // indirect @@ -385,7 +385,7 @@ require ( github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sercand/kuberesolver/v4 v4.0.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.9 // indirect + github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect @@ -438,38 +438,38 @@ require ( go.etcd.io/etcd/client/v3 v3.5.7 // indirect go.mongodb.org/mongo-driver v1.12.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/sdk v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/sdk v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/goleak v1.2.1 // indirect + go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.15.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.18.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/term v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 21be8c1f48..0ee9d7848a 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -37,8 +37,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= +cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -149,8 +149,8 @@ cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARy cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= +cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -272,8 +272,8 @@ cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQE cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= +cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= @@ -666,8 +666,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= -github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= +github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= +github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -972,8 +972,8 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= @@ -1064,8 +1064,8 @@ github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= @@ -1136,8 +1136,8 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-webauthn/webauthn v0.8.6 h1:bKMtL1qzd2WTFkf1mFTVbreYrwn7dsYmEPjTq6QN90E= -github.com/go-webauthn/webauthn v0.8.6/go.mod h1:emwVLMCI5yx9evTTvr0r+aOZCdWJqMfbRhF0MufyUog= +github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= +github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= @@ -1195,13 +1195,14 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= +github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1266,8 +1267,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -1315,8 +1317,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= @@ -1348,14 +1350,14 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= @@ -1678,8 +1680,8 @@ github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -1975,8 +1977,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -2157,8 +2159,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -2167,8 +2169,8 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= -github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= @@ -2231,8 +2233,8 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= -github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= +github.com/pressly/goose/v3 v3.16.0 h1:xMJUsZdHLqSnCqESyKSqEfcYVYsUuup1nrOhaEFftQg= +github.com/pressly/goose/v3 v3.16.0/go.mod h1:JwdKVnmCRhnF6XLQs2mHEQtucFD49cQBdRM4UiwkxsM= github.com/prometheus/alertmanager v0.25.1 h1:LGBNMspOfv8h7brb+LWj2wnwBCg2ZuuKWTh6CAVw2/Y= github.com/prometheus/alertmanager v0.25.1/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -2348,10 +2350,12 @@ github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYM github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec= +github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= -github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= +github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= +github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -2620,22 +2624,22 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -2653,8 +2657,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -2719,8 +2723,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2780,8 +2784,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2866,8 +2870,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2916,8 +2920,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -3046,9 +3050,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -3059,8 +3063,8 @@ golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -3076,8 +3080,8 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -3169,8 +3173,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -3394,12 +3398,12 @@ google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 h1:+VoAg+OKmWaommL56xmZSE2sUK8A7m6SUO7X89F2tbw= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753/go.mod h1:iqkVr8IRpZ53gx1dEnWlCUIEwDWqWARWrbzpasaTNYM= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 h1:lCbbUxUDD+DiXx9Q6F/ttL0aAu7N2pz8XnmMm8ZW4NE= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 h1:XUODHrpzJEUeWmVo/jfNTLj0YyVveOo28oE6vkFbkO4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -3444,8 +3448,8 @@ google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsA google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= From ab14bdc80e63b3dec61a2b0d8f983e5774f46581 Mon Sep 17 00:00:00 2001 From: Ryan Hall Date: Mon, 27 Nov 2023 12:33:27 -0500 Subject: [PATCH 202/327] Upkeep Balance Monitor (#11180) * write UpkeepBalanceMonWithBuffer * Update AutomationRegistryInterface2_0.sol Support getMinBalanceForUpkeep * reformat * remove modifier * add typeAndVersion check in constructor * restore AutomationRegistryInterface2_0.sol function * update import paths * update comments * cleanup * get rid of redundant REGISTRY variable * cleanup * rename * cleanup * remove target, min wait period, switch to min/target percentages * refactor getUnderfundedUpkeeps() to return top up amounts * refactor topUp() function * switch to max batch size * add max top up amount * add maxTopUpAmount * whitelist performUpkeep to forwarder * cleanup * rename * bring topUp() back * write initial test suite * fix solhint errors * update test for getUnderfundedUpkeeps() * add tests for owner only functions and events * add topUp and performUpkeep tests * rearrange functions on contract * add support for multiple registries * cleanup * change topUpAmounts to uint96[] * move pausable to topUp(); add length check to topUp() --------- Co-authored-by: De Clercq Wentzel <10665586+wentzeld@users.noreply.github.com> --- .../upkeeps/UpkeepBalanceMonitor.sol | 258 +++++++++++ .../automation/UpkeepBalanceMonitor.test.ts | 399 ++++++++++++++++++ 2 files changed, 657 insertions(+) create mode 100644 contracts/src/v0.8/automation/upkeeps/UpkeepBalanceMonitor.sol create mode 100644 contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts diff --git a/contracts/src/v0.8/automation/upkeeps/UpkeepBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/UpkeepBalanceMonitor.sol new file mode 100644 index 0000000000..dae17da729 --- /dev/null +++ b/contracts/src/v0.8/automation/upkeeps/UpkeepBalanceMonitor.sol @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.19; + +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +/// @title The UpkeepBalanceMonitor contract +/// @notice A keeper-compatible contract that monitors and funds Chainlink Automation upkeeps. +contract UpkeepBalanceMonitor is ConfirmedOwner, Pausable { + using EnumerableSet for EnumerableSet.AddressSet; + + event ConfigSet(Config config); + event ForwarderSet(address forwarderAddress); + event FundsWithdrawn(uint256 amountWithdrawn, address payee); + event TopUpFailed(uint256 indexed upkeepId); + event TopUpSucceeded(uint256 indexed upkeepId, uint96 amount); + event WatchListSet(address registryAddress); + + error InvalidConfig(); + error InvalidTopUpData(); + error OnlyForwarderOrOwner(); + + /// @member maxBatchSize is the maximum number of upkeeps to fund in a single transaction + /// @member minPercentage is the percentage of the upkeep's minBalance at which top-up occurs + /// @member targetPercentage is the percentage of the upkeep's minBalance to top-up to + /// @member maxTopUpAmount is the maximum amount of LINK to top-up an upkeep with + struct Config { + uint8 maxBatchSize; + uint24 minPercentage; + uint24 targetPercentage; + uint96 maxTopUpAmount; + } + + // ================================================================ + // | STORAGE | + // ================================================================ + + LinkTokenInterface private immutable LINK_TOKEN; + + mapping(address => uint256[]) s_registryWatchLists; + EnumerableSet.AddressSet s_registries; + Config private s_config; + address private s_forwarderAddress; + + // ================================================================ + // | CONSTRUCTOR | + // ================================================================ + + /// @param linkToken the Link token address + /// @param config the initial config for the contract + constructor(LinkTokenInterface linkToken, Config memory config) ConfirmedOwner(msg.sender) { + require(address(linkToken) != address(0)); + LINK_TOKEN = linkToken; + setConfig(config); + } + + // ================================================================ + // | CORE FUNCTIONALITY | + // ================================================================ + + /// @notice Gets a list of upkeeps that are underfunded + /// @return needsFunding list of underfunded upkeepIDs + /// @return registryAddresses list of registries that the upkeepIDs belong to + /// @return topUpAmounts amount to top up each upkeep + function getUnderfundedUpkeeps() public view returns (uint256[] memory, address[] memory, uint96[] memory) { + Config memory config = s_config; + uint256[] memory needsFunding = new uint256[](config.maxBatchSize); + address[] memory registryAddresses = new address[](config.maxBatchSize); + uint96[] memory topUpAmounts = new uint96[](config.maxBatchSize); + uint256 availableFunds = LINK_TOKEN.balanceOf(address(this)); + uint256 count; + for (uint256 i = 0; i < s_registries.length(); i++) { + IAutomationRegistryConsumer registry = IAutomationRegistryConsumer(s_registries.at(i)); + for (uint256 j = 0; j < s_registryWatchLists[address(registry)].length; j++) { + uint256 upkeepID = s_registryWatchLists[address(registry)][j]; + uint96 upkeepBalance = registry.getBalance(upkeepID); + uint96 minBalance = registry.getMinBalance(upkeepID); + uint96 topUpThreshold = (minBalance * config.minPercentage) / 100; + uint96 topUpAmount = ((minBalance * config.targetPercentage) / 100) - upkeepBalance; + if (topUpAmount > config.maxTopUpAmount) { + topUpAmount = config.maxTopUpAmount; + } + if (upkeepBalance <= topUpThreshold && availableFunds >= topUpAmount) { + needsFunding[count] = upkeepID; + topUpAmounts[count] = topUpAmount; + registryAddresses[count] = address(registry); + count++; + availableFunds -= topUpAmount; + } + if (count == config.maxBatchSize) { + break; + } + } + if (count == config.maxBatchSize) { + break; + } + } + if (count < config.maxBatchSize) { + assembly { + mstore(needsFunding, count) + mstore(registryAddresses, count) + mstore(topUpAmounts, count) + } + } + return (needsFunding, registryAddresses, topUpAmounts); + } + + /// @notice Called by the keeper/owner to send funds to underfunded upkeeps + /// @param upkeepIDs the list of upkeep ids to fund + /// @param registryAddresses the list of registries that the upkeepIDs belong to + /// @param topUpAmounts the list of amounts to fund each upkeep with + /// @dev We explicitly choose not to verify that input upkeepIDs are included in the watchlist. We also + /// explicity permit any amount to be sent via topUpAmounts; it does not have to meet the criteria + /// specified in getUnderfundedUpkeeps(). Here, we are relying on the security of automation's OCR to + /// secure the output of getUnderfundedUpkeeps() as the input to topUp(), and we are treating the owner + /// as a privileged user that can perform arbitrary top-ups to any upkeepID. + function topUp( + uint256[] memory upkeepIDs, + address[] memory registryAddresses, + uint96[] memory topUpAmounts + ) public whenNotPaused { + if (msg.sender != address(s_forwarderAddress) && msg.sender != owner()) revert OnlyForwarderOrOwner(); + if (upkeepIDs.length != registryAddresses.length || upkeepIDs.length != topUpAmounts.length) + revert InvalidTopUpData(); + for (uint256 i = 0; i < upkeepIDs.length; i++) { + try LINK_TOKEN.transferAndCall(registryAddresses[i], topUpAmounts[i], abi.encode(upkeepIDs[i])) returns ( + bool success + ) { + if (success) { + emit TopUpSucceeded(upkeepIDs[i], topUpAmounts[i]); + continue; + } + } catch {} + emit TopUpFailed(upkeepIDs[i]); + } + } + + // ================================================================ + // | AUTOMATION COMPATIBLE | + // ================================================================ + + /// @notice Gets list of upkeeps ids that are underfunded and returns a keeper-compatible payload. + /// @return upkeepNeeded signals if upkeep is needed, performData is an abi encoded list of subscription ids that need funds + function checkUpkeep(bytes calldata) external view returns (bool upkeepNeeded, bytes memory performData) { + ( + uint256[] memory needsFunding, + address[] memory registryAddresses, + uint96[] memory topUpAmounts + ) = getUnderfundedUpkeeps(); + upkeepNeeded = needsFunding.length > 0; + if (upkeepNeeded) { + performData = abi.encode(needsFunding, registryAddresses, topUpAmounts); + } + return (upkeepNeeded, performData); + } + + /// @notice Called by the keeper to send funds to underfunded addresses. + /// @param performData the abi encoded list of addresses to fund + function performUpkeep(bytes calldata performData) external { + (uint256[] memory upkeepIDs, address[] memory registryAddresses, uint96[] memory topUpAmounts) = abi.decode( + performData, + (uint256[], address[], uint96[]) + ); + topUp(upkeepIDs, registryAddresses, topUpAmounts); + } + + // ================================================================ + // | ADMIN | + // ================================================================ + + /// @notice Withdraws the contract balance in LINK. + /// @param amount the amount of LINK (in juels) to withdraw + /// @param payee the address to pay + function withdraw(uint256 amount, address payee) external onlyOwner { + require(payee != address(0)); + LINK_TOKEN.transfer(payee, amount); + emit FundsWithdrawn(amount, payee); + } + + /// @notice Pause the contract, which prevents executing performUpkeep. + function pause() external onlyOwner { + _pause(); + } + + /// @notice Unpause the contract. + function unpause() external onlyOwner { + _unpause(); + } + + // ================================================================ + // | SETTERS | + // ================================================================ + + /// @notice Sets the list of upkeeps to watch + /// @param registryAddress the registry that this watchlist applies to + /// @param watchlist the list of UpkeepIDs to watch + function setWatchList(address registryAddress, uint256[] calldata watchlist) external onlyOwner { + if (watchlist.length == 0) { + s_registries.remove(registryAddress); + delete s_registryWatchLists[registryAddress]; + } else { + s_registries.add(registryAddress); + s_registryWatchLists[registryAddress] = watchlist; + } + emit WatchListSet(registryAddress); + } + + /// @notice Sets the contract config + /// @param config the new config + function setConfig(Config memory config) public onlyOwner { + if ( + config.maxBatchSize == 0 || + config.minPercentage < 100 || + config.targetPercentage <= config.minPercentage || + config.maxTopUpAmount == 0 + ) { + revert InvalidConfig(); + } + s_config = config; + emit ConfigSet(config); + } + + /// @notice Sets the upkeep's forwarder contract + /// @param forwarderAddress the new forwarder + /// @dev this should only need to be called once, after registering the contract with the registry + function setForwarder(address forwarderAddress) external onlyOwner { + s_forwarderAddress = forwarderAddress; + emit ForwarderSet(forwarderAddress); + } + + // ================================================================ + // | GETTERS | + // ================================================================ + + /// @notice Gets the list of upkeeps ids being monitored + function getWatchList() external view returns (address[] memory, uint256[][] memory) { + address[] memory registryAddresses = s_registries.values(); + uint256[][] memory upkeepIDs = new uint256[][](registryAddresses.length); + for (uint256 i = 0; i < registryAddresses.length; i++) { + upkeepIDs[i] = s_registryWatchLists[registryAddresses[i]]; + } + return (registryAddresses, upkeepIDs); + } + + /// @notice Gets the contract config + function getConfig() external view returns (Config memory) { + return s_config; + } + + /// @notice Gets the upkeep's forwarder contract + function getForwarder() external view returns (address) { + return s_forwarderAddress; + } +} diff --git a/contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts b/contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts new file mode 100644 index 0000000000..259a9c3b9f --- /dev/null +++ b/contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts @@ -0,0 +1,399 @@ +import { ethers } from 'hardhat' +import { expect } from 'chai' +import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { randomAddress } from '../../test-helpers/helpers' +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { IKeeperRegistryMaster__factory as RegistryFactory } from '../../../typechain/factories/IKeeperRegistryMaster__factory' +import { IAutomationForwarder__factory as ForwarderFactory } from '../../../typechain/factories/IAutomationForwarder__factory' +import { UpkeepBalanceMonitor } from '../../../typechain/UpkeepBalanceMonitor' +import { LinkToken } from '../../../typechain/LinkToken' +import { BigNumber } from 'ethers' +import { + deployMockContract, + MockContract, +} from '@ethereum-waffle/mock-contract' + +let owner: SignerWithAddress +let stranger: SignerWithAddress +let registry: MockContract +let registry2: MockContract +let forwarder: MockContract +let linkToken: LinkToken +let upkeepBalanceMonitor: UpkeepBalanceMonitor + +const setup = async () => { + const accounts = await ethers.getSigners() + owner = accounts[0] + stranger = accounts[1] + + const ltFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + owner, + ) + linkToken = (await ltFactory.deploy()) as LinkToken + const bmFactory = await ethers.getContractFactory( + 'UpkeepBalanceMonitor', + owner, + ) + upkeepBalanceMonitor = await bmFactory.deploy(linkToken.address, { + maxBatchSize: 10, + minPercentage: 120, + targetPercentage: 300, + maxTopUpAmount: ethers.utils.parseEther('100'), + }) + registry = await deployMockContract(owner, RegistryFactory.abi) + registry2 = await deployMockContract(owner, RegistryFactory.abi) + forwarder = await deployMockContract(owner, ForwarderFactory.abi) + await forwarder.mock.getRegistry.returns(registry.address) + await upkeepBalanceMonitor.setForwarder(forwarder.address) + await linkToken + .connect(owner) + .transfer(upkeepBalanceMonitor.address, ethers.utils.parseEther('10000')) + await upkeepBalanceMonitor + .connect(owner) + .setWatchList(registry.address, [0, 1, 2, 3, 4, 5, 6, 7, 8]) + await upkeepBalanceMonitor + .connect(owner) + .setWatchList(registry2.address, [9, 10, 11]) + for (let i = 0; i < 9; i++) { + await registry.mock.getMinBalance.withArgs(i).returns(100) + await registry.mock.getBalance.withArgs(i).returns(121) // all upkeeps are sufficiently funded + } + for (let i = 9; i < 12; i++) { + await registry2.mock.getMinBalance.withArgs(i).returns(100) + await registry2.mock.getBalance.withArgs(i).returns(121) // all upkeeps are sufficiently funded + } +} + +describe('UpkeepBalanceMonitor', () => { + beforeEach(async () => { + await loadFixture(setup) + }) + + describe('constructor()', () => { + it('should set the initial values correctly', async () => { + const config = await upkeepBalanceMonitor.getConfig() + expect(config.maxBatchSize).to.equal(10) + expect(config.minPercentage).to.equal(120) + expect(config.targetPercentage).to.equal(300) + expect(config.maxTopUpAmount).to.equal(ethers.utils.parseEther('100')) + }) + }) + + describe('setConfig()', () => { + const newConfig = { + maxBatchSize: 100, + minPercentage: 150, + targetPercentage: 500, + maxTopUpAmount: 1, + } + + it('should set config correctly', async () => { + await upkeepBalanceMonitor.connect(owner).setConfig(newConfig) + const config = await upkeepBalanceMonitor.getConfig() + expect(config.maxBatchSize).to.equal(newConfig.maxBatchSize) + expect(config.minPercentage).to.equal(newConfig.minPercentage) + expect(config.targetPercentage).to.equal(newConfig.targetPercentage) + expect(config.maxTopUpAmount).to.equal(newConfig.maxTopUpAmount) + }) + + it('cannot be called by a non-owner', async () => { + await expect( + upkeepBalanceMonitor.connect(stranger).setConfig(newConfig), + ).to.be.revertedWith('Only callable by owner') + }) + + it('should emit an event', async () => { + await expect( + upkeepBalanceMonitor.connect(owner).setConfig(newConfig), + ).to.emit(upkeepBalanceMonitor, 'ConfigSet') + }) + }) + + describe('setForwarder()', () => { + const newForwarder = randomAddress() + + it('should set the forwarder correctly', async () => { + await upkeepBalanceMonitor.connect(owner).setForwarder(newForwarder) + const forwarderAddress = await upkeepBalanceMonitor.getForwarder() + expect(forwarderAddress).to.equal(newForwarder) + }) + + it('cannot be called by a non-owner', async () => { + await expect( + upkeepBalanceMonitor.connect(stranger).setForwarder(randomAddress()), + ).to.be.revertedWith('Only callable by owner') + }) + + it('should emit an event', async () => { + await expect( + upkeepBalanceMonitor.connect(owner).setForwarder(newForwarder), + ) + .to.emit(upkeepBalanceMonitor, 'ForwarderSet') + .withArgs(newForwarder) + }) + }) + + describe('setWatchList()', () => { + const newWatchList = [ + BigNumber.from(1), + BigNumber.from(2), + BigNumber.from(10), + ] + + it('should add addresses to the watchlist', async () => { + await upkeepBalanceMonitor + .connect(owner) + .setWatchList(registry.address, newWatchList) + const [_, upkeepIDs] = await upkeepBalanceMonitor.getWatchList() + expect(upkeepIDs[0]).to.deep.equal(newWatchList) + }) + + it('cannot be called by a non-owner', async () => { + await expect( + upkeepBalanceMonitor + .connect(stranger) + .setWatchList(registry.address, [1, 2, 3]), + ).to.be.revertedWith('Only callable by owner') + }) + + it('should emit an event', async () => { + await expect( + upkeepBalanceMonitor + .connect(owner) + .setWatchList(registry.address, newWatchList), + ) + .to.emit(upkeepBalanceMonitor, 'WatchListSet') + .withArgs(registry.address) + }) + }) + + describe('withdraw()', () => { + const payee = randomAddress() + const withdrawAmount = 100 + + it('should withdraw funds to a payee', async () => { + const initialBalance = await linkToken.balanceOf( + upkeepBalanceMonitor.address, + ) + await upkeepBalanceMonitor.connect(owner).withdraw(withdrawAmount, payee) + const finalBalance = await linkToken.balanceOf( + upkeepBalanceMonitor.address, + ) + const payeeBalance = await linkToken.balanceOf(payee) + expect(finalBalance).to.equal(initialBalance.sub(withdrawAmount)) + expect(payeeBalance).to.equal(withdrawAmount) + }) + + it('cannot be called by a non-owner', async () => { + await expect( + upkeepBalanceMonitor.connect(stranger).withdraw(withdrawAmount, payee), + ).to.be.revertedWith('Only callable by owner') + }) + + it('should emit an event', async () => { + await expect( + upkeepBalanceMonitor.connect(owner).withdraw(withdrawAmount, payee), + ) + .to.emit(upkeepBalanceMonitor, 'FundsWithdrawn') + .withArgs(100, payee) + }) + }) + + describe('pause() and unpause()', () => { + it('should pause and unpause the contract', async () => { + await upkeepBalanceMonitor.connect(owner).pause() + expect(await upkeepBalanceMonitor.paused()).to.be.true + await upkeepBalanceMonitor.connect(owner).unpause() + expect(await upkeepBalanceMonitor.paused()).to.be.false + }) + + it('cannot be called by a non-owner', async () => { + await expect( + upkeepBalanceMonitor.connect(stranger).pause(), + ).to.be.revertedWith('Only callable by owner') + await upkeepBalanceMonitor.connect(owner).pause() + await expect( + upkeepBalanceMonitor.connect(stranger).unpause(), + ).to.be.revertedWith('Only callable by owner') + }) + }) + + describe('checkUpkeep() / getUnderfundedUpkeeps()', () => { + it('should find the underfunded upkeeps', async () => { + let [upkeepIDs, registries, topUpAmounts] = + await upkeepBalanceMonitor.getUnderfundedUpkeeps() + expect(upkeepIDs.length).to.equal(0) + expect(registries.length).to.equal(0) + expect(topUpAmounts.length).to.equal(0) + let [upkeepNeeded, performData] = + await upkeepBalanceMonitor.checkUpkeep('0x') + expect(upkeepNeeded).to.be.false + expect(performData).to.equal('0x') + // update the balance for some upkeeps + await registry.mock.getBalance.withArgs(2).returns(120) + await registry.mock.getBalance.withArgs(4).returns(15) + await registry.mock.getBalance.withArgs(5).returns(0) + ;[upkeepIDs, registries, topUpAmounts] = + await upkeepBalanceMonitor.getUnderfundedUpkeeps() + expect(upkeepIDs.map((v) => v.toNumber())).to.deep.equal([2, 4, 5]) + expect(registries).to.deep.equal([ + registry.address, + registry.address, + registry.address, + ]) + expect(topUpAmounts.map((v) => v.toNumber())).to.deep.equal([ + 180, 285, 300, + ]) + ;[upkeepNeeded, performData] = + await upkeepBalanceMonitor.checkUpkeep('0x') + expect(upkeepNeeded).to.be.true + expect(performData).to.equal( + ethers.utils.defaultAbiCoder.encode( + ['uint256[]', 'address[]', 'uint256[]'], + [ + [2, 4, 5], + [registry.address, registry.address, registry.address], + [180, 285, 300], + ], + ), + ) + // update all to need funding + for (let i = 0; i < 9; i++) { + await registry.mock.getBalance.withArgs(i).returns(0) + } + for (let i = 9; i < 12; i++) { + await registry2.mock.getBalance.withArgs(i).returns(0) + } + // only the max batch size are included in the list + ;[upkeepIDs, registries, topUpAmounts] = + await upkeepBalanceMonitor.getUnderfundedUpkeeps() + expect(upkeepIDs.length).to.equal(10) + expect(topUpAmounts.length).to.equal(10) + expect(upkeepIDs.map((v) => v.toNumber())).to.deep.equal([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + ]) + expect(registries).to.deep.equal([ + ...Array(9).fill(registry.address), + registry2.address, + ]) + expect(topUpAmounts.map((v) => v.toNumber())).to.deep.equal([ + ...Array(10).fill(300), + ]) + // update the balance for some upkeeps + await registry.mock.getBalance.withArgs(0).returns(300) + await registry.mock.getBalance.withArgs(5).returns(300) + ;[upkeepIDs, registries, topUpAmounts] = + await upkeepBalanceMonitor.getUnderfundedUpkeeps() + expect(upkeepIDs.length).to.equal(10) + expect(topUpAmounts.length).to.equal(10) + expect(upkeepIDs.map((v) => v.toNumber())).to.deep.equal([ + 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, + ]) + expect(registries).to.deep.equal([ + ...Array(7).fill(registry.address), + ...Array(3).fill(registry2.address), + ]) + expect(topUpAmounts.map((v) => v.toNumber())).to.deep.equal([ + ...Array(10).fill(300), + ]) + }) + }) + + describe('topUp()', () => { + beforeEach(async () => { + await registry.mock.onTokenTransfer + .withArgs( + upkeepBalanceMonitor.address, + 100, + ethers.utils.defaultAbiCoder.encode(['uint256'], [1]), + ) + .returns() + await registry.mock.onTokenTransfer + .withArgs( + upkeepBalanceMonitor.address, + 50, + ethers.utils.defaultAbiCoder.encode(['uint256'], [7]), + ) + .returns() + }) + + it('cannot be called by a non-owner', async () => { + await expect( + upkeepBalanceMonitor.connect(stranger).topUp([], [], []), + ).to.be.revertedWith('OnlyForwarderOrOwner()') + }) + + it('should revert if the contract is paused', async () => { + await upkeepBalanceMonitor.connect(owner).pause() + await expect( + upkeepBalanceMonitor.connect(owner).topUp([], [], []), + ).to.be.revertedWith('Pausable: paused') + }) + + it('tops up the upkeeps by the amounts provided', async () => { + const initialBalance = await linkToken.balanceOf(registry.address) + const tx = await upkeepBalanceMonitor + .connect(owner) + .topUp([1, 7], [registry.address, registry.address], [100, 50]) + const finalBalance = await linkToken.balanceOf(registry.address) + expect(finalBalance).to.equal(initialBalance.add(150)) + await expect(tx) + .to.emit(upkeepBalanceMonitor, 'TopUpSucceeded') + .withArgs(1, 100) + await expect(tx) + .to.emit(upkeepBalanceMonitor, 'TopUpSucceeded') + .withArgs(7, 50) + }) + + it('does not abort if one top-up fails', async () => { + const initialBalance = await linkToken.balanceOf(registry.address) + const tx = await upkeepBalanceMonitor + .connect(owner) + .topUp( + [1, 7, 100], + [registry.address, registry.address, registry.address], + [100, 50, 100], + ) + const finalBalance = await linkToken.balanceOf(registry.address) + expect(finalBalance).to.equal(initialBalance.add(150)) + await expect(tx) + .to.emit(upkeepBalanceMonitor, 'TopUpSucceeded') + .withArgs(1, 100) + await expect(tx) + .to.emit(upkeepBalanceMonitor, 'TopUpSucceeded') + .withArgs(7, 50) + await expect(tx) + .to.emit(upkeepBalanceMonitor, 'TopUpFailed') + .withArgs(100) + }) + }) + + describe('checkUpkeep() / performUpkeep()', () => { + it('works round-trip', async () => { + await registry.mock.getBalance.withArgs(1).returns(100) // needs 200 + await registry.mock.getBalance.withArgs(7).returns(0) // needs 300 + await registry.mock.onTokenTransfer + .withArgs( + upkeepBalanceMonitor.address, + 200, + ethers.utils.defaultAbiCoder.encode(['uint256'], [1]), + ) + .returns() + await registry.mock.onTokenTransfer + .withArgs( + upkeepBalanceMonitor.address, + 300, + ethers.utils.defaultAbiCoder.encode(['uint256'], [7]), + ) + .returns() + const [upkeepNeeded, performData] = + await upkeepBalanceMonitor.checkUpkeep('0x') + expect(upkeepNeeded).to.be.true + const initialBalance = await linkToken.balanceOf(registry.address) + await upkeepBalanceMonitor.connect(owner).performUpkeep(performData) + const finalBalance = await linkToken.balanceOf(registry.address) + expect(finalBalance).to.equal(initialBalance.add(500)) + }) + }) +}) From a5e1873afedef375957e05a660b3bb4ca296fb93 Mon Sep 17 00:00:00 2001 From: Amir Y <83904651+amirylm@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:06:22 -0300 Subject: [PATCH 203/327] Bump chainlink-automation version (#11380) * bump chainlink-automation version NOTE: this is just for testing, referring to an open branch DO NOT MERGE before we import a proper version of chainlink-automation * go tidy * update version to 2.7.1 * go mod tidy * Update to cut tag * revert version change --------- Co-authored-by: anirudhwarrier <12178754+anirudhwarrier@users.noreply.github.com> Co-authored-by: Akshay Aggarwal --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 1a0775bb83..43840f93ce 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -21,7 +21,7 @@ require ( github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 - github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 + github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index ef7aa735bb..d8e682c742 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1502,8 +1502,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= -github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= +github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= +github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= diff --git a/go.mod b/go.mod index e396ba5ede..0f75e120fe 100644 --- a/go.mod +++ b/go.mod @@ -65,7 +65,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 - github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 + github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 diff --git a/go.sum b/go.sum index 0c72ac7e63..fc8cab806a 100644 --- a/go.sum +++ b/go.sum @@ -1505,8 +1505,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= -github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= +github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= +github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index fd167f81a9..ca77d3730e 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -23,7 +23,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 + github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 github.com/smartcontractkit/chainlink-testing-framework v1.19.5 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 0ee9d7848a..f117bf73e8 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2374,8 +2374,8 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459 h1:hJhuShYv9eUQxHJQdOmyEymVmApOrICrQdOY7kKQ5Io= -github.com/smartcontractkit/chainlink-automation v1.0.0-alpha.0.0.20231120164534-d4cab696c459/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= +github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= +github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= From 54563c01b188289c4d8aa3381bd2f6905c402161 Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:37:43 -0800 Subject: [PATCH 204/327] [Functions] Heartbeat request support in Gateway handlers (#11345) 1. Functions Handler - add a new method "heartbeat" - add a configurable list of allowed heartbeat senders - collect results from first F+1 nodes and send back in raw form 2. Connector Handler - asynchronously forward requests to Listener and cache results - run a loop to collect OCR reports from Offchain Transmitter 3. Listener - add Timestampi field and validate it --- core/services/functions/connector_handler.go | 182 ++++++++++++++++-- .../functions/connector_handler_test.go | 109 ++++++++++- core/services/functions/listener.go | 3 + core/services/functions/listener_test.go | 8 + core/services/functions/request.go | 17 +- .../gateway/handlers/functions/api.go | 1 + .../handlers/functions/handler.functions.go | 104 +++++++--- .../functions/handler.functions_test.go | 54 +++++- .../services/ocr2/plugins/functions/plugin.go | 6 +- .../ocr2/plugins/functions/plugin_test.go | 9 +- 10 files changed, 432 insertions(+), 61 deletions(-) diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 76608b8ada..5496bbdefc 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -1,14 +1,18 @@ package functions import ( + "bytes" "context" "crypto/ecdsa" "encoding/json" "fmt" + "sync" + "time" "go.uber.org/multierr" ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -25,35 +29,56 @@ import ( type functionsConnectorHandler struct { services.StateMachine - connector connector.GatewayConnector - signerKey *ecdsa.PrivateKey - nodeAddress string - storage s4.Storage - allowlist functions.OnchainAllowlist - rateLimiter *hc.RateLimiter - subscriptions functions.OnchainSubscriptions - minimumBalance assets.Link - lggr logger.Logger + connector connector.GatewayConnector + signerKey *ecdsa.PrivateKey + nodeAddress string + storage s4.Storage + allowlist functions.OnchainAllowlist + rateLimiter *hc.RateLimiter + subscriptions functions.OnchainSubscriptions + minimumBalance assets.Link + listener FunctionsListener + offchainTransmitter OffchainTransmitter + heartbeatRequests map[RequestID]*HeartbeatResponse + orderedRequests []RequestID + mu sync.Mutex + chStop services.StopChan + shutdownWaitGroup sync.WaitGroup + lggr logger.Logger } +const ( + HeartbeatRequestTimeoutSec = 240 + HeartbeatCacheSize = 1000 +) + var ( _ connector.Signer = &functionsConnectorHandler{} _ connector.GatewayConnectorHandler = &functionsConnectorHandler{} ) -func NewFunctionsConnectorHandler(nodeAddress string, signerKey *ecdsa.PrivateKey, storage s4.Storage, allowlist functions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions functions.OnchainSubscriptions, minimumBalance assets.Link, lggr logger.Logger) (*functionsConnectorHandler, error) { - if signerKey == nil || storage == nil || allowlist == nil || rateLimiter == nil || subscriptions == nil { - return nil, fmt.Errorf("signerKey, storage, allowlist, rateLimiter and subscriptions must be non-nil") +// internal request ID is a hash of (sender, requestID) +func InternalId(sender []byte, requestId []byte) RequestID { + return RequestID(crypto.Keccak256Hash(append(sender, requestId...)).Bytes()) +} + +func NewFunctionsConnectorHandler(nodeAddress string, signerKey *ecdsa.PrivateKey, storage s4.Storage, allowlist functions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions functions.OnchainSubscriptions, listener FunctionsListener, offchainTransmitter OffchainTransmitter, minimumBalance assets.Link, lggr logger.Logger) (*functionsConnectorHandler, error) { + if signerKey == nil || storage == nil || allowlist == nil || rateLimiter == nil || subscriptions == nil || listener == nil || offchainTransmitter == nil { + return nil, fmt.Errorf("all dependencies must be non-nil") } return &functionsConnectorHandler{ - nodeAddress: nodeAddress, - signerKey: signerKey, - storage: storage, - allowlist: allowlist, - rateLimiter: rateLimiter, - subscriptions: subscriptions, - minimumBalance: minimumBalance, - lggr: lggr.Named("FunctionsConnectorHandler"), + nodeAddress: nodeAddress, + signerKey: signerKey, + storage: storage, + allowlist: allowlist, + rateLimiter: rateLimiter, + subscriptions: subscriptions, + minimumBalance: minimumBalance, + listener: listener, + offchainTransmitter: offchainTransmitter, + heartbeatRequests: make(map[RequestID]*HeartbeatResponse), + chStop: make(services.StopChan), + lggr: lggr.Named("FunctionsConnectorHandler"), }, nil } @@ -92,6 +117,8 @@ func (h *functionsConnectorHandler) HandleGatewayMessage(ctx context.Context, ga return } h.handleSecretsSet(ctx, gatewayId, body, fromAddr) + case functions.MethodHeartbeat: + h.handleHeartbeat(ctx, gatewayId, body, fromAddr) default: h.lggr.Errorw("unsupported method", "id", gatewayId, "method", body.Method) } @@ -102,14 +129,21 @@ func (h *functionsConnectorHandler) Start(ctx context.Context) error { if err := h.allowlist.Start(ctx); err != nil { return err } - return h.subscriptions.Start(ctx) + if err := h.subscriptions.Start(ctx); err != nil { + return err + } + h.shutdownWaitGroup.Add(1) + go h.reportLoop() + return nil }) } func (h *functionsConnectorHandler) Close() error { return h.StopOnce("FunctionsConnectorHandler", func() (err error) { + close(h.chStop) err = multierr.Combine(err, h.allowlist.Close()) err = multierr.Combine(err, h.subscriptions.Close()) + h.shutdownWaitGroup.Wait() return }) } @@ -160,6 +194,112 @@ func (h *functionsConnectorHandler) handleSecretsSet(ctx context.Context, gatewa h.sendResponseAndLog(ctx, gatewayId, body, response) } +func (h *functionsConnectorHandler) handleHeartbeat(ctx context.Context, gatewayId string, requestBody *api.MessageBody, fromAddr ethCommon.Address) { + var request *OffchainRequest + err := json.Unmarshal(requestBody.Payload, &request) + if err != nil { + h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse(fmt.Sprintf("failed to unmarshal request: %v", err))) + return + } + if !bytes.Equal(request.RequestInitiator, fromAddr.Bytes()) { + h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("RequestInitiator doesn't match sender")) + return + } + if !bytes.Equal(request.SubscriptionOwner, fromAddr.Bytes()) { + h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("SubscriptionOwner doesn't match sender")) + return + } + + internalId := InternalId(fromAddr.Bytes(), request.RequestId) + request.RequestId = internalId[:] + h.lggr.Infow("handling offchain heartbeat", "messageId", requestBody.MessageId, "internalId", internalId, "sender", requestBody.Sender) + h.mu.Lock() + response, ok := h.heartbeatRequests[internalId] + if !ok { // new request + response = &HeartbeatResponse{ + Status: RequestStatePending, + ReceivedTs: uint64(time.Now().Unix()), + } + h.cacheNewRequestLocked(internalId, response) + h.shutdownWaitGroup.Add(1) + go h.handleOffchainRequest(request) + } + responseToSend := *response + h.mu.Unlock() + requestBody.Receiver = requestBody.Sender + h.sendResponseAndLog(ctx, gatewayId, requestBody, responseToSend) +} + +func internalErrorResponse(internalError string) HeartbeatResponse { + return HeartbeatResponse{ + Status: RequestStateInternalError, + InternalError: internalError, + } +} + +func (h *functionsConnectorHandler) handleOffchainRequest(request *OffchainRequest) { + defer h.shutdownWaitGroup.Done() + stopCtx, _ := h.chStop.NewCtx() + ctx, cancel := context.WithTimeout(stopCtx, time.Duration(HeartbeatRequestTimeoutSec)*time.Second) + defer cancel() + err := h.listener.HandleOffchainRequest(ctx, request) + if err != nil { + h.lggr.Errorw("internal error while processing", "id", request.RequestId, "error", err) + h.mu.Lock() + defer h.mu.Unlock() + state, ok := h.heartbeatRequests[RequestID(request.RequestId)] + if !ok { + h.lggr.Errorw("request unexpectedly disappeared from local cache", "id", request.RequestId) + return + } + state.CompletedTs = uint64(time.Now().Unix()) + state.Status = RequestStateInternalError + state.InternalError = err.Error() + } else { + // no error - results will be sent to OCR aggregation and returned via reportLoop() + h.lggr.Infow("request processed successfully, waiting for aggregation ...", "id", request.RequestId) + } +} + +// Listen to OCR reports passed from the plugin and process them against a local cache of requests. +func (h *functionsConnectorHandler) reportLoop() { + defer h.shutdownWaitGroup.Done() + for { + select { + case report := <-h.offchainTransmitter.ReportChannel(): + h.lggr.Infow("received report", "requestId", report.RequestId, "resultLen", len(report.Result), "errorLen", len(report.Error)) + if len(report.RequestId) != RequestIDLength { + h.lggr.Errorw("report has invalid requestId", "requestId", report.RequestId) + continue + } + h.mu.Lock() + cachedResponse, ok := h.heartbeatRequests[RequestID(report.RequestId)] + if !ok { + h.lggr.Infow("received report for unknown request, caching it", "id", report.RequestId) + cachedResponse = &HeartbeatResponse{} + h.cacheNewRequestLocked(RequestID(report.RequestId), cachedResponse) + } + cachedResponse.CompletedTs = uint64(time.Now().Unix()) + cachedResponse.Status = RequestStateComplete + cachedResponse.Response = report + h.mu.Unlock() + case <-h.chStop: + h.lggr.Info("exiting reportLoop") + return + } + } +} + +func (h *functionsConnectorHandler) cacheNewRequestLocked(requestId RequestID, response *HeartbeatResponse) { + // remove oldest requests + for len(h.orderedRequests) >= HeartbeatCacheSize { + delete(h.heartbeatRequests, h.orderedRequests[0]) + h.orderedRequests = h.orderedRequests[1:] + } + h.heartbeatRequests[requestId] = response + h.orderedRequests = append(h.orderedRequests, requestId) +} + func (h *functionsConnectorHandler) sendResponseAndLog(ctx context.Context, gatewayId string, requestBody *api.MessageBody, payload any) { err := h.sendResponse(ctx, gatewayId, requestBody, payload) if err != nil { diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index 82c3dab3af..fe1a1baa6f 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -1,16 +1,20 @@ package functions_test import ( + "crypto/rand" "encoding/base64" "encoding/json" "errors" "math/big" "testing" + geth_common "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/functions" + sfmocks "github.com/smartcontractkit/chainlink/v2/core/services/functions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" gcmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector/mocks" @@ -24,6 +28,31 @@ import ( "github.com/stretchr/testify/require" ) +func newOffchainRequest(t *testing.T, sender []byte) (*api.Message, functions.RequestID) { + requestId := make([]byte, 32) + _, err := rand.Read(requestId) + require.NoError(t, err) + request := &functions.OffchainRequest{ + RequestId: requestId, + RequestInitiator: sender, + SubscriptionId: 1, + SubscriptionOwner: sender, + } + + internalId := functions.InternalId(request.RequestInitiator, request.RequestId) + req, err := json.Marshal(request) + require.NoError(t, err) + msg := &api.Message{ + Body: api.MessageBody{ + DonId: "fun4", + MessageId: "1", + Method: "heartbeat", + Payload: req, + }, + } + return msg, internalId +} + func TestFunctionsConnectorHandler(t *testing.T) { t.Parallel() @@ -34,12 +63,16 @@ func TestFunctionsConnectorHandler(t *testing.T) { allowlist := gfmocks.NewOnchainAllowlist(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) subscriptions := gfmocks.NewOnchainSubscriptions(t) + reportCh := make(chan *functions.OffchainResponse) + offchainTransmitter := sfmocks.NewOffchainTransmitter(t) + offchainTransmitter.On("ReportChannel", mock.Anything).Return(reportCh) + listener := sfmocks.NewFunctionsListener(t) require.NoError(t, err) allowlist.On("Start", mock.Anything).Return(nil) allowlist.On("Close", mock.Anything).Return(nil) subscriptions.On("Start", mock.Anything).Return(nil) subscriptions.On("Close", mock.Anything).Return(nil) - handler, err := functions.NewFunctionsConnectorHandler(addr.Hex(), privateKey, storage, allowlist, rateLimiter, subscriptions, *assets.NewLinkFromJuels(100), logger) + handler, err := functions.NewFunctionsConnectorHandler(addr.Hex(), privateKey, storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(100), logger) require.NoError(t, err) handler.SetConnector(connector) @@ -219,4 +252,78 @@ func TestFunctionsConnectorHandler(t *testing.T) { handler.HandleGatewayMessage(testutils.Context(t), "gw1", &msg) }) }) + + t.Run("heartbeat success", func(t *testing.T) { + ctx := testutils.Context(t) + msg, internalId := newOffchainRequest(t, addr.Bytes()) + require.NoError(t, msg.Sign(privateKey)) + + // first call to trigger the request + var response functions.HeartbeatResponse + allowlist.On("Allow", addr).Return(true).Once() + listener.On("HandleOffchainRequest", mock.Anything, mock.Anything).Return(nil).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { + respMsg, ok := args[2].(*api.Message) + require.True(t, ok) + require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) + require.Equal(t, functions.RequestStatePending, response.Status) + }).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + + // async response computation + reportCh <- &functions.OffchainResponse{ + RequestId: internalId[:], + Result: []byte("ok!"), + } + reportCh <- &functions.OffchainResponse{} // sending second item to make sure the first one got processed + + // second call to collect the response + allowlist.On("Allow", addr).Return(true).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { + respMsg, ok := args[2].(*api.Message) + require.True(t, ok) + require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) + require.Equal(t, functions.RequestStateComplete, response.Status) + }).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + }) + + t.Run("heartbeat internal error", func(t *testing.T) { + ctx := testutils.Context(t) + msg, _ := newOffchainRequest(t, addr.Bytes()) + require.NoError(t, msg.Sign(privateKey)) + + // first call to trigger the request + var response functions.HeartbeatResponse + allowlist.On("Allow", addr).Return(true).Once() + listener.On("HandleOffchainRequest", mock.Anything, mock.Anything).Return(errors.New("boom")).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + + // second call to collect the response + allowlist.On("Allow", addr).Return(true).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { + respMsg, ok := args[2].(*api.Message) + require.True(t, ok) + require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) + require.Equal(t, functions.RequestStateInternalError, response.Status) + }).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + }) + + t.Run("heartbeat sender address doesn't match", func(t *testing.T) { + ctx := testutils.Context(t) + msg, _ := newOffchainRequest(t, geth_common.BytesToAddress([]byte("0x1234")).Bytes()) + require.NoError(t, msg.Sign(privateKey)) + + var response functions.HeartbeatResponse + allowlist.On("Allow", addr).Return(true).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { + respMsg, ok := args[2].(*api.Message) + require.True(t, ok) + require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) + require.Equal(t, functions.RequestStateInternalError, response.Status) + }).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + }) } diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index 3a30843180..65c364adb7 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -300,6 +300,9 @@ func (l *functionsListener) HandleOffchainRequest(ctx context.Context, request * if len(request.SubscriptionOwner) != common.AddressLength || len(request.RequestInitiator) != common.AddressLength { return fmt.Errorf("HandleOffchainRequest: SubscriptionOwner and RequestInitiator must be set to valid addresses") } + if request.Timestamp < uint64(time.Now().Unix()-int64(l.pluginConfig.RequestTimeoutSec)) { + return fmt.Errorf("HandleOffchainRequest: request timestamp is too old") + } var requestId RequestID copy(requestId[:], request.RequestId[:32]) diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index ecad9e4cce..0fcc9c6559 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -7,6 +7,7 @@ import ( "math/big" "sync" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/fxamacker/cbor/v2" @@ -195,6 +196,7 @@ func TestFunctionsListener_HandleOffchainRequest_Success(t *testing.T) { RequestInitiator: SubscriptionOwner.Bytes(), SubscriptionId: uint64(SubscriptionID), SubscriptionOwner: SubscriptionOwner.Bytes(), + Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, } require.NoError(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) @@ -210,6 +212,7 @@ func TestFunctionsListener_HandleOffchainRequest_Invalid(t *testing.T) { RequestInitiator: []byte("invalid_address"), SubscriptionId: uint64(SubscriptionID), SubscriptionOwner: SubscriptionOwner.Bytes(), + Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, } require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) @@ -217,6 +220,10 @@ func TestFunctionsListener_HandleOffchainRequest_Invalid(t *testing.T) { request.RequestInitiator = SubscriptionOwner.Bytes() request.SubscriptionOwner = []byte("invalid_address") require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) + + request.SubscriptionOwner = SubscriptionOwner.Bytes() + request.Timestamp = 1 + require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) } func TestFunctionsListener_HandleOffchainRequest_InternalError(t *testing.T) { @@ -233,6 +240,7 @@ func TestFunctionsListener_HandleOffchainRequest_InternalError(t *testing.T) { RequestInitiator: SubscriptionOwner.Bytes(), SubscriptionId: uint64(SubscriptionID), SubscriptionOwner: SubscriptionOwner.Bytes(), + Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, } require.Error(t, uni.service.HandleOffchainRequest(testutils.Context(t), request)) diff --git a/core/services/functions/request.go b/core/services/functions/request.go index 14c0b0d0e5..eaa92fc808 100644 --- a/core/services/functions/request.go +++ b/core/services/functions/request.go @@ -5,6 +5,10 @@ const ( LocationRemote = 1 LocationDONHosted = 2 LanguageJavaScript = 0 + + RequestStatePending = 1 + RequestStateComplete = 2 + RequestStateInternalError = 3 ) type RequestFlags [32]byte @@ -14,6 +18,7 @@ type OffchainRequest struct { RequestInitiator []byte `json:"requestInitiator"` SubscriptionId uint64 `json:"subscriptionId"` SubscriptionOwner []byte `json:"subscriptionOwner"` + Timestamp uint64 `json:"timestamp"` Data RequestData `json:"data"` } @@ -30,8 +35,16 @@ type RequestData struct { // NOTE: to be extended with raw report and signatures when needed type OffchainResponse struct { RequestId []byte `json:"requestId"` - Result []byte `json:"result"` - Error []byte `json:"error"` + Result []byte `json:"result,omitempty"` + Error []byte `json:"error,omitempty"` +} + +type HeartbeatResponse struct { + Status int `json:"status"` + InternalError string `json:"internalError,omitempty"` + ReceivedTs uint64 `json:"receivedTs"` + CompletedTs uint64 `json:"completedTs"` + Response *OffchainResponse `json:"response,omitempty"` } type DONHostedSecrets struct { diff --git a/core/services/gateway/handlers/functions/api.go b/core/services/gateway/handlers/functions/api.go index 202fa99e41..36db194393 100644 --- a/core/services/gateway/handlers/functions/api.go +++ b/core/services/gateway/handlers/functions/api.go @@ -5,6 +5,7 @@ import "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" const ( MethodSecretsSet = "secrets_set" MethodSecretsList = "secrets_list" + MethodHeartbeat = "heartbeat" ) type SecretsSetRequest struct { diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index 3269caa2d6..b52c866a13 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "math/big" + "strings" "time" "github.com/ethereum/go-ethereum/common" @@ -62,26 +63,28 @@ type FunctionsHandlerConfig struct { OnchainSubscriptions *OnchainSubscriptionsConfig `json:"onchainSubscriptions"` MinimumSubscriptionBalance *assets.Link `json:"minimumSubscriptionBalance"` // Not specifying RateLimiter config disables rate limiting - UserRateLimiter *hc.RateLimiterConfig `json:"userRateLimiter"` - NodeRateLimiter *hc.RateLimiterConfig `json:"nodeRateLimiter"` - MaxPendingRequests uint32 `json:"maxPendingRequests"` - RequestTimeoutMillis int64 `json:"requestTimeoutMillis"` + UserRateLimiter *hc.RateLimiterConfig `json:"userRateLimiter"` + NodeRateLimiter *hc.RateLimiterConfig `json:"nodeRateLimiter"` + MaxPendingRequests uint32 `json:"maxPendingRequests"` + RequestTimeoutMillis int64 `json:"requestTimeoutMillis"` + AllowedHeartbeatInitiators []string `json:"allowedHeartbeatInitiators"` } type functionsHandler struct { services.StateMachine - handlerConfig FunctionsHandlerConfig - donConfig *config.DONConfig - don handlers.DON - pendingRequests hc.RequestCache[PendingRequest] - allowlist OnchainAllowlist - subscriptions OnchainSubscriptions - minimumBalance *assets.Link - userRateLimiter *hc.RateLimiter - nodeRateLimiter *hc.RateLimiter - chStop services.StopChan - lggr logger.Logger + handlerConfig FunctionsHandlerConfig + donConfig *config.DONConfig + don handlers.DON + pendingRequests hc.RequestCache[PendingRequest] + allowlist OnchainAllowlist + subscriptions OnchainSubscriptions + minimumBalance *assets.Link + userRateLimiter *hc.RateLimiter + nodeRateLimiter *hc.RateLimiter + allowedHeartbeatInitiators map[string]struct{} + chStop services.StopChan + lggr logger.Logger } type PendingRequest struct { @@ -135,8 +138,12 @@ func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *con return nil, err2 } } + allowedHeartbeatInitiators := make(map[string]struct{}) + for _, initiator := range cfg.AllowedHeartbeatInitiators { + allowedHeartbeatInitiators[strings.ToLower(initiator)] = struct{}{} + } pendingRequestsCache := hc.NewRequestCache[PendingRequest](time.Millisecond*time.Duration(cfg.RequestTimeoutMillis), cfg.MaxPendingRequests) - return NewFunctionsHandler(cfg, donConfig, don, pendingRequestsCache, allowlist, subscriptions, cfg.MinimumSubscriptionBalance, userRateLimiter, nodeRateLimiter, lggr), nil + return NewFunctionsHandler(cfg, donConfig, don, pendingRequestsCache, allowlist, subscriptions, cfg.MinimumSubscriptionBalance, userRateLimiter, nodeRateLimiter, allowedHeartbeatInitiators, lggr), nil } func NewFunctionsHandler( @@ -149,19 +156,21 @@ func NewFunctionsHandler( minimumBalance *assets.Link, userRateLimiter *hc.RateLimiter, nodeRateLimiter *hc.RateLimiter, + allowedHeartbeatInitiators map[string]struct{}, lggr logger.Logger) handlers.Handler { return &functionsHandler{ - handlerConfig: cfg, - donConfig: donConfig, - don: don, - pendingRequests: pendingRequestsCache, - allowlist: allowlist, - subscriptions: subscriptions, - minimumBalance: minimumBalance, - userRateLimiter: userRateLimiter, - nodeRateLimiter: nodeRateLimiter, - chStop: make(services.StopChan), - lggr: lggr, + handlerConfig: cfg, + donConfig: donConfig, + don: don, + pendingRequests: pendingRequestsCache, + allowlist: allowlist, + subscriptions: subscriptions, + minimumBalance: minimumBalance, + userRateLimiter: userRateLimiter, + nodeRateLimiter: nodeRateLimiter, + allowedHeartbeatInitiators: allowedHeartbeatInitiators, + chStop: make(services.StopChan), + lggr: lggr, } } @@ -193,6 +202,13 @@ func (h *functionsHandler) HandleUserMessage(ctx context.Context, msg *api.Messa switch msg.Body.Method { case MethodSecretsSet, MethodSecretsList: return h.handleRequest(ctx, msg, callbackCh) + case MethodHeartbeat: + if _, ok := h.allowedHeartbeatInitiators[msg.Body.Sender]; !ok { + h.lggr.Debugw("received heartbeat request from a non-allowed sender", "sender", msg.Body.Sender) + promHandlerError.WithLabelValues(h.donConfig.DonId, ErrNotAllowlisted.Error()).Inc() + return ErrUnsupportedMethod + } + return h.handleRequest(ctx, msg, callbackCh) default: h.lggr.Debugw("unsupported method", "method", msg.Body.Method) promHandlerError.WithLabelValues(h.donConfig.DonId, ErrUnsupportedMethod.Error()).Inc() @@ -227,6 +243,8 @@ func (h *functionsHandler) HandleNodeMessage(ctx context.Context, msg *api.Messa switch msg.Body.Method { case MethodSecretsSet, MethodSecretsList: return h.pendingRequests.ProcessResponse(msg, h.processSecretsResponse) + case MethodHeartbeat: + return h.pendingRequests.ProcessResponse(msg, h.processHeartbeatResponse) default: h.lggr.Debugw("unsupported method", "method", msg.Body.Method) return ErrUnsupportedMethod @@ -295,6 +313,38 @@ func newSecretsResponse(request *api.Message, success bool, responses []*api.Mes return &handlers.UserCallbackPayload{Msg: &userResponse, ErrCode: api.NoError, ErrMsg: ""}, nil } +// Conforms to ResponseProcessor[*PendingRequest] +func (h *functionsHandler) processHeartbeatResponse(response *api.Message, responseData *PendingRequest) (*handlers.UserCallbackPayload, *PendingRequest, error) { + if _, exists := responseData.responses[response.Body.Sender]; exists { + return nil, nil, errors.New("duplicate response") + } + if response.Body.Method != responseData.request.Body.Method { + return nil, responseData, errors.New("invalid method") + } + responseData.responses[response.Body.Sender] = response + + // user response is ready with F+1 node responses + if len(responseData.responses) >= h.donConfig.F+1 { + var responseList []*api.Message + for _, response := range responseData.responses { + responseList = append(responseList, response) + } + userResponse := *responseData.request + userResponse.Body.Receiver = responseData.request.Body.Sender + // success = true only means that we got F+1 responses + // it's up to the heartbeat sender to validate computation results + payload := CombinedResponse{ResponseBase: ResponseBase{Success: true}, NodeResponses: responseList} + payloadJson, err := json.Marshal(payload) + if err != nil { + return &handlers.UserCallbackPayload{Msg: &userResponse, ErrCode: api.NodeReponseEncodingError, ErrMsg: ""}, nil, nil + } + userResponse.Body.Payload = payloadJson + return &handlers.UserCallbackPayload{Msg: &userResponse, ErrCode: api.NoError, ErrMsg: ""}, nil, nil + } + // not ready to be processed yet + return nil, responseData, nil +} + func (h *functionsHandler) Start(ctx context.Context) error { return h.StartOnce("FunctionsHandler", func() error { h.lggr.Info("starting FunctionsHandler") diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index 402823df17..f36b64709a 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -25,7 +25,7 @@ import ( handlers_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/mocks" ) -func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTimeout time.Duration) (handlers.Handler, *handlers_mocks.DON, *functions_mocks.OnchainAllowlist, *functions_mocks.OnchainSubscriptions) { +func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTimeout time.Duration, heartbeatSender string) (handlers.Handler, *handlers_mocks.DON, *functions_mocks.OnchainAllowlist, *functions_mocks.OnchainSubscriptions) { cfg := functions.FunctionsHandlerConfig{} donConfig := &config.DONConfig{ Members: []config.NodeConfig{}, @@ -48,7 +48,8 @@ func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTi nodeRateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) pendingRequestsCache := hc.NewRequestCache[functions.PendingRequest](requestTimeout, 1000) - handler := functions.NewFunctionsHandler(cfg, donConfig, don, pendingRequestsCache, allowlist, subscriptions, minBalance, userRateLimiter, nodeRateLimiter, logger.TestLogger(t)) + allowedHeartbeatInititors := map[string]struct{}{heartbeatSender: {}} + handler := functions.NewFunctionsHandler(cfg, donConfig, don, pendingRequestsCache, allowlist, subscriptions, minBalance, userRateLimiter, nodeRateLimiter, allowedHeartbeatInititors, logger.TestLogger(t)) return handler, don, allowlist, subscriptions } @@ -117,7 +118,7 @@ func TestFunctionsHandler_HandleUserMessage_SecretsSet(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { nodes, user := gc.NewTestNodes(t, 4), gc.NewTestNodes(t, 1)[0] - handler, don, allowlist, subscriptions := newFunctionsHandlerForATestDON(t, nodes, time.Hour*24) + handler, don, allowlist, subscriptions := newFunctionsHandlerForATestDON(t, nodes, time.Hour*24, user.Address) userRequestMsg := newSignedMessage(t, "1234", "secrets_set", "don_id", user.PrivateKey) callbachCh := make(chan handlers.UserCallbackPayload) @@ -144,11 +145,54 @@ func TestFunctionsHandler_HandleUserMessage_SecretsSet(t *testing.T) { } } +func TestFunctionsHandler_HandleUserMessage_Heartbeat(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + nodeResults []bool + expectedGatewayResult bool + expectedNodeMessageCount int + }{ + {"three successful", []bool{true, true, true, false}, true, 2}, + {"two successful", []bool{false, true, false, true}, true, 2}, + {"one successful", []bool{false, true, false, false}, true, 2}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + nodes, user := gc.NewTestNodes(t, 4), gc.NewTestNodes(t, 1)[0] + handler, don, allowlist, _ := newFunctionsHandlerForATestDON(t, nodes, time.Hour*24, user.Address) + userRequestMsg := newSignedMessage(t, "1234", "heartbeat", "don_id", user.PrivateKey) + + callbachCh := make(chan handlers.UserCallbackPayload) + done := make(chan struct{}) + go func() { + defer close(done) + // wait on a response from Gateway to the user + response := <-callbachCh + require.Equal(t, api.NoError, response.ErrCode) + require.Equal(t, userRequestMsg.Body.MessageId, response.Msg.Body.MessageId) + var payload functions.CombinedResponse + require.NoError(t, json.Unmarshal(response.Msg.Body.Payload, &payload)) + require.Equal(t, test.expectedGatewayResult, payload.Success) + require.Equal(t, test.expectedNodeMessageCount, len(payload.NodeResponses)) + }() + + allowlist.On("Allow", common.HexToAddress(user.Address)).Return(true, nil) + don.On("SendToNode", mock.Anything, mock.Anything, mock.Anything).Return(nil) + require.NoError(t, handler.HandleUserMessage(testutils.Context(t), &userRequestMsg, callbachCh)) + sendNodeReponses(t, handler, userRequestMsg, nodes, test.nodeResults) + <-done + }) + } +} + func TestFunctionsHandler_HandleUserMessage_InvalidMethod(t *testing.T) { t.Parallel() nodes, user := gc.NewTestNodes(t, 4), gc.NewTestNodes(t, 1)[0] - handler, _, allowlist, _ := newFunctionsHandlerForATestDON(t, nodes, time.Hour*24) + handler, _, allowlist, _ := newFunctionsHandlerForATestDON(t, nodes, time.Hour*24, user.Address) userRequestMsg := newSignedMessage(t, "1234", "secrets_reveal_all_please", "don_id", user.PrivateKey) allowlist.On("Allow", common.HexToAddress(user.Address)).Return(true, nil) @@ -160,7 +204,7 @@ func TestFunctionsHandler_HandleUserMessage_Timeout(t *testing.T) { t.Parallel() nodes, user := gc.NewTestNodes(t, 4), gc.NewTestNodes(t, 1)[0] - handler, don, allowlist, subscriptions := newFunctionsHandlerForATestDON(t, nodes, time.Millisecond*10) + handler, don, allowlist, subscriptions := newFunctionsHandlerForATestDON(t, nodes, time.Millisecond*10, user.Address) userRequestMsg := newSignedMessage(t, "1234", "secrets_set", "don_id", user.PrivateKey) callbachCh := make(chan handlers.UserCallbackPayload) diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 475cf0a2af..82280f527c 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -146,7 +146,7 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs return nil, errors.Wrap(err, "failed to create a OnchainSubscriptions") } connectorLogger := conf.Logger.Named("GatewayConnector").With("jobName", conf.Job.PipelineSpec.JobName) - connector, err2 := NewConnector(pluginConfig.GatewayConnectorConfig, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, pluginConfig.MinimumSubscriptionBalance, connectorLogger) + connector, err2 := NewConnector(pluginConfig.GatewayConnectorConfig, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, pluginConfig.MinimumSubscriptionBalance, connectorLogger) if err2 != nil { return nil, errors.Wrap(err, "failed to create a GatewayConnector") } @@ -173,7 +173,7 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs return allServices, nil } -func NewConnector(gwcCfg *connector.ConnectorConfig, ethKeystore keystore.Eth, chainID *big.Int, s4Storage s4.Storage, allowlist gwFunctions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwFunctions.OnchainSubscriptions, minimumBalance assets.Link, lggr logger.Logger) (connector.GatewayConnector, error) { +func NewConnector(gwcCfg *connector.ConnectorConfig, ethKeystore keystore.Eth, chainID *big.Int, s4Storage s4.Storage, allowlist gwFunctions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwFunctions.OnchainSubscriptions, listener functions.FunctionsListener, offchainTransmitter functions.OffchainTransmitter, minimumBalance assets.Link, lggr logger.Logger) (connector.GatewayConnector, error) { enabledKeys, err := ethKeystore.EnabledKeysForChain(chainID) if err != nil { return nil, err @@ -186,7 +186,7 @@ func NewConnector(gwcCfg *connector.ConnectorConfig, ethKeystore keystore.Eth, c signerKey := enabledKeys[idx].ToEcdsaPrivKey() nodeAddress := enabledKeys[idx].ID() - handler, err := functions.NewFunctionsConnectorHandler(nodeAddress, signerKey, s4Storage, allowlist, rateLimiter, subscriptions, minimumBalance, lggr) + handler, err := functions.NewFunctionsConnectorHandler(nodeAddress, signerKey, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, minimumBalance, lggr) if err != nil { return nil, err } diff --git a/core/services/ocr2/plugins/functions/plugin_test.go b/core/services/ocr2/plugins/functions/plugin_test.go index 453d4b67aa..d77fabcc43 100644 --- a/core/services/ocr2/plugins/functions/plugin_test.go +++ b/core/services/ocr2/plugins/functions/plugin_test.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/logger" + sfmocks "github.com/smartcontractkit/chainlink/v2/core/services/functions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" gfmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" @@ -35,8 +36,10 @@ func TestNewConnector_Success(t *testing.T) { subscriptions := gfmocks.NewOnchainSubscriptions(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) + listener := sfmocks.NewFunctionsListener(t) + offchainTransmitter := sfmocks.NewOffchainTransmitter(t) ethKeystore.On("EnabledKeysForChain", mock.Anything).Return([]ethkey.KeyV2{keyV2}, nil) - _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) + _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) require.NoError(t, err) } @@ -58,7 +61,9 @@ func TestNewConnector_NoKeyForConfiguredAddress(t *testing.T) { subscriptions := gfmocks.NewOnchainSubscriptions(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) + listener := sfmocks.NewFunctionsListener(t) + offchainTransmitter := sfmocks.NewOffchainTransmitter(t) ethKeystore.On("EnabledKeysForChain", mock.Anything).Return([]ethkey.KeyV2{{Address: common.HexToAddress(addresses[1])}}, nil) - _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) + _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) require.Error(t, err) } From bd7e233d3a489e8dacae0a8c8539802b3ae10832 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Tue, 28 Nov 2023 01:52:02 +0200 Subject: [PATCH 205/327] Remove core logger from common (#11366) * Remove core logger from common * Remove core logger from evm * Move legacy config to fix logger dependencies * Fix lint * Revert multinode trace removal * Fix lint * Fix testcase * Fix arbgas command logging * Fix imports * Fix sendonly node logger * Fix lint again * Minor fixes * bump chainlink-common --------- Co-authored-by: Jordan Krage --- common/client/multi_node.go | 37 +++++------ common/client/multi_node_test.go | 20 +++--- common/client/node.go | 7 ++- common/client/node_lifecycle.go | 32 +++++----- common/client/node_lifecycle_test.go | 44 ++++++------- common/client/node_test.go | 4 +- common/client/send_only_node.go | 5 +- common/client/send_only_node_test.go | 14 ++--- common/fee/models.go | 2 +- common/headtracker/head_broadcaster.go | 5 +- common/headtracker/head_listener.go | 4 +- common/headtracker/head_tracker.go | 8 +-- common/txmgr/broadcaster.go | 55 ++++++++-------- common/txmgr/confirmer.go | 17 ++--- common/txmgr/reaper.go | 4 +- common/txmgr/resender.go | 5 +- common/txmgr/txmgr.go | 8 +-- common/txmgr/types/client.go | 2 +- .../txmgr/types/mocks/tx_attempt_builder.go | 2 +- common/txmgr/types/tx.go | 24 +++---- common/txmgr/types/tx_attempt_builder.go | 2 +- core/chains/evm/client/chain_client.go | 3 +- core/chains/evm/client/client.go | 3 +- core/chains/evm/client/errors.go | 8 +-- core/chains/evm/client/helpers_test.go | 8 +-- core/chains/evm/client/node.go | 62 ++++++++++--------- core/chains/evm/client/node_fsm_test.go | 4 +- core/chains/evm/client/node_lifecycle.go | 32 +++++----- core/chains/evm/client/node_lifecycle_test.go | 30 ++++----- core/chains/evm/client/null_client.go | 6 +- core/chains/evm/client/null_client_test.go | 8 +-- core/chains/evm/client/pool.go | 15 ++--- core/chains/evm/client/pool_test.go | 14 ++--- core/chains/evm/client/rpc_client.go | 62 ++++++++++--------- core/chains/evm/client/send_only_node.go | 7 ++- core/chains/evm/client/send_only_node_test.go | 18 +++--- .../evm/client/simulated_backend_client.go | 5 +- core/chains/evm/config/chain_scoped.go | 3 +- .../evm/forwarders/forwarder_manager.go | 4 +- .../evm/forwarders/forwarder_manager_test.go | 10 +-- core/chains/evm/forwarders/orm.go | 2 +- core/chains/evm/forwarders/orm_test.go | 4 +- core/chains/evm/gas/arbitrum_estimator.go | 4 +- .../chains/evm/gas/arbitrum_estimator_test.go | 18 +++--- .../chains/evm/gas/block_history_estimator.go | 21 ++++--- .../evm/gas/block_history_estimator_test.go | 44 ++++++------- core/chains/evm/gas/cmd/arbgas/main.go | 10 +-- core/chains/evm/gas/fixed_price_estimator.go | 4 +- .../evm/gas/fixed_price_estimator_test.go | 14 ++--- core/chains/evm/gas/gas_test.go | 14 ++--- core/chains/evm/gas/models.go | 2 +- .../evm/gas/rollups/l1_gas_price_oracle.go | 7 ++- .../gas/rollups/l1_gas_price_oracle_test.go | 14 ++--- .../evm/gas/suggested_price_estimator.go | 5 +- .../evm/gas/suggested_price_estimator_test.go | 14 ++--- .../evm/headtracker/head_broadcaster.go | 2 +- .../evm/headtracker/head_broadcaster_test.go | 8 +-- core/chains/evm/headtracker/head_listener.go | 2 +- .../evm/headtracker/head_listener_test.go | 8 +-- core/chains/evm/headtracker/head_saver.go | 4 +- .../chains/evm/headtracker/head_saver_test.go | 4 +- core/chains/evm/headtracker/head_tracker.go | 2 +- .../evm/headtracker/head_tracker_test.go | 46 +++++++------- core/chains/evm/headtracker/orm.go | 4 +- core/chains/evm/headtracker/orm_test.go | 12 ++-- core/chains/evm/log/broadcaster.go | 6 +- core/chains/evm/log/eth_subscriber.go | 6 +- core/chains/evm/log/helpers_internal_test.go | 2 +- core/chains/evm/log/helpers_test.go | 8 +-- core/chains/evm/log/integration_test.go | 16 ++--- core/chains/evm/log/orm.go | 2 +- core/chains/evm/log/orm_test.go | 10 +-- core/chains/evm/log/pool.go | 4 +- core/chains/evm/log/pool_test.go | 18 +++--- core/chains/evm/log/registrations.go | 22 +++---- core/chains/evm/log/registrations_test.go | 4 +- core/chains/evm/logpoller/helper_test.go | 4 +- core/chains/evm/logpoller/log_poller.go | 8 +-- .../evm/logpoller/log_poller_internal_test.go | 15 ++--- core/chains/evm/logpoller/log_poller_test.go | 14 ++--- core/chains/evm/logpoller/observability.go | 2 +- .../evm/logpoller/observability_test.go | 4 +- core/chains/evm/logpoller/orm.go | 4 +- core/chains/evm/logpoller/orm_test.go | 6 +- core/chains/evm/monitor/balance.go | 9 +-- core/chains/evm/monitor/balance_test.go | 14 ++--- core/chains/evm/txmgr/attempts.go | 2 +- core/chains/evm/txmgr/attempts_test.go | 10 +-- core/chains/evm/txmgr/broadcaster_test.go | 15 ++--- core/chains/evm/txmgr/builder.go | 2 +- core/chains/evm/txmgr/client.go | 6 +- core/chains/evm/txmgr/common.go | 2 +- core/chains/evm/txmgr/confirmer_test.go | 10 +-- core/chains/evm/txmgr/evm_tx_store.go | 6 +- core/chains/evm/txmgr/evm_tx_store_test.go | 10 +-- core/chains/evm/txmgr/nonce_syncer.go | 4 +- core/chains/evm/txmgr/nonce_syncer_test.go | 10 +-- core/chains/evm/txmgr/reaper_test.go | 4 +- core/chains/evm/txmgr/resender_test.go | 8 +-- core/chains/evm/txmgr/transmitchecker.go | 4 +- core/chains/evm/txmgr/transmitchecker_test.go | 5 +- core/chains/evm/txmgr/txmgr_test.go | 18 +++--- core/chains/{evm => legacyevm}/chain.go | 2 +- core/chains/{evm => legacyevm}/chain_test.go | 16 ++--- core/chains/{evm => legacyevm}/evm_txm.go | 2 +- core/chains/{evm => legacyevm}/mocks/chain.go | 0 .../mocks/legacy_chain_container.go | 30 ++++----- core/cmd/shell.go | 4 +- core/cmd/shell_local_test.go | 12 ++-- core/internal/cltest/cltest.go | 6 +- core/internal/cltest/mocks.go | 12 ++-- core/internal/testutils/evmtest/evmtest.go | 14 ++--- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/blockhashstore/delegate.go | 6 +- core/services/blockhashstore/delegate_test.go | 4 +- core/services/blockheaderfeeder/delegate.go | 6 +- .../mocks/relayer_chain_interoperators.go | 6 +- .../chainlink/relayer_chain_interoperators.go | 12 ++-- .../relayer_chain_interoperators_test.go | 6 +- core/services/chainlink/relayer_factory.go | 8 +-- core/services/directrequest/delegate.go | 6 +- core/services/feeds/service.go | 6 +- core/services/feeds/service_test.go | 4 +- core/services/fluxmonitorv2/delegate.go | 6 +- core/services/gateway/delegate.go | 6 +- core/services/gateway/handler_factory.go | 6 +- .../handlers/functions/handler.functions.go | 4 +- core/services/keeper/delegate.go | 6 +- core/services/keeper/upkeep_executer_test.go | 4 +- core/services/ocr/delegate.go | 8 +-- core/services/ocr/validate.go | 4 +- core/services/ocr2/delegate.go | 8 +-- .../services/ocr2/plugins/functions/plugin.go | 4 +- .../ocr2/plugins/ocr2keeper/evm20/registry.go | 4 +- .../ocr2/plugins/ocr2keeper/evm21/registry.go | 4 +- .../ocr2/plugins/ocr2keeper/evm21/services.go | 4 +- core/services/ocr2/plugins/ocr2keeper/util.go | 8 +-- core/services/pipeline/helpers_test.go | 6 +- core/services/pipeline/runner.go | 6 +- core/services/pipeline/task.estimategas.go | 4 +- core/services/pipeline/task.eth_call.go | 4 +- core/services/pipeline/task.eth_call_test.go | 4 +- core/services/pipeline/task.eth_tx.go | 4 +- core/services/relay/evm/evm.go | 12 ++-- core/services/relay/evm/functions.go | 6 +- core/services/relay/evm/loop_impl.go | 6 +- core/services/relay/evm/median.go | 4 +- .../relay/evm/mocks/loop_relay_adapter.go | 11 ++-- core/services/relay/evm/ocr2keeper.go | 8 +-- core/services/relay/evm/ocr2vrf.go | 8 +-- core/services/relay/evm/relayer_extender.go | 29 +++++---- core/services/vrf/delegate.go | 6 +- core/services/vrf/delegate_test.go | 4 +- core/services/vrf/v1/listener_v1.go | 4 +- core/services/vrf/v2/integration_v2_test.go | 4 +- core/services/vrf/v2/listener_v2.go | 6 +- core/services/vrf/v2/listener_v2_test.go | 6 +- core/web/common.go | 4 +- core/web/eth_keys_controller.go | 4 +- core/web/evm_transfer_controller.go | 4 +- core/web/resolver/eth_key.go | 4 +- core/web/resolver/eth_key_test.go | 6 +- core/web/resolver/resolver_test.go | 9 +-- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 168 files changed, 812 insertions(+), 783 deletions(-) rename core/chains/{evm => legacyevm}/chain.go (99%) rename core/chains/{evm => legacyevm}/chain_test.go (80%) rename core/chains/{evm => legacyevm}/evm_txm.go (99%) rename core/chains/{evm => legacyevm}/mocks/chain.go (100%) rename core/chains/{evm => legacyevm}/mocks/legacy_chain_container.go (73%) diff --git a/common/client/multi_node.go b/common/client/multi_node.go index 48a4d37ad8..3f72d04124 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -12,12 +12,12 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -87,7 +87,7 @@ type multiNode[ sendonlys []SendOnlyNode[CHAIN_ID, RPC_CLIENT] chainID CHAIN_ID chainType config.ChainType - logger logger.Logger + lggr logger.Logger selectionMode string noNewHeadsThreshold time.Duration nodeSelector NodeSelector[CHAIN_ID, HEAD, RPC_CLIENT] @@ -119,7 +119,7 @@ func NewMultiNode[ HEAD types.Head[BLOCK_HASH], RPC_CLIENT RPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD], ]( - logger logger.Logger, + l logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, @@ -132,7 +132,8 @@ func NewMultiNode[ ) MultiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT] { nodeSelector := newNodeSelector(selectionMode, nodes) - lggr := logger.Named("MultiNode").With("chainID", chainID.String()) + lggr := logger.Named(l, "MultiNode") + lggr = logger.With(lggr, "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) @@ -142,7 +143,7 @@ func NewMultiNode[ sendonlys: sendonlys, chainID: chainID, chainType: chainType, - logger: lggr, + lggr: lggr, selectionMode: selectionMode, noNewHeadsThreshold: noNewHeadsThreshold, nodeSelector: nodeSelector, @@ -153,7 +154,7 @@ func NewMultiNode[ reportInterval: reportInterval, } - c.logger.Debugf("The MultiNode is configured to use NodeSelectionMode: %s", selectionMode) + c.lggr.Debugf("The MultiNode is configured to use NodeSelectionMode: %s", selectionMode) return c } @@ -197,11 +198,11 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP go c.runLoop() if c.leaseDuration.Seconds() > 0 && c.selectionMode != NodeSelectionModeRoundRobin { - c.logger.Infof("The MultiNode will switch to best node every %s", c.leaseDuration.String()) + c.lggr.Infof("The MultiNode will switch to best node every %s", c.leaseDuration.String()) c.wg.Add(1) go c.checkLeaseLoop() } else { - c.logger.Info("Best node switching is disabled") + c.lggr.Info("Best node switching is disabled") } return nil @@ -249,7 +250,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP c.activeNode = c.nodeSelector.Select() if c.activeNode == nil { - c.logger.Criticalw("No live RPC nodes available", "NodeSelectionMode", c.nodeSelector.Name()) + logger.Criticalw(c.lggr, "No live RPC nodes available", "NodeSelectionMode", c.nodeSelector.Name()) errmsg := fmt.Errorf("no live nodes available for chain %s", c.chainID.String()) c.SvcErrBuffer.Append(errmsg) err = ErroringNodeError @@ -282,7 +283,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP // Terminate client subscriptions. Services are responsible for reconnecting, which will be routed to the new // best node. Only terminate connections with more than 1 subscription to account for the aliveLoop subscription if n.State() == nodeStateAlive && n != bestNode && n.SubscribersCount() > 1 { - c.logger.Infof("Switching to best node from %q to %q", n.String(), bestNode.String()) + c.lggr.Infof("Switching to best node from %q to %q", n.String(), bestNode.String()) n.UnsubscribeAllExceptAliveLoop() } } @@ -351,13 +352,13 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP } live := total - dead - c.logger.Tracew(fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + logger.Tracew(c.lggr, fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) if total == dead { rerr := fmt.Errorf("no primary nodes available: 0/%d nodes are alive", total) - c.logger.Criticalw(rerr.Error(), "nodeStates", nodeStates) + logger.Criticalw(c.lggr, rerr.Error(), "nodeStates", nodeStates) c.SvcErrBuffer.Append(rerr) } else if dead > 0 { - c.logger.Errorw(fmt.Sprintf("At least one primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + c.lggr.Errorw(fmt.Sprintf("At least one primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) } } @@ -403,9 +404,9 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP defer wg.Done() err := n.RPC().BatchCallContext(ctx, b) if err != nil { - c.logger.Debugw("Secondary node BatchCallContext failed", "err", err) + c.lggr.Debugw("Secondary node BatchCallContext failed", "err", err) } else { - c.logger.Trace("Secondary node BatchCallContext success") + logger.Trace(c.lggr, "Secondary node BatchCallContext success") } }(n) } @@ -572,15 +573,15 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP defer c.wg.Done() txErr := n.RPC().SendTransaction(ctx, tx) - c.logger.Debugw("Sendonly node sent transaction", "name", n.String(), "tx", tx, "err", txErr) + c.lggr.Debugw("Sendonly node sent transaction", "name", n.String(), "tx", tx, "err", txErr) sendOnlyError := c.sendOnlyErrorParser(txErr) if sendOnlyError != Successful { - c.logger.Warnw("RPC returned error", "name", n.String(), "tx", tx, "err", txErr) + c.lggr.Warnw("RPC returned error", "name", n.String(), "tx", tx, "err", txErr) } }(n) }) if !ok { - c.logger.Debug("Cannot send transaction on sendonly node; MultiNode is stopped", "node", n.String()) + c.lggr.Debug("Cannot send transaction on sendonly node; MultiNode is stopped", "node", n.String()) } } if nodeError != nil { diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 4c0ebb1db9..45ffb74537 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -12,11 +12,11 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -43,7 +43,7 @@ type multiNodeOpts struct { func newTestMultiNode(t *testing.T, opts multiNodeOpts) testMultiNode { if opts.logger == nil { - opts.logger = logger.TestLogger(t) + opts.logger = logger.Test(t) } result := NewMultiNode[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, @@ -211,7 +211,7 @@ func TestMultiNode_Report(t *testing.T) { chainID := types.RandomID() node1 := newHealthyNode(t, chainID) node2 := newNodeWithState(t, chainID, nodeStateOutOfSync) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeRoundRobin, chainID: chainID, @@ -228,7 +228,7 @@ func TestMultiNode_Report(t *testing.T) { t.Parallel() chainID := types.RandomID() node := newNodeWithState(t, chainID, nodeStateOutOfSync) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeRoundRobin, chainID: chainID, @@ -252,7 +252,7 @@ func TestMultiNode_CheckLease(t *testing.T) { t.Parallel() chainID := types.RandomID() node := newHealthyNode(t, chainID) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + lggr, observedLogs := logger.TestObserved(t, zap.InfoLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeRoundRobin, chainID: chainID, @@ -268,7 +268,7 @@ func TestMultiNode_CheckLease(t *testing.T) { t.Parallel() chainID := types.RandomID() node := newHealthyNode(t, chainID) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + lggr, observedLogs := logger.TestObserved(t, zap.InfoLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeHighestHead, chainID: chainID, @@ -290,7 +290,7 @@ func TestMultiNode_CheckLease(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.InfoLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeHighestHead, chainID: chainID, @@ -402,7 +402,7 @@ func TestMultiNode_selectNode(t *testing.T) { t.Run("No active nodes - reports critical error", func(t *testing.T) { t.Parallel() chainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + lggr, observedLogs := logger.TestObserved(t, zap.InfoLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeRoundRobin, chainID: chainID, @@ -541,7 +541,7 @@ func TestMultiNode_BatchCallContextAll(t *testing.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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeRoundRobin, chainID: types.RandomID(), @@ -610,7 +610,7 @@ func TestMultiNode_SendTransaction(t *testing.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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) mn := newTestMultiNode(t, multiNodeOpts{ selectionMode: NodeSelectionModeRoundRobin, chainID: types.RandomID(), diff --git a/common/client/node.go b/common/client/node.go index 5faaa5da62..b2d3a33a5b 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -11,10 +11,10 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -135,14 +135,15 @@ func NewNode[ n.http = httpuri } n.nodeCtx, n.cancelNodeCtx = context.WithCancel(context.Background()) - lggr = lggr.Named("Node").With( + lggr = logger.Named(lggr, "Node") + lggr = logger.With(lggr, "nodeTier", Primary.String(), "nodeName", name, "node", n.String(), "chainID", chainID, "nodeOrder", n.order, ) - n.lfcLog = lggr.Named("Lifecycle") + n.lfcLog = logger.Named(lggr, "Lifecycle") n.stateLatestBlockNumber = -1 n.rpc = rpc n.chainFamily = chainFamily diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 4193560e29..9b47412766 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -10,6 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -88,8 +89,9 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() pollInterval := n.nodePoolCfg.PollInterval() - lggr := n.lfcLog.Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) - lggr.Tracew("Alive loop starting", "nodeState", n.State()) + lggr := logger.Named(n.lfcLog, "Alive") + lggr = logger.With(lggr, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) + logger.Tracew(lggr, "Alive loop starting", "nodeState", n.State()) headsC := make(chan HEAD) sub, err := n.rpc.Subscribe(n.nodeCtx, headsC, rpcSubscriptionMethodNewHeads) @@ -140,7 +142,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { case <-pollCh: var version string promPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + logger.Tracew(lggr, "Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) ctx, cancel := context.WithTimeout(n.nodeCtx, pollInterval) version, err := n.RPC().ClientVersion(ctx) cancel() @@ -160,7 +162,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) + logger.Criticalf(lggr, "RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) continue } } @@ -172,7 +174,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { // note: there must be another live node for us to be out of sync lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) if liveNodes < 2 { - lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) + logger.Criticalf(lggr, "RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) continue } n.declareOutOfSync(n.isOutOfSync) @@ -185,13 +187,13 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { return } promPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Tracew("Got head", "head", bh) + logger.Tracew(lggr, "Got head", "head", bh) if bh.BlockNumber() > highestReceivedBlockNumber { promPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.BlockNumber())) - lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + logger.Tracew(lggr, "Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) highestReceivedBlockNumber = bh.BlockNumber() } else { - lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + logger.Tracew(lggr, "Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) } if outOfSyncT != nil { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) @@ -207,7 +209,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) + logger.Criticalf(lggr, "RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) @@ -273,7 +275,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td outOfSyncAt := time.Now() - lggr := n.lfcLog.Named("OutOfSync") + lggr := logger.Named(n.lfcLog, "OutOfSync") lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) // Need to redial since out-of-sync nodes are automatically disconnected @@ -290,7 +292,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td return } - lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) + logger.Tracew(lggr, "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, rpcSubscriptionMethodNewHeads) @@ -322,7 +324,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { - lggr.Critical("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") + logger.Critical(lggr, "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") n.declareInSync() return } @@ -352,7 +354,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { unreachableAt := time.Now() - lggr := n.lfcLog.Named("Unreachable") + lggr := logger.Named(n.lfcLog, "Unreachable") lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) dialRetryBackoff := utils.NewRedialBackoff() @@ -362,7 +364,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { case <-n.nodeCtx.Done(): return case <-time.After(dialRetryBackoff.Duration()): - lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) + logger.Tracew(lggr, "Trying to re-dial RPC node", "nodeState", n.State()) err := n.rpc.Dial(n.nodeCtx) if err != nil { @@ -408,7 +410,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { invalidAt := time.Now() - lggr := n.lfcLog.Named("InvalidChainID") + lggr := logger.Named(n.lfcLog, "InvalidChainID") lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.State()) chainIDRecheckBackoff := utils.NewRedialBackoff() diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index 0dffe935fe..51b44ac516 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/mock" "go.uber.org/zap" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/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" ) @@ -60,7 +60,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) node := newDialedNode(t, testNodeOpts{ rpc: rpc, lggr: lggr, @@ -94,7 +94,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{}, rpc: rpc, @@ -109,7 +109,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) const pollFailureThreshold = 3 node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{ @@ -151,7 +151,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) const pollFailureThreshold = 3 node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{ @@ -177,7 +177,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) const pollFailureThreshold = 3 node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{ @@ -200,7 +200,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) const syncThreshold = 10 node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{ @@ -231,7 +231,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) const syncThreshold = 10 node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{ @@ -254,7 +254,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{ pollInterval: tests.TestInterval, @@ -302,7 +302,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{}, lggr: lggr, @@ -329,7 +329,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { close(ch) }).Return(sub, nil).Once() rpc.On("SetAliveLoopSub", sub).Once() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) node := newDialedNode(t, testNodeOpts{ lggr: lggr, config: testNodeConfig{}, @@ -426,7 +426,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newAliveNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -531,7 +531,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) node := newAliveNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -560,7 +560,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) node := newAliveNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -591,7 +591,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newAliveNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -627,7 +627,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newAliveNode(t, testNodeOpts{ noNewHeadsThreshold: tests.TestInterval, rpc: rpc, @@ -682,7 +682,7 @@ func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newAliveNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -698,7 +698,7 @@ func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newAliveNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -775,7 +775,7 @@ func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newDialedNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -797,7 +797,7 @@ func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.NewIDFromInt(10) rpcChainID := types.NewIDFromInt(11) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newDialedNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -846,7 +846,7 @@ func TestUnit_NodeLifecycle_start(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, @@ -868,7 +868,7 @@ func TestUnit_NodeLifecycle_start(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, diff --git a/common/client/node_test.go b/common/client/node_test.go index 0438e11e61..7b6a38e395 100644 --- a/common/client/node_test.go +++ b/common/client/node_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type testNodeConfig struct { @@ -52,7 +52,7 @@ type testNodeOpts struct { func newTestNode(t *testing.T, opts testNodeOpts) testNode { if opts.lggr == nil { - opts.lggr = logger.TestLogger(t) + opts.lggr = logger.Test(t) } if opts.name == "" { diff --git a/common/client/send_only_node.go b/common/client/send_only_node.go index 904916122f..b63e93b703 100644 --- a/common/client/send_only_node.go +++ b/common/client/send_only_node.go @@ -6,10 +6,10 @@ import ( "net/url" "sync" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) //go:generate mockery --quiet --name sendOnlyClient --structname mockSendOnlyClient --filename "mock_send_only_client_test.go" --inpackage --case=underscore @@ -75,7 +75,8 @@ func NewSendOnlyNode[ ) SendOnlyNode[CHAIN_ID, RPC] { s := new(sendOnlyNode[CHAIN_ID, RPC]) s.name = name - s.log = lggr.Named("SendOnlyNode").Named(name).With( + s.log = logger.Named(logger.Named(lggr, "SendOnlyNode"), name) + s.log = logger.With(s.log, "nodeTier", "sendonly", ) s.rpc = rpc diff --git a/common/client/send_only_node_test.go b/common/client/send_only_node_test.go index 3034b3f0a1..459f923cba 100644 --- a/common/client/send_only_node_test.go +++ b/common/client/send_only_node_test.go @@ -11,10 +11,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestNewSendOnlyNode(t *testing.T) { @@ -25,7 +25,7 @@ func TestNewSendOnlyNode(t *testing.T) { u, err := url.Parse(fmt.Sprintf(urlFormat, password)) require.NoError(t, err) redacted := fmt.Sprintf(urlFormat, "xxxxx") - lggr := logger.TestLogger(t) + lggr := logger.Test(t) name := "TestNewSendOnlyNode" chainID := types.RandomID() client := newMockSendOnlyClient[types.ID](t) @@ -42,7 +42,7 @@ 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) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) client := newMockSendOnlyClient[types.ID](t) client.On("Close").Once() expectedError := errors.New("some http error") @@ -58,7 +58,7 @@ func TestStartSendOnlyNode(t *testing.T) { }) t.Run("Default ChainID(0) produces warn and skips checks", func(t *testing.T) { t.Parallel() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) client := newMockSendOnlyClient[types.ID](t) client.On("Close").Once() client.On("DialHTTP").Return(nil).Once() @@ -73,7 +73,7 @@ func TestStartSendOnlyNode(t *testing.T) { }) t.Run("Can recover from chainID verification failure", func(t *testing.T) { t.Parallel() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) client := newMockSendOnlyClient[types.ID](t) client.On("Close").Once() client.On("DialHTTP").Return(nil) @@ -97,7 +97,7 @@ func TestStartSendOnlyNode(t *testing.T) { }) t.Run("Can recover from chainID mismatch", func(t *testing.T) { t.Parallel() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) client := newMockSendOnlyClient[types.ID](t) client.On("Close").Once() client.On("DialHTTP").Return(nil).Once() @@ -120,7 +120,7 @@ func TestStartSendOnlyNode(t *testing.T) { }) t.Run("Start with Random ChainID", func(t *testing.T) { t.Parallel() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) client := newMockSendOnlyClient[types.ID](t) client.On("Close").Once() client.On("DialHTTP").Return(nil).Once() diff --git a/common/fee/models.go b/common/fee/models.go index f980c73fc1..1fcb55c530 100644 --- a/common/fee/models.go +++ b/common/fee/models.go @@ -5,8 +5,8 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/chains/label" - "github.com/smartcontractkit/chainlink/v2/core/logger" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index 62b2f47b68..0e676f864f 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -7,9 +7,10 @@ import ( "sync" "time" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -45,7 +46,7 @@ func NewHeadBroadcaster[ lggr logger.Logger, ) *HeadBroadcaster[H, BLOCK_HASH] { return &HeadBroadcaster[H, BLOCK_HASH]{ - logger: lggr.Named("HeadBroadcaster"), + logger: logger.Named(lggr, "HeadBroadcaster"), callbacks: make(callbackSet[H, BLOCK_HASH]), mailbox: utils.NewSingleMailbox[H](), chClose: make(chan struct{}), diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index a3f262f4b7..2013895d0b 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -9,11 +9,11 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -59,7 +59,7 @@ func NewHeadListener[ return &HeadListener[HTH, S, ID, BLOCK_HASH]{ config: config, client: client, - logger: lggr.Named("HeadListener"), + logger: logger.Named(lggr, "HeadListener"), chStop: chStop, } } diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 810e749a2d..34a319e3c1 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -10,12 +10,12 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "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" ) @@ -75,7 +75,7 @@ func NewHeadTracker[ getNilHead func() HTH, ) types.HeadTracker[HTH, BLOCK_HASH] { chStop := make(chan struct{}) - lggr = lggr.Named("HeadTracker") + lggr = logger.Named(lggr, "HeadTracker") return &HeadTracker[HTH, S, ID, BLOCK_HASH]{ headBroadcaster: headBroadcaster, client: client, @@ -229,7 +229,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context prevUnFinalizedHead := prevHead.BlockNumber() - int64(ht.config.FinalityDepth()) if head.BlockNumber() < prevUnFinalizedHead { promOldHead.WithLabelValues(ht.chainID.String()).Inc() - ht.log.Criticalf("Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber()) + logger.Criticalf(ht.log, "Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber()) ht.SvcErrBuffer.Append(errors.New("got very old block")) } } @@ -312,7 +312,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, hea } mark := time.Now() fetched := 0 - l := ht.log.With("blockNumber", headBlockNumber, + l := logger.With(ht.log, "blockNumber", headBlockNumber, "n", headBlockNumber-baseHeight, "fromBlockHeight", baseHeight, "toBlockHeight", headBlockNumber-1) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index d9a72e367a..cff5746a9e 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -16,12 +16,13 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/chains/label" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -107,7 +108,7 @@ type Broadcaster[ FEE feetypes.Fee, ] struct { services.StateMachine - logger logger.Logger + lggr logger.Logger txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] @@ -164,14 +165,14 @@ func NewBroadcaster[ keystore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ], txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], - logger logger.Logger, + lggr logger.Logger, checkerFactory TransmitCheckerFactory[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], autoSyncSequence bool, generateNextSequence types.GenerateNextSequenceFunc[SEQ], ) *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { - logger = logger.Named("Broadcaster") + lggr = logger.Named(lggr, "Broadcaster") b := &Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{ - logger: logger, + lggr: lggr, txStore: txStore, client: client, TxAttemptBuilder: txAttemptBuilder, @@ -213,9 +214,9 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star } if len(eb.enabledAddresses) > 0 { - eb.logger.Debugw(fmt.Sprintf("Booting with %d keys", len(eb.enabledAddresses)), "keys", eb.enabledAddresses) + eb.lggr.Debugw(fmt.Sprintf("Booting with %d keys", len(eb.enabledAddresses)), "keys", eb.enabledAddresses) } else { - eb.logger.Warnf("Chain %s does not have any keys, no transactions will be sent on this chain", eb.chainID.String()) + eb.lggr.Warnf("Chain %s does not have any keys, no transactions will be sent on this chain", eb.chainID.String()) } eb.chStop = make(chan struct{}) eb.wg = sync.WaitGroup{} @@ -259,7 +260,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SetR } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Name() string { - return eb.logger.Name() + return eb.lggr.Name() } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) HealthReport() map[string]error { @@ -280,7 +281,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trig default: } } else { - eb.logger.Debugf("Unstarted; ignoring trigger for %s", addr) + eb.lggr.Debugf("Unstarted; ignoring trigger for %s", addr) } } @@ -314,7 +315,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) getS if err == nil { return seq, nil } - eb.logger.Criticalw("failed to retrieve next sequence from on-chain for address: ", "address", address.String()) + logger.Criticalw(eb.lggr, "failed to retrieve next sequence from on-chain for address: ", "address", address.String()) return seq, err } @@ -342,13 +343,13 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) moni defer cancel() if eb.autoSyncSequence { - eb.logger.Debugw("Auto-syncing sequence", "address", addr.String()) + eb.lggr.Debugw("Auto-syncing sequence", "address", addr.String()) eb.SyncSequence(ctx, addr) if ctx.Err() != nil { return } } else { - eb.logger.Debugw("Skipping sequence auto-sync", "address", addr.String()) + eb.lggr.Debugw("Skipping sequence auto-sync", "address", addr.String()) } // errorRetryCh allows retry on exponential backoff in case of timeout or @@ -361,7 +362,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) moni retryable, err := eb.processUnstartedTxsImpl(ctx, addr) if err != nil { - eb.logger.Errorw("Error occurred while handling tx queue in ProcessUnstartedTxs", "err", err) + eb.lggr.Errorw("Error occurred while handling tx queue in ProcessUnstartedTxs", "err", err) } // On retryable errors we implement exponential backoff retries. This // handles intermittent connectivity, remote RPC races, timing issues etc @@ -402,7 +403,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Sync localSequence, err := eb.GetNextSequence(ctx, addr) // Address not found in map so skip sync if err != nil { - eb.logger.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) + logger.Criticalw(eb.lggr, "Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) return } @@ -417,16 +418,16 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Sync newNextSequence, err := eb.sequenceSyncer.Sync(ctx, addr, localSequence) if err != nil { if attempt > 5 { - eb.logger.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + logger.Criticalw(eb.lggr, "Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) eb.SvcErrBuffer.Append(err) } else { - eb.logger.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + eb.lggr.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) } continue } // Found new sequence to use from on-chain if localSequence.String() != newNextSequence.String() { - eb.logger.Infow("Fast-forward sequence", "address", addr, "newNextSequence", newNextSequence, "oldNextSequence", localSequence) + eb.lggr.Infow("Fast-forward sequence", "address", addr, "newNextSequence", newNextSequence, "oldNextSequence", localSequence) // Set new sequence in the map eb.SetNextSequence(addr, newNextSequence) } @@ -451,7 +452,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc mark := time.Now() defer func() { if n > 0 { - eb.logger.Debugw("Finished processUnstartedTxs", "address", fromAddress, "time", time.Since(mark), "n", n, "id", "broadcaster") + eb.lggr.Debugw("Finished processUnstartedTxs", "address", fromAddress, "time", time.Since(mark), "n", n, "id", "broadcaster") } }() @@ -471,7 +472,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc if err != nil { return true, errors.Wrap(err, "CountUnstartedTransactions failed") } - eb.logger.Warnw(fmt.Sprintf(`Transaction throttling; %d transactions in-flight and %d unstarted transactions pending (maximum number of in-flight transactions is %d per key). %s`, nUnconfirmed, nUnstarted, maxInFlightTransactions, label.MaxInFlightTransactionsWarning), "maxInFlightTransactions", maxInFlightTransactions, "nUnconfirmed", nUnconfirmed, "nUnstarted", nUnstarted) + eb.lggr.Warnw(fmt.Sprintf(`Transaction throttling; %d transactions in-flight and %d unstarted transactions pending (maximum number of in-flight transactions is %d per key). %s`, nUnconfirmed, nUnstarted, maxInFlightTransactions, label.MaxInFlightTransactionsWarning), "maxInFlightTransactions", maxInFlightTransactions, "nUnconfirmed", nUnconfirmed, "nUnstarted", nUnstarted) select { case <-time.After(InFlightTransactionRecheckInterval): case <-ctx.Done(): @@ -490,13 +491,13 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc n++ var a txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var retryable bool - a, _, _, retryable, err = eb.NewTxAttempt(ctx, *etx, eb.logger) + a, _, _, retryable, err = eb.NewTxAttempt(ctx, *etx, eb.lggr) if err != nil { return retryable, errors.Wrap(err, "processUnstartedTxs failed on NewAttempt") } if err := eb.txStore.UpdateTxUnstartedToInProgress(ctx, etx, &a); errors.Is(err, ErrTxRemoved) { - eb.logger.Debugw("tx removed", "txID", etx.ID, "subject", etx.Subject) + eb.lggr.Debugw("tx removed", "txID", etx.ID, "subject", etx.Subject) continue } else if err != nil { return true, errors.Wrap(err, "processUnstartedTxs failed on UpdateTxUnstartedToInProgress") @@ -540,7 +541,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand return errors.Wrap(err, "building transmit checker"), false } - lgr := etx.GetLogger(eb.logger.With("fee", attempt.TxFee)) + lgr := etx.GetLogger(logger.With(eb.lggr, "fee", attempt.TxFee)) // If the transmit check does not complete within the timeout, the transaction will be sent // anyway. @@ -650,14 +651,14 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // If there is only one RPC node, or all RPC nodes have the same // configured cap, this transaction will get stuck and keep repeating // forever until the issue is resolved. - lgr.Criticalw(`RPC node rejected this tx as outside Fee Cap`) + logger.Criticalw(lgr, `RPC node rejected this tx as outside Fee Cap`) fallthrough default: // Every error that doesn't fall under one of the above categories will be treated as Unknown. fallthrough case client.Unknown: eb.SvcErrBuffer.Append(err) - lgr.Criticalw(`Unknown error occurred while handling tx queue in ProcessUnstartedTxs. This chain/RPC client may not be supported. `+ + logger.Criticalw(lgr, `Unknown error occurred while handling tx queue in ProcessUnstartedTxs. This chain/RPC client may not be supported. `+ `Urgent resolution required, Chainlink is currently operating in a degraded state and may miss transactions`, "err", err, "etx", etx, "attempt", attempt) nextSequence, e := eb.client.PendingSequenceAt(ctx, etx.FromAddress) if e != nil { @@ -717,7 +718,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryAgainBumpingGas(ctx context.Context, lgr logger.Logger, txError error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (err error, retryable bool) { - lgr.With( + logger.With(lgr, "sendError", txError, "attemptFee", attempt.TxFee, "maxGasPriceConfig", eb.feeConfig.MaxFeePrice(), @@ -738,7 +739,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryAgainWithNewEstimation(ctx context.Context, lgr logger.Logger, txError error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (err error, retryable bool) { if attempt.TxType == 0x2 { err = errors.Errorf("re-estimation is not supported for EIP-1559 transactions. Node returned error: %v. This is a bug", txError.Error()) - logger.Sugared(eb.logger).AssumptionViolation(err.Error()) + logger.Sugared(eb.lggr).AssumptionViolation(err.Error()) return err, false } @@ -807,7 +808,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetN return seq, nil } - eb.logger.Infow("address not found in local next sequence map. Attempting to search and populate sequence.", "address", address.String()) + eb.lggr.Infow("address not found in local next sequence map. Attempting to search and populate sequence.", "address", address.String()) // Check if address is in the enabled address list if !slices.Contains(eb.enabledAddresses, address) { return seq, fmt.Errorf("address disabled: %s", address) diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index bf35611582..a56768ce20 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -15,13 +15,14 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-common/pkg/chains/label" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -160,7 +161,7 @@ func NewConfirmer[ lggr logger.Logger, isReceiptNil func(R) bool, ) *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { - lggr = lggr.Named("Confirmer") + lggr = logger.Named(lggr, "Confirmer") return &Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ txStore: txStore, lggr: lggr, @@ -517,7 +518,8 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat } } - lggr := ec.lggr.Named("BatchFetchReceipts").With("blockNum", blockNum) + lggr := logger.Named(ec.lggr, "BatchFetchReceipts") + lggr = logger.With(lggr, "blockNum", blockNum) txReceipts, txErrs, err := ec.client.BatchGetReceipts(ctx, attempts) if err != nil { @@ -529,8 +531,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat receipt := txReceipts[i] err := txErrs[i] - l := logger.Sugared(attempt.Tx.GetLogger(lggr).With( - "txHash", attempt.Hash.String(), "txAttemptID", attempt.ID, + l := logger.Sugared(logger.With(attempt.Tx.GetLogger(lggr), "txHash", attempt.Hash.String(), "txAttemptID", attempt.ID, "txID", attempt.TxID, "err", err, "sequence", attempt.Tx.Sequence, )) @@ -551,7 +552,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat continue } - l = logger.Sugared(l.With("blockHash", receipt.GetBlockHash().String(), "status", receipt.GetStatus(), "transactionIndex", receipt.GetTransactionIndex())) + l = logger.Sugared(logger.With(l, "blockHash", receipt.GetBlockHash().String(), "status", receipt.GetStatus(), "transactionIndex", receipt.GetTransactionIndex())) if receipt.IsUnmined() { l.Debug("Got receipt for transaction but it's still in the mempool and not included in a block yet") @@ -843,7 +844,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han return errors.Wrap(err, "could not bump gas for terminally underpriced transaction") } promNumGasBumps.WithLabelValues(ec.chainID.String()).Inc() - lggr.With( + logger.With(lggr, "sendError", sendError, "maxGasPriceConfig", ec.feeConfig.MaxFeePrice(), "previousAttempt", attempt, @@ -864,7 +865,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han // Should NEVER be fatal this is an invariant violation. The // Broadcaster can never create a TxAttempt that will // fatally error. - lggr.Criticalw("Invariant violation: fatal error while re-attempting transaction", + logger.Criticalw(lggr, "Invariant violation: fatal error while re-attempting transaction", "err", sendError, "fee", attempt.TxFee, "feeLimit", etx.FeeLimit, diff --git a/common/txmgr/reaper.go b/common/txmgr/reaper.go index 7286efa3a8..385a9a17c3 100644 --- a/common/txmgr/reaper.go +++ b/common/txmgr/reaper.go @@ -5,11 +5,11 @@ import ( "sync/atomic" "time" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -33,7 +33,7 @@ func NewReaper[CHAIN_ID types.ID](lggr logger.Logger, store txmgrtypes.TxHistory config, txConfig, chainID, - lggr.Named("Reaper"), + logger.Named(lggr, "Reaper"), atomic.Int64{}, make(chan struct{}, 1), make(services.StopChan), diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index e604a960bf..ce77005560 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -7,11 +7,12 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/chains/label" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -87,7 +88,7 @@ func NewResender[ pollInterval, config, txConfig, - lggr.Named("Resender"), + logger.Named(lggr, "Resender"), make(map[string]time.Time), ctx, cancel, diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index b49c2b72f1..63bf039d8f 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -11,12 +11,12 @@ import ( "github.com/google/uuid" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -331,7 +331,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() select { case <-time.After(backoff.Duration()): if err := b.broadcaster.startInternal(); err != nil { - b.logger.Criticalw("Failed to start Broadcaster", "err", err) + logger.Criticalw(b.logger, "Failed to start Broadcaster", "err", err) b.SvcErrBuffer.Append(err) continue } @@ -350,7 +350,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() select { case <-time.After(backoff.Duration()): if err := b.confirmer.startInternal(); err != nil { - b.logger.Criticalw("Failed to start Confirmer", "err", err) + logger.Criticalw(b.logger, "Failed to start Confirmer", "err", err) b.SvcErrBuffer.Append(err) continue } @@ -408,7 +408,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() } enabledAddresses, err := b.keyStore.EnabledAddressesForChain(b.chainID) if err != nil { - b.logger.Criticalf("Failed to reload key states after key change") + logger.Criticalf(b.logger, "Failed to reload key states after key change") b.SvcErrBuffer.Append(err) continue } diff --git a/common/txmgr/types/client.go b/common/txmgr/types/client.go index 58c1b6f6ad..b44c41e417 100644 --- a/common/txmgr/types/client.go +++ b/common/txmgr/types/client.go @@ -6,10 +6,10 @@ import ( "math/big" "time" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) // TxmClient is a superset of all the methods needed for the txm diff --git a/common/txmgr/types/mocks/tx_attempt_builder.go b/common/txmgr/types/mocks/tx_attempt_builder.go index f49b0025ae..0f3d3e3fba 100644 --- a/common/txmgr/types/mocks/tx_attempt_builder.go +++ b/common/txmgr/types/mocks/tx_attempt_builder.go @@ -5,8 +5,8 @@ package mocks import ( context "context" + logger "github.com/smartcontractkit/chainlink-common/pkg/logger" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - logger "github.com/smartcontractkit/chainlink/v2/core/logger" mock "github.com/stretchr/testify/mock" diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index 78f6fba459..b8a16561d8 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -13,10 +13,10 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" clnull "github.com/smartcontractkit/chainlink/v2/core/null" ) @@ -250,7 +250,7 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetMeta() (*TxMeta[A // GetLogger returns a new logger with metadata fields. func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger.Logger) logger.Logger { - lgr = lgr.With( + lgr = logger.With(lgr, "txID", e.ID, "sequence", e.Sequence, "checker", e.TransmitChecker, @@ -264,15 +264,15 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger } if meta != nil { - lgr = lgr.With("jobID", meta.JobID) + lgr = logger.With(lgr, "jobID", meta.JobID) if meta.RequestTxHash != nil { - lgr = lgr.With("requestTxHash", *meta.RequestTxHash) + lgr = logger.With(lgr, "requestTxHash", *meta.RequestTxHash) } if meta.RequestID != nil { id := *meta.RequestID - lgr = lgr.With("requestID", new(big.Int).SetBytes(id.Bytes()).String()) + lgr = logger.With(lgr, "requestID", new(big.Int).SetBytes(id.Bytes()).String()) } if len(meta.RequestIDs) != 0 { @@ -280,33 +280,33 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger for _, id := range meta.RequestIDs { ids = append(ids, new(big.Int).SetBytes(id.Bytes()).String()) } - lgr = lgr.With("requestIDs", strings.Join(ids, ",")) + lgr = logger.With(lgr, "requestIDs", strings.Join(ids, ",")) } if meta.UpkeepID != nil { - lgr = lgr.With("upkeepID", *meta.UpkeepID) + lgr = logger.With(lgr, "upkeepID", *meta.UpkeepID) } if meta.SubID != nil { - lgr = lgr.With("subID", *meta.SubID) + lgr = logger.With(lgr, "subID", *meta.SubID) } if meta.MaxLink != nil { - lgr = lgr.With("maxLink", *meta.MaxLink) + lgr = logger.With(lgr, "maxLink", *meta.MaxLink) } if meta.FwdrDestAddress != nil { - lgr = lgr.With("FwdrDestAddress", *meta.FwdrDestAddress) + lgr = logger.With(lgr, "FwdrDestAddress", *meta.FwdrDestAddress) } if len(meta.MessageIDs) > 0 { for _, mid := range meta.MessageIDs { - lgr = lgr.With("messageID", mid) + lgr = logger.With(lgr, "messageID", mid) } } if len(meta.SeqNumbers) > 0 { - lgr = lgr.With("SeqNumbers", meta.SeqNumbers) + lgr = logger.With(lgr, "SeqNumbers", meta.SeqNumbers) } } diff --git a/common/txmgr/types/tx_attempt_builder.go b/common/txmgr/types/tx_attempt_builder.go index 75712fc0c3..383b6d862f 100644 --- a/common/txmgr/types/tx_attempt_builder.go +++ b/common/txmgr/types/tx_attempt_builder.go @@ -3,10 +3,10 @@ package types import ( "context" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) // TxAttemptBuilder takes the base unsigned transaction + optional parameters (tx type, gas parameters) diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 0f15b35ee9..d17c55f2e4 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -11,11 +11,12 @@ import ( "github.com/ethereum/go-ethereum/rpc" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) var _ Client = (*chainClient)(nil) diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index 5263c74de1..91c8659d8c 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -7,11 +7,12 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/common/config" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum" diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 4cb505dc9e..143a5f8806 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -10,9 +10,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) // fatal means this transaction can never be accepted even with a different nonce or higher gas price @@ -419,7 +419,7 @@ func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fro return commonclient.Successful, err } if sendError.Fatal() { - lggr.Criticalw("Fatal error sending transaction", "err", sendError, "etx", tx) + logger.Criticalw(lggr, "Fatal error sending transaction", "err", sendError, "etx", tx) // Attempt is thrown away in this case; we don't need it since it never got accepted by a node return commonclient.Fatal, err } @@ -462,7 +462,7 @@ func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fro return commonclient.Retryable, err } if sendError.IsInsufficientEth() { - lggr.Criticalw(fmt.Sprintf("Tx %x with type 0x%d was rejected due to insufficient eth: %s\n"+ + logger.Criticalw(lggr, fmt.Sprintf("Tx %x with type 0x%d was rejected due to insufficient eth: %s\n"+ "ACTION REQUIRED: Chainlink wallet with address 0x%x is OUT OF FUNDS", tx.Hash(), tx.Type(), sendError.Error(), fromAddress, ), "err", sendError) @@ -472,7 +472,7 @@ func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fro return commonclient.Retryable, errors.Wrapf(sendError, "timeout while sending transaction %s", tx.Hash().Hex()) } if sendError.IsTxFeeExceedsCap() { - lggr.Criticalw(fmt.Sprintf("Sending transaction failed: %s", label.RPCTxFeeCapConfiguredIncorrectlyWarning), + logger.Criticalw(lggr, fmt.Sprintf("Sending transaction failed: %s", label.RPCTxFeeCapConfiguredIncorrectlyWarning), "etx", tx, "err", sendError, "id", "RPCTxFeeCapExceeded", diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index b1d477b1a2..dce825f4f7 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -9,11 +9,11 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -43,7 +43,7 @@ func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeads return nil, errors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) } - lggr := logger.TestLogger(t) + lggr := logger.Test(t) n := NewNode(nodePoolCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-0", id, chainID, 1) n.(*node).setLatestReceived(0, utils.NewBigI(0)) primaries := []Node{n} @@ -87,7 +87,7 @@ func NewChainClientWithTestNode( return nil, errors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) } - lggr := logger.TestLogger(t) + lggr := logger.Test(t) rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, commonclient.Primary) n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCCLient]( @@ -120,7 +120,7 @@ func NewChainClientWithEmptyNode( chainID *big.Int, ) Client { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) var chainType commonconfig.ChainType c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, nil, nil, chainID, chainType) diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index b3ce489cf5..8bae566e27 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -19,10 +19,11 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -192,7 +193,8 @@ func NewNode(nodeCfg config.NodePool, noNewHeadsThreshold time.Duration, lggr lo } n.chStopInFlight = make(chan struct{}) n.nodeCtx, n.cancelNodeCtx = context.WithCancel(context.Background()) - lggr = lggr.Named("Node").With( + lggr = logger.Named(lggr, "Node") + lggr = logger.With(lggr, "nodeTier", "primary", "nodeName", name, "node", n.String(), @@ -200,8 +202,8 @@ func NewNode(nodeCfg config.NodePool, noNewHeadsThreshold time.Duration, lggr lo "nodeOrder", n.order, "mode", n.getNodeMode(), ) - n.lfcLog = lggr.Named("Lifecycle") - n.rpcLog = lggr.Named("RPC") + n.lfcLog = logger.Named(lggr, "Lifecycle") + n.rpcLog = logger.Named(lggr, "RPC") n.stateLatestBlockNumber = -1 return n @@ -259,9 +261,9 @@ func (n *node) dial(callerCtx context.Context) error { defer cancel() promEVMPoolRPCNodeDials.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr := n.lfcLog.With("wsuri", n.ws.uri.Redacted()) + lggr := logger.With(n.lfcLog, "wsuri", n.ws.uri.Redacted()) if n.http != nil { - lggr = lggr.With("httpuri", n.http.uri.Redacted()) + lggr = logger.With(lggr, "httpuri", n.http.uri.Redacted()) } lggr.Debugw("RPC dial: evmclient.Client#dial") @@ -448,7 +450,7 @@ func (n *node) CallContext(ctx context.Context, result interface{}, method strin return err } defer cancel() - lggr := n.newRqLggr().With( + lggr := logger.With(n.newRqLggr(), "method", method, "args", args, ) @@ -473,9 +475,9 @@ func (n *node) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { return err } defer cancel() - lggr := n.newRqLggr().With("nBatchElems", len(b), "batchElems", b) + lggr := logger.With(n.newRqLggr(), "nBatchElems", len(b), "batchElems", b) - lggr.Trace("RPC call: evmclient.Client#BatchCallContext") + logger.Trace(lggr, "RPC call: evmclient.Client#BatchCallContext") start := time.Now() if http != nil { err = n.wrapHTTP(http.rpc.BatchCallContext(ctx, b)) @@ -495,7 +497,7 @@ func (n *node) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, return nil, err } defer cancel() - lggr := n.newRqLggr().With("args", args) + lggr := logger.With(n.newRqLggr(), "args", args) lggr.Debug("RPC call: evmclient.Client#EthSubscribe") start := time.Now() @@ -518,7 +520,7 @@ func (n *node) TransactionReceipt(ctx context.Context, txHash common.Hash) (rece return nil, err } defer cancel() - lggr := n.newRqLggr().With("txHash", txHash) + lggr := logger.With(n.newRqLggr(), "txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionReceipt") @@ -545,7 +547,7 @@ func (n *node) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *t return nil, err } defer cancel() - lggr := n.newRqLggr().With("txHash", txHash) + lggr := logger.With(n.newRqLggr(), "txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionByHash") @@ -572,7 +574,7 @@ func (n *node) HeaderByNumber(ctx context.Context, number *big.Int) (header *typ return nil, err } defer cancel() - lggr := n.newRqLggr().With("number", number) + lggr := logger.With(n.newRqLggr(), "number", number) lggr.Debug("RPC call: evmclient.Client#HeaderByNumber") start := time.Now() @@ -596,7 +598,7 @@ func (n *node) HeaderByHash(ctx context.Context, hash common.Hash) (header *type return nil, err } defer cancel() - lggr := n.newRqLggr().With("hash", hash) + lggr := logger.With(n.newRqLggr(), "hash", hash) lggr.Debug("RPC call: evmclient.Client#HeaderByHash") start := time.Now() @@ -622,7 +624,7 @@ func (n *node) SendTransaction(ctx context.Context, tx *types.Transaction) error return err } defer cancel() - lggr := n.newRqLggr().With("tx", tx) + lggr := logger.With(n.newRqLggr(), "tx", tx) lggr.Debug("RPC call: evmclient.Client#SendTransaction") start := time.Now() @@ -645,7 +647,7 @@ func (n *node) PendingNonceAt(ctx context.Context, account common.Address) (nonc return 0, err } defer cancel() - lggr := n.newRqLggr().With("account", account) + lggr := logger.With(n.newRqLggr(), "account", account) lggr.Debug("RPC call: evmclient.Client#PendingNonceAt") start := time.Now() @@ -674,7 +676,7 @@ func (n *node) NonceAt(ctx context.Context, account common.Address, blockNumber return 0, err } defer cancel() - lggr := n.newRqLggr().With("account", account, "blockNumber", blockNumber) + lggr := logger.With(n.newRqLggr(), "account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#NonceAt") start := time.Now() @@ -700,7 +702,7 @@ func (n *node) PendingCodeAt(ctx context.Context, account common.Address) (code return nil, err } defer cancel() - lggr := n.newRqLggr().With("account", account) + lggr := logger.With(n.newRqLggr(), "account", account) lggr.Debug("RPC call: evmclient.Client#PendingCodeAt") start := time.Now() @@ -726,7 +728,7 @@ func (n *node) CodeAt(ctx context.Context, account common.Address, blockNumber * return nil, err } defer cancel() - lggr := n.newRqLggr().With("account", account, "blockNumber", blockNumber) + lggr := logger.With(n.newRqLggr(), "account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CodeAt") start := time.Now() @@ -752,7 +754,7 @@ func (n *node) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint return 0, err } defer cancel() - lggr := n.newRqLggr().With("call", call) + lggr := logger.With(n.newRqLggr(), "call", call) lggr.Debug("RPC call: evmclient.Client#EstimateGas") start := time.Now() @@ -804,7 +806,7 @@ func (n *node) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumb return nil, err } defer cancel() - lggr := n.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber) + lggr := logger.With(n.newRqLggr(), "callMsg", msg, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CallContract") start := time.Now() @@ -831,7 +833,7 @@ func (n *node) BlockByNumber(ctx context.Context, number *big.Int) (b *types.Blo return nil, err } defer cancel() - lggr := n.newRqLggr().With("number", number) + lggr := logger.With(n.newRqLggr(), "number", number) lggr.Debug("RPC call: evmclient.Client#BlockByNumber") start := time.Now() @@ -857,7 +859,7 @@ func (n *node) BlockByHash(ctx context.Context, hash common.Hash) (b *types.Bloc return nil, err } defer cancel() - lggr := n.newRqLggr().With("hash", hash) + lggr := logger.With(n.newRqLggr(), "hash", hash) lggr.Debug("RPC call: evmclient.Client#BlockByHash") start := time.Now() @@ -909,7 +911,7 @@ func (n *node) BalanceAt(ctx context.Context, account common.Address, blockNumbe return nil, err } defer cancel() - lggr := n.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber) + lggr := logger.With(n.newRqLggr(), "account", account.Hex(), "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#BalanceAt") start := time.Now() @@ -935,7 +937,7 @@ func (n *node) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l []type return nil, err } defer cancel() - lggr := n.newRqLggr().With("q", q) + lggr := logger.With(n.newRqLggr(), "q", q) lggr.Debug("RPC call: evmclient.Client#FilterLogs") start := time.Now() @@ -961,7 +963,7 @@ func (n *node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, return nil, err } defer cancel() - lggr := n.newRqLggr().With("q", q) + lggr := logger.With(n.newRqLggr(), "q", q) lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") start := time.Now() @@ -1007,7 +1009,7 @@ func (n *node) ChainID() (chainID *big.Int) { return n.chainID } // newRqLggr generates a new logger with a unique request ID func (n *node) newRqLggr() logger.Logger { - return n.rpcLog.With( + return logger.With(n.rpcLog, "requestID", uuid.New(), ) } @@ -1020,11 +1022,11 @@ func (n *node) logResult( callName string, results ...interface{}, ) { - lggr = lggr.With("duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) + lggr = logger.With(lggr, "duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) promEVMPoolRPCNodeCalls.WithLabelValues(n.chainID.String(), n.name).Inc() if err == nil { promEVMPoolRPCNodeCallsSuccess.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Tracew( + logger.Tracew(lggr, fmt.Sprintf("evmclient.Client#%s RPC call success", callName), results..., ) @@ -1057,7 +1059,7 @@ func (n *node) wrapHTTP(err error) error { if err != nil { n.rpcLog.Debugw("Call failed", "err", err) } else { - n.rpcLog.Trace("Call succeeded") + logger.Trace(n.rpcLog, "Call succeeded") } return err } diff --git a/core/chains/evm/client/node_fsm_test.go b/core/chains/evm/client/node_fsm_test.go index ce63a62a8b..321bbc7a30 100644 --- a/core/chains/evm/client/node_fsm_test.go +++ b/core/chains/evm/client/node_fsm_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type fnMock struct{ calls int } @@ -43,7 +43,7 @@ func TestUnit_Node_StateTransitions(t *testing.T) { t.Parallel() s := testutils.NewWSServer(t, testutils.FixtureChainID, nil) - iN := NewNode(TestNodePoolConfig{}, time.Second*0, logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, nil, 1) + iN := NewNode(TestNodePoolConfig{}, time.Second*0, logger.Test(t), *s.WSURL(), nil, "test node", 42, nil, 1) n := iN.(*node) assert.Equal(t, NodeStateUndialed, n.State()) diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index 609d1522ea..11d03d97dd 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -10,6 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -87,8 +88,9 @@ func (n *node) aliveLoop() { pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() pollInterval := n.nodePoolCfg.PollInterval() - lggr := n.lfcLog.Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) - lggr.Tracew("Alive loop starting", "nodeState", n.State()) + lggr := logger.Named(n.lfcLog, "Alive") + lggr = logger.With(lggr, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) + logger.Tracew(lggr, "Alive loop starting", "nodeState", n.State()) headsC := make(chan *evmtypes.Head) sub, err := n.EthSubscribe(n.nodeCtx, headsC, "newHeads") @@ -137,7 +139,7 @@ func (n *node) aliveLoop() { case <-pollCh: var version string promEVMPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + logger.Tracew(lggr, "Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) ctx, cancel := context.WithTimeout(n.nodeCtx, pollInterval) ctx, cancel2 := n.makeQueryCtx(ctx) err := n.CallContext(ctx, &version, "web3_clientVersion") @@ -159,7 +161,7 @@ func (n *node) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) + logger.Criticalf(lggr, "RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) continue } } @@ -171,7 +173,7 @@ func (n *node) aliveLoop() { // note: there must be another live node for us to be out of sync lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) if liveNodes < 2 { - lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) + logger.Criticalf(lggr, "RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) continue } n.declareOutOfSync(n.isOutOfSync) @@ -184,13 +186,13 @@ func (n *node) aliveLoop() { return } promEVMPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Tracew("Got head", "head", bh) + logger.Tracew(lggr, "Got head", "head", bh) if bh.Number > highestReceivedBlockNumber { promEVMPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.Number)) - lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) + logger.Tracew(lggr, "Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) highestReceivedBlockNumber = bh.Number } else { - lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) + logger.Tracew(lggr, "Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) } if outOfSyncT != nil { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) @@ -206,7 +208,7 @@ func (n *node) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) + logger.Criticalf(lggr, "RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) @@ -272,7 +274,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *utils.Big) bool) { outOfSyncAt := time.Now() - lggr := n.lfcLog.Named("OutOfSync") + lggr := logger.Named(n.lfcLog, "OutOfSync") lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) // Need to redial since out-of-sync nodes are automatically disconnected @@ -289,7 +291,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *utils.Big) bool) { return } - lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) + logger.Tracew(lggr, "Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) ch := make(chan *evmtypes.Head) subCtx, cancel := n.makeQueryCtx(n.nodeCtx) @@ -324,7 +326,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *utils.Big) bool) { case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { - lggr.Critical("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") + logger.Critical(lggr, "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") n.declareInSync() return } @@ -354,7 +356,7 @@ func (n *node) unreachableLoop() { unreachableAt := time.Now() - lggr := n.lfcLog.Named("Unreachable") + lggr := logger.Named(n.lfcLog, "Unreachable") lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) dialRetryBackoff := utils.NewRedialBackoff() @@ -364,7 +366,7 @@ func (n *node) unreachableLoop() { case <-n.nodeCtx.Done(): return case <-time.After(dialRetryBackoff.Duration()): - lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) + logger.Tracew(lggr, "Trying to re-dial RPC node", "nodeState", n.State()) err := n.dial(n.nodeCtx) if err != nil { @@ -410,7 +412,7 @@ func (n *node) invalidChainIDLoop() { invalidAt := time.Now() - lggr := n.lfcLog.Named("InvalidChainID") + lggr := logger.Named(n.lfcLog, "InvalidChainID") lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.State()) chainIDRecheckBackoff := utils.NewRedialBackoff() diff --git a/core/chains/evm/client/node_lifecycle_test.go b/core/chains/evm/client/node_lifecycle_test.go index 05b8af13ec..42f813cc2b 100644 --- a/core/chains/evm/client/node_lifecycle_test.go +++ b/core/chains/evm/client/node_lifecycle_test.go @@ -12,10 +12,10 @@ import ( "github.com/tidwall/gjson" "go.uber.org/zap" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -34,7 +34,7 @@ func newTestNode(t *testing.T, cfg config.NodePool, noNewHeadsThresholds time.Du func newTestNodeWithCallback(t *testing.T, cfg config.NodePool, noNewHeadsThreshold time.Duration, callback testutils.JSONRPCHandler) *node { s := testutils.NewWSServer(t, testutils.FixtureChainID, callback) - iN := NewNode(cfg, noNewHeadsThreshold, logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, noNewHeadsThreshold, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) return n } @@ -222,7 +222,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { return }) - iN := NewNode(cfg, testutils.WaitTimeout(t), logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, testutils.WaitTimeout(t), logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) dial(t, n) @@ -268,7 +268,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { return }) - iN := NewNode(cfg, 1*time.Second, logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, 1*time.Second, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) dial(t, n) @@ -288,7 +288,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { }) t.Run("when no new heads received for threshold but we are the last live node, forcibly stays alive", func(t *testing.T) { - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) pollDisabledCfg := TestNodePoolConfig{} s := testutils.NewWSServer(t, testutils.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { @@ -351,7 +351,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { return }) - iN := NewNode(cfg, 0*time.Second, logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, 0*time.Second, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { return 2, highestHead.Load(), nil @@ -413,7 +413,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { return }) - iN := NewNode(cfg, 0*time.Second, logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, 0*time.Second, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { return 2, highestHead.Load(), nil @@ -439,7 +439,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { }) t.Run("when behind more than SyncThreshold but we are the last live node, forcibly stays alive", func(t *testing.T) { - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) cfg := TestNodePoolConfig{NodeSyncThreshold: 5, NodePollFailureThreshold: 2, NodePollInterval: 100 * time.Millisecond, NodeSelectionMode: NodeSelectionMode_HighestHead} chSubbed := make(chan struct{}, 1) var highestHead atomic.Int64 @@ -557,7 +557,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { return }) - iN := NewNode(cfg, time.Duration(time.Second), logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, time.Duration(time.Second), logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) dial(t, n) @@ -584,7 +584,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { // NoNewHeadsThreshold needs to be positive but must be very large so // we don't time out waiting for a new head before we have a chance to // handle the server disconnect - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) cfg := TestNodePoolConfig{} chSubbed := make(chan struct{}, 1) s := testutils.NewWSServer(t, testutils.FixtureChainID, @@ -638,7 +638,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { }) t.Run("transitions to alive if back in-sync", func(t *testing.T) { - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) cfg := TestNodePoolConfig{NodeSyncThreshold: 5, NodeSelectionMode: NodeSelectionMode_HighestHead} chSubbed := make(chan struct{}, 1) const stall = 42 @@ -715,7 +715,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { return }) - iN := NewNode(cfg, testutils.TestInterval, logger.TestLogger(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, testutils.TestInterval, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) n.nLiveNodes = func() (int, int64, *utils.Big) { return 0, 0, nil } @@ -771,7 +771,7 @@ func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) { t.Run("on successful redial but failed verify, transitions to invalid chain ID", func(t *testing.T) { cfg := TestNodePoolConfig{} s := testutils.NewWSServer(t, testutils.FixtureChainID, standardHandler) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) iN := NewNode(cfg, time.Second*0, lggr, *s.WSURL(), nil, "test node", 0, big.NewInt(42), 1) n := iN.(*node) defer func() { assert.NoError(t, n.Close()) }() @@ -790,7 +790,7 @@ func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) { t.Run("on failed redial, keeps trying to redial", func(t *testing.T) { cfg := TestNodePoolConfig{} - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) iN := NewNode(cfg, time.Second*0, lggr, *testutils.MustParseURL(t, "ws://test.invalid"), nil, "test node", 0, big.NewInt(42), 1) n := iN.(*node) defer func() { assert.NoError(t, n.Close()) }() @@ -842,7 +842,7 @@ func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { t.Run("on failed verify, keeps checking", func(t *testing.T) { cfg := TestNodePoolConfig{} s := testutils.NewWSServer(t, testutils.FixtureChainID, standardHandler) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) iN := NewNode(cfg, time.Second*0, lggr, *s.WSURL(), nil, "test node", 0, big.NewInt(42), 1) n := iN.(*node) defer func() { assert.NoError(t, n.Close()) }() diff --git a/core/chains/evm/client/null_client.go b/core/chains/evm/client/null_client.go index e25fed6d96..e3bb1defd0 100644 --- a/core/chains/evm/client/null_client.go +++ b/core/chains/evm/client/null_client.go @@ -10,9 +10,9 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) // NullClient satisfies the Client but has no side effects @@ -22,7 +22,7 @@ type NullClient struct { } func NewNullClient(cid *big.Int, lggr logger.Logger) *NullClient { - return &NullClient{cid: cid, lggr: lggr.Named("NullClient")} + return &NullClient{cid: cid, lggr: logger.Named(lggr, "NullClient")} } // NullClientChainID the ChainID that nullclient will return @@ -72,7 +72,7 @@ type nullSubscription struct { } func newNullSubscription(lggr logger.Logger) *nullSubscription { - return &nullSubscription{lggr: lggr.Named("NullSubscription")} + return &nullSubscription{lggr: logger.Named(lggr, "NullSubscription")} } func (ns *nullSubscription) Unsubscribe() { diff --git a/core/chains/evm/client/null_client_test.go b/core/chains/evm/client/null_client_test.go index 6b0f6e3d1b..8f4ebd91c9 100644 --- a/core/chains/evm/client/null_client_test.go +++ b/core/chains/evm/client/null_client_test.go @@ -11,17 +11,17 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestNullClient(t *testing.T) { t.Parallel() t.Run("chain id", func(t *testing.T) { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) cid := big.NewInt(123) nc := client.NewNullClient(cid, lggr) require.Equal(t, cid, nc.ConfiguredChainID()) @@ -31,7 +31,7 @@ func TestNullClient(t *testing.T) { }) t.Run("CL client methods", func(t *testing.T) { - lggr, logs := logger.TestLoggerObserved(t, zapcore.DebugLevel) + lggr, logs := logger.TestObserved(t, zapcore.DebugLevel) nc := client.NewNullClient(nil, lggr) ctx := testutils.Context(t) @@ -77,7 +77,7 @@ func TestNullClient(t *testing.T) { }) t.Run("Geth client methods", func(t *testing.T) { - lggr, logs := logger.TestLoggerObserved(t, zapcore.DebugLevel) + lggr, logs := logger.TestObserved(t, zapcore.DebugLevel) nc := client.NewNullClient(nil, lggr) ctx := testutils.Context(t) diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 289a402a1c..ab190f8c6a 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -15,11 +15,11 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -76,7 +76,7 @@ type Pool struct { wg sync.WaitGroup } -func NewPool(logger logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsTreshold time.Duration, nodes []Node, sendonlys []SendOnlyNode, chainID *big.Int, chainType config.ChainType) *Pool { +func NewPool(lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsTreshold time.Duration, nodes []Node, sendonlys []SendOnlyNode, chainID *big.Int, chainType config.ChainType) *Pool { if chainID == nil { panic("chainID is required") } @@ -96,7 +96,8 @@ func NewPool(logger logger.Logger, selectionMode string, leaseDuration time.Dura } }() - lggr := logger.Named("Pool").With("evmChainID", chainID.String()) + lggr = logger.Named(lggr, "Pool") + lggr = logger.With(lggr, "evmChainID", chainID.String()) p := &Pool{ nodes: nodes, @@ -262,10 +263,10 @@ func (p *Pool) report() { } live := total - dead - p.logger.Tracew(fmt.Sprintf("Pool state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + logger.Tracew(p.logger, fmt.Sprintf("Pool state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) if total == dead { rerr := fmt.Errorf("no EVM primary nodes available: 0/%d nodes are alive", total) - p.logger.Criticalw(rerr.Error(), "nodeStates", nodeStates) + logger.Criticalw(p.logger, rerr.Error(), "nodeStates", nodeStates) p.SvcErrBuffer.Append(rerr) } else if dead > 0 { p.logger.Errorw(fmt.Sprintf("At least one EVM primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) @@ -310,7 +311,7 @@ func (p *Pool) selectNode() (node Node) { p.activeNode = p.nodeSelector.Select() if p.activeNode == nil { - p.logger.Criticalw("No live RPC nodes available", "NodeSelectionMode", p.nodeSelector.Name()) + logger.Criticalw(p.logger, "No live RPC nodes available", "NodeSelectionMode", p.nodeSelector.Name()) errmsg := fmt.Errorf("no live nodes available for chain %s", p.chainID.String()) p.SvcErrBuffer.Append(errmsg) return &erroringNode{errMsg: errmsg.Error()} @@ -357,7 +358,7 @@ func (p *Pool) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) error if err != nil { p.logger.Debugw("Secondary node BatchCallContext failed", "err", err) } else { - p.logger.Trace("Secondary node BatchCallContext success") + logger.Trace(p.logger, "Secondary node BatchCallContext success") } }(n) } diff --git a/core/chains/evm/client/pool_test.go b/core/chains/evm/client/pool_test.go index 75d38d01a4..462aeed43e 100644 --- a/core/chains/evm/client/pool_test.go +++ b/core/chains/evm/client/pool_test.go @@ -18,11 +18,11 @@ import ( "github.com/tidwall/gjson" "go.uber.org/zap" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type poolConfig struct { @@ -164,7 +164,7 @@ func TestPool_Dial(t *testing.T) { for i, n := range test.sendNodes { sendNodes[i] = n.newSendOnlyNode(t, test.sendNodeChainID) } - p := evmclient.NewPool(logger.TestLogger(t), defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, sendNodes, test.poolChainID, "") + p := evmclient.NewPool(logger.Test(t), defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, sendNodes, test.poolChainID, "") err := p.Dial(ctx) if err == nil { t.Cleanup(func() { assert.NoError(t, p.Close()) }) @@ -188,7 +188,7 @@ type chainIDResp struct { func (r *chainIDResp) newSendOnlyNode(t *testing.T, nodeChainID int64) evmclient.SendOnlyNode { httpURL := r.newHTTPServer(t) - return evmclient.NewSendOnlyNode(logger.TestLogger(t), *httpURL, t.Name(), big.NewInt(nodeChainID)) + return evmclient.NewSendOnlyNode(logger.Test(t), *httpURL, t.Name(), big.NewInt(nodeChainID)) } func (r *chainIDResp) newHTTPServer(t *testing.T) *url.URL { @@ -234,7 +234,7 @@ func (r *chainIDResps) newNode(t *testing.T, nodeChainID int64) evmclient.Node { } defer func() { r.id++ }() - return evmclient.NewNode(evmclient.TestNodePoolConfig{}, time.Second*0, logger.TestLogger(t), *wsURL, httpURL, t.Name(), r.id, big.NewInt(nodeChainID), 0) + return evmclient.NewNode(evmclient.TestNodePoolConfig{}, time.Second*0, logger.Test(t), *wsURL, httpURL, t.Name(), r.id, big.NewInt(nodeChainID), 0) } type chainIDService struct { @@ -256,7 +256,7 @@ func TestUnit_Pool_RunLoop(t *testing.T) { n3 := evmmocks.NewNode(t) nodes := []evmclient.Node{n1, n2, n3} - lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) p := evmclient.NewPool(lggr, defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, []evmclient.SendOnlyNode{}, &cltest.FixtureChainID, "") n1.On("String").Maybe().Return("n1") @@ -331,7 +331,7 @@ func TestUnit_Pool_BatchCallContextAll(t *testing.T) { sendonlys = append(sendonlys, s) } - p := evmclient.NewPool(logger.TestLogger(t), defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, sendonlys, &cltest.FixtureChainID, "") + p := evmclient.NewPool(logger.Test(t), defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, sendonlys, &cltest.FixtureChainID, "") assert.True(t, p.ChainType().IsValid()) assert.False(t, p.ChainType().IsL2()) @@ -378,7 +378,7 @@ func TestUnit_Pool_LeaseDuration(t *testing.T) { n2.On("Order").Return(int32(2)) n2.On("ChainID").Return(testutils.FixtureChainID).Once() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + lggr, observedLogs := logger.TestObserved(t, zap.InfoLevel) p := evmclient.NewPool(lggr, "PriorityLevel", time.Second*2, time.Second*0, nodes, []evmclient.SendOnlyNode{}, &cltest.FixtureChainID, "") require.NoError(t, p.Dial(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, p.Close()) }) diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index 785acbb2b7..fc9c348a57 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -18,11 +18,12 @@ import ( "github.com/pkg/errors" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -97,13 +98,14 @@ func NewRPCClient( r.http = &rawclient{uri: *httpuri} } r.chStopInFlight = make(chan struct{}) - lggr = lggr.Named("Client").With( + lggr = logger.Named(lggr, "Client") + lggr = logger.With(lggr, "clientTier", tier.String(), "clientName", name, "client", r.String(), "evmChainID", chainID, ) - r.rpcLog = lggr.Named("RPC") + r.rpcLog = logger.Named(lggr, "RPC") return r } @@ -114,9 +116,9 @@ func (r *rpcClient) Dial(callerCtx context.Context) error { defer cancel() promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() - lggr := r.rpcLog.With("wsuri", r.ws.uri.Redacted()) + lggr := logger.With(r.rpcLog, "wsuri", r.ws.uri.Redacted()) if r.http != nil { - lggr = lggr.With("httpuri", r.http.uri.Redacted()) + lggr = logger.With(lggr, "httpuri", r.http.uri.Redacted()) } lggr.Debugw("RPC dial: evmclient.Client#dial") @@ -145,7 +147,7 @@ func (r *rpcClient) Dial(callerCtx context.Context) error { // It can only return error if the URL is malformed. func (r *rpcClient) DialHTTP() error { promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() - lggr := r.rpcLog.With("httpuri", r.ws.uri.Redacted()) + lggr := logger.With(r.rpcLog, "httpuri", r.ws.uri.Redacted()) lggr.Debugw("RPC dial: evmclient.Client#dial") var httprpc *rpc.Client @@ -199,11 +201,11 @@ func (r *rpcClient) logResult( callName string, results ...interface{}, ) { - lggr = lggr.With("duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) + lggr = logger.With(lggr, "duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) promEVMPoolRPCNodeCalls.WithLabelValues(r.chainID.String(), r.name).Inc() if err == nil { promEVMPoolRPCNodeCallsSuccess.WithLabelValues(r.chainID.String(), r.name).Inc() - lggr.Tracew( + logger.Tracew(lggr, fmt.Sprintf("evmclient.Client#%s RPC call success", callName), results..., ) @@ -296,7 +298,7 @@ func (r *rpcClient) CallContext(ctx context.Context, result interface{}, method return err } defer cancel() - lggr := r.newRqLggr().With( + lggr := logger.With(r.newRqLggr(), "method", method, "args", args, ) @@ -325,9 +327,9 @@ func (r *rpcClient) BatchCallContext(ctx context.Context, b []any) error { batch[i] = arg.(rpc.BatchElem) } defer cancel() - lggr := r.newRqLggr().With("nBatchElems", len(b), "batchElems", b) + lggr := logger.With(r.newRqLggr(), "nBatchElems", len(b), "batchElems", b) - lggr.Trace("RPC call: evmclient.Client#BatchCallContext") + logger.Trace(lggr, "RPC call: evmclient.Client#BatchCallContext") start := time.Now() if http != nil { err = r.wrapHTTP(http.rpc.BatchCallContext(ctx, batch)) @@ -347,7 +349,7 @@ func (r *rpcClient) Subscribe(ctx context.Context, channel chan<- *evmtypes.Head return nil, err } defer cancel() - lggr := r.newRqLggr().With("args", args) + lggr := logger.With(r.newRqLggr(), "args", args) lggr.Debug("RPC call: evmclient.Client#EthSubscribe") start := time.Now() @@ -382,7 +384,7 @@ func (r *rpcClient) TransactionReceiptGeth(ctx context.Context, txHash common.Ha return nil, err } defer cancel() - lggr := r.newRqLggr().With("txHash", txHash) + lggr := logger.With(r.newRqLggr(), "txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionReceipt") @@ -408,7 +410,7 @@ func (r *rpcClient) TransactionByHash(ctx context.Context, txHash common.Hash) ( return nil, err } defer cancel() - lggr := r.newRqLggr().With("txHash", txHash) + lggr := logger.With(r.newRqLggr(), "txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionByHash") @@ -435,7 +437,7 @@ func (r *rpcClient) HeaderByNumber(ctx context.Context, number *big.Int) (header return nil, err } defer cancel() - lggr := r.newRqLggr().With("number", number) + lggr := logger.With(r.newRqLggr(), "number", number) lggr.Debug("RPC call: evmclient.Client#HeaderByNumber") start := time.Now() @@ -459,7 +461,7 @@ func (r *rpcClient) HeaderByHash(ctx context.Context, hash common.Hash) (header return nil, err } defer cancel() - lggr := r.newRqLggr().With("hash", hash) + lggr := logger.With(r.newRqLggr(), "hash", hash) lggr.Debug("RPC call: evmclient.Client#HeaderByHash") start := time.Now() @@ -512,7 +514,7 @@ func (r *rpcClient) BlockByHashGeth(ctx context.Context, hash common.Hash) (bloc return nil, err } defer cancel() - lggr := r.newRqLggr().With("hash", hash) + lggr := logger.With(r.newRqLggr(), "hash", hash) lggr.Debug("RPC call: evmclient.Client#BlockByHash") start := time.Now() @@ -538,7 +540,7 @@ func (r *rpcClient) BlockByNumberGeth(ctx context.Context, number *big.Int) (blo return nil, err } defer cancel() - lggr := r.newRqLggr().With("number", number) + lggr := logger.With(r.newRqLggr(), "number", number) lggr.Debug("RPC call: evmclient.Client#BlockByNumber") start := time.Now() @@ -564,7 +566,7 @@ func (r *rpcClient) SendTransaction(ctx context.Context, tx *types.Transaction) return err } defer cancel() - lggr := r.newRqLggr().With("tx", tx) + lggr := logger.With(r.newRqLggr(), "tx", tx) lggr.Debug("RPC call: evmclient.Client#SendTransaction") start := time.Now() @@ -604,7 +606,7 @@ func (r *rpcClient) PendingSequenceAt(ctx context.Context, account common.Addres return 0, err } defer cancel() - lggr := r.newRqLggr().With("account", account) + lggr := logger.With(r.newRqLggr(), "account", account) lggr.Debug("RPC call: evmclient.Client#PendingNonceAt") start := time.Now() @@ -636,7 +638,7 @@ func (r *rpcClient) SequenceAt(ctx context.Context, account common.Address, bloc return 0, err } defer cancel() - lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) + lggr := logger.With(r.newRqLggr(), "account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#NonceAt") start := time.Now() @@ -665,7 +667,7 @@ func (r *rpcClient) PendingCodeAt(ctx context.Context, account common.Address) ( return nil, err } defer cancel() - lggr := r.newRqLggr().With("account", account) + lggr := logger.With(r.newRqLggr(), "account", account) lggr.Debug("RPC call: evmclient.Client#PendingCodeAt") start := time.Now() @@ -691,7 +693,7 @@ func (r *rpcClient) CodeAt(ctx context.Context, account common.Address, blockNum return nil, err } defer cancel() - lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) + lggr := logger.With(r.newRqLggr(), "account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CodeAt") start := time.Now() @@ -718,7 +720,7 @@ func (r *rpcClient) EstimateGas(ctx context.Context, c interface{}) (gas uint64, } defer cancel() call := c.(ethereum.CallMsg) - lggr := r.newRqLggr().With("call", call) + lggr := logger.With(r.newRqLggr(), "call", call) lggr.Debug("RPC call: evmclient.Client#EstimateGas") start := time.Now() @@ -770,7 +772,7 @@ func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumb return nil, err } defer cancel() - lggr := r.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber) + lggr := logger.With(r.newRqLggr(), "callMsg", msg, "blockNumber", blockNumber) message := msg.(ethereum.CallMsg) lggr.Debug("RPC call: evmclient.Client#CallContract") @@ -830,7 +832,7 @@ func (r *rpcClient) BalanceAt(ctx context.Context, account common.Address, block return nil, err } defer cancel() - lggr := r.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber) + lggr := logger.With(r.newRqLggr(), "account", account.Hex(), "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#BalanceAt") start := time.Now() @@ -887,7 +889,7 @@ func (r *rpcClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l [ return nil, err } defer cancel() - lggr := r.newRqLggr().With("q", q) + lggr := logger.With(r.newRqLggr(), "q", q) lggr.Debug("RPC call: evmclient.Client#FilterLogs") start := time.Now() @@ -918,7 +920,7 @@ func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQu return nil, err } defer cancel() - lggr := r.newRqLggr().With("q", q) + lggr := logger.With(r.newRqLggr(), "q", q) lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") start := time.Now() @@ -979,7 +981,7 @@ func (r *rpcClient) ChainID(ctx context.Context) (chainID *big.Int, err error) { // newRqLggr generates a new logger with a unique request ID func (r *rpcClient) newRqLggr() logger.Logger { - return r.rpcLog.With( + return logger.With(r.rpcLog, "requestID", uuid.New(), ) } @@ -1004,7 +1006,7 @@ func (r *rpcClient) wrapHTTP(err error) error { if err != nil { r.rpcLog.Debugw("Call failed", "err", err) } else { - r.rpcLog.Trace("Call succeeded") + logger.Trace(r.rpcLog, "Call succeeded") } return err } diff --git a/core/chains/evm/client/send_only_node.go b/core/chains/evm/client/send_only_node.go index 02f04881c4..62a22ee193 100644 --- a/core/chains/evm/client/send_only_node.go +++ b/core/chains/evm/client/send_only_node.go @@ -14,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) //go:generate mockery --quiet --name SendOnlyNode --output ../mocks/ --case=underscore @@ -76,7 +76,8 @@ type sendOnlyNode struct { func NewSendOnlyNode(lggr logger.Logger, httpuri url.URL, name string, chainID *big.Int) SendOnlyNode { s := new(sendOnlyNode) s.name = name - s.log = lggr.Named("SendOnlyNode").Named(name).With( + s.log = logger.Named(logger.Named(lggr, "SendOnlyNode"), name) + s.log = logger.With(s.log, "nodeTier", "sendonly", ) s.uri = httpuri @@ -206,7 +207,7 @@ func (s *sendOnlyNode) SendTransaction(parentCtx context.Context, tx *types.Tran func (s *sendOnlyNode) BatchCallContext(parentCtx context.Context, b []rpc.BatchElem) (err error) { defer func(start time.Time) { - s.logTiming(s.log.With("nBatchElems", len(b)), time.Since(start), err, "BatchCallContext") + s.logTiming(logger.With(s.log, "nBatchElems", len(b)), time.Since(start), err, "BatchCallContext") }(time.Now()) ctx, cancel := s.makeQueryCtx(parentCtx) diff --git a/core/chains/evm/client/send_only_node_test.go b/core/chains/evm/client/send_only_node_test.go index 876ae9bc4d..760f7f4d3e 100644 --- a/core/chains/evm/client/send_only_node_test.go +++ b/core/chains/evm/client/send_only_node_test.go @@ -16,13 +16,13 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestNewSendOnlyNode(t *testing.T) { @@ -32,7 +32,7 @@ func TestNewSendOnlyNode(t *testing.T) { password := "pass" url := testutils.MustParseURL(t, fmt.Sprintf(urlFormat, password)) redacted := fmt.Sprintf(urlFormat, "xxxxx") - lggr := logger.TestLogger(t) + lggr := logger.Test(t) name := "TestNewSendOnlyNode" chainID := testutils.NewRandomEVMChainID() @@ -52,7 +52,7 @@ func TestStartSendOnlyNode(t *testing.T) { chainID := testutils.NewRandomEVMChainID() r := chainIDResp{chainID.Int64(), nil} url := r.newHTTPServer(t) - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) s := evmclient.NewSendOnlyNode(lggr, *url, t.Name(), chainID) defer func() { assert.NoError(t, s.Close()) }() err := s.Start(testutils.Context(t)) @@ -62,7 +62,7 @@ func TestStartSendOnlyNode(t *testing.T) { t.Run("Start with ChainID=0", func(t *testing.T) { t.Parallel() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) chainID := testutils.FixtureChainID r := chainIDResp{chainID.Int64(), nil} url := r.newHTTPServer(t) @@ -77,7 +77,7 @@ func TestStartSendOnlyNode(t *testing.T) { t.Run("becomes unusable (and remains undialed) if initial dial fails", func(t *testing.T) { t.Parallel() - lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zap.WarnLevel) invalidURL := url.URL{Scheme: "some rubbish", Host: "not a valid host"} s := evmclient.NewSendOnlyNode(lggr, invalidURL, t.Name(), testutils.FixtureChainID) @@ -109,7 +109,7 @@ func TestSendTransaction(t *testing.T) { t.Parallel() chainID := testutils.FixtureChainID - lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) url := testutils.MustParseURL(t, "http://place.holder") s := evmclient.NewSendOnlyNode(lggr, *url, @@ -135,7 +135,7 @@ func TestSendTransaction(t *testing.T) { func TestBatchCallContext(t *testing.T) { t.Parallel() - lggr := logger.TestLogger(t) + lggr := logger.Test(t) chainID := testutils.FixtureChainID url := testutils.MustParseURL(t, "http://place.holder") s := evmclient.NewSendOnlyNode( diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index e922715eb9..10b2aae502 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -19,9 +19,10 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -347,7 +348,7 @@ func (c *SimulatedBackendClient) SendTransactionReturnCode(ctx context.Context, func (c *SimulatedBackendClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { sender, err := types.Sender(types.NewLondonSigner(c.chainId), tx) if err != nil { - logger.TestLogger(c.t).Panic(fmt.Errorf("invalid transaction: %v (tx: %#v)", err, tx)) + logger.Test(c.t).Panic(fmt.Errorf("invalid transaction: %v (tx: %#v)", err, tx)) } pendingNonce, err := c.b.PendingNonceAt(ctx, sender) if err != nil { diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index 804c354e0e..fb6df26b1a 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -10,10 +10,11 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func NewTOMLChainScopedConfig(appCfg config.AppConfig, tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 819fb31951..eaf0c32afe 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -20,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -56,7 +56,7 @@ type FwdMgr struct { } func NewFwdMgr(db *sqlx.DB, client evmclient.Client, logpoller evmlogpoller.LogPoller, l logger.Logger, cfg Config, dbConfig pg.QConfig) *FwdMgr { - lggr := logger.Sugared(l.Named("EVMForwarderManager")) + lggr := logger.Sugared(logger.Named(l, "EVMForwarderManager")) fwdMgr := FwdMgr{ logger: lggr, cfg: cfg, diff --git a/core/chains/evm/forwarders/forwarder_manager_test.go b/core/chains/evm/forwarders/forwarder_manager_test.go index 082d329e38..1da638e743 100644 --- a/core/chains/evm/forwarders/forwarder_manager_test.go +++ b/core/chains/evm/forwarders/forwarder_manager_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -32,7 +32,7 @@ var GetAuthorisedSendersABI = evmtypes.MustGetABI(authorized_receiver.Authorized var SimpleOracleCallABI = evmtypes.MustGetABI(operator_wrapper.OperatorABI).Methods["getChainlinkToken"] func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -60,7 +60,7 @@ func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { evmClient := client.NewSimulatedBackendClient(t, ec, testutils.FixtureChainID) lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), evmClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) - fwdMgr.ORM = forwarders.NewORM(db, logger.TestLogger(t), cfg.Database()) + fwdMgr.ORM = forwarders.NewORM(db, logger.Test(t), cfg.Database()) fwd, err := fwdMgr.ORM.CreateForwarder(forwarderAddr, utils.Big(*testutils.FixtureChainID)) require.NoError(t, err) @@ -91,7 +91,7 @@ func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { } func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -113,7 +113,7 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) { evmClient := client.NewSimulatedBackendClient(t, ec, testutils.FixtureChainID) lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), evmClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) - fwdMgr.ORM = forwarders.NewORM(db, logger.TestLogger(t), cfg.Database()) + fwdMgr.ORM = forwarders.NewORM(db, logger.Test(t), cfg.Database()) _, err = fwdMgr.ORM.CreateForwarder(forwarderAddr, utils.Big(*testutils.FixtureChainID)) require.NoError(t, err) diff --git a/core/chains/evm/forwarders/orm.go b/core/chains/evm/forwarders/orm.go index df89dbe29e..104e257425 100644 --- a/core/chains/evm/forwarders/orm.go +++ b/core/chains/evm/forwarders/orm.go @@ -7,7 +7,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/forwarders/orm_test.go b/core/chains/evm/forwarders/orm_test.go index f6d63dc574..ba9664c196 100644 --- a/core/chains/evm/forwarders/orm_test.go +++ b/core/chains/evm/forwarders/orm_test.go @@ -9,9 +9,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -28,7 +28,7 @@ func setupORM(t *testing.T) *TestORM { var ( db = pgtest.NewSqlxDB(t) - lggr = logger.TestLogger(t) + lggr = logger.Test(t) orm = NewORM(db, lggr, pgtest.NewQConfig(true)) ) diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 480abfe721..ee020f6700 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -13,12 +13,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -53,7 +53,7 @@ type arbitrumEstimator struct { } func NewArbitrumEstimator(lggr logger.Logger, cfg ArbConfig, rpcClient rpcClient, ethClient ethClient) EvmEstimator { - lggr = lggr.Named("ArbitrumEstimator") + lggr = logger.Named(lggr, "ArbitrumEstimator") return &arbitrumEstimator{ cfg: cfg, EvmEstimator: NewSuggestedPriceEstimator(lggr, rpcClient), diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index 894b531dc9..53f8161798 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -14,11 +14,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type arbConfig struct { @@ -41,7 +41,7 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { rpcClient := mocks.NewRPCClient(t) ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, rpcClient, ethClient) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "estimator is not started") }) @@ -65,7 +65,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) require.NoError(t, o.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, o.Close()) }) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) @@ -78,7 +78,7 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("gas price is lower than user specified max gas price", func(t *testing.T) { client := mocks.NewRPCClient(t) ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{}, client, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, client, ethClient) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -104,7 +104,7 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("gas price is lower than global max gas price", func(t *testing.T) { ethClient := mocks.NewETHClient(t) client := mocks.NewRPCClient(t) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{}, client, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, client, ethClient) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -129,7 +129,7 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("calling BumpLegacyGas always returns error", func(t *testing.T) { rpcClient := mocks.NewRPCClient(t) ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, rpcClient, ethClient) _, _, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), gasLimit, assets.NewWeiI(10), nil) assert.EqualError(t, err, "bump gas is not supported for this chain") }) @@ -137,7 +137,7 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("calling GetLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{}, client, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, client, ethClient) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { @@ -180,7 +180,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(b.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) require.NoError(t, o.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, o.Close()) }) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) @@ -215,7 +215,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(b.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.TestLogger(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) require.NoError(t, o.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, o.Close()) }) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index a3f3520b36..64dc331f65 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -15,14 +15,15 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) @@ -142,7 +143,7 @@ func NewBlockHistoryEstimator(lggr logger.Logger, ethClient evmclient.Client, cf wg: new(sync.WaitGroup), ctx: ctx, ctxCancel: cancel, - logger: logger.Sugared(lggr.Named("BlockHistoryEstimator")), + logger: logger.Sugared(logger.Named(lggr, "BlockHistoryEstimator")), } return b @@ -197,7 +198,7 @@ func (b *BlockHistoryEstimator) getBlocks() []evmtypes.Block { // The provided context can be used to terminate Start sequence. func (b *BlockHistoryEstimator) Start(ctx context.Context) error { return b.StartOnce("BlockHistoryEstimator", func() error { - b.logger.Trace("Starting") + logger.Trace(b.logger, "Starting") if b.bhConfig.CheckInclusionBlocks() > 0 { b.logger.Infof("Inclusion checking enabled, bumping will be prevented on transactions that have been priced above the %d percentile for %d blocks", b.bhConfig.CheckInclusionPercentile(), b.bhConfig.CheckInclusionBlocks()) @@ -227,7 +228,7 @@ func (b *BlockHistoryEstimator) Start(ctx context.Context) error { b.wg.Add(1) go b.runLoop() - b.logger.Trace("Started") + logger.Trace(b.logger, "Started") return nil }) } @@ -290,7 +291,7 @@ func (b *BlockHistoryEstimator) BumpLegacyGas(_ context.Context, originalGasPric if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { if errors.Is(err, commonfee.ErrConnectivity) { - b.logger.Criticalw(BumpingHaltedLabel, "err", err) + logger.Criticalw(b.logger, BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "legacy").Inc() } @@ -466,7 +467,7 @@ func (b *BlockHistoryEstimator) BumpDynamicFee(_ context.Context, originalFee Dy if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { if errors.Is(err, commonfee.ErrConnectivity) { - b.logger.Criticalw(BumpingHaltedLabel, "err", err) + logger.Criticalw(b.logger, BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "eip1559").Inc() } @@ -507,7 +508,7 @@ func (b *BlockHistoryEstimator) FetchBlocksAndRecalculate(ctx context.Context, h func (b *BlockHistoryEstimator) Recalculate(head *evmtypes.Head) { percentile := int(b.bhConfig.TransactionPercentile()) - lggr := b.logger.With("head", head) + lggr := logger.With(b.logger, "head", head) blockHistory := b.getBlocks() if len(blockHistory) == 0 { @@ -629,9 +630,9 @@ func (b *BlockHistoryEstimator) FetchBlocks(ctx context.Context, head *evmtypes. reqs = append(reqs, req) } - lggr := b.logger.With("head", head) + lggr := logger.With(b.logger, "head", head) - lggr.Tracew(fmt.Sprintf("Fetching %v blocks (%v in local history)", len(reqs), len(blocks)), "n", len(reqs), "inHistory", len(blocks), "blockNum", head.Number) + logger.Tracew(lggr, fmt.Sprintf("Fetching %v blocks (%v in local history)", len(reqs), len(blocks)), "n", len(reqs), "inHistory", len(blocks), "blockNum", head.Number) if err := b.batchFetch(ctx, reqs); err != nil { return err } @@ -712,7 +713,7 @@ func (b *BlockHistoryEstimator) batchFetch(ctx context.Context, reqs []rpc.Batch j = len(reqs) } - b.logger.Tracew(fmt.Sprintf("Batch fetching blocks %v thru %v", HexToInt64(reqs[i].Args[0]), HexToInt64(reqs[j-1].Args[0]))) + logger.Tracew(b.logger, fmt.Sprintf("Batch fetching blocks %v thru %v", HexToInt64(reqs[i].Args[0]), HexToInt64(reqs[j-1].Args[0]))) err := b.ethClient.BatchCallContext(ctx, reqs[i:j]) if errors.Is(err, context.DeadlineExceeded) { diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index 2747ea067d..d3edf212b6 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -18,6 +18,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -27,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -42,7 +42,7 @@ func newBlockHistoryConfig() *gas.MockBlockHistoryConfig { } func newBlockHistoryEstimatorWithChainID(t *testing.T, c evmclient.Client, cfg gas.Config, gCfg gas.GasEstimatorConfig, bhCfg gas.BlockHistoryConfig, cid big.Int) gas.EvmEstimator { - return gas.NewBlockHistoryEstimator(logger.TestLogger(t), c, cfg, gCfg, bhCfg, cid) + return gas.NewBlockHistoryEstimator(logger.Test(t), c, cfg, gCfg, bhCfg, cid) } func newBlockHistoryEstimator(t *testing.T, c evmclient.Client, cfg gas.Config, gCfg gas.GasEstimatorConfig, bhCfg gas.BlockHistoryConfig) *gas.BlockHistoryEstimator { @@ -1300,69 +1300,69 @@ func TestBlockHistoryEstimator_IsUsable(t *testing.T) { } t.Run("returns false if transaction has 0 gas limit", func(t *testing.T) { tx := evmtypes.Transaction{Type: 0x0, GasPrice: assets.NewWeiI(10), GasLimit: 0, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) t.Run("returns false if transaction gas limit is nil and tx type is 0x0", func(t *testing.T) { tx := evmtypes.Transaction{Type: 0x0, GasPrice: nil, GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) t.Run("returns false if transaction is of type 0x7e only on Optimism", func(t *testing.T) { cfg.ChainTypeF = "optimismBedrock" tx := evmtypes.Transaction{Type: 0x7e, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) cfg.ChainTypeF = "" - assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) t.Run("returns false if transaction is of type 0x7c or 0x7b only on Celo", func(t *testing.T) { cfg.ChainTypeF = "celo" tx := evmtypes.Transaction{Type: 0x7c, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) tx2 := evmtypes.Transaction{Type: 0x7b, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) cfg.ChainTypeF = "" - assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) - assert.Equal(t, true, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) + assert.Equal(t, true, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) t.Run("returns false if transaction is of type 0x16 only on WeMix", func(t *testing.T) { cfg.ChainTypeF = "wemix" tx := evmtypes.Transaction{Type: 0x16, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) t.Run("returns false if transaction has base fee higher than the gas price only on Celo", func(t *testing.T) { cfg.ChainTypeF = "celo" tx := evmtypes.Transaction{Type: 0x0, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) tx2 := evmtypes.Transaction{Type: 0x2, MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(250), GasPrice: assets.NewWeiI(50), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) cfg.ChainTypeF = "" - assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) - assert.Equal(t, true, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) + assert.Equal(t, true, bhe.IsUsable(tx2, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) t.Run("returns false if transaction is of type 0x71 or 0xff only on zkSync", func(t *testing.T) { cfg.ChainTypeF = string(config.ChainZkSync) tx := evmtypes.Transaction{Type: 0x71, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) tx.Type = 0x02 - assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) tx.Type = 0xff - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) cfg.ChainTypeF = "" - assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) } @@ -2040,7 +2040,7 @@ func TestBlockHistoryEstimator_CheckConnectivity(t *testing.T) { cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() bhCfg.CheckInclusionBlocksF = uint16(4) - lggr, obs := logger.TestLoggerObserved(t, zapcore.DebugLevel) + lggr, obs := logger.TestObserved(t, zapcore.DebugLevel) geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = false @@ -2381,7 +2381,7 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { gasPrice, gasLimit, err := bhe.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) require.NoError(t, err) - expectedGasPrice, expectedGasLimit, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestLogger(t), nil, assets.NewWeiI(42), 100000, maxGasPrice) + expectedGasPrice, expectedGasLimit, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestSugared(t), nil, assets.NewWeiI(42), 100000, maxGasPrice) require.NoError(t, err) assert.Equal(t, expectedGasLimit, gasLimit) @@ -2395,7 +2395,7 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { massive := assets.NewWeiI(100000000000000) gas.SetGasPrice(bhe, massive) - expectedGasPrice, expectedGasLimit, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestLogger(t), massive, assets.NewWeiI(42), 100000, maxGasPrice) + expectedGasPrice, expectedGasLimit, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestSugared(t), massive, assets.NewWeiI(42), 100000, maxGasPrice) require.NoError(t, err) assert.Equal(t, expectedGasLimit, gasLimit) diff --git a/core/chains/evm/gas/cmd/arbgas/main.go b/core/chains/evm/gas/cmd/arbgas/main.go index 6b79ff2f13..e4fb1b4e88 100644 --- a/core/chains/evm/gas/cmd/arbgas/main.go +++ b/core/chains/evm/gas/cmd/arbgas/main.go @@ -9,12 +9,11 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" - "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/logger" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func main() { @@ -22,9 +21,10 @@ func main() { log.Fatal("Expected one URL argument but got", l-1) } url := os.Args[1] - lggr, sync := logger.NewLogger() - defer func() { _ = sync() }() - lggr.SetLogLevel(zapcore.DebugLevel) + lggr, err := logger.New() + if err != nil { + log.Fatal("Failed to create logger:", err) + } ctx := context.Background() withEstimator(ctx, logger.Sugared(lggr), url, func(e gas.EvmEstimator) { diff --git a/core/chains/evm/gas/fixed_price_estimator.go b/core/chains/evm/gas/fixed_price_estimator.go index 7eb7454dad..4d9f45a1bd 100644 --- a/core/chains/evm/gas/fixed_price_estimator.go +++ b/core/chains/evm/gas/fixed_price_estimator.go @@ -5,11 +5,11 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) var _ EvmEstimator = (*fixedPriceEstimator)(nil) @@ -45,7 +45,7 @@ type fixedPriceEstimatorBlockHistoryConfig interface { // NewFixedPriceEstimator returns a new "FixedPrice" estimator which will // always use the config default values for gas prices and limits func NewFixedPriceEstimator(cfg fixedPriceEstimatorConfig, bhCfg fixedPriceEstimatorBlockHistoryConfig, lggr logger.Logger) EvmEstimator { - return &fixedPriceEstimator{cfg, bhCfg, logger.Sugared(lggr.Named("FixedPriceEstimator"))} + return &fixedPriceEstimator{cfg, bhCfg, logger.Sugared(logger.Named(lggr, "FixedPriceEstimator"))} } func (f *fixedPriceEstimator) Start(context.Context) error { diff --git a/core/chains/evm/gas/fixed_price_estimator_test.go b/core/chains/evm/gas/fixed_price_estimator_test.go index 9fa0997c10..968275ace4 100644 --- a/core/chains/evm/gas/fixed_price_estimator_test.go +++ b/core/chains/evm/gas/fixed_price_estimator_test.go @@ -6,10 +6,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type blockHistoryConfig struct { @@ -26,7 +26,7 @@ func Test_FixedPriceEstimator(t *testing.T) { t.Run("GetLegacyGas returns EvmGasPriceDefault from config, with multiplier applied", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.TestLogger(t)) + f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) config.PriceDefaultF = assets.NewWeiI(42) config.LimitMultiplierF = float32(1.1) @@ -43,7 +43,7 @@ func Test_FixedPriceEstimator(t *testing.T) { config.PriceDefaultF = assets.NewWeiI(42) config.LimitMultiplierF = float32(1.1) config.PriceMaxF = assets.NewWeiI(35) - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.TestLogger(t)) + f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) gasPrice, gasLimit, err := f.GetLegacyGas(testutils.Context(t), nil, 100000, assets.NewWeiI(30)) require.NoError(t, err) @@ -57,7 +57,7 @@ func Test_FixedPriceEstimator(t *testing.T) { config.LimitMultiplierF = float32(1.1) config.PriceMaxF = assets.NewWeiI(20) - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.TestLogger(t)) + f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) gasPrice, gasLimit, err := f.GetLegacyGas(testutils.Context(t), nil, 100000, assets.NewWeiI(30)) require.NoError(t, err) assert.Equal(t, 110000, int(gasLimit)) @@ -72,7 +72,7 @@ func Test_FixedPriceEstimator(t *testing.T) { config.BumpPercentF = uint16(10) config.BumpMinF = assets.NewWeiI(150) - lggr := logger.TestLogger(t) + lggr := logger.TestSugared(t) f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) gasPrice, gasLimit, err := f.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) @@ -93,7 +93,7 @@ func Test_FixedPriceEstimator(t *testing.T) { config.FeeCapDefaultF = assets.NewWeiI(100) config.BumpThresholdF = uint64(3) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) fee, gasLimit, err := f.GetDynamicFee(testutils.Context(t), 100000, maxGasPrice) @@ -130,7 +130,7 @@ func Test_FixedPriceEstimator(t *testing.T) { config.BumpMinF = assets.NewWeiI(150) config.BumpPercentF = uint16(10) - lggr := logger.TestLogger(t) + lggr := logger.TestSugared(t) f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} diff --git a/core/chains/evm/gas/gas_test.go b/core/chains/evm/gas/gas_test.go index a3f7224a09..355d39b6ce 100644 --- a/core/chains/evm/gas/gas_test.go +++ b/core/chains/evm/gas/gas_test.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func Test_BumpLegacyGasPriceOnly(t *testing.T) { @@ -95,7 +95,7 @@ func Test_BumpLegacyGasPriceOnly(t *testing.T) { cfg.BumpMinF = test.bumpMin cfg.PriceMaxF = test.priceMax cfg.LimitMultiplierF = test.limitMultiplierPercent - actual, limit, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestLogger(t), test.currentGasPrice, test.originalGasPrice, test.originalLimit, test.priceMax) + actual, limit, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestSugared(t), test.currentGasPrice, test.originalGasPrice, test.originalLimit, test.priceMax) require.NoError(t, err) if actual.Cmp(test.expectedGasPrice) != 0 { t.Fatalf("Expected %s but got %s", test.expectedGasPrice.String(), actual.String()) @@ -115,7 +115,7 @@ func Test_BumpLegacyGasPriceOnly_HitsMaxError(t *testing.T) { cfg.PriceMaxF = priceMax originalGasPrice := toWei("3e10") // 30 GWei - _, _, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestLogger(t), nil, originalGasPrice, 42, priceMax) + _, _, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestSugared(t), nil, originalGasPrice, 42, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped gas price of 45 gwei would exceed configured max gas price of 40 gwei (original price was 30 gwei)") } @@ -124,7 +124,7 @@ func Test_BumpLegacyGasPriceOnly_NoBumpError(t *testing.T) { t.Parallel() priceMax := assets.GWei(40) - lggr := logger.TestLogger(t) + lggr := logger.TestSugared(t) cfg := &gas.MockGasEstimatorConfig{} cfg.BumpPercentF = uint16(0) @@ -298,7 +298,7 @@ func Test_BumpDynamicFeeOnly(t *testing.T) { cfg.LimitMultiplierF = test.limitMultiplierPercent bufferBlocks := uint16(4) - actual, limit, err := gas.BumpDynamicFeeOnly(cfg, bufferBlocks, logger.TestLogger(t), test.currentTipCap, test.currentBaseFee, test.originalFee, test.originalLimit, test.priceMax) + actual, limit, err := gas.BumpDynamicFeeOnly(cfg, bufferBlocks, logger.TestSugared(t), test.currentTipCap, test.currentBaseFee, test.originalFee, test.originalLimit, test.priceMax) require.NoError(t, err) if actual.TipCap.Cmp(test.expectedFee.TipCap) != 0 { t.Fatalf("TipCap not equal, expected %s but got %s", test.expectedFee.TipCap.String(), actual.TipCap.String()) @@ -324,14 +324,14 @@ func Test_BumpDynamicFeeOnly_HitsMaxError(t *testing.T) { t.Run("tip cap hits max", func(t *testing.T) { originalFee := gas.DynamicFee{TipCap: assets.GWei(30), FeeCap: assets.GWei(100)} - _, _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestLogger(t), nil, nil, originalFee, 42, priceMax) + _, _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestSugared(t), nil, nil, originalFee, 42, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped tip cap of 45 gwei would exceed configured max gas price of 40 gwei (original fee: tip cap 30 gwei, fee cap 100 gwei)") }) t.Run("fee cap hits max", func(t *testing.T) { originalFee := gas.DynamicFee{TipCap: assets.GWei(10), FeeCap: assets.GWei(100)} - _, _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestLogger(t), nil, nil, originalFee, 42, priceMax) + _, _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestSugared(t), nil, nil, originalFee, 42, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped fee cap of 150 gwei would exceed configured max gas price of 40 gwei (original fee: tip cap 10 gwei, fee cap 100 gwei)") }) diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index b6f34ab87a..4f9a541970 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/config" @@ -21,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index 1a0fe8b8b2..6a384fa9c5 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -12,11 +12,12 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -93,7 +94,7 @@ func NewL1GasPriceOracle(lggr logger.Logger, ethClient ethClient, chainType conf return &l1GasPriceOracle{ client: ethClient, pollPeriod: PollPeriod, - logger: lggr.Named(fmt.Sprintf("L1GasPriceOracle(%s)", chainType)), + logger: logger.Named(lggr, fmt.Sprintf("L1GasPriceOracle(%s)", chainType)), address: address, callArgs: callArgs, chInitialised: make(chan struct{}), @@ -158,7 +159,7 @@ func (o *l1GasPriceOracle) refresh() (t *time.Timer) { } if len(b) != 32 { // returns uint256; - o.logger.Criticalf("return data length (%d) different than expected (%d)", len(b), 32) + logger.Criticalf(o.logger, "return data length (%d) different than expected (%d)", len(b), 32) return } price := new(big.Int).SetBytes(b) diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go index 801d72919e..2defedd6b4 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go @@ -11,12 +11,12 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestL1GasPriceOracle(t *testing.T) { @@ -25,13 +25,13 @@ func TestL1GasPriceOracle(t *testing.T) { t.Run("Unsupported ChainType returns nil", func(t *testing.T) { ethClient := mocks.NewETHClient(t) - assert.Panicsf(t, func() { NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainCelo) }, "Received unspported chaintype %s", config.ChainCelo) + assert.Panicsf(t, func() { NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainCelo) }, "Received unspported chaintype %s", config.ChainCelo) }) t.Run("Calling L1GasPrice on unstarted L1Oracle returns error", func(t *testing.T) { ethClient := mocks.NewETHClient(t) - oracle := NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainOptimismBedrock) + oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock) _, err := oracle.GasPrice(testutils.Context(t)) assert.EqualError(t, err, "L1GasPriceOracle is not started; cannot estimate gas") @@ -49,7 +49,7 @@ func TestL1GasPriceOracle(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainArbitrum) + oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainArbitrum) require.NoError(t, oracle.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) @@ -71,7 +71,7 @@ func TestL1GasPriceOracle(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainKroma) + oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainKroma) require.NoError(t, oracle.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) @@ -93,7 +93,7 @@ func TestL1GasPriceOracle(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainOptimismBedrock) + oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock) require.NoError(t, oracle.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index cd5acbc694..2e0d32bfc9 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -9,12 +9,13 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -49,7 +50,7 @@ func NewSuggestedPriceEstimator(lggr logger.Logger, client rpcClient) EvmEstimat return &SuggestedPriceEstimator{ client: client, pollPeriod: 10 * time.Second, - logger: lggr.Named("SuggestedPriceEstimator"), + logger: logger.Named(lggr, "SuggestedPriceEstimator"), chForceRefetch: make(chan (chan struct{})), chInitialised: make(chan struct{}), chStop: make(chan struct{}), diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index 3b6b8184e3..304e535910 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -10,11 +10,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestSuggestedPriceEstimator(t *testing.T) { @@ -27,7 +27,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "estimator is not started") }) @@ -39,7 +39,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { (*big.Int)(res).SetInt64(42) }) - o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) require.NoError(t, o.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, o.Close()) }) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) @@ -50,7 +50,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { t.Run("gas price is lower than user specified max gas price", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -68,7 +68,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { t.Run("gas price is lower than global max gas price", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -85,14 +85,14 @@ func TestSuggestedPriceEstimator(t *testing.T) { t.Run("calling BumpLegacyGas always returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) _, _, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), gasLimit, assets.NewWeiI(10), nil) assert.EqualError(t, err, "bump gas is not supported for this chain") }) t.Run("calling GetLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.TestLogger(t), client) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) diff --git a/core/chains/evm/headtracker/head_broadcaster.go b/core/chains/evm/headtracker/head_broadcaster.go index b47fbc2726..9929646441 100644 --- a/core/chains/evm/headtracker/head_broadcaster.go +++ b/core/chains/evm/headtracker/head_broadcaster.go @@ -3,10 +3,10 @@ package headtracker import ( "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/headtracker" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type headBroadcaster = headtracker.HeadBroadcaster[*evmtypes.Head, common.Hash] diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index 5c2423f328..6fb151bfe6 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonhtrk "github.com/smartcontractkit/chainlink/v2/common/headtracker" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" @@ -20,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -48,7 +48,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { }) evmCfg := evmtest.NewChainScopedConfig(t, cfg) db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) sub := commonmocks.NewSubscription(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -101,7 +101,7 @@ func TestHeadBroadcaster_BroadcastNewLongestChain(t *testing.T) { t.Parallel() g := gomega.NewWithT(t) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) broadcaster := headtracker.NewHeadBroadcaster(lggr) err := broadcaster.Start(testutils.Context(t)) @@ -143,7 +143,7 @@ func TestHeadBroadcaster_BroadcastNewLongestChain(t *testing.T) { func TestHeadBroadcaster_TrackableCallbackTimeout(t *testing.T) { t.Parallel() - lggr := logger.TestLogger(t) + lggr := logger.Test(t) broadcaster := headtracker.NewHeadBroadcaster(lggr) err := broadcaster.Start(testutils.Context(t)) diff --git a/core/chains/evm/headtracker/head_listener.go b/core/chains/evm/headtracker/head_listener.go index 3c81c8895e..242b59e9a8 100644 --- a/core/chains/evm/headtracker/head_listener.go +++ b/core/chains/evm/headtracker/head_listener.go @@ -6,11 +6,11 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/headtracker" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type headListener = headtracker.HeadListener[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash] diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go index dff97f5843..8bb761bdfa 100644 --- a/core/chains/evm/headtracker/head_listener_test.go +++ b/core/chains/evm/headtracker/head_listener_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -19,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -35,7 +35,7 @@ func Test_HeadListener_HappyPath(t *testing.T) { // - 3 heads is passed to callback // - ethClient methods are invoked - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { // no need to test head timeouts here @@ -96,7 +96,7 @@ func Test_HeadListener_NotReceivingHeads(t *testing.T) { // - send one head, make sure ReceivingHeads() is true // - do not send any heads within BlockEmissionIdleWarningThreshold and check ReceivingHeads() is false - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -162,7 +162,7 @@ func Test_HeadListener_SubscriptionErr(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - l := logger.TestLogger(t) + l := logger.Test(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, nil) evmcfg := evmtest.NewChainScopedConfig(t, cfg) diff --git a/core/chains/evm/headtracker/head_saver.go b/core/chains/evm/headtracker/head_saver.go index 6b4b20c89c..92eedaf153 100644 --- a/core/chains/evm/headtracker/head_saver.go +++ b/core/chains/evm/headtracker/head_saver.go @@ -5,10 +5,10 @@ import ( "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type headSaver struct { @@ -26,7 +26,7 @@ func NewHeadSaver(lggr logger.Logger, orm ORM, config Config, htConfig HeadTrack orm: orm, config: config, htConfig: htConfig, - logger: lggr.Named("HeadSaver"), + logger: logger.Named(lggr, "HeadSaver"), heads: NewHeads(), } } diff --git a/core/chains/evm/headtracker/head_saver_test.go b/core/chains/evm/headtracker/head_saver_test.go index 5ed85adc59..f541330bc9 100644 --- a/core/chains/evm/headtracker/head_saver_test.go +++ b/core/chains/evm/headtracker/head_saver_test.go @@ -6,13 +6,13 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type headTrackerConfig struct { @@ -43,7 +43,7 @@ func (c *config) BlockEmissionIdleWarningThreshold() time.Duration { func configureSaver(t *testing.T) (httypes.HeadSaver, headtracker.ORM) { db := pgtest.NewSqlxDB(t) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) cfg := configtest.NewGeneralConfig(t, nil) htCfg := &config{finalityDepth: uint32(1)} orm := headtracker.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) diff --git a/core/chains/evm/headtracker/head_tracker.go b/core/chains/evm/headtracker/head_tracker.go index dd94f96383..b86a6b5fe2 100644 --- a/core/chains/evm/headtracker/head_tracker.go +++ b/core/chains/evm/headtracker/head_tracker.go @@ -8,12 +8,12 @@ import ( "github.com/ethereum/go-ethereum/common" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/headtracker" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index d734b230e1..4d3cebd24e 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -20,6 +20,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" @@ -32,7 +33,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -49,7 +49,7 @@ func TestHeadTracker_New(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := configtest.NewGeneralConfig(t, nil) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(cltest.Head(0), nil) @@ -73,7 +73,7 @@ func TestHeadTracker_Save_InsertsAndTrimsTable(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -118,7 +118,7 @@ func TestHeadTracker_Get(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) orm := headtracker.NewORM(db, logger, config.Database(), cltest.FixtureChainID) @@ -165,7 +165,7 @@ func TestHeadTracker_Start_NewHeads(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) orm := headtracker.NewORM(db, logger, config.Database(), cltest.FixtureChainID) @@ -190,7 +190,7 @@ func TestHeadTracker_Start_CancelContext(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) orm := headtracker.NewORM(db, logger, config.Database(), cltest.FixtureChainID) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -230,7 +230,7 @@ func TestHeadTracker_CallsHeadTrackableCallbacks(t *testing.T) { g := gomega.NewWithT(t) db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) orm := headtracker.NewORM(db, logger, config.Database(), cltest.FixtureChainID) @@ -269,7 +269,7 @@ func TestHeadTracker_ReconnectOnError(t *testing.T) { g := gomega.NewWithT(t) db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) orm := headtracker.NewORM(db, logger, config.Database(), cltest.FixtureChainID) @@ -305,7 +305,7 @@ func TestHeadTracker_ResubscribeOnSubscriptionError(t *testing.T) { g := gomega.NewWithT(t) db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) orm := headtracker.NewORM(db, logger, config.Database(), cltest.FixtureChainID) @@ -352,7 +352,7 @@ func TestHeadTracker_Start_LoadsLatestChain(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := cltest.NewTestChainScopedConfig(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -417,7 +417,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingEnabled(t *testing.T) t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](50) @@ -545,7 +545,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingDisabled(t *testing.T t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](50) @@ -773,7 +773,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("does nothing if all the heads are in database", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) for i := range heads { require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), &heads[i])) @@ -790,7 +790,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("fetches a missing head", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) for i := range heads { require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), &heads[i])) @@ -826,7 +826,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("fetches only heads that are missing", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) for i := range heads { require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), &heads[i])) @@ -859,7 +859,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("does not backfill if chain length is already greater than or equal to depth", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) for i := range heads { require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), &heads[i])) @@ -880,7 +880,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("only backfills to height 0 if chain length would otherwise cause it to try and fetch a negative head", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) ethClient := evmtest.NewEthClientMock(t) @@ -905,7 +905,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("abandons backfill and returns error if the eth node returns not found", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) for i := range heads { require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), &heads[i])) @@ -936,7 +936,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("abandons backfill and returns error if the context time budget is exceeded", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) for i := range heads { require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), &heads[i])) @@ -965,7 +965,7 @@ func TestHeadTracker_Backfill(t *testing.T) { t.Run("abandons backfill and returns error when fetching a block by hash fails, indicating a reorg", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - logger := logger.TestLogger(t) + logger := logger.Test(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) ethClient := evmtest.NewEthClientMock(t) ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) @@ -989,7 +989,7 @@ func TestHeadTracker_Backfill(t *testing.T) { } func createHeadTracker(t *testing.T, ethClient evmclient.Client, config headtracker.Config, htConfig headtracker.HeadTrackerConfig, orm headtracker.ORM) *headTrackerUniverse { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, config, htConfig) mailMon := utils.NewMailboxMonitor(t.Name()) @@ -1004,7 +1004,7 @@ func createHeadTracker(t *testing.T, ethClient evmclient.Client, config headtrac func createHeadTrackerWithNeverSleeper(t *testing.T, ethClient evmclient.Client, cfg chainlink.GeneralConfig, orm headtracker.ORM) *headTrackerUniverse { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, evmcfg.EVM(), evmcfg.EVM().HeadTracker()) mailMon := utils.NewMailboxMonitor(t.Name()) @@ -1021,7 +1021,7 @@ func createHeadTrackerWithNeverSleeper(t *testing.T, ethClient evmclient.Client, } func createHeadTrackerWithChecker(t *testing.T, ethClient evmclient.Client, config headtracker.Config, htConfig headtracker.HeadTrackerConfig, orm headtracker.ORM, checker httypes.HeadTrackable) *headTrackerUniverse { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, config, htConfig) hb.Subscribe(checker) diff --git a/core/chains/evm/headtracker/orm.go b/core/chains/evm/headtracker/orm.go index 34f46ce44d..88d569b9a2 100644 --- a/core/chains/evm/headtracker/orm.go +++ b/core/chains/evm/headtracker/orm.go @@ -10,8 +10,8 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -36,7 +36,7 @@ type orm struct { } func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, chainID big.Int) ORM { - return &orm{pg.NewQ(db, lggr.Named("HeadTrackerORM"), cfg), utils.Big(chainID)} + return &orm{pg.NewQ(db, logger.Named(lggr, "HeadTrackerORM"), cfg), utils.Big(chainID)} } func (orm *orm) IdempotentInsertHead(ctx context.Context, head *evmtypes.Head) error { diff --git a/core/chains/evm/headtracker/orm_test.go b/core/chains/evm/headtracker/orm_test.go index 123478ff90..c9a2146daf 100644 --- a/core/chains/evm/headtracker/orm_test.go +++ b/core/chains/evm/headtracker/orm_test.go @@ -11,17 +11,17 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestORM_IdempotentInsertHead(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) cfg := configtest.NewGeneralConfig(t, nil) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) @@ -47,7 +47,7 @@ func TestORM_TrimOldHeads(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) cfg := configtest.NewGeneralConfig(t, nil) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) @@ -72,7 +72,7 @@ func TestORM_HeadByHash(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) cfg := configtest.NewGeneralConfig(t, nil) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) @@ -95,7 +95,7 @@ func TestORM_HeadByHash_NotFound(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) cfg := configtest.NewGeneralConfig(t, nil) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) @@ -110,7 +110,7 @@ func TestORM_LatestHeads_NoRows(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logger := logger.TestLogger(t) + logger := logger.Test(t) cfg := configtest.NewGeneralConfig(t, nil) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index d69fd696fd..f452839609 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -12,13 +12,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -167,7 +167,7 @@ var _ Broadcaster = (*broadcaster)(nil) // NewBroadcaster creates a new instance of the broadcaster func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *utils.MailboxMonitor) *broadcaster { chStop := make(chan struct{}) - lggr = lggr.Named("LogBroadcaster") + lggr = logger.Named(lggr, "LogBroadcaster") chainId := ethClient.ConfiguredChainID() return &broadcaster{ orm: orm, @@ -443,7 +443,7 @@ func (b *broadcaster) eventLoop(chRawLogs <-chan types.Log, chErr <-chan error) // Do we have logs in the pool? // They are are invalid, since we may have missed 'removed' logs. if blockNum := b.invalidatePool(); blockNum > 0 { - lggr = lggr.With("blockNumber", blockNum) + lggr = logger.With(lggr, "blockNumber", blockNum) } lggr.Debugw("Subscription terminated. Backfilling after resubscribing") return true, err diff --git a/core/chains/evm/log/eth_subscriber.go b/core/chains/evm/log/eth_subscriber.go index b4d386140e..96a7a8248a 100644 --- a/core/chains/evm/log/eth_subscriber.go +++ b/core/chains/evm/log/eth_subscriber.go @@ -10,10 +10,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -27,11 +27,11 @@ type ( } ) -func newEthSubscriber(ethClient evmclient.Client, config Config, logger logger.Logger, chStop chan struct{}) *ethSubscriber { +func newEthSubscriber(ethClient evmclient.Client, config Config, lggr logger.Logger, chStop chan struct{}) *ethSubscriber { return ðSubscriber{ ethClient: ethClient, config: config, - logger: logger.Named("EthSubscriber"), + logger: logger.Named(lggr, "EthSubscriber"), chStop: chStop, } } diff --git a/core/chains/evm/log/helpers_internal_test.go b/core/chains/evm/log/helpers_internal_test.go index b3b4890e36..38f40bd329 100644 --- a/core/chains/evm/log/helpers_internal_test.go +++ b/core/chains/evm/log/helpers_internal_test.go @@ -3,9 +3,9 @@ package log import ( "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index f787002578..ac7eb863e6 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -20,6 +20,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -34,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -88,7 +88,7 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, } }) config := evmtest.NewChainScopedConfig(t, globalConfig) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) db := pgtest.NewSqlxDB(t) @@ -265,7 +265,7 @@ func (helper *broadcasterHelper) newLogListenerWithJob(name string) *simpleLogLi var rec received return &simpleLogListener{ db: db, - lggr: logger.TestLogger(t), + lggr: logger.Test(t), cfg: helper.config.Database(), name: name, received: &rec, @@ -281,7 +281,7 @@ func (listener *simpleLogListener) SkipMarkingConsumed(skip bool) { func (listener *simpleLogListener) HandleLog(lb log.Broadcast) { listener.received.Lock() defer listener.received.Unlock() - listener.lggr.Tracef("Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) + logger.Tracef(listener.lggr, "Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) listener.received.logs = append(listener.received.logs, lb.RawLog()) listener.received.broadcasts = append(listener.received.broadcasts, lb) diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index 137b4c7292..edc04a4ada 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -266,7 +266,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 0, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") @@ -292,7 +292,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 2, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") @@ -317,7 +317,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 4, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") @@ -342,7 +342,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 7, 1, logs[1:], func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") listener2 := helper.newLogListenerWithJob("two") @@ -468,7 +468,7 @@ func TestBroadcaster_BackfillInBatches(t *testing.T) { var backfillCount atomic.Int64 - lggr := logger.TestLogger(t) + lggr := logger.Test(t) backfillStart := lastStoredBlockHeight - numConfirmations - int64(blockBackfillDepth) // the first backfill should start from before the last stored head mockEth.CheckFilterLogs = func(fromBlock int64, toBlock int64) { @@ -539,7 +539,7 @@ func TestBroadcaster_BackfillALargeNumberOfLogs(t *testing.T) { var backfillCount atomic.Int64 - lggr := logger.TestLogger(t) + lggr := logger.Test(t) mockEth.CheckFilterLogs = func(fromBlock int64, toBlock int64) { times := backfillCount.Add(1) - 1 lggr.Warnf("Log Batch: --------- times %v - %v, %v", times, fromBlock, toBlock) @@ -1325,7 +1325,7 @@ func TestBroadcaster_AppendLogChannel(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) - lb := log.NewBroadcaster(nil, ethClient, nil, logger.TestLogger(t), nil, mailMon) + lb := log.NewBroadcaster(nil, ethClient, nil, logger.Test(t), nil, mailMon) chCombined := lb.ExportedAppendLogChannel(ch1, ch2) chCombined = lb.ExportedAppendLogChannel(chCombined, ch3) diff --git a/core/chains/evm/log/orm.go b/core/chains/evm/log/orm.go index d383419d72..a2bcab6e78 100644 --- a/core/chains/evm/log/orm.go +++ b/core/chains/evm/log/orm.go @@ -11,7 +11,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/evm/log/orm_test.go b/core/chains/evm/log/orm_test.go index 48524896cf..758cfa1d69 100644 --- a/core/chains/evm/log/orm_test.go +++ b/core/chains/evm/log/orm_test.go @@ -10,18 +10,18 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) func TestORM_broadcasts(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) @@ -134,7 +134,7 @@ func TestORM_broadcasts(t *testing.T) { func TestORM_pending(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) num, err := orm.GetPendingMinBlock() @@ -160,7 +160,7 @@ func TestORM_pending(t *testing.T) { func TestORM_MarkUnconsumed(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) @@ -259,7 +259,7 @@ func TestORM_Reinitialize(t *testing.T) { t.Run(tt.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) jobID := cltest.MustInsertV2JobSpec(t, db, common.BigToAddress(big.NewInt(rand.Int63()))).ID diff --git a/core/chains/evm/log/pool.go b/core/chains/evm/log/pool.go index 4511c26eb6..7d534ff410 100644 --- a/core/chains/evm/log/pool.go +++ b/core/chains/evm/log/pool.go @@ -8,7 +8,7 @@ import ( heaps "github.com/theodesp/go-heaps" pairingHeap "github.com/theodesp/go-heaps/pairing" - "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" ) // The Log Pool interface. @@ -59,7 +59,7 @@ func newLogPool(lggr logger.Logger) *logPool { hashesByBlockNumbers: make(map[uint64]map[common.Hash]struct{}), logsByBlockHash: make(map[common.Hash]map[uint]map[uint]types.Log), heap: pairingHeap.New(), - logger: lggr.Named("LogPool"), + logger: logger.Named(lggr, "LogPool"), } } diff --git a/core/chains/evm/log/pool_test.go b/core/chains/evm/log/pool_test.go index 9e760f5726..c4789f5acd 100644 --- a/core/chains/evm/log/pool_test.go +++ b/core/chains/evm/log/pool_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -49,7 +49,7 @@ var ( func TestUnit_AddLog(t *testing.T) { t.Parallel() - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) blockHash := common.BigToHash(big.NewInt(1)) l1 := types.Log{ @@ -105,7 +105,7 @@ func TestUnit_AddLog(t *testing.T) { func TestUnit_GetAndDeleteAll(t *testing.T) { t.Parallel() - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) p.addLog(L1) p.addLog(L1) // duplicate an add p.addLog(L21) @@ -139,7 +139,7 @@ func TestUnit_GetAndDeleteAll(t *testing.T) { func TestUnit_GetLogsToSendWhenEmptyPool(t *testing.T) { t.Parallel() - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) logsOnBlocks, minBlockNumToSend := p.getLogsToSend(1) assert.Equal(t, int64(0), minBlockNumToSend) assert.ElementsMatch(t, []logsOnBlock{}, logsOnBlocks) @@ -206,7 +206,7 @@ func TestUnit_GetLogsToSend(t *testing.T) { }, } - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) p.addLog(L1) p.addLog(L21) p.addLog(L3) @@ -222,7 +222,7 @@ func TestUnit_GetLogsToSend(t *testing.T) { func TestUnit_DeleteOlderLogsWhenEmptyPool(t *testing.T) { t.Parallel() - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) keptDepth := p.deleteOlderLogs(1) var expectedKeptDepth *int64 require.Equal(t, expectedKeptDepth, keptDepth) @@ -286,7 +286,7 @@ func TestUnit_DeleteOlderLogs(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) p.addLog(L1) p.addLog(L21) p.addLog(L3) @@ -302,7 +302,7 @@ func TestUnit_DeleteOlderLogs(t *testing.T) { func TestUnit_RemoveBlockWhenEmptyPool(t *testing.T) { t.Parallel() - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) p.removeBlock(L1.BlockHash, L1.BlockNumber) } @@ -343,7 +343,7 @@ func TestUnit_RemoveBlock(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - var p iLogPool = newLogPool(logger.TestLogger(t)) + var p iLogPool = newLogPool(logger.Test(t)) p.addLog(L21) p.addLog(L22) p.addLog(L23) diff --git a/core/chains/evm/log/registrations.go b/core/chains/evm/log/registrations.go index f9cc933d0d..73f197a6ab 100644 --- a/core/chains/evm/log/registrations.go +++ b/core/chains/evm/log/registrations.go @@ -9,10 +9,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -70,13 +70,13 @@ type ( subscribers map[*subscriber][][]Topic ) -func newRegistrations(logger logger.Logger, evmChainID big.Int) *registrations { +func newRegistrations(lggr logger.Logger, evmChainID big.Int) *registrations { return ®istrations{ registeredSubs: make(map[*subscriber]struct{}), jobIDAddrs: make(map[int32]map[common.Address]struct{}), handlersByConfs: make(map[uint32]*handler), evmChainID: evmChainID, - logger: logger.Named("Registrations"), + logger: logger.Named(lggr, "Registrations"), } } @@ -85,7 +85,7 @@ func (r *registrations) addSubscriber(sub *subscriber) (needsResubscribe bool) { r.logger.Panicw(err.Error(), "err", err, "addr", sub.opts.Contract.Hex(), "jobID", sub.listener.JobID()) } - r.logger.Tracef("Added subscription %p with job ID %v", sub, sub.listener.JobID()) + logger.Tracef(r.logger, "Added subscription %p with job ID %v", sub, sub.listener.JobID()) handler, exists := r.handlersByConfs[sub.opts.MinIncomingConfirmations] if !exists { @@ -142,7 +142,7 @@ func (r *registrations) removeSubscriber(sub *subscriber) (needsResubscribe bool if err := r.checkRemoveSubscriber(sub); err != nil { r.logger.Panicw(err.Error(), "err", err, "addr", sub.opts.Contract.Hex(), "jobID", sub.listener.JobID()) } - r.logger.Tracef("Removed subscription %p with job ID %v", sub, sub.listener.JobID()) + logger.Tracef(r.logger, "Removed subscription %p with job ID %v", sub, sub.listener.JobID()) handlers, exists := r.handlersByConfs[sub.opts.MinIncomingConfirmations] if !exists { @@ -284,7 +284,7 @@ func (r *handler) addSubscriber(sub *subscriber, handlersWithGreaterConfs []*han for topic, topicValueFilters := range sub.opts.LogsWithTopics { if _, exists := r.lookupSubs[addr][topic]; !exists { - r.logger.Tracef("No existing sub for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + logger.Tracef(r.logger, "No existing sub for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) r.lookupSubs[addr][topic] = make(subscribers) func() { @@ -295,11 +295,11 @@ func (r *handler) addSubscriber(sub *subscriber, handlersWithGreaterConfs []*han // again since even the worst case lookback is already covered for _, existingHandler := range handlersWithGreaterConfs { if _, exists := existingHandler.lookupSubs[addr][topic]; exists { - r.logger.Tracef("Sub already exists for addr %s and topic %s at greater than this MinIncomingConfirmations of %v. Resubscribe is not required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + logger.Tracef(r.logger, "Sub already exists for addr %s and topic %s at greater than this MinIncomingConfirmations of %v. Resubscribe is not required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) return } } - r.logger.Tracef("No sub exists for addr %s and topic %s at this or greater MinIncomingConfirmations of %v. Resubscribe is required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + logger.Tracef(r.logger, "No sub exists for addr %s and topic %s at this or greater MinIncomingConfirmations of %v. Resubscribe is required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) needsResubscribe = true } }() @@ -332,7 +332,7 @@ func (r *handler) removeSubscriber(sub *subscriber, allHandlers map[uint32]*hand // cleanup and resubscribe if necessary if len(topicMap) == 0 { - r.logger.Tracef("No subs left for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + logger.Tracef(r.logger, "No subs left for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) func() { if !needsResubscribe { @@ -344,12 +344,12 @@ func (r *handler) removeSubscriber(sub *subscriber, allHandlers map[uint32]*hand continue } if _, exists := otherHandler.lookupSubs[addr][topic]; exists { - r.logger.Tracef("Sub still exists for addr %s and topic %s. Resubscribe will not be performed", addr.Hex(), topic.Hex()) + logger.Tracef(r.logger, "Sub still exists for addr %s and topic %s. Resubscribe will not be performed", addr.Hex(), topic.Hex()) return } } - r.logger.Tracef("No sub exists for addr %s and topic %s. Resubscribe will be performed", addr.Hex(), topic.Hex()) + logger.Tracef(r.logger, "No sub exists for addr %s and topic %s. Resubscribe will be performed", addr.Hex(), topic.Hex()) needsResubscribe = true } }() diff --git a/core/chains/evm/log/registrations_test.go b/core/chains/evm/log/registrations_test.go index c9d4eba589..0682564fe7 100644 --- a/core/chains/evm/log/registrations_test.go +++ b/core/chains/evm/log/registrations_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -26,7 +26,7 @@ func newTestListener(t *testing.T, jobID int32) testListener { } func newTestRegistrations(t *testing.T) *registrations { - return newRegistrations(logger.TestLogger(t), *testutils.FixtureChainID) + return newRegistrations(logger.Test(t), *testutils.FixtureChainID) } func newTopic() Topic { diff --git a/core/chains/evm/logpoller/helper_test.go b/core/chains/evm/logpoller/helper_test.go index c61d3d5fad..9e48690a24 100644 --- a/core/chains/evm/logpoller/helper_test.go +++ b/core/chains/evm/logpoller/helper_test.go @@ -19,12 +19,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -46,7 +46,7 @@ type TestHarness struct { } func SetupTH(t testing.TB, useFinalityTag bool, finalityDepth, backfillBatchSize, rpcBatchSize, keepFinalizedBlocksDepth int64) TestHarness { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) chainID := testutils.NewRandomEVMChainID() chainID2 := testutils.NewRandomEVMChainID() db := pgtest.NewSqlxDB(t) diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index bb93db4037..7c4ea66cec 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -20,11 +20,11 @@ import ( "github.com/pkg/errors" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" @@ -136,7 +136,7 @@ func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, pollPeriod time.Durati cancel: cancel, ec: ec, orm: orm, - lggr: lggr.Named("LogPoller"), + lggr: logger.Named(lggr, "LogPoller"), replayStart: make(chan int64), replayComplete: make(chan error), pollPeriod: pollPeriod, @@ -661,7 +661,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } } if batchSize == 1 { - lp.lggr.Criticalw("Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) + logger.Criticalw(lp.lggr, "Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) return err } batchSize /= 2 @@ -916,7 +916,7 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He return nil, err } } - lp.lggr.Criticalw("Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) + logger.Criticalw(lp.lggr, "Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) rerr := errors.New("Reorg greater than finality depth") lp.SvcErrBuffer.Append(rerr) return nil, rerr diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index 2ef276802b..e3ba8b655e 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -20,13 +20,14 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -55,7 +56,7 @@ func TestLogPoller_RegisterFilter(t *testing.T) { a1 := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbb") a2 := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbc") - lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zapcore.ErrorLevel) chainID := testutils.NewRandomEVMChainID() db := pgtest.NewSqlxDB(t) @@ -137,7 +138,7 @@ func TestLogPoller_RegisterFilter(t *testing.T) { func TestLogPoller_ConvertLogs(t *testing.T) { t.Parallel() - lggr := logger.TestLogger(t) + lggr := logger.Test(t) topics := []common.Hash{EmitterABI.Events["Log1"].ID} @@ -192,7 +193,7 @@ func TestFilterName(t *testing.T) { func TestLogPoller_BackupPollerStartup(t *testing.T) { addr := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbc") - lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zapcore.WarnLevel) chainID := testutils.FixtureChainID db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) @@ -235,7 +236,7 @@ func TestLogPoller_Replay(t *testing.T) { t.Parallel() addr := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbc") - lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zapcore.ErrorLevel) chainID := testutils.FixtureChainID db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) @@ -437,7 +438,7 @@ func (lp *logPoller) reset() { } func Test_latestBlockAndFinalityDepth(t *testing.T) { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) chainID := testutils.FixtureChainID db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) @@ -507,7 +508,7 @@ func Test_latestBlockAndFinalityDepth(t *testing.T) { } func benchmarkFilter(b *testing.B, nFilters, nAddresses, nEvents int) { - lggr := logger.TestLogger(b) + lggr := logger.Test(b) lp := NewLogPoller(nil, nil, lggr, 1*time.Hour, false, 2, 3, 2, 1000) for i := 0; i < nFilters; i++ { var addresses []common.Address diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 94589f505a..82447bdb5f 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -26,6 +26,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -34,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -86,7 +86,7 @@ func populateDatabase(t testing.TB, o *logpoller.DbORM, chainID *big.Int) (commo func BenchmarkSelectLogsCreatedAfter(b *testing.B) { chainId := big.NewInt(137) _, db := heavyweight.FullTestDBV2(b, nil) - o := logpoller.NewORM(chainId, db, logger.TestLogger(b), pgtest.NewQConfig(false)) + o := logpoller.NewORM(chainId, db, logger.Test(b), pgtest.NewQConfig(false)) event, address, _ := populateDatabase(b, o, chainId) // Setting searchDate to pick around 5k logs @@ -106,7 +106,7 @@ func TestPopulateLoadedDB(t *testing.T) { _, db := heavyweight.FullTestDBV2(t, nil) chainID := big.NewInt(137) - o := logpoller.NewORM(big.NewInt(137), db, logger.TestLogger(t), pgtest.NewQConfig(true)) + o := logpoller.NewORM(big.NewInt(137), db, logger.Test(t), pgtest.NewQConfig(true)) event1, address1, address2 := populateDatabase(t, o, chainID) func() { @@ -651,7 +651,7 @@ func TestLogPoller_SynchronizedWithGeth(t *testing.T) { p := gopter.NewProperties(testParams) numChainInserts := 3 finalityDepth := 5 - lggr := logger.TestLogger(t) + lggr := logger.Test(t) db := pgtest.NewSqlxDB(t) owner := testutils.MustNewSimTransactor(t) @@ -1264,7 +1264,7 @@ func TestGetReplayFromBlock(t *testing.T) { func TestLogPoller_DBErrorHandling(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.WarnLevel) + lggr, observedLogs := logger.TestObserved(t, zapcore.WarnLevel) chainID1 := testutils.NewRandomEVMChainID() chainID2 := testutils.NewRandomEVMChainID() db := pgtest.NewSqlxDB(t) @@ -1332,7 +1332,7 @@ func TestNotifyAfterInsert(t *testing.T) { dbURL = s.Database.URL.URL().String() }) - lggr, _ := logger.TestLoggerObserved(t, zapcore.WarnLevel) + lggr, _ := logger.TestObserved(t, zapcore.WarnLevel) chainID := big.NewInt(1337) o := logpoller.NewORM(chainID, sqlxDB, lggr, pgtest.NewQConfig(true)) @@ -1386,7 +1386,7 @@ type getLogErrData struct { func TestTooManyLogResults(t *testing.T) { ctx := testutils.Context(t) ec := evmtest.NewEthClientMockWithDefaultChain(t) - lggr, obs := logger.TestLoggerObserved(t, zapcore.DebugLevel) + lggr, obs := logger.TestObserved(t, zapcore.DebugLevel) chainID := testutils.NewRandomEVMChainID() db := pgtest.NewSqlxDB(t) o := logpoller.NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) diff --git a/core/chains/evm/logpoller/observability.go b/core/chains/evm/logpoller/observability.go index 03f4b77be2..9826d503b9 100644 --- a/core/chains/evm/logpoller/observability.go +++ b/core/chains/evm/logpoller/observability.go @@ -9,7 +9,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) diff --git a/core/chains/evm/logpoller/observability_test.go b/core/chains/evm/logpoller/observability_test.go index ded3d7854d..83bd60a556 100644 --- a/core/chains/evm/logpoller/observability_test.go +++ b/core/chains/evm/logpoller/observability_test.go @@ -14,9 +14,9 @@ import ( "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -97,7 +97,7 @@ func TestMetricsAreProperlyPopulatedForWrites(t *testing.T) { } func createObservedORM(t *testing.T, chainId int64) *ObservedORM { - lggr, _ := logger.TestLoggerObserved(t, zapcore.ErrorLevel) + lggr, _ := logger.TestObserved(t, zapcore.ErrorLevel) db := pgtest.NewSqlxDB(t) return NewObservedORM( big.NewInt(chainId), db, lggr, pgtest.NewQConfig(true), diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index a1b86d2cb2..c6134ed4b6 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -11,7 +11,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -61,7 +61,7 @@ type DbORM struct { // NewORM creates a DbORM scoped to chainID. func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *DbORM { - namedLogger := lggr.Named("Configs") + namedLogger := logger.Named(lggr, "Configs") q := pg.NewQ(db, namedLogger, cfg) return &DbORM{ chainID: chainID, diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 887984055e..e55ebeccec 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -14,12 +14,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -1314,7 +1314,7 @@ func TestInsertLogsWithBlock(t *testing.T) { // Using pgtest.NewSqlxDB(t) will run all tests in TXs which is not desired for this type of test // (inner tx rollback will rollback outer tx, blocking rest of execution) _, db := heavyweight.FullTestDBV2(t, nil) - o := logpoller.NewORM(chainID, db, logger.TestLogger(t), pgtest.NewQConfig(true)) + o := logpoller.NewORM(chainID, db, logger.Test(t), pgtest.NewQConfig(true)) correctLog := GenLog(chainID, 1, 1, utils.RandomAddress().String(), event[:], address) invalidLog := GenLog(chainID, -10, -10, utils.RandomAddress().String(), event[:], address) @@ -1390,7 +1390,7 @@ func TestInsertLogsInTx(t *testing.T) { // We need full db here, because we want to test transaction rollbacks. _, db := heavyweight.FullTestDBV2(t, nil) - o := logpoller.NewORM(chainID, db, logger.TestLogger(t), pgtest.NewQConfig(true)) + o := logpoller.NewORM(chainID, db, logger.Test(t), pgtest.NewQConfig(true)) logs := make([]logpoller.Log, maxLogsSize, maxLogsSize+1) for i := 0; i < maxLogsSize; i++ { diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index b12346ac00..c3b9a49c7a 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -13,13 +13,13 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -51,11 +51,11 @@ type ( var _ BalanceMonitor = (*balanceMonitor)(nil) // NewBalanceMonitor returns a new balanceMonitor -func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keystore.Eth, logger logger.Logger) *balanceMonitor { +func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keystore.Eth, lggr logger.Logger) *balanceMonitor { chainId := ethClient.ConfiguredChainID() bm := &balanceMonitor{ services.StateMachine{}, - logger.Named("BalanceMonitor"), + logger.Named(lggr, "BalanceMonitor"), ethClient, chainId, chainId.String(), @@ -119,7 +119,8 @@ func (bm *balanceMonitor) updateBalance(ethBal assets.Eth, address gethCommon.Ad bm.ethBalances[address] = ðBal bm.ethBalancesMtx.Unlock() - lgr := bm.logger.Named("BalanceLog").With( + lgr := logger.Named(bm.logger, "BalanceLog") + lgr = logger.With(lgr, "address", address.Hex(), "ethBalance", ethBal.String(), "weiBalance", ethBal.ToInt()) diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index 6a62549e49..c2c976e78d 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" @@ -20,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) var nilBigInt *big.Int @@ -43,7 +43,7 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore) _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) - bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) + bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) defer func() { assert.NoError(t, bm.Close()) }() k0bal := big.NewInt(42) @@ -71,7 +71,7 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) - bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) + bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) defer func() { assert.NoError(t, bm.Close()) }() k0bal := big.NewInt(42) @@ -91,7 +91,7 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) - bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) + bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) defer func() { assert.NoError(t, bm.Close()) }() ctxCancelledAwaiter := cltest.NewAwaiter() @@ -121,7 +121,7 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) - bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) + bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) defer func() { assert.NoError(t, bm.Close()) }() ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt). @@ -149,7 +149,7 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore) - bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) + bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) k0bal := big.NewInt(42) // Deliberately larger than a 64 bit unsigned integer to test overflow k1bal := big.NewInt(0) @@ -201,7 +201,7 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { ethClient := newEthClientMock(t) - bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) + bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything). Once(). Return(big.NewInt(1), nil) diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index 06c1126b86..37626f4550 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -9,13 +9,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type TxAttemptSigner[ADDR commontypes.Hashable] interface { diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index 11304384ab..131115e6fa 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" @@ -21,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" ) @@ -93,7 +93,7 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { kst := ksmocks.NewEth(t) kst.On("SignTx", addr, mock.Anything, big.NewInt(1)).Return(tx, nil) var n evmtypes.Nonce - lggr := logger.TestLogger(t) + lggr := logger.Test(t) t.Run("creates attempt with fields", func(t *testing.T) { feeCfg := newFeeConfig() @@ -165,7 +165,7 @@ func TestTxm_NewLegacyAttempt(t *testing.T) { gc.priceMin = assets.NewWeiI(10) gc.priceMax = assets.NewWeiI(50) cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), gc, kst, nil) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) t.Run("creates attempt with fields", func(t *testing.T) { var n evmtypes.Nonce @@ -189,7 +189,7 @@ func TestTxm_NewCustomTxAttempt_NonRetryableErrors(t *testing.T) { t.Parallel() kst := ksmocks.NewEth(t) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), newFeeConfig(), kst, nil) dynamicFee := gas.DynamicFee{TipCap: assets.GWei(100), FeeCap: assets.GWei(200)} @@ -222,7 +222,7 @@ func TestTxm_EvmTxAttemptBuilder_RetryableEstimatorError(t *testing.T) { est.On("BumpFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint32(0), errors.New("fail")) kst := ksmocks.NewEth(t) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ctx := testutils.Context(t) cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), &feeConfig{eip1559DynamicFees: true}, kst, est) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 43f2fdb8ca..93b1093e79 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -22,7 +22,9 @@ import ( "go.uber.org/zap/zapcore" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -40,7 +42,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" @@ -60,7 +61,7 @@ func NewTestEthBroadcaster( t.Helper() ctx := testutils.Context(t) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) @@ -94,7 +95,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { ethKeyStore, txBuilder, nil, - logger.TestLogger(t), + logger.Test(t), &testCheckerFactory{}, false, ) @@ -152,7 +153,7 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) ethKeyStore, txBuilder, nil, - logger.TestLogger(t), + logger.Test(t), &testCheckerFactory{}, false, ) @@ -625,7 +626,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ethKeyStore, txBuilder, nil, - logger.TestLogger(t), + logger.Test(t), &testCheckerFactory{}, false, ) @@ -1132,7 +1133,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // same as the parent test, but callback is set by ctor t.Run("callback set by ctor", func(t *testing.T) { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) localNextNonce = getLocalNextNonce(t, eb, fromAddress) @@ -1744,7 +1745,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { db := pgtest.NewSqlxDB(t) ctx := testutils.Context(t) - lggr, observed := logger.TestLoggerObserved(t, zapcore.DebugLevel) + lggr, observed := logger.TestObserved(t, zapcore.DebugLevel) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(true) }) diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 5e3d61301c..84aa21e4de 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -6,6 +6,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -14,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) diff --git a/core/chains/evm/txmgr/client.go b/core/chains/evm/txmgr/client.go index 8789f5f173..d08274f74b 100644 --- a/core/chains/evm/txmgr/client.go +++ b/core/chains/evm/txmgr/client.go @@ -13,11 +13,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -62,7 +62,7 @@ func (c *evmTxmClient) BatchSendTransactions( if len(reqs) != len(attempts) { lenErr := fmt.Errorf("Returned request data length (%d) != number of tx attempts (%d)", len(reqs), len(attempts)) err = errors.Join(err, lenErr) - lggr.Criticalw("Mismatched length", "err", err) + logger.Criticalw(lggr, "Mismatched length", "err", err) return } @@ -91,7 +91,7 @@ func (c *evmTxmClient) BatchSendTransactions( func (c *evmTxmClient) SendTransactionReturnCode(ctx context.Context, etx Tx, attempt TxAttempt, lggr logger.Logger) (commonclient.SendTxReturnCode, error) { signedTx, err := GetGethSignedTx(attempt.SignedRawTx) if err != nil { - lggr.Criticalw("Fatal error signing transaction", "err", err, "etx", etx) + logger.Criticalw(lggr, "Fatal error signing transaction", "err", err, "etx", etx) return commonclient.Fatal, err } return c.client.SendTransactionReturnCode(ctx, signedTx, etx.FromAddress) diff --git a/core/chains/evm/txmgr/common.go b/core/chains/evm/txmgr/common.go index 37cc89dd7a..1956476f8d 100644 --- a/core/chains/evm/txmgr/common.go +++ b/core/chains/evm/txmgr/common.go @@ -10,8 +10,8 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) // Tries to send transactions in batches. Even if some batch(es) fail to get sent, it tries all remaining batches, diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index f5889b0664..84c42cd00f 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -36,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" @@ -121,7 +121,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertRandomKey(t, ethKeyStore) estimator := gasmocks.NewEvmEstimator(t) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ge := config.EVM().GasEstimator() feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) @@ -1353,7 +1353,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmOtherAddress := otherAddress - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -1619,7 +1619,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing.T) { t.Parallel() - lggr := logger.TestLogger(t) + lggr := logger.Test(t) db := pgtest.NewSqlxDB(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -3074,7 +3074,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { func ptr[T any](t T) *T { return &t } func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 84fe9a02c6..2788c2fd1c 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -18,6 +18,7 @@ import ( pkgerrors "github.com/pkg/errors" nullv4 "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -333,7 +333,7 @@ func NewTxStore( lggr logger.Logger, cfg pg.QConfig, ) *evmTxStore { - namedLogger := lggr.Named("TxmStore") + namedLogger := logger.Named(lggr, "TxmStore") ctx, cancel := context.WithCancel(context.Background()) q := pg.NewQ(db, namedLogger, cfg, pg.WithParentCtx(ctx)) return &evmTxStore{ @@ -1371,7 +1371,7 @@ GROUP BY e.id txHashesHex[i] = common.BytesToAddress(r.TxHashes[i]) } - o.logger.Criticalw(fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ + logger.Criticalw(o.logger, fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ "Current block height is %v, transaction was broadcast before block height %v. This transaction may not have not been sent and will be marked as fatally errored. "+ "This can happen if there is another instance of chainlink running that is using the same private key, or if "+ "an external wallet has been used to send a transaction from account %s with nonce %v."+ diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 15417a4309..d2cafcb8ef 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/logger" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -18,7 +19,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -1117,7 +1117,7 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 3, 9, time.Now(), fromAddress) etx.TxAttempts = []txmgr.TxAttempt{} - q := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) + q := pg.NewQ(db, logger.Test(t), cfg.Database()) newAttempt := cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) var dbAttempt txmgr.DbEthTxAttempt @@ -1258,7 +1258,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - q := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) + q := pg.NewQ(db, logger.Test(t), cfg.Database()) nonce := evmtypes.Nonce(123) t.Run("update successful", func(t *testing.T) { @@ -1293,7 +1293,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { txStore = cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore = cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - q = pg.NewQ(db, logger.TestLogger(t), cfg.Database()) + q = pg.NewQ(db, logger.Test(t), cfg.Database()) t.Run("update replaces abandoned tx with same hash", func(t *testing.T) { etx := mustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) @@ -1309,7 +1309,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { ccfg := evmtest.NewChainScopedConfig(t, evmCfg) evmTxmCfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ec := evmtest.NewEthClientMockWithDefaultChain(t) - txMgr := txmgr.NewEvmTxm(ec.ConfiguredChainID(), evmTxmCfg, ccfg.EVM().Transactions(), nil, logger.TestLogger(t), nil, nil, + txMgr := txmgr.NewEvmTxm(ec.ConfiguredChainID(), evmTxmCfg, ccfg.EVM().Transactions(), nil, logger.Test(t), nil, nil, nil, txStore, nil, nil, nil, nil) err := txMgr.XXXTestAbandon(fromAddress) // mark transaction as abandoned require.NoError(t, err) diff --git a/core/chains/evm/txmgr/nonce_syncer.go b/core/chains/evm/txmgr/nonce_syncer.go index dc0d27e641..2936736b3b 100644 --- a/core/chains/evm/txmgr/nonce_syncer.go +++ b/core/chains/evm/txmgr/nonce_syncer.go @@ -8,10 +8,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/txmgr" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) // NonceSyncer manages the delicate task of syncing the local nonce with the @@ -61,7 +61,7 @@ func NewNonceSyncer( lggr logger.Logger, ethClient evmclient.Client, ) NonceSyncer { - lggr = lggr.Named("NonceSyncer") + lggr = logger.Named(lggr, "NonceSyncer") return &nonceSyncerImpl{ txStore: txStore, client: NewEvmTxmClient(ethClient), diff --git a/core/chains/evm/txmgr/nonce_syncer_test.go b/core/chains/evm/txmgr/nonce_syncer_test.go index f6480b4c30..f757b8863d 100644 --- a/core/chains/evm/txmgr/nonce_syncer_test.go +++ b/core/chains/evm/txmgr/nonce_syncer_test.go @@ -3,6 +3,7 @@ package txmgr_test import ( "testing" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -10,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -30,7 +30,7 @@ func Test_NonceSyncer_Sync(t *testing.T) { _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) + ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), errors.New("something exploded")) _, err := ns.Sync(testutils.Context(t), from, types.Nonce(0)) @@ -50,7 +50,7 @@ func Test_NonceSyncer_Sync(t *testing.T) { _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) + ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), nil) @@ -72,7 +72,7 @@ func Test_NonceSyncer_Sync(t *testing.T) { _, fromAddress := cltest.RandomKey{Nonce: 32}.MustInsert(t, ks) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) + ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) // Used to mock the chain nonce ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(5), nil) @@ -97,7 +97,7 @@ func Test_NonceSyncer_Sync(t *testing.T) { key1LocalNonce := types.Nonce(0) key2LocalNonce := types.Nonce(32) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) + ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) // Used to mock the chain nonce ethClient.On("PendingNonceAt", mock.Anything, key1).Return(uint64(5), nil).Once() diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 67216c9fd1..2da8e7a93c 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -8,18 +8,18 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" txmgrmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) func newReaperWithChainID(t *testing.T, db txmgrtypes.TxHistoryReaper[*big.Int], cfg txmgrtypes.ReaperChainConfig, txConfig txmgrtypes.ReaperTransactionsConfig, cid *big.Int) *txmgr.Reaper { - return txmgr.NewEvmReaper(logger.TestLogger(t), db, cfg, txConfig, cid) + return txmgr.NewEvmReaper(logger.Test(t), db, cfg, txConfig, cid) } func newReaper(t *testing.T, db txmgrtypes.TxHistoryReaper[*big.Int], cfg txmgrtypes.ReaperChainConfig, txConfig txmgrtypes.ReaperTransactionsConfig) *txmgr.Reaper { diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index cc94511e3b..d2eefdece5 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -20,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -31,7 +31,7 @@ func Test_EthResender_resendUnconfirmed(t *testing.T) { db := pgtest.NewSqlxDB(t) logCfg := pgtest.NewQConfig(true) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {}) @@ -102,7 +102,7 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { db := pgtest.NewSqlxDB(t) logCfg := pgtest.NewQConfig(true) - lggr, o := logger.TestLoggerObserved(t, zapcore.DebugLevel) + lggr, o := logger.TestObserved(t, zapcore.DebugLevel) ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) // Set this to the smallest non-zero value possible for the attempt to be eligible for resend @@ -152,7 +152,7 @@ func Test_EthResender_Start(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ccfg := evmtest.NewChainScopedConfig(t, cfg) _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - lggr := logger.TestLogger(t) + lggr := logger.Test(t) t.Run("resends transactions that have been languishing unconfirmed for too long", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) diff --git a/core/chains/evm/txmgr/transmitchecker.go b/core/chains/evm/txmgr/transmitchecker.go index eb6edd3f58..f210934adb 100644 --- a/core/chains/evm/txmgr/transmitchecker.go +++ b/core/chains/evm/txmgr/transmitchecker.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -20,7 +21,6 @@ import ( v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" v2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) @@ -147,7 +147,7 @@ func (s *SimulateChecker) Check( err := s.Client.CallContext(ctx, &b, "eth_call", callArg, evmclient.ToBlockNumArg(nil)) if err != nil { if jErr := evmclient.ExtractRPCErrorOrNil(err); jErr != nil { - l.Criticalw("Transaction reverted during simulation", + logger.Criticalw(l, "Transaction reverted during simulation", "ethTxAttemptID", a.ID, "txHash", a.Hash, "err", err, "rpcErr", jErr.String(), "returnValue", b.String()) return errors.Errorf("transaction reverted during simulation: %s", jErr.String()) } diff --git a/core/chains/evm/txmgr/transmitchecker_test.go b/core/chains/evm/txmgr/transmitchecker_test.go index 5ebf5f32e3..6dd4edd91c 100644 --- a/core/chains/evm/txmgr/transmitchecker_test.go +++ b/core/chains/evm/txmgr/transmitchecker_test.go @@ -15,6 +15,8 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/mock" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -29,7 +31,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestFactory(t *testing.T) { @@ -105,7 +106,7 @@ func TestFactory(t *testing.T) { func TestTransmitCheckers(t *testing.T) { client := evmtest.NewEthClientMockWithDefaultChain(t) - log := logger.TestLogger(t) + log := logger.Test(t) ctx := testutils.Context(t) t.Run("no checker", func(t *testing.T) { diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index bab18f445b..f82bc991d5 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -20,6 +20,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/logger" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" @@ -36,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -45,7 +45,7 @@ import ( func makeTestEvmTxm( t *testing.T, db *sqlx.DB, ethClient evmclient.Client, estimator gas.EvmFeeEstimator, ccfg txmgr.ChainConfig, fcfg txmgr.FeeConfig, txConfig evmconfig.Transactions, dbConfig txmgr.DatabaseConfig, listenerConfig txmgr.ListenerConfig, keyStore keystore.Eth) (txmgr.TxManager, error) { - lggr := logger.TestLogger(t) + lggr := logger.Test(t) lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), ethClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) // logic for building components (from evm/evm_txm.go) ------- @@ -83,7 +83,7 @@ func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) { keyStore := cltest.NewKeyStore(t, db, dbConfig).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) + estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keyStore) require.NoError(t, err) @@ -109,7 +109,7 @@ func TestTxm_CreateTransaction(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) + estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth()) require.NoError(t, err) @@ -298,7 +298,7 @@ func TestTxm_CreateTransaction(t *testing.T) { evmConfig.MaxQueued = uint64(1) // Create mock forwarder, mock authorizedsenders call. - form := forwarders.NewORM(db, logger.TestLogger(t), cfg.Database()) + form := forwarders.NewORM(db, logger.Test(t), cfg.Database()) fwdrAddr := testutils.NewAddress() fwdr, err := form.CreateForwarder(fwdrAddr, utils.Big(cltest.FixtureChainID)) require.NoError(t, err) @@ -391,7 +391,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) + estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), etKeyStore) require.NoError(t, err) @@ -482,7 +482,7 @@ func TestTxm_Lifecycle(t *testing.T) { keyChangeCh := make(chan struct{}) unsub := cltest.NewAwaiter() kst.On("SubscribeToKeyChanges").Return(keyChangeCh, unsub.ItHappened) - estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) + estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst) require.NoError(t, err) @@ -535,7 +535,7 @@ func TestTxm_Reset(t *testing.T) { ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil) ethClient.On("BatchCallContextAll", mock.Anything, mock.Anything).Return(nil).Maybe() - estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) + estimator := gas.NewEstimator(logger.Test(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), cfg.Database(), cfg.Database().Listener(), kst.Eth()) require.NoError(t, err) @@ -576,7 +576,7 @@ func TestTxm_Reset(t *testing.T) { } func newTxStore(t *testing.T, db *sqlx.DB, cfg pg.QConfig) txmgr.EvmTxStore { - return txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + return txmgr.NewTxStore(db, logger.Test(t), cfg) } func newEthReceipt(blockNumber int64, blockHash common.Hash, txHash common.Hash, status uint64) txmgr.Receipt { diff --git a/core/chains/evm/chain.go b/core/chains/legacyevm/chain.go similarity index 99% rename from core/chains/evm/chain.go rename to core/chains/legacyevm/chain.go index 1e52bed5cb..0c35d929fc 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -1,4 +1,4 @@ -package evm +package legacyevm import ( "context" diff --git a/core/chains/evm/chain_test.go b/core/chains/legacyevm/chain_test.go similarity index 80% rename from core/chains/evm/chain_test.go rename to core/chains/legacyevm/chain_test.go index f25af87a35..4fcd51c39d 100644 --- a/core/chains/evm/chain_test.go +++ b/core/chains/legacyevm/chain_test.go @@ -1,4 +1,4 @@ -package evm_test +package legacyevm_test import ( "math/big" @@ -8,8 +8,8 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -17,13 +17,13 @@ import ( ) func TestLegacyChains(t *testing.T) { - evmCfg := configtest.NewGeneralConfig(t, nil) + legacyevmCfg := configtest.NewGeneralConfig(t, nil) c := mocks.NewChain(t) c.On("ID").Return(big.NewInt(7)) - m := map[string]evm.Chain{c.ID().String(): c} + m := map[string]legacyevm.Chain{c.ID().String(): c} - l := evm.NewLegacyChains(m, evmCfg.EVMConfigs()) + l := legacyevm.NewLegacyChains(m, legacyevmCfg.EVMConfigs()) assert.NotNil(t, l.ChainNodeConfigs()) got, err := l.Get(c.ID().String()) assert.NoError(t, err) @@ -33,7 +33,7 @@ func TestLegacyChains(t *testing.T) { func TestChainOpts_Validate(t *testing.T) { type fields struct { - AppConfig evm.AppConfig + AppConfig legacyevm.AppConfig EventBroadcaster pg.EventBroadcaster MailMon *utils.MailboxMonitor DB *sqlx.DB @@ -65,7 +65,7 @@ func TestChainOpts_Validate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - o := evm.ChainOpts{ + o := legacyevm.ChainOpts{ AppConfig: tt.fields.AppConfig, EventBroadcaster: tt.fields.EventBroadcaster, MailMon: tt.fields.MailMon, diff --git a/core/chains/evm/evm_txm.go b/core/chains/legacyevm/evm_txm.go similarity index 99% rename from core/chains/evm/evm_txm.go rename to core/chains/legacyevm/evm_txm.go index bfc0f6378b..1606ea1b24 100644 --- a/core/chains/evm/evm_txm.go +++ b/core/chains/legacyevm/evm_txm.go @@ -1,4 +1,4 @@ -package evm +package legacyevm import ( "fmt" diff --git a/core/chains/evm/mocks/chain.go b/core/chains/legacyevm/mocks/chain.go similarity index 100% rename from core/chains/evm/mocks/chain.go rename to core/chains/legacyevm/mocks/chain.go diff --git a/core/chains/evm/mocks/legacy_chain_container.go b/core/chains/legacyevm/mocks/legacy_chain_container.go similarity index 73% rename from core/chains/evm/mocks/legacy_chain_container.go rename to core/chains/legacyevm/mocks/legacy_chain_container.go index 9180a8a2fc..9ebacb890a 100644 --- a/core/chains/evm/mocks/legacy_chain_container.go +++ b/core/chains/legacyevm/mocks/legacy_chain_container.go @@ -3,7 +3,7 @@ package mocks import ( - evm "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + legacyevm "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -31,19 +31,19 @@ func (_m *LegacyChainContainer) ChainNodeConfigs() types.Configs { } // Get provides a mock function with given fields: id -func (_m *LegacyChainContainer) Get(id string) (evm.Chain, error) { +func (_m *LegacyChainContainer) Get(id string) (legacyevm.Chain, error) { ret := _m.Called(id) - var r0 evm.Chain + var r0 legacyevm.Chain var r1 error - if rf, ok := ret.Get(0).(func(string) (evm.Chain, error)); ok { + if rf, ok := ret.Get(0).(func(string) (legacyevm.Chain, error)); ok { return rf(id) } - if rf, ok := ret.Get(0).(func(string) evm.Chain); ok { + if rf, ok := ret.Get(0).(func(string) legacyevm.Chain); ok { r0 = rf(id) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(evm.Chain) + r0 = ret.Get(0).(legacyevm.Chain) } } @@ -71,7 +71,7 @@ func (_m *LegacyChainContainer) Len() int { } // List provides a mock function with given fields: ids -func (_m *LegacyChainContainer) List(ids ...string) ([]evm.Chain, error) { +func (_m *LegacyChainContainer) List(ids ...string) ([]legacyevm.Chain, error) { _va := make([]interface{}, len(ids)) for _i := range ids { _va[_i] = ids[_i] @@ -80,16 +80,16 @@ func (_m *LegacyChainContainer) List(ids ...string) ([]evm.Chain, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) - var r0 []evm.Chain + var r0 []legacyevm.Chain var r1 error - if rf, ok := ret.Get(0).(func(...string) ([]evm.Chain, error)); ok { + if rf, ok := ret.Get(0).(func(...string) ([]legacyevm.Chain, error)); ok { return rf(ids...) } - if rf, ok := ret.Get(0).(func(...string) []evm.Chain); ok { + if rf, ok := ret.Get(0).(func(...string) []legacyevm.Chain); ok { r0 = rf(ids...) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]evm.Chain) + r0 = ret.Get(0).([]legacyevm.Chain) } } @@ -103,15 +103,15 @@ func (_m *LegacyChainContainer) List(ids ...string) ([]evm.Chain, error) { } // Slice provides a mock function with given fields: -func (_m *LegacyChainContainer) Slice() []evm.Chain { +func (_m *LegacyChainContainer) Slice() []legacyevm.Chain { ret := _m.Called() - var r0 []evm.Chain - if rf, ok := ret.Get(0).(func() []evm.Chain); ok { + var r0 []legacyevm.Chain + if rf, ok := ret.Get(0).(func() []legacyevm.Chain); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]evm.Chain) + r0 = ret.Get(0).([]legacyevm.Chain) } } diff --git a/core/cmd/shell.go b/core/cmd/shell.go index b82bd85e3e..35659aa779 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -34,7 +34,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/build" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" @@ -166,7 +166,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G evmFactoryCfg := chainlink.EVMFactoryConfig{ CSAETHKeystore: keyStore, - ChainOpts: evm.ChainOpts{AppConfig: cfg, EventBroadcaster: eventBroadcaster, MailMon: mailMon, DB: db}, + ChainOpts: legacyevm.ChainOpts{AppConfig: cfg, EventBroadcaster: eventBroadcaster, MailMon: mailMon, DB: db}, } // evm always enabled for backward compatibility // TODO BCF-2510 this needs to change in order to clear the path for EVM extraction diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 2dc182944d..1e030fa9e9 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -9,7 +9,7 @@ import ( "time" "github.com/smartcontractkit/chainlink/v2/common/client" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/cmd" cmdMocks "github.com/smartcontractkit/chainlink/v2/core/cmd/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -39,7 +39,7 @@ import ( "github.com/urfave/cli" ) -func genTestEVMRelayers(t *testing.T, opts evm.ChainRelayExtenderConfig, ks evmrelayer.CSAETHKeystore) *chainlink.CoreRelayerChainInteroperators { +func genTestEVMRelayers(t *testing.T, opts legacyevm.ChainRelayExtenderConfig, ks evmrelayer.CSAETHKeystore) *chainlink.CoreRelayerChainInteroperators { f := chainlink.RelayerFactory{ Logger: opts.Logger, LoopRegistry: plugins.NewLoopRegistry(opts.Logger, opts.AppConfig.Tracing()), @@ -83,10 +83,10 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { lggr := logger.TestLogger(t) - opts := evm.ChainRelayExtenderConfig{ + opts := legacyevm.ChainRelayExtenderConfig{ Logger: lggr, KeyStore: keyStore.Eth(), - ChainOpts: evm.ChainOpts{ + ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), MailMon: &utils.MailboxMonitor{}, @@ -188,10 +188,10 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(10), nil).Maybe() lggr := logger.TestLogger(t) - opts := evm.ChainRelayExtenderConfig{ + opts := legacyevm.ChainRelayExtenderConfig{ Logger: lggr, KeyStore: keyStore.Eth(), - ChainOpts: evm.ChainOpts{ + ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), MailMon: &utils.MailboxMonitor{}, diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index b1431bf059..17a1d4fadd 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -44,7 +44,6 @@ import ( commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -52,6 +51,7 @@ import ( httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -173,7 +173,7 @@ type JobPipelineConfig interface { MaxSuccessfulRuns() uint64 } -func NewJobPipelineV2(t testing.TB, cfg pipeline.BridgeConfig, jpcfg JobPipelineConfig, dbCfg pg.QConfig, legacyChains evm.LegacyChainContainer, db *sqlx.DB, keyStore keystore.Master, restrictedHTTPClient, unrestrictedHTTPClient *http.Client) JobPipelineV2TestHelper { +func NewJobPipelineV2(t testing.TB, cfg pipeline.BridgeConfig, jpcfg JobPipelineConfig, dbCfg pg.QConfig, legacyChains legacyevm.LegacyChainContainer, db *sqlx.DB, keyStore keystore.Master, restrictedHTTPClient, unrestrictedHTTPClient *http.Client) JobPipelineV2TestHelper { lggr := logger.TestLogger(t) prm := pipeline.NewORM(db, lggr, dbCfg, jpcfg.MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, dbCfg) @@ -349,7 +349,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn } evmOpts := chainlink.EVMFactoryConfig{ - ChainOpts: evm.ChainOpts{ + ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: eventBroadcaster, MailMon: mailMon, diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 540924d7f0..d49e94557e 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -13,10 +13,10 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -397,7 +397,7 @@ func (m MockPasswordPrompter) Prompt() string { return m.Password } -func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg evm.AppConfig) evm.LegacyChainContainer { +func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg legacyevm.AppConfig) legacyevm.LegacyChainContainer { ch := new(evmmocks.Chain) ch.On("Client").Return(ethClient) ch.On("Logger").Return(logger.TestLogger(t)) @@ -409,7 +409,7 @@ func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg } -func NewLegacyChainsWithChain(ch evm.Chain, cfg evm.AppConfig) evm.LegacyChainContainer { - m := map[string]evm.Chain{ch.ID().String(): ch} - return evm.NewLegacyChains(m, cfg.EVMConfigs()) +func NewLegacyChainsWithChain(ch legacyevm.Chain, cfg legacyevm.AppConfig) legacyevm.LegacyChainContainer { + m := map[string]legacyevm.Chain{ch.ID().String(): ch} + return legacyevm.NewLegacyChains(m, cfg.EVMConfigs()) } diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 7674650c01..423615145e 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -19,7 +19,6 @@ import ( commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -30,6 +29,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -40,7 +40,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func NewChainScopedConfig(t testing.TB, cfg evm.AppConfig) evmconfig.ChainScopedConfig { +func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.ChainScopedConfig { var evmCfg *evmtoml.EVMConfig if len(cfg.EVMConfigs()) > 0 { evmCfg = cfg.EVMConfigs()[0] @@ -60,7 +60,7 @@ type TestChainOpts struct { Client evmclient.Client LogBroadcaster log.Broadcaster LogPoller logpoller.LogPoller - GeneralConfig evm.AppConfig + GeneralConfig legacyevm.AppConfig HeadTracker httypes.HeadTracker DB *sqlx.DB TxManager txmgr.TxManager @@ -78,12 +78,12 @@ func NewChainRelayExtenders(t testing.TB, testopts TestChainOpts) *evmrelay.Chai return cc } -func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) evm.ChainRelayExtenderConfig { +func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainRelayExtenderConfig { require.NotNil(t, testopts.KeyStore) - opts := evm.ChainRelayExtenderConfig{ + opts := legacyevm.ChainRelayExtenderConfig{ Logger: logger.TestLogger(t), KeyStore: testopts.KeyStore, - ChainOpts: evm.ChainOpts{ + ChainOpts: legacyevm.ChainOpts{ AppConfig: testopts.GeneralConfig, EventBroadcaster: pg.NewNullEventBroadcaster(), MailMon: testopts.MailMon, @@ -138,7 +138,7 @@ func MustGetDefaultChainID(t testing.TB, evmCfgs evmtoml.EVMConfigs) *big.Int { } // Deprecated, this is a replacement function for tests for now removed default chain logic -func MustGetDefaultChain(t testing.TB, cc evm.LegacyChainContainer) evm.Chain { +func MustGetDefaultChain(t testing.TB, cc legacyevm.LegacyChainContainer) legacyevm.Chain { if len(cc.Slice()) == 0 { t.Fatalf("at least one evm chain container must be defined") } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 43840f93ce..d1795bbc84 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -304,7 +304,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index d8e682c742..cd7adf6bee 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1504,8 +1504,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 h1:HJCPvJ+ZjU9TSX4YD5rxBJqGAvqhDfzoJgI3WmfeWeI= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index 1a84323b6f..d6c27acd0b 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/trusted_blockhash_store" @@ -28,14 +28,14 @@ var _ job.ServiceCtx = &service{} // Delegate creates BlockhashStore feeder jobs. type Delegate struct { logger logger.Logger - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer ks keystore.Eth } // NewDelegate creates a new Delegate. func NewDelegate( logger logger.Logger, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, ks keystore.Eth, ) *Delegate { return &Delegate{ diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 011ab87ad6..0096ac5ca9 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -10,10 +10,10 @@ import ( "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -41,7 +41,7 @@ func TestDelegate_JobType(t *testing.T) { type testData struct { ethClient *mocks.Client ethKeyStore keystore.Eth - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer sendingKey ethkey.KeyV2 logs *observer.ObservedLogs } diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 3de42d7a9e..53f514cee2 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -9,7 +9,7 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -27,13 +27,13 @@ var _ job.ServiceCtx = &service{} type Delegate struct { logger logger.Logger - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer ks keystore.Eth } func NewDelegate( logger logger.Logger, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, ks keystore.Eth, ) *Delegate { return &Delegate{ diff --git a/core/services/chainlink/mocks/relayer_chain_interoperators.go b/core/services/chainlink/mocks/relayer_chain_interoperators.go index f778f61b0c..74dc9dc1d4 100644 --- a/core/services/chainlink/mocks/relayer_chain_interoperators.go +++ b/core/services/chainlink/mocks/relayer_chain_interoperators.go @@ -7,7 +7,7 @@ import ( services2 "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink-common/pkg/loop" @@ -19,12 +19,12 @@ import ( // FakeRelayerChainInteroperators is a fake chainlink.RelayerChainInteroperators. // This exists because mockery generation doesn't understand how to produce an alias instead of the underlying type (which is not exported in this case). type FakeRelayerChainInteroperators struct { - EVMChains evm.LegacyChainContainer + EVMChains legacyevm.LegacyChainContainer Nodes []types.NodeStatus NodesErr error } -func (f *FakeRelayerChainInteroperators) LegacyEVMChains() evm.LegacyChainContainer { +func (f *FakeRelayerChainInteroperators) LegacyEVMChains() legacyevm.LegacyChainContainer { return f.EVMChains } diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 3be1395694..673f71e3c6 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -13,7 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" "github.com/smartcontractkit/chainlink/v2/core/services/relay" @@ -46,7 +46,7 @@ type LoopRelayerStorer interface { // This will be deprecated/removed when products depend only // on the relayer interface. type LegacyChainer interface { - LegacyEVMChains() evm.LegacyChainContainer + LegacyEVMChains() legacyevm.LegacyChainContainer LegacyCosmosChains() LegacyCosmosContainer } @@ -106,14 +106,14 @@ func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfi return fmt.Errorf("failed to setup EVM relayer: %w", err2) } - legacyMap := make(map[string]evm.Chain) + legacyMap := make(map[string]legacyevm.Chain) for id, a := range adapters { // adapter is a service op.srvs = append(op.srvs, a) op.loopRelayers[id] = a legacyMap[id.ChainID] = a.Chain() } - op.legacyChains.EVMChains = evm.NewLegacyChains(legacyMap, config.AppConfig.EVMConfigs()) + op.legacyChains.EVMChains = legacyevm.NewLegacyChains(legacyMap, config.AppConfig.EVMConfigs()) return nil } } @@ -185,7 +185,7 @@ func (rs *CoreRelayerChainInteroperators) Get(id relay.ID) (loop.Relayer, error) // LegacyEVMChains returns a container with all the evm chains // TODO BCF-2511 -func (rs *CoreRelayerChainInteroperators) LegacyEVMChains() evm.LegacyChainContainer { +func (rs *CoreRelayerChainInteroperators) LegacyEVMChains() legacyevm.LegacyChainContainer { rs.mu.Lock() defer rs.mu.Unlock() return rs.legacyChains.EVMChains @@ -351,7 +351,7 @@ func (rs *CoreRelayerChainInteroperators) Services() (s []services.ServiceCtx) { // legacyChains encapsulates the chain-specific dependencies. Will be // deprecated when chain-specific logic is removed from products. type legacyChains struct { - EVMChains evm.LegacyChainContainer + EVMChains legacyevm.LegacyChainContainer CosmosChains LegacyCosmosContainer } diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index da1246c7bf..6a5445d9f2 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -16,7 +16,7 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -203,7 +203,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { {name: "2 evm chains with 3 nodes", initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ - ChainOpts: evm.ChainOpts{ + ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), MailMon: &utils.MailboxMonitor{}, @@ -277,7 +277,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Keystore: keyStore.Solana(), TOMLConfigs: cfg.SolanaConfigs()}), chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ - ChainOpts: evm.ChainOpts{ + ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), MailMon: &utils.MailboxMonitor{}, diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 6376839c70..c15643551e 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -18,7 +18,7 @@ import ( starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -35,7 +35,7 @@ type RelayerFactory struct { } type EVMFactoryConfig struct { - evm.ChainOpts + legacyevm.ChainOpts evmrelay.CSAETHKeystore } @@ -45,7 +45,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m relayers := make(map[relay.ID]evmrelay.LoopRelayAdapter) // override some common opts with the factory values. this seems weird... maybe other signatures should change, or this should take a different type... - ccOpts := evm.ChainRelayExtenderConfig{ + ccOpts := legacyevm.ChainRelayExtenderConfig{ Logger: r.Logger.Named("EVM"), KeyStore: config.CSAETHKeystore.Eth(), ChainOpts: config.ChainOpts, @@ -69,7 +69,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m CSAETHKeystore: config.CSAETHKeystore, EventBroadcaster: ccOpts.EventBroadcaster, } - relayer, err2 := evmrelay.NewRelayer(ccOpts.Logger.Named(relayID.ChainID), chain, relayerOpts) + relayer, err2 := evmrelay.NewRelayer(r.Logger.Named("EVM").Named(relayID.ChainID), chain, relayerOpts) if err2 != nil { err = errors.Join(err, err2) continue diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 687e1cea67..a21029ea17 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -12,9 +12,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -30,7 +30,7 @@ type ( pipelineRunner pipeline.Runner pipelineORM pipeline.ORM chHeads chan *evmtypes.Head - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer mailMon *utils.MailboxMonitor } @@ -46,7 +46,7 @@ func NewDelegate( logger logger.Logger, pipelineRunner pipeline.Runner, pipelineORM pipeline.ORM, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, mailMon *utils.MailboxMonitor, ) *Delegate { return &Delegate{ diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index 32a8432f87..ea6e6cae5a 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" pb "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" @@ -115,7 +115,7 @@ type service struct { ocrCfg OCRConfig ocr2cfg OCR2Config connMgr ConnectionsManager - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer lggr logger.Logger version string } @@ -132,7 +132,7 @@ func NewService( ocrCfg OCRConfig, ocr2Cfg OCR2Config, dbCfg pg.QConfig, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, version string, ) *service { diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index c94a75b3dd..d811a4461f 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -11,8 +11,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -149,7 +149,7 @@ type TestService struct { p2pKeystore *ksmocks.P2P ocr1Keystore *ksmocks.OCR ocr2Keystore *ksmocks.OCR2 - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer } func setupTestService(t *testing.T) *TestService { diff --git a/core/services/fluxmonitorv2/delegate.go b/core/services/fluxmonitorv2/delegate.go index e63f355672..99e2b688f5 100644 --- a/core/services/fluxmonitorv2/delegate.go +++ b/core/services/fluxmonitorv2/delegate.go @@ -6,8 +6,8 @@ import ( "github.com/jmoiron/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -22,7 +22,7 @@ type Delegate struct { jobORM job.ORM pipelineORM pipeline.ORM pipelineRunner pipeline.Runner - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer lggr logger.Logger } @@ -35,7 +35,7 @@ func NewDelegate( pipelineORM pipeline.ORM, pipelineRunner pipeline.Runner, db *sqlx.DB, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, ) *Delegate { return &Delegate{ diff --git a/core/services/gateway/delegate.go b/core/services/gateway/delegate.go index 909ca21ad7..d4180184ac 100644 --- a/core/services/gateway/delegate.go +++ b/core/services/gateway/delegate.go @@ -7,7 +7,7 @@ import ( "github.com/pelletier/go-toml" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -16,14 +16,14 @@ import ( ) type Delegate struct { - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer ks keystore.Eth lggr logger.Logger } var _ job.Delegate = (*Delegate)(nil) -func NewDelegate(legacyChains evm.LegacyChainContainer, ks keystore.Eth, lggr logger.Logger) *Delegate { +func NewDelegate(legacyChains legacyevm.LegacyChainContainer, ks keystore.Eth, lggr logger.Logger) *Delegate { return &Delegate{legacyChains: legacyChains, ks: ks, lggr: lggr} } diff --git a/core/services/gateway/handler_factory.go b/core/services/gateway/handler_factory.go index 519de608a0..368bc64c87 100644 --- a/core/services/gateway/handler_factory.go +++ b/core/services/gateway/handler_factory.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers" @@ -17,13 +17,13 @@ const ( ) type handlerFactory struct { - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer lggr logger.Logger } var _ HandlerFactory = (*handlerFactory)(nil) -func NewHandlerFactory(legacyChains evm.LegacyChainContainer, lggr logger.Logger) HandlerFactory { +func NewHandlerFactory(legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger) HandlerFactory { return &handlerFactory{legacyChains, lggr} } diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index b52c866a13..5277f9789d 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" @@ -96,7 +96,7 @@ type PendingRequest struct { var _ handlers.Handler = (*functionsHandler)(nil) -func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *config.DONConfig, don handlers.DON, legacyChains evm.LegacyChainContainer, lggr logger.Logger) (handlers.Handler, error) { +func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *config.DONConfig, don handlers.DON, legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger) (handlers.Handler, error) { var cfg FunctionsHandlerConfig err := json.Unmarshal(handlerConfig, &cfg) if err != nil { diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index 6d41362496..0dbf584c56 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -5,7 +5,7 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -21,7 +21,7 @@ type Delegate struct { db *sqlx.DB jrm job.ORM pr pipeline.Runner - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer mailMon *utils.MailboxMonitor } @@ -31,7 +31,7 @@ func NewDelegate( jrm job.ORM, pr pipeline.Runner, logger logger.Logger, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, mailMon *utils.MailboxMonitor, ) *Delegate { return &Delegate{ diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index a064c3ed4b..7bbecafa22 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -15,7 +15,6 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -23,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -62,7 +62,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain cltest.JobPipelineV2TestHelper, *txmmocks.MockEvmTxManager, keystore.Master, - evm.Chain, + legacyevm.Chain, keeper.ORM, ) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index c8de3ec33c..aa058d6497 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -19,8 +19,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -41,7 +41,7 @@ type Delegate struct { pipelineRunner pipeline.Runner peerWrapper *ocrcommon.SingletonPeerWrapper monitoringEndpointGen telemetry.MonitoringEndpointGenerator - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer lggr logger.Logger cfg Config mailMon *utils.MailboxMonitor @@ -58,7 +58,7 @@ func NewDelegate( pipelineRunner pipeline.Runner, peerWrapper *ocrcommon.SingletonPeerWrapper, monitoringEndpointGen telemetry.MonitoringEndpointGenerator, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, cfg Config, mailMon *utils.MailboxMonitor, @@ -346,7 +346,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e return services, nil } -func (d *Delegate) maybeCreateConfigOverrider(logger logger.Logger, chain evm.Chain, contractAddress ethkey.EIP55Address) (*ConfigOverriderImpl, error) { +func (d *Delegate) maybeCreateConfigOverrider(logger logger.Logger, chain legacyevm.Chain, contractAddress ethkey.EIP55Address) (*ConfigOverriderImpl, error) { flagsContractAddress := chain.Config().EVM().FlagsContractAddress() if flagsContractAddress != "" { flags, err := NewFlags(flagsContractAddress, chain.Client()) diff --git a/core/services/ocr/validate.go b/core/services/ocr/validate.go index 145bb7597e..a780ebb082 100644 --- a/core/services/ocr/validate.go +++ b/core/services/ocr/validate.go @@ -11,8 +11,8 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting" "github.com/smartcontractkit/chainlink/v2/common/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" @@ -37,7 +37,7 @@ type insecureConfig interface { } // ValidatedOracleSpecToml validates an oracle spec that came from TOML -func ValidatedOracleSpecToml(legacyChains evm.LegacyChainContainer, tomlString string) (job.Job, error) { +func ValidatedOracleSpecToml(legacyChains legacyevm.LegacyChainContainer, tomlString string) (job.Job, error) { return ValidatedOracleSpecTomlCfg(func(id *big.Int) (evmconfig.ChainScopedConfig, error) { c, err := legacyChains.Get(id.String()) if err != nil { diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 7a90e3b07e..45ee4e0f8f 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -36,7 +36,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -118,7 +118,7 @@ type Delegate struct { isNewlyCreatedJob bool // Set to true if this is a new job freshly added, false if job was present already on node boot. mailMon *utils.MailboxMonitor - legacyChains evm.LegacyChainContainer // legacy: use relayers instead + legacyChains legacyevm.LegacyChainContainer // legacy: use relayers instead } type DelegateConfig interface { @@ -217,7 +217,7 @@ func NewDelegate( pipelineRunner pipeline.Runner, peerWrapper *ocrcommon.SingletonPeerWrapper, monitoringEndpointGen telemetry.MonitoringEndpointGenerator, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, cfg DelegateConfig, ks keystore.OCR2, @@ -462,7 +462,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { } } -func GetEVMEffectiveTransmitterID(jb *job.Job, chain evm.Chain, lggr logger.SugaredLogger) (string, error) { +func GetEVMEffectiveTransmitterID(jb *job.Job, chain legacyevm.Chain, lggr logger.SugaredLogger) (string, error) { spec := jb.OCR2OracleSpec if spec.PluginType == types.Mercury { return spec.TransmitterID.String, nil diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 82280f527c..2ebd7e3080 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/functions" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" @@ -39,7 +39,7 @@ type FunctionsServicesConfig struct { BridgeORM bridges.ORM QConfig pg.QConfig DB *sqlx.DB - Chain evm.Chain + Chain legacyevm.Chain ContractID string Logger logger.Logger MailMon *utils.MailboxMonitor diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go index 3cb91ab8dc..682ebb6e2a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go @@ -20,9 +20,9 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -71,7 +71,7 @@ type LatestBlockGetter interface { LatestBlock() int64 } -func NewEVMRegistryService(addr common.Address, client evm.Chain, lggr logger.Logger) (*EvmRegistry, error) { +func NewEVMRegistryService(addr common.Address, client legacyevm.Chain, lggr logger.Logger) (*EvmRegistry, error) { keeperRegistryABI, err := abi.JSON(strings.NewReader(keeper_registry_wrapper2_0.KeeperRegistryABI)) if err != nil { return nil, fmt.Errorf("%w: %s", ErrABINotParsable, err) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 18795eb073..e6db3e66e6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -21,9 +21,9 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -79,7 +79,7 @@ type HttpClient interface { func NewEvmRegistry( lggr logger.Logger, addr common.Address, - client evm.Chain, + client legacyevm.Chain, registry *iregistry21.IKeeperRegistryMaster, mc *models.MercuryCredentials, al ActiveUpkeepList, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go index 18c9ed6d39..35d2f82942 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" @@ -36,7 +36,7 @@ type AutomationServices interface { Keyring() ocr3types.OnchainKeyring[plugin.AutomationReportInfo] } -func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, lggr logger.Logger, db *sqlx.DB, dbCfg pg.QConfig) (AutomationServices, error) { +func New(addr common.Address, client legacyevm.Chain, mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, lggr logger.Logger, db *sqlx.DB, dbCfg pg.QConfig) (AutomationServices, error) { registryContract, err := iregistry21.NewIKeeperRegistryMaster(addr, client.Client()) if err != nil { return nil, fmt.Errorf("%w: failed to create caller for address and backend", ErrInitializationFailure) diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 2c477e7a6a..0c81b16f0f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -44,7 +44,7 @@ var ( ErrNoChainFromSpec = fmt.Errorf("could not create chain from spec") ) -func EVMProvider(db *sqlx.DB, chain evm.Chain, lggr logger.Logger, spec job.Job, pr pipeline.Runner) (evmrelay.OCR2KeeperProvider, error) { +func EVMProvider(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, pr pipeline.Runner) (evmrelay.OCR2KeeperProvider, error) { oSpec := spec.OCR2OracleSpec ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(db, chain, pr, spec, lggr.Named("OCR2KeeperRelayer")) @@ -71,7 +71,7 @@ func EVMDependencies20( spec job.Job, db *sqlx.DB, lggr logger.Logger, - chain evm.Chain, + chain legacyevm.Chain, pr pipeline.Runner, ) (evmrelay.OCR2KeeperProvider, *kevm20.EvmRegistry, Encoder20, *kevm20.LogProvider, error) { var err error @@ -112,7 +112,7 @@ func EVMDependencies21( spec job.Job, db *sqlx.DB, lggr logger.Logger, - chain evm.Chain, + chain legacyevm.Chain, pr pipeline.Runner, mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, diff --git a/core/services/pipeline/helpers_test.go b/core/services/pipeline/helpers_test.go index 974ff29d11..9ee2dc693f 100644 --- a/core/services/pipeline/helpers_test.go +++ b/core/services/pipeline/helpers_test.go @@ -6,7 +6,7 @@ import ( "github.com/google/uuid" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" ) const ( @@ -50,14 +50,14 @@ func (t *HTTPTask) HelperSetDependencies(config Config, restrictedHTTPClient, un t.unrestrictedHTTPClient = unrestrictedHTTPClient } -func (t *ETHCallTask) HelperSetDependencies(legacyChains evm.LegacyChainContainer, config Config, specGasLimit *uint32, jobType string) { +func (t *ETHCallTask) HelperSetDependencies(legacyChains legacyevm.LegacyChainContainer, config Config, specGasLimit *uint32, jobType string) { t.legacyChains = legacyChains t.config = config t.specGasLimit = specGasLimit t.jobType = jobType } -func (t *ETHTxTask) HelperSetDependencies(legacyChains evm.LegacyChainContainer, keyStore ETHKeyStore, specGasLimit *uint32, jobType string) { +func (t *ETHTxTask) HelperSetDependencies(legacyChains legacyevm.LegacyChainContainer, keyStore ETHKeyStore, specGasLimit *uint32, jobType string) { t.legacyChains = legacyChains t.keyStore = keyStore t.specGasLimit = specGasLimit diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 388f7358ef..768f163f9b 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -57,7 +57,7 @@ type runner struct { btORM bridges.ORM config Config bridgeConfig BridgeConfig - legacyEVMChains evm.LegacyChainContainer + legacyEVMChains legacyevm.LegacyChainContainer ethKeyStore ETHKeyStore vrfKeyStore VRFKeyStore runReaperWorker utils.SleeperTask @@ -102,7 +102,7 @@ var ( ) ) -func NewRunner(orm ORM, btORM bridges.ORM, cfg Config, bridgeCfg BridgeConfig, legacyChains evm.LegacyChainContainer, ethks ETHKeyStore, vrfks VRFKeyStore, lggr logger.Logger, httpClient, unrestrictedHTTPClient *http.Client) *runner { +func NewRunner(orm ORM, btORM bridges.ORM, cfg Config, bridgeCfg BridgeConfig, legacyChains legacyevm.LegacyChainContainer, ethks ETHKeyStore, vrfks VRFKeyStore, lggr logger.Logger, httpClient, unrestrictedHTTPClient *http.Client) *runner { r := &runner{ orm: orm, btORM: btORM, diff --git a/core/services/pipeline/task.estimategas.go b/core/services/pipeline/task.estimategas.go index 88c6f6facc..1c0159819b 100644 --- a/core/services/pipeline/task.estimategas.go +++ b/core/services/pipeline/task.estimategas.go @@ -12,7 +12,7 @@ import ( "github.com/shopspring/decimal" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -30,7 +30,7 @@ type EstimateGasLimitTask struct { EVMChainID string `json:"evmChainID" mapstructure:"evmChainID"` specGasLimit *uint32 - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer jobType string } diff --git a/core/services/pipeline/task.eth_call.go b/core/services/pipeline/task.eth_call.go index e877e1e90f..3862ea1030 100644 --- a/core/services/pipeline/task.eth_call.go +++ b/core/services/pipeline/task.eth_call.go @@ -12,8 +12,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -35,7 +35,7 @@ type ETHCallTask struct { EVMChainID string `json:"evmChainID" mapstructure:"evmChainID"` specGasLimit *uint32 - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer config Config jobType string } diff --git a/core/services/pipeline/task.eth_call_test.go b/core/services/pipeline/task.eth_call_test.go index 8fe8bec16c..cb58a03a9d 100644 --- a/core/services/pipeline/task.eth_call_test.go +++ b/core/services/pipeline/task.eth_call_test.go @@ -12,9 +12,9 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -257,7 +257,7 @@ func TestETHCallTask(t *testing.T) { txManager := txmmocks.NewMockEvmTxManager(t) db := pgtest.NewSqlxDB(t) - var legacyChains evm.LegacyChainContainer + var legacyChains legacyevm.LegacyChainContainer if test.expectedErrorCause != nil || test.expectedErrorContains != "" { exts := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, TxManager: txManager, KeyStore: keyStore}) legacyChains = evmrelay.NewLegacyChainsFromRelayerExtenders(exts) diff --git a/core/services/pipeline/task.eth_tx.go b/core/services/pipeline/task.eth_tx.go index 384c86446e..c421b340c9 100644 --- a/core/services/pipeline/task.eth_tx.go +++ b/core/services/pipeline/task.eth_tx.go @@ -14,8 +14,8 @@ import ( "gopkg.in/guregu/null.v4" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -42,7 +42,7 @@ type ETHTxTask struct { forwardingAllowed bool specGasLimit *uint32 keyStore ETHKeyStore - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer jobType string } diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index e8267c9a84..952c1869bf 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -24,8 +24,8 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -48,7 +48,7 @@ var _ commontypes.Relayer = &Relayer{} //nolint:staticcheck type Relayer struct { db *sqlx.DB - chain evm.Chain + chain legacyevm.Chain lggr logger.Logger ks CSAETHKeystore mercuryPool wsrpc.Pool @@ -89,7 +89,7 @@ func (c RelayerOpts) Validate() error { return err } -func NewRelayer(lggr logger.Logger, chain evm.Chain, opts RelayerOpts) (*Relayer, error) { +func NewRelayer(lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*Relayer, error) { err := opts.Validate() if err != nil { return nil, fmt.Errorf("cannot create evm relayer: %w", err) @@ -244,7 +244,7 @@ type configWatcher struct { contractABI abi.ABI offchainDigester ocrtypes.OffchainConfigDigester configPoller types.ConfigPoller - chain evm.Chain + chain legacyevm.Chain runReplay bool fromBlock uint64 replayCtx context.Context @@ -257,7 +257,7 @@ func newConfigWatcher(lggr logger.Logger, contractABI abi.ABI, offchainDigester ocrtypes.OffchainConfigDigester, configPoller types.ConfigPoller, - chain evm.Chain, + chain legacyevm.Chain, fromBlock uint64, runReplay bool, ) *configWatcher { @@ -321,7 +321,7 @@ func (c *configWatcher) ContractConfigTracker() ocrtypes.ContractConfigTracker { return c.configPoller } -func newConfigProvider(lggr logger.Logger, chain evm.Chain, opts *types.RelayOpts, eventBroadcaster pg.EventBroadcaster) (*configWatcher, error) { +func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.RelayOpts, eventBroadcaster pg.EventBroadcaster) (*configWatcher, error) { if !common.IsHexAddress(opts.ContractID) { return nil, pkgerrors.Errorf("invalid contractID, expected hex address") } diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index 88f9d22099..10e5d543b1 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -19,8 +19,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" @@ -85,7 +85,7 @@ func (p *functionsProvider) Name() string { return p.configWatcher.Name() } -func NewFunctionsProvider(chain evm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { +func NewFunctionsProvider(chain legacyevm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { relayOpts := evmRelayTypes.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() if err != nil { @@ -130,7 +130,7 @@ func NewFunctionsProvider(chain evm.Chain, rargs commontypes.RelayArgs, pargs co }, nil } -func newFunctionsConfigProvider(pluginType functionsRelay.FunctionsPluginType, chain evm.Chain, args commontypes.RelayArgs, fromBlock uint64, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (*configWatcher, error) { +func newFunctionsConfigProvider(pluginType functionsRelay.FunctionsPluginType, chain legacyevm.Chain, args commontypes.RelayArgs, fromBlock uint64, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (*configWatcher, error) { if !common.IsHexAddress(args.ContractID) { return nil, errors.Errorf("invalid contractID, expected hex address") } diff --git a/core/services/relay/evm/loop_impl.go b/core/services/relay/evm/loop_impl.go index 309b5e24f6..57a09dd49a 100644 --- a/core/services/relay/evm/loop_impl.go +++ b/core/services/relay/evm/loop_impl.go @@ -3,14 +3,14 @@ package evm import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) //go:generate mockery --quiet --name LoopRelayAdapter --output ./mocks/ --case=underscore type LoopRelayAdapter interface { loop.Relayer - Chain() evm.Chain + Chain() legacyevm.Chain } type LoopRelayer struct { loop.Relayer @@ -27,6 +27,6 @@ func NewLoopRelayServerAdapter(r *Relayer, cs EVMChainRelayerExtender) *LoopRela } } -func (la *LoopRelayer) Chain() evm.Chain { +func (la *LoopRelayer) Chain() legacyevm.Chain { return la.ext.Chain() } diff --git a/core/services/relay/evm/median.go b/core/services/relay/evm/median.go index 5184326cf2..db521a9720 100644 --- a/core/services/relay/evm/median.go +++ b/core/services/relay/evm/median.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -27,7 +27,7 @@ type medianContract struct { requestRoundTracker *RequestRoundTracker } -func newMedianContract(configTracker types.ContractConfigTracker, contractAddress common.Address, chain evm.Chain, specID int32, db *sqlx.DB, lggr logger.Logger) (*medianContract, error) { +func newMedianContract(configTracker types.ContractConfigTracker, contractAddress common.Address, chain legacyevm.Chain, specID int32, db *sqlx.DB, lggr logger.Logger) (*medianContract, error) { contract, err := offchain_aggregator_wrapper.NewOffchainAggregator(contractAddress, chain.Client()) if err != nil { return nil, errors.Wrap(err, "could not instantiate NewOffchainAggregator") diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 13a73036a1..0376c9f27a 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -6,7 +6,8 @@ import ( context "context" big "math/big" - evm "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + legacyevm "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -18,15 +19,15 @@ type LoopRelayAdapter struct { } // Chain provides a mock function with given fields: -func (_m *LoopRelayAdapter) Chain() evm.Chain { +func (_m *LoopRelayAdapter) Chain() legacyevm.Chain { ret := _m.Called() - var r0 evm.Chain - if rf, ok := ret.Get(0).(func() evm.Chain); ok { + var r0 legacyevm.Chain + if rf, ok := ret.Get(0).(func() legacyevm.Chain); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(evm.Chain) + r0 = ret.Get(0).(legacyevm.Chain) } } diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 2b484edb79..3b3bfeb652 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -20,7 +20,7 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -52,14 +52,14 @@ type OCR2KeeperRelayer interface { // ocr2keeperRelayer is the relayer with added DKG and OCR2Keeper provider functions. type ocr2keeperRelayer struct { db *sqlx.DB - chain evm.Chain + chain legacyevm.Chain pr pipeline.Runner spec job.Job lggr logger.Logger } // NewOCR2KeeperRelayer is the constructor of ocr2keeperRelayer -func NewOCR2KeeperRelayer(db *sqlx.DB, chain evm.Chain, pr pipeline.Runner, spec job.Job, lggr logger.Logger) OCR2KeeperRelayer { +func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, pr pipeline.Runner, spec job.Job, lggr logger.Logger) OCR2KeeperRelayer { return &ocr2keeperRelayer{ db: db, chain: chain, @@ -130,7 +130,7 @@ func (c *ocr2keeperProvider) ContractTransmitter() ocrtypes.ContractTransmitter return c.contractTransmitter } -func newOCR2KeeperConfigProvider(lggr logger.Logger, chain evm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { +func newOCR2KeeperConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) if err != nil { diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index 66ce42b7d8..b7a2220588 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -16,7 +16,7 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" @@ -48,12 +48,12 @@ var ( // Relayer with added DKG and OCR2VRF provider functions. type ocr2vrfRelayer struct { db *sqlx.DB - chain evm.Chain + chain legacyevm.Chain lggr logger.Logger ethKeystore keystore.Eth } -func NewOCR2VRFRelayer(db *sqlx.DB, chain evm.Chain, lggr logger.Logger, ethKeystore keystore.Eth) OCR2VRFRelayer { +func NewOCR2VRFRelayer(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, ethKeystore keystore.Eth) OCR2VRFRelayer { return &ocr2vrfRelayer{ db: db, chain: chain, @@ -119,7 +119,7 @@ func (c *ocr2vrfProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } -func newOCR2VRFConfigProvider(lggr logger.Logger, chain evm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { +func newOCR2VRFConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) if err != nil { diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index 43626037a1..83f03b47f9 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -11,9 +11,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - evmchain "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" ) // ErrNoChains indicates that no EVM chains have been started @@ -21,31 +20,31 @@ var ErrNoChains = errors.New("no EVM chains loaded") type EVMChainRelayerExtender interface { loop.RelayerExt - Chain() evmchain.Chain + Chain() legacyevm.Chain } type EVMChainRelayerExtenderSlicer interface { Slice() []EVMChainRelayerExtender Len() int - AppConfig() evmchain.AppConfig + AppConfig() legacyevm.AppConfig } type ChainRelayerExtenders struct { exts []EVMChainRelayerExtender - cfg evmchain.AppConfig + cfg legacyevm.AppConfig } var _ EVMChainRelayerExtenderSlicer = &ChainRelayerExtenders{} -func NewLegacyChainsFromRelayerExtenders(exts EVMChainRelayerExtenderSlicer) *evmchain.LegacyChains { - m := make(map[string]evmchain.Chain) +func NewLegacyChainsFromRelayerExtenders(exts EVMChainRelayerExtenderSlicer) *legacyevm.LegacyChains { + m := make(map[string]legacyevm.Chain) for _, r := range exts.Slice() { m[r.Chain().ID().String()] = r.Chain() } - return evmchain.NewLegacyChains(m, exts.AppConfig().EVMConfigs()) + return legacyevm.NewLegacyChains(m, exts.AppConfig().EVMConfigs()) } -func newChainRelayerExtsFromSlice(exts []*ChainRelayerExt, appConfig evm.AppConfig) *ChainRelayerExtenders { +func newChainRelayerExtsFromSlice(exts []*ChainRelayerExt, appConfig legacyevm.AppConfig) *ChainRelayerExtenders { temp := make([]EVMChainRelayerExtender, len(exts)) for i := range exts { temp[i] = exts[i] @@ -56,7 +55,7 @@ func newChainRelayerExtsFromSlice(exts []*ChainRelayerExt, appConfig evm.AppConf } } -func (c *ChainRelayerExtenders) AppConfig() evmchain.AppConfig { +func (c *ChainRelayerExtenders) AppConfig() legacyevm.AppConfig { return c.cfg } @@ -70,7 +69,7 @@ func (c *ChainRelayerExtenders) Len() int { // implements OneChain type ChainRelayerExt struct { - chain evmchain.Chain + chain legacyevm.Chain } var _ EVMChainRelayerExtender = &ChainRelayerExt{} @@ -91,7 +90,7 @@ func (s *ChainRelayerExt) ID() string { return s.chain.ID().String() } -func (s *ChainRelayerExt) Chain() evmchain.Chain { +func (s *ChainRelayerExt) Chain() legacyevm.Chain { return s.chain } @@ -117,7 +116,7 @@ func (s *ChainRelayerExt) Ready() (err error) { return s.chain.Ready() } -func NewChainRelayerExtenders(ctx context.Context, opts evmchain.ChainRelayExtenderConfig) (*ChainRelayerExtenders, error) { +func NewChainRelayerExtenders(ctx context.Context, opts legacyevm.ChainRelayExtenderConfig) (*ChainRelayerExtenders, error) { if err := opts.Validate(); err != nil { return nil, err } @@ -142,14 +141,14 @@ func NewChainRelayerExtenders(ctx context.Context, opts evmchain.ChainRelayExten for i := range enabled { cid := enabled[i].ChainID.String() - privOpts := evmchain.ChainRelayExtenderConfig{ + privOpts := legacyevm.ChainRelayExtenderConfig{ Logger: opts.Logger.Named(cid), ChainOpts: opts.ChainOpts, KeyStore: opts.KeyStore, } privOpts.Logger.Infow(fmt.Sprintf("Loading chain %s", cid), "evmChainID", cid) - chain, err2 := evmchain.NewTOMLChain(ctx, enabled[i], privOpts) + chain, err2 := legacyevm.NewTOMLChain(ctx, enabled[i], privOpts) if err2 != nil { err = multierr.Combine(err, fmt.Errorf("failed to create chain %s: %w", cid, err2)) continue diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index 3b91f783b4..f739d112ab 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -12,9 +12,9 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -37,7 +37,7 @@ type Delegate struct { pr pipeline.Runner porm pipeline.ORM ks keystore.Master - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer lggr logger.Logger mailMon *utils.MailboxMonitor } @@ -47,7 +47,7 @@ func NewDelegate( ks keystore.Master, pr pipeline.Runner, porm pipeline.ORM, - legacyChains evm.LegacyChainContainer, + legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, cfg pg.QConfig, mailMon *utils.MailboxMonitor) *Delegate { diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 3d544027d4..3c29702600 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -9,7 +9,6 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" @@ -18,6 +17,7 @@ import ( log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -60,7 +60,7 @@ type vrfUniverse struct { submitter common.Address txm *txmgr.TxManager hb httypes.HeadBroadcaster - legacyChains evm.LegacyChainContainer + legacyChains legacyevm.LegacyChainContainer cid big.Int } diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 3e958801cd..494847797f 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -17,9 +17,9 @@ import ( "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" @@ -63,7 +63,7 @@ type Listener struct { NewHead chan struct{} LatestHead uint64 LatestHeadMu sync.RWMutex - Chain evm.Chain + Chain legacyevm.Chain // We can keep these pending logs in memory because we // only mark them confirmed once we send a corresponding fulfillment transaction. diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index f57cb640f6..c1376eafeb 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -33,7 +33,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -41,6 +40,7 @@ import ( evmlogger "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -1604,7 +1604,7 @@ func TestIntegrationVRFV2(t *testing.T) { require.Zero(t, key.Cmp(keys[0])) require.NoError(t, app.Start(testutils.Context(t))) - var chain evm.Chain + var chain legacyevm.Chain chain, err = app.GetRelayers().LegacyEVMChains().Get(testutils.SimulatedChainID.String()) require.NoError(t, err) listenerV2 := v22.MakeTestListenerV2(chain) diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 7f23e02277..e0f8ff9a5b 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -28,11 +28,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2plus" @@ -98,7 +98,7 @@ func New( cfg vrfcommon.Config, feeCfg vrfcommon.FeeConfig, l logger.Logger, - chain evm.Chain, + chain legacyevm.Chain, chainID *big.Int, q pg.Q, coordinator CoordinatorV2_X, @@ -170,7 +170,7 @@ type listenerV2 struct { cfg vrfcommon.Config feeCfg vrfcommon.FeeConfig l logger.SugaredLogger - chain evm.Chain + chain legacyevm.Chain chainID *big.Int mailMon *utils.MailboxMonitor diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 513aa01ef6..8a7b9ce3fe 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -22,13 +22,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" - evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -49,7 +49,7 @@ func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.M return txm } -func MakeTestListenerV2(chain evm.Chain) *listenerV2 { +func MakeTestListenerV2(chain legacyevm.Chain) *listenerV2 { return &listenerV2{chainID: chain.Client().ConfiguredChainID(), chain: chain} } diff --git a/core/web/common.go b/core/web/common.go index ae2158d153..66159d8b60 100644 --- a/core/web/common.go +++ b/core/web/common.go @@ -5,7 +5,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" ) var ( @@ -15,7 +15,7 @@ var ( ErrMultipleChains = errors.New("more than one chain available, you must specify chain id parameter") ) -func getChain(legacyChains evm.LegacyChainContainer, chainIDstr string) (chain evm.Chain, err error) { +func getChain(legacyChains legacyevm.LegacyChainContainer, chainIDstr string) (chain legacyevm.Chain, err error) { if chainIDstr != "" && chainIDstr != "" { // evm keys are expected to be parsable as a big int diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index b202d90f21..d99992c0f5 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -10,8 +10,8 @@ import ( "strings" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" @@ -412,7 +412,7 @@ func (ekc *ETHKeysController) getKeyMaxGasPriceWei(state ethkey.State, keyAddres // getChain is a convenience wrapper to retrieve a chain for a given request // and call the corresponding API response error function for 400, 404 and 500 results -func (ekc *ETHKeysController) getChain(c *gin.Context, chainIDstr string) (chain evm.Chain, ok bool) { +func (ekc *ETHKeysController) getChain(c *gin.Context, chainIDstr string) (chain legacyevm.Chain, ok bool) { chain, err := getChain(ekc.app.GetRelayers().LegacyEVMChains(), chainIDstr) if err != nil { if errors.Is(err, ErrInvalidChainID) || errors.Is(err, ErrMultipleChains) { diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go index 7f09bc9fdc..6ab621661a 100644 --- a/core/web/evm_transfer_controller.go +++ b/core/web/evm_transfer_controller.go @@ -11,9 +11,9 @@ import ( "github.com/pkg/errors" commontxmgr "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -92,7 +92,7 @@ func (tc *EVMTransfersController) Create(c *gin.Context) { } // ValidateEthBalanceForTransfer validates that the current balance can cover the transaction amount -func ValidateEthBalanceForTransfer(c *gin.Context, chain evm.Chain, fromAddr common.Address, amount assets.Eth) error { +func ValidateEthBalanceForTransfer(c *gin.Context, chain legacyevm.Chain, fromAddr common.Address, amount assets.Eth) error { var err error var balance *big.Int diff --git a/core/web/resolver/eth_key.go b/core/web/resolver/eth_key.go index 868d53565d..a9c060ef0c 100644 --- a/core/web/resolver/eth_key.go +++ b/core/web/resolver/eth_key.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/graph-gophers/graphql-go" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/web/loader" ) @@ -14,7 +14,7 @@ import ( type ETHKey struct { state ethkey.State addr ethkey.EIP55Address - chain evm.Chain + chain legacyevm.Chain } type ETHKeyResolver struct { diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index d75282e0fb..ea106a4b30 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -10,11 +10,11 @@ import ( "github.com/stretchr/testify/mock" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -90,8 +90,8 @@ func TestResolver_ETHKeys(t *testing.T) { linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") cfg := configtest.NewGeneralConfig(t, nil) - m := map[string]evm.Chain{states[0].EVMChainID.String(): f.Mocks.chain} - legacyEVMChains := evm.NewLegacyChains(m, cfg.EVMConfigs()) + m := map[string]legacyevm.Chain{states[0].EVMChainID.String(): f.Mocks.chain} + legacyEVMChains := legacyevm.NewLegacyChains(m, cfg.EVMConfigs()) f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) diff --git a/core/web/resolver/resolver_test.go b/core/web/resolver/resolver_test.go index 85c495faaa..d5906d99af 100644 --- a/core/web/resolver/resolver_test.go +++ b/core/web/resolver/resolver_test.go @@ -15,6 +15,7 @@ import ( evmConfigMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" evmORMMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" evmtxmgrmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + legacyEvmORMMocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" coremocks "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -50,8 +51,8 @@ type mocks struct { p2p *keystoreMocks.P2P vrf *keystoreMocks.VRF solana *keystoreMocks.Solana - chain *evmORMMocks.Chain - legacyEVMChains *evmORMMocks.LegacyChainContainer + chain *legacyEvmORMMocks.Chain + legacyEVMChains *legacyEvmORMMocks.LegacyChainContainer relayerChainInterops *chainlinkMocks.FakeRelayerChainInteroperators ethClient *evmClientMocks.Client eIMgr *webhookmocks.ExternalInitiatorManager @@ -109,8 +110,8 @@ func setupFramework(t *testing.T) *gqlTestFramework { p2p: keystoreMocks.NewP2P(t), vrf: keystoreMocks.NewVRF(t), solana: keystoreMocks.NewSolana(t), - chain: evmORMMocks.NewChain(t), - legacyEVMChains: evmORMMocks.NewLegacyChainContainer(t), + chain: legacyEvmORMMocks.NewChain(t), + legacyEVMChains: legacyEvmORMMocks.NewLegacyChainContainer(t), relayerChainInterops: &chainlinkMocks.FakeRelayerChainInteroperators{}, ethClient: evmClientMocks.NewClient(t), eIMgr: webhookmocks.NewExternalInitiatorManager(t), diff --git a/go.mod b/go.mod index 0f75e120fe..b2afd2e211 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-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 diff --git a/go.sum b/go.sum index fc8cab806a..98371af2e2 100644 --- a/go.sum +++ b/go.sum @@ -1507,8 +1507,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 h1:HJCPvJ+ZjU9TSX4YD5rxBJqGAvqhDfzoJgI3WmfeWeI= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index ca77d3730e..4cf6a502c4 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 github.com/smartcontractkit/chainlink-testing-framework v1.19.5 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f117bf73e8..ef0a5b66ff 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2376,8 +2376,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3 h1:cyA1aW1PYrOLZAMaSmuH7U99QBTfrF59s+6uDxQgOr0= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231121180428-d7f28e91ccc3/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 h1:HJCPvJ+ZjU9TSX4YD5rxBJqGAvqhDfzoJgI3WmfeWeI= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= From 05ccd282d98151e75a0171be2da3862d55f2fb97 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Tue, 28 Nov 2023 13:51:25 +0200 Subject: [PATCH 206/327] Remove FriendlyNumber function (#11376) --- common/headtracker/head_tracker.go | 6 ++---- core/config/presenters.go | 14 -------------- 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 core/config/presenters.go diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 34a319e3c1..6e379776c0 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -15,7 +15,6 @@ import ( htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -103,7 +102,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error } if latestChain.IsValid() { ht.log.Debugw( - fmt.Sprintf("HeadTracker: Tracking logs from last block %v with hash %s", config.FriendlyNumber(latestChain.BlockNumber()), latestChain.BlockHash()), + fmt.Sprintf("HeadTracker: Tracking logs from last block %v with hash %s", latestChain.BlockNumber(), latestChain.BlockHash()), "blockNumber", latestChain.BlockNumber(), "blockHash", latestChain.BlockHash(), ) @@ -193,8 +192,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) getInitialHead(ctx context.Contex func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context, head HTH) error { prevHead := ht.headSaver.LatestChain() - ht.log.Debugw(fmt.Sprintf("Received new head %v", config.FriendlyNumber(head.BlockNumber())), - "blockHeight", head.BlockNumber(), + ht.log.Debugw(fmt.Sprintf("Received new head %v", head.BlockNumber()), "blockHash", head.BlockHash(), "parentHeadHash", head.GetParentHash(), "blockTs", head.GetTimestamp(), diff --git a/core/config/presenters.go b/core/config/presenters.go deleted file mode 100644 index f4da66fd15..0000000000 --- a/core/config/presenters.go +++ /dev/null @@ -1,14 +0,0 @@ -package config - -import ( - "fmt" - "math/big" - - "golang.org/x/exp/constraints" -) - -// FriendlyNumber returns a string printing the integer or big.Int in both -// decimal and hexadecimal formats. -func FriendlyNumber[N constraints.Integer | *big.Int](n N) string { - return fmt.Sprintf("#%[1]v (0x%[1]x)", n) -} From 524eafcfc37599acda0ad7ebef01a6fb2f8434ce Mon Sep 17 00:00:00 2001 From: Makram Date: Tue, 28 Nov 2023 15:05:06 +0200 Subject: [PATCH 207/327] feat: log poller for vrf v2/v2+ (#11174) * feat: log poller for vrf v2/+ * chore: address PR comments * fix: RLock() instead of Lock() * fix: test * fix: tests still flakey * fix: lint * fix: build * chore: PR comments * chore: time out old requests * chore: skip EOA tests these tests have questionable value; we should probably remove them or find a better way to test this particular functionality. Perhaps this should even be removed. * remove concurrency in processing seems unnecessary * fix build * fix build * fix lint * fix test * fix tests --- core/services/vrf/delegate.go | 57 +- core/services/vrf/v2/bhs_feeder_test.go | 26 +- .../vrf/v2/coordinator_v2x_interface.go | 37 + .../vrf/v2/integration_helpers_test.go | 35 +- .../vrf/v2/integration_v2_plus_test.go | 16 +- core/services/vrf/v2/integration_v2_test.go | 13 +- core/services/vrf/v2/listener_v2.go | 1608 +---------------- core/services/vrf/v2/listener_v2_helpers.go | 103 ++ .../vrf/v2/listener_v2_log_listener.go | 451 +++++ .../vrf/v2/listener_v2_log_processor.go | 1214 +++++++++++++ core/services/vrf/v2/listener_v2_test.go | 79 - core/services/vrf/v2/listener_v2_types.go | 114 +- .../services/vrf/v2/listener_v2_types_test.go | 5 - core/services/vrf/vrfcommon/inflight_cache.go | 85 + .../services/vrf/vrfcommon/log_dedupe_test.go | 22 +- core/services/vrf/vrftesthelpers/helpers.go | 2 +- core/testdata/testspecs/v2_specs.go | 10 +- .../actions/vrfv2plus/vrfv2plus_steps.go | 4 +- integration-tests/client/chainlink_models.go | 1 + integration-tests/types/config/node/core.go | 6 + 20 files changed, 2140 insertions(+), 1748 deletions(-) create mode 100644 core/services/vrf/v2/listener_v2_helpers.go create mode 100644 core/services/vrf/v2/listener_v2_log_listener.go create mode 100644 core/services/vrf/v2/listener_v2_log_processor.go create mode 100644 core/services/vrf/vrfcommon/inflight_cache.go diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index f739d112ab..a13df71d9a 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -66,10 +66,10 @@ func (d *Delegate) JobType() job.Type { return job.VRF } -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(job.Job) {} +func (d *Delegate) AfterJobCreated(job.Job) {} +func (d *Delegate) BeforeJobDeleted(job.Job) {} +func (d *Delegate) OnDeleteJob(job.Job, pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { @@ -160,24 +160,28 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { return nil, errors.Wrap(err2, "NewAggregatorV3Interface") } - return []job.ServiceCtx{v2.New( - chain.Config().EVM(), - chain.Config().EVM().GasEstimator(), - lV2Plus, - chain, - chain.ID(), - d.q, - v2.NewCoordinatorV2_5(coordinatorV2Plus), - batchCoordinatorV2, - vrfOwner, - aggregator, - d.pr, - d.ks.Eth(), - jb, - d.mailMon, - utils.NewHighCapacityMailbox[log.Broadcast](), - func() {}, - vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())))}, nil + return []job.ServiceCtx{ + v2.New( + chain.Config().EVM(), + chain.Config().EVM().GasEstimator(), + lV2Plus, + chain, + chain.ID(), + d.q, + v2.NewCoordinatorV2_5(coordinatorV2Plus), + batchCoordinatorV2, + vrfOwner, + aggregator, + d.pr, + d.ks.Eth(), + jb, + func() {}, + // the lookback in the deduper must be >= the lookback specified for the log poller + // otherwise we will end up re-delivering logs that were already delivered. + vrfcommon.NewInflightCache(int(chain.Config().EVM().FinalityDepth())), + vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())), + ), + }, nil } if _, ok := task.(*pipeline.VRFTaskV2); ok { if err2 := CheckFromAddressesExist(jb, d.ks.Eth()); err != nil { @@ -225,10 +229,13 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { d.pr, d.ks.Eth(), jb, - d.mailMon, - utils.NewHighCapacityMailbox[log.Broadcast](), func() {}, - vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())))}, nil + // the lookback in the deduper must be >= the lookback specified for the log poller + // otherwise we will end up re-delivering logs that were already delivered. + vrfcommon.NewInflightCache(int(chain.Config().EVM().FinalityDepth())), + vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())), + ), + }, nil } if _, ok := task.(*pipeline.VRFTask); ok { return []job.ServiceCtx{&v1.Listener{ diff --git a/core/services/vrf/v2/bhs_feeder_test.go b/core/services/vrf/v2/bhs_feeder_test.go index f388f80f56..31a4ff815a 100644 --- a/core/services/vrf/v2/bhs_feeder_test.go +++ b/core/services/vrf/v2/bhs_feeder_test.go @@ -10,7 +10,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -63,26 +62,12 @@ func TestStartHeartbeats(t *testing.T) { heartbeatPeriod := 5 * time.Second t.Run("bhs_feeder_startheartbeats_happy_path", func(tt *testing.T) { - coordinatorAddress := uni.rootContractAddress - vrfVersion := vrfcommon.V2 - app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, keys...) require.NoError(t, app.Start(testutils.Context(t))) - var ( - v2CoordinatorAddress string - v2PlusCoordinatorAddress string - ) - - if vrfVersion == vrfcommon.V2 { - v2CoordinatorAddress = coordinatorAddress.String() - } else if vrfVersion == vrfcommon.V2Plus { - v2PlusCoordinatorAddress = coordinatorAddress.String() - } - _ = vrftesthelpers.CreateAndStartBHSJob( t, bhsKeyAddresses, app, uni.bhsContractAddress.String(), "", - v2CoordinatorAddress, v2PlusCoordinatorAddress, "", 0, 200, heartbeatPeriod, 100) + uni.rootContractAddress.String(), "", "", 0, 200, heartbeatPeriod, 100) // Ensure log poller is ready and has all logs. require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Ready()) @@ -97,9 +82,10 @@ func TestStartHeartbeats(t *testing.T) { t.Logf("Sleeping %.2f seconds before checking blockhash in BHS added by BHS_Heartbeats_Service\n", diff.Seconds()) time.Sleep(diff) // storeEarliest in BHS contract stores blocktip - 256 in the Blockhash Store (BHS) - // before the initTxns:260 txns sent by the loop above, 18 txns are sent by - // newVRFCoordinatorV2Universe method. block tip is initTxns + 18 - blockTip := initTxns + 18 - verifyBlockhashStored(t, uni.coordinatorV2UniverseCommon, uint64(blockTip-256)) + tipHeader, err := uni.backend.HeaderByNumber(testutils.Context(t), nil) + require.NoError(t, err) + // the storeEarliest transaction will end up in a new block, hence the + 1 below. + blockNumberStored := tipHeader.Number.Uint64() - 256 + 1 + verifyBlockhashStored(t, uni.coordinatorV2UniverseCommon, blockNumberStored) }) } diff --git a/core/services/vrf/v2/coordinator_v2x_interface.go b/core/services/vrf/v2/coordinator_v2x_interface.go index b090c4ad5a..e20500cca8 100644 --- a/core/services/vrf/v2/coordinator_v2x_interface.go +++ b/core/services/vrf/v2/coordinator_v2x_interface.go @@ -28,6 +28,7 @@ var ( type CoordinatorV2_X interface { Address() common.Address ParseRandomWordsRequested(log types.Log) (RandomWordsRequested, error) + ParseRandomWordsFulfilled(log types.Log) (RandomWordsFulfilled, error) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subID *big.Int, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, payInEth bool) (*types.Transaction, error) AddConsumer(opts *bind.TransactOpts, subID *big.Int, consumer common.Address) (*types.Transaction, error) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) @@ -47,6 +48,10 @@ type CoordinatorV2_X interface { GetCommitment(opts *bind.CallOpts, requestID *big.Int) ([32]byte, error) Migrate(opts *bind.TransactOpts, subID *big.Int, newCoordinator common.Address) (*types.Transaction, error) FundSubscriptionWithNative(opts *bind.TransactOpts, subID *big.Int, amount *big.Int) (*types.Transaction, error) + // RandomWordsRequestedTopic returns the log topic of the RandomWordsRequested log + RandomWordsRequestedTopic() common.Hash + // RandomWordsFulfilledTopic returns the log topic of the RandomWordsFulfilled log + RandomWordsFulfilledTopic() common.Hash } type coordinatorV2 struct { @@ -61,6 +66,14 @@ func NewCoordinatorV2(c *vrf_coordinator_v2.VRFCoordinatorV2) CoordinatorV2_X { } } +func (c *coordinatorV2) RandomWordsRequestedTopic() common.Hash { + return vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested{}.Topic() +} + +func (c *coordinatorV2) RandomWordsFulfilledTopic() common.Hash { + return vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled{}.Topic() +} + func (c *coordinatorV2) Address() common.Address { return c.coordinator.Address() } @@ -73,6 +86,14 @@ func (c *coordinatorV2) ParseRandomWordsRequested(log types.Log) (RandomWordsReq return NewV2RandomWordsRequested(parsed), nil } +func (c *coordinatorV2) ParseRandomWordsFulfilled(log types.Log) (RandomWordsFulfilled, error) { + parsed, err := c.coordinator.ParseRandomWordsFulfilled(log) + if err != nil { + return nil, err + } + return NewV2RandomWordsFulfilled(parsed), nil +} + func (c *coordinatorV2) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subID *big.Int, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, payInEth bool) (*types.Transaction, error) { return c.coordinator.RequestRandomWords(opts, keyHash, subID.Uint64(), requestConfirmations, callbackGasLimit, numWords) } @@ -187,6 +208,14 @@ func NewCoordinatorV2_5(c vrf_coordinator_v2_5.VRFCoordinatorV25Interface) Coord } } +func (c *coordinatorV2_5) RandomWordsRequestedTopic() common.Hash { + return vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalRandomWordsRequested{}.Topic() +} + +func (c *coordinatorV2_5) RandomWordsFulfilledTopic() common.Hash { + return vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalRandomWordsFulfilled{}.Topic() +} + func (c *coordinatorV2_5) Address() common.Address { return c.coordinator.Address() } @@ -199,6 +228,14 @@ func (c *coordinatorV2_5) ParseRandomWordsRequested(log types.Log) (RandomWordsR return NewV2_5RandomWordsRequested(parsed), nil } +func (c *coordinatorV2_5) ParseRandomWordsFulfilled(log types.Log) (RandomWordsFulfilled, error) { + parsed, err := c.coordinator.ParseRandomWordsFulfilled(log) + if err != nil { + return nil, err + } + return NewV2_5RandomWordsFulfilled(parsed), nil +} + func (c *coordinatorV2_5) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subID *big.Int, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, payInEth bool) (*types.Transaction, error) { extraArgs, err := extraargs.ExtraArgsV1(payInEth) if err != nil { diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index a573737191..03d96cadf2 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -72,6 +72,8 @@ func testSingleConsumerHappyPath( GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) @@ -205,8 +207,8 @@ func testMultipleConsumersNeedBHS( simulatedOverrides(t, assets.GWei(10), keySpecificOverrides...)(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) - c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) }) keys = append(keys, ownerKey, vrfKey) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, keys...) @@ -353,8 +355,8 @@ func testMultipleConsumersNeedTrustedBHS( c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(5_000_000)) c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) - c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) }) keys = append(keys, ownerKey, vrfKey) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, keys...) @@ -539,6 +541,8 @@ func testSingleConsumerHappyPathBatchFulfillment( c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) @@ -641,6 +645,8 @@ func testSingleConsumerNeedsTopUp( GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key) @@ -746,8 +752,8 @@ func testBlockHeaderFeeder( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) - c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, vrfKey, bhfKey) require.NoError(t, app.Start(testutils.Context(t))) @@ -904,6 +910,8 @@ func testSingleConsumerForcedFulfillment( GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) @@ -1053,10 +1061,7 @@ func testSingleConsumerEIP150( vrfVersion vrfcommon.Version, nativePayment bool, ) { - callBackGasLimit := int64(2_500_000) // base callback gas. - eip150Fee := callBackGasLimit / 64 // premium needed for callWithExactGas - coordinatorFulfillmentOverhead := int64(90_000) // fixed gas used in coordinator fulfillment - gasLimit := callBackGasLimit + eip150Fee + coordinatorFulfillmentOverhead + callBackGasLimit := int64(2_500_000) // base callback gas. key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) @@ -1066,8 +1071,10 @@ func testSingleConsumerEIP150( Key: ptr(key1.EIP55Address), GasEstimator: v2.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, })(c, s) - c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(gasLimit)) + c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(3.5e6)) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1136,6 +1143,8 @@ func testSingleConsumerEIP150Revert( })(c, s) c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(gasLimit)) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1199,6 +1208,8 @@ func testSingleConsumerBigGasCallbackSandwich( })(c, s) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1319,6 +1330,8 @@ func testSingleConsumerMultipleGasLanes( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, cheapKey, expensiveKey) @@ -1434,6 +1447,8 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( GasEstimator: v2.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key) consumer := uni.reverter @@ -1505,6 +1520,8 @@ func testConsumerProxyHappyPath( GasEstimator: v2.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) consumerOwner := uni.neil @@ -1629,6 +1646,8 @@ func testMaliciousConsumer( c.EVM[0].GasEstimator.PriceDefault = assets.GWei(1) c.EVM[0].GasEstimator.FeeCapDefault = assets.GWei(1) c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) carol := uni.vrfConsumers[0] diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index e45e650dc8..1564f0f634 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -50,6 +50,7 @@ import ( v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" + "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -107,6 +108,10 @@ func newVRFCoordinatorV2PlusUniverse(t *testing.T, key ethkey.KeyV2, numConsumer vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalABI)) require.NoError(t, err) backend := cltest.NewSimulatedBackend(t, genesisData, gasLimit) + blockTime := time.UnixMilli(int64(backend.Blockchain().CurrentHeader().Time)) + err = backend.AdjustTime(time.Since(blockTime) - 24*time.Hour) + require.NoError(t, err) + backend.Commit() // Deploy link linkAddress, _, linkContract, err := link_token_interface.DeployLinkToken( sergey, backend) @@ -259,6 +264,10 @@ func newVRFCoordinatorV2PlusUniverse(t *testing.T, key ethkey.KeyV2, numConsumer require.NoError(t, err, "failed to set coordinator configuration") backend.Commit() + for i := 0; i < 200; i++ { + backend.Commit() + } + return coordinatorV2PlusUniverse{ coordinatorV2UniverseCommon: coordinatorV2UniverseCommon{ vrfConsumers: vrfConsumers, @@ -304,7 +313,6 @@ func newVRFCoordinatorV2PlusUniverse(t *testing.T, key ethkey.KeyV2, numConsumer } func TestVRFV2PlusIntegration_SingleConsumer_HappyPath_BatchFulfillment(t *testing.T) { - testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/BCF-2745") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) @@ -457,7 +465,7 @@ func TestVRFV2PlusIntegration_SingleConsumer_HappyPath(t *testing.T) { } func TestVRFV2PlusIntegration_SingleConsumer_EOA_Request(t *testing.T) { - testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/BCF-2744") + t.Skip("questionable value of this test") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) @@ -473,6 +481,7 @@ func TestVRFV2PlusIntegration_SingleConsumer_EOA_Request(t *testing.T) { } func TestVRFV2PlusIntegration_SingleConsumer_EOA_Request_Batching_Enabled(t *testing.T) { + t.Skip("questionable value of this test") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) @@ -488,7 +497,6 @@ func TestVRFV2PlusIntegration_SingleConsumer_EOA_Request_Batching_Enabled(t *tes } func TestVRFV2PlusIntegration_SingleConsumer_EIP150_HappyPath(t *testing.T) { - testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/VRF-589") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) @@ -1149,6 +1157,8 @@ func TestVRFV2PlusIntegration_Migration(t *testing.T) { })(c, s) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index c1376eafeb..74d923ce09 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -183,6 +183,10 @@ func newVRFCoordinatorV2Universe(t *testing.T, key ethkey.KeyV2, numConsumers in vrf_coordinator_v2.VRFCoordinatorV2ABI)) require.NoError(t, err) backend := cltest.NewSimulatedBackend(t, genesisData, gasLimit) + blockTime := time.UnixMilli(int64(backend.Blockchain().CurrentHeader().Time)) + err = backend.AdjustTime(time.Since(blockTime) - 24*time.Hour) + require.NoError(t, err) + backend.Commit() // Deploy link linkAddress, _, linkContract, err := link_token_interface.DeployLinkToken( sergey, backend) @@ -925,6 +929,7 @@ func TestVRFV2Integration_SingleConsumer_HappyPath(t *testing.T) { } func TestVRFV2Integration_SingleConsumer_EOA_Request(t *testing.T) { + t.Skip("questionable value of this test") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, ownerKey, 1) @@ -940,6 +945,7 @@ func TestVRFV2Integration_SingleConsumer_EOA_Request(t *testing.T) { } func TestVRFV2Integration_SingleConsumer_EOA_Request_Batching_Enabled(t *testing.T) { + t.Skip("questionable value of this test") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, ownerKey, 1) @@ -1217,6 +1223,8 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { })(c, s) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, ownerKey, 1) @@ -1452,7 +1460,10 @@ func simulatedOverrides(t *testing.T, defaultGasPrice *assets.Wei, ks ...toml.Ke if defaultGasPrice != nil { c.EVM[0].GasEstimator.PriceDefault = defaultGasPrice } - c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](2_000_000) + c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) + + c.Feature.LogPoller = ptr(true) + c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) c.EVM[0].HeadTracker.SamplingInterval = models.MustNewDuration(0) // Head sampling disabled diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index e0f8ff9a5b..5878bf5476 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -1,36 +1,22 @@ package v2 import ( - "cmp" "context" - "database/sql" "encoding/hex" - "fmt" - "math" "math/big" - "slices" "strings" "sync" "time" "github.com/avast/retry-go/v4" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rpc" - "github.com/google/uuid" "github.com/pkg/errors" - heaps "github.com/theodesp/go-heaps" "github.com/theodesp/go-heaps/pairing" - "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-common/pkg/services" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" @@ -45,12 +31,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils" - bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) var ( - _ log.Listener = &listenerV2{} _ job.ServiceCtx = &listenerV2{} coordinatorV2ABI = evmtypes.MustGetABI(vrf_coordinator_v2.VRFCoordinatorV2ABI) coordinatorV2PlusABI = evmtypes.MustGetABI(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalABI) @@ -78,22 +61,8 @@ const ( txMetaFieldSubId = "SubId" txMetaGlobalSubId = "GlobalSubId" - - CouldNotDetermineIfLogConsumedMsg = "Could not determine if log was already consumed" ) -type errPossiblyInsufficientFunds struct{} - -func (errPossiblyInsufficientFunds) Error() string { - return "Simulation errored, possibly insufficient funds. Request will remain unprocessed until funds are available" -} - -type errBlockhashNotInStore struct{} - -func (errBlockhashNotInStore) Error() string { - return "Blockhash not in store" -} - func New( cfg vrfcommon.Config, feeCfg vrfcommon.FeeConfig, @@ -108,63 +77,34 @@ func New( pipelineRunner pipeline.Runner, gethks keystore.Eth, job job.Job, - mailMon *utils.MailboxMonitor, - reqLogs *utils.Mailbox[log.Broadcast], reqAdded func(), - deduper *vrfcommon.LogDeduper, + inflightCache vrfcommon.InflightCache, + fulfillmentDeduper *vrfcommon.LogDeduper, ) job.ServiceCtx { return &listenerV2{ - cfg: cfg, - feeCfg: feeCfg, - l: logger.Sugared(l), - chain: chain, - chainID: chainID, - mailMon: mailMon, - coordinator: coordinator, - batchCoordinator: batchCoordinator, - vrfOwner: vrfOwner, - pipelineRunner: pipelineRunner, - job: job, - q: q, - gethks: gethks, - reqLogs: reqLogs, - chStop: make(services.StopChan), - reqAdded: reqAdded, - blockNumberToReqID: pairing.New(), - latestHeadMu: sync.RWMutex{}, - wg: &sync.WaitGroup{}, - aggregator: aggregator, - deduper: deduper, + cfg: cfg, + feeCfg: feeCfg, + l: logger.Sugared(l), + chain: chain, + chainID: chainID, + coordinator: coordinator, + batchCoordinator: batchCoordinator, + vrfOwner: vrfOwner, + pipelineRunner: pipelineRunner, + job: job, + q: q, + gethks: gethks, + chStop: make(chan struct{}), + reqAdded: reqAdded, + blockNumberToReqID: pairing.New(), + latestHeadMu: sync.RWMutex{}, + wg: &sync.WaitGroup{}, + aggregator: aggregator, + inflightCache: inflightCache, + fulfillmentLogDeduper: fulfillmentDeduper, } } -type pendingRequest struct { - confirmedAtBlock uint64 - req RandomWordsRequested - lb log.Broadcast - utcTimestamp time.Time - - // used for exponential backoff when retrying - attempts int - lastTry time.Time -} - -type vrfPipelineResult struct { - err error - // maxFee indicates how much juels (link) or wei (ether) would be paid for the VRF request - // if it were to be fulfilled at the maximum gas price (i.e gas lane gas price). - maxFee *big.Int - // fundsNeeded indicates a "minimum balance" in juels or wei that must be held in the - // subscription's account in order to fulfill the request. - fundsNeeded *big.Int - run *pipeline.Run - payload string - gasLimit uint32 - req pendingRequest - proof VRFProof - reqCommitment RequestCommitment -} - type listenerV2 struct { services.StateMachine cfg vrfcommon.Config @@ -172,7 +112,6 @@ type listenerV2 struct { l logger.SugaredLogger chain legacyevm.Chain chainID *big.Int - mailMon *utils.MailboxMonitor coordinator CoordinatorV2_X batchCoordinator batch_vrf_coordinator_v2.BatchVRFCoordinatorV2Interface @@ -182,19 +121,13 @@ type listenerV2 struct { job job.Job q pg.Q gethks keystore.Eth - reqLogs *utils.Mailbox[log.Broadcast] chStop services.StopChan - // We can keep these pending logs in memory because we - // only mark them confirmed once we send a corresponding fulfillment transaction. - // So on node restart in the middle of processing, the lb will resend them. - reqsMu sync.Mutex // Both the log listener and the request handler write to reqs - reqs []pendingRequest + reqAdded func() // A simple debug helper // Data structures for reorg attack protection // We want a map so we can do an O(1) count update every fulfillment log we get. - respCountMu sync.Mutex - respCount map[string]uint64 + respCount map[string]uint64 // This auxiliary heap is used when we need to purge the // respCount map - we repeatedly want to remove the minimum log. // You could use a sorted list if the completed logs arrive in order, but they may not. @@ -210,8 +143,14 @@ type listenerV2 struct { // aggregator client to get link/eth feed prices from chain. Can be nil for VRF V2 plus aggregator aggregator_v3_interface.AggregatorV3InterfaceInterface - // deduper prevents processing duplicate requests from the log broadcaster. - deduper *vrfcommon.LogDeduper + // fulfillmentLogDeduper prevents re-processing fulfillment logs. + // fulfillment logs are used to increment counts in the respCount map + // and to update the blockNumberToReqID heap. + fulfillmentLogDeduper *vrfcommon.LogDeduper + + // inflightCache is a cache of in-flight requests, used to prevent + // re-processing of requests that are in-flight or already fulfilled. + inflightCache vrfcommon.InflightCache } func (lsn *listenerV2) HealthReport() map[string]error { @@ -234,7 +173,7 @@ func (lsn *listenerV2) Start(ctx context.Context) error { } if err != nil { lsn.l.Criticalw("Error getting coordinator config for gas limit check, starting anyway.", "err", err) - } else if conf.MaxGasLimit()+(GasProofVerification*2) > uint32(gasLimit) { + } else if conf.MaxGasLimit()+(GasProofVerification*2) > gasLimit { lsn.l.Criticalw("Node gas limit setting may not be high enough to fulfill all requests; it should be increased. Starting anyway.", "currentGasLimit", gasLimit, "neededGasLimit", conf.MaxGasLimit()+(GasProofVerification*2), @@ -244,24 +183,6 @@ func (lsn *listenerV2) Start(ctx context.Context) error { spec := job.LoadDefaultVRFPollPeriod(*lsn.job.VRFSpec) - unsubscribeLogs := lsn.chain.LogBroadcaster().Register(lsn, log.ListenerOpts{ - Contract: lsn.coordinator.Address(), - ParseLog: lsn.coordinator.ParseLog, - LogsWithTopics: lsn.coordinator.LogsWithTopics(spec.PublicKey.MustHash()), - // Specify a min incoming confirmations of 1 so that we can receive a request log - // right away. We set the real number of confirmations on a per-request basis in - // the getConfirmedAt method. - MinIncomingConfirmations: 1, - ReplayStartedCallback: lsn.ReplayStartedCallback, - }) - - latestHead, unsubscribeHeadBroadcaster := lsn.chain.HeadBroadcaster().Subscribe(lsn) - if latestHead != nil { - lsn.setLatestHead(latestHead) - } - - lsn.respCountMu.Lock() - defer lsn.respCountMu.Unlock() var respCount map[string]uint64 respCount, err = lsn.GetStartingResponseCountsV2(ctx) if err != nil { @@ -269,19 +190,13 @@ func (lsn *listenerV2) Start(ctx context.Context) error { } lsn.respCount = respCount - // Log listener gathers request logs - lsn.wg.Add(1) - go func() { - lsn.runLogListener([]func(){unsubscribeLogs, unsubscribeHeadBroadcaster}, spec.MinIncomingConfirmations, lsn.wg) - }() - - // Request handler periodically computes a set of logs which can be fulfilled. + // Log listener gathers request logs and processes them lsn.wg.Add(1) go func() { - lsn.runRequestHandler(spec.PollPeriod, lsn.wg) + defer lsn.wg.Done() + lsn.runLogListener(spec.PollPeriod, spec.MinIncomingConfirmations) }() - lsn.mailMon.Monitor(lsn.reqLogs, "VRFListenerV2", "RequestLogs", fmt.Sprint(lsn.job.ID)) return nil }) } @@ -326,1466 +241,27 @@ func (lsn *listenerV2) GetStartingResponseCountsV2(ctx context.Context) (respCou return respCounts, nil } -func (lsn *listenerV2) setLatestHead(head *evmtypes.Head) { +func (lsn *listenerV2) setLatestHead(head logpoller.LogPollerBlock) { lsn.latestHeadMu.Lock() defer lsn.latestHeadMu.Unlock() - num := uint64(head.Number) + num := uint64(head.BlockNumber) if num > lsn.latestHeadNumber { lsn.latestHeadNumber = num } } -// OnNewLongestChain is called by the head broadcaster when a new head is available. -func (lsn *listenerV2) OnNewLongestChain(ctx context.Context, head *evmtypes.Head) { - lsn.setLatestHead(head) -} - func (lsn *listenerV2) getLatestHead() uint64 { lsn.latestHeadMu.RLock() defer lsn.latestHeadMu.RUnlock() - return uint64(lsn.latestHeadNumber) -} - -// Returns all the confirmed logs from -// the pending queue by subscription -func (lsn *listenerV2) getAndRemoveConfirmedLogsBySub(latestHead uint64) map[string][]pendingRequest { - lsn.reqsMu.Lock() - defer lsn.reqsMu.Unlock() - vrfcommon.UpdateQueueSize(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version(), uniqueReqs(lsn.reqs)) - var toProcess = make(map[string][]pendingRequest) - var toKeep []pendingRequest - for i := 0; i < len(lsn.reqs); i++ { - if r := lsn.reqs[i]; lsn.ready(r, latestHead) { - toProcess[r.req.SubID().String()] = append(toProcess[r.req.SubID().String()], r) - } else { - toKeep = append(toKeep, lsn.reqs[i]) - } - } - lsn.reqs = toKeep - return toProcess -} - -func (lsn *listenerV2) ready(req pendingRequest, latestHead uint64) bool { - // Request is not eligible for fulfillment yet - if req.confirmedAtBlock > latestHead { - return false - } - - if lsn.job.VRFSpec.BackoffInitialDelay == 0 || req.attempts == 0 { - // Backoff is disabled, or this is the first try - return true - } - - return time.Now().UTC().After( - nextTry( - req.attempts, - lsn.job.VRFSpec.BackoffInitialDelay, - lsn.job.VRFSpec.BackoffMaxDelay, - req.lastTry)) -} - -func nextTry(retries int, initial, max time.Duration, last time.Time) time.Time { - expBackoffFactor := math.Pow(backoffFactor, float64(retries-1)) - - var delay time.Duration - if expBackoffFactor > float64(max/initial) { - delay = max - } else { - delay = time.Duration(float64(initial) * expBackoffFactor) - } - return last.Add(delay) -} - -// Remove all entries 10000 blocks or older -// to avoid a memory leak. -func (lsn *listenerV2) pruneConfirmedRequestCounts() { - lsn.respCountMu.Lock() - defer lsn.respCountMu.Unlock() - min := lsn.blockNumberToReqID.FindMin() - for min != nil { - m := min.(fulfilledReqV2) - if m.blockNumber > (lsn.getLatestHead() - 10000) { - break - } - delete(lsn.respCount, m.reqID) - lsn.blockNumberToReqID.DeleteMin() - min = lsn.blockNumberToReqID.FindMin() - } -} - -// Determine a set of logs that are confirmed -// and the subscription has sufficient balance to fulfill, -// given a eth call with the max gas price. -// Note we have to consider the pending reqs already in the txm as already "spent" link or native, -// using a max link or max native consumed in their metadata. -// A user will need a minBalance capable of fulfilling a single req at the max gas price or nothing will happen. -// This is acceptable as users can choose different keyhashes which have different max gas prices. -// Other variables which can change the bill amount between our eth call simulation and tx execution: -// - Link/eth price fluctuation -// - Falling back to BHS -// However the likelihood is vanishingly small as -// 1) the window between simulation and tx execution is tiny. -// 2) the max gas price provides a very large buffer most of the time. -// Its easier to optimistically assume it will go though and in the rare case of a reversion -// we simply retry TODO: follow up where if we see a fulfillment revert, return log to the queue. -func (lsn *listenerV2) processPendingVRFRequests(ctx context.Context) { - confirmed := lsn.getAndRemoveConfirmedLogsBySub(lsn.getLatestHead()) - processed := make(map[string]struct{}) - start := time.Now() - - // Add any unprocessed requests back to lsn.reqs after request processing is complete. - defer func() { - var toKeep []pendingRequest - for _, subReqs := range confirmed { - for _, req := range subReqs { - if _, ok := processed[req.req.RequestID().String()]; !ok { - req.attempts++ - req.lastTry = time.Now().UTC() - toKeep = append(toKeep, req) - if lsn.job.VRFSpec.BackoffInitialDelay != 0 { - lsn.l.Infow("Request failed, next retry will be delayed.", - "reqID", req.req.RequestID().String(), - "subID", req.req.SubID(), - "attempts", req.attempts, - "lastTry", req.lastTry.String(), - "nextTry", nextTry( - req.attempts, - lsn.job.VRFSpec.BackoffInitialDelay, - lsn.job.VRFSpec.BackoffMaxDelay, - req.lastTry)) - } - } else { - lsn.markLogAsConsumed(req.lb) - } - } - } - // There could be logs accumulated to this slice while request processor is running, - // so we merged the new ones with the ones that need to be requeued. - lsn.reqsMu.Lock() - lsn.reqs = append(lsn.reqs, toKeep...) - lsn.l.Infow("Finished processing pending requests", - "totalProcessed", len(processed), - "totalFailed", len(toKeep), - "total", len(lsn.reqs), - "time", time.Since(start).String()) - lsn.reqsMu.Unlock() // unlock here since len(lsn.reqs) is a read, to avoid a data race. - }() - - if len(confirmed) == 0 { - lsn.l.Infow("No pending requests ready for processing") - return - } - for subID, reqs := range confirmed { - l := lsn.l.With("subID", subID, "startTime", time.Now(), "numReqsForSub", len(reqs)) - // Get the balance of the subscription and also it's active status. - // The reason we need both is that we cannot determine if a subscription - // is active solely by it's balance, since an active subscription could legitimately - // have a zero balance. - var ( - startLinkBalance *big.Int - startEthBalance *big.Int - subIsActive bool - ) - sID, ok := new(big.Int).SetString(subID, 10) - if !ok { - l.Criticalw("Unable to convert %s to Int", subID) - continue - } - sub, err := lsn.coordinator.GetSubscription(&bind.CallOpts{ - Context: ctx}, sID) - - if err != nil { - if strings.Contains(err.Error(), "execution reverted") { - // "execution reverted" indicates that the subscription no longer exists. - // We can no longer just mark these as processed and continue, - // since it could be that the subscription was canceled while there - // were still unfulfilled requests. - // The simplest approach to handle this is to enter the processRequestsPerSub - // loop rather than create a bunch of largely duplicated code - // to handle this specific situation, since we need to run the pipeline to get - // the VRF proof, abi-encode it, etc. - l.Warnw("Subscription not found - setting start balance to zero", "subID", subID, "err", err) - startLinkBalance = big.NewInt(0) - } else { - // Most likely this is an RPC error, so we re-try later. - l.Errorw("Unable to read subscription balance", "err", err) - continue - } - } else { - // Happy path - sub is active. - startLinkBalance = sub.Balance() - if sub.Version() == vrfcommon.V2Plus { - startEthBalance = sub.NativeBalance() - } - subIsActive = true - } - - // Sort requests in ascending order by CallbackGasLimit - // so that we process the "cheapest" requests for each subscription - // first. This allows us to break out of the processing loop as early as possible - // in the event that a subscription is too underfunded to have it's - // requests processed. - slices.SortFunc(reqs, func(a, b pendingRequest) int { - return cmp.Compare(a.req.CallbackGasLimit(), b.req.CallbackGasLimit()) - }) - - p := lsn.processRequestsPerSub(ctx, sID, startLinkBalance, startEthBalance, reqs, subIsActive) - for reqID := range p { - processed[reqID] = struct{}{} - } - } - lsn.pruneConfirmedRequestCounts() -} - -// MaybeSubtractReservedLink figures out how much LINK is reserved for other VRF requests that -// have not been fully confirmed yet on-chain, and subtracts that from the given startBalance, -// and returns that value if there are no errors. -func (lsn *listenerV2) MaybeSubtractReservedLink(ctx context.Context, startBalance *big.Int, chainID *big.Int, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { - var metaField string - if vrfVersion == vrfcommon.V2Plus { - metaField = txMetaGlobalSubId - } else if vrfVersion == vrfcommon.V2 { - metaField = txMetaFieldSubId - } else { - return nil, errors.Errorf("unsupported vrf version %s", vrfVersion) - } - - txes, err := lsn.chain.TxManager().FindTxesByMetaFieldAndStates(ctx, metaField, subID.String(), reserveEthLinkQueryStates, chainID) - if err != nil && !errors.Is(err, sql.ErrNoRows) { - return nil, errors.Wrap(err, "TXM FindTxesByMetaFieldAndStates failed") - } - - reservedLinkSum := big.NewInt(0) - // Aggregate non-null MaxLink from all txes returned - for _, tx := range txes { - var meta *txmgrtypes.TxMeta[common.Address, common.Hash] - meta, err = tx.GetMeta() - if err != nil { - return nil, errors.Wrap(err, "GetMeta for Tx failed") - } - if meta != nil && meta.MaxLink != nil { - txMaxLink, success := new(big.Int).SetString(*meta.MaxLink, 10) - if !success { - return nil, fmt.Errorf("converting reserved LINK %s", *meta.MaxLink) - } - - reservedLinkSum.Add(reservedLinkSum, txMaxLink) - } - } - - return new(big.Int).Sub(startBalance, reservedLinkSum), nil -} - -// MaybeSubtractReservedEth figures out how much ether is reserved for other VRF requests that -// have not been fully confirmed yet on-chain, and subtracts that from the given startBalance, -// and returns that value if there are no errors. -func (lsn *listenerV2) MaybeSubtractReservedEth(ctx context.Context, startBalance *big.Int, chainID *big.Int, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { - var metaField string - if vrfVersion == vrfcommon.V2Plus { - metaField = txMetaGlobalSubId - } else if vrfVersion == vrfcommon.V2 { - // native payment is not supported for v2, so returning 0 reserved ETH - return big.NewInt(0), nil - } else { - return nil, errors.Errorf("unsupported vrf version %s", vrfVersion) - } - txes, err := lsn.chain.TxManager().FindTxesByMetaFieldAndStates(ctx, metaField, subID.String(), reserveEthLinkQueryStates, chainID) - if err != nil && !errors.Is(err, sql.ErrNoRows) { - return nil, errors.Wrap(err, "TXM FindTxesByMetaFieldAndStates failed") - } - - reservedEthSum := big.NewInt(0) - // Aggregate non-null MaxEth from all txes returned - for _, tx := range txes { - var meta *txmgrtypes.TxMeta[common.Address, common.Hash] - meta, err = tx.GetMeta() - if err != nil { - return nil, errors.Wrap(err, "GetMeta for Tx failed") - } - if meta != nil && meta.MaxEth != nil { - txMaxEth, success := new(big.Int).SetString(*meta.MaxEth, 10) - if !success { - return nil, fmt.Errorf("converting reserved ETH %s", *meta.MaxEth) - } - - reservedEthSum.Add(reservedEthSum, txMaxEth) - } - } - - if startBalance != nil { - return new(big.Int).Sub(startBalance, reservedEthSum), nil - } - return big.NewInt(0), nil -} - -type fulfilledReqV2 struct { - blockNumber uint64 - reqID string -} - -func (a fulfilledReqV2) Compare(b heaps.Item) int { - a1 := a - a2 := b.(fulfilledReqV2) - switch { - case a1.blockNumber > a2.blockNumber: - return 1 - case a1.blockNumber < a2.blockNumber: - return -1 - default: - return 0 - } -} - -func (lsn *listenerV2) processRequestsPerSubBatchHelper( - ctx context.Context, - subID *big.Int, - startBalance *big.Int, - startBalanceNoReserved *big.Int, - reqs []pendingRequest, - subIsActive bool, - nativePayment bool, -) (processed map[string]struct{}) { - start := time.Now() - processed = make(map[string]struct{}) - - // Base the max gas for a batch on the max gas limit for a single callback. - // Since the max gas limit for a single callback is usually quite large already, - // we probably don't want to exceed it too much so that we can reliably get - // batch fulfillments included, while also making sure that the biggest gas guzzler - // callbacks are included. - config, err := lsn.coordinator.GetConfig(&bind.CallOpts{ - Context: ctx, - }) - if err != nil { - lsn.l.Errorw("Couldn't get config from coordinator", "err", err) - return processed - } - - // Add very conservative upper bound estimate on verification costs. - batchMaxGas := uint32(config.MaxGasLimit() + 400_000) - - l := lsn.l.With( - "subID", subID, - "eligibleSubReqs", len(reqs), - "startBalance", startBalance.String(), - "startBalanceNoReserved", startBalanceNoReserved.String(), - "batchMaxGas", batchMaxGas, - "subIsActive", subIsActive, - "nativePayment", nativePayment, - ) - - defer func() { - l.Infow("Finished processing for sub", - "endBalance", startBalanceNoReserved.String(), - "totalProcessed", len(processed), - "totalUnique", uniqueReqs(reqs), - "time", time.Since(start).String()) - }() - - l.Infow("Processing requests for subscription with batching") - - // Check for already consumed or expired reqs - unconsumed, processedReqs := lsn.getUnconsumed(l, reqs) - for _, reqID := range processedReqs { - processed[reqID] = struct{}{} - } - - // Process requests in chunks in order to kick off as many jobs - // as configured in parallel. Then we can combine into fulfillment - // batches afterwards. - for chunkStart := 0; chunkStart < len(unconsumed); chunkStart += int(lsn.job.VRFSpec.ChunkSize) { - chunkEnd := chunkStart + int(lsn.job.VRFSpec.ChunkSize) - if chunkEnd > len(unconsumed) { - chunkEnd = len(unconsumed) - } - chunk := unconsumed[chunkStart:chunkEnd] - - var unfulfilled []pendingRequest - alreadyFulfilled, err := lsn.checkReqsFulfilled(ctx, l, chunk) - if errors.Is(err, context.Canceled) { - l.Infow("Context canceled, stopping request processing", "err", err) - return processed - } else if err != nil { - l.Errorw("Error checking for already fulfilled requests, proceeding anyway", "err", err) - } - for i, a := range alreadyFulfilled { - if a { - processed[chunk[i].req.RequestID().String()] = struct{}{} - } else { - unfulfilled = append(unfulfilled, chunk[i]) - } - } - - // All fromAddresses passed to the VRFv2 job have the same KeySpecific-MaxPrice value. - fromAddresses := lsn.fromAddresses() - maxGasPriceWei := lsn.feeCfg.PriceMaxKey(fromAddresses[0]) - - // Cases: - // 1. Never simulated: in this case, we want to observe the time until simulated - // on the utcTimestamp field of the pending request. - // 2. Simulated before: in this case, lastTry will be set to a non-zero time value, - // in which case we'd want to use that as a relative point from when we last tried - // the request. - observeRequestSimDuration(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version(), unfulfilled) - - pipelines := lsn.runPipelines(ctx, l, maxGasPriceWei, unfulfilled) - batches := newBatchFulfillments(batchMaxGas, lsn.coordinator.Version()) - outOfBalance := false - for _, p := range pipelines { - ll := l.With("reqID", p.req.req.RequestID().String(), - "txHash", p.req.req.Raw().TxHash, - "maxGasPrice", maxGasPriceWei.String(), - "fundsNeeded", p.fundsNeeded.String(), - "maxFee", p.maxFee.String(), - "gasLimit", p.gasLimit, - "attempts", p.req.attempts, - "remainingBalance", startBalanceNoReserved.String(), - "consumerAddress", p.req.req.Sender(), - "blockNumber", p.req.req.Raw().BlockNumber, - "blockHash", p.req.req.Raw().BlockHash, - ) - fromAddresses := lsn.fromAddresses() - fromAddress, err := lsn.gethks.GetRoundRobinAddress(lsn.chainID, fromAddresses...) - if err != nil { - l.Errorw("Couldn't get next from address", "err", err) - continue - } - ll = ll.With("fromAddress", fromAddress) - - if p.err != nil { - if errors.Is(p.err, errBlockhashNotInStore{}) { - // Running the blockhash store feeder in backwards mode will be required to - // resolve this. - ll.Criticalw("Pipeline error", "err", p.err) - } else { - ll.Errorw("Pipeline error", "err", p.err) - if !subIsActive { - ll.Warnw("Force-fulfilling a request with insufficient funds on a cancelled sub") - etx, err := lsn.enqueueForceFulfillment(ctx, p, fromAddress) - if err != nil { - ll.Errorw("Error enqueuing force-fulfillment, re-queueing request", "err", err) - continue - } - ll.Infow("Successfully enqueued force-fulfillment", "ethTxID", etx.ID) - processed[p.req.req.RequestID().String()] = struct{}{} - - // Need to put a continue here, otherwise the next if statement will be hit - // and we'd break out of the loop prematurely. - // If a sub is canceled, we want to force-fulfill ALL of it's pending requests - // before saying we're done with it. - continue - } - - if startBalanceNoReserved.Cmp(p.fundsNeeded) < 0 && errors.Is(p.err, errPossiblyInsufficientFunds{}) { - ll.Infow("Insufficient balance to fulfill a request based on estimate, breaking", "err", p.err) - outOfBalance = true - - // break out of this inner loop to process the currently constructed batch - break - } - - // Ensure consumer is valid, otherwise drop the request. - if !lsn.isConsumerValidAfterFinalityDepthElapsed(ctx, p.req) { - lsn.l.Infow( - "Dropping request that was made by an invalid consumer.", - "consumerAddress", p.req.req.Sender(), - "reqID", p.req.req.RequestID(), - "blockNumber", p.req.req.Raw().BlockNumber, - "blockHash", p.req.req.Raw().BlockHash, - ) - lsn.markLogAsConsumed(p.req.lb) - } - } - continue - } - - if startBalanceNoReserved.Cmp(p.maxFee) < 0 { - // Insufficient funds, have to wait for a user top up. - // Break out of the loop now and process what we are able to process - // in the constructed batches. - ll.Infow("Insufficient balance to fulfill a request, breaking") - break - } - - batches.addRun(p, fromAddress) - - startBalanceNoReserved.Sub(startBalanceNoReserved, p.maxFee) - } - - var processedRequestIDs []string - for _, batch := range batches.fulfillments { - l.Debugw("Processing batch", "batchSize", len(batch.proofs)) - p := lsn.processBatch(l, subID, startBalanceNoReserved, batchMaxGas, batch, batch.fromAddress) - processedRequestIDs = append(processedRequestIDs, p...) - } - - for _, reqID := range processedRequestIDs { - processed[reqID] = struct{}{} - } - - // outOfBalance is set to true if the current sub we are processing - // has run out of funds to process any remaining requests. After enqueueing - // this constructed batch, we break out of this outer loop in order to - // avoid unnecessarily processing the remaining requests. - if outOfBalance { - break - } - } - - return -} - -func (lsn *listenerV2) processRequestsPerSubBatch( - ctx context.Context, - subID *big.Int, - startLinkBalance *big.Int, - startEthBalance *big.Int, - reqs []pendingRequest, - subIsActive bool, -) map[string]struct{} { - var processed = make(map[string]struct{}) - startBalanceNoReserveLink, err := lsn.MaybeSubtractReservedLink( - ctx, startLinkBalance, lsn.chainID, subID, lsn.coordinator.Version()) - if err != nil { - lsn.l.Errorw("Couldn't get reserved LINK for subscription", "sub", reqs[0].req.SubID(), "err", err) - return processed - } - startBalanceNoReserveEth, err := lsn.MaybeSubtractReservedEth( - ctx, startEthBalance, lsn.chainID, subID, lsn.coordinator.Version()) - if err != nil { - lsn.l.Errorw("Couldn't get reserved ether for subscription", "sub", reqs[0].req.SubID(), "err", err) - return processed - } - - // Split the requests into native and LINK requests. - var ( - nativeRequests []pendingRequest - linkRequests []pendingRequest - ) - for _, req := range reqs { - if req.req.NativePayment() { - nativeRequests = append(nativeRequests, req) - } else { - linkRequests = append(linkRequests, req) - } - } - // process the native and link requests in parallel - var wg sync.WaitGroup - var nativeProcessed, linkProcessed map[string]struct{} - wg.Add(2) - go func() { - defer wg.Done() - nativeProcessed = lsn.processRequestsPerSubBatchHelper(ctx, subID, startEthBalance, startBalanceNoReserveEth, nativeRequests, subIsActive, true) - }() - go func() { - defer wg.Done() - linkProcessed = lsn.processRequestsPerSubBatchHelper(ctx, subID, startLinkBalance, startBalanceNoReserveLink, linkRequests, subIsActive, false) - }() - wg.Wait() - // combine the processed link and native requests into the processed map - for k, v := range nativeProcessed { - processed[k] = v - } - for k, v := range linkProcessed { - processed[k] = v - } - - return processed -} - -// enqueueForceFulfillment enqueues a forced fulfillment through the -// VRFOwner contract. It estimates gas again on the transaction due -// to the extra steps taken within VRFOwner.fulfillRandomWords. -func (lsn *listenerV2) enqueueForceFulfillment( - ctx context.Context, - p vrfPipelineResult, - fromAddress common.Address, -) (etx txmgr.Tx, err error) { - if lsn.job.VRFSpec.VRFOwnerAddress == nil { - err = errors.New("vrf owner address not set in job spec, recreate job and provide it to force-fulfill") - return - } - - if p.payload == "" { - // should probably never happen - // a critical log will be logged if this is the case in simulateFulfillment - err = errors.New("empty payload in vrfPipelineResult") - return - } - - // fulfill the request through the VRF owner - err = lsn.q.Transaction(func(tx pg.Queryer) error { - if err = lsn.chain.LogBroadcaster().MarkConsumed(p.req.lb, pg.WithQueryer(tx)); err != nil { - return err - } - - lsn.l.Infow("VRFOwner.fulfillRandomWords vs. VRFCoordinatorV2.fulfillRandomWords", - "vrf_owner.fulfillRandomWords", hexutil.Encode(vrfOwnerABI.Methods["fulfillRandomWords"].ID), - "vrf_coordinator_v2.fulfillRandomWords", hexutil.Encode(coordinatorV2ABI.Methods["fulfillRandomWords"].ID), - ) - - vrfOwnerAddress1 := lsn.vrfOwner.Address() - vrfOwnerAddressSpec := lsn.job.VRFSpec.VRFOwnerAddress.Address() - lsn.l.Infow("addresses diff", "wrapper_address", vrfOwnerAddress1, "spec_address", vrfOwnerAddressSpec) - - lsn.l.Infow("fulfillRandomWords payload", "proof", p.proof, "commitment", p.reqCommitment.Get(), "payload", p.payload) - txData := hexutil.MustDecode(p.payload) - if err != nil { - return errors.Wrap(err, "abi pack VRFOwner.fulfillRandomWords") - } - estimateGasLimit, err := lsn.chain.Client().EstimateGas(ctx, ethereum.CallMsg{ - From: fromAddress, - To: &vrfOwnerAddressSpec, - Data: txData, - }) - if err != nil { - return errors.Wrap(err, "failed to estimate gas on VRFOwner.fulfillRandomWords") - } - - lsn.l.Infow("Estimated gas limit on force fulfillment", - "estimateGasLimit", estimateGasLimit, "pipelineGasLimit", p.gasLimit) - if estimateGasLimit < uint64(p.gasLimit) { - estimateGasLimit = uint64(p.gasLimit) - } - - requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) - subID := p.req.req.SubID() - requestTxHash := p.req.req.Raw().TxHash - etx, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ - FromAddress: fromAddress, - ToAddress: lsn.vrfOwner.Address(), - EncodedPayload: txData, - FeeLimit: uint32(estimateGasLimit), - Strategy: txmgrcommon.NewSendEveryStrategy(), - Meta: &txmgr.TxMeta{ - RequestID: &requestID, - SubID: ptr(subID.Uint64()), - RequestTxHash: &requestTxHash, - // No max link since simulation failed - }, - }) - return err - }) - return -} - -// For an errored pipeline run, wait until the finality depth of the chain to have elapsed, -// then check if the failing request is being called by an invalid sender. Return false if this is the case, -// otherwise true. -func (lsn *listenerV2) isConsumerValidAfterFinalityDepthElapsed(ctx context.Context, req pendingRequest) bool { - latestHead := lsn.getLatestHead() - if latestHead-req.req.Raw().BlockNumber > uint64(lsn.cfg.FinalityDepth()) { - code, err := lsn.chain.Client().CodeAt(ctx, req.req.Sender(), big.NewInt(int64(latestHead))) - if err != nil { - lsn.l.Warnw("Failed to fetch contract code", "err", err) - return true // error fetching code, give the benefit of doubt to the consumer - } - if len(code) == 0 { - return false // invalid consumer - } - } - - return true // valid consumer, or finality depth has not elapsed -} - -// processRequestsPerSubHelper processes a set of pending requests for the provided sub id. -// It returns a set of request IDs that were processed. -// Note that the provided startBalanceNoReserve is the balance of the subscription -// minus any pending requests that have already been processed and not yet fulfilled onchain. -func (lsn *listenerV2) processRequestsPerSubHelper( - ctx context.Context, - subID *big.Int, - startBalance *big.Int, - startBalanceNoReserved *big.Int, - reqs []pendingRequest, - subIsActive bool, - nativePayment bool, -) (processed map[string]struct{}) { - start := time.Now() - processed = make(map[string]struct{}) - - l := lsn.l.With( - "subID", subID, - "eligibleSubReqs", len(reqs), - "startBalance", startBalance.String(), - "startBalanceNoReserved", startBalanceNoReserved.String(), - "subIsActive", subIsActive, - "nativePayment", nativePayment, - ) - - defer func() { - l.Infow("Finished processing for sub", - "endBalance", startBalanceNoReserved.String(), - "totalProcessed", len(processed), - "totalUnique", uniqueReqs(reqs), - "time", time.Since(start).String()) - }() - - l.Infow("Processing requests for subscription") - - // Check for already consumed or expired reqs - unconsumed, processedReqs := lsn.getUnconsumed(l, reqs) - for _, reqID := range processedReqs { - processed[reqID] = struct{}{} - } - - // Process requests in chunks - for chunkStart := 0; chunkStart < len(unconsumed); chunkStart += int(lsn.job.VRFSpec.ChunkSize) { - chunkEnd := chunkStart + int(lsn.job.VRFSpec.ChunkSize) - if chunkEnd > len(unconsumed) { - chunkEnd = len(unconsumed) - } - chunk := unconsumed[chunkStart:chunkEnd] - - var unfulfilled []pendingRequest - alreadyFulfilled, err := lsn.checkReqsFulfilled(ctx, l, chunk) - if errors.Is(err, context.Canceled) { - l.Infow("Context canceled, stopping request processing", "err", err) - return processed - } else if err != nil { - l.Errorw("Error checking for already fulfilled requests, proceeding anyway", "err", err) - } - for i, a := range alreadyFulfilled { - if a { - processed[chunk[i].req.RequestID().String()] = struct{}{} - } else { - unfulfilled = append(unfulfilled, chunk[i]) - } - } - - // All fromAddresses passed to the VRFv2 job have the same KeySpecific-MaxPrice value. - fromAddresses := lsn.fromAddresses() - maxGasPriceWei := lsn.feeCfg.PriceMaxKey(fromAddresses[0]) - observeRequestSimDuration(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version(), unfulfilled) - pipelines := lsn.runPipelines(ctx, l, maxGasPriceWei, unfulfilled) - for _, p := range pipelines { - ll := l.With("reqID", p.req.req.RequestID().String(), - "txHash", p.req.req.Raw().TxHash, - "maxGasPrice", maxGasPriceWei.String(), - "fundsNeeded", p.fundsNeeded.String(), - "maxFee", p.maxFee.String(), - "gasLimit", p.gasLimit, - "attempts", p.req.attempts, - "remainingBalance", startBalanceNoReserved.String(), - "consumerAddress", p.req.req.Sender(), - "blockNumber", p.req.req.Raw().BlockNumber, - "blockHash", p.req.req.Raw().BlockHash, - ) - fromAddress, err := lsn.gethks.GetRoundRobinAddress(lsn.chainID, fromAddresses...) - if err != nil { - l.Errorw("Couldn't get next from address", "err", err) - continue - } - ll = ll.With("fromAddress", fromAddress) - - if p.err != nil { - if errors.Is(p.err, errBlockhashNotInStore{}) { - // Running the blockhash store feeder in backwards mode will be required to - // resolve this. - ll.Criticalw("Pipeline error", "err", p.err) - } else { - ll.Errorw("Pipeline error", "err", p.err) - - if !subIsActive { - lsn.l.Warnw("Force-fulfilling a request with insufficient funds on a cancelled sub") - etx, err2 := lsn.enqueueForceFulfillment(ctx, p, fromAddress) - if err2 != nil { - ll.Errorw("Error enqueuing force-fulfillment, re-queueing request", "err", err2) - continue - } - ll.Infow("Enqueued force-fulfillment", "ethTxID", etx.ID) - processed[p.req.req.RequestID().String()] = struct{}{} - - // Need to put a continue here, otherwise the next if statement will be hit - // and we'd break out of the loop prematurely. - // If a sub is canceled, we want to force-fulfill ALL of it's pending requests - // before saying we're done with it. - continue - } - - if startBalanceNoReserved.Cmp(p.fundsNeeded) < 0 { - ll.Infow("Insufficient balance to fulfill a request based on estimate, returning", "err", p.err) - return processed - } - - // Ensure consumer is valid, otherwise drop the request. - if !lsn.isConsumerValidAfterFinalityDepthElapsed(ctx, p.req) { - lsn.l.Infow( - "Dropping request that was made by an invalid consumer.", - "consumerAddress", p.req.req.Sender(), - "reqID", p.req.req.RequestID(), - "blockNumber", p.req.req.Raw().BlockNumber, - "blockHash", p.req.req.Raw().BlockHash, - ) - lsn.markLogAsConsumed(p.req.lb) - } - } - continue - } - - if startBalanceNoReserved.Cmp(p.maxFee) < 0 { - // Insufficient funds, have to wait for a user top up. Leave it unprocessed for now - ll.Infow("Insufficient balance to fulfill a request, returning") - return processed - } - - ll.Infow("Enqueuing fulfillment") - var transaction txmgr.Tx - err = lsn.q.Transaction(func(tx pg.Queryer) error { - if err = lsn.pipelineRunner.InsertFinishedRun(p.run, true, pg.WithQueryer(tx)); err != nil { - return err - } - if err = lsn.chain.LogBroadcaster().MarkConsumed(p.req.lb, pg.WithQueryer(tx)); err != nil { - return err - } - - var maxLink, maxEth *string - tmp := p.maxFee.String() - if p.reqCommitment.NativePayment() { - maxEth = &tmp - } else { - maxLink = &tmp - } - var ( - txMetaSubID *uint64 - txMetaGlobalSubID *string - ) - if lsn.coordinator.Version() == vrfcommon.V2Plus { - txMetaGlobalSubID = ptr(p.req.req.SubID().String()) - } else if lsn.coordinator.Version() == vrfcommon.V2 { - txMetaSubID = ptr(p.req.req.SubID().Uint64()) - } - requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) - coordinatorAddress := lsn.coordinator.Address() - requestTxHash := p.req.req.Raw().TxHash - transaction, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ - FromAddress: fromAddress, - ToAddress: lsn.coordinator.Address(), - EncodedPayload: hexutil.MustDecode(p.payload), - FeeLimit: p.gasLimit, - Meta: &txmgr.TxMeta{ - RequestID: &requestID, - MaxLink: maxLink, - MaxEth: maxEth, - SubID: txMetaSubID, - GlobalSubID: txMetaGlobalSubID, - RequestTxHash: &requestTxHash, - }, - Strategy: txmgrcommon.NewSendEveryStrategy(), - Checker: txmgr.TransmitCheckerSpec{ - CheckerType: lsn.transmitCheckerType(), - VRFCoordinatorAddress: &coordinatorAddress, - VRFRequestBlockNumber: new(big.Int).SetUint64(p.req.req.Raw().BlockNumber), - }, - }) - return err - }) - if err != nil { - ll.Errorw("Error enqueuing fulfillment, requeuing request", "err", err) - continue - } - ll.Infow("Enqueued fulfillment", "ethTxID", transaction.GetID()) - - // If we successfully enqueued for the txm, subtract that balance - // And loop to attempt to enqueue another fulfillment - startBalanceNoReserved.Sub(startBalanceNoReserved, p.maxFee) - processed[p.req.req.RequestID().String()] = struct{}{} - vrfcommon.IncProcessedReqs(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version()) - } - } - - return -} - -func (lsn *listenerV2) transmitCheckerType() txmgrtypes.TransmitCheckerType { - if lsn.coordinator.Version() == vrfcommon.V2 { - return txmgr.TransmitCheckerTypeVRFV2 - } - return txmgr.TransmitCheckerTypeVRFV2Plus -} - -func (lsn *listenerV2) processRequestsPerSub( - ctx context.Context, - subID *big.Int, - startLinkBalance *big.Int, - startEthBalance *big.Int, - reqs []pendingRequest, - subIsActive bool, -) map[string]struct{} { - if lsn.job.VRFSpec.BatchFulfillmentEnabled && lsn.batchCoordinator != nil { - return lsn.processRequestsPerSubBatch(ctx, subID, startLinkBalance, startEthBalance, reqs, subIsActive) - } - - var processed = make(map[string]struct{}) - chainId := lsn.chain.Client().ConfiguredChainID() - startBalanceNoReserveLink, err := lsn.MaybeSubtractReservedLink( - ctx, startLinkBalance, chainId, subID, lsn.coordinator.Version()) - if err != nil { - lsn.l.Errorw("Couldn't get reserved LINK for subscription", "sub", reqs[0].req.SubID(), "err", err) - return processed - } - startBalanceNoReserveEth, err := lsn.MaybeSubtractReservedEth( - ctx, startEthBalance, lsn.chainID, subID, lsn.coordinator.Version()) - if err != nil { - lsn.l.Errorw("Couldn't get reserved ETH for subscription", "sub", reqs[0].req.SubID(), "err", err) - return processed - } - - // Split the requests into native and LINK requests. - var ( - nativeRequests []pendingRequest - linkRequests []pendingRequest - ) - for _, req := range reqs { - if req.req.NativePayment() { - nativeRequests = append(nativeRequests, req) - } else { - linkRequests = append(linkRequests, req) - } - } - // process the native and link requests in parallel - var ( - wg sync.WaitGroup - nativeProcessed, linkProcessed map[string]struct{} - ) - wg.Add(2) - go func() { - defer wg.Done() - nativeProcessed = lsn.processRequestsPerSubHelper( - ctx, - subID, - startEthBalance, - startBalanceNoReserveEth, - nativeRequests, - subIsActive, - true) - }() - go func() { - defer wg.Done() - linkProcessed = lsn.processRequestsPerSubHelper( - ctx, - subID, - startLinkBalance, - startBalanceNoReserveLink, - linkRequests, - subIsActive, - false) - }() - wg.Wait() - // combine the native and link processed requests into the processed map - for k, v := range nativeProcessed { - processed[k] = v - } - for k, v := range linkProcessed { - processed[k] = v - } - - return processed -} - -func (lsn *listenerV2) requestCommitmentPayload(requestID *big.Int) (payload []byte, err error) { - if lsn.coordinator.Version() == vrfcommon.V2Plus { - return coordinatorV2PlusABI.Pack("s_requestCommitments", requestID) - } else if lsn.coordinator.Version() == vrfcommon.V2 { - return coordinatorV2ABI.Pack("getCommitment", requestID) - } - return nil, errors.Errorf("unsupported coordinator version: %s", lsn.coordinator.Version()) -} - -// checkReqsFulfilled returns a bool slice the same size of the given reqs slice -// where each slice element indicates whether that request was already fulfilled -// or not. -func (lsn *listenerV2) checkReqsFulfilled(ctx context.Context, l logger.Logger, reqs []pendingRequest) ([]bool, error) { - var ( - start = time.Now() - calls = make([]rpc.BatchElem, len(reqs)) - fulfilled = make([]bool, len(reqs)) - ) - - for i, req := range reqs { - payload, err := lsn.requestCommitmentPayload(req.req.RequestID()) - if err != nil { - // This shouldn't happen - return fulfilled, errors.Wrap(err, "creating getCommitment payload") - } - - reqBlockNumber := new(big.Int).SetUint64(req.req.Raw().BlockNumber) - - // Subtract 5 since the newest block likely isn't indexed yet and will cause "header not - // found" errors. - currBlock := new(big.Int).SetUint64(lsn.getLatestHead() - 5) - m := bigmath.Max(reqBlockNumber, currBlock) - - var result string - calls[i] = rpc.BatchElem{ - Method: "eth_call", - Args: []interface{}{ - map[string]interface{}{ - "to": lsn.coordinator.Address(), - "data": hexutil.Bytes(payload), - }, - // The block at which we want to make the call - hexutil.EncodeBig(m), - }, - Result: &result, - } - } - - err := lsn.chain.Client().BatchCallContext(ctx, calls) - if err != nil { - return fulfilled, errors.Wrap(err, "making batch call") - } - - var errs error - for i, call := range calls { - if call.Error != nil { - errs = multierr.Append(errs, fmt.Errorf("checking request %s with hash %s: %w", - reqs[i].req.RequestID().String(), reqs[i].req.Raw().TxHash.String(), call.Error)) - continue - } - - rString, ok := call.Result.(*string) - if !ok { - errs = multierr.Append(errs, - fmt.Errorf("unexpected result %+v on request %s with hash %s", - call.Result, reqs[i].req.RequestID().String(), reqs[i].req.Raw().TxHash.String())) - continue - } - result, err := hexutil.Decode(*rString) - if err != nil { - errs = multierr.Append(errs, - fmt.Errorf("decoding batch call result %+v %s request %s with hash %s: %w", - call.Result, *rString, reqs[i].req.RequestID().String(), reqs[i].req.Raw().TxHash.String(), err)) - continue - } - - if utils.IsEmpty(result) { - l.Infow("Request already fulfilled", - "reqID", reqs[i].req.RequestID().String(), - "attempts", reqs[i].attempts, - "txHash", reqs[i].req.Raw().TxHash) - fulfilled[i] = true - } - } - - l.Debugw("Done checking fulfillment status", - "numChecked", len(reqs), "time", time.Since(start).String()) - return fulfilled, errs -} - -func (lsn *listenerV2) runPipelines( - ctx context.Context, - l logger.Logger, - maxGasPriceWei *assets.Wei, - reqs []pendingRequest, -) []vrfPipelineResult { - var ( - start = time.Now() - results = make([]vrfPipelineResult, len(reqs)) - wg = sync.WaitGroup{} - ) - - for i, req := range reqs { - wg.Add(1) - go func(i int, req pendingRequest) { - defer wg.Done() - results[i] = lsn.simulateFulfillment(ctx, maxGasPriceWei, req, l) - }(i, req) - } - wg.Wait() - - l.Debugw("Finished running pipelines", - "count", len(reqs), "time", time.Since(start).String()) - return results -} - -func (lsn *listenerV2) estimateFee( - ctx context.Context, - req RandomWordsRequested, - maxGasPriceWei *assets.Wei, -) (*big.Int, error) { - // NativePayment() returns true if and only if the version is V2+ and the - // request was made in ETH. - if req.NativePayment() { - return EstimateFeeWei(req.CallbackGasLimit(), maxGasPriceWei.ToInt()) - } - - // In the event we are using LINK we need to estimate the fee in juels - // Don't use up too much time to get this info, it's not critical for operating vrf. - callCtx, cancel := context.WithTimeout(ctx, 1*time.Second) - defer cancel() - roundData, err := lsn.aggregator.LatestRoundData(&bind.CallOpts{Context: callCtx}) - if err != nil { - return nil, errors.Wrap(err, "get aggregator latestAnswer") - } - - return EstimateFeeJuels( - req.CallbackGasLimit(), - maxGasPriceWei.ToInt(), - roundData.Answer, - ) -} - -// Here we use the pipeline to parse the log, generate a vrf response -// then simulate the transaction at the max gas price to determine its maximum link cost. -func (lsn *listenerV2) simulateFulfillment( - ctx context.Context, - maxGasPriceWei *assets.Wei, - req pendingRequest, - lg logger.Logger, -) vrfPipelineResult { - var ( - res = vrfPipelineResult{req: req} - err error - ) - // estimate how much funds are needed so that we can log it if the simulation fails. - res.fundsNeeded, err = lsn.estimateFee(ctx, req.req, maxGasPriceWei) - if err != nil { - // not critical, just log and continue - lg.Warnw("unable to estimate funds needed for request, continuing anyway", - "reqID", req.req.RequestID(), - "err", err) - res.fundsNeeded = big.NewInt(0) - } - - vars := pipeline.NewVarsFrom(map[string]interface{}{ - "jobSpec": map[string]interface{}{ - "databaseID": lsn.job.ID, - "externalJobID": lsn.job.ExternalJobID, - "name": lsn.job.Name.ValueOrZero(), - "publicKey": lsn.job.VRFSpec.PublicKey[:], - "maxGasPrice": maxGasPriceWei.ToInt().String(), - "evmChainID": lsn.job.VRFSpec.EVMChainID.String(), - }, - "jobRun": map[string]interface{}{ - "logBlockHash": req.req.Raw().BlockHash.Bytes(), - "logBlockNumber": req.req.Raw().BlockNumber, - "logTxHash": req.req.Raw().TxHash, - "logTopics": req.req.Raw().Topics, - "logData": req.req.Raw().Data, - }, - }) - var trrs pipeline.TaskRunResults - res.run, trrs, err = lsn.pipelineRunner.ExecuteRun(ctx, *lsn.job.PipelineSpec, vars, lg) - if err != nil { - res.err = errors.Wrap(err, "executing run") - return res - } - // The call task will fail if there are insufficient funds - if res.run.AllErrors.HasError() { - res.err = errors.WithStack(res.run.AllErrors.ToError()) - - if strings.Contains(res.err.Error(), "blockhash not found in store") { - res.err = multierr.Combine(res.err, errBlockhashNotInStore{}) - } else if strings.Contains(res.err.Error(), "execution reverted") { - // Even if the simulation fails, we want to get the - // txData for the fulfillRandomWords call, in case - // we need to force fulfill. - for _, trr := range trrs { - if trr.Task.Type() == pipeline.TaskTypeVRFV2 { - if trr.Result.Error != nil { - // error in VRF proof generation - // this means that we won't be able to force-fulfill in the event of a - // canceled sub and active requests. - // since this would be an extraordinary situation, - // we can log loudly here. - lg.Criticalw("failed to generate VRF proof", "err", trr.Result.Error) - break - } - - // extract the abi-encoded tx data to fulfillRandomWords from the VRF task. - // that's all we need in the event of a force-fulfillment. - m := trr.Result.Value.(map[string]any) - res.payload = m["output"].(string) - res.proof = FromV2Proof(m["proof"].(vrf_coordinator_v2.VRFProof)) - res.reqCommitment = NewRequestCommitment(m["requestCommitment"]) - } - } - res.err = multierr.Combine(res.err, errPossiblyInsufficientFunds{}) - } - - return res - } - finalResult := trrs.FinalResult(lg) - if len(finalResult.Values) != 1 { - res.err = errors.Errorf("unexpected number of outputs, expected 1, was %d", len(finalResult.Values)) - return res - } - - // Run succeeded, we expect a byte array representing the billing amount - b, ok := finalResult.Values[0].([]uint8) - if !ok { - res.err = errors.New("expected []uint8 final result") - return res - } - res.maxFee = utils.HexToBig(hexutil.Encode(b)[2:]) - for _, trr := range trrs { - if trr.Task.Type() == pipeline.TaskTypeVRFV2 { - m := trr.Result.Value.(map[string]interface{}) - res.payload = m["output"].(string) - res.proof = FromV2Proof(m["proof"].(vrf_coordinator_v2.VRFProof)) - res.reqCommitment = NewRequestCommitment(m["requestCommitment"]) - } - - if trr.Task.Type() == pipeline.TaskTypeVRFV2Plus { - m := trr.Result.Value.(map[string]interface{}) - res.payload = m["output"].(string) - res.proof = FromV2PlusProof(m["proof"].(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalProof)) - res.reqCommitment = NewRequestCommitment(m["requestCommitment"]) - } - - if trr.Task.Type() == pipeline.TaskTypeEstimateGasLimit { - res.gasLimit = trr.Result.Value.(uint32) - } - } - return res -} - -func (lsn *listenerV2) runRequestHandler(pollPeriod time.Duration, wg *sync.WaitGroup) { - defer wg.Done() - tick := time.NewTicker(pollPeriod) - defer tick.Stop() - ctx, cancel := lsn.chStop.NewCtx() - defer cancel() - for { - select { - case <-lsn.chStop: - return - case <-tick.C: - lsn.processPendingVRFRequests(ctx) - } - } -} - -func (lsn *listenerV2) runLogListener(unsubscribes []func(), minConfs uint32, wg *sync.WaitGroup) { - defer wg.Done() - lsn.l.Infow("Listening for run requests", - "minConfs", minConfs) - for { - select { - case <-lsn.chStop: - for _, f := range unsubscribes { - f() - } - return - case <-lsn.reqLogs.Notify(): - // Process all the logs in the queue if one is added - for { - lb, exists := lsn.reqLogs.Retrieve() - if !exists { - break - } - lsn.handleLog(lb, minConfs) - } - } - } -} - -func (lsn *listenerV2) getConfirmedAt(req RandomWordsRequested, nodeMinConfs uint32) uint64 { - lsn.respCountMu.Lock() - defer lsn.respCountMu.Unlock() - // Take the max(nodeMinConfs, requestedConfs + requestedConfsDelay). - // Add the requested confs delay if provided in the jobspec so that we avoid an edge case - // where the primary and backup VRF v2 nodes submit a proof at the same time. - minConfs := nodeMinConfs - if uint32(req.MinimumRequestConfirmations())+uint32(lsn.job.VRFSpec.RequestedConfsDelay) > nodeMinConfs { - minConfs = uint32(req.MinimumRequestConfirmations()) + uint32(lsn.job.VRFSpec.RequestedConfsDelay) - } - newConfs := uint64(minConfs) * (1 << lsn.respCount[req.RequestID().String()]) - // We cap this at 200 because solidity only supports the most recent 256 blocks - // in the contract so if it was older than that, fulfillments would start failing - // without the blockhash store feeder. We use 200 to give the node plenty of time - // to fulfill even on fast chains. - if newConfs > 200 { - newConfs = 200 - } - if lsn.respCount[req.RequestID().String()] > 0 { - lsn.l.Warnw("Duplicate request found after fulfillment, doubling incoming confirmations", - "txHash", req.Raw().TxHash, - "blockNumber", req.Raw().BlockNumber, - "blockHash", req.Raw().BlockHash, - "reqID", req.RequestID().String(), - "newConfs", newConfs) - vrfcommon.IncDupeReqs(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version()) - } - return req.Raw().BlockNumber + newConfs -} - -func (lsn *listenerV2) handleLog(lb log.Broadcast, minConfs uint32) { - if v, ok := lb.DecodedLog().(*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled); ok { - lsn.l.Debugw("Received fulfilled log", "reqID", v.RequestId, "success", v.Success) - consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(lb) - if err != nil { - lsn.l.Errorw(CouldNotDetermineIfLogConsumedMsg, "err", err, "txHash", lb.RawLog().TxHash) - return - } else if consumed { - return - } - lsn.respCountMu.Lock() - lsn.respCount[v.RequestId.String()]++ - lsn.respCountMu.Unlock() - lsn.blockNumberToReqID.Insert(fulfilledReqV2{ - blockNumber: v.Raw.BlockNumber, - reqID: v.RequestId.String(), - }) - lsn.markLogAsConsumed(lb) - return - } - - if v, ok := lb.DecodedLog().(*vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalRandomWordsFulfilled); ok { - lsn.l.Debugw("Received fulfilled log", "reqID", v.RequestId, "success", v.Success) - consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(lb) - if err != nil { - lsn.l.Errorw(CouldNotDetermineIfLogConsumedMsg, "err", err, "txHash", lb.RawLog().TxHash) - return - } else if consumed { - return - } - lsn.respCountMu.Lock() - lsn.respCount[v.RequestId.String()]++ - lsn.respCountMu.Unlock() - lsn.blockNumberToReqID.Insert(fulfilledReqV2{ - blockNumber: v.Raw.BlockNumber, - reqID: v.RequestId.String(), - }) - lsn.markLogAsConsumed(lb) - return - } - - req, err := lsn.coordinator.ParseRandomWordsRequested(lb.RawLog()) - if err != nil { - lsn.l.Errorw("Failed to parse log", "err", err, "txHash", lb.RawLog().TxHash) - consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(lb) - if err != nil { - lsn.l.Errorw(CouldNotDetermineIfLogConsumedMsg, "err", err, "txHash", lb.RawLog().TxHash) - return - } else if consumed { - return - } - lsn.markLogAsConsumed(lb) - return - } - - confirmedAt := lsn.getConfirmedAt(req, minConfs) - lsn.l.Infow("VRFListenerV2: Received log request", "reqID", req.RequestID(), "confirmedAt", confirmedAt, "subID", req.SubID(), "sender", req.Sender()) - lsn.reqsMu.Lock() - lsn.reqs = append(lsn.reqs, pendingRequest{ - confirmedAtBlock: confirmedAt, - req: req, - lb: lb, - utcTimestamp: time.Now().UTC(), - }) - lsn.reqAdded() - lsn.reqsMu.Unlock() -} - -func (lsn *listenerV2) markLogAsConsumed(lb log.Broadcast) { - err := lsn.chain.LogBroadcaster().MarkConsumed(lb) - lsn.l.ErrorIf(err, fmt.Sprintf("Unable to mark log %v as consumed", lb.String())) + return lsn.latestHeadNumber } // Close complies with job.Service func (lsn *listenerV2) Close() error { return lsn.StopOnce("VRFListenerV2", func() error { close(lsn.chStop) - // wait on the request handler, log listener, and head listener to stop + // wait on the request handler, log listener lsn.wg.Wait() - return lsn.reqLogs.Close() + return nil }) } - -func (lsn *listenerV2) HandleLog(lb log.Broadcast) { - if !lsn.deduper.ShouldDeliver(lb.RawLog()) { - lsn.l.Tracew("skipping duplicate log broadcast", "log", lb.RawLog()) - return - } - - wasOverCapacity := lsn.reqLogs.Deliver(lb) - if wasOverCapacity { - lsn.l.Error("Log mailbox is over capacity - dropped the oldest log") - vrfcommon.IncDroppedReqs(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version(), vrfcommon.ReasonMailboxSize) - } -} - -// JobID complies with log.Listener -func (lsn *listenerV2) JobID() int32 { - return lsn.job.ID -} - -// ReplayStartedCallback is called by the log broadcaster when a replay is about to start. -func (lsn *listenerV2) ReplayStartedCallback() { - // Clear the log deduper cache so that we don't incorrectly ignore logs that have been sent that - // are already in the cache. - lsn.deduper.Clear() -} - -func (lsn *listenerV2) fromAddresses() []common.Address { - var addresses []common.Address - for _, a := range lsn.job.VRFSpec.FromAddresses { - addresses = append(addresses, a.Address()) - } - return addresses -} - -func uniqueReqs(reqs []pendingRequest) int { - s := map[string]struct{}{} - for _, r := range reqs { - s[r.req.RequestID().String()] = struct{}{} - } - return len(s) -} - -// GasProofVerification is an upper limit on the gas used for verifying the VRF proof on-chain. -// It can be used to estimate the amount of LINK or native needed to fulfill a request. -const GasProofVerification uint32 = 200_000 - -// EstimateFeeJuels estimates the amount of link needed to fulfill a request -// given the callback gas limit, the gas price, and the wei per unit link. -// An error is returned if the wei per unit link provided is zero. -func EstimateFeeJuels(callbackGasLimit uint32, maxGasPriceWei, weiPerUnitLink *big.Int) (*big.Int, error) { - if weiPerUnitLink.Cmp(big.NewInt(0)) == 0 { - return nil, errors.New("wei per unit link is zero") - } - maxGasUsed := big.NewInt(int64(callbackGasLimit + GasProofVerification)) - costWei := maxGasUsed.Mul(maxGasUsed, maxGasPriceWei) - // Multiply by 1e18 first so that we don't lose a ton of digits due to truncation when we divide - // by weiPerUnitLink - numerator := costWei.Mul(costWei, big.NewInt(1e18)) - costJuels := numerator.Quo(numerator, weiPerUnitLink) - return costJuels, nil -} - -// EstimateFeeWei estimates the amount of wei needed to fulfill a request -func EstimateFeeWei(callbackGasLimit uint32, maxGasPriceWei *big.Int) (*big.Int, error) { - maxGasUsed := big.NewInt(int64(callbackGasLimit + GasProofVerification)) - costWei := maxGasUsed.Mul(maxGasUsed, maxGasPriceWei) - return costWei, nil -} - -// observeRequestSimDuration records the time between the given requests simulations or -// the time until it's first simulation, whichever is applicable. -// Cases: -// 1. Never simulated: in this case, we want to observe the time until simulated -// on the utcTimestamp field of the pending request. -// 2. Simulated before: in this case, lastTry will be set to a non-zero time value, -// in which case we'd want to use that as a relative point from when we last tried -// the request. -func observeRequestSimDuration(jobName string, extJobID uuid.UUID, vrfVersion vrfcommon.Version, pendingReqs []pendingRequest) { - now := time.Now().UTC() - for _, request := range pendingReqs { - // First time around lastTry will be zero because the request has not been - // simulated yet. It will be updated every time the request is simulated (in the event - // the request is simulated multiple times, due to it being underfunded). - if request.lastTry.IsZero() { - vrfcommon.MetricTimeUntilInitialSim. - WithLabelValues(jobName, extJobID.String(), string(vrfVersion)). - Observe(float64(now.Sub(request.utcTimestamp))) - } else { - vrfcommon.MetricTimeBetweenSims. - WithLabelValues(jobName, extJobID.String(), string(vrfVersion)). - Observe(float64(now.Sub(request.lastTry))) - } - } -} - -func ptr[T any](t T) *T { return &t } diff --git a/core/services/vrf/v2/listener_v2_helpers.go b/core/services/vrf/v2/listener_v2_helpers.go new file mode 100644 index 0000000000..b3a3675e29 --- /dev/null +++ b/core/services/vrf/v2/listener_v2_helpers.go @@ -0,0 +1,103 @@ +package v2 + +import ( + "math/big" + "strings" + "time" + + "github.com/google/uuid" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" +) + +func uniqueReqs(reqs []pendingRequest) int { + s := map[string]struct{}{} + for _, r := range reqs { + s[r.req.RequestID().String()] = struct{}{} + } + return len(s) +} + +// GasProofVerification is an upper limit on the gas used for verifying the VRF proof on-chain. +// It can be used to estimate the amount of LINK or native needed to fulfill a request. +const GasProofVerification uint32 = 200_000 + +// EstimateFeeJuels estimates the amount of link needed to fulfill a request +// given the callback gas limit, the gas price, and the wei per unit link. +// An error is returned if the wei per unit link provided is zero. +func EstimateFeeJuels(callbackGasLimit uint32, maxGasPriceWei, weiPerUnitLink *big.Int) (*big.Int, error) { + if weiPerUnitLink.Cmp(big.NewInt(0)) == 0 { + return nil, errors.New("wei per unit link is zero") + } + maxGasUsed := big.NewInt(int64(callbackGasLimit + GasProofVerification)) + costWei := maxGasUsed.Mul(maxGasUsed, maxGasPriceWei) + // Multiply by 1e18 first so that we don't lose a ton of digits due to truncation when we divide + // by weiPerUnitLink + numerator := costWei.Mul(costWei, big.NewInt(1e18)) + costJuels := numerator.Quo(numerator, weiPerUnitLink) + return costJuels, nil +} + +// EstimateFeeWei estimates the amount of wei needed to fulfill a request +func EstimateFeeWei(callbackGasLimit uint32, maxGasPriceWei *big.Int) (*big.Int, error) { + maxGasUsed := big.NewInt(int64(callbackGasLimit + GasProofVerification)) + costWei := maxGasUsed.Mul(maxGasUsed, maxGasPriceWei) + return costWei, nil +} + +// observeRequestSimDuration records the time between the given requests simulations or +// the time until it's first simulation, whichever is applicable. +// Cases: +// 1. Never simulated: in this case, we want to observe the time until simulated +// on the utcTimestamp field of the pending request. +// 2. Simulated before: in this case, lastTry will be set to a non-zero time value, +// in which case we'd want to use that as a relative point from when we last tried +// the request. +func observeRequestSimDuration(jobName string, extJobID uuid.UUID, vrfVersion vrfcommon.Version, pendingReqs []pendingRequest) { + now := time.Now().UTC() + for _, request := range pendingReqs { + // First time around lastTry will be zero because the request has not been + // simulated yet. It will be updated every time the request is simulated (in the event + // the request is simulated multiple times, due to it being underfunded). + if request.lastTry.IsZero() { + vrfcommon.MetricTimeUntilInitialSim. + WithLabelValues(jobName, extJobID.String(), string(vrfVersion)). + Observe(float64(now.Sub(request.utcTimestamp))) + } else { + vrfcommon.MetricTimeBetweenSims. + WithLabelValues(jobName, extJobID.String(), string(vrfVersion)). + Observe(float64(now.Sub(request.lastTry))) + } + } +} + +func ptr[T any](t T) *T { return &t } + +func isProofVerificationError(errMsg string) bool { + // See VRF.sol for all these messages + // NOTE: it's unclear which of these errors are impossible and which + // may actually happen, so including them all to be safe. + errMessages := []string{ + "invalid x-ordinate", + "invalid y-ordinate", + "zero scalar", + "invZ must be inverse of z", + "bad witness", + "points in sum must be distinct", + "First mul check failed", + "Second mul check failed", + "public key is not on curve", + "gamma is not on curve", + "cGammaWitness is not on curve", + "sHashWitness is not on curve", + "addr(c*pk+s*g)!=_uWitness", + "invalid proof", + } + for _, msg := range errMessages { + if strings.Contains(errMsg, msg) { + return true + } + } + return false +} diff --git a/core/services/vrf/v2/listener_v2_log_listener.go b/core/services/vrf/v2/listener_v2_log_listener.go new file mode 100644 index 0000000000..b35593bd1c --- /dev/null +++ b/core/services/vrf/v2/listener_v2_log_listener.go @@ -0,0 +1,451 @@ +package v2 + +import ( + "bytes" + "context" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "go.uber.org/multierr" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" + "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" +) + +func (lsn *listenerV2) runLogListener( + pollPeriod time.Duration, + minConfs uint32, +) { + lsn.l.Infow("Listening for run requests via log poller", + "minConfs", minConfs) + ticker := time.NewTicker(pollPeriod) + defer ticker.Stop() + var ( + lastProcessedBlock int64 + startingUp = true + ) + ctx, cancel := lsn.chStop.NewCtx() + defer cancel() + for { + select { + case <-lsn.chStop: + return + case <-ticker.C: + start := time.Now() + lsn.l.Debugw("log listener loop") + // Filter registration is idempotent, so we can just call it every time + // and retry on errors using the ticker. + err := lsn.chain.LogPoller().RegisterFilter(logpoller.Filter{ + Name: logpoller.FilterName( + "VRFListener", + "version", lsn.coordinator.Version(), + "keyhash", lsn.job.VRFSpec.PublicKey.MustHash(), + "coordinatorAddress", lsn.coordinator.Address()), + EventSigs: evmtypes.HashArray{ + lsn.coordinator.RandomWordsFulfilledTopic(), + lsn.coordinator.RandomWordsRequestedTopic(), + }, + Addresses: evmtypes.AddressArray{ + lsn.coordinator.Address(), + }, + }) + if err != nil { + lsn.l.Errorw("error registering filter in log poller, retrying", + "err", err, + "elapsed", time.Since(start)) + continue + } + + // on startup we want to initialize the last processed block + if startingUp { + lsn.l.Debugw("initializing last processed block on startup") + lastProcessedBlock, err = lsn.initializeLastProcessedBlock(ctx) + if err != nil { + lsn.l.Errorw("error initializing last processed block, retrying", + "err", err, + "elapsed", time.Since(start)) + continue + } + startingUp = false + lsn.l.Debugw("initialized last processed block", "lastProcessedBlock", lastProcessedBlock) + } + + pending, err := lsn.pollLogs(ctx, minConfs, lastProcessedBlock) + if err != nil { + lsn.l.Errorw("error polling vrf logs, retrying", + "err", err, + "elapsed", time.Since(start)) + continue + } + + // process pending requests and insert any fulfillments into the inflight cache + lsn.processPendingVRFRequests(ctx, pending) + + lastProcessedBlock, err = lsn.updateLastProcessedBlock(ctx, lastProcessedBlock) + if err != nil { + lsn.l.Errorw("error updating last processed block, continuing anyway", "err", err) + } else { + lsn.l.Debugw("updated last processed block", "lastProcessedBlock", lastProcessedBlock) + } + lsn.l.Debugw("log listener loop done", "elapsed", time.Since(start)) + } + } +} + +// initializeLastProcessedBlock returns the earliest block number that we need to +// process requests for. This is the block number of the earliest unfulfilled request +// or the latest finalized block, if there are no unfulfilled requests. +// TODO: add tests +func (lsn *listenerV2) initializeLastProcessedBlock(ctx context.Context) (lastProcessedBlock int64, err error) { + lp := lsn.chain.LogPoller() + start := time.Now() + + // will retry on error in the runLogListener loop + latestBlock, err := lp.LatestBlock() + if err != nil { + return 0, fmt.Errorf("LogPoller.LatestBlock(): %w", err) + } + fromTimestamp := time.Now().UTC().Add(-lsn.job.VRFSpec.RequestTimeout) + ll := lsn.l.With( + "latestFinalizedBlock", latestBlock.FinalizedBlockNumber, + "latestBlock", latestBlock.BlockNumber, + "fromTimestamp", fromTimestamp) + ll.Debugw("Initializing last processed block") + defer func() { + ll.Debugw("Done initializing last processed block", "elapsed", time.Since(start)) + }() + + numBlocksToReplay := numReplayBlocks(lsn.job.VRFSpec.RequestTimeout, lsn.chain.ID()) + ll.Debugw("running replay on log poller") + err = lp.Replay(ctx, mathutil.Max(latestBlock.FinalizedBlockNumber-numBlocksToReplay, 1)) + if err != nil { + return 0, fmt.Errorf("LogPoller.Replay: %w", err) + } + + // get randomness requested logs with the appropriate keyhash + // keyhash is specified in topic1 + requests, err := lp.IndexedLogsCreatedAfter( + lsn.coordinator.RandomWordsRequestedTopic(), // event sig + lsn.coordinator.Address(), // address + 1, // topic index + []common.Hash{lsn.job.VRFSpec.PublicKey.MustHash()}, // topic values + fromTimestamp, // from time + logpoller.Finalized, // confs + ) + if err != nil { + return 0, fmt.Errorf("LogPoller.LogsCreatedAfter RandomWordsRequested logs: %w", err) + } + + // fulfillments don't have keyhash indexed, we'll have to get all of them + // TODO: can we instead write a single query that joins on request id's somehow? + fulfillments, err := lp.LogsCreatedAfter( + lsn.coordinator.RandomWordsFulfilledTopic(), // event sig + lsn.coordinator.Address(), // address + fromTimestamp, // from time + logpoller.Finalized, // confs + ) + if err != nil { + return 0, fmt.Errorf("LogPoller.LogsCreatedAfter RandomWordsFulfilled logs: %w", err) + } + + unfulfilled, _, _ := lsn.getUnfulfilled(append(requests, fulfillments...), ll) + // find request block of earliest unfulfilled request + // even if this block is > latest finalized, we use latest finalized as earliest unprocessed + // because re-orgs can occur on any unfinalized block. + var earliestUnfulfilledBlock = latestBlock.FinalizedBlockNumber + for _, req := range unfulfilled { + if req.Raw().BlockNumber < uint64(earliestUnfulfilledBlock) { + earliestUnfulfilledBlock = int64(req.Raw().BlockNumber) + } + } + + return earliestUnfulfilledBlock, nil +} + +func (lsn *listenerV2) updateLastProcessedBlock(ctx context.Context, currLastProcessedBlock int64) (lastProcessedBlock int64, err error) { + lp := lsn.chain.LogPoller() + start := time.Now() + + latestBlock, err := lp.LatestBlock(pg.WithParentCtx(ctx)) + if err != nil { + lsn.l.Errorw("error getting latest block", "err", err) + return 0, fmt.Errorf("LogPoller.LatestBlock(): %w", err) + } + ll := lsn.l.With( + "currLastProcessedBlock", currLastProcessedBlock, + "latestBlock", latestBlock.BlockNumber, + "latestFinalizedBlock", latestBlock.FinalizedBlockNumber) + ll.Debugw("updating last processed block") + defer func() { + ll.Debugw("done updating last processed block", "elapsed", time.Since(start)) + }() + + logs, err := lp.LogsWithSigs( + currLastProcessedBlock, + latestBlock.FinalizedBlockNumber, + []common.Hash{lsn.coordinator.RandomWordsFulfilledTopic(), lsn.coordinator.RandomWordsRequestedTopic()}, + lsn.coordinator.Address(), + pg.WithParentCtx(ctx), + ) + if err != nil { + return currLastProcessedBlock, fmt.Errorf("LogPoller.LogsWithSigs: %w", err) + } + + unfulfilled, unfulfilledLP, _ := lsn.getUnfulfilled(logs, ll) + // find request block of earliest unfulfilled request + // even if this block is > latest finalized, we use latest finalized as earliest unprocessed + // because re-orgs can occur on any unfinalized block. + var earliestUnprocessedRequestBlock = latestBlock.FinalizedBlockNumber + for i, req := range unfulfilled { + // need to drop requests that have timed out otherwise the earliestUnprocessedRequestBlock + // will be unnecessarily far back and our queries will be slower. + if unfulfilledLP[i].CreatedAt.Before(time.Now().UTC().Add(-lsn.job.VRFSpec.RequestTimeout)) { + // request timed out, don't process + lsn.l.Debugw("request timed out, skipping", + "reqID", req.RequestID(), + ) + continue + } + if req.Raw().BlockNumber < uint64(earliestUnprocessedRequestBlock) { + earliestUnprocessedRequestBlock = int64(req.Raw().BlockNumber) + } + } + + return earliestUnprocessedRequestBlock, nil +} + +// pollLogs uses the log poller to poll for the latest VRF logs +func (lsn *listenerV2) pollLogs(ctx context.Context, minConfs uint32, lastProcessedBlock int64) (pending []pendingRequest, err error) { + start := time.Now() + lp := lsn.chain.LogPoller() + + // latest unfinalized block used on purpose to get bleeding edge logs + // we don't really have the luxury to wait for finalization on most chains + // if we want to fulfill on time. + latestBlock, err := lp.LatestBlock() + if err != nil { + return nil, fmt.Errorf("LogPoller.LatestBlock(): %w", err) + } + lsn.setLatestHead(latestBlock) + ll := lsn.l.With( + "lastProcessedBlock", lastProcessedBlock, + "minConfs", minConfs, + "latestBlock", latestBlock.BlockNumber, + "latestFinalizedBlock", latestBlock.FinalizedBlockNumber) + ll.Debugw("polling for logs") + defer func() { + ll.Debugw("done polling for logs", "elapsed", time.Since(start)) + }() + + // We don't specify confs because each request can have a different conf above + // the minimum. So we do all conf handling in getConfirmedAt. + logs, err := lp.LogsWithSigs( + lastProcessedBlock, + latestBlock.BlockNumber, + []common.Hash{lsn.coordinator.RandomWordsFulfilledTopic(), lsn.coordinator.RandomWordsRequestedTopic()}, + lsn.coordinator.Address(), + pg.WithParentCtx(ctx), + ) + if err != nil { + return nil, fmt.Errorf("LogPoller.LogsWithSigs: %w", err) + } + + unfulfilled, unfulfilledLP, fulfilled := lsn.getUnfulfilled(logs, ll) + if len(unfulfilled) > 0 { + ll.Debugw("found unfulfilled logs", "unfulfilled", len(unfulfilled)) + } else { + ll.Debugw("no unfulfilled logs found") + } + + lsn.handleFulfilled(fulfilled) + + return lsn.handleRequested(unfulfilled, unfulfilledLP, minConfs), nil +} + +func (lsn *listenerV2) getUnfulfilled(logs []logpoller.Log, ll logger.Logger) (unfulfilled []RandomWordsRequested, unfulfilledLP []logpoller.Log, fulfilled map[string]RandomWordsFulfilled) { + var ( + requested = make(map[string]RandomWordsRequested) + requestedLP = make(map[string]logpoller.Log) + errs error + expectedKeyHash = lsn.job.VRFSpec.PublicKey.MustHash() + ) + fulfilled = make(map[string]RandomWordsFulfilled) + for _, l := range logs { + if l.EventSig == lsn.coordinator.RandomWordsFulfilledTopic() { + parsed, err2 := lsn.coordinator.ParseRandomWordsFulfilled(l.ToGethLog()) + if err2 != nil { + // should never happen + errs = multierr.Append(errs, err2) + continue + } + fulfilled[parsed.RequestID().String()] = parsed + } else if l.EventSig == lsn.coordinator.RandomWordsRequestedTopic() { + parsed, err2 := lsn.coordinator.ParseRandomWordsRequested(l.ToGethLog()) + if err2 != nil { + // should never happen + errs = multierr.Append(errs, err2) + continue + } + keyHash := parsed.KeyHash() + if !bytes.Equal(keyHash[:], expectedKeyHash[:]) { + // wrong keyhash, can ignore + continue + } + requested[parsed.RequestID().String()] = parsed + requestedLP[parsed.RequestID().String()] = l + } + } + // should never happen, unsure if recoverable + // may be worth a panic + if errs != nil { + ll.Errorw("encountered parse errors", "err", errs) + } + + if len(fulfilled) > 0 || len(requested) > 0 { + ll.Infow("found logs", "fulfilled", len(fulfilled), "requested", len(requested)) + } else { + ll.Debugw("no logs found") + } + + // find unfulfilled requests by comparing requested events with the fulfilled events + for reqID, req := range requested { + if _, isFulfilled := fulfilled[reqID]; !isFulfilled { + unfulfilled = append(unfulfilled, req) + unfulfilledLP = append(unfulfilledLP, requestedLP[reqID]) + } + } + + return unfulfilled, unfulfilledLP, fulfilled +} + +func (lsn *listenerV2) getConfirmedAt(req RandomWordsRequested, nodeMinConfs uint32) uint64 { + // Take the max(nodeMinConfs, requestedConfs + requestedConfsDelay). + // Add the requested confs delay if provided in the jobspec so that we avoid an edge case + // where the primary and backup VRF v2 nodes submit a proof at the same time. + minConfs := nodeMinConfs + if uint32(req.MinimumRequestConfirmations())+uint32(lsn.job.VRFSpec.RequestedConfsDelay) > nodeMinConfs { + minConfs = uint32(req.MinimumRequestConfirmations()) + uint32(lsn.job.VRFSpec.RequestedConfsDelay) + } + newConfs := uint64(minConfs) * (1 << lsn.respCount[req.RequestID().String()]) + // We cap this at 200 because solidity only supports the most recent 256 blocks + // in the contract so if it was older than that, fulfillments would start failing + // without the blockhash store feeder. We use 200 to give the node plenty of time + // to fulfill even on fast chains. + if newConfs > 200 { + newConfs = 200 + } + if lsn.respCount[req.RequestID().String()] > 0 { + lsn.l.Warnw("Duplicate request found after fulfillment, doubling incoming confirmations", + "txHash", req.Raw().TxHash, + "blockNumber", req.Raw().BlockNumber, + "blockHash", req.Raw().BlockHash, + "reqID", req.RequestID().String(), + "newConfs", newConfs) + vrfcommon.IncDupeReqs(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version()) + } + return req.Raw().BlockNumber + newConfs +} + +func (lsn *listenerV2) handleFulfilled(fulfilled map[string]RandomWordsFulfilled) { + for _, v := range fulfilled { + // don't process same log over again + // log key includes block number and blockhash, so on re-orgs it would return true + // and we would re-process the re-orged request. + if !lsn.fulfillmentLogDeduper.ShouldDeliver(v.Raw()) { + continue + } + lsn.l.Debugw("Received fulfilled log", "reqID", v.RequestID(), "success", v.Success()) + lsn.respCount[v.RequestID().String()]++ + lsn.blockNumberToReqID.Insert(fulfilledReqV2{ + blockNumber: v.Raw().BlockNumber, + reqID: v.RequestID().String(), + }) + } +} + +func (lsn *listenerV2) handleRequested(requested []RandomWordsRequested, requestedLP []logpoller.Log, minConfs uint32) (pendingRequests []pendingRequest) { + for i, req := range requested { + // don't process same log over again + // log key includes block number and blockhash, so on re-orgs it would return true + // and we would re-process the re-orged request. + if lsn.inflightCache.Contains(req.Raw()) { + continue + } + + confirmedAt := lsn.getConfirmedAt(req, minConfs) + lsn.l.Debugw("VRFListenerV2: Received log request", + "reqID", req.RequestID(), + "reqBlockNumber", req.Raw().BlockNumber, + "reqBlockHash", req.Raw().BlockHash, + "reqTxHash", req.Raw().TxHash, + "confirmedAt", confirmedAt, + "subID", req.SubID(), + "sender", req.Sender()) + pendingRequests = append(pendingRequests, pendingRequest{ + confirmedAtBlock: confirmedAt, + req: req, + utcTimestamp: requestedLP[i].CreatedAt.UTC(), + }) + lsn.reqAdded() + } + + return pendingRequests +} + +// numReplayBlocks returns the number of blocks to replay on startup +// given the request timeout and the chain ID. +// if the chain ID is not recognized it assumes a block time of 1 second +// and returns the number of blocks in a day. +func numReplayBlocks(requestTimeout time.Duration, chainID *big.Int) int64 { + var timeoutSeconds = int64(requestTimeout.Seconds()) + switch chainID.String() { + case "1": // eth mainnet + case "3": // eth ropsten + case "4": // eth rinkeby + case "5": // eth goerli + case "11155111": // eth sepolia + // block time is 12s + return timeoutSeconds / 12 + case "137": // polygon mainnet + case "80001": // polygon mumbai + // block time is 2s + return timeoutSeconds / 2 + case "56": // bsc mainnet + case "97": // bsc testnet + // block time is 2s + return timeoutSeconds / 2 + case "43114": // avalanche mainnet + case "43113": // avalanche fuji + // block time is 1s + return timeoutSeconds + case "250": // fantom mainnet + case "4002": // fantom testnet + // block time is 1s + return timeoutSeconds + case "42161": // arbitrum mainnet + case "421613": // arbitrum goerli + case "421614": // arbitrum sepolia + // block time is 0.25s in the worst case + return timeoutSeconds * 4 + case "10": // optimism mainnet + case "69": // optimism kovan + case "420": // optimism goerli + case "11155420": // optimism sepolia + case "8453": // base mainnet + case "84531": // base goerli + case "84532": // base sepolia + // block time is 2s + return timeoutSeconds / 2 + default: + // assume block time of 1s + return timeoutSeconds + } + // assume block time of 1s + return timeoutSeconds +} diff --git a/core/services/vrf/v2/listener_v2_log_processor.go b/core/services/vrf/v2/listener_v2_log_processor.go new file mode 100644 index 0000000000..004ab4c490 --- /dev/null +++ b/core/services/vrf/v2/listener_v2_log_processor.go @@ -0,0 +1,1214 @@ +package v2 + +import ( + "cmp" + "context" + "database/sql" + "fmt" + "math" + "math/big" + "slices" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/pkg/errors" + "go.uber.org/multierr" + + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" + txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" + "github.com/smartcontractkit/chainlink/v2/core/utils" + bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" +) + +// Returns all the confirmed logs from the provided pending queue by subscription +func (lsn *listenerV2) getConfirmedLogsBySub(latestHead uint64, pendingRequests []pendingRequest) map[string][]pendingRequest { + vrfcommon.UpdateQueueSize(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version(), uniqueReqs(pendingRequests)) + var toProcess = make(map[string][]pendingRequest) + for _, request := range pendingRequests { + if lsn.ready(request, latestHead) { + toProcess[request.req.SubID().String()] = append(toProcess[request.req.SubID().String()], request) + } + } + return toProcess +} + +func (lsn *listenerV2) ready(req pendingRequest, latestHead uint64) bool { + // Request is not eligible for fulfillment yet + if req.confirmedAtBlock > latestHead { + return false + } + + if lsn.job.VRFSpec.BackoffInitialDelay == 0 || req.attempts == 0 { + // Backoff is disabled, or this is the first try + return true + } + + return time.Now().UTC().After( + nextTry( + req.attempts, + lsn.job.VRFSpec.BackoffInitialDelay, + lsn.job.VRFSpec.BackoffMaxDelay, + req.lastTry)) +} + +func nextTry(retries int, initial, max time.Duration, last time.Time) time.Time { + expBackoffFactor := math.Pow(backoffFactor, float64(retries-1)) + + var delay time.Duration + if expBackoffFactor > float64(max/initial) { + delay = max + } else { + delay = time.Duration(float64(initial) * expBackoffFactor) + } + return last.Add(delay) +} + +// Remove all entries 10000 blocks or older +// to avoid a memory leak. +func (lsn *listenerV2) pruneConfirmedRequestCounts() { + min := lsn.blockNumberToReqID.FindMin() + for min != nil { + m := min.(fulfilledReqV2) + if m.blockNumber > (lsn.getLatestHead() - 10000) { + break + } + delete(lsn.respCount, m.reqID) + lsn.blockNumberToReqID.DeleteMin() + min = lsn.blockNumberToReqID.FindMin() + } +} + +// Determine a set of logs that are confirmed +// and the subscription has sufficient balance to fulfill, +// given a eth call with the max gas price. +// Note we have to consider the pending reqs already in the txm as already "spent" link or native, +// using a max link or max native consumed in their metadata. +// A user will need a minBalance capable of fulfilling a single req at the max gas price or nothing will happen. +// This is acceptable as users can choose different keyhashes which have different max gas prices. +// Other variables which can change the bill amount between our eth call simulation and tx execution: +// - Link/eth price fluctuation +// - Falling back to BHS +// However the likelihood is vanishingly small as +// 1) the window between simulation and tx execution is tiny. +// 2) the max gas price provides a very large buffer most of the time. +// Its easier to optimistically assume it will go though and in the rare case of a reversion +// we simply retry TODO: follow up where if we see a fulfillment revert, return log to the queue. +func (lsn *listenerV2) processPendingVRFRequests(ctx context.Context, pendingRequests []pendingRequest) { + confirmed := lsn.getConfirmedLogsBySub(lsn.getLatestHead(), pendingRequests) + var processedMu sync.Mutex + processed := make(map[string]struct{}) + start := time.Now() + + defer func() { + for _, subReqs := range confirmed { + for _, req := range subReqs { + if _, ok := processed[req.req.RequestID().String()]; ok { + // add to the inflight cache so that we don't re-process this request + lsn.inflightCache.Add(req.req.Raw()) + } + } + } + lsn.l.Infow("Finished processing pending requests", + "totalProcessed", len(processed), + "totalFailed", len(pendingRequests)-len(processed), + "total", len(pendingRequests), + "time", time.Since(start).String(), + "inflightCacheSize", lsn.inflightCache.Size()) + }() + + if len(confirmed) == 0 { + lsn.l.Infow("No pending requests ready for processing") + return + } + for subID, reqs := range confirmed { + l := lsn.l.With("subID", subID, "startTime", time.Now(), "numReqsForSub", len(reqs)) + // Get the balance of the subscription and also it's active status. + // The reason we need both is that we cannot determine if a subscription + // is active solely by it's balance, since an active subscription could legitimately + // have a zero balance. + var ( + startLinkBalance *big.Int + startEthBalance *big.Int + subIsActive bool + ) + sID, ok := new(big.Int).SetString(subID, 10) + if !ok { + l.Criticalw("Unable to convert %s to Int", subID) + return + } + sub, err := lsn.coordinator.GetSubscription(&bind.CallOpts{ + Context: ctx}, sID) + + if err != nil { + if strings.Contains(err.Error(), "execution reverted") { + // "execution reverted" indicates that the subscription no longer exists. + // We can no longer just mark these as processed and continue, + // since it could be that the subscription was canceled while there + // were still unfulfilled requests. + // The simplest approach to handle this is to enter the processRequestsPerSub + // loop rather than create a bunch of largely duplicated code + // to handle this specific situation, since we need to run the pipeline to get + // the VRF proof, abi-encode it, etc. + l.Warnw("Subscription not found - setting start balance to zero", "subID", subID, "err", err) + startLinkBalance = big.NewInt(0) + } else { + // Most likely this is an RPC error, so we re-try later. + l.Errorw("Unable to read subscription balance", "err", err) + return + } + } else { + // Happy path - sub is active. + startLinkBalance = sub.Balance() + if sub.Version() == vrfcommon.V2Plus { + startEthBalance = sub.NativeBalance() + } + subIsActive = true + } + + // Sort requests in ascending order by CallbackGasLimit + // so that we process the "cheapest" requests for each subscription + // first. This allows us to break out of the processing loop as early as possible + // in the event that a subscription is too underfunded to have it's + // requests processed. + slices.SortFunc(reqs, func(a, b pendingRequest) int { + return cmp.Compare(a.req.CallbackGasLimit(), b.req.CallbackGasLimit()) + }) + + p := lsn.processRequestsPerSub(ctx, sID, startLinkBalance, startEthBalance, reqs, subIsActive) + processedMu.Lock() + for reqID := range p { + processed[reqID] = struct{}{} + } + processedMu.Unlock() + } + lsn.pruneConfirmedRequestCounts() +} + +// MaybeSubtractReservedLink figures out how much LINK is reserved for other VRF requests that +// have not been fully confirmed yet on-chain, and subtracts that from the given startBalance, +// and returns that value if there are no errors. +func (lsn *listenerV2) MaybeSubtractReservedLink(ctx context.Context, startBalance *big.Int, chainID *big.Int, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { + var metaField string + if vrfVersion == vrfcommon.V2Plus { + metaField = txMetaGlobalSubId + } else if vrfVersion == vrfcommon.V2 { + metaField = txMetaFieldSubId + } else { + return nil, errors.Errorf("unsupported vrf version %s", vrfVersion) + } + + txes, err := lsn.chain.TxManager().FindTxesByMetaFieldAndStates(ctx, metaField, subID.String(), reserveEthLinkQueryStates, chainID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, fmt.Errorf("TXM FindTxesByMetaFieldAndStates failed: %w", err) + } + + reservedLinkSum := big.NewInt(0) + // Aggregate non-null MaxLink from all txes returned + for _, tx := range txes { + var meta *txmgrtypes.TxMeta[common.Address, common.Hash] + meta, err = tx.GetMeta() + if err != nil { + return nil, fmt.Errorf("GetMeta for Tx failed: %w", err) + } + if meta != nil && meta.MaxLink != nil { + txMaxLink, success := new(big.Int).SetString(*meta.MaxLink, 10) + if !success { + return nil, fmt.Errorf("converting reserved LINK %s", *meta.MaxLink) + } + + reservedLinkSum.Add(reservedLinkSum, txMaxLink) + } + } + + return new(big.Int).Sub(startBalance, reservedLinkSum), nil +} + +// MaybeSubtractReservedEth figures out how much ether is reserved for other VRF requests that +// have not been fully confirmed yet on-chain, and subtracts that from the given startBalance, +// and returns that value if there are no errors. +func (lsn *listenerV2) MaybeSubtractReservedEth(ctx context.Context, startBalance *big.Int, chainID *big.Int, subID *big.Int, vrfVersion vrfcommon.Version) (*big.Int, error) { + var metaField string + if vrfVersion == vrfcommon.V2Plus { + metaField = txMetaGlobalSubId + } else if vrfVersion == vrfcommon.V2 { + // native payment is not supported for v2, so returning 0 reserved ETH + return big.NewInt(0), nil + } else { + return nil, errors.Errorf("unsupported vrf version %s", vrfVersion) + } + txes, err := lsn.chain.TxManager().FindTxesByMetaFieldAndStates(ctx, metaField, subID.String(), reserveEthLinkQueryStates, chainID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, fmt.Errorf("TXM FindTxesByMetaFieldAndStates failed: %w", err) + } + + reservedEthSum := big.NewInt(0) + // Aggregate non-null MaxEth from all txes returned + for _, tx := range txes { + var meta *txmgrtypes.TxMeta[common.Address, common.Hash] + meta, err = tx.GetMeta() + if err != nil { + return nil, fmt.Errorf("GetMeta for Tx failed: %w", err) + } + if meta != nil && meta.MaxEth != nil { + txMaxEth, success := new(big.Int).SetString(*meta.MaxEth, 10) + if !success { + return nil, fmt.Errorf("converting reserved ETH %s", *meta.MaxEth) + } + + reservedEthSum.Add(reservedEthSum, txMaxEth) + } + } + + if startBalance != nil { + return new(big.Int).Sub(startBalance, reservedEthSum), nil + } + return big.NewInt(0), nil +} + +func (lsn *listenerV2) processRequestsPerSubBatchHelper( + ctx context.Context, + subID *big.Int, + startBalance *big.Int, + startBalanceNoReserved *big.Int, + reqs []pendingRequest, + subIsActive bool, + nativePayment bool, +) (processed map[string]struct{}) { + start := time.Now() + processed = make(map[string]struct{}) + + // Base the max gas for a batch on the max gas limit for a single callback. + // Since the max gas limit for a single callback is usually quite large already, + // we probably don't want to exceed it too much so that we can reliably get + // batch fulfillments included, while also making sure that the biggest gas guzzler + // callbacks are included. + config, err := lsn.coordinator.GetConfig(&bind.CallOpts{ + Context: ctx, + }) + if err != nil { + lsn.l.Errorw("Couldn't get config from coordinator", "err", err) + return processed + } + + // Add very conservative upper bound estimate on verification costs. + batchMaxGas := config.MaxGasLimit() + 400_000 + + l := lsn.l.With( + "subID", subID, + "eligibleSubReqs", len(reqs), + "startBalance", startBalance.String(), + "startBalanceNoReserved", startBalanceNoReserved.String(), + "batchMaxGas", batchMaxGas, + "subIsActive", subIsActive, + "nativePayment", nativePayment, + ) + + defer func() { + l.Infow("Finished processing for sub", + "endBalance", startBalanceNoReserved.String(), + "totalProcessed", len(processed), + "totalUnique", uniqueReqs(reqs), + "time", time.Since(start).String()) + }() + + l.Infow("Processing requests for subscription with batching") + + ready, expired := lsn.getReadyAndExpired(l, reqs) + for _, reqID := range expired { + processed[reqID] = struct{}{} + } + + // Process requests in chunks in order to kick off as many jobs + // as configured in parallel. Then we can combine into fulfillment + // batches afterwards. + for chunkStart := 0; chunkStart < len(ready); chunkStart += int(lsn.job.VRFSpec.ChunkSize) { + chunkEnd := chunkStart + int(lsn.job.VRFSpec.ChunkSize) + if chunkEnd > len(ready) { + chunkEnd = len(ready) + } + chunk := ready[chunkStart:chunkEnd] + + var unfulfilled []pendingRequest + alreadyFulfilled, err := lsn.checkReqsFulfilled(ctx, l, chunk) + if errors.Is(err, context.Canceled) { + l.Infow("Context canceled, stopping request processing", "err", err) + return processed + } else if err != nil { + l.Errorw("Error checking for already fulfilled requests, proceeding anyway", "err", err) + } + for i, a := range alreadyFulfilled { + if a { + processed[chunk[i].req.RequestID().String()] = struct{}{} + } else { + unfulfilled = append(unfulfilled, chunk[i]) + } + } + + // All fromAddresses passed to the VRFv2 job have the same KeySpecific-MaxPrice value. + fromAddresses := lsn.fromAddresses() + maxGasPriceWei := lsn.feeCfg.PriceMaxKey(fromAddresses[0]) + + // Cases: + // 1. Never simulated: in this case, we want to observe the time until simulated + // on the utcTimestamp field of the pending request. + // 2. Simulated before: in this case, lastTry will be set to a non-zero time value, + // in which case we'd want to use that as a relative point from when we last tried + // the request. + observeRequestSimDuration(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version(), unfulfilled) + + pipelines := lsn.runPipelines(ctx, l, maxGasPriceWei, unfulfilled) + batches := newBatchFulfillments(batchMaxGas, lsn.coordinator.Version()) + outOfBalance := false + for _, p := range pipelines { + ll := l.With("reqID", p.req.req.RequestID().String(), + "txHash", p.req.req.Raw().TxHash, + "maxGasPrice", maxGasPriceWei.String(), + "fundsNeeded", p.fundsNeeded.String(), + "maxFee", p.maxFee.String(), + "gasLimit", p.gasLimit, + "attempts", p.req.attempts, + "remainingBalance", startBalanceNoReserved.String(), + "consumerAddress", p.req.req.Sender(), + "blockNumber", p.req.req.Raw().BlockNumber, + "blockHash", p.req.req.Raw().BlockHash, + ) + fromAddresses := lsn.fromAddresses() + fromAddress, err := lsn.gethks.GetRoundRobinAddress(lsn.chainID, fromAddresses...) + if err != nil { + l.Errorw("Couldn't get next from address", "err", err) + continue + } + ll = ll.With("fromAddress", fromAddress) + + if p.err != nil { + if errors.Is(p.err, errBlockhashNotInStore{}) { + // Running the blockhash store feeder in backwards mode will be required to + // resolve this. + ll.Criticalw("Pipeline error", "err", p.err) + } else if errors.Is(p.err, errProofVerificationFailed{}) { + // This occurs when the proof reverts in the simulation + // This is almost always (if not always) due to a proof generated with an out-of-date + // blockhash + // we can simply mark as processed and move on, since we will eventually + // process the request with the right blockhash + ll.Infow("proof reverted in simulation, likely stale blockhash") + processed[p.req.req.RequestID().String()] = struct{}{} + } else { + ll.Errorw("Pipeline error", "err", p.err) + if !subIsActive { + ll.Warnw("Force-fulfilling a request with insufficient funds on a cancelled sub") + etx, err := lsn.enqueueForceFulfillment(ctx, p, fromAddress) + if err != nil { + ll.Errorw("Error enqueuing force-fulfillment, re-queueing request", "err", err) + continue + } + ll.Infow("Successfully enqueued force-fulfillment", "ethTxID", etx.ID) + processed[p.req.req.RequestID().String()] = struct{}{} + + // Need to put a continue here, otherwise the next if statement will be hit + // and we'd break out of the loop prematurely. + // If a sub is canceled, we want to force-fulfill ALL of it's pending requests + // before saying we're done with it. + continue + } + + if startBalanceNoReserved.Cmp(p.fundsNeeded) < 0 && errors.Is(p.err, errPossiblyInsufficientFunds{}) { + ll.Infow("Insufficient balance to fulfill a request based on estimate, breaking", "err", p.err) + outOfBalance = true + + // break out of this inner loop to process the currently constructed batch + break + } + + // Ensure consumer is valid, otherwise drop the request. + if !lsn.isConsumerValidAfterFinalityDepthElapsed(ctx, p.req) { + lsn.l.Infow( + "Dropping request that was made by an invalid consumer.", + "consumerAddress", p.req.req.Sender(), + "reqID", p.req.req.RequestID(), + "blockNumber", p.req.req.Raw().BlockNumber, + "blockHash", p.req.req.Raw().BlockHash, + ) + processed[p.req.req.RequestID().String()] = struct{}{} + continue + } + } + continue + } + + if startBalanceNoReserved.Cmp(p.maxFee) < 0 { + // Insufficient funds, have to wait for a user top up. + // Break out of the loop now and process what we are able to process + // in the constructed batches. + ll.Infow("Insufficient balance to fulfill a request, breaking") + break + } + + batches.addRun(p, fromAddress) + + startBalanceNoReserved.Sub(startBalanceNoReserved, p.maxFee) + } + + var processedRequestIDs []string + for _, batch := range batches.fulfillments { + l.Debugw("Processing batch", "batchSize", len(batch.proofs)) + p := lsn.processBatch(l, subID, startBalanceNoReserved, batchMaxGas, batch, batch.fromAddress) + processedRequestIDs = append(processedRequestIDs, p...) + } + + for _, reqID := range processedRequestIDs { + processed[reqID] = struct{}{} + } + + // outOfBalance is set to true if the current sub we are processing + // has run out of funds to process any remaining requests. After enqueueing + // this constructed batch, we break out of this outer loop in order to + // avoid unnecessarily processing the remaining requests. + if outOfBalance { + break + } + } + + return +} + +func (lsn *listenerV2) processRequestsPerSubBatch( + ctx context.Context, + subID *big.Int, + startLinkBalance *big.Int, + startEthBalance *big.Int, + reqs []pendingRequest, + subIsActive bool, +) map[string]struct{} { + var processed = make(map[string]struct{}) + startBalanceNoReserveLink, err := lsn.MaybeSubtractReservedLink( + ctx, startLinkBalance, lsn.chainID, subID, lsn.coordinator.Version()) + if err != nil { + lsn.l.Errorw("Couldn't get reserved LINK for subscription", "sub", reqs[0].req.SubID(), "err", err) + return processed + } + startBalanceNoReserveEth, err := lsn.MaybeSubtractReservedEth( + ctx, startEthBalance, lsn.chainID, subID, lsn.coordinator.Version()) + if err != nil { + lsn.l.Errorw("Couldn't get reserved ether for subscription", "sub", reqs[0].req.SubID(), "err", err) + return processed + } + + // Split the requests into native and LINK requests. + var ( + nativeRequests []pendingRequest + linkRequests []pendingRequest + ) + for _, req := range reqs { + if req.req.NativePayment() { + nativeRequests = append(nativeRequests, req) + } else { + linkRequests = append(linkRequests, req) + } + } + // process the native and link requests in parallel + var wg sync.WaitGroup + var nativeProcessed, linkProcessed map[string]struct{} + wg.Add(2) + go func() { + defer wg.Done() + nativeProcessed = lsn.processRequestsPerSubBatchHelper(ctx, subID, startEthBalance, startBalanceNoReserveEth, nativeRequests, subIsActive, true) + }() + go func() { + defer wg.Done() + linkProcessed = lsn.processRequestsPerSubBatchHelper(ctx, subID, startLinkBalance, startBalanceNoReserveLink, linkRequests, subIsActive, false) + }() + wg.Wait() + // combine the processed link and native requests into the processed map + for k, v := range nativeProcessed { + processed[k] = v + } + for k, v := range linkProcessed { + processed[k] = v + } + + return processed +} + +// enqueueForceFulfillment enqueues a forced fulfillment through the +// VRFOwner contract. It estimates gas again on the transaction due +// to the extra steps taken within VRFOwner.fulfillRandomWords. +func (lsn *listenerV2) enqueueForceFulfillment( + ctx context.Context, + p vrfPipelineResult, + fromAddress common.Address, +) (etx txmgr.Tx, err error) { + if lsn.job.VRFSpec.VRFOwnerAddress == nil { + err = errors.New("vrf owner address not set in job spec, recreate job and provide it to force-fulfill") + return + } + + if p.payload == "" { + // should probably never happen + // a critical log will be logged if this is the case in simulateFulfillment + err = errors.New("empty payload in vrfPipelineResult") + return + } + + // fulfill the request through the VRF owner + err = lsn.q.Transaction(func(tx pg.Queryer) error { + lsn.l.Infow("VRFOwner.fulfillRandomWords vs. VRFCoordinatorV2.fulfillRandomWords", + "vrf_owner.fulfillRandomWords", hexutil.Encode(vrfOwnerABI.Methods["fulfillRandomWords"].ID), + "vrf_coordinator_v2.fulfillRandomWords", hexutil.Encode(coordinatorV2ABI.Methods["fulfillRandomWords"].ID), + ) + + vrfOwnerAddress1 := lsn.vrfOwner.Address() + vrfOwnerAddressSpec := lsn.job.VRFSpec.VRFOwnerAddress.Address() + lsn.l.Infow("addresses diff", "wrapper_address", vrfOwnerAddress1, "spec_address", vrfOwnerAddressSpec) + + lsn.l.Infow("fulfillRandomWords payload", "proof", p.proof, "commitment", p.reqCommitment.Get(), "payload", p.payload) + txData := hexutil.MustDecode(p.payload) + if err != nil { + return fmt.Errorf("abi pack VRFOwner.fulfillRandomWords: %w", err) + } + estimateGasLimit, err := lsn.chain.Client().EstimateGas(ctx, ethereum.CallMsg{ + From: fromAddress, + To: &vrfOwnerAddressSpec, + Data: txData, + }) + if err != nil { + return fmt.Errorf("failed to estimate gas on VRFOwner.fulfillRandomWords: %w", err) + } + + lsn.l.Infow("Estimated gas limit on force fulfillment", + "estimateGasLimit", estimateGasLimit, "pipelineGasLimit", p.gasLimit) + if estimateGasLimit < uint64(p.gasLimit) { + estimateGasLimit = uint64(p.gasLimit) + } + + requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) + subID := p.req.req.SubID() + requestTxHash := p.req.req.Raw().TxHash + etx, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ + FromAddress: fromAddress, + ToAddress: lsn.vrfOwner.Address(), + EncodedPayload: txData, + FeeLimit: uint32(estimateGasLimit), + Strategy: txmgrcommon.NewSendEveryStrategy(), + Meta: &txmgr.TxMeta{ + RequestID: &requestID, + SubID: ptr(subID.Uint64()), + RequestTxHash: &requestTxHash, + // No max link since simulation failed + }, + }) + return err + }) + return +} + +// For an errored pipeline run, wait until the finality depth of the chain to have elapsed, +// then check if the failing request is being called by an invalid sender. Return false if this is the case, +// otherwise true. +func (lsn *listenerV2) isConsumerValidAfterFinalityDepthElapsed(ctx context.Context, req pendingRequest) bool { + latestHead := lsn.getLatestHead() + if latestHead-req.req.Raw().BlockNumber > uint64(lsn.cfg.FinalityDepth()) { + code, err := lsn.chain.Client().CodeAt(ctx, req.req.Sender(), big.NewInt(int64(latestHead))) + if err != nil { + lsn.l.Warnw("Failed to fetch contract code", "err", err) + return true // error fetching code, give the benefit of doubt to the consumer + } + if len(code) == 0 { + return false // invalid consumer + } + } + + return true // valid consumer, or finality depth has not elapsed +} + +// processRequestsPerSubHelper processes a set of pending requests for the provided sub id. +// It returns a set of request IDs that were processed. +// Note that the provided startBalanceNoReserve is the balance of the subscription +// minus any pending requests that have already been processed and not yet fulfilled onchain. +func (lsn *listenerV2) processRequestsPerSubHelper( + ctx context.Context, + subID *big.Int, + startBalance *big.Int, + startBalanceNoReserved *big.Int, + reqs []pendingRequest, + subIsActive bool, + nativePayment bool, +) (processed map[string]struct{}) { + start := time.Now() + processed = make(map[string]struct{}) + + l := lsn.l.With( + "subID", subID, + "eligibleSubReqs", len(reqs), + "startBalance", startBalance.String(), + "startBalanceNoReserved", startBalanceNoReserved.String(), + "subIsActive", subIsActive, + "nativePayment", nativePayment, + ) + + defer func() { + l.Infow("Finished processing for sub", + "endBalance", startBalanceNoReserved.String(), + "totalProcessed", len(processed), + "totalUnique", uniqueReqs(reqs), + "time", time.Since(start).String()) + }() + + l.Infow("Processing requests for subscription") + + ready, expired := lsn.getReadyAndExpired(l, reqs) + for _, reqID := range expired { + processed[reqID] = struct{}{} + } + + // Process requests in chunks + for chunkStart := 0; chunkStart < len(ready); chunkStart += int(lsn.job.VRFSpec.ChunkSize) { + chunkEnd := chunkStart + int(lsn.job.VRFSpec.ChunkSize) + if chunkEnd > len(ready) { + chunkEnd = len(ready) + } + chunk := ready[chunkStart:chunkEnd] + + var unfulfilled []pendingRequest + alreadyFulfilled, err := lsn.checkReqsFulfilled(ctx, l, chunk) + if errors.Is(err, context.Canceled) { + l.Infow("Context canceled, stopping request processing", "err", err) + return processed + } else if err != nil { + l.Errorw("Error checking for already fulfilled requests, proceeding anyway", "err", err) + } + for i, a := range alreadyFulfilled { + if a { + processed[chunk[i].req.RequestID().String()] = struct{}{} + } else { + unfulfilled = append(unfulfilled, chunk[i]) + } + } + + // All fromAddresses passed to the VRFv2 job have the same KeySpecific-MaxPrice value. + fromAddresses := lsn.fromAddresses() + maxGasPriceWei := lsn.feeCfg.PriceMaxKey(fromAddresses[0]) + observeRequestSimDuration(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version(), unfulfilled) + pipelines := lsn.runPipelines(ctx, l, maxGasPriceWei, unfulfilled) + for _, p := range pipelines { + ll := l.With("reqID", p.req.req.RequestID().String(), + "txHash", p.req.req.Raw().TxHash, + "maxGasPrice", maxGasPriceWei.String(), + "fundsNeeded", p.fundsNeeded.String(), + "maxFee", p.maxFee.String(), + "gasLimit", p.gasLimit, + "attempts", p.req.attempts, + "remainingBalance", startBalanceNoReserved.String(), + "consumerAddress", p.req.req.Sender(), + "blockNumber", p.req.req.Raw().BlockNumber, + "blockHash", p.req.req.Raw().BlockHash, + ) + fromAddress, err := lsn.gethks.GetRoundRobinAddress(lsn.chainID, fromAddresses...) + if err != nil { + l.Errorw("Couldn't get next from address", "err", err) + continue + } + ll = ll.With("fromAddress", fromAddress) + + if p.err != nil { + if errors.Is(p.err, errBlockhashNotInStore{}) { + // Running the blockhash store feeder in backwards mode will be required to + // resolve this. + ll.Criticalw("Pipeline error", "err", p.err) + } else if errors.Is(p.err, errProofVerificationFailed{}) { + // This occurs when the proof reverts in the simulation + // This is almost always (if not always) due to a proof generated with an out-of-date + // blockhash + // we can simply mark as processed and move on, since we will eventually + // process the request with the right blockhash + ll.Infow("proof reverted in simulation, likely stale blockhash") + processed[p.req.req.RequestID().String()] = struct{}{} + } else { + ll.Errorw("Pipeline error", "err", p.err) + + if !subIsActive { + lsn.l.Warnw("Force-fulfilling a request with insufficient funds on a cancelled sub") + etx, err2 := lsn.enqueueForceFulfillment(ctx, p, fromAddress) + if err2 != nil { + ll.Errorw("Error enqueuing force-fulfillment, re-queueing request", "err", err2) + continue + } + ll.Infow("Enqueued force-fulfillment", "ethTxID", etx.ID) + processed[p.req.req.RequestID().String()] = struct{}{} + + // Need to put a continue here, otherwise the next if statement will be hit + // and we'd break out of the loop prematurely. + // If a sub is canceled, we want to force-fulfill ALL of it's pending requests + // before saying we're done with it. + continue + } + + if startBalanceNoReserved.Cmp(p.fundsNeeded) < 0 { + ll.Infow("Insufficient balance to fulfill a request based on estimate, returning", "err", p.err) + return processed + } + + // Ensure consumer is valid, otherwise drop the request. + if !lsn.isConsumerValidAfterFinalityDepthElapsed(ctx, p.req) { + lsn.l.Infow( + "Dropping request that was made by an invalid consumer.", + "consumerAddress", p.req.req.Sender(), + "reqID", p.req.req.RequestID(), + "blockNumber", p.req.req.Raw().BlockNumber, + "blockHash", p.req.req.Raw().BlockHash, + ) + processed[p.req.req.RequestID().String()] = struct{}{} + continue + } + } + continue + } + + if startBalanceNoReserved.Cmp(p.maxFee) < 0 { + // Insufficient funds, have to wait for a user top up. Leave it unprocessed for now + ll.Infow("Insufficient balance to fulfill a request, returning") + return processed + } + + ll.Infow("Enqueuing fulfillment") + var transaction txmgr.Tx + err = lsn.q.Transaction(func(tx pg.Queryer) error { + if err = lsn.pipelineRunner.InsertFinishedRun(p.run, true, pg.WithQueryer(tx)); err != nil { + return err + } + + var maxLink, maxEth *string + tmp := p.maxFee.String() + if p.reqCommitment.NativePayment() { + maxEth = &tmp + } else { + maxLink = &tmp + } + var ( + txMetaSubID *uint64 + txMetaGlobalSubID *string + ) + if lsn.coordinator.Version() == vrfcommon.V2Plus { + txMetaGlobalSubID = ptr(p.req.req.SubID().String()) + } else if lsn.coordinator.Version() == vrfcommon.V2 { + txMetaSubID = ptr(p.req.req.SubID().Uint64()) + } + requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) + coordinatorAddress := lsn.coordinator.Address() + requestTxHash := p.req.req.Raw().TxHash + transaction, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ + FromAddress: fromAddress, + ToAddress: lsn.coordinator.Address(), + EncodedPayload: hexutil.MustDecode(p.payload), + FeeLimit: p.gasLimit, + Meta: &txmgr.TxMeta{ + RequestID: &requestID, + MaxLink: maxLink, + MaxEth: maxEth, + SubID: txMetaSubID, + GlobalSubID: txMetaGlobalSubID, + RequestTxHash: &requestTxHash, + }, + Strategy: txmgrcommon.NewSendEveryStrategy(), + Checker: txmgr.TransmitCheckerSpec{ + CheckerType: lsn.transmitCheckerType(), + VRFCoordinatorAddress: &coordinatorAddress, + VRFRequestBlockNumber: new(big.Int).SetUint64(p.req.req.Raw().BlockNumber), + }, + }) + return err + }) + if err != nil { + ll.Errorw("Error enqueuing fulfillment, requeuing request", "err", err) + continue + } + ll.Infow("Enqueued fulfillment", "ethTxID", transaction.GetID()) + + // If we successfully enqueued for the txm, subtract that balance + // And loop to attempt to enqueue another fulfillment + startBalanceNoReserved.Sub(startBalanceNoReserved, p.maxFee) + processed[p.req.req.RequestID().String()] = struct{}{} + vrfcommon.IncProcessedReqs(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, lsn.coordinator.Version()) + } + } + + return +} + +func (lsn *listenerV2) transmitCheckerType() txmgrtypes.TransmitCheckerType { + if lsn.coordinator.Version() == vrfcommon.V2 { + return txmgr.TransmitCheckerTypeVRFV2 + } + return txmgr.TransmitCheckerTypeVRFV2Plus +} + +func (lsn *listenerV2) processRequestsPerSub( + ctx context.Context, + subID *big.Int, + startLinkBalance *big.Int, + startEthBalance *big.Int, + reqs []pendingRequest, + subIsActive bool, +) map[string]struct{} { + if lsn.job.VRFSpec.BatchFulfillmentEnabled && lsn.batchCoordinator != nil { + return lsn.processRequestsPerSubBatch(ctx, subID, startLinkBalance, startEthBalance, reqs, subIsActive) + } + + var processed = make(map[string]struct{}) + chainId := lsn.chain.Client().ConfiguredChainID() + startBalanceNoReserveLink, err := lsn.MaybeSubtractReservedLink( + ctx, startLinkBalance, chainId, subID, lsn.coordinator.Version()) + if err != nil { + lsn.l.Errorw("Couldn't get reserved LINK for subscription", "sub", reqs[0].req.SubID(), "err", err) + return processed + } + startBalanceNoReserveEth, err := lsn.MaybeSubtractReservedEth( + ctx, startEthBalance, lsn.chainID, subID, lsn.coordinator.Version()) + if err != nil { + lsn.l.Errorw("Couldn't get reserved ETH for subscription", "sub", reqs[0].req.SubID(), "err", err) + return processed + } + + // Split the requests into native and LINK requests. + var ( + nativeRequests []pendingRequest + linkRequests []pendingRequest + ) + for _, req := range reqs { + if req.req.NativePayment() { + if !lsn.inflightCache.Contains(req.req.Raw()) { + nativeRequests = append(nativeRequests, req) + } else { + lsn.l.Debugw("Skipping native request because it is already inflight", + "reqID", req.req.RequestID()) + } + } else { + if !lsn.inflightCache.Contains(req.req.Raw()) { + linkRequests = append(linkRequests, req) + } else { + lsn.l.Debugw("Skipping link request because it is already inflight", + "reqID", req.req.RequestID()) + } + } + } + // process the native and link requests in parallel + var ( + wg sync.WaitGroup + nativeProcessed, linkProcessed map[string]struct{} + ) + wg.Add(2) + go func() { + defer wg.Done() + nativeProcessed = lsn.processRequestsPerSubHelper( + ctx, + subID, + startEthBalance, + startBalanceNoReserveEth, + nativeRequests, + subIsActive, + true) + }() + go func() { + defer wg.Done() + linkProcessed = lsn.processRequestsPerSubHelper( + ctx, + subID, + startLinkBalance, + startBalanceNoReserveLink, + linkRequests, + subIsActive, + false) + }() + wg.Wait() + // combine the native and link processed requests into the processed map + for k, v := range nativeProcessed { + processed[k] = v + } + for k, v := range linkProcessed { + processed[k] = v + } + + return processed +} + +func (lsn *listenerV2) requestCommitmentPayload(requestID *big.Int) (payload []byte, err error) { + if lsn.coordinator.Version() == vrfcommon.V2Plus { + return coordinatorV2PlusABI.Pack("s_requestCommitments", requestID) + } else if lsn.coordinator.Version() == vrfcommon.V2 { + return coordinatorV2ABI.Pack("getCommitment", requestID) + } + return nil, errors.Errorf("unsupported coordinator version: %s", lsn.coordinator.Version()) +} + +// checkReqsFulfilled returns a bool slice the same size of the given reqs slice +// where each slice element indicates whether that request was already fulfilled +// or not. +func (lsn *listenerV2) checkReqsFulfilled(ctx context.Context, l logger.Logger, reqs []pendingRequest) ([]bool, error) { + var ( + start = time.Now() + calls = make([]rpc.BatchElem, len(reqs)) + fulfilled = make([]bool, len(reqs)) + ) + + for i, req := range reqs { + payload, err := lsn.requestCommitmentPayload(req.req.RequestID()) + if err != nil { + // This shouldn't happen + return fulfilled, fmt.Errorf("creating getCommitment payload: %w", err) + } + + reqBlockNumber := new(big.Int).SetUint64(req.req.Raw().BlockNumber) + + // Subtract 5 since the newest block likely isn't indexed yet and will cause "header not + // found" errors. + currBlock := new(big.Int).SetUint64(lsn.getLatestHead() - 5) + m := bigmath.Max(reqBlockNumber, currBlock) + + var result string + calls[i] = rpc.BatchElem{ + Method: "eth_call", + Args: []interface{}{ + map[string]interface{}{ + "to": lsn.coordinator.Address(), + "data": hexutil.Bytes(payload), + }, + // The block at which we want to make the call + hexutil.EncodeBig(m), + }, + Result: &result, + } + } + + err := lsn.chain.Client().BatchCallContext(ctx, calls) + if err != nil { + return fulfilled, fmt.Errorf("making batch call: %w", err) + } + + var errs error + for i, call := range calls { + if call.Error != nil { + errs = multierr.Append(errs, fmt.Errorf("checking request %s with hash %s: %w", + reqs[i].req.RequestID().String(), reqs[i].req.Raw().TxHash.String(), call.Error)) + continue + } + + rString, ok := call.Result.(*string) + if !ok { + errs = multierr.Append(errs, + fmt.Errorf("unexpected result %+v on request %s with hash %s", + call.Result, reqs[i].req.RequestID().String(), reqs[i].req.Raw().TxHash.String())) + continue + } + result, err := hexutil.Decode(*rString) + if err != nil { + errs = multierr.Append(errs, + fmt.Errorf("decoding batch call result %+v %s request %s with hash %s: %w", + call.Result, *rString, reqs[i].req.RequestID().String(), reqs[i].req.Raw().TxHash.String(), err)) + continue + } + + if utils.IsEmpty(result) { + l.Infow("Request already fulfilled", + "reqID", reqs[i].req.RequestID().String(), + "attempts", reqs[i].attempts, + "txHash", reqs[i].req.Raw().TxHash) + fulfilled[i] = true + } + } + + l.Debugw("Done checking fulfillment status", + "numChecked", len(reqs), "time", time.Since(start).String()) + return fulfilled, errs +} + +func (lsn *listenerV2) runPipelines( + ctx context.Context, + l logger.Logger, + maxGasPriceWei *assets.Wei, + reqs []pendingRequest, +) []vrfPipelineResult { + var ( + start = time.Now() + results = make([]vrfPipelineResult, len(reqs)) + wg = sync.WaitGroup{} + ) + + for i, req := range reqs { + wg.Add(1) + go func(i int, req pendingRequest) { + defer wg.Done() + results[i] = lsn.simulateFulfillment(ctx, maxGasPriceWei, req, l) + }(i, req) + } + wg.Wait() + + l.Debugw("Finished running pipelines", + "count", len(reqs), "time", time.Since(start).String()) + return results +} + +func (lsn *listenerV2) estimateFee( + ctx context.Context, + req RandomWordsRequested, + maxGasPriceWei *assets.Wei, +) (*big.Int, error) { + // NativePayment() returns true if and only if the version is V2+ and the + // request was made in ETH. + if req.NativePayment() { + return EstimateFeeWei(req.CallbackGasLimit(), maxGasPriceWei.ToInt()) + } + + // In the event we are using LINK we need to estimate the fee in juels + // Don't use up too much time to get this info, it's not critical for operating vrf. + callCtx, cancel := context.WithTimeout(ctx, 1*time.Second) + defer cancel() + roundData, err := lsn.aggregator.LatestRoundData(&bind.CallOpts{Context: callCtx}) + if err != nil { + return nil, fmt.Errorf("get aggregator latestAnswer: %w", err) + } + + return EstimateFeeJuels( + req.CallbackGasLimit(), + maxGasPriceWei.ToInt(), + roundData.Answer, + ) +} + +// Here we use the pipeline to parse the log, generate a vrf response +// then simulate the transaction at the max gas price to determine its maximum link cost. +func (lsn *listenerV2) simulateFulfillment( + ctx context.Context, + maxGasPriceWei *assets.Wei, + req pendingRequest, + lg logger.Logger, +) vrfPipelineResult { + var ( + res = vrfPipelineResult{req: req} + err error + ) + // estimate how much funds are needed so that we can log it if the simulation fails. + res.fundsNeeded, err = lsn.estimateFee(ctx, req.req, maxGasPriceWei) + if err != nil { + // not critical, just log and continue + lg.Warnw("unable to estimate funds needed for request, continuing anyway", + "reqID", req.req.RequestID(), + "err", err) + res.fundsNeeded = big.NewInt(0) + } + + vars := pipeline.NewVarsFrom(map[string]interface{}{ + "jobSpec": map[string]interface{}{ + "databaseID": lsn.job.ID, + "externalJobID": lsn.job.ExternalJobID, + "name": lsn.job.Name.ValueOrZero(), + "publicKey": lsn.job.VRFSpec.PublicKey[:], + "maxGasPrice": maxGasPriceWei.ToInt().String(), + "evmChainID": lsn.job.VRFSpec.EVMChainID.String(), + }, + "jobRun": map[string]interface{}{ + "logBlockHash": req.req.Raw().BlockHash.Bytes(), + "logBlockNumber": req.req.Raw().BlockNumber, + "logTxHash": req.req.Raw().TxHash, + "logTopics": req.req.Raw().Topics, + "logData": req.req.Raw().Data, + }, + }) + var trrs pipeline.TaskRunResults + res.run, trrs, err = lsn.pipelineRunner.ExecuteRun(ctx, *lsn.job.PipelineSpec, vars, lg) + if err != nil { + res.err = fmt.Errorf("executing run: %w", err) + return res + } + // The call task will fail if there are insufficient funds + if res.run.AllErrors.HasError() { + res.err = errors.WithStack(res.run.AllErrors.ToError()) + + if strings.Contains(res.err.Error(), "blockhash not found in store") { + res.err = multierr.Combine(res.err, errBlockhashNotInStore{}) + } else if isProofVerificationError(res.err.Error()) { + res.err = multierr.Combine(res.err, errProofVerificationFailed{}) + } else if strings.Contains(res.err.Error(), "execution reverted") { + // Even if the simulation fails, we want to get the + // txData for the fulfillRandomWords call, in case + // we need to force fulfill. + for _, trr := range trrs { + if trr.Task.Type() == pipeline.TaskTypeVRFV2 { + if trr.Result.Error != nil { + // error in VRF proof generation + // this means that we won't be able to force-fulfill in the event of a + // canceled sub and active requests. + // since this would be an extraordinary situation, + // we can log loudly here. + lg.Criticalw("failed to generate VRF proof", "err", trr.Result.Error) + break + } + + // extract the abi-encoded tx data to fulfillRandomWords from the VRF task. + // that's all we need in the event of a force-fulfillment. + m := trr.Result.Value.(map[string]any) + res.payload = m["output"].(string) + res.proof = FromV2Proof(m["proof"].(vrf_coordinator_v2.VRFProof)) + res.reqCommitment = NewRequestCommitment(m["requestCommitment"]) + } + } + res.err = multierr.Combine(res.err, errPossiblyInsufficientFunds{}) + } + + return res + } + finalResult := trrs.FinalResult(lg) + if len(finalResult.Values) != 1 { + res.err = errors.Errorf("unexpected number of outputs, expected 1, was %d", len(finalResult.Values)) + return res + } + + // Run succeeded, we expect a byte array representing the billing amount + b, ok := finalResult.Values[0].([]uint8) + if !ok { + res.err = errors.New("expected []uint8 final result") + return res + } + res.maxFee = utils.HexToBig(hexutil.Encode(b)[2:]) + for _, trr := range trrs { + if trr.Task.Type() == pipeline.TaskTypeVRFV2 { + m := trr.Result.Value.(map[string]interface{}) + res.payload = m["output"].(string) + res.proof = FromV2Proof(m["proof"].(vrf_coordinator_v2.VRFProof)) + res.reqCommitment = NewRequestCommitment(m["requestCommitment"]) + } + + if trr.Task.Type() == pipeline.TaskTypeVRFV2Plus { + m := trr.Result.Value.(map[string]interface{}) + res.payload = m["output"].(string) + res.proof = FromV2PlusProof(m["proof"].(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalProof)) + res.reqCommitment = NewRequestCommitment(m["requestCommitment"]) + } + + if trr.Task.Type() == pipeline.TaskTypeEstimateGasLimit { + res.gasLimit = trr.Result.Value.(uint32) + } + } + return res +} + +func (lsn *listenerV2) fromAddresses() []common.Address { + var addresses []common.Address + for _, a := range lsn.job.VRFSpec.FromAddresses { + addresses = append(addresses, a.Address()) + } + return addresses +} diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 8a7b9ce3fe..bcc85b3700 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -3,7 +3,6 @@ package v2 import ( "encoding/json" "math/big" - "sync" "testing" "time" @@ -12,10 +11,8 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" @@ -23,8 +20,6 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -502,77 +497,3 @@ func TestListener_Backoff(t *testing.T) { }) } } - -func TestListener_handleLog(tt *testing.T) { - lb := mocks.NewBroadcaster(tt) - chainID := int64(2) - minConfs := uint32(3) - blockNumber := uint64(5) - requestID := int64(6) - tt.Run("v2", func(t *testing.T) { - j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ - VRFVersion: vrfcommon.V2, - RequestedConfsDelay: 10, - FromAddresses: []string{"0xF2982b7Ef6E3D8BB738f8Ea20502229781f6Ad97"}, - }).Toml()) - require.NoError(t, err) - fulfilledLog := vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled{ - RequestId: big.NewInt(requestID), - Raw: types.Log{BlockNumber: blockNumber}, - } - log := log.NewLogBroadcast(types.Log{}, *big.NewInt(chainID), &fulfilledLog) - lb.On("WasAlreadyConsumed", log).Return(false, nil).Once() - lb.On("MarkConsumed", log).Return(nil).Once() - defer lb.AssertExpectations(t) - chain := evmmocks.NewChain(t) - chain.On("LogBroadcaster").Return(lb) - listener := &listenerV2{ - respCount: map[string]uint64{}, - job: j, - blockNumberToReqID: pairing.New(), - latestHeadMu: sync.RWMutex{}, - chain: chain, - l: logger.TestLogger(t), - } - listener.handleLog(log, minConfs) - require.Equal(t, listener.respCount[fulfilledLog.RequestId.String()], uint64(1)) - req, ok := listener.blockNumberToReqID.FindMin().(fulfilledReqV2) - require.True(t, ok) - require.Equal(t, req.blockNumber, blockNumber) - require.Equal(t, req.reqID, "6") - }) - - tt.Run("v2 plus", func(t *testing.T) { - j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ - VRFVersion: vrfcommon.V2Plus, - RequestedConfsDelay: 10, - FromAddresses: []string{"0xF2982b7Ef6E3D8BB738f8Ea20502229781f6Ad97"}, - }).Toml()) - require.NoError(t, err) - fulfilledLog := vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalRandomWordsFulfilled{ - RequestId: big.NewInt(requestID), - Raw: types.Log{BlockNumber: blockNumber}, - } - log := log.NewLogBroadcast(types.Log{}, *big.NewInt(chainID), &fulfilledLog) - lb.On("WasAlreadyConsumed", log).Return(false, nil).Once() - lb.On("MarkConsumed", log).Return(nil).Once() - defer lb.AssertExpectations(t) - chain := evmmocks.NewChain(t) - chain.On("LogBroadcaster").Return(lb) - listener := &listenerV2{ - respCount: map[string]uint64{}, - job: j, - blockNumberToReqID: pairing.New(), - latestHeadMu: sync.RWMutex{}, - chain: chain, - l: logger.TestLogger(t), - } - listener.handleLog(log, minConfs) - require.Equal(t, listener.respCount[fulfilledLog.RequestId.String()], uint64(1)) - req, ok := listener.blockNumberToReqID.FindMin().(fulfilledReqV2) - require.True(t, ok) - require.Equal(t, req.blockNumber, blockNumber) - require.Equal(t, req.reqID, "6") - }) - -} diff --git a/core/services/vrf/v2/listener_v2_types.go b/core/services/vrf/v2/listener_v2_types.go index 5ad44c31a8..b3cbbff471 100644 --- a/core/services/vrf/v2/listener_v2_types.go +++ b/core/services/vrf/v2/listener_v2_types.go @@ -1,14 +1,14 @@ package v2 import ( + "fmt" "math/big" "time" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" + heaps "github.com/theodesp/go-heaps" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -16,6 +16,68 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" ) +type errPossiblyInsufficientFunds struct{} + +func (errPossiblyInsufficientFunds) Error() string { + return "Simulation errored, possibly insufficient funds. Request will remain unprocessed until funds are available" +} + +type errBlockhashNotInStore struct{} + +func (errBlockhashNotInStore) Error() string { + return "Blockhash not in store" +} + +type errProofVerificationFailed struct{} + +func (errProofVerificationFailed) Error() string { + return "Proof verification failed" +} + +type fulfilledReqV2 struct { + blockNumber uint64 + reqID string +} + +func (a fulfilledReqV2) Compare(b heaps.Item) int { + a1 := a + a2 := b.(fulfilledReqV2) + switch { + case a1.blockNumber > a2.blockNumber: + return 1 + case a1.blockNumber < a2.blockNumber: + return -1 + default: + return 0 + } +} + +type pendingRequest struct { + confirmedAtBlock uint64 + req RandomWordsRequested + utcTimestamp time.Time + + // used for exponential backoff when retrying + attempts int + lastTry time.Time +} + +type vrfPipelineResult struct { + err error + // maxFee indicates how much juels (link) or wei (ether) would be paid for the VRF request + // if it were to be fulfilled at the maximum gas price (i.e gas lane gas price). + maxFee *big.Int + // fundsNeeded indicates a "minimum balance" in juels or wei that must be held in the + // subscription's account in order to fulfill the request. + fundsNeeded *big.Int + run *pipeline.Run + payload string + gasLimit uint32 + req pendingRequest + proof VRFProof + reqCommitment RequestCommitment +} + // batchFulfillment contains all the information needed in order to // perform a batch fulfillment operation on the batch VRF coordinator. type batchFulfillment struct { @@ -24,7 +86,6 @@ type batchFulfillment struct { totalGasLimit uint32 runs []*pipeline.Run reqIDs []*big.Int - lbs []log.Broadcast maxFees []*big.Int txHashes []common.Hash fromAddress common.Address @@ -46,9 +107,6 @@ func newBatchFulfillment(result vrfPipelineResult, fromAddress common.Address, v reqIDs: []*big.Int{ result.req.req.RequestID(), }, - lbs: []log.Broadcast{ - result.req.lb, - }, maxFees: []*big.Int{ result.maxFee, }, @@ -97,7 +155,6 @@ func (b *batchFulfillments) addRun(result vrfPipelineResult, fromAddress common. currBatch.totalGasLimit += result.gasLimit currBatch.runs = append(currBatch.runs, result.run) currBatch.reqIDs = append(currBatch.reqIDs, result.req.req.RequestID()) - currBatch.lbs = append(currBatch.lbs, result.req.lb) currBatch.maxFees = append(currBatch.maxFees, result.maxFee) currBatch.txHashes = append(currBatch.txHashes, result.req.req.Raw().TxHash) } @@ -167,17 +224,15 @@ func (lsn *listenerV2) processBatch( var ethTX txmgr.Tx err = lsn.q.Transaction(func(tx pg.Queryer) error { if err = lsn.pipelineRunner.InsertFinishedRuns(batch.runs, true, pg.WithQueryer(tx)); err != nil { - return errors.Wrap(err, "inserting finished pipeline runs") - } - - if err = lsn.chain.LogBroadcaster().MarkManyConsumed(batch.lbs, pg.WithQueryer(tx)); err != nil { - return errors.Wrap(err, "mark logs consumed") + return fmt.Errorf("inserting finished pipeline runs: %w", err) } maxLink, maxEth := accumulateMaxLinkAndMaxEth(batch) - txHashes := []common.Hash{} + var ( + txHashes []common.Hash + reqIDHashes []common.Hash + ) copy(txHashes, batch.txHashes) - reqIDHashes := []common.Hash{} for _, reqID := range batch.reqIDs { reqIDHashes = append(reqIDHashes, common.BytesToHash(reqID.Bytes())) } @@ -196,8 +251,11 @@ func (lsn *listenerV2) processBatch( RequestTxHashes: txHashes, }, }) + if err != nil { + return fmt.Errorf("create batch fulfillment eth transaction: %w", err) + } - return errors.Wrap(err, "create batch fulfillment eth transaction") + return nil }) if err != nil { ll.Errorw("Error enqueuing batch fulfillments, requeuing requests", "err", err) @@ -217,35 +275,21 @@ func (lsn *listenerV2) processBatch( return } -// getUnconsumed returns the requests in the given slice that are not expired -// and not marked consumed in the log broadcaster. -func (lsn *listenerV2) getUnconsumed(l logger.Logger, reqs []pendingRequest) (unconsumed []pendingRequest, processed []string) { +// getReadyAndExpired filters out requests that are expired from the given pendingRequest slice +// and returns requests that are ready for processing. +func (lsn *listenerV2) getReadyAndExpired(l logger.Logger, reqs []pendingRequest) (ready []pendingRequest, expired []string) { for _, req := range reqs { // Check if we can ignore the request due to its age. if time.Now().UTC().Sub(req.utcTimestamp) >= lsn.job.VRFSpec.RequestTimeout { l.Infow("Request too old, dropping it", "reqID", req.req.RequestID().String(), "txHash", req.req.Raw().TxHash) - lsn.markLogAsConsumed(req.lb) - processed = append(processed, req.req.RequestID().String()) + expired = append(expired, req.req.RequestID().String()) vrfcommon.IncDroppedReqs(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, vrfcommon.V2, vrfcommon.ReasonAge) continue } - - // This check to see if the log was consumed needs to be in the same - // goroutine as the mark consumed to avoid processing duplicates. - consumed, err := lsn.chain.LogBroadcaster().WasAlreadyConsumed(req.lb) - if err != nil { - // Do not process for now, retry on next iteration. - l.Errorw("Could not determine if log was already consumed", - "reqID", req.req.RequestID().String(), - "txHash", req.req.Raw().TxHash, - "error", err) - } else if consumed { - processed = append(processed, req.req.RequestID().String()) - } else { - unconsumed = append(unconsumed, req) - } + // we always check if the requests are already fulfilled prior to trying to fulfill them again + ready = append(ready, req) } return } diff --git a/core/services/vrf/v2/listener_v2_types_test.go b/core/services/vrf/v2/listener_v2_types_test.go index 5391e18589..c66270210b 100644 --- a/core/services/vrf/v2/listener_v2_types_test.go +++ b/core/services/vrf/v2/listener_v2_types_test.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -30,7 +29,6 @@ func Test_BatchFulfillments_AddRun(t *testing.T) { TxHash: common.HexToHash("0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65"), }, }), - lb: mocks.NewBroadcast(t), }, run: pipeline.NewRun(pipeline.Spec{}, pipeline.Vars{}), }, fromAddress) @@ -49,7 +47,6 @@ func Test_BatchFulfillments_AddRun(t *testing.T) { TxHash: common.HexToHash("0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65"), }, }), - lb: mocks.NewBroadcast(t), }, run: pipeline.NewRun(pipeline.Spec{}, pipeline.Vars{}), }, fromAddress) @@ -70,7 +67,6 @@ func Test_BatchFulfillments_AddRun_V2Plus(t *testing.T) { TxHash: common.HexToHash("0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65"), }, }), - lb: mocks.NewBroadcast(t), }, run: pipeline.NewRun(pipeline.Spec{}, pipeline.Vars{}), }, fromAddress) @@ -89,7 +85,6 @@ func Test_BatchFulfillments_AddRun_V2Plus(t *testing.T) { TxHash: common.HexToHash("0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65"), }, }), - lb: mocks.NewBroadcast(t), }, run: pipeline.NewRun(pipeline.Spec{}, pipeline.Vars{}), }, fromAddress) diff --git a/core/services/vrf/vrfcommon/inflight_cache.go b/core/services/vrf/vrfcommon/inflight_cache.go new file mode 100644 index 0000000000..e5bd0e8870 --- /dev/null +++ b/core/services/vrf/vrfcommon/inflight_cache.go @@ -0,0 +1,85 @@ +package vrfcommon + +import ( + "sync" + + "github.com/ethereum/go-ethereum/core/types" +) + +type InflightCache interface { + Add(lg types.Log) + Contains(lg types.Log) bool + Size() int +} + +var _ InflightCache = (*inflightCache)(nil) + +const cachePruneInterval = 1000 + +type inflightCache struct { + // cache stores the logs whose fulfillments are currently in flight or already fulfilled. + cache map[logKey]struct{} + + // lookback defines how long state should be kept for. Logs included in blocks older than + // lookback may or may not be redelivered. + lookback int + + // lastPruneHeight is the blockheight at which logs were last pruned. + lastPruneHeight uint64 + + // mu synchronizes access to the delivered map. + mu sync.RWMutex +} + +func NewInflightCache(lookback int) InflightCache { + return &inflightCache{ + cache: make(map[logKey]struct{}), + lookback: lookback, + mu: sync.RWMutex{}, + } +} + +func (c *inflightCache) Size() int { + c.mu.RLock() + defer c.mu.RUnlock() + return len(c.cache) +} + +func (c *inflightCache) Add(lg types.Log) { + c.mu.Lock() + defer c.mu.Unlock() // unlock in the last defer, so that we hold the lock when pruning. + defer c.prune(lg.BlockNumber) + + c.cache[logKey{ + blockHash: lg.BlockHash, + blockNumber: lg.BlockNumber, + logIndex: lg.Index, + }] = struct{}{} +} + +func (c *inflightCache) Contains(lg types.Log) bool { + c.mu.RLock() + defer c.mu.RUnlock() + + _, ok := c.cache[logKey{ + blockHash: lg.BlockHash, + blockNumber: lg.BlockNumber, + logIndex: lg.Index, + }] + return ok +} + +func (c *inflightCache) prune(logBlock uint64) { + // Only prune every pruneInterval blocks + if int(logBlock)-int(c.lastPruneHeight) < cachePruneInterval { + return + } + + for key := range c.cache { + if int(key.blockNumber) < int(logBlock)-c.lookback { + delete(c.cache, key) + } + } + + c.lastPruneHeight = logBlock +} diff --git a/core/services/vrf/vrfcommon/log_dedupe_test.go b/core/services/vrf/vrfcommon/log_dedupe_test.go index 757842a3f6..f606b95e2a 100644 --- a/core/services/vrf/vrfcommon/log_dedupe_test.go +++ b/core/services/vrf/vrfcommon/log_dedupe_test.go @@ -30,6 +30,22 @@ func TestLogDeduper(t *testing.T) { }, results: []bool{true, false}, }, + { + name: "different block number", + logs: []types.Log{ + { + BlockNumber: 10, + BlockHash: common.Hash{0x1}, + Index: 3, + }, + { + BlockNumber: 11, + BlockHash: common.Hash{0x2}, + Index: 3, + }, + }, + results: []bool{true, true}, + }, { name: "same block number different hash", logs: []types.Log{ @@ -128,11 +144,11 @@ func TestLogDeduper(t *testing.T) { Index: 11, }, { - BlockNumber: 115, + BlockNumber: 1015, BlockHash: common.Hash{0x1, 0x1, 0x5}, Index: 0, }, - // Now the logs at blocks 10 and 11 should be pruned, and therefor redelivered. + // Now the logs at blocks 10 and 11 should be pruned, and therefore redelivered. // The log at block 115 should not be redelivered. { BlockNumber: 10, @@ -145,7 +161,7 @@ func TestLogDeduper(t *testing.T) { Index: 11, }, { - BlockNumber: 115, + BlockNumber: 1015, BlockHash: common.Hash{0x1, 0x1, 0x5}, Index: 0, }, diff --git a/core/services/vrf/vrftesthelpers/helpers.go b/core/services/vrf/vrftesthelpers/helpers.go index 2f269fbff0..77d3f33a65 100644 --- a/core/services/vrf/vrftesthelpers/helpers.go +++ b/core/services/vrf/vrftesthelpers/helpers.go @@ -67,7 +67,7 @@ func CreateAndStartBHSJob( TrustedBlockhashStoreAddress: trustedBlockhashStoreAddress, TrustedBlockhashStoreBatchSize: trustedBlockhashStoreBatchSize, PollPeriod: time.Second, - RunTimeout: 100 * time.Millisecond, + RunTimeout: 10 * time.Second, EVMChainID: 1337, FromAddresses: fromAddresses, }) diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index 0155dc0a53..0ecb85f1e4 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -247,6 +247,7 @@ type VRFSpecParams struct { BackoffInitialDelay time.Duration BackoffMaxDelay time.Duration GasLanePrice *assets.Wei + PollPeriod time.Duration } type VRFSpec struct { @@ -283,6 +284,10 @@ func GenerateVRFSpec(params VRFSpecParams) VRFSpec { if params.VRFOwnerAddress != "" && vrfVersion == vrfcommon.V2 { vrfOwnerAddress = params.VRFOwnerAddress } + pollPeriod := 5 * time.Second + if params.PollPeriod > 0 && (vrfVersion == vrfcommon.V2 || vrfVersion == vrfcommon.V2Plus) { + pollPeriod = params.PollPeriod + } batchFulfillmentGasMultiplier := 1.0 if params.BatchFulfillmentGasMultiplier >= 1.0 { batchFulfillmentGasMultiplier = params.BatchFulfillmentGasMultiplier @@ -406,6 +411,7 @@ chunkSize = %d backoffInitialDelay = "%s" backoffMaxDelay = "%s" gasLanePrice = "%s" +pollPeriod = "%s" observationSource = """ %s """ @@ -414,7 +420,8 @@ observationSource = """ jobID, name, coordinatorAddress, params.EVMChainID, batchCoordinatorAddress, params.BatchFulfillmentEnabled, strconv.FormatFloat(batchFulfillmentGasMultiplier, 'f', 2, 64), confirmations, params.RequestedConfsDelay, requestTimeout.String(), publicKey, chunkSize, - params.BackoffInitialDelay.String(), params.BackoffMaxDelay.String(), gasLanePrice.String(), observationSource) + params.BackoffInitialDelay.String(), params.BackoffMaxDelay.String(), gasLanePrice.String(), + pollPeriod.String(), observationSource) if len(params.FromAddresses) != 0 { var addresses []string for _, address := range params.FromAddresses { @@ -443,6 +450,7 @@ observationSource = """ BackoffMaxDelay: params.BackoffMaxDelay, VRFOwnerAddress: vrfOwnerAddress, VRFVersion: vrfVersion, + PollPeriod: pollPeriod, }, toml: toml} } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 0e3c8096f0..70320530aa 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -136,6 +136,7 @@ func CreateVRFV2PlusJob( ExternalJobID: jobUUID.String(), ObservationSource: ost, BatchFulfillmentEnabled: false, + PollPeriod: time.Second, }) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusJob, err) @@ -301,9 +302,10 @@ func SetupVRFV2_5Environment( // [[EVM.KeySpecific]] // Key = '...' nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, + node.WithLogPollInterval(1*time.Second), node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, vrfv2PlusConfig.CLNodeMaxGasPriceGWei), ) - l.Info().Msg("Restarting Node with new sending key PriceMax configuration") + l.Info().Msg("Restarting Node with new sending key PriceMax configuration and log poll period configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRestartCLNode, err) diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index 8ff8494155..abc6ef30e4 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -1128,6 +1128,7 @@ type VRFV2PlusJobSpec struct { BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` + PollPeriod time.Duration `toml:"pollPeriod"` } // Type returns the type of the job diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 5934809bac..ccbbce87a2 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -246,3 +246,9 @@ func WithVRFv2EVMEstimator(addresses []string, maxGasPriceGWei int64) NodeConfig } } + +func WithLogPollInterval(interval time.Duration) NodeConfigOpt { + return func(c *chainlink.Config) { + c.EVM[0].Chain.LogPollInterval = models.MustNewDuration(interval) + } +} From 1788c04f3e93f6d1478345b0ae92ace9f437d3d2 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 28 Nov 2023 08:43:12 -0600 Subject: [PATCH 208/327] plugins/cmd/chainlink-median: move to chainlink-feeds (#11270) --- .github/workflows/integration-tests.yml | 4 ++ GNUmakefile | 4 -- core/scripts/go.mod | 3 +- core/scripts/go.sum | 2 + core/services/ocr2/plugins/median/plugin.go | 67 ------------------- core/services/ocr2/plugins/median/services.go | 3 +- go.mod | 3 +- go.sum | 2 + integration-tests/go.mod | 3 +- integration-tests/go.sum | 2 + plugins/chainlink.Dockerfile | 12 ++-- plugins/cmd/chainlink-median/main.go | 41 ------------ 12 files changed, 26 insertions(+), 120 deletions(-) delete mode 100644 core/services/ocr2/plugins/median/plugin.go delete mode 100644 plugins/cmd/chainlink-median/main.go diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 9550be83ce..855e4ea936 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -615,6 +615,10 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Setup Go + uses: ./.github/actions/setup-go + with: + only-modules: "true" - name: Get the sha from go mod id: getshortsha run: | diff --git a/GNUmakefile b/GNUmakefile index cb665498a3..6cd5ab7143 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -57,10 +57,6 @@ chainlink-test: operator-ui ## Build a test build of chainlink binary. chainlink-local-start: ./chainlink -c /etc/node-secrets-volume/default.toml -c /etc/node-secrets-volume/overrides.toml -secrets /etc/node-secrets-volume/secrets.toml node start -d -p /etc/node-secrets-volume/node-password -a /etc/node-secrets-volume/apicredentials --vrfpassword=/etc/node-secrets-volume/apicredentials -.PHONY: install-median -install-median: ## Build & install the chainlink-median binary. - go install $(GOFLAGS) ./plugins/cmd/chainlink-median - .PHONY: install-medianpoc install-medianpoc: ## Build & install the chainlink-medianpoc binary. go install $(GOFLAGS) ./plugins/cmd/chainlink-medianpoc diff --git a/core/scripts/go.mod b/core/scripts/go.mod index d1795bbc84..7fa6055b16 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink/core/scripts -go 1.21 +go 1.21.3 // Make sure we're working with the latest chainlink libs replace github.com/smartcontractkit/chainlink/v2 => ../../ @@ -306,6 +306,7 @@ require ( github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // 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 cd7adf6bee..7706fa15f1 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1508,6 +1508,8 @@ github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f924 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= diff --git a/core/services/ocr2/plugins/median/plugin.go b/core/services/ocr2/plugins/median/plugin.go deleted file mode 100644 index 11197f0917..0000000000 --- a/core/services/ocr2/plugins/median/plugin.go +++ /dev/null @@ -1,67 +0,0 @@ -package median - -import ( - "context" - - "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/loop" - "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/types" -) - -type Plugin struct { - loop.Plugin - stop services.StopChan -} - -func NewPlugin(lggr logger.Logger) *Plugin { - return &Plugin{Plugin: loop.Plugin{Logger: lggr}, stop: make(services.StopChan)} -} - -func (p *Plugin) NewMedianFactory(ctx context.Context, provider types.MedianProvider, dataSource, juelsPerFeeCoin median.DataSource, errorLog loop.ErrorLog) (loop.ReportingPluginFactory, error) { - var ctxVals loop.ContextValues - ctxVals.SetValues(ctx) - lggr := logger.With(p.Logger, ctxVals.Args()...) - factory := median.NumericalMedianFactory{ - ContractTransmitter: provider.MedianContract(), - DataSource: dataSource, - JuelsPerFeeCoinDataSource: juelsPerFeeCoin, - Logger: logger.NewOCRWrapper(lggr, true, func(msg string) { - ctx, cancelFn := p.stop.NewCtx() - defer cancelFn() - if err := errorLog.SaveError(ctx, msg); err != nil { - lggr.Errorw("Unable to save error", "err", msg) - } - }), - OnchainConfigCodec: provider.OnchainConfigCodec(), - ReportCodec: provider.ReportCodec(), - } - s := &reportingPluginFactoryService{lggr: logger.Named(lggr, "ReportingPluginFactory"), ReportingPluginFactory: factory} - - p.SubService(s) - - return s, nil -} - -type reportingPluginFactoryService struct { - services.StateMachine - lggr logger.Logger - ocrtypes.ReportingPluginFactory -} - -func (r *reportingPluginFactoryService) Name() string { return r.lggr.Name() } - -func (r *reportingPluginFactoryService) Start(ctx context.Context) error { - return r.StartOnce("ReportingPluginFactory", func() error { return nil }) -} - -func (r *reportingPluginFactoryService) Close() error { - return r.StopOnce("ReportingPluginFactory", func() error { return nil }) -} - -func (r *reportingPluginFactoryService) HealthReport() map[string]error { - return map[string]error{r.Name(): r.Healthy()} -} diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 9d65921ef2..896bbacb41 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-feeds/median" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -125,7 +126,7 @@ func NewMedianServices(ctx context.Context, argsNoPlugin.ReportingPluginFactory = median srvs = append(srvs, median) } else { - argsNoPlugin.ReportingPluginFactory, err = NewPlugin(lggr).NewMedianFactory(ctx, medianProvider, dataSource, juelsPerFeeCoinSource, errorLog) + argsNoPlugin.ReportingPluginFactory, err = median.NewPlugin(lggr).NewMedianFactory(ctx, medianProvider, dataSource, juelsPerFeeCoinSource, errorLog) if err != nil { err = fmt.Errorf("failed to create median factory: %w", err) abort() diff --git a/go.mod b/go.mod index b2afd2e211..0133011813 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink/v2 -go 1.21 +go 1.21.3 require ( github.com/Depado/ginprom v1.7.11 @@ -68,6 +68,7 @@ require ( github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 + github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 diff --git a/go.sum b/go.sum index 98371af2e2..504f2ba807 100644 --- a/go.sum +++ b/go.sum @@ -1511,6 +1511,8 @@ github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f924 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 4cf6a502c4..63bf5e9e55 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink/integration-tests -go 1.21 +go 1.21.3 // Make sure we're working with the latest chainlink libs replace github.com/smartcontractkit/chainlink/v2 => ../ @@ -390,6 +390,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.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // 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 ef0a5b66ff..a1a272c0b8 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2380,6 +2380,8 @@ github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f924 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= diff --git a/plugins/chainlink.Dockerfile b/plugins/chainlink.Dockerfile index f07fab4812..2f3e46e9ce 100644 --- a/plugins/chainlink.Dockerfile +++ b/plugins/chainlink.Dockerfile @@ -16,12 +16,12 @@ COPY . . # Build the golang binaries RUN make install-chainlink -# Build LOOP Plugins -RUN make install-median # Install medianpoc binary RUN make install-medianpoc +# Link LOOP Plugin source dirs with simple names +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-feeds | xargs -I % ln -s % /chainlink-feeds RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana | xargs -I % ln -s % /chainlink-solana RUN mkdir /chainlink-starknet RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-starknet/relayer | xargs -I % ln -s % /chainlink-starknet/relayer @@ -30,6 +30,10 @@ RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-starknet/rela FROM golang:1.21-bullseye as buildplugins RUN go version +WORKDIR /chainlink-feeds +COPY --from=buildgo /chainlink-feeds . +RUN go install ./cmd/chainlink-feeds + WORKDIR /chainlink-solana COPY --from=buildgo /chainlink-solana . RUN go install ./pkg/solana/cmd/chainlink-solana @@ -53,9 +57,9 @@ RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ COPY --from=buildgo /go/bin/chainlink-medianpoc /usr/local/bin/ -COPY --from=buildgo /go/bin/chainlink-median /usr/local/bin/ -ENV CL_MEDIAN_CMD chainlink-median +COPY --from=buildplugins /go/bin/chainlink-feeds /usr/local/bin/ +ENV CL_MEDIAN_CMD chainlink-feeds COPY --from=buildplugins /go/bin/chainlink-solana /usr/local/bin/ ENV CL_SOLANA_CMD chainlink-solana COPY --from=buildplugins /go/bin/chainlink-starknet /usr/local/bin/ diff --git a/plugins/cmd/chainlink-median/main.go b/plugins/cmd/chainlink-median/main.go deleted file mode 100644 index e95bfbb221..0000000000 --- a/plugins/cmd/chainlink-median/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "github.com/hashicorp/go-plugin" - - "github.com/smartcontractkit/chainlink-common/pkg/loop" - - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median" -) - -const ( - loggerName = "PluginMedian" -) - -func main() { - s := loop.MustNewStartedServer(loggerName) - defer s.Stop() - - p := median.NewPlugin(s.Logger) - defer s.Logger.ErrorIfFn(p.Close, "Failed to close") - - s.MustRegister(p) - - stop := make(chan struct{}) - defer close(stop) - - plugin.Serve(&plugin.ServeConfig{ - HandshakeConfig: loop.PluginMedianHandshakeConfig(), - Plugins: map[string]plugin.Plugin{ - loop.PluginMedianName: &loop.GRPCPluginMedian{ - PluginServer: p, - BrokerConfig: loop.BrokerConfig{ - StopCh: stop, - Logger: s.Logger, - GRPCOpts: s.GRPCOpts, - }, - }, - }, - GRPCServer: s.GRPCOpts.NewServer, - }) -} From 25deefa0054d7a0dd2d729b61489e7107ee41d62 Mon Sep 17 00:00:00 2001 From: Dmytro Haidashenko <34754799+dhaidashenko@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:07:18 +0100 Subject: [PATCH 209/327] Soft migration to Generalize Multinode client for EVM BCI-2286 (#11369) * Allow switching to Generalized MultiNode EVM client via feature flag * test how linter reacts to deprecation * deprecate evm.client * address review comments * revert adding feature flag * create new client * fix call context * unwrapp CallContext args * deprecation msg improvements --- core/chains/evm/client/chain_client.go | 2 +- core/chains/evm/client/client.go | 2 + core/chains/evm/client/node.go | 4 ++ core/chains/evm/client/node_fsm.go | 2 + .../evm/client/node_selector_highest_head.go | 1 + .../client/node_selector_priority_level.go | 1 + .../evm/client/node_selector_round_robin.go | 1 + .../client/node_selector_total_difficulty.go | 1 + core/chains/evm/client/pool.go | 9 +++ core/chains/evm/client/send_only_node.go | 4 ++ core/chains/legacyevm/chain.go | 60 ++++++------------- 11 files changed, 45 insertions(+), 42 deletions(-) diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index d17c55f2e4..3efc5645e2 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -120,7 +120,7 @@ func (c *chainClient) BlockByNumber(ctx context.Context, number *big.Int) (b *ty } func (c *chainClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { - return c.multiNode.CallContext(ctx, result, method) + return c.multiNode.CallContext(ctx, result, method, args...) } func (c *chainClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index 91c8659d8c..cccda9914f 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -109,6 +109,8 @@ var _ htrktypes.Client[*evmtypes.Head, ethereum.Subscription, *big.Int, common.H // NewClientWithNodes instantiates a client from a list of nodes // Currently only supports one primary +// +// Deprecated: use [NewChainClient] func NewClientWithNodes(logger logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) { pool := NewPool(logger, selectionMode, leaseDuration, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType) return &client{ diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index 8bae566e27..e2da78b502 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -84,6 +84,8 @@ var ( //go:generate mockery --quiet --name Node --output ../mocks/ --case=underscore // Node represents a client that connects to an ethereum-compatible RPC node +// +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.Node] type Node interface { Start(ctx context.Context) error Close() error @@ -179,6 +181,8 @@ type node struct { } // NewNode returns a new *node as Node +// +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewNode] func NewNode(nodeCfg config.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, wsuri url.URL, httpuri *url.URL, name string, id int32, chainID *big.Int, nodeOrder int32) Node { n := new(node) n.name = name diff --git a/core/chains/evm/client/node_fsm.go b/core/chains/evm/client/node_fsm.go index 2d74512eac..10694eb7fc 100644 --- a/core/chains/evm/client/node_fsm.go +++ b/core/chains/evm/client/node_fsm.go @@ -38,6 +38,8 @@ var ( // NodeState represents the current state of the node // Node is a FSM (finite state machine) +// +// Deprecated: to be removed. It is now internal in common/client type NodeState int func (n NodeState) String() string { diff --git a/core/chains/evm/client/node_selector_highest_head.go b/core/chains/evm/client/node_selector_highest_head.go index 9e88674fac..2ed41486cf 100644 --- a/core/chains/evm/client/node_selector_highest_head.go +++ b/core/chains/evm/client/node_selector_highest_head.go @@ -6,6 +6,7 @@ import ( type highestHeadNodeSelector []Node +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewHighestHeadNodeSelector] func NewHighestHeadNodeSelector(nodes []Node) NodeSelector { return highestHeadNodeSelector(nodes) } diff --git a/core/chains/evm/client/node_selector_priority_level.go b/core/chains/evm/client/node_selector_priority_level.go index 7a5516dcd4..fba6d40332 100644 --- a/core/chains/evm/client/node_selector_priority_level.go +++ b/core/chains/evm/client/node_selector_priority_level.go @@ -16,6 +16,7 @@ type nodeWithPriority struct { priority int32 } +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewPriorityLevelNodeSelector] func NewPriorityLevelNodeSelector(nodes []Node) NodeSelector { return &priorityLevelNodeSelector{ nodes: nodes, diff --git a/core/chains/evm/client/node_selector_round_robin.go b/core/chains/evm/client/node_selector_round_robin.go index 9b2fa7508a..3bd19f0ede 100644 --- a/core/chains/evm/client/node_selector_round_robin.go +++ b/core/chains/evm/client/node_selector_round_robin.go @@ -7,6 +7,7 @@ type roundRobinSelector struct { roundRobinCount atomic.Uint32 } +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewRoundRobinSelector] func NewRoundRobinSelector(nodes []Node) NodeSelector { return &roundRobinSelector{ nodes: nodes, diff --git a/core/chains/evm/client/node_selector_total_difficulty.go b/core/chains/evm/client/node_selector_total_difficulty.go index a368422e49..99a1c89dd4 100644 --- a/core/chains/evm/client/node_selector_total_difficulty.go +++ b/core/chains/evm/client/node_selector_total_difficulty.go @@ -6,6 +6,7 @@ import ( type totalDifficultyNodeSelector []Node +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewTotalDifficultyNodeSelector] func NewTotalDifficultyNodeSelector(nodes []Node) NodeSelector { return totalDifficultyNodeSelector(nodes) } diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index ab190f8c6a..9217f633dc 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -39,6 +39,8 @@ const ( ) // NodeSelector represents a strategy to select the next node from the pool. +// +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NodeSelector] type NodeSelector interface { // Select returns a Node, or nil if none can be selected. // Implementation must be thread-safe. @@ -48,6 +50,8 @@ type NodeSelector interface { } // PoolConfig represents settings for the Pool +// +// Deprecated: to be removed type PoolConfig interface { NodeSelectionMode() string NodeNoNewHeadsThreshold() time.Duration @@ -56,6 +60,8 @@ type PoolConfig interface { // Pool represents an abstraction over one or more primary nodes // It is responsible for liveness checking and balancing queries across live nodes +// +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.MultiNode] type Pool struct { services.StateMachine nodes []Node @@ -76,6 +82,9 @@ type Pool struct { wg sync.WaitGroup } +// NewPool - creates new instance of [Pool] +// +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewMultiNode] func NewPool(lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsTreshold time.Duration, nodes []Node, sendonlys []SendOnlyNode, chainID *big.Int, chainType config.ChainType) *Pool { if chainID == nil { panic("chainID is required") diff --git a/core/chains/evm/client/send_only_node.go b/core/chains/evm/client/send_only_node.go index 62a22ee193..b6ad26696f 100644 --- a/core/chains/evm/client/send_only_node.go +++ b/core/chains/evm/client/send_only_node.go @@ -21,6 +21,8 @@ import ( //go:generate mockery --quiet --name SendOnlyNode --output ../mocks/ --case=underscore // SendOnlyNode represents one ethereum node used as a sendonly +// +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.SendOnlyNode] type SendOnlyNode interface { // Start may attempt to connect to the node, but should only return error for misconfiguration - never for temporary errors. Start(context.Context) error @@ -73,6 +75,8 @@ type sendOnlyNode struct { } // NewSendOnlyNode returns a new sendonly node +// +// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewSendOnlyNode] func NewSendOnlyNode(lggr logger.Logger, httpuri url.URL, name string, chainID *big.Int) SendOnlyNode { s := new(sendOnlyNode) s.name = name diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 0c35d929fc..4b4c69f1ab 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -220,11 +221,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod if !cfg.EVMRPCEnabled() { client = evmclient.NewNullClient(chainID, l) } else if opts.GenEthClient == nil { - var err2 error - client, err2 = newEthClientFromChain(cfg.EVM().NodePool(), cfg.EVM().NodeNoNewHeadsThreshold(), l, chainID, chainType, nodes) - if err2 != nil { - return nil, fmt.Errorf("failed to instantiate eth client for chain with ID %s: %w", cfg.EVM().ChainID().String(), err2) - } + client = newEthClientFromCfg(cfg.EVM().NodePool(), cfg.EVM().NodeNoNewHeadsThreshold(), l, chainID, chainType, nodes) } else { client = opts.GenEthClient(chainID) } @@ -474,46 +471,27 @@ func (c *chain) Logger() logger.Logger { return c.logger } func (c *chain) BalanceMonitor() monitor.BalanceMonitor { return c.balanceMonitor } func (c *chain) GasEstimator() gas.EvmFeeEstimator { return c.gasEstimator } -func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType commonconfig.ChainType, nodes []*toml.Node) (evmclient.Client, error) { - var primaries []evmclient.Node - var sendonlys []evmclient.SendOnlyNode +func newEthClientFromCfg(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType commonconfig.ChainType, nodes []*toml.Node) evmclient.Client { + var empty url.URL + var primaries []commonclient.Node[*big.Int, *evmtypes.Head, evmclient.RPCCLient] + var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient] for i, node := range nodes { if node.SendOnly != nil && *node.SendOnly { - sendonly := evmclient.NewSendOnlyNode(lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID) + name := fmt.Sprintf("eth-sendonly-rpc-%d", i) + rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), name, int32(i), chainID, + commonclient.Secondary) + sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCCLient](lggr, (url.URL)(*node.HTTPURL), + *node.Name, chainID, rpc) sendonlys = append(sendonlys, sendonly) } else { - primary, err := newPrimary(cfg, noNewHeadsThreshold, lggr, node, int32(i), chainID) - if err != nil { - return nil, err - } - primaries = append(primaries, primary) + name := fmt.Sprintf("eth-primary-rpc-%d", i) + rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), name, int32(i), + chainID, commonclient.Primary) + primaryNode := commonclient.NewNode[*big.Int, *evmtypes.Head, evmclient.RPCCLient](cfg, noNewHeadsThreshold, + lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order, + rpc, "EVM") + primaries = append(primaries, primaryNode) } } - return evmclient.NewClientWithNodes(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) + return evmclient.NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) } - -func newPrimary(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, n *toml.Node, id int32, chainID *big.Int) (evmclient.Node, error) { - if n.SendOnly != nil && *n.SendOnly { - return nil, errors.New("cannot cast send-only node to primary") - } - - return evmclient.NewNode(cfg, noNewHeadsThreshold, lggr, (url.URL)(*n.WSURL), (*url.URL)(n.HTTPURL), *n.Name, id, chainID, *n.Order), nil -} - -// TODO-1663: replace newEthClientFromChain with the function below once client.go is deprecated. -//func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType config.ChainType, nodes []*toml.Node) evmclient.Client { -// var empty url.URL -// var primaries []commonclient.Node[*big.Int, *evmtypes.Head, evmclient.RPCCLient] -// var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient] -// for i, node := range nodes { -// if node.SendOnly != nil && *node.SendOnly { -// rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), fmt.Sprintf("eth-sendonly-rpc-%d", i), int32(i), chainID, commontypes.Primary) -// sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCCLient](lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID, rpc) -// sendonlys = append(sendonlys, sendonly) -// } else { -// rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), fmt.Sprintf("eth-sendonly-rpc-%d", i), int32(i), chainID, commontypes.Primary) -// primaries = append(primaries, commonclient.NewNode[*big.Int, *evmtypes.Head, evmclient.RPCCLient](cfg, noNewHeadsThreshold, lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order, rpc, "EVM")) -// } -// } -// return evmclient.NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) -//} From 10588c7a68f45db03012b9c1cff1d2bc70fe749c Mon Sep 17 00:00:00 2001 From: Tate Date: Tue, 28 Nov 2023 09:37:38 -0700 Subject: [PATCH 210/327] Add loud error for failure to get the solana sha (#11400) --- .github/workflows/integration-tests.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 855e4ea936..5a505ce01c 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -623,6 +623,10 @@ jobs: id: getshortsha run: | sol_ver=$(go list -m -json github.com/smartcontractkit/chainlink-solana | jq -r .Version) + if [ -z "${sol_ver}" ]; then + echo "Error: could not get the solana version from the go.mod file, look above for error(s)" + exit 1 + fi short_sha="${sol_ver##*-}" echo "short sha is: ${short_sha}" echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" @@ -638,6 +642,10 @@ jobs: run: | cd solanapath full_sha=$(git rev-parse ${{steps.getshortsha.outputs.short_sha}}) + if [ -z "${full_sha}" ]; then + echo "Error: could not get the full sha from the short sha using git, look above for error(s)" + exit 1 + fi echo "sha is: ${full_sha}" echo "sha=${full_sha}" >> "$GITHUB_OUTPUT" From f47e29094b8093c1beef0a4654eee92d026e7980 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 28 Nov 2023 11:45:47 -0500 Subject: [PATCH 211/327] Feed LatestPrice query cache (#11326) * Price retrieval cache for Mercury Problem: Core nodes are querying LatestReport a lot (~70rps). This is not only wasteful, it potentially increases latency if Mercury server falls behind and is also completely unnecessary. We do not need such up-to-the-millisecond accuracy for billing, Proposed solution: Introduce a price cache for mercury with a TTL e.g. of 1 minute or whatever tolerance we have for billing price and only fetch from the server when the cache becomes stale. * fix * Some PR comments * Fix more PR comments * PR comments * lint --- core/cmd/shell.go | 11 + core/config/docs/core.toml | 23 + core/config/mercury_config.go | 13 +- core/config/toml/types.go | 28 ++ core/internal/cltest/cltest.go | 11 + core/services/chainlink/application.go | 8 + core/services/chainlink/config_general.go | 2 +- core/services/chainlink/config_mercury.go | 24 ++ core/services/chainlink/config_test.go | 13 + core/services/chainlink/relayer_factory.go | 3 + .../testdata/config-empty-effective.toml | 6 + .../chainlink/testdata/config-full.toml | 6 + .../config-multi-chain-effective.toml | 6 + core/services/ocr2/delegate.go | 1 + core/services/relay/evm/evm.go | 8 +- .../services/relay/evm/mercury/utils/feeds.go | 4 + .../relay/evm/mercury/wsrpc/cache/cache.go | 395 ++++++++++++++++++ .../evm/mercury/wsrpc/cache/cache_set.go | 120 ++++++ .../evm/mercury/wsrpc/cache/cache_set_test.go | 48 +++ .../evm/mercury/wsrpc/cache/cache_test.go | 199 +++++++++ .../evm/mercury/wsrpc/cache/helpers_test.go | 38 ++ .../relay/evm/mercury/wsrpc/client.go | 49 ++- .../relay/evm/mercury/wsrpc/client_test.go | 144 ++++++- .../relay/evm/mercury/wsrpc/mocks/mocks.go | 3 + core/services/relay/evm/mercury/wsrpc/pool.go | 15 +- .../relay/evm/mercury/wsrpc/pool_test.go | 16 +- core/utils/hash.go | 20 + .../testdata/config-empty-effective.toml | 6 + core/web/resolver/testdata/config-full.toml | 6 + .../config-multi-chain-effective.toml | 6 + docs/CHANGELOG.md | 33 +- docs/CONFIG.md | 45 ++ testdata/scripts/node/validate/default.txtar | 6 + .../disk-based-logging-disabled.txtar | 6 + .../validate/disk-based-logging-no-dir.txtar | 6 + .../node/validate/disk-based-logging.txtar | 6 + testdata/scripts/node/validate/invalid.txtar | 6 + testdata/scripts/node/validate/valid.txtar | 6 + testdata/scripts/node/validate/warnings.txtar | 6 + 39 files changed, 1322 insertions(+), 30 deletions(-) create mode 100644 core/services/relay/evm/mercury/wsrpc/cache/cache.go create mode 100644 core/services/relay/evm/mercury/wsrpc/cache/cache_set.go create mode 100644 core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go create mode 100644 core/services/relay/evm/mercury/wsrpc/cache/cache_test.go create mode 100644 core/services/relay/evm/mercury/wsrpc/cache/helpers_test.go diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 35659aa779..daf936b36c 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -43,6 +43,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/periodicbackup" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/versioning" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/sessions" @@ -157,11 +159,19 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), dbListener.MinReconnectInterval(), dbListener.MaxReconnectDuration(), appLggr, cfg.AppID()) loopRegistry := plugins.NewLoopRegistry(appLggr, cfg.Tracing()) + mercuryPool := wsrpc.NewPool(appLggr, cache.Config{ + Logger: appLggr, + LatestReportTTL: cfg.Mercury().Cache().LatestReportTTL(), + MaxStaleAge: cfg.Mercury().Cache().MaxStaleAge(), + LatestReportDeadline: cfg.Mercury().Cache().LatestReportDeadline(), + }) + // create the relayer-chain interoperators from application configuration relayerFactory := chainlink.RelayerFactory{ Logger: appLggr, LoopRegistry: loopRegistry, GRPCOpts: grpcOpts, + MercuryPool: mercuryPool, } evmFactoryCfg := chainlink.EVMFactoryConfig{ @@ -227,6 +237,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G SecretGenerator: chainlink.FilePersistedSecretGenerator{}, LoopRegistry: loopRegistry, GRPCOpts: grpcOpts, + MercuryPool: mercuryPool, }) } diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 79801c2c52..e438f4553f 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -601,3 +601,26 @@ TLSCertPath = '/path/to/cert.pem' # Example [Tracing.Attributes] # env is an example user specified key-value pair env = 'test' # Example + +[Mercury] + +# Mercury.Cache controls settings for the price retrieval cache querying a mercury server +[Mercury.Cache] +# LatestReportTTL controls how "stale" we will allow a price to be e.g. if +# set to 1s, a new price will always be fetched if the last result was +# from 1 second ago or older. +# +# Another way of looking at it is such: the cache will _never_ return a +# price that was queried from now-LatestReportTTL or before. +# +# Setting to zero disables caching entirely. +LatestReportTTL = "1s" # Default +# MaxStaleAge is that maximum amount of time that a value can be stale +# before it is deleted from the cache (a form of garbage collection). +# +# This should generally be set to something much larger than +# LatestReportTTL. Setting to zero disables garbage collection. +MaxStaleAge = "1h" # Default +# LatestReportDeadline controls how long to wait for a response from the +# mercury server before retrying. Setting this to zero will wait indefinitely. +LatestReportDeadline = "5s" # Default diff --git a/core/config/mercury_config.go b/core/config/mercury_config.go index d7e985d14e..e530af6338 100644 --- a/core/config/mercury_config.go +++ b/core/config/mercury_config.go @@ -1,7 +1,18 @@ package config -import ocr2models "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" +import ( + "time" + + ocr2models "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" +) + +type MercuryCache interface { + LatestReportTTL() time.Duration + MaxStaleAge() time.Duration + LatestReportDeadline() time.Duration +} type Mercury interface { Credentials(credName string) *ocr2models.MercuryCredentials + Cache() MercuryCache } diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 31076c1f1d..c420d7f3f4 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -54,6 +54,7 @@ type Core struct { Sentry Sentry `toml:",omitempty"` Insecure Insecure `toml:",omitempty"` Tracing Tracing `toml:",omitempty"` + Mercury Mercury `toml:",omitempty"` } // SetFrom updates c with any non-nil values from f. (currently TOML field only!) @@ -82,6 +83,7 @@ func (c *Core) SetFrom(f *Core) { c.OCR.setFrom(&f.OCR) c.P2P.setFrom(&f.P2P) c.Keeper.setFrom(&f.Keeper) + c.Mercury.setFrom(&f.Mercury) c.AutoPprof.setFrom(&f.AutoPprof) c.Pyroscope.setFrom(&f.Pyroscope) @@ -1358,6 +1360,32 @@ func (ins *Insecure) setFrom(f *Insecure) { } } +type MercuryCache struct { + LatestReportTTL *models.Duration + MaxStaleAge *models.Duration + LatestReportDeadline *models.Duration +} + +func (mc *MercuryCache) setFrom(f *MercuryCache) { + if v := f.LatestReportTTL; v != nil { + mc.LatestReportTTL = v + } + if v := f.MaxStaleAge; v != nil { + mc.MaxStaleAge = v + } + if v := f.LatestReportDeadline; v != nil { + mc.LatestReportDeadline = v + } +} + +type Mercury struct { + Cache MercuryCache `toml:",omitempty"` +} + +func (m *Mercury) setFrom(f *Mercury) { + m.Cache.setFrom(&f.Cache) +} + type MercuryCredentials struct { // LegacyURL is the legacy base URL for mercury v0.2 API LegacyURL *models.SecretURL diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 17a1d4fadd..fc648486a0 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -76,6 +76,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" clsessions "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/static" @@ -342,10 +344,18 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn mailMon := utils.NewMailboxMonitor(cfg.AppID().String()) loopRegistry := plugins.NewLoopRegistry(lggr, nil) + mercuryPool := wsrpc.NewPool(lggr, cache.Config{ + Logger: lggr, + LatestReportTTL: cfg.Mercury().Cache().LatestReportTTL(), + MaxStaleAge: cfg.Mercury().Cache().MaxStaleAge(), + LatestReportDeadline: cfg.Mercury().Cache().LatestReportDeadline(), + }) + relayerFactory := chainlink.RelayerFactory{ Logger: lggr, LoopRegistry: loopRegistry, GRPCOpts: loop.GRPCOpts{}, + MercuryPool: mercuryPool, } evmOpts := chainlink.EVMFactoryConfig{ @@ -419,6 +429,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn UnrestrictedHTTPClient: c, SecretGenerator: MockSecretGenerator{}, LoopRegistry: plugins.NewLoopRegistry(lggr, nil), + MercuryPool: mercuryPool, }) require.NoError(t, err) app := appInstance.(*chainlink.ChainlinkApplication) diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 29679ee92f..1ecf95d3a5 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -48,6 +48,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" @@ -160,6 +161,7 @@ type ApplicationOpts struct { SecretGenerator SecretGenerator LoopRegistry *plugins.LoopRegistry GRPCOpts loop.GRPCOpts + MercuryPool wsrpc.Pool } // NewApplication initializes a new store if one is not already @@ -241,6 +243,9 @@ func NewApplication(opts ApplicationOpts) (Application, error) { promReporter := promreporter.NewPromReporter(db.DB, globalLogger) srvcs = append(srvcs, promReporter) + // pool must be started before all relayers and stopped after them + srvcs = append(srvcs, opts.MercuryPool) + // EVM chains are used all over the place. This will need to change for fully EVM extraction // TODO: BCF-2510, BCF-2511 @@ -457,6 +462,9 @@ func NewApplication(opts ApplicationOpts) (Application, error) { } for _, s := range srvcs { + if s == nil { + panic("service unexpectedly nil") + } if err := healthChecker.Register(s); err != nil { return nil, err } diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index fff7822a81..c7d9cc6ce5 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -507,7 +507,7 @@ func (g *generalConfig) Prometheus() coreconfig.Prometheus { } func (g *generalConfig) Mercury() coreconfig.Mercury { - return &mercuryConfig{s: g.secrets.Mercury} + return &mercuryConfig{c: g.c.Mercury, s: g.secrets.Mercury} } func (g *generalConfig) Threshold() coreconfig.Threshold { diff --git a/core/services/chainlink/config_mercury.go b/core/services/chainlink/config_mercury.go index 1a20dd069d..61e48d340e 100644 --- a/core/services/chainlink/config_mercury.go +++ b/core/services/chainlink/config_mercury.go @@ -1,11 +1,31 @@ package chainlink import ( + "time" + + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" ) +var _ config.MercuryCache = (*mercuryCacheConfig)(nil) + +type mercuryCacheConfig struct { + c toml.MercuryCache +} + +func (m *mercuryCacheConfig) LatestReportTTL() time.Duration { + return m.c.LatestReportTTL.Duration() +} +func (m *mercuryCacheConfig) MaxStaleAge() time.Duration { + return m.c.MaxStaleAge.Duration() +} +func (m *mercuryCacheConfig) LatestReportDeadline() time.Duration { + return m.c.LatestReportDeadline.Duration() +} + type mercuryConfig struct { + c toml.Mercury s toml.MercurySecrets } @@ -23,3 +43,7 @@ func (m *mercuryConfig) Credentials(credName string) *models.MercuryCredentials } return nil } + +func (m *mercuryConfig) Cache() config.MercuryCache { + return &mercuryCacheConfig{c: m.c.Cache} +} diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 33fda22128..d777e34abf 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -668,6 +668,13 @@ func TestConfig_Marshal(t *testing.T) { }, }, } + full.Mercury = toml.Mercury{ + Cache: toml.MercuryCache{ + LatestReportTTL: models.MustNewDuration(100 * time.Second), + MaxStaleAge: models.MustNewDuration(101 * time.Second), + LatestReportDeadline: models.MustNewDuration(102 * time.Second), + }, + } for _, tt := range []struct { name string @@ -1103,6 +1110,12 @@ ConfirmationPoll = '42s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +`}, + {"Mercury", Config{Core: toml.Core{Mercury: full.Mercury}}, `[Mercury] +[Mercury.Cache] +LatestReportTTL = '1m40s' +MaxStaleAge = '1m41s' +LatestReportDeadline = '1m42s' `}, {"full", full, fullTOML}, {"multi-chain", multiChain, multiChainTOML}, diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index c15643551e..8b8749013f 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -32,6 +33,7 @@ type RelayerFactory struct { logger.Logger *plugins.LoopRegistry loop.GRPCOpts + MercuryPool wsrpc.Pool } type EVMFactoryConfig struct { @@ -68,6 +70,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m QConfig: ccOpts.AppConfig.Database(), CSAETHKeystore: config.CSAETHKeystore, EventBroadcaster: ccOpts.EventBroadcaster, + MercuryPool: r.MercuryPool, } relayer, err2 := evmrelay.NewRelayer(r.Logger.Named("EVM").Named(relayID.ChainID), chain, relayerOpts) if err2 != nil { diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 8f3135b34e..2531e7c281 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -234,3 +234,9 @@ NodeID = '' SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' + +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index eca5f6f96d..8036165d6e 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -245,6 +245,12 @@ TLSCertPath = '/path/to/cert.pem' env = 'dev' test = 'load' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1m40s' +MaxStaleAge = '1m41s' +LatestReportDeadline = '1m42s' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 6a60dfd419..371cc50a17 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -235,6 +235,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 45ee4e0f8f..eebc95903e 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -189,6 +189,7 @@ type jobPipelineConfig interface { type mercuryConfig interface { Credentials(credName string) *models.MercuryCredentials + Cache() coreconfig.MercuryCache } type thresholdConfig interface { diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 952c1869bf..088a69a258 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -66,6 +66,7 @@ type RelayerOpts struct { pg.QConfig CSAETHKeystore pg.EventBroadcaster + MercuryPool wsrpc.Pool } func (c RelayerOpts) Validate() error { @@ -100,7 +101,7 @@ func NewRelayer(lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*R chain: chain, lggr: lggr, ks: opts.CSAETHKeystore, - mercuryPool: wsrpc.NewPool(lggr), + mercuryPool: opts.MercuryPool, eventBroadcaster: opts.EventBroadcaster, pgCfg: opts.QConfig, }, nil @@ -116,17 +117,16 @@ func (r *Relayer) Start(context.Context) error { } func (r *Relayer) Close() error { - return r.mercuryPool.Close() + return nil } // Ready does noop: always ready func (r *Relayer) Ready() error { - return r.mercuryPool.Ready() + return nil } func (r *Relayer) HealthReport() (report map[string]error) { report = make(map[string]error) - services.CopyHealth(report, r.mercuryPool.HealthReport()) return } diff --git a/core/services/relay/evm/mercury/utils/feeds.go b/core/services/relay/evm/mercury/utils/feeds.go index b1a20618ef..6f8978bbf0 100644 --- a/core/services/relay/evm/mercury/utils/feeds.go +++ b/core/services/relay/evm/mercury/utils/feeds.go @@ -88,6 +88,10 @@ const ( type FeedID [32]byte +func BytesToFeedID(b []byte) FeedID { + return (FeedID)(utils.BytesToHash(b)) +} + func (f FeedID) Hex() string { return (utils.Hash)(f).Hex() } func (f FeedID) String() string { return (utils.Hash)(f).String() } diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache.go b/core/services/relay/evm/mercury/wsrpc/cache/cache.go new file mode 100644 index 0000000000..4962210d58 --- /dev/null +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache.go @@ -0,0 +1,395 @@ +package cache + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/jpillora/backoff" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +var ( + promFetchFailedCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_cache_fetch_failure_count", + Help: "Number of times we tried to call LatestReport from the mercury server, but some kind of error occurred", + }, + []string{"serverURL", "feedID"}, + ) + promCacheHitCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_cache_hit_count", + Help: "Running count of cache hits", + }, + []string{"serverURL", "feedID"}, + ) + promCacheWaitCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_cache_wait_count", + Help: "Running count of times that we had to wait for a fetch to complete before reading from cache", + }, + []string{"serverURL", "feedID"}, + ) + promCacheMissCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_cache_miss_count", + Help: "Running count of cache misses", + }, + []string{"serverURL", "feedID"}, + ) +) + +type Fetcher interface { + LatestReport(ctx context.Context, req *pb.LatestReportRequest) (resp *pb.LatestReportResponse, err error) +} + +type Client interface { + Fetcher + ServerURL() string + RawClient() pb.MercuryClient +} + +// Cache is scoped to one particular mercury server +// Use CacheSet to hold lookups for multiple servers +type Cache interface { + Fetcher + services.Service +} + +type Config struct { + Logger logger.Logger + // LatestReportTTL controls how "stale" we will allow a price to be e.g. if + // set to 1s, a new price will always be fetched if the last result was + // from more than 1 second ago. + // + // Another way of looking at it is such: the cache will _never_ return a + // price that was queried from before now-LatestReportTTL. + // + // Setting to zero disables caching entirely. + LatestReportTTL time.Duration + // MaxStaleAge is that maximum amount of time that a value can be stale + // before it is deleted from the cache (a form of garbage collection). + // + // This should generally be set to something much larger than + // LatestReportTTL. Setting to zero disables garbage collection. + MaxStaleAge time.Duration + // LatestReportDeadline controls how long to wait for a response before + // retrying. Setting this to zero will wait indefinitely. + LatestReportDeadline time.Duration +} + +func NewCache(client Client, cfg Config) Cache { + return newMemCache(client, cfg) +} + +type cacheVal struct { + sync.RWMutex + + fetching bool + fetchCh chan (struct{}) + + val *pb.LatestReportResponse + err error + + expiresAt time.Time +} + +func (v *cacheVal) read() (*pb.LatestReportResponse, error) { + v.RLock() + defer v.RUnlock() + return v.val, v.err +} + +// caller expected to hold lock +func (v *cacheVal) initiateFetch() <-chan struct{} { + if v.fetching { + panic("cannot initiateFetch on cache val that is already fetching") + } + v.fetching = true + v.fetchCh = make(chan struct{}) + return v.fetchCh +} + +func (v *cacheVal) setError(err error) { + v.Lock() + defer v.Unlock() + v.err = err +} + +func (v *cacheVal) completeFetch(val *pb.LatestReportResponse, err error, expiresAt time.Time) { + v.Lock() + defer v.Unlock() + if !v.fetching { + panic("can only completeFetch on cache val that is fetching") + } + v.val = val + v.err = err + if err == nil { + v.expiresAt = expiresAt + } + close(v.fetchCh) + v.fetchCh = nil + v.fetching = false +} + +func (v *cacheVal) abandonFetch(err error) { + v.completeFetch(nil, err, time.Now()) +} + +func (v *cacheVal) waitForResult(ctx context.Context, chResult <-chan struct{}, chStop <-chan struct{}) (*pb.LatestReportResponse, error) { + select { + case <-ctx.Done(): + _, err := v.read() + return nil, errors.Join(err, ctx.Err()) + case <-chStop: + return nil, errors.New("stopped") + case <-chResult: + return v.read() + } +} + +// memCache stores values in memory +// it will never return a stale value older than latestPriceTTL, instead +// waiting for a successful fetch or caller context cancels, whichever comes +// first +type memCache struct { + services.StateMachine + lggr logger.Logger + + client Client + + latestPriceTTL time.Duration + maxStaleAge time.Duration + latestReportDeadline time.Duration + + cache sync.Map + + wg sync.WaitGroup + chStop services.StopChan +} + +func newMemCache(client Client, cfg Config) *memCache { + return &memCache{ + services.StateMachine{}, + cfg.Logger.Named("MercuryMemCache"), + client, + cfg.LatestReportTTL, + cfg.MaxStaleAge, + cfg.LatestReportDeadline, + sync.Map{}, + sync.WaitGroup{}, + make(chan (struct{})), + } +} + +// LatestReport +// NOTE: This will actually block on all types of errors, even non-timeouts. +// Context should be set carefully and timed to be the maximum time we are +// willing to wait for a result, the background thread will keep re-querying +// until it gets one even on networking errors etc. +func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest) (resp *pb.LatestReportResponse, err error) { + if req == nil { + return nil, errors.New("req must not be nil") + } + if m.latestPriceTTL <= 0 { + return m.client.RawClient().LatestReport(ctx, req) + } + vi, _ := m.cache.LoadOrStore(req, &cacheVal{ + sync.RWMutex{}, + false, + nil, + nil, + nil, + time.Now(), // first result is always "expired" and requires fetch + }) + v := vi.(*cacheVal) + + // HOT PATH + v.RLock() + if time.Now().Before(v.expiresAt) { + // CACHE HIT + promCacheHitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + + defer v.RUnlock() + return v.val, nil + } else if v.fetching { + // CACHE WAIT + promCacheWaitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + // if someone else is fetching then wait for the fetch to complete + ch := v.fetchCh + v.RUnlock() + return v.waitForResult(ctx, ch, m.chStop) + } + // CACHE MISS + promCacheMissCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + // fallthrough to cold path and fetch + v.RUnlock() + + // COLD PATH + v.Lock() + if time.Now().Before(v.expiresAt) { + // CACHE HIT + promCacheHitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + defer v.RUnlock() + return v.val, nil + } else if v.fetching { + // CACHE WAIT + promCacheWaitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + // if someone else is fetching then wait for the fetch to complete + ch := v.fetchCh + v.Unlock() + return v.waitForResult(ctx, ch, m.chStop) + } + // CACHE MISS + promCacheMissCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + // initiate the fetch and wait for result + ch := v.initiateFetch() + v.Unlock() + + ok := m.IfStarted(func() { + m.wg.Add(1) + go m.fetch(req, v) + }) + if !ok { + err := fmt.Errorf("memCache must be started, but is: %v", m.State()) + v.abandonFetch(err) + return nil, err + } + return v.waitForResult(ctx, ch, m.chStop) +} + +const minBackoffRetryInterval = 50 * time.Millisecond + +// newBackoff creates a backoff for retrying +func (m *memCache) newBackoff() backoff.Backoff { + min := minBackoffRetryInterval + max := m.latestPriceTTL / 2 + if min > max { + // avoid setting a min that is greater than max + min = max + } + return backoff.Backoff{ + Min: min, + Max: max, + Factor: 2, + Jitter: true, + } +} + +// fetch continually tries to call FetchLatestReport and write the result to v +// it writes errors as they come up +func (m *memCache) fetch(req *pb.LatestReportRequest, v *cacheVal) { + defer m.wg.Done() + b := m.newBackoff() + memcacheCtx, cancel := m.chStop.NewCtx() + defer cancel() + var t time.Time + var val *pb.LatestReportResponse + var err error + defer func() { + v.completeFetch(val, err, t.Add(m.latestPriceTTL)) + }() + + for { + t = time.Now() + + ctx := memcacheCtx + cancel := func() {} + if m.latestReportDeadline > 0 { + ctx, cancel = context.WithTimeoutCause(memcacheCtx, m.latestReportDeadline, errors.New("latest report fetch deadline exceeded")) + } + + // NOTE: must drop down to RawClient here otherwise we enter an + // infinite loop of calling a client that calls back to this same cache + // and on and on + val, err = m.client.RawClient().LatestReport(ctx, req) + cancel() + v.setError(err) + if memcacheCtx.Err() != nil { + // stopped + return + } else if err != nil { + m.lggr.Warnw("FetchLatestReport failed", "err", err) + promFetchFailedCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + select { + case <-m.chStop: + return + case <-time.After(b.Duration()): + continue + } + } + return + } +} + +func (m *memCache) Start(context.Context) error { + return m.StartOnce(m.Name(), func() error { + m.wg.Add(1) + go m.runloop() + return nil + }) +} + +func (m *memCache) runloop() { + defer m.wg.Done() + + if m.maxStaleAge == 0 { + return + } + t := time.NewTicker(utils.WithJitter(m.maxStaleAge)) + + for { + select { + case <-t.C: + m.cleanup() + t.Reset(utils.WithJitter(m.maxStaleAge)) + case <-m.chStop: + return + } + } +} + +// remove anything that has been stale for longer than maxStaleAge so that +// cache doesn't grow forever and cause memory leaks +// +// NOTE: This should be concurrent-safe with LatestReport. The only time they +// can race is if the cache item has expired past the stale age between +// creation of the cache item and start of fetch. This is unlikely, and even if +// it does occur, the worst case is that we discard a cache item early and +// double fetch, which isn't bad at all. +func (m *memCache) cleanup() { + m.cache.Range(func(k, vi any) bool { + v := vi.(*cacheVal) + v.RLock() + defer v.RUnlock() + if v.fetching { + // skip cleanup if fetching + return true + } + if time.Now().After(v.expiresAt.Add(m.maxStaleAge)) { + // garbage collection + m.cache.Delete(k) + } + return true + }) +} + +func (m *memCache) Close() error { + return m.StopOnce(m.Name(), func() error { + close(m.chStop) + m.wg.Wait() + return nil + }) +} +func (m *memCache) HealthReport() map[string]error { + return map[string]error{ + m.Name(): m.Ready(), + } +} +func (m *memCache) Name() string { return m.lggr.Name() } diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go new file mode 100644 index 0000000000..f06f1137fb --- /dev/null +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go @@ -0,0 +1,120 @@ +package cache + +import ( + "context" + "fmt" + "sync" + "time" + + "golang.org/x/exp/maps" + + "github.com/smartcontractkit/chainlink-common/pkg/services" + + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +// CacheSet holds a set of mercury caches keyed by server URL +type CacheSet interface { + services.Service + Get(ctx context.Context, client Client) (Fetcher, error) +} + +var _ CacheSet = (*cacheSet)(nil) + +type cacheSet struct { + sync.RWMutex + services.StateMachine + + lggr logger.Logger + caches map[string]Cache + + latestPriceTTL time.Duration + maxStaleAge time.Duration +} + +func NewCacheSet(cfg Config) CacheSet { + return newCacheSet(cfg) +} + +func newCacheSet(cfg Config) *cacheSet { + return &cacheSet{ + sync.RWMutex{}, + services.StateMachine{}, + cfg.Logger.Named("CacheSet"), + make(map[string]Cache), + cfg.LatestReportTTL, + cfg.MaxStaleAge, + } +} + +func (cs *cacheSet) Start(context.Context) error { + return cs.StartOnce("CacheSet", func() error { + return nil + }) +} + +func (cs *cacheSet) Close() error { + return cs.StopOnce("CacheSet", func() error { + cs.Lock() + defer cs.Unlock() + caches := maps.Values(cs.caches) + if err := services.MultiCloser(caches).Close(); err != nil { + return err + } + cs.caches = nil + return nil + }) +} + +func (cs *cacheSet) Get(ctx context.Context, client Client) (f Fetcher, err error) { + ok := cs.IfStarted(func() { + f, err = cs.get(ctx, client) + }) + if !ok { + return nil, fmt.Errorf("cacheSet must be started, but is: %v", cs.State()) + } + return +} + +func (cs *cacheSet) get(ctx context.Context, client Client) (Fetcher, error) { + sURL := client.ServerURL() + // HOT PATH + cs.RLock() + c, exists := cs.caches[sURL] + cs.RUnlock() + if exists { + return c, nil + } + + // COLD PATH + cs.Lock() + defer cs.Unlock() + c, exists = cs.caches[sURL] + if exists { + return c, nil + } + cfg := Config{ + Logger: cs.lggr.With("serverURL", sURL), + LatestReportTTL: cs.latestPriceTTL, + MaxStaleAge: cs.maxStaleAge, + } + c = newMemCache(client, cfg) + if err := c.Start(ctx); err != nil { + return nil, err + } + cs.caches[sURL] = c + return c, nil +} + +func (cs *cacheSet) HealthReport() map[string]error { + report := map[string]error{ + cs.Name(): cs.Ready(), + } + cs.RLock() + defer cs.RUnlock() + for _, c := range cs.caches { + services.CopyHealth(report, c.HealthReport()) + } + return report +} +func (cs *cacheSet) Name() string { return cs.lggr.Name() } diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go new file mode 100644 index 0000000000..9262fb52d3 --- /dev/null +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go @@ -0,0 +1,48 @@ +package cache + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_CacheSet(t *testing.T) { + lggr := logger.TestLogger(t) + cs := newCacheSet(Config{Logger: lggr}) + ctx := testutils.Context(t) + require.NoError(t, cs.Start(ctx)) + t.Cleanup(func() { + assert.NoError(t, cs.Close()) + }) + + t.Run("Get", func(t *testing.T) { + c := &mockClient{} + + var err error + var f Fetcher + t.Run("with virgin cacheset, makes new entry and returns it", func(t *testing.T) { + assert.Len(t, cs.caches, 0) + + f, err = cs.Get(ctx, c) + require.NoError(t, err) + + assert.IsType(t, f, &memCache{}) + assert.Len(t, cs.caches, 1) + }) + t.Run("with existing cache for value, returns that", func(t *testing.T) { + var f2 Fetcher + assert.Len(t, cs.caches, 1) + + f2, err = cs.Get(ctx, c) + require.NoError(t, err) + + assert.IsType(t, f, &memCache{}) + assert.Equal(t, f, f2) + assert.Len(t, cs.caches, 1) + }) + }) +} diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_test.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_test.go new file mode 100644 index 0000000000..71f74b3b3c --- /dev/null +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_test.go @@ -0,0 +1,199 @@ +package cache + +import ( + "context" + "errors" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" +) + +const neverExpireTTL = 1000 * time.Hour // some massive value that will never expire during a test + +func Test_Cache(t *testing.T) { + client := &mockClient{} + cfg := Config{ + Logger: logger.TestLogger(t), + } + ctx := testutils.Context(t) + + req1 := &pb.LatestReportRequest{FeedId: []byte{1}} + req2 := &pb.LatestReportRequest{FeedId: []byte{2}} + req3 := &pb.LatestReportRequest{FeedId: []byte{3}} + + t.Run("errors with nil req", func(t *testing.T) { + c := newMemCache(client, cfg) + + _, err := c.LatestReport(ctx, nil) + assert.EqualError(t, err, "req must not be nil") + }) + + t.Run("with LatestReportTTL=0 does no caching", func(t *testing.T) { + c := newMemCache(client, cfg) + + req := &pb.LatestReportRequest{} + for i := 0; i < 5; i++ { + client.resp = &pb.LatestReportResponse{Report: &pb.Report{Price: []byte(strconv.Itoa(i))}} + + resp, err := c.LatestReport(ctx, req) + require.NoError(t, err) + assert.Equal(t, client.resp, resp) + } + + client.resp = nil + client.err = errors.New("something exploded") + + resp, err := c.LatestReport(ctx, req) + assert.EqualError(t, err, "something exploded") + assert.Nil(t, resp) + }) + + t.Run("caches repeated calls to LatestReport, keyed by request", func(t *testing.T) { + cfg.LatestReportTTL = neverExpireTTL + client.err = nil + c := newMemCache(client, cfg) + + t.Run("if cache is unstarted, returns error", func(t *testing.T) { + // starting the cache is required for state management if we + // actually cache results, since fetches are initiated async and + // need to be cleaned up properly on close + _, err := c.LatestReport(ctx, &pb.LatestReportRequest{}) + assert.EqualError(t, err, "memCache must be started, but is: Unstarted") + }) + + err := c.StartOnce("test start", func() error { return nil }) + require.NoError(t, err) + + t.Run("returns cached value for key", func(t *testing.T) { + var firstResp *pb.LatestReportResponse + for i := 0; i < 5; i++ { + client.resp = &pb.LatestReportResponse{Report: &pb.Report{Price: []byte(strconv.Itoa(i))}} + if firstResp == nil { + firstResp = client.resp + } + + resp, err := c.LatestReport(ctx, req1) + require.NoError(t, err) + assert.Equal(t, firstResp, resp) + } + }) + + t.Run("cache keys do not conflict", func(t *testing.T) { + var firstResp1 *pb.LatestReportResponse + for i := 5; i < 10; i++ { + client.resp = &pb.LatestReportResponse{Report: &pb.Report{Price: []byte(strconv.Itoa(i))}} + if firstResp1 == nil { + firstResp1 = client.resp + } + + resp, err := c.LatestReport(ctx, req2) + require.NoError(t, err) + assert.Equal(t, firstResp1, resp) + } + + var firstResp2 *pb.LatestReportResponse + for i := 10; i < 15; i++ { + client.resp = &pb.LatestReportResponse{Report: &pb.Report{Price: []byte(strconv.Itoa(i))}} + if firstResp2 == nil { + firstResp2 = client.resp + } + + resp, err := c.LatestReport(ctx, req3) + require.NoError(t, err) + assert.Equal(t, firstResp2, resp) + } + + // req1 key still has same value + resp, err := c.LatestReport(ctx, req1) + require.NoError(t, err) + assert.Equal(t, []byte(strconv.Itoa(0)), resp.Report.Price) + + // req2 key still has same value + resp, err = c.LatestReport(ctx, req2) + require.NoError(t, err) + assert.Equal(t, []byte(strconv.Itoa(5)), resp.Report.Price) + }) + + t.Run("re-queries when a cache item has expired", func(t *testing.T) { + vi, exists := c.cache.Load(req1) + assert.True(t, exists) + v := vi.(*cacheVal) + v.expiresAt = time.Now().Add(-1 * time.Second) + + client.resp = &pb.LatestReportResponse{Report: &pb.Report{Price: []byte(strconv.Itoa(15))}} + + resp, err := c.LatestReport(ctx, req1) + require.NoError(t, err) + assert.Equal(t, client.resp, resp) + + // querying again yields the same cached item + resp, err = c.LatestReport(ctx, req1) + require.NoError(t, err) + assert.Equal(t, client.resp, resp) + }) + }) + + t.Run("complete fetch", func(t *testing.T) { + t.Run("does not change expiry if fetch returns error", func(t *testing.T) { + expires := time.Now().Add(-1 * time.Second) + v := &cacheVal{ + fetching: true, + fetchCh: make(chan (struct{})), + val: nil, + err: nil, + expiresAt: expires, + } + v.completeFetch(nil, errors.New("foo"), time.Now().Add(neverExpireTTL)) + assert.Equal(t, expires, v.expiresAt) + + v = &cacheVal{ + fetching: true, + fetchCh: make(chan (struct{})), + val: nil, + err: nil, + expiresAt: expires, + } + expires = time.Now().Add(neverExpireTTL) + v.completeFetch(nil, nil, expires) + assert.Equal(t, expires, v.expiresAt) + }) + }) + + t.Run("timeouts", func(t *testing.T) { + c := newMemCache(client, cfg) + // simulate fetch already executing in background + v := &cacheVal{ + fetching: true, + fetchCh: make(chan (struct{})), + val: nil, + err: nil, + expiresAt: time.Now().Add(-1 * time.Second), + } + c.cache.Store(req1, v) + + canceledCtx, cancel := context.WithCancel(testutils.Context(t)) + cancel() + + t.Run("returns context deadline exceeded error if fetch takes too long", func(t *testing.T) { + _, err := c.LatestReport(canceledCtx, req1) + require.Error(t, err) + assert.True(t, errors.Is(err, context.Canceled)) + assert.EqualError(t, err, "context canceled") + }) + t.Run("returns wrapped context deadline exceeded error if fetch has errored and is in the retry loop", func(t *testing.T) { + v.err = errors.New("some background fetch error") + + _, err := c.LatestReport(canceledCtx, req1) + require.Error(t, err) + assert.True(t, errors.Is(err, context.Canceled)) + assert.EqualError(t, err, "some background fetch error\ncontext canceled") + }) + }) +} diff --git a/core/services/relay/evm/mercury/wsrpc/cache/helpers_test.go b/core/services/relay/evm/mercury/wsrpc/cache/helpers_test.go new file mode 100644 index 0000000000..4cc08bdd52 --- /dev/null +++ b/core/services/relay/evm/mercury/wsrpc/cache/helpers_test.go @@ -0,0 +1,38 @@ +package cache + +import ( + "context" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" +) + +var _ Client = &mockClient{} + +type mockClient struct { + resp *pb.LatestReportResponse + err error +} + +func (m *mockClient) LatestReport(ctx context.Context, req *pb.LatestReportRequest) (resp *pb.LatestReportResponse, err error) { + return m.resp, m.err +} + +func (m *mockClient) ServerURL() string { + return "mock client url" +} + +func (m *mockClient) RawClient() pb.MercuryClient { + return &mockRawClient{m.resp, m.err} +} + +type mockRawClient struct { + resp *pb.LatestReportResponse + err error +} + +func (m *mockRawClient) Transmit(ctx context.Context, in *pb.TransmitRequest) (*pb.TransmitResponse, error) { + return nil, nil +} +func (m *mockRawClient) LatestReport(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { + return m.resp, m.err +} diff --git a/core/services/relay/evm/mercury/wsrpc/client.go b/core/services/relay/evm/mercury/wsrpc/client.go index c04c00074a..5cdf1f44e9 100644 --- a/core/services/relay/evm/mercury/wsrpc/client.go +++ b/core/services/relay/evm/mercury/wsrpc/client.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -63,6 +64,8 @@ var ( type Client interface { services.Service pb.MercuryClient + ServerURL() string + RawClient() pb.MercuryClient } type Conn interface { @@ -78,15 +81,18 @@ type client struct { serverPubKey []byte serverURL string - logger logger.Logger - conn Conn - client pb.MercuryClient + logger logger.Logger + conn Conn + rawClient pb.MercuryClient consecutiveTimeoutCnt atomic.Int32 wg sync.WaitGroup chStop services.StopChan chResetTransport chan struct{} + cacheSet cache.CacheSet + cache cache.Fetcher + timeoutCountMetric prometheus.Counter dialCountMetric prometheus.Counter dialSuccessCountMetric prometheus.Counter @@ -95,17 +101,18 @@ type client struct { } // Consumers of wsrpc package should not usually call NewClient directly, but instead use the Pool -func NewClient(lggr logger.Logger, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string) Client { - return newClient(lggr, clientPrivKey, serverPubKey, serverURL) +func NewClient(lggr logger.Logger, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string, cacheSet cache.CacheSet) Client { + return newClient(lggr, clientPrivKey, serverPubKey, serverURL, cacheSet) } -func newClient(lggr logger.Logger, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string) *client { +func newClient(lggr logger.Logger, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string, cacheSet cache.CacheSet) *client { return &client{ csaKey: clientPrivKey, serverPubKey: serverPubKey, serverURL: serverURL, logger: lggr.Named("WSRPC").With("mercuryServerURL", serverURL), chResetTransport: make(chan struct{}, 1), + cacheSet: cacheSet, chStop: make(services.StopChan), timeoutCountMetric: timeoutCount.WithLabelValues(serverURL), dialCountMetric: dialCount.WithLabelValues(serverURL), @@ -115,9 +122,15 @@ func newClient(lggr logger.Logger, clientPrivKey csakey.KeyV2, serverPubKey []by } } -func (w *client) Start(_ context.Context) error { - return w.StartOnce("WSRPC Client", func() error { - if err := w.dial(context.Background()); err != nil { +func (w *client) Start(ctx context.Context) error { + return w.StartOnce("WSRPC Client", func() (err error) { + // NOTE: This is not a mistake, dial is non-blocking so it should use a + // background context, not the Start context + if err = w.dial(context.Background()); err != nil { + return err + } + w.cache, err = w.cacheSet.Get(ctx, w) + if err != nil { return err } w.wg.Add(1) @@ -148,7 +161,7 @@ func (w *client) dial(ctx context.Context, opts ...wsrpc.DialOption) error { w.dialSuccessCountMetric.Inc() setLivenessMetric(true) w.conn = conn - w.client = pb.NewMercuryClient(conn) + w.rawClient = pb.NewMercuryClient(conn) return nil } @@ -242,7 +255,7 @@ func (w *client) Transmit(ctx context.Context, req *pb.TransmitRequest) (resp *p if err = w.waitForReady(ctx); err != nil { return nil, errors.Wrap(err, "Transmit call failed") } - resp, err = w.client.Transmit(ctx, req) + resp, err = w.rawClient.Transmit(ctx, req) if errors.Is(err, context.DeadlineExceeded) { w.timeoutCountMetric.Inc() cnt := w.consecutiveTimeoutCnt.Add(1) @@ -290,7 +303,11 @@ func (w *client) LatestReport(ctx context.Context, req *pb.LatestReportRequest) if err = w.waitForReady(ctx); err != nil { return nil, errors.Wrap(err, "LatestReport failed") } - resp, err = w.client.LatestReport(ctx, req) + if w.cache == nil { + resp, err = w.rawClient.LatestReport(ctx, req) + } else { + resp, err = w.cache.LatestReport(ctx, req) + } if err != nil { lggr.Errorw("LatestReport failed", "err", err, "resp", resp) } else if resp.Error != "" { @@ -300,3 +317,11 @@ func (w *client) LatestReport(ctx context.Context, req *pb.LatestReportRequest) } return } + +func (w *client) ServerURL() string { + return w.serverURL +} + +func (w *client) RawClient() pb.MercuryClient { + return w.rawClient +} diff --git a/core/services/relay/evm/mercury/wsrpc/client_test.go b/core/services/relay/evm/mercury/wsrpc/client_test.go index 2410cbc52f..d5d1b1b5ee 100644 --- a/core/services/relay/evm/mercury/wsrpc/client_test.go +++ b/core/services/relay/evm/mercury/wsrpc/client_test.go @@ -3,6 +3,7 @@ package wsrpc import ( "context" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -10,15 +11,48 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" mocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) +var _ cache.CacheSet = &mockCacheSet{} + +type mockCacheSet struct{} + +func (m *mockCacheSet) Get(ctx context.Context, client cache.Client) (cache.Fetcher, error) { + return nil, nil +} +func (m *mockCacheSet) Start(context.Context) error { return nil } +func (m *mockCacheSet) Ready() error { return nil } +func (m *mockCacheSet) HealthReport() map[string]error { return nil } +func (m *mockCacheSet) Name() string { return "" } +func (m *mockCacheSet) Close() error { return nil } + +var _ cache.Cache = &mockCache{} + +type mockCache struct{} + +func (m *mockCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest) (resp *pb.LatestReportResponse, err error) { + return nil, nil +} +func (m *mockCache) Start(context.Context) error { return nil } +func (m *mockCache) Ready() error { return nil } +func (m *mockCache) HealthReport() map[string]error { return nil } +func (m *mockCache) Name() string { return "" } +func (m *mockCache) Close() error { return nil } + +func newNoopCacheSet() cache.CacheSet { + return &mockCacheSet{} +} + func Test_Client_Transmit(t *testing.T) { lggr := logger.TestLogger(t) ctx := testutils.Context(t) req := &pb.TransmitRequest{} + noopCacheSet := newNoopCacheSet() + t.Run("sends on reset channel after MaxConsecutiveTransmitFailures timed out transmits", func(t *testing.T) { calls := 0 transmitErr := context.DeadlineExceeded @@ -31,9 +65,9 @@ func Test_Client_Transmit(t *testing.T) { conn := &mocks.MockConn{ Ready: true, } - c := newClient(lggr, csakey.KeyV2{}, nil, "") + c := newClient(lggr, csakey.KeyV2{}, nil, "", noopCacheSet) c.conn = conn - c.client = wsrpcClient + c.rawClient = wsrpcClient require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) for i := 1; i < MaxConsecutiveTransmitFailures; i++ { _, err := c.Transmit(ctx, req) @@ -73,3 +107,109 @@ func Test_Client_Transmit(t *testing.T) { }) }) } + +func Test_Client_LatestReport(t *testing.T) { + lggr := logger.TestLogger(t) + ctx := testutils.Context(t) + + t.Run("with nil cache", func(t *testing.T) { + req := &pb.LatestReportRequest{} + noopCacheSet := newNoopCacheSet() + resp := &pb.LatestReportResponse{} + + wsrpcClient := &mocks.MockWSRPCClient{ + LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { + assert.Equal(t, req, in) + return resp, nil + }, + } + + conn := &mocks.MockConn{ + Ready: true, + } + c := newClient(lggr, csakey.KeyV2{}, nil, "", noopCacheSet) + c.conn = conn + c.rawClient = wsrpcClient + require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) + + r, err := c.LatestReport(ctx, req) + + require.NoError(t, err) + assert.Equal(t, resp, r) + }) + + t.Run("with cache disabled", func(t *testing.T) { + req := &pb.LatestReportRequest{} + cacheSet := cache.NewCacheSet(cache.Config{LatestReportTTL: 0, Logger: lggr}) + resp := &pb.LatestReportResponse{} + + var calls int + wsrpcClient := &mocks.MockWSRPCClient{ + LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { + calls++ + assert.Equal(t, req, in) + return resp, nil + }, + } + + conn := &mocks.MockConn{ + Ready: true, + } + c := newClient(lggr, csakey.KeyV2{}, nil, "", cacheSet) + c.conn = conn + c.rawClient = wsrpcClient + + // simulate start without dialling + require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) + var err error + require.NoError(t, cacheSet.Start(ctx)) + c.cache, err = cacheSet.Get(ctx, c) + require.NoError(t, err) + + for i := 0; i < 5; i++ { + r, err := c.LatestReport(ctx, req) + + require.NoError(t, err) + assert.Equal(t, resp, r) + } + assert.Equal(t, 5, calls, "expected 5 calls to LatestReport but it was called %d times", calls) + }) + + t.Run("with caching", func(t *testing.T) { + req := &pb.LatestReportRequest{} + const neverExpireTTL = 1000 * time.Hour // some massive value that will never expire during a test + cacheSet := cache.NewCacheSet(cache.Config{LatestReportTTL: neverExpireTTL, Logger: lggr}) + resp := &pb.LatestReportResponse{} + + var calls int + wsrpcClient := &mocks.MockWSRPCClient{ + LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { + calls++ + assert.Equal(t, req, in) + return resp, nil + }, + } + + conn := &mocks.MockConn{ + Ready: true, + } + c := newClient(lggr, csakey.KeyV2{}, nil, "", cacheSet) + c.conn = conn + c.rawClient = wsrpcClient + + // simulate start without dialling + require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) + var err error + require.NoError(t, cacheSet.Start(ctx)) + c.cache, err = cacheSet.Get(ctx, c) + require.NoError(t, err) + + for i := 0; i < 5; i++ { + r, err := c.LatestReport(ctx, req) + + require.NoError(t, err) + assert.Equal(t, resp, r) + } + assert.Equal(t, 1, calls, "expected only 1 call to LatestReport but it was called %d times", calls) + }) +} diff --git a/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go b/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go index d764143c5f..c0caf0dee1 100644 --- a/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go +++ b/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go @@ -24,6 +24,9 @@ func (m MockWSRPCClient) Transmit(ctx context.Context, in *pb.TransmitRequest) ( func (m MockWSRPCClient) LatestReport(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { return m.LatestReportF(ctx, in) } +func (m MockWSRPCClient) ServerURL() string { return "mock server url" } + +func (m MockWSRPCClient) RawClient() pb.MercuryClient { return nil } type MockConn struct { State connectivity.State diff --git a/core/services/relay/evm/mercury/wsrpc/pool.go b/core/services/relay/evm/mercury/wsrpc/pool.go index 6630a78437..6c525741dd 100644 --- a/core/services/relay/evm/mercury/wsrpc/pool.go +++ b/core/services/relay/evm/mercury/wsrpc/pool.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -58,7 +59,7 @@ func (conn *connection) checkout(ctx context.Context) (cco *clientCheckout, err // not thread-safe, access must be serialized func (conn *connection) ensureStartedClient(ctx context.Context) error { if len(conn.checkouts) == 0 { - conn.Client = conn.pool.newClient(conn.lggr, conn.clientPrivKey, conn.serverPubKey, conn.serverURL) + conn.Client = conn.pool.newClient(conn.lggr, conn.clientPrivKey, conn.serverPubKey, conn.serverURL, conn.pool.cacheSet) return conn.Client.Start(ctx) } return nil @@ -119,16 +120,19 @@ type pool struct { connections map[string]map[credentials.StaticSizedPublicKey]*connection // embedding newClient makes testing/mocking easier - newClient func(lggr logger.Logger, privKey csakey.KeyV2, serverPubKey []byte, serverURL string) Client + newClient func(lggr logger.Logger, privKey csakey.KeyV2, serverPubKey []byte, serverURL string, cacheSet cache.CacheSet) Client mu sync.RWMutex + cacheSet cache.CacheSet + closed bool } -func NewPool(lggr logger.Logger) Pool { +func NewPool(lggr logger.Logger, cacheCfg cache.Config) Pool { p := newPool(lggr.Named("Mercury.WSRPCPool")) p.newClient = NewClient + p.cacheSet = cache.NewCacheSet(cacheCfg) return p } @@ -188,7 +192,9 @@ func (p *pool) newConnection(lggr logger.Logger, clientPrivKey csakey.KeyV2, ser } } -func (p *pool) Start(_ context.Context) error { return nil } +func (p *pool) Start(ctx context.Context) error { + return p.cacheSet.Start(ctx) +} func (p *pool) Close() (merr error) { p.mu.Lock() @@ -199,6 +205,7 @@ func (p *pool) Close() (merr error) { merr = errors.Join(merr, conn.forceCloseAll()) } } + merr = errors.Join(merr, p.cacheSet.Close()) return } diff --git a/core/services/relay/evm/mercury/wsrpc/pool_test.go b/core/services/relay/evm/mercury/wsrpc/pool_test.go index 980b9f4d74..3d418d39d8 100644 --- a/core/services/relay/evm/mercury/wsrpc/pool_test.go +++ b/core/services/relay/evm/mercury/wsrpc/pool_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -19,8 +20,9 @@ import ( var _ Client = &mockClient{} type mockClient struct { - started bool - closed bool + started bool + closed bool + rawClient pb.MercuryClient } func (c *mockClient) Transmit(ctx context.Context, in *pb.TransmitRequest) (out *pb.TransmitResponse, err error) { @@ -40,6 +42,8 @@ func (c *mockClient) Close() error { func (c *mockClient) Name() string { return "mock client" } func (c *mockClient) Ready() error { return nil } func (c *mockClient) HealthReport() map[string]error { return nil } +func (c *mockClient) ServerURL() string { return "mock client url" } +func (c *mockClient) RawClient() pb.MercuryClient { return c.rawClient } func newMockClient(lggr logger.Logger) *mockClient { return &mockClient{} @@ -52,6 +56,7 @@ func Test_Pool(t *testing.T) { t.Run("Checkout", func(t *testing.T) { p := newPool(lggr) + p.cacheSet = &mockCacheSet{} t.Run("checks out one started client", func(t *testing.T) { clientPrivKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(rand.Int63())) @@ -59,7 +64,7 @@ func Test_Pool(t *testing.T) { serverURL := "example.com:443/ws" client := newMockClient(lggr) - p.newClient = func(lggr logger.Logger, cprivk csakey.KeyV2, spubk []byte, surl string) Client { + p.newClient = func(lggr logger.Logger, cprivk csakey.KeyV2, spubk []byte, surl string, cs cache.CacheSet) Client { assert.Equal(t, clientPrivKey, cprivk) assert.Equal(t, serverPubKey, spubk) assert.Equal(t, serverURL, surl) @@ -105,7 +110,7 @@ func Test_Pool(t *testing.T) { "example.invalid:8000/ws", } - p.newClient = func(lggr logger.Logger, cprivk csakey.KeyV2, spubk []byte, surl string) Client { + p.newClient = func(lggr logger.Logger, cprivk csakey.KeyV2, spubk []byte, surl string, cs cache.CacheSet) Client { return newMockClient(lggr) } @@ -199,6 +204,7 @@ func Test_Pool(t *testing.T) { }) p := newPool(lggr) + p.cacheSet = &mockCacheSet{} t.Run("Name", func(t *testing.T) { assert.Equal(t, "PoolTestLogger", p.Name()) @@ -220,7 +226,7 @@ func Test_Pool(t *testing.T) { } var clients []*mockClient - p.newClient = func(lggr logger.Logger, cprivk csakey.KeyV2, spubk []byte, surl string) Client { + p.newClient = func(lggr logger.Logger, cprivk csakey.KeyV2, spubk []byte, surl string, cs cache.CacheSet) Client { c := newMockClient(lggr) clients = append(clients, c) return c diff --git a/core/utils/hash.go b/core/utils/hash.go index bcae823770..b0a32454e2 100644 --- a/core/utils/hash.go +++ b/core/utils/hash.go @@ -8,12 +8,32 @@ import ( "github.com/pkg/errors" ) +const HashLength = 32 + // Hash is a simplified version of go-ethereum's common.Hash to avoid // go-ethereum dependency // It represents a 32 byte fixed size array that marshals/unmarshals assuming a // 0x prefix type Hash [32]byte +// BytesToHash sets b to hash. +// If b is larger than len(h), b will be cropped from the left. +func BytesToHash(b []byte) Hash { + var h Hash + h.SetBytes(b) + return h +} + +// SetBytes sets the hash to the value of b. +// If b is larger than len(h), b will be cropped from the left. +func (h *Hash) SetBytes(b []byte) { + if len(b) > len(h) { + b = b[len(b)-HashLength:] + } + + copy(h[HashLength-len(b):], b) +} + // Hex converts a hash to a hex string. func (h Hash) Hex() string { return fmt.Sprintf("0x%s", hex.EncodeToString(h[:])) } diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 8f3135b34e..2531e7c281 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -234,3 +234,9 @@ NodeID = '' SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' + +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 7e9872e955..cd0bce3cc7 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -245,6 +245,12 @@ TLSCertPath = '/path/to/cert.pem' env = 'dev' test = 'load' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1m40s' +MaxStaleAge = '1m41s' +LatestReportDeadline = '1m42s' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 6a60dfd419..371cc50a17 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -235,6 +235,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 265222c8be..d9a785ff51 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,11 +13,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added distributed tracing in the OpenTelemetry trace format to the node, currently focused at the LOOPP Plugin development effort. This includes a new set of `Tracing` TOML configurations. The default for collecting traces is off - you must explicitly enable traces and setup a valid OpenTelemetry collector. Refer to `.github/tracing/README.md` for more details. - Added a new, optional WebServer authentication option that supports LDAP as a user identity provider. This enables user login access and user roles to be managed and provisioned via a centralized remote server that supports the LDAP protocol, which can be helpful when running multiple nodes. See the documentation for more information and config setup instructions. There is a new `[WebServer].AuthenticationMethod` config option, when set to `ldap` requires the new `[WebServer.LDAP]` config section to be defined, see the reference `docs/core.toml`. -- New prom metrics for mercury: +- New prom metrics for mercury transmit queue: `mercury_transmit_queue_delete_error_count` `mercury_transmit_queue_insert_error_count` `mercury_transmit_queue_push_error_count` Nops should consider alerting on these. +- Mercury now implements a local cache for fetching prices for fees, which ought to reduce latency and load on the mercury server, as well as increasing performance. It is enabled by default and can be configured with the following new config variables: +``` +[Mercury] + +# Mercury.Cache controls settings for the price retrieval cache querying a mercury server +[Mercury.Cache] +# LatestReportTTL controls how "stale" we will allow a price to be e.g. if +# set to 1s, a new price will always be fetched if the last result was +# from 1 second ago or older. +# +# Another way of looking at it is such: the cache will _never_ return a +# price that was queried from now-LatestReportTTL or before. +# +# Setting to zero disables caching entirely. +LatestReportTTL = "1s" # Default +# MaxStaleAge is that maximum amount of time that a value can be stale +# before it is deleted from the cache (a form of garbage collection). +# +# This should generally be set to something much larger than +# LatestReportTTL. Setting to zero disables garbage collection. +MaxStaleAge = "1h" # Default +# LatestReportDeadline controls how long to wait for a response from the +# mercury server before retrying. Setting this to zero will wait indefinitely. +LatestReportDeadline = "5s" # Default +``` +- New prom metrics for the mercury cache: + `mercury_cache_fetch_failure_count` + `mercury_cache_hit_count` + `mercury_cache_wait_count` + `mercury_cache_miss_count` + ### Changed diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 63c20bdf4a..61d079fa4a 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1652,6 +1652,51 @@ env = 'test' # Example ``` env is an example user specified key-value pair +## Mercury +```toml +[Mercury] +``` + + +## Mercury.Cache +```toml +[Mercury.Cache] +LatestReportTTL = "1s" # Default +MaxStaleAge = "1h" # Default +LatestReportDeadline = "5s" # Default +``` +Mercury.Cache controls settings for the price retrieval cache querying a mercury server + +### LatestReportTTL +```toml +LatestReportTTL = "1s" # Default +``` +LatestReportTTL controls how "stale" we will allow a price to be e.g. if +set to 1s, a new price will always be fetched if the last result was +from 1 second ago or older. + +Another way of looking at it is such: the cache will _never_ return a +price that was queried from now-LatestReportTTL or before. + +Setting to zero disables caching entirely. + +### MaxStaleAge +```toml +MaxStaleAge = "1h" # Default +``` +MaxStaleAge is that maximum amount of time that a value can be stale +before it is deleted from the cache (a form of garbage collection). + +This should generally be set to something much larger than +LatestReportTTL. Setting to zero disables garbage collection. + +### LatestReportDeadline +```toml +LatestReportDeadline = "5s" # Default +``` +LatestReportDeadline controls how long to wait for a response from the +mercury server before retrying. Setting this to zero will wait indefinitely. + ## EVM EVM defaults depend on ChainID: diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 267a760f08..0b841f694b 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -247,6 +247,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + Invalid configuration: invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty - Password.Keystore: empty: must be provided and non-empty diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index e6281e8d22..45b08f0e52 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -291,6 +291,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 65d832aa82..2869af3e2d 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -291,6 +291,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 6b9e3d56ce..fb705819fc 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -291,6 +291,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index aa2036413c..7b82d3323b 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -281,6 +281,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 4ceb9d5df3..91fe0952dd 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -288,6 +288,12 @@ SamplingRatio = 0.0 Mode = 'tls' TLSCertPath = '' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index e4ff2aa35e..a10d6df537 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -296,6 +296,12 @@ SamplingRatio = 0.0 Mode = 'unencrypted' TLSCertPath = 'something' +[Mercury] +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + # Configuration warning: 3 errors: - P2P.V1: is deprecated and will be removed in a future version From 7280c405a8cce1750bd9a64964a214bae2a792d4 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Tue, 28 Nov 2023 14:29:47 -0500 Subject: [PATCH 212/327] Make job names less dynamic for required checks (#11403) --- .github/workflows/solidity-foundry.yml | 2 +- .github/workflows/solidity.yml | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 90d18ecac2..7f6fa4f482 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -34,7 +34,7 @@ jobs: matrix: product: [vrf, automation, llo-feeds, functions, shared] needs: [changes] - name: Foundry Tests ${{ matrix.product }} ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} + name: Foundry Tests ${{ matrix.product }} # See https://github.com/foundry-rs/foundry/issues/3827 runs-on: ubuntu-22.04 diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index 5699657fa5..90429a8c52 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -32,7 +32,6 @@ jobs: - 'contracts/src/v0.6/**/*' - 'contracts/src/v0.7/**/*' - - name: Fail if read-only files have changed if: ${{ steps.changes.outputs.old_sol == 'true' }} run: | @@ -42,8 +41,6 @@ jobs: done exit 1 - - prepublish-test: needs: [changes] if: needs.changes.outputs.changes == 'true' @@ -117,7 +114,7 @@ jobs: run: working-directory: contracts needs: [changes] - name: Lint ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} + name: Solidity Lint runs-on: ubuntu-latest steps: - name: Checkout the repo From 41ab6becb26c96f95d87eeae139db9a04e1c906b Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 28 Nov 2023 14:39:28 -0600 Subject: [PATCH 213/327] core/logger: sanitize escape chars in console logs (#11402) --- .../internal/colortest/prettyconsole_test.go | 6 ++++ core/logger/prettyconsole.go | 29 +++++++++++++++++-- docs/CHANGELOG.md | 1 + 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/logger/internal/colortest/prettyconsole_test.go b/core/logger/internal/colortest/prettyconsole_test.go index fd2ea3f0b1..125f5a2ea5 100644 --- a/core/logger/internal/colortest/prettyconsole_test.go +++ b/core/logger/internal/colortest/prettyconsole_test.go @@ -61,6 +61,12 @@ func TestPrettyConsole_Write(t *testing.T) { "2018-04-12T12:55:28Z \x1b[91m[FATAL] \x1b[0mtop level \x1b[34m\x1b[0m \n", false, }, + { + "control", + `{"ts":1523537728, "level":"fatal", "msg":"\u0008\t\n\r\u000b\u000c\ufffd\ufffd", "hash":"nuances"}`, + "2018-04-12T12:55:28Z \x1b[91m[FATAL] \x1b[0m\\b\t\n\r\\v\\f�� \x1b[34m\x1b[0m \n", + false, + }, {"broken", `{"broken":}`, `{}`, true}, } diff --git a/core/logger/prettyconsole.go b/core/logger/prettyconsole.go index 69427f7471..5150f1f3d6 100644 --- a/core/logger/prettyconsole.go +++ b/core/logger/prettyconsole.go @@ -6,8 +6,10 @@ import ( "net/url" "os" "sort" + "strconv" "strings" "time" + "unicode" "github.com/fatih/color" "github.com/tidwall/gjson" @@ -72,7 +74,7 @@ func generateHeadline(js gjson.Result) string { tsStr, " ", coloredLevel(js.Get("level")), - fmt.Sprintf("%-50s", js.Get("msg")), + fmt.Sprintf("%-50s", sanitized(js.Get("msg").String())), " ", fmt.Sprintf("%-32s", blue(js.Get("caller"))), } @@ -105,7 +107,7 @@ func generateDetails(js gjson.Result) string { var details strings.Builder for _, v := range keys { - details.WriteString(fmt.Sprintf("%s=%v ", green(v), data[v])) + details.WriteString(fmt.Sprintf("%s=%v ", green(sanitized(v)), sanitized(data[v].String()))) } return details.String() @@ -129,3 +131,26 @@ func prettyConsoleSink(s zap.Sink) func(*url.URL) (zap.Sink, error) { return PrettyConsole{s}, nil } } + +type sanitized string + +// String replaces control characters with Go escape sequences, except for newlines and tabs. +// See strconv.QuoteRune. +func (s sanitized) String() string { + var out string + for _, r := range s { + switch r { + case '\n', '\r', '\t': + // allowed + default: + // escape others + if unicode.IsControl(r) { + q := strconv.QuoteRune(r) + out += q[1 : len(q)-1] // trim quotes + continue + } + } + out += string(r) + } + return out +} diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d9a785ff51..64f9472319 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -54,6 +54,7 @@ LatestReportDeadline = "5s" # Default ### Changed - `L2Suggested` mode is now called `SuggestedPrice` +- Console logs will now escape (non-whitespace) control characters ### Removed From 9efb47d17de338146c614d4dc82c8b217af080f3 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 28 Nov 2023 15:35:25 -0600 Subject: [PATCH 214/327] core/config: add EVM.OCR DeltaCOverride and DeltaCJitterOverride (#11250) * core/config: add EVM.OCR OverrideDeltaC and OverrideDeltaCJitter * update changelog --- core/chains/evm/config/chain_scoped_ocr.go | 8 ++ core/chains/evm/config/config.go | 2 + core/chains/evm/config/toml/config.go | 8 ++ .../evm/config/toml/defaults/fallback.toml | 2 + core/config/docs/chains-evm.toml | 8 ++ core/services/chainlink/config_test.go | 4 + .../chainlink/testdata/config-full.toml | 2 + .../config-multi-chain-effective.toml | 6 + core/services/ocr/config_overrider.go | 12 +- core/services/ocr/config_overrider_test.go | 21 +++- core/services/ocr/delegate.go | 2 +- core/web/resolver/testdata/config-full.toml | 2 + .../config-multi-chain-effective.toml | 6 + docs/CHANGELOG.md | 50 ++++---- docs/CONFIG.md | 112 ++++++++++++++++++ .../disk-based-logging-disabled.txtar | 2 + .../validate/disk-based-logging-no-dir.txtar | 2 + .../node/validate/disk-based-logging.txtar | 2 + testdata/scripts/node/validate/invalid.txtar | 2 + testdata/scripts/node/validate/valid.txtar | 2 + 20 files changed, 221 insertions(+), 34 deletions(-) diff --git a/core/chains/evm/config/chain_scoped_ocr.go b/core/chains/evm/config/chain_scoped_ocr.go index 0cdec34e38..f8e171cf63 100644 --- a/core/chains/evm/config/chain_scoped_ocr.go +++ b/core/chains/evm/config/chain_scoped_ocr.go @@ -25,3 +25,11 @@ func (o *ocrConfig) ObservationGracePeriod() time.Duration { func (o *ocrConfig) DatabaseTimeout() time.Duration { return o.c.DatabaseTimeout.Duration() } + +func (o *ocrConfig) DeltaCOverride() time.Duration { + return o.c.DeltaCOverride.Duration() +} + +func (o *ocrConfig) DeltaCJitterOverride() time.Duration { + return o.c.DeltaCJitterOverride.Duration() +} diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index 2dd2d4704c..33e2c85eee 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -50,6 +50,8 @@ type OCR interface { ContractTransmitterTransmitTimeout() time.Duration ObservationGracePeriod() time.Duration DatabaseTimeout() time.Duration + DeltaCOverride() time.Duration + DeltaCJitterOverride() time.Duration } type OCR2 interface { diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index 26587cd3b0..9e51d5be79 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -715,6 +715,8 @@ type OCR struct { ContractConfirmations *uint16 ContractTransmitterTransmitTimeout *models.Duration DatabaseTimeout *models.Duration + DeltaCOverride *models.Duration + DeltaCJitterOverride *models.Duration ObservationGracePeriod *models.Duration } @@ -728,6 +730,12 @@ func (o *OCR) setFrom(f *OCR) { if v := f.DatabaseTimeout; v != nil { o.DatabaseTimeout = v } + if v := f.DeltaCOverride; v != nil { + o.DeltaCOverride = v + } + if v := f.DeltaCJitterOverride; v != nil { + o.DeltaCJitterOverride = v + } if v := f.ObservationGracePeriod; v != nil { o.ObservationGracePeriod = v } diff --git a/core/chains/evm/config/toml/defaults/fallback.toml b/core/chains/evm/config/toml/defaults/fallback.toml index a75cfa0bf3..b19423fd13 100644 --- a/core/chains/evm/config/toml/defaults/fallback.toml +++ b/core/chains/evm/config/toml/defaults/fallback.toml @@ -64,6 +64,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h' +DeltaCJitterOverride = '1h' ObservationGracePeriod = '1s' [OCR2.Automation] diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index 381ab794d6..711889b3fa 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -335,6 +335,14 @@ ContractConfirmations = 4 # Default ContractTransmitterTransmitTimeout = '10s' # Default # DatabaseTimeout sets `OCR.DatabaseTimeout` for this EVM chain. DatabaseTimeout = '10s' # Default +# **ADVANCED** +# DeltaCOverride (and `DeltaCJitterOverride`) determine the config override DeltaC. +# DeltaC is the maximum age of the latest report in the contract. If the maximum age is exceeded, a new report will be +# created by the report generation protocol. +DeltaCOverride = "168h" # Default +# **ADVANCED** +# DeltaCJitterOverride is the range for jitter to add to `DeltaCOverride`. +DeltaCJitterOverride = "1h" # Default # ObservationGracePeriod sets `OCR.ObservationGracePeriod` for this EVM chain. ObservationGracePeriod = '1s' # Default diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index d777e34abf..2966a89690 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -574,6 +574,8 @@ func TestConfig_Marshal(t *testing.T) { ContractConfirmations: ptr[uint16](11), ContractTransmitterTransmitTimeout: &minute, DatabaseTimeout: &second, + DeltaCOverride: models.MustNewDuration(time.Hour), + DeltaCJitterOverride: models.MustNewDuration(time.Second), ObservationGracePeriod: &second, }, OCR2: evmcfg.OCR2{ @@ -1019,6 +1021,8 @@ LeaseDuration = '0s' ContractConfirmations = 11 ContractTransmitterTransmitTimeout = '1m0s' DatabaseTimeout = '1s' +DeltaCOverride = '1h0m0s' +DeltaCJitterOverride = '1s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 8036165d6e..46d9dc2c23 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -340,6 +340,8 @@ LeaseDuration = '0s' ContractConfirmations = 11 ContractTransmitterTransmitTimeout = '1m0s' DatabaseTimeout = '1s' +DeltaCOverride = '1h0m0s' +DeltaCJitterOverride = '1s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 371cc50a17..74d83035cd 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -311,6 +311,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] @@ -396,6 +398,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] @@ -475,6 +479,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/core/services/ocr/config_overrider.go b/core/services/ocr/config_overrider.go index b1acf9a7d7..ac87d0e392 100644 --- a/core/services/ocr/config_overrider.go +++ b/core/services/ocr/config_overrider.go @@ -13,6 +13,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -40,8 +41,14 @@ type ConfigOverriderImpl struct { // InitialHibernationStatus - hibernation state set until the first successful update from the chain const InitialHibernationStatus = false +type DeltaCConfig interface { + DeltaCOverride() time.Duration + DeltaCJitterOverride() time.Duration +} + func NewConfigOverriderImpl( logger logger.Logger, + cfg DeltaCConfig, contractAddress ethkey.EIP55Address, flags *ContractFlags, pollTicker utils.TickerBase, @@ -53,8 +60,9 @@ func NewConfigOverriderImpl( } addressBig := contractAddress.Big() - addressSeconds := addressBig.Mod(addressBig, big.NewInt(3600)).Uint64() - deltaC := 23*time.Hour + time.Duration(addressSeconds)*time.Second + jitterSeconds := int64(cfg.DeltaCJitterOverride() / time.Second) + addressSeconds := addressBig.Mod(addressBig, big.NewInt(jitterSeconds)).Uint64() + deltaC := cfg.DeltaCOverride() + time.Duration(addressSeconds)*time.Second ctx, cancel := context.WithCancel(context.Background()) co := ConfigOverriderImpl{ diff --git a/core/services/ocr/config_overrider_test.go b/core/services/ocr/config_overrider_test.go index bb680189b1..245d634876 100644 --- a/core/services/ocr/config_overrider_test.go +++ b/core/services/ocr/config_overrider_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -27,6 +28,12 @@ type configOverriderUni struct { contractAddress ethkey.EIP55Address } +type deltaCConfig struct{} + +func (d deltaCConfig) DeltaCOverride() time.Duration { return time.Hour * 24 * 7 } + +func (d deltaCConfig) DeltaCJitterOverride() time.Duration { return time.Hour } + func newConfigOverriderUni(t *testing.T, pollITicker utils.TickerBase, flagsContract *mocks.Flags) (uni configOverriderUni) { var testLogger = logger.TestLogger(t) contractAddress := cltest.NewEIP55Address() @@ -35,6 +42,7 @@ func newConfigOverriderUni(t *testing.T, pollITicker utils.TickerBase, flagsCont var err error uni.overrider, err = ocr.NewConfigOverriderImpl( testLogger, + deltaCConfig{}, contractAddress, flags, pollITicker, @@ -141,6 +149,7 @@ func Test_OCRConfigOverrider(t *testing.T) { flags := &ocr.ContractFlags{FlagsInterface: nil} _, err := ocr.NewConfigOverriderImpl( testLogger, + deltaCConfig{}, contractAddress, flags, nil, @@ -160,18 +169,18 @@ func Test_OCRConfigOverrider(t *testing.T) { address2, err := ethkey.NewEIP55Address(common.BigToAddress(big.NewInt(1234567890)).Hex()) require.NoError(t, err) - overrider1a, err := ocr.NewConfigOverriderImpl(testLogger, address1, flags, nil) + overrider1a, err := ocr.NewConfigOverriderImpl(testLogger, deltaCConfig{}, address1, flags, nil) require.NoError(t, err) - overrider1b, err := ocr.NewConfigOverriderImpl(testLogger, address1, flags, nil) + overrider1b, err := ocr.NewConfigOverriderImpl(testLogger, deltaCConfig{}, address1, flags, nil) require.NoError(t, err) - overrider2, err := ocr.NewConfigOverriderImpl(testLogger, address2, flags, nil) + overrider2, err := ocr.NewConfigOverriderImpl(testLogger, deltaCConfig{}, address2, flags, nil) require.NoError(t, err) - require.Equal(t, overrider1a.DeltaCFromAddress, time.Duration(85600000000000)) - require.Equal(t, overrider1b.DeltaCFromAddress, time.Duration(85600000000000)) - require.Equal(t, overrider2.DeltaCFromAddress, time.Duration(84690000000000)) + assert.Equal(t, cltest.MustParseDuration(t, "168h46m40s"), overrider1a.DeltaCFromAddress) + assert.Equal(t, cltest.MustParseDuration(t, "168h46m40s"), overrider1b.DeltaCFromAddress) + assert.Equal(t, cltest.MustParseDuration(t, "168h31m30s"), overrider2.DeltaCFromAddress) }) } diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index aa058d6497..ac78002d45 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -358,7 +358,7 @@ func (d *Delegate) maybeCreateConfigOverrider(logger logger.Logger, chain legacy } ticker := utils.NewPausableTicker(ConfigOverriderPollInterval) - return NewConfigOverriderImpl(logger, contractAddress, flags, &ticker) + return NewConfigOverriderImpl(logger, chain.Config().EVM().OCR(), contractAddress, flags, &ticker) } return nil, nil } diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index cd0bce3cc7..e98f8602a0 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -339,6 +339,8 @@ LeaseDuration = '0s' ContractConfirmations = 11 ContractTransmitterTransmitTimeout = '1m0s' DatabaseTimeout = '1s' +DeltaCOverride = '1h0m0s' +DeltaCJitterOverride = '1s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 371cc50a17..74d83035cd 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -311,6 +311,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] @@ -396,6 +398,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] @@ -475,6 +479,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 64f9472319..727f5ad30d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -19,36 +19,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `mercury_transmit_queue_push_error_count` Nops should consider alerting on these. - Mercury now implements a local cache for fetching prices for fees, which ought to reduce latency and load on the mercury server, as well as increasing performance. It is enabled by default and can be configured with the following new config variables: -``` -[Mercury] - -# Mercury.Cache controls settings for the price retrieval cache querying a mercury server -[Mercury.Cache] -# LatestReportTTL controls how "stale" we will allow a price to be e.g. if -# set to 1s, a new price will always be fetched if the last result was -# from 1 second ago or older. -# -# Another way of looking at it is such: the cache will _never_ return a -# price that was queried from now-LatestReportTTL or before. -# -# Setting to zero disables caching entirely. -LatestReportTTL = "1s" # Default -# MaxStaleAge is that maximum amount of time that a value can be stale -# before it is deleted from the cache (a form of garbage collection). -# -# This should generally be set to something much larger than -# LatestReportTTL. Setting to zero disables garbage collection. -MaxStaleAge = "1h" # Default -# LatestReportDeadline controls how long to wait for a response from the -# mercury server before retrying. Setting this to zero will wait indefinitely. -LatestReportDeadline = "5s" # Default -``` + ``` + [Mercury] + + # Mercury.Cache controls settings for the price retrieval cache querying a mercury server + [Mercury.Cache] + # LatestReportTTL controls how "stale" we will allow a price to be e.g. if + # set to 1s, a new price will always be fetched if the last result was + # from 1 second ago or older. + # + # Another way of looking at it is such: the cache will _never_ return a + # price that was queried from now-LatestReportTTL or before. + # + # Setting to zero disables caching entirely. + LatestReportTTL = "1s" # Default + # MaxStaleAge is that maximum amount of time that a value can be stale + # before it is deleted from the cache (a form of garbage collection). + # + # This should generally be set to something much larger than + # LatestReportTTL. Setting to zero disables garbage collection. + MaxStaleAge = "1h" # Default + # LatestReportDeadline controls how long to wait for a response from the + # mercury server before retrying. Setting this to zero will wait indefinitely. + LatestReportDeadline = "5s" # Default + ``` - New prom metrics for the mercury cache: `mercury_cache_fetch_failure_count` `mercury_cache_hit_count` `mercury_cache_wait_count` `mercury_cache_miss_count` - +- Added new `EVM.OCR` TOML config fields `DeltaCOverride` and `DeltaCJitterOverride` for overriding the config DeltaC. ### Changed diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 61d079fa4a..38aac7085e 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1771,6 +1771,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -1850,6 +1852,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -1929,6 +1933,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2008,6 +2014,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2088,6 +2096,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2167,6 +2177,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2246,6 +2258,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2326,6 +2340,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2405,6 +2421,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '2s' DatabaseTimeout = '2s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '500ms' [OCR2] @@ -2483,6 +2501,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2561,6 +2581,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2640,6 +2662,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '2s' DatabaseTimeout = '2s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '500ms' [OCR2] @@ -2720,6 +2744,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2799,6 +2825,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '2s' DatabaseTimeout = '2s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '500ms' [OCR2] @@ -2878,6 +2906,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -2957,6 +2987,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3036,6 +3068,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3115,6 +3149,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3194,6 +3230,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3274,6 +3312,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3353,6 +3393,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3431,6 +3473,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3510,6 +3554,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3589,6 +3635,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3668,6 +3716,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3746,6 +3796,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3825,6 +3877,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3904,6 +3958,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -3982,6 +4038,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4061,6 +4119,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4141,6 +4201,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4220,6 +4282,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4299,6 +4363,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4378,6 +4444,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4457,6 +4525,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4535,6 +4605,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4613,6 +4685,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4692,6 +4766,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4771,6 +4847,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4851,6 +4929,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -4931,6 +5011,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5010,6 +5092,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5088,6 +5172,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5166,6 +5252,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5245,6 +5333,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5324,6 +5414,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5403,6 +5495,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -6077,6 +6171,8 @@ Set to '0s' to disable ContractConfirmations = 4 # Default ContractTransmitterTransmitTimeout = '10s' # Default DatabaseTimeout = '10s' # Default +DeltaCOverride = "168h" # Default +DeltaCJitterOverride = "1h" # Default ObservationGracePeriod = '1s' # Default ``` @@ -6099,6 +6195,22 @@ DatabaseTimeout = '10s' # Default ``` DatabaseTimeout sets `OCR.DatabaseTimeout` for this EVM chain. +### DeltaCOverride +:warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ +```toml +DeltaCOverride = "168h" # Default +``` +DeltaCOverride (and `DeltaCJitterOverride`) determine the config override DeltaC. +DeltaC is the maximum age of the latest report in the contract. If the maximum age is exceeded, a new report will be +created by the report generation protocol. + +### DeltaCJitterOverride +:warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ +```toml +DeltaCJitterOverride = "1h" # Default +``` +DeltaCJitterOverride is the range for jitter to add to `DeltaCOverride`. + ### ObservationGracePeriod ```toml ObservationGracePeriod = '1s' # Default diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 45b08f0e52..c1ac26c8d0 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -367,6 +367,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 2869af3e2d..5ae75ffca6 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -367,6 +367,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index fb705819fc..c8b3eb4b98 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -367,6 +367,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 7b82d3323b..fd591212d0 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -357,6 +357,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 91fe0952dd..020e66da52 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -364,6 +364,8 @@ LeaseDuration = '0s' ContractConfirmations = 4 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [EVM.OCR2] From 4fbb56e8a586c48422670eb16396c27b1303d57c Mon Sep 17 00:00:00 2001 From: Sneha Agnihotri <180277+snehaagni@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:41:52 -0800 Subject: [PATCH 215/327] release/2.7.1 -> develop (#11370) * Bump version and update CHANGELOG for core v2.7.0 * core: log a warning when deprecated P2P.V1 config is set in TOML (#11073) * core: log a warning when deprecated P2P.V1 config is set in TOML * change default P2P from V1 to V2 * bump operator ui (cherry picked from commit 5808e734cf024a5e8c5450e939e1f2d5b3cba546) * operator-ui deprecation warnings (#11104) Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> Co-authored-by: github-merge-queue[bot] Co-authored-by: Jordan Krage * chore: bump sigstore/cosign-installer from 2.1.0 to 3.1.2 * Finalize date on changelog for 2.7.0 * Bump version and update CHANGELOG for core v2.7.1 Signed-off-by: Sneha Agnihotri * [Hotfix] Update loading next sequence map to avoid startup failure (#11319) * Finalize date on changelog for 2.7.1 * fix failing CI tests for 2.7.1 * bump solana version in tests built --------- Signed-off-by: Sneha Agnihotri Co-authored-by: Jordan Krage Co-authored-by: chainchad <96362174+chainchad@users.noreply.github.com> Co-authored-by: george-dorin <120329946+george-dorin@users.noreply.github.com> Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> Co-authored-by: github-merge-queue[bot] Co-authored-by: Erik Burton Co-authored-by: amit-momin <108959691+amit-momin@users.noreply.github.com> Co-authored-by: anirudhwarrier <12178754+anirudhwarrier@users.noreply.github.com> Co-authored-by: Tate --- VERSION | 2 +- docs/CHANGELOG.md | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 24ba9a38de..860487ca19 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.7.0 +2.7.1 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 727f5ad30d..c5f243626d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -50,7 +50,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `mercury_cache_miss_count` - Added new `EVM.OCR` TOML config fields `DeltaCOverride` and `DeltaCJitterOverride` for overriding the config DeltaC. - ### Changed - `L2Suggested` mode is now called `SuggestedPrice` @@ -71,13 +70,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 -## 2.7.1 - UNRELEASED +## 2.7.1 - 2023-11-21 ### Fixed - Fixed a bug that causes the node to shutdown if all configured RPC's are unreachable during startup. -## 2.7.0 - UNRELEASED +## 2.7.0 - 2023-11-14 ### Added From c8ca97e27222d115b55f6dcd858b36e5cb4bc1a3 Mon Sep 17 00:00:00 2001 From: Dylan Tinianov Date: Tue, 28 Nov 2023 19:32:15 -0500 Subject: [PATCH 216/327] [BCI-2235] Abandoned Transaction Tracking (#11143) * Create Abandoned Tracker * Handle abandoned transactions * Update abandoned_tracker.go * fix tabbing * Query for non-finalized txes * fix tracker * Resend abandoned txes * Add evm_tx_store test * Resend abandoned transactions * add tracker testing * presubmit * tidy * generate * fix test * lint * tidy * fix txmgr tests * generate * Get tx by ID * generate * ensure tx attemps * Confirm abandoned txes * tracker reset * lint * Update tracker.go * Get Tx by ID * Update text * Make tracker its own component * check finality_depth * remove TxAbandoned state * generate * Fix race conditions * Update db functions * Add state machine to tracker * Delete coverage.txt * lint * count receipts in query * add context * update cltest * Add tracker description * filter chainID * update logger * generate * Update CHANGELOG.md * Test unstarted txes * lint * undo imports --------- Co-authored-by: amit-momin <108959691+amit-momin@users.noreply.github.com> --- common/txmgr/resender.go | 27 +- common/txmgr/test_helpers.go | 11 +- common/txmgr/tracker.go | 336 ++++++++++++++++++ common/txmgr/txmgr.go | 19 +- common/txmgr/types/mocks/tx_store.go | 76 ++++ common/txmgr/types/tx_store.go | 3 + core/chains/evm/txmgr/builder.go | 30 +- core/chains/evm/txmgr/evm_tx_store.go | 85 +++++ core/chains/evm/txmgr/evm_tx_store_test.go | 102 +++++- core/chains/evm/txmgr/mocks/evm_tx_store.go | 76 ++++ core/chains/evm/txmgr/models.go | 3 +- core/chains/evm/txmgr/resender_test.go | 6 +- core/chains/evm/txmgr/tracker_test.go | 161 +++++++++ core/internal/cltest/factories.go | 1 + core/scripts/common/vrf/model/model.go | 3 +- core/services/vrf/v2/integration_v2_test.go | 2 +- core/services/vrf/v2/listener_v2_test.go | 2 +- ...10_remove_evm_key_states_fk_constraint.sql | 4 + docs/CHANGELOG.md | 1 + 19 files changed, 920 insertions(+), 28 deletions(-) create mode 100644 common/txmgr/tracker.go create mode 100644 core/chains/evm/txmgr/tracker_test.go create mode 100644 core/store/migrate/migrations/0210_remove_evm_key_states_fk_constraint.sql diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index ce77005560..06c466e173 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -41,11 +41,13 @@ type Resender[ ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, + R txmgrtypes.ChainReceipt[TX_HASH, BLOCK_HASH], SEQ types.Sequence, FEE feetypes.Fee, ] struct { txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] ks txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ] chainID CHAIN_ID interval time.Duration @@ -64,25 +66,28 @@ func NewResender[ ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, + R txmgrtypes.ChainReceipt[TX_HASH, BLOCK_HASH], SEQ types.Sequence, FEE feetypes.Fee, ]( lggr logger.Logger, txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE], client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], + tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], ks txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ], pollInterval time.Duration, config txmgrtypes.ResenderChainConfig, txConfig txmgrtypes.ResenderTransactionsConfig, -) *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { +) *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { if txConfig.ResendAfterThreshold() == 0 { panic("Resender requires a non-zero threshold") } // todo: add context to txStore https://smartcontract-it.atlassian.net/browse/BCI-1585 ctx, cancel := context.WithCancel(context.Background()) - return &Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{ + return &Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ txStore, client, + tracker, ks, client.ConfiguredChainID(), pollInterval, @@ -97,18 +102,18 @@ func NewResender[ } // Start is a comment which satisfies the linter -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Start() { +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start() { er.logger.Debugf("Enabled with poll interval of %s and age threshold of %s", er.interval, er.txConfig.ResendAfterThreshold()) go er.runLoop() } // Stop is a comment which satisfies the linter -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Stop() { +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Stop() { er.cancel() <-er.chDone } -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) runLoop() { +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() { defer close(er.chDone) if err := er.resendUnconfirmed(); err != nil { @@ -129,16 +134,20 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) runLoop() { } } -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) resendUnconfirmed() error { - enabledAddresses, err := er.ks.EnabledAddressesForChain(er.chainID) +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) resendUnconfirmed() error { + resendAddresses, err := er.ks.EnabledAddressesForChain(er.chainID) if err != nil { return fmt.Errorf("Resender failed getting enabled keys for chain %s: %w", er.chainID.String(), err) } + + resendAddresses = append(resendAddresses, er.tracker.GetAbandonedAddresses()...) + ageThreshold := er.txConfig.ResendAfterThreshold() maxInFlightTransactions := er.txConfig.MaxInFlight() olderThan := time.Now().Add(-ageThreshold) var allAttempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - for _, k := range enabledAddresses { + + for _, k := range resendAddresses { var attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] attempts, err = er.txStore.FindTxAttemptsRequiringResend(er.ctx, olderThan, maxInFlightTransactions, er.chainID, k) if err != nil { @@ -189,7 +198,7 @@ func logResendResult(lggr logger.Logger, codes []client.SendTxReturnCode) { lggr.Debugw("Completed", "n", len(codes), "nNew", nNew, "nFatal", nFatal) } -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) logStuckAttempts(attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR) { +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) logStuckAttempts(attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR) { if time.Since(er.lastAlertTimestamps[fromAddress.String()]) >= unconfirmedTxAlertLogFrequency { oldestAttempt, exists := findOldestUnconfirmedAttempt(attempts) if exists { diff --git a/common/txmgr/test_helpers.go b/common/txmgr/test_helpers.go index 95d08c2e95..0f128a23af 100644 --- a/common/txmgr/test_helpers.go +++ b/common/txmgr/test_helpers.go @@ -2,6 +2,7 @@ package txmgr import ( "context" + "time" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" ) @@ -13,6 +14,14 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXX ec.client = client } +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXTestSetTTL(ttl time.Duration) { + tr.ttl = ttl +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXDeliverBlock(blockHeight int64) { + tr.mb.Deliver(blockHeight) +} + func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) XXXTestStartInternal() error { return eb.startInternal() } @@ -33,7 +42,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXX return ec.closeInternal() } -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) XXXTestResendUnconfirmed() error { +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXTestResendUnconfirmed() error { return er.resendUnconfirmed() } diff --git a/common/txmgr/tracker.go b/common/txmgr/tracker.go new file mode 100644 index 0000000000..1a24dd5b5f --- /dev/null +++ b/common/txmgr/tracker.go @@ -0,0 +1,336 @@ +package txmgr + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" + "github.com/smartcontractkit/chainlink/v2/common/types" + + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +const ( + // defaultTTL is the default time to live for abandoned transactions + // After this TTL, the TXM stops tracking abandoned Txs. + defaultTTL = 6 * time.Hour + // handleTxesTimeout represents a sanity limit on how long handleTxesByState + // should take to complete + handleTxesTimeout = 10 * time.Minute +) + +// AbandonedTx is a transaction who's 'FromAddress' was removed from the KeyStore(by the Node Operator). +// Thus, any new attempts for this Tx can't be signed/created. This means no fee bumping can be done. +// However, the Tx may still have live attempts in the chain's mempool, and could get confirmed on the +// chain as-is. Thus, the TXM should not directly discard this Tx. +type AbandonedTx[ADDR types.Hashable] struct { + id int64 + fromAddress ADDR +} + +// Tracker tracks all transactions which have abandoned fromAddresses. +// The fromAddresses can be deleted by Node Operators from the KeyStore. In such cases, +// existing in-flight transactions for these fromAddresses are considered abandoned too. +// Since such Txs can still have attempts on chain's mempool, these could still be confirmed. +// This tracker just tracks such Txs for some time, in case they get confirmed as-is. +type Tracker[ + CHAIN_ID types.ID, + ADDR types.Hashable, + TX_HASH types.Hashable, + BLOCK_HASH types.Hashable, + R txmgrtypes.ChainReceipt[TX_HASH, BLOCK_HASH], + SEQ types.Sequence, + FEE feetypes.Fee, +] struct { + services.StateMachine + txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] + keyStore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ] + chainID CHAIN_ID + lggr logger.Logger + enabledAddrs map[ADDR]bool + txCache map[int64]AbandonedTx[ADDR] + ttl time.Duration + lock sync.Mutex + mb *utils.Mailbox[int64] + wg sync.WaitGroup + isStarted bool + ctx context.Context + ctxCancel context.CancelFunc +} + +func NewTracker[ + CHAIN_ID types.ID, + ADDR types.Hashable, + TX_HASH types.Hashable, + BLOCK_HASH types.Hashable, + R txmgrtypes.ChainReceipt[TX_HASH, BLOCK_HASH], + SEQ types.Sequence, + FEE feetypes.Fee, +]( + txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE], + keyStore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ], + chainID CHAIN_ID, + lggr logger.Logger, +) *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { + return &Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ + txStore: txStore, + keyStore: keyStore, + chainID: chainID, + lggr: logger.Named(lggr, "TxMgrTracker"), + enabledAddrs: map[ADDR]bool{}, + txCache: map[int64]AbandonedTx[ADDR]{}, + ttl: defaultTTL, + mb: utils.NewSingleMailbox[int64](), + lock: sync.Mutex{}, + wg: sync.WaitGroup{}, + } +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(_ context.Context) (err error) { + tr.lock.Lock() + defer tr.lock.Unlock() + return tr.StartOnce("Tracker", func() error { + return tr.startInternal() + }) +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startInternal() (err error) { + tr.ctx, tr.ctxCancel = context.WithCancel(context.Background()) + + if err := tr.setEnabledAddresses(); err != nil { + return fmt.Errorf("failed to set enabled addresses: %w", err) + } + + if err := tr.trackAbandonedTxes(tr.ctx); err != nil { + return fmt.Errorf("failed to track abandoned txes: %w", err) + } + + tr.isStarted = true + if len(tr.txCache) == 0 { + tr.lggr.Infow("no abandoned txes found, skipping runLoop") + return nil + } + tr.wg.Add(1) + go tr.runLoop() + return nil +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() error { + tr.lock.Lock() + defer tr.lock.Unlock() + return tr.StopOnce("Tracker", func() error { + return tr.closeInternal() + }) +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) closeInternal() error { + tr.lggr.Infow("stopping tracker") + if !tr.isStarted { + return fmt.Errorf("tracker not started") + } + tr.ctxCancel() + tr.wg.Wait() + tr.isStarted = false + return nil +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() { + defer tr.wg.Done() + ttlExceeded := time.NewTicker(tr.ttl) + defer ttlExceeded.Stop() + for { + select { + case <-tr.mb.Notify(): + for { + if tr.ctx.Err() != nil { + return + } + blockHeight, exists := tr.mb.Retrieve() + if !exists { + break + } + if err := tr.HandleTxesByState(tr.ctx, blockHeight); err != nil { + tr.lggr.Errorw(fmt.Errorf("failed to handle txes by state: %w", err).Error()) + } + } + case <-ttlExceeded.C: + tr.lggr.Infow("ttl exceeded") + tr.MarkAllTxesFatal(tr.ctx) + return + case <-tr.ctx.Done(): + return + } + } +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetAbandonedAddresses() []ADDR { + tr.lock.Lock() + defer tr.lock.Unlock() + + if !tr.isStarted { + return []ADDR{} + } + + abandonedAddrs := make([]ADDR, len(tr.txCache)) + for _, atx := range tr.txCache { + abandonedAddrs = append(abandonedAddrs, atx.fromAddress) + } + return abandonedAddrs +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsStarted() bool { + tr.lock.Lock() + defer tr.lock.Unlock() + return tr.isStarted +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) setEnabledAddresses() error { + enabledAddrs, err := tr.keyStore.EnabledAddressesForChain(tr.chainID) + if err != nil { + return fmt.Errorf("failed to get enabled addresses for chain: %w", err) + } + + if len(enabledAddrs) == 0 { + tr.lggr.Warnf("enabled address list is empty") + } + + for _, addr := range enabledAddrs { + tr.enabledAddrs[addr] = true + } + return nil +} + +// trackAbandonedTxes called once to find and insert all abandoned txes into the tracker. +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) trackAbandonedTxes(ctx context.Context) (err error) { + if tr.isStarted { + return fmt.Errorf("tracker already started") + } + + nonFatalTxes, err := tr.txStore.GetNonFatalTransactions(ctx, tr.chainID) + if err != nil { + return fmt.Errorf("failed to get non fatal txes from txStore: %w", err) + } + + // insert abandoned txes + for _, tx := range nonFatalTxes { + if !tr.enabledAddrs[tx.FromAddress] { + tr.insertTx(tx) + } + } + + if err := tr.handleTxesByState(ctx, 0); err != nil { + return fmt.Errorf("failed to handle txes by state: %w", err) + } + + return nil +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HandleTxesByState(ctx context.Context, blockHeight int64) error { + tr.lock.Lock() + defer tr.lock.Unlock() + tr.ctx, tr.ctxCancel = context.WithTimeout(ctx, handleTxesTimeout) + defer tr.ctxCancel() + return tr.handleTxesByState(ctx, blockHeight) +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleTxesByState(ctx context.Context, blockHeight int64) error { + for id, atx := range tr.txCache { + tx, err := tr.txStore.GetTxByID(ctx, atx.id) + if err != nil { + return fmt.Errorf("failed to get tx by ID: %w", err) + } + + switch tx.State { + case TxConfirmed: + if err := tr.handleConfirmedTx(tx, blockHeight); err != nil { + return fmt.Errorf("failed to handle confirmed txes: %w", err) + } + case TxConfirmedMissingReceipt, TxUnconfirmed: + // Keep tracking tx + case TxInProgress, TxUnstarted: + // Tx could never be sent on chain even once. That means that we need to sign + // an attempt to even broadcast this Tx to the chain. Since the fromAddress + // is deleted, we can't sign it. + errMsg := "The FromAddress for this Tx was deleted before this Tx could be broadcast to the chain." + if err := tr.markTxFatal(ctx, tx, errMsg); err != nil { + return fmt.Errorf("failed to mark tx as fatal: %w", err) + } + delete(tr.txCache, id) + case TxFatalError: + delete(tr.txCache, id) + default: + tr.lggr.Errorw(fmt.Sprintf("unhandled transaction state: %v", tx.State)) + } + } + + return nil +} + +// handleConfirmedTx removes a transaction from the tracker if it's been finalized on chain +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleConfirmedTx( + tx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], + blockHeight int64, +) error { + finalized, err := tr.txStore.IsTxFinalized(tr.ctx, blockHeight, tx.ID, tr.chainID) + if err != nil { + return fmt.Errorf("failed to check if tx is finalized: %w", err) + } + + if finalized { + delete(tr.txCache, tx.ID) + } + + return nil +} + +// insertTx inserts a transaction into the tracker as an AbandonedTx +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) insertTx( + tx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) { + if _, contains := tr.txCache[tx.ID]; contains { + return + } + + tr.txCache[tx.ID] = AbandonedTx[ADDR]{ + id: tx.ID, + fromAddress: tx.FromAddress, + } + tr.lggr.Debugw(fmt.Sprintf("inserted tx %v", tx.ID)) +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) markTxFatal(ctx context.Context, + tx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], + errMsg string) error { + tx.Error.SetValid(errMsg) + + // Set state to TxInProgress so the tracker can attempt to mark it as fatal + tx.State = TxInProgress + if err := tr.txStore.UpdateTxFatalError(ctx, tx); err != nil { + return fmt.Errorf("failed to mark tx %v as abandoned: %w", tx.ID, err) + } + return nil +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllTxesFatal(ctx context.Context) { + tr.lock.Lock() + defer tr.lock.Unlock() + errMsg := fmt.Sprintf( + "fromAddress for this Tx was deleted, and existing attempts onchain didn't finalize within %d hours, thus this Tx was abandoned.", + int(tr.ttl.Hours())) + + for _, atx := range tr.txCache { + tx, err := tr.txStore.GetTxByID(ctx, atx.id) + if err != nil { + tr.lggr.Errorw(fmt.Errorf("failed to get tx by ID: %w", err).Error()) + continue + } + + if err := tr.markTxFatal(ctx, tx, errMsg); err != nil { + tr.lggr.Errorw(fmt.Errorf("failed to mark tx as abandoned: %w", err).Error()) + } + } +} diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 63bf039d8f..3aac88e2f4 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -95,9 +95,10 @@ type Txm[ wg sync.WaitGroup reaper *Reaper[CHAIN_ID] - resender *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + resender *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] broadcaster *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] confirmer *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] + tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] fwdMgr txmgrtypes.ForwarderManager[ADDR] txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ] @@ -132,7 +133,8 @@ func NewTxm[ sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], broadcaster *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], confirmer *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], - resender *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], + resender *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], + tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], ) *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { b := Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ logger: lggr, @@ -153,6 +155,7 @@ func NewTxm[ broadcaster: broadcaster, confirmer: confirmer, resender: resender, + tracker: tracker, } if txCfg.ResendAfterThreshold() <= 0 { @@ -183,6 +186,10 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx return fmt.Errorf("Txm: Estimator failed to start: %w", err) } + if err := ms.Start(ctx, b.tracker); err != nil { + return fmt.Errorf("Txm: Tracker failed to start: %w", err) + } + b.wg.Add(1) go b.runLoop() <-b.chSubbed @@ -260,6 +267,10 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() (m merr = errors.Join(merr, fmt.Errorf("Txm: failed to close TxAttemptBuilder: %w", err)) } + if err := b.tracker.Close(); err != nil { + merr = errors.Join(merr, fmt.Errorf("Txm: failed to close Tracker: %w", err)) + } + return nil }) } @@ -371,6 +382,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() b.broadcaster.Trigger(address) case head := <-b.chHeads: b.confirmer.mb.Deliver(head) + b.tracker.mb.Deliver(head.BlockNumber()) case reset := <-b.reset: // This check prevents the weird edge-case where you can select // into this block after chStop has already been closed and the @@ -396,6 +408,9 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() if err := utils.EnsureClosed(b.confirmer); err != nil { b.logger.Panicw(fmt.Sprintf("Failed to Close Confirmer: %v", err), "err", err) } + if err := utils.EnsureClosed(b.tracker); err != nil { + b.logger.Panicw(fmt.Sprintf("Failed to Close Tracker: %v", err), "err", err) + } return case <-keysChanged: // This check prevents the weird edge-case where you can select diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index 0e344b9b6f..0a7738fd68 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -544,6 +544,58 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgre return r0, r1 } +// GetNonFatalTransactions provides a mock function with given fields: ctx, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetNonFatalTransactions(ctx context.Context, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, chainID) + + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetTxByID provides a mock function with given fields: ctx, id +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxByID(ctx context.Context, id int64) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, id) + + var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetTxInProgress provides a mock function with given fields: ctx, fromAddress func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProgress(ctx context.Context, fromAddress ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, fromAddress) @@ -594,6 +646,30 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgre return r0, r1 } +// IsTxFinalized provides a mock function with given fields: ctx, blockHeight, txID, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID CHAIN_ID) (bool, error) { + ret := _m.Called(ctx, blockHeight, txID, chainID) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) (bool, error)); ok { + return rf(ctx, blockHeight, txID, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) bool); ok { + r0 = rf(ctx, blockHeight, txID, chainID) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, int64, CHAIN_ID) error); ok { + r1 = rf(ctx, blockHeight, txID, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // LoadTxAttempts provides a mock function with given fields: ctx, etx func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttempts(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx) diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index f731031f92..251135795f 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -81,6 +81,8 @@ type TransactionStore[ FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber, lowBlockNumber int64, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetTxInProgress(ctx context.Context, fromAddress ADDR) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetInProgressTxAttempts(ctx context.Context, address ADDR, chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + GetNonFatalTransactions(ctx context.Context, chainID CHAIN_ID) (txs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + GetTxByID(ctx context.Context, id int64) (tx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) HasInProgressTransaction(ctx context.Context, account ADDR, chainID CHAIN_ID) (exists bool, err error) LoadTxAttempts(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error MarkAllConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) (err error) @@ -100,6 +102,7 @@ type TransactionStore[ UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error UpdateTxFatalError(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error UpdateTxForRebroadcast(ctx context.Context, etx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID CHAIN_ID) (finalized bool, err error) } type TxHistoryReaper[CHAIN_ID types.ID] interface { diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 84aa21e4de..f0cbcbf8d9 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -50,13 +50,15 @@ func NewTxm( txmCfg := NewEvmTxmConfig(chainConfig) // wrap Evm specific config feeCfg := NewEvmTxmFeeConfig(fCfg) // wrap Evm specific config txmClient := NewEvmTxmClient(client) // wrap Evm specific client - ethBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, txNonceSyncer, lggr, checker, chainConfig.NonceAutoSync()) - ethConfirmer := NewEvmConfirmer(txStore, txmClient, txmCfg, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr) - var ethResender *Resender + chainID := txmClient.ConfiguredChainID() + evmBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, txNonceSyncer, lggr, checker, chainConfig.NonceAutoSync()) + evmTracker := NewEvmTracker(txStore, keyStore, chainID, lggr) + evmConfirmer := NewEvmConfirmer(txStore, txmClient, txmCfg, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr) + var evmResender *Resender if txConfig.ResendAfterThreshold() > 0 { - ethResender = NewEvmResender(lggr, txStore, txmClient, keyStore, txmgr.DefaultResenderPollInterval, chainConfig, txConfig) + evmResender = NewEvmResender(lggr, txStore, txmClient, evmTracker, keyStore, txmgr.DefaultResenderPollInterval, chainConfig, txConfig) } - txm = NewEvmTxm(txmClient.ConfiguredChainID(), txmCfg, txConfig, keyStore, lggr, checker, fwdMgr, txAttemptBuilder, txStore, txNonceSyncer, ethBroadcaster, ethConfirmer, ethResender) + txm = NewEvmTxm(chainID, txmCfg, txConfig, keyStore, lggr, checker, fwdMgr, txAttemptBuilder, txStore, txNonceSyncer, evmBroadcaster, evmConfirmer, evmResender, evmTracker) return txm, nil } @@ -75,21 +77,23 @@ func NewEvmTxm( broadcaster *Broadcaster, confirmer *Confirmer, resender *Resender, + tracker *Tracker, ) *Txm { - return txmgr.NewTxm(chainId, cfg, txCfg, keyStore, lggr, checkerFactory, fwdMgr, txAttemptBuilder, txStore, nonceSyncer, broadcaster, confirmer, resender) + return txmgr.NewTxm(chainId, cfg, txCfg, keyStore, lggr, checkerFactory, fwdMgr, txAttemptBuilder, txStore, nonceSyncer, broadcaster, confirmer, resender, tracker) } -// NewEvnResender creates a new concrete EvmResender +// NewEvmResender creates a new concrete EvmResender func NewEvmResender( lggr logger.Logger, txStore TransactionStore, client TransactionClient, + tracker *Tracker, ks KeyStore, pollInterval time.Duration, config EvmResenderConfig, txConfig txmgrtypes.ResenderTransactionsConfig, ) *Resender { - return txmgr.NewResender(lggr, txStore, client, ks, pollInterval, config, txConfig) + return txmgr.NewResender(lggr, txStore, client, tracker, ks, pollInterval, config, txConfig) } // NewEvmReaper instantiates a new EVM-specific reaper object @@ -112,6 +116,16 @@ func NewEvmConfirmer( return txmgr.NewConfirmer(txStore, client, chainConfig, feeConfig, txConfig, dbConfig, keystore, txAttemptBuilder, lggr, func(r *evmtypes.Receipt) bool { return r == nil }) } +// NewEvmTracker instantiates a new EVM tracker for abandoned transactions +func NewEvmTracker( + txStore TxStore, + keyStore KeyStore, + chainID *big.Int, + lggr logger.Logger, +) *Tracker { + return txmgr.NewTracker(txStore, keyStore, chainID, lggr) +} + // NewEvmBroadcaster returns a new concrete EvmBroadcaster func NewEvmBroadcaster( txStore TransactionStore, diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 2788c2fd1c..51c9f98e88 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -69,6 +69,7 @@ type TestEvmTxStore interface { FindTxAttemptsByTxIDs(ids []int64) ([]TxAttempt, error) InsertTxAttempt(attempt *TxAttempt) error LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error + GetFatalTransactions(ctx context.Context) (txes []*Tx, err error) } type evmTxStore struct { @@ -552,6 +553,26 @@ func (o *evmTxStore) InsertReceipt(receipt *evmtypes.Receipt) (int64, error) { return r.ID, pkgerrors.Wrap(err, "InsertReceipt failed") } +func (o *evmTxStore) GetFatalTransactions(ctx context.Context) (txes []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Transaction(func(tx pg.Queryer) error { + stmt := `SELECT * FROM evm.txes WHERE state = 'fatal_error'` + var dbEtxs []DbEthTx + if err = tx.Select(&dbEtxs, stmt); err != nil { + return fmt.Errorf("failed to load evm.txes: %w", err) + } + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + return fmt.Errorf("failed to load evm.tx_attempts: %w", err) + }, pg.OptReadOnlyTx()) + + return txes, nil +} + // FindTxWithAttempts finds the Tx with its attempts and receipts preloaded func (o *evmTxStore) FindTxWithAttempts(etxID int64) (etx Tx, err error) { err = o.q.Transaction(func(tx pg.Queryer) error { @@ -1107,6 +1128,25 @@ ORDER BY nonce ASC return etxs, pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed") } +func (o *evmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int) (finalized bool, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + + var count int32 + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.GetContext(ctx, &count, ` + SELECT COUNT(evm.receipts.receipt) FROM evm.txes + INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id + INNER JOIN evm.receipts ON evm.tx_attempts.hash = evm.receipts.tx_hash + WHERE evm.receipts.block_number <= ($1 - evm.txes.min_confirmations) + AND evm.txes.id = $2 AND evm.txes.evm_chain_id = $3`, blockHeight, txID, chainID.String()) + if err != nil { + return false, fmt.Errorf("failed to retrieve transaction reciepts: %w", err) + } + return count > 0, nil +} + func saveAttemptWithNewState(ctx context.Context, q pg.Queryer, logger logger.Logger, attempt TxAttempt, broadcastAt time.Time) error { var dbAttempt DbEthTxAttempt dbAttempt.FromTxAttempt(&attempt) @@ -1223,6 +1263,51 @@ func (o *evmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *TxAttem return nil } +func (o *evmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big.Int) (txes []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Transaction(func(tx pg.Queryer) error { + stmt := `SELECT * FROM evm.txes WHERE state <> 'fatal_error' AND evm_chain_id = $1` + var dbEtxs []DbEthTx + if err = tx.Select(&dbEtxs, stmt, chainID.String()); err != nil { + return fmt.Errorf("failed to load evm.txes: %w", err) + } + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + return fmt.Errorf("failed to load evm.txes: %w", err) + }, pg.OptReadOnlyTx()) + + return txes, nil +} + +func (o *evmTxStore) GetTxByID(ctx context.Context, id int64) (txe *Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + + err = qq.Transaction(func(tx pg.Queryer) error { + stmt := `SELECT * FROM evm.txes WHERE id = $1` + var dbEtxs []DbEthTx + if err = tx.Select(&dbEtxs, stmt, id); err != nil { + return fmt.Errorf("failed to load evm.txes: %w", err) + } + txes := make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + if len(txes) != 1 { + return fmt.Errorf("failed to get tx with id %v", id) + } + txe = txes[0] + err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + return fmt.Errorf("failed to load evm.tx_attempts: %w", err) + }, pg.OptReadOnlyTx()) + + return txe, nil +} + // FindTxsRequiringGasBump returns transactions that have all // attempts which are unconfirmed for at least gasBumpThreshold blocks, // limited by limit pending transactions diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index d2cafcb8ef..e68641735e 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -786,6 +786,31 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { }) } +func TestORM_IsTxFinalized(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := newTestChainScopedConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + + t.Run("confirmed tx not past finality_depth", func(t *testing.T) { + confirmedAddr := cltest.MustGenerateRandomKey(t).Address + tx := mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1) + finalized, err := txStore.IsTxFinalized(testutils.Context(t), 2, tx.ID, ethClient.ConfiguredChainID()) + require.NoError(t, err) + require.False(t, finalized) + }) + + t.Run("confirmed tx past finality_depth", func(t *testing.T) { + confirmedAddr := cltest.MustGenerateRandomKey(t).Address + tx := mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1) + finalized, err := txStore.IsTxFinalized(testutils.Context(t), 10, tx.ID, ethClient.ConfiguredChainID()) + require.NoError(t, err) + require.True(t, finalized) + }) +} + func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { t.Parallel() @@ -1310,7 +1335,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { evmTxmCfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ec := evmtest.NewEthClientMockWithDefaultChain(t) txMgr := txmgr.NewEvmTxm(ec.ConfiguredChainID(), evmTxmCfg, ccfg.EVM().Transactions(), nil, logger.Test(t), nil, nil, - nil, txStore, nil, nil, nil, nil) + nil, txStore, nil, nil, nil, nil, nil) err := txMgr.XXXTestAbandon(fromAddress) // mark transaction as abandoned require.NoError(t, err) @@ -1365,6 +1390,81 @@ func TestORM_GetTxInProgress(t *testing.T) { }) } +func TestORM_GetNonFatalTransactions(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := newTestChainScopedConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + + t.Run("gets 0 non finalized eth transaction", func(t *testing.T) { + txes, err := txStore.GetNonFatalTransactions(testutils.Context(t), ethClient.ConfiguredChainID()) + require.NoError(t, err) + require.Empty(t, txes) + }) + + t.Run("get in progress, unstarted, and unconfirmed eth transactions", func(t *testing.T) { + inProgressTx := mustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) + unstartedTx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, ethClient.ConfiguredChainID()) + + txes, err := txStore.GetNonFatalTransactions(testutils.Context(t), ethClient.ConfiguredChainID()) + require.NoError(t, err) + + for _, tx := range txes { + require.True(t, tx.ID == inProgressTx.ID || tx.ID == unstartedTx.ID) + } + }) +} + +func TestORM_GetTxByID(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := newTestChainScopedConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + + t.Run("no transaction", func(t *testing.T) { + tx, err := txStore.GetTxByID(testutils.Context(t), int64(0)) + require.NoError(t, err) + require.Nil(t, tx) + }) + + t.Run("get transaction by ID", func(t *testing.T) { + insertedTx := mustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) + tx, err := txStore.GetTxByID(testutils.Context(t), insertedTx.ID) + require.NoError(t, err) + require.NotNil(t, tx) + }) +} + +func TestORM_GetFatalTransactions(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := newTestChainScopedConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + + t.Run("gets 0 fatal eth transactions", func(t *testing.T) { + txes, err := txStore.GetFatalTransactions(testutils.Context(t)) + require.NoError(t, err) + require.Empty(t, txes) + }) + + t.Run("get fatal transactions", func(t *testing.T) { + fatalTx := mustInsertFatalErrorEthTx(t, txStore, fromAddress) + txes, err := txStore.GetFatalTransactions(testutils.Context(t)) + require.NoError(t, err) + require.Equal(t, txes[0].ID, fatalTx.ID) + }) +} + func TestORM_HasInProgressTransaction(t *testing.T) { t.Parallel() diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index f491bda40b..00efc1add9 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -649,6 +649,58 @@ func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address commo return r0, r1 } +// GetNonFatalTransactions provides a mock function with given fields: ctx, chainID +func (_m *EvmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, chainID) + + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetTxByID provides a mock function with given fields: ctx, id +func (_m *EvmTxStore) GetTxByID(ctx context.Context, id int64) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, id) + + var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetTxInProgress provides a mock function with given fields: ctx, fromAddress func (_m *EvmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Address) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, fromAddress) @@ -699,6 +751,30 @@ func (_m *EvmTxStore) HasInProgressTransaction(ctx context.Context, account comm return r0, r1 } +// IsTxFinalized provides a mock function with given fields: ctx, blockHeight, txID, chainID +func (_m *EvmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int) (bool, error) { + ret := _m.Called(ctx, blockHeight, txID, chainID) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) (bool, error)); ok { + return rf(ctx, blockHeight, txID, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) bool); ok { + r0 = rf(ctx, blockHeight, txID, chainID) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, int64, *big.Int) error); ok { + r1 = rf(ctx, blockHeight, txID, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // LoadTxAttempts provides a mock function with given fields: ctx, etx func (_m *EvmTxStore) LoadTxAttempts(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx) diff --git a/core/chains/evm/txmgr/models.go b/core/chains/evm/txmgr/models.go index 9044c52c9a..4c622ec945 100644 --- a/core/chains/evm/txmgr/models.go +++ b/core/chains/evm/txmgr/models.go @@ -19,7 +19,8 @@ import ( type ( Confirmer = txmgr.Confirmer[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] Broadcaster = txmgr.Broadcaster[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] - Resender = txmgr.Resender[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + Resender = txmgr.Resender[*big.Int, common.Address, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] + Tracker = txmgr.Tracker[*big.Int, common.Address, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] Reaper = txmgr.Reaper[*big.Int] TxStore = txmgrtypes.TxStore[common.Address, *big.Int, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] TransactionStore = txmgrtypes.TransactionStore[common.Address, *big.Int, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index d2eefdece5..0e86c0d4f8 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -65,7 +65,7 @@ func Test_EthResender_resendUnconfirmed(t *testing.T) { addr3TxesRawHex = append(addr3TxesRawHex, hexutil.Encode(etx.TxAttempts[0].SignedRawTx)) } - er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) + er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTracker(txStore, ethKeyStore, big.NewInt(0), lggr), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) var resentHex = make(map[string]struct{}) ethClient.On("BatchCallContextAll", mock.Anything, mock.MatchedBy(func(elems []rpc.BatchElem) bool { @@ -121,7 +121,7 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, logCfg) originalBroadcastAt := time.Unix(1616509100, 0) - er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) + er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTracker(txStore, ethKeyStore, big.NewInt(0), lggr), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) t.Run("alerts only once for unconfirmed transaction attempt within the unconfirmedTxAlertDelay duration", func(t *testing.T) { _ = cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, int64(1), fromAddress, originalBroadcastAt) @@ -157,7 +157,7 @@ func Test_EthResender_Start(t *testing.T) { t.Run("resends transactions that have been languishing unconfirmed for too long", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) + er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTracker(txStore, ethKeyStore, big.NewInt(0), lggr), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) originalBroadcastAt := time.Unix(1616509100, 0) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress, originalBroadcastAt) diff --git a/core/chains/evm/txmgr/tracker_test.go b/core/chains/evm/txmgr/tracker_test.go new file mode 100644 index 0000000000..a31187f04e --- /dev/null +++ b/core/chains/evm/txmgr/tracker_test.go @@ -0,0 +1,161 @@ +package txmgr_test + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +const waitTime = 5 * time.Millisecond + +func newTestEvmTrackerSetup(t *testing.T) (*txmgr.Tracker, txmgr.TestEvmTxStore, keystore.Eth, []common.Address) { + db := pgtest.NewSqlxDB(t) + cfg := newTestChainScopedConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + chainID := big.NewInt(0) + enabledAddresses := generateEnabledAddresses(t, ethKeyStore, chainID) + lggr := logger.TestLogger(t) + return txmgr.NewEvmTracker(txStore, ethKeyStore, chainID, lggr), txStore, ethKeyStore, enabledAddresses +} + +func generateEnabledAddresses(t *testing.T, keyStore keystore.Eth, chainID *big.Int) []common.Address { + var enabledAddresses []common.Address + _, addr1 := cltest.MustInsertRandomKey(t, keyStore, *utils.NewBigI(chainID.Int64())) + _, addr2 := cltest.MustInsertRandomKey(t, keyStore, *utils.NewBigI(chainID.Int64())) + enabledAddresses = append(enabledAddresses, addr1, addr2) + return enabledAddresses +} + +func containsID(txes []*txmgr.Tx, id int64) bool { + for _, tx := range txes { + if tx.ID == id { + return true + } + } + return false +} + +func TestEvmTracker_Initialization(t *testing.T) { + t.Parallel() + + tracker, _, _, _ := newTestEvmTrackerSetup(t) + + err := tracker.Start(context.Background()) + require.NoError(t, err) + require.True(t, tracker.IsStarted()) + + t.Run("stop tracker", func(t *testing.T) { + err := tracker.Close() + require.NoError(t, err) + require.False(t, tracker.IsStarted()) + }) +} + +func TestEvmTracker_AddressTracking(t *testing.T) { + t.Parallel() + + t.Run("track abandoned addresses", func(t *testing.T) { + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + tracker, txStore, _, _ := newTestEvmTrackerSetup(t) + inProgressAddr := cltest.MustGenerateRandomKey(t).Address + unstartedAddr := cltest.MustGenerateRandomKey(t).Address + unconfirmedAddr := cltest.MustGenerateRandomKey(t).Address + confirmedAddr := cltest.MustGenerateRandomKey(t).Address + _ = mustInsertInProgressEthTxWithAttempt(t, txStore, 123, inProgressAddr) + _ = cltest.MustInsertUnconfirmedEthTx(t, txStore, 123, unconfirmedAddr) + _ = mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1) + _ = mustCreateUnstartedTx(t, txStore, unstartedAddr, cltest.MustGenerateRandomKey(t).Address, []byte{}, 0, big.Int{}, ethClient.ConfiguredChainID()) + + err := tracker.Start(context.Background()) + require.NoError(t, err) + defer func(tracker *txmgr.Tracker) { + err = tracker.Close() + require.NoError(t, err) + }(tracker) + + addrs := tracker.GetAbandonedAddresses() + require.NotContains(t, addrs, inProgressAddr) + require.NotContains(t, addrs, unstartedAddr) + require.Contains(t, addrs, confirmedAddr) + require.Contains(t, addrs, unconfirmedAddr) + }) + + t.Run("stop tracking finalized tx", func(t *testing.T) { + tracker, txStore, _, _ := newTestEvmTrackerSetup(t) + confirmedAddr := cltest.MustGenerateRandomKey(t).Address + _ = mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1) + + err := tracker.Start(context.Background()) + require.NoError(t, err) + defer func(tracker *txmgr.Tracker) { + err = tracker.Close() + require.NoError(t, err) + }(tracker) + + addrs := tracker.GetAbandonedAddresses() + require.Contains(t, addrs, confirmedAddr) + + // deliver block past minConfirmations to finalize tx + tracker.XXXDeliverBlock(10) + time.Sleep(waitTime) + + addrs = tracker.GetAbandonedAddresses() + require.NotContains(t, addrs, confirmedAddr) + }) +} + +func TestEvmTracker_ExceedingTTL(t *testing.T) { + t.Parallel() + + t.Run("confirmed but unfinalized transaction still tracked", func(t *testing.T) { + tracker, txStore, _, _ := newTestEvmTrackerSetup(t) + addr1 := cltest.MustGenerateRandomKey(t).Address + _ = mustInsertConfirmedEthTxWithReceipt(t, txStore, addr1, 123, 1) + + err := tracker.Start(context.Background()) + require.NoError(t, err) + defer func(tracker *txmgr.Tracker) { + err = tracker.Close() + require.NoError(t, err) + }(tracker) + + require.Contains(t, tracker.GetAbandonedAddresses(), addr1) + }) + + t.Run("exceeding ttl", func(t *testing.T) { + tracker, txStore, _, _ := newTestEvmTrackerSetup(t) + addr1 := cltest.MustGenerateRandomKey(t).Address + addr2 := cltest.MustGenerateRandomKey(t).Address + tx1 := mustInsertInProgressEthTxWithAttempt(t, txStore, 123, addr1) + tx2 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 123, addr2) + + tracker.XXXTestSetTTL(time.Nanosecond) + err := tracker.Start(context.Background()) + require.NoError(t, err) + defer func(tracker *txmgr.Tracker) { + err = tracker.Close() + require.NoError(t, err) + }(tracker) + + time.Sleep(waitTime) + require.NotContains(t, tracker.GetAbandonedAddresses(), addr1, addr2) + + fatalTxes, err := txStore.GetFatalTransactions(context.Background()) + require.NoError(t, err) + require.True(t, containsID(fatalTxes, tx1.ID)) + require.True(t, containsID(fatalTxes, tx2.ID)) + }) +} diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 46014c4e04..f0ce8c4ff6 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -193,6 +193,7 @@ func MustInsertConfirmedEthTxWithLegacyAttempt(t *testing.T, txStore txmgr.TestE n := evmtypes.Nonce(nonce) etx.Sequence = &n etx.State = txmgrcommon.TxConfirmed + etx.MinConfirmations.SetValid(6) require.NoError(t, txStore.InsertTx(&etx)) attempt := NewLegacyEthTxAttempt(t, etx.ID) attempt.BroadcastBeforeBlockNum = &broadcastBeforeBlockNum diff --git a/core/scripts/common/vrf/model/model.go b/core/scripts/common/vrf/model/model.go index 42deb42453..0972c47e61 100644 --- a/core/scripts/common/vrf/model/model.go +++ b/core/scripts/common/vrf/model/model.go @@ -1,8 +1,9 @@ package model import ( - "github.com/ethereum/go-ethereum/common" "math/big" + + "github.com/ethereum/go-ethereum/common" ) var ( diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 74d923ce09..fa95b694f9 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -137,7 +137,7 @@ func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.M _, _, evmConfig := txmgr.MakeTestConfigs(t) txmConfig := txmgr.NewEvmTxmConfig(evmConfig) txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, - nil, txStore, nil, nil, nil, nil) + nil, txStore, nil, nil, nil, nil, nil) return txm } diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index bcc85b3700..6192db95df 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -39,7 +39,7 @@ func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.M ec := evmtest.NewEthClientMockWithDefaultChain(t) txmConfig := txmgr.NewEvmTxmConfig(evmConfig) txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, - nil, txStore, nil, nil, nil, nil) + nil, txStore, nil, nil, nil, nil, nil) return txm } diff --git a/core/store/migrate/migrations/0210_remove_evm_key_states_fk_constraint.sql b/core/store/migrate/migrations/0210_remove_evm_key_states_fk_constraint.sql new file mode 100644 index 0000000000..119de9d260 --- /dev/null +++ b/core/store/migrate/migrations/0210_remove_evm_key_states_fk_constraint.sql @@ -0,0 +1,4 @@ +-- +goose Up +ALTER TABLE evm.txes DROP CONSTRAINT eth_txes_evm_chain_id_from_address_fkey; +-- +goose Down +ALTER TABLE evm.txes ADD CONSTRAINT eth_txes_evm_chain_id_from_address_fkey FOREIGN KEY (evm_chain_id, from_address) REFERENCES evm.key_states(evm_chain_id, address) ON DELETE CASCADE DEFERRABLE INITIALLY IMMEDIATE NOT VALID; \ No newline at end of file diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c5f243626d..e8013d3617 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added a tracker component to the txmgr for tracking and gracefully handling abandoned transactions. Abandoned transactions occur when a fromAddress is removed from the keystore by a node operator. The tracker gives abandoned transactions a chance to be finalized on chain, or marks them as fatal_error if they are not finalized within a specified time to live (default 6hrs). - Added distributed tracing in the OpenTelemetry trace format to the node, currently focused at the LOOPP Plugin development effort. This includes a new set of `Tracing` TOML configurations. The default for collecting traces is off - you must explicitly enable traces and setup a valid OpenTelemetry collector. Refer to `.github/tracing/README.md` for more details. - Added a new, optional WebServer authentication option that supports LDAP as a user identity provider. This enables user login access and user roles to be managed and provisioned via a centralized remote server that supports the LDAP protocol, which can be helpful when running multiple nodes. See the documentation for more information and config setup instructions. There is a new `[WebServer].AuthenticationMethod` config option, when set to `ldap` requires the new `[WebServer.LDAP]` config section to be defined, see the reference `docs/core.toml`. - New prom metrics for mercury transmit queue: From 2ed60e4f0a057779ef3e23002cbe4bbb76da88d6 Mon Sep 17 00:00:00 2001 From: Domino Valdano <2644901+reductionista@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:01:55 -0800 Subject: [PATCH 217/327] Change UseFinalityTags to FinalityTagEnabled in CHANGELOG.md to avoid confusion (#11404) The name of the param LogPoller accepts is useFinalityTag, but the externally-facing name of the toml config param it's set based on is FinalityTagEnabled. There is also a toml config param named UseFinalityTag but it's only used for integration tests, there is no such thing in the main production toml config. Also, adding EVM prefix for clarity. --- docs/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e8013d3617..e282d04789 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -93,7 +93,7 @@ ServerPubKey = '...' These will eventually replace `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey`. Setting `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey` alongside `[[TelemetryIngress.Endpoints]]` will prevent the node from booting. Only one way of configuring telemetry endpoints is supported. - Added bridge_name label to `pipeline_tasks_total_finished` prometheus metric. This should make it easier to see directly what bridge was failing out from the CL NODE perspective. -- LogPoller will now use finality tags to dynamically determine finality on evm chains if `UseFinalityTags=true`, rather than the fixed `FinalityDepth` specified in toml config +- LogPoller will now use finality tags to dynamically determine finality on evm chains if `EVM.FinalityTagEnabled=true`, rather than the fixed `EVM.FinalityDepth` specified in toml config ### Changed From de6c45e89fc63dcda3e3cfc67566aa5fd3bd1f5c Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Wed, 29 Nov 2023 12:57:35 +0100 Subject: [PATCH 218/327] Add callWithExactGas lib (#11009) * add callWithExactGas lib * add fuzz test * dup code to make it more safe * add _callWithExactGasEvenIfTargetIsNoContract * make args order consistent * add callWithExactGasEvenIfTargetIsNoContract tests * improve tests * update snapshot * properly name fuzz test * fix comments * improve testing logic * return gas used in _callWithExactGasSafeReturnData (#11106) * fix function selector blacklist in fuzz test * Update shared.gas-snapshot * use constant revert reasons * fix solhint * fix ref * style nits and let all return success * fix solhint --- contracts/GNUmakefile | 5 + contracts/gas-snapshots/shared.gas-snapshot | 16 + contracts/package.json | 2 +- .../src/v0.8/shared/call/CallWithExactGas.sol | 162 +++++++ .../shared/test/call/CallWithExactGas.t.sol | 459 ++++++++++++++++++ .../test/call/CallWithExactGasHelper.sol | 35 ++ .../test/testhelpers/GenericReceiver.sol | 29 ++ 7 files changed, 707 insertions(+), 1 deletion(-) create mode 100644 contracts/src/v0.8/shared/call/CallWithExactGas.sol create mode 100644 contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol create mode 100644 contracts/src/v0.8/shared/test/call/CallWithExactGasHelper.sol create mode 100644 contracts/src/v0.8/shared/test/testhelpers/GenericReceiver.sol diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index e880813867..f5be193249 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -18,6 +18,11 @@ ALL_FOUNDRY_PRODUCTS = llo-feeds functions shared snapshot: ## Make a snapshot for a specific product. export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "testFuzz_\w{1,}?" --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot +.PHONY: snapshot-diff +snapshot-diff: ## Make a snapshot for a specific product. + export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "testFuzz_\w{1,}?" --diff gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot + + .PHONY: snapshot-all snapshot-all: ## Make a snapshot for all products. for foundry_profile in $(ALL_FOUNDRY_PRODUCTS) ; do \ diff --git a/contracts/gas-snapshots/shared.gas-snapshot b/contracts/gas-snapshots/shared.gas-snapshot index cf003c5a26..6f307d257f 100644 --- a/contracts/gas-snapshots/shared.gas-snapshot +++ b/contracts/gas-snapshots/shared.gas-snapshot @@ -25,6 +25,22 @@ BurnMintERC677_mint:testSenderNotMinterReverts() (gas: 11195) BurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 8685) BurnMintERC677_transfer:testInvalidAddressReverts() (gas: 10639) BurnMintERC677_transfer:testTransferSuccess() (gas: 39462) +CallWithExactGas__callWithExactGas:test_CallWithExactGasReceiverErrorSuccess() (gas: 66918) +CallWithExactGas__callWithExactGas:test_CallWithExactGasSafeReturnDataExactGas() (gas: 22615) +CallWithExactGas__callWithExactGas:test_NoContractReverts() (gas: 11559) +CallWithExactGas__callWithExactGas:test_NoGasForCallExactCheckReverts() (gas: 12908) +CallWithExactGas__callWithExactGas:test_NotEnoughGasForCallReverts() (gas: 13361) +CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 256, μ: 15477, ~: 15418) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 19147) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 67096) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes,bytes4) (runs: 256, μ: 15675, ~: 15616) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoContractSuccess() (gas: 9816) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoGasForCallExactCheckReturnFalseSuccess() (gas: 9578) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NotEnoughGasForCallReturnsFalseSuccess() (gas: 9890) +CallWithExactGas__callWithExactGasSafeReturnData:test_CallWithExactGasSafeReturnDataExactGas() (gas: 19017) +CallWithExactGas__callWithExactGasSafeReturnData:test_NoContractReverts() (gas: 13949) +CallWithExactGas__callWithExactGasSafeReturnData:test_NoGasForCallExactCheckReverts() (gas: 13239) +CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 13670) OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1739317) OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 263373) OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957) diff --git a/contracts/package.json b/contracts/package.json index 2ceb1602dc..1503c822ea 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 369 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 376 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", diff --git a/contracts/src/v0.8/shared/call/CallWithExactGas.sol b/contracts/src/v0.8/shared/call/CallWithExactGas.sol new file mode 100644 index 0000000000..6716dc1595 --- /dev/null +++ b/contracts/src/v0.8/shared/call/CallWithExactGas.sol @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @notice This library contains various callWithExactGas functions. All of them are +/// safe from gas bomb attacks. +/// @dev There is code duplication in this library. This is done to not leave the assembly +/// the blocks. +library CallWithExactGas { + error NoContract(); + error NoGasForCallExactCheck(); + error NotEnoughGasForCall(); + + bytes4 internal constant NO_CONTRACT_SIG = 0x0c3b563c; + bytes4 internal constant NO_GAS_FOR_CALL_EXACT_CHECK_SIG = 0xafa32a2c; + bytes4 internal constant NOT_ENOUGH_GAS_FOR_CALL_SIG = 0x37c3be29; + + /// @notice calls target address with exactly gasAmount gas and payload as calldata. + /// Accounts for gasForCallExactCheck gas that will be used by this function. Will revert + /// if the target is not a contact. Will revert when there is not enough gas to call the + /// target with gasAmount gas. + /// @dev Ignores the return data, which makes it immune to gas bomb attacks. + /// @return success whether the call succeeded + function _callWithExactGas( + bytes memory payload, + address target, + uint256 gasLimit, + uint16 gasForCallExactCheck + ) internal returns (bool success) { + assembly { + // solidity calls check that a contract actually exists at the destination, so we do the same + // Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion") + // doesn't need to account for it. + if iszero(extcodesize(target)) { + mstore(0x0, NO_CONTRACT_SIG) + revert(0x0, 0x4) + } + + let g := gas() + // Compute g -= gasForCallExactCheck and check for underflow + // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). + // We want to ensure that we revert if gasAmount > 63//64*gas available + // as we do not want to provide them with less, however that check itself costs + // gas. gasForCallExactCheck ensures we have at least enough gas to be able + // to revert if gasAmount > 63//64*gas available. + if lt(g, gasForCallExactCheck) { + mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG) + revert(0x0, 0x4) + } + g := sub(g, gasForCallExactCheck) + // if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150 + if iszero(gt(sub(g, div(g, 64)), gasLimit)) { + mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG) + revert(0x0, 0x4) + } + + // call and return whether we succeeded. ignore return data + // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) + success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0) + } + return success; + } + + /// @notice calls target address with exactly gasAmount gas and payload as calldata. + /// Account for gasForCallExactCheck gas that will be used by this function. Will revert + /// if the target is not a contact. Will revert when there is not enough gas to call the + /// target with gasAmount gas. + /// @dev Caps the return data length, which makes it immune to gas bomb attacks. + /// @dev Return data cap logic borrowed from + /// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol. + /// @return success whether the call succeeded + /// @return retData the return data from the call, capped at maxReturnBytes bytes + /// @return gasUsed the gas used by the external call. Does not include the overhead of this function. + function _callWithExactGasSafeReturnData( + bytes memory payload, + address target, + uint256 gasLimit, + uint16 gasForCallExactCheck, + uint16 maxReturnBytes + ) internal returns (bool success, bytes memory retData, uint256 gasUsed) { + // allocate retData memory ahead of time + retData = new bytes(maxReturnBytes); + + assembly { + // solidity calls check that a contract actually exists at the destination, so we do the same + // Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion") + // doesn't need to account for it. + if iszero(extcodesize(target)) { + mstore(0x0, NO_CONTRACT_SIG) + revert(0x0, 0x4) + } + + let g := gas() + // Compute g -= gasForCallExactCheck and check for underflow + // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). + // We want to ensure that we revert if gasAmount > 63//64*gas available + // as we do not want to provide them with less, however that check itself costs + // gas. gasForCallExactCheck ensures we have at least enough gas to be able + // to revert if gasAmount > 63//64*gas available. + if lt(g, gasForCallExactCheck) { + mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG) + revert(0x0, 0x4) + } + g := sub(g, gasForCallExactCheck) + // if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150 + if iszero(gt(sub(g, div(g, 64)), gasLimit)) { + mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG) + revert(0x0, 0x4) + } + + // We save the gas before the call so we can calculate how much gas the call used + let gasBeforeCall := gas() + // call and return whether we succeeded. ignore return data + // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) + success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0) + gasUsed := sub(gasBeforeCall, gas()) + + // limit our copy to maxReturnBytes bytes + let toCopy := returndatasize() + if gt(toCopy, maxReturnBytes) { + toCopy := maxReturnBytes + } + // Store the length of the copied bytes + mstore(retData, toCopy) + // copy the bytes from retData[0:_toCopy] + returndatacopy(add(retData, 0x20), 0x0, toCopy) + } + return (success, retData, gasUsed); + } + + /// @notice Calls target address with exactly gasAmount gas and payload as calldata + /// or reverts if at least gasLimit gas is not available. + /// @dev Does not check if target is a contract. If it is not a contract, the low-level + /// call will still be made and it will succeed. + /// @dev Ignores the return data, which makes it immune to gas bomb attacks. + /// @return success whether the call succeeded + /// @return sufficientGas Whether there was enough gas to make the call + function _callWithExactGasEvenIfTargetIsNoContract( + bytes memory payload, + address target, + uint256 gasLimit, + uint16 gasForCallExactCheck + ) internal returns (bool success, bool sufficientGas) { + assembly { + let g := gas() + // Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We + // need the cushion since the logic following the above call to gas also + // costs gas which we cannot account for exactly. So cushion is a + // conservative upper bound for the cost of this logic. + if iszero(lt(g, gasForCallExactCheck)) { + g := sub(g, gasForCallExactCheck) + // If g - g//64 <= gasAmount, we don't have enough gas. We subtract g//64 because of EIP-150. + if gt(sub(g, div(g, 64)), gasLimit) { + // Call and ignore success/return data. Note that we did not check + // whether a contract actually exists at the target address. + success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0) + sufficientGas := true + } + } + } + return (success, sufficientGas); + } +} diff --git a/contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol b/contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol new file mode 100644 index 0000000000..e5c90b172c --- /dev/null +++ b/contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {CallWithExactGas} from "../../call/CallWithExactGas.sol"; +import {CallWithExactGasHelper} from "./CallWithExactGasHelper.sol"; +import {BaseTest} from "../BaseTest.t.sol"; +import {GenericReceiver} from "../testhelpers/GenericReceiver.sol"; + +contract CallWithExactGasSetup is BaseTest { + GenericReceiver internal s_receiver; + CallWithExactGasHelper internal s_caller; + uint256 internal constant DEFAULT_GAS_LIMIT = 20_000; + uint16 internal constant DEFAULT_GAS_FOR_CALL_EXACT_CHECK = 5000; + uint256 internal constant EXTCODESIZE_GAS_COST = 2600; + + function setUp() public virtual override { + BaseTest.setUp(); + + s_receiver = new GenericReceiver(false); + s_caller = new CallWithExactGasHelper(); + } +} + +contract CallWithExactGas__callWithExactGas is CallWithExactGasSetup { + function test_callWithExactGasSuccess(bytes memory payload, bytes4 funcSelector) public { + vm.pauseGasMetering(); + + bytes memory data = abi.encodeWithSelector(funcSelector, payload); + vm.assume( + funcSelector != GenericReceiver.setRevert.selector && + funcSelector != GenericReceiver.setErr.selector && + funcSelector != 0x5100fc21 // s_toRevert(), which is public and therefore has a function selector + ); + + vm.expectCall(address(s_receiver), data); + vm.resumeGasMetering(); + + bool success = s_caller.callWithExactGas( + data, + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + assertTrue(success); + } + + function test_CallWithExactGasSafeReturnDataExactGas() public { + // The calculated overhead for otherwise unaccounted for gas usage + uint256 overheadForCallWithExactGas = 364; + + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGas.selector, + "", + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + // Since only 63/64th of the gas gets passed, we compensate + uint256 allowedGas = (DEFAULT_GAS_LIMIT + (DEFAULT_GAS_LIMIT / 64)); + + allowedGas += EXTCODESIZE_GAS_COST + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + overheadForCallWithExactGas; + + // Due to EIP-150 we expect to lose 1/64, so we compensate for this + allowedGas = (allowedGas * 64) / 63; + + (bool success, bytes memory retData) = address(s_caller).call{gas: allowedGas}(payload); + + assertTrue(success); + assertEq(abi.encode(true), retData); + } + + function test_CallWithExactGasReceiverErrorSuccess() public { + bytes memory data = abi.encode("0x52656E73"); + + bytes memory errorData = new bytes(20); + for (uint256 i = 0; i < errorData.length; ++i) { + errorData[i] = 0x01; + } + s_receiver.setErr(errorData); + s_receiver.setRevert(true); + + vm.expectCall(address(s_receiver), data); + + bool success = s_caller.callWithExactGas( + data, + address(s_receiver), + DEFAULT_GAS_LIMIT * 10, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + assertFalse(success); + } + + function test_NoContractReverts() public { + address addressWithoutContract = address(1337); + + vm.expectRevert(CallWithExactGas.NoContract.selector); + + s_caller.callWithExactGas( + "", // empty payload as it will revert well before needing it + addressWithoutContract, + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + } + + function test_NoGasForCallExactCheckReverts() public { + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGas.selector, + "", // empty payload as it will revert well before needing it + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + (bool success, bytes memory retData) = address(s_caller).call{gas: DEFAULT_GAS_FOR_CALL_EXACT_CHECK - 1}(payload); + assertFalse(success); + assertEq(retData.length, CallWithExactGas.NoGasForCallExactCheck.selector.length); + assertEq(abi.encodeWithSelector(CallWithExactGas.NoGasForCallExactCheck.selector), retData); + } + + function test_NotEnoughGasForCallReverts() public { + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGas.selector, + "", // empty payload as it will revert well before needing it + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + // Supply enough gas for the final call, the DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + // the extcodesize and account for EIP-150. This doesn't account for any other gas + // usage, and will therefore fail because the checks and memory stored/loads + // also cost gas. + uint256 allowedGas = (DEFAULT_GAS_LIMIT + (DEFAULT_GAS_LIMIT / 64)) + DEFAULT_GAS_FOR_CALL_EXACT_CHECK; + // extcodesize gas cost + allowedGas += EXTCODESIZE_GAS_COST; + // EIP-150 + allowedGas = (allowedGas * 64) / 63; + + // Expect this call to fail due to not having enough gas for the final call + (bool success, bytes memory retData) = address(s_caller).call{gas: allowedGas}(payload); + + assertFalse(success); + assertEq(retData.length, CallWithExactGas.NotEnoughGasForCall.selector.length); + assertEq(abi.encodeWithSelector(CallWithExactGas.NotEnoughGasForCall.selector), retData); + } +} + +contract CallWithExactGas__callWithExactGasSafeReturnData is CallWithExactGasSetup { + function testFuzz_CallWithExactGasSafeReturnDataSuccess(bytes memory payload, bytes4 funcSelector) public { + vm.pauseGasMetering(); + bytes memory data = abi.encodeWithSelector(funcSelector, payload); + vm.assume( + funcSelector != GenericReceiver.setRevert.selector && + funcSelector != GenericReceiver.setErr.selector && + funcSelector != 0x5100fc21 // s_toRevert(), which is public and therefore has a function selector + ); + uint16 maxRetBytes = 0; + + vm.expectCall(address(s_receiver), data); + vm.resumeGasMetering(); + + (bool success, bytes memory retData, uint256 gasUsed) = s_caller.callWithExactGasSafeReturnData( + data, + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + maxRetBytes + ); + + assertTrue(success); + assertEq(retData.length, 0); + assertGt(gasUsed, 500); + } + + function test_CallWithExactGasSafeReturnDataExactGas() public { + // The gas cost for `extcodesize` + uint256 extcodesizeGas = EXTCODESIZE_GAS_COST; + // The calculated overhead for retData initialization + uint256 overheadForRetDataInit = 114; + // The calculated overhead for otherwise unaccounted for gas usage + uint256 overheadForCallWithExactGas = 486; + + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGasSafeReturnData.selector, + "", + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + 0 + ); + + // Since only 63/64th of the gas gets passed, we compensate + uint256 allowedGas = (DEFAULT_GAS_LIMIT + (DEFAULT_GAS_LIMIT / 64)); + + allowedGas += + extcodesizeGas + + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + + overheadForRetDataInit + + overheadForCallWithExactGas; + + // Due to EIP-150 we expect to lose 1/64, so we compensate for this + allowedGas = (allowedGas * 64) / 63; + + vm.expectCall(address(s_receiver), ""); + (bool success, bytes memory retData) = address(s_caller).call{gas: allowedGas}(payload); + + assertTrue(success); + (bool innerSuccess, bytes memory innerRetData, uint256 gasUsed) = abi.decode(retData, (bool, bytes, uint256)); + + assertTrue(innerSuccess); + assertEq(innerRetData.length, 0); + assertGt(gasUsed, 500); + } + + function testFuzz_CallWithExactGasReceiverErrorSuccess(uint16 testRetBytes) public { + uint16 maxReturnBytes = 500; + // Bound with upper limit, otherwise the test runs out of gas. + testRetBytes = uint16(bound(testRetBytes, 0, maxReturnBytes * 10)); + + bytes memory data = abi.encode("0x52656E73"); + + bytes memory errorData = new bytes(testRetBytes); + for (uint256 i = 0; i < errorData.length; ++i) { + errorData[i] = 0x01; + } + s_receiver.setErr(errorData); + s_receiver.setRevert(true); + + vm.expectCall(address(s_receiver), data); + + (bool success, bytes memory retData, uint256 gasUsed) = s_caller.callWithExactGasSafeReturnData( + data, + address(s_receiver), + DEFAULT_GAS_LIMIT * 10, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + maxReturnBytes + ); + + assertFalse(success); + + bytes memory expectedReturnData = errorData; + + // If expected return data is longer than MAX_RET_BYTES, truncate it to MAX_RET_BYTES + if (expectedReturnData.length > maxReturnBytes) { + expectedReturnData = new bytes(maxReturnBytes); + for (uint256 i = 0; i < maxReturnBytes; ++i) { + expectedReturnData[i] = errorData[i]; + } + } + assertEq(expectedReturnData, retData); + assertGt(gasUsed, 500); + } + + function test_NoContractReverts() public { + address addressWithoutContract = address(1337); + + vm.expectRevert(CallWithExactGas.NoContract.selector); + + s_caller.callWithExactGasSafeReturnData( + "", // empty payload as it will revert well before needing it + addressWithoutContract, + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + 0 + ); + } + + function test_NoGasForCallExactCheckReverts() public { + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGasSafeReturnData.selector, + "", // empty payload as it will revert well before needing it + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + 0 + ); + + (bool success, bytes memory retData) = address(s_caller).call{gas: DEFAULT_GAS_FOR_CALL_EXACT_CHECK - 1}(payload); + assertFalse(success); + assertEq(retData.length, CallWithExactGas.NoGasForCallExactCheck.selector.length); + assertEq(abi.encodeWithSelector(CallWithExactGas.NoGasForCallExactCheck.selector), retData); + } + + function test_NotEnoughGasForCallReverts() public { + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGasSafeReturnData.selector, + "", // empty payload as it will revert well before needing it + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + 0 + ); + + // Supply enough gas for the final call, the DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + // the extcodesize and account for EIP-150. This doesn't account for any other gas + // usage, and will therefore fail because the checks and memory stored/loads + // also cost gas. + uint256 allowedGas = (DEFAULT_GAS_LIMIT + (DEFAULT_GAS_LIMIT / 64)) + DEFAULT_GAS_FOR_CALL_EXACT_CHECK; + // extcodesize gas cost + allowedGas += EXTCODESIZE_GAS_COST; + // EIP-150 + allowedGas = (allowedGas * 64) / 63; + + // Expect this call to fail due to not having enough gas for the final call + (bool success, bytes memory retData) = address(s_caller).call{gas: allowedGas}(payload); + + assertFalse(success); + assertEq(retData.length, CallWithExactGas.NotEnoughGasForCall.selector.length); + assertEq(abi.encodeWithSelector(CallWithExactGas.NotEnoughGasForCall.selector), retData); + } +} + +contract CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract is CallWithExactGasSetup { + function test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes memory payload, bytes4 funcSelector) public { + vm.pauseGasMetering(); + bytes memory data = abi.encodeWithSelector(funcSelector, payload); + vm.assume( + funcSelector != GenericReceiver.setRevert.selector && + funcSelector != GenericReceiver.setErr.selector && + funcSelector != 0x5100fc21 // s_toRevert(), which is public and therefore has a function selector + ); + vm.expectCall(address(s_receiver), data); + vm.resumeGasMetering(); + + (bool success, bool sufficientGas) = s_caller.callWithExactGasEvenIfTargetIsNoContract( + data, + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + assertTrue(success); + assertTrue(sufficientGas); + } + + function test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() public { + // The calculated overhead for otherwise unaccounted for gas usage + uint256 overheadForCallWithExactGas = 446; + + bytes memory data = abi.encode("0x52656E73"); + + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGasEvenIfTargetIsNoContract.selector, + data, + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + // Since only 63/64th of the gas gets passed, we compensate + uint256 allowedGas = (DEFAULT_GAS_LIMIT + (DEFAULT_GAS_LIMIT / 64)); + + allowedGas += DEFAULT_GAS_FOR_CALL_EXACT_CHECK + overheadForCallWithExactGas; + + // Due to EIP-150 we expect to lose 1/64, so we compensate for this + allowedGas = (allowedGas * 64) / 63; + + vm.expectCall(address(s_receiver), data); + (bool outerCallSuccess, bytes memory SuccessAndSufficientGas) = address(s_caller).call{gas: allowedGas}(payload); + + // The call succeeds + assertTrue(outerCallSuccess); + + (bool success, bool sufficientGas) = abi.decode(SuccessAndSufficientGas, (bool, bool)); + assertTrue(success); + assertTrue(sufficientGas); + } + + function test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() public { + bytes memory data = abi.encode("0x52656E73"); + + bytes memory errorData = new bytes(20); + for (uint256 i = 0; i < errorData.length; ++i) { + errorData[i] = 0x01; + } + s_receiver.setErr(errorData); + s_receiver.setRevert(true); + + vm.expectCall(address(s_receiver), data); + + (bool success, bool sufficientGas) = s_caller.callWithExactGasEvenIfTargetIsNoContract( + data, + address(s_receiver), + DEFAULT_GAS_LIMIT * 10, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + // We don't care if it reverts, we only care if we have enough gas + assertFalse(success); + assertTrue(sufficientGas); + } + + function test_NoContractSuccess() public { + bytes memory data = abi.encode("0x52656E73"); + address addressWithoutContract = address(1337); + + (bool success, bool sufficientGas) = s_caller.callWithExactGasEvenIfTargetIsNoContract( + data, + addressWithoutContract, + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + assertTrue(success); + assertTrue(sufficientGas); + } + + function test_NoGasForCallExactCheckReturnFalseSuccess() public { + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGasEvenIfTargetIsNoContract.selector, + "", // empty payload as it will revert well before needing it + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + (bool outerCallSuccess, bytes memory SuccessAndSufficientGas) = address(s_caller).call{ + gas: DEFAULT_GAS_FOR_CALL_EXACT_CHECK - 1 + }(payload); + + // The call succeeds + assertTrue(outerCallSuccess); + + (bool success, bool sufficientGas) = abi.decode(SuccessAndSufficientGas, (bool, bool)); + assertFalse(success); + assertFalse(sufficientGas); + } + + function test_NotEnoughGasForCallReturnsFalseSuccess() public { + bytes memory payload = abi.encodeWithSelector( + s_caller.callWithExactGasEvenIfTargetIsNoContract.selector, + "", // empty payload as it will revert well before needing it + address(s_receiver), + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_FOR_CALL_EXACT_CHECK + ); + + // Supply enough gas for the final call, the DEFAULT_GAS_FOR_CALL_EXACT_CHECK, + // and account for EIP-150. This doesn't account for any other gas usage, and + // will therefore fail because the checks and memory stored/loads also cost gas. + uint256 allowedGas = (DEFAULT_GAS_LIMIT + (DEFAULT_GAS_LIMIT / 64)) + DEFAULT_GAS_FOR_CALL_EXACT_CHECK; + // EIP-150 + allowedGas = (allowedGas * 64) / 63; + + // Expect this call to fail due to not having enough gas for the final call + (bool outerCallSuccess, bytes memory SuccessAndSufficientGas) = address(s_caller).call{gas: allowedGas}(payload); + + // The call succeeds + assertTrue(outerCallSuccess); + + (bool success, bool sufficientGas) = abi.decode(SuccessAndSufficientGas, (bool, bool)); + assertFalse(success); + assertFalse(sufficientGas); + } +} diff --git a/contracts/src/v0.8/shared/test/call/CallWithExactGasHelper.sol b/contracts/src/v0.8/shared/test/call/CallWithExactGasHelper.sol new file mode 100644 index 0000000000..932315639b --- /dev/null +++ b/contracts/src/v0.8/shared/test/call/CallWithExactGasHelper.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {CallWithExactGas} from "../../call/CallWithExactGas.sol"; + +contract CallWithExactGasHelper { + function callWithExactGas( + bytes memory payload, + address target, + uint256 gasLimit, + uint16 gasForCallExactCheck + ) public returns (bool success) { + return CallWithExactGas._callWithExactGas(payload, target, gasLimit, gasForCallExactCheck); + } + + function callWithExactGasSafeReturnData( + bytes memory payload, + address target, + uint256 gasLimit, + uint16 gasForCallExactCheck, + uint16 maxReturnBytes + ) public returns (bool success, bytes memory retData, uint256 gasUsed) { + return + CallWithExactGas._callWithExactGasSafeReturnData(payload, target, gasLimit, gasForCallExactCheck, maxReturnBytes); + } + + function callWithExactGasEvenIfTargetIsNoContract( + bytes memory payload, + address target, + uint256 gasLimit, + uint16 gasForCallExactCheck + ) public returns (bool success, bool sufficientGas) { + return CallWithExactGas._callWithExactGasEvenIfTargetIsNoContract(payload, target, gasLimit, gasForCallExactCheck); + } +} diff --git a/contracts/src/v0.8/shared/test/testhelpers/GenericReceiver.sol b/contracts/src/v0.8/shared/test/testhelpers/GenericReceiver.sol new file mode 100644 index 0000000000..2c058012df --- /dev/null +++ b/contracts/src/v0.8/shared/test/testhelpers/GenericReceiver.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract GenericReceiver { + bool public s_toRevert; + bytes private s_err; + + constructor(bool toRevert) { + s_toRevert = toRevert; + } + + function setRevert(bool toRevert) external { + s_toRevert = toRevert; + } + + function setErr(bytes memory err) external { + s_err = err; + } + + // solhint-disable-next-line payable-fallback + fallback() external { + if (s_toRevert) { + bytes memory reason = s_err; + assembly { + revert(add(32, reason), mload(reason)) + } + } + } +} From 99071cd7d8a8b2f13c31afb933af7e3a5615775f Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Wed, 29 Nov 2023 15:10:39 +0100 Subject: [PATCH 219/327] CCIP-1336 LogPoller - Bunch of minor improvements (#11348) * Tracking number of logs inserted by LP * Adding read query to LP * Index for fourth word in data * Regenerating mocks * Filter by address in SelectIndexedLogsByTxHash * Fix * Post review fixes * Post merge fixes --- core/chains/evm/logpoller/disabled.go | 6 +- core/chains/evm/logpoller/log_poller.go | 20 ++- core/chains/evm/logpoller/mocks/log_poller.go | 51 +++++-- core/chains/evm/logpoller/observability.go | 91 +++++++++--- .../evm/logpoller/observability_test.go | 72 ++++++++-- core/chains/evm/logpoller/orm.go | 35 ++++- core/chains/evm/logpoller/orm_test.go | 132 +++++++++++++++++- core/chains/evm/logpoller/query.go | 12 ++ .../0211_log_poller_word_indexes.sql | 6 + 9 files changed, 373 insertions(+), 52 deletions(-) create mode 100644 core/store/migrate/migrations/0211_log_poller_word_indexes.sql diff --git a/core/chains/evm/logpoller/disabled.go b/core/chains/evm/logpoller/disabled.go index b54d4e6fc8..05d591042f 100644 --- a/core/chains/evm/logpoller/disabled.go +++ b/core/chains/evm/logpoller/disabled.go @@ -71,7 +71,7 @@ func (disabled) IndexedLogsByBlockRange(start, end int64, eventSig common.Hash, return nil, ErrDisabled } -func (d disabled) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { +func (d disabled) IndexedLogsByTxHash(eventSig common.Hash, address common.Address, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } @@ -106,3 +106,7 @@ func (d disabled) IndexedLogsCreatedAfter(eventSig common.Hash, address common.A func (d disabled) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) (int64, error) { return 0, ErrDisabled } + +func (d disabled) LogsDataWordBetween(eventSig common.Hash, address common.Address, wordIndexMin, wordIndexMax int, wordValue common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return nil, ErrDisabled +} diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 7c4ea66cec..de1999da26 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -53,12 +53,13 @@ type LogPoller interface { IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) IndexedLogsByBlockRange(start, end int64, eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) - IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) + IndexedLogsByTxHash(eventSig common.Hash, address common.Address, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + LogsDataWordBetween(eventSig common.Hash, address common.Address, wordIndexMin, wordIndexMax int, wordValue common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) } type Confirmations int @@ -969,8 +970,8 @@ func (lp *logPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address commo return lp.orm.SelectIndexedLogsCreatedAfter(address, eventSig, topicIndex, topicValues, after, confs, qopts...) } -func (lp *logPoller) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectIndexedLogsByTxHash(eventSig, txHash, qopts...) +func (lp *logPoller) IndexedLogsByTxHash(eventSig common.Hash, address common.Address, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { + return lp.orm.SelectIndexedLogsByTxHash(address, eventSig, txHash, qopts...) } // LogsDataWordGreaterThan note index is 0 based. @@ -1021,6 +1022,19 @@ func (lp *logPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, event return lp.orm.SelectLatestBlockByEventSigsAddrsWithConfs(fromBlock, eventSigs, addresses, confs, qopts...) } +// LogsDataWordBetween retrieves a slice of Log records that match specific criteria. +// Besides generic filters like eventSig, address and confs, it also verifies data content against wordValue +// data[wordIndexMin] <= wordValue <= data[wordIndexMax]. +// +// Passing the same value for wordIndexMin and wordIndexMax will check the equality of the wordValue at that index. +// Leading to returning logs matching: data[wordIndexMin] == wordValue. +// +// This function is particularly useful for filtering logs by data word values and their positions within the event data. +// It returns an empty slice if no logs match the provided criteria. +func (lp *logPoller) LogsDataWordBetween(eventSig common.Hash, address common.Address, wordIndexMin, wordIndexMax int, wordValue common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return lp.orm.SelectLogsDataWordBetween(address, eventSig, wordIndexMin, wordIndexMax, wordValue, confs, qopts...) +} + // GetBlocksRange tries to get the specified block numbers from the log pollers // blocks table. It falls back to the RPC for any unfulfilled requested blocks. func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts ...pg.QOpt) ([]LogPollerBlock, error) { diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index 01be5f7ba5..fe4ccc965c 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -164,32 +164,32 @@ func (_m *LogPoller) IndexedLogsByBlockRange(start int64, end int64, eventSig co return r0, r1 } -// IndexedLogsByTxHash provides a mock function with given fields: eventSig, txHash, qopts -func (_m *LogPoller) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]logpoller.Log, error) { +// IndexedLogsByTxHash provides a mock function with given fields: eventSig, address, txHash, qopts +func (_m *LogPoller) IndexedLogsByTxHash(eventSig common.Hash, address common.Address, txHash common.Hash, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] } var _ca []interface{} - _ca = append(_ca, eventSig, txHash) + _ca = append(_ca, eventSig, address, txHash) _ca = append(_ca, _va...) ret := _m.Called(_ca...) var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Hash, ...pg.QOpt) ([]logpoller.Log, error)); ok { - return rf(eventSig, txHash, qopts...) + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, common.Hash, ...pg.QOpt) ([]logpoller.Log, error)); ok { + return rf(eventSig, address, txHash, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Hash, ...pg.QOpt) []logpoller.Log); ok { - r0 = rf(eventSig, txHash, qopts...) + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, common.Hash, ...pg.QOpt) []logpoller.Log); ok { + r0 = rf(eventSig, address, txHash, qopts...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]logpoller.Log) } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Hash, ...pg.QOpt) error); ok { - r1 = rf(eventSig, txHash, qopts...) + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, common.Hash, ...pg.QOpt) error); ok { + r1 = rf(eventSig, address, txHash, qopts...) } else { r1 = ret.Error(1) } @@ -522,6 +522,39 @@ func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Addre return r0, r1 } +// LogsDataWordBetween provides a mock function with given fields: eventSig, address, wordIndexMin, wordIndexMax, wordValue, confs, qopts +func (_m *LogPoller) LogsDataWordBetween(eventSig common.Hash, address common.Address, wordIndexMin int, wordIndexMax int, wordValue common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, eventSig, address, wordIndexMin, wordIndexMax, wordValue, confs) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []logpoller.Log + var r1 error + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { + return rf(eventSig, address, wordIndexMin, wordIndexMax, wordValue, confs, qopts...) + } + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { + r0 = rf(eventSig, address, wordIndexMin, wordIndexMax, wordValue, confs, qopts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]logpoller.Log) + } + } + + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) error); ok { + r1 = rf(eventSig, address, wordIndexMin, wordIndexMax, wordValue, confs, qopts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // LogsDataWordGreaterThan provides a mock function with given fields: eventSig, address, wordIndex, wordValueMin, confs, qopts func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) diff --git a/core/chains/evm/logpoller/observability.go b/core/chains/evm/logpoller/observability.go index 9826d503b9..a7a0d3c03d 100644 --- a/core/chains/evm/logpoller/observability.go +++ b/core/chains/evm/logpoller/observability.go @@ -14,6 +14,14 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) +type queryType string + +const ( + create queryType = "create" + read queryType = "read" + del queryType = "delete" +) + var ( sqlLatencyBuckets = []float64{ float64(1 * time.Millisecond), @@ -41,47 +49,63 @@ var ( Name: "log_poller_query_duration", Help: "Measures duration of Log Poller's queries fetching logs", Buckets: sqlLatencyBuckets, - }, []string{"evmChainID", "query"}) + }, []string{"evmChainID", "query", "type"}) lpQueryDataSets = promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "log_poller_query_dataset_size", Help: "Measures size of the datasets returned by Log Poller's queries", - }, []string{"evmChainID", "query"}) + }, []string{"evmChainID", "query", "type"}) + lpLogsInserted = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "log_poller_logs_inserted", + Help: "Counter to track number of logs inserted by Log Poller", + }, []string{"evmChainID"}) + lpBlockInserted = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "log_poller_blocks_inserted", + Help: "Counter to track number of blocks inserted by Log Poller", + }, []string{"evmChainID"}) ) // ObservedORM is a decorator layer for ORM used by LogPoller, responsible for pushing Prometheus metrics reporting duration and size of result set for the queries. // It doesn't change internal logic, because all calls are delegated to the origin ORM type ObservedORM struct { ORM - queryDuration *prometheus.HistogramVec - datasetSize *prometheus.GaugeVec - chainId string + queryDuration *prometheus.HistogramVec + datasetSize *prometheus.GaugeVec + logsInserted *prometheus.CounterVec + blocksInserted *prometheus.CounterVec + chainId string } // NewObservedORM creates an observed version of log poller's ORM created by NewORM // Please see ObservedLogPoller for more details on how latencies are measured func NewObservedORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *ObservedORM { return &ObservedORM{ - ORM: NewORM(chainID, db, lggr, cfg), - queryDuration: lpQueryDuration, - datasetSize: lpQueryDataSets, - chainId: chainID.String(), + ORM: NewORM(chainID, db, lggr, cfg), + queryDuration: lpQueryDuration, + datasetSize: lpQueryDataSets, + logsInserted: lpLogsInserted, + blocksInserted: lpBlockInserted, + chainId: chainID.String(), } } func (o *ObservedORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { - return withObservedExec(o, "InsertLogs", func() error { + err := withObservedExec(o, "InsertLogs", create, func() error { return o.ORM.InsertLogs(logs, qopts...) }) + trackInsertedLogsAndBlock(o, logs, nil, err) + return err } func (o *ObservedORM) InsertLogsWithBlock(logs []Log, block LogPollerBlock, qopts ...pg.QOpt) error { - return withObservedExec(o, "InsertLogsWithBlock", func() error { + err := withObservedExec(o, "InsertLogsWithBlock", create, func() error { return o.ORM.InsertLogsWithBlock(logs, block, qopts...) }) + trackInsertedLogsAndBlock(o, logs, &block, err) + return err } func (o *ObservedORM) InsertFilter(filter Filter, qopts ...pg.QOpt) error { - return withObservedExec(o, "InsertFilter", func() error { + return withObservedExec(o, "InsertFilter", create, func() error { return o.ORM.InsertFilter(filter, qopts...) }) } @@ -93,25 +117,25 @@ func (o *ObservedORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { } func (o *ObservedORM) DeleteFilter(name string, qopts ...pg.QOpt) error { - return withObservedExec(o, "DeleteFilter", func() error { + return withObservedExec(o, "DeleteFilter", del, func() error { return o.ORM.DeleteFilter(name, qopts...) }) } func (o *ObservedORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { - return withObservedExec(o, "DeleteBlocksBefore", func() error { + return withObservedExec(o, "DeleteBlocksBefore", del, func() error { return o.ORM.DeleteBlocksBefore(end, qopts...) }) } func (o *ObservedORM) DeleteLogsAndBlocksAfter(start int64, qopts ...pg.QOpt) error { - return withObservedExec(o, "DeleteLogsAndBlocksAfter", func() error { + return withObservedExec(o, "DeleteLogsAndBlocksAfter", del, func() error { return o.ORM.DeleteLogsAndBlocksAfter(start, qopts...) }) } func (o *ObservedORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { - return withObservedExec(o, "DeleteExpiredLogs", func() error { + return withObservedExec(o, "DeleteExpiredLogs", del, func() error { return o.ORM.DeleteExpiredLogs(qopts...) }) } @@ -176,9 +200,9 @@ func (o *ObservedORM) SelectLogs(start, end int64, address common.Address, event }) } -func (o *ObservedORM) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "IndexedLogsByTxHash", func() ([]Log, error) { - return o.ORM.SelectIndexedLogsByTxHash(eventSig, txHash, qopts...) +func (o *ObservedORM) SelectIndexedLogsByTxHash(address common.Address, eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectIndexedLogsByTxHash", func() ([]Log, error) { + return o.ORM.SelectIndexedLogsByTxHash(address, eventSig, txHash, qopts...) }) } @@ -212,6 +236,12 @@ func (o *ObservedORM) SelectLogsDataWordGreaterThan(address common.Address, even }) } +func (o *ObservedORM) SelectLogsDataWordBetween(address common.Address, eventSig common.Hash, wordIndexMin int, wordIndexMax int, wordValue common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectLogsDataWordBetween", func() ([]Log, error) { + return o.ORM.SelectLogsDataWordBetween(address, eventSig, wordIndexMin, wordIndexMax, wordValue, confs, qopts...) + }) +} + func (o *ObservedORM) SelectIndexedLogsTopicGreaterThan(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return withObservedQueryAndResults(o, "SelectIndexedLogsTopicGreaterThan", func() ([]Log, error) { return o.ORM.SelectIndexedLogsTopicGreaterThan(address, eventSig, topicIndex, topicValueMin, confs, qopts...) @@ -228,7 +258,7 @@ func withObservedQueryAndResults[T any](o *ObservedORM, queryName string, query results, err := withObservedQuery(o, queryName, query) if err == nil { o.datasetSize. - WithLabelValues(o.chainId, queryName). + WithLabelValues(o.chainId, queryName, string(read)). Set(float64(len(results))) } return results, err @@ -238,18 +268,33 @@ func withObservedQuery[T any](o *ObservedORM, queryName string, query func() (T, queryStarted := time.Now() defer func() { o.queryDuration. - WithLabelValues(o.chainId, queryName). + WithLabelValues(o.chainId, queryName, string(read)). Observe(float64(time.Since(queryStarted))) }() return query() } -func withObservedExec(o *ObservedORM, query string, exec func() error) error { +func withObservedExec(o *ObservedORM, query string, queryType queryType, exec func() error) error { queryStarted := time.Now() defer func() { o.queryDuration. - WithLabelValues(o.chainId, query). + WithLabelValues(o.chainId, query, string(queryType)). Observe(float64(time.Since(queryStarted))) }() return exec() } + +func trackInsertedLogsAndBlock(o *ObservedORM, logs []Log, block *LogPollerBlock, err error) { + if err != nil { + return + } + o.logsInserted. + WithLabelValues(o.chainId). + Add(float64(len(logs))) + + if block != nil { + o.blocksInserted. + WithLabelValues(o.chainId). + Inc() + } +} diff --git a/core/chains/evm/logpoller/observability_test.go b/core/chains/evm/logpoller/observability_test.go index 83bd60a556..76575f46ca 100644 --- a/core/chains/evm/logpoller/observability_test.go +++ b/core/chains/evm/logpoller/observability_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/prometheus/client_golang/prometheus" io_prometheus_client "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" @@ -18,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestMultipleMetricsArePublished(t *testing.T) { @@ -54,7 +56,7 @@ func TestShouldPublishDurationInCaseOfError(t *testing.T) { require.Error(t, err) require.Equal(t, 1, testutil.CollectAndCount(orm.queryDuration)) - require.Equal(t, 1, counterFromHistogramByLabels(t, orm.queryDuration, "200", "SelectLatestLogByEventSigWithConfs")) + require.Equal(t, 1, counterFromHistogramByLabels(t, orm.queryDuration, "200", "SelectLatestLogByEventSigWithConfs", "read")) } func TestMetricsAreProperlyPopulatedWithLabels(t *testing.T) { @@ -68,14 +70,14 @@ func TestMetricsAreProperlyPopulatedWithLabels(t *testing.T) { require.NoError(t, err) } - require.Equal(t, expectedCount, counterFromHistogramByLabels(t, orm.queryDuration, "420", "query")) - require.Equal(t, expectedSize, counterFromGaugeByLabels(orm.datasetSize, "420", "query")) + require.Equal(t, expectedCount, counterFromHistogramByLabels(t, orm.queryDuration, "420", "query", "read")) + require.Equal(t, expectedSize, counterFromGaugeByLabels(orm.datasetSize, "420", "query", "read")) - require.Equal(t, 0, counterFromHistogramByLabels(t, orm.queryDuration, "420", "other_query")) - require.Equal(t, 0, counterFromHistogramByLabels(t, orm.queryDuration, "5", "query")) + require.Equal(t, 0, counterFromHistogramByLabels(t, orm.queryDuration, "420", "other_query", "read")) + require.Equal(t, 0, counterFromHistogramByLabels(t, orm.queryDuration, "5", "query", "read")) - require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "420", "other_query")) - require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "5", "query")) + require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "420", "other_query", "read")) + require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "5", "query", "read")) } func TestNotPublishingDatasetSizeInCaseOfError(t *testing.T) { @@ -84,16 +86,60 @@ func TestNotPublishingDatasetSizeInCaseOfError(t *testing.T) { _, err := withObservedQueryAndResults(orm, "errorQuery", func() ([]string, error) { return nil, fmt.Errorf("error") }) require.Error(t, err) - require.Equal(t, 1, counterFromHistogramByLabels(t, orm.queryDuration, "420", "errorQuery")) - require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "420", "errorQuery")) + require.Equal(t, 1, counterFromHistogramByLabels(t, orm.queryDuration, "420", "errorQuery", "read")) + require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "420", "errorQuery", "read")) } func TestMetricsAreProperlyPopulatedForWrites(t *testing.T) { orm := createObservedORM(t, 420) - require.NoError(t, withObservedExec(orm, "execQuery", func() error { return nil })) - require.Error(t, withObservedExec(orm, "execQuery", func() error { return fmt.Errorf("error") })) + require.NoError(t, withObservedExec(orm, "execQuery", create, func() error { return nil })) + require.Error(t, withObservedExec(orm, "execQuery", create, func() error { return fmt.Errorf("error") })) - require.Equal(t, 2, counterFromHistogramByLabels(t, orm.queryDuration, "420", "execQuery")) + require.Equal(t, 2, counterFromHistogramByLabels(t, orm.queryDuration, "420", "execQuery", "create")) +} + +func TestCountersAreProperlyPopulatedForWrites(t *testing.T) { + orm := createObservedORM(t, 420) + logs := generateRandomLogs(420, 20) + + // First insert 10 logs + require.NoError(t, orm.InsertLogs(logs[:10])) + assert.Equal(t, float64(10), testutil.ToFloat64(orm.logsInserted.WithLabelValues("420"))) + + // Insert 5 more logs with block + require.NoError(t, orm.InsertLogsWithBlock(logs[10:15], NewLogPollerBlock(utils.RandomBytes32(), 10, time.Now(), 5))) + assert.Equal(t, float64(15), testutil.ToFloat64(orm.logsInserted.WithLabelValues("420"))) + assert.Equal(t, float64(1), testutil.ToFloat64(orm.blocksInserted.WithLabelValues("420"))) + + // Insert 5 more logs with block + require.NoError(t, orm.InsertLogsWithBlock(logs[15:], NewLogPollerBlock(utils.RandomBytes32(), 15, time.Now(), 5))) + assert.Equal(t, float64(20), testutil.ToFloat64(orm.logsInserted.WithLabelValues("420"))) + assert.Equal(t, float64(2), testutil.ToFloat64(orm.blocksInserted.WithLabelValues("420"))) + + // Don't update counters in case of an error + require.Error(t, orm.InsertLogsWithBlock(logs, NewLogPollerBlock(utils.RandomBytes32(), 0, time.Now(), 0))) + assert.Equal(t, float64(20), testutil.ToFloat64(orm.logsInserted.WithLabelValues("420"))) + assert.Equal(t, float64(2), testutil.ToFloat64(orm.blocksInserted.WithLabelValues("420"))) +} + +func generateRandomLogs(chainId, count int) []Log { + logs := make([]Log, count) + for i := range logs { + logs[i] = Log{ + EvmChainId: utils.NewBigI(int64(chainId)), + LogIndex: int64(i + 1), + BlockHash: utils.RandomBytes32(), + BlockNumber: int64(i + 1), + BlockTimestamp: time.Now(), + Topics: [][]byte{}, + EventSig: utils.RandomBytes32(), + Address: utils.RandomAddress(), + TxHash: utils.RandomBytes32(), + Data: []byte{}, + CreatedAt: time.Now(), + } + } + return logs } func createObservedORM(t *testing.T, chainId int64) *ObservedORM { @@ -107,6 +153,8 @@ func createObservedORM(t *testing.T, chainId int64) *ObservedORM { func resetMetrics(lp ObservedORM) { lp.queryDuration.Reset() lp.datasetSize.Reset() + lp.logsInserted.Reset() + lp.blocksInserted.Reset() } func counterFromGaugeByLabels(gaugeVec *prometheus.GaugeVec, labels ...string) int { diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index c6134ed4b6..c24d423b25 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -48,9 +48,10 @@ type ORM interface { SelectIndexedLogsTopicGreaterThan(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) SelectIndexedLogsTopicRange(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) SelectIndexedLogsWithSigsExcluding(sigA, sigB common.Hash, topicIndex int, address common.Address, startBlock, endBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) - SelectIndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) + SelectIndexedLogsByTxHash(address common.Address, eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) SelectLogsDataWordRange(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) SelectLogsDataWordGreaterThan(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectLogsDataWordBetween(address common.Address, eventSig common.Hash, wordIndexMin int, wordIndexMax int, wordValue common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) } type DbORM struct { @@ -535,6 +536,32 @@ func (o *DbORM) SelectLogsDataWordGreaterThan(address common.Address, eventSig c return logs, nil } +func (o *DbORM) SelectLogsDataWordBetween(address common.Address, eventSig common.Hash, wordIndexMin int, wordIndexMax int, wordValue common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withWordIndexMin(wordIndexMin). + withWordIndexMax(wordIndexMax). + withWordValue(wordValue). + withConfs(confs). + toArgs() + if err != nil { + return nil, err + } + query := fmt.Sprintf(` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND substring(data from 32*:word_index_min+1 for 32) <= :word_value + AND substring(data from 32*:word_index_max+1 for 32) >= :word_value + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery(confs)) + var logs []Log + if err = o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { + return nil, err + } + return logs, nil +} + func (o *DbORM) SelectIndexedLogsTopicGreaterThan(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { args, err := newQueryArgsForEvent(o.chainID, address, eventSig). withTopicIndex(topicIndex). @@ -664,9 +691,10 @@ func (o *DbORM) SelectIndexedLogsCreatedAfter(address common.Address, eventSig c return logs, nil } -func (o *DbORM) SelectIndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { +func (o *DbORM) SelectIndexedLogsByTxHash(address common.Address, eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { args, err := newQueryArgs(o.chainID). withTxHash(txHash). + withAddress(address). withEventSig(eventSig). toArgs() if err != nil { @@ -676,8 +704,9 @@ func (o *DbORM) SelectIndexedLogsByTxHash(eventSig common.Hash, txHash common.Ha err = o.q.WithOpts(qopts...).SelectNamed(&logs, ` SELECT * FROM evm.logs WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig AND tx_hash = :tx_hash - AND event_sig = :event_sig ORDER BY (block_number, log_index)`, args) if err != nil { return nil, err diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index e55ebeccec..2a6ebb2c04 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -49,6 +50,21 @@ func GenLogWithTimestamp(chainID *big.Int, logIndex int64, blockNum int64, block } } +func GenLogWithData(chainID *big.Int, address common.Address, eventSig common.Hash, logIndex int64, blockNum int64, data []byte) logpoller.Log { + return logpoller.Log{ + EvmChainId: utils.NewBig(chainID), + LogIndex: logIndex, + BlockHash: utils.RandomBytes32(), + BlockNumber: blockNum, + EventSig: eventSig, + Topics: [][]byte{}, + Address: address, + TxHash: utils.RandomBytes32(), + Data: data, + BlockTimestamp: time.Now(), + } +} + func TestLogPoller_Batching(t *testing.T) { t.Parallel() th := SetupTH(t, false, 2, 3, 2, 1000) @@ -568,7 +584,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { } require.NoError(t, o1.InsertLogs(logs)) - retrievedLogs, err := o1.SelectIndexedLogsByTxHash(eventSig, txHash) + retrievedLogs, err := o1.SelectIndexedLogsByTxHash(addr, eventSig, txHash) require.NoError(t, err) require.Equal(t, 2, len(retrievedLogs)) @@ -1434,3 +1450,117 @@ func TestInsertLogsInTx(t *testing.T) { }) } } + +func TestSelectLogsDataWordBetween(t *testing.T) { + address := utils.RandomAddress() + eventSig := utils.RandomBytes32() + th := SetupTH(t, false, 2, 3, 2, 1000) + + firstLogData := make([]byte, 0, 64) + firstLogData = append(firstLogData, logpoller.EvmWord(1).Bytes()...) + firstLogData = append(firstLogData, logpoller.EvmWord(10).Bytes()...) + + secondLogData := make([]byte, 0, 64) + secondLogData = append(secondLogData, logpoller.EvmWord(5).Bytes()...) + secondLogData = append(secondLogData, logpoller.EvmWord(20).Bytes()...) + + err := th.ORM.InsertLogsWithBlock( + []logpoller.Log{ + GenLogWithData(th.ChainID, address, eventSig, 1, 1, firstLogData), + GenLogWithData(th.ChainID, address, eventSig, 2, 2, secondLogData), + }, + logpoller.NewLogPollerBlock(utils.RandomBytes32(), 10, time.Now(), 1), + ) + require.NoError(t, err) + + tests := []struct { + name string + wordValue uint64 + expectedLogs []int64 + }{ + { + name: "returns only first log", + wordValue: 2, + expectedLogs: []int64{1}, + }, + { + name: "returns only second log", + wordValue: 11, + expectedLogs: []int64{2}, + }, + { + name: "returns both logs if word value is between", + wordValue: 5, + expectedLogs: []int64{1, 2}, + }, + { + name: "returns no logs if word value is outside of the range", + wordValue: 21, + expectedLogs: []int64{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + logs, err1 := th.ORM.SelectLogsDataWordBetween(address, eventSig, 0, 1, logpoller.EvmWord(tt.wordValue), logpoller.Unconfirmed) + assert.NoError(t, err1) + assert.Len(t, logs, len(tt.expectedLogs)) + + for index := range logs { + assert.Equal(t, tt.expectedLogs[index], logs[index].BlockNumber) + } + }) + } +} + +func Benchmark_LogsDataWordBetween(b *testing.B) { + chainId := big.NewInt(137) + _, db := heavyweight.FullTestDBV2(b, nil) + o := logpoller.NewORM(chainId, db, logger.Test(b), pgtest.NewQConfig(false)) + + numberOfReports := 100_000 + numberOfMessagesPerReport := 256 + + commitStoreAddress := utils.RandomAddress() + commitReportAccepted := utils.RandomBytes32() + + var dbLogs []logpoller.Log + for i := 0; i < numberOfReports; i++ { + data := make([]byte, 64) + // MinSeqNr + data = append(data, logpoller.EvmWord(uint64(numberOfMessagesPerReport*i+1)).Bytes()...) + // MaxSeqNr + data = append(data, logpoller.EvmWord(uint64(numberOfMessagesPerReport*(i+1))).Bytes()...) + + dbLogs = append(dbLogs, logpoller.Log{ + EvmChainId: utils.NewBig(chainId), + LogIndex: int64(i + 1), + BlockHash: utils.RandomBytes32(), + BlockNumber: int64(i + 1), + BlockTimestamp: time.Now(), + EventSig: commitReportAccepted, + Topics: [][]byte{}, + Address: commitStoreAddress, + TxHash: utils.RandomAddress().Hash(), + Data: data, + CreatedAt: time.Now(), + }) + } + require.NoError(b, o.InsertBlock(utils.RandomAddress().Hash(), int64(numberOfReports*numberOfMessagesPerReport), time.Now(), int64(numberOfReports*numberOfMessagesPerReport))) + require.NoError(b, o.InsertLogs(dbLogs)) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + logs, err := o.SelectLogsDataWordBetween( + commitStoreAddress, + commitReportAccepted, + 2, + 3, + logpoller.EvmWord(uint64(numberOfReports*numberOfMessagesPerReport/2)), // Pick the middle report + logpoller.Unconfirmed, + ) + assert.NoError(b, err) + assert.Len(b, logs, 1) + } +} diff --git a/core/chains/evm/logpoller/query.go b/core/chains/evm/logpoller/query.go index 7443a860a8..b7fbfade68 100644 --- a/core/chains/evm/logpoller/query.go +++ b/core/chains/evm/logpoller/query.go @@ -82,6 +82,18 @@ func (q *queryArgs) withWordValueMax(wordValueMax common.Hash) *queryArgs { return q.withCustomHashArg("word_value_max", wordValueMax) } +func (q *queryArgs) withWordIndexMin(wordIndex int) *queryArgs { + return q.withCustomArg("word_index_min", wordIndex) +} + +func (q *queryArgs) withWordIndexMax(wordIndex int) *queryArgs { + return q.withCustomArg("word_index_max", wordIndex) +} + +func (q *queryArgs) withWordValue(wordValue common.Hash) *queryArgs { + return q.withCustomHashArg("word_value", wordValue) +} + func (q *queryArgs) withConfs(confs Confirmations) *queryArgs { return q.withCustomArg("confs", confs) } diff --git a/core/store/migrate/migrations/0211_log_poller_word_indexes.sql b/core/store/migrate/migrations/0211_log_poller_word_indexes.sql new file mode 100644 index 0000000000..3d2e8bf8a4 --- /dev/null +++ b/core/store/migrate/migrations/0211_log_poller_word_indexes.sql @@ -0,0 +1,6 @@ +-- +goose Up +CREATE INDEX evm_logs_idx_data_word_four ON evm.logs (substring(data from 97 for 32)); + + +-- +goose Down +DROP INDEX IF EXISTS evm.evm_logs_idx_data_word_four; From e4f6d9906cb1aa010827b913b23886ac11c68324 Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 29 Nov 2023 08:06:02 -0700 Subject: [PATCH 220/327] Only enforce ctf version on merge_group push to develop (#11389) * Only enforce ctf version on merge_group push to develop * add debug echo to see what was missed * Updated with refernences to merge_group payload instead of pull_request payload * use output and test that we can indeed do this in a fail situation so we can switch it back and know it will work for a true since we already validated that we do get true in the correct place * The test worked, flip back to enforcing only for merge groups to develop --- .github/workflows/integration-tests.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 5a505ce01c..dd696f7b2d 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -28,7 +28,23 @@ jobs: steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Check Merge Group Condition + id: condition-check + run: | + echo "Checking event condition..." + SHOULD_ENFORCE="false" + if [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then + echo "We are in a merge_group event, now check if we are on the develop branch" + target_branch=$(cat $GITHUB_EVENT_PATH | jq -r .merge_group.base_ref) + if [[ "$target_branch" == "refs/heads/develop" ]]; then + echo "We are on the develop branch, we should enforce ctf version" + SHOULD_ENFORCE="true" + fi + fi + echo "should we enforce ctf version = $SHOULD_ENFORCE" + echo "should-enforce=$SHOULD_ENFORCE" >> $GITHUB_OUTPUT - name: Enforce CTF Version + if: steps.condition-check.outputs.should-enforce == 'true' uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: go-project-path: ./integration-tests From 7e7b84bb1b8a03d17c9b4dd49932854b0ea36c11 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 29 Nov 2023 10:38:08 -0600 Subject: [PATCH 221/327] core/services/chainlink: skip P2P Peer Wrapper when unused (#11411) --- core/services/chainlink/application.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 1ecf95d3a5..3d06789e7b 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -360,7 +360,9 @@ func NewApplication(opts ApplicationOpts) (Application, error) { } var peerWrapper *ocrcommon.SingletonPeerWrapper - if cfg.P2P().Enabled() { + if !cfg.OCR().Enabled() && !cfg.OCR2().Enabled() { + globalLogger.Debug("P2P stack not needed") + } else if cfg.P2P().Enabled() { if err := ocrcommon.ValidatePeerWrapperConfig(cfg.P2P()); err != nil { return nil, err } From e546a7ee4fbe07a27198c644a906f7f199ea8e68 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:49:11 +0100 Subject: [PATCH 222/327] Update CleanupChainTables shell cmd to specify schema (#11409) * Update CleanupChainTables shell cmd to specify schema * Update testdb naming checks to match * Add test that checks if cleanup chain table shell cmd works * Fix shell cmd test db checks to match CI * Adjust CleanupChainTables test to handle heavyweight db testdb naming * Change CleanupChainTables to account for duplicate table names --- core/cmd/shell_local.go | 27 ++++++++++++++++++++------- core/cmd/shell_local_test.go | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index ada70736f4..dc0d44f318 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -996,23 +996,36 @@ func (s *Shell) CleanupChainTables(c *cli.Context) error { if err != nil { return s.errorOut(errors.Wrap(err, "error connecting to the database")) } - defer db.Close() - tablesToDeleteFromQuery := `SELECT table_name FROM information_schema.columns WHERE "column_name"=$1;` + // some tables with evm_chain_id (mostly job specs) are in public schema + tablesToDeleteFromQuery := `SELECT table_name, table_schema FROM information_schema.columns WHERE "column_name"=$1;` // Delete rows from each table based on the chain_id. if strings.EqualFold("EVM", c.String("type")) { - var tables []string - if err = db.Select(&tables, tablesToDeleteFromQuery, "evm_chain_id"); err != nil { + rows, err := db.Query(tablesToDeleteFromQuery, "evm_chain_id") + if err != nil { return err + } else if rows.Err() != nil { + return rows.Err() } - for _, tableName := range tables { + + var tablesToDeleteFrom []string + for rows.Next() { + var name string + var schema string + if err = rows.Scan(&name, &schema); err != nil { + return err + } + tablesToDeleteFrom = append(tablesToDeleteFrom, schema+"."+name) + } + + for _, tableName := range tablesToDeleteFrom { query := fmt.Sprintf(`DELETE FROM %s WHERE "evm_chain_id"=$1;`, tableName) _, err = db.Exec(query, c.String("id")) if err != nil { - fmt.Printf("Error deleting rows from %s: %v\n", tableName, err) + fmt.Printf("Error deleting rows containing evm_chain_id from %s: %v\n", tableName, err) } else { - fmt.Printf("Rows with chain_id %s deleted from %s.\n", c.String("id"), tableName) + fmt.Printf("Rows with evm_chain_id %s deleted from %s.\n", c.String("id"), tableName) } } } else { diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 1e030fa9e9..fac2d7f040 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -492,3 +492,23 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { }) } } + +func TestShell_CleanupChainTables(t *testing.T) { + // Just check if it doesn't error, command itself shouldn't be changed unless major schema changes were made. + // It would be really hard to write a test that accounts for schema changes, so this should be enough to alarm us that something broke. + config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres }) + client := cmd.Shell{ + Config: config, + Logger: logger.TestLogger(t), + } + + set := flag.NewFlagSet("test", 0) + flagSetApplyFromAction(client.CleanupChainTables, set, "") + require.NoError(t, set.Set("id", testutils.FixtureChainID.String())) + require.NoError(t, set.Set("type", "EVM")) + // heavyweight creates test db named chainlink_test_uid, while usual naming is chainlink_test + // CleanupChainTables handles test db name with chainlink_test, but because of heavyweight test db naming we have to set danger flag + require.NoError(t, set.Set("danger", "true")) + c := cli.NewContext(nil, set, nil) + require.NoError(t, client.CleanupChainTables(c)) +} From 3876d9e077734deb284ee48e21b4be19efd92e7c Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 29 Nov 2023 13:40:17 -0600 Subject: [PATCH 223/327] embed Solana & Feeds LOOPPs; adjust CI (#11401) --- .github/workflows/integration-tests.yml | 39 +++---------------- core/chainlink.Dockerfile | 20 ++++++++++ core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- integration-tests/docker/test_env/test_env.go | 7 ++-- .../docker/test_env/test_env_builder.go | 10 ++++- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 10 files changed, 45 insertions(+), 49 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index dd696f7b2d..9e2cce0212 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -781,7 +781,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: smartcontractkit/chainlink-solana - ref: 23816fcf7d380a30c87b6d87e4fb0ca94419b259 # swtich back to this after the next solana release${{ needs.get_solana_sha.outputs.sha }} + ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Build Test Image if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' uses: ./.github/actions/build-test-image @@ -794,7 +794,7 @@ jobs: - run: echo "this exists so we don't have to run anything else if the build is skipped" if: needs.changes.outputs.src == 'false' || needs.solana-test-image-exists.outputs.exists == 'true' - solana-smoke-tests-matrix: + solana-smoke-tests: if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: @@ -802,14 +802,7 @@ jobs: pull-requests: write id-token: write contents: read - strategy: - matrix: - image: - - name: (legacy) - tag-suffix: "" - - name: (plugins) - tag-suffix: -plugins - name: Solana Smoke Tests ${{ matrix.image.name }} + name: Solana Smoke Tests runs-on: ubuntu20.04-16cores-64GB needs: [ @@ -832,7 +825,7 @@ jobs: with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Solana Smoke Tests ${{ matrix.image.name }} + this-job-name: Solana Smoke Tests test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo @@ -875,7 +868,7 @@ jobs: with: test_command_to_run: export ENV_JOB_IMAGE=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} && make test_smoke cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }}${{ matrix.image.tag-suffix }} + cl_image_tag: ${{ github.sha }} artifacts_location: /home/runner/work/chainlink-solana/chainlink-solana/integration-tests/logs publish_check_name: Solana Smoke Test Results go_mod_path: ./integration-tests/go.mod @@ -894,25 +887,3 @@ jobs: path: /tmp/gotest.log retention-days: 7 continue-on-error: true - - ### Used to check the required checks box when the matrix completes - solana-smoke-tests: - if: always() - runs-on: ubuntu-latest - name: Solana Smoke Tests - needs: [solana-smoke-tests-matrix] - steps: - - name: Check smoke test matrix status - if: needs.solana-smoke-tests-matrix.result != 'success' - run: exit 1 - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Solana Smoke Tests - matrix-aggregator-status: ${{ needs.solana-smoke-tests-matrix.result }} - continue-on-error: true - ### End Solana Section diff --git a/core/chainlink.Dockerfile b/core/chainlink.Dockerfile index be1fdb9053..22e65c0aa7 100644 --- a/core/chainlink.Dockerfile +++ b/core/chainlink.Dockerfile @@ -17,6 +17,22 @@ COPY . . # Build the golang binary RUN make install-chainlink +# Link LOOP Plugin source dirs with simple names +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-feeds | xargs -I % ln -s % /chainlink-feeds +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana | xargs -I % ln -s % /chainlink-solana + +# Build image: Plugins +FROM golang:1.21-bullseye as buildplugins +RUN go version + +WORKDIR /chainlink-feeds +COPY --from=buildgo /chainlink-feeds . +RUN go install ./cmd/chainlink-feeds + +WORKDIR /chainlink-solana +COPY --from=buildgo /chainlink-solana . +RUN go install ./pkg/solana/cmd/chainlink-solana + # Final image: ubuntu with chainlink binary FROM ubuntu:20.04 @@ -32,6 +48,10 @@ RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ +# Install (but don't enable) LOOP Plugins +COPY --from=buildplugins /go/bin/chainlink-feeds /usr/local/bin/ +COPY --from=buildplugins /go/bin/chainlink-solana /usr/local/bin/ + # Dependency of CosmWasm/wasmd COPY --from=buildgo /go/pkg/mod/github.com/\!cosm\!wasm/wasmvm@v*/internal/api/libwasmvm.*.so /usr/lib/ RUN chmod 755 /usr/lib/libwasmvm.*.so diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 7fa6055b16..1eb186931f 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -307,7 +307,7 @@ require ( github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7706fa15f1..2a77f2066d 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1510,8 +1510,8 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a454 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= diff --git a/go.mod b/go.mod index 0133011813..c105c1c600 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 diff --git a/go.sum b/go.sum index 504f2ba807..18d78d4815 100644 --- a/go.sum +++ b/go.sum @@ -1513,8 +1513,8 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a454 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 6278ec1398..4b0cefddd5 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -151,15 +151,14 @@ func (te *CLClusterTestEnv) StartMockAdapter() error { return te.MockAdapter.StartContainer() } -func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count int, secretsConfig string) error { +func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count int, secretsConfig string, opts ...ClNodeOption) error { if te.Cfg != nil && te.Cfg.ClCluster != nil { te.ClCluster = te.Cfg.ClCluster } else { + opts = append(opts, WithSecrets(secretsConfig)) te.ClCluster = &ClCluster{} for i := 0; i < count; i++ { - ocrNode := NewClNode([]string{te.Network.Name}, os.Getenv("CHAINLINK_IMAGE"), os.Getenv("CHAINLINK_VERSION"), nodeConfig, - WithSecrets(secretsConfig), - ) + ocrNode := NewClNode([]string{te.Network.Name}, os.Getenv("CHAINLINK_IMAGE"), os.Getenv("CHAINLINK_VERSION"), nodeConfig, opts...) te.ClCluster.Nodes = append(te.ClCluster.Nodes, ocrNode) } } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 32f84991ee..685ea5338a 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -40,6 +40,7 @@ type CLTestEnvBuilder struct { secretsConfig string nonDevGethNetworks []blockchain.EVMNetwork clNodesCount int + clNodesOpts []func(*ClNode) customNodeCsaKeys []string defaultNodeCsaKeys []string l zerolog.Logger @@ -110,6 +111,11 @@ func (b *CLTestEnvBuilder) WithCLNodes(clNodesCount int) *CLTestEnvBuilder { return b } +func (b *CLTestEnvBuilder) WithCLNodeOptions(opt ...ClNodeOption) *CLTestEnvBuilder { + b.clNodesOpts = append(b.clNodesOpts, opt...) + return b +} + func (b *CLTestEnvBuilder) WithForwarders() *CLTestEnvBuilder { b.hasForwarders = true return b @@ -267,7 +273,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, fmt.Errorf("cannot create nodes with custom config without nonDevNetworks") } - err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig) + err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig, b.clNodesOpts...) if err != nil { return nil, err } @@ -351,7 +357,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } - err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig) + err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig, b.clNodesOpts...) if err != nil { return nil, err } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 63bf5e9e55..5f250af6fa 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -391,7 +391,7 @@ require ( github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index a1a272c0b8..855d97d5e4 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2382,8 +2382,8 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a454 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1 h1:D7yb4kgNGVAiD5lFYqm/LW8d5jU66TXyYvSskDiW9yg= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231117191230-aa6640f2edd1/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= github.com/smartcontractkit/chainlink-testing-framework v1.19.5 h1:Iq1L7wCA8IkBBtP3p6W2ttu8v9cJp95spusnozW1UrA= From f77100049fa4f39274763e1d0323041397c69ad7 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Wed, 29 Nov 2023 22:13:42 +0200 Subject: [PATCH 224/327] Change difficulty from Big to BigInt (#11388) * Change difficulty from Big to BigInt * Fix headtracker mock head * Remove EsnureClosed * Fix mock heads * Fix Tracker close on txm --- common/client/mock_head_test.go | 11 ++-- common/client/mock_node_test.go | 14 ++--- common/client/multi_node.go | 6 +- common/client/multi_node_test.go | 28 +++++----- common/client/node.go | 8 +-- common/client/node_fsm.go | 7 +-- common/client/node_lifecycle.go | 17 +++--- common/client/node_lifecycle_test.go | 55 ++++++++++--------- .../client/node_selector_total_difficulty.go | 4 +- .../node_selector_total_difficulty_test.go | 34 ++++++------ common/client/types.go | 3 +- common/fee/models.go | 2 +- common/headtracker/types/mocks/head.go | 14 ++--- common/txmgr/broadcaster.go | 2 +- common/txmgr/txmgr.go | 17 +++--- common/types/head.go | 5 +- common/types/mocks/head.go | 11 ++-- core/chains/evm/assets/wei.go | 2 +- core/chains/evm/client/erroring_node.go | 3 +- core/chains/evm/client/helpers_test.go | 3 +- core/chains/evm/client/node.go | 7 +-- core/chains/evm/client/node_fsm.go | 7 +-- core/chains/evm/client/node_lifecycle.go | 17 +++--- core/chains/evm/client/node_lifecycle_test.go | 25 ++++----- .../client/node_selector_total_difficulty.go | 6 +- .../node_selector_total_difficulty_test.go | 34 ++++++------ core/chains/evm/client/pool.go | 4 +- .../evm/client/simulated_backend_client.go | 2 +- core/chains/evm/gas/models.go | 2 +- core/chains/evm/mocks/node.go | 12 ++-- core/chains/evm/txmgr/transmitchecker.go | 3 +- core/chains/evm/types/models.go | 10 ++-- core/utils/big.go | 2 +- core/utils/utils.go | 11 ---- 34 files changed, 188 insertions(+), 200 deletions(-) diff --git a/common/client/mock_head_test.go b/common/client/mock_head_test.go index b9cf0a5866..1b69eedf43 100644 --- a/common/client/mock_head_test.go +++ b/common/client/mock_head_test.go @@ -3,7 +3,8 @@ package client import ( - utils "github.com/smartcontractkit/chainlink/v2/core/utils" + big "math/big" + mock "github.com/stretchr/testify/mock" ) @@ -13,15 +14,15 @@ type mockHead struct { } // BlockDifficulty provides a mock function with given fields: -func (_m *mockHead) BlockDifficulty() *utils.Big { +func (_m *mockHead) BlockDifficulty() *big.Int { ret := _m.Called() - var r0 *utils.Big - if rf, ok := ret.Get(0).(func() *utils.Big); ok { + var r0 *big.Int + if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*utils.Big) + r0 = ret.Get(0).(*big.Int) } } diff --git a/common/client/mock_node_test.go b/common/client/mock_node_test.go index bd704cd2c6..ea0e7d1a12 100644 --- a/common/client/mock_node_test.go +++ b/common/client/mock_node_test.go @@ -4,11 +4,11 @@ package client import ( context "context" + big "math/big" - types "github.com/smartcontractkit/chainlink/v2/common/types" mock "github.com/stretchr/testify/mock" - utils "github.com/smartcontractkit/chainlink/v2/core/utils" + types "github.com/smartcontractkit/chainlink/v2/common/types" ) // mockNode is an autogenerated mock type for the Node type @@ -115,13 +115,13 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) State() nodeState { } // StateAndLatest provides a mock function with given fields: -func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *utils.Big) { +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *big.Int) { 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 { + var r2 *big.Int + if rf, ok := ret.Get(0).(func() (nodeState, int64, *big.Int)); ok { return rf() } if rf, ok := ret.Get(0).(func() nodeState); ok { @@ -136,11 +136,11 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *ut r1 = ret.Get(1).(int64) } - if rf, ok := ret.Get(2).(func() *utils.Big); ok { + if rf, ok := ret.Get(2).(func() *big.Int); ok { r2 = rf() } else { if ret.Get(2) != nil { - r2 = ret.Get(2).(*utils.Big) + r2 = ret.Get(2).(*big.Int) } } diff --git a/common/client/multi_node.go b/common/client/multi_node.go index 3f72d04124..db5380e91f 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -14,11 +14,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/common/config" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -261,8 +261,8 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP // nLiveNodes returns the number of currently alive nodes, as well as the highest block number and greatest total difficulty. // totalDifficulty will be 0 if all nodes return nil. -func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) nLiveNodes() (nLiveNodes int, blockNumber int64, totalDifficulty *utils.Big) { - totalDifficulty = utils.NewBigI(0) +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) nLiveNodes() (nLiveNodes int, blockNumber int64, totalDifficulty *big.Int) { + totalDifficulty = big.NewInt(0) for _, n := range c.nodes { if s, num, td := n.StateAndLatest(); s == nodeStateAlive { nLiveNodes++ diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 45ffb74537..229f1320a1 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -2,6 +2,7 @@ package client import ( "fmt" + big "math/big" "math/rand" "testing" "time" @@ -17,14 +18,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) -type multiNodeRPCClient RPC[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, +type multiNodeRPCClient RPC[types.ID, *big.Int, 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, + *multiNode[types.ID, *big.Int, Hashable, Hashable, any, Hashable, any, any, types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable], multiNodeRPCClient] } @@ -46,19 +46,19 @@ func newTestMultiNode(t *testing.T, opts multiNodeOpts) testMultiNode { opts.logger = logger.Test(t) } - result := NewMultiNode[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, + result := NewMultiNode[types.ID, *big.Int, 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, + result.(*multiNode[types.ID, *big.Int, 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, +func newMultiNodeRPCClient(t *testing.T) *mockRPC[types.ID, *big.Int, 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, + return newMockRPC[types.ID, *big.Int, Hashable, Hashable, any, Hashable, any, any, types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable]](t) } @@ -424,40 +424,40 @@ func TestMultiNode_nLiveNodes(t *testing.T) { t.Parallel() type nodeParams struct { BlockNumber int64 - TotalDifficulty *utils.Big + TotalDifficulty *big.Int State nodeState } testCases := []struct { Name string ExpectedNLiveNodes int ExpectedBlockNumber int64 - ExpectedTotalDifficulty *utils.Big + ExpectedTotalDifficulty *big.Int NodeParams []nodeParams }{ { Name: "no nodes", - ExpectedTotalDifficulty: utils.NewBigI(0), + ExpectedTotalDifficulty: big.NewInt(0), }, { Name: "Best node is not healthy", - ExpectedTotalDifficulty: utils.NewBigI(10), + ExpectedTotalDifficulty: big.NewInt(10), ExpectedBlockNumber: 20, ExpectedNLiveNodes: 3, NodeParams: []nodeParams{ { State: nodeStateOutOfSync, BlockNumber: 1000, - TotalDifficulty: utils.NewBigI(2000), + TotalDifficulty: big.NewInt(2000), }, { State: nodeStateAlive, BlockNumber: 20, - TotalDifficulty: utils.NewBigI(9), + TotalDifficulty: big.NewInt(9), }, { State: nodeStateAlive, BlockNumber: 19, - TotalDifficulty: utils.NewBigI(10), + TotalDifficulty: big.NewInt(10), }, { State: nodeStateAlive, diff --git a/common/client/node.go b/common/client/node.go index b2d3a33a5b..4fad18b42c 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -3,6 +3,7 @@ package client import ( "context" "fmt" + "math/big" "net/url" "sync" "time" @@ -15,7 +16,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const QueryTimeout = 10 * time.Second @@ -53,7 +53,7 @@ type Node[ // State returns nodeState State() nodeState // StateAndLatest returns nodeState with the latest received block number & total difficulty. - StateAndLatest() (nodeState, int64, *utils.Big) + StateAndLatest() (nodeState, int64, *big.Int) // Name is a unique identifier for this node. Name() string String() string @@ -90,7 +90,7 @@ type node[ state nodeState // Each node is tracking the last received head number and total difficulty stateLatestBlockNumber int64 - stateLatestTotalDifficulty *utils.Big + stateLatestTotalDifficulty *big.Int // nodeCtx is the node lifetime's context nodeCtx context.Context @@ -103,7 +103,7 @@ type node[ // 1. see how many live nodes there are in total, so we can prevent the last alive node in a pool from being // moved to out-of-sync state. It is better to have one out-of-sync node than no nodes at all. // 2. compare against the highest head (by number or difficulty) to ensure we don't fall behind too far. - nLiveNodes func() (count int, blockNumber int64, totalDifficulty *utils.Big) + nLiveNodes func() (count int, blockNumber int64, totalDifficulty *big.Int) } func NewNode[ diff --git a/common/client/node_fsm.go b/common/client/node_fsm.go index d4fc19140e..74a5814f77 100644 --- a/common/client/node_fsm.go +++ b/common/client/node_fsm.go @@ -2,11 +2,10 @@ package client import ( "fmt" + "math/big" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -110,7 +109,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) State() nodeState { return n.state } -func (n *node[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *utils.Big) { +func (n *node[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *big.Int) { n.stateMu.RLock() defer n.stateMu.RUnlock() return n.state, n.stateLatestBlockNumber, n.stateLatestTotalDifficulty @@ -182,7 +181,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToInSync(fn func()) { // declareOutOfSync puts a node into OutOfSync state, disconnecting all current // clients and making it unavailable for use until back in-sync. -func (n *node[CHAIN_ID, HEAD, RPC]) declareOutOfSync(isOutOfSync func(num int64, td *utils.Big) bool) { +func (n *node[CHAIN_ID, HEAD, RPC]) declareOutOfSync(isOutOfSync func(num int64, td *big.Int) bool) { n.transitionToOutOfSync(func() { n.lfcLog.Errorw("RPC Node is out of sync", "nodeState", n.state) n.wg.Add(1) diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 9b47412766..59a59691c8 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math" + "math/big" "time" "github.com/pkg/errors" @@ -11,6 +12,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/logger" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -49,7 +52,7 @@ func zombieNodeCheckInterval(noNewHeadsThreshold time.Duration) time.Duration { return utils.WithJitter(interval) } -func (n *node[CHAIN_ID, HEAD, RPC]) setLatestReceived(blockNumber int64, totalDifficulty *utils.Big) { +func (n *node[CHAIN_ID, HEAD, RPC]) setLatestReceived(blockNumber int64, totalDifficulty *big.Int) { n.stateMu.Lock() defer n.stateMu.Unlock() n.stateLatestBlockNumber = blockNumber @@ -216,13 +219,13 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { continue } } - n.declareOutOfSync(func(num int64, td *utils.Big) bool { return num < highestReceivedBlockNumber }) + n.declareOutOfSync(func(num int64, td *big.Int) bool { return num < highestReceivedBlockNumber }) return } } } -func (n *node[CHAIN_ID, HEAD, RPC]) isOutOfSync(num int64, td *utils.Big) (outOfSync bool) { +func (n *node[CHAIN_ID, HEAD, RPC]) isOutOfSync(num int64, td *big.Int) (outOfSync bool) { outOfSync, _ = n.syncStatus(num, td) return } @@ -230,7 +233,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) isOutOfSync(num int64, td *utils.Big) (outOf // syncStatus returns outOfSync true if num or td is more than SyncThresold behind the best node. // Always returns outOfSync false for SyncThreshold 0. // liveNodes is only included when outOfSync is true. -func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *utils.Big) (outOfSync bool, liveNodes int) { +func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *big.Int) (outOfSync bool, liveNodes int) { if n.nLiveNodes == nil { return // skip for tests } @@ -245,8 +248,8 @@ func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *utils.Big) (outOfS case NodeSelectionModeHighestHead, NodeSelectionModeRoundRobin, NodeSelectionModePriorityLevel: return num < highest-int64(threshold), ln case NodeSelectionModeTotalDifficulty: - bigThreshold := utils.NewBigI(int64(threshold)) - return td.Cmp(greatest.Sub(bigThreshold)) < 0, ln + bigThreshold := big.NewInt(int64(threshold)) + return td.Cmp(bigmath.Sub(greatest, bigThreshold)) < 0, ln default: panic("unrecognized NodeSelectionMode: " + mode) } @@ -258,7 +261,7 @@ const ( ) // outOfSyncLoop takes an OutOfSync node and waits until isOutOfSync returns false to go back to live status -func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td *utils.Big) bool) { +func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { defer n.wg.Done() { diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index 51b44ac516..224b79d837 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -2,6 +2,7 @@ package client import ( "fmt" + big "math/big" "sync/atomic" "testing" @@ -12,11 +13,11 @@ import ( "go.uber.org/zap" "github.com/smartcontractkit/chainlink-common/pkg/logger" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/common/types/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { @@ -188,8 +189,8 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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) + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { + return 1, 20, big.NewInt(10) } pollError := errors.New("failed to get ClientVersion") rpc.On("ClientVersion", mock.Anything).Return("", pollError) @@ -213,8 +214,8 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { }) 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) + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { + return 10, syncThreshold + node.stateLatestBlockNumber + 1, big.NewInt(10) } rpc.On("ClientVersion", mock.Anything).Return("", nil) // tries to redial in outOfSync @@ -244,8 +245,8 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { }) 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) + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { + return 1, syncThreshold + node.stateLatestBlockNumber + 1, big.NewInt(10) } rpc.On("ClientVersion", mock.Anything).Return("", nil) node.declareAlive() @@ -266,8 +267,8 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { }) 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) + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { + return 1, node.stateLatestBlockNumber + 100, big.NewInt(10) } rpc.On("ClientVersion", mock.Anything).Return("", nil) node.declareAlive() @@ -310,8 +311,8 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { 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.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { + return 1, 20, big.NewInt(10) } node.declareAlive() tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState)) @@ -353,7 +354,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { sub.On("Err").Return((<-chan error)(nil)) sub.On("Unsubscribe").Once() expectedBlockNumber := rand.Int64() - expectedDiff := utils.NewBigI(rand.Int64()) + expectedDiff := big.NewInt(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}) @@ -367,14 +368,14 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { node.declareAlive() tests.AssertEventually(t, func() bool { state, block, diff := node.StateAndLatest() - return state == nodeStateAlive && block == expectedBlockNumber == diff.Equal(expectedDiff) + return state == nodeStateAlive && block == expectedBlockNumber == bigmath.Equal(diff, expectedDiff) }) }) } type head struct { BlockNumber int64 - BlockDifficulty *utils.Big + BlockDifficulty *big.Int } func writeHeads(t *testing.T, ch chan<- Head, heads ...head) { @@ -411,7 +412,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { return node } - stubIsOutOfSync := func(num int64, td *utils.Big) bool { + stubIsOutOfSync := func(num int64, td *big.Int) bool { return false } @@ -448,7 +449,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { }).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 { + node.declareOutOfSync(func(num int64, td *big.Int) bool { return true }) tests.AssertLogCountEventually(t, observedLogs, msgReceivedBlock, len(heads)) @@ -614,7 +615,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { setupRPCForAliveLoop(t, rpc) - node.declareOutOfSync(func(num int64, td *utils.Big) bool { + node.declareOutOfSync(func(num int64, td *big.Int) bool { return num < highestBlock }) tests.AssertLogEventually(t, observedLogs, msgReceivedBlock) @@ -635,8 +636,8 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { 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) + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { + return 0, 100, big.NewInt(200) } rpc.On("Dial", mock.Anything).Return(nil).Once() @@ -943,7 +944,7 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { }) 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) { + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { return } outOfSync, liveNodes := node.syncStatus(0, nil) @@ -954,7 +955,7 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { node := newTestNode(t, testNodeOpts{ config: testNodeConfig{syncThreshold: 1}, }) - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { return } assert.Panics(t, func() { @@ -1000,13 +1001,13 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { selectionMode: selectionMode, }, }) - node.nLiveNodes = func() (int, int64, *utils.Big) { - return nodesNum, highestBlock, utils.NewBigI(totalDifficulty) + node.nLiveNodes = func() (int, int64, *big.Int) { + return nodesNum, highestBlock, big.NewInt(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)) + outOfSync, liveNodes := node.syncStatus(testCase.blockNumber, big.NewInt(td)) assert.Equal(t, nodesNum, liveNodes) assert.Equal(t, testCase.outOfSync, outOfSync) }) @@ -1053,13 +1054,13 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { selectionMode: NodeSelectionModeTotalDifficulty, }, }) - node.nLiveNodes = func() (int, int64, *utils.Big) { - return nodesNum, highestBlock, utils.NewBigI(totalDifficulty) + node.nLiveNodes = func() (int, int64, *big.Int) { + return nodesNum, highestBlock, big.NewInt(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)) + outOfSync, liveNodes := node.syncStatus(hb, big.NewInt(testCase.totalDifficulty)) assert.Equal(t, nodesNum, liveNodes) assert.Equal(t, testCase.outOfSync, outOfSync) }) diff --git a/common/client/node_selector_total_difficulty.go b/common/client/node_selector_total_difficulty.go index 9b29642d03..35491503bc 100644 --- a/common/client/node_selector_total_difficulty.go +++ b/common/client/node_selector_total_difficulty.go @@ -1,7 +1,7 @@ package client import ( - "github.com/smartcontractkit/chainlink/v2/core/utils" + "math/big" "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -22,7 +22,7 @@ func NewTotalDifficultyNodeSelector[ func (s totalDifficultyNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { // NodeNoNewHeadsThreshold may not be enabled, in this case all nodes have td == nil - var highestTD *utils.Big + var highestTD *big.Int var nodes []Node[CHAIN_ID, HEAD, RPC] var aliveNodes []Node[CHAIN_ID, HEAD, RPC] diff --git a/common/client/node_selector_total_difficulty_test.go b/common/client/node_selector_total_difficulty_test.go index 4eecb859db..5c43cdd847 100644 --- a/common/client/node_selector_total_difficulty_test.go +++ b/common/client/node_selector_total_difficulty_test.go @@ -1,10 +1,10 @@ package client import ( + big "math/big" "testing" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" ) @@ -27,10 +27,10 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { 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)) + node.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(7)) } else { // third node is alive and best - node.On("StateAndLatest").Return(nodeStateAlive, int64(2), utils.NewBigI(8)) + node.On("StateAndLatest").Return(nodeStateAlive, int64(2), big.NewInt(8)) } node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -42,7 +42,7 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { 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("StateAndLatest").Return(nodeStateAlive, int64(2), big.NewInt(8)) node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -53,7 +53,7 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { 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("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(11)) node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -88,7 +88,7 @@ func TestTotalDifficultyNodeSelector_None(t *testing.T) { node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) } else { // others are unreachable - node.On("StateAndLatest").Return(nodeStateUnreachable, int64(1), utils.NewBigI(7)) + node.On("StateAndLatest").Return(nodeStateUnreachable, int64(1), big.NewInt(7)) } nodes = append(nodes, node) } @@ -106,7 +106,7 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { 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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(10)) node.On("Order").Return(int32(2)) nodes = append(nodes, node) } @@ -117,15 +117,15 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { 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("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(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("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(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("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(10)) node3.On("Order").Return(int32(2)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} @@ -136,15 +136,15 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { 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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(12)) node3.On("Order").Return(int32(3)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} @@ -155,19 +155,19 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { 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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(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("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(105)) node4.On("Order").Maybe().Return(int32(2)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3, node4} diff --git a/common/client/types.go b/common/client/types.go index 6d3a22cee7..32d4da98b5 100644 --- a/common/client/types.go +++ b/common/client/types.go @@ -7,7 +7,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // RPC includes all the necessary methods for a multi-node client to interact directly with any RPC endpoint. @@ -51,7 +50,7 @@ type RPC[ //go:generate mockery --quiet --name Head --structname mockHead --filename "mock_head_test.go" --inpackage --case=underscore type Head interface { BlockNumber() int64 - BlockDifficulty() *utils.Big + BlockDifficulty() *big.Int } // NodeClient includes all the necessary RPC methods required by a node. diff --git a/common/fee/models.go b/common/fee/models.go index 1fcb55c530..b843cc3f05 100644 --- a/common/fee/models.go +++ b/common/fee/models.go @@ -6,8 +6,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink/v2/common/chains/label" - bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) var ( diff --git a/common/headtracker/types/mocks/head.go b/common/headtracker/types/mocks/head.go index 1de1f78de8..79c483c997 100644 --- a/common/headtracker/types/mocks/head.go +++ b/common/headtracker/types/mocks/head.go @@ -3,13 +3,13 @@ package mocks import ( - time "time" + big "math/big" mock "github.com/stretchr/testify/mock" - types "github.com/smartcontractkit/chainlink/v2/common/types" + time "time" - utils "github.com/smartcontractkit/chainlink/v2/core/utils" + types "github.com/smartcontractkit/chainlink/v2/common/types" ) // Head is an autogenerated mock type for the Head type @@ -18,15 +18,15 @@ type Head[BLOCK_HASH types.Hashable, CHAIN_ID types.ID] struct { } // BlockDifficulty provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockDifficulty() *utils.Big { +func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockDifficulty() *big.Int { ret := _m.Called() - var r0 *utils.Big - if rf, ok := ret.Get(0).(func() *utils.Big); ok { + var r0 *big.Int + if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*utils.Big) + r0 = ret.Get(0).(*big.Int) } } diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index cff5746a9e..ab620c51be 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -247,7 +247,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) clos eb.initSync.Lock() defer eb.initSync.Unlock() if !eb.isStarted { - return errors.Wrap(utils.ErrAlreadyStopped, "Broadcaster is not started") + return errors.Wrap(services.ErrAlreadyStopped, "Broadcaster is not started") } close(eb.chStop) eb.wg.Wait() diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 3aac88e2f4..0a50bb6638 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -401,15 +401,18 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() // be in an Unstarted state here, if execReset exited early. // // In this case, we don't care about stopping them since they are - // already "stopped", hence the usage of utils.EnsureClosed. - if err := utils.EnsureClosed(b.broadcaster); err != nil { - b.logger.Panicw(fmt.Sprintf("Failed to Close Broadcaster: %v", err), "err", err) + // already "stopped". + err := b.broadcaster.Close() + if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) { + b.logger.Errorw(fmt.Sprintf("Failed to Close Broadcaster: %v", err), "err", err) } - if err := utils.EnsureClosed(b.confirmer); err != nil { - b.logger.Panicw(fmt.Sprintf("Failed to Close Confirmer: %v", err), "err", err) + err = b.confirmer.Close() + if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) { + b.logger.Errorw(fmt.Sprintf("Failed to Close Confirmer: %v", err), "err", err) } - if err := utils.EnsureClosed(b.tracker); err != nil { - b.logger.Panicw(fmt.Sprintf("Failed to Close Tracker: %v", err), "err", err) + err = b.tracker.Close() + if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) { + b.logger.Errorw(fmt.Sprintf("Failed to Close Tracker: %v", err), "err", err) } return case <-keysChanged: diff --git a/common/types/head.go b/common/types/head.go index 000bad2390..c363fd5d0f 100644 --- a/common/types/head.go +++ b/common/types/head.go @@ -1,9 +1,8 @@ package types import ( + "math/big" "time" - - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Head provides access to a chain's head, as needed by the TxManager. @@ -36,5 +35,5 @@ type Head[BLOCK_HASH Hashable] interface { // Returns the total difficulty of the block. For chains who do not have a concept of block // difficulty, return 0. - BlockDifficulty() *utils.Big + BlockDifficulty() *big.Int } diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index 82fd910a08..99d2a265b4 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -3,13 +3,12 @@ package mocks import ( + big "math/big" time "time" mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink/v2/common/types" - - utils "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Head is an autogenerated mock type for the Head type @@ -18,15 +17,15 @@ type Head[BLOCK_HASH types.Hashable] struct { } // BlockDifficulty provides a mock function with given fields: -func (_m *Head[BLOCK_HASH]) BlockDifficulty() *utils.Big { +func (_m *Head[BLOCK_HASH]) BlockDifficulty() *big.Int { ret := _m.Called() - var r0 *utils.Big - if rf, ok := ret.Get(0).(func() *utils.Big); ok { + var r0 *big.Int + if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*utils.Big) + r0 = ret.Get(0).(*big.Int) } } diff --git a/core/chains/evm/assets/wei.go b/core/chains/evm/assets/wei.go index 7d1240d384..be0143b3a8 100644 --- a/core/chains/evm/assets/wei.go +++ b/core/chains/evm/assets/wei.go @@ -10,8 +10,8 @@ import ( "github.com/shopspring/decimal" "golang.org/x/exp/constraints" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink/v2/core/utils" - bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) const ( diff --git a/core/chains/evm/client/erroring_node.go b/core/chains/evm/client/erroring_node.go index 21c4d269ea..c33891728a 100644 --- a/core/chains/evm/client/erroring_node.go +++ b/core/chains/evm/client/erroring_node.go @@ -5,7 +5,6 @@ import ( "math/big" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -132,7 +131,7 @@ func (e *erroringNode) State() NodeState { return NodeStateUnreachable } -func (e *erroringNode) StateAndLatest() (NodeState, int64, *utils.Big) { +func (e *erroringNode) StateAndLatest() (NodeState, int64, *big.Int) { return NodeStateUnreachable, -1, nil } diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index dce825f4f7..27b335534d 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -14,7 +14,6 @@ import ( commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type TestNodePoolConfig struct { @@ -45,7 +44,7 @@ func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeads lggr := logger.Test(t) n := NewNode(nodePoolCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-0", id, chainID, 1) - n.(*node).setLatestReceived(0, utils.NewBigI(0)) + n.(*node).setLatestReceived(0, big.NewInt(0)) primaries := []Node{n} var sendonlys []SendOnlyNode diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index e2da78b502..a2c8b807ba 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -24,7 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -93,7 +92,7 @@ type Node interface { // State returns NodeState State() NodeState // StateAndLatest returns NodeState with the latest received block number & total difficulty. - StateAndLatest() (state NodeState, blockNum int64, totalDifficulty *utils.Big) + StateAndLatest() (state NodeState, blockNum int64, totalDifficulty *big.Int) // Name is a unique identifier for this node. Name() string ChainID() *big.Int @@ -153,7 +152,7 @@ type node struct { state NodeState // Each node is tracking the last received head number and total difficulty stateLatestBlockNumber int64 - stateLatestTotalDifficulty *utils.Big + stateLatestTotalDifficulty *big.Int // Need to track subscriptions because closing the RPC does not (always?) // close the underlying subscription @@ -177,7 +176,7 @@ type node struct { // 1. see how many live nodes there are in total, so we can prevent the last alive node in a pool from being // moved to out-of-sync state. It is better to have one out-of-sync node than no nodes at all. // 2. compare against the highest head (by number or difficulty) to ensure we don't fall behind too far. - nLiveNodes func() (count int, blockNumber int64, totalDifficulty *utils.Big) + nLiveNodes func() (count int, blockNumber int64, totalDifficulty *big.Int) } // NewNode returns a new *node as Node diff --git a/core/chains/evm/client/node_fsm.go b/core/chains/evm/client/node_fsm.go index 10694eb7fc..c92af3b412 100644 --- a/core/chains/evm/client/node_fsm.go +++ b/core/chains/evm/client/node_fsm.go @@ -2,11 +2,10 @@ package client import ( "fmt" + "math/big" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -112,7 +111,7 @@ func (n *node) State() NodeState { return n.state } -func (n *node) StateAndLatest() (NodeState, int64, *utils.Big) { +func (n *node) StateAndLatest() (NodeState, int64, *big.Int) { n.stateMu.RLock() defer n.stateMu.RUnlock() return n.state, n.stateLatestBlockNumber, n.stateLatestTotalDifficulty @@ -184,7 +183,7 @@ func (n *node) transitionToInSync(fn func()) { // declareOutOfSync puts a node into OutOfSync state, disconnecting all current // clients and making it unavailable for use until back in-sync. -func (n *node) declareOutOfSync(isOutOfSync func(num int64, td *utils.Big) bool) { +func (n *node) declareOutOfSync(isOutOfSync func(num int64, td *big.Int) bool) { n.transitionToOutOfSync(func() { n.lfcLog.Errorw("RPC Node is out of sync", "nodeState", n.state) n.wg.Add(1) diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index 11d03d97dd..f838325a64 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math" + "math/big" "time" "github.com/pkg/errors" @@ -11,6 +12,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/logger" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -50,7 +53,7 @@ func zombieNodeCheckInterval(noNewHeadsThreshold time.Duration) time.Duration { return utils.WithJitter(interval) } -func (n *node) setLatestReceived(blockNumber int64, totalDifficulty *utils.Big) { +func (n *node) setLatestReceived(blockNumber int64, totalDifficulty *big.Int) { n.stateMu.Lock() defer n.stateMu.Unlock() n.stateLatestBlockNumber = blockNumber @@ -215,13 +218,13 @@ func (n *node) aliveLoop() { continue } } - n.declareOutOfSync(func(num int64, td *utils.Big) bool { return num < highestReceivedBlockNumber }) + n.declareOutOfSync(func(num int64, td *big.Int) bool { return num < highestReceivedBlockNumber }) return } } } -func (n *node) isOutOfSync(num int64, td *utils.Big) (outOfSync bool) { +func (n *node) isOutOfSync(num int64, td *big.Int) (outOfSync bool) { outOfSync, _ = n.syncStatus(num, td) return } @@ -229,7 +232,7 @@ func (n *node) isOutOfSync(num int64, td *utils.Big) (outOfSync bool) { // syncStatus returns outOfSync true if num or td is more than SyncThresold behind the best node. // Always returns outOfSync false for SyncThreshold 0. // liveNodes is only included when outOfSync is true. -func (n *node) syncStatus(num int64, td *utils.Big) (outOfSync bool, liveNodes int) { +func (n *node) syncStatus(num int64, td *big.Int) (outOfSync bool, liveNodes int) { if n.nLiveNodes == nil { return // skip for tests } @@ -244,8 +247,8 @@ func (n *node) syncStatus(num int64, td *utils.Big) (outOfSync bool, liveNodes i case NodeSelectionMode_HighestHead, NodeSelectionMode_RoundRobin, NodeSelectionMode_PriorityLevel: return num < highest-int64(threshold), ln case NodeSelectionMode_TotalDifficulty: - bigThreshold := utils.NewBigI(int64(threshold)) - return td.Cmp(greatest.Sub(bigThreshold)) < 0, ln + bigThreshold := big.NewInt(int64(threshold)) + return td.Cmp(bigmath.Sub(greatest, bigThreshold)) < 0, ln default: panic("unrecognized NodeSelectionMode: " + mode) } @@ -257,7 +260,7 @@ const ( ) // outOfSyncLoop takes an OutOfSync node and waits until isOutOfSync returns false to go back to live status -func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *utils.Big) bool) { +func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { defer n.wg.Done() { diff --git a/core/chains/evm/client/node_lifecycle_test.go b/core/chains/evm/client/node_lifecycle_test.go index 42f813cc2b..f097c2bc07 100644 --- a/core/chains/evm/client/node_lifecycle_test.go +++ b/core/chains/evm/client/node_lifecycle_test.go @@ -16,7 +16,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func standardHandler(method string, _ gjson.Result) (resp testutils.JSONRPCResponse) { @@ -161,7 +160,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { } return }) - n.nLiveNodes = func() (int, int64, *utils.Big) { return 1, 0, nil } + n.nLiveNodes = func() (int, int64, *big.Int) { return 1, 0, nil } dial(t, n) defer func() { assert.NoError(t, n.Close()) }() @@ -308,7 +307,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { iN := NewNode(pollDisabledCfg, testutils.TestInterval, lggr, *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) - n.nLiveNodes = func() (int, int64, *utils.Big) { return 1, 0, nil } + n.nLiveNodes = func() (int, int64, *big.Int) { return 1, 0, nil } dial(t, n) defer func() { assert.NoError(t, n.Close()) }() @@ -353,7 +352,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { iN := NewNode(cfg, 0*time.Second, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) - n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { return 2, highestHead.Load(), nil } @@ -415,7 +414,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { iN := NewNode(cfg, 0*time.Second, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) - n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { return 2, highestHead.Load(), nil } @@ -474,7 +473,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { iN := NewNode(cfg, 0*time.Second, lggr, *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) - n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { return 1, highestHead.Load(), nil } @@ -521,7 +520,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { n.wg.Add(1) go func() { defer close(ch) - n.outOfSyncLoop(func(num int64, td *utils.Big) bool { return false }) + n.outOfSyncLoop(func(num int64, td *big.Int) bool { return false }) }() assert.NoError(t, n.Close()) testutils.WaitWithTimeout(t, ch, "expected outOfSyncLoop to exit") @@ -536,7 +535,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { n.wg.Add(1) - n.outOfSyncLoop(func(num int64, td *utils.Big) bool { return num == 0 }) + n.outOfSyncLoop(func(num int64, td *big.Int) bool { return num == 0 }) assert.Equal(t, NodeStateUnreachable, n.State()) }) @@ -565,7 +564,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { defer func() { assert.NoError(t, n.Close()) }() n.wg.Add(1) - go n.outOfSyncLoop(func(num int64, td *utils.Big) bool { return num == 0 }) + go n.outOfSyncLoop(func(num int64, td *big.Int) bool { return num == 0 }) testutils.WaitWithTimeout(t, chSubbed, "timed out waiting for initial subscription") @@ -612,7 +611,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { defer func() { assert.NoError(t, n.Close()) }() n.wg.Add(1) - go n.outOfSyncLoop(func(num int64, td *utils.Big) bool { return num < 43 }) + go n.outOfSyncLoop(func(num int64, td *big.Int) bool { return num < 43 }) testutils.WaitWithTimeout(t, chSubbed, "timed out waiting for initial subscription") @@ -661,7 +660,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { iN := NewNode(cfg, time.Second*0, lggr, *s.WSURL(), nil, "test node", 0, testutils.FixtureChainID, 1) n := iN.(*node) - n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + n.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { return 2, stall + int64(cfg.SyncThreshold()), nil } @@ -717,14 +716,14 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { iN := NewNode(cfg, testutils.TestInterval, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) - n.nLiveNodes = func() (int, int64, *utils.Big) { return 0, 0, nil } + n.nLiveNodes = func() (int, int64, *big.Int) { return 0, 0, nil } dial(t, n) n.setState(NodeStateOutOfSync) defer func() { assert.NoError(t, n.Close()) }() n.wg.Add(1) - go n.outOfSyncLoop(func(num int64, td *utils.Big) bool { return num == 0 }) + go n.outOfSyncLoop(func(num int64, td *big.Int) bool { return num == 0 }) testutils.WaitWithTimeout(t, chSubbed, "timed out waiting for initial subscription") diff --git a/core/chains/evm/client/node_selector_total_difficulty.go b/core/chains/evm/client/node_selector_total_difficulty.go index 99a1c89dd4..27d888947d 100644 --- a/core/chains/evm/client/node_selector_total_difficulty.go +++ b/core/chains/evm/client/node_selector_total_difficulty.go @@ -1,8 +1,6 @@ package client -import ( - "github.com/smartcontractkit/chainlink/v2/core/utils" -) +import "math/big" type totalDifficultyNodeSelector []Node @@ -13,7 +11,7 @@ func NewTotalDifficultyNodeSelector(nodes []Node) NodeSelector { func (s totalDifficultyNodeSelector) Select() Node { // NodeNoNewHeadsThreshold may not be enabled, in this case all nodes have td == nil - var highestTD *utils.Big + var highestTD *big.Int var nodes []Node var aliveNodes []Node diff --git a/core/chains/evm/client/node_selector_total_difficulty_test.go b/core/chains/evm/client/node_selector_total_difficulty_test.go index d42a7461de..486a421477 100644 --- a/core/chains/evm/client/node_selector_total_difficulty_test.go +++ b/core/chains/evm/client/node_selector_total_difficulty_test.go @@ -1,11 +1,11 @@ package client_test import ( + "math/big" "testing" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" ) @@ -27,10 +27,10 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { node.On("StateAndLatest").Return(evmclient.NodeStateOutOfSync, int64(-1), nil) } else if i == 1 { // second node is alive - node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(7)) + node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(7)) } else { // third node is alive and best - node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(2), utils.NewBigI(8)) + node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(2), big.NewInt(8)) } node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -42,7 +42,7 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { t.Run("stick to the same node", func(t *testing.T) { node := evmmocks.NewNode(t) // fourth node is alive (same as 3rd) - node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(2), utils.NewBigI(8)) + node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(2), big.NewInt(8)) node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -53,7 +53,7 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { t.Run("another best node", func(t *testing.T) { node := evmmocks.NewNode(t) // fifth node is alive (better than 3rd and 4th) - node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), utils.NewBigI(11)) + node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), big.NewInt(11)) node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -87,7 +87,7 @@ func TestTotalDifficultyNodeSelector_None(t *testing.T) { node.On("StateAndLatest").Return(evmclient.NodeStateOutOfSync, int64(-1), nil) } else { // others are unreachable - node.On("StateAndLatest").Return(evmclient.NodeStateUnreachable, int64(1), utils.NewBigI(7)) + node.On("StateAndLatest").Return(evmclient.NodeStateUnreachable, int64(1), big.NewInt(7)) } nodes = append(nodes, node) } @@ -104,7 +104,7 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("same td and order", func(t *testing.T) { for i := 0; i < 3; i++ { node := evmmocks.NewNode(t) - node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(10)) + node.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(10)) node.On("Order").Return(int32(2)) nodes = append(nodes, node) } @@ -115,15 +115,15 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("same td but different order", func(t *testing.T) { node1 := evmmocks.NewNode(t) - node1.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), utils.NewBigI(10)) + node1.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), big.NewInt(10)) node1.On("Order").Return(int32(3)) node2 := evmmocks.NewNode(t) - node2.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), utils.NewBigI(10)) + node2.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), big.NewInt(10)) node2.On("Order").Return(int32(1)) node3 := evmmocks.NewNode(t) - node3.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), utils.NewBigI(10)) + node3.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(3), big.NewInt(10)) node3.On("Order").Return(int32(2)) nodes := []evmclient.Node{node1, node2, node3} @@ -134,15 +134,15 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("different td but same order", func(t *testing.T) { node1 := evmmocks.NewNode(t) - node1.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(10)) + node1.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(10)) node1.On("Order").Maybe().Return(int32(3)) node2 := evmmocks.NewNode(t) - node2.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(11)) + node2.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(11)) node2.On("Order").Maybe().Return(int32(3)) node3 := evmmocks.NewNode(t) - node3.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(12)) + node3.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(12)) node3.On("Order").Return(int32(3)) nodes := []evmclient.Node{node1, node2, node3} @@ -153,19 +153,19 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("different head and different order", func(t *testing.T) { node1 := evmmocks.NewNode(t) - node1.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(100)) + node1.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(100)) node1.On("Order").Maybe().Return(int32(4)) node2 := evmmocks.NewNode(t) - node2.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(110)) + node2.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(110)) node2.On("Order").Maybe().Return(int32(5)) node3 := evmmocks.NewNode(t) - node3.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(110)) + node3.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(110)) node3.On("Order").Maybe().Return(int32(1)) node4 := evmmocks.NewNode(t) - node4.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), utils.NewBigI(105)) + node4.On("StateAndLatest").Return(evmclient.NodeStateAlive, int64(1), big.NewInt(105)) node4.On("Order").Maybe().Return(int32(2)) nodes := []evmclient.Node{node1, node2, node3, node4} diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 9217f633dc..6c36cc3e98 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -178,8 +178,8 @@ func (p *Pool) Dial(ctx context.Context) error { // nLiveNodes returns the number of currently alive nodes, as well as the highest block number and greatest total difficulty. // totalDifficulty will be 0 if all nodes return nil. -func (p *Pool) nLiveNodes() (nLiveNodes int, blockNumber int64, totalDifficulty *utils.Big) { - totalDifficulty = utils.NewBigI(0) +func (p *Pool) nLiveNodes() (nLiveNodes int, blockNumber int64, totalDifficulty *big.Int) { + totalDifficulty = big.NewInt(0) for _, n := range p.nodes { if s, num, td := n.StateAndLatest(); s == NodeStateAlive { nLiveNodes++ diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 10b2aae502..293bf64bad 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -302,7 +302,7 @@ func (c *SimulatedBackendClient) SubscribeNewHead( case h := <-ch: var head *evmtypes.Head if h != nil { - 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)} + head = &evmtypes.Head{Difficulty: 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/gas/models.go b/core/chains/evm/gas/models.go index 4f9a541970..c7476d58ba 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) // EvmFeeEstimator provides a unified interface that wraps EvmEstimator and can determine if legacy or dynamic fee estimation should be used diff --git a/core/chains/evm/mocks/node.go b/core/chains/evm/mocks/node.go index 85db2e0ca0..69020d411f 100644 --- a/core/chains/evm/mocks/node.go +++ b/core/chains/evm/mocks/node.go @@ -19,8 +19,6 @@ import ( rpc "github.com/ethereum/go-ethereum/rpc" types "github.com/ethereum/go-ethereum/core/types" - - utils "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Node is an autogenerated mock type for the Node type @@ -519,13 +517,13 @@ func (_m *Node) State() client.NodeState { } // StateAndLatest provides a mock function with given fields: -func (_m *Node) StateAndLatest() (client.NodeState, int64, *utils.Big) { +func (_m *Node) StateAndLatest() (client.NodeState, int64, *big.Int) { ret := _m.Called() var r0 client.NodeState var r1 int64 - var r2 *utils.Big - if rf, ok := ret.Get(0).(func() (client.NodeState, int64, *utils.Big)); ok { + var r2 *big.Int + if rf, ok := ret.Get(0).(func() (client.NodeState, int64, *big.Int)); ok { return rf() } if rf, ok := ret.Get(0).(func() client.NodeState); ok { @@ -540,11 +538,11 @@ func (_m *Node) StateAndLatest() (client.NodeState, int64, *utils.Big) { r1 = ret.Get(1).(int64) } - if rf, ok := ret.Get(2).(func() *utils.Big); ok { + if rf, ok := ret.Get(2).(func() *big.Int); ok { r2 = rf() } else { if ret.Get(2) != nil { - r2 = ret.Get(2).(*utils.Big) + r2 = ret.Get(2).(*big.Int) } } diff --git a/core/chains/evm/txmgr/transmitchecker.go b/core/chains/evm/txmgr/transmitchecker.go index f210934adb..76dfcb9d51 100644 --- a/core/chains/evm/txmgr/transmitchecker.go +++ b/core/chains/evm/txmgr/transmitchecker.go @@ -12,6 +12,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" + "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -22,7 +24,6 @@ import ( v2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "github.com/smartcontractkit/chainlink/v2/core/utils" - bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) type ( diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 83b90b4d53..314180a7e9 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -39,8 +39,8 @@ type Head struct { ReceiptsRoot common.Hash TransactionsRoot common.Hash StateRoot common.Hash - Difficulty *utils.Big - TotalDifficulty *utils.Big + Difficulty *big.Int + TotalDifficulty *big.Int } var _ commontypes.Head[common.Hash] = &Head{} @@ -80,7 +80,7 @@ func (h *Head) GetTimestamp() time.Time { return h.Timestamp } -func (h *Head) BlockDifficulty() *utils.Big { +func (h *Head) BlockDifficulty() *big.Int { return h.Difficulty } @@ -283,8 +283,8 @@ func (h *Head) UnmarshalJSON(bs []byte) error { h.ReceiptsRoot = jsonHead.ReceiptsRoot h.TransactionsRoot = jsonHead.TransactionsRoot h.StateRoot = jsonHead.StateRoot - h.Difficulty = utils.NewBig(jsonHead.Difficulty.ToInt()) - h.TotalDifficulty = utils.NewBig(jsonHead.TotalDifficulty.ToInt()) + h.Difficulty = jsonHead.Difficulty.ToInt() + h.TotalDifficulty = jsonHead.TotalDifficulty.ToInt() return nil } diff --git a/core/utils/big.go b/core/utils/big.go index 22cd8e64e5..69fab223de 100644 --- a/core/utils/big.go +++ b/core/utils/big.go @@ -8,8 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" + bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" - bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) const base10 = 10 diff --git a/core/utils/utils.go b/core/utils/utils.go index 69597fb9e4..0df280775b 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -9,7 +9,6 @@ import ( "encoding/json" "errors" "fmt" - "io" "math" "math/big" mrand "math/rand" @@ -771,16 +770,6 @@ var ( // Deprecated: use services.StateMachine type StartStopOnce = services.StateMachine -// EnsureClosed closes the io.Closer, returning nil if it was already -// closed or not started yet -func EnsureClosed(c io.Closer) error { - err := c.Close() - if errors.Is(err, ErrAlreadyStopped) || errors.Is(err, ErrCannotStopUnstarted) { - return nil - } - return err -} - // WithJitter adds +/- 10% to a duration func WithJitter(d time.Duration) time.Duration { // #nosec From c36340ca688ba991a2433171f870d6146eecc528 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 29 Nov 2023 14:18:50 -0600 Subject: [PATCH 225/327] core/chains/evm/txmgr: nil check errs before wrapping (#11412) --- core/chains/evm/txmgr/evm_tx_store.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 51c9f98e88..e36ca611e1 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -567,7 +567,10 @@ func (o *evmTxStore) GetFatalTransactions(ctx context.Context) (txes []*Tx, err txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) - return fmt.Errorf("failed to load evm.tx_attempts: %w", err) + if err != nil { + return fmt.Errorf("failed to load evm.tx_attempts: %w", err) + } + return nil }, pg.OptReadOnlyTx()) return txes, nil @@ -1277,7 +1280,10 @@ func (o *evmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big.I txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) - return fmt.Errorf("failed to load evm.txes: %w", err) + if err != nil { + return fmt.Errorf("failed to load evm.txes: %w", err) + } + return nil }, pg.OptReadOnlyTx()) return txes, nil @@ -1302,7 +1308,10 @@ func (o *evmTxStore) GetTxByID(ctx context.Context, id int64) (txe *Tx, err erro } txe = txes[0] err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) - return fmt.Errorf("failed to load evm.tx_attempts: %w", err) + if err != nil { + return fmt.Errorf("failed to load evm.tx_attempts: %w", err) + } + return nil }, pg.OptReadOnlyTx()) return txe, nil From 80054164e663b3f7418829bcae3b7401a678da87 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 29 Nov 2023 14:31:39 -0600 Subject: [PATCH 226/327] .github/workflows: notify slack for ci-core develop failues (#11408) --- .github/workflows/ci-core.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index e69fc64cc7..fd8dfed88a 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -29,7 +29,7 @@ jobs: gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} - name: Notify Slack - if: ${{ failure() && github.event.schedule != '' }} + if: ${{ failure() && (github.event_name == 'merge_group' || github.event.branch == 'develop')}} uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} @@ -107,7 +107,7 @@ jobs: ./coverage.txt ./postgres_logs.txt - name: Notify Slack - if: ${{ failure() && matrix.cmd == 'go_core_race_tests' && github.event.schedule != '' }} + if: ${{ failure() && matrix.cmd == 'go_core_race_tests' && (github.event_name == 'merge_group' || github.event.branch == 'develop') }} uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} From b8199c52e22c0c1a875713e0d01df21466a91567 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Wed, 29 Nov 2023 23:54:32 +0200 Subject: [PATCH 227/327] Add PendingSequenceAt to fix txm test case (#11416) * Add PendingSequenceAt nonce * Fix return values --- core/chains/evm/txmgr/txmgr_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index f82bc991d5..524c85b108 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -519,8 +519,8 @@ func TestTxm_Reset(t *testing.T) { cfg := evmtest.NewChainScopedConfig(t, gcfg) kst := cltest.NewKeyStore(t, db, cfg.Database()) - _, addr := cltest.RandomKey{Nonce: 5}.MustInsert(t, kst.Eth()) - _, addr2 := cltest.RandomKey{Nonce: 3}.MustInsert(t, kst.Eth()) + _, addr := cltest.RandomKey{}.MustInsert(t, kst.Eth()) + _, addr2 := cltest.RandomKey{}.MustInsert(t, kst.Eth()) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) // 4 confirmed tx from addr1 for i := int64(0); i < 4; i++ { @@ -534,6 +534,8 @@ func TestTxm_Reset(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil) ethClient.On("BatchCallContextAll", mock.Anything, mock.Anything).Return(nil).Maybe() + ethClient.On("PendingSequenceAt", mock.Anything, addr).Return(128, nil).Maybe() + ethClient.On("PendingSequenceAt", mock.Anything, addr2).Return(44, nil).Maybe() estimator := gas.NewEstimator(logger.Test(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), cfg.Database(), cfg.Database().Listener(), kst.Eth()) From 7e83c3477860130531486c877b89ce857bbb05cb Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 29 Nov 2023 20:06:46 -0600 Subject: [PATCH 228/327] core/chains/evm/txmgr: fix TestTxm_Reset mocks (#11420) --- core/chains/evm/txmgr/broadcaster_test.go | 1 + core/chains/evm/txmgr/txmgr_test.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 93b1093e79..26e78344b9 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -161,6 +161,7 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) // Instance starts without error even if loading next sequence map fails err := eb.Start(testutils.Context(t)) require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, eb.Close()) }) } func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 524c85b108..745623ed77 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -534,8 +534,8 @@ func TestTxm_Reset(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil) ethClient.On("BatchCallContextAll", mock.Anything, mock.Anything).Return(nil).Maybe() - ethClient.On("PendingSequenceAt", mock.Anything, addr).Return(128, nil).Maybe() - ethClient.On("PendingSequenceAt", mock.Anything, addr2).Return(44, nil).Maybe() + ethClient.On("PendingNonceAt", mock.Anything, addr).Return(uint64(128), nil).Maybe() + ethClient.On("PendingNonceAt", mock.Anything, addr2).Return(uint64(44), nil).Maybe() estimator := gas.NewEstimator(logger.Test(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), cfg.Database(), cfg.Database().Listener(), kst.Eth()) From cee0df125ba105d97d2d3ba99d51ac0ce16fef86 Mon Sep 17 00:00:00 2001 From: Andrei Smirnov Date: Thu, 30 Nov 2023 10:43:12 +0300 Subject: [PATCH 229/327] Gateway client script: added readme and json pretty print (#11361) * Gateway client script: added readme and json pretty print * Reading S4 payload from the file --- core/scripts/gateway/client/README.md | 20 ++++++++++++++++++ core/scripts/gateway/client/send_request.go | 23 +++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 core/scripts/gateway/client/README.md diff --git a/core/scripts/gateway/client/README.md b/core/scripts/gateway/client/README.md new file mode 100644 index 0000000000..8c257753e6 --- /dev/null +++ b/core/scripts/gateway/client/README.md @@ -0,0 +1,20 @@ +# A gateway client script + +This script is used to connect to a gateway server and send commands to it. + +## Usage + +All requests have to be signed on behalf of a user, you need to provide your private key in .env file, e.g. + +``` +PRIVATE_KEY=1a2b3c... +``` + +The script will automatically sign the message using the provided private key. +Run the script without arguments to get the list of available commands. + +## Example + +``` +go run . -gateway_url https://01.functions-gateway.chain.link -don_id fun-avalanche-mainnet-2 -method secrets_list -message_id 123 +``` diff --git a/core/scripts/gateway/client/send_request.go b/core/scripts/gateway/client/send_request.go index 94ff6fb17d..8ab4e8bce7 100644 --- a/core/scripts/gateway/client/send_request.go +++ b/core/scripts/gateway/client/send_request.go @@ -28,7 +28,7 @@ func main() { s4SetSlotId := flag.Uint("s4_set_slot_id", 0, "S4 set slot ID") s4SetVersion := flag.Uint64("s4_set_version", 0, "S4 set version") s4SetExpirationPeriod := flag.Int64("s4_set_expiration_period", 60*60*1000, "S4 how long until the entry expires from now (in milliseconds)") - s4SetPayload := flag.String("s4_set_payload", "", "S4 set payload") + s4SetPayloadFile := flag.String("s4_set_payload_file", "", "S4 payload file to set secret") repeat := flag.Bool("repeat", false, "Repeat sending the request every 10 seconds") flag.Parse() @@ -50,6 +50,16 @@ func main() { } address := crypto.PubkeyToAddress(key.PublicKey) + var s4SetPayload []byte + if *methodName == functions.MethodSecretsSet { + var err error + s4SetPayload, err = os.ReadFile(*s4SetPayloadFile) + if err != nil { + fmt.Println("error reading S4 payload file", err) + return + } + } + // build payload (if relevant) var payloadJSON []byte if *methodName == functions.MethodSecretsSet { @@ -57,7 +67,7 @@ func main() { Address: address.Bytes(), SlotID: *s4SetSlotId, Version: *s4SetVersion, - Payload: []byte(*s4SetPayload), + Payload: s4SetPayload, Expiration: time.Now().UnixMilli() + *s4SetExpirationPeriod, } signature, err := envelope.Sign(key) @@ -70,7 +80,7 @@ func main() { SlotID: envelope.SlotID, Version: envelope.Version, Expiration: envelope.Expiration, - Payload: []byte(*s4SetPayload), + Payload: s4SetPayload, Signature: signature, } @@ -131,7 +141,12 @@ func main() { return } - fmt.Println(string(body)) + var prettyJSON bytes.Buffer + if err := json.Indent(&prettyJSON, body, "", " "); err != nil { + fmt.Println(string(body)) + } else { + fmt.Println(prettyJSON.String()) + } } sendRequest() From 0ae82791595dd02675f18cedb23e18cedee6fe5f Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 30 Nov 2023 09:07:58 +0000 Subject: [PATCH 230/327] [BCF-2779] Better formatting of the generic plugin config (#11406) --- core/services/ocr2/delegate.go | 41 +++++++++++------- core/services/ocr2/validate/validate.go | 37 +++++++++++++--- core/services/ocr2/validate/validate_test.go | 44 +++++++++++++++++++- plugins/medianpoc/plugin.go | 14 +++++-- plugins/medianpoc/plugin_test.go | 2 +- 5 files changed, 109 insertions(+), 29 deletions(-) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index eebc95903e..af56c1e7a9 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -525,29 +525,33 @@ func (d *Delegate) newServicesGenericPlugin( ) (srvs []job.ServiceCtx, err error) { spec := jb.OCR2OracleSpec + // NOTE: we don't need to validate this config, since that happens as part of creating the job. + // See: validate/validate.go's `validateSpec`. p := validate.OCR2GenericPluginConfig{} err = json.Unmarshal(spec.PluginConfig.Bytes(), &p) if err != nil { return nil, err } - cconf := p.CoreConfig - command := cconf.Command + command := p.Command if command == "" { - command = defaultPathFromPluginName(cconf.PluginName) + command = defaultPathFromPluginName(p.PluginName) } - // NOTE: we don't need to validate this config, since that happens as part of creating the job. - // See: validate/validate.go's `validateSpec`. + // Add the default pipeline to the pluginConfig + p.Pipelines = append( + p.Pipelines, + validate.PipelineSpec{Name: "__DEFAULT_PIPELINE__", Spec: jb.Pipeline.Source}, + ) rid, err := spec.RelayID() if err != nil { - return nil, ErrJobSpecNoRelayer{PluginName: cconf.PluginName, Err: err} + return nil, ErrJobSpecNoRelayer{PluginName: p.PluginName, Err: err} } relayer, err := d.RelayGetter.Get(rid) if err != nil { - return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: p.CoreConfig.PluginName} + return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: p.PluginName} } provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{ @@ -556,7 +560,7 @@ func (d *Delegate) newServicesGenericPlugin( ContractID: spec.ContractID, New: d.isNewlyCreatedJob, RelayConfig: spec.RelayConfig.Bytes(), - ProviderType: cconf.ProviderType, + ProviderType: p.ProviderType, }, types.PluginArgs{ TransmitterID: spec.TransmitterID.String, PluginConfig: spec.PluginConfig.Bytes(), @@ -570,7 +574,7 @@ func (d *Delegate) newServicesGenericPlugin( rid.Network, rid.ChainID, spec.ContractID, - synchronization.TelemetryType(cconf.TelemetryType), + synchronization.TelemetryType(p.TelemetryType), ) oracleArgs := libocr2.OCR2OracleArgs{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, @@ -586,8 +590,8 @@ func (d *Delegate) newServicesGenericPlugin( OffchainConfigDigester: provider.OffchainConfigDigester(), } - pluginLggr := lggr.Named(cconf.PluginName).Named(spec.ContractID).Named(spec.GetID()) - cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(fmt.Sprintf("%s-%s-%s", cconf.PluginName, spec.ContractID, spec.GetID()), command) + pluginLggr := lggr.Named(p.PluginName).Named(spec.ContractID).Named(spec.GetID()) + cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(fmt.Sprintf("%s-%s-%s", p.PluginName, spec.ContractID, spec.GetID()), command) if err != nil { return nil, fmt.Errorf("failed to register loop: %w", err) } @@ -604,7 +608,7 @@ func (d *Delegate) newServicesGenericPlugin( //TODO: remove this workaround when the EVM relayer is running inside of an LOOPP d.lggr.Info("provider is not a LOOPP provider, switching to provider server") - ps, err2 := relay.NewProviderServer(provider, types.OCR2PluginType(cconf.ProviderType), d.lggr) + ps, err2 := relay.NewProviderServer(provider, types.OCR2PluginType(p.ProviderType), d.lggr) if err2 != nil { return nil, fmt.Errorf("cannot start EVM provider server: %s", err) } @@ -615,12 +619,17 @@ func (d *Delegate) newServicesGenericPlugin( srvs = append(srvs, ps) } + pc, err := json.Marshal(p.Config) + if err != nil { + return nil, fmt.Errorf("cannot dump plugin config to string before sending to plugin: %s", err) + } + pluginConfig := types.ReportingPluginServiceConfig{ - PluginName: cconf.PluginName, + PluginName: p.PluginName, Command: command, - ProviderType: cconf.ProviderType, - TelemetryType: cconf.TelemetryType, - PluginConfig: p.PluginConfig, + ProviderType: p.ProviderType, + TelemetryType: p.TelemetryType, + PluginConfig: string(pc), } pr := generic.NewPipelineRunnerAdapter(pluginLggr, jb, d.pipelineRunner) diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index c97d23dca0..bb9bb03a8a 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -125,16 +125,42 @@ func validateSpec(tree *toml.Tree, spec job.Job) error { return nil } -type coreConfig struct { +type PipelineSpec struct { + Name string `json:"name"` + Spec string `json:"spec"` +} + +type Config struct { + Pipelines []PipelineSpec `json:"pipelines"` + PluginConfig map[string]any `json:"pluginConfig"` +} + +type innerConfig struct { Command string `json:"command"` ProviderType string `json:"providerType"` PluginName string `json:"pluginName"` TelemetryType string `json:"telemetryType"` + Config } type OCR2GenericPluginConfig struct { - CoreConfig coreConfig `json:"coreConfig"` - PluginConfig string + innerConfig +} + +func (o *OCR2GenericPluginConfig) UnmarshalJSON(data []byte) error { + err := json.Unmarshal(data, &o.innerConfig) + if err != nil { + return nil + } + + m := map[string]any{} + err = json.Unmarshal(data, &m) + if err != nil { + return err + } + + o.PluginConfig = m + return nil } func validateOCR2GenericPluginSpec(jsonConfig job.JSONConfig) error { @@ -144,12 +170,11 @@ func validateOCR2GenericPluginSpec(jsonConfig job.JSONConfig) error { return err } - cc := p.CoreConfig - if cc.PluginName == "" { + if p.PluginName == "" { return errors.New("generic config invalid: must provide plugin name") } - if cc.TelemetryType == "" { + if p.TelemetryType == "" { return errors.New("generic config invalid: must provide telemetry type") } diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index 5b40224a4b..b03f08f6b0 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/manyminds/api2go/jsonapi" + "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -627,7 +628,7 @@ transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" [relayConfig] chainID = 4 -[pluginConfig.coreConfig] +[pluginConfig] pluginName = "median" `, assertion: func(t *testing.T, os job.Job, err error) { @@ -655,7 +656,7 @@ transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" [relayConfig] chainID = 4 -[pluginConfig.coreConfig] +[pluginConfig] pluginName = "median" telemetryType = "median" `, @@ -678,3 +679,42 @@ telemetryType = "median" }) } } + +type envelope struct { + PluginConfig *validate.OCR2GenericPluginConfig +} + +func TestOCR2GenericPluginConfig_Unmarshal(t *testing.T) { + payload := ` +[pluginConfig] +pluginName = "median" +telemetryType = "median" +foo = "bar" + +[[pluginConfig.pipelines]] +name = "default" +spec = "a spec" +` + tree, err := toml.Load(payload) + require.NoError(t, err) + + // Load the toml how we load it in the plugin, i.e. convert to + // map[string]any first, then treat as JSON + o := map[string]any{} + err = tree.Unmarshal(&o) + require.NoError(t, err) + + b, err := json.Marshal(o) + require.NoError(t, err) + + e := &envelope{} + err = json.Unmarshal(b, e) + require.NoError(t, err) + + pc := e.PluginConfig + assert.Equal(t, "bar", pc.PluginConfig["foo"]) + assert.Len(t, pc.Pipelines, 1) + assert.Equal(t, validate.PipelineSpec{Name: "default", Spec: "a spec"}, pc.Pipelines[0]) + assert.Equal(t, "median", pc.PluginName) + assert.Equal(t, "median", pc.TelemetryType) +} diff --git a/plugins/medianpoc/plugin.go b/plugins/medianpoc/plugin.go index af4ec41ab8..fdf409b588 100644 --- a/plugins/medianpoc/plugin.go +++ b/plugins/medianpoc/plugin.go @@ -30,8 +30,13 @@ type Plugin struct { reportingplugins.MedianProviderServer } +type pipelineSpec struct { + Name string `json:"name"` + Spec string `json:"spec"` +} + type jsonConfig struct { - Pipelines map[string]string `json:"pipelines"` + Pipelines []pipelineSpec `json:"pipelines"` } func (j jsonConfig) defaultPipeline() (string, error) { @@ -39,9 +44,10 @@ func (j jsonConfig) defaultPipeline() (string, error) { } func (j jsonConfig) getPipeline(key string) (string, error) { - v, ok := j.Pipelines[key] - if ok { - return v, nil + for _, v := range j.Pipelines { + if v.Name == key { + return v.Spec, nil + } } return "", fmt.Errorf("no pipeline found for %s", key) } diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go index bc6af7ae5d..0d6c0360e4 100644 --- a/plugins/medianpoc/plugin_test.go +++ b/plugins/medianpoc/plugin_test.go @@ -80,7 +80,7 @@ func TestNewPlugin(t *testing.T) { juelsPerFeeCoinSpec := "jpfc-spec" config := types.ReportingPluginServiceConfig{ PluginConfig: fmt.Sprintf( - `{"pipelines": {"__DEFAULT_PIPELINE__": "%s", "juelsPerFeeCoinPipeline": "%s"}}`, + `{"pipelines": [{"name": "__DEFAULT_PIPELINE__", "spec": "%s"},{"name": "juelsPerFeeCoinPipeline", "spec": "%s"}]}`, defaultSpec, juelsPerFeeCoinSpec, ), From 3a58f94dc6586df60eae5754d457e1f712180501 Mon Sep 17 00:00:00 2001 From: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:50:01 +0000 Subject: [PATCH 231/327] Add VRFOwner contract support to VRF V2 Super Script (#11414) * Deploy VRFOwner contract and transfer ownership of coordinator * Minor changes * Execute vrfOwner.SetAuthorizedSenders for all sending keys --------- Co-authored-by: Ilja Pavlovs --- core/scripts/common/arbitrum.go | 7 ++- .../vrfv2/testnet/v2scripts/super_scripts.go | 55 +++++++++++++++++-- core/scripts/vrfv2/testnet/v2scripts/util.go | 1 - 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/core/scripts/common/arbitrum.go b/core/scripts/common/arbitrum.go index a3a2a24fcd..251f9b7609 100644 --- a/core/scripts/common/arbitrum.go +++ b/core/scripts/common/arbitrum.go @@ -1,12 +1,13 @@ package common const ( - ArbitrumGoerliChainID int64 = 421613 - ArbitrumOneChainID int64 = 42161 + ArbitrumGoerliChainID int64 = 421613 + ArbitrumOneChainID int64 = 42161 + ArbitrumSepoliaChainID int64 = 421614 ) // IsArbitrumChainID returns true if and only if the given chain ID corresponds // to an Arbitrum chain (testnet or mainnet). func IsArbitrumChainID(chainID int64) bool { - return chainID == ArbitrumGoerliChainID || chainID == ArbitrumOneChainID + return chainID == ArbitrumGoerliChainID || chainID == ArbitrumOneChainID || chainID == ArbitrumSepoliaChainID } diff --git a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index b623ae6308..4a1c1fcec4 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -19,9 +19,11 @@ import ( "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" + evmtypes "github.com/ethereum/go-ethereum/core/types" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" ) @@ -50,6 +52,8 @@ func DeployUniverseViaCLI(e helpers.Environment) { batchFulfillmentEnabled := deployCmd.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") + deployVRFOwner := deployCmd.Bool("deploy-vrf-owner", false, "whether to deploy VRF owner contracts") + // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", constants.FallbackWeiPerUnitLink.String(), "fallback wei/link ratio") registerVRFKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") @@ -98,10 +102,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { nodesMap := make(map[string]model.Node) - fundingAmount, ok := new(big.Int).SetString(*nodeSendingKeyFundingAmount, 10) - if !ok { - panic(fmt.Sprintf("failed to parse node sending key funding amount '%s'", *nodeSendingKeyFundingAmount)) - } + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() nodesMap[model.VRFPrimaryNodeName] = model.Node{ SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), SendingKeyFundingAmount: fundingAmount, @@ -143,6 +144,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { coordinatorConfig, *batchFulfillmentEnabled, nodesMap, + *deployVRFOwner, ) vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] @@ -160,6 +162,7 @@ func VRFV2DeployUniverse( coordinatorConfig CoordinatorConfigV2, batchFulfillmentEnabled bool, nodesMap map[string]model.Node, + deployVRFOwner bool, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash @@ -216,6 +219,15 @@ func VRFV2DeployUniverse( coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(contractAddresses.CoordinatorAddress, e.Ec) helpers.PanicErr(err) + var vrfOwnerAddress common.Address + if deployVRFOwner { + var tx *evmtypes.Transaction + fmt.Printf("\nDeploying VRF Owner for coordinator %v\n", contractAddresses.CoordinatorAddress) + vrfOwnerAddress, tx, _, err = vrf_owner.DeployVRFOwner(e.Owner, e.Ec, contractAddresses.CoordinatorAddress) + helpers.PanicErr(err) + helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) + } + if contractAddresses.BatchCoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { fmt.Println("\nDeploying Batch Coordinator...") contractAddresses.BatchCoordinatorAddress = DeployBatchCoordinatorV2(e, contractAddresses.CoordinatorAddress) @@ -273,6 +285,28 @@ func VRFV2DeployUniverse( helpers.PanicErr(err) fmt.Printf("Subscription %+v\n", s) + if deployVRFOwner { + // VRF Owner + vrfOwner, err := vrf_owner.NewVRFOwner(vrfOwnerAddress, e.Ec) + helpers.PanicErr(err) + var authorizedSendersSlice []common.Address + for _, s := range nodesMap[model.VRFPrimaryNodeName].SendingKeys { + authorizedSendersSlice = append(authorizedSendersSlice, common.HexToAddress(s.Address)) + } + fmt.Printf("\nSetting authorised senders for VRF Owner: %v, Authorised senders %v\n", vrfOwnerAddress.String(), authorizedSendersSlice) + tx, err := vrfOwner.SetAuthorizedSenders(e.Owner, authorizedSendersSlice) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "vrf owner set authorized senders") + fmt.Printf("\nTransfering ownership of coordinator: %v, VRF Owner %v\n", contractAddresses.CoordinatorAddress, vrfOwnerAddress.String()) + tx, err = coordinator.TransferOwnership(e.Owner, vrfOwnerAddress) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "transfer ownership to", vrfOwnerAddress.String()) + fmt.Printf("\nAccepting ownership of coordinator: %v, VRF Owner %v\n", contractAddresses.CoordinatorAddress, vrfOwnerAddress.String()) + tx, err = vrfOwner.AcceptVRFOwnership(e.Owner) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "vrf owner accepting vrf ownership") + } + formattedVrfPrimaryJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress @@ -293,6 +327,12 @@ func VRFV2DeployUniverse( contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) + if deployVRFOwner { + formattedVrfPrimaryJobSpec = strings.Replace(formattedVrfPrimaryJobSpec, + "minIncomingConfirmations", + fmt.Sprintf("vrfOwnerAddress = \"%s\"\nminIncomingConfirmations", vrfOwnerAddress.Hex()), + 1) + } formattedVrfBackupJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, @@ -314,6 +354,12 @@ func VRFV2DeployUniverse( contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) + if deployVRFOwner { + formattedVrfBackupJobSpec = strings.Replace(formattedVrfBackupJobSpec, + "minIncomingConfirmations", + fmt.Sprintf("vrfOwnerAddress = \"%s\"\nminIncomingConfirmations", vrfOwnerAddress.Hex()), + 1) + } formattedBHSJobSpec := fmt.Sprintf( jobs.BHSJobFormatted, @@ -353,6 +399,7 @@ func VRFV2DeployUniverse( "\nVRF Coordinator Address:", contractAddresses.CoordinatorAddress, "\nBatch VRF Coordinator Address:", contractAddresses.BatchCoordinatorAddress, "\nVRF Consumer Address:", consumerAddress, + "\nVRF Owner Address:", vrfOwnerAddress, "\nVRF Subscription Id:", subID, "\nVRF Subscription Balance:", *subscriptionBalanceJuels, "\nPossible VRF Request command: ", diff --git a/core/scripts/vrfv2/testnet/v2scripts/util.go b/core/scripts/vrfv2/testnet/v2scripts/util.go index 0e348e9c01..94e381378b 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/util.go +++ b/core/scripts/vrfv2/testnet/v2scripts/util.go @@ -89,7 +89,6 @@ func EoaFundSubscription(e helpers.Environment, coordinator vrf_coordinator_v2.V fmt.Println("Initial account balance:", bal, e.Owner.From.String(), "Funding amount:", amount.String()) b, err := utils.ABIEncode(`[{"type":"uint64"}]`, subID) helpers.PanicErr(err) - e.Owner.GasLimit = 500000 tx, err := linkToken.TransferAndCall(e.Owner, coordinator.Address(), amount, b) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("sub ID: %d", subID)) From 44659b1e8a0ad2b221f60f3934e147fe428a640c Mon Sep 17 00:00:00 2001 From: Sergey Kudasov Date: Thu, 30 Nov 2023 15:52:20 +0300 Subject: [PATCH 232/327] RE-2081 All core metrics dashboard for CRIB (#11396) * complete core metrics * all core metrics * go mod tidy * revert go mod * extend wasp dashboard for load tests * run OCRv1 on devspace (#11417) * run OCRv1 on devspace * fix go.mod * fix goimports * remove external charts * dynamic nodes connection in config * try the same replaces from integration-tests * fix go.sum --- charts/chainlink-cluster/README.md | 19 +- charts/chainlink-cluster/connect.toml | 12 + .../dashboard/cmd/dashboard_deploy.go | 13 +- .../chainlink-cluster/dashboard/dashboard.go | 672 +++++- charts/chainlink-cluster/devspace.yaml | 8 +- charts/chainlink-cluster/go.mod | 177 +- charts/chainlink-cluster/go.sum | 2116 ++++++++++++++++- .../templates/chainlink-cm.yaml | 12 +- .../templates/chainlink-service.yaml | 2 +- .../templates/mockserver-service.yaml | 14 + .../templates/mockserver.yaml | 3 +- charts/chainlink-cluster/values-raw-helm.yaml | 19 +- integration-tests/go.mod | 2 +- integration-tests/k8s/connect.go | 103 + integration-tests/load/ocr/README.md | 28 + integration-tests/load/ocr/config.go | 72 + integration-tests/load/ocr/config.toml | 20 + integration-tests/load/ocr/gun.go | 55 + integration-tests/load/ocr/helper.go | 68 + integration-tests/load/ocr/ocr_test.go | 71 + integration-tests/load/ocr/vu.go | 128 + 21 files changed, 3555 insertions(+), 59 deletions(-) create mode 100644 charts/chainlink-cluster/connect.toml create mode 100644 charts/chainlink-cluster/templates/mockserver-service.yaml create mode 100644 integration-tests/k8s/connect.go create mode 100644 integration-tests/load/ocr/README.md create mode 100644 integration-tests/load/ocr/config.go create mode 100644 integration-tests/load/ocr/config.toml create mode 100644 integration-tests/load/ocr/gun.go create mode 100644 integration-tests/load/ocr/helper.go create mode 100644 integration-tests/load/ocr/ocr_test.go create mode 100644 integration-tests/load/ocr/vu.go diff --git a/charts/chainlink-cluster/README.md b/charts/chainlink-cluster/README.md index 46c337dc72..e3cec129a9 100644 --- a/charts/chainlink-cluster/README.md +++ b/charts/chainlink-cluster/README.md @@ -55,10 +55,8 @@ Destroy the cluster devspace purge ``` -If you need to run some system level tests inside k8s use `runner` profile: -``` -devspace dev -p runner -``` +## Running load tests +Check this [doc](../../integration-tests/load/ocr/README.md) If you used `devspace dev ...` always use `devspace reset pods` to switch the pods back @@ -66,8 +64,6 @@ If you used `devspace dev ...` always use `devspace reset pods` to switch the po If you need to debug CL node that is already deployed change `dev.app.container` and `dev.app.labelSelector` in [devspace.yaml](devspace.yaml) if they are not default and run: ``` devspace dev -p node -or -devspace dev -p runner ``` ## Automatic file sync @@ -85,7 +81,7 @@ helm install -f values-raw-helm.yaml cl-cluster . ``` Forward all apps (in another terminal) ``` -sudo kubefwd svc +sudo kubefwd svc -n cl-cluster ``` Then you can connect and run your tests @@ -126,14 +122,9 @@ export GRAFANA_URL=... export GRAFANA_TOKEN=... export LOKI_DATA_SOURCE_NAME=Loki export PROMETHEUS_DATA_SOURCE_NAME=Thanos -export DASHBOARD_FOLDER=CLClusterEphemeralDevspace +export DASHBOARD_FOLDER=CRIB export DASHBOARD_NAME=ChainlinkCluster cd dashboard/cmd && go run dashboard_deploy.go ``` -Open Grafana folder `CLClusterEphemeralDevspace` and find dashboard `ChainlinkCluster` - -If you'd like to add more metrics or verify that all of them are added you can have the full list using IDE search or `ripgrep`: -``` -rg -U ".*promauto.*\n.*Name: \"(.*)\"" ../.. > metrics.txt -``` \ No newline at end of file +Open Grafana folder `CRIB` and find dashboard `ChainlinkCluster` \ No newline at end of file diff --git a/charts/chainlink-cluster/connect.toml b/charts/chainlink-cluster/connect.toml new file mode 100644 index 0000000000..f0a74d4c14 --- /dev/null +++ b/charts/chainlink-cluster/connect.toml @@ -0,0 +1,12 @@ +namespace = "cl-cluster" +network_name = "geth" +network_chain_id = 1337 +network_private_key = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +network_ws_url = "ws://geth:8546" +network_http_url = "http://geth:8544" +cl_nodes_num = 6 +cl_node_url_template = "http://app-node-%d:6688" +cl_node_internal_dns_record_template = "app-node-%d" +cl_node_user = "notreal@fakeemail.ch" +cl_node_password = "fj293fbBnlQ!f9vNs" +mockserver_url = "http://app-mockserver:1080" \ No newline at end of file diff --git a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go index 170ffa0288..93619fe614 100644 --- a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go +++ b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go @@ -1,14 +1,13 @@ package main import ( - "context" "os" "github.com/smartcontractkit/chainlink/v2/dashboard/dashboard" + "github.com/smartcontractkit/wasp" ) func main() { - ctx := context.Background() name := os.Getenv("DASHBOARD_NAME") if name == "" { panic("DASHBOARD_NAME must be provided") @@ -17,6 +16,7 @@ func main() { if ldsn == "" { panic("DATA_SOURCE_NAME must be provided") } + os.Setenv("DATA_SOURCE_NAME", ldsn) pdsn := os.Getenv("PROMETHEUS_DATA_SOURCE_NAME") if ldsn == "" { panic("DATA_SOURCE_NAME must be provided") @@ -34,11 +34,16 @@ func main() { panic("GRAFANA_TOKEN must be provided") } // if you'll use this dashboard base in other projects, you can add your own opts here to extend it - db, err := dashboard.NewCLClusterDashboard(name, ldsn, pdsn, dbf, grafanaURL, grafanaToken, nil) + db, err := dashboard.NewCLClusterDashboard(6, name, ldsn, pdsn, dbf, grafanaURL, grafanaToken, nil) if err != nil { panic(err) } - if err := db.Deploy(ctx); err != nil { + // here we are extending load testing dashboard with core metrics, for example + wdb, err := wasp.NewDashboard(nil, db.Opts()) + if err != nil { + panic(err) + } + if _, err := wdb.Deploy(); err != nil { panic(err) } } diff --git a/charts/chainlink-cluster/dashboard/dashboard.go b/charts/chainlink-cluster/dashboard/dashboard.go index 293cded2b0..b29140c040 100644 --- a/charts/chainlink-cluster/dashboard/dashboard.go +++ b/charts/chainlink-cluster/dashboard/dashboard.go @@ -13,11 +13,178 @@ import ( "github.com/K-Phoen/grabana/target/prometheus" "github.com/K-Phoen/grabana/timeseries" "github.com/K-Phoen/grabana/timeseries/axis" - "github.com/K-Phoen/grabana/variable/interval" "github.com/K-Phoen/grabana/variable/query" "github.com/pkg/errors" ) +/* +Use ripgrep to get the full list +rg -oU ".*promauto.*\n.*Name: \"(.*)\"" -r '$1' > metrics.txt + +duplicates? + +common/client/node.go:pool_rpc_node_verifies +common/client/node.go:pool_rpc_node_verifies_failed +common/client/node.go:pool_rpc_node_verifies_success +common/client/node_fsm.go:pool_rpc_node_num_transitions_to_alive +common/client/node_fsm.go:pool_rpc_node_num_transitions_to_in_sync +common/client/node_fsm.go:pool_rpc_node_num_transitions_to_out_of_sync +common/client/node_fsm.go:pool_rpc_node_num_transitions_to_unreachable +common/client/node_fsm.go:pool_rpc_node_num_transitions_to_invalid_chain_id +common/client/node_fsm.go:pool_rpc_node_num_transitions_to_unusable +common/client/node_lifecycle.go:pool_rpc_node_highest_seen_block +common/client/node_lifecycle.go:pool_rpc_node_num_seen_blocks +common/client/node_lifecycle.go:pool_rpc_node_polls_total +common/client/node_lifecycle.go:pool_rpc_node_polls_failed +common/client/node_lifecycle.go:pool_rpc_node_polls_success + +covered + +core/logger/prometheus.go:log_warn_count +core/logger/prometheus.go:log_error_count +core/logger/prometheus.go:log_critical_count +core/logger/prometheus.go:log_panic_count +core/logger/prometheus.go:log_fatal_count +common/client/multi_node.go:multi_node_states +common/txmgr/broadcaster.go:tx_manager_time_until_tx_broadcast +common/txmgr/confirmer.go:tx_manager_num_gas_bumps +common/txmgr/confirmer.go:tx_manager_gas_bump_exceeds_limit +common/txmgr/confirmer.go:tx_manager_num_confirmed_transactions +common/txmgr/confirmer.go:tx_manager_num_successful_transactions +common/txmgr/confirmer.go:tx_manager_num_tx_reverted +common/txmgr/confirmer.go:tx_manager_fwd_tx_count +common/txmgr/confirmer.go:tx_manager_tx_attempt_count +common/txmgr/confirmer.go:tx_manager_time_until_tx_confirmed +common/txmgr/confirmer.go:tx_manager_blocks_until_tx_confirmed +common/headtracker/head_tracker.go:head_tracker_current_head +common/headtracker/head_tracker.go:head_tracker_very_old_head +common/headtracker/head_listener.go:head_tracker_heads_received +common/headtracker/head_listener.go:head_tracker_connection_errors +core/chains/evm/client/node_fsm.go:evm_pool_rpc_node_num_transitions_to_alive +core/chains/evm/client/node_fsm.go:evm_pool_rpc_node_num_transitions_to_in_sync +core/chains/evm/client/node_fsm.go:evm_pool_rpc_node_num_transitions_to_out_of_sync +core/chains/evm/client/node_fsm.go:evm_pool_rpc_node_num_transitions_to_unreachable +core/chains/evm/client/node_fsm.go:evm_pool_rpc_node_num_transitions_to_invalid_chain_id +core/chains/evm/client/node_fsm.go:evm_pool_rpc_node_num_transitions_to_unusable +core/services/promreporter/prom_reporter.go:unconfirmed_transactions +core/services/promreporter/prom_reporter.go:max_unconfirmed_tx_age +core/services/promreporter/prom_reporter.go:max_unconfirmed_blocks +core/services/promreporter/prom_reporter.go:pipeline_runs_queued +core/services/promreporter/prom_reporter.go:pipeline_task_runs_queued +core/services/pipeline/task.bridge.go:bridge_latency_seconds +core/services/pipeline/task.bridge.go:bridge_errors_total +core/services/pipeline/task.bridge.go:bridge_cache_hits_total +core/services/pipeline/task.bridge.go:bridge_cache_errors_total +core/services/pipeline/task.http.go:pipeline_task_http_fetch_time +core/services/pipeline/task.http.go:pipeline_task_http_response_body_size +core/services/pipeline/task.eth_call.go:pipeline_task_eth_call_execution_time +core/services/pipeline/runner.go:pipeline_task_execution_time +core/services/pipeline/runner.go:pipeline_run_errors +core/services/pipeline/runner.go:pipeline_run_total_time_to_completion +core/services/pipeline/runner.go:pipeline_tasks_total_finished +core/chains/evm/client/node.go:evm_pool_rpc_node_dials_total +core/chains/evm/client/node.go:evm_pool_rpc_node_dials_failed +core/chains/evm/client/node.go:evm_pool_rpc_node_dials_success +core/chains/evm/client/node.go:evm_pool_rpc_node_verifies +core/chains/evm/client/node.go:evm_pool_rpc_node_verifies_failed +core/chains/evm/client/node.go:evm_pool_rpc_node_verifies_success +core/chains/evm/client/node.go:evm_pool_rpc_node_calls_total +core/chains/evm/client/node.go:evm_pool_rpc_node_calls_failed +core/chains/evm/client/node.go:evm_pool_rpc_node_calls_success +core/chains/evm/client/node.go:evm_pool_rpc_node_rpc_call_time +core/chains/evm/client/pool.go:evm_pool_rpc_node_states +core/utils/mailbox_prom.go:mailbox_load_percent +core/services/pg/stats.go:db_conns_max +core/services/pg/stats.go:db_conns_open +core/services/pg/stats.go:db_conns_used +core/services/pg/stats.go:db_wait_count +core/services/pg/stats.go:db_wait_time_seconds +core/chains/evm/client/node_lifecycle.go:evm_pool_rpc_node_highest_seen_block +core/chains/evm/client/node_lifecycle.go:evm_pool_rpc_node_num_seen_blocks +core/chains/evm/client/node_lifecycle.go:evm_pool_rpc_node_polls_total +core/chains/evm/client/node_lifecycle.go:evm_pool_rpc_node_polls_failed +core/chains/evm/client/node_lifecycle.go:evm_pool_rpc_node_polls_success +core/services/relay/evm/config_poller.go:ocr2_failed_rpc_contract_calls +core/services/feeds/service.go:feeds_job_proposal_requests +core/services/feeds/service.go:feeds_job_proposal_count +core/services/ocrcommon/prom.go:bridge_json_parse_values +core/services/ocrcommon/prom.go:ocr_median_values +core/chains/evm/logpoller/observability.go:log_poller_query_dataset_size + +not-covered and product specific (definitions/usage should be moved to plugins) + +mercury + +core/services/relay/evm/mercury/types/types.go:mercury_price_feed_missing +core/services/relay/evm/mercury/types/types.go:mercury_price_feed_errors +core/services/relay/evm/mercury/queue.go:mercury_transmit_queue_load +core/services/relay/evm/mercury/v1/data_source.go:mercury_insufficient_blocks_count +core/services/relay/evm/mercury/v1/data_source.go:mercury_zero_blocks_count +core/services/relay/evm/mercury/wsrpc/client.go:mercury_transmit_timeout_count +core/services/relay/evm/mercury/wsrpc/client.go:mercury_dial_count +core/services/relay/evm/mercury/wsrpc/client.go:mercury_dial_success_count +core/services/relay/evm/mercury/wsrpc/client.go:mercury_dial_error_count +core/services/relay/evm/mercury/wsrpc/client.go:mercury_connection_reset_count +core/services/relay/evm/mercury/transmitter.go:mercury_transmit_success_count +core/services/relay/evm/mercury/transmitter.go:mercury_transmit_duplicate_count +core/services/relay/evm/mercury/transmitter.go:mercury_transmit_connection_error_count +core/services/relay/evm/mercury/transmitter.go:mercury_transmit_queue_delete_error_count +core/services/relay/evm/mercury/transmitter.go:mercury_transmit_queue_insert_error_count +core/services/relay/evm/mercury/transmitter.go:mercury_transmit_queue_push_error_count +core/services/relay/evm/mercury/transmitter.go:mercury_transmit_server_error_count + +functions + +core/services/gateway/connectionmanager.go:gateway_heartbeats_sent +core/services/gateway/gateway.go:gateway_request +core/services/gateway/handlers/functions/handler.functions.go:gateway_functions_handler_error +core/services/gateway/handlers/functions/handler.functions.go:gateway_functions_secrets_set_success +core/services/gateway/handlers/functions/handler.functions.go:gateway_functions_secrets_set_failure +core/services/gateway/handlers/functions/handler.functions.go:gateway_functions_secrets_list_success +core/services/gateway/handlers/functions/handler.functions.go:gateway_functions_secrets_list_failure +core/services/functions/external_adapter_client.go:functions_external_adapter_client_latency +core/services/functions/external_adapter_client.go:functions_external_adapter_client_errors_total +core/services/functions/listener.go:functions_request_received +core/services/functions/listener.go:functions_request_internal_error +core/services/functions/listener.go:functions_request_computation_error +core/services/functions/listener.go:functions_request_computation_success +core/services/functions/listener.go:functions_request_timeout +core/services/functions/listener.go:functions_request_confirmed +core/services/functions/listener.go:functions_request_computation_result_size +core/services/functions/listener.go:functions_request_computation_error_size +core/services/functions/listener.go:functions_request_computation_duration +core/services/functions/listener.go:functions_request_pruned +core/services/ocr2/plugins/functions/reporting.go:functions_reporting_plugin_restarts +core/services/ocr2/plugins/functions/reporting.go:functions_reporting_plugin_query +core/services/ocr2/plugins/functions/reporting.go:functions_reporting_plugin_observation +core/services/ocr2/plugins/functions/reporting.go:functions_reporting_plugin_report +core/services/ocr2/plugins/functions/reporting.go:functions_reporting_plugin_report_num_observations +core/services/ocr2/plugins/functions/reporting.go:functions_reporting_plugin_accept +core/services/ocr2/plugins/functions/reporting.go:functions_reporting_plugin_transmit +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_query +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_observation +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_report +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_accept +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_query_byte_size +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_query_rows_count +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_observation_rows_count +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_report_rows_count +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_wrong_sig_count +core/services/ocr2/plugins/s4/prometheus.go:s4_reporting_plugin_expired_rows + +vrf + +core/services/vrf/vrfcommon/metrics.go:vrf_request_queue_size +core/services/vrf/vrfcommon/metrics.go:vrf_processed_request_count +core/services/vrf/vrfcommon/metrics.go:vrf_dropped_request_count +core/services/vrf/vrfcommon/metrics.go:vrf_duplicate_requests +core/services/vrf/vrfcommon/metrics.go:vrf_request_time_between_sims +core/services/vrf/vrfcommon/metrics.go:vrf_request_time_until_initial_sim + +keeper +core/services/keeper/upkeep_executer.go:keeper_check_upkeep_execution_time +*/ + const ( ErrFailedToCreateDashboard = "failed to create dashboard" ErrFailedToCreateFolder = "failed to create folder" @@ -25,6 +192,7 @@ const ( // CLClusterDashboard is a dashboard for a Chainlink cluster type CLClusterDashboard struct { + Nodes int Name string LokiDataSourceName string PrometheusDataSourceName string @@ -37,8 +205,9 @@ type CLClusterDashboard struct { } // NewCLClusterDashboard returns a new dashboard for a Chainlink cluster, can be used as a base for more complex plugin based dashboards -func NewCLClusterDashboard(name, ldsn, pdsn, dbf, grafanaURL, grafanaToken string, opts []dashboard.Option) (*CLClusterDashboard, error) { +func NewCLClusterDashboard(nodes int, name, ldsn, pdsn, dbf, grafanaURL, grafanaToken string, opts []dashboard.Option) (*CLClusterDashboard, error) { db := &CLClusterDashboard{ + Nodes: nodes, Name: name, Folder: dbf, LokiDataSourceName: ldsn, @@ -58,19 +227,32 @@ func (m *CLClusterDashboard) Opts() []dashboard.Option { } // logsRowOption returns a row option for a node's logs with name and instance selector -func (m *CLClusterDashboard) logsRowOption(name, instanceSelector string) row.Option { +func (m *CLClusterDashboard) logsRowOption(name, q string) row.Option { return row.WithLogs( name, logs.DataSource(m.LokiDataSourceName), logs.Span(12), logs.Height("300px"), logs.Transparent(), - logs.WithLokiTarget(fmt.Sprintf(` - {namespace="${namespace}", app="app", instance="%s", container="node"} - `, instanceSelector)), + logs.WithLokiTarget(q), ) } +func (m *CLClusterDashboard) logsRowOptionsForNodes(nodes int) []row.Option { + opts := make([]row.Option, 0) + for i := 1; i <= nodes; i++ { + opts = append(opts, row.WithLogs( + fmt.Sprintf("Node %d", i), + logs.DataSource(m.LokiDataSourceName), + logs.Span(12), + logs.Height("300px"), + logs.Transparent(), + logs.WithLokiTarget(fmt.Sprintf(`{namespace="${namespace}", app="app", instance="node-%d", container="node"}`, i)), + )) + } + return opts +} + // timeseriesRowOption returns a row option for a timeseries with name, axis unit, query and legend template func (m *CLClusterDashboard) timeseriesRowOption(name, axisUnit, query, legendTemplate string) row.Option { var tsq timeseries.Option @@ -129,12 +311,9 @@ func (m *CLClusterDashboard) generate() error { query.Request(fmt.Sprintf("label_values(%s)", "namespace")), query.Sort(query.NumericalAsc), ), - dashboard.VariableAsInterval( - "interval", - interval.Values([]string{"30s", "1m", "5m", "10m", "30m", "1h", "6h", "12h"}), - ), dashboard.Row( "Cluster health", + row.Collapse(), m.statRowOption( "App Version", `version{namespace="${namespace}"}`, @@ -160,6 +339,21 @@ func (m *CLClusterDashboard) generate() error { prometheus.Legend("{{pod}} - {{service_id}}"), ), ), + row.WithTimeSeries( + "ETH Balance", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(m.PrometheusDataSourceName), + timeseries.WithPrometheusTarget( + `eth_balance{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - {{account}}"), + ), + ), + ), + // logs + dashboard.Row( + "Logs", + row.Collapse(), row.WithTimeSeries( "Log Counters", timeseries.Span(12), @@ -177,30 +371,244 @@ func (m *CLClusterDashboard) generate() error { `log_critical_count{namespace="${namespace}"}`, prometheus.Legend("{{pod}} - critical"), ), + timeseries.WithPrometheusTarget( + `log_warn_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - warn"), + ), timeseries.WithPrometheusTarget( `log_error_count{namespace="${namespace}"}`, prometheus.Legend("{{pod}} - error"), ), ), - row.WithTimeSeries( - "ETH Balance", - timeseries.Span(12), - timeseries.Height("200px"), - timeseries.DataSource(m.PrometheusDataSourceName), - timeseries.WithPrometheusTarget( - `eth_balance{namespace="${namespace}"}`, - prometheus.Legend("{{pod}} - {{account}}"), - ), + m.logsRowOption("All errors", ` + {namespace="${namespace}", app="app", container="node"} + | json + | level="error" + | line_format "{{ .instance }} {{ .level }} {{ .ts }} {{ .logger }} {{ .caller }} {{ .msg }} {{ .version }} {{ .nodeTier }} {{ .nodeName }} {{ .node }} {{ .evmChainID }} {{ .nodeOrder }} {{ .mode }} {{ .nodeState }} {{ .sentryEventID }} {{ .stacktrace }}"`), + m.logsRowOption("Node 1", `{namespace="${namespace}", app="app", instance="node-1", container="node"}`), + m.logsRowOption("Node 2", `{namespace="${namespace}", app="app", instance="node-2", container="node"}`), + m.logsRowOption("Node 3", `{namespace="${namespace}", app="app", instance="node-3", container="node"}`), + m.logsRowOption("Node 4", `{namespace="${namespace}", app="app", instance="node-4", container="node"}`), + m.logsRowOption("Node 5", `{namespace="${namespace}", app="app", instance="node-5", container="node"}`), + m.logsRowOption("Node 6", `{namespace="${namespace}", app="app", instance="node-6", container="node"}`), + ), + // HeadTracker + dashboard.Row("Head tracker", + row.Collapse(), + m.timeseriesRowOption( + "Head tracker current head", + "Block", + `head_tracker_current_head{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Head tracker very old head", + "Block", + `head_tracker_very_old_head{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Head tracker heads received", + "Block", + `head_tracker_heads_received{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Head tracker connection errors", + "Errors", + `head_tracker_connection_errors{namespace="${namespace}"}`, + "{{ pod }}", ), ), - // logs - dashboard.Row( - "Logs", + dashboard.Row("LogPoller", + row.Collapse(), + m.timeseriesRowOption( + "LogPoller Query Dataset Size", + "", + `log_poller_query_dataset_size{namespace="${namespace}"}`, + "{{ pod }}", + ), + ), + dashboard.Row("OCRCommon", + row.Collapse(), + m.timeseriesRowOption( + "Bridge JSON Parse Values", + "", + `bridge_json_parse_values{namespace="${namespace}"}`, + "{{ pod }} JobID: {{ job_id }}", + ), + m.timeseriesRowOption( + "OCR Median Values", + "", + `ocr_median_values{namespace="${namespace}"}`, + "{{pod}} JobID: {{ job_id }}", + ), + ), + dashboard.Row("Relay Config Poller", + row.Collapse(), + m.timeseriesRowOption( + "Relay Config Poller RPC Contract Calls", + "", + `ocr2_failed_rpc_contract_calls{namespace="${namespace}"}`, + "{{ pod }}", + ), + ), + dashboard.Row("Feeds Jobs", + row.Collapse(), + m.timeseriesRowOption( + "Feeds Job Proposal Requests", + "", + `feeds_job_proposal_requests{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Feeds Job Proposal Count", + "", + `feeds_job_proposal_count{namespace="${namespace}"}`, + "{{ pod }}", + ), + ), + dashboard.Row("Mailbox", + row.Collapse(), + m.timeseriesRowOption( + "Mailbox Load Percent", + "", + `mailbox_load_percent{namespace="${namespace}"}`, + "{{ pod }} {{ name }}", + ), + ), + dashboard.Row("Multi Node States", + row.Collapse(), + m.timeseriesRowOption( + "Multi Node States", + "", + `multi_node_states{namespace="${namespace}"}`, + "{{ pod }}", + ), + ), + dashboard.Row("Block History Estimator", + row.Collapse(), + m.timeseriesRowOption( + "Gas Updater All Gas Price Percentiles", + "", + `gas_updater_all_gas_price_percentiles{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Gas Updater All Tip Cap Percentiles", + "", + `gas_updater_all_tip_cap_percentiles{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Gas Updater Set Gas Price", + "", + `gas_updater_set_gas_price{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Gas Updater Set Tip Cap", + "", + `gas_updater_set_tip_cap{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Gas Updater Current Base Fee", + "", + `gas_updater_current_base_fee{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Block History Estimator Connectivity Failure Count", + "", + `block_history_estimator_connectivity_failure_count{namespace="${namespace}"}`, + "{{ pod }}", + ), + ), + // PromReporter + dashboard.Row("Prom Reporter", row.Collapse(), - m.logsRowOption("Node 1", "node-1"), - m.logsRowOption("Node 2", "node-2"), - m.logsRowOption("Node 3", "node-3"), - m.logsRowOption("Node 4", "node-4"), + m.timeseriesRowOption( + "Unconfirmed Transactions", + "Tx", + `unconfirmed_transactions{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Unconfirmed TX Age", + "Sec", + `max_unconfirmed_tx_age{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "Unconfirmed TX Blocks", + "Blocks", + `max_unconfirmed_blocks{namespace="${namespace}"}`, + "{{ pod }}", + ), + ), + dashboard.Row("TX Manager", + row.Collapse(), + m.timeseriesRowOption( + "TX Manager Time Until TX Broadcast", + "", + `tx_manager_time_until_tx_broadcast{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Num Gas Bumps", + "", + `tx_manager_num_gas_bumps{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Num Gas Bumps Exceeds Limit", + "", + `tx_manager_gas_bump_exceeds_limit{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Num Confirmed Transactions", + "", + `tx_manager_num_confirmed_transactions{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Num Successful Transactions", + "", + `tx_manager_num_successful_transactions{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Num Reverted Transactions", + "", + `tx_manager_num_tx_reverted{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Num Fwd Transactions", + "", + `tx_manager_fwd_tx_count{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Num Transactions Attempts", + "", + `tx_manager_tx_attempt_count{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Time Until TX Confirmed", + "", + `tx_manager_time_until_tx_confirmed{namespace="${namespace}"}`, + "{{ pod }}", + ), + m.timeseriesRowOption( + "TX Manager Block Until TX Confirmed", + "", + `tx_manager_blocks_until_tx_confirmed{namespace="${namespace}"}`, + "{{ pod }}", + ), ), // DON report metrics dashboard.Row("DON Report metrics", @@ -236,6 +644,40 @@ func (m *CLClusterDashboard) generate() error { "", ), ), + dashboard.Row( + "EVM Pool Lifecycle", + row.Collapse(), + m.timeseriesRowOption( + "EVM Pool Highest Seen Block", + "Block", + `evm_pool_rpc_node_highest_seen_block{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool Num Seen Blocks", + "Block", + `evm_pool_rpc_node_num_seen_blocks{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool Node Polls Total", + "Block", + `evm_pool_rpc_node_polls_total{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool Node Polls Failed", + "Block", + `evm_pool_rpc_node_polls_failed{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool Node Polls Success", + "Block", + `evm_pool_rpc_node_polls_success{namespace="${namespace}"}`, + "{{pod}}", + ), + ), dashboard.Row( "DB Connection Metrics (App)", row.Collapse(), @@ -263,6 +705,12 @@ func (m *CLClusterDashboard) generate() error { `db_conns_wait{namespace="${namespace}"}`, "{{pod}}", ), + m.timeseriesRowOption( + "DB Wait Count", + "", + `db_wait_count{namespace="${namespace}"}`, + "{{pod}}", + ), m.timeseriesRowOption( "DB Wait time", "Sec", @@ -291,6 +739,12 @@ func (m *CLClusterDashboard) generate() error { `evm_pool_rpc_node_dials_success{namespace="${namespace}"}`, "{{pod}}", ), + m.timeseriesRowOption( + "EVM Pool RPC Node Dials Failed", + "", + `evm_pool_rpc_node_dials_failed{namespace="${namespace}"}`, + "{{pod}}", + ), m.timeseriesRowOption( "EVM Pool RPC Node Dials Total", "", @@ -298,9 +752,9 @@ func (m *CLClusterDashboard) generate() error { "{{pod}}", ), m.timeseriesRowOption( - "EVM Pool RPC Highest Seen Block", + "EVM Pool RPC Node Dials Failed", "", - `evm_pool_rpc_node_highest_seen_block{namespace="${namespace}"}`, + `evm_pool_rpc_node_dials_failed{namespace="${namespace}"}`, "{{pod}}", ), m.timeseriesRowOption( @@ -309,6 +763,36 @@ func (m *CLClusterDashboard) generate() error { `evm_pool_rpc_node_num_transitions_to_alive{namespace="${namespace}"}`, "{{pod}}", ), + m.timeseriesRowOption( + "EVM Pool RPC Total Transitions to In Sync", + "", + `evm_pool_rpc_node_num_transitions_to_in_sync{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Total Transitions to Out of Sync", + "", + `evm_pool_rpc_node_num_transitions_to_out_of_sync{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Total Transitions to Unreachable", + "", + `evm_pool_rpc_node_num_transitions_to_unreachable{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Total Transitions to invalid Chain ID", + "", + `evm_pool_rpc_node_num_transitions_to_invalid_chain_id{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "EVM Pool RPC Total Transitions to unusable", + "", + `evm_pool_rpc_node_num_transitions_to_unusable{namespace="${namespace}"}`, + "{{pod}}", + ), m.timeseriesRowOption( "EVM Pool RPC Node Polls Success", "", @@ -339,6 +823,12 @@ func (m *CLClusterDashboard) generate() error { `evm_pool_rpc_node_verifies_success{namespace="${namespace}"}`, "{{pod}} - {{evmChainID}}", ), + m.timeseriesRowOption( + "EVM Pool RPC Node Verifies Failed", + "", + `evm_pool_rpc_node_verifies_failed{namespace="${namespace}"}`, + "{{pod}} - {{evmChainID}}", + ), ), dashboard.Row( "EVM Pool RPC Node Latencies (App)", @@ -351,7 +841,89 @@ func (m *CLClusterDashboard) generate() error { ), ), dashboard.Row( - "Pipeline Tasks Metrics (App)", + "Pipeline Metrics (Runner)", + row.Collapse(), + m.timeseriesRowOption( + "Pipeline Task Execution Time", + "Sec", + `pipeline_task_execution_time{namespace="${namespace}"} / 1e6`, + "{{ pod }} JobID: {{ job_id }}", + ), + m.timeseriesRowOption( + "Pipeline Run Errors", + "", + `pipeline_run_errors{namespace="${namespace}"}`, + "{{ pod }} JobID: {{ job_id }}", + ), + m.timeseriesRowOption( + "Pipeline Run Total Time to Completion", + "Sec", + `pipeline_run_total_time_to_completion{namespace="${namespace}"} / 1e6`, + "{{ pod }} JobID: {{ job_id }}", + ), + m.timeseriesRowOption( + "Pipeline Tasks Total Finished", + "", + `pipeline_tasks_total_finished{namespace="${namespace}"}`, + "{{ pod }} JobID: {{ job_id }}", + ), + ), + dashboard.Row( + "Pipeline Metrics (ETHCall)", + row.Collapse(), + m.timeseriesRowOption( + "Pipeline Task ETH Call Execution Time", + "Sec", + `pipeline_task_eth_call_execution_time{namespace="${namespace}"}`, + "{{pod}}", + ), + ), + dashboard.Row( + "Pipeline Metrics (HTTP)", + row.Collapse(), + m.timeseriesRowOption( + "Pipeline Task HTTP Fetch Time", + "Sec", + `pipeline_task_http_fetch_time{namespace="${namespace}"} / 1e6`, + "{{pod}}", + ), + m.timeseriesRowOption( + "Pipeline Task HTTP Response Body Size", + "Bytes", + `pipeline_task_http_response_body_size{namespace="${namespace}"}`, + "{{pod}}", + ), + ), + dashboard.Row( + "Pipeline Metrics (Bridge)", + row.Collapse(), + m.timeseriesRowOption( + "Pipeline Bridge Latency", + "Sec", + `bridge_latency_seconds{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "Pipeline Bridge Errors Total", + "", + `bridge_errors_total{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "Pipeline Bridge Cache Hits Total", + "", + `bridge_cache_hits_total{namespace="${namespace}"}`, + "{{pod}}", + ), + m.timeseriesRowOption( + "Pipeline Bridge Cache Errors Total", + "", + `bridge_cache_errors_total{namespace="${namespace}"}`, + "{{pod}}", + ), + ), + dashboard.Row( + "Pipeline Metrics", row.Collapse(), m.timeseriesRowOption( "Pipeline Runs Queued", @@ -367,6 +939,48 @@ func (m *CLClusterDashboard) generate() error { ), ), } + logOptsFinal := make([]row.Option, 0) + logOptsFinal = append( + logOptsFinal, + row.Collapse(), + row.WithTimeSeries( + "Log Counters", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(m.PrometheusDataSourceName), + timeseries.WithPrometheusTarget( + `log_panic_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - panic"), + ), + timeseries.WithPrometheusTarget( + `log_fatal_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - fatal"), + ), + timeseries.WithPrometheusTarget( + `log_critical_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - critical"), + ), + timeseries.WithPrometheusTarget( + `log_warn_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - warn"), + ), + timeseries.WithPrometheusTarget( + `log_error_count{namespace="${namespace}"}`, + prometheus.Legend("{{pod}} - error"), + ), + ), + m.logsRowOption("All errors", ` + {namespace="${namespace}", app="app", container="node"} + | json + | level="error" + | line_format "{{ .instance }} {{ .level }} {{ .ts }} {{ .logger }} {{ .caller }} {{ .msg }} {{ .version }} {{ .nodeTier }} {{ .nodeName }} {{ .node }} {{ .evmChainID }} {{ .nodeOrder }} {{ .mode }} {{ .nodeState }} {{ .sentryEventID }} {{ .stacktrace }}"`), + ) + logOptsFinal = append(logOptsFinal, m.logsRowOptionsForNodes(m.Nodes)...) + logRowOpts := dashboard.Row( + "Logs", + logOptsFinal..., + ) + opts = append(opts, logRowOpts) opts = append(opts, m.extendedOpts...) builder, err := dashboard.New( "Chainlink Cluster Dashboard", diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index 688660d918..4f7cf8641a 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -55,7 +55,7 @@ deployments: stateful: false chainlink: web_port: 6688 - p2p_port: 8090 + p2p_port: 6690 nodes: - name: node-1 image: ${DEVSPACE_IMAGE} @@ -69,6 +69,12 @@ deployments: - name: node-4 image: ${DEVSPACE_IMAGE} version: latest + - name: node-5 + image: ${DEVSPACE_IMAGE} + version: latest + - name: node-6 + image: ${DEVSPACE_IMAGE} + version: latest prometheusMonitor: "true" podAnnotations: { } nodeSelector: { } diff --git a/charts/chainlink-cluster/go.mod b/charts/chainlink-cluster/go.mod index 990ebbf713..951fb1d2e3 100644 --- a/charts/chainlink-cluster/go.mod +++ b/charts/chainlink-cluster/go.mod @@ -5,11 +5,186 @@ go 1.21 require ( github.com/K-Phoen/grabana v0.21.19 github.com/pkg/errors v0.9.1 + github.com/smartcontractkit/wasp v0.3.6 ) require ( github.com/K-Phoen/sdk v0.12.3 // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aws/aws-sdk-go v1.44.217 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee // indirect + github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dennwc/varint v1.0.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/edsrzf/mmap-go v1.1.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/fatih/color v1.14.1 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.8.1 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/analysis v0.21.4 // indirect + github.com/go-openapi/errors v0.20.3 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/strfmt v0.21.3 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.11.1 // indirect + github.com/go-resty/resty/v2 v2.7.0 // indirect + github.com/goccy/go-json v0.9.11 // indirect + github.com/gogo/googleapis v1.4.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/gogo/status v1.1.1 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/gnostic v0.6.9 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/gosimple/slug v1.13.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect - github.com/prometheus/common v0.39.0 // indirect + github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 // indirect + github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6 // indirect + github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 // indirect + github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect + github.com/hashicorp/consul/api v1.20.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.4.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/golang-lru v0.6.0 // indirect + github.com/hashicorp/memberlist v0.5.0 // indirect + github.com/hashicorp/serf v0.10.1 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/julienschmidt/httprouter v1.3.0 // indirect + github.com/klauspost/compress v1.16.3 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/miekg/dns v1.1.51 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect + github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/alertmanager v0.25.0 // indirect + github.com/prometheus/client_golang v1.15.1 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/common/sigv4 v0.1.0 // indirect + github.com/prometheus/exporter-toolkit v0.9.1 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 // indirect + github.com/rs/zerolog v1.29.0 // indirect + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect + github.com/sercand/kuberesolver/v4 v4.0.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/testify v1.8.3 // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + github.com/ugorji/go/codec v1.2.7 // indirect + github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205 // indirect + github.com/weaveworks/promrus v1.2.0 // indirect + go.etcd.io/etcd/api/v3 v3.5.7 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect + go.etcd.io/etcd/client/v3 v3.5.7 // indirect + go.mongodb.org/mongo-driver v1.11.2 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 // indirect + go.opentelemetry.io/otel v1.14.0 // indirect + go.opentelemetry.io/otel/metric v0.37.0 // indirect + go.opentelemetry.io/otel/trace v1.14.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/goleak v1.2.1 // indirect + go.uber.org/multierr v1.9.0 // indirect + go.uber.org/ratelimit v0.2.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect + golang.org/x/mod v0.9.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.7.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect + google.golang.org/grpc v1.57.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.26.2 // indirect + k8s.io/apimachinery v0.26.2 // indirect + k8s.io/client-go v0.26.2 // indirect + k8s.io/klog/v2 v2.90.1 // indirect + k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d // indirect + k8s.io/utils v0.0.0-20230308161112-d77c459e9343 // indirect + nhooyr.io/websocket v1.8.7 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace ( + // Fixes go mod tidy issue for ambiguous imports from go-ethereum + // See https://github.com/ugorji/go/issues/279 + github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 + + github.com/go-kit/log => github.com/go-kit/log v0.2.1 + + // replicating the replace directive on cosmos SDK + github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 + + // until merged upstream: https://github.com/hashicorp/go-plugin/pull/257 + github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 + + // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 + github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f + + github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 + github.com/sercand/kuberesolver/v4 => github.com/sercand/kuberesolver/v5 v5.1.1 ) diff --git a/charts/chainlink-cluster/go.sum b/charts/chainlink-cluster/go.sum index 093a42d608..4a7704cac4 100644 --- a/charts/chainlink-cluster/go.sum +++ b/charts/chainlink-cluster/go.sum @@ -1,20 +1,2126 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= +github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM= +github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA= +github.com/Azure/go-autorest/autorest/adal v0.9.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/K-Phoen/grabana v0.21.19 h1:tJjRO8nN9JrFjLoQGtOB9P5ILoqENZZGAtt3nK+Ry2Y= github.com/K-Phoen/grabana v0.21.19/go.mod h1:B7gxVxacQUgHWmgqduf4WPZoKYHO1mvZnRVCoyQiwdw= github.com/K-Phoen/sdk v0.12.3 h1:ScutEQASc9VEKJCm3OjIMD82BIS9B2XtNg3gEf6Gs+M= github.com/K-Phoen/sdk v0.12.3/go.mod h1:qmM0wO23CtoDux528MXPpYvS4XkRWkWX6rvX9Za8EVU= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.44.217 h1:FcWC56MRl+k756aH3qeMQTylSdeJ58WN0iFz3fkyRz0= +github.com/aws/aws-sdk-go v1.44.217/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I= +github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= +github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= +github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= +github.com/digitalocean/godo v1.97.0 h1:p9w1yCcWMZcxFSLPToNGXA96WfUVLXqoHti6GzVomL4= +github.com/digitalocean/godo v1.97.0/go.mod h1:NRpFznZFvhHjBoqZAaOD3khVzsJ3EibzKqFL4R60dmA= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= +github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= +github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= +github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= +github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= +github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= +github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= +github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= +github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= +github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= +github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gophercloud/gophercloud v1.2.0 h1:1oXyj4g54KBg/kFtCdMM6jtxSzeIyg8wv4z1HoGPp1E= +github.com/gophercloud/gophercloud v1.2.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= +github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 h1:IOks+FXJ6iO/pfbaVEf4efNw+YzYBYNCkCabyrbkFTM= +github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2/go.mod h1:zj+5BNZAVmQafV583uLTAOzRr963KPdEm4d6NPmtbwg= +github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6 h1:V5PspEXlSlNh22sMyGkgfSOVVLTsSmhbmsp1VPt8Fdc= +github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6/go.mod h1:+aWr7OBDuZMT+p0rKmLfW5saO2m3YOGBnt++IlgLhVk= +github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 h1:VXitROTlmZtLzvokNe8ZbUKpmwldM4Hy1zdNRO32jKU= +github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765/go.mod h1:DhJMrd2QInI/1CNtTN43BZuTmkccdizW1jZ+F6aHkhY= +github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= +github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= +github.com/hashicorp/consul/api v1.20.0/go.mod h1:nR64eD44KQ59Of/ECwt2vUmIK2DKsDzAwTmwmLl8Wpo= +github.com/hashicorp/consul/sdk v0.13.1 h1:EygWVWWMczTzXGpO93awkHFzfUka6hLYJ0qhETd+6lY= +github.com/hashicorp/consul/sdk v0.13.1/go.mod h1:SW/mM4LbKfqmMvcFu8v+eiQQ7oitXEFeiBe9StxERb0= +github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c= +github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I= +github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= +github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= +github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/nomad/api v0.0.0-20230308192510-48e7d70fcd4b h1:EkuSTU8c/63q4LMayj8ilgg/4I5PXDFVcnqKfs9qcwI= +github.com/hashicorp/nomad/api v0.0.0-20230308192510-48e7d70fcd4b/go.mod h1:bKUb1ytds5KwUioHdvdq9jmrDqCThv95si0Ub7iNeBg= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hetznercloud/hcloud-go v1.41.0 h1:KJGFRRc68QiVu4PrEP5BmCQVveCP2CM26UGQUKGpIUs= +github.com/hetznercloud/hcloud-go v1.41.0/go.mod h1:NaHg47L6C77mngZhwBG652dTAztYrsZ2/iITJKhQkHA= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ionos-cloud/sdk-go/v6 v6.1.4 h1:BJHhFA8Q1SZC7VOXqKKr2BV2ysQ2/4hlk1e4hZte7GY= +github.com/ionos-cloud/sdk-go/v6 v6.1.4/go.mod h1:Ox3W0iiEz0GHnfY9e5LmAxwklsxguuNFEUSu0gVRTME= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/linode/linodego v1.14.1 h1:uGxQyy0BidoEpLGdvfi4cPgEW+0YUFsEGrLEhcTfjNc= +github.com/linode/linodego v1.14.1/go.mod h1:NJlzvlNtdMRRkXb0oN6UWzUkj6t+IBsyveHgZ5Ppjyk= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo= +github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= +github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= +github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/ovh/go-ovh v1.3.0 h1:mvZaddk4E4kLcXhzb+cxBsMPYp2pHqiQpWYkInsuZPQ= +github.com/ovh/go-ovh v1.3.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= -github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/alertmanager v0.25.0 h1:vbXKUR6PYRiZPRIKfmXaG+dmCKG52RtPL4Btl8hQGvg= +github.com/prometheus/alertmanager v0.25.0/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= +github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= +github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= +github.com/prometheus/exporter-toolkit v0.9.1 h1:cNkC01riqiOS+kh3zdnNwRsbe/Blh0WwK3ij5rPJ9Sw= +github.com/prometheus/exporter-toolkit v0.9.1/go.mod h1:iFlTmFISCix0vyuyBmm0UqOUCTao9+RsAsKJP3YM9ec= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 h1:i5hmbBzR+VeL5pPl1ZncsJ1bpg3SO66bwkE1msJBsMA= +github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2/go.mod h1:Mm42Acga98xgA+u5yTaC3ki3i0rJEJWFpbdHN7q2trk= +github.com/pyroscope-io/client v0.6.0 h1:rcUFgcnfmuyVYDYT+4d0zfqc8YedOyruHSsUb9ImaBw= +github.com/pyroscope-io/client v0.6.0/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU= +github.com/pyroscope-io/godeltaprof v0.1.2 h1:MdlEmYELd5w+lvIzmZvXGNMVzW2Qc9jDMuJaPOR75g4= +github.com/pyroscope-io/godeltaprof v0.1.2/go.mod h1:psMITXp90+8pFenXkKIpNhrfmI9saQnPbba27VIaiQE= +github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= +github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= +github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.14 h1:yFl3jyaSVLNYXlnNYM5z2pagEk1dYQhfr1p20T1NyKY= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.14/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= +github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartcontractkit/wasp v0.3.6 h1:1TLWfrTzqZwNvyyoKzPZ8FLQat2lNz640eM+mMh2YxM= +github.com/smartcontractkit/wasp v0.3.6/go.mod h1:L/cyUGfpaWxy/2twOVJLRt2mySJEIqGrFj9nyvRLpSo= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= +github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= +github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= +github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= +github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205 h1:gjb7t9LCnRu14LHubyLIgrE+EYlAaREiPn/VknV7R3s= +github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205/go.mod h1:O9wmSPNVSuqxzUZPFlHnPQ8xnyvx0qBnKGFfGbj95uY= +github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= +github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= +go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= +go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= +go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= +go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= +go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.11.2 h1:+1v2rDQUWNcGW7/7E0Jvdz51V38XXxJfhzbV17aNHCw= +go.mongodb.org/mongo-driver v1.11.2/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 h1:lE9EJyw3/JhrjWH/hEy9FptnalDQgj7vpbgC2KCCCxE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0/go.mod h1:pcQ3MM3SWvrA71U4GDqv9UFDJ3HQsW7y5ZO3tDTlUdI= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/metric v0.37.0 h1:pHDQuLQOZwYD+Km0eb657A25NaRzy0a+eLyKfDXedEs= +go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s= +golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M= +google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.57.2 h1:uw37EN34aMFFXB2QPW7Tq6tdTbind1GpRxw5aOX3a5k= +google.golang.org/grpc v1.57.2/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ= +k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= +k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= +k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d h1:VcFq5n7wCJB2FQMCIHfC+f+jNcGgNMar1uKd6rVlifU= +k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= +k8s.io/utils v0.0.0-20230308161112-d77c459e9343 h1:m7tbIjXGcGIAtpmQr7/NAi7RsWoW3E7Zcm4jI1HicTc= +k8s.io/utils v0.0.0-20230308161112-d77c459e9343/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/charts/chainlink-cluster/templates/chainlink-cm.yaml b/charts/chainlink-cluster/templates/chainlink-cm.yaml index 736a332204..b33e29df4b 100644 --- a/charts/chainlink-cluster/templates/chainlink-cm.yaml +++ b/charts/chainlink-cluster/templates/chainlink-cm.yaml @@ -26,15 +26,25 @@ data: AllowOrigins = '*' SecureCookies = false SessionTimeout = '999h0m0s' + [Feature] + FeedsManager = true + LogPoller = true + UICSAKeys = true [OCR] Enabled = true + DefaultTransactionQueueDepth = 0 [P2P] [P2P.V2] Enabled = true - ListenAddresses = ["0.0.0.0:6690"] + ListenAddresses = ['0.0.0.0:6690'] + AnnounceAddresses = ['0.0.0.0:6690'] + DeltaDial = '500ms' + DeltaReconcile = '5s' [[EVM]] ChainID = '1337' MinContractPayment = '0' + AutoCreateKey = true + FinalityDepth = 1 [[EVM.Nodes]] Name = 'node-0' WSURL = 'ws://geth:8546' diff --git a/charts/chainlink-cluster/templates/chainlink-service.yaml b/charts/chainlink-cluster/templates/chainlink-service.yaml index 24c96c909e..7a3b70efb4 100644 --- a/charts/chainlink-cluster/templates/chainlink-service.yaml +++ b/charts/chainlink-cluster/templates/chainlink-service.yaml @@ -12,7 +12,7 @@ spec: port: {{ $.Values.chainlink.p2p_port }} targetPort: {{ $.Values.chainlink.p2p_port }} selector: - app: {{ $.Release.Name }} + instance: {{ $cfg.name }} type: ClusterIP --- {{- end }} \ No newline at end of file diff --git a/charts/chainlink-cluster/templates/mockserver-service.yaml b/charts/chainlink-cluster/templates/mockserver-service.yaml new file mode 100644 index 0000000000..f8ab78a84b --- /dev/null +++ b/charts/chainlink-cluster/templates/mockserver-service.yaml @@ -0,0 +1,14 @@ +{{ if (hasKey .Values "mockserver") }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-mockserver +spec: + selector: + app: {{ .Release.Name }}-mockserver + ports: + - name: serviceport + port: {{ default "1080" $.Values.mockserver.port}} + targetPort: serviceport + type: ClusterIP +{{ end }} \ No newline at end of file diff --git a/charts/chainlink-cluster/templates/mockserver.yaml b/charts/chainlink-cluster/templates/mockserver.yaml index 96f9582435..14c05d0acd 100755 --- a/charts/chainlink-cluster/templates/mockserver.yaml +++ b/charts/chainlink-cluster/templates/mockserver.yaml @@ -1,3 +1,4 @@ +{{ if (hasKey .Values "mockserver") }} apiVersion: apps/v1 kind: Deployment metadata: @@ -5,7 +6,6 @@ metadata: labels: app: {{ .Release.Name }}-mockserver spec: - replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Release.Name }}-mockserver @@ -57,4 +57,5 @@ spec: tolerations: {{ toYaml . | indent 8 }} {{- end }} +{{- end }} --- \ No newline at end of file diff --git a/charts/chainlink-cluster/values-raw-helm.yaml b/charts/chainlink-cluster/values-raw-helm.yaml index 006515f0a3..726a534711 100644 --- a/charts/chainlink-cluster/values-raw-helm.yaml +++ b/charts/chainlink-cluster/values-raw-helm.yaml @@ -11,7 +11,7 @@ # version: stable chainlink: web_port: 6688 - p2p_port: 8090 + p2p_port: 6690 nodes: - name: node-1 image: "public.ecr.aws/chainlink/chainlink:latest" @@ -45,9 +45,13 @@ chainlink: # HTTPURL = 'http://geth:8544' # [WebServer.TLS] # HTTPSPort = 0 +# or use overridesToml to override some part of configuration +# overridesToml: | - name: node-2 - name: node-3 - name: node-4 + - name: node-5 + - name: node-6 resources: requests: cpu: 350m @@ -106,6 +110,19 @@ runner: limits: cpu: 1 memory: 512Mi + affinity: { } + tolerations: [ ] + nodeSelector: { } + ingress: + enabled: false + className: "" + hosts: [ ] + tls: [ ] + annotations: { } + service: + type: NodePort + port: 8080 + # monitoring.coreos.com/v1 PodMonitor for each node prometheusMonitor: false diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 5f250af6fa..e801e25de5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -36,6 +36,7 @@ require ( github.com/testcontainers/testcontainers-go v0.23.0 github.com/umbracle/ethgo v0.1.3 go.dedis.ch/kyber/v3 v3.1.0 + go.uber.org/ratelimit v0.2.0 go.uber.org/zap v1.26.0 golang.org/x/sync v0.5.0 gopkg.in/guregu/null.v4 v4.0.0 @@ -452,7 +453,6 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect diff --git a/integration-tests/k8s/connect.go b/integration-tests/k8s/connect.go new file mode 100644 index 0000000000..34eafc42e2 --- /dev/null +++ b/integration-tests/k8s/connect.go @@ -0,0 +1,103 @@ +package k8s + +import ( + "fmt" + "os" + "time" + + "github.com/pelletier/go-toml/v2" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + client2 "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" +) + +const ( + DefaultConfigFilePath = "../../../charts/chainlink-cluster/connect.toml" + ErrReadConnectionConfig = "failed to read TOML environment connection config" + ErrUnmarshalConnectionConfig = "failed to unmarshal TOML environment connection config" +) + +type ConnectionVars struct { + Namespace string `toml:"namespace"` + NetworkName string `toml:"network_name"` + NetworkChainID int64 `toml:"network_chain_id"` + NetworkPrivateKey string `toml:"network_private_key"` + NetworkWSURL string `toml:"network_ws_url"` + NetworkHTTPURL string `toml:"network_http_url"` + CLNodesNum int `toml:"cl_nodes_num"` + CLNodeURLTemplate string `toml:"cl_node_url_template"` + CLNodeInternalDNSRecordTemplate string `toml:"cl_node_internal_dns_record_template"` + CLNodeUser string `toml:"cl_node_user"` + CLNodePassword string `toml:"cl_node_password"` + MockServerURL string `toml:"mockserver_url"` +} + +// ConnectRemote connects to a local environment, see charts/chainlink-cluster +func ConnectRemote(l zerolog.Logger) (blockchain.EVMClient, *client2.MockserverClient, contracts.ContractDeployer, *client.ChainlinkK8sClient, []*client.ChainlinkK8sClient, error) { + cfg, err := ReadConfig() + if err != nil { + return nil, nil, nil, nil, nil, err + } + net := &blockchain.EVMNetwork{ + Name: cfg.NetworkName, + Simulated: true, + SupportsEIP1559: true, + ClientImplementation: blockchain.EthereumClientImplementation, + ChainID: 1337, + PrivateKeys: []string{ + cfg.NetworkPrivateKey, + }, + URLs: []string{cfg.NetworkWSURL}, + HTTPURLs: []string{cfg.NetworkHTTPURL}, + ChainlinkTransactionLimit: 500000, + Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, + MinimumConfirmations: 1, + GasEstimationBuffer: 10000, + } + cc, err := blockchain.NewEVMClientFromNetwork(*net, l) + if err != nil { + return nil, nil, nil, nil, nil, err + } + cd, err := contracts.NewContractDeployer(cc, l) + if err != nil { + return nil, nil, nil, nil, nil, err + } + clClients := make([]*client.ChainlinkK8sClient, 0) + for i := 1; i <= cfg.CLNodesNum; i++ { + c, err := client.NewChainlinkK8sClient(&client.ChainlinkConfig{ + URL: fmt.Sprintf(cfg.CLNodeURLTemplate, i), + Email: cfg.CLNodeUser, + InternalIP: fmt.Sprintf(cfg.CLNodeInternalDNSRecordTemplate, i), + Password: cfg.CLNodePassword, + }, fmt.Sprintf(cfg.CLNodeInternalDNSRecordTemplate, i), cfg.Namespace) + if err != nil { + return nil, nil, nil, nil, nil, err + } + clClients = append(clClients, c) + } + msClient := client2.NewMockserverClient(&client2.MockserverConfig{ + LocalURL: cfg.MockServerURL, + ClusterURL: cfg.MockServerURL, + }) + return cc, msClient, cd, clClients[0], clClients[1:], nil +} + +func ReadConfig() (*ConnectionVars, error) { + var cfg *ConnectionVars + var d []byte + var err error + d, err = os.ReadFile(DefaultConfigFilePath) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrReadConnectionConfig, err) + } + err = toml.Unmarshal(d, &cfg) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalConnectionConfig, err) + } + log.Info().Interface("Config", cfg).Msg("Connecting to environment from config") + return cfg, nil +} diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md new file mode 100644 index 0000000000..20446992dc --- /dev/null +++ b/integration-tests/load/ocr/README.md @@ -0,0 +1,28 @@ +### OCR Load tests + +## Setup +These tests can connect to any cluster create with [chainlink-cluster](../../../charts/chainlink-cluster/README.md) + +Create your cluster +``` +kubectl create ns my-cluster +devspace use namespace my-cluster +devspace deploy +sudo kubefwd svc -n my-cluster +``` + +Change environment connection configuration [here](connection.toml) + +If you haven't changed anything in [devspace.yaml](../../../charts/chainlink-cluster/devspace.yaml) then default connection configuration will work + +## Usage + +``` +export LOKI_TOKEN=... +export LOKI_URL=... + +go test -v -run TestOCRLoad +go test -v -run TestOCRVolume +``` + +Check test configuration [here](config.toml) \ No newline at end of file diff --git a/integration-tests/load/ocr/config.go b/integration-tests/load/ocr/config.go new file mode 100644 index 0000000000..2991df3774 --- /dev/null +++ b/integration-tests/load/ocr/config.go @@ -0,0 +1,72 @@ +package ocr + +import ( + "encoding/base64" + "fmt" + "os" + + "github.com/pelletier/go-toml/v2" + "github.com/rs/zerolog/log" + + "github.com/smartcontractkit/chainlink/v2/core/store/models" +) + +const ( + DefaultConfigFilename = "config.toml" + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" +) + +type PerformanceConfig struct { + Load *Load `toml:"Load"` + Volume *Volume `toml:"Volume"` + Common *Common `toml:"Common"` +} + +type Common struct { + ETHFunds int `toml:"eth_funds"` +} + +type Load struct { + TestDuration *models.Duration `toml:"test_duration"` + Rate int64 `toml:"rate"` + RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` + VerificationInterval *models.Duration `toml:"verification_interval"` + VerificationTimeout *models.Duration `toml:"verification_timeout"` + EAChangeInterval *models.Duration `toml:"ea_change_interval"` +} + +type Volume struct { + TestDuration *models.Duration `toml:"test_duration"` + Rate int64 `toml:"rate"` + VURequestsPerUnit int `toml:"vu_requests_per_unit"` + RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` + VerificationInterval *models.Duration `toml:"verification_interval"` + VerificationTimeout *models.Duration `toml:"verification_timeout"` + EAChangeInterval *models.Duration `toml:"ea_change_interval"` +} + +func ReadConfig() (*PerformanceConfig, error) { + var cfg *PerformanceConfig + rawConfig := os.Getenv("CONFIG") + var d []byte + var err error + if rawConfig == "" { + d, err = os.ReadFile(DefaultConfigFilename) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) + } + } else { + d, err = base64.StdEncoding.DecodeString(rawConfig) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) + } + } + err = toml.Unmarshal(d, &cfg) + if err != nil { + return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) + } + + log.Debug().Interface("Config", cfg).Msg("Parsed config") + return cfg, nil +} diff --git a/integration-tests/load/ocr/config.toml b/integration-tests/load/ocr/config.toml new file mode 100644 index 0000000000..df8364b3ee --- /dev/null +++ b/integration-tests/load/ocr/config.toml @@ -0,0 +1,20 @@ +[Load] +test_duration = "3m" +rate_limit_unit_duration = "1m" +rate = 3 +verification_interval = "5s" +verification_timeout = "3m" +ea_change_interval = "5s" + +[Volume] +test_duration = "3m" +rate_limit_unit_duration = "1m" +vu_requests_per_unit = 10 +rate = 1 +verification_interval = "5s" +verification_timeout = "3m" + +ea_change_interval = "5s" + +[Common] +eth_funds = 3 \ No newline at end of file diff --git a/integration-tests/load/ocr/gun.go b/integration-tests/load/ocr/gun.go new file mode 100644 index 0000000000..a2eb1ff220 --- /dev/null +++ b/integration-tests/load/ocr/gun.go @@ -0,0 +1,55 @@ +package ocr + +import ( + "context" + "sync/atomic" + "time" + + "github.com/rs/zerolog" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + + "github.com/smartcontractkit/wasp" +) + +// Gun is a gun for the OCR load test +// it triggers new rounds for provided feed(aggregator) contract +type Gun struct { + roundNum atomic.Int64 + ocrInstances []contracts.OffchainAggregator + cc blockchain.EVMClient + l zerolog.Logger +} + +func NewGun(l zerolog.Logger, cc blockchain.EVMClient, ocrInstances []contracts.OffchainAggregator) *Gun { + return &Gun{ + l: l, + cc: cc, + ocrInstances: ocrInstances, + } +} + +func (m *Gun) Call(_ *wasp.Generator) *wasp.CallResult { + m.roundNum.Add(1) + requestedRound := m.roundNum.Load() + m.l.Info(). + Int64("RoundNum", requestedRound). + Str("FeedID", m.ocrInstances[0].Address()). + Msg("starting new round") + err := m.ocrInstances[0].RequestNewRound() + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + for { + time.Sleep(5 * time.Second) + lr, err := m.ocrInstances[0].GetLatestRound(context.Background()) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + m.l.Info().Interface("LatestRound", lr).Msg("latest round") + if lr.RoundId.Int64() >= requestedRound { + return &wasp.CallResult{} + } + } +} diff --git a/integration-tests/load/ocr/helper.go b/integration-tests/load/ocr/helper.go new file mode 100644 index 0000000000..c35dc384d1 --- /dev/null +++ b/integration-tests/load/ocr/helper.go @@ -0,0 +1,68 @@ +package ocr + +import ( + "math/big" + "math/rand" + "time" + + "github.com/rs/zerolog" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + + client2 "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" +) + +func SetupCluster( + cc blockchain.EVMClient, + cd contracts.ContractDeployer, + workerNodes []*client.ChainlinkK8sClient, +) (contracts.LinkToken, error) { + err := actions.FundChainlinkNodes(workerNodes, cc, big.NewFloat(3)) + if err != nil { + return nil, err + } + lt, err := cd.DeployLinkTokenContract() + if err != nil { + return nil, err + } + return lt, nil +} + +func SetupFeed( + cc blockchain.EVMClient, + msClient *client2.MockserverClient, + cd contracts.ContractDeployer, + bootstrapNode *client.ChainlinkK8sClient, + workerNodes []*client.ChainlinkK8sClient, + lt contracts.LinkToken, +) ([]contracts.OffchainAggregator, error) { + ocrInstances, err := actions.DeployOCRContracts(1, lt, cd, workerNodes, cc) + if err != nil { + return nil, err + } + err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, msClient, cc.GetChainID().String()) + if err != nil { + return nil, err + } + return ocrInstances, nil +} + +func SimulateEAActivity( + l zerolog.Logger, + eaChangeInterval time.Duration, + ocrInstances []contracts.OffchainAggregator, + workerNodes []*client.ChainlinkK8sClient, + msClient *client2.MockserverClient, +) { + go func() { + for { + time.Sleep(eaChangeInterval) + if err := actions.SetAllAdapterResponsesToTheSameValue(rand.Intn(1000), ocrInstances, workerNodes, msClient); err != nil { + l.Error().Err(err).Msg("failed to update mockserver responses") + } + } + }() +} diff --git a/integration-tests/load/ocr/ocr_test.go b/integration-tests/load/ocr/ocr_test.go new file mode 100644 index 0000000000..6bf1487125 --- /dev/null +++ b/integration-tests/load/ocr/ocr_test.go @@ -0,0 +1,71 @@ +package ocr + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/integration-tests/k8s" + + "github.com/smartcontractkit/wasp" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-testing-framework/logging" +) + +var ( + CommonTestLabels = map[string]string{ + "branch": "ocr_healthcheck_local", + "commit": "ocr_healthcheck_local", + } +) + +func TestOCRPerformance(t *testing.T) { + l := logging.GetTestLogger(t) + cc, msClient, cd, bootstrapNode, workerNodes, err := k8s.ConnectRemote(l) + require.NoError(t, err) + lt, err := SetupCluster(cc, cd, workerNodes) + require.NoError(t, err) + ocrInstances, err := SetupFeed(cc, msClient, cd, bootstrapNode, workerNodes, lt) + require.NoError(t, err) + cfg, err := ReadConfig() + require.NoError(t, err) + SimulateEAActivity(l, cfg.Load.EAChangeInterval.Duration(), ocrInstances, workerNodes, msClient) + + p := wasp.NewProfile() + p.Add(wasp.NewGenerator(&wasp.Config{ + T: t, + GenName: "ocr", + LoadType: wasp.RPS, + CallTimeout: cfg.Load.VerificationTimeout.Duration(), + RateLimitUnitDuration: cfg.Load.RateLimitUnitDuration.Duration(), + Schedule: wasp.Plain(cfg.Load.Rate, cfg.Load.TestDuration.Duration()), + Gun: NewGun(l, cc, ocrInstances), + Labels: CommonTestLabels, + LokiConfig: wasp.NewEnvLokiConfig(), + })) + _, err = p.Run(true) + require.NoError(t, err) +} + +func TestOCRCapacity(t *testing.T) { + l := logging.GetTestLogger(t) + cc, msClient, cd, bootstrapNode, workerNodes, err := k8s.ConnectRemote(l) + require.NoError(t, err) + lt, err := SetupCluster(cc, cd, workerNodes) + require.NoError(t, err) + cfg, err := ReadConfig() + require.NoError(t, err) + + p := wasp.NewProfile() + p.Add(wasp.NewGenerator(&wasp.Config{ + T: t, + GenName: "ocr", + LoadType: wasp.VU, + CallTimeout: cfg.Volume.VerificationTimeout.Duration(), + Schedule: wasp.Plain(cfg.Volume.Rate, cfg.Volume.TestDuration.Duration()), + VU: NewVU(l, cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration(), cc, lt, cd, bootstrapNode, workerNodes, msClient), + Labels: CommonTestLabels, + LokiConfig: wasp.NewEnvLokiConfig(), + })) + _, err = p.Run(true) + require.NoError(t, err) +} diff --git a/integration-tests/load/ocr/vu.go b/integration-tests/load/ocr/vu.go new file mode 100644 index 0000000000..a905ec011d --- /dev/null +++ b/integration-tests/load/ocr/vu.go @@ -0,0 +1,128 @@ +package ocr + +import ( + "context" + "sync/atomic" + "time" + + "github.com/rs/zerolog" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + + "github.com/smartcontractkit/wasp" + "go.uber.org/ratelimit" + + client2 "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" +) + +// VU is a virtual user for the OCR load test +// it creates a feed and triggers new rounds +type VU struct { + rl ratelimit.Limiter + rate int + rateUnit time.Duration + roundNum atomic.Int64 + cc blockchain.EVMClient + lt contracts.LinkToken + cd contracts.ContractDeployer + bootstrapNode *client.ChainlinkK8sClient + workerNodes []*client.ChainlinkK8sClient + msClient *client2.MockserverClient + l zerolog.Logger + ocrInstances []contracts.OffchainAggregator + stop chan struct{} +} + +func NewVU( + l zerolog.Logger, + rate int, + rateUnit time.Duration, + cc blockchain.EVMClient, + lt contracts.LinkToken, + cd contracts.ContractDeployer, + bootstrapNode *client.ChainlinkK8sClient, + workerNodes []*client.ChainlinkK8sClient, + msClient *client2.MockserverClient, +) *VU { + return &VU{ + rl: ratelimit.New(rate, ratelimit.Per(rateUnit)), + rate: rate, + rateUnit: rateUnit, + l: l, + cc: cc, + lt: lt, + cd: cd, + msClient: msClient, + bootstrapNode: bootstrapNode, + workerNodes: workerNodes, + } +} + +func (m *VU) Clone(_ *wasp.Generator) wasp.VirtualUser { + return &VU{ + stop: make(chan struct{}, 1), + rl: ratelimit.New(m.rate, ratelimit.Per(m.rateUnit)), + rate: m.rate, + rateUnit: m.rateUnit, + l: m.l, + cc: m.cc, + lt: m.lt, + cd: m.cd, + msClient: m.msClient, + bootstrapNode: m.bootstrapNode, + workerNodes: m.workerNodes, + } +} + +func (m *VU) Setup(_ *wasp.Generator) error { + ocrInstances, err := actions.DeployOCRContracts(1, m.lt, m.cd, m.workerNodes, m.cc) + if err != nil { + return err + } + err = actions.CreateOCRJobs(ocrInstances, m.bootstrapNode, m.workerNodes, 5, m.msClient, m.cc.GetChainID().String()) + if err != nil { + return err + } + m.ocrInstances = ocrInstances + return nil +} + +func (m *VU) Teardown(_ *wasp.Generator) error { + return nil +} + +func (m *VU) Call(l *wasp.Generator) { + m.rl.Take() + m.roundNum.Add(1) + requestedRound := m.roundNum.Load() + m.l.Info(). + Int64("RoundNum", requestedRound). + Str("FeedID", m.ocrInstances[0].Address()). + Msg("starting new round") + err := m.ocrInstances[0].RequestNewRound() + if err != nil { + l.ResponsesChan <- &wasp.CallResult{Error: err.Error(), Failed: true} + } + for { + time.Sleep(5 * time.Second) + lr, err := m.ocrInstances[0].GetLatestRound(context.Background()) + if err != nil { + l.ResponsesChan <- &wasp.CallResult{Error: err.Error(), Failed: true} + } + m.l.Info().Interface("LatestRound", lr).Msg("latest round") + if lr.RoundId.Int64() >= requestedRound { + l.ResponsesChan <- &wasp.CallResult{} + } + } +} + +func (m *VU) Stop(_ *wasp.Generator) { + m.stop <- struct{}{} +} + +func (m *VU) StopChan() chan struct{} { + return m.stop +} From 1f5182b61941f975aac92d9706aedd018065787a Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Thu, 30 Nov 2023 09:17:06 -0500 Subject: [PATCH 233/327] Update Test Go and CTF Version (#11413) --- integration-tests/go.mod | 4 ++-- integration-tests/go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index e801e25de5..e83859f2f4 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink/integration-tests -go 1.21.3 +go 1.21.4 // Make sure we're working with the latest chainlink libs replace github.com/smartcontractkit/chainlink/v2 => ../ @@ -25,7 +25,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 - github.com/smartcontractkit/chainlink-testing-framework v1.19.5 + github.com/smartcontractkit/chainlink-testing-framework v1.19.7 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 855d97d5e4..9a647daaff 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2386,8 +2386,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= -github.com/smartcontractkit/chainlink-testing-framework v1.19.5 h1:Iq1L7wCA8IkBBtP3p6W2ttu8v9cJp95spusnozW1UrA= -github.com/smartcontractkit/chainlink-testing-framework v1.19.5/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= +github.com/smartcontractkit/chainlink-testing-framework v1.19.7 h1:8oEduPXC5kBwnNwE5qdK+h/NZ2qOlxK0hgtedS+/St0= +github.com/smartcontractkit/chainlink-testing-framework v1.19.7/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= From b29c327b97f2ee713dfafb94d603489acf040c55 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 30 Nov 2023 09:42:02 -0600 Subject: [PATCH 234/327] core/chains/evm/config/toml/defaults: fix sepolia link address (#11426) --- core/chains/evm/client/client.go | 5 ++++- core/chains/evm/client/rpc_client.go | 4 +++- core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml | 2 +- docs/CHANGELOG.md | 4 ++++ docs/CONFIG.md | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index cccda9914f..688cc3c9be 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -2,6 +2,7 @@ package client import ( "context" + "fmt" "math/big" "strings" "time" @@ -166,7 +167,9 @@ func (client *client) TokenBalance(ctx context.Context, address common.Address, if err != nil { return numLinkBigInt, err } - numLinkBigInt.SetString(result, 0) + if _, ok := numLinkBigInt.SetString(result, 0); !ok { + return nil, fmt.Errorf("failed to parse int: %s", result) + } return numLinkBigInt, nil } diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index fc9c348a57..01851c4ae9 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -866,7 +866,9 @@ func (r *rpcClient) TokenBalance(ctx context.Context, address common.Address, co if err != nil { return numLinkBigInt, err } - numLinkBigInt.SetString(result, 0) + if _, ok := numLinkBigInt.SetString(result, 0); !ok { + return nil, fmt.Errorf("failed to parse int: %s", result) + } return numLinkBigInt, nil } diff --git a/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml b/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml index 7b979c2fd8..27dda60296 100644 --- a/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml @@ -1,5 +1,5 @@ ChainID = '11155111' -LinkContractAddress = '0xb227f007804c16546Bd054dfED2E7A1fD5437678' +LinkContractAddress = '0x779877A7B0D9E8603169DdbD7836e478b4624789' MinContractPayment = '0.1 link' [GasEstimator] diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e282d04789..dc2f774cd3 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -67,6 +67,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `mercury_insufficient_blocks_count` - `mercury_zero_blocks_count` +### Fixed + +- Corrected Ethereum Sepolia `LinkContractAddress` to `0x779877A7B0D9E8603169DdbD7836e478b4624789` + ... diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 38aac7085e..3568abe7a0 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -5271,7 +5271,7 @@ BlockBackfillDepth = 10 BlockBackfillSkip = false FinalityDepth = 50 FinalityTagEnabled = false -LinkContractAddress = '0xb227f007804c16546Bd054dfED2E7A1fD5437678' +LinkContractAddress = '0x779877A7B0D9E8603169DdbD7836e478b4624789' LogBackfillBatchSize = 1000 LogPollInterval = '15s' LogKeepBlocksDepth = 100000 From 31bf23accd80bec9e7aaffc7739328be2cc0778a Mon Sep 17 00:00:00 2001 From: george-dorin <120329946+george-dorin@users.noreply.github.com> Date: Thu, 30 Nov 2023 19:16:19 +0200 Subject: [PATCH 235/327] Fix telemetry manager health report (#11397) * Fix incorrect health report * Add network and chainID to logger and service names * Update helpers_test * Update services name * Remove unused * Add changelog * Implement feedback --- core/services/synchronization/helpers_test.go | 4 ++-- .../telemetry_ingress_batch_client.go | 4 ++-- .../synchronization/telemetry_ingress_client.go | 4 ++-- core/services/telemetry/manager.go | 13 +++++-------- core/services/telemetry/manager_test.go | 8 +++----- docs/CHANGELOG.md | 3 +++ 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/core/services/synchronization/helpers_test.go b/core/services/synchronization/helpers_test.go index 14aaf5a7a0..7bb2dde763 100644 --- a/core/services/synchronization/helpers_test.go +++ b/core/services/synchronization/helpers_test.go @@ -12,14 +12,14 @@ import ( // NewTestTelemetryIngressClient calls NewTelemetryIngressClient and injects telemClient. func NewTestTelemetryIngressClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient) TelemetryService { - tc := NewTelemetryIngressClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100) + tc := NewTelemetryIngressClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, "test", "test") tc.(*telemetryIngressClient).telemClient = telemClient return tc } // NewTestTelemetryIngressBatchClient calls NewTelemetryIngressBatchClient and injects telemClient. func NewTestTelemetryIngressBatchClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient, sendInterval time.Duration, uniconn bool) TelemetryService { - tc := NewTelemetryIngressBatchClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, 50, sendInterval, time.Second, uniconn) + tc := NewTelemetryIngressBatchClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, 50, sendInterval, time.Second, uniconn, "test", "test") tc.(*telemetryIngressBatchClient).close = func() error { return nil } tc.(*telemetryIngressBatchClient).telemClient = telemClient return tc diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go index c551ac85b3..5f286f1617 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client.go +++ b/core/services/synchronization/telemetry_ingress_batch_client.go @@ -66,7 +66,7 @@ type telemetryIngressBatchClient struct { // NewTelemetryIngressBatchClient returns a client backed by wsrpc that // can send telemetry to the telemetry ingress server -func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool) TelemetryService { +func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool, network string, chainID string) TelemetryService { return &telemetryIngressBatchClient{ telemBufferSize: telemBufferSize, telemMaxBatchSize: telemMaxBatchSize, @@ -77,7 +77,7 @@ func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks key serverPubKeyHex: serverPubKeyHex, globalLogger: lggr, logging: logging, - lggr: lggr.Named("TelemetryIngressBatchClient"), + lggr: lggr.Named("TelemetryIngressBatchClient").Named(network).Named(chainID), chDone: make(chan struct{}), workers: make(map[string]*telemetryIngressBatchWorker), useUniConn: useUniconn, diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go index b566199fdc..bcad01622e 100644 --- a/core/services/synchronization/telemetry_ingress_client.go +++ b/core/services/synchronization/telemetry_ingress_client.go @@ -52,13 +52,13 @@ type telemetryIngressClient struct { // NewTelemetryIngressClient returns a client backed by wsrpc that // can send telemetry to the telemetry ingress server -func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint) TelemetryService { +func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, network string, chainID string) TelemetryService { return &telemetryIngressClient{ url: url, ks: ks, serverPubKeyHex: serverPubKeyHex, logging: logging, - lggr: lggr.Named("TelemetryIngressClient"), + lggr: lggr.Named("TelemetryIngressClient").Named(network).Named(chainID), chTelemetry: make(chan TelemPayload, telemBufferSize), chDone: make(services.StopChan), } diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go index d760d13b2b..c457aca5bf 100644 --- a/core/services/telemetry/manager.go +++ b/core/services/telemetry/manager.go @@ -2,7 +2,6 @@ package telemetry import ( "context" - "fmt" "net/url" "strings" "time" @@ -68,7 +67,6 @@ func (l *legacyEndpointConfig) URL() *url.URL { } type telemetryEndpoint struct { - services.StateMachine ChainID string Network string URL *url.URL @@ -140,11 +138,10 @@ func (m *Manager) Name() string { } func (m *Manager) HealthReport() map[string]error { - hr := make(map[string]error) - hr[m.lggr.Name()] = m.Healthy() + hr := map[string]error{m.Name(): m.Healthy()} + for _, e := range m.endpoints { - name := fmt.Sprintf("%s.%s.%s", m.lggr.Name(), e.Network, e.ChainID) - hr[name] = e.Healthy() + services.CopyHealth(hr, e.client.HealthReport()) } return hr } @@ -190,9 +187,9 @@ func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error { var tClient synchronization.TelemetryService if m.useBatchSend { - tClient = synchronization.NewTelemetryIngressBatchClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize, m.maxBatchSize, m.sendInterval, m.sendTimeout, m.uniConn) + tClient = synchronization.NewTelemetryIngressBatchClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize, m.maxBatchSize, m.sendInterval, m.sendTimeout, m.uniConn, e.Network(), e.ChainID()) } else { - tClient = synchronization.NewTelemetryIngressClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize) + tClient = synchronization.NewTelemetryIngressClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize, e.Network(), e.ChainID()) } te := telemetryEndpoint{ diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index f09e4d3482..8564be8466 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -14,7 +14,6 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -246,10 +245,9 @@ func TestCorrectEndpointRouting(t *testing.T) { }) tm.endpoints[i] = &telemetryEndpoint{ - StateMachine: services.StateMachine{}, - ChainID: e.chainID, - Network: e.network, - client: clientMock, + ChainID: e.chainID, + Network: e.network, + client: clientMock, } } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index dc2f774cd3..929fec5a3e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] +### Fixed +- Fixed a bug that caused the Telemetry Manager to report incorrect health + ### Added - Added a tracker component to the txmgr for tracking and gracefully handling abandoned transactions. Abandoned transactions occur when a fromAddress is removed from the keystore by a node operator. The tracker gives abandoned transactions a chance to be finalized on chain, or marks them as fatal_error if they are not finalized within a specified time to live (default 6hrs). From 82ed297d4aed41024a2e10f7b8cbf086d44180d2 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 30 Nov 2023 12:22:14 -0500 Subject: [PATCH 236/327] Increase blocks number for mercury v1 to 10 (#11410) * Increase blocks number for mercury v1 to 10 * Fix test --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../relay/evm/mercury/v1/data_source_test.go | 42 ++++++------------- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- 7 files changed, 21 insertions(+), 39 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 1eb186931f..c1ed59097c 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -304,7 +304,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 2a77f2066d..de86a45721 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1504,8 +1504,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 h1:HJCPvJ+ZjU9TSX4YD5rxBJqGAvqhDfzoJgI3WmfeWeI= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde h1:yulX+cnJbiS/iACjOdJfFtD5bD9M6TnXy7Og/PBafew= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 6eb9f430c6..45a99f2919 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -356,49 +356,31 @@ func TestMercury_Observe(t *testing.T) { ht2.AssertExpectations(t) }) t.Run("when chain is long enough", func(t *testing.T) { - h1 := &evmtypes.Head{ - Number: 1, - } - h2 := &evmtypes.Head{ - Number: 2, - Parent: h1, - } - h3 := &evmtypes.Head{ - Number: 3, - Parent: h2, - } - h4 := &evmtypes.Head{ - Number: 4, - Parent: h3, - } - h5 := &evmtypes.Head{ - Number: 5, - Parent: h4, - } - h6 := &evmtypes.Head{ - Number: 6, - Parent: h5, + heads := make([]*evmtypes.Head, nBlocksObservation+5) + for i := range heads { + heads[i] = &evmtypes.Head{Number: int64(i)} + if i > 0 { + heads[i].Parent = heads[i-1] + } } ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - ht2.On("LatestChain").Return(h6) + ht2.On("LatestChain").Return(heads[len(heads)-1]) ds.chainReader = evm.NewChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) - assert.Len(t, obs.LatestBlocks, 5) - assert.Equal(t, 6, int(obs.LatestBlocks[0].Num)) - assert.Equal(t, 5, int(obs.LatestBlocks[1].Num)) - assert.Equal(t, 4, int(obs.LatestBlocks[2].Num)) - assert.Equal(t, 3, int(obs.LatestBlocks[3].Num)) - assert.Equal(t, 2, int(obs.LatestBlocks[4].Num)) + assert.Len(t, obs.LatestBlocks, nBlocksObservation) + highestBlockNum := heads[len(heads)-1].Number + for i := range obs.LatestBlocks { + assert.Equal(t, int(highestBlockNum)-i, int(obs.LatestBlocks[i].Num)) + } ht2.AssertExpectations(t) }) t.Run("when chain reader returns an error", func(t *testing.T) { - ds.chainReader = &mockChainReader{ err: io.EOF, obs: nil, diff --git a/go.mod b/go.mod index c105c1c600..688f581052 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-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 diff --git a/go.sum b/go.sum index 18d78d4815..d522aabb08 100644 --- a/go.sum +++ b/go.sum @@ -1507,8 +1507,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 h1:HJCPvJ+ZjU9TSX4YD5rxBJqGAvqhDfzoJgI3WmfeWeI= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde h1:yulX+cnJbiS/iACjOdJfFtD5bD9M6TnXy7Og/PBafew= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index e83859f2f4..b03819e206 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde github.com/smartcontractkit/chainlink-testing-framework v1.19.7 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 9a647daaff..74fe9e4dc4 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2376,8 +2376,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248 h1:HJCPvJ+ZjU9TSX4YD5rxBJqGAvqhDfzoJgI3WmfeWeI= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231127213516-5b67a57f9248/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde h1:yulX+cnJbiS/iACjOdJfFtD5bD9M6TnXy7Og/PBafew= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= From c21f4ffa9dcf7a836630baa5ddadd61510e57e5f Mon Sep 17 00:00:00 2001 From: Dylan Tinianov Date: Thu, 30 Nov 2023 15:20:49 -0500 Subject: [PATCH 237/327] [BCI-2151] Refactor prom reporter db API (#11394) * Refactor prom reporter db API * Add test case * lint * Use Txm from LegacyChainContainer * Use legacyevm * lint * Use TXM chainID * lint --------- Co-authored-by: Prashant Yadav <34992934+prashantkumar1982@users.noreply.github.com> --- common/txmgr/mocks/tx_manager.go | 74 ++++++++++++++++++ common/txmgr/txmgr.go | 29 ++++++- common/txmgr/types/mocks/tx_store.go | 74 ++++++++++++++++++ common/txmgr/types/tx_store.go | 4 + core/chains/evm/txmgr/evm_tx_store.go | 47 ++++++++++++ core/chains/evm/txmgr/evm_tx_store_test.go | 76 +++++++++++++++++++ core/chains/evm/txmgr/mocks/evm_tx_store.go | 74 ++++++++++++++++++ core/internal/cltest/mocks.go | 14 ++++ core/services/chainlink/application.go | 10 +-- core/services/promreporter/prom_reporter.go | 63 ++++++++++----- .../promreporter/prom_reporter_test.go | 41 ++++++++-- docs/CHANGELOG.md | 1 + 12 files changed, 476 insertions(+), 31 deletions(-) diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index 89abf1dea5..27077218f6 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -9,6 +9,8 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" mock "github.com/stretchr/testify/mock" + null "gopkg.in/guregu/null.v4" + txmgr "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -35,6 +37,30 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close( return r0 } +// CountTransactionsByState provides a mock function with given fields: ctx, state +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (uint32, error) { + ret := _m.Called(ctx, state) + + var r0 uint32 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState) (uint32, error)); ok { + return rf(ctx, state) + } + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState) uint32); ok { + r0 = rf(ctx, state) + } else { + r0 = ret.Get(0).(uint32) + } + + if rf, ok := ret.Get(1).(func(context.Context, txmgrtypes.TxState) error); ok { + r1 = rf(ctx, state) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // CreateTransaction provides a mock function with given fields: ctx, txRequest func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, txRequest) @@ -59,6 +85,54 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Create return r0, r1 } +// FindEarliestUnconfirmedBroadcastTime provides a mock function with given fields: ctx +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (null.Time, error) { + ret := _m.Called(ctx) + + var r0 null.Time + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (null.Time, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) null.Time); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(null.Time) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindEarliestUnconfirmedTxAttemptBlock provides a mock function with given fields: ctx +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (null.Int, error) { + ret := _m.Called(ctx) + + var r0 null.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (null.Int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) null.Int); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(null.Int) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindTxesByMetaFieldAndStates provides a mock function with given fields: ctx, metaField, metaValue, states, chainID func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, metaValue, states, chainID) diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 0a50bb6638..3fbdb852f8 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -10,10 +10,10 @@ import ( "time" "github.com/google/uuid" + nullv4 "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" @@ -55,6 +55,9 @@ type TxManager[ FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) // Find transactions loaded with transaction attempts and receipts by transaction IDs and states FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (nullv4.Time, error) + FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (nullv4.Int, error) + CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (count uint32, err error) } type reset struct { @@ -576,6 +579,18 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWi return } +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (nullv4.Time, error) { + return b.txStore.FindEarliestUnconfirmedBroadcastTime(ctx, b.chainID) +} + +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (nullv4.Int, error) { + return b.txStore.FindEarliestUnconfirmedTxAttemptBlock(ctx, b.chainID) +} + +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (count uint32, err error) { + return b.txStore.CountTransactionsByState(ctx, state, b.chainID) +} + type NullTxManager[ CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], @@ -642,3 +657,15 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Fin func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { return txes, errors.New(n.ErrMsg) } + +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (nullv4.Time, error) { + return nullv4.Time{}, errors.New(n.ErrMsg) +} + +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (nullv4.Int, error) { + return nullv4.Int{}, errors.New(n.ErrMsg) +} + +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (count uint32, err error) { + return count, errors.New(n.ErrMsg) +} diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index 0a7738fd68..df1528a4c2 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -9,6 +9,8 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" mock "github.com/stretchr/testify/mock" + null "gopkg.in/guregu/null.v4" + time "time" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -56,6 +58,30 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() { _m.Called() } +// CountTransactionsByState provides a mock function with given fields: ctx, state, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState, chainID CHAIN_ID) (uint32, error) { + ret := _m.Called(ctx, state, chainID) + + var r0 uint32 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState, CHAIN_ID) (uint32, error)); ok { + return rf(ctx, state, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState, CHAIN_ID) uint32); ok { + r0 = rf(ctx, state, chainID) + } else { + r0 = ret.Get(0).(uint32) + } + + if rf, ok := ret.Get(1).(func(context.Context, txmgrtypes.TxState, CHAIN_ID) error); ok { + r1 = rf(ctx, state, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // CountUnconfirmedTransactions provides a mock function with given fields: ctx, fromAddress, chainID func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconfirmedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) @@ -142,6 +168,54 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) DeleteInPro return r0 } +// FindEarliestUnconfirmedBroadcastTime provides a mock function with given fields: ctx, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID CHAIN_ID) (null.Time, error) { + ret := _m.Called(ctx, chainID) + + var r0 null.Time + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) (null.Time, error)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) null.Time); ok { + r0 = rf(ctx, chainID) + } else { + r0 = ret.Get(0).(null.Time) + } + + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindEarliestUnconfirmedTxAttemptBlock provides a mock function with given fields: ctx, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID CHAIN_ID) (null.Int, error) { + ret := _m.Called(ctx, chainID) + + var r0 null.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) (null.Int, error)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) null.Int); ok { + r0 = rf(ctx, chainID) + } else { + r0 = ret.Get(0).(null.Int) + } + + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindLatestSequence provides a mock function with given fields: ctx, fromAddress, chainId func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindLatestSequence(ctx context.Context, fromAddress ADDR, chainId CHAIN_ID) (SEQ, error) { ret := _m.Called(ctx, fromAddress, chainId) diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index 251135795f..57ecf28d58 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -6,6 +6,7 @@ import ( "time" "github.com/google/uuid" + "gopkg.in/guregu/null.v4" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" @@ -64,6 +65,7 @@ type TransactionStore[ FEE feetypes.Fee, ] interface { CountUnconfirmedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (count uint32, err error) + CountTransactionsByState(ctx context.Context, state TxState, chainID CHAIN_ID) (count uint32, err error) CountUnstartedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (count uint32, err error) CreateTransaction(ctx context.Context, txRequest TxRequest[ADDR, TX_HASH], chainID CHAIN_ID) (tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) DeleteInProgressAttempt(ctx context.Context, attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error @@ -79,6 +81,8 @@ type TransactionStore[ FindTxWithSequence(ctx context.Context, fromAddress ADDR, seq SEQ) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID) error FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber, lowBlockNumber int64, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID CHAIN_ID) (null.Time, error) + FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID CHAIN_ID) (null.Int, error) GetTxInProgress(ctx context.Context, fromAddress ADDR) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetInProgressTxAttempts(ctx context.Context, address ADDR, chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetNonFatalTransactions(ctx context.Context, chainID CHAIN_ID) (txs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index e36ca611e1..730809e8dd 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -1131,6 +1131,39 @@ ORDER BY nonce ASC return etxs, pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed") } +func (o *evmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID *big.Int) (broadcastAt nullv4.Time, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Transaction(func(tx pg.Queryer) error { + if err = qq.QueryRowContext(ctx, `SELECT min(initial_broadcast_at) FROM evm.txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, chainID.String()).Scan(&broadcastAt); err != nil { + return fmt.Errorf("failed to query for unconfirmed eth_tx count: %w", err) + } + return nil + }, pg.OptReadOnlyTx()) + return broadcastAt, err +} + +func (o *evmTxStore) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID *big.Int) (earliestUnconfirmedTxBlock nullv4.Int, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Transaction(func(tx pg.Queryer) error { + err = qq.QueryRowContext(ctx, ` +SELECT MIN(broadcast_before_block_num) FROM evm.tx_attempts +JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id +WHERE evm.txes.state = 'unconfirmed' +AND evm_chain_id = $1`, chainID.String()).Scan(&earliestUnconfirmedTxBlock) + if err != nil { + return fmt.Errorf("failed to query for earliest unconfirmed tx block: %w", err) + } + return nil + }, pg.OptReadOnlyTx()) + return earliestUnconfirmedTxBlock, err +} + func (o *evmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int) (finalized bool, err error) { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) @@ -1733,6 +1766,20 @@ func (o *evmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddre return o.countTransactionsWithState(ctx, fromAddress, txmgr.TxUnconfirmed, chainID) } +// CountTransactionsByState returns the number of transactions with any fromAddress in the given state +func (o *evmTxStore) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState, chainID *big.Int) (count uint32, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Get(&count, `SELECT count(*) FROM evm.txes WHERE state = $1 AND evm_chain_id = $2`, + state, chainID.String()) + if err != nil { + return 0, fmt.Errorf("failed to CountTransactionsByState: %w", err) + } + return count, nil +} + // CountUnstartedTransactions returns the number of unconfirmed transactions func (o *evmTxStore) CountUnstartedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (count uint32, err error) { return o.countTransactionsWithState(ctx, fromAddress, txmgr.TxUnstarted, chainID) diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index e68641735e..0b4287b6f6 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -847,6 +847,61 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { }) } +func TestORM_FindEarliestUnconfirmedBroadcastTime(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := newTestChainScopedConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + + t.Run("no unconfirmed eth txes", func(t *testing.T) { + broadcastAt, err := txStore.FindEarliestUnconfirmedBroadcastTime(testutils.Context(t), ethClient.ConfiguredChainID()) + require.NoError(t, err) + require.False(t, broadcastAt.Valid) + }) + + t.Run("verify broadcast time", func(t *testing.T) { + tx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 123, fromAddress) + broadcastAt, err := txStore.FindEarliestUnconfirmedBroadcastTime(testutils.Context(t), ethClient.ConfiguredChainID()) + require.NoError(t, err) + require.True(t, broadcastAt.Ptr().Equal(*tx.BroadcastAt)) + }) +} + +func TestORM_FindEarliestUnconfirmedTxAttemptBlock(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := newTestChainScopedConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, fromAddress2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + + t.Run("no earliest unconfirmed tx block", func(t *testing.T) { + earliestBlock, err := txStore.FindEarliestUnconfirmedTxAttemptBlock(testutils.Context(t), ethClient.ConfiguredChainID()) + require.NoError(t, err) + require.False(t, earliestBlock.Valid) + }) + + t.Run("verify earliest unconfirmed tx block", func(t *testing.T) { + var blockNum int64 = 2 + tx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 123, blockNum, time.Now(), fromAddress) + _ = mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 123, blockNum, time.Now().Add(time.Minute), fromAddress2) + err := txStore.UpdateTxsUnconfirmed(testutils.Context(t), []int64{tx.ID}) + require.NoError(t, err) + + earliestBlock, err := txStore.FindEarliestUnconfirmedTxAttemptBlock(testutils.Context(t), ethClient.ConfiguredChainID()) + require.NoError(t, err) + require.True(t, earliestBlock.Valid) + require.Equal(t, blockNum, earliestBlock.Int64) + }) +} + func TestORM_SaveInsufficientEthAttempt(t *testing.T) { t.Parallel() @@ -1511,6 +1566,27 @@ func TestORM_CountUnconfirmedTransactions(t *testing.T) { assert.Equal(t, int(count), 3) } +func TestORM_CountTransactionsByState(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewGeneralConfig(t, nil) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + _, fromAddress1 := cltest.MustInsertRandomKey(t, ethKeyStore) + _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) + _, fromAddress3 := cltest.MustInsertRandomKey(t, ethKeyStore) + + cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress1) + cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress2) + cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress3) + + count, err := txStore.CountTransactionsByState(testutils.Context(t), txmgrcommon.TxUnconfirmed, &cltest.FixtureChainID) + require.NoError(t, err) + assert.Equal(t, int(count), 3) +} + func TestORM_CountUnstartedTransactions(t *testing.T) { t.Parallel() diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 00efc1add9..bf3088b2aa 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -14,6 +14,8 @@ import ( mock "github.com/stretchr/testify/mock" + null "gopkg.in/guregu/null.v4" + time "time" types "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -59,6 +61,30 @@ func (_m *EvmTxStore) Close() { _m.Called() } +// CountTransactionsByState provides a mock function with given fields: ctx, state, chainID +func (_m *EvmTxStore) CountTransactionsByState(ctx context.Context, state types.TxState, chainID *big.Int) (uint32, error) { + ret := _m.Called(ctx, state, chainID) + + var r0 uint32 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, types.TxState, *big.Int) (uint32, error)); ok { + return rf(ctx, state, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, types.TxState, *big.Int) uint32); ok { + r0 = rf(ctx, state, chainID) + } else { + r0 = ret.Get(0).(uint32) + } + + if rf, ok := ret.Get(1).(func(context.Context, types.TxState, *big.Int) error); ok { + r1 = rf(ctx, state, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // CountUnconfirmedTransactions provides a mock function with given fields: ctx, fromAddress, chainID func (_m *EvmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) @@ -145,6 +171,54 @@ func (_m *EvmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt types return r0 } +// FindEarliestUnconfirmedBroadcastTime provides a mock function with given fields: ctx, chainID +func (_m *EvmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID *big.Int) (null.Time, error) { + ret := _m.Called(ctx, chainID) + + var r0 null.Time + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (null.Time, error)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) null.Time); ok { + r0 = rf(ctx, chainID) + } else { + r0 = ret.Get(0).(null.Time) + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindEarliestUnconfirmedTxAttemptBlock provides a mock function with given fields: ctx, chainID +func (_m *EvmTxStore) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID *big.Int) (null.Int, error) { + ret := _m.Called(ctx, chainID) + + var r0 null.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (null.Int, error)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) null.Int); ok { + r0 = rf(ctx, chainID) + } else { + r0 = ret.Get(0).(null.Int) + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindLatestSequence provides a mock function with given fields: ctx, fromAddress, chainId func (_m *EvmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (evmtypes.Nonce, error) { ret := _m.Called(ctx, fromAddress, chainId) diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index d49e94557e..073b3ba246 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/jmoiron/sqlx" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -409,6 +411,18 @@ func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg } +func NewLegacyChainsWithMockChainAndTxManager(t testing.TB, ethClient evmclient.Client, cfg legacyevm.AppConfig, txm txmgr.TxManager) legacyevm.LegacyChainContainer { + ch := new(evmmocks.Chain) + ch.On("Client").Return(ethClient) + ch.On("Logger").Return(logger.TestLogger(t)) + scopedCfg := evmtest.NewChainScopedConfig(t, cfg) + ch.On("ID").Return(scopedCfg.EVM().ChainID()) + ch.On("Config").Return(scopedCfg) + ch.On("TxManager").Return(txm) + + return NewLegacyChainsWithChain(ch, cfg) +} + func NewLegacyChainsWithChain(ch legacyevm.Chain, cfg legacyevm.AppConfig) legacyevm.LegacyChainContainer { m := map[string]legacyevm.Chain{ch.ID().String(): ch} return legacyevm.NewLegacyChains(m, cfg.EVMConfigs()) diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 3d06789e7b..1c9cd106ba 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -238,11 +238,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger.Info("DatabaseBackup: periodic database backups are disabled. To enable automatic backups, set Database.Backup.Mode=lite or Database.Backup.Mode=full") } - srvcs = append(srvcs, eventBroadcaster, mailMon) - srvcs = append(srvcs, relayerChainInterops.Services()...) - promReporter := promreporter.NewPromReporter(db.DB, globalLogger) - srvcs = append(srvcs, promReporter) - // pool must be started before all relayers and stopped after them srvcs = append(srvcs, opts.MercuryPool) @@ -254,6 +249,11 @@ func NewApplication(opts ApplicationOpts) (Application, error) { return nil, fmt.Errorf("no evm chains found") } + srvcs = append(srvcs, eventBroadcaster, mailMon) + srvcs = append(srvcs, relayerChainInterops.Services()...) + promReporter := promreporter.NewPromReporter(db.DB, legacyEVMChains, globalLogger) + srvcs = append(srvcs, promReporter) + // Initialize Local Users ORM and Authentication Provider specified in config // BasicAdminUsersORM is initialized and required regardless of separate Authentication Provider localAdminUsersORM := localauth.NewORM(db, cfg.WebServer().SessionTimeout().Duration(), globalLogger, cfg.Database(), auditLogger) diff --git a/core/services/promreporter/prom_reporter.go b/core/services/promreporter/prom_reporter.go index d115b1022c..3e1444a6da 100644 --- a/core/services/promreporter/prom_reporter.go +++ b/core/services/promreporter/prom_reporter.go @@ -3,18 +3,22 @@ package promreporter import ( "context" "database/sql" + "fmt" "math/big" "sync" "time" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" - "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/services" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -24,6 +28,7 @@ type ( promReporter struct { services.StateMachine db *sql.DB + chains legacyevm.LegacyChainContainer lggr logger.Logger backend PrometheusBackend newHeads *utils.Mailbox[*evmtypes.Head] @@ -86,7 +91,7 @@ func (defaultBackend) SetPipelineTaskRunsQueued(n int) { promPipelineRunsQueued.Set(float64(n)) } -func NewPromReporter(db *sql.DB, lggr logger.Logger, opts ...interface{}) *promReporter { +func NewPromReporter(db *sql.DB, chainContainer legacyevm.LegacyChainContainer, lggr logger.Logger, opts ...interface{}) *promReporter { var backend PrometheusBackend = defaultBackend{} period := 15 * time.Second for _, opt := range opts { @@ -101,6 +106,7 @@ func NewPromReporter(db *sql.DB, lggr logger.Logger, opts ...interface{}) *promR chStop := make(chan struct{}) return &promReporter{ db: db, + chains: chainContainer, lggr: lggr.Named("PromReporter"), backend: backend, newHeads: utils.NewSingleMailbox[*evmtypes.Head](), @@ -161,6 +167,14 @@ func (pr *promReporter) eventLoop() { } } +func (pr *promReporter) getTxm(evmChainID *big.Int) (txmgr.TxManager, error) { + chain, err := pr.chains.Get(evmChainID.String()) + if err != nil { + return nil, fmt.Errorf("failed to get chain: %w", err) + } + return chain.TxManager(), nil +} + func (pr *promReporter) reportHeadMetrics(ctx context.Context, head *evmtypes.Head) { evmChainID := head.EVMChainID.ToInt() err := multierr.Combine( @@ -175,40 +189,49 @@ func (pr *promReporter) reportHeadMetrics(ctx context.Context, head *evmtypes.He } func (pr *promReporter) reportPendingEthTxes(ctx context.Context, evmChainID *big.Int) (err error) { - var unconfirmed int64 - if err := pr.db.QueryRowContext(ctx, `SELECT count(*) FROM evm.txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, evmChainID.String()).Scan(&unconfirmed); err != nil { - return errors.Wrap(err, "failed to query for unconfirmed eth_tx count") + txm, err := pr.getTxm(evmChainID) + if err != nil { + return fmt.Errorf("failed to get txm: %w", err) + } + + unconfirmed, err := txm.CountTransactionsByState(ctx, txmgrcommon.TxUnconfirmed) + if err != nil { + return fmt.Errorf("failed to query for unconfirmed eth_tx count: %w", err) } - pr.backend.SetUnconfirmedTransactions(evmChainID, unconfirmed) + pr.backend.SetUnconfirmedTransactions(evmChainID, int64(unconfirmed)) return nil } func (pr *promReporter) reportMaxUnconfirmedAge(ctx context.Context, evmChainID *big.Int) (err error) { - var broadcastAt null.Time - now := time.Now() - if err := pr.db.QueryRowContext(ctx, `SELECT min(initial_broadcast_at) FROM evm.txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, evmChainID.String()).Scan(&broadcastAt); err != nil { - return errors.Wrap(err, "failed to query for unconfirmed eth_tx count") + txm, err := pr.getTxm(evmChainID) + if err != nil { + return fmt.Errorf("failed to get txm: %w", err) } + + broadcastAt, err := txm.FindEarliestUnconfirmedBroadcastTime(ctx) + if err != nil { + return fmt.Errorf("failed to query for min broadcast time: %w", err) + } + var seconds float64 if broadcastAt.Valid { - nanos := now.Sub(broadcastAt.ValueOrZero()) - seconds = float64(nanos) / 1000000000 + seconds = time.Since(broadcastAt.ValueOrZero()).Seconds() } pr.backend.SetMaxUnconfirmedAge(evmChainID, seconds) return nil } func (pr *promReporter) reportMaxUnconfirmedBlocks(ctx context.Context, head *evmtypes.Head) (err error) { - var earliestUnconfirmedTxBlock null.Int - err = pr.db.QueryRowContext(ctx, ` -SELECT MIN(broadcast_before_block_num) FROM evm.tx_attempts -JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id -WHERE evm.txes.state = 'unconfirmed' -AND evm_chain_id = $1 -AND evm.txes.state = 'unconfirmed'`, head.EVMChainID.String()).Scan(&earliestUnconfirmedTxBlock) + txm, err := pr.getTxm(head.EVMChainID.ToInt()) if err != nil { - return errors.Wrap(err, "failed to query for min broadcast_before_block_num") + return fmt.Errorf("failed to get txm: %w", err) } + + earliestUnconfirmedTxBlock, err := txm.FindEarliestUnconfirmedTxAttemptBlock(ctx) + if err != nil { + return fmt.Errorf("failed to query for earliest unconfirmed tx block: %w", err) + } + var blocksUnconfirmed int64 if !earliestUnconfirmedTxBlock.IsZero() { blocksUnconfirmed = head.Number - earliestUnconfirmedTxBlock.ValueOrZero() diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 1f15d94418..54e3a5d3fa 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -6,15 +6,21 @@ import ( "testing" "time" + "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" @@ -25,12 +31,38 @@ func newHead() evmtypes.Head { return evmtypes.Head{Number: 42, EVMChainID: utils.NewBigI(0)} } +func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer { + config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) + keyStore := cltest.NewKeyStore(t, db, dbConfig).Eth() + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) + lggr := logger.TestLogger(t) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), ethClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) + + txm, err := txmgr.NewTxm( + db, + evmConfig, + evmConfig.GasEstimator(), + evmConfig.Transactions(), + dbConfig, + dbConfig.Listener(), + ethClient, + lggr, + lp, + keyStore, + estimator) + require.NoError(t, err) + + cfg := configtest.NewGeneralConfig(t, nil) + return cltest.NewLegacyChainsWithMockChainAndTxManager(t, ethClient, cfg, txm) +} + func Test_PromReporter_OnNewLongestChain(t *testing.T) { t.Run("with nothing in the database", func(t *testing.T) { - d := pgtest.NewSqlDB(t) + db := pgtest.NewSqlxDB(t) backend := mocks.NewPrometheusBackend(t) - reporter := promreporter.NewPromReporter(d, logger.TestLogger(t), backend, 10*time.Millisecond) + reporter := promreporter.NewPromReporter(db.DB, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond) var subscribeCalls atomic.Int32 @@ -74,7 +106,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { subscribeCalls.Add(1) }). Return() - reporter := promreporter.NewPromReporter(db.DB, logger.TestLogger(t), backend, 10*time.Millisecond) + reporter := promreporter.NewPromReporter(db.DB, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond) require.NoError(t, reporter.Start(testutils.Context(t))) defer func() { assert.NoError(t, reporter.Close()) }() @@ -91,11 +123,10 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { t.Run("with unfinished pipeline task runs", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_task_runs_pipeline_run_id_fkey DEFERRED`) backend := mocks.NewPrometheusBackend(t) - reporter := promreporter.NewPromReporter(db.DB, logger.TestLogger(t), backend, 10*time.Millisecond) + reporter := promreporter.NewPromReporter(db.DB, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond) cltest.MustInsertUnfinishedPipelineTaskRun(t, db, 1) cltest.MustInsertUnfinishedPipelineTaskRun(t, db, 1) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 929fec5a3e..6af224157a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -56,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- `PromReporter` no longer directly reads txm related status from the db, and instead uses the txStore API. - `L2Suggested` mode is now called `SuggestedPrice` - Console logs will now escape (non-whitespace) control characters From 55b696ede4ae36993f20f449a549a641f7c7aab7 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 30 Nov 2023 15:54:23 -0500 Subject: [PATCH 238/327] FUN-1130: Move Functions Coordinator v1.1 to production folder (#11431) --- .../functions/v1_1_0/FunctionsBilling.sol | 391 ++++++++++++++++++ .../functions/v1_1_0/FunctionsCoordinator.sol | 184 +++++++++ .../v1_1_0/libraries/ChainSpecificUtil.sol | 78 ++++ .../functions/v1_1_0/ocr/OCR2Abstract.sol | 103 +++++ .../v0.8/functions/v1_1_0/ocr/OCR2Base.sol | 351 ++++++++++++++++ 5 files changed, 1107 insertions(+) create mode 100644 contracts/src/v0.8/functions/v1_1_0/FunctionsBilling.sol create mode 100644 contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol create mode 100644 contracts/src/v0.8/functions/v1_1_0/libraries/ChainSpecificUtil.sol create mode 100644 contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Abstract.sol create mode 100644 contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol diff --git a/contracts/src/v0.8/functions/v1_1_0/FunctionsBilling.sol b/contracts/src/v0.8/functions/v1_1_0/FunctionsBilling.sol new file mode 100644 index 0000000000..ff34500374 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_1_0/FunctionsBilling.sol @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsSubscriptions} from "../v1_0_0/interfaces/IFunctionsSubscriptions.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; +import {IFunctionsBilling} from "../v1_0_0/interfaces/IFunctionsBilling.sol"; + +import {Routable} from "../v1_0_0/Routable.sol"; +import {FunctionsResponse} from "../v1_0_0/libraries/FunctionsResponse.sol"; + +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; + +import {ChainSpecificUtil} from "./libraries/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 { + using FunctionsResponse for FunctionsResponse.RequestMeta; + using FunctionsResponse for FunctionsResponse.Commitment; + 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 | + // ================================================================ + + mapping(bytes32 requestId => bytes32 commitmentHash) private s_requestCommitments; + + event CommitmentDeleted(bytes32 requestId); + + // ================================================================ + // | Configuration state | + // ================================================================ + + struct Config { + uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) + uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. + uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. + uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. + uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. + uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request + uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. + uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale + uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out + } + + Config private s_config; + + event ConfigUpdated(Config config); + + error UnsupportedRequestDataVersion(); + error InsufficientBalance(); + error InvalidSubscription(); + error UnauthorizedSender(); + error MustBeSubOwner(address owner); + error InvalidLinkWeiPrice(int256 linkWei); + error PaymentTooLarge(); + error NoTransmittersSet(); + error InvalidCalldata(); + + // ================================================================ + // | Balance state | + // ================================================================ + + mapping(address transmitter => uint96 balanceJuelsLink) private s_withdrawableTokens; + // Pool together collected DON fees + // Disperse them on withdrawal or change in OCR configuration + uint96 internal s_feePool; + + AggregatorV3Interface private s_linkToNativeFeed; + + // ================================================================ + // | Initialization | + // ================================================================ + constructor(address router, Config memory config, address linkToNativeFeed) Routable(router) { + s_linkToNativeFeed = AggregatorV3Interface(linkToNativeFeed); + + updateConfig(config); + } + + // ================================================================ + // | Configuration | + // ================================================================ + + /// @notice Gets the Chainlink Coordinator's billing configuration + /// @return config + function getConfig() external view returns (Config memory) { + return s_config; + } + + /// @notice Sets the Chainlink Coordinator's billing configuration + /// @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information + function updateConfig(Config memory config) public { + _onlyOwner(); + + s_config = config; + emit ConfigUpdated(config); + } + + // ================================================================ + // | Fee Calculation | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function getDONFee(bytes memory /* requestData */) public view override returns (uint72) { + return s_config.donFee; + } + + /// @inheritdoc IFunctionsBilling + function getAdminFee() public view override returns (uint72) { + return _getRouter().getAdminFee(); + } + + /// @inheritdoc IFunctionsBilling + function getWeiPerUnitLink() public view returns (uint256) { + Config memory config = s_config; + (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); + // solhint-disable-next-line not-rely-on-time + if (config.feedStalenessSeconds < block.timestamp - timestamp && config.feedStalenessSeconds > 0) { + return config.fallbackNativePerUnitLink; + } + if (weiPerUnitLink <= 0) { + revert InvalidLinkWeiPrice(weiPerUnitLink); + } + return uint256(weiPerUnitLink); + } + + 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 * amountWei) / getWeiPerUnitLink()); + } + + // ================================================================ + // | Cost Estimation | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function estimateCost( + uint64 subscriptionId, + bytes calldata data, + uint32 callbackGasLimit, + uint256 gasPriceWei + ) external view override returns (uint96) { + _getRouter().isValidCallbackGasLimit(subscriptionId, callbackGasLimit); + // Reasonable ceilings to prevent integer overflows + if (gasPriceWei > REASONABLE_GAS_PRICE_CEILING) { + revert InvalidCalldata(); + } + uint72 adminFee = getAdminFee(); + uint72 donFee = getDONFee(data); + return _calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee); + } + + /// @notice Estimate the cost in Juels of LINK + // that will be charged to a subscription to fulfill a Functions request + // Gas Price can be overestimated to account for flucuations between request and response time + function _calculateCostEstimate( + uint32 callbackGasLimit, + uint256 gasPriceWei, + uint72 donFee, + uint72 adminFee + ) internal view returns (uint96) { + // 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; + } + + uint256 gasPriceWithOverestimation = gasPriceWei + + ((gasPriceWei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); + /// @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units + + 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 estimatedGasReimbursementJuels + feesJuels; + } + + // ================================================================ + // | Billing | + // ================================================================ + + /// @notice Initiate the billing process for an Functions request + /// @dev Only callable by the Functions Router + /// @param request - Chainlink Functions request data, see FunctionsResponse.RequestMeta for the structure + /// @return commitment - The parameters of the request that must be held consistent at response time + function _startBilling( + FunctionsResponse.RequestMeta memory request + ) internal returns (FunctionsResponse.Commitment memory commitment) { + Config memory config = s_config; + + // Nodes should support all past versions of the structure + if (request.dataVersion > config.maxSupportedRequestDataVersion) { + revert UnsupportedRequestDataVersion(); + } + + uint72 donFee = getDONFee(request.data); + uint96 estimatedTotalCostJuels = _calculateCostEstimate( + request.callbackGasLimit, + tx.gasprice, + donFee, + request.adminFee + ); + + // Check that subscription can afford the estimated cost + if ((request.availableBalance) < estimatedTotalCostJuels) { + revert InsufficientBalance(); + } + + uint32 timeoutTimestamp = uint32(block.timestamp + config.requestTimeoutSeconds); + bytes32 requestId = keccak256( + abi.encode( + address(this), + request.requestingContract, + request.subscriptionId, + request.initiatedRequests + 1, + keccak256(request.data), + request.dataVersion, + request.callbackGasLimit, + estimatedTotalCostJuels, + timeoutTimestamp, + // solhint-disable-next-line avoid-tx-origin + tx.origin + ) + ); + + commitment = FunctionsResponse.Commitment({ + adminFee: request.adminFee, + coordinator: address(this), + client: request.requestingContract, + subscriptionId: request.subscriptionId, + callbackGasLimit: request.callbackGasLimit, + estimatedTotalCostJuels: estimatedTotalCostJuels, + timeoutTimestamp: timeoutTimestamp, + requestId: requestId, + donFee: donFee, + gasOverheadBeforeCallback: config.gasOverheadBeforeCallback, + gasOverheadAfterCallback: config.gasOverheadAfterCallback + }); + + s_requestCommitments[requestId] = keccak256(abi.encode(commitment)); + + return commitment; + } + + /// @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription + /// @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 + function _fulfillAndBill( + bytes32 requestId, + bytes memory response, + bytes memory err, + bytes memory onchainMetadata, + 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)); + + uint256 gasOverheadWei = (commitment.gasOverheadBeforeCallback + commitment.gasOverheadAfterCallback) * tx.gasprice; + 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, + juelsPerGas, + gasOverheadJuels + commitment.donFee, // cost without callback or admin fee, those will be added by the Router + msg.sender, + commitment + ); + + // The router will only pay the DON on successfully processing the fulfillment + // In these two fulfillment results the user has been charged + // Otherwise, the Coordinator should hold on to the request commitment + if ( + resultCode == FunctionsResponse.FulfillResult.FULFILLED || + resultCode == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR + ) { + delete s_requestCommitments[requestId]; + // Reimburse the transmitter for the fulfillment gas cost + s_withdrawableTokens[msg.sender] = gasOverheadJuels + callbackCostJuels; + // 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; + } + + // ================================================================ + // | Request Timeout | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Router + /// @dev Used by FunctionsRouter.sol during timeout of a request + function deleteCommitment(bytes32 requestId) external override onlyRouter { + // Delete commitment + delete s_requestCommitments[requestId]; + emit CommitmentDeleted(requestId); + } + + // ================================================================ + // | Fund withdrawal | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function oracleWithdraw(address recipient, uint96 amount) external { + _disperseFeePool(); + + if (amount == 0) { + amount = s_withdrawableTokens[msg.sender]; + } else if (s_withdrawableTokens[msg.sender] < amount) { + revert InsufficientBalance(); + } + s_withdrawableTokens[msg.sender] -= amount; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(recipient, amount); + } + + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Coordinator owner + function oracleWithdrawAll() external { + _onlyOwner(); + _disperseFeePool(); + + address[] memory transmitters = _getTransmitters(); + + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < transmitters.length; ++i) { + uint96 balance = s_withdrawableTokens[transmitters[i]]; + if (balance > 0) { + s_withdrawableTokens[transmitters[i]] = 0; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); + } + } + } + + // Overriden in FunctionsCoordinator, which has visibility into transmitters + function _getTransmitters() internal view virtual returns (address[] memory); + + // DON fees are collected into a pool s_feePool + // When OCR configuration changes, or any oracle withdraws, this must be dispersed + function _disperseFeePool() internal { + if (s_feePool == 0) { + return; + } + // All transmitters are assumed to also be observers + // Pay out the DON fee to all transmitters + address[] memory transmitters = _getTransmitters(); + uint256 numberOfTransmitters = transmitters.length; + if (numberOfTransmitters == 0) { + revert NoTransmittersSet(); + } + uint96 feePoolShare = s_feePool / uint96(numberOfTransmitters); + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < numberOfTransmitters; ++i) { + s_withdrawableTokens[transmitters[i]] += feePoolShare; + } + s_feePool -= feePoolShare * uint96(numberOfTransmitters); + } + + // Overriden in FunctionsCoordinator.sol + function _onlyOwner() internal view virtual; +} diff --git a/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol new file mode 100644 index 0000000000..0a5da643a5 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsCoordinator} from "../v1_0_0/interfaces/IFunctionsCoordinator.sol"; +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; + +import {FunctionsBilling} from "./FunctionsBilling.sol"; +import {OCR2Base} from "./ocr/OCR2Base.sol"; +import {FunctionsResponse} from "../v1_0_0/libraries/FunctionsResponse.sol"; + +/// @title Functions Coordinator contract +/// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with +contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling { + using FunctionsResponse for FunctionsResponse.RequestMeta; + using FunctionsResponse for FunctionsResponse.Commitment; + using FunctionsResponse for FunctionsResponse.FulfillResult; + + /// @inheritdoc ITypeAndVersion + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "Functions Coordinator v1.1.0"; + + event OracleRequest( + bytes32 indexed requestId, + address indexed requestingContract, + address requestInitiator, + uint64 subscriptionId, + address subscriptionOwner, + bytes data, + uint16 dataVersion, + bytes32 flags, + uint64 callbackGasLimit, + FunctionsResponse.Commitment commitment + ); + event OracleResponse(bytes32 indexed requestId, address transmitter); + + error InconsistentReportData(); + error EmptyPublicKey(); + error UnauthorizedPublicKeyChange(); + + bytes private s_donPublicKey; + bytes private s_thresholdPublicKey; + + constructor( + address router, + Config memory config, + address linkToNativeFeed + ) OCR2Base() FunctionsBilling(router, config, linkToNativeFeed) {} + + /// @inheritdoc IFunctionsCoordinator + function getThresholdPublicKey() external view override returns (bytes memory) { + if (s_thresholdPublicKey.length == 0) { + revert EmptyPublicKey(); + } + return s_thresholdPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function setThresholdPublicKey(bytes calldata thresholdPublicKey) external override onlyOwner { + if (thresholdPublicKey.length == 0) { + revert EmptyPublicKey(); + } + s_thresholdPublicKey = thresholdPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function getDONPublicKey() external view override returns (bytes memory) { + if (s_donPublicKey.length == 0) { + revert EmptyPublicKey(); + } + return s_donPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { + if (donPublicKey.length == 0) { + revert EmptyPublicKey(); + } + s_donPublicKey = donPublicKey; + } + + /// @dev check if node is in current transmitter list + function _isTransmitter(address node) internal view returns (bool) { + address[] memory nodes = s_transmitters; + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < nodes.length; ++i) { + if (nodes[i] == node) { + return true; + } + } + return false; + } + + /// @inheritdoc IFunctionsCoordinator + function startRequest( + FunctionsResponse.RequestMeta calldata request + ) external override onlyRouter returns (FunctionsResponse.Commitment memory commitment) { + commitment = _startBilling(request); + + emit OracleRequest( + commitment.requestId, + request.requestingContract, + // solhint-disable-next-line avoid-tx-origin + tx.origin, + request.subscriptionId, + request.subscriptionOwner, + request.data, + request.dataVersion, + request.flags, + request.callbackGasLimit, + commitment + ); + + return commitment; + } + + /// @dev DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. + function _beforeSetConfig(uint8 /* _f */, bytes memory /* _onchainConfig */) internal override { + if (_getTransmitters().length > 0) { + _disperseFeePool(); + } + } + + /// @dev Used by FunctionsBilling.sol + function _getTransmitters() internal view override returns (address[] memory) { + return s_transmitters; + } + + /// @dev Report hook called within OCR2Base.sol + function _report( + uint256 /*initialGas*/, + address /*transmitter*/, + uint8 /*signerCount*/, + address[MAX_NUM_ORACLES] memory /*signers*/, + bytes calldata report + ) internal override { + ( + bytes32[] memory requestIds, + bytes[] memory results, + bytes[] memory errors, + bytes[] memory onchainMetadata, + bytes[] memory offchainMetadata + ) = abi.decode(report, (bytes32[], bytes[], bytes[], bytes[], bytes[])); + uint256 numberOfFulfillments = uint8(requestIds.length); + + if ( + numberOfFulfillments == 0 || + numberOfFulfillments != results.length || + numberOfFulfillments != errors.length || + numberOfFulfillments != onchainMetadata.length || + numberOfFulfillments != offchainMetadata.length + ) { + revert ReportInvalid("Fields must be equal length"); + } + + // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig + for (uint256 i = 0; i < numberOfFulfillments; ++i) { + FunctionsResponse.FulfillResult result = FunctionsResponse.FulfillResult( + _fulfillAndBill( + requestIds[i], + results[i], + errors[i], + onchainMetadata[i], + offchainMetadata[i], + uint8(numberOfFulfillments) // will not exceed "MaxRequestBatchSize" on the Job's ReportingPluginConfig + ) + ); + + // Emit on successfully processing the fulfillment + // In these two fulfillment results the user has been charged + // Otherwise, the DON will re-try + if ( + result == FunctionsResponse.FulfillResult.FULFILLED || + result == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR + ) { + emit OracleResponse(requestIds[i], msg.sender); + } + } + } + + /// @dev Used in FunctionsBilling.sol + function _onlyOwner() internal view override { + _validateOwnership(); + } +} diff --git a/contracts/src/v0.8/functions/v1_1_0/libraries/ChainSpecificUtil.sol b/contracts/src/v0.8/functions/v1_1_0/libraries/ChainSpecificUtil.sol new file mode 100644 index 0000000000..68d346e676 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_1_0/libraries/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 {GasPriceOracle} from "../../../vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/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 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); + GasPriceOracle private constant OVM_GASPRICEORACLE = 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 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/v1_1_0/ocr/OCR2Abstract.sol b/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Abstract.sol new file mode 100644 index 0000000000..4182227d64 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Abstract.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; + +abstract contract OCR2Abstract is ITypeAndVersion { + // Maximum number of oracles the offchain reporting protocol is designed for + uint256 internal constant MAX_NUM_ORACLES = 31; + + /** + * @notice triggers a new run of the offchain reporting protocol + * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis + * @param configDigest configDigest of this configuration + * @param configCount ordinal number of this config setting among all config settings over the life of this contract + * @param signers ith element is address ith oracle uses to sign a report + * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method + * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly + * @param onchainConfig serialized configuration used by the contract (and possibly oracles) + * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter + * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract + */ + event ConfigSet( + uint32 previousConfigBlockNumber, + bytes32 configDigest, + uint64 configCount, + address[] signers, + address[] transmitters, + uint8 f, + bytes onchainConfig, + uint64 offchainConfigVersion, + bytes offchainConfig + ); + + /** + * @notice sets offchain reporting protocol configuration incl. participating oracles + * @param signers addresses with which oracles sign the reports + * @param transmitters addresses oracles use to transmit the reports + * @param f number of faulty oracles the system can tolerate + * @param onchainConfig serialized configuration used by the contract (and possibly oracles) + * @param offchainConfigVersion version number for offchainEncoding schema + * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract + */ + function setConfig( + address[] memory signers, + address[] memory transmitters, + uint8 f, + bytes memory onchainConfig, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external virtual; + + /** + * @notice information about current offchain reporting protocol configuration + * @return configCount ordinal number of current config, out of all configs applied to this contract so far + * @return blockNumber block at which this config was set + * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) + */ + function latestConfigDetails() + external + view + virtual + returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); + + /** + * @notice optionally emited to indicate the latest configDigest and epoch for + which a report was successfully transmited. Alternatively, the contract may + use latestConfigDigestAndEpoch with scanLogs set to false. + */ + event Transmitted(bytes32 configDigest, uint32 epoch); + + /** + * @notice optionally returns the latest configDigest and epoch for which a + report was successfully transmitted. Alternatively, the contract may return + scanLogs set to true and use Transmitted events to provide this information + to offchain watchers. + * @return scanLogs indicates whether to rely on the configDigest and epoch + returned or whether to scan logs for the Transmitted event instead. + * @return configDigest + * @return epoch + */ + function latestConfigDigestAndEpoch() + external + view + virtual + returns (bool scanLogs, bytes32 configDigest, uint32 epoch); + + /** + * @notice transmit is called to post a new report to the contract + * @param report serialized report, which the signatures are signing. + * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries + * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries + * @param rawVs ith element is the the V component of the ith signature + */ + function transmit( + // NOTE: If these parameters are changed, expectedMsgDataLength and/or + // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly + bytes32[3] calldata reportContext, + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs // signatures + ) external virtual; +} diff --git a/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol new file mode 100644 index 0000000000..ea1d45ffd4 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {OCR2Abstract} from "./OCR2Abstract.sol"; + +/** + * @notice Onchain verification of reports from the offchain reporting protocol + * @dev For details on its operation, see the offchain reporting protocol design + * doc, which refers to this contract as simply the "contract". + */ +abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { + error ReportInvalid(string message); + error InvalidConfig(string message); + + constructor() ConfirmedOwner(msg.sender) {} + + // incremented each time a new config is posted. This count is incorporated + // into the config digest, to prevent replay attacks. + uint32 internal s_configCount; + uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems + // to extract config from logs. + + // Storing these fields used on the hot path in a ConfigInfo variable reduces the + // retrieval of all of them to a single SLOAD. If any further fields are + // added, make sure that storage of the struct still takes at most 32 bytes. + struct ConfigInfo { + bytes32 latestConfigDigest; + uint8 f; // TODO: could be optimized by squeezing into one slot + uint8 n; + } + ConfigInfo internal s_configInfo; + + // Used for s_oracles[a].role, where a is an address, to track the purpose + // of the address, or to indicate that the address is unset. + enum Role { + // No oracle role has been set for address a + Unset, + // Signing address for the s_oracles[a].index'th oracle. I.e., report + // signatures from this oracle should ecrecover back to address a. + Signer, + // Transmission address for the s_oracles[a].index'th oracle. I.e., if a + // report is received by OCR2Aggregator.transmit in which msg.sender is + // a, it is attributed to the s_oracles[a].index'th oracle. + Transmitter + } + + struct Oracle { + uint8 index; // Index of oracle in s_signers/s_transmitters + Role role; // Role of the address which mapped to this struct + } + + mapping(address signerOrTransmitter => Oracle) internal s_oracles; + + // s_signers contains the signing address of each oracle + address[] internal s_signers; + + // s_transmitters contains the transmission address of each oracle, + // i.e. the address the oracle actually sends transactions to the contract from + address[] internal s_transmitters; + + /* + * Config logic + */ + + // Reverts transaction if config args are invalid + modifier checkConfigValid( + uint256 numSigners, + uint256 numTransmitters, + uint256 f + ) { + if (numSigners > MAX_NUM_ORACLES) revert InvalidConfig("too many signers"); + if (f == 0) revert InvalidConfig("f must be positive"); + if (numSigners != numTransmitters) revert InvalidConfig("oracle addresses out of registration"); + if (numSigners <= 3 * f) revert InvalidConfig("faulty-oracle f too high"); + _; + } + + struct SetConfigArgs { + address[] signers; + address[] transmitters; + uint8 f; + bytes onchainConfig; + uint64 offchainConfigVersion; + bytes offchainConfig; + } + + /// @inheritdoc OCR2Abstract + function latestConfigDigestAndEpoch() + external + view + virtual + override + returns (bool scanLogs, bytes32 configDigest, uint32 epoch) + { + return (true, bytes32(0), uint32(0)); + } + + /** + * @notice sets offchain reporting protocol configuration incl. participating oracles + * @param _signers addresses with which oracles sign the reports + * @param _transmitters addresses oracles use to transmit the reports + * @param _f number of faulty oracles the system can tolerate + * @param _onchainConfig encoded on-chain contract configuration + * @param _offchainConfigVersion version number for offchainEncoding schema + * @param _offchainConfig encoded off-chain oracle configuration + */ + function setConfig( + address[] memory _signers, + address[] memory _transmitters, + uint8 _f, + bytes memory _onchainConfig, + uint64 _offchainConfigVersion, + bytes memory _offchainConfig + ) external override checkConfigValid(_signers.length, _transmitters.length, _f) onlyOwner { + SetConfigArgs memory args = SetConfigArgs({ + signers: _signers, + transmitters: _transmitters, + f: _f, + onchainConfig: _onchainConfig, + offchainConfigVersion: _offchainConfigVersion, + offchainConfig: _offchainConfig + }); + + _beforeSetConfig(args.f, args.onchainConfig); + + while (s_signers.length != 0) { + // remove any old signer/transmitter addresses + uint256 lastIdx = s_signers.length - 1; + address signer = s_signers[lastIdx]; + address transmitter = s_transmitters[lastIdx]; + delete s_oracles[signer]; + delete s_oracles[transmitter]; + s_signers.pop(); + s_transmitters.pop(); + } + + // 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 + if (s_oracles[args.signers[i]].role != Role.Unset) revert InvalidConfig("repeated signer address"); + s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); + 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]); + } + s_configInfo.f = args.f; + uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; + s_latestConfigBlockNumber = uint32(block.number); + s_configCount += 1; + { + s_configInfo.latestConfigDigest = _configDigestFromConfigData( + block.chainid, + address(this), + s_configCount, + args.signers, + args.transmitters, + args.f, + args.onchainConfig, + args.offchainConfigVersion, + args.offchainConfig + ); + } + s_configInfo.n = uint8(args.signers.length); + + emit ConfigSet( + previousConfigBlockNumber, + s_configInfo.latestConfigDigest, + s_configCount, + args.signers, + args.transmitters, + args.f, + args.onchainConfig, + args.offchainConfigVersion, + args.offchainConfig + ); + } + + function _configDigestFromConfigData( + uint256 _chainId, + address _contractAddress, + uint64 _configCount, + address[] memory _signers, + address[] memory _transmitters, + uint8 _f, + bytes memory _onchainConfig, + uint64 _encodedConfigVersion, + bytes memory _encodedConfig + ) internal pure returns (bytes32) { + uint256 h = uint256( + keccak256( + abi.encode( + _chainId, + _contractAddress, + _configCount, + _signers, + _transmitters, + _f, + _onchainConfig, + _encodedConfigVersion, + _encodedConfig + ) + ) + ); + uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 + uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 + return bytes32((prefix & prefixMask) | (h & ~prefixMask)); + } + + /** + * @notice information about current offchain reporting protocol configuration + * @return configCount ordinal number of current config, out of all configs applied to this contract so far + * @return blockNumber block at which this config was set + * @return configDigest domain-separation tag for current config (see __configDigestFromConfigData) + */ + function latestConfigDetails() + external + view + override + returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) + { + return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); + } + + /** + * @return list of addresses permitted to transmit reports to this contract + * @dev The list will match the order used to specify the transmitter during setConfig + */ + function transmitters() external view returns (address[] memory) { + return s_transmitters; + } + + function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; + + /** + * @dev hook called after the report has been fully validated + * for the extending contract to handle additional logic, such as oracle payment + * @param initialGas the amount of gas before validation + * @param transmitter the address of the account that submitted the report + * @param signers the addresses of all signing accounts + * @param report serialized report + */ + function _report( + uint256 initialGas, + address transmitter, + uint8 signerCount, + address[MAX_NUM_ORACLES] memory signers, + bytes calldata report + ) internal virtual; + + // The constant-length components of the msg.data sent to transmit. + // See the "If we wanted to call sam" example on for example reasoning + // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html + uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = + 4 + // function selector + 32 * + 3 + // 3 words containing reportContext + 32 + // word containing start location of abiencoded report value + 32 + // word containing location start of abiencoded rs value + 32 + // word containing start location of abiencoded ss value + 32 + // rawVs value + 32 + // word containing length of report + 32 + // word containing length rs + 32 + // word containing length of ss + 0; // placeholder + + function _requireExpectedMsgDataLength( + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss + ) private pure { + // calldata will never be big enough to make this overflow + uint256 expected = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) + + report.length + // one byte pure entry in _report + rs.length * + 32 + // 32 bytes per entry in _rs + ss.length * + 32 + // 32 bytes per entry in _ss + 0; // placeholder + if (msg.data.length != expected) revert ReportInvalid("calldata length mismatch"); + } + + /** + * @notice transmit is called to post a new report to the contract + * @param report serialized report, which the signatures are signing. + * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries + * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries + * @param rawVs ith element is the the V component of the ith signature + */ + function transmit( + // NOTE: If these parameters are changed, expectedMsgDataLength and/or + // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly + bytes32[3] calldata reportContext, + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs // signatures + ) external override { + uint256 initialGas = gasleft(); // This line must come first + + { + // reportContext consists of: + // reportContext[0]: ConfigDigest + // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round + // reportContext[2]: ExtraHash + bytes32 configDigest = reportContext[0]; + uint32 epochAndRound = uint32(uint256(reportContext[1])); + + emit Transmitted(configDigest, uint32(epochAndRound >> 8)); + + // 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 = (s_configInfo.n + s_configInfo.f) / 2 + 1; + + 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]; + if (transmitter.role != Role.Transmitter && msg.sender != s_transmitters[transmitter.index]) + revert ReportInvalid("unauthorized transmitter"); + } + + address[MAX_NUM_ORACLES] memory signed; + uint8 signerCount = 0; + + { + // Verify signatures attached to report + bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext)); + + Oracle memory o; + // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol + for (uint256 i = 0; i < rs.length; ++i) { + address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); + o = s_oracles[signer]; + 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; + } + } + + _report(initialGas, msg.sender, signerCount, signed, report); + } +} From 5b54684a0ef945949699ab55abfb96395cc63960 Mon Sep 17 00:00:00 2001 From: Tate Date: Thu, 30 Nov 2023 14:10:48 -0700 Subject: [PATCH 239/327] Bump chainlink-testing-framework to get postgres ecr changes (#11435) --- integration-tests/docker/test_env/cl_node.go | 9 ++++++--- integration-tests/docker/test_env/test_env.go | 5 ++++- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index c781ddfc1b..7dc077ad34 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -82,10 +82,13 @@ func WithLogWatch(lw *logwatch.LogWatch) ClNodeOption { } } -func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *chainlink.Config, opts ...ClNodeOption) *ClNode { +func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *chainlink.Config, opts ...ClNodeOption) (*ClNode, error) { nodeDefaultCName := fmt.Sprintf("%s-%s", "cl-node", uuid.NewString()[0:8]) pgDefaultCName := fmt.Sprintf("pg-%s", nodeDefaultCName) - pgDb := test_env.NewPostgresDb(networks, test_env.WithPostgresDbContainerName(pgDefaultCName)) + pgDb, err := test_env.NewPostgresDb(networks, test_env.WithPostgresDbContainerName(pgDefaultCName)) + if err != nil { + return nil, err + } n := &ClNode{ EnvComponent: test_env.EnvComponent{ ContainerName: nodeDefaultCName, @@ -102,7 +105,7 @@ func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *ch for _, opt := range opts { opt(n) } - return n + return n, nil } func (n *ClNode) SetTestLogger(t *testing.T) { diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 4b0cefddd5..030a3ae962 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -158,7 +158,10 @@ func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count i opts = append(opts, WithSecrets(secretsConfig)) te.ClCluster = &ClCluster{} for i := 0; i < count; i++ { - ocrNode := NewClNode([]string{te.Network.Name}, os.Getenv("CHAINLINK_IMAGE"), os.Getenv("CHAINLINK_VERSION"), nodeConfig, opts...) + ocrNode, err := NewClNode([]string{te.Network.Name}, os.Getenv("CHAINLINK_IMAGE"), os.Getenv("CHAINLINK_VERSION"), nodeConfig, opts...) + if err != nil { + return err + } te.ClCluster.Nodes = append(te.ClCluster.Nodes, ocrNode) } } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b03819e206..68b46d8a26 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -25,7 +25,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde - github.com/smartcontractkit/chainlink-testing-framework v1.19.7 + github.com/smartcontractkit/chainlink-testing-framework v1.20.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 74fe9e4dc4..46c132d6ff 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2386,8 +2386,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= -github.com/smartcontractkit/chainlink-testing-framework v1.19.7 h1:8oEduPXC5kBwnNwE5qdK+h/NZ2qOlxK0hgtedS+/St0= -github.com/smartcontractkit/chainlink-testing-framework v1.19.7/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= +github.com/smartcontractkit/chainlink-testing-framework v1.20.0 h1:gQPQRKJuMh6QTAIMkqZ7v5WkjEmbcoMIX/V6WPVrvuI= +github.com/smartcontractkit/chainlink-testing-framework v1.20.0/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= From 74e4c6819467c973e6dea77b651995d5702e0cc3 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Thu, 30 Nov 2023 22:30:40 +0100 Subject: [PATCH 240/327] Improve randomize testdb sequences (#11433) --- core/cmd/shell_local.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index dc0d44f318..a1f7fdb857 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -22,6 +22,7 @@ import ( gethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/fatih/color" + "github.com/lib/pq" "github.com/kylelemons/godebug/diff" "github.com/pkg/errors" @@ -834,7 +835,9 @@ func (m *failedToRandomizeTestDBSequencesError) Error() string { // randomizeTestDBSequences randomizes sequenced table columns sequence // This is necessary as to avoid false positives in some test cases. func randomizeTestDBSequences(db *sqlx.DB) error { - seqRows, err := db.Query(`SELECT sequence_schema, sequence_name FROM information_schema.sequences WHERE sequence_schema = $1`, "public") + // not ideal to hard code this, but also not safe to do it programmatically :( + schemas := pq.Array([]string{"public", "evm"}) + seqRows, err := db.Query(`SELECT sequence_schema, sequence_name, minimum_value FROM information_schema.sequences WHERE sequence_schema IN ($1)`, schemas) if err != nil { return fmt.Errorf("%s: error fetching sequences: %s", failedToRandomizeTestDBSequencesError{}, err) } @@ -842,7 +845,8 @@ func randomizeTestDBSequences(db *sqlx.DB) error { defer seqRows.Close() for seqRows.Next() { var sequenceSchema, sequenceName string - if err = seqRows.Scan(&sequenceSchema, &sequenceName); err != nil { + var minimumSequenceValue int64 + if err = seqRows.Scan(&sequenceSchema, &sequenceName, &minimumSequenceValue); err != nil { return fmt.Errorf("%s: failed scanning sequence rows: %s", failedToRandomizeTestDBSequencesError{}, err) } @@ -855,6 +859,7 @@ func randomizeTestDBSequences(db *sqlx.DB) error { if err != nil { return fmt.Errorf("%s: failed to generate random number", failedToRandomizeTestDBSequencesError{}) } + randNum.Add(randNum, big.NewInt(minimumSequenceValue)) if _, err = db.Exec(fmt.Sprintf("ALTER SEQUENCE %s.%s RESTART WITH %d", sequenceSchema, sequenceName, randNum)); err != nil { return fmt.Errorf("%s: failed to alter and restart %s sequence: %w", failedToRandomizeTestDBSequencesError{}, sequenceName, err) From 82eb917140a4eb27c398cbff67bf7bb57f05e7a2 Mon Sep 17 00:00:00 2001 From: ferglor <19188060+ferglor@users.noreply.github.com> Date: Thu, 30 Nov 2023 22:33:57 +0000 Subject: [PATCH 241/327] Refactor evm registry packages (#11374) --- core/scripts/chaincli/handler/debug.go | 6 ++--- core/scripts/chaincli/handler/keeper.go | 2 +- core/scripts/chaincli/handler/report.go | 2 +- core/services/ocr2/delegate.go | 4 ++-- .../plugins/ocr2keeper/custom_telemetry.go | 2 +- .../{evm20 => evmregistry/v20}/abi.go | 0 .../{evm20 => evmregistry/v20}/abi_test.go | 0 .../{evm20 => evmregistry/v20}/encoder.go | 0 .../v20}/encoder_test.go | 0 .../{evm20 => evmregistry/v20}/head.go | 0 .../v20}/log_provider.go | 1 + .../v20}/mocks/registry.go | 0 .../{evm20 => evmregistry/v20}/registry.go | 1 + .../v20}/registry_test.go | 0 .../{evm21 => evmregistry/v21}/active_list.go | 2 +- .../v21}/active_list_test.go | 2 +- .../v21}/autotelemetry21/custom_telemetry.go | 2 +- .../autotelemetry21/custom_telemetry_test.go | 2 +- .../v21}/block_subscriber.go | 0 .../v21}/block_subscriber_test.go | 0 .../{evm21 => evmregistry/v21}/core/abi.go | 0 .../v21}/core/interfaces.go | 0 .../v21}/core/mocks/upkeep_state_reader.go | 0 .../v21}/core/payload.go | 0 .../v21}/core/payload_test.go | 0 .../v21}/core/testutil.go | 0 .../v21}/core/trigger.go | 0 .../v21}/core/trigger_test.go | 0 .../{evm21 => evmregistry/v21}/core/type.go | 0 .../v21}/core/type_test.go | 0 .../{evm21 => evmregistry/v21}/core/utils.go | 0 .../v21}/core/utils_test.go | 0 .../v21}/encoding/encoder.go | 2 +- .../v21}/encoding/encoder_test.go | 2 +- .../v21}/encoding/interface.go | 3 +-- .../v21}/encoding/packer.go | 5 ++-- .../v21}/encoding/packer_test.go | 5 ++-- .../{evm21 => evmregistry/v21}/keyring.go | 0 .../v21}/keyring_test.go | 0 .../v21}/logprovider/block_time.go | 0 .../v21}/logprovider/block_time_test.go | 0 .../v21}/logprovider/buffer.go | 0 .../v21}/logprovider/buffer_test.go | 2 +- .../v21}/logprovider/factory.go | 2 +- .../v21}/logprovider/filter.go | 0 .../v21}/logprovider/filter_store.go | 0 .../v21}/logprovider/filter_store_test.go | 0 .../v21}/logprovider/filter_test.go | 0 .../v21}/logprovider/integration_test.go | 10 ++++---- .../v21}/logprovider/log_packer.go | 2 +- .../v21}/logprovider/provider.go | 3 ++- .../v21}/logprovider/provider_life_cycle.go | 0 .../logprovider/provider_life_cycle_test.go | 2 +- .../v21}/logprovider/provider_test.go | 0 .../v21}/logprovider/recoverer.go | 3 ++- .../v21}/logprovider/recoverer_test.go | 4 ++-- .../v21}/mercury/mercury.go | 0 .../v21}/mercury/mercury_test.go | 0 .../v21}/mercury/streams/streams.go | 8 +++---- .../v21}/mercury/streams/streams_test.go | 8 +++---- .../v21}/mercury/upkeep_failure_reasons.go | 0 .../v21}/mercury/upkeep_states.go | 0 .../v21}/mercury/v02/request.go | 2 +- .../v21}/mercury/v02/v02_request_test.go | 3 +-- .../v21}/mercury/v03/request.go | 2 +- .../v21}/mercury/v03/v03_request_test.go | 5 ++-- .../v21}/mocks/http_client.go | 0 .../v21}/mocks/registry.go | 0 .../v21}/payload_builder.go | 4 ++-- .../v21}/payload_builder_test.go | 4 ++-- .../{evm21 => evmregistry/v21}/registry.go | 8 +++---- .../v21}/registry_check_pipeline.go | 4 ++-- .../v21}/registry_check_pipeline_test.go | 6 ++--- .../v21}/registry_test.go | 6 ++--- .../{evm21 => evmregistry/v21}/services.go | 8 +++---- .../v21}/testdata/btc-usd.json | 0 .../v21}/testdata/eth-usd.json | 0 .../v21}/transmit/cache.go | 0 .../v21}/transmit/cache_test.go | 0 .../v21}/transmit/encoding.go | 0 .../v21}/transmit/encoding_test.go | 2 +- .../v21}/transmit/event_provider.go | 3 ++- .../v21}/transmit/event_provider_test.go | 2 +- .../v21}/upkeep_provider.go | 2 +- .../v21}/upkeep_provider_test.go | 2 +- .../v21}/upkeepstate/orm.go | 0 .../v21}/upkeepstate/orm_test.go | 0 .../v21}/upkeepstate/scanner.go | 2 +- .../v21}/upkeepstate/scanner_test.go | 0 .../v21}/upkeepstate/store.go | 3 ++- .../v21}/upkeepstate/store_test.go | 0 .../plugins/ocr2keeper/integration_21_test.go | 2 +- core/services/ocr2/plugins/ocr2keeper/util.go | 24 +++++++++---------- integration-tests/smoke/automation_test.go | 2 +- 94 files changed, 92 insertions(+), 91 deletions(-) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/abi.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/abi_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/encoder.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/encoder_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/head.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/log_provider.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/mocks/registry.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/registry.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm20 => evmregistry/v20}/registry_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/active_list.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/active_list_test.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/autotelemetry21/custom_telemetry.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/autotelemetry21/custom_telemetry_test.go (97%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/block_subscriber.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/block_subscriber_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/abi.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/interfaces.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/mocks/upkeep_state_reader.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/payload.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/payload_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/testutil.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/trigger.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/trigger_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/type.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/type_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/utils.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/core/utils_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/encoding/encoder.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/encoding/encoder_test.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/encoding/interface.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/encoding/packer.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/encoding/packer_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/keyring.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/keyring_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/block_time.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/block_time_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/buffer.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/buffer_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/factory.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/filter.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/filter_store.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/filter_store_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/filter_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/integration_test.go (97%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/log_packer.go (96%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/provider.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/provider_life_cycle.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/provider_life_cycle_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/provider_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/recoverer.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/logprovider/recoverer_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/mercury.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/mercury_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/streams/streams.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/streams/streams_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/upkeep_failure_reasons.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/upkeep_states.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/v02/request.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/v02/v02_request_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/v03/request.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mercury/v03/v03_request_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mocks/http_client.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/mocks/registry.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/payload_builder.go (95%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/payload_builder_test.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/registry.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/registry_check_pipeline.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/registry_check_pipeline_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/registry_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/services.go (96%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/testdata/btc-usd.json (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/testdata/eth-usd.json (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/transmit/cache.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/transmit/cache_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/transmit/encoding.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/transmit/encoding_test.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/transmit/event_provider.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/transmit/event_provider_test.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeep_provider.go (97%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeep_provider_test.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeepstate/orm.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeepstate/orm_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeepstate/scanner.go (98%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeepstate/scanner_test.go (100%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeepstate/store.go (99%) rename core/services/ocr2/plugins/ocr2keeper/{evm21 => evmregistry/v21}/upkeepstate/store_test.go (100%) diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 4938907669..fec8c6cd41 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -26,9 +26,9 @@ import ( "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/core/scripts/chaincli/handler/keeper.go b/core/scripts/chaincli/handler/keeper.go index 453ef43a56..439532430a 100644 --- a/core/scripts/chaincli/handler/keeper.go +++ b/core/scripts/chaincli/handler/keeper.go @@ -14,7 +14,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/umbracle/ethgo/abi" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" diff --git a/core/scripts/chaincli/handler/report.go b/core/scripts/chaincli/handler/report.go index 8381bbc137..622963f1ac 100644 --- a/core/scripts/chaincli/handler/report.go +++ b/core/scripts/chaincli/handler/report.go @@ -22,7 +22,7 @@ import ( ocr2keepers20 "github.com/smartcontractkit/chainlink-automation/pkg/v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" - evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm20" + evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20" ) type OCR2ReportDataElem struct { diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index af56c1e7a9..0234182137 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -50,8 +50,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21" - ocr2keeper21core "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21" + ocr2keeper21core "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" ocr2coordinator "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/coordinator" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin" diff --git a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go index fd43747f52..d250df4afe 100644 --- a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/abi.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/abi.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm20/abi.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/abi.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/abi_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/abi_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm20/abi_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/abi_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/encoder.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm20/encoder.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/encoder.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/encoder_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm20/encoder_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/encoder_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/head.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/head.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm20/head.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/head.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/log_provider.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/log_provider.go index 7ab641d2bf..45884d2f72 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/log_provider.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-automation/pkg/v2/encoding" "github.com/smartcontractkit/chainlink-common/pkg/services" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm20/mocks/registry.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm20/registry.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry.go index 682ebb6e2a..a6a2f40f85 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry.go @@ -20,6 +20,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm20/registry_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/active_list.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go index 9f82555633..7ea476ee77 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go @@ -6,7 +6,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) // ActiveUpkeepList is a list to manage active upkeep IDs diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/active_list_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go index 06b9979eef..378589d177 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/active_list_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go @@ -9,7 +9,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestActiveUpkeepList(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go index 0ed4c84dbb..e7e9728c3a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry_test.go similarity index 97% rename from core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry_test.go index 4318d9aac6..5fce8718cb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/autotelemetry21/custom_telemetry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry_test.go @@ -10,7 +10,7 @@ import ( headtracker "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" - evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" + evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" ) // const historySize = 4 diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/abi.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/abi.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/abi.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/abi.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/interfaces.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/interfaces.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/payload.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/testutil.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/testutil.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/type.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/type.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/type_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/type_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/utils.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/utils.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/utils_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/core/utils_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/utils_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go index fadf55633d..89fcbb4a0e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go @@ -7,7 +7,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) var ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go index 63ff2650be..1376e2a9bb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go @@ -9,7 +9,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestReportEncoder_EncodeExtract(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go index cf98115d76..83ace2492f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go @@ -5,10 +5,9 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) const ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go index 0157d1baf8..57013a6277 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go @@ -9,10 +9,9 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) // triggerWrapper is a wrapper for the different trigger types (log and condition triggers). diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go index b52b777dbe..42fcd40d61 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go @@ -14,11 +14,10 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" automation21Utils "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) func TestPacker_PackReport(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/keyring.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/keyring.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/keyring.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/keyring.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/keyring_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/keyring_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/keyring_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/keyring_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/block_time.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/block_time.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/block_time_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/block_time_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go index a973ea6e19..046c93a428 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go @@ -13,7 +13,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestLogEventBuffer_GetBlocksInRange(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go index 38342550c5..2b48fec2b3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go @@ -8,7 +8,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) // New creates a new log event provider and recoverer. diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter_store.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_store.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter_store.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_store.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter_store_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_store_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter_store_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_store_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go similarity index 97% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go index dd90b5e00b..caad1adc9a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go @@ -31,8 +31,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - kevmcore "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" + evmregistry21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -150,7 +150,7 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) { require.Equal(t, 1, len(addrs)) t.Run("update filter config", func(t *testing.T) { - upkeepID := kevmcore.GenUpkeepID(ocr2keepers.LogTrigger, "111") + upkeepID := evmregistry21.GenUpkeepID(ocr2keepers.LogTrigger, "111") id := upkeepID.BigInt() cfg := newPlainLogTriggerConfig(addrs[0]) b, err := ethClient.BlockByHash(ctx, backend.Commit()) @@ -182,7 +182,7 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) { }) t.Run("register same log filter", func(t *testing.T) { - upkeepID := kevmcore.GenUpkeepID(ocr2keepers.LogTrigger, "222") + upkeepID := evmregistry21.GenUpkeepID(ocr2keepers.LogTrigger, "222") id := upkeepID.BigInt() cfg := newPlainLogTriggerConfig(addrs[0]) b, err := ethClient.BlockByHash(ctx, backend.Commit()) @@ -663,7 +663,7 @@ func setupDependencies(t *testing.T, db *sqlx.DB, backend *backends.SimulatedBac return lp, ethClient } -func setup(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, stateStore kevmcore.UpkeepStateReader, filterStore logprovider.UpkeepFilterStore, opts *logprovider.LogTriggersOptions) (logprovider.LogEventProvider, logprovider.LogRecoverer) { +func setup(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, stateStore evmregistry21.UpkeepStateReader, filterStore logprovider.UpkeepFilterStore, opts *logprovider.LogTriggersOptions) (logprovider.LogEventProvider, logprovider.LogRecoverer) { packer := logprovider.NewLogEventsPacker() if opts == nil { o := logprovider.NewOptions(200) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/log_packer.go similarity index 96% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/log_packer.go index 655d7dacfe..5902af73f0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/log_packer.go @@ -7,7 +7,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) type LogDataPacker interface { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go index a3887cbe78..2dabcc8267 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go @@ -19,10 +19,11 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go index c58bd85951..278c727a06 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestLogEventProvider_LifeCycle(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go index 98eb0b291b..c7f6884426 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go @@ -20,10 +20,11 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go index 10e58bf26b..89b19b4a81 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go @@ -23,8 +23,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/mercury_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index f98d4ed2df..aec2343192 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -21,10 +21,10 @@ import ( iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" - v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02" - v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" + v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02" + v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index baa277e035..abcc37dca1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -26,10 +26,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" - v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02" - v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" + v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02" + v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03" ) type MockMercuryConfigProvider struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_failure_reasons.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_failure_reasons.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_states.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/upkeep_states.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go index 4ce7893a0b..8135617b6f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go index 2aecc0df77..ac945859d8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v02/v02_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go @@ -18,11 +18,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" ) const ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go index 1c60788974..7002e2f30a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go index 049448f8f7..16ccdac5d1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/v03/v03_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go @@ -16,12 +16,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury" ) const ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/http_client.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mocks/http_client.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/mocks/registry.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go similarity index 95% rename from core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go index e138f440e4..37c458ae6e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go @@ -6,8 +6,8 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" ) type payloadBuilder struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go index d7c2312d19..7e55267f6d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go @@ -12,8 +12,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" ) func TestNewPayloadBuilder(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/registry.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go index e6db3e66e6..bb05b8029f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go @@ -28,10 +28,10 @@ import ( iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go index b0db3f7dd1..f5a931aae4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go @@ -12,8 +12,8 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" ) const ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go index 4eaf334f7c..a14aaec0c5 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go @@ -26,9 +26,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go index fdc6675da8..f3e4402092 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go @@ -23,9 +23,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go similarity index 96% rename from core/services/ocr2/plugins/ocr2keeper/evm21/services.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go index 35d2f82942..71ccee872f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go @@ -16,10 +16,10 @@ import ( iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/transmit" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/testdata/btc-usd.json b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/testdata/btc-usd.json similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/testdata/btc-usd.json rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/testdata/btc-usd.json diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/testdata/eth-usd.json b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/testdata/eth-usd.json similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/testdata/eth-usd.json rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/testdata/eth-usd.json diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/transmit/cache_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go index 7415b3701f..da32376aab 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/encoding_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestTransmitEventLog(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go index 95f5ec0bf1..f66711c2b7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go @@ -11,11 +11,12 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go index 8d56fec22a..950ec81040 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go @@ -19,7 +19,7 @@ import ( iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestTransmitEventProvider_Sanity(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go similarity index 97% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go index 5b6d4ac703..b30215e4fb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go @@ -7,7 +7,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) var _ ocr2keepers.ConditionalUpkeepProvider = &upkeepProvider{} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go index 69bfabb259..81ea391318 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner.go similarity index 98% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner.go index d70611313a..30a50977d1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go similarity index 99% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go index 505959b8f3..4a4de5ea1a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go @@ -11,8 +11,9 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go similarity index 100% rename from core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go rename to core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 01418b9f76..7ccd785a66 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -54,7 +54,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 0c81b16f0f..02a0d033bc 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -20,9 +20,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - kevm20 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm20" - kevm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" - kevm21transmit "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/transmit" + evmregistry20 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20" + evmregistry21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" + evmregistry21transmit "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -73,11 +73,11 @@ func EVMDependencies20( lggr logger.Logger, chain legacyevm.Chain, pr pipeline.Runner, -) (evmrelay.OCR2KeeperProvider, *kevm20.EvmRegistry, Encoder20, *kevm20.LogProvider, error) { +) (evmrelay.OCR2KeeperProvider, *evmregistry20.EvmRegistry, Encoder20, *evmregistry20.LogProvider, error) { var err error var keeperProvider evmrelay.OCR2KeeperProvider - var registry *kevm20.EvmRegistry + var registry *evmregistry20.EvmRegistry // the provider will be returned as a dependency if keeperProvider, err = EVMProvider(db, chain, lggr, spec, pr); err != nil { @@ -85,17 +85,17 @@ func EVMDependencies20( } rAddr := ethkey.MustEIP55Address(spec.OCR2OracleSpec.ContractID).Address() - if registry, err = kevm20.NewEVMRegistryService(rAddr, chain, lggr); err != nil { + if registry, err = evmregistry20.NewEVMRegistryService(rAddr, chain, lggr); err != nil { return nil, nil, nil, nil, err } - encoder := kevm20.EVMAutomationEncoder20{} + encoder := evmregistry20.EVMAutomationEncoder20{} // lookback blocks is hard coded and should provide ample time for logs // to be detected in most cases var lookbackBlocks int64 = 250 // TODO: accept a version of the registry contract and use the correct interfaces - logProvider, err := kevm20.NewLogProvider(lggr, chain.LogPoller(), rAddr, chain.Client(), lookbackBlocks) + logProvider, err := evmregistry20.NewLogProvider(lggr, chain.LogPoller(), rAddr, chain.Client(), lookbackBlocks) return keeperProvider, registry, encoder, logProvider, err } @@ -105,7 +105,7 @@ func FilterNamesFromSpec20(spec *job.OCR2OracleSpec) (names []string, err error) if err != nil { return nil, err } - return []string{kevm20.LogProviderFilterName(addr.Address()), kevm20.UpkeepFilterName(addr.Address())}, err + return []string{evmregistry20.LogProviderFilterName(addr.Address()), evmregistry20.UpkeepFilterName(addr.Address())}, err } func EVMDependencies21( @@ -117,7 +117,7 @@ func EVMDependencies21( mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, dbCfg pg.QConfig, -) (evmrelay.OCR2KeeperProvider, kevm21.AutomationServices, error) { +) (evmrelay.OCR2KeeperProvider, evmregistry21.AutomationServices, error) { var err error var keeperProvider evmrelay.OCR2KeeperProvider @@ -128,7 +128,7 @@ func EVMDependencies21( } rAddr := ethkey.MustEIP55Address(oSpec.ContractID).Address() - services, err := kevm21.New(rAddr, chain, mc, keyring, lggr, db, dbCfg) + services, err := evmregistry21.New(rAddr, chain, mc, keyring, lggr, db, dbCfg) if err != nil { return nil, nil, err } @@ -141,5 +141,5 @@ func FilterNamesFromSpec21(spec *job.OCR2OracleSpec) (names []string, err error) if err != nil { return nil, err } - return []string{kevm21transmit.EventProviderFilterName(addr.Address()), kevm21.RegistryUpkeepFilterName(addr.Address())}, err + return []string{evmregistry21transmit.EventProviderFilterName(addr.Address()), evmregistry21.RegistryUpkeepFilterName(addr.Address())}, err } diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index cdc8748676..81b484f4e7 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -23,7 +23,7 @@ import ( cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/mercury/streams" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/integration-tests/actions" From 9bd3ecb16e5c682b7dbbbb40671677ef98a8f682 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 30 Nov 2023 17:03:09 -0600 Subject: [PATCH 242/327] core/services/chainlink: pass static ver & sha to HealtChecker (#11432) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- core/services/chainlink/application.go | 3 ++- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c1ed59097c..197716c2b2 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -304,7 +304,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index de86a45721..c6f922432b 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1504,8 +1504,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde h1:yulX+cnJbiS/iACjOdJfFtD5bD9M6TnXy7Og/PBafew= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 h1:68YZ874EBGEGwT3lcg6Y+3GZXzyNDeDDiqLHvNMBKYc= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 1c9cd106ba..5c204d693e 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/build" @@ -424,7 +425,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger.Debug("Off-chain reporting v2 disabled") } - healthChecker := commonservices.NewChecker() + healthChecker := commonservices.NewChecker(static.Version, static.Sha) var lbs []utils.DependentAwaiter for _, c := range legacyEVMChains.Slice() { diff --git a/go.mod b/go.mod index 688f581052..41255bc4f0 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-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 diff --git a/go.sum b/go.sum index d522aabb08..cc3e130377 100644 --- a/go.sum +++ b/go.sum @@ -1507,8 +1507,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde h1:yulX+cnJbiS/iACjOdJfFtD5bD9M6TnXy7Og/PBafew= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 h1:68YZ874EBGEGwT3lcg6Y+3GZXzyNDeDDiqLHvNMBKYc= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 68b46d8a26..220dc86b45 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 github.com/smartcontractkit/chainlink-testing-framework v1.20.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 46c132d6ff..134168a866 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2376,8 +2376,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde h1:yulX+cnJbiS/iACjOdJfFtD5bD9M6TnXy7Og/PBafew= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231129142348-7087174fecde/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 h1:68YZ874EBGEGwT3lcg6Y+3GZXzyNDeDDiqLHvNMBKYc= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= From 5969e1f654dee1fb90d5654ff51fbf824ff41013 Mon Sep 17 00:00:00 2001 From: Cedric Date: Fri, 1 Dec 2023 10:11:40 +0000 Subject: [PATCH 243/327] [chore] Refactor ResultsRunSaver to not expose runResults (#11398) --- core/services/ocr/delegate.go | 17 ++-- core/services/ocr2/delegate.go | 85 ++++--------------- core/services/ocr2/plugins/median/services.go | 32 ++++--- core/services/ocr2/plugins/mercury/plugin.go | 11 +-- core/services/ocrcommon/data_source.go | 24 +++--- core/services/ocrcommon/data_source_test.go | 22 +++-- core/services/ocrcommon/run_saver.go | 20 +++-- core/services/ocrcommon/run_saver_test.go | 6 +- .../relay/evm/mercury/v1/data_source.go | 13 ++- .../relay/evm/mercury/v1/data_source_test.go | 23 ++--- .../relay/evm/mercury/v2/data_source.go | 13 ++- .../relay/evm/mercury/v2/data_source_test.go | 11 +++ .../relay/evm/mercury/v3/data_source.go | 13 ++- .../relay/evm/mercury/v3/data_source_test.go | 11 +++ 14 files changed, 143 insertions(+), 158 deletions(-) diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index ac78002d45..f473c93b1f 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -274,7 +274,12 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e effectiveTransmitterAddress, ) - runResults := make(chan *pipeline.Run, chain.Config().JobPipeline().ResultWriteQueueDepth()) + saver := ocrcommon.NewResultRunSaver( + d.pipelineRunner, + lggr, + cfg.JobPipeline().MaxSuccessfulRuns(), + cfg.JobPipeline().ResultWriteQueueDepth(), + ) var configOverrider ocrtypes.ConfigOverrider configOverriderService, err := d.maybeCreateConfigOverrider(lggr, chain, concreteSpec.ContractAddress) @@ -311,7 +316,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e jb, *jb.PipelineSpec, lggr, - runResults, + saver, enhancedTelemChan, ), LocalConfig: lc, @@ -334,13 +339,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e // RunResultSaver needs to be started first so its available // to read db writes. It is stopped last after the Oracle is shut down // so no further runs are enqueued and we can drain the queue. - services = append([]job.ServiceCtx{ocrcommon.NewResultRunSaver( - runResults, - d.pipelineRunner, - make(chan struct{}), - lggr, - cfg.JobPipeline().MaxSuccessfulRuns(), - )}, services...) + services = append([]job.ServiceCtx{saver}, services...) } return services, nil diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 0234182137..16f02282af 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -426,24 +426,22 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { spec.CaptureEATelemetry = d.cfg.OCR2().CaptureEATelemetry() - runResults := make(chan *pipeline.Run, d.cfg.JobPipeline().ResultWriteQueueDepth()) - ctx := lggrCtx.ContextWithValues(context.Background()) switch spec.PluginType { case types.Mercury: - return d.newServicesMercury(ctx, lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) + return d.newServicesMercury(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) case types.Median: - return d.newServicesMedian(ctx, lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) + return d.newServicesMedian(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) case types.DKG: return d.newServicesDKG(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) case types.OCR2VRF: - return d.newServicesOCR2VRF(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc) + return d.newServicesOCR2VRF(lggr, jb, bootstrapPeers, kb, ocrDB, lc) case types.OCR2Keeper: - return d.newServicesOCR2Keepers(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) + return d.newServicesOCR2Keepers(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) case types.Functions: const ( @@ -453,7 +451,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { ) thresholdPluginDB := NewDB(d.db, spec.ID, thresholdPluginId, lggr, d.cfg.Database()) s4PluginDB := NewDB(d.db, spec.ID, s4PluginId, lggr, d.cfg.Database()) - return d.newServicesOCR2Functions(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, thresholdPluginDB, s4PluginDB, lc, ocrLogger) + return d.newServicesOCR2Functions(lggr, jb, bootstrapPeers, kb, ocrDB, thresholdPluginDB, s4PluginDB, lc, ocrLogger) case types.GenericPlugin: return d.newServicesGenericPlugin(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) @@ -652,7 +650,6 @@ func (d *Delegate) newServicesMercury( ctx context.Context, lggr logger.SugaredLogger, jb job.Job, - runResults chan *pipeline.Run, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, @@ -720,7 +717,7 @@ func (d *Delegate) newServicesMercury( chEnhancedTelem := make(chan ocrcommon.EnhancedTelemetryMercuryData, 100) - mercuryServices, err2 := mercury.NewServices(jb, mercuryProvider, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, d.cfg.JobPipeline(), chEnhancedTelem, d.mercuryORM, (mercuryutils.FeedID)(*spec.FeedID)) + mercuryServices, err2 := mercury.NewServices(jb, mercuryProvider, d.pipelineRunner, lggr, oracleArgsNoPlugin, d.cfg.JobPipeline(), chEnhancedTelem, d.mercuryORM, (mercuryutils.FeedID)(*spec.FeedID)) if ocrcommon.ShouldCollectEnhancedTelemetryMercury(jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.FeedID.String(), synchronization.EnhancedEAMercury), lggr.Named("EnhancedTelemetryMercury")) @@ -736,7 +733,6 @@ func (d *Delegate) newServicesMedian( ctx context.Context, lggr logger.SugaredLogger, jb job.Job, - runResults chan *pipeline.Run, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, @@ -762,14 +758,18 @@ func (d *Delegate) newServicesMedian( } errorLog := &errorLog{jobID: jb.ID, recordError: d.jobORM.RecordError} enhancedTelemChan := make(chan ocrcommon.EnhancedTelemetryData, 100) - mConfig := median.NewMedianConfig(d.cfg.JobPipeline().MaxSuccessfulRuns(), d.cfg) + mConfig := median.NewMedianConfig( + d.cfg.JobPipeline().MaxSuccessfulRuns(), + d.cfg.JobPipeline().ResultWriteQueueDepth(), + d.cfg, + ) relayer, err := d.RelayGetter.Get(rid) if err != nil { return nil, ErrRelayNotEnabled{Err: err, PluginName: "median", Relay: spec.Relay} } - medianServices, err2 := median.NewMedianServices(ctx, jb, d.isNewlyCreatedJob, relayer, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, mConfig, enhancedTelemChan, errorLog) + medianServices, err2 := median.NewMedianServices(ctx, jb, d.isNewlyCreatedJob, relayer, d.pipelineRunner, lggr, oracleArgsNoPlugin, mConfig, enhancedTelemChan, errorLog) if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) @@ -852,7 +852,6 @@ func (d *Delegate) newServicesDKG( func (d *Delegate) newServicesOCR2VRF( lggr logger.SugaredLogger, jb job.Job, - runResults chan *pipeline.Run, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, @@ -1019,28 +1018,16 @@ func (d *Delegate) newServicesOCR2VRF( return nil, errors.Wrap(err2, "new ocr2vrf") } - // RunResultSaver needs to be started first, so it's available - // to read odb writes. It is stopped last after the OraclePlugin is shut down - // so no further runs are enqueued, and we can drain the queue. - runResultSaver := ocrcommon.NewResultRunSaver( - runResults, - d.pipelineRunner, - make(chan struct{}), - lggr, - d.cfg.JobPipeline().MaxSuccessfulRuns(), - ) - // NOTE: we return from here with the services because the OCR2VRF oracles are defined // and exported from the ocr2vrf library. It takes care of running the DKG and OCR2VRF // oracles under the hood together. oracleCtx := job.NewServiceAdapter(oracles) - return []job.ServiceCtx{runResultSaver, vrfProvider, dkgProvider, oracleCtx}, nil + return []job.ServiceCtx{vrfProvider, dkgProvider, oracleCtx}, nil } func (d *Delegate) newServicesOCR2Keepers( lggr logger.SugaredLogger, jb job.Job, - runResults chan *pipeline.Run, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, @@ -1059,18 +1046,17 @@ func (d *Delegate) newServicesOCR2Keepers( switch cfg.ContractVersion { case "v2.1": - return d.newServicesOCR2Keepers21(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) + return d.newServicesOCR2Keepers21(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) case "v2.0": - return d.newServicesOCR2Keepers20(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) + return d.newServicesOCR2Keepers20(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) default: - return d.newServicesOCR2Keepers20(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) + return d.newServicesOCR2Keepers20(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) } } func (d *Delegate) newServicesOCR2Keepers21( lggr logger.SugaredLogger, jb job.Job, - runResults chan *pipeline.Run, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, @@ -1162,19 +1148,7 @@ func (d *Delegate) newServicesOCR2Keepers21( return nil, errors.Wrap(err, "could not create new keepers ocr2 delegate") } - // RunResultSaver needs to be started first, so it's available - // to read odb writes. It is stopped last after the OraclePlugin is shut down - // so no further runs are enqueued, and we can drain the queue. - runResultSaver := ocrcommon.NewResultRunSaver( - runResults, - d.pipelineRunner, - make(chan struct{}), - lggr, - d.cfg.JobPipeline().MaxSuccessfulRuns(), - ) - automationServices := []job.ServiceCtx{ - runResultSaver, keeperProvider, services.Registry(), services.BlockSubscriber(), @@ -1206,7 +1180,6 @@ func (d *Delegate) newServicesOCR2Keepers21( func (d *Delegate) newServicesOCR2Keepers20( lggr logger.SugaredLogger, jb job.Job, - runResults chan *pipeline.Run, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, @@ -1316,20 +1289,8 @@ func (d *Delegate) newServicesOCR2Keepers20( return nil, errors.Wrap(err, "could not create new keepers ocr2 delegate") } - // RunResultSaver needs to be started first, so it's available - // to read odb writes. It is stopped last after the OraclePlugin is shut down - // so no further runs are enqueued, and we can drain the queue. - runResultSaver := ocrcommon.NewResultRunSaver( - runResults, - d.pipelineRunner, - make(chan struct{}), - lggr, - d.cfg.JobPipeline().MaxSuccessfulRuns(), - ) - return []job.ServiceCtx{ job.NewServiceAdapter(runr), - runResultSaver, keeperProvider, rgstry, logProvider, @@ -1340,7 +1301,6 @@ func (d *Delegate) newServicesOCR2Keepers20( func (d *Delegate) newServicesOCR2Functions( lggr logger.SugaredLogger, jb job.Job, - runResults chan *pipeline.Run, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, functionsOcrDB *db, @@ -1480,18 +1440,7 @@ func (d *Delegate) newServicesOCR2Functions( return nil, errors.Wrap(err, "error calling NewFunctionsServices") } - // RunResultSaver needs to be started first, so it's available - // to read odb writes. It is stopped last after the OraclePlugin is shut down - // so no further runs are enqueued, and we can drain the queue. - runResultSaver := ocrcommon.NewResultRunSaver( - runResults, - d.pipelineRunner, - make(chan struct{}), - lggr, - d.cfg.JobPipeline().MaxSuccessfulRuns(), - ) - - return append([]job.ServiceCtx{runResultSaver, functionsProvider, thresholdProvider, s4Provider}, functionsServices...), nil + return append([]job.ServiceCtx{functionsProvider, thresholdProvider, s4Provider}, functionsServices...), nil } // errorLog implements [loop.ErrorLog] diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 896bbacb41..2d1ef72054 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -25,19 +25,22 @@ import ( type MedianConfig interface { JobPipelineMaxSuccessfulRuns() uint64 + JobPipelineResultWriteQueueDepth() uint64 plugins.RegistrarConfig } // concrete implementation of MedianConfig type medianConfig struct { - jobPipelineMaxSuccessfulRuns uint64 + jobPipelineMaxSuccessfulRuns uint64 + jobPipelineResultWriteQueueDepth uint64 plugins.RegistrarConfig } -func NewMedianConfig(jobPipelineMaxSuccessfulRuns uint64, pluginProcessCfg plugins.RegistrarConfig) MedianConfig { +func NewMedianConfig(jobPipelineMaxSuccessfulRuns uint64, jobPipelineResultWriteQueueDepth uint64, pluginProcessCfg plugins.RegistrarConfig) MedianConfig { return &medianConfig{ - jobPipelineMaxSuccessfulRuns: jobPipelineMaxSuccessfulRuns, - RegistrarConfig: pluginProcessCfg, + jobPipelineMaxSuccessfulRuns: jobPipelineMaxSuccessfulRuns, + jobPipelineResultWriteQueueDepth: jobPipelineResultWriteQueueDepth, + RegistrarConfig: pluginProcessCfg, } } @@ -45,12 +48,15 @@ func (m *medianConfig) JobPipelineMaxSuccessfulRuns() uint64 { return m.jobPipelineMaxSuccessfulRuns } +func (m *medianConfig) JobPipelineResultWriteQueueDepth() uint64 { + return m.jobPipelineResultWriteQueueDepth +} + func NewMedianServices(ctx context.Context, jb job.Job, isNewlyCreatedJob bool, relayer loop.Relayer, pipelineRunner pipeline.Runner, - runResults chan *pipeline.Run, lggr logger.Logger, argsNoPlugin libocr.OCR2OracleArgs, cfg MedianConfig, @@ -69,6 +75,13 @@ func NewMedianServices(ctx context.Context, } spec := jb.OCR2OracleSpec + runSaver := ocrcommon.NewResultRunSaver( + pipelineRunner, + lggr, + cfg.JobPipelineMaxSuccessfulRuns(), + cfg.JobPipelineResultWriteQueueDepth(), + ) + provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{ ExternalJobID: jb.ExternalJobID, JobID: jb.ID, @@ -104,7 +117,7 @@ func NewMedianServices(ctx context.Context, jb, *jb.PipelineSpec, lggr, - runResults, + runSaver, chEnhancedTelem, ), ocrcommon.NewInMemoryDataSource(pipelineRunner, jb, pipeline.Spec{ ID: jb.ID, @@ -140,13 +153,6 @@ func NewMedianServices(ctx context.Context, abort() return } - runSaver := ocrcommon.NewResultRunSaver( - runResults, - pipelineRunner, - make(chan struct{}), - lggr, - cfg.JobPipelineMaxSuccessfulRuns(), - ) srvs = append(srvs, runSaver, job.NewServiceAdapter(oracle)) if !jb.OCR2OracleSpec.CaptureEATelemetry { lggr.Infof("Enhanced EA telemetry is disabled for job %s", jb.Name.ValueOrZero()) diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index bd68ccd8b7..d443008334 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -26,13 +26,13 @@ import ( type Config interface { MaxSuccessfulRuns() uint64 + ResultWriteQueueDepth() uint64 } func NewServices( jb job.Job, ocr2Provider commontypes.MercuryProvider, pipelineRunner pipeline.Runner, - runResults chan *pipeline.Run, lggr logger.Logger, argsNoPlugin libocr2.MercuryOracleArgs, cfg Config, @@ -55,6 +55,8 @@ func NewServices( } lggr = lggr.Named("MercuryPlugin").With("jobID", jb.ID, "jobName", jb.Name.ValueOrZero()) + saver := ocrcommon.NewResultRunSaver(pipelineRunner, lggr, cfg.MaxSuccessfulRuns(), cfg.ResultWriteQueueDepth()) + switch feedID.Version() { case 1: ds := mercuryv1.NewDataSource( @@ -63,7 +65,7 @@ func NewServices( jb, *jb.PipelineSpec, lggr, - runResults, + saver, chEnhancedTelem, ocr2Provider.ChainReader(), ocr2Provider.MercuryServerFetcher(), @@ -84,7 +86,7 @@ func NewServices( *jb.PipelineSpec, feedID, lggr, - runResults, + saver, chEnhancedTelem, ocr2Provider.MercuryServerFetcher(), *pluginConfig.LinkFeedID, @@ -104,7 +106,7 @@ func NewServices( *jb.PipelineSpec, feedID, lggr, - runResults, + saver, chEnhancedTelem, ocr2Provider.MercuryServerFetcher(), *pluginConfig.LinkFeedID, @@ -124,6 +126,5 @@ func NewServices( if err != nil { return nil, errors.WithStack(err) } - saver := ocrcommon.NewResultRunSaver(runResults, pipelineRunner, make(chan struct{}), lggr, cfg.MaxSuccessfulRuns()) return []job.ServiceCtx{ocr2Provider, saver, job.NewServiceAdapter(oracle)}, nil } diff --git a/core/services/ocrcommon/data_source.go b/core/services/ocrcommon/data_source.go index 0363a7124b..706376fbfd 100644 --- a/core/services/ocrcommon/data_source.go +++ b/core/services/ocrcommon/data_source.go @@ -33,9 +33,13 @@ type inMemoryDataSource struct { chEnhancedTelemetry chan<- EnhancedTelemetryData } +type Saver interface { + Save(run *pipeline.Run) +} + type dataSourceBase struct { inMemoryDataSource - runResults chan<- *pipeline.Run + saver Saver } // dataSource implements dataSourceBase with the proper Observe return type for ocr1 @@ -55,7 +59,7 @@ type ObservationTimestamp struct { ConfigDigest string } -func NewDataSourceV1(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, runResults chan<- *pipeline.Run, chEnhancedTelemetry chan EnhancedTelemetryData) ocr1types.DataSource { +func NewDataSourceV1(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s Saver, chEnhancedTelemetry chan EnhancedTelemetryData) ocr1types.DataSource { return &dataSource{ dataSourceBase: dataSourceBase{ inMemoryDataSource: inMemoryDataSource{ @@ -65,12 +69,12 @@ func NewDataSourceV1(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr lo lggr: lggr, chEnhancedTelemetry: chEnhancedTelemetry, }, - runResults: runResults, + saver: s, }, } } -func NewDataSourceV2(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, runResults chan<- *pipeline.Run, enhancedTelemChan chan EnhancedTelemetryData) median.DataSource { +func NewDataSourceV2(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s Saver, enhancedTelemChan chan EnhancedTelemetryData) median.DataSource { return &dataSourceV2{ dataSourceBase: dataSourceBase{ inMemoryDataSource: inMemoryDataSource{ @@ -80,7 +84,7 @@ func NewDataSourceV2(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr lo lggr: lggr, chEnhancedTelemetry: enhancedTelemChan, }, - runResults: runResults, + saver: s, }, } } @@ -189,19 +193,13 @@ func (ds *dataSourceBase) observe(ctx context.Context, timestamp ObservationTime return nil, err } - // Do the database write in a non-blocking fashion + // Save() does the database write in a non-blocking fashion // so we can return the observation results immediately. // This is helpful in the case of a blocking API call, where // we reach the passed in context deadline and we want to // immediately return any result we have and do not want to have // a db write block that. - select { - case ds.runResults <- run: - default: - // If we're unable to enqueue a write, still return the value we have but warn. - ds.lggr.Warnf("unable to enqueue run save for job ID %d, buffer full", ds.inMemoryDataSource.spec.JobID) - return ds.inMemoryDataSource.parse(finalResult) - } + ds.saver.Save(run) return ds.inMemoryDataSource.parse(finalResult) } diff --git a/core/services/ocrcommon/data_source_test.go b/core/services/ocrcommon/data_source_test.go index 51a004f1f0..3ffc6b31e8 100644 --- a/core/services/ocrcommon/data_source_test.go +++ b/core/services/ocrcommon/data_source_test.go @@ -93,8 +93,17 @@ func Test_InMemoryDataSourceWithProm(t *testing.T) { } +type mockSaver struct { + r *pipeline.Run +} + +func (ms *mockSaver) Save(r *pipeline.Run) { + ms.r = r +} + func Test_NewDataSourceV2(t *testing.T) { runner := pipelinemocks.NewRunner(t) + ms := &mockSaver{} runner.On("ExecuteRun", mock.Anything, mock.AnythingOfType("pipeline.Spec"), mock.Anything, mock.Anything). Return(&pipeline.Run{}, pipeline.TaskRunResults{ { @@ -106,16 +115,16 @@ func Test_NewDataSourceV2(t *testing.T) { }, }, nil) - resChan := make(chan *pipeline.Run, 100) - ds := ocrcommon.NewDataSourceV2(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t), resChan, nil) + ds := ocrcommon.NewDataSourceV2(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t), ms, nil) val, err := ds.Observe(testutils.Context(t), types.ReportTimestamp{}) require.NoError(t, err) - assert.Equal(t, mockValue, val.String()) // returns expected value after pipeline run - assert.Equal(t, &pipeline.Run{}, <-resChan) // expected data properly passed to channel + assert.Equal(t, mockValue, val.String()) // returns expected value after pipeline run + assert.Equal(t, &pipeline.Run{}, ms.r) // expected data properly passed to channel } func Test_NewDataSourceV1(t *testing.T) { runner := pipelinemocks.NewRunner(t) + ms := &mockSaver{} runner.On("ExecuteRun", mock.Anything, mock.AnythingOfType("pipeline.Spec"), mock.Anything, mock.Anything). Return(&pipeline.Run{}, pipeline.TaskRunResults{ { @@ -127,10 +136,9 @@ func Test_NewDataSourceV1(t *testing.T) { }, }, nil) - resChan := make(chan *pipeline.Run, 100) - ds := ocrcommon.NewDataSourceV1(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t), resChan, nil) + ds := ocrcommon.NewDataSourceV1(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t), ms, nil) val, err := ds.Observe(testutils.Context(t), ocrtypes.ReportTimestamp{}) require.NoError(t, err) assert.Equal(t, mockValue, new(big.Int).Set(val).String()) // returns expected value after pipeline run - assert.Equal(t, &pipeline.Run{}, <-resChan) // expected data properly passed to channel + assert.Equal(t, &pipeline.Run{}, ms.r) // expected data properly passed to channel } diff --git a/core/services/ocrcommon/run_saver.go b/core/services/ocrcommon/run_saver.go index 184226605f..b1a0fc7b14 100644 --- a/core/services/ocrcommon/run_saver.go +++ b/core/services/ocrcommon/run_saver.go @@ -12,7 +12,7 @@ type RunResultSaver struct { services.StateMachine maxSuccessfulRuns uint64 - runResults <-chan *pipeline.Run + runResults chan *pipeline.Run pipelineRunner pipeline.Runner done chan struct{} logger logger.Logger @@ -24,18 +24,28 @@ func (r *RunResultSaver) HealthReport() map[string]error { func (r *RunResultSaver) Name() string { return r.logger.Name() } -func NewResultRunSaver(runResults <-chan *pipeline.Run, pipelineRunner pipeline.Runner, done chan struct{}, - logger logger.Logger, maxSuccessfulRuns uint64, +func NewResultRunSaver(pipelineRunner pipeline.Runner, + logger logger.Logger, maxSuccessfulRuns uint64, resultsWriteDepth uint64, ) *RunResultSaver { return &RunResultSaver{ maxSuccessfulRuns: maxSuccessfulRuns, - runResults: runResults, + runResults: make(chan *pipeline.Run, resultsWriteDepth), pipelineRunner: pipelineRunner, - done: done, + done: make(chan struct{}), logger: logger.Named("RunResultSaver"), } } +// Save sends the run on the internal `runResults` channel for saving. +// IMPORTANT: if the `runResults` pipeline is full, the run will be dropped. +func (r *RunResultSaver) Save(run *pipeline.Run) { + select { + case r.runResults <- run: + default: + r.logger.Warnw("RunSaver: the write queue was full, dropping run") + } +} + // Start starts RunResultSaver. func (r *RunResultSaver) Start(context.Context) error { return r.StartOnce("RunResultSaver", func() error { diff --git a/core/services/ocrcommon/run_saver_test.go b/core/services/ocrcommon/run_saver_test.go index 7d20a7a202..73697d181b 100644 --- a/core/services/ocrcommon/run_saver_test.go +++ b/core/services/ocrcommon/run_saver_test.go @@ -14,13 +14,11 @@ import ( func TestRunSaver(t *testing.T) { pipelineRunner := mocks.NewRunner(t) - rr := make(chan *pipeline.Run, 100) rs := NewResultRunSaver( - rr, pipelineRunner, - make(chan struct{}), logger.TestLogger(t), 1000, + 100, ) require.NoError(t, rs.Start(testutils.Context(t))) for i := 0; i < 100; i++ { @@ -31,7 +29,7 @@ func TestRunSaver(t *testing.T) { args.Get(0).(*pipeline.Run).ID = int64(d) }). Once() - rr <- &pipeline.Run{ID: int64(i)} + rs.Save(&pipeline.Run{ID: int64(i)}) } require.NoError(t, rs.Close()) } diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index 79eb32af44..bc94166e56 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -58,7 +58,7 @@ type datasource struct { jb job.Job spec pipeline.Spec lggr logger.Logger - runResults chan<- *pipeline.Run + saver ocrcommon.Saver orm types.DataSourceORM codec reportcodec.ReportCodec feedID [32]byte @@ -76,8 +76,8 @@ type datasource struct { var _ relaymercuryv1.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, rr chan *pipeline.Run, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainReader relaymercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { - return &datasource{pr, jb, spec, lggr, rr, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainReader relaymercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { + return &datasource{pr, jb, spec, lggr, s, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} } type ErrEmptyLatestReport struct { @@ -156,11 +156,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam pipelineExecutionErr = fmt.Errorf("Observe failed while executing run: %w", pipelineExecutionErr) return } - select { - case ds.runResults <- run: - default: - ds.lggr.Warnf("unable to enqueue run save for job ID %d, buffer full", ds.spec.JobID) - } + + ds.saver.Save(run) // NOTE: trrs comes back as _all_ tasks, but we only want the terminal ones // They are guaranteed to be sorted by index asc so should be in the correct order diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 45a99f2919..d8d7d39dbb 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -52,6 +52,14 @@ func (m *mockFetcher) LatestTimestamp(context.Context) (int64, error) { return 0, nil } +type mockSaver struct { + r *pipeline.Run +} + +func (ms *mockSaver) Save(r *pipeline.Run) { + ms.r = r +} + type mockORM struct { report []byte err error @@ -80,6 +88,9 @@ func TestMercury_Observe(t *testing.T) { fetcher := &mockFetcher{} ds.fetcher = fetcher + saver := &mockSaver{} + ds.saver = saver + trrs := []pipeline.TaskRunResult{ { // benchmark price @@ -293,24 +304,16 @@ func TestMercury_Observe(t *testing.T) { _, err := ds.Observe(ctx, repts, false) assert.EqualError(t, err, "Observe failed while parsing run results: failed to parse Bid: can't convert foo to decimal") }) - t.Run("sends run to runResults channel", func(t *testing.T) { + t.Run("saves run", func(t *testing.T) { for i := range trrs { trrs[i].Result.Value = "123" trrs[i].Result.Error = nil } - ch := make(chan *pipeline.Run, 1) - - ds.runResults = ch _, err := ds.Observe(ctx, repts, false) assert.NoError(t, err) - select { - case run := <-ch: - assert.Equal(t, int64(42), run.ID) - default: - t.Fatal("expected run on channel") - } + assert.Equal(t, int64(42), saver.r.ID) }) }) diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index f7b7892513..ec6cf5ad10 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -39,7 +39,7 @@ type datasource struct { spec pipeline.Spec feedID mercuryutils.FeedID lggr logger.Logger - runResults chan<- *pipeline.Run + saver ocrcommon.Saver orm types.DataSourceORM codec reportcodec.ReportCodec @@ -54,8 +54,8 @@ type datasource struct { var _ relaymercuryv2.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, rr chan *pipeline.Run, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { - return &datasource{pr, jb, spec, feedID, lggr, rr, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { + return &datasource{pr, jb, spec, feedID, lggr, s, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv2.Observation, pipelineExecutionErr error) { @@ -91,11 +91,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam pipelineExecutionErr = fmt.Errorf("Observe failed while executing run: %w", pipelineExecutionErr) return } - select { - case ds.runResults <- run: - default: - ds.lggr.Warnf("unable to enqueue run save for job ID %d, buffer full", ds.spec.JobID) - } + + ds.saver.Save(run) var parsed parseOutput parsed, pipelineExecutionErr = ds.parse(trrs) diff --git a/core/services/relay/evm/mercury/v2/data_source_test.go b/core/services/relay/evm/mercury/v2/data_source_test.go index 0249203193..d1030327e1 100644 --- a/core/services/relay/evm/mercury/v2/data_source_test.go +++ b/core/services/relay/evm/mercury/v2/data_source_test.go @@ -63,6 +63,14 @@ func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg return m.report, m.err } +type mockSaver struct { + r *pipeline.Run +} + +func (ms *mockSaver) Save(r *pipeline.Run) { + ms.r = r +} + func Test_Datasource(t *testing.T) { orm := &mockORM{} ds := &datasource{orm: orm, lggr: logger.TestLogger(t)} @@ -72,6 +80,9 @@ func Test_Datasource(t *testing.T) { fetcher := &mockFetcher{} ds.fetcher = fetcher + saver := &mockSaver{} + ds.saver = saver + goodTrrs := []pipeline.TaskRunResult{ { // bp diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index 34dbd13be9..d5e1e5716d 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -40,7 +40,7 @@ type datasource struct { spec pipeline.Spec feedID mercuryutils.FeedID lggr logger.Logger - runResults chan<- *pipeline.Run + saver ocrcommon.Saver orm types.DataSourceORM codec reportcodec.ReportCodec @@ -55,8 +55,8 @@ type datasource struct { var _ relaymercuryv3.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, rr chan *pipeline.Run, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { - return &datasource{pr, jb, spec, feedID, lggr, rr, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { + return &datasource{pr, jb, spec, feedID, lggr, s, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv3.Observation, pipelineExecutionErr error) { @@ -92,11 +92,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam pipelineExecutionErr = fmt.Errorf("Observe failed while executing run: %w", pipelineExecutionErr) return } - select { - case ds.runResults <- run: - default: - ds.lggr.Warnf("unable to enqueue run save for job ID %d, buffer full", ds.spec.JobID) - } + + ds.saver.Save(run) var parsed parseOutput parsed, pipelineExecutionErr = ds.parse(trrs) diff --git a/core/services/relay/evm/mercury/v3/data_source_test.go b/core/services/relay/evm/mercury/v3/data_source_test.go index c4b5b4c610..e03e321d09 100644 --- a/core/services/relay/evm/mercury/v3/data_source_test.go +++ b/core/services/relay/evm/mercury/v3/data_source_test.go @@ -63,6 +63,14 @@ func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg return m.report, m.err } +type mockSaver struct { + r *pipeline.Run +} + +func (ms *mockSaver) Save(r *pipeline.Run) { + ms.r = r +} + func Test_Datasource(t *testing.T) { orm := &mockORM{} ds := &datasource{orm: orm, lggr: logger.TestLogger(t)} @@ -72,6 +80,9 @@ func Test_Datasource(t *testing.T) { fetcher := &mockFetcher{} ds.fetcher = fetcher + saver := &mockSaver{} + ds.saver = saver + goodTrrs := []pipeline.TaskRunResult{ { // bp From 15e7b79c92208feee41d8cf51ca4e5bb8843a531 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:36:38 +0400 Subject: [PATCH 244/327] [AUTO-7451] Move load test and smoke test to use new actions (#11364) * move load test to use new common action * move smoke test to use common action * fix smoke tests * decrease batch size in load test report prep * add info logs in TestAutomationKeeperNodesDown * remove duplicate registry config in smoke test * use AutomationTest struct in setupAutomationTestDocker * add and use SetupMercuryMock --- .../actions/automationv2/actions.go | 23 ++ .../automationv2_1/automationv2_1_test.go | 233 ++++------- integration-tests/smoke/automation_test.go | 381 +++++++++++------- 3 files changed, 346 insertions(+), 291 deletions(-) diff --git a/integration-tests/actions/automationv2/actions.go b/integration-tests/actions/automationv2/actions.go index f97c17bb94..febdd89215 100644 --- a/integration-tests/actions/automationv2/actions.go +++ b/integration-tests/actions/automationv2/actions.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" @@ -36,6 +38,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" + + ctfTestEnv "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" ) type NodeDetails struct { @@ -70,6 +74,8 @@ type AutomationTest struct { ChainlinkNodesk8s []*client.ChainlinkK8sClient ChainlinkNodes []*client.ChainlinkClient + DockerEnv *test_env.CLClusterTestEnv + NodeDetails []NodeDetails DefaultP2Pv2Bootstrapper string MercuryCredentialName string @@ -135,6 +141,10 @@ func (a *AutomationTest) SetUpkeepPrivilegeManager(address string) { a.UpkeepPrivilegeManager = common.HexToAddress(address) } +func (a *AutomationTest) SetDockerEnv(env *test_env.CLClusterTestEnv) { + a.DockerEnv = env +} + func (a *AutomationTest) DeployLINK() error { linkToken, err := a.Deployer.DeployLinkTokenContract() if err != nil { @@ -646,6 +656,19 @@ func (a *AutomationTest) AddJobsAndSetConfig(t *testing.T) { l.Info().Str("Registry Address", a.Registry.Address()).Msg("Successfully setConfig on registry") } +func (a *AutomationTest) SetupMercuryMock(t *testing.T, imposters []ctfTestEnv.KillgraveImposter) { + if a.IsOnk8s { + t.Error("mercury mock is not supported on k8s") + } + if a.DockerEnv == nil { + t.Error("docker env is not set") + } + err := a.DockerEnv.MockAdapter.AddImposter(imposters) + if err != nil { + require.NoError(t, err, "Error adding mock imposter") + } +} + func (a *AutomationTest) SetupAutomationDeployment(t *testing.T) { l := logging.GetTestLogger(t) err := a.CollectNodeDetails() diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index 1f39d5e4b0..5fde9befba 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -2,8 +2,8 @@ package automationv2_1 import ( "context" - "encoding/json" "fmt" + "math" "math/big" "os" "strconv" @@ -31,12 +31,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - registrar21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/automationv2" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" contractseth "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" @@ -284,31 +284,14 @@ func TestLogTrigger(t *testing.T) { chainClient.ParallelTransactions(true) - linkToken, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Error deploying link token contract") - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for contracts to deploy") - - registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( - t, contractseth.RegistryVersion_2_1, *registrySettings, linkToken, contractDeployer, chainClient, - ) - - err = actions.FundChainlinkNodesAddress(chainlinkNodes[1:], chainClient, big.NewFloat(100), 0) - require.NoError(t, err, "Error funding chainlink nodes") - - actions.CreateOCRKeeperJobs( - t, - chainlinkNodes, - registry.Address(), - chainClient.GetChainID().Int64(), - 0, - contractseth.RegistryVersion_2_1, - ) - - S, oracleIdentities, err := actions.GetOracleIdentities(chainlinkNodes) - require.NoError(t, err, "Error getting oracle identities") - offC, err := json.Marshal(ocr2keepers30config.OffchainConfig{ + a := automationv2.NewAutomationTestK8s(chainClient, contractDeployer, chainlinkNodes) + a.RegistrySettings = *registrySettings + a.RegistrarSettings = contracts.KeeperRegistrarSettings{ + AutoApproveConfigType: uint8(2), + AutoApproveMaxAllowed: math.MaxUint16, + MinLinkJuels: big.NewInt(0), + } + a.PluginConfig = ocr2keepers30config.OffchainConfig{ TargetProbability: "0.999", TargetInRounds: 1, PerformLockoutWindow: 80_000, // Copied from arbitrum mainnet prod value @@ -316,64 +299,33 @@ func TestLogTrigger(t *testing.T) { GasOverheadPerUpkeep: 300_000, MinConfirmations: 0, MaxUpkeepBatchSize: 10, - }) - require.NoError(t, err, "Error marshalling offchain config") - - signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err := ocr3.ContractSetConfigArgsForTests( - 10*time.Second, // deltaProgress time.Duration, - 15*time.Second, // deltaResend time.Duration, - 500*time.Millisecond, // deltaInitial time.Duration, - 1000*time.Millisecond, // deltaRound time.Duration, - 200*time.Millisecond, // deltaGrace time.Duration, - 300*time.Millisecond, // deltaCertifiedCommitRequest time.Duration - 15*time.Second, // deltaStage time.Duration, - 24, // rMax uint64, - S, // s []int, - oracleIdentities, // oracles []OracleIdentityExtra, - offC, // reportingPluginConfig []byte, - 20*time.Millisecond, // maxDurationQuery time.Duration, - 20*time.Millisecond, // maxDurationObservation time.Duration, // good to here - 1200*time.Millisecond, // maxDurationShouldAcceptAttestedReport time.Duration, - 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, - 1, // f int, - nil, // onchainConfig []byte, - ) - require.NoError(t, err, "Error setting OCR config vars") - - var signers []common.Address - for _, signer := range signerOnchainPublicKeys { - require.Equal(t, 20, len(signer), "OnChainPublicKey '%v' has wrong length for address", signer) - signers = append(signers, common.BytesToAddress(signer)) } - - var transmitters []common.Address - for _, transmitter := range transmitterAccounts { - require.True(t, common.IsHexAddress(string(transmitter)), "TransmitAccount '%s' is not a valid Ethereum address", string(transmitter)) - transmitters = append(transmitters, common.HexToAddress(string(transmitter))) + a.PublicConfig = ocr3.PublicConfig{ + DeltaProgress: 10 * time.Second, + DeltaResend: 15 * time.Second, + DeltaInitial: 500 * time.Millisecond, + DeltaRound: 1000 * time.Millisecond, + DeltaGrace: 200 * time.Millisecond, + DeltaCertifiedCommitRequest: 300 * time.Millisecond, + DeltaStage: 15 * time.Second, + RMax: 24, + MaxDurationQuery: 20 * time.Millisecond, + MaxDurationObservation: 20 * time.Millisecond, + MaxDurationShouldAcceptAttestedReport: 1200 * time.Millisecond, + MaxDurationShouldTransmitAcceptedReport: 20 * time.Millisecond, + F: 1, } - onchainConfig, err := registrySettings.EncodeOnChainConfig(registrar.Address(), common.HexToAddress(chainClient.GetDefaultWallet().Address())) - require.NoError(t, err, "Error encoding onchain config") - l.Info().Msg("Done building OCR config") - ocrConfig := contracts.OCRv2Config{ - Signers: signers, - Transmitters: transmitters, - F: f, - OnchainConfig: onchainConfig, - OffchainConfigVersion: offchainConfigVersion, - OffchainConfig: offchainConfig, - } + a.SetupAutomationDeployment(t) - err = registry.SetConfig(*registrySettings, ocrConfig) - require.NoError(t, err, "Error setting registry config") + err = actions.FundChainlinkNodesAddress(chainlinkNodes[1:], chainClient, big.NewFloat(100), 0) + require.NoError(t, err, "Error funding chainlink nodes") consumerContracts := make([]contracts.KeeperConsumer, 0) triggerContracts := make([]contracts.LogEmitter, 0) utilsABI, err := automation_utils_2_1.AutomationUtilsMetaData.GetAbi() require.NoError(t, err, "Error getting automation utils abi") - registrarABI, err := registrar21.AutomationRegistrarMetaData.GetAbi() - require.NoError(t, err, "Error getting automation registrar abi") emitterABI, err := log_emitter.LogEmitterMetaData.GetAbi() require.NoError(t, err, "Error getting log emitter abi") consumerABI, err := simple_log_upkeep_counter_wrapper.SimpleLogUpkeepCounterMetaData.GetAbi() @@ -382,8 +334,8 @@ func TestLogTrigger(t *testing.T) { var bytes0 = [32]byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } - registrationTxHashes := make([]common.Hash, 0) - upkeepIds := make([]*big.Int, 0) + + upkeepConfigs := make([]automationv2.UpkeepConfig, 0) for i := 0; i < numberOfUpkeeps; i++ { consumerContract, err := contractDeployer.DeployAutomationSimpleLogTriggerConsumer() @@ -427,49 +379,32 @@ func TestLogTrigger(t *testing.T) { require.NoError(t, err, "Error encoding log trigger config") l.Debug().Bytes("Encoded Log Trigger Config", encodedLogTriggerConfig).Msg("Encoded Log Trigger Config") - registrationRequest, err := registrarABI.Pack( - "register", - fmt.Sprintf("LogTriggerUpkeep-%d", i), - []byte("test@mail.com"), - common.HexToAddress(consumerContract.Address()), - automationDefaultUpkeepGasLimit, - common.HexToAddress(chainClient.GetDefaultWallet().Address()), - uint8(1), - []byte("0"), - encodedLogTriggerConfig, - []byte("0"), - automationDefaultLinkFunds, - common.HexToAddress(chainClient.GetDefaultWallet().Address()), - ) - require.NoError(t, err, "Error encoding upkeep registration request") - tx, err := linkToken.TransferAndCall(registrar.Address(), automationDefaultLinkFunds, registrationRequest) - require.NoError(t, err, "Error sending upkeep registration request") - registrationTxHashes = append(registrationTxHashes, tx.Hash()) + upkeepConfig := automationv2.UpkeepConfig{ + UpkeepName: fmt.Sprintf("LogTriggerUpkeep-%d", i), + EncryptedEmail: []byte("test@mail.com"), + UpkeepContract: common.HexToAddress(consumerContract.Address()), + GasLimit: automationDefaultUpkeepGasLimit, + AdminAddress: common.HexToAddress(chainClient.GetDefaultWallet().Address()), + TriggerType: uint8(1), + CheckData: []byte("0"), + TriggerConfig: encodedLogTriggerConfig, + OffchainConfig: []byte("0"), + FundingAmount: automationDefaultLinkFunds, + } + upkeepConfigs = append(upkeepConfigs, upkeepConfig) } + registrationTxHashes, err := a.RegisterUpkeeps(upkeepConfigs) + require.NoError(t, err, "Error registering upkeeps") + err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for upkeeps to be registered") - - for _, txHash := range registrationTxHashes { - receipt, err := chainClient.GetTxReceipt(txHash) - require.NoError(t, err, "Registration tx should be completed") - var upkeepId *big.Int - for _, rawLog := range receipt.Logs { - parsedUpkeepId, err := registry.ParseUpkeepIdFromRegisteredLog(rawLog) - if err == nil { - upkeepId = parsedUpkeepId - break - } - } - require.NotNil(t, upkeepId, "Upkeep ID should be found after registration") - l.Debug(). - Str("TxHash", txHash.String()). - Str("Upkeep ID", upkeepId.String()). - Msg("Found upkeepId in tx hash") - upkeepIds = append(upkeepIds, upkeepId) - } - l.Info().Msg("Successfully registered all Automation Consumer Contracts") - l.Info().Interface("Upkeep IDs", upkeepIds).Msg("Upkeep IDs") + require.NoError(t, err, "Failed waiting for upkeeps to register") + + upkeepIds, err := a.ConfirmUpkeepsRegistered(registrationTxHashes) + require.NoError(t, err, "Error confirming upkeeps registered") + + l.Info().Msg("Successfully registered all Automation Upkeeps") + l.Info().Interface("Upkeep IDs", upkeepIds).Msg("Upkeeps Registered") l.Info().Str("STARTUP_WAIT_TIME", StartupWaitTime.String()).Msg("Waiting for plugin to start") time.Sleep(StartupWaitTime) @@ -523,7 +458,7 @@ func TestLogTrigger(t *testing.T) { upkeepDelays := make([][]int64, 0) var numberOfEventsEmitted int - var batchSize = 500 + var batchSize uint64 = 500 for _, gen := range p.Generators { numberOfEventsEmitted += len(gen.GetData().OKData.Data) @@ -531,38 +466,47 @@ func TestLogTrigger(t *testing.T) { numberOfEventsEmitted = numberOfEventsEmitted * numberOfEvents l.Info().Int("Number of Events Emitted", numberOfEventsEmitted).Msg("Number of Events Emitted") - if endBlock-startBlock < uint64(batchSize) { - batchSize = int(endBlock - startBlock) + if endBlock-startBlock < batchSize { + batchSize = endBlock - startBlock } - for cIter, consumerContract := range consumerContracts { + for _, consumerContract := range consumerContracts { var ( logs []types.Log address = common.HexToAddress(consumerContract.Address()) timeout = 5 * time.Second ) - for fromBlock := startBlock; fromBlock < endBlock; fromBlock += uint64(batchSize) + 1 { - var ( - filterQuery = geth.FilterQuery{ - Addresses: []common.Address{address}, - FromBlock: big.NewInt(0).SetUint64(fromBlock), - ToBlock: big.NewInt(0).SetUint64(fromBlock + uint64(batchSize)), - Topics: [][]common.Hash{{consumerABI.Events["PerformingUpkeep"].ID}}, + for fromBlock := startBlock; fromBlock < endBlock; fromBlock += batchSize + 1 { + filterQuery := geth.FilterQuery{ + Addresses: []common.Address{address}, + FromBlock: big.NewInt(0).SetUint64(fromBlock), + ToBlock: big.NewInt(0).SetUint64(fromBlock + batchSize), + Topics: [][]common.Hash{{consumerABI.Events["PerformingUpkeep"].ID}}, + } + err = fmt.Errorf("initial error") // to ensure our for loop runs at least once + for err != nil { + var ( + logsInBatch []types.Log + ) + ctx2, cancel := context.WithTimeout(ctx, timeout) + logsInBatch, err = chainClient.FilterLogs(ctx2, filterQuery) + cancel() + if err != nil { + l.Error().Err(err). + Interface("FilterQuery", filterQuery). + Str("Contract Address", consumerContract.Address()). + Str("Timeout", timeout.String()). + Msg("Error getting logs") + timeout = time.Duration(math.Min(float64(timeout)*2, float64(2*time.Minute))) + continue } - ) - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, timeout) - logsInBatch, err := chainClient.FilterLogs(ctx, filterQuery) - cancel() - if err != nil { - l.Error().Err(err). + l.Info(). Interface("FilterQuery", filterQuery). Str("Contract Address", consumerContract.Address()). Str("Timeout", timeout.String()). - Msg("Error getting logs") + Msg("Collected logs") + logs = append(logs, logsInBatch...) } - logs = append(logs, logsInBatch...) - time.Sleep(time.Millisecond * 500) } if len(logs) > 0 { @@ -582,9 +526,6 @@ func TestLogTrigger(t *testing.T) { } upkeepDelays = append(upkeepDelays, delay) } - if (cIter+1)%batchSize == 0 { - time.Sleep(time.Millisecond * 500) - } } l.Info().Interface("Upkeep Delays", upkeepDelays).Msg("Upkeep Delays") @@ -596,6 +537,8 @@ func TestLogTrigger(t *testing.T) { } avg, median, ninetyPct, ninetyNinePct, maximum := testreporters.IntListStats(allUpkeepDelays) + eventsMissed := numberOfEventsEmitted - len(allUpkeepDelays) + percentMissed := float64(eventsMissed) / float64(numberOfEventsEmitted) * 100 l.Info(). Float64("Average", avg).Int64("Median", median). Int64("90th Percentile", ninetyPct).Int64("99th Percentile", ninetyNinePct). @@ -604,13 +547,15 @@ func TestLogTrigger(t *testing.T) { l.Info(). Int("Total Perform Count", len(allUpkeepDelays)). Int("Total Events Emitted", numberOfEventsEmitted). - Int("Total Events Missed", numberOfEventsEmitted-len(allUpkeepDelays)). + Int("Total Events Missed", eventsMissed). + Float64("Percent Missed", percentMissed). Msg("Test completed") testReport := fmt.Sprintf("Upkeep Delays in seconds\nAverage: %f\nMedian: %d\n90th Percentile: %d\n"+ - "99th Percentile: %d\nMax: %d\nTotal Perform Count: %d\n\nTotal Events Emitted: %d\nTotal Events Missed: %d\nTest Duration: %s\n", + "99th Percentile: %d\nMax: %d\nTotal Perform Count: %d\n\nTotal Events Emitted: %d\nTotal Events Missed: %d\n"+ + "Percent Missed: %f\nTest Duration: %s\n", avg, median, ninetyPct, ninetyNinePct, maximum, len(allUpkeepDelays), numberOfEventsEmitted, - numberOfEventsEmitted-len(allUpkeepDelays), testDuration.String()) + eventsMissed, percentMissed, testDuration.String()) err = sendSlackNotification("Finished", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), strconv.FormatInt(startTime.UnixMilli(), 10), strconv.FormatInt(endTime.UnixMilli(), 10), diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 81b484f4e7..f72843e77e 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -10,12 +10,20 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" + ctfTestEnv "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + + ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + + ocr2keepers30config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" + + "github.com/smartcontractkit/chainlink/integration-tests/actions/automationv2" + "github.com/kelseyhightower/envconfig" + + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" @@ -27,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -37,28 +44,13 @@ import ( var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) const ( - automationDefaultUpkeepGasLimit = uint32(2500000) - automationDefaultLinkFunds = int64(9e18) - automationDefaultUpkeepsToDeploy = 10 - automationExpectedData = "abcdef" - defaultAmountOfUpkeeps = 2 + automationDefaultUpkeepGasLimit = uint32(2500000) + automationDefaultLinkFunds = int64(9e18) + automationExpectedData = "abcdef" + defaultAmountOfUpkeeps = 2 ) var ( - defaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ - PaymentPremiumPPB: uint32(200000000), - FlatFeeMicroLINK: uint32(0), - BlockCountPerTurn: big.NewInt(10), - CheckGasLimit: uint32(2500000), - StalenessSeconds: big.NewInt(90000), - GasCeilingMultiplier: uint16(1), - MinUpkeepSpend: big.NewInt(0), - MaxPerformGas: uint32(5000000), - FallbackGasPrice: big.NewInt(2e11), - FallbackLinkPrice: big.NewInt(2e18), - MaxCheckDataSize: uint32(5000), - MaxPerformDataSize: uint32(5000), - } automationDefaultRegistryConfig = contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(200000000), FlatFeeMicroLINK: uint32(0), @@ -124,17 +116,17 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { isMercuryV03 := name == "registry_2_1_with_mercury_v03" isMercury := isMercuryV02 || isMercuryV03 - chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, isMercuryV02, isMercuryV03, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, isMercuryV02, isMercuryV03, ) consumers, upkeepIDs := actions.DeployConsumers( t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, @@ -155,7 +147,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { privilegeConfigBytes, _ := json.Marshal(streams.UpkeepPrivilegeConfig{ MercuryEnabled: true, }) - if err := registry.SetUpkeepPrivilegeConfig(upkeepIDs[i], privilegeConfigBytes); err != nil { + if err := a.Registry.SetUpkeepPrivilegeConfig(upkeepIDs[i], privilegeConfigBytes); err != nil { l.Error().Msg("Error when setting upkeep privilege config") return } @@ -184,7 +176,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { expect := 5 // Upgrade the nodes one at a time and check that the upkeeps are still being performed for i := 0; i < 5; i++ { - err = actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, testEnv.ClCluster.Nodes[i]) + err = actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, a.DockerEnv.ClCluster.Nodes[i]) require.NoError(t, err, "Error when upgrading node %d", i) time.Sleep(time.Second * 10) expect = expect + 5 @@ -203,11 +195,11 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { // Cancel all the registered upkeeps via the registry for i := 0; i < len(upkeepIDs); i++ { - err := registry.CancelUpkeep(upkeepIDs[i]) + err := a.Registry.CancelUpkeep(upkeepIDs[i]) require.NoError(t, err, "Could not cancel upkeep at index %d", i) } - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error encountered when waiting for upkeeps to be cancelled") var countersAfterCancellation = make([]*big.Int, len(upkeepIDs)) @@ -238,17 +230,17 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, ethereum.RegistryVersion_2_1, automationDefaultRegistryConfig, false, false, ) consumers, upkeepIDs := actions.DeployConsumers( t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, @@ -313,11 +305,11 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { return } - err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + err = a.Registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) } - err := chainClient.WaitForEvents() + err := a.ChainClient.WaitForEvents() require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") var countersAfterSetNoMatch = make([]*big.Int, len(upkeepIDs)) @@ -361,11 +353,11 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { return } - err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + err = a.Registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) } - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") var countersAfterSetMatch = make([]*big.Int, len(upkeepIDs)) @@ -413,11 +405,23 @@ func TestAutomationAddFunds(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(1), automationDefaultUpkeepGasLimit, false, false) + consumers, upkeepIDs := actions.DeployConsumers( + t, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, + defaultAmountOfUpkeeps, + big.NewInt(1), + automationDefaultUpkeepGasLimit, + false, + false, + ) gom := gomega.NewGomegaWithT(t) // Since the upkeep is currently underfunded, check that it doesn't get executed @@ -429,15 +433,15 @@ func TestAutomationAddFunds(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Grant permission to the registry to fund the upkeep - err := linkToken.Approve(registry.Address(), big.NewInt(9e18)) + err := a.LinkToken.Approve(a.Registry.Address(), big.NewInt(9e18)) require.NoError(t, err, "Could not approve permissions for the registry on the link token contract") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") // Add funds to the upkeep whose ID we know from above - err = registry.AddUpkeepFunds(upkeepIDs[0], big.NewInt(9e18)) + err = a.Registry.AddUpkeepFunds(upkeepIDs[0], big.NewInt(9e18)) require.NoError(t, err, "Unable to add upkeep") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") // Now the new upkeep should be performing because we added enough funds @@ -464,11 +468,23 @@ func TestAutomationPauseUnPause(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) + consumers, upkeepIDs := actions.DeployConsumers( + t, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, + defaultAmountOfUpkeeps, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + false, + false, + ) gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { @@ -484,11 +500,11 @@ func TestAutomationPauseUnPause(t *testing.T) { // pause all the registered upkeeps via the registry for i := 0; i < len(upkeepIDs); i++ { - err := registry.PauseUpkeep(upkeepIDs[i]) + err := a.Registry.PauseUpkeep(upkeepIDs[i]) require.NoError(t, err, "Could not pause upkeep at index %d", i) } - err := chainClient.WaitForEvents() + err := a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for upkeeps to be paused") var countersAfterPause = make([]*big.Int, len(upkeepIDs)) @@ -513,11 +529,11 @@ func TestAutomationPauseUnPause(t *testing.T) { // unpause all the registered upkeeps via the registry for i := 0; i < len(upkeepIDs); i++ { - err := registry.UnpauseUpkeep(upkeepIDs[i]) + err := a.Registry.UnpauseUpkeep(upkeepIDs[i]) require.NoError(t, err, "Could not unpause upkeep at index %d", i) } - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for upkeeps to be unpaused") gom.Eventually(func(g gomega.Gomega) { @@ -547,11 +563,23 @@ func TestAutomationRegisterUpkeep(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) + consumers, upkeepIDs := actions.DeployConsumers( + t, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, + defaultAmountOfUpkeeps, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + false, + false, + ) var initialCounters = make([]*big.Int, len(upkeepIDs)) gom := gomega.NewGomegaWithT(t) @@ -571,8 +599,8 @@ func TestAutomationRegisterUpkeep(t *testing.T) { } }, "4m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~1m for performing each upkeep once, ~2m buffer - newConsumers, _ := actions.RegisterNewUpkeeps(t, contractDeployer, chainClient, linkToken, - registry, registrar, automationDefaultUpkeepGasLimit, 1) + newConsumers, _ := actions.RegisterNewUpkeeps(t, a.Deployer, a.ChainClient, a.LinkToken, + a.Registry, a.Registrar, automationDefaultUpkeepGasLimit, 1) // We know that newConsumers has size 1, so we can just use the newly registered upkeep. newUpkeep := newConsumers[0] @@ -618,11 +646,23 @@ func TestAutomationPauseRegistry(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) + consumers, upkeepIDs := actions.DeployConsumers( + t, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, + defaultAmountOfUpkeeps, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + false, + false, + ) gom := gomega.NewGomegaWithT(t) // Observe that the upkeeps which are initially registered are performing @@ -636,9 +676,9 @@ func TestAutomationPauseRegistry(t *testing.T) { }, "4m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~1m for performing each upkeep once, ~2m buffer // Pause the registry - err := registry.Pause() + err := a.Registry.Pause() require.NoError(t, err, "Error pausing registry") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for registry to pause") // Store how many times each upkeep performed once the registry was successfully paused @@ -676,13 +716,25 @@ func TestAutomationKeeperNodesDown(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) + consumers, upkeepIDs := actions.DeployConsumers( + t, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, + defaultAmountOfUpkeeps, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + false, + false, + ) gom := gomega.NewGomegaWithT(t) - nodesWithoutBootstrap := chainlinkNodes[1:] + nodesWithoutBootstrap := a.ChainlinkNodes[1:] var initialCounters = make([]*big.Int, len(upkeepIDs)) @@ -691,6 +743,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { counter, err := consumers[i].Counter(testcontext.Get(t)) initialCounters[i] = counter + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(0)), "Expected consumer counter to be greater than 0, but got %d", counter.Int64()) @@ -700,7 +753,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { // Take down 1 node. Currently, using 4 nodes so f=1 and is the max nodes that can go down. err := nodesWithoutBootstrap[0].MustDeleteJob("1") require.NoError(t, err, "Error deleting job from Chainlink node") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for blockchain events") l.Info().Msg("Successfully managed to take down the first half of the nodes") @@ -709,6 +762,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { for i := 0; i < len(upkeepIDs); i++ { currentCounter, err := consumers[i].Counter(testcontext.Get(t)) + l.Info().Int64("Upkeeps Performed", currentCounter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) g.Expect(currentCounter.Int64()).Should(gomega.BeNumerically(">", initialCounters[i].Int64()), "Expected counter to have increased from initial value of %s, but got %s", @@ -721,7 +775,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { for _, nodeToTakeDown := range restOfNodesDown { err = nodeToTakeDown.MustDeleteJob("1") require.NoError(t, err, "Error deleting job from Chainlink node") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for blockchain events") } l.Info().Msg("Successfully managed to take down the second half of the nodes") @@ -761,17 +815,17 @@ func TestAutomationPerformSimulation(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) consumersPerformance, _ := actions.DeployPerformanceConsumers( t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, @@ -797,7 +851,7 @@ func TestAutomationPerformSimulation(t *testing.T) { // Set performGas on consumer to be low, so that performUpkeep starts becoming successful err := consumerPerformance.SetPerformGasToBurn(testcontext.Get(t), big.NewInt(100000)) require.NoError(t, err, "Perform gas should be set successfully on consumer") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for set perform gas tx") // Upkeep should now start performing @@ -825,17 +879,17 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, @@ -846,7 +900,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - nodesWithoutBootstrap := chainlinkNodes[1:] + nodesWithoutBootstrap := a.ChainlinkNodes[1:] consumerPerformance := consumersPerformance[0] upkeepID := upkeepIDs[0] @@ -861,9 +915,9 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Increase gas limit for the upkeep, higher than the performGasBurn - err := registry.SetUpkeepGasLimit(upkeepID, uint32(4500000)) + err := a.Registry.SetUpkeepGasLimit(upkeepID, uint32(4500000)) require.NoError(t, err, "Error setting upkeep gas limit") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetUpkeepGasLimit tx") // Upkeep should now start performing @@ -878,7 +932,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { // Now increase the checkGasBurn on consumer, upkeep should stop performing err = consumerPerformance.SetCheckGasToBurn(testcontext.Get(t), big.NewInt(3000000)) require.NoError(t, err, "Check gas burn should be set successfully on consumer") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetCheckGasToBurn tx") // Get existing performed count @@ -906,12 +960,12 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { highCheckGasLimit.CheckGasLimit = uint32(5000000) highCheckGasLimit.RegistryVersion = registryVersion - ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second, registry.RegistryOwnerAddress()) + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, nodesWithoutBootstrap, highCheckGasLimit, a.Registrar.Address(), 30*time.Second, a.Registry.RegistryOwnerAddress()) require.NoError(t, err, "Error building OCR config") - err = registry.SetConfig(highCheckGasLimit, ocrConfig) + err = a.Registry.SetConfig(highCheckGasLimit, ocrConfig) require.NoError(t, err, "Registry config should be set successfully!") - err = chainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for set config tx") // Upkeep should start performing again, and it should get regularly performed @@ -939,17 +993,17 @@ func TestUpdateCheckData(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, registryVersion, defaultOCRRegistryConfig, false, false, + a := setupAutomationTestDocker( + t, registryVersion, automationDefaultRegistryConfig, false, false, ) performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, + a.Registry, + a.Registrar, + a.LinkToken, + a.Deployer, + a.ChainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, @@ -970,16 +1024,16 @@ func TestUpdateCheckData(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion for i := 0; i < len(upkeepIDs); i++ { - err := registry.UpdateCheckData(upkeepIDs[i], []byte(automationExpectedData)) + err := a.Registry.UpdateCheckData(upkeepIDs[i], []byte(automationExpectedData)) require.NoError(t, err, "Could not update check data for upkeep at index %d", i) } - err := chainClient.WaitForEvents() + err := a.ChainClient.WaitForEvents() require.NoError(t, err, "Error while waiting for check data update") // retrieve new check data for all upkeeps for i := 0; i < len(upkeepIDs); i++ { - upkeep, err := registry.GetUpkeepInfo(testcontext.Get(t), upkeepIDs[i]) + upkeep, err := a.Registry.GetUpkeepInfo(testcontext.Get(t), upkeepIDs[i]) require.NoError(t, err, "Failed to get upkeep info at index %d", i) require.Equal(t, []byte(automationExpectedData), upkeep.CheckData, "Upkeep data not as expected") } @@ -1009,15 +1063,7 @@ func setupAutomationTestDocker( registryConfig contracts.KeeperRegistrySettings, isMercuryV02 bool, isMercuryV03 bool, -) ( - blockchain.EVMClient, - []*client.ChainlinkClient, - contracts.ContractDeployer, - contracts.LinkToken, - contracts.KeeperRegistry, - contracts.KeeperRegistrar, - *test_env.CLClusterTestEnv, -) { +) automationv2.AutomationTest { require.False(t, isMercuryV02 && isMercuryV03, "Cannot run test with both Mercury V02 and V03 on") l := logging.GetTestLogger(t) @@ -1080,16 +1126,6 @@ func setupAutomationTestDocker( err = env.FundChainlinkNodes(big.NewFloat(testConfig.ChainlinkNodeFunding)) require.NoError(t, err, "Error funding CL nodes") - if isMercuryV02 { - output := `{"chainlinkBlob":"0x0001c38d71fed6c320b90e84b6f559459814d068e2a1700adc931ca9717d4fe70000000000000000000000000000000000000000000000000000000001a80b52b4bf1233f9cb71144a253a1791b202113c4ab4a92fa1b176d684b4959666ff8200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004254432d5553442d415242495452554d2d544553544e4554000000000000000000000000000000000000000000000000000000000000000000000000645570be000000000000000000000000000000000000000000000000000002af2b818dc5000000000000000000000000000000000000000000000000000002af2426faf3000000000000000000000000000000000000000000000000000002af32dc209700000000000000000000000000000000000000000000000000000000012130f8df0a9745bb6ad5e2df605e158ba8ad8a33ef8a0acf9851f0f01668a3a3f2b68600000000000000000000000000000000000000000000000000000000012130f60000000000000000000000000000000000000000000000000000000000000002c4a7958dce105089cf5edb68dad7dcfe8618d7784eb397f97d5a5fade78c11a58275aebda478968e545f7e3657aba9dcbe8d44605e4c6fde3e24edd5e22c94270000000000000000000000000000000000000000000000000000000000000002459c12d33986018a8959566d145225f0c4a4e61a9a3f50361ccff397899314f0018162cf10cd89897635a0bb62a822355bd199d09f4abe76e4d05261bb44733d"}` - err = env.MockAdapter.SetStringValuePath("/client", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) - require.NoError(t, err) - } - if isMercuryV03 { - output := `{"reports":[{"feedID":"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000","validFromTimestamp":0,"observationsTimestamp":0,"fullReport":"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}]}` - err = env.MockAdapter.SetStringValuePath("/api/v1/reports/bulk", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) - require.NoError(t, err) - } } else { env, err = test_env.NewCLTestEnvBuilder(). WithTestLogger(t). @@ -1105,31 +1141,82 @@ func setupAutomationTestDocker( env.ParallelTransactions(true) nodeClients := env.ClCluster.NodeAPIs() - workerNodes := nodeClients[1:] - linkToken, err := env.ContractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Error deploying LINK token") + a := automationv2.NewAutomationTestDocker(env.EVMClient, env.ContractDeployer, nodeClients) + a.MercuryCredentialName = "cred1" + a.RegistrySettings = registryConfig + a.RegistrarSettings = contracts.KeeperRegistrarSettings{ + AutoApproveConfigType: uint8(2), + AutoApproveMaxAllowed: 1000, + MinLinkJuels: big.NewInt(0), + } + a.PluginConfig = ocr2keepers30config.OffchainConfig{ + TargetProbability: "0.999", + TargetInRounds: 1, + PerformLockoutWindow: 3_600_000, // Intentionally set to be higher than in prod for testing purpose + GasLimitPerReport: 10_300_000, + GasOverheadPerUpkeep: 300_000, + MinConfirmations: 0, + MaxUpkeepBatchSize: 10, + } + a.PublicConfig = ocr3.PublicConfig{ + DeltaProgress: 10 * time.Second, + DeltaResend: 15 * time.Second, + DeltaInitial: 500 * time.Millisecond, + DeltaRound: 1000 * time.Millisecond, + DeltaGrace: 200 * time.Millisecond, + DeltaCertifiedCommitRequest: 300 * time.Millisecond, + DeltaStage: 30 * time.Second, + RMax: 24, + MaxDurationQuery: 20 * time.Millisecond, + MaxDurationObservation: 20 * time.Millisecond, + MaxDurationShouldAcceptAttestedReport: 1200 * time.Millisecond, + MaxDurationShouldTransmitAcceptedReport: 20 * time.Millisecond, + F: 1, + } - registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( - t, - registryVersion, - registryConfig, - linkToken, - env.ContractDeployer, - env.EVMClient, - ) + a.SetupAutomationDeployment(t) + a.SetDockerEnv(env) - // Fund the registry with LINK - err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(defaultAmountOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + if isMercuryV02 || isMercuryV03 { + var imposters []ctfTestEnv.KillgraveImposter + mercuryv03Mock200 := ctfTestEnv.KillgraveImposter{ + Request: ctfTestEnv.KillgraveRequest{ + Method: http.MethodGet, + Endpoint: "/api/v1/reports/bulk", + SchemaFile: nil, + Params: &map[string]string{"feedIDs": "0x00028c915d6af0fd66bba2d0fc9405226bca8d6806333121a7d9832103d1563c", "timestamp": "{[\\d+]}"}, + Headers: nil, + }, + Response: ctfTestEnv.KillgraveResponse{ + Status: 200, + Body: `{"reports":[{"feedID":"0x00028c915d6af0fd66bba2d0fc9405226bca8d6806333121a7d9832103d1563c","validFromTimestamp":0,"observationsTimestamp":0,"fullReport":"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}]}`, + BodyFile: nil, + Headers: nil, + Delay: nil, + }, + } - err = actions.CreateOCRKeeperJobsLocal(l, nodeClients, registry.Address(), network.ChainID, 0, registryVersion) - require.NoError(t, err, "Error creating OCR Keeper Jobs") - ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, workerNodes, registryConfig, registrar.Address(), 30*time.Second, registry.RegistryOwnerAddress()) - require.NoError(t, err, "Error building OCR config vars") - err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) - require.NoError(t, err, "Registry config should be set successfully") - require.NoError(t, env.EVMClient.WaitForEvents(), "Waiting for config to be set") + mercuryv02Mock200 := ctfTestEnv.KillgraveImposter{ + Request: ctfTestEnv.KillgraveRequest{ + Method: http.MethodGet, + Endpoint: "/client", + SchemaFile: nil, + Params: &map[string]string{"feedIdHex": "{0x00028c915d6af0fd66bba2d0fc9405226bca8d6806333121a7d9832103d1563c|0x4554482d5553442d415242495452554d2d544553544e45540000000000000000}", "blockNumber": "{[\\d+]}"}, + Headers: nil, + }, + Response: ctfTestEnv.KillgraveResponse{ + Status: 200, + Body: `{"chainlinkBlob":"0x0001c38d71fed6c320b90e84b6f559459814d068e2a1700adc931ca9717d4fe70000000000000000000000000000000000000000000000000000000001a80b52b4bf1233f9cb71144a253a1791b202113c4ab4a92fa1b176d684b4959666ff8200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004254432d5553442d415242495452554d2d544553544e4554000000000000000000000000000000000000000000000000000000000000000000000000645570be000000000000000000000000000000000000000000000000000002af2b818dc5000000000000000000000000000000000000000000000000000002af2426faf3000000000000000000000000000000000000000000000000000002af32dc209700000000000000000000000000000000000000000000000000000000012130f8df0a9745bb6ad5e2df605e158ba8ad8a33ef8a0acf9851f0f01668a3a3f2b68600000000000000000000000000000000000000000000000000000000012130f60000000000000000000000000000000000000000000000000000000000000002c4a7958dce105089cf5edb68dad7dcfe8618d7784eb397f97d5a5fade78c11a58275aebda478968e545f7e3657aba9dcbe8d44605e4c6fde3e24edd5e22c94270000000000000000000000000000000000000000000000000000000000000002459c12d33986018a8959566d145225f0c4a4e61a9a3f50361ccff397899314f0018162cf10cd89897635a0bb62a822355bd199d09f4abe76e4d05261bb44733d"}`, + BodyFile: nil, + Headers: nil, + Delay: nil, + }, + } + + imposters = append(imposters, mercuryv03Mock200, mercuryv02Mock200) + a.SetupMercuryMock(t, imposters) + } - return env.EVMClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env + return *a } From 0c010cd0e6b769d56d0a1664fb4ee4d981d77d42 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Fri, 1 Dec 2023 12:39:45 +0100 Subject: [PATCH 245/327] Fix keystore enable to upsert, now restores accidentally deleted keys (#11428) --- core/services/keystore/eth.go | 11 ++++++-- core/services/keystore/eth_test.go | 45 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index a2b207044c..cea7b6762e 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -221,13 +221,18 @@ func (ks *eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt func (ks *eth) enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) q := ks.q.WithOpts(qopts...) - sql := `UPDATE evm.key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 - RETURNING *;` + sql := `INSERT INTO evm.key_states as key_states ("address", "evm_chain_id", "disabled", "created_at", "updated_at") VALUES ($1, $2, false, NOW(), NOW()) + ON CONFLICT ("address", "evm_chain_id") DO UPDATE SET "disabled" = false, "updated_at" = NOW() WHERE key_states."address" = $1 AND key_states."evm_chain_id" = $2 + RETURNING *;` if err := q.Get(state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to enable state") } - ks.keyStates.enable(address, chainID, state.UpdatedAt) + if state.CreatedAt.Equal(state.UpdatedAt) { + ks.keyStates.add(state) + } else { + ks.keyStates.enable(address, chainID, state.UpdatedAt) + } ks.notify() return nil } diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 4165350300..d9c5cf5cb8 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -541,6 +541,51 @@ func Test_EthKeyStore_SubscribeToKeyChanges(t *testing.T) { assertCountAtLeast(1) } +func Test_EthKeyStore_Enable(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + ks := keyStore.Eth() + + t.Run("already existing disabled key gets enabled", func(t *testing.T) { + k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) + require.NoError(t, ks.Add(k.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Disable(k.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Enable(k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, err) + require.Equal(t, key.Disabled, false) + }) + + t.Run("creates key, deletes it unsafely and then enable creates it again", func(t *testing.T) { + k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) + require.NoError(t, ks.Add(k.Address, testutils.SimulatedChainID)) + _, err := db.Exec("DELETE FROM evm.key_states WHERE address = $1", k.Address) + require.NoError(t, err) + require.NoError(t, ks.Enable(k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, err) + require.Equal(t, key.Disabled, false) + }) + + t.Run("creates key and enables it if it exists in the keystore, but is missing from key states db table", func(t *testing.T) { + k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) + require.NoError(t, ks.Enable(k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, err) + require.Equal(t, key.Disabled, false) + }) + + t.Run("errors if key is not present in keystore", func(t *testing.T) { + addrNotInKs := testutils.NewAddress() + require.Error(t, ks.Enable(addrNotInKs, testutils.SimulatedChainID)) + _, err := ks.GetState(addrNotInKs.Hex(), testutils.SimulatedChainID) + require.Error(t, err) + }) +} + func Test_EthKeyStore_EnsureKeys(t *testing.T) { t.Parallel() From f4a97b260a9673c7a4bbde795dea463aaa66e7bb Mon Sep 17 00:00:00 2001 From: Jim W Date: Fri, 1 Dec 2023 08:44:48 -0500 Subject: [PATCH 246/327] upgrade cosmos gogoproto (#10879) * upgrade cosmos gogoproto pkg * upgrade gogoproto for core scripts * run go mod on integrations * upgrade prometheus to 0.48 * update integrations mod * rm replace * newer grafana/loki; updated kuberesolver replace --------- Co-authored-by: Jordan Krage --- core/scripts/go.mod | 8 +- core/scripts/go.sum | 36 +- go.mod | 8 +- go.sum | 36 +- integration-tests/go.mod | 62 ++- integration-tests/go.sum | 1098 ++++---------------------------------- 6 files changed, 185 insertions(+), 1063 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 197716c2b2..2de09adab5 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -81,7 +81,7 @@ require ( github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/cosmos-sdk v0.47.4 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect - github.com/cosmos/gogoproto v1.4.10 // indirect + github.com/cosmos/gogoproto v1.4.11 // indirect github.com/cosmos/iavl v0.20.0 // indirect github.com/cosmos/ibc-go/v7 v7.0.1 // indirect github.com/cosmos/ics23/go v0.9.1-0.20221207100636-b1abd8678aab // indirect @@ -149,7 +149,7 @@ require ( github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect + github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/sessions v1.2.2 // indirect @@ -290,7 +290,7 @@ require ( github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.47.2 // indirect + github.com/prometheus/prometheus v0.48.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rjeczalik/notify v0.9.3 // indirect @@ -359,7 +359,7 @@ require ( go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.15.0 // indirect - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sync v0.5.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index c6f922432b..9157e96876 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -158,8 +158,8 @@ github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= -github.com/aws/aws-sdk-go v1.44.302/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= +github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= @@ -275,8 +275,8 @@ github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= -github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= -github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= +github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= +github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= github.com/cosmos/ibc-go/v7 v7.0.1 h1:NIBNRWjlOoFvFQu1ZlgwkaSeHO5avf4C1YQiWegt8jw= @@ -613,11 +613,11 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= +github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -625,8 +625,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -1430,8 +1430,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.47.2 h1:jWcnuQHz1o1Wu3MZ6nMJDuTI0kU5yJp9pkxh8XEkNvI= -github.com/prometheus/prometheus v0.47.2/go.mod h1:J/bmOSjgH7lFxz2gZhrWEZs2i64vMS+HIuZfmYNhJ/M= +github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= +github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= @@ -1812,8 +1812,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1914,8 +1914,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2155,8 +2155,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc= -google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0= +google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= +google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/go.mod b/go.mod index 41255bc4f0..670ec435ea 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 github.com/gin-gonic/gin v1.9.1 github.com/go-webauthn/webauthn v0.9.1 - github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 + github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 github.com/google/uuid v1.4.0 github.com/gorilla/securecookie v1.1.2 github.com/gorilla/sessions v1.2.2 @@ -58,7 +58,7 @@ require ( github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.45.0 - github.com/prometheus/prometheus v0.47.2 + github.com/prometheus/prometheus v0.48.0 github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 @@ -90,7 +90,7 @@ require ( go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 golang.org/x/crypto v0.15.0 - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/sync v0.5.0 golang.org/x/term v0.14.0 golang.org/x/text v0.14.0 @@ -144,7 +144,7 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect - github.com/cosmos/gogoproto v1.4.10 // indirect + github.com/cosmos/gogoproto v1.4.11 // indirect github.com/cosmos/iavl v0.20.0 // indirect github.com/cosmos/ibc-go/v7 v7.0.1 // indirect github.com/cosmos/ics23/go v0.9.1-0.20221207100636-b1abd8678aab // indirect diff --git a/go.sum b/go.sum index cc3e130377..74a086d6cf 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,8 @@ github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= -github.com/aws/aws-sdk-go v1.44.302/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= +github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= @@ -274,8 +274,8 @@ github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= -github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= -github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= +github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= +github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= github.com/cosmos/ibc-go/v7 v7.0.1 h1:NIBNRWjlOoFvFQu1ZlgwkaSeHO5avf4C1YQiWegt8jw= @@ -612,11 +612,11 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= +github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -624,8 +624,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -1435,8 +1435,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.47.2 h1:jWcnuQHz1o1Wu3MZ6nMJDuTI0kU5yJp9pkxh8XEkNvI= -github.com/prometheus/prometheus v0.47.2/go.mod h1:J/bmOSjgH7lFxz2gZhrWEZs2i64vMS+HIuZfmYNhJ/M= +github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= +github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= @@ -1817,8 +1817,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1920,8 +1920,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2162,8 +2162,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc= -google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0= +google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= +google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 220dc86b45..9bcd36470b 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -59,8 +59,12 @@ require ( filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect @@ -75,7 +79,7 @@ require ( github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect - github.com/aws/aws-sdk-go v1.44.302 // indirect + github.com/aws/aws-sdk-go v1.45.25 // indirect github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect @@ -86,7 +90,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect - github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee // indirect + github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -112,7 +116,7 @@ require ( github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/cosmos-sdk v0.47.4 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect - github.com/cosmos/gogoproto v1.4.10 // indirect + github.com/cosmos/gogoproto v1.4.11 // indirect github.com/cosmos/iavl v0.20.0 // indirect github.com/cosmos/ibc-go/v7 v7.0.1 // indirect github.com/cosmos/ics23/go v0.9.1-0.20221207100636-b1abd8678aab // indirect @@ -129,7 +133,7 @@ require ( github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.5+incompatible // indirect + github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -197,7 +201,7 @@ require ( github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect + github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/mux v1.8.0 // indirect @@ -206,9 +210,9 @@ require ( github.com/gorilla/websocket v1.5.1 // indirect github.com/gosimple/slug v1.13.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect - github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 // indirect - github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6 // indirect - github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 // indirect + github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f // indirect + github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4 // indirect + github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 // indirect github.com/grafana/pyroscope-go v1.0.4 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect @@ -221,7 +225,7 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/consul/api v1.22.0 // indirect + github.com/hashicorp/consul/api v1.25.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect @@ -267,10 +271,11 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/klauspost/compress v1.17.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/libp2p/go-addr-util v0.0.2 // indirect @@ -319,10 +324,10 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/miekg/dns v1.1.56 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -366,17 +371,18 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/alertmanager v0.25.1 // indirect + github.com/prometheus/alertmanager v0.26.0 // indirect github.com/prometheus/client_golang v1.17.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect - github.com/prometheus/exporter-toolkit v0.10.0 // indirect + github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.47.2 // indirect + github.com/prometheus/prometheus v0.48.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect @@ -384,7 +390,7 @@ require ( github.com/russross/blackfriday v1.6.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - github.com/sercand/kuberesolver/v4 v4.0.0 // indirect + github.com/sercand/kuberesolver/v5 v5.1.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -396,9 +402,10 @@ require ( github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect + github.com/soheilhy/cmux v0.1.5 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/spf13/afero v1.9.3 // indirect + github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -424,8 +431,6 @@ require ( github.com/ugorji/go/codec v1.2.11 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect - github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205 // indirect - github.com/weaveworks/promrus v1.2.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -440,8 +445,10 @@ require ( go.etcd.io/etcd/client/v3 v3.5.7 // indirect go.mongodb.org/mongo-driver v1.12.0 // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect + go.opentelemetry.io/collector/semconv v0.87.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect @@ -455,10 +462,10 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.15.0 // indirect - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.18.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/term v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect @@ -479,14 +486,14 @@ require ( gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.27.3 // indirect + k8s.io/api v0.28.2 // indirect k8s.io/apiextensions-apiserver v0.25.3 // indirect - k8s.io/apimachinery v0.27.3 // indirect + k8s.io/apimachinery v0.28.2 // indirect k8s.io/cli-runtime v0.25.11 // indirect - k8s.io/client-go v0.27.3 // indirect + k8s.io/client-go v0.28.2 // indirect k8s.io/component-base v0.26.2 // indirect k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect k8s.io/kubectl v0.25.11 // indirect k8s.io/utils v0.0.0-20230711102312-30195339c3c7 // indirect nhooyr.io/websocket v1.8.7 // indirect @@ -514,7 +521,4 @@ replace ( // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f - - github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 - github.com/sercand/kuberesolver/v4 => github.com/sercand/kuberesolver/v5 v5.1.1 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 134168a866..17ff5e3030 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -18,507 +18,35 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= contrib.go.opencensus.io/exporter/stackdriver v0.12.6/go.mod h1:8x999/OcIPy5ivx/wDiV7Gx4D+VUPODf0mWRGRc5kSk= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= contrib.go.opencensus.io/exporter/stackdriver v0.13.5 h1:TNaexHK16gPUoc7uzELKOU7JULqccn1NDuqUxmxSqfo= @@ -543,40 +71,34 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= -github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM= -github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA= -github.com/Azure/go-autorest/autorest/adal v0.9.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc= -github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= -github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= -github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= -github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -598,7 +120,6 @@ github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/K-Phoen/grabana v0.21.17 h1:mO/9DvJWC/qpTF/X5jQDm5eKgCBaCGypP/tEfXAvKfg= github.com/K-Phoen/grabana v0.21.17/go.mod h1:vbASQt9UiQhX4lC3/opLpJMJ8m+hsTUU2FwkQMytHK4= @@ -628,12 +149,7 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= -github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -650,10 +166,7 @@ github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKS github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -670,10 +183,9 @@ github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= -github.com/aws/aws-sdk-go v1.44.302/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= +github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g= github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI= github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4= @@ -694,8 +206,6 @@ github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsy github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= @@ -719,8 +229,8 @@ github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6r github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I= -github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY= +github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 h1:rvc39Ol6z3MvaBzXkxFC6Nfsnixq/dRypushKDd7Nc0= @@ -730,8 +240,6 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -768,16 +276,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= @@ -797,7 +296,6 @@ github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoG github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -820,7 +318,6 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -835,8 +332,8 @@ github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= -github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= -github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= +github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= +github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= github.com/cosmos/ibc-go/v7 v7.0.1 h1:NIBNRWjlOoFvFQu1ZlgwkaSeHO5avf4C1YQiWegt8jw= @@ -864,8 +361,6 @@ github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbd github.com/cucumber/common/gherkin/go/v22 v22.0.0/go.mod h1:3mJT10B2GGn3MvVPd3FwR7m2u4tLhSRhWUqJU4KN4Fg= github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= github.com/cucumber/common/messages/go/v17 v17.1.1/go.mod h1:bpGxb57tDE385Rb2EohgUadLkAbhoC4IyCFi89u/JQI= -github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= @@ -908,12 +403,14 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.97.0 h1:p9w1yCcWMZcxFSLPToNGXA96WfUVLXqoHti6GzVomL4= -github.com/digitalocean/godo v1.97.0/go.mod h1:NRpFznZFvhHjBoqZAaOD3khVzsJ3EibzKqFL4R60dmA= +github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA= +github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= -github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -936,16 +433,9 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= @@ -975,7 +465,6 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= @@ -983,8 +472,6 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+ github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= @@ -1039,11 +526,6 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -1053,8 +535,6 @@ github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -1110,8 +590,6 @@ github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogB github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -1166,13 +644,15 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= +github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= @@ -1181,13 +661,11 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= -github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= @@ -1197,10 +675,7 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1216,7 +691,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -1250,9 +724,10 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -1266,7 +741,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -1286,8 +760,6 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -1300,53 +772,33 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= +github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v1.2.0 h1:1oXyj4g54KBg/kFtCdMM6jtxSzeIyg8wv4z1HoGPp1E= -github.com/gophercloud/gophercloud v1.2.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= +github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= @@ -1362,12 +814,12 @@ github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= -github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 h1:IOks+FXJ6iO/pfbaVEf4efNw+YzYBYNCkCabyrbkFTM= -github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2/go.mod h1:zj+5BNZAVmQafV583uLTAOzRr963KPdEm4d6NPmtbwg= -github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6 h1:V5PspEXlSlNh22sMyGkgfSOVVLTsSmhbmsp1VPt8Fdc= -github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6/go.mod h1:+aWr7OBDuZMT+p0rKmLfW5saO2m3YOGBnt++IlgLhVk= -github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 h1:VXitROTlmZtLzvokNe8ZbUKpmwldM4Hy1zdNRO32jKU= -github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765/go.mod h1:DhJMrd2QInI/1CNtTN43BZuTmkccdizW1jZ+F6aHkhY= +github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f h1:gyojr97YeWZ70pKNakWv5/tKwBHuLy3icnIeCo9gQr4= +github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f/go.mod h1:8dsy5tQOkeNQyjXpm5mQsbCu3H5uzeBD35MzRQFznKU= +github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4 h1:YbfISHhpbiDvoFNxDPCicPOU/+9s4rdv9Fq/V3iRvTo= +github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4/go.mod h1:Tx2uhmS+H0pGmtqX94/KaDkRHWhIowt4iYtJLctAbEY= +github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 h1:wQ0FnSeebhJIBkgYOD06Mxk9HV2KhtEG0hp/7R+5RUQ= +github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0= github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= @@ -1391,8 +843,6 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= @@ -1406,13 +856,13 @@ github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIv github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.22.0 h1:ydEvDooB/A0c/xpsBd8GSt7P2/zYPBui4KrNip0xGjE= -github.com/hashicorp/consul/api v1.22.0/go.mod h1:zHpYgZ7TeYqS6zaszjwSt128OwESRpnhU9aGa6ue3Eg= +github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= +github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= -github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c= -github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= +github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= +github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -1437,8 +887,8 @@ github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= -github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -1470,8 +920,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/nomad/api v0.0.0-20230308192510-48e7d70fcd4b h1:EkuSTU8c/63q4LMayj8ilgg/4I5PXDFVcnqKfs9qcwI= -github.com/hashicorp/nomad/api v0.0.0-20230308192510-48e7d70fcd4b/go.mod h1:bKUb1ytds5KwUioHdvdq9jmrDqCThv95si0Ub7iNeBg= +github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= +github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= @@ -1481,8 +931,8 @@ github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7H github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/henvic/httpretty v0.0.6 h1:JdzGzKZBajBfnvlMALXXMVQWxWMF/ofTy8C3/OSUTxs= github.com/henvic/httpretty v0.0.6/go.mod h1:X38wLjWXHkXT7r2+uK8LjCMne9rsuNaBLJ+5cU2/Pmo= -github.com/hetznercloud/hcloud-go v1.41.0 h1:KJGFRRc68QiVu4PrEP5BmCQVveCP2CM26UGQUKGpIUs= -github.com/hetznercloud/hcloud-go v1.41.0/go.mod h1:NaHg47L6C77mngZhwBG652dTAztYrsZ2/iITJKhQkHA= +github.com/hetznercloud/hcloud-go/v2 v2.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyuFUhE/Ukbok= +github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= @@ -1497,7 +947,6 @@ github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= @@ -1509,8 +958,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ionos-cloud/sdk-go/v6 v6.1.4 h1:BJHhFA8Q1SZC7VOXqKKr2BV2ysQ2/4hlk1e4hZte7GY= -github.com/ionos-cloud/sdk-go/v6 v6.1.4/go.mod h1:Ox3W0iiEz0GHnfY9e5LmAxwklsxguuNFEUSu0gVRTME= +github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= +github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -1655,8 +1104,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= @@ -1666,27 +1113,23 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1930,16 +1373,13 @@ github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE9 github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/linode/linodego v1.14.1 h1:uGxQyy0BidoEpLGdvfi4cPgEW+0YUFsEGrLEhcTfjNc= -github.com/linode/linodego v1.14.1/go.mod h1:NJlzvlNtdMRRkXb0oN6UWzUkj6t+IBsyveHgZ5Ppjyk= +github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= +github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -1983,12 +1423,10 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= @@ -2000,15 +1438,13 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= @@ -2016,8 +1452,8 @@ github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+ github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -2177,10 +1613,8 @@ github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYB github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= -github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= -github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -2193,8 +1627,8 @@ github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= -github.com/ovh/go-ovh v1.3.0 h1:mvZaddk4E4kLcXhzb+cxBsMPYp2pHqiQpWYkInsuZPQ= -github.com/ovh/go-ovh v1.3.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= +github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= +github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -2213,18 +1647,15 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -2235,25 +1666,20 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pressly/goose/v3 v3.16.0 h1:xMJUsZdHLqSnCqESyKSqEfcYVYsUuup1nrOhaEFftQg= github.com/pressly/goose/v3 v3.16.0/go.mod h1:JwdKVnmCRhnF6XLQs2mHEQtucFD49cQBdRM4UiwkxsM= -github.com/prometheus/alertmanager v0.25.1 h1:LGBNMspOfv8h7brb+LWj2wnwBCg2ZuuKWTh6CAVw2/Y= -github.com/prometheus/alertmanager v0.25.1/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w= +github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc= +github.com/prometheus/alertmanager v0.26.0/go.mod h1:rVcnARltVjavgVaNnmevxK7kOn7IZavyf0KNgHkbEpU= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -2263,29 +1689,22 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= -github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= -github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= -github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= +github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 h1:oHcfzdJnM/SFppy2aUlvomk37GI33x9vgJULihE5Dt8= +github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97/go.mod h1:LoBCZeRh+5hX+fSULNyFnagYlQG/gBsyA/deNzROkq8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 h1:i5hmbBzR+VeL5pPl1ZncsJ1bpg3SO66bwkE1msJBsMA= -github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2/go.mod h1:Mm42Acga98xgA+u5yTaC3ki3i0rJEJWFpbdHN7q2trk= +github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= +github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pyroscope-io/client v0.7.1 h1:yFRhj3vbgjBxehvxQmedmUWJQ4CAfCHhn+itPsuWsHw= github.com/pyroscope-io/client v0.7.1/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU= @@ -2299,7 +1718,6 @@ github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGn github.com/regen-network/gocuke v0.6.2/go.mod h1:zYaqIHZobHyd0xOrHGPQjbhGJsuZ1oElx150u2o1xuk= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -2315,8 +1733,8 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= +github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -2329,15 +1747,13 @@ github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNl github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.14 h1:yFl3jyaSVLNYXlnNYM5z2pagEk1dYQhfr1p20T1NyKY= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.14/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= @@ -2408,6 +1824,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= @@ -2415,11 +1833,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= @@ -2503,10 +1918,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -2539,10 +1952,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= -github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205 h1:gjb7t9LCnRu14LHubyLIgrE+EYlAaREiPn/VknV7R3s= -github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205/go.mod h1:O9wmSPNVSuqxzUZPFlHnPQ8xnyvx0qBnKGFfGbj95uY= -github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= -github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= @@ -2564,7 +1973,6 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= @@ -2581,12 +1989,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= @@ -2623,13 +2028,16 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9Atxpk78bmtVdi15KhE= +go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg= +go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8= +go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= @@ -2643,8 +2051,6 @@ go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6 go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g= @@ -2652,7 +2058,6 @@ go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunT go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -2720,43 +2125,26 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -2780,12 +2168,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2833,9 +2217,9 @@ golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -2844,33 +2228,17 @@ golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= @@ -2883,28 +2251,10 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2917,10 +2267,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -2991,11 +2338,8 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -3007,47 +2351,27 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -3060,9 +2384,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= @@ -3078,8 +2399,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -3088,16 +2407,12 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -3119,7 +2434,6 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -3157,7 +2471,6 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -3165,16 +2478,10 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -3183,23 +2490,13 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -3220,44 +2517,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= +google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -3309,97 +2570,10 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= @@ -3430,29 +2604,10 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -3467,9 +2622,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -3537,8 +2689,8 @@ k8s.io/api v0.25.11 h1:4mjYDfE3yp22jrytjH0knwgzjXKkxHX4D01ZCAazvZM= k8s.io/api v0.25.11/go.mod h1:bK4UvD4bthtutNlvensrfBX21PRQ/vs2cIYggHkOOAo= k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k= k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo= -k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= -k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= k8s.io/cli-runtime v0.25.11 h1:GE2yNZm1tN+MJtw1SGMOLesLF7Kp7NVAVqRSTbXfu4o= k8s.io/cli-runtime v0.25.11/go.mod h1:r/nEINuHVEpgGhcd2WamU7hD1t/lMnSz8XM44Autltc= k8s.io/client-go v0.25.11 h1:DJQ141UsbNRI6wYSlcYLP5J5BW5Wq7Bgm42Ztq2SW70= @@ -3553,40 +2705,6 @@ k8s.io/kubectl v0.25.11 h1:6bsft5Gan6BCvQ7cJbDRFjTm4Zfq8GuUYpsWAdVngYE= k8s.io/kubectl v0.25.11/go.mod h1:8mIfgkFgT+yJ8/TlmPW1qoRh46H2si9q5nW8id7i9iM= k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= From 60a328e018ae437fd8d04ee92596435b407f5350 Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal Date: Fri, 1 Dec 2023 19:54:47 +0530 Subject: [PATCH 247/327] Add NOTE for enum duplication and todo to resovle it (#11444) --- .../plugins/ocr2keeper/evmregistry/v21/encoding/interface.go | 4 ++++ .../evmregistry/v21/mercury/upkeep_failure_reasons.go | 2 ++ .../ocr2keeper/evmregistry/v21/mercury/upkeep_states.go | 2 ++ 3 files changed, 8 insertions(+) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go index 83ace2492f..06a3e7b106 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go @@ -11,6 +11,8 @@ import ( ) const ( + // NOTE: This enum should be kept in sync with evmregistry/v21/mercury/upkeep_failure_reasons.go + // TODO (AUTO-7928) Remove this duplication // upkeep failure onchain reasons UpkeepFailureReasonNone uint8 = 0 UpkeepFailureReasonUpkeepCancelled uint8 = 1 @@ -30,6 +32,8 @@ const ( UpkeepFailureReasonSimulationFailed uint8 = 35 UpkeepFailureReasonTxHashReorged uint8 = 36 + // NOTE: This enum should be kept in sync with evmregistry/v21/mercury/upkeep_states.go + // TODO (AUTO-7928) Remove this duplication // pipeline execution error NoPipelineError uint8 = 0 CheckBlockTooOld uint8 = 1 diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go index 261fc33bd4..66f8bca402 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go @@ -2,6 +2,8 @@ package mercury type MercuryUpkeepFailureReason uint8 +// NOTE: This enum should be kept in sync with evmregistry/v21/encoding/interface.go +// TODO (AUTO-7928) Remove this duplication const ( // upkeep failure onchain reasons MercuryUpkeepFailureReasonNone MercuryUpkeepFailureReason = 0 diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go index 4e9cd14aee..0d8276ff2d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go @@ -2,6 +2,8 @@ package mercury type MercuryUpkeepState uint8 +// NOTE: This enum should be kept in sync with evmregistry/v21/encoding/interface.go +// TODO (AUTO-7928) Remove this duplication const ( NoPipelineError MercuryUpkeepState = 0 RpcFlakyFailure MercuryUpkeepState = 3 From a4b39124bb5015bc72c09e7d12e5f4f22ecfdf78 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 1 Dec 2023 09:29:51 -0500 Subject: [PATCH 248/327] Fix keystore enable to upsert, now restores accidentally deleted keys (#11438) * Fix keystore enable to upsert, now restores accidentally deleted keys * BCF-2828: adding evm.key_states insert for Disable keys evm route as well --------- Co-authored-by: ilija Co-authored-by: ilija42 <57732589+ilija42@users.noreply.github.com> --- core/services/keystore/eth.go | 13 +++++++---- core/services/keystore/eth_test.go | 35 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index cea7b6762e..0e86cccaca 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -250,13 +250,18 @@ func (ks *eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOp func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) q := ks.q.WithOpts(qopts...) - sql := `UPDATE evm.key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 - RETURNING id, address, evm_chain_id, disabled, created_at, updated_at;` + sql := `INSERT INTO evm.key_states as key_states ("address", "evm_chain_id", "disabled", "created_at", "updated_at") VALUES ($1, $2, true, NOW(), NOW()) + ON CONFLICT ("address", "evm_chain_id") DO UPDATE SET "disabled" = true, "updated_at" = NOW() WHERE key_states."address" = $1 AND key_states."evm_chain_id" = $2 + RETURNING *;` if err := q.Get(state, sql, address, chainID.String()); err != nil { - return errors.Wrap(err, "failed to enable state") + return errors.Wrap(err, "failed to disable state") } - ks.keyStates.disable(address, chainID, state.UpdatedAt) + if state.CreatedAt.Equal(state.UpdatedAt) { + ks.keyStates.add(state) + } else { + ks.keyStates.disable(address, chainID, state.UpdatedAt) + } ks.notify() return nil } diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index d9c5cf5cb8..42d6c57537 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -788,3 +788,38 @@ func Test_EthKeyStore_CheckEnabled(t *testing.T) { require.Contains(t, err.Error(), fmt.Sprintf("eth key with address %s exists but is disabled for chain 1337 (enabled only for chain IDs: 0)", addr2.Hex())) }) } + +func Test_EthKeyStore_Disable(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + ks := keyStore.Eth() + + t.Run("creates key, deletes it unsafely and then enable creates it again", func(t *testing.T) { + k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) + require.NoError(t, ks.Add(k.Address, testutils.SimulatedChainID)) + _, err := db.Exec("DELETE FROM evm.key_states WHERE address = $1", k.Address) + require.NoError(t, err) + require.NoError(t, ks.Disable(k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, err) + require.Equal(t, key.Disabled, true) + }) + + t.Run("creates key and enables it if it exists in the keystore, but is missing from key states db table", func(t *testing.T) { + k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) + require.NoError(t, ks.Disable(k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, err) + require.Equal(t, key.Disabled, true) + }) + + t.Run("errors if key is not present in keystore", func(t *testing.T) { + addrNotInKs := testutils.NewAddress() + require.Error(t, ks.Disable(addrNotInKs, testutils.SimulatedChainID)) + _, err := ks.GetState(addrNotInKs.Hex(), testutils.SimulatedChainID) + require.Error(t, err) + }) +} From 43ed486d485a0a05242d9c578f9f740ebba8f740 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 1 Dec 2023 08:31:04 -0600 Subject: [PATCH 249/327] bump golang.org/x/... (#10449) --- core/scripts/go.mod | 16 ++++++------ core/scripts/go.sum | 47 ++++++++++++++++----------------- go.mod | 20 ++++++++------ go.sum | 56 +++++++++++++++++++++------------------- integration-tests/go.mod | 20 +++++++------- integration-tests/go.sum | 47 ++++++++++++++++----------------- 6 files changed, 107 insertions(+), 99 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 2de09adab5..c2f94a7edf 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -357,17 +357,17 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.15.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.15.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.16.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 9157e96876..67752858e4 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -26,8 +26,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -1761,8 +1761,8 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1800,8 +1800,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1812,8 +1812,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= +golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1902,8 +1902,8 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1914,8 +1914,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2024,16 +2024,16 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2051,8 +2051,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2122,8 +2122,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2131,8 +2131,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -2164,8 +2164,9 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/go.mod b/go.mod index 670ec435ea..a73fa5c5d1 100644 --- a/go.mod +++ b/go.mod @@ -89,13 +89,13 @@ require ( go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.15.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/crypto v0.16.0 + golang.org/x/exp v0.0.0-20231127185646-65229373498e golang.org/x/sync v0.5.0 - golang.org/x/term v0.14.0 + golang.org/x/term v0.15.0 golang.org/x/text v0.14.0 - golang.org/x/time v0.3.0 - golang.org/x/tools v0.15.0 + golang.org/x/time v0.5.0 + golang.org/x/tools v0.16.0 gonum.org/v1/gonum v0.14.0 google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 @@ -105,6 +105,7 @@ require ( ) require ( + cloud.google.com/go/compute v1.23.3 // indirect contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect @@ -363,9 +364,12 @@ require ( go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect diff --git a/go.sum b/go.sum index 74a086d6cf..0aa3ca40a0 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -624,8 +624,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -1765,8 +1765,8 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1805,8 +1805,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1817,8 +1817,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= +golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1908,8 +1908,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1920,8 +1920,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2030,8 +2030,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2039,8 +2039,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2050,6 +2050,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -2059,8 +2060,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2129,8 +2130,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2138,8 +2139,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -2162,8 +2163,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= +google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= +google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2171,8 +2172,9 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 9bcd36470b..7f524ec492 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -460,20 +460,20 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.15.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/oauth2 v0.13.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.15.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.16.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 17ff5e3030..d4ca22912e 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -26,8 +26,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -2086,8 +2086,8 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -2129,8 +2129,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -2141,8 +2141,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= +golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -2240,8 +2240,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2253,8 +2253,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2377,8 +2377,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2386,8 +2386,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2407,8 +2407,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2482,8 +2482,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2491,8 +2491,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= @@ -2526,8 +2526,9 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= From 97bef085e4bc8db0f8e156f552fb5661ba7697c6 Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal Date: Fri, 1 Dec 2023 21:23:47 +0530 Subject: [PATCH 250/327] Delete unused custom telemetry files (#11441) --- .../plugins/ocr2keeper/custom_telemetry.go | 159 ------------------ .../ocr2keeper/custom_telemetry_test.go | 17 -- 2 files changed, 176 deletions(-) delete mode 100644 core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go delete mode 100644 core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go diff --git a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go deleted file mode 100644 index d250df4afe..0000000000 --- a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry.go +++ /dev/null @@ -1,159 +0,0 @@ -package ocr2keeper - -import ( - "context" - "encoding/hex" - "time" - - "google.golang.org/protobuf/proto" - - "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - - "github.com/smartcontractkit/chainlink-common/pkg/services" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" - "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -type AutomationCustomTelemetryService struct { - services.StateMachine - monitoringEndpoint commontypes.MonitoringEndpoint - blockSubscriber *evm21.BlockSubscriber - blockSubChanID int - threadCtrl utils.ThreadControl - lggr logger.Logger - configDigest [32]byte - contractConfigTracker types.ContractConfigTracker -} - -// NewAutomationCustomTelemetryService creates a telemetry service for new blocks and node version -func NewAutomationCustomTelemetryService(me commontypes.MonitoringEndpoint, - lggr logger.Logger, blocksub *evm21.BlockSubscriber, configTracker types.ContractConfigTracker) (*AutomationCustomTelemetryService, error) { - return &AutomationCustomTelemetryService{ - monitoringEndpoint: me, - threadCtrl: utils.NewThreadControl(), - lggr: lggr.Named("AutomationCustomTelem"), - contractConfigTracker: configTracker, - blockSubscriber: blocksub, - }, nil -} - -// Start starts Custom Telemetry Service, sends 1 NodeVersion message to endpoint at start and sends new BlockNumber messages -func (e *AutomationCustomTelemetryService) Start(ctx context.Context) error { - return e.StartOnce("AutomationCustomTelemetryService", func() error { - e.lggr.Infof("Starting: Custom Telemetry Service") - _, configDetails, err := e.contractConfigTracker.LatestConfigDetails(ctx) - if err != nil { - e.lggr.Errorf("Error occurred while getting newestConfigDetails for initialization %s", err) - } else { - e.configDigest = configDetails - e.sendNodeVersionMsg() - } - e.threadCtrl.Go(func(ctx context.Context) { - ticker := time.NewTicker(1 * time.Minute) - defer ticker.Stop() - for { - select { - case <-ticker.C: - _, newConfigDigest, err := e.contractConfigTracker.LatestConfigDetails(ctx) - if err != nil { - e.lggr.Errorf("Error occurred while getting newestConfigDetails in configDigest loop %s", err) - } - if newConfigDigest != e.configDigest { - e.configDigest = newConfigDigest - e.sendNodeVersionMsg() - } - case <-ctx.Done(): - return - } - } - }) - - chanID, blockSubscriberChan, blockSubErr := e.blockSubscriber.Subscribe() - if blockSubErr != nil { - e.lggr.Errorf("Block Subscriber Error: Subscribe(): %s", blockSubErr) - - } else { - e.blockSubChanID = chanID - e.threadCtrl.Go(func(ctx context.Context) { - e.lggr.Infof("Started: Sending BlockNumber Messages") - for { - select { - case blockHistory := <-blockSubscriberChan: - latestBlockKey, err := blockHistory.Latest() - if err != nil { - e.lggr.Errorf("BlockSubscriber BlockHistory.Latest() failed: %s", err) - continue - } - e.sendBlockNumberMsg(latestBlockKey) - case <-ctx.Done(): - return - } - } - }) - } - return nil - }) -} - -// Close stops go routines and closes channels -func (e *AutomationCustomTelemetryService) Close() error { - // use utils - return e.StopOnce("AutomationCustomTelemetryService", func() error { - e.lggr.Infof("Stopping: custom telemetry service") - e.threadCtrl.Close() - err := e.blockSubscriber.Unsubscribe(e.blockSubChanID) - if err != nil { - return err - } - e.lggr.Infof("Stopped: Custom telemetry service") - return nil - }) -} - -func (e *AutomationCustomTelemetryService) sendNodeVersionMsg() { - vMsg := &telem.NodeVersion{ - Timestamp: uint64(time.Now().UTC().UnixMilli()), - NodeVersion: static.Version, - ConfigDigest: e.configDigest[:], - } - wrappedVMsg := &telem.AutomationTelemWrapper{ - Msg: &telem.AutomationTelemWrapper_NodeVersion{ - NodeVersion: vMsg, - }, - } - bytes, err := proto.Marshal(wrappedVMsg) - if err != nil { - e.lggr.Errorf("Error occurred while marshalling the Node Version Message %s: %v", wrappedVMsg.String(), err) - } else { - e.monitoringEndpoint.SendLog(bytes) - e.lggr.Infof("NodeVersion Message Sent to Endpoint: %d", vMsg.Timestamp) - } -} - -func (e *AutomationCustomTelemetryService) sendBlockNumberMsg(blockKey ocr2keepers.BlockKey) { - blockNumMsg := &telem.BlockNumber{ - Timestamp: uint64(time.Now().UTC().UnixMilli()), - BlockNumber: uint64(blockKey.Number), - BlockHash: hex.EncodeToString(blockKey.Hash[:]), - ConfigDigest: e.configDigest[:], - } - wrappedBlockNumMsg := &telem.AutomationTelemWrapper{ - Msg: &telem.AutomationTelemWrapper_BlockNumber{ - BlockNumber: blockNumMsg, - }, - } - b, err := proto.Marshal(wrappedBlockNumMsg) - if err != nil { - e.lggr.Errorf("Error occurred while marshalling the Block Num Message %s: %v", wrappedBlockNumMsg.String(), err) - } else { - e.monitoringEndpoint.SendLog(b) - e.lggr.Infof("BlockNumber Message Sent to Endpoint: %d", blockNumMsg.Timestamp) - } -} diff --git a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go b/core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go deleted file mode 100644 index a40a3f3525..0000000000 --- a/core/services/ocr2/plugins/ocr2keeper/custom_telemetry_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package ocr2keeper - -import ( - "testing" -) - -func TestNewAutomationCustomTelemetryService(t *testing.T) { - // me := &MockMonitoringEndpoint{} - // lggr := &MockLogger{} - // blocksub := &MockBlockSubscriber{} - // configTracker := &MockContractConfigTracker{} - - // service, err := NewAutomationCustomTelemetryService(me, lggr, blocksub, configTracker) - // if err != nil { - // t.Errorf("Expected no error, but got: %v", err) - // } -} From 7aed0973eeb6517b6b22335a49582d99699538a8 Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal Date: Fri, 1 Dec 2023 21:52:28 +0530 Subject: [PATCH 251/327] Small cleanup in mercury v0.3 request code (#11442) --- .../evmregistry/v21/mercury/v03/request.go | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go index 7002e2f30a..cb3c9ef322 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go @@ -3,7 +3,6 @@ package v03 import ( "context" "encoding/json" - "errors" "fmt" "io" "net/http" @@ -62,12 +61,11 @@ func NewClient(mercuryConfig mercury.MercuryConfigProvider, httpClient mercury.H } func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (mercury.MercuryUpkeepState, mercury.MercuryUpkeepFailureReason, [][]byte, bool, time.Duration, error) { - resultLen := len(streamsLookup.Feeds) - ch := make(chan mercury.MercuryData, resultLen) if len(streamsLookup.Feeds) == 0 { return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", streamsLookup.FeedParamKey, streamsLookup.TimeParamKey, streamsLookup.Feeds) } - resultLen = 1 + resultLen := 1 // Only 1 multi-feed request is made for all feeds + ch := make(chan mercury.MercuryData, resultLen) c.threadCtrl.Go(func(ctx context.Context) { c.multiFeedsRequest(ctx, ch, streamsLookup) }) @@ -75,29 +73,22 @@ func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLo var reqErr error var retryInterval time.Duration results := make([][]byte, len(streamsLookup.Feeds)) - retryable := true - allSuccess := true + retryable := false state := mercury.NoPipelineError - for i := 0; i < resultLen; i++ { - m := <-ch - if m.Error != nil { - reqErr = errors.Join(reqErr, m.Error) - retryable = retryable && m.Retryable - allSuccess = false - if m.State != mercury.NoPipelineError { - state = m.State - } - continue + m := <-ch + if m.Error != nil { + reqErr = m.Error + retryable = m.Retryable + state = m.State + if retryable { + retryInterval = mercury.CalculateRetryConfigFn(pluginRetryKey, c.mercuryConfig) } + } else { results = m.Bytes } - // only retry when not all successful AND none are not retryable - if retryable && !allSuccess { - retryInterval = mercury.CalculateRetryConfigFn(pluginRetryKey, c.mercuryConfig) - } - // only retry when not all successful AND none are not retryable - return state, mercury.MercuryUpkeepFailureReasonNone, results, retryable && !allSuccess, retryInterval, reqErr + + return state, mercury.MercuryUpkeepFailureReasonNone, results, retryable, retryInterval, reqErr } func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.MercuryData, sl *mercury.StreamsLookup) { From 699088f7ce5801c7d1c8c26d27eb560529563984 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 1 Dec 2023 11:35:51 -0500 Subject: [PATCH 252/327] Adjust price scaling factor from 1e8 => 1e18 (#11447) --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c2f94a7edf..c7af0541c1 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -304,7 +304,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 67752858e4..7cea79eb76 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1504,8 +1504,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 h1:68YZ874EBGEGwT3lcg6Y+3GZXzyNDeDDiqLHvNMBKYc= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= diff --git a/go.mod b/go.mod index a73fa5c5d1..0343f4e715 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-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 diff --git a/go.sum b/go.sum index 0aa3ca40a0..4bd90da600 100644 --- a/go.sum +++ b/go.sum @@ -1507,8 +1507,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 h1:68YZ874EBGEGwT3lcg6Y+3GZXzyNDeDDiqLHvNMBKYc= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 7f524ec492..f95557b2bb 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 github.com/smartcontractkit/chainlink-testing-framework v1.20.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index d4ca22912e..b275f6b653 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1792,8 +1792,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589 h1:68YZ874EBGEGwT3lcg6Y+3GZXzyNDeDDiqLHvNMBKYc= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231130184744-32b4198d2589/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= From abac315dbf1d3e165d4c956b3094b73685fbd384 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 1 Dec 2023 11:31:28 -0600 Subject: [PATCH 253/327] core/services/synchronization: track go routines to block close (#11443) --- .../telemetry_ingress_batch_client.go | 22 ++++++++++--------- .../telemetry_ingress_client.go | 12 ++++++---- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go index 5f286f1617..b8dbb5e5d3 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client.go +++ b/core/services/synchronization/telemetry_ingress_batch_client.go @@ -51,7 +51,7 @@ type telemetryIngressBatchClient struct { lggr logger.Logger wgDone sync.WaitGroup - chDone chan struct{} + chDone services.StopChan telemBufferSize uint telemMaxBatchSize uint @@ -78,7 +78,7 @@ func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks key globalLogger: lggr, logging: logging, lggr: lggr.Named("TelemetryIngressBatchClient").Named(network).Named(chainID), - chDone: make(chan struct{}), + chDone: make(services.StopChan), workers: make(map[string]*telemetryIngressBatchWorker), useUniConn: useUniconn, } @@ -103,22 +103,24 @@ func (tc *telemetryIngressBatchClient) Start(ctx context.Context) error { // This is used to call RPC methods on the server if tc.telemClient == nil { // only preset for tests if tc.useUniConn { + tc.wgDone.Add(1) go func() { - // Use background context to retry forever to connect - // Blocks until we connect - conn, err := wsrpc.DialUniWithContext(ctx, tc.lggr, tc.url.String(), clientPrivKey, serverPubKey) + defer tc.wgDone.Done() + ctx2, cancel := tc.chDone.NewCtx() + defer cancel() + conn, err := wsrpc.DialUniWithContext(ctx2, tc.lggr, tc.url.String(), clientPrivKey, serverPubKey) if err != nil { - if ctx.Err() != nil { + if ctx2.Err() != nil { tc.lggr.Warnw("gave up connecting to telemetry endpoint", "err", err) } else { tc.lggr.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err) tc.SvcErrBuffer.Append(err) } - } else { - tc.telemClient = telemPb.NewTelemClient(conn) - tc.close = conn.Close - tc.connected.Store(true) + return } + tc.telemClient = telemPb.NewTelemClient(conn) + tc.close = conn.Close + tc.connected.Store(true) }() } else { // Spawns a goroutine that will eventually connect diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go index bcad01622e..75aa3106a8 100644 --- a/core/services/synchronization/telemetry_ingress_client.go +++ b/core/services/synchronization/telemetry_ingress_client.go @@ -65,14 +65,14 @@ func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore } // Start connects the wsrpc client to the telemetry ingress server -func (tc *telemetryIngressClient) Start(ctx context.Context) error { +func (tc *telemetryIngressClient) Start(context.Context) error { return tc.StartOnce("TelemetryIngressClient", func() error { privkey, err := tc.getCSAPrivateKey() if err != nil { return err } - tc.connect(ctx, privkey) + tc.connect(privkey) return nil }) @@ -95,14 +95,15 @@ func (tc *telemetryIngressClient) HealthReport() map[string]error { return map[string]error{tc.Name(): tc.Healthy()} } -func (tc *telemetryIngressClient) connect(ctx context.Context, clientPrivKey []byte) { +func (tc *telemetryIngressClient) connect(clientPrivKey []byte) { tc.wgDone.Add(1) go func() { defer tc.wgDone.Done() + ctx, cancel := tc.chDone.NewCtx() + defer cancel() serverPubKey := keys.FromHex(tc.serverPubKeyHex) - conn, err := wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportCreds(clientPrivKey, serverPubKey), wsrpc.WithLogger(tc.lggr)) if err != nil { if ctx.Err() != nil { @@ -111,6 +112,7 @@ func (tc *telemetryIngressClient) connect(ctx context.Context, clientPrivKey []b tc.lggr.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err) tc.SvcErrBuffer.Append(err) } + return } defer conn.Close() @@ -130,7 +132,9 @@ func (tc *telemetryIngressClient) connect(ctx context.Context, clientPrivKey []b } func (tc *telemetryIngressClient) handleTelemetry() { + tc.wgDone.Add(1) go func() { + defer tc.wgDone.Done() ctx, cancel := tc.chDone.NewCtx() defer cancel() for { From eac8ebd2ec1dbdee1b60a4b0814a80b36e0ed7f3 Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:41:12 -0800 Subject: [PATCH 254/327] [Functions] Fix heartbeat handler test (#11449) Response is asynchronous so we need to "await" it. --- .../functions/connector_handler_test.go | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index fe1a1baa6f..409f9cdcc5 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -7,8 +7,10 @@ import ( "errors" "math/big" "testing" + "time" geth_common "github.com/ethereum/go-ethereum/common" + "github.com/onsi/gomega" "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -300,15 +302,19 @@ func TestFunctionsConnectorHandler(t *testing.T) { connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Return(nil).Once() handler.HandleGatewayMessage(ctx, "gw1", msg) - // second call to collect the response - allowlist.On("Allow", addr).Return(true).Once() - connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { - respMsg, ok := args[2].(*api.Message) - require.True(t, ok) - require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) - require.Equal(t, functions.RequestStateInternalError, response.Status) - }).Return(nil).Once() - handler.HandleGatewayMessage(ctx, "gw1", msg) + // collect the response - should eventually result in an internal error + gomega.NewGomegaWithT(t).Eventually(func() bool { + returnedState := 0 + allowlist.On("Allow", addr).Return(true).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { + respMsg, ok := args[2].(*api.Message) + require.True(t, ok) + require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) + returnedState = response.Status + }).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + return returnedState == functions.RequestStateInternalError + }, testutils.WaitTimeout(t), 50*time.Millisecond).Should(gomega.BeTrue()) }) t.Run("heartbeat sender address doesn't match", func(t *testing.T) { From e14061892a0fd9dc983d752e514e37361da16e04 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 1 Dec 2023 12:46:55 -0500 Subject: [PATCH 255/327] mercury cache fixes (#11448) * Properly pass through config * Key cache by feed ID, NOT by req req is a pointer meaning subsequent calls to LatestReport will never hit the cache * Remove logger from config --- core/cmd/shell.go | 1 - core/internal/cltest/cltest.go | 1 - .../relay/evm/mercury/wsrpc/cache/cache.go | 53 +++++++++---------- .../evm/mercury/wsrpc/cache/cache_set.go | 23 +++----- .../evm/mercury/wsrpc/cache/cache_set_test.go | 2 +- .../evm/mercury/wsrpc/cache/cache_test.go | 22 ++++---- .../relay/evm/mercury/wsrpc/client_test.go | 4 +- core/services/relay/evm/mercury/wsrpc/pool.go | 5 +- 8 files changed, 52 insertions(+), 59 deletions(-) diff --git a/core/cmd/shell.go b/core/cmd/shell.go index daf936b36c..2e382be4cc 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -160,7 +160,6 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G loopRegistry := plugins.NewLoopRegistry(appLggr, cfg.Tracing()) mercuryPool := wsrpc.NewPool(appLggr, cache.Config{ - Logger: appLggr, LatestReportTTL: cfg.Mercury().Cache().LatestReportTTL(), MaxStaleAge: cfg.Mercury().Cache().MaxStaleAge(), LatestReportDeadline: cfg.Mercury().Cache().LatestReportDeadline(), diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index fc648486a0..8802d9c4b0 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -345,7 +345,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn loopRegistry := plugins.NewLoopRegistry(lggr, nil) mercuryPool := wsrpc.NewPool(lggr, cache.Config{ - Logger: lggr, LatestReportTTL: cfg.Mercury().Cache().LatestReportTTL(), MaxStaleAge: cfg.Mercury().Cache().MaxStaleAge(), LatestReportDeadline: cfg.Mercury().Cache().LatestReportDeadline(), diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache.go b/core/services/relay/evm/mercury/wsrpc/cache/cache.go index 4962210d58..cab5654081 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache.go @@ -63,7 +63,6 @@ type Cache interface { } type Config struct { - Logger logger.Logger // LatestReportTTL controls how "stale" we will allow a price to be e.g. if // set to 1s, a new price will always be fetched if the last result was // from more than 1 second ago. @@ -84,8 +83,8 @@ type Config struct { LatestReportDeadline time.Duration } -func NewCache(client Client, cfg Config) Cache { - return newMemCache(client, cfg) +func NewCache(lggr logger.Logger, client Client, cfg Config) Cache { + return newMemCache(lggr, client, cfg) } type cacheVal struct { @@ -164,9 +163,7 @@ type memCache struct { client Client - latestPriceTTL time.Duration - maxStaleAge time.Duration - latestReportDeadline time.Duration + cfg Config cache sync.Map @@ -174,14 +171,12 @@ type memCache struct { chStop services.StopChan } -func newMemCache(client Client, cfg Config) *memCache { +func newMemCache(lggr logger.Logger, client Client, cfg Config) *memCache { return &memCache{ services.StateMachine{}, - cfg.Logger.Named("MercuryMemCache"), + lggr.Named("MemCache"), client, - cfg.LatestReportTTL, - cfg.MaxStaleAge, - cfg.LatestReportDeadline, + cfg, sync.Map{}, sync.WaitGroup{}, make(chan (struct{})), @@ -197,10 +192,11 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest if req == nil { return nil, errors.New("req must not be nil") } - if m.latestPriceTTL <= 0 { + feedIDHex := mercuryutils.BytesToFeedID(req.FeedId).String() + if m.cfg.LatestReportTTL <= 0 { return m.client.RawClient().LatestReport(ctx, req) } - vi, _ := m.cache.LoadOrStore(req, &cacheVal{ + vi, loaded := m.cache.LoadOrStore(feedIDHex, &cacheVal{ sync.RWMutex{}, false, nil, @@ -210,24 +206,26 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest }) v := vi.(*cacheVal) + m.lggr.Tracew("LatestReport", "feedID", feedIDHex, "loaded", loaded) + // HOT PATH v.RLock() if time.Now().Before(v.expiresAt) { // CACHE HIT - promCacheHitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() defer v.RUnlock() return v.val, nil } else if v.fetching { // CACHE WAIT - promCacheWaitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + promCacheWaitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() // if someone else is fetching then wait for the fetch to complete ch := v.fetchCh v.RUnlock() return v.waitForResult(ctx, ch, m.chStop) } // CACHE MISS - promCacheMissCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + promCacheMissCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() // fallthrough to cold path and fetch v.RUnlock() @@ -235,19 +233,19 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest v.Lock() if time.Now().Before(v.expiresAt) { // CACHE HIT - promCacheHitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() defer v.RUnlock() return v.val, nil } else if v.fetching { // CACHE WAIT - promCacheWaitCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + promCacheWaitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() // if someone else is fetching then wait for the fetch to complete ch := v.fetchCh v.Unlock() return v.waitForResult(ctx, ch, m.chStop) } // CACHE MISS - promCacheMissCount.WithLabelValues(m.client.ServerURL(), mercuryutils.BytesToFeedID(req.FeedId).String()).Inc() + promCacheMissCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() // initiate the fetch and wait for result ch := v.initiateFetch() v.Unlock() @@ -269,7 +267,7 @@ const minBackoffRetryInterval = 50 * time.Millisecond // newBackoff creates a backoff for retrying func (m *memCache) newBackoff() backoff.Backoff { min := minBackoffRetryInterval - max := m.latestPriceTTL / 2 + max := m.cfg.LatestReportTTL / 2 if min > max { // avoid setting a min that is greater than max min = max @@ -293,7 +291,7 @@ func (m *memCache) fetch(req *pb.LatestReportRequest, v *cacheVal) { var val *pb.LatestReportResponse var err error defer func() { - v.completeFetch(val, err, t.Add(m.latestPriceTTL)) + v.completeFetch(val, err, t.Add(m.cfg.LatestReportTTL)) }() for { @@ -301,8 +299,8 @@ func (m *memCache) fetch(req *pb.LatestReportRequest, v *cacheVal) { ctx := memcacheCtx cancel := func() {} - if m.latestReportDeadline > 0 { - ctx, cancel = context.WithTimeoutCause(memcacheCtx, m.latestReportDeadline, errors.New("latest report fetch deadline exceeded")) + if m.cfg.LatestReportDeadline > 0 { + ctx, cancel = context.WithTimeoutCause(memcacheCtx, m.cfg.LatestReportDeadline, errors.New("latest report fetch deadline exceeded")) } // NOTE: must drop down to RawClient here otherwise we enter an @@ -330,6 +328,7 @@ func (m *memCache) fetch(req *pb.LatestReportRequest, v *cacheVal) { func (m *memCache) Start(context.Context) error { return m.StartOnce(m.Name(), func() error { + m.lggr.Debugw("MemCache starting", "config", m.cfg) m.wg.Add(1) go m.runloop() return nil @@ -339,16 +338,16 @@ func (m *memCache) Start(context.Context) error { func (m *memCache) runloop() { defer m.wg.Done() - if m.maxStaleAge == 0 { + if m.cfg.MaxStaleAge == 0 { return } - t := time.NewTicker(utils.WithJitter(m.maxStaleAge)) + t := time.NewTicker(utils.WithJitter(m.cfg.MaxStaleAge)) for { select { case <-t.C: m.cleanup() - t.Reset(utils.WithJitter(m.maxStaleAge)) + t.Reset(utils.WithJitter(m.cfg.MaxStaleAge)) case <-m.chStop: return } @@ -372,7 +371,7 @@ func (m *memCache) cleanup() { // skip cleanup if fetching return true } - if time.Now().After(v.expiresAt.Add(m.maxStaleAge)) { + if time.Now().After(v.expiresAt.Add(m.cfg.MaxStaleAge)) { // garbage collection m.cache.Delete(k) } diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go index f06f1137fb..3171c8ab64 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "sync" - "time" "golang.org/x/exp/maps" @@ -28,27 +27,26 @@ type cacheSet struct { lggr logger.Logger caches map[string]Cache - latestPriceTTL time.Duration - maxStaleAge time.Duration + cfg Config } -func NewCacheSet(cfg Config) CacheSet { - return newCacheSet(cfg) +func NewCacheSet(lggr logger.Logger, cfg Config) CacheSet { + return newCacheSet(lggr, cfg) } -func newCacheSet(cfg Config) *cacheSet { +func newCacheSet(lggr logger.Logger, cfg Config) *cacheSet { return &cacheSet{ sync.RWMutex{}, services.StateMachine{}, - cfg.Logger.Named("CacheSet"), + lggr.Named("CacheSet"), make(map[string]Cache), - cfg.LatestReportTTL, - cfg.MaxStaleAge, + cfg, } } func (cs *cacheSet) Start(context.Context) error { return cs.StartOnce("CacheSet", func() error { + cs.lggr.Debugw("CacheSet starting", "config", cs.cfg) return nil }) } @@ -93,12 +91,7 @@ func (cs *cacheSet) get(ctx context.Context, client Client) (Fetcher, error) { if exists { return c, nil } - cfg := Config{ - Logger: cs.lggr.With("serverURL", sURL), - LatestReportTTL: cs.latestPriceTTL, - MaxStaleAge: cs.maxStaleAge, - } - c = newMemCache(client, cfg) + c = newMemCache(cs.lggr, client, cs.cfg) if err := c.Start(ctx); err != nil { return nil, err } diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go index 9262fb52d3..4e19c7b56d 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go @@ -12,7 +12,7 @@ import ( func Test_CacheSet(t *testing.T) { lggr := logger.TestLogger(t) - cs := newCacheSet(Config{Logger: lggr}) + cs := newCacheSet(lggr, Config{}) ctx := testutils.Context(t) require.NoError(t, cs.Start(ctx)) t.Cleanup(func() { diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_test.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_test.go index 71f74b3b3c..6378577d8d 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache_test.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_test.go @@ -12,31 +12,33 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) const neverExpireTTL = 1000 * time.Hour // some massive value that will never expire during a test func Test_Cache(t *testing.T) { + lggr := logger.TestLogger(t) client := &mockClient{} - cfg := Config{ - Logger: logger.TestLogger(t), - } + cfg := Config{} ctx := testutils.Context(t) req1 := &pb.LatestReportRequest{FeedId: []byte{1}} req2 := &pb.LatestReportRequest{FeedId: []byte{2}} req3 := &pb.LatestReportRequest{FeedId: []byte{3}} + feedID1Hex := mercuryutils.BytesToFeedID(req1.FeedId).String() + t.Run("errors with nil req", func(t *testing.T) { - c := newMemCache(client, cfg) + c := newMemCache(lggr, client, cfg) _, err := c.LatestReport(ctx, nil) assert.EqualError(t, err, "req must not be nil") }) t.Run("with LatestReportTTL=0 does no caching", func(t *testing.T) { - c := newMemCache(client, cfg) + c := newMemCache(lggr, client, cfg) req := &pb.LatestReportRequest{} for i := 0; i < 5; i++ { @@ -58,7 +60,7 @@ func Test_Cache(t *testing.T) { t.Run("caches repeated calls to LatestReport, keyed by request", func(t *testing.T) { cfg.LatestReportTTL = neverExpireTTL client.err = nil - c := newMemCache(client, cfg) + c := newMemCache(lggr, client, cfg) t.Run("if cache is unstarted, returns error", func(t *testing.T) { // starting the cache is required for state management if we @@ -122,8 +124,8 @@ func Test_Cache(t *testing.T) { }) t.Run("re-queries when a cache item has expired", func(t *testing.T) { - vi, exists := c.cache.Load(req1) - assert.True(t, exists) + vi, exists := c.cache.Load(feedID1Hex) + require.True(t, exists) v := vi.(*cacheVal) v.expiresAt = time.Now().Add(-1 * time.Second) @@ -167,7 +169,7 @@ func Test_Cache(t *testing.T) { }) t.Run("timeouts", func(t *testing.T) { - c := newMemCache(client, cfg) + c := newMemCache(lggr, client, cfg) // simulate fetch already executing in background v := &cacheVal{ fetching: true, @@ -176,7 +178,7 @@ func Test_Cache(t *testing.T) { err: nil, expiresAt: time.Now().Add(-1 * time.Second), } - c.cache.Store(req1, v) + c.cache.Store(feedID1Hex, v) canceledCtx, cancel := context.WithCancel(testutils.Context(t)) cancel() diff --git a/core/services/relay/evm/mercury/wsrpc/client_test.go b/core/services/relay/evm/mercury/wsrpc/client_test.go index d5d1b1b5ee..9b0100a3cd 100644 --- a/core/services/relay/evm/mercury/wsrpc/client_test.go +++ b/core/services/relay/evm/mercury/wsrpc/client_test.go @@ -140,7 +140,7 @@ func Test_Client_LatestReport(t *testing.T) { t.Run("with cache disabled", func(t *testing.T) { req := &pb.LatestReportRequest{} - cacheSet := cache.NewCacheSet(cache.Config{LatestReportTTL: 0, Logger: lggr}) + cacheSet := cache.NewCacheSet(lggr, cache.Config{LatestReportTTL: 0}) resp := &pb.LatestReportResponse{} var calls int @@ -178,7 +178,7 @@ func Test_Client_LatestReport(t *testing.T) { t.Run("with caching", func(t *testing.T) { req := &pb.LatestReportRequest{} const neverExpireTTL = 1000 * time.Hour // some massive value that will never expire during a test - cacheSet := cache.NewCacheSet(cache.Config{LatestReportTTL: neverExpireTTL, Logger: lggr}) + cacheSet := cache.NewCacheSet(lggr, cache.Config{LatestReportTTL: neverExpireTTL}) resp := &pb.LatestReportResponse{} var calls int diff --git a/core/services/relay/evm/mercury/wsrpc/pool.go b/core/services/relay/evm/mercury/wsrpc/pool.go index 6c525741dd..76f9bc808b 100644 --- a/core/services/relay/evm/mercury/wsrpc/pool.go +++ b/core/services/relay/evm/mercury/wsrpc/pool.go @@ -130,9 +130,10 @@ type pool struct { } func NewPool(lggr logger.Logger, cacheCfg cache.Config) Pool { - p := newPool(lggr.Named("Mercury.WSRPCPool")) + lggr = lggr.Named("Mercury.WSRPCPool") + p := newPool(lggr) p.newClient = NewClient - p.cacheSet = cache.NewCacheSet(cacheCfg) + p.cacheSet = cache.NewCacheSet(lggr, cacheCfg) return p } From bb03a45e452e4fadfd0648c0197c011ff454b7e0 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:10:39 -0500 Subject: [PATCH 256/327] Prep for CRIB (#11418) * Make CICD work with new ECRs (#495) * Fix ECR and publish on PRs (#496) * Remove test file * Add mockserver to helm chart dependency * Add default values file * Add security contexts * Fix ref to values * Use head SHA instead of commit SHA for image tagging * Use emptyDir mount for postgres to resolve perm issues * Fix volume mounts on postgres * Fix /tmp writes and mount /tmp emptyDir * Remove custom uid * Run as same uid as postgres * Test DOCKER_METADATA_PR_HEAD_SHA disable for root image * Upgrade docker metadata action * Do a full clone * Avoid emptyDir mounts and update gid * Use head SHA when on a PR as default input * Downgrade metata action to latest on prev major * Override sha tag with HEAD value * Remove old sha tag default * Attempt to fix sha tag * Fix syntax error * Remove DOCKER_METADATA_PR_HEAD_SHA env * Refactor shared var output * Revert "Refactor shared var output" This reverts commit 2362fe6473974d4723cf5294cccec7090ab07a0f. * Revert "Remove DOCKER_METADATA_PR_HEAD_SHA env" This reverts commit a7bd01e544ad97603147ccb33576e8006056e930. * Try to make things work again * Set the host to localhost for K8s * Add user to pg_isready * Make securityContext container specific * Create init container to create /clroot * Fix volumes * Add security context to init container * Skip the chown * Remove init container * Breakout DB into its own deployment and service * Fix typo * Update localhost to db service dns * Fix path to script * Change geth /root path to /app * Create emptyDir volume for geth devchain dir * Remove full clone * Add correct inputs to mockserver * merge with develop * cleanup & verify * Add fixes for /chainlink * Remove unused env var * Set back to hardcoded repo name * Reset values back to pre rebase changes * Remove mockserver templates in favor of subchart * fix connect.toml and rename mockserver connection * Backout triggering on PR * Create new build-publish workflow for chainlink-untrusted (from PR) * Reset workflow back * Make step name accurate --------- Co-authored-by: skudasov --- .../build-sign-publish-chainlink/action.yml | 12 +- .../workflows/automation-ondemand-tests.yml | 2 +- .github/workflows/build-publish-pr.yml | 44 +++++ charts/chainlink-cluster/Chart.yaml | 7 +- charts/chainlink-cluster/README.md | 6 +- charts/chainlink-cluster/connect.toml | 2 +- .../chainlink-cluster/dashboard/dashboard.go | 42 ---- charts/chainlink-cluster/devspace.yaml | 180 ++++++++++++++++-- ...ment.yaml => chainlink-db-deployment.yaml} | 72 ++----- .../templates/chainlink-db-service.yaml | 16 ++ .../templates/chainlink-node-deployment.yaml | 97 ++++++++++ ...rvice.yaml => chainlink-node-service.yaml} | 0 .../templates/geth-config-map.yaml | 6 +- .../templates/geth-deployment.yaml | 24 ++- .../templates/mockserver-service.yaml | 14 -- .../templates/mockserver.yaml | 61 ------ .../templates/runner-deployment.yaml | 4 + charts/chainlink-cluster/values-raw-helm.yaml | 134 ------------- charts/chainlink-cluster/values.yaml | 178 +++++++++++++++++ core/chainlink.devspace.Dockerfile | 2 +- 20 files changed, 554 insertions(+), 349 deletions(-) create mode 100644 .github/workflows/build-publish-pr.yml rename charts/chainlink-cluster/templates/{chainlink-deployment.yaml => chainlink-db-deployment.yaml} (60%) create mode 100644 charts/chainlink-cluster/templates/chainlink-db-service.yaml create mode 100644 charts/chainlink-cluster/templates/chainlink-node-deployment.yaml rename charts/chainlink-cluster/templates/{chainlink-service.yaml => chainlink-node-service.yaml} (100%) delete mode 100644 charts/chainlink-cluster/templates/mockserver-service.yaml delete mode 100755 charts/chainlink-cluster/templates/mockserver.yaml delete mode 100644 charts/chainlink-cluster/values-raw-helm.yaml create mode 100644 charts/chainlink-cluster/values.yaml diff --git a/.github/actions/build-sign-publish-chainlink/action.yml b/.github/actions/build-sign-publish-chainlink/action.yml index 62add53092..8c79f651af 100644 --- a/.github/actions/build-sign-publish-chainlink/action.yml +++ b/.github/actions/build-sign-publish-chainlink/action.yml @@ -34,7 +34,7 @@ inputs: required: false git-commit-sha: description: Git commit SHA used as metadata when building the application (appears in logs) - default: ${{ github.sha }} + default: ${{ github.event.pull_request.head.sha || github.sha }} required: false aws-role-to-assume: description: The AWS role to assume as the CD user, if any. Used in configuring the docker/login-action @@ -73,7 +73,7 @@ runs: using: composite steps: - name: Set shared variables - shell: sh + shell: bash # See https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#multiline-strings run: | SHARED_IMAGES=${{ inputs.ecr-hostname }}/${{ inputs.ecr-image-name }} @@ -122,7 +122,9 @@ runs: - name: Generate docker metadata for root image id: meta-root - uses: docker/metadata-action@c4ee3adeed93b1fa6a762f209fb01608c1a22f1e # v4.4.4 + uses: docker/metadata-action@2c0bd771b40637d97bf205cbccdd294a32112176 # v4.5.0 + env: + DOCKER_METADATA_PR_HEAD_SHA: "true" with: # list of Docker images to use as base name for tags images: ${{ env.shared-images }} @@ -164,7 +166,9 @@ runs: - name: Generate docker metadata for non-root image id: meta-nonroot - uses: docker/metadata-action@c4ee3adeed93b1fa6a762f209fb01608c1a22f1e # v4.4.4 + uses: docker/metadata-action@2c0bd771b40637d97bf205cbccdd294a32112176 # v4.5.0 + env: + DOCKER_METADATA_PR_HEAD_SHA: "true" with: flavor: | latest=auto diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 5cd2182ff6..016a10252b 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -115,7 +115,7 @@ jobs: pull-requests: write id-token: write contents: read - needs: [ build-chainlink, build-test-image ] + needs: [build-chainlink, build-test-image] env: CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml new file mode 100644 index 0000000000..b958295cf2 --- /dev/null +++ b/.github/workflows/build-publish-pr.yml @@ -0,0 +1,44 @@ +name: "Build and Publish from PR" + +## +# This workflow builds and publishes a Docker image for Chainlink from a PR. +# It doesn't use an environment, has its own special IAM role, does not sign +# the image, and publishes to a special ECR repo. +## + +on: + pull_request: + +jobs: + build-publish-untrusted: + if: ${{ ! startsWith(github.ref_name, 'release/') }} + runs-on: ubuntu-20.04 + permissions: + id-token: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Build and publish chainlink image + uses: ./.github/actions/build-sign-publish-chainlink + with: + publish: true + aws-role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} + aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS_DEFAULT }} + aws-region: ${{ secrets.AWS_REGION }} + sign-images: false + ecr-hostname: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }} + ecr-image-name: chainlink-untrusted + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: build-publish-untrusted + continue-on-error: true diff --git a/charts/chainlink-cluster/Chart.yaml b/charts/chainlink-cluster/Chart.yaml index bfea29c82e..127f5b6e32 100644 --- a/charts/chainlink-cluster/Chart.yaml +++ b/charts/chainlink-cluster/Chart.yaml @@ -2,4 +2,9 @@ apiVersion: v1 name: chainlink-cluster description: Chainlink nodes cluster version: 0.1.3 -appVersion: '2.6.0' \ No newline at end of file +appVersion: "2.6.0" +dependencies: + - name: mockserver + version: "5.14.0" + repository: "@mockserver" + condition: mockserver.enabled \ No newline at end of file diff --git a/charts/chainlink-cluster/README.md b/charts/chainlink-cluster/README.md index e3cec129a9..5fb5553663 100644 --- a/charts/chainlink-cluster/README.md +++ b/charts/chainlink-cluster/README.md @@ -74,10 +74,10 @@ After that all the changes will be synced automatically Check `.profiles` to understand what is uploaded in profiles `runner` and `node` # Helm -If you would like to use `helm` directly, please uncomment data in `values-raw-helm.yaml` +If you would like to use `helm` directly, please uncomment data in `values.yaml` ## Install from local files ``` -helm install -f values-raw-helm.yaml cl-cluster . +helm install -f values.yaml cl-cluster . ``` Forward all apps (in another terminal) ``` @@ -99,7 +99,7 @@ kubectl config set-context --current --namespace cl-cluster Install ``` -helm install -f values-raw-helm.yaml cl-cluster chainlink-cluster/chainlink-cluster --version v0.1.2 +helm install -f values.yaml cl-cluster . ``` ## Create a new release diff --git a/charts/chainlink-cluster/connect.toml b/charts/chainlink-cluster/connect.toml index f0a74d4c14..1f49b5a6e3 100644 --- a/charts/chainlink-cluster/connect.toml +++ b/charts/chainlink-cluster/connect.toml @@ -9,4 +9,4 @@ cl_node_url_template = "http://app-node-%d:6688" cl_node_internal_dns_record_template = "app-node-%d" cl_node_user = "notreal@fakeemail.ch" cl_node_password = "fj293fbBnlQ!f9vNs" -mockserver_url = "http://app-mockserver:1080" \ No newline at end of file +mockserver_url = "http://mockserver:1080" \ No newline at end of file diff --git a/charts/chainlink-cluster/dashboard/dashboard.go b/charts/chainlink-cluster/dashboard/dashboard.go index b29140c040..19a596b63e 100644 --- a/charts/chainlink-cluster/dashboard/dashboard.go +++ b/charts/chainlink-cluster/dashboard/dashboard.go @@ -350,48 +350,6 @@ func (m *CLClusterDashboard) generate() error { ), ), ), - // logs - dashboard.Row( - "Logs", - row.Collapse(), - row.WithTimeSeries( - "Log Counters", - timeseries.Span(12), - timeseries.Height("200px"), - timeseries.DataSource(m.PrometheusDataSourceName), - timeseries.WithPrometheusTarget( - `log_panic_count{namespace="${namespace}"}`, - prometheus.Legend("{{pod}} - panic"), - ), - timeseries.WithPrometheusTarget( - `log_fatal_count{namespace="${namespace}"}`, - prometheus.Legend("{{pod}} - fatal"), - ), - timeseries.WithPrometheusTarget( - `log_critical_count{namespace="${namespace}"}`, - prometheus.Legend("{{pod}} - critical"), - ), - timeseries.WithPrometheusTarget( - `log_warn_count{namespace="${namespace}"}`, - prometheus.Legend("{{pod}} - warn"), - ), - timeseries.WithPrometheusTarget( - `log_error_count{namespace="${namespace}"}`, - prometheus.Legend("{{pod}} - error"), - ), - ), - m.logsRowOption("All errors", ` - {namespace="${namespace}", app="app", container="node"} - | json - | level="error" - | line_format "{{ .instance }} {{ .level }} {{ .ts }} {{ .logger }} {{ .caller }} {{ .msg }} {{ .version }} {{ .nodeTier }} {{ .nodeName }} {{ .node }} {{ .evmChainID }} {{ .nodeOrder }} {{ .mode }} {{ .nodeState }} {{ .sentryEventID }} {{ .stacktrace }}"`), - m.logsRowOption("Node 1", `{namespace="${namespace}", app="app", instance="node-1", container="node"}`), - m.logsRowOption("Node 2", `{namespace="${namespace}", app="app", instance="node-2", container="node"}`), - m.logsRowOption("Node 3", `{namespace="${namespace}", app="app", instance="node-3", container="node"}`), - m.logsRowOption("Node 4", `{namespace="${namespace}", app="app", instance="node-4", container="node"}`), - m.logsRowOption("Node 5", `{namespace="${namespace}", app="app", instance="node-5", container="node"}`), - m.logsRowOption("Node 6", `{namespace="${namespace}", app="app", instance="node-6", container="node"}`), - ), // HeadTracker dashboard.Row("Head tracker", row.Collapse(), diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index 4f7cf8641a..cb4c8bfce4 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -40,26 +40,56 @@ deployments: # they can be defined the same way in values.yml # devspace merging this "values" and "values.yml" before deploy values: - runner: - image: ${DEVSPACE_IMAGE} - stateful: false - geth: - version: v1.12.0 - wsrpc-port: 8546 - httprpc-port: 8544 - networkid: 1337 - blocktime: 1 - mockserver: - port: 1080 - db: - stateful: false + podSecurityContext: + fsGroup: 999 + chainlink: + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 14933 + runAsGroup: 999 web_port: 6688 p2p_port: 6690 nodes: - name: node-1 image: ${DEVSPACE_IMAGE} version: latest + # override default config per node + # for example, use OCRv2 P2P setup, the whole config + # toml: | + # RootDir = './clroot' + # [Log] + # JSONConsole = true + # Level = 'debug' + # [WebServer] + # AllowOrigins = '*' + # SecureCookies = false + # SessionTimeout = '999h0m0s' + # [OCR2] + # Enabled = true + # [P2P] + # [P2P.V2] + # Enabled = false + # AnnounceAddresses = [] + # DefaultBootstrappers = [] + # DeltaDial = '15s' + # DeltaReconcile = '1m0s' + # ListenAddresses = [] + # [[EVM]] + # ChainID = '1337' + # MinContractPayment = '0' + # [[EVM.Nodes]] + # Name = 'node-0' + # WSURL = 'ws://geth:8546' + # HTTPURL = 'http://geth:8544' + # [WebServer.TLS] + # HTTPSPort = 0 + # or use overridesToml to override some part of configuration + # overridesToml: | - name: node-2 image: ${DEVSPACE_IMAGE} version: latest @@ -75,11 +105,125 @@ deployments: - name: node-6 image: ${DEVSPACE_IMAGE} version: latest - prometheusMonitor: "true" - podAnnotations: { } - nodeSelector: { } - tolerations: [ ] - affinity: { } + resources: + requests: + cpu: 350m + memory: 1024Mi + limits: + cpu: 350m + memory: 1024Mi + + # each CL node have a dedicated PostgreSQL 11.15 + # use StatefulSet by setting: + # + # stateful: true + # capacity 10Gi + # + # if you are running long tests + db: + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + stateful: false + resources: + requests: + cpu: 1 + memory: 1024Mi + limits: + cpu: 1 + memory: 1024Mi + # default cluster shipped with latest Geth ( dev mode by default ) + geth: + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + version: v1.12.0 + wsrpc-port: 8546 + httprpc-port: 8544 + networkid: 1337 + blocktime: 1 + resources: + requests: + cpu: 1 + memory: 1024Mi + limits: + cpu: 1 + memory: 1024Mi + # mockserver is https://www.mock-server.com/where/kubernetes.html + # used to stub External Adapters + mockserver: + # image: "mockserver/mockserver" + # version: "mockserver-5.15.0" + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + enabled: true + releasenameOverride: mockserver + app: + runAsUser: 999 + readOnlyRootFilesystem: false + port: 1080 + resources: + requests: + cpu: 1 + memory: 1024Mi + limits: + cpu: 1 + memory: 1024Mi + runner: + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + stateful: false + resources: + requests: + cpu: 1 + memory: 512Mi + limits: + cpu: 1 + memory: 512Mi + affinity: { } + tolerations: [ ] + nodeSelector: { } + ingress: + enabled: false + className: "" + hosts: [ ] + tls: [ ] + annotations: { } + service: + type: NodePort + port: 8080 + + + # monitoring.coreos.com/v1 PodMonitor for each node + prometheusMonitor: true + + # deployment placement, standard helm stuff + podAnnotations: + nodeSelector: + tolerations: + affinity: profiles: # this replaces only "runner" pod, usable when you'd like to run some system level tests inside k8s diff --git a/charts/chainlink-cluster/templates/chainlink-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml similarity index 60% rename from charts/chainlink-cluster/templates/chainlink-deployment.yaml rename to charts/chainlink-cluster/templates/chainlink-db-deployment.yaml index b434c9894b..f335130ea9 100644 --- a/charts/chainlink-cluster/templates/chainlink-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml @@ -6,10 +6,10 @@ kind: StatefulSet kind: Deployment {{ end }} metadata: - name: {{ $.Release.Name }}-{{ $cfg.name }} + name: {{ $.Release.Name }}-{{ $cfg.name }}-db spec: {{ if $.Values.db.stateful }} - serviceName: {{ $.Release.Name }}-{{ $cfg.name }}-service + serviceName: {{ $.Release.Name }}-db-${{ $cfg.name }} podManagementPolicy: Parallel volumeClaimTemplates: - metadata: @@ -23,14 +23,14 @@ spec: {{ end }} selector: matchLabels: - app: {{ $.Release.Name }} - instance: {{ $cfg.name }} + app: {{ $.Release.Name }}-db + instance: {{ $cfg.name }}-db release: {{ $.Release.Name }} template: metadata: labels: - app: {{ $.Release.Name }} - instance: {{ $cfg.name }} + app: {{ $.Release.Name }}-db + instance: {{ $cfg.name }}-db release: {{ $.Release.Name }} {{- range $key, $value := $.Values.labels }} {{ $key }}: {{ $value | quote }} @@ -44,11 +44,16 @@ spec: {{- end }} spec: volumes: + # TODO: breakout this config map into a separate one for the db. - name: {{ $.Release.Name }}-{{ $cfg.name }}-cm configMap: name: {{ $.Release.Name }}-{{ $cfg.name }}-cm + securityContext: + {{- toYaml $.Values.db.podSecurityContext | nindent 8 }} containers: - name: chainlink-db + securityContext: + {{- toYaml $.Values.db.securityContext | nindent 12 }} image: {{ default "postgres:11.15" $.Values.db.image }} command: - docker-entrypoint.sh @@ -114,60 +119,11 @@ spec: - mountPath: /docker-entrypoint-initdb.d/init.sql name: {{ $.Release.Name }}-{{ $cfg.name }}-cm subPath: init.sql - {{ if $.Values.db.stateful }} - volumeMounts: + {{ if $.Values.db.stateful }} - mountPath: /var/lib/postgresql/data name: postgres subPath: postgres-db - {{ end }} - - name: node - image: {{ default "public.ecr.aws/chainlink/chainlink" $cfg.image }} - imagePullPolicy: Always - command: ["bash", "-c", "while ! pg_isready --host 0.0.0.0 --port 5432; do echo \"waiting for database to start\"; sleep 1; done && chainlink -c /etc/node-secrets-volume/default.toml -c /etc/node-secrets-volume/overrides.toml -secrets /etc/node-secrets-volume/secrets.toml node start -d -p /etc/node-secrets-volume/node-password -a /etc/node-secrets-volume/apicredentials --vrfpassword=/etc/node-secrets-volume/apicredentials"] - ports: - - name: access - containerPort: {{ $.Values.chainlink.web_port }} - - name: p2p - containerPort: {{ $.Values.chainlink.p2p_port }} - env: - - name: CL_DATABASE_URL - value: postgresql://postgres:verylongdatabasepassword@0.0.0.0/chainlink?sslmode=disable - - name: CL_DEV - value: "false" - volumeMounts: - - name: {{ $.Release.Name }}-{{ $cfg.name }}-cm - mountPath: /etc/node-secrets-volume/ - livenessProbe: - httpGet: - path: /health - port: {{ $.Values.chainlink.web_port }} - initialDelaySeconds: 1 - periodSeconds: 5 - timeoutSeconds: 10 - readinessProbe: - httpGet: - path: /health - port: {{ $.Values.chainlink.web_port }} - initialDelaySeconds: 1 - periodSeconds: 5 - timeoutSeconds: 10 - startupProbe: - httpGet: - path: / - port: {{ $.Values.chainlink.web_port }} - initialDelaySeconds: 15 - periodSeconds: 5 - failureThreshold: 20 - {{ if (hasKey $.Values.chainlink "resources") }} - resources: - requests: - memory: {{ default "1024Mi" $.Values.chainlink.resources.requests.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.requests.cpu }} - limits: - memory: {{ default "1024Mi" $.Values.chainlink.resources.limits.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.limits.cpu }} - {{ else }} - {{ end }} + {{ end }} {{- with $.Values.nodeSelector }} nodeSelector: {{ toYaml . | indent 8 }} @@ -181,4 +137,4 @@ spec: {{ toYaml . | indent 8 }} {{- end }} --- -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/chainlink-cluster/templates/chainlink-db-service.yaml b/charts/chainlink-cluster/templates/chainlink-db-service.yaml new file mode 100644 index 0000000000..f27bd9eab2 --- /dev/null +++ b/charts/chainlink-cluster/templates/chainlink-db-service.yaml @@ -0,0 +1,16 @@ +{{- range $cfg := .Values.chainlink.nodes }} +apiVersion: v1 +kind: Service +metadata: + name: {{ $.Release.Name }}-db-{{ $cfg.name }} +spec: + selector: + app: {{ $.Release.Name }}-db + instance: {{ $cfg.name }}-db + release: {{ $.Release.Name }} + ports: + - protocol: TCP + port: 5432 + targetPort: 5432 +--- +{{- end }} \ No newline at end of file diff --git a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml new file mode 100644 index 0000000000..463453aff9 --- /dev/null +++ b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml @@ -0,0 +1,97 @@ +{{- range $cfg := .Values.chainlink.nodes }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Release.Name }}-{{ $cfg.name }} +spec: + selector: + matchLabels: + app: {{ $.Release.Name }} + instance: {{ $cfg.name }} + release: {{ $.Release.Name }} + template: + metadata: + labels: + app: {{ $.Release.Name }} + instance: {{ $cfg.name }} + release: {{ $.Release.Name }} + {{- range $key, $value := $.Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + annotations: + prometheus.io/scrape: 'true' + {{- range $key, $value := $.Values.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + volumes: + - name: {{ $.Release.Name }}-{{ $cfg.name }}-cm + configMap: + name: {{ $.Release.Name }}-{{ $cfg.name }}-cm + securityContext: + {{- toYaml $.Values.chainlink.podSecurityContext | nindent 8 }} + containers: + - name: node + securityContext: + {{- toYaml $.Values.chainlink.securityContext | nindent 12 }} + image: {{ default "public.ecr.aws/chainlink/chainlink" $cfg.image }} + imagePullPolicy: Always + command: ["bash", "-c", "while ! pg_isready -U postgres --host {{ $.Release.Name }}-db-{{ $cfg.name }} --port 5432; do echo \"waiting for database to start\"; sleep 1; done && chainlink -c /etc/node-secrets-volume/default.toml -c /etc/node-secrets-volume/overrides.toml -secrets /etc/node-secrets-volume/secrets.toml node start -d -p /etc/node-secrets-volume/node-password -a /etc/node-secrets-volume/apicredentials --vrfpassword=/etc/node-secrets-volume/apicredentials"] + ports: + - name: access + containerPort: {{ $.Values.chainlink.web_port }} + - name: p2p + containerPort: {{ $.Values.chainlink.p2p_port }} + env: + - name: CL_DATABASE_URL + value: postgresql://postgres:verylongdatabasepassword@{{ $.Release.Name }}-db-{{ $cfg.name }}/chainlink?sslmode=disable + - name: CL_DEV + value: "false" + volumeMounts: + - name: {{ $.Release.Name }}-{{ $cfg.name }}-cm + mountPath: /etc/node-secrets-volume/ + livenessProbe: + httpGet: + path: /health + port: {{ $.Values.chainlink.web_port }} + initialDelaySeconds: 1 + periodSeconds: 5 + timeoutSeconds: 10 + readinessProbe: + httpGet: + path: /health + port: {{ $.Values.chainlink.web_port }} + initialDelaySeconds: 1 + periodSeconds: 5 + timeoutSeconds: 10 + startupProbe: + httpGet: + path: / + port: {{ $.Values.chainlink.web_port }} + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 20 + {{ if (hasKey $.Values.chainlink "resources") }} + resources: + requests: + memory: {{ default "1024Mi" $.Values.chainlink.resources.requests.memory }} + cpu: {{ default "500m" $.Values.chainlink.resources.requests.cpu }} + limits: + memory: {{ default "1024Mi" $.Values.chainlink.resources.limits.memory }} + cpu: {{ default "500m" $.Values.chainlink.resources.limits.cpu }} + {{ else }} + {{ end }} +{{- with $.Values.nodeSelector }} + nodeSelector: + {{ toYaml . | indent 8 }} +{{- end }} +{{- with $.Values.affinity }} + affinity: + {{ toYaml . | indent 8 }} +{{- end }} +{{- with $.Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} +--- +{{- end }} diff --git a/charts/chainlink-cluster/templates/chainlink-service.yaml b/charts/chainlink-cluster/templates/chainlink-node-service.yaml similarity index 100% rename from charts/chainlink-cluster/templates/chainlink-service.yaml rename to charts/chainlink-cluster/templates/chainlink-node-service.yaml diff --git a/charts/chainlink-cluster/templates/geth-config-map.yaml b/charts/chainlink-cluster/templates/geth-config-map.yaml index f3369ba580..022d9f2ea6 100644 --- a/charts/chainlink-cluster/templates/geth-config-map.yaml +++ b/charts/chainlink-cluster/templates/geth-config-map.yaml @@ -50,9 +50,9 @@ data: password.txt: | init.sh: | #!/bin/bash - if [ ! -d /root/.ethereum/keystore ]; then - echo "/root/.ethereum/keystore not found, running 'geth init'..." - geth init /root/ethconfig/genesis.json + if [ ! -d /app/.ethereum/keystore ]; then + echo "/app/.ethereum/keystore not found, running 'geth init'..." + geth init /app/ethconfig/genesis.json echo "...done!" fi diff --git a/charts/chainlink-cluster/templates/geth-deployment.yaml b/charts/chainlink-cluster/templates/geth-deployment.yaml index 11fb0cbee2..6948c4df28 100644 --- a/charts/chainlink-cluster/templates/geth-deployment.yaml +++ b/charts/chainlink-cluster/templates/geth-deployment.yaml @@ -22,31 +22,39 @@ spec: - name: configmap-volume configMap: name: geth-cm + - name: devchain-volume + emptyDir: {} + securityContext: + {{- toYaml $.Values.geth.podSecurityContext | nindent 8 }} containers: - name: geth-network + securityContext: + {{- toYaml $.Values.geth.securityContext | nindent 12 }} image: "{{ default "ethereum/client-go" .Values.geth.image }}:{{ default "stable" .Values.geth.version }}" - command: [ "sh", "./root/init.sh" ] + command: [ "sh", "/app/init.sh" ] volumeMounts: + - name: devchain-volume + mountPath: /app/.ethereum/devchain - name : configmap-volume - mountPath: /root/init.sh + mountPath: /app/init.sh subPath: init.sh - name: configmap-volume - mountPath: /root/config + mountPath: /app/config - name: configmap-volume - mountPath: /root/.ethereum/devchain/keystore/key1 + mountPath: /app/.ethereum/devchain/keystore/key1 subPath: key1 - name: configmap-volume - mountPath: /root/.ethereum/devchain/keystore/key2 + mountPath: /app/.ethereum/devchain/keystore/key2 subPath: key2 - name: configmap-volume - mountPath: /root/.ethereum/devchain/keystore/key3 + mountPath: /app/.ethereum/devchain/keystore/key3 subPath: key3 args: - '--dev' - '--password' - - '/root/config/password.txt' + - '/app/config/password.txt' - '--datadir' - - '/root/.ethereum/devchain' + - '/app/.ethereum/devchain' - '--unlock' - '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' - '--unlock' diff --git a/charts/chainlink-cluster/templates/mockserver-service.yaml b/charts/chainlink-cluster/templates/mockserver-service.yaml deleted file mode 100644 index f8ab78a84b..0000000000 --- a/charts/chainlink-cluster/templates/mockserver-service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{ if (hasKey .Values "mockserver") }} -apiVersion: v1 -kind: Service -metadata: - name: {{ .Release.Name }}-mockserver -spec: - selector: - app: {{ .Release.Name }}-mockserver - ports: - - name: serviceport - port: {{ default "1080" $.Values.mockserver.port}} - targetPort: serviceport - type: ClusterIP -{{ end }} \ No newline at end of file diff --git a/charts/chainlink-cluster/templates/mockserver.yaml b/charts/chainlink-cluster/templates/mockserver.yaml deleted file mode 100755 index 14c05d0acd..0000000000 --- a/charts/chainlink-cluster/templates/mockserver.yaml +++ /dev/null @@ -1,61 +0,0 @@ -{{ if (hasKey .Values "mockserver") }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Release.Name }}-mockserver - labels: - app: {{ .Release.Name }}-mockserver -spec: - selector: - matchLabels: - app: {{ .Release.Name }}-mockserver - template: - metadata: -{{- if .Values.podAnnotations }} - annotations: -{{ toYaml .Values.podAnnotations | indent 8 }} -{{- end }} - name: {{ .Release.Name }}-mockserver - labels: - app: {{ .Release.Name }}-mockserver - spec: - containers: - - name: {{ .Release.Name }}-mockserver - image: {{ default "mockserver/mockserver" .Values.mockserver.image }}:{{ default "mockserver-5.15.0" .Values.mockserver.version }} - imagePullPolicy: IfNotPresent - securityContext: - runAsUser: 65534 # nonroot - readOnlyRootFilesystem: false - ports: - - name: serviceport - containerPort: {{ .Values.mockserver.port }} - protocol: TCP - env: - - name: LOG_LEVEL - value: "DEBUG" - - name: SERVER_PORT - value: {{ .Values.mockserver.port | quote }} - {{ if (hasKey $.Values.chainlink "resources") }} - resources: - requests: - memory: {{ default "1024Mi" $.Values.chainlink.resources.requests.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.requests.cpu }} - limits: - memory: {{ default "1024Mi" $.Values.chainlink.resources.limits.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.limits.cpu }} - {{ else }} - {{ end }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{ toYaml . | indent 8 }} - {{- end }} -{{- end }} ---- \ No newline at end of file diff --git a/charts/chainlink-cluster/templates/runner-deployment.yaml b/charts/chainlink-cluster/templates/runner-deployment.yaml index 5d9025b41c..9d80ac1bfa 100644 --- a/charts/chainlink-cluster/templates/runner-deployment.yaml +++ b/charts/chainlink-cluster/templates/runner-deployment.yaml @@ -22,8 +22,12 @@ spec: annotations: prometheus.io/scrape: 'true' spec: + securityContext: + {{- toYaml $.Values.runner.podSecurityContext | nindent 8 }} containers: - name: runner + securityContext: + {{- toYaml $.Values.runner.securityContext | nindent 12 }} image: {{ default "public.ecr.aws/chainlink/chainlink" .Values.runner.image }} imagePullPolicy: Always command: [ "/bin/bash", "-c", "--" ] diff --git a/charts/chainlink-cluster/values-raw-helm.yaml b/charts/chainlink-cluster/values-raw-helm.yaml deleted file mode 100644 index 726a534711..0000000000 --- a/charts/chainlink-cluster/values-raw-helm.yaml +++ /dev/null @@ -1,134 +0,0 @@ -# override resources for keys "chainlink", "db", or "geth" if needed -# resources: -# requests: -# cpu: 350m -# memory: 1024Mi -# limits: -# cpu: 350m -# memory: 1024Mi -# images can be overriden for the same keys: -# image: ethereum/client-go -# version: stable -chainlink: - web_port: 6688 - p2p_port: 6690 - nodes: - - name: node-1 - image: "public.ecr.aws/chainlink/chainlink:latest" - # override default config per node - # for example, use OCRv2 P2P setup, the whole config -# toml: | -# RootDir = './clroot' -# [Log] -# JSONConsole = true -# Level = 'debug' -# [WebServer] -# AllowOrigins = '*' -# SecureCookies = false -# SessionTimeout = '999h0m0s' -# [OCR2] -# Enabled = true -# [P2P] -# [P2P.V2] -# Enabled = false -# AnnounceAddresses = [] -# DefaultBootstrappers = [] -# DeltaDial = '15s' -# DeltaReconcile = '1m0s' -# ListenAddresses = [] -# [[EVM]] -# ChainID = '1337' -# MinContractPayment = '0' -# [[EVM.Nodes]] -# Name = 'node-0' -# WSURL = 'ws://geth:8546' -# HTTPURL = 'http://geth:8544' -# [WebServer.TLS] -# HTTPSPort = 0 -# or use overridesToml to override some part of configuration -# overridesToml: | - - name: node-2 - - name: node-3 - - name: node-4 - - name: node-5 - - name: node-6 - resources: - requests: - cpu: 350m - memory: 1024Mi - limits: - cpu: 350m - memory: 1024Mi - -# each CL node have a dedicated PostgreSQL 11.15 -# use StatefulSet by setting: -# -# stateful: true -# capacity 10Gi -# -# if you are running long tests -db: - stateful: false - resources: - requests: - cpu: 1 - memory: 1024Mi - limits: - cpu: 1 - memory: 1024Mi -# default cluster shipped with latest Geth ( dev mode by default ) -geth: - version: v1.12.0 - wsrpc-port: 8546 - httprpc-port: 8544 - networkid: 1337 - blocktime: 1 - resources: - requests: - cpu: 1 - memory: 1024Mi - limits: - cpu: 1 - memory: 1024Mi -# mockserver is https://www.mock-server.com/where/kubernetes.html -# used to stub External Adapters -mockserver: - port: 1080 - resources: - requests: - cpu: 1 - memory: 1024Mi - limits: - cpu: 1 - memory: 1024Mi -runner: - stateful: false - resources: - requests: - cpu: 1 - memory: 512Mi - limits: - cpu: 1 - memory: 512Mi - affinity: { } - tolerations: [ ] - nodeSelector: { } - ingress: - enabled: false - className: "" - hosts: [ ] - tls: [ ] - annotations: { } - service: - type: NodePort - port: 8080 - - -# monitoring.coreos.com/v1 PodMonitor for each node -prometheusMonitor: false - -# deployment placement, standard helm stuff -podAnnotations: -nodeSelector: -tolerations: -affinity: diff --git a/charts/chainlink-cluster/values.yaml b/charts/chainlink-cluster/values.yaml new file mode 100644 index 0000000000..eb93e6cefc --- /dev/null +++ b/charts/chainlink-cluster/values.yaml @@ -0,0 +1,178 @@ +# override resources for keys "chainlink", "db", or "geth" if needed +# resources: +# requests: +# cpu: 350m +# memory: 1024Mi +# limits: +# cpu: 350m +# memory: 1024Mi +# images can be overriden for the same keys: +# image: ethereum/client-go +# version: stable +chainlink: + podSecurityContext: + fsGroup: 14933 + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 14933 + runAsGroup: 14933 + web_port: 6688 + p2p_port: 6690 + nodes: + - name: node-1 + image: "public.ecr.aws/chainlink/chainlink:latest" + # override default config per node + # for example, use OCRv2 P2P setup, the whole config + # toml: | + # RootDir = './clroot' + # [Log] + # JSONConsole = true + # Level = 'debug' + # [WebServer] + # AllowOrigins = '*' + # SecureCookies = false + # SessionTimeout = '999h0m0s' + # [OCR2] + # Enabled = true + # [P2P] + # [P2P.V2] + # Enabled = false + # AnnounceAddresses = [] + # DefaultBootstrappers = [] + # DeltaDial = '15s' + # DeltaReconcile = '1m0s' + # ListenAddresses = [] + # [[EVM]] + # ChainID = '1337' + # MinContractPayment = '0' + # [[EVM.Nodes]] + # Name = 'node-0' + # WSURL = 'ws://geth:8546' + # HTTPURL = 'http://geth:8544' + # [WebServer.TLS] + # HTTPSPort = 0 + # or use overridesToml to override some part of configuration + # overridesToml: | + - name: node-2 + - name: node-3 + - name: node-4 + - name: node-5 + - name: node-6 + resources: + requests: + cpu: 350m + memory: 1024Mi + limits: + cpu: 350m + memory: 1024Mi + +# each CL node have a dedicated PostgreSQL 11.15 +# use StatefulSet by setting: +# +# stateful: true +# capacity 10Gi +# +# if you are running long tests +db: + podSecurityContext: + fsGroup: 999 + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + stateful: false + resources: + requests: + cpu: 1 + memory: 1024Mi + limits: + cpu: 1 + memory: 1024Mi +# default cluster shipped with latest Geth ( dev mode by default ) +geth: + podSecurityContext: + fsGroup: 999 + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + version: v1.12.0 + wsrpc-port: 8546 + httprpc-port: 8544 + networkid: 1337 + blocktime: 1 + resources: + requests: + cpu: 1 + memory: 1024Mi + limits: + cpu: 1 + memory: 1024Mi +# mockserver is https://www.mock-server.com/where/kubernetes.html +# used to stub External Adapters +mockserver: + enabled: true + releasenameOverride: mockserver + app: + runAsUser: 999 + readOnlyRootFilesystem: false + port: 1080 + resources: + requests: + cpu: 1 + memory: 1024Mi + limits: + cpu: 1 + memory: 1024Mi +runner: + podSecurityContext: + fsGroup: 999 + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + stateful: false + resources: + requests: + cpu: 1 + memory: 512Mi + limits: + cpu: 1 + memory: 512Mi + affinity: {} + tolerations: [] + nodeSelector: {} + ingress: + enabled: false + className: "" + hosts: [] + tls: [] + annotations: {} + service: + type: NodePort + port: 8080 + +# monitoring.coreos.com/v1 PodMonitor for each node +prometheusMonitor: true + +# deployment placement, standard helm stuff +podAnnotations: +nodeSelector: +tolerations: +affinity: diff --git a/core/chainlink.devspace.Dockerfile b/core/chainlink.devspace.Dockerfile index 9ec061ae40..88d3cec16a 100644 --- a/core/chainlink.devspace.Dockerfile +++ b/core/chainlink.devspace.Dockerfile @@ -20,7 +20,7 @@ RUN make install-chainlink # Final image: ubuntu with chainlink binary FROM golang:1.21-bullseye -ARG CHAINLINK_USER=root +ARG CHAINLINK_USER=chainlink ENV DEBIAN_FRONTEND noninteractive RUN apt-get update && apt-get install -y ca-certificates gnupg lsb-release curl From fa0f16ad0acf417db1186728560278a049357914 Mon Sep 17 00:00:00 2001 From: Lei Date: Fri, 1 Dec 2023 11:04:54 -0800 Subject: [PATCH 257/327] make streams lookup modular (#11368) * make streams lookup modular * polish * address comment to use pointer instead of array/map * rebase * get rid of slice --- core/scripts/chaincli/handler/debug.go | 150 +++-- .../handler/mercury_lookup_handler.go | 534 ------------------ core/scripts/go.mod | 3 +- core/scripts/go.sum | 2 - .../v21/mercury/streams/streams.go | 143 ++--- .../v21/mercury/streams/streams_test.go | 20 +- 6 files changed, 186 insertions(+), 666 deletions(-) delete mode 100644 core/scripts/chaincli/handler/mercury_lookup_handler.go diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index fec8c6cd41..0075862d95 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -22,12 +22,17 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" @@ -36,12 +41,7 @@ import ( const ( ConditionTrigger uint8 = iota LogTrigger - - blockNumber = "blockNumber" expectedTypeAndVersion = "KeeperRegistry 2.1.0" - feedIdHex = "feedIdHex" - feedIDs = "feedIDs" - timestamp = "timestamp" ) var packer = encoding.NewAbiPacker() @@ -125,6 +125,8 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { var checkResult iregistry21.CheckUpkeep var blockNum uint64 var performData []byte + var workID [32]byte + var trigger ocr2keepers.Trigger upkeepNeeded := false // check upkeep if triggerType == ConditionTrigger { @@ -177,7 +179,8 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } // check that tx for this upkeep / tx was not already performed message(fmt.Sprintf("LogTrigger{blockNum: %d, blockHash: %s, txHash: %s, logIndex: %d}", blockNum, receipt.BlockHash.Hex(), txHash, logIndex)) - workID := mustUpkeepWorkID(upkeepID, blockNum, receipt.BlockHash, txHash, logIndex) + trigger = mustAutomationTrigger(txHash, logIndex, blockNum, receipt.BlockHash) + workID = mustUpkeepWorkID(upkeepID, trigger) message(fmt.Sprintf("workID computed: %s", hex.EncodeToString(workID[:]))) hasKey, err := keeperRegistry21.HasDedupKey(latestCallOpts, workID) if err != nil { @@ -229,73 +232,82 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if checkResult.UpkeepFailureReason != 0 { message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) } + if checkResult.UpkeepFailureReason == uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { - // TODO use the new streams lookup lib - //mc := &models.MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey} - //mercuryConfig := evm.NewMercuryConfig(mc, core.StreamsCompatibleABI) - //lggr, _ := logger.NewLogger() - //blockSub := &blockSubscriber{k.client} - //_ = streams.NewStreamsLookup(packer, mercuryConfig, blockSub, keeperRegistry21, k.rpcClient, lggr) + mc := &models.MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey} + mercuryConfig := evm21.NewMercuryConfig(mc, core.StreamsCompatibleABI) + lggr, _ := logger.NewLogger() + blockSub := &blockSubscriber{k.client} + streams := streams.NewStreamsLookup(packer, mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr) streamsLookupErr, err := packer.DecodeStreamsLookupRequest(checkResult.PerformData) if err == nil { message("upkeep reverted with StreamsLookup") message(fmt.Sprintf("StreamsLookup data: {FeedParamKey: %s, Feeds: %v, TimeParamKey: %s, Time: %d, ExtraData: %s}", streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time.Uint64(), hexutil.Encode(streamsLookupErr.ExtraData))) - if streamsLookupErr.FeedParamKey == feedIdHex && streamsLookupErr.TimeParamKey == blockNumber { + + streamsLookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: streamsLookupErr.FeedParamKey, + Feeds: streamsLookupErr.Feeds, + TimeParamKey: streamsLookupErr.TimeParamKey, + Time: streamsLookupErr.Time, + ExtraData: streamsLookupErr.ExtraData, + }, + UpkeepId: upkeepID, + Block: blockNum, + } + + if streamsLookup.IsMercuryV02() { message("using mercury lookup v0.2") - // handle v0.2 - cfg, err := keeperRegistry21.GetUpkeepPrivilegeConfig(triggerCallOpts, upkeepID) + // check if upkeep is allowed to use mercury v0.2 + _, _, _, allowed, err := streams.AllowedToUseMercury(latestCallOpts, upkeepID) if err != nil { - failUnknown("failed to get upkeep privilege config ", err) - } - allowed := false - if len(cfg) > 0 { - var privilegeConfig streams.UpkeepPrivilegeConfig - if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { - failUnknown("failed to unmarshal privilege config ", err) - } - allowed = privilegeConfig.MercuryEnabled + failUnknown("failed to check if upkeep is allowed to use mercury", err) } if !allowed { resolveIneligible("upkeep reverted with StreamsLookup but is not allowed to access streams") } - } else if streamsLookupErr.FeedParamKey != feedIDs || streamsLookupErr.TimeParamKey != timestamp { + } else if streamsLookup.IsMercuryV03() { // handle v0.3 - resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") - } else { message("using mercury lookup v0.3") + } else { + resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") } - streamsLookup := &StreamsLookup{streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time, streamsLookupErr.ExtraData, upkeepID, blockNum} if k.cfg.MercuryLegacyURL == "" || k.cfg.MercuryURL == "" || k.cfg.MercuryID == "" || k.cfg.MercuryKey == "" { failCheckConfig("Mercury configs not set properly, check your MERCURY_LEGACY_URL, MERCURY_URL, MERCURY_ID and MERCURY_KEY", nil) } - handler := NewMercuryLookupHandler(&MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey}, k.rpcClient) - state, failureReason, values, _, err := handler.doMercuryRequest(ctx, streamsLookup) - if failureReason == UpkeepFailureReasonInvalidRevertDataInput { + + // do mercury request + automationCheckResult := mustAutomationCheckResult(upkeepID, checkResult, trigger) + values, err := streams.DoMercuryRequest(ctx, streamsLookup, &automationCheckResult) + + if automationCheckResult.IneligibilityReason == uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) { resolveIneligible("upkeep used invalid revert data") } - if state == InvalidMercuryRequest { + if automationCheckResult.PipelineExecutionState == uint8(mercury.InvalidMercuryRequest) { resolveIneligible("the mercury request data is invalid") } if err != nil { - failCheckConfig("failed to do mercury request ", err) + resolveIneligible("failed to DoMercuryRequest") } - callbackResult, err := keeperRegistry21.CheckCallback(triggerCallOpts, upkeepID, values, streamsLookup.extraData) + + // do checkCallback + err = streams.CheckCallback(ctx, values, streamsLookup, &automationCheckResult) if err != nil { failUnknown("failed to execute mercury callback ", err) } - if callbackResult.UpkeepFailureReason != 0 { - message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) + if automationCheckResult.IneligibilityReason != 0 { + message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", automationCheckResult.IneligibilityReason)) } - upkeepNeeded, performData = callbackResult.UpkeepNeeded, callbackResult.PerformData - // do tenderly simulations - rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.extraData) + upkeepNeeded, performData = automationCheckResult.Eligible, automationCheckResult.PerformData + // do tenderly simulations for checkCallback + rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.ExtraData) if err != nil { failUnknown("failed to pack raw checkCallback call", err) } addLink("checkCallback simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) - rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.extraData) + rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.ExtraData) if err != nil { failUnknown("failed to pack raw checkCallback (direct) call", err) } @@ -317,6 +329,23 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } } +func mustAutomationCheckResult(upkeepID *big.Int, checkResult iregistry21.CheckUpkeep, trigger ocr2keepers.Trigger) ocr2keepers.CheckResult { + upkeepIdentifier := mustUpkeepIdentifier(upkeepID) + checkResult2 := ocr2keepers.CheckResult{ + Eligible: checkResult.UpkeepNeeded, + IneligibilityReason: checkResult.UpkeepFailureReason, + UpkeepID: upkeepIdentifier, + Trigger: trigger, + WorkID: core.UpkeepWorkID(upkeepIdentifier, trigger), + GasAllocated: 0, + PerformData: checkResult.PerformData, + FastGasWei: checkResult.FastGasWei, + LinkNative: checkResult.LinkNative, + } + + return checkResult2 +} + type blockSubscriber struct { ethClient *ethclient.Client } @@ -370,9 +399,27 @@ func packTriggerData(log *types.Log, blockTime uint64) ([]byte, error) { return b, nil } -func mustUpkeepWorkID(upkeepID *big.Int, blockNum uint64, blockHash [32]byte, txHash [32]byte, logIndex int64) [32]byte { - // TODO - this is a copy of the code in core.UpkeepWorkID - // We should refactor that code to be more easily exported ex not rely on Trigger structs +func mustUpkeepWorkID(upkeepID *big.Int, trigger ocr2keepers.Trigger) [32]byte { + upkeepIdentifier := mustUpkeepIdentifier(upkeepID) + + workID := core.UpkeepWorkID(upkeepIdentifier, trigger) + workIDBytes, err := hex.DecodeString(workID) + if err != nil { + failUnknown("failed to decode workID", err) + } + + var result [32]byte + copy(result[:], workIDBytes[:]) + return result +} + +func mustUpkeepIdentifier(upkeepID *big.Int) ocr2keepers.UpkeepIdentifier { + upkeepIdentifier := &ocr2keepers.UpkeepIdentifier{} + upkeepIdentifier.FromBigInt(upkeepID) + return *upkeepIdentifier +} + +func mustAutomationTrigger(txHash [32]byte, logIndex int64, blockNum uint64, blockHash [32]byte) ocr2keepers.Trigger { trigger := ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ TxHash: txHash, @@ -381,16 +428,7 @@ func mustUpkeepWorkID(upkeepID *big.Int, blockNum uint64, blockHash [32]byte, tx BlockHash: blockHash, }, } - upkeepIdentifier := &ocr2keepers.UpkeepIdentifier{} - upkeepIdentifier.FromBigInt(upkeepID) - workID := core.UpkeepWorkID(*upkeepIdentifier, trigger) - workIDBytes, err := hex.DecodeString(workID) - if err != nil { - failUnknown("failed to decode workID", err) - } - var result [32]byte - copy(result[:], workIDBytes[:]) - return result + return trigger } func message(msg string) { @@ -402,11 +440,11 @@ func warning(msg string) { } func resolveIneligible(msg string) { - exit(fmt.Sprintf("✅ %s: this upkeep is not currently elligible", msg), nil, 0) + exit(fmt.Sprintf("✅ %s: this upkeep is not currently eligible", msg), nil, 0) } func resolveEligible() { - exit("❌ this upkeep is currently elligible", nil, 0) + exit("❌ this upkeep is currently eligible", nil, 0) } func rerun(msg string, err error) { @@ -507,5 +545,3 @@ func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, inpu } return common.TenderlySimLink(responseJSON.Simulation.Id) } - -// TODO - link to performUpkeep tx if exists diff --git a/core/scripts/chaincli/handler/mercury_lookup_handler.go b/core/scripts/chaincli/handler/mercury_lookup_handler.go deleted file mode 100644 index 1bd4b2e183..0000000000 --- a/core/scripts/chaincli/handler/mercury_lookup_handler.go +++ /dev/null @@ -1,534 +0,0 @@ -package handler - -import ( - "context" - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "io" - "math/big" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/avast/retry-go" - ethabi "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" -) - -// MercuryLookupHandler is responsible for initiating the calls to the Mercury server -// to determine whether the upkeeps are eligible -type MercuryLookupHandler struct { - credentials *MercuryCredentials - httpClient HttpClient - rpcClient *rpc.Client -} - -func NewMercuryLookupHandler( - credentials *MercuryCredentials, - rpcClient *rpc.Client, -) *MercuryLookupHandler { - return &MercuryLookupHandler{ - credentials: credentials, - httpClient: http.DefaultClient, - rpcClient: rpcClient, - } -} - -type MercuryVersion string - -type StreamsLookup struct { - feedParamKey string - feeds []string - timeParamKey string - time *big.Int - extraData []byte - upkeepId *big.Int - block uint64 -} - -//go:generate mockery --quiet --name HttpClient --output ./mocks/ --case=underscore -type HttpClient interface { - Do(req *http.Request) (*http.Response, error) -} - -type MercuryCredentials struct { - LegacyURL string - URL string - ClientID string - ClientKey string -} - -func (mc *MercuryCredentials) Validate() bool { - return mc.URL != "" && mc.ClientID != "" && mc.ClientKey != "" -} - -type MercuryData struct { - Index int - Error error - Retryable bool - Bytes [][]byte - State PipelineExecutionState -} - -// MercuryV02Response represents a JSON structure used by Mercury v0.2 -type MercuryV02Response struct { - ChainlinkBlob string `json:"chainlinkBlob"` -} - -// MercuryV03Response represents a JSON structure used by Mercury v0.3 -type MercuryV03Response struct { - Reports []MercuryV03Report `json:"reports"` -} - -type MercuryV03Report struct { - FeedID string `json:"feedID"` // feed id in hex encoded - ValidFromTimestamp uint32 `json:"validFromTimestamp"` - ObservationsTimestamp uint32 `json:"observationsTimestamp"` - FullReport string `json:"fullReport"` // the actual hex encoded mercury report of this feed, can be sent to verifier -} - -const ( - // DefaultAllowListExpiration decides how long an upkeep's allow list info will be valid for. - DefaultAllowListExpiration = 20 * time.Minute - // CleanupInterval decides when the expired items in cache will be deleted. - CleanupInterval = 25 * time.Minute -) - -const ( - ApplicationJson = "application/json" - BlockNumber = "blockNumber" // valid for v0.2 - FeedIDs = "feedIDs" // valid for v0.3 - FeedIdHex = "feedIdHex" // valid for v0.2 - HeaderAuthorization = "Authorization" - HeaderContentType = "Content-Type" - HeaderTimestamp = "X-Authorization-Timestamp" - HeaderSignature = "X-Authorization-Signature-SHA256" - HeaderUpkeepId = "X-Authorization-Upkeep-Id" - MercuryPathV2 = "/client?" // only used to access mercury v0.2 server - MercuryBatchPathV3 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server - RetryDelay = 500 * time.Millisecond - Timestamp = "timestamp" // valid for v0.3 - TotalAttempt = 3 - UserId = "userId" -) - -type UpkeepFailureReason uint8 -type PipelineExecutionState uint8 - -const ( - // upkeep failure onchain reasons - UpkeepFailureReasonNone UpkeepFailureReason = 0 - UpkeepFailureReasonUpkeepCancelled UpkeepFailureReason = 1 - UpkeepFailureReasonUpkeepPaused UpkeepFailureReason = 2 - UpkeepFailureReasonTargetCheckReverted UpkeepFailureReason = 3 - UpkeepFailureReasonUpkeepNotNeeded UpkeepFailureReason = 4 - UpkeepFailureReasonPerformDataExceedsLimit UpkeepFailureReason = 5 - UpkeepFailureReasonInsufficientBalance UpkeepFailureReason = 6 - UpkeepFailureReasonMercuryCallbackReverted UpkeepFailureReason = 7 - UpkeepFailureReasonRevertDataExceedsLimit UpkeepFailureReason = 8 - UpkeepFailureReasonRegistryPaused UpkeepFailureReason = 9 - // leaving a gap here for more onchain failure reasons in the future - // upkeep failure offchain reasons - UpkeepFailureReasonMercuryAccessNotAllowed UpkeepFailureReason = 32 - UpkeepFailureReasonTxHashNoLongerExists UpkeepFailureReason = 33 - UpkeepFailureReasonInvalidRevertDataInput UpkeepFailureReason = 34 - UpkeepFailureReasonSimulationFailed UpkeepFailureReason = 35 - UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 - - // pipeline execution error - NoPipelineError PipelineExecutionState = 0 - CheckBlockTooOld PipelineExecutionState = 1 - CheckBlockInvalid PipelineExecutionState = 2 - RpcFlakyFailure PipelineExecutionState = 3 - MercuryFlakyFailure PipelineExecutionState = 4 - PackUnpackDecodeFailed PipelineExecutionState = 5 - MercuryUnmarshalError PipelineExecutionState = 6 - InvalidMercuryRequest PipelineExecutionState = 7 - InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses - UpkeepNotAuthorized PipelineExecutionState = 9 -) - -// UpkeepPrivilegeConfig represents the administrative offchain config for each upkeep. It can be set by s_upkeepPrivilegeManager -// role on the registry. Upkeeps allowed to use Mercury server will have this set to true. -type UpkeepPrivilegeConfig struct { - MercuryEnabled bool `json:"mercuryEnabled"` -} - -// generateHMAC calculates a user HMAC for Mercury server authentication. -func (mlh *MercuryLookupHandler) generateHMAC(method string, path string, body []byte, clientId string, secret string, ts int64) string { - bodyHash := sha256.New() - bodyHash.Write(body) - hashString := fmt.Sprintf("%s %s %s %s %d", - method, - path, - hex.EncodeToString(bodyHash.Sum(nil)), - clientId, - ts) - signedMessage := hmac.New(sha256.New, []byte(secret)) - signedMessage.Write([]byte(hashString)) - userHmac := hex.EncodeToString(signedMessage.Sum(nil)) - return userHmac -} - -// singleFeedRequest sends a v0.2 Mercury request for a single feed report. -func (mlh *MercuryLookupHandler) singleFeedRequest(ctx context.Context, ch chan<- MercuryData, index int, ml *StreamsLookup) { - q := url.Values{ - ml.feedParamKey: {ml.feeds[index]}, - ml.timeParamKey: {ml.time.String()}, - } - mercuryURL := mlh.credentials.LegacyURL - reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, MercuryPathV2, q.Encode()) - // mlh.logger.Debugf("request URL for upkeep %s feed %s: %s", ml.upkeepId.String(), ml.feeds[index], reqUrl) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) - if err != nil { - ch <- MercuryData{Index: index, Error: err, Retryable: false, State: InvalidMercuryRequest} - return - } - - ts := time.Now().UTC().UnixMilli() - signature := mlh.generateHMAC(http.MethodGet, MercuryPathV2+q.Encode(), []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) - req.Header.Set(HeaderContentType, ApplicationJson) - req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) - req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) - req.Header.Set(HeaderSignature, signature) - - // in the case of multiple retries here, use the last attempt's data - state := NoPipelineError - retryable := false - sent := false - retryErr := retry.Do( - func() error { - retryable = false - resp, err1 := mlh.httpClient.Do(req) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup GET request failed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) - retryable = true - state = MercuryFlakyFailure - return err1 - } - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - // mlh.logger.Errorf("Encountered error when closing the body of the response in single feed: %s", err) - } - }(resp.Body) - - body, err1 := io.ReadAll(resp.Body) - if err1 != nil { - retryable = false - state = InvalidMercuryResponse - return err1 - } - - if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { - // mlh.logger.Errorw("StreamsLookup received retryable status code", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "statusCode", resp.StatusCode, "feed", ml.feeds[index]) - retryable = true - state = MercuryFlakyFailure - return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) - } else if resp.StatusCode != http.StatusOK { - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("StreamsLookup upkeep %s block %s received status code %d for feed %s", ml.upkeepId.String(), ml.time.String(), resp.StatusCode, ml.feeds[index]) - } - - // mlh.logger.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", ml.time.String(), ml.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) - - var m MercuryV02Response - err1 = json.Unmarshal(body, &m) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) - retryable = false - state = MercuryUnmarshalError - return err1 - } - blobBytes, err1 := hexutil.Decode(m.ChainlinkBlob) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup failed to decode chainlinkBlob for feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "blob", m.ChainlinkBlob, "feed", ml.feeds[index], "error", err1) - retryable = false - state = InvalidMercuryResponse - return err1 - } - ch <- MercuryData{ - Index: index, - Bytes: [][]byte{blobBytes}, - Retryable: false, - State: NoPipelineError, - } - sent = true - return nil - }, - // only retry when the error is 404 Not Found or 500 Internal Server Error - retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) - }), - retry.Context(ctx), - retry.Delay(RetryDelay), - retry.Attempts(TotalAttempt)) - - if !sent { - md := MercuryData{ - Index: index, - Bytes: [][]byte{}, - Retryable: retryable, - Error: fmt.Errorf("failed to request feed for %s: %w", ml.feeds[index], retryErr), - State: state, - } - ch <- md - } -} - -// multiFeedsRequest sends a Mercury v0.3 request for a multi-feed report -func (mlh *MercuryLookupHandler) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, ml *StreamsLookup) { - params := fmt.Sprintf("%s=%s&%s=%s", FeedIDs, strings.Join(ml.feeds, ","), Timestamp, ml.time.String()) - reqUrl := fmt.Sprintf("%s%s%s", mlh.credentials.URL, MercuryBatchPathV3, params) - // mlh.logger.Debugf("request URL for upkeep %s userId %s: %s", ml.upkeepId.String(), mlh.credentials.ClientID, reqUrl) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) - if err != nil { - ch <- MercuryData{Index: 0, Error: err, Retryable: false, State: InvalidMercuryRequest} - return - } - - ts := time.Now().UTC().UnixMilli() - signature := mlh.generateHMAC(http.MethodGet, MercuryBatchPathV3+params, []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) - req.Header.Set(HeaderContentType, ApplicationJson) - // username here is often referred to as user id - req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) - req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) - req.Header.Set(HeaderSignature, signature) - // mercury will inspect authorization headers above to make sure this user (in automation's context, this node) is eligible to access mercury - // and if it has an automation role. it will then look at this upkeep id to check if it has access to all the requested feeds. - req.Header.Set(HeaderUpkeepId, ml.upkeepId.String()) - - // in the case of multiple retries here, use the last attempt's data - state := NoPipelineError - retryable := false - sent := false - retryErr := retry.Do( - func() error { - retryable = false - resp, err1 := mlh.httpClient.Do(req) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup GET request fails for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) - retryable = true - state = MercuryFlakyFailure - return err1 - } - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - // mlh.logger.Errorf("Encountered error when closing the body of the response in the multi feed: %s", err) - } - }(resp.Body) - body, err1 := io.ReadAll(resp.Body) - if err1 != nil { - retryable = false - state = InvalidMercuryResponse - return err1 - } - - // mlh.logger.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - if resp.StatusCode == http.StatusUnauthorized { - retryable = false - state = UpkeepNotAuthorized - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } else if resp.StatusCode == http.StatusBadRequest { - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } else if resp.StatusCode == http.StatusInternalServerError { - retryable = true - state = MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusInternalServerError) - } else if resp.StatusCode == 420 { - // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } else if resp.StatusCode != http.StatusOK { - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } - - var response MercuryV03Response - err1 = json.Unmarshal(body, &response) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) - retryable = false - state = MercuryUnmarshalError - return err1 - } - // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract - // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated - if len(response.Reports) != len(ml.feeds) { - // TODO: AUTO-5044: calculate what reports are missing and log a warning - retryable = true - state = MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusNotFound) - } - var reportBytes [][]byte - for _, rsp := range response.Reports { - b, err := hexutil.Decode(rsp.FullReport) - if err != nil { - retryable = false - state = InvalidMercuryResponse - return err - } - reportBytes = append(reportBytes, b) - } - ch <- MercuryData{ - Index: 0, - Bytes: reportBytes, - Retryable: false, - State: NoPipelineError, - } - sent = true - return nil - }, - // only retry when the error is 404 Not Found or 500 Internal Server Error - retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) - }), - retry.Context(ctx), - retry.Delay(RetryDelay), - retry.Attempts(TotalAttempt)) - - if !sent { - md := MercuryData{ - Index: 0, - Bytes: [][]byte{}, - Retryable: retryable, - Error: retryErr, - State: state, - } - ch <- md - } -} - -// doMercuryRequest sends requests to Mercury API to retrieve ChainlinkBlob. -func (mlh *MercuryLookupHandler) doMercuryRequest(ctx context.Context, ml *StreamsLookup) (PipelineExecutionState, UpkeepFailureReason, [][]byte, bool, error) { - var isMercuryV03 bool - resultLen := len(ml.feeds) - ch := make(chan MercuryData, resultLen) - if len(ml.feeds) == 0 { - return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) - } - if ml.feedParamKey == FeedIdHex && ml.timeParamKey == BlockNumber { - // only v0.2 - for i := range ml.feeds { - go mlh.singleFeedRequest(ctx, ch, i, ml) - } - } else if ml.feedParamKey == FeedIDs && ml.timeParamKey == Timestamp { - // only v0.3 - resultLen = 1 - isMercuryV03 = true - ch = make(chan MercuryData, resultLen) - go mlh.multiFeedsRequest(ctx, ch, ml) - } else { - return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) - } - - var reqErr error - results := make([][]byte, len(ml.feeds)) - retryable := true - allSuccess := true - // in v0.2, use the last execution error as the state, if no execution errors, state will be no error - state := NoPipelineError - for i := 0; i < resultLen; i++ { - m := <-ch - if m.Error != nil { - if reqErr == nil { - reqErr = errors.New(m.Error.Error()) - } else { - reqErr = errors.New(reqErr.Error() + m.Error.Error()) - } - retryable = retryable && m.Retryable - allSuccess = false - if m.State != NoPipelineError { - state = m.State - } - continue - } - if isMercuryV03 { - results = m.Bytes - } else { - results[m.Index] = m.Bytes[0] - } - } - // only retry when not all successful AND none are not retryable - return state, UpkeepFailureReasonNone, results, retryable && !allSuccess, reqErr -} - -// decodeStreamsLookup decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string timeParamKey, uint256 time, byte[] extraData) -// func (mlh *MercuryLookupHandler) decodeStreamsLookup(data []byte) (*StreamsLookup, error) { -// e := mlh.mercuryConfig.Abi.Errors["StreamsLookup"] -// unpack, err := e.Unpack(data) -// if err != nil { -// return nil, fmt.Errorf("unpack error: %w", err) -// } -// errorParameters := unpack.([]interface{}) - -// return &StreamsLookup{ -// feedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), -// feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), -// timeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), -// time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), -// extraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), -// }, nil -// } - -// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if -// this upkeep is allowed to use Mercury service. -// func (mlh *MercuryLookupHandler) allowedToUseMercury(upkeep models.Upkeep) (bool, error) { -// allowed, ok := mlh.mercuryConfig.AllowListCache.Get(upkeep.Admin.Hex()) -// if ok { -// return allowed.(bool), nil -// } - -// if upkeep.UpkeepPrivilegeConfig == nil { -// return false, fmt.Errorf("the upkeep privilege config was not retrieved for upkeep with ID %s", upkeep.UpkeepID) -// } - -// if len(upkeep.UpkeepPrivilegeConfig) == 0 { -// return false, fmt.Errorf("the upkeep privilege config is empty") -// } - -// var a UpkeepPrivilegeConfig -// err := json.Unmarshal(upkeep.UpkeepPrivilegeConfig, &a) -// if err != nil { -// return false, fmt.Errorf("failed to unmarshal privilege config for upkeep ID %s: %v", upkeep.UpkeepID, err) -// } - -// mlh.mercuryConfig.AllowListCache.Set(upkeep.Admin.Hex(), a.MercuryEnabled, cache.DefaultExpiration) -// return a.MercuryEnabled, nil -// } - -func (mlh *MercuryLookupHandler) CheckCallback(ctx context.Context, values [][]byte, lookup *StreamsLookup, registryABI ethabi.ABI, registryAddress common.Address) (hexutil.Bytes, error) { - payload, err := registryABI.Pack("checkCallback", lookup.upkeepId, values, lookup.extraData) - if err != nil { - return nil, err - } - - var theBytes hexutil.Bytes - args := map[string]interface{}{ - "to": registryAddress.Hex(), - "data": hexutil.Bytes(payload), - } - - // call checkCallback function at the block which OCR3 has agreed upon - err = mlh.rpcClient.CallContext(ctx, &theBytes, "eth_call", args, hexutil.EncodeUint64(lookup.block)) - if err != nil { - return nil, err - } - return theBytes, nil -} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c7af0541c1..21f00df02d 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -7,7 +7,6 @@ replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( github.com/ava-labs/coreth v0.12.1 - github.com/avast/retry-go v3.0.0+incompatible github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/ethereum/go-ethereum v1.12.0 @@ -19,7 +18,6 @@ require ( github.com/montanaflynn/stats v0.7.1 github.com/olekukonko/tablewriter v0.0.5 github.com/pelletier/go-toml/v2 v2.1.0 - github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 @@ -283,6 +281,7 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/pressly/goose/v3 v3.16.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7cea79eb76..36504924e1 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -152,8 +152,6 @@ github.com/ava-labs/avalanchego v1.10.1 h1:lBeamJ1iNq+p2oKg2nAs+A65m8vhSDjkiTDbw github.com/ava-labs/avalanchego v1.10.1/go.mod h1:ZvSXWlbkUKlbk3BsWx29a+8eVHe/WBsOxh55BSGoeRk= github.com/ava-labs/coreth v0.12.1 h1:EWSkFGHGVUxmu1pnSK/2pdcxaAVHbGspHqO3Ag+i7sA= github.com/ava-labs/coreth v0.12.1/go.mod h1:/5x54QlIKjlPebkdzTA5ic9wXdejbWOnQosztkv9jxo= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index aec2343192..cb9e2dd675 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -16,7 +16,6 @@ import ( "github.com/patrickmn/go-cache" ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink-common/pkg/services" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" @@ -92,8 +91,9 @@ func NewStreamsLookup( // Lookup looks through check upkeep results looking for any that need off chain lookup func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckResult) []ocr2keepers.CheckResult { lookups := map[int]*mercury.StreamsLookup{} - for i, checkResult := range checkResults { - s.buildResult(ctx, i, checkResult, checkResults, lookups) + for _, checkResult := range checkResults { + copyCheckResult := checkResult + s.buildResult(ctx, ©CheckResult, lookups) } var wg sync.WaitGroup @@ -101,7 +101,7 @@ func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckRe wg.Add(1) func(i int, lookup *mercury.StreamsLookup) { s.threadCtrl.Go(func(ctx context.Context) { - s.doLookup(ctx, &wg, lookup, i, checkResults) + s.doLookup(ctx, &wg, lookup, &checkResults[i]) }) }(i, lookup) } @@ -112,7 +112,7 @@ func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckRe } // buildResult checks if the upkeep is allowed by Mercury and builds a streams lookup request from the check result -func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keepers.CheckResult, checkResults []ocr2keepers.CheckResult, lookups map[int]*mercury.StreamsLookup) { +func (s *streams) buildResult(ctx context.Context, checkResult *ocr2keepers.CheckResult, lookups map[int]*mercury.StreamsLookup) { lookupLggr := s.lggr.With("where", "StreamsLookup") if checkResult.IneligibilityReason != uint8(mercury.MercuryUpkeepFailureReasonTargetCheckReverted) { // Streams Lookup only works when upkeep target check reverts @@ -129,7 +129,7 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper // Try to decode the revert error into streams lookup format. User upkeeps can revert with any reason, see if they // tried to call mercury - lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) + lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResult.PerformData)) streamsLookupErr, err := s.packer.DecodeStreamsLookupRequest(checkResult.PerformData) if err != nil { lookupLggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) @@ -139,7 +139,7 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper streamsLookupResponse := &mercury.StreamsLookup{StreamsLookupError: streamsLookupErr} if len(streamsLookupResponse.Feeds) == 0 { - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) lookupLggr.Debugf("at block %s upkeep %s has empty feeds array", block, upkeepId) return } @@ -148,21 +148,21 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper if streamsLookupResponse.IsMercuryV02() { // check permission on the registry for mercury v0.2 opts := s.buildCallOpts(ctx, block) - if state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId.BigInt()); err != nil { + if state, reason, retryable, allowed, err := s.AllowedToUseMercury(opts, upkeepId.BigInt()); err != nil { lookupLggr.Warnf("at block %s upkeep %s failed to query mercury allow list: %s", block, upkeepId, err) - checkResults[i].PipelineExecutionState = uint8(state) - checkResults[i].IneligibilityReason = uint8(reason) - checkResults[i].Retryable = retryable + checkResult.PipelineExecutionState = uint8(state) + checkResult.IneligibilityReason = uint8(reason) + checkResult.Retryable = retryable return } else if !allowed { lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed) + checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed) return } } else if streamsLookupResponse.IsMercuryVersionUnkown() { // if mercury version cannot be determined, set failure reason lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) return } @@ -171,71 +171,103 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper // in the revert for mercury v0.2, which is denoted by time in the struct bc starting from v0.3, only timestamp will be supported streamsLookupResponse.Block = uint64(block.Int64()) lookupLggr.Infof("at block %d upkeep %s DecodeStreamsLookupRequest feedKey=%s timeKey=%s feeds=%v time=%s extraData=%s", block, upkeepId, streamsLookupResponse.FeedParamKey, streamsLookupResponse.TimeParamKey, streamsLookupResponse.Feeds, streamsLookupResponse.Time, hexutil.Encode(streamsLookupResponse.ExtraData)) - lookups[i] = streamsLookupResponse + lookups[len(lookups)] = streamsLookupResponse } -func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, i int, checkResults []ocr2keepers.CheckResult) { +func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, checkResult *ocr2keepers.CheckResult) { defer wg.Done() - state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) - pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) + values, err := s.DoMercuryRequest(ctx, lookup, checkResult) + if err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s DoMercuryRequest err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + } - if lookup.IsMercuryV02() { - state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) - } else if lookup.IsMercuryV03() { - state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) + if err := s.CheckCallback(ctx, values, lookup, checkResult); err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s CheckCallback err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) } +} +func (s *streams) CheckCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup, checkResult *ocr2keepers.CheckResult) error { + payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) if err != nil { - s.lggr.Errorf("at block %d upkeep %s requested time %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.Block, lookup.UpkeepId, lookup.Time, retryable, retryInterval, err.Error()) - checkResults[i].Retryable = retryable - checkResults[i].RetryInterval = retryInterval - checkResults[i].PipelineExecutionState = uint8(state) - checkResults[i].IneligibilityReason = uint8(reason) - return + s.lggr.Errorf("at block %d upkeep %s checkCallback packing err: %s", lookup.Block, lookup.UpkeepId, err.Error()) + checkResult.Retryable = false + checkResult.PipelineExecutionState = uint8(mercury.PackUnpackDecodeFailed) + return err } - for j, v := range values { - s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) + var mercuryBytes hexutil.Bytes + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), } - state, retryable, mercuryBytes, err := s.checkCallback(ctx, values, lookup) - if err != nil { + // call checkCallback function at the block which OCR3 has agreed upon + if err = s.client.CallContext(ctx, &mercuryBytes, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { s.lggr.Errorf("at block %d upkeep %s checkCallback err: %s", lookup.Block, lookup.UpkeepId, err.Error()) - checkResults[i].Retryable = retryable - checkResults[i].PipelineExecutionState = uint8(state) - return + checkResult.Retryable = true + checkResult.PipelineExecutionState = uint8(mercury.RpcFlakyFailure) + return err } + s.lggr.Infof("at block %d upkeep %s requested time %s checkCallback mercuryBytes: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(mercuryBytes)) unpackCallBackState, needed, performData, failureReason, _, err := s.packer.UnpackCheckCallbackResult(mercuryBytes) if err != nil { s.lggr.Errorf("at block %d upkeep %s requested time %s UnpackCheckCallbackResult err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) - checkResults[i].PipelineExecutionState = unpackCallBackState - return + checkResult.PipelineExecutionState = unpackCallBackState + return err } if failureReason == uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) { - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) + checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) s.lggr.Debugf("at block %d upkeep %s requested time %s mercury callback reverts", lookup.Block, lookup.UpkeepId, lookup.Time) - return + return fmt.Errorf("at block %d upkeep %s requested time %s mercury callback reverts", lookup.Block, lookup.UpkeepId, lookup.Time) + } if !needed { - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonUpkeepNotNeeded) + checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonUpkeepNotNeeded) s.lggr.Debugf("at block %d upkeep %s requested time %s callback reports upkeep not needed", lookup.Block, lookup.UpkeepId, lookup.Time) - return + return fmt.Errorf("at block %d upkeep %s requested time %s callback reports upkeep not needed", lookup.Block, lookup.UpkeepId, lookup.Time) } - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonNone) - checkResults[i].Eligible = true - checkResults[i].PerformData = performData + checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonNone) + checkResult.Eligible = true + checkResult.PerformData = performData s.lggr.Infof("at block %d upkeep %s requested time %s successful with perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(performData)) + + return nil +} + +func (s *streams) DoMercuryRequest(ctx context.Context, lookup *mercury.StreamsLookup, checkResult *ocr2keepers.CheckResult) ([][]byte, error) { + state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) + pluginRetryKey := generatePluginRetryKey(checkResult.WorkID, lookup.Block) + + if lookup.IsMercuryV02() { + state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) + } else if lookup.IsMercuryV03() { + state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) + } + + if err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.Block, lookup.UpkeepId, lookup.Time, retryable, retryInterval, err.Error()) + checkResult.Retryable = retryable + checkResult.RetryInterval = retryInterval + checkResult.PipelineExecutionState = uint8(state) + checkResult.IneligibilityReason = uint8(reason) + return nil, err + } + + for j, v := range values { + s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) + } + return values, nil } -// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if +// AllowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if // this upkeep is allowed to use Mercury service. -func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { +func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { allowed, ok := s.mercuryConfig.IsUpkeepAllowed(upkeepId.String()) if ok { return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, allowed.(bool), nil @@ -255,7 +287,6 @@ func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s "data": hexutil.Bytes(payload), } - // call checkCallback function at the block which OCR3 has agreed upon if err = s.client.CallContext(opts.Context, &resultBytes, "eth_call", args, hexutil.EncodeBig(opts.BlockNumber)); err != nil { return mercury.RpcFlakyFailure, mercury.MercuryUpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) } @@ -281,26 +312,6 @@ func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil } -func (s *streams) checkCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup) (mercury.MercuryUpkeepState, bool, hexutil.Bytes, error) { - payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) - if err != nil { - return mercury.PackUnpackDecodeFailed, false, nil, err - } - - var b hexutil.Bytes - args := map[string]interface{}{ - "to": s.registry.Address().Hex(), - "data": hexutil.Bytes(payload), - } - - // call checkCallback function at the block which OCR3 has agreed upon - if err := s.client.CallContext(ctx, &b, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { - return mercury.RpcFlakyFailure, true, nil, err - } - - return mercury.NoPipelineError, false, b, nil -} - func (s *streams) buildCallOpts(ctx context.Context, block *big.Int) *bind.CallOpts { opts := bind.CallOpts{ Context: ctx, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index abcc37dca1..2475244b4d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -126,6 +126,7 @@ func TestStreams_CheckCallback(t *testing.T) { tests := []struct { name string lookup *mercury.StreamsLookup + input []ocr2keepers.CheckResult values [][]byte statusCode int @@ -153,6 +154,9 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, + input: []ocr2keepers.CheckResult{ + {}, + }, values: values, statusCode: http.StatusOK, callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -185,6 +189,9 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, + input: []ocr2keepers.CheckResult{ + {}, + }, values: values, statusCode: http.StatusOK, callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -216,6 +223,9 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, + input: []ocr2keepers.CheckResult{ + {}, + }, values: values, statusCode: http.StatusOK, callbackResp: []byte{}, @@ -255,10 +265,10 @@ func TestStreams_CheckCallback(t *testing.T) { }).Once() s.client = client - state, retryable, _, err := s.checkCallback(testutils.Context(t), tt.values, tt.lookup) - tt.wantErr(t, err, fmt.Sprintf("Error asserion failed: %v", tt.name)) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.retryable, retryable) + err = s.CheckCallback(testutils.Context(t), tt.values, tt.lookup, &tt.input[0]) + tt.wantErr(t, err, fmt.Sprintf("Error assertion failed: %v", tt.name)) + assert.Equal(t, uint8(tt.state), tt.input[0].PipelineExecutionState) + assert.Equal(t, tt.retryable, tt.input[0].Retryable) }) } } @@ -434,7 +444,7 @@ func TestStreams_AllowedToUseMercury(t *testing.T) { BlockNumber: big.NewInt(10), } - state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId) + state, reason, retryable, allowed, err := s.AllowedToUseMercury(opts, upkeepId) assert.Equal(t, tt.err, err) assert.Equal(t, tt.allowed, allowed) assert.Equal(t, tt.state, state) From 5e018cc58bcc4f773f40c9cabe4ec66d5f2ebf95 Mon Sep 17 00:00:00 2001 From: Ryan Hall Date: Fri, 1 Dec 2023 14:06:55 -0500 Subject: [PATCH 258/327] write test for backwards compatibility in automation report encoding function (#11430) --- .../evmregistry/v21/encoding/encoder_test.go | 35 +++++++++++++++++++ .../v21/fixtures/expected_encoded_report.txt | 1 + 2 files changed, 36 insertions(+) create mode 100644 core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/fixtures/expected_encoded_report.txt diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go index 1376e2a9bb..aa549ab3ec 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go @@ -1,7 +1,10 @@ package encoding import ( + "bytes" + "encoding/hex" "math/big" + "os" "testing" "github.com/ethereum/go-ethereum/common" @@ -12,6 +15,19 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) +var expectedEncodedReport []byte + +func init() { + b, err := os.ReadFile("../fixtures/expected_encoded_report.txt") + if err != nil { + panic(err) + } + expectedEncodedReport, err = hex.DecodeString(string(b)) + if err != nil { + panic(err) + } +} + func TestReportEncoder_EncodeExtract(t *testing.T) { encoder := reportEncoder{ packer: NewAbiPacker(), @@ -93,6 +109,25 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { } } +func TestReportEncoder_BackwardsCompatibility(t *testing.T) { + encoder := reportEncoder{ + packer: NewAbiPacker(), + } + results := []ocr2keepers.CheckResult{ + newResult(1, 2, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 5, 6), + newResult(3, 4, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 7, 8), + } + encoded, err := encoder.Encode(results...) + assert.NoError(t, err) + if !bytes.Equal(encoded, expectedEncodedReport) { + assert.Fail(t, + "encoded report does not match expected encoded report; "+ + "this means a breaking change has been made to the report encoding function; "+ + "only update this test if non-backwards-compatible changes are necessary", + ) + } +} + func newResult(block int64, checkBlock ocr2keepers.BlockNumber, id ocr2keepers.UpkeepIdentifier, fastGasWei, linkNative int64) ocr2keepers.CheckResult { tp := core.GetUpkeepType(id) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/fixtures/expected_encoded_report.txt b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/fixtures/expected_encoded_report.txt new file mode 100644 index 0000000000..3fb42146c8 --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/fixtures/expected_encoded_report.txt @@ -0,0 +1 @@ +00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000131300000000000000000000000000000010000000000000000000000000000003230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a0aaaaaaaa9012345678901234567890123456789012345678901234567890123412345678901234567890123456789012345678901234567890123456789012340000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000101020304050607080102030405060708010203040506070801020304050607080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000301020304050607080102030405060708010203040506070801020304050607080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005646174613000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056461746130000000000000000000000000000000000000000000000000000000 \ No newline at end of file From 8ffd084314876a8ae27827b661179afde9db480c Mon Sep 17 00:00:00 2001 From: Steve Ellis Date: Fri, 1 Dec 2023 20:34:11 +0100 Subject: [PATCH 259/327] remove previous Solidity code owners (#11454) --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index bd2d0419cf..e34d3ea1be 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -71,7 +71,7 @@ core/scripts/gateway @bolekk @pinebit /operator-ui/ @DeividasK @jkongie # Contracts -/contracts/ @se3000 @connorwstein @RensR +/contracts/ @RensR # First we match on project names to catch files like the compilation scripts, # gas snapshots and other files not places in the project directories. From b8084cb357582fdf43f64b1e08c38e1b457ba4ad Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 1 Dec 2023 14:27:44 -0600 Subject: [PATCH 260/327] common/txmgr: initialize map before goroutines race ahead (#11452) * common/txmgr: initiliaze map before goroutines race ahead * pass ctx from Start() --- common/txmgr/broadcaster.go | 18 +++++++----------- common/txmgr/test_helpers.go | 4 ++-- common/txmgr/txmgr.go | 6 ++++-- core/chains/evm/txmgr/broadcaster_test.go | 4 ++-- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index ab620c51be..54ae653f66 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -194,14 +194,14 @@ func NewBroadcaster[ // Start starts Broadcaster service. // The provided context can be used to terminate Start sequence. -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Start(_ context.Context) error { +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Start(ctx context.Context) error { return eb.StartOnce("Broadcaster", func() (err error) { - return eb.startInternal() + return eb.startInternal(ctx) }) } // startInternal can be called multiple times, in conjunction with closeInternal. The TxMgr uses this functionality to reset broadcaster multiple times in its own lifetime. -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) startInternal() error { +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) startInternal(ctx context.Context) error { eb.initSync.Lock() defer eb.initSync.Unlock() if eb.isStarted { @@ -222,16 +222,15 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star eb.wg = sync.WaitGroup{} eb.wg.Add(len(eb.enabledAddresses)) eb.triggers = make(map[ADDR]chan struct{}) + eb.sequenceLock.Lock() + eb.nextSequenceMap = eb.loadNextSequenceMap(ctx, eb.enabledAddresses) + eb.sequenceLock.Unlock() for _, addr := range eb.enabledAddresses { triggerCh := make(chan struct{}, 1) eb.triggers[addr] = triggerCh go eb.monitorTxs(addr, triggerCh) } - eb.sequenceLock.Lock() - defer eb.sequenceLock.Unlock() - eb.nextSequenceMap = eb.loadNextSequenceMap(eb.enabledAddresses) - eb.isStarted = true return nil } @@ -286,10 +285,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trig } // Load the next sequence map using the tx table or on-chain (if not found in tx table) -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(addresses []ADDR) map[ADDR]SEQ { - ctx, cancel := eb.chStop.NewCtx() - defer cancel() - +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(ctx context.Context, addresses []ADDR) map[ADDR]SEQ { nextSequenceMap := make(map[ADDR]SEQ) for _, address := range addresses { seq, err := eb.getSequenceForAddr(ctx, address) diff --git a/common/txmgr/test_helpers.go b/common/txmgr/test_helpers.go index 0f128a23af..6c0c5680ea 100644 --- a/common/txmgr/test_helpers.go +++ b/common/txmgr/test_helpers.go @@ -22,8 +22,8 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXDeliverB tr.mb.Deliver(blockHeight) } -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) XXXTestStartInternal() error { - return eb.startInternal() +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) XXXTestStartInternal(ctx context.Context) error { + return eb.startInternal(ctx) } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) XXXTestCloseInternal() error { diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 3fbdb852f8..228ab4ec8b 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -339,18 +339,20 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() wg.Add(2) go func() { defer wg.Done() + ctx, cancel := b.chStop.NewCtx() + defer cancel() // Retry indefinitely on failure backoff := utils.NewRedialBackoff() for { select { case <-time.After(backoff.Duration()): - if err := b.broadcaster.startInternal(); err != nil { + if err := b.broadcaster.startInternal(ctx); err != nil { logger.Criticalw(b.logger, "Failed to start Broadcaster", "err", err) b.SvcErrBuffer.Append(err) continue } return - case <-b.chStop: + case <-ctx.Done(): stopOnce.Do(func() { stopped = true }) return } diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 26e78344b9..c6e05b0954 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -124,9 +124,9 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { require.Error(t, eb.XXXTestCloseInternal()) // Can successfully startInternal a previously closed instance - require.NoError(t, eb.XXXTestStartInternal()) + require.NoError(t, eb.XXXTestStartInternal(ctx)) // Can't startInternal already started instance - require.Error(t, eb.XXXTestStartInternal()) + require.Error(t, eb.XXXTestStartInternal(ctx)) // Can successfully closeInternal again require.NoError(t, eb.XXXTestCloseInternal()) } From a2a97cc6a8051441a4f48658fefdf160a4a6f062 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Fri, 1 Dec 2023 16:17:57 -0500 Subject: [PATCH 261/327] Use correct image name prefix for repo (#11465) --- .github/workflows/build-publish-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml index b958295cf2..a7186ee5a1 100644 --- a/.github/workflows/build-publish-pr.yml +++ b/.github/workflows/build-publish-pr.yml @@ -29,7 +29,7 @@ jobs: aws-region: ${{ secrets.AWS_REGION }} sign-images: false ecr-hostname: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }} - ecr-image-name: chainlink-untrusted + ecr-image-name: crib-chainlink-untrusted dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} From 0e301e8a371bbb7cf44cd876775cdf509160cea6 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Fri, 1 Dec 2023 17:54:33 -0500 Subject: [PATCH 262/327] Rename Functions Client i_router to i_functionsRouter (#11450) --- .../src/v0.8/functions/dev/v1_X/FunctionsClient.sol | 8 ++++---- contracts/src/v0.8/functions/dev/v1_X/Routable.sol | 10 +++++----- .../tests/v1_X/testhelpers/FunctionsClientHarness.sol | 2 +- .../v1_X/testhelpers/FunctionsClientTestHelper.sol | 10 +++++----- .../v1_X/testhelpers/FunctionsClientUpgradeHelper.sol | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol index 6d033d4b23..4aabef01f2 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol @@ -11,7 +11,7 @@ import {FunctionsRequest} from "./libraries/FunctionsRequest.sol"; abstract contract FunctionsClient is IFunctionsClient { using FunctionsRequest for FunctionsRequest.Request; - IFunctionsRouter internal immutable i_router; + IFunctionsRouter internal immutable i_functionsRouter; event RequestSent(bytes32 indexed id); event RequestFulfilled(bytes32 indexed id); @@ -19,7 +19,7 @@ abstract contract FunctionsClient is IFunctionsClient { error OnlyRouterCanFulfill(); constructor(address router) { - i_router = IFunctionsRouter(router); + i_functionsRouter = IFunctionsRouter(router); } /// @notice Sends a Chainlink Functions request @@ -33,7 +33,7 @@ abstract contract FunctionsClient is IFunctionsClient { uint32 callbackGasLimit, bytes32 donId ) internal returns (bytes32) { - bytes32 requestId = i_router.sendRequest( + bytes32 requestId = i_functionsRouter.sendRequest( subscriptionId, data, FunctionsRequest.REQUEST_DATA_VERSION, @@ -53,7 +53,7 @@ abstract contract FunctionsClient is IFunctionsClient { /// @inheritdoc IFunctionsClient function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override { - if (msg.sender != address(i_router)) { + if (msg.sender != address(i_functionsRouter)) { revert OnlyRouterCanFulfill(); } _fulfillRequest(requestId, response, err); diff --git a/contracts/src/v0.8/functions/dev/v1_X/Routable.sol b/contracts/src/v0.8/functions/dev/v1_X/Routable.sol index b50b1e603f..92e23362f9 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/Routable.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/Routable.sol @@ -8,7 +8,7 @@ import {IOwnableFunctionsRouter} from "./interfaces/IOwnableFunctionsRouter.sol" /// as the destinations to a route (id=>contract) on the Router. /// It provides a Router getter and modifiers. abstract contract Routable is ITypeAndVersion { - IOwnableFunctionsRouter private immutable i_router; + IOwnableFunctionsRouter private immutable i_functionsRouter; error RouterMustBeSet(); error OnlyCallableByRouter(); @@ -19,17 +19,17 @@ abstract contract Routable is ITypeAndVersion { if (router == address(0)) { revert RouterMustBeSet(); } - i_router = IOwnableFunctionsRouter(router); + i_functionsRouter = IOwnableFunctionsRouter(router); } /// @notice Return the Router function _getRouter() internal view returns (IOwnableFunctionsRouter router) { - return i_router; + return i_functionsRouter; } /// @notice Reverts if called by anyone other than the router. modifier onlyRouter() { - if (msg.sender != address(i_router)) { + if (msg.sender != address(i_functionsRouter)) { revert OnlyCallableByRouter(); } _; @@ -37,7 +37,7 @@ abstract contract Routable is ITypeAndVersion { /// @notice Reverts if called by anyone other than the router owner. modifier onlyRouterOwner() { - if (msg.sender != i_router.owner()) { + if (msg.sender != i_functionsRouter.owner()) { revert OnlyCallableByRouterOwner(); } _; diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol index ec3b5a65fe..f0cb3965b5 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientHarness.sol @@ -10,7 +10,7 @@ contract FunctionsClientHarness is FunctionsClientUpgradeHelper { constructor(address router) FunctionsClientUpgradeHelper(router) {} function getRouter_HARNESS() external view returns (address) { - return address(i_router); + return address(i_functionsRouter); } function sendRequest_HARNESS( diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol index bc73544205..c300f4d2b8 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol @@ -64,7 +64,7 @@ contract FunctionsClientTestHelper is FunctionsClient { uint32 callbackGasLimit = 20_000; request._initializeRequestForInlineJavaScript(sourceCode); bytes memory requestData = FunctionsRequest._encodeCBOR(request); - requestId = i_router.sendRequestToProposed( + requestId = i_functionsRouter.sendRequestToProposed( subscriptionId, requestData, FunctionsRequest.REQUEST_DATA_VERSION, @@ -76,13 +76,13 @@ contract FunctionsClientTestHelper is FunctionsClient { } function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external { - bytes32 allowListId = i_router.getAllowListId(); - ITermsOfServiceAllowList allowList = ITermsOfServiceAllowList(i_router.getContractById(allowListId)); + bytes32 allowListId = i_functionsRouter.getAllowListId(); + ITermsOfServiceAllowList allowList = ITermsOfServiceAllowList(i_functionsRouter.getContractById(allowListId)); allowList.acceptTermsOfService(acceptor, recipient, r, s, v); } function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external { - IFunctionsSubscriptions(address(i_router)).acceptSubscriptionOwnerTransfer(subscriptionId); + IFunctionsSubscriptions(address(i_functionsRouter)).acceptSubscriptionOwnerTransfer(subscriptionId); } function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { @@ -98,7 +98,7 @@ contract FunctionsClientTestHelper is FunctionsClient { sendSimpleRequestWithJavaScript("somedata", s_subscriptionId, s_donId, 20_000); } if (s_doInvalidReentrantOperation) { - IFunctionsSubscriptions(address(i_router)).cancelSubscription(s_subscriptionId, msg.sender); + IFunctionsSubscriptions(address(i_functionsRouter)).cancelSubscription(s_subscriptionId, msg.sender); } emit FulfillRequestInvoked(requestId, response, err); } diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientUpgradeHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientUpgradeHelper.sol index a52c300992..e0f636ee89 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientUpgradeHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientUpgradeHelper.sol @@ -82,7 +82,7 @@ contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { uint32 callbackGasLimit, bytes32 donId ) internal returns (bytes32) { - bytes32 requestId = i_router.sendRequestToProposed( + bytes32 requestId = i_functionsRouter.sendRequestToProposed( subscriptionId, data, FunctionsRequest.REQUEST_DATA_VERSION, From 7f5c4325bbf2ea510485f27e07ffb1725d71220f Mon Sep 17 00:00:00 2001 From: Sneha Agnihotri <180277+snehaagni@users.noreply.github.com> Date: Fri, 1 Dec 2023 15:51:44 -0800 Subject: [PATCH 263/327] Bump version and update CHANGELOG for core v2.8.0 (#11419) * Bump version and update CHANGELOG for core v2.8.0 * Add section for Upcoming changes * Combine Add sections * Consolidating Added section * Remove duplicate text --- VERSION | 2 +- docs/CHANGELOG.md | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/VERSION b/VERSION index 860487ca19..834f262953 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.7.1 +2.8.0 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 6af224157a..62236558c4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,8 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] -### Fixed -- Fixed a bug that caused the Telemetry Manager to report incorrect health +... + +## 2.8.0 - UNRELEASED ### Added @@ -53,7 +54,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `mercury_cache_wait_count` `mercury_cache_miss_count` - Added new `EVM.OCR` TOML config fields `DeltaCOverride` and `DeltaCJitterOverride` for overriding the config DeltaC. - +- Mercury v0.2 has improved consensus around current block that uses the most recent 5 blocks instead of only the latest one +- Two new prom metrics for mercury, nops should consider adding alerting on these: + - `mercury_insufficient_blocks_count` + - `mercury_zero_blocks_count` + ### Changed - `PromReporter` no longer directly reads txm related status from the db, and instead uses the txStore API. @@ -64,16 +69,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `Optimism2` as a supported gas estimator mode -### Added - -- Mercury v0.2 has improved consensus around current block that uses the most recent 5 blocks instead of only the latest one -- Two new prom metrics for mercury, nops should consider adding alerting on these: - - `mercury_insufficient_blocks_count` - - `mercury_zero_blocks_count` - ### Fixed - Corrected Ethereum Sepolia `LinkContractAddress` to `0x779877A7B0D9E8603169DdbD7836e478b4624789` +- Fixed a bug that caused the Telemetry Manager to report incorrect health + +### Upcoming Required Configuration Changes +Starting in `v2.9.0`: +- `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey` will no longer be allowed. Any TOML configuration that sets this fields will prevent the node from booting. These fields will be replaced by `[[TelemetryIngress.Endpoints]]` +- `P2P.V1` will no longer be supported and must not be set in TOML configuration in order to boot. Use `P2P.V2` instead. If you are using both, `V1` can simply be removed. ... From 5aa336a0e3251ac88d75a66d26e48bcbc5604861 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Mon, 4 Dec 2023 14:49:23 +0400 Subject: [PATCH 264/327] [AUTO-7471] add automation node upgrade test to nightly CI (#11469) * add automation node upgrade test to nightly CI * increase nodes to 6 for upgrade test --- .../workflows/automation-nightly-tests.yml | 108 ++++++++++++++++++ .../workflows/automation-ondemand-tests.yml | 2 +- CODEOWNERS | 1 + 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/automation-nightly-tests.yml diff --git a/.github/workflows/automation-nightly-tests.yml b/.github/workflows/automation-nightly-tests.yml new file mode 100644 index 0000000000..3c05786b66 --- /dev/null +++ b/.github/workflows/automation-nightly-tests.yml @@ -0,0 +1,108 @@ +name: Automation Nightly Tests +on: + schedule: + - cron: "0 0 * * *" # Run nightly + push: + tags: + - "*" + workflow_dispatch: + +jobs: + build-chainlink: + environment: integration + permissions: + id-token: write + contents: read + name: Build Chainlink Image + runs-on: ubuntu20.04-16cores-64GB + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Build Chainlink Image + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Chainlink Image + uses: ./.github/actions/build-chainlink-image + with: + tag_suffix: "" + dockerfile: core/chainlink.Dockerfile + git_commit_sha: ${{ github.sha }} + GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} + AWS_REGION: ${{ secrets.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + + automation-upgrade-test: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink] + env: + CHAINLINK_COMMIT_SHA: ${{ github.sha }} + CHAINLINK_ENV_USER: ${{ github.actor }} + TEST_LOG_LEVEL: debug + strategy: + fail-fast: false + matrix: + tests: + - name: Upgrade + suite: smoke + nodes: 6 + os: ubuntu20.04-8cores-32GB + network: SIMULATED + command: -run ^TestAutomationNodeUpgrade$ ./smoke + runs-on: ${{ matrix.tests.os }} + name: Automation ${{ matrix.tests.name }} Test + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.head_ref || github.ref_name }} + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + env: + SELECTED_NETWORKS: ${{ matrix.tests.network }} + TEST_SUITE: ${{ matrix.tests.suite }} + UPGRADE_VERSION: ${{ github.sha }} + UPGRADE_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + with: + test_command_to_run: cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: 'public.ecr.aws/chainlink/chainlink' + cl_image_tag: 'latest' + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_location: ./integration-tests/${{ matrix.tests.suite }}/logs + publish_check_name: Automation Results ${{ matrix.tests.name }} + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Upload test log + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + if: failure() + with: + name: test-log-${{ matrix.tests.name }} + path: /tmp/gotest.log + retention-days: 7 + continue-on-error: true + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Automation ${{ matrix.tests.name }} Test + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 016a10252b..e023006d58 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -140,7 +140,7 @@ jobs: command: -run ^TestAutomationReorg$ ./reorg - name: upgrade suite: smoke - nodes: 3 + nodes: 6 os: ubuntu20.04-8cores-32GB pyroscope_env: ci-automation-on-demand-upgrade network: SIMULATED diff --git a/CODEOWNERS b/CODEOWNERS index e34d3ea1be..83505b0ed8 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -120,6 +120,7 @@ core/scripts/gateway @bolekk @pinebit /.github/workflows/automation-ondemand-tests.yml @smartcontractkit/keepers /.github/workflows/automation-benchmark-tests.yml @smartcontractkit/keepers /.github/workflows/automation-load-tests.yml @smartcontractkit/keepers +/.github/workflows/automation-nightly-tests.yml @smartcontractkit/keepers /core/chainlink.Dockerfile @smartcontractkit/prodsec-public From 2f17dd6d7eb54f2625d44a996a144a2bc3ea3b44 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 4 Dec 2023 09:55:58 -0600 Subject: [PATCH 265/327] core/services/relay/evm/mercury: use chainlink-data-streams (#11293) --- core/scripts/go.mod | 3 +- core/scripts/go.sum | 6 ++- .../ocr2/plugins/mercury/integration_test.go | 17 +++--- core/services/ocr2/plugins/mercury/plugin.go | 6 +-- core/services/ocrcommon/telemetry.go | 12 ++--- core/services/ocrcommon/telemetry_test.go | 12 ++--- .../services/relay/evm/mercury/transmitter.go | 4 +- .../relay/evm/mercury/v1/data_source.go | 27 +++++----- .../relay/evm/mercury/v1/data_source_test.go | 20 +++---- .../mercury/v1/reportcodec/report_codec.go | 7 ++- .../v1/reportcodec/report_codec_test.go | 9 ++-- .../relay/evm/mercury/v2/data_source.go | 21 ++++---- .../relay/evm/mercury/v2/data_source_test.go | 14 ++--- .../mercury/v2/reportcodec/report_codec.go | 6 +-- .../v2/reportcodec/report_codec_test.go | 8 +-- .../relay/evm/mercury/v3/data_source.go | 25 ++++----- .../relay/evm/mercury/v3/data_source_test.go | 8 +-- .../mercury/v3/reportcodec/report_codec.go | 7 ++- .../v3/reportcodec/report_codec_test.go | 8 +-- core/services/relay/evm/mercury_provider.go | 53 ++++++++++--------- go.mod | 3 +- go.sum | 6 ++- integration-tests/go.mod | 3 +- integration-tests/go.sum | 6 ++- 24 files changed, 151 insertions(+), 140 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 21f00df02d..4b44c7a00e 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -303,8 +303,9 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 36504924e1..78faaf6839 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1502,10 +1502,12 @@ 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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c h1:YFyo0pCmKkpB4EOSykCZFueRXNxQ7OhKiCnhoVIzydo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index e8adb55b39..51f9eaa668 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -34,10 +34,11 @@ import ( ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/wsrpc/credentials" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaycodecv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaycodecv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaycodecv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" + relaymercury "github.com/smartcontractkit/chainlink-data-streams/mercury" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -62,7 +63,7 @@ var ( f = uint8(1) n = 4 // number of nodes multiplier int64 = 100000000 - rawOnchainConfig = relaymercury.OnchainConfig{ + rawOnchainConfig = mercurytypes.OnchainConfig{ Min: big.NewInt(0), Max: big.NewInt(math.MaxInt64), } @@ -154,7 +155,7 @@ func TestIntegration_MercuryV1(t *testing.T) { serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { - report, err := (&reportcodecv1.ReportCodec{}).BuildReport(relaycodecv1.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), CurrentBlockHash: make([]byte, 32)}) + report, err := (&reportcodecv1.ReportCodec{}).BuildReport(v1.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), CurrentBlockHash: make([]byte, 32)}) if err != nil { panic(err) } @@ -503,7 +504,7 @@ func TestIntegration_MercuryV2(t *testing.T) { serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { - report, err := (&reportcodecv2.ReportCodec{}).BuildReport(relaycodecv2.ReportFields{BenchmarkPrice: big.NewInt(234567), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + report, err := (&reportcodecv2.ReportCodec{}).BuildReport(v2.ReportFields{BenchmarkPrice: big.NewInt(234567), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) if err != nil { panic(err) } @@ -779,7 +780,7 @@ func TestIntegration_MercuryV3(t *testing.T) { serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { - report, err := (&reportcodecv3.ReportCodec{}).BuildReport(relaycodecv3.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + report, err := (&reportcodecv3.ReportCodec{}).BuildReport(v3.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) if err != nil { panic(err) } diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index d443008334..f5c11dc731 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -7,10 +7,10 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + relaymercuryv1 "github.com/smartcontractkit/chainlink-data-streams/mercury/v1" + relaymercuryv2 "github.com/smartcontractkit/chainlink-data-streams/mercury/v2" + relaymercuryv3 "github.com/smartcontractkit/chainlink-data-streams/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index c9d3e85cd2..18080fe22b 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -21,9 +21,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/utils" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + v1types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v2types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v3types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" ) type eaTelemetry struct { @@ -41,9 +41,9 @@ type EnhancedTelemetryData struct { } type EnhancedTelemetryMercuryData struct { - V1Observation *relaymercuryv1.Observation - V2Observation *relaymercuryv2.Observation - V3Observation *relaymercuryv3.Observation + V1Observation *v1types.Observation + V2Observation *v2types.Observation + V3Observation *v3types.Observation TaskRunResults pipeline.TaskRunResults RepTimestamp ocrtypes.ReportTimestamp FeedVersion mercuryutils.FeedVersion diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index 24c798259d..ae58e89d22 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -14,9 +14,9 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - mercury_v2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + mercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -696,7 +696,7 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { chTelem <- EnhancedTelemetryMercuryData{ TaskRunResults: trrsMercuryV2, - V2Observation: &mercury_v2.Observation{ + V2Observation: &mercuryv2.Observation{ BenchmarkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(111111)}, MaxFinalizedTimestamp: mercury.ObsResult[int64]{Val: 321}, LinkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(4321)}, @@ -749,7 +749,7 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { Value: nil, }}, }, - V2Observation: &mercury_v2.Observation{}, + V2Observation: &mercuryv2.Observation{}, RepTimestamp: types.ReportTimestamp{ ConfigDigest: types.ConfigDigest{2}, Epoch: 11, @@ -760,7 +760,7 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { trrsMercuryV2[0].Result.Value = "" chTelem <- EnhancedTelemetryMercuryData{ TaskRunResults: trrsMercuryV2, - V2Observation: &mercury_v2.Observation{}, + V2Observation: &mercuryv2.Observation{}, RepTimestamp: types.ReportTimestamp{ ConfigDigest: types.ConfigDigest{2}, Epoch: 11, diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index d5346ad28c..40a51b9d92 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -21,8 +21,8 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -89,7 +89,7 @@ var ( ) type Transmitter interface { - relaymercury.Transmitter + mercury.Transmitter services.Service } diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index bc94166e56..429780ef2e 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -1,4 +1,4 @@ -package mercury_v1 +package v1 import ( "context" @@ -13,8 +13,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v1 "github.com/smartcontractkit/chainlink-data-streams/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -41,7 +42,7 @@ var ( ) ) -const nBlocksObservation int = relaymercuryv1.MaxAllowedBlocks +const nBlocksObservation int = v1.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) @@ -66,7 +67,7 @@ type datasource struct { mu sync.RWMutex chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData - chainReader relaymercury.ChainReader + chainReader mercury.ChainReader fetcher Fetcher initialBlockNumber *int64 @@ -74,9 +75,9 @@ type datasource struct { zeroBlocksCounter prometheus.Counter } -var _ relaymercuryv1.DataSource = &datasource{} +var _ v1.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainReader relaymercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainReader mercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { return &datasource{pr, jb, spec, lggr, s, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} } @@ -90,7 +91,7 @@ func (e ErrEmptyLatestReport) Error() string { return fmt.Sprintf("FetchInitialMaxFinalizedBlockNumber returned empty LatestReport; this is a new feed. No initialBlockNumber was set, tried to use current block number to determine maxFinalizedBlockNumber but got error: %v", e.Err) } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs relaymercuryv1.Observation, pipelineExecutionErr error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs v1types.Observation, pipelineExecutionErr error) { // setLatestBlocks must come chronologically before observations, along // with observationTimestamp, to avoid front-running @@ -204,9 +205,9 @@ func toBigInt(val interface{}) (*big.Int, error) { } type parseOutput struct { - benchmarkPrice relaymercury.ObsResult[*big.Int] - bid relaymercury.ObsResult[*big.Int] - ask relaymercury.ObsResult[*big.Int] + benchmarkPrice mercury.ObsResult[*big.Int] + bid mercury.ObsResult[*big.Int] + ask mercury.ObsResult[*big.Int] } // parse expects the output of observe to be three values, in the following order: @@ -290,7 +291,7 @@ func (ds *datasource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.T return run, trrs, err } -func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.Observation) error { +func (ds *datasource) setLatestBlocks(ctx context.Context, obs *v1types.Observation) error { latestBlocks, err := ds.chainReader.LatestHeads(ctx, nBlocksObservation) if err != nil { ds.lggr.Errorw("failed to read latest blocks", "error", err) @@ -318,7 +319,7 @@ func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.O for _, block := range latestBlocks { obs.LatestBlocks = append( obs.LatestBlocks, - relaymercuryv1.NewBlock(int64(block.Number), block.Hash, block.Timestamp)) + v1types.NewBlock(int64(block.Number), block.Hash, block.Timestamp)) } return nil diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index d8d7d39dbb..72dc4327f1 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -1,4 +1,4 @@ -package mercury_v1 +package v1 import ( "context" @@ -15,8 +15,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" mercurymocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/mocks" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" @@ -33,7 +33,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -var _ relaymercury.MercuryServerFetcher = &mockFetcher{} +var _ mercury.ServerFetcher = &mockFetcher{} type mockFetcher struct { num *int64 @@ -71,10 +71,10 @@ func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg type mockChainReader struct { err error - obs []relaymercury.Head + obs []mercury.Head } -func (m *mockChainReader) LatestHeads(context.Context, int) ([]relaymercury.Head, error) { +func (m *mockChainReader) LatestHeads(context.Context, int) ([]mercury.Head, error) { return m.obs, m.err } @@ -391,7 +391,7 @@ func TestMercury_Observe(t *testing.T) { obs, err := ds.Observe(ctx, repts, true) assert.Error(t, err) - assert.Equal(t, obs, relaymercuryv1.Observation{}) + assert.Equal(t, obs, v1.Observation{}) }) }) } @@ -416,7 +416,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { headTracker.On("LatestChain").Return(&h, nil) ds.chainReader = evm.NewChainReader(headTracker) - obs := relaymercuryv1.Observation{} + obs := v1.Observation{} err := ds.setLatestBlocks(testutils.Context(t), &obs) assert.NoError(t, err) @@ -434,7 +434,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) ds.chainReader = evm.NewChainReader(headTracker) - obs := relaymercuryv1.Observation{} + obs := v1.Observation{} err := ds.setLatestBlocks(testutils.Context(t), &obs) assert.NoError(t, err) diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go index 28688e3b17..8f2eac59c3 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go @@ -11,8 +11,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" reporttypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/types" @@ -25,7 +24,7 @@ import ( var ReportTypes = reporttypes.GetSchema() var maxReportLength = 32 * len(ReportTypes) // each arg is 256 bit EVM word -var _ reportcodec.ReportCodec = &ReportCodec{} +var _ v1.ReportCodec = &ReportCodec{} type ReportCodec struct { logger logger.Logger @@ -36,7 +35,7 @@ func NewReportCodec(feedID [32]byte, lggr logger.Logger) *ReportCodec { return &ReportCodec{lggr, feedID} } -func (r *ReportCodec) BuildReport(rf reportcodec.ReportFields) (ocrtypes.Report, error) { +func (r *ReportCodec) BuildReport(rf v1.ReportFields) (ocrtypes.Report, error) { var merr error if rf.BenchmarkPrice == nil { merr = errors.Join(merr, errors.New("benchmarkPrice may not be nil")) diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go index f630b4522b..2e50faf47d 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go @@ -11,15 +11,14 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/utils" ) var hash = hexutil.MustDecode("0x552c2cea3ab43bae137d89ee6142a01db3ae2b5678bc3c9bd5f509f537bea57b") -func newValidReportFields() relaymercuryv1.ReportFields { - return relaymercuryv1.ReportFields{ +func newValidReportFields() v1.ReportFields { + return v1.ReportFields{ Timestamp: 242, BenchmarkPrice: big.NewInt(243), Bid: big.NewInt(244), @@ -35,7 +34,7 @@ func Test_ReportCodec(t *testing.T) { r := ReportCodec{} t.Run("BuildReport errors on zero fields", func(t *testing.T) { - _, err := r.BuildReport(relaymercuryv1.ReportFields{}) + _, err := r.BuildReport(v1.ReportFields{}) require.Error(t, err) assert.Contains(t, err.Error(), "benchmarkPrice may not be nil") assert.Contains(t, err.Error(), "bid may not be nil") diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index ec6cf5ad10..7c2d6424fa 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -1,4 +1,4 @@ -package mercury_v2 +package v2 import ( "context" @@ -10,8 +10,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v2types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v2 "github.com/smartcontractkit/chainlink-data-streams/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -52,13 +53,13 @@ type datasource struct { chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData } -var _ relaymercuryv2.DataSource = &datasource{} +var _ v2.DataSource = &datasource{} func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { return &datasource{pr, jb, spec, feedID, lggr, s, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv2.Observation, pipelineExecutionErr error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs v2types.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup ctx, cancel := context.WithCancel(ctx) @@ -116,8 +117,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.LinkPrice.Val, obs.LinkPrice.Err = ds.fetcher.LatestPrice(ctx, ds.linkFeedID) if obs.LinkPrice.Val == nil && obs.LinkPrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.linkFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", relaymercuryv2.MissingPrice), "linkFeedID", ds.linkFeedID) - obs.LinkPrice.Val = relaymercuryv2.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", v2.MissingPrice), "linkFeedID", ds.linkFeedID) + obs.LinkPrice.Val = v2.MissingPrice } else if obs.LinkPrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.linkFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying LINK price feed", "err", obs.LinkPrice.Err, "linkFeedID", ds.linkFeedID) @@ -134,8 +135,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.NativePrice.Val, obs.NativePrice.Err = ds.fetcher.LatestPrice(ctx, ds.nativeFeedID) if obs.NativePrice.Val == nil && obs.NativePrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.nativeFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", relaymercuryv2.MissingPrice), "nativeFeedID", ds.nativeFeedID) - obs.NativePrice.Val = relaymercuryv2.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", v2.MissingPrice), "nativeFeedID", ds.nativeFeedID) + obs.NativePrice.Val = v2.MissingPrice } else if obs.NativePrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.nativeFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying native price feed", "err", obs.NativePrice.Err, "nativeFeedID", ds.nativeFeedID) @@ -184,7 +185,7 @@ func toBigInt(val interface{}) (*big.Int, error) { } type parseOutput struct { - benchmarkPrice relaymercury.ObsResult[*big.Int] + benchmarkPrice mercury.ObsResult[*big.Int] } func (ds *datasource) parse(trrs pipeline.TaskRunResults) (o parseOutput, merr error) { diff --git a/core/services/relay/evm/mercury/v2/data_source_test.go b/core/services/relay/evm/mercury/v2/data_source_test.go index d1030327e1..c9ae37ae01 100644 --- a/core/services/relay/evm/mercury/v2/data_source_test.go +++ b/core/services/relay/evm/mercury/v2/data_source_test.go @@ -1,4 +1,4 @@ -package mercury_v2 +package v2 import ( "context" @@ -8,11 +8,11 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v2 "github.com/smartcontractkit/chainlink-data-streams/mercury/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -22,7 +22,7 @@ import ( reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" ) -var _ relaymercury.MercuryServerFetcher = &mockFetcher{} +var _ mercury.ServerFetcher = &mockFetcher{} type mockFetcher struct { ts int64 @@ -279,9 +279,9 @@ func Test_Datasource(t *testing.T) { obs, err := ds.Observe(ctx, repts, false) assert.NoError(t, err) - assert.Equal(t, obs.LinkPrice.Val, relaymercuryv2.MissingPrice) + assert.Equal(t, obs.LinkPrice.Val, v2.MissingPrice) assert.Nil(t, obs.LinkPrice.Err) - assert.Equal(t, obs.NativePrice.Val, relaymercuryv2.MissingPrice) + assert.Equal(t, obs.NativePrice.Val, v2.MissingPrice) assert.Nil(t, obs.NativePrice.Err) }) }) diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go index 6b13b3b6ef..33c5fa9a32 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go @@ -9,7 +9,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" @@ -20,7 +20,7 @@ var ReportTypes = reporttypes.GetSchema() var maxReportLength = 32 * len(ReportTypes) // each arg is 256 bit EVM word var zero = big.NewInt(0) -var _ reportcodec.ReportCodec = &ReportCodec{} +var _ v2.ReportCodec = &ReportCodec{} type ReportCodec struct { logger logger.Logger @@ -31,7 +31,7 @@ func NewReportCodec(feedID [32]byte, lggr logger.Logger) *ReportCodec { return &ReportCodec{lggr, feedID} } -func (r *ReportCodec) BuildReport(rf reportcodec.ReportFields) (ocrtypes.Report, error) { +func (r *ReportCodec) BuildReport(rf v2.ReportFields) (ocrtypes.Report, error) { var merr error if rf.BenchmarkPrice == nil { merr = errors.Join(merr, errors.New("benchmarkPrice may not be nil")) diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go index 3a58337b4c..36b3a44388 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go @@ -9,11 +9,11 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" ) -func newValidReportFields() relaymercuryv2.ReportFields { - return relaymercuryv2.ReportFields{ +func newValidReportFields() v2.ReportFields { + return v2.ReportFields{ Timestamp: 242, BenchmarkPrice: big.NewInt(243), ValidFromTimestamp: 123, @@ -27,7 +27,7 @@ func Test_ReportCodec_BuildReport(t *testing.T) { r := ReportCodec{} t.Run("BuildReport errors on zero values", func(t *testing.T) { - _, err := r.BuildReport(relaymercuryv2.ReportFields{}) + _, err := r.BuildReport(v2.ReportFields{}) require.Error(t, err) assert.Contains(t, err.Error(), "benchmarkPrice may not be nil") assert.Contains(t, err.Error(), "linkFee may not be nil") diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index d5e1e5716d..a751149f37 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -1,4 +1,4 @@ -package mercury_v3 +package v3 import ( "context" @@ -11,8 +11,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v3types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" + v3 "github.com/smartcontractkit/chainlink-data-streams/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -53,13 +54,13 @@ type datasource struct { chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData } -var _ relaymercuryv3.DataSource = &datasource{} +var _ v3.DataSource = &datasource{} func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { return &datasource{pr, jb, spec, feedID, lggr, s, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv3.Observation, pipelineExecutionErr error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs v3types.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup ctx, cancel := context.WithCancel(ctx) @@ -119,8 +120,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.LinkPrice.Val, obs.LinkPrice.Err = ds.fetcher.LatestPrice(ctx, ds.linkFeedID) if obs.LinkPrice.Val == nil && obs.LinkPrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.linkFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", relaymercuryv3.MissingPrice), "linkFeedID", ds.linkFeedID) - obs.LinkPrice.Val = relaymercuryv3.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", v3.MissingPrice), "linkFeedID", ds.linkFeedID) + obs.LinkPrice.Val = v3.MissingPrice } else if obs.LinkPrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.linkFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying LINK price feed", "err", obs.LinkPrice.Err, "linkFeedID", ds.linkFeedID) @@ -137,8 +138,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.NativePrice.Val, obs.NativePrice.Err = ds.fetcher.LatestPrice(ctx, ds.nativeFeedID) if obs.NativePrice.Val == nil && obs.NativePrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.nativeFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", relaymercuryv3.MissingPrice), "nativeFeedID", ds.nativeFeedID) - obs.NativePrice.Val = relaymercuryv3.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", v3.MissingPrice), "nativeFeedID", ds.nativeFeedID) + obs.NativePrice.Val = v3.MissingPrice } else if obs.NativePrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.nativeFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying native price feed", "err", obs.NativePrice.Err, "nativeFeedID", ds.nativeFeedID) @@ -187,9 +188,9 @@ func toBigInt(val interface{}) (*big.Int, error) { } type parseOutput struct { - benchmarkPrice relaymercury.ObsResult[*big.Int] - bid relaymercury.ObsResult[*big.Int] - ask relaymercury.ObsResult[*big.Int] + benchmarkPrice mercury.ObsResult[*big.Int] + bid mercury.ObsResult[*big.Int] + ask mercury.ObsResult[*big.Int] } func (ds *datasource) parse(trrs pipeline.TaskRunResults) (o parseOutput, merr error) { diff --git a/core/services/relay/evm/mercury/v3/data_source_test.go b/core/services/relay/evm/mercury/v3/data_source_test.go index e03e321d09..4ff713abb2 100644 --- a/core/services/relay/evm/mercury/v3/data_source_test.go +++ b/core/services/relay/evm/mercury/v3/data_source_test.go @@ -1,4 +1,4 @@ -package mercury_v3 +package v3 import ( "context" @@ -8,8 +8,8 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + relaymercuryv3 "github.com/smartcontractkit/chainlink-data-streams/mercury/v3" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -22,7 +22,7 @@ import ( reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" ) -var _ relaymercury.MercuryServerFetcher = &mockFetcher{} +var _ mercurytypes.ServerFetcher = &mockFetcher{} type mockFetcher struct { ts int64 diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go index 6b379dc194..601431838d 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go @@ -3,14 +3,13 @@ package reportcodec import ( "errors" "fmt" - "math/big" pkgerrors "github.com/pkg/errors" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" @@ -21,7 +20,7 @@ var ReportTypes = reporttypes.GetSchema() var maxReportLength = 32 * len(ReportTypes) // each arg is 256 bit EVM word var zero = big.NewInt(0) -var _ reportcodec.ReportCodec = &ReportCodec{} +var _ v3.ReportCodec = &ReportCodec{} type ReportCodec struct { logger logger.Logger @@ -32,7 +31,7 @@ func NewReportCodec(feedID [32]byte, lggr logger.Logger) *ReportCodec { return &ReportCodec{lggr, feedID} } -func (r *ReportCodec) BuildReport(rf reportcodec.ReportFields) (ocrtypes.Report, error) { +func (r *ReportCodec) BuildReport(rf v3.ReportFields) (ocrtypes.Report, error) { var merr error if rf.BenchmarkPrice == nil { merr = errors.Join(merr, errors.New("benchmarkPrice may not be nil")) diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go index 88416f7ea6..752e6ce34b 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go @@ -9,11 +9,11 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" ) -func newValidReportFields() relaymercuryv3.ReportFields { - return relaymercuryv3.ReportFields{ +func newValidReportFields() v3.ReportFields { + return v3.ReportFields{ Timestamp: 242, BenchmarkPrice: big.NewInt(243), Bid: big.NewInt(244), @@ -29,7 +29,7 @@ func Test_ReportCodec_BuildReport(t *testing.T) { r := ReportCodec{} t.Run("BuildReport errors on zero values", func(t *testing.T) { - _, err := r.BuildReport(relaymercuryv3.ReportFields{}) + _, err := r.BuildReport(v3.ReportFields{}) require.Error(t, err) assert.Contains(t, err.Error(), "benchmarkPrice may not be nil") assert.Contains(t, err.Error(), "linkFee may not be nil") diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index 9025380817..b6a2232da3 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -6,27 +6,28 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink-common/pkg/services" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" + relaymercury "github.com/smartcontractkit/chainlink-data-streams/mercury" + httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" ) -var _ commontypes.MercuryProvider = (*mercuryProvider)(nil) +var _ types.MercuryProvider = (*mercuryProvider)(nil) type mercuryProvider struct { configWatcher *configWatcher transmitter mercury.Transmitter - reportCodecV1 relaymercuryv1.ReportCodec - reportCodecV2 relaymercuryv2.ReportCodec - reportCodecV3 relaymercuryv3.ReportCodec - chainReader relaymercury.ChainReader + reportCodecV1 v1.ReportCodec + reportCodecV2 v2.ReportCodec + reportCodecV3 v3.ReportCodec + chainReader mercurytypes.ChainReader logger logger.Logger ms services.MultiStart @@ -35,10 +36,10 @@ type mercuryProvider struct { func NewMercuryProvider( configWatcher *configWatcher, transmitter mercury.Transmitter, - reportCodecV1 relaymercuryv1.ReportCodec, - reportCodecV2 relaymercuryv2.ReportCodec, - reportCodecV3 relaymercuryv3.ReportCodec, - chainReader relaymercury.ChainReader, + reportCodecV1 v1.ReportCodec, + reportCodecV2 v2.ReportCodec, + reportCodecV3 v3.ReportCodec, + chainReader mercurytypes.ChainReader, lggr logger.Logger, ) *mercuryProvider { return &mercuryProvider{ @@ -84,19 +85,19 @@ func (p *mercuryProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigest return p.configWatcher.OffchainConfigDigester() } -func (p *mercuryProvider) OnchainConfigCodec() relaymercury.OnchainConfigCodec { +func (p *mercuryProvider) OnchainConfigCodec() mercurytypes.OnchainConfigCodec { return relaymercury.StandardOnchainConfigCodec{} } -func (p *mercuryProvider) ReportCodecV1() relaymercuryv1.ReportCodec { +func (p *mercuryProvider) ReportCodecV1() v1.ReportCodec { return p.reportCodecV1 } -func (p *mercuryProvider) ReportCodecV2() relaymercuryv2.ReportCodec { +func (p *mercuryProvider) ReportCodecV2() v2.ReportCodec { return p.reportCodecV2 } -func (p *mercuryProvider) ReportCodecV3() relaymercuryv3.ReportCodec { +func (p *mercuryProvider) ReportCodecV3() v3.ReportCodec { return p.reportCodecV3 } @@ -104,35 +105,35 @@ func (p *mercuryProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return p.transmitter } -func (p *mercuryProvider) MercuryServerFetcher() relaymercury.MercuryServerFetcher { +func (p *mercuryProvider) MercuryServerFetcher() mercurytypes.ServerFetcher { return p.transmitter } -func (p *mercuryProvider) ChainReader() relaymercury.ChainReader { +func (p *mercuryProvider) ChainReader() mercurytypes.ChainReader { return p.chainReader } -var _ relaymercury.ChainReader = (*chainReader)(nil) +var _ mercurytypes.ChainReader = (*chainReader)(nil) type chainReader struct { tracker httypes.HeadTracker } -func NewChainReader(h httypes.HeadTracker) relaymercury.ChainReader { +func NewChainReader(h httypes.HeadTracker) mercurytypes.ChainReader { return &chainReader{ tracker: h, } } -func (r *chainReader) LatestHeads(ctx context.Context, k int) ([]relaymercury.Head, error) { +func (r *chainReader) LatestHeads(ctx context.Context, k int) ([]mercurytypes.Head, error) { evmBlocks := r.tracker.LatestChain().AsSlice(k) if len(evmBlocks) == 0 { return nil, nil } - blocks := make([]relaymercury.Head, len(evmBlocks)) + blocks := make([]mercurytypes.Head, len(evmBlocks)) for x := 0; x < len(evmBlocks); x++ { - blocks[x] = relaymercury.Head{ + blocks[x] = mercurytypes.Head{ Number: uint64(evmBlocks[x].BlockNumber()), Hash: evmBlocks[x].Hash.Bytes(), Timestamp: uint64(evmBlocks[x].Timestamp.Unix()), diff --git a/go.mod b/go.mod index 0343f4e715..c209cbca43 100644 --- a/go.mod +++ b/go.mod @@ -66,8 +66,9 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 diff --git a/go.sum b/go.sum index 4bd90da600..0874359653 100644 --- a/go.sum +++ b/go.sum @@ -1507,10 +1507,12 @@ 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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c h1:YFyo0pCmKkpB4EOSykCZFueRXNxQ7OhKiCnhoVIzydo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index f95557b2bb..4249cb0e9b 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c github.com/smartcontractkit/chainlink-testing-framework v1.20.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 @@ -397,6 +397,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.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index b275f6b653..d4b804101d 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1792,10 +1792,12 @@ 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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c h1:YFyo0pCmKkpB4EOSykCZFueRXNxQ7OhKiCnhoVIzydo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= From fb61a59360b8ea0ef7fd3dcf1444a5015cc106ca Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:32:59 +0400 Subject: [PATCH 266/327] [AUTO-7471] add notification to automation-nightly-test (#11473) * fix automation-nightly-test * add notification * fix test-results --- .../workflows/automation-nightly-tests.yml | 151 +++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automation-nightly-tests.yml b/.github/workflows/automation-nightly-tests.yml index 3c05786b66..9fa3746f3d 100644 --- a/.github/workflows/automation-nightly-tests.yml +++ b/.github/workflows/automation-nightly-tests.yml @@ -7,6 +7,9 @@ on: - "*" workflow_dispatch: +env: + CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + jobs: build-chainlink: environment: integration @@ -39,7 +42,7 @@ jobs: AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - automation-upgrade-test: + automation-upgrade-tests: environment: integration permissions: checks: write @@ -74,7 +77,7 @@ jobs: SELECTED_NETWORKS: ${{ matrix.tests.network }} TEST_SUITE: ${{ matrix.tests.suite }} UPGRADE_VERSION: ${{ github.sha }} - UPGRADE_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + UPGRADE_IMAGE: ${{ env.CHAINLINK_IMAGE }} with: test_command_to_run: cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -106,3 +109,147 @@ jobs: this-job-name: Automation ${{ matrix.tests.name }} Test test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true + + test-notify: + name: Start Slack Thread + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + outputs: + thread_ts: ${{ steps.slack.outputs.thread_ts }} + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: [ automation-upgrade-tests ] + steps: + - name: Debug Result + run: echo ${{ join(needs.*.result, ',') }} + - name: Main Slack Notification + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + id: slack + with: + channel-id: C03KJ5S7KEK + payload: | + { + "attachments": [ + { + "color": "${{ contains(join(needs.*.result, ','), 'failure') && '#C62828' || '#2E7D32' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "Automation Nightly Tests ${{ contains(join(needs.*.result, ','), 'failure') && ':x:' || ':white_check_mark:'}}", + "emoji": true + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "<${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}|${{ github.ref_name }}> | <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> | <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Run>" + } + } + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + + test-results: + name: Post Test Results for ${{ matrix.name }} + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: test-notify + strategy: + fail-fast: false + matrix: + name: [ Upgrade ] + steps: + - name: Get Results + id: test-results + run: | + # I feel like there's some clever, fully jq way to do this, but I ain't got the motivation to figure it out + echo "Querying test results" + + PARSED_RESULTS=$(curl \ + -H "Authorization: Bearer ${{ github.token }}" \ + 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ + | jq -r --arg pattern "${{ matrix.name }} Test" '.jobs[] + | select(.name | test($pattern)) as $job + | $job.steps[] + | select(.name == "Run Tests") + | { conclusion: (if .conclusion == "success" then ":white_check_mark:" else ":x:" end), product: ("*" + ($job.name | capture($pattern).product) + "*") }') + + echo "Parsed Results:" + echo $PARSED_RESULTS + + ALL_SUCCESS=true + for row in $(echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")'); do + success=false + break + done + + echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT + + FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] + | { + conclusion: .conclusion, + product: .product + } + ] + | map("{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"\(.product): \(.conclusion)\"}}") + | join(",")') + + echo "Formatted Results:" + echo $FORMATTED_RESULTS + + # Cleans out backslashes and quotes from jq + CLEAN_RESULTS=$(echo "$FORMATTED_RESULTS" | sed 's/\\\"/"/g' | sed 's/^"//;s/"$//') + + echo "Clean Results" + echo $CLEAN_RESULTS + + echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT + + - name: Test Details + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + with: + channel-id: C03KJ5S7KEK + payload: | + { + "thread_ts": "${{ needs.test-notify.outputs.thread_ts }}", + "attachments": [ + { + "color": "${{ steps.test-results.outputs.all_success && '#2E7D32' || '#C62828' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "${{ matrix.name }} ${{ steps.test-results.outputs.all_success && ':white_check_mark:' || ':x: Notifying <@U02Q14G80TY>'}}", + "emoji": true + } + }, + { + "type": "divider" + }, + ${{ steps.test-results.outputs.results }} + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} \ No newline at end of file From ea290bedf80fd5e575109f6d77bd7b719bd92579 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Mon, 4 Dec 2023 19:34:40 +0100 Subject: [PATCH 267/327] Fix solhint warnings (#11480) * ignore old automation & fix minor vrf * add more ignore and fix various non-automation * fix gas diff --- contracts/.solhintignore | 8 ++++++++ contracts/package.json | 2 +- contracts/src/v0.8/ChainlinkClient.sol | 1 + contracts/src/v0.8/ValidatorProxy.sol | 2 ++ contracts/src/v0.8/automation/libraries/internal/Cron.sol | 1 + .../l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol | 4 ++++ .../src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol | 2 ++ .../l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol | 2 ++ contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol | 4 ++++ .../src/v0.8/transmission/dev/ERC-4337/Paymaster.sol | 2 ++ .../src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol | 1 + .../dev/ERC-4337/SmartContractAccountFactory.sol | 2 ++ .../dev/testhelpers/SmartContractAccountHelper.sol | 3 +++ contracts/src/v0.8/vrf/KeepersVRFConsumer.sol | 1 + contracts/src/v0.8/vrf/VRF.sol | 7 +++++++ contracts/src/v0.8/vrf/VRFCoordinatorV2.sol | 1 + 16 files changed, 42 insertions(+), 1 deletion(-) diff --git a/contracts/.solhintignore b/contracts/.solhintignore index ba2aac1fb3..569c8c51df 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1,6 +1,14 @@ # 344 warnings #./src/v0.8/automation +# Ignore frozen Automation code +./src/v0.8/automation/v1_2 +./src/v0.8/automation/v1_3 +./src/v0.8/automation/v2_0 +./src/v0.8/automation/v2_1 +./src/v0.8/automation/mocks +./src/v0.8/automation/testhelpers + # Ignore Functions v1.0.0 code that was frozen after audit ./src/v0.8/functions/v1_0_0 diff --git a/contracts/package.json b/contracts/package.json index 1503c822ea..2604a12bea 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 376 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 83 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", diff --git a/contracts/src/v0.8/ChainlinkClient.sol b/contracts/src/v0.8/ChainlinkClient.sol index 2d9302faef..ef7f794345 100644 --- a/contracts/src/v0.8/ChainlinkClient.sol +++ b/contracts/src/v0.8/ChainlinkClient.sol @@ -171,6 +171,7 @@ abstract contract ChainlinkClient { s_pendingRequests[requestId] = oracleAddress; emit ChainlinkRequested(requestId); require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle"); + return requestId; } /** diff --git a/contracts/src/v0.8/ValidatorProxy.sol b/contracts/src/v0.8/ValidatorProxy.sol index 627af73b39..4584bb0255 100644 --- a/contracts/src/v0.8/ValidatorProxy.sol +++ b/contracts/src/v0.8/ValidatorProxy.sol @@ -167,6 +167,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface current = s_currentAggregator.target; hasProposal = s_currentAggregator.hasNewProposal; proposed = s_proposedAggregator; + return (current, hasProposal, proposed); } /** VALIDATOR CONFIGURATION FUNCTIONS **/ @@ -216,6 +217,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface current = s_currentValidator.target; hasProposal = s_currentValidator.hasNewProposal; proposed = s_proposedValidator; + return (current, hasProposal, proposed); } /** diff --git a/contracts/src/v0.8/automation/libraries/internal/Cron.sol b/contracts/src/v0.8/automation/libraries/internal/Cron.sol index fe72c412b6..ae4f90d0d7 100644 --- a/contracts/src/v0.8/automation/libraries/internal/Cron.sol +++ b/contracts/src/v0.8/automation/libraries/internal/Cron.sol @@ -84,6 +84,7 @@ struct Field { * abstraction called a Spec. The library also includes a spec function, nextTick(), which * determines the next time a cron job should fire based on the current block timestamp. */ +// solhint-disable chainlink-solidity/prefix-internal-functions-with-underscore, no-global-import library Cron { using strings for *; diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol index 5250fbda27..63952ab7ba 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol @@ -287,6 +287,8 @@ contract ArbitrumSequencerUptimeFeed is roundId = _roundId; updatedAt = startedAt; answeredInRound = roundId; + + return (roundId, answer, startedAt, updatedAt, answeredInRound); } /// @inheritdoc AggregatorV3Interface @@ -305,5 +307,7 @@ contract ArbitrumSequencerUptimeFeed is startedAt = feedState.latestTimestamp; updatedAt = startedAt; answeredInRound = roundId; + + return (roundId, answer, startedAt, updatedAt, answeredInRound); } } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol index 2043ffa628..66fee5053e 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol @@ -204,6 +204,8 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf message ); emit L2WithdrawalRequested(id, amount, refundAddr); + + return id; } /** diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol index fcf6093e3c..947b1b0bf5 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol @@ -245,6 +245,7 @@ contract OptimismSequencerUptimeFeed is } else { revert NoDataPresent(); } + return (roundId, answer, startedAt, updatedAt, answeredInRound); } /// @inheritdoc AggregatorV3Interface @@ -262,5 +263,6 @@ contract OptimismSequencerUptimeFeed is startedAt = feedState.startedAt; updatedAt = feedState.updatedAt; answeredInRound = roundId; + return (roundId, answer, startedAt, updatedAt, answeredInRound); } } diff --git a/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol b/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol index 9691cfb7fe..53f79b6dc4 100644 --- a/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol +++ b/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol @@ -16,6 +16,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint256 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readUint256(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 32 > data.length) revert MalformedData(); @@ -32,6 +33,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint192 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readUint192(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 24 > data.length) revert MalformedData(); @@ -50,6 +52,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint32 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readUint32(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 4 > data.length) revert MalformedData(); @@ -68,6 +71,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint32 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readAddress(bytes memory data, uint256 offset) internal pure returns (address result) { //bounds check if (offset + 20 > data.length) revert MalformedData(); diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol index 970ddf6b7e..38b6fb5798 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol @@ -103,6 +103,7 @@ contract Paymaster is IPaymaster, ConfirmedOwner { extraCost = directFundingData.topupAmount; } } + return extraCost; } /// @dev Deducts user subscription balance after execution. @@ -116,6 +117,7 @@ contract Paymaster is IPaymaster, ConfirmedOwner { function _getCostJuels(uint256 costWei) internal view returns (uint256 costJuels) { costJuels = (1e18 * costWei) / uint256(_getFeedData()); + return costJuels; } function _getFeedData() internal view returns (int256) { diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol index 47587e278f..35d666a2d3 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol @@ -31,6 +31,7 @@ library SCALibrary { hashOfEncoding ) ); + return fullHash; } function _recoverSignature(bytes memory signature, bytes32 fullHash) internal pure returns (address) { diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol index 35719345ec..bb0f2dbde6 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol @@ -27,5 +27,7 @@ contract SmartContractAccountFactory { } emit ContractCreated(scaAddress); + + return scaAddress; } } diff --git a/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol index c33df49d16..014f296f07 100644 --- a/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol +++ b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol @@ -18,6 +18,7 @@ library SmartContractAccountHelper { SCA.executeTransactionFromEntryPoint.selector, abi.encode(endContract, value, block.timestamp + deadline, data) ); + return encoding; } function getFullHashForSigning(bytes32 userOpHash, address scaAddress) public view returns (bytes32) { @@ -29,6 +30,7 @@ library SmartContractAccountHelper { address entryPoint ) public pure returns (bytes memory initCode) { initCode = bytes.concat(INITIALIZE_CODE, abi.encode(owner, entryPoint)); + return initCode; } function getInitCode( @@ -46,6 +48,7 @@ library SmartContractAccountHelper { initializeCodeWithConstructor ) ); + return initCode; } /// @dev Computes the smart contract address that results from a CREATE2 operation, per EIP-1014. diff --git a/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol index a18c6e0379..20fd806b0c 100644 --- a/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol +++ b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol @@ -61,6 +61,7 @@ contract KeepersVRFConsumer is KeeperCompatibleInterface, VRFConsumerBaseV2 { * @return upkeepNeeded true if and only if at least UPKEEP_INTERVAL seconds have elapsed since the last upkeep or since construction * of the contract. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function checkUpkeep( bytes calldata /* checkData */ ) external view override returns (bool upkeepNeeded, bytes memory /* performData */) { diff --git a/contracts/src/v0.8/vrf/VRF.sol b/contracts/src/v0.8/vrf/VRF.sol index a19fc39ec3..f7d62a272b 100644 --- a/contracts/src/v0.8/vrf/VRF.sol +++ b/contracts/src/v0.8/vrf/VRF.sol @@ -205,6 +205,7 @@ contract VRF { while (x_ >= FIELD_SIZE) { x_ = uint256(keccak256(abi.encodePacked(x_))); } + return x_; } // Hash b to a random point which hopefully lies on secp256k1. The y ordinate @@ -223,6 +224,7 @@ contract VRF { p[1] = FIELD_SIZE - p[1]; } } + return p; } // Domain-separation tag for initial hash in _hashToCurve. Corresponds to @@ -248,6 +250,7 @@ contract VRF { while (!_isOnCurve(rv)) { rv = _newCandidateSecp256k1Point(abi.encodePacked(rv[0])); } + return rv; } /** ********************************************************************* @@ -294,6 +297,7 @@ contract VRF { uint256 num2 = mulmod(FIELD_SIZE - x2, z1, FIELD_SIZE); (x3, z3) = (addmod(num1, num2, FIELD_SIZE), mulmod(z1, z2, FIELD_SIZE)); } + return (x3, z3); } // Returns x1/z1*x2/z2=(x1x2)/(z1z2), in projective coordinates on P¹(𝔽ₙ) @@ -304,6 +308,7 @@ contract VRF { uint256 z2 ) internal pure returns (uint256 x3, uint256 z3) { (x3, z3) = (mulmod(x1, x2, FIELD_SIZE), mulmod(z1, z2, FIELD_SIZE)); + return (x3, z3); } /** ************************************************************************** @@ -385,6 +390,7 @@ contract VRF { sz = dx; } } + return (sx, sy, sz); } // p1+p2, as affine points on secp256k1. @@ -577,5 +583,6 @@ contract VRF { proof.zInv ); output = uint256(keccak256(abi.encode(VRF_RANDOM_OUTPUT_HASH_PREFIX, proof.gamma))); + return output; } } diff --git a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol index 5acd3e7435..5dfb51a4b1 100644 --- a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol @@ -491,6 +491,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo // The seed actually used by the VRF machinery, mixing in the blockhash uint256 actualSeed = uint256(keccak256(abi.encodePacked(proof.seed, blockHash))); randomness = VRF._randomValueFromVRFProof(proof, actualSeed); // Reverts on failure + return (keyHash, requestId, randomness); } /* From c68240f73fcddef7b9ab9d578ecd3ea9a346faab Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 4 Dec 2023 12:45:04 -0600 Subject: [PATCH 268/327] bump libocr; remove P2P.V1; drop libp2p (#10872) --- core/cmd/jobs_commands_test.go | 4 +- core/cmd/ocr-bootstrap-spec.yml | 4 +- core/cmd/shell_remote_test.go | 5 +- core/config/docs/core.toml | 52 +-- core/config/p2p_config.go | 4 - core/config/p2p_v1_config.go | 20 - core/config/toml/types.go | 74 ---- core/internal/cltest/factories.go | 2 +- core/internal/cltest/job_factories.go | 2 +- core/internal/features/features_test.go | 129 ++----- .../features/ocr2/features_ocr2_test.go | 1 - .../testutils/configtest/general_config.go | 1 - core/scripts/go.mod | 57 +-- core/scripts/go.sum | 347 +----------------- core/services/chainlink/config.go | 37 +- core/services/chainlink/config_general.go | 10 - core/services/chainlink/config_p2p.go | 67 +--- core/services/chainlink/config_p2p_test.go | 15 - core/services/chainlink/config_test.go | 78 +--- .../testdata/config-empty-effective.toml | 13 - .../chainlink/testdata/config-full.toml | 13 - .../config-multi-chain-effective.toml | 13 - core/services/feeds/service_test.go | 5 +- core/services/job/helpers_test.go | 16 +- core/services/job/models.go | 1 - core/services/job/orm.go | 4 +- core/services/job/runner_integration_test.go | 17 +- core/services/ocr/delegate.go | 30 +- core/services/ocr/example-job-spec.toml | 4 +- core/services/ocr/validate.go | 7 +- core/services/ocr/validate_test.go | 59 +-- .../v1/internal/testutils.go | 1 - .../plugins/ocr2keeper/integration_test.go | 1 - .../internal/ocr2vrf_integration_test.go | 1 - core/services/ocrcommon/peer_wrapper.go | 110 +----- core/services/ocrcommon/peer_wrapper_test.go | 94 +---- ..._oracle_specs_drop_p2p_bootstrap_peers.sql | 5 + core/testdata/testspecs/v2_specs.go | 5 +- core/web/assets/index.html | 2 +- core/web/assets/index.html.gz | Bin 420 -> 418 bytes ...560e37.js => main.8f602c136d4004a835ee.js} | 2 +- ....js.gz => main.8f602c136d4004a835ee.js.gz} | Bin 1190421 -> 1190411 bytes core/web/jobs_controller_test.go | 17 +- core/web/loop_registry_test.go | 5 +- core/web/pipeline_runs_controller_test.go | 9 +- core/web/presenters/job.go | 2 - core/web/presenters/job_test.go | 2 - core/web/resolver/spec.go | 11 - core/web/resolver/spec_test.go | 3 - .../testdata/config-empty-effective.toml | 13 - core/web/resolver/testdata/config-full.toml | 13 - .../config-multi-chain-effective.toml | 13 - core/web/schema/type/spec.graphql | 1 - docs/CONFIG.md | 110 +----- go.mod | 57 +-- go.sum | 347 +----------------- integration-tests/go.mod | 53 +-- integration-tests/go.sum | 337 +---------------- integration-tests/types/config/node/core.go | 14 - operator_ui/TAG | 2 +- testdata/scripts/node/validate/default.txtar | 13 - .../disk-based-logging-disabled.txtar | 13 - .../validate/disk-based-logging-no-dir.txtar | 13 - .../node/validate/disk-based-logging.txtar | 13 - testdata/scripts/node/validate/invalid.txtar | 13 - testdata/scripts/node/validate/valid.txtar | 13 - testdata/scripts/node/validate/warnings.txtar | 54 +-- tools/benchmark/job_spec_delete_v2.sh | 2 +- 68 files changed, 173 insertions(+), 2282 deletions(-) delete mode 100644 core/config/p2p_v1_config.go create mode 100644 core/store/migrate/migrations/0212_ocr_oracle_specs_drop_p2p_bootstrap_peers.sql rename core/web/assets/{main.b0b6f79f7f4a94560e37.js => main.8f602c136d4004a835ee.js} (91%) rename core/web/assets/{main.b0b6f79f7f4a94560e37.js.gz => main.8f602c136d4004a835ee.js.gz} (93%) diff --git a/core/cmd/jobs_commands_test.go b/core/cmd/jobs_commands_test.go index 04908e18ff..5d9b3cb3f1 100644 --- a/core/cmd/jobs_commands_test.go +++ b/core/cmd/jobs_commands_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/urfave/cli" @@ -368,7 +369,8 @@ func TestShell_CreateJobV2(t *testing.T) { app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) diff --git a/core/cmd/ocr-bootstrap-spec.yml b/core/cmd/ocr-bootstrap-spec.yml index 9db118b77c..058fdeb2c1 100644 --- a/core/cmd/ocr-bootstrap-spec.yml +++ b/core/cmd/ocr-bootstrap-spec.yml @@ -4,7 +4,5 @@ contractAddress = "0x27548a32b9aD5D64c5945EaE9Da5337bc3169D15" externalJobID = "%s" name = "%s" evmChainID = "0" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 6143d678a9..6c8b46eda4 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/kylelemons/godebug/diff" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" @@ -62,7 +63,6 @@ func startNewApplicationV2(t *testing.T, overrideFn func(c *chainlink.Config, s c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(30 * time.Millisecond) f := false c.EVM[0].Enabled = &f - c.P2P.V1.Enabled = &f c.P2P.V2.Enabled = &f if overrideFn != nil { @@ -567,7 +567,8 @@ func TestShell_RunOCRJob_HappyPath(t *testing.T) { app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") }, func(opts *startOptions) { diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index e438f4553f..953f1feabd 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -394,13 +394,7 @@ CaptureEATelemetry = false # Default # TraceLogging enables trace level logging. TraceLogging = false # Default -# P2P supports multiple networking stack versions. You may configure `[P2P.V1]`, `[P2P.V2]`, or both to run simultaneously. -# If both are configured, then for each link with another peer, V2 networking will be preferred. If V2 does not work, the link will -# automatically fall back to V1. If V2 starts working again later, it will automatically be preferred again. This is useful -# for migrating networks without downtime. Note that the two networking stacks _must not_ be configured to bind to the same IP/port. -# -# Note: P2P.V1 is deprecated will be removed in the future. -# +# P2P has a versioned networking stack. Currenly only `[P2P.V2]` is supported. # All nodes in the OCR network should share the same networking stack. [P2P] # IncomingMessageBufferSize is the per-remote number of incoming @@ -419,50 +413,6 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example # TraceLogging enables trace level logging. TraceLogging = false # Default -# P2P.V1 is deprecated and will be removed in a future version. -[P2P.V1] -# Enabled enables P2P V1. -Enabled = false # Default -# AnnounceIP should be set as the externally reachable IP address of the Chainlink node. -AnnounceIP = '1.2.3.4' # Example -# AnnouncePort should be set as the externally reachable port of the Chainlink node. -AnnouncePort = 1337 # Example -# BootstrapCheckInterval is the interval at which nodes check connections to bootstrap nodes and reconnect if any of them is lost. -# Setting this to a small value would allow newly joined bootstrap nodes to get more connectivity -# more quickly, which helps to make bootstrap process faster. The cost of this operation is relatively -# cheap. We set this to 1 minute during our test. -BootstrapCheckInterval = '20s' # Default -# DefaultBootstrapPeers is the default set of bootstrap peers. -DefaultBootstrapPeers = ['/dns4/example.com/tcp/1337/p2p/12D3KooWMHMRLQkgPbFSYHwD3NBuwtS1AmxhvKVUrcfyaGDASR4U', '/ip4/1.2.3.4/tcp/9999/p2p/12D3KooWLZ9uTC3MrvKfDpGju6RAQubiMDL7CuJcAgDRTYP7fh7R'] # Example -# DHTAnnouncementCounterUserPrefix can be used to restore the node's -# ability to announce its IP/port on the P2P network after a database -# rollback. Make sure to only increase this value, and *never* decrease it. -# Don't use this variable unless you really know what you're doing, since you -# could semi-permanently exclude your node from the P2P network by -# misconfiguring it. -DHTAnnouncementCounterUserPrefix = 0 # Default -# **ADVANCED** -# DHTLookupInterval is the interval between which we do the expensive peer -# lookup using DHT. -# -# Every DHTLookupInterval failures to open a stream to a peer, we will -# attempt to lookup its IP from DHT -DHTLookupInterval = 10 # Default -# ListenIP is the default IP address to bind to. -ListenIP = '0.0.0.0' # Default -# ListenPort is the port to listen on. If left blank, the node randomly selects a different port each time it boots. It is highly recommended to set this to a static value to avoid network instability. -ListenPort = 1337 # Example -# **ADVANCED** -# NewStreamTimeout is the maximum length of time to wait to open a -# stream before we give up. -# We shouldn't hit this in practice since libp2p will give up fast if -# it can't get a connection, but it is here anyway as a failsafe. -# Set to 0 to disable any timeout on top of what libp2p gives us by default. -NewStreamTimeout = '10s' # Default -# **ADVANCED** -# PeerstoreWriteInterval controls how often the peerstore for the OCR V1 networking stack is persisted to the database. -PeerstoreWriteInterval = '5m' # Default - [P2P.V2] # Enabled enables P2P V2. # Note: V1.Enabled is true by default, so it must be set false in order to run V2 only. diff --git a/core/config/p2p_config.go b/core/config/p2p_config.go index 30693b3a25..4a7ec28417 100644 --- a/core/config/p2p_config.go +++ b/core/config/p2p_config.go @@ -1,15 +1,11 @@ package config import ( - ocrnetworking "github.com/smartcontractkit/libocr/networking" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) type P2P interface { V2() V2 - V1() V1 - NetworkStack() (n ocrnetworking.NetworkingStack) PeerID() p2pkey.PeerID IncomingMessageBufferSize() int OutgoingMessageBufferSize() int diff --git a/core/config/p2p_v1_config.go b/core/config/p2p_v1_config.go deleted file mode 100644 index 2e13828518..0000000000 --- a/core/config/p2p_v1_config.go +++ /dev/null @@ -1,20 +0,0 @@ -package config - -import ( - "net" - "time" -) - -type V1 interface { - Enabled() bool - AnnounceIP() net.IP - AnnouncePort() uint16 - DefaultBootstrapPeers() ([]string, error) - DHTAnnouncementCounterUserPrefix() uint32 - ListenIP() net.IP - ListenPort() uint16 - NewStreamTimeout() time.Duration - BootstrapCheckInterval() time.Duration - DHTLookupInterval() int - PeerstoreWriteInterval() time.Duration -} diff --git a/core/config/toml/types.go b/core/config/toml/types.go index c420d7f3f4..e944b44853 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -13,7 +13,6 @@ import ( "go.uber.org/zap/zapcore" ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" - ocrnetworking "github.com/smartcontractkit/libocr/networking" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/config" @@ -1040,23 +1039,9 @@ type P2P struct { PeerID *p2pkey.PeerID TraceLogging *bool - V1 P2PV1 `toml:",omitempty"` V2 P2PV2 `toml:",omitempty"` } -func (p *P2P) NetworkStack() ocrnetworking.NetworkingStack { - v1, v2 := *p.V1.Enabled, *p.V2.Enabled - switch { - case v1 && v2: - return ocrnetworking.NetworkingStackV1V2 - case v2: - return ocrnetworking.NetworkingStackV2 - case v1: - return ocrnetworking.NetworkingStackV1 - } - return ocrnetworking.NetworkingStack(0) -} - func (p *P2P) setFrom(f *P2P) { if v := f.IncomingMessageBufferSize; v != nil { p.IncomingMessageBufferSize = v @@ -1071,68 +1056,9 @@ func (p *P2P) setFrom(f *P2P) { p.TraceLogging = v } - p.V1.setFrom(&f.V1) p.V2.setFrom(&f.V2) } -type P2PV1 struct { - Enabled *bool - AnnounceIP *net.IP - AnnouncePort *uint16 - BootstrapCheckInterval *models.Duration - DefaultBootstrapPeers *[]string - DHTAnnouncementCounterUserPrefix *uint32 - DHTLookupInterval *int64 - ListenIP *net.IP - ListenPort *uint16 - NewStreamTimeout *models.Duration - PeerstoreWriteInterval *models.Duration -} - -func (p *P2PV1) ValidateConfig() (err error) { - //TODO or empty? - if p.AnnouncePort != nil && p.AnnounceIP == nil { - err = multierr.Append(err, configutils.ErrMissing{Name: "AnnounceIP", Msg: fmt.Sprintf("required when AnnouncePort is set: %d", *p.AnnouncePort)}) - } - return -} - -func (p *P2PV1) setFrom(f *P2PV1) { - if v := f.Enabled; v != nil { - p.Enabled = v - } - if v := f.AnnounceIP; v != nil { - p.AnnounceIP = v - } - if v := f.AnnouncePort; v != nil { - p.AnnouncePort = v - } - if v := f.BootstrapCheckInterval; v != nil { - p.BootstrapCheckInterval = v - } - if v := f.DefaultBootstrapPeers; v != nil { - p.DefaultBootstrapPeers = v - } - if v := f.DHTAnnouncementCounterUserPrefix; v != nil { - p.DHTAnnouncementCounterUserPrefix = v - } - if v := f.DHTLookupInterval; v != nil { - p.DHTLookupInterval = v - } - if v := f.ListenIP; v != nil { - p.ListenIP = v - } - if v := f.ListenPort; v != nil { - p.ListenPort = v - } - if v := f.NewStreamTimeout; v != nil { - p.NewStreamTimeout = v - } - if v := f.PeerstoreWriteInterval; v != nil { - p.PeerstoreWriteInterval = v - } -} - type P2PV2 struct { Enabled *bool AnnounceAddresses *[]string diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index f0ce8c4ff6..c169c5fd22 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -339,7 +339,7 @@ func MustInsertOffchainreportingOracleSpec(t *testing.T, db *sqlx.DB, transmitte ocrKeyID := models.MustSha256HashFromHex(DefaultOCRKeyBundleID) spec := job.OCROracleSpec{} - require.NoError(t, db.Get(&spec, `INSERT INTO ocr_oracle_specs (created_at, updated_at, contract_address, p2p_bootstrap_peers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, observation_timeout, blockchain_timeout, contract_config_tracker_subscribe_interval, contract_config_tracker_poll_interval, contract_config_confirmations, database_timeout, observation_grace_period, contract_transmitter_transmit_timeout, evm_chain_id) VALUES ( + require.NoError(t, db.Get(&spec, `INSERT INTO ocr_oracle_specs (created_at, updated_at, contract_address, p2pv2_bootstrappers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, observation_timeout, blockchain_timeout, contract_config_tracker_subscribe_interval, contract_config_tracker_poll_interval, contract_config_confirmations, database_timeout, observation_grace_period, contract_transmitter_transmit_timeout, evm_chain_id) VALUES ( NOW(),NOW(),$1,'{}',false,$2,$3,0,0,0,0,0,0,0,0,0 ) RETURNING *`, NewEIP55Address(), &ocrKeyID, &transmitterAddress)) return spec diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index a9e403fb60..399e71ff21 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -25,7 +25,7 @@ const ( contractAddress = "%s" evmChainID = "0" p2pPeerID = "%s" - p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] + p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false transmitterAddress = "%s" keyBundleID = "%s" diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 35fd3a31ff..7b29fdae4f 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -37,7 +37,6 @@ import ( ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" "github.com/smartcontractkit/libocr/gethwrappers/testoffchainaggregator" - ocrnetworking "github.com/smartcontractkit/libocr/networking" "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" @@ -675,8 +674,8 @@ func setupOCRContracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBac return owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress } -func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, - b *backends.SimulatedBackend, ns ocrnetworking.NetworkingStack, overrides func(c *chainlink.Config, s *chainlink.Secrets), +func setupNode(t *testing.T, owner *bind.TransactOpts, portV2 int, + b *backends.SimulatedBackend, overrides func(c *chainlink.Config, s *chainlink.Secrets), ) (*cltest.TestApplication, string, common.Address, ocrkey.KeyV2) { p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -686,32 +685,10 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - switch ns { - case ocrnetworking.NetworkingStackV1: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(false) - // We want to quickly poll for the bootstrap node to come up, but if we poll too quickly - // we'll flood it with messages and slow things down. 5s is about how long it takes the - // bootstrap node to come up. - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - - case ocrnetworking.NetworkingStackV2: - c.P2P.V1.Enabled = ptr(false) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - - case ocrnetworking.NetworkingStackV1V2: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - // Note v1 and v2 ports must be distinct, - // v1v2 mode will listen on both. - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - } + + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} + c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) // GracePeriod < ObservationTimeout c.EVM[0].OCR.ObservationGracePeriod = models.MustNewDuration(100 * time.Millisecond) @@ -743,21 +720,7 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, return app, p2pKey.PeerID().Raw(), transmitter, key } -func setupForwarderEnabledNode( - t *testing.T, - owner *bind.TransactOpts, - portV1, - portV2 int, - b *backends.SimulatedBackend, - ns ocrnetworking.NetworkingStack, - overrides func(c *chainlink.Config, s *chainlink.Secrets), -) ( - *cltest.TestApplication, - string, - common.Address, - common.Address, - ocrkey.KeyV2, -) { +func setupForwarderEnabledNode(t *testing.T, owner *bind.TransactOpts, portV2 int, b *backends.SimulatedBackend, overrides func(c *chainlink.Config, s *chainlink.Secrets)) (*cltest.TestApplication, string, common.Address, common.Address, ocrkey.KeyV2) { p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. @@ -766,32 +729,9 @@ func setupForwarderEnabledNode( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - switch ns { - case ocrnetworking.NetworkingStackV1: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(false) - // We want to quickly poll for the bootstrap node to come up, but if we poll too quickly - // we'll flood it with messages and slow things down. 5s is about how long it takes the - // bootstrap node to come up. - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - - case ocrnetworking.NetworkingStackV2: - c.P2P.V1.Enabled = ptr(false) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - - case ocrnetworking.NetworkingStackV1V2: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - // Note v1 and v2 ports must be distinct, - // v1v2 mode will listen on both. - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - } + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} + c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) c.EVM[0].Transactions.ForwardersEnabled = ptr(true) @@ -842,16 +782,12 @@ func TestIntegration_OCR(t *testing.T) { testutils.SkipShort(t, "long test") t.Parallel() tests := []struct { - id int - portStart int // Test need to run in parallel, all need distinct port ranges. - name string - eip1559 bool - ns ocrnetworking.NetworkingStack + id int + name string + eip1559 bool }{ - {1, 20000, "legacy mode", false, ocrnetworking.NetworkingStackV1}, - {2, 20010, "eip1559 mode", true, ocrnetworking.NetworkingStackV1}, - {3, 20020, "legacy mode V1V2", false, ocrnetworking.NetworkingStackV1V2}, - {4, 20030, "legacy mode V2", false, ocrnetworking.NetworkingStackV2}, + {1, "legacy mode", false}, + {2, "eip1559 mode", true}, } numOracles := 4 @@ -859,31 +795,27 @@ func TestIntegration_OCR(t *testing.T) { test := tt t.Run(test.name, func(t *testing.T) { t.Parallel() - bootstrapNodePortV1 := freeport.GetOne(t) bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) // Note it's plausible these ports could be occupied on a CI machine. // May need a port randomize + retry approach if we observe collisions. - appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, b, test.ns, nil) + appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV2, b, nil) var ( oracles []confighelper.OracleIdentityExtra transmitters []common.Address keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) - ports := freeport.GetN(t, 2*numOracles) + ports := freeport.GetN(t, numOracles) for i := 0; i < numOracles; i++ { - portV1 := ports[2*i] - portV2 := ports[2*i+1] - app, peerID, transmitter, key := setupNode(t, owner, portV1, portV2, b, test.ns, func(c *chainlink.Config, s *chainlink.Secrets) { + app, peerID, transmitter, key := setupNode(t, owner, ports[i], b, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(test.eip1559) - if test.ns != ocrnetworking.NetworkingStackV1 { - c.P2P.V2.DefaultBootstrappers = &[]ocrcommontypes.BootstrapperLocator{ - {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePortV2)}}, - } + + c.P2P.V2.DefaultBootstrappers = &[]ocrcommontypes.BootstrapperLocator{ + {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePortV2)}}, } }) @@ -1007,9 +939,6 @@ name = "web oracle spec" contractAddress = "%s" evmChainID = "%s" isBootstrapPeer = false -p2pBootstrapPeers = [ - "/ip4/127.0.0.1/tcp/%d/p2p/%s" -] keyBundleID = "%s" transmitterAddress = "%s" observationTimeout = "100ms" @@ -1031,7 +960,7 @@ observationSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, testutils.SimulatedChainID.String(), bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, testutils.SimulatedChainID.String(), keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) require.NoError(t, err) jb.Name = null.NewString("testocr", true) err = apps[i].AddJobV2(testutils.Context(t), &jb) @@ -1084,14 +1013,13 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { t.Parallel() numOracles := 4 t.Run("ocr_forwarder_flow", func(t *testing.T) { - bootstrapNodePortV1 := freeport.GetOne(t) bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) // Note it's plausible these ports could be occupied on a CI machine. // May need a port randomize + retry approach if we observe collisions. - appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, b, ocrnetworking.NetworkingStackV2, nil) + appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV2, b, nil) var ( oracles []confighelper.OracleIdentityExtra @@ -1100,11 +1028,9 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) - ports := freeport.GetN(t, 2*numOracles) + ports := freeport.GetN(t, numOracles) for i := 0; i < numOracles; i++ { - portV1 := ports[2*i] - portV2 := ports[2*i+1] - app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, portV1, portV2, b, ocrnetworking.NetworkingStackV2, func(c *chainlink.Config, s *chainlink.Secrets) { + app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, ports[i], b, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) @@ -1241,9 +1167,6 @@ contractAddress = "%s" evmChainID = "%s" forwardingAllowed = true isBootstrapPeer = false -p2pBootstrapPeers = [ - "/ip4/127.0.0.1/tcp/%d/p2p/%s" -] keyBundleID = "%s" transmitterAddress = "%s" observationTimeout = "100ms" @@ -1265,7 +1188,7 @@ observationSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, testutils.SimulatedChainID.String(), bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, testutils.SimulatedChainID.String(), keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) require.NoError(t, err) jb.Name = null.NewString("testocr", true) err = apps[i].AddJobV2(testutils.Context(t), &jb) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 387b15f76c..295bb7fb14 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -119,7 +119,6 @@ func setupNodeOCR2( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) diff --git a/core/internal/testutils/configtest/general_config.go b/core/internal/testutils/configtest/general_config.go index 93d388b2d3..f076521b71 100644 --- a/core/internal/testutils/configtest/general_config.go +++ b/core/internal/testutils/configtest/general_config.go @@ -56,7 +56,6 @@ func overrides(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ReaperInterval = models.MustNewDuration(0) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(false) c.WebServer.SessionTimeout = models.MustNewDuration(2 * time.Minute) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 4b44c7a00e..89ddc54ca7 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -22,7 +22,7 @@ require ( github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 + github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.4 @@ -70,7 +70,7 @@ require ( github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect + github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 // indirect github.com/cockroachdb/redact v1.1.3 // indirect github.com/cometbft/cometbft v0.37.2 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect @@ -88,7 +88,6 @@ require ( github.com/danieljoos/wincred v1.1.2 // indirect github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect @@ -102,7 +101,6 @@ require ( github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/esote/minmaxheap v1.0.0 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect @@ -146,7 +144,6 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect @@ -164,10 +161,8 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -175,14 +170,11 @@ require ( github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.2 // indirect + github.com/holiman/uint256 v1.2.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect - github.com/huin/goupnp v1.0.3 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/go-cid v0.0.7 // indirect - github.com/ipfs/go-datastore v0.4.5 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipns v0.0.2 // indirect github.com/ipfs/go-log v1.0.4 // indirect github.com/ipfs/go-log/v2 v2.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -194,58 +186,21 @@ require ( github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgx/v4 v4.18.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/libp2p/go-addr-util v0.0.2 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect - github.com/libp2p/go-eventbus v0.2.1 // indirect - github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p v0.13.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 // indirect - github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect - github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect - github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect github.com/libp2p/go-libp2p-core v0.8.5 // indirect - github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.11.1 // indirect - github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect - github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect - github.com/libp2p/go-libp2p-nat v0.0.6 // indirect - github.com/libp2p/go-libp2p-noise v0.1.2 // indirect github.com/libp2p/go-libp2p-peerstore v0.2.7 // indirect - github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect - github.com/libp2p/go-libp2p-record v0.1.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect - github.com/libp2p/go-libp2p-tls v0.1.3 // indirect - github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect - github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect - github.com/libp2p/go-mplex v0.3.0 // indirect - github.com/libp2p/go-msgio v0.0.6 // indirect - github.com/libp2p/go-nat v0.0.5 // indirect - github.com/libp2p/go-netroute v0.1.4 // indirect github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/libp2p/go-reuseport v0.0.2 // indirect - github.com/libp2p/go-reuseport-transport v0.0.4 // indirect - github.com/libp2p/go-sockaddr v0.1.0 // indirect - github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect - github.com/libp2p/go-tcp-transport v0.2.1 // indirect - github.com/libp2p/go-ws-transport v0.4.0 // indirect - github.com/libp2p/go-yamux/v2 v2.0.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -266,12 +221,10 @@ require ( github.com/multiformats/go-base32 v0.0.3 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr v0.3.3 // indirect - github.com/multiformats/go-multiaddr-dns v0.2.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multiaddr-net v0.2.0 // indirect github.com/multiformats/go-multibase v0.0.3 // indirect github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-multistream v0.2.0 // indirect github.com/multiformats/go-varint v0.0.6 // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect @@ -337,8 +290,6 @@ require ( github.com/ulule/limiter/v3 v3.11.2 // indirect github.com/unrolled/secure v1.13.0 // indirect github.com/valyala/fastjson v1.4.1 // indirect - github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect - github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zondax/hid v0.9.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 78faaf6839..5f0e22fba0 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -75,7 +75,6 @@ github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo8 github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= -github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= @@ -105,7 +104,6 @@ github.com/Depado/ginprom v1.7.11/go.mod h1:49mxL3NTQwDrhpDbY4V1mAIB3us9B+b2hP1+ github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -230,15 +228,16 @@ github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b80 github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877 h1:1MLK4YpFtIEo3ZtMA5C795Wtv5VuUnrXX7mQG+aHg6o= +github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 h1:T+Np/xtzIjYM/P5NAw0e2Rf1FGvzDau1h54MKvx8G7w= +github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= @@ -257,7 +256,6 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -306,9 +304,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= @@ -323,8 +318,6 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFM github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= -github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= @@ -334,7 +327,6 @@ github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KP github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -390,8 +382,6 @@ github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBd github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= @@ -591,10 +581,6 @@ github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -674,15 +660,11 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -698,9 +680,6 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= @@ -735,17 +714,15 @@ github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gt github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= -github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= +github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -758,45 +735,18 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= -github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg= -github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= -github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= -github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= -github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= -github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= -github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= -github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= -github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs= -github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= @@ -860,19 +810,10 @@ github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= -github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= -github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= -github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= -github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= @@ -903,7 +844,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= @@ -927,9 +867,6 @@ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZX github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.2 h1:fL3wAoyT6hXHQlORyXUW4Q23kkQpJRgEAYcZB5BR71o= -github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -958,211 +895,22 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= -github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= -github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= -github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= -github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= -github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= -github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= -github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= -github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= -github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= -github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 h1:2H/P+forDWBHije1WULwPfGduByUmC4fthndHVRpYNU= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= -github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= -github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= -github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug= -github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= -github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= -github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= -github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= -github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= -github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= -github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= -github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= -github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= -github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= -github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= -github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= -github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= -github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= -github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= -github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= -github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= -github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= -github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= -github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= -github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= -github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= -github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= -github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= -github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= -github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= -github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= -github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= -github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= -github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk= -github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE= -github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= -github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= -github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= -github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= -github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= -github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= -github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= -github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= -github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= -github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= -github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= -github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= -github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= -github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= -github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= -github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= -github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= -github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= -github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= -github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= -github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= -github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= -github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= -github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= -github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= -github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= -github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.4 h1:47V0+hJfYaqj1WO0A+cDkRc9xr9qKiK7i8zaoGv8Mmo= -github.com/libp2p/go-netroute v0.1.4/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= -github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= -github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= -github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= -github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= -github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= -github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= -github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= -github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= -github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= -github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= -github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= -github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= -github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= @@ -1170,7 +918,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -1187,7 +934,6 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -1209,12 +955,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= @@ -1222,9 +964,6 @@ github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= @@ -1260,7 +999,6 @@ github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -1271,50 +1009,24 @@ github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= -github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= -github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= -github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= -github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= -github.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU= -github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= @@ -1338,9 +1050,7 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -1348,9 +1058,7 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= @@ -1520,8 +1228,8 @@ github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88 github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= -github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 h1:AA7vf29c6lFsZm+MtIEtXtg6VUOQV6waJo5MUuHfRjQ= +github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7/go.mod h1:WcuWFMskcGK0MYZuH5hEhGJOzdJRUFeNEM4PAKlejI4= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= @@ -1530,9 +1238,7 @@ github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1559,7 +1265,6 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= -github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1637,8 +1342,8 @@ github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFs github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= @@ -1649,15 +1354,8 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= -github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= -github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1755,7 +1453,6 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -1767,26 +1464,18 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1847,7 +1536,6 @@ golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1883,7 +1571,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1942,17 +1629,13 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1961,7 +1644,6 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1981,7 +1663,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2054,7 +1735,6 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -2230,7 +1910,6 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -2286,8 +1965,6 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= -gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 5d8b1019e8..b2f60384ec 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -76,42 +76,7 @@ func (c *Config) valueWarnings() (err error) { // deprecationWarnings returns an error if the Config contains deprecated fields. // This is typically used before defaults have been applied, with input from the user. func (c *Config) deprecationWarnings() (err error) { - if c.P2P.V1 != (toml.P2PV1{}) { - err = multierr.Append(err, config.ErrDeprecated{Name: "P2P.V1"}) - var err2 error - if c.P2P.V1.AnnounceIP != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnounceIP"}) - } - if c.P2P.V1.AnnouncePort != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnouncePort"}) - } - if c.P2P.V1.BootstrapCheckInterval != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "BootstrapCheckInterval"}) - } - if c.P2P.V1.DefaultBootstrapPeers != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DefaultBootstrapPeers"}) - } - if c.P2P.V1.DHTAnnouncementCounterUserPrefix != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTAnnouncementCounterUserPrefix"}) - } - if c.P2P.V1.DHTLookupInterval != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTLookupInterval"}) - } - if c.P2P.V1.ListenIP != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenIP"}) - } - if c.P2P.V1.ListenPort != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenPort"}) - } - if c.P2P.V1.NewStreamTimeout != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "NewStreamTimeout"}) - } - if c.P2P.V1.PeerstoreWriteInterval != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "PeerstoreWriteInterval"}) - } - err2 = config.NamedMultiErrorList(err2, "P2P.V1") - err = multierr.Append(err, err2) - } + // none return } diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index c7d9cc6ce5..5df2b177bd 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -13,8 +13,6 @@ import ( "go.uber.org/multierr" "go.uber.org/zap/zapcore" - ocrnetworking "github.com/smartcontractkit/libocr/networking" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" starknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" @@ -443,14 +441,6 @@ func (g *generalConfig) P2P() config.P2P { return &p2p{c: g.c.P2P} } -func (g *generalConfig) P2PNetworkingStack() (n ocrnetworking.NetworkingStack) { - return g.c.P2P.NetworkStack() -} - -func (g *generalConfig) P2PNetworkingStackRaw() string { - return g.c.P2P.NetworkStack().String() -} - func (g *generalConfig) P2PPeerID() p2pkey.PeerID { return *g.c.P2P.PeerID } diff --git a/core/services/chainlink/config_p2p.go b/core/services/chainlink/config_p2p.go index 35b80cc5f7..596a4fe0ca 100644 --- a/core/services/chainlink/config_p2p.go +++ b/core/services/chainlink/config_p2p.go @@ -1,11 +1,7 @@ package chainlink import ( - "net" - "time" - "github.com/smartcontractkit/libocr/commontypes" - ocrnetworking "github.com/smartcontractkit/libocr/networking" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" @@ -18,11 +14,7 @@ type p2p struct { } func (p *p2p) Enabled() bool { - return p.V1().Enabled() || p.V2().Enabled() -} - -func (p *p2p) NetworkStack() (n ocrnetworking.NetworkingStack) { - return p.c.NetworkStack() + return p.V2().Enabled() } func (p *p2p) PeerID() p2pkey.PeerID { @@ -45,63 +37,6 @@ func (p *p2p) V2() config.V2 { return &p2pv2{p.c.V2} } -func (p *p2p) V1() config.V1 { - return &p2pv1{p.c.V1} -} - -type p2pv1 struct { - c toml.P2PV1 -} - -func (v *p2pv1) Enabled() bool { - return *v.c.Enabled -} - -func (v *p2pv1) AnnounceIP() net.IP { - return *v.c.AnnounceIP -} - -func (v *p2pv1) AnnouncePort() uint16 { - return *v.c.AnnouncePort -} - -func (v *p2pv1) DefaultBootstrapPeers() ([]string, error) { - p := *v.c.DefaultBootstrapPeers - if p == nil { - p = []string{} - } - return p, nil -} - -func (v *p2pv1) DHTAnnouncementCounterUserPrefix() uint32 { - return *v.c.DHTAnnouncementCounterUserPrefix -} - -func (v *p2pv1) ListenIP() net.IP { - return *v.c.ListenIP -} - -func (v *p2pv1) ListenPort() uint16 { - p := *v.c.ListenPort - return p -} - -func (v *p2pv1) NewStreamTimeout() time.Duration { - return v.c.NewStreamTimeout.Duration() -} - -func (v *p2pv1) BootstrapCheckInterval() time.Duration { - return v.c.BootstrapCheckInterval.Duration() -} - -func (v *p2pv1) DHTLookupInterval() int { - return int(*v.c.DHTLookupInterval) -} - -func (v *p2pv1) PeerstoreWriteInterval() time.Duration { - return v.c.PeerstoreWriteInterval.Duration() -} - type p2pv2 struct { c toml.P2PV2 } diff --git a/core/services/chainlink/config_p2p_test.go b/core/services/chainlink/config_p2p_test.go index 21ce8f17e4..c23f3296ef 100644 --- a/core/services/chainlink/config_p2p_test.go +++ b/core/services/chainlink/config_p2p_test.go @@ -23,21 +23,6 @@ func TestP2PConfig(t *testing.T) { assert.Equal(t, 17, p2p.OutgoingMessageBufferSize()) assert.True(t, p2p.TraceLogging()) - v1 := p2p.V1() - assert.True(t, v1.Enabled()) - assert.Equal(t, "1.2.3.4", v1.AnnounceIP().String()) - assert.Equal(t, uint16(1234), v1.AnnouncePort()) - assert.Equal(t, time.Minute, v1.BootstrapCheckInterval()) - p, err := v1.DefaultBootstrapPeers() - require.NoError(t, err) - assert.Equal(t, []string{"foo", "bar", "should", "these", "be", "typed"}, p) - assert.Equal(t, uint32(4321), v1.DHTAnnouncementCounterUserPrefix()) - assert.Equal(t, 9, v1.DHTLookupInterval()) - assert.Equal(t, "4.3.2.1", v1.ListenIP().String()) - assert.Equal(t, uint16(9), v1.ListenPort()) - assert.Equal(t, time.Second, v1.NewStreamTimeout()) - assert.Equal(t, time.Minute, v1.PeerstoreWriteInterval()) - v2 := p2p.V2() assert.False(t, v2.Enabled()) assert.Equal(t, []string{"a", "b", "c"}, v2.AnnounceAddresses()) diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 2966a89690..6453fe05e0 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -410,19 +410,6 @@ func TestConfig_Marshal(t *testing.T) { OutgoingMessageBufferSize: ptr[int64](17), PeerID: mustPeerID("12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw"), TraceLogging: ptr(true), - V1: toml.P2PV1{ - Enabled: ptr(true), - AnnounceIP: mustIP("1.2.3.4"), - AnnouncePort: ptr[uint16](1234), - BootstrapCheckInterval: models.MustNewDuration(time.Minute), - DefaultBootstrapPeers: &[]string{"foo", "bar", "should", "these", "be", "typed"}, - DHTAnnouncementCounterUserPrefix: ptr[uint32](4321), - DHTLookupInterval: ptr[int64](9), - ListenIP: mustIP("4.3.2.1"), - ListenPort: ptr[uint16](9), - NewStreamTimeout: models.MustNewDuration(time.Second), - PeerstoreWriteInterval: models.MustNewDuration(time.Minute), - }, V2: toml.P2PV2{ Enabled: ptr(false), AnnounceAddresses: &[]string{"a", "b", "c"}, @@ -872,19 +859,6 @@ OutgoingMessageBufferSize = 17 PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true -[P2P.V1] -Enabled = true -AnnounceIP = '1.2.3.4' -AnnouncePort = 1234 -BootstrapCheckInterval = '1m0s' -DefaultBootstrapPeers = ['foo', 'bar', 'should', 'these', 'be', 'typed'] -DHTAnnouncementCounterUserPrefix = 4321 -DHTLookupInterval = 9 -ListenIP = '4.3.2.1' -ListenPort = 9 -NewStreamTimeout = '1s' -PeerstoreWriteInterval = '1m0s' - [P2P.V2] Enabled = false AnnounceAddresses = ['a', 'b', 'c'] @@ -1320,19 +1294,7 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { effective = "# Effective Configuration, with defaults applied:\n" warning = "# Configuration warning:\n" - deprecated = `2 errors: - - P2P.V1: is deprecated and will be removed in a future version - - P2P.V1: 10 errors: - - AnnounceIP: is deprecated and will be removed in a future version - - AnnouncePort: is deprecated and will be removed in a future version - - BootstrapCheckInterval: is deprecated and will be removed in a future version - - DefaultBootstrapPeers: is deprecated and will be removed in a future version - - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version - - DHTLookupInterval: is deprecated and will be removed in a future version - - ListenIP: is deprecated and will be removed in a future version - - ListenPort: is deprecated and will be removed in a future version - - NewStreamTimeout: is deprecated and will be removed in a future version - - PeerstoreWriteInterval: is deprecated and will be removed in a future version` + deprecated = `` // none ) tests := []struct { name string @@ -1558,7 +1520,7 @@ func TestConfig_SetFrom(t *testing.T) { } } -func TestConfig_Warnings(t *testing.T) { +func TestConfig_warnings(t *testing.T) { tests := []struct { name string config Config @@ -1582,42 +1544,6 @@ func TestConfig_Warnings(t *testing.T) { }, expectedErrors: []string{"Tracing.TLSCertPath: invalid value (/path/to/cert.pem): must be empty when Tracing.Mode is 'unencrypted'"}, }, - { - name: "Deprecation warning - P2P.V1 fields set", - config: Config{ - Core: toml.Core{ - P2P: toml.P2P{ - V1: toml.P2PV1{ - Enabled: ptr(true), - }, - }, - }, - }, - expectedErrors: []string{ - "P2P.V1: is deprecated and will be removed in a future version", - }, - }, - { - name: "Value warning and deprecation warning", - config: Config{ - Core: toml.Core{ - P2P: toml.P2P{ - V1: toml.P2PV1{ - Enabled: ptr(true), - }, - }, - Tracing: toml.Tracing{ - Enabled: ptr(true), - Mode: ptr("unencrypted"), - TLSCertPath: ptr("/path/to/cert.pem"), - }, - }, - }, - expectedErrors: []string{ - "Tracing.TLSCertPath: invalid value (/path/to/cert.pem): must be empty when Tracing.Mode is 'unencrypted'", - "P2P.V1: is deprecated and will be removed in a future version", - }, - }, } for _, tt := range tests { diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 2531e7c281..9efad05c03 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -161,19 +161,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 46d9dc2c23..c6387e4ef6 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -167,19 +167,6 @@ OutgoingMessageBufferSize = 17 PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true -[P2P.V1] -Enabled = true -AnnounceIP = '1.2.3.4' -AnnouncePort = 1234 -BootstrapCheckInterval = '1m0s' -DefaultBootstrapPeers = ['foo', 'bar', 'should', 'these', 'be', 'typed'] -DHTAnnouncementCounterUserPrefix = 4321 -DHTLookupInterval = 9 -ListenIP = '4.3.2.1' -ListenPort = 9 -NewStreamTimeout = '1s' -PeerstoreWriteInterval = '1m0s' - [P2P.V2] Enabled = false AnnounceAddresses = ['a', 'b', 'c'] diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 74d83035cd..40c18f28eb 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -161,19 +161,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index d811a4461f..271321a116 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -75,10 +75,7 @@ name = "%s" externalJobID = "%s" evmChainID = 0 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] keyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5" transmitterAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" isBootstrapPeer = false diff --git a/core/services/job/helpers_test.go b/core/services/job/helpers_test.go index 4151ed401c..a7543753d6 100644 --- a/core/services/job/helpers_test.go +++ b/core/services/job/helpers_test.go @@ -36,10 +36,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" evmChainID = "0" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "%s" monitoringEndpoint = "chain.link:4321" @@ -108,7 +105,7 @@ ds1 -> ds1_parse -> ds1_multiply; type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" - p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] + p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false transmitterAddress = "%s" keyBundleID = "%s" @@ -125,7 +122,6 @@ ds1 -> ds1_parse; schemaVersion = 1 contractAddress = "%s" evmChainID = "0" - p2pBootstrapPeers = [] isBootstrapPeer = true ` ocrJobSpecText = ` @@ -134,10 +130,7 @@ schemaVersion = 1 contractAddress = "%s" evmChainID = "0" p2pPeerID = "%s" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "%s" monitoringEndpoint = "chain.link:4321" @@ -194,7 +187,7 @@ func makeOCRJobSpec(t *testing.T, transmitterAddress common.Address, b1, b2 stri func compareOCRJobSpecs(t *testing.T, expected, actual job.Job) { require.NotNil(t, expected.OCROracleSpec) require.Equal(t, expected.OCROracleSpec.ContractAddress, actual.OCROracleSpec.ContractAddress) - require.Equal(t, expected.OCROracleSpec.P2PBootstrapPeers, actual.OCROracleSpec.P2PBootstrapPeers) + require.Equal(t, expected.OCROracleSpec.P2PV2Bootstrappers, actual.OCROracleSpec.P2PV2Bootstrappers) require.Equal(t, expected.OCROracleSpec.IsBootstrapPeer, actual.OCROracleSpec.IsBootstrapPeer) require.Equal(t, expected.OCROracleSpec.EncryptedOCRKeyBundleID, actual.OCROracleSpec.EncryptedOCRKeyBundleID) require.Equal(t, expected.OCROracleSpec.TransmitterAddress, actual.OCROracleSpec.TransmitterAddress) @@ -207,7 +200,6 @@ func compareOCRJobSpecs(t *testing.T, expected, actual job.Job) { func makeMinimalHTTPOracleSpec(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig, contractAddress, transmitterAddress, keyBundle, fetchUrl, timeout string) *job.Job { var ocrSpec = job.OCROracleSpec{ - P2PBootstrapPeers: pq.StringArray{}, P2PV2Bootstrappers: pq.StringArray{}, ObservationTimeout: models.Interval(10 * time.Second), BlockchainTimeout: models.Interval(20 * time.Second), diff --git a/core/services/job/models.go b/core/services/job/models.go index 05dcab831f..18a0cb79e2 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -237,7 +237,6 @@ func (pr *PipelineRun) SetID(value string) error { type OCROracleSpec struct { ID int32 `toml:"-"` ContractAddress ethkey.EIP55Address `toml:"contractAddress"` - P2PBootstrapPeers pq.StringArray `toml:"p2pBootstrapPeers" db:"p2p_bootstrap_peers"` P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers" db:"p2pv2_bootstrappers"` IsBootstrapPeer bool `toml:"isBootstrapPeer"` EncryptedOCRKeyBundleID *models.Sha256Hash `toml:"keyBundleID"` diff --git a/core/services/job/orm.go b/core/services/job/orm.go index c5f533c3d2..482d3d851e 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -212,10 +212,10 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { return errors.Errorf("a job with contract address %s already exists for chain ID %s", jb.OCROracleSpec.ContractAddress, newChainID) } - sql := `INSERT INTO ocr_oracle_specs (contract_address, p2p_bootstrap_peers, p2pv2_bootstrappers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, + sql := `INSERT INTO ocr_oracle_specs (contract_address, p2pv2_bootstrappers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, observation_timeout, blockchain_timeout, contract_config_tracker_subscribe_interval, contract_config_tracker_poll_interval, contract_config_confirmations, evm_chain_id, created_at, updated_at, database_timeout, observation_grace_period, contract_transmitter_transmit_timeout) - VALUES (:contract_address, :p2p_bootstrap_peers, :p2pv2_bootstrappers, :is_bootstrap_peer, :encrypted_ocr_key_bundle_id, :transmitter_address, + VALUES (:contract_address, :p2pv2_bootstrappers, :is_bootstrap_peer, :encrypted_ocr_key_bundle_id, :transmitter_address, :observation_timeout, :blockchain_timeout, :contract_config_tracker_subscribe_interval, :contract_config_tracker_poll_interval, :contract_config_confirmations, :evm_chain_id, NOW(), NOW(), :database_timeout, :observation_grace_period, :contract_transmitter_transmit_timeout) RETURNING id;` diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index eb6af3607f..ef0458312b 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -14,6 +14,7 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/shopspring/decimal" @@ -58,11 +59,8 @@ func TestRunner(t *testing.T) { require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V1.DefaultBootstrapPeers = &[]string{ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", - "/dns4/chain.link/tcp/1235/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", - } + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} kb, err := keyStore.OCR().Create() require.NoError(t, err) kbid := models.MustSha256HashFromHex(kb.ID()) @@ -78,7 +76,10 @@ func TestRunner(t *testing.T) { ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(cltest.Head(10), nil) ethClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(nil, nil) + ctx := testutils.Context(t) pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + require.NoError(t, pipelineORM.Start(ctx)) + t.Cleanup(func() { assert.NoError(t, pipelineORM.Close()) }) btORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: ethClient, GeneralConfig: config, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -86,10 +87,11 @@ func TestRunner(t *testing.T) { runner := pipeline.NewRunner(pipelineORM, btORM, config.JobPipeline(), config.WebServer(), legacyChains, nil, nil, logger.TestLogger(t), c, c) jobORM := NewTestORM(t, db, pipelineORM, btORM, keyStore, config.Database()) + t.Cleanup(func() { assert.NoError(t, jobORM.Close()) }) _, placeHolderAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) - require.NoError(t, runner.Start(testutils.Context(t))) + require.NoError(t, runner.Start(ctx)) t.Cleanup(func() { assert.NoError(t, runner.Close()) }) t.Run("gets the election result winner", func(t *testing.T) { @@ -545,7 +547,8 @@ answer1 [type=median index=0]; for _, tc := range testCases { config = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.OCR.CaptureEATelemetry = ptr(tc.specCaptureEATelemetry) }) diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index f473c93b1f..d3d133e712 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -14,7 +14,6 @@ import ( commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - ocrnetworking "github.com/smartcontractkit/libocr/networking" ocr "github.com/smartcontractkit/libocr/offchainreporting" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" @@ -146,16 +145,6 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e return nil, errors.New("peerWrapper is not started. OCR jobs require a started and running p2p peer") } - var v1BootstrapPeers []string - if concreteSpec.P2PBootstrapPeers != nil { - v1BootstrapPeers = concreteSpec.P2PBootstrapPeers - } else { - v1BootstrapPeers, err = chain.Config().P2P().V1().DefaultBootstrapPeers() - if err != nil { - return nil, err - } - } - v2Bootstrappers, err := ocrcommon.ParseBootstrapPeers(concreteSpec.P2PV2Bootstrappers) if err != nil { return nil, err @@ -181,7 +170,6 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e var bootstrapper *ocr.BootstrapNode bootstrapper, err = ocr.NewBootstrapNode(ocr.BootstrapNodeArgs{ BootstrapperFactory: peerWrapper.Peer1, - V1Bootstrappers: v1BootstrapPeers, V2Bootstrappers: v2Bootstrappers, ContractConfigTracker: tracker, Database: ocrDB, @@ -194,20 +182,9 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e bootstrapperCtx := job.NewServiceAdapter(bootstrapper) services = append(services, bootstrapperCtx) } else { - // In V1 or V1V2 mode, p2pv1BootstrapPeers must be defined either in - // node config or in job spec - if peerWrapper.P2PConfig().NetworkStack() != ocrnetworking.NetworkingStackV2 { - if len(v1BootstrapPeers) < 1 { - return nil, errors.New("Need at least one v1 bootstrap peer defined") - } - } - - // In V1V2 or V2 mode, p2pv2Bootstrappers must be defined either in - // node config or in job spec - if peerWrapper.P2PConfig().NetworkStack() != ocrnetworking.NetworkingStackV1 { - if len(v2Bootstrappers) < 1 { - return nil, errors.New("Need at least one v2 bootstrap peer defined") - } + // p2pv2Bootstrappers must be defined either in node config or in job spec + if len(v2Bootstrappers) < 1 { + return nil, errors.New("Need at least one v2 bootstrap peer defined") } ocrkey, err := d.keyStore.OCR().Get(concreteSpec.EncryptedOCRKeyBundleID.String()) @@ -325,7 +302,6 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e PrivateKeys: ocrkey, BinaryNetworkEndpointFactory: peerWrapper.Peer1, Logger: ocrLogger, - V1Bootstrappers: v1BootstrapPeers, V2Bootstrappers: v2Bootstrappers, MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint("EVM", chain.ID().String(), concreteSpec.ContractAddress.String(), synchronization.OCR), ConfigOverrider: configOverrider, diff --git a/core/services/ocr/example-job-spec.toml b/core/services/ocr/example-job-spec.toml index f8854a0a0b..7622c45f21 100644 --- a/core/services/ocr/example-job-spec.toml +++ b/core/services/ocr/example-job-spec.toml @@ -2,9 +2,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" diff --git a/core/services/ocr/validate.go b/core/services/ocr/validate.go index a780ebb082..0524ed24d0 100644 --- a/core/services/ocr/validate.go +++ b/core/services/ocr/validate.go @@ -5,9 +5,9 @@ import ( "time" "github.com/lib/pq" - "github.com/multiformats/go-multiaddr" "github.com/pelletier/go-toml" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/offchainreporting" "github.com/smartcontractkit/chainlink/v2/common/config" @@ -77,11 +77,6 @@ func ValidatedOracleSpecTomlCfg(configFn func(id *big.Int) (evmconfig.ChainScope if !tree.Has("isBootstrapPeer") { return jb, errors.New("isBootstrapPeer is not defined") } - for i := range spec.P2PBootstrapPeers { - if _, err = multiaddr.NewMultiaddr(spec.P2PBootstrapPeers[i]); err != nil { - return jb, errors.Wrapf(err, "p2p bootstrap peer %v is invalid", spec.P2PBootstrapPeers[i]) - } - } if len(spec.P2PV2Bootstrappers) > 0 { _, err = ocrcommon.ParseBootstrapPeers(spec.P2PV2Bootstrappers) diff --git a/core/services/ocr/validate_test.go b/core/services/ocr/validate_test.go index 0164fd82c5..4d8a9ae26c 100644 --- a/core/services/ocr/validate_test.go +++ b/core/services/ocr/validate_test.go @@ -60,9 +60,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -92,7 +90,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true `, assertion: func(t *testing.T, os job.Job, err error) { @@ -108,9 +106,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -136,7 +132,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false `, assertion: func(t *testing.T, os job.Job, err error) { @@ -150,28 +146,11 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false observationSource = """ -> """ -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - }, - }, - { - name: "invalid v1 bootstrap peer address", - toml: ` -type = "offchainreporting" -schemaVersion = 1 -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/invalid/peer/address"] -isBootstrapPeer = false -observationSource = """ -blah -""" `, assertion: func(t *testing.T, os job.Job, err error) { require.Error(t, err) @@ -184,9 +163,6 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] p2pv2Bootstrappers = ["invalid bootstrapper /#@ address"] isBootstrapPeer = false observationSource = """ @@ -204,7 +180,6 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] p2pv2Bootstrappers = [ "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001", ] @@ -225,7 +200,6 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] p2pv2Bootstrappers = [ "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001", ] @@ -246,7 +220,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false observationGracePeriod = "0s" observationSource = """ @@ -264,7 +238,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false contractTransmitterTransmitTimeout = "0s" observationSource = """ @@ -282,7 +256,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false contractConfigTrackerSubscribeInterval = "0s" observationSource = """ @@ -300,13 +274,12 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true monitoringEndpoint = "\t/fd\2ff )(*&^%$#@" `, assertion: func(t *testing.T, os job.Job, err error) { - require.EqualError(t, err, "toml error on load: (9, 23): invalid escape sequence: \\2") + require.EqualError(t, err, "toml error on load: (8, 23): invalid escape sequence: \\2") }, }, { @@ -317,9 +290,7 @@ maxTaskDuration = "30s" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -341,9 +312,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -372,9 +341,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index e576e82967..22a59feb3a 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -318,7 +318,6 @@ func StartNewNode( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 1ab9194c49..58c1e38e01 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -123,7 +123,6 @@ func setupNode( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index e93824283b..4a583e5db3 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -232,7 +232,6 @@ func setupNodeOCR2( c.Feature.LogPoller = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) diff --git a/core/services/ocrcommon/peer_wrapper.go b/core/services/ocrcommon/peer_wrapper.go index a7d510ef90..ff666eefdb 100644 --- a/core/services/ocrcommon/peer_wrapper.go +++ b/core/services/ocrcommon/peer_wrapper.go @@ -2,19 +2,17 @@ package ocrcommon import ( "context" + "crypto/ed25519" "fmt" "io" - "net" p2ppeer "github.com/libp2p/go-libp2p-core/peer" - p2ppeerstore "github.com/libp2p/go-libp2p-core/peerstore" "github.com/pkg/errors" "go.uber.org/multierr" "github.com/jmoiron/sqlx" ocrnetworking "github.com/smartcontractkit/libocr/networking" - ocrnetworkingtypes "github.com/smartcontractkit/libocr/networking/types" ocr1types "github.com/smartcontractkit/libocr/offchainreporting/types" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -67,20 +65,8 @@ type ( ) func ValidatePeerWrapperConfig(config config.P2P) error { - switch config.NetworkStack() { - case ocrnetworking.NetworkingStackV1: - // Note: If P2PListenPort isn't set, the peer wrapper will generate a random one itself. - return nil - case ocrnetworking.NetworkingStackV2: - if len(config.V2().ListenAddresses()) == 0 { - return errors.New("networking stack v2 selected but no P2P.V2.ListenAddresses specified") - } - case ocrnetworking.NetworkingStackV1V2: - if len(config.V2().ListenAddresses()) == 0 { - return errors.New("networking stack v1v2 selected but no P2P.V2.ListenAddresses specified") - } - default: - return errors.New("unknown networking stack") + if len(config.V2().ListenAddresses()) == 0 { + return errors.New("no P2P.V2.ListenAddresses specified") } return nil } @@ -139,70 +125,16 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { } p.PeerID = key.PeerID() - v1 := p.p2pCfg.V1() - p2pPort := v1.ListenPort() - // We need to start the peer store wrapper if v1 is required. - // Also fallback to listen params if announce params not specified. - ns := p.p2pCfg.NetworkStack() - // NewPeer requires that these are both set or unset, otherwise it will error out. - v1AnnounceIP, v1AnnouncePort := v1.AnnounceIP(), v1.AnnouncePort() - var peerStore p2ppeerstore.Peerstore - if ns == ocrnetworking.NetworkingStackV1 || ns == ocrnetworking.NetworkingStackV1V2 { - p.pstoreWrapper, err = NewPeerstoreWrapper(p.db, v1.PeerstoreWriteInterval(), p.PeerID, p.lggr, p.dbConfig) - if err != nil { - return ocrnetworking.PeerConfig{}, errors.Wrap(err, "could not make new pstorewrapper") - } - if err = p.pstoreWrapper.Start(); err != nil { - return ocrnetworking.PeerConfig{}, errors.Wrap(err, "failed to start peer store wrapper") - } - - peerStore = p.pstoreWrapper.Peerstore - - // Use a random port if the port hasn't been set explicitly. - if p2pPort == 0 { - port, perr := p.randomPort() - if perr != nil { - return ocrnetworking.PeerConfig{}, perr - } - p2pPort = port - - p.lggr.Warnw( - fmt.Sprintf("P2PListenPort was not set, listening on random port %d. A new random port will be generated on every boot, for stability it is recommended to set P2PListenPort to a fixed value in your environment", p2pPort), - "p2pPort", - p2pPort, - ) - } - - // Support someone specifying only the announce IP but leaving out - // the port. - // We _should not_ handle the case of someone specifying only the - // port but leaving out the IP, because the listen IP is typically - // an unspecified IP (https://pkg.go.dev/net#IP.IsUnspecified) and - // using that for the announce IP will cause other peers to not be - // able to connect. - if v1AnnounceIP != nil && v1AnnouncePort == 0 { - v1AnnouncePort = p2pPort - } - } - - // Discover DB is only required for v2 - var discovererDB ocrnetworkingtypes.DiscovererDatabase - if ns == ocrnetworking.NetworkingStackV2 || ns == ocrnetworking.NetworkingStackV1V2 { - discovererDB = NewDiscovererDatabase(p.db.DB, p2ppeer.ID(p.PeerID)) - } + discovererDB := NewDiscovererDatabase(p.db.DB, p2ppeer.ID(p.PeerID)) config := p.p2pCfg + pk, err := key.PrivKey.Raw() + if err != nil { + return ocrnetworking.PeerConfig{}, fmt.Errorf("failed to get raw private key: %w", err) + } peerConfig := ocrnetworking.PeerConfig{ - NetworkingStack: config.NetworkStack(), - PrivKey: key.PrivKey, - Logger: commonlogger.NewOCRWrapper(p.lggr, p.ocrCfg.TraceLogging(), func(string) {}), - // V1 config - V1ListenIP: config.V1().ListenIP(), - V1ListenPort: p2pPort, - V1AnnounceIP: v1AnnounceIP, - V1AnnouncePort: v1AnnouncePort, - V1Peerstore: peerStore, - V1DHTAnnouncementCounterUserPrefix: config.V1().DHTAnnouncementCounterUserPrefix(), + PrivKey: ed25519.PrivateKey(pk), + Logger: commonlogger.NewOCRWrapper(p.lggr, p.ocrCfg.TraceLogging(), func(string) {}), // V2 config V2ListenAddresses: config.V2().ListenAddresses(), @@ -211,14 +143,6 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { V2DeltaDial: config.V2().DeltaDial().Duration(), V2DiscovererDatabase: discovererDB, - V1EndpointConfig: ocrnetworking.EndpointConfigV1{ - IncomingMessageBufferSize: config.IncomingMessageBufferSize(), - OutgoingMessageBufferSize: config.OutgoingMessageBufferSize(), - NewStreamTimeout: config.V1().NewStreamTimeout(), - DHTLookupInterval: config.V1().DHTLookupInterval(), - BootstrapCheckInterval: config.V1().BootstrapCheckInterval(), - }, - V2EndpointConfig: ocrnetworking.EndpointConfigV2{ IncomingMessageBufferSize: config.IncomingMessageBufferSize(), OutgoingMessageBufferSize: config.OutgoingMessageBufferSize(), @@ -228,20 +152,6 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { return peerConfig, nil } -func (p *SingletonPeerWrapper) randomPort() (uint16, error) { - addr, err := net.ResolveTCPAddr("tcp", "localhost:0") - if err != nil { - return 0, fmt.Errorf("unexpected ResolveTCPAddr error generating random P2PListenPort: %w", err) - } - l, err := net.ListenTCP("tcp", addr) - if err != nil { - return 0, fmt.Errorf("unexpected ListenTCP error generating random P2PListenPort: %w", err) - } - defer l.Close() - - return uint16(l.Addr().(*net.TCPAddr).Port), nil -} - // Close closes the peer and peerstore func (p *SingletonPeerWrapper) Close() error { return p.StopOnce("SingletonPeerWrapper", func() (err error) { diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index 209bc6b969..854ecb153e 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -1,11 +1,12 @@ package ocrcommon_test import ( + "fmt" "testing" "time" + "github.com/hashicorp/consul/sdk/freeport" p2ppeer "github.com/libp2p/go-libp2p-core/peer" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -17,7 +18,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_SingletonPeerWrapper_Start(t *testing.T) { @@ -30,7 +30,7 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { t.Run("with no p2p keys returns error", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) @@ -39,14 +39,15 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { t.Run("with one p2p key and matching P2P.PeerID returns nil", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) k, err := keyStore.P2P().Create() require.NoError(t, err) cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = ptr(k.PeerID()) }) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) @@ -58,7 +59,7 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { t.Run("with one p2p key and mismatching P2P.PeerID returns error", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pkey.PeerID(peerID)) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) @@ -73,14 +74,16 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { t.Run("with multiple p2p keys and valid P2P.PeerID returns nil", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) k2, err := keyStore.P2P().Create() require.NoError(t, err) cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = ptr(k2.PeerID()) }) @@ -93,7 +96,8 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { t.Run("with multiple p2p keys and mismatching P2P.PeerID returns error", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = ptr(p2pkey.PeerID(peerID)) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) @@ -122,7 +126,6 @@ func Test_SingletonPeerWrapper_Close(t *testing.T) { c.P2P.PeerID = ptr(k.PeerID()) c.P2P.V2.DeltaDial = models.MustNewDuration(100 * time.Millisecond) c.P2P.V2.DeltaReconcile = models.MustNewDuration(1 * time.Second) - c.P2P.V1.ListenPort = ptr[uint16](0) p2paddresses := []string{ "127.0.0.1:17193", @@ -146,75 +149,4 @@ func Test_SingletonPeerWrapper_Close(t *testing.T) { require.NoError(t, pw.Close()) } -func TestSingletonPeerWrapper_PeerConfig(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM encrypted_key_rings`))) - - cfg := configtest.NewGeneralConfig(t, nil) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - k, err := keyStore.P2P().Create() - require.NoError(t, err) - - t.Run("generates a random port if v1 enabled and listen port isn't set", func(t *testing.T) { - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(0)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.NotEqual(t, peerConfig.V1ListenPort, 0) - }) - - t.Run("generates a random port if v1v2 enabled and listen port isn't set", func(t *testing.T) { - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(0)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.NotEqual(t, peerConfig.V1ListenPort, 0) - }) - - t.Run("doesnt generate a port if v2 is enabled", func(t *testing.T) { - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(0)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.NotEqual(t, peerConfig.V1ListenPort, 0) - }) - - t.Run("doesnt override a port if listenport is set", func(t *testing.T) { - portNo := uint16(33247) - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(33247)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.Equal(t, peerConfig.V1ListenPort, portNo) - }) -} - func ptr[T any](t T) *T { return &t } diff --git a/core/store/migrate/migrations/0212_ocr_oracle_specs_drop_p2p_bootstrap_peers.sql b/core/store/migrate/migrations/0212_ocr_oracle_specs_drop_p2p_bootstrap_peers.sql new file mode 100644 index 0000000000..d38370e3f2 --- /dev/null +++ b/core/store/migrate/migrations/0212_ocr_oracle_specs_drop_p2p_bootstrap_peers.sql @@ -0,0 +1,5 @@ +-- +goose Up +ALTER TABLE ocr_oracle_specs DROP COLUMN p2p_bootstrap_peers; + +-- +goose Down +ALTER TABLE ocr_oracle_specs ADD COLUMN p2p_bootstrap_peers text[]; diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index 0ecb85f1e4..00297ebdb1 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -511,10 +511,7 @@ contractAddress = "%s" evmChainID = %s p2pPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" externalJobID = "%s" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5" monitoringEndpoint = "chain.link:4321" diff --git a/core/web/assets/index.html b/core/web/assets/index.html index 601453b4ea..f2257bfbfa 100644 --- a/core/web/assets/index.html +++ b/core/web/assets/index.html @@ -1 +1 @@ -Operator UIChainlink

\ No newline at end of file +Operator UIChainlink
\ No newline at end of file diff --git a/core/web/assets/index.html.gz b/core/web/assets/index.html.gz index 24cc3068f6e66871c3c3479164b48ea3e892d6ee..4d09643ee1b9aebe70088e318891e5418c6f45b6 100644 GIT binary patch literal 418 zcmV;T0bTwdiwFP!000021C^3ZYuqpphX0Bp$f;S&$tGb5mU9RMQV4;zIrKOyjn_)` zVWe3n`|mrpHw%SA=|Ph9TJJL-QgddLp~HZpr{LS>I3w7$2}mGJ54j*|`TFB=wUO#5 zM+m6p=?vuJ z!jQ3)^Q(t0qIfeXM5f)bxkX4xL(F zOm+haiydYy=S7N=4M&2)cVARsOSS24>nn4)zO`KbHEh;5h}Bz>ZKDK@Kos5ljqi|NsoDxlOc+c~KSMyW- M4L7Cb62Jlg09%;KA^-pY literal 420 zcmV;V0bBkbiwFP!000021C^3bZ`3dl#lMQN#EEVk=(bC%I6YKCDiT7X^uTdqPc{bs zi9EAu_uJzn+m(=z5QjMNi{I~!$8O%(WcWCu7&!R0IgJRmZ2~d~Ge9O}EuX%B+I*Di zBu5CS<>c^rOqr!HDKf^g?Aci!w8hC8+$@s|7acqB8#3Tgzn>ZG*kk*3#0;FWczS5m zDmC84Um~N|l7>Py2Ntftr5G~yS`N%3-6}-^%Fhy-!Eoim-n~>2S(S2KoEcSd-NAvA zHYto5iQay=?^6!Ia{)`tpUA$@sM@Er_Xwk-su-0ay6Yi0f7IVnmpI*C*7e1&5Ak zJ+@6uC;3M@h=^zfCxH<x2 diff --git a/core/web/assets/main.b0b6f79f7f4a94560e37.js b/core/web/assets/main.8f602c136d4004a835ee.js similarity index 91% rename from core/web/assets/main.b0b6f79f7f4a94560e37.js rename to core/web/assets/main.8f602c136d4004a835ee.js index 6c9f23d1cc..de75dc2b1c 100644 --- a/core/web/assets/main.b0b6f79f7f4a94560e37.js +++ b/core/web/assets/main.8f602c136d4004a835ee.js @@ -184,4 +184,4 @@ object-assign */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nOB});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(97779),h=n(47886),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(55977),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e5(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e6(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n7.kG)(!!n,32),n}var rb=n(10542),rm=n(53712),rg=n(21436),rv=Object.prototype.hasOwnProperty;function ry(e,t){return void 0===t&&(t=Object.create(null)),rw(rp(t.client),e).useQuery(t)}function rw(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new r_(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var r_=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rb.J)({loading:!0,data:void 0,error:void 0,networkStatus:rc.I.loading}),this.skipStandbyResult=(0,rb.J)({loading:!1,data:void 0,error:void 0,networkStatus:rc.I.ready}),this.toQueryResultCache=new(re.mr?WeakMap:Map),rh(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n7.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,rs.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rn((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ra.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rv.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ra.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:rc.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ra.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rm.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ro.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,n8._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n7.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rg.O)(e.errors)?new ru.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,n8._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,n8.pi)((0,n8.pi)((0,n8.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rg.O)(e.errors)&&(t.error=new ru.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:rc.I.refetch}),this.observable.refetch())},e}();function rE(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return ry(i$,e)},iG=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=iz({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(ij,null):o?l.createElement(iN,{error:o}):i?l.createElement(iD,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iW=n(67932),iK=n(8126),iV="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iq(e){if(iZ())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iZ(){return("undefined"==typeof Intl?"undefined":iV(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iX="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iJ=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iX(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iX(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i0=i1;var i2=new i0;function i3(e,t){if(!iZ())return function(e){return e.toString()};var n=i5(e),r=JSON.stringify(t),i=i2.get(String(n),r)||i2.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i4={};function i5(e){var t=e.toString();return i4[t]?i4[t]:i4[t]=iq(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i9(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i7(e)}function i7(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var ae=n(54087),at=n.n(ae);function an(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)ao(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=at()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){at().cancel(this.scheduledTick)}};function aa(e){var t=ar(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function ao(e,t){aa(e),au(t,e),as(t,e)}function as(e,t){var n=ac(e,t);e.splice(n,0,t)}function au(e,t){var n=e.indexOf(t);e.splice(n,1)}function ac(e,t){var n=t.nextUpdateTime;return an(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var al=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),af=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(al).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),ad=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ab(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ap(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iK.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iK.Z(y)},[y]);t=(0,l.useMemo)(function(){return i9(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ah(u,2),l=c[0],f=c[1];return f=o?av:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ah(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ah(M,2),A=O[0],L=O[1],C=ah((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ai.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ah(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i3(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,ad({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,ad({},f,{verboseDate:I?R:void 0}),j):j}ab.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:af,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ab.defaultProps={locales:[],component:ay,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ab=l.memo(ab);let am=ab;var ag,av=31536e9;function ay(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ap(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",ad({},a,{dateTime:o,title:r?n:void 0}),i)}ay.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var aw=n(30381),a_=n.n(aw),aE=n(31657);function aS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ak(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new ru.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ra.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ra.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,n8.pi)({reset:c},a)]}var ou=n(59067),oc=n(28428),ol=n(11186),of=n(78513);function od(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var oh=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:od({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},op=(0,b.withStyles)(oh)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ia.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),ob=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},om=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},og=(0,b.withStyles)(oh)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function ov(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sZ=sq;function sX(e,t){var n=this.__data__,r=s$(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sJ=sX;function sQ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cI}let cN=cD;var cP="[object Arguments]",cR="[object Array]",cj="[object Boolean]",cF="[object Date]",cY="[object Error]",cB="[object Function]",cU="[object Map]",cH="[object Number]",c$="[object Object]",cz="[object RegExp]",cG="[object Set]",cW="[object String]",cK="[object WeakMap]",cV="[object ArrayBuffer]",cq="[object DataView]",cZ="[object Float64Array]",cX="[object Int8Array]",cJ="[object Int16Array]",cQ="[object Int32Array]",c1="[object Uint8Array]",c0="[object Uint8ClampedArray]",c2="[object Uint16Array]",c3="[object Uint32Array]",c4={};function c5(e){return eD(e)&&cN(e.length)&&!!c4[eC(e)]}c4["[object Float32Array]"]=c4[cZ]=c4[cX]=c4[cJ]=c4[cQ]=c4[c1]=c4[c0]=c4[c2]=c4[c3]=!0,c4[cP]=c4[cR]=c4[cV]=c4[cj]=c4[cq]=c4[cF]=c4[cY]=c4[cB]=c4[cU]=c4[cH]=c4[c$]=c4[cz]=c4[cG]=c4[cW]=c4[cK]=!1;let c6=c5;function c9(e){return function(t){return e(t)}}let c8=c9;var c7=n(79730),le=c7.Z&&c7.Z.isTypedArray,lt=le?c8(le):c6;let ln=lt;var lr=Object.prototype.hasOwnProperty;function li(e,t){var n=cT(e),r=!n&&ck(e),i=!n&&!r&&(0,cM.Z)(e),a=!n&&!r&&!i&&ln(e),o=n||r||i||a,s=o?cm(e.length,String):[],u=s.length;for(var c in e)(t||lr.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cC(c,u)))&&s.push(c);return s}let la=li;var lo=Object.prototype;function ls(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||lo)}let lu=ls;var lc=sM(Object.keys,Object);let ll=lc;var lf=Object.prototype.hasOwnProperty;function ld(e){if(!lu(e))return ll(e);var t=[];for(var n in Object(e))lf.call(e,n)&&"constructor"!=n&&t.push(n);return t}let lh=ld;function lp(e){return null!=e&&cN(e.length)&&!ui(e)}let lb=lp;function lm(e){return lb(e)?la(e):lh(e)}let lg=lm;function lv(e,t){return e&&cp(t,lg(t),e)}let ly=lv;function lw(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let l_=lw;var lE=Object.prototype.hasOwnProperty;function lS(e){if(!ed(e))return l_(e);var t=lu(e),n=[];for(var r in e)"constructor"==r&&(t||!lE.call(e,r))||n.push(r);return n}let lk=lS;function lx(e){return lb(e)?la(e,!0):lk(e)}let lT=lx;function lM(e,t){return e&&cp(t,lT(t),e)}let lO=lM;var lA=n(42896);function lL(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hc(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hl=function(e){return Array.isArray(e)&&0===e.length},hf=function(e){return"function"==typeof e},hd=function(e){return null!==e&&"object"==typeof e},hh=function(e){return String(Math.floor(Number(e)))===e},hp=function(e){return"[object String]"===Object.prototype.toString.call(e)},hb=function(e){return 0===l.Children.count(e)},hm=function(e){return hd(e)&&hf(e.then)};function hg(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hy(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hg(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hv(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sx.all([t,n,r],{arrayMerge:hC})})},[h.validate,h.validationSchema,T,S,k]),O=hP(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sh()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sh()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hm(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sh()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hk,E({type:"SET_ERRORS",payload:h.initialErrors||hk}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hx,E({type:"SET_TOUCHED",payload:h.initialTouched||hx}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hP(function(e){if(y.current[e]&&hf(y.current[e].validate)){var t=hg(_.values,e),n=y.current[e].validate(t);return hm(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hP(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hP(function(e,t){var r=hf(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hP(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hv(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hp(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hD(hg(_.values,r),l,c):d?hI(f):c}r&&j(r,i)},[j,_.values]),Y=hP(function(e){if(hp(e))return function(t){return F(t,e)};F(e)}),B=hP(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hP(function(e){if(hp(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hf(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hP(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hP(function(){return f(_.values,V)}),Z=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hg(_.values,e),error:hg(_.errors,e),touched:!!hg(_.touched,e),initialValue:hg(p.current,e),initialTouched:!!hg(m.current,e),initialError:hg(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hd(e),n=t?e.name:e,r=hg(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sh()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hf(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ho({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hM(e){var t=hT(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(h_,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hf(r)?r(t):hb(r)?null:l.Children.only(r):null)}function hO(e){var t={};if(e.inner){if(0===e.inner.length)return hv(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hg(t,o.path)||(t=hv(t,o.path,o.message))}}return t}function hA(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hL(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hL(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sj(e)?hL(e):""!==e?e:void 0}):sj(e[r])?t[r]=hL(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hC(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sx(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sx(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hI(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hD(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hN="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hP(e){var t=(0,l.useRef)(e);return hN(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ho({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hv(n.values,a,e(hg(n.values,a))),u=r?i(hg(n.errors,a)):void 0,c=t?o(hg(n.touched,a)):void 0;return hl(u)&&(u=void 0),hl(c)&&(c=void 0),ho({},n,{values:s,errors:r?hv(n.errors,a,u):n.errors,touched:t?hv(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hH(t),[ha(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},function(t){return hB(t,e,null)},function(t){return hB(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hU(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hc(n)),n.pop=n.pop.bind(hc(n)),n}hs(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sh()(hg(e.formik.values,e.name),hg(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hH(n):[];return t||(t=r[e]),hf(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hu(t.formik,["validate","validationSchema"]),s=ho({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hb(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var h$=n(24802),hz=n(71209),hG=n(91750),hW=n(11970),hK=n(4689),hV=n(67598),hq=function(){return(hq=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hX(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hZ(e,["disabled","field","form","onBlur","helperText"]),d=hg(u,i.name),h=hg(s,i.name)&&!!d;return hq(hq({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hJ(e){var t=e.children,n=hZ(e,["children"]);return(0,l.createElement)(i_.Z,hq({},hX(n)),t)}function hQ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h1(e){return(0,l.createElement)(h$.Z,hq({},hQ(e)))}function h0(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hZ(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h2(e){return(0,l.createElement)(hz.Z,hq({},h0(e)))}function h3(e){var t=e.Label,n=hZ(e,["Label"]);return(0,l.createElement)(hG.Z,hq({control:(0,l.createElement)(hz.Z,hq({},h0(n)))},t))}function h4(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h5(e){return(0,l.createElement)(hW.default,hq({},h4(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hZ(t,["onBlur"]),i=(e.form,e.onBlur),a=hZ(e,["field","form","onBlur"]);return hq(hq({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h9(e){return(0,l.createElement)(hK.Z,hq({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h7(e){return(0,l.createElement)(hV.default,hq({},h8(e)))}hJ.displayName="FormikMaterialUITextField",h1.displayName="FormikMaterialUISwitch",h2.displayName="FormikMaterialUICheckbox",h3.displayName="FormikMaterialUICheckboxWithLabel",h5.displayName="FormikMaterialUISelect",h9.displayName="FormikMaterialUIRadioGroup",h7.displayName="FormikMaterialUIInputBase";try{a=Map}catch(pe){}try{o=Set}catch(pt){}function pn(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pr);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pn(e[i],t,n)}return r}return e}function pr(e){return pn(e,[],[])}let pi=Object.prototype.toString,pa=Error.prototype.toString,po=RegExp.prototype.toString,ps="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",pu=/^Symbol\((.*)\)(.*)$/;function pc(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pl(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pc(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return ps.call(e).replace(pu,"Symbol($1)");let r=pi.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pa.call(e)+"]":"RegExp"===r?po.call(e):null}function pf(e,t){let n=pl(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pl(this[e],t);return null!==r?r:n},2)}let pd={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pf(n,!0)}\``+(i?` (cast from the value \`${pf(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},ph={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},pp={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pb={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pm={isValue:"${path} field must be ${value}"},pg={noUnknown:"${path} field has unspecified keys: ${unknown}"},pv={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pd,string:ph,number:pp,date:pb,object:pg,array:pv,boolean:pm});var py=n(18721),pw=n.n(py);let p_=e=>e&&e.__isYupSchema__;class pE{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!pw()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!p_(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pS=pE;function pk(e){return null==e?[]:[].concat(e)}function px(){return(px=Object.assign||function(e){for(var t=1;tpf(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pk(e).forEach(e=>{pM.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pM)}}let pO=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pA(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pO(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pM(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pj(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pR(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pN.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pC()(pP({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pM(pM.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pP({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pM.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pM.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pN.prototype.__isYupRef=!0;let pF=e=>e.substr(0,e.length-1).substr(1);function pY(e,t,n,r=n){let i,a,o;return t?((0,pI.forEach)(t,(s,u,c)=>{let l=u?pF(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pB{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pN.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pN.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pB;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pU(){return(pU=Object.assign||function(e){for(var t=1;t{this.typeError(pd.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pU({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pU({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pr(pU({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pU({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pU({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pf(e),a=pf(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". attempted value: ${i} -`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566),gb=n(68239);function gm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gg(){var e=gm(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gg=function(){return e},e}var gv=function(){var e="[[TelemetryIngress.Endpoints]] \nNetwork = '...' # e.g. EVM. Solana, Starknet, Cosmos \nChainID = '...' # e.g. 1, 5, devnet, mainnet-beta URL\nURL = '...'\nServerPubKey = '...'";return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Deprecation warning"}),l.createElement(aK.Z,null,l.createElement(x.default,{variant:"h5",gutterBottom:!0},"Starting in ",l.createElement("code",null,"v2.9.0"),":"),l.createElement(w.default,{dense:!0},l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"TelemetryIngress.URL")," and"," ",l.createElement("code",null,"TelemetryIngress.ServerPubKey")," will no longer be allowed. Please switch to ",l.createElement("code",null,"TelemetryIngress.Endpoints"),":",l.createElement(gh,{language:"toml",style:gu},e))),l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"P2P.V1")," will no longer be supported and must not be set in TOML configuration in order to boot. Use"," ",l.createElement("code",null,"P2P.V2")," instead. If you are using both,"," ",l.createElement("code",null,"V1")," can simply be removed.")))))},gy=n0(gg()),gw=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},g_=function(){return l.createElement(gw,null,"...")},gE=function(e){var t=e.children;return l.createElement(gw,null,t)},gS=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gE,null,i);if(t)return l.createElement(g_,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gk=function(){var e=ry(gy,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gv,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(gS,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gx=n(34823),gT=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gM=(0,b.withStyles)(gT)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gx.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gO=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gk,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gM,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gA=function(){return l.createElement(gO,null)},gL=function(){return l.createElement(gA,null)},gC=n(44431),gI=1e18,gD=function(e){return new gC.BigNumber(e).dividedBy(gI).toFixed(8)},gN=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gD(e.linkBalance):"--"}))))})),r+1s&&l.createElement(g$.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vi(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function va(){var e=vi(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return va=function(){return e},e}var vo=5,vs=n0(va(),vt),vu=function(){var e=ry(vs,{variables:{offset:0,limit:vo},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vr,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vo})},vc=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=(0,A.v9)(gx.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vf=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vd=(0,b.withStyles)(vf)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vp(){var e=vh(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vp=function(){return e},e}var vb=n0(vp()),vm=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vg=(0,b.withStyles)(vm)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gz,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vd,{job:e,key:t})}))))});function vv(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vy(){var e=vv(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vy=function(){return e},e}var vw=5,v_=n0(vy(),vb),vE=function(){var e=ry(v_,{variables:{offset:0,limit:vw},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vg,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},vS=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vu,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gH,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vE,null))))),l.createElement(vl,null))},vk=function(){return l.createElement(vS,null)},vx=function(){return l.createElement(vk,null)},vT=n(87239),vM=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vO=n(5022),vA=n(78718),vL=n.n(vA);function vC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,ym(t,e.status))},e.status.toLowerCase())))})))}),yv=n(16839),yy=n.n(yv);function yw(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yy().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var y_=n(94164),yE=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},yS=n(73343),yk=n(3379),yx=n.n(yk);function yT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(y_.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:yS.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yE,{data:e}))}))};function yD(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyH&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yU,{observationSource:n.observationSource})))});function yG(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vO.parse(e),!0}catch(t){return!1}})}),wq=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wV,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wZ=n(50109),wX="persistSpec";function wJ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wZ.t8(wX,n),{toml:n}):{toml:wZ.U2(wX)||""}}var wQ=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wJ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wZ.t8("".concat(wX),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wq,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function w1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _L(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_q,e)},_X=function(){var e=_Z({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_z,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_J=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_O,{data:t.publicKey}))))};function _Q(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _1(){var e=_Q(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _1=function(){return e},e}var _0=n0(_1()),_2=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gz,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_J,{csaKey:e,key:t})}))))};function _3(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EL,e)};function EI(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(E0,e)},E6=function(){return os(E2)},E9=function(){return os(E3)},E8=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E4,e)};function E7(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SZ,e)};function SJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kX(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kJ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kZ(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kq(kK({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(kG,{object:n})))};function kQ(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function k1(e){for(var t=1;t0&&l.createElement(ko,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kJ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kj,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k7(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xe(){var e=k7(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return xe=function(){return e},e}var xt=n0(xe(),k9),xn=function(){var e=ry(xt,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k8,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xr(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xi(){var e=xr(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xi=function(){return e},e}var xa=n0(xi()),xo=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yg,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xs(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xu(){var e=xs(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xu=function(){return e},e}var xc=n0(xu(),xa),xl=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xc,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xo,{loading:a,data:i,page:t,pageSize:n})},xf=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xl,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xn,null)))},xd=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xh=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xd,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xp=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:r,onSubmit:n})))))};function xb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xm(){var e=xb(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xm=function(){return e},e}var xg=n0(xm()),xv=function(){return ry(xg)};function xy(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xJ,e)};function x1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(Tz,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},TW={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TK=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:TW,onSubmit:t})))))};function TV(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mm(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(El.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?M_[c.action].title:"",body:c?M_[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mo,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function MS(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function Mk(){var e=MS(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return Mk=function(){return e},e}var Mx=n0(Mk(),My),MT=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(Me,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(T$,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ME,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function MM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file +`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566),gb=n(68239);function gm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gg(){var e=gm(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gg=function(){return e},e}var gv=function(){var e="[[TelemetryIngress.Endpoints]] \nNetwork = '...' # e.g. EVM. Solana, Starknet, Cosmos \nChainID = '...' # e.g. 1, 5, devnet, mainnet-beta URL\nURL = '...'\nServerPubKey = '...'";return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Deprecation warning"}),l.createElement(aK.Z,null,l.createElement(x.default,{variant:"h5",gutterBottom:!0},"Starting in ",l.createElement("code",null,"v2.9.0"),":"),l.createElement(w.default,{dense:!0},l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"TelemetryIngress.URL")," and"," ",l.createElement("code",null,"TelemetryIngress.ServerPubKey")," will no longer be allowed. Please switch to ",l.createElement("code",null,"TelemetryIngress.Endpoints"),":",l.createElement(gh,{language:"toml",style:gu},e))),l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"P2P.V1")," will no longer be supported and must not be set in TOML configuration in order to boot. Use"," ",l.createElement("code",null,"P2P.V2")," instead. If you are using both,"," ",l.createElement("code",null,"V1")," can simply be removed.")))))},gy=n0(gg()),gw=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},g_=function(){return l.createElement(gw,null,"...")},gE=function(e){var t=e.children;return l.createElement(gw,null,t)},gS=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gE,null,i);if(t)return l.createElement(g_,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gk=function(){var e=ry(gy,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gv,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(gS,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gx=n(34823),gT=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gM=(0,b.withStyles)(gT)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gx.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gO=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gk,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gM,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gA=function(){return l.createElement(gO,null)},gL=function(){return l.createElement(gA,null)},gC=n(44431),gI=1e18,gD=function(e){return new gC.BigNumber(e).dividedBy(gI).toFixed(8)},gN=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gD(e.linkBalance):"--"}))))})),r+1s&&l.createElement(g$.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vi(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function va(){var e=vi(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return va=function(){return e},e}var vo=5,vs=n0(va(),vt),vu=function(){var e=ry(vs,{variables:{offset:0,limit:vo},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vr,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vo})},vc=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=(0,A.v9)(gx.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vf=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vd=(0,b.withStyles)(vf)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vp(){var e=vh(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vp=function(){return e},e}var vb=n0(vp()),vm=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vg=(0,b.withStyles)(vm)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gz,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vd,{job:e,key:t})}))))});function vv(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vy(){var e=vv(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vy=function(){return e},e}var vw=5,v_=n0(vy(),vb),vE=function(){var e=ry(v_,{variables:{offset:0,limit:vw},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vg,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},vS=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vu,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gH,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vE,null))))),l.createElement(vl,null))},vk=function(){return l.createElement(vS,null)},vx=function(){return l.createElement(vk,null)},vT=n(87239),vM=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vO=n(5022),vA=n(78718),vL=n.n(vA);function vC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,ym(t,e.status))},e.status.toLowerCase())))})))}),yv=n(16839),yy=n.n(yv);function yw(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yy().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var y_=n(94164),yE=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},yS=n(73343),yk=n(3379),yx=n.n(yk);function yT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(y_.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:yS.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yE,{data:e}))}))};function yD(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyH&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yU,{observationSource:n.observationSource})))});function yG(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vO.parse(e),!0}catch(t){return!1}})}),wq=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wV,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wZ=n(50109),wX="persistSpec";function wJ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wZ.t8(wX,n),{toml:n}):{toml:wZ.U2(wX)||""}}var wQ=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wJ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wZ.t8("".concat(wX),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wq,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function w1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _L(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_q,e)},_X=function(){var e=_Z({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_z,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_J=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_O,{data:t.publicKey}))))};function _Q(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _1(){var e=_Q(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _1=function(){return e},e}var _0=n0(_1()),_2=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gz,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_J,{csaKey:e,key:t})}))))};function _3(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EL,e)};function EI(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(E0,e)},E6=function(){return os(E2)},E9=function(){return os(E3)},E8=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E4,e)};function E7(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SZ,e)};function SJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kX(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kJ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kZ(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kq(kK({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(kG,{object:n})))};function kQ(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function k1(e){for(var t=1;t0&&l.createElement(ko,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kJ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kj,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k7(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xe(){var e=k7(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return xe=function(){return e},e}var xt=n0(xe(),k9),xn=function(){var e=ry(xt,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k8,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xr(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xi(){var e=xr(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xi=function(){return e},e}var xa=n0(xi()),xo=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yg,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xs(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xu(){var e=xs(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xu=function(){return e},e}var xc=n0(xu(),xa),xl=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xc,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xo,{loading:a,data:i,page:t,pageSize:n})},xf=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xl,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xn,null)))},xd=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xh=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xd,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xp=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:r,onSubmit:n})))))};function xb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xm(){var e=xb(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xm=function(){return e},e}var xg=n0(xm()),xv=function(){return ry(xg)};function xy(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xJ,e)};function x1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(Tz,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},TW={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TK=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:TW,onSubmit:t})))))};function TV(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mm(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(El.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?M_[c.action].title:"",body:c?M_[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mo,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function MS(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function Mk(){var e=MS(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return Mk=function(){return e},e}var Mx=n0(Mk(),My),MT=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(Me,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(T$,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ME,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function MM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file diff --git a/core/web/assets/main.b0b6f79f7f4a94560e37.js.gz b/core/web/assets/main.8f602c136d4004a835ee.js.gz similarity index 93% rename from core/web/assets/main.b0b6f79f7f4a94560e37.js.gz rename to core/web/assets/main.8f602c136d4004a835ee.js.gz index c505ea9eeade9a8933c1cc213f6e6d36bc873d85..fceb7ce3cbe253bc309228ad9e7047001c11ebe5 100644 GIT binary patch delta 77848 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 q7&!1oMM3noy>#<`BbQBrcE@x{C_qD~{ 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 delta 77867 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 Date: Mon, 4 Dec 2023 11:27:30 -0800 Subject: [PATCH 269/327] Revert "make streams lookup modular (#11368)" (#11482) This reverts commit fa0f16ad0acf417db1186728560278a049357914. --- core/scripts/chaincli/handler/debug.go | 150 ++--- .../handler/mercury_lookup_handler.go | 534 ++++++++++++++++++ core/scripts/go.mod | 3 +- core/scripts/go.sum | 2 + .../v21/mercury/streams/streams.go | 143 +++-- .../v21/mercury/streams/streams_test.go | 20 +- 6 files changed, 666 insertions(+), 186 deletions(-) create mode 100644 core/scripts/chaincli/handler/mercury_lookup_handler.go diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 0075862d95..fec8c6cd41 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -22,17 +22,12 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" - "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" @@ -41,7 +36,12 @@ import ( const ( ConditionTrigger uint8 = iota LogTrigger + + blockNumber = "blockNumber" expectedTypeAndVersion = "KeeperRegistry 2.1.0" + feedIdHex = "feedIdHex" + feedIDs = "feedIDs" + timestamp = "timestamp" ) var packer = encoding.NewAbiPacker() @@ -125,8 +125,6 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { var checkResult iregistry21.CheckUpkeep var blockNum uint64 var performData []byte - var workID [32]byte - var trigger ocr2keepers.Trigger upkeepNeeded := false // check upkeep if triggerType == ConditionTrigger { @@ -179,8 +177,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } // check that tx for this upkeep / tx was not already performed message(fmt.Sprintf("LogTrigger{blockNum: %d, blockHash: %s, txHash: %s, logIndex: %d}", blockNum, receipt.BlockHash.Hex(), txHash, logIndex)) - trigger = mustAutomationTrigger(txHash, logIndex, blockNum, receipt.BlockHash) - workID = mustUpkeepWorkID(upkeepID, trigger) + workID := mustUpkeepWorkID(upkeepID, blockNum, receipt.BlockHash, txHash, logIndex) message(fmt.Sprintf("workID computed: %s", hex.EncodeToString(workID[:]))) hasKey, err := keeperRegistry21.HasDedupKey(latestCallOpts, workID) if err != nil { @@ -232,82 +229,73 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if checkResult.UpkeepFailureReason != 0 { message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) } - if checkResult.UpkeepFailureReason == uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { - mc := &models.MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey} - mercuryConfig := evm21.NewMercuryConfig(mc, core.StreamsCompatibleABI) - lggr, _ := logger.NewLogger() - blockSub := &blockSubscriber{k.client} - streams := streams.NewStreamsLookup(packer, mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr) + // TODO use the new streams lookup lib + //mc := &models.MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey} + //mercuryConfig := evm.NewMercuryConfig(mc, core.StreamsCompatibleABI) + //lggr, _ := logger.NewLogger() + //blockSub := &blockSubscriber{k.client} + //_ = streams.NewStreamsLookup(packer, mercuryConfig, blockSub, keeperRegistry21, k.rpcClient, lggr) streamsLookupErr, err := packer.DecodeStreamsLookupRequest(checkResult.PerformData) if err == nil { message("upkeep reverted with StreamsLookup") message(fmt.Sprintf("StreamsLookup data: {FeedParamKey: %s, Feeds: %v, TimeParamKey: %s, Time: %d, ExtraData: %s}", streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time.Uint64(), hexutil.Encode(streamsLookupErr.ExtraData))) - - streamsLookup := &mercury.StreamsLookup{ - StreamsLookupError: &mercury.StreamsLookupError{ - FeedParamKey: streamsLookupErr.FeedParamKey, - Feeds: streamsLookupErr.Feeds, - TimeParamKey: streamsLookupErr.TimeParamKey, - Time: streamsLookupErr.Time, - ExtraData: streamsLookupErr.ExtraData, - }, - UpkeepId: upkeepID, - Block: blockNum, - } - - if streamsLookup.IsMercuryV02() { + if streamsLookupErr.FeedParamKey == feedIdHex && streamsLookupErr.TimeParamKey == blockNumber { message("using mercury lookup v0.2") - // check if upkeep is allowed to use mercury v0.2 - _, _, _, allowed, err := streams.AllowedToUseMercury(latestCallOpts, upkeepID) + // handle v0.2 + cfg, err := keeperRegistry21.GetUpkeepPrivilegeConfig(triggerCallOpts, upkeepID) if err != nil { - failUnknown("failed to check if upkeep is allowed to use mercury", err) + failUnknown("failed to get upkeep privilege config ", err) + } + allowed := false + if len(cfg) > 0 { + var privilegeConfig streams.UpkeepPrivilegeConfig + if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { + failUnknown("failed to unmarshal privilege config ", err) + } + allowed = privilegeConfig.MercuryEnabled } if !allowed { resolveIneligible("upkeep reverted with StreamsLookup but is not allowed to access streams") } - } else if streamsLookup.IsMercuryV03() { + } else if streamsLookupErr.FeedParamKey != feedIDs || streamsLookupErr.TimeParamKey != timestamp { // handle v0.3 - message("using mercury lookup v0.3") - } else { resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") + } else { + message("using mercury lookup v0.3") } + streamsLookup := &StreamsLookup{streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time, streamsLookupErr.ExtraData, upkeepID, blockNum} if k.cfg.MercuryLegacyURL == "" || k.cfg.MercuryURL == "" || k.cfg.MercuryID == "" || k.cfg.MercuryKey == "" { failCheckConfig("Mercury configs not set properly, check your MERCURY_LEGACY_URL, MERCURY_URL, MERCURY_ID and MERCURY_KEY", nil) } - - // do mercury request - automationCheckResult := mustAutomationCheckResult(upkeepID, checkResult, trigger) - values, err := streams.DoMercuryRequest(ctx, streamsLookup, &automationCheckResult) - - if automationCheckResult.IneligibilityReason == uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) { + handler := NewMercuryLookupHandler(&MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey}, k.rpcClient) + state, failureReason, values, _, err := handler.doMercuryRequest(ctx, streamsLookup) + if failureReason == UpkeepFailureReasonInvalidRevertDataInput { resolveIneligible("upkeep used invalid revert data") } - if automationCheckResult.PipelineExecutionState == uint8(mercury.InvalidMercuryRequest) { + if state == InvalidMercuryRequest { resolveIneligible("the mercury request data is invalid") } if err != nil { - resolveIneligible("failed to DoMercuryRequest") + failCheckConfig("failed to do mercury request ", err) } - - // do checkCallback - err = streams.CheckCallback(ctx, values, streamsLookup, &automationCheckResult) + callbackResult, err := keeperRegistry21.CheckCallback(triggerCallOpts, upkeepID, values, streamsLookup.extraData) if err != nil { failUnknown("failed to execute mercury callback ", err) } - if automationCheckResult.IneligibilityReason != 0 { - message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", automationCheckResult.IneligibilityReason)) + if callbackResult.UpkeepFailureReason != 0 { + message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) } - upkeepNeeded, performData = automationCheckResult.Eligible, automationCheckResult.PerformData - // do tenderly simulations for checkCallback - rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.ExtraData) + upkeepNeeded, performData = callbackResult.UpkeepNeeded, callbackResult.PerformData + // do tenderly simulations + rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.extraData) if err != nil { failUnknown("failed to pack raw checkCallback call", err) } addLink("checkCallback simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) - rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.ExtraData) + rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.extraData) if err != nil { failUnknown("failed to pack raw checkCallback (direct) call", err) } @@ -329,23 +317,6 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } } -func mustAutomationCheckResult(upkeepID *big.Int, checkResult iregistry21.CheckUpkeep, trigger ocr2keepers.Trigger) ocr2keepers.CheckResult { - upkeepIdentifier := mustUpkeepIdentifier(upkeepID) - checkResult2 := ocr2keepers.CheckResult{ - Eligible: checkResult.UpkeepNeeded, - IneligibilityReason: checkResult.UpkeepFailureReason, - UpkeepID: upkeepIdentifier, - Trigger: trigger, - WorkID: core.UpkeepWorkID(upkeepIdentifier, trigger), - GasAllocated: 0, - PerformData: checkResult.PerformData, - FastGasWei: checkResult.FastGasWei, - LinkNative: checkResult.LinkNative, - } - - return checkResult2 -} - type blockSubscriber struct { ethClient *ethclient.Client } @@ -399,27 +370,9 @@ func packTriggerData(log *types.Log, blockTime uint64) ([]byte, error) { return b, nil } -func mustUpkeepWorkID(upkeepID *big.Int, trigger ocr2keepers.Trigger) [32]byte { - upkeepIdentifier := mustUpkeepIdentifier(upkeepID) - - workID := core.UpkeepWorkID(upkeepIdentifier, trigger) - workIDBytes, err := hex.DecodeString(workID) - if err != nil { - failUnknown("failed to decode workID", err) - } - - var result [32]byte - copy(result[:], workIDBytes[:]) - return result -} - -func mustUpkeepIdentifier(upkeepID *big.Int) ocr2keepers.UpkeepIdentifier { - upkeepIdentifier := &ocr2keepers.UpkeepIdentifier{} - upkeepIdentifier.FromBigInt(upkeepID) - return *upkeepIdentifier -} - -func mustAutomationTrigger(txHash [32]byte, logIndex int64, blockNum uint64, blockHash [32]byte) ocr2keepers.Trigger { +func mustUpkeepWorkID(upkeepID *big.Int, blockNum uint64, blockHash [32]byte, txHash [32]byte, logIndex int64) [32]byte { + // TODO - this is a copy of the code in core.UpkeepWorkID + // We should refactor that code to be more easily exported ex not rely on Trigger structs trigger := ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ TxHash: txHash, @@ -428,7 +381,16 @@ func mustAutomationTrigger(txHash [32]byte, logIndex int64, blockNum uint64, blo BlockHash: blockHash, }, } - return trigger + upkeepIdentifier := &ocr2keepers.UpkeepIdentifier{} + upkeepIdentifier.FromBigInt(upkeepID) + workID := core.UpkeepWorkID(*upkeepIdentifier, trigger) + workIDBytes, err := hex.DecodeString(workID) + if err != nil { + failUnknown("failed to decode workID", err) + } + var result [32]byte + copy(result[:], workIDBytes[:]) + return result } func message(msg string) { @@ -440,11 +402,11 @@ func warning(msg string) { } func resolveIneligible(msg string) { - exit(fmt.Sprintf("✅ %s: this upkeep is not currently eligible", msg), nil, 0) + exit(fmt.Sprintf("✅ %s: this upkeep is not currently elligible", msg), nil, 0) } func resolveEligible() { - exit("❌ this upkeep is currently eligible", nil, 0) + exit("❌ this upkeep is currently elligible", nil, 0) } func rerun(msg string, err error) { @@ -545,3 +507,5 @@ func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, inpu } return common.TenderlySimLink(responseJSON.Simulation.Id) } + +// TODO - link to performUpkeep tx if exists diff --git a/core/scripts/chaincli/handler/mercury_lookup_handler.go b/core/scripts/chaincli/handler/mercury_lookup_handler.go new file mode 100644 index 0000000000..1bd4b2e183 --- /dev/null +++ b/core/scripts/chaincli/handler/mercury_lookup_handler.go @@ -0,0 +1,534 @@ +package handler + +import ( + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/avast/retry-go" + ethabi "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/pkg/errors" +) + +// MercuryLookupHandler is responsible for initiating the calls to the Mercury server +// to determine whether the upkeeps are eligible +type MercuryLookupHandler struct { + credentials *MercuryCredentials + httpClient HttpClient + rpcClient *rpc.Client +} + +func NewMercuryLookupHandler( + credentials *MercuryCredentials, + rpcClient *rpc.Client, +) *MercuryLookupHandler { + return &MercuryLookupHandler{ + credentials: credentials, + httpClient: http.DefaultClient, + rpcClient: rpcClient, + } +} + +type MercuryVersion string + +type StreamsLookup struct { + feedParamKey string + feeds []string + timeParamKey string + time *big.Int + extraData []byte + upkeepId *big.Int + block uint64 +} + +//go:generate mockery --quiet --name HttpClient --output ./mocks/ --case=underscore +type HttpClient interface { + Do(req *http.Request) (*http.Response, error) +} + +type MercuryCredentials struct { + LegacyURL string + URL string + ClientID string + ClientKey string +} + +func (mc *MercuryCredentials) Validate() bool { + return mc.URL != "" && mc.ClientID != "" && mc.ClientKey != "" +} + +type MercuryData struct { + Index int + Error error + Retryable bool + Bytes [][]byte + State PipelineExecutionState +} + +// MercuryV02Response represents a JSON structure used by Mercury v0.2 +type MercuryV02Response struct { + ChainlinkBlob string `json:"chainlinkBlob"` +} + +// MercuryV03Response represents a JSON structure used by Mercury v0.3 +type MercuryV03Response struct { + Reports []MercuryV03Report `json:"reports"` +} + +type MercuryV03Report struct { + FeedID string `json:"feedID"` // feed id in hex encoded + ValidFromTimestamp uint32 `json:"validFromTimestamp"` + ObservationsTimestamp uint32 `json:"observationsTimestamp"` + FullReport string `json:"fullReport"` // the actual hex encoded mercury report of this feed, can be sent to verifier +} + +const ( + // DefaultAllowListExpiration decides how long an upkeep's allow list info will be valid for. + DefaultAllowListExpiration = 20 * time.Minute + // CleanupInterval decides when the expired items in cache will be deleted. + CleanupInterval = 25 * time.Minute +) + +const ( + ApplicationJson = "application/json" + BlockNumber = "blockNumber" // valid for v0.2 + FeedIDs = "feedIDs" // valid for v0.3 + FeedIdHex = "feedIdHex" // valid for v0.2 + HeaderAuthorization = "Authorization" + HeaderContentType = "Content-Type" + HeaderTimestamp = "X-Authorization-Timestamp" + HeaderSignature = "X-Authorization-Signature-SHA256" + HeaderUpkeepId = "X-Authorization-Upkeep-Id" + MercuryPathV2 = "/client?" // only used to access mercury v0.2 server + MercuryBatchPathV3 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server + RetryDelay = 500 * time.Millisecond + Timestamp = "timestamp" // valid for v0.3 + TotalAttempt = 3 + UserId = "userId" +) + +type UpkeepFailureReason uint8 +type PipelineExecutionState uint8 + +const ( + // upkeep failure onchain reasons + UpkeepFailureReasonNone UpkeepFailureReason = 0 + UpkeepFailureReasonUpkeepCancelled UpkeepFailureReason = 1 + UpkeepFailureReasonUpkeepPaused UpkeepFailureReason = 2 + UpkeepFailureReasonTargetCheckReverted UpkeepFailureReason = 3 + UpkeepFailureReasonUpkeepNotNeeded UpkeepFailureReason = 4 + UpkeepFailureReasonPerformDataExceedsLimit UpkeepFailureReason = 5 + UpkeepFailureReasonInsufficientBalance UpkeepFailureReason = 6 + UpkeepFailureReasonMercuryCallbackReverted UpkeepFailureReason = 7 + UpkeepFailureReasonRevertDataExceedsLimit UpkeepFailureReason = 8 + UpkeepFailureReasonRegistryPaused UpkeepFailureReason = 9 + // leaving a gap here for more onchain failure reasons in the future + // upkeep failure offchain reasons + UpkeepFailureReasonMercuryAccessNotAllowed UpkeepFailureReason = 32 + UpkeepFailureReasonTxHashNoLongerExists UpkeepFailureReason = 33 + UpkeepFailureReasonInvalidRevertDataInput UpkeepFailureReason = 34 + UpkeepFailureReasonSimulationFailed UpkeepFailureReason = 35 + UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 + + // pipeline execution error + NoPipelineError PipelineExecutionState = 0 + CheckBlockTooOld PipelineExecutionState = 1 + CheckBlockInvalid PipelineExecutionState = 2 + RpcFlakyFailure PipelineExecutionState = 3 + MercuryFlakyFailure PipelineExecutionState = 4 + PackUnpackDecodeFailed PipelineExecutionState = 5 + MercuryUnmarshalError PipelineExecutionState = 6 + InvalidMercuryRequest PipelineExecutionState = 7 + InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses + UpkeepNotAuthorized PipelineExecutionState = 9 +) + +// UpkeepPrivilegeConfig represents the administrative offchain config for each upkeep. It can be set by s_upkeepPrivilegeManager +// role on the registry. Upkeeps allowed to use Mercury server will have this set to true. +type UpkeepPrivilegeConfig struct { + MercuryEnabled bool `json:"mercuryEnabled"` +} + +// generateHMAC calculates a user HMAC for Mercury server authentication. +func (mlh *MercuryLookupHandler) generateHMAC(method string, path string, body []byte, clientId string, secret string, ts int64) string { + bodyHash := sha256.New() + bodyHash.Write(body) + hashString := fmt.Sprintf("%s %s %s %s %d", + method, + path, + hex.EncodeToString(bodyHash.Sum(nil)), + clientId, + ts) + signedMessage := hmac.New(sha256.New, []byte(secret)) + signedMessage.Write([]byte(hashString)) + userHmac := hex.EncodeToString(signedMessage.Sum(nil)) + return userHmac +} + +// singleFeedRequest sends a v0.2 Mercury request for a single feed report. +func (mlh *MercuryLookupHandler) singleFeedRequest(ctx context.Context, ch chan<- MercuryData, index int, ml *StreamsLookup) { + q := url.Values{ + ml.feedParamKey: {ml.feeds[index]}, + ml.timeParamKey: {ml.time.String()}, + } + mercuryURL := mlh.credentials.LegacyURL + reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, MercuryPathV2, q.Encode()) + // mlh.logger.Debugf("request URL for upkeep %s feed %s: %s", ml.upkeepId.String(), ml.feeds[index], reqUrl) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) + if err != nil { + ch <- MercuryData{Index: index, Error: err, Retryable: false, State: InvalidMercuryRequest} + return + } + + ts := time.Now().UTC().UnixMilli() + signature := mlh.generateHMAC(http.MethodGet, MercuryPathV2+q.Encode(), []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) + req.Header.Set(HeaderContentType, ApplicationJson) + req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) + req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) + req.Header.Set(HeaderSignature, signature) + + // in the case of multiple retries here, use the last attempt's data + state := NoPipelineError + retryable := false + sent := false + retryErr := retry.Do( + func() error { + retryable = false + resp, err1 := mlh.httpClient.Do(req) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup GET request failed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) + retryable = true + state = MercuryFlakyFailure + return err1 + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + // mlh.logger.Errorf("Encountered error when closing the body of the response in single feed: %s", err) + } + }(resp.Body) + + body, err1 := io.ReadAll(resp.Body) + if err1 != nil { + retryable = false + state = InvalidMercuryResponse + return err1 + } + + if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { + // mlh.logger.Errorw("StreamsLookup received retryable status code", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "statusCode", resp.StatusCode, "feed", ml.feeds[index]) + retryable = true + state = MercuryFlakyFailure + return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) + } else if resp.StatusCode != http.StatusOK { + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("StreamsLookup upkeep %s block %s received status code %d for feed %s", ml.upkeepId.String(), ml.time.String(), resp.StatusCode, ml.feeds[index]) + } + + // mlh.logger.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", ml.time.String(), ml.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + + var m MercuryV02Response + err1 = json.Unmarshal(body, &m) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) + retryable = false + state = MercuryUnmarshalError + return err1 + } + blobBytes, err1 := hexutil.Decode(m.ChainlinkBlob) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup failed to decode chainlinkBlob for feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "blob", m.ChainlinkBlob, "feed", ml.feeds[index], "error", err1) + retryable = false + state = InvalidMercuryResponse + return err1 + } + ch <- MercuryData{ + Index: index, + Bytes: [][]byte{blobBytes}, + Retryable: false, + State: NoPipelineError, + } + sent = true + return nil + }, + // only retry when the error is 404 Not Found or 500 Internal Server Error + retry.RetryIf(func(err error) bool { + return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) + }), + retry.Context(ctx), + retry.Delay(RetryDelay), + retry.Attempts(TotalAttempt)) + + if !sent { + md := MercuryData{ + Index: index, + Bytes: [][]byte{}, + Retryable: retryable, + Error: fmt.Errorf("failed to request feed for %s: %w", ml.feeds[index], retryErr), + State: state, + } + ch <- md + } +} + +// multiFeedsRequest sends a Mercury v0.3 request for a multi-feed report +func (mlh *MercuryLookupHandler) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, ml *StreamsLookup) { + params := fmt.Sprintf("%s=%s&%s=%s", FeedIDs, strings.Join(ml.feeds, ","), Timestamp, ml.time.String()) + reqUrl := fmt.Sprintf("%s%s%s", mlh.credentials.URL, MercuryBatchPathV3, params) + // mlh.logger.Debugf("request URL for upkeep %s userId %s: %s", ml.upkeepId.String(), mlh.credentials.ClientID, reqUrl) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) + if err != nil { + ch <- MercuryData{Index: 0, Error: err, Retryable: false, State: InvalidMercuryRequest} + return + } + + ts := time.Now().UTC().UnixMilli() + signature := mlh.generateHMAC(http.MethodGet, MercuryBatchPathV3+params, []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) + req.Header.Set(HeaderContentType, ApplicationJson) + // username here is often referred to as user id + req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) + req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) + req.Header.Set(HeaderSignature, signature) + // mercury will inspect authorization headers above to make sure this user (in automation's context, this node) is eligible to access mercury + // and if it has an automation role. it will then look at this upkeep id to check if it has access to all the requested feeds. + req.Header.Set(HeaderUpkeepId, ml.upkeepId.String()) + + // in the case of multiple retries here, use the last attempt's data + state := NoPipelineError + retryable := false + sent := false + retryErr := retry.Do( + func() error { + retryable = false + resp, err1 := mlh.httpClient.Do(req) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup GET request fails for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) + retryable = true + state = MercuryFlakyFailure + return err1 + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + // mlh.logger.Errorf("Encountered error when closing the body of the response in the multi feed: %s", err) + } + }(resp.Body) + body, err1 := io.ReadAll(resp.Body) + if err1 != nil { + retryable = false + state = InvalidMercuryResponse + return err1 + } + + // mlh.logger.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + if resp.StatusCode == http.StatusUnauthorized { + retryable = false + state = UpkeepNotAuthorized + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusBadRequest { + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusInternalServerError { + retryable = true + state = MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusInternalServerError) + } else if resp.StatusCode == 420 { + // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode != http.StatusOK { + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } + + var response MercuryV03Response + err1 = json.Unmarshal(body, &response) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) + retryable = false + state = MercuryUnmarshalError + return err1 + } + // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract + // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated + if len(response.Reports) != len(ml.feeds) { + // TODO: AUTO-5044: calculate what reports are missing and log a warning + retryable = true + state = MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusNotFound) + } + var reportBytes [][]byte + for _, rsp := range response.Reports { + b, err := hexutil.Decode(rsp.FullReport) + if err != nil { + retryable = false + state = InvalidMercuryResponse + return err + } + reportBytes = append(reportBytes, b) + } + ch <- MercuryData{ + Index: 0, + Bytes: reportBytes, + Retryable: false, + State: NoPipelineError, + } + sent = true + return nil + }, + // only retry when the error is 404 Not Found or 500 Internal Server Error + retry.RetryIf(func(err error) bool { + return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) + }), + retry.Context(ctx), + retry.Delay(RetryDelay), + retry.Attempts(TotalAttempt)) + + if !sent { + md := MercuryData{ + Index: 0, + Bytes: [][]byte{}, + Retryable: retryable, + Error: retryErr, + State: state, + } + ch <- md + } +} + +// doMercuryRequest sends requests to Mercury API to retrieve ChainlinkBlob. +func (mlh *MercuryLookupHandler) doMercuryRequest(ctx context.Context, ml *StreamsLookup) (PipelineExecutionState, UpkeepFailureReason, [][]byte, bool, error) { + var isMercuryV03 bool + resultLen := len(ml.feeds) + ch := make(chan MercuryData, resultLen) + if len(ml.feeds) == 0 { + return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) + } + if ml.feedParamKey == FeedIdHex && ml.timeParamKey == BlockNumber { + // only v0.2 + for i := range ml.feeds { + go mlh.singleFeedRequest(ctx, ch, i, ml) + } + } else if ml.feedParamKey == FeedIDs && ml.timeParamKey == Timestamp { + // only v0.3 + resultLen = 1 + isMercuryV03 = true + ch = make(chan MercuryData, resultLen) + go mlh.multiFeedsRequest(ctx, ch, ml) + } else { + return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) + } + + var reqErr error + results := make([][]byte, len(ml.feeds)) + retryable := true + allSuccess := true + // in v0.2, use the last execution error as the state, if no execution errors, state will be no error + state := NoPipelineError + for i := 0; i < resultLen; i++ { + m := <-ch + if m.Error != nil { + if reqErr == nil { + reqErr = errors.New(m.Error.Error()) + } else { + reqErr = errors.New(reqErr.Error() + m.Error.Error()) + } + retryable = retryable && m.Retryable + allSuccess = false + if m.State != NoPipelineError { + state = m.State + } + continue + } + if isMercuryV03 { + results = m.Bytes + } else { + results[m.Index] = m.Bytes[0] + } + } + // only retry when not all successful AND none are not retryable + return state, UpkeepFailureReasonNone, results, retryable && !allSuccess, reqErr +} + +// decodeStreamsLookup decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string timeParamKey, uint256 time, byte[] extraData) +// func (mlh *MercuryLookupHandler) decodeStreamsLookup(data []byte) (*StreamsLookup, error) { +// e := mlh.mercuryConfig.Abi.Errors["StreamsLookup"] +// unpack, err := e.Unpack(data) +// if err != nil { +// return nil, fmt.Errorf("unpack error: %w", err) +// } +// errorParameters := unpack.([]interface{}) + +// return &StreamsLookup{ +// feedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), +// feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), +// timeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), +// time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), +// extraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), +// }, nil +// } + +// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if +// this upkeep is allowed to use Mercury service. +// func (mlh *MercuryLookupHandler) allowedToUseMercury(upkeep models.Upkeep) (bool, error) { +// allowed, ok := mlh.mercuryConfig.AllowListCache.Get(upkeep.Admin.Hex()) +// if ok { +// return allowed.(bool), nil +// } + +// if upkeep.UpkeepPrivilegeConfig == nil { +// return false, fmt.Errorf("the upkeep privilege config was not retrieved for upkeep with ID %s", upkeep.UpkeepID) +// } + +// if len(upkeep.UpkeepPrivilegeConfig) == 0 { +// return false, fmt.Errorf("the upkeep privilege config is empty") +// } + +// var a UpkeepPrivilegeConfig +// err := json.Unmarshal(upkeep.UpkeepPrivilegeConfig, &a) +// if err != nil { +// return false, fmt.Errorf("failed to unmarshal privilege config for upkeep ID %s: %v", upkeep.UpkeepID, err) +// } + +// mlh.mercuryConfig.AllowListCache.Set(upkeep.Admin.Hex(), a.MercuryEnabled, cache.DefaultExpiration) +// return a.MercuryEnabled, nil +// } + +func (mlh *MercuryLookupHandler) CheckCallback(ctx context.Context, values [][]byte, lookup *StreamsLookup, registryABI ethabi.ABI, registryAddress common.Address) (hexutil.Bytes, error) { + payload, err := registryABI.Pack("checkCallback", lookup.upkeepId, values, lookup.extraData) + if err != nil { + return nil, err + } + + var theBytes hexutil.Bytes + args := map[string]interface{}{ + "to": registryAddress.Hex(), + "data": hexutil.Bytes(payload), + } + + // call checkCallback function at the block which OCR3 has agreed upon + err = mlh.rpcClient.CallContext(ctx, &theBytes, "eth_call", args, hexutil.EncodeUint64(lookup.block)) + if err != nil { + return nil, err + } + return theBytes, nil +} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 89ddc54ca7..91e26caef6 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -7,6 +7,7 @@ replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( github.com/ava-labs/coreth v0.12.1 + github.com/avast/retry-go v3.0.0+incompatible github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/ethereum/go-ethereum v1.12.0 @@ -18,6 +19,7 @@ require ( github.com/montanaflynn/stats v0.7.1 github.com/olekukonko/tablewriter v0.0.5 github.com/pelletier/go-toml/v2 v2.1.0 + github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 @@ -234,7 +236,6 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/pressly/goose/v3 v3.16.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 5f0e22fba0..1622f1d24d 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -150,6 +150,8 @@ github.com/ava-labs/avalanchego v1.10.1 h1:lBeamJ1iNq+p2oKg2nAs+A65m8vhSDjkiTDbw github.com/ava-labs/avalanchego v1.10.1/go.mod h1:ZvSXWlbkUKlbk3BsWx29a+8eVHe/WBsOxh55BSGoeRk= github.com/ava-labs/coreth v0.12.1 h1:EWSkFGHGVUxmu1pnSK/2pdcxaAVHbGspHqO3Ag+i7sA= github.com/ava-labs/coreth v0.12.1/go.mod h1:/5x54QlIKjlPebkdzTA5ic9wXdejbWOnQosztkv9jxo= +github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= +github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index cb9e2dd675..aec2343192 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -16,6 +16,7 @@ import ( "github.com/patrickmn/go-cache" ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" @@ -91,9 +92,8 @@ func NewStreamsLookup( // Lookup looks through check upkeep results looking for any that need off chain lookup func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckResult) []ocr2keepers.CheckResult { lookups := map[int]*mercury.StreamsLookup{} - for _, checkResult := range checkResults { - copyCheckResult := checkResult - s.buildResult(ctx, ©CheckResult, lookups) + for i, checkResult := range checkResults { + s.buildResult(ctx, i, checkResult, checkResults, lookups) } var wg sync.WaitGroup @@ -101,7 +101,7 @@ func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckRe wg.Add(1) func(i int, lookup *mercury.StreamsLookup) { s.threadCtrl.Go(func(ctx context.Context) { - s.doLookup(ctx, &wg, lookup, &checkResults[i]) + s.doLookup(ctx, &wg, lookup, i, checkResults) }) }(i, lookup) } @@ -112,7 +112,7 @@ func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckRe } // buildResult checks if the upkeep is allowed by Mercury and builds a streams lookup request from the check result -func (s *streams) buildResult(ctx context.Context, checkResult *ocr2keepers.CheckResult, lookups map[int]*mercury.StreamsLookup) { +func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keepers.CheckResult, checkResults []ocr2keepers.CheckResult, lookups map[int]*mercury.StreamsLookup) { lookupLggr := s.lggr.With("where", "StreamsLookup") if checkResult.IneligibilityReason != uint8(mercury.MercuryUpkeepFailureReasonTargetCheckReverted) { // Streams Lookup only works when upkeep target check reverts @@ -129,7 +129,7 @@ func (s *streams) buildResult(ctx context.Context, checkResult *ocr2keepers.Chec // Try to decode the revert error into streams lookup format. User upkeeps can revert with any reason, see if they // tried to call mercury - lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResult.PerformData)) + lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) streamsLookupErr, err := s.packer.DecodeStreamsLookupRequest(checkResult.PerformData) if err != nil { lookupLggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) @@ -139,7 +139,7 @@ func (s *streams) buildResult(ctx context.Context, checkResult *ocr2keepers.Chec streamsLookupResponse := &mercury.StreamsLookup{StreamsLookupError: streamsLookupErr} if len(streamsLookupResponse.Feeds) == 0 { - checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) lookupLggr.Debugf("at block %s upkeep %s has empty feeds array", block, upkeepId) return } @@ -148,21 +148,21 @@ func (s *streams) buildResult(ctx context.Context, checkResult *ocr2keepers.Chec if streamsLookupResponse.IsMercuryV02() { // check permission on the registry for mercury v0.2 opts := s.buildCallOpts(ctx, block) - if state, reason, retryable, allowed, err := s.AllowedToUseMercury(opts, upkeepId.BigInt()); err != nil { + if state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId.BigInt()); err != nil { lookupLggr.Warnf("at block %s upkeep %s failed to query mercury allow list: %s", block, upkeepId, err) - checkResult.PipelineExecutionState = uint8(state) - checkResult.IneligibilityReason = uint8(reason) - checkResult.Retryable = retryable + checkResults[i].PipelineExecutionState = uint8(state) + checkResults[i].IneligibilityReason = uint8(reason) + checkResults[i].Retryable = retryable return } else if !allowed { lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed) + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed) return } } else if streamsLookupResponse.IsMercuryVersionUnkown() { // if mercury version cannot be determined, set failure reason lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) return } @@ -171,103 +171,71 @@ func (s *streams) buildResult(ctx context.Context, checkResult *ocr2keepers.Chec // in the revert for mercury v0.2, which is denoted by time in the struct bc starting from v0.3, only timestamp will be supported streamsLookupResponse.Block = uint64(block.Int64()) lookupLggr.Infof("at block %d upkeep %s DecodeStreamsLookupRequest feedKey=%s timeKey=%s feeds=%v time=%s extraData=%s", block, upkeepId, streamsLookupResponse.FeedParamKey, streamsLookupResponse.TimeParamKey, streamsLookupResponse.Feeds, streamsLookupResponse.Time, hexutil.Encode(streamsLookupResponse.ExtraData)) - lookups[len(lookups)] = streamsLookupResponse + lookups[i] = streamsLookupResponse } -func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, checkResult *ocr2keepers.CheckResult) { +func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, i int, checkResults []ocr2keepers.CheckResult) { defer wg.Done() - values, err := s.DoMercuryRequest(ctx, lookup, checkResult) - if err != nil { - s.lggr.Errorf("at block %d upkeep %s requested time %s DoMercuryRequest err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) - } + state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) + pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) - if err := s.CheckCallback(ctx, values, lookup, checkResult); err != nil { - s.lggr.Errorf("at block %d upkeep %s requested time %s CheckCallback err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + if lookup.IsMercuryV02() { + state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) + } else if lookup.IsMercuryV03() { + state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) } -} -func (s *streams) CheckCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup, checkResult *ocr2keepers.CheckResult) error { - payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) if err != nil { - s.lggr.Errorf("at block %d upkeep %s checkCallback packing err: %s", lookup.Block, lookup.UpkeepId, err.Error()) - checkResult.Retryable = false - checkResult.PipelineExecutionState = uint8(mercury.PackUnpackDecodeFailed) - return err + s.lggr.Errorf("at block %d upkeep %s requested time %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.Block, lookup.UpkeepId, lookup.Time, retryable, retryInterval, err.Error()) + checkResults[i].Retryable = retryable + checkResults[i].RetryInterval = retryInterval + checkResults[i].PipelineExecutionState = uint8(state) + checkResults[i].IneligibilityReason = uint8(reason) + return } - var mercuryBytes hexutil.Bytes - args := map[string]interface{}{ - "to": s.registry.Address().Hex(), - "data": hexutil.Bytes(payload), + for j, v := range values { + s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) } - // call checkCallback function at the block which OCR3 has agreed upon - if err = s.client.CallContext(ctx, &mercuryBytes, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { + state, retryable, mercuryBytes, err := s.checkCallback(ctx, values, lookup) + if err != nil { s.lggr.Errorf("at block %d upkeep %s checkCallback err: %s", lookup.Block, lookup.UpkeepId, err.Error()) - checkResult.Retryable = true - checkResult.PipelineExecutionState = uint8(mercury.RpcFlakyFailure) - return err + checkResults[i].Retryable = retryable + checkResults[i].PipelineExecutionState = uint8(state) + return } - s.lggr.Infof("at block %d upkeep %s requested time %s checkCallback mercuryBytes: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(mercuryBytes)) unpackCallBackState, needed, performData, failureReason, _, err := s.packer.UnpackCheckCallbackResult(mercuryBytes) if err != nil { s.lggr.Errorf("at block %d upkeep %s requested time %s UnpackCheckCallbackResult err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) - checkResult.PipelineExecutionState = unpackCallBackState - return err + checkResults[i].PipelineExecutionState = unpackCallBackState + return } if failureReason == uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) { - checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) s.lggr.Debugf("at block %d upkeep %s requested time %s mercury callback reverts", lookup.Block, lookup.UpkeepId, lookup.Time) - return fmt.Errorf("at block %d upkeep %s requested time %s mercury callback reverts", lookup.Block, lookup.UpkeepId, lookup.Time) - + return } if !needed { - checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonUpkeepNotNeeded) + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonUpkeepNotNeeded) s.lggr.Debugf("at block %d upkeep %s requested time %s callback reports upkeep not needed", lookup.Block, lookup.UpkeepId, lookup.Time) - return fmt.Errorf("at block %d upkeep %s requested time %s callback reports upkeep not needed", lookup.Block, lookup.UpkeepId, lookup.Time) + return } - checkResult.IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonNone) - checkResult.Eligible = true - checkResult.PerformData = performData + checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonNone) + checkResults[i].Eligible = true + checkResults[i].PerformData = performData s.lggr.Infof("at block %d upkeep %s requested time %s successful with perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(performData)) - - return nil -} - -func (s *streams) DoMercuryRequest(ctx context.Context, lookup *mercury.StreamsLookup, checkResult *ocr2keepers.CheckResult) ([][]byte, error) { - state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) - pluginRetryKey := generatePluginRetryKey(checkResult.WorkID, lookup.Block) - - if lookup.IsMercuryV02() { - state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) - } else if lookup.IsMercuryV03() { - state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) - } - - if err != nil { - s.lggr.Errorf("at block %d upkeep %s requested time %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.Block, lookup.UpkeepId, lookup.Time, retryable, retryInterval, err.Error()) - checkResult.Retryable = retryable - checkResult.RetryInterval = retryInterval - checkResult.PipelineExecutionState = uint8(state) - checkResult.IneligibilityReason = uint8(reason) - return nil, err - } - - for j, v := range values { - s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) - } - return values, nil } -// AllowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if +// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if // this upkeep is allowed to use Mercury service. -func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { +func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { allowed, ok := s.mercuryConfig.IsUpkeepAllowed(upkeepId.String()) if ok { return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, allowed.(bool), nil @@ -287,6 +255,7 @@ func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s "data": hexutil.Bytes(payload), } + // call checkCallback function at the block which OCR3 has agreed upon if err = s.client.CallContext(opts.Context, &resultBytes, "eth_call", args, hexutil.EncodeBig(opts.BlockNumber)); err != nil { return mercury.RpcFlakyFailure, mercury.MercuryUpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) } @@ -312,6 +281,26 @@ func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil } +func (s *streams) checkCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup) (mercury.MercuryUpkeepState, bool, hexutil.Bytes, error) { + payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) + if err != nil { + return mercury.PackUnpackDecodeFailed, false, nil, err + } + + var b hexutil.Bytes + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + + // call checkCallback function at the block which OCR3 has agreed upon + if err := s.client.CallContext(ctx, &b, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { + return mercury.RpcFlakyFailure, true, nil, err + } + + return mercury.NoPipelineError, false, b, nil +} + func (s *streams) buildCallOpts(ctx context.Context, block *big.Int) *bind.CallOpts { opts := bind.CallOpts{ Context: ctx, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index 2475244b4d..abcc37dca1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -126,7 +126,6 @@ func TestStreams_CheckCallback(t *testing.T) { tests := []struct { name string lookup *mercury.StreamsLookup - input []ocr2keepers.CheckResult values [][]byte statusCode int @@ -154,9 +153,6 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, - input: []ocr2keepers.CheckResult{ - {}, - }, values: values, statusCode: http.StatusOK, callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -189,9 +185,6 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, - input: []ocr2keepers.CheckResult{ - {}, - }, values: values, statusCode: http.StatusOK, callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -223,9 +216,6 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, - input: []ocr2keepers.CheckResult{ - {}, - }, values: values, statusCode: http.StatusOK, callbackResp: []byte{}, @@ -265,10 +255,10 @@ func TestStreams_CheckCallback(t *testing.T) { }).Once() s.client = client - err = s.CheckCallback(testutils.Context(t), tt.values, tt.lookup, &tt.input[0]) - tt.wantErr(t, err, fmt.Sprintf("Error assertion failed: %v", tt.name)) - assert.Equal(t, uint8(tt.state), tt.input[0].PipelineExecutionState) - assert.Equal(t, tt.retryable, tt.input[0].Retryable) + state, retryable, _, err := s.checkCallback(testutils.Context(t), tt.values, tt.lookup) + tt.wantErr(t, err, fmt.Sprintf("Error asserion failed: %v", tt.name)) + assert.Equal(t, tt.state, state) + assert.Equal(t, tt.retryable, retryable) }) } } @@ -444,7 +434,7 @@ func TestStreams_AllowedToUseMercury(t *testing.T) { BlockNumber: big.NewInt(10), } - state, reason, retryable, allowed, err := s.AllowedToUseMercury(opts, upkeepId) + state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId) assert.Equal(t, tt.err, err) assert.Equal(t, tt.allowed, allowed) assert.Equal(t, tt.state, state) From 7d9274044baa79752940f6fed70c99d18746fbc4 Mon Sep 17 00:00:00 2001 From: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:51:16 +0000 Subject: [PATCH 270/327] Update Loki auth in Github test workflow (#11488) --- .github/workflows/on-demand-vrfv2-performance-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml index 100fdf73e6..56a5c8eee8 100644 --- a/.github/workflows/on-demand-vrfv2-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -71,7 +71,8 @@ jobs: contents: read env: LOKI_URL: ${{ secrets.LOKI_URL }} - LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} + LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} SELECTED_NETWORKS: ${{ inputs.network }} TEST_TYPE: ${{ inputs.performanceTestType }} VRFV2_TEST_DURATION: ${{ inputs.testDuration }} From 1032ba3ae823442732d9007ca8e479ca9debd350 Mon Sep 17 00:00:00 2001 From: Jim W Date: Mon, 4 Dec 2023 20:05:11 -0500 Subject: [PATCH 271/327] remove pkgerrors dependency from common pkg (#11479) * remove pkgerrors dependency from common pkg * fix naming inconsistencies * clean up error return * clean up error return and remove use of Unwrap --- common/client/multi_node.go | 7 +-- common/client/multi_node_test.go | 2 +- common/client/node.go | 10 ++-- common/client/node_lifecycle.go | 2 +- common/client/node_lifecycle_test.go | 2 +- common/client/send_only_node_test.go | 2 +- common/fee/models.go | 12 ++-- common/fee/utils.go | 4 +- common/headtracker/head_listener.go | 5 +- common/headtracker/head_tracker.go | 12 ++-- common/txmgr/broadcaster.go | 50 ++++++++--------- common/txmgr/confirmer.go | 83 ++++++++++++++-------------- common/txmgr/strategies.go | 4 +- common/txmgr/types/tx.go | 14 ++++- 14 files changed, 110 insertions(+), 99 deletions(-) diff --git a/common/client/multi_node.go b/common/client/multi_node.go index db5380e91f..dfd6585b64 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -7,7 +7,6 @@ import ( "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -166,12 +165,12 @@ func NewMultiNode[ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) Dial(ctx context.Context) error { return c.StartOnce("MultiNode", func() (merr error) { if len(c.nodes) == 0 { - return errors.Errorf("no available nodes for chain %s", c.chainID.String()) + return fmt.Errorf("no available nodes for chain %s", c.chainID.String()) } var ms services.MultiStart for _, n := range c.nodes { if n.ConfiguredChainID().String() != c.chainID.String() { - return ms.CloseBecause(errors.Errorf("node %s has configured chain ID %s which does not match multinode configured chain ID of %s", n.String(), n.ConfiguredChainID().String(), c.chainID.String())) + return ms.CloseBecause(fmt.Errorf("node %s has configured chain ID %s which does not match multinode configured chain ID of %s", n.String(), n.ConfiguredChainID().String(), c.chainID.String())) } rawNode, ok := n.(*node[CHAIN_ID, HEAD, RPC_CLIENT]) if ok { @@ -188,7 +187,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP } for _, s := range c.sendonlys { if s.ConfiguredChainID().String() != c.chainID.String() { - return ms.CloseBecause(errors.Errorf("sendonly node %s has configured chain ID %s which does not match multinode configured chain ID of %s", s.String(), s.ConfiguredChainID().String(), c.chainID.String())) + return ms.CloseBecause(fmt.Errorf("sendonly node %s has configured chain ID %s which does not match multinode configured chain ID of %s", s.String(), s.ConfiguredChainID().String(), c.chainID.String())) } if err := ms.Start(ctx, s); err != nil { return err diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 229f1320a1..82af741108 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -1,13 +1,13 @@ package client import ( + "errors" "fmt" big "math/big" "math/rand" "testing" "time" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/common/client/node.go b/common/client/node.go index 4fad18b42c..ce144bbca8 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -2,13 +2,13 @@ package client import ( "context" + "errors" "fmt" "math/big" "net/url" "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -256,15 +256,15 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verify(callerCtx context.Context) (err error var chainID CHAIN_ID if chainID, err = n.rpc.ChainID(callerCtx); err != nil { promFailed() - return errors.Wrapf(err, "failed to verify chain ID for node %s", n.name) + return fmt.Errorf("failed to verify chain ID for node %s: %w", n.name, err) } else if chainID.String() != n.chainID.String() { promFailed() - return errors.Wrapf( - errInvalidChainID, - "rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s", + return fmt.Errorf( + "rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s: %w", chainID.String(), n.chainID.String(), n.name, + errInvalidChainID, ) } diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 59a59691c8..5ba0bff323 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -2,12 +2,12 @@ package client import ( "context" + "errors" "fmt" "math" "math/big" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index 224b79d837..bf94e6bd06 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -1,13 +1,13 @@ package client import ( + "errors" "fmt" big "math/big" "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" diff --git a/common/client/send_only_node_test.go b/common/client/send_only_node_test.go index 459f923cba..79f4bfd60e 100644 --- a/common/client/send_only_node_test.go +++ b/common/client/send_only_node_test.go @@ -1,11 +1,11 @@ package client import ( + "errors" "fmt" "net/url" "testing" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/common/fee/models.go b/common/fee/models.go index b843cc3f05..1fe4d2b053 100644 --- a/common/fee/models.go +++ b/common/fee/models.go @@ -1,10 +1,10 @@ package fee import ( + "errors" + "fmt" "math/big" - "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-common/pkg/logger" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink/v2/common/chains/label" @@ -47,15 +47,15 @@ func CalculateBumpedFee( bumpedFeePrice = maxFee(lggr, currentfeePrice, bumpedFeePrice, maxFeePrice, "fee price", toChainUnit) if bumpedFeePrice.Cmp(maxFeePrice) > 0 { - return maxFeePrice, errors.Wrapf(ErrBumpFeeExceedsLimit, "bumped fee price of %s would exceed configured max fee price of %s (original price was %s). %s", - toChainUnit(bumpedFeePrice), toChainUnit(maxFeePrice), toChainUnit(originalfeePrice), label.NodeConnectivityProblemWarning) + return maxFeePrice, fmt.Errorf("bumped fee price of %s would exceed configured max fee price of %s (original price was %s). %s: %w", + toChainUnit(bumpedFeePrice), toChainUnit(maxFeePrice), toChainUnit(originalfeePrice), label.NodeConnectivityProblemWarning, ErrBumpFeeExceedsLimit) } else if bumpedFeePrice.Cmp(originalfeePrice) == 0 { // NOTE: This really shouldn't happen since we enforce minimums for // FeeEstimator.BumpPercent and FeeEstimator.BumpMin in the config validation, // but it's here anyway for a "belts and braces" approach - return bumpedFeePrice, errors.Wrapf(ErrBump, "bumped fee price of %s is equal to original fee price of %s."+ + return bumpedFeePrice, fmt.Errorf("bumped fee price of %s is equal to original fee price of %s."+ " ACTION REQUIRED: This is a configuration error, you must increase either "+ - "FeeEstimator.BumpPercent or FeeEstimator.BumpMin", toChainUnit(bumpedFeePrice), toChainUnit(bumpedFeePrice)) + "FeeEstimator.BumpPercent or FeeEstimator.BumpMin: %w", toChainUnit(bumpedFeePrice), toChainUnit(bumpedFeePrice), ErrBump) } return bumpedFeePrice, nil } diff --git a/common/fee/utils.go b/common/fee/utils.go index 71ababddbe..eeb2c96671 100644 --- a/common/fee/utils.go +++ b/common/fee/utils.go @@ -1,10 +1,10 @@ package fee import ( + "fmt" "math" "math/big" - "github.com/pkg/errors" "github.com/shopspring/decimal" ) @@ -12,7 +12,7 @@ func ApplyMultiplier(feeLimit uint32, multiplier float32) (uint32, error) { result := decimal.NewFromBigInt(big.NewInt(0).SetUint64(uint64(feeLimit)), 0).Mul(decimal.NewFromFloat32(multiplier)).IntPart() if result > math.MaxUint32 { - return 0, errors.Errorf("integer overflow when applying multiplier of %f to fee limit of %d", multiplier, feeLimit) + return 0, fmt.Errorf("integer overflow when applying multiplier of %f to fee limit of %d", multiplier, feeLimit) } return uint32(result), nil } diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index 2013895d0b..0aebf60663 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -2,10 +2,11 @@ package headtracker import ( "context" + "errors" + "fmt" "sync/atomic" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -202,7 +203,7 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) subscribeToHead(ctx context.Cont hl.headSubscription, err = hl.client.SubscribeNewHead(ctx, hl.chHeaders) if err != nil { close(hl.chHeaders) - return errors.Wrap(err, "Client#SubscribeNewHead") + return fmt.Errorf("Client#SubscribeNewHead: %w", err) } hl.connected.Store(true) diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 6e379776c0..c977eb023c 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -2,11 +2,11 @@ package headtracker import ( "context" + "errors" "fmt" "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -123,7 +123,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error ht.log.Errorw("Error getting initial head", "err", err) } else if initialHead.IsValid() { if err := ht.handleNewHead(ctx, initialHead); err != nil { - return errors.Wrap(err, "error handling initial head") + return fmt.Errorf("error handling initial head: %w", err) } } else { ht.log.Debug("Got nil initial head") @@ -179,7 +179,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) LatestChain() HTH { func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) getInitialHead(ctx context.Context) (HTH, error) { head, err := ht.client.HeadByNumber(ctx, nil) if err != nil { - return ht.getNilHead(), errors.Wrap(err, "failed to fetch initial head") + return ht.getNilHead(), fmt.Errorf("failed to fetch initial head: %w", err) } loggerFields := []interface{}{"head", head} if head.IsValid() { @@ -204,7 +204,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context if ctx.Err() != nil { return nil } else if err != nil { - return errors.Wrapf(err, "failed to save head: %#v", head) + return fmt.Errorf("failed to save head: %#v: %w", head, err) } if !prevHead.IsValid() || head.BlockNumber() > prevHead.BlockNumber() { @@ -212,7 +212,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context headWithChain := ht.headSaver.Chain(head.BlockHash()) if !headWithChain.IsValid() { - return errors.Errorf("HeadTracker#handleNewHighestHead headWithChain was unexpectedly nil") + return fmt.Errorf("HeadTracker#handleNewHighestHead headWithChain was unexpectedly nil") } ht.backfillMB.Deliver(headWithChain) ht.broadcastMB.Deliver(headWithChain) @@ -339,7 +339,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, hea ht.log.Debugw("context canceled, aborting backfill", "err", err, "ctx.Err", ctx.Err()) break } else if err != nil { - return errors.Wrap(err, "fetchAndSaveHead failed") + return fmt.Errorf("fetchAndSaveHead failed: %w", err) } } return diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 54ae653f66..f10ecafc67 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -3,13 +3,13 @@ package txmgr import ( "context" "database/sql" + "errors" "fmt" "slices" "sync" "time" "github.com/jpillora/backoff" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" @@ -210,7 +210,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star var err error eb.enabledAddresses, err = eb.ks.EnabledAddressesForChain(eb.chainID) if err != nil { - return errors.Wrap(err, "Broadcaster: failed to load EnabledAddressesForChain") + return fmt.Errorf("Broadcaster: failed to load EnabledAddressesForChain: %w", err) } if len(eb.enabledAddresses) > 0 { @@ -246,7 +246,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) clos eb.initSync.Lock() defer eb.initSync.Unlock() if !eb.isStarted { - return errors.Wrap(services.ErrAlreadyStopped, "Broadcaster is not started") + return fmt.Errorf("Broadcaster is not started: %w", services.ErrAlreadyStopped) } close(eb.chStop) eb.wg.Wait() @@ -454,19 +454,19 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc err, retryable = eb.handleAnyInProgressTx(ctx, fromAddress) if err != nil { - return retryable, errors.Wrap(err, "processUnstartedTxs failed on handleAnyInProgressTx") + return retryable, fmt.Errorf("processUnstartedTxs failed on handleAnyInProgressTx: %w", err) } for { maxInFlightTransactions := eb.txConfig.MaxInFlight() if maxInFlightTransactions > 0 { nUnconfirmed, err := eb.txStore.CountUnconfirmedTransactions(ctx, fromAddress, eb.chainID) if err != nil { - return true, errors.Wrap(err, "CountUnconfirmedTransactions failed") + return true, fmt.Errorf("CountUnconfirmedTransactions failed: %w", err) } if nUnconfirmed >= maxInFlightTransactions { nUnstarted, err := eb.txStore.CountUnstartedTransactions(ctx, fromAddress, eb.chainID) if err != nil { - return true, errors.Wrap(err, "CountUnstartedTransactions failed") + return true, fmt.Errorf("CountUnstartedTransactions failed: %w", err) } eb.lggr.Warnw(fmt.Sprintf(`Transaction throttling; %d transactions in-flight and %d unstarted transactions pending (maximum number of in-flight transactions is %d per key). %s`, nUnconfirmed, nUnstarted, maxInFlightTransactions, label.MaxInFlightTransactionsWarning), "maxInFlightTransactions", maxInFlightTransactions, "nUnconfirmed", nUnconfirmed, "nUnstarted", nUnstarted) select { @@ -479,7 +479,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc } etx, err := eb.nextUnstartedTransactionWithSequence(fromAddress) if err != nil { - return true, errors.Wrap(err, "processUnstartedTxs failed on nextUnstartedTransactionWithSequence") + return true, fmt.Errorf("processUnstartedTxs failed on nextUnstartedTransactionWithSequence: %w", err) } if etx == nil { return false, nil @@ -489,18 +489,18 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc var retryable bool a, _, _, retryable, err = eb.NewTxAttempt(ctx, *etx, eb.lggr) if err != nil { - return retryable, errors.Wrap(err, "processUnstartedTxs failed on NewAttempt") + return retryable, fmt.Errorf("processUnstartedTxs failed on NewAttempt: %w", err) } if err := eb.txStore.UpdateTxUnstartedToInProgress(ctx, etx, &a); errors.Is(err, ErrTxRemoved) { eb.lggr.Debugw("tx removed", "txID", etx.ID, "subject", etx.Subject) continue } else if err != nil { - return true, errors.Wrap(err, "processUnstartedTxs failed on UpdateTxUnstartedToInProgress") + return true, fmt.Errorf("processUnstartedTxs failed on UpdateTxUnstartedToInProgress: %w", err) } if err, retryable := eb.handleInProgressTx(ctx, *etx, a, time.Now()); err != nil { - return retryable, errors.Wrap(err, "processUnstartedTxs failed on handleAnyInProgressTx") + return retryable, fmt.Errorf("processUnstartedTxs failed on handleInProgressTx: %w", err) } } } @@ -510,11 +510,11 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleAnyInProgressTx(ctx context.Context, fromAddress ADDR) (err error, retryable bool) { etx, err := eb.txStore.GetTxInProgress(ctx, fromAddress) if err != nil { - return errors.Wrap(err, "handleAnyInProgressTx failed"), true + return fmt.Errorf("handleAnyInProgressTx failed: %w", err), true } if etx != nil { if err, retryable := eb.handleInProgressTx(ctx, *etx, etx.TxAttempts[0], etx.CreatedAt); err != nil { - return errors.Wrap(err, "handleAnyInProgressTx failed"), retryable + return fmt.Errorf("handleAnyInProgressTx failed: %w", err), retryable } } return nil, false @@ -524,17 +524,17 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // Here we complete the job that we didn't finish last time. func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleInProgressTx(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (error, bool) { if etx.State != TxInProgress { - return errors.Errorf("invariant violation: expected transaction %v to be in_progress, it was %s", etx.ID, etx.State), false + return fmt.Errorf("invariant violation: expected transaction %v to be in_progress, it was %s", etx.ID, etx.State), false } checkerSpec, err := etx.GetChecker() if err != nil { - return errors.Wrap(err, "parsing transmit checker"), false + return fmt.Errorf("parsing transmit checker: %w", err), false } checker, err := eb.checkerFactory.BuildChecker(checkerSpec) if err != nil { - return errors.Wrap(err, "building transmit checker"), false + return fmt.Errorf("building transmit checker: %w", err), false } lgr := etx.GetLogger(logger.With(eb.lggr, "fee", attempt.TxFee)) @@ -659,7 +659,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand nextSequence, e := eb.client.PendingSequenceAt(ctx, etx.FromAddress) if e != nil { err = multierr.Combine(e, err) - return errors.Wrapf(err, "failed to fetch latest pending sequence after encountering unknown RPC error while sending transaction"), true + return fmt.Errorf("failed to fetch latest pending sequence after encountering unknown RPC error while sending transaction: %w", err), true } if nextSequence.Int64() > (*etx.Sequence).Int64() { // Despite the error, the RPC node considers the previously sent @@ -686,7 +686,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // // In all cases, the best thing we can do is go into a retry loop and keep // trying to send the transaction over again. - return errors.Wrapf(err, "retryable error while sending transaction %s (tx ID %d)", attempt.Hash.String(), etx.ID), true + return fmt.Errorf("retryable error while sending transaction %s (tx ID %d): %w", attempt.Hash.String(), etx.ID, err), true } } @@ -702,7 +702,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next // Finish. No more transactions left to process. Hoorah! return nil, nil } - return nil, errors.Wrap(err, "findNextUnstartedTransactionFromAddress failed") + return nil, fmt.Errorf("findNextUnstartedTransactionFromAddress failed: %w", err) } sequence, err := eb.GetNextSequence(ctx, etx.FromAddress) @@ -726,7 +726,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA replacementAttempt, bumpedFee, bumpedFeeLimit, retryable, err := eb.NewBumpTxAttempt(ctx, etx, attempt, nil, lgr) if err != nil { - return errors.Wrap(err, "tryAgainBumpFee failed"), retryable + return fmt.Errorf("tryAgainBumpFee failed: %w", err), retryable } return eb.saveTryAgainAttempt(ctx, lgr, etx, attempt, replacementAttempt, initialBroadcastAt, bumpedFee, bumpedFeeLimit) @@ -734,14 +734,14 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryAgainWithNewEstimation(ctx context.Context, lgr logger.Logger, txError error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (err error, retryable bool) { if attempt.TxType == 0x2 { - err = errors.Errorf("re-estimation is not supported for EIP-1559 transactions. Node returned error: %v. This is a bug", txError.Error()) + err = fmt.Errorf("re-estimation is not supported for EIP-1559 transactions. Node returned error: %v. This is a bug", txError.Error()) logger.Sugared(eb.lggr).AssumptionViolation(err.Error()) return err, false } replacementAttempt, fee, feeLimit, retryable, err := eb.NewTxAttemptWithType(ctx, etx, lgr, attempt.TxType, feetypes.OptForceRefetch) if err != nil { - return errors.Wrap(err, "tryAgainWithNewEstimation failed to build new attempt"), retryable + return fmt.Errorf("tryAgainWithNewEstimation failed to build new attempt: %w", err), retryable } lgr.Warnw("L2 rejected transaction due to incorrect fee, re-estimated and will try again", "etxID", etx.ID, "err", err, "newGasPrice", fee, "newGasLimit", feeLimit) @@ -751,7 +751,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveTryAgainAttempt(ctx context.Context, lgr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time, newFee FEE, newFeeLimit uint32) (err error, retyrable bool) { if err = eb.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &replacementAttempt); err != nil { - return errors.Wrap(err, "tryAgainWithNewFee failed"), true + return fmt.Errorf("tryAgainWithNewFee failed: %w", err), true } lgr.Debugw("Bumped fee on initial send", "oldFee", attempt.TxFee.String(), "newFee", newFee.String(), "newFeeLimit", newFeeLimit) return eb.handleInProgressTx(ctx, etx, replacementAttempt, initialBroadcastAt) @@ -761,7 +761,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save ctx, cancel := eb.chStop.NewCtx() defer cancel() if etx.State != TxInProgress { - return errors.Errorf("can only transition to fatal_error from in_progress, transaction is currently %s", etx.State) + return fmt.Errorf("can only transition to fatal_error from in_progress, transaction is currently %s", etx.State) } if !etx.Error.Valid { return errors.New("expected error field to be set") @@ -779,11 +779,11 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save // is relatively benign and probably nobody will ever run into it in // practice, but something to be aware of. if etx.PipelineTaskRunID.Valid && eb.resumeCallback != nil && etx.SignalCallback { - err := eb.resumeCallback(etx.PipelineTaskRunID.UUID, nil, errors.Errorf("fatal error while sending transaction: %s", etx.Error.String)) + err := eb.resumeCallback(etx.PipelineTaskRunID.UUID, nil, fmt.Errorf("fatal error while sending transaction: %s", etx.Error.String)) if errors.Is(err, sql.ErrNoRows) { lgr.Debugw("callback missing or already resumed", "etxID", etx.ID) } else if err != nil { - return errors.Wrap(err, "failed to resume pipeline") + return fmt.Errorf("failed to resume pipeline: %w", err) } else { // Mark tx as having completed callback if err := eb.txStore.UpdateTxCallbackCompleted(ctx, etx.PipelineTaskRunID.UUID, eb.chainID); err != nil { diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index a56768ce20..95be9ad23e 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -3,13 +3,13 @@ package txmgr import ( "context" "encoding/hex" + "errors" "fmt" "sort" "strconv" "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" @@ -201,7 +201,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) sta var err error ec.enabledAddresses, err = ec.ks.EnabledAddressesForChain(ec.chainID) if err != nil { - return errors.Wrap(err, "Confirmer: failed to load EnabledAddressesForChain") + return fmt.Errorf("Confirmer: failed to load EnabledAddressesForChain: %w", err) } ec.ctx, ec.ctxCancel = context.WithCancel(context.Background()) @@ -223,7 +223,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) clo ec.initSync.Lock() defer ec.initSync.Unlock() if !ec.isStarted { - return errors.Wrap(utils.ErrAlreadyStopped, "Confirmer is not started") + return fmt.Errorf("Confirmer is not started: %w", utils.ErrAlreadyStopped) } ec.ctxCancel() ec.wg.Wait() @@ -281,28 +281,28 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro ec.lggr.Debugw("processHead start", "headNum", head.BlockNumber(), "id", "confirmer") if err := ec.txStore.SetBroadcastBeforeBlockNum(ctx, head.BlockNumber(), ec.chainID); err != nil { - return errors.Wrap(err, "SetBroadcastBeforeBlockNum failed") + return fmt.Errorf("SetBroadcastBeforeBlockNum failed: %w", err) } if err := ec.CheckConfirmedMissingReceipt(ctx); err != nil { - return errors.Wrap(err, "CheckConfirmedMissingReceipt failed") + return fmt.Errorf("CheckConfirmedMissingReceipt failed: %w", err) } if err := ec.CheckForReceipts(ctx, head.BlockNumber()); err != nil { - return errors.Wrap(err, "CheckForReceipts failed") + return fmt.Errorf("CheckForReceipts failed: %w", err) } ec.lggr.Debugw("Finished CheckForReceipts", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") mark = time.Now() if err := ec.RebroadcastWhereNecessary(ctx, head.BlockNumber()); err != nil { - return errors.Wrap(err, "RebroadcastWhereNecessary failed") + return fmt.Errorf("RebroadcastWhereNecessary failed: %w", err) } ec.lggr.Debugw("Finished RebroadcastWhereNecessary", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") mark = time.Now() if err := ec.EnsureConfirmedTransactionsInLongestChain(ctx, head); err != nil { - return errors.Wrap(err, "EnsureConfirmedTransactionsInLongestChain failed") + return fmt.Errorf("EnsureConfirmedTransactionsInLongestChain failed: %w", err) } ec.lggr.Debugw("Finished EnsureConfirmedTransactionsInLongestChain", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") @@ -310,7 +310,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro if ec.resumeCallback != nil { mark = time.Now() if err := ec.ResumePendingTaskRuns(ctx, head); err != nil { - return errors.Wrap(err, "ResumePendingTaskRuns failed") + return fmt.Errorf("ResumePendingTaskRuns failed: %w", err) } ec.lggr.Debugw("Finished ResumePendingTaskRuns", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") @@ -382,7 +382,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckForReceipts(ctx context.Context, blockNum int64) error { attempts, err := ec.txStore.FindTxAttemptsRequiringReceiptFetch(ctx, ec.chainID) if err != nil { - return errors.Wrap(err, "FindTxAttemptsRequiringReceiptFetch failed") + return fmt.Errorf("FindTxAttemptsRequiringReceiptFetch failed: %w", err) } if len(attempts) == 0 { return nil @@ -398,7 +398,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che for from, attempts := range attemptsByAddress { minedSequence, err := ec.getMinedSequenceForAddress(ctx, from) if err != nil { - return errors.Wrapf(err, "unable to fetch pending sequence for address: %v", from) + return fmt.Errorf("unable to fetch pending sequence for address: %v: %w", from, err) } // separateLikelyConfirmedAttempts is used as an optimisation: there is @@ -415,7 +415,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che start := time.Now() err = ec.fetchAndSaveReceipts(ctx, likelyConfirmed, blockNum) if err != nil { - return errors.Wrapf(err, "unable to fetch and save receipts for likely confirmed txs, for address: %v", from) + return fmt.Errorf("unable to fetch and save receipts for likely confirmed txs, for address: %v: %w", from, err) } ec.lggr.Debugw(fmt.Sprintf("Fetching and saving %v likely confirmed receipts done", likelyConfirmedCount), "time", time.Since(start)) @@ -423,11 +423,11 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che } if err := ec.txStore.MarkAllConfirmedMissingReceipt(ctx, ec.chainID); err != nil { - return errors.Wrap(err, "unable to mark txes as 'confirmed_missing_receipt'") + return fmt.Errorf("unable to mark txes as 'confirmed_missing_receipt': %w", err) } if err := ec.txStore.MarkOldTxesMissingReceiptAsErrored(ctx, blockNum, ec.chainConfig.FinalityDepth(), ec.chainID); err != nil { - return errors.Wrap(err, "unable to confirm buried unconfirmed txes") + return fmt.Errorf("unable to confirm buried unconfirmed txes': %w", err) } return nil } @@ -488,10 +488,10 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) fet receipts, err := ec.batchFetchReceipts(ctx, batch, blockNum) if err != nil { - return errors.Wrap(err, "batchFetchReceipts failed") + return fmt.Errorf("batchFetchReceipts failed: %w", err) } if err := ec.txStore.SaveFetchedReceipts(ctx, receipts, ec.chainID); err != nil { - return errors.Wrap(err, "saveFetchedReceipts failed") + return fmt.Errorf("saveFetchedReceipts failed: %w", err) } promNumConfirmedTxs.WithLabelValues(ec.chainID.String()).Add(float64(len(receipts))) @@ -514,7 +514,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat if ec.txConfig.ForwardersEnabled() { err = ec.txStore.PreloadTxes(ctx, attempts) if err != nil { - return nil, errors.Wrap(err, "Confirmer#batchFetchReceipts error loading txs for attempts") + return nil, fmt.Errorf("Confirmer#batchFetchReceipts error loading txs for attempts: %w", err) } } @@ -629,7 +629,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reb func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) rebroadcastWhereNecessary(ctx context.Context, address ADDR, blockHeight int64) error { if err := ec.handleAnyInProgressAttempts(ctx, address, blockHeight); err != nil { - return errors.Wrap(err, "handleAnyInProgressAttempts failed") + return fmt.Errorf("handleAnyInProgressAttempts failed: %w", err) } threshold := int64(ec.feeConfig.BumpThreshold()) @@ -637,24 +637,24 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) reb maxInFlightTransactions := ec.txConfig.MaxInFlight() etxs, err := ec.FindTxsRequiringRebroadcast(ctx, ec.lggr, address, blockHeight, threshold, bumpDepth, maxInFlightTransactions, ec.chainID) if err != nil { - return errors.Wrap(err, "FindTxsRequiringRebroadcast failed") + return fmt.Errorf("FindTxsRequiringRebroadcast failed: %w", err) } for _, etx := range etxs { lggr := etx.GetLogger(ec.lggr) attempt, err := ec.attemptForRebroadcast(ctx, lggr, *etx) if err != nil { - return errors.Wrap(err, "attemptForRebroadcast failed") + return fmt.Errorf("attemptForRebroadcast failed: %w", err) } lggr.Debugw("Rebroadcasting transaction", "nPreviousAttempts", len(etx.TxAttempts), "fee", attempt.TxFee) if err := ec.txStore.SaveInProgressAttempt(ctx, &attempt); err != nil { - return errors.Wrap(err, "saveInProgressAttempt failed") + return fmt.Errorf("saveInProgressAttempt failed: %w", err) } if err := ec.handleInProgressAttempt(ctx, lggr, *etx, attempt, blockHeight); err != nil { - return errors.Wrap(err, "handleInProgressAttempt failed") + return fmt.Errorf("handleInProgressAttempt failed: %w", err) } } return nil @@ -670,14 +670,14 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han if ctx.Err() != nil { return nil } else if err != nil { - return errors.Wrap(err, "GetInProgressTxAttempts failed") + return fmt.Errorf("GetInProgressTxAttempts failed: %w", err) } for _, a := range attempts { err := ec.handleInProgressAttempt(ctx, a.Tx.GetLogger(ec.lggr), a.Tx, a, blockHeight) if ctx.Err() != nil { break } else if err != nil { - return errors.Wrap(err, "handleInProgressAttempt failed") + return fmt.Errorf("handleInProgressAttempt failed: %w", err) } } return nil @@ -769,7 +769,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) att } return attempt, err } - return attempt, errors.Errorf("invariant violation: Tx %v was unconfirmed but didn't have any attempts. "+ + return attempt, fmt.Errorf("invariant violation: Tx %v was unconfirmed but didn't have any attempts. "+ "Falling back to default gas price instead."+ "This is a bug! Please report to https://github.com/smartcontractkit/chainlink/issues", etx.ID) } @@ -802,17 +802,17 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bum return bumpedAttempt, err } - if errors.Is(errors.Cause(err), commonfee.ErrBumpFeeExceedsLimit) { + if errors.Is(err, commonfee.ErrBumpFeeExceedsLimit) { promGasBumpExceedsLimit.WithLabelValues(ec.chainID.String()).Inc() } - return bumpedAttempt, errors.Wrap(err, "error bumping gas") + return bumpedAttempt, fmt.Errorf("error bumping gas: %w", err) } func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleInProgressAttempt(ctx context.Context, lggr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], blockHeight int64) error { if attempt.State != txmgrtypes.TxAttemptInProgress { - return errors.Errorf("invariant violation: expected tx_attempt %v to be in_progress, it was %s", attempt.ID, attempt.State) + return fmt.Errorf("invariant violation: expected tx_attempt %v to be in_progress, it was %s", attempt.ID, attempt.State) } now := time.Now() @@ -827,7 +827,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han // "Lazily" load attempts here since the overwhelmingly common case is // that we don't need them unless we enter this path if err := ec.txStore.LoadTxAttempts(ctx, &etx); err != nil { - return errors.Wrap(err, "failed to load TxAttempts while bumping on terminally underpriced error") + return fmt.Errorf("failed to load TxAttempts while bumping on terminally underpriced error: %w", err) } if len(etx.TxAttempts) == 0 { err := errors.New("expected to find at least 1 attempt") @@ -841,7 +841,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han } replacementAttempt, err := ec.bumpGas(ctx, etx, etx.TxAttempts) if err != nil { - return errors.Wrap(err, "could not bump gas for terminally underpriced transaction") + return fmt.Errorf("could not bump gas for terminally underpriced transaction: %w", err) } promNumGasBumps.WithLabelValues(ec.chainID.String()).Inc() logger.With(lggr, @@ -852,7 +852,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han ).Errorf("gas price was rejected by the node for being too low. Node returned: '%s'", sendError.Error()) if err := ec.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &replacementAttempt); err != nil { - return errors.Wrap(err, "saveReplacementInProgressAttempt failed") + return fmt.Errorf("saveReplacementInProgressAttempt failed: %w", err) } return ec.handleInProgressAttempt(ctx, lggr, etx, replacementAttempt, blockHeight) case client.ExceedsMaxFee: @@ -896,7 +896,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han // node operator. The node may have it in the mempool so we must keep the // attempt (leave it in_progress). Safest thing to do is bail out and wait // for the next head. - return errors.Wrapf(sendError, "unexpected error sending tx %v with hash %s", etx.ID, attempt.Hash.String()) + return fmt.Errorf("unexpected error sending tx %v with hash %s: %w", etx.ID, attempt.Hash.String(), sendError) } } @@ -924,13 +924,13 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Ens } etxs, err := ec.txStore.FindTransactionsConfirmedInBlockRange(ctx, head.BlockNumber(), head.EarliestHeadInChain().BlockNumber(), ec.chainID) if err != nil { - return errors.Wrap(err, "findTransactionsConfirmedInBlockRange failed") + return fmt.Errorf("findTransactionsConfirmedInBlockRange failed: %w", err) } for _, etx := range etxs { if !hasReceiptInLongestChain(*etx, head) { if err := ec.markForRebroadcast(*etx, head); err != nil { - return errors.Wrapf(err, "markForRebroadcast failed for etx %v", etx.ID) + return fmt.Errorf("markForRebroadcast failed for etx %v: %w", etx.ID, err) } } } @@ -983,7 +983,7 @@ func hasReceiptInLongestChain[ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) markForRebroadcast(etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], head types.Head[BLOCK_HASH]) error { if len(etx.TxAttempts) == 0 { - return errors.Errorf("invariant violation: expected tx %v to have at least one attempt", etx.ID) + return fmt.Errorf("invariant violation: expected tx %v to have at least one attempt", etx.ID) } // Rebroadcast the one with the highest gas price @@ -1016,8 +1016,11 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) mar ec.lggr.Infow(fmt.Sprintf("Re-org detected. Rebroadcasting transaction %s which may have been re-org'd out of the main chain", attempt.Hash.String()), logValues...) // Put it back in progress and delete all receipts (they do not apply to the new chain) - err := ec.txStore.UpdateTxForRebroadcast(ec.ctx, etx, attempt) - return errors.Wrap(err, "markForRebroadcast failed") + if err := ec.txStore.UpdateTxForRebroadcast(ec.ctx, etx, attempt); err != nil { + return fmt.Errorf("markForRebroadcast failed: %w", err) + } + + return nil } // ForceRebroadcast sends a transaction for every sequence in the given sequence range at the given gas price. @@ -1037,7 +1040,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For etx, err := ec.txStore.FindTxWithSequence(ctx, address, seq) if err != nil { - return errors.Wrap(err, "ForceRebroadcast failed") + return fmt.Errorf("ForceRebroadcast failed: %w", err) } if etx == nil { ec.lggr.Debugf("ForceRebroadcast: no tx found with sequence %s, will rebroadcast empty transaction", seq) @@ -1076,7 +1079,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) sen } txhash, err := ec.client.SendEmptyTransaction(ctx, ec.TxAttemptBuilder.NewEmptyTxAttempt, seq, gasLimit, fee, fromAddress) if err != nil { - return "", errors.Wrap(err, "(Confirmer).sendEmptyTransaction failed") + return "", fmt.Errorf("(Confirmer).sendEmptyTransaction failed: %w", err) } return txhash, nil } @@ -1099,7 +1102,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Res var taskErr error var output interface{} if data.FailOnRevert && data.Receipt.GetStatus() == 0 { - taskErr = errors.Errorf("transaction %s reverted on-chain", data.Receipt.GetTxHash()) + taskErr = fmt.Errorf("transaction %s reverted on-chain", data.Receipt.GetTxHash()) } else { output = data.Receipt } diff --git a/common/txmgr/strategies.go b/common/txmgr/strategies.go index b986d0d9b8..faba2ba97b 100644 --- a/common/txmgr/strategies.go +++ b/common/txmgr/strategies.go @@ -2,10 +2,10 @@ package txmgr import ( "context" + "fmt" "time" "github.com/google/uuid" - "github.com/pkg/errors" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" ) @@ -63,7 +63,7 @@ func (s DropOldestStrategy) PruneQueue(ctx context.Context, pruneService txmgrty n, err = pruneService.PruneUnstartedTxQueue(ctx, s.queueSize, s.subject) if err != nil { - return 0, errors.Wrap(err, "DropOldestStrategy#PruneQueue failed") + return 0, fmt.Errorf("DropOldestStrategy#PruneQueue failed: %w", err) } return } diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index b8a16561d8..3af43b1961 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -3,6 +3,7 @@ package types import ( "context" "encoding/json" + "errors" "fmt" "math/big" "slices" @@ -10,7 +11,6 @@ import ( "time" "github.com/google/uuid" - "github.com/pkg/errors" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -245,7 +245,11 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetMeta() (*TxMeta[A return nil, nil } var m TxMeta[ADDR, TX_HASH] - return &m, errors.Wrap(json.Unmarshal(*e.Meta, &m), "unmarshalling meta") + if err := json.Unmarshal(*e.Meta, &m); err != nil { + return nil, fmt.Errorf("unmarshalling meta: %w", err) + } + + return &m, nil } // GetLogger returns a new logger with metadata fields. @@ -320,5 +324,9 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetChecker() (Transm return TransmitCheckerSpec[ADDR]{}, nil } var t TransmitCheckerSpec[ADDR] - return t, errors.Wrap(json.Unmarshal(*e.TransmitChecker, &t), "unmarshalling transmit checker") + if err := json.Unmarshal(*e.TransmitChecker, &t); err != nil { + return t, fmt.Errorf("unmarshalling transmit checker: %w", err) + } + + return t, nil } From 006e3c7dd5bf249ca85891ee9b9a26ed926cc1d1 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Tue, 5 Dec 2023 14:15:09 +0200 Subject: [PATCH 272/327] Extract mathutil (#11446) * Extract mathutil * Fix dependencies --- .../chains/evm/gas/block_history_estimator.go | 2 +- core/chains/evm/logpoller/log_poller.go | 2 +- core/services/blockhashstore/feeder_test.go | 3 +- .../ocr2vrf/coordinator/coordinator.go | 3 +- .../ocr2vrf/coordinator/coordinator_test.go | 2 +- core/services/vrf/v1/listener_v1.go | 3 +- .../vrf/v2/listener_v2_log_listener.go | 2 +- core/sessions/ldapauth/ldap.go | 2 +- core/sessions/localauth/orm.go | 2 +- core/utils/mathutil/mathutil.go | 23 ------------- core/utils/mathutil/mathutil_test.go | 33 ------------------- 11 files changed, 12 insertions(+), 65 deletions(-) delete mode 100644 core/utils/mathutil/mathutil.go delete mode 100644 core/utils/mathutil/mathutil_test.go diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 64dc331f65..0ec4721b79 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" @@ -25,7 +26,6 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) // MaxStartTime is the maximum amount of time we are allowed to spend diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index de1999da26..fb380f84b2 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -22,12 +22,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) //go:generate mockery --quiet --name LogPoller --output ./mocks/ --case=underscore --structname LogPoller --filename log_poller.go diff --git a/core/services/blockhashstore/feeder_test.go b/core/services/blockhashstore/feeder_test.go index 8d9ed48c4b..ad03979840 100644 --- a/core/services/blockhashstore/feeder_test.go +++ b/core/services/blockhashstore/feeder_test.go @@ -14,9 +14,10 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" bhsmocks "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore/mocks" diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go index 6353894153..a25fcca9fe 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go @@ -23,6 +23,8 @@ import ( "github.com/smartcontractkit/libocr/commontypes" ocr2Types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/chainlink-vrf/dkg" ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" @@ -38,7 +40,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) var _ ocr2vrftypes.CoordinatorInterface = &coordinator{} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index 418e4356c6..9c3eb08798 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -27,6 +27,7 @@ import ( ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -38,7 +39,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) func TestCoordinator_BeaconPeriod(t *testing.T) { diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 494847797f..66a8ddcd58 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -17,6 +17,8 @@ import ( "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -28,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) var ( diff --git a/core/services/vrf/v2/listener_v2_log_listener.go b/core/services/vrf/v2/listener_v2_log_listener.go index b35593bd1c..07b4c2c380 100644 --- a/core/services/vrf/v2/listener_v2_log_listener.go +++ b/core/services/vrf/v2/listener_v2_log_listener.go @@ -10,12 +10,12 @@ import ( "github.com/ethereum/go-ethereum/common" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) func (lsn *listenerV2) runLogListener( diff --git a/core/sessions/ldapauth/ldap.go b/core/sessions/ldapauth/ldap.go index 04f6fbfbbb..147f8bd2ae 100644 --- a/core/sessions/ldapauth/ldap.go +++ b/core/sessions/ldapauth/ldap.go @@ -34,6 +34,7 @@ import ( "github.com/go-ldap/ldap/v3" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/config" @@ -42,7 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) const ( diff --git a/core/sessions/localauth/orm.go b/core/sessions/localauth/orm.go index 090dc468a6..013f719ad3 100644 --- a/core/sessions/localauth/orm.go +++ b/core/sessions/localauth/orm.go @@ -9,6 +9,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -16,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) type orm struct { diff --git a/core/utils/mathutil/mathutil.go b/core/utils/mathutil/mathutil.go deleted file mode 100644 index e9659a1f15..0000000000 --- a/core/utils/mathutil/mathutil.go +++ /dev/null @@ -1,23 +0,0 @@ -package mathutil - -import "golang.org/x/exp/constraints" - -func Max[V constraints.Ordered](first V, vals ...V) V { - max := first - for _, v := range vals { - if v > max { - max = v - } - } - return max -} - -func Min[V constraints.Ordered](first V, vals ...V) V { - min := first - for _, v := range vals { - if v < min { - min = v - } - } - return min -} diff --git a/core/utils/mathutil/mathutil_test.go b/core/utils/mathutil/mathutil_test.go deleted file mode 100644 index 24a464bb39..0000000000 --- a/core/utils/mathutil/mathutil_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package mathutil - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestMax(t *testing.T) { - // Happy path - assert.Equal(t, 3, Max(3, 2, 1)) - // Single element - assert.Equal(t, 3, Max(3)) - // Signed - assert.Equal(t, -1, Max(-2, -1)) - // Uint64 - assert.Equal(t, uint64(2), Max(uint64(0), uint64(2))) - // String - assert.Equal(t, "c", Max("a", []string{"b", "c"}...)) -} - -func TestMin(t *testing.T) { - // Happy path - assert.Equal(t, 1, Min(3, 2, 1)) - // Single element - assert.Equal(t, 3, Min(3)) - // Signed - assert.Equal(t, -2, Min(-2, -1)) - // Uint64 - assert.Equal(t, uint64(0), Min(uint64(0), uint64(2))) - // String - assert.Equal(t, "a", Min("a", []string{"b", "c"}...)) -} From 6cc81208ad45a89914cd5d36048ce646c1ac6272 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Tue, 5 Dec 2023 14:17:19 +0200 Subject: [PATCH 273/327] VRF-784: add contract loader client for BSC to run CTF tests there (#11494) --- integration-tests/contracts/contract_loader.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 6136e78b36..e66c95138b 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -71,6 +71,8 @@ func NewContractLoader(bcClient blockchain.EVMClient, logger zerolog.Logger) (Co return &PolygonZkEvmContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.WeMixClient: return &WeMixContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.BSCClient: + return &BSCContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract Loader, register blockchain client in NewContractLoader") } @@ -119,6 +121,11 @@ type WeMixContractLoader struct { *EthereumContractLoader } +// BSCContractLoader wraps ethereum contract deployments for BSC +type BSCContractLoader struct { + *EthereumContractLoader +} + // NewEthereumContractLoader returns an instantiated instance of the ETH contract Loader func NewEthereumContractLoader(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractLoader { return &EthereumContractLoader{ From 9d49a2002d8fb811ecbd754ac5171fb6c3807397 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:09:22 -0500 Subject: [PATCH 274/327] Check if ECR image exists before trying to publish (#11495) * Check if ECR image exists before trying to publish * Fix role to use correct secret --- .github/workflows/build-publish-pr.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml index a7186ee5a1..cdc9cf3f11 100644 --- a/.github/workflows/build-publish-pr.yml +++ b/.github/workflows/build-publish-pr.yml @@ -16,11 +16,31 @@ jobs: permissions: id-token: write contents: read + env: + ECR_IMAGE_NAME: crib-chainlink-untrusted steps: + - name: Git Short SHA + shell: bash + env: + GIT_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + echo "GIT_SHORT_SHA=${GIT_PR_HEAD_SHA:0:7}" | tee -a "$GITHUB_ENV" + + - name: Check if image exists + id: check-image + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + with: + repository: ${{ env.ECR_IMAGE_NAME}} + tag: sha-${{ env.GIT_SHORT_SHA }} + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} + - name: Checkout repository + if: steps.check-image.outputs.exists == 'false' uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Build and publish chainlink image + if: steps.check-image.outputs.exists == 'false' uses: ./.github/actions/build-sign-publish-chainlink with: publish: true @@ -29,7 +49,7 @@ jobs: aws-region: ${{ secrets.AWS_REGION }} sign-images: false ecr-hostname: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }} - ecr-image-name: crib-chainlink-untrusted + ecr-image-name: ${{ env.ECR_IMAGE_NAME }} dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} From cf9ab4ec36292468172ef178e774d06faca005c5 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Tue, 5 Dec 2023 18:34:10 +0200 Subject: [PATCH 275/327] =?UTF-8?q?VRF-782:=20Fix=20setup-env=20script=20i?= =?UTF-8?q?n=20order=20to=20include=20flag=20for=20deploying=20=E2=80=A6?= =?UTF-8?q?=20(#11445)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-782: Fix setup-env script in order to include flag for deploying VRFOwner contract * Update main.go * VRF-782: Fix setup-env script to create ETH key --------- Co-authored-by: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> --- core/scripts/common/vrf/setup-envs/README.md | 6 ++++-- core/scripts/common/vrf/setup-envs/main.go | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/scripts/common/vrf/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md index 9aa76ffbbb..5aa6aa4754 100644 --- a/core/scripts/common/vrf/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -38,7 +38,8 @@ go run . \ --batch-fulfillment-enabled="true" \ --min-confs=3 \ --register-vrf-key-against-address= +in order to call oracleWithdraw from this address> \ +--deploy-vrfv2-owner="true" ``` Optional parameters - will not be deployed if specified @@ -71,7 +72,7 @@ go run . \ --sending-key-funding-amount="1e17" \ --deploy-contracts-and-create-jobs="false" ``` -Then update corresponding deployment scripts with the new ETH addresses, specifying max gas price for each key +Then update corresponding deployment scripts in infra-k8s repo with the new ETH addresses, specifying max gas price for each key e.g.: ``` @@ -98,6 +99,7 @@ go run . \ --batch-fulfillment-enabled="true" \ --min-confs=3 \ --register-vrf-key-against-address="" \ +--deploy-vrfv2-owner="true" \ --link-address "" \ --link-eth-feed "" ``` diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index 94662aa183..e9ea252e4c 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -12,6 +12,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/shopspring/decimal" + "github.com/urfave/cli" + helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" @@ -21,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" - "github.com/urfave/cli" ) func newApp(remoteNodeURL string, writer io.Writer) (*clcmd.Shell, *cli.App) { @@ -87,6 +88,7 @@ func main() { batchCoordinatorAddressString := flag.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") registerVRFKeyAgainstAddress := flag.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") + deployVRFOwner := flag.Bool("deploy-vrfv2-owner", true, "whether to deploy VRF owner contracts") e := helpers.SetupEnv(false) flag.Parse() @@ -211,6 +213,7 @@ func main() { coordinatorConfigV2, *batchFulfillmentEnabled, nodesMap, + *deployVRFOwner, ) case "v2plus": feeConfigV2Plus := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ @@ -503,6 +506,7 @@ func createETHKeysIfNeeded(client *clcmd.Shell, app *cli.App, output *bytes.Buff var newKey presenters.ETHKeyResource flagSet := flag.NewFlagSet("blah", flag.ExitOnError) + flagSet.String("evm-chain-id", os.Getenv("ETH_CHAIN_ID"), "chain id") if *maxGasPriceGwei > 0 { helpers.PanicErr(flagSet.Set("max-gas-price-gwei", fmt.Sprintf("%d", *maxGasPriceGwei))) } From 14d22dfd39c5227ca2139108182a0b8801104f02 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:26:19 +0100 Subject: [PATCH 276/327] BCF-2823 Minor changes to distributeFunds (#11476) * Improve OperatorFactory deployNewOperatorAndForwarder natspec * Change to fwds distributeFunds to use call --- contracts/src/v0.8/operatorforwarder/dev/Operator.sol | 3 ++- contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol | 2 +- .../generated/operator_factory/operator_factory.go | 2 +- .../generated/operator_wrapper/operator_wrapper.go | 2 +- .../generated-wrapper-dependency-versions-do-not-edit.txt | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol index c8451bf03c..26295b27d1 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol @@ -318,7 +318,8 @@ contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, Oper for (uint256 i = 0; i < receivers.length; ++i) { uint256 sendAmount = amounts[i]; valueRemaining = valueRemaining - sendAmount; - receivers[i].transfer(sendAmount); + (bool success, ) = receivers[i].call{value: sendAmount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); } require(valueRemaining == 0, "Too much ETH sent"); } diff --git a/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol index 62ace2451c..0ff4bb6562 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol @@ -34,7 +34,7 @@ contract OperatorFactory { } // @notice creates a new Operator contract with the msg.sender as owner and a - // new Operator Forwarder with the Operator as the owner + // new Operator Forwarder with the OperatorFactory as the owner function deployNewOperatorAndForwarder() external returns (address, address) { Operator operator = new Operator(linkToken, msg.sender); s_created[address(operator)] = true; diff --git a/core/gethwrappers/generated/operator_factory/operator_factory.go b/core/gethwrappers/generated/operator_factory/operator_factory.go index c9a6c57ce2..c14ef43936 100644 --- a/core/gethwrappers/generated/operator_factory/operator_factory.go +++ b/core/gethwrappers/generated/operator_factory/operator_factory.go @@ -32,7 +32,7 @@ var ( var OperatorFactoryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AuthorizedForwarderCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"OperatorCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"created\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deployNewForwarderAndTransferOwnership\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperatorAndForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051615caf380380615caf83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051615c016100ae6000396000818161014f015281816101e6015281816102e3015281816103da015281816104be01526105a50152615c016000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c806357970e93116200006257806357970e931462000149578063d42efd831462000171578063d689d09514620001be578063f4adb6e114620001d557600080fd5b8063181f5a77146200008c57806332f01eae14620000e15780633babafdb1462000119575b600080fd5b620000c96040518060400160405280601581526020017f4f70657261746f72466163746f727920312e302e30000000000000000000000081525081565b604051620000d8919062000717565b60405180910390f35b620000eb620001df565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201620000d8565b62000123620003c6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001620000d8565b620001237f000000000000000000000000000000000000000000000000000000000000000081565b620001ad620001823660046200075d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6040519015158152602001620000d8565b62000123620001cf3660046200077b565b620004b9565b62000123620005a0565b60008060007f000000000000000000000000000000000000000000000000000000000000000033604051620002149062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000255573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4604080516000808252602082019092527f000000000000000000000000000000000000000000000000000000000000000090309084906040516200031590620006a3565b62000324949392919062000805565b604051809103906000f08015801562000341573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a490939092509050565b6040805160008082526020820190925281907f000000000000000000000000000000000000000000000000000000000000000090339083906040516200040c90620006a3565b6200041b949392919062000805565b604051809103906000f08015801562000438573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919050565b6000807f000000000000000000000000000000000000000000000000000000000000000033868686604051620004ef90620006a3565b620004ff95949392919062000852565b604051809103906000f0801580156200051c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f000000000000000000000000000000000000000000000000000000000000000033604051620005d39062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000614573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4919050565b613c8880620008d483390190565b611699806200455c83390190565b6000815180845260005b81811015620006d957602081850181015186830182015201620006bb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006200072c6020830184620006b1565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200075857600080fd5b919050565b6000602082840312156200077057600080fd5b6200072c8262000733565b6000806000604084860312156200079157600080fd5b6200079c8462000733565b9250602084013567ffffffffffffffff80821115620007ba57600080fd5b818601915086601f830112620007cf57600080fd5b813581811115620007df57600080fd5b876020828501011115620007f257600080fd5b6020830194508093505050509250925092565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015280851660408401525060806060830152620008486080830184620006b1565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501168301019050969550505050505056fe60a060405260016006553480156200001657600080fd5b5060405162003c8838038062003c888339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613a4362000245600039600081816101ec0152818161075e015281816109f301528181610c4f015281816117d201528181611a3c01528181611adc01528181611e7701528181612310015281816125c30152612b4b0152613a436000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612fbe565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004613064565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d91906130dd565b34801561029857600080fd5b506102a161096c565b60405161022d919061312e565b3480156102ba57600080fd5b506101bb6102c93660046131bd565b6109db565b3480156102da57600080fd5b506101bb6102e936600461324a565b610ae3565b3480156102fa57600080fd5b506101bb6103093660046132a1565b610c37565b34801561031a57600080fd5b5061032e610329366004613344565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb61039236600461339e565b611045565b3480156103a357600080fd5b5061032e6103b236600461340a565b6110c9565b6101bb6103c536600461339e565b611445565b3480156103d657600080fd5b506101bb6103e536600461348e565b6115d8565b3480156103f657600080fd5b506101bb61185c565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e6104453660046134cb565b61195d565b34801561045657600080fd5b506101bb61046536600461354a565b611ac4565b34801561047657600080fd5b506101bb61048536600461348e565b611c52565b34801561049657600080fd5b506101bb6104a5366004612fbe565b611f02565b3480156104b657600080fd5b506101bb6104c5366004613635565b612210565b3480156104d657600080fd5b506101bb6104e5366004613659565b612224565b3480156104f657600080fd5b5061032e610505366004613635565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b36600461339e565b612389565b6105586124e5565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e6613685565b90506020020160208101906105fb9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905582828281811061066057610660613685565b90506020020160208101906106759190613635565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c9613685565b90506020020160208101906106de9190613635565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b5050505080610747906136e3565b90506105c6565b505050565b61075b61253a565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b892919061371b565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a6125bd565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf99989796959493929190613774565b60405180910390a250505050505050505050565b610aeb61253a565b60005b82811015610c3157600060056000868685818110610b0e57610b0e613685565b9050602002016020810190610b239190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b88613685565b9050602002016020810190610b9d9190613635565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a906136e3565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a6125bd565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b99989796959493929190613774565b60405180910390a25050505050505050505050565b6000610d4a61289b565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c89898989896001612914565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906137ff565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612b0c565b905090565b61104d6124e5565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612389565b60006110d361289b565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e6002612914565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b49392919061381b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916137ff565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b8481101561156f5760008484838181106114d9576114d9613685565b90506020020135905080836114ee9190613857565b925086868381811061150257611502613685565b90506020020160208101906115179190613635565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f1935050505015801561155c573d6000803e3d6000fd5b505080611568906136e3565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146116fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42821115611765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118549190613870565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600061196761253a565b8380611971612b0c565b10156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611a77908990899089908990600401613892565b6020604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190613870565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611b748183612bd5565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611ba791906137ff565b600060405180830381855af49150503d8060008114611be2576040519150601f19603f3d011682016040523d82523d6000602084013e611be7565b606091505b5050905080611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611da0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef99190613870565b50505050505050565b611f0a6124e5565b611f70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611fd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b8181101561206c57600080600060018481548110611ffd57611ffd613685565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612065816136e3565b9050611fdd565b5060005b828110156121c25760008085858481811061208d5761208d613685565b90506020020160208101906120a29190613635565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615612133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b600160008086868581811061214a5761214a613685565b905060200201602081019061215f9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556121bb816136e3565b9050612070565b506121cf60018484612ede565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122039392919061391e565b60405180910390a1505050565b61221861253a565b61222181612d51565b50565b61222c61253a565b8080612236612b0c565b10156122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190613870565b61074e5761074e613958565b6123916124e5565b6123f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e7727848484843360405161242e959493929190613987565b60405180910390a160005b838110156109655784848281811061245357612453613685565b90506020020160208101906124689190613635565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b81526004016124a29291906139d7565b600060405180830381600087803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050806124de906136e3565b9050612439565b3360009081526020819052604081205460ff168061104057503361251e60025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612676576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001615612781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61278d61012c426139f3565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161282c87612e47565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c91909117905560065461288b908a906139f3565b6006555050965096945050505050565b3360009081526020819052604090205460ff166125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612a4182612e47565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612ae4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612af29190613857565b600655505050600093845250506004602052506040812055565b60006001600654612b1d9190613857565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ba7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bcb9190613a06565b6110409190613857565b612be160026020613a1f565b612bec9060046139f3565b81511015612c56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612ce757507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612dd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612f56579160200282015b82811115612f565781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612efe565b50612eda9291505b80821115612eda5760008155600101612f5e565b60008083601f840112612f8457600080fd5b50813567ffffffffffffffff811115612f9c57600080fd5b6020830191508360208260051b8501011115612fb757600080fd5b9250929050565b60008060208385031215612fd157600080fd5b823567ffffffffffffffff811115612fe857600080fd5b612ff485828601612f72565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461222157600080fd5b60008083601f84011261303457600080fd5b50813567ffffffffffffffff81111561304c57600080fd5b602083019150836020828501011115612fb757600080fd5b60008060006040848603121561307957600080fd5b833561308481613000565b9250602084013567ffffffffffffffff8111156130a057600080fd5b6130ac86828701613022565b9497909650939450505050565b60005b838110156130d45781810151838201526020016130bc565b50506000910152565b60208152600082518060208401526130fc8160408501602087016130b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561317c57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161314a565b50909695505050505050565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146131b857600080fd5b919050565b60008060008060008060008060e0898b0312156131d957600080fd5b88356131e481613000565b9750602089013596506040890135955061320060608a01613188565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561322a57600080fd5b6132368b828c01613022565b999c989b5096995094979396929594505050565b60008060006040848603121561325f57600080fd5b833567ffffffffffffffff81111561327657600080fd5b61328286828701612f72565b909450925050602084013561329681613000565b809150509250925092565b60008060008060008060008060006101008a8c0312156132c057600080fd5b89356132cb81613000565b985060208a0135975060408a0135965060608a01356132e981613000565b95506132f760808b01613188565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561332157600080fd5b61332d8c828d01613022565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561335d57600080fd5b8635955060208701359450604087013561337681613000565b935061338460608801613188565b92506080870135915060a087013590509295509295509295565b600080600080604085870312156133b457600080fd5b843567ffffffffffffffff808211156133cc57600080fd5b6133d888838901612f72565b909650945060208701359150808211156133f157600080fd5b506133fe87828801612f72565b95989497509550505050565b600080600080600080600060c0888a03121561342557600080fd5b8735965060208801359550604088013561343e81613000565b945061344c60608901613188565b93506080880135925060a088013567ffffffffffffffff81111561346f57600080fd5b61347b8a828b01613022565b989b979a50959850939692959293505050565b600080600080608085870312156134a457600080fd5b84359350602085013592506134bb60408601613188565b9396929550929360600135925050565b600080600080606085870312156134e157600080fd5b84356134ec81613000565b935060208501359250604085013567ffffffffffffffff81111561350f57600080fd5b6133fe87828801613022565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561355f57600080fd5b833561356a81613000565b925060208401359150604084013567ffffffffffffffff8082111561358e57600080fd5b818601915086601f8301126135a257600080fd5b8135818111156135b4576135b461351b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135fa576135fa61351b565b8160405282815289602084870101111561361357600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561364757600080fd5b813561365281613000565b9392505050565b6000806040838503121561366c57600080fd5b823561367781613000565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613714576137146136b4565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e08401526137ef818401858761372b565b9c9b505050505050505050505050565b600082516138118184602087016130b9565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b8181038181111561386a5761386a6136b4565b92915050565b60006020828403121561388257600080fd5b8151801515811461365257600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611aba60608301848661372b565b8183526000602080850194508260005b858110156139135781356138eb81613000565b73ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016138d8565b509495945050505050565b6040815260006139326040830185876138c8565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60608152600061399b6060830187896138c8565b82810360208401526139ae8186886138c8565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b6020815260006139eb6020830184866138c8565b949350505050565b8082018082111561386a5761386a6136b4565b600060208284031215613a1857600080fd5b5051919050565b808202811582820484141761386a5761386a6136b456fea164736f6c6343000813000a60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000aa164736f6c6343000813000a", + Bin: "0x60a060405234801561001057600080fd5b50604051615d59380380615d5983398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051615cab6100ae6000396000818161014f015281816101e6015281816102e3015281816103da015281816104be01526105a50152615cab6000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c806357970e93116200006257806357970e931462000149578063d42efd831462000171578063d689d09514620001be578063f4adb6e114620001d557600080fd5b8063181f5a77146200008c57806332f01eae14620000e15780633babafdb1462000119575b600080fd5b620000c96040518060400160405280601581526020017f4f70657261746f72466163746f727920312e302e30000000000000000000000081525081565b604051620000d8919062000717565b60405180910390f35b620000eb620001df565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201620000d8565b62000123620003c6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001620000d8565b620001237f000000000000000000000000000000000000000000000000000000000000000081565b620001ad620001823660046200075d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6040519015158152602001620000d8565b62000123620001cf3660046200077b565b620004b9565b62000123620005a0565b60008060007f000000000000000000000000000000000000000000000000000000000000000033604051620002149062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000255573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4604080516000808252602082019092527f000000000000000000000000000000000000000000000000000000000000000090309084906040516200031590620006a3565b62000324949392919062000805565b604051809103906000f08015801562000341573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a490939092509050565b6040805160008082526020820190925281907f000000000000000000000000000000000000000000000000000000000000000090339083906040516200040c90620006a3565b6200041b949392919062000805565b604051809103906000f08015801562000438573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919050565b6000807f000000000000000000000000000000000000000000000000000000000000000033868686604051620004ef90620006a3565b620004ff95949392919062000852565b604051809103906000f0801580156200051c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f000000000000000000000000000000000000000000000000000000000000000033604051620005d39062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000614573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4919050565b613d3280620008d483390190565b611699806200460683390190565b6000815180845260005b81811015620006d957602081850181015186830182015201620006bb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006200072c6020830184620006b1565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200075857600080fd5b919050565b6000602082840312156200077057600080fd5b6200072c8262000733565b6000806000604084860312156200079157600080fd5b6200079c8462000733565b9250602084013567ffffffffffffffff80821115620007ba57600080fd5b818601915086601f830112620007cf57600080fd5b813581811115620007df57600080fd5b876020828501011115620007f257600080fd5b6020830194508093505050509250925092565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015280851660408401525060806060830152620008486080830184620006b1565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501168301019050969550505050505056fe60a060405260016006553480156200001657600080fd5b5060405162003d3238038062003d328339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613aed62000245600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161187c01528181611ae601528181611b8601528181611f21015281816123ba0152818161266d0152612bf50152613aed6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004613068565b610550565b005b3480156101c957600080fd5b506101bb6101d836600461310e565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190613187565b34801561029857600080fd5b506102a161096c565b60405161022d91906131d8565b3480156102ba57600080fd5b506101bb6102c9366004613267565b6109db565b3480156102da57600080fd5b506101bb6102e93660046132f4565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461334b565b610c37565b34801561031a57600080fd5b5061032e6103293660046133ee565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613448565b611045565b3480156103a357600080fd5b5061032e6103b23660046134b4565b6110c9565b6101bb6103c5366004613448565b611445565b3480156103d657600080fd5b506101bb6103e5366004613538565b611682565b3480156103f657600080fd5b506101bb611906565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613575565b611a07565b34801561045657600080fd5b506101bb6104653660046135f4565b611b6e565b34801561047657600080fd5b506101bb610485366004613538565b611cfc565b34801561049657600080fd5b506101bb6104a5366004613068565b611fac565b3480156104b657600080fd5b506101bb6104c53660046136df565b6122ba565b3480156104d657600080fd5b506101bb6104e5366004613703565b6122ce565b3480156104f657600080fd5b5061032e6105053660046136df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613448565b612433565b61055861258f565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e661372f565b90506020020160208101906105fb91906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558282828181106106605761066061372f565b905060200201602081019061067591906136df565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c961372f565b90506020020160208101906106de91906136df565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061378d565b90506105c6565b505050565b61075b6125e4565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b89291906137c5565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612667565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf9998979695949392919061381e565b60405180910390a250505050505050505050565b610aeb6125e4565b60005b82811015610c3157600060056000868685818110610b0e57610b0e61372f565b9050602002016020810190610b2391906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b8861372f565b9050602002016020810190610b9d91906136df565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061378d565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612667565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b9998979695949392919061381e565b60405180910390a25050505050505050505050565b6000610d4a612945565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c898989898960016129be565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906138a9565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612bb6565b905090565b61104d61258f565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612433565b60006110d3612945565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e60026129be565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b4939291906138c5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916138a9565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d961372f565b90506020020135905080836114ee9190613901565b925060008787848181106115045761150461372f565b905060200201602081019061151991906136df565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061378d565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe919061391a565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a116125e4565b8380611a1b612bb6565b1015611aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b2190899089908990899060040161393c565b6020604051808303816000875af1158015611b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b64919061391a565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c1e8183612c7f565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c5191906138a9565b600060405180830381855af49150503d8060008114611c8c576040519150601f19603f3d011682016040523d82523d6000602084013e611c91565b606091505b50509050806118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611eb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa3919061391a565b50505050505050565b611fb461258f565b61201a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80612081576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015612116576000806000600184815481106120a7576120a761372f565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561210f8161378d565b9050612087565b5060005b8281101561226c576000808585848181106121375761213761372f565b905060200201602081019061214c91906136df565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b60016000808686858181106121f4576121f461372f565b905060200201602081019061220991906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556122658161378d565b905061211a565b5061227960018484612f88565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122ad939291906139c8565b60405180910390a1505050565b6122c26125e4565b6122cb81612dfb565b50565b6122d66125e4565b80806122e0612bb6565b101561236e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612403573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612427919061391a565b61074e5761074e613a02565b61243b61258f565b6124a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516124d8959493929190613a31565b60405180910390a160005b83811015610965578484828181106124fd576124fd61372f565b905060200201602081019061251291906136df565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161254c929190613a81565b600060405180830381600087803b15801561256657600080fd5b505af115801561257a573d6000803e3d6000fd5b50505050806125889061378d565b90506124e3565b3360009081526020819052604081205460ff16806110405750336125c860025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612720576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00161561282b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61283761012c42613a9d565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff191681526020016128d687612ef1565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c919091179055600654612935908a90613a9d565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612aeb82612ef1565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612b8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612b9c9190613901565b600655505050600093845250506004602052506040812055565b60006001600654612bc79190613901565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c759190613ab0565b6110409190613901565b612c8b60026020613ac9565b612c96906004613a9d565b81511015612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612d9157507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612df7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612e7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215613000579160200282015b828111156130005781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612fa8565b50612f849291505b80821115612f845760008155600101613008565b60008083601f84011261302e57600080fd5b50813567ffffffffffffffff81111561304657600080fd5b6020830191508360208260051b850101111561306157600080fd5b9250929050565b6000806020838503121561307b57600080fd5b823567ffffffffffffffff81111561309257600080fd5b61309e8582860161301c565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146122cb57600080fd5b60008083601f8401126130de57600080fd5b50813567ffffffffffffffff8111156130f657600080fd5b60208301915083602082850101111561306157600080fd5b60008060006040848603121561312357600080fd5b833561312e816130aa565b9250602084013567ffffffffffffffff81111561314a57600080fd5b613156868287016130cc565b9497909650939450505050565b60005b8381101561317e578181015183820152602001613166565b50506000910152565b60208152600082518060208401526131a6816040850160208701613163565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561322657835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016131f4565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461326257600080fd5b919050565b60008060008060008060008060e0898b03121561328357600080fd5b883561328e816130aa565b975060208901359650604089013595506132aa60608a01613232565b94506080890135935060a0890135925060c089013567ffffffffffffffff8111156132d457600080fd5b6132e08b828c016130cc565b999c989b5096995094979396929594505050565b60008060006040848603121561330957600080fd5b833567ffffffffffffffff81111561332057600080fd5b61332c8682870161301c565b9094509250506020840135613340816130aa565b809150509250925092565b60008060008060008060008060006101008a8c03121561336a57600080fd5b8935613375816130aa565b985060208a0135975060408a0135965060608a0135613393816130aa565b95506133a160808b01613232565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff8111156133cb57600080fd5b6133d78c828d016130cc565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561340757600080fd5b86359550602087013594506040870135613420816130aa565b935061342e60608801613232565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561345e57600080fd5b843567ffffffffffffffff8082111561347657600080fd5b6134828883890161301c565b9096509450602087013591508082111561349b57600080fd5b506134a88782880161301c565b95989497509550505050565b600080600080600080600060c0888a0312156134cf57600080fd5b873596506020880135955060408801356134e8816130aa565b94506134f660608901613232565b93506080880135925060a088013567ffffffffffffffff81111561351957600080fd5b6135258a828b016130cc565b989b979a50959850939692959293505050565b6000806000806080858703121561354e57600080fd5b843593506020850135925061356560408601613232565b9396929550929360600135925050565b6000806000806060858703121561358b57600080fd5b8435613596816130aa565b935060208501359250604085013567ffffffffffffffff8111156135b957600080fd5b6134a8878288016130cc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561360957600080fd5b8335613614816130aa565b925060208401359150604084013567ffffffffffffffff8082111561363857600080fd5b818601915086601f83011261364c57600080fd5b81358181111561365e5761365e6135c5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156136a4576136a46135c5565b816040528281528960208487010111156136bd57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156136f157600080fd5b81356136fc816130aa565b9392505050565b6000806040838503121561371657600080fd5b8235613721816130aa565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036137be576137be61375e565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261389981840185876137d5565b9c9b505050505050505050505050565b600082516138bb818460208701613163565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156139145761391461375e565b92915050565b60006020828403121561392c57600080fd5b815180151581146136fc57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b646060830184866137d5565b8183526000602080850194508260005b858110156139bd578135613995816130aa565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613982565b509495945050505050565b6040815260006139dc604083018587613972565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613a45606083018789613972565b8281036020840152613a58818688613972565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613a95602083018486613972565b949350505050565b808201808211156139145761391461375e565b600060208284031215613ac257600080fd5b5051919050565b80820281158282048414176139145761391461375e56fea164736f6c6343000813000a60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000aa164736f6c6343000813000a", } var OperatorFactoryABI = OperatorFactoryMetaData.ABI diff --git a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go index 4b7f634763..db0ca418b2 100644 --- a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go +++ b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go @@ -32,7 +32,7 @@ var ( var OperatorMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"AuthorizedSendersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CancelOracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"callbackAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cancelExpiration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"acceptedContract\",\"type\":\"address\"}],\"name\":\"OwnableContractAccepted\",\"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\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"TargetsUpdatedAuthorizedSenders\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"EXPIRYTIME\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"acceptAuthorizedReceivers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"}],\"name\":\"acceptOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequestByRequester\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable[]\",\"name\":\"receivers\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"distributeFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"data\",\"type\":\"bytes32\"}],\"name\":\"fulfillOracleRequest\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"fulfillOracleRequest2\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAuthorizedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainlinkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isAuthorizedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"operatorRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"oracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerTransferAndCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSenders\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSendersOn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003c8838038062003c888339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613a4362000245600039600081816101ec0152818161075e015281816109f301528181610c4f015281816117d201528181611a3c01528181611adc01528181611e7701528181612310015281816125c30152612b4b0152613a436000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612fbe565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004613064565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d91906130dd565b34801561029857600080fd5b506102a161096c565b60405161022d919061312e565b3480156102ba57600080fd5b506101bb6102c93660046131bd565b6109db565b3480156102da57600080fd5b506101bb6102e936600461324a565b610ae3565b3480156102fa57600080fd5b506101bb6103093660046132a1565b610c37565b34801561031a57600080fd5b5061032e610329366004613344565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb61039236600461339e565b611045565b3480156103a357600080fd5b5061032e6103b236600461340a565b6110c9565b6101bb6103c536600461339e565b611445565b3480156103d657600080fd5b506101bb6103e536600461348e565b6115d8565b3480156103f657600080fd5b506101bb61185c565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e6104453660046134cb565b61195d565b34801561045657600080fd5b506101bb61046536600461354a565b611ac4565b34801561047657600080fd5b506101bb61048536600461348e565b611c52565b34801561049657600080fd5b506101bb6104a5366004612fbe565b611f02565b3480156104b657600080fd5b506101bb6104c5366004613635565b612210565b3480156104d657600080fd5b506101bb6104e5366004613659565b612224565b3480156104f657600080fd5b5061032e610505366004613635565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b36600461339e565b612389565b6105586124e5565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e6613685565b90506020020160208101906105fb9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905582828281811061066057610660613685565b90506020020160208101906106759190613635565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c9613685565b90506020020160208101906106de9190613635565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b5050505080610747906136e3565b90506105c6565b505050565b61075b61253a565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b892919061371b565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a6125bd565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf99989796959493929190613774565b60405180910390a250505050505050505050565b610aeb61253a565b60005b82811015610c3157600060056000868685818110610b0e57610b0e613685565b9050602002016020810190610b239190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b88613685565b9050602002016020810190610b9d9190613635565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a906136e3565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a6125bd565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b99989796959493929190613774565b60405180910390a25050505050505050505050565b6000610d4a61289b565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c89898989896001612914565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906137ff565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612b0c565b905090565b61104d6124e5565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612389565b60006110d361289b565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e6002612914565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b49392919061381b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916137ff565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b8481101561156f5760008484838181106114d9576114d9613685565b90506020020135905080836114ee9190613857565b925086868381811061150257611502613685565b90506020020160208101906115179190613635565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f1935050505015801561155c573d6000803e3d6000fd5b505080611568906136e3565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146116fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42821115611765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118549190613870565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600061196761253a565b8380611971612b0c565b10156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611a77908990899089908990600401613892565b6020604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190613870565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611b748183612bd5565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611ba791906137ff565b600060405180830381855af49150503d8060008114611be2576040519150601f19603f3d011682016040523d82523d6000602084013e611be7565b606091505b5050905080611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611da0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef99190613870565b50505050505050565b611f0a6124e5565b611f70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611fd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b8181101561206c57600080600060018481548110611ffd57611ffd613685565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612065816136e3565b9050611fdd565b5060005b828110156121c25760008085858481811061208d5761208d613685565b90506020020160208101906120a29190613635565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615612133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b600160008086868581811061214a5761214a613685565b905060200201602081019061215f9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556121bb816136e3565b9050612070565b506121cf60018484612ede565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122039392919061391e565b60405180910390a1505050565b61221861253a565b61222181612d51565b50565b61222c61253a565b8080612236612b0c565b10156122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190613870565b61074e5761074e613958565b6123916124e5565b6123f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e7727848484843360405161242e959493929190613987565b60405180910390a160005b838110156109655784848281811061245357612453613685565b90506020020160208101906124689190613635565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b81526004016124a29291906139d7565b600060405180830381600087803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050806124de906136e3565b9050612439565b3360009081526020819052604081205460ff168061104057503361251e60025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612676576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001615612781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61278d61012c426139f3565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161282c87612e47565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c91909117905560065461288b908a906139f3565b6006555050965096945050505050565b3360009081526020819052604090205460ff166125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612a4182612e47565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612ae4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612af29190613857565b600655505050600093845250506004602052506040812055565b60006001600654612b1d9190613857565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ba7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bcb9190613a06565b6110409190613857565b612be160026020613a1f565b612bec9060046139f3565b81511015612c56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612ce757507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612dd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612f56579160200282015b82811115612f565781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612efe565b50612eda9291505b80821115612eda5760008155600101612f5e565b60008083601f840112612f8457600080fd5b50813567ffffffffffffffff811115612f9c57600080fd5b6020830191508360208260051b8501011115612fb757600080fd5b9250929050565b60008060208385031215612fd157600080fd5b823567ffffffffffffffff811115612fe857600080fd5b612ff485828601612f72565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461222157600080fd5b60008083601f84011261303457600080fd5b50813567ffffffffffffffff81111561304c57600080fd5b602083019150836020828501011115612fb757600080fd5b60008060006040848603121561307957600080fd5b833561308481613000565b9250602084013567ffffffffffffffff8111156130a057600080fd5b6130ac86828701613022565b9497909650939450505050565b60005b838110156130d45781810151838201526020016130bc565b50506000910152565b60208152600082518060208401526130fc8160408501602087016130b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561317c57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161314a565b50909695505050505050565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146131b857600080fd5b919050565b60008060008060008060008060e0898b0312156131d957600080fd5b88356131e481613000565b9750602089013596506040890135955061320060608a01613188565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561322a57600080fd5b6132368b828c01613022565b999c989b5096995094979396929594505050565b60008060006040848603121561325f57600080fd5b833567ffffffffffffffff81111561327657600080fd5b61328286828701612f72565b909450925050602084013561329681613000565b809150509250925092565b60008060008060008060008060006101008a8c0312156132c057600080fd5b89356132cb81613000565b985060208a0135975060408a0135965060608a01356132e981613000565b95506132f760808b01613188565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561332157600080fd5b61332d8c828d01613022565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561335d57600080fd5b8635955060208701359450604087013561337681613000565b935061338460608801613188565b92506080870135915060a087013590509295509295509295565b600080600080604085870312156133b457600080fd5b843567ffffffffffffffff808211156133cc57600080fd5b6133d888838901612f72565b909650945060208701359150808211156133f157600080fd5b506133fe87828801612f72565b95989497509550505050565b600080600080600080600060c0888a03121561342557600080fd5b8735965060208801359550604088013561343e81613000565b945061344c60608901613188565b93506080880135925060a088013567ffffffffffffffff81111561346f57600080fd5b61347b8a828b01613022565b989b979a50959850939692959293505050565b600080600080608085870312156134a457600080fd5b84359350602085013592506134bb60408601613188565b9396929550929360600135925050565b600080600080606085870312156134e157600080fd5b84356134ec81613000565b935060208501359250604085013567ffffffffffffffff81111561350f57600080fd5b6133fe87828801613022565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561355f57600080fd5b833561356a81613000565b925060208401359150604084013567ffffffffffffffff8082111561358e57600080fd5b818601915086601f8301126135a257600080fd5b8135818111156135b4576135b461351b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135fa576135fa61351b565b8160405282815289602084870101111561361357600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561364757600080fd5b813561365281613000565b9392505050565b6000806040838503121561366c57600080fd5b823561367781613000565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613714576137146136b4565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e08401526137ef818401858761372b565b9c9b505050505050505050505050565b600082516138118184602087016130b9565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b8181038181111561386a5761386a6136b4565b92915050565b60006020828403121561388257600080fd5b8151801515811461365257600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611aba60608301848661372b565b8183526000602080850194508260005b858110156139135781356138eb81613000565b73ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016138d8565b509495945050505050565b6040815260006139326040830185876138c8565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60608152600061399b6060830187896138c8565b82810360208401526139ae8186886138c8565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b6020815260006139eb6020830184866138c8565b949350505050565b8082018082111561386a5761386a6136b4565b600060208284031215613a1857600080fd5b5051919050565b808202811582820484141761386a5761386a6136b456fea164736f6c6343000813000a", + Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003d3238038062003d328339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613aed62000245600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161187c01528181611ae601528181611b8601528181611f21015281816123ba0152818161266d0152612bf50152613aed6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004613068565b610550565b005b3480156101c957600080fd5b506101bb6101d836600461310e565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190613187565b34801561029857600080fd5b506102a161096c565b60405161022d91906131d8565b3480156102ba57600080fd5b506101bb6102c9366004613267565b6109db565b3480156102da57600080fd5b506101bb6102e93660046132f4565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461334b565b610c37565b34801561031a57600080fd5b5061032e6103293660046133ee565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613448565b611045565b3480156103a357600080fd5b5061032e6103b23660046134b4565b6110c9565b6101bb6103c5366004613448565b611445565b3480156103d657600080fd5b506101bb6103e5366004613538565b611682565b3480156103f657600080fd5b506101bb611906565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613575565b611a07565b34801561045657600080fd5b506101bb6104653660046135f4565b611b6e565b34801561047657600080fd5b506101bb610485366004613538565b611cfc565b34801561049657600080fd5b506101bb6104a5366004613068565b611fac565b3480156104b657600080fd5b506101bb6104c53660046136df565b6122ba565b3480156104d657600080fd5b506101bb6104e5366004613703565b6122ce565b3480156104f657600080fd5b5061032e6105053660046136df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613448565b612433565b61055861258f565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e661372f565b90506020020160208101906105fb91906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558282828181106106605761066061372f565b905060200201602081019061067591906136df565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c961372f565b90506020020160208101906106de91906136df565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061378d565b90506105c6565b505050565b61075b6125e4565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b89291906137c5565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612667565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf9998979695949392919061381e565b60405180910390a250505050505050505050565b610aeb6125e4565b60005b82811015610c3157600060056000868685818110610b0e57610b0e61372f565b9050602002016020810190610b2391906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b8861372f565b9050602002016020810190610b9d91906136df565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061378d565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612667565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b9998979695949392919061381e565b60405180910390a25050505050505050505050565b6000610d4a612945565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c898989898960016129be565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906138a9565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612bb6565b905090565b61104d61258f565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612433565b60006110d3612945565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e60026129be565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b4939291906138c5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916138a9565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d961372f565b90506020020135905080836114ee9190613901565b925060008787848181106115045761150461372f565b905060200201602081019061151991906136df565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061378d565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe919061391a565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a116125e4565b8380611a1b612bb6565b1015611aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b2190899089908990899060040161393c565b6020604051808303816000875af1158015611b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b64919061391a565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c1e8183612c7f565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c5191906138a9565b600060405180830381855af49150503d8060008114611c8c576040519150601f19603f3d011682016040523d82523d6000602084013e611c91565b606091505b50509050806118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611eb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa3919061391a565b50505050505050565b611fb461258f565b61201a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80612081576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015612116576000806000600184815481106120a7576120a761372f565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561210f8161378d565b9050612087565b5060005b8281101561226c576000808585848181106121375761213761372f565b905060200201602081019061214c91906136df565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b60016000808686858181106121f4576121f461372f565b905060200201602081019061220991906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556122658161378d565b905061211a565b5061227960018484612f88565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122ad939291906139c8565b60405180910390a1505050565b6122c26125e4565b6122cb81612dfb565b50565b6122d66125e4565b80806122e0612bb6565b101561236e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612403573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612427919061391a565b61074e5761074e613a02565b61243b61258f565b6124a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516124d8959493929190613a31565b60405180910390a160005b83811015610965578484828181106124fd576124fd61372f565b905060200201602081019061251291906136df565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161254c929190613a81565b600060405180830381600087803b15801561256657600080fd5b505af115801561257a573d6000803e3d6000fd5b50505050806125889061378d565b90506124e3565b3360009081526020819052604081205460ff16806110405750336125c860025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612720576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00161561282b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61283761012c42613a9d565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff191681526020016128d687612ef1565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c919091179055600654612935908a90613a9d565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612aeb82612ef1565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612b8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612b9c9190613901565b600655505050600093845250506004602052506040812055565b60006001600654612bc79190613901565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c759190613ab0565b6110409190613901565b612c8b60026020613ac9565b612c96906004613a9d565b81511015612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612d9157507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612df7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612e7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215613000579160200282015b828111156130005781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612fa8565b50612f849291505b80821115612f845760008155600101613008565b60008083601f84011261302e57600080fd5b50813567ffffffffffffffff81111561304657600080fd5b6020830191508360208260051b850101111561306157600080fd5b9250929050565b6000806020838503121561307b57600080fd5b823567ffffffffffffffff81111561309257600080fd5b61309e8582860161301c565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146122cb57600080fd5b60008083601f8401126130de57600080fd5b50813567ffffffffffffffff8111156130f657600080fd5b60208301915083602082850101111561306157600080fd5b60008060006040848603121561312357600080fd5b833561312e816130aa565b9250602084013567ffffffffffffffff81111561314a57600080fd5b613156868287016130cc565b9497909650939450505050565b60005b8381101561317e578181015183820152602001613166565b50506000910152565b60208152600082518060208401526131a6816040850160208701613163565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561322657835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016131f4565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461326257600080fd5b919050565b60008060008060008060008060e0898b03121561328357600080fd5b883561328e816130aa565b975060208901359650604089013595506132aa60608a01613232565b94506080890135935060a0890135925060c089013567ffffffffffffffff8111156132d457600080fd5b6132e08b828c016130cc565b999c989b5096995094979396929594505050565b60008060006040848603121561330957600080fd5b833567ffffffffffffffff81111561332057600080fd5b61332c8682870161301c565b9094509250506020840135613340816130aa565b809150509250925092565b60008060008060008060008060006101008a8c03121561336a57600080fd5b8935613375816130aa565b985060208a0135975060408a0135965060608a0135613393816130aa565b95506133a160808b01613232565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff8111156133cb57600080fd5b6133d78c828d016130cc565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561340757600080fd5b86359550602087013594506040870135613420816130aa565b935061342e60608801613232565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561345e57600080fd5b843567ffffffffffffffff8082111561347657600080fd5b6134828883890161301c565b9096509450602087013591508082111561349b57600080fd5b506134a88782880161301c565b95989497509550505050565b600080600080600080600060c0888a0312156134cf57600080fd5b873596506020880135955060408801356134e8816130aa565b94506134f660608901613232565b93506080880135925060a088013567ffffffffffffffff81111561351957600080fd5b6135258a828b016130cc565b989b979a50959850939692959293505050565b6000806000806080858703121561354e57600080fd5b843593506020850135925061356560408601613232565b9396929550929360600135925050565b6000806000806060858703121561358b57600080fd5b8435613596816130aa565b935060208501359250604085013567ffffffffffffffff8111156135b957600080fd5b6134a8878288016130cc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561360957600080fd5b8335613614816130aa565b925060208401359150604084013567ffffffffffffffff8082111561363857600080fd5b818601915086601f83011261364c57600080fd5b81358181111561365e5761365e6135c5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156136a4576136a46135c5565b816040528281528960208487010111156136bd57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156136f157600080fd5b81356136fc816130aa565b9392505050565b6000806040838503121561371657600080fd5b8235613721816130aa565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036137be576137be61375e565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261389981840185876137d5565b9c9b505050505050505050505050565b600082516138bb818460208701613163565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156139145761391461375e565b92915050565b60006020828403121561392c57600080fd5b815180151581146136fc57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b646060830184866137d5565b8183526000602080850194508260005b858110156139bd578135613995816130aa565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613982565b509495945050505050565b6040815260006139dc604083018587613972565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613a45606083018789613972565b8281036020840152613a58818688613972565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613a95602083018486613972565b949350505050565b808201808211156139145761391461375e565b600060208284031215613ac257600080fd5b5051919050565b80820281158282048414176139145761391461375e56fea164736f6c6343000813000a", } var OperatorABI = OperatorMetaData.ABI diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 6efc75fce9..1db18d8366 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -46,8 +46,8 @@ mock_ethlink_aggregator_wrapper: ../../contracts/solc/v0.6/MockETHLINKAggregator mock_gas_aggregator_wrapper: ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.bin bacbb1ea4dc6beac0db8a13ca5c75e2fd61b903d70feea9b3b1c8b10fe8df4f3 multiwordconsumer_wrapper: ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.bin 6e68abdf614e3ed0f5066c1b5f9d7c1199f1e7c5c5251fe8a471344a59afc6ba offchain_aggregator_wrapper: OffchainAggregator/OffchainAggregator.abi - 5c8d6562e94166d4790f1ee6e4321d359d9f7262e6c5452a712b1f1c896f45cf -operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin 0fdfacf8879537b854875608dfca41c6221c342174417112acaa67dfcadafddc -operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin d7abd0e67f30a3a4c9c04c896124391306fa364fcf579fa6df04dbf912b48568 +operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin 357203fabe3df436eb015e2d5094374c6967a9fc922ac8edc265b27aac4d67cf +operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin c5e1db81070d940a82ef100b0bce38e055593cbeebbc73abf9d45c30d6020cd2 oracle_wrapper: ../../contracts/solc/v0.6/Oracle/Oracle.abi ../../contracts/solc/v0.6/Oracle/Oracle.bin 7af2fbac22a6e8c2847e8e685a5400cac5101d72ddf5365213beb79e4dede43a perform_data_checker_wrapper: ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 simple_log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin 0a7a0cc4da7dc2a3d0a0c36c746b1adc044af5cad1838367356a0604f3255a01 From 79da81ffd0b459395d82cc66db4d5142336b190c Mon Sep 17 00:00:00 2001 From: Dylan Tinianov Date: Wed, 6 Dec 2023 10:55:57 -0500 Subject: [PATCH 277/327] Create auto update workflow (#11483) * Create auto-update.yml * Ignore merge conflicts --- .github/workflows/auto-update.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/auto-update.yml diff --git a/.github/workflows/auto-update.yml b/.github/workflows/auto-update.yml new file mode 100644 index 0000000000..963145c404 --- /dev/null +++ b/.github/workflows/auto-update.yml @@ -0,0 +1,17 @@ +name: Auto Update +on: + push: + branches: + - develop +jobs: + autoupdate: + name: Auto Update + runs-on: ubuntu-latest + steps: + - uses: docker://chinthakagodawita/autoupdate-action:v1 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + PR_FILTER: "labelled" + PR_LABELS: "auto-update" + MERGE_MSG: "Branch was auto-updated." + MERGE_CONFLICT_ACTION: "ignore" From d65ca4fd20568b8cd623b517fd3e33a34709f7d0 Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 6 Dec 2023 09:20:53 -0700 Subject: [PATCH 278/327] [TT-744] Bump core results output filter (#11486) * [TT-755] Bump core results output filter * bump to merged action version --- .github/workflows/ci-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index fd8dfed88a..bac6f76389 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -84,7 +84,7 @@ jobs: run: ./tools/bin/${{ matrix.cmd }} ./... - name: Print Filtered Test Results if: ${{ failure() && matrix.cmd == 'go_core_tests' }} - uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@a052942591aaa12716eb9835b490d812a77d0831 # v2.3.1 with: results-file: ./output.txt output-file: ./output-short.txt From c17067b874bebcda72cae8a335d9c6b5fc681f3a Mon Sep 17 00:00:00 2001 From: Domino Valdano <2644901+reductionista@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:20:41 -0800 Subject: [PATCH 279/327] Interfaces and skeleton methods for ChainReader EVM POC (#10990) * Implement skeleton interfaces, structs, & methods for ChainReader EVM POC - Read ChainReader config in from RelayConfig - Add some initialization and validation relay skeletons - Use medianProviderWrapper instead of passing medianContract separately This avoids us having to modify the signature of NewMedianFactory, which would require further modifications to all non-evm repos and chainlink-relay - Add chain_reader_test.go with some basic relay tests Co-authored-by: Jordan Krage - Add chain reader config validation - Add chain reader config validation tests - Add config for chain reader median contract to cr validation testcases - Add unimplemented Encode(), Decode(), GetMaxEncodingSize(), GetMaxDecodingSize() - Add ChainReader() method to mock provider for plugin test - Rename relaymercury.ChainReader to MercuryChainReader, resolve name collisions - Add tests for errors during ChainReader construction - Propagate InvalidConfig & any other errors back to client We should ignore Unimplemented until node ops have been given ample time to migrate to the new job spec (including a section for ChainReader config) so that we can remove the old product-specific MedianContract component from MedianProvider. All other errors we can immediately start passing back to the client, letting the core node decide how to handle them (eg. displaying an "invalid job spec" message to the UI if the RelayConfig was invalid or the ContractID missing) * Update relay versions * Simplify chain reader config validation * Update commit hashes one final time now that all relays are merged. --------- Co-authored-by: ilija --- core/scripts/go.mod | 9 +- core/scripts/go.sum | 18 +- core/services/chainlink/relayer_factory.go | 3 +- core/services/functions/listener.go | 1 + .../services/ocr2/plugins/functions/plugin.go | 1 + core/services/ocr2/plugins/median/plugin.go | 68 +++++ core/services/ocr2/plugins/median/services.go | 83 +++++- core/services/ocr2/plugins/mercury/plugin.go | 2 +- .../plugins/ocr2keeper/integration_21_test.go | 1 - core/services/ocr2/plugins/ocr2keeper/util.go | 1 - core/services/relay/evm/chain_reader.go | 154 ++++++++++ core/services/relay/evm/chain_reader_test.go | 272 ++++++++++++++++++ core/services/relay/evm/config_poller.go | 1 + core/services/relay/evm/evm.go | 34 ++- core/services/relay/evm/functions.go | 5 + .../relay/evm/functions/logpoller_wrapper.go | 1 + .../evm/functions/offchain_config_digester.go | 8 +- core/services/relay/evm/median_test.go | 47 +++ .../relay/evm/mercury/v1/data_source.go | 9 +- .../relay/evm/mercury/v1/data_source_test.go | 26 +- core/services/relay/evm/mercury_provider.go | 54 ++-- core/services/relay/evm/ocr2keeper.go | 4 + core/services/relay/evm/ocr2vrf.go | 8 + core/services/relay/evm/types/types.go | 35 ++- .../relay/grpc_provider_server_test.go | 3 +- core/services/relay/relay_test.go | 1 + go.mod | 9 +- go.sum | 18 +- integration-tests/docker/test_env/test_env.go | 18 +- integration-tests/go.mod | 9 +- integration-tests/go.sum | 18 +- plugins/medianpoc/plugin_test.go | 7 +- 32 files changed, 828 insertions(+), 100 deletions(-) create mode 100644 core/services/ocr2/plugins/median/plugin.go create mode 100644 core/services/relay/evm/chain_reader.go create mode 100644 core/services/relay/evm/chain_reader_test.go create mode 100644 core/services/relay/evm/median_test.go diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 91e26caef6..b0b5f801ed 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -119,6 +119,7 @@ require ( github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.5 // indirect @@ -257,12 +258,12 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 1622f1d24d..dd69053b40 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -443,6 +443,8 @@ github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= @@ -1212,18 +1214,18 @@ 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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c h1:YFyo0pCmKkpB4EOSykCZFueRXNxQ7OhKiCnhoVIzydo= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 h1:2LC5HtHkAm7I1h5j4Uz0KTX+h4fo4z/5NoAARSF4ZVA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e h1:/tCHhoAJM+ittEHPZTtJsAgXmYujKiDW0ub9HXW9qtY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 8b8749013f..4ed73d8e53 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -5,9 +5,8 @@ import ( "errors" "fmt" - "github.com/pelletier/go-toml/v2" - "github.com/jmoiron/sqlx" + "github.com/pelletier/go-toml/v2" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index 65c364adb7..f9d74f1bae 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/cbor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 2ebd7e3080..61fa7f5d82 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -14,6 +14,7 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/median/plugin.go b/core/services/ocr2/plugins/median/plugin.go new file mode 100644 index 0000000000..cad2099832 --- /dev/null +++ b/core/services/ocr2/plugins/median/plugin.go @@ -0,0 +1,68 @@ +package median + +import ( + "context" + + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type Plugin struct { + loop.Plugin + stop services.StopChan +} + +func NewPlugin(lggr logger.Logger) *Plugin { + return &Plugin{Plugin: loop.Plugin{Logger: lggr}, stop: make(services.StopChan)} +} + +func (p *Plugin) NewMedianFactory(ctx context.Context, provider types.MedianProvider, dataSource, juelsPerFeeCoin median.DataSource, errorLog loop.ErrorLog) (loop.ReportingPluginFactory, error) { + var ctxVals loop.ContextValues + ctxVals.SetValues(ctx) + lggr := logger.With(p.Logger, ctxVals.Args()...) + + factory := median.NumericalMedianFactory{ + ContractTransmitter: provider.MedianContract(), + DataSource: dataSource, + JuelsPerFeeCoinDataSource: juelsPerFeeCoin, + Logger: logger.NewOCRWrapper(lggr, true, func(msg string) { + ctx, cancelFn := p.stop.NewCtx() + defer cancelFn() + if err := errorLog.SaveError(ctx, msg); err != nil { + lggr.Errorw("Unable to save error", "err", msg) + } + }), + OnchainConfigCodec: provider.OnchainConfigCodec(), + ReportCodec: provider.ReportCodec(), + } + s := &reportingPluginFactoryService{lggr: logger.Named(lggr, "ReportingPluginFactory"), ReportingPluginFactory: factory} + + p.SubService(s) + + return s, nil +} + +type reportingPluginFactoryService struct { + services.StateMachine + lggr logger.Logger + ocrtypes.ReportingPluginFactory +} + +func (r *reportingPluginFactoryService) Name() string { return r.lggr.Name() } + +func (r *reportingPluginFactoryService) Start(ctx context.Context) error { + return r.StartOnce("ReportingPluginFactory", func() error { return nil }) +} + +func (r *reportingPluginFactoryService) Close() error { + return r.StopOnce("ReportingPluginFactory", func() error { return nil }) +} + +func (r *reportingPluginFactoryService) HealthReport() map[string]error { + return map[string]error{r.Name(): r.Healthy()} +} diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 2d1ef72054..4adfc306d6 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -5,9 +5,14 @@ import ( "encoding/json" "errors" "fmt" + "math/big" "time" + "github.com/ethereum/go-ethereum/common" libocr "github.com/smartcontractkit/libocr/offchainreporting2plus" + ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + mediantypes "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -52,6 +57,21 @@ func (m *medianConfig) JobPipelineResultWriteQueueDepth() uint64 { return m.jobPipelineResultWriteQueueDepth } +// This wrapper avoids the need to modify the signature of NewMedianFactory in all of the non-evm +// relay repos as well as its primary definition in chainlink-common. Once ChainReader is implemented +// and working on all 4 blockchain families, we can remove the original MedianContract() method from +// MedianProvider and pass medianContract as a separate param to NewMedianFactory +type medianProviderWrapper struct { + types.MedianProvider + contract mediantypes.MedianContract +} + +// Override relay's implementation of MedianContract with product plugin's implementation of +// MedianContract, making use of product-agnostic ChainReader to read the contract instead of relay MedianContract +func (m medianProviderWrapper) MedianContract() mediantypes.MedianContract { + return m.contract +} + func NewMedianServices(ctx context.Context, jb job.Job, isNewlyCreatedJob bool, @@ -125,11 +145,24 @@ func NewMedianServices(ctx context.Context, CreatedAt: time.Now(), }, lggr) - if cmdName := env.MedianPluginCmd.Get(); cmdName != "" { + medianPluginCmd := env.MedianPluginCmd.Get() + medianLoopEnabled := medianPluginCmd != "" + + // TODO BCF-2821 handle this properly as this blocks Solana chain reader dev + if !medianLoopEnabled && medianProvider.ChainReader() != nil { + lggr.Info("Chain Reader enabled") + medianProvider = medianProviderWrapper{ + medianProvider, // attach newer MedianContract which uses ChainReader + newMedianContract(provider.ChainReader(), common.HexToAddress(spec.ContractID)), + } + } else { + lggr.Info("Chain Reader disabled") + } + if medianLoopEnabled { // use unique logger names so we can use it to register a loop medianLggr := lggr.Named("Median").Named(spec.ContractID).Named(spec.GetID()) - cmdFn, telem, err2 := cfg.RegisterLOOP(medianLggr.Name(), cmdName) + cmdFn, telem, err2 := cfg.RegisterLOOP(medianLggr.Name(), medianPluginCmd) if err2 != nil { err = fmt.Errorf("failed to register loop: %w", err2) abort() @@ -159,3 +192,49 @@ func NewMedianServices(ctx context.Context, } return } + +type medianContract struct { + chainReader types.ChainReader + contract types.BoundContract +} + +type latestTransmissionDetailsResponse struct { + configDigest ocr2types.ConfigDigest + epoch uint32 + round uint8 + latestAnswer *big.Int + latestTimestamp time.Time +} + +type latestRoundRequested struct { + configDigest ocr2types.ConfigDigest + epoch uint32 + round uint8 +} + +func (m *medianContract) LatestTransmissionDetails(ctx context.Context) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, latestAnswer *big.Int, latestTimestamp time.Time, err error) { + var resp latestTransmissionDetailsResponse + + err = m.chainReader.GetLatestValue(ctx, m.contract, "LatestTransmissionDetails", nil, &resp) + if err != nil { + return + } + + return resp.configDigest, resp.epoch, resp.round, resp.latestAnswer, resp.latestTimestamp, err +} + +func (m *medianContract) LatestRoundRequested(ctx context.Context, lookback time.Duration) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, err error) { + var resp latestRoundRequested + + err = m.chainReader.GetLatestValue(ctx, m.contract, "LatestRoundReported", map[string]string{}, &resp) + if err != nil { + return + } + + return resp.configDigest, resp.epoch, resp.round, err +} + +func newMedianContract(chainReader types.ChainReader, address common.Address) *medianContract { + contract := types.BoundContract{Address: address.String(), Name: "median", Pending: true} + return &medianContract{chainReader, contract} +} diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index f5c11dc731..b2767d6bcf 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -67,7 +67,7 @@ func NewServices( lggr, saver, chEnhancedTelem, - ocr2Provider.ChainReader(), + ocr2Provider.MercuryChainReader(), ocr2Provider.MercuryServerFetcher(), pluginConfig.InitialBlockNumber.Ptr(), feedID, diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 7ccd785a66..c2b6612f66 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -32,7 +32,6 @@ import ( ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" - "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 02a0d033bc..76e5bb6e00 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -12,7 +12,6 @@ import ( ocr2keepers20polling "github.com/smartcontractkit/chainlink-automation/pkg/v2/observer/polling" ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go new file mode 100644 index 0000000000..e4da4cc1a4 --- /dev/null +++ b/core/services/relay/evm/chain_reader.go @@ -0,0 +1,154 @@ +package evm + +import ( + "context" + "fmt" + "slices" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type ChainReaderService interface { + services.ServiceCtx + commontypes.ChainReader +} + +type chainReader struct { + lggr logger.Logger + contractID common.Address + lp logpoller.LogPoller +} + +// NewChainReaderService constructor for ChainReader +func NewChainReaderService(lggr logger.Logger, lp logpoller.LogPoller, contractID common.Address, config types.ChainReaderConfig) (*chainReader, error) { + if err := validateChainReaderConfig(config); err != nil { + return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidConfig, err) + } + + // TODO BCF-2814 implement initialisation of chain reading definitions and pass them into chainReader + return &chainReader{lggr.Named("ChainReader"), contractID, lp}, nil +} + +func (cr *chainReader) Name() string { return cr.lggr.Name() } + +func (cr *chainReader) initialize() error { + // Initialize chain reader, start cache polling loop, etc. + return nil +} + +func (cr *chainReader) Start(ctx context.Context) error { + if err := cr.initialize(); err != nil { + return fmt.Errorf("Failed to initialize ChainReader: %w", err) + } + return nil +} + +func (cr *chainReader) Close() error { return nil } + +func (cr *chainReader) Ready() error { return nil } + +func (cr *chainReader) HealthReport() map[string]error { + return map[string]error{cr.Name(): nil} +} + +func (cr *chainReader) GetLatestValue(ctx context.Context, bc commontypes.BoundContract, method string, params any, returnVal any) error { + return commontypes.UnimplementedError("Unimplemented method GetLatestValue called") +} + +func validateChainReaderConfig(cfg types.ChainReaderConfig) error { + if len(cfg.ChainContractReaders) == 0 { + return fmt.Errorf("%w: no contract readers defined", commontypes.ErrInvalidConfig) + } + + for contractName, chainContractReader := range cfg.ChainContractReaders { + abi, err := abi.JSON(strings.NewReader(chainContractReader.ContractABI)) + if err != nil { + return fmt.Errorf("invalid abi: %w", err) + } + + for chainReadingDefinitionName, chainReaderDefinition := range chainContractReader.ChainReaderDefinitions { + switch chainReaderDefinition.ReadType { + case types.Method: + err = validateMethods(abi, chainReaderDefinition) + case types.Event: + err = validateEvents(abi, chainReaderDefinition) + default: + return fmt.Errorf("%w: invalid chainreading definition read type: %d for contract: %q", commontypes.ErrInvalidConfig, chainReaderDefinition.ReadType, contractName) + } + if err != nil { + return fmt.Errorf("%w: invalid chainreading definition: %q for contract: %q, err: %w", commontypes.ErrInvalidConfig, chainReadingDefinitionName, contractName, err) + } + } + } + + return nil +} + +func validateEvents(contractABI abi.ABI, chainReaderDefinition types.ChainReaderDefinition) error { + event, methodExists := contractABI.Events[chainReaderDefinition.ChainSpecificName] + if !methodExists { + return fmt.Errorf("event: %s doesn't exist", chainReaderDefinition.ChainSpecificName) + } + + var abiEventIndexedInputs []abi.Argument + for _, eventInput := range event.Inputs { + if eventInput.Indexed { + abiEventIndexedInputs = append(abiEventIndexedInputs, eventInput) + } + } + + var chainReaderEventParams []string + for chainReaderEventParam := range chainReaderDefinition.Params { + chainReaderEventParams = append(chainReaderEventParams, chainReaderEventParam) + } + + if !areChainReaderArgumentsValid(abiEventIndexedInputs, chainReaderEventParams) { + var abiEventIndexedInputsNames []string + for _, abiEventIndexedInput := range abiEventIndexedInputs { + abiEventIndexedInputsNames = append(abiEventIndexedInputsNames, abiEventIndexedInput.Name) + } + return fmt.Errorf("params: [%s] don't match abi event indexed inputs: [%s]", strings.Join(chainReaderEventParams, ","), strings.Join(abiEventIndexedInputsNames, ",")) + } + return nil +} + +func validateMethods(abi abi.ABI, chainReaderDefinition types.ChainReaderDefinition) error { + method, methodExists := abi.Methods[chainReaderDefinition.ChainSpecificName] + if !methodExists { + return fmt.Errorf("method: %q doesn't exist", chainReaderDefinition.ChainSpecificName) + } + + var methodNames []string + for methodName := range chainReaderDefinition.Params { + methodNames = append(methodNames, methodName) + } + + if !areChainReaderArgumentsValid(method.Inputs, methodNames) { + var abiMethodInputs []string + for _, input := range method.Inputs { + abiMethodInputs = append(abiMethodInputs, input.Name) + } + return fmt.Errorf("params: [%s] don't match abi method inputs: [%s]", strings.Join(methodNames, ","), strings.Join(abiMethodInputs, ",")) + } + + return nil +} + +func areChainReaderArgumentsValid(contractArgs []abi.Argument, chainReaderArgs []string) bool { + for _, contractArg := range contractArgs { + if !slices.Contains(chainReaderArgs, contractArg.Name) { + return false + } + } + + return true +} diff --git a/core/services/relay/evm/chain_reader_test.go b/core/services/relay/evm/chain_reader_test.go new file mode 100644 index 0000000000..ece2234ab5 --- /dev/null +++ b/core/services/relay/evm/chain_reader_test.go @@ -0,0 +1,272 @@ +package evm + +import ( + "encoding/json" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + mocklogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type chainReaderTestHelper struct { +} + +func (crTestHelper chainReaderTestHelper) makeChainReaderConfig(abi string, params map[string]any) evmtypes.ChainReaderConfig { + return evmtypes.ChainReaderConfig{ + ChainContractReaders: map[string]evmtypes.ChainContractReader{ + "MyContract": { + ContractABI: abi, + ChainReaderDefinitions: map[string]evmtypes.ChainReaderDefinition{ + "MyGenericMethod": { + ChainSpecificName: "name", + Params: params, + CacheEnabled: false, + ReadType: evmtypes.Method, + }, + }, + }, + }, + } +} + +func (crTestHelper chainReaderTestHelper) makeChainReaderConfigFromStrings(abi string, chainReadingDefinitions string) (evmtypes.ChainReaderConfig, error) { + chainReaderConfigTemplate := `{ + "chainContractReaders": { + "testContract": { + "contractName": "testContract", + "contractABI": "[%s]", + "chainReaderDefinitions": { + %s + } + } + } + }` + + abi = strings.Replace(abi, `"`, `\"`, -1) + formattedCfgJsonString := fmt.Sprintf(chainReaderConfigTemplate, abi, chainReadingDefinitions) + var chainReaderConfig evmtypes.ChainReaderConfig + err := json.Unmarshal([]byte(formattedCfgJsonString), &chainReaderConfig) + return chainReaderConfig, err +} + +func TestNewChainReader(t *testing.T) { + lggr := logger.TestLogger(t) + lp := mocklogpoller.NewLogPoller(t) + chain := mocks.NewChain(t) + contractID := testutils.NewAddress() + contractABI := `[{"inputs":[{"internalType":"string","name":"param","type":"string"}],"name":"name","stateMutability":"view","type":"function"}]` + + t.Run("happy path", func(t *testing.T) { + params := make(map[string]any) + params["param"] = "" + chainReaderConfig := chainReaderTestHelper{}.makeChainReaderConfig(contractABI, params) + chain.On("LogPoller").Return(lp) + _, err := NewChainReaderService(lggr, chain.LogPoller(), contractID, chainReaderConfig) + assert.NoError(t, err) + }) + + t.Run("invalid config", func(t *testing.T) { + invalidChainReaderConfig := chainReaderTestHelper{}.makeChainReaderConfig(contractABI, map[string]any{}) // missing param + _, err := NewChainReaderService(lggr, chain.LogPoller(), contractID, invalidChainReaderConfig) + assert.ErrorIs(t, err, commontypes.ErrInvalidConfig) + }) + + t.Run("ChainReader config is empty", func(t *testing.T) { + emptyChainReaderConfig := evmtypes.ChainReaderConfig{} + _, err := NewChainReaderService(lggr, chain.LogPoller(), contractID, emptyChainReaderConfig) + assert.ErrorIs(t, err, commontypes.ErrInvalidConfig) + assert.ErrorContains(t, err, "no contract readers defined") + }) +} + +func TestChainReaderStartClose(t *testing.T) { + lggr := logger.TestLogger(t) + lp := mocklogpoller.NewLogPoller(t) + cr := chainReader{ + lggr: lggr, + lp: lp, + } + err := cr.Start(testutils.Context(t)) + assert.NoError(t, err) + err = cr.Close() + assert.NoError(t, err) +} + +// TODO Chain Reading Definitions return values are WIP, waiting on codec work and BCF-2789 +func TestValidateChainReaderConfig_HappyPath(t *testing.T) { + type testCase struct { + name string + abiInput string + chainReadingDefinitions string + } + + var testCases []testCase + testCases = append(testCases, + testCase{ + name: "eventWithMultipleIndexedTopics", + abiInput: `{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"}`, + chainReadingDefinitions: `"Swap":{ + "chainSpecificName": "Swap", + "params":{ + "sender": "0x0", + "to": "0x0" + }, + "readType": 1 + }`, + }) + + testCases = append(testCases, + testCase{ + name: "methodWithOneParamAndMultipleResponses", + abiInput: `{"constant":true,"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getUserAccountData","payable":false,"stateMutability":"view","type":"function"}`, + chainReadingDefinitions: `"getUserAccountData":{ + "chainSpecificName": "getUserAccountData", + "params":{ + "_user": "0x0" + }, + "readType": 0 + }`, + }) + + testCases = append(testCases, + testCase{ + name: "methodWithMultipleParamsAndOneResult", + abiInput: `{"inputs":[{"internalType":"address","name":"_input","type":"address"},{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_inputQuantity","type":"uint256"}],"name":"getSwapOutput","stateMutability":"view","type":"function"}`, + chainReadingDefinitions: `"getSwapOutput":{ + "chainSpecificName": "getSwapOutput", + "params":{ + "_input":"0x0", + "_output":"0x0", + "_inputQuantity":"0x0" + }, + "readType": 0 + }`, + }) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cfg, err := chainReaderTestHelper{}.makeChainReaderConfigFromStrings(tc.abiInput, tc.chainReadingDefinitions) + assert.NoError(t, err) + assert.NoError(t, validateChainReaderConfig(cfg)) + }) + } + + t.Run("large config with all test cases", func(t *testing.T) { + var largeABI string + var manyChainReadingDefinitions string + for _, tc := range testCases { + largeABI += tc.abiInput + "," + manyChainReadingDefinitions += tc.chainReadingDefinitions + "," + } + + largeABI = largeABI[:len(largeABI)-1] + manyChainReadingDefinitions = manyChainReadingDefinitions[:len(manyChainReadingDefinitions)-1] + cfg, err := chainReaderTestHelper{}.makeChainReaderConfigFromStrings(largeABI, manyChainReadingDefinitions) + assert.NoError(t, err) + assert.NoError(t, validateChainReaderConfig(cfg)) + }) +} + +// TODO Chain Reading Definitions return values are WIP, waiting on codec work and BCF-2789 +func TestValidateChainReaderConfig_BadPath(t *testing.T) { + type testCase struct { + name string + abiInput string + chainReadingDefinitions string + expected error + } + + var testCases []testCase + mismatchedEventArgumentsTestABI := `{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"Swap","type":"event"}` + testCases = append(testCases, + testCase{ + name: "mismatched abi and event chain reading param values", + abiInput: mismatchedEventArgumentsTestABI, + chainReadingDefinitions: `"Swap":{ + "chainSpecificName": "Swap", + "params":{ + "malformedParam": "0x0" + }, + "readType": 1 + }`, + expected: fmt.Errorf("invalid chainreading definition: \"Swap\" for contract: \"testContract\", err: params: [malformedParam] don't match abi event indexed inputs: [sender]"), + }) + + mismatchedFunctionArgumentsTestABI := `{"constant":true,"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"Swap","payable":false,"stateMutability":"view","type":"function"}` + testCases = append(testCases, + testCase{ + name: "mismatched abi and method chain reading param values", + abiInput: mismatchedFunctionArgumentsTestABI, + chainReadingDefinitions: `"Swap":{ + "chainSpecificName": "Swap", + "params":{ + "malformedParam": "0x0" + }, + "readType": 0 + }`, + expected: fmt.Errorf("invalid chainreading definition: \"Swap\" for contract: \"testContract\", err: params: [malformedParam] don't match abi method inputs: [from]"), + }, + ) + + testCases = append(testCases, + testCase{ + name: "event doesn't exist", + abiInput: `{"constant":true,"inputs":[],"name":"someName","payable":false,"stateMutability":"view","type":"function"}`, + chainReadingDefinitions: `"TestMethod":{ + "chainSpecificName": "Swap", + "readType": 1 + }`, + expected: fmt.Errorf("invalid chainreading definition: \"TestMethod\" for contract: \"testContract\", err: event: Swap doesn't exist"), + }, + ) + + testCases = append(testCases, + testCase{ + name: "method doesn't exist", + abiInput: `{"constant":true,"inputs":[],"name":"someName","payable":false,"stateMutability":"view","type":"function"}`, + chainReadingDefinitions: `"TestMethod":{ + "chainSpecificName": "Swap", + "readType": 0 + }`, + expected: fmt.Errorf("invalid chainreading definition: \"TestMethod\" for contract: \"testContract\", err: method: \"Swap\" doesn't exist"), + }, + ) + + testCases = append(testCases, testCase{ + name: "invalid abi", + abiInput: `broken abi`, + chainReadingDefinitions: `"TestMethod":{ + "chainSpecificName": "Swap", + "readType": 0 + }`, + expected: fmt.Errorf("invalid abi"), + }) + + testCases = append(testCases, testCase{ + name: "invalid read type", + abiInput: `{"constant":true,"inputs":[],"name":"someName","payable":false,"stateMutability":"view","type":"function"}`, + chainReadingDefinitions: `"TestMethod":{"readType": 59}`, + expected: fmt.Errorf("invalid chainreading definition read type: 59"), + }) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cfg, err := chainReaderTestHelper{}.makeChainReaderConfigFromStrings(tc.abiInput, tc.chainReadingDefinitions) + assert.NoError(t, err) + if tc.expected == nil { + assert.NoError(t, validateChainReaderConfig(cfg)) + } else { + assert.ErrorContains(t, validateChainReaderConfig(cfg), tc.expected.Error()) + } + }) + } +} diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index fe39ed0e34..dc75fe037f 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -17,6 +17,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 088a69a258..aea704adac 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -54,6 +54,7 @@ type Relayer struct { mercuryPool wsrpc.Pool eventBroadcaster pg.EventBroadcaster pgCfg pg.QConfig + chainReader commontypes.ChainReader } type CSAETHKeystore interface { @@ -189,8 +190,7 @@ func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commonty } transmitter := mercury.NewTransmitter(lggr, cw.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) - chainReader := NewChainReader(r.chain.HeadTracker()) - return NewMercuryProvider(cw, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, chainReader, lggr), nil + return NewMercuryProvider(cw, r.chainReader, NewMercuryChainReader(r.chain.HeadTracker()), transmitter, reportCodecV1, reportCodecV2, reportCodecV3, lggr), nil } func (r *Relayer) NewFunctionsProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.FunctionsProvider, error) { @@ -502,6 +502,10 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp if expectedChainID != r.chain.ID().String() { return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } + if !common.IsHexAddress(relayOpts.ContractID) { + return nil, fmt.Errorf("invalid contractID %s, expected hex address", relayOpts.ContractID) + } + contractID := common.HexToAddress(relayOpts.ContractID) configWatcher, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) if err != nil { @@ -518,12 +522,26 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp if err != nil { return nil, err } - return &medianProvider{ + + medianProvider := medianProvider{ configWatcher: configWatcher, reportCodec: reportCodec, contractTransmitter: contractTransmitter, medianContract: medianContract, - }, nil + } + + // allow fallback until chain reader is default and median contract is removed, but still log just in case + var chainReaderService commontypes.ChainReader + if relayConfig.ChainReader != nil { + if chainReaderService, err = NewChainReaderService(lggr, r.chain.LogPoller(), contractID, *relayConfig.ChainReader); err != nil { + return nil, err + } + } else { + lggr.Info("ChainReader missing from RelayConfig; falling back to internal MedianContract") + } + medianProvider.chainReader = chainReaderService + + return &medianProvider, nil } var _ commontypes.MedianProvider = (*medianProvider)(nil) @@ -533,8 +551,8 @@ type medianProvider struct { contractTransmitter ContractTransmitter reportCodec median.ReportCodec medianContract *medianContract - - ms services.MultiStart + chainReader commontypes.ChainReader + ms services.MultiStart } func (p *medianProvider) Name() string { @@ -582,3 +600,7 @@ func (p *medianProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigeste func (p *medianProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { return p.configWatcher.ContractConfigTracker() } + +func (p *medianProvider) ChainReader() commontypes.ChainReader { + return p.chainReader +} diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index 10e5d543b1..f1d652fd6f 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -85,6 +86,10 @@ func (p *functionsProvider) Name() string { return p.configWatcher.Name() } +func (p *functionsProvider) ChainReader() commontypes.ChainReader { + return nil +} + func NewFunctionsProvider(chain legacyevm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { relayOpts := evmRelayTypes.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go index 95f45022ab..e7f3a1a96a 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper.go +++ b/core/services/relay/evm/functions/logpoller_wrapper.go @@ -11,6 +11,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" diff --git a/core/services/relay/evm/functions/offchain_config_digester.go b/core/services/relay/evm/functions/offchain_config_digester.go index b4467543d9..29547e794c 100644 --- a/core/services/relay/evm/functions/offchain_config_digester.go +++ b/core/services/relay/evm/functions/offchain_config_digester.go @@ -10,13 +10,13 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) var ( - _ types.OffchainConfigDigester = &functionsOffchainConfigDigester{} - _ relaytypes.RouteUpdateSubscriber = &functionsOffchainConfigDigester{} - FunctionsDigestPrefix = types.ConfigDigestPrefixEVM + _ types.OffchainConfigDigester = &functionsOffchainConfigDigester{} + _ evmRelayTypes.RouteUpdateSubscriber = &functionsOffchainConfigDigester{} + FunctionsDigestPrefix = types.ConfigDigestPrefixEVM // In order to support multiple OCR plugins with a single jobspec & OCR2Base contract, each plugin must have a unique config digest. // This is accomplished by overriding the single config digest from the contract with a unique prefix for each plugin via this custom offchain digester & config poller. ThresholdDigestPrefix = types.ConfigDigestPrefix(7) diff --git a/core/services/relay/evm/median_test.go b/core/services/relay/evm/median_test.go new file mode 100644 index 0000000000..4286290d28 --- /dev/null +++ b/core/services/relay/evm/median_test.go @@ -0,0 +1,47 @@ +package evm + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +func TestNewMedianProvider(t *testing.T) { + lggr := logger.TestLogger(t) + + chain := mocks.NewChain(t) + chainID := testutils.NewRandomEVMChainID() + chain.On("ID").Return(chainID) + contractID := testutils.NewAddress() + relayer := Relayer{lggr: lggr, chain: chain} + + pargs := commontypes.PluginArgs{} + + t.Run("wrong chainID", func(t *testing.T) { + relayConfigBadChainID := evmtypes.RelayConfig{} + rc, err2 := json.Marshal(&relayConfigBadChainID) + rargs2 := commontypes.RelayArgs{ContractID: contractID.String(), RelayConfig: rc} + require.NoError(t, err2) + _, err2 = relayer.NewMedianProvider(rargs2, pargs) + assert.ErrorContains(t, err2, "chain id in spec does not match") + }) + + t.Run("invalid contractID", func(t *testing.T) { + relayConfig := evmtypes.RelayConfig{ChainID: utils.NewBig(chainID)} + rc, err2 := json.Marshal(&relayConfig) + require.NoError(t, err2) + rargsBadContractID := commontypes.RelayArgs{ContractID: "NotAContractID", RelayConfig: rc} + _, err2 = relayer.NewMedianProvider(rargsBadContractID, pargs) + assert.ErrorContains(t, err2, "invalid contractID") + }) +} diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index 429780ef2e..ce48ec6cf9 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -67,7 +67,7 @@ type datasource struct { mu sync.RWMutex chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData - chainReader mercury.ChainReader + mercuryChainReader mercury.ChainReader fetcher Fetcher initialBlockNumber *int64 @@ -77,8 +77,8 @@ type datasource struct { var _ v1.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainReader mercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { - return &datasource{pr, jb, spec, lggr, s, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, mercuryChainReader mercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { + return &datasource{pr, jb, spec, lggr, s, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, mercuryChainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} } type ErrEmptyLatestReport struct { @@ -292,7 +292,8 @@ func (ds *datasource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.T } func (ds *datasource) setLatestBlocks(ctx context.Context, obs *v1types.Observation) error { - latestBlocks, err := ds.chainReader.LatestHeads(ctx, nBlocksObservation) + latestBlocks, err := ds.mercuryChainReader.LatestHeads(ctx, nBlocksObservation) + if err != nil { ds.lggr.Errorw("failed to read latest blocks", "error", err) return err diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index 72dc4327f1..ce0d71acc6 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -15,7 +15,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" @@ -33,7 +33,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -var _ mercury.ServerFetcher = &mockFetcher{} +var _ mercurytypes.ServerFetcher = &mockFetcher{} type mockFetcher struct { num *int64 @@ -71,10 +71,10 @@ func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg type mockChainReader struct { err error - obs []mercury.Head + obs []mercurytypes.Head } -func (m *mockChainReader) LatestHeads(context.Context, int) ([]mercury.Head, error) { +func (m *mockChainReader) LatestHeads(context.Context, int) ([]mercurytypes.Head, error) { return m.obs, m.err } @@ -118,7 +118,7 @@ func TestMercury_Observe(t *testing.T) { ds.spec = spec h := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - ds.chainReader = evm.NewChainReader(h) + ds.mercuryChainReader = evm.NewMercuryChainReader(h) head := &evmtypes.Head{ Number: int64(rand.Int31()), @@ -210,7 +210,7 @@ func TestMercury_Observe(t *testing.T) { t.Run("if no current block available", func(t *testing.T) { h2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) h2.On("LatestChain").Return((*evmtypes.Head)(nil)) - ds.chainReader = evm.NewChainReader(h2) + ds.mercuryChainReader = evm.NewMercuryChainReader(h2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -221,7 +221,7 @@ func TestMercury_Observe(t *testing.T) { }) }) - ds.chainReader = evm.NewChainReader(h) + ds.mercuryChainReader = evm.NewMercuryChainReader(h) t.Run("when fetchMaxFinalizedBlockNum=false", func(t *testing.T) { t.Run("when run execution fails, returns error", func(t *testing.T) { @@ -321,7 +321,7 @@ func TestMercury_Observe(t *testing.T) { t.Run("when chain length is zero", func(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return((*evmtypes.Head)(nil)) - ds.chainReader = evm.NewChainReader(ht2) + ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -346,7 +346,7 @@ func TestMercury_Observe(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(h6) - ds.chainReader = evm.NewChainReader(ht2) + ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -369,7 +369,7 @@ func TestMercury_Observe(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(heads[len(heads)-1]) - ds.chainReader = evm.NewChainReader(ht2) + ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -384,7 +384,7 @@ func TestMercury_Observe(t *testing.T) { }) t.Run("when chain reader returns an error", func(t *testing.T) { - ds.chainReader = &mockChainReader{ + ds.mercuryChainReader = &mockChainReader{ err: io.EOF, obs: nil, } @@ -414,7 +414,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { t.Run("returns head from headtracker if present", func(t *testing.T) { headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) headTracker.On("LatestChain").Return(&h, nil) - ds.chainReader = evm.NewChainReader(headTracker) + ds.mercuryChainReader = evm.NewMercuryChainReader(headTracker) obs := v1.Observation{} err := ds.setLatestBlocks(testutils.Context(t), &obs) @@ -433,7 +433,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { // This can happen in some cases e.g. RPC node is offline headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) - ds.chainReader = evm.NewChainReader(headTracker) + ds.mercuryChainReader = evm.NewChainReader(headTracker) obs := v1.Observation{} err := ds.setLatestBlocks(testutils.Context(t), &obs) diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index b6a2232da3..2ff882efa6 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -7,48 +7,50 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" - relaymercury "github.com/smartcontractkit/chainlink-data-streams/mercury" + "github.com/smartcontractkit/chainlink-data-streams/mercury" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" + evmmercury "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" ) -var _ types.MercuryProvider = (*mercuryProvider)(nil) +var _ commontypes.MercuryProvider = (*mercuryProvider)(nil) type mercuryProvider struct { - configWatcher *configWatcher - transmitter mercury.Transmitter - reportCodecV1 v1.ReportCodec - reportCodecV2 v2.ReportCodec - reportCodecV3 v3.ReportCodec - chainReader mercurytypes.ChainReader - logger logger.Logger - - ms services.MultiStart + configWatcher *configWatcher + chainReader commontypes.ChainReader + transmitter evmmercury.Transmitter + reportCodecV1 v1.ReportCodec + reportCodecV2 v2.ReportCodec + reportCodecV3 v3.ReportCodec + mercuryChainReader mercurytypes.ChainReader + logger logger.Logger + ms services.MultiStart } func NewMercuryProvider( configWatcher *configWatcher, - transmitter mercury.Transmitter, + chainReader commontypes.ChainReader, + mercuryChainReader mercurytypes.ChainReader, + transmitter evmmercury.Transmitter, reportCodecV1 v1.ReportCodec, reportCodecV2 v2.ReportCodec, reportCodecV3 v3.ReportCodec, - chainReader mercurytypes.ChainReader, lggr logger.Logger, ) *mercuryProvider { return &mercuryProvider{ configWatcher, + chainReader, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, - chainReader, + mercuryChainReader, lggr, services.MultiStart{}, } @@ -77,6 +79,10 @@ func (p *mercuryProvider) HealthReport() map[string]error { return report } +func (p *mercuryProvider) MercuryChainReader() mercurytypes.ChainReader { + return p.mercuryChainReader +} + func (p *mercuryProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { return p.configWatcher.ContractConfigTracker() } @@ -86,7 +92,7 @@ func (p *mercuryProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigest } func (p *mercuryProvider) OnchainConfigCodec() mercurytypes.OnchainConfigCodec { - return relaymercury.StandardOnchainConfigCodec{} + return mercury.StandardOnchainConfigCodec{} } func (p *mercuryProvider) ReportCodecV1() v1.ReportCodec { @@ -109,23 +115,27 @@ func (p *mercuryProvider) MercuryServerFetcher() mercurytypes.ServerFetcher { return p.transmitter } -func (p *mercuryProvider) ChainReader() mercurytypes.ChainReader { +func (p *mercuryProvider) ChainReader() commontypes.ChainReader { return p.chainReader } -var _ mercurytypes.ChainReader = (*chainReader)(nil) +var _ mercurytypes.ChainReader = (*mercuryChainReader)(nil) -type chainReader struct { +type mercuryChainReader struct { tracker httypes.HeadTracker } func NewChainReader(h httypes.HeadTracker) mercurytypes.ChainReader { - return &chainReader{ + return &mercuryChainReader{h} +} + +func NewMercuryChainReader(h httypes.HeadTracker) mercurytypes.ChainReader { + return &mercuryChainReader{ tracker: h, } } -func (r *chainReader) LatestHeads(ctx context.Context, k int) ([]mercurytypes.Head, error) { +func (r *mercuryChainReader) LatestHeads(ctx context.Context, k int) ([]mercurytypes.Head, error) { evmBlocks := r.tracker.LatestChain().AsSlice(k) if len(evmBlocks) == 0 { return nil, nil diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 3b3bfeb652..abc03c7abb 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -130,6 +130,10 @@ func (c *ocr2keeperProvider) ContractTransmitter() ocrtypes.ContractTransmitter return c.contractTransmitter } +func (c *ocr2keeperProvider) ChainReader() commontypes.ChainReader { + return nil +} + func newOCR2KeeperConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index b7a2220588..39d0503b8b 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -110,6 +110,10 @@ func (c *dkgProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } +func (c *dkgProvider) ChainReader() commontypes.ChainReader { + return nil +} + type ocr2vrfProvider struct { *configWatcher contractTransmitter ContractTransmitter @@ -119,6 +123,10 @@ func (c *ocr2vrfProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } +func (c *ocr2vrfProvider) ChainReader() commontypes.ChainReader { + return nil +} + func newOCR2VRFConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index d2edef8b11..24afb65c55 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -20,11 +20,38 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) +type ChainReaderConfig struct { + // ChainContractReaders key is contract name + ChainContractReaders map[string]ChainContractReader `json:"chainContractReaders"` +} + +type ChainContractReader struct { + ContractABI string `json:"contractABI"` + // ChainReaderDefinitions key is chainAgnostic read name. + ChainReaderDefinitions map[string]ChainReaderDefinition `json:"chainReaderDefinitions"` +} + +type ChainReaderDefinition struct { + ChainSpecificName string `json:"chainSpecificName"` // chain specific contract method name or event type. + Params map[string]any `json:"params"` + ReturnValues []string `json:"returnValues"` + CacheEnabled bool `json:"cacheEnabled"` + ReadType ReadType `json:"readType"` +} + +type ReadType int64 + +const ( + Method ReadType = 0 + Event ReadType = 1 +) + type RelayConfig struct { - ChainID *utils.Big `json:"chainID"` - FromBlock uint64 `json:"fromBlock"` - EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` - ConfigContractAddress *common.Address `json:"configContractAddress"` + ChainID *utils.Big `json:"chainID"` + FromBlock uint64 `json:"fromBlock"` + EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` + ConfigContractAddress *common.Address `json:"configContractAddress"` + ChainReader *ChainReaderConfig `json:"chainReader"` // Contract-specific SendingKeys pq.StringArray `json:"sendingKeys"` diff --git a/core/services/relay/grpc_provider_server_test.go b/core/services/relay/grpc_provider_server_test.go index 6aff32f5e3..72bbbca0f4 100644 --- a/core/services/relay/grpc_provider_server_test.go +++ b/core/services/relay/grpc_provider_server_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -17,7 +18,7 @@ func TestProviderServer(t *testing.T) { lggr := logger.TestLogger(t) _, err := NewProviderServer(mp, "unsupported-type", lggr) - require.Error(t, err) + require.ErrorContains(t, err, "unsupported-type") ps, err := NewProviderServer(staticMedianProvider{}, types.Median, lggr) require.NoError(t, err) diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index 18a7b1b44e..d23895699d 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) diff --git a/go.mod b/go.mod index 0cbd2f16d1..2ac067959e 100644 --- a/go.mod +++ b/go.mod @@ -66,12 +66,12 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 @@ -171,6 +171,7 @@ require ( github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.5 diff --git a/go.sum b/go.sum index 96e5c06945..b7305210e0 100644 --- a/go.sum +++ b/go.sum @@ -440,6 +440,8 @@ github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= @@ -1215,18 +1217,18 @@ 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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c h1:YFyo0pCmKkpB4EOSykCZFueRXNxQ7OhKiCnhoVIzydo= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 h1:2LC5HtHkAm7I1h5j4Uz0KTX+h4fo4z/5NoAARSF4ZVA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e h1:/tCHhoAJM+ittEHPZTtJsAgXmYujKiDW0ub9HXW9qtY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 030a3ae962..b1b179badc 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -206,6 +206,15 @@ func (te *CLClusterTestEnv) Cleanup() error { te.logWhetherAllContainersAreRunning() + // Getting the absolute path + wd, err := os.Getwd() + if err != nil { + return err + } + + wd = filepath.Join(wd, "logs") + te.l.Info().Str("Working dir", wd).Msg("Would write test logs here") + // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution // Collect logs if the test fails, or if we just want them if te.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { @@ -285,7 +294,14 @@ func (te *CLClusterTestEnv) collectTestLogs() error { return err } - te.l.Info().Str("Logs Location", folder).Msg("Wrote test logs") + // Getting the absolute path + wd, err := os.Getwd() + if err != nil { + return err + } + absolutePath := filepath.Join(wd, folder) + + te.l.Info().Str("Logs absolute Location", absolutePath).Msg("Wrote test logs") return nil } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a161e67941..01d7c4dbef 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 github.com/smartcontractkit/chainlink-testing-framework v1.20.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 @@ -160,6 +160,7 @@ require ( github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-errors/errors v1.4.2 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.5 // indirect @@ -351,11 +352,11 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect 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.20231117191236-12eab01a4542 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/soheilhy/cmux v0.1.5 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 0392afe287..f3d707d18e 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -520,6 +520,8 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= @@ -1505,18 +1507,18 @@ 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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c h1:YFyo0pCmKkpB4EOSykCZFueRXNxQ7OhKiCnhoVIzydo= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 h1:2LC5HtHkAm7I1h5j4Uz0KTX+h4fo4z/5NoAARSF4ZVA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e h1:/tCHhoAJM+ittEHPZTtJsAgXmYujKiDW0ub9HXW9qtY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= github.com/smartcontractkit/chainlink-testing-framework v1.20.0 h1:gQPQRKJuMh6QTAIMkqZ7v5WkjEmbcoMIX/V6WPVrvuI= github.com/smartcontractkit/chainlink-testing-framework v1.20.0/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go index 0d6c0360e4..ba06d5ea46 100644 --- a/plugins/medianpoc/plugin_test.go +++ b/plugins/medianpoc/plugin_test.go @@ -7,9 +7,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" @@ -72,6 +71,10 @@ func (p provider) OnchainConfigCodec() median.OnchainConfigCodec { return mockOnchainConfigCodec{} } +func (p provider) ChainReader() types.ChainReader { + return nil +} + func TestNewPlugin(t *testing.T) { lggr := logger.TestLogger(t) p := NewPlugin(lggr) From 47d0690d3d130e13b1975fd9edb0b982e584fda6 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 6 Dec 2023 13:12:28 -0500 Subject: [PATCH 280/327] Improve logging for cache (#11453) * Include ServerURL in cache logging * Add additional cache tracing * TEMP - DO NOT MERGE THIS - promote Trace=>Debug cache logging * Log if call was cached or not * Revert "TEMP - DO NOT MERGE THIS - promote Trace=>Debug cache logging" This reverts commit f0f3f07a59c8d310ac74849519d46ea9b53495c1. --- core/services/relay/evm/mercury/wsrpc/cache/cache.go | 7 ++++++- core/services/relay/evm/mercury/wsrpc/client.go | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache.go b/core/services/relay/evm/mercury/wsrpc/cache/cache.go index cab5654081..181900bc15 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache.go @@ -213,12 +213,14 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest if time.Now().Before(v.expiresAt) { // CACHE HIT promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE HIT (hot path)", "feedID", feedIDHex) defer v.RUnlock() return v.val, nil } else if v.fetching { // CACHE WAIT promCacheWaitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE WAIT (hot path)", "feedID", feedIDHex) // if someone else is fetching then wait for the fetch to complete ch := v.fetchCh v.RUnlock() @@ -234,11 +236,13 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest if time.Now().Before(v.expiresAt) { // CACHE HIT promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE HIT (cold path)", "feedID", feedIDHex) defer v.RUnlock() return v.val, nil } else if v.fetching { // CACHE WAIT promCacheWaitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE WAIT (cold path)", "feedID", feedIDHex) // if someone else is fetching then wait for the fetch to complete ch := v.fetchCh v.Unlock() @@ -246,6 +250,7 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest } // CACHE MISS promCacheMissCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE MISS (cold path)", "feedID", feedIDHex) // initiate the fetch and wait for result ch := v.initiateFetch() v.Unlock() @@ -328,7 +333,7 @@ func (m *memCache) fetch(req *pb.LatestReportRequest, v *cacheVal) { func (m *memCache) Start(context.Context) error { return m.StartOnce(m.Name(), func() error { - m.lggr.Debugw("MemCache starting", "config", m.cfg) + m.lggr.Debugw("MemCache starting", "config", m.cfg, "serverURL", m.client.ServerURL()) m.wg.Add(1) go m.runloop() return nil diff --git a/core/services/relay/evm/mercury/wsrpc/client.go b/core/services/relay/evm/mercury/wsrpc/client.go index 5cdf1f44e9..5b6bfa1a9b 100644 --- a/core/services/relay/evm/mercury/wsrpc/client.go +++ b/core/services/relay/evm/mercury/wsrpc/client.go @@ -303,17 +303,21 @@ func (w *client) LatestReport(ctx context.Context, req *pb.LatestReportRequest) if err = w.waitForReady(ctx); err != nil { return nil, errors.Wrap(err, "LatestReport failed") } + var cached bool if w.cache == nil { resp, err = w.rawClient.LatestReport(ctx, req) } else { + cached = true resp, err = w.cache.LatestReport(ctx, req) } if err != nil { - lggr.Errorw("LatestReport failed", "err", err, "resp", resp) + lggr.Errorw("LatestReport failed", "err", err, "resp", resp, "cached", cached) } else if resp.Error != "" { - lggr.Errorw("LatestReport failed; mercury server returned error", "err", resp.Error, "resp", resp) + lggr.Errorw("LatestReport failed; mercury server returned error", "err", resp.Error, "resp", resp, "cached", cached) + } else if !cached { + lggr.Debugw("LatestReport succeeded", "resp", resp, "cached", cached) } else { - lggr.Debugw("LatestReport succeeded", "resp", resp) + lggr.Tracew("LatestReport succeeded", "resp", resp, "cached", cached) } return } From 346448ee5248ef4347214edb7dd7c70f696da5ca Mon Sep 17 00:00:00 2001 From: Tate Date: Wed, 6 Dec 2023 11:46:07 -0700 Subject: [PATCH 281/327] Only run keepers tests in the merge_group for PRs to develop (#11506) --- .github/workflows/integration-tests.yml | 33 ++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 9e2cce0212..5e3cf02a7c 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -144,7 +144,7 @@ jobs: - name: Build Chainlink Image if: needs.changes.outputs.src == 'true' uses: ./.github/actions/build-chainlink-image - with: + with: tag_suffix: ${{ matrix.image.tag-suffix }} dockerfile: ${{ matrix.image.dockerfile }} git_commit_sha: ${{ github.sha }} @@ -210,17 +210,33 @@ jobs: MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu20.04-8cores-32GB 1) MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu20.04-8cores-32GB 1) COMBINED_ARRAY=$(jq -c -n "$MATRIX_JSON_AUTOMATION + $MATRIX_JSON_KEEPER") - echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + + # if we running a PR against the develop branch we should only run the automation tests unless we are in the merge group event + if [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then + echo "We are in a merge_group event, run both automation and keepers tests" + echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + else + echo "we are not in a merge_group event, if this is a PR to develop run only automation tests, otherwise run everything because we could be running against a release branch" + target_branch=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.base.ref) + if [[ "$target_branch" == "develop" ]]; then + echo "only run automation tests" + echo "MATRIX_JSON=${MATRIX_JSON_AUTOMATION}" >> $GITHUB_ENV + else + echo "run both automation and keepers tests" + echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + fi + fi eth-smoke-tests-matrix-automation: - if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || (github.event_name == 'workflow_dispatch' && !inputs.simulatedNetwork)) }} + if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') }} environment: integration permissions: checks: write pull-requests: write id-token: write contents: read - needs: [build-chainlink, changes, compare-tests, build-lint-integration-tests] + needs: + [build-chainlink, changes, compare-tests, build-lint-integration-tests] env: SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 CHAINLINK_COMMIT_SHA: ${{ github.sha }} @@ -281,7 +297,7 @@ jobs: continue-on-error: true eth-smoke-tests-matrix: - if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || (github.event_name == 'workflow_dispatch' && !inputs.simulatedNetwork)) }} + if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') }} environment: integration permissions: checks: write @@ -410,7 +426,7 @@ jobs: - name: Show Otel-Collector Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - docker logs otel-collector + docker logs otel-collector ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' @@ -450,7 +466,7 @@ jobs: - name: Show Otel-Collector Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - docker logs otel-collector + docker logs otel-collector - name: Collect Metrics if: always() id: collect-gha-metrics @@ -464,7 +480,7 @@ jobs: - name: Permissions on traces if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - ls -l ./integration-tests/smoke/traces + ls -l ./integration-tests/smoke/traces - name: Upload Trace Data if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' uses: actions/upload-artifact@v3 @@ -472,7 +488,6 @@ jobs: name: trace-data path: ./integration-tests/smoke/traces/trace-data.json - ### Used to check the required checks box when the matrix completes eth-smoke-tests: if: always() From 4d8e0934396bfe02dcce9f8fc31c6377b846250b Mon Sep 17 00:00:00 2001 From: Gabriel Paradiso Date: Wed, 6 Dec 2023 20:43:17 +0100 Subject: [PATCH 282/327] [FUN-1094] Minor fixes (#11434) * fix: do not emit AddedAccess if the recipient already had access & minor doc improvements * chore: save gas by avoiding declaring a new var --- .../gas-snapshots/functions.gas-snapshot | 40 +++++++++---------- .../functions/dev/v1_X/FunctionsBilling.sol | 34 +++++----------- .../dev/v1_X/FunctionsCoordinator.sol | 6 +-- .../functions/dev/v1_X/FunctionsRouter.sol | 10 ++--- .../accessControl/TermsOfServiceAllowList.sol | 29 +++++--------- .../interfaces/ITermsOfServiceAllowList.sol | 8 ++++ .../dev/v1_X/interfaces/IFunctionsBilling.sol | 17 ++++++++ .../tests/v1_X/FunctionsBilling.t.sol | 12 +++--- .../tests/v1_X/FunctionsCoordinator.t.sol | 2 +- .../tests/v1_X/FunctionsRouter.t.sol | 2 +- .../FunctionsTermsOfServiceAllowList.t.sol | 27 +++++++------ .../src/v0.8/functions/tests/v1_X/Setup.t.sol | 10 +++-- .../FunctionsCoordinatorHarness.sol | 3 +- .../FunctionsCoordinatorTestHelper.sol | 3 +- .../v0.8/functions/v1/FunctionsRouter.test.ts | 2 +- .../functions_allow_list.go | 4 +- .../functions_coordinator.go | 4 +- .../functions_router/functions_router.go | 18 ++++----- ...rapper-dependency-versions-do-not-edit.txt | 6 +-- 19 files changed, 124 insertions(+), 113 deletions(-) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 4e6cf83cd1..8275d9afaf 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: 14578318) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14578296) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14578312) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14589732) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14589709) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14589681) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14589632) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14589621) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14589665) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14579333) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14579311) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14579327) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14590747) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14590724) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14590696) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14590647) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14590636) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14590680) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -118,12 +118,12 @@ FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() ( FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164837) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12946) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 57809) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87162) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87177) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18094) FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95480) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15041) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57885) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89272) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89287) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20148) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 194325) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114506) @@ -142,10 +142,10 @@ 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, μ: 43508, ~: 45548) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46020, ~: 48060) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43774, ~: 45548) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46286, ~: 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_RevertIfPaused(uint96) (runs: 256, μ: 51443, ~: 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) @@ -181,7 +181,7 @@ FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success(uint64) (runs: 256 FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30260) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 15019) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57800) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87208) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87223) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18049) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191858) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41979) @@ -195,14 +195,14 @@ FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 5775 FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26390) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15759) FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152576) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94815) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94830) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25837) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 44348) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23597) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1866530) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26003) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946547) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 104851) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946562) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 103411) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 51794) FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 12187) @@ -214,10 +214,10 @@ FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (ga FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15354) FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 41957) FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13525) -FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 95184) +FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 95199) FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13727) FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22073) -Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84675) +Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84690) Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79087) Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73375) Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38546) 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 cb4f2f4567..c3f351e6c7 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; -import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; +import {IFunctionsBilling, FunctionsBillingConfig} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; @@ -37,25 +37,9 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { event CommitmentDeleted(bytes32 requestId); - // ================================================================ - // | Configuration state | - // ================================================================ - - struct Config { - uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) - uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. - uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. - uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. - uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. - uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request - uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. - uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale - uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out - } - - Config private s_config; + FunctionsBillingConfig private s_config; - event ConfigUpdated(Config config); + event ConfigUpdated(FunctionsBillingConfig config); error UnsupportedRequestDataVersion(); error InsufficientBalance(); @@ -81,7 +65,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // ================================================================ // | Initialization | // ================================================================ - constructor(address router, Config memory config, address linkToNativeFeed) Routable(router) { + constructor(address router, FunctionsBillingConfig memory config, address linkToNativeFeed) Routable(router) { s_linkToNativeFeed = AggregatorV3Interface(linkToNativeFeed); updateConfig(config); @@ -93,13 +77,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @notice Gets the Chainlink Coordinator's billing configuration /// @return config - function getConfig() external view returns (Config memory) { + function getConfig() external view returns (FunctionsBillingConfig memory) { return s_config; } /// @notice Sets the Chainlink Coordinator's billing configuration - /// @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information - function updateConfig(Config memory config) public { + /// @param config - See the contents of the FunctionsBillingConfig struct in IFunctionsBilling.sol for more information + function updateConfig(FunctionsBillingConfig memory config) public { _onlyOwner(); s_config = config; @@ -122,7 +106,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @inheritdoc IFunctionsBilling function getWeiPerUnitLink() public view returns (uint256) { - Config memory config = s_config; + FunctionsBillingConfig memory config = s_config; (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); // solhint-disable-next-line not-rely-on-time if (config.feedStalenessSeconds < block.timestamp - timestamp && config.feedStalenessSeconds > 0) { @@ -199,7 +183,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { function _startBilling( FunctionsResponse.RequestMeta memory request ) internal returns (FunctionsResponse.Commitment memory commitment) { - Config memory config = s_config; + FunctionsBillingConfig memory config = s_config; // Nodes should support all past versions of the structure if (request.dataVersion > config.maxSupportedRequestDataVersion) { 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 16e9029ce3..33c45c218d 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.19; import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol"; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; -import {FunctionsBilling} from "./FunctionsBilling.sol"; +import {FunctionsBilling, FunctionsBillingConfig} from "./FunctionsBilling.sol"; import {OCR2Base} from "./ocr/OCR2Base.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; @@ -17,7 +17,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli /// @inheritdoc ITypeAndVersion // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override typeAndVersion = "Functions Coordinator v1.1.0"; + string public constant override typeAndVersion = "Functions Coordinator v1.2.0"; event OracleRequest( bytes32 indexed requestId, @@ -42,7 +42,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli constructor( address router, - Config memory config, + FunctionsBillingConfig memory config, address linkToNativeFeed ) OCR2Base() FunctionsBilling(router, config, linkToNativeFeed) {} diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol index 2e12a75679..d86d881151 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol @@ -19,7 +19,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, using FunctionsResponse for FunctionsResponse.FulfillResult; // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override typeAndVersion = "Functions Router v1.0.0"; + string public constant override typeAndVersion = "Functions Router v2.0.0"; // We limit return data to a selector plus 4 words. This is to avoid // malicious contracts from returning large amounts of data and causing @@ -90,7 +90,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract uint16 gasForCallExactCheck; // ════════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. - uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with GAS_FLAG_INDEX + uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX uint16 subscriptionDepositMinimumRequests; //═══╗ Amount of requests that must be completed before the full subscription balance will be released when closing a subscription account. uint72 subscriptionDepositJuels; // ════════════╝ Amount of subscription funds that are held as a deposit until Config.subscriptionDepositMinimumRequests are made using the subscription. } @@ -306,7 +306,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, bytes memory response, bytes memory err, uint96 juelsPerGas, - uint96 costWithoutCallback, + uint96 costWithoutFulfillment, address transmitter, FunctionsResponse.Commitment memory commitment ) external override returns (FunctionsResponse.FulfillResult resultCode, uint96) { @@ -341,7 +341,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, { uint96 callbackCost = juelsPerGas * SafeCast.toUint96(commitment.callbackGasLimit); - uint96 totalCostJuels = commitment.adminFee + costWithoutCallback + callbackCost; + uint96 totalCostJuels = commitment.adminFee + costWithoutFulfillment + callbackCost; // Check that the subscription can still afford to fulfill the request if (totalCostJuels > getSubscription(commitment.subscriptionId).balance) { @@ -379,7 +379,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, commitment.adminFee, juelsPerGas, SafeCast.toUint96(result.gasUsed), - costWithoutCallback + costWithoutFulfillment ); emit RequestProcessed({ diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol index b36d063ad7..3bb7c7b04c 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {ITermsOfServiceAllowList} from "./interfaces/ITermsOfServiceAllowList.sol"; +import {ITermsOfServiceAllowList, TermsOfServiceAllowListConfig} from "./interfaces/ITermsOfServiceAllowList.sol"; import {IAccessController} from "../../../../shared/interfaces/IAccessController.sol"; import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol"; @@ -17,7 +17,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, /// @inheritdoc ITypeAndVersion // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.0.0"; + string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.1.0"; EnumerableSet.AddressSet private s_allowedSenders; mapping(address => bool) private s_blockedSenders; @@ -30,23 +30,15 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, error InvalidUsage(); error RecipientIsBlocked(); - // ================================================================ - // | Configuration state | - // ================================================================ - struct Config { - bool enabled; // ═════════════╗ When enabled, access will be checked against s_allowedSenders. When disabled, all access will be allowed. - address signerPublicKey; // ══╝ The key pair that needs to sign the acceptance data - } + TermsOfServiceAllowListConfig private s_config; - Config private s_config; - - event ConfigUpdated(Config config); + event ConfigUpdated(TermsOfServiceAllowListConfig config); // ================================================================ // | Initialization | // ================================================================ - constructor(Config memory config) ConfirmedOwner(msg.sender) { + constructor(TermsOfServiceAllowListConfig memory config) ConfirmedOwner(msg.sender) { updateConfig(config); } @@ -56,13 +48,13 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, /// @notice Gets the contracts's configuration /// @return config - function getConfig() external view returns (Config memory) { + function getConfig() external view returns (TermsOfServiceAllowListConfig memory) { return s_config; } /// @notice Sets the contracts's configuration - /// @param config - See the contents of the TermsOfServiceAllowList.Config struct for more information - function updateConfig(Config memory config) public onlyOwner { + /// @param config - See the contents of the TermsOfServiceAllowListConfig struct in ITermsOfServiceAllowList.sol for more information + function updateConfig(TermsOfServiceAllowListConfig memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); } @@ -99,8 +91,9 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, } // Add recipient to the allow list - s_allowedSenders.add(recipient); - emit AddedAccess(recipient); + if (s_allowedSenders.add(recipient)) { + emit AddedAccess(recipient); + } } /// @inheritdoc ITermsOfServiceAllowList diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol index af4daa18bc..209d25c0ab 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol @@ -38,3 +38,11 @@ interface ITermsOfServiceAllowList { /// @param sender - Address of the sender to unblock function unblockSender(address sender) external; } + +// ================================================================ +// | Configuration state | +// ================================================================ +struct TermsOfServiceAllowListConfig { + bool enabled; // ═════════════╗ When enabled, access will be checked against s_allowedSenders. When disabled, all access will be allowed. + address signerPublicKey; // ══╝ The key pair that needs to sign the acceptance data +} diff --git a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol index 6291d05e57..0bd7817f77 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol @@ -40,5 +40,22 @@ interface IFunctionsBilling { function oracleWithdraw(address recipient, uint96 amount) external; /// @notice Withdraw all LINK earned by Oracles through fulfilling requests + /// @dev transmitter addresses must support LINK tokens to avoid tokens from getting stuck as oracleWithdrawAll() calls will forward tokens directly to transmitters function oracleWithdrawAll() external; } + +// ================================================================ +// | Configuration state | +// ================================================================ + +struct FunctionsBillingConfig { + uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) + uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. + uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. + uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. + uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. + uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request + uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. + uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale + uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out +} 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 739521c530..6664000342 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 @@ -10,6 +10,8 @@ import {Routable} from "../../dev/v1_X/Routable.sol"; import {FunctionsRouterSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsFulfillmentSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; +import {FunctionsBillingConfig} from "../../dev/v1_X/interfaces/IFunctionsBilling.sol"; + /// @notice #constructor contract FunctionsBilling_Constructor is FunctionsSubscriptionSetup { function test_Constructor_Success() public { @@ -25,7 +27,7 @@ contract FunctionsBilling_GetConfig is FunctionsRouterSetup { vm.stopPrank(); vm.startPrank(STRANGER_ADDRESS); - FunctionsBilling.Config memory config = s_functionsCoordinator.getConfig(); + FunctionsBillingConfig memory config = s_functionsCoordinator.getConfig(); assertEq(config.feedStalenessSeconds, getCoordinatorConfig().feedStalenessSeconds); assertEq(config.gasOverheadBeforeCallback, getCoordinatorConfig().gasOverheadBeforeCallback); assertEq(config.gasOverheadAfterCallback, getCoordinatorConfig().gasOverheadAfterCallback); @@ -39,12 +41,12 @@ contract FunctionsBilling_GetConfig is FunctionsRouterSetup { /// @notice #updateConfig contract FunctionsBilling_UpdateConfig is FunctionsRouterSetup { - FunctionsBilling.Config internal configToSet; + FunctionsBillingConfig internal configToSet; function setUp() public virtual override { FunctionsRouterSetup.setUp(); - configToSet = FunctionsBilling.Config({ + configToSet = FunctionsBillingConfig({ feedStalenessSeconds: getCoordinatorConfig().feedStalenessSeconds * 2, gasOverheadAfterCallback: getCoordinatorConfig().gasOverheadAfterCallback * 2, gasOverheadBeforeCallback: getCoordinatorConfig().gasOverheadBeforeCallback * 2, @@ -66,7 +68,7 @@ contract FunctionsBilling_UpdateConfig is FunctionsRouterSetup { s_functionsCoordinator.updateConfig(configToSet); } - event ConfigUpdated(FunctionsBilling.Config config); + event ConfigUpdated(FunctionsBillingConfig config); function test_UpdateConfig_Success() public { // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). @@ -79,7 +81,7 @@ contract FunctionsBilling_UpdateConfig is FunctionsRouterSetup { s_functionsCoordinator.updateConfig(configToSet); - FunctionsBilling.Config memory config = s_functionsCoordinator.getConfig(); + FunctionsBillingConfig memory config = s_functionsCoordinator.getConfig(); assertEq(config.feedStalenessSeconds, configToSet.feedStalenessSeconds); assertEq(config.gasOverheadAfterCallback, configToSet.gasOverheadAfterCallback); assertEq(config.gasOverheadBeforeCallback, configToSet.gasOverheadBeforeCallback); 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 f6d3d41e63..c21a2c090f 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 @@ -14,7 +14,7 @@ import {FunctionsRouterSetup, FunctionsDONSetup, FunctionsSubscriptionSetup} fro /// @notice #constructor contract FunctionsCoordinator_Constructor is FunctionsRouterSetup { function test_Constructor_Success() public { - assertEq(s_functionsCoordinator.typeAndVersion(), "Functions Coordinator v1.1.0"); + assertEq(s_functionsCoordinator.typeAndVersion(), "Functions Coordinator v1.2.0"); assertEq(s_functionsCoordinator.owner(), OWNER_ADDRESS); } } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol index 081fe2f664..43540ba02b 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol @@ -21,7 +21,7 @@ import "forge-std/Vm.sol"; /// @notice #constructor contract FunctionsRouter_Constructor is FunctionsRouterSetup { function test_Constructor_Success() public { - assertEq(s_functionsRouter.typeAndVersion(), "Functions Router v1.0.0"); + assertEq(s_functionsRouter.typeAndVersion(), "Functions Router v2.0.0"); assertEq(s_functionsRouter.owner(), OWNER_ADDRESS); } } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol index 450ec48d50..08c981dd4f 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol @@ -2,14 +2,16 @@ pragma solidity ^0.8.19; import {TermsOfServiceAllowList} from "../../dev/v1_X/accessControl/TermsOfServiceAllowList.sol"; +import {TermsOfServiceAllowListConfig} from "../../dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol"; import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol"; import {FunctionsRoutesSetup, FunctionsOwnerAcceptTermsOfServiceSetup} from "./Setup.t.sol"; +import "forge-std/Vm.sol"; /// @notice #constructor contract FunctionsTermsOfServiceAllowList_Constructor is FunctionsRoutesSetup { function test_Constructor_Success() public { - assertEq(s_termsOfServiceAllowList.typeAndVersion(), "Functions Terms of Service Allow List v1.0.0"); + assertEq(s_termsOfServiceAllowList.typeAndVersion(), "Functions Terms of Service Allow List v1.1.0"); assertEq(s_termsOfServiceAllowList.owner(), OWNER_ADDRESS); } } @@ -21,7 +23,7 @@ contract FunctionsTermsOfServiceAllowList_GetConfig is FunctionsRoutesSetup { vm.stopPrank(); vm.startPrank(STRANGER_ADDRESS); - TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig(); + TermsOfServiceAllowListConfig memory config = s_termsOfServiceAllowList.getConfig(); assertEq(config.enabled, getTermsOfServiceConfig().enabled); assertEq(config.signerPublicKey, getTermsOfServiceConfig().signerPublicKey); } @@ -36,14 +38,14 @@ contract FunctionsTermsOfServiceAllowList_UpdateConfig is FunctionsRoutesSetup { vm.expectRevert("Only callable by owner"); s_termsOfServiceAllowList.updateConfig( - TermsOfServiceAllowList.Config({enabled: true, signerPublicKey: STRANGER_ADDRESS}) + TermsOfServiceAllowListConfig({enabled: true, signerPublicKey: STRANGER_ADDRESS}) ); } - event ConfigUpdated(TermsOfServiceAllowList.Config config); + event ConfigUpdated(TermsOfServiceAllowListConfig config); function test_UpdateConfig_Success() public { - TermsOfServiceAllowList.Config memory configToSet = TermsOfServiceAllowList.Config({ + TermsOfServiceAllowListConfig memory configToSet = TermsOfServiceAllowListConfig({ enabled: false, signerPublicKey: TOS_SIGNER }); @@ -58,7 +60,7 @@ contract FunctionsTermsOfServiceAllowList_UpdateConfig is FunctionsRoutesSetup { s_termsOfServiceAllowList.updateConfig(configToSet); - TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig(); + TermsOfServiceAllowListConfig memory config = s_termsOfServiceAllowList.getConfig(); assertEq(config.enabled, configToSet.enabled); assertEq(config.signerPublicKey, configToSet.signerPublicKey); } @@ -156,7 +158,7 @@ contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoute function testAcceptTermsOfService_InvalidSigner_vuln() public { // Set the signer as the zero address - TermsOfServiceAllowList.Config memory allowListConfig; + TermsOfServiceAllowListConfig memory allowListConfig; allowListConfig.enabled = true; allowListConfig.signerPublicKey = address(0); s_termsOfServiceAllowList.updateConfig(allowListConfig); @@ -197,11 +199,12 @@ contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoute assertTrue(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0))); - // Event emitted even though adding existing item into EnumerableSet set does nothing - // TODO: handle differently in contract - vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); - emit AddedAccess(STRANGER_ADDRESS); + // Check the addedAccess is not emitted, given the recipient was already in the list + vm.recordLogs(); s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries.length, 0); + assertTrue(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0))); } @@ -258,7 +261,7 @@ contract FunctionsTermsOfServiceAllowList_HasAccess is FunctionsRoutesSetup { function test_HasAccess_TrueWhenDisabled() public { // Disable allow list, which opens all access s_termsOfServiceAllowList.updateConfig( - TermsOfServiceAllowList.Config({enabled: false, signerPublicKey: TOS_SIGNER}) + TermsOfServiceAllowListConfig({enabled: false, signerPublicKey: TOS_SIGNER}) ); // Send as stranger 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 41ee663e8b..0e131f9b89 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 @@ -9,7 +9,9 @@ import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; import {TermsOfServiceAllowList} from "../../dev/v1_X/accessControl/TermsOfServiceAllowList.sol"; +import {TermsOfServiceAllowListConfig} from "../../dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol"; import {MockLinkToken} from "../../../mocks/MockLinkToken.sol"; +import {FunctionsBillingConfig} from "../../dev/v1_X/interfaces/IFunctionsBilling.sol"; import "forge-std/Vm.sol"; @@ -64,9 +66,9 @@ contract FunctionsRouterSetup is BaseTest { }); } - function getCoordinatorConfig() public view returns (FunctionsBilling.Config memory) { + function getCoordinatorConfig() public view returns (FunctionsBillingConfig memory) { return - FunctionsBilling.Config({ + FunctionsBillingConfig({ feedStalenessSeconds: 24 * 60 * 60, // 1 day gasOverheadAfterCallback: 93_942, gasOverheadBeforeCallback: 105_000, @@ -79,8 +81,8 @@ contract FunctionsRouterSetup is BaseTest { }); } - function getTermsOfServiceConfig() public view returns (TermsOfServiceAllowList.Config memory) { - return TermsOfServiceAllowList.Config({enabled: true, signerPublicKey: TOS_SIGNER}); + function getTermsOfServiceConfig() public view returns (TermsOfServiceAllowListConfig memory) { + return TermsOfServiceAllowListConfig({enabled: true, signerPublicKey: TOS_SIGNER}); } } 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 c1b6d5d0b1..15d9790f61 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 @@ -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 {FunctionsResponse} from "../../../dev/v1_X/libraries/FunctionsResponse.sol"; +import {FunctionsBillingConfig} from "../../../dev/v1_X/interfaces/IFunctionsBilling.sol"; /// @title Functions Coordinator Test Harness /// @notice Contract to expose internal functions for testing purposes @@ -13,7 +14,7 @@ contract FunctionsCoordinatorHarness is FunctionsCoordinator { constructor( address router, - FunctionsBilling.Config memory config, + FunctionsBillingConfig memory config, address linkToNativeFeed ) FunctionsCoordinator(router, config, linkToNativeFeed) { s_linkToNativeFeed_HARNESS = linkToNativeFeed; diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol index 5e57e62e59..1a7d721d63 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol @@ -3,11 +3,12 @@ pragma solidity ^0.8.19; import {FunctionsCoordinator} from "../../../dev/v1_X/FunctionsCoordinator.sol"; import {FunctionsBilling} from "../../../dev/v1_X/FunctionsBilling.sol"; +import {FunctionsBillingConfig} from "../../../dev/v1_X/interfaces/IFunctionsBilling.sol"; contract FunctionsCoordinatorTestHelper is FunctionsCoordinator { constructor( address router, - FunctionsBilling.Config memory config, + FunctionsBillingConfig memory config, address linkToNativeFeed ) FunctionsCoordinator(router, config, linkToNativeFeed) {} diff --git a/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts b/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts index aecad5466b..e484283e80 100644 --- a/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts +++ b/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts @@ -20,7 +20,7 @@ describe('Functions Router - Request lifecycle', () => { describe('Config', () => { it('#typeAndVersion', async () => { expect(await contracts.router.typeAndVersion()).to.be.equal( - 'Functions Router v1.0.0', + 'Functions Router v2.0.0', ) }) it('non-owner is unable to update config', async () => { diff --git a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go index 0ccb08cdaa..b0c4894f14 100644 --- a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go +++ b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go @@ -36,8 +36,8 @@ type TermsOfServiceAllowListConfig struct { } var TermsOfServiceAllowListMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUsage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIsBlocked\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"AddedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"BlockedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"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\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"UnblockedAccess\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"}],\"name\":\"acceptTermsOfService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"blockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAllowedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"hasAccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isBlockedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"unblockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620012c4380380620012c4833981016040819052620000349162000269565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018460201b60201c565b50620002ea565b336001600160a01b03821603620001335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018e6200020b565b805160058054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b6000546001600160a01b03163314620002675760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000604082840312156200027c57600080fd5b604080519081016001600160401b0381118282101715620002ad57634e487b7160e01b600052604160045260246000fd5b60405282518015158114620002c157600080fd5b815260208301516001600160a01b0381168114620002de57600080fd5b60208201529392505050565b610fca80620002fa6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806382184c7b1161008c578063a39b06e311610066578063a39b06e3146101b8578063a5e1d61d146101d9578063c3f909d4146101ec578063f2fde38b1461024b57600080fd5b806382184c7b1461016a57806389f9a2c41461017d5780638da5cb5b1461019057600080fd5b80636b14daf8116100bd5780636b14daf81461012a57806379ba50971461014d578063817ef62e1461015557600080fd5b8063181f5a77146100e45780633908c4d41461010257806347663acb14610117575b600080fd5b6100ec61025e565b6040516100f99190610c4f565b60405180910390f35b610115610110366004610ce4565b61027a565b005b610115610125366004610d45565b6104f0565b61013d610138366004610d60565b61057b565b60405190151581526020016100f9565b6101156105a5565b61015d6106a7565b6040516100f99190610de3565b610115610178366004610d45565b6106b8565b61011561018b366004610e3d565b61074b565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f9565b6101cb6101c6366004610ec6565b610806565b6040519081526020016100f9565b61013d6101e7366004610d45565b610864565b60408051808201825260008082526020918201528151808301835260055460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff6101009092048216928401928352845190815291511691810191909152016100f9565b610115610259366004610d45565b6108a5565b6040518060600160405280602c8152602001610f92602c913981565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602052604090205460ff16156102da576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006102e68686610806565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206005546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156103c0573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff1614610417576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061045c57503373ffffffffffffffffffffffffffffffffffffffff87161480159061045c5750333b155b15610493576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049e6002866108b9565b5060405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a1505050505050565b6104f86108db565b73ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b91015b60405180910390a150565b60055460009060ff166105905750600161059e565b61059b60028561095e565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461062b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606106b3600261098d565b905090565b6106c06108db565b6106cb60028261099a565b5073ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19101610570565b6107536108db565b805160058054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a9101610570565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b1660348201526000906048016040516020818303038152906040528051906020012090505b92915050565b60055460009060ff1661087957506000919050565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205460ff1690565b6108ad6108db565b6108b6816109bc565b50565b600061059e8373ffffffffffffffffffffffffffffffffffffffff8416610ab1565b60005473ffffffffffffffffffffffffffffffffffffffff16331461095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610622565b565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561059e565b6060600061059e83610b00565b600061059e8373ffffffffffffffffffffffffffffffffffffffff8416610b5c565b3373ffffffffffffffffffffffffffffffffffffffff821603610a3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610622565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054610af85750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085e565b50600061085e565b606081600001805480602002602001604051908101604052809291908181526020018280548015610b5057602002820191906000526020600020905b815481526020019060010190808311610b3c575b50505050509050919050565b60008181526001830160205260408120548015610c45576000610b80600183610ef9565b8554909150600090610b9490600190610ef9565b9050818114610bf9576000866000018281548110610bb457610bb4610f33565b9060005260206000200154905080876000018481548110610bd757610bd7610f33565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610c0a57610c0a610f62565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085e565b600091505061085e565b600060208083528351808285015260005b81811015610c7c57858101830151858201604001528201610c60565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cdf57600080fd5b919050565b600080600080600060a08688031215610cfc57600080fd5b610d0586610cbb565b9450610d1360208701610cbb565b93506040860135925060608601359150608086013560ff81168114610d3757600080fd5b809150509295509295909350565b600060208284031215610d5757600080fd5b61059e82610cbb565b600080600060408486031215610d7557600080fd5b610d7e84610cbb565b9250602084013567ffffffffffffffff80821115610d9b57600080fd5b818601915086601f830112610daf57600080fd5b813581811115610dbe57600080fd5b876020828501011115610dd057600080fd5b6020830194508093505050509250925092565b6020808252825182820181905260009190848201906040850190845b81811015610e3157835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610dff565b50909695505050505050565b600060408284031215610e4f57600080fd5b6040516040810181811067ffffffffffffffff82111715610e99577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405282358015158114610eac57600080fd5b8152610eba60208401610cbb565b60208201529392505050565b60008060408385031215610ed957600080fd5b610ee283610cbb565b9150610ef060208401610cbb565b90509250929050565b8181038181111561085e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e302e30a164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUsage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIsBlocked\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"AddedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"BlockedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"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\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"UnblockedAccess\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"}],\"name\":\"acceptTermsOfService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"blockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAllowedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"hasAccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isBlockedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"unblockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b50604051620012c9380380620012c9833981016040819052620000349162000269565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018460201b60201c565b50620002ea565b336001600160a01b03821603620001335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018e6200020b565b805160058054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b6000546001600160a01b03163314620002675760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000604082840312156200027c57600080fd5b604080519081016001600160401b0381118282101715620002ad57634e487b7160e01b600052604160045260246000fd5b60405282518015158114620002c157600080fd5b815260208301516001600160a01b0381168114620002de57600080fd5b60208201529392505050565b610fcf80620002fa6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806382184c7b1161008c578063a39b06e311610066578063a39b06e3146101b8578063a5e1d61d146101d9578063c3f909d4146101ec578063f2fde38b1461024b57600080fd5b806382184c7b1461016a57806389f9a2c41461017d5780638da5cb5b1461019057600080fd5b80636b14daf8116100bd5780636b14daf81461012a57806379ba50971461014d578063817ef62e1461015557600080fd5b8063181f5a77146100e45780633908c4d41461010257806347663acb14610117575b600080fd5b6100ec61025e565b6040516100f99190610c54565b60405180910390f35b610115610110366004610ce9565b61027a565b005b610115610125366004610d4a565b6104f5565b61013d610138366004610d65565b610580565b60405190151581526020016100f9565b6101156105aa565b61015d6106ac565b6040516100f99190610de8565b610115610178366004610d4a565b6106bd565b61011561018b366004610e42565b610750565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f9565b6101cb6101c6366004610ecb565b61080b565b6040519081526020016100f9565b61013d6101e7366004610d4a565b610869565b60408051808201825260008082526020918201528151808301835260055460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff6101009092048216928401928352845190815291511691810191909152016100f9565b610115610259366004610d4a565b6108aa565b6040518060600160405280602c8152602001610f97602c913981565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602052604090205460ff16156102da576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006102e6868661080b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206005546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156103c0573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff1614610417576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061045c57503373ffffffffffffffffffffffffffffffffffffffff87161480159061045c5750333b155b15610493576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049e6002866108be565b156104ed5760405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a15b505050505050565b6104fd6108e0565b73ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b91015b60405180910390a150565b60055460009060ff16610595575060016105a3565b6105a0600285610963565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610630576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606106b86002610992565b905090565b6106c56108e0565b6106d060028261099f565b5073ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19101610575565b6107586108e0565b805160058054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a9101610575565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b1660348201526000906048016040516020818303038152906040528051906020012090505b92915050565b60055460009060ff1661087e57506000919050565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205460ff1690565b6108b26108e0565b6108bb816109c1565b50565b60006105a38373ffffffffffffffffffffffffffffffffffffffff8416610ab6565b60005473ffffffffffffffffffffffffffffffffffffffff163314610961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610627565b565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156105a3565b606060006105a383610b05565b60006105a38373ffffffffffffffffffffffffffffffffffffffff8416610b61565b3373ffffffffffffffffffffffffffffffffffffffff821603610a40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610627565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054610afd57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610863565b506000610863565b606081600001805480602002602001604051908101604052809291908181526020018280548015610b5557602002820191906000526020600020905b815481526020019060010190808311610b41575b50505050509050919050565b60008181526001830160205260408120548015610c4a576000610b85600183610efe565b8554909150600090610b9990600190610efe565b9050818114610bfe576000866000018281548110610bb957610bb9610f38565b9060005260206000200154905080876000018481548110610bdc57610bdc610f38565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610c0f57610c0f610f67565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610863565b6000915050610863565b600060208083528351808285015260005b81811015610c8157858101830151858201604001528201610c65565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ce457600080fd5b919050565b600080600080600060a08688031215610d0157600080fd5b610d0a86610cc0565b9450610d1860208701610cc0565b93506040860135925060608601359150608086013560ff81168114610d3c57600080fd5b809150509295509295909350565b600060208284031215610d5c57600080fd5b6105a382610cc0565b600080600060408486031215610d7a57600080fd5b610d8384610cc0565b9250602084013567ffffffffffffffff80821115610da057600080fd5b818601915086601f830112610db457600080fd5b813581811115610dc357600080fd5b876020828501011115610dd557600080fd5b6020830194508093505050509250925092565b6020808252825182820181905260009190848201906040850190845b81811015610e3657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610e04565b50909695505050505050565b600060408284031215610e5457600080fd5b6040516040810181811067ffffffffffffffff82111715610e9e577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405282358015158114610eb157600080fd5b8152610ebf60208401610cc0565b60208201529392505050565b60008060408385031215610ede57600080fd5b610ee783610cc0565b9150610ef560208401610cc0565b90509250929050565b81810381811115610863577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e312e30a164736f6c6343000813000a", } var TermsOfServiceAllowListABI = TermsOfServiceAllowListMetaData.ABI diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 5f0d2d45f2..a280297782 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\":[{\"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: "0x60a06040523480156200001157600080fd5b50604051620056d0380380620056d083398101604081905262000034916200046d565b8282828233806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000139565b5050506001600160a01b038116620000ed57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200012d82620001e4565b5050505050506200062c565b336001600160a01b03821603620001935760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee62000342565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033790839062000576565b60405180910390a150565b6200034c6200034e565b565b6000546001600160a01b031633146200034c5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000086565b80516001600160a01b0381168114620003c257600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f957634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c257600080fd5b80516001600160481b0381168114620003c257600080fd5b805164ffffffffff81168114620003c257600080fd5b805161ffff81168114620003c257600080fd5b80516001600160e01b0381168114620003c257600080fd5b60008060008385036101608112156200048557600080fd5b6200049085620003aa565b935061012080601f1983011215620004a757600080fd5b620004b1620003c7565b9150620004c160208701620003ff565b8252620004d160408701620003ff565b6020830152620004e460608701620003ff565b6040830152620004f760808701620003ff565b60608301526200050a60a0870162000414565b60808301526200051d60c087016200042c565b60a08301526200053060e0870162000442565b60c08301526101006200054581880162000455565b60e084015262000557828801620003ff565b908301525091506200056d6101408501620003aa565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005c960808401826001600160481b03169052565b5060a0830151620005e360a084018264ffffffffff169052565b5060c0830151620005fa60c084018261ffff169052565b5060e08301516200061660e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805161505e6200067260003960008181610845015281816109d301528181610ca601528181610f3a01528181611045015281816117890152613490015261505e6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046139d4565b61059c565b005b6101a56101b5366004613b7d565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613ca1565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613d42565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613dd1565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046139d4565b610d92565b6102a0610de2565b6040516102039190613e5b565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613e6e565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613e87565b610fd4565b6040516102039190613fdc565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004614030565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b60405161020391906140e7565b61053b6105363660046141d7565b611785565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f66118e5565b6101a561056e3660046142f0565b61193c565b61057b6124b8565b604051908152602001610203565b6101a56105973660046143bd565b612711565b6105a4612725565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec828483614473565b505050565b6105f96127a8565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906108369083906140e7565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d29190614599565b905090565b6108df6127b0565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6127a8565b610ba26127b0565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561460a565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614639565b9050610bb1565b5050565b610d9a612725565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec828483614473565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e60906143da565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea8906143da565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed4906143da565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614671565b61295c565b90506110bf60608301604084016143bd565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a0880161475e565b61111f610160880161014089016143bd565b611129888061477b565b61113b6101208b016101008c016147e0565b60208b01356111516101008d0160e08e016147fb565b8b60405161116799989796959493929190614818565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16111d68a8a8a8a8a8a612dfa565b6003546000906002906111f49060ff808216916101009004166148c0565b6111fe9190614908565b6112099060016148c0565b60ff169050878114611277576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b878614611306576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e6774680000000000000000000000000000000000000000000000006064820152608401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113495761134961492a565b600281111561135a5761135a61492a565b90525090506002816020015160028111156113775761137761492a565b141580156113c057506006816000015160ff168154811061139a5761139a61460a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611427576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b5050505061143361396c565b6000808a8a604051611446929190614959565b60405190819003812061145d918e90602001614969565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117675760006001848984602081106114c6576114c661460a565b6114d391901a601b6148c0565b8e8e868181106114e5576114e561460a565b905060200201358d8d878181106114fe576114fe61460a565b905060200201356040516000815260200160405260405161153b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561155d573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156115dd576115dd61492a565b60028111156115ee576115ee61492a565b905250925060018360200151600281111561160b5761160b61492a565b14611672576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061168c5761168c61460a565b602002015173ffffffffffffffffffffffffffffffffffffffff161461170e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117285761172861460a565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117536001866148c0565b9450508061176090614639565b90506114a7565b505050611778833383858e8e612eb1565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561182557600080fd5b505afa158015611839573d6000803e3d6000fd5b5050505066038d7ea4c6800082111561187e576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611888610841565b905060006118cb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b90506118d9858583856130b0565b98975050505050505050565b6060600c80546118f4906143da565b905060000361192f576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea8906143da565b855185518560ff16601f8311156119af576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611a19576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611aa7576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611ab281600361497d565b8311611b1a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611b22612725565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611b69908861321d565b60055415611d1e57600554600090611b8390600190614994565b9050600060058281548110611b9a57611b9a61460a565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611bd457611bd461460a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611c5457611c546149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611cbd57611cbd6149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611b69915050565b60005b8151518110156122d557815180516000919083908110611d4357611d4361460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611dc8576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d70747900000000000000006044820152606401610b0d565b600073ffffffffffffffffffffffffffffffffffffffff1682602001518281518110611df657611df661460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611e7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d7074790000006044820152606401610b0d565b60006004600084600001518481518110611e9757611e9761460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611ee157611ee161492a565b14611f48576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611f7957611f7961460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561201a5761201a61492a565b02179055506000915061202a9050565b60046000846020015184815181106120445761204461460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561208e5761208e61492a565b146120f5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106121285761212861460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156121c9576121c961492a565b0217905550508251805160059250839081106121e7576121e761460a565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106122635761226361460a565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806122cd81614639565b915050611d21565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161238d918491740100000000000000000000000000000000000000009004166149d6565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123ec4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613236565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986124a3988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926149f3565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266a9190614aa3565b50935050925050804261267d9190614994565b836020015163ffffffff1610801561269f57506000836020015163ffffffff16115b156126cd57505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361270a576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b612719612725565b612722816132e1565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146127a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6127a6612725565b600b546bffffffffffffffffffffffff166000036127ca57565b60006127d4610de2565b80519091506000819003612814576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546000906128339083906bffffffffffffffffffffffff16614af3565b905060005b828110156128fe5781600a60008684815181106128575761285761460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128bf9190614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806128f790614639565b9050612838565b506129098282614b43565b600b80546000906129299084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612b17576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612b548560e001513a8488608001516130b0565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612bb0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612bc99190614b6b565b905060003087604001518860a001518960c001516001612be99190614b7e565b8a5180516020918201206101008d015160e08e0151604051612c9d98979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612dac9190613fdc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612e0782602061497d565b612e1285602061497d565b612e1e88610144614b6b565b612e289190614b6b565b612e329190614b6b565b612e3d906000614b6b565b9050368114612ea8576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b600080808080612ec386880188614c7a565b84519499509297509095509350915060ff16801580612ee3575084518114155b80612eef575083518114155b80612efb575082518114155b80612f07575081518114155b15612f6e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e67746800000000006044820152606401610b0d565b60005b818110156130a1576000613006888381518110612f9057612f9061460a565b6020026020010151888481518110612faa57612faa61460a565b6020026020010151888581518110612fc457612fc461460a565b6020026020010151888681518110612fde57612fde61460a565b6020026020010151888781518110612ff857612ff861460a565b6020026020010151886133d6565b9050600081600681111561301c5761301c61492a565b1480613039575060018160068111156130375761303761492a565b145b15613090578782815181106130505761305061460a565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b5061309a81614639565b9050612f71565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561310b57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b600854600090612710906131259063ffffffff168761497d565b61312f9190614d4c565b6131399086614b6b565b60085490915060009087906131729063ffffffff6c010000000000000000000000008204811691680100000000000000009004166149d6565b61317c91906149d6565b63ffffffff16905060006131c66000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b905060006131e7826131d8858761497d565b6131e29190614b6b565b61382c565b9050600061320368ffffffffffffffffff808916908a16614b1e565b905061320f8183614b1e565b9a9950505050505050505050565b6000613227610de2565b511115610d8e57610d8e6127b0565b6000808a8a8a8a8a8a8a8a8a60405160200161325a99989796959493929190614d60565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133ed9190614e2c565b905060003a8261012001518361010001516134089190614ef4565b64ffffffffff16613419919061497d565b905060008460ff166134616000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b61346b9190614d4c565b9050600061347c6131e28385614b6b565b905060006134893a61382c565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff16896134e89190614b1e565b338d6040518763ffffffff1660e01b815260040161350b96959493929190614f12565b60408051808303816000875af1158015613529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354d9190614f8e565b909250905060008260068111156135665761356661492a565b1480613583575060018260068111156135815761358161492a565b145b156136d95760008e8152600760205260408120556135a18185614b1e565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161360d91859116614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b61368c9190614b1e565b6136969190614b1e565b6136a09190614b1e565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b6000466136f681613860565b1561377257606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376b9190614fc1565b9392505050565b61377b81613883565b156138235773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161500a604891396040516020016137db929190614fda565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016138069190613ca1565b602060405180830381865afa158015613747573d6000803e3d6000fd5b50600092915050565b600061385a6138396124b8565b61384b84670de0b6b3a764000061497d565b6138559190614d4c565b6138ca565b92915050565b600061a4b1821480613874575062066eed82145b8061385a57505062066eee1490565b6000600a82148061389557506101a482145b806138a2575062aa37dc82145b806138ae575061210582145b806138bb575062014a3382145b8061385a57505062014a341490565b60006bffffffffffffffffffffffff821115613968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261399d57600080fd5b50813567ffffffffffffffff8111156139b557600080fd5b6020830191508360208285010111156139cd57600080fd5b9250929050565b600080602083850312156139e757600080fd5b823567ffffffffffffffff8111156139fe57600080fd5b613a0a8582860161398b565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613a6957613a69613a16565b60405290565b604051610160810167ffffffffffffffff81118282101715613a6957613a69613a16565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a16565b604052919050565b63ffffffff8116811461272257600080fd5b803561117081613ae2565b68ffffffffffffffffff8116811461272257600080fd5b803561117081613aff565b64ffffffffff8116811461272257600080fd5b803561117081613b21565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613b9057600080fd5b613b98613a45565b613ba183613af4565b8152613baf60208401613af4565b6020820152613bc060408401613af4565b6040820152613bd160608401613af4565b6060820152613be260808401613b16565b6080820152613bf360a08401613b34565b60a0820152613c0460c08401613b3f565b60c0820152613c1560e08401613b51565b60e0820152610100613c28818501613af4565b908201529392505050565b60005b83811015613c4e578181015183820152602001613c36565b50506000910152565b60008151808452613c6f816020860160208601613c33565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061376b6020830184613c57565b600082601f830112613cc557600080fd5b813567ffffffffffffffff811115613cdf57613cdf613a16565b613d1060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613a93565b818152846020838601011115613d2557600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613d5457600080fd5b813567ffffffffffffffff811115613d6b57600080fd5b613d7784828501613cb4565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461272257600080fd5b803561117081613d7f565b6bffffffffffffffffffffffff8116811461272257600080fd5b803561117081613dac565b60008060408385031215613de457600080fd5b8235613def81613d7f565b91506020830135613dff81613dac565b809150509250929050565b600081518084526020808501945080840160005b83811015613e5057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e1e565b509495945050505050565b60208152600061376b6020830184613e0a565b600060208284031215613e8057600080fd5b5035919050565b600060208284031215613e9957600080fd5b813567ffffffffffffffff811115613eb057600080fd5b8201610160818503121561376b57600080fd5b805182526020810151613eee602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613f0e60408401826bffffffffffffffffffffffff169052565b506060810151613f36606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613f52608084018267ffffffffffffffff169052565b5060a0810151613f6a60a084018263ffffffff169052565b5060c0810151613f8760c084018268ffffffffffffffffff169052565b5060e0810151613fa460e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161385a8284613ec3565b60008083601f840112613ffd57600080fd5b50813567ffffffffffffffff81111561401557600080fd5b6020830191508360208260051b85010111156139cd57600080fd5b60008060008060008060008060e0898b03121561404c57600080fd5b606089018a81111561405d57600080fd5b8998503567ffffffffffffffff8082111561407757600080fd5b6140838c838d0161398b565b909950975060808b013591508082111561409c57600080fd5b6140a88c838d01613feb565b909750955060a08b01359150808211156140c157600080fd5b506140ce8b828c01613feb565b999c989b50969995989497949560c00135949350505050565b815163ffffffff90811682526020808401518216908301526040808401518216908301526060808401519182169083015261012082019050608083015161413b608084018268ffffffffffffffffff169052565b5060a083015161415460a084018264ffffffffff169052565b5060c083015161416a60c084018261ffff169052565b5060e083015161419a60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461272257600080fd5b8035611170816141b6565b6000806000806000608086880312156141ef57600080fd5b85356141fa816141b6565b9450602086013567ffffffffffffffff81111561421657600080fd5b6142228882890161398b565b909550935050604086013561423681613ae2565b949793965091946060013592915050565b600067ffffffffffffffff82111561426157614261613a16565b5060051b60200190565b600082601f83011261427c57600080fd5b8135602061429161428c83614247565b613a93565b82815260059290921b840181019181810190868411156142b057600080fd5b8286015b848110156142d45780356142c781613d7f565b83529183019183016142b4565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561430957600080fd5b863567ffffffffffffffff8082111561432157600080fd5b61432d8a838b0161426b565b9750602089013591508082111561434357600080fd5b61434f8a838b0161426b565b965061435d60408a016142df565b9550606089013591508082111561437357600080fd5b61437f8a838b01613cb4565b945061438d60808a016141cc565b935060a08901359150808211156143a357600080fd5b506143b089828a01613cb4565b9150509295509295509295565b6000602082840312156143cf57600080fd5b813561376b81613d7f565b600181811c908216806143ee57607f821691505b602082108103614427577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156144545750805b601f850160051c820191505b81811015610a8857828155600101614460565b67ffffffffffffffff83111561448b5761448b613a16565b61449f8361449983546143da565b8361442d565b6000601f8411600181146144f157600085156144bb5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614587565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145405786850135825560209485019460019092019101614520565b508682101561457b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613aff565b6000602082840312156145ab57600080fd5b815161376b81613aff565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561270a5761270a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361466a5761466a6145b6565b5060010190565b6000610160823603121561468457600080fd5b61468c613a6f565b823567ffffffffffffffff8111156146a357600080fd5b6146af36828601613cb4565b825250602083013560208201526146c860408401613da1565b60408201526146d960608401613dc6565b60608201526146ea60808401613b16565b60808201526146fb60a084016141cc565b60a082015261470c60c084016141cc565b60c082015261471d60e08401613af4565b60e0820152610100614730818501613b3f565b908201526101206147428482016141cc565b90820152610140614754848201613da1565b9082015292915050565b60006020828403121561477057600080fd5b813561376b816141b6565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126147b057600080fd5b83018035915067ffffffffffffffff8211156147cb57600080fd5b6020019150368190038213156139cd57600080fd5b6000602082840312156147f257600080fd5b61376b82613b3f565b60006020828403121561480d57600080fd5b813561376b81613ae2565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061320f60e0830184613ec3565b60ff818116838216019081111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061491b5761491b6148d9565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761385a5761385a6145b6565b8181038181111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561270a5761270a6145b6565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152614a238184018a613e0a565b90508281036080840152614a378189613e0a565b905060ff871660a084015282810360c0840152614a548187613c57565b905067ffffffffffffffff851660e0840152828103610100840152614a798185613c57565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a08688031215614abb57600080fd5b614ac486614a89565b9450602086015193506040860151925060608601519150614ae760808701614a89565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614b1257614b126148d9565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561270a5761270a6145b6565b6bffffffffffffffffffffffff8181168382160280821691908281146141ae576141ae6145b6565b8082018082111561385a5761385a6145b6565b67ffffffffffffffff81811683821601908082111561270a5761270a6145b6565b600082601f830112614bb057600080fd5b81356020614bc061428c83614247565b82815260059290921b84018101918181019086841115614bdf57600080fd5b8286015b848110156142d45780358352918301918301614be3565b600082601f830112614c0b57600080fd5b81356020614c1b61428c83614247565b82815260059290921b84018101918181019086841115614c3a57600080fd5b8286015b848110156142d457803567ffffffffffffffff811115614c5e5760008081fd5b614c6c8986838b0101613cb4565b845250918301918301614c3e565b600080600080600060a08688031215614c9257600080fd5b853567ffffffffffffffff80821115614caa57600080fd5b614cb689838a01614b9f565b96506020880135915080821115614ccc57600080fd5b614cd889838a01614bfa565b95506040880135915080821115614cee57600080fd5b614cfa89838a01614bfa565b94506060880135915080821115614d1057600080fd5b614d1c89838a01614bfa565b93506080880135915080821115614d3257600080fd5b50614d3f88828901614bfa565b9150509295509295909350565b600082614d5b57614d5b6148d9565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614da78285018b613e0a565b91508382036080850152614dbb828a613e0a565b915060ff881660a085015283820360c0850152614dd88288613c57565b90861660e08501528381036101008501529050614a798185613c57565b805161117081613d7f565b805161117081613dac565b8051611170816141b6565b805161117081613ae2565b805161117081613b21565b60006101608284031215614e3f57600080fd5b614e47613a6f565b82518152614e5760208401614df5565b6020820152614e6860408401614e00565b6040820152614e7960608401614df5565b6060820152614e8a60808401614e0b565b6080820152614e9b60a08401614e16565b60a0820152614eac60c0840161458e565b60c0820152614ebd60e0840161458e565b60e0820152610100614ed0818501614e21565b90820152610120614ee2848201614e21565b90820152610140613c28848201614e16565b64ffffffffff81811683821601908082111561270a5761270a6145b6565b6000610200808352614f268184018a613c57565b90508281036020840152614f3a8189613c57565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614f83905060a0830184613ec3565b979650505050505050565b60008060408385031215614fa157600080fd5b825160078110614fb057600080fd5b6020840151909250613dff81613dac565b600060208284031215614fd357600080fd5b5051919050565b60008351614fec818460208801613c33565b835190830190615000818360208801613c33565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", + 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\":\"structFunctionsBillingConfig\",\"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\":\"structFunctionsBillingConfig\",\"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\":\"structFunctionsBillingConfig\",\"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\":\"structFunctionsBillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620056d0380380620056d083398101604081905262000034916200046d565b8282828233806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000139565b5050506001600160a01b038116620000ed57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200012d82620001e4565b5050505050506200062c565b336001600160a01b03821603620001935760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee62000342565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033790839062000576565b60405180910390a150565b6200034c6200034e565b565b6000546001600160a01b031633146200034c5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000086565b80516001600160a01b0381168114620003c257600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f957634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c257600080fd5b80516001600160481b0381168114620003c257600080fd5b805164ffffffffff81168114620003c257600080fd5b805161ffff81168114620003c257600080fd5b80516001600160e01b0381168114620003c257600080fd5b60008060008385036101608112156200048557600080fd5b6200049085620003aa565b935061012080601f1983011215620004a757600080fd5b620004b1620003c7565b9150620004c160208701620003ff565b8252620004d160408701620003ff565b6020830152620004e460608701620003ff565b6040830152620004f760808701620003ff565b60608301526200050a60a0870162000414565b60808301526200051d60c087016200042c565b60a08301526200053060e0870162000442565b60c08301526101006200054581880162000455565b60e084015262000557828801620003ff565b908301525091506200056d6101408501620003aa565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005c960808401826001600160481b03169052565b5060a0830151620005e360a084018264ffffffffff169052565b5060c0830151620005fa60c084018261ffff169052565b5060e08301516200061660e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805161505e6200067260003960008181610845015281816109d301528181610ca601528181610f3a01528181611045015281816117890152613490015261505e6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046139d4565b61059c565b005b6101a56101b5366004613b7d565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e322e300000000081525081565b6040516102039190613ca1565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613d42565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613dd1565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046139d4565b610d92565b6102a0610de2565b6040516102039190613e5b565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613e6e565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613e87565b610fd4565b6040516102039190613fdc565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004614030565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b60405161020391906140e7565b61053b6105363660046141d7565b611785565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f66118e5565b6101a561056e3660046142f0565b61193c565b61057b6124b8565b604051908152602001610203565b6101a56105973660046143bd565b612711565b6105a4612725565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec828483614473565b505050565b6105f96127a8565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906108369083906140e7565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d29190614599565b905090565b6108df6127b0565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6127a8565b610ba26127b0565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561460a565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614639565b9050610bb1565b5050565b610d9a612725565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec828483614473565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e60906143da565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea8906143da565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed4906143da565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614671565b61295c565b90506110bf60608301604084016143bd565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a0880161475e565b61111f610160880161014089016143bd565b611129888061477b565b61113b6101208b016101008c016147e0565b60208b01356111516101008d0160e08e016147fb565b8b60405161116799989796959493929190614818565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16111d68a8a8a8a8a8a612dfa565b6003546000906002906111f49060ff808216916101009004166148c0565b6111fe9190614908565b6112099060016148c0565b60ff169050878114611277576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b878614611306576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e6774680000000000000000000000000000000000000000000000006064820152608401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113495761134961492a565b600281111561135a5761135a61492a565b90525090506002816020015160028111156113775761137761492a565b141580156113c057506006816000015160ff168154811061139a5761139a61460a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611427576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b5050505061143361396c565b6000808a8a604051611446929190614959565b60405190819003812061145d918e90602001614969565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117675760006001848984602081106114c6576114c661460a565b6114d391901a601b6148c0565b8e8e868181106114e5576114e561460a565b905060200201358d8d878181106114fe576114fe61460a565b905060200201356040516000815260200160405260405161153b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561155d573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156115dd576115dd61492a565b60028111156115ee576115ee61492a565b905250925060018360200151600281111561160b5761160b61492a565b14611672576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061168c5761168c61460a565b602002015173ffffffffffffffffffffffffffffffffffffffff161461170e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117285761172861460a565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117536001866148c0565b9450508061176090614639565b90506114a7565b505050611778833383858e8e612eb1565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561182557600080fd5b505afa158015611839573d6000803e3d6000fd5b5050505066038d7ea4c6800082111561187e576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611888610841565b905060006118cb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b90506118d9858583856130b0565b98975050505050505050565b6060600c80546118f4906143da565b905060000361192f576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea8906143da565b855185518560ff16601f8311156119af576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611a19576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611aa7576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611ab281600361497d565b8311611b1a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611b22612725565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611b69908861321d565b60055415611d1e57600554600090611b8390600190614994565b9050600060058281548110611b9a57611b9a61460a565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611bd457611bd461460a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611c5457611c546149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611cbd57611cbd6149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611b69915050565b60005b8151518110156122d557815180516000919083908110611d4357611d4361460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611dc8576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d70747900000000000000006044820152606401610b0d565b600073ffffffffffffffffffffffffffffffffffffffff1682602001518281518110611df657611df661460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611e7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d7074790000006044820152606401610b0d565b60006004600084600001518481518110611e9757611e9761460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611ee157611ee161492a565b14611f48576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611f7957611f7961460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561201a5761201a61492a565b02179055506000915061202a9050565b60046000846020015184815181106120445761204461460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561208e5761208e61492a565b146120f5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106121285761212861460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156121c9576121c961492a565b0217905550508251805160059250839081106121e7576121e761460a565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106122635761226361460a565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806122cd81614639565b915050611d21565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161238d918491740100000000000000000000000000000000000000009004166149d6565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123ec4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613236565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986124a3988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926149f3565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266a9190614aa3565b50935050925050804261267d9190614994565b836020015163ffffffff1610801561269f57506000836020015163ffffffff16115b156126cd57505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361270a576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b612719612725565b612722816132e1565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146127a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6127a6612725565b600b546bffffffffffffffffffffffff166000036127ca57565b60006127d4610de2565b80519091506000819003612814576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546000906128339083906bffffffffffffffffffffffff16614af3565b905060005b828110156128fe5781600a60008684815181106128575761285761460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128bf9190614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806128f790614639565b9050612838565b506129098282614b43565b600b80546000906129299084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612b17576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612b548560e001513a8488608001516130b0565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612bb0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612bc99190614b6b565b905060003087604001518860a001518960c001516001612be99190614b7e565b8a5180516020918201206101008d015160e08e0151604051612c9d98979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612dac9190613fdc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612e0782602061497d565b612e1285602061497d565b612e1e88610144614b6b565b612e289190614b6b565b612e329190614b6b565b612e3d906000614b6b565b9050368114612ea8576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b600080808080612ec386880188614c7a565b84519499509297509095509350915060ff16801580612ee3575084518114155b80612eef575083518114155b80612efb575082518114155b80612f07575081518114155b15612f6e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e67746800000000006044820152606401610b0d565b60005b818110156130a1576000613006888381518110612f9057612f9061460a565b6020026020010151888481518110612faa57612faa61460a565b6020026020010151888581518110612fc457612fc461460a565b6020026020010151888681518110612fde57612fde61460a565b6020026020010151888781518110612ff857612ff861460a565b6020026020010151886133d6565b9050600081600681111561301c5761301c61492a565b1480613039575060018160068111156130375761303761492a565b145b15613090578782815181106130505761305061460a565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b5061309a81614639565b9050612f71565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561310b57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b600854600090612710906131259063ffffffff168761497d565b61312f9190614d4c565b6131399086614b6b565b60085490915060009087906131729063ffffffff6c010000000000000000000000008204811691680100000000000000009004166149d6565b61317c91906149d6565b63ffffffff16905060006131c66000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b905060006131e7826131d8858761497d565b6131e29190614b6b565b61382c565b9050600061320368ffffffffffffffffff808916908a16614b1e565b905061320f8183614b1e565b9a9950505050505050505050565b6000613227610de2565b511115610d8e57610d8e6127b0565b6000808a8a8a8a8a8a8a8a8a60405160200161325a99989796959493929190614d60565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133ed9190614e2c565b905060003a8261012001518361010001516134089190614ef4565b64ffffffffff16613419919061497d565b905060008460ff166134616000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b61346b9190614d4c565b9050600061347c6131e28385614b6b565b905060006134893a61382c565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff16896134e89190614b1e565b338d6040518763ffffffff1660e01b815260040161350b96959493929190614f12565b60408051808303816000875af1158015613529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354d9190614f8e565b909250905060008260068111156135665761356661492a565b1480613583575060018260068111156135815761358161492a565b145b156136d95760008e8152600760205260408120556135a18185614b1e565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161360d91859116614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b61368c9190614b1e565b6136969190614b1e565b6136a09190614b1e565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b6000466136f681613860565b1561377257606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376b9190614fc1565b9392505050565b61377b81613883565b156138235773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161500a604891396040516020016137db929190614fda565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016138069190613ca1565b602060405180830381865afa158015613747573d6000803e3d6000fd5b50600092915050565b600061385a6138396124b8565b61384b84670de0b6b3a764000061497d565b6138559190614d4c565b6138ca565b92915050565b600061a4b1821480613874575062066eed82145b8061385a57505062066eee1490565b6000600a82148061389557506101a482145b806138a2575062aa37dc82145b806138ae575061210582145b806138bb575062014a3382145b8061385a57505062014a341490565b60006bffffffffffffffffffffffff821115613968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261399d57600080fd5b50813567ffffffffffffffff8111156139b557600080fd5b6020830191508360208285010111156139cd57600080fd5b9250929050565b600080602083850312156139e757600080fd5b823567ffffffffffffffff8111156139fe57600080fd5b613a0a8582860161398b565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613a6957613a69613a16565b60405290565b604051610160810167ffffffffffffffff81118282101715613a6957613a69613a16565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a16565b604052919050565b63ffffffff8116811461272257600080fd5b803561117081613ae2565b68ffffffffffffffffff8116811461272257600080fd5b803561117081613aff565b64ffffffffff8116811461272257600080fd5b803561117081613b21565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613b9057600080fd5b613b98613a45565b613ba183613af4565b8152613baf60208401613af4565b6020820152613bc060408401613af4565b6040820152613bd160608401613af4565b6060820152613be260808401613b16565b6080820152613bf360a08401613b34565b60a0820152613c0460c08401613b3f565b60c0820152613c1560e08401613b51565b60e0820152610100613c28818501613af4565b908201529392505050565b60005b83811015613c4e578181015183820152602001613c36565b50506000910152565b60008151808452613c6f816020860160208601613c33565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061376b6020830184613c57565b600082601f830112613cc557600080fd5b813567ffffffffffffffff811115613cdf57613cdf613a16565b613d1060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613a93565b818152846020838601011115613d2557600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613d5457600080fd5b813567ffffffffffffffff811115613d6b57600080fd5b613d7784828501613cb4565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461272257600080fd5b803561117081613d7f565b6bffffffffffffffffffffffff8116811461272257600080fd5b803561117081613dac565b60008060408385031215613de457600080fd5b8235613def81613d7f565b91506020830135613dff81613dac565b809150509250929050565b600081518084526020808501945080840160005b83811015613e5057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e1e565b509495945050505050565b60208152600061376b6020830184613e0a565b600060208284031215613e8057600080fd5b5035919050565b600060208284031215613e9957600080fd5b813567ffffffffffffffff811115613eb057600080fd5b8201610160818503121561376b57600080fd5b805182526020810151613eee602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613f0e60408401826bffffffffffffffffffffffff169052565b506060810151613f36606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613f52608084018267ffffffffffffffff169052565b5060a0810151613f6a60a084018263ffffffff169052565b5060c0810151613f8760c084018268ffffffffffffffffff169052565b5060e0810151613fa460e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161385a8284613ec3565b60008083601f840112613ffd57600080fd5b50813567ffffffffffffffff81111561401557600080fd5b6020830191508360208260051b85010111156139cd57600080fd5b60008060008060008060008060e0898b03121561404c57600080fd5b606089018a81111561405d57600080fd5b8998503567ffffffffffffffff8082111561407757600080fd5b6140838c838d0161398b565b909950975060808b013591508082111561409c57600080fd5b6140a88c838d01613feb565b909750955060a08b01359150808211156140c157600080fd5b506140ce8b828c01613feb565b999c989b50969995989497949560c00135949350505050565b815163ffffffff90811682526020808401518216908301526040808401518216908301526060808401519182169083015261012082019050608083015161413b608084018268ffffffffffffffffff169052565b5060a083015161415460a084018264ffffffffff169052565b5060c083015161416a60c084018261ffff169052565b5060e083015161419a60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461272257600080fd5b8035611170816141b6565b6000806000806000608086880312156141ef57600080fd5b85356141fa816141b6565b9450602086013567ffffffffffffffff81111561421657600080fd5b6142228882890161398b565b909550935050604086013561423681613ae2565b949793965091946060013592915050565b600067ffffffffffffffff82111561426157614261613a16565b5060051b60200190565b600082601f83011261427c57600080fd5b8135602061429161428c83614247565b613a93565b82815260059290921b840181019181810190868411156142b057600080fd5b8286015b848110156142d45780356142c781613d7f565b83529183019183016142b4565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561430957600080fd5b863567ffffffffffffffff8082111561432157600080fd5b61432d8a838b0161426b565b9750602089013591508082111561434357600080fd5b61434f8a838b0161426b565b965061435d60408a016142df565b9550606089013591508082111561437357600080fd5b61437f8a838b01613cb4565b945061438d60808a016141cc565b935060a08901359150808211156143a357600080fd5b506143b089828a01613cb4565b9150509295509295509295565b6000602082840312156143cf57600080fd5b813561376b81613d7f565b600181811c908216806143ee57607f821691505b602082108103614427577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156144545750805b601f850160051c820191505b81811015610a8857828155600101614460565b67ffffffffffffffff83111561448b5761448b613a16565b61449f8361449983546143da565b8361442d565b6000601f8411600181146144f157600085156144bb5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614587565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145405786850135825560209485019460019092019101614520565b508682101561457b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613aff565b6000602082840312156145ab57600080fd5b815161376b81613aff565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561270a5761270a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361466a5761466a6145b6565b5060010190565b6000610160823603121561468457600080fd5b61468c613a6f565b823567ffffffffffffffff8111156146a357600080fd5b6146af36828601613cb4565b825250602083013560208201526146c860408401613da1565b60408201526146d960608401613dc6565b60608201526146ea60808401613b16565b60808201526146fb60a084016141cc565b60a082015261470c60c084016141cc565b60c082015261471d60e08401613af4565b60e0820152610100614730818501613b3f565b908201526101206147428482016141cc565b90820152610140614754848201613da1565b9082015292915050565b60006020828403121561477057600080fd5b813561376b816141b6565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126147b057600080fd5b83018035915067ffffffffffffffff8211156147cb57600080fd5b6020019150368190038213156139cd57600080fd5b6000602082840312156147f257600080fd5b61376b82613b3f565b60006020828403121561480d57600080fd5b813561376b81613ae2565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061320f60e0830184613ec3565b60ff818116838216019081111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061491b5761491b6148d9565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761385a5761385a6145b6565b8181038181111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561270a5761270a6145b6565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152614a238184018a613e0a565b90508281036080840152614a378189613e0a565b905060ff871660a084015282810360c0840152614a548187613c57565b905067ffffffffffffffff851660e0840152828103610100840152614a798185613c57565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a08688031215614abb57600080fd5b614ac486614a89565b9450602086015193506040860151925060608601519150614ae760808701614a89565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614b1257614b126148d9565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561270a5761270a6145b6565b6bffffffffffffffffffffffff8181168382160280821691908281146141ae576141ae6145b6565b8082018082111561385a5761385a6145b6565b67ffffffffffffffff81811683821601908082111561270a5761270a6145b6565b600082601f830112614bb057600080fd5b81356020614bc061428c83614247565b82815260059290921b84018101918181019086841115614bdf57600080fd5b8286015b848110156142d45780358352918301918301614be3565b600082601f830112614c0b57600080fd5b81356020614c1b61428c83614247565b82815260059290921b84018101918181019086841115614c3a57600080fd5b8286015b848110156142d457803567ffffffffffffffff811115614c5e5760008081fd5b614c6c8986838b0101613cb4565b845250918301918301614c3e565b600080600080600060a08688031215614c9257600080fd5b853567ffffffffffffffff80821115614caa57600080fd5b614cb689838a01614b9f565b96506020880135915080821115614ccc57600080fd5b614cd889838a01614bfa565b95506040880135915080821115614cee57600080fd5b614cfa89838a01614bfa565b94506060880135915080821115614d1057600080fd5b614d1c89838a01614bfa565b93506080880135915080821115614d3257600080fd5b50614d3f88828901614bfa565b9150509295509295909350565b600082614d5b57614d5b6148d9565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614da78285018b613e0a565b91508382036080850152614dbb828a613e0a565b915060ff881660a085015283820360c0850152614dd88288613c57565b90861660e08501528381036101008501529050614a798185613c57565b805161117081613d7f565b805161117081613dac565b8051611170816141b6565b805161117081613ae2565b805161117081613b21565b60006101608284031215614e3f57600080fd5b614e47613a6f565b82518152614e5760208401614df5565b6020820152614e6860408401614e00565b6040820152614e7960608401614df5565b6060820152614e8a60808401614e0b565b6080820152614e9b60a08401614e16565b60a0820152614eac60c0840161458e565b60c0820152614ebd60e0840161458e565b60e0820152610100614ed0818501614e21565b90820152610120614ee2848201614e21565b90820152610140613c28848201614e16565b64ffffffffff81811683821601908082111561270a5761270a6145b6565b6000610200808352614f268184018a613c57565b90508281036020840152614f3a8189613c57565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614f83905060a0830184613ec3565b979650505050505050565b60008060408385031215614fa157600080fd5b825160078110614fb057600080fd5b6020840151909250613dff81613dac565b600060208284031215614fd357600080fd5b5051919050565b60008351614fec818460208801613c33565b835190830190615000818360208801613c33565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI diff --git a/core/gethwrappers/functions/generated/functions_router/functions_router.go b/core/gethwrappers/functions/generated/functions_router/functions_router.go index 592f95b568..368ef65560 100644 --- a/core/gethwrappers/functions/generated/functions_router/functions_router.go +++ b/core/gethwrappers/functions/generated/functions_router/functions_router.go @@ -70,8 +70,8 @@ type IFunctionsSubscriptionsSubscription struct { } var FunctionsRouterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateRequestId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"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\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutCallback\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"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\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionIdStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionIdEnd\",\"type\":\"uint64\"}],\"name\":\"getSubscriptionsInRange\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription[]\",\"name\":\"subscriptions\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"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\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200673c3803806200673c833981016040819052620000349162000549565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200071a565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b4620002c0565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b9291019062000323565b5060a08201516002909101805460c0909301516001600160481b031662010000026001600160581b031990931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e98590620002b590839062000652565b60405180910390a150565b60065461010090046001600160a01b03163314620003215760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b82805482825590600052602060002090600701600890048101928215620003c75791602002820160005b838211156200039357835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026200034d565b8015620003c55782816101000a81549063ffffffff021916905560040160208160030104928301926001030262000393565b505b50620003d5929150620003d9565b5090565b5b80821115620003d55760008155600101620003da565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200042b576200042b620003f0565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200045c576200045c620003f0565b604052919050565b805161ffff811681146200047757600080fd5b919050565b80516001600160481b03811681146200047757600080fd5b80516001600160e01b0319811681146200047757600080fd5b600082601f830112620004bf57600080fd5b815160206001600160401b03821115620004dd57620004dd620003f0565b8160051b620004ee82820162000431565b92835284810182019282810190878511156200050957600080fd5b83870192505b848310156200053e57825163ffffffff811681146200052e5760008081fd5b825291830191908301906200050f565b979650505050505050565b600080604083850312156200055d57600080fd5b82516001600160a01b03811681146200057557600080fd5b60208401519092506001600160401b03808211156200059357600080fd5b9084019060e08287031215620005a857600080fd5b620005b262000406565b620005bd8362000464565b8152620005cd602084016200047c565b6020820152620005e06040840162000494565b6040820152620005f36060840162000464565b60608201526080830151828111156200060b57600080fd5b6200061988828601620004ad565b6080830152506200062d60a0840162000464565b60a08201526200064060c084016200047c565b60c08201528093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160e060a0840152805161010084018190526000929182019083906101208601905b80831015620006e857835163ffffffff168252928401926001929092019190840190620006c0565b5060a087015161ffff811660c0880152935060c08701516001600160481b03811660e088015293509695505050505050565b608051615fea62000752600039600081816111cd0152818161208c015281816129b801528181612a7c01526135d30152615fea6000f3fe608060405234801561001057600080fd5b50600436106102e95760003560e01c80637341c10c11610191578063b734c0f4116100e3578063e72f6e3011610097578063ea320e0b11610071578063ea320e0b146106dd578063ec2454e5146106f0578063f2fde38b1461071057600080fd5b8063e72f6e30146106a4578063e82622aa146106b7578063e82ad7d4146106ca57600080fd5b8063c3f909d4116100c8578063c3f909d414610669578063cc77470a1461067e578063d7ae1d301461069157600080fd5b8063b734c0f41461064b578063badc3eb61461065357600080fd5b80639f87fad711610145578063a4c0ed361161011f578063a4c0ed361461061d578063a9c9a91814610630578063aab396bd1461064357600080fd5b80639f87fad7146105e2578063a21a23e4146105f5578063a47c7696146105fd57600080fd5b8063823597401161017657806382359740146105a45780638456cb59146105b75780638da5cb5b146105bf57600080fd5b80637341c10c1461058957806379ba50971461059c57600080fd5b806341db4ca31161024a5780635ed6dfba116101fe57806366419970116101d857806366419970146104e1578063674603d0146105085780636a2215de1461055157600080fd5b80635ed6dfba146104a85780636162a323146104bb57806366316d8d146104ce57600080fd5b80634b8832d31161022f5780634b8832d31461045057806355fedefa146104635780635c975abb1461049157600080fd5b806341db4ca31461041c578063461d27621461043d57600080fd5b80631ded3b36116102a1578063330605291161028657806333060529146103e05780633e871e4d146104015780633f4ba83a1461041457600080fd5b80631ded3b361461039f5780632a905ccc146103b257600080fd5b806310fc49c1116102d257806310fc49c11461032357806312b5834914610336578063181f5a771461035657600080fd5b806302bcc5b6146102ee5780630c5d49cb14610303575b600080fd5b6103016102fc366004614ba6565b610723565b005b61030b608481565b60405161ffff90911681526020015b60405180910390f35b610301610331366004614be7565b610783565b6000546040516bffffffffffffffffffffffff909116815260200161031a565b6103926040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076312e302e3000000000000000000081525081565b60405161031a9190614c8e565b6103016103ad366004614ca1565b61087f565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161031a565b6103f36103ee366004614f8c565b6108b1565b60405161031a929190615074565b61030161040f366004615135565b610c7c565b610301610e91565b61042f61042a366004615249565b610ea3565b60405190815260200161031a565b61042f61044b366004615249565b610f03565b61030161045e3660046152cd565b610f0f565b61042f610471366004614ba6565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161031a565b6103016104b63660046152fb565b61105d565b6103016104c93660046153bd565b611216565b6103016104dc3660046152fb565b611396565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161031a565b61051b610516366004615490565b61147f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161031a565b61056461055f3660046154be565b61150f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031a565b6103016105973660046152cd565b6115ce565b610301611781565b6103016105b2366004614ba6565b6118a8565b6103016119ef565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610564565b6103016105f03660046152cd565b6119ff565b6104ef611daa565b61061061060b366004614ba6565b611f37565b60405161031a91906155a7565b61030161062b3660046155ba565b61206c565b61056461063e3660046154be565b6122b8565b60095461042f565b610301612317565b61065b612463565b60405161031a929190615616565b610671612533565b60405161031a919061566d565b6104ef61068c366004615749565b61269a565b61030161069f3660046152cd565b61291a565b6103016106b2366004615749565b61297f565b6103016106c5366004615766565b612af8565b6104986106d8366004614ba6565b612db7565b6103016106eb3660046154be565b612f06565b6107036106fe3660046157dc565b612f13565b60405161031a91906157fa565b61030161071e366004615749565b6131a8565b61072b6131b9565b610734816131c1565b67ffffffffffffffff81166000908152600360205260408120546107809183916c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690613237565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107e8576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106108035761080361587a565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff161115610879576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107df565b50505050565b6108876131b9565b610890826131c1565b67ffffffffffffffff90911660009081526003602081905260409091200155565b6000806108bc613689565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610925576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516000908152600560205260409020548061098a5783516020850151604051600295507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b60405180910390a25060009050610c71565b808460405160200161099c91906158db565b60405160208183030381529060405280519060200120146109f45783516020850151604051600695507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b8361012001518460a0015163ffffffff16610a0f9190615a37565b64ffffffffff165a1015610a5a5783516020850151604051600495507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b506000610a708460a0015163ffffffff16613691565b610a7a9088615a55565b9050600081878660c0015168ffffffffffffffffff16610a9a9190615a7d565b610aa49190615a7d565b9050610ab38560800151611f37565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b2b5784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b60405180910390a25060009150610c719050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b905784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b505082516000908152600560205260408120819055835160a08501516060860151610bc092918c918c9190613733565b8051909150610bd0576001610bd3565b60005b92506000610c0d8560800151866040015187606001518860c0015168ffffffffffffffffff168c610c078860200151613691565b8d6138f1565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610c6496959493929190615aa2565b60405180910390a3519150505b965096945050505050565b610c84613c17565b8151815181141580610c965750600881115b15610ccd576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e47576000848281518110610cec57610cec61587a565b602002602001015190506000848381518110610d0a57610d0a61587a565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610d75575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610dac576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020526040908190205490517f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f48191610e2c91859173ffffffffffffffffffffffffffffffffffffffff1690859092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1505080610e4090615b25565b9050610cd0565b506040805180820190915283815260208082018490528451600d91610e709183918801906149e6565b506020828101518051610e899260018501920190614a2d565b505050505050565b610e99613c17565b610ea1613c9d565b565b600080610eaf8361150f565b9050610ef783828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613d1a9050565b98975050505050505050565b600080610eaf836122b8565b610f17613689565b610f20826140ef565b610f286141b5565b73ffffffffffffffffffffffffffffffffffffffff81161580610f8f575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15610fc6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6110656131b9565b806bffffffffffffffffffffffff1660000361109b5750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611107576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b30600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff1661118a9190615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061121183836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b505050565b61121e613c17565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361130592600b92910190614aa7565b5060a08201516002909101805460c09093015168ffffffffffffffffff1662010000027fffffffffffffffffffffffffffffffffffffffffff000000000000000000000090931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e9859061138b90839061566d565b60405180910390a150565b61139e613689565b806bffffffffffffffffffffffff166000036113e6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611452576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b33600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600d5460ff8216101561159857600d805460ff83169081106115375761153761587a565b9060005260206000200154830361158857600e805460ff831690811061155f5761155f61587a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b61159181615b82565b9050611513565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107df565b6115d6613689565b6115df826140ef565b6115e76141b5565b60006115f6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff821611611658576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107df565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff16156116a057505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff163314611802576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107df565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6118b0613689565b6118b86141b5565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611958576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107df565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611774565b6119f7613c17565b610ea161434c565b611a07613689565b611a10826140ef565b611a186141b5565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151582526101008104851693820193909352690100000000000000000090920490921691810191909152611a9782846143a7565b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611aec576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611b3c575b5050505050905060005b8151811015611d0f578373ffffffffffffffffffffffffffffffffffffffff16828281518110611ba357611ba361587a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611cff578160018351611bd59190615ba1565b81518110611be557611be561587a565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611c2857611c2861587a565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611ca257611ca2615bb4565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611d0f565b611d0881615b25565b9050611b71565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a250505050565b6000611db4613689565b611dbc6141b5565b60028054600090611dd69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611e4c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611ee792600285019290910190614a2d565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a0810191909152611f71826131c1565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561205257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612027575b505050505081526020016003820154815250509050919050565b612074613689565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146120e3576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461211d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061212b82840184614ba6565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166121a4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906121db8385615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff166122319190615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846122989190615c0a565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611509576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107df565b61231f613c17565b60005b600d54811015612442576000600d60000182815481106123445761234461587a565b906000526020600020015490506000600d60010183815481106123695761236961587a565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905561243b81615b25565b9050612322565b50600d60006124518282614b51565b61245f600183016000614b51565b5050565b606080600d600001600d600101818054806020026020016040519081016040528092919081815260200182805480156124bb57602002820191906000526020600020905b8154815260200190600101908083116124a7575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561252457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f9575b50505050509050915091509091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a0810182905260c08101919091526040805160e08082018352600a805461ffff808216855262010000820468ffffffffffffffffff166020808701919091526b010000000000000000000000830490941b7fffffffff0000000000000000000000000000000000000000000000000000000016858701526f01000000000000000000000000000000909104166060840152600b805485518185028101850190965280865293949193608086019383018282801561266557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116126285790505b50505091835250506002919091015461ffff8116602083015262010000900468ffffffffffffffffff16604090910152919050565b60006126a4613689565b6126ac6141b5565b600280546000906126c69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c081018252600080825233602083015291810182905260608101829052919250608082019060405190808252806020026020018201604052801561273c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926127d792600285019290910190614a2d565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b612922613689565b61292b826140ef565b6129336141b5565b61293c82612db7565b15612973576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f82826001613237565b6129876131b9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a389190615c1d565b6000549091506bffffffffffffffffffffffff1681811015611211576000612a608284615ba1565b9050612aa373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836142bf565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612b00613689565b60005b81811015611211576000838383818110612b1f57612b1f61587a565b90506101600201803603810190612b369190615c36565b80516080820151600082815260056020908152604091829020549151949550929391929091612b67918691016158db565b6040516020818303038152906040528051906020012014612bb4576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612bf9576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf90602401600060405180830381600087803b158015612c6757600080fd5b505af1158015612c7b573d6000803e3d6000fd5b50505060408085015167ffffffffffffffff84166000908152600360205291822060010180549193509190612cbf9084906bffffffffffffffffffffffff16615b5d565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612d479185916901000000000000000000900416615c53565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612db090615b25565b9050612b03565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612e2f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612e04575b5050505050905060005b8151811015612efc57600060046000848481518110612e5a57612e5a61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612eeb57506001949350505050565b50612ef581615b25565b9050612e39565b5060009392505050565b612f0e613c17565b600955565b60608167ffffffffffffffff168367ffffffffffffffff161180612f46575060025467ffffffffffffffff908116908316115b80612f5b575060025467ffffffffffffffff16155b15612f92576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612f9c8383615c74565b612fa7906001615c53565b67ffffffffffffffff1667ffffffffffffffff811115612fc957612fc9614ccd565b60405190808252806020026020018201604052801561304657816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612fe75790505b50905060005b6130568484615c74565b67ffffffffffffffff1681116131a1576003600061307e8367ffffffffffffffff8816615c0a565b67ffffffffffffffff1681526020808201929092526040908101600020815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561316057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613135575b505050505081526020016003820154815250508282815181106131855761318561587a565b60200260200101819052508061319a90615b25565b905061304c565b5092915050565b6131b0613c17565b6107808161441b565b610ea1613c17565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610780576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff83166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561331857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132ed575b50505091835250506003919091015460209091015280519091506000805b83608001515181101561342e5760008460800151828151811061335b5761335b61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff8116600090815260048352604080822067ffffffffffffffff808e16845294529020549092506133bb9169010000000000000000009091041684615c53565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260046020908152604080832067ffffffffffffffff8c168452909152902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055915061342781615b25565b9050613336565b5067ffffffffffffffff8616600090815260036020526040812081815560018101829055906134606002830182614b51565b50600060039190910155600c5461ffff81169062010000900468ffffffffffffffffff1685801561349e57508161ffff168367ffffffffffffffff16105b1561355a576000846bffffffffffffffffffffffff168268ffffffffffffffffff16116134d6578168ffffffffffffffffff166134d8565b845b90506bffffffffffffffffffffffff81161561355857306000908152600160205260408120805483929061351b9084906bffffffffffffffffffffffff16615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080856135559190615b5d565b94505b505b6bffffffffffffffffffffffff841615613617576000805485919081906135909084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061361787856bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff891681526bffffffffffffffffffffffff8616602082015267ffffffffffffffff8a16917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050505050565b610ea1614517565b60006bffffffffffffffffffffffff82111561372f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107df565b5090565b60408051606080820183526000808352602083015291810191909152813b1580156137865750506040805160608101825260008082526020808301829052835191825281018352918101919091526138e8565b600a546040516000916b010000000000000000000000900460e01b906137b4908a908a908a90602401615c95565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f01000000000000000000000000000000909104169260009283928392820181803683370190505090505a8481101561388257600080fd5b8490036040810481038a1061389657600080fd5b505a60008087516020890160008d8ff193505a900391503d60848111156138bb575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015293505050505b95945050505050565b604080518082019091526000808252602082015260006139118486615a55565b90506000816139208886615a7d565b61392a9190615a7d565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff80831691161080613991575067ffffffffffffffff8a166000908152600360205260409020600101546bffffffffffffffffffffffff808b169116105b156139f45767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107df565b67ffffffffffffffff8a1660009081526003602052604081208054839290613a2b9084906bffffffffffffffffffffffff16615b5d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c16600090815260036020526040812060010180548d94509092613a7f91859116615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508184613ab99190615a7d565b3360009081526001602052604081208054909190613ae69084906bffffffffffffffffffffffff16615a7d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b94509092613b2d91859116615a7d565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613bb19185916901000000000000000000900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107df565b613ca5614584565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613d24613689565b613d2d856131c1565b613d3733866143a7565b613d418583610783565b8351600003613d7b576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613d8686611f37565b90506000613d94338861147f565b600a54604080516101608101825289815267ffffffffffffffff8b1660009081526003602081815293822001549495506201000090930468ffffffffffffffffff169373ffffffffffffffffffffffffffffffffffffffff8d169263a631571e929190820190815233602082015260408881015189519190920191613e1891615b5d565b6bffffffffffffffffffffffff1681526020018568ffffffffffffffffff1681526020018c67ffffffffffffffff168152602001866020015167ffffffffffffffff1681526020018963ffffffff1681526020018a61ffff168152602001866040015167ffffffffffffffff168152602001876020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613ec49190615cc0565b610160604051808303816000875af1158015613ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f089190615e25565b805160009081526005602052604090205490915015613f595780516040517f304f32e800000000000000000000000000000000000000000000000000000000815260048101919091526024016107df565b604051806101600160405280826000015181526020018b73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018a67ffffffffffffffff1681526020018763ffffffff1681526020018368ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff1681525060405160200161404491906158db565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550614084338a83604001516145f0565b8867ffffffffffffffff168b82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9876020015133328e8e8e8a604001516040516140d89796959493929190615ef8565b60405180910390a4519a9950505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680614166576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461245f576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806141e55750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061424690339060248101615f70565b602060405180830381865afa158015614263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142879190615f9f565b610780576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107df565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112119084906146cb565b614354614517565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613cf03390565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661245f576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82160361449a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107df565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff1615610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107df565b60065460ff16610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107df565b67ffffffffffffffff82166000908152600360205260408120600101805483929061462a9084906bffffffffffffffffffffffff16615a7d565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff80891685529252909120805460019450909284926146a0928492900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061472d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166147d79092919063ffffffff16565b805190915015611211578080602001905181019061474b9190615f9f565b611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107df565b60606147e684846000856147ee565b949350505050565b606082471015614880576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107df565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516148a99190615fc1565b60006040518083038185875af1925050503d80600081146148e6576040519150601f19603f3d011682016040523d82523d6000602084013e6148eb565b606091505b50915091506148fc87838387614907565b979650505050505050565b6060831561499d5782516000036149965773ffffffffffffffffffffffffffffffffffffffff85163b614996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107df565b50816147e6565b6147e683838151156149b25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df9190614c8e565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a21578251825591602001919060010190614a06565b5061372f929150614b6b565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a2157825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614a4d565b82805482825590600052602060002090600701600890048101928215614a215791602002820160005b83821115614b1457835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ad0565b8015614b445782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614b14565b505061372f929150614b6b565b508054600082559060005260206000209081019061078091905b5b8082111561372f5760008155600101614b6c565b67ffffffffffffffff8116811461078057600080fd5b8035614ba181614b80565b919050565b600060208284031215614bb857600080fd5b8135614bc381614b80565b9392505050565b63ffffffff8116811461078057600080fd5b8035614ba181614bca565b60008060408385031215614bfa57600080fd5b8235614c0581614b80565b91506020830135614c1581614bca565b809150509250929050565b60005b83811015614c3b578181015183820152602001614c23565b50506000910152565b60008151808452614c5c816020860160208601614c20565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000614bc36020830184614c44565b60008060408385031215614cb457600080fd5b8235614cbf81614b80565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614d2057614d20614ccd565b60405290565b60405160e0810167ffffffffffffffff81118282101715614d2057614d20614ccd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614d9057614d90614ccd565b604052919050565b600082601f830112614da957600080fd5b813567ffffffffffffffff811115614dc357614dc3614ccd565b614df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614d49565b818152846020838601011115614e0957600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e26565b73ffffffffffffffffffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e4b565b68ffffffffffffffffff8116811461078057600080fd5b8035614ba181614e78565b64ffffffffff8116811461078057600080fd5b8035614ba181614e9a565b60006101608284031215614ecb57600080fd5b614ed3614cfc565b905081358152614ee560208301614e6d565b6020820152614ef660408301614e40565b6040820152614f0760608301614e6d565b6060820152614f1860808301614b96565b6080820152614f2960a08301614bdc565b60a0820152614f3a60c08301614e8f565b60c0820152614f4b60e08301614e8f565b60e0820152610100614f5e818401614ead565b90820152610120614f70838201614ead565b90820152610140614f82838201614bdc565b9082015292915050565b6000806000806000806102008789031215614fa657600080fd5b863567ffffffffffffffff80821115614fbe57600080fd5b614fca8a838b01614d98565b97506020890135915080821115614fe057600080fd5b50614fed89828a01614d98565b9550506040870135614ffe81614e26565b9350606087013561500e81614e26565b9250608087013561501e81614e4b565b915061502d8860a08901614eb8565b90509295509295509295565b60078110615070577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b604081016150828285615039565b6bffffffffffffffffffffffff831660208301529392505050565b600067ffffffffffffffff8211156150b7576150b7614ccd565b5060051b60200190565b600082601f8301126150d257600080fd5b813560206150e76150e28361509d565b614d49565b82815260059290921b8401810191818101908684111561510657600080fd5b8286015b8481101561512a57803561511d81614e4b565b835291830191830161510a565b509695505050505050565b6000806040838503121561514857600080fd5b823567ffffffffffffffff8082111561516057600080fd5b818501915085601f83011261517457600080fd5b813560206151846150e28361509d565b82815260059290921b840181019181810190898411156151a357600080fd5b948201945b838610156151c1578535825294820194908201906151a8565b965050860135925050808211156151d757600080fd5b506151e4858286016150c1565b9150509250929050565b60008083601f84011261520057600080fd5b50813567ffffffffffffffff81111561521857600080fd5b60208301915083602082850101111561523057600080fd5b9250929050565b803561ffff81168114614ba157600080fd5b60008060008060008060a0878903121561526257600080fd5b863561526d81614b80565b9550602087013567ffffffffffffffff81111561528957600080fd5b61529589828a016151ee565b90965094506152a8905060408801615237565b925060608701356152b881614bca565b80925050608087013590509295509295509295565b600080604083850312156152e057600080fd5b82356152eb81614b80565b91506020830135614c1581614e4b565b6000806040838503121561530e57600080fd5b823561531981614e4b565b91506020830135614c1581614e26565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114614ba157600080fd5b600082601f83011261536a57600080fd5b8135602061537a6150e28361509d565b82815260059290921b8401810191818101908684111561539957600080fd5b8286015b8481101561512a5780356153b081614bca565b835291830191830161539d565b6000602082840312156153cf57600080fd5b813567ffffffffffffffff808211156153e757600080fd5b9083019060e082860312156153fb57600080fd5b615403614d26565b61540c83615237565b815261541a60208401614e8f565b602082015261542b60408401615329565b604082015261543c60608401615237565b606082015260808301358281111561545357600080fd5b61545f87828601615359565b60808301525061547160a08401615237565b60a082015261548260c08401614e8f565b60c082015295945050505050565b600080604083850312156154a357600080fd5b82356154ae81614e4b565b91506020830135614c1581614b80565b6000602082840312156154d057600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561551d57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016154eb565b509495945050505050565b60006bffffffffffffffffffffffff808351168452602083015173ffffffffffffffffffffffffffffffffffffffff8082166020870152826040860151166040870152806060860151166060870152505050608082015160c0608085015261559360c08501826154d7565b60a093840151949093019390935250919050565b602081526000614bc36020830184615528565b600080600080606085870312156155d057600080fd5b84356155db81614e4b565b935060208501359250604085013567ffffffffffffffff8111156155fe57600080fd5b61560a878288016151ee565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b8281101561564f57815184529284019290840190600101615633565b5050508381038285015261566381866154d7565b9695505050505050565b60006020808352610100830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160e060a0860152818151808452610120870191508483019350600092505b8083101561571a57835163ffffffff1682529284019260019290920191908401906156f4565b5060a087015161ffff811660c0880152935060c087015168ffffffffffffffffff811660e08801529350615663565b60006020828403121561575b57600080fd5b8135614bc381614e4b565b6000806020838503121561577957600080fd5b823567ffffffffffffffff8082111561579157600080fd5b818501915085601f8301126157a557600080fd5b8135818111156157b457600080fd5b866020610160830285010111156157ca57600080fd5b60209290920196919550909350505050565b600080604083850312156157ef57600080fd5b82356154ae81614b80565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561586d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261585b858351615528565b94509285019290850190600101615821565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016147e66040830184615039565b8151815260208083015161016083019161590c9084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015161592c60408401826bffffffffffffffffffffffff169052565b506060830151615954606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615970608084018267ffffffffffffffff169052565b5060a083015161598860a084018263ffffffff169052565b5060c08301516159a560c084018268ffffffffffffffffff169052565b5060e08301516159c260e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff818116838216028082169190828114615a0057615a00615a08565b6bffffffffffffffffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff86166020820152615adc6040820186615039565b60c060608201526000615af260c0830186614c44565b8281036080840152615b048186614c44565b905082810360a0840152615b188185614c44565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b5657615b56615a08565b5060010190565b6bffffffffffffffffffffffff8281168282160390808211156131a1576131a1615a08565b600060ff821660ff8103615b9857615b98615a08565b60010192915050565b8181038181111561150957611509615a08565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff808316818103615c0057615c00615a08565b6001019392505050565b8082018082111561150957611509615a08565b600060208284031215615c2f57600080fd5b5051919050565b60006101608284031215615c4957600080fd5b614bc38383614eb8565b67ffffffffffffffff8181168382160190808211156131a1576131a1615a08565b67ffffffffffffffff8281168282160390808211156131a1576131a1615a08565b838152606060208201526000615cae6060830185614c44565b82810360408401526156638185614c44565b6020815260008251610160806020850152615cdf610180850183614c44565b9150602085015160408501526040850151615d12606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e0850151610100615d898187018363ffffffff169052565b8601519050610120615da08682018361ffff169052565b8601519050610140615dbd8682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b8051614ba181614e4b565b8051614ba181614e26565b8051614ba181614b80565b8051614ba181614bca565b8051614ba181614e78565b8051614ba181614e9a565b60006101608284031215615e3857600080fd5b615e40614cfc565b82518152615e5060208401615de3565b6020820152615e6160408401615dee565b6040820152615e7260608401615de3565b6060820152615e8360808401615df9565b6080820152615e9460a08401615e04565b60a0820152615ea560c08401615e0f565b60c0820152615eb660e08401615e0f565b60e0820152610100615ec9818501615e1a565b90820152610120615edb848201615e1a565b90820152610140615eed848201615e04565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615f3960e0830187614c44565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006147e66040830184614c44565b600060208284031215615fb157600080fd5b81518015158114614bc357600080fd5b60008251615fd3818460208701614c20565b919091019291505056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateRequestId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"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\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutFulfillment\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"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\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionIdStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionIdEnd\",\"type\":\"uint64\"}],\"name\":\"getSubscriptionsInRange\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription[]\",\"name\":\"subscriptions\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"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\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b506040516200673c3803806200673c833981016040819052620000349162000549565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200071a565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b4620002c0565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b9291019062000323565b5060a08201516002909101805460c0909301516001600160481b031662010000026001600160581b031990931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e98590620002b590839062000652565b60405180910390a150565b60065461010090046001600160a01b03163314620003215760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b82805482825590600052602060002090600701600890048101928215620003c75791602002820160005b838211156200039357835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026200034d565b8015620003c55782816101000a81549063ffffffff021916905560040160208160030104928301926001030262000393565b505b50620003d5929150620003d9565b5090565b5b80821115620003d55760008155600101620003da565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200042b576200042b620003f0565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200045c576200045c620003f0565b604052919050565b805161ffff811681146200047757600080fd5b919050565b80516001600160481b03811681146200047757600080fd5b80516001600160e01b0319811681146200047757600080fd5b600082601f830112620004bf57600080fd5b815160206001600160401b03821115620004dd57620004dd620003f0565b8160051b620004ee82820162000431565b92835284810182019282810190878511156200050957600080fd5b83870192505b848310156200053e57825163ffffffff811681146200052e5760008081fd5b825291830191908301906200050f565b979650505050505050565b600080604083850312156200055d57600080fd5b82516001600160a01b03811681146200057557600080fd5b60208401519092506001600160401b03808211156200059357600080fd5b9084019060e08287031215620005a857600080fd5b620005b262000406565b620005bd8362000464565b8152620005cd602084016200047c565b6020820152620005e06040840162000494565b6040820152620005f36060840162000464565b60608201526080830151828111156200060b57600080fd5b6200061988828601620004ad565b6080830152506200062d60a0840162000464565b60a08201526200064060c084016200047c565b60c08201528093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160e060a0840152805161010084018190526000929182019083906101208601905b80831015620006e857835163ffffffff168252928401926001929092019190840190620006c0565b5060a087015161ffff811660c0880152935060c08701516001600160481b03811660e088015293509695505050505050565b608051615fea62000752600039600081816111cd0152818161208c015281816129b801528181612a7c01526135d30152615fea6000f3fe608060405234801561001057600080fd5b50600436106102e95760003560e01c80637341c10c11610191578063b734c0f4116100e3578063e72f6e3011610097578063ea320e0b11610071578063ea320e0b146106dd578063ec2454e5146106f0578063f2fde38b1461071057600080fd5b8063e72f6e30146106a4578063e82622aa146106b7578063e82ad7d4146106ca57600080fd5b8063c3f909d4116100c8578063c3f909d414610669578063cc77470a1461067e578063d7ae1d301461069157600080fd5b8063b734c0f41461064b578063badc3eb61461065357600080fd5b80639f87fad711610145578063a4c0ed361161011f578063a4c0ed361461061d578063a9c9a91814610630578063aab396bd1461064357600080fd5b80639f87fad7146105e2578063a21a23e4146105f5578063a47c7696146105fd57600080fd5b8063823597401161017657806382359740146105a45780638456cb59146105b75780638da5cb5b146105bf57600080fd5b80637341c10c1461058957806379ba50971461059c57600080fd5b806341db4ca31161024a5780635ed6dfba116101fe57806366419970116101d857806366419970146104e1578063674603d0146105085780636a2215de1461055157600080fd5b80635ed6dfba146104a85780636162a323146104bb57806366316d8d146104ce57600080fd5b80634b8832d31161022f5780634b8832d31461045057806355fedefa146104635780635c975abb1461049157600080fd5b806341db4ca31461041c578063461d27621461043d57600080fd5b80631ded3b36116102a1578063330605291161028657806333060529146103e05780633e871e4d146104015780633f4ba83a1461041457600080fd5b80631ded3b361461039f5780632a905ccc146103b257600080fd5b806310fc49c1116102d257806310fc49c11461032357806312b5834914610336578063181f5a771461035657600080fd5b806302bcc5b6146102ee5780630c5d49cb14610303575b600080fd5b6103016102fc366004614ba6565b610723565b005b61030b608481565b60405161ffff90911681526020015b60405180910390f35b610301610331366004614be7565b610783565b6000546040516bffffffffffffffffffffffff909116815260200161031a565b6103926040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076322e302e3000000000000000000081525081565b60405161031a9190614c8e565b6103016103ad366004614ca1565b61087f565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161031a565b6103f36103ee366004614f8c565b6108b1565b60405161031a929190615074565b61030161040f366004615135565b610c7c565b610301610e91565b61042f61042a366004615249565b610ea3565b60405190815260200161031a565b61042f61044b366004615249565b610f03565b61030161045e3660046152cd565b610f0f565b61042f610471366004614ba6565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161031a565b6103016104b63660046152fb565b61105d565b6103016104c93660046153bd565b611216565b6103016104dc3660046152fb565b611396565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161031a565b61051b610516366004615490565b61147f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161031a565b61056461055f3660046154be565b61150f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031a565b6103016105973660046152cd565b6115ce565b610301611781565b6103016105b2366004614ba6565b6118a8565b6103016119ef565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610564565b6103016105f03660046152cd565b6119ff565b6104ef611daa565b61061061060b366004614ba6565b611f37565b60405161031a91906155a7565b61030161062b3660046155ba565b61206c565b61056461063e3660046154be565b6122b8565b60095461042f565b610301612317565b61065b612463565b60405161031a929190615616565b610671612533565b60405161031a919061566d565b6104ef61068c366004615749565b61269a565b61030161069f3660046152cd565b61291a565b6103016106b2366004615749565b61297f565b6103016106c5366004615766565b612af8565b6104986106d8366004614ba6565b612db7565b6103016106eb3660046154be565b612f06565b6107036106fe3660046157dc565b612f13565b60405161031a91906157fa565b61030161071e366004615749565b6131a8565b61072b6131b9565b610734816131c1565b67ffffffffffffffff81166000908152600360205260408120546107809183916c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690613237565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107e8576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106108035761080361587a565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff161115610879576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107df565b50505050565b6108876131b9565b610890826131c1565b67ffffffffffffffff90911660009081526003602081905260409091200155565b6000806108bc613689565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610925576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516000908152600560205260409020548061098a5783516020850151604051600295507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b60405180910390a25060009050610c71565b808460405160200161099c91906158db565b60405160208183030381529060405280519060200120146109f45783516020850151604051600695507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b8361012001518460a0015163ffffffff16610a0f9190615a37565b64ffffffffff165a1015610a5a5783516020850151604051600495507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b506000610a708460a0015163ffffffff16613691565b610a7a9088615a55565b9050600081878660c0015168ffffffffffffffffff16610a9a9190615a7d565b610aa49190615a7d565b9050610ab38560800151611f37565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b2b5784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b60405180910390a25060009150610c719050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b905784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b505082516000908152600560205260408120819055835160a08501516060860151610bc092918c918c9190613733565b8051909150610bd0576001610bd3565b60005b92506000610c0d8560800151866040015187606001518860c0015168ffffffffffffffffff168c610c078860200151613691565b8d6138f1565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610c6496959493929190615aa2565b60405180910390a3519150505b965096945050505050565b610c84613c17565b8151815181141580610c965750600881115b15610ccd576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e47576000848281518110610cec57610cec61587a565b602002602001015190506000848381518110610d0a57610d0a61587a565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610d75575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610dac576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020526040908190205490517f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f48191610e2c91859173ffffffffffffffffffffffffffffffffffffffff1690859092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1505080610e4090615b25565b9050610cd0565b506040805180820190915283815260208082018490528451600d91610e709183918801906149e6565b506020828101518051610e899260018501920190614a2d565b505050505050565b610e99613c17565b610ea1613c9d565b565b600080610eaf8361150f565b9050610ef783828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613d1a9050565b98975050505050505050565b600080610eaf836122b8565b610f17613689565b610f20826140ef565b610f286141b5565b73ffffffffffffffffffffffffffffffffffffffff81161580610f8f575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15610fc6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6110656131b9565b806bffffffffffffffffffffffff1660000361109b5750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611107576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b30600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff1661118a9190615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061121183836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b505050565b61121e613c17565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361130592600b92910190614aa7565b5060a08201516002909101805460c09093015168ffffffffffffffffff1662010000027fffffffffffffffffffffffffffffffffffffffffff000000000000000000000090931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e9859061138b90839061566d565b60405180910390a150565b61139e613689565b806bffffffffffffffffffffffff166000036113e6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611452576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b33600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600d5460ff8216101561159857600d805460ff83169081106115375761153761587a565b9060005260206000200154830361158857600e805460ff831690811061155f5761155f61587a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b61159181615b82565b9050611513565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107df565b6115d6613689565b6115df826140ef565b6115e76141b5565b60006115f6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff821611611658576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107df565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff16156116a057505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff163314611802576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107df565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6118b0613689565b6118b86141b5565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611958576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107df565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611774565b6119f7613c17565b610ea161434c565b611a07613689565b611a10826140ef565b611a186141b5565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151582526101008104851693820193909352690100000000000000000090920490921691810191909152611a9782846143a7565b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611aec576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611b3c575b5050505050905060005b8151811015611d0f578373ffffffffffffffffffffffffffffffffffffffff16828281518110611ba357611ba361587a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611cff578160018351611bd59190615ba1565b81518110611be557611be561587a565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611c2857611c2861587a565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611ca257611ca2615bb4565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611d0f565b611d0881615b25565b9050611b71565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a250505050565b6000611db4613689565b611dbc6141b5565b60028054600090611dd69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611e4c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611ee792600285019290910190614a2d565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a0810191909152611f71826131c1565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561205257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612027575b505050505081526020016003820154815250509050919050565b612074613689565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146120e3576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461211d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061212b82840184614ba6565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166121a4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906121db8385615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff166122319190615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846122989190615c0a565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611509576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107df565b61231f613c17565b60005b600d54811015612442576000600d60000182815481106123445761234461587a565b906000526020600020015490506000600d60010183815481106123695761236961587a565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905561243b81615b25565b9050612322565b50600d60006124518282614b51565b61245f600183016000614b51565b5050565b606080600d600001600d600101818054806020026020016040519081016040528092919081815260200182805480156124bb57602002820191906000526020600020905b8154815260200190600101908083116124a7575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561252457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f9575b50505050509050915091509091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a0810182905260c08101919091526040805160e08082018352600a805461ffff808216855262010000820468ffffffffffffffffff166020808701919091526b010000000000000000000000830490941b7fffffffff0000000000000000000000000000000000000000000000000000000016858701526f01000000000000000000000000000000909104166060840152600b805485518185028101850190965280865293949193608086019383018282801561266557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116126285790505b50505091835250506002919091015461ffff8116602083015262010000900468ffffffffffffffffff16604090910152919050565b60006126a4613689565b6126ac6141b5565b600280546000906126c69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c081018252600080825233602083015291810182905260608101829052919250608082019060405190808252806020026020018201604052801561273c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926127d792600285019290910190614a2d565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b612922613689565b61292b826140ef565b6129336141b5565b61293c82612db7565b15612973576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f82826001613237565b6129876131b9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a389190615c1d565b6000549091506bffffffffffffffffffffffff1681811015611211576000612a608284615ba1565b9050612aa373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836142bf565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612b00613689565b60005b81811015611211576000838383818110612b1f57612b1f61587a565b90506101600201803603810190612b369190615c36565b80516080820151600082815260056020908152604091829020549151949550929391929091612b67918691016158db565b6040516020818303038152906040528051906020012014612bb4576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612bf9576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf90602401600060405180830381600087803b158015612c6757600080fd5b505af1158015612c7b573d6000803e3d6000fd5b50505060408085015167ffffffffffffffff84166000908152600360205291822060010180549193509190612cbf9084906bffffffffffffffffffffffff16615b5d565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612d479185916901000000000000000000900416615c53565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612db090615b25565b9050612b03565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612e2f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612e04575b5050505050905060005b8151811015612efc57600060046000848481518110612e5a57612e5a61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612eeb57506001949350505050565b50612ef581615b25565b9050612e39565b5060009392505050565b612f0e613c17565b600955565b60608167ffffffffffffffff168367ffffffffffffffff161180612f46575060025467ffffffffffffffff908116908316115b80612f5b575060025467ffffffffffffffff16155b15612f92576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612f9c8383615c74565b612fa7906001615c53565b67ffffffffffffffff1667ffffffffffffffff811115612fc957612fc9614ccd565b60405190808252806020026020018201604052801561304657816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612fe75790505b50905060005b6130568484615c74565b67ffffffffffffffff1681116131a1576003600061307e8367ffffffffffffffff8816615c0a565b67ffffffffffffffff1681526020808201929092526040908101600020815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561316057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613135575b505050505081526020016003820154815250508282815181106131855761318561587a565b60200260200101819052508061319a90615b25565b905061304c565b5092915050565b6131b0613c17565b6107808161441b565b610ea1613c17565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610780576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff83166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561331857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132ed575b50505091835250506003919091015460209091015280519091506000805b83608001515181101561342e5760008460800151828151811061335b5761335b61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff8116600090815260048352604080822067ffffffffffffffff808e16845294529020549092506133bb9169010000000000000000009091041684615c53565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260046020908152604080832067ffffffffffffffff8c168452909152902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055915061342781615b25565b9050613336565b5067ffffffffffffffff8616600090815260036020526040812081815560018101829055906134606002830182614b51565b50600060039190910155600c5461ffff81169062010000900468ffffffffffffffffff1685801561349e57508161ffff168367ffffffffffffffff16105b1561355a576000846bffffffffffffffffffffffff168268ffffffffffffffffff16116134d6578168ffffffffffffffffff166134d8565b845b90506bffffffffffffffffffffffff81161561355857306000908152600160205260408120805483929061351b9084906bffffffffffffffffffffffff16615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080856135559190615b5d565b94505b505b6bffffffffffffffffffffffff841615613617576000805485919081906135909084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061361787856bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff891681526bffffffffffffffffffffffff8616602082015267ffffffffffffffff8a16917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050505050565b610ea1614517565b60006bffffffffffffffffffffffff82111561372f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107df565b5090565b60408051606080820183526000808352602083015291810191909152813b1580156137865750506040805160608101825260008082526020808301829052835191825281018352918101919091526138e8565b600a546040516000916b010000000000000000000000900460e01b906137b4908a908a908a90602401615c95565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f01000000000000000000000000000000909104169260009283928392820181803683370190505090505a8481101561388257600080fd5b8490036040810481038a1061389657600080fd5b505a60008087516020890160008d8ff193505a900391503d60848111156138bb575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015293505050505b95945050505050565b604080518082019091526000808252602082015260006139118486615a55565b90506000816139208886615a7d565b61392a9190615a7d565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff80831691161080613991575067ffffffffffffffff8a166000908152600360205260409020600101546bffffffffffffffffffffffff808b169116105b156139f45767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107df565b67ffffffffffffffff8a1660009081526003602052604081208054839290613a2b9084906bffffffffffffffffffffffff16615b5d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c16600090815260036020526040812060010180548d94509092613a7f91859116615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508184613ab99190615a7d565b3360009081526001602052604081208054909190613ae69084906bffffffffffffffffffffffff16615a7d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b94509092613b2d91859116615a7d565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613bb19185916901000000000000000000900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107df565b613ca5614584565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613d24613689565b613d2d856131c1565b613d3733866143a7565b613d418583610783565b8351600003613d7b576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613d8686611f37565b90506000613d94338861147f565b600a54604080516101608101825289815267ffffffffffffffff8b1660009081526003602081815293822001549495506201000090930468ffffffffffffffffff169373ffffffffffffffffffffffffffffffffffffffff8d169263a631571e929190820190815233602082015260408881015189519190920191613e1891615b5d565b6bffffffffffffffffffffffff1681526020018568ffffffffffffffffff1681526020018c67ffffffffffffffff168152602001866020015167ffffffffffffffff1681526020018963ffffffff1681526020018a61ffff168152602001866040015167ffffffffffffffff168152602001876020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613ec49190615cc0565b610160604051808303816000875af1158015613ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f089190615e25565b805160009081526005602052604090205490915015613f595780516040517f304f32e800000000000000000000000000000000000000000000000000000000815260048101919091526024016107df565b604051806101600160405280826000015181526020018b73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018a67ffffffffffffffff1681526020018763ffffffff1681526020018368ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff1681525060405160200161404491906158db565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550614084338a83604001516145f0565b8867ffffffffffffffff168b82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9876020015133328e8e8e8a604001516040516140d89796959493929190615ef8565b60405180910390a4519a9950505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680614166576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461245f576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806141e55750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061424690339060248101615f70565b602060405180830381865afa158015614263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142879190615f9f565b610780576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107df565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112119084906146cb565b614354614517565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613cf03390565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661245f576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82160361449a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107df565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff1615610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107df565b60065460ff16610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107df565b67ffffffffffffffff82166000908152600360205260408120600101805483929061462a9084906bffffffffffffffffffffffff16615a7d565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff80891685529252909120805460019450909284926146a0928492900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061472d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166147d79092919063ffffffff16565b805190915015611211578080602001905181019061474b9190615f9f565b611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107df565b60606147e684846000856147ee565b949350505050565b606082471015614880576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107df565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516148a99190615fc1565b60006040518083038185875af1925050503d80600081146148e6576040519150601f19603f3d011682016040523d82523d6000602084013e6148eb565b606091505b50915091506148fc87838387614907565b979650505050505050565b6060831561499d5782516000036149965773ffffffffffffffffffffffffffffffffffffffff85163b614996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107df565b50816147e6565b6147e683838151156149b25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df9190614c8e565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a21578251825591602001919060010190614a06565b5061372f929150614b6b565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a2157825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614a4d565b82805482825590600052602060002090600701600890048101928215614a215791602002820160005b83821115614b1457835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ad0565b8015614b445782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614b14565b505061372f929150614b6b565b508054600082559060005260206000209081019061078091905b5b8082111561372f5760008155600101614b6c565b67ffffffffffffffff8116811461078057600080fd5b8035614ba181614b80565b919050565b600060208284031215614bb857600080fd5b8135614bc381614b80565b9392505050565b63ffffffff8116811461078057600080fd5b8035614ba181614bca565b60008060408385031215614bfa57600080fd5b8235614c0581614b80565b91506020830135614c1581614bca565b809150509250929050565b60005b83811015614c3b578181015183820152602001614c23565b50506000910152565b60008151808452614c5c816020860160208601614c20565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000614bc36020830184614c44565b60008060408385031215614cb457600080fd5b8235614cbf81614b80565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614d2057614d20614ccd565b60405290565b60405160e0810167ffffffffffffffff81118282101715614d2057614d20614ccd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614d9057614d90614ccd565b604052919050565b600082601f830112614da957600080fd5b813567ffffffffffffffff811115614dc357614dc3614ccd565b614df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614d49565b818152846020838601011115614e0957600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e26565b73ffffffffffffffffffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e4b565b68ffffffffffffffffff8116811461078057600080fd5b8035614ba181614e78565b64ffffffffff8116811461078057600080fd5b8035614ba181614e9a565b60006101608284031215614ecb57600080fd5b614ed3614cfc565b905081358152614ee560208301614e6d565b6020820152614ef660408301614e40565b6040820152614f0760608301614e6d565b6060820152614f1860808301614b96565b6080820152614f2960a08301614bdc565b60a0820152614f3a60c08301614e8f565b60c0820152614f4b60e08301614e8f565b60e0820152610100614f5e818401614ead565b90820152610120614f70838201614ead565b90820152610140614f82838201614bdc565b9082015292915050565b6000806000806000806102008789031215614fa657600080fd5b863567ffffffffffffffff80821115614fbe57600080fd5b614fca8a838b01614d98565b97506020890135915080821115614fe057600080fd5b50614fed89828a01614d98565b9550506040870135614ffe81614e26565b9350606087013561500e81614e26565b9250608087013561501e81614e4b565b915061502d8860a08901614eb8565b90509295509295509295565b60078110615070577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b604081016150828285615039565b6bffffffffffffffffffffffff831660208301529392505050565b600067ffffffffffffffff8211156150b7576150b7614ccd565b5060051b60200190565b600082601f8301126150d257600080fd5b813560206150e76150e28361509d565b614d49565b82815260059290921b8401810191818101908684111561510657600080fd5b8286015b8481101561512a57803561511d81614e4b565b835291830191830161510a565b509695505050505050565b6000806040838503121561514857600080fd5b823567ffffffffffffffff8082111561516057600080fd5b818501915085601f83011261517457600080fd5b813560206151846150e28361509d565b82815260059290921b840181019181810190898411156151a357600080fd5b948201945b838610156151c1578535825294820194908201906151a8565b965050860135925050808211156151d757600080fd5b506151e4858286016150c1565b9150509250929050565b60008083601f84011261520057600080fd5b50813567ffffffffffffffff81111561521857600080fd5b60208301915083602082850101111561523057600080fd5b9250929050565b803561ffff81168114614ba157600080fd5b60008060008060008060a0878903121561526257600080fd5b863561526d81614b80565b9550602087013567ffffffffffffffff81111561528957600080fd5b61529589828a016151ee565b90965094506152a8905060408801615237565b925060608701356152b881614bca565b80925050608087013590509295509295509295565b600080604083850312156152e057600080fd5b82356152eb81614b80565b91506020830135614c1581614e4b565b6000806040838503121561530e57600080fd5b823561531981614e4b565b91506020830135614c1581614e26565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114614ba157600080fd5b600082601f83011261536a57600080fd5b8135602061537a6150e28361509d565b82815260059290921b8401810191818101908684111561539957600080fd5b8286015b8481101561512a5780356153b081614bca565b835291830191830161539d565b6000602082840312156153cf57600080fd5b813567ffffffffffffffff808211156153e757600080fd5b9083019060e082860312156153fb57600080fd5b615403614d26565b61540c83615237565b815261541a60208401614e8f565b602082015261542b60408401615329565b604082015261543c60608401615237565b606082015260808301358281111561545357600080fd5b61545f87828601615359565b60808301525061547160a08401615237565b60a082015261548260c08401614e8f565b60c082015295945050505050565b600080604083850312156154a357600080fd5b82356154ae81614e4b565b91506020830135614c1581614b80565b6000602082840312156154d057600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561551d57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016154eb565b509495945050505050565b60006bffffffffffffffffffffffff808351168452602083015173ffffffffffffffffffffffffffffffffffffffff8082166020870152826040860151166040870152806060860151166060870152505050608082015160c0608085015261559360c08501826154d7565b60a093840151949093019390935250919050565b602081526000614bc36020830184615528565b600080600080606085870312156155d057600080fd5b84356155db81614e4b565b935060208501359250604085013567ffffffffffffffff8111156155fe57600080fd5b61560a878288016151ee565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b8281101561564f57815184529284019290840190600101615633565b5050508381038285015261566381866154d7565b9695505050505050565b60006020808352610100830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160e060a0860152818151808452610120870191508483019350600092505b8083101561571a57835163ffffffff1682529284019260019290920191908401906156f4565b5060a087015161ffff811660c0880152935060c087015168ffffffffffffffffff811660e08801529350615663565b60006020828403121561575b57600080fd5b8135614bc381614e4b565b6000806020838503121561577957600080fd5b823567ffffffffffffffff8082111561579157600080fd5b818501915085601f8301126157a557600080fd5b8135818111156157b457600080fd5b866020610160830285010111156157ca57600080fd5b60209290920196919550909350505050565b600080604083850312156157ef57600080fd5b82356154ae81614b80565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561586d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261585b858351615528565b94509285019290850190600101615821565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016147e66040830184615039565b8151815260208083015161016083019161590c9084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015161592c60408401826bffffffffffffffffffffffff169052565b506060830151615954606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615970608084018267ffffffffffffffff169052565b5060a083015161598860a084018263ffffffff169052565b5060c08301516159a560c084018268ffffffffffffffffff169052565b5060e08301516159c260e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff818116838216028082169190828114615a0057615a00615a08565b6bffffffffffffffffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff86166020820152615adc6040820186615039565b60c060608201526000615af260c0830186614c44565b8281036080840152615b048186614c44565b905082810360a0840152615b188185614c44565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b5657615b56615a08565b5060010190565b6bffffffffffffffffffffffff8281168282160390808211156131a1576131a1615a08565b600060ff821660ff8103615b9857615b98615a08565b60010192915050565b8181038181111561150957611509615a08565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff808316818103615c0057615c00615a08565b6001019392505050565b8082018082111561150957611509615a08565b600060208284031215615c2f57600080fd5b5051919050565b60006101608284031215615c4957600080fd5b614bc38383614eb8565b67ffffffffffffffff8181168382160190808211156131a1576131a1615a08565b67ffffffffffffffff8281168282160390808211156131a1576131a1615a08565b838152606060208201526000615cae6060830185614c44565b82810360408401526156638185614c44565b6020815260008251610160806020850152615cdf610180850183614c44565b9150602085015160408501526040850151615d12606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e0850151610100615d898187018363ffffffff169052565b8601519050610120615da08682018361ffff169052565b8601519050610140615dbd8682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b8051614ba181614e4b565b8051614ba181614e26565b8051614ba181614b80565b8051614ba181614bca565b8051614ba181614e78565b8051614ba181614e9a565b60006101608284031215615e3857600080fd5b615e40614cfc565b82518152615e5060208401615de3565b6020820152615e6160408401615dee565b6040820152615e7260608401615de3565b6060820152615e8360808401615df9565b6080820152615e9460a08401615e04565b60a0820152615ea560c08401615e0f565b60c0820152615eb660e08401615e0f565b60e0820152610100615ec9818501615e1a565b90820152610120615edb848201615e1a565b90820152610140615eed848201615e04565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615f3960e0830187614c44565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006147e66040830184614c44565b600060208284031215615fb157600080fd5b81518015158114614bc357600080fd5b60008251615fd3818460208701614c20565b919091019291505056fea164736f6c6343000813000a", } var FunctionsRouterABI = FunctionsRouterMetaData.ABI @@ -677,16 +677,16 @@ func (_FunctionsRouter *FunctionsRouterTransactorSession) CreateSubscriptionWith return _FunctionsRouter.Contract.CreateSubscriptionWithConsumer(&_FunctionsRouter.TransactOpts, consumer) } -func (_FunctionsRouter *FunctionsRouterTransactor) Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { - return _FunctionsRouter.contract.Transact(opts, "fulfill", response, err, juelsPerGas, costWithoutCallback, transmitter, commitment) +func (_FunctionsRouter *FunctionsRouterTransactor) Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { + return _FunctionsRouter.contract.Transact(opts, "fulfill", response, err, juelsPerGas, costWithoutFulfillment, transmitter, commitment) } -func (_FunctionsRouter *FunctionsRouterSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { - return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutCallback, transmitter, commitment) +func (_FunctionsRouter *FunctionsRouterSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { + return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutFulfillment, transmitter, commitment) } -func (_FunctionsRouter *FunctionsRouterTransactorSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { - return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutCallback, transmitter, commitment) +func (_FunctionsRouter *FunctionsRouterTransactorSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { + return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutFulfillment, transmitter, commitment) } func (_FunctionsRouter *FunctionsRouterTransactor) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { @@ -3510,7 +3510,7 @@ type FunctionsRouterInterface interface { CreateSubscriptionWithConsumer(opts *bind.TransactOpts, consumer common.Address) (*types.Transaction, error) - Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) + Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, 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 ac1fc4e83d..3cdd44cbc5 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 @@ -1,13 +1,13 @@ GETH_VERSION: 1.12.0 functions: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.bin 3c972870b0afeb6d73a29ebb182f24956a2cebb127b21c4f867d1ecf19a762db -functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin b2697ad4dfece903a1d34028826a017fa445eb3cd984006f1734fa9d47836ca0 +functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin 6beec092fbb3b619dfe69f1ad23392b0bbaf00327b335e4080f921c7122a57e4 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 97aa7c56d78c703056990eff102279af86b97b11b5855b059e8dd658dc15da8a +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 7e8a63d56d81fe16a51d4196f5ca3e9623eaa04b56a6e8d7dee1eb0c266944ab 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 +functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 1f6d18f9e0846ad74b37a0a6acef5942ab73ace1e84307f201899f69e732e776 functions_v1_events_mock: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.bin 0f0ba42e0cc33c7abc8b8fd4fdfce903748a169886dd5f16cfdd56e75bcf708d ocr2dr: ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.bin d9a794b33f47cc57563d216f7cf3a612309fc3062356a27e30005cf1d59e449d ocr2dr_client: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.bin 84aa63f9dbc5c7eac240db699b09e613ca4c6cd56dab10bdc25b02461b717e21 From c0a5821a4e3d8d9dafbe7ff0e720ffb06aa2d46d Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Thu, 7 Dec 2023 04:56:48 -0500 Subject: [PATCH 283/327] [TT-523] Add Networks for Live Tests (#11358) * Adds A Lot More Networks for Testnet Tests * TT-523 * Enable new network definitions * Clean up reporting * Fix success indicator * Roll-back CTF version * Debug color * Linea contract loader * Reverse time further * tidy * Fix slack colors * Fixes markdown formatting * Fix kuberesolver * Kuberesolver v4 * Tidy * Valid slack blocks * Update CTF * New contract loaders * Fixed contracts and some URLs * Change schedule * Debug * Knocking problems down * Fixed CELO funding * More Cash * Smaller runner * Update actions * Build Tests * Fix runner sizes * Compiled Tests * Control * Update CTF * Network name * Fix selected networks * Moar Cash * Contract Loader * Deprecate Arbitrum Goerli * Upgrade CTF * Fix compile * Enable Scroll * Fix dependencies * Add mockserver logs * Increase timeout * Remove debug * Update CTF * Update Automation Tests * Fix name regex * Actually fix regex * Complete merge --- .github/workflows/live-testnet-tests.yml | 881 ++++++++++++++---- .../contracts/contract_loader.go | 30 +- integration-tests/docker/test_env/test_env.go | 25 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/smoke/ocr_test.go | 3 +- 6 files changed, 767 insertions(+), 178 deletions(-) diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index f174e8847b..2e9809505f 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -1,7 +1,16 @@ +# *** +# This workflow is a monstrosity of copy-paste, and that's to increase legibility in reporting and running, so the code be damned. +# I suspect this can be cleaned up significantly with some clever trickery of the GitHub actions matrices, but I am not that clever. +# We want each chain to run in parallel, but each test within the chain needs to be able to run sequentially +# (we're trying to eliminate this as a requirement, should make it a lot easier). +# Each chain can have a variety of tests to run. +# We also want reporting to be clear in the start-slack-thread and post-test-results-to-slack jobs. +# *** + name: Live Testnet Tests on: schedule: - - cron: "0 0 * * *" # Run nightly + - cron: "0 0 * * *" # Run every Sunday at midnight push: tags: - "*" @@ -11,7 +20,7 @@ env: CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com MOD_CACHE_VERSION: 2 - CHAINLINK_NODE_FUNDING: .1 + CHAINLINK_NODE_FUNDING: .5 CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} @@ -21,20 +30,53 @@ env: SEPOLIA_URLS: ${{ secrets.QA_SEPOLIA_URLS }} SEPOLIA_HTTP_URLS: ${{ secrets.QA_SEPOLIA_HTTP_URLS }} + BSC_TESTNET_URLS: ${{ secrets.QA_BSC_TESTNET_URLS }} + BSC_TESTNET_HTTP_URLS: ${{ secrets.QA_BSC_TESTNET_HTTP_URLS }} + OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} - ARBITRUM_GOERLI_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_URLS }} - ARBITRUM_GOERLI_HTTP_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_HTTP_URLS }} + OPTIMISM_SEPOLIA_URLS: ${{ secrets.QA_OPTIMISM_SEPOLIA_URLS }} + OPTIMISM_SEPOLIA_HTTP_URLS: ${{ secrets.QA_OPTIMISM_SEPOLIA_HTTP_URLS }} + + ARBITRUM_SEPOLIA_URLS: ${{ secrets.QA_ARBITRUM_SEPOLIA_URLS }} + ARBITRUM_SEPOLIA_HTTP_URLS: ${{ secrets.QA_ARBITRUM_SEPOLIA_HTTP_URLS }} + + BASE_GOERLI_URLS: ${{ secrets.QA_BASE_GOERLI_URLS }} + BASE_GOERLI_HTTP_URLS: ${{ secrets.QA_BASE_GOERLI_HTTP_URLS }} + + BASE_SEPOLIA_URLS: ${{ secrets.QA_BASE_SEPOLIA_URLS }} + BASE_SEPOLIA_HTTP_URLS: ${{ secrets.QA_BASE_SEPOLIA_HTTP_URLS }} + + POLYGON_MUMBAI_URLS: ${{ secrets.QA_POLYGON_MUMBAI_URLS }} + POLYGON_MUMBAI_HTTP_URLS: ${{ secrets.QA_POLYGON_MUMBAI_HTTP_URLS }} + + AVALANCHE_FUJI_URLS: ${{ secrets.QA_AVALANCHE_FUJI_URLS }} + AVALANCHE_FUJI_HTTP_URLS: ${{ secrets.QA_AVALANCHE_FUJI_HTTP_URLS }} + + FANTOM_TESTNET_URLS: ${{ secrets.QA_FANTOM_TESTNET_URLS }} + FANTOM_TESTNET_HTTP_URLS: ${{ secrets.QA_FANTOM_TESTNET_HTTP_URLS }} + + CELO_ALFAJORES_URLS: ${{ secrets.QA_CELO_ALFAJORES_URLS }} + CELO_ALFAJORES_HTTP_URLS: ${{ secrets.QA_CELO_ALFAJORES_HTTP_URLS }} + + SCROLL_SEPOLIA_URLS: ${{ secrets.QA_SCROLL_SEPOLIA_URLS }} + SCROLL_SEPOLIA_HTTP_URLS: ${{ secrets.QA_SCROLL_SEPOLIA_HTTP_URLS }} + + LINEA_GOERLI_URLS: ${{ secrets.QA_LINEA_GOERLI_URLS }} + LINEA_GOERLI_HTTP_URLS: ${{ secrets.QA_LINEA_GOERLI_HTTP_URLS }} jobs: + + # Build Test Dependencies + build-chainlink: environment: integration permissions: id-token: write contents: read name: Build Chainlink Image - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu-latest steps: - name: Collect Metrics id: collect-gha-metrics @@ -59,188 +101,41 @@ jobs: AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - # TODO: Re-enable when we have secrets properly configured - # sepolia-smoke-tests: - # environment: integration - # permissions: - # checks: write - # pull-requests: write - # id-token: write - # contents: read - # needs: [build-chainlink] - # env: - # SELECTED_NETWORKS: SEPOLIA - # strategy: - # max-parallel: 1 - # fail-fast: false - # matrix: - # include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - # - product: OCR - # test: TestOCRBasic - # - product: Automation - # test: TestAutomationBasic/registry_2_0 - # name: Sepolia ${{ matrix.product }} Tests - # runs-on: ubuntu-latest - # steps: - # - name: Checkout the repo - # uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - # with: - # ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - # - name: Run Tests - # uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - # env: - # PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - # PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia - # PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - # with: - # test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt - # test_download_vendor_packages_command: cd ./integration-tests && go mod download - # cl_repo: ${{ env.CHAINLINK_IMAGE }} - # cl_image_tag: ${{ github.sha }} - # aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - # dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - # dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - # artifacts_location: ./integration-tests/smoke/logs - # publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results - # token: ${{ secrets.GITHUB_TOKEN }} - # go_mod_path: ./integration-tests/go.mod - # cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - # cache_restore_only: "true" - # QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - # QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - # QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - # - name: Collect Metrics - # if: always() - # id: collect-gha-metrics - # uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - # with: - # basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - # hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - # this-job-name: Sepolia ${{ matrix.product }} Tests - # test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - # continue-on-error: true - - optimism-goerli-smoke-tests: + build-tests: environment: integration permissions: - checks: write - pull-requests: write id-token: write contents: read - needs: [build-chainlink] - env: - SELECTED_NETWORKS: OPTIMISM_GOERLI - strategy: - fail-fast: false - max-parallel: 1 - matrix: - include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - - product: OCR - test: TestOCRBasic - - product: Automation - test: TestAutomationBasic/registry_2_0 - name: Optimism Goerli ${{ matrix.product }} Tests + name: Build Tests Binary runs-on: ubuntu-latest steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-goerli - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt - test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./integration-tests/smoke/logs - publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results - token: ${{ secrets.GITHUB_TOKEN }} - go_mod_path: ./integration-tests/go.mod - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Collect Metrics - if: always() id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Optimism Goerli ${{ matrix.product }} Tests - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + this-job-name: Build Tests Binary continue-on-error: true - - arbitrum-goerli-smoke-tests: - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink] - env: - SELECTED_NETWORKS: ARBITRUM_GOERLI - strategy: - max-parallel: 1 - fail-fast: false - matrix: - include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - - product: OCR - test: TestOCRBasic - - product: Automation - test: TestAutomationBasic/registry_2_0 - name: Arbitrum Goerli ${{ matrix.product }} Tests - runs-on: ubuntu-latest - steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-arbitrum-goerli - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + - name: Build Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./integration-tests/smoke/logs - publish_check_name: Arbitrum Goerli ${{ matrix.product }} Smoke Test Results token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Arbitrum Goerli ${{ matrix.product }} Tests - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - continue-on-error: true + binary_name: tests + + # End Build Test Dependencies - testnet-smoke-tests-notify: + # Reporting Jobs + + start-slack-thread: name: Start Slack Thread if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} environment: integration @@ -252,7 +147,7 @@ jobs: id-token: write contents: read runs-on: ubuntu-latest - needs: [optimism-goerli-smoke-tests, arbitrum-goerli-smoke-tests] + needs: [sepolia-smoke-tests, bsc-testnet-tests, optimism-goerli-smoke-tests, optimism-sepolia-smoke-tests, arbitrum-sepolia-smoke-tests, base-goerli-smoke-tests, base-sepolia-smoke-tests, polygon-mumbai-smoke-tests, avalanche-fuji-smoke-tests, fantom-testnet-smoke-tests, celo-alfajores-smoke-tests, scroll-sepolia-smoke-tests, linea-goerli-smoke-tests] steps: - name: Debug Result run: echo ${{ join(needs.*.result, ',') }} @@ -275,6 +170,13 @@ jobs: "emoji": true } }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "${{ contains(join(needs.*.result, ','), 'failure') && 'Some tests failed, notifying <@U01Q4N37KFG>' || 'All Good!' }}" + } + }, { "type": "divider" }, @@ -292,7 +194,7 @@ jobs: env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} - testnet-smoke-tests-results: + post-test-results-to-slack: name: Post Test Results for ${{ matrix.network }} if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} environment: integration @@ -302,11 +204,11 @@ jobs: id-token: write contents: read runs-on: ubuntu-latest - needs: testnet-smoke-tests-notify + needs: start-slack-thread strategy: fail-fast: false matrix: - network: [Optimism Goerli, Arbitrum Goerli] + network: [Sepolia, Optimism Goerli, Optimism Sepolia, Arbitrum Sepolia, Base Goerli, Base Sepolia, Polygon Mumbai, Avalanche Fuji, Fantom Testnet, Celo Alfajores, Scroll Sepolia, Linea Goerli] steps: - name: Get Results id: test-results @@ -317,7 +219,7 @@ jobs: PARSED_RESULTS=$(curl \ -H "Authorization: Bearer ${{ github.token }}" \ 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ - | jq -r --arg pattern "${{ matrix.network }} (?\\w+) Tests" '.jobs[] + | jq -r --arg pattern "^${{ matrix.network }} (?.*?) Tests$" '.jobs[] | select(.name | test($pattern)) as $job | $job.steps[] | select(.name == "Run Tests") @@ -327,10 +229,13 @@ jobs: echo $PARSED_RESULTS ALL_SUCCESS=true + echo "Checking for failures" + echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")' for row in $(echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")'); do - success=false + ALL_SUCCESS=false break done + echo "Success: $ALL_SUCCESS" echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT @@ -360,16 +265,16 @@ jobs: channel-id: ${{ secrets.QA_SLACK_CHANNEL }} payload: | { - "thread_ts": "${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}", + "thread_ts": "${{ needs.start-slack-thread.outputs.thread_ts }}", "attachments": [ { - "color": "${{ steps.test-results.outputs.all_success && '#2E7D32' || '#C62828' }}", + "color": "${{ steps.test-results.outputs.all_success == 'true' && '#2E7D32' || '#C62828' }}", "blocks": [ { "type": "header", "text": { "type": "plain_text", - "text": "${{ matrix.network }} ${{ steps.test-results.outputs.all_success && ':white_check_mark:' || ':x: Notifying <@U01Q4N37KFG>'}}", + "text": "${{ matrix.network }} ${{ steps.test-results.outputs.all_success == 'true' && ':white_check_mark:' || ':x:'}}", "emoji": true } }, @@ -383,3 +288,635 @@ jobs: } env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + + # End Reporting Jobs + + sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: SEPOLIA + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + bsc-testnet-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: BSC_TESTNET + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: BSC Testnet ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-bsc-testnet + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + optimism-goerli-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: OPTIMISM_GOERLI + strategy: + fail-fast: false + max-parallel: 1 + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Optimism Goerli ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-goerli + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + optimism-sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: OPTIMISM_SEPOLIA + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Optimism Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + arbitrum-sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: ARBITRUM_SEPOLIA + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Arbitrum Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-arbitrum-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + base-goerli-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: BASE_GOERLI + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Base Goerli ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-base-goerli + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + base-sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: BASE_SEPOLIA + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Base Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-base-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + polygon-mumbai-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: POLYGON_MUMBAI + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Polygon Mumbai ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-polygon-mumbai + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + avalanche-fuji-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: AVALANCHE_FUJI + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Avalanche Fuji ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-avalanche-fuji + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + fantom-testnet-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: FANTOM_TESTNET + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Fantom Testnet ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-fantom-testnet + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + celo-alfajores-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: CELO_ALFAJORES + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Celo Alfajores ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-celo-alfajores + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + scroll-sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: SCROLL_SEPOLIA + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Scroll Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-scroll-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + linea-goerli-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: LINEA_GOERLI + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Linea Goerli ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-linea-goerli + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} \ No newline at end of file diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index e66c95138b..0fec424426 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -71,6 +71,14 @@ func NewContractLoader(bcClient blockchain.EVMClient, logger zerolog.Logger) (Co return &PolygonZkEvmContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.WeMixClient: return &WeMixContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.LineaClient: + return &LineaContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.CeloClient: + return &CeloContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.ScrollClient: + return &ScrollContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.FantomClient: + return &FantomContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.BSCClient: return &BSCContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil } @@ -121,7 +129,27 @@ type WeMixContractLoader struct { *EthereumContractLoader } -// BSCContractLoader wraps ethereum contract deployments for BSC +// LineaContractLoader wraps for Linea +type LineaContractLoader struct { + *EthereumContractLoader +} + +// CeloContractLoader wraps for Celo +type CeloContractLoader struct { + *EthereumContractLoader +} + +// ScrollContractLoader wraps for Scroll +type ScrollContractLoader struct { + *EthereumContractLoader +} + +// FantomContractLoader wraps for Fantom +type FantomContractLoader struct { + *EthereumContractLoader +} + +// BSCContractLoader wraps for BSC type BSCContractLoader struct { *EthereumContractLoader } diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index b1b179badc..b04d24a959 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "runtime/debug" + "strings" "testing" "time" @@ -262,7 +263,8 @@ func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { // collectTestLogs collects the logs from all the Chainlink nodes in the test environment and writes them to local files func (te *CLClusterTestEnv) collectTestLogs() error { te.l.Info().Msg("Collecting test logs") - folder := fmt.Sprintf("./logs/%s-%s", te.t.Name(), time.Now().Format("2006-01-02T15-04-05")) + sanitizedNetworkName := strings.ReplaceAll(te.EVMClient.GetNetworkName(), " ", "-") + folder := fmt.Sprintf("./logs/%s-%s-%s", te.t.Name(), sanitizedNetworkName, time.Now().Format("2006-01-02T15-04-05")) if err := os.MkdirAll(folder, os.ModePerm); err != nil { return err } @@ -290,6 +292,27 @@ func (te *CLClusterTestEnv) collectTestLogs() error { }) } + if te.MockAdapter != nil { + eg.Go(func() error { + logFileName := filepath.Join(folder, "mock-adapter.log") + logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer logFile.Close() + logReader, err := te.MockAdapter.Container.Logs(testcontext.Get(te.t)) + if err != nil { + return err + } + _, err = io.Copy(logFile, logReader) + if err != nil { + return err + } + te.l.Info().Str("Container", te.MockAdapter.ContainerName).Str("File", logFileName).Msg("Wrote Logs") + return nil + }) + } + if err := eg.Wait(); err != nil { return err } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 01d7c4dbef..32c35c28a9 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -25,7 +25,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 - github.com/smartcontractkit/chainlink-testing-framework v1.20.0 + github.com/smartcontractkit/chainlink-testing-framework v1.20.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f3d707d18e..21e237923b 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1519,8 +1519,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= -github.com/smartcontractkit/chainlink-testing-framework v1.20.0 h1:gQPQRKJuMh6QTAIMkqZ7v5WkjEmbcoMIX/V6WPVrvuI= -github.com/smartcontractkit/chainlink-testing-framework v1.20.0/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= +github.com/smartcontractkit/chainlink-testing-framework v1.20.1 h1:0hxLRts4yIum52MaE95RuM2Xi1S/R0r4UFExpp00iK4= +github.com/smartcontractkit/chainlink-testing-framework v1.20.1/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 9ed692700a..57afbdc1a4 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) @@ -21,7 +22,7 @@ func TestOCRBasic(t *testing.T) { WithGeth(). WithMockAdapter(). WithCLNodes(6). - WithFunding(big.NewFloat(.01)). + WithFunding(big.NewFloat(.5)). WithStandardCleanup(). Build() require.NoError(t, err) From c545d2c7aa452f4e3c2c6e15c640e4ec39f2cb56 Mon Sep 17 00:00:00 2001 From: Sergey Kudasov Date: Thu, 7 Dec 2023 17:02:17 +0300 Subject: [PATCH 284/327] Devspace non-root/build update (#11510) * move root parts to build inside container * update README + add more resources to the build node --- charts/chainlink-cluster/README.md | 12 +++---- charts/chainlink-cluster/devspace.yaml | 34 ++++++++++--------- .../templates/chainlink-node-deployment.yaml | 10 +++--- charts/chainlink-cluster/values.yaml | 10 ++++++ core/chainlink.devspace.Dockerfile | 20 +++++++++++ integration-tests/load/ocr/README.md | 10 +++--- integration-tests/load/ocr/ocr_test.go | 4 +-- 7 files changed, 64 insertions(+), 36 deletions(-) diff --git a/charts/chainlink-cluster/README.md b/charts/chainlink-cluster/README.md index 5fb5553663..3deb37794a 100644 --- a/charts/chainlink-cluster/README.md +++ b/charts/chainlink-cluster/README.md @@ -16,13 +16,8 @@ nix develop ## New cluster We are using [devspace](https://www.devspace.sh/docs/getting-started/installation?x0=3) -Configure the cluster, see `deployments.app.helm.values` and [values.yaml](./values.yaml) comments +Configure the cluster, see `deployments.app.helm.values` and [values.yaml](./values.yaml) comments for more details -Set your registry for the image, example for `ECR`: -``` -aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin ${aws_account}.dkr.ecr.us-west-2.amazonaws.com -export DEVSPACE_IMAGE="${aws_account}.dkr.ecr.us-west-2.amazonaws.com/chainlink-devspace" -``` Enter the shell and deploy ``` # set your unique namespace if it's a new cluster @@ -45,11 +40,12 @@ Fix something in the code locally, it'd automatically sync, rebuild it inside co make chainlink make chainlink-local-start ``` -If you need to update the whole cluster run `deploy` again with a new set of images + +Reset the pod to original image ``` devspace reset pods -devspace deploy ``` + Destroy the cluster ``` devspace purge diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index cb4c8bfce4..f62b87edf6 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -58,6 +58,16 @@ deployments: - name: node-1 image: ${DEVSPACE_IMAGE} version: latest + # default resources are 300m/1Gi + # first node need more resources to build faster inside container + # at least 2Gi of memory is required otherwise build will fail (OOM) + resources: + requests: + cpu: 2000m + memory: 2048Mi + limits: + cpu: 2000m + memory: 2048Mi # override default config per node # for example, use OCRv2 P2P setup, the whole config # toml: | @@ -105,13 +115,6 @@ deployments: - name: node-6 image: ${DEVSPACE_IMAGE} version: latest - resources: - requests: - cpu: 350m - memory: 1024Mi - limits: - cpu: 350m - memory: 1024Mi # each CL node have a dedicated PostgreSQL 11.15 # use StatefulSet by setting: @@ -231,7 +234,7 @@ profiles: patches: - op: replace path: dev.app.workingDir - value: /home/root/chainlink/integration-tests + value: /home/chainlink/integration-tests - op: replace path: dev.app.container value: runner @@ -256,21 +259,20 @@ profiles: # This is a list of `dev` containers that are based on the containers created by your deployments dev: app: - workingDir: /home/root/chainlink + workingDir: /home/chainlink container: node labelSelector: instance: node-1 # Sync files between the local filesystem and the development container sync: - - path: ../../core/services/chainlink:/home/root/chainlink/core/services/chainlink + - path: ../../core/services/chainlink:/home/chainlink/core/services/chainlink printLogs: true disableDownload: true - - path: ../..:/home/root/chainlink + - path: ../..:/home/chainlink printLogs: true disableDownload: true uploadExcludePaths: - integration-tests/ - - .git/ - .github/ - belt/ - charts/ @@ -280,16 +282,16 @@ dev: - integration-scripts/ - testdata/ - evm-test-helpers/ - - tools/ # Open a terminal and use the following command terminal: command: bash ssh: enabled: true proxyCommands: - - command: devspace - - command: kubectl - - command: helm +# TODO: access issues +# - command: devspace +# - command: kubectl +# - command: helm - gitCredentials: true ports: - port: "2345" diff --git a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml index 463453aff9..a08c31c2c4 100644 --- a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml @@ -71,14 +71,14 @@ spec: initialDelaySeconds: 15 periodSeconds: 5 failureThreshold: 20 - {{ if (hasKey $.Values.chainlink "resources") }} + {{ if (hasKey $cfg "resources") }} resources: requests: - memory: {{ default "1024Mi" $.Values.chainlink.resources.requests.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.requests.cpu }} + memory: {{ default "1024Mi" $cfg.resources.requests.memory }} + cpu: {{ default "300m" $cfg.resources.requests.cpu }} limits: - memory: {{ default "1024Mi" $.Values.chainlink.resources.limits.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.limits.cpu }} + memory: {{ default "1024Mi" $cfg.resources.limits.memory }} + cpu: {{ default "300m" $cfg.resources.limits.cpu }} {{ else }} {{ end }} {{- with $.Values.nodeSelector }} diff --git a/charts/chainlink-cluster/values.yaml b/charts/chainlink-cluster/values.yaml index eb93e6cefc..feba141444 100644 --- a/charts/chainlink-cluster/values.yaml +++ b/charts/chainlink-cluster/values.yaml @@ -25,6 +25,16 @@ chainlink: nodes: - name: node-1 image: "public.ecr.aws/chainlink/chainlink:latest" + # default resources are 300m/1Gi + # first node need more resources to build faster inside container + # at least 2Gi of memory is required otherwise build will fail (OOM) + resources: + requests: + cpu: 2000m + memory: 2048Mi + limits: + cpu: 2000m + memory: 2048Mi # override default config per node # for example, use OCRv2 P2P setup, the whole config # toml: | diff --git a/core/chainlink.devspace.Dockerfile b/core/chainlink.devspace.Dockerfile index 88d3cec16a..c639190a80 100644 --- a/core/chainlink.devspace.Dockerfile +++ b/core/chainlink.devspace.Dockerfile @@ -17,6 +17,22 @@ COPY . . # Build the golang binary RUN make install-chainlink +# Link LOOP Plugin source dirs with simple names +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-feeds | xargs -I % ln -s % /chainlink-feeds +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana | xargs -I % ln -s % /chainlink-solana + +# Build image: Plugins +FROM golang:1.21-bullseye as buildplugins +RUN go version + +WORKDIR /chainlink-feeds +COPY --from=buildgo /chainlink-feeds . +RUN go install ./cmd/chainlink-feeds + +WORKDIR /chainlink-solana +COPY --from=buildgo /chainlink-solana . +RUN go install ./pkg/solana/cmd/chainlink-solana + # Final image: ubuntu with chainlink binary FROM golang:1.21-bullseye @@ -32,6 +48,10 @@ RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ +# Install (but don't enable) LOOP Plugins +COPY --from=buildplugins /go/bin/chainlink-feeds /usr/local/bin/ +COPY --from=buildplugins /go/bin/chainlink-solana /usr/local/bin/ + # Dependency of CosmWasm/wasmd COPY --from=buildgo /go/pkg/mod/github.com/\!cosm\!wasm/wasmvm@v*/internal/api/libwasmvm.*.so /usr/lib/ RUN chmod 755 /usr/lib/libwasmvm.*.so diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md index 20446992dc..61951ba700 100644 --- a/integration-tests/load/ocr/README.md +++ b/integration-tests/load/ocr/README.md @@ -3,15 +3,15 @@ ## Setup These tests can connect to any cluster create with [chainlink-cluster](../../../charts/chainlink-cluster/README.md) -Create your cluster +Create your cluster, if you already have one just use `kubefwd` ``` -kubectl create ns my-cluster -devspace use namespace my-cluster +kubectl create ns cl-cluster +devspace use namespace cl-cluster devspace deploy -sudo kubefwd svc -n my-cluster +sudo kubefwd svc -n cl-cluster ``` -Change environment connection configuration [here](connection.toml) +Change environment connection configuration [here](../../../charts/chainlink-cluster/connect.toml) If you haven't changed anything in [devspace.yaml](../../../charts/chainlink-cluster/devspace.yaml) then default connection configuration will work diff --git a/integration-tests/load/ocr/ocr_test.go b/integration-tests/load/ocr/ocr_test.go index 6bf1487125..13aea441b2 100644 --- a/integration-tests/load/ocr/ocr_test.go +++ b/integration-tests/load/ocr/ocr_test.go @@ -18,7 +18,7 @@ var ( } ) -func TestOCRPerformance(t *testing.T) { +func TestOCRLoad(t *testing.T) { l := logging.GetTestLogger(t) cc, msClient, cd, bootstrapNode, workerNodes, err := k8s.ConnectRemote(l) require.NoError(t, err) @@ -46,7 +46,7 @@ func TestOCRPerformance(t *testing.T) { require.NoError(t, err) } -func TestOCRCapacity(t *testing.T) { +func TestOCRVolume(t *testing.T) { l := logging.GetTestLogger(t) cc, msClient, cd, bootstrapNode, workerNodes, err := k8s.ConnectRemote(l) require.NoError(t, err) From 6bb80e0f9ae87e6faa20ccc3ab3e09196157673f Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 7 Dec 2023 08:03:53 -0600 Subject: [PATCH 285/327] bump mockery to v2.38.0 (#11509) --- .tool-versions | 2 +- GNUmakefile | 2 +- common/client/mock_head_test.go | 10 +- common/client/mock_node_client_test.go | 26 +- common/client/mock_node_selector_test.go | 10 +- common/client/mock_node_test.go | 42 +- common/client/mock_rpc_test.go | 102 ++++- common/client/mock_send_only_client_test.go | 10 +- common/client/mock_send_only_node_test.go | 30 +- common/headtracker/types/mocks/head.go | 50 ++- common/mocks/head_broadcaster.go | 26 +- common/mocks/head_tracker.go | 30 +- common/txmgr/mocks/tx_manager.go | 66 ++- common/txmgr/types/mocks/forwarder_manager.go | 30 +- common/txmgr/types/mocks/key_store.go | 14 +- .../txmgr/types/mocks/reaper_chain_config.go | 6 +- .../txmgr/types/mocks/tx_attempt_builder.go | 42 +- common/txmgr/types/mocks/tx_store.go | 202 ++++++++- common/txmgr/types/mocks/tx_strategy.go | 10 +- common/types/mocks/head.go | 38 +- common/types/mocks/head_trackable.go | 2 +- common/types/mocks/subscription.go | 6 +- core/bridges/mocks/orm.go | 54 ++- core/chains/evm/client/mocks/batch_sender.go | 6 +- core/chains/evm/client/mocks/client.go | 134 +++++- core/chains/evm/client/mocks/tx_sender.go | 10 +- .../evm/config/mocks/chain_scoped_config.go | 138 +++++- core/chains/evm/config/mocks/gas_estimator.go | 78 +++- core/chains/evm/forwarders/mocks/orm.go | 22 +- core/chains/evm/gas/mocks/config.go | 14 +- core/chains/evm/gas/mocks/eth_client.go | 6 +- core/chains/evm/gas/mocks/evm_estimator.go | 38 +- .../chains/evm/gas/mocks/evm_fee_estimator.go | 38 +- core/chains/evm/gas/mocks/rpc_client.go | 6 +- .../evm/gas/rollups/mocks/eth_client.go | 6 +- .../chains/evm/gas/rollups/mocks/l1_oracle.go | 26 +- core/chains/evm/headtracker/mocks/config.go | 10 +- core/chains/evm/log/mocks/abigen_contract.go | 10 +- core/chains/evm/log/mocks/broadcast.go | 42 +- core/chains/evm/log/mocks/broadcaster.go | 46 +- core/chains/evm/logpoller/mocks/log_poller.go | 110 ++++- core/chains/evm/mocks/balance_monitor.go | 26 +- core/chains/evm/mocks/node.go | 126 +++++- core/chains/evm/mocks/send_only_node.go | 34 +- core/chains/evm/txmgr/mocks/config.go | 22 +- core/chains/evm/txmgr/mocks/evm_tx_store.go | 230 +++++++++- core/chains/legacyevm/mocks/chain.go | 78 +++- .../legacyevm/mocks/legacy_chain_container.go | 22 +- core/cmd/mocks/prompter.go | 14 +- core/config/mocks/telemetry_ingress.go | 42 +- .../mocks/telemetry_ingress_endpoint.go | 18 +- core/internal/mocks/application.go | 122 +++++- core/internal/mocks/flags.go | 182 +++++++- core/internal/mocks/flux_aggregator.go | 318 +++++++++++++- core/internal/mocks/prometheus_backend.go | 2 +- core/logger/logger_mock_test.go | 22 +- core/logger/mocks/logger.go | 22 +- core/services/blockhashstore/mocks/bhs.go | 22 +- core/services/blockhashstore/mocks/timer.go | 6 +- .../chainlink/mocks/general_config.go | 154 ++++++- .../feeds/mocks/connections_manager.go | 14 +- .../feeds/mocks/feeds_manager_client.go | 22 +- core/services/feeds/mocks/orm.go | 138 +++++- core/services/feeds/mocks/service.go | 114 ++++- .../fluxmonitorv2/mocks/contract_submitter.go | 6 +- core/services/fluxmonitorv2/mocks/flags.go | 18 +- .../mocks/key_store_interface.go | 10 +- core/services/fluxmonitorv2/mocks/orm.go | 26 +- .../functions/mocks/bridge_accessor.go | 6 +- .../mocks/external_adapter_client.go | 10 +- .../functions/mocks/functions_listener.go | 14 +- .../functions/mocks/offchain_transmitter.go | 10 +- core/services/functions/mocks/orm.go | 38 +- .../connector/mocks/gateway_connector.go | 22 +- .../mocks/gateway_connector_handler.go | 10 +- .../gateway/connector/mocks/signer.go | 6 +- .../functions/mocks/onchain_allowlist.go | 18 +- .../functions/mocks/onchain_subscriptions.go | 14 +- core/services/gateway/handlers/mocks/don.go | 6 +- .../gateway/handlers/mocks/handler.go | 18 +- .../network/mocks/connection_acceptor.go | 10 +- .../network/mocks/connection_initiator.go | 10 +- .../network/mocks/http_request_handler.go | 6 +- .../gateway/network/mocks/http_server.go | 14 +- .../network/mocks/web_socket_server.go | 14 +- core/services/job/mocks/orm.go | 102 ++++- core/services/job/mocks/service_ctx.go | 10 +- core/services/job/mocks/spawner.go | 38 +- core/services/keystore/mocks/cosmos.go | 34 +- core/services/keystore/mocks/csa.go | 34 +- core/services/keystore/mocks/dkg_encrypt.go | 34 +- core/services/keystore/mocks/dkg_sign.go | 34 +- core/services/keystore/mocks/eth.go | 82 +++- core/services/keystore/mocks/master.go | 54 ++- core/services/keystore/mocks/ocr.go | 34 +- core/services/keystore/mocks/ocr2.go | 38 +- core/services/keystore/mocks/p2p.go | 38 +- core/services/keystore/mocks/solana.go | 38 +- core/services/keystore/mocks/starknet.go | 34 +- core/services/keystore/mocks/vrf.go | 34 +- core/services/mocks/checker.go | 26 +- .../ocr/mocks/ocr_contract_tracker_db.go | 10 +- .../evmregistry/v20/mocks/registry.go | 18 +- .../v21/core/mocks/upkeep_state_reader.go | 6 +- .../evmregistry/v21/mocks/http_client.go | 6 +- .../evmregistry/v21/mocks/registry.go | 30 +- .../ocr2vrf/coordinator/mocks/vrf_beacon.go | 290 +++++++++++- .../mocks/vrf_beacon_coordinator.go | 22 +- .../coordinator/mocks/vrf_coordinator.go | 414 +++++++++++++++++- .../promwrapper/mocks/prometheus_backend.go | 2 +- .../ocr2/plugins/threshold/mocks/decryptor.go | 6 +- core/services/pg/mocks/event_broadcaster.go | 30 +- core/services/pg/mocks/subscription.go | 14 +- core/services/pipeline/mocks/config.go | 22 +- core/services/pipeline/mocks/orm.go | 74 +++- .../mocks/pipeline_param_unmarshaler.go | 6 +- core/services/pipeline/mocks/runner.go | 46 +- .../relay/evm/mercury/mocks/async_deleter.go | 2 +- .../relay/evm/mocks/loop_relay_adapter.go | 46 +- .../relay/evm/mocks/request_round_db.go | 10 +- .../evm/types/mocks/log_poller_wrapper.go | 26 +- core/services/s4/mocks/orm.go | 22 +- core/services/s4/mocks/storage.go | 18 +- .../mocks/telemetry_service.go | 22 +- .../vrf/mocks/aggregator_v3_interface.go | 26 +- core/services/vrf/mocks/config.go | 10 +- core/services/vrf/mocks/fee_config.go | 14 +- core/services/vrf/mocks/vrf_coordinator_v2.go | 334 +++++++++++++- .../mocks/external_initiator_manager.go | 14 +- core/services/webhook/mocks/http_client.go | 6 +- core/sessions/ldapauth/mocks/ldap_client.go | 6 +- core/sessions/ldapauth/mocks/ldap_conn.go | 14 +- .../sessions/mocks/authentication_provider.go | 78 +++- core/sessions/mocks/basic_admin_users_orm.go | 14 +- 134 files changed, 5774 insertions(+), 134 deletions(-) diff --git a/.tool-versions b/.tool-versions index c60396ccb8..d78ce677cd 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,5 +1,5 @@ golang 1.21.4 -mockery 2.35.4 +mockery 2.38.0 nodejs 16.16.0 postgres 13.3 helm 3.10.3 diff --git a/GNUmakefile b/GNUmakefile index 6cd5ab7143..7d0753911a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -112,7 +112,7 @@ presubmit: ## Format go files and imports. .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.35.4 + go install github.com/vektra/mockery/v2@v2.38.0 .PHONY: codecgen codecgen: $(codecgen) ## Install codecgen diff --git a/common/client/mock_head_test.go b/common/client/mock_head_test.go index 1b69eedf43..747770480f 100644 --- a/common/client/mock_head_test.go +++ b/common/client/mock_head_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -17,6 +17,10 @@ type mockHead struct { func (_m *mockHead) BlockDifficulty() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockDifficulty") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -33,6 +37,10 @@ func (_m *mockHead) BlockDifficulty() *big.Int { func (_m *mockHead) BlockNumber() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go index 7c8eb69171..661ad68ede 100644 --- a/common/client/mock_node_client_test.go +++ b/common/client/mock_node_client_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -18,6 +18,10 @@ type mockNodeClient[CHAIN_ID types.ID, HEAD Head] struct { func (_m *mockNodeClient[CHAIN_ID, HEAD]) ChainID(ctx context.Context) (CHAIN_ID, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID var r1 error if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { @@ -42,6 +46,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) ChainID(ctx context.Context) (CHAIN_ID func (_m *mockNodeClient[CHAIN_ID, HEAD]) ClientVersion(_a0 context.Context) (string, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ClientVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok { @@ -71,6 +79,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Close() { func (_m *mockNodeClient[CHAIN_ID, HEAD]) Dial(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Dial") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -85,6 +97,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Dial(ctx context.Context) error { func (_m *mockNodeClient[CHAIN_ID, HEAD]) DialHTTP() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DialHTTP") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -112,6 +128,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Subscribe(ctx context.Context, channel _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + var r0 types.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { @@ -138,6 +158,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Subscribe(ctx context.Context, channel func (_m *mockNodeClient[CHAIN_ID, HEAD]) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() diff --git a/common/client/mock_node_selector_test.go b/common/client/mock_node_selector_test.go index e7b8d9ecb8..bd0805fa4e 100644 --- a/common/client/mock_node_selector_test.go +++ b/common/client/mock_node_selector_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -16,6 +16,10 @@ type mockNodeSelector[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEA func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -30,6 +34,10 @@ func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Select") + } + var r0 Node[CHAIN_ID, HEAD, RPC] if rf, ok := ret.Get(0).(func() Node[CHAIN_ID, HEAD, RPC]); ok { r0 = rf() diff --git a/common/client/mock_node_test.go b/common/client/mock_node_test.go index ea0e7d1a12..56132b2cee 100644 --- a/common/client/mock_node_test.go +++ b/common/client/mock_node_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -20,6 +20,10 @@ type mockNode[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEAD]] stru func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Close() error { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) ConfiguredChainID() CHAIN_ID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConfiguredChainID") + } + var r0 CHAIN_ID if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) ConfiguredChainID() CHAIN_ID { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -62,6 +74,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Name() string { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Order() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Order") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -76,6 +92,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Order() int32 { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) RPC() RPC { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RPC") + } + var r0 RPC if rf, ok := ret.Get(0).(func() RPC); ok { r0 = rf() @@ -90,6 +110,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) RPC() RPC { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -104,6 +128,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Start(_a0 context.Context) error { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) State() nodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 nodeState if rf, ok := ret.Get(0).(func() nodeState); ok { r0 = rf() @@ -118,6 +146,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) State() nodeState { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *big.Int) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StateAndLatest") + } + var r0 nodeState var r1 int64 var r2 *big.Int @@ -151,6 +183,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *bi func (_m *mockNode[CHAIN_ID, HEAD, RPC]) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -165,6 +201,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) String() string { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go index d5e8db8283..d87a02d47c 100644 --- a/common/client/mock_rpc_test.go +++ b/common/client/mock_rpc_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -25,6 +25,10 @@ type mockRPC[CHAIN_ID types.ID, SEQ types.Sequence, ADDR types.Hashable, BLOCK_H 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) + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) (*big.Int, error)); ok { @@ -51,6 +55,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for BatchCallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []interface{}) error); ok { r0 = rf(ctx, b) @@ -65,6 +73,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for BlockByHash") + } + var r0 HEAD var r1 error if rf, ok := ret.Get(0).(func(context.Context, BLOCK_HASH) (HEAD, error)); ok { @@ -89,6 +101,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for BlockByNumber") + } + var r0 HEAD var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (HEAD, error)); ok { @@ -116,6 +132,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, interface{}, string, ...interface{}) error); ok { r0 = rf(ctx, result, method, args...) @@ -130,6 +150,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, interface{}, *big.Int) ([]byte, error)); ok { @@ -156,6 +180,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID var r1 error if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { @@ -180,6 +208,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for ClientVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok { @@ -209,6 +241,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) ([]byte, error)); ok { @@ -235,6 +271,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for Dial") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -249,6 +289,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) DialHTTP() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DialHTTP") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -268,6 +312,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, interface{}) (uint64, error)); ok { @@ -292,6 +340,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for FilterEvents") + } + var r0 []EVENT var r1 error if rf, ok := ret.Get(0).(func(context.Context, EVENT_OPS) ([]EVENT, error)); ok { @@ -318,6 +370,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for LINKBalance") + } + var r0 *assets.Link var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) (*assets.Link, error)); ok { @@ -344,6 +400,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for LatestBlockHeight") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -370,6 +430,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for PendingSequenceAt") + } + var r0 SEQ var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR) (SEQ, error)); ok { @@ -394,6 +458,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for SendEmptyTransaction") + } + 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 { @@ -418,6 +486,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, TX) error); ok { r0 = rf(ctx, tx) @@ -432,6 +504,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for SequenceAt") + } + var r0 SEQ var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) (SEQ, error)); ok { @@ -461,6 +537,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for SimulateTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, TX) error); ok { r0 = rf(ctx, tx) @@ -478,6 +558,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + var r0 types.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { @@ -504,6 +588,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -518,6 +606,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for TokenBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) (*big.Int, error)); ok { @@ -544,6 +636,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for TransactionByHash") + } + var r0 TX var r1 error if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) (TX, error)); ok { @@ -568,6 +664,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS 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) + if len(ret) == 0 { + panic("no return value specified for TransactionReceipt") + } + var r0 TX_RECEIPT var r1 error if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) (TX_RECEIPT, error)); ok { diff --git a/common/client/mock_send_only_client_test.go b/common/client/mock_send_only_client_test.go index 481b2602ea..b667a2ceb5 100644 --- a/common/client/mock_send_only_client_test.go +++ b/common/client/mock_send_only_client_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -18,6 +18,10 @@ type mockSendOnlyClient[CHAIN_ID types.ID] struct { func (_m *mockSendOnlyClient[CHAIN_ID]) ChainID(_a0 context.Context) (CHAIN_ID, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID var r1 error if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { @@ -47,6 +51,10 @@ func (_m *mockSendOnlyClient[CHAIN_ID]) Close() { func (_m *mockSendOnlyClient[CHAIN_ID]) DialHTTP() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DialHTTP") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() diff --git a/common/client/mock_send_only_node_test.go b/common/client/mock_send_only_node_test.go index 524d7d8a6c..0a319db5f7 100644 --- a/common/client/mock_send_only_node_test.go +++ b/common/client/mock_send_only_node_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -18,6 +18,10 @@ type mockSendOnlyNode[CHAIN_ID types.ID, RPC sendOnlyClient[CHAIN_ID]] struct { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Close() error { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) ConfiguredChainID() CHAIN_ID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConfiguredChainID") + } + var r0 CHAIN_ID if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { r0 = rf() @@ -46,6 +54,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) ConfiguredChainID() CHAIN_ID { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -60,6 +72,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Name() string { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) RPC() RPC { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RPC") + } + var r0 RPC if rf, ok := ret.Get(0).(func() RPC); ok { r0 = rf() @@ -74,6 +90,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) RPC() RPC { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -88,6 +108,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Start(_a0 context.Context) error { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) State() nodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 nodeState if rf, ok := ret.Get(0).(func() nodeState); ok { r0 = rf() @@ -102,6 +126,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) State() nodeState { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() diff --git a/common/headtracker/types/mocks/head.go b/common/headtracker/types/mocks/head.go index 79c483c997..f86df1d7fc 100644 --- a/common/headtracker/types/mocks/head.go +++ b/common/headtracker/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Head[BLOCK_HASH types.Hashable, CHAIN_ID types.ID] struct { func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockDifficulty() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockDifficulty") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockDifficulty() *big.Int { func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockNumber() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() @@ -65,6 +77,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockNumber() int64 { func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainID() CHAIN_ID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { r0 = rf() @@ -79,6 +95,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainID() CHAIN_ID { func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainLength() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainLength") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -93,6 +113,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainLength() uint32 { func (_m *Head[BLOCK_HASH, CHAIN_ID]) EarliestHeadInChain() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EarliestHeadInChain") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -109,6 +133,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) EarliestHeadInChain() types.Head[BLOCK_HAS func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParent() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParent") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -125,6 +153,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParent() types.Head[BLOCK_HASH] { func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParentHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParentHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -139,6 +171,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParentHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetTimestamp() time.Time { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetTimestamp") + } + var r0 time.Time if rf, ok := ret.Get(0).(func() time.Time); ok { r0 = rf() @@ -153,6 +189,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetTimestamp() time.Time { func (_m *Head[BLOCK_HASH, CHAIN_ID]) HasChainID() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HasChainID") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -167,6 +207,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) HasChainID() bool { func (_m *Head[BLOCK_HASH, CHAIN_ID]) HashAtHeight(blockNum int64) BLOCK_HASH { ret := _m.Called(blockNum) + if len(ret) == 0 { + panic("no return value specified for HashAtHeight") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func(int64) BLOCK_HASH); ok { r0 = rf(blockNum) @@ -181,6 +225,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) HashAtHeight(blockNum int64) BLOCK_HASH { func (_m *Head[BLOCK_HASH, CHAIN_ID]) IsValid() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsValid") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() diff --git a/common/mocks/head_broadcaster.go b/common/mocks/head_broadcaster.go index 12036f6784..265fceae91 100644 --- a/common/mocks/head_broadcaster.go +++ b/common/mocks/head_broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) BroadcastNewLongestChain(_a0 H) { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Close() error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -53,6 +61,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -67,6 +79,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Name() string { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -81,6 +97,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Ready() error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -95,6 +115,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Start(_a0 context.Context) error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback types.HeadTrackable[H, BLOCK_HASH]) (H, func()) { ret := _m.Called(callback) + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + var r0 H var r1 func() if rf, ok := ret.Get(0).(func(types.HeadTrackable[H, BLOCK_HASH]) (H, func())); ok { diff --git a/common/mocks/head_tracker.go b/common/mocks/head_tracker.go index 2a1f64eeeb..83ee54b184 100644 --- a/common/mocks/head_tracker.go +++ b/common/mocks/head_tracker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type HeadTracker[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct { func (_m *HeadTracker[H, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain H, depth uint) error { ret := _m.Called(ctx, headWithChain, depth) + if len(ret) == 0 { + panic("no return value specified for Backfill") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, H, uint) error); ok { r0 = rf(ctx, headWithChain, depth) @@ -32,6 +36,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Backfill(ctx context.Context, headWithChai func (_m *HeadTracker[H, BLOCK_HASH]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -46,6 +54,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Close() error { func (_m *HeadTracker[H, BLOCK_HASH]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -62,6 +74,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) HealthReport() map[string]error { func (_m *HeadTracker[H, BLOCK_HASH]) LatestChain() H { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestChain") + } + var r0 H if rf, ok := ret.Get(0).(func() H); ok { r0 = rf() @@ -76,6 +92,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) LatestChain() H { func (_m *HeadTracker[H, BLOCK_HASH]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -90,6 +110,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Name() string { func (_m *HeadTracker[H, BLOCK_HASH]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -104,6 +128,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Ready() error { func (_m *HeadTracker[H, BLOCK_HASH]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index 27077218f6..45a3675ace 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ type TxManager[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types.Hashab func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -41,6 +45,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close( func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (uint32, error) { ret := _m.Called(ctx, state) + if len(ret) == 0 { + panic("no return value specified for CountTransactionsByState") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState) (uint32, error)); ok { @@ -65,6 +73,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CountT func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, txRequest) + if len(ret) == 0 { + panic("no return value specified for CreateTransaction") + } + var r0 txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH]) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -89,6 +101,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Create func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (null.Time, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedBroadcastTime") + } + var r0 null.Time var r1 error if rf, ok := ret.Get(0).(func(context.Context) (null.Time, error)); ok { @@ -113,6 +129,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEa func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (null.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedTxAttemptBlock") + } + var r0 null.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (null.Int, error)); ok { @@ -137,6 +157,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEa func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, metaValue, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesByMetaFieldAndStates") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -163,6 +187,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, ids, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithAttemptsAndReceiptsByIdsAndState") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -189,6 +217,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByReceiptBlockNum") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -215,6 +247,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByStates") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -241,6 +277,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetForwarderForEOA(eoa ADDR) (ADDR, error) { ret := _m.Called(eoa) + if len(ret) == 0 { + panic("no return value specified for GetForwarderForEOA") + } + var r0 ADDR var r1 error if rf, ok := ret.Get(0).(func(ADDR) (ADDR, error)); ok { @@ -265,6 +305,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetFor func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -281,6 +325,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Health func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -300,6 +348,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) OnNewL func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -319,6 +371,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Regist func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(addr ADDR, abandon bool) error { ret := _m.Called(addr, abandon) + if len(ret) == 0 { + panic("no return value specified for Reset") + } + var r0 error if rf, ok := ret.Get(0).(func(ADDR, bool) error); ok { r0 = rf(addr, abandon) @@ -333,6 +389,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset( func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from ADDR, to ADDR, value big.Int, gasLimit uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID, from, to, value, gasLimit) + if len(ret) == 0 { + panic("no return value specified for SendNativeToken") + } + var r0 txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -357,6 +417,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNa func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/types/mocks/forwarder_manager.go b/common/txmgr/types/mocks/forwarder_manager.go index abf176550b..bf61d0c3d2 100644 --- a/common/txmgr/types/mocks/forwarder_manager.go +++ b/common/txmgr/types/mocks/forwarder_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type ForwarderManager[ADDR types.Hashable] struct { func (_m *ForwarderManager[ADDR]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -33,6 +37,10 @@ func (_m *ForwarderManager[ADDR]) Close() error { func (_m *ForwarderManager[ADDR]) ConvertPayload(dest ADDR, origPayload []byte) ([]byte, error) { ret := _m.Called(dest, origPayload) + if len(ret) == 0 { + panic("no return value specified for ConvertPayload") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(ADDR, []byte) ([]byte, error)); ok { @@ -59,6 +67,10 @@ func (_m *ForwarderManager[ADDR]) ConvertPayload(dest ADDR, origPayload []byte) func (_m *ForwarderManager[ADDR]) ForwarderFor(addr ADDR) (ADDR, error) { ret := _m.Called(addr) + if len(ret) == 0 { + panic("no return value specified for ForwarderFor") + } + var r0 ADDR var r1 error if rf, ok := ret.Get(0).(func(ADDR) (ADDR, error)); ok { @@ -83,6 +95,10 @@ func (_m *ForwarderManager[ADDR]) ForwarderFor(addr ADDR) (ADDR, error) { func (_m *ForwarderManager[ADDR]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -99,6 +115,10 @@ func (_m *ForwarderManager[ADDR]) HealthReport() map[string]error { func (_m *ForwarderManager[ADDR]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -113,6 +133,10 @@ func (_m *ForwarderManager[ADDR]) Name() string { func (_m *ForwarderManager[ADDR]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -127,6 +151,10 @@ func (_m *ForwarderManager[ADDR]) Ready() error { func (_m *ForwarderManager[ADDR]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index ad5178c09d..d440528a41 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type KeyStore[ADDR types.Hashable, CHAIN_ID types.ID, SEQ types.Sequence] struct func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(address ADDR, chainID CHAIN_ID) error { ret := _m.Called(address, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckEnabled") + } + var r0 error if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID) error); ok { r0 = rf(address, chainID) @@ -31,6 +35,10 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(address ADDR, chainID CHAI func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ID) ([]ADDR, error) { ret := _m.Called(chainId) + if len(ret) == 0 { + panic("no return value specified for EnabledAddressesForChain") + } + var r0 []ADDR var r1 error if rf, ok := ret.Get(0).(func(CHAIN_ID) ([]ADDR, error)); ok { @@ -57,6 +65,10 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges() (chan struct{}, func()) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribeToKeyChanges") + } + var r0 chan struct{} var r1 func() if rf, ok := ret.Get(0).(func() (chan struct{}, func())); ok { diff --git a/common/txmgr/types/mocks/reaper_chain_config.go b/common/txmgr/types/mocks/reaper_chain_config.go index a733b22370..041214b80c 100644 --- a/common/txmgr/types/mocks/reaper_chain_config.go +++ b/common/txmgr/types/mocks/reaper_chain_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type ReaperConfig struct { func (_m *ReaperConfig) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/common/txmgr/types/mocks/tx_attempt_builder.go b/common/txmgr/types/mocks/tx_attempt_builder.go index 0f3d3e3fba..b3b6ff761f 100644 --- a/common/txmgr/types/mocks/tx_attempt_builder.go +++ b/common/txmgr/types/mocks/tx_attempt_builder.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type TxAttemptBuilder[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -54,6 +62,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -68,6 +80,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewBumpTxAttempt(ctx context.Context, tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], previousAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], priorAttempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], lggr logger.Logger) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, bool, error) { ret := _m.Called(ctx, tx, previousAttempt, priorAttempts, lggr) + if len(ret) == 0 { + panic("no return value specified for NewBumpTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 FEE var r2 uint32 @@ -113,6 +129,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewCustomTxAttempt(tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fee FEE, gasLimit uint32, txType int, lggr logger.Logger) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], bool, error) { ret := _m.Called(tx, fee, gasLimit, txType, lggr) + if len(ret) == 0 { + panic("no return value specified for NewCustomTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 bool var r2 error @@ -144,6 +164,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewEmptyTxAttempt(seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(seq, feeLimit, fee, fromAddress) + if len(ret) == 0 { + panic("no return value specified for NewEmptyTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(SEQ, uint32, FEE, ADDR) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -175,6 +199,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for NewTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 FEE var r2 uint32 @@ -227,6 +255,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for NewTxAttemptWithType") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 FEE var r2 uint32 @@ -277,6 +309,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -291,6 +327,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index df1528a4c2..16c20df31d 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -29,6 +29,10 @@ type TxStore[ADDR types.Hashable, CHAIN_ID types.ID, TX_HASH types.Hashable, BLO func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Abandon(ctx context.Context, id CHAIN_ID, addr ADDR) error { ret := _m.Called(ctx, id, addr) + if len(ret) == 0 { + panic("no return value specified for Abandon") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR) error); ok { r0 = rf(ctx, id, addr) @@ -43,6 +47,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Abandon(ctx func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckTxQueueCapacity(ctx context.Context, fromAddress ADDR, maxQueuedTransactions uint64, chainID CHAIN_ID) error { ret := _m.Called(ctx, fromAddress, maxQueuedTransactions, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckTxQueueCapacity") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, uint64, CHAIN_ID) error); ok { r0 = rf(ctx, fromAddress, maxQueuedTransactions, chainID) @@ -62,6 +70,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() { func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState, chainID CHAIN_ID) (uint32, error) { ret := _m.Called(ctx, state, chainID) + if len(ret) == 0 { + panic("no return value specified for CountTransactionsByState") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState, CHAIN_ID) (uint32, error)); ok { @@ -86,6 +98,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountTransa func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconfirmedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnconfirmedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (uint32, error)); ok { @@ -110,6 +126,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconf func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnstartedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnstartedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (uint32, error)); ok { @@ -134,6 +154,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnstar func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH], chainID CHAIN_ID) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, txRequest, chainID) + if len(ret) == 0 { + panic("no return value specified for CreateTransaction") + } + var r0 txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -158,6 +182,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTrans func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) DeleteInProgressAttempt(ctx context.Context, attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for DeleteInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, attempt) @@ -172,6 +200,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) DeleteInPro func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID CHAIN_ID) (null.Time, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedBroadcastTime") + } + var r0 null.Time var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) (null.Time, error)); ok { @@ -196,6 +228,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarlies func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID CHAIN_ID) (null.Int, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedTxAttemptBlock") + } + var r0 null.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) (null.Int, error)); ok { @@ -220,6 +256,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarlies func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindLatestSequence(ctx context.Context, fromAddress ADDR, chainId CHAIN_ID) (SEQ, error) { ret := _m.Called(ctx, fromAddress, chainId) + if len(ret) == 0 { + panic("no return value specified for FindLatestSequence") + } + var r0 SEQ var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (SEQ, error)); ok { @@ -244,6 +284,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindLatestS func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID) error { ret := _m.Called(ctx, etx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for FindNextUnstartedTransactionFromAddress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ADDR, CHAIN_ID) error); ok { r0 = rf(ctx, etx, fromAddress, chainID) @@ -258,6 +302,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUns func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTransactionsConfirmedInBlockRange") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -284,6 +332,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransac func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsConfirmedMissingReceipt") + } + var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -310,6 +362,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringReceiptFetch") + } + var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -336,6 +392,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID CHAIN_ID, address ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, olderThan, maxInFlightTransactions, chainID, address) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringResend") + } + var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, uint32, CHAIN_ID, ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -362,6 +422,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, idempotencyKey, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxWithIdempotencyKey") + } + var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -388,6 +452,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithI func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithSequence(ctx context.Context, fromAddress ADDR, seq SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, fromAddress, seq) + if len(ret) == 0 { + panic("no return value specified for FindTxWithSequence") + } + var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -414,6 +482,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithS func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, metaValue, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesByMetaFieldAndStates") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -440,6 +512,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesByM func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error) { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesPendingCallback") + } + var r0 []txmgrtypes.ReceiptPlus[R] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error)); ok { @@ -466,6 +542,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesPen func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, ids, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithAttemptsAndReceiptsByIdsAndState") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -492,6 +572,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByReceiptBlockNum") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -518,6 +602,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByStates") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -544,6 +632,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringGasBump(ctx context.Context, address ADDR, blockNum int64, gasBumpThreshold int64, depth int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, address, blockNum, gasBumpThreshold, depth, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxsRequiringGasBump") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, int64, int64, int64, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -570,6 +662,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address ADDR, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, address, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxsRequiringResubmissionDueToInsufficientFunds") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -596,6 +692,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgressTxAttempts(ctx context.Context, address ADDR, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, address, chainID) + if len(ret) == 0 { + panic("no return value specified for GetInProgressTxAttempts") + } + var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -622,6 +722,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgre func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetNonFatalTransactions(ctx context.Context, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for GetNonFatalTransactions") + } + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -648,6 +752,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetNonFatal func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxByID(ctx context.Context, id int64) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for GetTxByID") + } + var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -674,6 +782,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxByID(c func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProgress(ctx context.Context, fromAddress ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, fromAddress) + if len(ret) == 0 { + panic("no return value specified for GetTxInProgress") + } + var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -700,6 +812,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProg func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgressTransaction(ctx context.Context, account ADDR, chainID CHAIN_ID) (bool, error) { ret := _m.Called(ctx, account, chainID) + if len(ret) == 0 { + panic("no return value specified for HasInProgressTransaction") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (bool, error)); ok { @@ -724,6 +840,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgre func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID CHAIN_ID) (bool, error) { ret := _m.Called(ctx, blockHeight, txID, chainID) + if len(ret) == 0 { + panic("no return value specified for IsTxFinalized") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) (bool, error)); ok { @@ -748,6 +868,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsTxFinaliz func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttempts(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for LoadTxAttempts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx) @@ -762,6 +886,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) error { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkAllConfirmedMissingReceipt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) error); ok { r0 = rf(ctx, chainID) @@ -776,6 +904,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllConf func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID CHAIN_ID) error { ret := _m.Called(ctx, blockNum, finalityDepth, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkOldTxesMissingReceiptAsErrored") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, CHAIN_ID) error); ok { r0 = rf(ctx, blockNum, finalityDepth, chainID) @@ -790,6 +922,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxes func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PreloadTxes(ctx context.Context, attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, attempts) + if len(ret) == 0 { + panic("no return value specified for PreloadTxes") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, attempts) @@ -804,6 +940,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PreloadTxes func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (int64, error) { ret := _m.Called(ctx, queueSize, subject) + if len(ret) == 0 { + panic("no return value specified for PruneUnstartedTxQueue") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) (int64, error)); ok { @@ -828,6 +968,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PruneUnstar func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error { ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID) + if len(ret) == 0 { + panic("no return value specified for ReapTxHistory") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, CHAIN_ID) error); ok { r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID) @@ -842,6 +986,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHisto func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveConfirmedMissingReceiptAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -856,6 +1004,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveConfirm func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveFetchedReceipts(ctx context.Context, receipts []R, chainID CHAIN_ID) error { ret := _m.Called(ctx, receipts, chainID) + if len(ret) == 0 { + panic("no return value specified for SaveFetchedReceipts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []R, CHAIN_ID) error); ok { r0 = rf(ctx, receipts, chainID) @@ -870,6 +1022,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveFetched func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInProgressAttempt(ctx context.Context, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for SaveInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, attempt) @@ -884,6 +1040,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInProgr func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveInsufficientFundsAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -898,6 +1058,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInsuffi func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, oldAttempt, replacementAttempt) + if len(ret) == 0 { + panic("no return value specified for SaveReplacementInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, oldAttempt, replacementAttempt) @@ -912,6 +1076,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveReplace func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveSentAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -926,6 +1094,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveSentAtt func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID CHAIN_ID) error { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for SetBroadcastBeforeBlockNum") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) error); ok { r0 = rf(ctx, blockNum, chainID) @@ -940,6 +1112,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SetBroadcas func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error { ret := _m.Called(ctx, now, etxIDs) + if len(ret) == 0 { + panic("no return value specified for UpdateBroadcastAts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, []int64) error); ok { r0 = rf(ctx, now, etxIDs) @@ -954,6 +1130,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroad func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState txmgrtypes.TxAttemptState) error { ret := _m.Called(ctx, etx, attempt, NewAttemptState) + if len(ret) == 0 { + panic("no return value specified for UpdateTxAttemptInProgressToBroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttemptState) error); ok { r0 = rf(ctx, etx, attempt, NewAttemptState) @@ -968,6 +1148,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAtt func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId CHAIN_ID) error { ret := _m.Called(ctx, pipelineTaskRunRid, chainId) + if len(ret) == 0 { + panic("no return value specified for UpdateTxCallbackCompleted") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, CHAIN_ID) error); ok { r0 = rf(ctx, pipelineTaskRunRid, chainId) @@ -982,6 +1166,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxCal func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFatalError(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for UpdateTxFatalError") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx) @@ -996,6 +1184,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFat func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxForRebroadcast(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx, etxAttempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxForRebroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx, etxAttempt) @@ -1010,6 +1202,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFor func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxUnstartedToInProgress(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx, attempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxUnstartedToInProgress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx, attempt) @@ -1024,6 +1220,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxUns func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error { ret := _m.Called(ctx, ids) + if len(ret) == 0 { + panic("no return value specified for UpdateTxsUnconfirmed") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []int64) error); ok { r0 = rf(ctx, ids) diff --git a/common/txmgr/types/mocks/tx_strategy.go b/common/txmgr/types/mocks/tx_strategy.go index f4ec9bef49..7992c3fe05 100644 --- a/common/txmgr/types/mocks/tx_strategy.go +++ b/common/txmgr/types/mocks/tx_strategy.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type TxStrategy struct { func (_m *TxStrategy) PruneQueue(ctx context.Context, pruneService types.UnstartedTxQueuePruner) (int64, error) { ret := _m.Called(ctx, pruneService) + if len(ret) == 0 { + panic("no return value specified for PruneQueue") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.UnstartedTxQueuePruner) (int64, error)); ok { @@ -44,6 +48,10 @@ func (_m *TxStrategy) PruneQueue(ctx context.Context, pruneService types.Unstart func (_m *TxStrategy) Subject() uuid.NullUUID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Subject") + } + var r0 uuid.NullUUID if rf, ok := ret.Get(0).(func() uuid.NullUUID); ok { r0 = rf() diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index 99d2a265b4..29b6d07365 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type Head[BLOCK_HASH types.Hashable] struct { func (_m *Head[BLOCK_HASH]) BlockDifficulty() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockDifficulty") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *Head[BLOCK_HASH]) BlockDifficulty() *big.Int { func (_m *Head[BLOCK_HASH]) BlockHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -50,6 +58,10 @@ func (_m *Head[BLOCK_HASH]) BlockHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH]) BlockNumber() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() @@ -64,6 +76,10 @@ func (_m *Head[BLOCK_HASH]) BlockNumber() int64 { func (_m *Head[BLOCK_HASH]) ChainLength() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainLength") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -78,6 +94,10 @@ func (_m *Head[BLOCK_HASH]) ChainLength() uint32 { func (_m *Head[BLOCK_HASH]) EarliestHeadInChain() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EarliestHeadInChain") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -94,6 +114,10 @@ func (_m *Head[BLOCK_HASH]) EarliestHeadInChain() types.Head[BLOCK_HASH] { func (_m *Head[BLOCK_HASH]) GetParent() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParent") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -110,6 +134,10 @@ func (_m *Head[BLOCK_HASH]) GetParent() types.Head[BLOCK_HASH] { func (_m *Head[BLOCK_HASH]) GetParentHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParentHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -124,6 +152,10 @@ func (_m *Head[BLOCK_HASH]) GetParentHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH]) GetTimestamp() time.Time { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetTimestamp") + } + var r0 time.Time if rf, ok := ret.Get(0).(func() time.Time); ok { r0 = rf() @@ -138,6 +170,10 @@ func (_m *Head[BLOCK_HASH]) GetTimestamp() time.Time { func (_m *Head[BLOCK_HASH]) HashAtHeight(blockNum int64) BLOCK_HASH { ret := _m.Called(blockNum) + if len(ret) == 0 { + panic("no return value specified for HashAtHeight") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func(int64) BLOCK_HASH); ok { r0 = rf(blockNum) diff --git a/common/types/mocks/head_trackable.go b/common/types/mocks/head_trackable.go index e63e9ca249..55f0ebd288 100644 --- a/common/types/mocks/head_trackable.go +++ b/common/types/mocks/head_trackable.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/common/types/mocks/subscription.go b/common/types/mocks/subscription.go index 5577ee4a62..32db6dfa76 100644 --- a/common/types/mocks/subscription.go +++ b/common/types/mocks/subscription.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type Subscription struct { func (_m *Subscription) Err() <-chan error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Err") + } + var r0 <-chan error if rf, ok := ret.Get(0).(func() <-chan error); ok { r0 = rf() diff --git a/core/bridges/mocks/orm.go b/core/bridges/mocks/orm.go index ba8c7526d1..2c92a7e802 100644 --- a/core/bridges/mocks/orm.go +++ b/core/bridges/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type ORM struct { func (_m *ORM) BridgeTypes(offset int, limit int) ([]bridges.BridgeType, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for BridgeTypes") + } + var r0 []bridges.BridgeType var r1 int var r2 error @@ -53,6 +57,10 @@ func (_m *ORM) BridgeTypes(offset int, limit int) ([]bridges.BridgeType, int, er func (_m *ORM) CreateBridgeType(bt *bridges.BridgeType) error { ret := _m.Called(bt) + if len(ret) == 0 { + panic("no return value specified for CreateBridgeType") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.BridgeType) error); ok { r0 = rf(bt) @@ -67,6 +75,10 @@ func (_m *ORM) CreateBridgeType(bt *bridges.BridgeType) error { func (_m *ORM) CreateExternalInitiator(externalInitiator *bridges.ExternalInitiator) error { ret := _m.Called(externalInitiator) + if len(ret) == 0 { + panic("no return value specified for CreateExternalInitiator") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.ExternalInitiator) error); ok { r0 = rf(externalInitiator) @@ -81,6 +93,10 @@ func (_m *ORM) CreateExternalInitiator(externalInitiator *bridges.ExternalInitia func (_m *ORM) DeleteBridgeType(bt *bridges.BridgeType) error { ret := _m.Called(bt) + if len(ret) == 0 { + panic("no return value specified for DeleteBridgeType") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.BridgeType) error); ok { r0 = rf(bt) @@ -95,6 +111,10 @@ func (_m *ORM) DeleteBridgeType(bt *bridges.BridgeType) error { func (_m *ORM) DeleteExternalInitiator(name string) error { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for DeleteExternalInitiator") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(name) @@ -109,6 +129,10 @@ func (_m *ORM) DeleteExternalInitiator(name string) error { func (_m *ORM) ExternalInitiators(offset int, limit int) ([]bridges.ExternalInitiator, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for ExternalInitiators") + } + var r0 []bridges.ExternalInitiator var r1 int var r2 error @@ -142,6 +166,10 @@ func (_m *ORM) ExternalInitiators(offset int, limit int) ([]bridges.ExternalInit func (_m *ORM) FindBridge(name bridges.BridgeName) (bridges.BridgeType, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindBridge") + } + var r0 bridges.BridgeType var r1 error if rf, ok := ret.Get(0).(func(bridges.BridgeName) (bridges.BridgeType, error)); ok { @@ -166,6 +194,10 @@ func (_m *ORM) FindBridge(name bridges.BridgeName) (bridges.BridgeType, error) { func (_m *ORM) FindBridges(name []bridges.BridgeName) ([]bridges.BridgeType, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindBridges") + } + var r0 []bridges.BridgeType var r1 error if rf, ok := ret.Get(0).(func([]bridges.BridgeName) ([]bridges.BridgeType, error)); ok { @@ -192,6 +224,10 @@ func (_m *ORM) FindBridges(name []bridges.BridgeName) ([]bridges.BridgeType, err func (_m *ORM) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiator, error) { ret := _m.Called(eia) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiator") + } + var r0 *bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(*auth.Token) (*bridges.ExternalInitiator, error)); ok { @@ -218,6 +254,10 @@ func (_m *ORM) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiato func (_m *ORM) FindExternalInitiatorByName(iname string) (bridges.ExternalInitiator, error) { ret := _m.Called(iname) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiatorByName") + } + var r0 bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(string) (bridges.ExternalInitiator, error)); ok { @@ -242,6 +282,10 @@ func (_m *ORM) FindExternalInitiatorByName(iname string) (bridges.ExternalInitia func (_m *ORM) GetCachedResponse(dotId string, specId int32, maxElapsed time.Duration) ([]byte, error) { ret := _m.Called(dotId, specId, maxElapsed) + if len(ret) == 0 { + panic("no return value specified for GetCachedResponse") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, int32, time.Duration) ([]byte, error)); ok { @@ -268,6 +312,10 @@ func (_m *ORM) GetCachedResponse(dotId string, specId int32, maxElapsed time.Dur func (_m *ORM) UpdateBridgeType(bt *bridges.BridgeType, btr *bridges.BridgeTypeRequest) error { ret := _m.Called(bt, btr) + if len(ret) == 0 { + panic("no return value specified for UpdateBridgeType") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.BridgeType, *bridges.BridgeTypeRequest) error); ok { r0 = rf(bt, btr) @@ -282,6 +330,10 @@ func (_m *ORM) UpdateBridgeType(bt *bridges.BridgeType, btr *bridges.BridgeTypeR func (_m *ORM) UpsertBridgeResponse(dotId string, specId int32, response []byte) error { ret := _m.Called(dotId, specId, response) + if len(ret) == 0 { + panic("no return value specified for UpsertBridgeResponse") + } + var r0 error if rf, ok := ret.Get(0).(func(string, int32, []byte) error); ok { r0 = rf(dotId, specId, response) diff --git a/core/chains/evm/client/mocks/batch_sender.go b/core/chains/evm/client/mocks/batch_sender.go index 7f1a5bdee6..3d65749b5b 100644 --- a/core/chains/evm/client/mocks/batch_sender.go +++ b/core/chains/evm/client/mocks/batch_sender.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type BatchSender struct { func (_m *BatchSender) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) + if len(ret) == 0 { + panic("no return value specified for BatchCallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { r0 = rf(ctx, b) diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index 22498370a2..0b45894cf2 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -33,6 +33,10 @@ type Client struct { func (_m *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (*big.Int, error)); ok { @@ -59,6 +63,10 @@ func (_m *Client) BalanceAt(ctx context.Context, account common.Address, blockNu func (_m *Client) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) + if len(ret) == 0 { + panic("no return value specified for BatchCallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { r0 = rf(ctx, b) @@ -73,6 +81,10 @@ func (_m *Client) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error func (_m *Client) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) + if len(ret) == 0 { + panic("no return value specified for BatchCallContextAll") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { r0 = rf(ctx, b) @@ -87,6 +99,10 @@ func (_m *Client) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) er func (_m *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { ret := _m.Called(ctx, hash) + if len(ret) == 0 { + panic("no return value specified for BlockByHash") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Block, error)); ok { @@ -113,6 +129,10 @@ func (_m *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo func (_m *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { ret := _m.Called(ctx, number) + if len(ret) == 0 { + panic("no return value specified for BlockByNumber") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Block, error)); ok { @@ -142,6 +162,10 @@ func (_m *Client) CallContext(ctx context.Context, result interface{}, method st _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, interface{}, string, ...interface{}) error); ok { r0 = rf(ctx, result, method, args...) @@ -156,6 +180,10 @@ func (_m *Client) CallContext(ctx context.Context, result interface{}, method st func (_m *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, msg, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok { @@ -182,6 +210,10 @@ func (_m *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockN func (_m *Client) ChainID() (*big.Int, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func() (*big.Int, error)); ok { @@ -213,6 +245,10 @@ func (_m *Client) Close() { func (_m *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]byte, error)); ok { @@ -239,6 +275,10 @@ func (_m *Client) CodeAt(ctx context.Context, account common.Address, blockNumbe func (_m *Client) ConfiguredChainID() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConfiguredChainID") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -255,6 +295,10 @@ func (_m *Client) ConfiguredChainID() *big.Int { func (_m *Client) Dial(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Dial") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -269,6 +313,10 @@ func (_m *Client) Dial(ctx context.Context) error { func (_m *Client) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { ret := _m.Called(ctx, call) + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) (uint64, error)); ok { @@ -293,6 +341,10 @@ func (_m *Client) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint6 func (_m *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { ret := _m.Called(ctx, q) + if len(ret) == 0 { + panic("no return value specified for FilterLogs") + } + var r0 []types.Log var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) ([]types.Log, error)); ok { @@ -319,6 +371,10 @@ func (_m *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]typ func (_m *Client) HeadByHash(ctx context.Context, n common.Hash) (*evmtypes.Head, error) { ret := _m.Called(ctx, n) + if len(ret) == 0 { + panic("no return value specified for HeadByHash") + } + var r0 *evmtypes.Head var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*evmtypes.Head, error)); ok { @@ -345,6 +401,10 @@ func (_m *Client) HeadByHash(ctx context.Context, n common.Hash) (*evmtypes.Head func (_m *Client) HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, error) { ret := _m.Called(ctx, n) + if len(ret) == 0 { + panic("no return value specified for HeadByNumber") + } + var r0 *evmtypes.Head var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*evmtypes.Head, error)); ok { @@ -371,6 +431,10 @@ func (_m *Client) HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, func (_m *Client) HeaderByHash(ctx context.Context, h common.Hash) (*types.Header, error) { ret := _m.Called(ctx, h) + if len(ret) == 0 { + panic("no return value specified for HeaderByHash") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Header, error)); ok { @@ -397,6 +461,10 @@ func (_m *Client) HeaderByHash(ctx context.Context, h common.Hash) (*types.Heade func (_m *Client) HeaderByNumber(ctx context.Context, n *big.Int) (*types.Header, error) { ret := _m.Called(ctx, n) + if len(ret) == 0 { + panic("no return value specified for HeaderByNumber") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Header, error)); ok { @@ -423,6 +491,10 @@ func (_m *Client) HeaderByNumber(ctx context.Context, n *big.Int) (*types.Header func (_m *Client) IsL2() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsL2") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -437,6 +509,10 @@ func (_m *Client) IsL2() bool { func (_m *Client) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*assets.Link, error) { ret := _m.Called(ctx, address, linkAddress) + if len(ret) == 0 { + panic("no return value specified for LINKBalance") + } + var r0 *assets.Link var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address) (*assets.Link, error)); ok { @@ -463,6 +539,10 @@ func (_m *Client) LINKBalance(ctx context.Context, address common.Address, linkA func (_m *Client) LatestBlockHeight(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for LatestBlockHeight") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -489,6 +569,10 @@ func (_m *Client) LatestBlockHeight(ctx context.Context) (*big.Int, error) { func (_m *Client) NodeStates() map[string]string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for NodeStates") + } + var r0 map[string]string if rf, ok := ret.Get(0).(func() map[string]string); ok { r0 = rf() @@ -505,6 +589,10 @@ func (_m *Client) NodeStates() map[string]string { func (_m *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingCodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]byte, error)); ok { @@ -531,6 +619,10 @@ func (_m *Client) PendingCodeAt(ctx context.Context, account common.Address) ([] func (_m *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingNonceAt") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint64, error)); ok { @@ -555,6 +647,10 @@ func (_m *Client) PendingNonceAt(ctx context.Context, account common.Address) (u func (_m *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) @@ -569,6 +665,10 @@ func (_m *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er func (_m *Client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { ret := _m.Called(ctx, tx, fromAddress) + if len(ret) == 0 { + panic("no return value specified for SendTransactionReturnCode") + } + var r0 commonclient.SendTxReturnCode var r1 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction, common.Address) (commonclient.SendTxReturnCode, error)); ok { @@ -593,6 +693,10 @@ func (_m *Client) SendTransactionReturnCode(ctx context.Context, tx *types.Trans func (_m *Client) SequenceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (evmtypes.Nonce, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for SequenceAt") + } + var r0 evmtypes.Nonce var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (evmtypes.Nonce, error)); ok { @@ -617,6 +721,10 @@ func (_m *Client) SequenceAt(ctx context.Context, account common.Address, blockN func (_m *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { ret := _m.Called(ctx, q, ch) + if len(ret) == 0 { + panic("no return value specified for SubscribeFilterLogs") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)); ok { @@ -643,6 +751,10 @@ func (_m *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuer func (_m *Client) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head) (ethereum.Subscription, error) { ret := _m.Called(ctx, ch) + if len(ret) == 0 { + panic("no return value specified for SubscribeNewHead") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- *evmtypes.Head) (ethereum.Subscription, error)); ok { @@ -669,6 +781,10 @@ func (_m *Client) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head func (_m *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasPrice") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -695,6 +811,10 @@ func (_m *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { func (_m *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasTipCap") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -721,6 +841,10 @@ func (_m *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { func (_m *Client) TokenBalance(ctx context.Context, address common.Address, contractAddress common.Address) (*big.Int, error) { ret := _m.Called(ctx, address, contractAddress) + if len(ret) == 0 { + panic("no return value specified for TokenBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address) (*big.Int, error)); ok { @@ -747,6 +871,10 @@ func (_m *Client) TokenBalance(ctx context.Context, address common.Address, cont func (_m *Client) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionByHash") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Transaction, error)); ok { @@ -773,6 +901,10 @@ func (_m *Client) TransactionByHash(ctx context.Context, txHash common.Hash) (*t func (_m *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionReceipt") + } + var r0 *types.Receipt var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Receipt, error)); ok { diff --git a/core/chains/evm/client/mocks/tx_sender.go b/core/chains/evm/client/mocks/tx_sender.go index 889069dcfc..a769a786a1 100644 --- a/core/chains/evm/client/mocks/tx_sender.go +++ b/core/chains/evm/client/mocks/tx_sender.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type TxSender struct { func (_m *TxSender) ChainID(_a0 context.Context) (*big.Int, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -47,6 +51,10 @@ func (_m *TxSender) ChainID(_a0 context.Context) (*big.Int, error) { func (_m *TxSender) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index cb18282f49..badba1d69f 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type ChainScopedConfig struct { func (_m *ChainScopedConfig) AppID() uuid.UUID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AppID") + } + var r0 uuid.UUID if rf, ok := ret.Get(0).(func() uuid.UUID); ok { r0 = rf() @@ -40,6 +44,10 @@ func (_m *ChainScopedConfig) AppID() uuid.UUID { func (_m *ChainScopedConfig) AuditLogger() coreconfig.AuditLogger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AuditLogger") + } + var r0 coreconfig.AuditLogger if rf, ok := ret.Get(0).(func() coreconfig.AuditLogger); ok { r0 = rf() @@ -56,6 +64,10 @@ func (_m *ChainScopedConfig) AuditLogger() coreconfig.AuditLogger { func (_m *ChainScopedConfig) AutoPprof() coreconfig.AutoPprof { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AutoPprof") + } + var r0 coreconfig.AutoPprof if rf, ok := ret.Get(0).(func() coreconfig.AutoPprof); ok { r0 = rf() @@ -72,6 +84,10 @@ func (_m *ChainScopedConfig) AutoPprof() coreconfig.AutoPprof { func (_m *ChainScopedConfig) CosmosEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CosmosEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -86,6 +102,10 @@ func (_m *ChainScopedConfig) CosmosEnabled() bool { func (_m *ChainScopedConfig) Database() coreconfig.Database { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Database") + } + var r0 coreconfig.Database if rf, ok := ret.Get(0).(func() coreconfig.Database); ok { r0 = rf() @@ -102,6 +122,10 @@ func (_m *ChainScopedConfig) Database() coreconfig.Database { func (_m *ChainScopedConfig) EVM() config.EVM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVM") + } + var r0 config.EVM if rf, ok := ret.Get(0).(func() config.EVM); ok { r0 = rf() @@ -118,6 +142,10 @@ func (_m *ChainScopedConfig) EVM() config.EVM { func (_m *ChainScopedConfig) EVMEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -132,6 +160,10 @@ func (_m *ChainScopedConfig) EVMEnabled() bool { func (_m *ChainScopedConfig) EVMRPCEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMRPCEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -146,6 +178,10 @@ func (_m *ChainScopedConfig) EVMRPCEnabled() bool { func (_m *ChainScopedConfig) Feature() coreconfig.Feature { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Feature") + } + var r0 coreconfig.Feature if rf, ok := ret.Get(0).(func() coreconfig.Feature); ok { r0 = rf() @@ -162,6 +198,10 @@ func (_m *ChainScopedConfig) Feature() coreconfig.Feature { func (_m *ChainScopedConfig) FluxMonitor() coreconfig.FluxMonitor { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FluxMonitor") + } + var r0 coreconfig.FluxMonitor if rf, ok := ret.Get(0).(func() coreconfig.FluxMonitor); ok { r0 = rf() @@ -178,6 +218,10 @@ func (_m *ChainScopedConfig) FluxMonitor() coreconfig.FluxMonitor { func (_m *ChainScopedConfig) Insecure() coreconfig.Insecure { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Insecure") + } + var r0 coreconfig.Insecure if rf, ok := ret.Get(0).(func() coreconfig.Insecure); ok { r0 = rf() @@ -194,6 +238,10 @@ func (_m *ChainScopedConfig) Insecure() coreconfig.Insecure { func (_m *ChainScopedConfig) InsecureFastScrypt() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for InsecureFastScrypt") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -208,6 +256,10 @@ func (_m *ChainScopedConfig) InsecureFastScrypt() bool { func (_m *ChainScopedConfig) JobPipeline() coreconfig.JobPipeline { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobPipeline") + } + var r0 coreconfig.JobPipeline if rf, ok := ret.Get(0).(func() coreconfig.JobPipeline); ok { r0 = rf() @@ -224,6 +276,10 @@ func (_m *ChainScopedConfig) JobPipeline() coreconfig.JobPipeline { func (_m *ChainScopedConfig) Keeper() coreconfig.Keeper { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Keeper") + } + var r0 coreconfig.Keeper if rf, ok := ret.Get(0).(func() coreconfig.Keeper); ok { r0 = rf() @@ -240,6 +296,10 @@ func (_m *ChainScopedConfig) Keeper() coreconfig.Keeper { func (_m *ChainScopedConfig) Log() coreconfig.Log { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Log") + } + var r0 coreconfig.Log if rf, ok := ret.Get(0).(func() coreconfig.Log); ok { r0 = rf() @@ -261,6 +321,10 @@ func (_m *ChainScopedConfig) LogConfiguration(log coreconfig.LogfFn, warn coreco func (_m *ChainScopedConfig) Mercury() coreconfig.Mercury { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Mercury") + } + var r0 coreconfig.Mercury if rf, ok := ret.Get(0).(func() coreconfig.Mercury); ok { r0 = rf() @@ -277,6 +341,10 @@ func (_m *ChainScopedConfig) Mercury() coreconfig.Mercury { func (_m *ChainScopedConfig) OCR() coreconfig.OCR { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR") + } + var r0 coreconfig.OCR if rf, ok := ret.Get(0).(func() coreconfig.OCR); ok { r0 = rf() @@ -293,6 +361,10 @@ func (_m *ChainScopedConfig) OCR() coreconfig.OCR { func (_m *ChainScopedConfig) OCR2() coreconfig.OCR2 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR2") + } + var r0 coreconfig.OCR2 if rf, ok := ret.Get(0).(func() coreconfig.OCR2); ok { r0 = rf() @@ -309,6 +381,10 @@ func (_m *ChainScopedConfig) OCR2() coreconfig.OCR2 { func (_m *ChainScopedConfig) P2P() coreconfig.P2P { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for P2P") + } + var r0 coreconfig.P2P if rf, ok := ret.Get(0).(func() coreconfig.P2P); ok { r0 = rf() @@ -325,6 +401,10 @@ func (_m *ChainScopedConfig) P2P() coreconfig.P2P { func (_m *ChainScopedConfig) Password() coreconfig.Password { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Password") + } + var r0 coreconfig.Password if rf, ok := ret.Get(0).(func() coreconfig.Password); ok { r0 = rf() @@ -341,6 +421,10 @@ func (_m *ChainScopedConfig) Password() coreconfig.Password { func (_m *ChainScopedConfig) Prometheus() coreconfig.Prometheus { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Prometheus") + } + var r0 coreconfig.Prometheus if rf, ok := ret.Get(0).(func() coreconfig.Prometheus); ok { r0 = rf() @@ -357,6 +441,10 @@ func (_m *ChainScopedConfig) Prometheus() coreconfig.Prometheus { func (_m *ChainScopedConfig) Pyroscope() coreconfig.Pyroscope { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Pyroscope") + } + var r0 coreconfig.Pyroscope if rf, ok := ret.Get(0).(func() coreconfig.Pyroscope); ok { r0 = rf() @@ -373,6 +461,10 @@ func (_m *ChainScopedConfig) Pyroscope() coreconfig.Pyroscope { func (_m *ChainScopedConfig) RootDir() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RootDir") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -387,6 +479,10 @@ func (_m *ChainScopedConfig) RootDir() string { func (_m *ChainScopedConfig) Sentry() coreconfig.Sentry { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Sentry") + } + var r0 coreconfig.Sentry if rf, ok := ret.Get(0).(func() coreconfig.Sentry); ok { r0 = rf() @@ -403,6 +499,10 @@ func (_m *ChainScopedConfig) Sentry() coreconfig.Sentry { func (_m *ChainScopedConfig) SetLogLevel(lvl zapcore.Level) error { ret := _m.Called(lvl) + if len(ret) == 0 { + panic("no return value specified for SetLogLevel") + } + var r0 error if rf, ok := ret.Get(0).(func(zapcore.Level) error); ok { r0 = rf(lvl) @@ -427,6 +527,10 @@ func (_m *ChainScopedConfig) SetPasswords(keystore *string, vrf *string) { func (_m *ChainScopedConfig) ShutdownGracePeriod() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ShutdownGracePeriod") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -441,6 +545,10 @@ func (_m *ChainScopedConfig) ShutdownGracePeriod() time.Duration { func (_m *ChainScopedConfig) SolanaEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SolanaEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -455,6 +563,10 @@ func (_m *ChainScopedConfig) SolanaEnabled() bool { func (_m *ChainScopedConfig) StarkNetEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StarkNetEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -469,6 +581,10 @@ func (_m *ChainScopedConfig) StarkNetEnabled() bool { func (_m *ChainScopedConfig) TelemetryIngress() coreconfig.TelemetryIngress { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TelemetryIngress") + } + var r0 coreconfig.TelemetryIngress if rf, ok := ret.Get(0).(func() coreconfig.TelemetryIngress); ok { r0 = rf() @@ -485,6 +601,10 @@ func (_m *ChainScopedConfig) TelemetryIngress() coreconfig.TelemetryIngress { func (_m *ChainScopedConfig) Threshold() coreconfig.Threshold { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Threshold") + } + var r0 coreconfig.Threshold if rf, ok := ret.Get(0).(func() coreconfig.Threshold); ok { r0 = rf() @@ -501,6 +621,10 @@ func (_m *ChainScopedConfig) Threshold() coreconfig.Threshold { func (_m *ChainScopedConfig) Tracing() coreconfig.Tracing { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Tracing") + } + var r0 coreconfig.Tracing if rf, ok := ret.Get(0).(func() coreconfig.Tracing); ok { r0 = rf() @@ -517,6 +641,10 @@ func (_m *ChainScopedConfig) Tracing() coreconfig.Tracing { func (_m *ChainScopedConfig) Validate() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Validate") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -531,6 +659,10 @@ func (_m *ChainScopedConfig) Validate() error { func (_m *ChainScopedConfig) ValidateDB() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ValidateDB") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -545,6 +677,10 @@ func (_m *ChainScopedConfig) ValidateDB() error { func (_m *ChainScopedConfig) WebServer() coreconfig.WebServer { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for WebServer") + } + var r0 coreconfig.WebServer if rf, ok := ret.Get(0).(func() coreconfig.WebServer); ok { r0 = rf() diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go index 6260b3cd50..69a2c85275 100644 --- a/core/chains/evm/config/mocks/gas_estimator.go +++ b/core/chains/evm/config/mocks/gas_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type GasEstimator struct { func (_m *GasEstimator) BlockHistory() config.BlockHistory { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockHistory") + } + var r0 config.BlockHistory if rf, ok := ret.Get(0).(func() config.BlockHistory); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *GasEstimator) BlockHistory() config.BlockHistory { func (_m *GasEstimator) BumpMin() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpMin") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -52,6 +60,10 @@ func (_m *GasEstimator) BumpMin() *assets.Wei { func (_m *GasEstimator) BumpPercent() uint16 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpPercent") + } + var r0 uint16 if rf, ok := ret.Get(0).(func() uint16); ok { r0 = rf() @@ -66,6 +78,10 @@ func (_m *GasEstimator) BumpPercent() uint16 { func (_m *GasEstimator) BumpThreshold() uint64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpThreshold") + } + var r0 uint64 if rf, ok := ret.Get(0).(func() uint64); ok { r0 = rf() @@ -80,6 +96,10 @@ func (_m *GasEstimator) BumpThreshold() uint64 { func (_m *GasEstimator) BumpTxDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpTxDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -94,6 +114,10 @@ func (_m *GasEstimator) BumpTxDepth() uint32 { func (_m *GasEstimator) EIP1559DynamicFees() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EIP1559DynamicFees") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -108,6 +132,10 @@ func (_m *GasEstimator) EIP1559DynamicFees() bool { func (_m *GasEstimator) FeeCapDefault() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FeeCapDefault") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -124,6 +152,10 @@ func (_m *GasEstimator) FeeCapDefault() *assets.Wei { func (_m *GasEstimator) LimitDefault() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitDefault") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -138,6 +170,10 @@ func (_m *GasEstimator) LimitDefault() uint32 { func (_m *GasEstimator) LimitJobType() config.LimitJobType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitJobType") + } + var r0 config.LimitJobType if rf, ok := ret.Get(0).(func() config.LimitJobType); ok { r0 = rf() @@ -154,6 +190,10 @@ func (_m *GasEstimator) LimitJobType() config.LimitJobType { func (_m *GasEstimator) LimitMax() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitMax") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -168,6 +208,10 @@ func (_m *GasEstimator) LimitMax() uint32 { func (_m *GasEstimator) LimitMultiplier() float32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitMultiplier") + } + var r0 float32 if rf, ok := ret.Get(0).(func() float32); ok { r0 = rf() @@ -182,6 +226,10 @@ func (_m *GasEstimator) LimitMultiplier() float32 { func (_m *GasEstimator) LimitTransfer() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitTransfer") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -196,6 +244,10 @@ func (_m *GasEstimator) LimitTransfer() uint32 { func (_m *GasEstimator) Mode() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Mode") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -210,6 +262,10 @@ func (_m *GasEstimator) Mode() string { func (_m *GasEstimator) PriceDefault() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PriceDefault") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -226,6 +282,10 @@ func (_m *GasEstimator) PriceDefault() *assets.Wei { func (_m *GasEstimator) PriceMax() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PriceMax") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -242,6 +302,10 @@ func (_m *GasEstimator) PriceMax() *assets.Wei { func (_m *GasEstimator) PriceMaxKey(_a0 common.Address) *assets.Wei { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for PriceMaxKey") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func(common.Address) *assets.Wei); ok { r0 = rf(_a0) @@ -258,6 +322,10 @@ func (_m *GasEstimator) PriceMaxKey(_a0 common.Address) *assets.Wei { func (_m *GasEstimator) PriceMin() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PriceMin") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -274,6 +342,10 @@ func (_m *GasEstimator) PriceMin() *assets.Wei { func (_m *GasEstimator) TipCapDefault() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TipCapDefault") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -290,6 +362,10 @@ func (_m *GasEstimator) TipCapDefault() *assets.Wei { func (_m *GasEstimator) TipCapMin() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TipCapMin") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() diff --git a/core/chains/evm/forwarders/mocks/orm.go b/core/chains/evm/forwarders/mocks/orm.go index e8ab62ce7d..c06a04b8eb 100644 --- a/core/chains/evm/forwarders/mocks/orm.go +++ b/core/chains/evm/forwarders/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type ORM struct { func (_m *ORM) CreateForwarder(addr common.Address, evmChainId utils.Big) (forwarders.Forwarder, error) { ret := _m.Called(addr, evmChainId) + if len(ret) == 0 { + panic("no return value specified for CreateForwarder") + } + var r0 forwarders.Forwarder var r1 error if rf, ok := ret.Get(0).(func(common.Address, utils.Big) (forwarders.Forwarder, error)); ok { @@ -45,6 +49,10 @@ func (_m *ORM) CreateForwarder(addr common.Address, evmChainId utils.Big) (forwa func (_m *ORM) DeleteForwarder(id int64, cleanup func(pg.Queryer, int64, common.Address) error) error { ret := _m.Called(id, cleanup) + if len(ret) == 0 { + panic("no return value specified for DeleteForwarder") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, func(pg.Queryer, int64, common.Address) error) error); ok { r0 = rf(id, cleanup) @@ -59,6 +67,10 @@ func (_m *ORM) DeleteForwarder(id int64, cleanup func(pg.Queryer, int64, common. func (_m *ORM) FindForwarders(offset int, limit int) ([]forwarders.Forwarder, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for FindForwarders") + } + var r0 []forwarders.Forwarder var r1 int var r2 error @@ -92,6 +104,10 @@ func (_m *ORM) FindForwarders(offset int, limit int) ([]forwarders.Forwarder, in func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forwarder, error) { ret := _m.Called(evmChainId) + if len(ret) == 0 { + panic("no return value specified for FindForwardersByChain") + } + var r0 []forwarders.Forwarder var r1 error if rf, ok := ret.Get(0).(func(utils.Big) ([]forwarders.Forwarder, error)); ok { @@ -118,6 +134,10 @@ func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forward func (_m *ORM) FindForwardersInListByChain(evmChainId utils.Big, addrs []common.Address) ([]forwarders.Forwarder, error) { ret := _m.Called(evmChainId, addrs) + if len(ret) == 0 { + panic("no return value specified for FindForwardersInListByChain") + } + var r0 []forwarders.Forwarder var r1 error if rf, ok := ret.Get(0).(func(utils.Big, []common.Address) ([]forwarders.Forwarder, error)); ok { diff --git a/core/chains/evm/gas/mocks/config.go b/core/chains/evm/gas/mocks/config.go index c09005b5e3..4a7b6f4d7e 100644 --- a/core/chains/evm/gas/mocks/config.go +++ b/core/chains/evm/gas/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Config struct { func (_m *Config) ChainType() config.ChainType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainType") + } + var r0 config.ChainType if rf, ok := ret.Get(0).(func() config.ChainType); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *Config) ChainType() config.ChainType { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *Config) FinalityDepth() uint32 { func (_m *Config) FinalityTagEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityTagEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() diff --git a/core/chains/evm/gas/mocks/eth_client.go b/core/chains/evm/gas/mocks/eth_client.go index 2b0aaff025..bb0784f851 100644 --- a/core/chains/evm/gas/mocks/eth_client.go +++ b/core/chains/evm/gas/mocks/eth_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type ETHClient struct { func (_m *ETHClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, msg, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok { diff --git a/core/chains/evm/gas/mocks/evm_estimator.go b/core/chains/evm/gas/mocks/evm_estimator.go index f2cb51f856..29705b2a5d 100644 --- a/core/chains/evm/gas/mocks/evm_estimator.go +++ b/core/chains/evm/gas/mocks/evm_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type EvmEstimator struct { func (_m *EvmEstimator) BumpDynamicFee(ctx context.Context, original gas.DynamicFee, gasLimit uint32, maxGasPriceWei *assets.Wei, attempts []gas.EvmPriorAttempt) (gas.DynamicFee, uint32, error) { ret := _m.Called(ctx, original, gasLimit, maxGasPriceWei, attempts) + if len(ret) == 0 { + panic("no return value specified for BumpDynamicFee") + } + var r0 gas.DynamicFee var r1 uint32 var r2 error @@ -56,6 +60,10 @@ func (_m *EvmEstimator) BumpDynamicFee(ctx context.Context, original gas.Dynamic func (_m *EvmEstimator) BumpLegacyGas(ctx context.Context, originalGasPrice *assets.Wei, gasLimit uint32, maxGasPriceWei *assets.Wei, attempts []gas.EvmPriorAttempt) (*assets.Wei, uint32, error) { ret := _m.Called(ctx, originalGasPrice, gasLimit, maxGasPriceWei, attempts) + if len(ret) == 0 { + panic("no return value specified for BumpLegacyGas") + } + var r0 *assets.Wei var r1 uint32 var r2 error @@ -89,6 +97,10 @@ func (_m *EvmEstimator) BumpLegacyGas(ctx context.Context, originalGasPrice *ass func (_m *EvmEstimator) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -103,6 +115,10 @@ func (_m *EvmEstimator) Close() error { func (_m *EvmEstimator) GetDynamicFee(ctx context.Context, gasLimit uint32, maxGasPriceWei *assets.Wei) (gas.DynamicFee, uint32, error) { ret := _m.Called(ctx, gasLimit, maxGasPriceWei) + if len(ret) == 0 { + panic("no return value specified for GetDynamicFee") + } + var r0 gas.DynamicFee var r1 uint32 var r2 error @@ -141,6 +157,10 @@ func (_m *EvmEstimator) GetLegacyGas(ctx context.Context, calldata []byte, gasLi _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetLegacyGas") + } + var r0 *assets.Wei var r1 uint32 var r2 error @@ -174,6 +194,10 @@ func (_m *EvmEstimator) GetLegacyGas(ctx context.Context, calldata []byte, gasLi func (_m *EvmEstimator) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -190,6 +214,10 @@ func (_m *EvmEstimator) HealthReport() map[string]error { func (_m *EvmEstimator) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -209,6 +237,10 @@ func (_m *EvmEstimator) OnNewLongestChain(ctx context.Context, head *evmtypes.He func (_m *EvmEstimator) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -223,6 +255,10 @@ func (_m *EvmEstimator) Ready() error { func (_m *EvmEstimator) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/gas/mocks/evm_fee_estimator.go b/core/chains/evm/gas/mocks/evm_fee_estimator.go index b9b1636779..66acbdbf7f 100644 --- a/core/chains/evm/gas/mocks/evm_fee_estimator.go +++ b/core/chains/evm/gas/mocks/evm_fee_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -29,6 +29,10 @@ type EvmFeeEstimator struct { func (_m *EvmFeeEstimator) BumpFee(ctx context.Context, originalFee gas.EvmFee, feeLimit uint32, maxFeePrice *assets.Wei, attempts []gas.EvmPriorAttempt) (gas.EvmFee, uint32, error) { ret := _m.Called(ctx, originalFee, feeLimit, maxFeePrice, attempts) + if len(ret) == 0 { + panic("no return value specified for BumpFee") + } + var r0 gas.EvmFee var r1 uint32 var r2 error @@ -60,6 +64,10 @@ func (_m *EvmFeeEstimator) BumpFee(ctx context.Context, originalFee gas.EvmFee, func (_m *EvmFeeEstimator) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -81,6 +89,10 @@ func (_m *EvmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetFee") + } + var r0 gas.EvmFee var r1 uint32 var r2 error @@ -119,6 +131,10 @@ func (_m *EvmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, ca _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetMaxCost") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, assets.Eth, []byte, uint32, *assets.Wei, ...types.Opt) (*big.Int, error)); ok { @@ -145,6 +161,10 @@ func (_m *EvmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, ca func (_m *EvmFeeEstimator) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -161,6 +181,10 @@ func (_m *EvmFeeEstimator) HealthReport() map[string]error { func (_m *EvmFeeEstimator) L1Oracle() rollups.L1Oracle { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for L1Oracle") + } + var r0 rollups.L1Oracle if rf, ok := ret.Get(0).(func() rollups.L1Oracle); ok { r0 = rf() @@ -177,6 +201,10 @@ func (_m *EvmFeeEstimator) L1Oracle() rollups.L1Oracle { func (_m *EvmFeeEstimator) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -196,6 +224,10 @@ func (_m *EvmFeeEstimator) OnNewLongestChain(ctx context.Context, head *evmtypes func (_m *EvmFeeEstimator) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -210,6 +242,10 @@ func (_m *EvmFeeEstimator) Ready() error { func (_m *EvmFeeEstimator) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/gas/mocks/rpc_client.go b/core/chains/evm/gas/mocks/rpc_client.go index 6f6ac8d6b7..d1262665f6 100644 --- a/core/chains/evm/gas/mocks/rpc_client.go +++ b/core/chains/evm/gas/mocks/rpc_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ func (_m *RPCClient) CallContext(ctx context.Context, result interface{}, method _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, interface{}, string, ...interface{}) error); ok { r0 = rf(ctx, result, method, args...) diff --git a/core/chains/evm/gas/rollups/mocks/eth_client.go b/core/chains/evm/gas/rollups/mocks/eth_client.go index 2b0aaff025..bb0784f851 100644 --- a/core/chains/evm/gas/rollups/mocks/eth_client.go +++ b/core/chains/evm/gas/rollups/mocks/eth_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type ETHClient struct { func (_m *ETHClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, msg, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok { diff --git a/core/chains/evm/gas/rollups/mocks/l1_oracle.go b/core/chains/evm/gas/rollups/mocks/l1_oracle.go index f6f8cc736a..9e52a3ec38 100644 --- a/core/chains/evm/gas/rollups/mocks/l1_oracle.go +++ b/core/chains/evm/gas/rollups/mocks/l1_oracle.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type L1Oracle struct { func (_m *L1Oracle) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -33,6 +37,10 @@ func (_m *L1Oracle) Close() error { func (_m *L1Oracle) GasPrice(ctx context.Context) (*assets.Wei, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GasPrice") + } + var r0 *assets.Wei var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*assets.Wei, error)); ok { @@ -59,6 +67,10 @@ func (_m *L1Oracle) GasPrice(ctx context.Context) (*assets.Wei, error) { func (_m *L1Oracle) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -75,6 +87,10 @@ func (_m *L1Oracle) HealthReport() map[string]error { func (_m *L1Oracle) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -89,6 +105,10 @@ func (_m *L1Oracle) Name() string { func (_m *L1Oracle) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -103,6 +123,10 @@ func (_m *L1Oracle) Ready() error { func (_m *L1Oracle) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/headtracker/mocks/config.go b/core/chains/evm/headtracker/mocks/config.go index b505cfc445..74376a7136 100644 --- a/core/chains/evm/headtracker/mocks/config.go +++ b/core/chains/evm/headtracker/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Config struct { func (_m *Config) BlockEmissionIdleWarningThreshold() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockEmissionIdleWarningThreshold") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *Config) BlockEmissionIdleWarningThreshold() time.Duration { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/core/chains/evm/log/mocks/abigen_contract.go b/core/chains/evm/log/mocks/abigen_contract.go index dcc95a1acd..fde8949e4f 100644 --- a/core/chains/evm/log/mocks/abigen_contract.go +++ b/core/chains/evm/log/mocks/abigen_contract.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type AbigenContract struct { func (_m *AbigenContract) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *AbigenContract) Address() common.Address { func (_m *AbigenContract) ParseLog(_a0 types.Log) (generated.AbigenLog, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/chains/evm/log/mocks/broadcast.go b/core/chains/evm/log/mocks/broadcast.go index a58ce9f30e..6d9a83716d 100644 --- a/core/chains/evm/log/mocks/broadcast.go +++ b/core/chains/evm/log/mocks/broadcast.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Broadcast struct { func (_m *Broadcast) DecodedLog() interface{} { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DecodedLog") + } + var r0 interface{} if rf, ok := ret.Get(0).(func() interface{}); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *Broadcast) DecodedLog() interface{} { func (_m *Broadcast) EVMChainID() big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMChainID") + } + var r0 big.Int if rf, ok := ret.Get(0).(func() big.Int); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *Broadcast) EVMChainID() big.Int { func (_m *Broadcast) JobID() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobID") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -65,6 +77,10 @@ func (_m *Broadcast) JobID() int32 { func (_m *Broadcast) LatestBlockHash() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestBlockHash") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() @@ -81,6 +97,10 @@ func (_m *Broadcast) LatestBlockHash() common.Hash { func (_m *Broadcast) LatestBlockNumber() uint64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestBlockNumber") + } + var r0 uint64 if rf, ok := ret.Get(0).(func() uint64); ok { r0 = rf() @@ -95,6 +115,10 @@ func (_m *Broadcast) LatestBlockNumber() uint64 { func (_m *Broadcast) RawLog() types.Log { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RawLog") + } + var r0 types.Log if rf, ok := ret.Get(0).(func() types.Log); ok { r0 = rf() @@ -109,6 +133,10 @@ func (_m *Broadcast) RawLog() types.Log { func (_m *Broadcast) ReceiptsRoot() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReceiptsRoot") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() @@ -125,6 +153,10 @@ func (_m *Broadcast) ReceiptsRoot() common.Hash { func (_m *Broadcast) StateRoot() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StateRoot") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() @@ -141,6 +173,10 @@ func (_m *Broadcast) StateRoot() common.Hash { func (_m *Broadcast) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -155,6 +191,10 @@ func (_m *Broadcast) String() string { func (_m *Broadcast) TransactionsRoot() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TransactionsRoot") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() diff --git a/core/chains/evm/log/mocks/broadcaster.go b/core/chains/evm/log/mocks/broadcaster.go index 84f143b39e..031bdaaa7d 100644 --- a/core/chains/evm/log/mocks/broadcaster.go +++ b/core/chains/evm/log/mocks/broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *Broadcaster) AddDependents(n int) { func (_m *Broadcaster) AwaitDependents() <-chan struct{} { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AwaitDependents") + } + var r0 <-chan struct{} if rf, ok := ret.Get(0).(func() <-chan struct{}); ok { r0 = rf() @@ -43,6 +47,10 @@ func (_m *Broadcaster) AwaitDependents() <-chan struct{} { func (_m *Broadcaster) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -62,6 +70,10 @@ func (_m *Broadcaster) DependentReady() { func (_m *Broadcaster) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -78,6 +90,10 @@ func (_m *Broadcaster) HealthReport() map[string]error { func (_m *Broadcaster) IsConnected() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsConnected") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -99,6 +115,10 @@ func (_m *Broadcaster) MarkConsumed(lb log.Broadcast, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for MarkConsumed") + } + var r0 error if rf, ok := ret.Get(0).(func(log.Broadcast, ...pg.QOpt) error); ok { r0 = rf(lb, qopts...) @@ -120,6 +140,10 @@ func (_m *Broadcaster) MarkManyConsumed(lbs []log.Broadcast, qopts ...pg.QOpt) e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for MarkManyConsumed") + } + var r0 error if rf, ok := ret.Get(0).(func([]log.Broadcast, ...pg.QOpt) error); ok { r0 = rf(lbs, qopts...) @@ -134,6 +158,10 @@ func (_m *Broadcaster) MarkManyConsumed(lbs []log.Broadcast, qopts ...pg.QOpt) e func (_m *Broadcaster) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -153,6 +181,10 @@ func (_m *Broadcaster) OnNewLongestChain(ctx context.Context, head *types.Head) func (_m *Broadcaster) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -167,6 +199,10 @@ func (_m *Broadcaster) Ready() error { func (_m *Broadcaster) Register(listener log.Listener, opts log.ListenerOpts) func() { ret := _m.Called(listener, opts) + if len(ret) == 0 { + panic("no return value specified for Register") + } + var r0 func() if rf, ok := ret.Get(0).(func(log.Listener, log.ListenerOpts) func()); ok { r0 = rf(listener, opts) @@ -188,6 +224,10 @@ func (_m *Broadcaster) ReplayFromBlock(number int64, forceBroadcast bool) { func (_m *Broadcaster) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -209,6 +249,10 @@ func (_m *Broadcaster) WasAlreadyConsumed(lb log.Broadcast, qopts ...pg.QOpt) (b _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for WasAlreadyConsumed") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(log.Broadcast, ...pg.QOpt) (bool, error)); ok { diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index fe4ccc965c..65d808b98d 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type LogPoller struct { func (_m *LogPoller) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -46,6 +50,10 @@ func (_m *LogPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetBlocksRange") + } + var r0 []logpoller.LogPollerBlock var r1 error if rf, ok := ret.Get(0).(func(context.Context, []uint64, ...pg.QOpt) ([]logpoller.LogPollerBlock, error)); ok { @@ -72,6 +80,10 @@ func (_m *LogPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts func (_m *LogPoller) HasFilter(name string) bool { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for HasFilter") + } + var r0 bool if rf, ok := ret.Get(0).(func(string) bool); ok { r0 = rf(name) @@ -86,6 +98,10 @@ func (_m *LogPoller) HasFilter(name string) bool { func (_m *LogPoller) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -109,6 +125,10 @@ func (_m *LogPoller) IndexedLogs(eventSig common.Hash, address common.Address, t _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -142,6 +162,10 @@ func (_m *LogPoller) IndexedLogsByBlockRange(start int64, end int64, eventSig co _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsByBlockRange") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, int64, common.Hash, common.Address, int, []common.Hash, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -175,6 +199,10 @@ func (_m *LogPoller) IndexedLogsByTxHash(eventSig common.Hash, address common.Ad _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsByTxHash") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, common.Hash, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -208,6 +236,10 @@ func (_m *LogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address commo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsCreatedAfter") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, time.Time, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -241,6 +273,10 @@ func (_m *LogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address c _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsTopicGreaterThan") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -274,6 +310,10 @@ func (_m *LogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common. _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsTopicRange") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -307,6 +347,10 @@ func (_m *LogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventS _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsWithSigsExcluding") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Address, common.Hash, common.Hash, int, int64, int64, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -339,6 +383,10 @@ func (_m *LogPoller) LatestBlock(qopts ...pg.QOpt) (logpoller.LogPollerBlock, er _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestBlock") + } + var r0 logpoller.LogPollerBlock var r1 error if rf, ok := ret.Get(0).(func(...pg.QOpt) (logpoller.LogPollerBlock, error)); ok { @@ -370,6 +418,10 @@ func (_m *LogPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, event _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestBlockByEventSigsAddrsWithConfs") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) (int64, error)); ok { @@ -401,6 +453,10 @@ func (_m *LogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestLogByEventSigWithConfs") + } + var r0 *logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, logpoller.Confirmations, ...pg.QOpt) (*logpoller.Log, error)); ok { @@ -434,6 +490,10 @@ func (_m *LogPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestLogEventSigsAddrsWithConfs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -467,6 +527,10 @@ func (_m *LogPoller) Logs(start int64, end int64, eventSig common.Hash, address _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Logs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, int64, common.Hash, common.Address, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -500,6 +564,10 @@ func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Addre _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsCreatedAfter") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, time.Time, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -533,6 +601,10 @@ func (_m *LogPoller) LogsDataWordBetween(eventSig common.Hash, address common.Ad _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsDataWordBetween") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -566,6 +638,10 @@ func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address commo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsDataWordGreaterThan") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -599,6 +675,10 @@ func (_m *LogPoller) LogsDataWordRange(eventSig common.Hash, address common.Addr _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsDataWordRange") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -632,6 +712,10 @@ func (_m *LogPoller) LogsWithSigs(start int64, end int64, eventSigs []common.Has _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsWithSigs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, int64, []common.Hash, common.Address, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -658,6 +742,10 @@ func (_m *LogPoller) LogsWithSigs(start int64, end int64, eventSigs []common.Has func (_m *LogPoller) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -672,6 +760,10 @@ func (_m *LogPoller) Name() string { func (_m *LogPoller) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -693,6 +785,10 @@ func (_m *LogPoller) RegisterFilter(filter logpoller.Filter, qopts ...pg.QOpt) e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RegisterFilter") + } + var r0 error if rf, ok := ret.Get(0).(func(logpoller.Filter, ...pg.QOpt) error); ok { r0 = rf(filter, qopts...) @@ -707,6 +803,10 @@ func (_m *LogPoller) RegisterFilter(filter logpoller.Filter, qopts ...pg.QOpt) e func (_m *LogPoller) Replay(ctx context.Context, fromBlock int64) error { ret := _m.Called(ctx, fromBlock) + if len(ret) == 0 { + panic("no return value specified for Replay") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, fromBlock) @@ -726,6 +826,10 @@ func (_m *LogPoller) ReplayAsync(fromBlock int64) { func (_m *LogPoller) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -747,6 +851,10 @@ func (_m *LogPoller) UnregisterFilter(name string, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UnregisterFilter") + } + var r0 error if rf, ok := ret.Get(0).(func(string, ...pg.QOpt) error); ok { r0 = rf(name, qopts...) diff --git a/core/chains/evm/mocks/balance_monitor.go b/core/chains/evm/mocks/balance_monitor.go index cdda18b7f0..f03fd8829c 100644 --- a/core/chains/evm/mocks/balance_monitor.go +++ b/core/chains/evm/mocks/balance_monitor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -22,6 +22,10 @@ type BalanceMonitor struct { func (_m *BalanceMonitor) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *BalanceMonitor) Close() error { func (_m *BalanceMonitor) GetEthBalance(_a0 common.Address) *assets.Eth { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetEthBalance") + } + var r0 *assets.Eth if rf, ok := ret.Get(0).(func(common.Address) *assets.Eth); ok { r0 = rf(_a0) @@ -52,6 +60,10 @@ func (_m *BalanceMonitor) GetEthBalance(_a0 common.Address) *assets.Eth { func (_m *BalanceMonitor) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -68,6 +80,10 @@ func (_m *BalanceMonitor) HealthReport() map[string]error { func (_m *BalanceMonitor) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -87,6 +103,10 @@ func (_m *BalanceMonitor) OnNewLongestChain(ctx context.Context, head *types.Hea func (_m *BalanceMonitor) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -101,6 +121,10 @@ func (_m *BalanceMonitor) Ready() error { func (_m *BalanceMonitor) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/mocks/node.go b/core/chains/evm/mocks/node.go index 69020d411f..8f27218aec 100644 --- a/core/chains/evm/mocks/node.go +++ b/core/chains/evm/mocks/node.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -30,6 +30,10 @@ type Node struct { func (_m *Node) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (*big.Int, error)); ok { @@ -56,6 +60,10 @@ func (_m *Node) BalanceAt(ctx context.Context, account common.Address, blockNumb func (_m *Node) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) + if len(ret) == 0 { + panic("no return value specified for BatchCallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { r0 = rf(ctx, b) @@ -70,6 +78,10 @@ func (_m *Node) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { func (_m *Node) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { ret := _m.Called(ctx, hash) + if len(ret) == 0 { + panic("no return value specified for BlockByHash") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Block, error)); ok { @@ -96,6 +108,10 @@ func (_m *Node) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block func (_m *Node) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { ret := _m.Called(ctx, number) + if len(ret) == 0 { + panic("no return value specified for BlockByNumber") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Block, error)); ok { @@ -122,6 +138,10 @@ func (_m *Node) BlockByNumber(ctx context.Context, number *big.Int) (*types.Bloc func (_m *Node) BlockNumber(ctx context.Context) (uint64, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { @@ -149,6 +169,10 @@ func (_m *Node) CallContext(ctx context.Context, result interface{}, method stri _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, interface{}, string, ...interface{}) error); ok { r0 = rf(ctx, result, method, args...) @@ -163,6 +187,10 @@ func (_m *Node) CallContext(ctx context.Context, result interface{}, method stri func (_m *Node) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, msg, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok { @@ -189,6 +217,10 @@ func (_m *Node) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum func (_m *Node) ChainID() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -205,6 +237,10 @@ func (_m *Node) ChainID() *big.Int { func (_m *Node) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -219,6 +255,10 @@ func (_m *Node) Close() error { func (_m *Node) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]byte, error)); ok { @@ -245,6 +285,10 @@ func (_m *Node) CodeAt(ctx context.Context, account common.Address, blockNumber func (_m *Node) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { ret := _m.Called(ctx, call) + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) (uint64, error)); ok { @@ -272,6 +316,10 @@ func (_m *Node) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for EthSubscribe") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- *evmtypes.Head, ...interface{}) (ethereum.Subscription, error)); ok { @@ -298,6 +346,10 @@ func (_m *Node) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, func (_m *Node) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { ret := _m.Called(ctx, q) + if len(ret) == 0 { + panic("no return value specified for FilterLogs") + } + var r0 []types.Log var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) ([]types.Log, error)); ok { @@ -324,6 +376,10 @@ func (_m *Node) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types func (_m *Node) HeaderByHash(_a0 context.Context, _a1 common.Hash) (*types.Header, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for HeaderByHash") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Header, error)); ok { @@ -350,6 +406,10 @@ func (_m *Node) HeaderByHash(_a0 context.Context, _a1 common.Hash) (*types.Heade func (_m *Node) HeaderByNumber(_a0 context.Context, _a1 *big.Int) (*types.Header, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for HeaderByNumber") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Header, error)); ok { @@ -376,6 +436,10 @@ func (_m *Node) HeaderByNumber(_a0 context.Context, _a1 *big.Int) (*types.Header func (_m *Node) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -390,6 +454,10 @@ func (_m *Node) Name() string { func (_m *Node) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for NonceAt") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint64, error)); ok { @@ -414,6 +482,10 @@ func (_m *Node) NonceAt(ctx context.Context, account common.Address, blockNumber func (_m *Node) Order() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Order") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -428,6 +500,10 @@ func (_m *Node) Order() int32 { func (_m *Node) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingCodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]byte, error)); ok { @@ -454,6 +530,10 @@ func (_m *Node) PendingCodeAt(ctx context.Context, account common.Address) ([]by func (_m *Node) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingNonceAt") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint64, error)); ok { @@ -478,6 +558,10 @@ func (_m *Node) PendingNonceAt(ctx context.Context, account common.Address) (uin func (_m *Node) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) @@ -492,6 +576,10 @@ func (_m *Node) SendTransaction(ctx context.Context, tx *types.Transaction) erro func (_m *Node) Start(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -506,6 +594,10 @@ func (_m *Node) Start(ctx context.Context) error { func (_m *Node) State() client.NodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 client.NodeState if rf, ok := ret.Get(0).(func() client.NodeState); ok { r0 = rf() @@ -520,6 +612,10 @@ func (_m *Node) State() client.NodeState { func (_m *Node) StateAndLatest() (client.NodeState, int64, *big.Int) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StateAndLatest") + } + var r0 client.NodeState var r1 int64 var r2 *big.Int @@ -553,6 +649,10 @@ func (_m *Node) StateAndLatest() (client.NodeState, int64, *big.Int) { func (_m *Node) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -567,6 +667,10 @@ func (_m *Node) String() string { func (_m *Node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { ret := _m.Called(ctx, q, ch) + if len(ret) == 0 { + panic("no return value specified for SubscribeFilterLogs") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)); ok { @@ -593,6 +697,10 @@ func (_m *Node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, func (_m *Node) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -607,6 +715,10 @@ func (_m *Node) SubscribersCount() int32 { func (_m *Node) SuggestGasPrice(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasPrice") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -633,6 +745,10 @@ func (_m *Node) SuggestGasPrice(ctx context.Context) (*big.Int, error) { func (_m *Node) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasTipCap") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -659,6 +775,10 @@ func (_m *Node) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { func (_m *Node) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionByHash") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Transaction, error)); ok { @@ -685,6 +805,10 @@ func (_m *Node) TransactionByHash(ctx context.Context, txHash common.Hash) (*typ func (_m *Node) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionReceipt") + } + var r0 *types.Receipt var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Receipt, error)); ok { diff --git a/core/chains/evm/mocks/send_only_node.go b/core/chains/evm/mocks/send_only_node.go index c836399a8b..8ec3270281 100644 --- a/core/chains/evm/mocks/send_only_node.go +++ b/core/chains/evm/mocks/send_only_node.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type SendOnlyNode struct { func (_m *SendOnlyNode) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) + if len(ret) == 0 { + panic("no return value specified for BatchCallContext") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { r0 = rf(ctx, b) @@ -38,6 +42,10 @@ func (_m *SendOnlyNode) BatchCallContext(ctx context.Context, b []rpc.BatchElem) func (_m *SendOnlyNode) ChainID() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -54,6 +62,10 @@ func (_m *SendOnlyNode) ChainID() *big.Int { func (_m *SendOnlyNode) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -68,6 +80,10 @@ func (_m *SendOnlyNode) Close() error { func (_m *SendOnlyNode) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -82,6 +98,10 @@ func (_m *SendOnlyNode) Name() string { func (_m *SendOnlyNode) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) @@ -96,6 +116,10 @@ func (_m *SendOnlyNode) SendTransaction(ctx context.Context, tx *types.Transacti func (_m *SendOnlyNode) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -110,6 +134,10 @@ func (_m *SendOnlyNode) Start(_a0 context.Context) error { func (_m *SendOnlyNode) State() client.NodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 client.NodeState if rf, ok := ret.Get(0).(func() client.NodeState); ok { r0 = rf() @@ -124,6 +152,10 @@ func (_m *SendOnlyNode) State() client.NodeState { func (_m *SendOnlyNode) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() diff --git a/core/chains/evm/txmgr/mocks/config.go b/core/chains/evm/txmgr/mocks/config.go index ab98d686c8..0a0ece4b90 100644 --- a/core/chains/evm/txmgr/mocks/config.go +++ b/core/chains/evm/txmgr/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Config struct { func (_m *Config) ChainType() config.ChainType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainType") + } + var r0 config.ChainType if rf, ok := ret.Get(0).(func() config.ChainType); ok { r0 = rf() @@ -30,6 +34,10 @@ func (_m *Config) ChainType() config.ChainType { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -44,6 +52,10 @@ func (_m *Config) FinalityDepth() uint32 { func (_m *Config) FinalityTagEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityTagEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -58,6 +70,10 @@ func (_m *Config) FinalityTagEnabled() bool { func (_m *Config) NonceAutoSync() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for NonceAutoSync") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -72,6 +88,10 @@ func (_m *Config) NonceAutoSync() bool { func (_m *Config) RPCDefaultBatchSize() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RPCDefaultBatchSize") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index bf3088b2aa..a9a7023ac1 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -32,6 +32,10 @@ type EvmTxStore struct { func (_m *EvmTxStore) Abandon(ctx context.Context, id *big.Int, addr common.Address) error { ret := _m.Called(ctx, id, addr) + if len(ret) == 0 { + panic("no return value specified for Abandon") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int, common.Address) error); ok { r0 = rf(ctx, id, addr) @@ -46,6 +50,10 @@ func (_m *EvmTxStore) Abandon(ctx context.Context, id *big.Int, addr common.Addr func (_m *EvmTxStore) CheckTxQueueCapacity(ctx context.Context, fromAddress common.Address, maxQueuedTransactions uint64, chainID *big.Int) error { ret := _m.Called(ctx, fromAddress, maxQueuedTransactions, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckTxQueueCapacity") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint64, *big.Int) error); ok { r0 = rf(ctx, fromAddress, maxQueuedTransactions, chainID) @@ -65,6 +73,10 @@ func (_m *EvmTxStore) Close() { func (_m *EvmTxStore) CountTransactionsByState(ctx context.Context, state types.TxState, chainID *big.Int) (uint32, error) { ret := _m.Called(ctx, state, chainID) + if len(ret) == 0 { + panic("no return value specified for CountTransactionsByState") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.TxState, *big.Int) (uint32, error)); ok { @@ -89,6 +101,10 @@ func (_m *EvmTxStore) CountTransactionsByState(ctx context.Context, state types. func (_m *EvmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnconfirmedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint32, error)); ok { @@ -113,6 +129,10 @@ func (_m *EvmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddr func (_m *EvmTxStore) CountUnstartedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnstartedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint32, error)); ok { @@ -137,6 +157,10 @@ func (_m *EvmTxStore) CountUnstartedTransactions(ctx context.Context, fromAddres func (_m *EvmTxStore) CreateTransaction(ctx context.Context, txRequest types.TxRequest[common.Address, common.Hash], chainID *big.Int) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, txRequest, chainID) + if len(ret) == 0 { + panic("no return value specified for CreateTransaction") + } + var r0 types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.TxRequest[common.Address, common.Hash], *big.Int) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -161,6 +185,10 @@ func (_m *EvmTxStore) CreateTransaction(ctx context.Context, txRequest types.TxR func (_m *EvmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for DeleteInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, attempt) @@ -175,6 +203,10 @@ func (_m *EvmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt types func (_m *EvmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID *big.Int) (null.Time, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedBroadcastTime") + } + var r0 null.Time var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (null.Time, error)); ok { @@ -199,6 +231,10 @@ func (_m *EvmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, func (_m *EvmTxStore) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID *big.Int) (null.Int, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedTxAttemptBlock") + } + var r0 null.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (null.Int, error)); ok { @@ -223,6 +259,10 @@ func (_m *EvmTxStore) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, func (_m *EvmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (evmtypes.Nonce, error) { ret := _m.Called(ctx, fromAddress, chainId) + if len(ret) == 0 { + panic("no return value specified for FindLatestSequence") + } + var r0 evmtypes.Nonce var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (evmtypes.Nonce, error)); ok { @@ -247,6 +287,10 @@ func (_m *EvmTxStore) FindLatestSequence(ctx context.Context, fromAddress common func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], fromAddress common.Address, chainID *big.Int) error { ret := _m.Called(ctx, etx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for FindNextUnstartedTransactionFromAddress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], common.Address, *big.Int) error); ok { r0 = rf(ctx, etx, fromAddress, chainID) @@ -261,6 +305,10 @@ func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Contex func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTransactionsConfirmedInBlockRange") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -287,6 +335,10 @@ func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, func (_m *EvmTxStore) FindTxAttempt(hash common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(hash) + if len(ret) == 0 { + panic("no return value specified for FindTxAttempt") + } + var r0 *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -313,6 +365,10 @@ func (_m *EvmTxStore) FindTxAttempt(hash common.Hash) (*types.TxAttempt[*big.Int func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptConfirmedByTxIDs") + } + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -339,6 +395,10 @@ func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]types.TxAtte func (_m *EvmTxStore) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsConfirmedMissingReceipt") + } + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -365,6 +425,10 @@ func (_m *EvmTxStore) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, func (_m *EvmTxStore) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringReceiptFetch") + } + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -391,6 +455,10 @@ func (_m *EvmTxStore) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, c func (_m *EvmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID *big.Int, address common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, olderThan, maxInFlightTransactions, chainID, address) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringResend") + } + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, uint32, *big.Int, common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -417,6 +485,10 @@ func (_m *EvmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderTh func (_m *EvmTxStore) FindTxByHash(hash common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(hash) + if len(ret) == 0 { + panic("no return value specified for FindTxByHash") + } + var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -443,6 +515,10 @@ func (_m *EvmTxStore) FindTxByHash(hash common.Hash) (*types.Tx[*big.Int, common func (_m *EvmTxStore) FindTxWithAttempts(etxID int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(etxID) + if len(ret) == 0 { + panic("no return value specified for FindTxWithAttempts") + } + var r0 types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -467,6 +543,10 @@ func (_m *EvmTxStore) FindTxWithAttempts(etxID int64) (types.Tx[*big.Int, common func (_m *EvmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, idempotencyKey, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxWithIdempotencyKey") + } + var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -493,6 +573,10 @@ func (_m *EvmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyK func (_m *EvmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common.Address, seq evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, fromAddress, seq) + if len(ret) == 0 { + panic("no return value specified for FindTxWithSequence") + } + var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -519,6 +603,10 @@ func (_m *EvmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common func (_m *EvmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, metaField, metaValue, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesByMetaFieldAndStates") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -545,6 +633,10 @@ func (_m *EvmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaFiel func (_m *EvmTxStore) FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error) { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesPendingCallback") + } + var r0 []types.ReceiptPlus[*evmtypes.Receipt] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error)); ok { @@ -571,6 +663,10 @@ func (_m *EvmTxStore) FindTxesPendingCallback(ctx context.Context, blockNum int6 func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, ids, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithAttemptsAndReceiptsByIdsAndState") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -597,6 +693,10 @@ func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.C func (_m *EvmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, metaField, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByReceiptBlockNum") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -623,6 +723,10 @@ func (_m *EvmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context func (_m *EvmTxStore) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, metaField, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByStates") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -649,6 +753,10 @@ func (_m *EvmTxStore) FindTxesWithMetaFieldByStates(ctx context.Context, metaFie func (_m *EvmTxStore) FindTxsRequiringGasBump(ctx context.Context, address common.Address, blockNum int64, gasBumpThreshold int64, depth int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, address, blockNum, gasBumpThreshold, depth, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxsRequiringGasBump") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, int64, int64, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -675,6 +783,10 @@ func (_m *EvmTxStore) FindTxsRequiringGasBump(ctx context.Context, address commo func (_m *EvmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address common.Address, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, address, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxsRequiringResubmissionDueToInsufficientFunds") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -701,6 +813,10 @@ func (_m *EvmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx con func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address common.Address, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, address, chainID) + if len(ret) == 0 { + panic("no return value specified for GetInProgressTxAttempts") + } + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -727,6 +843,10 @@ func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address commo func (_m *EvmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for GetNonFatalTransactions") + } + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -753,6 +873,10 @@ func (_m *EvmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big. func (_m *EvmTxStore) GetTxByID(ctx context.Context, id int64) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for GetTxByID") + } + var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -779,6 +903,10 @@ func (_m *EvmTxStore) GetTxByID(ctx context.Context, id int64) (*types.Tx[*big.I func (_m *EvmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Address) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, fromAddress) + if len(ret) == 0 { + panic("no return value specified for GetTxInProgress") + } + var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -805,6 +933,10 @@ func (_m *EvmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Ad func (_m *EvmTxStore) HasInProgressTransaction(ctx context.Context, account common.Address, chainID *big.Int) (bool, error) { ret := _m.Called(ctx, account, chainID) + if len(ret) == 0 { + panic("no return value specified for HasInProgressTransaction") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (bool, error)); ok { @@ -829,6 +961,10 @@ func (_m *EvmTxStore) HasInProgressTransaction(ctx context.Context, account comm func (_m *EvmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int) (bool, error) { ret := _m.Called(ctx, blockHeight, txID, chainID) + if len(ret) == 0 { + panic("no return value specified for IsTxFinalized") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) (bool, error)); ok { @@ -853,6 +989,10 @@ func (_m *EvmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID func (_m *EvmTxStore) LoadTxAttempts(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for LoadTxAttempts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx) @@ -867,6 +1007,10 @@ func (_m *EvmTxStore) LoadTxAttempts(ctx context.Context, etx *types.Tx[*big.Int func (_m *EvmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) error { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkAllConfirmedMissingReceipt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) error); ok { r0 = rf(ctx, chainID) @@ -881,6 +1025,10 @@ func (_m *EvmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainI func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID *big.Int) error { ret := _m.Called(ctx, blockNum, finalityDepth, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkOldTxesMissingReceiptAsErrored") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, *big.Int) error); ok { r0 = rf(ctx, blockNum, finalityDepth, chainID) @@ -895,6 +1043,10 @@ func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, bl func (_m *EvmTxStore) PreloadTxes(ctx context.Context, attempts []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, attempts) + if len(ret) == 0 { + panic("no return value specified for PreloadTxes") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, attempts) @@ -909,6 +1061,10 @@ func (_m *EvmTxStore) PreloadTxes(ctx context.Context, attempts []types.TxAttemp func (_m *EvmTxStore) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (int64, error) { ret := _m.Called(ctx, queueSize, subject) + if len(ret) == 0 { + panic("no return value specified for PruneUnstartedTxQueue") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) (int64, error)); ok { @@ -933,6 +1089,10 @@ func (_m *EvmTxStore) PruneUnstartedTxQueue(ctx context.Context, queueSize uint3 func (_m *EvmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error { ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID) + if len(ret) == 0 { + panic("no return value specified for ReapTxHistory") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, *big.Int) error); ok { r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID) @@ -947,6 +1107,10 @@ func (_m *EvmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep in func (_m *EvmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveConfirmedMissingReceiptAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -961,6 +1125,10 @@ func (_m *EvmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, ti func (_m *EvmTxStore) SaveFetchedReceipts(ctx context.Context, receipts []*evmtypes.Receipt, chainID *big.Int) error { ret := _m.Called(ctx, receipts, chainID) + if len(ret) == 0 { + panic("no return value specified for SaveFetchedReceipts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []*evmtypes.Receipt, *big.Int) error); ok { r0 = rf(ctx, receipts, chainID) @@ -975,6 +1143,10 @@ func (_m *EvmTxStore) SaveFetchedReceipts(ctx context.Context, receipts []*evmty func (_m *EvmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for SaveInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, attempt) @@ -989,6 +1161,10 @@ func (_m *EvmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *types. func (_m *EvmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveInsufficientFundsAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -1003,6 +1179,10 @@ func (_m *EvmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout func (_m *EvmTxStore) SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], replacementAttempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, oldAttempt, replacementAttempt) + if len(ret) == 0 { + panic("no return value specified for SaveReplacementInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, oldAttempt, replacementAttempt) @@ -1017,6 +1197,10 @@ func (_m *EvmTxStore) SaveReplacementInProgressAttempt(ctx context.Context, oldA func (_m *EvmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveSentAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -1031,6 +1215,10 @@ func (_m *EvmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration func (_m *EvmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID *big.Int) error { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for SetBroadcastBeforeBlockNum") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) error); ok { r0 = rf(ctx, blockNum, chainID) @@ -1045,6 +1233,10 @@ func (_m *EvmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum i func (_m *EvmTxStore) Transactions(offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for Transactions") + } + var r0 []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error @@ -1078,6 +1270,10 @@ func (_m *EvmTxStore) Transactions(offset int, limit int) ([]types.Tx[*big.Int, func (_m *EvmTxStore) TransactionsWithAttempts(offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for TransactionsWithAttempts") + } + var r0 []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error @@ -1111,6 +1307,10 @@ func (_m *EvmTxStore) TransactionsWithAttempts(offset int, limit int) ([]types.T func (_m *EvmTxStore) TxAttempts(offset int, limit int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for TxAttempts") + } + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error @@ -1144,6 +1344,10 @@ func (_m *EvmTxStore) TxAttempts(offset int, limit int) ([]types.TxAttempt[*big. func (_m *EvmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error { ret := _m.Called(ctx, now, etxIDs) + if len(ret) == 0 { + panic("no return value specified for UpdateBroadcastAts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, []int64) error); ok { r0 = rf(ctx, now, etxIDs) @@ -1158,6 +1362,10 @@ func (_m *EvmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etx func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], NewAttemptState types.TxAttemptState) error { ret := _m.Called(ctx, etx, attempt, NewAttemptState) + if len(ret) == 0 { + panic("no return value specified for UpdateTxAttemptInProgressToBroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttemptState) error); ok { r0 = rf(ctx, etx, attempt, NewAttemptState) @@ -1172,6 +1380,10 @@ func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, func (_m *EvmTxStore) UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId *big.Int) error { ret := _m.Called(ctx, pipelineTaskRunRid, chainId) + if len(ret) == 0 { + panic("no return value specified for UpdateTxCallbackCompleted") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *big.Int) error); ok { r0 = rf(ctx, pipelineTaskRunRid, chainId) @@ -1186,6 +1398,10 @@ func (_m *EvmTxStore) UpdateTxCallbackCompleted(ctx context.Context, pipelineTas func (_m *EvmTxStore) UpdateTxFatalError(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for UpdateTxFatalError") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx) @@ -1200,6 +1416,10 @@ func (_m *EvmTxStore) UpdateTxFatalError(ctx context.Context, etx *types.Tx[*big func (_m *EvmTxStore) UpdateTxForRebroadcast(ctx context.Context, etx types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], etxAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx, etxAttempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxForRebroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx, etxAttempt) @@ -1214,6 +1434,10 @@ func (_m *EvmTxStore) UpdateTxForRebroadcast(ctx context.Context, etx types.Tx[* func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx, attempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxUnstartedToInProgress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx, attempt) @@ -1228,6 +1452,10 @@ func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *ty func (_m *EvmTxStore) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error { ret := _m.Called(ctx, ids) + if len(ret) == 0 { + panic("no return value specified for UpdateTxsUnconfirmed") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []int64) error); ok { r0 = rf(ctx, ids) diff --git a/core/chains/legacyevm/mocks/chain.go b/core/chains/legacyevm/mocks/chain.go index 3a686887d7..d8cc489549 100644 --- a/core/chains/legacyevm/mocks/chain.go +++ b/core/chains/legacyevm/mocks/chain.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -42,6 +42,10 @@ type Chain struct { func (_m *Chain) BalanceMonitor() monitor.BalanceMonitor { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BalanceMonitor") + } + var r0 monitor.BalanceMonitor if rf, ok := ret.Get(0).(func() monitor.BalanceMonitor); ok { r0 = rf() @@ -58,6 +62,10 @@ func (_m *Chain) BalanceMonitor() monitor.BalanceMonitor { func (_m *Chain) Client() client.Client { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Client") + } + var r0 client.Client if rf, ok := ret.Get(0).(func() client.Client); ok { r0 = rf() @@ -74,6 +82,10 @@ func (_m *Chain) Client() client.Client { func (_m *Chain) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -88,6 +100,10 @@ func (_m *Chain) Close() error { func (_m *Chain) Config() config.ChainScopedConfig { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Config") + } + var r0 config.ChainScopedConfig if rf, ok := ret.Get(0).(func() config.ChainScopedConfig); ok { r0 = rf() @@ -104,6 +120,10 @@ func (_m *Chain) Config() config.ChainScopedConfig { func (_m *Chain) GasEstimator() gas.EvmFeeEstimator { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GasEstimator") + } + var r0 gas.EvmFeeEstimator if rf, ok := ret.Get(0).(func() gas.EvmFeeEstimator); ok { r0 = rf() @@ -120,6 +140,10 @@ func (_m *Chain) GasEstimator() gas.EvmFeeEstimator { func (_m *Chain) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetChainStatus") + } + var r0 types.ChainStatus var r1 error if rf, ok := ret.Get(0).(func(context.Context) (types.ChainStatus, error)); ok { @@ -144,6 +168,10 @@ func (_m *Chain) GetChainStatus(ctx context.Context) (types.ChainStatus, error) func (_m *Chain) HeadBroadcaster() commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HeadBroadcaster") + } + var r0 commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] if rf, ok := ret.Get(0).(func() commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash]); ok { r0 = rf() @@ -160,6 +188,10 @@ func (_m *Chain) HeadBroadcaster() commontypes.HeadBroadcaster[*evmtypes.Head, c func (_m *Chain) HeadTracker() commontypes.HeadTracker[*evmtypes.Head, common.Hash] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HeadTracker") + } + var r0 commontypes.HeadTracker[*evmtypes.Head, common.Hash] if rf, ok := ret.Get(0).(func() commontypes.HeadTracker[*evmtypes.Head, common.Hash]); ok { r0 = rf() @@ -176,6 +208,10 @@ func (_m *Chain) HeadTracker() commontypes.HeadTracker[*evmtypes.Head, common.Ha func (_m *Chain) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -192,6 +228,10 @@ func (_m *Chain) HealthReport() map[string]error { func (_m *Chain) ID() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ID") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -208,6 +248,10 @@ func (_m *Chain) ID() *big.Int { func (_m *Chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) ([]types.NodeStatus, string, int, error) { ret := _m.Called(ctx, pageSize, pageToken) + if len(ret) == 0 { + panic("no return value specified for ListNodeStatuses") + } + var r0 []types.NodeStatus var r1 string var r2 int @@ -248,6 +292,10 @@ func (_m *Chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken func (_m *Chain) LogBroadcaster() log.Broadcaster { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LogBroadcaster") + } + var r0 log.Broadcaster if rf, ok := ret.Get(0).(func() log.Broadcaster); ok { r0 = rf() @@ -264,6 +312,10 @@ func (_m *Chain) LogBroadcaster() log.Broadcaster { func (_m *Chain) LogPoller() logpoller.LogPoller { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LogPoller") + } + var r0 logpoller.LogPoller if rf, ok := ret.Get(0).(func() logpoller.LogPoller); ok { r0 = rf() @@ -280,6 +332,10 @@ func (_m *Chain) LogPoller() logpoller.LogPoller { func (_m *Chain) Logger() logger.Logger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Logger") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func() logger.Logger); ok { r0 = rf() @@ -296,6 +352,10 @@ func (_m *Chain) Logger() logger.Logger { func (_m *Chain) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -310,6 +370,10 @@ func (_m *Chain) Name() string { func (_m *Chain) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -324,6 +388,10 @@ func (_m *Chain) Ready() error { func (_m *Chain) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -338,6 +406,10 @@ func (_m *Chain) Start(_a0 context.Context) error { func (_m *Chain) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { ret := _m.Called(ctx, from, to, amount, balanceCheck) + if len(ret) == 0 { + panic("no return value specified for Transact") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { r0 = rf(ctx, from, to, amount, balanceCheck) @@ -352,6 +424,10 @@ func (_m *Chain) Transact(ctx context.Context, from string, to string, amount *b func (_m *Chain) TxManager() txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TxManager") + } + var r0 txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] if rf, ok := ret.Get(0).(func() txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { r0 = rf() diff --git a/core/chains/legacyevm/mocks/legacy_chain_container.go b/core/chains/legacyevm/mocks/legacy_chain_container.go index 9ebacb890a..812b95d369 100644 --- a/core/chains/legacyevm/mocks/legacy_chain_container.go +++ b/core/chains/legacyevm/mocks/legacy_chain_container.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type LegacyChainContainer struct { func (_m *LegacyChainContainer) ChainNodeConfigs() types.Configs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainNodeConfigs") + } + var r0 types.Configs if rf, ok := ret.Get(0).(func() types.Configs); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *LegacyChainContainer) ChainNodeConfigs() types.Configs { func (_m *LegacyChainContainer) Get(id string) (legacyevm.Chain, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 legacyevm.Chain var r1 error if rf, ok := ret.Get(0).(func(string) (legacyevm.Chain, error)); ok { @@ -60,6 +68,10 @@ func (_m *LegacyChainContainer) Get(id string) (legacyevm.Chain, error) { func (_m *LegacyChainContainer) Len() int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Len") + } + var r0 int if rf, ok := ret.Get(0).(func() int); ok { r0 = rf() @@ -80,6 +92,10 @@ func (_m *LegacyChainContainer) List(ids ...string) ([]legacyevm.Chain, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 []legacyevm.Chain var r1 error if rf, ok := ret.Get(0).(func(...string) ([]legacyevm.Chain, error)); ok { @@ -106,6 +122,10 @@ func (_m *LegacyChainContainer) List(ids ...string) ([]legacyevm.Chain, error) { func (_m *LegacyChainContainer) Slice() []legacyevm.Chain { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Slice") + } + var r0 []legacyevm.Chain if rf, ok := ret.Get(0).(func() []legacyevm.Chain); ok { r0 = rf() diff --git a/core/cmd/mocks/prompter.go b/core/cmd/mocks/prompter.go index c0f682d5b9..a05d24d671 100644 --- a/core/cmd/mocks/prompter.go +++ b/core/cmd/mocks/prompter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type Prompter struct { func (_m *Prompter) IsTerminal() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsTerminal") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -27,6 +31,10 @@ func (_m *Prompter) IsTerminal() bool { func (_m *Prompter) PasswordPrompt(_a0 string) string { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for PasswordPrompt") + } + var r0 string if rf, ok := ret.Get(0).(func(string) string); ok { r0 = rf(_a0) @@ -41,6 +49,10 @@ func (_m *Prompter) PasswordPrompt(_a0 string) string { func (_m *Prompter) Prompt(_a0 string) string { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Prompt") + } + var r0 string if rf, ok := ret.Get(0).(func(string) string); ok { r0 = rf(_a0) diff --git a/core/config/mocks/telemetry_ingress.go b/core/config/mocks/telemetry_ingress.go index 59f4ed10da..ed5dbc4cf5 100644 --- a/core/config/mocks/telemetry_ingress.go +++ b/core/config/mocks/telemetry_ingress.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type TelemetryIngress struct { func (_m *TelemetryIngress) BufferSize() uint { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BufferSize") + } + var r0 uint if rf, ok := ret.Get(0).(func() uint); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *TelemetryIngress) BufferSize() uint { func (_m *TelemetryIngress) Endpoints() []config.TelemetryIngressEndpoint { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Endpoints") + } + var r0 []config.TelemetryIngressEndpoint if rf, ok := ret.Get(0).(func() []config.TelemetryIngressEndpoint); ok { r0 = rf() @@ -50,6 +58,10 @@ func (_m *TelemetryIngress) Endpoints() []config.TelemetryIngressEndpoint { func (_m *TelemetryIngress) Logging() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Logging") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -64,6 +76,10 @@ func (_m *TelemetryIngress) Logging() bool { func (_m *TelemetryIngress) MaxBatchSize() uint { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for MaxBatchSize") + } + var r0 uint if rf, ok := ret.Get(0).(func() uint); ok { r0 = rf() @@ -78,6 +94,10 @@ func (_m *TelemetryIngress) MaxBatchSize() uint { func (_m *TelemetryIngress) SendInterval() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SendInterval") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -92,6 +112,10 @@ func (_m *TelemetryIngress) SendInterval() time.Duration { func (_m *TelemetryIngress) SendTimeout() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SendTimeout") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -106,6 +130,10 @@ func (_m *TelemetryIngress) SendTimeout() time.Duration { func (_m *TelemetryIngress) ServerPubKey() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ServerPubKey") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -120,6 +148,10 @@ func (_m *TelemetryIngress) ServerPubKey() string { func (_m *TelemetryIngress) URL() *url.URL { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for URL") + } + var r0 *url.URL if rf, ok := ret.Get(0).(func() *url.URL); ok { r0 = rf() @@ -136,6 +168,10 @@ func (_m *TelemetryIngress) URL() *url.URL { func (_m *TelemetryIngress) UniConn() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for UniConn") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -150,6 +186,10 @@ func (_m *TelemetryIngress) UniConn() bool { func (_m *TelemetryIngress) UseBatchSend() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for UseBatchSend") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() diff --git a/core/config/mocks/telemetry_ingress_endpoint.go b/core/config/mocks/telemetry_ingress_endpoint.go index 7aa6f46aa2..08432cfe0e 100644 --- a/core/config/mocks/telemetry_ingress_endpoint.go +++ b/core/config/mocks/telemetry_ingress_endpoint.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type TelemetryIngressEndpoint struct { func (_m *TelemetryIngressEndpoint) ChainID() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *TelemetryIngressEndpoint) ChainID() string { func (_m *TelemetryIngressEndpoint) Network() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Network") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *TelemetryIngressEndpoint) Network() string { func (_m *TelemetryIngressEndpoint) ServerPubKey() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ServerPubKey") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -59,6 +71,10 @@ func (_m *TelemetryIngressEndpoint) ServerPubKey() string { func (_m *TelemetryIngressEndpoint) URL() *url.URL { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for URL") + } + var r0 *url.URL if rf, ok := ret.Get(0).(func() *url.URL); ok { r0 = rf() diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index 48f8e12dac..20874e4b60 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -53,6 +53,10 @@ type Application struct { func (_m *Application) AddJobV2(ctx context.Context, _a1 *job.Job) error { ret := _m.Called(ctx, _a1) + if len(ret) == 0 { + panic("no return value specified for AddJobV2") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *job.Job) error); ok { r0 = rf(ctx, _a1) @@ -67,6 +71,10 @@ func (_m *Application) AddJobV2(ctx context.Context, _a1 *job.Job) error { func (_m *Application) AuthenticationProvider() sessions.AuthenticationProvider { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AuthenticationProvider") + } + var r0 sessions.AuthenticationProvider if rf, ok := ret.Get(0).(func() sessions.AuthenticationProvider); ok { r0 = rf() @@ -83,6 +91,10 @@ func (_m *Application) AuthenticationProvider() sessions.AuthenticationProvider func (_m *Application) BasicAdminUsersORM() sessions.BasicAdminUsersORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BasicAdminUsersORM") + } + var r0 sessions.BasicAdminUsersORM if rf, ok := ret.Get(0).(func() sessions.BasicAdminUsersORM); ok { r0 = rf() @@ -99,6 +111,10 @@ func (_m *Application) BasicAdminUsersORM() sessions.BasicAdminUsersORM { func (_m *Application) BridgeORM() bridges.ORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BridgeORM") + } + var r0 bridges.ORM if rf, ok := ret.Get(0).(func() bridges.ORM); ok { r0 = rf() @@ -115,6 +131,10 @@ func (_m *Application) BridgeORM() bridges.ORM { func (_m *Application) DeleteJob(ctx context.Context, jobID int32) error { ret := _m.Called(ctx, jobID) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int32) error); ok { r0 = rf(ctx, jobID) @@ -129,6 +149,10 @@ func (_m *Application) DeleteJob(ctx context.Context, jobID int32) error { func (_m *Application) EVMORM() types.Configs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMORM") + } + var r0 types.Configs if rf, ok := ret.Get(0).(func() types.Configs); ok { r0 = rf() @@ -145,6 +169,10 @@ func (_m *Application) EVMORM() types.Configs { func (_m *Application) GetAuditLogger() audit.AuditLogger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAuditLogger") + } + var r0 audit.AuditLogger if rf, ok := ret.Get(0).(func() audit.AuditLogger); ok { r0 = rf() @@ -161,6 +189,10 @@ func (_m *Application) GetAuditLogger() audit.AuditLogger { func (_m *Application) GetConfig() chainlink.GeneralConfig { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetConfig") + } + var r0 chainlink.GeneralConfig if rf, ok := ret.Get(0).(func() chainlink.GeneralConfig); ok { r0 = rf() @@ -177,6 +209,10 @@ func (_m *Application) GetConfig() chainlink.GeneralConfig { func (_m *Application) GetExternalInitiatorManager() webhook.ExternalInitiatorManager { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetExternalInitiatorManager") + } + var r0 webhook.ExternalInitiatorManager if rf, ok := ret.Get(0).(func() webhook.ExternalInitiatorManager); ok { r0 = rf() @@ -193,6 +229,10 @@ func (_m *Application) GetExternalInitiatorManager() webhook.ExternalInitiatorMa func (_m *Application) GetFeedsService() feeds.Service { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetFeedsService") + } + var r0 feeds.Service if rf, ok := ret.Get(0).(func() feeds.Service); ok { r0 = rf() @@ -209,6 +249,10 @@ func (_m *Application) GetFeedsService() feeds.Service { func (_m *Application) GetHealthChecker() services.Checker { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetHealthChecker") + } + var r0 services.Checker if rf, ok := ret.Get(0).(func() services.Checker); ok { r0 = rf() @@ -225,6 +269,10 @@ func (_m *Application) GetHealthChecker() services.Checker { func (_m *Application) GetKeyStore() keystore.Master { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetKeyStore") + } + var r0 keystore.Master if rf, ok := ret.Get(0).(func() keystore.Master); ok { r0 = rf() @@ -241,6 +289,10 @@ func (_m *Application) GetKeyStore() keystore.Master { func (_m *Application) GetLogger() logger.SugaredLogger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetLogger") + } + var r0 logger.SugaredLogger if rf, ok := ret.Get(0).(func() logger.SugaredLogger); ok { r0 = rf() @@ -257,6 +309,10 @@ func (_m *Application) GetLogger() logger.SugaredLogger { func (_m *Application) GetLoopRegistry() *plugins.LoopRegistry { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetLoopRegistry") + } + var r0 *plugins.LoopRegistry if rf, ok := ret.Get(0).(func() *plugins.LoopRegistry); ok { r0 = rf() @@ -273,6 +329,10 @@ func (_m *Application) GetLoopRegistry() *plugins.LoopRegistry { func (_m *Application) GetRelayers() chainlink.RelayerChainInteroperators { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetRelayers") + } + var r0 chainlink.RelayerChainInteroperators if rf, ok := ret.Get(0).(func() chainlink.RelayerChainInteroperators); ok { r0 = rf() @@ -289,6 +349,10 @@ func (_m *Application) GetRelayers() chainlink.RelayerChainInteroperators { func (_m *Application) GetSqlxDB() *sqlx.DB { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetSqlxDB") + } + var r0 *sqlx.DB if rf, ok := ret.Get(0).(func() *sqlx.DB); ok { r0 = rf() @@ -305,6 +369,10 @@ func (_m *Application) GetSqlxDB() *sqlx.DB { func (_m *Application) GetWebAuthnConfiguration() sessions.WebAuthnConfiguration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetWebAuthnConfiguration") + } + var r0 sessions.WebAuthnConfiguration if rf, ok := ret.Get(0).(func() sessions.WebAuthnConfiguration); ok { r0 = rf() @@ -319,6 +387,10 @@ func (_m *Application) GetWebAuthnConfiguration() sessions.WebAuthnConfiguration func (_m *Application) ID() uuid.UUID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ID") + } + var r0 uuid.UUID if rf, ok := ret.Get(0).(func() uuid.UUID); ok { r0 = rf() @@ -335,6 +407,10 @@ func (_m *Application) ID() uuid.UUID { func (_m *Application) JobORM() job.ORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobORM") + } + var r0 job.ORM if rf, ok := ret.Get(0).(func() job.ORM); ok { r0 = rf() @@ -351,6 +427,10 @@ func (_m *Application) JobORM() job.ORM { func (_m *Application) JobSpawner() job.Spawner { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobSpawner") + } + var r0 job.Spawner if rf, ok := ret.Get(0).(func() job.Spawner); ok { r0 = rf() @@ -367,6 +447,10 @@ func (_m *Application) JobSpawner() job.Spawner { func (_m *Application) PipelineORM() pipeline.ORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PipelineORM") + } + var r0 pipeline.ORM if rf, ok := ret.Get(0).(func() pipeline.ORM); ok { r0 = rf() @@ -383,6 +467,10 @@ func (_m *Application) PipelineORM() pipeline.ORM { func (_m *Application) ReplayFromBlock(chainID *big.Int, number uint64, forceBroadcast bool) error { ret := _m.Called(chainID, number, forceBroadcast) + if len(ret) == 0 { + panic("no return value specified for ReplayFromBlock") + } + var r0 error if rf, ok := ret.Get(0).(func(*big.Int, uint64, bool) error); ok { r0 = rf(chainID, number, forceBroadcast) @@ -397,6 +485,10 @@ func (_m *Application) ReplayFromBlock(chainID *big.Int, number uint64, forceBro func (_m *Application) ResumeJobV2(ctx context.Context, taskID uuid.UUID, result pipeline.Result) error { ret := _m.Called(ctx, taskID, result) + if len(ret) == 0 { + panic("no return value specified for ResumeJobV2") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, pipeline.Result) error); ok { r0 = rf(ctx, taskID, result) @@ -411,6 +503,10 @@ func (_m *Application) ResumeJobV2(ctx context.Context, taskID uuid.UUID, result func (_m *Application) RunJobV2(ctx context.Context, jobID int32, meta map[string]interface{}) (int64, error) { ret := _m.Called(ctx, jobID, meta) + if len(ret) == 0 { + panic("no return value specified for RunJobV2") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, int32, map[string]interface{}) (int64, error)); ok { @@ -435,6 +531,10 @@ func (_m *Application) RunJobV2(ctx context.Context, jobID int32, meta map[strin func (_m *Application) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta pipeline.JSONSerializable) (int64, error) { ret := _m.Called(ctx, jobUUID, requestBody, meta) + if len(ret) == 0 { + panic("no return value specified for RunWebhookJobV2") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, string, pipeline.JSONSerializable) (int64, error)); ok { @@ -459,6 +559,10 @@ func (_m *Application) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, r func (_m *Application) SecretGenerator() chainlink.SecretGenerator { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SecretGenerator") + } + var r0 chainlink.SecretGenerator if rf, ok := ret.Get(0).(func() chainlink.SecretGenerator); ok { r0 = rf() @@ -475,6 +579,10 @@ func (_m *Application) SecretGenerator() chainlink.SecretGenerator { func (_m *Application) SetLogLevel(lvl zapcore.Level) error { ret := _m.Called(lvl) + if len(ret) == 0 { + panic("no return value specified for SetLogLevel") + } + var r0 error if rf, ok := ret.Get(0).(func(zapcore.Level) error); ok { r0 = rf(lvl) @@ -489,6 +597,10 @@ func (_m *Application) SetLogLevel(lvl zapcore.Level) error { func (_m *Application) Start(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -503,6 +615,10 @@ func (_m *Application) Start(ctx context.Context) error { func (_m *Application) Stop() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Stop") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -517,6 +633,10 @@ func (_m *Application) Stop() error { func (_m *Application) TxmStorageService() txmgr.EvmTxStore { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TxmStorageService") + } + var r0 txmgr.EvmTxStore if rf, ok := ret.Get(0).(func() txmgr.EvmTxStore); ok { r0 = rf() diff --git a/core/internal/mocks/flags.go b/core/internal/mocks/flags.go index 5b5aa81268..32d21326ba 100644 --- a/core/internal/mocks/flags.go +++ b/core/internal/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -26,6 +26,10 @@ type Flags struct { func (_m *Flags) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -52,6 +56,10 @@ func (_m *Flags) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, e func (_m *Flags) AddAccess(opts *bind.TransactOpts, _user common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _user) + if len(ret) == 0 { + panic("no return value specified for AddAccess") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -78,6 +86,10 @@ func (_m *Flags) AddAccess(opts *bind.TransactOpts, _user common.Address) (*type func (_m *Flags) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -94,6 +106,10 @@ func (_m *Flags) Address() common.Address { func (_m *Flags) CheckEnabled(opts *bind.CallOpts) (bool, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CheckEnabled") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok { @@ -118,6 +134,10 @@ func (_m *Flags) CheckEnabled(opts *bind.CallOpts) (bool, error) { func (_m *Flags) DisableAccessCheck(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for DisableAccessCheck") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -144,6 +164,10 @@ func (_m *Flags) DisableAccessCheck(opts *bind.TransactOpts) (*types.Transaction func (_m *Flags) EnableAccessCheck(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for EnableAccessCheck") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -170,6 +194,10 @@ func (_m *Flags) EnableAccessCheck(opts *bind.TransactOpts) (*types.Transaction, func (_m *Flags) FilterAddedAccess(opts *bind.FilterOpts) (*flags_wrapper.FlagsAddedAccessIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterAddedAccess") + } + var r0 *flags_wrapper.FlagsAddedAccessIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsAddedAccessIterator, error)); ok { @@ -196,6 +224,10 @@ func (_m *Flags) FilterAddedAccess(opts *bind.FilterOpts) (*flags_wrapper.FlagsA func (_m *Flags) FilterCheckAccessDisabled(opts *bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessDisabledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCheckAccessDisabled") + } + var r0 *flags_wrapper.FlagsCheckAccessDisabledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessDisabledIterator, error)); ok { @@ -222,6 +254,10 @@ func (_m *Flags) FilterCheckAccessDisabled(opts *bind.FilterOpts) (*flags_wrappe func (_m *Flags) FilterCheckAccessEnabled(opts *bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessEnabledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCheckAccessEnabled") + } + var r0 *flags_wrapper.FlagsCheckAccessEnabledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessEnabledIterator, error)); ok { @@ -248,6 +284,10 @@ func (_m *Flags) FilterCheckAccessEnabled(opts *bind.FilterOpts) (*flags_wrapper func (_m *Flags) FilterFlagLowered(opts *bind.FilterOpts, subject []common.Address) (*flags_wrapper.FlagsFlagLoweredIterator, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for FilterFlagLowered") + } + var r0 *flags_wrapper.FlagsFlagLoweredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flags_wrapper.FlagsFlagLoweredIterator, error)); ok { @@ -274,6 +314,10 @@ func (_m *Flags) FilterFlagLowered(opts *bind.FilterOpts, subject []common.Addre func (_m *Flags) FilterFlagRaised(opts *bind.FilterOpts, subject []common.Address) (*flags_wrapper.FlagsFlagRaisedIterator, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for FilterFlagRaised") + } + var r0 *flags_wrapper.FlagsFlagRaisedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flags_wrapper.FlagsFlagRaisedIterator, error)); ok { @@ -300,6 +344,10 @@ func (_m *Flags) FilterFlagRaised(opts *bind.FilterOpts, subject []common.Addres func (_m *Flags) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flags_wrapper.FlagsOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *flags_wrapper.FlagsOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flags_wrapper.FlagsOwnershipTransferRequestedIterator, error)); ok { @@ -326,6 +374,10 @@ func (_m *Flags) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from [] func (_m *Flags) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flags_wrapper.FlagsOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *flags_wrapper.FlagsOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flags_wrapper.FlagsOwnershipTransferredIterator, error)); ok { @@ -352,6 +404,10 @@ func (_m *Flags) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common func (_m *Flags) FilterRaisingAccessControllerUpdated(opts *bind.FilterOpts, previous []common.Address, current []common.Address) (*flags_wrapper.FlagsRaisingAccessControllerUpdatedIterator, error) { ret := _m.Called(opts, previous, current) + if len(ret) == 0 { + panic("no return value specified for FilterRaisingAccessControllerUpdated") + } + var r0 *flags_wrapper.FlagsRaisingAccessControllerUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flags_wrapper.FlagsRaisingAccessControllerUpdatedIterator, error)); ok { @@ -378,6 +434,10 @@ func (_m *Flags) FilterRaisingAccessControllerUpdated(opts *bind.FilterOpts, pre func (_m *Flags) FilterRemovedAccess(opts *bind.FilterOpts) (*flags_wrapper.FlagsRemovedAccessIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterRemovedAccess") + } + var r0 *flags_wrapper.FlagsRemovedAccessIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsRemovedAccessIterator, error)); ok { @@ -404,6 +464,10 @@ func (_m *Flags) FilterRemovedAccess(opts *bind.FilterOpts) (*flags_wrapper.Flag func (_m *Flags) GetFlag(opts *bind.CallOpts, subject common.Address) (bool, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for GetFlag") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (bool, error)); ok { @@ -428,6 +492,10 @@ func (_m *Flags) GetFlag(opts *bind.CallOpts, subject common.Address) (bool, err func (_m *Flags) GetFlags(opts *bind.CallOpts, subjects []common.Address) ([]bool, error) { ret := _m.Called(opts, subjects) + if len(ret) == 0 { + panic("no return value specified for GetFlags") + } + var r0 []bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, []common.Address) ([]bool, error)); ok { @@ -454,6 +522,10 @@ func (_m *Flags) GetFlags(opts *bind.CallOpts, subjects []common.Address) ([]boo func (_m *Flags) HasAccess(opts *bind.CallOpts, _user common.Address, _calldata []byte) (bool, error) { ret := _m.Called(opts, _user, _calldata) + if len(ret) == 0 { + panic("no return value specified for HasAccess") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, []byte) (bool, error)); ok { @@ -478,6 +550,10 @@ func (_m *Flags) HasAccess(opts *bind.CallOpts, _user common.Address, _calldata func (_m *Flags) LowerFlags(opts *bind.TransactOpts, subjects []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subjects) + if len(ret) == 0 { + panic("no return value specified for LowerFlags") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address) (*types.Transaction, error)); ok { @@ -504,6 +580,10 @@ func (_m *Flags) LowerFlags(opts *bind.TransactOpts, subjects []common.Address) func (_m *Flags) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -530,6 +610,10 @@ func (_m *Flags) Owner(opts *bind.CallOpts) (common.Address, error) { func (_m *Flags) ParseAddedAccess(log types.Log) (*flags_wrapper.FlagsAddedAccess, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAddedAccess") + } + var r0 *flags_wrapper.FlagsAddedAccess var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsAddedAccess, error)); ok { @@ -556,6 +640,10 @@ func (_m *Flags) ParseAddedAccess(log types.Log) (*flags_wrapper.FlagsAddedAcces func (_m *Flags) ParseCheckAccessDisabled(log types.Log) (*flags_wrapper.FlagsCheckAccessDisabled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCheckAccessDisabled") + } + var r0 *flags_wrapper.FlagsCheckAccessDisabled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsCheckAccessDisabled, error)); ok { @@ -582,6 +670,10 @@ func (_m *Flags) ParseCheckAccessDisabled(log types.Log) (*flags_wrapper.FlagsCh func (_m *Flags) ParseCheckAccessEnabled(log types.Log) (*flags_wrapper.FlagsCheckAccessEnabled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCheckAccessEnabled") + } + var r0 *flags_wrapper.FlagsCheckAccessEnabled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsCheckAccessEnabled, error)); ok { @@ -608,6 +700,10 @@ func (_m *Flags) ParseCheckAccessEnabled(log types.Log) (*flags_wrapper.FlagsChe func (_m *Flags) ParseFlagLowered(log types.Log) (*flags_wrapper.FlagsFlagLowered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFlagLowered") + } + var r0 *flags_wrapper.FlagsFlagLowered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsFlagLowered, error)); ok { @@ -634,6 +730,10 @@ func (_m *Flags) ParseFlagLowered(log types.Log) (*flags_wrapper.FlagsFlagLowere func (_m *Flags) ParseFlagRaised(log types.Log) (*flags_wrapper.FlagsFlagRaised, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFlagRaised") + } + var r0 *flags_wrapper.FlagsFlagRaised var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsFlagRaised, error)); ok { @@ -660,6 +760,10 @@ func (_m *Flags) ParseFlagRaised(log types.Log) (*flags_wrapper.FlagsFlagRaised, func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -686,6 +790,10 @@ func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { func (_m *Flags) ParseOwnershipTransferRequested(log types.Log) (*flags_wrapper.FlagsOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *flags_wrapper.FlagsOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsOwnershipTransferRequested, error)); ok { @@ -712,6 +820,10 @@ func (_m *Flags) ParseOwnershipTransferRequested(log types.Log) (*flags_wrapper. func (_m *Flags) ParseOwnershipTransferred(log types.Log) (*flags_wrapper.FlagsOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *flags_wrapper.FlagsOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsOwnershipTransferred, error)); ok { @@ -738,6 +850,10 @@ func (_m *Flags) ParseOwnershipTransferred(log types.Log) (*flags_wrapper.FlagsO func (_m *Flags) ParseRaisingAccessControllerUpdated(log types.Log) (*flags_wrapper.FlagsRaisingAccessControllerUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRaisingAccessControllerUpdated") + } + var r0 *flags_wrapper.FlagsRaisingAccessControllerUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsRaisingAccessControllerUpdated, error)); ok { @@ -764,6 +880,10 @@ func (_m *Flags) ParseRaisingAccessControllerUpdated(log types.Log) (*flags_wrap func (_m *Flags) ParseRemovedAccess(log types.Log) (*flags_wrapper.FlagsRemovedAccess, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRemovedAccess") + } + var r0 *flags_wrapper.FlagsRemovedAccess var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsRemovedAccess, error)); ok { @@ -790,6 +910,10 @@ func (_m *Flags) ParseRemovedAccess(log types.Log) (*flags_wrapper.FlagsRemovedA func (_m *Flags) RaiseFlag(opts *bind.TransactOpts, subject common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for RaiseFlag") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -816,6 +940,10 @@ func (_m *Flags) RaiseFlag(opts *bind.TransactOpts, subject common.Address) (*ty func (_m *Flags) RaiseFlags(opts *bind.TransactOpts, subjects []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subjects) + if len(ret) == 0 { + panic("no return value specified for RaiseFlags") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address) (*types.Transaction, error)); ok { @@ -842,6 +970,10 @@ func (_m *Flags) RaiseFlags(opts *bind.TransactOpts, subjects []common.Address) func (_m *Flags) RaisingAccessController(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for RaisingAccessController") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -868,6 +1000,10 @@ func (_m *Flags) RaisingAccessController(opts *bind.CallOpts) (common.Address, e func (_m *Flags) RemoveAccess(opts *bind.TransactOpts, _user common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _user) + if len(ret) == 0 { + panic("no return value specified for RemoveAccess") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -894,6 +1030,10 @@ func (_m *Flags) RemoveAccess(opts *bind.TransactOpts, _user common.Address) (*t func (_m *Flags) SetRaisingAccessController(opts *bind.TransactOpts, racAddress common.Address) (*types.Transaction, error) { ret := _m.Called(opts, racAddress) + if len(ret) == 0 { + panic("no return value specified for SetRaisingAccessController") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -920,6 +1060,10 @@ func (_m *Flags) SetRaisingAccessController(opts *bind.TransactOpts, racAddress func (_m *Flags) TransferOwnership(opts *bind.TransactOpts, _to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -946,6 +1090,10 @@ func (_m *Flags) TransferOwnership(opts *bind.TransactOpts, _to common.Address) func (_m *Flags) WatchAddedAccess(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsAddedAccess) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchAddedAccess") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsAddedAccess) (event.Subscription, error)); ok { @@ -972,6 +1120,10 @@ func (_m *Flags) WatchAddedAccess(opts *bind.WatchOpts, sink chan<- *flags_wrapp func (_m *Flags) WatchCheckAccessDisabled(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsCheckAccessDisabled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCheckAccessDisabled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsCheckAccessDisabled) (event.Subscription, error)); ok { @@ -998,6 +1150,10 @@ func (_m *Flags) WatchCheckAccessDisabled(opts *bind.WatchOpts, sink chan<- *fla func (_m *Flags) WatchCheckAccessEnabled(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsCheckAccessEnabled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCheckAccessEnabled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsCheckAccessEnabled) (event.Subscription, error)); ok { @@ -1024,6 +1180,10 @@ func (_m *Flags) WatchCheckAccessEnabled(opts *bind.WatchOpts, sink chan<- *flag func (_m *Flags) WatchFlagLowered(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsFlagLowered, subject []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, subject) + if len(ret) == 0 { + panic("no return value specified for WatchFlagLowered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsFlagLowered, []common.Address) (event.Subscription, error)); ok { @@ -1050,6 +1210,10 @@ func (_m *Flags) WatchFlagLowered(opts *bind.WatchOpts, sink chan<- *flags_wrapp func (_m *Flags) WatchFlagRaised(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsFlagRaised, subject []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, subject) + if len(ret) == 0 { + panic("no return value specified for WatchFlagRaised") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsFlagRaised, []common.Address) (event.Subscription, error)); ok { @@ -1076,6 +1240,10 @@ func (_m *Flags) WatchFlagRaised(opts *bind.WatchOpts, sink chan<- *flags_wrappe func (_m *Flags) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1102,6 +1270,10 @@ func (_m *Flags) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan func (_m *Flags) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1128,6 +1300,10 @@ func (_m *Flags) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *fl func (_m *Flags) WatchRaisingAccessControllerUpdated(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsRaisingAccessControllerUpdated, previous []common.Address, current []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, previous, current) + if len(ret) == 0 { + panic("no return value specified for WatchRaisingAccessControllerUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsRaisingAccessControllerUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1154,6 +1330,10 @@ func (_m *Flags) WatchRaisingAccessControllerUpdated(opts *bind.WatchOpts, sink func (_m *Flags) WatchRemovedAccess(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsRemovedAccess) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchRemovedAccess") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsRemovedAccess) (event.Subscription, error)); ok { diff --git a/core/internal/mocks/flux_aggregator.go b/core/internal/mocks/flux_aggregator.go index e3da1b83df..ac72bd07db 100644 --- a/core/internal/mocks/flux_aggregator.go +++ b/core/internal/mocks/flux_aggregator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type FluxAggregator struct { func (_m *FluxAggregator) AcceptAdmin(opts *bind.TransactOpts, _oracle common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _oracle) + if len(ret) == 0 { + panic("no return value specified for AcceptAdmin") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *FluxAggregator) AcceptAdmin(opts *bind.TransactOpts, _oracle common.Ad func (_m *FluxAggregator) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *FluxAggregator) AcceptOwnership(opts *bind.TransactOpts) (*types.Trans func (_m *FluxAggregator) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -96,6 +108,10 @@ func (_m *FluxAggregator) Address() common.Address { func (_m *FluxAggregator) AllocatedFunds(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AllocatedFunds") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -122,6 +138,10 @@ func (_m *FluxAggregator) AllocatedFunds(opts *bind.CallOpts) (*big.Int, error) func (_m *FluxAggregator) AvailableFunds(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AvailableFunds") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -148,6 +168,10 @@ func (_m *FluxAggregator) AvailableFunds(opts *bind.CallOpts) (*big.Int, error) func (_m *FluxAggregator) ChangeOracles(opts *bind.TransactOpts, _removed []common.Address, _added []common.Address, _addedAdmins []common.Address, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32) (*types.Transaction, error) { ret := _m.Called(opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay) + if len(ret) == 0 { + panic("no return value specified for ChangeOracles") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, []common.Address, uint32, uint32, uint32) (*types.Transaction, error)); ok { @@ -174,6 +198,10 @@ func (_m *FluxAggregator) ChangeOracles(opts *bind.TransactOpts, _removed []comm func (_m *FluxAggregator) Decimals(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Decimals") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -198,6 +226,10 @@ func (_m *FluxAggregator) Decimals(opts *bind.CallOpts) (uint8, error) { func (_m *FluxAggregator) Description(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Description") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -222,6 +254,10 @@ func (_m *FluxAggregator) Description(opts *bind.CallOpts) (string, error) { func (_m *FluxAggregator) FilterAnswerUpdated(opts *bind.FilterOpts, current []*big.Int, roundId []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, error) { ret := _m.Called(opts, current, roundId) + if len(ret) == 0 { + panic("no return value specified for FilterAnswerUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, error)); ok { @@ -248,6 +284,10 @@ func (_m *FluxAggregator) FilterAnswerUpdated(opts *bind.FilterOpts, current []* func (_m *FluxAggregator) FilterAvailableFundsUpdated(opts *bind.FilterOpts, amount []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, error) { ret := _m.Called(opts, amount) + if len(ret) == 0 { + panic("no return value specified for FilterAvailableFundsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, error)); ok { @@ -274,6 +314,10 @@ func (_m *FluxAggregator) FilterAvailableFundsUpdated(opts *bind.FilterOpts, amo func (_m *FluxAggregator) FilterNewRound(opts *bind.FilterOpts, roundId []*big.Int, startedBy []common.Address) (*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, error) { ret := _m.Called(opts, roundId, startedBy) + if len(ret) == 0 { + panic("no return value specified for FilterNewRound") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorNewRoundIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, error)); ok { @@ -300,6 +344,10 @@ func (_m *FluxAggregator) FilterNewRound(opts *bind.FilterOpts, roundId []*big.I func (_m *FluxAggregator) FilterOracleAdminUpdateRequested(opts *bind.FilterOpts, oracle []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, error) { ret := _m.Called(opts, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterOracleAdminUpdateRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, error)); ok { @@ -326,6 +374,10 @@ func (_m *FluxAggregator) FilterOracleAdminUpdateRequested(opts *bind.FilterOpts func (_m *FluxAggregator) FilterOracleAdminUpdated(opts *bind.FilterOpts, oracle []common.Address, newAdmin []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, error) { ret := _m.Called(opts, oracle, newAdmin) + if len(ret) == 0 { + panic("no return value specified for FilterOracleAdminUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, error)); ok { @@ -352,6 +404,10 @@ func (_m *FluxAggregator) FilterOracleAdminUpdated(opts *bind.FilterOpts, oracle func (_m *FluxAggregator) FilterOraclePermissionsUpdated(opts *bind.FilterOpts, oracle []common.Address, whitelisted []bool) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, error) { ret := _m.Called(opts, oracle, whitelisted) + if len(ret) == 0 { + panic("no return value specified for FilterOraclePermissionsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []bool) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, error)); ok { @@ -378,6 +434,10 @@ func (_m *FluxAggregator) FilterOraclePermissionsUpdated(opts *bind.FilterOpts, func (_m *FluxAggregator) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, error)); ok { @@ -404,6 +464,10 @@ func (_m *FluxAggregator) FilterOwnershipTransferRequested(opts *bind.FilterOpts func (_m *FluxAggregator) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, error)); ok { @@ -430,6 +494,10 @@ func (_m *FluxAggregator) FilterOwnershipTransferred(opts *bind.FilterOpts, from func (_m *FluxAggregator) FilterRequesterPermissionsSet(opts *bind.FilterOpts, requester []common.Address) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, error) { ret := _m.Called(opts, requester) + if len(ret) == 0 { + panic("no return value specified for FilterRequesterPermissionsSet") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, error)); ok { @@ -456,6 +524,10 @@ func (_m *FluxAggregator) FilterRequesterPermissionsSet(opts *bind.FilterOpts, r func (_m *FluxAggregator) FilterRoundDetailsUpdated(opts *bind.FilterOpts, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, error) { ret := _m.Called(opts, paymentAmount, minSubmissionCount, maxSubmissionCount) + if len(ret) == 0 { + panic("no return value specified for FilterRoundDetailsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []uint32) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, error)); ok { @@ -482,6 +554,10 @@ func (_m *FluxAggregator) FilterRoundDetailsUpdated(opts *bind.FilterOpts, payme func (_m *FluxAggregator) FilterSubmissionReceived(opts *bind.FilterOpts, submission []*big.Int, round []uint32, oracle []common.Address) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, error) { ret := _m.Called(opts, submission, round, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterSubmissionReceived") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, error)); ok { @@ -508,6 +584,10 @@ func (_m *FluxAggregator) FilterSubmissionReceived(opts *bind.FilterOpts, submis func (_m *FluxAggregator) FilterValidatorUpdated(opts *bind.FilterOpts, previous []common.Address, current []common.Address) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, error) { ret := _m.Called(opts, previous, current) + if len(ret) == 0 { + panic("no return value specified for FilterValidatorUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, error)); ok { @@ -534,6 +614,10 @@ func (_m *FluxAggregator) FilterValidatorUpdated(opts *bind.FilterOpts, previous func (_m *FluxAggregator) GetAdmin(opts *bind.CallOpts, _oracle common.Address) (common.Address, error) { ret := _m.Called(opts, _oracle) + if len(ret) == 0 { + panic("no return value specified for GetAdmin") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok { @@ -560,6 +644,10 @@ func (_m *FluxAggregator) GetAdmin(opts *bind.CallOpts, _oracle common.Address) func (_m *FluxAggregator) GetAnswer(opts *bind.CallOpts, _roundId *big.Int) (*big.Int, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetAnswer") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (*big.Int, error)); ok { @@ -586,6 +674,10 @@ func (_m *FluxAggregator) GetAnswer(opts *bind.CallOpts, _roundId *big.Int) (*bi func (_m *FluxAggregator) GetOracles(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetOracles") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -612,6 +704,10 @@ func (_m *FluxAggregator) GetOracles(opts *bind.CallOpts) ([]common.Address, err func (_m *FluxAggregator) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (flux_aggregator_wrapper.GetRoundData, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetRoundData") + } + var r0 flux_aggregator_wrapper.GetRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (flux_aggregator_wrapper.GetRoundData, error)); ok { @@ -636,6 +732,10 @@ func (_m *FluxAggregator) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) ( func (_m *FluxAggregator) GetTimestamp(opts *bind.CallOpts, _roundId *big.Int) (*big.Int, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetTimestamp") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (*big.Int, error)); ok { @@ -662,6 +762,10 @@ func (_m *FluxAggregator) GetTimestamp(opts *bind.CallOpts, _roundId *big.Int) ( func (_m *FluxAggregator) LatestAnswer(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestAnswer") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -688,6 +792,10 @@ func (_m *FluxAggregator) LatestAnswer(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) LatestRound(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestRound") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -714,6 +822,10 @@ func (_m *FluxAggregator) LatestRound(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) LatestRoundData(opts *bind.CallOpts) (flux_aggregator_wrapper.LatestRoundData, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestRoundData") + } + var r0 flux_aggregator_wrapper.LatestRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (flux_aggregator_wrapper.LatestRoundData, error)); ok { @@ -738,6 +850,10 @@ func (_m *FluxAggregator) LatestRoundData(opts *bind.CallOpts) (flux_aggregator_ func (_m *FluxAggregator) LatestTimestamp(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestTimestamp") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -764,6 +880,10 @@ func (_m *FluxAggregator) LatestTimestamp(opts *bind.CallOpts) (*big.Int, error) func (_m *FluxAggregator) LinkToken(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LinkToken") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -790,6 +910,10 @@ func (_m *FluxAggregator) LinkToken(opts *bind.CallOpts) (common.Address, error) func (_m *FluxAggregator) MaxSubmissionCount(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MaxSubmissionCount") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -814,6 +938,10 @@ func (_m *FluxAggregator) MaxSubmissionCount(opts *bind.CallOpts) (uint32, error func (_m *FluxAggregator) MaxSubmissionValue(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MaxSubmissionValue") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -840,6 +968,10 @@ func (_m *FluxAggregator) MaxSubmissionValue(opts *bind.CallOpts) (*big.Int, err func (_m *FluxAggregator) MinSubmissionCount(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MinSubmissionCount") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -864,6 +996,10 @@ func (_m *FluxAggregator) MinSubmissionCount(opts *bind.CallOpts) (uint32, error func (_m *FluxAggregator) MinSubmissionValue(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MinSubmissionValue") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -890,6 +1026,10 @@ func (_m *FluxAggregator) MinSubmissionValue(opts *bind.CallOpts) (*big.Int, err func (_m *FluxAggregator) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int, _data []byte) (*types.Transaction, error) { ret := _m.Called(opts, arg0, arg1, _data) + if len(ret) == 0 { + panic("no return value specified for OnTokenTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -916,6 +1056,10 @@ func (_m *FluxAggregator) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.A func (_m *FluxAggregator) OracleCount(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for OracleCount") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -940,6 +1084,10 @@ func (_m *FluxAggregator) OracleCount(opts *bind.CallOpts) (uint8, error) { func (_m *FluxAggregator) OracleRoundState(opts *bind.CallOpts, _oracle common.Address, _queriedRoundId uint32) (flux_aggregator_wrapper.OracleRoundState, error) { ret := _m.Called(opts, _oracle, _queriedRoundId) + if len(ret) == 0 { + panic("no return value specified for OracleRoundState") + } + var r0 flux_aggregator_wrapper.OracleRoundState var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, uint32) (flux_aggregator_wrapper.OracleRoundState, error)); ok { @@ -964,6 +1112,10 @@ func (_m *FluxAggregator) OracleRoundState(opts *bind.CallOpts, _oracle common.A func (_m *FluxAggregator) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -990,6 +1142,10 @@ func (_m *FluxAggregator) Owner(opts *bind.CallOpts) (common.Address, error) { func (_m *FluxAggregator) ParseAnswerUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAnswerUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, error)); ok { @@ -1016,6 +1172,10 @@ func (_m *FluxAggregator) ParseAnswerUpdated(log types.Log) (*flux_aggregator_wr func (_m *FluxAggregator) ParseAvailableFundsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAvailableFundsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, error)); ok { @@ -1042,6 +1202,10 @@ func (_m *FluxAggregator) ParseAvailableFundsUpdated(log types.Log) (*flux_aggre func (_m *FluxAggregator) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -1068,6 +1232,10 @@ func (_m *FluxAggregator) ParseLog(log types.Log) (generated.AbigenLog, error) { func (_m *FluxAggregator) ParseNewRound(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorNewRound, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseNewRound") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorNewRound var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorNewRound, error)); ok { @@ -1094,6 +1262,10 @@ func (_m *FluxAggregator) ParseNewRound(log types.Log) (*flux_aggregator_wrapper func (_m *FluxAggregator) ParseOracleAdminUpdateRequested(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOracleAdminUpdateRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, error)); ok { @@ -1120,6 +1292,10 @@ func (_m *FluxAggregator) ParseOracleAdminUpdateRequested(log types.Log) (*flux_ func (_m *FluxAggregator) ParseOracleAdminUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOracleAdminUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, error)); ok { @@ -1146,6 +1322,10 @@ func (_m *FluxAggregator) ParseOracleAdminUpdated(log types.Log) (*flux_aggregat func (_m *FluxAggregator) ParseOraclePermissionsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOraclePermissionsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, error)); ok { @@ -1172,6 +1352,10 @@ func (_m *FluxAggregator) ParseOraclePermissionsUpdated(log types.Log) (*flux_ag func (_m *FluxAggregator) ParseOwnershipTransferRequested(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, error)); ok { @@ -1198,6 +1382,10 @@ func (_m *FluxAggregator) ParseOwnershipTransferRequested(log types.Log) (*flux_ func (_m *FluxAggregator) ParseOwnershipTransferred(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, error)); ok { @@ -1224,6 +1412,10 @@ func (_m *FluxAggregator) ParseOwnershipTransferred(log types.Log) (*flux_aggreg func (_m *FluxAggregator) ParseRequesterPermissionsSet(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRequesterPermissionsSet") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, error)); ok { @@ -1250,6 +1442,10 @@ func (_m *FluxAggregator) ParseRequesterPermissionsSet(log types.Log) (*flux_agg func (_m *FluxAggregator) ParseRoundDetailsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRoundDetailsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, error)); ok { @@ -1276,6 +1472,10 @@ func (_m *FluxAggregator) ParseRoundDetailsUpdated(log types.Log) (*flux_aggrega func (_m *FluxAggregator) ParseSubmissionReceived(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubmissionReceived") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, error)); ok { @@ -1302,6 +1502,10 @@ func (_m *FluxAggregator) ParseSubmissionReceived(log types.Log) (*flux_aggregat func (_m *FluxAggregator) ParseValidatorUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseValidatorUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, error)); ok { @@ -1328,6 +1532,10 @@ func (_m *FluxAggregator) ParseValidatorUpdated(log types.Log) (*flux_aggregator func (_m *FluxAggregator) PaymentAmount(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for PaymentAmount") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -1354,6 +1562,10 @@ func (_m *FluxAggregator) PaymentAmount(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) RequestNewRound(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for RequestNewRound") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -1380,6 +1592,10 @@ func (_m *FluxAggregator) RequestNewRound(opts *bind.TransactOpts) (*types.Trans func (_m *FluxAggregator) RestartDelay(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for RestartDelay") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -1404,6 +1620,10 @@ func (_m *FluxAggregator) RestartDelay(opts *bind.CallOpts) (uint32, error) { func (_m *FluxAggregator) SetRequesterPermissions(opts *bind.TransactOpts, _requester common.Address, _authorized bool, _delay uint32) (*types.Transaction, error) { ret := _m.Called(opts, _requester, _authorized, _delay) + if len(ret) == 0 { + panic("no return value specified for SetRequesterPermissions") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, uint32) (*types.Transaction, error)); ok { @@ -1430,6 +1650,10 @@ func (_m *FluxAggregator) SetRequesterPermissions(opts *bind.TransactOpts, _requ func (_m *FluxAggregator) SetValidator(opts *bind.TransactOpts, _newValidator common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _newValidator) + if len(ret) == 0 { + panic("no return value specified for SetValidator") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1456,6 +1680,10 @@ func (_m *FluxAggregator) SetValidator(opts *bind.TransactOpts, _newValidator co func (_m *FluxAggregator) Submit(opts *bind.TransactOpts, _roundId *big.Int, _submission *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _roundId, _submission) + if len(ret) == 0 { + panic("no return value specified for Submit") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int) (*types.Transaction, error)); ok { @@ -1482,6 +1710,10 @@ func (_m *FluxAggregator) Submit(opts *bind.TransactOpts, _roundId *big.Int, _su func (_m *FluxAggregator) Timeout(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Timeout") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -1506,6 +1738,10 @@ func (_m *FluxAggregator) Timeout(opts *bind.CallOpts) (uint32, error) { func (_m *FluxAggregator) TransferAdmin(opts *bind.TransactOpts, _oracle common.Address, _newAdmin common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _oracle, _newAdmin) + if len(ret) == 0 { + panic("no return value specified for TransferAdmin") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok { @@ -1532,6 +1768,10 @@ func (_m *FluxAggregator) TransferAdmin(opts *bind.TransactOpts, _oracle common. func (_m *FluxAggregator) TransferOwnership(opts *bind.TransactOpts, _to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1558,6 +1798,10 @@ func (_m *FluxAggregator) TransferOwnership(opts *bind.TransactOpts, _to common. func (_m *FluxAggregator) UpdateAvailableFunds(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for UpdateAvailableFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -1584,6 +1828,10 @@ func (_m *FluxAggregator) UpdateAvailableFunds(opts *bind.TransactOpts) (*types. func (_m *FluxAggregator) UpdateFutureRounds(opts *bind.TransactOpts, _paymentAmount *big.Int, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32, _timeout uint32) (*types.Transaction, error) { ret := _m.Called(opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout) + if len(ret) == 0 { + panic("no return value specified for UpdateFutureRounds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint32, uint32, uint32, uint32) (*types.Transaction, error)); ok { @@ -1610,6 +1858,10 @@ func (_m *FluxAggregator) UpdateFutureRounds(opts *bind.TransactOpts, _paymentAm func (_m *FluxAggregator) Validator(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Validator") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1636,6 +1888,10 @@ func (_m *FluxAggregator) Validator(opts *bind.CallOpts) (common.Address, error) func (_m *FluxAggregator) Version(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Version") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -1662,6 +1918,10 @@ func (_m *FluxAggregator) Version(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) WatchAnswerUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, current []*big.Int, roundId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, current, roundId) + if len(ret) == 0 { + panic("no return value specified for WatchAnswerUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, []*big.Int, []*big.Int) (event.Subscription, error)); ok { @@ -1688,6 +1948,10 @@ func (_m *FluxAggregator) WatchAnswerUpdated(opts *bind.WatchOpts, sink chan<- * func (_m *FluxAggregator) WatchAvailableFundsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, amount []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, amount) + if len(ret) == 0 { + panic("no return value specified for WatchAvailableFundsUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, []*big.Int) (event.Subscription, error)); ok { @@ -1714,6 +1978,10 @@ func (_m *FluxAggregator) WatchAvailableFundsUpdated(opts *bind.WatchOpts, sink func (_m *FluxAggregator) WatchNewRound(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, roundId []*big.Int, startedBy []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, roundId, startedBy) + if len(ret) == 0 { + panic("no return value specified for WatchNewRound") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -1740,6 +2008,10 @@ func (_m *FluxAggregator) WatchNewRound(opts *bind.WatchOpts, sink chan<- *flux_ func (_m *FluxAggregator) WatchOracleAdminUpdateRequested(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchOracleAdminUpdateRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, []common.Address) (event.Subscription, error)); ok { @@ -1766,6 +2038,10 @@ func (_m *FluxAggregator) WatchOracleAdminUpdateRequested(opts *bind.WatchOpts, func (_m *FluxAggregator) WatchOracleAdminUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, oracle []common.Address, newAdmin []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle, newAdmin) + if len(ret) == 0 { + panic("no return value specified for WatchOracleAdminUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1792,6 +2068,10 @@ func (_m *FluxAggregator) WatchOracleAdminUpdated(opts *bind.WatchOpts, sink cha func (_m *FluxAggregator) WatchOraclePermissionsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, oracle []common.Address, whitelisted []bool) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle, whitelisted) + if len(ret) == 0 { + panic("no return value specified for WatchOraclePermissionsUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, []common.Address, []bool) (event.Subscription, error)); ok { @@ -1818,6 +2098,10 @@ func (_m *FluxAggregator) WatchOraclePermissionsUpdated(opts *bind.WatchOpts, si func (_m *FluxAggregator) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1844,6 +2128,10 @@ func (_m *FluxAggregator) WatchOwnershipTransferRequested(opts *bind.WatchOpts, func (_m *FluxAggregator) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1870,6 +2158,10 @@ func (_m *FluxAggregator) WatchOwnershipTransferred(opts *bind.WatchOpts, sink c func (_m *FluxAggregator) WatchRequesterPermissionsSet(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, requester []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, requester) + if len(ret) == 0 { + panic("no return value specified for WatchRequesterPermissionsSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, []common.Address) (event.Subscription, error)); ok { @@ -1896,6 +2188,10 @@ func (_m *FluxAggregator) WatchRequesterPermissionsSet(opts *bind.WatchOpts, sin func (_m *FluxAggregator) WatchRoundDetailsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32) (event.Subscription, error) { ret := _m.Called(opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount) + if len(ret) == 0 { + panic("no return value specified for WatchRoundDetailsUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, []*big.Int, []uint32, []uint32) (event.Subscription, error)); ok { @@ -1922,6 +2218,10 @@ func (_m *FluxAggregator) WatchRoundDetailsUpdated(opts *bind.WatchOpts, sink ch func (_m *FluxAggregator) WatchSubmissionReceived(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, submission []*big.Int, round []uint32, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, submission, round, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchSubmissionReceived") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, []*big.Int, []uint32, []common.Address) (event.Subscription, error)); ok { @@ -1948,6 +2248,10 @@ func (_m *FluxAggregator) WatchSubmissionReceived(opts *bind.WatchOpts, sink cha func (_m *FluxAggregator) WatchValidatorUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, previous []common.Address, current []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, previous, current) + if len(ret) == 0 { + panic("no return value specified for WatchValidatorUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1974,6 +2278,10 @@ func (_m *FluxAggregator) WatchValidatorUpdated(opts *bind.WatchOpts, sink chan< func (_m *FluxAggregator) WithdrawFunds(opts *bind.TransactOpts, _recipient common.Address, _amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _recipient, _amount) + if len(ret) == 0 { + panic("no return value specified for WithdrawFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -2000,6 +2308,10 @@ func (_m *FluxAggregator) WithdrawFunds(opts *bind.TransactOpts, _recipient comm func (_m *FluxAggregator) WithdrawPayment(opts *bind.TransactOpts, _oracle common.Address, _recipient common.Address, _amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _oracle, _recipient, _amount) + if len(ret) == 0 { + panic("no return value specified for WithdrawPayment") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -2026,6 +2338,10 @@ func (_m *FluxAggregator) WithdrawPayment(opts *bind.TransactOpts, _oracle commo func (_m *FluxAggregator) WithdrawablePayment(opts *bind.CallOpts, _oracle common.Address) (*big.Int, error) { ret := _m.Called(opts, _oracle) + if len(ret) == 0 { + panic("no return value specified for WithdrawablePayment") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { diff --git a/core/internal/mocks/prometheus_backend.go b/core/internal/mocks/prometheus_backend.go index b2556a0bad..6573dbaf03 100644 --- a/core/internal/mocks/prometheus_backend.go +++ b/core/internal/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/core/logger/logger_mock_test.go b/core/logger/logger_mock_test.go index 2b6dfcf3b2..afddd03188 100644 --- a/core/logger/logger_mock_test.go +++ b/core/logger/logger_mock_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package logger @@ -108,6 +108,10 @@ func (_m *MockLogger) Fatalw(msg string, keysAndValues ...interface{}) { func (_m *MockLogger) Helper(skip int) Logger { ret := _m.Called(skip) + if len(ret) == 0 { + panic("no return value specified for Helper") + } + var r0 Logger if rf, ok := ret.Get(0).(func(int) Logger); ok { r0 = rf(skip) @@ -147,6 +151,10 @@ func (_m *MockLogger) Infow(msg string, keysAndValues ...interface{}) { func (_m *MockLogger) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -161,6 +169,10 @@ func (_m *MockLogger) Name() string { func (_m *MockLogger) Named(name string) Logger { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for Named") + } + var r0 Logger if rf, ok := ret.Get(0).(func(string) Logger); ok { r0 = rf(name) @@ -210,6 +222,10 @@ func (_m *MockLogger) SetLogLevel(_a0 zapcore.Level) { func (_m *MockLogger) Sync() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Sync") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -272,6 +288,10 @@ func (_m *MockLogger) With(args ...interface{}) Logger { _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for With") + } + var r0 Logger if rf, ok := ret.Get(0).(func(...interface{}) Logger); ok { r0 = rf(args...) diff --git a/core/logger/mocks/logger.go b/core/logger/mocks/logger.go index 965bd57baa..316f6216b9 100644 --- a/core/logger/mocks/logger.go +++ b/core/logger/mocks/logger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -110,6 +110,10 @@ func (_m *Logger) Fatalw(msg string, keysAndValues ...interface{}) { func (_m *Logger) Helper(skip int) logger.Logger { ret := _m.Called(skip) + if len(ret) == 0 { + panic("no return value specified for Helper") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func(int) logger.Logger); ok { r0 = rf(skip) @@ -149,6 +153,10 @@ func (_m *Logger) Infow(msg string, keysAndValues ...interface{}) { func (_m *Logger) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -163,6 +171,10 @@ func (_m *Logger) Name() string { func (_m *Logger) Named(name string) logger.Logger { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for Named") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func(string) logger.Logger); ok { r0 = rf(name) @@ -212,6 +224,10 @@ func (_m *Logger) SetLogLevel(_a0 zapcore.Level) { func (_m *Logger) Sync() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Sync") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -274,6 +290,10 @@ func (_m *Logger) With(args ...interface{}) logger.Logger { _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for With") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func(...interface{}) logger.Logger); ok { r0 = rf(args...) diff --git a/core/services/blockhashstore/mocks/bhs.go b/core/services/blockhashstore/mocks/bhs.go index 51ddca46a0..a69016c802 100644 --- a/core/services/blockhashstore/mocks/bhs.go +++ b/core/services/blockhashstore/mocks/bhs.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type BHS struct { func (_m *BHS) IsStored(ctx context.Context, blockNum uint64) (bool, error) { ret := _m.Called(ctx, blockNum) + if len(ret) == 0 { + panic("no return value specified for IsStored") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64) (bool, error)); ok { @@ -43,6 +47,10 @@ func (_m *BHS) IsStored(ctx context.Context, blockNum uint64) (bool, error) { func (_m *BHS) IsTrusted() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsTrusted") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -57,6 +65,10 @@ func (_m *BHS) IsTrusted() bool { func (_m *BHS) Store(ctx context.Context, blockNum uint64) error { ret := _m.Called(ctx, blockNum) + if len(ret) == 0 { + panic("no return value specified for Store") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uint64) error); ok { r0 = rf(ctx, blockNum) @@ -71,6 +83,10 @@ func (_m *BHS) Store(ctx context.Context, blockNum uint64) error { func (_m *BHS) StoreEarliest(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for StoreEarliest") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -85,6 +101,10 @@ func (_m *BHS) StoreEarliest(ctx context.Context) error { func (_m *BHS) StoreTrusted(ctx context.Context, blockNums []uint64, blockhashes []common.Hash, recentBlock uint64, recentBlockhash common.Hash) error { ret := _m.Called(ctx, blockNums, blockhashes, recentBlock, recentBlockhash) + if len(ret) == 0 { + panic("no return value specified for StoreTrusted") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []uint64, []common.Hash, uint64, common.Hash) error); ok { r0 = rf(ctx, blockNums, blockhashes, recentBlock, recentBlockhash) diff --git a/core/services/blockhashstore/mocks/timer.go b/core/services/blockhashstore/mocks/timer.go index c116163a3d..4236bdf8d9 100644 --- a/core/services/blockhashstore/mocks/timer.go +++ b/core/services/blockhashstore/mocks/timer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Timer struct { func (_m *Timer) After(d time.Duration) <-chan time.Time { ret := _m.Called(d) + if len(ret) == 0 { + panic("no return value specified for After") + } + var r0 <-chan time.Time if rf, ok := ret.Get(0).(func(time.Duration) <-chan time.Time); ok { r0 = rf(d) diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 98796e9005..1dd8587539 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -30,6 +30,10 @@ type GeneralConfig struct { func (_m *GeneralConfig) AppID() uuid.UUID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AppID") + } + var r0 uuid.UUID if rf, ok := ret.Get(0).(func() uuid.UUID); ok { r0 = rf() @@ -46,6 +50,10 @@ func (_m *GeneralConfig) AppID() uuid.UUID { func (_m *GeneralConfig) AuditLogger() config.AuditLogger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AuditLogger") + } + var r0 config.AuditLogger if rf, ok := ret.Get(0).(func() config.AuditLogger); ok { r0 = rf() @@ -62,6 +70,10 @@ func (_m *GeneralConfig) AuditLogger() config.AuditLogger { func (_m *GeneralConfig) AutoPprof() config.AutoPprof { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AutoPprof") + } + var r0 config.AutoPprof if rf, ok := ret.Get(0).(func() config.AutoPprof); ok { r0 = rf() @@ -78,6 +90,10 @@ func (_m *GeneralConfig) AutoPprof() config.AutoPprof { func (_m *GeneralConfig) ConfigTOML() (string, string) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConfigTOML") + } + var r0 string var r1 string if rf, ok := ret.Get(0).(func() (string, string)); ok { @@ -102,6 +118,10 @@ func (_m *GeneralConfig) ConfigTOML() (string, string) { func (_m *GeneralConfig) CosmosConfigs() cosmosconfig.TOMLConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CosmosConfigs") + } + var r0 cosmosconfig.TOMLConfigs if rf, ok := ret.Get(0).(func() cosmosconfig.TOMLConfigs); ok { r0 = rf() @@ -118,6 +138,10 @@ func (_m *GeneralConfig) CosmosConfigs() cosmosconfig.TOMLConfigs { func (_m *GeneralConfig) CosmosEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CosmosEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -132,6 +156,10 @@ func (_m *GeneralConfig) CosmosEnabled() bool { func (_m *GeneralConfig) Database() config.Database { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Database") + } + var r0 config.Database if rf, ok := ret.Get(0).(func() config.Database); ok { r0 = rf() @@ -148,6 +176,10 @@ func (_m *GeneralConfig) Database() config.Database { func (_m *GeneralConfig) EVMConfigs() toml.EVMConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMConfigs") + } + var r0 toml.EVMConfigs if rf, ok := ret.Get(0).(func() toml.EVMConfigs); ok { r0 = rf() @@ -164,6 +196,10 @@ func (_m *GeneralConfig) EVMConfigs() toml.EVMConfigs { func (_m *GeneralConfig) EVMEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -178,6 +214,10 @@ func (_m *GeneralConfig) EVMEnabled() bool { func (_m *GeneralConfig) EVMRPCEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMRPCEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -192,6 +232,10 @@ func (_m *GeneralConfig) EVMRPCEnabled() bool { func (_m *GeneralConfig) Feature() config.Feature { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Feature") + } + var r0 config.Feature if rf, ok := ret.Get(0).(func() config.Feature); ok { r0 = rf() @@ -208,6 +252,10 @@ func (_m *GeneralConfig) Feature() config.Feature { func (_m *GeneralConfig) FluxMonitor() config.FluxMonitor { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FluxMonitor") + } + var r0 config.FluxMonitor if rf, ok := ret.Get(0).(func() config.FluxMonitor); ok { r0 = rf() @@ -224,6 +272,10 @@ func (_m *GeneralConfig) FluxMonitor() config.FluxMonitor { func (_m *GeneralConfig) Insecure() config.Insecure { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Insecure") + } + var r0 config.Insecure if rf, ok := ret.Get(0).(func() config.Insecure); ok { r0 = rf() @@ -240,6 +292,10 @@ func (_m *GeneralConfig) Insecure() config.Insecure { func (_m *GeneralConfig) InsecureFastScrypt() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for InsecureFastScrypt") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -254,6 +310,10 @@ func (_m *GeneralConfig) InsecureFastScrypt() bool { func (_m *GeneralConfig) JobPipeline() config.JobPipeline { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobPipeline") + } + var r0 config.JobPipeline if rf, ok := ret.Get(0).(func() config.JobPipeline); ok { r0 = rf() @@ -270,6 +330,10 @@ func (_m *GeneralConfig) JobPipeline() config.JobPipeline { func (_m *GeneralConfig) Keeper() config.Keeper { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Keeper") + } + var r0 config.Keeper if rf, ok := ret.Get(0).(func() config.Keeper); ok { r0 = rf() @@ -286,6 +350,10 @@ func (_m *GeneralConfig) Keeper() config.Keeper { func (_m *GeneralConfig) Log() config.Log { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Log") + } + var r0 config.Log if rf, ok := ret.Get(0).(func() config.Log); ok { r0 = rf() @@ -307,6 +375,10 @@ func (_m *GeneralConfig) LogConfiguration(log config.LogfFn, warn config.LogfFn) func (_m *GeneralConfig) Mercury() config.Mercury { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Mercury") + } + var r0 config.Mercury if rf, ok := ret.Get(0).(func() config.Mercury); ok { r0 = rf() @@ -323,6 +395,10 @@ func (_m *GeneralConfig) Mercury() config.Mercury { func (_m *GeneralConfig) OCR() config.OCR { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR") + } + var r0 config.OCR if rf, ok := ret.Get(0).(func() config.OCR); ok { r0 = rf() @@ -339,6 +415,10 @@ func (_m *GeneralConfig) OCR() config.OCR { func (_m *GeneralConfig) OCR2() config.OCR2 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR2") + } + var r0 config.OCR2 if rf, ok := ret.Get(0).(func() config.OCR2); ok { r0 = rf() @@ -355,6 +435,10 @@ func (_m *GeneralConfig) OCR2() config.OCR2 { func (_m *GeneralConfig) P2P() config.P2P { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for P2P") + } + var r0 config.P2P if rf, ok := ret.Get(0).(func() config.P2P); ok { r0 = rf() @@ -371,6 +455,10 @@ func (_m *GeneralConfig) P2P() config.P2P { func (_m *GeneralConfig) Password() config.Password { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Password") + } + var r0 config.Password if rf, ok := ret.Get(0).(func() config.Password); ok { r0 = rf() @@ -387,6 +475,10 @@ func (_m *GeneralConfig) Password() config.Password { func (_m *GeneralConfig) Prometheus() config.Prometheus { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Prometheus") + } + var r0 config.Prometheus if rf, ok := ret.Get(0).(func() config.Prometheus); ok { r0 = rf() @@ -403,6 +495,10 @@ func (_m *GeneralConfig) Prometheus() config.Prometheus { func (_m *GeneralConfig) Pyroscope() config.Pyroscope { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Pyroscope") + } + var r0 config.Pyroscope if rf, ok := ret.Get(0).(func() config.Pyroscope); ok { r0 = rf() @@ -419,6 +515,10 @@ func (_m *GeneralConfig) Pyroscope() config.Pyroscope { func (_m *GeneralConfig) RootDir() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RootDir") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -433,6 +533,10 @@ func (_m *GeneralConfig) RootDir() string { func (_m *GeneralConfig) Sentry() config.Sentry { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Sentry") + } + var r0 config.Sentry if rf, ok := ret.Get(0).(func() config.Sentry); ok { r0 = rf() @@ -449,6 +553,10 @@ func (_m *GeneralConfig) Sentry() config.Sentry { func (_m *GeneralConfig) SetLogLevel(lvl zapcore.Level) error { ret := _m.Called(lvl) + if len(ret) == 0 { + panic("no return value specified for SetLogLevel") + } + var r0 error if rf, ok := ret.Get(0).(func(zapcore.Level) error); ok { r0 = rf(lvl) @@ -473,6 +581,10 @@ func (_m *GeneralConfig) SetPasswords(keystore *string, vrf *string) { func (_m *GeneralConfig) ShutdownGracePeriod() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ShutdownGracePeriod") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -487,6 +599,10 @@ func (_m *GeneralConfig) ShutdownGracePeriod() time.Duration { func (_m *GeneralConfig) SolanaConfigs() solana.TOMLConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SolanaConfigs") + } + var r0 solana.TOMLConfigs if rf, ok := ret.Get(0).(func() solana.TOMLConfigs); ok { r0 = rf() @@ -503,6 +619,10 @@ func (_m *GeneralConfig) SolanaConfigs() solana.TOMLConfigs { func (_m *GeneralConfig) SolanaEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SolanaEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -517,6 +637,10 @@ func (_m *GeneralConfig) SolanaEnabled() bool { func (_m *GeneralConfig) StarkNetEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StarkNetEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -531,6 +655,10 @@ func (_m *GeneralConfig) StarkNetEnabled() bool { func (_m *GeneralConfig) StarknetConfigs() chainlinkconfig.TOMLConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StarknetConfigs") + } + var r0 chainlinkconfig.TOMLConfigs if rf, ok := ret.Get(0).(func() chainlinkconfig.TOMLConfigs); ok { r0 = rf() @@ -547,6 +675,10 @@ func (_m *GeneralConfig) StarknetConfigs() chainlinkconfig.TOMLConfigs { func (_m *GeneralConfig) TelemetryIngress() config.TelemetryIngress { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TelemetryIngress") + } + var r0 config.TelemetryIngress if rf, ok := ret.Get(0).(func() config.TelemetryIngress); ok { r0 = rf() @@ -563,6 +695,10 @@ func (_m *GeneralConfig) TelemetryIngress() config.TelemetryIngress { func (_m *GeneralConfig) Threshold() config.Threshold { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Threshold") + } + var r0 config.Threshold if rf, ok := ret.Get(0).(func() config.Threshold); ok { r0 = rf() @@ -579,6 +715,10 @@ func (_m *GeneralConfig) Threshold() config.Threshold { func (_m *GeneralConfig) Tracing() config.Tracing { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Tracing") + } + var r0 config.Tracing if rf, ok := ret.Get(0).(func() config.Tracing); ok { r0 = rf() @@ -595,6 +735,10 @@ func (_m *GeneralConfig) Tracing() config.Tracing { func (_m *GeneralConfig) Validate() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Validate") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -609,6 +753,10 @@ func (_m *GeneralConfig) Validate() error { func (_m *GeneralConfig) ValidateDB() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ValidateDB") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -623,6 +771,10 @@ func (_m *GeneralConfig) ValidateDB() error { func (_m *GeneralConfig) WebServer() config.WebServer { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for WebServer") + } + var r0 config.WebServer if rf, ok := ret.Get(0).(func() config.WebServer); ok { r0 = rf() diff --git a/core/services/feeds/mocks/connections_manager.go b/core/services/feeds/mocks/connections_manager.go index e72c98a987..5bdc508710 100644 --- a/core/services/feeds/mocks/connections_manager.go +++ b/core/services/feeds/mocks/connections_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ func (_m *ConnectionsManager) Connect(opts feeds.ConnectOpts) { func (_m *ConnectionsManager) Disconnect(id int64) error { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Disconnect") + } + var r0 error if rf, ok := ret.Get(0).(func(int64) error); ok { r0 = rf(id) @@ -42,6 +46,10 @@ func (_m *ConnectionsManager) Disconnect(id int64) error { func (_m *ConnectionsManager) GetClient(id int64) (proto.FeedsManagerClient, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetClient") + } + var r0 proto.FeedsManagerClient var r1 error if rf, ok := ret.Get(0).(func(int64) (proto.FeedsManagerClient, error)); ok { @@ -68,6 +76,10 @@ func (_m *ConnectionsManager) GetClient(id int64) (proto.FeedsManagerClient, err func (_m *ConnectionsManager) IsConnected(id int64) bool { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for IsConnected") + } + var r0 bool if rf, ok := ret.Get(0).(func(int64) bool); ok { r0 = rf(id) diff --git a/core/services/feeds/mocks/feeds_manager_client.go b/core/services/feeds/mocks/feeds_manager_client.go index 9d0037ceab..f07200cc8f 100644 --- a/core/services/feeds/mocks/feeds_manager_client.go +++ b/core/services/feeds/mocks/feeds_manager_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type FeedsManagerClient struct { func (_m *FeedsManagerClient) ApprovedJob(ctx context.Context, in *proto.ApprovedJobRequest) (*proto.ApprovedJobResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for ApprovedJob") + } + var r0 *proto.ApprovedJobResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.ApprovedJobRequest) (*proto.ApprovedJobResponse, error)); ok { @@ -44,6 +48,10 @@ func (_m *FeedsManagerClient) ApprovedJob(ctx context.Context, in *proto.Approve func (_m *FeedsManagerClient) CancelledJob(ctx context.Context, in *proto.CancelledJobRequest) (*proto.CancelledJobResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for CancelledJob") + } + var r0 *proto.CancelledJobResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.CancelledJobRequest) (*proto.CancelledJobResponse, error)); ok { @@ -70,6 +78,10 @@ func (_m *FeedsManagerClient) CancelledJob(ctx context.Context, in *proto.Cancel func (_m *FeedsManagerClient) Healthcheck(ctx context.Context, in *proto.HealthcheckRequest) (*proto.HealthcheckResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for Healthcheck") + } + var r0 *proto.HealthcheckResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.HealthcheckRequest) (*proto.HealthcheckResponse, error)); ok { @@ -96,6 +108,10 @@ func (_m *FeedsManagerClient) Healthcheck(ctx context.Context, in *proto.Healthc func (_m *FeedsManagerClient) RejectedJob(ctx context.Context, in *proto.RejectedJobRequest) (*proto.RejectedJobResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for RejectedJob") + } + var r0 *proto.RejectedJobResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.RejectedJobRequest) (*proto.RejectedJobResponse, error)); ok { @@ -122,6 +138,10 @@ func (_m *FeedsManagerClient) RejectedJob(ctx context.Context, in *proto.Rejecte func (_m *FeedsManagerClient) UpdateNode(ctx context.Context, in *proto.UpdateNodeRequest) (*proto.UpdateNodeResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for UpdateNode") + } + var r0 *proto.UpdateNodeResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.UpdateNodeRequest) (*proto.UpdateNodeResponse, error)); ok { diff --git a/core/services/feeds/mocks/orm.go b/core/services/feeds/mocks/orm.go index 09326ada51..73bc4c4d4a 100644 --- a/core/services/feeds/mocks/orm.go +++ b/core/services/feeds/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -35,6 +35,10 @@ func (_m *ORM) ApproveSpec(id int64, externalJobID uuid.UUID, qopts ...pg.QOpt) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ApproveSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, uuid.UUID, ...pg.QOpt) error); ok { r0 = rf(id, externalJobID, qopts...) @@ -93,6 +97,10 @@ func (_m *ORM) CancelSpec(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CancelSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -143,6 +151,10 @@ func (_c *ORM_CancelSpec_Call) RunAndReturn(run func(int64, ...pg.QOpt) error) * func (_m *ORM) CountJobProposals() (int64, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountJobProposals") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func() (int64, error)); ok { @@ -194,6 +206,10 @@ func (_c *ORM_CountJobProposals_Call) RunAndReturn(run func() (int64, error)) *O func (_m *ORM) CountJobProposalsByStatus() (*feeds.JobProposalCounts, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountJobProposalsByStatus") + } + var r0 *feeds.JobProposalCounts var r1 error if rf, ok := ret.Get(0).(func() (*feeds.JobProposalCounts, error)); ok { @@ -247,6 +263,10 @@ func (_c *ORM_CountJobProposalsByStatus_Call) RunAndReturn(run func() (*feeds.Jo func (_m *ORM) CountManagers() (int64, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountManagers") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func() (int64, error)); ok { @@ -305,6 +325,10 @@ func (_m *ORM) CreateBatchChainConfig(cfgs []feeds.ChainConfig, qopts ...pg.QOpt _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateBatchChainConfig") + } + var r0 []int64 var r1 error if rf, ok := ret.Get(0).(func([]feeds.ChainConfig, ...pg.QOpt) ([]int64, error)); ok { @@ -374,6 +398,10 @@ func (_m *ORM) CreateChainConfig(cfg feeds.ChainConfig, qopts ...pg.QOpt) (int64 _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(feeds.ChainConfig, ...pg.QOpt) (int64, error)); ok { @@ -434,6 +462,10 @@ func (_c *ORM_CreateChainConfig_Call) RunAndReturn(run func(feeds.ChainConfig, . func (_m *ORM) CreateJobProposal(jp *feeds.JobProposal) (int64, error) { ret := _m.Called(jp) + if len(ret) == 0 { + panic("no return value specified for CreateJobProposal") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(*feeds.JobProposal) (int64, error)); ok { @@ -493,6 +525,10 @@ func (_m *ORM) CreateManager(ms *feeds.FeedsManager, qopts ...pg.QOpt) (int64, e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateManager") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(*feeds.FeedsManager, ...pg.QOpt) (int64, error)); ok { @@ -560,6 +596,10 @@ func (_m *ORM) CreateSpec(spec feeds.JobProposalSpec, qopts ...pg.QOpt) (int64, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateSpec") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(feeds.JobProposalSpec, ...pg.QOpt) (int64, error)); ok { @@ -620,6 +660,10 @@ func (_c *ORM_CreateSpec_Call) RunAndReturn(run func(feeds.JobProposalSpec, ...p func (_m *ORM) DeleteChainConfig(id int64) (int64, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for DeleteChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(int64) (int64, error)); ok { @@ -679,6 +723,10 @@ func (_m *ORM) DeleteProposal(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteProposal") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -736,6 +784,10 @@ func (_m *ORM) ExistsSpecByJobProposalIDAndVersion(jpID int64, version int32, qo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ExistsSpecByJobProposalIDAndVersion") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(int64, int32, ...pg.QOpt) (bool, error)); ok { @@ -804,6 +856,10 @@ func (_m *ORM) GetApprovedSpec(jpID int64, qopts ...pg.QOpt) (*feeds.JobProposal _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetApprovedSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (*feeds.JobProposalSpec, error)); ok { @@ -866,6 +922,10 @@ func (_c *ORM_GetApprovedSpec_Call) RunAndReturn(run func(int64, ...pg.QOpt) (*f func (_m *ORM) GetChainConfig(id int64) (*feeds.ChainConfig, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetChainConfig") + } + var r0 *feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.ChainConfig, error)); ok { @@ -927,6 +987,10 @@ func (_m *ORM) GetJobProposal(id int64, qopts ...pg.QOpt) (*feeds.JobProposal, e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetJobProposal") + } + var r0 *feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (*feeds.JobProposal, error)); ok { @@ -989,6 +1053,10 @@ func (_c *ORM_GetJobProposal_Call) RunAndReturn(run func(int64, ...pg.QOpt) (*fe func (_m *ORM) GetJobProposalByRemoteUUID(_a0 uuid.UUID) (*feeds.JobProposal, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetJobProposalByRemoteUUID") + } + var r0 *feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func(uuid.UUID) (*feeds.JobProposal, error)); ok { @@ -1043,6 +1111,10 @@ func (_c *ORM_GetJobProposalByRemoteUUID_Call) RunAndReturn(run func(uuid.UUID) func (_m *ORM) GetLatestSpec(jpID int64) (*feeds.JobProposalSpec, error) { ret := _m.Called(jpID) + if len(ret) == 0 { + panic("no return value specified for GetLatestSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.JobProposalSpec, error)); ok { @@ -1097,6 +1169,10 @@ func (_c *ORM_GetLatestSpec_Call) RunAndReturn(run func(int64) (*feeds.JobPropos func (_m *ORM) GetManager(id int64) (*feeds.FeedsManager, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetManager") + } + var r0 *feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.FeedsManager, error)); ok { @@ -1158,6 +1234,10 @@ func (_m *ORM) GetSpec(id int64, qopts ...pg.QOpt) (*feeds.JobProposalSpec, erro _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (*feeds.JobProposalSpec, error)); ok { @@ -1227,6 +1307,10 @@ func (_m *ORM) IsJobManaged(jobID int64, qopts ...pg.QOpt) (bool, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IsJobManaged") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (bool, error)); ok { @@ -1287,6 +1371,10 @@ func (_c *ORM_IsJobManaged_Call) RunAndReturn(run func(int64, ...pg.QOpt) (bool, func (_m *ORM) ListChainConfigsByManagerIDs(mgrIDs []int64) ([]feeds.ChainConfig, error) { ret := _m.Called(mgrIDs) + if len(ret) == 0 { + panic("no return value specified for ListChainConfigsByManagerIDs") + } + var r0 []feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.ChainConfig, error)); ok { @@ -1341,6 +1429,10 @@ func (_c *ORM_ListChainConfigsByManagerIDs_Call) RunAndReturn(run func([]int64) func (_m *ORM) ListJobProposals() ([]feeds.JobProposal, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListJobProposals") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.JobProposal, error)); ok { @@ -1401,6 +1493,10 @@ func (_m *ORM) ListJobProposalsByManagersIDs(ids []int64, qopts ...pg.QOpt) ([]f _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ListJobProposalsByManagersIDs") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func([]int64, ...pg.QOpt) ([]feeds.JobProposal, error)); ok { @@ -1463,6 +1559,10 @@ func (_c *ORM_ListJobProposalsByManagersIDs_Call) RunAndReturn(run func([]int64, func (_m *ORM) ListManagers() ([]feeds.FeedsManager, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListManagers") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.FeedsManager, error)); ok { @@ -1516,6 +1616,10 @@ func (_c *ORM_ListManagers_Call) RunAndReturn(run func() ([]feeds.FeedsManager, func (_m *ORM) ListManagersByIDs(ids []int64) ([]feeds.FeedsManager, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListManagersByIDs") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.FeedsManager, error)); ok { @@ -1577,6 +1681,10 @@ func (_m *ORM) ListSpecsByJobProposalIDs(ids []int64, qopts ...pg.QOpt) ([]feeds _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ListSpecsByJobProposalIDs") + } + var r0 []feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func([]int64, ...pg.QOpt) ([]feeds.JobProposalSpec, error)); ok { @@ -1646,6 +1754,10 @@ func (_m *ORM) RejectSpec(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RejectSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -1703,6 +1815,10 @@ func (_m *ORM) RevokeSpec(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RevokeSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -1753,6 +1869,10 @@ func (_c *ORM_RevokeSpec_Call) RunAndReturn(run func(int64, ...pg.QOpt) error) * func (_m *ORM) UpdateChainConfig(cfg feeds.ChainConfig) (int64, error) { ret := _m.Called(cfg) + if len(ret) == 0 { + panic("no return value specified for UpdateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(feeds.ChainConfig) (int64, error)); ok { @@ -1812,6 +1932,10 @@ func (_m *ORM) UpdateJobProposalStatus(id int64, status feeds.JobProposalStatus, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpdateJobProposalStatus") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, feeds.JobProposalStatus, ...pg.QOpt) error); ok { r0 = rf(id, status, qopts...) @@ -1870,6 +1994,10 @@ func (_m *ORM) UpdateManager(mgr feeds.FeedsManager, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpdateManager") + } + var r0 error if rf, ok := ret.Get(0).(func(feeds.FeedsManager, ...pg.QOpt) error); ok { r0 = rf(mgr, qopts...) @@ -1927,6 +2055,10 @@ func (_m *ORM) UpdateSpecDefinition(id int64, spec string, qopts ...pg.QOpt) err _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpdateSpecDefinition") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, string, ...pg.QOpt) error); ok { r0 = rf(id, spec, qopts...) @@ -1985,6 +2117,10 @@ func (_m *ORM) UpsertJobProposal(jp *feeds.JobProposal, qopts ...pg.QOpt) (int64 _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpsertJobProposal") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(*feeds.JobProposal, ...pg.QOpt) (int64, error)); ok { diff --git a/core/services/feeds/mocks/service.go b/core/services/feeds/mocks/service.go index 1681918bb7..d8bc88c815 100644 --- a/core/services/feeds/mocks/service.go +++ b/core/services/feeds/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type Service struct { func (_m *Service) ApproveSpec(ctx context.Context, id int64, force bool) error { ret := _m.Called(ctx, id, force) + if len(ret) == 0 { + panic("no return value specified for ApproveSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, bool) error); ok { r0 = rf(ctx, id, force) @@ -32,6 +36,10 @@ func (_m *Service) ApproveSpec(ctx context.Context, id int64, force bool) error func (_m *Service) CancelSpec(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for CancelSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -46,6 +54,10 @@ func (_m *Service) CancelSpec(ctx context.Context, id int64) error { func (_m *Service) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -60,6 +72,10 @@ func (_m *Service) Close() error { func (_m *Service) CountJobProposalsByStatus() (*feeds.JobProposalCounts, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountJobProposalsByStatus") + } + var r0 *feeds.JobProposalCounts var r1 error if rf, ok := ret.Get(0).(func() (*feeds.JobProposalCounts, error)); ok { @@ -86,6 +102,10 @@ func (_m *Service) CountJobProposalsByStatus() (*feeds.JobProposalCounts, error) func (_m *Service) CountManagers() (int64, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountManagers") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func() (int64, error)); ok { @@ -110,6 +130,10 @@ func (_m *Service) CountManagers() (int64, error) { func (_m *Service) CreateChainConfig(ctx context.Context, cfg feeds.ChainConfig) (int64, error) { ret := _m.Called(ctx, cfg) + if len(ret) == 0 { + panic("no return value specified for CreateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, feeds.ChainConfig) (int64, error)); ok { @@ -134,6 +158,10 @@ func (_m *Service) CreateChainConfig(ctx context.Context, cfg feeds.ChainConfig) func (_m *Service) DeleteChainConfig(ctx context.Context, id int64) (int64, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for DeleteChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok { @@ -158,6 +186,10 @@ func (_m *Service) DeleteChainConfig(ctx context.Context, id int64) (int64, erro func (_m *Service) DeleteJob(ctx context.Context, args *feeds.DeleteJobArgs) (int64, error) { ret := _m.Called(ctx, args) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, *feeds.DeleteJobArgs) (int64, error)); ok { @@ -182,6 +214,10 @@ func (_m *Service) DeleteJob(ctx context.Context, args *feeds.DeleteJobArgs) (in func (_m *Service) GetChainConfig(id int64) (*feeds.ChainConfig, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetChainConfig") + } + var r0 *feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.ChainConfig, error)); ok { @@ -208,6 +244,10 @@ func (_m *Service) GetChainConfig(id int64) (*feeds.ChainConfig, error) { func (_m *Service) GetJobProposal(id int64) (*feeds.JobProposal, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetJobProposal") + } + var r0 *feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.JobProposal, error)); ok { @@ -234,6 +274,10 @@ func (_m *Service) GetJobProposal(id int64) (*feeds.JobProposal, error) { func (_m *Service) GetManager(id int64) (*feeds.FeedsManager, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetManager") + } + var r0 *feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.FeedsManager, error)); ok { @@ -260,6 +304,10 @@ func (_m *Service) GetManager(id int64) (*feeds.FeedsManager, error) { func (_m *Service) GetSpec(id int64) (*feeds.JobProposalSpec, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.JobProposalSpec, error)); ok { @@ -286,6 +334,10 @@ func (_m *Service) GetSpec(id int64) (*feeds.JobProposalSpec, error) { func (_m *Service) IsJobManaged(ctx context.Context, jobID int64) (bool, error) { ret := _m.Called(ctx, jobID) + if len(ret) == 0 { + panic("no return value specified for IsJobManaged") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64) (bool, error)); ok { @@ -310,6 +362,10 @@ func (_m *Service) IsJobManaged(ctx context.Context, jobID int64) (bool, error) func (_m *Service) ListChainConfigsByManagerIDs(mgrIDs []int64) ([]feeds.ChainConfig, error) { ret := _m.Called(mgrIDs) + if len(ret) == 0 { + panic("no return value specified for ListChainConfigsByManagerIDs") + } + var r0 []feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.ChainConfig, error)); ok { @@ -336,6 +392,10 @@ func (_m *Service) ListChainConfigsByManagerIDs(mgrIDs []int64) ([]feeds.ChainCo func (_m *Service) ListJobProposals() ([]feeds.JobProposal, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListJobProposals") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.JobProposal, error)); ok { @@ -362,6 +422,10 @@ func (_m *Service) ListJobProposals() ([]feeds.JobProposal, error) { func (_m *Service) ListJobProposalsByManagersIDs(ids []int64) ([]feeds.JobProposal, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListJobProposalsByManagersIDs") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.JobProposal, error)); ok { @@ -388,6 +452,10 @@ func (_m *Service) ListJobProposalsByManagersIDs(ids []int64) ([]feeds.JobPropos func (_m *Service) ListManagers() ([]feeds.FeedsManager, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListManagers") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.FeedsManager, error)); ok { @@ -414,6 +482,10 @@ func (_m *Service) ListManagers() ([]feeds.FeedsManager, error) { func (_m *Service) ListManagersByIDs(ids []int64) ([]feeds.FeedsManager, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListManagersByIDs") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.FeedsManager, error)); ok { @@ -440,6 +512,10 @@ func (_m *Service) ListManagersByIDs(ids []int64) ([]feeds.FeedsManager, error) func (_m *Service) ListSpecsByJobProposalIDs(ids []int64) ([]feeds.JobProposalSpec, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListSpecsByJobProposalIDs") + } + var r0 []feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.JobProposalSpec, error)); ok { @@ -466,6 +542,10 @@ func (_m *Service) ListSpecsByJobProposalIDs(ids []int64) ([]feeds.JobProposalSp func (_m *Service) ProposeJob(ctx context.Context, args *feeds.ProposeJobArgs) (int64, error) { ret := _m.Called(ctx, args) + if len(ret) == 0 { + panic("no return value specified for ProposeJob") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, *feeds.ProposeJobArgs) (int64, error)); ok { @@ -490,6 +570,10 @@ func (_m *Service) ProposeJob(ctx context.Context, args *feeds.ProposeJobArgs) ( func (_m *Service) RegisterManager(ctx context.Context, params feeds.RegisterManagerParams) (int64, error) { ret := _m.Called(ctx, params) + if len(ret) == 0 { + panic("no return value specified for RegisterManager") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, feeds.RegisterManagerParams) (int64, error)); ok { @@ -514,6 +598,10 @@ func (_m *Service) RegisterManager(ctx context.Context, params feeds.RegisterMan func (_m *Service) RejectSpec(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for RejectSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -528,6 +616,10 @@ func (_m *Service) RejectSpec(ctx context.Context, id int64) error { func (_m *Service) RevokeJob(ctx context.Context, args *feeds.RevokeJobArgs) (int64, error) { ret := _m.Called(ctx, args) + if len(ret) == 0 { + panic("no return value specified for RevokeJob") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, *feeds.RevokeJobArgs) (int64, error)); ok { @@ -552,6 +644,10 @@ func (_m *Service) RevokeJob(ctx context.Context, args *feeds.RevokeJobArgs) (in func (_m *Service) Start(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -566,6 +662,10 @@ func (_m *Service) Start(ctx context.Context) error { func (_m *Service) SyncNodeInfo(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for SyncNodeInfo") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -585,6 +685,10 @@ func (_m *Service) Unsafe_SetConnectionsManager(_a0 feeds.ConnectionsManager) { func (_m *Service) UpdateChainConfig(ctx context.Context, cfg feeds.ChainConfig) (int64, error) { ret := _m.Called(ctx, cfg) + if len(ret) == 0 { + panic("no return value specified for UpdateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, feeds.ChainConfig) (int64, error)); ok { @@ -609,6 +713,10 @@ func (_m *Service) UpdateChainConfig(ctx context.Context, cfg feeds.ChainConfig) func (_m *Service) UpdateManager(ctx context.Context, mgr feeds.FeedsManager) error { ret := _m.Called(ctx, mgr) + if len(ret) == 0 { + panic("no return value specified for UpdateManager") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, feeds.FeedsManager) error); ok { r0 = rf(ctx, mgr) @@ -623,6 +731,10 @@ func (_m *Service) UpdateManager(ctx context.Context, mgr feeds.FeedsManager) er func (_m *Service) UpdateSpecDefinition(ctx context.Context, id int64, spec string) error { ret := _m.Called(ctx, id, spec) + if len(ret) == 0 { + panic("no return value specified for UpdateSpecDefinition") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { r0 = rf(ctx, id, spec) diff --git a/core/services/fluxmonitorv2/mocks/contract_submitter.go b/core/services/fluxmonitorv2/mocks/contract_submitter.go index 03540a6cb1..3154b4c86e 100644 --- a/core/services/fluxmonitorv2/mocks/contract_submitter.go +++ b/core/services/fluxmonitorv2/mocks/contract_submitter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type ContractSubmitter struct { func (_m *ContractSubmitter) Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error { ret := _m.Called(ctx, roundID, submission, idempotencyKey) + if len(ret) == 0 { + panic("no return value specified for Submit") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int, *big.Int, *string) error); ok { r0 = rf(ctx, roundID, submission, idempotencyKey) diff --git a/core/services/fluxmonitorv2/mocks/flags.go b/core/services/fluxmonitorv2/mocks/flags.go index 08ad0f5b3f..6ff1616111 100644 --- a/core/services/fluxmonitorv2/mocks/flags.go +++ b/core/services/fluxmonitorv2/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Flags struct { func (_m *Flags) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *Flags) Address() common.Address { func (_m *Flags) ContractExists() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ContractExists") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *Flags) ContractExists() bool { func (_m *Flags) IsLowered(contractAddr common.Address) (bool, error) { ret := _m.Called(contractAddr) + if len(ret) == 0 { + panic("no return value specified for IsLowered") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(common.Address) (bool, error)); ok { @@ -75,6 +87,10 @@ func (_m *Flags) IsLowered(contractAddr common.Address) (bool, error) { func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/services/fluxmonitorv2/mocks/key_store_interface.go b/core/services/fluxmonitorv2/mocks/key_store_interface.go index c409a987e0..98f5ab7102 100644 --- a/core/services/fluxmonitorv2/mocks/key_store_interface.go +++ b/core/services/fluxmonitorv2/mocks/key_store_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type KeyStoreInterface struct { func (_m *KeyStoreInterface) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for EnabledKeysForChain") + } + var r0 []ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.KeyV2, error)); ok { @@ -53,6 +57,10 @@ func (_m *KeyStoreInterface) GetRoundRobinAddress(chainID *big.Int, addrs ...com _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetRoundRobinAddress") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) (common.Address, error)); ok { diff --git a/core/services/fluxmonitorv2/mocks/orm.go b/core/services/fluxmonitorv2/mocks/orm.go index 5080f19edf..8d277d61d2 100644 --- a/core/services/fluxmonitorv2/mocks/orm.go +++ b/core/services/fluxmonitorv2/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ type ORM struct { func (_m *ORM) CountFluxMonitorRoundStats() (int, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountFluxMonitorRoundStats") + } + var r0 int var r1 error if rf, ok := ret.Get(0).(func() (int, error)); ok { @@ -47,6 +51,10 @@ func (_m *ORM) CountFluxMonitorRoundStats() (int, error) { func (_m *ORM) CreateEthTransaction(ctx context.Context, fromAddress common.Address, toAddress common.Address, payload []byte, gasLimit uint32, idempotencyKey *string) error { ret := _m.Called(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) + if len(ret) == 0 { + panic("no return value specified for CreateEthTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address, []byte, uint32, *string) error); ok { r0 = rf(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) @@ -61,6 +69,10 @@ func (_m *ORM) CreateEthTransaction(ctx context.Context, fromAddress common.Addr func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, roundID uint32) error { ret := _m.Called(aggregator, roundID) + if len(ret) == 0 { + panic("no return value specified for DeleteFluxMonitorRoundsBackThrough") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, uint32) error); ok { r0 = rf(aggregator, roundID) @@ -75,6 +87,10 @@ func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, rou func (_m *ORM) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, newRoundLogs uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error) { ret := _m.Called(aggregator, roundID, newRoundLogs) + if len(ret) == 0 { + panic("no return value specified for FindOrCreateFluxMonitorRoundStats") + } + var r0 fluxmonitorv2.FluxMonitorRoundStatsV2 var r1 error if rf, ok := ret.Get(0).(func(common.Address, uint32, uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error)); ok { @@ -99,6 +115,10 @@ func (_m *ORM) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roun func (_m *ORM) MostRecentFluxMonitorRoundID(aggregator common.Address) (uint32, error) { ret := _m.Called(aggregator) + if len(ret) == 0 { + panic("no return value specified for MostRecentFluxMonitorRoundID") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(common.Address) (uint32, error)); ok { @@ -130,6 +150,10 @@ func (_m *ORM) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID ui _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpdateFluxMonitorRoundStats") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, uint32, int64, uint, ...pg.QOpt) error); ok { r0 = rf(aggregator, roundID, runID, newRoundLogsAddition, qopts...) diff --git a/core/services/functions/mocks/bridge_accessor.go b/core/services/functions/mocks/bridge_accessor.go index 65e81ab8b8..fa765287c4 100644 --- a/core/services/functions/mocks/bridge_accessor.go +++ b/core/services/functions/mocks/bridge_accessor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type BridgeAccessor struct { func (_m *BridgeAccessor) NewExternalAdapterClient() (functions.ExternalAdapterClient, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for NewExternalAdapterClient") + } + var r0 functions.ExternalAdapterClient var r1 error if rf, ok := ret.Get(0).(func() (functions.ExternalAdapterClient, error)); ok { diff --git a/core/services/functions/mocks/external_adapter_client.go b/core/services/functions/mocks/external_adapter_client.go index b06f13fdea..dbf4081c95 100644 --- a/core/services/functions/mocks/external_adapter_client.go +++ b/core/services/functions/mocks/external_adapter_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type ExternalAdapterClient struct { func (_m *ExternalAdapterClient) FetchEncryptedSecrets(ctx context.Context, encryptedSecretsUrls []byte, requestId string, jobName string) ([]byte, []byte, error) { ret := _m.Called(ctx, encryptedSecretsUrls, requestId, jobName) + if len(ret) == 0 { + panic("no return value specified for FetchEncryptedSecrets") + } + var r0 []byte var r1 []byte var r2 error @@ -53,6 +57,10 @@ func (_m *ExternalAdapterClient) FetchEncryptedSecrets(ctx context.Context, encr func (_m *ExternalAdapterClient) RunComputation(ctx context.Context, requestId string, jobName string, subscriptionOwner string, subscriptionId uint64, flags functions.RequestFlags, nodeProvidedSecrets string, requestData *functions.RequestData) ([]byte, []byte, []string, error) { ret := _m.Called(ctx, requestId, jobName, subscriptionOwner, subscriptionId, flags, nodeProvidedSecrets, requestData) + if len(ret) == 0 { + panic("no return value specified for RunComputation") + } + var r0 []byte var r1 []byte var r2 []string diff --git a/core/services/functions/mocks/functions_listener.go b/core/services/functions/mocks/functions_listener.go index d2aeb2ddab..d63248f00c 100644 --- a/core/services/functions/mocks/functions_listener.go +++ b/core/services/functions/mocks/functions_listener.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type FunctionsListener struct { func (_m *FunctionsListener) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *FunctionsListener) Close() error { func (_m *FunctionsListener) HandleOffchainRequest(ctx context.Context, request *functions.OffchainRequest) error { ret := _m.Called(ctx, request) + if len(ret) == 0 { + panic("no return value specified for HandleOffchainRequest") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *functions.OffchainRequest) error); ok { r0 = rf(ctx, request) @@ -46,6 +54,10 @@ func (_m *FunctionsListener) HandleOffchainRequest(ctx context.Context, request func (_m *FunctionsListener) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/functions/mocks/offchain_transmitter.go b/core/services/functions/mocks/offchain_transmitter.go index d9a7be04dd..5eee967e68 100644 --- a/core/services/functions/mocks/offchain_transmitter.go +++ b/core/services/functions/mocks/offchain_transmitter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type OffchainTransmitter struct { func (_m *OffchainTransmitter) ReportChannel() chan *functions.OffchainResponse { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReportChannel") + } + var r0 chan *functions.OffchainResponse if rf, ok := ret.Get(0).(func() chan *functions.OffchainResponse); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *OffchainTransmitter) ReportChannel() chan *functions.OffchainResponse func (_m *OffchainTransmitter) TransmitReport(ctx context.Context, report *functions.OffchainResponse) error { ret := _m.Called(ctx, report) + if len(ret) == 0 { + panic("no return value specified for TransmitReport") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *functions.OffchainResponse) error); ok { r0 = rf(ctx, report) diff --git a/core/services/functions/mocks/orm.go b/core/services/functions/mocks/orm.go index 8d11b0b981..90055fe628 100644 --- a/core/services/functions/mocks/orm.go +++ b/core/services/functions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *ORM) CreateRequest(request *functions.Request, qopts ...pg.QOpt) error _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateRequest") + } + var r0 error if rf, ok := ret.Get(0).(func(*functions.Request, ...pg.QOpt) error); ok { r0 = rf(request, qopts...) @@ -48,6 +52,10 @@ func (_m *ORM) FindById(requestID functions.RequestID, qopts ...pg.QOpt) (*funct _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindById") + } + var r0 *functions.Request var r1 error if rf, ok := ret.Get(0).(func(functions.RequestID, ...pg.QOpt) (*functions.Request, error)); ok { @@ -81,6 +89,10 @@ func (_m *ORM) FindOldestEntriesByState(state functions.RequestState, limit uint _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindOldestEntriesByState") + } + var r0 []functions.Request var r1 error if rf, ok := ret.Get(0).(func(functions.RequestState, uint32, ...pg.QOpt) ([]functions.Request, error)); ok { @@ -114,6 +126,10 @@ func (_m *ORM) PruneOldestRequests(maxRequestsInDB uint32, batchSize uint32, qop _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for PruneOldestRequests") + } + var r0 uint32 var r1 uint32 var r2 error @@ -152,6 +168,10 @@ func (_m *ORM) SetConfirmed(requestID functions.RequestID, qopts ...pg.QOpt) err _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetConfirmed") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, ...pg.QOpt) error); ok { r0 = rf(requestID, qopts...) @@ -173,6 +193,10 @@ func (_m *ORM) SetError(requestID functions.RequestID, errorType functions.ErrTy _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetError") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, functions.ErrType, []byte, time.Time, bool, ...pg.QOpt) error); ok { r0 = rf(requestID, errorType, computationError, readyAt, readyForProcessing, qopts...) @@ -194,6 +218,10 @@ func (_m *ORM) SetFinalized(requestID functions.RequestID, reportedResult []byte _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetFinalized") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, []byte, []byte, ...pg.QOpt) error); ok { r0 = rf(requestID, reportedResult, reportedError, qopts...) @@ -215,6 +243,10 @@ func (_m *ORM) SetResult(requestID functions.RequestID, computationResult []byte _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetResult") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, []byte, time.Time, ...pg.QOpt) error); ok { r0 = rf(requestID, computationResult, readyAt, qopts...) @@ -236,6 +268,10 @@ func (_m *ORM) TimeoutExpiredResults(cutoff time.Time, limit uint32, qopts ...pg _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for TimeoutExpiredResults") + } + var r0 []functions.RequestID var r1 error if rf, ok := ret.Get(0).(func(time.Time, uint32, ...pg.QOpt) ([]functions.RequestID, error)); ok { diff --git a/core/services/gateway/connector/mocks/gateway_connector.go b/core/services/gateway/connector/mocks/gateway_connector.go index a9fa69e1e3..ba972425f6 100644 --- a/core/services/gateway/connector/mocks/gateway_connector.go +++ b/core/services/gateway/connector/mocks/gateway_connector.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type GatewayConnector struct { func (_m *GatewayConnector) ChallengeResponse(_a0 *url.URL, challenge []byte) ([]byte, error) { ret := _m.Called(_a0, challenge) + if len(ret) == 0 { + panic("no return value specified for ChallengeResponse") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL, []byte) ([]byte, error)); ok { @@ -47,6 +51,10 @@ func (_m *GatewayConnector) ChallengeResponse(_a0 *url.URL, challenge []byte) ([ func (_m *GatewayConnector) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -61,6 +69,10 @@ func (_m *GatewayConnector) Close() error { func (_m *GatewayConnector) NewAuthHeader(_a0 *url.URL) ([]byte, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for NewAuthHeader") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL) ([]byte, error)); ok { @@ -87,6 +99,10 @@ func (_m *GatewayConnector) NewAuthHeader(_a0 *url.URL) ([]byte, error) { func (_m *GatewayConnector) SendToGateway(ctx context.Context, gatewayId string, msg *api.Message) error { ret := _m.Called(ctx, gatewayId, msg) + if len(ret) == 0 { + panic("no return value specified for SendToGateway") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *api.Message) error); ok { r0 = rf(ctx, gatewayId, msg) @@ -101,6 +117,10 @@ func (_m *GatewayConnector) SendToGateway(ctx context.Context, gatewayId string, func (_m *GatewayConnector) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/connector/mocks/gateway_connector_handler.go b/core/services/gateway/connector/mocks/gateway_connector_handler.go index 8eb27708a5..e83e06b60e 100644 --- a/core/services/gateway/connector/mocks/gateway_connector_handler.go +++ b/core/services/gateway/connector/mocks/gateway_connector_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type GatewayConnectorHandler struct { func (_m *GatewayConnectorHandler) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *GatewayConnectorHandler) HandleGatewayMessage(ctx context.Context, gat func (_m *GatewayConnectorHandler) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/connector/mocks/signer.go b/core/services/gateway/connector/mocks/signer.go index 497b25d8df..18c7186f7f 100644 --- a/core/services/gateway/connector/mocks/signer.go +++ b/core/services/gateway/connector/mocks/signer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ func (_m *Signer) Sign(data ...[]byte) ([]byte, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Sign") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(...[]byte) ([]byte, error)); ok { diff --git a/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go b/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go index 8cbf301f0e..6668a3c76f 100644 --- a/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go +++ b/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type OnchainAllowlist struct { func (_m *OnchainAllowlist) Allow(_a0 common.Address) bool { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Allow") + } + var r0 bool if rf, ok := ret.Get(0).(func(common.Address) bool); ok { r0 = rf(_a0) @@ -33,6 +37,10 @@ func (_m *OnchainAllowlist) Allow(_a0 common.Address) bool { func (_m *OnchainAllowlist) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -47,6 +55,10 @@ func (_m *OnchainAllowlist) Close() error { func (_m *OnchainAllowlist) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -61,6 +73,10 @@ func (_m *OnchainAllowlist) Start(_a0 context.Context) error { func (_m *OnchainAllowlist) UpdateFromContract(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for UpdateFromContract") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) diff --git a/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go b/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go index 64e2960f94..5f2054c4e4 100644 --- a/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go +++ b/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type OnchainSubscriptions struct { func (_m *OnchainSubscriptions) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *OnchainSubscriptions) Close() error { func (_m *OnchainSubscriptions) GetMaxUserBalance(_a0 common.Address) (*big.Int, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetMaxUserBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(common.Address) (*big.Int, error)); ok { @@ -60,6 +68,10 @@ func (_m *OnchainSubscriptions) GetMaxUserBalance(_a0 common.Address) (*big.Int, func (_m *OnchainSubscriptions) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/handlers/mocks/don.go b/core/services/gateway/handlers/mocks/don.go index 02df7c0334..6e88708dd7 100644 --- a/core/services/gateway/handlers/mocks/don.go +++ b/core/services/gateway/handlers/mocks/don.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type DON struct { func (_m *DON) SendToNode(ctx context.Context, nodeAddress string, msg *api.Message) error { ret := _m.Called(ctx, nodeAddress, msg) + if len(ret) == 0 { + panic("no return value specified for SendToNode") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *api.Message) error); ok { r0 = rf(ctx, nodeAddress, msg) diff --git a/core/services/gateway/handlers/mocks/handler.go b/core/services/gateway/handlers/mocks/handler.go index 10a31c6d76..7dfe1eae78 100644 --- a/core/services/gateway/handlers/mocks/handler.go +++ b/core/services/gateway/handlers/mocks/handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Handler struct { func (_m *Handler) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -35,6 +39,10 @@ func (_m *Handler) Close() error { func (_m *Handler) HandleNodeMessage(ctx context.Context, msg *api.Message, nodeAddr string) error { ret := _m.Called(ctx, msg, nodeAddr) + if len(ret) == 0 { + panic("no return value specified for HandleNodeMessage") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *api.Message, string) error); ok { r0 = rf(ctx, msg, nodeAddr) @@ -49,6 +57,10 @@ func (_m *Handler) HandleNodeMessage(ctx context.Context, msg *api.Message, node func (_m *Handler) HandleUserMessage(ctx context.Context, msg *api.Message, callbackCh chan<- handlers.UserCallbackPayload) error { ret := _m.Called(ctx, msg, callbackCh) + if len(ret) == 0 { + panic("no return value specified for HandleUserMessage") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *api.Message, chan<- handlers.UserCallbackPayload) error); ok { r0 = rf(ctx, msg, callbackCh) @@ -63,6 +75,10 @@ func (_m *Handler) HandleUserMessage(ctx context.Context, msg *api.Message, call func (_m *Handler) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/network/mocks/connection_acceptor.go b/core/services/gateway/network/mocks/connection_acceptor.go index 738904984a..c45cc7fbe3 100644 --- a/core/services/gateway/network/mocks/connection_acceptor.go +++ b/core/services/gateway/network/mocks/connection_acceptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -22,6 +22,10 @@ func (_m *ConnectionAcceptor) AbortHandshake(attemptId string) { func (_m *ConnectionAcceptor) FinalizeHandshake(attemptId string, response []byte, conn *websocket.Conn) error { ret := _m.Called(attemptId, response, conn) + if len(ret) == 0 { + panic("no return value specified for FinalizeHandshake") + } + var r0 error if rf, ok := ret.Get(0).(func(string, []byte, *websocket.Conn) error); ok { r0 = rf(attemptId, response, conn) @@ -36,6 +40,10 @@ func (_m *ConnectionAcceptor) FinalizeHandshake(attemptId string, response []byt func (_m *ConnectionAcceptor) StartHandshake(authHeader []byte) (string, []byte, error) { ret := _m.Called(authHeader) + if len(ret) == 0 { + panic("no return value specified for StartHandshake") + } + var r0 string var r1 []byte var r2 error diff --git a/core/services/gateway/network/mocks/connection_initiator.go b/core/services/gateway/network/mocks/connection_initiator.go index 3ff60e6139..87e4f40732 100644 --- a/core/services/gateway/network/mocks/connection_initiator.go +++ b/core/services/gateway/network/mocks/connection_initiator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type ConnectionInitiator struct { func (_m *ConnectionInitiator) ChallengeResponse(_a0 *url.URL, challenge []byte) ([]byte, error) { ret := _m.Called(_a0, challenge) + if len(ret) == 0 { + panic("no return value specified for ChallengeResponse") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL, []byte) ([]byte, error)); ok { @@ -43,6 +47,10 @@ func (_m *ConnectionInitiator) ChallengeResponse(_a0 *url.URL, challenge []byte) func (_m *ConnectionInitiator) NewAuthHeader(_a0 *url.URL) ([]byte, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for NewAuthHeader") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL) ([]byte, error)); ok { diff --git a/core/services/gateway/network/mocks/http_request_handler.go b/core/services/gateway/network/mocks/http_request_handler.go index 7716626ac7..7c5ff4025c 100644 --- a/core/services/gateway/network/mocks/http_request_handler.go +++ b/core/services/gateway/network/mocks/http_request_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type HTTPRequestHandler struct { func (_m *HTTPRequestHandler) ProcessRequest(ctx context.Context, rawRequest []byte) ([]byte, int) { ret := _m.Called(ctx, rawRequest) + if len(ret) == 0 { + panic("no return value specified for ProcessRequest") + } + var r0 []byte var r1 int if rf, ok := ret.Get(0).(func(context.Context, []byte) ([]byte, int)); ok { diff --git a/core/services/gateway/network/mocks/http_server.go b/core/services/gateway/network/mocks/http_server.go index 197e77f1b8..81e180e7b8 100644 --- a/core/services/gateway/network/mocks/http_server.go +++ b/core/services/gateway/network/mocks/http_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type HttpServer struct { func (_m *HttpServer) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *HttpServer) Close() error { func (_m *HttpServer) GetPort() int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetPort") + } + var r0 int if rf, ok := ret.Get(0).(func() int); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *HttpServer) SetHTTPRequestHandler(handler network.HTTPRequestHandler) func (_m *HttpServer) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/network/mocks/web_socket_server.go b/core/services/gateway/network/mocks/web_socket_server.go index d88cd5ba4f..4f75f3b7d0 100644 --- a/core/services/gateway/network/mocks/web_socket_server.go +++ b/core/services/gateway/network/mocks/web_socket_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type WebSocketServer struct { func (_m *WebSocketServer) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *WebSocketServer) Close() error { func (_m *WebSocketServer) GetPort() int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetPort") + } + var r0 int if rf, ok := ret.Get(0).(func() int); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *WebSocketServer) GetPort() int { func (_m *WebSocketServer) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index 9e18573f4e..66602c6005 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -31,6 +31,10 @@ type ORM struct { func (_m *ORM) AssertBridgesExist(p pipeline.Pipeline) error { ret := _m.Called(p) + if len(ret) == 0 { + panic("no return value specified for AssertBridgesExist") + } + var r0 error if rf, ok := ret.Get(0).(func(pipeline.Pipeline) error); ok { r0 = rf(p) @@ -45,6 +49,10 @@ func (_m *ORM) AssertBridgesExist(p pipeline.Pipeline) error { func (_m *ORM) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -59,6 +67,10 @@ func (_m *ORM) Close() error { func (_m *ORM) CountPipelineRunsByJobID(jobID int32) (int32, error) { ret := _m.Called(jobID) + if len(ret) == 0 { + panic("no return value specified for CountPipelineRunsByJobID") + } + var r0 int32 var r1 error if rf, ok := ret.Get(0).(func(int32) (int32, error)); ok { @@ -90,6 +102,10 @@ func (_m *ORM) CreateJob(jb *job.Job, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateJob") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.Job, ...pg.QOpt) error); ok { r0 = rf(jb, qopts...) @@ -111,6 +127,10 @@ func (_m *ORM) DeleteJob(id int32, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 error if rf, ok := ret.Get(0).(func(int32, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -125,6 +145,10 @@ func (_m *ORM) DeleteJob(id int32, qopts ...pg.QOpt) error { func (_m *ORM) DismissError(ctx context.Context, errorID int64) error { ret := _m.Called(ctx, errorID) + if len(ret) == 0 { + panic("no return value specified for DismissError") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, errorID) @@ -139,6 +163,10 @@ func (_m *ORM) DismissError(ctx context.Context, errorID int64) error { func (_m *ORM) FindJob(ctx context.Context, id int32) (job.Job, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for FindJob") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(context.Context, int32) (job.Job, error)); ok { @@ -170,6 +198,10 @@ func (_m *ORM) FindJobByExternalJobID(_a0 uuid.UUID, qopts ...pg.QOpt) (job.Job, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindJobByExternalJobID") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(uuid.UUID, ...pg.QOpt) (job.Job, error)); ok { @@ -201,6 +233,10 @@ func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindJobIDByAddress") + } + var r0 int32 var r1 error if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *utils.Big, ...pg.QOpt) (int32, error)); ok { @@ -225,6 +261,10 @@ func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils func (_m *ORM) FindJobIDsWithBridge(name string) ([]int32, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindJobIDsWithBridge") + } + var r0 []int32 var r1 error if rf, ok := ret.Get(0).(func(string) ([]int32, error)); ok { @@ -251,6 +291,10 @@ func (_m *ORM) FindJobIDsWithBridge(name string) ([]int32, error) { func (_m *ORM) FindJobTx(ctx context.Context, id int32) (job.Job, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for FindJobTx") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(context.Context, int32) (job.Job, error)); ok { @@ -275,6 +319,10 @@ func (_m *ORM) FindJobTx(ctx context.Context, id int32) (job.Job, error) { func (_m *ORM) FindJobWithoutSpecErrors(id int32) (job.Job, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for FindJobWithoutSpecErrors") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(int32) (job.Job, error)); ok { @@ -299,6 +347,10 @@ func (_m *ORM) FindJobWithoutSpecErrors(id int32) (job.Job, error) { func (_m *ORM) FindJobs(offset int, limit int) ([]job.Job, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for FindJobs") + } + var r0 []job.Job var r1 int var r2 error @@ -332,6 +384,10 @@ func (_m *ORM) FindJobs(offset int, limit int) ([]job.Job, int, error) { func (_m *ORM) FindJobsByPipelineSpecIDs(ids []int32) ([]job.Job, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for FindJobsByPipelineSpecIDs") + } + var r0 []job.Job var r1 error if rf, ok := ret.Get(0).(func([]int32) ([]job.Job, error)); ok { @@ -365,6 +421,10 @@ func (_m *ORM) FindOCR2JobIDByAddress(contractID string, feedID *common.Hash, qo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindOCR2JobIDByAddress") + } + var r0 int32 var r1 error if rf, ok := ret.Get(0).(func(string, *common.Hash, ...pg.QOpt) (int32, error)); ok { @@ -389,6 +449,10 @@ func (_m *ORM) FindOCR2JobIDByAddress(contractID string, feedID *common.Hash, qo func (_m *ORM) FindPipelineRunByID(id int64) (pipeline.Run, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for FindPipelineRunByID") + } + var r0 pipeline.Run var r1 error if rf, ok := ret.Get(0).(func(int64) (pipeline.Run, error)); ok { @@ -413,6 +477,10 @@ func (_m *ORM) FindPipelineRunByID(id int64) (pipeline.Run, error) { func (_m *ORM) FindPipelineRunIDsByJobID(jobID int32, offset int, limit int) ([]int64, error) { ret := _m.Called(jobID, offset, limit) + if len(ret) == 0 { + panic("no return value specified for FindPipelineRunIDsByJobID") + } + var r0 []int64 var r1 error if rf, ok := ret.Get(0).(func(int32, int, int) ([]int64, error)); ok { @@ -439,6 +507,10 @@ func (_m *ORM) FindPipelineRunIDsByJobID(jobID int32, offset int, limit int) ([] func (_m *ORM) FindPipelineRunsByIDs(ids []int64) ([]pipeline.Run, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for FindPipelineRunsByIDs") + } + var r0 []pipeline.Run var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]pipeline.Run, error)); ok { @@ -472,6 +544,10 @@ func (_m *ORM) FindSpecError(id int64, qopts ...pg.QOpt) (job.SpecError, error) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindSpecError") + } + var r0 job.SpecError var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (job.SpecError, error)); ok { @@ -503,6 +579,10 @@ func (_m *ORM) FindSpecErrorsByJobIDs(ids []int32, qopts ...pg.QOpt) ([]job.Spec _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindSpecErrorsByJobIDs") + } + var r0 []job.SpecError var r1 error if rf, ok := ret.Get(0).(func([]int32, ...pg.QOpt) ([]job.SpecError, error)); ok { @@ -536,6 +616,10 @@ func (_m *ORM) FindTaskResultByRunIDAndTaskName(runID int64, taskName string, qo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindTaskResultByRunIDAndTaskName") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(int64, string, ...pg.QOpt) ([]byte, error)); ok { @@ -569,6 +653,10 @@ func (_m *ORM) InsertJob(_a0 *job.Job, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertJob") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.Job, ...pg.QOpt) error); ok { r0 = rf(_a0, qopts...) @@ -590,6 +678,10 @@ func (_m *ORM) InsertWebhookSpec(webhookSpec *job.WebhookSpec, qopts ...pg.QOpt) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertWebhookSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.WebhookSpec, ...pg.QOpt) error); ok { r0 = rf(webhookSpec, qopts...) @@ -604,6 +696,10 @@ func (_m *ORM) InsertWebhookSpec(webhookSpec *job.WebhookSpec, qopts ...pg.QOpt) func (_m *ORM) PipelineRuns(jobID *int32, offset int, size int) ([]pipeline.Run, int, error) { ret := _m.Called(jobID, offset, size) + if len(ret) == 0 { + panic("no return value specified for PipelineRuns") + } + var r0 []pipeline.Run var r1 int var r2 error @@ -644,6 +740,10 @@ func (_m *ORM) RecordError(jobID int32, description string, qopts ...pg.QOpt) er _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RecordError") + } + var r0 error if rf, ok := ret.Get(0).(func(int32, string, ...pg.QOpt) error); ok { r0 = rf(jobID, description, qopts...) diff --git a/core/services/job/mocks/service_ctx.go b/core/services/job/mocks/service_ctx.go index 93ef76619d..43c2863296 100644 --- a/core/services/job/mocks/service_ctx.go +++ b/core/services/job/mocks/service_ctx.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type ServiceCtx struct { func (_m *ServiceCtx) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *ServiceCtx) Close() error { func (_m *ServiceCtx) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/job/mocks/spawner.go b/core/services/job/mocks/spawner.go index 6866f1fc15..60d36b18fa 100644 --- a/core/services/job/mocks/spawner.go +++ b/core/services/job/mocks/spawner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type Spawner struct { func (_m *Spawner) ActiveJobs() map[int32]job.Job { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ActiveJobs") + } + var r0 map[int32]job.Job if rf, ok := ret.Get(0).(func() map[int32]job.Job); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *Spawner) ActiveJobs() map[int32]job.Job { func (_m *Spawner) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -57,6 +65,10 @@ func (_m *Spawner) CreateJob(jb *job.Job, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateJob") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.Job, ...pg.QOpt) error); ok { r0 = rf(jb, qopts...) @@ -78,6 +90,10 @@ func (_m *Spawner) DeleteJob(jobID int32, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 error if rf, ok := ret.Get(0).(func(int32, ...pg.QOpt) error); ok { r0 = rf(jobID, qopts...) @@ -92,6 +108,10 @@ func (_m *Spawner) DeleteJob(jobID int32, qopts ...pg.QOpt) error { func (_m *Spawner) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -108,6 +128,10 @@ func (_m *Spawner) HealthReport() map[string]error { func (_m *Spawner) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -122,6 +146,10 @@ func (_m *Spawner) Name() string { func (_m *Spawner) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -136,6 +164,10 @@ func (_m *Spawner) Ready() error { func (_m *Spawner) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -157,6 +189,10 @@ func (_m *Spawner) StartService(ctx context.Context, spec job.Job, qopts ...pg.Q _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for StartService") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, job.Job, ...pg.QOpt) error); ok { r0 = rf(ctx, spec, qopts...) diff --git a/core/services/keystore/mocks/cosmos.go b/core/services/keystore/mocks/cosmos.go index b8d5d56c37..40ba12d15d 100644 --- a/core/services/keystore/mocks/cosmos.go +++ b/core/services/keystore/mocks/cosmos.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Cosmos struct { func (_m *Cosmos) Add(key cosmoskey.Key) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(cosmoskey.Key) error); ok { r0 = rf(key) @@ -31,6 +35,10 @@ func (_m *Cosmos) Add(key cosmoskey.Key) error { func (_m *Cosmos) Create() (cosmoskey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func() (cosmoskey.Key, error)); ok { @@ -55,6 +63,10 @@ func (_m *Cosmos) Create() (cosmoskey.Key, error) { func (_m *Cosmos) Delete(id string) (cosmoskey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (cosmoskey.Key, error)); ok { @@ -79,6 +91,10 @@ func (_m *Cosmos) Delete(id string) (cosmoskey.Key, error) { func (_m *Cosmos) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -93,6 +109,10 @@ func (_m *Cosmos) EnsureKey() error { func (_m *Cosmos) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *Cosmos) Export(id string, password string) ([]byte, error) { func (_m *Cosmos) Get(id string) (cosmoskey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (cosmoskey.Key, error)); ok { @@ -143,6 +167,10 @@ func (_m *Cosmos) Get(id string) (cosmoskey.Key, error) { func (_m *Cosmos) GetAll() ([]cosmoskey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]cosmoskey.Key, error)); ok { @@ -169,6 +197,10 @@ func (_m *Cosmos) GetAll() ([]cosmoskey.Key, error) { func (_m *Cosmos) Import(keyJSON []byte, password string) (cosmoskey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (cosmoskey.Key, error)); ok { diff --git a/core/services/keystore/mocks/csa.go b/core/services/keystore/mocks/csa.go index 4f4e02a2fe..ad5b25a27b 100644 --- a/core/services/keystore/mocks/csa.go +++ b/core/services/keystore/mocks/csa.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type CSA struct { func (_m *CSA) Add(key csakey.KeyV2) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(csakey.KeyV2) error); ok { r0 = rf(key) @@ -31,6 +35,10 @@ func (_m *CSA) Add(key csakey.KeyV2) error { func (_m *CSA) Create() (csakey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (csakey.KeyV2, error)); ok { @@ -55,6 +63,10 @@ func (_m *CSA) Create() (csakey.KeyV2, error) { func (_m *CSA) Delete(id string) (csakey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (csakey.KeyV2, error)); ok { @@ -79,6 +91,10 @@ func (_m *CSA) Delete(id string) (csakey.KeyV2, error) { func (_m *CSA) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -93,6 +109,10 @@ func (_m *CSA) EnsureKey() error { func (_m *CSA) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *CSA) Export(id string, password string) ([]byte, error) { func (_m *CSA) Get(id string) (csakey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (csakey.KeyV2, error)); ok { @@ -143,6 +167,10 @@ func (_m *CSA) Get(id string) (csakey.KeyV2, error) { func (_m *CSA) GetAll() ([]csakey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]csakey.KeyV2, error)); ok { @@ -169,6 +197,10 @@ func (_m *CSA) GetAll() ([]csakey.KeyV2, error) { func (_m *CSA) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (csakey.KeyV2, error)); ok { diff --git a/core/services/keystore/mocks/dkg_encrypt.go b/core/services/keystore/mocks/dkg_encrypt.go index e1f83888c4..e7e52bada2 100644 --- a/core/services/keystore/mocks/dkg_encrypt.go +++ b/core/services/keystore/mocks/dkg_encrypt.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type DKGEncrypt struct { func (_m *DKGEncrypt) Add(key dkgencryptkey.Key) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(dkgencryptkey.Key) error); ok { r0 = rf(key) @@ -31,6 +35,10 @@ func (_m *DKGEncrypt) Add(key dkgencryptkey.Key) error { func (_m *DKGEncrypt) Create() (dkgencryptkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func() (dkgencryptkey.Key, error)); ok { @@ -55,6 +63,10 @@ func (_m *DKGEncrypt) Create() (dkgencryptkey.Key, error) { func (_m *DKGEncrypt) Delete(id string) (dkgencryptkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgencryptkey.Key, error)); ok { @@ -79,6 +91,10 @@ func (_m *DKGEncrypt) Delete(id string) (dkgencryptkey.Key, error) { func (_m *DKGEncrypt) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -93,6 +109,10 @@ func (_m *DKGEncrypt) EnsureKey() error { func (_m *DKGEncrypt) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *DKGEncrypt) Export(id string, password string) ([]byte, error) { func (_m *DKGEncrypt) Get(id string) (dkgencryptkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgencryptkey.Key, error)); ok { @@ -143,6 +167,10 @@ func (_m *DKGEncrypt) Get(id string) (dkgencryptkey.Key, error) { func (_m *DKGEncrypt) GetAll() ([]dkgencryptkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]dkgencryptkey.Key, error)); ok { @@ -169,6 +197,10 @@ func (_m *DKGEncrypt) GetAll() ([]dkgencryptkey.Key, error) { func (_m *DKGEncrypt) Import(keyJSON []byte, password string) (dkgencryptkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (dkgencryptkey.Key, error)); ok { diff --git a/core/services/keystore/mocks/dkg_sign.go b/core/services/keystore/mocks/dkg_sign.go index ed1aa756a6..e5c6434d90 100644 --- a/core/services/keystore/mocks/dkg_sign.go +++ b/core/services/keystore/mocks/dkg_sign.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type DKGSign struct { func (_m *DKGSign) Add(key dkgsignkey.Key) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(dkgsignkey.Key) error); ok { r0 = rf(key) @@ -31,6 +35,10 @@ func (_m *DKGSign) Add(key dkgsignkey.Key) error { func (_m *DKGSign) Create() (dkgsignkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func() (dkgsignkey.Key, error)); ok { @@ -55,6 +63,10 @@ func (_m *DKGSign) Create() (dkgsignkey.Key, error) { func (_m *DKGSign) Delete(id string) (dkgsignkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgsignkey.Key, error)); ok { @@ -79,6 +91,10 @@ func (_m *DKGSign) Delete(id string) (dkgsignkey.Key, error) { func (_m *DKGSign) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -93,6 +109,10 @@ func (_m *DKGSign) EnsureKey() error { func (_m *DKGSign) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *DKGSign) Export(id string, password string) ([]byte, error) { func (_m *DKGSign) Get(id string) (dkgsignkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgsignkey.Key, error)); ok { @@ -143,6 +167,10 @@ func (_m *DKGSign) Get(id string) (dkgsignkey.Key, error) { func (_m *DKGSign) GetAll() ([]dkgsignkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]dkgsignkey.Key, error)); ok { @@ -169,6 +197,10 @@ func (_m *DKGSign) GetAll() ([]dkgsignkey.Key, error) { func (_m *DKGSign) Import(keyJSON []byte, password string) (dkgsignkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (dkgsignkey.Key, error)); ok { diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index 6a076e130d..b3827398fd 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -31,6 +31,10 @@ func (_m *Eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { r0 = rf(address, chainID, qopts...) @@ -45,6 +49,10 @@ func (_m *Eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e func (_m *Eth) CheckEnabled(address common.Address, chainID *big.Int) error { ret := _m.Called(address, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckEnabled") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int) error); ok { r0 = rf(address, chainID) @@ -65,6 +73,10 @@ func (_m *Eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(...*big.Int) (ethkey.KeyV2, error)); ok { @@ -89,6 +101,10 @@ func (_m *Eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { func (_m *Eth) Delete(id string) (ethkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ethkey.KeyV2, error)); ok { @@ -120,6 +136,10 @@ func (_m *Eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOp _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Disable") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { r0 = rf(address, chainID, qopts...) @@ -141,6 +161,10 @@ func (_m *Eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Enable") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { r0 = rf(address, chainID, qopts...) @@ -155,6 +179,10 @@ func (_m *Eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt func (_m *Eth) EnabledAddressesForChain(chainID *big.Int) ([]common.Address, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for EnabledAddressesForChain") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]common.Address, error)); ok { @@ -181,6 +209,10 @@ func (_m *Eth) EnabledAddressesForChain(chainID *big.Int) ([]common.Address, err func (_m *Eth) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for EnabledKeysForChain") + } + var r0 []ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.KeyV2, error)); ok { @@ -213,6 +245,10 @@ func (_m *Eth) EnsureKeys(chainIDs ...*big.Int) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for EnsureKeys") + } + var r0 error if rf, ok := ret.Get(0).(func(...*big.Int) error); ok { r0 = rf(chainIDs...) @@ -227,6 +263,10 @@ func (_m *Eth) EnsureKeys(chainIDs ...*big.Int) error { func (_m *Eth) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -253,6 +293,10 @@ func (_m *Eth) Export(id string, password string) ([]byte, error) { func (_m *Eth) Get(id string) (ethkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ethkey.KeyV2, error)); ok { @@ -277,6 +321,10 @@ func (_m *Eth) Get(id string) (ethkey.KeyV2, error) { func (_m *Eth) GetAll() ([]ethkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]ethkey.KeyV2, error)); ok { @@ -310,6 +358,10 @@ func (_m *Eth) GetRoundRobinAddress(chainID *big.Int, addresses ...common.Addres _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetRoundRobinAddress") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) (common.Address, error)); ok { @@ -336,6 +388,10 @@ func (_m *Eth) GetRoundRobinAddress(chainID *big.Int, addresses ...common.Addres func (_m *Eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { ret := _m.Called(id, chainID) + if len(ret) == 0 { + panic("no return value specified for GetState") + } + var r0 ethkey.State var r1 error if rf, ok := ret.Get(0).(func(string, *big.Int) (ethkey.State, error)); ok { @@ -360,6 +416,10 @@ func (_m *Eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { func (_m *Eth) GetStateForKey(_a0 ethkey.KeyV2) (ethkey.State, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetStateForKey") + } + var r0 ethkey.State var r1 error if rf, ok := ret.Get(0).(func(ethkey.KeyV2) (ethkey.State, error)); ok { @@ -384,6 +444,10 @@ func (_m *Eth) GetStateForKey(_a0 ethkey.KeyV2) (ethkey.State, error) { func (_m *Eth) GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for GetStatesForChain") + } + var r0 []ethkey.State var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.State, error)); ok { @@ -410,6 +474,10 @@ func (_m *Eth) GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) { func (_m *Eth) GetStatesForKeys(_a0 []ethkey.KeyV2) ([]ethkey.State, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetStatesForKeys") + } + var r0 []ethkey.State var r1 error if rf, ok := ret.Get(0).(func([]ethkey.KeyV2) ([]ethkey.State, error)); ok { @@ -443,6 +511,10 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string, ...*big.Int) (ethkey.KeyV2, error)); ok { @@ -467,6 +539,10 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { ret := _m.Called(fromAddress, tx, chainID) + if len(ret) == 0 { + panic("no return value specified for SignTx") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)); ok { @@ -493,6 +569,10 @@ func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID func (_m *Eth) SubscribeToKeyChanges() (chan struct{}, func()) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribeToKeyChanges") + } + var r0 chan struct{} var r1 func() if rf, ok := ret.Get(0).(func() (chan struct{}, func())); ok { diff --git a/core/services/keystore/mocks/master.go b/core/services/keystore/mocks/master.go index d29d2fa469..3025f5b103 100644 --- a/core/services/keystore/mocks/master.go +++ b/core/services/keystore/mocks/master.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Master struct { func (_m *Master) CSA() keystore.CSA { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CSA") + } + var r0 keystore.CSA if rf, ok := ret.Get(0).(func() keystore.CSA); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *Master) CSA() keystore.CSA { func (_m *Master) Cosmos() keystore.Cosmos { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Cosmos") + } + var r0 keystore.Cosmos if rf, ok := ret.Get(0).(func() keystore.Cosmos); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *Master) Cosmos() keystore.Cosmos { func (_m *Master) DKGEncrypt() keystore.DKGEncrypt { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DKGEncrypt") + } + var r0 keystore.DKGEncrypt if rf, ok := ret.Get(0).(func() keystore.DKGEncrypt); ok { r0 = rf() @@ -64,6 +76,10 @@ func (_m *Master) DKGEncrypt() keystore.DKGEncrypt { func (_m *Master) DKGSign() keystore.DKGSign { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DKGSign") + } + var r0 keystore.DKGSign if rf, ok := ret.Get(0).(func() keystore.DKGSign); ok { r0 = rf() @@ -80,6 +96,10 @@ func (_m *Master) DKGSign() keystore.DKGSign { func (_m *Master) Eth() keystore.Eth { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Eth") + } + var r0 keystore.Eth if rf, ok := ret.Get(0).(func() keystore.Eth); ok { r0 = rf() @@ -96,6 +116,10 @@ func (_m *Master) Eth() keystore.Eth { func (_m *Master) IsEmpty() (bool, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsEmpty") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func() (bool, error)); ok { @@ -120,6 +144,10 @@ func (_m *Master) IsEmpty() (bool, error) { func (_m *Master) OCR() keystore.OCR { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR") + } + var r0 keystore.OCR if rf, ok := ret.Get(0).(func() keystore.OCR); ok { r0 = rf() @@ -136,6 +164,10 @@ func (_m *Master) OCR() keystore.OCR { func (_m *Master) OCR2() keystore.OCR2 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR2") + } + var r0 keystore.OCR2 if rf, ok := ret.Get(0).(func() keystore.OCR2); ok { r0 = rf() @@ -152,6 +184,10 @@ func (_m *Master) OCR2() keystore.OCR2 { func (_m *Master) P2P() keystore.P2P { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for P2P") + } + var r0 keystore.P2P if rf, ok := ret.Get(0).(func() keystore.P2P); ok { r0 = rf() @@ -168,6 +204,10 @@ func (_m *Master) P2P() keystore.P2P { func (_m *Master) Solana() keystore.Solana { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Solana") + } + var r0 keystore.Solana if rf, ok := ret.Get(0).(func() keystore.Solana); ok { r0 = rf() @@ -184,6 +224,10 @@ func (_m *Master) Solana() keystore.Solana { func (_m *Master) StarkNet() keystore.StarkNet { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StarkNet") + } + var r0 keystore.StarkNet if rf, ok := ret.Get(0).(func() keystore.StarkNet); ok { r0 = rf() @@ -200,6 +244,10 @@ func (_m *Master) StarkNet() keystore.StarkNet { func (_m *Master) Unlock(password string) error { ret := _m.Called(password) + if len(ret) == 0 { + panic("no return value specified for Unlock") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(password) @@ -214,6 +262,10 @@ func (_m *Master) Unlock(password string) error { func (_m *Master) VRF() keystore.VRF { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for VRF") + } + var r0 keystore.VRF if rf, ok := ret.Get(0).(func() keystore.VRF); ok { r0 = rf() diff --git a/core/services/keystore/mocks/ocr.go b/core/services/keystore/mocks/ocr.go index 505eaa0e46..e1c4d58833 100644 --- a/core/services/keystore/mocks/ocr.go +++ b/core/services/keystore/mocks/ocr.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type OCR struct { func (_m *OCR) Add(key ocrkey.KeyV2) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(ocrkey.KeyV2) error); ok { r0 = rf(key) @@ -30,6 +34,10 @@ func (_m *OCR) Add(key ocrkey.KeyV2) error { func (_m *OCR) Create() (ocrkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (ocrkey.KeyV2, error)); ok { @@ -54,6 +62,10 @@ func (_m *OCR) Create() (ocrkey.KeyV2, error) { func (_m *OCR) Delete(id string) (ocrkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ocrkey.KeyV2, error)); ok { @@ -78,6 +90,10 @@ func (_m *OCR) Delete(id string) (ocrkey.KeyV2, error) { func (_m *OCR) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -92,6 +108,10 @@ func (_m *OCR) EnsureKey() error { func (_m *OCR) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -118,6 +138,10 @@ func (_m *OCR) Export(id string, password string) ([]byte, error) { func (_m *OCR) Get(id string) (ocrkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ocrkey.KeyV2, error)); ok { @@ -142,6 +166,10 @@ func (_m *OCR) Get(id string) (ocrkey.KeyV2, error) { func (_m *OCR) GetAll() ([]ocrkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]ocrkey.KeyV2, error)); ok { @@ -168,6 +196,10 @@ func (_m *OCR) GetAll() ([]ocrkey.KeyV2, error) { func (_m *OCR) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (ocrkey.KeyV2, error)); ok { diff --git a/core/services/keystore/mocks/ocr2.go b/core/services/keystore/mocks/ocr2.go index 30d870dcdc..d44e739dee 100644 --- a/core/services/keystore/mocks/ocr2.go +++ b/core/services/keystore/mocks/ocr2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type OCR2 struct { func (_m *OCR2) Add(key ocr2key.KeyBundle) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(ocr2key.KeyBundle) error); ok { r0 = rf(key) @@ -33,6 +37,10 @@ func (_m *OCR2) Add(key ocr2key.KeyBundle) error { func (_m *OCR2) Create(_a0 chaintype.ChainType) (ocr2key.KeyBundle, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func(chaintype.ChainType) (ocr2key.KeyBundle, error)); ok { @@ -59,6 +67,10 @@ func (_m *OCR2) Create(_a0 chaintype.ChainType) (ocr2key.KeyBundle, error) { func (_m *OCR2) Delete(id string) error { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(id) @@ -79,6 +91,10 @@ func (_m *OCR2) EnsureKeys(enabledChains ...chaintype.ChainType) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for EnsureKeys") + } + var r0 error if rf, ok := ret.Get(0).(func(...chaintype.ChainType) error); ok { r0 = rf(enabledChains...) @@ -93,6 +109,10 @@ func (_m *OCR2) EnsureKeys(enabledChains ...chaintype.ChainType) error { func (_m *OCR2) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *OCR2) Export(id string, password string) ([]byte, error) { func (_m *OCR2) Get(id string) (ocr2key.KeyBundle, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func(string) (ocr2key.KeyBundle, error)); ok { @@ -145,6 +169,10 @@ func (_m *OCR2) Get(id string) (ocr2key.KeyBundle, error) { func (_m *OCR2) GetAll() ([]ocr2key.KeyBundle, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func() ([]ocr2key.KeyBundle, error)); ok { @@ -171,6 +199,10 @@ func (_m *OCR2) GetAll() ([]ocr2key.KeyBundle, error) { func (_m *OCR2) GetAllOfType(_a0 chaintype.ChainType) ([]ocr2key.KeyBundle, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetAllOfType") + } + var r0 []ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func(chaintype.ChainType) ([]ocr2key.KeyBundle, error)); ok { @@ -197,6 +229,10 @@ func (_m *OCR2) GetAllOfType(_a0 chaintype.ChainType) ([]ocr2key.KeyBundle, erro func (_m *OCR2) Import(keyJSON []byte, password string) (ocr2key.KeyBundle, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (ocr2key.KeyBundle, error)); ok { diff --git a/core/services/keystore/mocks/p2p.go b/core/services/keystore/mocks/p2p.go index c91be5a4a9..fa2a1b6cee 100644 --- a/core/services/keystore/mocks/p2p.go +++ b/core/services/keystore/mocks/p2p.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type P2P struct { func (_m *P2P) Add(key p2pkey.KeyV2) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(p2pkey.KeyV2) error); ok { r0 = rf(key) @@ -30,6 +34,10 @@ func (_m *P2P) Add(key p2pkey.KeyV2) error { func (_m *P2P) Create() (p2pkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (p2pkey.KeyV2, error)); ok { @@ -54,6 +62,10 @@ func (_m *P2P) Create() (p2pkey.KeyV2, error) { func (_m *P2P) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { @@ -78,6 +90,10 @@ func (_m *P2P) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { func (_m *P2P) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -92,6 +108,10 @@ func (_m *P2P) EnsureKey() error { func (_m *P2P) Export(id p2pkey.PeerID, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID, string) ([]byte, error)); ok { @@ -118,6 +138,10 @@ func (_m *P2P) Export(id p2pkey.PeerID, password string) ([]byte, error) { func (_m *P2P) Get(id p2pkey.PeerID) (p2pkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { @@ -142,6 +166,10 @@ func (_m *P2P) Get(id p2pkey.PeerID) (p2pkey.KeyV2, error) { func (_m *P2P) GetAll() ([]p2pkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]p2pkey.KeyV2, error)); ok { @@ -168,6 +196,10 @@ func (_m *P2P) GetAll() ([]p2pkey.KeyV2, error) { func (_m *P2P) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetOrFirst") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { @@ -192,6 +224,10 @@ func (_m *P2P) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { func (_m *P2P) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (p2pkey.KeyV2, error)); ok { diff --git a/core/services/keystore/mocks/solana.go b/core/services/keystore/mocks/solana.go index 66357e32b9..c2cc4139ba 100644 --- a/core/services/keystore/mocks/solana.go +++ b/core/services/keystore/mocks/solana.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type Solana struct { func (_m *Solana) Add(key solkey.Key) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(solkey.Key) error); ok { r0 = rf(key) @@ -33,6 +37,10 @@ func (_m *Solana) Add(key solkey.Key) error { func (_m *Solana) Create() (solkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func() (solkey.Key, error)); ok { @@ -57,6 +65,10 @@ func (_m *Solana) Create() (solkey.Key, error) { func (_m *Solana) Delete(id string) (solkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (solkey.Key, error)); ok { @@ -81,6 +93,10 @@ func (_m *Solana) Delete(id string) (solkey.Key, error) { func (_m *Solana) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -95,6 +111,10 @@ func (_m *Solana) EnsureKey() error { func (_m *Solana) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -121,6 +141,10 @@ func (_m *Solana) Export(id string, password string) ([]byte, error) { func (_m *Solana) Get(id string) (solkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (solkey.Key, error)); ok { @@ -145,6 +169,10 @@ func (_m *Solana) Get(id string) (solkey.Key, error) { func (_m *Solana) GetAll() ([]solkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []solkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]solkey.Key, error)); ok { @@ -171,6 +199,10 @@ func (_m *Solana) GetAll() ([]solkey.Key, error) { func (_m *Solana) Import(keyJSON []byte, password string) (solkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (solkey.Key, error)); ok { @@ -195,6 +227,10 @@ func (_m *Solana) Import(keyJSON []byte, password string) (solkey.Key, error) { func (_m *Solana) Sign(ctx context.Context, id string, msg []byte) ([]byte, error) { ret := _m.Called(ctx, id, msg) + if len(ret) == 0 { + panic("no return value specified for Sign") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []byte) ([]byte, error)); ok { diff --git a/core/services/keystore/mocks/starknet.go b/core/services/keystore/mocks/starknet.go index ff9b52d713..c3d74a8389 100644 --- a/core/services/keystore/mocks/starknet.go +++ b/core/services/keystore/mocks/starknet.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type StarkNet struct { func (_m *StarkNet) Add(key starkkey.Key) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(starkkey.Key) error); ok { r0 = rf(key) @@ -30,6 +34,10 @@ func (_m *StarkNet) Add(key starkkey.Key) error { func (_m *StarkNet) Create() (starkkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func() (starkkey.Key, error)); ok { @@ -54,6 +62,10 @@ func (_m *StarkNet) Create() (starkkey.Key, error) { func (_m *StarkNet) Delete(id string) (starkkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (starkkey.Key, error)); ok { @@ -78,6 +90,10 @@ func (_m *StarkNet) Delete(id string) (starkkey.Key, error) { func (_m *StarkNet) EnsureKey() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EnsureKey") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -92,6 +108,10 @@ func (_m *StarkNet) EnsureKey() error { func (_m *StarkNet) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -118,6 +138,10 @@ func (_m *StarkNet) Export(id string, password string) ([]byte, error) { func (_m *StarkNet) Get(id string) (starkkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (starkkey.Key, error)); ok { @@ -142,6 +166,10 @@ func (_m *StarkNet) Get(id string) (starkkey.Key, error) { func (_m *StarkNet) GetAll() ([]starkkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []starkkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]starkkey.Key, error)); ok { @@ -168,6 +196,10 @@ func (_m *StarkNet) GetAll() ([]starkkey.Key, error) { func (_m *StarkNet) Import(keyJSON []byte, password string) (starkkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (starkkey.Key, error)); ok { diff --git a/core/services/keystore/mocks/vrf.go b/core/services/keystore/mocks/vrf.go index 5aa15dca59..ab730ebec6 100644 --- a/core/services/keystore/mocks/vrf.go +++ b/core/services/keystore/mocks/vrf.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type VRF struct { func (_m *VRF) Add(key vrfkey.KeyV2) error { ret := _m.Called(key) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(vrfkey.KeyV2) error); ok { r0 = rf(key) @@ -33,6 +37,10 @@ func (_m *VRF) Add(key vrfkey.KeyV2) error { func (_m *VRF) Create() (vrfkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (vrfkey.KeyV2, error)); ok { @@ -57,6 +65,10 @@ func (_m *VRF) Create() (vrfkey.KeyV2, error) { func (_m *VRF) Delete(id string) (vrfkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (vrfkey.KeyV2, error)); ok { @@ -81,6 +93,10 @@ func (_m *VRF) Delete(id string) (vrfkey.KeyV2, error) { func (_m *VRF) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -107,6 +123,10 @@ func (_m *VRF) Export(id string, password string) ([]byte, error) { func (_m *VRF) GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error) { ret := _m.Called(id, seed) + if len(ret) == 0 { + panic("no return value specified for GenerateProof") + } + var r0 vrfkey.Proof var r1 error if rf, ok := ret.Get(0).(func(string, *big.Int) (vrfkey.Proof, error)); ok { @@ -131,6 +151,10 @@ func (_m *VRF) GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error) { func (_m *VRF) Get(id string) (vrfkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (vrfkey.KeyV2, error)); ok { @@ -155,6 +179,10 @@ func (_m *VRF) Get(id string) (vrfkey.KeyV2, error) { func (_m *VRF) GetAll() ([]vrfkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]vrfkey.KeyV2, error)); ok { @@ -181,6 +209,10 @@ func (_m *VRF) GetAll() ([]vrfkey.KeyV2, error) { func (_m *VRF) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (vrfkey.KeyV2, error)); ok { diff --git a/core/services/mocks/checker.go b/core/services/mocks/checker.go index e0c209d8af..2572efb182 100644 --- a/core/services/mocks/checker.go +++ b/core/services/mocks/checker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Checker struct { func (_m *Checker) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -30,6 +34,10 @@ func (_m *Checker) Close() error { func (_m *Checker) IsHealthy() (bool, map[string]error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsHealthy") + } + var r0 bool var r1 map[string]error if rf, ok := ret.Get(0).(func() (bool, map[string]error)); ok { @@ -56,6 +64,10 @@ func (_m *Checker) IsHealthy() (bool, map[string]error) { func (_m *Checker) IsReady() (bool, map[string]error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsReady") + } + var r0 bool var r1 map[string]error if rf, ok := ret.Get(0).(func() (bool, map[string]error)); ok { @@ -82,6 +94,10 @@ func (_m *Checker) IsReady() (bool, map[string]error) { func (_m *Checker) Register(service pkgservices.HealthReporter) error { ret := _m.Called(service) + if len(ret) == 0 { + panic("no return value specified for Register") + } + var r0 error if rf, ok := ret.Get(0).(func(pkgservices.HealthReporter) error); ok { r0 = rf(service) @@ -96,6 +112,10 @@ func (_m *Checker) Register(service pkgservices.HealthReporter) error { func (_m *Checker) Start() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -110,6 +130,10 @@ func (_m *Checker) Start() error { func (_m *Checker) Unregister(name string) error { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for Unregister") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(name) diff --git a/core/services/ocr/mocks/ocr_contract_tracker_db.go b/core/services/ocr/mocks/ocr_contract_tracker_db.go index a1d2f523cc..6724e41801 100644 --- a/core/services/ocr/mocks/ocr_contract_tracker_db.go +++ b/core/services/ocr/mocks/ocr_contract_tracker_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type OCRContractTrackerDB struct { func (_m *OCRContractTrackerDB) LoadLatestRoundRequested() (offchainaggregator.OffchainAggregatorRoundRequested, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LoadLatestRoundRequested") + } + var r0 offchainaggregator.OffchainAggregatorRoundRequested var r1 error if rf, ok := ret.Get(0).(func() (offchainaggregator.OffchainAggregatorRoundRequested, error)); ok { @@ -43,6 +47,10 @@ func (_m *OCRContractTrackerDB) LoadLatestRoundRequested() (offchainaggregator.O func (_m *OCRContractTrackerDB) SaveLatestRoundRequested(tx pg.Queryer, rr offchainaggregator.OffchainAggregatorRoundRequested) error { ret := _m.Called(tx, rr) + if len(ret) == 0 { + panic("no return value specified for SaveLatestRoundRequested") + } + var r0 error if rf, ok := ret.Get(0).(func(pg.Queryer, offchainaggregator.OffchainAggregatorRoundRequested) error); ok { r0 = rf(tx, rr) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go index bc30ac781d..8c8ea721d7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type Registry struct { func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { ret := _m.Called(opts, startIndex, maxCount) + if len(ret) == 0 { + panic("no return value specified for GetActiveUpkeepIDs") + } + var r0 []*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, *big.Int) ([]*big.Int, error)); ok { @@ -51,6 +55,10 @@ func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, func (_m *Registry) GetState(opts *bind.CallOpts) (keeper_registry_wrapper2_0.GetState, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetState") + } + var r0 keeper_registry_wrapper2_0.GetState var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (keeper_registry_wrapper2_0.GetState, error)); ok { @@ -75,6 +83,10 @@ func (_m *Registry) GetState(opts *bind.CallOpts) (keeper_registry_wrapper2_0.Ge func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (keeper_registry_wrapper2_0.UpkeepInfo, error) { ret := _m.Called(opts, id) + if len(ret) == 0 { + panic("no return value specified for GetUpkeep") + } + var r0 keeper_registry_wrapper2_0.UpkeepInfo var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (keeper_registry_wrapper2_0.UpkeepInfo, error)); ok { @@ -99,6 +111,10 @@ func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (keeper_registry func (_m *Registry) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go index b036fbb26c..3167cf97aa 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -26,6 +26,10 @@ func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...str _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SelectByWorkIDs") + } + var r0 []types.UpkeepState var r1 error if rf, ok := ret.Get(0).(func(context.Context, ...string) ([]types.UpkeepState, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go index 53d347b1c0..d6982e9dbd 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type HttpClient struct { func (_m *HttpClient) Do(req *http.Request) (*http.Response, error) { ret := _m.Called(req) + if len(ret) == 0 { + panic("no return value specified for Do") + } + var r0 *http.Response var r1 error if rf, ok := ret.Get(0).(func(*http.Request) (*http.Response, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go index a3cbd772b1..1bb4cb2a32 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type Registry struct { func (_m *Registry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (i_keeper_registry_master_wrapper_2_1.CheckCallback, error) { ret := _m.Called(opts, id, values, extraData) + if len(ret) == 0 { + panic("no return value specified for CheckCallback") + } + var r0 i_keeper_registry_master_wrapper_2_1.CheckCallback var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, [][]byte, []byte) (i_keeper_registry_master_wrapper_2_1.CheckCallback, error)); ok { @@ -49,6 +53,10 @@ func (_m *Registry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]b func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { ret := _m.Called(opts, startIndex, maxCount) + if len(ret) == 0 { + panic("no return value specified for GetActiveUpkeepIDs") + } + var r0 []*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, *big.Int) ([]*big.Int, error)); ok { @@ -75,6 +83,10 @@ func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, func (_m *Registry) GetState(opts *bind.CallOpts) (i_keeper_registry_master_wrapper_2_1.GetState, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetState") + } + var r0 i_keeper_registry_master_wrapper_2_1.GetState var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (i_keeper_registry_master_wrapper_2_1.GetState, error)); ok { @@ -99,6 +111,10 @@ func (_m *Registry) GetState(opts *bind.CallOpts) (i_keeper_registry_master_wrap func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (i_keeper_registry_master_wrapper_2_1.KeeperRegistryBase21UpkeepInfo, error) { ret := _m.Called(opts, id) + if len(ret) == 0 { + panic("no return value specified for GetUpkeep") + } + var r0 i_keeper_registry_master_wrapper_2_1.KeeperRegistryBase21UpkeepInfo var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (i_keeper_registry_master_wrapper_2_1.KeeperRegistryBase21UpkeepInfo, error)); ok { @@ -123,6 +139,10 @@ func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (i_keeper_regist func (_m *Registry) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { ret := _m.Called(opts, upkeepId) + if len(ret) == 0 { + panic("no return value specified for GetUpkeepPrivilegeConfig") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([]byte, error)); ok { @@ -149,6 +169,10 @@ func (_m *Registry) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big. func (_m *Registry) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { ret := _m.Called(opts, upkeepId) + if len(ret) == 0 { + panic("no return value specified for GetUpkeepTriggerConfig") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([]byte, error)); ok { @@ -175,6 +199,10 @@ func (_m *Registry) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.In func (_m *Registry) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go index d3fe5c9119..57521566a7 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type VRFBeaconInterface struct { func (_m *VRFBeaconInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *VRFBeaconInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.T func (_m *VRFBeaconInterface) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitter) + if len(ret) == 0 { + panic("no return value specified for AcceptPayeeship") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *VRFBeaconInterface) AcceptPayeeship(opts *bind.TransactOpts, transmitt func (_m *VRFBeaconInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -96,6 +108,10 @@ func (_m *VRFBeaconInterface) Address() common.Address { func (_m *VRFBeaconInterface) ExposeType(opts *bind.TransactOpts, arg0 vrf_beacon.VRFBeaconReportReport) (*types.Transaction, error) { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for ExposeType") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.VRFBeaconReportReport) (*types.Transaction, error)); ok { @@ -122,6 +138,10 @@ func (_m *VRFBeaconInterface) ExposeType(opts *bind.TransactOpts, arg0 vrf_beaco func (_m *VRFBeaconInterface) FilterBillingAccessControllerSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingAccessControllerSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterBillingAccessControllerSet") + } + var r0 *vrf_beacon.VRFBeaconBillingAccessControllerSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingAccessControllerSetIterator, error)); ok { @@ -148,6 +168,10 @@ func (_m *VRFBeaconInterface) FilterBillingAccessControllerSet(opts *bind.Filter func (_m *VRFBeaconInterface) FilterBillingSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterBillingSet") + } + var r0 *vrf_beacon.VRFBeaconBillingSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingSetIterator, error)); ok { @@ -174,6 +198,10 @@ func (_m *VRFBeaconInterface) FilterBillingSet(opts *bind.FilterOpts) (*vrf_beac func (_m *VRFBeaconInterface) FilterConfigSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet") + } + var r0 *vrf_beacon.VRFBeaconConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconConfigSetIterator, error)); ok { @@ -200,6 +228,10 @@ func (_m *VRFBeaconInterface) FilterConfigSet(opts *bind.FilterOpts) (*vrf_beaco func (_m *VRFBeaconInterface) FilterNewTransmission(opts *bind.FilterOpts, epochAndRound []*big.Int) (*vrf_beacon.VRFBeaconNewTransmissionIterator, error) { ret := _m.Called(opts, epochAndRound) + if len(ret) == 0 { + panic("no return value specified for FilterNewTransmission") + } + var r0 *vrf_beacon.VRFBeaconNewTransmissionIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconNewTransmissionIterator, error)); ok { @@ -226,6 +258,10 @@ func (_m *VRFBeaconInterface) FilterNewTransmission(opts *bind.FilterOpts, epoch func (_m *VRFBeaconInterface) FilterOraclePaid(opts *bind.FilterOpts, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (*vrf_beacon.VRFBeaconOraclePaidIterator, error) { ret := _m.Called(opts, transmitter, payee, linkToken) + if len(ret) == 0 { + panic("no return value specified for FilterOraclePaid") + } + var r0 *vrf_beacon.VRFBeaconOraclePaidIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOraclePaidIterator, error)); ok { @@ -252,6 +288,10 @@ func (_m *VRFBeaconInterface) FilterOraclePaid(opts *bind.FilterOpts, transmitte func (_m *VRFBeaconInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconOutputsServedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterOutputsServed") + } + var r0 *vrf_beacon.VRFBeaconOutputsServedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconOutputsServedIterator, error)); ok { @@ -278,6 +318,10 @@ func (_m *VRFBeaconInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_b func (_m *VRFBeaconInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator, error)); ok { @@ -304,6 +348,10 @@ func (_m *VRFBeaconInterface) FilterOwnershipTransferRequested(opts *bind.Filter func (_m *VRFBeaconInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferredIterator, error)); ok { @@ -330,6 +378,10 @@ func (_m *VRFBeaconInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, func (_m *VRFBeaconInterface) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, current []common.Address, proposed []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator, error) { ret := _m.Called(opts, transmitter, current, proposed) + if len(ret) == 0 { + panic("no return value specified for FilterPayeeshipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator, error)); ok { @@ -356,6 +408,10 @@ func (_m *VRFBeaconInterface) FilterPayeeshipTransferRequested(opts *bind.Filter func (_m *VRFBeaconInterface) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, previous []common.Address, current []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferredIterator, error) { ret := _m.Called(opts, transmitter, previous, current) + if len(ret) == 0 { + panic("no return value specified for FilterPayeeshipTransferred") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferredIterator, error)); ok { @@ -382,6 +438,10 @@ func (_m *VRFBeaconInterface) FilterPayeeshipTransferred(opts *bind.FilterOpts, func (_m *VRFBeaconInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconRandomWordsFulfilledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsFulfilled") + } + var r0 *vrf_beacon.VRFBeaconRandomWordsFulfilledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconRandomWordsFulfilledIterator, error)); ok { @@ -408,6 +468,10 @@ func (_m *VRFBeaconInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) func (_m *VRFBeaconInterface) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessFulfillmentRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator, error)); ok { @@ -434,6 +498,10 @@ func (_m *VRFBeaconInterface) FilterRandomnessFulfillmentRequested(opts *bind.Fi func (_m *VRFBeaconInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*vrf_beacon.VRFBeaconRandomnessRedeemedIterator, error) { ret := _m.Called(opts, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRedeemed") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRedeemedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_beacon.VRFBeaconRandomnessRedeemedIterator, error)); ok { @@ -460,6 +528,10 @@ func (_m *VRFBeaconInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, re func (_m *VRFBeaconInterface) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_beacon.VRFBeaconRandomnessRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconRandomnessRequestedIterator, error)); ok { @@ -486,6 +558,10 @@ func (_m *VRFBeaconInterface) FilterRandomnessRequested(opts *bind.FilterOpts, r func (_m *VRFBeaconInterface) GetBilling(opts *bind.CallOpts) (vrf_beacon.GetBilling, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetBilling") + } + var r0 vrf_beacon.GetBilling var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.GetBilling, error)); ok { @@ -510,6 +586,10 @@ func (_m *VRFBeaconInterface) GetBilling(opts *bind.CallOpts) (vrf_beacon.GetBil func (_m *VRFBeaconInterface) GetBillingAccessController(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetBillingAccessController") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -536,6 +616,10 @@ func (_m *VRFBeaconInterface) GetBillingAccessController(opts *bind.CallOpts) (c func (_m *VRFBeaconInterface) ICoordinator(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for ICoordinator") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -562,6 +646,10 @@ func (_m *VRFBeaconInterface) ICoordinator(opts *bind.CallOpts) (common.Address, func (_m *VRFBeaconInterface) ILink(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for ILink") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -588,6 +676,10 @@ func (_m *VRFBeaconInterface) ILink(opts *bind.CallOpts) (common.Address, error) func (_m *VRFBeaconInterface) KeyGenerated(opts *bind.TransactOpts, kd vrf_beacon.KeyDataStructKeyData) (*types.Transaction, error) { ret := _m.Called(opts, kd) + if len(ret) == 0 { + panic("no return value specified for KeyGenerated") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.KeyDataStructKeyData) (*types.Transaction, error)); ok { @@ -614,6 +706,10 @@ func (_m *VRFBeaconInterface) KeyGenerated(opts *bind.TransactOpts, kd vrf_beaco func (_m *VRFBeaconInterface) LatestConfigDetails(opts *bind.CallOpts) (vrf_beacon.LatestConfigDetails, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDetails") + } + var r0 vrf_beacon.LatestConfigDetails var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.LatestConfigDetails, error)); ok { @@ -638,6 +734,10 @@ func (_m *VRFBeaconInterface) LatestConfigDetails(opts *bind.CallOpts) (vrf_beac func (_m *VRFBeaconInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (vrf_beacon.LatestConfigDigestAndEpoch, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDigestAndEpoch") + } + var r0 vrf_beacon.LatestConfigDigestAndEpoch var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.LatestConfigDigestAndEpoch, error)); ok { @@ -662,6 +762,10 @@ func (_m *VRFBeaconInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (v func (_m *VRFBeaconInterface) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LinkAvailableForPayment") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -688,6 +792,10 @@ func (_m *VRFBeaconInterface) LinkAvailableForPayment(opts *bind.CallOpts) (*big func (_m *VRFBeaconInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for NUMCONFDELAYS") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -712,6 +820,10 @@ func (_m *VRFBeaconInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) func (_m *VRFBeaconInterface) NewKeyRequested(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for NewKeyRequested") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -738,6 +850,10 @@ func (_m *VRFBeaconInterface) NewKeyRequested(opts *bind.TransactOpts) (*types.T func (_m *VRFBeaconInterface) OwedPayment(opts *bind.CallOpts, transmitterAddress common.Address) (*big.Int, error) { ret := _m.Called(opts, transmitterAddress) + if len(ret) == 0 { + panic("no return value specified for OwedPayment") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { @@ -764,6 +880,10 @@ func (_m *VRFBeaconInterface) OwedPayment(opts *bind.CallOpts, transmitterAddres func (_m *VRFBeaconInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -790,6 +910,10 @@ func (_m *VRFBeaconInterface) Owner(opts *bind.CallOpts) (common.Address, error) func (_m *VRFBeaconInterface) ParseBillingAccessControllerSet(log types.Log) (*vrf_beacon.VRFBeaconBillingAccessControllerSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseBillingAccessControllerSet") + } + var r0 *vrf_beacon.VRFBeaconBillingAccessControllerSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconBillingAccessControllerSet, error)); ok { @@ -816,6 +940,10 @@ func (_m *VRFBeaconInterface) ParseBillingAccessControllerSet(log types.Log) (*v func (_m *VRFBeaconInterface) ParseBillingSet(log types.Log) (*vrf_beacon.VRFBeaconBillingSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseBillingSet") + } + var r0 *vrf_beacon.VRFBeaconBillingSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconBillingSet, error)); ok { @@ -842,6 +970,10 @@ func (_m *VRFBeaconInterface) ParseBillingSet(log types.Log) (*vrf_beacon.VRFBea func (_m *VRFBeaconInterface) ParseConfigSet(log types.Log) (*vrf_beacon.VRFBeaconConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet") + } + var r0 *vrf_beacon.VRFBeaconConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconConfigSet, error)); ok { @@ -868,6 +1000,10 @@ func (_m *VRFBeaconInterface) ParseConfigSet(log types.Log) (*vrf_beacon.VRFBeac func (_m *VRFBeaconInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -894,6 +1030,10 @@ func (_m *VRFBeaconInterface) ParseLog(log types.Log) (generated.AbigenLog, erro func (_m *VRFBeaconInterface) ParseNewTransmission(log types.Log) (*vrf_beacon.VRFBeaconNewTransmission, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseNewTransmission") + } + var r0 *vrf_beacon.VRFBeaconNewTransmission var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconNewTransmission, error)); ok { @@ -920,6 +1060,10 @@ func (_m *VRFBeaconInterface) ParseNewTransmission(log types.Log) (*vrf_beacon.V func (_m *VRFBeaconInterface) ParseOraclePaid(log types.Log) (*vrf_beacon.VRFBeaconOraclePaid, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOraclePaid") + } + var r0 *vrf_beacon.VRFBeaconOraclePaid var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOraclePaid, error)); ok { @@ -946,6 +1090,10 @@ func (_m *VRFBeaconInterface) ParseOraclePaid(log types.Log) (*vrf_beacon.VRFBea func (_m *VRFBeaconInterface) ParseOutputsServed(log types.Log) (*vrf_beacon.VRFBeaconOutputsServed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOutputsServed") + } + var r0 *vrf_beacon.VRFBeaconOutputsServed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOutputsServed, error)); ok { @@ -972,6 +1120,10 @@ func (_m *VRFBeaconInterface) ParseOutputsServed(log types.Log) (*vrf_beacon.VRF func (_m *VRFBeaconInterface) ParseOwnershipTransferRequested(log types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferRequested, error)); ok { @@ -998,6 +1150,10 @@ func (_m *VRFBeaconInterface) ParseOwnershipTransferRequested(log types.Log) (*v func (_m *VRFBeaconInterface) ParseOwnershipTransferred(log types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferred, error)); ok { @@ -1024,6 +1180,10 @@ func (_m *VRFBeaconInterface) ParseOwnershipTransferred(log types.Log) (*vrf_bea func (_m *VRFBeaconInterface) ParsePayeeshipTransferRequested(log types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePayeeshipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferRequested, error)); ok { @@ -1050,6 +1210,10 @@ func (_m *VRFBeaconInterface) ParsePayeeshipTransferRequested(log types.Log) (*v func (_m *VRFBeaconInterface) ParsePayeeshipTransferred(log types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePayeeshipTransferred") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferred, error)); ok { @@ -1076,6 +1240,10 @@ func (_m *VRFBeaconInterface) ParsePayeeshipTransferred(log types.Log) (*vrf_bea func (_m *VRFBeaconInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_beacon.VRFBeaconRandomWordsFulfilled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsFulfilled") + } + var r0 *vrf_beacon.VRFBeaconRandomWordsFulfilled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomWordsFulfilled, error)); ok { @@ -1102,6 +1270,10 @@ func (_m *VRFBeaconInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_bea func (_m *VRFBeaconInterface) ParseRandomnessFulfillmentRequested(log types.Log) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessFulfillmentRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, error)); ok { @@ -1128,6 +1300,10 @@ func (_m *VRFBeaconInterface) ParseRandomnessFulfillmentRequested(log types.Log) func (_m *VRFBeaconInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_beacon.VRFBeaconRandomnessRedeemed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRedeemed") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRedeemed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessRedeemed, error)); ok { @@ -1154,6 +1330,10 @@ func (_m *VRFBeaconInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_beaco func (_m *VRFBeaconInterface) ParseRandomnessRequested(log types.Log) (*vrf_beacon.VRFBeaconRandomnessRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessRequested, error)); ok { @@ -1180,6 +1360,10 @@ func (_m *VRFBeaconInterface) ParseRandomnessRequested(log types.Log) (*vrf_beac func (_m *VRFBeaconInterface) SKeyID(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SKeyID") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { @@ -1206,6 +1390,10 @@ func (_m *VRFBeaconInterface) SKeyID(opts *bind.CallOpts) ([32]byte, error) { func (_m *VRFBeaconInterface) SKeyProvider(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SKeyProvider") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1232,6 +1420,10 @@ func (_m *VRFBeaconInterface) SKeyProvider(opts *bind.CallOpts) (common.Address, func (_m *VRFBeaconInterface) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SProvingKeyHash") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { @@ -1258,6 +1450,10 @@ func (_m *VRFBeaconInterface) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, er func (_m *VRFBeaconInterface) SetBilling(opts *bind.TransactOpts, maximumGasPrice uint64, reasonableGasPrice uint64, observationPayment uint64, transmissionPayment uint64, accountingGas *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) + if len(ret) == 0 { + panic("no return value specified for SetBilling") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, uint64, uint64, uint64, *big.Int) (*types.Transaction, error)); ok { @@ -1284,6 +1480,10 @@ func (_m *VRFBeaconInterface) SetBilling(opts *bind.TransactOpts, maximumGasPric func (_m *VRFBeaconInterface) SetBillingAccessController(opts *bind.TransactOpts, _billingAccessController common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _billingAccessController) + if len(ret) == 0 { + panic("no return value specified for SetBillingAccessController") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1310,6 +1510,10 @@ func (_m *VRFBeaconInterface) SetBillingAccessController(opts *bind.TransactOpts func (_m *VRFBeaconInterface) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) + if len(ret) == 0 { + panic("no return value specified for SetConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok { @@ -1336,6 +1540,10 @@ func (_m *VRFBeaconInterface) SetConfig(opts *bind.TransactOpts, signers []commo func (_m *VRFBeaconInterface) SetPayees(opts *bind.TransactOpts, transmitters []common.Address, payees []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitters, payees) + if len(ret) == 0 { + panic("no return value specified for SetPayees") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) (*types.Transaction, error)); ok { @@ -1362,6 +1570,10 @@ func (_m *VRFBeaconInterface) SetPayees(opts *bind.TransactOpts, transmitters [] func (_m *VRFBeaconInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1388,6 +1600,10 @@ func (_m *VRFBeaconInterface) TransferOwnership(opts *bind.TransactOpts, to comm func (_m *VRFBeaconInterface) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitter, proposed) + if len(ret) == 0 { + panic("no return value specified for TransferPayeeship") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok { @@ -1414,6 +1630,10 @@ func (_m *VRFBeaconInterface) TransferPayeeship(opts *bind.TransactOpts, transmi func (_m *VRFBeaconInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { ret := _m.Called(opts, reportContext, report, rs, ss, rawVs) + if len(ret) == 0 { + panic("no return value specified for Transmit") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok { @@ -1440,6 +1660,10 @@ func (_m *VRFBeaconInterface) Transmit(opts *bind.TransactOpts, reportContext [3 func (_m *VRFBeaconInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -1464,6 +1688,10 @@ func (_m *VRFBeaconInterface) TypeAndVersion(opts *bind.CallOpts) (string, error func (_m *VRFBeaconInterface) WatchBillingAccessControllerSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchBillingAccessControllerSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) (event.Subscription, error)); ok { @@ -1490,6 +1718,10 @@ func (_m *VRFBeaconInterface) WatchBillingAccessControllerSet(opts *bind.WatchOp func (_m *VRFBeaconInterface) WatchBillingSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconBillingSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchBillingSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingSet) (event.Subscription, error)); ok { @@ -1516,6 +1748,10 @@ func (_m *VRFBeaconInterface) WatchBillingSet(opts *bind.WatchOpts, sink chan<- func (_m *VRFBeaconInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconConfigSet) (event.Subscription, error)); ok { @@ -1542,6 +1778,10 @@ func (_m *VRFBeaconInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- * func (_m *VRFBeaconInterface) WatchNewTransmission(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconNewTransmission, epochAndRound []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, epochAndRound) + if len(ret) == 0 { + panic("no return value specified for WatchNewTransmission") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconNewTransmission, []*big.Int) (event.Subscription, error)); ok { @@ -1568,6 +1808,10 @@ func (_m *VRFBeaconInterface) WatchNewTransmission(opts *bind.WatchOpts, sink ch func (_m *VRFBeaconInterface) WatchOraclePaid(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOraclePaid, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, transmitter, payee, linkToken) + if len(ret) == 0 { + panic("no return value specified for WatchOraclePaid") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOraclePaid, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1594,6 +1838,10 @@ func (_m *VRFBeaconInterface) WatchOraclePaid(opts *bind.WatchOpts, sink chan<- func (_m *VRFBeaconInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOutputsServed) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchOutputsServed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOutputsServed) (event.Subscription, error)); ok { @@ -1620,6 +1868,10 @@ func (_m *VRFBeaconInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan func (_m *VRFBeaconInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1646,6 +1898,10 @@ func (_m *VRFBeaconInterface) WatchOwnershipTransferRequested(opts *bind.WatchOp func (_m *VRFBeaconInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1672,6 +1928,10 @@ func (_m *VRFBeaconInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, si func (_m *VRFBeaconInterface) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, transmitter []common.Address, current []common.Address, proposed []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, transmitter, current, proposed) + if len(ret) == 0 { + panic("no return value specified for WatchPayeeshipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1698,6 +1958,10 @@ func (_m *VRFBeaconInterface) WatchPayeeshipTransferRequested(opts *bind.WatchOp func (_m *VRFBeaconInterface) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, transmitter []common.Address, previous []common.Address, current []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, transmitter, previous, current) + if len(ret) == 0 { + panic("no return value specified for WatchPayeeshipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1724,6 +1988,10 @@ func (_m *VRFBeaconInterface) WatchPayeeshipTransferred(opts *bind.WatchOpts, si func (_m *VRFBeaconInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsFulfilled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) (event.Subscription, error)); ok { @@ -1750,6 +2018,10 @@ func (_m *VRFBeaconInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, si func (_m *VRFBeaconInterface) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessFulfillmentRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, []*big.Int) (event.Subscription, error)); ok { @@ -1776,6 +2048,10 @@ func (_m *VRFBeaconInterface) WatchRandomnessFulfillmentRequested(opts *bind.Wat func (_m *VRFBeaconInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRedeemed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -1802,6 +2078,10 @@ func (_m *VRFBeaconInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink func (_m *VRFBeaconInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRequested, []*big.Int) (event.Subscription, error)); ok { @@ -1828,6 +2108,10 @@ func (_m *VRFBeaconInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sin func (_m *VRFBeaconInterface) WithdrawFunds(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipient, amount) + if len(ret) == 0 { + panic("no return value specified for WithdrawFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -1854,6 +2138,10 @@ func (_m *VRFBeaconInterface) WithdrawFunds(opts *bind.TransactOpts, recipient c func (_m *VRFBeaconInterface) WithdrawPayment(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitter) + if len(ret) == 0 { + panic("no return value specified for WithdrawPayment") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go index 835702d136..c0f85d67e0 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ type VRFBeaconCoordinator struct { func (_m *VRFBeaconCoordinator) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetConfirmationDelays") + } + var r0 [8]*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([8]*big.Int, error)); ok { @@ -49,6 +53,10 @@ func (_m *VRFBeaconCoordinator) GetConfirmationDelays(opts *bind.CallOpts) ([8]* func (_m *VRFBeaconCoordinator) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for IBeaconPeriodBlocks") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -75,6 +83,10 @@ func (_m *VRFBeaconCoordinator) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.I func (_m *VRFBeaconCoordinator) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -101,6 +113,10 @@ func (_m *VRFBeaconCoordinator) ParseLog(log types.Log) (generated.AbigenLog, er func (_m *VRFBeaconCoordinator) SKeyID(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SKeyID") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { @@ -127,6 +143,10 @@ func (_m *VRFBeaconCoordinator) SKeyID(opts *bind.CallOpts) ([32]byte, error) { func (_m *VRFBeaconCoordinator) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SProvingKeyHash") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go index d5e373f4bc..4b2155bb4e 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type VRFCoordinatorInterface struct { func (_m *VRFCoordinatorInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *VRFCoordinatorInterface) AcceptOwnership(opts *bind.TransactOpts) (*ty func (_m *VRFCoordinatorInterface) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for AcceptSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *VRFCoordinatorInterface) AcceptSubscriptionOwnerTransfer(opts *bind.Tr func (_m *VRFCoordinatorInterface) AddConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for AddConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -106,6 +118,10 @@ func (_m *VRFCoordinatorInterface) AddConsumer(opts *bind.TransactOpts, subId *b func (_m *VRFCoordinatorInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -122,6 +138,10 @@ func (_m *VRFCoordinatorInterface) Address() common.Address { func (_m *VRFCoordinatorInterface) BatchTransferLink(opts *bind.TransactOpts, recipients []common.Address, paymentsInJuels []*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipients, paymentsInJuels) + if len(ret) == 0 { + panic("no return value specified for BatchTransferLink") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []*big.Int) (*types.Transaction, error)); ok { @@ -148,6 +168,10 @@ func (_m *VRFCoordinatorInterface) BatchTransferLink(opts *bind.TransactOpts, re func (_m *VRFCoordinatorInterface) CancelSubscription(opts *bind.TransactOpts, subId *big.Int, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, to) + if len(ret) == 0 { + panic("no return value specified for CancelSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -174,6 +198,10 @@ func (_m *VRFCoordinatorInterface) CancelSubscription(opts *bind.TransactOpts, s func (_m *VRFCoordinatorInterface) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CreateSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -200,6 +228,10 @@ func (_m *VRFCoordinatorInterface) CreateSubscription(opts *bind.TransactOpts) ( func (_m *VRFCoordinatorInterface) DeregisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { ret := _m.Called(opts, target) + if len(ret) == 0 { + panic("no return value specified for DeregisterMigratableCoordinator") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -226,6 +258,10 @@ func (_m *VRFCoordinatorInterface) DeregisterMigratableCoordinator(opts *bind.Tr func (_m *VRFCoordinatorInterface) FilterCallbackConfigSet(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCallbackConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator, error)); ok { @@ -252,6 +288,10 @@ func (_m *VRFCoordinatorInterface) FilterCallbackConfigSet(opts *bind.FilterOpts func (_m *VRFCoordinatorInterface) FilterCoordinatorConfigSet(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCoordinatorConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator, error)); ok { @@ -278,6 +318,10 @@ func (_m *VRFCoordinatorInterface) FilterCoordinatorConfigSet(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterCoordinatorDeregistered(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCoordinatorDeregistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator, error)); ok { @@ -304,6 +348,10 @@ func (_m *VRFCoordinatorInterface) FilterCoordinatorDeregistered(opts *bind.Filt func (_m *VRFCoordinatorInterface) FilterCoordinatorRegistered(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCoordinatorRegistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator, error)); ok { @@ -330,6 +378,10 @@ func (_m *VRFCoordinatorInterface) FilterCoordinatorRegistered(opts *bind.Filter func (_m *VRFCoordinatorInterface) FilterMigrationCompleted(opts *bind.FilterOpts, newVersion []uint8, subID []*big.Int) (*vrf_coordinator.VRFCoordinatorMigrationCompletedIterator, error) { ret := _m.Called(opts, newVersion, subID) + if len(ret) == 0 { + panic("no return value specified for FilterMigrationCompleted") + } + var r0 *vrf_coordinator.VRFCoordinatorMigrationCompletedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint8, []*big.Int) (*vrf_coordinator.VRFCoordinatorMigrationCompletedIterator, error)); ok { @@ -356,6 +408,10 @@ func (_m *VRFCoordinatorInterface) FilterMigrationCompleted(opts *bind.FilterOpt func (_m *VRFCoordinatorInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorOutputsServedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterOutputsServed") + } + var r0 *vrf_coordinator.VRFCoordinatorOutputsServedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorOutputsServedIterator, error)); ok { @@ -382,6 +438,10 @@ func (_m *VRFCoordinatorInterface) FilterOutputsServed(opts *bind.FilterOpts) (* func (_m *VRFCoordinatorInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator, error)); ok { @@ -408,6 +468,10 @@ func (_m *VRFCoordinatorInterface) FilterOwnershipTransferRequested(opts *bind.F func (_m *VRFCoordinatorInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator, error)); ok { @@ -434,6 +498,10 @@ func (_m *VRFCoordinatorInterface) FilterOwnershipTransferred(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterPauseFlagChanged(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterPauseFlagChanged") + } + var r0 *vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator, error)); ok { @@ -460,6 +528,10 @@ func (_m *VRFCoordinatorInterface) FilterPauseFlagChanged(opts *bind.FilterOpts) func (_m *VRFCoordinatorInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsFulfilled") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator, error)); ok { @@ -486,6 +558,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomWordsFulfilled(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessFulfillmentRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator, error)); ok { @@ -512,6 +588,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomnessFulfillmentRequested(opts *bi func (_m *VRFCoordinatorInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator, error) { ret := _m.Called(opts, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRedeemed") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator, error)); ok { @@ -538,6 +618,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomnessRedeemed(opts *bind.FilterOpt func (_m *VRFCoordinatorInterface) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator, error)); ok { @@ -564,6 +648,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomnessRequested(opts *bind.FilterOp func (_m *VRFCoordinatorInterface) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCanceled") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator, error)); ok { @@ -590,6 +678,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionCanceled(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator, error)); ok { @@ -616,6 +708,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerAdded(opts *bind.Fi func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator, error)); ok { @@ -642,6 +738,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerRemoved(opts *bind. func (_m *VRFCoordinatorInterface) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []*big.Int, owner []common.Address) (*vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator, error) { ret := _m.Called(opts, subId, owner) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCreated") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator, error)); ok { @@ -668,6 +768,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionCreated(opts *bind.FilterOp func (_m *VRFCoordinatorInterface) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionFunded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator, error)); ok { @@ -694,6 +798,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionFunded(opts *bind.FilterOpt func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error)); ok { @@ -720,6 +828,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferRequested(opts func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator, error)); ok { @@ -746,6 +858,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferred(opts *bind func (_m *VRFCoordinatorInterface) GetCallbackMemo(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { ret := _m.Called(opts, requestId) + if len(ret) == 0 { + panic("no return value specified for GetCallbackMemo") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([32]byte, error)); ok { @@ -772,6 +888,10 @@ func (_m *VRFCoordinatorInterface) GetCallbackMemo(opts *bind.CallOpts, requestI func (_m *VRFCoordinatorInterface) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetConfirmationDelays") + } + var r0 [8]*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([8]*big.Int, error)); ok { @@ -798,6 +918,10 @@ func (_m *VRFCoordinatorInterface) GetConfirmationDelays(opts *bind.CallOpts) ([ func (_m *VRFCoordinatorInterface) GetFee(opts *bind.CallOpts, arg0 *big.Int, arg1 []byte) (*big.Int, error) { ret := _m.Called(opts, arg0, arg1) + if len(ret) == 0 { + panic("no return value specified for GetFee") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, []byte) (*big.Int, error)); ok { @@ -824,6 +948,10 @@ func (_m *VRFCoordinatorInterface) GetFee(opts *bind.CallOpts, arg0 *big.Int, ar func (_m *VRFCoordinatorInterface) GetFulfillmentFee(opts *bind.CallOpts, arg0 *big.Int, callbackGasLimit uint32, arguments []byte, arg3 []byte) (*big.Int, error) { ret := _m.Called(opts, arg0, callbackGasLimit, arguments, arg3) + if len(ret) == 0 { + panic("no return value specified for GetFulfillmentFee") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, uint32, []byte, []byte) (*big.Int, error)); ok { @@ -850,6 +978,10 @@ func (_m *VRFCoordinatorInterface) GetFulfillmentFee(opts *bind.CallOpts, arg0 * func (_m *VRFCoordinatorInterface) GetSubscription(opts *bind.CallOpts, subId *big.Int) (vrf_coordinator.GetSubscription, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for GetSubscription") + } + var r0 vrf_coordinator.GetSubscription var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (vrf_coordinator.GetSubscription, error)); ok { @@ -874,6 +1006,10 @@ func (_m *VRFCoordinatorInterface) GetSubscription(opts *bind.CallOpts, subId *b func (_m *VRFCoordinatorInterface) GetSubscriptionLinkBalance(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetSubscriptionLinkBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -900,6 +1036,10 @@ func (_m *VRFCoordinatorInterface) GetSubscriptionLinkBalance(opts *bind.CallOpt func (_m *VRFCoordinatorInterface) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for IBeaconPeriodBlocks") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -926,6 +1066,10 @@ func (_m *VRFCoordinatorInterface) IBeaconPeriodBlocks(opts *bind.CallOpts) (*bi func (_m *VRFCoordinatorInterface) ILink(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for ILink") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -952,6 +1096,10 @@ func (_m *VRFCoordinatorInterface) ILink(opts *bind.CallOpts) (common.Address, e func (_m *VRFCoordinatorInterface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXCONSUMERS") + } + var r0 uint16 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint16, error)); ok { @@ -976,6 +1124,10 @@ func (_m *VRFCoordinatorInterface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, er func (_m *VRFCoordinatorInterface) MAXNUMWORDS(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXNUMWORDS") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -1002,6 +1154,10 @@ func (_m *VRFCoordinatorInterface) MAXNUMWORDS(opts *bind.CallOpts) (*big.Int, e func (_m *VRFCoordinatorInterface) Migrate(opts *bind.TransactOpts, newCoordinator common.Address, encodedRequest []byte) (*types.Transaction, error) { ret := _m.Called(opts, newCoordinator, encodedRequest) + if len(ret) == 0 { + panic("no return value specified for Migrate") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, []byte) (*types.Transaction, error)); ok { @@ -1028,6 +1184,10 @@ func (_m *VRFCoordinatorInterface) Migrate(opts *bind.TransactOpts, newCoordinat func (_m *VRFCoordinatorInterface) MigrationVersion(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MigrationVersion") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -1052,6 +1212,10 @@ func (_m *VRFCoordinatorInterface) MigrationVersion(opts *bind.CallOpts) (uint8, func (_m *VRFCoordinatorInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for NUMCONFDELAYS") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -1076,6 +1240,10 @@ func (_m *VRFCoordinatorInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, er func (_m *VRFCoordinatorInterface) OnMigration(opts *bind.CallOpts, arg0 []byte) error { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for OnMigration") + } + var r0 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, []byte) error); ok { r0 = rf(opts, arg0) @@ -1090,6 +1258,10 @@ func (_m *VRFCoordinatorInterface) OnMigration(opts *bind.CallOpts, arg0 []byte) func (_m *VRFCoordinatorInterface) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { ret := _m.Called(opts, arg0, amount, data) + if len(ret) == 0 { + panic("no return value specified for OnTokenTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1116,6 +1288,10 @@ func (_m *VRFCoordinatorInterface) OnTokenTransfer(opts *bind.TransactOpts, arg0 func (_m *VRFCoordinatorInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1142,6 +1318,10 @@ func (_m *VRFCoordinatorInterface) Owner(opts *bind.CallOpts) (common.Address, e func (_m *VRFCoordinatorInterface) ParseCallbackConfigSet(log types.Log) (*vrf_coordinator.VRFCoordinatorCallbackConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCallbackConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCallbackConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCallbackConfigSet, error)); ok { @@ -1168,6 +1348,10 @@ func (_m *VRFCoordinatorInterface) ParseCallbackConfigSet(log types.Log) (*vrf_c func (_m *VRFCoordinatorInterface) ParseCoordinatorConfigSet(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCoordinatorConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSet, error)); ok { @@ -1194,6 +1378,10 @@ func (_m *VRFCoordinatorInterface) ParseCoordinatorConfigSet(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParseCoordinatorDeregistered(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCoordinatorDeregistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregistered, error)); ok { @@ -1220,6 +1408,10 @@ func (_m *VRFCoordinatorInterface) ParseCoordinatorDeregistered(log types.Log) ( func (_m *VRFCoordinatorInterface) ParseCoordinatorRegistered(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorRegistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCoordinatorRegistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorRegistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorRegistered, error)); ok { @@ -1246,6 +1438,10 @@ func (_m *VRFCoordinatorInterface) ParseCoordinatorRegistered(log types.Log) (*v func (_m *VRFCoordinatorInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -1272,6 +1468,10 @@ func (_m *VRFCoordinatorInterface) ParseLog(log types.Log) (generated.AbigenLog, func (_m *VRFCoordinatorInterface) ParseMigrationCompleted(log types.Log) (*vrf_coordinator.VRFCoordinatorMigrationCompleted, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseMigrationCompleted") + } + var r0 *vrf_coordinator.VRFCoordinatorMigrationCompleted var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorMigrationCompleted, error)); ok { @@ -1298,6 +1498,10 @@ func (_m *VRFCoordinatorInterface) ParseMigrationCompleted(log types.Log) (*vrf_ func (_m *VRFCoordinatorInterface) ParseOutputsServed(log types.Log) (*vrf_coordinator.VRFCoordinatorOutputsServed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOutputsServed") + } + var r0 *vrf_coordinator.VRFCoordinatorOutputsServed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOutputsServed, error)); ok { @@ -1324,6 +1528,10 @@ func (_m *VRFCoordinatorInterface) ParseOutputsServed(log types.Log) (*vrf_coord func (_m *VRFCoordinatorInterface) ParseOwnershipTransferRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, error)); ok { @@ -1350,6 +1558,10 @@ func (_m *VRFCoordinatorInterface) ParseOwnershipTransferRequested(log types.Log func (_m *VRFCoordinatorInterface) ParseOwnershipTransferred(log types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferred, error)); ok { @@ -1376,6 +1588,10 @@ func (_m *VRFCoordinatorInterface) ParseOwnershipTransferred(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParsePauseFlagChanged(log types.Log) (*vrf_coordinator.VRFCoordinatorPauseFlagChanged, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePauseFlagChanged") + } + var r0 *vrf_coordinator.VRFCoordinatorPauseFlagChanged var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorPauseFlagChanged, error)); ok { @@ -1402,6 +1618,10 @@ func (_m *VRFCoordinatorInterface) ParsePauseFlagChanged(log types.Log) (*vrf_co func (_m *VRFCoordinatorInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsFulfilled") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled, error)); ok { @@ -1428,6 +1648,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomWordsFulfilled(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParseRandomnessFulfillmentRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessFulfillmentRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, error)); ok { @@ -1454,6 +1678,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomnessFulfillmentRequested(log types func (_m *VRFCoordinatorInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRedeemed") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRedeemed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemed, error)); ok { @@ -1480,6 +1708,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_ func (_m *VRFCoordinatorInterface) ParseRandomnessRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRequested, error)); ok { @@ -1506,6 +1738,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomnessRequested(log types.Log) (*vrf func (_m *VRFCoordinatorInterface) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCanceled") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCanceled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceled, error)); ok { @@ -1532,6 +1768,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionCanceled(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerAdded(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, error)); ok { @@ -1558,6 +1798,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerAdded(log types.Log) func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerRemoved(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, error)); ok { @@ -1584,6 +1828,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerRemoved(log types.Lo func (_m *VRFCoordinatorInterface) ParseSubscriptionCreated(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCreated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCreated") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCreated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCreated, error)); ok { @@ -1610,6 +1858,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionCreated(log types.Log) (*vrf func (_m *VRFCoordinatorInterface) ParseSubscriptionFunded(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionFunded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionFunded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionFunded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionFunded, error)); ok { @@ -1636,6 +1888,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionFunded(log types.Log) (*vrf_ func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, error)); ok { @@ -1662,6 +1918,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferRequested(log t func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferred(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, error)); ok { @@ -1688,6 +1948,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferred(log types.L func (_m *VRFCoordinatorInterface) ProcessVRFOutputs(opts *bind.TransactOpts, vrfOutputs []vrf_coordinator.VRFBeaconTypesVRFOutput, juelsPerFeeCoin *big.Int, reasonableGasPrice uint64, blockHeight uint64) (*types.Transaction, error) { ret := _m.Called(opts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) + if len(ret) == 0 { + panic("no return value specified for ProcessVRFOutputs") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []vrf_coordinator.VRFBeaconTypesVRFOutput, *big.Int, uint64, uint64) (*types.Transaction, error)); ok { @@ -1714,6 +1978,10 @@ func (_m *VRFCoordinatorInterface) ProcessVRFOutputs(opts *bind.TransactOpts, vr func (_m *VRFCoordinatorInterface) RedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int, arg2 []byte) (*types.Transaction, error) { ret := _m.Called(opts, subID, requestID, arg2) + if len(ret) == 0 { + panic("no return value specified for RedeemRandomness") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1740,6 +2008,10 @@ func (_m *VRFCoordinatorInterface) RedeemRandomness(opts *bind.TransactOpts, sub func (_m *VRFCoordinatorInterface) RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { ret := _m.Called(opts, target) + if len(ret) == 0 { + panic("no return value specified for RegisterMigratableCoordinator") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1766,6 +2038,10 @@ func (_m *VRFCoordinatorInterface) RegisterMigratableCoordinator(opts *bind.Tran func (_m *VRFCoordinatorInterface) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for RemoveConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -1792,6 +2068,10 @@ func (_m *VRFCoordinatorInterface) RemoveConsumer(opts *bind.TransactOpts, subId func (_m *VRFCoordinatorInterface) RequestRandomness(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, arg3 []byte) (*types.Transaction, error) { ret := _m.Called(opts, subID, numWords, confDelay, arg3) + if len(ret) == 0 { + panic("no return value specified for RequestRandomness") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1818,6 +2098,10 @@ func (_m *VRFCoordinatorInterface) RequestRandomness(opts *bind.TransactOpts, su func (_m *VRFCoordinatorInterface) RequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte, arg5 []byte) (*types.Transaction, error) { ret := _m.Called(opts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) + if len(ret) == 0 { + panic("no return value specified for RequestRandomnessFulfillment") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, uint32, []byte, []byte) (*types.Transaction, error)); ok { @@ -1844,6 +2128,10 @@ func (_m *VRFCoordinatorInterface) RequestRandomnessFulfillment(opts *bind.Trans func (_m *VRFCoordinatorInterface) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int, newOwner common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, newOwner) + if len(ret) == 0 { + panic("no return value specified for RequestSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -1870,6 +2158,10 @@ func (_m *VRFCoordinatorInterface) RequestSubscriptionOwnerTransfer(opts *bind.T func (_m *VRFCoordinatorInterface) SCallbackConfig(opts *bind.CallOpts) (vrf_coordinator.SCallbackConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SCallbackConfig") + } + var r0 vrf_coordinator.SCallbackConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator.SCallbackConfig, error)); ok { @@ -1894,6 +2186,10 @@ func (_m *VRFCoordinatorInterface) SCallbackConfig(opts *bind.CallOpts) (vrf_coo func (_m *VRFCoordinatorInterface) SCoordinatorConfig(opts *bind.CallOpts) (vrf_coordinator.SCoordinatorConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SCoordinatorConfig") + } + var r0 vrf_coordinator.SCoordinatorConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator.SCoordinatorConfig, error)); ok { @@ -1918,6 +2214,10 @@ func (_m *VRFCoordinatorInterface) SCoordinatorConfig(opts *bind.CallOpts) (vrf_ func (_m *VRFCoordinatorInterface) SPendingRequests(opts *bind.CallOpts, arg0 *big.Int) (vrf_coordinator.SPendingRequests, error) { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for SPendingRequests") + } + var r0 vrf_coordinator.SPendingRequests var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (vrf_coordinator.SPendingRequests, error)); ok { @@ -1942,6 +2242,10 @@ func (_m *VRFCoordinatorInterface) SPendingRequests(opts *bind.CallOpts, arg0 *b func (_m *VRFCoordinatorInterface) SProducer(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SProducer") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1968,6 +2272,10 @@ func (_m *VRFCoordinatorInterface) SProducer(opts *bind.CallOpts) (common.Addres func (_m *VRFCoordinatorInterface) SetCallbackConfig(opts *bind.TransactOpts, config vrf_coordinator.VRFCoordinatorCallbackConfig) (*types.Transaction, error) { ret := _m.Called(opts, config) + if len(ret) == 0 { + panic("no return value specified for SetCallbackConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFCoordinatorCallbackConfig) (*types.Transaction, error)); ok { @@ -1994,6 +2302,10 @@ func (_m *VRFCoordinatorInterface) SetCallbackConfig(opts *bind.TransactOpts, co func (_m *VRFCoordinatorInterface) SetConfirmationDelays(opts *bind.TransactOpts, confDelays [8]*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, confDelays) + if len(ret) == 0 { + panic("no return value specified for SetConfirmationDelays") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [8]*big.Int) (*types.Transaction, error)); ok { @@ -2020,6 +2332,10 @@ func (_m *VRFCoordinatorInterface) SetConfirmationDelays(opts *bind.TransactOpts func (_m *VRFCoordinatorInterface) SetCoordinatorConfig(opts *bind.TransactOpts, coordinatorConfig vrf_coordinator.VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error) { ret := _m.Called(opts, coordinatorConfig) + if len(ret) == 0 { + panic("no return value specified for SetCoordinatorConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error)); ok { @@ -2046,6 +2362,10 @@ func (_m *VRFCoordinatorInterface) SetCoordinatorConfig(opts *bind.TransactOpts, func (_m *VRFCoordinatorInterface) SetPauseFlag(opts *bind.TransactOpts, pause bool) (*types.Transaction, error) { ret := _m.Called(opts, pause) + if len(ret) == 0 { + panic("no return value specified for SetPauseFlag") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, bool) (*types.Transaction, error)); ok { @@ -2072,6 +2392,10 @@ func (_m *VRFCoordinatorInterface) SetPauseFlag(opts *bind.TransactOpts, pause b func (_m *VRFCoordinatorInterface) SetProducer(opts *bind.TransactOpts, producer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, producer) + if len(ret) == 0 { + panic("no return value specified for SetProducer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -2098,6 +2422,10 @@ func (_m *VRFCoordinatorInterface) SetProducer(opts *bind.TransactOpts, producer func (_m *VRFCoordinatorInterface) TransferLink(opts *bind.TransactOpts, recipient common.Address, juelsAmount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipient, juelsAmount) + if len(ret) == 0 { + panic("no return value specified for TransferLink") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -2124,6 +2452,10 @@ func (_m *VRFCoordinatorInterface) TransferLink(opts *bind.TransactOpts, recipie func (_m *VRFCoordinatorInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -2150,6 +2482,10 @@ func (_m *VRFCoordinatorInterface) TransferOwnership(opts *bind.TransactOpts, to func (_m *VRFCoordinatorInterface) WatchCallbackConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCallbackConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) (event.Subscription, error)); ok { @@ -2176,6 +2512,10 @@ func (_m *VRFCoordinatorInterface) WatchCallbackConfigSet(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchCoordinatorConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCoordinatorConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error)); ok { @@ -2202,6 +2542,10 @@ func (_m *VRFCoordinatorInterface) WatchCoordinatorConfigSet(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchCoordinatorDeregistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCoordinatorDeregistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error)); ok { @@ -2228,6 +2572,10 @@ func (_m *VRFCoordinatorInterface) WatchCoordinatorDeregistered(opts *bind.Watch func (_m *VRFCoordinatorInterface) WatchCoordinatorRegistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCoordinatorRegistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) (event.Subscription, error)); ok { @@ -2254,6 +2602,10 @@ func (_m *VRFCoordinatorInterface) WatchCoordinatorRegistered(opts *bind.WatchOp func (_m *VRFCoordinatorInterface) WatchMigrationCompleted(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, newVersion []uint8, subID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, newVersion, subID) + if len(ret) == 0 { + panic("no return value specified for WatchMigrationCompleted") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, []uint8, []*big.Int) (event.Subscription, error)); ok { @@ -2280,6 +2632,10 @@ func (_m *VRFCoordinatorInterface) WatchMigrationCompleted(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchOutputsServed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) (event.Subscription, error)); ok { @@ -2306,6 +2662,10 @@ func (_m *VRFCoordinatorInterface) WatchOutputsServed(opts *bind.WatchOpts, sink func (_m *VRFCoordinatorInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -2332,6 +2692,10 @@ func (_m *VRFCoordinatorInterface) WatchOwnershipTransferRequested(opts *bind.Wa func (_m *VRFCoordinatorInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -2358,6 +2722,10 @@ func (_m *VRFCoordinatorInterface) WatchOwnershipTransferred(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchPauseFlagChanged(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchPauseFlagChanged") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) (event.Subscription, error)); ok { @@ -2384,6 +2752,10 @@ func (_m *VRFCoordinatorInterface) WatchPauseFlagChanged(opts *bind.WatchOpts, s func (_m *VRFCoordinatorInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsFulfilled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error)); ok { @@ -2410,6 +2782,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessFulfillmentRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, []*big.Int) (event.Subscription, error)); ok { @@ -2436,6 +2812,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomnessFulfillmentRequested(opts *bin func (_m *VRFCoordinatorInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRedeemed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -2462,6 +2842,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, []*big.Int) (event.Subscription, error)); ok { @@ -2488,6 +2872,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomnessRequested(opts *bind.WatchOpts func (_m *VRFCoordinatorInterface) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCanceled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, []*big.Int) (event.Subscription, error)); ok { @@ -2514,6 +2902,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionCanceled(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerAdded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, []*big.Int) (event.Subscription, error)); ok { @@ -2540,6 +2932,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerAdded(opts *bind.Wat func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, []*big.Int) (event.Subscription, error)); ok { @@ -2566,6 +2962,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerRemoved(opts *bind.W func (_m *VRFCoordinatorInterface) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, subId []*big.Int, owner []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, subId, owner) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCreated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -2592,6 +2992,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionCreated(opts *bind.WatchOpts func (_m *VRFCoordinatorInterface) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionFunded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, []*big.Int) (event.Subscription, error)); ok { @@ -2618,6 +3022,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionFunded(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, []*big.Int) (event.Subscription, error)); ok { @@ -2644,6 +3052,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferRequested(opts func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, []*big.Int) (event.Subscription, error)); ok { diff --git a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go index ba97eda30b..418cb27601 100644 --- a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go +++ b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/threshold/mocks/decryptor.go b/core/services/ocr2/plugins/threshold/mocks/decryptor.go index 4b91cbbd26..5496483c9d 100644 --- a/core/services/ocr2/plugins/threshold/mocks/decryptor.go +++ b/core/services/ocr2/plugins/threshold/mocks/decryptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type Decryptor struct { func (_m *Decryptor) Decrypt(ctx context.Context, ciphertextId decryptionplugin.CiphertextId, ciphertext []byte) ([]byte, error) { ret := _m.Called(ctx, ciphertextId, ciphertext) + if len(ret) == 0 { + panic("no return value specified for Decrypt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, decryptionplugin.CiphertextId, []byte) ([]byte, error)); ok { diff --git a/core/services/pg/mocks/event_broadcaster.go b/core/services/pg/mocks/event_broadcaster.go index b4d04b8b99..63f06db494 100644 --- a/core/services/pg/mocks/event_broadcaster.go +++ b/core/services/pg/mocks/event_broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type EventBroadcaster struct { func (_m *EventBroadcaster) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *EventBroadcaster) Close() error { func (_m *EventBroadcaster) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *EventBroadcaster) HealthReport() map[string]error { func (_m *EventBroadcaster) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -62,6 +74,10 @@ func (_m *EventBroadcaster) Name() string { func (_m *EventBroadcaster) Notify(channel string, payload string) error { ret := _m.Called(channel, payload) + if len(ret) == 0 { + panic("no return value specified for Notify") + } + var r0 error if rf, ok := ret.Get(0).(func(string, string) error); ok { r0 = rf(channel, payload) @@ -76,6 +92,10 @@ func (_m *EventBroadcaster) Notify(channel string, payload string) error { func (_m *EventBroadcaster) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -90,6 +110,10 @@ func (_m *EventBroadcaster) Ready() error { func (_m *EventBroadcaster) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -104,6 +128,10 @@ func (_m *EventBroadcaster) Start(_a0 context.Context) error { func (_m *EventBroadcaster) Subscribe(channel string, payloadFilter string) (pg.Subscription, error) { ret := _m.Called(channel, payloadFilter) + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + var r0 pg.Subscription var r1 error if rf, ok := ret.Get(0).(func(string, string) (pg.Subscription, error)); ok { diff --git a/core/services/pg/mocks/subscription.go b/core/services/pg/mocks/subscription.go index 9cfe4c4f02..fcd194004d 100644 --- a/core/services/pg/mocks/subscription.go +++ b/core/services/pg/mocks/subscription.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Subscription struct { func (_m *Subscription) ChannelName() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChannelName") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -35,6 +39,10 @@ func (_m *Subscription) Close() { func (_m *Subscription) Events() <-chan pg.Event { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Events") + } + var r0 <-chan pg.Event if rf, ok := ret.Get(0).(func() <-chan pg.Event); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *Subscription) Events() <-chan pg.Event { func (_m *Subscription) InterestedIn(event pg.Event) bool { ret := _m.Called(event) + if len(ret) == 0 { + panic("no return value specified for InterestedIn") + } + var r0 bool if rf, ok := ret.Get(0).(func(pg.Event) bool); ok { r0 = rf(event) diff --git a/core/services/pipeline/mocks/config.go b/core/services/pipeline/mocks/config.go index eb9a411f42..4cd6bc7a72 100644 --- a/core/services/pipeline/mocks/config.go +++ b/core/services/pipeline/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type Config struct { func (_m *Config) DefaultHTTPLimit() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DefaultHTTPLimit") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *Config) DefaultHTTPLimit() int64 { func (_m *Config) DefaultHTTPTimeout() models.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DefaultHTTPTimeout") + } + var r0 models.Duration if rf, ok := ret.Get(0).(func() models.Duration); ok { r0 = rf() @@ -46,6 +54,10 @@ func (_m *Config) DefaultHTTPTimeout() models.Duration { func (_m *Config) MaxRunDuration() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for MaxRunDuration") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -60,6 +72,10 @@ func (_m *Config) MaxRunDuration() time.Duration { func (_m *Config) ReaperInterval() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReaperInterval") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -74,6 +90,10 @@ func (_m *Config) ReaperInterval() time.Duration { func (_m *Config) ReaperThreshold() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReaperThreshold") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() diff --git a/core/services/pipeline/mocks/orm.go b/core/services/pipeline/mocks/orm.go index 88d067c6ff..759686204d 100644 --- a/core/services/pipeline/mocks/orm.go +++ b/core/services/pipeline/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -26,6 +26,10 @@ type ORM struct { func (_m *ORM) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -47,6 +51,10 @@ func (_m *ORM) CreateRun(run *pipeline.Run, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateRun") + } + var r0 error if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) error); ok { r0 = rf(run, qopts...) @@ -68,6 +76,10 @@ func (_m *ORM) CreateSpec(_a0 pipeline.Pipeline, maxTaskTimeout models.Interval, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateSpec") + } + var r0 int32 var r1 error if rf, ok := ret.Get(0).(func(pipeline.Pipeline, models.Interval, ...pg.QOpt) (int32, error)); ok { @@ -92,6 +104,10 @@ func (_m *ORM) CreateSpec(_a0 pipeline.Pipeline, maxTaskTimeout models.Interval, func (_m *ORM) DeleteRun(id int64) error { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for DeleteRun") + } + var r0 error if rf, ok := ret.Get(0).(func(int64) error); ok { r0 = rf(id) @@ -106,6 +122,10 @@ func (_m *ORM) DeleteRun(id int64) error { func (_m *ORM) DeleteRunsOlderThan(_a0 context.Context, _a1 time.Duration) error { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for DeleteRunsOlderThan") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration) error); ok { r0 = rf(_a0, _a1) @@ -120,6 +140,10 @@ func (_m *ORM) DeleteRunsOlderThan(_a0 context.Context, _a1 time.Duration) error func (_m *ORM) FindRun(id int64) (pipeline.Run, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for FindRun") + } + var r0 pipeline.Run var r1 error if rf, ok := ret.Get(0).(func(int64) (pipeline.Run, error)); ok { @@ -144,6 +168,10 @@ func (_m *ORM) FindRun(id int64) (pipeline.Run, error) { func (_m *ORM) GetAllRuns() ([]pipeline.Run, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAllRuns") + } + var r0 []pipeline.Run var r1 error if rf, ok := ret.Get(0).(func() ([]pipeline.Run, error)); ok { @@ -170,6 +198,10 @@ func (_m *ORM) GetAllRuns() ([]pipeline.Run, error) { func (_m *ORM) GetQ() pg.Q { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetQ") + } + var r0 pg.Q if rf, ok := ret.Get(0).(func() pg.Q); ok { r0 = rf() @@ -184,6 +216,10 @@ func (_m *ORM) GetQ() pg.Q { func (_m *ORM) GetUnfinishedRuns(_a0 context.Context, _a1 time.Time, _a2 func(pipeline.Run) error) error { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for GetUnfinishedRuns") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, func(pipeline.Run) error) error); ok { r0 = rf(_a0, _a1, _a2) @@ -198,6 +234,10 @@ func (_m *ORM) GetUnfinishedRuns(_a0 context.Context, _a1 time.Time, _a2 func(pi func (_m *ORM) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -221,6 +261,10 @@ func (_m *ORM) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertFinishedRun") + } + var r0 error if rf, ok := ret.Get(0).(func(*pipeline.Run, bool, ...pg.QOpt) error); ok { r0 = rf(run, saveSuccessfulTaskRuns, qopts...) @@ -242,6 +286,10 @@ func (_m *ORM) InsertFinishedRuns(run []*pipeline.Run, saveSuccessfulTaskRuns bo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertFinishedRuns") + } + var r0 error if rf, ok := ret.Get(0).(func([]*pipeline.Run, bool, ...pg.QOpt) error); ok { r0 = rf(run, saveSuccessfulTaskRuns, qopts...) @@ -263,6 +311,10 @@ func (_m *ORM) InsertRun(run *pipeline.Run, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertRun") + } + var r0 error if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) error); ok { r0 = rf(run, qopts...) @@ -277,6 +329,10 @@ func (_m *ORM) InsertRun(run *pipeline.Run, qopts ...pg.QOpt) error { func (_m *ORM) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -291,6 +347,10 @@ func (_m *ORM) Name() string { func (_m *ORM) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -305,6 +365,10 @@ func (_m *ORM) Ready() error { func (_m *ORM) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -326,6 +390,10 @@ func (_m *ORM) StoreRun(run *pipeline.Run, qopts ...pg.QOpt) (bool, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for StoreRun") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) (bool, error)); ok { @@ -350,6 +418,10 @@ func (_m *ORM) StoreRun(run *pipeline.Run, qopts ...pg.QOpt) (bool, error) { func (_m *ORM) UpdateTaskRunResult(taskID uuid.UUID, result pipeline.Result) (pipeline.Run, bool, error) { ret := _m.Called(taskID, result) + if len(ret) == 0 { + panic("no return value specified for UpdateTaskRunResult") + } + var r0 pipeline.Run var r1 bool var r2 error diff --git a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go index 3478ce1322..40f2ba4dd3 100644 --- a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go +++ b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type PipelineParamUnmarshaler struct { func (_m *PipelineParamUnmarshaler) UnmarshalPipelineParam(val interface{}) error { ret := _m.Called(val) + if len(ret) == 0 { + panic("no return value specified for UnmarshalPipelineParam") + } + var r0 error if rf, ok := ret.Get(0).(func(interface{}) error); ok { r0 = rf(val) diff --git a/core/services/pipeline/mocks/runner.go b/core/services/pipeline/mocks/runner.go index 34b5539975..f6e5033eae 100644 --- a/core/services/pipeline/mocks/runner.go +++ b/core/services/pipeline/mocks/runner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type Runner struct { func (_m *Runner) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *Runner) Close() error { func (_m *Runner) ExecuteAndInsertFinishedRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger, saveSuccessfulTaskRuns bool) (int64, pipeline.FinalResult, error) { ret := _m.Called(ctx, spec, vars, l, saveSuccessfulTaskRuns) + if len(ret) == 0 { + panic("no return value specified for ExecuteAndInsertFinishedRun") + } + var r0 int64 var r1 pipeline.FinalResult var r2 error @@ -69,6 +77,10 @@ func (_m *Runner) ExecuteAndInsertFinishedRun(ctx context.Context, spec pipeline func (_m *Runner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (*pipeline.Run, pipeline.TaskRunResults, error) { ret := _m.Called(ctx, spec, vars, l) + if len(ret) == 0 { + panic("no return value specified for ExecuteRun") + } + var r0 *pipeline.Run var r1 pipeline.TaskRunResults var r2 error @@ -104,6 +116,10 @@ func (_m *Runner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipel func (_m *Runner) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -127,6 +143,10 @@ func (_m *Runner) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertFinishedRun") + } + var r0 error if rf, ok := ret.Get(0).(func(*pipeline.Run, bool, ...pg.QOpt) error); ok { r0 = rf(run, saveSuccessfulTaskRuns, qopts...) @@ -148,6 +168,10 @@ func (_m *Runner) InsertFinishedRuns(runs []*pipeline.Run, saveSuccessfulTaskRun _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertFinishedRuns") + } + var r0 error if rf, ok := ret.Get(0).(func([]*pipeline.Run, bool, ...pg.QOpt) error); ok { r0 = rf(runs, saveSuccessfulTaskRuns, qopts...) @@ -162,6 +186,10 @@ func (_m *Runner) InsertFinishedRuns(runs []*pipeline.Run, saveSuccessfulTaskRun func (_m *Runner) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -181,6 +209,10 @@ func (_m *Runner) OnRunFinished(_a0 func(*pipeline.Run)) { func (_m *Runner) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -195,6 +227,10 @@ func (_m *Runner) Ready() error { func (_m *Runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) error { ret := _m.Called(taskID, value, err) + if len(ret) == 0 { + panic("no return value specified for ResumeRun") + } + var r0 error if rf, ok := ret.Get(0).(func(uuid.UUID, interface{}, error) error); ok { r0 = rf(taskID, value, err) @@ -209,6 +245,10 @@ func (_m *Runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) erro func (_m *Runner) Run(ctx context.Context, run *pipeline.Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(pg.Queryer) error) (bool, error) { ret := _m.Called(ctx, run, l, saveSuccessfulTaskRuns, fn) + if len(ret) == 0 { + panic("no return value specified for Run") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run, logger.Logger, bool, func(pg.Queryer) error) (bool, error)); ok { @@ -233,6 +273,10 @@ func (_m *Runner) Run(ctx context.Context, run *pipeline.Run, l logger.Logger, s func (_m *Runner) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/relay/evm/mercury/mocks/async_deleter.go b/core/services/relay/evm/mercury/mocks/async_deleter.go index c0f583efd1..b706e9c771 100644 --- a/core/services/relay/evm/mercury/mocks/async_deleter.go +++ b/core/services/relay/evm/mercury/mocks/async_deleter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 0376c9f27a..5b927f1b8a 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -22,6 +22,10 @@ type LoopRelayAdapter struct { func (_m *LoopRelayAdapter) Chain() legacyevm.Chain { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Chain") + } + var r0 legacyevm.Chain if rf, ok := ret.Get(0).(func() legacyevm.Chain); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *LoopRelayAdapter) Chain() legacyevm.Chain { func (_m *LoopRelayAdapter) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -52,6 +60,10 @@ func (_m *LoopRelayAdapter) Close() error { func (_m *LoopRelayAdapter) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetChainStatus") + } + var r0 types.ChainStatus var r1 error if rf, ok := ret.Get(0).(func(context.Context) (types.ChainStatus, error)); ok { @@ -76,6 +88,10 @@ func (_m *LoopRelayAdapter) GetChainStatus(ctx context.Context) (types.ChainStat func (_m *LoopRelayAdapter) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -92,6 +108,10 @@ func (_m *LoopRelayAdapter) HealthReport() map[string]error { func (_m *LoopRelayAdapter) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) ([]types.NodeStatus, string, int, error) { ret := _m.Called(ctx, pageSize, pageToken) + if len(ret) == 0 { + panic("no return value specified for ListNodeStatuses") + } + var r0 []types.NodeStatus var r1 string var r2 int @@ -132,6 +152,10 @@ func (_m *LoopRelayAdapter) ListNodeStatuses(ctx context.Context, pageSize int32 func (_m *LoopRelayAdapter) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -146,6 +170,10 @@ func (_m *LoopRelayAdapter) Name() string { func (_m *LoopRelayAdapter) NewConfigProvider(_a0 context.Context, _a1 types.RelayArgs) (types.ConfigProvider, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for NewConfigProvider") + } + var r0 types.ConfigProvider var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs) (types.ConfigProvider, error)); ok { @@ -172,6 +200,10 @@ func (_m *LoopRelayAdapter) NewConfigProvider(_a0 context.Context, _a1 types.Rel func (_m *LoopRelayAdapter) NewPluginProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.PluginProvider, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for NewPluginProvider") + } + var r0 types.PluginProvider var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.PluginProvider, error)); ok { @@ -198,6 +230,10 @@ func (_m *LoopRelayAdapter) NewPluginProvider(_a0 context.Context, _a1 types.Rel func (_m *LoopRelayAdapter) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -212,6 +248,10 @@ func (_m *LoopRelayAdapter) Ready() error { func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -226,6 +266,10 @@ func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { func (_m *LoopRelayAdapter) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { ret := _m.Called(ctx, from, to, amount, balanceCheck) + if len(ret) == 0 { + panic("no return value specified for Transact") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { r0 = rf(ctx, from, to, amount, balanceCheck) diff --git a/core/services/relay/evm/mocks/request_round_db.go b/core/services/relay/evm/mocks/request_round_db.go index 1727e8cc47..eb27e8bd52 100644 --- a/core/services/relay/evm/mocks/request_round_db.go +++ b/core/services/relay/evm/mocks/request_round_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type RequestRoundDB struct { func (_m *RequestRoundDB) LoadLatestRoundRequested() (ocr2aggregator.OCR2AggregatorRoundRequested, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LoadLatestRoundRequested") + } + var r0 ocr2aggregator.OCR2AggregatorRoundRequested var r1 error if rf, ok := ret.Get(0).(func() (ocr2aggregator.OCR2AggregatorRoundRequested, error)); ok { @@ -41,6 +45,10 @@ func (_m *RequestRoundDB) LoadLatestRoundRequested() (ocr2aggregator.OCR2Aggrega func (_m *RequestRoundDB) SaveLatestRoundRequested(tx pg.Queryer, rr ocr2aggregator.OCR2AggregatorRoundRequested) error { ret := _m.Called(tx, rr) + if len(ret) == 0 { + panic("no return value specified for SaveLatestRoundRequested") + } + var r0 error if rf, ok := ret.Get(0).(func(pg.Queryer, ocr2aggregator.OCR2AggregatorRoundRequested) error); ok { r0 = rf(tx, rr) diff --git a/core/services/relay/evm/types/mocks/log_poller_wrapper.go b/core/services/relay/evm/types/mocks/log_poller_wrapper.go index 6812ce5aba..675cf317b1 100644 --- a/core/services/relay/evm/types/mocks/log_poller_wrapper.go +++ b/core/services/relay/evm/types/mocks/log_poller_wrapper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type LogPollerWrapper struct { func (_m *LogPollerWrapper) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *LogPollerWrapper) Close() error { func (_m *LogPollerWrapper) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *LogPollerWrapper) HealthReport() map[string]error { func (_m *LogPollerWrapper) LatestEvents() ([]types.OracleRequest, []types.OracleResponse, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestEvents") + } + var r0 []types.OracleRequest var r1 []types.OracleResponse var r2 error @@ -83,6 +95,10 @@ func (_m *LogPollerWrapper) LatestEvents() ([]types.OracleRequest, []types.Oracl func (_m *LogPollerWrapper) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -97,6 +113,10 @@ func (_m *LogPollerWrapper) Name() string { func (_m *LogPollerWrapper) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -111,6 +131,10 @@ func (_m *LogPollerWrapper) Ready() error { func (_m *LogPollerWrapper) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/s4/mocks/orm.go b/core/services/s4/mocks/orm.go index f053af9ca7..706c119429 100644 --- a/core/services/s4/mocks/orm.go +++ b/core/services/s4/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ func (_m *ORM) DeleteExpired(limit uint, utcNow time.Time, qopts ...pg.QOpt) (in _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteExpired") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(uint, time.Time, ...pg.QOpt) (int64, error)); ok { @@ -59,6 +63,10 @@ func (_m *ORM) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *s4.Row var r1 error if rf, ok := ret.Get(0).(func(*utils.Big, uint, ...pg.QOpt) (*s4.Row, error)); ok { @@ -92,6 +100,10 @@ func (_m *ORM) GetSnapshot(addressRange *s4.AddressRange, qopts ...pg.QOpt) ([]* _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetSnapshot") + } + var r0 []*s4.SnapshotRow var r1 error if rf, ok := ret.Get(0).(func(*s4.AddressRange, ...pg.QOpt) ([]*s4.SnapshotRow, error)); ok { @@ -125,6 +137,10 @@ func (_m *ORM) GetUnconfirmedRows(limit uint, qopts ...pg.QOpt) ([]*s4.Row, erro _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetUnconfirmedRows") + } + var r0 []*s4.Row var r1 error if rf, ok := ret.Get(0).(func(uint, ...pg.QOpt) ([]*s4.Row, error)); ok { @@ -158,6 +174,10 @@ func (_m *ORM) Update(row *s4.Row, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(*s4.Row, ...pg.QOpt) error); ok { r0 = rf(row, qopts...) diff --git a/core/services/s4/mocks/storage.go b/core/services/s4/mocks/storage.go index f4174f171b..06fc153a35 100644 --- a/core/services/s4/mocks/storage.go +++ b/core/services/s4/mocks/storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Storage struct { func (_m *Storage) Constraints() s4.Constraints { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Constraints") + } + var r0 s4.Constraints if rf, ok := ret.Get(0).(func() s4.Constraints); ok { r0 = rf() @@ -35,6 +39,10 @@ func (_m *Storage) Constraints() s4.Constraints { func (_m *Storage) Get(ctx context.Context, key *s4.Key) (*s4.Record, *s4.Metadata, error) { ret := _m.Called(ctx, key) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *s4.Record var r1 *s4.Metadata var r2 error @@ -70,6 +78,10 @@ func (_m *Storage) Get(ctx context.Context, key *s4.Key) (*s4.Record, *s4.Metada func (_m *Storage) List(ctx context.Context, address common.Address) ([]*s4.SnapshotRow, error) { ret := _m.Called(ctx, address) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 []*s4.SnapshotRow var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]*s4.SnapshotRow, error)); ok { @@ -96,6 +108,10 @@ func (_m *Storage) List(ctx context.Context, address common.Address) ([]*s4.Snap func (_m *Storage) Put(ctx context.Context, key *s4.Key, record *s4.Record, signature []byte) error { ret := _m.Called(ctx, key, record, signature) + if len(ret) == 0 { + panic("no return value specified for Put") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *s4.Key, *s4.Record, []byte) error); ok { r0 = rf(ctx, key, record, signature) diff --git a/core/services/synchronization/mocks/telemetry_service.go b/core/services/synchronization/mocks/telemetry_service.go index bd822666b9..375b46ad7b 100644 --- a/core/services/synchronization/mocks/telemetry_service.go +++ b/core/services/synchronization/mocks/telemetry_service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type TelemetryService struct { func (_m *TelemetryService) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *TelemetryService) Close() error { func (_m *TelemetryService) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *TelemetryService) HealthReport() map[string]error { func (_m *TelemetryService) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -62,6 +74,10 @@ func (_m *TelemetryService) Name() string { func (_m *TelemetryService) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -81,6 +97,10 @@ func (_m *TelemetryService) Send(ctx context.Context, telemetry []byte, contract func (_m *TelemetryService) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/vrf/mocks/aggregator_v3_interface.go b/core/services/vrf/mocks/aggregator_v3_interface.go index 956e315f29..46ca11aa20 100644 --- a/core/services/vrf/mocks/aggregator_v3_interface.go +++ b/core/services/vrf/mocks/aggregator_v3_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ type AggregatorV3Interface struct { func (_m *AggregatorV3Interface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -39,6 +43,10 @@ func (_m *AggregatorV3Interface) Address() common.Address { func (_m *AggregatorV3Interface) Decimals(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Decimals") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -63,6 +71,10 @@ func (_m *AggregatorV3Interface) Decimals(opts *bind.CallOpts) (uint8, error) { func (_m *AggregatorV3Interface) Description(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Description") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -87,6 +99,10 @@ func (_m *AggregatorV3Interface) Description(opts *bind.CallOpts) (string, error func (_m *AggregatorV3Interface) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (aggregator_v3_interface.GetRoundData, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetRoundData") + } + var r0 aggregator_v3_interface.GetRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (aggregator_v3_interface.GetRoundData, error)); ok { @@ -111,6 +127,10 @@ func (_m *AggregatorV3Interface) GetRoundData(opts *bind.CallOpts, _roundId *big func (_m *AggregatorV3Interface) LatestRoundData(opts *bind.CallOpts) (aggregator_v3_interface.LatestRoundData, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestRoundData") + } + var r0 aggregator_v3_interface.LatestRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (aggregator_v3_interface.LatestRoundData, error)); ok { @@ -135,6 +155,10 @@ func (_m *AggregatorV3Interface) LatestRoundData(opts *bind.CallOpts) (aggregato func (_m *AggregatorV3Interface) Version(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Version") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { diff --git a/core/services/vrf/mocks/config.go b/core/services/vrf/mocks/config.go index 72d5960f2c..b46a28ec03 100644 --- a/core/services/vrf/mocks/config.go +++ b/core/services/vrf/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type Config struct { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -27,6 +31,10 @@ func (_m *Config) FinalityDepth() uint32 { func (_m *Config) MinIncomingConfirmations() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for MinIncomingConfirmations") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/core/services/vrf/mocks/fee_config.go b/core/services/vrf/mocks/fee_config.go index 067ce7e445..2f33415b33 100644 --- a/core/services/vrf/mocks/fee_config.go +++ b/core/services/vrf/mocks/fee_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type FeeConfig struct { func (_m *FeeConfig) LimitDefault() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitDefault") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *FeeConfig) LimitDefault() uint32 { func (_m *FeeConfig) LimitJobType() config.LimitJobType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitJobType") + } + var r0 config.LimitJobType if rf, ok := ret.Get(0).(func() config.LimitJobType); ok { r0 = rf() @@ -50,6 +58,10 @@ func (_m *FeeConfig) LimitJobType() config.LimitJobType { func (_m *FeeConfig) PriceMaxKey(addr common.Address) *assets.Wei { ret := _m.Called(addr) + if len(ret) == 0 { + panic("no return value specified for PriceMaxKey") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func(common.Address) *assets.Wei); ok { r0 = rf(addr) diff --git a/core/services/vrf/mocks/vrf_coordinator_v2.go b/core/services/vrf/mocks/vrf_coordinator_v2.go index c39995b38e..529bc78925 100644 --- a/core/services/vrf/mocks/vrf_coordinator_v2.go +++ b/core/services/vrf/mocks/vrf_coordinator_v2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type VRFCoordinatorV2Interface struct { func (_m *VRFCoordinatorV2Interface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *VRFCoordinatorV2Interface) AcceptOwnership(opts *bind.TransactOpts) (* func (_m *VRFCoordinatorV2Interface) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for AcceptSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *VRFCoordinatorV2Interface) AcceptSubscriptionOwnerTransfer(opts *bind. func (_m *VRFCoordinatorV2Interface) AddConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for AddConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -106,6 +118,10 @@ func (_m *VRFCoordinatorV2Interface) AddConsumer(opts *bind.TransactOpts, subId func (_m *VRFCoordinatorV2Interface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -122,6 +138,10 @@ func (_m *VRFCoordinatorV2Interface) Address() common.Address { func (_m *VRFCoordinatorV2Interface) BLOCKHASHSTORE(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for BLOCKHASHSTORE") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -148,6 +168,10 @@ func (_m *VRFCoordinatorV2Interface) BLOCKHASHSTORE(opts *bind.CallOpts) (common func (_m *VRFCoordinatorV2Interface) CancelSubscription(opts *bind.TransactOpts, subId uint64, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, to) + if len(ret) == 0 { + panic("no return value specified for CancelSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -174,6 +198,10 @@ func (_m *VRFCoordinatorV2Interface) CancelSubscription(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CreateSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -200,6 +228,10 @@ func (_m *VRFCoordinatorV2Interface) CreateSubscription(opts *bind.TransactOpts) func (_m *VRFCoordinatorV2Interface) DeregisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, publicProvingKey) + if len(ret) == 0 { + panic("no return value specified for DeregisterProvingKey") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [2]*big.Int) (*types.Transaction, error)); ok { @@ -226,6 +258,10 @@ func (_m *VRFCoordinatorV2Interface) DeregisterProvingKey(opts *bind.TransactOpt func (_m *VRFCoordinatorV2Interface) FilterConfigSet(opts *bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSetIterator, error)); ok { @@ -252,6 +288,10 @@ func (_m *VRFCoordinatorV2Interface) FilterConfigSet(opts *bind.FilterOpts) (*vr func (_m *VRFCoordinatorV2Interface) FilterFundsRecovered(opts *bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecoveredIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterFundsRecovered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2FundsRecoveredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecoveredIterator, error)); ok { @@ -278,6 +318,10 @@ func (_m *VRFCoordinatorV2Interface) FilterFundsRecovered(opts *bind.FilterOpts) func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequestedIterator, error)); ok { @@ -304,6 +348,10 @@ func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferRequested(opts *bind func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferredIterator, error)); ok { @@ -330,6 +378,10 @@ func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferred(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregisteredIterator, error) { ret := _m.Called(opts, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterProvingKeyDeregistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregisteredIterator, error)); ok { @@ -356,6 +408,10 @@ func (_m *VRFCoordinatorV2Interface) FilterProvingKeyDeregistered(opts *bind.Fil func (_m *VRFCoordinatorV2Interface) FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegisteredIterator, error) { ret := _m.Called(opts, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterProvingKeyRegistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegisteredIterator, error)); ok { @@ -382,6 +438,10 @@ func (_m *VRFCoordinatorV2Interface) FilterProvingKeyRegistered(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilledIterator, error) { ret := _m.Called(opts, requestId) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsFulfilled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilledIterator, error)); ok { @@ -408,6 +468,10 @@ func (_m *VRFCoordinatorV2Interface) FilterRandomWordsFulfilled(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequestedIterator, error) { ret := _m.Called(opts, keyHash, subId, sender) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, [][32]byte, []uint64, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequestedIterator, error)); ok { @@ -434,6 +498,10 @@ func (_m *VRFCoordinatorV2Interface) FilterRandomWordsRequested(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceledIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCanceled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceledIterator, error)); ok { @@ -460,6 +528,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCanceled(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAddedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAddedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAddedIterator, error)); ok { @@ -486,6 +558,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerAdded(opts *bind. func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemovedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemovedIterator, error)); ok { @@ -512,6 +588,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerRemoved(opts *bin func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreatedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCreated") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreatedIterator, error)); ok { @@ -538,6 +618,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCreated(opts *bind.Filter func (_m *VRFCoordinatorV2Interface) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFundedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionFunded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFundedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFundedIterator, error)); ok { @@ -564,6 +648,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionFunded(opts *bind.FilterO func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequestedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequestedIterator, error)); ok { @@ -590,6 +678,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferRequested(op func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferredIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferredIterator, error)); ok { @@ -616,6 +708,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferred(opts *bi func (_m *VRFCoordinatorV2Interface) FulfillRandomWords(opts *bind.TransactOpts, proof vrf_coordinator_v2.VRFProof, rc vrf_coordinator_v2.VRFCoordinatorV2RequestCommitment) (*types.Transaction, error) { ret := _m.Called(opts, proof, rc) + if len(ret) == 0 { + panic("no return value specified for FulfillRandomWords") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator_v2.VRFProof, vrf_coordinator_v2.VRFCoordinatorV2RequestCommitment) (*types.Transaction, error)); ok { @@ -642,6 +738,10 @@ func (_m *VRFCoordinatorV2Interface) FulfillRandomWords(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) GetCommitment(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { ret := _m.Called(opts, requestId) + if len(ret) == 0 { + panic("no return value specified for GetCommitment") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([32]byte, error)); ok { @@ -668,6 +768,10 @@ func (_m *VRFCoordinatorV2Interface) GetCommitment(opts *bind.CallOpts, requestI func (_m *VRFCoordinatorV2Interface) GetConfig(opts *bind.CallOpts) (vrf_coordinator_v2.GetConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetConfig") + } + var r0 vrf_coordinator_v2.GetConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator_v2.GetConfig, error)); ok { @@ -692,6 +796,10 @@ func (_m *VRFCoordinatorV2Interface) GetConfig(opts *bind.CallOpts) (vrf_coordin func (_m *VRFCoordinatorV2Interface) GetCurrentSubId(opts *bind.CallOpts) (uint64, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetCurrentSubId") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok { @@ -716,6 +824,10 @@ func (_m *VRFCoordinatorV2Interface) GetCurrentSubId(opts *bind.CallOpts) (uint6 func (_m *VRFCoordinatorV2Interface) GetFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetFallbackWeiPerUnitLink") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -742,6 +854,10 @@ func (_m *VRFCoordinatorV2Interface) GetFallbackWeiPerUnitLink(opts *bind.CallOp func (_m *VRFCoordinatorV2Interface) GetFeeConfig(opts *bind.CallOpts) (vrf_coordinator_v2.GetFeeConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetFeeConfig") + } + var r0 vrf_coordinator_v2.GetFeeConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator_v2.GetFeeConfig, error)); ok { @@ -766,6 +882,10 @@ func (_m *VRFCoordinatorV2Interface) GetFeeConfig(opts *bind.CallOpts) (vrf_coor func (_m *VRFCoordinatorV2Interface) GetFeeTier(opts *bind.CallOpts, reqCount uint64) (uint32, error) { ret := _m.Called(opts, reqCount) + if len(ret) == 0 { + panic("no return value specified for GetFeeTier") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint32, error)); ok { @@ -790,6 +910,10 @@ func (_m *VRFCoordinatorV2Interface) GetFeeTier(opts *bind.CallOpts, reqCount ui func (_m *VRFCoordinatorV2Interface) GetRequestConfig(opts *bind.CallOpts) (uint16, uint32, [][32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetRequestConfig") + } + var r0 uint16 var r1 uint32 var r2 [][32]byte @@ -830,6 +954,10 @@ func (_m *VRFCoordinatorV2Interface) GetRequestConfig(opts *bind.CallOpts) (uint func (_m *VRFCoordinatorV2Interface) GetSubscription(opts *bind.CallOpts, subId uint64) (vrf_coordinator_v2.GetSubscription, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for GetSubscription") + } + var r0 vrf_coordinator_v2.GetSubscription var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (vrf_coordinator_v2.GetSubscription, error)); ok { @@ -854,6 +982,10 @@ func (_m *VRFCoordinatorV2Interface) GetSubscription(opts *bind.CallOpts, subId func (_m *VRFCoordinatorV2Interface) GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetTotalBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -880,6 +1012,10 @@ func (_m *VRFCoordinatorV2Interface) GetTotalBalance(opts *bind.CallOpts) (*big. func (_m *VRFCoordinatorV2Interface) HashOfKey(opts *bind.CallOpts, publicKey [2]*big.Int) ([32]byte, error) { ret := _m.Called(opts, publicKey) + if len(ret) == 0 { + panic("no return value specified for HashOfKey") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, [2]*big.Int) ([32]byte, error)); ok { @@ -906,6 +1042,10 @@ func (_m *VRFCoordinatorV2Interface) HashOfKey(opts *bind.CallOpts, publicKey [2 func (_m *VRFCoordinatorV2Interface) LINK(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LINK") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -932,6 +1072,10 @@ func (_m *VRFCoordinatorV2Interface) LINK(opts *bind.CallOpts) (common.Address, func (_m *VRFCoordinatorV2Interface) LINKETHFEED(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LINKETHFEED") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -958,6 +1102,10 @@ func (_m *VRFCoordinatorV2Interface) LINKETHFEED(opts *bind.CallOpts) (common.Ad func (_m *VRFCoordinatorV2Interface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXCONSUMERS") + } + var r0 uint16 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint16, error)); ok { @@ -982,6 +1130,10 @@ func (_m *VRFCoordinatorV2Interface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, func (_m *VRFCoordinatorV2Interface) MAXNUMWORDS(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXNUMWORDS") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -1006,6 +1158,10 @@ func (_m *VRFCoordinatorV2Interface) MAXNUMWORDS(opts *bind.CallOpts) (uint32, e func (_m *VRFCoordinatorV2Interface) MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts) (uint16, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXREQUESTCONFIRMATIONS") + } + var r0 uint16 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint16, error)); ok { @@ -1030,6 +1186,10 @@ func (_m *VRFCoordinatorV2Interface) MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts func (_m *VRFCoordinatorV2Interface) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { ret := _m.Called(opts, arg0, amount, data) + if len(ret) == 0 { + panic("no return value specified for OnTokenTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1056,6 +1216,10 @@ func (_m *VRFCoordinatorV2Interface) OnTokenTransfer(opts *bind.TransactOpts, ar func (_m *VRFCoordinatorV2Interface) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipient, amount) + if len(ret) == 0 { + panic("no return value specified for OracleWithdraw") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -1082,6 +1246,10 @@ func (_m *VRFCoordinatorV2Interface) OracleWithdraw(opts *bind.TransactOpts, rec func (_m *VRFCoordinatorV2Interface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1108,6 +1276,10 @@ func (_m *VRFCoordinatorV2Interface) Owner(opts *bind.CallOpts) (common.Address, func (_m *VRFCoordinatorV2Interface) OwnerCancelSubscription(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for OwnerCancelSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64) (*types.Transaction, error)); ok { @@ -1134,6 +1306,10 @@ func (_m *VRFCoordinatorV2Interface) OwnerCancelSubscription(opts *bind.Transact func (_m *VRFCoordinatorV2Interface) ParseConfigSet(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error)); ok { @@ -1160,6 +1336,10 @@ func (_m *VRFCoordinatorV2Interface) ParseConfigSet(log types.Log) (*vrf_coordin func (_m *VRFCoordinatorV2Interface) ParseFundsRecovered(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFundsRecovered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered, error)); ok { @@ -1186,6 +1366,10 @@ func (_m *VRFCoordinatorV2Interface) ParseFundsRecovered(log types.Log) (*vrf_co func (_m *VRFCoordinatorV2Interface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -1212,6 +1396,10 @@ func (_m *VRFCoordinatorV2Interface) ParseLog(log types.Log) (generated.AbigenLo func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, error)); ok { @@ -1238,6 +1426,10 @@ func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferRequested(log types.L func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferred(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, error)); ok { @@ -1264,6 +1456,10 @@ func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferred(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseProvingKeyDeregistered(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseProvingKeyDeregistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, error)); ok { @@ -1290,6 +1486,10 @@ func (_m *VRFCoordinatorV2Interface) ParseProvingKeyDeregistered(log types.Log) func (_m *VRFCoordinatorV2Interface) ParseProvingKeyRegistered(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseProvingKeyRegistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, error)); ok { @@ -1316,6 +1516,10 @@ func (_m *VRFCoordinatorV2Interface) ParseProvingKeyRegistered(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseRandomWordsFulfilled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsFulfilled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error)); ok { @@ -1342,6 +1546,10 @@ func (_m *VRFCoordinatorV2Interface) ParseRandomWordsFulfilled(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseRandomWordsRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error)); ok { @@ -1368,6 +1576,10 @@ func (_m *VRFCoordinatorV2Interface) ParseRandomWordsRequested(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCanceled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error)); ok { @@ -1394,6 +1606,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCanceled(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerAdded(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error)); ok { @@ -1420,6 +1636,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerAdded(log types.Lo func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerRemoved(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error)); ok { @@ -1446,6 +1666,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerRemoved(log types. func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCreated(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCreated") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error)); ok { @@ -1472,6 +1696,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCreated(log types.Log) (*v func (_m *VRFCoordinatorV2Interface) ParseSubscriptionFunded(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionFunded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error)); ok { @@ -1498,6 +1726,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionFunded(log types.Log) (*vr func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, error)); ok { @@ -1524,6 +1756,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferRequested(log func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferred(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, error)); ok { @@ -1550,6 +1786,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferred(log types func (_m *VRFCoordinatorV2Interface) PendingRequestExists(opts *bind.CallOpts, subId uint64) (bool, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for PendingRequestExists") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (bool, error)); ok { @@ -1574,6 +1814,10 @@ func (_m *VRFCoordinatorV2Interface) PendingRequestExists(opts *bind.CallOpts, s func (_m *VRFCoordinatorV2Interface) RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for RecoverFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1600,6 +1844,10 @@ func (_m *VRFCoordinatorV2Interface) RecoverFunds(opts *bind.TransactOpts, to co func (_m *VRFCoordinatorV2Interface) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, oracle, publicProvingKey) + if len(ret) == 0 { + panic("no return value specified for RegisterProvingKey") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, [2]*big.Int) (*types.Transaction, error)); ok { @@ -1626,6 +1874,10 @@ func (_m *VRFCoordinatorV2Interface) RegisterProvingKey(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) RemoveConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for RemoveConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -1652,6 +1904,10 @@ func (_m *VRFCoordinatorV2Interface) RemoveConsumer(opts *bind.TransactOpts, sub func (_m *VRFCoordinatorV2Interface) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { ret := _m.Called(opts, keyHash, subId, requestConfirmations, callbackGasLimit, numWords) + if len(ret) == 0 { + panic("no return value specified for RequestRandomWords") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [32]byte, uint64, uint16, uint32, uint32) (*types.Transaction, error)); ok { @@ -1678,6 +1934,10 @@ func (_m *VRFCoordinatorV2Interface) RequestRandomWords(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64, newOwner common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, newOwner) + if len(ret) == 0 { + panic("no return value specified for RequestSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -1704,6 +1964,10 @@ func (_m *VRFCoordinatorV2Interface) RequestSubscriptionOwnerTransfer(opts *bind func (_m *VRFCoordinatorV2Interface) SetConfig(opts *bind.TransactOpts, minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) (*types.Transaction, error) { ret := _m.Called(opts, minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) + if len(ret) == 0 { + panic("no return value specified for SetConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint16, uint32, uint32, uint32, *big.Int, vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) (*types.Transaction, error)); ok { @@ -1730,6 +1994,10 @@ func (_m *VRFCoordinatorV2Interface) SetConfig(opts *bind.TransactOpts, minimumR func (_m *VRFCoordinatorV2Interface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1756,6 +2024,10 @@ func (_m *VRFCoordinatorV2Interface) TransferOwnership(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -1780,6 +2052,10 @@ func (_m *VRFCoordinatorV2Interface) TypeAndVersion(opts *bind.CallOpts) (string func (_m *VRFCoordinatorV2Interface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) (event.Subscription, error)); ok { @@ -1806,6 +2082,10 @@ func (_m *VRFCoordinatorV2Interface) WatchConfigSet(opts *bind.WatchOpts, sink c func (_m *VRFCoordinatorV2Interface) WatchFundsRecovered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchFundsRecovered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered) (event.Subscription, error)); ok { @@ -1832,6 +2112,10 @@ func (_m *VRFCoordinatorV2Interface) WatchFundsRecovered(opts *bind.WatchOpts, s func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1858,6 +2142,10 @@ func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferRequested(opts *bind. func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1884,6 +2172,10 @@ func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferred(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchProvingKeyDeregistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, []common.Address) (event.Subscription, error)); ok { @@ -1910,6 +2202,10 @@ func (_m *VRFCoordinatorV2Interface) WatchProvingKeyDeregistered(opts *bind.Watc func (_m *VRFCoordinatorV2Interface) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchProvingKeyRegistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, []common.Address) (event.Subscription, error)); ok { @@ -1936,6 +2232,10 @@ func (_m *VRFCoordinatorV2Interface) WatchProvingKeyRegistered(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestId) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsFulfilled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, []*big.Int) (event.Subscription, error)); ok { @@ -1962,6 +2262,10 @@ func (_m *VRFCoordinatorV2Interface) WatchRandomWordsFulfilled(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, keyHash, subId, sender) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, [][32]byte, []uint64, []common.Address) (event.Subscription, error)); ok { @@ -1988,6 +2292,10 @@ func (_m *VRFCoordinatorV2Interface) WatchRandomWordsRequested(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCanceled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, []uint64) (event.Subscription, error)); ok { @@ -2014,6 +2322,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCanceled(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerAdded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, []uint64) (event.Subscription, error)); ok { @@ -2040,6 +2352,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerAdded(opts *bind.W func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, []uint64) (event.Subscription, error)); ok { @@ -2066,6 +2382,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerRemoved(opts *bind func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCreated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, []uint64) (event.Subscription, error)); ok { @@ -2092,6 +2412,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCreated(opts *bind.WatchOp func (_m *VRFCoordinatorV2Interface) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionFunded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, []uint64) (event.Subscription, error)); ok { @@ -2118,6 +2442,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionFunded(opts *bind.WatchOpt func (_m *VRFCoordinatorV2Interface) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, []uint64) (event.Subscription, error)); ok { @@ -2144,6 +2472,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionOwnerTransferRequested(opt func (_m *VRFCoordinatorV2Interface) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, []uint64) (event.Subscription, error)); ok { diff --git a/core/services/webhook/mocks/external_initiator_manager.go b/core/services/webhook/mocks/external_initiator_manager.go index a94f2ffe97..6c061f5412 100644 --- a/core/services/webhook/mocks/external_initiator_manager.go +++ b/core/services/webhook/mocks/external_initiator_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type ExternalInitiatorManager struct { func (_m *ExternalInitiatorManager) DeleteJob(webhookSpecID int32) error { ret := _m.Called(webhookSpecID) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 error if rf, ok := ret.Get(0).(func(int32) error); ok { r0 = rf(webhookSpecID) @@ -30,6 +34,10 @@ func (_m *ExternalInitiatorManager) DeleteJob(webhookSpecID int32) error { func (_m *ExternalInitiatorManager) FindExternalInitiatorByName(name string) (bridges.ExternalInitiator, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiatorByName") + } + var r0 bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(string) (bridges.ExternalInitiator, error)); ok { @@ -54,6 +62,10 @@ func (_m *ExternalInitiatorManager) FindExternalInitiatorByName(name string) (br func (_m *ExternalInitiatorManager) Notify(webhookSpecID int32) error { ret := _m.Called(webhookSpecID) + if len(ret) == 0 { + panic("no return value specified for Notify") + } + var r0 error if rf, ok := ret.Get(0).(func(int32) error); ok { r0 = rf(webhookSpecID) diff --git a/core/services/webhook/mocks/http_client.go b/core/services/webhook/mocks/http_client.go index b5b448a56d..fa4f597dc4 100644 --- a/core/services/webhook/mocks/http_client.go +++ b/core/services/webhook/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type HTTPClient struct { func (_m *HTTPClient) Do(req *http.Request) (*http.Response, error) { ret := _m.Called(req) + if len(ret) == 0 { + panic("no return value specified for Do") + } + var r0 *http.Response var r1 error if rf, ok := ret.Get(0).(func(*http.Request) (*http.Response, error)); ok { diff --git a/core/sessions/ldapauth/mocks/ldap_client.go b/core/sessions/ldapauth/mocks/ldap_client.go index 7a44778dca..6302163601 100644 --- a/core/sessions/ldapauth/mocks/ldap_client.go +++ b/core/sessions/ldapauth/mocks/ldap_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type LDAPClient struct { func (_m *LDAPClient) CreateEphemeralConnection() (ldapauth.LDAPConn, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CreateEphemeralConnection") + } + var r0 ldapauth.LDAPConn var r1 error if rf, ok := ret.Get(0).(func() (ldapauth.LDAPConn, error)); ok { diff --git a/core/sessions/ldapauth/mocks/ldap_conn.go b/core/sessions/ldapauth/mocks/ldap_conn.go index c05fb6c4fa..8b4fff8204 100644 --- a/core/sessions/ldapauth/mocks/ldap_conn.go +++ b/core/sessions/ldapauth/mocks/ldap_conn.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type LDAPConn struct { func (_m *LDAPConn) Bind(username string, password string) error { ret := _m.Called(username, password) + if len(ret) == 0 { + panic("no return value specified for Bind") + } + var r0 error if rf, ok := ret.Get(0).(func(string, string) error); ok { r0 = rf(username, password) @@ -31,6 +35,10 @@ func (_m *LDAPConn) Bind(username string, password string) error { func (_m *LDAPConn) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *LDAPConn) Close() error { func (_m *LDAPConn) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) { ret := _m.Called(searchRequest) + if len(ret) == 0 { + panic("no return value specified for Search") + } + var r0 *ldap.SearchResult var r1 error if rf, ok := ret.Get(0).(func(*ldap.SearchRequest) (*ldap.SearchResult, error)); ok { diff --git a/core/sessions/mocks/authentication_provider.go b/core/sessions/mocks/authentication_provider.go index d6e33d11e4..d1b846c318 100644 --- a/core/sessions/mocks/authentication_provider.go +++ b/core/sessions/mocks/authentication_provider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type AuthenticationProvider struct { func (_m *AuthenticationProvider) AuthorizedUserWithSession(sessionID string) (sessions.User, error) { ret := _m.Called(sessionID) + if len(ret) == 0 { + panic("no return value specified for AuthorizedUserWithSession") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -44,6 +48,10 @@ func (_m *AuthenticationProvider) AuthorizedUserWithSession(sessionID string) (s func (_m *AuthenticationProvider) ClearNonCurrentSessions(sessionID string) error { ret := _m.Called(sessionID) + if len(ret) == 0 { + panic("no return value specified for ClearNonCurrentSessions") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(sessionID) @@ -58,6 +66,10 @@ func (_m *AuthenticationProvider) ClearNonCurrentSessions(sessionID string) erro func (_m *AuthenticationProvider) CreateAndSetAuthToken(user *sessions.User) (*auth.Token, error) { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for CreateAndSetAuthToken") + } + var r0 *auth.Token var r1 error if rf, ok := ret.Get(0).(func(*sessions.User) (*auth.Token, error)); ok { @@ -84,6 +96,10 @@ func (_m *AuthenticationProvider) CreateAndSetAuthToken(user *sessions.User) (*a func (_m *AuthenticationProvider) CreateSession(sr sessions.SessionRequest) (string, error) { ret := _m.Called(sr) + if len(ret) == 0 { + panic("no return value specified for CreateSession") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(sessions.SessionRequest) (string, error)); ok { @@ -108,6 +124,10 @@ func (_m *AuthenticationProvider) CreateSession(sr sessions.SessionRequest) (str func (_m *AuthenticationProvider) CreateUser(user *sessions.User) error { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for CreateUser") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User) error); ok { r0 = rf(user) @@ -122,6 +142,10 @@ func (_m *AuthenticationProvider) CreateUser(user *sessions.User) error { func (_m *AuthenticationProvider) DeleteAuthToken(user *sessions.User) error { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for DeleteAuthToken") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User) error); ok { r0 = rf(user) @@ -136,6 +160,10 @@ func (_m *AuthenticationProvider) DeleteAuthToken(user *sessions.User) error { func (_m *AuthenticationProvider) DeleteUser(email string) error { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for DeleteUser") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(email) @@ -150,6 +178,10 @@ func (_m *AuthenticationProvider) DeleteUser(email string) error { func (_m *AuthenticationProvider) DeleteUserSession(sessionID string) error { ret := _m.Called(sessionID) + if len(ret) == 0 { + panic("no return value specified for DeleteUserSession") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(sessionID) @@ -164,6 +196,10 @@ func (_m *AuthenticationProvider) DeleteUserSession(sessionID string) error { func (_m *AuthenticationProvider) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiator, error) { ret := _m.Called(eia) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiator") + } + var r0 *bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(*auth.Token) (*bridges.ExternalInitiator, error)); ok { @@ -190,6 +226,10 @@ func (_m *AuthenticationProvider) FindExternalInitiator(eia *auth.Token) (*bridg func (_m *AuthenticationProvider) FindUser(email string) (sessions.User, error) { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for FindUser") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -214,6 +254,10 @@ func (_m *AuthenticationProvider) FindUser(email string) (sessions.User, error) func (_m *AuthenticationProvider) FindUserByAPIToken(apiToken string) (sessions.User, error) { ret := _m.Called(apiToken) + if len(ret) == 0 { + panic("no return value specified for FindUserByAPIToken") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -238,6 +282,10 @@ func (_m *AuthenticationProvider) FindUserByAPIToken(apiToken string) (sessions. func (_m *AuthenticationProvider) GetUserWebAuthn(email string) ([]sessions.WebAuthn, error) { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for GetUserWebAuthn") + } + var r0 []sessions.WebAuthn var r1 error if rf, ok := ret.Get(0).(func(string) ([]sessions.WebAuthn, error)); ok { @@ -264,6 +312,10 @@ func (_m *AuthenticationProvider) GetUserWebAuthn(email string) ([]sessions.WebA func (_m *AuthenticationProvider) ListUsers() ([]sessions.User, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListUsers") + } + var r0 []sessions.User var r1 error if rf, ok := ret.Get(0).(func() ([]sessions.User, error)); ok { @@ -290,6 +342,10 @@ func (_m *AuthenticationProvider) ListUsers() ([]sessions.User, error) { func (_m *AuthenticationProvider) SaveWebAuthn(token *sessions.WebAuthn) error { ret := _m.Called(token) + if len(ret) == 0 { + panic("no return value specified for SaveWebAuthn") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.WebAuthn) error); ok { r0 = rf(token) @@ -304,6 +360,10 @@ func (_m *AuthenticationProvider) SaveWebAuthn(token *sessions.WebAuthn) error { func (_m *AuthenticationProvider) Sessions(offset int, limit int) ([]sessions.Session, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for Sessions") + } + var r0 []sessions.Session var r1 error if rf, ok := ret.Get(0).(func(int, int) ([]sessions.Session, error)); ok { @@ -330,6 +390,10 @@ func (_m *AuthenticationProvider) Sessions(offset int, limit int) ([]sessions.Se func (_m *AuthenticationProvider) SetAuthToken(user *sessions.User, token *auth.Token) error { ret := _m.Called(user, token) + if len(ret) == 0 { + panic("no return value specified for SetAuthToken") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User, *auth.Token) error); ok { r0 = rf(user, token) @@ -344,6 +408,10 @@ func (_m *AuthenticationProvider) SetAuthToken(user *sessions.User, token *auth. func (_m *AuthenticationProvider) SetPassword(user *sessions.User, newPassword string) error { ret := _m.Called(user, newPassword) + if len(ret) == 0 { + panic("no return value specified for SetPassword") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User, string) error); ok { r0 = rf(user, newPassword) @@ -358,6 +426,10 @@ func (_m *AuthenticationProvider) SetPassword(user *sessions.User, newPassword s func (_m *AuthenticationProvider) TestPassword(email string, password string) error { ret := _m.Called(email, password) + if len(ret) == 0 { + panic("no return value specified for TestPassword") + } + var r0 error if rf, ok := ret.Get(0).(func(string, string) error); ok { r0 = rf(email, password) @@ -372,6 +444,10 @@ func (_m *AuthenticationProvider) TestPassword(email string, password string) er func (_m *AuthenticationProvider) UpdateRole(email string, newRole string) (sessions.User, error) { ret := _m.Called(email, newRole) + if len(ret) == 0 { + panic("no return value specified for UpdateRole") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string, string) (sessions.User, error)); ok { diff --git a/core/sessions/mocks/basic_admin_users_orm.go b/core/sessions/mocks/basic_admin_users_orm.go index 845e2d8880..44ee0b1f70 100644 --- a/core/sessions/mocks/basic_admin_users_orm.go +++ b/core/sessions/mocks/basic_admin_users_orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type BasicAdminUsersORM struct { func (_m *BasicAdminUsersORM) CreateUser(user *sessions.User) error { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for CreateUser") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User) error); ok { r0 = rf(user) @@ -30,6 +34,10 @@ func (_m *BasicAdminUsersORM) CreateUser(user *sessions.User) error { func (_m *BasicAdminUsersORM) FindUser(email string) (sessions.User, error) { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for FindUser") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -54,6 +62,10 @@ func (_m *BasicAdminUsersORM) FindUser(email string) (sessions.User, error) { func (_m *BasicAdminUsersORM) ListUsers() ([]sessions.User, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListUsers") + } + var r0 []sessions.User var r1 error if rf, ok := ret.Get(0).(func() ([]sessions.User, error)); ok { From 5a98ac61aaf6e926d4c653543211f5c355f118ed Mon Sep 17 00:00:00 2001 From: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:34:17 +0000 Subject: [PATCH 286/327] Test VRF LogPoller functionality- initializeLastProcessedBlock, updateLastProcessedBlock and getUnfulfilled (#11472) * Test VRF LogPoller functionality- initializeLastProcessedBlock, updateLastProcessedBlock and getUnfulfilled * Addressed PR comments * Minor change * Add comments to explain replay * Addressed PR comments * Prettier --- .../scripts/native_solc_compile_all_logpoller | 3 +- contracts/src/v0.8/tests/VRFLogEmitter.sol | 42 + .../vrf_log_emitter/vrf_log_emitter.go | 526 +++++++++ ...rapper-dependency-versions-do-not-edit.txt | 1 + core/gethwrappers/go_generate_logpoller.go | 7 + .../vrf/v2/listener_v2_log_listener_test.go | 1039 +++++++++++++++++ 6 files changed, 1617 insertions(+), 1 deletion(-) create mode 100644 contracts/src/v0.8/tests/VRFLogEmitter.sol create mode 100644 core/gethwrappers/generated/vrf_log_emitter/vrf_log_emitter.go create mode 100644 core/gethwrappers/go_generate_logpoller.go create mode 100644 core/services/vrf/v2/listener_v2_log_listener_test.go diff --git a/contracts/scripts/native_solc_compile_all_logpoller b/contracts/scripts/native_solc_compile_all_logpoller index b6ac51eced..e8ea2a2be8 100755 --- a/contracts/scripts/native_solc_compile_all_logpoller +++ b/contracts/scripts/native_solc_compile_all_logpoller @@ -29,4 +29,5 @@ compileContract () { } -compileContract tests/LogEmitter.sol \ No newline at end of file +compileContract tests/LogEmitter.sol +compileContract tests/VRFLogEmitter.sol \ No newline at end of file diff --git a/contracts/src/v0.8/tests/VRFLogEmitter.sol b/contracts/src/v0.8/tests/VRFLogEmitter.sol new file mode 100644 index 0000000000..18b99605ac --- /dev/null +++ b/contracts/src/v0.8/tests/VRFLogEmitter.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract VRFLogEmitter { + event RandomWordsRequested( + bytes32 indexed keyHash, + uint256 requestId, + uint256 preSeed, + uint64 indexed subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + address indexed sender + ); + event RandomWordsFulfilled(uint256 indexed requestId, uint256 outputSeed, uint96 payment, bool success); + + function emitRandomWordsRequested( + bytes32 keyHash, + uint256 requestId, + uint256 preSeed, + uint64 subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + address sender + ) public { + emit RandomWordsRequested( + keyHash, + requestId, + preSeed, + subId, + minimumRequestConfirmations, + callbackGasLimit, + numWords, + sender + ); + } + + function emitRandomWordsFulfilled(uint256 requestId, uint256 outputSeed, uint96 payment, bool success) public { + emit RandomWordsFulfilled(requestId, outputSeed, payment, success); + } +} diff --git a/core/gethwrappers/generated/vrf_log_emitter/vrf_log_emitter.go b/core/gethwrappers/generated/vrf_log_emitter/vrf_log_emitter.go new file mode 100644 index 0000000000..2cdeaa6c3a --- /dev/null +++ b/core/gethwrappers/generated/vrf_log_emitter/vrf_log_emitter.go @@ -0,0 +1,526 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrf_log_emitter + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var VRFLogEmitterMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"emitRandomWordsFulfilled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"emitRandomWordsRequested\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5061027f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ca920adb1461003b578063fe62d3e914610050575b600080fd5b61004e61004936600461015b565b610063565b005b61004e61005e366004610212565b6100eb565b604080518881526020810188905261ffff86168183015263ffffffff858116606083015284166080820152905173ffffffffffffffffffffffffffffffffffffffff83169167ffffffffffffffff8816918b917f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772919081900360a00190a45050505050505050565b604080518481526bffffffffffffffffffffffff8416602082015282151581830152905185917f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4919081900360600190a250505050565b803563ffffffff8116811461015657600080fd5b919050565b600080600080600080600080610100898b03121561017857600080fd5b883597506020890135965060408901359550606089013567ffffffffffffffff811681146101a557600080fd5b9450608089013561ffff811681146101bc57600080fd5b93506101ca60a08a01610142565b92506101d860c08a01610142565b915060e089013573ffffffffffffffffffffffffffffffffffffffff8116811461020157600080fd5b809150509295985092959890939650565b6000806000806080858703121561022857600080fd5b843593506020850135925060408501356bffffffffffffffffffffffff8116811461025257600080fd5b91506060850135801515811461026757600080fd5b93969295509093505056fea164736f6c6343000813000a", +} + +var VRFLogEmitterABI = VRFLogEmitterMetaData.ABI + +var VRFLogEmitterBin = VRFLogEmitterMetaData.Bin + +func DeployVRFLogEmitter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *VRFLogEmitter, error) { + parsed, err := VRFLogEmitterMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFLogEmitterBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFLogEmitter{address: address, abi: *parsed, VRFLogEmitterCaller: VRFLogEmitterCaller{contract: contract}, VRFLogEmitterTransactor: VRFLogEmitterTransactor{contract: contract}, VRFLogEmitterFilterer: VRFLogEmitterFilterer{contract: contract}}, nil +} + +type VRFLogEmitter struct { + address common.Address + abi abi.ABI + VRFLogEmitterCaller + VRFLogEmitterTransactor + VRFLogEmitterFilterer +} + +type VRFLogEmitterCaller struct { + contract *bind.BoundContract +} + +type VRFLogEmitterTransactor struct { + contract *bind.BoundContract +} + +type VRFLogEmitterFilterer struct { + contract *bind.BoundContract +} + +type VRFLogEmitterSession struct { + Contract *VRFLogEmitter + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFLogEmitterCallerSession struct { + Contract *VRFLogEmitterCaller + CallOpts bind.CallOpts +} + +type VRFLogEmitterTransactorSession struct { + Contract *VRFLogEmitterTransactor + TransactOpts bind.TransactOpts +} + +type VRFLogEmitterRaw struct { + Contract *VRFLogEmitter +} + +type VRFLogEmitterCallerRaw struct { + Contract *VRFLogEmitterCaller +} + +type VRFLogEmitterTransactorRaw struct { + Contract *VRFLogEmitterTransactor +} + +func NewVRFLogEmitter(address common.Address, backend bind.ContractBackend) (*VRFLogEmitter, error) { + abi, err := abi.JSON(strings.NewReader(VRFLogEmitterABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFLogEmitter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFLogEmitter{address: address, abi: abi, VRFLogEmitterCaller: VRFLogEmitterCaller{contract: contract}, VRFLogEmitterTransactor: VRFLogEmitterTransactor{contract: contract}, VRFLogEmitterFilterer: VRFLogEmitterFilterer{contract: contract}}, nil +} + +func NewVRFLogEmitterCaller(address common.Address, caller bind.ContractCaller) (*VRFLogEmitterCaller, error) { + contract, err := bindVRFLogEmitter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFLogEmitterCaller{contract: contract}, nil +} + +func NewVRFLogEmitterTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFLogEmitterTransactor, error) { + contract, err := bindVRFLogEmitter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFLogEmitterTransactor{contract: contract}, nil +} + +func NewVRFLogEmitterFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFLogEmitterFilterer, error) { + contract, err := bindVRFLogEmitter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFLogEmitterFilterer{contract: contract}, nil +} + +func bindVRFLogEmitter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFLogEmitterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFLogEmitter *VRFLogEmitterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFLogEmitter.Contract.VRFLogEmitterCaller.contract.Call(opts, result, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.VRFLogEmitterTransactor.contract.Transfer(opts) +} + +func (_VRFLogEmitter *VRFLogEmitterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.VRFLogEmitterTransactor.contract.Transact(opts, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFLogEmitter.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.contract.Transfer(opts) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactor) EmitRandomWordsFulfilled(opts *bind.TransactOpts, requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) { + return _VRFLogEmitter.contract.Transact(opts, "emitRandomWordsFulfilled", requestId, outputSeed, payment, success) +} + +func (_VRFLogEmitter *VRFLogEmitterSession) EmitRandomWordsFulfilled(requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsFulfilled(&_VRFLogEmitter.TransactOpts, requestId, outputSeed, payment, success) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorSession) EmitRandomWordsFulfilled(requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsFulfilled(&_VRFLogEmitter.TransactOpts, requestId, outputSeed, payment, success) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactor) EmitRandomWordsRequested(opts *bind.TransactOpts, keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) { + return _VRFLogEmitter.contract.Transact(opts, "emitRandomWordsRequested", keyHash, requestId, preSeed, subId, minimumRequestConfirmations, callbackGasLimit, numWords, sender) +} + +func (_VRFLogEmitter *VRFLogEmitterSession) EmitRandomWordsRequested(keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsRequested(&_VRFLogEmitter.TransactOpts, keyHash, requestId, preSeed, subId, minimumRequestConfirmations, callbackGasLimit, numWords, sender) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorSession) EmitRandomWordsRequested(keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsRequested(&_VRFLogEmitter.TransactOpts, keyHash, requestId, preSeed, subId, minimumRequestConfirmations, callbackGasLimit, numWords, sender) +} + +type VRFLogEmitterRandomWordsFulfilledIterator struct { + Event *VRFLogEmitterRandomWordsFulfilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFLogEmitterRandomWordsFulfilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFLogEmitterRandomWordsFulfilled) + 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(VRFLogEmitterRandomWordsFulfilled) + 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 *VRFLogEmitterRandomWordsFulfilledIterator) Error() error { + return it.fail +} + +func (it *VRFLogEmitterRandomWordsFulfilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFLogEmitterRandomWordsFulfilled struct { + RequestId *big.Int + OutputSeed *big.Int + Payment *big.Int + Success bool + Raw types.Log +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFLogEmitterRandomWordsFulfilledIterator, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFLogEmitter.contract.FilterLogs(opts, "RandomWordsFulfilled", requestIdRule) + if err != nil { + return nil, err + } + return &VRFLogEmitterRandomWordsFulfilledIterator{contract: _VRFLogEmitter.contract, event: "RandomWordsFulfilled", logs: logs, sub: sub}, nil +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFLogEmitter.contract.WatchLogs(opts, "RandomWordsFulfilled", 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(VRFLogEmitterRandomWordsFulfilled) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsFulfilled", 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 (_VRFLogEmitter *VRFLogEmitterFilterer) ParseRandomWordsFulfilled(log types.Log) (*VRFLogEmitterRandomWordsFulfilled, error) { + event := new(VRFLogEmitterRandomWordsFulfilled) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFLogEmitterRandomWordsRequestedIterator struct { + Event *VRFLogEmitterRandomWordsRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFLogEmitterRandomWordsRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFLogEmitterRandomWordsRequested) + 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(VRFLogEmitterRandomWordsRequested) + 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 *VRFLogEmitterRandomWordsRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFLogEmitterRandomWordsRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFLogEmitterRandomWordsRequested struct { + KeyHash [32]byte + RequestId *big.Int + PreSeed *big.Int + SubId uint64 + MinimumRequestConfirmations uint16 + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address + Raw types.Log +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFLogEmitterRandomWordsRequestedIterator, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFLogEmitter.contract.FilterLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return &VRFLogEmitterRandomWordsRequestedIterator{contract: _VRFLogEmitter.contract, event: "RandomWordsRequested", logs: logs, sub: sub}, nil +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFLogEmitter.contract.WatchLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFLogEmitterRandomWordsRequested) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsRequested", 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 (_VRFLogEmitter *VRFLogEmitterFilterer) ParseRandomWordsRequested(log types.Log) (*VRFLogEmitterRandomWordsRequested, error) { + event := new(VRFLogEmitterRandomWordsRequested) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_VRFLogEmitter *VRFLogEmitter) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _VRFLogEmitter.abi.Events["RandomWordsFulfilled"].ID: + return _VRFLogEmitter.ParseRandomWordsFulfilled(log) + case _VRFLogEmitter.abi.Events["RandomWordsRequested"].ID: + return _VRFLogEmitter.ParseRandomWordsRequested(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (VRFLogEmitterRandomWordsFulfilled) Topic() common.Hash { + return common.HexToHash("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4") +} + +func (VRFLogEmitterRandomWordsRequested) Topic() common.Hash { + return common.HexToHash("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772") +} + +func (_VRFLogEmitter *VRFLogEmitter) Address() common.Address { + return _VRFLogEmitter.address +} + +type VRFLogEmitterInterface interface { + EmitRandomWordsFulfilled(opts *bind.TransactOpts, requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) + + EmitRandomWordsRequested(opts *bind.TransactOpts, keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) + + FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFLogEmitterRandomWordsFulfilledIterator, error) + + WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) + + ParseRandomWordsFulfilled(log types.Log) (*VRFLogEmitterRandomWordsFulfilled, error) + + FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFLogEmitterRandomWordsRequestedIterator, error) + + WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) + + ParseRandomWordsRequested(log types.Log) (*VRFLogEmitterRandomWordsRequested, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 1db18d8366..5e9dcfc332 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -82,6 +82,7 @@ vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerE vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin 8ab9de5816fbdf93a2865e2711b85a39a6fc9c413a4b336578c485be1158d430 +vrf_log_emitter: ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.abi ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.bin 15f491d445ac4d0c712d1cbe4e5054c759b080bf20de7d54bfe2a82cde4dcf06 vrf_malicious_consumer_v2: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.bin 9755fa8ffc7f5f0b337d5d413d77b0c9f6cd6f68c31727d49acdf9d4a51bc522 vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin e2a72638e11da807b6533d037e7e5aaeed695efd5035777b8e20d2f8973a574c vrf_owner: ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.bin eccfae5ee295b5850e22f61240c469f79752b8d9a3bac5d64aec7ac8def2f6cb diff --git a/core/gethwrappers/go_generate_logpoller.go b/core/gethwrappers/go_generate_logpoller.go new file mode 100644 index 0000000000..b28b820583 --- /dev/null +++ b/core/gethwrappers/go_generate_logpoller.go @@ -0,0 +1,7 @@ +// Package gethwrappers provides tools for wrapping solidity contracts with +// golang packages, using abigen. +package gethwrappers + +// Log tester +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin LogEmitter log_emitter +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.abi ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.bin VRFLogEmitter vrf_log_emitter diff --git a/core/services/vrf/v2/listener_v2_log_listener_test.go b/core/services/vrf/v2/listener_v2_log_listener_test.go new file mode 100644 index 0000000000..11b299abc4 --- /dev/null +++ b/core/services/vrf/v2/listener_v2_log_listener_test.go @@ -0,0 +1,1039 @@ +package v2 + +import ( + "context" + "fmt" + "math/big" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_log_emitter" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" + "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +var ( + emitterABI, _ = abi.JSON(strings.NewReader(log_emitter.LogEmitterABI)) + vrfEmitterABI, _ = abi.JSON(strings.NewReader(vrf_log_emitter.VRFLogEmitterABI)) +) + +type vrfLogPollerListenerTH struct { + Lggr logger.Logger + ChainID *big.Int + ORM *logpoller.DbORM + LogPoller logpoller.LogPollerTest + Client *backends.SimulatedBackend + Emitter *log_emitter.LogEmitter + EmitterAddress common.Address + VRFLogEmitter *vrf_log_emitter.VRFLogEmitter + VRFEmitterAddress common.Address + Owner *bind.TransactOpts + EthDB ethdb.Database + Db *sqlx.DB + Listener *listenerV2 + Ctx context.Context +} + +func setupVRFLogPollerListenerTH(t *testing.T, + useFinalityTag bool, + finalityDepth, backfillBatchSize, + rpcBatchSize, keepFinalizedBlocksDepth int64, + mockChainUpdateFn func(*evmmocks.Chain, *vrfLogPollerListenerTH)) *vrfLogPollerListenerTH { + + lggr := logger.TestLogger(t) + chainID := testutils.NewRandomEVMChainID() + db := pgtest.NewSqlxDB(t) + + o := logpoller.NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + owner := testutils.MustNewSimTransactor(t) + ethDB := rawdb.NewMemoryDatabase() + ec := backends.NewSimulatedBackendWithDatabase(ethDB, map[common.Address]core.GenesisAccount{ + owner.From: { + Balance: big.NewInt(0).Mul(big.NewInt(10), big.NewInt(1e18)), + }, + }, 10e6) + // VRF Listener relies on block timestamps, but SimulatedBackend uses by default clock starting from 1970-01-01 + // This trick is used to move the clock closer to the current time. We set first block to be X hours ago. + // FirstBlockAge is used to compute first block's timestamp in SimulatedBackend (time.Now() - FirstBlockAge) + const FirstBlockAge = 24 * time.Hour + blockTime := time.UnixMilli(int64(ec.Blockchain().CurrentHeader().Time)) + err := ec.AdjustTime(time.Since(blockTime) - FirstBlockAge) + require.NoError(t, err) + ec.Commit() + + esc := client.NewSimulatedBackendClient(t, ec, chainID) + // Mark genesis block as finalized to avoid any nulls in the tests + head := esc.Backend().Blockchain().CurrentHeader() + esc.Backend().Blockchain().SetFinalized(head) + + // Poll period doesn't matter, we intend to call poll and save logs directly in the test. + // Set it to some insanely high value to not interfere with any tests. + lp := logpoller.NewLogPoller(o, esc, lggr, 1*time.Hour, useFinalityTag, finalityDepth, backfillBatchSize, rpcBatchSize, keepFinalizedBlocksDepth) + + emitterAddress1, _, emitter1, err := log_emitter.DeployLogEmitter(owner, ec) + require.NoError(t, err) + vrfLogEmitterAddress, _, vrfLogEmitter, err := vrf_log_emitter.DeployVRFLogEmitter(owner, ec) + require.NoError(t, err) + ec.Commit() + + // Log Poller Listener + cfg := pgtest.NewQConfig(false) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) + require.NoError(t, ks.Unlock("blah")) + j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ + RequestedConfsDelay: 10, + EVMChainID: chainID.String(), + }).Toml()) + require.NoError(t, err) + + coordinatorV2, err := vrf_coordinator_v2.NewVRFCoordinatorV2(vrfLogEmitter.Address(), ec) + require.Nil(t, err) + coordinator := NewCoordinatorV2(coordinatorV2) + + chain := evmmocks.NewChain(t) + listener := &listenerV2{ + respCount: map[string]uint64{}, + job: j, + chain: chain, + l: logger.Sugared(lggr), + coordinator: coordinator, + } + ctx := testutils.Context(t) + + // Filter registration is idempotent, so we can just call it every time + // and retry on errors using the ticker. + err = lp.RegisterFilter(logpoller.Filter{ + Name: fmt.Sprintf("vrf_%s_keyhash_%s_job_%d", "v2", listener.job.VRFSpec.PublicKey.MustHash().String(), listener.job.ID), + EventSigs: evmtypes.HashArray{ + vrf_log_emitter.VRFLogEmitterRandomWordsRequested{}.Topic(), + vrf_log_emitter.VRFLogEmitterRandomWordsFulfilled{}.Topic(), + }, + Addresses: evmtypes.AddressArray{ + vrfLogEmitter.Address(), + // listener.job.VRFSpec.CoordinatorAddress.Address(), + }, + }) + require.Nil(t, err) + require.NoError(t, lp.RegisterFilter(logpoller.Filter{ + Name: "Integration test", + EventSigs: []common.Hash{emitterABI.Events["Log1"].ID}, + Addresses: []common.Address{emitterAddress1}, + Retention: 0})) + require.Nil(t, err) + require.Len(t, lp.Filter(nil, nil, nil).Addresses, 2) + require.Len(t, lp.Filter(nil, nil, nil).Topics, 1) + require.Len(t, lp.Filter(nil, nil, nil).Topics[0], 3) + + th := &vrfLogPollerListenerTH{ + Lggr: lggr, + ChainID: chainID, + ORM: o, + LogPoller: lp, + Emitter: emitter1, + EmitterAddress: emitterAddress1, + VRFLogEmitter: vrfLogEmitter, + VRFEmitterAddress: vrfLogEmitterAddress, + Client: ec, + Owner: owner, + EthDB: ethDB, + Db: db, + Listener: listener, + Ctx: ctx, + } + mockChainUpdateFn(chain, th) + return th +} + +/* Tests for initializeLastProcessedBlock: BEGIN + * TestInitProcessedBlock_NoVRFReqs + * TestInitProcessedBlock_NoUnfulfilledVRFReqs + * TestInitProcessedBlock_OneUnfulfilledVRFReq + * TestInitProcessedBlock_SomeUnfulfilledVRFReqs + * TestInitProcessedBlock_UnfulfilledNFulfilledVRFReqs + */ + +func TestInitProcessedBlock_NoVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, th *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(th.ChainID) + mockChain.On("LogPoller").Return(th.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs from block 5 to 9 (Inclusive) + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 5 (EmitLog blocks) = 9 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(testutils.Context(t))) + + // The poller starts on a new chain at latest-finality (finalityDepth + 5 in this case), + // Replaying from block 4 should guarantee we have block 4 immediately. (We will also get + // block 3 once the backup poller runs, since it always starts 100 blocks behind.) + require.NoError(t, th.LogPoller.Replay(testutils.Context(t), 4)) + + // Should return logs from block 5 to 7 (inclusive) + logs, err := th.LogPoller.Logs(4, 7, emitterABI.Events["Log1"].ID, th.EmitterAddress, + pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + require.Equal(t, 3, len(logs)) + + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(6), lastProcessedBlock) +} + +func TestInitProcessedBlock_NoUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request block and a fulfillment block + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID := big.NewInt(1) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 2 (VRF req/resp block) + 5 (EmitLog blocks) = 11 + latestBlock := int64(2 + 2 + 2 + 5) + + // A replay is needed so that log poller has a latest block + // Replay from block 11 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from finalizedBlockNumber (8 --> onwards) + // since there are no pending VRF requests + // Blocks: 1 2 3 4 [5;Request] [6;Fulfilment] 7 8 9 10 11 + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the finalizedBlockNumber (8) instead of + // VRF request block number (5), since all VRF requests are fulfilled + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(8), lastProcessedBlock) +} + +func TestInitProcessedBlock_OneUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Make a VRF request without fulfilling it + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID := big.NewInt(1) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + th.Client.Commit() + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 1 (VRF req block) + 5 (EmitLog blocks) = 10 + latestBlock := int64(2 + 2 + 1 + 5) + + // A replay is needed so that log poller has a latest block + // Replay from block 10 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from earliestUnprocessedBlock (5 --> onwards) + // Blocks: 1 2 3 4 [5;Request] 6 7 8 9 10 + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the unfulfilled VRF + // request block number (5) instead of finalizedBlockNumber (8) + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(5), lastProcessedBlock) +} + +func TestInitProcessedBlock_SomeUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks with VRF reqs interspersed + // No fulfillment for any VRF requests + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req/resp blocks) = 19 + latestBlock := int64(2 + 2 + 3*5) + + // A replay is needed so that log poller has a latest block + // Replay from block 19 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from earliestUnprocessedBlock (6 --> onwards) + // Blocks: 1 2 3 4 5 [6;Request] [7;Request] 8 [9;Request] [10;Request] + // 11 [12;Request] [13;Request] 14 [15;Request] [16;Request] + // 17 [18;Request] [19;Request] + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the earliest unfulfilled VRF request block + // number instead of finalizedBlockNumber + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(6), lastProcessedBlock) +} + +func TestInitProcessedBlock_UnfulfilledNFulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks with VRF reqs interspersed + // One VRF request in each iteration is fulfilled to imitate mixed workload + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration and fulfill one + // of them. This creates a mixed workload of fulfilled and unfulfilled + // VRF requests for testing the VRF listener + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID1, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req/resp blocks) = 19 + latestBlock := int64(2 + 2 + 3*5) + // A replay is needed so that log poller has a latest block + // Replay from block 19 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from earliestUnprocessedBlock (7 --> onwards) + // Blocks: 1 2 3 4 5 [6;Request] [7;Request;6-Fulfilment] 8 [9;Request] [10;Request;9-Fulfilment] + // 11 [12;Request] [13;Request;12-Fulfilment] 14 [15;Request] [16;Request;15-Fulfilment] + // 17 [18;Request] [19;Request;18-Fulfilment] + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the earliest unfulfilled VRF request block + // number instead of finalizedBlockNumber + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(7), lastProcessedBlock) +} + +/* Tests for initializeLastProcessedBlock: END */ + +/* Tests for updateLastProcessedBlock: BEGIN + * TestUpdateLastProcessedBlock_NoVRFReqs + * TestUpdateLastProcessedBlock_NoUnfulfilledVRFReqs + * TestUpdateLastProcessedBlock_OneUnfulfilledVRFReq + * TestUpdateLastProcessedBlock_SomeUnfulfilledVRFReqs + * TestUpdateLastProcessedBlock_UnfulfilledNFulfilledVRFReqs + */ + +func TestUpdateLastProcessedBlock_NoVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request logs + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(1)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 2 (VRF req blocks) + 5 (EmitLog blocks) = 11 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the finalizedBlockNumber as there are + // no VRF requests, after currLastProcessedBlock (block 6). The VRF requests + // made above are before the currLastProcessedBlock (7) passed in below + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 7) + require.Nil(t, err) + require.Equal(t, int64(8), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_NoUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request log block with a fulfillment log block + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(1)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID1, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 2 (VRF req/resp blocks) + 5 (EmitLog blocks) = 11 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the finalizedBlockNumber (8) though we have + // a VRF req at block (5) after currLastProcessedBlock (4) passed below, because + // the VRF request is fulfilled + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(8), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_OneUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request logs without a fulfillment log block + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(1)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 1 (VRF req block) + 5 (EmitLog blocks) = 10 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the VRF req at block (5) instead of + // finalizedBlockNumber (8) after currLastProcessedBlock (4) passed below, + // because the VRF request is unfulfilled + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(5), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_SomeUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req blocks) = 19 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the VRF req at block (6) instead of + // finalizedBlockNumber (16) after currLastProcessedBlock (4) passed below, + // as block 6 contains the earliest unfulfilled VRF request + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(6), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_UnfulfilledNFulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration and fulfill one + // of them. This creates a mixed workload of fulfilled and unfulfilled + // VRF requests for testing the VRF listener + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID1, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req blocks) = 19 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the VRF req at block (7) instead of + // finalizedBlockNumber (16) after currLastProcessedBlock (4) passed below, + // as block 7 contains the earliest unfulfilled VRF request. VRF request + // in block 6 has been fulfilled in block 7. + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(7), lastProcessedBlock) +} + +/* Tests for updateLastProcessedBlock: END */ + +/* Tests for getUnfulfilled: BEGIN + * TestGetUnfulfilled_NoVRFReqs + * TestGetUnfulfilled_NoUnfulfilledVRFReqs + * TestGetUnfulfilled_OneUnfulfilledVRFReq + * TestGetUnfulfilled_SomeUnfulfilledVRFReqs + * TestGetUnfulfilled_UnfulfilledNFulfilledVRFReqs + */ + +func SetupGetUnfulfilledTH(t *testing.T) (*listenerV2, *utils.Big) { + chainID := utils.NewBig(big.NewInt(12345)) + lggr := logger.TestLogger(t) + j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ + RequestedConfsDelay: 10, + EVMChainID: chainID.String(), + }).Toml()) + require.NoError(t, err) + chain := evmmocks.NewChain(t) + + // Construct CoordinatorV2_X object for VRF listener + owner := testutils.MustNewSimTransactor(t) + ethDB := rawdb.NewMemoryDatabase() + ec := backends.NewSimulatedBackendWithDatabase(ethDB, map[common.Address]core.GenesisAccount{ + owner.From: { + Balance: big.NewInt(0).Mul(big.NewInt(10), big.NewInt(1e18)), + }, + }, 10e6) + _, _, vrfLogEmitter, err := vrf_log_emitter.DeployVRFLogEmitter(owner, ec) + require.NoError(t, err) + ec.Commit() + coordinatorV2, err := vrf_coordinator_v2.NewVRFCoordinatorV2(vrfLogEmitter.Address(), ec) + require.Nil(t, err) + coordinator := NewCoordinatorV2(coordinatorV2) + + listener := &listenerV2{ + respCount: map[string]uint64{}, + job: j, + chain: chain, + l: logger.Sugared(lggr), + coordinator: coordinator, + } + return listener, chainID +} + +func TestGetUnfulfilled_NoVRFReqs(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(i))), + BlockNumber: int64(i), + BlockTimestamp: time.Now(), + Topics: [][]byte{ + []byte("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + }, + EventSig: emitterABI.Events["Log1"].ID, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(i))), + Data: nil, + CreatedAt: time.Now(), + }) + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Empty(t, unfulfilled) + require.Empty(t, fulfilled) +} + +func TestGetUnfulfilled_NoUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i%2 == 0 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + if i%2 == 0 { + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + BlockNumber: int64(2*i + 1), + BlockTimestamp: time.Now(), + Topics: [][]byte{ + common.FromHex("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4"), + common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i)), + }, + EventSig: vrfEmitterABI.Events["RandomWordsFulfilled"].ID, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + Data: common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000069000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001"), + CreatedAt: time.Now(), + }) + } + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Empty(t, unfulfilled) + require.Len(t, fulfilled, 5) +} + +func TestGetUnfulfilled_OneUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i == 4 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Equal(t, unfulfilled[0].RequestID().Int64(), big.NewInt(4).Int64()) + require.Len(t, unfulfilled, 1) + require.Empty(t, fulfilled) +} + +func TestGetUnfulfilled_SomeUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i%2 == 0 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Len(t, unfulfilled, 5) + require.Len(t, fulfilled, 0) + expected := map[int64]bool{0: true, 2: true, 4: true, 6: true, 8: true} + for _, u := range unfulfilled { + v, ok := expected[u.RequestID().Int64()] + require.Equal(t, ok, true) + require.Equal(t, v, true) + } + require.Equal(t, len(expected), len(unfulfilled)) +} + +func TestGetUnfulfilled_UnfulfilledNFulfilledVRFReqs(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i%2 == 0 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + if i%2 == 0 && i < 6 { + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + BlockNumber: int64(2*i + 1), + BlockTimestamp: time.Now(), + Topics: [][]byte{ + common.FromHex("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4"), + common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i)), + }, + EventSig: vrfEmitterABI.Events["RandomWordsFulfilled"].ID, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + Data: common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000069000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001"), + CreatedAt: time.Now(), + }) + } + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Len(t, unfulfilled, 2) + require.Len(t, fulfilled, 3) + expected := map[int64]bool{6: true, 8: true} + for _, u := range unfulfilled { + v, ok := expected[u.RequestID().Int64()] + require.Equal(t, ok, true) + require.Equal(t, v, true) + } + require.Equal(t, len(expected), len(unfulfilled)) +} + +/* Tests for getUnfulfilled: END */ From df54d26d7f9ebe23f349807850635cb51d4f0616 Mon Sep 17 00:00:00 2001 From: Dylan Tinianov Date: Thu, 7 Dec 2023 12:38:24 -0500 Subject: [PATCH 287/327] EVM Extraction core/services/servicetest (#11514) * Extract servicetest * tidy --- core/chains/evm/log/helpers_test.go | 4 ++-- core/chains/evm/log/integration_test.go | 4 ++-- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index ac7eb863e6..49f9266f70 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -21,6 +21,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -40,7 +41,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -89,7 +89,7 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, }) config := evmtest.NewChainScopedConfig(t, globalConfig) lggr := logger.Test(t) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) db := pgtest.NewSqlxDB(t) orm := log.NewORM(db, lggr, config.Database(), cltest.FixtureChainID) diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index edc04a4ada..2d66cdf585 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -17,6 +17,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -27,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -1324,7 +1324,7 @@ func TestBroadcaster_AppendLogChannel(t *testing.T) { ch3 := make(chan types.Log) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) lb := log.NewBroadcaster(nil, ethClient, nil, logger.Test(t), nil, mailMon) chCombined := lb.ExportedAppendLogChannel(ch1, ch2) chCombined = lb.ExportedAppendLogChannel(chCombined, ch3) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index b0b5f801ed..07d41c9d7e 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -258,7 +258,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index dd69053b40..48b168459b 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1214,8 +1214,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 h1:2LC5HtHkAm7I1h5j4Uz0KTX+h4fo4z/5NoAARSF4ZVA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad h1:ysPjfbCPJuVxxFZa1Ifv8OPE20pzvnEHjJrPDUo4gT0= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= diff --git a/go.mod b/go.mod index 2ac067959e..f659881d1a 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-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d diff --git a/go.sum b/go.sum index b7305210e0..d700ec724b 100644 --- a/go.sum +++ b/go.sum @@ -1217,8 +1217,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 h1:2LC5HtHkAm7I1h5j4Uz0KTX+h4fo4z/5NoAARSF4ZVA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad h1:ysPjfbCPJuVxxFZa1Ifv8OPE20pzvnEHjJrPDUo4gT0= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 32c35c28a9..90f4bbae26 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad github.com/smartcontractkit/chainlink-testing-framework v1.20.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 21e237923b..f5640eb891 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1507,8 +1507,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 h1:2LC5HtHkAm7I1h5j4Uz0KTX+h4fo4z/5NoAARSF4ZVA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad h1:ysPjfbCPJuVxxFZa1Ifv8OPE20pzvnEHjJrPDUo4gT0= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= From 711987f11751d69f0c0d7d0b02d11497539ece90 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Thu, 7 Dec 2023 19:08:18 -0300 Subject: [PATCH 288/327] [TT-590] Logstream with buffered streaming to Loki (#11477) * testing out with local CTF * print location for failed tests * use logwatch with buffer * try logwatch with loki and test targets in CI * fix merge conflict * fix lint issue * adjust env vars in workflow * add logwatch env vars as env and not with * fix env var name * fix go.mod * use newer ctf * fix go.sum * use correct ctf version * fix go.sum * trigger tests * small debug * make the Gh summary print a bit nicer * latest ctf, use var not secret for grafana url * update ctf, change how we print test summary * shutdown logwatch after flushing logs * trigger tests * use latest ctf where logwatch -> logstream * update var name in GH workflow * enable log stream for all smoke tests * use better method for logstream shutdown and log flushing * fix compile error * latest ctf, remove comment * remove replace from go.mod * collect all logs to see what happens * update ctf, better scoped dashboard link * do not save logs if test doesn't fail * print absolute log folder path * cause test failure to make sure file logs are where they should be * fix typo in var declaration in gh workflow * run go mod tidy for integeration tests * always execute test summary step * remove failing vrfv2 test on purpose * use taggeg CTF version * connect mock adapter to logstream * initialise killgrave only when necessary --- .github/workflows/integration-tests.yml | 28 ++++ .gitignore | 3 + integration-tests/docker/test_env/cl_node.go | 33 +++-- integration-tests/docker/test_env/test_env.go | 131 ++++-------------- .../docker/test_env/test_env_builder.go | 46 ++++-- integration-tests/go.mod | 19 ++- integration-tests/go.sum | 43 +++--- integration-tests/load/vrfv2/vrfv2_test.go | 2 +- .../load/vrfv2plus/vrfv2plus_test.go | 2 +- integration-tests/smoke/automation_test.go | 1 + integration-tests/smoke/cron_test.go | 2 + integration-tests/smoke/flux_test.go | 1 + integration-tests/smoke/forwarder_ocr_test.go | 1 + .../smoke/forwarders_ocr2_test.go | 1 + integration-tests/smoke/keeper_test.go | 1 + integration-tests/smoke/ocr2_test.go | 2 + integration-tests/smoke/ocr_test.go | 1 + integration-tests/smoke/runlog_test.go | 1 + integration-tests/smoke/vrf_test.go | 2 + integration-tests/smoke/vrfv2_test.go | 2 + integration-tests/smoke/vrfv2plus_test.go | 3 + .../universal/log_poller/helpers.go | 1 + 22 files changed, 180 insertions(+), 146 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 5e3cf02a7c..37a2718be4 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -435,6 +435,13 @@ jobs: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }} + LOKI_URL: ${{ secrets.LOKI_URL }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} + LOGSTREAM_LOG_TARGETS: ${{ vars.LOGSTREAM_LOG_TARGETS }} + GRAFANA_URL: ${{ vars.GRAFANA_URL }} + GRAFANA_DATASOURCE: ${{ vars.GRAFANA_DATASOURCE }} + RUN_ID: ${{ github.run_id }} with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -487,6 +494,27 @@ jobs: with: name: trace-data path: ./integration-tests/smoke/traces/trace-data.json + - name: Print failed test summary + if: always() + run: | + directory="./integration-tests/smoke/.test_summary" + files=("$directory"/*) + if [ -d "$directory" ]; then + echo "Test summary folder found" + if [ ${#files[@]} -gt 0 ]; then + first_file="${files[0]}" + echo "Name of the first test summary file: $(basename "$first_file")" + echo "### Failed Test Execution Logs Dashboard (over VPN):" >> $GITHUB_STEP_SUMMARY + cat "$first_file" | jq -r '.loki[] | "* [\(.test_name)](\(.value))"' >> $GITHUB_STEP_SUMMARY + if [ ${#files[@]} -gt 1 ]; then + echo "Found more than one test summary file. This is incorrect, there should be only one file" + fi + else + echo "Test summary directory is empty. This should not happen" + fi + else + echo "No test summary folder found. If no test failed or log collection wasn't explicitly requested this is correct. Exiting" + fi ### Used to check the required checks box when the matrix completes eth-smoke-tests: diff --git a/.gitignore b/.gitignore index 3f016503a8..8d127dbb72 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,6 @@ go.work* # This sometimes shows up for some reason tools/flakeytests/coverage.txt + +.test_summary/ +.run.id \ No newline at end of file diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 7dc077ad34..6039425633 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -1,6 +1,7 @@ package test_env import ( + "context" "fmt" "math/big" "net/url" @@ -22,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" @@ -47,7 +48,7 @@ type ClNode struct { UserPassword string `json:"userPassword"` t *testing.T l zerolog.Logger - lw *logwatch.LogWatch + ls *logstream.LogStream } type ClNodeOption = func(c *ClNode) @@ -76,9 +77,9 @@ func WithDbContainerName(name string) ClNodeOption { } } -func WithLogWatch(lw *logwatch.LogWatch) ClNodeOption { +func WithLogStream(ls *logstream.LogStream) ClNodeOption { return func(c *ClNode) { - c.lw = lw + c.ls = ls } } @@ -285,11 +286,7 @@ func (n *ClNode) StartContainer() error { if err != nil { return fmt.Errorf("%s err: %w", ErrStartCLNodeContainer, err) } - if n.lw != nil { - if err := n.lw.ConnectContainer(testcontext.Get(n.t), container, "cl-node", true); err != nil { - return err - } - } + clEndpoint, err := test_env.GetEndpoint(testcontext.Get(n.t), container, "http") if err != nil { return err @@ -410,5 +407,23 @@ func (n *ClNode) getContainerRequest(secrets string) ( FileMode: 0644, }, }, + LifecycleHooks: []tc.ContainerLifecycleHooks{ + {PostStarts: []tc.ContainerHook{ + func(ctx context.Context, c tc.Container) error { + if n.ls != nil { + return n.ls.ConnectContainer(ctx, c, "cl-node") + } + return nil + }, + }, + PostStops: []tc.ContainerHook{ + func(ctx context.Context, c tc.Container) error { + if n.ls != nil { + return n.ls.DisconnectContainer(c) + } + return nil + }, + }}, + }, }, nil } diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index b04d24a959..15bf6641bf 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -1,14 +1,12 @@ package test_env import ( + "context" "encoding/json" "fmt" - "io" "math/big" "os" - "path/filepath" "runtime/debug" - "strings" "testing" "time" @@ -16,14 +14,12 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" - "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/logwatch" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -35,9 +31,9 @@ var ( ) type CLClusterTestEnv struct { - Cfg *TestEnvConfig - Network *tc.DockerNetwork - LogWatch *logwatch.LogWatch + Cfg *TestEnvConfig + Network *tc.DockerNetwork + LogStream *logstream.LogStream /* components */ ClCluster *ClCluster @@ -58,11 +54,9 @@ func NewTestEnv() (*CLClusterTestEnv, error) { if err != nil { return nil, err } - n := []string{network.Name} return &CLClusterTestEnv{ - MockAdapter: test_env.NewKillgrave(n, ""), - Network: network, - l: log.Logger, + Network: network, + l: log.Logger, }, nil } @@ -70,15 +64,19 @@ func NewTestEnv() (*CLClusterTestEnv, error) { // Sets up private ethereum chain and MockAdapter containers with the provided cfg. func (te *CLClusterTestEnv) WithTestEnvConfig(cfg *TestEnvConfig) *CLClusterTestEnv { te.Cfg = cfg - n := []string{te.Network.Name} - te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName)) + if cfg.MockAdapter.ContainerName != "" { + n := []string{te.Network.Name} + te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName)) + } return te } func (te *CLClusterTestEnv) WithTestLogger(t *testing.T) *CLClusterTestEnv { te.t = t te.l = logging.GetTestLogger(t) - te.MockAdapter.WithTestLogger(t) + if te.MockAdapter != nil { + te.MockAdapter.WithTestLogger(t) + } return te } @@ -174,6 +172,18 @@ func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count i } } + if te.LogStream != nil { + for _, node := range te.ClCluster.Nodes { + node.ls = te.LogStream + } + if te.MockAdapter != nil { + err := te.LogStream.ConnectContainer(context.Background(), te.MockAdapter.Container, "mock-adapter") + if err != nil { + return err + } + } + } + // Start/attach node containers return te.ClCluster.Start() } @@ -207,23 +217,6 @@ func (te *CLClusterTestEnv) Cleanup() error { te.logWhetherAllContainersAreRunning() - // Getting the absolute path - wd, err := os.Getwd() - if err != nil { - return err - } - - wd = filepath.Join(wd, "logs") - te.l.Info().Str("Working dir", wd).Msg("Would write test logs here") - - // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution - // Collect logs if the test fails, or if we just want them - if te.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { - if err := te.collectTestLogs(); err != nil { - return err - } - } - if te.EVMClient == nil { return fmt.Errorf("evm client is nil, unable to return funds from chainlink nodes during cleanup") } else if te.EVMClient.NetworkSimulated() { @@ -247,6 +240,10 @@ func (te *CLClusterTestEnv) Cleanup() error { func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { for _, node := range te.ClCluster.Nodes { + if node.Container == nil { + continue + } + isCLRunning := node.Container.IsRunning() isDBRunning := node.PostgresDb.Container.IsRunning() @@ -260,74 +257,6 @@ func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { } } -// collectTestLogs collects the logs from all the Chainlink nodes in the test environment and writes them to local files -func (te *CLClusterTestEnv) collectTestLogs() error { - te.l.Info().Msg("Collecting test logs") - sanitizedNetworkName := strings.ReplaceAll(te.EVMClient.GetNetworkName(), " ", "-") - folder := fmt.Sprintf("./logs/%s-%s-%s", te.t.Name(), sanitizedNetworkName, time.Now().Format("2006-01-02T15-04-05")) - if err := os.MkdirAll(folder, os.ModePerm); err != nil { - return err - } - - eg := &errgroup.Group{} - for _, n := range te.ClCluster.Nodes { - node := n - eg.Go(func() error { - logFileName := filepath.Join(folder, fmt.Sprintf("node-%s.log", node.ContainerName)) - logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer logFile.Close() - logReader, err := node.Container.Logs(testcontext.Get(te.t)) - if err != nil { - return err - } - _, err = io.Copy(logFile, logReader) - if err != nil { - return err - } - te.l.Info().Str("Node", node.ContainerName).Str("File", logFileName).Msg("Wrote Logs") - return nil - }) - } - - if te.MockAdapter != nil { - eg.Go(func() error { - logFileName := filepath.Join(folder, "mock-adapter.log") - logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer logFile.Close() - logReader, err := te.MockAdapter.Container.Logs(testcontext.Get(te.t)) - if err != nil { - return err - } - _, err = io.Copy(logFile, logReader) - if err != nil { - return err - } - te.l.Info().Str("Container", te.MockAdapter.ContainerName).Str("File", logFileName).Msg("Wrote Logs") - return nil - }) - } - - if err := eg.Wait(); err != nil { - return err - } - - // Getting the absolute path - wd, err := os.Getwd() - if err != nil { - return err - } - absolutePath := filepath.Join(wd, folder) - - te.l.Info().Str("Logs absolute Location", absolutePath).Msg("Wrote test logs") - return nil -} - func (te *CLClusterTestEnv) returnFunds() error { te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") for _, chainlinkNode := range te.ClCluster.Nodes { diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 685ea5338a..cc0499ea0c 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -13,8 +13,9 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -32,8 +33,7 @@ const ( ) type CLTestEnvBuilder struct { - hasLogWatch bool - // hasGeth bool + hasLogStream bool hasKillgrave bool hasForwarders bool clNodeConfig *chainlink.Config @@ -101,8 +101,8 @@ func (b *CLTestEnvBuilder) WithTestLogger(t *testing.T) *CLTestEnvBuilder { return b } -func (b *CLTestEnvBuilder) WithLogWatcher() *CLTestEnvBuilder { - b.hasLogWatch = true +func (b *CLTestEnvBuilder) WithLogStream() *CLTestEnvBuilder { + b.hasLogStream = true return b } @@ -220,24 +220,30 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } var err error - if b.t != nil { - b.te.WithTestLogger(b.t) - } - - if b.hasLogWatch { - b.te.LogWatch, err = logwatch.NewLogWatch(nil, nil) + if b.hasLogStream { + b.te.LogStream, err = logstream.NewLogStream(b.t, nil) if err != nil { return nil, err } } if b.hasKillgrave { + if b.te.Network == nil { + return nil, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("cannot start mock adapter without a network")) + } + + b.te.MockAdapter = test_env.NewKillgrave([]string{b.te.Network.Name}, "") + err = b.te.StartMockAdapter() if err != nil { return nil, err } } + if b.t != nil { + b.te.WithTestLogger(b.t) + } + switch b.cleanUpType { case CleanUpTypeStandard: b.t.Cleanup(func() { @@ -253,6 +259,24 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return b.te, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("explicit cleanup type must be set when building test environment")) } + if b.te.LogStream != nil { + b.t.Cleanup(func() { + b.l.Warn().Msg("Shutting down LogStream") + logPath, err := osutil.GetAbsoluteFolderPath("logs") + if err != nil { + b.l.Info().Str("Absolute path", logPath).Msg("LogStream logs folder location") + } + + if b.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { + // we can't do much if this fails, so we just log the error in logstream + _ = b.te.LogStream.FlushAndShutdown() + b.te.LogStream.PrintLogTargetsLocations() + b.te.LogStream.SaveLogLocationInTestSummary() + } + + }) + } + if b.nonDevGethNetworks != nil { b.te.WithPrivateChain(b.nonDevGethNetworks) err := b.te.StartPrivateChain() diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 90f4bbae26..2f32347bb4 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -25,12 +25,12 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad - github.com/smartcontractkit/chainlink-testing-framework v1.20.1 + github.com/smartcontractkit/chainlink-testing-framework v1.21.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 - github.com/smartcontractkit/wasp v0.3.6 + github.com/smartcontractkit/wasp v0.3.7 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 github.com/testcontainers/testcontainers-go v0.23.0 @@ -42,8 +42,12 @@ require ( gopkg.in/guregu/null.v4 v4.0.0 ) +// avoids ambigious imports of indirect dependencies +exclude github.com/hashicorp/consul v1.2.1 + // Pin K8s versions as their updates are highly disruptive and go mod keeps wanting to update them replace ( + github.com/testcontainers/testcontainers-go => github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 k8s.io/api => k8s.io/api v0.25.11 k8s.io/client-go => k8s.io/client-go v0.25.11 k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d @@ -73,11 +77,13 @@ require ( github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/hcsshim v0.11.1 // indirect github.com/VictoriaMetrics/fastcache v1.10.0 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aws/aws-sdk-go v1.45.25 // indirect github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect @@ -109,7 +115,8 @@ require ( github.com/cometbft/cometbft v0.37.2 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect - github.com/containerd/containerd v1.7.3 // indirect + github.com/containerd/containerd v1.7.7 // indirect + github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -276,6 +283,7 @@ require ( github.com/libp2p/go-openssl v0.0.7 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -290,7 +298,7 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/patternmatcher v0.5.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/term v0.5.0 // indirect @@ -316,7 +324,7 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc4 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opencontainers/runc v1.1.7 // indirect github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect @@ -349,6 +357,7 @@ require ( github.com/sercand/kuberesolver/v5 v5.1.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.23.10 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f5640eb891..08d02446d1 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -131,16 +131,18 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0 github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek= -github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM= +github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA= +github.com/Microsoft/hcsshim v0.11.1/go.mod h1:nFJmaO4Zr5Y7eADdFOpYswDDlNVbvcIJJNJLECr5JQg= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.6 h1:U68crOE3y3MPttCMQGywZOLrTeF5HHJ3/vDBCJn9/bA= -github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 h1:HItfr1XKD/4xnsJE56m3uxnkMQ9lbg8xDnkf9qoZCH0= +github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56/go.mod h1:ICriE9bLX5CLxL9OFQ2N+2N+f+803LNJ1utJb1+Inx0= github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= @@ -177,6 +179,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= +github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -304,10 +308,12 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o= -github.com/containerd/containerd v1.7.3/go.mod h1:32FOM4/O0RkNg7AjQj3hDzN9cUGtu+HMvaKUNiqCZB8= -github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= -github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4= +github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -1135,6 +1141,7 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -1222,8 +1229,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= -github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -1324,8 +1331,8 @@ github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= -github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= @@ -1487,7 +1494,9 @@ github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKl github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -1519,8 +1528,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= -github.com/smartcontractkit/chainlink-testing-framework v1.20.1 h1:0hxLRts4yIum52MaE95RuM2Xi1S/R0r4UFExpp00iK4= -github.com/smartcontractkit/chainlink-testing-framework v1.20.1/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= +github.com/smartcontractkit/chainlink-testing-framework v1.21.0 h1:MrtpGMgPpcRX06FtDEj14Vokoo6Sx8e0/D6AA9LxCgM= +github.com/smartcontractkit/chainlink-testing-framework v1.21.0/go.mod h1:9SCqZ+lcWZNEofpPgasQ+wUF6A6fFgZvWmhqQJwFYV0= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= @@ -1533,8 +1542,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -github.com/smartcontractkit/wasp v0.3.6 h1:1TLWfrTzqZwNvyyoKzPZ8FLQat2lNz640eM+mMh2YxM= -github.com/smartcontractkit/wasp v0.3.6/go.mod h1:L/cyUGfpaWxy/2twOVJLRt2mySJEIqGrFj9nyvRLpSo= +github.com/smartcontractkit/wasp v0.3.7 h1:3toT+iMSHJ1EKQXE+jGnxfmtLlT0gwEl1A7xGyw0NZY= +github.com/smartcontractkit/wasp v0.3.7/go.mod h1:L/cyUGfpaWxy/2twOVJLRt2mySJEIqGrFj9nyvRLpSo= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -1606,8 +1615,6 @@ github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 h1:3SNcvBmEPE1YlB github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= -github.com/testcontainers/testcontainers-go v0.23.0 h1:ERYTSikX01QczBLPZpqsETTBO7lInqEP349phDOVJVs= -github.com/testcontainers/testcontainers-go v0.23.0/go.mod h1:3gzuZfb7T9qfcH2pHpV4RLlWrPjeWNQah6XlYQ32c4I= github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a h1:YuO+afVc3eqrjiCUizNCxI53bl/BnPiVwXqLzqYTqgU= github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a/go.mod h1:/sfW47zCZp9FrtGcWyo1VjbgDaodxX9ovZvgLb/MxaA= github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e h1:BuzhfgfWQbX0dWzYzT1zsORLnHRv3bcRcsaUk0VmXA8= diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index ae109f75e2..8a0faeabb2 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -178,7 +178,7 @@ func TestVRFV2Performance(t *testing.T) { l.Error().Err(err).Msg("Error cleaning up test environment") } }). - WithLogWatcher(). + WithLogStream(). Build() require.NoError(t, err, "error creating test env") diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 4b6728440b..68c1012987 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -184,7 +184,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Error().Err(err).Msg("Error cleaning up test environment") } }). - WithLogWatcher(). + WithLogStream(). Build() require.NoError(t, err, "error creating test env") diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index f72843e77e..bc9f130845 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -1097,6 +1097,7 @@ func setupAutomationTestDocker( WithMockAdapter(). WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "Error deploying test environment for Mercury") env.ParallelTransactions(true) diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 013e4c631c..3eebc19f8b 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -25,6 +25,7 @@ func TestCronBasic(t *testing.T) { WithMockAdapter(). WithCLNodes(1). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) @@ -71,6 +72,7 @@ func TestCronJobReplacement(t *testing.T) { WithMockAdapter(). WithCLNodes(1). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 72dc15e7b1..5b35b0d248 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -31,6 +31,7 @@ func TestFluxBasic(t *testing.T) { WithMockAdapter(). WithCLNodes(3). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index d4f9b5884a..923ca046ec 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -26,6 +26,7 @@ func TestForwarderOCRBasic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index c9fe3cb11d..bdfd65c767 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -35,6 +35,7 @@ func TestForwarderOCR2Basic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index bcf64a5feb..336223b7a4 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1113,6 +1113,7 @@ func setupKeeperTest(t *testing.T) ( WithCLNodeConfig(clNodeConfig). WithFunding(big.NewFloat(.5)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "Error deploying test environment") diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 0676ed0300..8f0fbd7605 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -33,6 +33,7 @@ func TestOCRv2Basic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) @@ -107,6 +108,7 @@ func TestOCRv2JobReplacement(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 57afbdc1a4..25192248c4 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -24,6 +24,7 @@ func TestOCRBasic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.5)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index e2cd28b332..2fc771fb9b 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -29,6 +29,7 @@ func TestRunLogBasic(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 9c24d97b13..0412005374 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -29,6 +29,7 @@ func TestVRFBasic(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) env.ParallelTransactions(true) @@ -118,6 +119,7 @@ func TestVRFJobReplacement(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err) env.ParallelTransactions(true) diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 4edb92e5df..9976de0395 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -34,6 +34,7 @@ func TestVRFv2Basic(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "error creating test env") @@ -125,6 +126,7 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "error creating test env") diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index f4f52b6ee0..69e1eb7ebd 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -39,6 +39,7 @@ func TestVRFv2Plus(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "error creating test env") @@ -616,6 +617,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "error creating test env") @@ -706,6 +708,7 @@ func TestVRFv2PlusMigration(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 7bf1657316..48f34e6827 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -1059,6 +1059,7 @@ func setupLogPollerTestDocker( WithChainOptions(logPolllerSettingsFn). EVMClientNetworkOptions(evmClientSettingsFn). WithStandardCleanup(). + WithLogStream(). Build() require.NoError(t, err, "Error deploying test environment") From 8b13213bfbbe855fc1ffadf82301b47b4ec1b00b Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 8 Dec 2023 06:53:40 -0600 Subject: [PATCH 289/327] go generate a mermaid flowchart for org modules (#11467) --- GNUmakefile | 4 +++ go.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++ main.go | 1 + tools/bin/modgraph | 46 ++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 go.md create mode 100755 tools/bin/modgraph diff --git a/GNUmakefile b/GNUmakefile index 7d0753911a..09b1dfe87a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -147,6 +147,10 @@ goreleaser-dev-build: ## Run goreleaser snapshot build goreleaser-dev-release: ## run goreleaser snapshot release ./tools/bin/goreleaser_wrapper release --snapshot --rm-dist --config ${GORELEASER_CONFIG} +.PHONY: modgraph +modgraph: + ./tools/bin/modgraph > go.md + help: @echo "" @echo " .__ .__ .__ .__ __" diff --git a/go.md b/go.md new file mode 100644 index 0000000000..090221a89f --- /dev/null +++ b/go.md @@ -0,0 +1,65 @@ +# smartcontractkit Go modules +```mermaid +flowchart LR + subgraph chains + chainlink-cosmos + chainlink-evm + chainlink-solana + chainlink-starknet/relayer + end + + subgraph products + chainlink-automation + chainlink-ccip + chainlink-data-streams + chainlink-feeds + chainlink-functions + chainlink-vrf + end + + classDef outline stroke-dasharray:6,fill:none; + class chains,products outline + + chainlink/v2 --> caigo + click caigo href "https://github.com/smartcontractkit/caigo" + chainlink/v2 --> chainlink-automation + click chainlink-automation href "https://github.com/smartcontractkit/chainlink-automation" + chainlink/v2 --> chainlink-common + click chainlink-common href "https://github.com/smartcontractkit/chainlink-common" + chainlink/v2 --> chainlink-cosmos + click chainlink-cosmos href "https://github.com/smartcontractkit/chainlink-cosmos" + chainlink/v2 --> chainlink-data-streams + click chainlink-data-streams href "https://github.com/smartcontractkit/chainlink-data-streams" + chainlink/v2 --> chainlink-feeds + click chainlink-feeds href "https://github.com/smartcontractkit/chainlink-feeds" + chainlink/v2 --> chainlink-solana + click chainlink-solana href "https://github.com/smartcontractkit/chainlink-solana" + chainlink/v2 --> chainlink-starknet/relayer + click chainlink-starknet/relayer href "https://github.com/smartcontractkit/chainlink-starknet" + chainlink/v2 --> chainlink-vrf + click chainlink-vrf href "https://github.com/smartcontractkit/chainlink-vrf" + chainlink/v2 --> libocr + click libocr href "https://github.com/smartcontractkit/libocr" + chainlink/v2 --> tdh2/go/ocr2/decryptionplugin + click tdh2/go/ocr2/decryptionplugin href "https://github.com/smartcontractkit/tdh2" + chainlink/v2 --> tdh2/go/tdh2 + click tdh2/go/tdh2 href "https://github.com/smartcontractkit/tdh2" + chainlink/v2 --> wsrpc + click wsrpc href "https://github.com/smartcontractkit/wsrpc" + chainlink-automation --> libocr + chainlink-common --> libocr + chainlink-cosmos --> chainlink-common + chainlink-cosmos --> libocr + chainlink-data-streams --> chainlink-common + chainlink-data-streams --> libocr + chainlink-feeds --> chainlink-common + chainlink-feeds --> libocr + chainlink-solana --> chainlink-common + chainlink-solana --> libocr + chainlink-starknet/relayer --> caigo + chainlink-starknet/relayer --> chainlink-common + chainlink-starknet/relayer --> libocr + chainlink-vrf --> libocr + tdh2/go/ocr2/decryptionplugin --> libocr + tdh2/go/ocr2/decryptionplugin --> tdh2/go/tdh2 +``` diff --git a/main.go b/main.go index 2a224c96d2..7e262f85f2 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core" ) +//go:generate make modgraph func main() { os.Exit(core.Main()) } diff --git a/tools/bin/modgraph b/tools/bin/modgraph new file mode 100755 index 0000000000..b61264cb02 --- /dev/null +++ b/tools/bin/modgraph @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# Generates go.md + +set -e + +echo "# smartcontractkit Go modules +\`\`\`mermaid +flowchart LR + subgraph chains + chainlink-cosmos + chainlink-evm + chainlink-solana + chainlink-starknet/relayer + end + + subgraph products + chainlink-automation + chainlink-ccip + chainlink-data-streams + chainlink-feeds + chainlink-functions + chainlink-vrf + end + + classDef outline stroke-dasharray:6,fill:none; + class chains,products outline +" +go mod graph | \ + # org only + grep smartcontractkit.*smartcontractkit | \ + # drop prefix + sed s/"github\.com\/smartcontractkit\/"/""/g | \ + # insert edges + sed s/" "/" --> "/ | \ + # drop versions + sed s/"@[^ ]*"/""/g | \ + # insert links + sed s/"\([^ ]*\)$"/"\1\nclick \1 href \"https:\/\/github.com\/smartcontractkit\/\1\""/ | \ + # truncate links to repo + sed s/"\"https:\/\/github.com\/smartcontractkit\/\([^\"\/]*\)\/.*\""/"\"https:\/\/github.com\/smartcontractkit\/\1\""/ | \ + # dedupe lines + awk '!x[$0]++' | \ + # indent + sed 's/^/ /' +echo "\`\`\`" \ No newline at end of file From d3f99e408c27eb294873fbbfe9d57d0f9aab91f2 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 8 Dec 2023 08:31:24 -0600 Subject: [PATCH 290/327] use servicetest.Run & RunHealthy (#11354) --- .../chains/evm/gas/arbitrum_estimator_test.go | 19 ++++----- .../gas/rollups/l1_gas_price_oracle_test.go | 10 ++--- .../evm/gas/suggested_price_estimator_test.go | 13 +++---- .../evm/headtracker/head_broadcaster_test.go | 11 +++--- core/chains/evm/log/helpers_test.go | 1 + core/chains/evm/log/integration_test.go | 3 +- .../evm/logpoller/log_poller_internal_test.go | 13 +++---- core/chains/evm/monitor/balance_test.go | 18 +++------ core/chains/evm/txmgr/broadcaster_test.go | 14 +++---- core/chains/evm/txmgr/confirmer_test.go | 7 ++-- core/chains/evm/txmgr/txmgr_test.go | 4 +- core/internal/testutils/evmtest/evmtest.go | 4 +- core/services/directrequest/delegate_test.go | 7 ++-- core/services/feeds/service_test.go | 18 ++++----- .../fluxmonitorv2/flux_monitor_test.go | 25 ++++-------- core/services/functions/listener_test.go | 26 +++++-------- .../gateway/connector/connector_test.go | 5 +-- core/services/gateway/gateway_test.go | 4 +- .../functions/handler.functions_test.go | 4 +- .../gateway_integration_test.go | 8 ++-- .../gateway/network/wsconnection_test.go | 10 ++--- core/services/job/runner_integration_test.go | 31 +++++++-------- core/services/job/spawner_test.go | 10 ++--- .../keeper/registry1_1_synchronizer_test.go | 16 +++----- .../keeper/registry1_2_synchronizer_test.go | 25 +++++------- .../keeper/registry1_3_synchronizer_test.go | 39 +++++++------------ .../registry_synchronizer_helper_test.go | 5 ++- core/services/keeper/upkeep_executer_test.go | 4 +- core/services/nurse_test.go | 1 - core/services/ocr/config_overrider_test.go | 8 ++-- core/services/ocr/contract_tracker_test.go | 8 ++-- .../evmregistry/v21/upkeepstate/store_test.go | 9 ++--- core/services/ocrcommon/peer_wrapper_test.go | 7 ++-- core/services/ocrcommon/run_saver_test.go | 6 +-- core/services/ocrcommon/telemetry.go | 2 +- core/services/ocrcommon/telemetry_test.go | 10 ++--- core/services/pg/event_broadcaster_test.go | 5 +-- .../promreporter/prom_reporter_test.go | 12 +++--- core/services/relay/evm/config_poller_test.go | 8 ++-- .../relay/evm/functions/config_poller_test.go | 9 ++--- .../evm/functions/logpoller_wrapper_test.go | 10 ++--- .../relay/evm/mercury/helpers_test.go | 5 +-- .../evm/mercury/wsrpc/cache/cache_set_test.go | 12 +++--- .../relay/evm/mercury/wsrpc/client_test.go | 7 ++-- core/services/srvctest/servicetest.go | 18 --------- .../telemetry_ingress_batch_client_test.go | 7 +--- .../telemetry_ingress_client_test.go | 5 +-- core/services/vrf/delegate_test.go | 23 ++++++----- .../vrf/v1/listener_v1_test_helpers.go | 4 +- core/web/jobs_controller_test.go | 1 + 50 files changed, 214 insertions(+), 317 deletions(-) delete mode 100644 core/services/srvctest/servicetest.go diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index 53f8161798..9d56e2c10a 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" @@ -66,8 +67,7 @@ func TestArbitrumEstimator(t *testing.T) { }).Return(zeros.Bytes(), nil) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) // Expected price for a standard l2_suggested_estimator would be 42, but we add a fixed gasPriceBufferPercentage. @@ -92,8 +92,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(40)) require.Error(t, err) assert.EqualError(t, err, "estimated gas price: 42 wei is greater than the maximum gas price configured: 40 wei") @@ -118,8 +117,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(110)) assert.EqualError(t, err, "estimated gas price: 120 wei is greater than the maximum gas price configured: 110 wei") assert.Nil(t, gasPrice) @@ -148,8 +146,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "failed to estimate gas; gas price not set") @@ -181,8 +178,7 @@ func TestArbitrumEstimator(t *testing.T) { }).Return(b.Bytes(), nil) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) require.NotNil(t, gasPrice) @@ -216,8 +212,7 @@ func TestArbitrumEstimator(t *testing.T) { }).Return(b.Bytes(), nil) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.Error(t, err, "expected error but got (%s, %d)", gasPrice, chainSpecificGasLimit) }) diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go index 2defedd6b4..1a1d1ffdee 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -50,8 +51,7 @@ func TestL1GasPriceOracle(t *testing.T) { }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainArbitrum) - require.NoError(t, oracle.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) require.NoError(t, err) @@ -72,8 +72,7 @@ func TestL1GasPriceOracle(t *testing.T) { }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainKroma) - require.NoError(t, oracle.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) require.NoError(t, err) @@ -94,8 +93,7 @@ func TestL1GasPriceOracle(t *testing.T) { }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock) - require.NoError(t, oracle.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) require.NoError(t, err) diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index 304e535910..8e45f5b759 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" @@ -40,8 +41,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) assert.Equal(t, assets.NewWeiI(42), gasPrice) @@ -57,8 +57,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { (*big.Int)(res).SetInt64(42) }) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(40)) require.Error(t, err) assert.EqualError(t, err, "estimated gas price: 42 wei is greater than the maximum gas price configured: 40 wei") @@ -75,8 +74,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { (*big.Int)(res).SetInt64(120) }) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(110)) assert.EqualError(t, err, "estimated gas price: 120 wei is greater than the maximum gas price configured: 110 wei") assert.Nil(t, gasPrice) @@ -96,8 +94,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "failed to estimate gas; gas price not set") diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index 6fb151bfe6..ac43c08fe8 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -11,6 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + commonhtrk "github.com/smartcontractkit/chainlink/v2/common/headtracker" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" @@ -21,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -68,14 +69,14 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { checker1 := &cltest.MockHeadTrackable{} checker2 := &cltest.MockHeadTrackable{} - hb := headtracker.NewHeadBroadcaster(logger) orm := headtracker.NewORM(db, logger, cfg.Database(), *ethClient.ConfiguredChainID()) hs := headtracker.NewHeadSaver(logger, orm, evmCfg.EVM(), evmCfg.EVM().HeadTracker()) mailMon := utils.NewMailboxMonitor(t.Name()) + servicetest.Run(t, mailMon) + hb := headtracker.NewHeadBroadcaster(logger) + servicetest.Run(t, hb) ht := headtracker.NewHeadTracker(logger, ethClient, evmCfg.EVM(), evmCfg.EVM().HeadTracker(), hb, hs, mailMon) - var ms services.MultiStart - require.NoError(t, ms.Start(testutils.Context(t), mailMon, hb, ht)) - t.Cleanup(func() { require.NoError(t, services.CloseAll(mailMon, hb, ht)) }) + servicetest.Run(t, ht) latest1, unsubscribe1 := hb.Subscribe(checker1) // "latest head" is nil here because we didn't receive any yet diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index 49f9266f70..e41f08e8d2 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index 2d66cdf585..e5b6ad3caf 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -1324,7 +1325,7 @@ func TestBroadcaster_AppendLogChannel(t *testing.T) { ch3 := make(chan types.Log) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.RunHealthy(t, utils.NewMailboxMonitor(t.Name())) lb := log.NewBroadcaster(nil, ethClient, nil, logger.Test(t), nil, mailMon) chCombined := lb.ExportedAppendLogChannel(ch1, ch2) chCombined = lb.ExportedAppendLogChannel(chCombined, ch3) diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index e3ba8b655e..f840eefc7b 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -351,8 +352,7 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Maybe() // in case task gets delayed by >= 100ms t.Cleanup(lp.reset) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) select { case <-ctx.Done(): @@ -389,8 +389,7 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Maybe() // in case task gets delayed by >= 100ms t.Cleanup(lp.reset) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) select { case <-ctx.Done(): @@ -402,8 +401,7 @@ func TestLogPoller_Replay(t *testing.T) { // ReplayAsync should return as soon as replayStart is received t.Run("ReplayAsync success", func(t *testing.T) { t.Cleanup(lp.reset) - require.NoError(t, lp.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) lp.ReplayAsync(1) @@ -412,8 +410,7 @@ func TestLogPoller_Replay(t *testing.T) { t.Run("ReplayAsync error", func(t *testing.T) { t.Cleanup(lp.reset) - require.NoError(t, lp.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) anyErr := errors.New("async error") observedLogs.TakeAll() diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index c2c976e78d..246d5d0759 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" @@ -44,7 +45,6 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() k0bal := big.NewInt(42) k1bal := big.NewInt(43) @@ -54,7 +54,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) ethClient.On("BalanceAt", mock.Anything, k1Addr, nilBigInt).Once().Return(k1bal, nil) - assert.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) gomega.NewWithT(t).Eventually(func() *big.Int { return bm.GetEthBalance(k0Addr).ToInt() @@ -72,12 +72,11 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() k0bal := big.NewInt(42) ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) - assert.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) gomega.NewWithT(t).Eventually(func() *big.Int { return bm.GetEthBalance(k0Addr).ToInt() @@ -92,7 +91,6 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() ctxCancelledAwaiter := cltest.NewAwaiter() ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Run(func(args mock.Arguments) { @@ -122,13 +120,12 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt). Once(). Return(nil, errors.New("a little easter egg for the 4chan link marines error")) - assert.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) gomega.NewWithT(t).Consistently(func() *big.Int { return bm.GetEthBalance(k0Addr).ToInt() @@ -160,8 +157,7 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) ethClient.On("BalanceAt", mock.Anything, k1Addr, nilBigInt).Once().Return(k1bal, nil) - require.NoError(t, bm.Start(testutils.Context(t))) - defer func() { assert.NoError(t, bm.Close()) }() + servicetest.RunHealthy(t, bm) ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) ethClient.On("BalanceAt", mock.Anything, k1Addr, nilBigInt).Once().Return(k1bal, nil) @@ -205,7 +201,7 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything). Once(). Return(big.NewInt(1), nil) - require.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) head := cltest.Head(0) @@ -234,8 +230,6 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { mockUnblocker <- time.Time{} }) - bm.Close() - // Make sure the BalanceAt mock wasn't called more than once assert.LessOrEqual(t, callCount.Load(), int32(1)) } diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index c6e05b0954..21a4bd2865 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -23,6 +23,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" @@ -59,7 +60,6 @@ func NewTestEthBroadcaster( nonceAutoSync bool, ) *txmgr.Broadcaster { t.Helper() - ctx := testutils.Context(t) lggr := logger.Test(t) ge := config.EVM().GasEstimator() @@ -70,8 +70,7 @@ func NewTestEthBroadcaster( // Mark instance as test ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing() - require.NoError(t, ethBroadcaster.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, ethBroadcaster.Close()) }) + servicetest.Run(t, ethBroadcaster) return ethBroadcaster } @@ -634,8 +633,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi eb.XXXTestDisableUnstartedTxAutoProcessing() // Start instance of broadcaster - require.NoError(t, eb.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, eb.Close()) }) + servicetest.Run(t, eb) mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) @@ -1794,8 +1792,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(ethNodeNonce), nil).Once() - require.NoError(t, eb.Start(ctx)) - defer func() { assert.NoError(t, eb.Close()) }() + servicetest.Run(t, eb) testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") @@ -1828,8 +1825,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("something exploded")).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil) - require.NoError(t, eb.Start(ctx)) - defer func() { assert.NoError(t, eb.Close()) }() + servicetest.Run(t, eb) testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 84c42cd00f..9d909d5834 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -1646,7 +1647,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Create confirmer with necessary state ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr) - require.NoError(t, ec.Start(testutils.Context(t))) + servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) nonce := int64(0) @@ -1691,7 +1692,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr) - require.NoError(t, ec.Start(testutils.Context(t))) + servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) nonce := int64(0) @@ -3080,6 +3081,6 @@ func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Cl txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) - require.NoError(t, ec.Start(testutils.Context(t))) + servicetest.Run(t, ec) return ec } diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 745623ed77..9833acfd45 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -21,6 +21,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" @@ -552,8 +553,7 @@ func TestTxm_Reset(t *testing.T) { assert.EqualError(t, err, "not started") }) - require.NoError(t, txm.Start(testutils.Context(t))) - defer func() { assert.NoError(t, txm.Close()) }() + servicetest.Run(t, txm) t.Run("returns no error if started", func(t *testing.T) { err := txm.Reset(addr, false) diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 423615145e..e0a447a327 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/types" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" @@ -36,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -118,7 +118,7 @@ func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainR } } if opts.MailMon == nil { - opts.MailMon = srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + opts.MailMon = servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) } if testopts.GasEstimator != nil { opts.GenGasEstimator = func(*big.Int) gas.EvmFeeEstimator { diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 56c28e5745..2d5b9bef03 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -14,6 +14,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -31,7 +33,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" pipeline_mocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -43,7 +44,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) relayerExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, MailMon: mailMon, KeyStore: keyStore.Eth()}) lggr := logger.TestLogger(t) @@ -80,7 +81,7 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi runner := pipeline_mocks.NewRunner(t) broadcaster.On("AddDependents", 1) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 271321a116..bd0993825e 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -9,8 +9,15 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" + "github.com/lib/pq" "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -36,13 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" - - "github.com/google/uuid" - "github.com/lib/pq" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" ) const FluxMonitorTestSpecTemplate = ` @@ -3465,9 +3465,7 @@ func Test_Service_StartStop(t *testing.T) { tt.beforeFunc(svc) } - require.NoError(t, svc.Start(testutils.Context(t))) - - svc.Close() + servicetest.Run(t, svc) }) } } diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index 1a14fb8bd0..b13edcc12d 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -21,6 +21,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -701,7 +702,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { Once(). Run(func(mock.Arguments) { readyToAssert.ItHappened() }) - require.NoError(t, fm.Start(testutils.Context(t))) + servicetest.Run(t, fm) var logBroadcasts []*logmocks.Broadcast @@ -724,8 +725,6 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { logsAwaiter.ItHappened() readyToAssert.AwaitOrFail(t) - - fm.Close() } func TestFluxMonitor_TriggerIdleTimeThreshold(t *testing.T) { @@ -1049,8 +1048,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { idleDurationOccured := make(chan struct{}, 4) initialPollOccurred := make(chan struct{}, 1) - require.NoError(t, fm.Start(testutils.Context(t))) - t.Cleanup(func() { fm.Close() }) + servicetest.Run(t, fm) // Initial Poll roundState1 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} @@ -1169,11 +1167,9 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutAtZero(t *testing.T) { require.NoError(t, fm.SetOracleAddress()) fm.ExportedRoundState(t) - require.NoError(t, fm.Start(testutils.Context(t))) + servicetest.Run(t, fm) g.Eventually(ch).Should(gomega.BeClosed()) - - fm.Close() } func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) { @@ -1229,15 +1225,13 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) Run(func(mock.Arguments) { close(chRoundState) }). Maybe() - require.NoError(t, fm.Start(testutils.Context(t))) + servicetest.Run(t, fm) if test.expectedToSubmit { g.Eventually(chRoundState).Should(gomega.BeClosed()) } else { g.Consistently(chRoundState).ShouldNot(gomega.BeClosed()) } - - require.NoError(t, fm.Close()) }) } } @@ -1310,8 +1304,7 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_IdleTimer(t *testing.T) { }). Maybe() - require.NoError(t, fm.Start(testutils.Context(t))) - t.Cleanup(func() { fm.Close() }) + servicetest.Run(t, fm) assert.Eventually(t, func() bool { return len(initialPollOccurred) == 1 }, 3*time.Second, 10*time.Millisecond) @@ -1385,7 +1378,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { Run(func(mock.Arguments) { close(chRoundState2) }). Once() - require.NoError(t, fm.Start(testutils.Context(t))) + servicetest.Run(t, fm) tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) @@ -1401,7 +1394,6 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { g.Eventually(chRoundState2).Should(gomega.BeClosed()) time.Sleep(time.Duration(2*timeout) * time.Second) - require.NoError(t, fm.Close()) } func TestFluxMonitor_ConsumeLogBroadcast(t *testing.T) { @@ -1927,8 +1919,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { Return(flux_aggregator_wrapper.OracleRoundState{RoundId: 4, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()}, nil). Maybe() - require.NoError(t, fm.Start(testutils.Context(t))) - defer func() { assert.NoError(t, fm.Close()) }() + servicetest.Run(t, fm) waitTime := 15 * time.Second interval := 50 * time.Millisecond diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 0fcc9c6559..5020537bf6 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -19,6 +19,8 @@ import ( decryptionPlugin "github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -38,7 +40,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" evmrelay_mocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types/mocks" s4_mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" sync_mocks "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" @@ -81,7 +82,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe ethClient := evmtest.NewEthClientMockWithDefaultChain(t) broadcaster := log_mocks.NewBroadcaster(t) broadcaster.On("AddDependents", 1) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db, cfg.Database()) @@ -175,9 +176,8 @@ func TestFunctionsListener_HandleOracleRequestV1_Success(t *testing.T) { close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_HandleOffchainRequest_Success(t *testing.T) { @@ -270,9 +270,8 @@ func TestFunctionsListener_HandleOracleRequestV1_ComputationError(t *testing.T) close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *testing.T) { @@ -312,9 +311,8 @@ func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *te close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { @@ -339,9 +337,8 @@ func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_ReportSourceCodeDomains(t *testing.T) { @@ -395,9 +392,8 @@ func TestFunctionsListener_PruneRequests(t *testing.T) { doneCh <- true }) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_TimeoutRequests(t *testing.T) { @@ -411,9 +407,8 @@ func TestFunctionsListener_TimeoutRequests(t *testing.T) { doneCh <- true }) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_ORMDoesNotFreezeHandlersForever(t *testing.T) { @@ -434,7 +429,6 @@ func TestFunctionsListener_ORMDoesNotFreezeHandlersForever(t *testing.T) { ormCallExited.Done() }).Return(errors.New("timeout")) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) ormCallExited.Wait() // should not freeze - uni.service.Close() } diff --git a/core/services/gateway/connector/connector_test.go b/core/services/gateway/connector/connector_test.go index 4001914524..1c2c6d26b1 100644 --- a/core/services/gateway/connector/connector_test.go +++ b/core/services/gateway/connector/connector_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector/mocks" @@ -121,8 +121,7 @@ func TestGatewayConnector_CleanStartAndClose(t *testing.T) { handler.On("Start", mock.Anything).Return(nil) handler.On("Close").Return(nil) signer.On("Sign", mock.Anything).Return(nil, errors.New("cannot sign")) - require.NoError(t, connector.Start(testutils.Context(t))) - require.NoError(t, connector.Close()) + servicetest.Run(t, connector) } func TestGatewayConnector_NewAuthHeader_SignerError(t *testing.T) { diff --git a/core/services/gateway/gateway_test.go b/core/services/gateway/gateway_test.go index 5fad6315a3..74d689fffe 100644 --- a/core/services/gateway/gateway_test.go +++ b/core/services/gateway/gateway_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" @@ -130,8 +131,7 @@ func TestGateway_CleanStartAndClose(t *testing.T) { lggr := logger.TestLogger(t) gateway, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, buildConfig("")), gateway.NewHandlerFactory(nil, lggr), lggr) require.NoError(t, err) - require.NoError(t, gateway.Start(testutils.Context(t))) - require.NoError(t, gateway.Close()) + servicetest.Run(t, gateway) } func requireJsonRPCResult(t *testing.T, response []byte, expectedId string, expectedResult string) { diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index f36b64709a..1d6dd10962 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" @@ -97,8 +98,7 @@ func TestFunctionsHandler_CleanStartAndClose(t *testing.T) { handler, err := functions.NewFunctionsHandlerFromConfig(json.RawMessage("{}"), &config.DONConfig{}, nil, nil, logger.TestLogger(t)) require.NoError(t, err) - require.NoError(t, handler.Start(testutils.Context(t))) - require.NoError(t, handler.Close()) + servicetest.Run(t, handler) } func TestFunctionsHandler_HandleUserMessage_SecretsSet(t *testing.T) { diff --git a/core/services/gateway/integration_tests/gateway_integration_test.go b/core/services/gateway/integration_tests/gateway_integration_test.go index 310047950e..415a8f67cf 100644 --- a/core/services/gateway/integration_tests/gateway_integration_test.go +++ b/core/services/gateway/integration_tests/gateway_integration_test.go @@ -14,6 +14,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" @@ -119,7 +120,7 @@ func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) gatewayConfig := fmt.Sprintf(gatewayConfigTemplate, nodeKeys.Address) gateway, err := gateway.NewGatewayFromConfig(parseGatewayConfig(t, gatewayConfig), gateway.NewHandlerFactory(nil, lggr), lggr) require.NoError(t, err) - require.NoError(t, gateway.Start(testutils.Context(t))) + servicetest.Run(t, gateway) userPort, nodePort := gateway.GetUserPort(), gateway.GetNodePort() userUrl := fmt.Sprintf("http://localhost:%d/user", userPort) nodeUrl := fmt.Sprintf("ws://localhost:%d/node", nodePort) @@ -129,7 +130,7 @@ func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) connector, err := connector.NewGatewayConnector(parseConnectorConfig(t, nodeConfigTemplate, nodeKeys.Address, nodeUrl), client, client, utils.NewRealClock(), lggr) require.NoError(t, err) client.connector = connector - require.NoError(t, connector.Start(testutils.Context(t))) + servicetest.Run(t, connector) // Send requests until one of them reaches Connector gomega.NewGomegaWithT(t).Eventually(func() bool { @@ -144,7 +145,4 @@ func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) _, _ = httpClient.Do(req) // could initially return error if Gateway is not fully initialized yet return client.done.Load() }, testutils.WaitTimeout(t), testutils.TestInterval).Should(gomega.Equal(true)) - - require.NoError(t, connector.Close()) - require.NoError(t, gateway.Close()) } diff --git a/core/services/gateway/network/wsconnection_test.go b/core/services/gateway/network/wsconnection_test.go index 5fd8aa50e3..4ded4f40b1 100644 --- a/core/services/gateway/network/wsconnection_test.go +++ b/core/services/gateway/network/wsconnection_test.go @@ -9,6 +9,7 @@ import ( "github.com/gorilla/websocket" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/network" @@ -30,18 +31,17 @@ func (ssl *serverSideLogic) wsHandler(w http.ResponseWriter, r *http.Request) { } func TestWSConnectionWrapper_ClientReconnect(t *testing.T) { - ctx := testutils.Context(t) lggr := logger.TestLogger(t) // server ssl := &serverSideLogic{connWrapper: network.NewWSConnectionWrapper(lggr)} - require.NoError(t, ssl.connWrapper.Start(ctx)) + servicetest.Run(t, ssl.connWrapper) s := httptest.NewServer(http.HandlerFunc(ssl.wsHandler)) serverURL := "ws" + strings.TrimPrefix(s.URL, "http") defer s.Close() // client clientConnWrapper := network.NewWSConnectionWrapper(lggr) - require.NoError(t, clientConnWrapper.Start(ctx)) + servicetest.Run(t, clientConnWrapper) // connect, write a message, disconnect conn, _, err := websocket.DefaultDialer.Dial(serverURL, nil) @@ -64,8 +64,4 @@ func TestWSConnectionWrapper_ClientReconnect(t *testing.T) { require.NoError(t, writeErr) <-ssl.connWrapper.ReadChannel() // consumed by server conn.Close() - - ssl.connWrapper.Close() - clientConnWrapper.Close() - clientConnWrapper.Close() // safe to call Close() twice } diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index ef0458312b..0223f1a10d 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -23,6 +23,8 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -40,7 +42,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -91,8 +92,7 @@ func TestRunner(t *testing.T) { _, placeHolderAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) - require.NoError(t, runner.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, runner.Close()) }) + servicetest.Run(t, runner) t.Run("gets the election result winner", func(t *testing.T) { var httpURL string @@ -451,8 +451,7 @@ answer1 [type=median index=0]; _, err = keyStore.P2P().Create() assert.NoError(t, err) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -463,7 +462,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -486,8 +485,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -498,7 +496,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -515,8 +513,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -527,7 +524,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -571,8 +568,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -583,7 +579,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), ) jb.OCROracleSpec.CaptureEATelemetry = tc.jbCaptureEATelemetry @@ -616,8 +612,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -628,7 +623,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), ) services, err := sd.ServicesForSpec(*jb) require.NoError(t, err) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 0ad7649143..d639ce859a 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -33,7 +34,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -128,7 +128,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA2 := mocks.NewServiceCtx(t) serviceA1.On("Start", mock.Anything).Return(nil).Once() serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyA.ItHappened() }) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) dA := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, make(chan struct{}), dA} @@ -187,7 +187,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -221,7 +221,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -299,7 +299,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { jobOCR2VRF := makeOCR2VRFJobSpec(t, keyStore, config, address, chain.ID(), 2) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }) ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), config.Database(), processConfig) diff --git a/core/services/keeper/registry1_1_synchronizer_test.go b/core/services/keeper/registry1_1_synchronizer_test.go index 031b7a5907..fb0b1866c4 100644 --- a/core/services/keeper/registry1_1_synchronizer_test.go +++ b/core/services/keeper/registry1_1_synchronizer_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -217,8 +218,7 @@ func Test_RegistrySynchronizer1_1_ConfigSetLog(t *testing.T) { upkeepConfig1_1, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -266,8 +266,7 @@ func Test_RegistrySynchronizer1_1_KeepersUpdatedLog(t *testing.T) { upkeepConfig1_1, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -313,8 +312,7 @@ func Test_RegistrySynchronizer1_1_UpkeepCanceledLog(t *testing.T) { upkeepConfig1_1, 3) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -352,8 +350,7 @@ func Test_RegistrySynchronizer1_1_UpkeepRegisteredLog(t *testing.T) { upkeepConfig1_1, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -396,8 +393,7 @@ func Test_RegistrySynchronizer1_1_UpkeepPerformedLog(t *testing.T) { upkeepConfig1_1, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) diff --git a/core/services/keeper/registry1_2_synchronizer_test.go b/core/services/keeper/registry1_2_synchronizer_test.go index e7d8d6a48a..b7456ad94e 100644 --- a/core/services/keeper/registry1_2_synchronizer_test.go +++ b/core/services/keeper/registry1_2_synchronizer_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -237,8 +238,7 @@ func Test_RegistrySynchronizer1_2_ConfigSetLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -290,8 +290,7 @@ func Test_RegistrySynchronizer1_2_KeepersUpdatedLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -342,8 +341,7 @@ func Test_RegistrySynchronizer1_2_UpkeepCanceledLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -382,8 +380,7 @@ func Test_RegistrySynchronizer1_2_UpkeepRegisteredLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -427,8 +424,7 @@ func Test_RegistrySynchronizer1_2_UpkeepPerformedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -482,8 +478,7 @@ func Test_RegistrySynchronizer1_2_UpkeepGasLimitSetLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -535,8 +530,7 @@ func Test_RegistrySynchronizer1_2_UpkeepReceivedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -578,8 +572,7 @@ func Test_RegistrySynchronizer1_2_UpkeepMigratedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) diff --git a/core/services/keeper/registry1_3_synchronizer_test.go b/core/services/keeper/registry1_3_synchronizer_test.go index a0522fd717..6e3be4ea78 100644 --- a/core/services/keeper/registry1_3_synchronizer_test.go +++ b/core/services/keeper/registry1_3_synchronizer_test.go @@ -12,19 +12,20 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) var registryConfig1_3 = registry1_3.Config{ @@ -242,8 +243,7 @@ func Test_RegistrySynchronizer1_3_ConfigSetLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -295,8 +295,7 @@ func Test_RegistrySynchronizer1_3_KeepersUpdatedLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -347,8 +346,7 @@ func Test_RegistrySynchronizer1_3_UpkeepCanceledLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -387,8 +385,7 @@ func Test_RegistrySynchronizer1_3_UpkeepRegisteredLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -432,8 +429,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPerformedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -487,8 +483,7 @@ func Test_RegistrySynchronizer1_3_UpkeepGasLimitSetLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -540,8 +535,7 @@ func Test_RegistrySynchronizer1_3_UpkeepReceivedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -583,8 +577,7 @@ func Test_RegistrySynchronizer1_3_UpkeepMigratedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -625,8 +618,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -695,8 +687,7 @@ func Test_RegistrySynchronizer1_3_UpkeepCheckDataUpdatedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index 966366b106..5ba60db396 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -10,6 +10,8 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -21,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -72,7 +73,7 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( })).Maybe().Return(func() {}) lbMock.On("IsConnected").Return(true).Maybe() - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) orm := keeper.NewORM(db, logger.TestLogger(t), ch.Config().Database()) synchronizer := keeper.NewRegistrySynchronizer(keeper.RegistrySynchronizerOptions{ diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 7bbecafa22..123b1dc0de 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -15,6 +15,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -88,8 +89,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain lggr := logger.TestLogger(t) executer := keeper.NewUpkeepExecuter(job, orm, jpv2.Pr, ethClient, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, ch.Config().Keeper(), job.KeeperSpec.FromAddress.Address()) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, ch.Config().Database(), registry) - require.NoError(t, executer.Start(testutils.Context(t))) - t.Cleanup(func() { executer.Close() }) + servicetest.Run(t, executer) return db, cfg, ethClient, executer, registry, upkeep, job, jpv2, txm, keyStore, ch, orm } diff --git a/core/services/nurse_test.go b/core/services/nurse_test.go index 4e68501b74..79f57d9123 100644 --- a/core/services/nurse_test.go +++ b/core/services/nurse_test.go @@ -128,7 +128,6 @@ func TestNurse(t *testing.T) { n2, err := nrse.totalProfileBytes() require.NoError(t, err) require.Greater(t, n2, uint64(0)) - } func profileExists(t *testing.T, nrse *Nurse, typ string) bool { diff --git a/core/services/ocr/config_overrider_test.go b/core/services/ocr/config_overrider_test.go index 245d634876..acd5245e19 100644 --- a/core/services/ocr/config_overrider_test.go +++ b/core/services/ocr/config_overrider_test.go @@ -14,9 +14,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" @@ -72,7 +72,7 @@ func TestIntegration_OCRConfigOverrider_EntersHibernation(t *testing.T) { Run(checkFlagsAddress(t, uni.contractAddress)). Return([]bool{true, true}, nil) - require.NoError(t, uni.overrider.Start(testutils.Context(t))) + servicetest.Run(t, uni.overrider) // not hibernating initially require.Nil(t, uni.overrider.ConfigOverride()) @@ -102,7 +102,7 @@ func Test_OCRConfigOverrider(t *testing.T) { Run(checkFlagsAddress(t, uni.contractAddress)). Return([]bool{true, true}, nil) - require.NoError(t, uni.overrider.Start(testutils.Context(t))) + servicetest.Run(t, uni.overrider) // not hibernating initially require.Nil(t, uni.overrider.ConfigOverride()) @@ -130,7 +130,7 @@ func Test_OCRConfigOverrider(t *testing.T) { Run(checkFlagsAddress(t, uni.contractAddress)). Return([]bool{true, false}, nil) - require.NoError(t, uni.overrider.Start(testutils.Context(t))) + servicetest.Run(t, uni.overrider) // initially enters hibernation expectedOverride := &ocrtypes.ConfigOverride{AlphaPPB: math.MaxUint64, DeltaC: uni.overrider.DeltaCFromAddress} diff --git a/core/services/ocr/contract_tracker_test.go b/core/services/ocr/contract_tracker_test.go index 5684219cf1..af65f330d6 100644 --- a/core/services/ocr/contract_tracker_test.go +++ b/core/services/ocr/contract_tracker_test.go @@ -15,6 +15,8 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -29,7 +31,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" ocrmocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -83,7 +84,7 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack uni.hb = commonmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) uni.ec = evmtest.NewEthClientMock(t) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) db := pgtest.NewSqlxDB(t) uni.tracker = ocr.NewOCRContractTracker( contract, @@ -148,13 +149,12 @@ func Test_OCRContractTracker_LatestBlockHeight(t *testing.T) { uni.db.On("LoadLatestRoundRequested").Return(offchainaggregator.OffchainAggregatorRoundRequested{}, nil) uni.lb.On("Register", uni.tracker, mock.Anything).Return(func() {}) - require.NoError(t, uni.tracker.Start(testutils.Context(t))) + servicetest.Run(t, uni.tracker) l, err := uni.tracker.LatestBlockHeight(testutils.Context(t)) require.NoError(t, err) assert.Equal(t, uint64(42), l) - require.NoError(t, uni.tracker.Close()) }) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go index 138b9ffd78..7108e1b64c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go @@ -14,6 +14,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -346,7 +347,7 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { scanner := &mockScanner{} store := NewUpkeepStateStore(orm, lggr, scanner) - require.NoError(t, store.Start(ctx)) + servicetest.Run(t, store) t.Cleanup(func() { t.Log("cleaning up database") @@ -379,8 +380,6 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { observedLogs.TakeAll() require.Equal(t, 0, observedLogs.Len()) - - require.NoError(t, store.Close()) }) } } @@ -467,7 +466,7 @@ func TestUpkeepStateStore_Service(t *testing.T) { store.retention = 500 * time.Millisecond store.cleanCadence = 100 * time.Millisecond - assert.NoError(t, store.Start(ctx), "no error from starting service") + servicetest.Run(t, store) // add a value to set up the test require.NoError(t, store.SetUpkeepState(ctx, ocr2keepers.CheckResult{ @@ -493,8 +492,6 @@ func TestUpkeepStateStore_Service(t *testing.T) { values, err = store.SelectByWorkIDs(ctx, "0x2") require.NoError(t, err, "no error from selecting states") require.Equal(t, []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, values, "selected values should match expected") - - assert.NoError(t, store.Close(), "no error from closing service") } func createUpkeepIDForTest(v int64) ocr2keepers.UpkeepIdentifier { diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index 854ecb153e..dbe2252372 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -9,6 +9,7 @@ import ( p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -52,9 +53,8 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { }) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - require.NoError(t, pw.Start(testutils.Context(t)), "foo") + servicetest.Run(t, pw) require.Equal(t, k.PeerID(), pw.PeerID) - require.NoError(t, pw.Close()) }) t.Run("with one p2p key and mismatching P2P.PeerID returns error", func(t *testing.T) { @@ -89,9 +89,8 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - require.NoError(t, pw.Start(testutils.Context(t)), "foo") + servicetest.Run(t, pw) require.Equal(t, k2.PeerID(), pw.PeerID) - require.NoError(t, pw.Close()) }) t.Run("with multiple p2p keys and mismatching P2P.PeerID returns error", func(t *testing.T) { diff --git a/core/services/ocrcommon/run_saver_test.go b/core/services/ocrcommon/run_saver_test.go index 73697d181b..7bfe60f2a0 100644 --- a/core/services/ocrcommon/run_saver_test.go +++ b/core/services/ocrcommon/run_saver_test.go @@ -4,9 +4,8 @@ import ( "testing" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" @@ -20,7 +19,7 @@ func TestRunSaver(t *testing.T) { 1000, 100, ) - require.NoError(t, rs.Start(testutils.Context(t))) + servicetest.Run(t, rs) for i := 0; i < 100; i++ { d := i pipelineRunner.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). @@ -31,5 +30,4 @@ func TestRunSaver(t *testing.T) { Once() rs.Save(&pipeline.Run{ID: int64(i)}) } - require.NoError(t, rs.Close()) } diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index 18080fe22b..5fbda45608 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -99,7 +99,7 @@ func (e *EnhancedTelemetryService[T]) Start(context.Context) error { func (e *EnhancedTelemetryService[T]) Close() error { return e.StopOnce("EnhancedTelemetryService", func() error { - e.chDone <- struct{}{} + close(e.chDone) e.lggr.Infof("Stopping enhanced telemetry service for job %d", e.job.ID) return nil }) diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index ae58e89d22..9c90eea180 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -14,11 +14,11 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" mercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -213,7 +213,7 @@ func TestSendEATelemetry(t *testing.T) { lggr, _ := logger.TestLoggerObserved(t, zap.WarnLevel) doneCh := make(chan struct{}) enhancedTelemService := NewEnhancedTelemetryService(&jb, enhancedTelemChan, doneCh, monitoringEndpoint, lggr.Named("Enhanced Telemetry Mercury")) - require.NoError(t, enhancedTelemService.Start(testutils.Context(t))) + servicetest.Run(t, enhancedTelemService) trrs := pipeline.TaskRunResults{ pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ @@ -324,7 +324,7 @@ func TestCollectAndSend(t *testing.T) { doneCh := make(chan struct{}) enhancedTelemService := NewEnhancedTelemetryService(&jb, enhancedTelemChan, doneCh, monitoringEndpoint, lggr.Named("Enhanced Telemetry")) - require.NoError(t, enhancedTelemService.Start(testutils.Context(t))) + servicetest.Run(t, enhancedTelemService) finalResult := &pipeline.FinalResult{ Values: []interface{}{"123456"}, AllErrors: nil, @@ -574,7 +574,7 @@ func TestCollectMercuryEnhancedTelemetryV1(t *testing.T) { lggr: lggr, monitoringEndpoint: monitoringEndpoint, } - require.NoError(t, e.Start(testutils.Context(t))) + servicetest.Run(t, &e) wg.Add(1) @@ -690,7 +690,7 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { lggr: lggr, monitoringEndpoint: monitoringEndpoint, } - require.NoError(t, e.Start(testutils.Context(t))) + servicetest.Run(t, &e) wg.Add(1) diff --git a/core/services/pg/event_broadcaster_test.go b/core/services/pg/event_broadcaster_test.go index 41dcbb0176..e8a4a1086d 100644 --- a/core/services/pg/event_broadcaster_test.go +++ b/core/services/pg/event_broadcaster_test.go @@ -9,8 +9,8 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -19,8 +19,7 @@ func TestEventBroadcaster(t *testing.T) { config, _ := heavyweight.FullTestDBNoFixturesV2(t, nil) eventBroadcaster := pg.NewEventBroadcaster(config.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) - t.Cleanup(func() { require.NoError(t, eventBroadcaster.Close()) }) + servicetest.Run(t, eventBroadcaster) t.Run("doesn't broadcast unrelated events (no payload filter)", func(t *testing.T) { sub, err := eventBroadcaster.Subscribe("foo", "") diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 54e3a5d3fa..1cebba2faf 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -7,10 +7,11 @@ import ( "time" "github.com/jmoiron/sqlx" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -76,8 +77,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { }). Return() - require.NoError(t, reporter.Start(testutils.Context(t))) - defer func() { assert.NoError(t, reporter.Close()) }() + servicetest.Run(t, reporter) head := newHead() reporter.OnNewLongestChain(testutils.Context(t), &head) @@ -107,8 +107,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { }). Return() reporter := promreporter.NewPromReporter(db.DB, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond) - require.NoError(t, reporter.Start(testutils.Context(t))) - defer func() { assert.NoError(t, reporter.Close()) }() + servicetest.Run(t, reporter) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) @@ -143,8 +142,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { subscribeCalls.Add(1) }). Return() - require.NoError(t, reporter.Start(testutils.Context(t))) - defer func() { assert.NoError(t, reporter.Close()) }() + servicetest.Run(t, reporter) head := newHead() reporter.OnNewLongestChain(testutils.Context(t), &head) diff --git a/core/services/relay/evm/config_poller_test.go b/core/services/relay/evm/config_poller_test.go index 0a433c3bc5..3409c2f159 100644 --- a/core/services/relay/evm/config_poller_test.go +++ b/core/services/relay/evm/config_poller_test.go @@ -7,8 +7,6 @@ import ( "time" "github.com/ethereum/go-ethereum" - "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" @@ -22,12 +20,14 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" testoffchainaggregator2 "github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -85,11 +85,9 @@ func TestConfigPoller(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(false) ethClient = evmclient.NewSimulatedBackendClient(t, b, testutils.SimulatedChainID) - ctx := testutils.Context(t) lorm := logpoller.NewORM(testutils.SimulatedChainID, db, lggr, cfg) lp = logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { lp.Close() }) + servicetest.Run(t, lp) } t.Run("LatestConfig errors if there is no config in logs and config store is unconfigured", func(t *testing.T) { diff --git a/core/services/relay/evm/functions/config_poller_test.go b/core/services/relay/evm/functions/config_poller_test.go index 085f0c6e31..a5e5c1f805 100644 --- a/core/services/relay/evm/functions/config_poller_test.go +++ b/core/services/relay/evm/functions/config_poller_test.go @@ -20,8 +20,7 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - functionsConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -29,6 +28,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + functionsConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -78,11 +79,9 @@ func runTest(t *testing.T, pluginType functions.FunctionsPluginType, expectedDig ethClient := evmclient.NewSimulatedBackendClient(t, b, big.NewInt(1337)) defer ethClient.Close() lggr := logger.TestLogger(t) - ctx := testutils.Context(t) lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) - defer lp.Close() - require.NoError(t, lp.Start(ctx)) + servicetest.Run(t, lp) configPoller, err := functions.NewFunctionsConfigPoller(pluginType, lp, lggr) require.NoError(t, err) require.NoError(t, configPoller.UpdateRoutes(ocrAddress, ocrAddress)) diff --git a/core/services/relay/evm/functions/logpoller_wrapper_test.go b/core/services/relay/evm/functions/logpoller_wrapper_test.go index 2108e822d5..9df285b4c2 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper_test.go +++ b/core/services/relay/evm/functions/logpoller_wrapper_test.go @@ -12,11 +12,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" @@ -95,13 +95,12 @@ func TestLogPollerWrapper_SingleSubscriberEmptyEvents(t *testing.T) { subscriber := newSubscriber(1) lpWrapper.SubscribeToUpdates("mock_subscriber", subscriber) - require.NoError(t, lpWrapper.Start(testutils.Context(t))) + servicetest.Run(t, lpWrapper) subscriber.updates.Wait() reqs, resps, err := lpWrapper.LatestEvents() require.NoError(t, err) require.Equal(t, 0, len(reqs)) require.Equal(t, 0, len(resps)) - lpWrapper.Close() } func TestLogPollerWrapper_ErrorOnZeroAddresses(t *testing.T) { @@ -111,10 +110,9 @@ func TestLogPollerWrapper_ErrorOnZeroAddresses(t *testing.T) { client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(addr(t, "00"), nil) - require.NoError(t, lpWrapper.Start(testutils.Context(t))) + servicetest.Run(t, lpWrapper) _, _, err := lpWrapper.LatestEvents() require.Error(t, err) - lpWrapper.Close() } func TestLogPollerWrapper_LatestEvents_ReorgHandling(t *testing.T) { @@ -135,7 +133,7 @@ func TestLogPollerWrapper_LatestEvents_ReorgHandling(t *testing.T) { // On the 3rd query, the original request log appears again lp.On("Logs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{mockedLog}, nil).Once() - require.NoError(t, lpWrapper.Start(testutils.Context(t))) + servicetest.Run(t, lpWrapper) subscriber.updates.Wait() oracleRequests, _, err := lpWrapper.LatestEvents() diff --git a/core/services/relay/evm/mercury/helpers_test.go b/core/services/relay/evm/mercury/helpers_test.go index 3a58a25a55..59e0e58781 100644 --- a/core/services/relay/evm/mercury/helpers_test.go +++ b/core/services/relay/evm/mercury/helpers_test.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" @@ -167,13 +168,11 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { cfg := pgtest.NewQConfig(false) ethClient := evmclient.NewSimulatedBackendClient(t, b, big.NewInt(1337)) lggr := logger.TestLogger(t) - ctx := testutils.Context(t) lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) eventBroadcaster := pgmocks.NewEventBroadcaster(t) subscription := pgmocks.NewSubscription(t) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { lp.Close() }) + servicetest.Run(t, lp) eventBroadcaster.On("Subscribe", "evm.insert_on_logs", "").Return(subscription, nil) diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go index 4e19c7b56d..7d754b8326 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go @@ -3,21 +3,19 @@ package cache import ( "testing" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" ) func Test_CacheSet(t *testing.T) { lggr := logger.TestLogger(t) cs := newCacheSet(lggr, Config{}) ctx := testutils.Context(t) - require.NoError(t, cs.Start(ctx)) - t.Cleanup(func() { - assert.NoError(t, cs.Close()) - }) + servicetest.Run(t, cs) t.Run("Get", func(t *testing.T) { c := &mockClient{} diff --git a/core/services/relay/evm/mercury/wsrpc/client_test.go b/core/services/relay/evm/mercury/wsrpc/client_test.go index 9b0100a3cd..f265d54879 100644 --- a/core/services/relay/evm/mercury/wsrpc/client_test.go +++ b/core/services/relay/evm/mercury/wsrpc/client_test.go @@ -8,11 +8,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" - mocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) @@ -162,7 +163,7 @@ func Test_Client_LatestReport(t *testing.T) { // simulate start without dialling require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) var err error - require.NoError(t, cacheSet.Start(ctx)) + servicetest.Run(t, cacheSet) c.cache, err = cacheSet.Get(ctx, c) require.NoError(t, err) @@ -200,7 +201,7 @@ func Test_Client_LatestReport(t *testing.T) { // simulate start without dialling require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) var err error - require.NoError(t, cacheSet.Start(ctx)) + servicetest.Run(t, cacheSet) c.cache, err = cacheSet.Get(ctx, c) require.NoError(t, err) diff --git a/core/services/srvctest/servicetest.go b/core/services/srvctest/servicetest.go deleted file mode 100644 index ee888a46fa..0000000000 --- a/core/services/srvctest/servicetest.go +++ /dev/null @@ -1,18 +0,0 @@ -package srvctest - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services" -) - -// Start is test helper to automatically Start/Close a ServiceCtx along with a test. -func Start[S services.ServiceCtx](tb testing.TB, s S) S { - require.NoError(tb, s.Start(testutils.Context(tb))) - tb.Cleanup(func() { assert.NoError(tb, s.Close()) }) - return s -} diff --git a/core/services/synchronization/telemetry_ingress_batch_client_test.go b/core/services/synchronization/telemetry_ingress_batch_client_test.go index 6dd9d401a8..c4f6417131 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client_test.go +++ b/core/services/synchronization/telemetry_ingress_batch_client_test.go @@ -9,8 +9,8 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -37,7 +37,7 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { serverPubKeyHex := "33333333333" sendInterval := time.Millisecond * 5 telemIngressClient := synchronization.NewTestTelemetryIngressBatchClient(t, url, serverPubKeyHex, csaKeystore, false, telemClient, sendInterval, false) - require.NoError(t, telemIngressClient.Start(testutils.Context(t))) + servicetest.Run(t, telemIngressClient) // Create telemetry payloads for different contracts telemPayload1 := synchronization.TelemPayload{ @@ -100,7 +100,4 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { g.Eventually(func() []uint32 { return []uint32{contractCounter1.Load(), contractCounter2.Load(), contractCounter3.Load()} }).Should(gomega.Equal([]uint32{3, 2, 1})) - - // Client should shut down - telemIngressClient.Close() } diff --git a/core/services/synchronization/telemetry_ingress_client_test.go b/core/services/synchronization/telemetry_ingress_client_test.go index 5a0cc23ecd..55be107b97 100644 --- a/core/services/synchronization/telemetry_ingress_client_test.go +++ b/core/services/synchronization/telemetry_ingress_client_test.go @@ -9,8 +9,8 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -35,8 +35,7 @@ func TestTelemetryIngressClient_Send_HappyPath(t *testing.T) { url := &url.URL{} serverPubKeyHex := "33333333333" telemIngressClient := synchronization.NewTestTelemetryIngressClient(t, url, serverPubKeyHex, csaKeystore, false, telemClient) - require.NoError(t, telemIngressClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, telemIngressClient.Close()) }() + servicetest.Run(t, telemIngressClient) // Create the telemetry payload telemetry := []byte("101010") diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 3c29702600..d957e3c721 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -6,7 +6,15 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -32,7 +40,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" vrf_mocks "github.com/smartcontractkit/chainlink/v2/core/services/vrf/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/solidity_cross_tests" @@ -40,13 +47,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" ) type vrfUniverse struct { @@ -149,7 +149,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { cfg := configtest.NewTestGeneralConfig(t) vuni := buildVrfUni(t, db, cfg) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) vd := vrf.NewDelegate( db, @@ -176,8 +176,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { go func() { listener.RunHeadListener(func() {}) }() - t.Cleanup(func() { listener.Stop(t) }) - require.NoError(t, listener.Start(testutils.Context(t))) + servicetest.Run(t, listener) return vuni, listener, jb } @@ -674,7 +673,7 @@ func Test_VRFV2PlusServiceFailsWhenVRFOwnerProvided(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) vuni := buildVrfUni(t, db, cfg) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) vd := vrf.NewDelegate( db, diff --git a/core/services/vrf/v1/listener_v1_test_helpers.go b/core/services/vrf/v1/listener_v1_test_helpers.go index e9adde35b5..f9532bf83e 100644 --- a/core/services/vrf/v1/listener_v1_test_helpers.go +++ b/core/services/vrf/v1/listener_v1_test_helpers.go @@ -3,6 +3,8 @@ package v1 import ( "testing" "time" + + "github.com/stretchr/testify/assert" ) func (lsn *Listener) SetReqAdded(fn func()) { @@ -10,7 +12,7 @@ func (lsn *Listener) SetReqAdded(fn func()) { } func (lsn *Listener) Stop(t *testing.T) { - lsn.ChStop <- struct{}{} + assert.NoError(t, lsn.Close()) select { case <-lsn.WaitOnStop: case <-time.After(time.Second): diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 1ce4fd08a3..3beee88c2e 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -380,6 +380,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { func TestJobsController_Create_WebhookSpec(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, app.Stop()) }) _, fetchBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, submitBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) From f99fd8e8abac4becae9bd125114b404314af2a15 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 8 Dec 2023 08:31:34 -0600 Subject: [PATCH 291/327] bump go to 1.21.5 and misc deps (#11525) --- .tool-versions | 2 +- core/chains/evm/txmgr/confirmer_test.go | 18 +++--- core/scripts/go.mod | 31 ++++----- core/scripts/go.sum | 83 ++++++++++++++----------- go.mod | 33 +++++----- go.sum | 83 ++++++++++++++----------- integration-tests/.tool-versions | 2 +- integration-tests/go.mod | 25 ++++---- integration-tests/go.sum | 79 ++++++++++++----------- 9 files changed, 191 insertions(+), 165 deletions(-) diff --git a/.tool-versions b/.tool-versions index d78ce677cd..d8f0afd901 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ -golang 1.21.4 +golang 1.21.5 mockery 2.38.0 nodejs 16.16.0 postgres 13.3 diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 9d909d5834..3acbfe9800 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -3006,12 +3006,14 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `DELETE FROM pipeline_runs`) t.Run("processes eth_txes with receipt older than minConfirmations that reverted", func(t *testing.T) { - ch := make(chan interface{}) + type data struct { + value any + error + } + ch := make(chan data) nonce := evmtypes.Nonce(4) - var err error - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { - err = thisErr - ch <- value + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, err error) error { + ch <- data{value, err} return nil }) @@ -3038,11 +3040,11 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { select { case data := <-ch: - assert.Error(t, err) + assert.Error(t, data.error) - assert.EqualError(t, err, fmt.Sprintf("transaction %s reverted on-chain", etx.TxAttempts[0].Hash.String())) + assert.EqualError(t, data.error, fmt.Sprintf("transaction %s reverted on-chain", etx.TxAttempts[0].Hash.String())) - assert.Nil(t, data) + assert.Nil(t, data.value) case <-testutils.AfterWaitTimeout(t): t.Fatal("no value received") diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 07d41c9d7e..afaa65b38b 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -49,7 +49,7 @@ require ( github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect github.com/DataDog/zstd v1.5.2 // indirect - github.com/Depado/ginprom v1.7.11 // indirect + github.com/Depado/ginprom v1.8.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/VictoriaMetrics/fastcache v1.10.0 // indirect @@ -64,12 +64,13 @@ require ( github.com/btcsuite/btcd v0.23.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/bytedance/sonic v1.9.1 // indirect + github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 // indirect @@ -112,32 +113,32 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/getsentry/sentry-go v0.19.0 // indirect - github.com/gin-contrib/cors v1.4.0 // indirect + github.com/gin-contrib/cors v1.5.0 // indirect github.com/gin-contrib/expvar v0.0.1 // indirect github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-ldap/ldap/v3 v3.4.5 // indirect + github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/webauthn v0.9.1 // indirect - github.com/go-webauthn/x v0.1.4 // indirect + github.com/go-webauthn/webauthn v0.9.4 // indirect + github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect @@ -193,7 +194,7 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -255,7 +256,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.10 // indirect + github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad // indirect @@ -270,7 +271,7 @@ require ( github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.3 // indirect - github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/status-im/keycard-go v0.2.0 // indirect @@ -288,7 +289,7 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/ulule/limiter/v3 v3.11.2 // indirect github.com/unrolled/secure v1.13.0 // indirect github.com/valyala/fastjson v1.4.1 // indirect @@ -330,7 +331,7 @@ require ( gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/guregu/null.v4 v4.0.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 48b168459b..2b0504ce5f 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -81,7 +81,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= @@ -99,8 +98,8 @@ github.com/CosmWasm/wasmvm v1.2.4/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Depado/ginprom v1.7.11 h1:qOhxW/NJZkNkkG4TQrzAZklX8SUTjTfLA73zIUNIpww= -github.com/Depado/ginprom v1.7.11/go.mod h1:49mxL3NTQwDrhpDbY4V1mAIB3us9B+b2hP1+ph+Sla8= +github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= +github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= @@ -193,8 +192,9 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -209,8 +209,11 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= @@ -386,8 +389,8 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlK github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -415,8 +418,8 @@ github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TB github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM= github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= -github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= @@ -430,8 +433,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -452,8 +455,8 @@ github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEai github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -477,8 +480,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -486,10 +489,10 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= -github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= -github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= -github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= +github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= +github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= +github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= +github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -511,8 +514,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= -github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -611,6 +614,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= @@ -867,8 +871,9 @@ github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -1196,8 +1201,8 @@ github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08O github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1252,8 +1257,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= @@ -1332,8 +1337,8 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= @@ -1492,7 +1497,7 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1592,7 +1597,7 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1698,7 +1703,6 @@ golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1708,7 +1712,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1716,7 +1720,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1729,7 +1734,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1964,8 +1970,8 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -2023,6 +2029,7 @@ modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/go.mod b/go.mod index f659881d1a..40359ab16f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/smartcontractkit/chainlink/v2 go 1.21.3 require ( - github.com/Depado/ginprom v1.7.11 + github.com/Depado/ginprom v1.8.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 github.com/avast/retry-go/v4 v4.5.1 @@ -17,12 +17,13 @@ require ( github.com/fxamacker/cbor/v2 v2.5.0 github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 github.com/getsentry/sentry-go v0.19.0 - github.com/gin-contrib/cors v1.4.0 + github.com/gin-contrib/cors v1.5.0 github.com/gin-contrib/expvar v0.0.1 github.com/gin-contrib/sessions v0.0.5 github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 github.com/gin-gonic/gin v1.9.1 - github.com/go-webauthn/webauthn v0.9.1 + github.com/go-ldap/ldap/v3 v3.4.6 + github.com/go-webauthn/webauthn v0.9.4 github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 github.com/google/uuid v1.4.0 github.com/gorilla/securecookie v1.1.2 @@ -37,6 +38,7 @@ require ( github.com/jackc/pgconn v1.14.1 github.com/jackc/pgtype v1.14.0 github.com/jackc/pgx/v4 v4.18.1 + github.com/jmoiron/sqlx v1.3.5 github.com/jpillora/backoff v1.0.0 github.com/kylelemons/godebug v1.1.0 github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a @@ -62,7 +64,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 - github.com/shirou/gopsutil/v3 v3.23.10 + github.com/shirou/gopsutil/v3 v3.23.11 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-automation v1.0.1 @@ -77,11 +79,11 @@ require ( github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 - github.com/spf13/cast v1.5.1 + github.com/spf13/cast v1.6.0 github.com/stretchr/testify v1.8.4 github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a github.com/tidwall/gjson v1.17.0 - github.com/ugorji/go/codec v1.2.11 + github.com/ugorji/go/codec v1.2.12 github.com/ulule/limiter/v3 v3.11.2 github.com/umbracle/ethgo v0.1.3 github.com/unrolled/secure v1.13.0 @@ -102,7 +104,7 @@ require ( google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 gopkg.in/guregu/null.v4 v4.0.0 - gopkg.in/natefinch/lumberjack.v2 v2.0.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( @@ -131,12 +133,13 @@ require ( github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/bytedance/sonic v1.9.1 // indirect + github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 // indirect @@ -170,26 +173,25 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-ldap/ldap/v3 v3.4.5 github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/x v0.1.4 // indirect + github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -231,10 +233,9 @@ require ( github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/jmoiron/sqlx v1.3.5 github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect diff --git a/go.sum b/go.sum index d700ec724b..11b377b11f 100644 --- a/go.sum +++ b/go.sum @@ -81,7 +81,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= @@ -99,8 +98,8 @@ github.com/CosmWasm/wasmvm v1.2.4/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Depado/ginprom v1.7.11 h1:qOhxW/NJZkNkkG4TQrzAZklX8SUTjTfLA73zIUNIpww= -github.com/Depado/ginprom v1.7.11/go.mod h1:49mxL3NTQwDrhpDbY4V1mAIB3us9B+b2hP1+ph+Sla8= +github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= +github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= @@ -192,8 +191,9 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -208,8 +208,11 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= @@ -383,8 +386,8 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlK github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -412,8 +415,8 @@ github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TB github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM= github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= -github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= @@ -427,8 +430,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -449,8 +452,8 @@ github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEai github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -474,8 +477,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -485,10 +488,10 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= -github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= -github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= -github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= +github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= +github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= +github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= +github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -510,8 +513,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= -github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -610,6 +613,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= @@ -868,8 +872,9 @@ github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -1199,8 +1204,8 @@ github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08O github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1256,8 +1261,8 @@ github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= @@ -1336,8 +1341,8 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= @@ -1497,7 +1502,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1598,7 +1603,7 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1703,7 +1708,6 @@ golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1714,7 +1718,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1723,7 +1727,8 @@ golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1738,7 +1743,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1972,8 +1978,8 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -2029,6 +2035,7 @@ modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/integration-tests/.tool-versions b/integration-tests/.tool-versions index 47b73e9de1..ac6300f979 100644 --- a/integration-tests/.tool-versions +++ b/integration-tests/.tool-versions @@ -1,4 +1,4 @@ -golang 1.21.4 +golang 1.21.5 k3d 5.4.6 kubectl 1.25.5 nodejs 18.13.0 diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 2f32347bb4..5b44209f9a 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -95,7 +95,7 @@ require ( github.com/btcsuite/btcd v0.23.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/bytedance/sonic v1.9.1 // indirect + github.com/bytedance/sonic v1.10.1 // indirect github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 // indirect @@ -105,7 +105,8 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cli/safeexec v1.0.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect @@ -165,12 +166,12 @@ require ( github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-ldap/ldap/v3 v3.4.5 // indirect + github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -186,17 +187,17 @@ require ( github.com/go-openapi/validate v0.22.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/webauthn v0.9.1 // indirect - github.com/go-webauthn/x v0.1.4 // indirect + github.com/go-webauthn/webauthn v0.9.4 // indirect + github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect github.com/gogo/status v1.1.1 // indirect - github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -356,7 +357,7 @@ require ( github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sercand/kuberesolver/v5 v5.1.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.10 // indirect + github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -372,7 +373,7 @@ require ( github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.5 // indirect - github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.15.0 // indirect @@ -394,7 +395,7 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -446,7 +447,7 @@ require ( gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 08d02446d1..0e29f6f671 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -99,8 +99,6 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzS github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= @@ -113,8 +111,8 @@ github.com/CosmWasm/wasmvm v1.2.4/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Depado/ginprom v1.7.11 h1:qOhxW/NJZkNkkG4TQrzAZklX8SUTjTfLA73zIUNIpww= -github.com/Depado/ginprom v1.7.11/go.mod h1:49mxL3NTQwDrhpDbY4V1mAIB3us9B+b2hP1+ph+Sla8= +github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= +github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= @@ -229,8 +227,9 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2 github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= @@ -255,8 +254,11 @@ github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHe github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 h1:CyuI+igIjadM/GRnE2o0q+WCwipDh0n2cUYFPAvxziM= github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657/go.mod h1:JRiumF+RFsH1mrrP8FUsi9tExPylKkO/oSRWeQEUdLE= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -471,8 +473,8 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+ github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -502,8 +504,8 @@ github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TB github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM= github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= -github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= @@ -517,8 +519,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -534,8 +536,8 @@ github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= @@ -599,8 +601,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= @@ -613,10 +615,10 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= -github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= -github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= -github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= +github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= +github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= +github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= +github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= @@ -672,8 +674,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= -github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -778,6 +780,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= @@ -1084,6 +1087,7 @@ github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1492,8 +1496,8 @@ github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08O github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -1560,8 +1564,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= @@ -1647,8 +1651,8 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= @@ -1833,7 +1837,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1942,7 +1946,7 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2074,7 +2078,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2083,7 +2087,8 @@ golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2098,7 +2103,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2345,8 +2351,8 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -2402,6 +2408,7 @@ k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 06656fac80999d1539e16951a54b87c6df13a9c7 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 8 Dec 2023 08:43:33 -0600 Subject: [PATCH 292/327] core/scripts/common: rm ava-labs/coreth; lint (#11451) --- .github/workflows/ci-chaincli.yml | 4 - .../command/keeper/verifiable_load.go | 2 +- core/scripts/chaincli/handler/debug.go | 17 -- core/scripts/chaincli/handler/keeper.go | 12 +- .../scripts/chaincli/handler/keeper_launch.go | 2 +- .../handler/keeper_verifiable_load.go | 10 +- .../handler/mercury_lookup_handler.go | 2 + core/scripts/chaincli/handler/report.go | 15 +- .../chaincli/handler/scrape_node_config.go | 2 +- core/scripts/common/avalanche.go | 265 ++++++++++++++++++ core/scripts/common/helpers.go | 20 +- core/scripts/go.mod | 7 +- core/scripts/go.sum | 18 +- 13 files changed, 292 insertions(+), 84 deletions(-) create mode 100644 core/scripts/common/avalanche.go diff --git a/.github/workflows/ci-chaincli.yml b/.github/workflows/ci-chaincli.yml index fd58d08005..8a9ab03d76 100644 --- a/.github/workflows/ci-chaincli.yml +++ b/.github/workflows/ci-chaincli.yml @@ -2,11 +2,7 @@ name: chaincli CI on: push: - paths: - - "core/scripts/chaincli/**" pull_request: - paths: - - "core/scripts/chaincli/**" jobs: golangci: diff --git a/core/scripts/chaincli/command/keeper/verifiable_load.go b/core/scripts/chaincli/command/keeper/verifiable_load.go index 33acf9bf3b..ce0acddfbd 100644 --- a/core/scripts/chaincli/command/keeper/verifiable_load.go +++ b/core/scripts/chaincli/command/keeper/verifiable_load.go @@ -21,7 +21,7 @@ var verifiableLoad = &cobra.Command{ if err != nil { log.Fatal("failed to get verify flag: ", err) } - hdlr.GetVerifiableLoadStats(cmd.Context(), csv) + hdlr.PrintVerifiableLoadStats(cmd.Context(), csv) }, } diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index fec8c6cd41..5947337b18 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -18,7 +18,6 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" @@ -317,22 +316,6 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } } -type blockSubscriber struct { - ethClient *ethclient.Client -} - -func (bs *blockSubscriber) LatestBlock() *ocr2keepers.BlockKey { - header, err := bs.ethClient.HeaderByNumber(context.Background(), nil) - if err != nil { - return nil - } - - return &ocr2keepers.BlockKey{ - Number: ocr2keepers.BlockNumber(header.Number.Uint64()), - Hash: header.Hash(), - } -} - func logMatchesTriggerConfig(log *types.Log, config automation_utils_2_1.LogTriggerConfig) bool { if log.Topics[0] != config.Topic0 { return false diff --git a/core/scripts/chaincli/handler/keeper.go b/core/scripts/chaincli/handler/keeper.go index 439532430a..ad8bd93649 100644 --- a/core/scripts/chaincli/handler/keeper.go +++ b/core/scripts/chaincli/handler/keeper.go @@ -435,9 +435,8 @@ func (k *Keeper) getRegistry20(ctx context.Context) (common.Address, *registry20 } if k.cfg.RegistryConfigUpdate { panic("KeeperRegistry2.0 could not be updated") - } else { - log.Println("KeeperRegistry2.0 config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry2.0 config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry20 } @@ -453,9 +452,8 @@ func (k *Keeper) getRegistry21(ctx context.Context) (common.Address, *iregistry2 } if k.cfg.RegistryConfigUpdate { panic("KeeperRegistry2.1 could not be updated") - } else { - log.Println("KeeperRegistry2.1 config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry2.1 config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry21 } @@ -479,9 +477,8 @@ func (k *Keeper) getRegistry12(ctx context.Context) (common.Address, *registry12 log.Fatalf("KeeperRegistry config update failed on registry address: %s, error is: %s", k.cfg.RegistryAddress, err.Error()) } log.Println("KeeperRegistry config update:", k.cfg.RegistryAddress, "-", helpers.ExplorerLink(k.cfg.ChainID, transaction.Hash())) - } else { - log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry12 } @@ -513,9 +510,8 @@ func (k *Keeper) getRegistry11(ctx context.Context) (common.Address, *registry11 log.Fatalf("KeeperRegistry config update failed on registry address: %s, error is %s", k.cfg.RegistryAddress, err.Error()) } log.Println("KeeperRegistry config update:", k.cfg.RegistryAddress, "-", helpers.ExplorerLink(k.cfg.ChainID, transaction.Hash())) - } else { - log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry11 } diff --git a/core/scripts/chaincli/handler/keeper_launch.go b/core/scripts/chaincli/handler/keeper_launch.go index 83ee6a7712..22b6776394 100644 --- a/core/scripts/chaincli/handler/keeper_launch.go +++ b/core/scripts/chaincli/handler/keeper_launch.go @@ -371,7 +371,7 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd } // Correctly assign contract version in OCR job spec. - var contractVersion string = "v2.0" + contractVersion := "v2.0" if k.cfg.RegistryVersion == keeper.RegistryVersion_2_1 { contractVersion = "v2.1" } diff --git a/core/scripts/chaincli/handler/keeper_verifiable_load.go b/core/scripts/chaincli/handler/keeper_verifiable_load.go index b71a9af338..aa62d82010 100644 --- a/core/scripts/chaincli/handler/keeper_verifiable_load.go +++ b/core/scripts/chaincli/handler/keeper_verifiable_load.go @@ -58,7 +58,7 @@ type upkeepStats struct { SortedAllDelays []float64 } -func (k *Keeper) GetVerifiableLoadStats(ctx context.Context, csv bool) { +func (k *Keeper) PrintVerifiableLoadStats(ctx context.Context, csv bool) { var v verifiableLoad var err error addr := common.HexToAddress(k.cfg.VerifiableLoadContractAddress) @@ -99,7 +99,7 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context, csv bool) { // create a number of workers to process the upkeep ids in batch for i := 0; i < workerNum; i++ { wg.Add(1) - go k.getUpkeepInfo(idChan, resultsChan, v, opts, &wg, csv) + go k.fetchUpkeepInfo(idChan, resultsChan, v, opts, &wg, csv) } for _, id := range upkeepIds { @@ -134,7 +134,7 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context, csv bool) { log.Printf("All STATS ABOVE ARE CALCULATED AT BLOCK %d", blockNum) } -func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInfo, v verifiableLoad, opts *bind.CallOpts, wg *sync.WaitGroup, csv bool) { +func (k *Keeper) fetchUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInfo, v verifiableLoad, opts *bind.CallOpts, wg *sync.WaitGroup, csv bool) { defer wg.Done() for id := range idChan { @@ -161,7 +161,7 @@ func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInf var wg1 sync.WaitGroup for i := uint16(0); i <= b; i++ { wg1.Add(1) - go k.getBucketData(v, opts, id, i, &wg1, info) + go k.fetchBucketData(v, opts, id, i, &wg1, info) } wg1.Wait() @@ -196,7 +196,7 @@ func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInf } } -func (k *Keeper) getBucketData(v verifiableLoad, opts *bind.CallOpts, id *big.Int, bucketNum uint16, wg *sync.WaitGroup, info *upkeepInfo) { +func (k *Keeper) fetchBucketData(v verifiableLoad, opts *bind.CallOpts, id *big.Int, bucketNum uint16, wg *sync.WaitGroup, info *upkeepInfo) { defer wg.Done() var bucketDelays []*big.Int diff --git a/core/scripts/chaincli/handler/mercury_lookup_handler.go b/core/scripts/chaincli/handler/mercury_lookup_handler.go index 1bd4b2e183..1165d83921 100644 --- a/core/scripts/chaincli/handler/mercury_lookup_handler.go +++ b/core/scripts/chaincli/handler/mercury_lookup_handler.go @@ -218,6 +218,7 @@ func (mlh *MercuryLookupHandler) singleFeedRequest(ctx context.Context, ch chan< defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { + _ = "" // placate linter // mlh.logger.Errorf("Encountered error when closing the body of the response in single feed: %s", err) } }(resp.Body) @@ -326,6 +327,7 @@ func (mlh *MercuryLookupHandler) multiFeedsRequest(ctx context.Context, ch chan< defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { + _ = "" // placate linter // mlh.logger.Errorf("Encountered error when closing the body of the response in the multi feed: %s", err) } }(resp.Body) diff --git a/core/scripts/chaincli/handler/report.go b/core/scripts/chaincli/handler/report.go index 622963f1ac..10970b5f03 100644 --- a/core/scripts/chaincli/handler/report.go +++ b/core/scripts/chaincli/handler/report.go @@ -235,15 +235,12 @@ func (t *OCR2Transaction) BlockNumber() (uint64, error) { block, err := hexutil.DecodeUint64(blStr) if err != nil { return 0, fmt.Errorf("failed to parse block number: %s", err) - } else { - return block, nil } - } else { - return 0, fmt.Errorf("not a string") + return block, nil } - } else { - return 0, fmt.Errorf("not found") + return 0, fmt.Errorf("not a string") } + return 0, fmt.Errorf("not found") } func (t *OCR2Transaction) To() *common.Address { @@ -335,17 +332,15 @@ func (t *OCR2TransmitTx) SetStaticValues(elem *OCR2ReportDataElem) { if err != nil { elem.Err = err.Error() return - } else { - elem.From = from.String() } + elem.From = from.String() block, err := t.BlockNumber() if err != nil { elem.Err = err.Error() return - } else { - elem.BlockNumber = fmt.Sprintf("%d", block) } + elem.BlockNumber = fmt.Sprintf("%d", block) upkeeps, err := t.UpkeepsInTransmit() if err != nil { diff --git a/core/scripts/chaincli/handler/scrape_node_config.go b/core/scripts/chaincli/handler/scrape_node_config.go index f00beb4b4f..aaaf5d2647 100644 --- a/core/scripts/chaincli/handler/scrape_node_config.go +++ b/core/scripts/chaincli/handler/scrape_node_config.go @@ -279,5 +279,5 @@ func writeJSON(data interface{}, path string) error { return err } - return os.WriteFile(path, dataBytes, 0644) + return os.WriteFile(path, dataBytes, 0644) //nolint:gosec } diff --git a/core/scripts/common/avalanche.go b/core/scripts/common/avalanche.go new file mode 100644 index 0000000000..c9c5377990 --- /dev/null +++ b/core/scripts/common/avalanche.go @@ -0,0 +1,265 @@ +package common + +import ( + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" +) + +const ( + // BloomByteLength represents the number of bytes used in a header log bloom. + BloomByteLength = 256 + + // BloomBitLength represents the number of bits used in a header log bloom. + BloomBitLength = 8 * BloomByteLength +) + +// AvaBloom represents a 2048 bit bloom filter. +type AvaBloom [BloomByteLength]byte + +// SetBytes sets the content of b to the given bytes. +// It panics if d is not of suitable size. +func (b *AvaBloom) SetBytes(d []byte) { + if len(b) < len(d) { + panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d))) + } + copy(b[BloomByteLength-len(d):], d) +} + +// Add adds d to the filter. Future calls of Test(d) will return true. +func (b *AvaBloom) Add(d []byte) { + b.add(d, make([]byte, 6)) +} + +// add is internal version of Add, which takes a scratch buffer for reuse (needs to be at least 6 bytes) +func (b *AvaBloom) add(d []byte, buf []byte) { + i1, v1, i2, v2, i3, v3 := bloomValues(d, buf) + b[i1] |= v1 + b[i2] |= v2 + b[i3] |= v3 +} + +// Big converts b to a big integer. +// Note: Converting a bloom filter to a big.Int and then calling GetBytes +// does not return the same bytes, since big.Int will trim leading zeroes +func (b AvaBloom) Big() *big.Int { + return new(big.Int).SetBytes(b[:]) +} + +// Bytes returns the backing byte slice of the bloom +func (b AvaBloom) Bytes() []byte { + return b[:] +} + +// Test checks if the given topic is present in the bloom filter +func (b AvaBloom) Test(topic []byte) bool { + i1, v1, i2, v2, i3, v3 := bloomValues(topic, make([]byte, 6)) + return v1 == v1&b[i1] && + v2 == v2&b[i2] && + v3 == v3&b[i3] +} + +// MarshalText encodes b as a hex string with 0x prefix. +func (b AvaBloom) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +// UnmarshalText b as a hex string with 0x prefix. +func (b *AvaBloom) UnmarshalText(input []byte) error { + return hexutil.UnmarshalFixedText("Bloom", input, b[:]) +} + +// bloomValues returns the bytes (index-value pairs) to set for the given data +func bloomValues(data []byte, hashbuf []byte) (uint, byte, uint, byte, uint, byte) { + sha := crypto.NewKeccakState() + sha.Write(data) + sha.Read(hashbuf) + // The actual bits to flip + v1 := byte(1 << (hashbuf[1] & 0x7)) + v2 := byte(1 << (hashbuf[3] & 0x7)) + v3 := byte(1 << (hashbuf[5] & 0x7)) + // The indices for the bytes to OR in + i1 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf)&0x7ff)>>3) - 1 + i2 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[2:])&0x7ff)>>3) - 1 + i3 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[4:])&0x7ff)>>3) - 1 + + return i1, v1, i2, v2, i3, v3 +} + +// A AvaBlockNonce is a 64-bit hash which proves (combined with the +// mix-hash) that a sufficient amount of computation has been carried +// out on a block. +type AvaBlockNonce [8]byte + +// EncodeNonce converts the given integer to a block nonce. +func EncodeNonce(i uint64) AvaBlockNonce { + var n AvaBlockNonce + binary.BigEndian.PutUint64(n[:], i) + return n +} + +// Uint64 returns the integer value of a block nonce. +func (n AvaBlockNonce) Uint64() uint64 { + return binary.BigEndian.Uint64(n[:]) +} + +// MarshalText encodes n as a hex string with 0x prefix. +func (n AvaBlockNonce) MarshalText() ([]byte, error) { + return hexutil.Bytes(n[:]).MarshalText() +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (n *AvaBlockNonce) UnmarshalText(input []byte) error { + return hexutil.UnmarshalFixedText("AvaBlockNonce", input, n[:]) +} + +// AvaHeader is a copy of [github.com/ava-labs/coreth/core/types.Header] to avoid importing the whole module. +type AvaHeader struct { + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner" gencodec:"required"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom AvaBloom `json:"logsBloom" gencodec:"required"` + Difficulty *big.Int `json:"difficulty" gencodec:"required"` + Number *big.Int `json:"number" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + Time uint64 `json:"timestamp" gencodec:"required"` + Extra []byte `json:"extraData" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce AvaBlockNonce `json:"nonce"` + ExtDataHash common.Hash `json:"extDataHash" gencodec:"required"` + + // BaseFee was added by EIP-1559 and is ignored in legacy headers. + BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` + + // ExtDataGasUsed was added by Apricot Phase 4 and is ignored in legacy + // headers. + // + // It is not a uint64 like GasLimit or GasUsed because it is not possible to + // correctly encode this field optionally with uint64. + ExtDataGasUsed *big.Int `json:"extDataGasUsed" rlp:"optional"` + + // BlockGasCost was added by Apricot Phase 4 and is ignored in legacy + // headers. + BlockGasCost *big.Int `json:"blockGasCost" rlp:"optional"` +} + +func (h *AvaHeader) UnmarshalJSON(input []byte) error { + type Header struct { + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase *common.Address `json:"miner" gencodec:"required"` + Root *common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom *AvaBloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest *common.Hash `json:"mixHash"` + Nonce *AvaBlockNonce `json:"nonce"` + ExtDataHash *common.Hash `json:"extDataHash" gencodec:"required"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + ExtDataGasUsed *hexutil.Big `json:"extDataGasUsed" rlp:"optional"` + BlockGasCost *hexutil.Big `json:"blockGasCost" rlp:"optional"` + } + var dec Header + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.ParentHash == nil { + return errors.New("missing required field 'parentHash' for Header") + } + h.ParentHash = *dec.ParentHash + if dec.UncleHash == nil { + return errors.New("missing required field 'sha3Uncles' for Header") + } + h.UncleHash = *dec.UncleHash + if dec.Coinbase == nil { + return errors.New("missing required field 'miner' for Header") + } + h.Coinbase = *dec.Coinbase + if dec.Root == nil { + return errors.New("missing required field 'stateRoot' for Header") + } + h.Root = *dec.Root + if dec.TxHash == nil { + return errors.New("missing required field 'transactionsRoot' for Header") + } + h.TxHash = *dec.TxHash + if dec.ReceiptHash == nil { + return errors.New("missing required field 'receiptsRoot' for Header") + } + h.ReceiptHash = *dec.ReceiptHash + if dec.Bloom == nil { + return errors.New("missing required field 'logsBloom' for Header") + } + h.Bloom = *dec.Bloom + if dec.Difficulty == nil { + return errors.New("missing required field 'difficulty' for Header") + } + h.Difficulty = (*big.Int)(dec.Difficulty) + if dec.Number == nil { + return errors.New("missing required field 'number' for Header") + } + h.Number = (*big.Int)(dec.Number) + if dec.GasLimit == nil { + return errors.New("missing required field 'gasLimit' for Header") + } + h.GasLimit = uint64(*dec.GasLimit) + if dec.GasUsed == nil { + return errors.New("missing required field 'gasUsed' for Header") + } + h.GasUsed = uint64(*dec.GasUsed) + if dec.Time == nil { + return errors.New("missing required field 'timestamp' for Header") + } + h.Time = uint64(*dec.Time) + if dec.Extra == nil { + return errors.New("missing required field 'extraData' for Header") + } + h.Extra = *dec.Extra + if dec.MixDigest != nil { + h.MixDigest = *dec.MixDigest + } + if dec.Nonce != nil { + h.Nonce = *dec.Nonce + } + if dec.ExtDataHash == nil { + return errors.New("missing required field 'extDataHash' for Header") + } + h.ExtDataHash = *dec.ExtDataHash + if dec.BaseFee != nil { + h.BaseFee = (*big.Int)(dec.BaseFee) + } + if dec.ExtDataGasUsed != nil { + h.ExtDataGasUsed = (*big.Int)(dec.ExtDataGasUsed) + } + if dec.BlockGasCost != nil { + h.BlockGasCost = (*big.Int)(dec.BlockGasCost) + } + return nil +} +func (h *AvaHeader) Hash() common.Hash { + return rlpHash(h) +} +func rlpHash(x interface{}) (h common.Hash) { + sha := crypto.NewKeccakState() + sha.Reset() + rlp.Encode(sha, x) + sha.Read(h[:]) + return h +} diff --git a/core/scripts/common/helpers.go b/core/scripts/common/helpers.go index c141e8a29c..b5a3b1ed94 100644 --- a/core/scripts/common/helpers.go +++ b/core/scripts/common/helpers.go @@ -12,7 +12,6 @@ import ( "strings" "time" - avaxclient "github.com/ava-labs/coreth/ethclient" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -34,11 +33,6 @@ type Environment struct { Jc *rpc.Client - // AvaxEc is appropriately set if the environment is configured to interact with an avalanche - // chain. It should be used instead of the regular Ec field because avalanche calculates - // blockhashes differently and the regular Ec will give consistently incorrect results on basic - // queries (like e.g eth_blockByNumber). - AvaxEc avaxclient.Client ChainID int64 } @@ -84,12 +78,6 @@ func SetupEnv(overrideNonce bool) Environment { chainID, err := strconv.ParseInt(chainIDEnv, 10, 64) PanicErr(err) - var avaxClient avaxclient.Client - if IsAvaxNetwork(chainID) { - avaxClient, err = avaxclient.Dial(ethURL) - PanicErr(err) - } - // Owner key. Make sure it has eth b, err := hex.DecodeString(accountKey) PanicErr(err) @@ -136,7 +124,6 @@ func SetupEnv(overrideNonce bool) Environment { Owner: owner, Ec: ec, Jc: jsonRPCClient, - AvaxEc: avaxClient, ChainID: chainID, } } @@ -485,11 +472,10 @@ func GetRlpHeaders(env Environment, blockNumbers []*big.Int, getParentBlocks boo // Avalanche block headers are special, handle them by using the avalanche rpc client // rather than the regular go-ethereum ethclient. if IsAvaxNetwork(env.ChainID) { + var h AvaHeader // Get child block since it's the one that has the parent hash in its header. - h, err := env.AvaxEc.HeaderByNumber( - context.Background(), - new(big.Int).Set(blockNum).Add(blockNum, offset), - ) + nextBlockNum := new(big.Int).Set(blockNum).Add(blockNum, offset) + err := env.Jc.CallContext(context.Background(), &h, "eth_getBlockByNumber", hexutil.EncodeBig(nextBlockNum), false) if err != nil { return nil, hashes, fmt.Errorf("failed to get header: %+v", err) } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index afaa65b38b..b7dd835cb6 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -6,7 +6,6 @@ go 1.21.3 replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( - github.com/ava-labs/coreth v0.12.1 github.com/avast/retry-go v3.0.0+incompatible github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 @@ -55,7 +54,6 @@ require ( github.com/VictoriaMetrics/fastcache v1.10.0 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/ava-labs/avalanchego v1.10.1 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -63,6 +61,7 @@ require ( github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd v0.23.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -91,7 +90,6 @@ require ( github.com/danieljoos/wincred v1.1.2 // indirect github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect @@ -141,7 +139,6 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect @@ -172,7 +169,6 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect - github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect @@ -248,7 +244,6 @@ require ( github.com/prometheus/prometheus v0.48.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rjeczalik/notify v0.9.3 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 2b0504ce5f..a8cf979a0e 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -145,10 +145,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/ava-labs/avalanchego v1.10.1 h1:lBeamJ1iNq+p2oKg2nAs+A65m8vhSDjkiTDbwzQW7kY= -github.com/ava-labs/avalanchego v1.10.1/go.mod h1:ZvSXWlbkUKlbk3BsWx29a+8eVHe/WBsOxh55BSGoeRk= -github.com/ava-labs/coreth v0.12.1 h1:EWSkFGHGVUxmu1pnSK/2pdcxaAVHbGspHqO3Ag+i7sA= -github.com/ava-labs/coreth v0.12.1/go.mod h1:/5x54QlIKjlPebkdzTA5ic9wXdejbWOnQosztkv9jxo= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= @@ -175,10 +171,12 @@ github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHf github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= @@ -309,12 +307,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= -github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= @@ -718,8 +716,6 @@ github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce h1:7UnVY3T/ZnHUrfv github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= -github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= -github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= @@ -1161,8 +1157,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= -github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1631,7 +1625,6 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1807,7 +1800,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -1977,8 +1969,6 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHN gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 1b357f631ad7d576ce60caf27814e163e4db43af Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Fri, 8 Dec 2023 12:02:01 -0500 Subject: [PATCH 293/327] (test): Remove unnecessary fuzzing from Functions OnTokenTransfer tests (#11517) * (test): Remove unnecessary fuzzing from Functions OnTokenTransfer tests * Update gas snapshot --- .../gas-snapshots/functions.gas-snapshot | 12 ++--- .../tests/v1_X/FunctionsSubscriptions.t.sol | 51 ++++++------------- 2 files changed, 22 insertions(+), 41 deletions(-) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 8275d9afaf..d0893969bf 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -142,11 +142,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, μ: 43774, ~: 45548) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46286, ~: 48060) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14295, ~: 14295) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51443, ~: 53040) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 86057, ~: 89604) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 39939) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 42404) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13441) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 47347) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 81598, ~: 81598) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) @@ -177,7 +177,7 @@ FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscription FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68196) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82749) FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15554) -FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success(uint64) (runs: 256, μ: 41717, ~: 41721) +FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41111) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30260) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 15019) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57800) diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol index 5a54bcc84c..907eadacd8 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol @@ -130,12 +130,8 @@ contract FunctionsSubscriptions_OwnerCancelSubscription is FunctionsSubscription contract FunctionsSubscriptions_RecoverFunds is FunctionsRouterSetup { event FundsRecovered(address to, uint256 amount); - function test_RecoverFunds_Success(uint64 fundsTransferred) public { - //amount must be less than LINK total supply - vm.assume(fundsTransferred < 1_000_000_000 * 1e18); - vm.assume(fundsTransferred > 0); - - // uint256 fundsTransferred = 1 * 1e18; // 1 LINK + function test_RecoverFunds_Success() public { + uint256 fundsTransferred = 1 * 1e18; // 1 LINK s_linkToken.transfer(address(s_functionsRouter), fundsTransferred); // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). @@ -320,58 +316,43 @@ contract FunctionsSubscriptions_OnTokenTransfer is FunctionsClientSetup { s_functionsRouter.addConsumer(s_subscriptionId, address(s_functionsClient)); } - function test_OnTokenTransfer_RevertIfPaused(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfPaused() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - s_functionsRouter.pause(); vm.expectRevert("Pausable: paused"); - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, abi.encode(s_subscriptionId)); } - function test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfCallerIsNotLink() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - vm.expectRevert(FunctionsSubscriptions.OnlyCallableFromLink.selector); - s_functionsRouter.onTokenTransfer(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + s_functionsRouter.onTokenTransfer(address(s_functionsRouter), totalSupplyJuels, abi.encode(s_subscriptionId)); } - function test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfCallerIsNoCalldata() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, new bytes(0)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, new bytes(0)); } - function test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfCallerIsNoSubscription() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); uint64 invalidSubscriptionId = 123456789; - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(invalidSubscriptionId)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, abi.encode(invalidSubscriptionId)); } function test_OnTokenTransfer_Success(uint96 fundingAmount) public { // Funding amount must be less than LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; // Some of the total supply is already in the subscription account - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, abi.encode(s_subscriptionId)); uint96 subscriptionBalanceAfter = s_functionsRouter.getSubscription(s_subscriptionId).balance; - assertEq(fundingAmount, subscriptionBalanceAfter); + assertEq(totalSupplyJuels, subscriptionBalanceAfter); } } From 1a45097cbf51751efe6295718629a0e09c7361ce Mon Sep 17 00:00:00 2001 From: Lei Date: Fri, 8 Dec 2023 10:55:35 -0800 Subject: [PATCH 294/327] small improvements based on comments (#11491) * small improvements based on comments * add unit test --- .../evmregistry/v21/mercury/mercury.go | 6 +--- .../v21/mercury/streams/streams.go | 7 +++-- .../v21/mercury/streams/streams_test.go | 28 ++++++++++++++++++- .../evmregistry/v21/mercury/v03/request.go | 2 +- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go index cf6ebeafc6..f9a3c001c6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go @@ -105,10 +105,6 @@ type StreamsLookup struct { Block uint64 } -func (l *StreamsLookup) IsMercuryVersionUnkown() bool { - return l.FeedParamKey != FeedIDs -} - func (l *StreamsLookup) IsMercuryV02() bool { return l.FeedParamKey == FeedIdHex && l.TimeParamKey == BlockNumber } @@ -117,6 +113,6 @@ func (l *StreamsLookup) IsMercuryV03() bool { return l.FeedParamKey == FeedIDs } -func (l *StreamsLookup) IsMercuryUsingBatchPathV03() bool { +func (l *StreamsLookup) IsMercuryV03UsingBlockNumber() bool { return l.TimeParamKey == BlockNumber } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index aec2343192..70db40c26b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -131,6 +131,7 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper // tried to call mercury lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) streamsLookupErr, err := s.packer.DecodeStreamsLookupRequest(checkResult.PerformData) + if err != nil { lookupLggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) // user contract did not revert with StreamsLookup error @@ -144,7 +145,7 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper return } - // mercury permission checking for v0.3 is done by mercury server + // mercury permission checking for v0.3 is done by mercury server, so no need to check here if streamsLookupResponse.IsMercuryV02() { // check permission on the registry for mercury v0.2 opts := s.buildCallOpts(ctx, block) @@ -159,8 +160,8 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed) return } - } else if streamsLookupResponse.IsMercuryVersionUnkown() { - // if mercury version cannot be determined, set failure reason + } else if !streamsLookupResponse.IsMercuryV03() { + // if mercury version is not v02 or v03, set failure reason lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) return diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index abcc37dca1..32041d0f18 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -11,10 +11,11 @@ import ( "testing" "time" + "github.com/pkg/errors" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -619,6 +620,31 @@ func TestStreams_StreamsLookup(t *testing.T) { }, hasError: true, }, + { + name: "failure - invalid mercury version", + input: []ocr2keepers.CheckResult{ + { + // This Perform data contains invalid FeedParamKey: {feedIdHex:RandomString [ETD-USD BTC-ETH] blockNumber 100 [48 120 48 48]} + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000166665656449644865783a52616e646f6d537472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000074554442d5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074254432d45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043078303000000000000000000000000000000000000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), + }, + }, + expectedResults: []ocr2keepers.CheckResult{ + { + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000166665656449644865783a52616e646f6d537472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000074554442d5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074254432d45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043078303000000000000000000000000000000000000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput), + }, + }, + hasError: true, + }, } for _, tt := range tests { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go index cb3c9ef322..ea465ff858 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go @@ -100,7 +100,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur params := fmt.Sprintf("%s=%s&%s=%s", mercury.FeedIDs, strings.Join(sl.Feeds, ","), mercury.Timestamp, sl.Time.String()) batchPathV03 := mercuryBatchPathV03 - if sl.IsMercuryUsingBatchPathV03() { + if sl.IsMercuryV03UsingBlockNumber() { batchPathV03 = mercuryBatchPathV03BlockNumber } reqUrl := fmt.Sprintf("%s%s%s", c.mercuryConfig.Credentials().URL, batchPathV03, params) From 500a4dba7ef9059fd76e09b84c9acd6022b2c247 Mon Sep 17 00:00:00 2001 From: Sergey Kudasov Date: Tue, 12 Dec 2023 00:15:20 +0300 Subject: [PATCH 295/327] wrap devspace commands (#11530) --- .../dashboard/cmd/dashboard_deploy.go | 2 +- charts/chainlink-cluster/devspace.yaml | 24 ++++++++++++++++++- charts/chainlink-cluster/go.mod | 2 +- .../templates/chainlink-pod-monitor.yaml | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go index 93619fe614..b65be29501 100644 --- a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go +++ b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go @@ -3,7 +3,7 @@ package main import ( "os" - "github.com/smartcontractkit/chainlink/v2/dashboard/dashboard" + "github.com/smartcontractkit/chainlink/charts/chainlink-cluster/dashboard/dashboard" "github.com/smartcontractkit/wasp" ) diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index f62b87edf6..186e49257a 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -2,6 +2,7 @@ version: v2beta1 name: chainlink vars: + NS_TTL: 72h DEVSPACE_IMAGE: source: env @@ -20,7 +21,16 @@ pipelines: run_dependencies --all # 1. Deploy any projects this project needs (see "dependencies") ensure_pull_secrets --all # 2. Ensure pull secrets build_images --all -t $(git rev-parse --short HEAD) # 3. Build, tag (git commit hash) and push all images (see "images") - create_deployments --all # 4. Deploy Helm charts and manifests specfied as "deployments" + create_deployments --all # 5. Deploy Helm charts and manifests specfied as "deployments" + kubectl annotate namespace ${DEVSPACE_NAMESPACE} janitor/ttl=${NS_TTL} + echo "Namespace ${DEVSPACE_NAMESPACE} will be deleted in ${NS_TTL}" + purge: + run: |- + kubectl delete ns ${DEVSPACE_NAMESPACE} + +commands: + connect: |- + sudo kubefwd svc -n ${DEVSPACE_NAMESPACE} images: app: @@ -28,9 +38,21 @@ images: dockerfile: ../../core/chainlink.devspace.Dockerfile context: ../.. +hooks: + - wait: + running: true + terminatedWithCode: 0 + container: + labelSelector: + # vars don't work here, = releaseName + release: "app" + events: ["after:deploy:app"] + name: "wait-for-pod-hook" + # This is a list of `deployments` that DevSpace can create for this project deployments: app: + namespace: ${DEVSPACE_NAMESPACE} helm: releaseName: "app" chart: diff --git a/charts/chainlink-cluster/go.mod b/charts/chainlink-cluster/go.mod index 951fb1d2e3..34ee35887b 100644 --- a/charts/chainlink-cluster/go.mod +++ b/charts/chainlink-cluster/go.mod @@ -1,4 +1,4 @@ -module github.com/smartcontractkit/chainlink/v2/dashboard +module github.com/smartcontractkit/chainlink/charts/chainlink-cluster/dashboard go 1.21 diff --git a/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml b/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml index 2cd9c3df2b..05852642a2 100644 --- a/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml +++ b/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml @@ -8,7 +8,7 @@ metadata: spec: namespaceSelector: matchNames: - - "cl-cluster" + - {{ $.Release.Namespace }} podMetricsEndpoints: - port: access selector: From 120bef7aa5259967348e9d8ee46f8aea82d8cc01 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 11 Dec 2023 16:45:19 -0600 Subject: [PATCH 296/327] go.mods: rm libp2p; rm btcd replace (#11502) * go.mods: drop btcd replace; upgrade libp2p * Replace deprecated call to btcd API for secp256k1 constant * Fix comment describing sqrtPower calculation * Change calculation of sqrtPower to standard order of operations * rm libp2p peer & crypto uses --------- Co-authored-by: Alex Coventry --- charts/chainlink-cluster/go.mod | 4 - core/internal/cltest/cltest.go | 4 +- core/internal/cltest/factories.go | 6 +- core/scripts/go.mod | 25 +-- core/scripts/go.sum | 110 ++--------- .../keystore/keys/cosmoskey/export.go | 4 +- core/services/keystore/keys/csakey/export.go | 4 +- .../keystore/keys/dkgencryptkey/export.go | 4 +- .../keystore/keys/dkgsignkey/export.go | 4 +- core/services/keystore/keys/exportutils.go | 9 +- core/services/keystore/keys/ocr2key/export.go | 4 +- core/services/keystore/keys/ocrkey/export.go | 4 +- core/services/keystore/keys/p2pkey/export.go | 14 +- core/services/keystore/keys/p2pkey/key.go | 24 +-- .../services/keystore/keys/p2pkey/key_test.go | 21 +- core/services/keystore/keys/p2pkey/key_v2.go | 46 +++-- .../keystore/keys/p2pkey/key_v2_test.go | 18 +- core/services/keystore/keys/p2pkey/peer_id.go | 23 ++- .../keystore/keys/p2pkey/peer_id_test.go | 8 +- core/services/keystore/keys/solkey/export.go | 4 +- .../services/keystore/keys/starkkey/export.go | 4 +- core/services/keystore/models_test.go | 4 +- core/services/keystore/p2p.go | 2 +- core/services/keystore/p2p_test.go | 32 ++- .../services/ocrcommon/discoverer_database.go | 8 +- .../ocrcommon/discoverer_database_test.go | 19 +- core/services/ocrcommon/peer_wrapper.go | 33 +--- core/services/ocrcommon/peer_wrapper_test.go | 6 +- core/services/ocrcommon/peerstore.go | 182 ------------------ core/services/ocrcommon/peerstore_test.go | 101 ---------- core/services/signatures/secp256k1/curve.go | 2 +- core/services/signatures/secp256k1/field.go | 8 +- core/services/signatures/secp256k1/scalar.go | 2 +- core/utils/utils.go | 12 +- core/web/jobs_controller_test.go | 6 +- core/web/p2p_keys_controller.go | 6 +- core/web/presenters/p2p_key_test.go | 8 +- core/web/resolver/mutation.go | 3 +- go.mod | 27 +-- go.sum | 105 +--------- integration-tests/go.mod | 25 +-- integration-tests/go.sum | 105 +--------- 42 files changed, 204 insertions(+), 836 deletions(-) delete mode 100644 core/services/ocrcommon/peerstore.go delete mode 100644 core/services/ocrcommon/peerstore_test.go diff --git a/charts/chainlink-cluster/go.mod b/charts/chainlink-cluster/go.mod index 34ee35887b..ae67574aa0 100644 --- a/charts/chainlink-cluster/go.mod +++ b/charts/chainlink-cluster/go.mod @@ -170,10 +170,6 @@ require ( ) replace ( - // Fixes go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - github.com/go-kit/log => github.com/go-kit/log v0.2.1 // replicating the replace directive on cosmos SDK diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 8802d9c4b0..88abc3de5c 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -26,7 +26,6 @@ import ( "github.com/google/uuid" "github.com/gorilla/securecookie" "github.com/gorilla/sessions" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/manyminds/api2go/jsonapi" "github.com/onsi/gomega" "github.com/stretchr/testify/assert" @@ -141,11 +140,10 @@ func init() { fmt.Printf("[gin] %-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) } - defaultP2PPeerID, err := p2ppeer.Decode(configtest.DefaultPeerID) + err := DefaultP2PPeerID.UnmarshalString(configtest.DefaultPeerID) if err != nil { panic(err) } - DefaultP2PPeerID = p2pkey.PeerID(defaultP2PPeerID) } func NewRandomPositiveInt64() int64 { diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index c169c5fd22..a76d23d376 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/require" "github.com/urfave/cli" "gopkg.in/guregu/null.v4" @@ -55,8 +55,8 @@ func NewEIP55Address() ethkey.EIP55Address { return e } -func NewPeerID() p2ppeer.ID { - id, err := p2ppeer.Decode("12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw") +func NewPeerID() (id ragep2ptypes.PeerID) { + err := id.UnmarshalText([]byte("12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw")) if err != nil { panic(err) } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index b7dd835cb6..2f4d45e746 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -59,7 +59,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect - github.com/btcsuite/btcd v0.23.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect @@ -145,7 +144,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect + github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/sessions v1.2.2 // indirect @@ -174,9 +173,6 @@ require ( github.com/huandu/skiplist v1.2.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-cid v0.0.7 // indirect - github.com/ipfs/go-log v1.0.4 // indirect - github.com/ipfs/go-log/v2 v2.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.1 // indirect github.com/jackc/pgio v1.0.0 // indirect @@ -198,9 +194,6 @@ require ( github.com/leodido/go-urn v1.2.4 // indirect github.com/lib/pq v1.10.9 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-libp2p-core v0.8.5 // indirect - github.com/libp2p/go-libp2p-peerstore v0.2.7 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -208,8 +201,6 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v0.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -218,14 +209,6 @@ require ( github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr v0.3.3 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multiaddr-net v0.2.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -263,8 +246,6 @@ require ( github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -335,10 +316,6 @@ require ( ) replace ( - // Fix go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - // replicating the replace directive on cosmos SDK github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index a8cf979a0e..a59590fa12 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -169,20 +169,26 @@ github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsy github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= @@ -303,6 +309,7 @@ github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuA github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e h1:5jVSh2l/ho6ajWhSPNN84eHEdq3dp0T7+f6r3Tc6hsk= github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e/go.mod h1:IJgIiGUARc4aOr4bOQ85klmjsShkEEfiRc6q/yBSfo8= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -322,10 +329,8 @@ github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= @@ -552,7 +557,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= @@ -602,14 +606,13 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -703,7 +706,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -739,22 +741,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= -github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= -github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -816,9 +802,7 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -875,7 +859,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -900,22 +883,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= @@ -965,13 +934,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1003,39 +967,10 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= @@ -1057,6 +992,7 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= @@ -1075,7 +1011,6 @@ github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/ github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -1242,8 +1177,6 @@ github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgq github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1292,7 +1225,7 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= @@ -1357,8 +1290,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1438,7 +1369,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -1455,7 +1385,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -1463,6 +1392,7 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1471,14 +1401,11 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1545,7 +1472,6 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1573,6 +1499,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1664,8 +1591,10 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1760,7 +1689,6 @@ golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/core/services/keystore/keys/cosmoskey/export.go b/core/services/keystore/keys/cosmoskey/export.go index a327b60e80..05061ddb01 100644 --- a/core/services/keystore/keys/cosmoskey/export.go +++ b/core/services/keystore/keys/cosmoskey/export.go @@ -33,12 +33,12 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: hex.EncodeToString(key.PublicKey().Bytes()), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/csakey/export.go b/core/services/keystore/keys/csakey/export.go index a1ad499e0e..bd0e0229ed 100644 --- a/core/services/keystore/keys/csakey/export.go +++ b/core/services/keystore/keys/csakey/export.go @@ -29,12 +29,12 @@ func (k KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.PublicKeyString(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/dkgencryptkey/export.go b/core/services/keystore/keys/dkgencryptkey/export.go index c689c29f66..3bccf1a07b 100644 --- a/core/services/keystore/keys/dkgencryptkey/export.go +++ b/core/services/keystore/keys/dkgencryptkey/export.go @@ -30,12 +30,12 @@ func (k Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) ( password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.PublicKeyString(), Crypto: cryptoJSON, - }, nil + } }) } diff --git a/core/services/keystore/keys/dkgsignkey/export.go b/core/services/keystore/keys/dkgsignkey/export.go index 7ecada8ddc..3c421760d6 100644 --- a/core/services/keystore/keys/dkgsignkey/export.go +++ b/core/services/keystore/keys/dkgsignkey/export.go @@ -31,12 +31,12 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.PublicKeyString(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/exportutils.go b/core/services/keystore/keys/exportutils.go index 0c3e782a9a..5d75b5076e 100644 --- a/core/services/keystore/keys/exportutils.go +++ b/core/services/keystore/keys/exportutils.go @@ -3,7 +3,7 @@ package keys import ( "encoding/json" - keystore "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -62,7 +62,7 @@ func ToEncryptedJSON[E Encrypted, K any]( password string, scryptParams utils.ScryptParams, passwordFunc func(string) string, - buildExport func(id string, key K, cryptoJSON keystore.CryptoJSON) (E, error), + buildExport func(id string, key K, cryptoJSON keystore.CryptoJSON) E, ) (export []byte, err error) { // encrypt data using prefixed password @@ -77,10 +77,7 @@ func ToEncryptedJSON[E Encrypted, K any]( } // build [E] export struct using encrypted key, identifier, and original key [K] - encryptedKeyExport, err := buildExport(identifier, key, cryptoJSON) - if err != nil { - return nil, errors.Wrapf(err, "could not build encrypted export for %s key", identifier) - } + encryptedKeyExport := buildExport(identifier, key, cryptoJSON) return json.Marshal(encryptedKeyExport) } diff --git a/core/services/keystore/keys/ocr2key/export.go b/core/services/keystore/keys/ocr2key/export.go index 54e73ecf98..5487e31046 100644 --- a/core/services/keystore/keys/ocr2key/export.go +++ b/core/services/keystore/keys/ocr2key/export.go @@ -66,7 +66,7 @@ func ToEncryptedJSON(key KeyBundle, password string, scryptParams utils.ScryptPa password, scryptParams, adulteratedPassword, - func(id string, key KeyBundle, cryptoJSON keystore.CryptoJSON) (EncryptedOCRKeyExport, error) { + func(id string, key KeyBundle, cryptoJSON keystore.CryptoJSON) EncryptedOCRKeyExport { pubKeyConfig := key.ConfigEncryptionPublicKey() pubKey := key.OffchainPublicKey() return EncryptedOCRKeyExport{ @@ -77,7 +77,7 @@ func ToEncryptedJSON(key KeyBundle, password string, scryptParams utils.ScryptPa OffChainPublicKey: hex.EncodeToString(pubKey[:]), ConfigPublicKey: hex.EncodeToString(pubKeyConfig[:]), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/ocrkey/export.go b/core/services/keystore/keys/ocrkey/export.go index 9f63a3c2d9..363f38b20a 100644 --- a/core/services/keystore/keys/ocrkey/export.go +++ b/core/services/keystore/keys/ocrkey/export.go @@ -42,7 +42,7 @@ func (key KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParam password, scryptParams, adulteratedPassword, - func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) (EncryptedOCRKeyExport, error) { + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) EncryptedOCRKeyExport { return EncryptedOCRKeyExport{ KeyType: id, ID: key.ID(), @@ -50,7 +50,7 @@ func (key KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParam OffChainPublicKey: key.OffChainSigning.PublicKey(), ConfigPublicKey: key.PublicKeyConfig(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/p2pkey/export.go b/core/services/keystore/keys/p2pkey/export.go index b81cf1d02d..0db73167c4 100644 --- a/core/services/keystore/keys/p2pkey/export.go +++ b/core/services/keystore/keys/p2pkey/export.go @@ -1,9 +1,7 @@ package p2pkey import ( - keystore "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -42,17 +40,13 @@ func (key KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParam password, scryptParams, adulteratedPassword, - func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) (EncryptedP2PKeyExport, error) { - rawPubKey, err := key.GetPublic().Bytes() - if err != nil { - return EncryptedP2PKeyExport{}, errors.Wrapf(err, "could not get raw public key") - } + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) EncryptedP2PKeyExport { return EncryptedP2PKeyExport{ KeyType: id, - PublicKey: hexutil.Encode(rawPubKey), + PublicKey: key.PublicKeyHex(), PeerID: key.PeerID(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/p2pkey/key.go b/core/services/keystore/keys/p2pkey/key.go index 6a96103dac..abf4f70294 100644 --- a/core/services/keystore/keys/p2pkey/key.go +++ b/core/services/keystore/keys/p2pkey/key.go @@ -1,6 +1,7 @@ package p2pkey import ( + "crypto/ed25519" "database/sql/driver" "encoding/hex" "encoding/json" @@ -8,14 +9,14 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/keystore" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" + + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" ) -// Key represents a libp2p private key +// Key represents a p2p private key type Key struct { - cryptop2p.PrivKey + PrivKey ed25519.PrivateKey } func (k Key) ToV2() KeyV2 { @@ -25,7 +26,7 @@ func (k Key) ToV2() KeyV2 { } } -// PublicKeyBytes is generated using cryptop2p.PubKey.Raw() +// PublicKeyBytes is a [ed25519.PublicKey] type PublicKeyBytes []byte func (pkb PublicKeyBytes) String() string { @@ -47,7 +48,7 @@ func (pkb *PublicKeyBytes) UnmarshalJSON(input []byte) error { return err } - *pkb = PublicKeyBytes(result) + *pkb = result return nil } @@ -66,19 +67,19 @@ func (pkb PublicKeyBytes) Value() (driver.Value, error) { } func (k Key) GetPeerID() (PeerID, error) { - peerID, err := peer.IDFromPrivateKey(k) + peerID, err := ragep2ptypes.PeerIDFromPrivateKey(k.PrivKey) if err != nil { - return "", errors.WithStack(err) + return PeerID{}, errors.WithStack(err) } return PeerID(peerID), err } func (k Key) PeerID() PeerID { - peerID, err := peer.IDFromPrivateKey(k) + peerID, err := k.GetPeerID() if err != nil { panic(err) } - return PeerID(peerID) + return peerID } type EncryptedP2PKey struct { @@ -113,7 +114,8 @@ func (ep2pk EncryptedP2PKey) Decrypt(auth string) (k Key, err error) { if err != nil { return k, errors.Wrapf(err, "could not decrypt P2P key %s (0x%x)", ep2pk.PeerID.String(), ep2pk.PubKey) } - privK, err := cryptop2p.UnmarshalPrivateKey(marshalledPrivK) + + privK, err := UnmarshalPrivateKey(marshalledPrivK) if err != nil { return k, errors.Wrapf(err, "could not unmarshal P2P private key for %s (0x%x)", ep2pk.PeerID.String(), ep2pk.PubKey) } diff --git a/core/services/keystore/keys/p2pkey/key_test.go b/core/services/keystore/keys/p2pkey/key_test.go index fc111f1421..57490483e8 100644 --- a/core/services/keystore/keys/p2pkey/key_test.go +++ b/core/services/keystore/keys/p2pkey/key_test.go @@ -1,13 +1,13 @@ package p2pkey import ( + "crypto/ed25519" "crypto/rand" "encoding/hex" "encoding/json" "testing" "github.com/ethereum/go-ethereum/accounts/keystore" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -15,7 +15,7 @@ import ( ) func TestP2PKeys_KeyStruct(t *testing.T) { - pk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, pk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) k := Key{PrivKey: pk} @@ -37,12 +37,10 @@ func TestP2PKeys_KeyStruct(t *testing.T) { } func TestP2PKeys_PublicKeyBytes(t *testing.T) { - _, pk, err := cryptop2p.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - r, err := pk.Raw() + pk, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - pkb := PublicKeyBytes(r) + pkb := PublicKeyBytes(pk) assert.Equal(t, hex.EncodeToString(pkb), pkb.String()) b, err := pkb.MarshalJSON() @@ -55,7 +53,7 @@ func TestP2PKeys_PublicKeyBytes(t *testing.T) { err = pkb.UnmarshalJSON([]byte("")) assert.Error(t, err) - err = pkb.Scan(r) + err = pkb.Scan([]byte(pk)) assert.NoError(t, err) err = pkb.Scan("invalid-type") @@ -67,16 +65,15 @@ func TestP2PKeys_PublicKeyBytes(t *testing.T) { } func TestP2PKeys_EncryptedP2PKey(t *testing.T) { - privk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, privk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) k := Key{PrivKey: privk} - pubkr, err := k.GetPublic().Raw() - require.NoError(t, err) + pubkr := k.PrivKey.Public().(ed25519.PublicKey) var marshalledPrivK []byte - marshalledPrivK, err = cryptop2p.MarshalPrivateKey(k) + marshalledPrivK, err = MarshalPrivateKey(k.PrivKey) require.NoError(t, err) cryptoJSON, err := keystore.EncryptDataV3(marshalledPrivK, []byte(adulteratedPassword("password")), utils.FastScryptParams.N, utils.FastScryptParams.P) require.NoError(t, err) @@ -86,7 +83,7 @@ func TestP2PKeys_EncryptedP2PKey(t *testing.T) { p2pk := EncryptedP2PKey{ ID: 1, PeerID: k.PeerID(), - PubKey: pubkr, + PubKey: []byte(pubkr), EncryptedPrivKey: encryptedPrivKey, } diff --git a/core/services/keystore/keys/p2pkey/key_v2.go b/core/services/keystore/keys/p2pkey/key_v2.go index d92302cf5f..6af71d5e2d 100644 --- a/core/services/keystore/keys/p2pkey/key_v2.go +++ b/core/services/keystore/keys/p2pkey/key_v2.go @@ -1,20 +1,24 @@ package p2pkey import ( + "bytes" "crypto/ed25519" "crypto/rand" "encoding/hex" + "errors" "fmt" "math/big" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/smartcontractkit/libocr/ragep2p/types" ) +var libp2pPBPrefix = []byte{0x08, 0x01, 0x12, 0x40} + +// Raw is an encoded protocol buffer. type Raw []byte func (raw Raw) Key() KeyV2 { - privKey, err := cryptop2p.UnmarshalPrivateKey(raw) + privKey, err := UnmarshalPrivateKey(raw) if err != nil { panic(err) } @@ -25,6 +29,17 @@ func (raw Raw) Key() KeyV2 { return key } +func UnmarshalPrivateKey(raw Raw) (ed25519.PrivateKey, error) { + if !bytes.HasPrefix(raw, libp2pPBPrefix) { + return nil, errors.New("invalid key: missing libp2p protobuf prefix") + } + return ed25519.PrivateKey(raw[len(libp2pPBPrefix):]), nil +} + +func MarshalPrivateKey(key ed25519.PrivateKey) ([]byte, error) { + return bytes.Join([][]byte{libp2pPBPrefix, key}, nil), nil +} + func (raw Raw) String() string { return "" } @@ -36,12 +51,12 @@ func (raw Raw) GoString() string { var _ fmt.GoStringer = &KeyV2{} type KeyV2 struct { - cryptop2p.PrivKey - peerID PeerID + PrivKey ed25519.PrivateKey + peerID PeerID } func NewV2() (KeyV2, error) { - privKey, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, privKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { return KeyV2{}, err } @@ -52,11 +67,7 @@ func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { seed := make([]byte, ed25519.SeedSize) copy(seed, k.Bytes()) pk := ed25519.NewKeyFromSeed(seed[:]) - p2pPrivKey, err := cryptop2p.UnmarshalEd25519PrivateKey(pk[:]) - if err != nil { - panic(err) - } - key, err := fromPrivkey(p2pPrivKey) + key, err := fromPrivkey(pk) if err != nil { panic(err) } @@ -64,11 +75,11 @@ func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { } func (key KeyV2) ID() string { - return peer.ID(key.peerID).String() + return types.PeerID(key.peerID).String() } func (key KeyV2) Raw() Raw { - marshalledPrivK, err := cryptop2p.MarshalPrivateKey(key.PrivKey) + marshalledPrivK, err := MarshalPrivateKey(key.PrivKey) if err != nil { panic(err) } @@ -80,10 +91,7 @@ func (key KeyV2) PeerID() PeerID { } func (key KeyV2) PublicKeyHex() string { - pubKeyBytes, err := key.GetPublic().Raw() - if err != nil { - panic(err) - } + pubKeyBytes := key.PrivKey.Public().(ed25519.PublicKey) return hex.EncodeToString(pubKeyBytes) } @@ -95,8 +103,8 @@ func (key KeyV2) GoString() string { return key.String() } -func fromPrivkey(privKey cryptop2p.PrivKey) (KeyV2, error) { - peerID, err := peer.IDFromPrivateKey(privKey) +func fromPrivkey(privKey ed25519.PrivateKey) (KeyV2, error) { + peerID, err := types.PeerIDFromPrivateKey(privKey) if err != nil { return KeyV2{}, err } diff --git a/core/services/keystore/keys/p2pkey/key_v2_test.go b/core/services/keystore/keys/p2pkey/key_v2_test.go index 53c3c30238..d93678b8f2 100644 --- a/core/services/keystore/keys/p2pkey/key_v2_test.go +++ b/core/services/keystore/keys/p2pkey/key_v2_test.go @@ -1,38 +1,36 @@ package p2pkey import ( + "crypto/ed25519" "crypto/rand" "encoding/hex" "testing" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestP2PKeys_Raw(t *testing.T) { - pk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - pkr, err := pk.Raw() + _, pk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - r := Raw(pkr) + r := Raw(pk) assert.Equal(t, r.String(), r.GoString()) assert.Equal(t, "", r.String()) } func TestP2PKeys_KeyV2(t *testing.T) { - pk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, pk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) k := Key{PrivKey: pk} kv2 := k.ToV2() - pkv2, err := kv2.GetPublic().Raw() - require.NoError(t, err) + + pkv2 := kv2.PrivKey.Public().(ed25519.PublicKey) assert.Equal(t, kv2.String(), kv2.GoString()) - assert.Equal(t, peer.ID(k.PeerID()).String(), kv2.ID()) + assert.Equal(t, ragep2ptypes.PeerID(k.PeerID()).String(), kv2.ID()) assert.Equal(t, hex.EncodeToString(pkv2), kv2.PublicKeyHex()) } diff --git a/core/services/keystore/keys/p2pkey/peer_id.go b/core/services/keystore/keys/p2pkey/peer_id.go index 2147fa9774..38fbc471b5 100644 --- a/core/services/keystore/keys/p2pkey/peer_id.go +++ b/core/services/keystore/keys/p2pkey/peer_id.go @@ -6,13 +6,14 @@ import ( "fmt" "strings" - "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" + + "github.com/smartcontractkit/libocr/ragep2p/types" ) const peerIDPrefix = "p2p_" -type PeerID peer.ID +type PeerID types.PeerID func MakePeerID(s string) (PeerID, error) { var peerID PeerID @@ -22,15 +23,14 @@ func MakePeerID(s string) (PeerID, error) { func (p PeerID) String() string { // Handle a zero peerID more gracefully, i.e. print it as empty string rather // than `p2p_` - raw := p.Raw() - if raw == "" { + if p == (PeerID{}) { return "" } - return fmt.Sprintf("%s%s", peerIDPrefix, raw) + return fmt.Sprintf("%s%s", peerIDPrefix, p.Raw()) } func (p PeerID) Raw() string { - return peer.ID(p).String() + return types.PeerID(p).String() } func (p *PeerID) UnmarshalString(s string) error { @@ -38,6 +38,9 @@ func (p *PeerID) UnmarshalString(s string) error { } func (p *PeerID) MarshalText() ([]byte, error) { + if *p == (PeerID{}) { + return nil, nil + } return []byte(p.Raw()), nil } @@ -51,7 +54,8 @@ func (p *PeerID) UnmarshalText(bs []byte) error { return nil } - peerID, err := peer.Decode(input) + var peerID types.PeerID + err := peerID.UnmarshalText([]byte(input)) if err != nil { return errors.Wrapf(err, `PeerID#UnmarshalText("%v")`, input) } @@ -60,7 +64,7 @@ func (p *PeerID) UnmarshalText(bs []byte) error { } func (p *PeerID) Scan(value interface{}) error { - *p = PeerID("") + *p = PeerID{} switch s := value.(type) { case string: if s != "" { @@ -74,7 +78,8 @@ func (p *PeerID) Scan(value interface{}) error { } func (p PeerID) Value() (driver.Value, error) { - return peer.Encode(peer.ID(p)), nil + b, err := types.PeerID(p).MarshalText() + return string(b), err } func (p PeerID) MarshalJSON() ([]byte, error) { diff --git a/core/services/keystore/keys/p2pkey/peer_id_test.go b/core/services/keystore/keys/p2pkey/peer_id_test.go index 197c54624f..c648fec8de 100644 --- a/core/services/keystore/keys/p2pkey/peer_id_test.go +++ b/core/services/keystore/keys/p2pkey/peer_id_test.go @@ -10,16 +10,16 @@ import ( func TestP2PKeys_PeerID(t *testing.T) { t.Run("make peer ID", func(t *testing.T) { - id, err := MakePeerID("11") + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") require.NoError(t, err) _, err = MakePeerID("invalid") assert.Error(t, err) - assert.Equal(t, "p2p_11", id.String()) + assert.Equal(t, "p2p_12D3KooWM1111111111111111111111111111111111111111111", id.String()) }) t.Run("unmarshals new ID", func(t *testing.T) { - id, err := MakePeerID("11") + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") require.NoError(t, err) fakeKey := MustNewV2XXXTestingOnly(big.NewInt(1)) @@ -30,7 +30,7 @@ func TestP2PKeys_PeerID(t *testing.T) { }) t.Run("scans new ID", func(t *testing.T) { - id, err := MakePeerID("11") + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") require.NoError(t, err) fakeKey := MustNewV2XXXTestingOnly(big.NewInt(1)) diff --git a/core/services/keystore/keys/solkey/export.go b/core/services/keystore/keys/solkey/export.go index 27f19fb5ed..59e84136bc 100644 --- a/core/services/keystore/keys/solkey/export.go +++ b/core/services/keystore/keys/solkey/export.go @@ -33,12 +33,12 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: hex.EncodeToString(key.pubKey), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/starkkey/export.go b/core/services/keystore/keys/starkkey/export.go index 366243a8da..26770028ca 100644 --- a/core/services/keystore/keys/starkkey/export.go +++ b/core/services/keystore/keys/starkkey/export.go @@ -31,12 +31,12 @@ func ToEncryptedJSON(key Key, password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.StarkKeyStr(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/models_test.go b/core/services/keystore/models_test.go index f124f16d9b..93c0f5fcb2 100644 --- a/core/services/keystore/models_test.go +++ b/core/services/keystore/models_test.go @@ -98,9 +98,9 @@ func TestKeyRing_Encrypt_Decrypt(t *testing.T) { } // compare p2p keys require.Equal(t, 2, len(decryptedKeyRing.P2P)) - require.Equal(t, originalKeyRing.P2P[p2p1.ID()].GetPublic(), decryptedKeyRing.P2P[p2p1.ID()].GetPublic()) + require.Equal(t, originalKeyRing.P2P[p2p1.ID()].PublicKeyHex(), decryptedKeyRing.P2P[p2p1.ID()].PublicKeyHex()) require.Equal(t, originalKeyRing.P2P[p2p1.ID()].PeerID(), decryptedKeyRing.P2P[p2p1.ID()].PeerID()) - require.Equal(t, originalKeyRing.P2P[p2p2.ID()].GetPublic(), decryptedKeyRing.P2P[p2p2.ID()].GetPublic()) + require.Equal(t, originalKeyRing.P2P[p2p2.ID()].PublicKeyHex(), decryptedKeyRing.P2P[p2p2.ID()].PublicKeyHex()) require.Equal(t, originalKeyRing.P2P[p2p2.ID()].PeerID(), decryptedKeyRing.P2P[p2p2.ID()].PeerID()) // compare solana keys require.Equal(t, 2, len(decryptedKeyRing.Solana)) diff --git a/core/services/keystore/p2p.go b/core/services/keystore/p2p.go index 657dfbc897..ee2c64c021 100644 --- a/core/services/keystore/p2p.go +++ b/core/services/keystore/p2p.go @@ -160,7 +160,7 @@ func (ks *p2p) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { if ks.isLocked() { return p2pkey.KeyV2{}, ErrLocked } - if id != "" { + if id != (p2pkey.PeerID{}) { return ks.getByID(id) } else if len(ks.keyRing.P2P) == 1 { ks.logger.Warn("No P2P.PeerID set, defaulting to first key in database") diff --git a/core/services/keystore/p2p_test.go b/core/services/keystore/p2p_test.go index 89cab3e162..829df9812f 100644 --- a/core/services/keystore/p2p_test.go +++ b/core/services/keystore/p2p_test.go @@ -1,8 +1,10 @@ package keystore_test import ( + "crypto/rand" "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -13,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -39,7 +40,10 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("errors when getting non-existent ID", func(t *testing.T) { defer reset() - _, err := ks.Get("non-existent-id") + var nonExistent p2pkey.PeerID + _, err := rand.Read(nonExistent[:]) + require.NoError(t, err) + _, err = ks.Get(nonExistent) require.Error(t, err) }) @@ -58,7 +62,10 @@ func Test_P2PKeyStore_E2E(t *testing.T) { require.NoError(t, err) exportJSON, err := ks.Export(key.PeerID(), cltest.Password) require.NoError(t, err) - _, err = ks.Export("non-existent", cltest.Password) + var nonExistent p2pkey.PeerID + _, err = rand.Read(nonExistent[:]) + require.NoError(t, err) + _, err = ks.Export(nonExistent, cltest.Password) assert.Error(t, err) _, err = ks.Delete(key.PeerID()) require.NoError(t, err) @@ -117,14 +124,14 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("GetOrFirst", func(t *testing.T) { defer reset() - _, err := ks.GetOrFirst("") + _, err := ks.GetOrFirst(p2pkey.PeerID{}) require.Contains(t, err.Error(), "no p2p keys exist") - id := p2pkey.PeerID("a0") + id := p2pkey.PeerID{0xa0} _, err = ks.GetOrFirst(id) require.Contains(t, err.Error(), fmt.Sprintf("unable to find P2P key with id %s", id)) k1, err := ks.Create() require.NoError(t, err) - k2, err := ks.GetOrFirst("") + k2, err := ks.GetOrFirst(p2pkey.PeerID{}) require.NoError(t, err) require.Equal(t, k1, k2) k3, err := ks.GetOrFirst(k1.PeerID()) @@ -132,7 +139,7 @@ func Test_P2PKeyStore_E2E(t *testing.T) { require.Equal(t, k1, k3) _, err = ks.Create() require.NoError(t, err) - _, err = ks.GetOrFirst("") + _, err = ks.GetOrFirst(p2pkey.PeerID{}) require.Contains(t, err.Error(), "multiple p2p keys found") //Check for possible keys in error message require.Contains(t, err.Error(), k1.ID()) @@ -147,12 +154,19 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("clears p2p_peers on delete", func(t *testing.T) { key, err := ks.Create() require.NoError(t, err) - p2pPeer1 := ocrcommon.P2PPeer{ + type P2PPeer struct { + ID string + Addr string + PeerID string + CreatedAt time.Time + UpdatedAt time.Time + } + p2pPeer1 := P2PPeer{ ID: cltest.NewPeerID().String(), Addr: testutils.NewAddress().Hex(), PeerID: cltest.DefaultPeerID, // different p2p key } - p2pPeer2 := ocrcommon.P2PPeer{ + p2pPeer2 := P2PPeer{ ID: cltest.NewPeerID().String(), Addr: testutils.NewAddress().Hex(), PeerID: key.PeerID().Raw(), diff --git a/core/services/ocrcommon/discoverer_database.go b/core/services/ocrcommon/discoverer_database.go index 0a85566557..6468a910a6 100644 --- a/core/services/ocrcommon/discoverer_database.go +++ b/core/services/ocrcommon/discoverer_database.go @@ -5,10 +5,10 @@ import ( "database/sql" "github.com/lib/pq" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" - ocrnetworking "github.com/smartcontractkit/libocr/networking/types" "go.uber.org/multierr" + + ocrnetworking "github.com/smartcontractkit/libocr/networking/types" ) var _ ocrnetworking.DiscovererDatabase = &DiscovererDatabase{} @@ -18,10 +18,10 @@ type DiscovererDatabase struct { peerID string } -func NewDiscovererDatabase(db *sql.DB, peerID p2ppeer.ID) *DiscovererDatabase { +func NewDiscovererDatabase(db *sql.DB, peerID string) *DiscovererDatabase { return &DiscovererDatabase{ db, - peerID.Pretty(), + peerID, } } diff --git a/core/services/ocrcommon/discoverer_database_test.go b/core/services/ocrcommon/discoverer_database_test.go index ff1a931b01..b7a79e92bc 100644 --- a/core/services/ocrcommon/discoverer_database_test.go +++ b/core/services/ocrcommon/discoverer_database_test.go @@ -1,16 +1,17 @@ package ocrcommon_test import ( + "crypto/ed25519" "crypto/rand" "testing" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" ) @@ -20,8 +21,8 @@ func Test_DiscovererDatabase(t *testing.T) { localPeerID1 := mustRandomP2PPeerID(t) localPeerID2 := mustRandomP2PPeerID(t) - dd1 := ocrcommon.NewDiscovererDatabase(db, localPeerID1) - dd2 := ocrcommon.NewDiscovererDatabase(db, localPeerID2) + dd1 := ocrcommon.NewDiscovererDatabase(db, localPeerID1.Raw()) + dd2 := ocrcommon.NewDiscovererDatabase(db, localPeerID2.Raw()) ctx := testutils.Context(t) @@ -73,7 +74,7 @@ func Test_DiscovererDatabase(t *testing.T) { }) t.Run("persists data across restarts", func(t *testing.T) { - dd3 := ocrcommon.NewDiscovererDatabase(db, localPeerID1) + dd3 := ocrcommon.NewDiscovererDatabase(db, localPeerID1.Raw()) announcements, err := dd3.ReadAnnouncements(ctx, []string{"remote1"}) require.NoError(t, err) @@ -83,10 +84,10 @@ func Test_DiscovererDatabase(t *testing.T) { }) } -func mustRandomP2PPeerID(t *testing.T) p2ppeer.ID { - p2pPrivkey, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) +func mustRandomP2PPeerID(t *testing.T) p2pkey.PeerID { + _, p2pPrivkey, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - id, err := p2ppeer.IDFromPrivateKey(p2pPrivkey) + id, err := ragep2ptypes.PeerIDFromPrivateKey(p2pPrivkey) require.NoError(t, err) - return id + return p2pkey.PeerID(id) } diff --git a/core/services/ocrcommon/peer_wrapper.go b/core/services/ocrcommon/peer_wrapper.go index ff666eefdb..1b8ebfcdb2 100644 --- a/core/services/ocrcommon/peer_wrapper.go +++ b/core/services/ocrcommon/peer_wrapper.go @@ -2,15 +2,10 @@ package ocrcommon import ( "context" - "crypto/ed25519" - "fmt" "io" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" - "github.com/pkg/errors" - "go.uber.org/multierr" - "github.com/jmoiron/sqlx" + "github.com/pkg/errors" ocrnetworking "github.com/smartcontractkit/libocr/networking" ocr1types "github.com/smartcontractkit/libocr/offchainreporting/types" @@ -44,14 +39,13 @@ type ( // SingletonPeerWrapper manages all libocr peers for the application SingletonPeerWrapper struct { services.StateMachine - keyStore keystore.Master - p2pCfg config.P2P - ocrCfg PeerWrapperOCRConfig - dbConfig pg.QConfig - db *sqlx.DB - lggr logger.Logger - PeerID p2pkey.PeerID - pstoreWrapper *Pstorewrapper + keyStore keystore.Master + p2pCfg config.P2P + ocrCfg PeerWrapperOCRConfig + dbConfig pg.QConfig + db *sqlx.DB + lggr logger.Logger + PeerID p2pkey.PeerID // Used at shutdown to stop all of this peer's goroutines peerCloser io.Closer @@ -125,15 +119,11 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { } p.PeerID = key.PeerID() - discovererDB := NewDiscovererDatabase(p.db.DB, p2ppeer.ID(p.PeerID)) + discovererDB := NewDiscovererDatabase(p.db.DB, p.PeerID.Raw()) config := p.p2pCfg - pk, err := key.PrivKey.Raw() - if err != nil { - return ocrnetworking.PeerConfig{}, fmt.Errorf("failed to get raw private key: %w", err) - } peerConfig := ocrnetworking.PeerConfig{ - PrivKey: ed25519.PrivateKey(pk), + PrivKey: key.PrivKey, Logger: commonlogger.NewOCRWrapper(p.lggr, p.ocrCfg.TraceLogging(), func(string) {}), // V2 config @@ -158,9 +148,6 @@ func (p *SingletonPeerWrapper) Close() error { if p.peerCloser != nil { err = p.peerCloser.Close() } - if p.pstoreWrapper != nil { - err = multierr.Combine(err, p.pstoreWrapper.Close()) - } return err }) } diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index dbe2252372..278e0684fd 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/hashicorp/consul/sdk/freeport" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" @@ -26,8 +26,8 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) + var peerID ragep2ptypes.PeerID + require.NoError(t, peerID.UnmarshalText([]byte(configtest.DefaultPeerID))) t.Run("with no p2p keys returns error", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { diff --git a/core/services/ocrcommon/peerstore.go b/core/services/ocrcommon/peerstore.go deleted file mode 100644 index 1d859184ab..0000000000 --- a/core/services/ocrcommon/peerstore.go +++ /dev/null @@ -1,182 +0,0 @@ -package ocrcommon - -import ( - "context" - "fmt" - "strings" - "time" - - p2ppeer "github.com/libp2p/go-libp2p-core/peer" - p2ppeerstore "github.com/libp2p/go-libp2p-core/peerstore" - "github.com/libp2p/go-libp2p-peerstore/pstoremem" - ma "github.com/multiformats/go-multiaddr" - "github.com/pkg/errors" - - "github.com/jmoiron/sqlx" - - "github.com/smartcontractkit/chainlink-common/pkg/services" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/recovery" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -type ( - P2PPeer struct { - ID string - Addr string - PeerID string - CreatedAt time.Time - UpdatedAt time.Time - } - - Pstorewrapper struct { - services.StateMachine - Peerstore p2ppeerstore.Peerstore - peerID string - q pg.Q - writeInterval time.Duration - ctx context.Context - ctxCancel context.CancelFunc - chDone chan struct{} - lggr logger.SugaredLogger - } -) - -// NewPeerstoreWrapper creates a new database-backed peerstore wrapper scoped to the given jobID -// Multiple peerstore wrappers should not be instantiated with the same jobID -func NewPeerstoreWrapper(db *sqlx.DB, writeInterval time.Duration, peerID p2pkey.PeerID, lggr logger.Logger, cfg pg.QConfig) (*Pstorewrapper, error) { - ctx, cancel := context.WithCancel(context.Background()) - namedLogger := lggr.Named("PeerStore") - q := pg.NewQ(db, namedLogger, cfg) - - return &Pstorewrapper{ - services.StateMachine{}, - pstoremem.NewPeerstore(), - peerID.Raw(), - q, - writeInterval, - ctx, - cancel, - make(chan struct{}), - logger.Sugared(namedLogger), - }, nil -} - -func (p *Pstorewrapper) Start() error { - return p.StartOnce("PeerStore", func() error { - err := p.readFromDB() - if err != nil { - return errors.Wrap(err, "could not start peerstore wrapper") - } - go p.dbLoop() - return nil - }) -} - -func (p *Pstorewrapper) dbLoop() { - defer close(p.chDone) - ticker := time.NewTicker(utils.WithJitter(p.writeInterval)) - defer ticker.Stop() - for { - select { - case <-p.ctx.Done(): - return - case <-ticker.C: - recovery.WrapRecover(p.lggr, func() { - if err := p.WriteToDB(); err != nil { - p.lggr.Errorw("Error writing peerstore to DB", "err", err) - } - }) - } - } -} - -func (p *Pstorewrapper) Close() error { - return p.StopOnce("PeerStore", func() error { - p.ctxCancel() - <-p.chDone - return p.Peerstore.Close() - }) -} - -func (p *Pstorewrapper) readFromDB() error { - peers, err := p.getPeers() - if err != nil { - return err - } - for _, peer := range peers { - peerID, err := p2ppeer.Decode(peer.ID) - if err != nil { - return errors.Wrapf(err, "unexpectedly failed to decode peer ID '%s'", peer.ID) - } - peerAddr, err := ma.NewMultiaddr(peer.Addr) - if err != nil { - return errors.Wrapf(err, "unexpectedly failed to decode peer multiaddr '%s'", peer.Addr) - } - p.Peerstore.AddAddr(peerID, peerAddr, p2ppeerstore.PermanentAddrTTL) - } - return nil -} - -func (p *Pstorewrapper) getPeers() (peers []P2PPeer, err error) { - rows, err := p.q.WithOpts(pg.WithParentCtx(p.ctx)).Query(`SELECT id, addr FROM p2p_peers WHERE peer_id = $1`, p.peerID) - if err != nil { - return nil, errors.Wrap(err, "error querying peers") - } - defer p.lggr.ErrorIfFn(rows.Close, "Error closing p2p_peers rows") - - peers = make([]P2PPeer, 0) - - for rows.Next() { - peer := P2PPeer{} - if err = rows.Scan(&peer.ID, &peer.Addr); err != nil { - return nil, errors.Wrap(err, "unexpected error scanning row") - } - peers = append(peers, peer) - } - if err = rows.Err(); err != nil { - return nil, err - } - - return peers, nil -} - -func (p *Pstorewrapper) WriteToDB() error { - q := p.q.WithOpts(pg.WithParentCtx(p.ctx)) - err := q.Transaction(func(tx pg.Queryer) error { - _, err := tx.Exec(`DELETE FROM p2p_peers WHERE peer_id = $1`, p.peerID) - if err != nil { - return errors.Wrap(err, "delete from p2p_peers failed") - } - peers := make([]P2PPeer, 0) - for _, pid := range p.Peerstore.PeersWithAddrs() { - addrs := p.Peerstore.Addrs(pid) - for _, addr := range addrs { - p := P2PPeer{ - ID: pid.String(), - Addr: addr.String(), - PeerID: p.peerID, - } - peers = append(peers, p) - } - } - valueStrings := []string{} - valueArgs := []interface{}{} - for _, p := range peers { - valueStrings = append(valueStrings, "(?, ?, ?, NOW(), NOW())") - valueArgs = append(valueArgs, p.ID) - valueArgs = append(valueArgs, p.Addr) - valueArgs = append(valueArgs, p.PeerID) - } - - /* #nosec G201 */ - stmt := fmt.Sprintf("INSERT INTO p2p_peers (id, addr, peer_id, created_at, updated_at) VALUES %s", strings.Join(valueStrings, ",")) - stmt = sqlx.Rebind(sqlx.DOLLAR, stmt) - _, err = tx.Exec(stmt, valueArgs...) - return errors.Wrap(err, "insert into p2p_peers failed") - }) - return errors.Wrap(err, "could not write peers to DB") -} diff --git a/core/services/ocrcommon/peerstore_test.go b/core/services/ocrcommon/peerstore_test.go deleted file mode 100644 index 6e69215356..0000000000 --- a/core/services/ocrcommon/peerstore_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package ocrcommon_test - -import ( - "testing" - "time" - - p2ppeer "github.com/libp2p/go-libp2p-core/peer" - p2ppeerstore "github.com/libp2p/go-libp2p-core/peerstore" - ma "github.com/multiformats/go-multiaddr" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func Test_Peerstore_Start(t *testing.T) { - db := pgtest.NewSqlxDB(t) - - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) - - nonExistentP2PPeerID, err := p2ppeer.Decode("12D3KooWAdCzaesXyezatDzgGvCngqsBqoUqnV9PnVc46jsVt2i9") - require.NoError(t, err) - - err = utils.JustError(db.Exec(`INSERT INTO p2p_peers (id, addr, created_at, updated_at, peer_id) VALUES - ( - '12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - '/ip4/127.0.0.1/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - NOW(), - NOW(), - $1 - ), - ( - '12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - '/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - NOW(), - NOW(), - $2 - ), - ( - '12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - '/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - NOW(), - NOW(), - $3 - ) - `, p2pkey.PeerID(peerID), p2pkey.PeerID(peerID), p2pkey.PeerID(nonExistentP2PPeerID))) - require.NoError(t, err) - - cfg := configtest.NewTestGeneralConfig(t) - wrapper, err := ocrcommon.NewPeerstoreWrapper(db, 1*time.Second, p2pkey.PeerID(peerID), logger.TestLogger(t), cfg.Database()) - require.NoError(t, err) - - err = wrapper.Start() - require.NoError(t, err) - - require.Equal(t, 1, wrapper.Peerstore.PeersWithAddrs().Len()) - - peerID, err = p2ppeer.Decode("12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph") - require.NoError(t, err) - - maddrs := wrapper.Peerstore.Addrs(peerID) - - require.Len(t, maddrs, 2) -} - -func Test_Peerstore_WriteToDB(t *testing.T) { - db := pgtest.NewSqlxDB(t) - - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) - - cfg := configtest.NewTestGeneralConfig(t) - wrapper, err := ocrcommon.NewPeerstoreWrapper(db, 1*time.Second, p2pkey.PeerID(peerID), logger.TestLogger(t), cfg.Database()) - require.NoError(t, err) - - maddr, err := ma.NewMultiaddr("/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph") - require.NoError(t, err) - newPeerID, err := p2ppeer.Decode("12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph") - require.NoError(t, err) - - wrapper.Peerstore.AddAddr(newPeerID, maddr, p2ppeerstore.PermanentAddrTTL) - - err = wrapper.WriteToDB() - require.NoError(t, err) - - var peers []ocrcommon.P2PPeer - err = db.Select(&peers, `SELECT * FROM p2p_peers`) - require.NoError(t, err) - require.Equal(t, 1, len(peers)) - - peer := peers[0] - require.Equal(t, "12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph", peer.ID) - require.Equal(t, "/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph", peer.Addr) - require.Equal(t, p2pkey.PeerID(peerID).Raw(), peer.PeerID) -} diff --git a/core/services/signatures/secp256k1/curve.go b/core/services/signatures/secp256k1/curve.go index 2ed52a87ce..70187e6873 100644 --- a/core/services/signatures/secp256k1/curve.go +++ b/core/services/signatures/secp256k1/curve.go @@ -12,7 +12,7 @@ package secp256k1 import ( "math/big" - secp256k1BTCD "github.com/btcsuite/btcd/btcec" + secp256k1BTCD "github.com/btcsuite/btcd/btcec/v2" "go.dedis.ch/kyber/v3" ) diff --git a/core/services/signatures/secp256k1/field.go b/core/services/signatures/secp256k1/field.go index 7cfa7af2e5..1ff0d062f3 100644 --- a/core/services/signatures/secp256k1/field.go +++ b/core/services/signatures/secp256k1/field.go @@ -137,13 +137,11 @@ func fieldSquare(y *fieldElt) *fieldElt { return fieldEltFromBigInt(newFieldZero().int().Exp(y.int(), two, q)) } +func i() *big.Int { return new(big.Int) } + // sqrtPower is s.t. n^sqrtPower≡sqrt(n) mod q, if n has a root at all. See // https://math.stackexchange.com/a/1816280, for instance -// -// What I'm calling sqrtPower is called q on the s256 struct. (See -// btcec.initS256), which is confusing because the "Q" in "QPlus1Div4" refers to -// the field characteristic -var sqrtPower = s256.QPlus1Div4() +var sqrtPower = i().Rsh(i().Add(q, big.NewInt(1)), 2) // (q +1)/4 // maybeSqrtInField returns a square root of v, if it has any, else nil func maybeSqrtInField(v *fieldElt) *fieldElt { diff --git a/core/services/signatures/secp256k1/scalar.go b/core/services/signatures/secp256k1/scalar.go index 9d89188c4c..d12826a827 100644 --- a/core/services/signatures/secp256k1/scalar.go +++ b/core/services/signatures/secp256k1/scalar.go @@ -19,7 +19,7 @@ import ( "io" "math/big" - secp256k1BTCD "github.com/btcsuite/btcd/btcec" + secp256k1BTCD "github.com/btcsuite/btcd/btcec/v2" "github.com/ethereum/go-ethereum/common" "go.dedis.ch/kyber/v3" diff --git a/core/utils/utils.go b/core/utils/utils.go index 0df280775b..b887fe9a80 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -3,6 +3,7 @@ package utils import ( "context" + "crypto/ed25519" "crypto/rand" "encoding/base64" "encoding/hex" @@ -18,18 +19,17 @@ import ( "sync/atomic" "time" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - "golang.org/x/exp/constraints" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/google/uuid" "github.com/jpillora/backoff" - "github.com/libp2p/go-libp2p-core/peer" pkgerrors "github.com/pkg/errors" "github.com/robfig/cron/v3" "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/sha3" + "golang.org/x/exp/constraints" + + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/smartcontractkit/chainlink-common/pkg/services" ) @@ -64,11 +64,11 @@ func Bytes32ToSlice(a [32]byte) (r []byte) { } func MustNewPeerID() string { - _, pubKey, err := cryptop2p.GenerateEd25519Key(rand.Reader) + pubKey, _, err := ed25519.GenerateKey(rand.Reader) if err != nil { panic(err) } - peerID, err := peer.IDFromPublicKey(pubKey) + peerID, err := ragep2ptypes.PeerIDFromPublicKey(pubKey) if err != nil { panic(err) } diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 3beee88c2e..27d4433b63 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -18,8 +18,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/hashicorp/consul/sdk/freeport" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/pelletier/go-toml" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -48,8 +48,8 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin contractAddress = cltest.NewEIP55Address() ) - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) + var peerID ragep2ptypes.PeerID + require.NoError(t, peerID.UnmarshalText([]byte(configtest.DefaultPeerID))) randomBytes := testutils.Random32Byte() var tt = []struct { diff --git a/core/web/p2p_keys_controller.go b/core/web/p2p_keys_controller.go index c81400615b..bbe9d83f74 100644 --- a/core/web/p2p_keys_controller.go +++ b/core/web/p2p_keys_controller.go @@ -29,6 +29,8 @@ func (p2pkc *P2PKeysController) Index(c *gin.Context) { jsonAPIResponse(c, presenters.NewP2PKeyResources(keys), "p2pKey") } +const keyType = "Ed25519" + // Create and return a P2P key // Example: // "POST /keys/p2p" @@ -44,7 +46,7 @@ func (p2pkc *P2PKeysController) Create(c *gin.Context) { "id": key.ID(), "p2pPublicKey": key.PublicKeyHex(), "p2pPeerID": key.PeerID(), - "p2pType": key.Type(), + "p2pType": keyType, }) jsonAPIResponse(c, presenters.NewP2PKeyResource(key), "p2pKey") } @@ -101,7 +103,7 @@ func (p2pkc *P2PKeysController) Import(c *gin.Context) { "id": key.ID(), "p2pPublicKey": key.PublicKeyHex(), "p2pPeerID": key.PeerID(), - "p2pType": key.Type(), + "p2pType": keyType, }) jsonAPIResponse(c, presenters.NewP2PKeyResource(key), "p2pKey") diff --git a/core/web/presenters/p2p_key_test.go b/core/web/presenters/p2p_key_test.go index 2d30f87fe1..4e7b4e954f 100644 --- a/core/web/presenters/p2p_key_test.go +++ b/core/web/presenters/p2p_key_test.go @@ -1,7 +1,6 @@ package presenters import ( - "encoding/hex" "fmt" "testing" @@ -16,9 +15,6 @@ func TestP2PKeyResource(t *testing.T) { key := keystest.NewP2PKeyV2(t) peerID := key.PeerID() peerIDStr := peerID.String() - pubKey := key.GetPublic() - pubKeyBytes, err := pubKey.Raw() - require.NoError(t, err) r := NewP2PKeyResource(key) b, err := jsonapi.Marshal(r) @@ -34,7 +30,7 @@ func TestP2PKeyResource(t *testing.T) { "publicKey": "%s" } } - }`, key.ID(), peerIDStr, hex.EncodeToString(pubKeyBytes)) + }`, key.ID(), peerIDStr, key.PublicKeyHex()) assert.JSONEq(t, expected, string(b)) @@ -52,7 +48,7 @@ func TestP2PKeyResource(t *testing.T) { "publicKey": "%s" } } - }`, key.ID(), peerIDStr, hex.EncodeToString(pubKeyBytes)) + }`, key.ID(), peerIDStr, key.PublicKeyHex()) assert.JSONEq(t, expected, string(b)) } diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index 990a6c0805..996b3859a5 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -640,12 +640,13 @@ func (r *Resolver) CreateP2PKey(ctx context.Context) (*CreateP2PKeyPayloadResolv return nil, err } + const keyType = "Ed25519" r.App.GetAuditLogger().Audit(audit.KeyCreated, map[string]interface{}{ "type": "p2p", "id": key.ID(), "p2pPublicKey": key.PublicKeyHex(), "p2pPeerID": key.PeerID(), - "p2pType": key.Type(), + "p2pType": keyType, }) return NewCreateP2PKeyPayload(key), nil diff --git a/go.mod b/go.mod index 40359ab16f..d8394633c3 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 github.com/avast/retry-go/v4 v4.5.1 - github.com/btcsuite/btcd v0.23.4 + github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/cometbft/cometbft v0.37.2 github.com/cosmos/cosmos-sdk v0.47.4 github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e @@ -24,7 +24,7 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-webauthn/webauthn v0.9.4 - github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 + github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b github.com/google/uuid v1.4.0 github.com/gorilla/securecookie v1.1.2 github.com/gorilla/sessions v1.2.2 @@ -43,13 +43,10 @@ require ( github.com/kylelemons/godebug v1.1.0 github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a github.com/lib/pq v1.10.9 - github.com/libp2p/go-libp2p-core v0.8.5 - github.com/libp2p/go-libp2p-peerstore v0.2.7 github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/mr-tron/base58 v1.2.0 - github.com/multiformats/go-multiaddr v0.3.3 github.com/olekukonko/tablewriter v0.0.5 github.com/onsi/gomega v1.30.0 github.com/patrickmn/go-cache v2.1.0+incompatible @@ -131,7 +128,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -223,9 +219,6 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-cid v0.0.7 // indirect - github.com/ipfs/go-log v1.0.4 // indirect - github.com/ipfs/go-log/v2 v2.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -240,7 +233,6 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -248,8 +240,6 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v0.1.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -257,13 +247,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multiaddr-net v0.2.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -279,8 +262,6 @@ require ( github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cobra v1.6.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -336,10 +317,6 @@ require ( ) replace ( - // Fix go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - // replicating the replace directive on cosmos SDK github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 diff --git a/go.sum b/go.sum index 11b377b11f..d702fd37e9 100644 --- a/go.sum +++ b/go.sum @@ -123,7 +123,6 @@ github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40wo github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= @@ -173,20 +172,12 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= @@ -314,17 +305,14 @@ github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5il github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= @@ -553,7 +541,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= @@ -603,8 +590,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -704,7 +691,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -744,22 +730,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= -github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= -github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -821,9 +791,6 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -843,7 +810,6 @@ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -862,7 +828,6 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= @@ -880,7 +845,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -905,22 +869,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= @@ -970,13 +920,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -1010,39 +955,10 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= @@ -1061,7 +977,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -1070,8 +985,6 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -1084,7 +997,6 @@ github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/ github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -1251,8 +1163,6 @@ github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgq github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1302,7 +1212,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= @@ -1367,8 +1276,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1448,7 +1355,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -1465,7 +1371,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -1481,14 +1386,11 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1546,7 +1448,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1556,7 +1457,6 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1776,7 +1676,6 @@ golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 5b44209f9a..72c15a8966 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -92,7 +92,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect - github.com/btcsuite/btcd v0.23.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/bytedance/sonic v1.10.1 // indirect @@ -207,7 +206,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect + github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/mux v1.8.0 // indirect @@ -253,9 +252,6 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-cid v0.0.7 // indirect - github.com/ipfs/go-log v1.0.4 // indirect - github.com/ipfs/go-log/v2 v2.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.1 // indirect github.com/jackc/pgio v1.0.0 // indirect @@ -279,9 +275,6 @@ require ( github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-libp2p-core v0.8.5 // indirect - github.com/libp2p/go-libp2p-peerstore v0.2.7 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect @@ -293,8 +286,6 @@ require ( github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/miekg/dns v1.1.56 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -310,14 +301,6 @@ require ( github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr v0.3.3 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multiaddr-net v0.2.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect @@ -370,8 +353,6 @@ require ( github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/soheilhy/cmux v0.1.5 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -472,10 +453,6 @@ require ( ) replace ( - // Fixes go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - github.com/go-kit/log => github.com/go-kit/log v0.2.1 // replicating the replace directive on cosmos SDK diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 0e29f6f671..494e5c21ec 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -145,7 +145,6 @@ github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40wo github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= @@ -207,20 +206,12 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= @@ -383,7 +374,6 @@ github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5il github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= @@ -392,10 +382,8 @@ github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= @@ -714,7 +702,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -770,8 +757,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -905,7 +892,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -954,22 +940,6 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= -github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= -github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -1026,9 +996,6 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -1049,7 +1016,6 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -1074,7 +1040,6 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= @@ -1121,22 +1086,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= @@ -1204,14 +1155,8 @@ github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SW github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= -github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -1256,9 +1201,6 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= @@ -1267,32 +1209,6 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc= github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1316,7 +1232,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -1325,8 +1240,6 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -1343,7 +1256,6 @@ github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cP github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -1555,8 +1467,6 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1607,7 +1517,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= @@ -1677,8 +1586,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -1780,7 +1687,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -1797,7 +1703,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -1814,16 +1719,13 @@ golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaE golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1881,7 +1783,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1891,7 +1792,6 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -2141,7 +2041,6 @@ golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= From 0c63446ae535671b67a253ac1c1d43860ebeb653 Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 12 Dec 2023 10:52:16 +0000 Subject: [PATCH 297/327] [BCF-2760] Flakey test detection improvements (#11470) * [BCF-2760] Flakey test detection improvements * [BCF-2760] Dedupe test and subtest entries --- tools/flakeytests/reporter.go | 69 +++++++-- tools/flakeytests/reporter_test.go | 103 ++++++++++--- tools/flakeytests/runner.go | 222 ++++++++++++++++++++++------- tools/flakeytests/runner_test.go | 106 +++++++++++--- 4 files changed, 399 insertions(+), 101 deletions(-) diff --git a/tools/flakeytests/reporter.go b/tools/flakeytests/reporter.go index 6696ec29a4..f17a44ef9f 100644 --- a/tools/flakeytests/reporter.go +++ b/tools/flakeytests/reporter.go @@ -11,6 +11,12 @@ import ( "time" ) +const ( + messageType_flakeyTest = "flakey_test" + messageType_runReport = "run_report" + messageType_packagePanic = "package_panic" +) + type pushRequest struct { Streams []stream `json:"streams"` } @@ -20,16 +26,28 @@ type stream struct { Values [][]string `json:"values"` } +type BaseMessage struct { + MessageType string `json:"message_type"` + Context +} + type flakeyTest struct { + BaseMessage Package string `json:"package"` TestName string `json:"test_name"` FQTestName string `json:"fq_test_name"` - Context } -type numFlakes struct { - NumFlakes int `json:"num_flakes"` - Context +type packagePanic struct { + BaseMessage + Package string `json:"package"` +} + +type runReport struct { + BaseMessage + NumPackagePanics int `json:"num_package_panics"` + NumFlakes int `json:"num_flakes"` + NumCombined int `json:"num_combined"` } type Context struct { @@ -48,17 +66,21 @@ type LokiReporter struct { ctx Context } -func (l *LokiReporter) createRequest(flakeyTests map[string]map[string]struct{}) (pushRequest, error) { +func (l *LokiReporter) createRequest(report *Report) (pushRequest, error) { vs := [][]string{} now := l.now() nows := fmt.Sprintf("%d", now.UnixNano()) - for pkg, tests := range flakeyTests { + + for pkg, tests := range report.tests { for t := range tests { d, err := json.Marshal(flakeyTest{ + BaseMessage: BaseMessage{ + MessageType: messageType_flakeyTest, + Context: l.ctx, + }, Package: pkg, TestName: t, FQTestName: fmt.Sprintf("%s:%s", pkg, t), - Context: l.ctx, }) if err != nil { return pushRequest{}, err @@ -67,10 +89,35 @@ func (l *LokiReporter) createRequest(flakeyTests map[string]map[string]struct{}) } } - // Flakes are store in a map[string][]string, so to count them, we can't just do len(flakeyTests), + // Flakes are stored in a map[string][]string, so to count them, we can't just do len(flakeyTests), // as that will get us the number of flakey packages, not the number of flakes tests. // However, we do emit one log line per flakey test above, so use that to count our flakes. - f, err := json.Marshal(numFlakes{NumFlakes: len(vs), Context: l.ctx}) + numFlakes := len(vs) + + for pkg := range report.packagePanics { + d, err := json.Marshal(packagePanic{ + BaseMessage: BaseMessage{ + MessageType: messageType_packagePanic, + Context: l.ctx, + }, + Package: pkg, + }) + if err != nil { + return pushRequest{}, err + } + + vs = append(vs, []string{nows, string(d)}) + } + + f, err := json.Marshal(runReport{ + BaseMessage: BaseMessage{ + MessageType: messageType_runReport, + Context: l.ctx, + }, + NumFlakes: numFlakes, + NumPackagePanics: len(report.packagePanics), + NumCombined: numFlakes + len(report.packagePanics), + }) if err != nil { return pushRequest{}, nil } @@ -120,8 +167,8 @@ func (l *LokiReporter) makeRequest(pushReq pushRequest) error { return err } -func (l *LokiReporter) Report(flakeyTests map[string]map[string]struct{}) error { - pushReq, err := l.createRequest(flakeyTests) +func (l *LokiReporter) Report(report *Report) error { + pushReq, err := l.createRequest(report) if err != nil { return err } diff --git a/tools/flakeytests/reporter_test.go b/tools/flakeytests/reporter_test.go index 9cb2c8e9f7..15650fc7bd 100644 --- a/tools/flakeytests/reporter_test.go +++ b/tools/flakeytests/reporter_test.go @@ -12,68 +12,131 @@ import ( func TestMakeRequest_SingleTest(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{ - "core/assets": map[string]struct{}{ - "TestLink": struct{}{}, + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestLink": 1, + }, }, } lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink","commit_sha":"","repository":"","event_type":""}`}, - {ts, `{"num_flakes":1,"commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink"}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":0,"num_flakes":1,"num_combined":1}`}, }) } func TestMakeRequest_MultipleTests(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{ - "core/assets": map[string]struct{}{ - "TestLink": struct{}{}, - "TestCore": struct{}{}, + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestLink": 1, + "TestCore": 1, + }, }, } lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink","commit_sha":"","repository":"","event_type":""}`}, - {ts, `{"package":"core/assets","test_name":"TestCore","fq_test_name":"core/assets:TestCore","commit_sha":"","repository":"","event_type":""}`}, - {ts, `{"num_flakes":2,"commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink"}`}, + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestCore","fq_test_name":"core/assets:TestCore"}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":0,"num_flakes":2,"num_combined":2}`}, }) } func TestMakeRequest_NoTests(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{} + r := NewReport() lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"num_flakes":0,"commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":0,"num_flakes":0,"num_combined":0}`}, }) } func TestMakeRequest_WithContext(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{} + r := NewReport() lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }, ctx: Context{CommitSHA: "42"}} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"num_flakes":0,"commit_sha":"42","repository":"","event_type":""}`}, + {ts, `{"message_type":"run_report","commit_sha":"42","repository":"","event_type":"","num_package_panics":0,"num_flakes":0,"num_combined":0}`}, }) } + +func TestMakeRequest_Panics(t *testing.T) { + now := time.Now() + ts := fmt.Sprintf("%d", now.UnixNano()) + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestLink": 1, + }, + }, + packagePanics: map[string]int{ + "core/assets": 1, + }, + } + lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} + pr, err := lr.createRequest(r) + require.NoError(t, err) + assert.Len(t, pr.Streams, 1) + assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) + + assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink"}`}, + {ts, `{"message_type":"package_panic","commit_sha":"","repository":"","event_type":"","package":"core/assets"}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":1,"num_flakes":1,"num_combined":2}`}, + }) +} + +func TestDedupeEntries(t *testing.T) { + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestSomethingAboutAssets/test_1": 2, + "TestSomethingAboutAssets": 4, + "TestSomeOtherTest": 1, + "TestSomethingAboutAssets/test_2": 2, + "TestFinalTest/test_1": 1, + }, + "core/services/important_service": map[string]int{ + "TestAnImportantService/a_subtest": 1, + }, + }, + } + + otherReport, err := dedupeEntries(r) + require.NoError(t, err) + + expectedMap := map[string]map[string]int{ + "core/assets": map[string]int{ + "TestSomethingAboutAssets/test_1": 2, + "TestSomeOtherTest": 1, + "TestSomethingAboutAssets/test_2": 2, + "TestFinalTest/test_1": 1, + }, + "core/services/important_service": map[string]int{ + "TestAnImportantService/a_subtest": 1, + }, + } + assert.Equal(t, expectedMap, otherReport.tests) +} diff --git a/tools/flakeytests/runner.go b/tools/flakeytests/runner.go index d935000222..97402633f3 100644 --- a/tools/flakeytests/runner.go +++ b/tools/flakeytests/runner.go @@ -11,6 +11,7 @@ import ( "os" "os/exec" "regexp" + "sort" "strings" "time" ) @@ -32,10 +33,10 @@ type tester interface { } type reporter interface { - Report(map[string]map[string]struct{}) error + Report(r *Report) error } -type parseFn func(readers ...io.Reader) (map[string]map[string]int, error) +type parseFn func(readers ...io.Reader) (*Report, error) func NewRunner(readers []io.Reader, reporter reporter, numReruns int) *Runner { tc := &testCommand{ @@ -60,9 +61,14 @@ type testCommand struct { func (t *testCommand) test(pkg string, tests []string, w io.Writer) error { replacedPkg := strings.Replace(pkg, t.repo, "", -1) - testFilter := strings.Join(tests, "|") cmd := exec.Command(t.command, fmt.Sprintf(".%s", replacedPkg)) //#nosec - cmd.Env = append(os.Environ(), fmt.Sprintf("TEST_FLAGS=-run %s", testFilter)) + cmd.Env = os.Environ() + + if len(tests) > 0 { + testFilter := strings.Join(tests, "|") + cmd.Env = append(cmd.Env, fmt.Sprintf("TEST_FLAGS=-run %s", testFilter)) + } + cmd.Stdout = io.MultiWriter(os.Stdout, w) cmd.Stderr = io.MultiWriter(os.Stderr, w) t.overrides(cmd) @@ -84,8 +90,8 @@ func newEvent(b []byte) (*TestEvent, error) { return e, err } -func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { - tests := map[string]map[string]int{} +func parseOutput(readers ...io.Reader) (*Report, error) { + report := NewReport() for _, r := range readers { s := bufio.NewScanner(r) for s.Scan() { @@ -105,24 +111,32 @@ func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { return nil, err } - // We're only interested in test failures, for which - // both Package and Test would be present. - if e.Package == "" || e.Test == "" { - continue - } - switch e.Action { case "fail": - if tests[e.Package] == nil { - tests[e.Package] = map[string]int{} + // Fail logs come in two forms: + // - with e.Package && e.Test, in which case it indicates a test failure. + // - with e.Package only, which indicates that the package test has failed, + // or possible that there has been a panic in an out-of-process goroutine running + // as part of the tests. + // + // We can ignore the last case because a package failure will be accounted elsewhere, either + // in the form of a failing test entry, or in the form of a panic output log, covered below. + if e.Test == "" { + continue } - tests[e.Package][e.Test]++ + + report.IncTest(e.Package, e.Test) case "output": if panicRe.MatchString(e.Output) { - if tests[e.Package] == nil { - tests[e.Package] = map[string]int{} + // Similar to the above, a panic can come in two forms: + // - attached to a test (i.e. with e.Test != ""), in which case + // we'll treat it like a failing test. + // - package-scoped, in which case we'll treat it as a package panic. + if e.Test != "" { + report.IncTest(e.Package, e.Test) + } else { + report.IncPackagePanic(e.Package) } - tests[e.Package][e.Test]++ } } } @@ -131,75 +145,183 @@ func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { return nil, err } } - return tests, nil + + return report, nil } type exitCoder interface { ExitCode() int } -func (r *Runner) runTests(failedTests map[string]map[string]int) (map[string]map[string]struct{}, error) { - suspectedFlakes := map[string]map[string]struct{}{} +type Report struct { + tests map[string]map[string]int + packagePanics map[string]int +} + +func NewReport() *Report { + return &Report{ + tests: map[string]map[string]int{}, + packagePanics: map[string]int{}, + } +} + +func (r *Report) HasFlakes() bool { + return len(r.tests) > 0 || len(r.packagePanics) > 0 +} + +func (r *Report) SetTest(pkg, test string, val int) { + if r.tests[pkg] == nil { + r.tests[pkg] = map[string]int{} + } + r.tests[pkg][test] = val +} + +func (r *Report) IncTest(pkg string, test string) { + if r.tests[pkg] == nil { + r.tests[pkg] = map[string]int{} + } + r.tests[pkg][test]++ +} - for pkg, tests := range failedTests { +func (r *Report) IncPackagePanic(pkg string) { + r.packagePanics[pkg]++ +} + +func (r *Runner) runTest(pkg string, tests []string) (*Report, error) { + var out bytes.Buffer + err := r.testCommand.test(pkg, tests, &out) + if err != nil { + log.Printf("Test command errored: %s\n", err) + // There was an error because the command failed with a non-zero + // exit code. This could just mean that the test failed again, so let's + // keep going. + var exErr exitCoder + if errors.As(err, &exErr) && exErr.ExitCode() > 0 { + return r.parse(&out) + } + return nil, err + } + + return r.parse(&out) +} + +func (r *Runner) runTests(rep *Report) (*Report, error) { + report := NewReport() + + // We need to deal with two types of flakes here: + // - flakes where we know the test that failed; in this case, we just rerun the failing test in question + // - flakes where we don't know what test failed. These are flakes where a panic occurred in an out-of-process goroutine, + // thus failing the package as a whole. For these, we'll rerun the whole package again. + for pkg, tests := range rep.tests { ts := []string{} for test := range tests { ts = append(ts, test) } - log.Printf("Executing test command with parameters: pkg=%s, tests=%+v, numReruns=%d\n", pkg, ts, r.numReruns) + log.Printf("[FLAKEY_TEST] Executing test command with parameters: pkg=%s, tests=%+v, numReruns=%d\n", pkg, ts, r.numReruns) for i := 0; i < r.numReruns; i++ { - var out bytes.Buffer - - err := r.testCommand.test(pkg, ts, &out) + pr, err := r.runTest(pkg, ts) if err != nil { - log.Printf("Test command errored: %s\n", err) - // There was an error because the command failed with a non-zero - // exit code. This could just mean that the test failed again, so let's - // keep going. - var exErr exitCoder - if errors.As(err, &exErr) && exErr.ExitCode() > 0 { - continue + return report, err + } + + for t := range tests { + failures := pr.tests[pkg][t] + if failures == 0 { + report.SetTest(pkg, t, 1) } - return suspectedFlakes, err } - fr, err := r.parse(&out) + } + } + + for pkg := range rep.packagePanics { + log.Printf("[PACKAGE_PANIC]: Executing test command with parameters: pkg=%s, numReruns=%d\n", pkg, r.numReruns) + for i := 0; i < r.numReruns; i++ { + pr, err := r.runTest(pkg, []string{}) if err != nil { - return nil, err + return report, err } - for t := range tests { - failures := fr[pkg][t] - if failures == 0 { - if suspectedFlakes[pkg] == nil { - suspectedFlakes[pkg] = map[string]struct{}{} - } - suspectedFlakes[pkg][t] = struct{}{} - } + if pr.packagePanics[pkg] == 0 { + report.IncPackagePanic(pkg) + } + } + } + + return report, nil +} + +func isSubtest(tn string) bool { + return strings.Contains(tn, "/") +} + +func isSubtestOf(st, mt string) bool { + return isSubtest(st) && strings.Contains(st, mt) +} + +func dedupeEntries(report *Report) (*Report, error) { + out := NewReport() + out.packagePanics = report.packagePanics + for pkg, tests := range report.tests { + // Sort the test names + testNames := make([]string, 0, len(tests)) + for t := range tests { + testNames = append(testNames, t) + } + + sort.Strings(testNames) + + for i, tn := range testNames { + // Is this the last element? If it is, then add it to the deduped set. + // This is because a) it's a main test, in which case we add it because + // it has no subtests following it, or b) it's a subtest, which we always add. + if i == len(testNames)-1 { + out.SetTest(pkg, tn, report.tests[pkg][tn]) + continue } + + // Next, let's compare the current item to the next one in the alphabetical order. + // In all cases we want to add the current item, UNLESS the current item is a main test, + // and the following one is a subtest of the current item. + nextItem := testNames[i+1] + if !isSubtest(tn) && isSubtestOf(nextItem, tn) { + continue + } + + out.SetTest(pkg, tn, report.tests[pkg][tn]) } + } - return suspectedFlakes, nil + return out, nil } func (r *Runner) Run() error { - failedTests, err := r.parse(r.readers...) + parseReport, err := r.parse(r.readers...) if err != nil { return err } - suspectedFlakes, err := r.runTests(failedTests) + report, err := r.runTests(parseReport) if err != nil { return err } - if len(suspectedFlakes) > 0 { - log.Printf("ERROR: Suspected flakes found: %+v\n", suspectedFlakes) + if report.HasFlakes() { + log.Printf("ERROR: Suspected flakes found: %+v\n", report) } else { log.Print("SUCCESS: No suspected flakes detected") } - return r.reporter.Report(suspectedFlakes) + // Before reporting the errors, let's dedupe some entries: + // In actuality, a failing subtest will produce two failing test entries, + // namely one for the test as a whole, and one for the subtest. + // This leads to inaccurate metrics since a failing subtest is double-counted. + report, err = dedupeEntries(report) + if err != nil { + return err + } + + return r.reporter.Report(report) } diff --git a/tools/flakeytests/runner_test.go b/tools/flakeytests/runner_test.go index 31f300dcbe..64e2a6c968 100644 --- a/tools/flakeytests/runner_test.go +++ b/tools/flakeytests/runner_test.go @@ -12,16 +12,16 @@ import ( ) type mockReporter struct { - entries map[string]map[string]struct{} + report *Report } -func (m *mockReporter) Report(entries map[string]map[string]struct{}) error { - m.entries = entries +func (m *mockReporter) Report(report *Report) error { + m.report = report return nil } func newMockReporter() *mockReporter { - return &mockReporter{entries: map[string]map[string]struct{}{}} + return &mockReporter{report: NewReport()} } func TestParser(t *testing.T) { @@ -29,9 +29,10 @@ func TestParser(t *testing.T) { ` r := strings.NewReader(output) - ts, err := parseOutput(r) + pr, err := parseOutput(r) require.NoError(t, err) + ts := pr.tests assert.Len(t, ts, 1) assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"], 1) @@ -44,9 +45,10 @@ func TestParser_SkipsNonJSON(t *testing.T) { ` r := strings.NewReader(output) - ts, err := parseOutput(r) + pr, err := parseOutput(r) require.NoError(t, err) + ts := pr.tests assert.Len(t, ts, 1) assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"], 1) @@ -58,9 +60,10 @@ func TestParser_PanicDueToLogging(t *testing.T) { ` r := strings.NewReader(output) - ts, err := parseOutput(r) + pr, err := parseOutput(r) require.NoError(t, err) + ts := pr.tests assert.Len(t, ts, 1) assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestAssets_LinkScanValue"], 1) @@ -85,7 +88,7 @@ func TestParser_SuccessfulOutput(t *testing.T) { r := strings.NewReader(output) ts, err := parseOutput(r) require.NoError(t, err) - assert.Len(t, ts, 0) + assert.Len(t, ts.tests, 0) } type testAdapter func(string, []string, io.Writer) error @@ -119,8 +122,8 @@ func TestRunner_WithFlake(t *testing.T) { // to only report one failure (not two as expected). err := r.Run() require.NoError(t, err) - assert.Len(t, m.entries, 1) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + assert.Len(t, m.report.tests, 1) + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -154,8 +157,8 @@ func TestRunner_WithFailedPackage(t *testing.T) { // to only report one failure (not two as expected). err := r.Run() require.NoError(t, err) - assert.Len(t, m.entries, 1) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + assert.Len(t, m.report.tests, 1) + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -180,7 +183,7 @@ func TestRunner_AllFailures(t *testing.T) { err := r.Run() require.NoError(t, err) - assert.Len(t, m.entries, 0) + assert.Len(t, m.report.tests, 0) } func TestRunner_RerunSuccessful(t *testing.T) { @@ -206,7 +209,7 @@ func TestRunner_RerunSuccessful(t *testing.T) { err := r.Run() require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -228,7 +231,7 @@ func TestRunner_RootLevelTest(t *testing.T) { err := r.Run() require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/"]["TestConfigDocs"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/"]["TestConfigDocs"] assert.True(t, ok) } @@ -255,7 +258,7 @@ func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { err := r.Run() require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -295,10 +298,25 @@ func TestRunner_RerunWithNonZeroExitCodeDoesntStopCommand(t *testing.T) { calls := index assert.Equal(t, 4, calls) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } +// Used for integration tests +func TestSkippedForTests_Subtests(t *testing.T) { + if os.Getenv("FLAKEY_TEST_RUNNER_RUN_FIXTURE_TEST") != "1" { + t.Skip() + } + + t.Run("1: should fail", func(t *testing.T) { + assert.False(t, true) + }) + + t.Run("2: should fail", func(t *testing.T) { + assert.False(t, true) + }) +} + // Used for integration tests func TestSkippedForTests(t *testing.T) { if os.Getenv("FLAKEY_TEST_RUNNER_RUN_FIXTURE_TEST") != "1" { @@ -319,7 +337,51 @@ func TestSkippedForTests_Success(t *testing.T) { assert.True(t, true) } -func TestParsesPanicCorrectly(t *testing.T) { +func TestIntegration_DealsWithSubtests(t *testing.T) { + if testing.Short() { + t.Skip() + } + + output := ` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Subtests/1:_should_fail","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Subtests","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Subtests/2:_should_fail","Elapsed":0} +` + + m := newMockReporter() + tc := &testCommand{ + repo: "github.com/smartcontractkit/chainlink/v2/tools/flakeytests", + command: "../bin/go_core_tests", + overrides: func(cmd *exec.Cmd) { + cmd.Env = append(cmd.Env, "FLAKEY_TESTRUNNER_RUN_FIXTURE_TEST=1") + cmd.Stdout = io.Discard + cmd.Stderr = io.Discard + }, + } + r := &Runner{ + numReruns: 2, + readers: []io.Reader{strings.NewReader(output)}, + testCommand: tc, + parse: parseOutput, + reporter: m, + } + + err := r.Run() + require.NoError(t, err) + expectedTests := map[string]map[string]int{ + "github.com/smartcontractkit/chainlink/v2/tools/flakeytests/": { + "TestSkippedForTests_Subtests/1:_should_fail": 1, + "TestSkippedForTests_Subtests/2:_should_fail": 1, + }, + } + assert.Equal(t, expectedTests, m.report.tests) +} + +func TestIntegration_ParsesPanics(t *testing.T) { + if testing.Short() { + t.Skip() + } + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests","Elapsed":0}` m := newMockReporter() @@ -342,11 +404,15 @@ func TestParsesPanicCorrectly(t *testing.T) { err := r.Run() require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests"] assert.False(t, ok) } func TestIntegration(t *testing.T) { + if testing.Short() { + t.Skip() + } + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Success","Elapsed":0}` m := newMockReporter() @@ -369,6 +435,6 @@ func TestIntegration(t *testing.T) { err := r.Run() require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests_Success"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests_Success"] assert.False(t, ok) } From 306eadcf505b54502b7112efc395457d4bd0f3c5 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Tue, 12 Dec 2023 14:35:33 +0200 Subject: [PATCH 298/327] Remove core utils dependencies from common (#11425) * Change difficulty from Big to BigInt * Fix headtracker mock head * Remove EsnureClosed * Fix mock heads * Migrate to common Mailbox * Fix Tracker close on txm * Change to EnsureHexPrefix * Change names to mailbox * Remove core/null dependency from common * Remove core mailbox * Fix dependencies * Tidy * Fix dependencies * Change path to internal utils * Minor fixes * Rename MinKey function * Update MinFunc * Fix utils conflicts --- common/client/node_lifecycle.go | 7 +- common/client/send_only_node_lifecycle.go | 2 +- common/headtracker/head_broadcaster.go | 6 +- common/headtracker/head_listener.go | 2 +- common/headtracker/head_tracker.go | 14 +- common/internal/utils/utils.go | 36 ++++ common/txmgr/broadcaster.go | 2 +- common/txmgr/confirmer.go | 14 +- common/txmgr/reaper.go | 2 +- common/txmgr/resender.go | 2 +- common/txmgr/tracker.go | 8 +- common/txmgr/txmgr.go | 8 +- common/txmgr/types/tx.go | 3 +- .../chains/evm/gas/block_history_estimator.go | 6 +- .../evm/headtracker/head_broadcaster_test.go | 3 +- core/chains/evm/headtracker/head_tracker.go | 5 +- .../evm/headtracker/head_tracker_test.go | 9 +- core/chains/evm/log/broadcaster.go | 13 +- core/chains/evm/log/helpers_internal_test.go | 5 +- core/chains/evm/log/helpers_test.go | 4 +- core/chains/evm/log/integration_test.go | 3 +- core/chains/evm/txmgr/evm_tx_store.go | 3 +- core/chains/legacyevm/chain.go | 3 +- core/chains/legacyevm/chain_test.go | 7 +- core/cmd/shell.go | 3 +- core/cmd/shell_local_test.go | 6 +- core/internal/cltest/cltest.go | 3 +- core/internal/testutils/evmtest/evmtest.go | 5 +- core/services/chainlink/application.go | 3 +- .../relayer_chain_interoperators_test.go | 6 +- core/services/directrequest/delegate.go | 18 +- core/services/directrequest/delegate_test.go | 5 +- core/services/functions/listener_test.go | 4 +- core/services/job/runner_integration_test.go | 12 +- core/services/job/spawner_test.go | 9 +- core/services/keeper/delegate.go | 6 +- .../keeper/registry_synchronizer_core.go | 10 +- .../registry_synchronizer_helper_test.go | 4 +- core/services/keeper/upkeep_executer.go | 7 +- core/services/ocr/contract_tracker.go | 10 +- core/services/ocr/contract_tracker_test.go | 4 +- core/services/ocr/delegate.go | 5 +- core/services/ocr2/delegate.go | 6 +- .../services/ocr2/plugins/functions/plugin.go | 3 +- core/services/pipeline/task.eth_tx.go | 2 +- core/services/pipeline/task.eth_tx_test.go | 2 +- core/services/promreporter/prom_reporter.go | 7 +- core/services/vrf/delegate.go | 8 +- core/services/vrf/delegate_test.go | 5 +- core/services/vrf/v1/listener_v1.go | 5 +- core/services/vrf/v2/listener_v2.go | 1 + core/services/vrf/v2/listener_v2_test.go | 3 +- core/utils/mailbox.go | 126 ------------ core/utils/mailbox_prom.go | 93 --------- core/utils/mailbox_test.go | 181 ------------------ core/utils/utils.go | 21 -- 56 files changed, 200 insertions(+), 550 deletions(-) create mode 100644 common/internal/utils/utils.go delete mode 100644 core/utils/mailbox.go delete mode 100644 core/utils/mailbox_prom.go delete mode 100644 core/utils/mailbox_test.go diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 5ba0bff323..eda137d510 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -12,9 +12,10 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" - "github.com/smartcontractkit/chainlink/v2/core/utils" + iutils "github.com/smartcontractkit/chainlink/v2/common/internal/utils" ) var ( @@ -360,7 +361,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { lggr := logger.Named(n.lfcLog, "Unreachable") lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) - dialRetryBackoff := utils.NewRedialBackoff() + dialRetryBackoff := iutils.NewRedialBackoff() for { select { @@ -416,7 +417,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { lggr := logger.Named(n.lfcLog, "InvalidChainID") lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.State()) - chainIDRecheckBackoff := utils.NewRedialBackoff() + chainIDRecheckBackoff := iutils.NewRedialBackoff() for { select { diff --git a/common/client/send_only_node_lifecycle.go b/common/client/send_only_node_lifecycle.go index 4d5b102b5b..c66d267ed4 100644 --- a/common/client/send_only_node_lifecycle.go +++ b/common/client/send_only_node_lifecycle.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/common/internal/utils" ) // verifyLoop may only be triggered once, on Start, if initial chain ID check diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index 0e676f864f..758a771384 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -9,9 +9,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const TrackableCallbackTimeout = 2 * time.Second @@ -30,7 +30,7 @@ type HeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct services.StateMachine logger logger.Logger callbacks callbackSet[H, BLOCK_HASH] - mailbox *utils.Mailbox[H] + mailbox *mailbox.Mailbox[H] mutex sync.Mutex chClose services.StopChan wgDone sync.WaitGroup @@ -48,7 +48,7 @@ func NewHeadBroadcaster[ return &HeadBroadcaster[H, BLOCK_HASH]{ logger: logger.Named(lggr, "HeadBroadcaster"), callbacks: make(callbackSet[H, BLOCK_HASH]), - mailbox: utils.NewSingleMailbox[H](), + mailbox: mailbox.NewSingle[H](), chClose: make(chan struct{}), } } diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index 0aebf60663..e7ea4fb51a 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -14,8 +14,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/common/internal/utils" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index c977eb023c..373aa5a958 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -12,10 +12,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -43,14 +43,14 @@ type HeadTracker[ log logger.Logger headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH] headSaver types.HeadSaver[HTH, BLOCK_HASH] - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor client htrktypes.Client[HTH, S, ID, BLOCK_HASH] chainID ID config htrktypes.Config htConfig htrktypes.HeadTrackerConfig - backfillMB *utils.Mailbox[HTH] - broadcastMB *utils.Mailbox[HTH] + backfillMB *mailbox.Mailbox[HTH] + broadcastMB *mailbox.Mailbox[HTH] headListener types.HeadListener[HTH, BLOCK_HASH] chStop services.StopChan wgDone sync.WaitGroup @@ -70,7 +70,7 @@ func NewHeadTracker[ htConfig htrktypes.HeadTrackerConfig, headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH], headSaver types.HeadSaver[HTH, BLOCK_HASH], - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, getNilHead func() HTH, ) types.HeadTracker[HTH, BLOCK_HASH] { chStop := make(chan struct{}) @@ -82,8 +82,8 @@ func NewHeadTracker[ config: config, htConfig: htConfig, log: lggr, - backfillMB: utils.NewSingleMailbox[HTH](), - broadcastMB: utils.NewMailbox[HTH](HeadsBufferSize), + backfillMB: mailbox.NewSingle[HTH](), + broadcastMB: mailbox.New[HTH](HeadsBufferSize), chStop: chStop, headListener: NewHeadListener[HTH, S, ID, BLOCK_HASH](lggr, client, config, chStop), headSaver: headSaver, diff --git a/common/internal/utils/utils.go b/common/internal/utils/utils.go new file mode 100644 index 0000000000..1e285868c5 --- /dev/null +++ b/common/internal/utils/utils.go @@ -0,0 +1,36 @@ +package utils + +import ( + "cmp" + "slices" + "time" + + "github.com/jpillora/backoff" + "golang.org/x/exp/constraints" +) + +// NewRedialBackoff is a standard backoff to use for redialling or reconnecting to +// unreachable network endpoints +func NewRedialBackoff() backoff.Backoff { + return backoff.Backoff{ + Min: 1 * time.Second, + Max: 15 * time.Second, + Jitter: true, + } + +} + +// MinFunc returns the minimum value of the given element array with respect +// to the given key function. In the event U is not a compound type (e.g a +// struct) an identity function can be provided. +func MinFunc[U any, T constraints.Ordered](elems []U, f func(U) T) T { + var min T + if len(elems) == 0 { + return min + } + + e := slices.MinFunc(elems, func(a, b U) int { + return cmp.Compare(f(a), f(b)) + }) + return f(e) +} diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index f10ecafc67..dba2b976c3 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -18,12 +18,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index 95be9ad23e..aabdf45ae3 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -17,13 +17,15 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + iutils "github.com/smartcontractkit/chainlink/v2/common/internal/utils" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -129,7 +131,7 @@ type Confirmer[ ks txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ] enabledAddresses []ADDR - mb *utils.Mailbox[HEAD] + mb *mailbox.Mailbox[HEAD] ctx context.Context ctxCancel context.CancelFunc wg sync.WaitGroup @@ -174,7 +176,7 @@ func NewConfirmer[ dbConfig: dbConfig, chainID: client.ConfiguredChainID(), ks: keystore, - mb: utils.NewSingleMailbox[HEAD](), + mb: mailbox.NewSingle[HEAD](), isReceiptNil: isReceiptNil, } } @@ -223,7 +225,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) clo ec.initSync.Lock() defer ec.initSync.Unlock() if !ec.isStarted { - return fmt.Errorf("Confirmer is not started: %w", utils.ErrAlreadyStopped) + return fmt.Errorf("Confirmer is not started: %w", services.ErrAlreadyStopped) } ec.ctxCancel() ec.wg.Wait() @@ -869,7 +871,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han "err", sendError, "fee", attempt.TxFee, "feeLimit", etx.FeeLimit, - "signedRawTx", utils.AddHexPrefix(hex.EncodeToString(attempt.SignedRawTx)), + "signedRawTx", utils.EnsureHexPrefix(hex.EncodeToString(attempt.SignedRawTx)), "blockHeight", blockHeight, ) ec.SvcErrBuffer.Append(sendError) @@ -1147,7 +1149,7 @@ func observeUntilTxConfirmed[ // Since a tx can have many attempts, we take the number of blocks to confirm as the block number // of the receipt minus the block number of the first ever broadcast for this transaction. - broadcastBefore := utils.MinKey(attempt.Tx.TxAttempts, func(attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) int64 { + broadcastBefore := iutils.MinFunc(attempt.Tx.TxAttempts, func(attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) int64 { if attempt.BroadcastBeforeBlockNum != nil { return *attempt.BroadcastBeforeBlockNum } diff --git a/common/txmgr/reaper.go b/common/txmgr/reaper.go index 385a9a17c3..3ed05b2cae 100644 --- a/common/txmgr/reaper.go +++ b/common/txmgr/reaper.go @@ -7,10 +7,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Reaper handles periodic database cleanup for Txm diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 06c466e173..74cf3d1389 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -8,12 +8,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( diff --git a/common/txmgr/tracker.go b/common/txmgr/tracker.go index 1a24dd5b5f..3ef2fc0720 100644 --- a/common/txmgr/tracker.go +++ b/common/txmgr/tracker.go @@ -8,11 +8,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -56,7 +56,7 @@ type Tracker[ txCache map[int64]AbandonedTx[ADDR] ttl time.Duration lock sync.Mutex - mb *utils.Mailbox[int64] + mb *mailbox.Mailbox[int64] wg sync.WaitGroup isStarted bool ctx context.Context @@ -85,7 +85,7 @@ func NewTracker[ enabledAddrs: map[ADDR]bool{}, txCache: map[int64]AbandonedTx[ADDR]{}, ttl: defaultTTL, - mb: utils.NewSingleMailbox[int64](), + mb: mailbox.NewSingle[int64](), lock: sync.Mutex{}, wg: sync.WaitGroup{}, } diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 228ab4ec8b..e43a16b29e 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -14,10 +14,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + iutils "github.com/smartcontractkit/chainlink/v2/common/internal/utils" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // For more information about the Txm architecture, see the design doc: @@ -342,7 +344,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() ctx, cancel := b.chStop.NewCtx() defer cancel() // Retry indefinitely on failure - backoff := utils.NewRedialBackoff() + backoff := iutils.NewRedialBackoff() for { select { case <-time.After(backoff.Duration()): @@ -361,7 +363,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() go func() { defer wg.Done() // Retry indefinitely on failure - backoff := utils.NewRedialBackoff() + backoff := iutils.NewRedialBackoff() for { select { case <-time.After(backoff.Duration()): diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index 3af43b1961..caac763fc0 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -15,9 +15,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" ) // TxStrategy controls how txes are queued and sent diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 0ec4721b79..844b9e547f 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/common/config" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // MaxStartTime is the maximum amount of time we are allowed to spend @@ -109,7 +109,7 @@ type ( blocks []evmtypes.Block blocksMu sync.RWMutex size int64 - mb *utils.Mailbox[*evmtypes.Head] + mb *mailbox.Mailbox[*evmtypes.Head] wg *sync.WaitGroup ctx context.Context ctxCancel context.CancelFunc @@ -139,7 +139,7 @@ func NewBlockHistoryEstimator(lggr logger.Logger, ethClient evmclient.Client, cf blocks: make([]evmtypes.Block, 0), // Must have enough blocks for both estimator and connectivity checker size: int64(mathutil.Max(bhCfg.BlockHistorySize(), bhCfg.CheckInclusionBlocks())), - mb: utils.NewSingleMailbox[*evmtypes.Head](), + mb: mailbox.NewSingle[*evmtypes.Head](), wg: new(sync.WaitGroup), ctx: ctx, ctxCancel: cancel, diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index ac43c08fe8..b9fab9cdd4 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" commonhtrk "github.com/smartcontractkit/chainlink/v2/common/headtracker" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" @@ -71,7 +72,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { orm := headtracker.NewORM(db, logger, cfg.Database(), *ethClient.ConfiguredChainID()) hs := headtracker.NewHeadSaver(logger, orm, evmCfg.EVM(), evmCfg.EVM().HeadTracker()) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailbox.NewMonitor(t.Name()) servicetest.Run(t, mailMon) hb := headtracker.NewHeadBroadcaster(logger) servicetest.Run(t, hb) diff --git a/core/chains/evm/headtracker/head_tracker.go b/core/chains/evm/headtracker/head_tracker.go index b86a6b5fe2..3cddfb71d0 100644 --- a/core/chains/evm/headtracker/head_tracker.go +++ b/core/chains/evm/headtracker/head_tracker.go @@ -9,12 +9,13 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/common/headtracker" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type headTracker = headtracker.HeadTracker[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash] @@ -28,7 +29,7 @@ func NewHeadTracker( htConfig HeadTrackerConfig, headBroadcaster httypes.HeadBroadcaster, headSaver httypes.HeadSaver, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) httypes.HeadTracker { return headtracker.NewHeadTracker[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash]( lggr, diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index 4d3cebd24e..d8abb1328a 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -992,7 +993,7 @@ func createHeadTracker(t *testing.T, ethClient evmclient.Client, config headtrac lggr := logger.Test(t) hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, config, htConfig) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailbox.NewMonitor(t.Name()) return &headTrackerUniverse{ mu: new(sync.Mutex), headTracker: headtracker.NewHeadTracker(lggr, ethClient, config, htConfig, hb, hs, mailMon), @@ -1007,7 +1008,7 @@ func createHeadTrackerWithNeverSleeper(t *testing.T, ethClient evmclient.Client, lggr := logger.Test(t) hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, evmcfg.EVM(), evmcfg.EVM().HeadTracker()) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailbox.NewMonitor(t.Name()) ht := headtracker.NewHeadTracker(lggr, ethClient, evmcfg.EVM(), evmcfg.EVM().HeadTracker(), hb, hs, mailMon) _, err := hs.Load(testutils.Context(t)) require.NoError(t, err) @@ -1025,7 +1026,7 @@ func createHeadTrackerWithChecker(t *testing.T, ethClient evmclient.Client, conf hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, config, htConfig) hb.Subscribe(checker) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailbox.NewMonitor(t.Name()) ht := headtracker.NewHeadTracker(lggr, ethClient, config, htConfig, hb, hs, mailMon) return &headTrackerUniverse{ mu: new(sync.Mutex), @@ -1042,7 +1043,7 @@ type headTrackerUniverse struct { headTracker httypes.HeadTracker headBroadcaster httypes.HeadBroadcaster headSaver httypes.HeadSaver - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } func (u *headTrackerUniverse) Backfill(ctx context.Context, head *evmtypes.Head, depth uint) error { diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index f452839609..393d1c1b26 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" @@ -102,11 +103,11 @@ type ( registrations *registrations logPool *logPool - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor // Use the same channel for subs/unsubs so ordering is preserved // (unsubscribe must happen after subscribe) - changeSubscriberStatus *utils.Mailbox[changeSubscriberStatus] - newHeads *utils.Mailbox[*evmtypes.Head] + changeSubscriberStatus *mailbox.Mailbox[changeSubscriberStatus] + newHeads *mailbox.Mailbox[*evmtypes.Head] utils.DependentAwaiter @@ -165,7 +166,7 @@ const ( var _ Broadcaster = (*broadcaster)(nil) // NewBroadcaster creates a new instance of the broadcaster -func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *utils.MailboxMonitor) *broadcaster { +func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { chStop := make(chan struct{}) lggr = logger.Named(lggr, "LogBroadcaster") chainId := ethClient.ConfiguredChainID() @@ -178,8 +179,8 @@ func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr log registrations: newRegistrations(lggr, *chainId), logPool: newLogPool(lggr), mailMon: mailMon, - changeSubscriberStatus: utils.NewHighCapacityMailbox[changeSubscriberStatus](), - newHeads: utils.NewSingleMailbox[*evmtypes.Head](), + changeSubscriberStatus: mailbox.NewHighCapacity[changeSubscriberStatus](), + newHeads: mailbox.NewSingle[*evmtypes.Head](), DependentAwaiter: utils.NewDependentAwaiter(), chStop: chStop, highestSavedHead: highestSavedHead, diff --git a/core/chains/evm/log/helpers_internal_test.go b/core/chains/evm/log/helpers_internal_test.go index 38f40bd329..4d4318cdf9 100644 --- a/core/chains/evm/log/helpers_internal_test.go +++ b/core/chains/evm/log/helpers_internal_test.go @@ -4,13 +4,14 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // NewTestBroadcaster creates a broadcaster with Pause/Resume enabled. -func NewTestBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *utils.MailboxMonitor) *broadcaster { +func NewTestBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { b := NewBroadcaster(orm, ethClient, config, lggr, highestSavedHead, mailMon) b.testPause, b.testResume = make(chan struct{}), make(chan struct{}) return b diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index e41f08e8d2..13dfe1ffab 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -42,7 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type broadcasterHelper struct { @@ -90,7 +90,7 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, }) config := evmtest.NewChainScopedConfig(t, globalConfig) lggr := logger.Test(t) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) db := pgtest.NewSqlxDB(t) orm := log.NewORM(db, lggr, config.Database(), cltest.FixtureChainID) diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index e5b6ad3caf..b26e87e668 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -1325,7 +1326,7 @@ func TestBroadcaster_AppendLogChannel(t *testing.T) { ch3 := make(chan types.Log) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - mailMon := servicetest.RunHealthy(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.RunHealthy(t, mailbox.NewMonitor(t.Name())) lb := log.NewBroadcaster(nil, ethClient, nil, logger.Test(t), nil, mailMon) chCombined := lb.ExportedAppendLogChannel(ch1, ch2) chCombined = lb.ExportedAppendLogChannel(chCombined, ch3) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 730809e8dd..1c9868741f 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -20,13 +20,14 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/smartcontractkit/chainlink-common/pkg/utils/null" + "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 4b4c69f1ab..18277a55d0 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -16,6 +16,7 @@ import ( common "github.com/smartcontractkit/chainlink-common/pkg/chains" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" @@ -164,7 +165,7 @@ type ChainOpts struct { AppConfig AppConfig EventBroadcaster pg.EventBroadcaster - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor GasEstimator gas.EvmFeeEstimator *sqlx.DB diff --git a/core/chains/legacyevm/chain_test.go b/core/chains/legacyevm/chain_test.go index 4fcd51c39d..93332348aa 100644 --- a/core/chains/legacyevm/chain_test.go +++ b/core/chains/legacyevm/chain_test.go @@ -8,12 +8,13 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestLegacyChains(t *testing.T) { @@ -35,7 +36,7 @@ func TestChainOpts_Validate(t *testing.T) { type fields struct { AppConfig legacyevm.AppConfig EventBroadcaster pg.EventBroadcaster - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor DB *sqlx.DB } tests := []struct { @@ -48,7 +49,7 @@ func TestChainOpts_Validate(t *testing.T) { fields: fields{ AppConfig: configtest.NewTestGeneralConfig(t), EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, + MailMon: &mailbox.Monitor{}, DB: pgtest.NewSqlxDB(t), }, }, diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 2e382be4cc..3810559cf3 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -32,6 +32,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -153,7 +154,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G } keyStore := keystore.New(db, utils.GetScryptParams(cfg), appLggr, cfg.Database()) - mailMon := utils.NewMailboxMonitor(cfg.AppID().String()) + mailMon := mailbox.NewMonitor(cfg.AppID().String()) dbListener := cfg.Database().Listener() eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), dbListener.MinReconnectInterval(), dbListener.MaxReconnectDuration(), appLggr, cfg.AppID()) diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index fac2d7f040..56da90d811 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/cmd" @@ -89,7 +91,7 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, + MailMon: &mailbox.Monitor{}, DB: db, }, } @@ -194,7 +196,7 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, + MailMon: &mailbox.Monitor{}, DB: db, }, } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 88abc3de5c..dc90201890 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -38,6 +38,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/client" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" @@ -339,7 +340,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn keyStore := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) - mailMon := utils.NewMailboxMonitor(cfg.AppID().String()) + mailMon := mailbox.NewMonitor(cfg.AppID().String()) loopRegistry := plugins.NewLoopRegistry(lggr, nil) mercuryPool := wsrpc.NewPool(lggr, cache.Config{ diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index e0a447a327..095ea1a35c 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains" @@ -65,7 +66,7 @@ type TestChainOpts struct { DB *sqlx.DB TxManager txmgr.TxManager KeyStore keystore.Eth - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor GasEstimator gas.EvmFeeEstimator } @@ -118,7 +119,7 @@ func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainR } } if opts.MailMon == nil { - opts.MailMon = servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + opts.MailMon = servicetest.Run(t, mailbox.NewMonitor(t.Name())) } if testopts.GasEstimator != nil { opts.GenGasEstimator = func(*big.Int) gas.EvmFeeEstimator { diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 5c204d693e..ed04308658 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -149,7 +150,7 @@ type ApplicationOpts struct { Config GeneralConfig Logger logger.Logger EventBroadcaster pg.EventBroadcaster - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor SqlxDB *sqlx.DB KeyStore keystore.Master RelayerChainInteroperators *CoreRelayerChainInteroperators diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 6a5445d9f2..a0754fa013 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -11,6 +11,8 @@ import ( commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" @@ -206,7 +208,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, + MailMon: &mailbox.Monitor{}, DB: db, }, CSAETHKeystore: keyStore, @@ -280,7 +282,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { ChainOpts: legacyevm.ChainOpts{ AppConfig: cfg, EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, + MailMon: &mailbox.Monitor{}, DB: db, }, CSAETHKeystore: keyStore, diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index a21029ea17..cfdf1eed11 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -21,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ( @@ -31,7 +31,7 @@ type ( pipelineORM pipeline.ORM chHeads chan *evmtypes.Head legacyChains legacyevm.LegacyChainContainer - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } Config interface { @@ -47,7 +47,7 @@ func NewDelegate( pipelineRunner pipeline.Runner, pipelineORM pipeline.ORM, legacyChains legacyevm.LegacyChainContainer, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ logger: logger.Named("DirectRequest"), @@ -101,8 +101,8 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { pipelineORM: d.pipelineORM, mailMon: d.mailMon, job: jb, - mbOracleRequests: utils.NewHighCapacityMailbox[log.Broadcast](), - mbOracleCancelRequests: utils.NewHighCapacityMailbox[log.Broadcast](), + mbOracleRequests: mailbox.NewHighCapacity[log.Broadcast](), + mbOracleCancelRequests: mailbox.NewHighCapacity[log.Broadcast](), minIncomingConfirmations: concreteSpec.MinIncomingConfirmations.Uint32, requesters: concreteSpec.Requesters, minContractPayment: concreteSpec.MinContractPayment, @@ -127,12 +127,12 @@ type listener struct { oracle operator_wrapper.OperatorInterface pipelineRunner pipeline.Runner pipelineORM pipeline.ORM - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor job job.Job runs sync.Map // map[string]services.StopChan shutdownWaitGroup sync.WaitGroup - mbOracleRequests *utils.Mailbox[log.Broadcast] - mbOracleCancelRequests *utils.Mailbox[log.Broadcast] + mbOracleRequests *mailbox.Mailbox[log.Broadcast] + mbOracleCancelRequests *mailbox.Mailbox[log.Broadcast] minIncomingConfirmations uint32 requesters models.AddressCollection minContractPayment *assets.Link @@ -238,7 +238,7 @@ func (l *listener) processCancelOracleRequests() { } } -func (l *listener) handleReceivedLogs(mailbox *utils.Mailbox[log.Broadcast]) { +func (l *listener) handleReceivedLogs(mailbox *mailbox.Mailbox[log.Broadcast]) { for { select { case <-l.chStop: diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 2d5b9bef03..865edb1b48 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -44,7 +45,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) relayerExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, MailMon: mailMon, KeyStore: keyStore.Eth()}) lggr := logger.TestLogger(t) @@ -81,7 +82,7 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi runner := pipeline_mocks.NewRunner(t) broadcaster.On("AddDependents", 1) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 5020537bf6..07bd82ed28 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -20,6 +20,7 @@ import ( decryptionPlugin "github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -44,7 +45,6 @@ import ( sync_mocks "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type FunctionsListenerUniverse struct { @@ -82,7 +82,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe ethClient := evmtest.NewEthClientMockWithDefaultChain(t) broadcaster := log_mocks.NewBroadcaster(t) broadcaster.On("AddDependents", 1) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db, cfg.Database()) diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 0223f1a10d..14a5c41b39 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -24,6 +24,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -45,7 +46,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" ) @@ -462,7 +462,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailbox.NewMonitor(t.Name())), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -496,7 +496,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailbox.NewMonitor(t.Name())), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -524,7 +524,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailbox.NewMonitor(t.Name())), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -579,7 +579,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailbox.NewMonitor(t.Name())), ) jb.OCROracleSpec.CaptureEATelemetry = tc.jbCaptureEATelemetry @@ -623,7 +623,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - servicetest.Run(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailbox.NewMonitor(t.Name())), ) services, err := sd.ServicesForSpec(*jb) require.NoError(t, err) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index d639ce859a..b82aa73c0b 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -128,7 +129,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA2 := mocks.NewServiceCtx(t) serviceA1.On("Start", mock.Anything).Return(nil).Once() serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyA.ItHappened() }) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) dA := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, make(chan struct{}), dA} @@ -187,7 +188,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -221,7 +222,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -299,7 +300,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { jobOCR2VRF := makeOCR2VRFJobSpec(t, keyStore, config, address, chain.ID(), 2) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }) ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), config.Database(), processConfig) diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index 0dbf584c56..4418bea670 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -5,12 +5,12 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // To make sure Delegate struct implements job.Delegate interface @@ -22,7 +22,7 @@ type Delegate struct { jrm job.ORM pr pipeline.Runner legacyChains legacyevm.LegacyChainContainer - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } // NewDelegate is the constructor of Delegate @@ -32,7 +32,7 @@ func NewDelegate( pr pipeline.Runner, logger logger.Logger, legacyChains legacyevm.LegacyChainContainer, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ logger: logger, diff --git a/core/services/keeper/registry_synchronizer_core.go b/core/services/keeper/registry_synchronizer_core.go index db7cca1763..f26c38fc2e 100644 --- a/core/services/keeper/registry_synchronizer_core.go +++ b/core/services/keeper/registry_synchronizer_core.go @@ -10,6 +10,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -28,7 +30,7 @@ type RegistrySynchronizerOptions struct { ORM ORM JRM job.ORM LogBroadcaster log.Broadcaster - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor SyncInterval time.Duration MinIncomingConfirmations uint32 Logger logger.Logger @@ -44,14 +46,14 @@ type RegistrySynchronizer struct { job job.Job jrm job.ORM logBroadcaster log.Broadcaster - mbLogs *utils.Mailbox[log.Broadcast] + mbLogs *mailbox.Mailbox[log.Broadcast] minIncomingConfirmations uint32 effectiveKeeperAddress common.Address orm ORM logger logger.SugaredLogger wgDone sync.WaitGroup syncUpkeepQueueSize uint32 //Represents the max number of upkeeps that can be synced in parallel - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } // NewRegistrySynchronizer is the constructor of RegistrySynchronizer @@ -63,7 +65,7 @@ func NewRegistrySynchronizer(opts RegistrySynchronizerOptions) *RegistrySynchron job: opts.Job, jrm: opts.JRM, logBroadcaster: opts.LogBroadcaster, - mbLogs: utils.NewMailbox[log.Broadcast](5_000), // Arbitrary limit, better to have excess capacity + mbLogs: mailbox.New[log.Broadcast](5_000), // Arbitrary limit, better to have excess capacity minIncomingConfirmations: opts.MinIncomingConfirmations, orm: opts.ORM, effectiveKeeperAddress: opts.EffectiveKeeperAddress, diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index 5ba60db396..dff97202f6 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -11,6 +11,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -23,7 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const syncInterval = 1000 * time.Hour // prevents sync timer from triggering during test @@ -73,7 +73,7 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( })).Maybe().Return(func() {}) lbMock.On("IsConnected").Return(true).Maybe() - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) orm := keeper.NewORM(db, logger.TestLogger(t), ch.Config().Database()) synchronizer := keeper.NewRegistrySynchronizer(keeper.RegistrySynchronizerOptions{ diff --git a/core/services/keeper/upkeep_executer.go b/core/services/keeper/upkeep_executer.go index 84349ba2dc..bab2f73edf 100644 --- a/core/services/keeper/upkeep_executer.go +++ b/core/services/keeper/upkeep_executer.go @@ -13,6 +13,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -23,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -62,7 +63,7 @@ type UpkeepExecuter struct { headBroadcaster httypes.HeadBroadcasterRegistry gasEstimator gas.EvmFeeEstimator job job.Job - mailbox *utils.Mailbox[*evmtypes.Head] + mailbox *mailbox.Mailbox[*evmtypes.Head] orm ORM pr pipeline.Runner logger logger.Logger @@ -89,7 +90,7 @@ func NewUpkeepExecuter( headBroadcaster: headBroadcaster, gasEstimator: gasEstimator, job: job, - mailbox: utils.NewSingleMailbox[*evmtypes.Head](), + mailbox: mailbox.NewSingle[*evmtypes.Head](), config: config, orm: orm, pr: pr, diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 4f79bcfc31..1287e52e9b 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -21,6 +21,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/config" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -31,7 +32,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // configMailboxSanityLimit is the maximum number of configs that can be held @@ -67,7 +67,7 @@ type ( q pg.Q blockTranslator ocrcommon.BlockTranslator cfg ocrcommon.Config - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor // HeadBroadcaster headBroadcaster httypes.HeadBroadcaster @@ -83,7 +83,7 @@ type ( lrrMu sync.RWMutex // ContractConfig - configsMB *utils.Mailbox[ocrtypes.ContractConfig] + configsMB *mailbox.Mailbox[ocrtypes.ContractConfig] chConfigs chan ocrtypes.ContractConfig // LatestBlockHeight @@ -117,7 +117,7 @@ func NewOCRContractTracker( cfg ocrcommon.Config, q pg.QConfig, headBroadcaster httypes.HeadBroadcaster, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) (o *OCRContractTracker) { logger = logger.Named("OCRContractTracker") return &OCRContractTracker{ @@ -136,7 +136,7 @@ func NewOCRContractTracker( headBroadcaster: headBroadcaster, chStop: make(services.StopChan), latestRoundRequested: offchainaggregator.OffchainAggregatorRoundRequested{}, - configsMB: utils.NewMailbox[ocrtypes.ContractConfig](configMailboxSanityLimit), + configsMB: mailbox.New[ocrtypes.ContractConfig](configMailboxSanityLimit), chConfigs: make(chan ocrtypes.ContractConfig), latestBlockHeight: -1, } diff --git a/core/services/ocr/contract_tracker_test.go b/core/services/ocr/contract_tracker_test.go index af65f330d6..f7ebbe0848 100644 --- a/core/services/ocr/contract_tracker_test.go +++ b/core/services/ocr/contract_tracker_test.go @@ -16,6 +16,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -31,7 +32,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" ocrmocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func mustNewContract(t *testing.T, address gethCommon.Address) *offchain_aggregator_wrapper.OffchainAggregator { @@ -84,7 +84,7 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack uni.hb = commonmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) uni.ec = evmtest.NewEthClientMock(t) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) db := pgtest.NewSqlxDB(t) uni.tracker = ocr.NewOCRContractTracker( contract, diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index d3d133e712..0eed680a3d 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocr "github.com/smartcontractkit/libocr/offchainreporting" @@ -43,7 +44,7 @@ type Delegate struct { legacyChains legacyevm.LegacyChainContainer lggr logger.Logger cfg Config - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } var _ job.Delegate = (*Delegate)(nil) @@ -60,7 +61,7 @@ func NewDelegate( legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, cfg Config, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ db: db, diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 16f02282af..5200866e3a 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -34,6 +34,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -70,7 +71,6 @@ import ( evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -116,7 +116,7 @@ type Delegate struct { ethKs keystore.Eth RelayGetter isNewlyCreatedJob bool // Set to true if this is a new job freshly added, false if job was present already on node boot. - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor legacyChains legacyevm.LegacyChainContainer // legacy: use relayers instead } @@ -226,7 +226,7 @@ func NewDelegate( dkgEncryptKs keystore.DKGEncrypt, ethKs keystore.Eth, relayers RelayGetter, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, eventBroadcaster pg.EventBroadcaster, ) *Delegate { return &Delegate{ diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 61fa7f5d82..7e2b15bdcc 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -14,6 +14,7 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -43,7 +44,7 @@ type FunctionsServicesConfig struct { Chain legacyevm.Chain ContractID string Logger logger.Logger - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor URLsMonEndpoint commontypes.MonitoringEndpoint EthKeystore keystore.Eth ThresholdKeyShare []byte diff --git a/core/services/pipeline/task.eth_tx.go b/core/services/pipeline/task.eth_tx.go index c421b340c9..58e9f6f2c1 100644 --- a/core/services/pipeline/task.eth_tx.go +++ b/core/services/pipeline/task.eth_tx.go @@ -13,11 +13,11 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index a0ff54d444..5f5019d196 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -19,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" keystoremocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" diff --git a/core/services/promreporter/prom_reporter.go b/core/services/promreporter/prom_reporter.go index 3e1444a6da..a302a6fa22 100644 --- a/core/services/promreporter/prom_reporter.go +++ b/core/services/promreporter/prom_reporter.go @@ -17,10 +17,11 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name PrometheusBackend --output ../../internal/mocks/ --case=underscore @@ -31,7 +32,7 @@ type ( chains legacyevm.LegacyChainContainer lggr logger.Logger backend PrometheusBackend - newHeads *utils.Mailbox[*evmtypes.Head] + newHeads *mailbox.Mailbox[*evmtypes.Head] chStop services.StopChan wgDone sync.WaitGroup reportPeriod time.Duration @@ -109,7 +110,7 @@ func NewPromReporter(db *sql.DB, chainContainer legacyevm.LegacyChainContainer, chains: chainContainer, lggr: lggr.Named("PromReporter"), backend: backend, - newHeads: utils.NewSingleMailbox[*evmtypes.Head](), + newHeads: mailbox.NewSingle[*evmtypes.Head](), chStop: chStop, reportPeriod: period, } diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index a13df71d9a..03e40614a1 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -29,7 +30,6 @@ import ( v1 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v1" v2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type Delegate struct { @@ -39,7 +39,7 @@ type Delegate struct { ks keystore.Master legacyChains legacyevm.LegacyChainContainer lggr logger.Logger - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } func NewDelegate( @@ -50,7 +50,7 @@ func NewDelegate( legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, cfg pg.QConfig, - mailMon *utils.MailboxMonitor) *Delegate { + mailMon *mailbox.Monitor) *Delegate { return &Delegate{ q: pg.NewQ(db, lggr, cfg), ks: ks, @@ -250,7 +250,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { MailMon: d.mailMon, // Note the mailbox size effectively sets a limit on how many logs we can replay // in the event of a VRF outage. - ReqLogs: utils.NewHighCapacityMailbox[log.Broadcast](), + ReqLogs: mailbox.NewHighCapacity[log.Broadcast](), ChStop: make(chan struct{}), WaitOnStop: make(chan struct{}), NewHead: make(chan struct{}, 1), diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index d957e3c721..3b643d19b0 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -149,7 +150,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { cfg := configtest.NewTestGeneralConfig(t) vuni := buildVrfUni(t, db, cfg) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) vd := vrf.NewDelegate( db, @@ -673,7 +674,7 @@ func Test_VRFV2PlusServiceFailsWhenVRFOwnerProvided(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) vuni := buildVrfUni(t, db, cfg) - mailMon := servicetest.Run(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailbox.NewMonitor(t.Name())) vd := vrf.NewDelegate( db, diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 66a8ddcd58..f4e813d7d6 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -17,6 +17,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -57,8 +58,8 @@ type Listener struct { Job job.Job Q pg.Q GethKs vrfcommon.GethKeyStore - MailMon *utils.MailboxMonitor - ReqLogs *utils.Mailbox[log.Broadcast] + MailMon *mailbox.Monitor + ReqLogs *mailbox.Mailbox[log.Broadcast] ChStop services.StopChan WaitOnStop chan struct{} NewHead chan struct{} diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 5878bf5476..6556bbd218 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -14,6 +14,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-common/pkg/services" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 6192db95df..d8bc0a6695 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -17,6 +17,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -28,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/utils/mailbox.go b/core/utils/mailbox.go deleted file mode 100644 index 87fe1627f3..0000000000 --- a/core/utils/mailbox.go +++ /dev/null @@ -1,126 +0,0 @@ -package utils - -import ( - "sync" - "sync/atomic" -) - -// Mailbox contains a notify channel, -// a mutual exclusive lock, -// a queue of interfaces, -// and a queue capacity. -type Mailbox[T any] struct { - mu sync.Mutex - chNotify chan struct{} - queue []T - queueLen atomic.Int64 // atomic so monitor can read w/o blocking the queue - - // capacity - number of items the mailbox can buffer - // NOTE: if the capacity is 1, it's possible that an empty Retrieve may occur after a notification. - capacity uint64 - // onCloseFn is a hook used to stop monitoring, if non-nil - onCloseFn func() -} - -// NewHighCapacityMailbox create a new mailbox with a capacity -// that is better able to handle e.g. large log replays. -func NewHighCapacityMailbox[T any]() *Mailbox[T] { - return NewMailbox[T](100_000) -} - -// NewSingleMailbox returns a new Mailbox with capacity one. -func NewSingleMailbox[T any]() *Mailbox[T] { return NewMailbox[T](1) } - -// NewMailbox creates a new mailbox instance. If name is non-empty, it must be unique and calling Start will launch -// prometheus metric monitor that periodically reports mailbox load until Close() is called. -func NewMailbox[T any](capacity uint64) *Mailbox[T] { - queueCap := capacity - if queueCap == 0 { - queueCap = 100 - } - return &Mailbox[T]{ - chNotify: make(chan struct{}, 1), - queue: make([]T, 0, queueCap), - capacity: capacity, - } -} - -// Notify returns the contents of the notify channel -func (m *Mailbox[T]) Notify() <-chan struct{} { - return m.chNotify -} - -func (m *Mailbox[T]) Close() error { - if m.onCloseFn != nil { - m.onCloseFn() - } - return nil -} - -func (m *Mailbox[T]) onClose(fn func()) { m.onCloseFn = fn } - -func (m *Mailbox[T]) load() (capacity uint64, loadPercent float64) { - capacity = m.capacity - loadPercent = 100 * float64(m.queueLen.Load()) / float64(capacity) - return -} - -// Deliver appends to the queue and returns true if the queue was full, causing a message to be dropped. -func (m *Mailbox[T]) Deliver(x T) (wasOverCapacity bool) { - m.mu.Lock() - defer m.mu.Unlock() - - m.queue = append([]T{x}, m.queue...) - if uint64(len(m.queue)) > m.capacity && m.capacity > 0 { - m.queue = m.queue[:len(m.queue)-1] - wasOverCapacity = true - } else { - m.queueLen.Add(1) - } - - select { - case m.chNotify <- struct{}{}: - default: - } - return -} - -// Retrieve fetches one element from the queue. -func (m *Mailbox[T]) Retrieve() (t T, ok bool) { - m.mu.Lock() - defer m.mu.Unlock() - if len(m.queue) == 0 { - return - } - t = m.queue[len(m.queue)-1] - m.queue = m.queue[:len(m.queue)-1] - m.queueLen.Add(-1) - ok = true - return -} - -// RetrieveAll fetches all elements from the queue. -func (m *Mailbox[T]) RetrieveAll() []T { - m.mu.Lock() - defer m.mu.Unlock() - queue := m.queue - m.queue = nil - m.queueLen.Store(0) - for i, j := 0, len(queue)-1; i < j; i, j = i+1, j-1 { - queue[i], queue[j] = queue[j], queue[i] - } - return queue -} - -// RetrieveLatestAndClear fetch the latest value (or nil), and clears the rest of the queue (if any). -func (m *Mailbox[T]) RetrieveLatestAndClear() (t T) { - m.mu.Lock() - defer m.mu.Unlock() - if len(m.queue) == 0 { - return - } - t = m.queue[0] - m.queue = nil - m.queueLen.Store(0) - return -} diff --git a/core/utils/mailbox_prom.go b/core/utils/mailbox_prom.go deleted file mode 100644 index 33cbb2357b..0000000000 --- a/core/utils/mailbox_prom.go +++ /dev/null @@ -1,93 +0,0 @@ -package utils - -import ( - "context" - "strconv" - "strings" - "sync" - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - - "github.com/smartcontractkit/chainlink-common/pkg/services" -) - -var mailboxLoad = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Name: "mailbox_load_percent", - Help: "Percent of mailbox capacity used", -}, - []string{"appID", "name", "capacity"}, -) - -const mailboxPromInterval = 5 * time.Second - -type MailboxMonitor struct { - services.StateMachine - appID string - - mailboxes sync.Map - stop func() - done chan struct{} -} - -func NewMailboxMonitor(appID string) *MailboxMonitor { - return &MailboxMonitor{appID: appID} -} - -func (m *MailboxMonitor) Name() string { return "MailboxMonitor" } - -func (m *MailboxMonitor) Start(context.Context) error { - return m.StartOnce("MailboxMonitor", func() error { - t := time.NewTicker(WithJitter(mailboxPromInterval)) - ctx, cancel := context.WithCancel(context.Background()) - m.stop = func() { - t.Stop() - cancel() - } - m.done = make(chan struct{}) - go m.monitorLoop(ctx, t.C) - return nil - }) -} - -func (m *MailboxMonitor) Close() error { - return m.StopOnce("MailboxMonitor", func() error { - m.stop() - <-m.done - return nil - }) -} - -func (m *MailboxMonitor) HealthReport() map[string]error { - return map[string]error{m.Name(): m.Healthy()} -} - -func (m *MailboxMonitor) monitorLoop(ctx context.Context, c <-chan time.Time) { - defer close(m.done) - for { - select { - case <-ctx.Done(): - return - case <-c: - m.mailboxes.Range(func(k, v any) bool { - name, mb := k.(string), v.(mailbox) - c, p := mb.load() - capacity := strconv.FormatUint(c, 10) - mailboxLoad.WithLabelValues(m.appID, name, capacity).Set(p) - return true - }) - } - } -} - -type mailbox interface { - load() (capacity uint64, percent float64) - onClose(func()) -} - -func (m *MailboxMonitor) Monitor(mb mailbox, name ...string) { - n := strings.Join(name, ".") - m.mailboxes.Store(n, mb) - mb.onClose(func() { m.mailboxes.Delete(n) }) -} diff --git a/core/utils/mailbox_test.go b/core/utils/mailbox_test.go deleted file mode 100644 index c83d0035ba..0000000000 --- a/core/utils/mailbox_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package utils - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestMailbox(t *testing.T) { - var ( - expected = []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - toDeliver = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - ) - - const capacity = 10 - m := NewMailbox[int](capacity) - - // Queue deliveries - for i, d := range toDeliver { - atCapacity := m.Deliver(d) - if atCapacity && i < capacity { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= capacity { - t.Errorf("mailbox below capacity %d", i) - } - } - - // Retrieve them - var recvd []int - chDone := make(chan struct{}) - go func() { - defer close(chDone) - for range m.Notify() { - for { - x, exists := m.Retrieve() - if !exists { - break - } - recvd = append(recvd, x) - } - } - }() - - close(m.chNotify) - <-chDone - - require.Equal(t, expected, recvd) -} - -func TestMailbox_RetrieveAll(t *testing.T) { - var ( - expected = []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - toDeliver = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - ) - - const capacity = 10 - m := NewMailbox[int](capacity) - - // Queue deliveries - for i, d := range toDeliver { - atCapacity := m.Deliver(d) - if atCapacity && i < capacity { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= capacity { - t.Errorf("mailbox below capacity %d", i) - } - } - - require.Equal(t, expected, m.RetrieveAll()) -} - -func TestMailbox_RetrieveLatestAndClear(t *testing.T) { - var ( - expected = 11 - toDeliver = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - ) - - const capacity = 10 - m := NewMailbox[int](capacity) - - // Queue deliveries - for i, d := range toDeliver { - atCapacity := m.Deliver(d) - if atCapacity && i < capacity { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= capacity { - t.Errorf("mailbox below capacity %d", i) - } - } - - require.Equal(t, expected, m.RetrieveLatestAndClear()) - require.Len(t, m.RetrieveAll(), 0) -} - -func TestMailbox_NoEmptyReceivesWhenCapacityIsTwo(t *testing.T) { - m := NewMailbox[int](2) - - var ( - recvd []int - emptyReceives []int - ) - - chDone := make(chan struct{}) - go func() { - defer close(chDone) - for range m.Notify() { - x, exists := m.Retrieve() - if !exists { - emptyReceives = append(emptyReceives, recvd[len(recvd)-1]) - } else { - recvd = append(recvd, x) - } - } - }() - - for i := 0; i < 100000; i++ { - m.Deliver(i) - } - close(m.chNotify) - - <-chDone - require.Len(t, emptyReceives, 0) -} - -func TestMailbox_load(t *testing.T) { - for _, tt := range []struct { - name string - capacity uint64 - deliver []int - exp float64 - - retrieve int - exp2 float64 - - all bool - }{ - {"single-all", 1, []int{1}, 100, 0, 100, true}, - {"single-latest", 1, []int{1}, 100, 0, 100, false}, - {"ten-low", 10, []int{1}, 10, 1, 0.0, false}, - {"ten-full-all", 10, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 100, 5, 50, true}, - {"ten-full-latest", 10, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 100, 5, 50, false}, - {"ten-overflow", 10, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 100, 5, 50, false}, - {"nine", 9, []int{1, 2, 3}, 100.0 / 3.0, 2, 100.0 / 9.0, true}, - } { - t.Run(tt.name, func(t *testing.T) { - m := NewMailbox[int](tt.capacity) - - // Queue deliveries - for i, d := range tt.deliver { - atCapacity := m.Deliver(d) - if atCapacity && i < int(tt.capacity) { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= int(tt.capacity) { - t.Errorf("mailbox below capacity %d", i) - } - } - gotCap, gotLoad := m.load() - require.Equal(t, gotCap, tt.capacity) - require.Equal(t, gotLoad, tt.exp) - - // Retrieve some - for i := 0; i < tt.retrieve; i++ { - _, ok := m.Retrieve() - require.True(t, ok) - } - gotCap, gotLoad = m.load() - require.Equal(t, gotCap, tt.capacity) - require.Equal(t, gotLoad, tt.exp2) - - // Drain it - if tt.all { - m.RetrieveAll() - } else { - m.RetrieveLatestAndClear() - } - gotCap, gotLoad = m.load() - require.Equal(t, gotCap, tt.capacity) - require.Equal(t, gotLoad, 0.0) - }) - } -} diff --git a/core/utils/utils.go b/core/utils/utils.go index b887fe9a80..4f3f921233 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -27,7 +27,6 @@ import ( "github.com/robfig/cron/v3" "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/sha3" - "golang.org/x/exp/constraints" ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" @@ -879,26 +878,6 @@ func TryParseHex(s string) (b []byte, err error) { return } -// MinKey returns the minimum value of the given element array with respect -// to the given key function. In the event U is not a compound type (e.g a -// struct) an identity function can be provided. -func MinKey[U any, T constraints.Ordered](elems []U, key func(U) T) T { - var min T - if len(elems) == 0 { - return min - } - - min = key(elems[0]) - for i := 1; i < len(elems); i++ { - v := key(elems[i]) - if v < min { - min = v - } - } - - return min -} - // ErrorBuffer uses joinedErrors interface to join multiple errors into a single error. // This is useful to track the most recent N errors in a service and flush them as a single error. type ErrorBuffer struct { From cf74cd0c9e9601c213b03c9d076339464a634291 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Tue, 12 Dec 2023 11:50:40 -0300 Subject: [PATCH 299/327] Use multiple EL clients with ocrv2 median smoke test (#11399) * use multiple EL clients with ocrv2 median test * update ethereum network component to latest * try with latest implementation of eth clients * change WithTestLogger() to WithTestInstance() * fix geth backward compatibility * run ocrv2 eth2 tests in parallel * run also ocr1 and 2 vrf tests iwth multiple clients * try running multipl el client tests in parallel * fix go.sum * fix lint * 1. add matrix for running 4 smoke tests on different execution clients, 2. if for these tests no client is set in env var use geth * comment out failing nethermind & besu vrf tests in the CI * fix go.sum * do not use negative lookahead with go test * use faster eth2 network config * add comment to integration tests workflow * run only OCR and OCRv2 jobs with multiple clients, add on-demand jobs for VRF * use latest ctf with increased network timeout * slow down private eth networks a bit * update CTF dep to tagged version * disable nethermind ocr smoke tests in CI * fix compilation errors --- .github/workflows/integration-tests.yml | 67 +++++++++++++++++- .../on-demand-vrfv2-eth2-clients-test.yml | 70 +++++++++++++++++++ .../on-demand-vrfv2plus-eth2-clients-test.yml | 70 +++++++++++++++++++ .gitignore | 2 +- integration-tests/actions/private_network.go | 33 +++++++++ integration-tests/docker/test_env/cl_node.go | 2 +- integration-tests/docker/test_env/test_env.go | 6 +- .../docker/test_env/test_env_builder.go | 10 ++- integration-tests/go.mod | 2 +- integration-tests/go.sum | 5 +- integration-tests/load/vrfv2/vrfv2_test.go | 4 +- .../load/vrfv2plus/vrfv2plus_test.go | 4 +- .../migration/upgrade_version_test.go | 2 +- integration-tests/smoke/automation_test.go | 4 +- integration-tests/smoke/cron_test.go | 4 +- integration-tests/smoke/flux_test.go | 2 +- integration-tests/smoke/forwarder_ocr_test.go | 2 +- .../smoke/forwarders_ocr2_test.go | 2 +- integration-tests/smoke/keeper_test.go | 2 +- integration-tests/smoke/ocr2_test.go | 10 ++- integration-tests/smoke/ocr_test.go | 9 ++- integration-tests/smoke/runlog_test.go | 2 +- integration-tests/smoke/vrf_test.go | 4 +- integration-tests/smoke/vrfv2_test.go | 11 +-- integration-tests/smoke/vrfv2plus_test.go | 14 ++-- .../universal/log_poller/helpers.go | 5 +- 26 files changed, 303 insertions(+), 45 deletions(-) create mode 100644 .github/workflows/on-demand-vrfv2-eth2-clients-test.yml create mode 100644 .github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml create mode 100644 integration-tests/actions/private_network.go diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 37a2718be4..6ffd1a14ff 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -325,11 +325,73 @@ jobs: - name: ocr nodes: 1 os: ubuntu20.04-8cores-32GB + run: -run TestOCRJobReplacement + file: ocr pyroscope_env: ci-smoke-ocr-evm-simulated + - name: ocr-geth + nodes: 1 + os: ubuntu20.04-8cores-32GB + run: -run TestOCRBasic + file: ocr + client: geth + pyroscope_env: ci-smoke-ocr-evm-simulated + # Uncomment, when https://smartcontract-it.atlassian.net/browse/TT-753 is DONE + # - name: ocr-nethermind + # nodes: 1 + # os: ubuntu20.04-8cores-32GB + # run: -run TestOCRBasic + # file: ocr + # client: nethermind + # pyroscope_env: ci-smoke-ocr-evm-simulated + - name: ocr-besu + nodes: 1 + os: ubuntu20.04-8cores-32GB + run: -run TestOCRBasic + file: ocr + client: besu + pyroscope_env: ci-smoke-ocr-evm-simulated + - name: ocr-erigon + nodes: 1 + os: ubuntu20.04-8cores-32GB + run: -run TestOCRBasic + file: ocr + client: erigon + pyroscope_env: ci-smoke-ocr-evm-simulated - name: ocr2 nodes: 1 os: ubuntu20.04-8cores-32GB + run: -run TestOCRv2JobReplacement + file: ocr2 pyroscope_env: ci-smoke-ocr2-evm-simulated + - name: ocr2-geth + nodes: 1 + os: ubuntu20.04-8cores-32GB + run: -run TestOCRv2Basic + file: ocr2 + client: geth + pyroscope_env: ci-smoke-ocr2-evm-simulated + # Uncomment, when https://smartcontract-it.atlassian.net/browse/TT-753 is DONE + # - name: ocr2-nethermind + # nodes: 1 + # os: ubuntu20.04-8cores-32GB + # run: -run TestOCRv2Basic + # file: ocr2 + # client: nethermind + # pyroscope_env: ci-smoke-ocr2-evm-simulated + - name: ocr2-besu + nodes: 1 + os: ubuntu20.04-8cores-32GB + run: -run TestOCRv2Basic + file: ocr2 + client: besu + pyroscope_env: ci-smoke-ocr2-evm-simulated + - name: ocr2-erigon + nodes: 1 + os: ubuntu20.04-8cores-32GB + run: -run TestOCRv2Basic + file: ocr2 + client: erigon + pyroscope_env: ci-smoke-ocr2-evm-simulated - name: ocr2 nodes: 1 os: ubuntu20.04-8cores-32GB @@ -345,12 +407,14 @@ jobs: pyroscope_env: ci-smoke-vrf-evm-simulated - name: vrfv2 nodes: 1 + run: -run TestVRFv2MultipleSendingKeys + file: vrfv2 os: ubuntu20.04-8cores-32GB pyroscope_env: ci-smoke-vrf2-evm-simulated - name: vrfv2plus nodes: 1 os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-vrf2plus-evm-simulated + pyroscope_env: ci-smoke-vrf2plus-evm-simulated - name: forwarder_ocr nodes: 1 os: ubuntu20.04-8cores-32GB @@ -435,6 +499,7 @@ jobs: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + ETH2_EL_CLIENT: ${{matrix.product.client}} LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }} LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} diff --git a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml new file mode 100644 index 0000000000..3b27e4519c --- /dev/null +++ b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml @@ -0,0 +1,70 @@ +name: On Demand VRFV2 Smoke Test (Ethereum clients) +on: + workflow_dispatch: + inputs: + client: + description: Execution client to use + type: choice + options: + - "geth" + - "nethermind" + - "besu" + - "erigon" + chainlinkImage: + description: Container image location for the Chainlink nodes + required: true + default: public.ecr.aws/chainlink/chainlink + chainlinkVersion: + description: Container image version for the Chainlink nodes + required: true + default: "2.6.0" + configBase64: + description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) + required: false +jobs: + vrfv2_smoke_test: + name: VRFV2 Smoke Test with ${{ inputs.client }} client + environment: integration + runs-on: ubuntu20.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + env: + SELECTED_NETWORKS: "SIMULATED" + CONFIG: ${{ inputs.configBase64 }} + TEST_LOG_LEVEL: debug + REF_NAME: ${{ github.head_ref || github.ref_name }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + steps: + - name: Setup Push Tag + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run TestVRFv2Basic ./smoke/vrfv2_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ inputs.chainlinkImage }} + cl_image_tag: ${{ inputs.chainlinkVersion }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrf-test-logs + artifacts_location: ./integration-tests/smoke/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: "" + env: + ETH2_EL_CLIENT: ${{ inputs.client }} diff --git a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml new file mode 100644 index 0000000000..331c626ba9 --- /dev/null +++ b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml @@ -0,0 +1,70 @@ +name: On Demand VRFV2Plus Smoke Test (Ethereum clients) +on: + workflow_dispatch: + inputs: + client: + description: Execution client to use + type: choice + options: + - "geth" + - "nethermind" + - "besu" + - "erigon" + chainlinkImage: + description: Container image location for the Chainlink nodes + required: true + default: public.ecr.aws/chainlink/chainlink + chainlinkVersion: + description: Container image version for the Chainlink nodes + required: true + default: "2.6.0" + configBase64: + description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) + required: false +jobs: + vrfv2plus_smoke_test: + name: VRFV2Plus Smoke Test with ${{ inputs.client }} client + environment: integration + runs-on: ubuntu20.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + env: + SELECTED_NETWORKS: "SIMULATED" + CONFIG: ${{ inputs.configBase64 }} + TEST_LOG_LEVEL: debug + REF_NAME: ${{ github.head_ref || github.ref_name }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + steps: + - name: Setup Push Tag + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run ^TestVRFv2Plus$/^Link_Billing$ ./smoke/vrfv2plus_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ inputs.chainlinkImage }} + cl_image_tag: ${{ inputs.chainlinkVersion }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrfplus-test-logs + artifacts_location: ./integration-tests/smoke/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: "" + env: + ETH2_EL_CLIENT: ${{ inputs.client }} diff --git a/.gitignore b/.gitignore index 8d127dbb72..2f68ec2c94 100644 --- a/.gitignore +++ b/.gitignore @@ -84,4 +84,4 @@ go.work* tools/flakeytests/coverage.txt .test_summary/ -.run.id \ No newline at end of file +.run.id diff --git a/integration-tests/actions/private_network.go b/integration-tests/actions/private_network.go new file mode 100644 index 0000000000..c7556f8061 --- /dev/null +++ b/integration-tests/actions/private_network.go @@ -0,0 +1,33 @@ +package actions + +import ( + "errors" + + "github.com/rs/zerolog" + + ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" +) + +func EthereumNetworkConfigFromEnvOrDefault(l zerolog.Logger) (network ctf_test_env.EthereumNetwork, err error) { + chainConfig := ctf_test_env.EthereumChainConfig{ + SecondsPerSlot: 8, + SlotsPerEpoch: 4, + } + + ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() + network, err = ethBuilder. + WithExecClientFromEnvVar(). + WithEthereumChainConfig(chainConfig). + Build() + + if errors.Is(err, ctf_test_env.ErrMissingExecClientEnvVar) { + l.Warn().Msg("No exec client env var set, will use old geth") + ethBuilder = ctf_test_env.NewEthereumNetworkBuilder() + network, err = ethBuilder. + WithConsensusType(ctf_test_env.ConsensusType_PoW). + WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). + Build() + } + + return +} diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 6039425633..b79bb91c70 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -112,7 +112,7 @@ func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *ch func (n *ClNode) SetTestLogger(t *testing.T) { n.l = logging.GetTestLogger(t) n.t = t - n.PostgresDb.WithTestLogger(t) + n.PostgresDb.WithTestInstance(t) } // Restart restarts only CL node, DB container is reused diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 15bf6641bf..20e231e598 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -71,11 +71,11 @@ func (te *CLClusterTestEnv) WithTestEnvConfig(cfg *TestEnvConfig) *CLClusterTest return te } -func (te *CLClusterTestEnv) WithTestLogger(t *testing.T) *CLClusterTestEnv { +func (te *CLClusterTestEnv) WithTestInstance(t *testing.T) *CLClusterTestEnv { te.t = t te.l = logging.GetTestLogger(t) if te.MockAdapter != nil { - te.MockAdapter.WithTestLogger(t) + te.MockAdapter.WithTestInstance(t) } return te } @@ -90,7 +90,7 @@ func (te *CLClusterTestEnv) WithPrivateChain(evmNetworks []blockchain.EVMNetwork n := evmNetwork pgc := test_env.NewPrivateGethChain(&n, []string{te.Network.Name}) if te.t != nil { - pgc.GetPrimaryNode().WithTestLogger(te.t) + pgc.GetPrimaryNode().WithTestInstance(te.t) } chains = append(chains, pgc) var privateChain test_env.PrivateChain diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index cc0499ea0c..7358d76f2a 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -95,7 +95,7 @@ func (b *CLTestEnvBuilder) WithTestEnv(te *CLClusterTestEnv) (*CLTestEnvBuilder, // WithTestLogger sets the test logger to use for the test. // Useful for parallel tests so the logging will be separated correctly in the results views. -func (b *CLTestEnvBuilder) WithTestLogger(t *testing.T) *CLTestEnvBuilder { +func (b *CLTestEnvBuilder) WithTestInstance(t *testing.T) *CLTestEnvBuilder { b.t = t b.l = logging.GetTestLogger(t) return b @@ -220,8 +220,12 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } var err error + if b.t != nil { + b.te.WithTestInstance(b.t) + } + if b.hasLogStream { - b.te.LogStream, err = logstream.NewLogStream(b.t, nil) + b.te.LogStream, err = logstream.NewLogStream(b.te.t, nil) if err != nil { return nil, err } @@ -241,7 +245,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } if b.t != nil { - b.te.WithTestLogger(b.t) + b.te.WithTestInstance(b.t) } switch b.cleanUpType { diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 72c15a8966..c080f61755 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -25,7 +25,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad - github.com/smartcontractkit/chainlink-testing-framework v1.21.0 + github.com/smartcontractkit/chainlink-testing-framework v1.22.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 494e5c21ec..e8cefd67d6 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1411,6 +1411,7 @@ github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMT github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= @@ -1444,8 +1445,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= -github.com/smartcontractkit/chainlink-testing-framework v1.21.0 h1:MrtpGMgPpcRX06FtDEj14Vokoo6Sx8e0/D6AA9LxCgM= -github.com/smartcontractkit/chainlink-testing-framework v1.21.0/go.mod h1:9SCqZ+lcWZNEofpPgasQ+wUF6A6fFgZvWmhqQJwFYV0= +github.com/smartcontractkit/chainlink-testing-framework v1.22.0 h1:Lur628wkrceWgcLmxGZe7Mauwxht4YO71hX9Jj5YslE= +github.com/smartcontractkit/chainlink-testing-framework v1.22.0/go.mod h1:yu6qqrppNJfutQV37fiSs4eS0uQP5QT0ebi3tlIgWN0= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 8a0faeabb2..86f9b8d61f 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -87,7 +87,7 @@ func TestVRFV2Performance(t *testing.T) { vrfv2Config.KeyHash = cfg.ExistingEnvConfig.KeyHash env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithCustomCleanup( func() { teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2Config) @@ -156,7 +156,7 @@ func TestVRFV2Performance(t *testing.T) { vrfv2Config.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeSendingKeyFunding vrfv2Config.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 68c1012987..6fe0d06e7d 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -89,7 +89,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusConfig.KeyHash = cfg.ExistingEnvConfig.KeyHash env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithCustomCleanup( func() { teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) @@ -162,7 +162,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.NewEnvConfig.Funding.SubFundsNative env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index d1f07a52b7..97db2374bf 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -13,7 +13,7 @@ import ( func TestVersionUpgrade(t *testing.T) { t.Parallel() env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). Build() diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index bc9f130845..1dbfc78ec8 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -1092,7 +1092,7 @@ func setupAutomationTestDocker( clNodesCount := 5 if isMercuryV02 || isMercuryV03 { env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). @@ -1129,7 +1129,7 @@ func setupAutomationTestDocker( } else { env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodes(clNodesCount). diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 3eebc19f8b..751c286767 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -20,7 +20,7 @@ func TestCronBasic(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodes(1). @@ -67,7 +67,7 @@ func TestCronJobReplacement(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodes(1). diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 5b35b0d248..828350a942 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -26,7 +26,7 @@ func TestFluxBasic(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodes(3). diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index 923ca046ec..c71c6e3151 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -19,7 +19,7 @@ func TestForwarderOCRBasic(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithForwarders(). diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index bdfd65c767..c2e2b12e51 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -24,7 +24,7 @@ func TestForwarderOCR2Basic(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 336223b7a4..1bc416f045 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1107,7 +1107,7 @@ func setupKeeperTest(t *testing.T) ( clNodeConfig.Keeper.Registry.PerformGasOverhead = &performGasOverhead env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(5). WithCLNodeConfig(clNodeConfig). diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 8f0fbd7605..a1a37c3b18 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -19,11 +19,15 @@ import ( // Tests a basic OCRv2 median feed func TestOCRv2Basic(t *testing.T) { + t.Parallel() l := logging.GetTestLogger(t) + network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), @@ -97,7 +101,7 @@ func TestOCRv2JobReplacement(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 25192248c4..ba15892381 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -17,9 +17,12 @@ func TestOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodes(6). WithFunding(big.NewFloat(.5)). @@ -66,7 +69,7 @@ func TestOCRJobReplacement(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodes(6). diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index 2fc771fb9b..5cc21a28c2 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -23,7 +23,7 @@ func TestRunLogBasic(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithMockAdapter(). WithCLNodes(1). diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 0412005374..0554bd3476 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -24,7 +24,7 @@ func TestVRFBasic(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). @@ -114,7 +114,7 @@ func TestVRFJobReplacement(t *testing.T) { l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 9976de0395..a8edb2c51d 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -24,13 +24,16 @@ func TestVRFv2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) + require.NoError(t, err, "Error building ethereum network config") + var vrfv2Config vrfv2_config.VRFV2Config - err := envconfig.Process("VRFV2", &vrfv2Config) + err = envconfig.Process("VRFV2", &vrfv2Config) require.NoError(t, err) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithPrivateEthereumNetwork(network). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). WithStandardCleanup(). @@ -121,7 +124,7 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { require.NoError(t, err) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 69e1eb7ebd..a850cb4fe1 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -29,13 +29,16 @@ func TestVRFv2Plus(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) + require.NoError(t, err, "Error building ethereum network config") + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) require.NoError(t, err) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithPrivateEthereumNetwork(network). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). WithStandardCleanup(). @@ -118,6 +121,7 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) + t.Run("Native Billing", func(t *testing.T) { testConfig := vrfv2PlusConfig var isNativeBilling = true @@ -612,7 +616,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { require.NoError(t, err) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). @@ -703,7 +707,7 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err) env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 48f34e6827..1abd98632f 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -1043,7 +1043,8 @@ func setupLogPollerTestDocker( WithConsensusType(ctf_test_env.ConsensusType_PoS). WithConsensusLayer(ctf_test_env.ConsensusLayer_Prysm). WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). - WithBeaconChainConfig(ctf_test_env.BeaconChainConfig{ + WithWaitingForFinalization(). + WithEthereumChainConfig(ctf_test_env.EthereumChainConfig{ SecondsPerSlot: 8, SlotsPerEpoch: 2, }). @@ -1051,7 +1052,7 @@ func setupLogPollerTestDocker( require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithPrivateEthereumNetwork(cfg). WithCLNodes(clNodesCount). WithCLNodeConfig(clNodeConfig). From dfc62cc51035f1dd7a555a6797fe305cd1b09bc6 Mon Sep 17 00:00:00 2001 From: Sergey Kudasov Date: Wed, 13 Dec 2023 00:01:58 +0300 Subject: [PATCH 300/327] disable kaniko fallback, increase deploy wait timeout (#11548) --- charts/chainlink-cluster/devspace.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index 186e49257a..bd50a469de 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -37,11 +37,14 @@ images: image: ${DEVSPACE_IMAGE} dockerfile: ../../core/chainlink.devspace.Dockerfile context: ../.. + docker: + disableFallback: true hooks: - wait: running: true terminatedWithCode: 0 + timeout: 600 container: labelSelector: # vars don't work here, = releaseName From 82faf5d4ca91706fa8fdf9fdc9893f97a4449548 Mon Sep 17 00:00:00 2001 From: chris-de-leon-cll <147140544+chris-de-leon-cll@users.noreply.github.com> Date: Tue, 12 Dec 2023 13:07:37 -0800 Subject: [PATCH 301/327] [DEPLOY-178]: Adds Scroll L2EP Contracts (#11405) * Adds scroll L2EP contracts and tests * fixes comments, adds fixed solidity compiler version, and adds scroll tech contracts as a dev dependency * renames SCROLL_CROSS_DOMAIN_MESSENGER to i_SCROLL_CROSS_DOMAIN_MESSENGER for solhint * removes unnecessary solhint disable rule * moves scroll mocks from tests folder to l2ep folder * resolve solhint errors for scroll * proposed restructure to reduce inheritance * removes extraneous comments from scroll contracts and refactors typeAndVersion * use named parameters in mappings for scroll contracts * removes extraneous empty comments from scroll contracts (again) * removes unnecessary comment from scroll cross domain governor * adds minor formatting updates to scroll mocks * adds onlyL1Owner modifier back to ScrollCrossDomainGovernor * adds style and formatting improvements * adds formatting updates * refactors scroll sequencer uptime feed to reduce gas and updates test suites --------- Co-authored-by: Rens Rooimans --- contracts/foundry.toml | 2 +- contracts/package.json | 1 + contracts/pnpm-lock.yaml | 17 +- .../ScrollSequencerUptimeFeedInterface.sol | 6 + .../dev/scroll/ScrollCrossDomainForwarder.sol | 65 +++ .../dev/scroll/ScrollCrossDomainGovernor.sol | 92 ++++ .../dev/scroll/ScrollSequencerUptimeFeed.sol | 231 +++++++++ .../v0.8/l2ep/dev/scroll/ScrollValidator.sol | 77 +++ .../MockScrollL1CrossDomainMessenger.sol | 60 +++ .../MockScrollL2CrossDomainMessenger.sol | 50 ++ .../vendor/MockScrollCrossDomainMessenger.sol | 101 ++++ .../dev/ScrollCrossDomainForwarder.test.ts | 259 ++++++++++ .../dev/ScrollCrossDomainGovernor.test.ts | 459 ++++++++++++++++++ .../dev/ScrollSequencerUptimeFeed.test.ts | 426 ++++++++++++++++ .../test/v0.8/dev/ScrollValidator.test.ts | 118 +++++ 15 files changed, 1961 insertions(+), 3 deletions(-) create mode 100644 contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol create mode 100644 contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol create mode 100644 contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol create mode 100644 contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol create mode 100644 contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol create mode 100644 contracts/src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol create mode 100644 contracts/src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol create mode 100644 contracts/src/v0.8/vendor/MockScrollCrossDomainMessenger.sol create mode 100644 contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts create mode 100644 contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts create mode 100644 contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts create mode 100644 contracts/test/v0.8/dev/ScrollValidator.test.ts diff --git a/contracts/foundry.toml b/contracts/foundry.toml index cf27c0f2a8..003c836b1f 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -37,7 +37,7 @@ test = 'src/v0.8/automation/test' optimizer_runs = 1000000 src = 'src/v0.8/l2ep' test = 'src/v0.8/l2ep/test' - +solc_version = '0.8.19' [profile.llo-feeds] optimizer_runs = 1000000 diff --git a/contracts/package.json b/contracts/package.json index 2604a12bea..abbf722140 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -43,6 +43,7 @@ "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "2.0.6", "@openzeppelin/hardhat-upgrades": "1.28.0", + "@scroll-tech/contracts": "0.1.0", "@openzeppelin/test-helpers": "^0.5.16", "@typechain/ethers-v5": "^7.2.0", "@typechain/hardhat": "^7.0.0", diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index fbae71fb3d..dffcb0a7c7 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -55,6 +55,9 @@ devDependencies: '@openzeppelin/test-helpers': specifier: ^0.5.16 version: 0.5.16(bn.js@4.12.0) + '@scroll-tech/contracts': + specifier: 0.1.0 + version: 0.1.0 '@typechain/ethers-v5': specifier: ^7.2.0 version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.2.2) @@ -1387,6 +1390,10 @@ packages: - supports-color dev: true + /@scroll-tech/contracts@0.1.0: + resolution: {integrity: sha512-aBbDOc3WB/WveZdpJYcrfvMYMz7ZTEiW8M9XMJLba8p9FAR5KGYB/cV+8+EUsq3MKt7C1BfR+WnXoTVdvwIY6w==} + dev: true + /@scure/base@1.1.1: resolution: {integrity: sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==} dev: true @@ -5861,7 +5868,7 @@ packages: heap: 0.2.6 level-sublevel: 6.6.4 levelup: 3.1.1 - lodash: 4.17.21 + lodash: 4.17.20 lru-cache: 5.1.1 merkle-patricia-tree: 3.0.0 patch-package: 6.2.2 @@ -7919,6 +7926,12 @@ packages: /minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + /minimatch@3.0.4: + resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} + dependencies: + brace-expansion: 1.1.11 + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -9232,7 +9245,7 @@ packages: resolution: {integrity: sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==} engines: {node: '>=0.10.0'} dependencies: - minimatch: 3.1.2 + minimatch: 3.0.4 dev: true /reduce-flatten@2.0.0: diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol new file mode 100644 index 0000000000..f0f716d6f0 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +interface ScrollSequencerUptimeFeedInterface { + function updateStatus(bool status, uint64 timestamp) external; +} diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol new file mode 100644 index 0000000000..f18f7c3270 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; + +/// @title ScrollCrossDomainForwarder - L1 xDomain account representation +/// @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination. +/// @dev Any other L2 contract which uses this contract's address as a privileged position, +/// can be considered to be owned by the `l1Owner` +contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollCrossDomainForwarder 1.0.0"; + + address internal immutable i_scrollCrossDomainMessenger; + + /// @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address + /// @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn + constructor(IScrollMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { + // solhint-disable-next-line custom-errors + require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); + i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr); + } + + /// @dev forwarded only if L2 Messenger calls with `xDomainMessageSender` being the L1 owner address + /// @inheritdoc ForwarderInterface + function forward(address target, bytes memory data) external override onlyL1Owner { + Address.functionCall(target, data, "Forwarder call reverted"); + } + + /// @notice This is always the address of the Scroll Cross Domain Messenger contract + function crossDomainMessenger() external view returns (address) { + return address(i_scrollCrossDomainMessenger); + } + + /// @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), + "xDomain sender is not the L1 owner" + ); + _; + } + + /// @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyProposedL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner, + "Must be proposed L1 owner" + ); + _; + } +} diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol new file mode 100644 index 0000000000..00ef9219b2 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; + +/// @title ScrollCrossDomainGovernor - L1 xDomain account representation (with delegatecall support) for Scroll +/// @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination. +/// @dev Any other L2 contract which uses this contract's address as a privileged position, +/// can be considered to be simultaneously owned by the `l1Owner` and L2 `owner` +contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersionInterface, CrossDomainForwarder { + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollCrossDomainGovernor 1.0.0"; + + address internal immutable i_scrollCrossDomainMessenger; + + /// @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address + /// @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn + constructor(IScrollMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { + // solhint-disable-next-line custom-errors + require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); + i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr); + } + + /// @inheritdoc ForwarderInterface + /// @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner + function forward(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { + Address.functionCall(target, data, "Governor call reverted"); + } + + /// @inheritdoc DelegateForwarderInterface + /// @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner + function forwardDelegate(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { + Address.functionDelegateCall(target, data, "Governor delegatecall reverted"); + } + + /// @notice The address of the Scroll Cross Domain Messenger contract + function crossDomainMessenger() external view returns (address) { + return address(i_scrollCrossDomainMessenger); + } + + /// @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), + "xDomain sender is not the L1 owner" + ); + _; + } + + /// @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise. + modifier onlyLocalOrCrossDomainOwner() { + // 1. The delegatecall MUST come from either the L1 owner (via cross-chain message) or the L2 owner + // solhint-disable-next-line custom-errors + require( + msg.sender == i_scrollCrossDomainMessenger || msg.sender == owner(), + "Sender is not the L2 messenger or owner" + ); + // 2. The L2 Messenger's caller MUST be the L1 Owner + if (msg.sender == i_scrollCrossDomainMessenger) { + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), + "xDomain sender is not the L1 owner" + ); + } + _; + } + + /// @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyProposedL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner, + "Must be proposed L1 owner" + ); + _; + } +} diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol new file mode 100644 index 0000000000..22b5ed1e2b --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {ScrollSequencerUptimeFeedInterface} from "../interfaces/ScrollSequencerUptimeFeedInterface.sol"; +import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; + +import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; + +import {IL2ScrollMessenger} from "@scroll-tech/contracts/L2/IL2ScrollMessenger.sol"; + +/// @title ScrollSequencerUptimeFeed - L2 sequencer uptime status aggregator +/// @notice L2 contract that receives status updates, and records a new answer if the status changed +contract ScrollSequencerUptimeFeed is + AggregatorV2V3Interface, + ScrollSequencerUptimeFeedInterface, + TypeAndVersionInterface, + SimpleReadAccessController +{ + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollSequencerUptimeFeed 1.0.0"; + + /// @dev Round info (for uptime history) + struct Round { + bool status; + uint64 startedAt; + uint64 updatedAt; + } + + /// @dev Packed state struct to save sloads + struct FeedState { + uint80 latestRoundId; + bool latestStatus; + uint64 startedAt; + uint64 updatedAt; + } + + /// @notice Sender is not the L2 messenger + error InvalidSender(); + /// @notice Replacement for AggregatorV3Interface "No data present" + error NoDataPresent(); + + event L1SenderTransferred(address indexed from, address indexed to); + /// @dev Emitted when an `updateStatus` call is ignored due to unchanged status or stale timestamp + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + /// @dev Emitted when a updateStatus is called without the status changing + event RoundUpdated(int256 status, uint64 updatedAt); + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint8 public constant override decimals = 0; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override description = "L2 Sequencer Uptime Status Feed"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint256 public constant override version = 1; + + /// @dev L1 address + address private s_l1Sender; + /// @dev s_latestRoundId == 0 means this contract is uninitialized. + FeedState private s_feedState = FeedState({latestRoundId: 0, latestStatus: false, startedAt: 0, updatedAt: 0}); + mapping(uint80 roundId => Round round) private s_rounds; + + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + IL2ScrollMessenger private immutable s_l2CrossDomainMessenger; + + /// @param l1SenderAddress Address of the L1 contract that is permissioned to call this contract + /// @param l2CrossDomainMessengerAddr Address of the L2CrossDomainMessenger contract + /// @param initialStatus The initial status of the feed + constructor(address l1SenderAddress, address l2CrossDomainMessengerAddr, bool initialStatus) { + _setL1Sender(l1SenderAddress); + s_l2CrossDomainMessenger = IL2ScrollMessenger(l2CrossDomainMessengerAddr); + + // Initialise roundId == 1 as the first round + _recordRound(1, initialStatus, uint64(block.timestamp)); + } + + /// @notice Check if a roundId is valid in this current contract state + /// @dev Mainly used for AggregatorV2V3Interface functions + /// @param roundId Round ID to check + function _isValidRound(uint256 roundId) private view returns (bool) { + return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; + } + + /// @return L1 sender address + function l1Sender() public view virtual returns (address) { + return s_l1Sender; + } + + /// @notice Set the allowed L1 sender for this contract to a new L1 sender + /// @dev Can be disabled by setting the L1 sender as `address(0)`. Accessible only by owner. + /// @param to new L1 sender that will be allowed to call `updateStatus` on this contract + function transferL1Sender(address to) external virtual onlyOwner { + _setL1Sender(to); + } + + /// @notice internal method that stores the L1 sender + function _setL1Sender(address to) private { + address from = s_l1Sender; + if (from != to) { + s_l1Sender = to; + emit L1SenderTransferred(from, to); + } + } + + /// @dev Returns an AggregatorV2V3Interface compatible answer from status flag + /// @param status The status flag to convert to an aggregator-compatible answer + function _getStatusAnswer(bool status) private pure returns (int256) { + return status ? int256(1) : int256(0); + } + + /// @notice Helper function to record a round and set the latest feed state. + /// @param roundId The round ID to record + /// @param status Sequencer status + /// @param timestamp The L1 block timestamp of status update + function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { + s_feedState = FeedState(roundId, status, timestamp, uint64(block.timestamp)); + s_rounds[roundId] = Round(status, timestamp, uint64(block.timestamp)); + + emit NewRound(roundId, msg.sender, timestamp); + emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); + } + + /// @notice Helper function to update when a round was last updated + /// @param roundId The round ID to update + /// @param status Sequencer status + function _updateRound(uint80 roundId, bool status) private { + s_feedState.updatedAt = uint64(block.timestamp); + s_rounds[roundId].updatedAt = uint64(block.timestamp); + emit RoundUpdated(_getStatusAnswer(status), uint64(block.timestamp)); + } + + /// @notice Record a new status and timestamp if it has changed since the last round. + /// @dev This function will revert if not called from `l1Sender` via the L1->L2 messenger. + /// + /// @param status Sequencer status + /// @param timestamp Block timestamp of status update + function updateStatus(bool status, uint64 timestamp) external override { + FeedState memory feedState = s_feedState; + + if ( + msg.sender != address(s_l2CrossDomainMessenger) || s_l2CrossDomainMessenger.xDomainMessageSender() != s_l1Sender + ) { + revert InvalidSender(); + } + + // Ignore if latest recorded timestamp is newer + if (feedState.startedAt > timestamp) { + emit UpdateIgnored(feedState.latestStatus, feedState.startedAt, status, timestamp); + return; + } + + if (feedState.latestStatus == status) { + _updateRound(feedState.latestRoundId, status); + } else { + feedState.latestRoundId += 1; + _recordRound(feedState.latestRoundId, status, timestamp); + } + } + + /// @inheritdoc AggregatorInterface + function latestAnswer() external view override checkAccess returns (int256) { + return _getStatusAnswer(s_feedState.latestStatus); + } + + /// @inheritdoc AggregatorInterface + function latestTimestamp() external view override checkAccess returns (uint256) { + return s_feedState.startedAt; + } + + /// @inheritdoc AggregatorInterface + function latestRound() external view override checkAccess returns (uint256) { + return s_feedState.latestRoundId; + } + + /// @inheritdoc AggregatorInterface + function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { + if (!_isValidRound(roundId)) { + revert NoDataPresent(); + } + + return _getStatusAnswer(s_rounds[uint80(roundId)].status); + } + + /// @inheritdoc AggregatorInterface + function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { + if (!_isValidRound(roundId)) { + revert NoDataPresent(); + } + + return s_rounds[uint80(roundId)].startedAt; + } + + /// @inheritdoc AggregatorV3Interface + function getRoundData( + uint80 _roundId + ) + public + view + override + checkAccess + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + if (!_isValidRound(_roundId)) { + revert NoDataPresent(); + } + + Round memory round = s_rounds[_roundId]; + + return (_roundId, _getStatusAnswer(round.status), uint256(round.startedAt), uint256(round.updatedAt), _roundId); + } + + /// @inheritdoc AggregatorV3Interface + function latestRoundData() + external + view + override + checkAccess + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + FeedState memory feedState = s_feedState; + + return ( + feedState.latestRoundId, + _getStatusAnswer(feedState.latestStatus), + feedState.startedAt, + feedState.updatedAt, + feedState.latestRoundId + ); + } +} diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol new file mode 100644 index 0000000000..31a5f0764e --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ScrollSequencerUptimeFeedInterface} from "../interfaces/ScrollSequencerUptimeFeedInterface.sol"; + +import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; + +import {IL1ScrollMessenger} from "@scroll-tech/contracts/L1/IL1ScrollMessenger.sol"; + +/// @title ScrollValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 +contract ScrollValidator is TypeAndVersionInterface, AggregatorValidatorInterface, SimpleWriteAccessController { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable L1_CROSS_DOMAIN_MESSENGER_ADDRESS; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable L2_UPTIME_FEED_ADDR; + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollValidator 1.0.0"; + int256 private constant ANSWER_SEQ_OFFLINE = 1; + uint32 private s_gasLimit; + + /// @notice emitted when gas cost to spend on L2 is updated + /// @param gasLimit updated gas cost + event GasLimitUpdated(uint32 gasLimit); + + /// @param l1CrossDomainMessengerAddress address the L1CrossDomainMessenger contract address + /// @param l2UptimeFeedAddr the address of the ScrollSequencerUptimeFeed contract address + /// @param gasLimit the gasLimit to use for sending a message from L1 to L2 + constructor(address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, uint32 gasLimit) { + // solhint-disable-next-line custom-errors + require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); + // solhint-disable-next-line custom-errors + require(l2UptimeFeedAddr != address(0), "Invalid ScrollSequencerUptimeFeed contract address"); + L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; + L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; + s_gasLimit = gasLimit; + } + + /// @notice sets the new gas cost to spend when sending cross chain message + /// @param gasLimit the updated gas cost + function setGasLimit(uint32 gasLimit) external onlyOwner { + s_gasLimit = gasLimit; + emit GasLimitUpdated(gasLimit); + } + + /// @notice fetches the gas cost of sending a cross chain message + function getGasLimit() external view returns (uint32) { + return s_gasLimit; + } + + /// @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. + /// @dev A message is sent using the L1CrossDomainMessenger. This method is accessed controlled. + /// @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. + function validate( + uint256 /* previousRoundId */, + int256 /* previousAnswer */, + uint256 /* currentRoundId */, + int256 currentAnswer + ) external override checkAccess returns (bool) { + // Make the xDomain call + IL1ScrollMessenger(L1_CROSS_DOMAIN_MESSENGER_ADDRESS).sendMessage( + L2_UPTIME_FEED_ADDR, + 0, + abi.encodeWithSelector( + ScrollSequencerUptimeFeedInterface.updateStatus.selector, + currentAnswer == ANSWER_SEQ_OFFLINE, + uint64(block.timestamp) + ), + s_gasLimit + ); + + // return success + return true; + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol new file mode 100644 index 0000000000..e63847d655 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {IL1ScrollMessenger} from "@scroll-tech/contracts/L1/IL1ScrollMessenger.sol"; + +contract MockScrollL1CrossDomainMessenger is IL1ScrollMessenger { + uint256 private s_nonce; + + function xDomainMessageSender() public pure returns (address) { + return address(0); + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit, + address + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function relayMessageWithProof( + address from, + address to, + uint256 value, + uint256 nonce, + bytes memory message, + L2MessageProof memory proof + ) external override {} + + function replayMessage( + address from, + address to, + uint256 value, + uint256 messageNonce, + bytes memory message, + uint32 newGasLimit, + address refundAddress + ) external payable override {} + + function dropMessage( + address from, + address to, + uint256 value, + uint256 messageNonce, + bytes memory message + ) external override {} +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol new file mode 100644 index 0000000000..f63faa3517 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {IL2ScrollMessenger} from "@scroll-tech/contracts/L2/IL2ScrollMessenger.sol"; + +contract MockScrollL2CrossDomainMessenger is IL2ScrollMessenger { + uint256 private s_nonce; + address private s_sender; + + function xDomainMessageSender() public view returns (address) { + return s_sender; + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit, + address + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function relayMessage( + address from, + address to, + uint256 value, + uint256 nonce, + bytes calldata message + ) external override {} + + /// Needed for testing + function setSender(address newSender) external { + s_sender = newSender; + } + + /// Needed for testing + receive() external payable {} +} diff --git a/contracts/src/v0.8/vendor/MockScrollCrossDomainMessenger.sol b/contracts/src/v0.8/vendor/MockScrollCrossDomainMessenger.sol new file mode 100644 index 0000000000..bb5390b945 --- /dev/null +++ b/contracts/src/v0.8/vendor/MockScrollCrossDomainMessenger.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import "./openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; + +/// sourced from: https://github.com/scroll-tech/scroll/blob/develop/contracts/src/libraries/IScrollMessenger.sol +interface IScrollMessenger { + /// ********** + /// * Events * + /// ********** + + /// @notice Emitted when a cross domain message is sent. + /// @param sender The address of the sender who initiates the message. + /// @param target The address of target contract to call. + /// @param value The amount of value passed to the target contract. + /// @param messageNonce The nonce of the message. + /// @param gasLimit The optional gas limit passed to L1 or L2. + /// @param message The calldata passed to the target contract. + event SentMessage( + address indexed sender, + address indexed target, + uint256 value, + uint256 messageNonce, + uint256 gasLimit, + bytes message + ); + + /// @notice Emitted when a cross domain message is relayed successfully. + /// @param messageHash The hash of the message. + event RelayedMessage(bytes32 indexed messageHash); + + /// @notice Emitted when a cross domain message is failed to relay. + /// @param messageHash The hash of the message. + event FailedRelayedMessage(bytes32 indexed messageHash); + + /// ************************* + /// * Public View Functions * + /// ************************* + + /// @notice Return the sender of a cross domain message. + function xDomainMessageSender() external view returns (address); + + /// ***************************** + /// * Public Mutating Functions * + /// ***************************** + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param target The address of account who receive the message. + /// @param value The amount of ether passed when call target contract. + /// @param message The content of the message. + /// @param gasLimit Gas limit required to complete the message relay on corresponding chain. + function sendMessage(address target, uint256 value, bytes calldata message, uint256 gasLimit) external payable; + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param target The address of account who receive the message. + /// @param value The amount of ether passed when call target contract. + /// @param message The content of the message. + /// @param gasLimit Gas limit required to complete the message relay on corresponding chain. + /// @param refundAddress The address of account who will receive the refunded fee. + function sendMessage( + address target, + uint256 value, + bytes calldata message, + uint256 gasLimit, + address refundAddress + ) external payable; +} + +contract MockScrollCrossDomainMessenger is IScrollMessenger { + address internal mockMessageSender; + + constructor(address sender) { + mockMessageSender = sender; + } + + function xDomainMessageSender() external view override returns (address) { + return mockMessageSender; + } + + function _setMockMessageSender(address sender) external { + mockMessageSender = sender; + } + + /// ***************************** + /// * Public Mutating Functions * + /// ***************************** + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256, address) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } +} diff --git a/contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts b/contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts new file mode 100644 index 0000000000..923d41326a --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts @@ -0,0 +1,259 @@ +import { ethers } from 'hardhat' +import { assert, expect } from 'chai' +import { Contract, ContractFactory } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { publicAbi } from '../../test-helpers/helpers' + +let owner: SignerWithAddress +let stranger: SignerWithAddress +let l1OwnerAddress: string +let newL1OwnerAddress: string +let forwarderFactory: ContractFactory +let greeterFactory: ContractFactory +let crossDomainMessengerFactory: ContractFactory +let crossDomainMessenger: Contract +let forwarder: Contract +let greeter: Contract + +before(async () => { + const accounts = await ethers.getSigners() + owner = accounts[0] + stranger = accounts[1] + + // forwarder config + l1OwnerAddress = owner.address + newL1OwnerAddress = stranger.address + + // Contract factories + forwarderFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol:ScrollCrossDomainForwarder', + owner, + ) + greeterFactory = await ethers.getContractFactory( + 'src/v0.8/tests/Greeter.sol:Greeter', + owner, + ) + crossDomainMessengerFactory = await ethers.getContractFactory( + 'src/v0.8/vendor/MockScrollCrossDomainMessenger.sol:MockScrollCrossDomainMessenger', + ) +}) + +describe('ScrollCrossDomainForwarder', () => { + beforeEach(async () => { + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) + forwarder = await forwarderFactory.deploy( + crossDomainMessenger.address, + l1OwnerAddress, + ) + greeter = await greeterFactory.deploy(forwarder.address) + }) + + it('has a limited public interface [ @skip-coverage ]', async () => { + publicAbi(forwarder, [ + 'typeAndVersion', + 'crossDomainMessenger', + 'forward', + 'l1Owner', + 'transferL1Ownership', + 'acceptL1Ownership', + // ConfirmedOwner methods: + 'owner', + 'transferOwnership', + 'acceptOwnership', + ]) + }) + + describe('#constructor', () => { + it('should set the owner correctly', async () => { + const response = await forwarder.owner() + assert.equal(response, owner.address) + }) + + it('should set the l1Owner correctly', async () => { + const response = await forwarder.l1Owner() + assert.equal(response, l1OwnerAddress) + }) + + it('should set the crossdomain messenger correctly', async () => { + const response = await forwarder.crossDomainMessenger() + assert.equal(response, crossDomainMessenger.address) + }) + + it('should set the typeAndVersion correctly', async () => { + const response = await forwarder.typeAndVersion() + assert.equal(response, 'ScrollCrossDomainForwarder 1.0.0') + }) + }) + + describe('#forward', () => { + it('should not be callable by unknown address', async () => { + await expect( + forwarder.connect(stranger).forward(greeter.address, '0x'), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by crossdomain messenger address / L1 owner', async () => { + const newGreeting = 'hello' + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [newGreeting], + ) + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, newGreeting) + }) + + it('should revert when contract call reverts', async () => { + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [''], + ) + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Invalid greeting length') + }) + }) + + describe('#transferL1Ownership', () => { + it('should not be callable by non-owners', async () => { + await expect( + forwarder.connect(stranger).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should not be callable by L2 owner', async () => { + const forwarderOwner = await forwarder.owner() + assert.equal(forwarderOwner, owner.address) + + await expect( + forwarder.connect(owner).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by current L1 owner', async () => { + const currentL1Owner = await forwarder.l1Owner() + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(forwarder, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, newL1OwnerAddress) + }) + + it('should be callable by current L1 owner to zero address', async () => { + const currentL1Owner = await forwarder.l1Owner() + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [ethers.constants.AddressZero], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(forwarder, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, ethers.constants.AddressZero) + }) + }) + + describe('#acceptL1Ownership', () => { + it('should not be callable by non pending-owners', async () => { + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Must be proposed L1 owner') + }) + + it('should be callable by pending L1 owner', async () => { + const currentL1Owner = await forwarder.l1Owner() + + // Transfer ownership + const forwardTransferData = forwarderFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardTransferData, // message + 0, // gasLimit + ) + + const forwardAcceptData = forwarderFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + // Simulate cross-chain message from another sender + await crossDomainMessenger._setMockMessageSender(newL1OwnerAddress) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardAcceptData, // message + 0, // gasLimit + ), + ) + .to.emit(forwarder, 'L1OwnershipTransferred') + .withArgs(currentL1Owner, newL1OwnerAddress) + + const updatedL1Owner = await forwarder.l1Owner() + assert.equal(updatedL1Owner, newL1OwnerAddress) + }) + }) +}) diff --git a/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts b/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts new file mode 100644 index 0000000000..adb78c2624 --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts @@ -0,0 +1,459 @@ +import { ethers } from 'hardhat' +import { assert, expect } from 'chai' +import etherslib, { Contract, ContractFactory } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { publicAbi, stripHexPrefix } from '../../test-helpers/helpers' + +let owner: SignerWithAddress +let stranger: SignerWithAddress +let l1OwnerAddress: string +let newL1OwnerAddress: string +let governorFactory: ContractFactory +let greeterFactory: ContractFactory +let multisendFactory: ContractFactory +let crossDomainMessengerFactory: ContractFactory +let crossDomainMessenger: Contract +let governor: Contract +let greeter: Contract +let multisend: Contract + +before(async () => { + const accounts = await ethers.getSigners() + owner = accounts[0] + stranger = accounts[1] + + // governor config + l1OwnerAddress = owner.address + newL1OwnerAddress = stranger.address + + // Contract factories + governorFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol:ScrollCrossDomainGovernor', + owner, + ) + greeterFactory = await ethers.getContractFactory( + 'src/v0.8/tests/Greeter.sol:Greeter', + owner, + ) + multisendFactory = await ethers.getContractFactory( + 'src/v0.8/vendor/MultiSend.sol:MultiSend', + owner, + ) + crossDomainMessengerFactory = await ethers.getContractFactory( + 'src/v0.8/vendor/MockScrollCrossDomainMessenger.sol:MockScrollCrossDomainMessenger', + ) +}) + +describe('ScrollCrossDomainGovernor', () => { + beforeEach(async () => { + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) + governor = await governorFactory.deploy( + crossDomainMessenger.address, + l1OwnerAddress, + ) + greeter = await greeterFactory.deploy(governor.address) + multisend = await multisendFactory.deploy() + }) + + it('has a limited public interface [ @skip-coverage ]', async () => { + publicAbi(governor, [ + 'typeAndVersion', + 'crossDomainMessenger', + 'forward', + 'forwardDelegate', + 'l1Owner', + 'transferL1Ownership', + 'acceptL1Ownership', + // ConfirmedOwner methods: + 'owner', + 'transferOwnership', + 'acceptOwnership', + ]) + }) + + describe('#constructor', () => { + it('should set the owner correctly', async () => { + const response = await governor.owner() + assert.equal(response, owner.address) + }) + + it('should set the l1Owner correctly', async () => { + const response = await governor.l1Owner() + assert.equal(response, l1OwnerAddress) + }) + + it('should set the crossdomain messenger correctly', async () => { + const response = await governor.crossDomainMessenger() + assert.equal(response, crossDomainMessenger.address) + }) + + it('should set the typeAndVersion correctly', async () => { + const response = await governor.typeAndVersion() + assert.equal(response, 'ScrollCrossDomainGovernor 1.0.0') + }) + }) + + describe('#forward', () => { + it('should not be callable by unknown address', async () => { + await expect( + governor.connect(stranger).forward(greeter.address, '0x'), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by crossdomain messenger address / L1 owner', async () => { + const newGreeting = 'hello' + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [newGreeting], + ) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, newGreeting) + }) + + it('should be callable by L2 owner', async () => { + const newGreeting = 'hello' + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [newGreeting], + ) + await governor.connect(owner).forward(greeter.address, setGreetingData) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, newGreeting) + }) + + it('should revert when contract call reverts', async () => { + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [''], + ) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Invalid greeting length') + }) + }) + + describe('#forwardDelegate', () => { + it('should not be callable by unknown address', async () => { + await expect( + governor.connect(stranger).forwardDelegate(multisend.address, '0x'), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by crossdomain messenger address / L1 owner', async () => { + const calls = [ + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'foo', + ]), + value: 0, + }, + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'bar', + ]), + value: 0, + }, + ] + const multisendData = encodeMultisendData(multisend.interface, calls) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forwardDelegate', + [multisend.address, multisendData], + ) + + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, 'bar') + }) + + it('should be callable by L2 owner', async () => { + const calls = [ + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'foo', + ]), + value: 0, + }, + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'bar', + ]), + value: 0, + }, + ] + const multisendData = encodeMultisendData(multisend.interface, calls) + await governor + .connect(owner) + .forwardDelegate(multisend.address, multisendData) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, 'bar') + }) + + it('should revert batch when one call fails', async () => { + const calls = [ + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'foo', + ]), + value: 0, + }, + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + '', // should revert + ]), + value: 0, + }, + ] + const multisendData = encodeMultisendData(multisend.interface, calls) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forwardDelegate', + [multisend.address, multisendData], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Governor delegatecall reverted') + + const greeting = await greeter.greeting() + assert.equal(greeting, '') // Unchanged + }) + + it('should bubble up revert when contract call reverts', async () => { + const triggerRevertData = + greeterFactory.interface.encodeFunctionData('triggerRevert') + const forwardData = governorFactory.interface.encodeFunctionData( + 'forwardDelegate', + [greeter.address, triggerRevertData], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Greeter: revert triggered') + }) + }) + + describe('#transferL1Ownership', () => { + it('should not be callable by non-owners', async () => { + await expect( + governor.connect(stranger).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should not be callable by L2 owner', async () => { + const governorOwner = await governor.owner() + assert.equal(governorOwner, owner.address) + + await expect( + governor.connect(owner).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by current L1 owner', async () => { + const currentL1Owner = await governor.l1Owner() + const forwardData = governorFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(governor, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, newL1OwnerAddress) + }) + + it('should be callable by current L1 owner to zero address', async () => { + const currentL1Owner = await governor.l1Owner() + const forwardData = governorFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [ethers.constants.AddressZero], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(governor, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, ethers.constants.AddressZero) + }) + }) + + describe('#acceptL1Ownership', () => { + it('should not be callable by non pending-owners', async () => { + const forwardData = governorFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Must be proposed L1 owner') + }) + + it('should be callable by pending L1 owner', async () => { + const currentL1Owner = await governor.l1Owner() + + // Transfer ownership + const forwardTransferData = governorFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardTransferData, // message + 0, // gasLimit + ) + + const forwardAcceptData = governorFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + // Simulate cross-chain message from another sender + await crossDomainMessenger._setMockMessageSender(newL1OwnerAddress) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardAcceptData, // message + 0, // gasLimit + ), + ) + .to.emit(governor, 'L1OwnershipTransferred') + .withArgs(currentL1Owner, newL1OwnerAddress) + + const updatedL1Owner = await governor.l1Owner() + assert.equal(updatedL1Owner, newL1OwnerAddress) + }) + }) +}) + +// Multisend contract helpers + +/** + * Encodes an underlying transaction for the Multisend contract + * + * @param operation 0 for CALL, 1 for DELEGATECALL + * @param to tx target address + * @param value tx value + * @param data tx data + */ +export function encodeTxData( + operation: number, + to: string, + value: number, + data: string, +): string { + const dataBuffer = Buffer.from(stripHexPrefix(data), 'hex') + const types = ['uint8', 'address', 'uint256', 'uint256', 'bytes'] + const values = [operation, to, value, dataBuffer.length, dataBuffer] + const encoded = ethers.utils.solidityPack(types, values) + return stripHexPrefix(encoded) +} + +/** + * Encodes a Multisend call + * + * @param MultisendInterface Ethers Interface object of the Multisend contract + * @param transactions one or more transactions to include in the Multisend call + * @param to tx target address + * @param value tx value + * @param data tx data + */ +export function encodeMultisendData( + MultisendInterface: etherslib.utils.Interface, + transactions: { to: string; value: number; data: string }[], +): string { + let nestedTransactionData = '0x' + for (const transaction of transactions) { + nestedTransactionData += encodeTxData( + 0, + transaction.to, + transaction.value, + transaction.data, + ) + } + const encodedMultisendFnData = MultisendInterface.encodeFunctionData( + 'multiSend', + [nestedTransactionData], + ) + return encodedMultisendFnData +} diff --git a/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts b/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts new file mode 100644 index 0000000000..b294032e73 --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts @@ -0,0 +1,426 @@ +import { ethers, network } from 'hardhat' +import { BigNumber, Contract } from 'ethers' +import { expect } from 'chai' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' + +describe('ScrollSequencerUptimeFeed', () => { + let l2CrossDomainMessenger: Contract + let scrollUptimeFeed: Contract + let uptimeFeedConsumer: Contract + let deployer: SignerWithAddress + let l1Owner: SignerWithAddress + let l2Messenger: SignerWithAddress + let dummy: SignerWithAddress + const gasUsedDeviation = 100 + const initialStatus = 0 + + before(async () => { + const accounts = await ethers.getSigners() + deployer = accounts[0] + l1Owner = accounts[1] + dummy = accounts[3] + + const l2CrossDomainMessengerFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol:MockScrollL2CrossDomainMessenger', + deployer, + ) + + l2CrossDomainMessenger = await l2CrossDomainMessengerFactory.deploy() + + // Pretend we're on L2 + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [l2CrossDomainMessenger.address], + }) + l2Messenger = await ethers.getSigner(l2CrossDomainMessenger.address) + // Credit the L2 messenger with some ETH + await dummy.sendTransaction({ + to: l2Messenger.address, + value: ethers.utils.parseEther('10'), + }) + }) + + beforeEach(async () => { + const scrollSequencerStatusRecorderFactory = + await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol:ScrollSequencerUptimeFeed', + deployer, + ) + scrollUptimeFeed = await scrollSequencerStatusRecorderFactory.deploy( + l1Owner.address, + l2CrossDomainMessenger.address, + initialStatus, + ) + + // Set mock sender in mock L2 messenger contract + await l2CrossDomainMessenger.setSender(l1Owner.address) + + // Mock consumer + const statusFeedConsumerFactory = await ethers.getContractFactory( + 'src/v0.8/tests/FeedConsumer.sol:FeedConsumer', + deployer, + ) + uptimeFeedConsumer = await statusFeedConsumerFactory.deploy( + scrollUptimeFeed.address, + ) + }) + + describe('constructor', () => { + it('should have been deployed with the correct initial state', async () => { + const l1Sender = await scrollUptimeFeed.l1Sender() + expect(l1Sender).to.equal(l1Owner.address) + const { roundId, answer } = await scrollUptimeFeed.latestRoundData() + expect(roundId).to.equal(1) + expect(answer).to.equal(initialStatus) + }) + }) + + describe('#updateStatus', () => { + it('should revert if called by an address that is not the L2 Cross Domain Messenger', async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + expect( + scrollUptimeFeed.connect(dummy).updateStatus(true, timestamp), + ).to.be.revertedWith('InvalidSender') + }) + + it('should revert if called by an address that is not the L2 Cross Domain Messenger and is not the L1 sender', async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + await l2CrossDomainMessenger.setSender(dummy.address) + expect( + scrollUptimeFeed.connect(dummy).updateStatus(true, timestamp), + ).to.be.revertedWith('InvalidSender') + }) + + it(`should update status when status has not changed and incoming timestamp is the same as latest`, async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + const latestRoundBeforeUpdate = await scrollUptimeFeed.latestRoundData() + + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp.add(200)) + + // Submit another status update with the same status + const latestBlock = await ethers.provider.getBlock('latest') + + await expect(tx) + .to.emit(scrollUptimeFeed, 'RoundUpdated') + .withArgs(1, latestBlock.timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + expect(await scrollUptimeFeed.latestTimestamp()).to.equal(timestamp) + + // Verify that latest round has been properly updated + const latestRoundDataAfterUpdate = + await scrollUptimeFeed.latestRoundData() + expect(latestRoundDataAfterUpdate.roundId).to.equal( + latestRoundBeforeUpdate.roundId, + ) + expect(latestRoundDataAfterUpdate.answer).to.equal( + latestRoundBeforeUpdate.answer, + ) + expect(latestRoundDataAfterUpdate.startedAt).to.equal( + latestRoundBeforeUpdate.startedAt, + ) + expect(latestRoundDataAfterUpdate.answeredInRound).to.equal( + latestRoundBeforeUpdate.answeredInRound, + ) + expect(latestRoundDataAfterUpdate.updatedAt).to.equal( + latestBlock.timestamp, + ) + }) + + it(`should update status when status has changed and incoming timestamp is newer than the latest`, async () => { + let timestamp = await scrollUptimeFeed.latestTimestamp() + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp.add(2000) + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(0, 3 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + expect(await scrollUptimeFeed.latestTimestamp()).to.equal(timestamp) + }) + + it(`should update status when status has changed and incoming timestamp is the same as latest`, async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + // Submit another status update, different status, same timestamp should update + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(0, 3 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + expect(await scrollUptimeFeed.latestTimestamp()).to.equal(timestamp) + }) + + it('should ignore out-of-order updates', async () => { + const timestamp = (await scrollUptimeFeed.latestTimestamp()).add(10_000) + // Update status + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + // Update with different status, but stale timestamp, should be ignored + const staleTimestamp = timestamp.sub(1000) + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, staleTimestamp) + await expect(tx) + .to.not.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + await expect(tx).to.emit(scrollUptimeFeed, 'UpdateIgnored') + }) + }) + + describe('AggregatorV3Interface', () => { + it('should return valid answer from getRoundData and latestRoundData', async () => { + let [roundId, answer, startedAt, updatedAt, answeredInRound] = + await scrollUptimeFeed.latestRoundData() + expect(roundId).to.equal(1) + expect(answer).to.equal(0) + expect(answeredInRound).to.equal(roundId) + expect(startedAt).to.equal(updatedAt) + + // Submit status update with different status and newer timestamp, should update + const timestamp = (startedAt as BigNumber).add(1000) + await scrollUptimeFeed.connect(l2Messenger).updateStatus(true, timestamp) + ;[roundId, answer, startedAt, updatedAt, answeredInRound] = + await scrollUptimeFeed.getRoundData(2) + expect(roundId).to.equal(2) + expect(answer).to.equal(1) + expect(answeredInRound).to.equal(roundId) + expect(startedAt).to.equal(timestamp) + expect(updatedAt.lte(startedAt)).to.be.true + + // Check that last round is still returning the correct data + ;[roundId, answer, startedAt, updatedAt, answeredInRound] = + await scrollUptimeFeed.getRoundData(1) + expect(roundId).to.equal(1) + expect(answer).to.equal(0) + expect(answeredInRound).to.equal(roundId) + expect(startedAt).to.equal(updatedAt) + + // Assert latestRoundData corresponds to latest round id + expect(await scrollUptimeFeed.getRoundData(2)).to.deep.equal( + await scrollUptimeFeed.latestRoundData(), + ) + }) + + it('should revert from #getRoundData when round does not yet exist (future roundId)', async () => { + expect(scrollUptimeFeed.getRoundData(2)).to.be.revertedWith( + 'NoDataPresent()', + ) + }) + + it('should revert from #getAnswer when round does not yet exist (future roundId)', async () => { + expect(scrollUptimeFeed.getAnswer(2)).to.be.revertedWith( + 'NoDataPresent()', + ) + }) + + it('should revert from #getTimestamp when round does not yet exist (future roundId)', async () => { + expect(scrollUptimeFeed.getTimestamp(2)).to.be.revertedWith( + 'NoDataPresent()', + ) + }) + }) + + describe('Protect reads on AggregatorV2V3Interface functions', () => { + it('should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted', async () => { + // Sanity - consumer is not whitelisted + expect(await scrollUptimeFeed.checkEnabled()).to.be.true + expect( + await scrollUptimeFeed.hasAccess(uptimeFeedConsumer.address, '0x00'), + ).to.be.false + + // Assert reads are not possible from consuming contract + await expect(uptimeFeedConsumer.latestAnswer()).to.be.revertedWith( + 'No access', + ) + await expect(uptimeFeedConsumer.latestRoundData()).to.be.revertedWith( + 'No access', + ) + }) + + it('should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted', async () => { + // Whitelist consumer + await scrollUptimeFeed.addAccess(uptimeFeedConsumer.address) + // Sanity - consumer is whitelisted + expect(await scrollUptimeFeed.checkEnabled()).to.be.true + expect( + await scrollUptimeFeed.hasAccess(uptimeFeedConsumer.address, '0x00'), + ).to.be.true + + // Assert reads are possible from consuming contract + expect(await uptimeFeedConsumer.latestAnswer()).to.be.equal('0') + const [roundId, answer] = await uptimeFeedConsumer.latestRoundData() + expect(roundId).to.equal(1) + expect(answer).to.equal(0) + }) + }) + + describe('Gas costs', () => { + it('should consume a known amount of gas for updates @skip-coverage', async () => { + // Sanity - start at flag = 0 (`false`) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + let timestamp = await scrollUptimeFeed.latestTimestamp() + + // Gas for no update + timestamp = timestamp.add(1000) + const _noUpdateTx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, timestamp) + const noUpdateTx = await _noUpdateTx.wait(1) + // Assert no update + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + expect(noUpdateTx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 38594, + gasUsedDeviation, + ) + + // Gas for update + timestamp = timestamp.add(1000) + const _updateTx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + const updateTx = await _updateTx.wait(1) + // Assert update + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + expect(updateTx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 58458, + gasUsedDeviation, + ) + }) + + describe('Aggregator interface', () => { + beforeEach(async () => { + const timestamp = (await scrollUptimeFeed.latestTimestamp()).add(1000) + // Initialise a round + await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + }) + + it('should consume a known amount of gas for getRoundData(uint80) @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.getRoundData(1), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 30952, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestRoundData() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestRoundData(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28523, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestAnswer() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestAnswer(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28229, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestTimestamp() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestTimestamp(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28129, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestRound() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestRound(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28145, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for getAnswer(roundId) @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.getAnswer(1), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 30682, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for getTimestamp(roundId) @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.getTimestamp(1), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 30570, + gasUsedDeviation, + ) + }) + }) + }) +}) diff --git a/contracts/test/v0.8/dev/ScrollValidator.test.ts b/contracts/test/v0.8/dev/ScrollValidator.test.ts new file mode 100644 index 0000000000..866d52b202 --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollValidator.test.ts @@ -0,0 +1,118 @@ +import { ethers } from 'hardhat' +import { BigNumber, Contract, ContractFactory } from 'ethers' +import { expect } from 'chai' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' + +describe('ScrollValidator', () => { + const GAS_LIMIT = BigNumber.from(1_900_000) + /** Fake L2 target */ + const L2_SEQ_STATUS_RECORDER_ADDRESS = + '0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b' + let scrollValidator: Contract + let scrollUptimeFeedFactory: ContractFactory + let mockScrollL1CrossDomainMessenger: Contract + let deployer: SignerWithAddress + let eoaValidator: SignerWithAddress + + before(async () => { + const accounts = await ethers.getSigners() + deployer = accounts[0] + eoaValidator = accounts[1] + }) + + beforeEach(async () => { + // Required for building the calldata + scrollUptimeFeedFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol:ScrollSequencerUptimeFeed', + deployer, + ) + + // Scroll Messenger contract on L1 + const mockScrollL1CrossDomainMessengerFactory = + await ethers.getContractFactory( + 'src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol:MockScrollL1CrossDomainMessenger', + ) + mockScrollL1CrossDomainMessenger = + await mockScrollL1CrossDomainMessengerFactory.deploy() + + // Contract under test + const scrollValidatorFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollValidator.sol:ScrollValidator', + deployer, + ) + + scrollValidator = await scrollValidatorFactory.deploy( + mockScrollL1CrossDomainMessenger.address, + L2_SEQ_STATUS_RECORDER_ADDRESS, + GAS_LIMIT, + ) + }) + + describe('#setGasLimit', () => { + it('correctly updates the gas limit', async () => { + const newGasLimit = BigNumber.from(2_000_000) + const tx = await scrollValidator.setGasLimit(newGasLimit) + await tx.wait() + const currentGasLimit = await scrollValidator.getGasLimit() + expect(currentGasLimit).to.equal(newGasLimit) + }) + }) + + describe('#validate', () => { + it('reverts if called by account with no access', async () => { + await expect( + scrollValidator.connect(eoaValidator).validate(0, 0, 1, 1), + ).to.be.revertedWith('No access') + }) + + it('posts sequencer status when there is not status change', async () => { + await scrollValidator.addAccess(eoaValidator.address) + + const currentBlock = await ethers.provider.getBlock('latest') + const futureTimestamp = currentBlock.timestamp + 5000 + + await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) + const sequencerStatusRecorderCallData = + scrollUptimeFeedFactory.interface.encodeFunctionData('updateStatus', [ + false, + futureTimestamp, + ]) + + await expect(scrollValidator.connect(eoaValidator).validate(0, 0, 0, 0)) + .to.emit(mockScrollL1CrossDomainMessenger, 'SentMessage') + .withArgs( + scrollValidator.address, // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + GAS_LIMIT, // gas limit + sequencerStatusRecorderCallData, // message + ) + }) + + it('post sequencer offline', async () => { + await scrollValidator.addAccess(eoaValidator.address) + + const currentBlock = await ethers.provider.getBlock('latest') + const futureTimestamp = currentBlock.timestamp + 10000 + + await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) + const sequencerStatusRecorderCallData = + scrollUptimeFeedFactory.interface.encodeFunctionData('updateStatus', [ + true, + futureTimestamp, + ]) + + await expect(scrollValidator.connect(eoaValidator).validate(0, 0, 1, 1)) + .to.emit(mockScrollL1CrossDomainMessenger, 'SentMessage') + .withArgs( + scrollValidator.address, // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + GAS_LIMIT, // gas limit + sequencerStatusRecorderCallData, // message + ) + }) + }) +}) From 35ad7d164a29409e60a9896434df5685bc8f2a59 Mon Sep 17 00:00:00 2001 From: Domino Valdano <2644901+reductionista@users.noreply.github.com> Date: Tue, 12 Dec 2023 13:11:14 -0800 Subject: [PATCH 302/327] Handle edge case involving blocks not being found in the db (#11298) If there is a backfill followed by an error, logs get written to the db but no blocks. This will make the logpoller (or backup log poller) rely on the chain next time instead of the db to determine lastFinalizedBlock, which could result in a gap in logs processed. Fixing this by writing the last block in the backfil to the db along with the logs. Its lastFinalizedBlock field will be set to its own block number + 1, so if the db crashes it should start by pulling the logs from that one. --- core/chains/evm/logpoller/log_poller.go | 2 +- core/chains/evm/logpoller/log_poller_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index fb380f84b2..1cf1cf42be 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -679,7 +679,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } lp.lggr.Debugw("Backfill found logs", "from", from, "to", to, "logs", len(gethLogs), "blocks", blocks) - err = lp.orm.InsertLogs(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), pg.WithParentCtx(ctx)) + err = lp.orm.InsertLogsWithBlock(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), blocks[len(blocks)-1], pg.WithParentCtx(ctx)) if err != nil { lp.lggr.Warnw("Unable to insert logs, retrying", "err", err, "from", from, "to", to) return err diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 82447bdb5f..6c4dd381b5 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -965,8 +965,8 @@ func TestLogPoller_PollAndSaveLogs(t *testing.T) { lgs, err = th.ORM.SelectLogsByBlockRange(11, 17) require.NoError(t, err) assert.Equal(t, 7, len(lgs)) - th.assertHaveCanonical(t, 15, 16) - th.assertDontHave(t, 11, 14) // Do not expect to save backfilled blocks. + th.assertHaveCanonical(t, 14, 16) // Should have last finalized block plus unfinalized blocks + th.assertDontHave(t, 11, 13) // Should not have older finalized blocks // Verify that a custom block timestamp will get written to db correctly also b, err = th.Client.BlockByNumber(testutils.Context(t), nil) @@ -1057,8 +1057,8 @@ func TestLogPoller_PollAndSaveLogsDeepReorg(t *testing.T) { require.NoError(t, err) assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000002`), lgs[0].Data) th.assertHaveCanonical(t, 1, 1) - th.assertDontHave(t, 2, 5) // These blocks are backfilled - th.assertHaveCanonical(t, 6, 10) + th.assertDontHave(t, 2, 3) // These blocks are backfilled + th.assertHaveCanonical(t, 5, 10) }) } } From a8d096cc69b49cd2f8fc0672b819ccd8b5b38048 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Tue, 12 Dec 2023 23:18:34 +0200 Subject: [PATCH 303/327] Remove big from core utils (#11511) * Change difficulty from Big to BigInt * Fix headtracker mock head * Remove EsnureClosed * Fix mock heads * Migrate to common Mailbox * Fix Tracker close on txm * Change to EnsureHexPrefix * Change names to mailbox * Remove core/null dependency from common * Remove core mailbox * Fix dependencies * Tidy * Fix dependencies * Change path to internal utils * Minor fixes * Implement skeleton interfaces, structs, & methods for ChainReader EVM POC - Read ChainReader config in from RelayConfig - Add some initialization and validation relay skeletons - Use medianProviderWrapper instead of passing medianContract separately This avoids us having to modify the signature of NewMedianFactory, which would require further modifications to all non-evm repos and chainlink-relay - Add chain_reader_test.go with some basic relay tests Co-authored-by: Jordan Krage - Add chain reader config validation - Add chain reader config validation tests - Add config for chain reader median contract to cr validation testcases - Add unimplemented Encode(), Decode(), GetMaxEncodingSize(), GetMaxDecodingSize() - Add ChainReader() method to mock provider for plugin test - Rename relaymercury.ChainReader to MercuryChainReader, resolve name collisions - Add tests for errors during ChainReader construction - Propagate InvalidConfig & any other errors back to client We should ignore Unimplemented until node ops have been given ample time to migrate to the new job spec (including a section for ChainReader config) so that we can remove the old product-specific MedianContract component from MedianProvider. All other errors we can immediately start passing back to the client, letting the core node decide how to handle them (eg. displaying an "invalid job spec" message to the UI if the RelayConfig was invalid or the ContractID missing) * Update relay versions * Big migration * Simplify chain reader config validation * Rename MinKey function * Remove big from utils * Fix dependencies * Minor fixes * Fix merge conflicts * Minor fixes --------- Co-authored-by: Domino Valdano <2644901+reductionista@users.noreply.github.com> Co-authored-by: ilija --- core/chains/evm/assets/assets.go | 6 +- core/chains/evm/assets/wei.go | 10 +-- core/chains/evm/client/chain_id_sub.go | 4 +- core/chains/evm/client/chain_id_sub_test.go | 4 +- core/chains/evm/client/client.go | 5 +- core/chains/evm/client/node_lifecycle.go | 5 +- core/chains/evm/client/pool.go | 2 +- core/chains/evm/client/rpc_client.go | 5 +- .../evm/client/send_only_node_lifecycle.go | 2 +- .../evm/client/simulated_backend_client.go | 8 +-- core/chains/evm/config/config_test.go | 16 ++--- core/chains/evm/config/toml/config.go | 8 +-- core/chains/evm/config/toml/defaults.go | 14 ++-- core/chains/evm/forwarders/forwarder.go | 4 +- .../evm/forwarders/forwarder_manager.go | 7 +- .../evm/forwarders/forwarder_manager_test.go | 12 ++-- core/chains/evm/forwarders/mocks/orm.go | 29 ++++---- core/chains/evm/forwarders/orm.go | 14 ++-- core/chains/evm/forwarders/orm_test.go | 4 +- .../evm/gas/block_history_estimator_test.go | 15 ++-- .../evm/headtracker/head_broadcaster_test.go | 5 +- .../evm/headtracker/head_tracker_test.go | 9 +-- core/chains/evm/headtracker/heads_test.go | 5 +- core/chains/evm/headtracker/orm.go | 6 +- core/chains/evm/log/orm.go | 7 +- core/chains/evm/logpoller/log_poller.go | 3 +- core/chains/evm/logpoller/log_poller_test.go | 5 +- core/chains/evm/logpoller/models.go | 6 +- .../evm/logpoller/observability_test.go | 3 +- core/chains/evm/logpoller/orm.go | 16 ++--- core/chains/evm/logpoller/orm_test.go | 69 ++++++++++--------- core/chains/evm/logpoller/query.go | 4 +- core/chains/evm/logpoller/query_test.go | 3 +- core/chains/evm/txmgr/broadcaster_test.go | 3 +- core/chains/evm/txmgr/evm_tx_store.go | 6 +- core/chains/evm/txmgr/resender_test.go | 4 +- core/chains/evm/txmgr/tracker_test.go | 6 +- core/chains/evm/txmgr/txmgr_test.go | 5 +- core/chains/evm/types/models.go | 5 +- core/chains/evm/types/types.go | 3 +- core/{utils => chains/evm/utils/big}/big.go | 21 +++--- .../evm/utils/big}/big_test.go | 14 ++-- core/chains/evm/utils/utils.go | 37 ++++++++++ core/chains/legacyevm/chain.go | 4 +- core/cmd/blocks_commands_test.go | 4 +- core/cmd/eth_keys_commands_test.go | 3 +- core/cmd/evm_chains_commands_test.go | 6 +- core/cmd/evm_transaction_commands.go | 3 +- core/cmd/forwarders_commands.go | 4 +- core/cmd/forwarders_commands_test.go | 3 +- core/cmd/ocr2vrf_configure_commands.go | 3 +- core/cmd/shell_local.go | 3 +- core/internal/cltest/cltest.go | 21 +++--- core/internal/cltest/factories.go | 17 ++--- core/internal/cltest/simulated_backend.go | 6 +- core/internal/features/features_test.go | 5 +- .../features/ocr2/features_ocr2_test.go | 4 +- .../testutils/configtest/general_config.go | 8 +-- core/internal/testutils/evmtest/evmtest.go | 6 +- core/internal/testutils/evmtest/v2/evmtest.go | 4 +- core/scripts/functions/src/fetching.go | 3 +- core/services/blockhashstore/delegate_test.go | 10 +-- core/services/blockhashstore/validate_test.go | 4 +- .../blockheaderfeeder/validate_test.go | 6 +- core/services/chainlink/config.go | 4 +- core/services/chainlink/config_test.go | 11 +-- .../relayer_chain_interoperators_test.go | 6 +- core/services/directrequest/delegate_test.go | 4 +- core/services/directrequest/validate.go | 4 +- core/services/feeds/service.go | 4 +- core/services/feeds/service_test.go | 4 +- core/services/fluxmonitorv2/orm_test.go | 4 +- core/services/job/job_orm_test.go | 14 ++-- core/services/job/mocks/orm.go | 15 ++-- core/services/job/models.go | 29 ++++---- core/services/job/orm.go | 6 +- core/services/keeper/integration_test.go | 8 +-- core/services/keeper/models.go | 9 +-- core/services/keeper/models_test.go | 4 +- core/services/keeper/orm.go | 10 +-- core/services/keeper/orm_test.go | 13 ++-- .../keeper/registry1_1_synchronizer_test.go | 4 +- .../keeper/registry1_3_synchronizer_test.go | 6 +- .../registry_synchronizer_process_logs.go | 20 +++--- .../keeper/registry_synchronizer_sync.go | 17 ++--- .../keeper/registry_synchronizer_sync_test.go | 4 +- core/services/keeper/upkeep_executer_test.go | 15 ++-- .../keeper/upkeep_executer_unit_test.go | 4 +- core/services/keystore/eth_test.go | 3 +- core/services/keystore/keys/ethkey/models.go | 4 +- core/services/ocr/database.go | 6 +- core/services/ocr2/delegate_test.go | 4 +- .../evmregistry/v20/registry_test.go | 6 +- .../v21/logprovider/recoverer_test.go | 4 +- .../evmregistry/v21/registry_test.go | 6 +- .../evmregistry/v21/upkeepstate/orm.go | 12 ++-- .../evmregistry/v21/upkeepstate/orm_test.go | 4 +- .../evmregistry/v21/upkeepstate/store.go | 3 +- .../plugins/ocr2keeper/integration_test.go | 4 +- .../internal/ocr2vrf_integration_test.go | 3 +- .../ocr2/plugins/s4/integration_test.go | 6 +- core/services/ocr2/plugins/s4/messages.go | 6 +- core/services/ocr2/plugins/s4/plugin.go | 4 +- core/services/ocr2/plugins/s4/plugin_test.go | 8 +-- core/services/ocrcommon/telemetry_test.go | 5 +- core/services/pipeline/orm_test.go | 5 +- .../promreporter/prom_reporter_test.go | 3 +- core/services/relay/evm/median_test.go | 4 +- .../relay/evm/relayer_extender_test.go | 4 +- core/services/relay/evm/types/types.go | 4 +- core/services/relay/evm/types/types_test.go | 2 +- core/services/s4/address_range.go | 28 ++++---- core/services/s4/address_range_test.go | 8 +-- core/services/s4/in_memory_orm.go | 6 +- core/services/s4/in_memory_orm_test.go | 16 ++--- core/services/s4/mocks/orm.go | 15 ++-- core/services/s4/orm.go | 10 +-- core/services/s4/postgres_orm.go | 4 +- core/services/s4/postgres_orm_test.go | 4 +- core/services/s4/storage.go | 7 +- core/services/s4/storage_test.go | 9 +-- core/services/vrf/delegate_test.go | 2 +- core/services/vrf/v1/integration_test.go | 6 +- .../vrf/v2/integration_helpers_test.go | 5 +- core/services/vrf/v2/integration_v2_test.go | 3 +- .../vrf/v2/listener_v2_log_listener_test.go | 5 +- core/store/migrate/migrate_test.go | 8 +-- core/store/models/common.go | 4 +- core/web/eth_keys_controller.go | 4 +- core/web/evm_chains_controller_test.go | 10 +-- core/web/evm_forwarders_controller.go | 4 +- core/web/evm_forwarders_controller_test.go | 5 +- core/web/evm_transfer_controller_test.go | 18 ++--- core/web/loader/loader_test.go | 5 +- core/web/presenters/eth_key.go | 8 +-- core/web/presenters/eth_key_test.go | 8 +-- core/web/presenters/eth_tx.go | 8 +-- core/web/presenters/evm_forwarder.go | 4 +- core/web/presenters/job.go | 16 ++--- core/web/presenters/job_test.go | 8 +-- core/web/replay_controller.go | 8 +-- core/web/resolver/chain_test.go | 6 +- core/web/resolver/eth_key_test.go | 22 +++--- core/web/resolver/eth_transaction_test.go | 4 +- core/web/resolver/node_test.go | 4 +- core/web/resolver/spec_test.go | 18 ++--- integration-tests/client/chainlink_models.go | 6 +- integration-tests/types/config/node/core.go | 5 +- 148 files changed, 636 insertions(+), 550 deletions(-) rename core/{utils => chains/evm/utils/big}/big.go (91%) rename core/{utils => chains/evm/utils/big}/big_test.go (95%) create mode 100644 core/chains/evm/utils/utils.go diff --git a/core/chains/evm/assets/assets.go b/core/chains/evm/assets/assets.go index 377e92a855..738ba5c817 100644 --- a/core/chains/evm/assets/assets.go +++ b/core/chains/evm/assets/assets.go @@ -7,7 +7,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/shopspring/decimal" ) @@ -108,10 +108,10 @@ func (e *Eth) ToInt() *big.Int { // Scan reads the database value and returns an instance. func (e *Eth) Scan(value interface{}) error { - return (*utils.Big)(e).Scan(value) + return (*ubig.Big)(e).Scan(value) } // Value returns the Eth value for serialization to database. func (e Eth) Value() (driver.Value, error) { - return (utils.Big)(e).Value() + return (ubig.Big)(e).Value() } diff --git a/core/chains/evm/assets/wei.go b/core/chains/evm/assets/wei.go index be0143b3a8..8bacabfdb4 100644 --- a/core/chains/evm/assets/wei.go +++ b/core/chains/evm/assets/wei.go @@ -11,7 +11,7 @@ import ( "golang.org/x/exp/constraints" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) const ( @@ -58,10 +58,10 @@ func suffixExp(suf string) int32 { } } -// Wei extends utils.Big to implement encoding.TextMarshaler and +// Wei extends ubig.Big to implement encoding.TextMarshaler and // encoding.TextUnmarshaler with support for unit suffixes, as well as // additional functions -type Wei utils.Big +type Wei ubig.Big func MaxWei(w, x *Wei) *Wei { return NewWei(bigmath.Max(w.ToInt(), x.ToInt())) @@ -271,10 +271,10 @@ func (w *Wei) AddPercentage(percentage uint16) *Wei { // Scan reads the database value and returns an instance. func (w *Wei) Scan(value interface{}) error { - return (*utils.Big)(w).Scan(value) + return (*ubig.Big)(w).Scan(value) } // Value returns this instance serialized for database storage. func (w Wei) Value() (driver.Value, error) { - return (utils.Big)(w).Value() + return (ubig.Big)(w).Value() } diff --git a/core/chains/evm/client/chain_id_sub.go b/core/chains/evm/client/chain_id_sub.go index 8ea4e20797..c3162b300c 100644 --- a/core/chains/evm/client/chain_id_sub.go +++ b/core/chains/evm/client/chain_id_sub.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) var _ ethereum.Subscription = &chainIDSubForwarder{} @@ -64,7 +64,7 @@ func (c *chainIDSubForwarder) forwardLoop() { return case h := <-c.srcCh: - h.EVMChainID = utils.NewBig(c.chainID) + h.EVMChainID = ubig.New(c.chainID) select { case c.destCh <- h: case <-c.unSub: diff --git a/core/chains/evm/client/chain_id_sub_test.go b/core/chains/evm/client/chain_id_sub_test.go index 211ba812fb..c71b45c489 100644 --- a/core/chains/evm/client/chain_id_sub_test.go +++ b/core/chains/evm/client/chain_id_sub_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type mockSubscription struct { @@ -111,7 +111,7 @@ func TestChainIDSubForwarder(t *testing.T) { forwarder.srcCh <- head receivedHead := <-ch assert.Equal(t, head, receivedHead) - assert.Equal(t, utils.NewBig(chainID), receivedHead.EVMChainID) + assert.Equal(t, ubig.New(chainID), receivedHead.EVMChainID) expectedErr := errors.New("error") sub.Errors <- expectedErr diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index 688cc3c9be..b85331a62a 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/config" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum" @@ -286,7 +287,7 @@ func (client *client) HeadByNumber(ctx context.Context, number *big.Int) (head * err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(client.ConfiguredChainID()) + head.EVMChainID = ubig.New(client.ConfiguredChainID()) return } @@ -299,7 +300,7 @@ func (client *client) HeadByHash(ctx context.Context, hash common.Hash) (head *e err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(client.ConfiguredChainID()) + head.EVMChainID = ubig.New(client.ConfiguredChainID()) return } diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index f838325a64..4e984de00f 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -12,10 +12,11 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/logger" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) var ( @@ -50,7 +51,7 @@ func zombieNodeCheckInterval(noNewHeadsThreshold time.Duration) time.Duration { if interval <= 0 || interval > queryTimeout { interval = queryTimeout } - return utils.WithJitter(interval) + return cutils.WithJitter(interval) } func (n *node) setLatestReceived(blockNumber int64, totalDifficulty *big.Int) { diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 6c36cc3e98..afe592533c 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -17,10 +17,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/common/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index 01851c4ae9..3cc90c4d8d 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -24,6 +24,7 @@ import ( commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -491,7 +492,7 @@ func (r *rpcClient) BlockByNumber(ctx context.Context, number *big.Int) (head *e err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(r.chainID) + head.EVMChainID = ubig.New(r.chainID) return } @@ -504,7 +505,7 @@ func (r *rpcClient) BlockByHash(ctx context.Context, hash common.Hash) (head *ev err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(r.chainID) + head.EVMChainID = ubig.New(r.chainID) return } diff --git a/core/chains/evm/client/send_only_node_lifecycle.go b/core/chains/evm/client/send_only_node_lifecycle.go index 9d704e4938..127a5c6678 100644 --- a/core/chains/evm/client/send_only_node_lifecycle.go +++ b/core/chains/evm/client/send_only_node_lifecycle.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) // verifyLoop may only be triggered once, on Start, if initial chain ID check diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 293bf64bad..bd2e959d9b 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -23,7 +23,7 @@ import ( commonclient "github.com/smartcontractkit/chainlink/v2/common/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func init() { @@ -197,7 +197,7 @@ func (c *SimulatedBackendClient) HeadByNumber(ctx context.Context, n *big.Int) ( return nil, ethereum.NotFound } return &evmtypes.Head{ - EVMChainID: utils.NewBigI(c.chainId.Int64()), + EVMChainID: ubig.NewI(c.chainId.Int64()), Hash: header.Hash(), Number: header.Number.Int64(), ParentHash: header.ParentHash, @@ -214,7 +214,7 @@ func (c *SimulatedBackendClient) HeadByHash(ctx context.Context, h common.Hash) return nil, ethereum.NotFound } return &evmtypes.Head{ - EVMChainID: utils.NewBigI(c.chainId.Int64()), + EVMChainID: ubig.NewI(c.chainId.Int64()), Hash: header.Hash(), Number: header.Number.Int64(), ParentHash: header.ParentHash, @@ -302,7 +302,7 @@ func (c *SimulatedBackendClient) SubscribeNewHead( case h := <-ch: var head *evmtypes.Head if h != nil { - head = &evmtypes.Head{Difficulty: 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)} + head = &evmtypes.Head{Difficulty: h.Difficulty, Timestamp: time.Unix(int64(h.Time), 0), Number: h.Number.Int64(), Hash: h.Hash(), ParentHash: h.ParentHash, Parent: lastHead, EVMChainID: ubig.New(c.chainId)} lastHead = head } select { diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index d34d1eae63..0127328239 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -14,6 +14,7 @@ import ( commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -21,13 +22,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestChainScopedConfig(t *testing.T) { t.Parallel() gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{ @@ -38,7 +38,7 @@ func TestChainScopedConfig(t *testing.T) { cfg := evmtest.NewChainScopedConfig(t, gcfg) overrides := func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{ @@ -65,7 +65,7 @@ func TestChainScopedConfig(t *testing.T) { t.Run("uses customer configured value when set", func(t *testing.T) { var override uint32 = 10 gasBumpOverrides := func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{ @@ -292,7 +292,7 @@ func TestChainScopedConfig_GasEstimator(t *testing.T) { func TestChainScopedConfig_BSCDefaults(t *testing.T) { chainID := big.NewInt(56) gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, secrets *chainlink.Secrets) { - id := utils.NewBig(chainID) + id := ubig.New(chainID) cfg := toml.Defaults(id) c.EVM[0] = &toml.EVMConfig{ ChainID: id, @@ -344,7 +344,7 @@ func TestChainScopedConfig_Profiles(t *testing.T) { t.Parallel() gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, secrets *chainlink.Secrets) { - id := utils.NewBigI(tt.chainID) + id := ubig.NewI(tt.chainID) cfg := toml.Defaults(id) c.EVM[0] = &toml.EVMConfig{ ChainID: id, @@ -379,7 +379,7 @@ func TestChainScopedConfig_HeadTracker(t *testing.T) { func Test_chainScopedConfig_Validate(t *testing.T) { configWithChains := func(t *testing.T, id int64, chains ...*toml.Chain) config.AppConfig { return configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - chainID := utils.NewBigI(id) + chainID := ubig.NewI(id) c.EVM[0] = &toml.EVMConfig{ChainID: chainID, Enabled: ptr(true), Chain: toml.Defaults(chainID, chains...), Nodes: toml.EVMNodes{{ Name: ptr("fake"), @@ -462,7 +462,7 @@ func Test_chainScopedConfig_Validate(t *testing.T) { func TestNodePoolConfig(t *testing.T) { gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{}), diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index 9e51d5be79..16ad74dbca 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -19,10 +19,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -161,7 +161,7 @@ func (cs EVMConfigs) NodeStatus(name string) (commontypes.NodeStatus, error) { return commontypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) } -func legacyNode(n *Node, chainID *utils.Big) (v2 types.Node) { +func legacyNode(n *Node, chainID *big.Big) (v2 types.Node) { v2.Name = *n.Name v2.EVMChainID = *chainID if n.HTTPURL != nil { @@ -215,7 +215,7 @@ func (cs EVMConfigs) Nodes(chainID relay.ChainID) (ns []types.Node, err error) { continue } - ns = append(ns, legacyNode(n, utils.NewBigI(evmID))) + ns = append(ns, legacyNode(n, big.NewI(evmID))) } return } @@ -268,7 +268,7 @@ func (ns *EVMNodes) SetFrom(fs *EVMNodes) { } type EVMConfig struct { - ChainID *utils.Big + ChainID *big.Big Enabled *bool Chain Nodes EVMNodes diff --git a/core/chains/evm/config/toml/defaults.go b/core/chains/evm/config/toml/defaults.go index d362e9ac3d..27127993d8 100644 --- a/core/chains/evm/config/toml/defaults.go +++ b/core/chains/evm/config/toml/defaults.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/smartcontractkit/chainlink/v2/common/config" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -21,7 +21,7 @@ var ( defaultNames = map[string]string{} // DefaultIDs is the set of chain ids which have defaults. - DefaultIDs []*utils.Big + DefaultIDs []*big.Big ) func init() { @@ -36,7 +36,7 @@ func init() { log.Fatalf("failed to read %q: %v", path, err) } var config = struct { - ChainID *utils.Big + ChainID *big.Big Chain }{} @@ -61,13 +61,13 @@ func init() { defaults[id] = config.Chain defaultNames[id] = strings.ReplaceAll(strings.TrimSuffix(fe.Name(), ".toml"), "_", " ") } - slices.SortFunc(DefaultIDs, func(a, b *utils.Big) int { + slices.SortFunc(DefaultIDs, func(a, b *big.Big) int { return a.Cmp(b) }) } // DefaultsNamed returns the default Chain values, optionally for the given chainID, as well as a name if the chainID is known. -func DefaultsNamed(chainID *utils.Big) (c Chain, name string) { +func DefaultsNamed(chainID *big.Big) (c Chain, name string) { c.SetFrom(&fallback) if chainID == nil { return @@ -82,7 +82,7 @@ func DefaultsNamed(chainID *utils.Big) (c Chain, name string) { // Defaults returns a Chain based on the defaults for chainID and fields from with, applied in order so later Chains // override earlier ones. -func Defaults(chainID *utils.Big, with ...*Chain) Chain { +func Defaults(chainID *big.Big, with ...*Chain) Chain { c, _ := DefaultsNamed(chainID) for _, w := range with { c.SetFrom(w) @@ -90,7 +90,7 @@ func Defaults(chainID *utils.Big, with ...*Chain) Chain { return c } -func ChainTypeForID(chainID *utils.Big) (config.ChainType, bool) { +func ChainTypeForID(chainID *big.Big) (config.ChainType, bool) { s := chainID.String() if d, ok := defaults[s]; ok { if d.ChainType == nil { diff --git a/core/chains/evm/forwarders/forwarder.go b/core/chains/evm/forwarders/forwarder.go index 0221c39e0a..a0f6334a2c 100644 --- a/core/chains/evm/forwarders/forwarder.go +++ b/core/chains/evm/forwarders/forwarder.go @@ -5,14 +5,14 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // Forwarder is the struct for Forwarder Addresses type Forwarder struct { ID int64 Address common.Address - EVMChainID utils.Big + EVMChainID big.Big CreatedAt time.Time UpdatedAt time.Time } diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index eaf0c32afe..03792966fe 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -14,15 +14,16 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmlogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var forwardABI = evmtypes.MustGetABI(authorized_forwarder.AuthorizedForwarderABI).Methods["forward"] @@ -79,7 +80,7 @@ func (f *FwdMgr) Start(ctx context.Context) error { f.logger.Debug("Initializing EVM forwarder manager") chainId := f.evmClient.ConfiguredChainID() - fwdrs, err := f.ORM.FindForwardersByChain(utils.Big(*chainId)) + fwdrs, err := f.ORM.FindForwardersByChain(big.Big(*chainId)) if err != nil { return errors.Wrapf(err, "Failed to retrieve forwarders for chain %d", chainId) } @@ -112,7 +113,7 @@ func FilterName(addr common.Address) string { func (f *FwdMgr) ForwarderFor(addr common.Address) (forwarder common.Address, err error) { // Gets forwarders for current chain. - fwdrs, err := f.ORM.FindForwardersByChain(utils.Big(*f.evmClient.ConfiguredChainID())) + fwdrs, err := f.ORM.FindForwardersByChain(big.Big(*f.evmClient.ConfiguredChainID())) if err != nil { return common.Address{}, err } diff --git a/core/chains/evm/forwarders/forwarder_manager_test.go b/core/chains/evm/forwarders/forwarder_manager_test.go index 1da638e743..5ef150aa5c 100644 --- a/core/chains/evm/forwarders/forwarder_manager_test.go +++ b/core/chains/evm/forwarders/forwarder_manager_test.go @@ -12,10 +12,13 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" @@ -24,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var GetAuthorisedSendersABI = evmtypes.MustGetABI(authorized_receiver.AuthorizedReceiverABI).Methods["getAuthorizedSenders"] @@ -62,9 +64,9 @@ func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) fwdMgr.ORM = forwarders.NewORM(db, logger.Test(t), cfg.Database()) - fwd, err := fwdMgr.ORM.CreateForwarder(forwarderAddr, utils.Big(*testutils.FixtureChainID)) + fwd, err := fwdMgr.ORM.CreateForwarder(forwarderAddr, ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) - lst, err := fwdMgr.ORM.FindForwardersByChain(utils.Big(*testutils.FixtureChainID)) + lst, err := fwdMgr.ORM.FindForwardersByChain(ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) require.Equal(t, len(lst), 1) require.Equal(t, lst[0].Address, forwarderAddr) @@ -115,9 +117,9 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) { fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) fwdMgr.ORM = forwarders.NewORM(db, logger.Test(t), cfg.Database()) - _, err = fwdMgr.ORM.CreateForwarder(forwarderAddr, utils.Big(*testutils.FixtureChainID)) + _, err = fwdMgr.ORM.CreateForwarder(forwarderAddr, ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) - lst, err := fwdMgr.ORM.FindForwardersByChain(utils.Big(*testutils.FixtureChainID)) + lst, err := fwdMgr.ORM.FindForwardersByChain(ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) require.Equal(t, len(lst), 1) require.Equal(t, lst[0].Address, forwarderAddr) diff --git a/core/chains/evm/forwarders/mocks/orm.go b/core/chains/evm/forwarders/mocks/orm.go index c06a04b8eb..691fbce8e9 100644 --- a/core/chains/evm/forwarders/mocks/orm.go +++ b/core/chains/evm/forwarders/mocks/orm.go @@ -4,12 +4,13 @@ package mocks import ( common "github.com/ethereum/go-ethereum/common" + big "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + forwarders "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + mock "github.com/stretchr/testify/mock" pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - - utils "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM is an autogenerated mock type for the ORM type @@ -18,7 +19,7 @@ type ORM struct { } // CreateForwarder provides a mock function with given fields: addr, evmChainId -func (_m *ORM) CreateForwarder(addr common.Address, evmChainId utils.Big) (forwarders.Forwarder, error) { +func (_m *ORM) CreateForwarder(addr common.Address, evmChainId big.Big) (forwarders.Forwarder, error) { ret := _m.Called(addr, evmChainId) if len(ret) == 0 { @@ -27,16 +28,16 @@ func (_m *ORM) CreateForwarder(addr common.Address, evmChainId utils.Big) (forwa var r0 forwarders.Forwarder var r1 error - if rf, ok := ret.Get(0).(func(common.Address, utils.Big) (forwarders.Forwarder, error)); ok { + if rf, ok := ret.Get(0).(func(common.Address, big.Big) (forwarders.Forwarder, error)); ok { return rf(addr, evmChainId) } - if rf, ok := ret.Get(0).(func(common.Address, utils.Big) forwarders.Forwarder); ok { + if rf, ok := ret.Get(0).(func(common.Address, big.Big) forwarders.Forwarder); ok { r0 = rf(addr, evmChainId) } else { r0 = ret.Get(0).(forwarders.Forwarder) } - if rf, ok := ret.Get(1).(func(common.Address, utils.Big) error); ok { + if rf, ok := ret.Get(1).(func(common.Address, big.Big) error); ok { r1 = rf(addr, evmChainId) } else { r1 = ret.Error(1) @@ -101,7 +102,7 @@ func (_m *ORM) FindForwarders(offset int, limit int) ([]forwarders.Forwarder, in } // FindForwardersByChain provides a mock function with given fields: evmChainId -func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forwarder, error) { +func (_m *ORM) FindForwardersByChain(evmChainId big.Big) ([]forwarders.Forwarder, error) { ret := _m.Called(evmChainId) if len(ret) == 0 { @@ -110,10 +111,10 @@ func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forward var r0 []forwarders.Forwarder var r1 error - if rf, ok := ret.Get(0).(func(utils.Big) ([]forwarders.Forwarder, error)); ok { + if rf, ok := ret.Get(0).(func(big.Big) ([]forwarders.Forwarder, error)); ok { return rf(evmChainId) } - if rf, ok := ret.Get(0).(func(utils.Big) []forwarders.Forwarder); ok { + if rf, ok := ret.Get(0).(func(big.Big) []forwarders.Forwarder); ok { r0 = rf(evmChainId) } else { if ret.Get(0) != nil { @@ -121,7 +122,7 @@ func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forward } } - if rf, ok := ret.Get(1).(func(utils.Big) error); ok { + if rf, ok := ret.Get(1).(func(big.Big) error); ok { r1 = rf(evmChainId) } else { r1 = ret.Error(1) @@ -131,7 +132,7 @@ func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forward } // FindForwardersInListByChain provides a mock function with given fields: evmChainId, addrs -func (_m *ORM) FindForwardersInListByChain(evmChainId utils.Big, addrs []common.Address) ([]forwarders.Forwarder, error) { +func (_m *ORM) FindForwardersInListByChain(evmChainId big.Big, addrs []common.Address) ([]forwarders.Forwarder, error) { ret := _m.Called(evmChainId, addrs) if len(ret) == 0 { @@ -140,10 +141,10 @@ func (_m *ORM) FindForwardersInListByChain(evmChainId utils.Big, addrs []common. var r0 []forwarders.Forwarder var r1 error - if rf, ok := ret.Get(0).(func(utils.Big, []common.Address) ([]forwarders.Forwarder, error)); ok { + if rf, ok := ret.Get(0).(func(big.Big, []common.Address) ([]forwarders.Forwarder, error)); ok { return rf(evmChainId, addrs) } - if rf, ok := ret.Get(0).(func(utils.Big, []common.Address) []forwarders.Forwarder); ok { + if rf, ok := ret.Get(0).(func(big.Big, []common.Address) []forwarders.Forwarder); ok { r0 = rf(evmChainId, addrs) } else { if ret.Get(0) != nil { @@ -151,7 +152,7 @@ func (_m *ORM) FindForwardersInListByChain(evmChainId utils.Big, addrs []common. } } - if rf, ok := ret.Get(1).(func(utils.Big, []common.Address) error); ok { + if rf, ok := ret.Get(1).(func(big.Big, []common.Address) error); ok { r1 = rf(evmChainId, addrs) } else { r1 = ret.Error(1) diff --git a/core/chains/evm/forwarders/orm.go b/core/chains/evm/forwarders/orm.go index 104e257425..2a45536019 100644 --- a/core/chains/evm/forwarders/orm.go +++ b/core/chains/evm/forwarders/orm.go @@ -8,18 +8,18 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore type ORM interface { - CreateForwarder(addr common.Address, evmChainId utils.Big) (fwd Forwarder, err error) + CreateForwarder(addr common.Address, evmChainId big.Big) (fwd Forwarder, err error) FindForwarders(offset, limit int) ([]Forwarder, int, error) - FindForwardersByChain(evmChainId utils.Big) ([]Forwarder, error) + FindForwardersByChain(evmChainId big.Big) ([]Forwarder, error) DeleteForwarder(id int64, cleanup func(tx pg.Queryer, evmChainId int64, addr common.Address) error) error - FindForwardersInListByChain(evmChainId utils.Big, addrs []common.Address) ([]Forwarder, error) + FindForwardersInListByChain(evmChainId big.Big, addrs []common.Address) ([]Forwarder, error) } type orm struct { @@ -33,7 +33,7 @@ func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *orm { } // CreateForwarder creates the Forwarder address associated with the current EVM chain id. -func (o *orm) CreateForwarder(addr common.Address, evmChainId utils.Big) (fwd Forwarder, err error) { +func (o *orm) CreateForwarder(addr common.Address, evmChainId big.Big) (fwd Forwarder, err error) { sql := `INSERT INTO evm.forwarders (address, evm_chain_id, created_at, updated_at) VALUES ($1, $2, now(), now()) RETURNING *` err = o.q.Get(&fwd, sql, addr, evmChainId) return fwd, err @@ -93,13 +93,13 @@ func (o *orm) FindForwarders(offset, limit int) (fwds []Forwarder, count int, er } // FindForwardersByChain returns all forwarder addresses for a chain. -func (o *orm) FindForwardersByChain(evmChainId utils.Big) (fwds []Forwarder, err error) { +func (o *orm) FindForwardersByChain(evmChainId big.Big) (fwds []Forwarder, err error) { sql := `SELECT * FROM evm.forwarders where evm_chain_id = $1 ORDER BY created_at DESC, id DESC` err = o.q.Select(&fwds, sql, evmChainId) return } -func (o *orm) FindForwardersInListByChain(evmChainId utils.Big, addrs []common.Address) ([]Forwarder, error) { +func (o *orm) FindForwardersInListByChain(evmChainId big.Big, addrs []common.Address) ([]Forwarder, error) { var fwdrs []Forwarder arg := map[string]interface{}{ diff --git a/core/chains/evm/forwarders/orm_test.go b/core/chains/evm/forwarders/orm_test.go index ba9664c196..e95ac3778c 100644 --- a/core/chains/evm/forwarders/orm_test.go +++ b/core/chains/evm/forwarders/orm_test.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/jmoiron/sqlx" ) @@ -42,7 +42,7 @@ func Test_DeleteForwarder(t *testing.T) { addr := testutils.NewAddress() chainID := testutils.FixtureChainID - fwd, err := orm.CreateForwarder(addr, *utils.NewBig(chainID)) + fwd, err := orm.CreateForwarder(addr, *big.New(chainID)) require.NoError(t, err) assert.Equal(t, addr, fwd.Address) diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index d3edf212b6..43ea3e0bb7 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -25,6 +25,7 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -429,7 +430,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { elems[1].Result = &b42 }) - head := evmtypes.NewHead(big.NewInt(44), b44.Hash, b43.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head := evmtypes.NewHead(big.NewInt(44), b44.Hash, b43.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) err = bhe.FetchBlocks(testutils.Context(t), &head) require.NoError(t, err) @@ -493,8 +494,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { elems[1].Result = &b2 }) - head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) - head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, b2.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) + head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, b2.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) head3.Parent = &head2 err := bhe.FetchBlocks(testutils.Context(t), &head3) require.NoError(t, err) @@ -546,8 +547,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { gas.SetRollingBlockHistory(bhe, blocks) // RE-ORG, head2 and head3 have different hash than saved b2 and b3 - head2 := evmtypes.NewHead(big.NewInt(2), utils.NewHash(), b1.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) - head3 := evmtypes.NewHead(big.NewInt(3), utils.NewHash(), head2.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head2 := evmtypes.NewHead(big.NewInt(2), utils.NewHash(), b1.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) + head3 := evmtypes.NewHead(big.NewInt(3), utils.NewHash(), head2.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) head3.Parent = &head2 ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { @@ -617,8 +618,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { gas.SetRollingBlockHistory(bhe, blocks) // head2 and head3 have identical hash to saved blocks - head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) - head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, head2.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) + head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, head2.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) head3.Parent = &head2 err := bhe.FetchBlocks(testutils.Context(t), &head3) diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index b9fab9cdd4..21c864eda6 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -84,7 +85,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { assert.Equal(t, (*evmtypes.Head)(nil), latest1) headers := <-chchHeaders - h := evmtypes.Head{Number: 1, Hash: utils.NewHash(), ParentHash: utils.NewHash(), EVMChainID: utils.NewBig(&cltest.FixtureChainID)} + h := evmtypes.Head{Number: 1, Hash: utils.NewHash(), ParentHash: utils.NewHash(), EVMChainID: big.New(&cltest.FixtureChainID)} headers <- &h g.Eventually(checker1.OnNewLongestChainCount).Should(gomega.Equal(int32(1))) @@ -95,7 +96,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { unsubscribe1() - headers <- &evmtypes.Head{Number: 2, Hash: utils.NewHash(), ParentHash: h.Hash, EVMChainID: utils.NewBig(&cltest.FixtureChainID)} + headers <- &evmtypes.Head{Number: 2, Hash: utils.NewHash(), ParentHash: h.Hash, EVMChainID: big.New(&cltest.FixtureChainID)} g.Eventually(checker2.OnNewLongestChainCount).Should(gomega.Equal(int32(1))) } diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index d8abb1328a..67e76aee52 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -29,6 +29,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -258,7 +259,7 @@ func TestHeadTracker_CallsHeadTrackableCallbacks(t *testing.T) { assert.Equal(t, int32(0), checker.OnNewLongestChainCount()) headers := <-chchHeaders - headers.TrySend(&evmtypes.Head{Number: 1, Hash: utils.NewHash(), EVMChainID: utils.NewBig(&cltest.FixtureChainID)}) + headers.TrySend(&evmtypes.Head{Number: 1, Hash: utils.NewHash(), EVMChainID: ubig.New(&cltest.FixtureChainID)}) g.Eventually(checker.OnNewLongestChainCount).Should(gomega.Equal(int32(1))) ht.Stop(t) @@ -719,7 +720,7 @@ func TestHeadTracker_Backfill(t *testing.T) { ParentHash: gethCommon.BigToHash(big.NewInt(0)), Time: now, } - head0 := evmtypes.NewHead(gethHead0.Number, utils.NewHash(), gethHead0.ParentHash, gethHead0.Time, utils.NewBig(&cltest.FixtureChainID)) + head0 := evmtypes.NewHead(gethHead0.Number, utils.NewHash(), gethHead0.ParentHash, gethHead0.Time, ubig.New(&cltest.FixtureChainID)) h1 := *cltest.Head(1) h1.ParentHash = head0.Hash @@ -729,7 +730,7 @@ func TestHeadTracker_Backfill(t *testing.T) { ParentHash: utils.NewHash(), Time: now, } - head8 := evmtypes.NewHead(gethHead8.Number, utils.NewHash(), gethHead8.ParentHash, gethHead8.Time, utils.NewBig(&cltest.FixtureChainID)) + head8 := evmtypes.NewHead(gethHead8.Number, utils.NewHash(), gethHead8.ParentHash, gethHead8.Time, ubig.New(&cltest.FixtureChainID)) h9 := *cltest.Head(9) h9.ParentHash = head8.Hash @@ -739,7 +740,7 @@ func TestHeadTracker_Backfill(t *testing.T) { ParentHash: h9.Hash, Time: now, } - head10 := evmtypes.NewHead(gethHead10.Number, utils.NewHash(), gethHead10.ParentHash, gethHead10.Time, utils.NewBig(&cltest.FixtureChainID)) + head10 := evmtypes.NewHead(gethHead10.Number, utils.NewHash(), gethHead10.ParentHash, gethHead10.Time, ubig.New(&cltest.FixtureChainID)) h11 := *cltest.Head(11) h11.ParentHash = head10.Hash diff --git a/core/chains/evm/headtracker/heads_test.go b/core/chains/evm/headtracker/heads_test.go index 7da6b1cc9b..11c1bfd4f7 100644 --- a/core/chains/evm/headtracker/heads_test.go +++ b/core/chains/evm/headtracker/heads_test.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -77,11 +78,11 @@ func TestHeads_AddHeads(t *testing.T) { var parentHash common.Hash for i := 0; i < 5; i++ { hash := utils.NewHash() - h := evmtypes.NewHead(big.NewInt(int64(i)), hash, parentHash, uint64(time.Now().Unix()), utils.NewBigI(0)) + h := evmtypes.NewHead(big.NewInt(int64(i)), hash, parentHash, uint64(time.Now().Unix()), ubig.NewI(0)) testHeads = append(testHeads, &h) if i == 2 { // uncled block - h := evmtypes.NewHead(big.NewInt(int64(i)), uncleHash, parentHash, uint64(time.Now().Unix()), utils.NewBigI(0)) + h := evmtypes.NewHead(big.NewInt(int64(i)), uncleHash, parentHash, uint64(time.Now().Unix()), ubig.NewI(0)) testHeads = append(testHeads, &h) } parentHash = hash diff --git a/core/chains/evm/headtracker/orm.go b/core/chains/evm/headtracker/orm.go index 88d569b9a2..859f6764b6 100644 --- a/core/chains/evm/headtracker/orm.go +++ b/core/chains/evm/headtracker/orm.go @@ -12,8 +12,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ORM interface { @@ -32,11 +32,11 @@ type ORM interface { type orm struct { q pg.Q - chainID utils.Big + chainID ubig.Big } func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, chainID big.Int) ORM { - return &orm{pg.NewQ(db, logger.Named(lggr, "HeadTrackerORM"), cfg), utils.Big(chainID)} + return &orm{pg.NewQ(db, logger.Named(lggr, "HeadTrackerORM"), cfg), ubig.Big(chainID)} } func (orm *orm) IdempotentInsertHead(ctx context.Context, head *evmtypes.Head) error { diff --git a/core/chains/evm/log/orm.go b/core/chains/evm/log/orm.go index a2bcab6e78..3feb4bb836 100644 --- a/core/chains/evm/log/orm.go +++ b/core/chains/evm/log/orm.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/logger" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -48,13 +49,13 @@ type ORM interface { type orm struct { q pg.Q - evmChainID utils.Big + evmChainID ubig.Big } var _ ORM = (*orm)(nil) func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, evmChainID big.Int) *orm { - return &orm{pg.NewQ(db, lggr, cfg), *utils.NewBig(&evmChainID)} + return &orm{pg.NewQ(db, lggr, cfg), *ubig.New(&evmChainID)} } func (o *orm) WasBroadcastConsumed(blockHash common.Hash, logIndex uint, jobID int32, qopts ...pg.QOpt) (consumed bool, err error) { @@ -128,7 +129,7 @@ func (o *orm) MarkBroadcastsConsumed(blockHashes []common.Hash, blockNumbers []u BlockNumber uint64 `db:"blockNumber"` LogIndex uint `db:"logIndex"` JobID int32 `db:"jobID"` - ChainID utils.Big `db:"chainID"` + ChainID ubig.Big `db:"chainID"` } inputs := make([]input, len(blockHashes)) query := ` diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 1cf1cf42be..77b8025359 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -26,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -608,7 +609,7 @@ func convertLogs(logs []types.Log, blocks []LogPollerBlock, lggr logger.Logger, blockTimestamp = blocks[i].BlockTimestamp } lgs = append(lgs, Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: int64(l.Index), BlockHash: l.BlockHash, // We assume block numbers fit in int64 diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 6c4dd381b5..ed2d617065 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -62,7 +63,7 @@ func populateDatabase(t testing.TB, o *logpoller.DbORM, chainID *big.Int) (commo blockTimestamp := startDate.Add(time.Duration(j*1000) * time.Hour) logs = append(logs, logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: 1, BlockHash: common.HexToHash(fmt.Sprintf("0x%d", i+(1000*j))), BlockNumber: blockNumber, @@ -1341,7 +1342,7 @@ func TestNotifyAfterInsert(t *testing.T) { require.NoError(t, err) log := logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: 10, BlockHash: testutils.Random32Byte(), BlockNumber: 100, diff --git a/core/chains/evm/logpoller/models.go b/core/chains/evm/logpoller/models.go index 87ddd079a5..c5d6f5eab1 100644 --- a/core/chains/evm/logpoller/models.go +++ b/core/chains/evm/logpoller/models.go @@ -7,13 +7,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/lib/pq" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // LogPollerBlock represents an unfinalized block // used for reorg detection when polling. type LogPollerBlock struct { - EvmChainId *utils.Big + EvmChainId *big.Big BlockHash common.Hash // Note geth uses int64 internally https://github.com/ethereum/go-ethereum/blob/f66f1a16b3c480d3a43ac7e8a09ab3e362e96ae4/eth/filters/api.go#L340 BlockNumber int64 @@ -24,7 +24,7 @@ type LogPollerBlock struct { // Log represents an EVM log. type Log struct { - EvmChainId *utils.Big + EvmChainId *big.Big LogIndex int64 BlockHash common.Hash BlockNumber int64 diff --git a/core/chains/evm/logpoller/observability_test.go b/core/chains/evm/logpoller/observability_test.go index 76575f46ca..749934dc4b 100644 --- a/core/chains/evm/logpoller/observability_test.go +++ b/core/chains/evm/logpoller/observability_test.go @@ -16,6 +16,7 @@ import ( "github.com/prometheus/client_golang/prometheus/testutil" "github.com/smartcontractkit/chainlink-common/pkg/logger" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -126,7 +127,7 @@ func generateRandomLogs(chainId, count int) []Log { logs := make([]Log, count) for i := range logs { logs[i] = Log{ - EvmChainId: utils.NewBigI(int64(chainId)), + EvmChainId: ubig.NewI(int64(chainId)), LogIndex: int64(i + 1), BlockHash: utils.RandomBytes32(), BlockNumber: int64(i + 1), diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index c24d423b25..663c56d10e 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -12,8 +12,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM represents the persistent data access layer used by the log poller. At this moment, it's a bit leaky abstraction, because @@ -119,7 +119,7 @@ func (o *DbORM) InsertFilter(filter Filter, qopts ...pg.QOpt) (err error) { // DeleteFilter removes all events,address pairs associated with the Filter func (o *DbORM) DeleteFilter(name string, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - return q.ExecQ(`DELETE FROM evm.log_poller_filters WHERE name = $1 AND evm_chain_id = $2`, name, utils.NewBig(o.chainID)) + return q.ExecQ(`DELETE FROM evm.log_poller_filters WHERE name = $1 AND evm_chain_id = $2`, name, ubig.New(o.chainID)) } // LoadFiltersForChain returns all filters for this chain @@ -131,7 +131,7 @@ func (o *DbORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { ARRAY_AGG(DISTINCT event)::BYTEA[] AS event_sigs, MAX(retention) AS retention FROM evm.log_poller_filters WHERE evm_chain_id = $1 - GROUP BY name`, utils.NewBig(o.chainID)) + GROUP BY name`, ubig.New(o.chainID)) filters := make(map[string]Filter) for _, filter := range rows { filters[filter.Name] = filter @@ -143,7 +143,7 @@ func (o *DbORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { func (o *DbORM) SelectBlockByHash(hash common.Hash, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, hash, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, hash, ubig.New(o.chainID)); err != nil { return nil, err } return &b, nil @@ -152,7 +152,7 @@ func (o *DbORM) SelectBlockByHash(hash common.Hash, qopts ...pg.QOpt) (*LogPolle func (o *DbORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_number = $1 AND evm_chain_id = $2`, n, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_number = $1 AND evm_chain_id = $2`, n, ubig.New(o.chainID)); err != nil { return nil, err } return &b, nil @@ -161,7 +161,7 @@ func (o *DbORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, func (o *DbORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1`, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1`, ubig.New(o.chainID)); err != nil { return nil, err } return &b, nil @@ -191,7 +191,7 @@ func (o *DbORM) SelectLatestLogByEventSigWithConfs(eventSig common.Hash, address // DeleteBlocksBefore delete all blocks before and including end. func (o *DbORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - _, err := q.Exec(`DELETE FROM evm.log_poller_blocks WHERE block_number <= $1 AND evm_chain_id = $2`, end, utils.NewBig(o.chainID)) + _, err := q.Exec(`DELETE FROM evm.log_poller_blocks WHERE block_number <= $1 AND evm_chain_id = $2`, end, ubig.New(o.chainID)) return err } @@ -241,7 +241,7 @@ func (o *DbORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { ) DELETE FROM evm.logs l USING r WHERE l.evm_chain_id = $1 AND l.address=r.address AND l.event_sig=r.event AND l.created_at <= STATEMENT_TIMESTAMP() - (r.retention / 10^9 * interval '1 second')`, // retention is in nanoseconds (time.Duration aka BIGINT) - utils.NewBig(o.chainID)) + ubig.New(o.chainID)) } // InsertLogs is idempotent to support replays. diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 2a6ebb2c04..3c54b3cf65 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -37,7 +38,7 @@ func GenLog(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, func GenLogWithTimestamp(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, topic1 []byte, address common.Address, blockTimestamp time.Time) logpoller.Log { return logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: logIndex, BlockHash: common.HexToHash(blockHash), BlockNumber: blockNum, @@ -52,7 +53,7 @@ func GenLogWithTimestamp(chainID *big.Int, logIndex int64, blockNum int64, block func GenLogWithData(chainID *big.Int, address common.Address, eventSig common.Hash, logIndex int64, blockNum int64, data []byte) logpoller.Log { return logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: logIndex, BlockHash: utils.RandomBytes32(), BlockNumber: blockNum, @@ -219,7 +220,7 @@ func TestORM(t *testing.T) { topic2 := common.HexToHash("0x1600") require.NoError(t, o1.InsertLogs([]logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 1, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(10), @@ -230,7 +231,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 2, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(11), @@ -241,7 +242,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 3, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(12), @@ -252,7 +253,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 4, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(13), @@ -263,7 +264,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 5, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(14), @@ -274,7 +275,7 @@ func TestORM(t *testing.T) { Data: []byte("hello2"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 6, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(15), @@ -285,7 +286,7 @@ func TestORM(t *testing.T) { Data: []byte("hello2"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 7, BlockHash: common.HexToHash("0x1237"), BlockNumber: int64(16), @@ -296,7 +297,7 @@ func TestORM(t *testing.T) { Data: []byte("hello short retention"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 8, BlockHash: common.HexToHash("0x1238"), BlockNumber: int64(17), @@ -451,7 +452,7 @@ func insertLogsTopicValueRange(t *testing.T, chainID *big.Int, o *logpoller.DbOR var lgs []logpoller.Log for i := start; i <= stop; i++ { lgs = append(lgs, logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: int64(i), BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(blockNumber), @@ -536,7 +537,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) logs := []logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(0), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -547,7 +548,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { Data: logpoller.EvmWord(1).Bytes(), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(1), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -559,7 +560,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { }, // Different txHash { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(2), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -571,7 +572,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { }, // Different eventSig { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(3), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -600,7 +601,7 @@ func TestORM_DataWords(t *testing.T) { require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) require.NoError(t, o1.InsertLogs([]logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(0), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -612,7 +613,7 @@ func TestORM_DataWords(t *testing.T) { }, { // In block 2, unconfirmed to start - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(1), BlockHash: common.HexToHash("0x2"), BlockNumber: int64(2), @@ -667,7 +668,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { sourceAddr := common.HexToAddress("0x12345") inputLogs := []logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 1, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(10), @@ -678,7 +679,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello1"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 2, BlockHash: common.HexToHash("0x1235"), BlockNumber: int64(11), @@ -689,7 +690,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello2"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 3, BlockHash: common.HexToHash("0x1236"), BlockNumber: int64(12), @@ -700,7 +701,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello3"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 4, BlockHash: common.HexToHash("0x1237"), BlockNumber: int64(13), @@ -711,7 +712,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello4"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 5, BlockHash: common.HexToHash("0x1238"), BlockNumber: int64(14), @@ -722,7 +723,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello5"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 6, BlockHash: common.HexToHash("0x1239"), BlockNumber: int64(15), @@ -827,7 +828,7 @@ func BenchmarkLogs(b *testing.B) { addr := common.HexToAddress("0x1234") for i := 0; i < 10_000; i++ { lgs = append(lgs, logpoller.Log{ - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(i), BlockHash: common.HexToHash("0x1"), BlockNumber: 1, @@ -866,7 +867,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Insert two logs that mimics an oracle request from 2 different addresses (matching will be on topic index 1) require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 1, BlockHash: common.HexToHash("0x1"), BlockNumber: 1, @@ -878,7 +879,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { Data: []byte("requestID-A1"), }, { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 2, BlockHash: common.HexToHash("0x1"), BlockNumber: 1, @@ -907,7 +908,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Insert a log that mimics response for requestID-A1 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 3, BlockHash: common.HexToHash("0x2"), BlockNumber: 2, @@ -935,7 +936,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Insert 3 request from addressC (matching will be on topic index 3) require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 5, BlockHash: common.HexToHash("0x2"), BlockNumber: 3, @@ -947,7 +948,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { Data: []byte("requestID-C1"), }, { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 6, BlockHash: common.HexToHash("0x2"), BlockNumber: 3, @@ -958,7 +959,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { TxHash: common.HexToHash("0x0002"), Data: []byte("requestID-C2"), }, { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 7, BlockHash: common.HexToHash("0x2"), BlockNumber: 3, @@ -983,7 +984,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Fulfill requestID-C2 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 8, BlockHash: common.HexToHash("0x3"), BlockNumber: 3, @@ -1006,7 +1007,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Fulfill requestID-C3 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 9, BlockHash: common.HexToHash("0x3"), BlockNumber: 3, @@ -1041,7 +1042,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Fulfill requestID-C3 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 10, BlockHash: common.HexToHash("0x2"), BlockNumber: 10, @@ -1533,7 +1534,7 @@ func Benchmark_LogsDataWordBetween(b *testing.B) { data = append(data, logpoller.EvmWord(uint64(numberOfMessagesPerReport*(i+1))).Bytes()...) dbLogs = append(dbLogs, logpoller.Log{ - EvmChainId: utils.NewBig(chainId), + EvmChainId: ubig.New(chainId), LogIndex: int64(i + 1), BlockHash: utils.RandomBytes32(), BlockNumber: int64(i + 1), diff --git a/core/chains/evm/logpoller/query.go b/core/chains/evm/logpoller/query.go index b7fbfade68..a37b15b2b2 100644 --- a/core/chains/evm/logpoller/query.go +++ b/core/chains/evm/logpoller/query.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type bytesProducer interface { @@ -34,7 +34,7 @@ type queryArgs struct { func newQueryArgs(chainId *big.Int) *queryArgs { return &queryArgs{ args: map[string]interface{}{ - "evm_chain_id": utils.NewBig(chainId), + "evm_chain_id": ubig.New(chainId), }, err: []error{}, } diff --git a/core/chains/evm/logpoller/query_test.go b/core/chains/evm/logpoller/query_test.go index e38aeb0581..bc2b20c85c 100644 --- a/core/chains/evm/logpoller/query_test.go +++ b/core/chains/evm/logpoller/query_test.go @@ -8,6 +8,7 @@ import ( "github.com/lib/pq" "github.com/stretchr/testify/require" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -22,7 +23,7 @@ func Test_QueryArgs(t *testing.T) { name: "valid arguments", queryArgs: newQueryArgs(big.NewInt(20)).withAddress(utils.ZeroAddress), want: map[string]interface{}{ - "evm_chain_id": utils.NewBigI(20), + "evm_chain_id": ubig.NewI(20), "address": utils.ZeroAddress, }, }, diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 21a4bd2865..b9e8fe99e3 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -37,6 +37,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -1897,7 +1898,7 @@ func Test_NextNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) ctx := testutils.Context(t) - cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.FixtureChainID)) + cltest.MustInsertRandomKey(t, ks, *ubig.New(testutils.FixtureChainID)) nonce, err := eb.GetNextSequence(ctx, addr1) require.NoError(t, err) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 1c9868741f..bb2a30e51d 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -28,8 +28,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -177,7 +177,7 @@ type DbEthTx struct { Subject uuid.NullUUID PipelineTaskRunID uuid.NullUUID MinConfirmations null.Uint32 - EVMChainID utils.Big + EVMChainID ubig.Big // TransmitChecker defines the check that should be performed before a transaction is submitted on // chain. TransmitChecker *sqlutil.JSON @@ -210,7 +210,7 @@ func (db *DbEthTx) FromTx(tx *Tx) { db.CallbackCompleted = tx.CallbackCompleted if tx.ChainID != nil { - db.EVMChainID = *utils.NewBig(tx.ChainID) + db.EVMChainID = *ubig.New(tx.ChainID) } if tx.Sequence != nil { n := tx.Sequence.Int64() diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index 0e86c0d4f8..f6b0e3e29c 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -23,7 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_EthResender_resendUnconfirmed(t *testing.T) { @@ -109,7 +109,7 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { delay := models.MustNewDuration(1 * time.Nanosecond) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0] = &toml.EVMConfig{ - Chain: toml.Defaults(utils.NewBig(big.NewInt(0)), &toml.Chain{ + Chain: toml.Defaults(ubig.New(big.NewInt(0)), &toml.Chain{ Transactions: toml.Transactions{ResendAfterThreshold: delay}, }), } diff --git a/core/chains/evm/txmgr/tracker_test.go b/core/chains/evm/txmgr/tracker_test.go index a31187f04e..3e0bef5156 100644 --- a/core/chains/evm/txmgr/tracker_test.go +++ b/core/chains/evm/txmgr/tracker_test.go @@ -7,12 +7,12 @@ import ( "time" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -33,8 +33,8 @@ func newTestEvmTrackerSetup(t *testing.T) (*txmgr.Tracker, txmgr.TestEvmTxStore, func generateEnabledAddresses(t *testing.T, keyStore keystore.Eth, chainID *big.Int) []common.Address { var enabledAddresses []common.Address - _, addr1 := cltest.MustInsertRandomKey(t, keyStore, *utils.NewBigI(chainID.Int64())) - _, addr2 := cltest.MustInsertRandomKey(t, keyStore, *utils.NewBigI(chainID.Int64())) + _, addr1 := cltest.MustInsertRandomKey(t, keyStore, *ubig.NewI(chainID.Int64())) + _, addr2 := cltest.MustInsertRandomKey(t, keyStore, *ubig.NewI(chainID.Int64())) enabledAddresses = append(enabledAddresses, addr1, addr2) return enabledAddresses } diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 9833acfd45..df913a4190 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -33,6 +33,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -206,7 +207,7 @@ func TestTxm_CreateTransaction(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), fmt.Sprintf("no eth key exists with address %s", rndAddr.String())) - _, otherAddress := cltest.MustInsertRandomKey(t, kst.Eth(), *utils.NewBigI(1337)) + _, otherAddress := cltest.MustInsertRandomKey(t, kst.Eth(), *ubig.NewI(1337)) _, err = txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: otherAddress, @@ -301,7 +302,7 @@ func TestTxm_CreateTransaction(t *testing.T) { // Create mock forwarder, mock authorizedsenders call. form := forwarders.NewORM(db, logger.Test(t), cfg.Database()) fwdrAddr := testutils.NewAddress() - fwdr, err := form.CreateForwarder(fwdrAddr, utils.Big(cltest.FixtureChainID)) + fwdr, err := form.CreateForwarder(fwdrAddr, ubig.Big(cltest.FixtureChainID)) require.NoError(t, err) require.Equal(t, fwdr.Address, fwdrAddr) diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 314180a7e9..b7c1e5b56d 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -20,6 +20,7 @@ import ( commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types/internal/blocks" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -32,7 +33,7 @@ type Head struct { L1BlockNumber null.Int64 ParentHash common.Hash Parent *Head - EVMChainID *utils.Big + EVMChainID *ubig.Big Timestamp time.Time CreatedAt time.Time BaseFeePerGas *assets.Wei @@ -47,7 +48,7 @@ var _ commontypes.Head[common.Hash] = &Head{} var _ htrktypes.Head[common.Hash, *big.Int] = &Head{} // NewHead returns a Head instance. -func NewHead(number *big.Int, blockHash common.Hash, parentHash common.Hash, timestamp uint64, chainID *utils.Big) Head { +func NewHead(number *big.Int, blockHash common.Hash, parentHash common.Hash, timestamp uint64, chainID *ubig.Big) Head { return Head{ Number: number.Int64(), Hash: blockHash, diff --git a/core/chains/evm/types/types.go b/core/chains/evm/types/types.go index d0e7292b20..aa43806da1 100644 --- a/core/chains/evm/types/types.go +++ b/core/chains/evm/types/types.go @@ -13,6 +13,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -26,7 +27,7 @@ type Configs interface { type Node struct { Name string - EVMChainID utils.Big + EVMChainID ubig.Big WSURL null.String HTTPURL null.String SendOnly bool diff --git a/core/utils/big.go b/core/chains/evm/utils/big/big.go similarity index 91% rename from core/utils/big.go rename to core/chains/evm/utils/big/big.go index 69fab223de..f0ff475a7e 100644 --- a/core/utils/big.go +++ b/core/chains/evm/utils/big/big.go @@ -1,4 +1,4 @@ -package utils +package big import ( "database/sql/driver" @@ -10,6 +10,7 @@ import ( bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) const base10 = 10 @@ -50,8 +51,8 @@ func (b *BigFloat) Value() *big.Float { // Big stores large integers and can deserialize a variety of inputs. type Big big.Int -// NewBig constructs a Big from *big.Int. -func NewBig(i *big.Int) *Big { +// New constructs a Big from *big.Int. +func New(i *big.Int) *Big { if i != nil { var b big.Int b.Set(i) @@ -60,9 +61,9 @@ func NewBig(i *big.Int) *Big { return nil } -// NewBigI constructs a Big from int64. -func NewBigI(i int64) *Big { - return NewBig(big.NewInt(i)) +// NewI constructs a Big from int64. +func NewI(i int64) *Big { + return New(big.NewInt(i)) } // MarshalText marshals this instance to base 10 number as string. @@ -83,7 +84,7 @@ func (b Big) MarshalJSON() ([]byte, error) { func (b *Big) UnmarshalText(input []byte) error { input = bytes.TrimQuotes(input) str := string(input) - if HasHexPrefix(str) { + if utils.HasHexPrefix(str) { decoded, err := hexutil.DecodeBig(str) if err != nil { return err @@ -174,15 +175,15 @@ func (b *Big) Int64() int64 { // Add returns the sum of b and c func (b *Big) Add(c *Big) *Big { - return NewBig(bigmath.Add(b.ToInt(), c.ToInt())) + return New(bigmath.Add(b.ToInt(), c.ToInt())) } // Sub returns the differencs between b and c func (b *Big) Sub(c *Big) *Big { - return NewBig(bigmath.Sub(b.ToInt(), c.ToInt())) + return New(bigmath.Sub(b.ToInt(), c.ToInt())) } // Sub returns b % c func (b *Big) Mod(c *Big) *Big { - return NewBig(bigmath.Mod(b.ToInt(), c.ToInt())) + return New(bigmath.Mod(b.ToInt(), c.ToInt())) } diff --git a/core/utils/big_test.go b/core/chains/evm/utils/big/big_test.go similarity index 95% rename from core/utils/big_test.go rename to core/chains/evm/utils/big/big_test.go index e46d46a065..c4774cf198 100644 --- a/core/utils/big_test.go +++ b/core/chains/evm/utils/big/big_test.go @@ -1,4 +1,4 @@ -package utils +package big import ( "encoding/json" @@ -198,15 +198,15 @@ func TestBig_Scan(t *testing.T) { input interface{} want *Big }{ - {"zero string", "0", NewBig(big.NewInt(0))}, - {"one string", "1", NewBig(big.NewInt(1))}, + {"zero string", "0", New(big.NewInt(0))}, + {"one string", "1", New(big.NewInt(1))}, { "large string", "115792089237316195423570985008687907853269984665640564039457584007913129639935", - NewBig(uint256Max), + New(uint256Max), }, - {"zero as bytes", []uint8{48}, NewBig(big.NewInt(0))}, - {"small number as bytes", []uint8{49, 52}, NewBig(big.NewInt(14))}, + {"zero as bytes", []uint8{48}, New(big.NewInt(0))}, + {"small number as bytes", []uint8{49, 52}, New(big.NewInt(14))}, { "max number as bytes", []uint8{ @@ -216,7 +216,7 @@ func TestBig_Scan(t *testing.T) { 48, 51, 57, 52, 53, 55, 53, 56, 52, 48, 48, 55, 57, 49, 51, 49, 50, 57, 54, 51, 57, 57, 51, 53, }, - NewBig(uint256Max), + New(uint256Max), }, } for _, test := range tests { diff --git a/core/chains/evm/utils/utils.go b/core/chains/evm/utils/utils.go new file mode 100644 index 0000000000..abcea77124 --- /dev/null +++ b/core/chains/evm/utils/utils.go @@ -0,0 +1,37 @@ +package utils + +import ( + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/jpillora/backoff" + "golang.org/x/crypto/sha3" +) + +// MustHash returns the keccak256 hash, or panics on failure. +func MustHash(in string) common.Hash { + out, err := Keccak256([]byte(in)) + if err != nil { + panic(err) + } + return common.BytesToHash(out) +} + +// Keccak256 is a simplified interface for the legacy SHA3 implementation that +// Ethereum uses. +func Keccak256(in []byte) ([]byte, error) { + hash := sha3.NewLegacyKeccak256() + _, err := hash.Write(in) + return hash.Sum(nil), err +} + +// NewRedialBackoff is a standard backoff to use for redialling or reconnecting to +// unreachable network endpoints +func NewRedialBackoff() backoff.Backoff { + return backoff.Backoff{ + Min: 1 * time.Second, + Max: 15 * time.Second, + Jitter: true, + } + +} diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 18277a55d0..ef84573cd0 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -33,11 +33,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name Chain --output ./mocks/ --case=underscore @@ -127,7 +127,7 @@ type chain struct { } type errChainDisabled struct { - ChainID *utils.Big + ChainID *ubig.Big } func (e errChainDisabled) Error() string { diff --git a/core/cmd/blocks_commands_test.go b/core/cmd/blocks_commands_test.go index d0c0e118f9..30540748cb 100644 --- a/core/cmd/blocks_commands_test.go +++ b/core/cmd/blocks_commands_test.go @@ -8,15 +8,15 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_ReplayFromBlock(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(big.NewInt(5)) + c.EVM[0].ChainID = (*ubig.Big)(big.NewInt(5)) c.EVM[0].Enabled = ptr(true) }) diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index 3eb45e27bd..7c85b779ec 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -14,6 +14,7 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -39,7 +40,7 @@ func TestEthKeysPresenter_RenderTable(t *testing.T) { isDisabled = true createdAt = time.Now() updatedAt = time.Now().Add(time.Second) - maxGasPriceWei = utils.NewBigI(12345) + maxGasPriceWei = ubig.NewI(12345) bundleID = cltest.DefaultOCRKeyBundleID buffer = bytes.NewBufferString("") r = cmd.RendererTable{Writer: buffer} diff --git a/core/cmd/evm_chains_commands_test.go b/core/cmd/evm_chains_commands_test.go index b489127121..fa6d7bb519 100644 --- a/core/cmd/evm_chains_commands_test.go +++ b/core/cmd/evm_chains_commands_test.go @@ -8,15 +8,15 @@ import ( "github.com/stretchr/testify/require" client2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func newRandChainID() *utils.Big { - return utils.NewBig(testutils.NewRandomEVMChainID()) +func newRandChainID() *big.Big { + return big.New(testutils.NewRandomEVMChainID()) } func TestShell_IndexEVMChains(t *testing.T) { diff --git a/core/cmd/evm_transaction_commands.go b/core/cmd/evm_transaction_commands.go index d702bc3b79..a1a11ab9b3 100644 --- a/core/cmd/evm_transaction_commands.go +++ b/core/cmd/evm_transaction_commands.go @@ -11,6 +11,7 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" @@ -186,7 +187,7 @@ func (s *Shell) SendEther(c *cli.Context) (err error) { DestinationAddress: destinationAddress, FromAddress: fromAddress, Amount: amount, - EVMChainID: (*utils.Big)(evmChainID), + EVMChainID: (*ubig.Big)(evmChainID), AllowHigherAmounts: c.IsSet("force"), } diff --git a/core/cmd/forwarders_commands.go b/core/cmd/forwarders_commands.go index 51e90a4390..a870d4714c 100644 --- a/core/cmd/forwarders_commands.go +++ b/core/cmd/forwarders_commands.go @@ -14,7 +14,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -136,7 +136,7 @@ func (s *Shell) TrackForwarder(c *cli.Context) (err error) { } request, err := json.Marshal(web.TrackEVMForwarderRequest{ - EVMChainID: (*utils.Big)(chainID), + EVMChainID: (*ubig.Big)(chainID), Address: address, }) if err != nil { diff --git a/core/cmd/forwarders_commands_test.go b/core/cmd/forwarders_commands_test.go index 179216b8e4..5946d31dc3 100644 --- a/core/cmd/forwarders_commands_test.go +++ b/core/cmd/forwarders_commands_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -23,7 +24,7 @@ func TestEVMForwarderPresenter_RenderTable(t *testing.T) { var ( id = "1" address = utils.RandomAddress() - evmChainID = utils.NewBigI(4) + evmChainID = big.NewI(4) createdAt = time.Now() updatedAt = time.Now().Add(time.Second) buffer = bytes.NewBufferString("") diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index cf014d5e5d..06f26ddb6a 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -17,6 +17,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -342,7 +343,7 @@ func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, lggr logger.Logg // Create forwarder for management in forwarder_manager.go. orm := forwarders.NewORM(db, lggr, s.Config.Database()) - _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *utils.NewBigI(chainID)) + _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *ubig.NewI(chainID)) if err != nil { return err } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index a1f7fdb857..e4c29a0e5c 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -38,6 +38,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -855,7 +856,7 @@ func randomizeTestDBSequences(db *sqlx.DB) error { } var randNum *big.Int - randNum, err = crand.Int(crand.Reader, utils.NewBigI(10000).ToInt()) + randNum, err = crand.Int(crand.Reader, ubig.NewI(10000).ToInt()) if err != nil { return fmt.Errorf("%s: failed to generate random number", failedToRandomizeTestDBSequencesError{}) } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index dc90201890..c5e1fc5e4d 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -51,6 +51,7 @@ import ( httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -232,10 +233,10 @@ func NewApplicationWithKey(t *testing.T, flagsAndDeps ...interface{}) *TestAppli func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, flagsAndDeps ...interface{}) *TestApplication { app := NewApplicationWithConfig(t, c, flagsAndDeps...) - chainID := *utils.NewBig(&FixtureChainID) + chainID := *ubig.New(&FixtureChainID) for _, dep := range flagsAndDeps { switch v := dep.(type) { - case *utils.Big: + case *ubig.Big: chainID = *v } } @@ -255,7 +256,7 @@ func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, fla return app } -func setKeys(t testing.TB, app *TestApplication, flagsAndDeps ...interface{}) (chainID utils.Big) { +func setKeys(t testing.TB, app *TestApplication, flagsAndDeps ...interface{}) (chainID ubig.Big) { require.NoError(t, app.KeyStore.Unlock(Password)) for _, dep := range flagsAndDeps { @@ -993,13 +994,13 @@ func Head(val interface{}) *evmtypes.Head { time := uint64(0) switch t := val.(type) { case int: - h = evmtypes.NewHead(big.NewInt(int64(t)), utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(int64(t)), utils.NewHash(), utils.NewHash(), time, ubig.New(&FixtureChainID)) case uint64: - h = evmtypes.NewHead(big.NewInt(int64(t)), utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(int64(t)), utils.NewHash(), utils.NewHash(), time, ubig.New(&FixtureChainID)) case int64: - h = evmtypes.NewHead(big.NewInt(t), utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(t), utils.NewHash(), utils.NewHash(), time, ubig.New(&FixtureChainID)) case *big.Int: - h = evmtypes.NewHead(t, utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(t, utils.NewHash(), utils.NewHash(), time, ubig.New(&FixtureChainID)) default: panic(fmt.Sprintf("Could not convert %v of type %T to Head", val, val)) } @@ -1009,7 +1010,7 @@ func Head(val interface{}) *evmtypes.Head { func HeadWithHash(n int64, hash common.Hash) *evmtypes.Head { var h evmtypes.Head time := uint64(0) - h = evmtypes.NewHead(big.NewInt(n), hash, utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(n), hash, utils.NewHash(), time, ubig.New(&FixtureChainID)) return &h } @@ -1390,7 +1391,7 @@ func (b *Blocks) NewHead(number uint64) *evmtypes.Head { ParentHash: parent.Hash, Parent: parent, Timestamp: time.Unix(parent.Number+1, 0), - EVMChainID: utils.NewBig(&FixtureChainID), + EVMChainID: ubig.New(&FixtureChainID), } return head } @@ -1429,7 +1430,7 @@ func NewBlocks(t *testing.T, numHashes int) *Blocks { hash := utils.NewHash() hashes = append(hashes, hash) - heads[i] = &evmtypes.Head{Hash: hash, Number: i, Timestamp: time.Unix(i, 0), EVMChainID: utils.NewBig(&FixtureChainID)} + heads[i] = &evmtypes.Head{Hash: hash, Number: i, Timestamp: time.Unix(i, 0), EVMChainID: ubig.New(&FixtureChainID)} if i > 0 { parent := heads[i-1] heads[i].Parent = parent diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index a76d23d376..bece916ecc 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -32,6 +32,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -240,12 +241,12 @@ type RandomKey struct { Nonce int64 Disabled bool - chainIDs []utils.Big // nil: Fixture, set empty for none + chainIDs []ubig.Big // nil: Fixture, set empty for none } func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { if r.chainIDs == nil { - r.chainIDs = []utils.Big{*utils.NewBig(&FixtureChainID)} + r.chainIDs = []ubig.Big{*ubig.New(&FixtureChainID)} } key := MustGenerateRandomKey(t) @@ -272,7 +273,7 @@ func (r RandomKey) MustInsertWithState(t testing.TB, keystore keystore.Eth) (eth // MustInsertRandomKey inserts a randomly generated (not cryptographically secure) key for testing. // By default, it is enabled for the fixture chain. Pass chainIDs to override. // Use MustInsertRandomKeyNoChains for a key associate with no chains. -func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...utils.Big) (ethkey.KeyV2, common.Address) { +func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...ubig.Big) (ethkey.KeyV2, common.Address) { r := RandomKey{} if len(chainIDs) > 0 { r.chainIDs = chainIDs @@ -281,7 +282,7 @@ func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...utils. } func MustInsertRandomKeyNoChains(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { - return RandomKey{chainIDs: []utils.Big{}}.MustInsert(t, keystore) + return RandomKey{chainIDs: []ubig.Big{}}.MustInsert(t, keystore) } func MustInsertRandomKeyReturningState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { @@ -299,7 +300,7 @@ func MustGenerateRandomKeyState(_ testing.TB) ethkey.State { } func MustInsertHead(t *testing.T, db *sqlx.DB, cfg pg.QConfig, number int64) evmtypes.Head { - h := evmtypes.NewHead(big.NewInt(number), utils.NewHash(), utils.NewHash(), 0, utils.NewBig(&FixtureChainID)) + h := evmtypes.NewHead(big.NewInt(number), utils.NewHash(), utils.NewHash(), 0, ubig.New(&FixtureChainID)) horm := headtracker.NewORM(db, logger.TestLogger(t), cfg, FixtureChainID) err := horm.IdempotentInsertHead(testutils.Context(t), &h) @@ -347,7 +348,7 @@ NOW(),NOW(),$1,'{}',false,$2,$3,0,0,0,0,0,0,0,0,0 func MakeDirectRequestJobSpec(t *testing.T) *job.Job { t.Helper() - drs := &job.DirectRequestSpec{EVMChainID: (*utils.Big)(testutils.FixtureChainID)} + drs := &job.DirectRequestSpec{EVMChainID: (*ubig.Big)(testutils.FixtureChainID)} spec := &job.Job{ Type: job.DirectRequest, SchemaVersion: 1, @@ -391,7 +392,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey } func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKeyStore keystore.Eth, keeperIndex, numKeepers, blockCountPerTurn int32) (keeper.Registry, job.Job) { - key, _ := MustInsertRandomKey(t, ethKeyStore, *utils.NewBig(testutils.SimulatedChainID)) + key, _ := MustInsertRandomKey(t, ethKeyStore, *ubig.New(testutils.SimulatedChainID)) from := key.EIP55Address t.Helper() contractAddress := NewEIP55Address() @@ -415,7 +416,7 @@ func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKey func MustInsertUpkeepForRegistry(t *testing.T, db *sqlx.DB, cfg pg.QConfig, registry keeper.Registry) keeper.UpkeepRegistration { korm := keeper.NewORM(db, logger.TestLogger(t), cfg) - upkeepID := utils.NewBigI(int64(mathrand.Uint32())) + upkeepID := ubig.NewI(int64(mathrand.Uint32())) upkeep := keeper.UpkeepRegistration{ UpkeepID: upkeepID, ExecuteGas: uint32(150_000), diff --git a/core/internal/cltest/simulated_backend.go b/core/internal/cltest/simulated_backend.go index 010478837d..0aecc7f832 100644 --- a/core/internal/cltest/simulated_backend.go +++ b/core/internal/cltest/simulated_backend.go @@ -11,12 +11,12 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func NewSimulatedBackend(t *testing.T, alloc core.GenesisAlloc, gasLimit uint32) *backends.SimulatedBackend { @@ -39,7 +39,7 @@ func NewApplicationWithConfigV2OnSimulatedBlockchain( } require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := big.New(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) @@ -64,7 +64,7 @@ func NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain( } require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := big.New(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 7b29fdae4f..f115a3f885 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -46,6 +46,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/consumer_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" @@ -771,7 +772,7 @@ func setupForwarderEnabledNode(t *testing.T, owner *bind.TransactOpts, portV2 in // add forwarder address to be tracked in db forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), config.Database()) - chainID := utils.Big(*b.Blockchain().Config().ChainID) + chainID := ubig.Big(*b.Blockchain().Config().ChainID) _, err = forwarderORM.CreateForwarder(forwarder, chainID) require.NoError(t, err) @@ -1277,7 +1278,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { Transactions: cltest.LegacyTransactionsFromGasPrices(48_000_000_000, 49_000_000_000, 31_000_000_000), } - evmChainID := utils.NewBig(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) + evmChainID := ubig.New(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) h40 := evmtypes.Head{Hash: utils.NewHash(), Number: 40, EVMChainID: evmChainID} h41 := evmtypes.Head{Hash: b41.Hash, ParentHash: h40.Hash, Number: 41, EVMChainID: evmChainID} h42 := evmtypes.Head{Hash: b42.Hash, ParentHash: h41.Hash, Number: 42, EVMChainID: evmChainID} diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 295bb7fb14..70d4b0d79f 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -37,6 +37,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -51,7 +52,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ocr2Node struct { @@ -170,7 +170,7 @@ func setupNodeOCR2( // add forwarder address to be tracked in db forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), config.Database()) - chainID := utils.Big(*b.Blockchain().Config().ChainID) + chainID := ubig.Big(*b.Blockchain().Config().ChainID) _, err2 = forwarderORM.CreateForwarder(faddr, chainID) require.NoError(t, err2) diff --git a/core/internal/testutils/configtest/general_config.go b/core/internal/testutils/configtest/general_config.go index f076521b71..c414c97316 100644 --- a/core/internal/testutils/configtest/general_config.go +++ b/core/internal/testutils/configtest/general_config.go @@ -10,11 +10,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const DefaultPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" @@ -64,7 +64,7 @@ func overrides(c *chainlink.Config, s *chainlink.Secrets) { c.WebServer.ListenIP = &testIP c.WebServer.TLS.ListenIP = &testIP - chainID := utils.NewBigI(evmclient.NullClientChainID) + chainID := big.NewI(evmclient.NullClientChainID) c.EVM = append(c.EVM, &evmcfg.EVMConfig{ ChainID: chainID, Chain: evmcfg.Defaults(chainID), @@ -95,7 +95,7 @@ func NewGeneralConfigSimulated(t testing.TB, overrideFn func(*chainlink.Config, // simulated is a config override func that appends the simulated EVM chain (testutils.SimulatedChainID), // or replaces the null chain (client.NullClientChainID) if that is the only entry. func simulated(c *chainlink.Config, s *chainlink.Secrets) { - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := big.New(testutils.SimulatedChainID) enabled := true cfg := evmcfg.EVMConfig{ ChainID: chainID, @@ -103,7 +103,7 @@ func simulated(c *chainlink.Config, s *chainlink.Secrets) { Enabled: &enabled, Nodes: evmcfg.EVMNodes{&validTestNode}, } - if len(c.EVM) == 1 && c.EVM[0].ChainID.Cmp(utils.NewBigI(client.NullClientChainID)) == 0 { + if len(c.EVM) == 1 && c.EVM[0].ChainID.Cmp(big.NewI(client.NullClientChainID)) == 0 { c.EVM[0] = &cfg // replace null, if only entry } else { c.EVM = append(c.EVM, &cfg) diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 095ea1a35c..eb1a03530a 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -31,6 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -38,7 +39,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.ChainScopedConfig { @@ -46,7 +46,7 @@ func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.Chain if len(cfg.EVMConfigs()) > 0 { evmCfg = cfg.EVMConfigs()[0] } else { - var chainID = (*utils.Big)(testutils.FixtureChainID) + var chainID = (*ubig.Big)(testutils.FixtureChainID) evmCfg = &evmtoml.EVMConfig{ ChainID: chainID, Chain: evmtoml.Defaults(chainID), @@ -267,7 +267,7 @@ func (mo *TestConfigs) NodeStatusesPaged(offset int, limit int, chainIDs ...stri return } -func legacyNode(n *evmtoml.Node, chainID *utils.Big) (v2 evmtypes.Node) { +func legacyNode(n *evmtoml.Node, chainID *ubig.Big) (v2 evmtypes.Node) { v2.Name = *n.Name v2.EVMChainID = *chainID if n.HTTPURL != nil { diff --git a/core/internal/testutils/evmtest/v2/evmtest.go b/core/internal/testutils/evmtest/v2/evmtest.go index fa22588c8f..22b2bc5e0c 100644 --- a/core/internal/testutils/evmtest/v2/evmtest.go +++ b/core/internal/testutils/evmtest/v2/evmtest.go @@ -5,9 +5,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func ChainEthMainnet(t *testing.T) config.ChainScopedConfig { return scopedConfig(t, 1) } @@ -16,7 +16,7 @@ func ChainArbitrumMainnet(t *testing.T) config.ChainScopedConfig { return scoped func ChainArbitrumRinkeby(t *testing.T) config.ChainScopedConfig { return scopedConfig(t, 421611) } func scopedConfig(t *testing.T, chainID int64) config.ChainScopedConfig { - id := utils.NewBigI(chainID) + id := big.NewI(chainID) evmCfg := toml.EVMConfig{ChainID: id, Chain: toml.Defaults(id)} return config.NewTOMLChainScopedConfig(configtest.NewTestGeneralConfig(t), &evmCfg, logger.TestLogger(t)) } diff --git a/core/scripts/functions/src/fetching.go b/core/scripts/functions/src/fetching.go index 0b22a93252..9be624a40b 100644 --- a/core/scripts/functions/src/fetching.go +++ b/core/scripts/functions/src/fetching.go @@ -11,7 +11,6 @@ import ( "github.com/urfave/cli" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -114,7 +113,7 @@ func findEvmOCR2Bundle(ocr2Bundles []ocr2Bundle) int { func findFirstGoodEthKeyAddress(chainID int64, ethKeys []presenters.ETHKeyResource) (string, error) { for _, ethKey := range ethKeys { - if ethKey.EVMChainID.Equal(utils.NewBigI(chainID)) && !ethKey.Disabled { + if ethKey.EVMChainID.Equal(ubig.NewI(chainID)) && !ethKey.Disabled { if ethKey.EthBalance.IsZero() { fmt.Println("WARN: selected ETH address has zero balance", ethKey.Address) } diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 0096ac5ca9..6fffcfdd49 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -26,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestDelegate_JobType(t *testing.T) { @@ -90,7 +90,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { defaultWaitBlocks := (int32)(testData.legacyChains.Slice()[0].Config().EVM().FinalityDepth()) t.Run("happy", func(t *testing.T) { - spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{WaitBlocks: defaultWaitBlocks, EVMChainID: (*utils.Big)(testutils.FixtureChainID)}} + spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{WaitBlocks: defaultWaitBlocks, EVMChainID: (*big.Big)(testutils.FixtureChainID)}} services, err := delegate.ServicesForSpec(spec) require.NoError(t, err) @@ -107,7 +107,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { CoordinatorV1Address: &coordinatorV1, CoordinatorV2Address: &coordinatorV2, CoordinatorV2PlusAddress: &coordinatorV2Plus, - EVMChainID: (*utils.Big)(testutils.FixtureChainID), + EVMChainID: (*big.Big)(testutils.FixtureChainID), }} services, err := delegate.ServicesForSpec(spec) @@ -123,7 +123,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { t.Run("wrong EVMChainID", func(t *testing.T) { spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{ - EVMChainID: utils.NewBigI(123), + EVMChainID: big.NewI(123), }} _, err := delegate.ServicesForSpec(spec) assert.Error(t, err) @@ -152,7 +152,7 @@ func TestDelegate_StartStop(t *testing.T) { WaitBlocks: defaultWaitBlocks, PollPeriod: time.Second, RunTimeout: testutils.WaitTimeout(t), - EVMChainID: (*utils.Big)(testutils.FixtureChainID), + EVMChainID: (*big.Big)(testutils.FixtureChainID), }} services, err := delegate.ServicesForSpec(spec) diff --git a/core/services/blockhashstore/validate_test.go b/core/services/blockhashstore/validate_test.go index 0b7110a752..48487bb548 100644 --- a/core/services/blockhashstore/validate_test.go +++ b/core/services/blockhashstore/validate_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestValidate(t *testing.T) { @@ -49,7 +49,7 @@ fromAddresses = ["0x469aA2CD13e037DC5236320783dCfd0e641c0559"]`, os.BlockhashStoreSpec.BlockhashStoreAddress) require.Equal(t, 23*time.Second, os.BlockhashStoreSpec.PollPeriod) require.Equal(t, 7*time.Second, os.BlockhashStoreSpec.RunTimeout) - require.Equal(t, utils.NewBigI(4), os.BlockhashStoreSpec.EVMChainID) + require.Equal(t, big.NewI(4), os.BlockhashStoreSpec.EVMChainID) require.Equal(t, fromAddresses, os.BlockhashStoreSpec.FromAddresses) }, diff --git a/core/services/blockheaderfeeder/validate_test.go b/core/services/blockheaderfeeder/validate_test.go index c58058d162..cdab0322a4 100644 --- a/core/services/blockheaderfeeder/validate_test.go +++ b/core/services/blockheaderfeeder/validate_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestValidate(t *testing.T) { @@ -59,7 +59,7 @@ storeBlockhashesBatchSize = 10 os.BlockHeaderFeederSpec.BatchBlockhashStoreAddress) require.Equal(t, 23*time.Second, os.BlockHeaderFeederSpec.PollPeriod) require.Equal(t, 7*time.Second, os.BlockHeaderFeederSpec.RunTimeout) - require.Equal(t, utils.NewBigI(4), os.BlockHeaderFeederSpec.EVMChainID) + require.Equal(t, big.NewI(4), os.BlockHeaderFeederSpec.EVMChainID) require.Equal(t, fromAddresses, os.BlockHeaderFeederSpec.FromAddresses) require.Equal(t, uint16(20), @@ -86,7 +86,7 @@ fromAddresses = ["0x469aA2CD13e037DC5236320783dCfd0e641c0559"] require.Equal(t, int32(256), os.BlockHeaderFeederSpec.WaitBlocks) require.Equal(t, 15*time.Second, os.BlockHeaderFeederSpec.PollPeriod) require.Equal(t, 30*time.Second, os.BlockHeaderFeederSpec.RunTimeout) - require.Equal(t, utils.NewBigI(4), os.BlockHeaderFeederSpec.EVMChainID) + require.Equal(t, big.NewI(4), os.BlockHeaderFeederSpec.EVMChainID) require.Equal(t, fromAddresses, os.BlockHeaderFeederSpec.FromAddresses) require.Equal(t, uint16(100), diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index b2f60384ec..192fbb311d 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -28,9 +28,9 @@ import ( // When adding a new field: // - consider including a unit suffix with the field name // - TOML is limited to int64/float64, so fields requiring greater range/precision must use non-standard types -// implementing encoding.TextMarshaler/TextUnmarshaler, like utils.Big and decimal.Decimal +// implementing encoding.TextMarshaler/TextUnmarshaler, like big.Big and decimal.Decimal // - std lib types that don't implement encoding.TextMarshaler/TextUnmarshaler (time.Duration, url.URL, big.Int) won't -// work as expected, and require wrapper types. See models.Duration, models.URL, utils.Big. +// work as expected, and require wrapper types. See models.Duration, models.URL, big.Big. type Config struct { toml.Core diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 6453fe05e0..85a4c99b86 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -26,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" legacy "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -95,7 +96,7 @@ var ( }, EVM: []*evmcfg.EVMConfig{ { - ChainID: utils.NewBigI(1), + ChainID: big.NewI(1), Chain: evmcfg.Chain{ FinalityDepth: ptr[uint32](26), FinalityTagEnabled: ptr[bool](false), @@ -112,7 +113,7 @@ var ( }, }}, { - ChainID: utils.NewBigI(42), + ChainID: big.NewI(42), Chain: evmcfg.Chain{ GasEstimator: evmcfg.GasEstimator{ PriceDefault: assets.NewWeiI(math.MaxInt64), @@ -125,7 +126,7 @@ var ( }, }}, { - ChainID: utils.NewBigI(137), + ChainID: big.NewI(137), Chain: evmcfg.Chain{ GasEstimator: evmcfg.GasEstimator{ Mode: ptr("FixedPrice"), @@ -463,7 +464,7 @@ func TestConfig_Marshal(t *testing.T) { } full.EVM = []*evmcfg.EVMConfig{ { - ChainID: utils.NewBigI(1), + ChainID: big.NewI(1), Enabled: ptr(false), Chain: evmcfg.Chain{ AutoCreateKey: ptr(false), @@ -1466,7 +1467,7 @@ func assertValidationError(t *testing.T, invalid interface{ Validate() error }, func TestConfig_setDefaults(t *testing.T) { var c Config - c.EVM = evmcfg.EVMConfigs{{ChainID: utils.NewBigI(99999133712345)}} + c.EVM = evmcfg.EVMConfigs{{ChainID: big.NewI(99999133712345)}} c.Cosmos = coscfg.TOMLConfigs{{ChainID: ptr("unknown cosmos chain")}} c.Solana = solana.TOMLConfigs{{ChainID: ptr("unknown solana chain")}} c.Starknet = stkcfg.TOMLConfigs{{ChainID: ptr("unknown starknet chain")}} diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index a0754fa013..d89fbce12d 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -18,6 +18,7 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -31,12 +32,11 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestCoreRelayerChainInteroperators(t *testing.T) { - evmChainID1, evmChainID2 := utils.NewBig(big.NewInt(1)), utils.NewBig(big.NewInt(2)) + evmChainID1, evmChainID2 := ubig.New(big.NewInt(1)), ubig.New(big.NewInt(2)) solanaChainID1, solanaChainID2 := "solana-id-1", "solana-id-2" starknetChainID1, starknetChainID2 := "starknet-id-1", "starknet-id-2" cosmosChainID1, cosmosChainID2 := "cosmos-id-1", "cosmos-id-2" @@ -71,7 +71,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: cfg, Nodes: evmcfg.EVMNodes{&node1_1, &node1_2}, } - id2 := utils.NewBig(big.NewInt(2)) + id2 := ubig.New(big.NewInt(2)) c.EVM = append(c.EVM, &evmcfg.EVMConfig{ ChainID: evmChainID2, Chain: evmcfg.Defaults(id2), diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 865edb1b48..be61cde4d6 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -34,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" pipeline_mocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestDelegate_ServicesForSpec(t *testing.T) { @@ -59,7 +59,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { }) t.Run("Spec with DirectRequestSpec", func(t *testing.T) { - spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{EVMChainID: (*utils.Big)(testutils.FixtureChainID)}, PipelineSpec: &pipeline.Spec{}} + spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{EVMChainID: (*ubig.Big)(testutils.FixtureChainID)}, PipelineSpec: &pipeline.Spec{}} services, err := delegate.ServicesForSpec(spec) require.NoError(t, err) assert.Len(t, services, 1) diff --git a/core/services/directrequest/validate.go b/core/services/directrequest/validate.go index bc31f09b68..271e720660 100644 --- a/core/services/directrequest/validate.go +++ b/core/services/directrequest/validate.go @@ -5,18 +5,18 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type DirectRequestToml struct { ContractAddress ethkey.EIP55Address `toml:"contractAddress"` Requesters models.AddressCollection `toml:"requesters"` MinContractPayment *assets.Link `toml:"minContractPaymentLinkJuels"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` MinIncomingConfirmations null.Uint32 `toml:"minIncomingConfirmations"` } diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index ea6e6cae5a..a1b4e9b283 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" pb "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto" @@ -32,7 +33,6 @@ import ( ocr2 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" ) @@ -1073,7 +1073,7 @@ func (s *service) findExistingJobForOCR2(j *job.Job, qopts pg.QOpt) (int32, erro // findExistingJobForOCRFlux looks for existing job for OCR or flux func (s *service) findExistingJobForOCRFlux(j *job.Job, qopts pg.QOpt) (int32, error) { var address ethkey.EIP55Address - var evmChainID *utils.Big + var evmChainID *big.Big switch j.Type { case job.OffchainReporting: diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index bd0993825e..d37393eba9 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -41,7 +42,6 @@ import ( evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/versioning" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" ) @@ -1543,7 +1543,7 @@ func Test_Service_ListSpecsByJobProposalIDs(t *testing.T) { } func Test_Service_ApproveSpec(t *testing.T) { - var evmChainID *utils.Big + var evmChainID *big.Big address := ethkey.EIP55AddressFromAddress(common.Address{}) externalJobID := uuid.New() diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index 6e06a1e65b..bcbec4363e 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestORM_MostRecentFluxMonitorRoundID(t *testing.T) { @@ -159,7 +159,7 @@ func makeJob(t *testing.T) *job.Job { IdleTimerDisabled: false, CreatedAt: time.Now(), UpdatedAt: time.Now(), - EVMChainID: (*utils.Big)(testutils.FixtureChainID), + EVMChainID: (*big.Big)(testutils.FixtureChainID), }, } } diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 21035140f5..c0622ba806 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -41,7 +42,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const mercuryOracleTOML = `name = 'LINK / ETH | 0x0000000000000000000000000000000000000000000000000000000000000001 | verifier_proxy 0x0000000000000000000000000000000000000001' @@ -695,7 +695,7 @@ func TestORM_CreateJob_EVMChainID_Validation(t *testing.T) { } func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true @@ -764,7 +764,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { } func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true @@ -825,7 +825,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { } func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true @@ -1021,7 +1021,7 @@ func Test_FindJob(t *testing.T) { // Create a config with multiple EVM chains. The test fixtures already load 1337 // Additional chains will need additional fixture statements to add a chain to evm_chains. config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - chainID := utils.NewBigI(1337) + chainID := big.NewI(1337) enabled := true c.EVM = append(c.EVM, &evmcfg.EVMConfig{ ChainID: chainID, @@ -1154,7 +1154,7 @@ func Test_FindJob(t *testing.T) { assert.Equal(t, job.ID, jbID) - _, err2 = orm.FindJobIDByAddress("not-existing", utils.NewBigI(0)) + _, err2 = orm.FindJobIDByAddress("not-existing", big.NewI(0)) require.Error(t, err2) require.ErrorIs(t, err2, sql.ErrNoRows) }) @@ -1222,7 +1222,7 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) - jb.DirectRequestSpec.EVMChainID = utils.NewBigI(0) + jb.DirectRequestSpec.EVMChainID = big.NewI(0) err = orm.CreateJob(&jb) require.NoError(t, err) diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index 66602c6005..062c6e936b 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -3,9 +3,10 @@ package mocks import ( - context "context" - common "github.com/ethereum/go-ethereum/common" + big "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + + context "context" ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -17,8 +18,6 @@ import ( pipeline "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - utils "github.com/smartcontractkit/chainlink/v2/core/utils" - uuid "github.com/google/uuid" ) @@ -223,7 +222,7 @@ func (_m *ORM) FindJobByExternalJobID(_a0 uuid.UUID, qopts ...pg.QOpt) (job.Job, } // FindJobIDByAddress provides a mock function with given fields: address, evmChainID, qopts -func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils.Big, qopts ...pg.QOpt) (int32, error) { +func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -239,16 +238,16 @@ func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils var r0 int32 var r1 error - if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *utils.Big, ...pg.QOpt) (int32, error)); ok { + if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) (int32, error)); ok { return rf(address, evmChainID, qopts...) } - if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *utils.Big, ...pg.QOpt) int32); ok { + if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) int32); ok { r0 = rf(address, evmChainID, qopts...) } else { r0 = ret.Get(0).(int32) } - if rf, ok := ret.Get(1).(func(ethkey.EIP55Address, *utils.Big, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) error); ok { r1 = rf(address, evmChainID, qopts...) } else { r1 = ret.Error(1) diff --git a/core/services/job/models.go b/core/services/job/models.go index 18a0cb79e2..b21ecc12e7 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -246,7 +247,7 @@ type OCROracleSpec struct { ContractConfigTrackerSubscribeInterval models.Interval `toml:"contractConfigTrackerSubscribeInterval"` ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` - EVMChainID *utils.Big `toml:"evmChainID" db:"evm_chain_id"` + EVMChainID *big.Big `toml:"evmChainID" db:"evm_chain_id"` DatabaseTimeout *models.Interval `toml:"databaseTimeout"` ObservationGracePeriod *models.Interval `toml:"observationGracePeriod"` ContractTransmitterTransmitTimeout *models.Interval `toml:"contractTransmitterTransmitTimeout"` @@ -434,7 +435,7 @@ type DirectRequestSpec struct { MinIncomingConfirmations clnull.Uint32 `toml:"minIncomingConfirmations"` Requesters models.AddressCollection `toml:"requesters"` MinContractPayment *commonassets.Link `toml:"minContractPaymentLinkJuels"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` } @@ -475,9 +476,9 @@ type FluxMonitorSpec struct { DrumbeatRandomDelay time.Duration DrumbeatEnabled bool MinPayment *commonassets.Link - EVMChainID *utils.Big `toml:"evmChainID"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` + EVMChainID *big.Big `toml:"evmChainID"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` } type KeeperSpec struct { @@ -485,7 +486,7 @@ type KeeperSpec struct { ContractAddress ethkey.EIP55Address `toml:"contractAddress"` MinIncomingConfirmations *uint32 `toml:"minIncomingConfirmations"` FromAddress ethkey.EIP55Address `toml:"fromAddress"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` } @@ -512,7 +513,7 @@ type VRFSpec struct { CoordinatorAddress ethkey.EIP55Address `toml:"coordinatorAddress"` PublicKey secp256k1.PublicKey `toml:"publicKey"` MinIncomingConfirmations uint32 `toml:"minIncomingConfirmations"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` PollPeriod time.Duration `toml:"pollPeriod"` // For v2 jobs RequestedConfsDelay int64 `toml:"requestedConfsDelay"` // For v2 jobs. Optional, defaults to 0 if not provided. @@ -586,7 +587,7 @@ type BlockhashStoreSpec struct { RunTimeout time.Duration `toml:"runTimeout"` // EVMChainID defines the chain ID for monitoring and storing of blockhashes. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to store blockhashes. FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` @@ -635,7 +636,7 @@ type BlockHeaderFeederSpec struct { RunTimeout time.Duration `toml:"runTimeout"` // EVMChainID defines the chain ID for monitoring and storing of blockhashes. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to store blockhashes. FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` @@ -662,11 +663,11 @@ type LegacyGasStationServerSpec struct { ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` // EVMChainID defines the chain ID from which the meta-transaction request originates. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // CCIPChainSelector is the CCIP chain selector that corresponds to EVMChainID param. // This selector is equivalent to (source) chainID specified in SendTransaction request - CCIPChainSelector *utils.Big `toml:"ccipChainSelector"` + CCIPChainSelector *big.Big `toml:"ccipChainSelector"` // FromAddress is the sender address that should be used to send meta-transactions FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` @@ -699,10 +700,10 @@ type LegacyGasStationSidecarSpec struct { RunTimeout time.Duration `toml:"runTimeout"` // EVMChainID defines the chain ID for the on-chain events tracked by sidecar - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // CCIPChainSelector is the CCIP chain selector that corresponds to EVMChainID param - CCIPChainSelector *utils.Big `toml:"ccipChainSelector"` + CCIPChainSelector *big.Big `toml:"ccipChainSelector"` // CreatedAt is the time this job was created. CreatedAt time.Time `toml:"-"` @@ -772,7 +773,7 @@ type EALSpec struct { ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` // EVMChainID defines the chain ID from which the meta-transaction request originates. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to send meta-transactions FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 482d3d851e..b2cf2b2af4 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" @@ -32,7 +33,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -52,7 +52,7 @@ type ORM interface { FindJobTx(ctx context.Context, id int32) (Job, error) FindJob(ctx context.Context, id int32) (Job, error) FindJobByExternalJobID(uuid uuid.UUID, qopts ...pg.QOpt) (Job, error) - FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils.Big, qopts ...pg.QOpt) (int32, error) + FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) FindOCR2JobIDByAddress(contractID string, feedID *common.Hash, qopts ...pg.QOpt) (int32, error) FindJobIDsWithBridge(name string) ([]int32, error) DeleteJob(id int32, qopts ...pg.QOpt) error @@ -832,7 +832,7 @@ func (o *orm) FindJobByExternalJobID(externalJobID uuid.UUID, qopts ...pg.QOpt) } // FindJobIDByAddress - finds a job id by contract address. Currently only OCR and FM jobs are supported -func (o *orm) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils.Big, qopts ...pg.QOpt) (jobID int32, err error) { +func (o *orm) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (jobID int32, err error) { q := o.q.WithOpts(qopts...) err = q.Transaction(func(tx pg.Queryer) error { stmt := ` diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index 29a0b68702..c35ebc81b7 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_logic1_3" @@ -36,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keeper" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" webpresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -405,7 +405,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) // disable reorg protection for this test c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) // helps prevent missed heads c.EVM[0].Transactions.ForwardersEnabled = ptr(true) // Enable Operator Forwarder flow - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) scopedConfig := evmtest.NewChainScopedConfig(t, config) korm := keeper.NewORM(db, logger.TestLogger(t), scopedConfig.Database()) @@ -414,7 +414,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) forwarderORM := forwarders.NewORM(db, logger.TestLogger(t), config.Database()) - chainID := utils.Big(*backend.ConfiguredChainID()) + chainID := ubig.Big(*backend.ConfiguredChainID()) _, err = forwarderORM.CreateForwarder(fwdrAddress, chainID) require.NoError(t, err) @@ -431,7 +431,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { KeeperSpec: &job.KeeperSpec{ FromAddress: nodeAddressEIP55, ContractAddress: regAddrEIP55, - EVMChainID: (*utils.Big)(testutils.SimulatedChainID), + EVMChainID: (*ubig.Big)(testutils.SimulatedChainID), }, SchemaVersion: 1, ForwardingAllowed: true, diff --git a/core/services/keeper/models.go b/core/services/keeper/models.go index fd5538b604..8f72f0b22c 100644 --- a/core/services/keeper/models.go +++ b/core/services/keeper/models.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -34,7 +35,7 @@ type UpkeepRegistration struct { LastRunBlockHeight int64 RegistryID int64 Registry Registry - UpkeepID *utils.Big + UpkeepID *big.Big LastKeeperIndex null.Int64 PositioningConstant int32 } @@ -60,16 +61,16 @@ func (upkeep UpkeepRegistration) PrettyID() string { return NewUpkeepIdentifier(upkeep.UpkeepID).String() } -func NewUpkeepIdentifier(i *utils.Big) *UpkeepIdentifier { +func NewUpkeepIdentifier(i *big.Big) *UpkeepIdentifier { val := UpkeepIdentifier(*i) return &val } -type UpkeepIdentifier utils.Big +type UpkeepIdentifier big.Big // String produces a hex encoded value, zero padded, prefixed with UpkeepPrefix func (ui UpkeepIdentifier) String() string { - val := utils.Big(ui) + val := big.Big(ui) result, err := utils.Uint256ToBytes(val.ToInt()) if err != nil { panic(errors.Wrap(err, "invariant, invalid upkeepID")) diff --git a/core/services/keeper/models_test.go b/core/services/keeper/models_test.go index ad81f47d8e..729d1bbf23 100644 --- a/core/services/keeper/models_test.go +++ b/core/services/keeper/models_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func TestUpkeepIdentifer_String(t *testing.T) { @@ -26,7 +26,7 @@ func TestUpkeepIdentifer_String(t *testing.T) { return } - result := NewUpkeepIdentifier(utils.NewBig(o)).String() + result := NewUpkeepIdentifier(ubig.New(o)).String() require.Equal(t, test.hex, result) }) } diff --git a/core/services/keeper/orm.go b/core/services/keeper/orm.go index 91883f8056..fc8770cd86 100644 --- a/core/services/keeper/orm.go +++ b/core/services/keeper/orm.go @@ -7,10 +7,10 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM implements ORM layer using PostgreSQL @@ -86,7 +86,7 @@ RETURNING * } // UpdateUpkeepLastKeeperIndex updates the last keeper index for an upkeep -func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *utils.Big, fromAddress ethkey.EIP55Address) error { +func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *big.Big, fromAddress ethkey.EIP55Address) error { _, err := korm.q.Exec(` UPDATE upkeep_registrations SET @@ -98,7 +98,7 @@ func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *utils.Big, fr } // BatchDeleteUpkeepsForJob deletes all upkeeps by the given IDs for the job with the given ID -func (korm ORM) BatchDeleteUpkeepsForJob(jobID int32, upkeepIDs []utils.Big) (int64, error) { +func (korm ORM) BatchDeleteUpkeepsForJob(jobID int32, upkeepIDs []big.Big) (int64, error) { strIds := []string{} for _, upkeepID := range upkeepIDs { strIds = append(strIds, upkeepID.String()) @@ -202,7 +202,7 @@ func loadUpkeepsRegistry(q pg.Queryer, upkeeps []UpkeepRegistration) error { return nil } -func (korm ORM) AllUpkeepIDsForRegistry(regID int64) (upkeeps []utils.Big, err error) { +func (korm ORM) AllUpkeepIDsForRegistry(regID int64) (upkeeps []big.Big, err error) { err = korm.q.Select(&upkeeps, ` SELECT upkeep_id FROM upkeep_registrations @@ -212,7 +212,7 @@ WHERE registry_id = $1 } // SetLastRunInfoForUpkeepOnJob sets the last run block height and the associated keeper index only if the new block height is greater than the previous. -func (korm ORM) SetLastRunInfoForUpkeepOnJob(jobID int32, upkeepID *utils.Big, height int64, fromAddress ethkey.EIP55Address, qopts ...pg.QOpt) (int64, error) { +func (korm ORM) SetLastRunInfoForUpkeepOnJob(jobID int32, upkeepID *big.Big, height int64, fromAddress ethkey.EIP55Address, qopts ...pg.QOpt) (int64, error) { res, err := korm.q.WithOpts(qopts...).Exec(` UPDATE upkeep_registrations SET last_run_block_height = $1, diff --git a/core/services/keeper/orm_test.go b/core/services/keeper/orm_test.go index d67baa09a0..e5b56e9511 100644 --- a/core/services/keeper/orm_test.go +++ b/core/services/keeper/orm_test.go @@ -15,6 +15,7 @@ import ( "github.com/jmoiron/sqlx" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -45,7 +46,7 @@ func setupKeeperDB(t *testing.T) ( func newUpkeep(registry keeper.Registry, upkeepID int64) keeper.UpkeepRegistration { return keeper.UpkeepRegistration{ - UpkeepID: utils.NewBigI(upkeepID), + UpkeepID: ubig.NewI(upkeepID), ExecuteGas: executeGas, Registry: registry, RegistryID: registry.ID, @@ -103,7 +104,7 @@ func TestKeeperDB_UpsertUpkeep(t *testing.T) { registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) upkeep := keeper.UpkeepRegistration{ - UpkeepID: utils.NewBigI(0), + UpkeepID: ubig.NewI(0), ExecuteGas: executeGas, Registry: registry, RegistryID: registry.ID, @@ -139,7 +140,7 @@ func TestKeeperDB_BatchDeleteUpkeepsForJob(t *testing.T) { registry, job := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) expectedUpkeepID := cltest.MustInsertUpkeepForRegistry(t, db, config.Database(), registry).UpkeepID - var upkeepIDs []utils.Big + var upkeepIDs []ubig.Big for i := 0; i < 2; i++ { upkeep := cltest.MustInsertUpkeepForRegistry(t, db, config.Database(), registry) upkeepIDs = append(upkeepIDs, *upkeep.UpkeepID) @@ -180,7 +181,7 @@ func TestKeeperDB_EligibleUpkeeps_Shuffle(t *testing.T) { assert.NoError(t, err) require.Len(t, eligibleUpkeeps, 100) - shuffled := [100]*utils.Big{} + shuffled := [100]*ubig.Big{} for i := 0; i < 100; i++ { shuffled[i] = eligibleUpkeeps[i].UpkeepID } @@ -372,8 +373,8 @@ func TestKeeperDB_AllUpkeepIDsForRegistry(t *testing.T) { require.NoError(t, err) // No upkeeps returned require.Len(t, upkeepIDs, 2) - require.Contains(t, upkeepIDs, *utils.NewBig(big.NewInt(3))) - require.Contains(t, upkeepIDs, *utils.NewBig(big.NewInt(8))) + require.Contains(t, upkeepIDs, *ubig.New(big.NewInt(3))) + require.Contains(t, upkeepIDs, *ubig.New(big.NewInt(8))) } func TestKeeperDB_UpdateUpkeepLastKeeperIndex(t *testing.T) { diff --git a/core/services/keeper/registry1_1_synchronizer_test.go b/core/services/keeper/registry1_1_synchronizer_test.go index fb0b1866c4..a4f03d4d34 100644 --- a/core/services/keeper/registry1_1_synchronizer_test.go +++ b/core/services/keeper/registry1_1_synchronizer_test.go @@ -16,6 +16,7 @@ import ( evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" registry1_1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -24,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var registryConfig1_1 = registry1_1.GetConfig{ @@ -123,7 +123,7 @@ func Test_RegistrySynchronizer1_1_Start(t *testing.T) { func Test_RegistrySynchronizer_CalcPositioningConstant(t *testing.T) { t.Parallel() for _, upkeepID := range []int64{0, 1, 100, 10_000} { - _, err := keeper.CalcPositioningConstant(utils.NewBigI(upkeepID), cltest.NewEIP55Address()) + _, err := keeper.CalcPositioningConstant(ubig.NewI(upkeepID), cltest.NewEIP55Address()) require.NoError(t, err) } } diff --git a/core/services/keeper/registry1_3_synchronizer_test.go b/core/services/keeper/registry1_3_synchronizer_test.go index 6e3be4ea78..77bb873e1d 100644 --- a/core/services/keeper/registry1_3_synchronizer_test.go +++ b/core/services/keeper/registry1_3_synchronizer_test.go @@ -17,6 +17,7 @@ import ( evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var registryConfig1_3 = registry1_3.Config{ @@ -654,7 +654,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T cltest.WaitForCount(t, db, "upkeep_registrations", 3) var upkeep keeper.UpkeepRegistration - err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, utils.NewBig(upkeepId)) + err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, ubig.New(upkeepId)) require.NoError(t, err) require.Equal(t, upkeepId.String(), upkeep.UpkeepID.String()) @@ -714,7 +714,7 @@ func Test_RegistrySynchronizer1_3_UpkeepCheckDataUpdatedLog(t *testing.T) { g.Eventually(func() []byte { var upkeep keeper.UpkeepRegistration - err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, utils.NewBig(upkeepId)) + err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, ubig.New(upkeepId)) require.NoError(t, err) return upkeep.CheckData }, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(newCheckData)) diff --git a/core/services/keeper/registry_synchronizer_process_logs.go b/core/services/keeper/registry_synchronizer_process_logs.go index 9e1aa3b410..7b82f49ae4 100644 --- a/core/services/keeper/registry_synchronizer_process_logs.go +++ b/core/services/keeper/registry_synchronizer_process_logs.go @@ -7,11 +7,11 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" registry1_1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" registry1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func (rs *RegistrySynchronizer) processLogs() { @@ -109,7 +109,7 @@ func (rs *RegistrySynchronizer) handleUpkeepCancelled(broadcast log.Broadcast) e return errors.Wrap(err, "Unable to fetch cancelled upkeep ID from log") } - affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []utils.Big{*utils.NewBig(cancelledID)}) + affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []big.Big{*big.New(cancelledID)}) if err != nil { return errors.Wrap(err, "unable to batch delete upkeeps") } @@ -130,7 +130,7 @@ func (rs *RegistrySynchronizer) handleUpkeepRegistered(broadcast log.Broadcast) return errors.Wrap(err, "Unable to fetch upkeep ID from registration log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(upkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(upkeepID)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %v", broadcast.String()) } @@ -144,7 +144,7 @@ func (rs *RegistrySynchronizer) handleUpkeepPerformed(broadcast log.Broadcast) e if err != nil { return errors.Wrap(err, "Unable to fetch upkeep ID from performed log") } - rowsAffected, err := rs.orm.SetLastRunInfoForUpkeepOnJob(rs.job.ID, utils.NewBig(log.UpkeepID), int64(broadcast.RawLog().BlockNumber), ethkey.EIP55AddressFromAddress(log.FromKeeper)) + rowsAffected, err := rs.orm.SetLastRunInfoForUpkeepOnJob(rs.job.ID, big.New(log.UpkeepID), int64(broadcast.RawLog().BlockNumber), ethkey.EIP55AddressFromAddress(log.FromKeeper)) if err != nil { return errors.Wrap(err, "failed to set last run to 0") } @@ -171,7 +171,7 @@ func (rs *RegistrySynchronizer) handleUpkeepGasLimitSet(broadcast log.Broadcast) return errors.Wrap(err, "Unable to fetch upkeep ID from gas limit set log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(upkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(upkeepID)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %v", broadcast.String()) } @@ -191,7 +191,7 @@ func (rs *RegistrySynchronizer) handleUpkeepReceived(broadcast log.Broadcast) er return errors.Wrap(err, "Unable to fetch upkeep ID from received log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(upkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(upkeepID)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %v", broadcast.String()) } @@ -206,7 +206,7 @@ func (rs *RegistrySynchronizer) handleUpkeepMigrated(broadcast log.Broadcast) er return errors.Wrap(err, "Unable to fetch migrated upkeep ID from log") } - affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []utils.Big{*utils.NewBig(migratedID)}) + affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []big.Big{*big.New(migratedID)}) if err != nil { return errors.Wrap(err, "unable to batch delete upkeeps") } @@ -222,7 +222,7 @@ func (rs *RegistrySynchronizer) handleUpkeepPaused(broadcast log.Broadcast) erro return errors.Wrap(err, "Unable to fetch upkeep ID from upkeep paused log") } - _, err = rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []utils.Big{*utils.NewBig(pausedUpkeepId)}) + _, err = rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []big.Big{*big.New(pausedUpkeepId)}) if err != nil { return errors.Wrap(err, "unable to batch delete upkeeps") } @@ -243,7 +243,7 @@ func (rs *RegistrySynchronizer) handleUpkeepUnpaused(broadcast log.Broadcast) er return errors.Wrap(err, "Unable to fetch upkeep ID from upkeep unpaused log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(unpausedUpkeepId)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(unpausedUpkeepId)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %s", broadcast.String()) } @@ -264,7 +264,7 @@ func (rs *RegistrySynchronizer) handleUpkeepCheckDataUpdated(broadcast log.Broad return errors.Wrap(err, "Unable to parse update log from upkeep check data updated log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(updateLog.UpkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(updateLog.UpkeepID)) if err != nil { return errors.Wrapf(err, "unable to update check data for upkeep %s", updateLog.UpkeepID.String()) } diff --git a/core/services/keeper/registry_synchronizer_sync.go b/core/services/keeper/registry_synchronizer_sync.go index 649ccd9406..f90e0bc85d 100644 --- a/core/services/keeper/registry_synchronizer_sync.go +++ b/core/services/keeper/registry_synchronizer_sync.go @@ -7,6 +7,7 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -53,15 +54,15 @@ func (rs *RegistrySynchronizer) fullSyncUpkeeps(reg Registry) error { } activeSet := make(map[string]bool) - allActiveUpkeeps := make([]utils.Big, 0) + allActiveUpkeeps := make([]big.Big, 0) for _, upkeepID := range activeUpkeepIDs { activeSet[upkeepID.String()] = true - allActiveUpkeeps = append(allActiveUpkeeps, *utils.NewBig(upkeepID)) + allActiveUpkeeps = append(allActiveUpkeeps, *big.New(upkeepID)) } rs.batchSyncUpkeepsOnRegistry(reg, allActiveUpkeeps) // All upkeeps in existingUpkeepIDs, not in activeUpkeepIDs should be deleted - canceled := make([]utils.Big, 0) + canceled := make([]big.Big, 0) for _, upkeepID := range existingUpkeepIDs { if _, found := activeSet[upkeepID.ToInt().String()]; !found { canceled = append(canceled, upkeepID) @@ -75,7 +76,7 @@ func (rs *RegistrySynchronizer) fullSyncUpkeeps(reg Registry) error { // batchSyncUpkeepsOnRegistry syncs upkeeps at a time in parallel // for all the IDs within newUpkeeps slice -func (rs *RegistrySynchronizer) batchSyncUpkeepsOnRegistry(reg Registry, newUpkeeps []utils.Big) { +func (rs *RegistrySynchronizer) batchSyncUpkeepsOnRegistry(reg Registry, newUpkeeps []big.Big) { wg := sync.WaitGroup{} wg.Add(len(newUpkeeps)) chSyncUpkeepQueue := make(chan struct{}, rs.syncUpkeepQueueSize) @@ -93,7 +94,7 @@ func (rs *RegistrySynchronizer) batchSyncUpkeepsOnRegistry(reg Registry, newUpke wg.Wait() } -func (rs *RegistrySynchronizer) syncUpkeepWithCallback(getter upkeepGetter, registry Registry, upkeepID *utils.Big, doneCallback func()) { +func (rs *RegistrySynchronizer) syncUpkeepWithCallback(getter upkeepGetter, registry Registry, upkeepID *big.Big, doneCallback func()) { defer doneCallback() if err := rs.syncUpkeep(getter, registry, upkeepID); err != nil { @@ -104,7 +105,7 @@ func (rs *RegistrySynchronizer) syncUpkeepWithCallback(getter upkeepGetter, regi } } -func (rs *RegistrySynchronizer) syncUpkeep(getter upkeepGetter, registry Registry, upkeepID *utils.Big) error { +func (rs *RegistrySynchronizer) syncUpkeep(getter upkeepGetter, registry Registry, upkeepID *big.Big) error { upkeep, err := getter.GetUpkeep(nil, upkeepID.ToInt()) if err != nil { return errors.Wrap(err, "failed to get upkeep config") @@ -173,9 +174,9 @@ func (rs *RegistrySynchronizer) newRegistryFromChain() (Registry, error) { // CalcPositioningConstant calculates a positioning constant. // The positioning constant is fixed because upkeepID and registryAddress are immutable -func CalcPositioningConstant(upkeepID *utils.Big, registryAddress ethkey.EIP55Address) (int32, error) { +func CalcPositioningConstant(upkeepID *big.Big, registryAddress ethkey.EIP55Address) (int32, error) { upkeepBytes := make([]byte, binary.MaxVarintLen64) - binary.PutVarint(upkeepBytes, upkeepID.Mod(utils.NewBigI(math.MaxInt64)).Int64()) + binary.PutVarint(upkeepBytes, upkeepID.Mod(big.NewI(math.MaxInt64)).Int64()) bytesToHash := utils.ConcatBytes(upkeepBytes, registryAddress.Bytes()) checksum, err := utils.Keccak256(bytesToHash) if err != nil { diff --git a/core/services/keeper/registry_synchronizer_sync_test.go b/core/services/keeper/registry_synchronizer_sync_test.go index 10a51679c5..e6f42a8320 100644 --- a/core/services/keeper/registry_synchronizer_sync_test.go +++ b/core/services/keeper/registry_synchronizer_sync_test.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // GetUpkeepFailure implements the upkeepGetter interface with an induced error and nil @@ -42,7 +42,7 @@ func TestSyncUpkeepWithCallback_UpkeepNotFound(t *testing.T) { t.FailNow() } - id := utils.NewBig(o) + id := ubig.New(o) count := 0 doneFunc := func() { count++ diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 123b1dc0de..61ccca956f 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -23,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -39,7 +40,7 @@ import ( ) func newHead() evmtypes.Head { - return evmtypes.NewHead(big.NewInt(20), utils.NewHash(), utils.NewHash(), 1000, utils.NewBigI(0)) + return evmtypes.NewHead(big.NewInt(20), utils.NewHash(), utils.NewHash(), 1000, ubig.NewI(0)) } func mockEstimator(t *testing.T) gas.EvmFeeEstimator { @@ -128,7 +129,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { t.Run("runs upkeep on triggering block number", func(t *testing.T) { db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) gasLimit := 5_000_000 + config.Keeper().Registry().PerformGasOverhead() @@ -173,7 +174,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { runTest := func(t *testing.T, eip1559 bool) { db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &eip1559 - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) gasLimit := 5_000_000 + config.Keeper().Registry().PerformGasOverhead() @@ -226,7 +227,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { t.Run("errors if submission key not found", func(t *testing.T) { _, _, ethMock, executer, registry, _, job, jpv2, _, keyStore, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) // replace expected key with random one @@ -263,7 +264,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { registry, jb := cltest.MustInsertKeeperRegistry(t, db, orm, keyStore.Eth(), 0, 1, 20) // change chain ID to non-configured chain - jb.KeeperSpec.EVMChainID = (*utils.Big)(big.NewInt(999)) + jb.KeeperSpec.EVMChainID = (*ubig.Big)(big.NewInt(999)) cltest.MustInsertUpkeepForRegistry(t, db, ch.Config().Database(), registry) lggr := logger.TestLogger(t) executer := keeper.NewUpkeepExecuter(jb, orm, jpv2.Pr, ethMock, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, ch.Config().Keeper(), jb.KeeperSpec.FromAddress.Address()) @@ -278,7 +279,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { t.Run("triggers if heads are skipped but later heads arrive within range", func(t *testing.T) { db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) etxs := []cltest.Awaiter{ @@ -321,7 +322,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Error(t *testing.T) { db, _, ethMock, executer, registry, _, _, _, _, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) var wasCalled atomic.Bool diff --git a/core/services/keeper/upkeep_executer_unit_test.go b/core/services/keeper/upkeep_executer_unit_test.go index a8fc46319c..8589720ca5 100644 --- a/core/services/keeper/upkeep_executer_unit_test.go +++ b/core/services/keeper/upkeep_executer_unit_test.go @@ -7,11 +7,11 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type registry struct { @@ -34,7 +34,7 @@ func TestBuildJobSpec(t *testing.T) { ContractAddress: contract, }} - upkeepID := utils.NewBigI(4) + upkeepID := big.NewI(4) upkeep := UpkeepRegistration{ Registry: Registry{ FromAddress: from, diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 42d6c57537..3935a44558 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -673,7 +674,7 @@ func Test_EthKeyStore_Delete(t *testing.T) { _, addr1 := cltest.MustInsertRandomKey(t, ks) _, addr2 := cltest.MustInsertRandomKey(t, ks) - cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.SimulatedChainID)) + cltest.MustInsertRandomKey(t, ks, *ubig.New(testutils.SimulatedChainID)) require.NoError(t, ks.Add(addr1, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(addr1, testutils.SimulatedChainID)) diff --git a/core/services/keystore/keys/ethkey/models.go b/core/services/keystore/keys/ethkey/models.go index b90503c3ed..df4c474b7b 100644 --- a/core/services/keystore/keys/ethkey/models.go +++ b/core/services/keystore/keys/ethkey/models.go @@ -3,13 +3,13 @@ package ethkey import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type State struct { ID int32 Address EIP55Address - EVMChainID utils.Big + EVMChainID big.Big Disabled bool CreatedAt time.Time UpdatedAt time.Time diff --git a/core/services/ocr/database.go b/core/services/ocr/database.go index 524dfa0e7b..cec9596bb9 100644 --- a/core/services/ocr/database.go +++ b/core/services/ocr/database.go @@ -15,9 +15,9 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type db struct { @@ -161,7 +161,7 @@ func (d *db) WriteConfig(ctx context.Context, c ocrtypes.ContractConfig) error { } func (d *db) StorePendingTransmission(ctx context.Context, k ocrtypes.ReportTimestamp, p ocrtypes.PendingTransmission) error { - median := utils.NewBig(p.Median) + median := big.New(p.Median) var rs [][]byte var ss [][]byte // Note: p.Rs and p.Ss are of type [][32]byte. @@ -232,7 +232,7 @@ WHERE ocr_oracle_spec_id = $1 AND config_digest = $2 k := ocrtypes.ReportTimestamp{} p := ocrtypes.PendingTransmission{} - var median utils.Big + var median big.Big var rs [][]byte var ss [][]byte var vs []byte diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index b55e128119..3da0c9cbfd 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -23,11 +24,10 @@ import ( ocr2validate "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestGetEVMEffectiveTransmitterID(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go index 0e0ceba716..51448db35c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go @@ -16,8 +16,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestGetActiveUpkeepKeys(t *testing.T) { @@ -176,8 +176,8 @@ func TestPollLogs(t *testing.T) { InputStart: 250, InputEnd: 500, OutputLogs: []logpoller.Log{ - {EvmChainId: utils.NewBig(big.NewInt(5)), LogIndex: 1}, - {EvmChainId: utils.NewBig(big.NewInt(6)), LogIndex: 2}, + {EvmChainId: ubig.New(big.NewInt(5)), LogIndex: 1}, + {EvmChainId: ubig.New(big.NewInt(6)), LogIndex: 2}, }, OutputErr: nil, }, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go index 89b19b4a81..65fe3c85fb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go @@ -21,12 +21,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestLogRecoverer_GetRecoverables(t *testing.T) { @@ -1023,7 +1023,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ { - EvmChainId: utils.NewBig(big.NewInt(1)), + EvmChainId: ubig.New(big.NewInt(1)), LogIndex: 3, BlockHash: [32]byte{1}, BlockNumber: 80, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go index f3e4402092..0d097ceadb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go @@ -19,6 +19,7 @@ import ( types3 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" @@ -27,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestPollLogs(t *testing.T) { @@ -132,8 +132,8 @@ func TestPollLogs(t *testing.T) { InputStart: 250, InputEnd: 500, OutputLogs: []logpoller.Log{ - {EvmChainId: utils.NewBig(big.NewInt(5)), LogIndex: 1}, - {EvmChainId: utils.NewBig(big.NewInt(6)), LogIndex: 2}, + {EvmChainId: ubig.New(big.NewInt(5)), LogIndex: 1}, + {EvmChainId: ubig.New(big.NewInt(6)), LogIndex: 2}, }, OutputErr: nil, }, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go index c918ad595f..a5bd738de4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go @@ -7,18 +7,18 @@ import ( "github.com/jmoiron/sqlx" "github.com/lib/pq" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type orm struct { - chainID *utils.Big + chainID *ubig.Big q pg.Q } type persistedStateRecord struct { - UpkeepID *utils.Big + UpkeepID *ubig.Big WorkID string CompletionState uint8 BlockNumber int64 @@ -29,7 +29,7 @@ type persistedStateRecord struct { // NewORM creates an ORM scoped to chainID. func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *orm { return &orm{ - chainID: utils.NewBig(chainID), + chainID: ubig.New(chainID), q: pg.NewQ(db, lggr.Named("ORM"), cfg), } } @@ -43,12 +43,12 @@ func (o *orm) BatchInsertRecords(state []persistedStateRecord, qopts ...pg.QOpt) } type row struct { - EvmChainId *utils.Big + EvmChainId *ubig.Big WorkId string CompletionState uint8 BlockNumber int64 InsertedAt time.Time - UpkeepId *utils.Big + UpkeepId *ubig.Big IneligibilityReason uint8 } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go index 54ca7285dd..bfd131b505 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestInsertSelectDelete(t *testing.T) { @@ -23,7 +23,7 @@ func TestInsertSelectDelete(t *testing.T) { inserted := []persistedStateRecord{ { - UpkeepID: utils.NewBig(big.NewInt(2)), + UpkeepID: ubig.New(big.NewInt(2)), WorkID: "0x1", CompletionState: 100, BlockNumber: 2, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go index 4a4de5ea1a..19b3c46f50 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -225,7 +226,7 @@ func (u *upkeepStateStore) upsertStateRecord(ctx context.Context, workID string, u.cache[workID] = record u.pendingRecords = append(u.pendingRecords, persistedStateRecord{ - UpkeepID: utils.NewBig(upkeepID), + UpkeepID: ubig.New(upkeepID), WorkID: record.workID, CompletionState: uint8(record.state), IneligibilityReason: reason, diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 58c1e38e01..6674b0828b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -37,6 +37,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" @@ -60,7 +61,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -448,7 +448,7 @@ func setupForwarderForNode( // add forwarder address to be tracked in db forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), app.GetConfig().Database()) - chainID := utils.Big(*backend.Blockchain().Config().ChainID) + chainID := ubig.Big(*backend.Blockchain().Config().ChainID) _, err = forwarderORM.CreateForwarder(faddr, chainID) require.NoError(t, err) diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index 4a583e5db3..c559fb27fb 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -33,6 +33,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract" @@ -285,7 +286,7 @@ func setupNodeOCR2( // Add the forwarder to the node's forwarder manager. forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), config.Database()) - chainID := utils.Big(*b.Blockchain().Config().ChainID) + chainID := ubig.Big(*b.Blockchain().Config().ChainID) _, err = forwarderORM.CreateForwarder(faddr, chainID) require.NoError(t, err) effectiveTransmitter = faddr diff --git a/core/services/ocr2/plugins/s4/integration_test.go b/core/services/ocr2/plugins/s4/integration_test.go index 54f0f02ad9..8efe38f8e2 100644 --- a/core/services/ocr2/plugins/s4/integration_test.go +++ b/core/services/ocr2/plugins/s4/integration_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -16,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" "github.com/smartcontractkit/chainlink/v2/core/services/pg" s4_svc "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -357,14 +357,14 @@ func TestS4Integration_RandomState(t *testing.T) { type user struct { privateKey *ecdsa.PrivateKey - address *utils.Big + address *big.Big } nUsers := 100 users := make([]user, nUsers) for i := 0; i < nUsers; i++ { pk, addr := testutils.NewPrivateKeyAndAddress(t) - users[i] = user{pk, utils.NewBig(addr.Big())} + users[i] = user{pk, big.New(addr.Big())} } // generating test records diff --git a/core/services/ocr2/plugins/s4/messages.go b/core/services/ocr2/plugins/s4/messages.go index 8f3a64f4e2..c9695d2db7 100644 --- a/core/services/ocr2/plugins/s4/messages.go +++ b/core/services/ocr2/plugins/s4/messages.go @@ -4,8 +4,8 @@ import ( "bytes" "math/big" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "google.golang.org/protobuf/proto" @@ -58,8 +58,8 @@ func UnmarshalRows(data []byte) ([]*Row, error) { return rows.Rows, nil } -func UnmarshalAddress(address []byte) *utils.Big { - return utils.NewBig(new(big.Int).SetBytes(address)) +func UnmarshalAddress(address []byte) *ubig.Big { + return ubig.New(new(big.Int).SetBytes(address)) } func (row *Row) VerifySignature() error { diff --git a/core/services/ocr2/plugins/s4/plugin.go b/core/services/ocr2/plugins/s4/plugin.go index 68bd9fd214..fcb025b21c 100644 --- a/core/services/ocr2/plugins/s4/plugin.go +++ b/core/services/ocr2/plugins/s4/plugin.go @@ -4,9 +4,9 @@ import ( "context" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/pkg/errors" "github.com/smartcontractkit/libocr/commontypes" @@ -123,7 +123,7 @@ func (c *plugin) Observation(ctx context.Context, ts types.ReportTimestamp, quer c.logger.Error("ORM GetSnapshot error", commontypes.LogFields{"err": err}) } else { type rkey struct { - address *utils.Big + address *big.Big slotID uint } diff --git a/core/services/ocr2/plugins/s4/plugin_test.go b/core/services/ocr2/plugins/s4/plugin_test.go index e2b5d21b84..e0aa84183e 100644 --- a/core/services/ocr2/plugins/s4/plugin_test.go +++ b/core/services/ocr2/plugins/s4/plugin_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" s4_svc "github.com/smartcontractkit/chainlink/v2/core/services/s4" s4_mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -51,7 +51,7 @@ func generateTestRows(t *testing.T, n int, ttl time.Duration) []*s4.Row { func generateTestOrmRow(t *testing.T, ttl time.Duration, version uint64, confimed bool) *s4_svc.Row { priv, addr := testutils.NewPrivateKeyAndAddress(t) row := &s4_svc.Row{ - Address: utils.NewBig(addr.Big()), + Address: big.New(addr.Big()), SlotId: 0, Version: version, Confirmed: confimed, @@ -296,7 +296,7 @@ func TestPlugin_Query(t *testing.T) { for i := 0; i < 256; i++ { var thisAddress common.Address thisAddress[0] = byte(i) - ormRows[i].Address = utils.NewBig(thisAddress.Big()) + ormRows[i].Address = big.New(thisAddress.Big()) } versions := rowsToShapshotRows(ormRows) @@ -322,7 +322,7 @@ func TestPlugin_Query(t *testing.T) { assert.Len(t, qq.Rows, 16) for _, r := range qq.Rows { thisAddress := s4.UnmarshalAddress(r.Address) - assert.True(t, ar.Contains((*utils.Big)(thisAddress))) + assert.True(t, ar.Contains((*big.Big)(thisAddress))) } ar.Advance() diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index 9c90eea180..7627a627de 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -19,6 +19,7 @@ import ( mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" mercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -147,7 +148,7 @@ func TestGetChainID(t *testing.T) { } j.Type = job.Type(pipeline.OffchainReportingJobType) - j.OCROracleSpec.EVMChainID = (*utils.Big)(big.NewInt(1234567890)) + j.OCROracleSpec.EVMChainID = (*ubig.Big)(big.NewInt(1234567890)) assert.Equal(t, "1234567890", e.getChainID()) j.Type = job.Type(pipeline.OffchainReporting2JobType) @@ -206,7 +207,7 @@ func TestSendEATelemetry(t *testing.T) { OCROracleSpec: &job.OCROracleSpec{ ContractAddress: ethkey.EIP55AddressFromAddress(feedAddress), CaptureEATelemetry: true, - EVMChainID: (*utils.Big)(big.NewInt(9)), + EVMChainID: (*ubig.Big)(big.NewInt(9)), }, } diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index dcbbfd9c97..92a6c25da3 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -13,6 +13,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -531,7 +532,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { FromAddress: cltest.NewEIP55Address(), CreatedAt: timestamp, UpdatedAt: timestamp, - EVMChainID: (*utils.Big)(&cltest.FixtureChainID), + EVMChainID: (*big.Big)(&cltest.FixtureChainID), }, ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), PipelineSpec: &pipeline.Spec{ @@ -630,7 +631,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { ContractAddress: cltest.NewEIP55Address(), CreatedAt: timestamp, UpdatedAt: timestamp, - EVMChainID: (*utils.Big)(&cltest.FixtureChainID), + EVMChainID: (*big.Big)(&cltest.FixtureChainID), }, ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), PipelineSpec: &pipeline.Spec{ diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 1cebba2faf..7b9930e4da 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" @@ -29,7 +30,7 @@ import ( ) func newHead() evmtypes.Head { - return evmtypes.Head{Number: 42, EVMChainID: utils.NewBigI(0)} + return evmtypes.Head{Number: 42, EVMChainID: ubig.NewI(0)} } func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer { diff --git a/core/services/relay/evm/median_test.go b/core/services/relay/evm/median_test.go index 4286290d28..9c474006aa 100644 --- a/core/services/relay/evm/median_test.go +++ b/core/services/relay/evm/median_test.go @@ -9,11 +9,11 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestNewMedianProvider(t *testing.T) { @@ -37,7 +37,7 @@ func TestNewMedianProvider(t *testing.T) { }) t.Run("invalid contractID", func(t *testing.T) { - relayConfig := evmtypes.RelayConfig{ChainID: utils.NewBig(chainID)} + relayConfig := evmtypes.RelayConfig{ChainID: big.New(chainID)} rc, err2 := json.Marshal(&relayConfig) require.NoError(t, err2) rargsBadContractID := commontypes.RelayArgs{ContractID: "NotAContractID", RelayConfig: rc} diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go index 3f4a3749ac..af15461aee 100644 --- a/core/services/relay/evm/relayer_extender_test.go +++ b/core/services/relay/evm/relayer_extender_test.go @@ -10,6 +10,7 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -17,7 +18,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestChainRelayExtenders(t *testing.T) { @@ -28,7 +28,7 @@ func TestChainRelayExtenders(t *testing.T) { one := uint32(1) c.EVM[0].MinIncomingConfirmations = &one t := true - c.EVM = append(c.EVM, &toml.EVMConfig{ChainID: utils.NewBig(newId), Enabled: &t, Chain: toml.Defaults(nil)}) + c.EVM = append(c.EVM, &toml.EVMConfig{ChainID: ubig.New(newId), Enabled: &t, Chain: toml.Defaults(nil)}) }) db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db, cfg.Database()) diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index 24afb65c55..129ccb4a5e 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type ChainReaderConfig struct { @@ -47,7 +47,7 @@ const ( ) type RelayConfig struct { - ChainID *utils.Big `json:"chainID"` + ChainID *big.Big `json:"chainID"` FromBlock uint64 `json:"fromBlock"` EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` ConfigContractAddress *common.Address `json:"configContractAddress"` diff --git a/core/services/relay/evm/types/types_test.go b/core/services/relay/evm/types/types_test.go index dec368614e..6952c35a70 100644 --- a/core/services/relay/evm/types/types_test.go +++ b/core/services/relay/evm/types/types_test.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -// ChainID *utils.Big `json:"chainID"` +// ChainID *big.Big `json:"chainID"` // FromBlock uint64 `json:"fromBlock"` // // Contract-specific diff --git a/core/services/s4/address_range.go b/core/services/s4/address_range.go index 679bb3b846..e7b60ecb47 100644 --- a/core/services/s4/address_range.go +++ b/core/services/s4/address_range.go @@ -5,23 +5,23 @@ import ( "errors" "math/big" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/ethereum/go-ethereum/common" + + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // AddressRange represents a range of Ethereum addresses. type AddressRange struct { // MinAddress (inclusive). - MinAddress *utils.Big + MinAddress *ubig.Big // MaxAddress (inclusive). - MaxAddress *utils.Big + MaxAddress *ubig.Big } var ( ErrInvalidIntervals = errors.New("invalid intervals value") - MinAddress = utils.NewBig(common.BytesToAddress(bytes.Repeat([]byte{0x00}, common.AddressLength)).Big()) - MaxAddress = utils.NewBig(common.BytesToAddress(bytes.Repeat([]byte{0xff}, common.AddressLength)).Big()) + MinAddress = ubig.New(common.BytesToAddress(bytes.Repeat([]byte{0x00}, common.AddressLength)).Big()) + MaxAddress = ubig.New(common.BytesToAddress(bytes.Repeat([]byte{0xff}, common.AddressLength)).Big()) ) // NewFullAddressRange creates AddressRange for all address space: 0x00..-0xFF.. @@ -33,7 +33,7 @@ func NewFullAddressRange() *AddressRange { } // NewSingleAddressRange creates AddressRange for a single address. -func NewSingleAddressRange(address *utils.Big) (*AddressRange, error) { +func NewSingleAddressRange(address *ubig.Big) (*AddressRange, error) { if address == nil || address.Cmp(MinAddress) < 0 || address.Cmp(MaxAddress) > 0 { return nil, errors.New("invalid address") } @@ -56,12 +56,12 @@ func NewInitialAddressRangeForIntervals(intervals uint) (*AddressRange, error) { } divisor := big.NewInt(int64(intervals)) - maxPlusOne := MaxAddress.Add(utils.NewBigI(1)) - interval := utils.NewBig(new(big.Int).Div(maxPlusOne.ToInt(), divisor)) + maxPlusOne := MaxAddress.Add(ubig.NewI(1)) + interval := ubig.New(new(big.Int).Div(maxPlusOne.ToInt(), divisor)) return &AddressRange{ MinAddress: MinAddress, - MaxAddress: MinAddress.Add(interval).Sub(utils.NewBigI(1)), + MaxAddress: MinAddress.Add(interval).Sub(ubig.NewI(1)), }, nil } @@ -80,7 +80,7 @@ func (r *AddressRange) Advance() { if r.MinAddress.Cmp(MaxAddress) >= 0 { r.MinAddress = MinAddress - r.MaxAddress = MinAddress.Add(interval).Sub(utils.NewBigI(1)) + r.MaxAddress = MinAddress.Add(interval).Sub(ubig.NewI(1)) } if r.MaxAddress.Cmp(MaxAddress) > 0 { @@ -89,7 +89,7 @@ func (r *AddressRange) Advance() { } // Contains returns true if the given address belongs to the range. -func (r *AddressRange) Contains(address *utils.Big) bool { +func (r *AddressRange) Contains(address *ubig.Big) bool { if r == nil { return false } @@ -97,9 +97,9 @@ func (r *AddressRange) Contains(address *utils.Big) bool { } // Interval returns the interval between max and min address plus one. -func (r *AddressRange) Interval() *utils.Big { +func (r *AddressRange) Interval() *ubig.Big { if r == nil { return nil } - return r.MaxAddress.Sub(r.MinAddress).Add(utils.NewBigI(1)) + return r.MaxAddress.Sub(r.MinAddress).Add(ubig.NewI(1)) } diff --git a/core/services/s4/address_range_test.go b/core/services/s4/address_range_test.go index bbd4d3baa5..2b12acd08e 100644 --- a/core/services/s4/address_range_test.go +++ b/core/services/s4/address_range_test.go @@ -3,8 +3,8 @@ package s4_test import ( "testing" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" ) @@ -26,7 +26,7 @@ func TestAddressRange_NewFullAddressRange(t *testing.T) { func TestAddressRange_NewSingleAddressRange(t *testing.T) { t.Parallel() - addr := utils.NewBigI(0x123) + addr := big.NewI(0x123) sar, err := s4.NewSingleAddressRange(addr) assert.NoError(t, err) assert.Equal(t, addr, sar.MinAddress) @@ -94,10 +94,10 @@ func TestAddressRange_Contains(t *testing.T) { assert.NoError(t, err) assert.True(t, r.Contains(r.MinAddress)) assert.True(t, r.Contains(r.MaxAddress)) - assert.False(t, r.Contains(r.MaxAddress.Add(utils.NewBigI(1)))) + assert.False(t, r.Contains(r.MaxAddress.Add(big.NewI(1)))) r.Advance() assert.True(t, r.Contains(r.MinAddress)) assert.True(t, r.Contains(r.MaxAddress)) - assert.False(t, r.Contains(r.MinAddress.Sub(utils.NewBigI(1)))) + assert.False(t, r.Contains(r.MinAddress.Sub(big.NewI(1)))) } diff --git a/core/services/s4/in_memory_orm.go b/core/services/s4/in_memory_orm.go index bb67d2d63a..28b50ce430 100644 --- a/core/services/s4/in_memory_orm.go +++ b/core/services/s4/in_memory_orm.go @@ -5,8 +5,8 @@ import ( "sync" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type key struct { @@ -32,7 +32,7 @@ func NewInMemoryORM() ORM { } } -func (o *inMemoryOrm) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { +func (o *inMemoryOrm) Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { o.mu.RLock() defer o.mu.RUnlock() @@ -103,7 +103,7 @@ func (o *inMemoryOrm) GetSnapshot(addressRange *AddressRange, qopts ...pg.QOpt) for _, mrow := range o.rows { if mrow.Row.Expiration > now { rows = append(rows, &SnapshotRow{ - Address: utils.NewBig(mrow.Row.Address.ToInt()), + Address: big.New(mrow.Row.Address.ToInt()), SlotId: mrow.Row.SlotId, Version: mrow.Row.Version, Expiration: mrow.Row.Expiration, diff --git a/core/services/s4/in_memory_orm_test.go b/core/services/s4/in_memory_orm_test.go index 68bff00634..318db5f1a4 100644 --- a/core/services/s4/in_memory_orm_test.go +++ b/core/services/s4/in_memory_orm_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" @@ -21,7 +21,7 @@ func TestInMemoryORM(t *testing.T) { signature := testutils.Random32Byte() expiration := time.Now().Add(time.Minute).UnixMilli() row := &s4.Row{ - Address: utils.NewBig(address.Big()), + Address: big.New(address.Big()), SlotId: slotId, Payload: payload[:], Version: 3, @@ -33,7 +33,7 @@ func TestInMemoryORM(t *testing.T) { orm := s4.NewInMemoryORM() t.Run("row not found", func(t *testing.T) { - _, err := orm.Get(utils.NewBig(address.Big()), slotId) + _, err := orm.Get(big.New(address.Big()), slotId) assert.ErrorIs(t, err, s4.ErrNotFound) }) @@ -41,7 +41,7 @@ func TestInMemoryORM(t *testing.T) { err := orm.Update(row) assert.NoError(t, err) - e, err := orm.Get(utils.NewBig(address.Big()), slotId) + e, err := orm.Get(big.New(address.Big()), slotId) assert.NoError(t, err) assert.Equal(t, row, e) }) @@ -59,7 +59,7 @@ func TestInMemoryORM(t *testing.T) { err = orm.Update(row) assert.NoError(t, err) - e, err := orm.Get(utils.NewBig(address.Big()), slotId) + e, err := orm.Get(big.New(address.Big()), slotId) assert.NoError(t, err) assert.Equal(t, row, e) }) @@ -76,7 +76,7 @@ func TestInMemoryORM_DeleteExpired(t *testing.T) { thisAddress[0] = byte(i) row := &s4.Row{ - Address: utils.NewBig(thisAddress.Big()), + Address: big.New(thisAddress.Big()), SlotId: 1, Payload: []byte{}, Version: 1, @@ -109,7 +109,7 @@ func TestInMemoryORM_GetUnconfirmedRows(t *testing.T) { thisAddress[0] = byte(i) row := &s4.Row{ - Address: utils.NewBig(thisAddress.Big()), + Address: big.New(thisAddress.Big()), SlotId: 1, Payload: []byte{}, Version: 1, @@ -139,7 +139,7 @@ func TestInMemoryORM_GetSnapshot(t *testing.T) { thisAddress[0] = byte(i) row := &s4.Row{ - Address: utils.NewBig(thisAddress.Big()), + Address: big.New(thisAddress.Big()), SlotId: 1, Payload: []byte{}, Version: uint64(i), diff --git a/core/services/s4/mocks/orm.go b/core/services/s4/mocks/orm.go index 706c119429..3b8cac8e76 100644 --- a/core/services/s4/mocks/orm.go +++ b/core/services/s4/mocks/orm.go @@ -3,13 +3,14 @@ package mocks import ( + big "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + mock "github.com/stretchr/testify/mock" + pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" + s4 "github.com/smartcontractkit/chainlink/v2/core/services/s4" - mock "github.com/stretchr/testify/mock" time "time" - - utils "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM is an autogenerated mock type for the ORM type @@ -53,7 +54,7 @@ func (_m *ORM) DeleteExpired(limit uint, utcNow time.Time, qopts ...pg.QOpt) (in } // Get provides a mock function with given fields: address, slotId, qopts -func (_m *ORM) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, error) { +func (_m *ORM) Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -69,10 +70,10 @@ func (_m *ORM) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, var r0 *s4.Row var r1 error - if rf, ok := ret.Get(0).(func(*utils.Big, uint, ...pg.QOpt) (*s4.Row, error)); ok { + if rf, ok := ret.Get(0).(func(*big.Big, uint, ...pg.QOpt) (*s4.Row, error)); ok { return rf(address, slotId, qopts...) } - if rf, ok := ret.Get(0).(func(*utils.Big, uint, ...pg.QOpt) *s4.Row); ok { + if rf, ok := ret.Get(0).(func(*big.Big, uint, ...pg.QOpt) *s4.Row); ok { r0 = rf(address, slotId, qopts...) } else { if ret.Get(0) != nil { @@ -80,7 +81,7 @@ func (_m *ORM) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, } } - if rf, ok := ret.Get(1).(func(*utils.Big, uint, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(*big.Big, uint, ...pg.QOpt) error); ok { r1 = rf(address, slotId, qopts...) } else { r1 = ret.Error(1) diff --git a/core/services/s4/orm.go b/core/services/s4/orm.go index 1e0227b119..59f3410e14 100644 --- a/core/services/s4/orm.go +++ b/core/services/s4/orm.go @@ -3,13 +3,13 @@ package s4 import ( "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Row represents a data row persisted by ORM. type Row struct { - Address *utils.Big + Address *big.Big SlotId uint Payload []byte Version uint64 @@ -20,7 +20,7 @@ type Row struct { // SnapshotRow(s) are returned by GetSnapshot function. type SnapshotRow struct { - Address *utils.Big + Address *big.Big SlotId uint Version uint64 Expiration int64 @@ -35,7 +35,7 @@ type ORM interface { // Get reads a row for the given address and slotId combination. // If such row does not exist, ErrNotFound is returned. // There is no filter on Expiration. - Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) + Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) // Update inserts or updates the row identified by (Address, SlotId) pair. // When updating, the new row must have greater or equal version, @@ -59,7 +59,7 @@ type ORM interface { func (r Row) Clone() *Row { clone := Row{ - Address: utils.NewBig(r.Address.ToInt()), + Address: big.New(r.Address.ToInt()), SlotId: r.SlotId, Payload: make([]byte, len(r.Payload)), Version: r.Version, diff --git a/core/services/s4/postgres_orm.go b/core/services/s4/postgres_orm.go index 1f91270fd0..dba98b64aa 100644 --- a/core/services/s4/postgres_orm.go +++ b/core/services/s4/postgres_orm.go @@ -5,9 +5,9 @@ import ( "fmt" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/jmoiron/sqlx" "github.com/pkg/errors" @@ -34,7 +34,7 @@ func NewPostgresORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, tableName, } } -func (o orm) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { +func (o orm) Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { row := &Row{} q := o.q.WithOpts(qopts...) diff --git a/core/services/s4/postgres_orm_test.go b/core/services/s4/postgres_orm_test.go index c233fe2361..4d07524b4e 100644 --- a/core/services/s4/postgres_orm_test.go +++ b/core/services/s4/postgres_orm_test.go @@ -6,12 +6,12 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" ) @@ -36,7 +36,7 @@ func generateTestRows(t *testing.T, n int) []*s4.Row { rows := make([]*s4.Row, n) for i := 0; i < n; i++ { row := &s4.Row{ - Address: utils.NewBig(testutils.NewAddress().Big()), + Address: big.New(testutils.NewAddress().Big()), SlotId: 1, Payload: cltest.MustRandomBytes(t, 32), Version: 1 + uint64(i), diff --git a/core/services/s4/storage.go b/core/services/s4/storage.go index 65aa2f4bab..7c9a92d1f6 100644 --- a/core/services/s4/storage.go +++ b/core/services/s4/storage.go @@ -3,6 +3,7 @@ package s4 import ( "context" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -92,7 +93,7 @@ func (s *storage) Get(ctx context.Context, key *Key) (*Record, *Metadata, error) return nil, nil, ErrSlotIdTooBig } - bigAddress := utils.NewBig(key.Address.Big()) + bigAddress := big.New(key.Address.Big()) row, err := s.orm.Get(bigAddress, key.SlotId, pg.WithParentCtx(ctx)) if err != nil { return nil, nil, err @@ -118,7 +119,7 @@ func (s *storage) Get(ctx context.Context, key *Key) (*Record, *Metadata, error) } func (s *storage) List(ctx context.Context, address common.Address) ([]*SnapshotRow, error) { - bigAddress := utils.NewBig(address.Big()) + bigAddress := big.New(address.Big()) sar, err := NewSingleAddressRange(bigAddress) if err != nil { return nil, err @@ -148,7 +149,7 @@ func (s *storage) Put(ctx context.Context, key *Key, record *Record, signature [ } row := &Row{ - Address: utils.NewBig(key.Address.Big()), + Address: big.New(key.Address.Big()), SlotId: key.SlotId, Payload: make([]byte, len(record.Payload)), Version: key.Version, diff --git a/core/services/s4/storage_test.go b/core/services/s4/storage_test.go index 11a8f6544c..86161f298e 100644 --- a/core/services/s4/storage_test.go +++ b/core/services/s4/storage_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/s4" @@ -51,7 +52,7 @@ func TestStorage_Errors(t *testing.T) { SlotId: 1, Version: 0, } - ormMock.On("Get", utils.NewBig(key.Address.Big()), uint(key.SlotId), mock.Anything).Return(nil, s4.ErrNotFound) + ormMock.On("Get", big.New(key.Address.Big()), uint(key.SlotId), mock.Anything).Return(nil, s4.ErrNotFound) _, _, err := storage.Get(testutils.Context(t), key) assert.ErrorIs(t, err, s4.ErrNotFound) }) @@ -179,8 +180,8 @@ func TestStorage_PutAndGet(t *testing.T) { assert.NoError(t, err) ormMock.On("Update", mock.Anything, mock.Anything).Return(nil) - ormMock.On("Get", utils.NewBig(key.Address.Big()), uint(2), mock.Anything).Return(&s4.Row{ - Address: utils.NewBig(key.Address.Big()), + ormMock.On("Get", big.New(key.Address.Big()), uint(2), mock.Anything).Return(&s4.Row{ + Address: big.New(key.Address.Big()), SlotId: key.SlotId, Version: key.Version, Payload: record.Payload, @@ -217,7 +218,7 @@ func TestStorage_List(t *testing.T) { }, } - addressRange, err := s4.NewSingleAddressRange(utils.NewBig(address.Big())) + addressRange, err := s4.NewSingleAddressRange(big.New(address.Big())) assert.NoError(t, err) ormMock.On("GetSnapshot", addressRange, mock.Anything).Return(ormRows, nil) diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 3b643d19b0..663080c86a 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -15,8 +15,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index a7dca56776..3e9cfbe087 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -16,6 +16,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -29,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestIntegration_VRF_JPV2(t *testing.T) { @@ -47,7 +47,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { t.Run(test.name, func(t *testing.T) { config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) @@ -134,7 +134,7 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { c.Feature.LogPoller = ptr(true) c.EVM[0].FinalityDepth = ptr[uint32](2) c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) key := cltest.MustGenerateRandomKey(t) cu := vrftesthelpers.NewVRFCoordinatorUniverse(t, key) diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index 03d96cadf2..d8a7da70a8 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -21,6 +21,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2_upgradeable_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_external_sub_owner_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy" @@ -540,7 +541,7 @@ func testSingleConsumerHappyPathBatchFulfillment( })(c, s) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) c.Feature.LogPoller = ptr(true) c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) @@ -1645,7 +1646,7 @@ func testMaliciousConsumer( c.EVM[0].GasEstimator.PriceMax = assets.GWei(1) c.EVM[0].GasEstimator.PriceDefault = assets.GWei(1) c.EVM[0].GasEstimator.FeeCapDefault = assets.GWei(1) - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) c.Feature.LogPoller = ptr(true) c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) }) diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index fa95b694f9..8d6354c4fd 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -40,6 +40,7 @@ import ( evmlogger "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" @@ -2057,7 +2058,7 @@ func TestStartingCountsV1(t *testing.T) { md2, err := json.Marshal(&m2) md2SQL := sqlutil.JSON(md2) require.NoError(t, err) - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := ubig.New(testutils.SimulatedChainID) confirmedTxes := []txmgr.Tx{ { Sequence: &n1, diff --git a/core/services/vrf/v2/listener_v2_log_listener_test.go b/core/services/vrf/v2/listener_v2_log_listener_test.go index 11b299abc4..6f5177c230 100644 --- a/core/services/vrf/v2/listener_v2_log_listener_test.go +++ b/core/services/vrf/v2/listener_v2_log_listener_test.go @@ -21,6 +21,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" @@ -761,8 +762,8 @@ func TestUpdateLastProcessedBlock_UnfulfilledNFulfilledVRFReqs(t *testing.T) { * TestGetUnfulfilled_UnfulfilledNFulfilledVRFReqs */ -func SetupGetUnfulfilledTH(t *testing.T) (*listenerV2, *utils.Big) { - chainID := utils.NewBig(big.NewInt(12345)) +func SetupGetUnfulfilledTH(t *testing.T) (*listenerV2, *ubig.Big) { + chainID := ubig.New(big.NewInt(12345)) lggr := logger.TestLogger(t) j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ RequestedConfsDelay: 10, diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 43ddd41d56..10c698e96f 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -16,6 +16,7 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -29,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/migrate" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var migrationDir = "migrations" @@ -417,7 +417,7 @@ func TestMigrate(t *testing.T) { func TestSetMigrationENVVars(t *testing.T) { t.Run("ValidEVMConfig", func(t *testing.T) { - chainID := utils.NewBig(big.NewInt(1337)) + chainID := ubig.New(big.NewInt(1337)) testConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { evmEnabled := true c.EVM = evmcfg.EVMConfigs{&evmcfg.EVMConfig{ @@ -433,7 +433,7 @@ func TestSetMigrationENVVars(t *testing.T) { }) t.Run("EVMConfigMissing", func(t *testing.T) { - chainID := utils.NewBig(big.NewInt(1337)) + chainID := ubig.New(big.NewInt(1337)) testConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM = nil }) require.NoError(t, migrate.SetMigrationENVVars(testConfig)) @@ -535,7 +535,7 @@ func BenchmarkBackfillingRecordsWithMigration202(b *testing.B) { var blocks []logpoller.LogPollerBlock for i := 0; i < maxLogsSize; i++ { blocks = append(blocks, logpoller.LogPollerBlock{ - EvmChainId: utils.NewBigI(int64(j + 1)), + EvmChainId: ubig.NewI(int64(j + 1)), BlockHash: testutils.Random32Byte(), BlockNumber: int64(i + 1000), FinalizedBlockNumber: 0, diff --git a/core/store/models/common.go b/core/store/models/common.go index 10f391861e..93cc708fe0 100644 --- a/core/store/models/common.go +++ b/core/store/models/common.go @@ -18,7 +18,7 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // CronParser is the global parser for crontabs. @@ -365,7 +365,7 @@ type SendEtherRequest struct { DestinationAddress common.Address `json:"address"` FromAddress common.Address `json:"from"` Amount assets.Eth `json:"amount"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` AllowHigherAmounts bool `json:"allowHigherAmounts"` SkipWaitTxAttempt bool `json:"skipWaitTxAttempt"` WaitAttemptTimeout *time.Duration `json:"waitAttemptTimeout"` diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index d99992c0f5..fe76e8863e 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -11,6 +11,7 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -19,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" "github.com/ethereum/go-ethereum/common" @@ -393,7 +393,7 @@ func (ekc *ETHKeysController) getLinkBalance(ctx context.Context, state ethkey.S // gets the key specific max gas price from the chain config and sets it on the // resource. func (ekc *ETHKeysController) setKeyMaxGasPriceWei(price *assets.Wei) presenters.NewETHKeyOption { - return presenters.SetETHKeyMaxGasPriceWei(utils.NewBig(price.ToInt())) + return presenters.SetETHKeyMaxGasPriceWei(ubig.New(price.ToInt())) } func (ekc *ETHKeysController) getKeyMaxGasPriceWei(state ethkey.State, keyAddress common.Address) *assets.Wei { diff --git a/core/web/evm_chains_controller_test.go b/core/web/evm_chains_controller_test.go index 3d5a4e3eed..ea3d5476ce 100644 --- a/core/web/evm_chains_controller_test.go +++ b/core/web/evm_chains_controller_test.go @@ -12,12 +12,12 @@ import ( "github.com/stretchr/testify/require" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -25,7 +25,7 @@ import ( func Test_EVMChainsController_Show(t *testing.T) { t.Parallel() - validId := utils.NewBig(testutils.NewRandomEVMChainID()) + validId := ubig.New(testutils.NewRandomEVMChainID()) testCases := []struct { name string @@ -111,9 +111,9 @@ func Test_EVMChainsController_Index(t *testing.T) { }) configuredChains := evmcfg.EVMConfigs{ - {ChainID: utils.NewBig(chainIDs[0]), Chain: evmcfg.Defaults(nil)}, + {ChainID: ubig.New(chainIDs[0]), Chain: evmcfg.Defaults(nil)}, { - ChainID: utils.NewBig(chainIDs[1]), + ChainID: ubig.New(chainIDs[1]), Chain: evmcfg.Defaults(nil, &evmcfg.Chain{ RPCBlockQueryDelay: ptr[uint16](13), GasEstimator: evmcfg.GasEstimator{ @@ -126,7 +126,7 @@ func Test_EVMChainsController_Index(t *testing.T) { }), }, { - ChainID: utils.NewBig(chainIDs[2]), + ChainID: ubig.New(chainIDs[2]), Chain: evmcfg.Defaults(nil, &evmcfg.Chain{ RPCBlockQueryDelay: ptr[uint16](5), GasEstimator: evmcfg.GasEstimator{ diff --git a/core/web/evm_forwarders_controller.go b/core/web/evm_forwarders_controller.go index 6228723506..56d1285c88 100644 --- a/core/web/evm_forwarders_controller.go +++ b/core/web/evm_forwarders_controller.go @@ -8,10 +8,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -43,7 +43,7 @@ func (cc *EVMForwardersController) Index(c *gin.Context, size, page, offset int) // TrackEVMForwarderRequest is a JSONAPI request for creating an EVM forwarder. type TrackEVMForwarderRequest struct { - EVMChainID *utils.Big `json:"evmChainId"` + EVMChainID *ubig.Big `json:"evmChainId"` Address common.Address `json:"address"` } diff --git a/core/web/evm_forwarders_controller_test.go b/core/web/evm_forwarders_controller_test.go index 31e49f20ec..49671157cb 100644 --- a/core/web/evm_forwarders_controller_test.go +++ b/core/web/evm_forwarders_controller_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -42,7 +43,7 @@ func setupEVMForwardersControllerTest(t *testing.T, overrideFn func(c *chainlink func Test_EVMForwardersController_Track(t *testing.T) { t.Parallel() - chainId := utils.NewBig(testutils.NewRandomEVMChainID()) + chainId := big.New(testutils.NewRandomEVMChainID()) controller := setupEVMForwardersControllerTest(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM = evmcfg.EVMConfigs{ {ChainID: chainId, Enabled: ptr(true), Chain: evmcfg.Defaults(chainId)}, @@ -79,7 +80,7 @@ func Test_EVMForwardersController_Track(t *testing.T) { func Test_EVMForwardersController_Index(t *testing.T) { t.Parallel() - chainId := utils.NewBig(testutils.NewRandomEVMChainID()) + chainId := big.New(testutils.NewRandomEVMChainID()) controller := setupEVMForwardersControllerTest(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM = evmcfg.EVMConfigs{ {ChainID: chainId, Enabled: ptr(true), Chain: evmcfg.Defaults(chainId)}, diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index c41219e189..dd083a8cd6 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -13,13 +13,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -55,7 +55,7 @@ func TestTransfersController_CreateSuccess_From(t *testing.T) { FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -96,7 +96,7 @@ func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -142,7 +142,7 @@ func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testin FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -172,7 +172,7 @@ func TestTransfersController_TransferZeroAddressError(t *testing.T) { DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), FromAddress: common.HexToAddress("0x0000000000000000000000000000000000000000"), Amount: amount, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -207,7 +207,7 @@ func TestTransfersController_TransferBalanceToLowError(t *testing.T) { DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), Amount: amount, AllowHigherAmounts: false, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -245,7 +245,7 @@ func TestTransfersController_TransferBalanceToLowError_ZeroBalance(t *testing.T) DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), Amount: amount, AllowHigherAmounts: false, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -288,7 +288,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") - c.EVM[0].ChainID = (*utils.Big)(testutils.FixtureChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.FixtureChainID) // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) @@ -308,7 +308,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { FromAddress: key.Address, Amount: amount, WaitAttemptTimeout: &timeout, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, config.EVMConfigs())), } body, err := json.Marshal(&request) diff --git a/core/web/loader/loader_test.go b/core/web/loader/loader_test.go index 9bd1feb05b..cbd73a575a 100644 --- a/core/web/loader/loader_test.go +++ b/core/web/loader/loader_test.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtxmgrmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" coremocks "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -35,9 +36,9 @@ func TestLoader_Chains(t *testing.T) { app := coremocks.NewApplication(t) ctx := InjectDataloader(testutils.Context(t), app) - one := utils.NewBigI(1) + one := ubig.NewI(1) chain := toml.EVMConfig{ChainID: one, Chain: toml.Defaults(one)} - two := utils.NewBigI(2) + two := ubig.NewI(2) chain2 := toml.EVMConfig{ChainID: two, Chain: toml.Defaults(two)} evmORM := evmtest.NewTestConfigs(&chain, &chain2) app.On("EVMORM").Return(evmORM) diff --git a/core/web/presenters/eth_key.go b/core/web/presenters/eth_key.go index 3d952dabed..d661d4334c 100644 --- a/core/web/presenters/eth_key.go +++ b/core/web/presenters/eth_key.go @@ -5,22 +5,22 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ETHKeyResource represents a ETH key JSONAPI resource. It holds the hex // representation of the address plus its ETH & LINK balances type ETHKeyResource struct { JAID - EVMChainID utils.Big `json:"evmChainID"` + EVMChainID big.Big `json:"evmChainID"` Address string `json:"address"` EthBalance *assets.Eth `json:"ethBalance"` LinkBalance *commonassets.Link `json:"linkBalance"` Disabled bool `json:"disabled"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - MaxGasPriceWei *utils.Big `json:"maxGasPriceWei"` + MaxGasPriceWei *big.Big `json:"maxGasPriceWei"` } // GetName implements the api2go EntityNamer interface @@ -69,7 +69,7 @@ func SetETHKeyLinkBalance(linkBalance *commonassets.Link) NewETHKeyOption { } } -func SetETHKeyMaxGasPriceWei(maxGasPriceWei *utils.Big) NewETHKeyOption { +func SetETHKeyMaxGasPriceWei(maxGasPriceWei *big.Big) NewETHKeyOption { return func(r *ETHKeyResource) { r.MaxGasPriceWei = maxGasPriceWei } diff --git a/core/web/presenters/eth_key_test.go b/core/web/presenters/eth_key_test.go index 85d005cf61..8be13de74a 100644 --- a/core/web/presenters/eth_key_test.go +++ b/core/web/presenters/eth_key_test.go @@ -7,8 +7,8 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/manyminds/api2go/jsonapi" @@ -31,7 +31,7 @@ func TestETHKeyResource(t *testing.T) { state := ethkey.State{ ID: 1, - EVMChainID: *utils.NewBigI(42), + EVMChainID: *big.NewI(42), Address: eip55address, CreatedAt: now, UpdatedAt: now, @@ -41,12 +41,12 @@ func TestETHKeyResource(t *testing.T) { r := NewETHKeyResource(key, state, SetETHKeyEthBalance(assets.NewEth(1)), SetETHKeyLinkBalance(commonassets.NewLinkFromJuels(1)), - SetETHKeyMaxGasPriceWei(utils.NewBigI(12345)), + SetETHKeyMaxGasPriceWei(big.NewI(12345)), ) assert.Equal(t, assets.NewEth(1), r.EthBalance) assert.Equal(t, commonassets.NewLinkFromJuels(1), r.LinkBalance) - assert.Equal(t, utils.NewBigI(12345), r.MaxGasPriceWei) + assert.Equal(t, big.NewI(12345), r.MaxGasPriceWei) b, err := jsonapi.Marshal(r) require.NoError(t, err) diff --git a/core/web/presenters/eth_tx.go b/core/web/presenters/eth_tx.go index 2c2b5b90ff..f944a99213 100644 --- a/core/web/presenters/eth_tx.go +++ b/core/web/presenters/eth_tx.go @@ -8,7 +8,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // EthTxResource represents a Ethereum Transaction JSONAPI resource. @@ -25,7 +25,7 @@ type EthTxResource struct { SentAt string `json:"sentAt"` To *common.Address `json:"to"` Value string `json:"value"` - EVMChainID utils.Big `json:"evmChainID"` + EVMChainID big.Big `json:"evmChainID"` } // GetName implements the api2go EntityNamer interface @@ -50,7 +50,7 @@ func NewEthTxResource(tx txmgr.Tx) EthTxResource { } if tx.ChainID != nil { - r.EVMChainID = *utils.NewBig(tx.ChainID) + r.EVMChainID = *big.New(tx.ChainID) } return r } @@ -65,7 +65,7 @@ func NewEthTxResourceFromAttempt(txa txmgr.TxAttempt) EthTxResource { r.Hex = hexutil.Encode(txa.SignedRawTx) if txa.Tx.ChainID != nil { - r.EVMChainID = *utils.NewBig(txa.Tx.ChainID) + r.EVMChainID = *big.New(txa.Tx.ChainID) } if tx.Sequence != nil { diff --git a/core/web/presenters/evm_forwarder.go b/core/web/presenters/evm_forwarder.go index c91bfc088f..43c2764485 100644 --- a/core/web/presenters/evm_forwarder.go +++ b/core/web/presenters/evm_forwarder.go @@ -6,14 +6,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // EVMForwarderResource is an EVM forwarder JSONAPI resource. type EVMForwarderResource struct { JAID Address common.Address `json:"address"` - EVMChainID utils.Big `json:"evmChainId"` + EVMChainID big.Big `json:"evmChainId"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index 9b0a3cb342..a2a9e70c79 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -9,6 +9,7 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -16,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // JobSpecType defines the the the spec type of the job @@ -49,7 +49,7 @@ type DirectRequestSpec struct { Initiator string `json:"initiator"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` } // NewDirectRequestSpec initializes a new DirectRequestSpec from a @@ -84,7 +84,7 @@ type FluxMonitorSpec struct { MinPayment *commonassets.Link `json:"minPayment"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` } // NewFluxMonitorSpec initializes a new DirectFluxMonitorSpec from a @@ -131,7 +131,7 @@ type OffChainReportingSpec struct { ContractConfigConfirmations uint16 `json:"contractConfigConfirmations"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` DatabaseTimeout *models.Interval `json:"databaseTimeout"` ObservationGracePeriod *models.Interval `json:"observationGracePeriod"` ContractTransmitterTransmitTimeout *models.Interval `json:"contractTransmitterTransmitTimeout"` @@ -220,7 +220,7 @@ type KeeperSpec struct { FromAddress ethkey.EIP55Address `json:"fromAddress"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` } // NewKeeperSpec generates a new KeeperSpec from a job.KeeperSpec @@ -275,7 +275,7 @@ type VRFSpec struct { MinIncomingConfirmations uint32 `json:"confirmations"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` ChunkSize uint32 `json:"chunkSize"` RequestTimeout models.Duration `json:"requestTimeout"` BackoffInitialDelay models.Duration `json:"backoffInitialDelay"` @@ -317,7 +317,7 @@ type BlockhashStoreSpec struct { TrustedBlockhashStoreBatchSize int32 `json:"trustedBlockhashStoreBatchSize"` PollPeriod time.Duration `json:"pollPeriod"` RunTimeout time.Duration `json:"runTimeout"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` @@ -353,7 +353,7 @@ type BlockHeaderFeederSpec struct { BatchBlockhashStoreAddress ethkey.EIP55Address `json:"batchBlockhashStoreAddress"` PollPeriod time.Duration `json:"pollPeriod"` RunTimeout time.Duration `json:"runTimeout"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` GetBlockhashesBatchSize uint16 `json:"getBlockhashesBatchSize"` StoreBlockhashesBatchSize uint16 `json:"storeBlockhashesBatchSize"` diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index 260cce0caf..a5d6db0df1 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -14,12 +14,12 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -29,7 +29,7 @@ func TestJob(t *testing.T) { contractAddress, err := ethkey.NewEIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba") require.NoError(t, err) cronSchedule := "0 0 0 1 1 *" - evmChainID := utils.NewBigI(42) + evmChainID := big.NewI(42) fromAddress, err := ethkey.NewEIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e") require.NoError(t, err) @@ -484,7 +484,7 @@ func TestJob(t *testing.T) { BlockhashStoreAddress: contractAddress, PollPeriod: 25 * time.Second, RunTimeout: 10 * time.Second, - EVMChainID: utils.NewBigI(4), + EVMChainID: big.NewI(4), FromAddresses: []ethkey.EIP55Address{fromAddress}, TrustedBlockhashStoreAddress: &trustedBlockhashStoreAddress, TrustedBlockhashStoreBatchSize: trustedBlockhashStoreBatchSize, @@ -564,7 +564,7 @@ func TestJob(t *testing.T) { BatchBlockhashStoreAddress: batchBHSAddress, PollPeriod: 25 * time.Second, RunTimeout: 10 * time.Second, - EVMChainID: utils.NewBigI(4), + EVMChainID: big.NewI(4), FromAddresses: []ethkey.EIP55Address{fromAddress}, GetBlockhashesBatchSize: 5, StoreBlockhashesBatchSize: 10, diff --git a/core/web/replay_controller.go b/core/web/replay_controller.go index 5006b68c84..84c54e3836 100644 --- a/core/web/replay_controller.go +++ b/core/web/replay_controller.go @@ -7,8 +7,8 @@ import ( "github.com/gin-gonic/gin" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ReplayController struct { @@ -64,14 +64,14 @@ func (bdc *ReplayController) ReplayFromBlock(c *gin.Context) { response := ReplayResponse{ Message: "Replay started", - EVMChainID: utils.NewBig(chainID), + EVMChainID: big.New(chainID), } jsonAPIResponse(c, &response, "response") } type ReplayResponse struct { - Message string `json:"message"` - EVMChainID *utils.Big `json:"evmChainID"` + Message string `json:"message"` + EVMChainID *big.Big `json:"evmChainID"` } // GetID returns the jsonapi ID. diff --git a/core/web/resolver/chain_test.go b/core/web/resolver/chain_test.go index c3cafd329b..700963cd4d 100644 --- a/core/web/resolver/chain_test.go +++ b/core/web/resolver/chain_test.go @@ -9,12 +9,12 @@ import ( "github.com/stretchr/testify/require" evmtoml "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func TestResolver_Chains(t *testing.T) { var ( - chainID = *utils.NewBigI(1) + chainID = *big.NewI(1) query = ` query GetChains { chains { @@ -100,7 +100,7 @@ ResendAfterThreshold = '1h0m0s' func TestResolver_Chain(t *testing.T) { var ( - chainID = *utils.NewBigI(1) + chainID = *big.NewI(1) query = ` query GetChain { chain(id: "1") { diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index ea106a4b30..1874e4c68e 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -14,12 +14,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type mockEvmConfig struct { @@ -80,13 +80,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") cfg := configtest.NewGeneralConfig(t, nil) @@ -139,13 +139,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(nil, evmrelay.ErrNoChains) f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) @@ -225,7 +225,7 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), @@ -257,7 +257,7 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), @@ -288,13 +288,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) @@ -342,13 +342,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.EIP55AddressFromAddress(address), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) diff --git a/core/web/resolver/eth_transaction_test.go b/core/web/resolver/eth_transaction_test.go index a719c838e8..238aa9d167 100644 --- a/core/web/resolver/eth_transaction_test.go +++ b/core/web/resolver/eth_transaction_test.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func TestResolver_EthTransaction(t *testing.T) { @@ -54,7 +54,7 @@ func TestResolver_EthTransaction(t *testing.T) { "hash": "0x5431F5F973781809D18643b87B44921b11355d81", } hash := common.HexToHash("0x5431F5F973781809D18643b87B44921b11355d81") - chainID := *utils.NewBigI(22) + chainID := *ubig.NewI(22) gError := errors.New("error") testCases := []GQLTestCase{ diff --git a/core/web/resolver/node_test.go b/core/web/resolver/node_test.go index 24a31b986f..a209a60fc3 100644 --- a/core/web/resolver/node_test.go +++ b/core/web/resolver/node_test.go @@ -8,16 +8,16 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestResolver_Nodes(t *testing.T) { t.Parallel() var ( - chainID = *utils.NewBigI(1) + chainID = *big.NewI(1) query = ` query GetNodes { diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index ef89dafa04..277aac851a 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -13,13 +13,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Specs are only embedded on the job and are not fetchable by it's own id, so @@ -95,7 +95,7 @@ func TestResolver_DirectRequestSpec(t *testing.T) { DirectRequestSpec: &job.DirectRequestSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), MinIncomingConfirmations: clnull.NewUint32(1, true), MinContractPayment: commonassets.NewLinkFromJuels(1000), Requesters: models.AddressCollection{requesterAddress}, @@ -160,7 +160,7 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { FluxMonitorSpec: &job.FluxMonitorSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), DrumbeatEnabled: false, IdleTimerDisabled: false, IdleTimerPeriod: time.Duration(1 * time.Hour), @@ -227,7 +227,7 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { FluxMonitorSpec: &job.FluxMonitorSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), DrumbeatEnabled: true, DrumbeatRandomDelay: time.Duration(1 * time.Second), DrumbeatSchedule: "CRON_TZ=UTC 0 0 1 1 *", @@ -310,7 +310,7 @@ func TestResolver_KeeperSpec(t *testing.T) { KeeperSpec: &job.KeeperSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddress: ethkey.EIP55AddressFromAddress(fromAddress), }, }, nil) @@ -381,7 +381,7 @@ func TestResolver_OCRSpec(t *testing.T) { ObservationGracePeriod: models.NewInterval(4 * time.Second), ContractTransmitterTransmitTimeout: models.NewInterval(555 * time.Millisecond), CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), IsBootstrapPeer: false, EncryptedOCRKeyBundleID: &keyBundleID, ObservationTimeout: models.Interval(2 * time.Minute), @@ -584,7 +584,7 @@ func TestResolver_VRFSpec(t *testing.T) { MinIncomingConfirmations: 1, CoordinatorAddress: coordinatorAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddresses: []ethkey.EIP55Address{fromAddress1, fromAddress2}, PollPeriod: 1 * time.Minute, PublicKey: pubKey, @@ -745,7 +745,7 @@ func TestResolver_BlockhashStoreSpec(t *testing.T) { CoordinatorV2Address: &coordinatorV2Address, CoordinatorV2PlusAddress: &coordinatorV2PlusAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddresses: []ethkey.EIP55Address{fromAddress1, fromAddress2}, PollPeriod: 1 * time.Minute, RunTimeout: 37 * time.Second, @@ -849,7 +849,7 @@ func TestResolver_BlockHeaderFeederSpec(t *testing.T) { CoordinatorV2Address: &coordinatorV2Address, CoordinatorV2PlusAddress: &coordinatorV2PlusAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddresses: []ethkey.EIP55Address{fromAddress}, PollPeriod: 1 * time.Minute, RunTimeout: 37 * time.Second, diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index abc6ef30e4..e6e1de25e4 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -8,8 +8,8 @@ import ( "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // EIServiceConfig represents External Initiator service config @@ -1420,6 +1420,6 @@ type ReplayResponseData struct { } type ReplayResponseAttributes struct { - Message string `json:"message"` - EVMChainID *utils.Big `json:"evmChainID"` + Message string `json:"message"` + EVMChainID *big.Big `json:"evmChainID"` } diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 0337274bb1..7436c05a10 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -162,7 +163,7 @@ func SetChainConfig( } cfg.EVM = evmcfg.EVMConfigs{ { - ChainID: utils.NewBig(big.NewInt(chain.ChainID)), + ChainID: ubig.New(big.NewInt(chain.ChainID)), Chain: chainConfig, Nodes: nodes, }, @@ -179,7 +180,7 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { var evmConfigs []*evmcfg.EVMConfig for _, network := range networks { evmConfigs = append(evmConfigs, &evmcfg.EVMConfig{ - ChainID: utils.NewBig(big.NewInt(network.ChainID)), + ChainID: ubig.New(big.NewInt(network.ChainID)), Chain: evmcfg.Chain{ AutoCreateKey: ptr.Ptr(true), FinalityDepth: ptr.Ptr[uint32](50), From 96b7ab6ee1daa751a58fe34d1f67b90066f26afd Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 12 Dec 2023 15:24:26 -0600 Subject: [PATCH 304/327] bump toml/v2 and prometheus to latest patch (#11541) Co-authored-by: Vyzaldy Sanchez --- core/scripts/go.mod | 4 ++-- core/scripts/go.sum | 8 ++++---- go.mod | 4 ++-- go.sum | 8 ++++---- integration-tests/go.mod | 4 ++-- integration-tests/go.sum | 8 ++++---- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 2f4d45e746..c532759627 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -17,7 +17,7 @@ require ( github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f github.com/montanaflynn/stats v0.7.1 github.com/olekukonko/tablewriter v0.0.5 - github.com/pelletier/go-toml/v2 v2.1.0 + github.com/pelletier/go-toml/v2 v2.1.1 github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.1 @@ -224,7 +224,7 @@ require ( github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.48.0 // indirect + github.com/prometheus/prometheus v0.48.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index a59590fa12..28750a076d 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1029,8 +1029,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= @@ -1076,8 +1076,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= -github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= +github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= diff --git a/go.mod b/go.mod index d8394633c3..e7b93c40bd 100644 --- a/go.mod +++ b/go.mod @@ -51,13 +51,13 @@ require ( github.com/onsi/gomega v1.30.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pelletier/go-toml v1.9.5 - github.com/pelletier/go-toml/v2 v2.1.0 + github.com/pelletier/go-toml/v2 v2.1.1 github.com/pkg/errors v0.9.1 github.com/pressly/goose/v3 v3.16.0 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.45.0 - github.com/prometheus/prometheus v0.48.0 + github.com/prometheus/prometheus v0.48.1 github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 diff --git a/go.sum b/go.sum index d702fd37e9..e9a7f0267a 100644 --- a/go.sum +++ b/go.sum @@ -1015,8 +1015,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= @@ -1062,8 +1062,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= -github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= +github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index c080f61755..84da65e9a5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -18,7 +18,7 @@ require ( github.com/lib/pq v1.10.9 github.com/manifoldco/promptui v0.9.0 github.com/onsi/gomega v1.30.0 - github.com/pelletier/go-toml/v2 v2.1.0 + github.com/pelletier/go-toml/v2 v2.1.1 github.com/rs/zerolog v1.30.0 github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 @@ -330,7 +330,7 @@ require ( github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.48.0 // indirect + github.com/prometheus/prometheus v0.48.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index e8cefd67d6..854978e335 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1278,8 +1278,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= @@ -1341,8 +1341,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= -github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= +github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pyroscope-io/client v0.7.1 h1:yFRhj3vbgjBxehvxQmedmUWJQ4CAfCHhn+itPsuWsHw= github.com/pyroscope-io/client v0.7.1/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU= From 00e1c55ddb5fa3736fccaa545c12cff91b702b68 Mon Sep 17 00:00:00 2001 From: ferglor <19188060+ferglor@users.noreply.github.com> Date: Tue, 12 Dec 2023 21:34:28 +0000 Subject: [PATCH 305/327] Change keepers to use the default contract transmitter (#11308) * Switch keepers to use the default contract transmitter Pass the gas limit into the transmitter constructor so we can specify the automation gas limit Update tests * Fix streams import * Clean up function calls * Remove pipeline runner dependency for automation * Use contractTransmitterOpts to specify a pluginGasLimit * Make the pluginGasLimit a pointer * Clean up the pipeline transmitter * Attempt to listen for transmits Clean up linter Extract function Intentionally fail test Rework transmit listen Try filtering for transmits Update test * Revert "Attempt to listen for transmits" This reverts commit 198e6669a6f64768c84acb82e01b2773c89426ce. * Listen for performed events * Goimports * Add wrapper function that lets us specify a count of performed * Update integration test * Pass the configWatcher as a parameter to indicate that its required --- core/services/ocr2/delegate.go | 4 +- .../plugins/ocr2keeper/integration_21_test.go | 93 +++++++----------- .../plugins/ocr2keeper/integration_test.go | 19 ---- core/services/ocr2/plugins/ocr2keeper/util.go | 14 +-- .../ocrcommon/transmitter_pipeline.go | 97 ------------------- .../ocrcommon/transmitter_pipeline_test.go | 77 --------------- core/services/relay/evm/evm.go | 63 ++---------- core/services/relay/evm/ocr2keeper.go | 25 +++-- core/services/relay/evm/ocr2vrf.go | 4 +- 9 files changed, 67 insertions(+), 329 deletions(-) delete mode 100644 core/services/ocrcommon/transmitter_pipeline.go delete mode 100644 core/services/ocrcommon/transmitter_pipeline_test.go diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 5200866e3a..1b7be2b7f0 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -1084,7 +1084,7 @@ func (d *Delegate) newServicesOCR2Keepers21( return nil, fmt.Errorf("keeper2 services: failed to get chain %s: %w", rid.ChainID, err2) } - keeperProvider, services, err2 := ocr2keeper.EVMDependencies21(jb, d.db, lggr, chain, d.pipelineRunner, mc, kb, d.cfg.Database()) + keeperProvider, services, err2 := ocr2keeper.EVMDependencies21(jb, d.db, lggr, chain, mc, kb, d.cfg.Database(), d.ethKs) if err2 != nil { return nil, errors.Wrap(err2, "could not build dependencies for ocr2 keepers") } @@ -1201,7 +1201,7 @@ func (d *Delegate) newServicesOCR2Keepers20( return nil, fmt.Errorf("keepers2.0 services: failed to get chain (%s): %w", rid.ChainID, err2) } - keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(jb, d.db, lggr, chain, d.pipelineRunner) + keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(jb, d.db, lggr, chain, d.ethKs) if err2 != nil { return nil, errors.Wrap(err2, "could not build dependencies for ocr2 keepers") } diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index c2b6612f66..81a35a5ced 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -54,7 +54,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -117,7 +116,7 @@ func TestIntegration_KeeperPluginConditionalUpkeep(t *testing.T) { require.NoError(t, err) registry := deployKeeper21Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) - nodes, _ := setupNodes(t, nodeKeys, registry, backend, steve) + setupNodes(t, nodeKeys, registry, backend, steve) <-time.After(time.Second * 5) @@ -160,8 +159,6 @@ func TestIntegration_KeeperPluginConditionalUpkeep(t *testing.T) { } g.Eventually(receivedBytes, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(payload1)) - checkPipelineRuns(t, nodes, 1) - // change payload _, err = upkeepContract.SetBytesToSend(carrol, payload2) require.NoError(t, err) @@ -204,7 +201,7 @@ func TestIntegration_KeeperPluginLogUpkeep(t *testing.T) { require.NoError(t, err) registry := deployKeeper21Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) - nodes, _ := setupNodes(t, nodeKeys, registry, backend, steve) + setupNodes(t, nodeKeys, registry, backend, steve) upkeeps := 1 _, err = linkToken.Transfer(sergey, carrol.From, big.NewInt(0).Mul(oneHunEth, big.NewInt(int64(upkeeps+1)))) @@ -228,35 +225,36 @@ func TestIntegration_KeeperPluginLogUpkeep(t *testing.T) { g.Eventually(listener, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.BeTrue()) done() - runs := checkPipelineRuns(t, nodes, 1) - t.Run("recover logs", func(t *testing.T) { - addr, contract := addrs[0], contracts[0] upkeepID := registerUpkeep(t, registry, addr, carrol, steve, backend) backend.Commit() t.Logf("Registered new upkeep %s for address %s", upkeepID.String(), addr.String()) // Emit 100 logs in a burst - emits := 100 + recoverEmits := 100 i := 0 emitEvents(testutils.Context(t), t, 100, []*log_upkeep_counter_wrapper.LogUpkeepCounter{contract}, carrol, func() { i++ - if i%(emits/4) == 0 { + if i%(recoverEmits/4) == 0 { backend.Commit() time.Sleep(time.Millisecond * 250) // otherwise we get "invalid transaction nonce" errors } }) - // Mine enough blocks to ensre these logs don't fall into log provider range + + beforeDummyBlocks := backend.Blockchain().CurrentBlock().Number.Uint64() + + // Mine enough blocks to ensure these logs don't fall into log provider range dummyBlocks := 500 for i := 0; i < dummyBlocks; i++ { backend.Commit() time.Sleep(time.Millisecond * 10) } - t.Logf("Mined %d blocks, waiting for logs to be recovered", dummyBlocks) - expectedPostRecover := runs + emits - waitPipelineRuns(t, nodes, expectedPostRecover, testutils.WaitTimeout(t), cltest.DBPollingInterval) + t.Logf("Mined %d blocks, waiting for logs to be recovered", dummyBlocks) + listener, done := listenPerformedN(t, backend, registry, ids, int64(beforeDummyBlocks), recoverEmits) + g.Eventually(listener, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.BeTrue()) + done() }) } @@ -296,7 +294,7 @@ func TestIntegration_KeeperPluginLogUpkeep_Retry(t *testing.T) { registry := deployKeeper21Registry(t, registryOwner, backend, linkAddr, linkFeedAddr, gasFeedAddr) - nodes, mercuryServer := setupNodes(t, nodeKeys, registry, backend, registryOwner) + _, mercuryServer := setupNodes(t, nodeKeys, registry, backend, registryOwner) const upkeepCount = 10 const mercuryFailCount = upkeepCount * 3 * 2 @@ -374,39 +372,6 @@ func TestIntegration_KeeperPluginLogUpkeep_Retry(t *testing.T) { g.Eventually(listener, testutils.WaitTimeout(t)-(5*time.Second), cltest.DBPollingInterval).Should(gomega.BeTrue()) done() - - _ = checkPipelineRuns(t, nodes, 1*len(nodes)) // TODO: TBD -} - -func waitPipelineRuns(t *testing.T, nodes []Node, n int, timeout, interval time.Duration) { - ctx, cancel := context.WithTimeout(testutils.Context(t), timeout) - defer cancel() - var allRuns []pipeline.Run - for len(allRuns) < n && ctx.Err() == nil { - allRuns = []pipeline.Run{} - for _, node := range nodes { - runs, err := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err) - allRuns = append(allRuns, runs...) - } - time.Sleep(interval) - } - runs := len(allRuns) - t.Logf("found %d pipeline runs", runs) - require.GreaterOrEqual(t, runs, n) -} - -func checkPipelineRuns(t *testing.T, nodes []Node, n int) int { - var allRuns []pipeline.Run - for _, node := range nodes { - runs, err2 := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err2) - allRuns = append(allRuns, runs...) - } - runs := len(allRuns) - t.Logf("found %d pipeline runs", runs) - require.GreaterOrEqual(t, runs, n) - return runs } func emitEvents(ctx context.Context, t *testing.T, n int, contracts []*log_upkeep_counter_wrapper.LogUpkeepCounter, carrol *bind.TransactOpts, afterEmit func()) { @@ -424,32 +389,32 @@ func mapListener(m *sync.Map, n int) func() bool { return func() bool { count := 0 m.Range(func(key, value interface{}) bool { - count++ + count += value.(int) return true }) return count > n } } -func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry *iregistry21.IKeeperRegistryMaster, ids []*big.Int, startBlock int64) (func() bool, func()) { +func listenPerformedN(t *testing.T, backend *backends.SimulatedBackend, registry *iregistry21.IKeeperRegistryMaster, ids []*big.Int, startBlock int64, count int) (func() bool, func()) { cache := &sync.Map{} ctx, cancel := context.WithCancel(testutils.Context(t)) start := startBlock go func() { for ctx.Err() == nil { - bl := backend.Blockchain().CurrentBlock().Number.Uint64() + currentBlock := backend.Blockchain().CurrentBlock().Number.Uint64() - sc := make([]bool, len(ids)) - for i := range sc { - sc[i] = true + success := make([]bool, len(ids)) + for i := range success { + success[i] = true } iter, err := registry.FilterUpkeepPerformed(&bind.FilterOpts{ Start: uint64(start), - End: &bl, + End: ¤tBlock, Context: ctx, - }, ids, sc) + }, ids, success) if ctx.Err() != nil { return @@ -460,7 +425,15 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry for iter.Next() { if iter.Event != nil { t.Logf("[automation-ocr3 | EvmRegistry] upkeep performed event emitted for id %s", iter.Event.Id.String()) - cache.Store(iter.Event.Id.String(), true) + + //cache.Store(iter.Event.Id.String(), true) + count, ok := cache.Load(iter.Event.Id.String()) + if !ok { + cache.Store(iter.Event.Id.String(), 1) + continue + } + countI := count.(int) + cache.Store(iter.Event.Id.String(), countI+1) } } @@ -470,7 +443,11 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry } }() - return mapListener(cache, 0), cancel + return mapListener(cache, count), cancel +} + +func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry *iregistry21.IKeeperRegistryMaster, ids []*big.Int, startBlock int64) (func() bool, func()) { + return listenPerformedN(t, backend, registry, ids, startBlock, 0) } func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IKeeperRegistryMaster, backend *backends.SimulatedBackend, usr *bind.TransactOpts) ([]Node, *SimulatedMercuryServer) { diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 6674b0828b..d0a93f7763 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -58,7 +58,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -411,15 +410,6 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { } g.Eventually(receivedBytes, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(payload1)) - // check pipeline runs - var allRuns []pipeline.Run - for _, node := range nodes { - runs, err2 := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err2) - allRuns = append(allRuns, runs...) - } - require.GreaterOrEqual(t, len(allRuns), 1) - // change payload _, err = upkeepContract.SetBytesToSend(carrol, payload2) require.NoError(t, err) @@ -683,15 +673,6 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { } g.Eventually(receivedBytes, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(payload1)) - // check pipeline runs - var allRuns []pipeline.Run - for _, node := range nodes { - runs, err2 := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err2) - allRuns = append(allRuns, runs...) - } - require.GreaterOrEqual(t, len(allRuns), 1) - // change payload _, err = upkeepContract.SetBytesToSend(carrol, payload2) require.NoError(t, err) diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 76e5bb6e00..c3c60ad58b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -17,13 +17,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" evmregistry20 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20" evmregistry21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" evmregistry21transmit "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -43,9 +43,9 @@ var ( ErrNoChainFromSpec = fmt.Errorf("could not create chain from spec") ) -func EVMProvider(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, pr pipeline.Runner) (evmrelay.OCR2KeeperProvider, error) { +func EVMProvider(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, ethKeystore keystore.Eth) (evmrelay.OCR2KeeperProvider, error) { oSpec := spec.OCR2OracleSpec - ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(db, chain, pr, spec, lggr.Named("OCR2KeeperRelayer")) + ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(db, chain, lggr.Named("OCR2KeeperRelayer"), ethKeystore) keeperProvider, err := ocr2keeperRelayer.NewOCR2KeeperProvider( types.RelayArgs{ @@ -71,7 +71,7 @@ func EVMDependencies20( db *sqlx.DB, lggr logger.Logger, chain legacyevm.Chain, - pr pipeline.Runner, + ethKeystore keystore.Eth, ) (evmrelay.OCR2KeeperProvider, *evmregistry20.EvmRegistry, Encoder20, *evmregistry20.LogProvider, error) { var err error @@ -79,7 +79,7 @@ func EVMDependencies20( var registry *evmregistry20.EvmRegistry // the provider will be returned as a dependency - if keeperProvider, err = EVMProvider(db, chain, lggr, spec, pr); err != nil { + if keeperProvider, err = EVMProvider(db, chain, lggr, spec, ethKeystore); err != nil { return nil, nil, nil, nil, err } @@ -112,17 +112,17 @@ func EVMDependencies21( db *sqlx.DB, lggr logger.Logger, chain legacyevm.Chain, - pr pipeline.Runner, mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, dbCfg pg.QConfig, + ethKeystore keystore.Eth, ) (evmrelay.OCR2KeeperProvider, evmregistry21.AutomationServices, error) { var err error var keeperProvider evmrelay.OCR2KeeperProvider oSpec := spec.OCR2OracleSpec // the provider will be returned as a dependency - if keeperProvider, err = EVMProvider(db, chain, lggr, spec, pr); err != nil { + if keeperProvider, err = EVMProvider(db, chain, lggr, spec, ethKeystore); err != nil { return nil, nil, err } diff --git a/core/services/ocrcommon/transmitter_pipeline.go b/core/services/ocrcommon/transmitter_pipeline.go deleted file mode 100644 index e62f745a94..0000000000 --- a/core/services/ocrcommon/transmitter_pipeline.go +++ /dev/null @@ -1,97 +0,0 @@ -package ocrcommon - -import ( - "context" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" -) - -const txObservationSource = ` - transmit_tx [type=ethtx - minConfirmations=0 - to="$(jobSpec.contractAddress)" - from="[$(jobSpec.fromAddress)]" - evmChainID="$(jobSpec.evmChainID)" - data="$(jobSpec.data)" - gasLimit="$(jobSpec.gasLimit)" - forwardingAllowed="$(jobSpec.forwardingAllowed)" - transmitChecker="$(jobSpec.transmitChecker)"] - transmit_tx -` - -type pipelineTransmitter struct { - lgr logger.Logger - fromAddress common.Address - gasLimit uint32 - effectiveTransmitterAddress common.Address - strategy types.TxStrategy - checker txmgr.TransmitCheckerSpec - pr pipeline.Runner - spec job.Job - chainID string -} - -// NewPipelineTransmitter creates a new eth transmitter using the job pipeline mechanism -func NewPipelineTransmitter( - lgr logger.Logger, - fromAddress common.Address, - gasLimit uint32, - effectiveTransmitterAddress common.Address, - strategy types.TxStrategy, - checker txmgr.TransmitCheckerSpec, - pr pipeline.Runner, - spec job.Job, - chainID string, -) Transmitter { - return &pipelineTransmitter{ - lgr: lgr, - fromAddress: fromAddress, - gasLimit: gasLimit, - effectiveTransmitterAddress: effectiveTransmitterAddress, - strategy: strategy, - checker: checker, - pr: pr, - spec: spec, - chainID: chainID, - } -} - -func (t *pipelineTransmitter) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, _ *txmgr.TxMeta) error { - // t.strategy is ignored currently as pipeline does not support passing this (sc-55115) - vars := pipeline.NewVarsFrom(map[string]interface{}{ - "jobSpec": map[string]interface{}{ - "contractAddress": toAddress.String(), - "fromAddress": t.fromAddress.String(), - "gasLimit": t.gasLimit, - "evmChainID": t.chainID, - "forwardingAllowed": t.spec.ForwardingAllowed, - "data": payload, - "transmitChecker": t.checker, - }, - }) - - t.spec.PipelineSpec.DotDagSource = txObservationSource - run := pipeline.NewRun(*t.spec.PipelineSpec, vars) - - if _, err := t.pr.Run(ctx, run, t.lgr, true, nil); err != nil { - return errors.Wrap(err, "Skipped OCR transmission") - } - - if run.State != pipeline.RunStatusCompleted { - return fmt.Errorf("unexpected pipeline run state: %s with fatal errors %w", run.State, run.FatalErrors.ToError()) - } - - return nil -} - -func (t *pipelineTransmitter) FromAddress() common.Address { - return t.effectiveTransmitterAddress -} diff --git a/core/services/ocrcommon/transmitter_pipeline_test.go b/core/services/ocrcommon/transmitter_pipeline_test.go deleted file mode 100644 index e0114d0aa0..0000000000 --- a/core/services/ocrcommon/transmitter_pipeline_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package ocrcommon_test - -import ( - "testing" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" -) - -func Test_PipelineTransmitter_CreateEthTransaction(t *testing.T) { - t.Parallel() - - lggr := logger.TestLogger(t) - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - - chainID := "12345" - gasLimit := uint32(1000) - effectiveTransmitterAddress := fromAddress - toAddress := testutils.NewAddress() - payload := []byte{1, 2, 3} - strategy := newMockTxStrategy(t) - checker := txmgr.TransmitCheckerSpec{CheckerType: txmgr.TransmitCheckerTypeSimulate} - runner := pipelinemocks.NewRunner(t) - - transmitter := ocrcommon.NewPipelineTransmitter( - lggr, - fromAddress, - gasLimit, - effectiveTransmitterAddress, - strategy, - checker, - runner, - job.Job{ - PipelineSpec: &pipeline.Spec{}, - }, - chainID, - ) - - runner.On("Run", mock.Anything, mock.AnythingOfType("*pipeline.Run"), mock.Anything, mock.Anything, mock.Anything). - Return(false, nil). - Run(func(args mock.Arguments) { - run := args.Get(1).(*pipeline.Run) - require.Equal(t, map[string]interface{}{ - "jobSpec": map[string]interface{}{ - "contractAddress": toAddress.String(), - "fromAddress": fromAddress.String(), - "gasLimit": gasLimit, - "evmChainID": chainID, - "forwardingAllowed": false, - "data": payload, - "transmitChecker": checker, - }, - }, run.Inputs.Val) - - save := args.Get(3).(bool) - require.True(t, save) - - run.State = pipeline.RunStatusCompleted - }).Once() - - require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil)) -} diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index aea704adac..83540e22bb 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -27,13 +27,11 @@ import ( txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" @@ -373,7 +371,12 @@ func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.Re return newConfigWatcher(lggr, aggregatorAddress, contractABI, offchainConfigDigester, cp, chain, relayConfig.FromBlock, opts.New), nil } -func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth) (*contractTransmitter, error) { +type configTransmitterOpts struct { + // override the gas limit default provided in the config watcher + pluginGasLimit *uint32 +} + +func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts) (*contractTransmitter, error) { var relayConfig types.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -415,6 +418,9 @@ func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, tra if ocr2Limit != nil { gasLimit = *ocr2Limit } + if opts.pluginGasLimit != nil { + gasLimit = *opts.pluginGasLimit + } transmitter, err := ocrcommon.NewTransmitter( configWatcher.chain.TxManager(), @@ -442,55 +448,6 @@ func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, tra ) } -func newPipelineContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, pluginGasLimit *uint32, configWatcher *configWatcher, spec job.Job, pr pipeline.Runner) (*contractTransmitter, error) { - var relayConfig types.RelayConfig - if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { - return nil, err - } - - if !relayConfig.EffectiveTransmitterID.Valid { - return nil, pkgerrors.New("EffectiveTransmitterID must be specified") - } - effectiveTransmitterAddress := common.HexToAddress(relayConfig.EffectiveTransmitterID.String) - transmitterAddress := common.HexToAddress(transmitterID) - scoped := configWatcher.chain.Config() - strategy := txmgrcommon.NewQueueingTxStrategy(rargs.ExternalJobID, scoped.OCR2().DefaultTransactionQueueDepth(), scoped.Database().DefaultQueryTimeout()) - - var checker txm.TransmitCheckerSpec - if configWatcher.chain.Config().OCR2().SimulateTransactions() { - checker.CheckerType = txm.TransmitCheckerTypeSimulate - } - - gasLimit := configWatcher.chain.Config().EVM().GasEstimator().LimitDefault() - ocr2Limit := configWatcher.chain.Config().EVM().GasEstimator().LimitJobType().OCR2() - if ocr2Limit != nil { - gasLimit = *ocr2Limit - } - if pluginGasLimit != nil { - gasLimit = *pluginGasLimit - } - - return NewOCRContractTransmitter( - configWatcher.contractAddress, - configWatcher.chain.Client(), - configWatcher.contractABI, - ocrcommon.NewPipelineTransmitter( - lggr, - transmitterAddress, - gasLimit, - effectiveTransmitterAddress, - strategy, - checker, - pr, - spec, - configWatcher.chain.ID().String(), - ), - configWatcher.chain.LogPoller(), - lggr, - nil, - ) -} - func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.MedianProvider, error) { lggr := r.lggr.Named("MedianProvider").Named(rargs.ExternalJobID.String()) relayOpts := types.NewRelayOpts(rargs) @@ -513,7 +470,7 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp } reportCodec := evmreportcodec.ReportCodec{} - contractTransmitter, err := newContractTransmitter(lggr, rargs, pargs.TransmitterID, configWatcher, r.ks.Eth()) + contractTransmitter, err := newContractTransmitter(lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}) if err != nil { return nil, err } diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index abc03c7abb..55c4d78e7b 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -22,8 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -51,21 +50,19 @@ type OCR2KeeperRelayer interface { // ocr2keeperRelayer is the relayer with added DKG and OCR2Keeper provider functions. type ocr2keeperRelayer struct { - db *sqlx.DB - chain legacyevm.Chain - pr pipeline.Runner - spec job.Job - lggr logger.Logger + db *sqlx.DB + chain legacyevm.Chain + lggr logger.Logger + ethKeystore keystore.Eth } // NewOCR2KeeperRelayer is the constructor of ocr2keeperRelayer -func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, pr pipeline.Runner, spec job.Job, lggr logger.Logger) OCR2KeeperRelayer { +func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, ethKeystore keystore.Eth) OCR2KeeperRelayer { return &ocr2keeperRelayer{ - db: db, - chain: chain, - pr: pr, - spec: spec, - lggr: lggr, + db: db, + chain: chain, + lggr: lggr, + ethKeystore: ethKeystore, } } @@ -76,7 +73,7 @@ func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, p } gasLimit := cfgWatcher.chain.Config().EVM().OCR2().Automation().GasLimit() - contractTransmitter, err := newPipelineContractTransmitter(r.lggr, rargs, pargs.TransmitterID, &gasLimit, cfgWatcher, r.spec, r.pr) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, cfgWatcher, configTransmitterOpts{pluginGasLimit: &gasLimit}) if err != nil { return nil, err } diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index 39d0503b8b..1e05f89d9d 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -67,7 +67,7 @@ func (r *ocr2vrfRelayer) NewDKGProvider(rargs commontypes.RelayArgs, pargs commo if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, configWatcher, r.ethKeystore) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func (r *ocr2vrfRelayer) NewOCR2VRFProvider(rargs commontypes.RelayArgs, pargs c if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, configWatcher, r.ethKeystore) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}) if err != nil { return nil, err } From f3d5417948c9a837b50327d4bf6a218fac915a92 Mon Sep 17 00:00:00 2001 From: Connor Stein Date: Tue, 12 Dec 2023 17:11:55 -0500 Subject: [PATCH 306/327] Standardize LP filter logging (#11515) * Standardize logs * Comments * More PR review * More * Fix test --- core/chains/evm/logpoller/log_poller.go | 15 +++++++++------ .../evm/logpoller/log_poller_internal_test.go | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 77b8025359..991cc8d430 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -217,6 +217,7 @@ func (filter *Filter) Contains(other *Filter) bool { // Generally speaking this is harmless. We enforce that EventSigs and Addresses are non-empty, // which means that anonymous events are not supported and log.Topics >= 1 always (log.Topics[0] is the event signature). // The filter may be unregistered later by Filter.Name +// Warnings/debug information is keyed by filter name. func (lp *logPoller) RegisterFilter(filter Filter, qopts ...pg.QOpt) error { if len(filter.Addresses) == 0 { return errors.Errorf("at least one address must be specified") @@ -242,33 +243,35 @@ func (lp *logPoller) RegisterFilter(filter Filter, qopts ...pg.QOpt) error { if existingFilter, ok := lp.filters[filter.Name]; ok { if existingFilter.Contains(&filter) { // Nothing new in this Filter + lp.lggr.Warnw("Filter already present, no-op", "name", filter.Name, "filter", filter) return nil } - lp.lggr.Warnw("Updating existing filter with more events or addresses", "filter", filter) - } else { - lp.lggr.Debugw("Creating new filter", "filter", filter) + lp.lggr.Warnw("Updating existing filter with more events or addresses", "name", filter.Name, "filter", filter) } if err := lp.orm.InsertFilter(filter, qopts...); err != nil { - return errors.Wrap(err, "RegisterFilter failed to save filter to db") + return errors.Wrap(err, "error inserting filter") } lp.filters[filter.Name] = filter lp.filterDirty = true return nil } +// UnregisterFilter will remove the filter with the given name. +// If the name does not exist, it will log an error but not return an error. +// Warnings/debug information is keyed by filter name. func (lp *logPoller) UnregisterFilter(name string, qopts ...pg.QOpt) error { lp.filterMu.Lock() defer lp.filterMu.Unlock() _, ok := lp.filters[name] if !ok { - lp.lggr.Errorf("Filter %s not found", name) + lp.lggr.Warnw("Filter not found", "name", name) return nil } if err := lp.orm.DeleteFilter(name, qopts...); err != nil { - return errors.Wrapf(err, "Failed to delete filter %s", name) + return errors.Wrap(err, "error deleting filter") } delete(lp.filters, name) lp.filterDirty = true diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index f840eefc7b..09e1deb864 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -57,7 +57,7 @@ func TestLogPoller_RegisterFilter(t *testing.T) { a1 := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbb") a2 := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbc") - lggr, observedLogs := logger.TestObserved(t, zapcore.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zapcore.WarnLevel) chainID := testutils.NewRandomEVMChainID() db := pgtest.NewSqlxDB(t) From ac9338f723d43283554e76bd9a996ebcaa90024d Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Wed, 13 Dec 2023 10:37:42 +0100 Subject: [PATCH 307/327] bump Foundry to the December release (#11540) --- .github/workflows/solidity-foundry.yml | 2 +- contracts/GNUmakefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 7f6fa4f482..b629106972 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -58,7 +58,7 @@ jobs: uses: foundry-rs/foundry-toolchain@v1 with: # Has to match the `make foundry` version. - version: nightly-09fe3e041369a816365a020f715ad6f94dbce9f2 + version: nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a - name: Run Forge build if: needs.changes.outputs.changes == 'true' diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index f5be193249..8ec536d520 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -43,7 +43,7 @@ mockery: $(mockery) ## Install mockery. .PHONY: foundry foundry: ## Install foundry. - foundryup --version nightly-09fe3e041369a816365a020f715ad6f94dbce9f2 + foundryup --version nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a .PHONY: foundry-refresh foundry-refresh: foundry From 57236b327a4f3f86d378ad2622572f3833256d3f Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Wed, 13 Dec 2023 09:20:12 -0500 Subject: [PATCH 308/327] Removes Optimism Goerli from Scheduled Tests (#11559) * Removes Optimism Goerli from Scheduled Tests * Missed a spot --- .github/workflows/live-testnet-tests.yml | 57 +----------------------- 1 file changed, 2 insertions(+), 55 deletions(-) diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index 2e9809505f..d060b5c510 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -33,9 +33,6 @@ env: BSC_TESTNET_URLS: ${{ secrets.QA_BSC_TESTNET_URLS }} BSC_TESTNET_HTTP_URLS: ${{ secrets.QA_BSC_TESTNET_HTTP_URLS }} - OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} - OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} - OPTIMISM_SEPOLIA_URLS: ${{ secrets.QA_OPTIMISM_SEPOLIA_URLS }} OPTIMISM_SEPOLIA_HTTP_URLS: ${{ secrets.QA_OPTIMISM_SEPOLIA_HTTP_URLS }} @@ -147,7 +144,7 @@ jobs: id-token: write contents: read runs-on: ubuntu-latest - needs: [sepolia-smoke-tests, bsc-testnet-tests, optimism-goerli-smoke-tests, optimism-sepolia-smoke-tests, arbitrum-sepolia-smoke-tests, base-goerli-smoke-tests, base-sepolia-smoke-tests, polygon-mumbai-smoke-tests, avalanche-fuji-smoke-tests, fantom-testnet-smoke-tests, celo-alfajores-smoke-tests, scroll-sepolia-smoke-tests, linea-goerli-smoke-tests] + needs: [sepolia-smoke-tests, bsc-testnet-tests, optimism-sepolia-smoke-tests, arbitrum-sepolia-smoke-tests, base-goerli-smoke-tests, base-sepolia-smoke-tests, polygon-mumbai-smoke-tests, avalanche-fuji-smoke-tests, fantom-testnet-smoke-tests, celo-alfajores-smoke-tests, scroll-sepolia-smoke-tests, linea-goerli-smoke-tests] steps: - name: Debug Result run: echo ${{ join(needs.*.result, ',') }} @@ -208,7 +205,7 @@ jobs: strategy: fail-fast: false matrix: - network: [Sepolia, Optimism Goerli, Optimism Sepolia, Arbitrum Sepolia, Base Goerli, Base Sepolia, Polygon Mumbai, Avalanche Fuji, Fantom Testnet, Celo Alfajores, Scroll Sepolia, Linea Goerli] + network: [Sepolia, Optimism Sepolia, Arbitrum Sepolia, Base Goerli, Base Sepolia, Polygon Mumbai, Avalanche Fuji, Fantom Testnet, Celo Alfajores, Scroll Sepolia, Linea Goerli] steps: - name: Get Results id: test-results @@ -391,56 +388,6 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - optimism-goerli-smoke-tests: - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: OPTIMISM_GOERLI - strategy: - fail-fast: false - max-parallel: 1 - matrix: - include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - - product: OCR - test: TestOCRBasic - - product: Automation Conditional - test: TestAutomationBasic/registry_2_1_conditional - - product: Automation Log Trigger - test: TestAutomationBasic/registry_2_1_logtrigger - name: Optimism Goerli ${{ matrix.product }} Tests - runs-on: ubuntu-latest - steps: - - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 - with: - name: tests - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-goerli - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - with: - test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} - binary_name: tests - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./logs - token: ${{ secrets.GITHUB_TOKEN }} - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - optimism-sepolia-smoke-tests: environment: integration permissions: From 1a26acd5515ddeaf14e17f98cfbf474249d05157 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 13 Dec 2023 08:35:28 -0600 Subject: [PATCH 309/327] fix health monitoring (#11558) --- core/chains/evm/gas/models.go | 31 +++- core/chains/evm/gas/models_test.go | 71 +++++---- core/chains/evm/txmgr/broadcaster_test.go | 12 +- core/chains/evm/txmgr/confirmer_test.go | 13 +- core/services/chainlink/relayer_factory.go | 6 +- core/services/relay/evm/evm.go | 4 +- core/web/health_controller.go | 11 +- core/web/health_controller_test.go | 70 ++++++++- core/web/testdata/body/health.json | 166 +++++++++++++++++++++ 9 files changed, 333 insertions(+), 51 deletions(-) create mode 100644 core/web/testdata/body/health.json diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index c7476d58ba..8d977df099 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -71,19 +71,31 @@ func NewEstimator(lggr logger.Logger, ethClient evmclient.Client, cfg Config, ge if rollups.IsRollupWithL1Support(cfg.ChainType()) { l1Oracle = rollups.NewL1GasPriceOracle(lggr, ethClient, cfg.ChainType()) } + var newEstimator func(logger.Logger) EvmEstimator switch s { case "Arbitrum": - return NewWrappedEvmEstimator(NewArbitrumEstimator(lggr, geCfg, ethClient, ethClient), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewArbitrumEstimator(lggr, geCfg, ethClient, ethClient) + } case "BlockHistory": - return NewWrappedEvmEstimator(NewBlockHistoryEstimator(lggr, ethClient, cfg, geCfg, bh, *ethClient.ConfiguredChainID()), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewBlockHistoryEstimator(lggr, ethClient, cfg, geCfg, bh, *ethClient.ConfiguredChainID()) + } case "FixedPrice": - return NewWrappedEvmEstimator(NewFixedPriceEstimator(geCfg, bh, lggr), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewFixedPriceEstimator(geCfg, bh, lggr) + } case "L2Suggested", "SuggestedPrice": - return NewWrappedEvmEstimator(NewSuggestedPriceEstimator(lggr, ethClient), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewSuggestedPriceEstimator(lggr, ethClient) + } default: lggr.Warnf("GasEstimator: unrecognised mode '%s', falling back to FixedPriceEstimator", s) - return NewWrappedEvmEstimator(NewFixedPriceEstimator(geCfg, bh, lggr), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewFixedPriceEstimator(geCfg, bh, lggr) + } } + return NewWrappedEvmEstimator(lggr, newEstimator, df, l1Oracle) } // DynamicFee encompasses both FeeCap and TipCap for EIP1559 transactions @@ -150,6 +162,7 @@ func (fee EvmFee) ValidDynamic() bool { // WrappedEvmEstimator provides a struct that wraps the EVM specific dynamic and legacy estimators into one estimator that conforms to the generic FeeEstimator type WrappedEvmEstimator struct { services.StateMachine + lggr logger.Logger EvmEstimator EIP1559Enabled bool l1Oracle rollups.L1Oracle @@ -157,16 +170,18 @@ type WrappedEvmEstimator struct { var _ EvmFeeEstimator = (*WrappedEvmEstimator)(nil) -func NewWrappedEvmEstimator(e EvmEstimator, eip1559Enabled bool, l1Oracle rollups.L1Oracle) EvmFeeEstimator { +func NewWrappedEvmEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, l1Oracle rollups.L1Oracle) EvmFeeEstimator { + lggr = logger.Named(lggr, "WrappedEvmEstimator") return &WrappedEvmEstimator{ - EvmEstimator: e, + lggr: lggr, + EvmEstimator: newEstimator(lggr), EIP1559Enabled: eip1559Enabled, l1Oracle: l1Oracle, } } func (e *WrappedEvmEstimator) Name() string { - return fmt.Sprintf("WrappedEvmEstimator(%s)", e.EvmEstimator.Name()) + return e.lggr.Name() } func (e *WrappedEvmEstimator) Start(ctx context.Context) error { diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index a2dce58ee3..95a7a471eb 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" @@ -27,39 +28,41 @@ func TestWrappedEvmEstimator(t *testing.T) { FeeCap: assets.NewWeiI(20), TipCap: assets.NewWeiI(1), } - - e := mocks.NewEvmEstimator(t) - e.On("GetDynamicFee", mock.Anything, mock.Anything, mock.Anything). + est := mocks.NewEvmEstimator(t) + est.On("GetDynamicFee", mock.Anything, mock.Anything, mock.Anything). Return(dynamicFee, gasLimit, nil).Twice() - e.On("GetLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + est.On("GetLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(legacyFee, gasLimit, nil).Twice() - e.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + est.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(dynamicFee, gasLimit, nil).Once() - e.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + est.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(legacyFee, gasLimit, nil).Once() + getRootEst := func(logger.Logger) gas.EvmEstimator { return est } - mockEvmEstimatorName := "MockEstimator" - mockEstimatorName := "WrappedEvmEstimator(MockEstimator)" + mockEstimatorName := "WrappedEvmEstimator" + mockEvmEstimatorName := "WrappedEvmEstimator.MockEstimator" // L1Oracle returns the correct L1Oracle interface t.Run("L1Oracle", func(t *testing.T) { + lggr := logger.Test(t) // expect nil - estimator := gas.NewWrappedEvmEstimator(e, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, false, nil) l1Oracle := estimator.L1Oracle() assert.Nil(t, l1Oracle) // expect l1Oracle oracle := rollupMocks.NewL1Oracle(t) - estimator = gas.NewWrappedEvmEstimator(e, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, false, oracle) l1Oracle = estimator.L1Oracle() assert.Equal(t, oracle, l1Oracle) }) // GetFee returns gas estimation based on configuration value t.Run("GetFee", func(t *testing.T) { + lggr := logger.Test(t) // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) fee, max, err := estimator.GetFee(ctx, nil, 0, nil) require.NoError(t, err) assert.Equal(t, gasLimit, max) @@ -69,7 +72,7 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) fee, max, err = estimator.GetFee(ctx, nil, 0, nil) require.NoError(t, err) assert.Equal(t, gasLimit, max) @@ -80,8 +83,9 @@ func TestWrappedEvmEstimator(t *testing.T) { // BumpFee returns bumped fee type based on original fee calculation t.Run("BumpFee", func(t *testing.T) { + lggr := logger.Test(t) dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) // expect legacy fee data fee, max, err := estimator.BumpFee(ctx, gas.EvmFee{Legacy: assets.NewWeiI(0)}, 0, nil, nil) @@ -114,11 +118,12 @@ func TestWrappedEvmEstimator(t *testing.T) { }) t.Run("GetMaxCost", func(t *testing.T) { + lggr := logger.Test(t) val := assets.NewEthValue(1) // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) total, err := estimator.GetMaxCost(ctx, val, nil, gasLimit, nil) require.NoError(t, err) fee := new(big.Int).Mul(legacyFee.ToInt(), big.NewInt(int64(gasLimit))) @@ -126,7 +131,7 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) total, err = estimator.GetMaxCost(ctx, val, nil, gasLimit, nil) require.NoError(t, err) fee = new(big.Int).Mul(dynamicFee.FeeCap.ToInt(), big.NewInt(int64(gasLimit))) @@ -134,33 +139,38 @@ func TestWrappedEvmEstimator(t *testing.T) { }) t.Run("Name", func(t *testing.T) { - evmEstimator := mocks.NewEvmEstimator(t) - oracle := rollupMocks.NewL1Oracle(t) + lggr := logger.Test(t) + oracle := rollupMocks.NewL1Oracle(t) + evmEstimator := mocks.NewEvmEstimator(t) evmEstimator.On("Name").Return(mockEvmEstimatorName, nil).Once() - estimator := gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) - name := estimator.Name() - require.Equal(t, mockEstimatorName, name) + estimator := gas.NewWrappedEvmEstimator(lggr, func(logger.Logger) gas.EvmEstimator { + return evmEstimator + }, false, oracle) + + require.Equal(t, mockEstimatorName, estimator.Name()) + require.Equal(t, mockEvmEstimatorName, evmEstimator.Name()) }) t.Run("Start and stop calls both EVM estimator and L1Oracle", func(t *testing.T) { - evmEstimator := mocks.NewEvmEstimator(t) + lggr := logger.Test(t) oracle := rollupMocks.NewL1Oracle(t) + evmEstimator := mocks.NewEvmEstimator(t) - evmEstimator.On("Name").Return(mockEvmEstimatorName, nil).Times(4) evmEstimator.On("Start", mock.Anything).Return(nil).Twice() evmEstimator.On("Close").Return(nil).Twice() oracle.On("Start", mock.Anything).Return(nil).Once() oracle.On("Close").Return(nil).Once() + getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(evmEstimator, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) err := estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) err = estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() @@ -168,22 +178,25 @@ func TestWrappedEvmEstimator(t *testing.T) { }) t.Run("Read calls both EVM estimator and L1Oracle", func(t *testing.T) { + lggr := logger.Test(t) evmEstimator := mocks.NewEvmEstimator(t) oracle := rollupMocks.NewL1Oracle(t) evmEstimator.On("Ready").Return(nil).Twice() oracle.On("Ready").Return(nil).Once() + getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(evmEstimator, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) err := estimator.Ready() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) err = estimator.Ready() require.NoError(t, err) }) t.Run("HealthReport merges report from EVM estimator and L1Oracle", func(t *testing.T) { + lggr := logger.Test(t) evmEstimator := mocks.NewEvmEstimator(t) oracle := rollupMocks.NewL1Oracle(t) @@ -192,17 +205,17 @@ func TestWrappedEvmEstimator(t *testing.T) { oracleKey := "oracle" oracleError := errors.New("oracle error") - evmEstimator.On("Name").Return(mockEvmEstimatorName, nil).Twice() evmEstimator.On("HealthReport").Return(map[string]error{evmEstimatorKey: evmEstimatorError}).Twice() oracle.On("HealthReport").Return(map[string]error{oracleKey: oracleError}).Once() + getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(evmEstimator, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) report := estimator.HealthReport() require.True(t, errors.Is(report[evmEstimatorKey], evmEstimatorError)) require.Nil(t, report[oracleKey]) require.NotNil(t, report[mockEstimatorName]) - estimator = gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) report = estimator.HealthReport() require.True(t, errors.Is(report[evmEstimatorKey], evmEstimatorError)) require.True(t, errors.Is(report[oracleKey], oracleError)) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index b9e8fe99e3..f676d3d18e 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -64,7 +64,9 @@ func NewTestEthBroadcaster( lggr := logger.Test(t) ge := config.EVM().GasEstimator() - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) + estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr) + }, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) @@ -1134,7 +1136,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // same as the parent test, but callback is set by ctor t.Run("callback set by ctor", func(t *testing.T) { lggr := logger.Test(t) - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) + estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr) + }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) localNextNonce = getLocalNextNonce(t, eb, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() @@ -1759,7 +1763,9 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethNodeNonce := uint64(22) - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) + estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr) + }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) checkerFactory := &testCheckerFactory{} ge := evmcfg.EVM().GasEstimator() diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 3acbfe9800..30b2a391a7 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -122,9 +122,10 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertRandomKey(t, ethKeyStore) estimator := gasmocks.NewEvmEstimator(t) + newEst := func(logger.Logger) gas.EvmEstimator { return estimator } lggr := logger.Test(t) ge := config.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ethKeyStore, txBuilder, lggr) ctx := testutils.Context(t) @@ -1639,9 +1640,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing kst := ksmocks.NewEth(t) estimator := gasmocks.NewEvmEstimator(t) + newEst := func(logger.Logger) gas.EvmEstimator { return estimator } estimator.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, uint32(0), pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() @@ -1685,9 +1687,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing estimator := gasmocks.NewEvmEstimator(t) estimator.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.DynamicFee{}, uint32(0), pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) + newEst := func(logger.Logger) gas.EvmEstimator { return estimator } // Create confirmer with necessary state ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() @@ -3079,7 +3082,9 @@ func ptr[T any](t T) *T { return &t } func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { lggr := logger.Test(t) ge := config.EVM().GasEstimator() - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) + estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr) + }, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 4ed73d8e53..b4bd530d08 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -45,9 +45,11 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m relayers := make(map[relay.ID]evmrelay.LoopRelayAdapter) + lggr := r.Logger.Named("EVM") + // override some common opts with the factory values. this seems weird... maybe other signatures should change, or this should take a different type... ccOpts := legacyevm.ChainRelayExtenderConfig{ - Logger: r.Logger.Named("EVM"), + Logger: lggr, KeyStore: config.CSAETHKeystore.Eth(), ChainOpts: config.ChainOpts, } @@ -71,7 +73,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m EventBroadcaster: ccOpts.EventBroadcaster, MercuryPool: r.MercuryPool, } - relayer, err2 := evmrelay.NewRelayer(r.Logger.Named("EVM").Named(relayID.ChainID), chain, relayerOpts) + relayer, err2 := evmrelay.NewRelayer(lggr.Named(relayID.ChainID), chain, relayerOpts) if err2 != nil { err = errors.Join(err, err2) continue diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 83540e22bb..303cdd3ba0 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -13,6 +13,7 @@ import ( "github.com/jmoiron/sqlx" pkgerrors "github.com/pkg/errors" "go.uber.org/multierr" + "golang.org/x/exp/maps" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" @@ -121,11 +122,12 @@ func (r *Relayer) Close() error { // Ready does noop: always ready func (r *Relayer) Ready() error { - return nil + return r.chain.Ready() } func (r *Relayer) HealthReport() (report map[string]error) { report = make(map[string]error) + maps.Copy(report, r.chain.HealthReport()) return } diff --git a/core/web/health_controller.go b/core/web/health_controller.go index d6a7edb234..d6490e5542 100644 --- a/core/web/health_controller.go +++ b/core/web/health_controller.go @@ -1,7 +1,10 @@ package web import ( + "cmp" "net/http" + "slices" + "testing" "github.com/gin-gonic/gin" @@ -94,6 +97,12 @@ func (hc *HealthController) Health(c *gin.Context) { }) } + if testing.Testing() { + slices.SortFunc(checks, func(a, b presenters.Check) int { + return cmp.Compare(a.Name, b.Name) + }) + } + // return a json description of all the checks - jsonAPIResponse(c, checks, "checks") + jsonAPIResponseWithStatus(c, checks, "checks", status) } diff --git a/core/web/health_controller_test.go b/core/web/health_controller_test.go index d380b279d0..7e7c42141c 100644 --- a/core/web/health_controller_test.go +++ b/core/web/health_controller_test.go @@ -1,15 +1,19 @@ package web_test import ( + "bytes" + _ "embed" + "encoding/json" + "io" "net/http" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/mocks" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestHealthController_Readyz(t *testing.T) { @@ -47,3 +51,63 @@ func TestHealthController_Readyz(t *testing.T) { }) } } + +func TestHealthController_Health_status(t *testing.T) { + var tt = []struct { + name string + ready bool + status int + }{ + { + name: "not ready", + ready: false, + status: http.StatusServiceUnavailable, + }, + { + name: "ready", + ready: true, + status: http.StatusOK, + }, + } + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + app := cltest.NewApplicationWithKey(t) + healthChecker := new(mocks.Checker) + healthChecker.On("Start").Return(nil).Once() + healthChecker.On("IsHealthy").Return(tc.ready, nil).Once() + healthChecker.On("Close").Return(nil).Once() + + app.HealthChecker = healthChecker + require.NoError(t, app.Start(testutils.Context(t))) + + client := app.NewHTTPClient(nil) + resp, cleanup := client.Get("/health") + t.Cleanup(cleanup) + assert.Equal(t, tc.status, resp.StatusCode) + }) + } +} + +var ( + //go:embed testdata/body/health.json + healthJSON string +) + +func TestHealthController_Health_body(t *testing.T) { + app := cltest.NewApplicationWithKey(t) + require.NoError(t, app.Start(testutils.Context(t))) + + client := app.NewHTTPClient(nil) + resp, cleanup := client.Get("/health") + t.Cleanup(cleanup) + assert.Equal(t, http.StatusServiceUnavailable, resp.StatusCode) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + // pretty print for comparison + var b bytes.Buffer + require.NoError(t, json.Indent(&b, body, "", " ")) + body = b.Bytes() + + assert.Equal(t, healthJSON, string(body)) +} diff --git a/core/web/testdata/body/health.json b/core/web/testdata/body/health.json new file mode 100644 index 0000000000..d841856054 --- /dev/null +++ b/core/web/testdata/body/health.json @@ -0,0 +1,166 @@ +{ + "data": [ + { + "type": "checks", + "id": "EVM.0", + "attributes": { + "name": "EVM.0", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.BalanceMonitor", + "attributes": { + "name": "EVM.0.BalanceMonitor", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.HeadBroadcaster", + "attributes": { + "name": "EVM.0.HeadBroadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.HeadTracker", + "attributes": { + "name": "EVM.0.HeadTracker", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.HeadTracker.HeadListener", + "attributes": { + "name": "EVM.0.HeadTracker.HeadListener", + "status": "failing", + "output": "Listener is not connected" + } + }, + { + "type": "checks", + "id": "EVM.0.LogBroadcaster", + "attributes": { + "name": "EVM.0.LogBroadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm", + "attributes": { + "name": "EVM.0.Txm", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.BlockHistoryEstimator", + "attributes": { + "name": "EVM.0.Txm.BlockHistoryEstimator", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.Broadcaster", + "attributes": { + "name": "EVM.0.Txm.Broadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.Confirmer", + "attributes": { + "name": "EVM.0.Txm.Confirmer", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.WrappedEvmEstimator", + "attributes": { + "name": "EVM.0.Txm.WrappedEvmEstimator", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "JobSpawner", + "attributes": { + "name": "JobSpawner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mercury.WSRPCPool", + "attributes": { + "name": "Mercury.WSRPCPool", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Monitor", + "attributes": { + "name": "Monitor", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineORM", + "attributes": { + "name": "PipelineORM", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineRunner", + "attributes": { + "name": "PipelineRunner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PromReporter", + "attributes": { + "name": "PromReporter", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "TelemetryManager", + "attributes": { + "name": "TelemetryManager", + "status": "passing", + "output": "" + } + } + ] +} \ No newline at end of file From 6f13447cca0105bccd0aeea6c6cf69526f3e1585 Mon Sep 17 00:00:00 2001 From: Gabriel Paradiso Date: Wed, 13 Dec 2023 15:49:01 +0100 Subject: [PATCH 310/327] [FUN-990] s4 observability improvements (#11512) * chore: count s4 number of updates performed by nodes * chore: add storage total use and slots occupied * chore: add plugin side of counting updates * fix: modify total size counter to use snapshot len * chore: take into account the payload size for total size * chore: fix lint errors * fix: fetch only payload_size, reword metrics help * chore: remove don_id label * chore: remove don_id for consistency --- core/services/functions/connector_handler.go | 10 ++++++++ core/services/ocr2/plugins/s4/plugin.go | 27 +++++++++++++++++--- core/services/s4/orm.go | 11 ++++---- core/services/s4/postgres_orm.go | 2 +- core/services/s4/postgres_orm_test.go | 1 + 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 5496bbdefc..1594dc6eb5 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -13,6 +13,8 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -57,6 +59,13 @@ var ( _ connector.GatewayConnectorHandler = &functionsConnectorHandler{} ) +var ( + promStorageUserUpdatesCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "storage_user_updates", + Help: "Number of storage updates performed by users", + }, []string{}) +) + // internal request ID is a hash of (sender, requestID) func InternalId(sender []byte, requestId []byte) RequestID { return RequestID(crypto.Keccak256Hash(append(sender, requestId...)).Bytes()) @@ -185,6 +194,7 @@ func (h *functionsConnectorHandler) handleSecretsSet(ctx context.Context, gatewa err = h.storage.Put(ctx, &key, &record, request.Signature) if err == nil { response.Success = true + promStorageUserUpdatesCount.WithLabelValues().Inc() } else { response.ErrorMessage = fmt.Sprintf("Failed to set secret: %v", err) } diff --git a/core/services/ocr2/plugins/s4/plugin.go b/core/services/ocr2/plugins/s4/plugin.go index fcb025b21c..677743c091 100644 --- a/core/services/ocr2/plugins/s4/plugin.go +++ b/core/services/ocr2/plugins/s4/plugin.go @@ -4,13 +4,28 @@ import ( "context" "time" + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/s4" +) - "github.com/pkg/errors" - "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +var ( + promStoragePluginUpdatesCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "storage_plugin_updates", + Help: "Number of storage updates fetched from other nodes", + }, []string{}) + + promStorageTotalByteSize = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "storage_total_byte_size", + Help: "Current byte size of data stored in S4", + }, []string{}) ) type plugin struct { @@ -59,6 +74,7 @@ func (c *plugin) Query(ctx context.Context, ts types.ReportTimestamp) (types.Que return nil, errors.Wrap(err, "failed to GetVersions in Query()") } + var storageTotalByteSize uint64 rows := make([]*SnapshotRow, len(snapshot)) for i, v := range snapshot { rows[i] = &SnapshotRow{ @@ -66,6 +82,8 @@ func (c *plugin) Query(ctx context.Context, ts types.ReportTimestamp) (types.Que Slotid: uint32(v.SlotId), Version: v.Version, } + + storageTotalByteSize += v.PayloadSize } queryBytes, err := MarshalQuery(rows, c.addressRange) @@ -76,6 +94,8 @@ func (c *plugin) Query(ctx context.Context, ts types.ReportTimestamp) (types.Que promReportingPluginsQueryRowsCount.WithLabelValues(c.config.ProductName).Set(float64(len(rows))) promReportingPluginsQueryByteSize.WithLabelValues(c.config.ProductName).Set(float64(len(queryBytes))) + promStorageTotalByteSize.WithLabelValues().Set(float64(storageTotalByteSize)) + c.addressRange.Advance() c.logger.Debug("S4StorageReporting Query", commontypes.LogFields{ @@ -268,6 +288,7 @@ func (c *plugin) ShouldAcceptFinalizedReport(ctx context.Context, ts types.Repor c.logger.Error("Failed to Update a row in ShouldAcceptFinalizedReport()", commontypes.LogFields{"err": err}) continue } + promStoragePluginUpdatesCount.WithLabelValues().Inc() } c.logger.Debug("S4StorageReporting ShouldAcceptFinalizedReport", commontypes.LogFields{ diff --git a/core/services/s4/orm.go b/core/services/s4/orm.go index 59f3410e14..4d3cee9312 100644 --- a/core/services/s4/orm.go +++ b/core/services/s4/orm.go @@ -20,11 +20,12 @@ type Row struct { // SnapshotRow(s) are returned by GetSnapshot function. type SnapshotRow struct { - Address *big.Big - SlotId uint - Version uint64 - Expiration int64 - Confirmed bool + Address *big.Big + SlotId uint + Version uint64 + Expiration int64 + Confirmed bool + PayloadSize uint64 } //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore diff --git a/core/services/s4/postgres_orm.go b/core/services/s4/postgres_orm.go index dba98b64aa..1f92f2e128 100644 --- a/core/services/s4/postgres_orm.go +++ b/core/services/s4/postgres_orm.go @@ -90,7 +90,7 @@ func (o orm) GetSnapshot(addressRange *AddressRange, qopts ...pg.QOpt) ([]*Snaps q := o.q.WithOpts(qopts...) rows := make([]*SnapshotRow, 0) - stmt := fmt.Sprintf(`SELECT address, slot_id, version, expiration, confirmed FROM %s WHERE namespace = $1 AND address >= $2 AND address <= $3;`, o.tableName) + stmt := fmt.Sprintf(`SELECT address, slot_id, version, expiration, confirmed, octet_length(payload) AS payload_size FROM %s WHERE namespace = $1 AND address >= $2 AND address <= $3;`, o.tableName) if err := q.Select(&rows, stmt, o.namespace, addressRange.MinAddress, addressRange.MaxAddress); err != nil { if !errors.Is(err, sql.ErrNoRows) { return nil, err diff --git a/core/services/s4/postgres_orm_test.go b/core/services/s4/postgres_orm_test.go index 4d07524b4e..d26f082ce5 100644 --- a/core/services/s4/postgres_orm_test.go +++ b/core/services/s4/postgres_orm_test.go @@ -181,6 +181,7 @@ func TestPostgresORM_GetSnapshot(t *testing.T) { assert.Equal(t, snapshotRow.Version, sr.Version) assert.Equal(t, snapshotRow.Expiration, sr.Expiration) assert.Equal(t, snapshotRow.Confirmed, sr.Confirmed) + assert.Equal(t, snapshotRow.PayloadSize, uint64(len(sr.Payload))) } }) From 9b500414c022acc7fa704b516dfe65194d49fea4 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Wed, 13 Dec 2023 10:04:45 -0500 Subject: [PATCH 311/327] [TT-367] [TT-745] Quick and Dirty OCRv2 Soak Test (#11487) * Quick and Dirty OCRv2 Soak Test * Enable version in on-demand action * Remove inputs * Default input * Fix echos * Debug * Bash shell * Increment another way * No 2130 silly * When did incrementing get hard? * Cleanup debug * Include in reporter * Fix version input * Instantiate map * Fix OCR2 job names * Change default intpus * Bridge work * Build pair IDs properly * Cleanup paths * Build more bridges * Fix configuration * Fix config build * Fix import --- .github/workflows/on-demand-ocr-soak-test.yml | 45 ++- integration-tests/actions/ocr2_helpers.go | 146 +++++++-- .../actions/ocr2_helpers_local.go | 9 +- integration-tests/actions/ocr_helpers.go | 2 +- .../actions/ocr_helpers_local.go | 2 +- integration-tests/client/chainlink.go | 9 +- .../contracts/contract_deployer.go | 20 ++ integration-tests/load/README.md | 17 +- integration-tests/load/ocr/README.md | 15 +- integration-tests/load/ocr/ocr_test.go | 5 +- integration-tests/load/ocr/vu.go | 1 + integration-tests/scripts/entrypoint | 4 + integration-tests/testreporters/ocr.go | 7 +- integration-tests/testsetups/ocr.go | 298 +++++++++++++----- 14 files changed, 447 insertions(+), 133 deletions(-) diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 567d9510de..a4289dd012 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -55,18 +55,16 @@ on: description: Container image version for the Chainlink nodes required: true default: "2.7.0" - testDuration: - description: Duration of the test (time string) - required: false - default: 15m - chainlinkNodeFunding: - description: How much to fund each Chainlink node (in ETH) - required: false - default: ".001" - timeBetweenRounds: - description: How long to wait before starting a new round + ocrVersion: + description: Version of OCR to Use + type: choice + options: + - 1 + - 2 + testInputs: + description: Duration;Funding;TimeBetweenRounds required: false - default: 1m + default: "10m;.1;1m" jobs: ocr_soak_test: @@ -84,9 +82,7 @@ jobs: SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_SLACK_CHANNEL }} - OCR_TEST_DURATION: ${{ inputs.testDuration }} - OCR_CHAINLINK_NODE_FUNDING: ${{ inputs.chainlinkNodeFunding }} - OCR_TIME_BETWEEN_ROUNDS: ${{ inputs.timeBetweenRounds }} + OCR_VERSION: ${{ inputs.ocrVersion }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} ENV_JOB_IMAGE_BASE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests @@ -101,6 +97,7 @@ jobs: continue-on-error: true - name: Get Inputs run: | + # Mask the sensitive inputs EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) @@ -115,6 +112,26 @@ jobs: echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV + + # Read in our test inputs + IFS=';' read -ra parts <<< "${{ inputs.testInputs }}" + index=0 + for part in "${parts[@]}"; do + # A little hacky, but good enough for this + if [ $index -eq 0 ]; then + echo "OCR_TEST_DURATION=$part" + echo "OCR_TEST_DURATION=$part" >> $GITHUB_ENV + elif [ $index -eq 1 ]; then + echo "OCR_CHAINLINK_NODE_FUNDING=$part" + echo "OCR_CHAINLINK_NODE_FUNDING=$part" >> $GITHUB_ENV + elif [ $index -eq 2 ]; then + echo "OCR_TIME_BETWEEN_ROUNDS=$part" + echo "OCR_TIME_BETWEEN_ROUNDS=$part" >> $GITHUB_ENV + else + echo "Additional Unregistered Input: $part" + fi + ((index+=1)) + done - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: diff --git a/integration-tests/actions/ocr2_helpers.go b/integration-tests/actions/ocr2_helpers.go index 02ce73e813..c4bc30c7c5 100644 --- a/integration-tests/actions/ocr2_helpers.go +++ b/integration-tests/actions/ocr2_helpers.go @@ -9,6 +9,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" "github.com/lib/pq" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -23,6 +24,7 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -104,12 +106,15 @@ func ConfigureOCRv2AggregatorContracts( } // BuildMedianOCR2Config builds a default OCRv2 config for the given chainlink nodes for a standard median aggregation job -func BuildMedianOCR2Config(workerNodes []*client.ChainlinkK8sClient) (*contracts.OCRv2Config, error) { +func BuildMedianOCR2Config( + workerNodes []*client.ChainlinkK8sClient, + ocrOffchainOptions contracts.OffchainOptions, +) (*contracts.OCRv2Config, error) { S, oracleIdentities, err := GetOracleIdentities(workerNodes) if err != nil { return nil, err } - signerKeys, transmitterAccounts, f_, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( + signerKeys, transmitterAccounts, f_, _, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( 30*time.Second, // deltaProgress time.Duration, 30*time.Second, // deltaResend time.Duration, 10*time.Second, // deltaRound time.Duration, @@ -149,6 +154,8 @@ func BuildMedianOCR2Config(workerNodes []*client.ChainlinkK8sClient) (*contracts transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(account))) } + onchainConfig, err := testhelpers.GenerateDefaultOCR2OnchainConfig(ocrOffchainOptions.MinimumAnswer, ocrOffchainOptions.MaximumAnswer) + return &contracts.OCRv2Config{ Signers: signerAddresses, Transmitters: transmitterAddresses, @@ -156,7 +163,7 @@ func BuildMedianOCR2Config(workerNodes []*client.ChainlinkK8sClient) (*contracts OnchainConfig: onchainConfig, OffchainConfigVersion: offchainConfigVersion, OffchainConfig: []byte(fmt.Sprintf("0x%s", offchainConfig)), - }, nil + }, err } // GetOracleIdentities retrieves all chainlink nodes' OCR2 config identities with defaul key index @@ -257,7 +264,6 @@ func CreateOCRv2Jobs( bootstrapNode *client.ChainlinkK8sClient, workerChainlinkNodes []*client.ChainlinkK8sClient, mockserver *ctfClient.MockserverClient, - mockServerPath string, // Path on the mock server for the Chainlink nodes to query mockServerValue int, // Value to get from the mock server when querying the path chainId uint64, // EVM chain ID forwardingAllowed bool, @@ -268,20 +274,28 @@ func CreateOCRv2Jobs( return err } p2pV2Bootstrapper := fmt.Sprintf("%s@%s:%d", bootstrapP2PIds.Data[0].Attributes.PeerID, bootstrapNode.InternalIP(), 6690) - // Set the value for the jobs to report on - err = mockserver.SetValuePath(mockServerPath, mockServerValue) - if err != nil { - return err - } + mockJuelsPath := "ocr2/juelsPerFeeCoinSource" // Set the juelsPerFeeCoinSource config value - err = mockserver.SetValuePath(fmt.Sprintf("%s/juelsPerFeeCoinSource", mockServerPath), mockServerValue) + err = mockserver.SetValuePath(mockJuelsPath, mockServerValue) if err != nil { return err } + // Create the juels bridge for each node only once + juelsBridge := &client.BridgeTypeAttributes{ + Name: "juels", + URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockJuelsPath), + } + for _, chainlinkNode := range workerChainlinkNodes { + err = chainlinkNode.MustCreateBridge(juelsBridge) + if err != nil { + return fmt.Errorf("failed creating bridge %s on CL node : %w", juelsBridge.Name, err) + } + } + for _, ocrInstance := range ocrInstances { bootstrapSpec := &client.OCR2TaskJobSpec{ - Name: "ocr2 bootstrap node", + Name: fmt.Sprintf("ocr2-bootstrap-%s", ocrInstance.Address()), JobType: "bootstrap", OCR2OracleSpec: job.OCR2OracleSpec{ ContractID: ocrInstance.Address(), @@ -289,7 +303,7 @@ func CreateOCRv2Jobs( RelayConfig: map[string]interface{}{ "chainID": chainId, }, - MonitoringEndpoint: null.StringFrom(fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockServerPath)), + MonitoringEndpoint: null.StringFrom(fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, "ocr2")), ContractConfigTrackerPollInterval: *models.NewInterval(15 * time.Second), }, } @@ -309,25 +323,22 @@ func CreateOCRv2Jobs( } nodeOCRKeyId := nodeOCRKeys.Data[0].ID - bta := &client.BridgeTypeAttributes{ - Name: mockServerPath, - URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockServerPath), + nodeContractPairID, err := BuildOCR2NodeContractPairID(chainlinkNode, ocrInstance) + if err != nil { + return err } - juelsBridge := &client.BridgeTypeAttributes{ - Name: "juels", - URL: fmt.Sprintf("%s/%s/juelsPerFeeCoinSource", mockserver.Config.ClusterURL, mockServerPath), + bta := &client.BridgeTypeAttributes{ + Name: nodeContractPairID, + URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, strings.TrimPrefix(nodeContractPairID, "/")), } + err = chainlinkNode.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) - } - err = chainlinkNode.MustCreateBridge(juelsBridge) - if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("failed creating bridge %s on CL node: %w", bta.Name, err) } ocrSpec := &client.OCR2TaskJobSpec{ - Name: "ocr2", + Name: fmt.Sprintf("ocr2-%s", uuid.NewString()), JobType: "offchainreporting2", MaxTaskDuration: "1m", ObservationSource: client.ObservationSourceSpecBridge(bta), @@ -379,3 +390,90 @@ func StartNewOCR2Round( } return nil } + +// SetOCR2AdapterResponse sets a single adapter response that correlates with an ocr contract and a chainlink node +// used for OCR2 tests +func SetOCR2AdapterResponse( + response int, + ocrInstance contracts.OffchainAggregatorV2, + chainlinkNode *client.ChainlinkK8sClient, + mockserver *ctfClient.MockserverClient, +) error { + nodeContractPairID, err := BuildOCR2NodeContractPairID(chainlinkNode, ocrInstance) + if err != nil { + return err + } + path := fmt.Sprintf("/%s", nodeContractPairID) + err = mockserver.SetValuePath(path, response) + if err != nil { + return fmt.Errorf("setting mockserver value path failed: %w", err) + } + return nil +} + +// SetOCR2AllAdapterResponsesToTheSameValue sets the mock responses in mockserver that are read by chainlink nodes +// to simulate different adapters. This sets all adapter responses for each node and contract to the same response +// used for OCR2 tests +func SetOCR2AllAdapterResponsesToTheSameValue( + response int, + ocrInstances []contracts.OffchainAggregatorV2, + chainlinkNodes []*client.ChainlinkK8sClient, + mockserver *ctfClient.MockserverClient, +) error { + eg := &errgroup.Group{} + for _, o := range ocrInstances { + ocrInstance := o + for _, n := range chainlinkNodes { + node := n + eg.Go(func() error { + return SetOCR2AdapterResponse(response, ocrInstance, node, mockserver) + }) + } + } + return eg.Wait() +} + +// SetOCR2AllAdapterResponsesToDifferentValues sets the mock responses in mockserver that are read by chainlink nodes +// to simulate different adapters. This sets all adapter responses for each node and contract to different responses +// used for OCR2 tests +func SetOCR2AllAdapterResponsesToDifferentValues( + responses []int, + ocrInstances []contracts.OffchainAggregatorV2, + chainlinkNodes []*client.ChainlinkK8sClient, + mockserver *ctfClient.MockserverClient, +) error { + if len(responses) != len(ocrInstances)*len(chainlinkNodes) { + return fmt.Errorf( + "amount of responses %d should be equal to the amount of OCR instances %d times the amount of Chainlink nodes %d", + len(responses), len(ocrInstances), len(chainlinkNodes), + ) + } + eg := &errgroup.Group{} + for _, o := range ocrInstances { + ocrInstance := o + for ni := 1; ni < len(chainlinkNodes); ni++ { + nodeIndex := ni + eg.Go(func() error { + return SetOCR2AdapterResponse(responses[nodeIndex-1], ocrInstance, chainlinkNodes[nodeIndex], mockserver) + }) + } + } + return eg.Wait() +} + +// BuildOCR2NodeContractPairID builds a UUID based on a related pair of a Chainlink node and OCRv2 contract +func BuildOCR2NodeContractPairID(node *client.ChainlinkK8sClient, ocrInstance contracts.OffchainAggregatorV2) (string, error) { + if node == nil { + return "", fmt.Errorf("chainlink node is nil") + } + if ocrInstance == nil { + return "", fmt.Errorf("OCR Instance is nil") + } + nodeAddress, err := node.PrimaryEthAddress() + if err != nil { + return "", fmt.Errorf("getting chainlink node's primary ETH address failed: %w", err) + } + shortNodeAddr := nodeAddress[2:12] + shortOCRAddr := ocrInstance.Address()[2:12] + return strings.ToLower(fmt.Sprintf("node_%s_contract_%s", shortNodeAddr, shortOCRAddr)), nil +} diff --git a/integration-tests/actions/ocr2_helpers_local.go b/integration-tests/actions/ocr2_helpers_local.go index e1b470bd0d..4a08921b8d 100644 --- a/integration-tests/actions/ocr2_helpers_local.go +++ b/integration-tests/actions/ocr2_helpers_local.go @@ -20,12 +20,13 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/store/models" + + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) func CreateOCRv2JobsLocal( @@ -95,11 +96,11 @@ func CreateOCRv2JobsLocal( } err = chainlinkNode.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } err = chainlinkNode.MustCreateBridge(juelsBridge) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } ocrSpec := &client.OCR2TaskJobSpec{ diff --git a/integration-tests/actions/ocr_helpers.go b/integration-tests/actions/ocr_helpers.go index 4f713dcdd6..17e536ec83 100644 --- a/integration-tests/actions/ocr_helpers.go +++ b/integration-tests/actions/ocr_helpers.go @@ -236,7 +236,7 @@ func CreateOCRJobs( } err = node.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } bootstrapPeers := []*client.ChainlinkClient{bootstrapNode.ChainlinkClient} diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index fb0fd0bd47..e9cad3f67e 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -196,7 +196,7 @@ func CreateOCRJobsLocal( } err = node.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } bootstrapPeers := []*client.ChainlinkClient{bootstrapNode} diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 16299a1ac8..56670812fb 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -267,6 +267,7 @@ func (c *ChainlinkClient) DeleteSpec(id string) (*http.Response, error) { // MustCreateBridge creates a bridge on the Chainlink node based on the provided attributes and returns error if // the request is unsuccessful func (c *ChainlinkClient) MustCreateBridge(bta *BridgeTypeAttributes) error { + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") resp, err := c.CreateBridge(bta) if err != nil { return err @@ -275,7 +276,7 @@ func (c *ChainlinkClient) MustCreateBridge(bta *BridgeTypeAttributes) error { } func (c *ChainlinkClient) CreateBridge(bta *BridgeTypeAttributes) (*http.Response, error) { - c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") resp, err := c.APIClient.R(). SetBody(bta). Post("/v2/bridge_types") @@ -288,7 +289,7 @@ func (c *ChainlinkClient) CreateBridge(bta *BridgeTypeAttributes) (*http.Respons // ReadBridge reads a bridge from the Chainlink node based on the provided name func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, error) { bt := BridgeType{} - c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Reading Bridge") + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Reading Bridge") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "name": name, @@ -304,7 +305,7 @@ func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, // ReadBridges reads bridges from the Chainlink node func (c *ChainlinkClient) ReadBridges() (*Bridges, *resty.Response, error) { result := &Bridges{} - c.l.Info().Str(NodeURL, c.Config.URL).Msg("Getting all bridges") + c.l.Debug().Str(NodeURL, c.Config.URL).Msg("Getting all bridges") resp, err := c.APIClient.R(). SetResult(&result). Get("/v2/bridge_types") @@ -316,7 +317,7 @@ func (c *ChainlinkClient) ReadBridges() (*Bridges, *resty.Response, error) { // DeleteBridge deletes a bridge on the Chainlink node based on the provided name func (c *ChainlinkClient) DeleteBridge(name string) (*http.Response, error) { - c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting Bridge") + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting Bridge") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "name": name, diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 528f07ec68..464ae7a340 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -135,6 +135,7 @@ type ContractDeployer interface { DeployOffchainAggregatorEventsMock() (OffchainAggregatorEventsMock, error) DeployMockAggregatorProxy(aggregatorAddr string) (MockAggregatorProxy, error) DeployOffchainAggregatorV2(linkAddr string, offchainOptions OffchainOptions) (OffchainAggregatorV2, error) + LoadOffChainAggregatorV2(address *common.Address) (OffchainAggregatorV2, error) DeployKeeperRegistryCheckUpkeepGasUsageWrapper(keeperRegistryAddr string) (KeeperRegistryCheckUpkeepGasUsageWrapper, error) DeployKeeperRegistry11Mock() (KeeperRegistry11Mock, error) DeployKeeperRegistrar12Mock() (KeeperRegistrar12Mock, error) @@ -1584,6 +1585,25 @@ func (e *EthereumContractDeployer) DeployOffchainAggregatorV2( }, err } +// LoadOffChainAggregatorV2 loads an already deployed offchain aggregator v2 contract +func (e *EthereumContractDeployer) LoadOffChainAggregatorV2(address *common.Address) (OffchainAggregatorV2, error) { + instance, err := e.client.LoadContract("OffChainAggregatorV2", *address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return ocr2aggregator.NewOCR2Aggregator(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumOffchainAggregatorV2{ + client: e.client, + contract: instance.(*ocr2aggregator.OCR2Aggregator), + address: address, + l: e.l, + }, err +} + func (e *EthereumContractDeployer) DeployMercuryVerifierContract(verifierProxyAddr common.Address) (MercuryVerifier, error) { address, _, instance, err := e.client.DeployContract("Mercury Verifier", func( auth *bind.TransactOpts, diff --git a/integration-tests/load/README.md b/integration-tests/load/README.md index 1ed1ee8b94..3738a1d9ac 100644 --- a/integration-tests/load/README.md +++ b/integration-tests/load/README.md @@ -1,9 +1,11 @@ -## Performance tests for CL jobs +# Performance tests for CL jobs This folder container performance e2e tests for different job types, currently implemented: + - VRFv2 All the tests have 4 groups: + - one product soak - one product load - multiple product instances soak @@ -12,11 +14,13 @@ All the tests have 4 groups: When you develop an e2e performance suite for a new product you can implement the tests one by one to answer the questions: What are performance characteristics of a one instance of a product (jobs + contracts): + - is our product stable at all, no memory leaks, no flaking performance under some RPS? (test #1) - what are the limits for one product instance, figuring out the max/optimal performance params by increasing RPS and varying configuration (test #2) - update test #1 with optimal params and workload to constantly run in CI What are performance and capacity characteristics of Chainlink node(s) that run multiple products of the same type simultaneously: + - how many products of the same type we can run at once at a stable load with optimal configuration? (test #3) - what are the limits if we add more and more products of the same type, each product have a stable RPS, we vary only amount of products - update test #3 with optimal params and workload to constantly run in CI @@ -24,9 +28,9 @@ What are performance and capacity characteristics of Chainlink node(s) that run Implementing test #1 is **mandatory** for each product. Tests #2,#3,#4 are optional if you need to figure out your product scaling or node/cluster capacity. - ## Usage -``` + +```sh export LOKI_TOKEN=... export LOKI_URL=... @@ -34,10 +38,12 @@ go test -v -run TestVRFV2Load/vrfv2_soak_test ``` ### Dashboards + Each product has its own generated dashboard in `cmd/dashboard.go` Deploying dashboard: -``` + +```sh export GRAFANA_URL=... export GRAFANA_TOKEN=... export DATA_SOURCE_NAME=grafanacloud-logs @@ -56,8 +62,9 @@ If you need to assert some metrics in `Prometheus/Loki`, here is an [example](ht Do not mix workload logic with assertions, separate them. ### Implementation + To implement a standard e2e performance suite for a new product please look at `gun.go` and `vu.go`. Gun should be working with one instance of your product. -VU(Virtual user) creates a new instance of your product and works with it in `Call()` \ No newline at end of file +VU(Virtual user) creates a new instance of your product and works with it in `Call()` diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md index 61951ba700..3c231b5027 100644 --- a/integration-tests/load/ocr/README.md +++ b/integration-tests/load/ocr/README.md @@ -1,12 +1,21 @@ -### OCR Load tests +# OCR Load tests ## Setup + These tests can connect to any cluster create with [chainlink-cluster](../../../charts/chainlink-cluster/README.md) +<<<<<<< HEAD +Create your cluster + +```sh +kubectl create ns my-cluster +devspace use namespace my-cluster +======= Create your cluster, if you already have one just use `kubefwd` ``` kubectl create ns cl-cluster devspace use namespace cl-cluster +>>>>>>> 06656fac80999d1539e16951a54b87c6df13a9c7 devspace deploy sudo kubefwd svc -n cl-cluster ``` @@ -17,7 +26,7 @@ If you haven't changed anything in [devspace.yaml](../../../charts/chainlink-clu ## Usage -``` +```sh export LOKI_TOKEN=... export LOKI_URL=... @@ -25,4 +34,4 @@ go test -v -run TestOCRLoad go test -v -run TestOCRVolume ``` -Check test configuration [here](config.toml) \ No newline at end of file +Check test configuration [here](config.toml) diff --git a/integration-tests/load/ocr/ocr_test.go b/integration-tests/load/ocr/ocr_test.go index 13aea441b2..49e624ecd8 100644 --- a/integration-tests/load/ocr/ocr_test.go +++ b/integration-tests/load/ocr/ocr_test.go @@ -3,12 +3,13 @@ package ocr import ( "testing" - "github.com/smartcontractkit/chainlink/integration-tests/k8s" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/wasp" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + + "github.com/smartcontractkit/chainlink/integration-tests/k8s" ) var ( diff --git a/integration-tests/load/ocr/vu.go b/integration-tests/load/ocr/vu.go index a905ec011d..96be77c701 100644 --- a/integration-tests/load/ocr/vu.go +++ b/integration-tests/load/ocr/vu.go @@ -13,6 +13,7 @@ import ( "go.uber.org/ratelimit" client2 "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" diff --git a/integration-tests/scripts/entrypoint b/integration-tests/scripts/entrypoint index cb5c98fde6..d2297abaa9 100755 --- a/integration-tests/scripts/entrypoint +++ b/integration-tests/scripts/entrypoint @@ -24,6 +24,7 @@ echo "Test exit code: ${exit_code}" # 3 is the code for an interrupted test, we only want to restart the test when the test is interrupted and in a state # that it can recover from. Otherwise we mark the test as "passed" as far as K8s is concerned so it doesn't restart it. if [ $exit_code -eq 3 ]; then +echo "Test was interrupted, exiting with 1 exit code to trigger K8s to restart" exit 1 # Exiting with non-zero status to trigger pod restart fi @@ -38,3 +39,6 @@ fi if [ -n "${UPLOAD_MEM_PROFILE}" ]; then upload_to_slack memprofile.out "MEM Profile for ${TEST_NAME}" fi + +echo "Exiting with 0 exit code as test is either completed, or failed and cannot be restarted" +exit 0 \ No newline at end of file diff --git a/integration-tests/testreporters/ocr.go b/integration-tests/testreporters/ocr.go index abbb261fa7..31f5eeab1b 100644 --- a/integration-tests/testreporters/ocr.go +++ b/integration-tests/testreporters/ocr.go @@ -21,6 +21,7 @@ import ( type OCRSoakTestReporter struct { StartTime time.Time AnomaliesDetected bool + OCRVersion string anomalies [][]string timeLine [][]string @@ -159,7 +160,7 @@ func (o *OCRSoakTestReporter) SetNamespace(namespace string) { // WriteReport writes OCR Soak test report to a CSV file and final report func (o *OCRSoakTestReporter) WriteReport(folderLocation string) error { - log.Debug().Msg("Writing OCR Soak Test Report") + log.Debug().Msgf("Writing OCRv%s Soak Test Report", o.OCRVersion) reportLocation := filepath.Join(folderLocation, "./ocr_soak_report.csv") o.csvLocation = reportLocation ocrReportFile, err := os.Create(reportLocation) @@ -170,7 +171,7 @@ func (o *OCRSoakTestReporter) WriteReport(folderLocation string) error { ocrReportWriter := csv.NewWriter(ocrReportFile) - err = ocrReportWriter.Write([]string{"OCR Soak Test Report"}) + err = ocrReportWriter.Write([]string{fmt.Sprintf("OCRv%s Soak Test Report", o.OCRVersion)}) if err != nil { return err } @@ -240,7 +241,7 @@ func (o *OCRSoakTestReporter) SendSlackNotification(t *testing.T, slackClient *s } testFailed := t.Failed() - headerText := ":white_check_mark: OCR Soak Test PASSED :white_check_mark:" + headerText := fmt.Sprintf(":white_check_mark: OCRv%s Soak Test PASSED :white_check_mark:", o.OCRVersion) if testFailed { headerText = ":x: OCR Soak Test FAILED :x:" } else if o.AnomaliesDetected { diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index a35d915ea9..f7e0e65d36 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" @@ -72,12 +73,16 @@ type OCRSoakTest struct { ocrRoundStates []*testreporters.OCRRoundState testIssues []*testreporters.TestIssue - ocrInstances []contracts.OffchainAggregator - ocrInstanceMap map[string]contracts.OffchainAggregator // address : instance + ocrV1Instances []contracts.OffchainAggregator + ocrV1InstanceMap map[string]contracts.OffchainAggregator // address : instance + + ocrV2Instances []contracts.OffchainAggregatorV2 + ocrV2InstanceMap map[string]contracts.OffchainAggregatorV2 // address : instance } // OCRSoakTestInputs define required inputs to run an OCR soak test type OCRSoakTestInputs struct { + OCRVersion string `envconfig:"OCR_VERSION" default:"1"` // Version of OCR to use (1 or 2) TestDuration time.Duration `envconfig:"TEST_DURATION" default:"15m"` // How long to run the test for NumberOfContracts int `envconfig:"NUMBER_CONTRACTS" default:"2"` // Number of OCR contracts to launch ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with @@ -86,6 +91,7 @@ type OCRSoakTestInputs struct { } func (i OCRSoakTestInputs) setForRemoteRunner() { + os.Setenv("TEST_OCR_VERSION", i.OCRVersion) os.Setenv("TEST_OCR_TEST_DURATION", i.TestDuration.String()) os.Setenv("TEST_OCR_NUMBER_CONTRACTS", fmt.Sprint(i.NumberOfContracts)) os.Setenv("TEST_OCR_CHAINLINK_NODE_FUNDING", strconv.FormatFloat(i.ChainlinkNodeFunding, 'f', -1, 64)) @@ -113,14 +119,16 @@ func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { Inputs: &testInputs, OperatorForwarderFlow: forwarderFlow, TestReporter: testreporters.OCRSoakTestReporter{ - StartTime: time.Now(), + OCRVersion: testInputs.OCRVersion, + StartTime: time.Now(), }, - t: t, - startTime: time.Now(), - timeLeft: testInputs.TestDuration, - log: logging.GetTestLogger(t), - ocrRoundStates: make([]*testreporters.OCRRoundState, 0), - ocrInstanceMap: make(map[string]contracts.OffchainAggregator), + t: t, + startTime: time.Now(), + timeLeft: testInputs.TestDuration, + log: logging.GetTestLogger(t), + ocrRoundStates: make([]*testreporters.OCRRoundState, 0), + ocrV1InstanceMap: make(map[string]contracts.OffchainAggregator), + ocrV2InstanceMap: make(map[string]contracts.OffchainAggregatorV2), } return test, test.ensureInputValues() } @@ -128,7 +136,7 @@ func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { // DeployEnvironment deploys the test environment, starting all Chainlink nodes and other components for the test func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { network := networks.MustGetSelectedNetworksFromEnv()[0] // Environment currently being used to soak test on - nsPre := "soak-ocr-" + nsPre := fmt.Sprintf("soak-ocr-v%s-", o.Inputs.OCRVersion) if o.OperatorForwarderFlow { nsPre = fmt.Sprintf("%sforwarder-", nsPre) } @@ -140,9 +148,15 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { PreventPodEviction: true, } + var conf string + if o.Inputs.OCRVersion == "1" { + conf = config.BaseOCR1Config + } else if o.Inputs.OCRVersion == "2" { + conf = config.BaseOCR2Config + } cd := chainlink.New(0, map[string]any{ "replicas": 6, - "toml": networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customChainlinkNetworkTOML, network), + "toml": networks.AddNetworkDetailedConfig(conf, customChainlinkNetworkTOML, network), "db": map[string]any{ "stateful": true, // stateful DB by default for soak tests }, @@ -228,7 +242,7 @@ func (o *OCRSoakTest) Setup() { err = o.chainClient.WaitForEvents() } - o.ocrInstances = actions.DeployOCRContractsForwarderFlow( + o.ocrV1Instances = actions.DeployOCRContractsForwarderFlow( o.t, o.Inputs.NumberOfContracts, linkTokenContract, @@ -237,8 +251,8 @@ func (o *OCRSoakTest) Setup() { authorizedForwarders, o.chainClient, ) - } else { - o.ocrInstances, err = actions.DeployOCRContracts( + } else if o.Inputs.OCRVersion == "1" { + o.ocrV1Instances, err = actions.DeployOCRContracts( o.Inputs.NumberOfContracts, linkTokenContract, contractDeployer, @@ -246,13 +260,41 @@ func (o *OCRSoakTest) Setup() { o.chainClient, ) require.NoError(o.t, err) + } else if o.Inputs.OCRVersion == "2" { + var transmitters []string + for _, node := range o.workerNodes { + nodeAddress, err := node.PrimaryEthAddress() + require.NoError(o.t, err, "Error getting node's primary ETH address") + transmitters = append(transmitters, nodeAddress) + } + ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() + o.ocrV2Instances, err = actions.DeployOCRv2Contracts( + o.Inputs.NumberOfContracts, + linkTokenContract, + contractDeployer, + transmitters, + o.chainClient, + ocrOffchainOptions, + ) + require.NoError(o.t, err, "Error deploying OCRv2 contracts") + contractConfig, err := actions.BuildMedianOCR2Config(o.workerNodes, ocrOffchainOptions) + require.NoError(o.t, err, "Error building median config") + err = actions.ConfigureOCRv2AggregatorContracts(o.chainClient, contractConfig, o.ocrV2Instances) + require.NoError(o.t, err, "Error configuring OCRv2 aggregator contracts") } err = o.chainClient.WaitForEvents() require.NoError(o.t, err, "Error waiting for OCR contracts to be deployed") - for _, ocrInstance := range o.ocrInstances { - o.ocrInstanceMap[ocrInstance.Address()] = ocrInstance + if o.Inputs.OCRVersion == "1" { + for _, ocrInstance := range o.ocrV1Instances { + o.ocrV1InstanceMap[ocrInstance.Address()] = ocrInstance + } + } else if o.Inputs.OCRVersion == "2" { + for _, ocrInstance := range o.ocrV2Instances { + o.ocrV2InstanceMap[ocrInstance.Address()] = ocrInstance + } } + o.log.Info().Msg("OCR Soak Test Setup Complete") } @@ -266,15 +308,19 @@ func (o *OCRSoakTest) Run() { startingValue := 5 if o.OperatorForwarderFlow { - actions.CreateOCRJobsWithForwarder(o.t, o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) - } else { - err := actions.CreateOCRJobs(o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) + actions.CreateOCRJobsWithForwarder(o.t, o.ocrV1Instances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) + } else if o.Inputs.OCRVersion == "1" { + err := actions.CreateOCRJobs(o.ocrV1Instances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) + require.NoError(o.t, err, "Error creating OCR jobs") + } else if o.Inputs.OCRVersion == "2" { + err := actions.CreateOCRv2Jobs(o.ocrV2Instances, o.bootstrapNode, o.workerNodes, o.mockServer, startingValue, o.chainClient.GetChainID().Uint64(), o.OperatorForwarderFlow) require.NoError(o.t, err, "Error creating OCR jobs") } o.log.Info(). Str("Test Duration", o.Inputs.TestDuration.Truncate(time.Second).String()). - Int("Number of OCR Contracts", len(o.ocrInstances)). + Int("Number of OCR Contracts", o.Inputs.NumberOfContracts). + Str("OCR Version", o.Inputs.OCRVersion). Msg("Starting OCR Soak Test") o.testLoop(o.Inputs.TestDuration, startingValue) @@ -306,6 +352,7 @@ type OCRSoakTestState struct { TimeRunning time.Duration `toml:"timeRunning"` TestDuration time.Duration `toml:"testDuration"` OCRContractAddresses []string `toml:"ocrContractAddresses"` + OCRVersion string `toml:"ocrVersion"` BootStrapNodeURL string `toml:"bootstrapNodeURL"` WorkerNodeURLs []string `toml:"workerNodeURLs"` @@ -315,10 +362,7 @@ type OCRSoakTestState struct { // SaveState saves the current state of the test to a TOML file func (o *OCRSoakTest) SaveState() error { - ocrAddresses := make([]string, len(o.ocrInstances)) - for i, ocrInstance := range o.ocrInstances { - ocrAddresses[i] = ocrInstance.Address() - } + ocrAddresses := o.getContractAddressesString() workerNodeURLs := make([]string, len(o.workerNodes)) for i, workerNode := range o.workerNodes { workerNodeURLs[i] = workerNode.URL() @@ -333,6 +377,7 @@ func (o *OCRSoakTest) SaveState() error { TimeRunning: time.Since(o.startTime), TestDuration: o.Inputs.TestDuration, OCRContractAddresses: ocrAddresses, + OCRVersion: o.Inputs.OCRVersion, ChainURL: o.chainClient.GetNetworkConfig().URL, MockServerURL: "http://mockserver:1080", // TODO: Make this dynamic @@ -378,7 +423,8 @@ func (o *OCRSoakTest) LoadState() error { o.namespace = testState.Namespace o.TestReporter = testreporters.OCRSoakTestReporter{ - StartTime: testState.StartTime, + OCRVersion: testState.OCRVersion, + StartTime: testState.StartTime, } o.ocrRoundStates = testState.OCRRoundStates o.testIssues = testState.TestIssues @@ -386,6 +432,7 @@ func (o *OCRSoakTest) LoadState() error { o.timeLeft = testState.TestDuration - testState.TimeRunning o.startTime = testState.StartTime o.startingBlockNum = testState.StartingBlockNum + o.Inputs.OCRVersion = testState.OCRVersion network := networks.MustGetSelectedNetworksFromEnv()[0] o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) @@ -405,15 +452,28 @@ func (o *OCRSoakTest) LoadState() error { return err } - o.ocrInstances = make([]contracts.OffchainAggregator, len(testState.OCRContractAddresses)) - for i, addr := range testState.OCRContractAddresses { - address := common.HexToAddress(addr) - instance, err := contractDeployer.LoadOffChainAggregator(&address) - if err != nil { - return err + if testState.OCRVersion == "1" { + o.ocrV1Instances = make([]contracts.OffchainAggregator, len(testState.OCRContractAddresses)) + for i, addr := range testState.OCRContractAddresses { + address := common.HexToAddress(addr) + instance, err := contractDeployer.LoadOffChainAggregator(&address) + if err != nil { + return err + } + o.ocrV1Instances[i] = instance + } + } else if testState.OCRVersion == "2" { + o.ocrV2Instances = make([]contracts.OffchainAggregatorV2, len(testState.OCRContractAddresses)) + for i, addr := range testState.OCRContractAddresses { + address := common.HexToAddress(addr) + instance, err := contractDeployer.LoadOffChainAggregatorV2(&address) + if err != nil { + return err + } + o.ocrV2Instances[i] = instance } - o.ocrInstances[i] = instance } + o.mockServer, err = ctfClient.ConnectMockServerURL(testState.MockServerURL) if err != nil { return err @@ -432,16 +492,30 @@ func (o *OCRSoakTest) Resume() { Str("Time Left", o.timeLeft.String()). Msg("Resuming OCR Soak Test") - ocrAddresses := make([]common.Address, len(o.ocrInstances)) - for i, ocrInstance := range o.ocrInstances { - ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) - } - contractABI, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() - require.NoError(o.t, err, "Error retrieving OCR contract ABI") - o.filterQuery = geth.FilterQuery{ - Addresses: ocrAddresses, - Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, - FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), + ocrAddresses := make([]common.Address, o.Inputs.NumberOfContracts) + + if o.Inputs.OCRVersion == "1" { + for i, ocrInstance := range o.ocrV1Instances { + ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) + } + contractABI, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() + require.NoError(o.t, err, "Error retrieving OCR contract ABI") + o.filterQuery = geth.FilterQuery{ + Addresses: ocrAddresses, + Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, + FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), + } + } else if o.Inputs.OCRVersion == "2" { + for i, ocrInstance := range o.ocrV2Instances { + ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) + } + contractABI, err := ocr2aggregator.AggregatorInterfaceMetaData.GetAbi() + require.NoError(o.t, err, "Error retrieving OCR contract ABI") + o.filterQuery = geth.FilterQuery{ + Addresses: ocrAddresses, + Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, + FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), + } } startingValue := 5 @@ -449,7 +523,7 @@ func (o *OCRSoakTest) Resume() { o.log.Info().Msg("Test Complete, collecting on-chain events") - err = o.collectEvents() + err := o.collectEvents() o.log.Error().Err(err).Interface("Query", o.filterQuery).Msg("Error collecting on-chain events, expect malformed report") o.TestReporter.RecordEvents(o.ocrRoundStates, o.testIssues) } @@ -537,10 +611,7 @@ func (o *OCRSoakTest) complete() { // setFilterQuery to look for all events that happened func (o *OCRSoakTest) setFilterQuery() { - ocrAddresses := make([]common.Address, len(o.ocrInstances)) - for i, ocrInstance := range o.ocrInstances { - ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) - } + ocrAddresses := o.getContractAddresses() contractABI, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() require.NoError(o.t, err, "Error retrieving OCR contract ABI") o.filterQuery = geth.FilterQuery{ @@ -570,21 +641,39 @@ func (o *OCRSoakTest) observeOCREvents() error { for { select { case event := <-eventLogs: - answerUpdated, err := o.ocrInstances[0].ParseEventAnswerUpdated(event) - if err != nil { - o.log.Warn(). - Err(err). + if o.Inputs.OCRVersion == "1" { + answerUpdated, err := o.ocrV1Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + o.log.Warn(). + Err(err). + Str("Address", event.Address.Hex()). + Uint64("Block Number", event.BlockNumber). + Msg("Error parsing event as AnswerUpdated") + continue + } + o.log.Info(). Str("Address", event.Address.Hex()). Uint64("Block Number", event.BlockNumber). - Msg("Error parsing event as AnswerUpdated") - continue + Uint64("Round ID", answerUpdated.RoundId.Uint64()). + Int64("Answer", answerUpdated.Current.Int64()). + Msg("Answer Updated Event") + } else if o.Inputs.OCRVersion == "2" { + answerUpdated, err := o.ocrV2Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + o.log.Warn(). + Err(err). + Str("Address", event.Address.Hex()). + Uint64("Block Number", event.BlockNumber). + Msg("Error parsing event as AnswerUpdated") + continue + } + o.log.Info(). + Str("Address", event.Address.Hex()). + Uint64("Block Number", event.BlockNumber). + Uint64("Round ID", answerUpdated.RoundId.Uint64()). + Int64("Answer", answerUpdated.Current.Int64()). + Msg("Answer Updated Event") } - o.log.Info(). - Str("Address", event.Address.Hex()). - Uint64("Block Number", event.BlockNumber). - Uint64("Round ID", answerUpdated.RoundId.Uint64()). - Int64("Answer", answerUpdated.Current.Int64()). - Msg("Answer Updated Event") case err = <-eventSub.Err(): backoff := time.Second for err != nil { @@ -614,7 +703,12 @@ func (o *OCRSoakTest) triggerNewRound(newValue int) error { o.ocrRoundStates[len(o.ocrRoundStates)-1].EndTime = time.Now() } - err := actions.SetAllAdapterResponsesToTheSameValue(newValue, o.ocrInstances, o.workerNodes, o.mockServer) + var err error + if o.Inputs.OCRVersion == "1" { + err = actions.SetAllAdapterResponsesToTheSameValue(newValue, o.ocrV1Instances, o.workerNodes, o.mockServer) + } else if o.Inputs.OCRVersion == "2" { + err = actions.SetOCR2AllAdapterResponsesToTheSameValue(newValue, o.ocrV2Instances, o.workerNodes, o.mockServer) + } if err != nil { return err } @@ -624,9 +718,16 @@ func (o *OCRSoakTest) triggerNewRound(newValue int) error { Answer: int64(newValue), FoundEvents: make(map[string][]*testreporters.FoundEvent), } - for _, ocrInstance := range o.ocrInstances { - expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) + if o.Inputs.OCRVersion == "1" { + for _, ocrInstance := range o.ocrV1Instances { + expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) + } + } else if o.Inputs.OCRVersion == "2" { + for _, ocrInstance := range o.ocrV2Instances { + expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) + } } + o.ocrRoundStates = append(o.ocrRoundStates, expectedState) o.log.Info(). Int("Value", newValue). @@ -662,17 +763,31 @@ func (o *OCRSoakTest) collectEvents() error { sortedFoundEvents := make([]*testreporters.FoundEvent, 0) for _, event := range contractEvents { - answerUpdated, err := o.ocrInstances[0].ParseEventAnswerUpdated(event) - if err != nil { - return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) + if o.Inputs.OCRVersion == "1" { + answerUpdated, err := o.ocrV1Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) + } + sortedFoundEvents = append(sortedFoundEvents, &testreporters.FoundEvent{ + StartTime: time.Unix(answerUpdated.UpdatedAt.Int64(), 0), + Address: event.Address.Hex(), + Answer: answerUpdated.Current.Int64(), + RoundID: answerUpdated.RoundId.Uint64(), + BlockNumber: event.BlockNumber, + }) + } else if o.Inputs.OCRVersion == "2" { + answerUpdated, err := o.ocrV2Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) + } + sortedFoundEvents = append(sortedFoundEvents, &testreporters.FoundEvent{ + StartTime: time.Unix(answerUpdated.UpdatedAt.Int64(), 0), + Address: event.Address.Hex(), + Answer: answerUpdated.Current.Int64(), + RoundID: answerUpdated.RoundId.Uint64(), + BlockNumber: event.BlockNumber, + }) } - sortedFoundEvents = append(sortedFoundEvents, &testreporters.FoundEvent{ - StartTime: time.Unix(answerUpdated.UpdatedAt.Int64(), 0), - Address: event.Address.Hex(), - Answer: answerUpdated.Current.Int64(), - RoundID: answerUpdated.RoundId.Uint64(), - BlockNumber: event.BlockNumber, - }) } // Sort our events by time to make sure they are in order (don't trust RPCs) @@ -705,6 +820,9 @@ func (o *OCRSoakTest) collectEvents() error { // ensureValues ensures that all values needed to run the test are present func (o *OCRSoakTest) ensureInputValues() error { inputs := o.Inputs + if inputs.OCRVersion != "1" && inputs.OCRVersion != "2" { + return fmt.Errorf("OCR version must be 1 or 2, found %s", inputs.OCRVersion) + } if inputs.NumberOfContracts <= 0 { return fmt.Errorf("Number of OCR contracts must be greater than 0, found %d", inputs.NumberOfContracts) } @@ -723,3 +841,39 @@ func (o *OCRSoakTest) ensureInputValues() error { o.Inputs.bigChainlinkNodeFunding = big.NewFloat(inputs.ChainlinkNodeFunding) return nil } + +// getContractAddressesString returns the addresses of all OCR contracts deployed as a string slice +func (o *OCRSoakTest) getContractAddressesString() []string { + contractAddresses := []string{} + if len(o.ocrV1Instances) != 0 { + for _, ocrInstance := range o.ocrV1Instances { + contractAddresses = append(contractAddresses, ocrInstance.Address()) + } + } else if len(o.ocrV2Instances) != 0 { + if len(o.ocrV2Instances) != 0 { + for _, ocrInstance := range o.ocrV2Instances { + contractAddresses = append(contractAddresses, ocrInstance.Address()) + } + } + } + + return contractAddresses +} + +// getContractAddresses returns the addresses of all OCR contracts deployed +func (o *OCRSoakTest) getContractAddresses() []common.Address { + contractAddresses := []common.Address{} + if len(o.ocrV1Instances) != 0 { + for _, ocrInstance := range o.ocrV1Instances { + contractAddresses = append(contractAddresses, common.HexToAddress(ocrInstance.Address())) + } + } else if len(o.ocrV2Instances) != 0 { + if len(o.ocrV2Instances) != 0 { + for _, ocrInstance := range o.ocrV2Instances { + contractAddresses = append(contractAddresses, common.HexToAddress(ocrInstance.Address())) + } + } + } + + return contractAddresses +} From 862f79ab2f469a36bae5f6623432ba37878d6be3 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 13 Dec 2023 12:18:35 -0600 Subject: [PATCH 312/327] bump common; use SugaredLogger methods (#11556) --- common/client/multi_node.go | 17 +++-- common/client/node_lifecycle.go | 29 +++++---- common/headtracker/head_tracker.go | 8 +-- common/txmgr/broadcaster.go | 18 +++--- common/txmgr/confirmer.go | 23 ++++--- common/txmgr/resender.go | 4 +- common/txmgr/txmgr.go | 10 +-- common/txmgr/types/client.go | 4 +- common/txmgr/types/tx.go | 6 +- core/chains/evm/client/chain_client.go | 8 +-- core/chains/evm/client/client.go | 8 +-- core/chains/evm/client/errors.go | 8 +-- core/chains/evm/client/helpers_test.go | 2 +- core/chains/evm/client/node.go | 61 +++++++++--------- core/chains/evm/client/node_lifecycle.go | 29 +++++---- core/chains/evm/client/pool.go | 12 ++-- core/chains/evm/client/rpc_client.go | 63 +++++++++---------- .../chains/evm/gas/block_history_estimator.go | 16 ++--- .../evm/gas/rollups/l1_gas_price_oracle.go | 6 +- core/chains/evm/log/helpers_test.go | 6 +- core/chains/evm/log/registrations.go | 24 +++---- core/chains/evm/logpoller/log_poller.go | 8 +-- core/chains/evm/txmgr/broadcaster_test.go | 2 +- core/chains/evm/txmgr/client.go | 8 +-- core/chains/evm/txmgr/evm_tx_store.go | 6 +- core/chains/evm/txmgr/transmitchecker.go | 10 +-- core/chains/evm/txmgr/transmitchecker_test.go | 2 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/pg/q.go | 6 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 5 +- 34 files changed, 203 insertions(+), 220 deletions(-) diff --git a/common/client/multi_node.go b/common/client/multi_node.go index dfd6585b64..7d55784e68 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -86,7 +86,7 @@ type multiNode[ sendonlys []SendOnlyNode[CHAIN_ID, RPC_CLIENT] chainID CHAIN_ID chainType config.ChainType - lggr logger.Logger + lggr logger.SugaredLogger selectionMode string noNewHeadsThreshold time.Duration nodeSelector NodeSelector[CHAIN_ID, HEAD, RPC_CLIENT] @@ -118,7 +118,7 @@ func NewMultiNode[ HEAD types.Head[BLOCK_HASH], RPC_CLIENT RPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD], ]( - l logger.Logger, + lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, @@ -131,9 +131,6 @@ func NewMultiNode[ ) MultiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT] { nodeSelector := newNodeSelector(selectionMode, nodes) - lggr := logger.Named(l, "MultiNode") - lggr = logger.With(lggr, "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 @@ -142,7 +139,7 @@ func NewMultiNode[ sendonlys: sendonlys, chainID: chainID, chainType: chainType, - lggr: lggr, + lggr: logger.Sugared(lggr).Named("MultiNode").With("chainID", chainID.String()), selectionMode: selectionMode, noNewHeadsThreshold: noNewHeadsThreshold, nodeSelector: nodeSelector, @@ -249,7 +246,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP c.activeNode = c.nodeSelector.Select() if c.activeNode == nil { - logger.Criticalw(c.lggr, "No live RPC nodes available", "NodeSelectionMode", c.nodeSelector.Name()) + c.lggr.Criticalw("No live RPC nodes available", "NodeSelectionMode", c.nodeSelector.Name()) errmsg := fmt.Errorf("no live nodes available for chain %s", c.chainID.String()) c.SvcErrBuffer.Append(errmsg) err = ErroringNodeError @@ -351,10 +348,10 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP } live := total - dead - logger.Tracew(c.lggr, fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + c.lggr.Tracew(fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) if total == dead { rerr := fmt.Errorf("no primary nodes available: 0/%d nodes are alive", total) - logger.Criticalw(c.lggr, rerr.Error(), "nodeStates", nodeStates) + c.lggr.Criticalw(rerr.Error(), "nodeStates", nodeStates) c.SvcErrBuffer.Append(rerr) } else if dead > 0 { c.lggr.Errorw(fmt.Sprintf("At least one primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) @@ -405,7 +402,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP if err != nil { c.lggr.Debugw("Secondary node BatchCallContext failed", "err", err) } else { - logger.Trace(c.lggr, "Secondary node BatchCallContext success") + c.lggr.Trace("Secondary node BatchCallContext success") } }(n) } diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index eda137d510..af8f27d498 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -93,9 +93,8 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() pollInterval := n.nodePoolCfg.PollInterval() - lggr := logger.Named(n.lfcLog, "Alive") - lggr = logger.With(lggr, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) - logger.Tracew(lggr, "Alive loop starting", "nodeState", n.State()) + lggr := logger.Sugared(n.lfcLog).Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) + lggr.Tracew("Alive loop starting", "nodeState", n.State()) headsC := make(chan HEAD) sub, err := n.rpc.Subscribe(n.nodeCtx, headsC, rpcSubscriptionMethodNewHeads) @@ -146,7 +145,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { case <-pollCh: var version string promPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) ctx, cancel := context.WithTimeout(n.nodeCtx, pollInterval) version, err := n.RPC().ClientVersion(ctx) cancel() @@ -166,7 +165,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) continue } } @@ -178,7 +177,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { // note: there must be another live node for us to be out of sync lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) if liveNodes < 2 { - logger.Criticalf(lggr, "RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) continue } n.declareOutOfSync(n.isOutOfSync) @@ -191,13 +190,13 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { return } promPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Got head", "head", bh) + lggr.Tracew("Got head", "head", bh) if bh.BlockNumber() > highestReceivedBlockNumber { promPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.BlockNumber())) - logger.Tracew(lggr, "Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) highestReceivedBlockNumber = bh.BlockNumber() } else { - logger.Tracew(lggr, "Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) } if outOfSyncT != nil { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) @@ -213,7 +212,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) @@ -279,7 +278,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td outOfSyncAt := time.Now() - lggr := logger.Named(n.lfcLog, "OutOfSync") + lggr := logger.Sugared(logger.Named(n.lfcLog, "OutOfSync")) lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) // Need to redial since out-of-sync nodes are automatically disconnected @@ -296,7 +295,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td return } - logger.Tracew(lggr, "Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) + 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, rpcSubscriptionMethodNewHeads) @@ -328,7 +327,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { - logger.Critical(lggr, "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") + lggr.Critical("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") n.declareInSync() return } @@ -358,7 +357,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { unreachableAt := time.Now() - lggr := logger.Named(n.lfcLog, "Unreachable") + lggr := logger.Sugared(logger.Named(n.lfcLog, "Unreachable")) lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) dialRetryBackoff := iutils.NewRedialBackoff() @@ -368,7 +367,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { case <-n.nodeCtx.Done(): return case <-time.After(dialRetryBackoff.Duration()): - logger.Tracew(lggr, "Trying to re-dial RPC node", "nodeState", n.State()) + lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) err := n.rpc.Dial(n.nodeCtx) if err != nil { diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 373aa5a958..4cc152fb9f 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -40,7 +40,7 @@ type HeadTracker[ BLOCK_HASH types.Hashable, ] struct { services.StateMachine - log logger.Logger + log logger.SugaredLogger headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH] headSaver types.HeadSaver[HTH, BLOCK_HASH] mailMon *mailbox.Monitor @@ -81,7 +81,7 @@ func NewHeadTracker[ chainID: client.ConfiguredChainID(), config: config, htConfig: htConfig, - log: lggr, + log: logger.Sugared(lggr), backfillMB: mailbox.NewSingle[HTH](), broadcastMB: mailbox.New[HTH](HeadsBufferSize), chStop: chStop, @@ -227,7 +227,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context prevUnFinalizedHead := prevHead.BlockNumber() - int64(ht.config.FinalityDepth()) if head.BlockNumber() < prevUnFinalizedHead { promOldHead.WithLabelValues(ht.chainID.String()).Inc() - logger.Criticalf(ht.log, "Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber()) + ht.log.Criticalf("Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber()) ht.SvcErrBuffer.Append(errors.New("got very old block")) } } @@ -310,7 +310,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, hea } mark := time.Now() fetched := 0 - l := logger.With(ht.log, "blockNumber", headBlockNumber, + l := ht.log.With("blockNumber", headBlockNumber, "n", headBlockNumber-baseHeight, "fromBlockHeight", baseHeight, "toBlockHeight", headBlockNumber-1) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index dba2b976c3..a62b3df869 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -82,7 +82,7 @@ type TransmitChecker[ // is returned. Errors should only be returned if the checker can confirm that a transaction // should not be sent, other errors (for example connection or other unexpected errors) should // be logged and swallowed. - Check(ctx context.Context, l logger.Logger, tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], a txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + Check(ctx context.Context, l logger.SugaredLogger, tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], a txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error } // Broadcaster monitors txes for transactions that need to @@ -108,7 +108,7 @@ type Broadcaster[ FEE feetypes.Fee, ] struct { services.StateMachine - lggr logger.Logger + lggr logger.SugaredLogger txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] @@ -172,7 +172,7 @@ func NewBroadcaster[ ) *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { lggr = logger.Named(lggr, "Broadcaster") b := &Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{ - lggr: lggr, + lggr: logger.Sugared(lggr), txStore: txStore, client: client, TxAttemptBuilder: txAttemptBuilder, @@ -311,7 +311,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) getS if err == nil { return seq, nil } - logger.Criticalw(eb.lggr, "failed to retrieve next sequence from on-chain for address: ", "address", address.String()) + eb.lggr.Criticalw("failed to retrieve next sequence from on-chain for address: ", "address", address.String()) return seq, err } @@ -399,7 +399,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Sync localSequence, err := eb.GetNextSequence(ctx, addr) // Address not found in map so skip sync if err != nil { - logger.Criticalw(eb.lggr, "Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) + eb.lggr.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) return } @@ -414,7 +414,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Sync newNextSequence, err := eb.sequenceSyncer.Sync(ctx, addr, localSequence) if err != nil { if attempt > 5 { - logger.Criticalw(eb.lggr, "Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + eb.lggr.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) eb.SvcErrBuffer.Append(err) } else { eb.lggr.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) @@ -537,7 +537,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand return fmt.Errorf("building transmit checker: %w", err), false } - lgr := etx.GetLogger(logger.With(eb.lggr, "fee", attempt.TxFee)) + lgr := etx.GetLogger(eb.lggr.With("fee", attempt.TxFee)) // If the transmit check does not complete within the timeout, the transaction will be sent // anyway. @@ -647,14 +647,14 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // If there is only one RPC node, or all RPC nodes have the same // configured cap, this transaction will get stuck and keep repeating // forever until the issue is resolved. - logger.Criticalw(lgr, `RPC node rejected this tx as outside Fee Cap`) + lgr.Criticalw(`RPC node rejected this tx as outside Fee Cap`) fallthrough default: // Every error that doesn't fall under one of the above categories will be treated as Unknown. fallthrough case client.Unknown: eb.SvcErrBuffer.Append(err) - logger.Criticalw(lgr, `Unknown error occurred while handling tx queue in ProcessUnstartedTxs. This chain/RPC client may not be supported. `+ + lgr.Criticalw(`Unknown error occurred while handling tx queue in ProcessUnstartedTxs. This chain/RPC client may not be supported. `+ `Urgent resolution required, Chainlink is currently operating in a degraded state and may miss transactions`, "err", err, "etx", etx, "attempt", attempt) nextSequence, e := eb.client.PendingSequenceAt(ctx, etx.FromAddress) if e != nil { diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index aabdf45ae3..fbc6ea8a10 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -118,7 +118,7 @@ type Confirmer[ ] struct { services.StateMachine txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] - lggr logger.Logger + lggr logger.SugaredLogger client txmgrtypes.TxmClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] resumeCallback ResumeCallback @@ -166,7 +166,7 @@ func NewConfirmer[ lggr = logger.Named(lggr, "Confirmer") return &Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ txStore: txStore, - lggr: lggr, + lggr: logger.Sugared(lggr), client: client, TxAttemptBuilder: txAttemptBuilder, resumeCallback: nil, @@ -520,8 +520,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat } } - lggr := logger.Named(ec.lggr, "BatchFetchReceipts") - lggr = logger.With(lggr, "blockNum", blockNum) + lggr := ec.lggr.Named("BatchFetchReceipts").With("blockNum", blockNum) txReceipts, txErrs, err := ec.client.BatchGetReceipts(ctx, attempts) if err != nil { @@ -533,9 +532,9 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat receipt := txReceipts[i] err := txErrs[i] - l := logger.Sugared(logger.With(attempt.Tx.GetLogger(lggr), "txHash", attempt.Hash.String(), "txAttemptID", attempt.ID, + l := attempt.Tx.GetLogger(lggr).With("txHash", attempt.Hash.String(), "txAttemptID", attempt.ID, "txID", attempt.TxID, "err", err, "sequence", attempt.Tx.Sequence, - )) + ) if err != nil { l.Error("FetchReceipt failed") @@ -554,7 +553,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat continue } - l = logger.Sugared(logger.With(l, "blockHash", receipt.GetBlockHash().String(), "status", receipt.GetStatus(), "transactionIndex", receipt.GetTransactionIndex())) + l = l.With("blockHash", receipt.GetBlockHash().String(), "status", receipt.GetStatus(), "transactionIndex", receipt.GetTransactionIndex()) if receipt.IsUnmined() { l.Debug("Got receipt for transaction but it's still in the mempool and not included in a block yet") @@ -811,7 +810,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bum return bumpedAttempt, fmt.Errorf("error bumping gas: %w", err) } -func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleInProgressAttempt(ctx context.Context, lggr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], blockHeight int64) error { +func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleInProgressAttempt(ctx context.Context, lggr logger.SugaredLogger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], blockHeight int64) error { if attempt.State != txmgrtypes.TxAttemptInProgress { return fmt.Errorf("invariant violation: expected tx_attempt %v to be in_progress, it was %s", attempt.ID, attempt.State) @@ -833,12 +832,12 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han } if len(etx.TxAttempts) == 0 { err := errors.New("expected to find at least 1 attempt") - logger.Sugared(ec.lggr).AssumptionViolationw(err.Error(), "err", err, "attempt", attempt) + ec.lggr.AssumptionViolationw(err.Error(), "err", err, "attempt", attempt) return err } if attempt.ID != etx.TxAttempts[0].ID { err := errors.New("expected highest priced attempt to be the current in_progress attempt") - logger.Sugared(ec.lggr).AssumptionViolationw(err.Error(), "err", err, "attempt", attempt, "txAttempts", etx.TxAttempts) + ec.lggr.AssumptionViolationw(err.Error(), "err", err, "attempt", attempt, "txAttempts", etx.TxAttempts) return err } replacementAttempt, err := ec.bumpGas(ctx, etx, etx.TxAttempts) @@ -846,7 +845,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han return fmt.Errorf("could not bump gas for terminally underpriced transaction: %w", err) } promNumGasBumps.WithLabelValues(ec.chainID.String()).Inc() - logger.With(lggr, + lggr.With( "sendError", sendError, "maxGasPriceConfig", ec.feeConfig.MaxFeePrice(), "previousAttempt", attempt, @@ -867,7 +866,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han // Should NEVER be fatal this is an invariant violation. The // Broadcaster can never create a TxAttempt that will // fatally error. - logger.Criticalw(lggr, "Invariant violation: fatal error while re-attempting transaction", + lggr.Criticalw("Invariant violation: fatal error while re-attempting transaction", "err", sendError, "fee", attempt.TxFee, "feeLimit", etx.FeeLimit, diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 74cf3d1389..dded59f55d 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -53,7 +53,7 @@ type Resender[ interval time.Duration config txmgrtypes.ResenderChainConfig txConfig txmgrtypes.ResenderTransactionsConfig - logger logger.Logger + logger logger.SugaredLogger lastAlertTimestamps map[string]time.Time ctx context.Context @@ -93,7 +93,7 @@ func NewResender[ pollInterval, config, txConfig, - logger.Named(lggr, "Resender"), + logger.Sugared(logger.Named(lggr, "Resender")), make(map[string]time.Time), ctx, cancel, diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index e43a16b29e..36a6a1304a 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -82,7 +82,7 @@ type Txm[ FEE feetypes.Fee, ] struct { services.StateMachine - logger logger.Logger + logger logger.SugaredLogger txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] config txmgrtypes.TransactionManagerChainConfig txConfig txmgrtypes.TransactionManagerTransactionsConfig @@ -142,7 +142,7 @@ func NewTxm[ tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], ) *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { b := Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ - logger: lggr, + logger: logger.Sugared(lggr), txStore: txStore, config: cfg, txConfig: txCfg, @@ -349,7 +349,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() select { case <-time.After(backoff.Duration()): if err := b.broadcaster.startInternal(ctx); err != nil { - logger.Criticalw(b.logger, "Failed to start Broadcaster", "err", err) + b.logger.Criticalw("Failed to start Broadcaster", "err", err) b.SvcErrBuffer.Append(err) continue } @@ -368,7 +368,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() select { case <-time.After(backoff.Duration()): if err := b.confirmer.startInternal(); err != nil { - logger.Criticalw(b.logger, "Failed to start Confirmer", "err", err) + b.logger.Criticalw("Failed to start Confirmer", "err", err) b.SvcErrBuffer.Append(err) continue } @@ -433,7 +433,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() } enabledAddresses, err := b.keyStore.EnabledAddressesForChain(b.chainID) if err != nil { - logger.Criticalf(b.logger, "Failed to reload key states after key change") + b.logger.Critical("Failed to reload key states after key change") b.SvcErrBuffer.Append(err) continue } diff --git a/common/txmgr/types/client.go b/common/txmgr/types/client.go index b44c41e417..0db50e97ad 100644 --- a/common/txmgr/types/client.go +++ b/common/txmgr/types/client.go @@ -47,7 +47,7 @@ type TransactionClient[ ctx context.Context, attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], bathSize int, - lggr logger.Logger, + lggr logger.SugaredLogger, ) ( txCodes []client.SendTxReturnCode, txErrs []error, @@ -58,7 +58,7 @@ type TransactionClient[ ctx context.Context, tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], - lggr logger.Logger, + lggr logger.SugaredLogger, ) (client.SendTxReturnCode, error) SendEmptyTransaction( ctx context.Context, diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index caac763fc0..0f5d651ae2 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -254,7 +254,7 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetMeta() (*TxMeta[A } // GetLogger returns a new logger with metadata fields. -func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger.Logger) logger.Logger { +func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger.Logger) logger.SugaredLogger { lgr = logger.With(lgr, "txID", e.ID, "sequence", e.Sequence, @@ -265,7 +265,7 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger meta, err := e.GetMeta() if err != nil { lgr.Errorw("failed to get meta of the transaction", "err", err) - return lgr + return logger.Sugared(lgr) } if meta != nil { @@ -315,7 +315,7 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger } } - return lgr + return logger.Sugared(lgr) } // GetChecker returns an Tx's transmit checker spec in struct form, unmarshalling it from JSON diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 3efc5645e2..255d802720 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -37,11 +37,11 @@ type chainClient struct { *evmtypes.Head, RPCCLient, ] - logger logger.Logger + logger logger.SugaredLogger } func NewChainClient( - logger logger.Logger, + lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, @@ -64,7 +64,7 @@ func NewChainClient( *evmtypes.Head, RPCCLient, ]( - logger, + lggr, selectionMode, leaseDuration, noNewHeadsThreshold, @@ -77,7 +77,7 @@ func NewChainClient( ) return &chainClient{ multiNode: multiNode, - logger: logger, + logger: logger.Sugared(lggr), } } diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index b85331a62a..f32ec01144 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -102,7 +102,7 @@ func ContextWithDefaultTimeout() (ctx context.Context, cancel context.CancelFunc // client represents an abstract client that manages connections to // multiple nodes for a single chain id type client struct { - logger logger.Logger + logger logger.SugaredLogger pool *Pool } @@ -113,10 +113,10 @@ var _ htrktypes.Client[*evmtypes.Head, ethereum.Subscription, *big.Int, common.H // Currently only supports one primary // // Deprecated: use [NewChainClient] -func NewClientWithNodes(logger logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) { - pool := NewPool(logger, selectionMode, leaseDuration, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType) +func NewClientWithNodes(lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) { + pool := NewPool(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType) return &client{ - logger: logger, + logger: logger.Sugared(lggr), pool: pool, }, nil } diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 143a5f8806..66cc30f74b 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -413,13 +413,13 @@ func ExtractRPCError(baseErr error) (*JsonError, error) { return &jErr, nil } -func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fromAddress common.Address, isL2 bool) (commonclient.SendTxReturnCode, error) { +func ClassifySendError(err error, lggr logger.SugaredLogger, tx *types.Transaction, fromAddress common.Address, isL2 bool) (commonclient.SendTxReturnCode, error) { sendError := NewSendError(err) if sendError == nil { return commonclient.Successful, err } if sendError.Fatal() { - logger.Criticalw(lggr, "Fatal error sending transaction", "err", sendError, "etx", tx) + lggr.Criticalw("Fatal error sending transaction", "err", sendError, "etx", tx) // Attempt is thrown away in this case; we don't need it since it never got accepted by a node return commonclient.Fatal, err } @@ -462,7 +462,7 @@ func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fro return commonclient.Retryable, err } if sendError.IsInsufficientEth() { - logger.Criticalw(lggr, fmt.Sprintf("Tx %x with type 0x%d was rejected due to insufficient eth: %s\n"+ + lggr.Criticalw(fmt.Sprintf("Tx %x with type 0x%d was rejected due to insufficient eth: %s\n"+ "ACTION REQUIRED: Chainlink wallet with address 0x%x is OUT OF FUNDS", tx.Hash(), tx.Type(), sendError.Error(), fromAddress, ), "err", sendError) @@ -472,7 +472,7 @@ func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fro return commonclient.Retryable, errors.Wrapf(sendError, "timeout while sending transaction %s", tx.Hash().Hex()) } if sendError.IsTxFeeExceedsCap() { - logger.Criticalw(lggr, fmt.Sprintf("Sending transaction failed: %s", label.RPCTxFeeCapConfiguredIncorrectlyWarning), + lggr.Criticalw(fmt.Sprintf("Sending transaction failed: %s", label.RPCTxFeeCapConfiguredIncorrectlyWarning), "etx", tx, "err", sendError, "id", "RPCTxFeeCapExceeded", diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 27b335534d..c2f60e13f5 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -42,7 +42,7 @@ func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeads return nil, errors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) } - lggr := logger.Test(t) + lggr := logger.Sugared(logger.Test(t)) n := NewNode(nodePoolCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-0", id, chainID, 1) n.(*node).setLatestReceived(0, big.NewInt(0)) primaries := []Node{n} diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index a2c8b807ba..a27321535e 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -137,7 +137,7 @@ type rawclient struct { type node struct { services.StateMachine lfcLog logger.Logger - rpcLog logger.Logger + rpcLog logger.SugaredLogger name string id int32 chainID *big.Int @@ -206,7 +206,7 @@ func NewNode(nodeCfg config.NodePool, noNewHeadsThreshold time.Duration, lggr lo "mode", n.getNodeMode(), ) n.lfcLog = logger.Named(lggr, "Lifecycle") - n.rpcLog = logger.Named(lggr, "RPC") + n.rpcLog = logger.Sugared(lggr).Named("RPC") n.stateLatestBlockNumber = -1 return n @@ -453,7 +453,7 @@ func (n *node) CallContext(ctx context.Context, result interface{}, method strin return err } defer cancel() - lggr := logger.With(n.newRqLggr(), + lggr := n.newRqLggr().With( "method", method, "args", args, ) @@ -478,9 +478,9 @@ func (n *node) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { return err } defer cancel() - lggr := logger.With(n.newRqLggr(), "nBatchElems", len(b), "batchElems", b) + lggr := n.newRqLggr().With("nBatchElems", len(b), "batchElems", b) - logger.Trace(lggr, "RPC call: evmclient.Client#BatchCallContext") + lggr.Trace("RPC call: evmclient.Client#BatchCallContext") start := time.Now() if http != nil { err = n.wrapHTTP(http.rpc.BatchCallContext(ctx, b)) @@ -500,7 +500,7 @@ func (n *node) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "args", args) + lggr := n.newRqLggr().With("args", args) lggr.Debug("RPC call: evmclient.Client#EthSubscribe") start := time.Now() @@ -523,7 +523,7 @@ func (n *node) TransactionReceipt(ctx context.Context, txHash common.Hash) (rece return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "txHash", txHash) + lggr := n.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionReceipt") @@ -550,7 +550,7 @@ func (n *node) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *t return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "txHash", txHash) + lggr := n.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionByHash") @@ -577,7 +577,7 @@ func (n *node) HeaderByNumber(ctx context.Context, number *big.Int) (header *typ return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "number", number) + lggr := n.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#HeaderByNumber") start := time.Now() @@ -601,7 +601,7 @@ func (n *node) HeaderByHash(ctx context.Context, hash common.Hash) (header *type return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "hash", hash) + lggr := n.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#HeaderByHash") start := time.Now() @@ -627,7 +627,7 @@ func (n *node) SendTransaction(ctx context.Context, tx *types.Transaction) error return err } defer cancel() - lggr := logger.With(n.newRqLggr(), "tx", tx) + lggr := n.newRqLggr().With("tx", tx) lggr.Debug("RPC call: evmclient.Client#SendTransaction") start := time.Now() @@ -650,7 +650,7 @@ func (n *node) PendingNonceAt(ctx context.Context, account common.Address) (nonc return 0, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account) + lggr := n.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingNonceAt") start := time.Now() @@ -679,7 +679,7 @@ func (n *node) NonceAt(ctx context.Context, account common.Address, blockNumber return 0, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := n.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#NonceAt") start := time.Now() @@ -705,7 +705,7 @@ func (n *node) PendingCodeAt(ctx context.Context, account common.Address) (code return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account) + lggr := n.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingCodeAt") start := time.Now() @@ -731,7 +731,7 @@ func (n *node) CodeAt(ctx context.Context, account common.Address, blockNumber * return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := n.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CodeAt") start := time.Now() @@ -757,7 +757,7 @@ func (n *node) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint return 0, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "call", call) + lggr := n.newRqLggr().With("call", call) lggr.Debug("RPC call: evmclient.Client#EstimateGas") start := time.Now() @@ -809,7 +809,7 @@ func (n *node) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumb return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "callMsg", msg, "blockNumber", blockNumber) + lggr := n.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CallContract") start := time.Now() @@ -836,7 +836,7 @@ func (n *node) BlockByNumber(ctx context.Context, number *big.Int) (b *types.Blo return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "number", number) + lggr := n.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#BlockByNumber") start := time.Now() @@ -862,7 +862,7 @@ func (n *node) BlockByHash(ctx context.Context, hash common.Hash) (b *types.Bloc return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "hash", hash) + lggr := n.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#BlockByHash") start := time.Now() @@ -914,7 +914,7 @@ func (n *node) BalanceAt(ctx context.Context, account common.Address, blockNumbe return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account.Hex(), "blockNumber", blockNumber) + lggr := n.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#BalanceAt") start := time.Now() @@ -940,7 +940,7 @@ func (n *node) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l []type return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "q", q) + lggr := n.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#FilterLogs") start := time.Now() @@ -966,7 +966,7 @@ func (n *node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "q", q) + lggr := n.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") start := time.Now() @@ -1011,10 +1011,8 @@ func (n *node) SuggestGasTipCap(ctx context.Context) (tipCap *big.Int, err error func (n *node) ChainID() (chainID *big.Int) { return n.chainID } // newRqLggr generates a new logger with a unique request ID -func (n *node) newRqLggr() logger.Logger { - return logger.With(n.rpcLog, - "requestID", uuid.New(), - ) +func (n *node) newRqLggr() logger.SugaredLogger { + return n.rpcLog.With("requestID", uuid.New()) } func (n *node) logResult( @@ -1025,17 +1023,14 @@ func (n *node) logResult( callName string, results ...interface{}, ) { - lggr = logger.With(lggr, "duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) + slggr := logger.Sugared(lggr).With("duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) promEVMPoolRPCNodeCalls.WithLabelValues(n.chainID.String(), n.name).Inc() if err == nil { promEVMPoolRPCNodeCallsSuccess.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, - fmt.Sprintf("evmclient.Client#%s RPC call success", callName), - results..., - ) + slggr.Tracew(fmt.Sprintf("evmclient.Client#%s RPC call success", callName), results...) } else { promEVMPoolRPCNodeCallsFailed.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Debugw( + slggr.Debugw( fmt.Sprintf("evmclient.Client#%s RPC call failure", callName), append(results, "err", err)..., ) @@ -1062,7 +1057,7 @@ func (n *node) wrapHTTP(err error) error { if err != nil { n.rpcLog.Debugw("Call failed", "err", err) } else { - logger.Trace(n.rpcLog, "Call succeeded") + n.rpcLog.Trace("Call succeeded") } return err } diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index 4e984de00f..f2232a1493 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -92,9 +92,8 @@ func (n *node) aliveLoop() { pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() pollInterval := n.nodePoolCfg.PollInterval() - lggr := logger.Named(n.lfcLog, "Alive") - lggr = logger.With(lggr, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) - logger.Tracew(lggr, "Alive loop starting", "nodeState", n.State()) + lggr := logger.Sugared(n.lfcLog).Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) + lggr.Tracew("Alive loop starting", "nodeState", n.State()) headsC := make(chan *evmtypes.Head) sub, err := n.EthSubscribe(n.nodeCtx, headsC, "newHeads") @@ -143,7 +142,7 @@ func (n *node) aliveLoop() { case <-pollCh: var version string promEVMPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) ctx, cancel := context.WithTimeout(n.nodeCtx, pollInterval) ctx, cancel2 := n.makeQueryCtx(ctx) err := n.CallContext(ctx, &version, "web3_clientVersion") @@ -165,7 +164,7 @@ func (n *node) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) continue } } @@ -177,7 +176,7 @@ func (n *node) aliveLoop() { // note: there must be another live node for us to be out of sync lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) if liveNodes < 2 { - logger.Criticalf(lggr, "RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) continue } n.declareOutOfSync(n.isOutOfSync) @@ -190,13 +189,13 @@ func (n *node) aliveLoop() { return } promEVMPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Got head", "head", bh) + lggr.Tracew("Got head", "head", bh) if bh.Number > highestReceivedBlockNumber { promEVMPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.Number)) - logger.Tracew(lggr, "Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) + lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) highestReceivedBlockNumber = bh.Number } else { - logger.Tracew(lggr, "Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) + lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) } if outOfSyncT != nil { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) @@ -212,7 +211,7 @@ func (n *node) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) @@ -278,7 +277,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { outOfSyncAt := time.Now() - lggr := logger.Named(n.lfcLog, "OutOfSync") + lggr := logger.Sugared(logger.Named(n.lfcLog, "OutOfSync")) lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) // Need to redial since out-of-sync nodes are automatically disconnected @@ -295,7 +294,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { return } - logger.Tracew(lggr, "Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) + lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) ch := make(chan *evmtypes.Head) subCtx, cancel := n.makeQueryCtx(n.nodeCtx) @@ -330,7 +329,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { - logger.Critical(lggr, "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") + lggr.Critical("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") n.declareInSync() return } @@ -360,7 +359,7 @@ func (n *node) unreachableLoop() { unreachableAt := time.Now() - lggr := logger.Named(n.lfcLog, "Unreachable") + lggr := logger.Sugared(logger.Named(n.lfcLog, "Unreachable")) lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) dialRetryBackoff := utils.NewRedialBackoff() @@ -370,7 +369,7 @@ func (n *node) unreachableLoop() { case <-n.nodeCtx.Done(): return case <-time.After(dialRetryBackoff.Duration()): - logger.Tracew(lggr, "Trying to re-dial RPC node", "nodeState", n.State()) + lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) err := n.dial(n.nodeCtx) if err != nil { diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index afe592533c..b2d5a4847a 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -68,7 +68,7 @@ type Pool struct { sendonlys []SendOnlyNode chainID *big.Int chainType config.ChainType - logger logger.Logger + logger logger.SugaredLogger selectionMode string noNewHeadsThreshold time.Duration nodeSelector NodeSelector @@ -113,7 +113,7 @@ func NewPool(lggr logger.Logger, selectionMode string, leaseDuration time.Durati sendonlys: sendonlys, chainID: chainID, chainType: chainType, - logger: lggr, + logger: logger.Sugared(lggr), selectionMode: selectionMode, noNewHeadsThreshold: noNewHeadsTreshold, nodeSelector: nodeSelector, @@ -272,10 +272,10 @@ func (p *Pool) report() { } live := total - dead - logger.Tracew(p.logger, fmt.Sprintf("Pool state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + p.logger.Tracew(fmt.Sprintf("Pool state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) if total == dead { rerr := fmt.Errorf("no EVM primary nodes available: 0/%d nodes are alive", total) - logger.Criticalw(p.logger, rerr.Error(), "nodeStates", nodeStates) + p.logger.Criticalw(rerr.Error(), "nodeStates", nodeStates) p.SvcErrBuffer.Append(rerr) } else if dead > 0 { p.logger.Errorw(fmt.Sprintf("At least one EVM primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) @@ -320,7 +320,7 @@ func (p *Pool) selectNode() (node Node) { p.activeNode = p.nodeSelector.Select() if p.activeNode == nil { - logger.Criticalw(p.logger, "No live RPC nodes available", "NodeSelectionMode", p.nodeSelector.Name()) + p.logger.Criticalw("No live RPC nodes available", "NodeSelectionMode", p.nodeSelector.Name()) errmsg := fmt.Errorf("no live nodes available for chain %s", p.chainID.String()) p.SvcErrBuffer.Append(errmsg) return &erroringNode{errMsg: errmsg.Error()} @@ -367,7 +367,7 @@ func (p *Pool) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) error if err != nil { p.logger.Debugw("Secondary node BatchCallContext failed", "err", err) } else { - logger.Trace(p.logger, "Secondary node BatchCallContext success") + p.logger.Trace("Secondary node BatchCallContext success") } }(n) } diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index 3cc90c4d8d..627a283310 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -55,7 +55,7 @@ type RPCCLient interface { } type rpcClient struct { - rpcLog logger.Logger + rpcLog logger.SugaredLogger name string id int32 chainID *big.Int @@ -106,7 +106,7 @@ func NewRPCClient( "client", r.String(), "evmChainID", chainID, ) - r.rpcLog = logger.Named(lggr, "RPC") + r.rpcLog = logger.Sugared(lggr).Named("RPC") return r } @@ -117,9 +117,9 @@ func (r *rpcClient) Dial(callerCtx context.Context) error { defer cancel() promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() - lggr := logger.With(r.rpcLog, "wsuri", r.ws.uri.Redacted()) + lggr := r.rpcLog.With("wsuri", r.ws.uri.Redacted()) if r.http != nil { - lggr = logger.With(lggr, "httpuri", r.http.uri.Redacted()) + lggr = lggr.With("httpuri", r.http.uri.Redacted()) } lggr.Debugw("RPC dial: evmclient.Client#dial") @@ -148,7 +148,7 @@ func (r *rpcClient) Dial(callerCtx context.Context) error { // It can only return error if the URL is malformed. func (r *rpcClient) DialHTTP() error { promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() - lggr := logger.With(r.rpcLog, "httpuri", r.ws.uri.Redacted()) + lggr := r.rpcLog.With("httpuri", r.ws.uri.Redacted()) lggr.Debugw("RPC dial: evmclient.Client#dial") var httprpc *rpc.Client @@ -206,10 +206,7 @@ func (r *rpcClient) logResult( promEVMPoolRPCNodeCalls.WithLabelValues(r.chainID.String(), r.name).Inc() if err == nil { promEVMPoolRPCNodeCallsSuccess.WithLabelValues(r.chainID.String(), r.name).Inc() - logger.Tracew(lggr, - fmt.Sprintf("evmclient.Client#%s RPC call success", callName), - results..., - ) + logger.Sugared(lggr).Tracew(fmt.Sprintf("evmclient.Client#%s RPC call success", callName), results...) } else { promEVMPoolRPCNodeCallsFailed.WithLabelValues(r.chainID.String(), r.name).Inc() lggr.Debugw( @@ -299,7 +296,7 @@ func (r *rpcClient) CallContext(ctx context.Context, result interface{}, method return err } defer cancel() - lggr := logger.With(r.newRqLggr(), + lggr := r.newRqLggr().With( "method", method, "args", args, ) @@ -328,9 +325,9 @@ func (r *rpcClient) BatchCallContext(ctx context.Context, b []any) error { batch[i] = arg.(rpc.BatchElem) } defer cancel() - lggr := logger.With(r.newRqLggr(), "nBatchElems", len(b), "batchElems", b) + lggr := r.newRqLggr().With("nBatchElems", len(b), "batchElems", b) - logger.Trace(lggr, "RPC call: evmclient.Client#BatchCallContext") + lggr.Trace("RPC call: evmclient.Client#BatchCallContext") start := time.Now() if http != nil { err = r.wrapHTTP(http.rpc.BatchCallContext(ctx, batch)) @@ -350,7 +347,7 @@ func (r *rpcClient) Subscribe(ctx context.Context, channel chan<- *evmtypes.Head return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "args", args) + lggr := r.newRqLggr().With("args", args) lggr.Debug("RPC call: evmclient.Client#EthSubscribe") start := time.Now() @@ -385,7 +382,7 @@ func (r *rpcClient) TransactionReceiptGeth(ctx context.Context, txHash common.Ha return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "txHash", txHash) + lggr := r.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionReceipt") @@ -411,7 +408,7 @@ func (r *rpcClient) TransactionByHash(ctx context.Context, txHash common.Hash) ( return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "txHash", txHash) + lggr := r.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionByHash") @@ -438,7 +435,7 @@ func (r *rpcClient) HeaderByNumber(ctx context.Context, number *big.Int) (header return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "number", number) + lggr := r.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#HeaderByNumber") start := time.Now() @@ -462,7 +459,7 @@ func (r *rpcClient) HeaderByHash(ctx context.Context, hash common.Hash) (header return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "hash", hash) + lggr := r.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#HeaderByHash") start := time.Now() @@ -515,7 +512,7 @@ func (r *rpcClient) BlockByHashGeth(ctx context.Context, hash common.Hash) (bloc return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "hash", hash) + lggr := r.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#BlockByHash") start := time.Now() @@ -541,7 +538,7 @@ func (r *rpcClient) BlockByNumberGeth(ctx context.Context, number *big.Int) (blo return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "number", number) + lggr := r.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#BlockByNumber") start := time.Now() @@ -567,7 +564,7 @@ func (r *rpcClient) SendTransaction(ctx context.Context, tx *types.Transaction) return err } defer cancel() - lggr := logger.With(r.newRqLggr(), "tx", tx) + lggr := r.newRqLggr().With("tx", tx) lggr.Debug("RPC call: evmclient.Client#SendTransaction") start := time.Now() @@ -607,7 +604,7 @@ func (r *rpcClient) PendingSequenceAt(ctx context.Context, account common.Addres return 0, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account) + lggr := r.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingNonceAt") start := time.Now() @@ -639,7 +636,7 @@ func (r *rpcClient) SequenceAt(ctx context.Context, account common.Address, bloc return 0, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#NonceAt") start := time.Now() @@ -668,7 +665,7 @@ func (r *rpcClient) PendingCodeAt(ctx context.Context, account common.Address) ( return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account) + lggr := r.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingCodeAt") start := time.Now() @@ -694,7 +691,7 @@ func (r *rpcClient) CodeAt(ctx context.Context, account common.Address, blockNum return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CodeAt") start := time.Now() @@ -721,7 +718,7 @@ func (r *rpcClient) EstimateGas(ctx context.Context, c interface{}) (gas uint64, } defer cancel() call := c.(ethereum.CallMsg) - lggr := logger.With(r.newRqLggr(), "call", call) + lggr := r.newRqLggr().With("call", call) lggr.Debug("RPC call: evmclient.Client#EstimateGas") start := time.Now() @@ -773,7 +770,7 @@ func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumb return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "callMsg", msg, "blockNumber", blockNumber) + lggr := r.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber) message := msg.(ethereum.CallMsg) lggr.Debug("RPC call: evmclient.Client#CallContract") @@ -833,7 +830,7 @@ func (r *rpcClient) BalanceAt(ctx context.Context, account common.Address, block return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account.Hex(), "blockNumber", blockNumber) + lggr := r.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#BalanceAt") start := time.Now() @@ -892,7 +889,7 @@ func (r *rpcClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l [ return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "q", q) + lggr := r.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#FilterLogs") start := time.Now() @@ -923,7 +920,7 @@ func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQu return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "q", q) + lggr := r.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") start := time.Now() @@ -983,10 +980,8 @@ func (r *rpcClient) ChainID(ctx context.Context) (chainID *big.Int, err error) { } // newRqLggr generates a new logger with a unique request ID -func (r *rpcClient) newRqLggr() logger.Logger { - return logger.With(r.rpcLog, - "requestID", uuid.New(), - ) +func (r *rpcClient) newRqLggr() logger.SugaredLogger { + return r.rpcLog.With("requestID", uuid.New()) } func wrapCallError(err error, tp string) error { @@ -1009,7 +1004,7 @@ func (r *rpcClient) wrapHTTP(err error) error { if err != nil { r.rpcLog.Debugw("Call failed", "err", err) } else { - logger.Trace(r.rpcLog, "Call succeeded") + r.rpcLog.Trace("Call succeeded") } return err } diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 844b9e547f..dc95240fd4 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -198,7 +198,7 @@ func (b *BlockHistoryEstimator) getBlocks() []evmtypes.Block { // The provided context can be used to terminate Start sequence. func (b *BlockHistoryEstimator) Start(ctx context.Context) error { return b.StartOnce("BlockHistoryEstimator", func() error { - logger.Trace(b.logger, "Starting") + b.logger.Trace("Starting") if b.bhConfig.CheckInclusionBlocks() > 0 { b.logger.Infof("Inclusion checking enabled, bumping will be prevented on transactions that have been priced above the %d percentile for %d blocks", b.bhConfig.CheckInclusionPercentile(), b.bhConfig.CheckInclusionBlocks()) @@ -228,7 +228,7 @@ func (b *BlockHistoryEstimator) Start(ctx context.Context) error { b.wg.Add(1) go b.runLoop() - logger.Trace(b.logger, "Started") + b.logger.Trace("Started") return nil }) } @@ -291,7 +291,7 @@ func (b *BlockHistoryEstimator) BumpLegacyGas(_ context.Context, originalGasPric if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { if errors.Is(err, commonfee.ErrConnectivity) { - logger.Criticalw(b.logger, BumpingHaltedLabel, "err", err) + b.logger.Criticalw(BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "legacy").Inc() } @@ -467,7 +467,7 @@ func (b *BlockHistoryEstimator) BumpDynamicFee(_ context.Context, originalFee Dy if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { if errors.Is(err, commonfee.ErrConnectivity) { - logger.Criticalw(b.logger, BumpingHaltedLabel, "err", err) + b.logger.Criticalw(BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "eip1559").Inc() } @@ -508,7 +508,7 @@ func (b *BlockHistoryEstimator) FetchBlocksAndRecalculate(ctx context.Context, h func (b *BlockHistoryEstimator) Recalculate(head *evmtypes.Head) { percentile := int(b.bhConfig.TransactionPercentile()) - lggr := logger.With(b.logger, "head", head) + lggr := b.logger.With("head", head) blockHistory := b.getBlocks() if len(blockHistory) == 0 { @@ -630,9 +630,9 @@ func (b *BlockHistoryEstimator) FetchBlocks(ctx context.Context, head *evmtypes. reqs = append(reqs, req) } - lggr := logger.With(b.logger, "head", head) + lggr := b.logger.With("head", head) - logger.Tracew(lggr, fmt.Sprintf("Fetching %v blocks (%v in local history)", len(reqs), len(blocks)), "n", len(reqs), "inHistory", len(blocks), "blockNum", head.Number) + lggr.Tracew(fmt.Sprintf("Fetching %v blocks (%v in local history)", len(reqs), len(blocks)), "n", len(reqs), "inHistory", len(blocks), "blockNum", head.Number) if err := b.batchFetch(ctx, reqs); err != nil { return err } @@ -713,7 +713,7 @@ func (b *BlockHistoryEstimator) batchFetch(ctx context.Context, reqs []rpc.Batch j = len(reqs) } - logger.Tracew(b.logger, fmt.Sprintf("Batch fetching blocks %v thru %v", HexToInt64(reqs[i].Args[0]), HexToInt64(reqs[j-1].Args[0]))) + b.logger.Tracew(fmt.Sprintf("Batch fetching blocks %v thru %v", HexToInt64(reqs[i].Args[0]), HexToInt64(reqs[j-1].Args[0]))) err := b.ethClient.BatchCallContext(ctx, reqs[i:j]) if errors.Is(err, context.DeadlineExceeded) { diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index 6a384fa9c5..ce1a50aa32 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -31,7 +31,7 @@ type l1GasPriceOracle struct { services.StateMachine client ethClient pollPeriod time.Duration - logger logger.Logger + logger logger.SugaredLogger address string callArgs string @@ -94,7 +94,7 @@ func NewL1GasPriceOracle(lggr logger.Logger, ethClient ethClient, chainType conf return &l1GasPriceOracle{ client: ethClient, pollPeriod: PollPeriod, - logger: logger.Named(lggr, fmt.Sprintf("L1GasPriceOracle(%s)", chainType)), + logger: logger.Sugared(logger.Named(lggr, fmt.Sprintf("L1GasPriceOracle(%s)", chainType))), address: address, callArgs: callArgs, chInitialised: make(chan struct{}), @@ -159,7 +159,7 @@ func (o *l1GasPriceOracle) refresh() (t *time.Timer) { } if len(b) != 32 { // returns uint256; - logger.Criticalf(o.logger, "return data length (%d) different than expected (%d)", len(b), 32) + o.logger.Criticalf("return data length (%d) different than expected (%d)", len(b), 32) return } price := new(big.Int).SetBytes(b) diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index 13dfe1ffab..cea2e36118 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -241,7 +241,7 @@ func (rec *received) logsOnBlocks() []logOnBlock { type simpleLogListener struct { name string - lggr logger.Logger + lggr logger.SugaredLogger cfg pg.QConfig received *received t *testing.T @@ -266,7 +266,7 @@ func (helper *broadcasterHelper) newLogListenerWithJob(name string) *simpleLogLi var rec received return &simpleLogListener{ db: db, - lggr: logger.Test(t), + lggr: logger.Sugared(logger.Test(t)), cfg: helper.config.Database(), name: name, received: &rec, @@ -282,7 +282,7 @@ func (listener *simpleLogListener) SkipMarkingConsumed(skip bool) { func (listener *simpleLogListener) HandleLog(lb log.Broadcast) { listener.received.Lock() defer listener.received.Unlock() - logger.Tracef(listener.lggr, "Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) + listener.lggr.Tracef("Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) listener.received.logs = append(listener.received.logs, lb.RawLog()) listener.received.broadcasts = append(listener.received.broadcasts, lb) diff --git a/core/chains/evm/log/registrations.go b/core/chains/evm/log/registrations.go index 73f197a6ab..346a6776e8 100644 --- a/core/chains/evm/log/registrations.go +++ b/core/chains/evm/log/registrations.go @@ -46,7 +46,7 @@ type ( // handlersByConfs maps numConfirmations => *handler handlersByConfs map[uint32]*handler - logger logger.Logger + logger logger.SugaredLogger evmChainID big.Int // highest 'NumConfirmations' per all listeners, used to decide about deleting older logs if it's higher than EvmFinalityDepth @@ -57,7 +57,7 @@ type ( handler struct { lookupSubs map[common.Address]map[common.Hash]subscribers // contractAddress => logTopic => *subscriber => topicValueFilters evmChainID big.Int - logger logger.Logger + logger logger.SugaredLogger } // The Listener responds to log events through HandleLog. @@ -76,7 +76,7 @@ func newRegistrations(lggr logger.Logger, evmChainID big.Int) *registrations { jobIDAddrs: make(map[int32]map[common.Address]struct{}), handlersByConfs: make(map[uint32]*handler), evmChainID: evmChainID, - logger: logger.Named(lggr, "Registrations"), + logger: logger.Sugared(logger.Named(lggr, "Registrations")), } } @@ -85,7 +85,7 @@ func (r *registrations) addSubscriber(sub *subscriber) (needsResubscribe bool) { r.logger.Panicw(err.Error(), "err", err, "addr", sub.opts.Contract.Hex(), "jobID", sub.listener.JobID()) } - logger.Tracef(r.logger, "Added subscription %p with job ID %v", sub, sub.listener.JobID()) + r.logger.Tracef("Added subscription %p with job ID %v", sub, sub.listener.JobID()) handler, exists := r.handlersByConfs[sub.opts.MinIncomingConfirmations] if !exists { @@ -142,7 +142,7 @@ func (r *registrations) removeSubscriber(sub *subscriber) (needsResubscribe bool if err := r.checkRemoveSubscriber(sub); err != nil { r.logger.Panicw(err.Error(), "err", err, "addr", sub.opts.Contract.Hex(), "jobID", sub.listener.JobID()) } - logger.Tracef(r.logger, "Removed subscription %p with job ID %v", sub, sub.listener.JobID()) + r.logger.Tracef("Removed subscription %p with job ID %v", sub, sub.listener.JobID()) handlers, exists := r.handlersByConfs[sub.opts.MinIncomingConfirmations] if !exists { @@ -263,7 +263,7 @@ func filtersContainValues(topicValues []common.Hash, filters [][]Topic) bool { return true } -func newHandler(lggr logger.Logger, evmChainID big.Int) *handler { +func newHandler(lggr logger.SugaredLogger, evmChainID big.Int) *handler { return &handler{ lookupSubs: make(map[common.Address]map[common.Hash]subscribers), evmChainID: evmChainID, @@ -284,7 +284,7 @@ func (r *handler) addSubscriber(sub *subscriber, handlersWithGreaterConfs []*han for topic, topicValueFilters := range sub.opts.LogsWithTopics { if _, exists := r.lookupSubs[addr][topic]; !exists { - logger.Tracef(r.logger, "No existing sub for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("No existing sub for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) r.lookupSubs[addr][topic] = make(subscribers) func() { @@ -295,11 +295,11 @@ func (r *handler) addSubscriber(sub *subscriber, handlersWithGreaterConfs []*han // again since even the worst case lookback is already covered for _, existingHandler := range handlersWithGreaterConfs { if _, exists := existingHandler.lookupSubs[addr][topic]; exists { - logger.Tracef(r.logger, "Sub already exists for addr %s and topic %s at greater than this MinIncomingConfirmations of %v. Resubscribe is not required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("Sub already exists for addr %s and topic %s at greater than this MinIncomingConfirmations of %v. Resubscribe is not required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) return } } - logger.Tracef(r.logger, "No sub exists for addr %s and topic %s at this or greater MinIncomingConfirmations of %v. Resubscribe is required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("No sub exists for addr %s and topic %s at this or greater MinIncomingConfirmations of %v. Resubscribe is required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) needsResubscribe = true } }() @@ -332,7 +332,7 @@ func (r *handler) removeSubscriber(sub *subscriber, allHandlers map[uint32]*hand // cleanup and resubscribe if necessary if len(topicMap) == 0 { - logger.Tracef(r.logger, "No subs left for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("No subs left for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) func() { if !needsResubscribe { @@ -344,12 +344,12 @@ func (r *handler) removeSubscriber(sub *subscriber, allHandlers map[uint32]*hand continue } if _, exists := otherHandler.lookupSubs[addr][topic]; exists { - logger.Tracef(r.logger, "Sub still exists for addr %s and topic %s. Resubscribe will not be performed", addr.Hex(), topic.Hex()) + r.logger.Tracef("Sub still exists for addr %s and topic %s. Resubscribe will not be performed", addr.Hex(), topic.Hex()) return } } - logger.Tracef(r.logger, "No sub exists for addr %s and topic %s. Resubscribe will be performed", addr.Hex(), topic.Hex()) + r.logger.Tracef("No sub exists for addr %s and topic %s. Resubscribe will be performed", addr.Hex(), topic.Hex()) needsResubscribe = true } }() diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 991cc8d430..7bc131afef 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -98,7 +98,7 @@ type logPoller struct { services.StateMachine ec Client orm ORM - lggr logger.Logger + lggr logger.SugaredLogger pollPeriod time.Duration // poll period set by block production rate useFinalityTag bool // indicates whether logPoller should use chain's finality or pick a fixed depth for finality finalityDepth int64 // finality depth is taken to mean that block (head - finality) is finalized. If `useFinalityTag` is set to true, this value is ignored, because finalityDepth is fetched from chain @@ -138,7 +138,7 @@ func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, pollPeriod time.Durati cancel: cancel, ec: ec, orm: orm, - lggr: logger.Named(lggr, "LogPoller"), + lggr: logger.Sugared(logger.Named(lggr, "LogPoller")), replayStart: make(chan int64), replayComplete: make(chan error), pollPeriod: pollPeriod, @@ -666,7 +666,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } } if batchSize == 1 { - logger.Criticalw(lp.lggr, "Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) + lp.lggr.Criticalw("Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) return err } batchSize /= 2 @@ -921,7 +921,7 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He return nil, err } } - logger.Criticalw(lp.lggr, "Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) + lp.lggr.Criticalw("Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) rerr := errors.New("Reorg greater than finality depth") lp.SvcErrBuffer.Append(rerr) return nil, rerr diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index f676d3d18e..68a81299bf 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -2033,7 +2033,7 @@ type testChecker struct { func (t *testChecker) Check( _ context.Context, - _ logger.Logger, + _ logger.SugaredLogger, _ txmgr.Tx, _ txmgr.TxAttempt, ) error { diff --git a/core/chains/evm/txmgr/client.go b/core/chains/evm/txmgr/client.go index d08274f74b..dc7b62647c 100644 --- a/core/chains/evm/txmgr/client.go +++ b/core/chains/evm/txmgr/client.go @@ -43,7 +43,7 @@ func (c *evmTxmClient) BatchSendTransactions( ctx context.Context, attempts []TxAttempt, batchSize int, - lggr logger.Logger, + lggr logger.SugaredLogger, ) ( codes []commonclient.SendTxReturnCode, txErrs []error, @@ -62,7 +62,7 @@ func (c *evmTxmClient) BatchSendTransactions( if len(reqs) != len(attempts) { lenErr := fmt.Errorf("Returned request data length (%d) != number of tx attempts (%d)", len(reqs), len(attempts)) err = errors.Join(err, lenErr) - logger.Criticalw(lggr, "Mismatched length", "err", err) + lggr.Criticalw("Mismatched length", "err", err) return } @@ -88,10 +88,10 @@ func (c *evmTxmClient) BatchSendTransactions( return } -func (c *evmTxmClient) SendTransactionReturnCode(ctx context.Context, etx Tx, attempt TxAttempt, lggr logger.Logger) (commonclient.SendTxReturnCode, error) { +func (c *evmTxmClient) SendTransactionReturnCode(ctx context.Context, etx Tx, attempt TxAttempt, lggr logger.SugaredLogger) (commonclient.SendTxReturnCode, error) { signedTx, err := GetGethSignedTx(attempt.SignedRawTx) if err != nil { - logger.Criticalw(lggr, "Fatal error signing transaction", "err", err, "etx", etx) + lggr.Criticalw("Fatal error signing transaction", "err", err, "etx", etx) return commonclient.Fatal, err } return c.client.SendTransactionReturnCode(ctx, signedTx, etx.FromAddress) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index bb2a30e51d..f901416367 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -75,7 +75,7 @@ type TestEvmTxStore interface { type evmTxStore struct { q pg.Q - logger logger.Logger + logger logger.SugaredLogger ctx context.Context ctxCancel context.CancelFunc } @@ -340,7 +340,7 @@ func NewTxStore( q := pg.NewQ(db, namedLogger, cfg, pg.WithParentCtx(ctx)) return &evmTxStore{ q: q, - logger: namedLogger, + logger: logger.Sugared(namedLogger), ctx: ctx, ctxCancel: cancel, } @@ -1499,7 +1499,7 @@ GROUP BY e.id txHashesHex[i] = common.BytesToAddress(r.TxHashes[i]) } - logger.Criticalw(o.logger, fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ + o.logger.Criticalw(fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ "Current block height is %v, transaction was broadcast before block height %v. This transaction may not have not been sent and will be marked as fatally errored. "+ "This can happen if there is another instance of chainlink running that is using the same private key, or if "+ "an external wallet has been used to send a transaction from account %s with nonce %v."+ diff --git a/core/chains/evm/txmgr/transmitchecker.go b/core/chains/evm/txmgr/transmitchecker.go index 76dfcb9d51..919fb509fe 100644 --- a/core/chains/evm/txmgr/transmitchecker.go +++ b/core/chains/evm/txmgr/transmitchecker.go @@ -110,7 +110,7 @@ type noChecker struct{} // Check satisfies the TransmitChecker interface. func (noChecker) Check( _ context.Context, - _ logger.Logger, + _ logger.SugaredLogger, _ Tx, _ TxAttempt, ) error { @@ -125,7 +125,7 @@ type SimulateChecker struct { // Check satisfies the TransmitChecker interface. func (s *SimulateChecker) Check( ctx context.Context, - l logger.Logger, + l logger.SugaredLogger, tx Tx, a TxAttempt, ) error { @@ -148,7 +148,7 @@ func (s *SimulateChecker) Check( err := s.Client.CallContext(ctx, &b, "eth_call", callArg, evmclient.ToBlockNumArg(nil)) if err != nil { if jErr := evmclient.ExtractRPCErrorOrNil(err); jErr != nil { - logger.Criticalw(l, "Transaction reverted during simulation", + l.Criticalw("Transaction reverted during simulation", "ethTxAttemptID", a.ID, "txHash", a.Hash, "err", err, "rpcErr", jErr.String(), "returnValue", b.String()) return errors.Errorf("transaction reverted during simulation: %s", jErr.String()) } @@ -175,7 +175,7 @@ type VRFV1Checker struct { // Check satisfies the TransmitChecker interface. func (v *VRFV1Checker) Check( ctx context.Context, - l logger.Logger, + l logger.SugaredLogger, tx Tx, _ TxAttempt, ) error { @@ -284,7 +284,7 @@ type VRFV2Checker struct { // Check satisfies the TransmitChecker interface. func (v *VRFV2Checker) Check( ctx context.Context, - l logger.Logger, + l logger.SugaredLogger, tx Tx, _ TxAttempt, ) error { diff --git a/core/chains/evm/txmgr/transmitchecker_test.go b/core/chains/evm/txmgr/transmitchecker_test.go index 6dd4edd91c..d2f668da11 100644 --- a/core/chains/evm/txmgr/transmitchecker_test.go +++ b/core/chains/evm/txmgr/transmitchecker_test.go @@ -106,7 +106,7 @@ func TestFactory(t *testing.T) { func TestTransmitCheckers(t *testing.T) { client := evmtest.NewEthClientMockWithDefaultChain(t) - log := logger.Test(t) + log := logger.Sugared(logger.Test(t)) ctx := testutils.Context(t) t.Run("no checker", func(t *testing.T) { diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c532759627..db71535723 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -237,7 +237,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad // indirect + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 28750a076d..1c48074ea3 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1148,8 +1148,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad h1:ysPjfbCPJuVxxFZa1Ifv8OPE20pzvnEHjJrPDUo4gT0= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 h1:lSYiaiIfAA+5ac45/UD8ciytlNw/S6fnhK7bxFHYI88= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= diff --git a/core/services/pg/q.go b/core/services/pg/q.go index 050606c793..e69e16ec48 100644 --- a/core/services/pg/q.go +++ b/core/services/pg/q.go @@ -118,7 +118,7 @@ type Q struct { Queryer ParentCtx context.Context db *sqlx.DB - logger logger.Logger + logger logger.SugaredLogger config QConfig QueryTimeout time.Duration } @@ -130,7 +130,7 @@ func NewQ(db *sqlx.DB, lggr logger.Logger, config QConfig, qopts ...QOpt) (q Q) q.db = db // skip two levels since we use internal helpers and also want to point up the stack to the caller of the Q method. - q.logger = logger.Helper(lggr, 2) + q.logger = logger.Sugared(logger.Helper(lggr, 2)) q.config = config if q.Queryer == nil { @@ -356,7 +356,7 @@ func (q *queryLogger) postSqlLog(ctx context.Context, begin time.Time) { kvs := []any{"ms", elapsed.Milliseconds(), "timeout", timeout.Milliseconds(), "percent", strconv.FormatFloat(pct, 'f', 1, 64), "sql", q} if elapsed >= timeout { - logger.Criticalw(q.logger, "SLOW SQL QUERY", kvs...) + q.logger.Criticalw("SLOW SQL QUERY", kvs...) } else if errThreshold := timeout / 5; errThreshold > 0 && elapsed > errThreshold { q.logger.Errorw("SLOW SQL QUERY", kvs...) } else if warnThreshold := timeout / 10; warnThreshold > 0 && elapsed > warnThreshold { diff --git a/go.mod b/go.mod index e7b93c40bd..c71705d9c9 100644 --- a/go.mod +++ b/go.mod @@ -65,7 +65,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d diff --git a/go.sum b/go.sum index e9a7f0267a..b38b7ac263 100644 --- a/go.sum +++ b/go.sum @@ -1134,8 +1134,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad h1:ysPjfbCPJuVxxFZa1Ifv8OPE20pzvnEHjJrPDUo4gT0= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 h1:lSYiaiIfAA+5ac45/UD8ciytlNw/S6fnhK7bxFHYI88= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 84da65e9a5..9f0ff1b384 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad + github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 github.com/smartcontractkit/chainlink-testing-framework v1.22.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 854978e335..f8a9529a4c 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1411,7 +1411,6 @@ github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMT github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= -github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= @@ -1433,8 +1432,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-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad h1:ysPjfbCPJuVxxFZa1Ifv8OPE20pzvnEHjJrPDUo4gT0= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231206181640-faad3f11cfad/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 h1:lSYiaiIfAA+5ac45/UD8ciytlNw/S6fnhK7bxFHYI88= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= From 7cb552e9dfd7c344bfd3c180bb3253a486ad7b91 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Wed, 13 Dec 2023 21:02:27 +0200 Subject: [PATCH 313/327] =?UTF-8?q?VRF-798:=20fix=20"nonce=20too=20low"=20?= =?UTF-8?q?in=20load=20test=20setup=20when=20creating=20a=20subsc=E2=80=A6?= =?UTF-8?q?=20(#11560)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-798: fix "nonce too low" in load test setup when creating a subscription * VRF-798: fix runtime issue * VRF-798: PR comments --- integration-tests/load/vrfv2/vrfv2_test.go | 6 ++++++ .../load/vrfv2plus/vrfv2plus_test.go | 15 +++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 86f9b8d61f..ec0f945870 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -115,6 +115,12 @@ func TestVRFV2Performance(t *testing.T) { require.NoError(t, err) consumers, err = vrfv2_actions.DeployVRFV2Consumers(env.ContractDeployer, coordinator, 1) require.NoError(t, err) + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2_actions.ErrWaitTXsComplete) + l.Info(). + Str("Coordinator", cfg.ExistingEnvConfig.CoordinatorAddress). + Int("Number of Subs to create", vrfv2Config.NumberOfSubToCreate). + Msg("Creating and funding subscriptions, deploying and adding consumers to subs") subIDs, err = vrfv2_actions.CreateFundSubsAndAddConsumers( env, vrfv2Config, diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 6fe0d06e7d..6d298e075f 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" "github.com/rs/zerolog" @@ -117,6 +116,12 @@ func TestVRFV2PlusPerformance(t *testing.T) { require.NoError(t, err) consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) require.NoError(t, err) + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + l.Info(). + Str("Coordinator", cfg.ExistingEnvConfig.CoordinatorAddress). + Int("Number of Subs to create", vrfv2PlusConfig.NumberOfSubToCreate). + Msg("Creating and funding subscriptions, deploying and adding consumers to subs") subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers( env, vrfv2PlusConfig, @@ -308,13 +313,7 @@ func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l ze Str("Should have at least", fundingAtLeast.String()). Str("Funding Amount in ETH", fundingToSendEth.String()). Msg("Funding Node's Sending Key") - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ - To: &address, - }) - if err != nil { - return err - } - err = client.Fund(sendingKey, fundingToSendEth, gasEstimates) + err := actions.FundAddress(client, sendingKey, fundingToSendEth) if err != nil { return err } From 43e9f277d4c42b224f83870586150ff5c02a8ced Mon Sep 17 00:00:00 2001 From: Makram Date: Wed, 13 Dec 2023 22:01:04 +0200 Subject: [PATCH 314/327] feat: add liquidity balancer specs table (#11564) Add the liquidity balancer specs table. This table will be used to house the specs for the liquidity balancer job which will be implemented in ccip rather than core. The entirety of the spec's content will be in the `liquidity_balancer_config` field. This is done to minimize future migrations. This doesn't mean we won't be doing strict checks on the contents of the config during the validation process. --- core/services/job/models.go | 8 +++ .../0213_liquidity_balancer_specs.sql | 49 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 core/store/migrate/migrations/0213_liquidity_balancer_specs.sql diff --git a/core/services/job/models.go b/core/services/job/models.go index b21ecc12e7..3c869f7605 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -152,6 +152,8 @@ type Job struct { GatewaySpecID *int32 EALSpec *EALSpec EALSpecID *int32 + LiquidityBalancerSpec *LiquidityBalancerSpec + LiquidityBalancerSpecID *int32 PipelineSpecID int32 PipelineSpec *pipeline.Spec JobSpecErrors []SpecError @@ -793,3 +795,9 @@ type EALSpec struct { // UpdatedAt is the time this job was last updated. UpdatedAt time.Time `toml:"-"` } + +type LiquidityBalancerSpec struct { + ID int32 + + LiquidityBalancerConfig string `toml:"liquidityBalancerConfig" db:"liquidity_balancer_config"` +} diff --git a/core/store/migrate/migrations/0213_liquidity_balancer_specs.sql b/core/store/migrate/migrations/0213_liquidity_balancer_specs.sql new file mode 100644 index 0000000000..cd717181f5 --- /dev/null +++ b/core/store/migrate/migrations/0213_liquidity_balancer_specs.sql @@ -0,0 +1,49 @@ +-- +goose Up +CREATE TABLE liquidity_balancer_specs ( + id BIGSERIAL PRIMARY KEY, + liquidity_balancer_config JSONB NOT NULL +); + +ALTER TABLE + jobs +ADD COLUMN + liquidity_balancer_spec_id BIGINT REFERENCES liquidity_balancer_specs(id), +DROP CONSTRAINT chk_only_one_spec, +ADD CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id, + liquidity_balancer_spec_id + ) = 1 +); + +-- +goose Down +ALTER TABLE + jobs +DROP CONSTRAINT chk_only_one_spec, +ADD CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id + ) = 1 +); +ALTER TABLE + jobs +DROP COLUMN + liquidity_balancer_spec_id; +DROP TABLE + liquidity_balancer_specs; From 19c7ccac1714dae991d7b3aecc864f99d722b2d4 Mon Sep 17 00:00:00 2001 From: Lei Date: Wed, 13 Dec 2023 12:07:31 -0800 Subject: [PATCH 315/327] Auto 8087 modular streams (#11489) * make streams lookup modular * polish * address comment to use pointer instead of array/map * rebase * get rid of slice * keep using array and index * remove duplicate logging * address err re-declarion lint issues --- core/scripts/chaincli/handler/debug.go | 223 +++++--- .../handler/mercury_lookup_handler.go | 536 ------------------ core/scripts/go.mod | 3 +- core/scripts/go.sum | 2 - .../v21/mercury/streams/streams.go | 105 ++-- .../v21/mercury/streams/streams_test.go | 20 +- 6 files changed, 222 insertions(+), 667 deletions(-) delete mode 100644 core/scripts/chaincli/handler/mercury_lookup_handler.go diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 5947337b18..815a0c9a03 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -18,13 +18,19 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" @@ -35,12 +41,7 @@ import ( const ( ConditionTrigger uint8 = iota LogTrigger - - blockNumber = "blockNumber" expectedTypeAndVersion = "KeeperRegistry 2.1.0" - feedIdHex = "feedIdHex" - feedIDs = "feedIDs" - timestamp = "timestamp" ) var packer = encoding.NewAbiPacker() @@ -51,24 +52,29 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if len(args) < 1 { failCheckArgs("no upkeepID supplied", nil) } + // test that we are connected to an archive node _, err := k.client.BalanceAt(ctx, gethcommon.Address{}, big.NewInt(1)) if err != nil { failCheckConfig("you are not connected to an archive node; try using infura or alchemy", err) } + chainIDBig, err := k.client.ChainID(ctx) if err != nil { failUnknown("unable to retrieve chainID from rpc client", err) } chainID := chainIDBig.Int64() + + var triggerCallOpts *bind.CallOpts // use latest block for conditionals, but use block from tx for log triggers + latestCallOpts := &bind.CallOpts{Context: ctx} // always use latest block + // connect to registry contract - latestCallOpts := &bind.CallOpts{Context: ctx} // always use latest block - triggerCallOpts := &bind.CallOpts{Context: ctx} // use latest block for conditionals, but use block from tx for log triggers registryAddress := gethcommon.HexToAddress(k.cfg.RegistryAddress) keeperRegistry21, err := iregistry21.NewIKeeperRegistryMaster(registryAddress, k.client) if err != nil { failUnknown("failed to connect to registry contract", err) } + // verify contract is correct typeAndVersion, err := keeperRegistry21.TypeAndVersion(latestCallOpts) if err != nil { @@ -124,17 +130,21 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { var checkResult iregistry21.CheckUpkeep var blockNum uint64 var performData []byte + var workID [32]byte + var trigger ocr2keepers.Trigger upkeepNeeded := false // check upkeep if triggerType == ConditionTrigger { message("upkeep identified as conditional trigger") - tmpCheckResult, err := keeperRegistry21.CheckUpkeep0(latestCallOpts, upkeepID) + var tmpCheckResult iregistry21.CheckUpkeep0 + tmpCheckResult, err = keeperRegistry21.CheckUpkeep0(latestCallOpts, upkeepID) if err != nil { failUnknown("failed to check upkeep: ", err) } checkResult = iregistry21.CheckUpkeep(tmpCheckResult) // do tenderly simulation - rawCall, err := core.RegistryABI.Pack("checkUpkeep", upkeepID, []byte{}) + var rawCall []byte + rawCall, err = core.RegistryABI.Pack("checkUpkeep", upkeepID, []byte{}) if err != nil { failUnknown("failed to pack raw checkUpkeep call", err) } @@ -146,19 +156,26 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { failCheckArgs("txHash and log index must be supplied to command in order to debug log triggered upkeeps", nil) } txHash := gethcommon.HexToHash(args[1]) - logIndex, err := strconv.ParseInt(args[2], 10, 64) + + var logIndex int64 + logIndex, err = strconv.ParseInt(args[2], 10, 64) if err != nil { failCheckArgs("unable to parse log index", err) } - // find transaction receipt - _, isPending, err := k.client.TransactionByHash(ctx, txHash) + + // check that tx is confirmed + var isPending bool + _, isPending, err = k.client.TransactionByHash(ctx, txHash) if err != nil { log.Fatal("failed to get tx by hash", err) } if isPending { resolveIneligible(fmt.Sprintf("tx %s is still pending confirmation", txHash)) } - receipt, err := k.client.TransactionReceipt(ctx, txHash) + + // find transaction receipt + var receipt *types.Receipt + receipt, err = k.client.TransactionReceipt(ctx, txHash) if err != nil { failCheckArgs("failed to fetch tx receipt", err) } @@ -176,9 +193,11 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } // check that tx for this upkeep / tx was not already performed message(fmt.Sprintf("LogTrigger{blockNum: %d, blockHash: %s, txHash: %s, logIndex: %d}", blockNum, receipt.BlockHash.Hex(), txHash, logIndex)) - workID := mustUpkeepWorkID(upkeepID, blockNum, receipt.BlockHash, txHash, logIndex) + trigger = mustAutomationTrigger(txHash, logIndex, blockNum, receipt.BlockHash) + workID = mustUpkeepWorkID(upkeepID, trigger) message(fmt.Sprintf("workID computed: %s", hex.EncodeToString(workID[:]))) - hasKey, err := keeperRegistry21.HasDedupKey(latestCallOpts, workID) + var hasKey bool + hasKey, err = keeperRegistry21.HasDedupKey(latestCallOpts, workID) if err != nil { failUnknown("failed to check if upkeep was already performed: ", err) } @@ -186,11 +205,13 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { resolveIneligible("upkeep was already performed") } triggerCallOpts = &bind.CallOpts{Context: ctx, BlockNumber: big.NewInt(receipt.BlockNumber.Int64())} - rawTriggerConfig, err := keeperRegistry21.GetUpkeepTriggerConfig(triggerCallOpts, upkeepID) + var rawTriggerConfig []byte + rawTriggerConfig, err = keeperRegistry21.GetUpkeepTriggerConfig(triggerCallOpts, upkeepID) if err != nil { failUnknown("failed to fetch trigger config for upkeep", err) } - triggerConfig, err := packer.UnpackLogTriggerConfig(rawTriggerConfig) + var triggerConfig automation_utils_2_1.LogTriggerConfig + triggerConfig, err = packer.UnpackLogTriggerConfig(rawTriggerConfig) if err != nil { failUnknown("failed to unpack trigger config", err) } @@ -200,11 +221,13 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if !logMatchesTriggerConfig(triggeringEvent, triggerConfig) { resolveIneligible("log does not match trigger config") } - header, err := k.client.HeaderByHash(ctx, receipt.BlockHash) + var header *types.Header + header, err = k.client.HeaderByHash(ctx, receipt.BlockHash) if err != nil { failUnknown("failed to find block", err) } - triggerData, err := packTriggerData(triggeringEvent, header.Time) + var triggerData []byte + triggerData, err = packTriggerData(triggeringEvent, header.Time) if err != nil { failUnknown("failed to pack trigger data", err) } @@ -213,7 +236,8 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { failUnknown("failed to check upkeep", err) } // do tenderly simulations - rawCall, err := core.RegistryABI.Pack("checkUpkeep", upkeepID, triggerData) + var rawCall []byte + rawCall, err = core.RegistryABI.Pack("checkUpkeep", upkeepID, triggerData) if err != nil { failUnknown("failed to pack raw checkUpkeep call", err) } @@ -228,73 +252,88 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if checkResult.UpkeepFailureReason != 0 { message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) } + if checkResult.UpkeepFailureReason == uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { - // TODO use the new streams lookup lib - //mc := &models.MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey} - //mercuryConfig := evm.NewMercuryConfig(mc, core.StreamsCompatibleABI) - //lggr, _ := logger.NewLogger() - //blockSub := &blockSubscriber{k.client} - //_ = streams.NewStreamsLookup(packer, mercuryConfig, blockSub, keeperRegistry21, k.rpcClient, lggr) - - streamsLookupErr, err := packer.DecodeStreamsLookupRequest(checkResult.PerformData) + mc := &models.MercuryCredentials{LegacyURL: k.cfg.MercuryLegacyURL, URL: k.cfg.MercuryURL, Username: k.cfg.MercuryID, Password: k.cfg.MercuryKey} + mercuryConfig := evm21.NewMercuryConfig(mc, core.StreamsCompatibleABI) + lggr, _ := logger.NewLogger() + blockSub := &blockSubscriber{k.client} + streams := streams.NewStreamsLookup(packer, mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr) + + var streamsLookupErr *mercury.StreamsLookupError + streamsLookupErr, err = packer.DecodeStreamsLookupRequest(checkResult.PerformData) if err == nil { message("upkeep reverted with StreamsLookup") message(fmt.Sprintf("StreamsLookup data: {FeedParamKey: %s, Feeds: %v, TimeParamKey: %s, Time: %d, ExtraData: %s}", streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time.Uint64(), hexutil.Encode(streamsLookupErr.ExtraData))) - if streamsLookupErr.FeedParamKey == feedIdHex && streamsLookupErr.TimeParamKey == blockNumber { + + streamsLookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: streamsLookupErr.FeedParamKey, + Feeds: streamsLookupErr.Feeds, + TimeParamKey: streamsLookupErr.TimeParamKey, + Time: streamsLookupErr.Time, + ExtraData: streamsLookupErr.ExtraData, + }, + UpkeepId: upkeepID, + Block: blockNum, + } + + if streamsLookup.IsMercuryV02() { message("using mercury lookup v0.2") - // handle v0.2 - cfg, err := keeperRegistry21.GetUpkeepPrivilegeConfig(triggerCallOpts, upkeepID) + // check if upkeep is allowed to use mercury v0.2 + var allowed bool + _, _, _, allowed, err = streams.AllowedToUseMercury(latestCallOpts, upkeepID) if err != nil { - failUnknown("failed to get upkeep privilege config ", err) - } - allowed := false - if len(cfg) > 0 { - var privilegeConfig streams.UpkeepPrivilegeConfig - if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { - failUnknown("failed to unmarshal privilege config ", err) - } - allowed = privilegeConfig.MercuryEnabled + failUnknown("failed to check if upkeep is allowed to use mercury", err) } if !allowed { resolveIneligible("upkeep reverted with StreamsLookup but is not allowed to access streams") } - } else if streamsLookupErr.FeedParamKey != feedIDs || streamsLookupErr.TimeParamKey != timestamp { + } else if streamsLookup.IsMercuryV03() { // handle v0.3 - resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") - } else { message("using mercury lookup v0.3") + } else { + resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") } - streamsLookup := &StreamsLookup{streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time, streamsLookupErr.ExtraData, upkeepID, blockNum} if k.cfg.MercuryLegacyURL == "" || k.cfg.MercuryURL == "" || k.cfg.MercuryID == "" || k.cfg.MercuryKey == "" { failCheckConfig("Mercury configs not set properly, check your MERCURY_LEGACY_URL, MERCURY_URL, MERCURY_ID and MERCURY_KEY", nil) } - handler := NewMercuryLookupHandler(&MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey}, k.rpcClient) - state, failureReason, values, _, err := handler.doMercuryRequest(ctx, streamsLookup) - if failureReason == UpkeepFailureReasonInvalidRevertDataInput { + + // do mercury request + automationCheckResult := mustAutomationCheckResult(upkeepID, checkResult, trigger) + checkResults := []ocr2keepers.CheckResult{automationCheckResult} + + var values [][]byte + values, err = streams.DoMercuryRequest(ctx, streamsLookup, checkResults, 0) + + if automationCheckResult.IneligibilityReason == uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) { resolveIneligible("upkeep used invalid revert data") } - if state == InvalidMercuryRequest { + if automationCheckResult.PipelineExecutionState == uint8(mercury.InvalidMercuryRequest) { resolveIneligible("the mercury request data is invalid") } if err != nil { failCheckConfig("failed to do mercury request ", err) } - callbackResult, err := keeperRegistry21.CheckCallback(triggerCallOpts, upkeepID, values, streamsLookup.extraData) + + // do checkCallback + err = streams.CheckCallback(ctx, values, streamsLookup, checkResults, 0) if err != nil { failUnknown("failed to execute mercury callback ", err) } - if callbackResult.UpkeepFailureReason != 0 { - message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) + if automationCheckResult.IneligibilityReason != 0 { + message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", automationCheckResult.IneligibilityReason)) } - upkeepNeeded, performData = callbackResult.UpkeepNeeded, callbackResult.PerformData - // do tenderly simulations - rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.extraData) + upkeepNeeded, performData = automationCheckResult.Eligible, automationCheckResult.PerformData + // do tenderly simulations for checkCallback + var rawCall []byte + rawCall, err = core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.ExtraData) if err != nil { failUnknown("failed to pack raw checkCallback call", err) } addLink("checkCallback simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) - rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.extraData) + rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.ExtraData) if err != nil { failUnknown("failed to pack raw checkCallback (direct) call", err) } @@ -316,6 +355,39 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } } +func mustAutomationCheckResult(upkeepID *big.Int, checkResult iregistry21.CheckUpkeep, trigger ocr2keepers.Trigger) ocr2keepers.CheckResult { + upkeepIdentifier := mustUpkeepIdentifier(upkeepID) + checkResult2 := ocr2keepers.CheckResult{ + Eligible: checkResult.UpkeepNeeded, + IneligibilityReason: checkResult.UpkeepFailureReason, + UpkeepID: upkeepIdentifier, + Trigger: trigger, + WorkID: core.UpkeepWorkID(upkeepIdentifier, trigger), + GasAllocated: 0, + PerformData: checkResult.PerformData, + FastGasWei: checkResult.FastGasWei, + LinkNative: checkResult.LinkNative, + } + + return checkResult2 +} + +type blockSubscriber struct { + ethClient *ethclient.Client +} + +func (bs *blockSubscriber) LatestBlock() *ocr2keepers.BlockKey { + header, err := bs.ethClient.HeaderByNumber(context.Background(), nil) + if err != nil { + return nil + } + + return &ocr2keepers.BlockKey{ + Number: ocr2keepers.BlockNumber(header.Number.Uint64()), + Hash: header.Hash(), + } +} + func logMatchesTriggerConfig(log *types.Log, config automation_utils_2_1.LogTriggerConfig) bool { if log.Topics[0] != config.Topic0 { return false @@ -353,9 +425,27 @@ func packTriggerData(log *types.Log, blockTime uint64) ([]byte, error) { return b, nil } -func mustUpkeepWorkID(upkeepID *big.Int, blockNum uint64, blockHash [32]byte, txHash [32]byte, logIndex int64) [32]byte { - // TODO - this is a copy of the code in core.UpkeepWorkID - // We should refactor that code to be more easily exported ex not rely on Trigger structs +func mustUpkeepWorkID(upkeepID *big.Int, trigger ocr2keepers.Trigger) [32]byte { + upkeepIdentifier := mustUpkeepIdentifier(upkeepID) + + workID := core.UpkeepWorkID(upkeepIdentifier, trigger) + workIDBytes, err := hex.DecodeString(workID) + if err != nil { + failUnknown("failed to decode workID", err) + } + + var result [32]byte + copy(result[:], workIDBytes[:]) + return result +} + +func mustUpkeepIdentifier(upkeepID *big.Int) ocr2keepers.UpkeepIdentifier { + upkeepIdentifier := &ocr2keepers.UpkeepIdentifier{} + upkeepIdentifier.FromBigInt(upkeepID) + return *upkeepIdentifier +} + +func mustAutomationTrigger(txHash [32]byte, logIndex int64, blockNum uint64, blockHash [32]byte) ocr2keepers.Trigger { trigger := ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ TxHash: txHash, @@ -364,16 +454,7 @@ func mustUpkeepWorkID(upkeepID *big.Int, blockNum uint64, blockHash [32]byte, tx BlockHash: blockHash, }, } - upkeepIdentifier := &ocr2keepers.UpkeepIdentifier{} - upkeepIdentifier.FromBigInt(upkeepID) - workID := core.UpkeepWorkID(*upkeepIdentifier, trigger) - workIDBytes, err := hex.DecodeString(workID) - if err != nil { - failUnknown("failed to decode workID", err) - } - var result [32]byte - copy(result[:], workIDBytes[:]) - return result + return trigger } func message(msg string) { @@ -385,11 +466,11 @@ func warning(msg string) { } func resolveIneligible(msg string) { - exit(fmt.Sprintf("✅ %s: this upkeep is not currently elligible", msg), nil, 0) + exit(fmt.Sprintf("✅ %s: this upkeep is not currently eligible", msg), nil, 0) } func resolveEligible() { - exit("❌ this upkeep is currently elligible", nil, 0) + exit("❌ this upkeep is currently eligible", nil, 0) } func rerun(msg string, err error) { @@ -490,5 +571,3 @@ func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, inpu } return common.TenderlySimLink(responseJSON.Simulation.Id) } - -// TODO - link to performUpkeep tx if exists diff --git a/core/scripts/chaincli/handler/mercury_lookup_handler.go b/core/scripts/chaincli/handler/mercury_lookup_handler.go deleted file mode 100644 index 1165d83921..0000000000 --- a/core/scripts/chaincli/handler/mercury_lookup_handler.go +++ /dev/null @@ -1,536 +0,0 @@ -package handler - -import ( - "context" - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "io" - "math/big" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/avast/retry-go" - ethabi "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" -) - -// MercuryLookupHandler is responsible for initiating the calls to the Mercury server -// to determine whether the upkeeps are eligible -type MercuryLookupHandler struct { - credentials *MercuryCredentials - httpClient HttpClient - rpcClient *rpc.Client -} - -func NewMercuryLookupHandler( - credentials *MercuryCredentials, - rpcClient *rpc.Client, -) *MercuryLookupHandler { - return &MercuryLookupHandler{ - credentials: credentials, - httpClient: http.DefaultClient, - rpcClient: rpcClient, - } -} - -type MercuryVersion string - -type StreamsLookup struct { - feedParamKey string - feeds []string - timeParamKey string - time *big.Int - extraData []byte - upkeepId *big.Int - block uint64 -} - -//go:generate mockery --quiet --name HttpClient --output ./mocks/ --case=underscore -type HttpClient interface { - Do(req *http.Request) (*http.Response, error) -} - -type MercuryCredentials struct { - LegacyURL string - URL string - ClientID string - ClientKey string -} - -func (mc *MercuryCredentials) Validate() bool { - return mc.URL != "" && mc.ClientID != "" && mc.ClientKey != "" -} - -type MercuryData struct { - Index int - Error error - Retryable bool - Bytes [][]byte - State PipelineExecutionState -} - -// MercuryV02Response represents a JSON structure used by Mercury v0.2 -type MercuryV02Response struct { - ChainlinkBlob string `json:"chainlinkBlob"` -} - -// MercuryV03Response represents a JSON structure used by Mercury v0.3 -type MercuryV03Response struct { - Reports []MercuryV03Report `json:"reports"` -} - -type MercuryV03Report struct { - FeedID string `json:"feedID"` // feed id in hex encoded - ValidFromTimestamp uint32 `json:"validFromTimestamp"` - ObservationsTimestamp uint32 `json:"observationsTimestamp"` - FullReport string `json:"fullReport"` // the actual hex encoded mercury report of this feed, can be sent to verifier -} - -const ( - // DefaultAllowListExpiration decides how long an upkeep's allow list info will be valid for. - DefaultAllowListExpiration = 20 * time.Minute - // CleanupInterval decides when the expired items in cache will be deleted. - CleanupInterval = 25 * time.Minute -) - -const ( - ApplicationJson = "application/json" - BlockNumber = "blockNumber" // valid for v0.2 - FeedIDs = "feedIDs" // valid for v0.3 - FeedIdHex = "feedIdHex" // valid for v0.2 - HeaderAuthorization = "Authorization" - HeaderContentType = "Content-Type" - HeaderTimestamp = "X-Authorization-Timestamp" - HeaderSignature = "X-Authorization-Signature-SHA256" - HeaderUpkeepId = "X-Authorization-Upkeep-Id" - MercuryPathV2 = "/client?" // only used to access mercury v0.2 server - MercuryBatchPathV3 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server - RetryDelay = 500 * time.Millisecond - Timestamp = "timestamp" // valid for v0.3 - TotalAttempt = 3 - UserId = "userId" -) - -type UpkeepFailureReason uint8 -type PipelineExecutionState uint8 - -const ( - // upkeep failure onchain reasons - UpkeepFailureReasonNone UpkeepFailureReason = 0 - UpkeepFailureReasonUpkeepCancelled UpkeepFailureReason = 1 - UpkeepFailureReasonUpkeepPaused UpkeepFailureReason = 2 - UpkeepFailureReasonTargetCheckReverted UpkeepFailureReason = 3 - UpkeepFailureReasonUpkeepNotNeeded UpkeepFailureReason = 4 - UpkeepFailureReasonPerformDataExceedsLimit UpkeepFailureReason = 5 - UpkeepFailureReasonInsufficientBalance UpkeepFailureReason = 6 - UpkeepFailureReasonMercuryCallbackReverted UpkeepFailureReason = 7 - UpkeepFailureReasonRevertDataExceedsLimit UpkeepFailureReason = 8 - UpkeepFailureReasonRegistryPaused UpkeepFailureReason = 9 - // leaving a gap here for more onchain failure reasons in the future - // upkeep failure offchain reasons - UpkeepFailureReasonMercuryAccessNotAllowed UpkeepFailureReason = 32 - UpkeepFailureReasonTxHashNoLongerExists UpkeepFailureReason = 33 - UpkeepFailureReasonInvalidRevertDataInput UpkeepFailureReason = 34 - UpkeepFailureReasonSimulationFailed UpkeepFailureReason = 35 - UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 - - // pipeline execution error - NoPipelineError PipelineExecutionState = 0 - CheckBlockTooOld PipelineExecutionState = 1 - CheckBlockInvalid PipelineExecutionState = 2 - RpcFlakyFailure PipelineExecutionState = 3 - MercuryFlakyFailure PipelineExecutionState = 4 - PackUnpackDecodeFailed PipelineExecutionState = 5 - MercuryUnmarshalError PipelineExecutionState = 6 - InvalidMercuryRequest PipelineExecutionState = 7 - InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses - UpkeepNotAuthorized PipelineExecutionState = 9 -) - -// UpkeepPrivilegeConfig represents the administrative offchain config for each upkeep. It can be set by s_upkeepPrivilegeManager -// role on the registry. Upkeeps allowed to use Mercury server will have this set to true. -type UpkeepPrivilegeConfig struct { - MercuryEnabled bool `json:"mercuryEnabled"` -} - -// generateHMAC calculates a user HMAC for Mercury server authentication. -func (mlh *MercuryLookupHandler) generateHMAC(method string, path string, body []byte, clientId string, secret string, ts int64) string { - bodyHash := sha256.New() - bodyHash.Write(body) - hashString := fmt.Sprintf("%s %s %s %s %d", - method, - path, - hex.EncodeToString(bodyHash.Sum(nil)), - clientId, - ts) - signedMessage := hmac.New(sha256.New, []byte(secret)) - signedMessage.Write([]byte(hashString)) - userHmac := hex.EncodeToString(signedMessage.Sum(nil)) - return userHmac -} - -// singleFeedRequest sends a v0.2 Mercury request for a single feed report. -func (mlh *MercuryLookupHandler) singleFeedRequest(ctx context.Context, ch chan<- MercuryData, index int, ml *StreamsLookup) { - q := url.Values{ - ml.feedParamKey: {ml.feeds[index]}, - ml.timeParamKey: {ml.time.String()}, - } - mercuryURL := mlh.credentials.LegacyURL - reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, MercuryPathV2, q.Encode()) - // mlh.logger.Debugf("request URL for upkeep %s feed %s: %s", ml.upkeepId.String(), ml.feeds[index], reqUrl) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) - if err != nil { - ch <- MercuryData{Index: index, Error: err, Retryable: false, State: InvalidMercuryRequest} - return - } - - ts := time.Now().UTC().UnixMilli() - signature := mlh.generateHMAC(http.MethodGet, MercuryPathV2+q.Encode(), []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) - req.Header.Set(HeaderContentType, ApplicationJson) - req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) - req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) - req.Header.Set(HeaderSignature, signature) - - // in the case of multiple retries here, use the last attempt's data - state := NoPipelineError - retryable := false - sent := false - retryErr := retry.Do( - func() error { - retryable = false - resp, err1 := mlh.httpClient.Do(req) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup GET request failed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) - retryable = true - state = MercuryFlakyFailure - return err1 - } - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - _ = "" // placate linter - // mlh.logger.Errorf("Encountered error when closing the body of the response in single feed: %s", err) - } - }(resp.Body) - - body, err1 := io.ReadAll(resp.Body) - if err1 != nil { - retryable = false - state = InvalidMercuryResponse - return err1 - } - - if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { - // mlh.logger.Errorw("StreamsLookup received retryable status code", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "statusCode", resp.StatusCode, "feed", ml.feeds[index]) - retryable = true - state = MercuryFlakyFailure - return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) - } else if resp.StatusCode != http.StatusOK { - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("StreamsLookup upkeep %s block %s received status code %d for feed %s", ml.upkeepId.String(), ml.time.String(), resp.StatusCode, ml.feeds[index]) - } - - // mlh.logger.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", ml.time.String(), ml.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) - - var m MercuryV02Response - err1 = json.Unmarshal(body, &m) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) - retryable = false - state = MercuryUnmarshalError - return err1 - } - blobBytes, err1 := hexutil.Decode(m.ChainlinkBlob) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup failed to decode chainlinkBlob for feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "blob", m.ChainlinkBlob, "feed", ml.feeds[index], "error", err1) - retryable = false - state = InvalidMercuryResponse - return err1 - } - ch <- MercuryData{ - Index: index, - Bytes: [][]byte{blobBytes}, - Retryable: false, - State: NoPipelineError, - } - sent = true - return nil - }, - // only retry when the error is 404 Not Found or 500 Internal Server Error - retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) - }), - retry.Context(ctx), - retry.Delay(RetryDelay), - retry.Attempts(TotalAttempt)) - - if !sent { - md := MercuryData{ - Index: index, - Bytes: [][]byte{}, - Retryable: retryable, - Error: fmt.Errorf("failed to request feed for %s: %w", ml.feeds[index], retryErr), - State: state, - } - ch <- md - } -} - -// multiFeedsRequest sends a Mercury v0.3 request for a multi-feed report -func (mlh *MercuryLookupHandler) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, ml *StreamsLookup) { - params := fmt.Sprintf("%s=%s&%s=%s", FeedIDs, strings.Join(ml.feeds, ","), Timestamp, ml.time.String()) - reqUrl := fmt.Sprintf("%s%s%s", mlh.credentials.URL, MercuryBatchPathV3, params) - // mlh.logger.Debugf("request URL for upkeep %s userId %s: %s", ml.upkeepId.String(), mlh.credentials.ClientID, reqUrl) - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) - if err != nil { - ch <- MercuryData{Index: 0, Error: err, Retryable: false, State: InvalidMercuryRequest} - return - } - - ts := time.Now().UTC().UnixMilli() - signature := mlh.generateHMAC(http.MethodGet, MercuryBatchPathV3+params, []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) - req.Header.Set(HeaderContentType, ApplicationJson) - // username here is often referred to as user id - req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) - req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) - req.Header.Set(HeaderSignature, signature) - // mercury will inspect authorization headers above to make sure this user (in automation's context, this node) is eligible to access mercury - // and if it has an automation role. it will then look at this upkeep id to check if it has access to all the requested feeds. - req.Header.Set(HeaderUpkeepId, ml.upkeepId.String()) - - // in the case of multiple retries here, use the last attempt's data - state := NoPipelineError - retryable := false - sent := false - retryErr := retry.Do( - func() error { - retryable = false - resp, err1 := mlh.httpClient.Do(req) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup GET request fails for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) - retryable = true - state = MercuryFlakyFailure - return err1 - } - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - _ = "" // placate linter - // mlh.logger.Errorf("Encountered error when closing the body of the response in the multi feed: %s", err) - } - }(resp.Body) - body, err1 := io.ReadAll(resp.Body) - if err1 != nil { - retryable = false - state = InvalidMercuryResponse - return err1 - } - - // mlh.logger.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - if resp.StatusCode == http.StatusUnauthorized { - retryable = false - state = UpkeepNotAuthorized - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } else if resp.StatusCode == http.StatusBadRequest { - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } else if resp.StatusCode == http.StatusInternalServerError { - retryable = true - state = MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusInternalServerError) - } else if resp.StatusCode == 420 { - // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } else if resp.StatusCode != http.StatusOK { - retryable = false - state = InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) - } - - var response MercuryV03Response - err1 = json.Unmarshal(body, &response) - if err1 != nil { - // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) - retryable = false - state = MercuryUnmarshalError - return err1 - } - // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract - // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated - if len(response.Reports) != len(ml.feeds) { - // TODO: AUTO-5044: calculate what reports are missing and log a warning - retryable = true - state = MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusNotFound) - } - var reportBytes [][]byte - for _, rsp := range response.Reports { - b, err := hexutil.Decode(rsp.FullReport) - if err != nil { - retryable = false - state = InvalidMercuryResponse - return err - } - reportBytes = append(reportBytes, b) - } - ch <- MercuryData{ - Index: 0, - Bytes: reportBytes, - Retryable: false, - State: NoPipelineError, - } - sent = true - return nil - }, - // only retry when the error is 404 Not Found or 500 Internal Server Error - retry.RetryIf(func(err error) bool { - return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) - }), - retry.Context(ctx), - retry.Delay(RetryDelay), - retry.Attempts(TotalAttempt)) - - if !sent { - md := MercuryData{ - Index: 0, - Bytes: [][]byte{}, - Retryable: retryable, - Error: retryErr, - State: state, - } - ch <- md - } -} - -// doMercuryRequest sends requests to Mercury API to retrieve ChainlinkBlob. -func (mlh *MercuryLookupHandler) doMercuryRequest(ctx context.Context, ml *StreamsLookup) (PipelineExecutionState, UpkeepFailureReason, [][]byte, bool, error) { - var isMercuryV03 bool - resultLen := len(ml.feeds) - ch := make(chan MercuryData, resultLen) - if len(ml.feeds) == 0 { - return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) - } - if ml.feedParamKey == FeedIdHex && ml.timeParamKey == BlockNumber { - // only v0.2 - for i := range ml.feeds { - go mlh.singleFeedRequest(ctx, ch, i, ml) - } - } else if ml.feedParamKey == FeedIDs && ml.timeParamKey == Timestamp { - // only v0.3 - resultLen = 1 - isMercuryV03 = true - ch = make(chan MercuryData, resultLen) - go mlh.multiFeedsRequest(ctx, ch, ml) - } else { - return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) - } - - var reqErr error - results := make([][]byte, len(ml.feeds)) - retryable := true - allSuccess := true - // in v0.2, use the last execution error as the state, if no execution errors, state will be no error - state := NoPipelineError - for i := 0; i < resultLen; i++ { - m := <-ch - if m.Error != nil { - if reqErr == nil { - reqErr = errors.New(m.Error.Error()) - } else { - reqErr = errors.New(reqErr.Error() + m.Error.Error()) - } - retryable = retryable && m.Retryable - allSuccess = false - if m.State != NoPipelineError { - state = m.State - } - continue - } - if isMercuryV03 { - results = m.Bytes - } else { - results[m.Index] = m.Bytes[0] - } - } - // only retry when not all successful AND none are not retryable - return state, UpkeepFailureReasonNone, results, retryable && !allSuccess, reqErr -} - -// decodeStreamsLookup decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string timeParamKey, uint256 time, byte[] extraData) -// func (mlh *MercuryLookupHandler) decodeStreamsLookup(data []byte) (*StreamsLookup, error) { -// e := mlh.mercuryConfig.Abi.Errors["StreamsLookup"] -// unpack, err := e.Unpack(data) -// if err != nil { -// return nil, fmt.Errorf("unpack error: %w", err) -// } -// errorParameters := unpack.([]interface{}) - -// return &StreamsLookup{ -// feedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), -// feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), -// timeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), -// time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), -// extraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), -// }, nil -// } - -// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if -// this upkeep is allowed to use Mercury service. -// func (mlh *MercuryLookupHandler) allowedToUseMercury(upkeep models.Upkeep) (bool, error) { -// allowed, ok := mlh.mercuryConfig.AllowListCache.Get(upkeep.Admin.Hex()) -// if ok { -// return allowed.(bool), nil -// } - -// if upkeep.UpkeepPrivilegeConfig == nil { -// return false, fmt.Errorf("the upkeep privilege config was not retrieved for upkeep with ID %s", upkeep.UpkeepID) -// } - -// if len(upkeep.UpkeepPrivilegeConfig) == 0 { -// return false, fmt.Errorf("the upkeep privilege config is empty") -// } - -// var a UpkeepPrivilegeConfig -// err := json.Unmarshal(upkeep.UpkeepPrivilegeConfig, &a) -// if err != nil { -// return false, fmt.Errorf("failed to unmarshal privilege config for upkeep ID %s: %v", upkeep.UpkeepID, err) -// } - -// mlh.mercuryConfig.AllowListCache.Set(upkeep.Admin.Hex(), a.MercuryEnabled, cache.DefaultExpiration) -// return a.MercuryEnabled, nil -// } - -func (mlh *MercuryLookupHandler) CheckCallback(ctx context.Context, values [][]byte, lookup *StreamsLookup, registryABI ethabi.ABI, registryAddress common.Address) (hexutil.Bytes, error) { - payload, err := registryABI.Pack("checkCallback", lookup.upkeepId, values, lookup.extraData) - if err != nil { - return nil, err - } - - var theBytes hexutil.Bytes - args := map[string]interface{}{ - "to": registryAddress.Hex(), - "data": hexutil.Bytes(payload), - } - - // call checkCallback function at the block which OCR3 has agreed upon - err = mlh.rpcClient.CallContext(ctx, &theBytes, "eth_call", args, hexutil.EncodeUint64(lookup.block)) - if err != nil { - return nil, err - } - return theBytes, nil -} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index db71535723..895363a53f 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -6,7 +6,6 @@ go 1.21.3 replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( - github.com/avast/retry-go v3.0.0+incompatible github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/ethereum/go-ethereum v1.12.0 @@ -18,7 +17,6 @@ require ( github.com/montanaflynn/stats v0.7.1 github.com/olekukonko/tablewriter v0.0.5 github.com/pelletier/go-toml/v2 v2.1.1 - github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 @@ -217,6 +215,7 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/pressly/goose/v3 v3.16.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 1c48074ea3..dcf47d392c 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -145,8 +145,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index 70db40c26b..d64a9e7ef8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -16,7 +16,6 @@ import ( "github.com/patrickmn/go-cache" ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink-common/pkg/services" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" @@ -131,7 +130,6 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper // tried to call mercury lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) streamsLookupErr, err := s.packer.DecodeStreamsLookupRequest(checkResult.PerformData) - if err != nil { lookupLggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) // user contract did not revert with StreamsLookup error @@ -149,7 +147,7 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper if streamsLookupResponse.IsMercuryV02() { // check permission on the registry for mercury v0.2 opts := s.buildCallOpts(ctx, block) - if state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId.BigInt()); err != nil { + if state, reason, retryable, allowed, err := s.AllowedToUseMercury(opts, upkeepId.BigInt()); err != nil { lookupLggr.Warnf("at block %s upkeep %s failed to query mercury allow list: %s", block, upkeepId, err) checkResults[i].PipelineExecutionState = uint8(state) checkResults[i].IneligibilityReason = uint8(reason) @@ -178,65 +176,93 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, i int, checkResults []ocr2keepers.CheckResult) { defer wg.Done() - state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) - pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) + values, err := s.DoMercuryRequest(ctx, lookup, checkResults, i) + if err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s DoMercuryRequest err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + } - if lookup.IsMercuryV02() { - state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) - } else if lookup.IsMercuryV03() { - state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) + if err := s.CheckCallback(ctx, values, lookup, checkResults, i); err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s CheckCallback err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) } +} +func (s *streams) CheckCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) error { + payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) if err != nil { - s.lggr.Errorf("at block %d upkeep %s requested time %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.Block, lookup.UpkeepId, lookup.Time, retryable, retryInterval, err.Error()) - checkResults[i].Retryable = retryable - checkResults[i].RetryInterval = retryInterval - checkResults[i].PipelineExecutionState = uint8(state) - checkResults[i].IneligibilityReason = uint8(reason) - return + checkResults[i].Retryable = false + checkResults[i].PipelineExecutionState = uint8(mercury.PackUnpackDecodeFailed) + return err } - for j, v := range values { - s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) + var mercuryBytes hexutil.Bytes + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), } - state, retryable, mercuryBytes, err := s.checkCallback(ctx, values, lookup) - if err != nil { - s.lggr.Errorf("at block %d upkeep %s checkCallback err: %s", lookup.Block, lookup.UpkeepId, err.Error()) - checkResults[i].Retryable = retryable - checkResults[i].PipelineExecutionState = uint8(state) - return + // call checkCallback function at the block which OCR3 has agreed upon + if err = s.client.CallContext(ctx, &mercuryBytes, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { + checkResults[i].Retryable = true + checkResults[i].PipelineExecutionState = uint8(mercury.RpcFlakyFailure) + return err } + s.lggr.Infof("at block %d upkeep %s requested time %s checkCallback mercuryBytes: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(mercuryBytes)) unpackCallBackState, needed, performData, failureReason, _, err := s.packer.UnpackCheckCallbackResult(mercuryBytes) if err != nil { - s.lggr.Errorf("at block %d upkeep %s requested time %s UnpackCheckCallbackResult err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) checkResults[i].PipelineExecutionState = unpackCallBackState - return + return err } if failureReason == uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) { checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryCallbackReverted) s.lggr.Debugf("at block %d upkeep %s requested time %s mercury callback reverts", lookup.Block, lookup.UpkeepId, lookup.Time) - return + return nil + } if !needed { checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonUpkeepNotNeeded) s.lggr.Debugf("at block %d upkeep %s requested time %s callback reports upkeep not needed", lookup.Block, lookup.UpkeepId, lookup.Time) - return + return nil } checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonNone) checkResults[i].Eligible = true checkResults[i].PerformData = performData s.lggr.Infof("at block %d upkeep %s requested time %s successful with perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(performData)) + + return nil } -// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if +func (s *streams) DoMercuryRequest(ctx context.Context, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) ([][]byte, error) { + state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) + pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) + + if lookup.IsMercuryV02() { + state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) + } else if lookup.IsMercuryV03() { + state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) + } + + if err != nil { + checkResults[i].Retryable = retryable + checkResults[i].RetryInterval = retryInterval + checkResults[i].PipelineExecutionState = uint8(state) + checkResults[i].IneligibilityReason = uint8(reason) + return nil, err + } + + for j, v := range values { + s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) + } + return values, nil +} + +// AllowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if // this upkeep is allowed to use Mercury service. -func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { +func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { allowed, ok := s.mercuryConfig.IsUpkeepAllowed(upkeepId.String()) if ok { return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, allowed.(bool), nil @@ -256,7 +282,6 @@ func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s "data": hexutil.Bytes(payload), } - // call checkCallback function at the block which OCR3 has agreed upon if err = s.client.CallContext(opts.Context, &resultBytes, "eth_call", args, hexutil.EncodeBig(opts.BlockNumber)); err != nil { return mercury.RpcFlakyFailure, mercury.MercuryUpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) } @@ -282,26 +307,6 @@ func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil } -func (s *streams) checkCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup) (mercury.MercuryUpkeepState, bool, hexutil.Bytes, error) { - payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) - if err != nil { - return mercury.PackUnpackDecodeFailed, false, nil, err - } - - var b hexutil.Bytes - args := map[string]interface{}{ - "to": s.registry.Address().Hex(), - "data": hexutil.Bytes(payload), - } - - // call checkCallback function at the block which OCR3 has agreed upon - if err := s.client.CallContext(ctx, &b, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { - return mercury.RpcFlakyFailure, true, nil, err - } - - return mercury.NoPipelineError, false, b, nil -} - func (s *streams) buildCallOpts(ctx context.Context, block *big.Int) *bind.CallOpts { opts := bind.CallOpts{ Context: ctx, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index 32041d0f18..caa3efb974 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -127,6 +127,7 @@ func TestStreams_CheckCallback(t *testing.T) { tests := []struct { name string lookup *mercury.StreamsLookup + input []ocr2keepers.CheckResult values [][]byte statusCode int @@ -154,6 +155,9 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, + input: []ocr2keepers.CheckResult{ + {}, + }, values: values, statusCode: http.StatusOK, callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -186,6 +190,9 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, + input: []ocr2keepers.CheckResult{ + {}, + }, values: values, statusCode: http.StatusOK, callbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -217,6 +224,9 @@ func TestStreams_CheckCallback(t *testing.T) { UpkeepId: upkeepId, Block: bn, }, + input: []ocr2keepers.CheckResult{ + {}, + }, values: values, statusCode: http.StatusOK, callbackResp: []byte{}, @@ -256,10 +266,10 @@ func TestStreams_CheckCallback(t *testing.T) { }).Once() s.client = client - state, retryable, _, err := s.checkCallback(testutils.Context(t), tt.values, tt.lookup) - tt.wantErr(t, err, fmt.Sprintf("Error asserion failed: %v", tt.name)) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.retryable, retryable) + err = s.CheckCallback(testutils.Context(t), tt.values, tt.lookup, tt.input, 0) + tt.wantErr(t, err, fmt.Sprintf("Error assertion failed: %v", tt.name)) + assert.Equal(t, uint8(tt.state), tt.input[0].PipelineExecutionState) + assert.Equal(t, tt.retryable, tt.input[0].Retryable) }) } } @@ -435,7 +445,7 @@ func TestStreams_AllowedToUseMercury(t *testing.T) { BlockNumber: big.NewInt(10), } - state, reason, retryable, allowed, err := s.allowedToUseMercury(opts, upkeepId) + state, reason, retryable, allowed, err := s.AllowedToUseMercury(opts, upkeepId) assert.Equal(t, tt.err, err) assert.Equal(t, tt.allowed, allowed) assert.Equal(t, tt.state, state) From ee2996fa748812dc406fd6147d54f2c1e53a4ade Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Wed, 13 Dec 2023 16:26:36 -0500 Subject: [PATCH 316/327] Adds MAKE Command for Building Plugin Image (#11567) --- integration-tests/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/integration-tests/Makefile b/integration-tests/Makefile index fb4bfa74f3..86a266a996 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -192,6 +192,12 @@ test_reorg_automation: ## Run the automation reorg tests build_docker_image: docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t $(image):$(tag) ../ +# image: the name for the chainlink image being built, example: image=chainlink +# tag: the tag for the chainlink image being built, example: tag=latest +# example usage: make build_docker_image image=chainlink tag=latest +.PHONY: build_plugin_docker_image +build_docker_image: + docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ # image: the name for the chainlink image being built, example: image=chainlink # tag: the tag for the chainlink image being built, example: tag=latest From 8b2c48dbcdd31ed5defff930f66b8cc7a49b9817 Mon Sep 17 00:00:00 2001 From: Lei Date: Wed, 13 Dec 2023 14:42:33 -0800 Subject: [PATCH 317/327] Mercury Packer (#11521) * Refactor encoding.Packer to have Mercury control its own interface and function implementations * rebase and update --- core/scripts/chaincli/handler/debug.go | 37 ++-- .../evmregistry/v21/encoding/interface.go | 7 - .../evmregistry/v21/encoding/packer.go | 48 ----- .../evmregistry/v21/encoding/packer_test.go | 186 ----------------- .../evmregistry/v21/mercury/mercury.go | 75 ++++++- .../evmregistry/v21/mercury/mercury_test.go | 193 ++++++++++++++++++ .../v21/mercury/streams/streams.go | 6 +- .../v21/mercury/streams/streams_test.go | 2 - .../ocr2keeper/evmregistry/v21/registry.go | 3 +- 9 files changed, 290 insertions(+), 267 deletions(-) diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 815a0c9a03..3e8bd6d597 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -23,7 +23,6 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" @@ -33,6 +32,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" @@ -44,6 +44,7 @@ const ( expectedTypeAndVersion = "KeeperRegistry 2.1.0" ) +var mercuryPacker = mercury.NewAbiPacker() var packer = encoding.NewAbiPacker() var links []string @@ -258,10 +259,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { mercuryConfig := evm21.NewMercuryConfig(mc, core.StreamsCompatibleABI) lggr, _ := logger.NewLogger() blockSub := &blockSubscriber{k.client} - streams := streams.NewStreamsLookup(packer, mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr) + streams := streams.NewStreamsLookup(mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr) var streamsLookupErr *mercury.StreamsLookupError - streamsLookupErr, err = packer.DecodeStreamsLookupRequest(checkResult.PerformData) + streamsLookupErr, err = mercuryPacker.DecodeStreamsLookupRequest(checkResult.PerformData) if err == nil { message("upkeep reverted with StreamsLookup") message(fmt.Sprintf("StreamsLookup data: {FeedParamKey: %s, Feeds: %v, TimeParamKey: %s, Time: %d, ExtraData: %s}", streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time.Uint64(), hexutil.Encode(streamsLookupErr.ExtraData))) @@ -282,7 +283,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { message("using mercury lookup v0.2") // check if upkeep is allowed to use mercury v0.2 var allowed bool - _, _, _, allowed, err = streams.AllowedToUseMercury(latestCallOpts, upkeepID) + _, _, _, allowed, err = streams.AllowedToUseMercury(triggerCallOpts, upkeepID) if err != nil { failUnknown("failed to check if upkeep is allowed to use mercury", err) } @@ -307,10 +308,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { var values [][]byte values, err = streams.DoMercuryRequest(ctx, streamsLookup, checkResults, 0) - if automationCheckResult.IneligibilityReason == uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) { + if checkResults[0].IneligibilityReason == uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) { resolveIneligible("upkeep used invalid revert data") } - if automationCheckResult.PipelineExecutionState == uint8(mercury.InvalidMercuryRequest) { + if checkResults[0].PipelineExecutionState == uint8(mercury.InvalidMercuryRequest) { resolveIneligible("the mercury request data is invalid") } if err != nil { @@ -322,10 +323,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failUnknown("failed to execute mercury callback ", err) } - if automationCheckResult.IneligibilityReason != 0 { - message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", automationCheckResult.IneligibilityReason)) + if checkResults[0].IneligibilityReason != 0 { + message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResults[0].IneligibilityReason)) } - upkeepNeeded, performData = automationCheckResult.Eligible, automationCheckResult.PerformData + upkeepNeeded, performData = checkResults[0].Eligible, checkResults[0].PerformData // do tenderly simulations for checkCallback var rawCall []byte rawCall, err = core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.ExtraData) @@ -345,13 +346,23 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if !upkeepNeeded { resolveIneligible("upkeep is not needed") } - // simulate perform ukeep - simulateResult, err := keeperRegistry21.SimulatePerformUpkeep(latestCallOpts, upkeepID, performData) + // simulate perform upkeep + simulateResult, err := keeperRegistry21.SimulatePerformUpkeep(triggerCallOpts, upkeepID, performData) if err != nil { failUnknown("failed to simulate perform upkeep: ", err) } + + // do tenderly simulation + rawCall, err := core.RegistryABI.Pack("simulatePerformUpkeep", upkeepID, performData) + if err != nil { + failUnknown("failed to pack raw simulatePerformUpkeep call", err) + } + addLink("simulatePerformUpkeep simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + if simulateResult.Success { resolveEligible() + } else { + resolveIneligible("simulate perform upkeep unsuccessful") } } @@ -466,11 +477,11 @@ func warning(msg string) { } func resolveIneligible(msg string) { - exit(fmt.Sprintf("✅ %s: this upkeep is not currently eligible", msg), nil, 0) + exit(fmt.Sprintf("❌ this upkeep is not eligible: %s", msg), nil, 0) } func resolveEligible() { - exit("❌ this upkeep is currently eligible", nil, 0) + exit("✅ this upkeep is eligible", nil, 0) } func rerun(msg string, err error) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go index 06a3e7b106..ed3218ea40 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go @@ -1,13 +1,10 @@ package encoding import ( - "math/big" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) const ( @@ -51,12 +48,8 @@ type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo type Packer interface { UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw string) (ocr2keepers.CheckResult, error) - UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) UnpackPerformResult(raw string) (uint8, bool, error) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) - PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) - UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) - DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go index 57013a6277..4a92b4a17e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go @@ -11,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) // triggerWrapper is a wrapper for the different trigger types (log and condition triggers). @@ -67,35 +66,6 @@ func (p *abiPacker) UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw str return result, nil } -func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { - return p.registryABI.Pack("getUpkeepPrivilegeConfig", upkeepId) -} - -func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) { - out, err := p.registryABI.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp) - if err != nil { - return nil, fmt.Errorf("%w: unpack getUpkeepPrivilegeConfig return", err) - } - - bts := *abi.ConvertType(out[0], new([]byte)).(*[]byte) - - return bts, nil -} - -func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) { - out, err := p.registryABI.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) - if err != nil { - return PackUnpackDecodeFailed, false, nil, 0, nil, fmt.Errorf("%w: unpack checkUpkeep return: %s", err, hexutil.Encode(callbackResp)) - } - - upkeepNeeded := *abi.ConvertType(out[0], new(bool)).(*bool) - rawPerformData := *abi.ConvertType(out[1], new([]byte)).(*[]byte) - failureReason := *abi.ConvertType(out[2], new(uint8)).(*uint8) - gasUsed := *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - - return NoPipelineError, upkeepNeeded, rawPerformData, failureReason, gasUsed, nil -} - func (p *abiPacker) UnpackPerformResult(raw string) (uint8, bool, error) { b, err := hexutil.Decode(raw) if err != nil { @@ -163,24 +133,6 @@ func (p *abiPacker) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistr return report, nil } -// DecodeStreamsLookupRequest decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) -func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error) { - e := p.streamsABI.Errors["StreamsLookup"] - unpack, err := e.Unpack(data) - if err != nil { - return nil, fmt.Errorf("unpack error: %w", err) - } - errorParameters := unpack.([]interface{}) - - return &mercury.StreamsLookupError{ - FeedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), - Feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), - TimeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), - Time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), - ExtraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), - }, nil -} - // GetIneligibleCheckResultWithoutPerformData returns an ineligible check result with ineligibility reason and pipeline execution state but without perform data func GetIneligibleCheckResultWithoutPerformData(p ocr2keepers.UpkeepPayload, reason uint8, state uint8, retryable bool) ocr2keepers.CheckResult { return ocr2keepers.CheckResult{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go index 42fcd40d61..71c2755f15 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go @@ -1,8 +1,6 @@ package encoding import ( - "encoding/json" - "errors" "fmt" "math/big" "testing" @@ -17,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" automation21Utils "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) func TestPacker_PackReport(t *testing.T) { @@ -231,62 +228,6 @@ func TestPacker_UnpackPerformResult(t *testing.T) { } } -func TestPacker_UnpackCheckCallbackResult(t *testing.T) { - tests := []struct { - Name string - CallbackResp []byte - UpkeepNeeded bool - PerformData []byte - FailureReason uint8 - GasUsed *big.Int - ErrorString string - State uint8 - }{ - { - Name: "unpack upkeep needed", - CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - UpkeepNeeded: true, - PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - FailureReason: uint8(UpkeepFailureReasonNone), - GasUsed: big.NewInt(11796), - }, - { - Name: "unpack upkeep not needed", - CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - UpkeepNeeded: false, - PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - FailureReason: uint8(UpkeepFailureReasonUpkeepNotNeeded), - GasUsed: big.NewInt(13008), - }, - { - Name: "unpack malformed data", - CallbackResp: []byte{0, 0, 0, 23, 4, 163, 66, 91, 228, 102, 200, 84, 144, 233, 218, 44, 168, 192, 191, 253, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - UpkeepNeeded: false, - PerformData: nil, - ErrorString: "abi: improperly encoded boolean value: unpack checkUpkeep return: ", - State: PackUnpackDecodeFailed, - }, - } - for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - packer := NewAbiPacker() - - state, needed, pd, failureReason, gasUsed, err := packer.UnpackCheckCallbackResult(test.CallbackResp) - - if test.ErrorString != "" { - assert.EqualError(t, err, test.ErrorString+hexutil.Encode(test.CallbackResp)) - } else { - assert.Nil(t, err) - } - assert.Equal(t, test.UpkeepNeeded, needed) - assert.Equal(t, test.PerformData, pd) - assert.Equal(t, test.FailureReason, failureReason) - assert.Equal(t, test.GasUsed, gasUsed) - assert.Equal(t, test.State, state) - }) - } -} - func TestPacker_UnpackLogTriggerConfig(t *testing.T) { tests := []struct { name string @@ -349,130 +290,3 @@ func TestPacker_PackReport_UnpackReport(t *testing.T) { expected := "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405060708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000" assert.Equal(t, hexutil.Encode(res), expected) } - -func TestPacker_PackGetUpkeepPrivilegeConfig(t *testing.T) { - tests := []struct { - name string - upkeepId *big.Int - raw []byte - errored bool - }{ - { - name: "happy path", - upkeepId: func() *big.Int { - id, _ := new(big.Int).SetString("52236098515066839510538748191966098678939830769967377496848891145101407612976", 10) - - return id - }(), - raw: func() []byte { - b, _ := hexutil.Decode("0x19d97a94737c9583000000000000000000000001ea8ed6d0617dd5b3b87374020efaf030") - - return b - }(), - errored: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - packer := NewAbiPacker() - - b, err := packer.PackGetUpkeepPrivilegeConfig(test.upkeepId) - - if !test.errored { - require.NoError(t, err, "no error expected from packing") - - assert.Equal(t, test.raw, b, "raw bytes for output should match expected") - } else { - assert.NotNil(t, err, "error expected from packing function") - } - }) - } -} - -func TestPacker_UnpackGetUpkeepPrivilegeConfig(t *testing.T) { - tests := []struct { - name string - raw []byte - errored bool - }{ - { - name: "happy path", - raw: func() []byte { - b, _ := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000177b226d657263757279456e61626c6564223a747275657d000000000000000000") - - return b - }(), - errored: false, - }, - { - name: "error empty config", - raw: func() []byte { - b, _ := hexutil.Decode("0x") - - return b - }(), - errored: true, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - packer := NewAbiPacker() - - b, err := packer.UnpackGetUpkeepPrivilegeConfig(test.raw) - - if !test.errored { - require.NoError(t, err, "should unpack bytes from abi encoded value") - - // the actual struct to unmarshal into is not available to this - // package so basic json encoding is the limit of the following test - var data map[string]interface{} - err = json.Unmarshal(b, &data) - - assert.NoError(t, err, "packed data should unmarshal using json encoding") - assert.Equal(t, []byte(`{"mercuryEnabled":true}`), b) - } else { - assert.NotNil(t, err, "error expected from unpack function") - } - }) - } -} - -func TestPacker_DecodeStreamsLookupRequest(t *testing.T) { - tests := []struct { - name string - data []byte - expected *mercury.StreamsLookupError - state uint8 - err error - }{ - { - name: "success - decode to streams lookup", - data: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000002435eb50000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - expected: &mercury.StreamsLookupError{ - FeedParamKey: "feedIdHex", - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: "blockNumber", - Time: big.NewInt(37969589), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - }, - { - name: "failure - unpack error", - data: []byte{1, 2, 3, 4}, - err: errors.New("unpack error: invalid data for unpacking"), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - packer := NewAbiPacker() - fl, err := packer.DecodeStreamsLookupRequest(tt.data) - assert.Equal(t, tt.expected, fl) - if tt.err != nil { - assert.Equal(t, tt.err.Error(), err.Error()) - } - }) - } -} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go index f9a3c001c6..10e77bf50c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go @@ -10,9 +10,13 @@ import ( "net/http" "time" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" ) const ( @@ -68,13 +72,6 @@ type MercuryData struct { State MercuryUpkeepState } -type Packer interface { - UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) - PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) - UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) - DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) -} - type MercuryConfigProvider interface { Credentials() *models.MercuryCredentials IsUpkeepAllowed(string) (interface{}, bool) @@ -113,6 +110,70 @@ func (l *StreamsLookup) IsMercuryV03() bool { return l.FeedParamKey == FeedIDs } +// IsMercuryV03UsingBlockNumber is used to distinguish the batch path. It is used for Mercury V03 only func (l *StreamsLookup) IsMercuryV03UsingBlockNumber() bool { return l.TimeParamKey == BlockNumber } + +type Packer interface { + UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) + PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) + UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) + DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) +} + +type abiPacker struct { + registryABI abi.ABI + streamsABI abi.ABI +} + +func NewAbiPacker() *abiPacker { + return &abiPacker{registryABI: core.RegistryABI, streamsABI: core.StreamsCompatibleABI} +} + +// DecodeStreamsLookupRequest decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) +func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) { + e := p.streamsABI.Errors["StreamsLookup"] + unpack, err := e.Unpack(data) + if err != nil { + return nil, fmt.Errorf("unpack error: %w", err) + } + errorParameters := unpack.([]interface{}) + + return &StreamsLookupError{ + FeedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), + Feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), + TimeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), + Time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), + ExtraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), + }, nil +} + +func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) { + out, err := p.registryABI.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) + if err != nil { + return encoding.PackUnpackDecodeFailed, false, nil, 0, nil, fmt.Errorf("%w: unpack checkUpkeep return: %s", err, hexutil.Encode(callbackResp)) + } + + upkeepNeeded := *abi.ConvertType(out[0], new(bool)).(*bool) + rawPerformData := *abi.ConvertType(out[1], new([]byte)).(*[]byte) + failureReason := *abi.ConvertType(out[2], new(uint8)).(*uint8) + gasUsed := *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + + return encoding.NoPipelineError, upkeepNeeded, rawPerformData, failureReason, gasUsed, nil +} + +func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) { + out, err := p.registryABI.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp) + if err != nil { + return nil, fmt.Errorf("%w: unpack getUpkeepPrivilegeConfig return", err) + } + + bts := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return bts, nil +} + +func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return p.registryABI.Pack("getUpkeepPrivilegeConfig", upkeepId) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go index baa939dbec..6095e7b946 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go @@ -1,7 +1,17 @@ package mercury import ( + "encoding/json" + "errors" + "math/big" "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" ) func TestGenerateHMACFn(t *testing.T) { @@ -47,3 +57,186 @@ func TestGenerateHMACFn(t *testing.T) { }) } } + +func TestPacker_DecodeStreamsLookupRequest(t *testing.T) { + tests := []struct { + name string + data []byte + expected *StreamsLookupError + state uint8 + err error + }{ + { + name: "success - decode to streams lookup", + data: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000002435eb50000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + expected: &StreamsLookupError{ + FeedParamKey: "feedIdHex", + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: "blockNumber", + Time: big.NewInt(37969589), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + }, + { + name: "failure - unpack error", + data: []byte{1, 2, 3, 4}, + err: errors.New("unpack error: invalid data for unpacking"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + packer := NewAbiPacker() + fl, err := packer.DecodeStreamsLookupRequest(tt.data) + assert.Equal(t, tt.expected, fl) + if tt.err != nil { + assert.Equal(t, tt.err.Error(), err.Error()) + } + }) + } +} + +func TestPacker_UnpackGetUpkeepPrivilegeConfig(t *testing.T) { + tests := []struct { + name string + raw []byte + errored bool + }{ + { + name: "happy path", + raw: func() []byte { + b, _ := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000177b226d657263757279456e61626c6564223a747275657d000000000000000000") + + return b + }(), + errored: false, + }, + { + name: "error empty config", + raw: func() []byte { + b, _ := hexutil.Decode("0x") + + return b + }(), + errored: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + packer := NewAbiPacker() + + b, err := packer.UnpackGetUpkeepPrivilegeConfig(test.raw) + + if !test.errored { + require.NoError(t, err, "should unpack bytes from abi encoded value") + + // the actual struct to unmarshal into is not available to this + // package so basic json encoding is the limit of the following test + var data map[string]interface{} + err = json.Unmarshal(b, &data) + + assert.NoError(t, err, "packed data should unmarshal using json encoding") + assert.Equal(t, []byte(`{"mercuryEnabled":true}`), b) + } else { + assert.NotNil(t, err, "error expected from unpack function") + } + }) + } +} + +func TestPacker_PackGetUpkeepPrivilegeConfig(t *testing.T) { + tests := []struct { + name string + upkeepId *big.Int + raw []byte + errored bool + }{ + { + name: "happy path", + upkeepId: func() *big.Int { + id, _ := new(big.Int).SetString("52236098515066839510538748191966098678939830769967377496848891145101407612976", 10) + + return id + }(), + raw: func() []byte { + b, _ := hexutil.Decode("0x19d97a94737c9583000000000000000000000001ea8ed6d0617dd5b3b87374020efaf030") + + return b + }(), + errored: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + packer := NewAbiPacker() + + b, err := packer.PackGetUpkeepPrivilegeConfig(test.upkeepId) + + if !test.errored { + require.NoError(t, err, "no error expected from packing") + + assert.Equal(t, test.raw, b, "raw bytes for output should match expected") + } else { + assert.NotNil(t, err, "error expected from packing function") + } + }) + } +} + +func TestPacker_UnpackCheckCallbackResult(t *testing.T) { + tests := []struct { + Name string + CallbackResp []byte + UpkeepNeeded bool + PerformData []byte + FailureReason uint8 + GasUsed *big.Int + ErrorString string + State uint8 + }{ + { + Name: "unpack upkeep needed", + CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + UpkeepNeeded: true, + PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + FailureReason: uint8(encoding.UpkeepFailureReasonNone), + GasUsed: big.NewInt(11796), + }, + { + Name: "unpack upkeep not needed", + CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + UpkeepNeeded: false, + PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + FailureReason: uint8(encoding.UpkeepFailureReasonUpkeepNotNeeded), + GasUsed: big.NewInt(13008), + }, + { + Name: "unpack malformed data", + CallbackResp: []byte{0, 0, 0, 23, 4, 163, 66, 91, 228, 102, 200, 84, 144, 233, 218, 44, 168, 192, 191, 253, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + UpkeepNeeded: false, + PerformData: nil, + ErrorString: "abi: improperly encoded boolean value: unpack checkUpkeep return: ", + State: encoding.PackUnpackDecodeFailed, + }, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + packer := NewAbiPacker() + + state, needed, pd, failureReason, gasUsed, err := packer.UnpackCheckCallbackResult(test.CallbackResp) + + if test.ErrorString != "" { + assert.EqualError(t, err, test.ErrorString+hexutil.Encode(test.CallbackResp)) + } else { + assert.Nil(t, err) + } + assert.Equal(t, test.UpkeepNeeded, needed) + assert.Equal(t, test.PerformData, pd) + assert.Equal(t, test.FailureReason, failureReason) + assert.Equal(t, test.GasUsed, gasUsed) + assert.Equal(t, test.State, state) + }) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index d64a9e7ef8..e1bb69f33d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -66,7 +66,6 @@ type UpkeepPrivilegeConfig struct { } func NewStreamsLookup( - packer mercury.Packer, mercuryConfig mercury.MercuryConfigProvider, blockSubscriber latestBlockProvider, client contextCaller, @@ -74,6 +73,8 @@ func NewStreamsLookup( lggr logger.Logger) *streams { httpClient := http.DefaultClient threadCtrl := utils.NewThreadControl() + packer := mercury.NewAbiPacker() + return &streams{ packer: packer, mercuryConfig: mercuryConfig, @@ -231,7 +232,7 @@ func (s *streams) CheckCallback(ctx context.Context, values [][]byte, lookup *me checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonNone) checkResults[i].Eligible = true checkResults[i].PerformData = performData - s.lggr.Infof("at block %d upkeep %s requested time %s successful with perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(performData)) + s.lggr.Infof("at block %d upkeep %s requested time %s CheckCallback successful with perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(performData)) return nil } @@ -288,6 +289,7 @@ func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s var upkeepPrivilegeConfigBytes []byte upkeepPrivilegeConfigBytes, err = s.packer.UnpackGetUpkeepPrivilegeConfig(resultBytes) + if err != nil { return mercury.PackUnpackDecodeFailed, mercury.MercuryUpkeepFailureReasonNone, false, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index caa3efb974..54124b7c1a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -102,14 +102,12 @@ func (r *mockRegistry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [] // setups up a streams object for tests. func setupStreams(t *testing.T) *streams { lggr := logger.TestLogger(t) - packer := encoding.NewAbiPacker() mercuryConfig := new(MockMercuryConfigProvider) blockSubscriber := new(MockBlockSubscriber) registry := &mockRegistry{} client := evmClientMocks.NewClient(t) streams := NewStreamsLookup( - packer, mercuryConfig, blockSubscriber, client, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go index bb05b8029f..39862bb753 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go @@ -94,7 +94,6 @@ func NewEvmRegistry( AllowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), } - hc := http.DefaultClient return &EvmRegistry{ @@ -115,7 +114,7 @@ func NewEvmRegistry( logEventProvider: logEventProvider, bs: blockSub, finalityDepth: finalityDepth, - streams: streams.NewStreamsLookup(packer, mercuryConfig, blockSub, client.Client(), registry, lggr), + streams: streams.NewStreamsLookup(mercuryConfig, blockSub, client.Client(), registry, lggr), } } From c274c23eabc7fade1b1a5e7649187c56f218cc77 Mon Sep 17 00:00:00 2001 From: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:45:38 +0000 Subject: [PATCH 318/327] Introduce job spec flag for custom reverted pipeline (#11529) * Introduce job spec flag for custom reverted pipeline * Disable the flag for V2+ * Rename file after merge conflict --- core/services/job/job_orm_test.go | 21 +++-- core/services/job/models.go | 3 + core/services/job/orm.go | 4 +- core/services/job/validate.go | 1 + core/services/vrf/delegate.go | 3 + .../0214_add_custom_reverts_vrf.sql | 5 ++ core/testdata/testspecs/v2_specs.go | 3 + core/web/presenters/job.go | 38 ++++---- core/web/presenters/job_test.go | 87 +++++++++++++++++++ core/web/resolver/spec.go | 5 ++ core/web/resolver/spec_test.go | 3 + core/web/schema/type/spec.graphql | 1 + 12 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 core/store/migrate/migrations/0214_add_custom_reverts_vrf.sql diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index c0622ba806..768d16ddeb 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -454,6 +454,9 @@ func TestORM_CreateJob_VRFV2(t *testing.T) { var batchFulfillmentEnabled bool require.NoError(t, db.Get(&batchFulfillmentEnabled, `SELECT batch_fulfillment_enabled FROM vrf_specs LIMIT 1`)) require.False(t, batchFulfillmentEnabled) + var customRevertsPipelineEnabled bool + require.NoError(t, db.Get(&customRevertsPipelineEnabled, `SELECT custom_reverts_pipeline_enabled FROM vrf_specs LIMIT 1`)) + require.False(t, customRevertsPipelineEnabled) var batchFulfillmentGasMultiplier float64 require.NoError(t, db.Get(&batchFulfillmentGasMultiplier, `SELECT batch_fulfillment_gas_multiplier FROM vrf_specs LIMIT 1`)) require.Equal(t, float64(1.0), batchFulfillmentGasMultiplier) @@ -514,13 +517,14 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { fromAddresses := []string{cltest.NewEIP55Address().String(), cltest.NewEIP55Address().String()} jb, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec( testspecs.VRFSpecParams{ - VRFVersion: vrfcommon.V2Plus, - RequestedConfsDelay: 10, - FromAddresses: fromAddresses, - ChunkSize: 25, - BackoffInitialDelay: time.Minute, - BackoffMaxDelay: time.Hour, - GasLanePrice: assets.GWei(100), + VRFVersion: vrfcommon.V2Plus, + RequestedConfsDelay: 10, + FromAddresses: fromAddresses, + ChunkSize: 25, + BackoffInitialDelay: time.Minute, + BackoffMaxDelay: time.Hour, + GasLanePrice: assets.GWei(100), + CustomRevertsPipelineEnabled: true, }). Toml()) require.NoError(t, err) @@ -534,6 +538,9 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { var batchFulfillmentEnabled bool require.NoError(t, db.Get(&batchFulfillmentEnabled, `SELECT batch_fulfillment_enabled FROM vrf_specs LIMIT 1`)) require.False(t, batchFulfillmentEnabled) + var customRevertsPipelineEnabled bool + require.NoError(t, db.Get(&customRevertsPipelineEnabled, `SELECT custom_reverts_pipeline_enabled FROM vrf_specs LIMIT 1`)) + require.True(t, customRevertsPipelineEnabled) var batchFulfillmentGasMultiplier float64 require.NoError(t, db.Get(&batchFulfillmentGasMultiplier, `SELECT batch_fulfillment_gas_multiplier FROM vrf_specs LIMIT 1`)) require.Equal(t, float64(1.0), batchFulfillmentGasMultiplier) diff --git a/core/services/job/models.go b/core/services/job/models.go index 3c869f7605..f60e0a1298 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -503,6 +503,9 @@ type VRFSpec struct { // for fulfilling requests. If set to true, batchCoordinatorAddress must be set in // the job spec. BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` + // CustomRevertsPipelineEnabled indicates to the vrf job to run the + // custom reverted txns pipeline along with VRF listener + CustomRevertsPipelineEnabled bool `toml:"customRevertsPipelineEnabled"` // BatchFulfillmentGasMultiplier is used to determine the final gas estimate for the batch // fulfillment. BatchFulfillmentGasMultiplier tomlutils.Float64 `toml:"batchFulfillmentGasMultiplier"` diff --git a/core/services/job/orm.go b/core/services/job/orm.go index b2cf2b2af4..6c5a879ebd 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -326,14 +326,14 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { evm_chain_id, from_addresses, poll_period, requested_confs_delay, request_timeout, chunk_size, batch_coordinator_address, batch_fulfillment_enabled, batch_fulfillment_gas_multiplier, backoff_initial_delay, backoff_max_delay, gas_lane_price, - vrf_owner_address, + vrf_owner_address, custom_reverts_pipeline_enabled, created_at, updated_at) VALUES ( :coordinator_address, :public_key, :min_incoming_confirmations, :evm_chain_id, :from_addresses, :poll_period, :requested_confs_delay, :request_timeout, :chunk_size, :batch_coordinator_address, :batch_fulfillment_enabled, :batch_fulfillment_gas_multiplier, :backoff_initial_delay, :backoff_max_delay, :gas_lane_price, - :vrf_owner_address, + :vrf_owner_address, :custom_reverts_pipeline_enabled, NOW(), NOW()) RETURNING id;` diff --git a/core/services/job/validate.go b/core/services/job/validate.go index 8f559fdb02..b7a1dca361 100644 --- a/core/services/job/validate.go +++ b/core/services/job/validate.go @@ -63,6 +63,7 @@ func ValidateSpec(ts string) (Type, error) { if jb.Pipeline.RequiresPreInsert() && !jb.Type.SupportsAsync() { return "", errors.Errorf("async=true tasks are not supported for %v", jb.Type) } + // spec.CustomRevertsPipelineEnabled == false, default is custom reverted txns pipeline disabled if strings.Contains(ts, "<{}>") { return "", errors.Errorf("'<{}>' syntax is not supported. Please use \"{}\" instead") diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index 03e40614a1..ba28e83bf3 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -142,6 +142,9 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if vrfOwner != nil { return nil, errors.New("VRF Owner is not supported for VRF V2 Plus") } + if jb.VRFSpec.CustomRevertsPipelineEnabled { + return nil, errors.New("Custom Reverted Txns Pipeline is not supported for VRF V2 Plus") + } // Get the LINKNATIVEFEED address with retries // This is needed because the RPC endpoint may be down so we need to diff --git a/core/store/migrate/migrations/0214_add_custom_reverts_vrf.sql b/core/store/migrate/migrations/0214_add_custom_reverts_vrf.sql new file mode 100644 index 0000000000..a2865fce81 --- /dev/null +++ b/core/store/migrate/migrations/0214_add_custom_reverts_vrf.sql @@ -0,0 +1,5 @@ +-- +goose Up +ALTER TABLE vrf_specs ADD COLUMN custom_reverts_pipeline_enabled boolean DEFAULT FALSE NOT NULL; + +-- +goose Down +ALTER TABLE vrf_specs DROP COLUMN custom_reverts_pipeline_enabled; diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index 00297ebdb1..e9dd25fa0f 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -234,6 +234,7 @@ type VRFSpecParams struct { BatchCoordinatorAddress string VRFOwnerAddress string BatchFulfillmentEnabled bool + CustomRevertsPipelineEnabled bool BatchFulfillmentGasMultiplier float64 MinIncomingConfirmations int FromAddresses []string @@ -403,6 +404,7 @@ evmChainID = "%s" batchCoordinatorAddress = "%s" batchFulfillmentEnabled = %v batchFulfillmentGasMultiplier = %s +customRevertsPipelineEnabled = %v minIncomingConfirmations = %d requestedConfsDelay = %d requestTimeout = "%s" @@ -419,6 +421,7 @@ observationSource = """ toml := fmt.Sprintf(template, jobID, name, coordinatorAddress, params.EVMChainID, batchCoordinatorAddress, params.BatchFulfillmentEnabled, strconv.FormatFloat(batchFulfillmentGasMultiplier, 'f', 2, 64), + params.CustomRevertsPipelineEnabled, confirmations, params.RequestedConfsDelay, requestTimeout.String(), publicKey, chunkSize, params.BackoffInitialDelay.String(), params.BackoffMaxDelay.String(), gasLanePrice.String(), pollPeriod.String(), observationSource) diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index a2a9e70c79..e9b63c7361 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -267,6 +267,7 @@ func NewCronSpec(spec *job.CronSpec) *CronSpec { type VRFSpec struct { BatchCoordinatorAddress *ethkey.EIP55Address `json:"batchCoordinatorAddress"` BatchFulfillmentEnabled bool `json:"batchFulfillmentEnabled"` + CustomRevertsPipelineEnabled *bool `json:"customRevertsPipelineEnabled,omitempty"` BatchFulfillmentGasMultiplier float64 `json:"batchFulfillmentGasMultiplier"` CoordinatorAddress ethkey.EIP55Address `json:"coordinatorAddress"` PublicKey secp256k1.PublicKey `json:"publicKey"` @@ -281,26 +282,31 @@ type VRFSpec struct { BackoffInitialDelay models.Duration `json:"backoffInitialDelay"` BackoffMaxDelay models.Duration `json:"backoffMaxDelay"` GasLanePrice *assets.Wei `json:"gasLanePrice"` - VRFOwnerAddress *ethkey.EIP55Address `json:"vrfOwnerAddress"` + RequestedConfsDelay int64 `json:"requestedConfsDelay"` + VRFOwnerAddress *ethkey.EIP55Address `json:"vrfOwnerAddress,omitempty"` } func NewVRFSpec(spec *job.VRFSpec) *VRFSpec { return &VRFSpec{ - BatchCoordinatorAddress: spec.BatchCoordinatorAddress, - BatchFulfillmentEnabled: spec.BatchFulfillmentEnabled, - CoordinatorAddress: spec.CoordinatorAddress, - PublicKey: spec.PublicKey, - FromAddresses: spec.FromAddresses, - PollPeriod: models.MustMakeDuration(spec.PollPeriod), - MinIncomingConfirmations: spec.MinIncomingConfirmations, - CreatedAt: spec.CreatedAt, - UpdatedAt: spec.UpdatedAt, - EVMChainID: spec.EVMChainID, - ChunkSize: spec.ChunkSize, - RequestTimeout: models.MustMakeDuration(spec.RequestTimeout), - BackoffInitialDelay: models.MustMakeDuration(spec.BackoffInitialDelay), - BackoffMaxDelay: models.MustMakeDuration(spec.BackoffMaxDelay), - GasLanePrice: spec.GasLanePrice, + BatchCoordinatorAddress: spec.BatchCoordinatorAddress, + BatchFulfillmentEnabled: spec.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: float64(spec.BatchFulfillmentGasMultiplier), + CustomRevertsPipelineEnabled: &spec.CustomRevertsPipelineEnabled, + CoordinatorAddress: spec.CoordinatorAddress, + PublicKey: spec.PublicKey, + FromAddresses: spec.FromAddresses, + PollPeriod: models.MustMakeDuration(spec.PollPeriod), + MinIncomingConfirmations: spec.MinIncomingConfirmations, + CreatedAt: spec.CreatedAt, + UpdatedAt: spec.UpdatedAt, + EVMChainID: spec.EVMChainID, + ChunkSize: spec.ChunkSize, + RequestTimeout: models.MustMakeDuration(spec.RequestTimeout), + BackoffInitialDelay: models.MustMakeDuration(spec.BackoffInitialDelay), + BackoffMaxDelay: models.MustMakeDuration(spec.BackoffMaxDelay), + GasLanePrice: spec.GasLanePrice, + RequestedConfsDelay: spec.RequestedConfsDelay, + VRFOwnerAddress: spec.VRFOwnerAddress, } } diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index a5d6db0df1..b782452948 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -14,11 +14,13 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/assets" + evmassets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -58,6 +60,7 @@ func TestJob(t *testing.T) { trustedBlockhashStoreBatchSize := int32(20) var specGasLimit uint32 = 1000 + vrfPubKey, _ := secp256k1.NewPublicKeyFromHex("0xede539e216e3a50e69d1c68aa9cc472085876c4002f6e1e6afee0ea63b50a78b00") testCases := []struct { name string @@ -469,6 +472,90 @@ func TestJob(t *testing.T) { } }`, }, + { + name: "vrf job spec", + job: job.Job{ + ID: 1, + Name: null.StringFrom("vrf_test"), + Type: job.VRF, + SchemaVersion: 1, + ExternalJobID: uuid.MustParse("0eec7e1d-d0d2-476c-a1a8-72dfb6633f47"), + VRFSpec: &job.VRFSpec{ + BatchCoordinatorAddress: &contractAddress, + BatchFulfillmentEnabled: true, + CustomRevertsPipelineEnabled: true, + MinIncomingConfirmations: 1, + CoordinatorAddress: contractAddress, + CreatedAt: timestamp, + UpdatedAt: timestamp, + EVMChainID: evmChainID, + FromAddresses: []ethkey.EIP55Address{fromAddress}, + PublicKey: vrfPubKey, + RequestedConfsDelay: 10, + ChunkSize: 25, + BatchFulfillmentGasMultiplier: 1, + GasLanePrice: evmassets.GWei(200), + VRFOwnerAddress: nil, + }, + PipelineSpec: &pipeline.Spec{ + ID: 1, + DotDagSource: "", + }, + }, + want: fmt.Sprintf(` + { + "data": { + "type": "jobs", + "id": "1", + "attributes": { + "name": "vrf_test", + "type": "vrf", + "schemaVersion": 1, + "maxTaskDuration": "0s", + "externalJobID": "0eec7e1d-d0d2-476c-a1a8-72dfb6633f47", + "directRequestSpec": null, + "fluxMonitorSpec": null, + "gasLimit": null, + "forwardingAllowed": false, + "cronSpec": null, + "offChainReportingOracleSpec": null, + "offChainReporting2OracleSpec": null, + "keeperSpec": null, + "vrfSpec": { + "batchCoordinatorAddress": "%s", + "batchFulfillmentEnabled": true, + "customRevertsPipelineEnabled": true, + "confirmations": 1, + "coordinatorAddress": "%s", + "createdAt": "2000-01-01T00:00:00Z", + "updatedAt": "2000-01-01T00:00:00Z", + "evmChainID": "42", + "fromAddresses": ["%s"], + "pollPeriod": "0s", + "publicKey": "%s", + "requestedConfsDelay": 10, + "requestTimeout": "0s", + "chunkSize": 25, + "batchFulfillmentGasMultiplier": 1, + "backoffInitialDelay": "0s", + "backoffMaxDelay": "0s", + "gasLanePrice": "200 gwei" + }, + "webhookSpec": null, + "blockhashStoreSpec": null, + "blockHeaderFeederSpec": null, + "bootstrapSpec": null, + "pipelineSpec": { + "id": 1, + "jobID": 0, + "dotDagSource": "" + }, + "gatewaySpec": null, + "errors": [] + } + } + }`, contractAddress, contractAddress, fromAddress, vrfPubKey.String()), + }, { name: "blockhash store spec", job: job.Job{ diff --git a/core/web/resolver/spec.go b/core/web/resolver/spec.go index 3e93ea38ea..5e8937dbb9 100644 --- a/core/web/resolver/spec.go +++ b/core/web/resolver/spec.go @@ -641,6 +641,11 @@ func (r *VRFSpecResolver) BatchFulfillmentGasMultiplier() float64 { return float64(r.spec.BatchFulfillmentGasMultiplier) } +// CustomRevertsPipelineEnabled resolves the spec's custom reverts pipeline enabled flag. +func (r *VRFSpecResolver) CustomRevertsPipelineEnabled() *bool { + return &r.spec.CustomRevertsPipelineEnabled +} + // ChunkSize resolves the spec's chunk size. func (r *VRFSpecResolver) ChunkSize() int32 { return int32(r.spec.ChunkSize) diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 277aac851a..a4fb9cdb33 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -581,6 +581,7 @@ func TestResolver_VRFSpec(t *testing.T) { VRFSpec: &job.VRFSpec{ BatchCoordinatorAddress: &batchCoordinatorAddress, BatchFulfillmentEnabled: true, + CustomRevertsPipelineEnabled: true, MinIncomingConfirmations: 1, CoordinatorAddress: coordinatorAddress, CreatedAt: f.Timestamp(), @@ -617,6 +618,7 @@ func TestResolver_VRFSpec(t *testing.T) { batchCoordinatorAddress batchFulfillmentEnabled batchFulfillmentGasMultiplier + customRevertsPipelineEnabled chunkSize backoffInitialDelay backoffMaxDelay @@ -644,6 +646,7 @@ func TestResolver_VRFSpec(t *testing.T) { "batchCoordinatorAddress": "0x0ad9FE7a58216242a8475ca92F222b0640E26B63", "batchFulfillmentEnabled": true, "batchFulfillmentGasMultiplier": 1, + "customRevertsPipelineEnabled": true, "chunkSize": 25, "backoffInitialDelay": "1m0s", "backoffMaxDelay": "1h0m0s", diff --git a/core/web/schema/type/spec.graphql b/core/web/schema/type/spec.graphql index 8124447863..5e24f7c3fa 100644 --- a/core/web/schema/type/spec.graphql +++ b/core/web/schema/type/spec.graphql @@ -97,6 +97,7 @@ type VRFSpec { batchCoordinatorAddress: String batchFulfillmentEnabled: Boolean! batchFulfillmentGasMultiplier: Float! + customRevertsPipelineEnabled: Boolean chunkSize: Int! backoffInitialDelay: String! backoffMaxDelay: String! From 917b74f3a67395f4106f60f70949043f0d989bdf Mon Sep 17 00:00:00 2001 From: Anindita Ghosh <88458927+AnieeG@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:47:26 -0800 Subject: [PATCH 319/327] options to include customized pg and chainlink image (#11570) --- integration-tests/docker/test_env/cl_node.go | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index b79bb91c70..d6ab22957a 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" @@ -83,6 +84,28 @@ func WithLogStream(ls *logstream.LogStream) ClNodeOption { } } +func WithImage(image string) ClNodeOption { + return func(c *ClNode) { + c.ContainerImage = image + } +} + +func WithVersion(version string) ClNodeOption { + return func(c *ClNode) { + c.ContainerVersion = version + } +} + +func WithPgDBOptions(opts ...test_env.PostgresDbOption) ClNodeOption { + return func(c *ClNode) { + var err error + c.PostgresDb, err = test_env.NewPostgresDb(c.EnvComponent.Networks, opts...) + if err != nil { + c.t.Fatalf("failed to create postgres db: %v", err) + } + } +} + func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *chainlink.Config, opts ...ClNodeOption) (*ClNode, error) { nodeDefaultCName := fmt.Sprintf("%s-%s", "cl-node", uuid.NewString()[0:8]) pgDefaultCName := fmt.Sprintf("pg-%s", nodeDefaultCName) From 7a0704f436a4be1fa0d5c607b901265056c69f2d Mon Sep 17 00:00:00 2001 From: Lei Date: Wed, 13 Dec 2023 17:45:54 -0800 Subject: [PATCH 320/327] add readme (#11535) --- core/scripts/chaincli/README.md | 91 ++++++++++++++++++++++++++ core/scripts/chaincli/handler/debug.go | 6 +- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/core/scripts/chaincli/README.md b/core/scripts/chaincli/README.md index da7aa7cc77..bcf407b684 100644 --- a/core/scripts/chaincli/README.md +++ b/core/scripts/chaincli/README.md @@ -122,3 +122,94 @@ You can use the `grep` and `grepv` flags to filter log lines, e.g. to only show ```shell ./chaincli keeper logs --grep keepers-plugin ``` + +--- + +## ChainCLI Automation Debugging Script + +### Context + +The debugging script is a tool within ChainCLI designed to facilitate the debugging of upkeeps in Automation v21, covering both conditional and log-based scenarios. + +### Configuration + +#### Mandatory Fields + +Ensure the following fields are provided in your `.env` file: + +- `NODE_URL`: Archival node URL +- `KEEPER_REGISTRY_ADDRESS`: Address of the Keeper Registry contract. Refer to the [Supported Networks](https://docs.chain.link/chainlink-automation/overview/supported-networks#configurations) doc for addresses. + +#### Additional Fields (Streams Lookup) + +If your targeted upkeep involves streams lookup, include the following information: + +- `MERCURY_ID` +- `MERCURY_KEY` +- `MERCURY_LEGACY_URL` +- `MERCURY_URL` + +#### Tenderly Integration + +For detailed transaction simulation logs, set up Tenderly credentials. Refer to the [Tenderly Documentation](https://docs.tenderly.co/other/platform-access/how-to-generate-api-access-tokens) for creating an API key, account name, and project name. + +- `TENDERLY_KEY` +- `TENDERLY_ACCOUNT_NAME` +- `TENDERLY_PROJECT_NAME` + +### Usage + +Execute the following command based on your upkeep type: + +- For conditional upkeep: + + ```bash + go run main.go keeper debug UPKEEP_ID + ``` + +- For log trigger upkeep: + + ```bash + go run main.go keeper debug UPKEEP_ID TX_HASH LOG_INDEX + ``` + +### Checks Performed by the Debugging Script + +1. **Fetch and Sanity Check Upkeep:** + - Verify upkeep status: active, paused, or canceled + - Check upkeep balance + +2. **For Conditional Upkeep:** + - Check conditional upkeep + - Simulate `performUpkeep` + +3. **For Log Trigger Upkeep:** + - Check if the upkeep has already run for log-trigger-based upkeep + - Verify if log matches trigger configuration + - Check upkeep + - If check result indicates a streams lookup is required (TargetCheckReverted): + - Verify if the upkeep is allowed to use Mercury + - Execute Mercury request + - Execute check callback + + - Simulate `performUpkeep` + +### Examples +- Eligible and log trigger based and using mercury lookup v0.3: + + ```bash + go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xdc6d0e547a5aa85fefa5b0f3a37e3493eafb5aeba8b5f3071ce53c9e9a539e9c 0 + ``` + +- Ineligible and conditional upkeep: + + ```bash + go run main.go keeper debug 52635131310730056105456985154251306793887717546629785340977553840883117540096 + ``` + +- Ineligible and Log does not match trigger config: + + ```bash + go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xc0686ae85d2a7a976ef46df6c613517b9fd46f23340ac583be4e44f5c8b7a186 1 + ``` +--- \ No newline at end of file diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 3e8bd6d597..288c7a68b8 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -111,8 +111,8 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if (upkeepInfo.Target == gethcommon.Address{}) { failCheckArgs("this upkeep does not exist on this registry", nil) } - addLink("upkeep", common.UpkeepLink(chainID, upkeepID)) - addLink("target", common.ContractExplorerLink(chainID, upkeepInfo.Target)) + addLink("upkeep link", common.UpkeepLink(chainID, upkeepID)) + addLink("upkeep contract address", common.ContractExplorerLink(chainID, upkeepInfo.Target)) if upkeepInfo.Paused { resolveIneligible("upkeep is paused") } @@ -180,7 +180,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failCheckArgs("failed to fetch tx receipt", err) } - addLink("trigger", common.ExplorerLink(chainID, txHash)) + addLink("trigger transaction", common.ExplorerLink(chainID, txHash)) blockNum = receipt.BlockNumber.Uint64() // find matching log event in tx var triggeringEvent *types.Log From f874ea608e835edd616937f852b193752cd48db8 Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Thu, 14 Dec 2023 05:42:05 -0500 Subject: [PATCH 321/327] Little Docs Updates (#11569) * Little Docs Updates * Addition --- integration-tests/README.md | 6 ++++++ integration-tests/example.env | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/integration-tests/README.md b/integration-tests/README.md index c0b673fa92..37a8fa19ed 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -26,10 +26,16 @@ e.g. `make build_docker_image image=chainlink tag=test-tag` +You'll want to set the `CHAINLINK_IMAGE` and `CHAINLINK_VERSION` env values appropriately as well. See [example.env](./example.env) for more details. + ## Run `go test ./smoke/_test.go` +Most test files have a couple of tests, it's recommended to look into the file and focus on a specific one if possible. 90% of the time this will probably be the `Basic` test. See [ocr_test.go](./smoke/ocr_test.go) for example, which contains the `TestOCRBasic` test. + +`go test ./smoke/ocr_test.go -run TestOCRBasic` + It's generally recommended to run only one test at a time on a local machine as it needs a lot of docker containers and can peg your resources otherwise. You will see docker containers spin up on your machine for each component of the test where you can inspect logs. ## Analyze diff --git a/integration-tests/example.env b/integration-tests/example.env index 3e27ac2c7a..bbc76bb0c0 100644 --- a/integration-tests/example.env +++ b/integration-tests/example.env @@ -30,15 +30,16 @@ export TEST_UPGRADE_VERSION="2.0.0" # Version of the Chainlink image to upgrade ########## Network Settings ########## +# If running on a live network, you must set the following values # Select a pre-defined network(s) export SELECTED_NETWORKS="SIMULATED" - # General private values that will be retrieved when running on non-simulated networks export EVM_URLS="wss://evm.url,wss://other.url" # Comma-sparated list of websocket URLs to use when running on live networks export EVM_HTTP_URLS="https://evm.url,https://other.url" # Comma-sparated list of HTTP URLs to use when running on live networks export EVM_KEYS="private,funding,keys" # Comma-separated list of private keys to use when running on live networks # Specific private values retrieved when running on specified chains +# Will override the general values above if the SELECTED_NETWORKS contains the network name # Goerli export GOERLI_URLS="wss://goerli.io/ws" export GOERLI_HTTP_URLS="http://goerli.io/ws" From 71e1a796ee3450cd1a0cb20fff8e5f1d46690972 Mon Sep 17 00:00:00 2001 From: Lei Date: Thu, 14 Dec 2023 03:12:22 -0800 Subject: [PATCH 322/327] add unit test to cover 2 check results (#11490) --- .../v21/mercury/streams/streams_test.go | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index 54124b7c1a..40f3275116 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -521,6 +521,69 @@ func TestStreams_StreamsLookup(t *testing.T) { }, }, }, + { + name: "two CheckResults: Mercury success E2E and No Mercury because of insufficient balance", + input: []ocr2keepers.CheckResult{ + { + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), + }, + { + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(mercury.MercuryUpkeepFailureReasonTargetCheckReverted), + }, + }, + blobs: map[string]string{ + "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000": "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3", + "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000": "0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d", + }, + cachedAdminCfg: false, + extraData: hexutil.MustDecode("0x0000000000000000000000000000000000000064"), + callbackNeeded: true, + checkCallbackResp: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063a400000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + values: [][]byte{hexutil.MustDecode("0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3"), hexutil.MustDecode("0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d")}, + expectedResults: []ocr2keepers.CheckResult{ + { + Eligible: false, + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), + }, + { + Eligible: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonNone), + }, + }, + hasPermission: true, + v3: false, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{ + UpkeepNeeded: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + }, nil + }, + }, + }, { name: "success - happy path no cache - v0.3", input: []ocr2keepers.CheckResult{ From e427abbf4baf54e39281ee83495352c2de0ff02d Mon Sep 17 00:00:00 2001 From: frank zhu Date: Thu, 14 Dec 2023 06:41:44 -0800 Subject: [PATCH 323/327] add CI test for core/scripts (#11466) * add CI test for core/scripts * refactor * refactor golangci-lint build binary step * add ubig pkg * refactor based on suggestions --- .github/actions/golangci-lint/action.yml | 7 +--- .github/workflows/ci-chaincli.yml | 22 ------------ .github/workflows/ci-scripts.yml | 46 ++++++++++++++++++++++++ core/scripts/functions/src/fetching.go | 1 + 4 files changed, 48 insertions(+), 28 deletions(-) delete mode 100644 .github/workflows/ci-chaincli.yml create mode 100644 .github/workflows/ci-scripts.yml diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index 055960ff28..0047c6a54b 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -42,14 +42,9 @@ runs: shell: bash run: mkdir -p core/web/assets && touch core/web/assets/index.html - name: Build binary - if: ${{ inputs.go-directory == '.' }} - shell: bash - run: go build ./... - - name: Build binary - if: ${{ inputs.go-directory != '.' }} working-directory: ${{ inputs.go-directory }} shell: bash - run: go build + run: go build ./... - name: golangci-lint uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: diff --git a/.github/workflows/ci-chaincli.yml b/.github/workflows/ci-chaincli.yml deleted file mode 100644 index 8a9ab03d76..0000000000 --- a/.github/workflows/ci-chaincli.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: chaincli CI - -on: - push: - pull_request: - -jobs: - golangci: - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' }} - name: chaincli-lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Golang Lint - uses: ./.github/actions/golangci-lint - with: - name: chaincli-lint - go-directory: core/scripts/chaincli - go-version-file: core/scripts/go.mod - go-module-file: core/scripts/go.sum - gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml new file mode 100644 index 0000000000..e83c22520c --- /dev/null +++ b/.github/workflows/ci-scripts.yml @@ -0,0 +1,46 @@ +name: CI Scripts + +on: + push: + pull_request: + +jobs: + golangci: + if: ${{ github.event_name == 'pull_request' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Golang Lint + uses: ./.github/actions/golangci-lint + with: + name: scripts-lint + go-directory: core/scripts + go-version-file: core/scripts/go.mod + go-module-file: core/scripts/go.sum + gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} + + test: + if: ${{ github.event_name == 'pull_request' }} + name: scripts-test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Go + uses: ./.github/actions/setup-go + with: + go-version-file: core/scripts/go.mod + go-module-file: core/scripts/go.sum + - name: Run Tests + shell: bash + working-directory: core/scripts + run: go test ./... + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: scripts-test + continue-on-error: true diff --git a/core/scripts/functions/src/fetching.go b/core/scripts/functions/src/fetching.go index 9be624a40b..cbe491fff5 100644 --- a/core/scripts/functions/src/fetching.go +++ b/core/scripts/functions/src/fetching.go @@ -11,6 +11,7 @@ import ( "github.com/urfave/cli" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) From 147721d5e1490d1cde18454da026f7a8804618f8 Mon Sep 17 00:00:00 2001 From: AnieeG Date: Thu, 14 Dec 2023 12:24:09 -0800 Subject: [PATCH 324/327] merge core develop -> ccip-develop merge core develop -> ccip-develop fix conflicts, build use openzeppelin-solidity v4.8.3 add ERC165Checker.sol to the vendor, wasn't there before add missing file update shared snapshot update gethwrappers add ERC165.sol to fix metatx compile update generated files update modgraph fix one config test fix some config tests fix config again more config test fixes bump mockery version in contracts makefile go.mod updates more updates remove integration-tests dependencies USDC filter fix (#383) fix integration-tests go mod more fixes fix lint errors fix TestSecrets_Validate fix TestResolver_ConfigV2 fix TestIntegration_CCIP try using crypto/rand remove build-publish-pr.yml skip metatx test --- .github/workflows/build-publish-pr.yml | 64 - contracts/GNUmakefile | 6 +- contracts/STYLE_GUIDE.md | 24 +- contracts/gas-snapshots/shared.gas-snapshot | 8 + contracts/src/v0.8/ccip/PriceRegistry.sol | 2 +- contracts/src/v0.8/ccip/Router.sol | 6 +- .../ccip/applications/CCIPClientExample.sol | 2 +- .../v0.8/ccip/applications/CCIPReceiver.sol | 2 +- .../ccip/applications/DefensiveExample.sol | 6 +- .../v0.8/ccip/applications/PingPongDemo.sol | 2 +- .../ccip/applications/SelfFundedPingPong.sol | 2 +- .../src/v0.8/ccip/applications/TokenProxy.sol | 4 +- .../ccip/interfaces/IEVM2AnyOnRampClient.sol | 2 +- .../v0.8/ccip/interfaces/IWrappedNative.sol | 2 +- .../src/v0.8/ccip/interfaces/pools/IPool.sol | 2 +- .../src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol | 6 +- .../src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol | 6 +- .../v0.8/ccip/pools/BurnFromMintTokenPool.sol | 2 +- .../ccip/pools/BurnWithFromMintTokenPool.sol | 2 +- .../v0.8/ccip/pools/LockReleaseTokenPool.sol | 4 +- contracts/src/v0.8/ccip/pools/TokenPool.sol | 6 +- .../v0.8/ccip/pools/USDC/USDCTokenPool.sol | 6 +- .../test/applications/ImmutableExample.t.sol | 2 +- .../applications/SelfFundedPingPong.t.sol | 2 +- .../ccip/test/applications/TokenProxy.t.sol | 2 +- .../ccip/test/attacks/onRamp/FacadeClient.sol | 2 +- .../onRamp/OnRampTokenPoolReentrancy.t.sol | 2 +- .../onRamp/ReentrantMaliciousTokenPool.sol | 2 +- .../ccip/test/helpers/CustomTokenPool.sol | 2 +- .../receivers/MaybeRevertMessageReceiver.sol | 2 +- .../v0.8/ccip/test/mocks/MockTokenPool.sol | 2 +- .../test/offRamp/EVM2EVMOffRampSetup.t.sol | 2 +- .../test/pools/LockReleaseTokenPool.t.sol | 2 +- .../v0.8/ccip/test/pools/USDCTokenPool.t.sol | 2 +- contracts/src/v0.8/metatx/BankERC20.sol | 4 +- contracts/src/v0.8/metatx/Forwarder.sol | 4 +- contracts/src/v0.8/metatx/IForwarder.sol | 2 +- .../enumerable/EnumerableMapAddresses.sol | 2 +- .../contracts/utils/introspection/ERC165.sol | 29 + .../utils/introspection/ERC165Checker.sol | 127 ++ .../evm/gas/block_history_estimator_test.go | 3 +- .../gas/rollups/l1_gas_price_oracle_test.go | 2 +- core/chains/evm/logpoller/mocks/log_poller.go | 6 - core/chains/evm/logpoller/query.go | 12 - .../generated/arm_contract/arm_contract.go | 2 +- .../arm_proxy_contract/arm_proxy_contract.go | 2 +- .../burn_from_mint_token_pool.go | 2 +- .../burn_mint_token_pool.go | 2 +- .../burn_with_from_mint_token_pool.go | 2 +- .../generated/commit_store/commit_store.go | 2 +- .../commit_store_helper.go | 2 +- .../custom_token_pool/custom_token_pool.go | 2 +- .../evm_2_evm_offramp/evm_2_evm_offramp.go | 2 +- .../evm_2_evm_onramp/evm_2_evm_onramp.go | 2 +- .../lock_release_token_pool.go | 2 +- .../maybe_revert_message_receiver.go | 2 +- .../mock_arm_contract/mock_arm_contract.go | 2 +- .../ping_pong_demo/ping_pong_demo.go | 2 +- .../price_registry/price_registry.go | 2 +- .../ccip/generated/router/router.go | 2 +- .../self_funded_ping_pong.go | 2 +- .../usdc_token_pool/usdc_token_pool.go | 2 +- .../ccip/generated/weth9/weth9.go | 2 +- .../ccip/mocks/commit_store_interface.go | 214 ++- .../ccip/mocks/evm2_evm_off_ramp_interface.go | 246 ++- .../ccip/mocks/evm2_evm_on_ramp_interface.go | 254 ++- .../ccip/mocks/link_token_interface.go | 82 +- .../ccip/mocks/price_registry_interface.go | 170 +- .../generated/bank_erc20/bank_erc20.go | 2 +- .../generated/forwarder/forwarder.go | 2 +- ...rapper-dependency-versions-do-not-edit.txt | 2 + core/scripts/go.mod | 78 +- core/scripts/go.sum | 480 +----- core/services/chainlink/application.go | 4 +- core/services/chainlink/config_test.go | 2 + .../testdata/config-empty-effective.toml | 1 + .../chainlink/testdata/config-full.toml | 1 + .../config-multi-chain-effective.toml | 3 +- core/services/fluxmonitorv2/delegate.go | 2 +- core/services/keeper/delegate.go | 2 +- core/services/metatx/integration_test.go | 13 +- .../plugins/ccip/clo_ccip_integration_test.go | 2 +- .../ocr2/plugins/ccip/commit_plugin.go | 8 +- .../ocr2/plugins/ccip/commit_plugin_test.go | 4 +- .../plugins/ccip/commit_reporting_plugin.go | 3 +- .../ocr2/plugins/ccip/config/chain_config.go | 8 +- .../plugins/ccip/config/chain_config_test.go | 14 +- .../ocr2/plugins/ccip/config/config_test.go | 3 +- .../ocr2/plugins/ccip/execution_plugin.go | 19 +- .../plugins/ccip/execution_plugin_test.go | 4 +- .../ocr2/plugins/ccip/integration_test.go | 4 +- .../plugins/ccip/internal/cache/autosync.go | 4 +- .../ccipdata/commit_store_reader_test.go | 2 +- .../mocks/commit_store_reader_mock.go | 62 +- .../ccipdata/mocks/offramp_reader_mock.go | 74 +- .../ccipdata/mocks/onramp_reader_mock.go | 26 +- .../mocks/price_registry_reader_mock.go | 30 +- .../ccipdata/mocks/usdc_reader_mock.go | 34 +- .../internal/ccipdata/offramp_reader_test.go | 3 +- .../internal/ccipdata/onramp_reader_test.go | 6 +- .../ccipdata/price_registry_reader_test.go | 3 +- .../ccip/internal/ccipdata/usdc_reader.go | 33 +- .../ccipdata/usdc_reader_internal_test.go | 4 +- .../internal/ccipdata/usdc_reader_test.go | 1 + .../plugins/ccip/internal/pricegetter/mock.go | 6 +- .../internal/pricegetter/pipeline_test.go | 2 +- .../internal/rpclib/rpclibmocks/evm_mock.go | 6 +- core/services/ocr2/plugins/ccip/metrics.go | 4 + .../ocr2/plugins/ccip/observations_test.go | 6 +- .../ccip/prices/da_price_estimator_test.go | 2 +- .../ccip/prices/exec_price_estimator.go | 2 +- .../ccip/prices/exec_price_estimator_test.go | 2 +- .../prices/gas_price_estimator_commit_mock.go | 22 +- .../prices/gas_price_estimator_exec_mock.go | 22 +- .../ccip/prices/gas_price_estimator_mock.go | 26 +- .../ccip/testhelpers/integration/chainlink.go | 55 +- .../ccip/testhelpers/integration/jobspec.go | 152 +- .../ccip/tokendata/http/http_client.go | 2 +- .../ocr2/plugins/ccip/tokendata/reader.go | 1 + .../plugins/ccip/tokendata/reader_mock.go | 34 +- .../ocr2/plugins/ccip/tokendata/usdc/usdc.go | 4 + .../plugins/ccip/tokendata/usdc/usdc_test.go | 6 +- .../logprovider/provider_life_cycle_test.go | 3 +- core/services/ocr2/validate/validate.go | 2 +- core/services/relay/evm/ccip.go | 24 +- core/services/relay/evm/evm.go | 6 +- core/services/relay/evm/ocr2keeper.go | 2 +- core/services/relay/evm/ocr2vrf.go | 4 +- .../testdata/config-empty-effective.toml | 1 + core/web/resolver/testdata/config-full.toml | 1 + .../config-multi-chain-effective.toml | 3 +- docs/CONFIG.md | 255 +-- go.md | 5 + go.mod | 108 +- go.sum | 559 +----- .../actions/automation_ocr_helpers.go | 3 - .../ccip-tests/actions/ccip_helpers.go | 278 ++- .../ccip-tests/chaos/ccip_test.go | 3 +- .../ccip-tests/contracts/contract_deployer.go | 19 +- .../ccip-tests/contracts/contract_models.go | 44 +- .../ccip-tests/contracts/multicall.go | 3 +- .../ccip-tests/load/ccip_loadgen.go | 4 +- .../ccip-tests/load/ccip_multicall_loadgen.go | 11 +- .../ccip-tests/load/ccip_test.go | 16 +- integration-tests/ccip-tests/load/helper.go | 32 +- .../ccip-tests/smoke/ccip_test.go | 3 +- .../ccip-tests/testconfig/global.go | 20 +- .../ccip-tests/testconfig/tomls/default.toml | 4 - .../ccip-tests/testreporters/ccip.go | 11 +- .../ccip-tests/testsetups/ccip.go | 48 +- .../ccip-tests/testsetups/test_env.go | 27 +- .../ccip-tests/types/config/node/core.go | 6 +- integration-tests/client/chainlink.go | 5 + integration-tests/go.mod | 196 ++- integration-tests/go.sum | 1505 ++++++++++++----- integration-tests/load/automationv2_1/gun.go | 6 +- .../load/functions/gateway_gun.go | 18 +- .../load/functions/request_gun.go | 20 +- integration-tests/load/ocr/README.md | 8 - integration-tests/load/ocr/gun.go | 9 +- integration-tests/load/ocr/vu.go | 6 +- integration-tests/load/vrfv2/gun.go | 6 +- integration-tests/load/vrfv2plus/gun.go | 6 +- integration-tests/universal/log_poller/gun.go | 8 +- operator_ui/TAG | 4 - testdata/scripts/node/validate/default.txtar | 16 - .../disk-based-logging-disabled.txtar | 16 - .../validate/disk-based-logging-no-dir.txtar | 16 - .../node/validate/disk-based-logging.txtar | 16 - testdata/scripts/node/validate/invalid.txtar | 16 - testdata/scripts/node/validate/valid.txtar | 16 - testdata/scripts/node/validate/warnings.txtar | 82 - 172 files changed, 3504 insertions(+), 2658 deletions(-) delete mode 100644 .github/workflows/build-publish-pr.yml create mode 100644 contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol create mode 100644 contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml deleted file mode 100644 index cdc9cf3f11..0000000000 --- a/.github/workflows/build-publish-pr.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: "Build and Publish from PR" - -## -# This workflow builds and publishes a Docker image for Chainlink from a PR. -# It doesn't use an environment, has its own special IAM role, does not sign -# the image, and publishes to a special ECR repo. -## - -on: - pull_request: - -jobs: - build-publish-untrusted: - if: ${{ ! startsWith(github.ref_name, 'release/') }} - runs-on: ubuntu-20.04 - permissions: - id-token: write - contents: read - env: - ECR_IMAGE_NAME: crib-chainlink-untrusted - steps: - - name: Git Short SHA - shell: bash - env: - GIT_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - run: | - echo "GIT_SHORT_SHA=${GIT_PR_HEAD_SHA:0:7}" | tee -a "$GITHUB_ENV" - - - name: Check if image exists - id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - with: - repository: ${{ env.ECR_IMAGE_NAME}} - tag: sha-${{ env.GIT_SHORT_SHA }} - AWS_REGION: ${{ secrets.AWS_REGION }} - AWS_ROLE_TO_ASSUME: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} - - - name: Checkout repository - if: steps.check-image.outputs.exists == 'false' - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Build and publish chainlink image - if: steps.check-image.outputs.exists == 'false' - uses: ./.github/actions/build-sign-publish-chainlink - with: - publish: true - aws-role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} - aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS_DEFAULT }} - aws-region: ${{ secrets.AWS_REGION }} - sign-images: false - ecr-hostname: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }} - ecr-image-name: ${{ env.ECR_IMAGE_NAME }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: build-publish-untrusted - continue-on-error: true diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index d38ed0b403..af73bf21c2 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -1,5 +1,5 @@ # ALL_FOUNDRY_PRODUCTS contains a list of all products that have a foundry -# profile defined and use the Foundry snapshots. +# profile defined and use the Foundry snapshots. ALL_FOUNDRY_PRODUCTS = llo-feeds functions shared ccip # To make a snapshot for a specific product, either set the `FOUNDRY_PROFILE` env var @@ -39,7 +39,7 @@ abigen: ## Build & install abigen. .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.35.4 + go install github.com/vektra/mockery/v2@v2.38.0 .PHONY: foundry foundry: ## Install foundry. @@ -109,4 +109,4 @@ help: @echo " \/ \/ \/ \/ \/ \/" @echo "" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \ - awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' \ No newline at end of file + awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/contracts/STYLE_GUIDE.md b/contracts/STYLE_GUIDE.md index 3868117d4b..192694eca9 100644 --- a/contracts/STYLE_GUIDE.md +++ b/contracts/STYLE_GUIDE.md @@ -1,7 +1,7 @@ # Structure -This guide is split into two sections: [Guidelines](#guidelines) and [Rules](#rules). -Guidelines are recommendations that should be followed but are hard to enforce in an automated way. +This guide is split into two sections: [Guidelines](#guidelines) and [Rules](#rules). +Guidelines are recommendations that should be followed but are hard to enforce in an automated way. Rules are all enforced through CI, this can be through Solhint rules or other tools. ## Background @@ -27,7 +27,7 @@ We will be looking into `forge fmt`, but for now we still use `prettier`. - This `dev` folder also has implications for when code is valid for bug bounties, so be extra careful to move functionality out of a `dev` folder. -## comments +## comments - Besides comment above functions/structs, comments should live everywhere a reader might be confused. Don’t overestimate the reader of your contract, expect confusion in many places and document accordingly. This will help massively during audits and onboarding new team members. @@ -78,11 +78,11 @@ uint256 networkFeeUSDCents; // good struct FeeTokenConfigArgs { address token; // ────────────╮ Token address uint32 networkFeeUSD; // │ Flat network fee to charge for messages, multiples of 0.01 USD - // │ multiline comments should work like this. More fee info + // │ multiline comments should work like this. More fee info uint64 gasMultiplier; // ─────╯ Price multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost uint64 premiumMultiplier; // ─╮ Multiplier for fee-token-specific premiums bool enabled; // ─────────────╯ Whether this fee token is enabled - uint256 fee; // The flat fee the user pays in juels + uint256 fee; // The flat fee the user pays in juels } ``` ## Functions @@ -134,7 +134,7 @@ assembly { // call and return whether we succeeded. ignore return data // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0, 0) - + // limit our copy to maxReturnBytes bytes let toCopy := returndatasize() if gt(toCopy, maxReturnBytes) { @@ -246,7 +246,7 @@ contract AccessControlledFoo is Foo { contract OffchainAggregator is ITypeAndVersion { // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "OffchainAggregator 1.0.0"; - + function getData() public returns(uint256) { return 4; } @@ -256,7 +256,7 @@ contract OffchainAggregator is ITypeAndVersion { contract SuperDuperAggregator is ITypeAndVersion { /// This is a new contract that has not been released yet, so we /// add a `-dev` suffix to the typeAndVersion. - + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "SuperDuperAggregator 1.1.0-dev"; @@ -316,8 +316,8 @@ import {IPool} from "../interfaces/pools/IPool.sol"; import {AggregateRateLimiter} from "../AggregateRateLimiter.sol"; import {Client} from "../libraries/Client.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; ``` ## Variables @@ -386,6 +386,6 @@ rule: `custom-errors` ## Interfaces -Interfaces should be named `IFoo` instead of `FooInterface`. This follows the patterns of popular [libraries like OpenZeppelin’s](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L9). +Interfaces should be named `IFoo` instead of `FooInterface`. This follows the patterns of popular [libraries like OpenZeppelin’s](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L9). -rule: `tbd` \ No newline at end of file +rule: `tbd` diff --git a/contracts/gas-snapshots/shared.gas-snapshot b/contracts/gas-snapshots/shared.gas-snapshot index 6f307d257f..e0983697e9 100644 --- a/contracts/gas-snapshots/shared.gas-snapshot +++ b/contracts/gas-snapshots/shared.gas-snapshot @@ -41,6 +41,14 @@ CallWithExactGas__callWithExactGasSafeReturnData:test_CallWithExactGasSafeReturn CallWithExactGas__callWithExactGasSafeReturnData:test_NoContractReverts() (gas: 13949) CallWithExactGas__callWithExactGasSafeReturnData:test_NoGasForCallExactCheckReverts() (gas: 13239) CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 13670) +EnumerableMapAddresses_at:testAtSuccess() (gas: 98813) +EnumerableMapAddresses_contains:testContainsSuccess() (gas: 97480) +EnumerableMapAddresses_get:testGetSuccess() (gas: 98781) +EnumerableMapAddresses_get_errorMessage:testGetErrorMessageSuccess() (gas: 99220) +EnumerableMapAddresses_length:testLengthSuccess() (gas: 76136) +EnumerableMapAddresses_remove:testRemoveSuccess() (gas: 78050) +EnumerableMapAddresses_set:testSetSuccess() (gas: 99129) +EnumerableMapAddresses_tryGet:testTryGetSuccess() (gas: 99170) OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1739317) OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 263373) OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957) diff --git a/contracts/src/v0.8/ccip/PriceRegistry.sol b/contracts/src/v0.8/ccip/PriceRegistry.sol index e13ea6cfed..cbc6914f7e 100644 --- a/contracts/src/v0.8/ccip/PriceRegistry.sol +++ b/contracts/src/v0.8/ccip/PriceRegistry.sol @@ -8,7 +8,7 @@ import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol"; import {Internal} from "./libraries/Internal.sol"; import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol"; -import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; +import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; /// @notice The PriceRegistry contract responsibility is to store the current gas price in USD for a given destination chain, /// and the price of a token in USD allowing the owner or priceUpdater to update this value. diff --git a/contracts/src/v0.8/ccip/Router.sol b/contracts/src/v0.8/ccip/Router.sol index ac7bc02bd0..9b2ce03aeb 100644 --- a/contracts/src/v0.8/ccip/Router.sol +++ b/contracts/src/v0.8/ccip/Router.sol @@ -14,9 +14,9 @@ import {Internal} from "./libraries/Internal.sol"; import {CallWithExactGas} from "../shared/call/CallWithExactGas.sol"; import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol"; -import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; +import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; /// @title Router /// @notice This is the entry point for the end user wishing to send data across chains. diff --git a/contracts/src/v0.8/ccip/applications/CCIPClientExample.sol b/contracts/src/v0.8/ccip/applications/CCIPClientExample.sol index 431ddbe99e..dd9c6502d9 100644 --- a/contracts/src/v0.8/ccip/applications/CCIPClientExample.sol +++ b/contracts/src/v0.8/ccip/applications/CCIPClientExample.sol @@ -7,7 +7,7 @@ import {Client} from "../libraries/Client.sol"; import {CCIPReceiver} from "./CCIPReceiver.sol"; import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; // @notice Example of a client which supports EVM/non-EVM chains // @dev If chain specific logic is required for different chain families (e.g. particular diff --git a/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol b/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol index 615f0d5b01..cea7cbe0af 100644 --- a/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol +++ b/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol @@ -5,7 +5,7 @@ import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol import {Client} from "../libraries/Client.sol"; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; /// @title CCIPReceiver - Base contract for CCIP applications that can receive messages. abstract contract CCIPReceiver is IAny2EVMMessageReceiver, IERC165 { diff --git a/contracts/src/v0.8/ccip/applications/DefensiveExample.sol b/contracts/src/v0.8/ccip/applications/DefensiveExample.sol index 66be7bef63..0c996b3190 100644 --- a/contracts/src/v0.8/ccip/applications/DefensiveExample.sol +++ b/contracts/src/v0.8/ccip/applications/DefensiveExample.sol @@ -6,9 +6,9 @@ import {IRouterClient} from "../interfaces/IRouterClient.sol"; import {Client} from "../libraries/Client.sol"; import {CCIPClientExample} from "./CCIPClientExample.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; -import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; contract DefensiveExample is CCIPClientExample { using EnumerableMap for EnumerableMap.Bytes32ToUintMap; diff --git a/contracts/src/v0.8/ccip/applications/PingPongDemo.sol b/contracts/src/v0.8/ccip/applications/PingPongDemo.sol index 750cae956c..f9820ef1ff 100644 --- a/contracts/src/v0.8/ccip/applications/PingPongDemo.sol +++ b/contracts/src/v0.8/ccip/applications/PingPongDemo.sol @@ -8,7 +8,7 @@ import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol"; import {Client} from "../libraries/Client.sol"; import {CCIPReceiver} from "./CCIPReceiver.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; /// @title PingPongDemo - A simple ping-pong contract for demonstrating cross-chain communication contract PingPongDemo is CCIPReceiver, OwnerIsCreator, ITypeAndVersion { diff --git a/contracts/src/v0.8/ccip/applications/SelfFundedPingPong.sol b/contracts/src/v0.8/ccip/applications/SelfFundedPingPong.sol index 696dc79e77..719d8678fe 100644 --- a/contracts/src/v0.8/ccip/applications/SelfFundedPingPong.sol +++ b/contracts/src/v0.8/ccip/applications/SelfFundedPingPong.sol @@ -6,7 +6,7 @@ import {Client} from "../libraries/Client.sol"; import {Router} from "../Router.sol"; import {EVM2EVMOnRamp} from "../onRamp/EVM2EVMOnRamp.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract SelfFundedPingPong is PingPongDemo { // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables diff --git a/contracts/src/v0.8/ccip/applications/TokenProxy.sol b/contracts/src/v0.8/ccip/applications/TokenProxy.sol index 41fab9252a..1c9b725192 100644 --- a/contracts/src/v0.8/ccip/applications/TokenProxy.sol +++ b/contracts/src/v0.8/ccip/applications/TokenProxy.sol @@ -6,8 +6,8 @@ import {IRouterClient} from "../interfaces/IRouterClient.sol"; import {Client} from "../libraries/Client.sol"; import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract TokenProxy is OwnerIsCreator { using SafeERC20 for IERC20; diff --git a/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRampClient.sol b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRampClient.sol index 0249214e79..b25128f49f 100644 --- a/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRampClient.sol +++ b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRampClient.sol @@ -5,7 +5,7 @@ import {IPool} from "./pools/IPool.sol"; import {Client} from "../libraries/Client.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; interface IEVM2AnyOnRampClient { /// @notice Get the fee for a given ccip message diff --git a/contracts/src/v0.8/ccip/interfaces/IWrappedNative.sol b/contracts/src/v0.8/ccip/interfaces/IWrappedNative.sol index 283dcee738..cc9d3e289f 100644 --- a/contracts/src/v0.8/ccip/interfaces/IWrappedNative.sol +++ b/contracts/src/v0.8/ccip/interfaces/IWrappedNative.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; interface IWrappedNative is IERC20 { function deposit() external payable; diff --git a/contracts/src/v0.8/ccip/interfaces/pools/IPool.sol b/contracts/src/v0.8/ccip/interfaces/pools/IPool.sol index c7dcffa4e5..f1a8dbd99f 100644 --- a/contracts/src/v0.8/ccip/interfaces/pools/IPool.sol +++ b/contracts/src/v0.8/ccip/interfaces/pools/IPool.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; // Shared public interface for multiple pool types. // Each pool type handles a different child token model (lock/unlock, mint/burn.) diff --git a/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol b/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol index 6035362676..61dce72313 100644 --- a/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol +++ b/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol @@ -18,9 +18,9 @@ import {OCR2BaseNoChecks} from "../ocr/OCR2BaseNoChecks.sol"; import {AggregateRateLimiter} from "../AggregateRateLimiter.sol"; import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {Address} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; -import {ERC165Checker} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/ERC165Checker.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {Address} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; +import {ERC165Checker} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol"; /// @notice EVM2EVMOffRamp enables OCR networks to execute multiple messages /// in an OffRamp in a single transaction. diff --git a/contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol b/contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol index 6f0b75bbc7..9ec6ccad26 100644 --- a/contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol +++ b/contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol @@ -16,9 +16,9 @@ import {RateLimiter} from "../libraries/RateLimiter.sol"; import {USDPriceWith18Decimals} from "../libraries/USDPriceWith18Decimals.sol"; import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; /// @notice The onRamp is a contract that handles lane-specific fee logic, NOP payments and /// bridgeable token support. diff --git a/contracts/src/v0.8/ccip/pools/BurnFromMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/BurnFromMintTokenPool.sol index 08c9f2555d..cb0a2a1099 100644 --- a/contracts/src/v0.8/ccip/pools/BurnFromMintTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/BurnFromMintTokenPool.sol @@ -7,7 +7,7 @@ import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; import {TokenPool} from "./TokenPool.sol"; import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /// @notice This pool mints and burns a 3rd-party token. /// @dev Pool whitelisting mode is set in the constructor and cannot be modified later. diff --git a/contracts/src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol index 2d9d0ee15a..86d069cafa 100644 --- a/contracts/src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol @@ -7,7 +7,7 @@ import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; import {TokenPool} from "./TokenPool.sol"; import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /// @notice This pool mints and burns a 3rd-party token. /// @dev Pool whitelisting mode is set in the constructor and cannot be modified later. diff --git a/contracts/src/v0.8/ccip/pools/LockReleaseTokenPool.sol b/contracts/src/v0.8/ccip/pools/LockReleaseTokenPool.sol index 19ea83c254..1d54c3f236 100644 --- a/contracts/src/v0.8/ccip/pools/LockReleaseTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/LockReleaseTokenPool.sol @@ -5,8 +5,8 @@ import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {TokenPool} from "./TokenPool.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /// @notice Token pool used for tokens on their native chain. This uses a lock and release mechanism. /// Because of lock/unlock requiring liquidity, this pool contract also has function to add and remove diff --git a/contracts/src/v0.8/ccip/pools/TokenPool.sol b/contracts/src/v0.8/ccip/pools/TokenPool.sol index 7bf9bce40e..83dfa977c4 100644 --- a/contracts/src/v0.8/ccip/pools/TokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/TokenPool.sol @@ -7,9 +7,9 @@ import {IARM} from "../interfaces/IARM.sol"; import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; -import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; /// @notice Base abstract class with common functions for all token pools. /// A token pool serves as isolated place for holding tokens and token specific logic diff --git a/contracts/src/v0.8/ccip/pools/USDC/USDCTokenPool.sol b/contracts/src/v0.8/ccip/pools/USDC/USDCTokenPool.sol index 843a7682d1..1977e4ace8 100644 --- a/contracts/src/v0.8/ccip/pools/USDC/USDCTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/USDC/USDCTokenPool.sol @@ -7,9 +7,9 @@ import {IMessageTransmitter} from "./IMessageTransmitter.sol"; import {TokenPool} from "../TokenPool.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; /// @notice This pool mints and burns USDC tokens through the Cross Chain Transfer /// Protocol (CCTP). diff --git a/contracts/src/v0.8/ccip/test/applications/ImmutableExample.t.sol b/contracts/src/v0.8/ccip/test/applications/ImmutableExample.t.sol index befc2cc07c..52d0a359ff 100644 --- a/contracts/src/v0.8/ccip/test/applications/ImmutableExample.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/ImmutableExample.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import "../onRamp/EVM2EVMOnRampSetup.t.sol"; import "../../applications/CCIPClientExample.sol"; -import {ERC165Checker} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/ERC165Checker.sol"; +import {ERC165Checker} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol"; contract CCIPClientExample_sanity is EVM2EVMOnRampSetup { function testExamples() public { diff --git a/contracts/src/v0.8/ccip/test/applications/SelfFundedPingPong.t.sol b/contracts/src/v0.8/ccip/test/applications/SelfFundedPingPong.t.sol index 04118ef16d..f5be6f539e 100644 --- a/contracts/src/v0.8/ccip/test/applications/SelfFundedPingPong.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/SelfFundedPingPong.t.sol @@ -6,7 +6,7 @@ import {EVM2EVMOnRampSetup} from "../onRamp/EVM2EVMOnRampSetup.t.sol"; import {EVM2EVMOnRamp} from "../../onRamp/EVM2EVMOnRamp.sol"; import {Client} from "../../libraries/Client.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract SelfFundedPingPongDappSetup is EVM2EVMOnRampSetup { event Ping(uint256 pingPongs); diff --git a/contracts/src/v0.8/ccip/test/applications/TokenProxy.t.sol b/contracts/src/v0.8/ccip/test/applications/TokenProxy.t.sol index 6e27b73ee8..da59327497 100644 --- a/contracts/src/v0.8/ccip/test/applications/TokenProxy.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/TokenProxy.t.sol @@ -6,7 +6,7 @@ import {TokenProxy} from "../../applications/TokenProxy.sol"; import {Client} from "../../libraries/Client.sol"; import {Internal} from "../../libraries/Internal.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract TokenProxySetup is EVM2EVMOnRampSetup { TokenProxy internal s_tokenProxy; diff --git a/contracts/src/v0.8/ccip/test/attacks/onRamp/FacadeClient.sol b/contracts/src/v0.8/ccip/test/attacks/onRamp/FacadeClient.sol index 5b52dc4ef5..4621cf3530 100644 --- a/contracts/src/v0.8/ccip/test/attacks/onRamp/FacadeClient.sol +++ b/contracts/src/v0.8/ccip/test/attacks/onRamp/FacadeClient.sol @@ -7,7 +7,7 @@ import {OwnerIsCreator} from "../../../../shared/access/OwnerIsCreator.sol"; import {Client} from "../../../libraries/Client.sol"; import {CCIPReceiver} from "../../../applications/CCIPReceiver.sol"; -import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; /// @title FacadeClient - A simple proxy for calling Router contract FacadeClient { diff --git a/contracts/src/v0.8/ccip/test/attacks/onRamp/OnRampTokenPoolReentrancy.t.sol b/contracts/src/v0.8/ccip/test/attacks/onRamp/OnRampTokenPoolReentrancy.t.sol index 11ab97a5fe..d5f3a5e05f 100644 --- a/contracts/src/v0.8/ccip/test/attacks/onRamp/OnRampTokenPoolReentrancy.t.sol +++ b/contracts/src/v0.8/ccip/test/attacks/onRamp/OnRampTokenPoolReentrancy.t.sol @@ -7,7 +7,7 @@ import {FacadeClient} from "./FacadeClient.sol"; import {ReentrantMaliciousTokenPool} from "./ReentrantMaliciousTokenPool.sol"; import {EVM2EVMOnRampSetup} from "../../onRamp/EVM2EVMOnRampSetup.t.sol"; -import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; /// @title OnRampTokenPoolReentrancy /// Attempts to perform a reentrancy exploit on Onramp with a malicious TokenPool diff --git a/contracts/src/v0.8/ccip/test/attacks/onRamp/ReentrantMaliciousTokenPool.sol b/contracts/src/v0.8/ccip/test/attacks/onRamp/ReentrantMaliciousTokenPool.sol index 4bddca5c02..5444917b79 100644 --- a/contracts/src/v0.8/ccip/test/attacks/onRamp/ReentrantMaliciousTokenPool.sol +++ b/contracts/src/v0.8/ccip/test/attacks/onRamp/ReentrantMaliciousTokenPool.sol @@ -5,7 +5,7 @@ import {FacadeClient} from "./FacadeClient.sol"; import {RateLimiter} from "../../../libraries/RateLimiter.sol"; import {TokenPool} from "../../../pools/TokenPool.sol"; -import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract ReentrantMaliciousTokenPool is TokenPool { address private i_facade; diff --git a/contracts/src/v0.8/ccip/test/helpers/CustomTokenPool.sol b/contracts/src/v0.8/ccip/test/helpers/CustomTokenPool.sol index fc19f7b26d..0f00288a3a 100644 --- a/contracts/src/v0.8/ccip/test/helpers/CustomTokenPool.sol +++ b/contracts/src/v0.8/ccip/test/helpers/CustomTokenPool.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.19; import {TokenPool} from "../../pools/TokenPool.sol"; import {RateLimiter} from "../../libraries/RateLimiter.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract CustomTokenPool is TokenPool { event SynthBurned(uint256 amount); diff --git a/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol index c4488166f2..e687ed697f 100644 --- a/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol +++ b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.19; import "../../../interfaces/IAny2EVMMessageReceiver.sol"; -import "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; contract MaybeRevertMessageReceiver is IAny2EVMMessageReceiver, IERC165 { error ReceiveRevert(); diff --git a/contracts/src/v0.8/ccip/test/mocks/MockTokenPool.sol b/contracts/src/v0.8/ccip/test/mocks/MockTokenPool.sol index d8ef17f0c6..69bdeee3b7 100644 --- a/contracts/src/v0.8/ccip/test/mocks/MockTokenPool.sol +++ b/contracts/src/v0.8/ccip/test/mocks/MockTokenPool.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.19; import {IPool} from "../../interfaces/pools/IPool.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract MockTokenPool is IPool { address public s_token; diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol index 8b5b1ccd77..9bf8ff67e4 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol @@ -19,7 +19,7 @@ import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol"; import {TokenPool} from "../../pools/TokenPool.sol"; import {OCR2BaseSetup} from "../ocr/OCR2Base.t.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; contract EVM2EVMOffRampSetup is TokenSetup, PriceRegistrySetup, OCR2BaseSetup { MockCommitStore internal s_mockCommitStore; diff --git a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol index 35f5aa28a0..272fa9e254 100644 --- a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol @@ -8,7 +8,7 @@ import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol"; import {TokenPool} from "../../pools/TokenPool.sol"; import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; contract LockReleaseTokenPoolSetup is BaseTest { IERC20 internal s_token; diff --git a/contracts/src/v0.8/ccip/test/pools/USDCTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/USDCTokenPool.t.sol index 4c6ee49396..4a40f108ce 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDCTokenPool.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDCTokenPool.t.sol @@ -12,7 +12,7 @@ import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol"; import {MockUSDCTokenMessenger} from "../mocks/MockUSDCTokenMessenger.sol"; import {USDCTokenPoolHelper} from "../helpers/USDCTokenPoolHelper.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; contract USDCTokenPoolSetup is BaseTest { IBurnMintERC20 internal s_token; diff --git a/contracts/src/v0.8/metatx/BankERC20.sol b/contracts/src/v0.8/metatx/BankERC20.sol index 539d1ea787..0c700bbb59 100644 --- a/contracts/src/v0.8/metatx/BankERC20.sol +++ b/contracts/src/v0.8/metatx/BankERC20.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {AbstractCrossChainMetaTransactor} from "./AbstractCrossChainMetaTransactor.sol"; /// @dev Implementation of the {IERC20} interface. diff --git a/contracts/src/v0.8/metatx/Forwarder.sol b/contracts/src/v0.8/metatx/Forwarder.sol index a5e079010a..59675f36a6 100644 --- a/contracts/src/v0.8/metatx/Forwarder.sol +++ b/contracts/src/v0.8/metatx/Forwarder.sol @@ -7,8 +7,8 @@ pragma abicoder v2; import "./IForwarder.sol"; import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol"; -import {ECDSA} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/cryptography/ECDSA.sol"; -import {ERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/ERC165.sol"; +import {ECDSA} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/cryptography/ECDSA.sol"; +import {ERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol"; import {ExcessivelySafeCall} from "../vendor/nomad-xyz/ExcessivelySafeCall.sol"; /// @title The Forwarder Implementation diff --git a/contracts/src/v0.8/metatx/IForwarder.sol b/contracts/src/v0.8/metatx/IForwarder.sol index a57de5cd0c..274ca09156 100644 --- a/contracts/src/v0.8/metatx/IForwarder.sol +++ b/contracts/src/v0.8/metatx/IForwarder.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.15; pragma abicoder v2; -import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; /// @title The Forwarder Interface /// @notice The contracts implementing this interface take a role of authorization, authentication and replay protection diff --git a/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol b/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol index 50d2edd2af..aaf3839438 100644 --- a/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol +++ b/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol"; +import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; library EnumerableMapAddresses { using EnumerableMap for EnumerableMap.UintToAddressMap; diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol new file mode 100644 index 0000000000..3bf5613a6c --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol new file mode 100644 index 0000000000..4daefc5d4f --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.2) (utils/introspection/ERC165Checker.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Library used to query support of an interface declared via {IERC165}. + * + * Note that these functions return the actual result of the query: they do not + * `revert` if an interface is not supported. It is up to the caller to decide + * what to do in these cases. + */ +library ERC165Checker { + // As per the EIP-165 spec, no interface should ever match 0xffffffff + bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; + + /** + * @dev Returns true if `account` supports the {IERC165} interface. + */ + function supportsERC165(address account) internal view returns (bool) { + // Any contract that implements ERC165 must explicitly indicate support of + // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid + return + supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && + !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID); + } + + /** + * @dev Returns true if `account` supports the interface defined by + * `interfaceId`. Support for {IERC165} itself is queried automatically. + * + * See {IERC165-supportsInterface}. + */ + function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { + // query support of both ERC165 as per the spec and support of _interfaceId + return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); + } + + /** + * @dev Returns a boolean array where each value corresponds to the + * interfaces passed in and whether they're supported or not. This allows + * you to batch check interfaces for a contract where your expectation + * is that some interfaces may not be supported. + * + * See {IERC165-supportsInterface}. + * + * _Available since v3.4._ + */ + function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) + internal + view + returns (bool[] memory) + { + // an array of booleans corresponding to interfaceIds and whether they're supported or not + bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); + + // query support of ERC165 itself + if (supportsERC165(account)) { + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); + } + } + + return interfaceIdsSupported; + } + + /** + * @dev Returns true if `account` supports all the interfaces defined in + * `interfaceIds`. Support for {IERC165} itself is queried automatically. + * + * Batch-querying can lead to gas savings by skipping repeated checks for + * {IERC165} support. + * + * See {IERC165-supportsInterface}. + */ + function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { + // query support of ERC165 itself + if (!supportsERC165(account)) { + return false; + } + + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { + return false; + } + } + + // all interfaces supported + return true; + } + + /** + * @notice Query if a contract implements an interface, does not check ERC165 support + * @param account The address of the contract to query for support of an interface + * @param interfaceId The interface identifier, as specified in ERC-165 + * @return true if the contract at account indicates support of the interface with + * identifier interfaceId, false otherwise + * @dev Assumes that account contains a contract that supports ERC165, otherwise + * the behavior of this method is undefined. This precondition can be checked + * with {supportsERC165}. + * + * Some precompiled contracts will falsely indicate support for a given interface, so caution + * should be exercised when using this function. + * + * Interface identification is specified in ERC-165. + */ + function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { + // prepare call + bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); + + // perform static call + bool success; + uint256 returnSize; + uint256 returnValue; + assembly { + success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) + returnSize := returndatasize() + returnValue := mload(0x00) + } + + return success && returnSize >= 0x20 && returnValue > 0; + } +} diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index 68fb2092f7..d8a9bc648a 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -19,6 +19,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -1340,7 +1341,7 @@ func TestBlockHistoryEstimator_IsUsable(t *testing.T) { t.Run("returns false if transaction is of type 0x16 only on WeMix", func(t *testing.T) { cfg.ChainTypeF = "wemix" tx := evmtypes.Transaction{Type: 0x16, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} - assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.TestLogger(t))) + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) t.Run("returns false if transaction has base fee higher than the gas price only on Celo", func(t *testing.T) { diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go index 0f185420e8..c5773173b8 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go @@ -92,7 +92,7 @@ func TestL1GasPriceOracle(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainKroma) + oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainKroma) require.NoError(t, oracle.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index 11b2dd1125..65d808b98d 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -383,13 +383,10 @@ func (_m *LogPoller) LatestBlock(qopts ...pg.QOpt) (logpoller.LogPollerBlock, er _ca = append(_ca, _va...) ret := _m.Called(_ca...) -<<<<<<< HEAD -======= if len(ret) == 0 { panic("no return value specified for LatestBlock") } ->>>>>>> develop var r0 logpoller.LogPollerBlock var r1 error if rf, ok := ret.Get(0).(func(...pg.QOpt) (logpoller.LogPollerBlock, error)); ok { @@ -604,13 +601,10 @@ func (_m *LogPoller) LogsDataWordBetween(eventSig common.Hash, address common.Ad _ca = append(_ca, _va...) ret := _m.Called(_ca...) -<<<<<<< HEAD -======= if len(ret) == 0 { panic("no return value specified for LogsDataWordBetween") } ->>>>>>> develop var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { diff --git a/core/chains/evm/logpoller/query.go b/core/chains/evm/logpoller/query.go index afe021245a..a37b15b2b2 100644 --- a/core/chains/evm/logpoller/query.go +++ b/core/chains/evm/logpoller/query.go @@ -74,18 +74,6 @@ func (q *queryArgs) withWordIndex(wordIndex int) *queryArgs { return q.withCustomArg("word_index", wordIndex) } -func (q *queryArgs) withWordIndexMin(wordIndex int) *queryArgs { - return q.withCustomArg("word_index_min", wordIndex) -} - -func (q *queryArgs) withWordIndexMax(wordIndex int) *queryArgs { - return q.withCustomArg("word_index_max", wordIndex) -} - -func (q *queryArgs) withWordValue(wordValue common.Hash) *queryArgs { - return q.withCustomHashArg("word_value", wordValue) -} - func (q *queryArgs) withWordValueMin(wordValueMin common.Hash) *queryArgs { return q.withCustomHashArg("word_value_min", wordValueMin) } diff --git a/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go b/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go index 5f9788b41e..b6e95adb16 100644 --- a/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go +++ b/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go @@ -77,7 +77,7 @@ func DeployARMContract(auth *bind.TransactOpts, backend bind.ContractBackend, co if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &ARMContract{ARMContractCaller: ARMContractCaller{contract: contract}, ARMContractTransactor: ARMContractTransactor{contract: contract}, ARMContractFilterer: ARMContractFilterer{contract: contract}}, nil + return address, tx, &ARMContract{address: address, abi: *parsed, ARMContractCaller: ARMContractCaller{contract: contract}, ARMContractTransactor: ARMContractTransactor{contract: contract}, ARMContractFilterer: ARMContractFilterer{contract: contract}}, nil } type ARMContract struct { diff --git a/core/gethwrappers/ccip/generated/arm_proxy_contract/arm_proxy_contract.go b/core/gethwrappers/ccip/generated/arm_proxy_contract/arm_proxy_contract.go index 7e4f03621e..6e3ab98f28 100644 --- a/core/gethwrappers/ccip/generated/arm_proxy_contract/arm_proxy_contract.go +++ b/core/gethwrappers/ccip/generated/arm_proxy_contract/arm_proxy_contract.go @@ -52,7 +52,7 @@ func DeployARMProxyContract(auth *bind.TransactOpts, backend bind.ContractBacken if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &ARMProxyContract{ARMProxyContractCaller: ARMProxyContractCaller{contract: contract}, ARMProxyContractTransactor: ARMProxyContractTransactor{contract: contract}, ARMProxyContractFilterer: ARMProxyContractFilterer{contract: contract}}, nil + return address, tx, &ARMProxyContract{address: address, abi: *parsed, ARMProxyContractCaller: ARMProxyContractCaller{contract: contract}, ARMProxyContractTransactor: ARMProxyContractTransactor{contract: contract}, ARMProxyContractFilterer: ARMProxyContractFilterer{contract: contract}}, nil } type ARMProxyContract struct { diff --git a/core/gethwrappers/ccip/generated/burn_from_mint_token_pool/burn_from_mint_token_pool.go b/core/gethwrappers/ccip/generated/burn_from_mint_token_pool/burn_from_mint_token_pool.go index 06c2cfa6fb..ad91eddc5f 100644 --- a/core/gethwrappers/ccip/generated/burn_from_mint_token_pool/burn_from_mint_token_pool.go +++ b/core/gethwrappers/ccip/generated/burn_from_mint_token_pool/burn_from_mint_token_pool.go @@ -72,7 +72,7 @@ func DeployBurnFromMintTokenPool(auth *bind.TransactOpts, backend bind.ContractB if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BurnFromMintTokenPool{BurnFromMintTokenPoolCaller: BurnFromMintTokenPoolCaller{contract: contract}, BurnFromMintTokenPoolTransactor: BurnFromMintTokenPoolTransactor{contract: contract}, BurnFromMintTokenPoolFilterer: BurnFromMintTokenPoolFilterer{contract: contract}}, nil + return address, tx, &BurnFromMintTokenPool{address: address, abi: *parsed, BurnFromMintTokenPoolCaller: BurnFromMintTokenPoolCaller{contract: contract}, BurnFromMintTokenPoolTransactor: BurnFromMintTokenPoolTransactor{contract: contract}, BurnFromMintTokenPoolFilterer: BurnFromMintTokenPoolFilterer{contract: contract}}, nil } type BurnFromMintTokenPool struct { diff --git a/core/gethwrappers/ccip/generated/burn_mint_token_pool/burn_mint_token_pool.go b/core/gethwrappers/ccip/generated/burn_mint_token_pool/burn_mint_token_pool.go index c925c51590..d254ce17a2 100644 --- a/core/gethwrappers/ccip/generated/burn_mint_token_pool/burn_mint_token_pool.go +++ b/core/gethwrappers/ccip/generated/burn_mint_token_pool/burn_mint_token_pool.go @@ -72,7 +72,7 @@ func DeployBurnMintTokenPool(auth *bind.TransactOpts, backend bind.ContractBacke if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BurnMintTokenPool{BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil + return address, tx, &BurnMintTokenPool{address: address, abi: *parsed, BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil } type BurnMintTokenPool struct { diff --git a/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool/burn_with_from_mint_token_pool.go b/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool/burn_with_from_mint_token_pool.go index 6ec9b4c073..20b483b92d 100644 --- a/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool/burn_with_from_mint_token_pool.go +++ b/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool/burn_with_from_mint_token_pool.go @@ -72,7 +72,7 @@ func DeployBurnWithFromMintTokenPool(auth *bind.TransactOpts, backend bind.Contr if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BurnWithFromMintTokenPool{BurnWithFromMintTokenPoolCaller: BurnWithFromMintTokenPoolCaller{contract: contract}, BurnWithFromMintTokenPoolTransactor: BurnWithFromMintTokenPoolTransactor{contract: contract}, BurnWithFromMintTokenPoolFilterer: BurnWithFromMintTokenPoolFilterer{contract: contract}}, nil + return address, tx, &BurnWithFromMintTokenPool{address: address, abi: *parsed, BurnWithFromMintTokenPoolCaller: BurnWithFromMintTokenPoolCaller{contract: contract}, BurnWithFromMintTokenPoolTransactor: BurnWithFromMintTokenPoolTransactor{contract: contract}, BurnWithFromMintTokenPoolFilterer: BurnWithFromMintTokenPoolFilterer{contract: contract}}, nil } type BurnWithFromMintTokenPool struct { diff --git a/core/gethwrappers/ccip/generated/commit_store/commit_store.go b/core/gethwrappers/ccip/generated/commit_store/commit_store.go index 288e82954a..6b42f1b096 100644 --- a/core/gethwrappers/ccip/generated/commit_store/commit_store.go +++ b/core/gethwrappers/ccip/generated/commit_store/commit_store.go @@ -89,7 +89,7 @@ func DeployCommitStore(auth *bind.TransactOpts, backend bind.ContractBackend, st if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &CommitStore{CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil + return address, tx, &CommitStore{address: address, abi: *parsed, CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil } type CommitStore struct { diff --git a/core/gethwrappers/ccip/generated/commit_store_helper/commit_store_helper.go b/core/gethwrappers/ccip/generated/commit_store_helper/commit_store_helper.go index 1a48443edb..658bc5c834 100644 --- a/core/gethwrappers/ccip/generated/commit_store_helper/commit_store_helper.go +++ b/core/gethwrappers/ccip/generated/commit_store_helper/commit_store_helper.go @@ -89,7 +89,7 @@ func DeployCommitStoreHelper(auth *bind.TransactOpts, backend bind.ContractBacke if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &CommitStoreHelper{CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil + return address, tx, &CommitStoreHelper{address: address, abi: *parsed, CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil } type CommitStoreHelper struct { diff --git a/core/gethwrappers/ccip/generated/custom_token_pool/custom_token_pool.go b/core/gethwrappers/ccip/generated/custom_token_pool/custom_token_pool.go index 2bd494788b..f99a3e5f5b 100644 --- a/core/gethwrappers/ccip/generated/custom_token_pool/custom_token_pool.go +++ b/core/gethwrappers/ccip/generated/custom_token_pool/custom_token_pool.go @@ -72,7 +72,7 @@ func DeployCustomTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &CustomTokenPool{CustomTokenPoolCaller: CustomTokenPoolCaller{contract: contract}, CustomTokenPoolTransactor: CustomTokenPoolTransactor{contract: contract}, CustomTokenPoolFilterer: CustomTokenPoolFilterer{contract: contract}}, nil + return address, tx, &CustomTokenPool{address: address, abi: *parsed, CustomTokenPoolCaller: CustomTokenPoolCaller{contract: contract}, CustomTokenPoolTransactor: CustomTokenPoolTransactor{contract: contract}, CustomTokenPoolFilterer: CustomTokenPoolFilterer{contract: contract}}, nil } type CustomTokenPool struct { diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go b/core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go index 96cb662d47..f98a7b6ca2 100644 --- a/core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go +++ b/core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go @@ -125,7 +125,7 @@ func DeployEVM2EVMOffRamp(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &EVM2EVMOffRamp{EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil + return address, tx, &EVM2EVMOffRamp{address: address, abi: *parsed, EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil } type EVM2EVMOffRamp struct { diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go b/core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go index 6d7b6ce843..cd762286e0 100644 --- a/core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go +++ b/core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go @@ -160,7 +160,7 @@ func DeployEVM2EVMOnRamp(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &EVM2EVMOnRamp{EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil + return address, tx, &EVM2EVMOnRamp{address: address, abi: *parsed, EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil } type EVM2EVMOnRamp struct { diff --git a/core/gethwrappers/ccip/generated/lock_release_token_pool/lock_release_token_pool.go b/core/gethwrappers/ccip/generated/lock_release_token_pool/lock_release_token_pool.go index fffe85fbcd..760e6b7960 100644 --- a/core/gethwrappers/ccip/generated/lock_release_token_pool/lock_release_token_pool.go +++ b/core/gethwrappers/ccip/generated/lock_release_token_pool/lock_release_token_pool.go @@ -72,7 +72,7 @@ func DeployLockReleaseTokenPool(auth *bind.TransactOpts, backend bind.ContractBa if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &LockReleaseTokenPool{LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil + return address, tx, &LockReleaseTokenPool{address: address, abi: *parsed, LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil } type LockReleaseTokenPool struct { diff --git a/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go b/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go index 2edc36d18a..226bd5f684 100644 --- a/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go +++ b/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go @@ -65,7 +65,7 @@ func DeployMaybeRevertMessageReceiver(auth *bind.TransactOpts, backend bind.Cont if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &MaybeRevertMessageReceiver{MaybeRevertMessageReceiverCaller: MaybeRevertMessageReceiverCaller{contract: contract}, MaybeRevertMessageReceiverTransactor: MaybeRevertMessageReceiverTransactor{contract: contract}, MaybeRevertMessageReceiverFilterer: MaybeRevertMessageReceiverFilterer{contract: contract}}, nil + return address, tx, &MaybeRevertMessageReceiver{address: address, abi: *parsed, MaybeRevertMessageReceiverCaller: MaybeRevertMessageReceiverCaller{contract: contract}, MaybeRevertMessageReceiverTransactor: MaybeRevertMessageReceiverTransactor{contract: contract}, MaybeRevertMessageReceiverFilterer: MaybeRevertMessageReceiverFilterer{contract: contract}}, nil } type MaybeRevertMessageReceiver struct { diff --git a/core/gethwrappers/ccip/generated/mock_arm_contract/mock_arm_contract.go b/core/gethwrappers/ccip/generated/mock_arm_contract/mock_arm_contract.go index d9127ed84f..04f075d1c2 100644 --- a/core/gethwrappers/ccip/generated/mock_arm_contract/mock_arm_contract.go +++ b/core/gethwrappers/ccip/generated/mock_arm_contract/mock_arm_contract.go @@ -77,7 +77,7 @@ func DeployMockARMContract(auth *bind.TransactOpts, backend bind.ContractBackend if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &MockARMContract{MockARMContractCaller: MockARMContractCaller{contract: contract}, MockARMContractTransactor: MockARMContractTransactor{contract: contract}, MockARMContractFilterer: MockARMContractFilterer{contract: contract}}, nil + return address, tx, &MockARMContract{address: address, abi: *parsed, MockARMContractCaller: MockARMContractCaller{contract: contract}, MockARMContractTransactor: MockARMContractTransactor{contract: contract}, MockARMContractFilterer: MockARMContractFilterer{contract: contract}}, nil } type MockARMContract struct { diff --git a/core/gethwrappers/ccip/generated/ping_pong_demo/ping_pong_demo.go b/core/gethwrappers/ccip/generated/ping_pong_demo/ping_pong_demo.go index 8c5aac9245..4da554f90d 100644 --- a/core/gethwrappers/ccip/generated/ping_pong_demo/ping_pong_demo.go +++ b/core/gethwrappers/ccip/generated/ping_pong_demo/ping_pong_demo.go @@ -65,7 +65,7 @@ func DeployPingPongDemo(auth *bind.TransactOpts, backend bind.ContractBackend, r if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &PingPongDemo{PingPongDemoCaller: PingPongDemoCaller{contract: contract}, PingPongDemoTransactor: PingPongDemoTransactor{contract: contract}, PingPongDemoFilterer: PingPongDemoFilterer{contract: contract}}, nil + return address, tx, &PingPongDemo{address: address, abi: *parsed, PingPongDemoCaller: PingPongDemoCaller{contract: contract}, PingPongDemoTransactor: PingPongDemoTransactor{contract: contract}, PingPongDemoFilterer: PingPongDemoFilterer{contract: contract}}, nil } type PingPongDemo struct { diff --git a/core/gethwrappers/ccip/generated/price_registry/price_registry.go b/core/gethwrappers/ccip/generated/price_registry/price_registry.go index b42e532150..91c1ff7d24 100644 --- a/core/gethwrappers/ccip/generated/price_registry/price_registry.go +++ b/core/gethwrappers/ccip/generated/price_registry/price_registry.go @@ -72,7 +72,7 @@ func DeployPriceRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &PriceRegistry{PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil + return address, tx, &PriceRegistry{address: address, abi: *parsed, PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil } type PriceRegistry struct { diff --git a/core/gethwrappers/ccip/generated/router/router.go b/core/gethwrappers/ccip/generated/router/router.go index f46931661e..55696d7aac 100644 --- a/core/gethwrappers/ccip/generated/router/router.go +++ b/core/gethwrappers/ccip/generated/router/router.go @@ -83,7 +83,7 @@ func DeployRouter(auth *bind.TransactOpts, backend bind.ContractBackend, wrapped if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Router{RouterCaller: RouterCaller{contract: contract}, RouterTransactor: RouterTransactor{contract: contract}, RouterFilterer: RouterFilterer{contract: contract}}, nil + return address, tx, &Router{address: address, abi: *parsed, RouterCaller: RouterCaller{contract: contract}, RouterTransactor: RouterTransactor{contract: contract}, RouterFilterer: RouterFilterer{contract: contract}}, nil } type Router struct { diff --git a/core/gethwrappers/ccip/generated/self_funded_ping_pong/self_funded_ping_pong.go b/core/gethwrappers/ccip/generated/self_funded_ping_pong/self_funded_ping_pong.go index 4ffdf2a0f4..893c82fdf2 100644 --- a/core/gethwrappers/ccip/generated/self_funded_ping_pong/self_funded_ping_pong.go +++ b/core/gethwrappers/ccip/generated/self_funded_ping_pong/self_funded_ping_pong.go @@ -65,7 +65,7 @@ func DeploySelfFundedPingPong(auth *bind.TransactOpts, backend bind.ContractBack if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &SelfFundedPingPong{SelfFundedPingPongCaller: SelfFundedPingPongCaller{contract: contract}, SelfFundedPingPongTransactor: SelfFundedPingPongTransactor{contract: contract}, SelfFundedPingPongFilterer: SelfFundedPingPongFilterer{contract: contract}}, nil + return address, tx, &SelfFundedPingPong{address: address, abi: *parsed, SelfFundedPingPongCaller: SelfFundedPingPongCaller{contract: contract}, SelfFundedPingPongTransactor: SelfFundedPingPongTransactor{contract: contract}, SelfFundedPingPongFilterer: SelfFundedPingPongFilterer{contract: contract}}, nil } type SelfFundedPingPong struct { diff --git a/core/gethwrappers/ccip/generated/usdc_token_pool/usdc_token_pool.go b/core/gethwrappers/ccip/generated/usdc_token_pool/usdc_token_pool.go index 213ea23e34..a60402fb8a 100644 --- a/core/gethwrappers/ccip/generated/usdc_token_pool/usdc_token_pool.go +++ b/core/gethwrappers/ccip/generated/usdc_token_pool/usdc_token_pool.go @@ -85,7 +85,7 @@ func DeployUSDCTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &USDCTokenPool{USDCTokenPoolCaller: USDCTokenPoolCaller{contract: contract}, USDCTokenPoolTransactor: USDCTokenPoolTransactor{contract: contract}, USDCTokenPoolFilterer: USDCTokenPoolFilterer{contract: contract}}, nil + return address, tx, &USDCTokenPool{address: address, abi: *parsed, USDCTokenPoolCaller: USDCTokenPoolCaller{contract: contract}, USDCTokenPoolTransactor: USDCTokenPoolTransactor{contract: contract}, USDCTokenPoolFilterer: USDCTokenPoolFilterer{contract: contract}}, nil } type USDCTokenPool struct { diff --git a/core/gethwrappers/ccip/generated/weth9/weth9.go b/core/gethwrappers/ccip/generated/weth9/weth9.go index 9ffe5683b0..50765b7598 100644 --- a/core/gethwrappers/ccip/generated/weth9/weth9.go +++ b/core/gethwrappers/ccip/generated/weth9/weth9.go @@ -52,7 +52,7 @@ func DeployWETH9(auth *bind.TransactOpts, backend bind.ContractBackend) (common. if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &WETH9{WETH9Caller: WETH9Caller{contract: contract}, WETH9Transactor: WETH9Transactor{contract: contract}, WETH9Filterer: WETH9Filterer{contract: contract}}, nil + return address, tx, &WETH9{address: address, abi: *parsed, WETH9Caller: WETH9Caller{contract: contract}, WETH9Transactor: WETH9Transactor{contract: contract}, WETH9Filterer: WETH9Filterer{contract: contract}}, nil } type WETH9 struct { diff --git a/core/gethwrappers/ccip/mocks/commit_store_interface.go b/core/gethwrappers/ccip/mocks/commit_store_interface.go index 313eb4d76f..32266b178d 100644 --- a/core/gethwrappers/ccip/mocks/commit_store_interface.go +++ b/core/gethwrappers/ccip/mocks/commit_store_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mock_contracts @@ -27,6 +27,10 @@ type CommitStoreInterface struct { func (_m *CommitStoreInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -53,6 +57,10 @@ func (_m *CommitStoreInterface) AcceptOwnership(opts *bind.TransactOpts) (*types func (_m *CommitStoreInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -69,6 +77,10 @@ func (_m *CommitStoreInterface) Address() common.Address { func (_m *CommitStoreInterface) FilterConfigSet(opts *bind.FilterOpts) (*commit_store.CommitStoreConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet") + } + var r0 *commit_store.CommitStoreConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreConfigSetIterator, error)); ok { @@ -95,6 +107,10 @@ func (_m *CommitStoreInterface) FilterConfigSet(opts *bind.FilterOpts) (*commit_ func (_m *CommitStoreInterface) FilterConfigSet0(opts *bind.FilterOpts) (*commit_store.CommitStoreConfigSet0Iterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet0") + } + var r0 *commit_store.CommitStoreConfigSet0Iterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreConfigSet0Iterator, error)); ok { @@ -121,6 +137,10 @@ func (_m *CommitStoreInterface) FilterConfigSet0(opts *bind.FilterOpts) (*commit func (_m *CommitStoreInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*commit_store.CommitStoreOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *commit_store.CommitStoreOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*commit_store.CommitStoreOwnershipTransferRequestedIterator, error)); ok { @@ -147,6 +167,10 @@ func (_m *CommitStoreInterface) FilterOwnershipTransferRequested(opts *bind.Filt func (_m *CommitStoreInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*commit_store.CommitStoreOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *commit_store.CommitStoreOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*commit_store.CommitStoreOwnershipTransferredIterator, error)); ok { @@ -173,6 +197,10 @@ func (_m *CommitStoreInterface) FilterOwnershipTransferred(opts *bind.FilterOpts func (_m *CommitStoreInterface) FilterPaused(opts *bind.FilterOpts) (*commit_store.CommitStorePausedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterPaused") + } + var r0 *commit_store.CommitStorePausedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStorePausedIterator, error)); ok { @@ -199,6 +227,10 @@ func (_m *CommitStoreInterface) FilterPaused(opts *bind.FilterOpts) (*commit_sto func (_m *CommitStoreInterface) FilterReportAccepted(opts *bind.FilterOpts) (*commit_store.CommitStoreReportAcceptedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterReportAccepted") + } + var r0 *commit_store.CommitStoreReportAcceptedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreReportAcceptedIterator, error)); ok { @@ -225,6 +257,10 @@ func (_m *CommitStoreInterface) FilterReportAccepted(opts *bind.FilterOpts) (*co func (_m *CommitStoreInterface) FilterRootRemoved(opts *bind.FilterOpts) (*commit_store.CommitStoreRootRemovedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterRootRemoved") + } + var r0 *commit_store.CommitStoreRootRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreRootRemovedIterator, error)); ok { @@ -251,6 +287,10 @@ func (_m *CommitStoreInterface) FilterRootRemoved(opts *bind.FilterOpts) (*commi func (_m *CommitStoreInterface) FilterTransmitted(opts *bind.FilterOpts) (*commit_store.CommitStoreTransmittedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterTransmitted") + } + var r0 *commit_store.CommitStoreTransmittedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreTransmittedIterator, error)); ok { @@ -277,6 +317,10 @@ func (_m *CommitStoreInterface) FilterTransmitted(opts *bind.FilterOpts) (*commi func (_m *CommitStoreInterface) FilterUnpaused(opts *bind.FilterOpts) (*commit_store.CommitStoreUnpausedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterUnpaused") + } + var r0 *commit_store.CommitStoreUnpausedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreUnpausedIterator, error)); ok { @@ -303,6 +347,10 @@ func (_m *CommitStoreInterface) FilterUnpaused(opts *bind.FilterOpts) (*commit_s func (_m *CommitStoreInterface) GetDynamicConfig(opts *bind.CallOpts) (commit_store.CommitStoreDynamicConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetDynamicConfig") + } + var r0 commit_store.CommitStoreDynamicConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.CommitStoreDynamicConfig, error)); ok { @@ -327,6 +375,10 @@ func (_m *CommitStoreInterface) GetDynamicConfig(opts *bind.CallOpts) (commit_st func (_m *CommitStoreInterface) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetExpectedNextSequenceNumber") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok { @@ -351,6 +403,10 @@ func (_m *CommitStoreInterface) GetExpectedNextSequenceNumber(opts *bind.CallOpt func (_m *CommitStoreInterface) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetLatestPriceEpochAndRound") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok { @@ -375,6 +431,10 @@ func (_m *CommitStoreInterface) GetLatestPriceEpochAndRound(opts *bind.CallOpts) func (_m *CommitStoreInterface) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) { ret := _m.Called(opts, root) + if len(ret) == 0 { + panic("no return value specified for GetMerkleRoot") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) (*big.Int, error)); ok { @@ -401,6 +461,10 @@ func (_m *CommitStoreInterface) GetMerkleRoot(opts *bind.CallOpts, root [32]byte func (_m *CommitStoreInterface) GetStaticConfig(opts *bind.CallOpts) (commit_store.CommitStoreStaticConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetStaticConfig") + } + var r0 commit_store.CommitStoreStaticConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.CommitStoreStaticConfig, error)); ok { @@ -425,6 +489,10 @@ func (_m *CommitStoreInterface) GetStaticConfig(opts *bind.CallOpts) (commit_sto func (_m *CommitStoreInterface) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetTransmitters") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -451,6 +519,10 @@ func (_m *CommitStoreInterface) GetTransmitters(opts *bind.CallOpts) ([]common.A func (_m *CommitStoreInterface) IsARMHealthy(opts *bind.CallOpts) (bool, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for IsARMHealthy") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok { @@ -475,6 +547,10 @@ func (_m *CommitStoreInterface) IsARMHealthy(opts *bind.CallOpts) (bool, error) func (_m *CommitStoreInterface) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) { ret := _m.Called(opts, root) + if len(ret) == 0 { + panic("no return value specified for IsBlessed") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) (bool, error)); ok { @@ -499,6 +575,10 @@ func (_m *CommitStoreInterface) IsBlessed(opts *bind.CallOpts, root [32]byte) (b func (_m *CommitStoreInterface) IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for IsUnpausedAndARMHealthy") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok { @@ -523,6 +603,10 @@ func (_m *CommitStoreInterface) IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bo func (_m *CommitStoreInterface) LatestConfigDetails(opts *bind.CallOpts) (commit_store.LatestConfigDetails, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDetails") + } + var r0 commit_store.LatestConfigDetails var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.LatestConfigDetails, error)); ok { @@ -547,6 +631,10 @@ func (_m *CommitStoreInterface) LatestConfigDetails(opts *bind.CallOpts) (commit func (_m *CommitStoreInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (commit_store.LatestConfigDigestAndEpoch, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDigestAndEpoch") + } + var r0 commit_store.LatestConfigDigestAndEpoch var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.LatestConfigDigestAndEpoch, error)); ok { @@ -571,6 +659,10 @@ func (_m *CommitStoreInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) func (_m *CommitStoreInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -597,6 +689,10 @@ func (_m *CommitStoreInterface) Owner(opts *bind.CallOpts) (common.Address, erro func (_m *CommitStoreInterface) ParseConfigSet(log types.Log) (*commit_store.CommitStoreConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet") + } + var r0 *commit_store.CommitStoreConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreConfigSet, error)); ok { @@ -623,6 +719,10 @@ func (_m *CommitStoreInterface) ParseConfigSet(log types.Log) (*commit_store.Com func (_m *CommitStoreInterface) ParseConfigSet0(log types.Log) (*commit_store.CommitStoreConfigSet0, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet0") + } + var r0 *commit_store.CommitStoreConfigSet0 var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreConfigSet0, error)); ok { @@ -649,6 +749,10 @@ func (_m *CommitStoreInterface) ParseConfigSet0(log types.Log) (*commit_store.Co func (_m *CommitStoreInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -675,6 +779,10 @@ func (_m *CommitStoreInterface) ParseLog(log types.Log) (generated.AbigenLog, er func (_m *CommitStoreInterface) ParseOwnershipTransferRequested(log types.Log) (*commit_store.CommitStoreOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *commit_store.CommitStoreOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreOwnershipTransferRequested, error)); ok { @@ -701,6 +809,10 @@ func (_m *CommitStoreInterface) ParseOwnershipTransferRequested(log types.Log) ( func (_m *CommitStoreInterface) ParseOwnershipTransferred(log types.Log) (*commit_store.CommitStoreOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *commit_store.CommitStoreOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreOwnershipTransferred, error)); ok { @@ -727,6 +839,10 @@ func (_m *CommitStoreInterface) ParseOwnershipTransferred(log types.Log) (*commi func (_m *CommitStoreInterface) ParsePaused(log types.Log) (*commit_store.CommitStorePaused, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePaused") + } + var r0 *commit_store.CommitStorePaused var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStorePaused, error)); ok { @@ -753,6 +869,10 @@ func (_m *CommitStoreInterface) ParsePaused(log types.Log) (*commit_store.Commit func (_m *CommitStoreInterface) ParseReportAccepted(log types.Log) (*commit_store.CommitStoreReportAccepted, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseReportAccepted") + } + var r0 *commit_store.CommitStoreReportAccepted var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreReportAccepted, error)); ok { @@ -779,6 +899,10 @@ func (_m *CommitStoreInterface) ParseReportAccepted(log types.Log) (*commit_stor func (_m *CommitStoreInterface) ParseRootRemoved(log types.Log) (*commit_store.CommitStoreRootRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRootRemoved") + } + var r0 *commit_store.CommitStoreRootRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreRootRemoved, error)); ok { @@ -805,6 +929,10 @@ func (_m *CommitStoreInterface) ParseRootRemoved(log types.Log) (*commit_store.C func (_m *CommitStoreInterface) ParseTransmitted(log types.Log) (*commit_store.CommitStoreTransmitted, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseTransmitted") + } + var r0 *commit_store.CommitStoreTransmitted var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreTransmitted, error)); ok { @@ -831,6 +959,10 @@ func (_m *CommitStoreInterface) ParseTransmitted(log types.Log) (*commit_store.C func (_m *CommitStoreInterface) ParseUnpaused(log types.Log) (*commit_store.CommitStoreUnpaused, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseUnpaused") + } + var r0 *commit_store.CommitStoreUnpaused var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreUnpaused, error)); ok { @@ -857,6 +989,10 @@ func (_m *CommitStoreInterface) ParseUnpaused(log types.Log) (*commit_store.Comm func (_m *CommitStoreInterface) Pause(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Pause") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -883,6 +1019,10 @@ func (_m *CommitStoreInterface) Pause(opts *bind.TransactOpts) (*types.Transacti func (_m *CommitStoreInterface) Paused(opts *bind.CallOpts) (bool, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Paused") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok { @@ -907,6 +1047,10 @@ func (_m *CommitStoreInterface) Paused(opts *bind.CallOpts) (bool, error) { func (_m *CommitStoreInterface) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) { ret := _m.Called(opts, rootToReset) + if len(ret) == 0 { + panic("no return value specified for ResetUnblessedRoots") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [][32]byte) (*types.Transaction, error)); ok { @@ -933,6 +1077,10 @@ func (_m *CommitStoreInterface) ResetUnblessedRoots(opts *bind.TransactOpts, roo func (_m *CommitStoreInterface) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, latestPriceEpochAndRound) + if len(ret) == 0 { + panic("no return value specified for SetLatestPriceEpochAndRound") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int) (*types.Transaction, error)); ok { @@ -959,6 +1107,10 @@ func (_m *CommitStoreInterface) SetLatestPriceEpochAndRound(opts *bind.TransactO func (_m *CommitStoreInterface) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) { ret := _m.Called(opts, minSeqNr) + if len(ret) == 0 { + panic("no return value specified for SetMinSeqNr") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64) (*types.Transaction, error)); ok { @@ -985,6 +1137,10 @@ func (_m *CommitStoreInterface) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr ui func (_m *CommitStoreInterface) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) + if len(ret) == 0 { + panic("no return value specified for SetOCR2Config") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok { @@ -1011,6 +1167,10 @@ func (_m *CommitStoreInterface) SetOCR2Config(opts *bind.TransactOpts, signers [ func (_m *CommitStoreInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1037,6 +1197,10 @@ func (_m *CommitStoreInterface) TransferOwnership(opts *bind.TransactOpts, to co func (_m *CommitStoreInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { ret := _m.Called(opts, reportContext, report, rs, ss, rawVs) + if len(ret) == 0 { + panic("no return value specified for Transmit") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok { @@ -1063,6 +1227,10 @@ func (_m *CommitStoreInterface) Transmit(opts *bind.TransactOpts, reportContext func (_m *CommitStoreInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -1087,6 +1255,10 @@ func (_m *CommitStoreInterface) TypeAndVersion(opts *bind.CallOpts) (string, err func (_m *CommitStoreInterface) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Unpause") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -1113,6 +1285,10 @@ func (_m *CommitStoreInterface) Unpause(opts *bind.TransactOpts) (*types.Transac func (_m *CommitStoreInterface) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) { ret := _m.Called(opts, hashedLeaves, proofs, proofFlagBits) + if len(ret) == 0 { + panic("no return value specified for Verify") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, [][32]byte, [][32]byte, *big.Int) (*big.Int, error)); ok { @@ -1139,6 +1315,10 @@ func (_m *CommitStoreInterface) Verify(opts *bind.CallOpts, hashedLeaves [][32]b func (_m *CommitStoreInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet) (event.Subscription, error)); ok { @@ -1165,6 +1345,10 @@ func (_m *CommitStoreInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- func (_m *CommitStoreInterface) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreConfigSet0) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet0") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet0) (event.Subscription, error)); ok { @@ -1191,6 +1375,10 @@ func (_m *CommitStoreInterface) WatchConfigSet0(opts *bind.WatchOpts, sink chan< func (_m *CommitStoreInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1217,6 +1405,10 @@ func (_m *CommitStoreInterface) WatchOwnershipTransferRequested(opts *bind.Watch func (_m *CommitStoreInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1243,6 +1435,10 @@ func (_m *CommitStoreInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, func (_m *CommitStoreInterface) WatchPaused(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStorePaused) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchPaused") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStorePaused) (event.Subscription, error)); ok { @@ -1269,6 +1465,10 @@ func (_m *CommitStoreInterface) WatchPaused(opts *bind.WatchOpts, sink chan<- *c func (_m *CommitStoreInterface) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreReportAccepted) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchReportAccepted") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreReportAccepted) (event.Subscription, error)); ok { @@ -1295,6 +1495,10 @@ func (_m *CommitStoreInterface) WatchReportAccepted(opts *bind.WatchOpts, sink c func (_m *CommitStoreInterface) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreRootRemoved) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchRootRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreRootRemoved) (event.Subscription, error)); ok { @@ -1321,6 +1525,10 @@ func (_m *CommitStoreInterface) WatchRootRemoved(opts *bind.WatchOpts, sink chan func (_m *CommitStoreInterface) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreTransmitted) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchTransmitted") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreTransmitted) (event.Subscription, error)); ok { @@ -1347,6 +1555,10 @@ func (_m *CommitStoreInterface) WatchTransmitted(opts *bind.WatchOpts, sink chan func (_m *CommitStoreInterface) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreUnpaused) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchUnpaused") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreUnpaused) (event.Subscription, error)); ok { diff --git a/core/gethwrappers/ccip/mocks/evm2_evm_off_ramp_interface.go b/core/gethwrappers/ccip/mocks/evm2_evm_off_ramp_interface.go index a07a7d7b81..b377003d9c 100644 --- a/core/gethwrappers/ccip/mocks/evm2_evm_off_ramp_interface.go +++ b/core/gethwrappers/ccip/mocks/evm2_evm_off_ramp_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mock_contracts @@ -28,6 +28,10 @@ type EVM2EVMOffRampInterface struct { func (_m *EVM2EVMOffRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *EVM2EVMOffRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*ty func (_m *EVM2EVMOffRampInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -70,6 +78,10 @@ func (_m *EVM2EVMOffRampInterface) Address() common.Address { func (_m *EVM2EVMOffRampInterface) ApplyPoolUpdates(opts *bind.TransactOpts, removes []evm_2_evm_offramp.InternalPoolUpdate, adds []evm_2_evm_offramp.InternalPoolUpdate) (*types.Transaction, error) { ret := _m.Called(opts, removes, adds) + if len(ret) == 0 { + panic("no return value specified for ApplyPoolUpdates") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_offramp.InternalPoolUpdate, []evm_2_evm_offramp.InternalPoolUpdate) (*types.Transaction, error)); ok { @@ -96,6 +108,10 @@ func (_m *EVM2EVMOffRampInterface) ApplyPoolUpdates(opts *bind.TransactOpts, rem func (_m *EVM2EVMOffRampInterface) CcipReceive(opts *bind.CallOpts, arg0 evm_2_evm_offramp.ClientAny2EVMMessage) error { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for CcipReceive") + } + var r0 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, evm_2_evm_offramp.ClientAny2EVMMessage) error); ok { r0 = rf(opts, arg0) @@ -110,6 +126,10 @@ func (_m *EVM2EVMOffRampInterface) CcipReceive(opts *bind.CallOpts, arg0 evm_2_e func (_m *EVM2EVMOffRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) (evm_2_evm_offramp.RateLimiterTokenBucket, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CurrentRateLimiterState") + } + var r0 evm_2_evm_offramp.RateLimiterTokenBucket var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.RateLimiterTokenBucket, error)); ok { @@ -134,6 +154,10 @@ func (_m *EVM2EVMOffRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) func (_m *EVM2EVMOffRampInterface) ExecuteSingleMessage(opts *bind.TransactOpts, message evm_2_evm_offramp.InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) { ret := _m.Called(opts, message, offchainTokenData) + if len(ret) == 0 { + panic("no return value specified for ExecuteSingleMessage") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalEVM2EVMMessage, [][]byte) (*types.Transaction, error)); ok { @@ -160,6 +184,10 @@ func (_m *EVM2EVMOffRampInterface) ExecuteSingleMessage(opts *bind.TransactOpts, func (_m *EVM2EVMOffRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterAdminSet") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator, error)); ok { @@ -186,6 +214,10 @@ func (_m *EVM2EVMOffRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2 func (_m *EVM2EVMOffRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator, error)); ok { @@ -212,6 +244,10 @@ func (_m *EVM2EVMOffRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_ func (_m *EVM2EVMOffRampInterface) FilterConfigSet0(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet0") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator, error)); ok { @@ -238,6 +274,10 @@ func (_m *EVM2EVMOffRampInterface) FilterConfigSet0(opts *bind.FilterOpts) (*evm func (_m *EVM2EVMOffRampInterface) FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator, error) { ret := _m.Called(opts, sequenceNumber, messageId) + if len(ret) == 0 { + panic("no return value specified for FilterExecutionStateChanged") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator, error)); ok { @@ -264,6 +304,10 @@ func (_m *EVM2EVMOffRampInterface) FilterExecutionStateChanged(opts *bind.Filter func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator, error)); ok { @@ -290,6 +334,10 @@ func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferRequested(opts *bind.F func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator, error)); ok { @@ -316,6 +364,10 @@ func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferred(opts *bind.FilterO func (_m *EVM2EVMOffRampInterface) FilterPoolAdded(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampPoolAddedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterPoolAdded") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampPoolAddedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampPoolAddedIterator, error)); ok { @@ -342,6 +394,10 @@ func (_m *EVM2EVMOffRampInterface) FilterPoolAdded(opts *bind.FilterOpts) (*evm_ func (_m *EVM2EVMOffRampInterface) FilterPoolRemoved(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampPoolRemovedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterPoolRemoved") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampPoolRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampPoolRemovedIterator, error)); ok { @@ -368,6 +424,10 @@ func (_m *EVM2EVMOffRampInterface) FilterPoolRemoved(opts *bind.FilterOpts) (*ev func (_m *EVM2EVMOffRampInterface) FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator, error) { ret := _m.Called(opts, nonce, sender) + if len(ret) == 0 { + panic("no return value specified for FilterSkippedIncorrectNonce") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator, error)); ok { @@ -394,6 +454,10 @@ func (_m *EVM2EVMOffRampInterface) FilterSkippedIncorrectNonce(opts *bind.Filter func (_m *EVM2EVMOffRampInterface) FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error) { ret := _m.Called(opts, nonce, sender) + if len(ret) == 0 { + panic("no return value specified for FilterSkippedSenderWithPreviousRampMessageInflight") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)); ok { @@ -420,6 +484,10 @@ func (_m *EVM2EVMOffRampInterface) FilterSkippedSenderWithPreviousRampMessageInf func (_m *EVM2EVMOffRampInterface) FilterTransmitted(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterTransmitted") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator, error)); ok { @@ -446,6 +514,10 @@ func (_m *EVM2EVMOffRampInterface) FilterTransmitted(opts *bind.FilterOpts) (*ev func (_m *EVM2EVMOffRampInterface) GetDestinationToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) { ret := _m.Called(opts, sourceToken) + if len(ret) == 0 { + panic("no return value specified for GetDestinationToken") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok { @@ -472,6 +544,10 @@ func (_m *EVM2EVMOffRampInterface) GetDestinationToken(opts *bind.CallOpts, sour func (_m *EVM2EVMOffRampInterface) GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetDestinationTokens") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -498,6 +574,10 @@ func (_m *EVM2EVMOffRampInterface) GetDestinationTokens(opts *bind.CallOpts) ([] func (_m *EVM2EVMOffRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetDynamicConfig") + } + var r0 evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, error)); ok { @@ -522,6 +602,10 @@ func (_m *EVM2EVMOffRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_ func (_m *EVM2EVMOffRampInterface) GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error) { ret := _m.Called(opts, sequenceNumber) + if len(ret) == 0 { + panic("no return value specified for GetExecutionState") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint8, error)); ok { @@ -546,6 +630,10 @@ func (_m *EVM2EVMOffRampInterface) GetExecutionState(opts *bind.CallOpts, sequen func (_m *EVM2EVMOffRampInterface) GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error) { ret := _m.Called(opts, destToken) + if len(ret) == 0 { + panic("no return value specified for GetPoolByDestToken") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok { @@ -572,6 +660,10 @@ func (_m *EVM2EVMOffRampInterface) GetPoolByDestToken(opts *bind.CallOpts, destT func (_m *EVM2EVMOffRampInterface) GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) { ret := _m.Called(opts, sourceToken) + if len(ret) == 0 { + panic("no return value specified for GetPoolBySourceToken") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok { @@ -598,6 +690,10 @@ func (_m *EVM2EVMOffRampInterface) GetPoolBySourceToken(opts *bind.CallOpts, sou func (_m *EVM2EVMOffRampInterface) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) { ret := _m.Called(opts, sender) + if len(ret) == 0 { + panic("no return value specified for GetSenderNonce") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok { @@ -622,6 +718,10 @@ func (_m *EVM2EVMOffRampInterface) GetSenderNonce(opts *bind.CallOpts, sender co func (_m *EVM2EVMOffRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampStaticConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetStaticConfig") + } + var r0 evm_2_evm_offramp.EVM2EVMOffRampStaticConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampStaticConfig, error)); ok { @@ -646,6 +746,10 @@ func (_m *EVM2EVMOffRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_e func (_m *EVM2EVMOffRampInterface) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetSupportedTokens") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -672,6 +776,10 @@ func (_m *EVM2EVMOffRampInterface) GetSupportedTokens(opts *bind.CallOpts) ([]co func (_m *EVM2EVMOffRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetTokenLimitAdmin") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -698,6 +806,10 @@ func (_m *EVM2EVMOffRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (comm func (_m *EVM2EVMOffRampInterface) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetTransmitters") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -724,6 +836,10 @@ func (_m *EVM2EVMOffRampInterface) GetTransmitters(opts *bind.CallOpts) ([]commo func (_m *EVM2EVMOffRampInterface) LatestConfigDetails(opts *bind.CallOpts) (evm_2_evm_offramp.LatestConfigDetails, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDetails") + } + var r0 evm_2_evm_offramp.LatestConfigDetails var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.LatestConfigDetails, error)); ok { @@ -748,6 +864,10 @@ func (_m *EVM2EVMOffRampInterface) LatestConfigDetails(opts *bind.CallOpts) (evm func (_m *EVM2EVMOffRampInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (evm_2_evm_offramp.LatestConfigDigestAndEpoch, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDigestAndEpoch") + } + var r0 evm_2_evm_offramp.LatestConfigDigestAndEpoch var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.LatestConfigDigestAndEpoch, error)); ok { @@ -772,6 +892,10 @@ func (_m *EVM2EVMOffRampInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpt func (_m *EVM2EVMOffRampInterface) ManuallyExecute(opts *bind.TransactOpts, report evm_2_evm_offramp.InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, report, gasLimitOverrides) + if len(ret) == 0 { + panic("no return value specified for ManuallyExecute") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalExecutionReport, []*big.Int) (*types.Transaction, error)); ok { @@ -798,6 +922,10 @@ func (_m *EVM2EVMOffRampInterface) ManuallyExecute(opts *bind.TransactOpts, repo func (_m *EVM2EVMOffRampInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -824,6 +952,10 @@ func (_m *EVM2EVMOffRampInterface) Owner(opts *bind.CallOpts) (common.Address, e func (_m *EVM2EVMOffRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAdminSet") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampAdminSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSet, error)); ok { @@ -850,6 +982,10 @@ func (_m *EVM2EVMOffRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_offr func (_m *EVM2EVMOffRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet, error)); ok { @@ -876,6 +1012,10 @@ func (_m *EVM2EVMOffRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_off func (_m *EVM2EVMOffRampInterface) ParseConfigSet0(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet0") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0 var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0, error)); ok { @@ -902,6 +1042,10 @@ func (_m *EVM2EVMOffRampInterface) ParseConfigSet0(log types.Log) (*evm_2_evm_of func (_m *EVM2EVMOffRampInterface) ParseExecutionStateChanged(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseExecutionStateChanged") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, error)); ok { @@ -928,6 +1072,10 @@ func (_m *EVM2EVMOffRampInterface) ParseExecutionStateChanged(log types.Log) (*e func (_m *EVM2EVMOffRampInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -954,6 +1102,10 @@ func (_m *EVM2EVMOffRampInterface) ParseLog(log types.Log) (generated.AbigenLog, func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferRequested(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, error)); ok { @@ -980,6 +1132,10 @@ func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferRequested(log types.Log func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferred(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, error)); ok { @@ -1006,6 +1162,10 @@ func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferred(log types.Log) (*ev func (_m *EVM2EVMOffRampInterface) ParsePoolAdded(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampPoolAdded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePoolAdded") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampPoolAdded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampPoolAdded, error)); ok { @@ -1032,6 +1192,10 @@ func (_m *EVM2EVMOffRampInterface) ParsePoolAdded(log types.Log) (*evm_2_evm_off func (_m *EVM2EVMOffRampInterface) ParsePoolRemoved(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampPoolRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePoolRemoved") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampPoolRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampPoolRemoved, error)); ok { @@ -1058,6 +1222,10 @@ func (_m *EVM2EVMOffRampInterface) ParsePoolRemoved(log types.Log) (*evm_2_evm_o func (_m *EVM2EVMOffRampInterface) ParseSkippedIncorrectNonce(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSkippedIncorrectNonce") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, error)); ok { @@ -1084,6 +1252,10 @@ func (_m *EVM2EVMOffRampInterface) ParseSkippedIncorrectNonce(log types.Log) (*e func (_m *EVM2EVMOffRampInterface) ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSkippedSenderWithPreviousRampMessageInflight") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)); ok { @@ -1110,6 +1282,10 @@ func (_m *EVM2EVMOffRampInterface) ParseSkippedSenderWithPreviousRampMessageInfl func (_m *EVM2EVMOffRampInterface) ParseTransmitted(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTransmitted, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseTransmitted") + } + var r0 *evm_2_evm_offramp.EVM2EVMOffRampTransmitted var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTransmitted, error)); ok { @@ -1136,6 +1312,10 @@ func (_m *EVM2EVMOffRampInterface) ParseTransmitted(log types.Log) (*evm_2_evm_o func (_m *EVM2EVMOffRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) { ret := _m.Called(opts, newAdmin) + if len(ret) == 0 { + panic("no return value specified for SetAdmin") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1162,6 +1342,10 @@ func (_m *EVM2EVMOffRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin co func (_m *EVM2EVMOffRampInterface) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) + if len(ret) == 0 { + panic("no return value specified for SetOCR2Config") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok { @@ -1188,6 +1372,10 @@ func (_m *EVM2EVMOffRampInterface) SetOCR2Config(opts *bind.TransactOpts, signer func (_m *EVM2EVMOffRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, config evm_2_evm_offramp.RateLimiterConfig) (*types.Transaction, error) { ret := _m.Called(opts, config) + if len(ret) == 0 { + panic("no return value specified for SetRateLimiterConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.RateLimiterConfig) (*types.Transaction, error)); ok { @@ -1214,6 +1402,10 @@ func (_m *EVM2EVMOffRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, func (_m *EVM2EVMOffRampInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1240,6 +1432,10 @@ func (_m *EVM2EVMOffRampInterface) TransferOwnership(opts *bind.TransactOpts, to func (_m *EVM2EVMOffRampInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) { ret := _m.Called(opts, reportContext, report, rs, ss, arg4) + if len(ret) == 0 { + panic("no return value specified for Transmit") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok { @@ -1266,6 +1462,10 @@ func (_m *EVM2EVMOffRampInterface) Transmit(opts *bind.TransactOpts, reportConte func (_m *EVM2EVMOffRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -1290,6 +1490,10 @@ func (_m *EVM2EVMOffRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, func (_m *EVM2EVMOffRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchAdminSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet) (event.Subscription, error)); ok { @@ -1316,6 +1520,10 @@ func (_m *EVM2EVMOffRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan func (_m *EVM2EVMOffRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet) (event.Subscription, error)); ok { @@ -1342,6 +1550,10 @@ func (_m *EVM2EVMOffRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink cha func (_m *EVM2EVMOffRampInterface) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet0") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0) (event.Subscription, error)); ok { @@ -1368,6 +1580,10 @@ func (_m *EVM2EVMOffRampInterface) WatchConfigSet0(opts *bind.WatchOpts, sink ch func (_m *EVM2EVMOffRampInterface) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) { ret := _m.Called(opts, sink, sequenceNumber, messageId) + if len(ret) == 0 { + panic("no return value specified for WatchExecutionStateChanged") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) (event.Subscription, error)); ok { @@ -1394,6 +1610,10 @@ func (_m *EVM2EVMOffRampInterface) WatchExecutionStateChanged(opts *bind.WatchOp func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1420,6 +1640,10 @@ func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferRequested(opts *bind.Wa func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1446,6 +1670,10 @@ func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpt func (_m *EVM2EVMOffRampInterface) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampPoolAdded) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchPoolAdded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampPoolAdded) (event.Subscription, error)); ok { @@ -1472,6 +1700,10 @@ func (_m *EVM2EVMOffRampInterface) WatchPoolAdded(opts *bind.WatchOpts, sink cha func (_m *EVM2EVMOffRampInterface) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampPoolRemoved) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchPoolRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampPoolRemoved) (event.Subscription, error)); ok { @@ -1498,6 +1730,10 @@ func (_m *EVM2EVMOffRampInterface) WatchPoolRemoved(opts *bind.WatchOpts, sink c func (_m *EVM2EVMOffRampInterface) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, nonce, sender) + if len(ret) == 0 { + panic("no return value specified for WatchSkippedIncorrectNonce") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) (event.Subscription, error)); ok { @@ -1524,6 +1760,10 @@ func (_m *EVM2EVMOffRampInterface) WatchSkippedIncorrectNonce(opts *bind.WatchOp func (_m *EVM2EVMOffRampInterface) WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, nonce, sender) + if len(ret) == 0 { + panic("no return value specified for WatchSkippedSenderWithPreviousRampMessageInflight") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) (event.Subscription, error)); ok { @@ -1550,6 +1790,10 @@ func (_m *EVM2EVMOffRampInterface) WatchSkippedSenderWithPreviousRampMessageInfl func (_m *EVM2EVMOffRampInterface) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchTransmitted") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted) (event.Subscription, error)); ok { diff --git a/core/gethwrappers/ccip/mocks/evm2_evm_on_ramp_interface.go b/core/gethwrappers/ccip/mocks/evm2_evm_on_ramp_interface.go index e03322fc1d..a4dd4d861b 100644 --- a/core/gethwrappers/ccip/mocks/evm2_evm_on_ramp_interface.go +++ b/core/gethwrappers/ccip/mocks/evm2_evm_on_ramp_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mock_contracts @@ -28,6 +28,10 @@ type EVM2EVMOnRampInterface struct { func (_m *EVM2EVMOnRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *EVM2EVMOnRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*typ func (_m *EVM2EVMOnRampInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -70,6 +78,10 @@ func (_m *EVM2EVMOnRampInterface) Address() common.Address { func (_m *EVM2EVMOnRampInterface) ApplyPoolUpdates(opts *bind.TransactOpts, removes []evm_2_evm_onramp.InternalPoolUpdate, adds []evm_2_evm_onramp.InternalPoolUpdate) (*types.Transaction, error) { ret := _m.Called(opts, removes, adds) + if len(ret) == 0 { + panic("no return value specified for ApplyPoolUpdates") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.InternalPoolUpdate, []evm_2_evm_onramp.InternalPoolUpdate) (*types.Transaction, error)); ok { @@ -96,6 +108,10 @@ func (_m *EVM2EVMOnRampInterface) ApplyPoolUpdates(opts *bind.TransactOpts, remo func (_m *EVM2EVMOnRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) (evm_2_evm_onramp.RateLimiterTokenBucket, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CurrentRateLimiterState") + } + var r0 evm_2_evm_onramp.RateLimiterTokenBucket var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.RateLimiterTokenBucket, error)); ok { @@ -120,6 +136,10 @@ func (_m *EVM2EVMOnRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) ( func (_m *EVM2EVMOnRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterAdminSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator, error)); ok { @@ -146,6 +166,10 @@ func (_m *EVM2EVMOnRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2_ func (_m *EVM2EVMOnRampInterface) FilterCCIPSendRequested(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCCIPSendRequested") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator, error)); ok { @@ -172,6 +196,10 @@ func (_m *EVM2EVMOnRampInterface) FilterCCIPSendRequested(opts *bind.FilterOpts) func (_m *EVM2EVMOnRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator, error)); ok { @@ -198,6 +226,10 @@ func (_m *EVM2EVMOnRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_2 func (_m *EVM2EVMOnRampInterface) FilterFeeConfigSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterFeeConfigSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator, error)); ok { @@ -224,6 +256,10 @@ func (_m *EVM2EVMOnRampInterface) FilterFeeConfigSet(opts *bind.FilterOpts) (*ev func (_m *EVM2EVMOnRampInterface) FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator, error) { ret := _m.Called(opts, nop) + if len(ret) == 0 { + panic("no return value specified for FilterNopPaid") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator, error)); ok { @@ -250,6 +286,10 @@ func (_m *EVM2EVMOnRampInterface) FilterNopPaid(opts *bind.FilterOpts, nop []com func (_m *EVM2EVMOnRampInterface) FilterNopsSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterNopsSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator, error)); ok { @@ -276,6 +316,10 @@ func (_m *EVM2EVMOnRampInterface) FilterNopsSet(opts *bind.FilterOpts) (*evm_2_e func (_m *EVM2EVMOnRampInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator, error)); ok { @@ -302,6 +346,10 @@ func (_m *EVM2EVMOnRampInterface) FilterOwnershipTransferRequested(opts *bind.Fi func (_m *EVM2EVMOnRampInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator, error)); ok { @@ -328,6 +376,10 @@ func (_m *EVM2EVMOnRampInterface) FilterOwnershipTransferred(opts *bind.FilterOp func (_m *EVM2EVMOnRampInterface) FilterPoolAdded(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampPoolAddedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterPoolAdded") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampPoolAddedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampPoolAddedIterator, error)); ok { @@ -354,6 +406,10 @@ func (_m *EVM2EVMOnRampInterface) FilterPoolAdded(opts *bind.FilterOpts) (*evm_2 func (_m *EVM2EVMOnRampInterface) FilterPoolRemoved(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampPoolRemovedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterPoolRemoved") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampPoolRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampPoolRemovedIterator, error)); ok { @@ -380,6 +436,10 @@ func (_m *EVM2EVMOnRampInterface) FilterPoolRemoved(opts *bind.FilterOpts) (*evm func (_m *EVM2EVMOnRampInterface) FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterTokenTransferFeeConfigSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error)); ok { @@ -406,6 +466,10 @@ func (_m *EVM2EVMOnRampInterface) FilterTokenTransferFeeConfigSet(opts *bind.Fil func (_m *EVM2EVMOnRampInterface) ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message evm_2_evm_onramp.ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) { ret := _m.Called(opts, destChainSelector, message, feeTokenAmount, originalSender) + if len(ret) == 0 { + panic("no return value specified for ForwardFromRouter") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -432,6 +496,10 @@ func (_m *EVM2EVMOnRampInterface) ForwardFromRouter(opts *bind.TransactOpts, des func (_m *EVM2EVMOnRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetDynamicConfig") + } + var r0 evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig, error)); ok { @@ -456,6 +524,10 @@ func (_m *EVM2EVMOnRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_e func (_m *EVM2EVMOnRampInterface) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetExpectedNextSequenceNumber") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok { @@ -480,6 +552,10 @@ func (_m *EVM2EVMOnRampInterface) GetExpectedNextSequenceNumber(opts *bind.CallO func (_m *EVM2EVMOnRampInterface) GetFee(opts *bind.CallOpts, destChainSelector uint64, message evm_2_evm_onramp.ClientEVM2AnyMessage) (*big.Int, error) { ret := _m.Called(opts, destChainSelector, message) + if len(ret) == 0 { + panic("no return value specified for GetFee") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage) (*big.Int, error)); ok { @@ -506,6 +582,10 @@ func (_m *EVM2EVMOnRampInterface) GetFee(opts *bind.CallOpts, destChainSelector func (_m *EVM2EVMOnRampInterface) GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig, error) { ret := _m.Called(opts, token) + if len(ret) == 0 { + panic("no return value specified for GetFeeTokenConfig") + } + var r0 evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig, error)); ok { @@ -530,6 +610,10 @@ func (_m *EVM2EVMOnRampInterface) GetFeeTokenConfig(opts *bind.CallOpts, token c func (_m *EVM2EVMOnRampInterface) GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetNopFeesJuels") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -556,6 +640,10 @@ func (_m *EVM2EVMOnRampInterface) GetNopFeesJuels(opts *bind.CallOpts) (*big.Int func (_m *EVM2EVMOnRampInterface) GetNops(opts *bind.CallOpts) (evm_2_evm_onramp.GetNops, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetNops") + } + var r0 evm_2_evm_onramp.GetNops var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.GetNops, error)); ok { @@ -580,6 +668,10 @@ func (_m *EVM2EVMOnRampInterface) GetNops(opts *bind.CallOpts) (evm_2_evm_onramp func (_m *EVM2EVMOnRampInterface) GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error) { ret := _m.Called(opts, arg0, sourceToken) + if len(ret) == 0 { + panic("no return value specified for GetPoolBySourceToken") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address) (common.Address, error)); ok { @@ -606,6 +698,10 @@ func (_m *EVM2EVMOnRampInterface) GetPoolBySourceToken(opts *bind.CallOpts, arg0 func (_m *EVM2EVMOnRampInterface) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) { ret := _m.Called(opts, sender) + if len(ret) == 0 { + panic("no return value specified for GetSenderNonce") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok { @@ -630,6 +726,10 @@ func (_m *EVM2EVMOnRampInterface) GetSenderNonce(opts *bind.CallOpts, sender com func (_m *EVM2EVMOnRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetStaticConfig") + } + var r0 evm_2_evm_onramp.EVM2EVMOnRampStaticConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, error)); ok { @@ -654,6 +754,10 @@ func (_m *EVM2EVMOnRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_ev func (_m *EVM2EVMOnRampInterface) GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error) { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for GetSupportedTokens") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) ([]common.Address, error)); ok { @@ -680,6 +784,10 @@ func (_m *EVM2EVMOnRampInterface) GetSupportedTokens(opts *bind.CallOpts, arg0 u func (_m *EVM2EVMOnRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetTokenLimitAdmin") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -706,6 +814,10 @@ func (_m *EVM2EVMOnRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (commo func (_m *EVM2EVMOnRampInterface) GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig, error) { ret := _m.Called(opts, token) + if len(ret) == 0 { + panic("no return value specified for GetTokenTransferFeeConfig") + } + var r0 evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig, error)); ok { @@ -730,6 +842,10 @@ func (_m *EVM2EVMOnRampInterface) GetTokenTransferFeeConfig(opts *bind.CallOpts, func (_m *EVM2EVMOnRampInterface) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LinkAvailableForPayment") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -756,6 +872,10 @@ func (_m *EVM2EVMOnRampInterface) LinkAvailableForPayment(opts *bind.CallOpts) ( func (_m *EVM2EVMOnRampInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -782,6 +902,10 @@ func (_m *EVM2EVMOnRampInterface) Owner(opts *bind.CallOpts) (common.Address, er func (_m *EVM2EVMOnRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAdminSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampAdminSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSet, error)); ok { @@ -808,6 +932,10 @@ func (_m *EVM2EVMOnRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_onram func (_m *EVM2EVMOnRampInterface) ParseCCIPSendRequested(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCCIPSendRequested") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested, error)); ok { @@ -834,6 +962,10 @@ func (_m *EVM2EVMOnRampInterface) ParseCCIPSendRequested(log types.Log) (*evm_2_ func (_m *EVM2EVMOnRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSet, error)); ok { @@ -860,6 +992,10 @@ func (_m *EVM2EVMOnRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_onra func (_m *EVM2EVMOnRampInterface) ParseFeeConfigSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFeeConfigSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet, error)); ok { @@ -886,6 +1022,10 @@ func (_m *EVM2EVMOnRampInterface) ParseFeeConfigSet(log types.Log) (*evm_2_evm_o func (_m *EVM2EVMOnRampInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -912,6 +1052,10 @@ func (_m *EVM2EVMOnRampInterface) ParseLog(log types.Log) (generated.AbigenLog, func (_m *EVM2EVMOnRampInterface) ParseNopPaid(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaid, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseNopPaid") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopPaid var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaid, error)); ok { @@ -938,6 +1082,10 @@ func (_m *EVM2EVMOnRampInterface) ParseNopPaid(log types.Log) (*evm_2_evm_onramp func (_m *EVM2EVMOnRampInterface) ParseNopsSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseNopsSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopsSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSet, error)); ok { @@ -964,6 +1112,10 @@ func (_m *EVM2EVMOnRampInterface) ParseNopsSet(log types.Log) (*evm_2_evm_onramp func (_m *EVM2EVMOnRampInterface) ParseOwnershipTransferRequested(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, error)); ok { @@ -990,6 +1142,10 @@ func (_m *EVM2EVMOnRampInterface) ParseOwnershipTransferRequested(log types.Log) func (_m *EVM2EVMOnRampInterface) ParseOwnershipTransferred(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, error)); ok { @@ -1016,6 +1172,10 @@ func (_m *EVM2EVMOnRampInterface) ParseOwnershipTransferred(log types.Log) (*evm func (_m *EVM2EVMOnRampInterface) ParsePoolAdded(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampPoolAdded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePoolAdded") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampPoolAdded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampPoolAdded, error)); ok { @@ -1042,6 +1202,10 @@ func (_m *EVM2EVMOnRampInterface) ParsePoolAdded(log types.Log) (*evm_2_evm_onra func (_m *EVM2EVMOnRampInterface) ParsePoolRemoved(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampPoolRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePoolRemoved") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampPoolRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampPoolRemoved, error)); ok { @@ -1068,6 +1232,10 @@ func (_m *EVM2EVMOnRampInterface) ParsePoolRemoved(log types.Log) (*evm_2_evm_on func (_m *EVM2EVMOnRampInterface) ParseTokenTransferFeeConfigSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseTokenTransferFeeConfigSet") + } + var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet, error)); ok { @@ -1094,6 +1262,10 @@ func (_m *EVM2EVMOnRampInterface) ParseTokenTransferFeeConfigSet(log types.Log) func (_m *EVM2EVMOnRampInterface) PayNops(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for PayNops") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -1120,6 +1292,10 @@ func (_m *EVM2EVMOnRampInterface) PayNops(opts *bind.TransactOpts) (*types.Trans func (_m *EVM2EVMOnRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) { ret := _m.Called(opts, newAdmin) + if len(ret) == 0 { + panic("no return value specified for SetAdmin") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1146,6 +1322,10 @@ func (_m *EVM2EVMOnRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin com func (_m *EVM2EVMOnRampInterface) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) { ret := _m.Called(opts, dynamicConfig) + if len(ret) == 0 { + panic("no return value specified for SetDynamicConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig) (*types.Transaction, error)); ok { @@ -1172,6 +1352,10 @@ func (_m *EVM2EVMOnRampInterface) SetDynamicConfig(opts *bind.TransactOpts, dyna func (_m *EVM2EVMOnRampInterface) SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) { ret := _m.Called(opts, feeTokenConfigArgs) + if len(ret) == 0 { + panic("no return value specified for SetFeeTokenConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error)); ok { @@ -1198,6 +1382,10 @@ func (_m *EVM2EVMOnRampInterface) SetFeeTokenConfig(opts *bind.TransactOpts, fee func (_m *EVM2EVMOnRampInterface) SetNops(opts *bind.TransactOpts, nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) { ret := _m.Called(opts, nopsAndWeights) + if len(ret) == 0 { + panic("no return value specified for SetNops") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) (*types.Transaction, error)); ok { @@ -1224,6 +1412,10 @@ func (_m *EVM2EVMOnRampInterface) SetNops(opts *bind.TransactOpts, nopsAndWeight func (_m *EVM2EVMOnRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, config evm_2_evm_onramp.RateLimiterConfig) (*types.Transaction, error) { ret := _m.Called(opts, config) + if len(ret) == 0 { + panic("no return value specified for SetRateLimiterConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_onramp.RateLimiterConfig) (*types.Transaction, error)); ok { @@ -1250,6 +1442,10 @@ func (_m *EVM2EVMOnRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, func (_m *EVM2EVMOnRampInterface) SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) { ret := _m.Called(opts, tokenTransferFeeConfigArgs) + if len(ret) == 0 { + panic("no return value specified for SetTokenTransferFeeConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error)); ok { @@ -1276,6 +1472,10 @@ func (_m *EVM2EVMOnRampInterface) SetTokenTransferFeeConfig(opts *bind.TransactO func (_m *EVM2EVMOnRampInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1302,6 +1502,10 @@ func (_m *EVM2EVMOnRampInterface) TransferOwnership(opts *bind.TransactOpts, to func (_m *EVM2EVMOnRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -1326,6 +1530,10 @@ func (_m *EVM2EVMOnRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, e func (_m *EVM2EVMOnRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchAdminSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet) (event.Subscription, error)); ok { @@ -1352,6 +1560,10 @@ func (_m *EVM2EVMOnRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan< func (_m *EVM2EVMOnRampInterface) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCCIPSendRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error)); ok { @@ -1378,6 +1590,10 @@ func (_m *EVM2EVMOnRampInterface) WatchCCIPSendRequested(opts *bind.WatchOpts, s func (_m *EVM2EVMOnRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet) (event.Subscription, error)); ok { @@ -1404,6 +1620,10 @@ func (_m *EVM2EVMOnRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan func (_m *EVM2EVMOnRampInterface) WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchFeeConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet) (event.Subscription, error)); ok { @@ -1430,6 +1650,10 @@ func (_m *EVM2EVMOnRampInterface) WatchFeeConfigSet(opts *bind.WatchOpts, sink c func (_m *EVM2EVMOnRampInterface) WatchNopPaid(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, nop) + if len(ret) == 0 { + panic("no return value specified for WatchNopPaid") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, []common.Address) (event.Subscription, error)); ok { @@ -1456,6 +1680,10 @@ func (_m *EVM2EVMOnRampInterface) WatchNopPaid(opts *bind.WatchOpts, sink chan<- func (_m *EVM2EVMOnRampInterface) WatchNopsSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchNopsSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet) (event.Subscription, error)); ok { @@ -1482,6 +1710,10 @@ func (_m *EVM2EVMOnRampInterface) WatchNopsSet(opts *bind.WatchOpts, sink chan<- func (_m *EVM2EVMOnRampInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1508,6 +1740,10 @@ func (_m *EVM2EVMOnRampInterface) WatchOwnershipTransferRequested(opts *bind.Wat func (_m *EVM2EVMOnRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1534,6 +1770,10 @@ func (_m *EVM2EVMOnRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpts func (_m *EVM2EVMOnRampInterface) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampPoolAdded) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchPoolAdded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampPoolAdded) (event.Subscription, error)); ok { @@ -1560,6 +1800,10 @@ func (_m *EVM2EVMOnRampInterface) WatchPoolAdded(opts *bind.WatchOpts, sink chan func (_m *EVM2EVMOnRampInterface) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampPoolRemoved) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchPoolRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampPoolRemoved) (event.Subscription, error)); ok { @@ -1586,6 +1830,10 @@ func (_m *EVM2EVMOnRampInterface) WatchPoolRemoved(opts *bind.WatchOpts, sink ch func (_m *EVM2EVMOnRampInterface) WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchTokenTransferFeeConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error)); ok { @@ -1612,6 +1860,10 @@ func (_m *EVM2EVMOnRampInterface) WatchTokenTransferFeeConfigSet(opts *bind.Watc func (_m *EVM2EVMOnRampInterface) WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, feeToken, to) + if len(ret) == 0 { + panic("no return value specified for WithdrawNonLinkFees") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok { diff --git a/core/gethwrappers/ccip/mocks/link_token_interface.go b/core/gethwrappers/ccip/mocks/link_token_interface.go index a7bd39a01c..3a5ae501f2 100644 --- a/core/gethwrappers/ccip/mocks/link_token_interface.go +++ b/core/gethwrappers/ccip/mocks/link_token_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mock_contracts @@ -28,6 +28,10 @@ type LinkTokenInterface struct { func (_m *LinkTokenInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -44,6 +48,10 @@ func (_m *LinkTokenInterface) Address() common.Address { func (_m *LinkTokenInterface) Allowance(opts *bind.CallOpts, _owner common.Address, _spender common.Address) (*big.Int, error) { ret := _m.Called(opts, _owner, _spender) + if len(ret) == 0 { + panic("no return value specified for Allowance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address) (*big.Int, error)); ok { @@ -70,6 +78,10 @@ func (_m *LinkTokenInterface) Allowance(opts *bind.CallOpts, _owner common.Addre func (_m *LinkTokenInterface) Approve(opts *bind.TransactOpts, _spender common.Address, _value *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _spender, _value) + if len(ret) == 0 { + panic("no return value specified for Approve") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -96,6 +108,10 @@ func (_m *LinkTokenInterface) Approve(opts *bind.TransactOpts, _spender common.A func (_m *LinkTokenInterface) BalanceOf(opts *bind.CallOpts, _owner common.Address) (*big.Int, error) { ret := _m.Called(opts, _owner) + if len(ret) == 0 { + panic("no return value specified for BalanceOf") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { @@ -122,6 +138,10 @@ func (_m *LinkTokenInterface) BalanceOf(opts *bind.CallOpts, _owner common.Addre func (_m *LinkTokenInterface) Decimals(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Decimals") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -146,6 +166,10 @@ func (_m *LinkTokenInterface) Decimals(opts *bind.CallOpts) (uint8, error) { func (_m *LinkTokenInterface) DecreaseApproval(opts *bind.TransactOpts, _spender common.Address, _subtractedValue *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _spender, _subtractedValue) + if len(ret) == 0 { + panic("no return value specified for DecreaseApproval") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -172,6 +196,10 @@ func (_m *LinkTokenInterface) DecreaseApproval(opts *bind.TransactOpts, _spender func (_m *LinkTokenInterface) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*link_token_interface.LinkTokenApprovalIterator, error) { ret := _m.Called(opts, owner, spender) + if len(ret) == 0 { + panic("no return value specified for FilterApproval") + } + var r0 *link_token_interface.LinkTokenApprovalIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*link_token_interface.LinkTokenApprovalIterator, error)); ok { @@ -198,6 +226,10 @@ func (_m *LinkTokenInterface) FilterApproval(opts *bind.FilterOpts, owner []comm func (_m *LinkTokenInterface) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*link_token_interface.LinkTokenTransferIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterTransfer") + } + var r0 *link_token_interface.LinkTokenTransferIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*link_token_interface.LinkTokenTransferIterator, error)); ok { @@ -224,6 +256,10 @@ func (_m *LinkTokenInterface) FilterTransfer(opts *bind.FilterOpts, from []commo func (_m *LinkTokenInterface) IncreaseApproval(opts *bind.TransactOpts, _spender common.Address, _addedValue *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _spender, _addedValue) + if len(ret) == 0 { + panic("no return value specified for IncreaseApproval") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -250,6 +286,10 @@ func (_m *LinkTokenInterface) IncreaseApproval(opts *bind.TransactOpts, _spender func (_m *LinkTokenInterface) Name(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -274,6 +314,10 @@ func (_m *LinkTokenInterface) Name(opts *bind.CallOpts) (string, error) { func (_m *LinkTokenInterface) ParseApproval(log types.Log) (*link_token_interface.LinkTokenApproval, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseApproval") + } + var r0 *link_token_interface.LinkTokenApproval var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*link_token_interface.LinkTokenApproval, error)); ok { @@ -300,6 +344,10 @@ func (_m *LinkTokenInterface) ParseApproval(log types.Log) (*link_token_interfac func (_m *LinkTokenInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -326,6 +374,10 @@ func (_m *LinkTokenInterface) ParseLog(log types.Log) (generated.AbigenLog, erro func (_m *LinkTokenInterface) ParseTransfer(log types.Log) (*link_token_interface.LinkTokenTransfer, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseTransfer") + } + var r0 *link_token_interface.LinkTokenTransfer var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*link_token_interface.LinkTokenTransfer, error)); ok { @@ -352,6 +404,10 @@ func (_m *LinkTokenInterface) ParseTransfer(log types.Log) (*link_token_interfac func (_m *LinkTokenInterface) Symbol(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Symbol") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -376,6 +432,10 @@ func (_m *LinkTokenInterface) Symbol(opts *bind.CallOpts) (string, error) { func (_m *LinkTokenInterface) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TotalSupply") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -402,6 +462,10 @@ func (_m *LinkTokenInterface) TotalSupply(opts *bind.CallOpts) (*big.Int, error) func (_m *LinkTokenInterface) Transfer(opts *bind.TransactOpts, _to common.Address, _value *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _to, _value) + if len(ret) == 0 { + panic("no return value specified for Transfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -428,6 +492,10 @@ func (_m *LinkTokenInterface) Transfer(opts *bind.TransactOpts, _to common.Addre func (_m *LinkTokenInterface) TransferAndCall(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) { ret := _m.Called(opts, _to, _value, _data) + if len(ret) == 0 { + panic("no return value specified for TransferAndCall") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -454,6 +522,10 @@ func (_m *LinkTokenInterface) TransferAndCall(opts *bind.TransactOpts, _to commo func (_m *LinkTokenInterface) TransferFrom(opts *bind.TransactOpts, _from common.Address, _to common.Address, _value *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _from, _to, _value) + if len(ret) == 0 { + panic("no return value specified for TransferFrom") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -480,6 +552,10 @@ func (_m *LinkTokenInterface) TransferFrom(opts *bind.TransactOpts, _from common func (_m *LinkTokenInterface) WatchApproval(opts *bind.WatchOpts, sink chan<- *link_token_interface.LinkTokenApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, owner, spender) + if len(ret) == 0 { + panic("no return value specified for WatchApproval") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenApproval, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -506,6 +582,10 @@ func (_m *LinkTokenInterface) WatchApproval(opts *bind.WatchOpts, sink chan<- *l func (_m *LinkTokenInterface) WatchTransfer(opts *bind.WatchOpts, sink chan<- *link_token_interface.LinkTokenTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchTransfer") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenTransfer, []common.Address, []common.Address) (event.Subscription, error)); ok { diff --git a/core/gethwrappers/ccip/mocks/price_registry_interface.go b/core/gethwrappers/ccip/mocks/price_registry_interface.go index f006daa8ee..b51b04d34f 100644 --- a/core/gethwrappers/ccip/mocks/price_registry_interface.go +++ b/core/gethwrappers/ccip/mocks/price_registry_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mock_contracts @@ -28,6 +28,10 @@ type PriceRegistryInterface struct { func (_m *PriceRegistryInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *PriceRegistryInterface) AcceptOwnership(opts *bind.TransactOpts) (*typ func (_m *PriceRegistryInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -70,6 +78,10 @@ func (_m *PriceRegistryInterface) Address() common.Address { func (_m *PriceRegistryInterface) ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, feeTokensToAdd, feeTokensToRemove) + if len(ret) == 0 { + panic("no return value specified for ApplyFeeTokensUpdates") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) (*types.Transaction, error)); ok { @@ -96,6 +108,10 @@ func (_m *PriceRegistryInterface) ApplyFeeTokensUpdates(opts *bind.TransactOpts, func (_m *PriceRegistryInterface) ApplyPriceUpdatersUpdates(opts *bind.TransactOpts, priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, priceUpdatersToAdd, priceUpdatersToRemove) + if len(ret) == 0 { + panic("no return value specified for ApplyPriceUpdatersUpdates") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) (*types.Transaction, error)); ok { @@ -122,6 +138,10 @@ func (_m *PriceRegistryInterface) ApplyPriceUpdatersUpdates(opts *bind.TransactO func (_m *PriceRegistryInterface) ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) { ret := _m.Called(opts, fromToken, fromTokenAmount, toToken) + if len(ret) == 0 { + panic("no return value specified for ConvertTokenAmount") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, *big.Int, common.Address) (*big.Int, error)); ok { @@ -148,6 +168,10 @@ func (_m *PriceRegistryInterface) ConvertTokenAmount(opts *bind.CallOpts, fromTo func (_m *PriceRegistryInterface) FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*price_registry.PriceRegistryFeeTokenAddedIterator, error) { ret := _m.Called(opts, feeToken) + if len(ret) == 0 { + panic("no return value specified for FilterFeeTokenAdded") + } + var r0 *price_registry.PriceRegistryFeeTokenAddedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryFeeTokenAddedIterator, error)); ok { @@ -174,6 +198,10 @@ func (_m *PriceRegistryInterface) FilterFeeTokenAdded(opts *bind.FilterOpts, fee func (_m *PriceRegistryInterface) FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*price_registry.PriceRegistryFeeTokenRemovedIterator, error) { ret := _m.Called(opts, feeToken) + if len(ret) == 0 { + panic("no return value specified for FilterFeeTokenRemoved") + } + var r0 *price_registry.PriceRegistryFeeTokenRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryFeeTokenRemovedIterator, error)); ok { @@ -200,6 +228,10 @@ func (_m *PriceRegistryInterface) FilterFeeTokenRemoved(opts *bind.FilterOpts, f func (_m *PriceRegistryInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*price_registry.PriceRegistryOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *price_registry.PriceRegistryOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*price_registry.PriceRegistryOwnershipTransferRequestedIterator, error)); ok { @@ -226,6 +258,10 @@ func (_m *PriceRegistryInterface) FilterOwnershipTransferRequested(opts *bind.Fi func (_m *PriceRegistryInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*price_registry.PriceRegistryOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *price_registry.PriceRegistryOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*price_registry.PriceRegistryOwnershipTransferredIterator, error)); ok { @@ -252,6 +288,10 @@ func (_m *PriceRegistryInterface) FilterOwnershipTransferred(opts *bind.FilterOp func (_m *PriceRegistryInterface) FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*price_registry.PriceRegistryPriceUpdaterRemovedIterator, error) { ret := _m.Called(opts, priceUpdater) + if len(ret) == 0 { + panic("no return value specified for FilterPriceUpdaterRemoved") + } + var r0 *price_registry.PriceRegistryPriceUpdaterRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceUpdaterRemovedIterator, error)); ok { @@ -278,6 +318,10 @@ func (_m *PriceRegistryInterface) FilterPriceUpdaterRemoved(opts *bind.FilterOpt func (_m *PriceRegistryInterface) FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*price_registry.PriceRegistryPriceUpdaterSetIterator, error) { ret := _m.Called(opts, priceUpdater) + if len(ret) == 0 { + panic("no return value specified for FilterPriceUpdaterSet") + } + var r0 *price_registry.PriceRegistryPriceUpdaterSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceUpdaterSetIterator, error)); ok { @@ -304,6 +348,10 @@ func (_m *PriceRegistryInterface) FilterPriceUpdaterSet(opts *bind.FilterOpts, p func (_m *PriceRegistryInterface) FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*price_registry.PriceRegistryUsdPerTokenUpdatedIterator, error) { ret := _m.Called(opts, token) + if len(ret) == 0 { + panic("no return value specified for FilterUsdPerTokenUpdated") + } + var r0 *price_registry.PriceRegistryUsdPerTokenUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryUsdPerTokenUpdatedIterator, error)); ok { @@ -330,6 +378,10 @@ func (_m *PriceRegistryInterface) FilterUsdPerTokenUpdated(opts *bind.FilterOpts func (_m *PriceRegistryInterface) FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator, error) { ret := _m.Called(opts, destChain) + if len(ret) == 0 { + panic("no return value specified for FilterUsdPerUnitGasUpdated") + } + var r0 *price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator, error)); ok { @@ -356,6 +408,10 @@ func (_m *PriceRegistryInterface) FilterUsdPerUnitGasUpdated(opts *bind.FilterOp func (_m *PriceRegistryInterface) GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (price_registry.InternalTimestampedPackedUint224, error) { ret := _m.Called(opts, destChainSelector) + if len(ret) == 0 { + panic("no return value specified for GetDestinationChainGasPrice") + } + var r0 price_registry.InternalTimestampedPackedUint224 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (price_registry.InternalTimestampedPackedUint224, error)); ok { @@ -380,6 +436,10 @@ func (_m *PriceRegistryInterface) GetDestinationChainGasPrice(opts *bind.CallOpt func (_m *PriceRegistryInterface) GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetFeeTokens") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -406,6 +466,10 @@ func (_m *PriceRegistryInterface) GetFeeTokens(opts *bind.CallOpts) ([]common.Ad func (_m *PriceRegistryInterface) GetPriceUpdaters(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetPriceUpdaters") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -432,6 +496,10 @@ func (_m *PriceRegistryInterface) GetPriceUpdaters(opts *bind.CallOpts) ([]commo func (_m *PriceRegistryInterface) GetStalenessThreshold(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetStalenessThreshold") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -458,6 +526,10 @@ func (_m *PriceRegistryInterface) GetStalenessThreshold(opts *bind.CallOpts) (*b func (_m *PriceRegistryInterface) GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (price_registry.GetTokenAndGasPrices, error) { ret := _m.Called(opts, token, destChainSelector) + if len(ret) == 0 { + panic("no return value specified for GetTokenAndGasPrices") + } + var r0 price_registry.GetTokenAndGasPrices var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, uint64) (price_registry.GetTokenAndGasPrices, error)); ok { @@ -482,6 +554,10 @@ func (_m *PriceRegistryInterface) GetTokenAndGasPrices(opts *bind.CallOpts, toke func (_m *PriceRegistryInterface) GetTokenPrice(opts *bind.CallOpts, token common.Address) (price_registry.InternalTimestampedPackedUint224, error) { ret := _m.Called(opts, token) + if len(ret) == 0 { + panic("no return value specified for GetTokenPrice") + } + var r0 price_registry.InternalTimestampedPackedUint224 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (price_registry.InternalTimestampedPackedUint224, error)); ok { @@ -506,6 +582,10 @@ func (_m *PriceRegistryInterface) GetTokenPrice(opts *bind.CallOpts, token commo func (_m *PriceRegistryInterface) GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]price_registry.InternalTimestampedPackedUint224, error) { ret := _m.Called(opts, tokens) + if len(ret) == 0 { + panic("no return value specified for GetTokenPrices") + } + var r0 []price_registry.InternalTimestampedPackedUint224 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, []common.Address) ([]price_registry.InternalTimestampedPackedUint224, error)); ok { @@ -532,6 +612,10 @@ func (_m *PriceRegistryInterface) GetTokenPrices(opts *bind.CallOpts, tokens []c func (_m *PriceRegistryInterface) GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error) { ret := _m.Called(opts, token) + if len(ret) == 0 { + panic("no return value specified for GetValidatedTokenPrice") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { @@ -558,6 +642,10 @@ func (_m *PriceRegistryInterface) GetValidatedTokenPrice(opts *bind.CallOpts, to func (_m *PriceRegistryInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -584,6 +672,10 @@ func (_m *PriceRegistryInterface) Owner(opts *bind.CallOpts) (common.Address, er func (_m *PriceRegistryInterface) ParseFeeTokenAdded(log types.Log) (*price_registry.PriceRegistryFeeTokenAdded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFeeTokenAdded") + } + var r0 *price_registry.PriceRegistryFeeTokenAdded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryFeeTokenAdded, error)); ok { @@ -610,6 +702,10 @@ func (_m *PriceRegistryInterface) ParseFeeTokenAdded(log types.Log) (*price_regi func (_m *PriceRegistryInterface) ParseFeeTokenRemoved(log types.Log) (*price_registry.PriceRegistryFeeTokenRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFeeTokenRemoved") + } + var r0 *price_registry.PriceRegistryFeeTokenRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryFeeTokenRemoved, error)); ok { @@ -636,6 +732,10 @@ func (_m *PriceRegistryInterface) ParseFeeTokenRemoved(log types.Log) (*price_re func (_m *PriceRegistryInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -662,6 +762,10 @@ func (_m *PriceRegistryInterface) ParseLog(log types.Log) (generated.AbigenLog, func (_m *PriceRegistryInterface) ParseOwnershipTransferRequested(log types.Log) (*price_registry.PriceRegistryOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *price_registry.PriceRegistryOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryOwnershipTransferRequested, error)); ok { @@ -688,6 +792,10 @@ func (_m *PriceRegistryInterface) ParseOwnershipTransferRequested(log types.Log) func (_m *PriceRegistryInterface) ParseOwnershipTransferred(log types.Log) (*price_registry.PriceRegistryOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *price_registry.PriceRegistryOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryOwnershipTransferred, error)); ok { @@ -714,6 +822,10 @@ func (_m *PriceRegistryInterface) ParseOwnershipTransferred(log types.Log) (*pri func (_m *PriceRegistryInterface) ParsePriceUpdaterRemoved(log types.Log) (*price_registry.PriceRegistryPriceUpdaterRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePriceUpdaterRemoved") + } + var r0 *price_registry.PriceRegistryPriceUpdaterRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryPriceUpdaterRemoved, error)); ok { @@ -740,6 +852,10 @@ func (_m *PriceRegistryInterface) ParsePriceUpdaterRemoved(log types.Log) (*pric func (_m *PriceRegistryInterface) ParsePriceUpdaterSet(log types.Log) (*price_registry.PriceRegistryPriceUpdaterSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePriceUpdaterSet") + } + var r0 *price_registry.PriceRegistryPriceUpdaterSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryPriceUpdaterSet, error)); ok { @@ -766,6 +882,10 @@ func (_m *PriceRegistryInterface) ParsePriceUpdaterSet(log types.Log) (*price_re func (_m *PriceRegistryInterface) ParseUsdPerTokenUpdated(log types.Log) (*price_registry.PriceRegistryUsdPerTokenUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseUsdPerTokenUpdated") + } + var r0 *price_registry.PriceRegistryUsdPerTokenUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryUsdPerTokenUpdated, error)); ok { @@ -792,6 +912,10 @@ func (_m *PriceRegistryInterface) ParseUsdPerTokenUpdated(log types.Log) (*price func (_m *PriceRegistryInterface) ParseUsdPerUnitGasUpdated(log types.Log) (*price_registry.PriceRegistryUsdPerUnitGasUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseUsdPerUnitGasUpdated") + } + var r0 *price_registry.PriceRegistryUsdPerUnitGasUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryUsdPerUnitGasUpdated, error)); ok { @@ -818,6 +942,10 @@ func (_m *PriceRegistryInterface) ParseUsdPerUnitGasUpdated(log types.Log) (*pri func (_m *PriceRegistryInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -844,6 +972,10 @@ func (_m *PriceRegistryInterface) TransferOwnership(opts *bind.TransactOpts, to func (_m *PriceRegistryInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -868,6 +1000,10 @@ func (_m *PriceRegistryInterface) TypeAndVersion(opts *bind.CallOpts) (string, e func (_m *PriceRegistryInterface) UpdatePrices(opts *bind.TransactOpts, priceUpdates price_registry.InternalPriceUpdates) (*types.Transaction, error) { ret := _m.Called(opts, priceUpdates) + if len(ret) == 0 { + panic("no return value specified for UpdatePrices") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, price_registry.InternalPriceUpdates) (*types.Transaction, error)); ok { @@ -894,6 +1030,10 @@ func (_m *PriceRegistryInterface) UpdatePrices(opts *bind.TransactOpts, priceUpd func (_m *PriceRegistryInterface) WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, feeToken) + if len(ret) == 0 { + panic("no return value specified for WatchFeeTokenAdded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenAdded, []common.Address) (event.Subscription, error)); ok { @@ -920,6 +1060,10 @@ func (_m *PriceRegistryInterface) WatchFeeTokenAdded(opts *bind.WatchOpts, sink func (_m *PriceRegistryInterface) WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, feeToken) + if len(ret) == 0 { + panic("no return value specified for WatchFeeTokenRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenRemoved, []common.Address) (event.Subscription, error)); ok { @@ -946,6 +1090,10 @@ func (_m *PriceRegistryInterface) WatchFeeTokenRemoved(opts *bind.WatchOpts, sin func (_m *PriceRegistryInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -972,6 +1120,10 @@ func (_m *PriceRegistryInterface) WatchOwnershipTransferRequested(opts *bind.Wat func (_m *PriceRegistryInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -998,6 +1150,10 @@ func (_m *PriceRegistryInterface) WatchOwnershipTransferred(opts *bind.WatchOpts func (_m *PriceRegistryInterface) WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, priceUpdater) + if len(ret) == 0 { + panic("no return value specified for WatchPriceUpdaterRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, []common.Address) (event.Subscription, error)); ok { @@ -1024,6 +1180,10 @@ func (_m *PriceRegistryInterface) WatchPriceUpdaterRemoved(opts *bind.WatchOpts, func (_m *PriceRegistryInterface) WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, priceUpdater) + if len(ret) == 0 { + panic("no return value specified for WatchPriceUpdaterSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterSet, []common.Address) (event.Subscription, error)); ok { @@ -1050,6 +1210,10 @@ func (_m *PriceRegistryInterface) WatchPriceUpdaterSet(opts *bind.WatchOpts, sin func (_m *PriceRegistryInterface) WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, token) + if len(ret) == 0 { + panic("no return value specified for WatchUsdPerTokenUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, []common.Address) (event.Subscription, error)); ok { @@ -1076,6 +1240,10 @@ func (_m *PriceRegistryInterface) WatchUsdPerTokenUpdated(opts *bind.WatchOpts, func (_m *PriceRegistryInterface) WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, destChain) + if len(ret) == 0 { + panic("no return value specified for WatchUsdPerUnitGasUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, []uint64) (event.Subscription, error)); ok { diff --git a/core/gethwrappers/generated/bank_erc20/bank_erc20.go b/core/gethwrappers/generated/bank_erc20/bank_erc20.go index e9ccd956ad..da4de3d840 100644 --- a/core/gethwrappers/generated/bank_erc20/bank_erc20.go +++ b/core/gethwrappers/generated/bank_erc20/bank_erc20.go @@ -52,7 +52,7 @@ func DeployBankERC20(auth *bind.TransactOpts, backend bind.ContractBackend, name if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &BankERC20{BankERC20Caller: BankERC20Caller{contract: contract}, BankERC20Transactor: BankERC20Transactor{contract: contract}, BankERC20Filterer: BankERC20Filterer{contract: contract}}, nil + return address, tx, &BankERC20{address: address, abi: *parsed, BankERC20Caller: BankERC20Caller{contract: contract}, BankERC20Transactor: BankERC20Transactor{contract: contract}, BankERC20Filterer: BankERC20Filterer{contract: contract}}, nil } type BankERC20 struct { diff --git a/core/gethwrappers/generated/forwarder/forwarder.go b/core/gethwrappers/generated/forwarder/forwarder.go index 69eb456874..3b6088dc67 100644 --- a/core/gethwrappers/generated/forwarder/forwarder.go +++ b/core/gethwrappers/generated/forwarder/forwarder.go @@ -60,7 +60,7 @@ func DeployForwarder(auth *bind.TransactOpts, backend bind.ContractBackend) (com if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Forwarder{ForwarderCaller: ForwarderCaller{contract: contract}, ForwarderTransactor: ForwarderTransactor{contract: contract}, ForwarderFilterer: ForwarderFilterer{contract: contract}}, nil + return address, tx, &Forwarder{address: address, abi: *parsed, ForwarderCaller: ForwarderCaller{contract: contract}, ForwarderTransactor: ForwarderTransactor{contract: contract}, ForwarderFilterer: ForwarderFilterer{contract: contract}}, nil } type Forwarder struct { diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 5e9dcfc332..36745bf8a5 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -7,6 +7,7 @@ automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBe automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 331bfa79685aee6ddf63b64c0747abee556c454cae3fb8175edff425b615d8aa +bank_erc20: ../../contracts/solc/v0.8.15/BankERC20.abi ../../contracts/solc/v0.8.15/BankERC20.bin 544cd578927f8e4f3259c01f79e448760f0110b46bb023686f00453960bc2f4e batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.bin 14356c48ef70f66ef74f22f644450dbf3b2a147c1b68deaa7e7d1eb8ffab15db batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin 7bb76ae241cf1b37b41920830b836cb99f1ad33efd7435ca2398ff6cd2fe5d48 @@ -18,6 +19,7 @@ cron_upkeep_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeep.ab dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.bin 583a448170b13abf7ed64e406e8177d78c9e55ab44efd141eee60de23a71ee3b flags_wrapper: ../../contracts/solc/v0.6/Flags/Flags.abi ../../contracts/solc/v0.6/Flags/Flags.bin 2034d1b562ca37a63068851915e3703980276e8d5f7db6db8a3351a49d69fc4a flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.bin a3b0a6396c4aa3b5ee39b3c4bd45efc89789d4859379a8a92caca3a0496c5794 +forwarder: ../../contracts/solc/v0.8.15/Forwarder.abi ../../contracts/solc/v0.8.15/Forwarder.bin 2911ae6bcf6b60b6828320c999bc9dbf94e6e24cf5e31ea42074667d5b88d4e5 gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin 6501bb9bcf5048bab2737b00685c6984a24867e234ddf5b60a65904eee9a4ebc diff --git a/core/scripts/go.mod b/core/scripts/go.mod index ab8b780b45..5c72c75f59 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -22,17 +22,19 @@ require ( github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 - github.com/spf13/cobra v1.6.1 - github.com/spf13/viper v1.15.0 + github.com/spf13/cobra v1.7.0 + github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 github.com/umbracle/ethgo v0.1.3 github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 github.com/urfave/cli v1.22.14 go.dedis.ch/kyber/v3 v3.1.0 - golang.org/x/tools v0.14.0 // indirect - gonum.org/v1/gonum v0.13.0 // indirect + golang.org/x/tools v0.16.0 // indirect + gonum.org/v1/gonum v0.14.0 // indirect ) +require github.com/pkg/errors v0.9.1 + require ( contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect cosmossdk.io/api v0.3.1 // indirect @@ -62,6 +64,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect @@ -114,6 +117,9 @@ require ( github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.6 // indirect @@ -123,6 +129,7 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/go-webauthn/webauthn v0.9.4 // indirect github.com/go-webauthn/x v0.1.5 // indirect @@ -139,6 +146,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/sessions v1.2.2 // indirect @@ -188,43 +196,14 @@ require ( github.com/leodido/go-urn v1.2.4 // indirect github.com/lib/pq v1.10.9 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect - github.com/libp2p/go-eventbus v0.2.1 // indirect - github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p v0.13.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 // indirect - github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect - github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect - github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect - github.com/libp2p/go-libp2p-core v0.8.5 // indirect - github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.11.1 // indirect - github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect - github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect - github.com/libp2p/go-libp2p-nat v0.0.6 // indirect - github.com/libp2p/go-libp2p-noise v0.1.2 // indirect - github.com/libp2p/go-libp2p-peerstore v0.2.7 // indirect - github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect - github.com/libp2p/go-libp2p-record v0.1.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect - github.com/libp2p/go-libp2p-tls v0.1.3 // indirect - github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect - github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect - github.com/libp2p/go-mplex v0.3.0 // indirect - github.com/libp2p/go-msgio v0.0.6 // indirect - github.com/libp2p/go-nat v0.0.5 // indirect - github.com/libp2p/go-netroute v0.1.4 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/libp2p/go-reuseport v0.0.2 // indirect - github.com/libp2p/go-reuseport-transport v0.0.4 // indirect - github.com/libp2p/go-sockaddr v0.1.0 // indirect - github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect - github.com/libp2p/go-tcp-transport v0.2.1 // indirect - github.com/libp2p/go-ws-transport v0.4.0 // indirect - github.com/libp2p/go-yamux/v2 v2.0.0 // indirect github.com/linxGnu/grocksdb v1.7.16 // indirect + github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -233,16 +212,6 @@ require ( github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr v0.3.3 // indirect - github.com/multiformats/go-multiaddr-dns v0.2.0 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multiaddr-net v0.2.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-multistream v0.2.2 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -251,7 +220,6 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/pressly/goose/v3 v3.16.0 // indirect @@ -272,16 +240,18 @@ require ( github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect + github.com/smartcontractkit/chain-selectors v1.0.6 // indirect github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect - github.com/spf13/afero v1.9.3 // indirect + github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -333,8 +303,6 @@ require ( golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.16.0 // indirect - gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect @@ -347,8 +315,6 @@ require ( gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v1.5.2 // indirect - nhooyr.io/websocket v1.8.7 // indirect pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/core/scripts/go.sum b/core/scripts/go.sum index c72b480e11..aa562c88ed 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -103,12 +103,6 @@ github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0F github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -<<<<<<< HEAD -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -======= ->>>>>>> develop github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -117,8 +111,8 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= @@ -133,13 +127,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -<<<<<<< HEAD -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -======= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= ->>>>>>> develop github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -160,17 +149,8 @@ github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -<<<<<<< HEAD -github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= -github.com/aws/aws-sdk-go v1.44.302/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g= -github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI= -github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4= -github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I= -======= github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= ->>>>>>> develop github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= @@ -214,16 +194,9 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -<<<<<<< HEAD -github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= -github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 h1:rvc39Ol6z3MvaBzXkxFC6Nfsnixq/dRypushKDd7Nc0= -github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5/go.mod h1:R/pdNYDYFQk+tuuOo7QES1kkv6OLmp5ze2XBZQIVffM= -======= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= ->>>>>>> develop github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -237,10 +210,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 h1:CyuI+igIjadM/GRnE2o0q+WCwipDh0n2cUYFPAvxziM= -github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657/go.mod h1:JRiumF+RFsH1mrrP8FUsi9tExPylKkO/oSRWeQEUdLE= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -384,15 +353,10 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -<<<<<<< HEAD -github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -======= github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T/Lao= github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= ->>>>>>> develop github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -407,15 +371,7 @@ github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGC github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= -github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -435,15 +391,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -<<<<<<< HEAD -github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= -github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= -github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= -github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -======= github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= ->>>>>>> develop github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= @@ -476,7 +425,6 @@ github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NB github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= @@ -517,34 +465,18 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -<<<<<<< HEAD -github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= -github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= -======= github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= ->>>>>>> develop github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -626,8 +558,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= -github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -671,18 +601,10 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -<<<<<<< HEAD -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -======= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= ->>>>>>> develop github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -719,8 +641,6 @@ github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EK github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= @@ -889,13 +809,8 @@ github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9 github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -<<<<<<< HEAD -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -======= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= ->>>>>>> develop github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -915,21 +830,17 @@ github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7 github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= -github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -954,7 +865,6 @@ github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awS github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a h1:dHCfT5W7gghzPtfsW488uPmEOm85wewI+ypUwibyTdU= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= @@ -966,211 +876,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -<<<<<<< HEAD -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= -github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= -github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= -github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= -github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= -github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= -github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= -github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= -github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 h1:2H/P+forDWBHije1WULwPfGduByUmC4fthndHVRpYNU= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= -github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= -github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= -github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug= -github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= -github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= -github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= -github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= -github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= -github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= -github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= -github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= -github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= -github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= -github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= -github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= -github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= -github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= -github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= -github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= -github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= -github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= -github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= -github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= -github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= -github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= -github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= -github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= -github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= -github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= -github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= -github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= -github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= -github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk= -github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE= -github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= -github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= -github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= -github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= -github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= -github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= -github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= -github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= -github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= -github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= -github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= -github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= -github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= -github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= -github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= -github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= -github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= -github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= -github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= -github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= -github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= -github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= -github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= -github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= -github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= -github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= -github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.4 h1:47V0+hJfYaqj1WO0A+cDkRc9xr9qKiK7i8zaoGv8Mmo= -github.com/libp2p/go-netroute v0.1.4/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= -github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= -github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= -github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= -github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= -github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= -github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= -github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= -github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= -github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= -github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= -github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= -github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= -github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= -======= ->>>>>>> develop github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= @@ -1178,12 +885,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -<<<<<<< HEAD -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -======= ->>>>>>> develop github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -1228,16 +929,6 @@ github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0Em github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -<<<<<<< HEAD -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -======= ->>>>>>> develop github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1245,8 +936,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -1255,8 +944,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1266,8 +953,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -1279,64 +964,6 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -<<<<<<< HEAD -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= -github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= -github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= -github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= -github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= -github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= -github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -======= ->>>>>>> develop github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= @@ -1395,15 +1022,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -<<<<<<< HEAD -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -======= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= ->>>>>>> develop github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= @@ -1484,8 +1104,6 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1521,24 +1139,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -<<<<<<< HEAD github.com/smartcontractkit/chain-selectors v1.0.6 h1:SWvONQuYnMSMoaOeLBSQY+iQjMVKvzmRGniKO2mYO64= github.com/smartcontractkit/chain-selectors v1.0.6/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-env v0.38.3 h1:ZtOnwkG622R0VCTxL5V09AnT/QXhlFwkGTjd0Lsfpfg= -github.com/smartcontractkit/chainlink-env v0.38.3/go.mod h1:7z4sw/hN8TxioQCLwFqQdhK3vaOV0a22Qe99z4bRUcg= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/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= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.16.0 h1:jLpqwqaTpJXQvTJ1IXTomcCToOdrSCe4+IGcLXGsmD0= -github.com/smartcontractkit/chainlink-testing-framework v1.16.0/go.mod h1:t6FJX3akEfAO31p96ru0ilNPfE9P2UshUlXTIkI58LM= -github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20230828183543-6d0939746966 h1:18MPun8xOGNhP3dGPvr9nYENEKhuhHNPMIQzOsiN6l4= -github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20230828183543-6d0939746966/go.mod h1:RcA3U87XQ2VqXkEG4PuHz2uZiFyXBtUHcFddeHJTWSk= -======= github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 h1:lSYiaiIfAA+5ac45/UD8ciytlNw/S6fnhK7bxFHYI88= @@ -1549,30 +1151,20 @@ github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e h1:/tCHhoAJM+ittEHPZTtJsAgXmYujKiDW0ub9HXW9qtY= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= ->>>>>>> develop github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -<<<<<<< HEAD -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= -github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -======= github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 h1:AA7vf29c6lFsZm+MtIEtXtg6VUOQV6waJo5MUuHfRjQ= github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7/go.mod h1:WcuWFMskcGK0MYZuH5hEhGJOzdJRUFeNEM4PAKlejI4= ->>>>>>> develop github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= @@ -1604,14 +1196,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -<<<<<<< HEAD github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -======= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= ->>>>>>> develop github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1709,8 +1295,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= -github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= @@ -1727,7 +1311,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -1774,8 +1357,6 @@ go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8 go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g= -go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1860,7 +1441,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -2157,19 +1737,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -<<<<<<< HEAD golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= -gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= -======= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= ->>>>>>> develop google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -2310,8 +1881,6 @@ gopkg.in/guregu/null.v2 v2.1.2/go.mod h1:XORrx8tyS5ZDcyUboCIxQtta/Aujk/6pfWrn9Xe gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -2350,32 +1919,10 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -<<<<<<< HEAD -k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs= -k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ= -k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k= -k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo= -k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= -k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/cli-runtime v0.25.11 h1:GE2yNZm1tN+MJtw1SGMOLesLF7Kp7NVAVqRSTbXfu4o= -k8s.io/cli-runtime v0.25.11/go.mod h1:r/nEINuHVEpgGhcd2WamU7hD1t/lMnSz8XM44Autltc= -k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8= -k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw= -k8s.io/component-base v0.26.2 h1:IfWgCGUDzrD6wLLgXEstJKYZKAFS2kO+rBRi0p3LqcI= -k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 h1:OmK1d0WrkD3IPfkskvroRykOulHVHf0s0ZIFRjyt+UI= -k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515/go.mod h1:kzo02I3kQ4BTtEfVLaPbjvCkX97YqGve33wzlb3fofQ= -k8s.io/kubectl v0.25.11 h1:6bsft5Gan6BCvQ7cJbDRFjTm4Zfq8GuUYpsWAdVngYE= -k8s.io/kubectl v0.25.11/go.mod h1:8mIfgkFgT+yJ8/TlmPW1qoRh46H2si9q5nW8id7i9iM= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -======= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= ->>>>>>> develop +k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= +k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= @@ -2396,29 +1943,14 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -<<<<<<< HEAD nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -======= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= -nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= ->>>>>>> develop pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ= -sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= -sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= -sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= -sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index ed04308658..ccf61d1794 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -241,7 +241,9 @@ func NewApplication(opts ApplicationOpts) (Application, error) { } // pool must be started before all relayers and stopped after them - srvcs = append(srvcs, opts.MercuryPool) + if opts.MercuryPool != nil { + srvcs = append(srvcs, opts.MercuryPool) + } // EVM chains are used all over the place. This will need to change for fully EVM extraction // TODO: BCF-2510, BCF-2511 diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 85a4c99b86..34ef8114b7 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -256,6 +256,7 @@ func TestConfig_Marshal(t *testing.T) { FeedsManager: ptr(true), LogPoller: ptr(true), UICSAKeys: ptr(true), + CCIP: ptr(false), } full.Database = toml.Database{ DefaultIdleInTxSessionTimeout: models.MustNewDuration(time.Minute), @@ -704,6 +705,7 @@ Headers = ['Authorization: token', 'X-SomeOther-Header: value with spaces | and FeedsManager = true LogPoller = true UICSAKeys = true +CCIP = false `}, {"Database", Config{Core: toml.Core{Database: full.Database}}, `[Database] DefaultIdleInTxSessionTimeout = '1m0s' diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 9efad05c03..c7235d5481 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s' FeedsManager = true LogPoller = false UICSAKeys = false +CCIP = false [Database] DefaultIdleInTxSessionTimeout = '1h0m0s' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index c6387e4ef6..9db37fb437 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -6,6 +6,7 @@ ShutdownGracePeriod = '10s' FeedsManager = true LogPoller = true UICSAKeys = true +CCIP = false [Database] DefaultIdleInTxSessionTimeout = '1m0s' diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 40c18f28eb..59389118c9 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s' FeedsManager = true LogPoller = false UICSAKeys = false +CCIP = false [Database] DefaultIdleInTxSessionTimeout = '1h0m0s' @@ -403,7 +404,7 @@ AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false FinalityDepth = 500 -FinalityTagEnabled = false +FinalityTagEnabled = true LinkContractAddress = '0xb0897686c545045aFc77CF20eC7A532E3120E0F1' LogBackfillBatchSize = 1000 LogPollInterval = '1s' diff --git a/core/services/fluxmonitorv2/delegate.go b/core/services/fluxmonitorv2/delegate.go index 99e2b688f5..30a9d57aa0 100644 --- a/core/services/fluxmonitorv2/delegate.go +++ b/core/services/fluxmonitorv2/delegate.go @@ -60,7 +60,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the flux monitor service for the job spec -func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) (services []job.ServiceCtx, err error) { if jb.FluxMonitorSpec == nil { return nil, errors.Errorf("Delegate expects a *job.FluxMonitorSpec to be present, got %v", jb) } diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index 4418bea670..0d085c861b 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -55,7 +55,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(spec job.Job, opts ...pg.QOpt) (services []job.ServiceCtx, err error) { if spec.KeeperSpec == nil { return nil, errors.Errorf("Delegate expects a *job.KeeperSpec to be present, got %v", spec) } diff --git a/core/services/metatx/integration_test.go b/core/services/metatx/integration_test.go index 36f749572b..a04dc317b1 100644 --- a/core/services/metatx/integration_test.go +++ b/core/services/metatx/integration_test.go @@ -19,7 +19,7 @@ import ( "github.com/stretchr/testify/require" "github.com/test-go/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/bank_erc20" forwarder_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/forwarder" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -120,6 +120,7 @@ func TestMetaERC20SameChain(t *testing.T) { } func TestMetaERC20CrossChain(t *testing.T) { + t.Skip("racy test") ccipContracts := integrationtesthelpers.SetupCCIPIntegrationTH(t, testhelpers.SourceChainID, testhelpers.SourceChainSelector, testhelpers.DestChainID, testhelpers.DestChainSelector) // holder1Key sends tokens to holder2 @@ -144,19 +145,19 @@ func TestMetaERC20CrossChain(t *testing.T) { transferNative(t, ccipContracts.Source.User, sourceTokenAddress, 50_000, ccipFeeBudget, ccipContracts.Source.Chain) linkUSD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(`{"UsdPerLink": "8000000000000000000"}`)) + _, err = w.Write([]byte(`{"UsdPerLink": "8000000000000000000"}`)) require.NoError(t, err) })) ethUSD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(`{"UsdPerETH": "2000000000000000000000"}`)) + _, err = w.Write([]byte(`{"UsdPerETH": "2000000000000000000000"}`)) require.NoError(t, err) })) wrappedDestTokenUSD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(`{"UsdPerWrappedDestToken": "500000000000000000"}`)) + _, err = w.Write([]byte(`{"UsdPerWrappedDestToken": "500000000000000000"}`)) require.NoError(t, err) })) bankERC20USD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(`{"UsdPerBankERC20": "5000000000000000000"}`)) + _, err = w.Write([]byte(`{"UsdPerBankERC20": "5000000000000000000"}`)) require.NoError(t, err) })) wrapped, err := ccipContracts.Source.Router.GetWrappedNative(nil) @@ -181,7 +182,7 @@ merge [type=merge left="{}" right="{\\\"%s\\\":$(link_parse), \\\"%s\\\":$(eth_p defer wrappedDestTokenUSD.Close() defer bankERC20USD.Close() - ccipContracts.SetUpNodesAndJobs(t, tokenPricesUSDPipeline) + ccipContracts.SetUpNodesAndJobs(t, tokenPricesUSDPipeline, "") geCurrentSeqNum := 1 diff --git a/core/services/ocr2/plugins/ccip/clo_ccip_integration_test.go b/core/services/ocr2/plugins/ccip/clo_ccip_integration_test.go index 01e2deaff1..eeb3cc250a 100644 --- a/core/services/ocr2/plugins/ccip/clo_ccip_integration_test.go +++ b/core/services/ocr2/plugins/ccip/clo_ccip_integration_test.go @@ -20,7 +20,7 @@ func Test_CLOSpecApprovalFlow(t *testing.T) { defer ethUSD.Close() // Create initial job specs - jobParams := ccipTH.SetUpNodesAndJobs(t, tokenPricesUSDPipeline) + jobParams := ccipTH.SetUpNodesAndJobs(t, tokenPricesUSDPipeline, "http://blah.com") ccipTH.SetupFeedsManager(t) // Propose and approve new specs diff --git a/core/services/ocr2/plugins/ccip/commit_plugin.go b/core/services/ocr2/plugins/ccip/commit_plugin.go index 9618368bb5..827bd8f18a 100644 --- a/core/services/ocr2/plugins/ccip/commit_plugin.go +++ b/core/services/ocr2/plugins/ccip/commit_plugin.go @@ -13,9 +13,9 @@ import ( relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -36,7 +36,7 @@ type BackfillArgs struct { sourceStartBlock, destStartBlock uint64 } -func jobSpecToCommitPluginConfig(lggr logger.Logger, jb job.Job, pr pipeline.Runner, chainSet evm.LegacyChainContainer, qopts ...pg.QOpt) (*CommitPluginStaticConfig, *BackfillArgs, error) { +func jobSpecToCommitPluginConfig(lggr logger.Logger, jb job.Job, pr pipeline.Runner, chainSet legacyevm.LegacyChainContainer, qopts ...pg.QOpt) (*CommitPluginStaticConfig, *BackfillArgs, error) { if jb.OCR2OracleSpec == nil { return nil, nil, errors.New("spec is nil") } @@ -127,7 +127,7 @@ func jobSpecToCommitPluginConfig(lggr logger.Logger, jb job.Job, pr pipeline.Run }, nil } -func NewCommitServices(lggr logger.Logger, jb job.Job, chainSet evm.LegacyChainContainer, new bool, pr pipeline.Runner, argsNoPlugin libocr2.OCR2OracleArgs, logError func(string), qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func NewCommitServices(lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer, new bool, pr pipeline.Runner, argsNoPlugin libocr2.OCR2OracleArgs, logError func(string), qopts ...pg.QOpt) ([]job.ServiceCtx, error) { pluginConfig, backfillArgs, err := jobSpecToCommitPluginConfig(lggr, jb, pr, chainSet, qopts...) if err != nil { return nil, err @@ -179,7 +179,7 @@ func CommitReportToEthTxMeta(typ ccipconfig.ContractType, ver semver.Version) (f // https://github.com/smartcontractkit/ccip/blob/68e2197472fb017dd4e5630d21e7878d58bc2a44/core/services/feeds/service.go#L716 // TODO once that transaction is broken up, we should be able to simply rely on oracle.Close() to cleanup the filters. // Until then we have to deterministically reload the readers from the spec (and thus their filters) and close them. -func UnregisterCommitPluginLpFilters(ctx context.Context, lggr logger.Logger, jb job.Job, pr pipeline.Runner, chainSet evm.LegacyChainContainer, qopts ...pg.QOpt) error { +func UnregisterCommitPluginLpFilters(ctx context.Context, lggr logger.Logger, jb job.Job, pr pipeline.Runner, chainSet legacyevm.LegacyChainContainer, qopts ...pg.QOpt) error { commitPluginConfig, _, err := jobSpecToCommitPluginConfig(lggr, jb, pr, chainSet) if err != nil { return errors.New("spec is nil") diff --git a/core/services/ocr2/plugins/ccip/commit_plugin_test.go b/core/services/ocr2/plugins/ccip/commit_plugin_test.go index d1c6aa5b94..0b7a186182 100644 --- a/core/services/ocr2/plugins/ccip/commit_plugin_test.go +++ b/core/services/ocr2/plugins/ccip/commit_plugin_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" - evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" + legacyEvmORMMocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" @@ -57,7 +57,7 @@ func TestGetCommitPluginFilterNamesFromSpec(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { - chainSet := &evmmocks.LegacyChainContainer{} + chainSet := &legacyEvmORMMocks.LegacyChainContainer{} prMock := &pipelinemocks.Runner{} if tc.spec != nil { diff --git a/core/services/ocr2/plugins/ccip/commit_reporting_plugin.go b/core/services/ocr2/plugins/ccip/commit_reporting_plugin.go index 3f08b4e612..4fc197be04 100644 --- a/core/services/ocr2/plugins/ccip/commit_reporting_plugin.go +++ b/core/services/ocr2/plugins/ccip/commit_reporting_plugin.go @@ -16,6 +16,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon" @@ -23,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/hashlib" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/merklemulti" diff --git a/core/services/ocr2/plugins/ccip/config/chain_config.go b/core/services/ocr2/plugins/ccip/config/chain_config.go index ede0e8833b..ff82def606 100644 --- a/core/services/ocr2/plugins/ccip/config/chain_config.go +++ b/core/services/ocr2/plugins/ccip/config/chain_config.go @@ -6,11 +6,11 @@ import ( "github.com/pkg/errors" chainselectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services/job" ) -func GetChainFromSpec(spec *job.OCR2OracleSpec, chainSet evm.LegacyChainContainer) (evm.Chain, int64, error) { +func GetChainFromSpec(spec *job.OCR2OracleSpec, chainSet legacyevm.LegacyChainContainer) (legacyevm.Chain, int64, error) { chainIDInterface, ok := spec.RelayConfig["chainID"] if !ok { return nil, 0, errors.New("chainID must be provided in relay config") @@ -19,7 +19,7 @@ func GetChainFromSpec(spec *job.OCR2OracleSpec, chainSet evm.LegacyChainContaine return GetChainByChainID(chainSet, destChainID) } -func GetChainByChainSelector(chainSet evm.LegacyChainContainer, chainSelector uint64) (evm.Chain, int64, error) { +func GetChainByChainSelector(chainSet legacyevm.LegacyChainContainer, chainSelector uint64) (legacyevm.Chain, int64, error) { chainID, err := chainselectors.ChainIdFromSelector(chainSelector) if err != nil { return nil, 0, err @@ -27,7 +27,7 @@ func GetChainByChainSelector(chainSet evm.LegacyChainContainer, chainSelector ui return GetChainByChainID(chainSet, chainID) } -func GetChainByChainID(chainSet evm.LegacyChainContainer, chainID uint64) (evm.Chain, int64, error) { +func GetChainByChainID(chainSet legacyevm.LegacyChainContainer, chainID uint64) (legacyevm.Chain, int64, error) { chain, err := chainSet.Get(strconv.FormatUint(chainID, 10)) if err != nil { return nil, 0, errors.Wrap(err, "chain not found in chainset") diff --git a/core/services/ocr2/plugins/ccip/config/chain_config_test.go b/core/services/ocr2/plugins/ccip/config/chain_config_test.go index 0488e619c2..895cb5eed2 100644 --- a/core/services/ocr2/plugins/ccip/config/chain_config_test.go +++ b/core/services/ocr2/plugins/ccip/config/chain_config_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - evmORMMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/job" ) @@ -40,10 +40,10 @@ func TestGetChainFromSpec(t *testing.T) { }, } - mockChain := evmORMMocks.NewChain(t) + mockChain := mocks.NewChain(t) mockChain.On("ID").Return(big.NewInt(testChainID)).Maybe() - mockChainSet := evmORMMocks.NewLegacyChainContainer(t) + mockChainSet := mocks.NewLegacyChainContainer(t) mockChainSet.On("Get", strconv.FormatInt(testChainID, 10)).Return(mockChain, nil).Maybe() for _, test := range tests { @@ -63,10 +63,10 @@ func TestGetChainFromSpec(t *testing.T) { } func TestGetChainByChainSelector_success(t *testing.T) { - mockChain := evmORMMocks.NewChain(t) + mockChain := mocks.NewChain(t) mockChain.On("ID").Return(big.NewInt(11155111)) - mockChainSet := evmORMMocks.NewLegacyChainContainer(t) + mockChainSet := mocks.NewLegacyChainContainer(t) mockChainSet.On("Get", "11155111").Return(mockChain, nil) // Ethereum Sepolia chain selector. @@ -77,14 +77,14 @@ func TestGetChainByChainSelector_success(t *testing.T) { } func TestGetChainByChainSelector_selectorNotFound(t *testing.T) { - mockChainSet := evmORMMocks.NewLegacyChainContainer(t) + mockChainSet := mocks.NewLegacyChainContainer(t) _, _, err := GetChainByChainSelector(mockChainSet, uint64(444000444)) require.Error(t, err) } func TestGetChainById_notFound(t *testing.T) { - mockChainSet := evmORMMocks.NewLegacyChainContainer(t) + mockChainSet := mocks.NewLegacyChainContainer(t) mockChainSet.On("Get", "444").Return(nil, errors.New("test")).Maybe() _, _, err := GetChainByChainID(mockChainSet, uint64(444)) diff --git a/core/services/ocr2/plugins/ccip/config/config_test.go b/core/services/ocr2/plugins/ccip/config/config_test.go index a1941eb320..24ad5d1777 100644 --- a/core/services/ocr2/plugins/ccip/config/config_test.go +++ b/core/services/ocr2/plugins/ccip/config/config_test.go @@ -6,8 +6,9 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestCommitConfig(t *testing.T) { diff --git a/core/services/ocr2/plugins/ccip/execution_plugin.go b/core/services/ocr2/plugins/ccip/execution_plugin.go index 52bd20d78e..d3a6a3c23d 100644 --- a/core/services/ocr2/plugins/ccip/execution_plugin.go +++ b/core/services/ocr2/plugins/ccip/execution_plugin.go @@ -18,9 +18,9 @@ import ( relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -38,7 +38,7 @@ import ( ) // TODO pass context? -func jobSpecToExecPluginConfig(lggr logger.Logger, jb job.Job, chainSet evm.LegacyChainContainer, qopts ...pg.QOpt) (*ExecutionPluginStaticConfig, *BackfillArgs, error) { +func jobSpecToExecPluginConfig(lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer) (*ExecutionPluginStaticConfig, *BackfillArgs, error) { if jb.OCR2OracleSpec == nil { return nil, nil, errors.New("spec is nil") } @@ -150,8 +150,8 @@ func jobSpecToExecPluginConfig(lggr logger.Logger, jb job.Job, chainSet evm.Lega }, nil } -func NewExecutionServices(lggr logger.Logger, jb job.Job, chainSet evm.LegacyChainContainer, new bool, argsNoPlugin libocr2.OCR2OracleArgs, logError func(string), qopts ...pg.QOpt) ([]job.ServiceCtx, error) { - execPluginConfig, backfillArgs, err := jobSpecToExecPluginConfig(lggr, jb, chainSet, qopts...) +func NewExecutionServices(lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer, new bool, argsNoPlugin libocr2.OCR2OracleArgs, logError func(string), qopts ...pg.QOpt) ([]job.ServiceCtx, error) { + execPluginConfig, backfillArgs, err := jobSpecToExecPluginConfig(lggr, jb, chainSet) if err != nil { return nil, err } @@ -166,7 +166,11 @@ func NewExecutionServices(lggr logger.Logger, jb job.Job, chainSet evm.LegacyCha if err1 := execPluginConfig.commitStoreReader.RegisterFilters(qopts...); err1 != nil { return nil, err1 } - + for _, dp := range execPluginConfig.tokenDataProviders { + if err1 := dp.RegisterFilters(qopts...); err1 != nil { + return nil, err1 + } + } destChainID, err := chainselectors.ChainIdFromSelector(execPluginConfig.destChainSelector) if err != nil { return nil, err @@ -226,8 +230,9 @@ func getTokenDataProviders(lggr logger.Logger, pluginConfig ccipconfig.Execution // UnregisterExecPluginLpFilters unregisters all the registered filters for both source and dest chains. // See comment in UnregisterCommitPluginLpFilters -func UnregisterExecPluginLpFilters(ctx context.Context, lggr logger.Logger, jb job.Job, chainSet evm.LegacyChainContainer, qopts ...pg.QOpt) error { - execPluginConfig, _, err := jobSpecToExecPluginConfig(lggr, jb, chainSet, qopts...) +// It MUST mirror the filters registered in NewExecutionServices. +func UnregisterExecPluginLpFilters(ctx context.Context, lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer, qopts ...pg.QOpt) error { + execPluginConfig, _, err := jobSpecToExecPluginConfig(lggr, jb, chainSet) if err != nil { return err } diff --git a/core/services/ocr2/plugins/ccip/execution_plugin_test.go b/core/services/ocr2/plugins/ccip/execution_plugin_test.go index e870814c9d..0e0249a4ee 100644 --- a/core/services/ocr2/plugins/ccip/execution_plugin_test.go +++ b/core/services/ocr2/plugins/ccip/execution_plugin_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" + legacyEvmORMMocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" ) @@ -46,7 +46,7 @@ func TestGetExecutionPluginFilterNamesFromSpec(t *testing.T) { } for _, tc := range testCases { - chainSet := &mocks.LegacyChainContainer{} + chainSet := &legacyEvmORMMocks.LegacyChainContainer{} t.Run(tc.description, func(t *testing.T) { err := UnregisterExecPluginLpFilters(context.Background(), logger.TestLogger(t), job.Job{OCR2OracleSpec: tc.spec}, chainSet) if tc.expectingErr { diff --git a/core/services/ocr2/plugins/ccip/integration_test.go b/core/services/ocr2/plugins/ccip/integration_test.go index 7c626d3f23..67f4ad5d6a 100644 --- a/core/services/ocr2/plugins/ccip/integration_test.go +++ b/core/services/ocr2/plugins/ccip/integration_test.go @@ -27,7 +27,7 @@ func TestIntegration_CCIP(t *testing.T) { defer linkUSD.Close() defer ethUSD.Close() - jobParams := ccipTH.SetUpNodesAndJobs(t, tokenPricesUSDPipeline) + jobParams := ccipTH.SetUpNodesAndJobs(t, tokenPricesUSDPipeline, "") currentSeqNum := 1 @@ -264,7 +264,7 @@ func TestIntegration_CCIP(t *testing.T) { ccipTH.Dest.Chain.Commit() // create new jobs - jobParams = ccipTH.NewCCIPJobSpecParams(tokenPricesUSDPipeline, newConfigBlock) + jobParams = ccipTH.NewCCIPJobSpecParams(tokenPricesUSDPipeline, newConfigBlock, "") jobParams.Version = "v2" jobParams.SourceStartBlock = srcStartBlock ccipTH.AddAllJobs(t, jobParams) diff --git a/core/services/ocr2/plugins/ccip/internal/cache/autosync.go b/core/services/ocr2/plugins/ccip/internal/cache/autosync.go index 47d179cb76..a73cd80f7f 100644 --- a/core/services/ocr2/plugins/ccip/internal/cache/autosync.go +++ b/core/services/ocr2/plugins/ccip/internal/cache/autosync.go @@ -56,7 +56,8 @@ func (c *LogpollerEventsBased[T]) Get(ctx context.Context, syncFunc func(ctx con } if hasExpired { - latestValue, err := syncFunc(ctx) + var latestValue T + latestValue, err = syncFunc(ctx) if err != nil { return empty, fmt.Errorf("sync func: %w", err) } @@ -131,7 +132,6 @@ func (c *LogpollerEventsBased[T]) set(value T, blockNum int64) { c.value = value c.lastChangeBlock = blockNum - return } func (c *LogpollerEventsBased[T]) get() T { diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader_test.go index 5ab9c95e07..4e71f08e44 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/commit_store_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/commit_store_reader_mock.go index 5b7816592c..18fe610f86 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/commit_store_reader_mock.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/commit_store_reader_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -26,6 +26,10 @@ type CommitStoreReader struct { func (_m *CommitStoreReader) ChangeConfig(onchainConfig []byte, offchainConfig []byte) (common.Address, error) { ret := _m.Called(onchainConfig, offchainConfig) + if len(ret) == 0 { + panic("no return value specified for ChangeConfig") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func([]byte, []byte) (common.Address, error)); ok { @@ -58,6 +62,10 @@ func (_m *CommitStoreReader) Close(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -72,6 +80,10 @@ func (_m *CommitStoreReader) Close(qopts ...pg.QOpt) error { func (_m *CommitStoreReader) DecodeCommitReport(report []byte) (ccipdata.CommitStoreReport, error) { ret := _m.Called(report) + if len(ret) == 0 { + panic("no return value specified for DecodeCommitReport") + } + var r0 ccipdata.CommitStoreReport var r1 error if rf, ok := ret.Get(0).(func([]byte) (ccipdata.CommitStoreReport, error)); ok { @@ -96,6 +108,10 @@ func (_m *CommitStoreReader) DecodeCommitReport(report []byte) (ccipdata.CommitS func (_m *CommitStoreReader) EncodeCommitReport(report ccipdata.CommitStoreReport) ([]byte, error) { ret := _m.Called(report) + if len(ret) == 0 { + panic("no return value specified for EncodeCommitReport") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(ccipdata.CommitStoreReport) ([]byte, error)); ok { @@ -122,6 +138,10 @@ func (_m *CommitStoreReader) EncodeCommitReport(report ccipdata.CommitStoreRepor func (_m *CommitStoreReader) GasPriceEstimator() prices.GasPriceEstimatorCommit { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GasPriceEstimator") + } + var r0 prices.GasPriceEstimatorCommit if rf, ok := ret.Get(0).(func() prices.GasPriceEstimatorCommit); ok { r0 = rf() @@ -138,6 +158,10 @@ func (_m *CommitStoreReader) GasPriceEstimator() prices.GasPriceEstimatorCommit func (_m *CommitStoreReader) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confs int) ([]ccipdata.Event[ccipdata.CommitStoreReport], error) { ret := _m.Called(ctx, ts, confs) + if len(ret) == 0 { + panic("no return value specified for GetAcceptedCommitReportsGteTimestamp") + } + var r0 []ccipdata.Event[ccipdata.CommitStoreReport] var r1 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) ([]ccipdata.Event[ccipdata.CommitStoreReport], error)); ok { @@ -164,6 +188,10 @@ func (_m *CommitStoreReader) GetAcceptedCommitReportsGteTimestamp(ctx context.Co func (_m *CommitStoreReader) GetCommitReportMatchingSeqNum(ctx context.Context, seqNum uint64, confs int) ([]ccipdata.Event[ccipdata.CommitStoreReport], error) { ret := _m.Called(ctx, seqNum, confs) + if len(ret) == 0 { + panic("no return value specified for GetCommitReportMatchingSeqNum") + } + var r0 []ccipdata.Event[ccipdata.CommitStoreReport] var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64, int) ([]ccipdata.Event[ccipdata.CommitStoreReport], error)); ok { @@ -190,6 +218,10 @@ func (_m *CommitStoreReader) GetCommitReportMatchingSeqNum(ctx context.Context, func (_m *CommitStoreReader) GetCommitStoreStaticConfig(ctx context.Context) (ccipdata.CommitStoreStaticConfig, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetCommitStoreStaticConfig") + } + var r0 ccipdata.CommitStoreStaticConfig var r1 error if rf, ok := ret.Get(0).(func(context.Context) (ccipdata.CommitStoreStaticConfig, error)); ok { @@ -214,6 +246,10 @@ func (_m *CommitStoreReader) GetCommitStoreStaticConfig(ctx context.Context) (cc func (_m *CommitStoreReader) GetExpectedNextSequenceNumber(_a0 context.Context) (uint64, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetExpectedNextSequenceNumber") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { @@ -238,6 +274,10 @@ func (_m *CommitStoreReader) GetExpectedNextSequenceNumber(_a0 context.Context) func (_m *CommitStoreReader) GetLatestPriceEpochAndRound(_a0 context.Context) (uint64, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetLatestPriceEpochAndRound") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { @@ -262,6 +302,10 @@ func (_m *CommitStoreReader) GetLatestPriceEpochAndRound(_a0 context.Context) (u func (_m *CommitStoreReader) IsBlessed(ctx context.Context, root [32]byte) (bool, error) { ret := _m.Called(ctx, root) + if len(ret) == 0 { + panic("no return value specified for IsBlessed") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, [32]byte) (bool, error)); ok { @@ -286,6 +330,10 @@ func (_m *CommitStoreReader) IsBlessed(ctx context.Context, root [32]byte) (bool func (_m *CommitStoreReader) IsDown(ctx context.Context) (bool, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for IsDown") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok { @@ -310,6 +358,10 @@ func (_m *CommitStoreReader) IsDown(ctx context.Context) (bool, error) { func (_m *CommitStoreReader) OffchainConfig() ccipdata.CommitOffchainConfig { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OffchainConfig") + } + var r0 ccipdata.CommitOffchainConfig if rf, ok := ret.Get(0).(func() ccipdata.CommitOffchainConfig); ok { r0 = rf() @@ -330,6 +382,10 @@ func (_m *CommitStoreReader) RegisterFilters(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RegisterFilters") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -344,6 +400,10 @@ func (_m *CommitStoreReader) RegisterFilters(qopts ...pg.QOpt) error { func (_m *CommitStoreReader) VerifyExecutionReport(ctx context.Context, report ccipdata.ExecReport) (bool, error) { ret := _m.Called(ctx, report) + if len(ret) == 0 { + panic("no return value specified for VerifyExecutionReport") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, ccipdata.ExecReport) (bool, error)); ok { diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/offramp_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/offramp_reader_mock.go index 4b016f63bb..eac5270e31 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/offramp_reader_mock.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/offramp_reader_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -26,6 +26,10 @@ type OffRampReader struct { func (_m *OffRampReader) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -42,6 +46,10 @@ func (_m *OffRampReader) Address() common.Address { func (_m *OffRampReader) ChangeConfig(onchainConfig []byte, offchainConfig []byte) (common.Address, common.Address, error) { ret := _m.Called(onchainConfig, offchainConfig) + if len(ret) == 0 { + panic("no return value specified for ChangeConfig") + } + var r0 common.Address var r1 common.Address var r2 error @@ -83,6 +91,10 @@ func (_m *OffRampReader) Close(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -97,6 +109,10 @@ func (_m *OffRampReader) Close(qopts ...pg.QOpt) error { func (_m *OffRampReader) CurrentRateLimiterState(ctx context.Context) (evm_2_evm_offramp.RateLimiterTokenBucket, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for CurrentRateLimiterState") + } + var r0 evm_2_evm_offramp.RateLimiterTokenBucket var r1 error if rf, ok := ret.Get(0).(func(context.Context) (evm_2_evm_offramp.RateLimiterTokenBucket, error)); ok { @@ -121,6 +137,10 @@ func (_m *OffRampReader) CurrentRateLimiterState(ctx context.Context) (evm_2_evm func (_m *OffRampReader) DecodeExecutionReport(report []byte) (ccipdata.ExecReport, error) { ret := _m.Called(report) + if len(ret) == 0 { + panic("no return value specified for DecodeExecutionReport") + } + var r0 ccipdata.ExecReport var r1 error if rf, ok := ret.Get(0).(func([]byte) (ccipdata.ExecReport, error)); ok { @@ -145,6 +165,10 @@ func (_m *OffRampReader) DecodeExecutionReport(report []byte) (ccipdata.ExecRepo func (_m *OffRampReader) EncodeExecutionReport(report ccipdata.ExecReport) ([]byte, error) { ret := _m.Called(report) + if len(ret) == 0 { + panic("no return value specified for EncodeExecutionReport") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(ccipdata.ExecReport) ([]byte, error)); ok { @@ -171,6 +195,10 @@ func (_m *OffRampReader) EncodeExecutionReport(report ccipdata.ExecReport) ([]by func (_m *OffRampReader) GasPriceEstimator() prices.GasPriceEstimatorExec { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GasPriceEstimator") + } + var r0 prices.GasPriceEstimatorExec if rf, ok := ret.Get(0).(func() prices.GasPriceEstimatorExec); ok { r0 = rf() @@ -187,6 +215,10 @@ func (_m *OffRampReader) GasPriceEstimator() prices.GasPriceEstimatorExec { func (_m *OffRampReader) GetDestinationTokenPools(ctx context.Context) (map[common.Address]common.Address, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetDestinationTokenPools") + } + var r0 map[common.Address]common.Address var r1 error if rf, ok := ret.Get(0).(func(context.Context) (map[common.Address]common.Address, error)); ok { @@ -213,6 +245,10 @@ func (_m *OffRampReader) GetDestinationTokenPools(ctx context.Context) (map[comm func (_m *OffRampReader) GetDestinationTokens(ctx context.Context) ([]common.Address, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetDestinationTokens") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(context.Context) ([]common.Address, error)); ok { @@ -239,6 +275,10 @@ func (_m *OffRampReader) GetDestinationTokens(ctx context.Context) ([]common.Add func (_m *OffRampReader) GetExecutionState(ctx context.Context, sequenceNumber uint64) (uint8, error) { ret := _m.Called(ctx, sequenceNumber) + if len(ret) == 0 { + panic("no return value specified for GetExecutionState") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64) (uint8, error)); ok { @@ -263,6 +303,10 @@ func (_m *OffRampReader) GetExecutionState(ctx context.Context, sequenceNumber u func (_m *OffRampReader) GetExecutionStateChangesBetweenSeqNums(ctx context.Context, seqNumMin uint64, seqNumMax uint64, confs int) ([]ccipdata.Event[ccipdata.ExecutionStateChanged], error) { ret := _m.Called(ctx, seqNumMin, seqNumMax, confs) + if len(ret) == 0 { + panic("no return value specified for GetExecutionStateChangesBetweenSeqNums") + } + var r0 []ccipdata.Event[ccipdata.ExecutionStateChanged] var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, int) ([]ccipdata.Event[ccipdata.ExecutionStateChanged], error)); ok { @@ -289,6 +333,10 @@ func (_m *OffRampReader) GetExecutionStateChangesBetweenSeqNums(ctx context.Cont func (_m *OffRampReader) GetSenderNonce(ctx context.Context, sender common.Address) (uint64, error) { ret := _m.Called(ctx, sender) + if len(ret) == 0 { + panic("no return value specified for GetSenderNonce") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint64, error)); ok { @@ -313,6 +361,10 @@ func (_m *OffRampReader) GetSenderNonce(ctx context.Context, sender common.Addre func (_m *OffRampReader) GetSourceToDestTokensMapping(ctx context.Context) (map[common.Address]common.Address, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetSourceToDestTokensMapping") + } + var r0 map[common.Address]common.Address var r1 error if rf, ok := ret.Get(0).(func(context.Context) (map[common.Address]common.Address, error)); ok { @@ -339,6 +391,10 @@ func (_m *OffRampReader) GetSourceToDestTokensMapping(ctx context.Context) (map[ func (_m *OffRampReader) GetStaticConfig(ctx context.Context) (ccipdata.OffRampStaticConfig, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetStaticConfig") + } + var r0 ccipdata.OffRampStaticConfig var r1 error if rf, ok := ret.Get(0).(func(context.Context) (ccipdata.OffRampStaticConfig, error)); ok { @@ -363,6 +419,10 @@ func (_m *OffRampReader) GetStaticConfig(ctx context.Context) (ccipdata.OffRampS func (_m *OffRampReader) GetTokenPoolsRateLimits(ctx context.Context, poolAddresses []common.Address) ([]ccipdata.TokenBucketRateLimit, error) { ret := _m.Called(ctx, poolAddresses) + if len(ret) == 0 { + panic("no return value specified for GetTokenPoolsRateLimits") + } + var r0 []ccipdata.TokenBucketRateLimit var r1 error if rf, ok := ret.Get(0).(func(context.Context, []common.Address) ([]ccipdata.TokenBucketRateLimit, error)); ok { @@ -389,6 +449,10 @@ func (_m *OffRampReader) GetTokenPoolsRateLimits(ctx context.Context, poolAddres func (_m *OffRampReader) OffchainConfig() ccipdata.ExecOffchainConfig { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OffchainConfig") + } + var r0 ccipdata.ExecOffchainConfig if rf, ok := ret.Get(0).(func() ccipdata.ExecOffchainConfig); ok { r0 = rf() @@ -403,6 +467,10 @@ func (_m *OffRampReader) OffchainConfig() ccipdata.ExecOffchainConfig { func (_m *OffRampReader) OnchainConfig() ccipdata.ExecOnchainConfig { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OnchainConfig") + } + var r0 ccipdata.ExecOnchainConfig if rf, ok := ret.Get(0).(func() ccipdata.ExecOnchainConfig); ok { r0 = rf() @@ -423,6 +491,10 @@ func (_m *OffRampReader) RegisterFilters(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RegisterFilters") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/onramp_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/onramp_reader_mock.go index a8169341c2..9d7f95a741 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/onramp_reader_mock.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/onramp_reader_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type OnRampReader struct { func (_m *OnRampReader) Address() (common.Address, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func() (common.Address, error)); ok { @@ -56,6 +60,10 @@ func (_m *OnRampReader) Close(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -70,6 +78,10 @@ func (_m *OnRampReader) Close(qopts ...pg.QOpt) error { func (_m *OnRampReader) GetDynamicConfig() (ccipdata.OnRampDynamicConfig, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetDynamicConfig") + } + var r0 ccipdata.OnRampDynamicConfig var r1 error if rf, ok := ret.Get(0).(func() (ccipdata.OnRampDynamicConfig, error)); ok { @@ -94,6 +106,10 @@ func (_m *OnRampReader) GetDynamicConfig() (ccipdata.OnRampDynamicConfig, error) func (_m *OnRampReader) GetSendRequestsBetweenSeqNums(ctx context.Context, seqNumMin uint64, seqNumMax uint64, finalized bool) ([]ccipdata.Event[internal.EVM2EVMMessage], error) { ret := _m.Called(ctx, seqNumMin, seqNumMax, finalized) + if len(ret) == 0 { + panic("no return value specified for GetSendRequestsBetweenSeqNums") + } + var r0 []ccipdata.Event[internal.EVM2EVMMessage] var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, bool) ([]ccipdata.Event[internal.EVM2EVMMessage], error)); ok { @@ -126,6 +142,10 @@ func (_m *OnRampReader) RegisterFilters(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RegisterFilters") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -140,6 +160,10 @@ func (_m *OnRampReader) RegisterFilters(qopts ...pg.QOpt) error { func (_m *OnRampReader) RouterAddress() (common.Address, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RouterAddress") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func() (common.Address, error)); ok { diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/price_registry_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/price_registry_reader_mock.go index 555e15eab0..e0115f5009 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/price_registry_reader_mock.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/price_registry_reader_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type PriceRegistryReader struct { func (_m *PriceRegistryReader) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -46,6 +50,10 @@ func (_m *PriceRegistryReader) Close(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -60,6 +68,10 @@ func (_m *PriceRegistryReader) Close(qopts ...pg.QOpt) error { func (_m *PriceRegistryReader) GetFeeTokens(ctx context.Context) ([]common.Address, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetFeeTokens") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(context.Context) ([]common.Address, error)); ok { @@ -86,6 +98,10 @@ func (_m *PriceRegistryReader) GetFeeTokens(ctx context.Context) ([]common.Addre func (_m *PriceRegistryReader) GetGasPriceUpdatesCreatedAfter(ctx context.Context, chainSelector uint64, ts time.Time, confs int) ([]ccipdata.Event[ccipdata.GasPriceUpdate], error) { ret := _m.Called(ctx, chainSelector, ts, confs) + if len(ret) == 0 { + panic("no return value specified for GetGasPriceUpdatesCreatedAfter") + } + var r0 []ccipdata.Event[ccipdata.GasPriceUpdate] var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64, time.Time, int) ([]ccipdata.Event[ccipdata.GasPriceUpdate], error)); ok { @@ -112,6 +128,10 @@ func (_m *PriceRegistryReader) GetGasPriceUpdatesCreatedAfter(ctx context.Contex func (_m *PriceRegistryReader) GetTokenPriceUpdatesCreatedAfter(ctx context.Context, ts time.Time, confs int) ([]ccipdata.Event[ccipdata.TokenPriceUpdate], error) { ret := _m.Called(ctx, ts, confs) + if len(ret) == 0 { + panic("no return value specified for GetTokenPriceUpdatesCreatedAfter") + } + var r0 []ccipdata.Event[ccipdata.TokenPriceUpdate] var r1 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) ([]ccipdata.Event[ccipdata.TokenPriceUpdate], error)); ok { @@ -138,6 +158,10 @@ func (_m *PriceRegistryReader) GetTokenPriceUpdatesCreatedAfter(ctx context.Cont func (_m *PriceRegistryReader) GetTokenPrices(ctx context.Context, wantedTokens []common.Address) ([]ccipdata.TokenPriceUpdate, error) { ret := _m.Called(ctx, wantedTokens) + if len(ret) == 0 { + panic("no return value specified for GetTokenPrices") + } + var r0 []ccipdata.TokenPriceUpdate var r1 error if rf, ok := ret.Get(0).(func(context.Context, []common.Address) ([]ccipdata.TokenPriceUpdate, error)); ok { @@ -164,6 +188,10 @@ func (_m *PriceRegistryReader) GetTokenPrices(ctx context.Context, wantedTokens func (_m *PriceRegistryReader) GetTokensDecimals(ctx context.Context, tokenAddresses []common.Address) ([]uint8, error) { ret := _m.Called(ctx, tokenAddresses) + if len(ret) == 0 { + panic("no return value specified for GetTokensDecimals") + } + var r0 []uint8 var r1 error if rf, ok := ret.Get(0).(func(context.Context, []common.Address) ([]uint8, error)); ok { diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/usdc_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/usdc_reader_mock.go index 76ab22775a..df5b1576ef 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/usdc_reader_mock.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/usdc_reader_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *USDCReader) Close(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -41,6 +45,10 @@ func (_m *USDCReader) Close(qopts ...pg.QOpt) error { func (_m *USDCReader) GetLastUSDCMessagePriorToLogIndexInTx(ctx context.Context, logIndex int64, txHash common.Hash) ([]byte, error) { ret := _m.Called(ctx, logIndex, txHash) + if len(ret) == 0 { + panic("no return value specified for GetLastUSDCMessagePriorToLogIndexInTx") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, common.Hash) ([]byte, error)); ok { @@ -63,6 +71,30 @@ func (_m *USDCReader) GetLastUSDCMessagePriorToLogIndexInTx(ctx context.Context, return r0, r1 } +// RegisterFilters provides a mock function with given fields: qopts +func (_m *USDCReader) RegisterFilters(qopts ...pg.QOpt) error { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RegisterFilters") + } + + var r0 error + if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { + r0 = rf(qopts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // NewUSDCReader creates a new instance of USDCReader. 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 NewUSDCReader(t interface { diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go index 8a75f4e849..66dea7dfcb 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go @@ -1,12 +1,13 @@ package ccipdata_test import ( - "github.com/stretchr/testify/mock" "math/big" "math/rand" "testing" "time" + "github.com/stretchr/testify/mock" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go index 6c956af659..dd4be8484c 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go @@ -1,12 +1,14 @@ package ccipdata_test import ( - evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/stretchr/testify/mock" "math/big" "testing" "time" + "github.com/stretchr/testify/mock" + + evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go index cdde2301b9..7397e26580 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go @@ -2,12 +2,13 @@ package ccipdata_test import ( "context" - "github.com/stretchr/testify/mock" "math/big" "reflect" "testing" "time" + "github.com/stretchr/testify/mock" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader.go index c8021300f0..71e1c511b5 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader.go @@ -20,20 +20,26 @@ const ( //go:generate mockery --quiet --name USDCReader --filename usdc_reader_mock.go --case=underscore type USDCReader interface { + RegisterFilters(qopts ...pg.QOpt) error // GetLastUSDCMessagePriorToLogIndexInTx returns the last USDC message that was sent before the provided log index in the given transaction. GetLastUSDCMessagePriorToLogIndexInTx(ctx context.Context, logIndex int64, txHash common.Hash) ([]byte, error) Close(qopts ...pg.QOpt) error } type USDCReaderImpl struct { - usdcMessageSent common.Hash - lp logpoller.LogPoller - filterName string - lggr logger.Logger + usdcMessageSent common.Hash + lp logpoller.LogPoller + filter logpoller.Filter + lggr logger.Logger + transmitterAddress common.Address } func (u *USDCReaderImpl) Close(qopts ...pg.QOpt) error { - return u.lp.UnregisterFilter(u.filterName, qopts...) + return u.lp.UnregisterFilter(u.filter.Name, qopts...) +} + +func (u *USDCReaderImpl) RegisterFilters(qopts ...pg.QOpt) error { + return u.lp.RegisterFilter(u.filter, qopts...) } // usdcPayload has to match the onchain event emitted by the USDC message transmitter @@ -61,6 +67,7 @@ func parseUSDCMessageSent(logData []byte) ([]byte, error) { func (u *USDCReaderImpl) GetLastUSDCMessagePriorToLogIndexInTx(ctx context.Context, logIndex int64, txHash common.Hash) ([]byte, error) { logs, err := u.lp.IndexedLogsByTxHash( u.usdcMessageSent, + u.transmitterAddress, txHash, pg.WithParentCtx(ctx), ) @@ -79,19 +86,17 @@ func (u *USDCReaderImpl) GetLastUSDCMessagePriorToLogIndexInTx(ctx context.Conte } func NewUSDCReader(lggr logger.Logger, transmitter common.Address, lp logpoller.LogPoller) (*USDCReaderImpl, error) { - filterName := logpoller.FilterName(MESSAGE_SENT_FILTER_NAME, transmitter.Hex()) eventSig := utils.Keccak256Fixed([]byte("MessageSent(bytes)")) - if err := lp.RegisterFilter(logpoller.Filter{ - Name: filterName, + filter := logpoller.Filter{ + Name: logpoller.FilterName(MESSAGE_SENT_FILTER_NAME, transmitter.Hex()), EventSigs: []common.Hash{eventSig}, Addresses: []common.Address{transmitter}, - }); err != nil { - return nil, err } return &USDCReaderImpl{ - lggr: lggr, - lp: lp, - usdcMessageSent: eventSig, - filterName: filterName, + lggr: lggr, + lp: lp, + usdcMessageSent: eventSig, + filter: filter, + transmitterAddress: transmitter, }, nil } diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go index d10f9a7af8..531d190fd5 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go @@ -26,11 +26,11 @@ func TestLogPollerClient_GetLastUSDCMessagePriorToLogIndexInTx(t *testing.T) { t.Run("multiple found", func(t *testing.T) { lp := lpmocks.NewLogPoller(t) - lp.On("RegisterFilter", mock.Anything).Return(nil) u, err := NewUSDCReader(lggr, utils.RandomAddress(), lp) require.NoError(t, err) lp.On("IndexedLogsByTxHash", u.usdcMessageSent, + u.transmitterAddress, txHash, mock.Anything, ).Return([]logpoller.Log{ @@ -48,11 +48,11 @@ func TestLogPollerClient_GetLastUSDCMessagePriorToLogIndexInTx(t *testing.T) { t.Run("none found", func(t *testing.T) { lp := lpmocks.NewLogPoller(t) - lp.On("RegisterFilter", mock.Anything).Return(nil) u, err := NewUSDCReader(lggr, utils.RandomAddress(), lp) require.NoError(t, err) lp.On("IndexedLogsByTxHash", u.usdcMessageSent, + u.transmitterAddress, txHash, mock.Anything, ).Return([]logpoller.Log{}, nil) diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_test.go index dd99dad33d..c518ef1f1d 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_test.go @@ -15,6 +15,7 @@ func TestUSDCReaderFilters(t *testing.T) { ccipdata.AssertFilterRegistration(t, new(lpmocks.LogPoller), func(lp *lpmocks.LogPoller, addr common.Address) ccipdata.Closer { c, err := ccipdata.NewUSDCReader(logger.TestLogger(t), addr, lp) require.NoError(t, err) + require.NoError(t, c.RegisterFilters()) return c }, 1) } diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go index 63e86f1ca6..afab263ade 100644 --- a/core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go +++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package pricegetter @@ -20,6 +20,10 @@ type MockPriceGetter struct { func (_m *MockPriceGetter) TokenPricesUSD(ctx context.Context, tokens []common.Address) (map[common.Address]*big.Int, error) { ret := _m.Called(ctx, tokens) + if len(ret) == 0 { + panic("no return value specified for TokenPricesUSD") + } + var r0 map[common.Address]*big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, []common.Address) (map[common.Address]*big.Int, error)); ok { diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline_test.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline_test.go index 2d8f835150..6fdf5955ac 100644 --- a/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline_test.go +++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline_test.go @@ -23,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" - config "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + config "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" ) diff --git a/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks/evm_mock.go b/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks/evm_mock.go index 348c56a4a6..41a1f3eda0 100644 --- a/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks/evm_mock.go +++ b/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks/evm_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package rpclibmocks @@ -18,6 +18,10 @@ type EvmBatchCaller struct { func (_m *EvmBatchCaller) BatchCall(ctx context.Context, blockNumber uint64, calls []rpclib.EvmCall) ([]rpclib.DataAndErr, error) { ret := _m.Called(ctx, blockNumber, calls) + if len(ret) == 0 { + panic("no return value specified for BatchCall") + } + var r0 []rpclib.DataAndErr var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64, []rpclib.EvmCall) ([]rpclib.DataAndErr, error)); ok { diff --git a/core/services/ocr2/plugins/ccip/metrics.go b/core/services/ocr2/plugins/ccip/metrics.go index e14aa2cd7c..13d22be005 100644 --- a/core/services/ocr2/plugins/ccip/metrics.go +++ b/core/services/ocr2/plugins/ccip/metrics.go @@ -50,6 +50,8 @@ var ( Help: "Duration of building single batch in Execution Plugin", Buckets: execPluginDurationBuckets, }, execPluginLabels) + + //nolint unused execPluginReportsIterationDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "ccip_execution_reports_iteration_build_batch", Help: "Duration of iterating over all unexpired reports in Execution Plugin", @@ -67,10 +69,12 @@ func measureObservationBuildDuration(timestamp types.ReportTimestamp, duration t measureExecPluginDuration(execPluginObservationBuildDuration, timestamp, duration) } +// nolint unused func measureBatchBuildDuration(timestamp types.ReportTimestamp, duration time.Duration) { measureExecPluginDuration(execPluginBatchBuildDuration, timestamp, duration) } +// nolint unused func measureReportsIterationDuration(timestamp types.ReportTimestamp, duration time.Duration) { measureExecPluginDuration(execPluginReportsIterationDuration, timestamp, duration) } diff --git a/core/services/ocr2/plugins/ccip/observations_test.go b/core/services/ocr2/plugins/ccip/observations_test.go index 89bfeb5403..3cec1c928d 100644 --- a/core/services/ocr2/plugins/ccip/observations_test.go +++ b/core/services/ocr2/plugins/ccip/observations_test.go @@ -2,11 +2,13 @@ package ccip import ( "encoding/json" - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_0_0" "math/big" "testing" + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_0_0" + "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" diff --git a/core/services/ocr2/plugins/ccip/prices/da_price_estimator_test.go b/core/services/ocr2/plugins/ccip/prices/da_price_estimator_test.go index d8d4a661e0..b5695460b5 100644 --- a/core/services/ocr2/plugins/ccip/prices/da_price_estimator_test.go +++ b/core/services/ocr2/plugins/ccip/prices/da_price_estimator_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal" ) diff --git a/core/services/ocr2/plugins/ccip/prices/exec_price_estimator.go b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator.go index 8e26e24edb..361ba34fee 100644 --- a/core/services/ocr2/plugins/ccip/prices/exec_price_estimator.go +++ b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator.go @@ -5,7 +5,7 @@ import ( "fmt" "math/big" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc" diff --git a/core/services/ocr2/plugins/ccip/prices/exec_price_estimator_test.go b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator_test.go index 19b1b83115..4024056519 100644 --- a/core/services/ocr2/plugins/ccip/prices/exec_price_estimator_test.go +++ b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator_test.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal" diff --git a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_commit_mock.go b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_commit_mock.go index 0d431d40e6..d265321511 100644 --- a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_commit_mock.go +++ b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_commit_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package prices @@ -18,6 +18,10 @@ type MockGasPriceEstimatorCommit struct { func (_m *MockGasPriceEstimatorCommit) DenoteInUSD(p GasPrice, wrappedNativePrice *big.Int) (GasPrice, error) { ret := _m.Called(p, wrappedNativePrice) + if len(ret) == 0 { + panic("no return value specified for DenoteInUSD") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func(GasPrice, *big.Int) (GasPrice, error)); ok { @@ -44,6 +48,10 @@ func (_m *MockGasPriceEstimatorCommit) DenoteInUSD(p GasPrice, wrappedNativePric func (_m *MockGasPriceEstimatorCommit) Deviates(p1 GasPrice, p2 GasPrice) (bool, error) { ret := _m.Called(p1, p2) + if len(ret) == 0 { + panic("no return value specified for Deviates") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(GasPrice, GasPrice) (bool, error)); ok { @@ -68,6 +76,10 @@ func (_m *MockGasPriceEstimatorCommit) Deviates(p1 GasPrice, p2 GasPrice) (bool, func (_m *MockGasPriceEstimatorCommit) GetGasPrice(ctx context.Context) (GasPrice, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetGasPrice") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func(context.Context) (GasPrice, error)); ok { @@ -94,6 +106,10 @@ func (_m *MockGasPriceEstimatorCommit) GetGasPrice(ctx context.Context) (GasPric func (_m *MockGasPriceEstimatorCommit) Median(gasPrices []GasPrice) (GasPrice, error) { ret := _m.Called(gasPrices) + if len(ret) == 0 { + panic("no return value specified for Median") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func([]GasPrice) (GasPrice, error)); ok { @@ -120,6 +136,10 @@ func (_m *MockGasPriceEstimatorCommit) Median(gasPrices []GasPrice) (GasPrice, e func (_m *MockGasPriceEstimatorCommit) String(p GasPrice) string { ret := _m.Called(p) + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func(GasPrice) string); ok { r0 = rf(p) diff --git a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_exec_mock.go b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_exec_mock.go index 52ecc06a3e..3097f2431d 100644 --- a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_exec_mock.go +++ b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_exec_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package prices @@ -19,6 +19,10 @@ type MockGasPriceEstimatorExec struct { func (_m *MockGasPriceEstimatorExec) DenoteInUSD(p GasPrice, wrappedNativePrice *big.Int) (GasPrice, error) { ret := _m.Called(p, wrappedNativePrice) + if len(ret) == 0 { + panic("no return value specified for DenoteInUSD") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func(GasPrice, *big.Int) (GasPrice, error)); ok { @@ -45,6 +49,10 @@ func (_m *MockGasPriceEstimatorExec) DenoteInUSD(p GasPrice, wrappedNativePrice func (_m *MockGasPriceEstimatorExec) EstimateMsgCostUSD(p GasPrice, wrappedNativePrice *big.Int, msg internal.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error) { ret := _m.Called(p, wrappedNativePrice, msg) + if len(ret) == 0 { + panic("no return value specified for EstimateMsgCostUSD") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(GasPrice, *big.Int, internal.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error)); ok { @@ -71,6 +79,10 @@ func (_m *MockGasPriceEstimatorExec) EstimateMsgCostUSD(p GasPrice, wrappedNativ func (_m *MockGasPriceEstimatorExec) GetGasPrice(ctx context.Context) (GasPrice, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetGasPrice") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func(context.Context) (GasPrice, error)); ok { @@ -97,6 +109,10 @@ func (_m *MockGasPriceEstimatorExec) GetGasPrice(ctx context.Context) (GasPrice, func (_m *MockGasPriceEstimatorExec) Median(gasPrices []GasPrice) (GasPrice, error) { ret := _m.Called(gasPrices) + if len(ret) == 0 { + panic("no return value specified for Median") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func([]GasPrice) (GasPrice, error)); ok { @@ -123,6 +139,10 @@ func (_m *MockGasPriceEstimatorExec) Median(gasPrices []GasPrice) (GasPrice, err func (_m *MockGasPriceEstimatorExec) String(p GasPrice) string { ret := _m.Called(p) + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func(GasPrice) string); ok { r0 = rf(p) diff --git a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_mock.go b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_mock.go index bae00e1062..ab9c1caa96 100644 --- a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_mock.go +++ b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package prices @@ -19,6 +19,10 @@ type MockGasPriceEstimator struct { func (_m *MockGasPriceEstimator) DenoteInUSD(p GasPrice, wrappedNativePrice *big.Int) (GasPrice, error) { ret := _m.Called(p, wrappedNativePrice) + if len(ret) == 0 { + panic("no return value specified for DenoteInUSD") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func(GasPrice, *big.Int) (GasPrice, error)); ok { @@ -45,6 +49,10 @@ func (_m *MockGasPriceEstimator) DenoteInUSD(p GasPrice, wrappedNativePrice *big func (_m *MockGasPriceEstimator) Deviates(p1 GasPrice, p2 GasPrice) (bool, error) { ret := _m.Called(p1, p2) + if len(ret) == 0 { + panic("no return value specified for Deviates") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(GasPrice, GasPrice) (bool, error)); ok { @@ -69,6 +77,10 @@ func (_m *MockGasPriceEstimator) Deviates(p1 GasPrice, p2 GasPrice) (bool, error func (_m *MockGasPriceEstimator) EstimateMsgCostUSD(p GasPrice, wrappedNativePrice *big.Int, msg internal.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error) { ret := _m.Called(p, wrappedNativePrice, msg) + if len(ret) == 0 { + panic("no return value specified for EstimateMsgCostUSD") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(GasPrice, *big.Int, internal.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error)); ok { @@ -95,6 +107,10 @@ func (_m *MockGasPriceEstimator) EstimateMsgCostUSD(p GasPrice, wrappedNativePri func (_m *MockGasPriceEstimator) GetGasPrice(ctx context.Context) (GasPrice, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetGasPrice") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func(context.Context) (GasPrice, error)); ok { @@ -121,6 +137,10 @@ func (_m *MockGasPriceEstimator) GetGasPrice(ctx context.Context) (GasPrice, err func (_m *MockGasPriceEstimator) Median(gasPrices []GasPrice) (GasPrice, error) { ret := _m.Called(gasPrices) + if len(ret) == 0 { + panic("no return value specified for Median") + } + var r0 GasPrice var r1 error if rf, ok := ret.Get(0).(func([]GasPrice) (GasPrice, error)); ok { @@ -147,6 +167,10 @@ func (_m *MockGasPriceEstimator) Median(gasPrices []GasPrice) (GasPrice, error) func (_m *MockGasPriceEstimator) String(p GasPrice) string { ret := _m.Called(p) + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func(GasPrice) string); ok { r0 = rf(p) diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go index 124c3986ee..75c9286db0 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go @@ -2,10 +2,10 @@ package integrationtesthelpers import ( "context" + "crypto/rand" "encoding/hex" "fmt" "math/big" - "math/rand" "net" "net/http" "net/http/httptest" @@ -19,24 +19,27 @@ import ( "github.com/ethereum/go-ethereum/common" types3 "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" + "github.com/jmoiron/sqlx" "github.com/onsi/gomega" "github.com/pkg/errors" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" "k8s.io/utils/pointer" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - ctfClient "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + + evmUtils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + + "github.com/smartcontractkit/chainlink-common/pkg/loop" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp" @@ -85,12 +88,18 @@ const ( relay = "evm" pluginType = "ccip-execution" transmitterID = "%s" - + [relayConfig] chainID = 1_337 - + [pluginConfig] destStartBlock = 50 + + [pluginConfig.USDCConfig] + AttestationAPI = "http://blah.com" + SourceMessageTransmitterAddress = "%s" + SourceTokenAddress = "%s" + AttestationAPITimeoutSeconds = 10 ` commitSpecTemplate = ` type = "offchainreporting2" @@ -106,10 +115,10 @@ const ( relay = "evm" pluginType = "ccip-commit" transmitterID = "%s" - + [relayConfig] chainID = 1_337 - + [pluginConfig] destStartBlock = 50 offRamp = "%s" @@ -291,7 +300,7 @@ func (node *Node) ConsistentlySeqNumHasNotBeenExecuted(t *testing.T, ccipContrac return log } -func (node *Node) AddJob(t *testing.T, spec *ctfClient.OCR2TaskJobSpec) { +func (node *Node) AddJob(t *testing.T, spec *OCR2TaskJobSpec) { specString, err := spec.String() require.NoError(t, err) ccipJob, err := validate.ValidatedOracleSpecToml(node.App.GetConfig().OCR2(), node.App.GetConfig().Insecure(), specString) @@ -300,7 +309,7 @@ func (node *Node) AddJob(t *testing.T, spec *ctfClient.OCR2TaskJobSpec) { require.NoError(t, err) } -func (node *Node) AddBootstrapJob(t *testing.T, spec *ctfClient.OCR2TaskJobSpec) { +func (node *Node) AddBootstrapJob(t *testing.T, spec *OCR2TaskJobSpec) { specString, err := spec.String() require.NoError(t, err) ccipJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(specString) @@ -309,7 +318,7 @@ func (node *Node) AddBootstrapJob(t *testing.T, spec *ctfClient.OCR2TaskJobSpec) require.NoError(t, err) } -func (node *Node) AddJobsWithSpec(t *testing.T, jobSpec *ctfClient.OCR2TaskJobSpec) { +func (node *Node) AddJobsWithSpec(t *testing.T, jobSpec *OCR2TaskJobSpec) { // set node specific values jobSpec.OCR2OracleSpec.OCRKeyBundleID.SetValid(node.KeyBundle.ID()) jobSpec.OCR2OracleSpec.TransmitterID.SetValid(node.Transmitter.Hex()) @@ -330,7 +339,7 @@ func setupNodeCCIP( // Do not want to load fixtures as they contain a dummy chainID. loglevel := configv2.LogLevel(zap.DebugLevel) - config, db := heavyweight.FullTestDBNoFixturesV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, _ *chainlink.Secrets) { + config, db := heavyweight.FullTestDBNoFixturesV2(t, func(c *chainlink.Config, _ *chainlink.Secrets) { p2pAddresses := []string{ fmt.Sprintf("127.0.0.1:%d", port), } @@ -342,7 +351,6 @@ func setupNodeCCIP( c.OCR.DefaultTransactionQueueDepth = pointer.Uint32(200) c.OCR2.Enabled = &trueRef c.Feature.LogPoller = &trueRef - c.P2P.V1.Enabled = &falseRef c.P2P.V2.Enabled = &trueRef c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) @@ -386,9 +394,9 @@ func setupNodeCCIP( ETHKS: keyStore.Eth(), CSAKS: keyStore.CSA(), } - mailMon := utils.NewMailboxMonitor("CCIP") + mailMon := mailbox.NewMonitor("CCIP") evmOpts := chainlink.EVMFactoryConfig{ - ChainOpts: evm.ChainOpts{ + ChainOpts: legacyevm.ChainOpts{ AppConfig: config, EventBroadcaster: eventBroadcaster, GenEthClient: func(chainID *big.Int) client.Client { @@ -476,7 +484,7 @@ func createConfigV2Chain(chainId *big.Int) *v2.EVMConfig { defaultGasLimit := uint32(5000000) tr := true - sourceC := v2.Defaults((*utils.Big)(chainId)) + sourceC := v2.Defaults((*evmUtils.Big)(chainId)) sourceC.GasEstimator.LimitDefault = &defaultGasLimit fixedPrice := "FixedPrice" sourceC.GasEstimator.Mode = &fixedPrice @@ -485,7 +493,7 @@ func createConfigV2Chain(chainId *big.Int) *v2.EVMConfig { fd := uint32(2) sourceC.FinalityDepth = &fd return &v2.EVMConfig{ - ChainID: (*utils.Big)(chainId), + ChainID: (*evmUtils.Big)(chainId), Enabled: &tr, Chain: sourceC, Nodes: v2.EVMNodes{&v2.Node{}}, @@ -544,7 +552,7 @@ func (c *CCIPIntegrationTestHarness) AddAllJobs(t *testing.T, jobParams CCIPJobS } } -func (c *CCIPIntegrationTestHarness) jobSpecProposal(t *testing.T, specTemplate string, f func() (*ctfClient.OCR2TaskJobSpec, error), feedsManagerId int64, version int32, opts ...any) feeds2.ProposeJobArgs { +func (c *CCIPIntegrationTestHarness) jobSpecProposal(t *testing.T, specTemplate string, f func() (*OCR2TaskJobSpec, error), feedsManagerId int64, version int32, opts ...any) feeds2.ProposeJobArgs { spec, err := f() require.NoError(t, err) @@ -609,6 +617,8 @@ func (c *CCIPIntegrationTestHarness) ApproveJobSpecs(t *testing.T, jobParams CCI 1, node.KeyBundle.ID(), node.Transmitter.Hex(), + utils.RandomAddress().String(), + utils.RandomAddress().String(), ) execId, err := f.ProposeJob(ctx, &execSpec) require.NoError(t, err) @@ -871,13 +881,13 @@ func (c *CCIPIntegrationTestHarness) SetupAndStartNodes(ctx context.Context, t * return bootstrapNode, nodes, configBlock } -func (c *CCIPIntegrationTestHarness) SetUpNodesAndJobs(t *testing.T, pricePipeline string) CCIPJobSpecParams { +func (c *CCIPIntegrationTestHarness) SetUpNodesAndJobs(t *testing.T, pricePipeline string, usdcAttestationAPI string) CCIPJobSpecParams { // setup Jobs ctx := context.Background() // Starts nodes and configures them in the OCR contracts. bootstrapNode, _, configBlock := c.SetupAndStartNodes(ctx, t, generateRandomBootstrapPort()) - jobParams := c.NewCCIPJobSpecParams(pricePipeline, configBlock) + jobParams := c.NewCCIPJobSpecParams(pricePipeline, configBlock, usdcAttestationAPI) // Add the bootstrap job c.Bootstrap.AddBootstrapJob(t, jobParams.BootstrapJob(c.Dest.CommitStore.Address().Hex())) @@ -961,7 +971,8 @@ func generateRandomBootstrapPort() int64 { minPort := int64(10000) maxPort := int64(65500) for { - port := rand.Int63n(maxPort-minPort+1) + minPort + i, _ := rand.Int(rand.Reader, big.NewInt(maxPort-minPort)) + port := i.Int64() + minPort if isPortAvailable(port) { return port } diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/jobspec.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/jobspec.go index 13e75f8084..8abe3cb546 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/integration/jobspec.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/jobspec.go @@ -1,21 +1,145 @@ package integrationtesthelpers import ( + "bytes" "fmt" + "text/template" + "time" "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" - "github.com/smartcontractkit/chainlink-relay/pkg/types" - - "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) +// OCR2TaskJobSpec represents an OCR2 job that is given to other nodes, meant to communicate with the bootstrap node, +// and provide their answers +type OCR2TaskJobSpec struct { + Name string `toml:"name"` + JobType string `toml:"type"` + MaxTaskDuration string `toml:"maxTaskDuration"` // Optional + ForwardingAllowed bool `toml:"forwardingAllowed"` + OCR2OracleSpec job.OCR2OracleSpec + ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node +} + +// Type returns the type of the job +func (o *OCR2TaskJobSpec) Type() string { return o.JobType } + +// String representation of the job +func (o *OCR2TaskJobSpec) String() (string, error) { + var feedID string + if o.OCR2OracleSpec.FeedID != nil { + feedID = o.OCR2OracleSpec.FeedID.Hex() + } + specWrap := struct { + Name string + JobType string + MaxTaskDuration string + ForwardingAllowed bool + ContractID string + FeedID string + Relay string + PluginType string + RelayConfig map[string]interface{} + PluginConfig map[string]interface{} + P2PV2Bootstrappers []string + OCRKeyBundleID string + MonitoringEndpoint string + TransmitterID string + BlockchainTimeout time.Duration + TrackerSubscribeInterval time.Duration + TrackerPollInterval time.Duration + ContractConfirmations uint16 + ObservationSource string + }{ + Name: o.Name, + JobType: o.JobType, + ForwardingAllowed: o.ForwardingAllowed, + MaxTaskDuration: o.MaxTaskDuration, + ContractID: o.OCR2OracleSpec.ContractID, + FeedID: feedID, + Relay: string(o.OCR2OracleSpec.Relay), + PluginType: string(o.OCR2OracleSpec.PluginType), + RelayConfig: o.OCR2OracleSpec.RelayConfig, + PluginConfig: o.OCR2OracleSpec.PluginConfig, + P2PV2Bootstrappers: o.OCR2OracleSpec.P2PV2Bootstrappers, + OCRKeyBundleID: o.OCR2OracleSpec.OCRKeyBundleID.String, + MonitoringEndpoint: o.OCR2OracleSpec.MonitoringEndpoint.String, + TransmitterID: o.OCR2OracleSpec.TransmitterID.String, + BlockchainTimeout: o.OCR2OracleSpec.BlockchainTimeout.Duration(), + ContractConfirmations: o.OCR2OracleSpec.ContractConfigConfirmations, + TrackerPollInterval: o.OCR2OracleSpec.ContractConfigTrackerPollInterval.Duration(), + ObservationSource: o.ObservationSource, + } + ocr2TemplateString := ` +type = "{{ .JobType }}" +name = "{{.Name}}" +forwardingAllowed = {{.ForwardingAllowed}} +{{if .MaxTaskDuration}} +maxTaskDuration = "{{ .MaxTaskDuration }}" {{end}} +{{if .PluginType}} +pluginType = "{{ .PluginType }}" {{end}} +relay = "{{.Relay}}" +schemaVersion = 1 +contractID = "{{.ContractID}}" +{{if .FeedID}} +feedID = "{{.FeedID}}" +{{end}} +{{if eq .JobType "offchainreporting2" }} +ocrKeyBundleID = "{{.OCRKeyBundleID}}" {{end}} +{{if eq .JobType "offchainreporting2" }} +transmitterID = "{{.TransmitterID}}" {{end}} +{{if .BlockchainTimeout}} +blockchainTimeout = "{{.BlockchainTimeout}}" +{{end}} +{{if .ContractConfirmations}} +contractConfigConfirmations = {{.ContractConfirmations}} +{{end}} +{{if .TrackerPollInterval}} +contractConfigTrackerPollInterval = "{{.TrackerPollInterval}}" +{{end}} +{{if .TrackerSubscribeInterval}} +contractConfigTrackerSubscribeInterval = "{{.TrackerSubscribeInterval}}" +{{end}} +{{if .P2PV2Bootstrappers}} +p2pv2Bootstrappers = [{{range .P2PV2Bootstrappers}}"{{.}}",{{end}}]{{end}} +{{if .MonitoringEndpoint}} +monitoringEndpoint = "{{.MonitoringEndpoint}}" {{end}} +{{if .ObservationSource}} +observationSource = """ +{{.ObservationSource}} +"""{{end}} +{{if eq .JobType "offchainreporting2" }} +[pluginConfig]{{range $key, $value := .PluginConfig}} +{{$key}} = {{$value}}{{end}} +{{end}} +[relayConfig]{{range $key, $value := .RelayConfig}} +{{$key}} = {{$value}}{{end}} +` + return MarshallTemplate(specWrap, "OCR2 Job", ocr2TemplateString) +} + +// marshallTemplate Helper to marshall templates +func MarshallTemplate(jobSpec interface{}, name, templateString string) (string, error) { + var buf bytes.Buffer + tmpl, err := template.New(name).Parse(templateString) + if err != nil { + return "", err + } + err = tmpl.Execute(&buf, jobSpec) + if err != nil { + return "", err + } + return buf.String(), err +} + type JobType string const ( @@ -42,6 +166,7 @@ type CCIPJobSpecParams struct { TokenPricesUSDPipeline string SourceStartBlock uint64 DestStartBlock uint64 + USDCAttestationAPI string P2PV2Bootstrappers pq.StringArray } @@ -76,7 +201,7 @@ func (params CCIPJobSpecParams) ValidateExecJobSpec() error { // CommitJobSpec generates template for CCIP-relay job spec. // OCRKeyBundleID,TransmitterID need to be set from the calling function -func (params CCIPJobSpecParams) CommitJobSpec() (*client.OCR2TaskJobSpec, error) { +func (params CCIPJobSpecParams) CommitJobSpec() (*OCR2TaskJobSpec, error) { err := params.ValidateCommitJobSpec() if err != nil { return nil, err @@ -104,7 +229,7 @@ func (params CCIPJobSpecParams) CommitJobSpec() (*client.OCR2TaskJobSpec, error) if params.SourceStartBlock > 0 { ocrSpec.PluginConfig["sourceStartBlock"] = params.SourceStartBlock } - return &client.OCR2TaskJobSpec{ + return &OCR2TaskJobSpec{ OCR2OracleSpec: ocrSpec, JobType: "offchainreporting2", Name: JobName(Commit, params.SourceChainName, params.DestChainName, params.Version), @@ -113,7 +238,7 @@ func (params CCIPJobSpecParams) CommitJobSpec() (*client.OCR2TaskJobSpec, error) // ExecutionJobSpec generates template for CCIP-execution job spec. // OCRKeyBundleID,TransmitterID need to be set from the calling function -func (params CCIPJobSpecParams) ExecutionJobSpec() (*client.OCR2TaskJobSpec, error) { +func (params CCIPJobSpecParams) ExecutionJobSpec() (*OCR2TaskJobSpec, error) { err := params.ValidateExecJobSpec() if err != nil { return nil, err @@ -137,14 +262,20 @@ func (params CCIPJobSpecParams) ExecutionJobSpec() (*client.OCR2TaskJobSpec, err if params.SourceStartBlock > 0 { ocrSpec.PluginConfig["sourceStartBlock"] = params.SourceStartBlock } - return &client.OCR2TaskJobSpec{ + if params.USDCAttestationAPI != "" { + ocrSpec.PluginConfig["USDCConfig.AttestationAPI"] = fmt.Sprintf("\"%s\"", params.USDCAttestationAPI) + ocrSpec.PluginConfig["USDCConfig.SourceTokenAddress"] = fmt.Sprintf("\"%s\"", utils.RandomAddress().String()) + ocrSpec.PluginConfig["USDCConfig.SourceMessageTransmitterAddress"] = fmt.Sprintf("\"%s\"", utils.RandomAddress().String()) + ocrSpec.PluginConfig["USDCConfig.AttestationAPITimeoutSeconds"] = 5 + } + return &OCR2TaskJobSpec{ OCR2OracleSpec: ocrSpec, JobType: "offchainreporting2", Name: JobName(Execution, params.SourceChainName, params.DestChainName, params.Version), }, err } -func (params CCIPJobSpecParams) BootstrapJob(contractID string) *client.OCR2TaskJobSpec { +func (params CCIPJobSpecParams) BootstrapJob(contractID string) *OCR2TaskJobSpec { bootstrapSpec := job.OCR2OracleSpec{ ContractID: contractID, Relay: relay.EVM, @@ -154,14 +285,14 @@ func (params CCIPJobSpecParams) BootstrapJob(contractID string) *client.OCR2Task "chainID": params.DestEvmChainId, }, } - return &client.OCR2TaskJobSpec{ + return &OCR2TaskJobSpec{ Name: fmt.Sprintf("%s-%s", Boostrap, params.DestChainName), JobType: "bootstrap", OCR2OracleSpec: bootstrapSpec, } } -func (c *CCIPIntegrationTestHarness) NewCCIPJobSpecParams(tokenPricesUSDPipeline string, configBlock int64) CCIPJobSpecParams { +func (c *CCIPIntegrationTestHarness) NewCCIPJobSpecParams(tokenPricesUSDPipeline string, configBlock int64, usdcAttestationAPI string) CCIPJobSpecParams { return CCIPJobSpecParams{ CommitStore: c.Dest.CommitStore.Address(), OffRamp: c.Dest.OffRamp.Address(), @@ -170,5 +301,6 @@ func (c *CCIPIntegrationTestHarness) NewCCIPJobSpecParams(tokenPricesUSDPipeline DestChainName: "SimulatedDest", TokenPricesUSDPipeline: tokenPricesUSDPipeline, DestStartBlock: uint64(configBlock), + USDCAttestationAPI: usdcAttestationAPI, } } diff --git a/core/services/ocr2/plugins/ccip/tokendata/http/http_client.go b/core/services/ocr2/plugins/ccip/tokendata/http/http_client.go index cc8e37cd17..4775b33394 100644 --- a/core/services/ocr2/plugins/ccip/tokendata/http/http_client.go +++ b/core/services/ocr2/plugins/ccip/tokendata/http/http_client.go @@ -31,7 +31,7 @@ func (s *HttpClient) Get(ctx context.Context, url string, timeout time.Duration) res, err := http.DefaultClient.Do(req) if err != nil { // Only report API timeout if child context timed out. - if errors.Is(err, context.DeadlineExceeded) && context.Cause(timeoutCtx) == tokendata.ErrTimeout { + if errors.Is(err, context.DeadlineExceeded) && errors.Is(context.Cause(timeoutCtx), tokendata.ErrTimeout) { return nil, http.StatusRequestTimeout, tokendata.ErrTimeout } // On error, res is nil in most cases, do not read res.StatusCode, return BadRequest diff --git a/core/services/ocr2/plugins/ccip/tokendata/reader.go b/core/services/ocr2/plugins/ccip/tokendata/reader.go index 2ea32be998..07558cad5f 100644 --- a/core/services/ocr2/plugins/ccip/tokendata/reader.go +++ b/core/services/ocr2/plugins/ccip/tokendata/reader.go @@ -20,5 +20,6 @@ var ( type Reader interface { // ReadTokenData returns the attestation bytes if ready, and throws an error if not ready. ReadTokenData(ctx context.Context, msg internal.EVM2EVMOnRampCCIPSendRequestedWithMeta) (tokenData []byte, err error) + RegisterFilters(qopts ...pg.QOpt) error Close(qopts ...pg.QOpt) error } diff --git a/core/services/ocr2/plugins/ccip/tokendata/reader_mock.go b/core/services/ocr2/plugins/ccip/tokendata/reader_mock.go index f88869bae7..a525b72d27 100644 --- a/core/services/ocr2/plugins/ccip/tokendata/reader_mock.go +++ b/core/services/ocr2/plugins/ccip/tokendata/reader_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package tokendata @@ -26,6 +26,10 @@ func (_m *MockReader) Close(qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { r0 = rf(qopts...) @@ -40,6 +44,10 @@ func (_m *MockReader) Close(qopts ...pg.QOpt) error { func (_m *MockReader) ReadTokenData(ctx context.Context, msg internal.EVM2EVMOnRampCCIPSendRequestedWithMeta) ([]byte, error) { ret := _m.Called(ctx, msg) + if len(ret) == 0 { + panic("no return value specified for ReadTokenData") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, internal.EVM2EVMOnRampCCIPSendRequestedWithMeta) ([]byte, error)); ok { @@ -62,6 +70,30 @@ func (_m *MockReader) ReadTokenData(ctx context.Context, msg internal.EVM2EVMOnR return r0, r1 } +// RegisterFilters provides a mock function with given fields: qopts +func (_m *MockReader) RegisterFilters(qopts ...pg.QOpt) error { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RegisterFilters") + } + + var r0 error + if rf, ok := ret.Get(0).(func(...pg.QOpt) error); ok { + r0 = rf(qopts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // NewMockReader creates a new instance of MockReader. 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 NewMockReader(t interface { diff --git a/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go index 7ef4833be6..7cf98a9a8b 100644 --- a/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go +++ b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go @@ -172,3 +172,7 @@ func (s *TokenDataReader) callAttestationApi(ctx context.Context, usdcMessageHas func (s *TokenDataReader) Close(qopts ...pg.QOpt) error { return s.usdcReader.Close(qopts...) } + +func (s *TokenDataReader) RegisterFilters(qopts ...pg.QOpt) error { + return s.usdcReader.RegisterFilters(qopts...) +} diff --git a/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go index 8bd314992f..3bac237511 100644 --- a/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go +++ b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go @@ -57,7 +57,6 @@ func TestUSDCReader_callAttestationApiMock(t *testing.T) { lggr := logger.TestLogger(t) lp := mocks.NewLogPoller(t) - lp.On("RegisterFilter", mock.Anything).Return(nil) usdcReader, err := ccipdata.NewUSDCReader(lggr, mockMsgTransmitter, lp) require.NoError(t, err) usdcService := NewUSDCTokenDataReader(lggr, usdcReader, attestationURI, 0) @@ -160,10 +159,11 @@ func TestUSDCReader_callAttestationApiMockError(t *testing.T) { lggr := logger.TestLogger(t) lp := mocks.NewLogPoller(t) - lp.On("RegisterFilter", mock.Anything).Return(nil) usdcReader, err := ccipdata.NewUSDCReader(lggr, mockMsgTransmitter, lp) require.NoError(t, err) usdcService := NewUSDCTokenDataReader(lggr, usdcReader, attestationURI, test.customTimeoutSeconds) + lp.On("RegisterFilter", mock.Anything).Return(nil) + require.NoError(t, usdcReader.RegisterFilters()) parentCtx, cancel := context.WithTimeout(context.Background(), time.Duration(test.parentTimeoutSeconds)*time.Second) defer cancel() @@ -174,6 +174,8 @@ func TestUSDCReader_callAttestationApiMockError(t *testing.T) { if test.expectedError != nil { require.True(t, errors.Is(err, test.expectedError)) } + lp.On("UnregisterFilter", mock.Anything).Return(nil) + require.NoError(t, usdcReader.Close()) }) } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go index 9f61ad29d0..278c727a06 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go @@ -6,11 +6,12 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 54a5058a64..dbd44b3546 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -30,7 +30,7 @@ func ValidatedOracleSpecToml(config OCR2Config, insConf InsecureConfig, tomlStri var spec job.OCR2OracleSpec tree, err := toml.Load(tomlString) if err != nil { - return jb, pkgerrors.Wrap(err, "toml error on load") + return jb, pkgerrors.Wrapf(err, "toml error on load %v", tomlString) } // Note this validates all the fields which implement an UnmarshalText // i.e. TransmitterAddress, PeerID... diff --git a/core/services/relay/evm/ccip.go b/core/services/relay/evm/ccip.go index 1c3ff504ed..c3a5d01bae 100644 --- a/core/services/relay/evm/ccip.go +++ b/core/services/relay/evm/ccip.go @@ -12,17 +12,17 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - relaytypes "github.com/smartcontractkit/chainlink-common/pkg/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" ) // CCIPCommitProvider provides all components needed for a CCIP Relay OCR2 plugin. type CCIPCommitProvider interface { - relaytypes.Plugin + commontypes.Plugin } // CCIPExecutionProvider provides all components needed for a CCIP Execution OCR2 plugin. type CCIPExecutionProvider interface { - relaytypes.Plugin + commontypes.Plugin } type ccipCommitProvider struct { @@ -30,7 +30,7 @@ type ccipCommitProvider struct { contractTransmitter *contractTransmitter } -func NewCCIPCommitProvider(lggr logger.Logger, chainSet legacyevm.Chain, rargs relaytypes.RelayArgs, transmitterID string, ks keystore.Eth, eventBroadcaster pg.EventBroadcaster) (CCIPCommitProvider, error) { +func NewCCIPCommitProvider(lggr logger.Logger, chainSet legacyevm.Chain, rargs commontypes.RelayArgs, transmitterID string, ks keystore.Eth, eventBroadcaster pg.EventBroadcaster) (CCIPCommitProvider, error) { relayOpts := types.NewRelayOpts(rargs) configWatcher, err := newConfigProvider(lggr, chainSet, relayOpts, eventBroadcaster) if err != nil { @@ -45,7 +45,7 @@ func NewCCIPCommitProvider(lggr logger.Logger, chainSet legacyevm.Chain, rargs r if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(lggr, rargs, transmitterID, ks, configWatcher, fn) + contractTransmitter, err := newContractTransmitter(lggr, rargs, transmitterID, ks, configWatcher, configTransmitterOpts{}, fn) if err != nil { return nil, err } @@ -59,14 +59,18 @@ func (c *ccipCommitProvider) ContractTransmitter() ocrtypes.ContractTransmitter return c.contractTransmitter } +func (c *ccipCommitProvider) ChainReader() commontypes.ChainReader { + return nil +} + type ccipExecutionProvider struct { *configWatcher contractTransmitter *contractTransmitter } -var _ relaytypes.Plugin = (*ccipExecutionProvider)(nil) +var _ commontypes.Plugin = (*ccipExecutionProvider)(nil) -func NewCCIPExecutionProvider(lggr logger.Logger, chainSet legacyevm.Chain, rargs relaytypes.RelayArgs, transmitterID string, ks keystore.Eth, eventBroadcaster pg.EventBroadcaster) (CCIPExecutionProvider, error) { +func NewCCIPExecutionProvider(lggr logger.Logger, chainSet legacyevm.Chain, rargs commontypes.RelayArgs, transmitterID string, ks keystore.Eth, eventBroadcaster pg.EventBroadcaster) (CCIPExecutionProvider, error) { relayOpts := types.NewRelayOpts(rargs) configWatcher, err := newConfigProvider(lggr, chainSet, relayOpts, eventBroadcaster) @@ -82,7 +86,7 @@ func NewCCIPExecutionProvider(lggr logger.Logger, chainSet legacyevm.Chain, rarg if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(lggr, rargs, transmitterID, ks, configWatcher, fn) + contractTransmitter, err := newContractTransmitter(lggr, rargs, transmitterID, ks, configWatcher, configTransmitterOpts{}, fn) if err != nil { return nil, err } @@ -95,3 +99,7 @@ func NewCCIPExecutionProvider(lggr logger.Logger, chainSet legacyevm.Chain, rarg func (c *ccipExecutionProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } + +func (c *ccipExecutionProvider) ChainReader() commontypes.ChainReader { + return nil +} diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 303cdd3ba0..e939334dbe 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -378,7 +378,7 @@ type configTransmitterOpts struct { pluginGasLimit *uint32 } -func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts) (*contractTransmitter, error) { +func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts, reportToEthMeta ReportToEthMetadata) (*contractTransmitter, error) { var relayConfig types.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -446,7 +446,7 @@ func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, tra transmitter, configWatcher.chain.LogPoller(), lggr, - nil, + reportToEthMeta, ) } @@ -472,7 +472,7 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp } reportCodec := evmreportcodec.ReportCodec{} - contractTransmitter, err := newContractTransmitter(lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}) + contractTransmitter, err := newContractTransmitter(lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}, nil) if err != nil { return nil, err } diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 55c4d78e7b..4d925221c2 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -73,7 +73,7 @@ func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, p } gasLimit := cfgWatcher.chain.Config().EVM().OCR2().Automation().GasLimit() - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, cfgWatcher, configTransmitterOpts{pluginGasLimit: &gasLimit}) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, cfgWatcher, configTransmitterOpts{pluginGasLimit: &gasLimit}, nil) if err != nil { return nil, err } diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index 1e05f89d9d..829d2747ab 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -67,7 +67,7 @@ func (r *ocr2vrfRelayer) NewDKGProvider(rargs commontypes.RelayArgs, pargs commo if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, nil) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func (r *ocr2vrfRelayer) NewOCR2VRFProvider(rargs commontypes.RelayArgs, pargs c if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, nil) if err != nil { return nil, err } diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 9efad05c03..c7235d5481 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s' FeedsManager = true LogPoller = false UICSAKeys = false +CCIP = false [Database] DefaultIdleInTxSessionTimeout = '1h0m0s' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 45504d6259..9339181ab5 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -6,6 +6,7 @@ ShutdownGracePeriod = '10s' FeedsManager = true LogPoller = true UICSAKeys = true +CCIP = false [Database] DefaultIdleInTxSessionTimeout = '1m0s' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 40c18f28eb..59389118c9 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s' FeedsManager = true LogPoller = false UICSAKeys = false +CCIP = false [Database] DefaultIdleInTxSessionTimeout = '1h0m0s' @@ -403,7 +404,7 @@ AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false FinalityDepth = 500 -FinalityTagEnabled = false +FinalityTagEnabled = true LinkContractAddress = '0xb0897686c545045aFc77CF20eC7A532E3120E0F1' LogBackfillBatchSize = 1000 LogPollInterval = '1s' diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 3c4dbc8efc..80cf456f80 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1116,9 +1116,7 @@ OutgoingMessageBufferSize = 10 # Default PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example TraceLogging = false # Default ``` - P2P has a versioned networking stack. Currenly only `[P2P.V2]` is supported. - All nodes in the OCR network should share the same networking stack. ### IncomingMessageBufferSize @@ -2906,7 +2904,7 @@ AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false ChainType = 'kroma' -FinalityDepth = 40 +FinalityDepth = 400 FinalityTagEnabled = true LogBackfillBatchSize = 1000 LogPollInterval = '2s' @@ -3474,7 +3472,7 @@ BlockBackfillDepth = 10 BlockBackfillSkip = false ChainType = 'wemix' FinalityDepth = 1 -FinalityTagEnabled = false +FinalityTagEnabled = true LogBackfillBatchSize = 1000 LogPollInterval = '3s' LogKeepBlocksDepth = 100000 @@ -3555,7 +3553,7 @@ BlockBackfillDepth = 10 BlockBackfillSkip = false ChainType = 'wemix' FinalityDepth = 1 -FinalityTagEnabled = false +FinalityTagEnabled = true LogBackfillBatchSize = 1000 LogPollInterval = '3s' LogKeepBlocksDepth = 100000 @@ -3628,164 +3626,6 @@ GasLimit = 5300000

S*n=hVDw^envM(;P<`2}eMwkS_%=_P29;Ql1+ge?#4 zPSx2e+%R3zlZxK9Z!-8m{KN>93Xq@3aiH0Se|L7OR^MwOz7Jc0xaZ1B@HJ_b{UEoQ zCaSbLNa#9tdC8Dezo9V0%gYt(TUMDUpc;k`icYb4jL+5dpGyuRP_Nf^?8bTvkt%i= zy8S@w&>RMA;3wQCqg&l-PtiY1o%LtFdf)RZ6DDFecaItTFEOB}I}K>^m;nW;X{!kk zR1c_ig-23u=~p!RvxhcG(HyR$-rhz)?N+PZUfF}sVe#OGVBM-j;fvV!fAgU~`P84V z^HF{$n_*$@Ko29099U6B?Z`?c+*ui9CWY7ceD1mk;`%l&#t__8G~xDsL`C(apf8!= z^l7O;^?f}?7`_eM)%Hoa{Pgtn^5pf|yO$@YG}s&!p^i>oyIE9@K4s76;f1Vj}o#F#ziDnoOZ1sXZEi3 zJ@vgQsQ!PhzO0a4>x%%ZTPY0_$v;48!s87lQN!8Vc8TfNak@<@w5)~=c#oO=h{ez= z#CQ!95j8ry2NFLhTJfAEnc@{AZPj{|pf!!6n`~YnIV&uqNMaeG4A37(xNQME+C*%4 zOGeMZ$NG2I!PEyXjuv$xKzEz9|9TsK`UM)E6gIpG^Kjcbt%X#tig=Nd3v;$PK1=5q z2p*=KmqlR$osj$~84#&>t<(+TV8FydPZI}Q)#lc<;`5uD04Mn(t;2#I(V)(Dmc-DE zx3i=qzufXguvzb}16Q}Y9G9B!-+BxK7jvJ*=xi*p@GpQ*Cy3GNl(6y}@ekw7a|Gq-ufS?M}1Cbu*{d ztT!0BGCfD{MHuo~kmMq_yy+CV%(Tde>au_)7Zh-l%*dE9Hi@RUsORCa1lw7O@Sr?| z;#r0{0hL2nET^C3)FhF3B`TNE8O-T>ERt5>3}kRUGnlBY|l1B@z! zvyIBZh$H;lQGd9BLm1aI#oTac3QP>>7@_Wk&YMl4HHYqlykDf)1uK)58iKIPLcC z05)}}>nNn}R!%tN=ru$gnS%Eok)+aSbGUlWzb7uJ5-8#75~UVZHwi-M;(HNRcdg6z zlwn0b!}e0LzICdSf=%q_7~q6KZQ?fyXpLc@Aat}Sh~*kD$RaE^+At!Ah#^#&ZbL2c z5m1Y1tKi_M3LH9kq@OUtkoJF=6uCdC!p^Yb6F$LD-O$l zrNpaS#meqglEgcLV`*cm^h?FRPE>B5Q$@`;^gylUScKg7k>Wc@;677y{)#-xYAj(P zXOd49ll)%c13pvEX)h%L&~tjL4fTDk@SxsGOq6%-OC1d8S65N{3-^10cm-tcN66e^5nzvf6 z>%LtqkUxJV$Ug`4@)nWROQplmqeQBsXzU+~_^Lc0IsvfleVbbsd}a-e-TXzJkF78@ z;iezvT!`S#`MV1@w)agRgTYpr!ZL?27o#l!TK61U^$RA?i(KD>ODDOyeOqDJbQKnB zx58U(KiQbAaex1c3_=C4PXsFomBaLkOWV&1lI8l9FiL|-;EypOi#SF!Wf2(*v_2@9-0CgdLNIyBwh$DPmVAadiLd0i@9 zVM+Rf_H_5dRM%Pe}z0v&$Qv_H&kQe>L zj4VsUEJv7V%IZz(e!c08$Ou$Hs7Rxzu_X1tWbB92@9nUuzJwaZ1R$ z!07!^akQcx^#3(5&DhQH1=FA(sIq95o7xzWhXSn|!Xf&cu}6Iyz6||fudotKgV+P| z=LPgqArFU3d;b?i6mm!B1`uG`zpyZqHfXBQk^d-_UYW*w!8tTxR5BRc8}X+(66aa) zMyo7@A*4>ckvH~jNqop0{0TFRrtVXnP+t#zs`xYXD3q-2o%(VN-|qP%^BC6%07(}oIfedC$5S@ubGg>5;Q&NN_b_wTXSV&`>G+b*lz_h zPN@-p$GnhS#-wUpZ}Nwdmt*9BDRl$V)O_s)pOTf)e8U42nK3b@?}nE6mWy9yGaptw zAEkMmMNr&utvJSWuq08mULwtJ97^71ayn+ct)`&LG%nPcy&z5e>BJC8kbK-|?Z<zc?X0bfg>ilrKHZTdqX0puTWIHyA~bpxpC+zdfr3v#p^OX03 zrGflKH*P^xKM*BmxWbjANWwvs7P!q84i_g6I~4H9A)kswe~Jfl1TWOls9pQ+55RR1 z1RuuMj-}#eQ%@J!os=HJzr-|yz+DrDP(;Cv#209|6@UW7o1t^?loPls2by2S&UeM2 zFKx^i{9Pdjf(i63bQAn|l)M#fV!a<(+Q_U>QvvDpJ#ed4Yo29&irn|qERgU}yEfn3 z2A-}WVryy7H2j}$SK#cp;}K%srbsH(Uo4rkuF%-@8R}}o{)!1lxd+%(;DA%_bumq# z7R*3|nwLs*DCjF|ndqjtyV#p+8mW&qcg|#b-@?a-CQL@L7|u|7_dsU&6*C$MJ@?mD zdoC5iMyNoo{Vor7lJc=+ogvA^PBr_$wvS~nw(NUECq>kFX2Lk*M~Mc$?J-zN>w$v( zh}i@;TYeU`7$Qg{Hv7b^4bD=AVpAfujObVDg|Ta0J|S#LRdZv+X3( z-WM+KJ6?O$thu-YKiud%h%>KTZ7#%8d= zs;DO$*^Z~d74el+adLYjFpYQqWJ(5igTNjL2U)_D&?OM!SNwNZl^5OCD9c-+H-zz{ z;(8kd7IH3$FvDp!$oM@_8yKRuoeH=ur`B+~f2Q%=Op&S3vXMl^VaXm@?@aQ&Bl!-8 z3Vslie3Dl?QSe{GB?rZ4KVQ_EUO0Ehi^cUWJv?XoO!K9d(s5-m=6#%6T=!cGWvUYj zfu56=ba&Ki1RyI*Wr?mZDCb}_nS@#uF1svPtlHC72cJcVIk{_QdR~PO(4E@)9XmaD z#O?Zq+wi9*o@s1*2L9A9tR>H(iI64=cazu;2Rn&z5vDYN`~uET_8#&-C21kHV*)bZ zAn2_vr7&vwIV8wa{mS$3! zm_V71fLX!>O7f((>%`7B`*W_&bWh;5qDvNLLp8ZVAagGuZK0+D>#-8D71$CBo^E!w z_f$(@P{|GXEzO`>qij)FYq7L>BKNhh7ww1WKSEX`>D>vcDHl^PSb~ECwmS944=dGs zYv(`g5VygJuQJKG@zuNa?ZIcNH#I~r<_@+)1*4rDzH|?jcB8YEziXTLT908ML~YHl zkkwd0%#2omV>j?Wjr;Yr#fgkeII;-Y#z+mewgRr8jMi?Q3Herz_lTH{5m|DHS z#H3OP!#<)MQgDfDRNKiEua9U3I926(xgMid@anaf6q7@WNMcN?Xm+}tT?nDT8}5Pm z^?<({sVp`FS>gNnt#-4yZH_aK(g!{p-G$$wOBCC1Z)~S?U2ITf#au#mr1R~bE5!Sd z*9jB>>FHpsy=W-)0VI3sovPCN^X#zRZEl4f(Izm$Pm0t@%yT3U6jsoO$)>qW)@7`j zNBK=Oh&j5qrNW(hvs>Sh;|RaN+ys}>t621u?-j{!oKH<;HgClM#(6txVqe2by~YF@ zIVMoQu!rslrn^`H(7-h$JC|oBE`bEdbi`&tsPuEIKXfN%)mjD^A~0l-_WKAgJ*?ct zL5j--EFd0;06DzEn7%}Y9(*H4#sP{9ZZyH;_iog=*P!}6L z!bGA}$*0U~MEmzstr|S1!yF}Uu{A^T&-MDozwhRR+|`zwZ_h2xHZfPR3;9=ipIBnJpu#WM>idMwQERl; z@tYn5#^AUYD>>%{dc{bCxL}G%r^%r)INs@)awb+=JbyzI8rx;NvwY8XsOHB^p>JHt z&CrS;Qn%4AE#JGnmz$z@ls*D;MqE-@uG6mL9_>A5k3#zl?$Tn9T%CNJ+c)m1HfA3Y zxpHuH{?8A|hw=Wu`CI8p`N%!~cmKS=EBg79<3sz*J@gK*>{smP4Oz)f%`?P=I9 zkuf4iV03R;UMiPkP)(vR4Z_S{!UAVh49eMT8s`SZD?`cEo^e4Z&_?_a&=00Y%A_kimhW)*UAoAQT&RKvy8ks$^S#~7dEbttr^OOZJ ztE?I@nPDJrUD^fP2W@;_Dh*2|KeuV^y3ZxJEk0+?7mFOq?Q@GZVW79840*tiw$cbi z|0*#M;olnER_LrZ<_1fk0o!-=EODr2#U|@qxoO^HK>LdYAw|Fqk7yYCpx2k~A3I+{==JwUX|OOS%^&T~ecAYQ4mj z`kX?+Jv1y(#*b4bu3WQ>Z8!FF%Qn&36{tyAGsxD6G2Aw?A>63OwjsrgDzSIxJ~y8c za6Eh~pa)o$iF`#Nbe*U!ac9`2zy@wD6q^z=vkf*NAPOQS-wq6O(6fx*t=R0jmu98C zY-zvFF#r>X7>0JS$js*$hWG#)un0^)_b-4e==Xp;@v6%r*50}!^AsIns{OZOlmA`c zdTqWve@BVyZgRx;+F%7|$>ii9FHg3;Tu;jP|)3J|F-78ZZ>%2F&JOifYbY?2r85 z){kvo3S9VC7R3J8u$ElU?e3mXqEyCf?X({P zsb;?MOu$f1huF7KLA-l%Z>W8wO=bvlb);<0Z!D!0e_~xq>J-f#=IRDB4}rip6;M3B z9s>rguiJ>U#xlWaMa=kYdgCnWuc9|r{GX<`c56c>4iHO`7A@sIsE98Y1dMFlv4I62 zo_nK%ZX*M+S^`j64}%#H)SpVQQyhPE)S7M%9T%{x{jzEELR13>7dDy3m1F@cvs`&dow@1j>dbeY=69mY2%=<@M+VqL|WPNKGGBHLlLLo$YBqWip4Hs>~IH6;EM4l`}o9!)T3`LChJQ zXBVJo6wPvworlniQ$AJMQq@BpjY$f|(4dWqF+742)xMkc&B?NW9biGg#xN ze)`v8jXTYnvwIXlqgEF*QE$}pFi(O8)3WlR=^lqov06g51^AHE0r6Uk{A~jgh zcV5jpjYg-lH7VI@V#5NmL?HY|4HqEe|NBq>*Z*TwJOn~q?$q3j0J#fxdlQq>B2WDy zbBM)+JBH~!j@>GOAH^~&07406$8IRBy{S-`GGWnfw3~nR@C}128aw#in3&b3r$ER= z!I%dJc5B_gylT@RykV8YqixlrCvz37cAdYz@1p6L)ejD~RWDbyHU?zxEWmY;eN;vS zV7aYYw0S%B-$p^0KHZv9StJzgY>R7MO-djUB{t8vI*m~oI8J^F(reITWhOvWUk!1?Ks|PU0_+)C^uCGni09+f>;B0ee$r=AUA)A;QV zv2a2`VTBY<>k*&U7>KlK^Sd~2E5S!7Mi97K=F7NuZIZ`AjJ-?2xxx@U7z=+7%*zBk zfmt|$1A*cVSJ7XG4Pv+U0Oal$pz;agrxBS?@hc<}*)&CNeO@iNiSyw#Sp{n$bsA;#+ZEo8Kk*PZi^4G%j)vpSM zQB?g^_$9fyG@uT!%Pnd$G&A99|L18 zH$kIo+3DY$YOPTQ`K*TC$-*0?@+%Z(3UY>fwVfv$V}_n$hLK{HiR6pBkj;K#f@nIL zW@C&f!d+2*QiuTZA0mn1CM{hN+a-TgzUgMCU2pu=(*c+@FgM;RcD#kV1o>68)9!2^ z4Y72ROqEamCPTcKn%ZhoJT$NB-pkaFy%c!^;zwhs)(C!8s8(Y2Bfc2fvU#~EQ{8zw zu@jylk-&s-OnRg{tg15z8zj>Q0^esJ2wZNmlx}_?F$&rLlkPmgowTdVp6P>X5yC=Y z^LNY2#Lr*xg-iF+5(~*+KHO5A%S&^`TEcbgPZV=*)!REyy;`H&ZLH0`Vwr_|`i+!M zJXL`66SbALvVX?+;O0tc9?HG2nTkieBB`f|opq~d?q114ckYmHk)hoYch7`rKy>4Y zdkKtAQRJz6OB8tnzltJHEc@fSc7Eo5B#VUo3PmpQ8T*a9zyAtlA6+?uK9^6Jhm}KA z%%2wTLAXAZ+Rs@_R5CASMv0h@f-s_(p&Lt&OsfDKUty<`Q6%=0Y?>-}hEVY2GgZpc z{$5A<;c4BiPpA6qJF#Q`3iNFtcs>nNn{V5Ob`}P>X7plhGT4{vc7_|3ADjoMu-X() zzrG00VP7VD1fR^Y`_$CIz|fL|Tk}N|S%$zY;gD5%z;>(>Ge-AE+_sR{jE^J7s1W zsQC0DL(E5PUFeR5?-MH0n*3}SJO}m)_hw*Eu+`Rb7hd-Uc$}C_y-j@>>1pSgwUC)0S*+Ure=t%1 z@bpd@`1wsXbRe;Eja#2s|6We(f4?`5d@eCzT6H)I4;W$X5vlqdsQ8UAbiU#?*ho*} zmvaIEW^jIoqm~K7`3I za6In^&sd28I(`RGACp|Z?fb>z4)?e|E*973NBhoxMhIIE2ywM`6?ylHnUpUdYf>Do zFPY-=xRP|+ttM@{aPJ4Z*m3<_-#}xUWg?@UL>Eg}!1UZ#xzGjPAZAYF+9EWacS~x) zqoiK0pj&X?C22ODGJHc^=29CIFXGrvbOyIKQ8ASJ3FktVL_VN*ICz0zHT^`JO4Yv5 z1g=pJm}B5Cvx}p{61{Kn_}?K^hS*yF`h0%j4%wC_?lkKKBATM7UxB3=n8UnWUTSde z^8tRPcfGtIpTJhLwzCzq4Nq6m+hxpMaJrq=Zt@L5^^8x#@iyDbqh#<--EnG@utn&3vcWb%}4(M4px3;LG7}4b26)T&F-;NvWC_j678|05X1)c_thXZDFbv@ple z47&RS!;!d@np*Zv8J$4MKzVAPSmitD_mlFiEbpXzFQ?1t(NOuc=r2NzZdimCte~x3 z*Jd3dSNUD@ZJ|VQl}t^871K0du_tOqjOF6Zyd+uraWxy}iu8xdZas6i1MB-ekqHCZ z2&3~=73TvgT+-*La%kgaR1^32;q3hS0^})tjGdUI64Mj+Zaygh(@@~CzJwN7-Cbvo zoL{IXxI@t=uV=K4rR^_m_{AMDLnANat0V8&U^`>76YS!Q&$k2PE2D=s?5_$pzIsY1 z49XVn3-QK>R<4OR!5|RRfxsBJ*9Xdw95q|}O2ED{lKDKYDOjQ~O}WV%hummc=|LiIOt&glmm@*;5l1 zL;Z?n-&vOY;3+zT-T*H}S?=S}rAV^&5xqafLuXL7dE#E4f4o39IfPh(=@0AX3F}K3 z3dw1zh`R(l*JLe!=ANHjpcC21OU*a- zE9?YGGvAj=&sagr477|CZS8k)(90SB*|tdw?<_+I=d z^}_pd>P50ay^xDA+twnUix?sv(dj5RZ#ecLb;#6>6%F=51qVt2YL4}3z{Ya|<4NVo zMNxYQ6pEF%rc4Ee2{1ufWWq?2X$JLnt@W4tM3ZF?AOFw2F_ubDmBle&?+hTE>Y zuZSe~t*nTgo)Tr1T+vqfIyqHTHc`vqSo#pI#tlfj=c>~^dK}XPgtbntk+-gvmKc_> zdBGBfzN?1_0LILV{w6Q6bc1IY-<>tQp-2>{j8ZksRK=(7Vgaiuo&&Ff;~_hCF4#gx zZ*ExTWZbW7j0{}Dhr^Nh)}cAHo*Y_G&SKHncMWtdQ}?K82aYAH02R_IiVt}7zI*`7 zsHppufrbBT59oI-Q{6ds;GVoy8OR%hf+gAZC9fjCNyYAWGDy})M%n3Zl-gPXTd1%%Uis#(*?0xtIFULjb z(7vTrf+Dr3B$+mStnGGf|RCX9mIqI9h-N^>+gN>er{Sb_$Dg_%(y?M6kk8?Dps zZ~#Qv!x#h%p7QVZ=6LC!zy~m28Kc~?VHv&1zQ=tb+1mk3%0Qo#m$^xaSH?n4$?q~u z%sYE*4bI0GJ$P13MWrmm#nU74ZXYwvDxw??s=ZU{laKZpl{6fTr2^L*>r&_$%pu&4 z7@1lL*y7V30_e%wp&QGIbqdS**gmyqEJO%(^czOEqWlw^R7C!o*5bVz*@{;nPQE&F zg@kqhXDkIUFYE05)y1YVKxK75ihRF&s~;!rlw>ny9sRK6rbxS0?K+lezzegJaBSchdxK5i1{nZGoj<$lb_9PMRzEy?7hGMZ zy@(~`+=^jcSZ}o_qSu_ZJ9e%+J^h&4v)vR{|L^??uYS9(<^9^R`dETi`yI&w-y*ue zgWl!_vW!cOhL#b#+pg7{&`Vx&AC9E!3Cn@yv_B&k4v%S%RABiEo|YcS-enoXrmj~x zy`K#uvXB)+r%y?UH^w|>4DSWu-c-X=S}ddlIW?_{_9VCLO)$oJylyRB!**~)QRsZD zg-a?GXJ>xzit0m;B%y=tP)U>Oo?8$<|FSuGTF5C6#?`e2%sC)Nk+{GZlE z`Kv=%#jovLcRv`q#(IQ&ZsDOJ4H9!wJx7tK=){p&)ri zw#d_Y?0aME2!q^39c2L29@gelr`D|PzUV7p2rbJ8mkx7z9&tW7bq?Ck?KD$0_sFdc z#aL$E;nR?rcbqPFYvUHAp-NvhQ=7I|3PJ2vt?u^{H-+#ZI7Z&3N>z3uU@8c+pYj?q z$o{5-75}KvSk7czDWdh0k1oUO=Z<$zRX7{s^+VSRy#7`VeV<>lPI4Grf2-SeI9@;7 z??kx%Ruzp}?_4o5_OB{G!3*WA_cNs*sCH|>o}&1~8(rI9yU&0yg7Mf74Fv7y6Uwl^ zbqzTa4f`wiHB71KEwJAJA?e}S-`p4Ey!Q?KD(AiTmi-eChCToG!v4+;IODT_1lh&- z`{|q4hRwGyf(dGj|8hS9v-}0ror(Pq_Z0sA-F*dre{jDCd4S%<jyZ~zZ1FJj&`|l$FEc}6nh+jnOA3wVe zrenmnPfDdx0R%^T-@P+`K~OnDe<=<<|3$fna(}h<(yCx21pc)K#amPVGJhiYHHoqI z6EIc#7yb~2=3`9#Po>f?_#gt{^nS^M>MJz2A27`Q&ioFVB~_8%K`2)(D11Mdk4j!1e zU-mWVbpH9*7w7Q>!Wgh40tpGB0U<`c$XvtsW)%^Pmxx)<-d!xPf4;WwO~?L(peM3` zDrPC*`*Bw97k;z`Id6TMD}`^yFi-7#m{DJ>$?>u=A`u}0tYxn1=Z)! zo-lZX#lC_HuR)V(^7|dGv;N4udI2L$-eF(J&Rl-^Uc~=xRBXn;z)M!gJL-py{qB4B~mgIJ{ ze^D+!=^HK{L~ly$I{b9V#*RQRG&*4@Da#coc+n^SFlQ7q5Ni9zKZCZdKZ&36sY);D zmxo*sK54ju7%w5~u{lucKg@LC`#tuNIQNmT;3L@0DSqiEo18Zo@}`ONk@9vBlu8Ek z?5Syf=dOp&>mt~9>pmQe->P^LO^D*i@#_*{sicgPIe9QI14>hd`<#)P-Z({C9JUz2 z;&EO}x?zVffwGz|Scj zUfVbLGq>MXiZdo8=4)P*jmg-4Aujw#X>_G6+Pf$zMvKK$=q_Bu35()oaw2Do0jwjB zF1{jJt^kJb3v|;=Nt)lmH-0uRO+U7Bo%N1Q8Ku{~UkkpCd z0g;wbhdu}>CREwIU^buntM{B`t}`}e$K2O*L$h=yJ%4JiAjtxy<*s0gc7J4V#6I=M zJAQma)@-2T{AD)waAUqx!8zdwW(4IWTKkqLv|yg#J3|hNYX8U;u%WvT%yG27>H3{1 zH75pbZ0x%~n#ffb3**z0&OUiPf2p0bn$st8#t0^;uA;>cxj~d<*EL{YnJNfW9QZ0| zH%@=eHthASfbo09Sv`UhBH+W+-Z%HhCh|w6QlrbahOdYqQ{(}+mgcA^goPlX;@nmi z`pvy{(LGFJEyqqS3 z1L{a?U0GD2K?w9*t+qEjVla42Wm;1ArS}?{ZyE(pa5obAM5jQ#mD$Wlr)_qNp1?hG z3{7pd8U^=rS`a}8H=LrU*y?lU5h6jW+AK0k0Sg{Qb7aX>qeiFo07e4lVHU6_Yy&1| zoQ^9VvbXWmIQH)QAPL7DorD-L3_bE@Iz7n{E#5FSBcDfH_tJLbx zwQB#?kMAGZ40@+f;0Uy;@9M2iNxq%x&Qw%$YMtg|dmb~*7T1_F4^eN;p#>|}tk#>4 z>{0j>thjt5q1tXdmde@tMU);0H<8_YSK(lD^@!}v&I305qDF;d=Hd0&e&_FfNpfj7 z>W$`SG~hGp{w1s3XgFPM1#!BaMjbvwNvrF%?Jz_$q3l-U&y`)T zbsDY5b~iWHJ+jByTlwmKW^Z>p&I3f!s&^2YI*<)mtJoI~@#aU?>8Q>>-In@Fk~H8^-L>)h8$IN7tU-`l3q*NL}4^!had2 zPV3K+eXFU#r{qfhvy-*c)<`o~a_7$#+-=pJ?IX!|F%-=+gMVUOXwm>}$HG)E_D`|Lcz7{z_W$u$l3 z4bTd%37t-D|FLu28(Ft3aA?2@cSKnB#|UXe6)Q5TOjjPqq-F-TsOaHQ(Zjr!_R!v+ zkIe9p=)2nYj^e)MyXm=yNx#s-1jh#l zA)bX7uHRRtAK(*>R_!zF4xL7`E8$jYUp<$ZB;WSY=C)7sDK*fkc+eiF^F($?~*GD z_HF{bizlo06hU{P%S8gk%xN=Jg-KzeOA(ra9vhhW6(Ob)w0n+#7I{i^L4Bj8JtF+Z zM-U)irx05Bk*on<`LdRlPOY)~ypb+1ayTVs(@KnQw^47^n9B<~iSUS~dbK88USL_T z@etom6(`>H3TezYlg1EaNEAVx7JGDtz!XCzI6}|HseJ{a9-QxJDRju_o^J8l&)S>CL zkp37c;|a|`Scv=n5uEm6Rkc#r|69YR<+kZG4}3euL;s-mBrVtJ`HI2!^Wa& z9hfQo;wEFRa10cH;xN1r_ZeiOAao#lK=)YL;>XPCgR)O|7K>^x+;>Ba@k{sJbl~)= zEYk;zO>qv><7%no9EL|#xQ9<2hs$MujwBuz*>yRq%SG$^h-VKB?^g8jOy(-K`k1nc zQ*mO38t^CU>zMU)3Z0R{LX%=w&|VyF)bTqu#t4V@J&J4cDSW`iM>Sz*|8}vsB6rwo z&H0RFh+{-Xif1N|V++~P!wbb3o)wIZWNaCl!!=I@6z~Y526}3kO(uS9!@+&(znM&6 zxhiK*!phe_pPiguzCC$&dGh_qtCQDfc3_&CcSnrg+2{*#kXc;F=ssXrELK0YwL-Fa zT-0*xA=|7+j&S8jqwgai2A?}xPSt8MaS1##H?g@ghjTK*FtH_uNErDtij_bfV>aNr zBkyagm#nKZwzuwTb?(@;)ykUIzRPMtcdfPCxc!%BOp(U?@=vpBv4WNs!8%l(T|~c4 zy}OF`Ktrfo1R~di-c=P^EGTagjR_x(Olqz<@C5F&|B2;{Fq6$1J#&_3^Lyk*vgCa? z!KhK?Ig!xn+^IDS3@mI3`Ew?gTGy#>DEd#Eg=)~v#YO)~yHEq>W&O*S%rdIAJGI)* zc-j&Iv=|)s@So=&#@@l?;!|z;)nNcsq^>mZ%4*uTEcBC+H}^Ne-;$_D0Pu!E@;v8< zQ&xr1L=RzXXiiL}M54nHFXJ4kL5e7}#gJ*oHN zZ28R((UF25GIhnWuW~6-77KBo*9RS(Bv^|6fkO+m&kM9L2tP zH3s*&)1Iu<6=txMmAYT4R4&Vwa9CNZRw%0#s``Z6>vOl_+|m=zvz(f^PfHA9^*Pyc zxUi(aiF&8;fPSuJKw)zk7fht;zclwrr=>vuK*Dg^Rp#KL`^YqFHP9L1*+$3NeFf2X z+28r(`OZY@TCJXQh(79+@uLKXKRmdx;0LdwaCEzG#EAa%qIBjn3ya=+SNY3z~r~aJt={Q@^yFdWWl= zFqG}4*yDS+5rq2m^?iZI>uxpguQnL^k6II%1}~eu=KRJskV+ONrR6SvL0l4AvBsA% z4>>`fkgDWsd6A_pkn*cW5{tbbA4PqOy!=-Y%0Mjh&tvp)gcVHlYYeqw1>otv>qg6h z&eZd$pZT--)C28$xHe(&`xwyy;)N<(LRfouGS8TFZbSb{=>#8vh`#TLfam%{8H@B> zdPD_W0Vh-V3P=Kv3hnR5i-p?N1L^Jj0#>-hq;~3<2I`p|;}SiYKn!|7SZw+VNj4o+ zd+7l=BnR5YqJe5{qg8tVlm5@OHT7o?H5DKEVl9 zIWdcDT*Ot-z$H8t6uM&UC(-oQHv^EuLjR+{tBMKvzLH-1p;^e8eT$H2Fq})`vU5;* zTgQiAT0MT<;n&YYp68)#`^-7wV!2##&wiSV=2ju&u`hI4jCF-V{P9~ah>J3Dpe*T` zpG1p$ViQ9pwP1M5AcgFltfATNwD};j*v^$GaTc+ek)g67Ec`s`6*s~1Zo~E@7yQF` z|HNAMCtARC25Ue@NO2zi+ACdS(QP9a15_$ydStcCUdoEdJ&TwSMKQ-C=;7RldJ_im z)@pnXX}0UtDtDQAfJ!x!D+to^Da6p@FiBdMVP@ft6s(Bd4&j-Z7lhF9g!@!T*;rU1 zS;yuE!bU|z6>MrJ2L~`La9_SEXrB}OQsg{_wj*cz zEX7Qw>(fEjx#v-251SP*jJwBrgJRO2Y zmnL{=lDjm*OGL`k)d*X6<-^u`Psti^i_*pg!_yaxd~@`6P_WeqSA=MX6(M6QLblps zGIBvF%l`DU<|61+ue^u8QFXEPPBfkWTqzb(+nN^VrGCT-hJl9`@1> zQ?}EpZ%cO2sCJs|^;xQUJh2IzsR>J1w4EmI3!s6&?bI6Fa|0URt~1vSCJkOwb~gk= zvghu24XB9RHFAx$XS%zT?j6a7MPFg)Twi2pn`uiwDm@!FlZx{FFfXatMbC%1LXJ>4 z%M@^!Q7FHqMXC=6sX_@#wSaRocBi;QLtsKMGufLxJez4WC!bFT6z= zhj-MjJ(y1ZY@XiliNV-I_=3GK+5=HN4ZP_djlTiYC_wi+DH4WKB#Z|z?|@K%fAN(^ z*3mZ;1VmYT+rHjJ`UV&EHVm zTC1*f`dwPLu{Ip9WW7R;4t^-N0M^p0=L7Hmw$;6y`z4QOG_wH+LBg^9GtAJ;QCE>R5g{zG4&V@-b z6Oybz<`Ra*PnO$QgDrU^8F0Y+Stj07qx5|49Tp$_V=BcFGgzhwYs{x zy1Fh+yQ;?ZLEl^C99sK1GrvB*=Y_c=Ak>b3+ugQ5Sk#cOLNRVV$WSJO9<kqqlF4&)=LJetdTF{v$T^<{i9z z{Pf}E@FlsoswQa!XOynkH}`hGR$46ZObF5GXIYOv|-jyg5N@s}Jl0qoY z8f(6gKa6b&%AXO#)d^8^d5^%S`=zntC8e=jdyi0a`6dXpNHUwlr$y+L$EI`{bP@r* zm74M1S7MVC4ka04kqOXVqfQruIqGj%01{>;GnnOzcPX!E+44N8C|^#jNo&bcx9PJo zO_KbYu|%XGvNd0mn=en&%qc?FH3d>a!5=W$#A7~BHGNCAl#jPf(H`fW9ag2(as{jJ zc>d)|(vQZ2?urt%gyM|c8NjJou$Xqy5YWR>b~0x(BSMQnk`VsXp3U>F};%aTbbE2bs?{lJ~=MGp~Jm2KJ;9*g#4)|LzS>Ks67; zun5YALcH;^|dlvQG^ zftg(oFe_~XVy)JpRBSt;%L&D%^9z-w^W^ri^2f}|PZ(3|?ri>BLAppH_yo@2v3%zC zc5SoyEzUEv>?Av|#ImEsHG6ikO(CQbBH}75g;6~81|_CkoCzs$@Wh21KKcxEpG0xI z>=~xf+}YfH@?Ixg!Jtph<$FCZS)2__oNa;;p>c|~TmATBb!qA=Gf>@LS!nMsOb#Z5__Q)=hb}!IDPwZXw=FSt^HMxep zy`4?PHBe~mvBrYOb!_h3I(w&-2rck=Pg;V}`SN6@96`rg)4AZiGaC2*6BG>{$hfP{HybjmZ!Wp;QIj+G~6rZc2otYl`j7?X4%{rgC*z#A=PL zNc$&av&QNqTQt4l$6vYsptf%9@4$;oK6xZo+&BMv(o-GtLCh*Fke%&sHmgsVN*L$+ zUeP=z56oj|gtvxiOuvdy06VbT_}{`t!08_Ly5v8IkI>wMBH)i3*|{Q zWjR<(Gpjgx{l440PxWLMhP8Pgsg8PrM`-SDZ8yIeFu#s_TS8?}@^1waxL|>{AjN=0 zk0~Y&hG?v$^zQ=Kvz@@@fQ=ptS-J!w#t+NoVAVY&k`w5>Rcki?Q~2jOVcq`-|NNDw z>&?w4$w_wWTbqxA)_BxK8|e5=nD96i(vqF6`Zu9XPv}S?_ajbZ#S5Z(5b@U%Y2_TmO6UZy*t^}G zohNOsPnp1M;x@OpGs(bQLn@>=G^7HJ=UYnqCUx}(-f*-?$uL0jBc!-; zt0Fa~_+pmLXr>*KQJQxXipTOZ4e z{#s~LsyIs2w#|4^4|Y5mcb){ziiBpxvi=*v34r_;z%!@_Xy$;qRo`yzF5f3u4zw&_ zc{m29OKs=OjYRR%7HjA}G>yG(;Dz@ui>;l;?t{zXzDC4S2n0PcJX}9;U$s+fNN2XF z3nMuJ8F6^*mX0~^@-BK!?qZM+-yN4rE3bH{ZdV3wLUDw9@HdMi>?0@t4}wlY6@2*k z?v-V0ZCs`1(f6+Sinmh2Or@1xz#)wo9}ixD@!?{lsQ!cXXRgkqBPbE=)@N9O!+&Vh zH+O)$1vUo3FlKWXJiVOPEE&4js@Ha!JDYGeXs%hDdhA+tfcI8?tFgJYE|SXiMsst^ zHrlZ5jjSY-wmUPrB)M72#r)0y;}mK8a+_MET@?i%b9-vnbYQyDC#ymVz|z>;TORe3 z;3Dh2ru3M>Z)EvIASJ@-T==kXrOOveSY1RUwrK#3dt+Bjx zPey1XMxj}&(Peh&O$gWnoJlwyb~qH_qnIOaq3BBe>FOD_zHtNH~GSnvH(g9=L zR(|Of;vG+5Xg6k+R_GcYaO*X^V*v+J?+Kf2l2d8Fyby-;7?z9W=n(Gk78$=GWeyWr+_v%X0epnKa(>r89| z^PU&a&qU_L?UU}c`Jo8pvgqm^`>BJyNKSF9(cJwTdNL=Oo9zb0kWs!@mp3eYL>CGq zRI{Csv1z0US*@|PylMwIPNINU+vKlx*6+L6OUIc{P(QO(7-a60q+d|7Tj*xaM*Eox z+$ggz?qtIAAw_Cv*z7`^HC$yo^u)bD;~O}NTv2FXn_atCJPXV zjz^@kY2WI1xu9F9c$#XPd;rrBFQ%qbc3k9>Gz)cF6S#@8rnlx{mt zB$tA12#eIz8Y4FOEumrP13Y3qX$9tNesvtm>N~t`ut5X!1I)04E@b3;S@sRG{YS~Z)SK(V3eDRBHMzu*bbZ3}cy3d@kPs4}`bnjc_o-WRM zDWEN62YtHj&tR7?+p&TI9Z_0~D3|7v7CcI06iZ1MldU|9dQM?zu?Ij^7L8JM ztrhR57<4Q)gO0^!(6PMFAmds|m5xQc6FFk6YHrZ2nc=_ydpR_oEVfCUvER*>iE|{} zwwenE_~M;rX5N5So_mc3anX%EL!8;%+}_?5u6K8qHq+VJ-BP|9>y52uUaYGeQW#8R zTBsEmRD1g3!pjg#QO!(qIDc?Fh=YaW(RUNGqiGh6rg4VLCn1j^q;9)xlPS~~`&k3gw-~ghGM1Td#AM+Qv3Izt1 zxgF}>b;WINsvLHzC_oD@Dv(; zB520Npz&uwv$dHi05@K|<&A@AQl!Ocy>wf*11Gz^RTKO6XhF6Ru6AVLwwRO*86 zEg$X3)MUdjTsgLk!f)Jn+wOI{kGFaOZgP3MqI(T<9_-&!4Rh+vt>q2SAEOK?H30oW zU7m-B6JQuT9u{g;WqN<8z&92Od|0JT0g{=JCeY&L*#J#71_}^k3B=J%zmI4`Bpje8wL43|OsL-%h zUD!8w_x?kW_1|i`A{FmuQI$W^^~UCQt+xFrTNMIBv8@X5bpLroGze3S0ZxE>BpD?d znhLv@fXJzdxeI71YK5(>1qFn4bF04mE#wolo*xE9@-j#;=4JY0u`DsK`i$dNq%z43 zR@y?WQUIE4*m>)gdr9P8{So(|k3km0k;RiBbUf|=(>7xpBA_!ipu!oDUpS7Xcm>25H0d$NOp8-2Gb1->*fv*pZjt z>@2-JD;QF|*&zlcN~)Wi zyE3ky3^JZm>Q}5 zREHZLfSCr%tS$*l-M*ghv?|JyS4=9cbp;MweZ6#RdRdn$*tMx+aSTcUWSYscWgRAx z$s)Hn@DF$-aS(d|8su;q(J-EBW$p(ilsr|-Y8LrJ9vODsO6a#^1_a*OZtgTuopq;? zU9h08;Lg?#S*sZ8+ z=Hw}x-`ag(TQoXv1W(@HZq^=+SSrjh`}!El83s}qWxCRZ|CSyJ#czH3 z649|-i)KP1xn#U_Pi`vRw=6%MvMuZdCrt0}vIIM$rd+?WsfXG^{T^W*+qQ{%zkaq(w<#%_G zfL0-~P9j6oEQjOKF)p765-CA?kjwVc`+K{$wYRye;=MJtrD74xg3psAKZtzi!{~&T z!z(VA0BopZeiZmHfnIW1BnDVpL!Y(iI~KiwwbLqs1^q>EMSr%om+bcLZoS@=USrAF z5xTu`bo}OUrTRy8Ll`G|h@A!ddtQOOSg-a#$R4GuIsKJ2>={;uTd`@GQ>5vS!4iMW z0?gSaX$$PBlajhnF~Ud`NdyL*1VbK;Q)evPE6G=wGC&Tzr-W6ezNvRxIDOt;Ae~f; zyO6>QX%Pi9+EXzB>##{kv5~NSqllZkHFWpjX9A2tCaUOVmUP`LzE3}sc#cSUb{i|} zWRj_2W{Y=`i9oKh_*oOug{#*$(Ogd7+?{7G=nplKI)*b(smJNe$}aKcBL{Q^PTXcU z?&aFrrJ)~xg5O_rugl{Ez8|@VIRf|IEq(g<_83;0-~Zsn-Y_Y#XYTv5;jH+rJD>&n z0{&)lmiIP$lS_DJvzPA1ALWe;_Rc+J@ZTBxP=v7WPI;vcl+6+k?ni!ccr&s}meqEC zIQ;{yk$Y#ijVa7+nU_mbyTnQt0mimsAKe9!eY+fG9-ltGd4WN?LO|}!Y$#J8<3RfU zEVKcXCw%KAE3K4J)U(;Tzjo6Q2x)RFY}u)s>WV&CVWncTkEWk1_M^LTy7~{x{_nH9 z9~w0P)bH+XX|?2(erVKTkpG~k9eA?nX&0VsdfJ1h|Hh}CLwJI+@C=Y)&x_#u`zb%0 zvQI^ycvt`?-RB?KbAa({ckT){wbiyGW6xBR(I7~z(pm`@RITOh2g*>$#`uA!Ub%c` z>j-ET-VVzmZV7EX$k8SG9d!Ogt@eJiLMorzytFA$Wnaafi} z@lp~kW-DpVQ0(}U+F683pC)pMMxyvIzeiczJ;$$vwxMgG zfufH`UJ(#!mGDtTW+7mT7)e&-TAphKkiBEYD(;aeWoO|pCG->5n@wBQDZ+{U9HIfC z<9^D!D+yBU(C6YlPJnWyQL!JQX4VG&)hJyeeHX}@v#z=7PFt-U-OJ@V*Lzfw9$y?RK9Sz ze6i-N$Qmjlzzb=J8|tNOj@%e?N>@cyjV*W`Cr(>AwydD7dUgs)ReL1IS41Lqr8WWj zFAOye3r~YHTr8-0(iWu4$J>+Tv0e$EByS>Po0p zUob6C5->^+b|iQH{F=U;o=K?a4#CLnGy_bCw!$=Hlqk?r--k?D-%I`ms7R2&_A&#M zRmH=u)~CopK8%P)>u8g&&;uA{-3JeE-y_kH#6?U52C>!}XWQKvfI>SStS;FjI2c%7 zJ5X3Nu2c|jfUw{(LsIO-wp$+FhGr-qNqi^E#XN!~QJgySH&bkJw*$Fu#SlZ-9Rs~l zw!(d76V(c#`^3MbkcGnuF+6Lf`(Y~;$QPWZ1m^>ezd$3^pi&0e?N%q|-sLnE*bpf9 z)zg{o7X@@O!r9Hue2iwZkJ4qyuihBr9EIe6)E4k&DQ$hi1p>Rw8S&&U#$JgXP&o(@ zQ}R$|?Z`uKZTIIloS?AV+%a^DwhTYBBldH~NnnB&LF9M{BXnEA>VXA3yLLh`L!T_z zAjKjgoVClqXq7+dC~1aAL&1iv;n?PSI<}BeC=A89inqx#=L+XnD6{IVtreUpPXtc? zlH>AdkJrZf#2R&??gTfSkrmn)G1OMx*x*}VoN?O1S%rSL$!7b+CXbL9RWt<n3Me{}=nqaC31}j8NnfPc-QKg&pVeIwW!D5e+xO;}oSx zFQ#}|y+|1c4YPN4n^IgL#iJxJ@G>_$krEgrnaoBgm((_QrK+D0BMdUpKra&wpp>9d z-$KyWHla}=ERYg{i%cGIMXB4(9U&}`@`!6UsR97Vx6TY8 z*rD*dL!e;C?u3r2IPFJqkWNY{G*GFD z-{(V)G6S8|kMK_LZI*!3RAMjS@cXRt8C{KSus87XN4H$5>J*e6bT`;LcjI5Rn~i{d zK+j~g$`1M^gLD7JzaTq2{V5!lJ*)hPQUXlDL-ilEKhi(KKjM||e%NsK58D5A`o|xC zoc-$#>is?UdG_mbs%~6^|0?*WQ9CQ&%_e*gC-qNQ4OMamZ?B8}`mlf&^(n5TjENS9 zlrvO?R*8xvSL#56Fo^FLbgnHpZ3c<9);)XH0!jt|bwk0qLskDIqDYY~JIImzDCC1F zR3$BzY+=tN1J|Endk-5zJ*(E(cH)3Jug8Qly-BRKhDxI*Rf?O;=f4W*vO)KgRfmX0I{ z%1{@KVT_(6vh47|bL$xkbWn#@Ymha_Ih^y{cLFGZ-L7vtyFd>V8@21YUc2rzfS_X& zZeT~SwJKPyTJ;)c_~=l+56+*qswnG3<|>nRz=N!kvZ$kl+kFs@`BZSeA@RhUYioasX~POonpfXmPs@7N zAeGgDo?|t@HdAv|qd7o<@b1p)RosyI2isZS<@D-42LeFxK~0Rg3S)+kNC@KnO=HYu z^3U}$>y%k#>!sP*Tf*^tUt#x<^dPVU*VE`)!vqC0SQqO-*~69s1A(aZ@u`320%ok^ zLpfkp!v*lgcXylUbYX4H7d_lu)h-z1fnatf5M-l+BV_&;+ofZaOt54#yd} zeq{iNwbQDRkFn^W*0K{9yTst9QaOX?K{*1#!SJC{iO$@lrJC4X%@9QC{Gwd1INAYC zOz758=0;&~-I|nd?zTKwFerWEr`}l`fQA0wQWs;A2DXtOPI}5O1qnVqo0ZE!reB>e zmrhLyTz;JqhDoQ6nV%)mT|Ci|Ck?<`I>e>uLyg3!{D%gz9l%Lhd;=e~1X^7$bF;~=6MVl;=xxgWSC-JN(Jc}a2| z#a$?r78F_)+y31hkZCUrqx3m{_S{SGtPeF{x5<;MXcA(#3gFWDMvQ0+zsp!XZNx6@%#w$;G4 z5Cc$<4o_|M@Etv1+d<)d(#Ru!S^DUWi(UX{RRibluD*&}#wzqHJ%!zKl}4P3y&9_a zislTr92Y0+hX$udSXpnQYaYLVNuXj;VKFL4-gI;MZBdi1wW_KW>FN!tO>iahG5z}V zJD}el{dVcMProDj?a=R#elO_vihd{bdriOR^m|CZ$Mkzizc=)ILcd4!`+mk72$Sj- z*~J7vlB4S(WIKR*jZk#g!Ji@g2r(FJ&kFdMCBuF3rZ8W;3Fa18Abf!njDCixMd1ps z!f7;~sN`PkUEncSz0WQV?1_0n_#8M%3=3~0eZnNzZ;10A?7Lb@XWu5*0bVvnu6H^B zHp{;Cq1F|iILP?vr4!k9x9mpw83xesvEKZ(4EcQv(hXLKcJ7v_b}Xy4-l%#38_IwP zk@VDze-UL08`OI*E!{})Vo({LTUK2pOkF!86!R%tE5m{#?gDr{{?`Tt8Sy%E3zNZAjYwNkl@l1~g251U*!yMMa?`gXCeoy}gL zI0w_O+~oA)OrPwpUY7YtwDuGA$wh}Gexj3L?gI0=D>L2h`(2k*b-+q9s=oMHZ&y> zf&O%a6zGwC7TB2U_Oq63`@X%`*k8x)Yv8!LnVUdNR0BO`YP-rhP2$g}4Xjtqfm4&X z5AD!75doq%y7^w++tdWuX_sFq5rPTU34-%wjs-GgbB}=;;FsQi-xAv48WFg7ZHQM; zxPqUr4=7GZRzxmG0rzX*oDEi_jWBku2}`ENPLGV(aq&93&TUHqUDzybf#TPi7Esc2 zXMT5<3s*|N=BEHT*W#Yy3JfjLFL?%Rn+&4iuJW#^{s#(AL1 zc2SLv#2?*JQTNYwzVZ`CV_jR8DE%Xwqqc0a?2^K-YS2t=mK^;mTX2dxlxy}V>z>Le zO8;WpQ()>agu}C9d9y2{m+@yz-U$awnnA)TX($w=j;&Z~c~TWq!?X1&UOLe2$4U?; zsTcYra(-r~?xhuEGK0|N@2wO?J{am@KEhZ?vTMqfu!t@=SXz{=CCrV`ML>2VPLWK` z0dR-b*lzjNc}-I*5kLp}nkg}v*I4qqE2Y_E$vaJ%hq0ro{h0S${z9mM#;C~^#lb}Y z9e!h^k-CE)4P5@xNY!Tm{?5#+&H(&_kxHwRf1F7XrT;WbBRj%>%+;6nMZVvSQ~@QI zKc7pJkmH}sw!8%LzE&wHb$sjcXNK7Uf8ow)J6{^w&hmgA8Ukp*!Hjta>=Pu2d6Fpw zG?Q{w=!|3w@LpLVI?QT{)M>^IaL~4VSWp`qB}S|+(*Cj=maQ1CD$20~B(4lc6`1g{ z`zzoalLbAI6Ek_R_7rtXWinJqMdsxl?FjXtBjpYPh;%uU8$OhAa5EJxB(kb@shsF$ z$1?G|Qh5vw0A$}R4M_wO?ZBNu)WN>mh7kjWV|ZqznxT-Gnb|Q&Q89KzUBM`sbt>r= zLKsF~{#9-ec3Iul(aldeL~uH?3dUa+TmWCHs20|s;SzU+BnwsD_!mI9~YM_=m(Y5?#`h2 z@Ar=hCpEkCm_tdtUvN?rCDR;ALIcki_fMPzRPCrHUgo0Er~4+@ARmzR_2T-~5;mIn zPB-zrTjUHHJ(@e56n$ak&ji@XYbuhO0j%b+#ow}9B+w53-r_F`?EWvciuh3I9^+=j zMC71(|5~x#Iz+u4W1M!;mXgXX1+_bA$x-`nY^JsWdVjgNKP~D8b_wy2@dT?<%Yq8O zyLT{sp-3rWE|SvEZED_qwDN&jaylZZAwl_#VzjW&q&KM68@2!8@$DP8E%&#d$#Zh; z<8q_6Ki&hlwBV9b1C#L!TUMk2`RCIsyTZzFDN{v1-Zz~>TT7@bal$nqt=aX2L$$&t zI z;M(KXjhUDF`^iQF1JU=__w-#Ug~{$C;^l7Y)I|_+;P($CcgrEia)c_quuUUrDW%a* z$M4^j3IY--hEOV?+Y@&!uXOV)5LY3djEy6VG;Amt)7C8~z;){-F)th^4rM_2Z zD~-l3Td7s+d-?yi?U`DIo48xE&)dGoyWM=gOFqeG;{H}|dncc%6Ga%$GM{m8&)?bG z%x9DVmlx(Mu~LbGn<=IB6hl>SW{%75#hU*LhFEH491kp^2DGt(^O;mHqUZv8IKsG* z(Qw00lD5DlSD;cEQ3)vcnJoh?sVdP{L3CHof30@a7gHF7mDyAp>vwS!rE{fzC@SN?TALS+ynY2_mJM*T{+DIcz5G%1W%s+1!hhn2v`#lyoc;$+4YONp5i%#5~}&gOHRwuiUH|nZHqbaQ>UjwISTRh%$DKn zZl~gOrOp6C-~8+T##Zk?bqQzE+~jkI}!1 z!lcs#x?rthyuILb3^kHcD~fl<2oC%KPESu4K*9^VD;Y2_gY8f@43Q+L>zE9r(Ild= zRo~eXt1Pz!1&34>;SoQ;%I0x8!RpV?d2$qW$9Tmj{eco^M|r*RAa!GDIK6RN`6D?i zTUEQgagnX**yOadQWW#}K|0xF@?nl$=^q)4c4;fWhvylyVwtDeyLWIRGN=3R=2 z?ivZIyo;eJp~f2(>03E(+1}mV*+n_Dk5Wf+MpWP3Cf6-Ky2Fv7&bP>KlWzgHugB?| zuvlB;)vSXUTUJ8U;nQgb-doWNCr~MDuB%Qo|Bc4wjMaxJ)5FOsDjIcE^i=@KsElCn zP3A&_wb|Tl?2vdLB^VlH-qIiwOA+>q1kdiIRVKfxWp;ZMeQ`>aVf3X^VsK)E#{{0< z!$Smrf90La0GM*%Q}Llvnlj(*Mn0Vgj)63i=54t{o)r zymwX~B^$ld?rHz*%*9`W{EUn-4cbz4+&ksy4all7jrSND1nV4#nQvnjmuIUFnC@~u zf2mR`7nI3Lz=W5%Ly4%0f)6$Vj}Zm=))+9D$ADxG0}{Z1Y`&96%{S>``-)=fN(Ncj z6dxETxeeB$ga-RiEi-H#b}w$R7|@!Rt=mQJ^)_H zzU0aQ?ZV`#UL>RuaL+2iLw;ksQS2%;tabs6x1Sx$b`N|_X(eWuu5G3*V<*lV@S`>3 zoQsMW7c=@}D3|4|0vDBC!KP>B5?Zly#Cu?5HctOYs%O$)99OrZ()CO*81M^kutN8< zE4W%(F~Z{XY--#P;hr$f?+L_;ox40sj&fWCuL2x~mMtwjH~w|^M^fIf=U9G$S!7tm zg$MNaJ#7yfAGkG&5Ts;oak-90Oqsz(3{#4l3ltgW{dK4pU$I3m*@NR6%_l_YvUfH{b9m%%=weQA}1=XlAcd2yQXtWp(GS63^{$#kW` zzSlzAFjN9T7b?2KTYPon-0*|!3?$P6RN0jKTkg&iwR)su5gKYLJ&T~fCqDHIWBb5( zzBO#}9gpQg9~d^yu0RI>4q!nUXA`MfrB307)xdhzeDo9PC#_ue_WhOwBw%wu=Qr$u zP4f?A5>_T0X0huTVNxbTnSEgHOqx-+8Kjpc=qRv52@~Q&DmE^oC$k;F9=Kz(BN$Iw zt0>S7o$!ek(#k6;V44|-fb`6dMw2-=E=b2y3DnFV4OW}loJbj3&na&%xs{6df;cc| z&dHfIPfIEd`=B=C$Bn#5V*pig=0Y;#*$4-N#(3q1kO+t_K4I|*16WZU2o5#|v`*WV zt9D~(SF9lAQ4&usjGmo>P{3c;A$bheof1nko?V);c5S3PMcyq3JY4~Vr^vpW3w%*l zV~U+CHivHPUC{n8Wcc_pNJ#pODdXyAN;?dVq?ZQ6PCJiu2E3)+Q*1VCdoudT-e#?? zVsUNm>@{U9s?EmswscUj+1T5&b8N!A|4`FSqR!c~3Y@^nJweFUUCzWC5|LCqCu3rr z+)%s*T|lLv7w{N}8l`wp`xUG?@pj{S;sH)Y;-P!vCh}?Gj+xwo{H$MH-QCro`n>9= z@!)4Zf$ag`I^#5r!Yp%tMkWHx4|M2V)aAvjsaWB>eT#>|=hYiFp}&)d)vUAhJnc!NXXRhZJ!FaneW#vZVcikzsZ4A!+x8M5BV z9M6pOVRXf1@>?Srnx)hgdh=12Yap||kY_cSv*HQz%t~Pt@{<0j4t}XOs`P`4{s861 zLhcWFN$@Xy3fQLb?!*!+f4H`GQS4D$$+zCfp_kZIaYp9Bs+&n`q2?Sk93iZ6!mk1@ z!9-R#SFB-7txI-{eBSqG;0)!4RBeh7Rq?!17sg8G-v#MozMpYF~zQ1&3m9zzvc0De8>)yfT^t?*FwFLecfPIg?ewP^dN`ADo z$BEIt%nAY}WLZCTn}n=clh4F}?wv> z@&3r&R?lDC7P2)x>xPv&9Qw~CwTl>M$IM6Vc>lD1MsxwtuE56{@r8tkY6FVgi9{6a z3idmJGv-YNYrDGx#D%v>#it998m`@`<~WV5rY{CDVjb6SNmJauu)&q6;UE(M#Czl( z=S-&vGLCRoxk8LarE)C3(DXVQBv5iX2Z%lmenf*WCp7%>nBFQK1rK-vpa4JyVx(-q zPWuS?GeB24mK#a+i#!F)GKy{M!Y#P$K_SGzT3v;%-q_B?l#vs!)CdqG~hlE32Ax&%h~X4*4U6^c418D`x>d6Fycruf*#KO`n2 zZt_0y$4lZ|BPPTkp2@!o_B1G9L_O1K!a`YNs5u}mb|qXpCesoC4Tr_s0(MJi6=eKY zJERgua=wgXrPcHEFcKLk#2c_E)uZUkr-aAHl*$TIUCGqU$wj0HZSi=#hsGlgk0_P$ z=sTfGzTd2vkk99*x~9NM*=!y>VcS~(9xCQoVd2O_17y+_?~0j*mtZv256jCu7SrFr zKp1h#$;--Or0Quj(h(x?#OGajV%(<4O5`2I{0d}#{Q%aK48V*}VdJVqhiA;!IJz_X}WdS7ap*%o#@MhPc zGLz+~RSKjE%cM{ycLllR+0)a>7LmHx3%d~lrEf+ z?Uw12TzVEln!fs|dO>G=Vqf^Igb-O8VZ}m1bX4LLPod%IjU;{9VHx)09_z9`5QKBo zpMjnJmJ|l!Dex1JcvAzm4E|1PaQ?&hI-CLVy-sqMzOGr6hohnJfY<7qPLVC&O%KR@ zd8d3~Z!~PX-ElqV0*=mH0GtBj*Y+2@ad9R^RQP_T0h#e*MnR9Oq%c z8EOnYe8W`cVcM_aAW+hPUnT`#&@FJXwid#lv8r=KzSN=7pe?F*%u#itmB5u>L<9-_ zSq7AN(kNTk{Qyp#mKvh%x>nb<#s_X>V?uJ^dd8@`XV^bE_?$F%#tmK;zcZ4eG=hhI z^xgUf`oqKDo?F2`UHYS(GNUJESl*$%DiJC!!roMP+|sxf6rnPDdqjgflo-Zzx#0#Z z-uLNZ18sH=dhpo8$6$W|j{|f+794cRI6n}|+5SQA?rw0Pt+KHh>Z`Fh0H1C72xyH9 zD;tJbMGQMZU0~GloDkH!-ju>hF)HF~)DUqM+qqtdJyimyrp3?`l+w%8I?RYnrIn*s zW`O>qGXJJ1A}nKO0Jo8vVydtzRsurd<}j#)Xj?=zBQCbW1AceM58UAHE84;kR2KwbMZIdgreC}QJvx4{zW!>8r|Z3m{_bK~;ZH0G;2aK@_? zd}zoLvFlZGADXfReVAq)UR%qavzQ!Nn(J$~#0tPlat8obB0B)ElGg!%rNnM(h!ho@ znQ13c=BpqH3>HP+W2uhVu;%4uMJniqT&>88QQQT(v@qq7i+3CYP0Jk4M|eaM5A`!U z`%qUO>h!^pI46g0s}Sv{ryAW9EY8@eMm7bBvoljFsimb-MjA$4t|X)YRw*ByXaECH zC42#y14pskev&PNUbYPS*)kaEWdIw@=^5-U2J%Y5Ku5qF51L(TNPASDjcmm} zgzXT?mIGvh1NuWd@C#d5ImFuGH(Yl^yES$@(z7USK|^;;14cgz7W!d@A=?Li@#?|r z1YSqtHNvlTdw(Ea6Z{IVJz*3*ROoRl+=Ey_IRcsv8>8iw6L@On2XNXvV;AfSVInYBBqKq4%cR3tig!s7B>6!nX$`r|c7aJvR`;&h=4HLZE^O8O%~I z$TA>esk1Z+Yw6)6s4UIGT6%O}iy>JAk0nV^>c(o=fZGC{XmB(%8W^Eb@p8L1Rn=gG z*_ZSC1p;CMBtK+Jl5vw2Kg?BJH!40}qT@qXlm zljj)!1k-*IX&=3A;0-9{FOhN_495eKxKZlQBK0?V`7B<3rB;v0q(sBI?u;K6z+8eq9 zc$nbJ1Q@Q)dZ#>GAGR*`N9*XquLdkZ2mW4^fopO-%eL1$HpA4ROdX2UAx15+MiuMA z;7c!nHQcyZ$LrRs8?0d+IO}z59KZ#6!EPvmI_4X7}|Hia89Zl)m^PR*-X5xqi5inN#)P$Iy{Od2KJGKQUt zF?5jj$T6q$CPcr1rRY=LDRYA50?99`?D!N{Ovajo^kg}aZiFITAg~b@PSRL}6kDoj zEQ`iiGzQWzPL>rtFNi`MSY`BsX4zORhia!sbgS$Zg-Vk&U(#AdXqVy=w6uwMIb_1( zOf8XK6{DavK?U7DL6z@NUjLuo3cE1}W>Xj?hdJ5i^sGe=aKx@`sEoD(!oC3S;$vwT zcNz$5B?Tmt_kes+aJmDg7 z2k-z}3Yx1G*QnwZ}THCp<#cPcHLE zP+fFp%+DKRH+;EBdH2m+>_u7rMVU0kg*NJJ)JlWXJB5sAMNt%I^GKFv%EWvZL`jES zn%Pio>oY9XlR`_Rrs5QZwo_$nJU5S=CY7Y;sEa=31 z)W1j7DMn>hSP&QRF*QrB(3F zx(dEo!?*>DVm%g(P=SjX?NlLt?InwvX~UemVr+NHh%` zt_6%?#$)289&A{$A2#sO1LPll)c1miyE|e}yJf5I4uG>BAT#Ns`WHONkHCXgLTqDW zv>vag@Wi_7u%q?yhiY@X>%jgdn1@jfZhyVQeBx^9Q@zqbTO;IS;fpC>C7v*rat7uB z)D`0Zz}I()J@=gzv$3t?v8l^NAH%T?1SjCpHX^x1I5(9XjDQ@Kk;>hojD)BS)9mFZ-nHhE?(S-MzlP~Kj1XCKNg}HrX(C5D$VMs#$`a&N z=33gAZ@fI$2FiF;wX8!LxcYTynJS$fHAC7;B5wo~k`WNBIJ{jg`xf4A&S(h?XRAo_ zRiso!3XFaVRSZa`$%qjtQ06!V6zeZy;(?K16egx$9l%+9XS${5K zxjqof^%0Fx7!dn=7%PjH(W~y6lnZIr>7(SCB`@@`N`DnA@)6_oCSrU4NNlv+s6STe zuh?`y(#|#|*7;LrIPw}5@3xvdn}+n@`@Ga7!{9G@feG!luP}PzuY%Hkc(ZObD;d$< zvW;4QHU+jAMXg$^;r3atsEDFK+Ugrk)H3#nv{koZ)xWb)Z^Ejv*VWf2HZDvb-#(Ge zLmK#(%GRNkyKe4bI0kY3By*u8YadVLV^Z}pzGHDzk}z+QB`Fqns(OhEVVjQMW<&|^ zAtOb4(LG`ORdy|}658tloM`8G3XZ;NRlIN{W@B3{ZuC7(;lg`2ZP=U2E^Z#{Zsb_- z1~0uE+D%X?J&Om(dBea4>VY5mB z{smH|098P$ze>dlAYoK|HL=CH_X>MOL!X+AhH*wQ2qy;B%HB{lI9)_+$+-Xc0V zJtlR~3mk)utMVISYYL1vpj%-!iHDE{h3v)=AiS4Mhtv~^R(PLA1lt>o`ku2Cg$t4D zLa9)eItoH(c{xo=avCc5lKb9dxuStAS`K8{6Cs6Is<0;udvN~ZgUAok$s?MMfW}bq zdL^0)NwRr%T@37ldfQUM|Lm&Kb`m;(!^TBnyi-g-wi|6OQQ(nPE|mgjwEid%DmO)b zqLH{AlVU}@?#7s_vMXQNxC{$A zfS+|BeasUN6AYmYgm7cbV54=tjj>P@!J2KNx+IdmVS?7u%LH{Kq2l;7%?Ye$FR8g` z*iG^pMFEU(Aa1#34t0PRUUzx`+?xvau?tTVc$zRcEL8%$O<3=hyX#%jwpj0P`1>QR z)VV*F_XDV7I4a}i2A!sQ;(nkjQ@bJ+V*u@=?`!kymaLD+$tE77dh4=t>*2--(wI0H%H9By|u3vhzV3Qo zDYdD4xy&+WP{`k-3jpBMd&u7p9?3ID_p`RhG!00AKhQig>Qf_dO*bC?>gV;wZ?=a{(6_Lw94*a zy*r(|K8iD5I-aF@US_->=|`y z(Z<>2f6j~OyjgsWa`-BbQEBE)Arf93-1O8#gAuxIMc)dQ09lFyXDUrHLVvMiS_QhMYow`uIlQ1GpHG>;s;LXDkwP z*+s7QtQ#yi6U`*OJ0>rp(-||Yg|=Puy`8I%SE(1k5K|B_v+g9jRLra=m4a+4^0y<$ zvn?_|+}hpR+Frsji|~{{{yJz{`qj@&^h%m1(n}=uq447vj`YJrG%lpHepuj(LzVQE1jxQ_45ar zBs)FSWujP>y1+Cv?4-A=>MVbfZorUa1KZ>ht+no~FMTtuTB*327kaqF%V&;cbjVDty_nv2gU+QL2|CX!x;)P*GgGtr-dh))GBr+T z!CE_?3Ry6@0IKaa(eZ+I9MsF`PFK?%IPF1(M!mj;9tqGR`EG7rJBIJ(IUm1moSRYg z_quheCzm2P9B0@E<}88p0%VgLI9lTU%RAV+iL`2gKlH0X475?M7ANeJ1l2a#M7aD|P~>ru}BcwicrX zcq0V0^a;UPYMQ+TQ(>b4o!+W7>gcaWSvXG_&dP%}#}AQIL1GdT<>a=Q7=shgbT46t zZ7gd6GFsRI7YYsb)q>81&oll=2)46{s1VH*P2j{YFhawJyJ(t-&u)`};YgrN0V~}! zb28|ZvdeICG+4SB4#EU|M_Q@jWG}Syfj>fYv4^9a^)i;)?OQ>&;UgZR1j*-9@|8fH zyKg)nq;~D>xJu~V-`Uu>zP_$rH>**6v4QapHg5Xqa8M$Bh`_x~t}dK{oQ+zowgKNt zjIuj1yTO}5XJMuI6*5ECf-Jusy~S+18+t>ctYNaSY5KZ>4x|ZbmN%sba1&Q>{L3pz z2k!1j0Y8-d0eqkhTB~o*q-Q7?liW->R*Fe*rW`AsTCs~Bx}YmJ+K;eB+7!n=y6t~) za%7>r@QTOi4BJNge5m4VDkKAx^EpPS0J8UjD*Xs#O*ek38?K<`KrgLuneY}~nC=LC zO{0f7gGnQ{VXs z`z%%hf6spUBA#xH0SPKUGoXd%ij2XqTeG`2Miv<*L=>cidV%-Dyy-6;uTbEl)ilUE zqSD7;;zrP?8$q;aJnfwcA46R5I1wB$&d*Umcz%wi7(`x5Dg_;Ip#S!q0|Lyz zM%&KQ0Rcu@p-AW?EE_o+Aar0?pbUvUJ8ZP5oeJOnl9!p0;N3UW^e_+qr){9tG1xX>xMR8&>B6nRtZ ze1)Pqvg^3JGlx!2dVPCgdp$v>=TB~mX6tk3+^N&$xmVc)*`f%K1xAzFNJg!LbXur_ zR_rfi5mVno=b=38zUT*o?qc>@bOGpo0$clY@;qj7qq{(i&2NiUVi#5gHRLGkgMFE$ z!!zZd<$S&_QH3;B5~qQFUa5MNH(N3Ypeu~rG@5%lpa!k%1W8_sVKmxSMz>rKQdo@M z4kFkg@UQS@#+gSUH%K!wp;eOAKv6uX$aK!YMVeKL&0m?o-%jDwVi@75zOjy6!1At9 zgaYY`#>Tp_4tZm6`{hV1&M_Nji!(tz5}$m@x2acSXK+e(+(wlnRV94N>Jfv48ax}p zLSQiK7SN&EgoC9804nbG;1v6fnzLgCuyIcLOgn#9_j+(x65tSSSyB6e0^V1odBdF6 z%J8&YhR*S+&4$Y9M!VyTv<-x$5!&sBpd+n?$8SZ9 zgBSn@n{I%A`fg8EHB|fUfDHgj*-ZL)^>N`UZvt>iOc3;a`M!ENE*s1h;AI^6c z+IwBG3A<)PmS*EPXNTJF>hb;s^zj&_0_X14>G7FZM8^m2B|zZPJ%&R>Yt=e*C#RP< zi{tLkj?`b}O(X?+ zVAGZ@CtLYf!MY8Wdx5MK&c|pcNfekog=-BW#9cSV@ZQ?&(o>ojup)5oLYsNvpY!OV>Z`pWWRJFb)Q~+JV1{jzA+ZHA3aF_8B%HS~yqNre1!2 z=qavk!;-#S#!EpxkeGserDrT#i4`<^M839Fsd#WYZrN~9B5&yEP-ty!^ItIrm&0DD z-Tp(A1Vk~Ai-`;|Sbpn^foenD@d7hqG8Q&MlBI_73L18|Ir-+3YdOqVV`nw3tcFv5 zcLxOK&=l6>K#{paHDorD+mDIc&+T@2Yr-&Myx#B(W`Atwxw{A`iQs8{_=^fTel>|= z)XSgV&#)_8&RIR1qQU*NU8y_#AZ_C>kl&i~&U@N zMW$k3-g9)32Z-5ml*>Hd|D(*$xc28`n58uAs0$@AKz$4eM zkEZ+$j>ymCecFQ19R^PzRzMbjP+YvlC>%3e4`u72>S8_zDo4*PMD3A5)%wDD>lEI* zstg~TcaC~~>AbN~$4_1${i$yRT7^bd#$3!;6wcXQ72}@>eU!7U`kJZEcfwIEghmUW zaxE0-cNT#1$6^3JcYYV*cZoYFEpT58iEM@_C8`X=9FmJ6A{?63_sno zO_^m(&$9o#PpN`0Sg3O~swGw`IVK(8{6Qau1P67$`I}=Eo}m8e{6tbqbAg)e8!e`4 zz(E-D`1Q%r+Z>2^cn^%SA|`}*{A3Vi6)pl$@HhbRbOD5T?C@|NM!Ew=lb#wb9=VT$ z&L9Xcq+d+q^kT>htr>4+Jes+6r7m*M%#x@^(D`%_jgy59<&H@N#n~LaAWl;1iP^%q zuoKYFFQyQ5)&i||U{F|nD@p;k%nw2~uOtKr%sgu&DX~eeWgOs@l8qtq7J30FZoZX@ zpl{|^++Tc-Q3=1IABrX|7Lv|(1v(<7quiHzEg9Fq2iZs#=#>En#r>R0(u!osPylN! zxVX=u+k!wSW|TVK%LltKzI07O|8OT!6e1TV?>P%p+th_x`j|20Fgsijr6nj%7lN?- zko)=Y1=$K|QIJf5a>XllRJd5on-bp1*X|FZkYnW*28>MSnl$1j7hM+^w8b_O#S6^g`b*%!74B7z+Mgx))ITjX~jo5ib@jB@biW}QjK&qu89g0;u<4$M5;b>kJ zVXH7I2%=+`1Hl*oiz6OvCtr|4nPU7&G;|oDx{df^hSuhXiE(qHFBm|CAmE9)a+U;UnWun9RIrRwCL)z3_=66X`6U5R&{&kUI~ zhjT`1I6Ppn7bM)_5gSC;$g_;)#iYXr@@moHUA24i5hMEG@CzKy7*_5T+W7GaYIZ98 zbNHq3kHX&ryeQm!?Ovth=R#dXXwbn#HS~%3UF+?Zr%~EO#TB!c47cb-;~b zL8ZJatUg=9EJQ?-xx3q43l~a}iEv{aTOsEX{LqYEajqY_acLssxj_r)0R<+`RbpN$ zQw`Hz5W?rlZQy#-S?%H{1hh?suGvgL+nlbMp z$O?kj(xENQBG?KSbLfj0{m^g<*oYoO@h>_frU%%9>DrzWC2xM0fZ8CCzR$+?6yaIho)fj^Fd=tG zoB;>L_<;ZTQ946Za2mMiKwYV6KCHeQ5?8=ZbG2)Ae*8d>$>RLexNGrk^{}I zt$Zl<+`(!043In0;h9lt9%pmclXDlSx$B9!Q}`o;HcOCVz0j++4||De+_p+y0BgFT zY+oH%*c`!O!8KPeiyWh9mGYiM6XynaCr7kPE7Hmv8??;J5vO@NM?Gm zoKQC?KC+SZ3)LrO%B7M6Xz7eid0x(6(Re13yXf&n*5hArbx@!q!+rz4zksbA&f?u; z3g{}sT^ALcP8q3jKBNw8dUgy7V)4d{j2z~4rKYnAvQvh-kq>u3s_~wEi;gIbtNFf= za{VI}dkf;BWsZr_E9mnU$Ix{dQE8!9h0H4qFoKim|mVKO!-wNyj5L!1!q*x7cSaUPrSVE^zuLSk9!%MW<+eg zFGlf;_%<-VB|azn3h}9He0s_A-$ur_H(>%K;{8|{Nv0j+Q`Ym?Nd3sk$U}S>vSc#s zL=x`D^6f>_y`7Ut>?=2OQ^RS}O6F_hrgS8~|NZ zZKz)SI*|$IGC?+Ys427b!v=)8v5vOmI zf0oKCWlpuMlvA@dtUsKqA9#P(;a_0WTU5CjXaX8|G2g&SIh23n*#?8T20dsHcA@!( zD8v9K|6CXbG=$y)@|Dq%Ksjm&s|@WneVj!f^WCt*(P*ZU!bvTG=dL@3=f3GoDB7>( zeb|N^gR)-n72(kXec6h$yWqfdOLh@j)!n&?N;9Xv{R5BmqqV=L?z&$YtoQ5#Z*5IV z4@T&5i*+cH-q4j^T$mZlV2I|X*=wKlh=udI)C(;u7Tyj$^lfJi%l(QqS|61=>mA$P zuo~+Z>sJ^Ip@HhglZ`73>a}sv(p|c))TujG4iS0z8oDV*2G3pF&XD;TK!`r!FNR0Q z35T(b4tmh&%*6BZ`MN&`BS;)bcjUzjpa85>LYG-&Ar1XGbn)HQRlg+;{bA<%FCjbR z%<*4>#>l)pzz7@V9viv!fB6`7y`5CX&bUI+x56b5CRE2XjV)~xTe>uszLOz>%2w$D z@bB(s(kJywAJXlaS&`KM3x_5J`zY({xSbyYSX-=f5Vg$-66-Le397@>NPv@91`4nh zoZrPc^-OeUXQFRAojk_O)I#XcIdEf9ax{k##*B>ZdE7822tJFOUO&B$);)#LmrH#~ zu&yM*g7*r%el9I%>W<=Y-yNI2=^ij05q> zZ#K)byrmDuMimaXaQpDx7`BXo8&v|@L_Cb7w>}24?UN5UpmW{*D;+iueSojSV)E=t zZylCb0Hn6dPC0BhW0u0Nf0m2?Q($65AunMYtDuKQD{6ZV)V6V9CF@CfyiS_nK2+9o zEB<(@Yb&)G4uZtT+S zt`94n^*+0Ct@HgFDuLJS^$TkR2i@cK> zE?(c$$FltROnfZMk8j!VWK<^G7GC|^R`Bk0-yk`Ar}cX4oDxw4b0;Dup6 z`W94kxjuwHD8`3P)52Z)lHITqw));?qk}851C}L5P~rqqp~Ok9#0c`=u=lp$Xb3Pb z*c+I|8}<%>_yPWYguj0RFn@%9zq?WK@BkH`yT4PTal0HBXL2rxZxKlM$?aG@>#{P! zvgHMO9q4NM6Z_u%gwT49(7+ykagVL%8#tKXA;&9vyA*FN>(2_1#V_{3RonWq?!IpW zQq|dqvipU7thirn$NJN)!MHxU)=l|@m?rB-Eb@wqywXKpmfctEUB!I`MSg@LFWq;# z2$A_;U7UxPHv8Gd#^K=?7vcQTW`DWZxsSwSep0>u%zmR1?`-xHm4JtTQi%^Xv<@wcr|Uc}^KhL9z%yRZdrI#ik^~;p=KwzoR+2~Vg@x6v<4+l@TgM-}^%`dG z6SGDY9zj*ytDqvo_agC9C8D2;>GVf{>GufN7w%h&27)8HWZwhI0l|1{$#JP9jj%7O z{!RHs6-Wbv#|bk2=MZcrZ4xw>o&KD?n1Z}7vL*%~kvKZ#aVPF*_RRhv31p#Z?jcjF~{N12>_7Fz9p z0-RqfSR+gkwj)+~tzfN@NhRXVV0aI-Ul&08^;4kz`ccpxJptMUz<#|Hu+3&avJX&^ zqrrj;ZYqv28s3nT)+p&*2_XXcc9c7w*lpOjTq;Q;OzpSZ$Cy2l86QDgODx)j@YKD4 zFaptxpiWpM!s$hnk3m>r%!2x=Xr4f2i63t5q!XSGqRT zm3k5!kEk?yu+m6OUWlqq%erpOL6|E?tvS0eb!1dE^PKHhP6YWTce;7EFa+&~g)wA5 zYA*C0aG@WF3tctY(3fcCkYhh1%kVoe0G2<>%zjtvreAjqn&Sq*5F&S|jELPH8ThVR z$$oEb4NlKwE6frMoGe{WTToHgZhJ(Ev=*7q<^kg@~v^RFygnUri8JS4E{ER!X-u%dS)|jnmaU z#x_+HP(_bHdwospin(y8Hdpj3&N+eoGl!2far$8N0nkxkr<~FVuyg)!G?t1qA}TG$ z%*uT53;{#gg*4~wpv+P|8hGoGyCOJpNW2wB&TfZPp~#hlHQ4X0{eSGe347bNvOoM) z61_P&q(#YEEH83cKiQKeY0_qC6CYpyDG8DoOQb?lc9huP{hb*AB!(hnr|r4hbGujs z1_ZIpZ!p+q?uO2k&O}K&J?Qk6sPK)sJN9QZoQpv5uToW1NX}Krszt%pJPDv_)@UD& zegeQW8Y4GV{60Azop|T)$35il;>YOu>WaM2;vH-N$CQc(Z(uOeL7iK61gMd5eSE{i zxsQ&(cR&Y*IxR}t!J+^Y^Gl#ofmG4_ip*H~u0dZWxl&~5+V0jg=5D@ig)ikh91~n0 zwM{>~m4CkFO!R8xx^1GdKR8~X{gRXfaG~D(gu5Zrx<4*Po7;YNw2)RZDjn8j&fr*_ zcmuSadIe~tSE9Rj*WW3+k$h32`^gO7A)8f0ANXR@7;UZGZ9Gt<%8LHY-I+hHJ5=bU zkHtQLavqJhhW(aXU%{7`C;oT3LlDEGM`ybGsX8h<_KFDr-7%0Fb{|FvrEK@luk>2# zpisQzsolR*`NHO)^L00#n+eUQTI0ejZYnl~9&xm0^`jG^XO3K@h zO@xALGex8E%nkGRT=D6bPobWoNcLM-o>EsV2~g~Kxi++(h_n~XMrlBOb|E~^=kl_Z zABe#4-Mj64|C6$C)jd=_+hS`XMtRzeB5)jnF^Dm;Tw#{x!WKjsxvntR9EK&KVKf^A zK#R&>Q!OF%{KWoZQt_hx=JTp`JmcMP{oRlHqpz#h>Wp`Tig(+8Cs(~NhvZ}Qg_F6( zi2~8kJK?xdkrihNgnM%J?1qw*K5EV}Hwe`tt(+omlC3hWF%_+pvgNcY-zw2)CRNi; zv&LRShvg2xtF3Z=kXm2S9P*CXp=lGu+=-{7-X*U=#r-w9fmh{j#{UBF{RFuE1pxb| zV!caQ)&foHgR)y&=$uP_Cn6<(0z8JU`&?e4^;@}5DxARMN~}Ys$(A0fmwZJWGOS8E zt4xZcF<+2h))yot^QV3=!Yg&L3#OB>prI86@7TZ z{Vw!qO_xJOlO0?{7YkWE!Cesa!5Gpj%o@v$GXm~)qIyUhD(V$(d8NonUbcE6Gm7Pd zei>&9FC4s!15EvbOh6vyUk-3rHo(o(weQDBigB+NITQZC(-NPSn7m|>MYZi8&d)Bh z#bQu?b(zT(J@5iv3quk=sx4g6wcrpYGD&bzl1_35t2n!uZLf@qM_vo7thd-8=$+yz zKM~w8vmP{UkzJ#^6?qNnMWu~3D#DP+h^dM&gKJr01W(UHJhw(g1PkWb8M?8y3=$i4 zZEtrWRqA)PL@e)NFK^gJBBd29d`}eHl&nsP><1NU@e(RxMfuP(>p^S3-EAGTd!2*M zey`(+S$;~*S#7sl?sgvB+oA|hjEf|v7_%j2o*4O!e3;U)vZB+QRdh=Xv7%zUMNV5s zThWI4hNg+&_F-_ZC+%}eE03pJ!FCT2n-?fX*ye?fk%d)OOXQD~b#c0tG?rVTx7k;%>BS2gEMYYJ5@{;b(u3{iqxQ#b6w^PnIbi{wEtuOSilzoPe9s*C#Ig5d*alz ztWlV9ojD@JIo8bC-Eq}o4Zod8cR%R-GpJXQpD6XJdf~2#eFxIddLY3|+}taiT)Sf6KmMLRwn#gG1;igg994>%zI z@r-j_(2a!ct|wzw6tj{sGKEZ;$E;KgOS2=>!1QT*SEt&Msp=8LncBj;jl1XKRcZU2 z(i`;Gn_s_Qe*HCn{pIG@AC_N#$zOkNPL>9ENzu;>sg{Zc=m$9CmSO(=Yi(cGFG(4v z)ZuOK`ZYPVI<~$h*6jmJ8HP!|w(~1Wu3X#dRIg&KC%^i?g+G(jVWh5C`6Z{fr8~Kv zUm`-F>G+k7M^Ns%`O2d1HCjwu;}fsANa3xqjBy7IHI3KR%q-4wwuQ$ZV$ZJ~{m|79 zI~AO(9(3ZBPQ2Rrt4!Ul?mS&O-2ffev+`h7PnNRF^8=}=>q~-DXP?KfFy6IrfPS^e zrDNt&#IHIPxmb$al|@#oJ(hYis%Fqtw~D%>sXM5h{;e%@&>x&`3*8XL&Gn)wu3eb_Dy>@8b2W3NB5<2f&U_#F zg`P@w)pW?5UXX@$lOfQeC#hk-j#Us zUo1y+O{h}u`HNc4X2skX?YRhn9<}KE|EIurDr9AQql!_;;9qVggG=3GYCn}yS#_eJ zA!(uT+f9T52?2yl%Mb#Yh*C(nSq_+o#l+_u0`BvF=49e)@5g2p>Y?}VonEXd(my)A z;5h!_?5b4%8!Pt})SjmH{(jZpuE|&9vbx2&dhgy~LeMMT=;h!2uS4>a8zcGiUqrXl4fI`Y+J=>JouJ;;&jCHOJEuWiJ#=vDV$k!PbON*_=sO8+9$^b_W`|~j8#~Ts15@-OzHp+gsGe*k zCbzlnm9=&MJM2*uvi<#9p^ErObQ!12XTMA@e@}Rhjqujbz^M|EGKX z*H2jg`wNc$nG@vyl>+6(4+xas4T19UuL_h8n~!&WDX#&1;K#ezZ4`BR*dYH=G2fRH zZuGp{kn?|-)5@JGxsSE&B$t;V+E{J0@HoE{HPq=jC%n8&G$F;Aa9EGG5`3c`>QnR% zlqqoQ@HckV-6VDkI&i)GId;8fZz~UyYpRw}{GZLUutwo?Cj>`McZ(N3!i7FSjFHQ) z>y6M-iyket=+Rb-9&M^t1FFf8?R z+|K4)x@F#I^VfIE^cJW0HfO(^UuD939>y*4bTR7mA>L@u%bA zbq?C<#8E(rDpvR9!hrFjAHX5p!4!s;w zsa(uhzMoNLDGvurQI{FwJ&mHCR6$)Om4`Mt7J7kULP;Eyd#}fPZ-0{}k})@dd*!U~ zT@XV>l1x-3X_+aqsuXQAMKSI=Va_h@Pi@!mmqxy;2yMrB;^74FrmZs^2KPd`iy&Q2 z#VSz%i6UtKh`g0VZhRb_00Y&1dH}8pQ&4D}L`J(uiHz>62%~)Dh(wnq%S#BkOU4Cd z8#)>L+KsTEvRupW!uAEg<#c-V#zT-0AV+#2@>|Ew7I3 zzc}$m-ogvr6K~u^(+obw9Zs8PV&#vn)VH8lGH2%IpPU`X*hSJSpC9B+=AaP+FF)cQ zVlIE(aGts;nW3+AI_e&ljXwN^yMQ6x1q_?ywem+z^JIzLFpVm;kfqM(8|1j-M~~BI zQD0yd5oBSoU0eV!F@V=%o(c(hEdo{Rq<~ypFiz-8oF#;_uug}OpmPC5Ff8MCKuFj$ zQx!?J{qRbO0K*<}mKJ48S=mZOLm&Xdqfrqh8gv<##A!=cG9dafGQ|Ou8Y_K_=cP`L zmnSY1rIEn1F1z? zki$0j1(~OnZkW*bQbfL&Qf%e;1jY;9%JLBkg%41sM!MapYS>}5v_)euiH}83`P)~FT7^`xFym7`22O?n1lTl=ga|&5ZsjH^S z>4P_*45lY1hoidh4Du}81_p}Pua<#PwXlr~GX-eH!kJPbCG$PmVhucfnmZYNT zW~RLe^fj7|3y*?0N^CNnb1Y68$ZV$f&}__x7GO}&k`z;Du^m9%b_;nHTGYj>`$7#_ zUa zRopO-(4a741z+B}R%33nA4D9+j&d8@5@Ts#VO2 zT^G8!+5T^Ic3bJVt$*)PL-WcIKWg}^dDJj#c`#395$=E02B4fML#vRZV&nu`0&@-b zO_!Hh9)g;E|8Ko>=jo=_EeyljAI0*M3v#Z!++FUQ(i?yN9C@ClkDipFVOs_wUJpKt zA#@y+1*cL5SX@_bc=#o(8cAdV)0sAU4)sLGgxm&qU*%;zdb`q<*9L*I!9!OW9+dyh z{bf}zqChTmsXIWs5>VORf3AGt2mSx#fqpv9Pb%28;K0-UsE^qolGD8oIo`D7f=d$Q zYk-We=hp~)TCBlQbQf;{7m6J!nSqDO-KM@k-4`c|q54H7Scc^fV{nZoUxD<`SQ-i32?o{meBd+t@S(zYmU0L?Bhohh2Op734hkekO6lXcgr!OIF{{ zox<%svc#!FhRKb|@HlspK_PkFkF)7RG9ikhi)WG ze&hr{MY2XT^;OTVC;SLaa>$C{3`IYCkYx$7lka`+Y;Z>dLxJ zb{NCQVt+UjL8AF3M#~+zAZv(wpy$Dup} z@b=f=-gN*m9T1y4AU4S%VIh5{#WI2eFs4_;S6nJ_>+NmfZg;K>No7sjD5o7*(ss5e zH9DHAn_Dw;V|wTrmrhBc#1-Mr30*lw^J+dSnBE+IAadfTjnF&ymyN(%`ID_l{e0^j z)!x;;k*oY8&*F(Q-;Ukwp%+ywXdj0#98SCd{+@fvc`KH6xFxm{_vES=OD~M$7BDoP z`p$f7-iWv2`WP)tL+#?N+17>YJD?XI&oe>f4ub=>5tvU z+x1GQWw$Nd$C)~B5!mszgCE;+qOAc`Bdfo48w()0`A%Lvr5dMH<7j)TQk`5C2L(pU zgoZX8dogozoi+gm>-5^K12iBGyw+_U^w2UmaNtf01~%^k6YT6Abg_BhvAd74kKvKj z0^?x8+x4O7ar41mzHI25K=+EliMdT^B32zVEg8}21vPGAmS?^L+C%e`>(uDQnpYFi z2>uRH3z)$}h{7*fF0vZB288+6I~ZVIfe3sJaJdhY`VwV)a;6_N@dpk41uF>9ucx~UBh;fOK+}XU{?MBV8B#~v<(cTeyW&1{ishN# zqzZ|}Z&KQy-f=IxSsdS*LHyyZU{womi)aW_q z#whfuvn0jU;d?%48KAf~RM_Yk^oJlXiAYxgM!UgO>Xo+KwRGfO>k#=ZbaBsRZaQU(tD*NN0c}%H!sTC(bX7E#=~eSu3*$uBJ}m$yXx`YL(f|A zqIr`e1HAoeoUOIDY9cJt70gtsTddk^3TeqA7*0)SK2giwt~nAt;Kx_;#hD6kNdlKN zU`mi}Mbdxwd%wNk+Sb0dpZVXZTsW5e(QkQq;3EWJK7)fGXb5NG0;wsq3nXjHhmZZX zF-N~sG34W60DYj)v<54-1QaME{E2Np2H5zq>p4qM(LhH5jS~610imUrz~mIIQ97xS zfjY5E8ARKD>LvJR34cJ%*-Gv~Z82-Vfeq8h&;ZL47^?vvG3y(e^$m1=3#aC^O1|}8 z)jy917-OVtj952DdR6jeAS+&r;z-ndJoxdfkB2gy#2>{&Ivt|68XnIChMd}?=O1dg z0G!kHgGvElDM)fL>_bQvMS*))GttcSEC}Xo!Vj7gkv)v(i)AK8Z!v*GM!`XBJe-EJ z5uW!$Jh_MaCoB-iFI=L_U%KPe9W<~^CfA)k4<;+kbTJE|3SP~1 zaRySSSxKEHCGfXPe|P9_@5B^IPt6l)>Vyn5R16IjTN>(@w@z)EWsCmy_Ql0T^P<~~ zlgW0c)oN|0=MyLbXhAOeT@l&+3}%!AsJ~ewkJc#SqP3a>km68r+(k~~SvbP|AJ;v) z<4`r{0c7&kZ3bxH8jY92|08s_0RNBO{xj1TgaUza_Bdpw=GAc^+%5uXQ?K0u$x^#A zwIkE5JDz?Ap@t`R;V003-eb8=Udy=`+FcGm@+U(7Z9-?26=dw2p3$(53QNzD6*%d~EGoDskyk%UsIg zSz+Bjk=&0>^!4gMXB1#YC?51zfjQNK3u<(nmov>fDUzL(s?x!%F7Kqa{8XDhMP4q~ zzEY3s@QHd-$Ncp?wK%U=OeJ9^7vgD*d?qPq!3BO`au_&Svk;S>5%`G1WkHEd3YjX7 z;Z@m9KvWMz05z&fZHhxL{ZjN2qe+r_>H$BYVj>+wNkIva%Sql!{sQ<<%R#d^UbR*zIwN6_~XLgk(fYRdLMxF6nYN{ zF8z<5&?9HByT8A0OxZs%1?RBb1(Fi_Z}hlMMJCOalpgG25EoF@Vi8#`@#jinOee8o zoWLZ<@rjc-J5QQ{r1aXC$W$Ezdy^f(Z18jbi3!G6r5~wh`@(XG=CM=)Ilm|LPQ0en| zrf_oxr0O0TI*~d8QFaGmT#SIa0d9dx?;T`z!X-It}fn1-OKw|94TcDj2# zFZi+y`n$beS3b^zB#cCVA4GF+cgG99Efbl=P8$*rL^#2B+wFtSZp#~l=@mB97tho!-H2r`z_1!ANA3#cpSJx7XSChSMO)60uBWfxEp9M8(4x2i1PN zySIO^vj>tePJ$U0VrQqb*TG;kp2Zg;k$LqF+6Vh>icZ7X8I`sNxp~7RoTo9A3Eu0r zTaeKzh*VRJg5*rLZufu!MCqdr>j7r~ zw`hz2CmcYdfrJ!krn;)L+uh&kfFK`E(=ebCwGV(LCP5gbgE)ziVSv{FACqaEW;(BK zdl!;=$Qk$&1R!UFPjT-Z*4^LRY2osJ7)03H?e0!*zt`EJs7Xw%*zH1!^Eg>i-JyUjPqANb zZy$=>@@By~%z;G$G3{;#IYY-l%cfI$uiJ&@o&^_?Ed4(4^1Rt4nEii(B)C(RJzf6`#Za;j2aOT3Ek0Aks1=6_D*O2Kz&v-CPcKlJL)S1B=+{Z zAbGniT9l(RA!e#spb!8p8J|}Zx~IL5k#m$`o&6R)Dt-Z0!mh;QG!ZpPZx;li78^Os zg0PRFN+>&bTl?NzjKbyI7zKc7_PU*pA}HweR8UKiPN$8Wtzs9;WHA!}T#(T)=E%sr zmAVIe`@jo2Iu{-Lt^K_{Xgw9bfUi&F8@oGg;0PIC2#Oux&2CGlm%>8wbZgXoV~}J) zx9!ZdZQC<#RcqRwwryL}wry+LwvDN_ZFjY8>-G0^@4NRtM7%%Wji{(xC)YkZ^F&6T zI$3AuUZ&NZP@4#1@<6qzFJI_FBbk+a_c{EXR$h39h^6X3H`BQz_p0t}Gm7_$_d6nX zeCI&o9c-0aTHl1|3KG}D#SZlSs=p)z8w%1vBI8Fzqip|shmK1D%;{cSS>6QGR|z#j zw*KOZQv?c-;yCQ#FI#mkhWp}MrTbTD0vV%oeS=U*SyYk5kK^o1rjgRLjP>mVxR=1R zD9f4SgTS04i91Tgw~}SSZ=d3c2Xt~5+O&g)Wi+pF!@_mKZnf=52Ai`>OV-W4A(-`h z_=ATN6E;{n(F~#zLp{y!KFs6E_on5fhz6I+ld+8N=Y4J#_N)R3X zOjT@e!U_pv#f~x&qzu@AU_Eu?6cu>`3cpkOz2TZz*FT5di2jK;_sVCiIT5&=8^9!arlW z;J>J|@&QCzb=DVc8}#Qvgkf-0zhAW7i`sikW$tHXUtCr@B_G#YSN-Br35maDU6^Fe zp0AIuc|17NUjZ%K-@MXhe{?PTsp{2)6yH~QuM|T;y|4A-eRO86ZZheZyUZ=#-z~Cv zXZh&viP5aNLQBI(h)&(bnb!V%EcWn+7;vm_bc~(GELs;u(17GJ$)N!|ezU*gRSEDR z`?YcSyn2GaXuaJUPjH<5rd)S zq@$z?En)83PG_)G*jZEKB)Ff$^6irn+DamX<&tIrNZFK6D5rk9s!*}Y!>{f=TK0P{ zvLCvY^g6>B<$dEsRQ)@??ZXBxluG;VXh<}WbQBCHLgkHnMN8a|#|<5865^{uVx3|D zs|gJvpKrzc3+3?!)r!Qx1d6sq$BTw&%Sv`{^J`Nb+>(?M9Z<=>p!t;-Ny;QmXTYA= z9oqqe(ZYG>{keQ)PzLwZ7IEsP35Oup*?Ro%T3AZH5%mrtfy?X9{JFM@PWUAGwzPC^}X$)9oD3XDq32c4s`08LR#W4rU*b9EoC=u&J%%;Cn3EeQ8r@ zRoaM$KW=YKlJ2hj^Tw5>q#jrm_{;(~W?a5qE0#kEcSyjVfqxI&MnnJ>I8n8wv}m@! zi4Rbk=~Gs^@N=_~dVW(jS=HUJypJX>_b&E(8qj>FAF7+v1x20ib>7RD6P+{_ty|~U zwlp{6{R(_(6?Sb=C*`L76=+V6GNVO0#wHnf;EtgZ(d*IPqI-~2`iHKzbM-jFqa_Fn z$N*o=Iqb&|_BPb;jO@R`bnV%2&ZlMtqxHBsW4Xde$=;@!x3Lb3TiXuNdd}+HJmt?2 zNXoCHt@wkobWoFI<it~JHml*S6Y<-h@HqkqU9ip-D7A?YM8AhQv{I^K=xY^iAf z&XILYoxZ7aN_3le)#uUrLFc4IC+0b>eDs*ysbY|iS=q!h)VL#3+Bhe`Z$#l(+qgcl z8)v7kRx(GIJ;B=~M5Zh{eJ)pjoIT4fIUspRx=PPcGoP$;X65_zjxe0f9R zfz`{-3WhbBwNqbD)r|-J4z)WPHi^$$Wo*$lxCYW+*;K$iAGa515HIM+0P^?hSE+~v zkHJ)GY?v#%cO}oWh}INY$w+>#lZdbsS-NM?+H3$Sx2_*OIDq4(PZOzGhxFow7)Sw~ z%AqnRvdbndyu{GFebQeTmzx#2yJ2=bXEC9A=}{mc|~hh;eX8J;z@kgnSDLbTpR z)nBWQ(92Rkc{WOk=-b9Ik!JGi2+EGHyGFgKG*hU=m?LiSWa4pi1JvuK!8sh z)RkDCj5)4bxwV`8!oprI*slgaFe-(+Fq-~)wa%(3f>Sn*kURnBi5L>}pb){VSt z*o2>%*xe#DN{l=FwrhwJ_sprk{(gz@`w9+OVg};R!Gi!foVlL4M%ho$TpdB886AaO z>u*6_3zVBOL7X(MC~ph8qmCUgc6fZ=h9J^kb%@-TjdLm(<;i5FK0{ymxV;nj2r(D3 z1(~}Nx1t>K z`9MfC`61K>qm)eu=`DdYhp4J1pE|KMiRTs|xpvhYgLjuec2M$BEl=PwEvA`rtLSoP z!Zl;g;Dxt;vUy8b-!dz;W6X^1NIGRUUd+De?%mAlX@kuAyL7i7kAYf-W7B-XpVdQV zVZM)@%$G_O*R1;bF;Hq(?qEpqJI*_gFrJ*t^*kOk90ZOWHpc@pohijNd|d;7U?efp zBDmx6F$XVa51$j?Y4PBldt`7eciZVSmp#hzr*^HY5xKPEOuiHJR#+&wDvhWyu^87HF|iaH&hy`INNP!e=O&iXmoV z$Ifwd#?Y&{trOa!w7bvPJ-@)^qUaKh5W#qy6oI&RJwsMJ1nfUAIhS zH1l)rUO_OBg4DL~LK@B4w}f;(IarH%z9t?KWVHp*QlCk2#nEoZnLYGZyIRp-B`W9Q zcCA&+AK`235>?UYJkDY1Zb7tl<>z^yNAMXDo*ojc+&7Me6$baZ{$;5I6Y2QT#y)A* ziN$8z(HoPGTRe03Yp&usHQVO=lI@O4oSnNLnhZG!&^PR^k9n(x% z=qm@yf+-iHIKUePPZ zzm(Z$HLmm>3+SG4Zl8aUuHK8q+MNt#z;#)ixu%P{ArYz zZG7)6w|M{=mjpA7SF>3J*;^jjp|hP`hLt#^;QsoJpkv%Fc;5QV1)&ljVXJMk9Nu7x zEhK;nirgf8wyRCc@hO_}PJ?IeL6j_Wr4dnxIS*t1-U6(_*AqWIxmg2+nc2v))hlHpB7&B`5jjrI&oG3M0$b=wtx_(3_ z88Wj3CAN9j_OlwLy?RzbyW;$NS zJ_@uOf%OX?{YTP5v)|2xNSy<$fH3sRbb6H*<)Y*o9;rSX=A5|s@N#&} z*q%O%vva{nEFF1!z!z?Q2_+9dlAjB4Sz{MCM*P$AaD z0eYPHZyx;>2iH!vj~qHaDhxm?^;K}Nce}#KH2=uui&JOm0Nk0L$}mC$y8I(H*c@~9 zFBJFz`reWu481v}hq3f$yI4Bhfmj=xUtRZFa9_Umm9U%AZ&f&Pw6O=Ui_zoKauK5B zC3nS(l&0XiymyjRBF{NWA>b0x5zyVRddIEZ4a8=2-x6{@^1rx}*`B`b$0Dj@8Vlg0 zaMb5HJ3s!_y<{{(#D~VnSmCzQ_~$IJwtmeJQZk3 zBKea`2ejQqdIfsnr_bMQk>NP-AL(q*W$(H+wl?su@p3TykFLJ7AI7odVG_71+HMn; zmAfknGxE^E*|M~G8Rkn6j>?Y~jMeGS}#_UC+5aqYKjHh`7?r*%M{_>qg zI3Y@&%&6vj2i}D^4Es1%l6ZLR{CaV(FLFmjlK5qjs4yW2J?s6PFCEhvbn<1N)k|G! zHsy(x$5?Ub)XG`_jk#=ia)Do7#w)(B(cP+aYo-OA<2Hr3y)$hEN23hS@M>7z&MoY7 zsbUXPDQk&QDP;P+x&tI-w{MaED8$B?$Nfbok zVVF?@Os(uzBqr68Z)N3G&yF{=d`zZKM*O6$)3kg~x$55YFKx?-m0cQ@M4!LY?~qTy z<v4Zqv}6KXDj3*9wwg8WCHPgZ3T2gJoRs&}x#!8CP$&1FGHIo@b`lXcbW=H(YK9 z7(D%N9qNlF={%@UlmX-BESR1~S^jKnFX5Usc*{tYKXQU%;rn4W3PYH`vbd_(q7|#j zregB4?9j$n*ih6r0_u$^>*HDztfH2MA?l6s(xkOUt}Emv248ED`pD#q(qB(_i|==JVJX<6|7E4c3v3O zS&Ig{9<#JA1$3{7W;B2ns85^6CGJ;E9L#eol#&iMjkI&k5;kv}*l{?L>JX)q1QoX` zI1##GLXLpM#0UD+;cnzOesT|sd;NFV3{~Z(vlbJ>Z9_Mls67-qQ|F9Kul6s93fZv<5G^_L(*gMK`6*t)InyR*(h*-ViG;VhYWFOk8be=1P&)n7(*>rQWUaSDX!@xFt z%#=|rJJzu9tzR5D0VmVXhj6aDdUisI3h(5M_iTTB zB_Oxk31WUwxDW(j@_k2lz!&&*Uw{C`-@3tyt9ywvlOwswULG*sQWSe zX+>w$G7XL+`}Rj_@9KBGY2teT=vGpnRJ4fQ?g=WD3CUvG3TSaH5lIHi|nY}H;qK0&?T$O!SaiX@v< z$l+E=(-kVLAgrSUi*?b0)3iMyWPe5cuJJo2I_3xiBNw5!6u!eiTTz3* z4f1NbI1)rJ7Bak#MD)a2`Jx^k>MVE$M%R2w6Gvccms_&fI~MnC$f8^6K|%s?D1PyV0)v;yY4u! zjh@`>xOoUfDQMijQ+nu3C{161KyqDGGaU3s&pCz3sFS)no3#+fFqL=4vOh3^OZEW- zaN}nl5ul^5?35RGF{^y#S?esCN6J94j*y1%8AmH58Zia``PbA-S}XHImF^V;XcdLf zDOMR0WB(eJ#YdZK@OkBOCrLU$>nP-WBn1k&^q|Lf7+Ffh{#W%O*I6n!az;9#$NA40 z8vZ-jERz^O(+F0bkuF6>F8qj_H&NjZM6&I4GR#oa@5B}dx}<2+*c!)eKjDJi%+;DBCjRJVzy_Ny3OeW45_%O(7Y8E)r;prM!?)t|9RMh z@ELv>enm;X8}-jw8ku7R#w=_hiI;RNF4GCkI<8}kpqubI!-mg|?fcAl72hRysmK$4 zWMci&8Hw(cPFC?L`Q5onrJ)t@^%>NdVkK3)|5l5J#0 z97)-LZ*}B&TIF{3NLgeNMlc`J52(|&!0hJ{KuC~3qdMKw>{>q~(I_T;S7Jsjt2(YY zrfL!#!Y=P?nyCg|baN zez|S9wHA=FT!T8)2TMQP^~7BVbBGY@4Gre4%>J%gS+dN_%UEo85@J{!R5vW@3NTot zhcf&MVKw7ek7eQty8a8o%l@kT9SNB8^Ezrxk2)d5x9Rdv5TD>4gqWp^rF^j+UavKL zZ@~c0qoNd35qbbu&?@!-dO+`x4;-%CHo0Cc&);>Uk5pFQXYrGPR70-gwYiwH2$~rX6OM5@LPQS}$aqRmsQT-=cdE_+8m3MI==wXt#kcN! zqX&+v8;0g}Z$OJm=WxLZRXW6UUrE`A|kK*N#WPOFFlP0lRsM~=vU);J(bg|3l`IICs z23L#{WSslU8y1QW@3&>|EymoH8OXsGbP%FxS^B-@93}7j%>bD(v%+gh_%L9{X&&0; zY*yndH4T=%3pG*VETUgNy4jj%X6o=x4NfX_*!M41{uDFq_fCzQ2_3}cDoI*SE)6Ver?==T2kOEh*>8#(H@Iy>4cgThWu()KC$-Eq_k(Vh z&@7FeI!kx4ZI21?b`4Mtz_n}mlF^>US^#p}=#Fowv1pI;Dece87rO^4^BS_%lUc5V?&}M)G>ueL zw@2he1B4%cALQrnez+jrY3V-e`=3UKaGeJZ&k_xLQc7MN%%=|Ly|@vW)M<28WlQCb z=0-Shk8UnjGLEvyS^EYhuD%IiuUEM4@~oVNJX(0mUx?a9PiNtFa1E&ba?yx=d&}tL ziQgpH9^J>fyJYE?WK-amr9mXi6N^2X-s#Gr&KG?8p6HRr{_(jQ~aZvv})P-mzL@!5}YAv(kklieY$AnET*zr)F#YYos!lW9vySHTB)AXVuyUH+e#>_h(EShKP+6WGXdiRXqIV)Ak)g2}svx zzN;K^gGP;Gv1a{q^DWZFRv9>Ak#n5Tdt(aqo@Z+NE|RzwoWK*u6VFqpE;AjUrHaj-z=k=1a)v4*kLWBdQN@A-;D+wPm&wj%B z1?Oe{NOYTrizq}?!k`sf6orWHuc_x2nUK%7-Zd!;3c-gaE+BhO^6^GEvc&{XOSY0Mvwji%2q@WoJ-NPqNrHREtD*9OHsy8Ox@HbCU(i5#4R0Bh zG_L{Na*m3Pv4IsEpUX>O`aN&QJ*g{qy{qvYCdJC58Tn5hKo6B0$J&R??J)kT_eAbU zlG)j_a8z|K3wb%js=LB*x;Ft zmSg&MxI}|QAbo0%sDpNEc6gezXnoNha-XR<4-7-&>^z?U5-!`XydzOXV5JzbT{<9} z5@XVv8f4}Ym0_3eHit{uTfddN9VHWJL>;G8o#3zQcsj)d3^e;>&RtmHJp|k$Jghz= zf;Gh)FYAIdk9`*^MPiE#9BCqK-?{-vMdu&ots&3XY=2JO3o-*OT8&u&1VUT}6ABr` zGFyfDGo!S_D`NANWnHKGKi@o-<1Bo})$pn=wtt2+UeO}ji94B@(#%oV?Mb7ACb4H^ z$uV1Vf{Xea`*#QtL8kq73(KZIPat=>@W&0LDm!w=AgCM=agXzd3>5Mr&Sp{F)Z%~n zVt5+|=c_L2`kr<@Q0{KF@+B;!05EM>3XUG~02``;H;7E+O%~F;EMG~t-{>vaOpUp% z%H#nPcHG#%nC?w-7nvE-Y9&5}u7$DFta-LRp=4+Jd?#23~fk%exi4n z)7iZ0pj}rrXMWbm<;n~Wb9hy9f*ZnQT6kg(;Qmy-9q<-?a8pnSjoc&r7T9qSItps- zw;HA#G+y{SUXST$Mo2-u_5hk@9gq!S?ElIsX7lzLCFY>TQ}RoNK?wVUU{|KRhj(=<@miHV^XJHkokV!TE9w<)5TlT$*Ctvu; zmN@B;CzsC;uPU9H9>0@U`=_hxS!0)7LTw3#0Yn}lgqffmvXtTDzDzKV zZ%Ed$Tl|2sI!JK1pKLsa76;=Uwd_6ZSL^~-3-Eb%GP6&E(?jsQ@oZt?(5VX3#|3fZ z%}a`XZ~hO-%!aDECYpg!DUsrLwWO3E8YqR!LSi$bF>T|KMPAp{Ak`T5|A}F5)&muPOW_#R?40GMJ-{Qj)1&Otw(2 z>`uncw@mU<)5llU=CTJ2=WSxIl71|e}Y(qE|l-1@xbIPgkdJA3+OPAX3@4R_5Z>K7-jPjq3UB1&uuyc~MP6?>Gm- zZQWq>B-M7S2HDQL@JSqb7aR5~w~l}f#@;2d%a)^dxJUHSFx-xRP03XE<;{ug*_HWo z;#3(EG21C@Wc&1)lcPKJtNZw)Ik~f0Lb9akNvAh9u^M z`@{|y$C!sk11X=yHkjZE7|7*fGV^!qkSf=5@nIKOo#ckR?z$}CK7>+L4SM7YX;pj4 zY5X{V91NayY^F-;#T`e+I((R5%0#Rgr#9Psh!B}TOpc408|p4f8VFXAXjGo99pJXM zB1)%`8mQC|VxlcWbp^N88;-Q<&v55llbd?=UqV(Uu%F0?=1NwWzbRmc$=he^%1~cyC?`nL9W9Wy9QH!C z$`r0GU)-|&Fk-h|`-=qESU6X7xb?~=^;6Ro8iGM}y%X>9ig%T^Yx_hYMyKzX*Mbha z;0j*J96y+xE&_}A8gYv#llNGy&3tdsosLC8r-6FVKR7FA)F@R2DZ!Pk+|4Z)^2#h| z^p?0R@rkL(ARYCJ&R)TXLYsnccTo%(dL@DYVQ+taDF&w^Qf zwFXsLB+O_~5~SlEFY1DRq3;Nb_Oy1;@fin+_SJUN=9l4*bkq`#*0j82V?xMJ(Who# zQ?cg#KBDG#_42{H6~5XXGZfP$`~fm-BArg}+xNYlSzVp(pI+C`ZwxUO8yZ#Xpf?qFZ~+4*ZpBR!o|HoXTxDOEB~+KGB!Ta_fg{9i-{>gfjfDRBjW1QEC8ynJtnGlxHebccCKM?gUJC6l5z*Xg^+zAvMjRdpzPb73RCRM+EX`E zsL4IQz5rT$1i zQC|GUNTTh|IxT6JZ1R= z!u#6;`AvVu?%|6vA22|8T#qd*H>mhGH&`Z>cucfq&V63?8g9Cegm8LKFFwIvxQ=4X z$R54mB4?0MC`vvf!9XfHwnhge3>zFKSEyv{lXVODGm@ZbOOxY_Y$r+LHmT?!t?aiB z`fkAlP3nCw!IL0;o5TniFD2y(RaN{R=v@a!xbCnxq_w0)(;`iztPsy!9hc0m+8DUo z7~L-4Y5I&FC>sQjmHSDyo8LRkZ5(1b=|_EOGSA@qCF2Ffy|mt*{d^N;mez*^A zw9z4=pDOuWWcZ$Ss#8S30t5SJ5(LeB%{tF!(OPj^{X5^C$zGJKB@~SsLAuC__cRuZ z`XXAUVeZ2TmD5P2lTq<{58CRXIB(>@;arwaA|zkYml;FIwHh8pLip?zen}dUw1)Dz3Ky{^oI# zeXG6e#_dk=vP&DzK)Ou%aI>L%Lh9W#q0#N{W1*UqEvNie|5ScoYxIuHBi8%SpFQED zwyWp)E!~Dtlt13CdT4D7ARCnucX^B!E!C>`5Fq5Xu$t$W=Iq=GKE9l$>A$+RT_^Q1 z1_2fc$@F|Eyru}scX!k{md|bJ$n>}S!5IQHGw(o z#?pJW<>7|P$;#u3^Y+_I4US&!&zu}c=b_a?0^&Rc`KpW@Q|elGQ~2T(paZ4jzy>#I z^v(F5*>^Y^cd4$gvsWD?qd|YmQD8$_(0o8nRq`$KY$b}8HWAC}WNLxqljh^|$W7mO z)p_-6e(dXH^~v&IjAQZTD7`Aa-Os~d&i_2mY>^oRAR%rk%T_O*oGMqF)hIftj*$#t z)aRNL{$LjR0Y|59HYCV`iCaGv8dOBvpqKjP0vSU7v3CgM+lELxlBgCm)6V_y*;cmQ#9?Iy4??;sAmfN8pR=UAC< z5C=ZMuf!bRz(ahuu#xe>{qyrP{6Mw9HihO zfm^A__~`!mf_7@q(QrUN5)NkYkl?K)WPE)8d?7nm=x8M1S5gi^@Q~0gY!rNQ|9oM) zROo0lpdYD(xcQA<1k_LNr9B`4;px>DJrd#N7BA9yt=_;@hW)DvemBmb?SBf`cZFyF zDvIBYGHCms0`^>G*u7HXcf$3hBi9C~1gOTJ)iTmKdE_CVrye;u^_dxdBB`p*Cd z@Vl7?ZO5+ge!qS~dvn{M9rpdlC{Ay~=*`rBLMYAYtr)$TxWm5p_}^ed1Lw$9hQn(S ze)o?-+kZOPzWb={@Ji3=or2#j8NEp{coDzjqRzGc_v$}nhW}}*hpv9^J`&6bFp*^@ z_JnRdA+qSle8&uhBSXxk#oScGe*)*|*0YDUxJvDg7{WxFRKxGllsd0(Ve0qNw}-x+ zU8IEtdXM}T`pfqmB|>s2>-G-q=@$_zil6s!OA;Xnb162ICkG3?2FVDLLx1JglmCvG zb$#zDW$iWrlA{k*+(u`;Spi)b8$eVOGgy1BQ>UrJ_|XWN&1==Pi}lKY4fld4+3eUZ5Cff?d2-T_h; zGQa(uA>x&*VOR7b+}SI64RwWhK!q;%DdJ@Ry|6EXGeSuIPQ0cB6L3g_xtN=7|L7tw z$o-hcX-9CbSI|Isj2Ao>%p>_)Me+U@wc9pqvpiZXgFEReje@tXk1F|b3YAC=WGLxr z5vHpF3Q2xUqwuy0BT@$yCqD*Jc*hPRsl9T?5Y;_~QDpy?d>#1|?+xQ??Bi?d>u&7J zRtI%!fHu`Zx}P6S(1j-G(+80TC|eWs>A}bT+RQ}tB8n>s=_(E7P1EVtlz>NXTDB~o zPeqJxYC2o})`NgYe|pl% zb9|WXbek&jq4B3pd%dReSi`wYv!*=X5VJEs9}RQ8oPOBG=@+77gWmMZeB)aA=~HdV zm{F#(33GH=J{kc*?O{zF*G>)>SJf%VUW1^s;xzcGrj4uqcqFD=lDX`Cx8XS<;#d~3 zEW<)4Z1k$2jr<^qhfhbjxGVPk2b3B8VkmFY^kIPQ94l>1G@LyzbN|v3>BJzWJ#SO! zO|3{~3?0bR3gy5sf`dr2@9AHtD~9Ap_T^;!io3}doPfi$jk_U> z$RtwVeH|kGZ0cW|+%BVj^r3!CqyCG{VKl{i2E}_R#m2ui{`B|1^Yibh#-XQDkqKEk z2XBkG8^wssY>nO5xjHMB#-Wc=k#||TYaffa55I-$cF;^Mr z$Z%cEH+hoiL!!*qO1&Pe>2TRC`KlK3u5yN7*e$1Bw~VkWMIJIcgzARj0&-R6f zn(o?%ux_B7eoMR5RxdhEqt5NB2Gk8!K;oS-B1am~LLf2IP}C`)(oi%g`1j!BJoV6j zuTAoY(pEv5e!m}#ZdK-0E2A_sA)d-GDMtt%cy#5<9J)+0BAGzoS; z`Z!%1=Dsg2WfLV&uNFh((Cvf!SfJ)OBdCb|G`q~0!5m>oRSz1bpI@kGsuJXUM`Q6)qoy|k8oFFv3;F&S7 zPZ8SW@NDvXC_z(P12pBX*FjJLlHIeb0CC$)ttqne?suE1OS8!>_K&WRM3KRqt*_a@ zonwRD_Q9F+f**#E7I07FKl1!onl?neUkT4*?bBBz-$P6A?cz6N2OdV%kEM;*4(MlZ zCma~X3V!28$$(C%sG&Wl3-&z5Ooaxm-Zo!?n{MPL^FXz zcxHUIId3E82F6n>nfJp+DVW8^CI`+OX9klwPMl{CU;$0N=9|1Y4TQx!uO?H@>~j}- zVAeih){`qAHGp7N-mgP1v?aV(DpV%B22o| zYb51l?W9cti!E@o-aH@k(t}O;p`hkjx#767Rc0^c4h@Rao0j-{4fAe900@&28)>Su zlz3*YzK-vO=}jyA?Vnt&t&O=X{)u9gS)cyi!s>Qc(DI_li$4?7(z^2(J#Q+4kRw2*B`!5 z6O^Sr9YB3Gnir;VJwTBb`FSF)0! zf#2X`_oPcG7ny|_vb|B}LnsFo$gQF(LH9h+ZkoVeDd=4G|9$14&T4y z7bSDk8}XBk`7=F(l}L7A#_*?QB@wUs%1}cjN0_w{KEG)U{ISby_e~%shOR7iv3!C$ z?~7=8pKI{Q*4Xe;=3Ur}1FY?o*Z}$*nr$|7|8E1S?*Tg%oC3x15KeK5lifMX=2`Vz zTKC)zbtcez;Zk|L2FZEwW+r4s@UoO+>`zHpIRPBBQ_ zLKSCvx3yLi+ER9}OYyFbQ8jq}n0gjfR-Gl?zv;9ftu*rX&JDA2bGUX#yL#Uz?Ov1e zZb^IfWOa6ot6flqVSq4Xg0#q+DJ{auzHo-CEPQ*QBznDP!1EGMym?Wvz@>@IBXSf@=D;s>PACrEu7g+jiDEro+{v@ zorffG`$F+tBkZHTkRov#vIqHnI$KwvMbm^j&z=-9rO zR3(~;=aL{d*Xc1zF%Cv&&OE0ej}R>*_59-RO+tM*Ir0Z;%{UU}z=e&b{$Nw$7X5JG z+uM_(44=haz36Jrhd08TNEo70a1{~-dudC&&BDbfVC?BAed1#WcmJ(bm?-J6Tc;QQ z%rZ6KN&1Ovajx1!`ss6)K2#0+JfuGpX(@iZSsr&ct8-NJ?cb{#Q@E?;efIYNm1mij zTV)$?aT1~78nNNQMSB)nWq>d_=`-{Pzvz2~nZ~>KCNpVOa>g(#ozF&N++LrjmF8cK zs6CK|UjD4!$7y2}_qx`lQTpro9cI=$GF&#GU{D;>I4^0Zu${??s-)2T59QQ`@6_JugYxb=R+HLiP=b!Bdx~z?Sz4A{~-FbdsI=y<99~ zxZ8@dds*t;n&s)nq|VJVtO@yHnXxesr`^?Gk_rTD_(qQ;fy2E`qhJ0IG`S!&t(6Z-BNs4~Qr#4Bf@ z1)eIf9z2{oMN-@I(P~ROlhbg)deA36Ni`LeJGhEL6dm!(_O7<(}-bL&CS;9wOaSgM0<;}=B zt0j7Df^;h)$^B${&J%RCw6b?^pUGpYWv}m_$xRojp4`3ST^6a_oV;c`yLgA+P7*pg zc!!0^hSjL_n_%g)J~y+<^c1aP#YB>${Rv#oZ+YB%c6L)t3dCV*c|3C;c=db>$@+A< zbN5TU)fK_e^fxQGI;b)`po?)*x?6p!tnB3MOCpd6t8{`IqTBDYuat`8+@fH zQrOj>LF}30tf;YeOyfsm?+=@IbY)OV=ZPQW5>5TL7^%W z!j2;R;fTDg>#4DBP>W=Lmhr`_0&eVCp1}2H9Q#$uor1|CoGH*#chq zJBgZfVmbajMwlF)&!f2ugUao*5!w>NDuKXi=vb@8TD&TD>#$3*g|_5fRv7>H5Gw z{u`9k0hieE47O6{BF%OEWuES8UArHj)P9F+>iU?*(Gt{pU6+SsQ8iZ|;j!wajo4YyvH3N9AmOpgV^tgLwemH+g>3TWI+|xQ z7sZ9(RxYBJ({I#47b^8@dRPTPJVuY{1xu~tzsnw`GPkpM8Ry5&;a|h|c5z7#Y^;N; zbsdD^j#)T*hFOe=N2ii~5m(U{>tT_zzzPXW0$VXpD=tululiF%f}+*XgrBF7;;w=N z$h4i2ESaE*5zXMApXst881n}~$WEvszF>7w?J0amdtbo2pW%Dej<2)FhT8eB%DcDP z7mu|C+seU)tKTEz8dW`Al*li>jaPdIT$I6C3p3c|pw3-ft(Uqt3vWOW3h)G9ls#Dr z58*jMbIs*HR$Yg}1}5l)_zLkvUr=Y4@l!EEv&|tf78Uc}#FP6SBb${_U25N@r8tuM z5evN`$B51gxm5^7=6VPEJPZk0RS1RVdc(5c?)ibd(7KzdRNRkV8iVtgs&7RN>R6X; zTD(sWYzB5<{9B6}^(dB_C_%Z<(C?`5)v%WDfq#{n`-!>drx@JmJ1pszrxYYt7_Nh= zpUQ~dj02$i+D~1AhCM@0!jb_29GHBJi*VJ7#czKKLjrE2grTdL;N#Mm7-$Id!PLs% zxw`FNyshb8E;0hXES~8>7m?EM<)LkeZ*(;EpuCZ96J5zy_zG8cqcAxnR7y$>i0)c( z6amvts;AvSy;z*Z@Nzc>c71J!bwu(*A+1-t_88lxNe_`E4Osx6L!iN;uub z9wSw7@l0Z8>CFQjT;Wdwyb3)LWGujj{{<;@4UAQ~WFLVLs`9TsZ`Tw5fvtcTd>cS= zq$f^??SKPc3Mo_vj9u3o;=+!H3Fd|nvI!uG0miB`?owc1<9oVof(xAokksmlvtpwn z1>=JYp#o!j^@ijxdAxApIbnkFp#%xR{Te)X{ves?iQnquKNb@0pVp`He(ej<*;0O( zf)1AQCyCG-V#c0<4TcXO0iKTv)x2C^;=-pv3Z(;MxCrgiIZR}zz35DkUZ&$Q)9=&1%tmZAOYV$U3^?4pLTQqNCw+~vhag$ouAAi2^T5?~}pf#-w| z#)lA+2_T^Y#_sSB@q-JE=?yKlkM3=c1GU8XT@ys1AZbs(QFF$9ii%SQ1V24)vHFbUOD;IzFZ2O=o5ske?eP9yDFQVY%+UYMjQIaZa@;dRM|Z;e z8!`lJEsYXmzz_dp%t$`n=b&>-aAKp5LEwP@7WhYd|8S%P_NPFA4Z98xUL8t^8A$Z- z1KWUo=7$Q?cinVclgG=@U@fTR3kO|0lv-?|ON9glA_s@fLqgX}5Nxx+I8K>t7>79( zv+tU$iJs|AI-yhO*Cu62-nPaFLU5G?Z*hLU9hx#G=zDcYAXAEf-Iy^l{%;)cL9Krr z0_7QZ=NMwgNvQm4&w;f>gOPDfDx|TCjd@HdSqzHSfP1*n8X6w}((6ol)~ejEFov-N zjXE>q#bVD79Ri&Fk_v4YnkbTQ&-WS&7L7Tj49E=+W)YRi?o7g~(B_4({{>(`pTDaX zl|4|*(hK-`M(&^$C9j$vQ!(lMA!t(b0W@a z%0WGOkwk7=2B)*GnmlnQ|B@$jw;K89|7c;$ifc~*PuDxnoBQ2%cJ>TQAb=wD0++?I zxiIJad$AH1Y=jf`W;Iu=&ZQzSH`Zc2q}4Tnl$(ZiayjO~TN)rgI%DUo23ufOTVN_% zUnp;=0NpNoiLhl4Fi|;)NT)XcSQ+7H6Pap9(pepkF-(0hrc& zxYhG@Csr?8p{$5ZYP9)$TM?ODZ!^S-$gIrG5WD4I<8Cv?a&MB!%@E7I0dh(hSH`N2 z;H=l=8W+YW$0WSWNBLiilWmS85w!loh2eT^=RF`5FTlg9k=KjbxPddMU z<4?l#tF$(O$o`;0{h#|B5UpXcV069;mF$Nthfjf7rM(4)J3o%HZJ2nNm8log(n#4A z?)iv@X%9p}-1WJ_%@ZuB6w}=T^X7+Xag62s+{5)7^{4VwfK}U}WFfd5XY4WqYHgn= za>}vrKZ*f@ZFc@ShP4oYBV(Nks>4tj@TGDUD65gkU^IXNiFBTu{RX^>k3l1x;+wLI;&y(A);KbWq;~ zEp5U&iD{v^ovPXH66CL)X z#0!A0Ecb(IHNobD6m+X?Ipt>RLM%XejcSZkxWqC^?gi!{bPAPu}s7{vQ2U1uI%~lQ(9j zDwEA>Xw#wa1_9>+ZRvz}Rm?|3vw;3o>WS>K{ZM(&id$}syJ9EI zZVl8Ve=GB30?I%n1{7zxRdQb@y^bm@)RCJOUcGG!<3ekhYxKRx(2a+Fv^#B@t&VVC z#k;{2N`9z;j^fg5h{3HaNA)!>$o4H)4Ev{3*rU3O`pT_4k#1cnd=OK+CFi}95kj4Ei5-Vy2M27t7Ygh5 zHo+`cOOz|hUC6WymD)RGFs&H7oUoG|{6f3;Y(I)ee#w9W_qITVLrkuGk=)^OrlQCt zj}8^$Y`QHrjgXv3OHEIjrEoxj&^DE9f$4w=zdtM;tL8$>HWUt7&^S9;&KFpTd^gjP zM~>*0^uNkLpb4+rnxk^cJSVJt3CE5So{lty6aB94&wTu~!ZDEuKaU+ovXYNJ*Jy?B7jIX%V4&L}8`t962gY-9z1r}T0gKWvK zjcGKf=&1+)kAnS&*J~F$J}x`N=(LNV*mes?5u#45^tHS4C4#d;Uiqb3=HWlf4YZ=<4 zT!cz;qxg2741voW&#A^k1n{AC%nCcd9L9)eU342{_K1K9{!S&oi*@IIz5OJbP`tKb z#rkKkhwWgF16REM47S?tvsJc(6&%>jXRzXSu%z=93ZKF94s7)qOeZ`sC!fs^I`64_ zvk7^%HS%t2Bx?s69`g7A^`MGnrl3K(zrj9&;5aeLO&> zyh^rXq|qG=c~}BP&DR^kx`cgEAYRVC5l=KKryG5VU2Q!r?rPs?WBZTd+HVJRBJZX15Z>R1lz%7E4)<$@c81XZV|v?80rdfMpNh9zBOi6Kf}PymLnV2ay53;`1gH)nzLJ^Qs7i_fYH}Hs4fzeT&YSK)ov7qo&Xu zYKKHiOjops!hcL&-7oP}jBW>u`>3t^YzB+y@^xx~xP*`Xx*rY-_NBvaN!MJ_U1*(E z#TSpZzCcgCk$b4jQF|tS)$5YM!^XnQ`Q#^y#~yFPNn^6vGbw!HUZUDP6P+}Rd?n3| z9Hq#(F(St(IrfH@F}Bgr{P84BX@b6Gq!GHvz=lr;_Iw=j^@E3wm1GX!w{Ir)_fXAo zX#6-iVLOK1?C;+O{5ap+6Y*O*;DT#v?up3gKO&ovKVRif(pEFM)U$!6@}IPDZL;OX zHT`hIEytsTujG;89B&<`+7swmy_+TXvy!%Q;j1SF(qhwn^4%BM zLLiN!BzZ_r&h#%cOA(CgxFz+@2V)2k$cfJ6d*I~5mN=Rtg)pW3qQ8IR6Y9MuSK74j zX!)jEbS7EZjAP%oKz6M6ijNFJ7m;*}2{I%d$Ix!uDmN*9-CdIwXAA^c!k^GPlNNCd zq*=nB@J*AJb4c4OnPG1a@ucM%zT9KRG|Y*xd`N7I^wyaFVg4}BEmj+3tZ^?#fwVyq zX5+DI&^M(tNN}W8(%zo=@uu?a4dZ~{NoCJ6ksDzSw5vx>lC*&m^ppz=Q80{57gGsc z&WB8sTw`A8X51yiB{y|MNmfyiiu1kOr+N@AnWa!VEr4UhNPvCL>lTv|najIJpKK2aJ^S<53(pik;G z(vj<92Z=$n#YFOPd+3ZW1i+4!_q4TzC#k^X%O+q;dcG8hz99y~Vu#Vt_wS0oAfHAu zuj~T8(WK)fFq>D&xC9NlCs7?5q~yZ7KTci6B)W>ADfc-ns@!$efiZciqL{*yC`-mS z`M62?*$%exs*{Oryz1oPCe#B(9c|-#pY7JXiXCGJ0DPR=*94+)M{Sac3`!f@W{PH_`MV!<Y_H9ch-29ZQf+A@sYLkZO)tSf0A#0T^ zQCHptBtKGl{V7cJCv+z^;*D_fUE)-HLVV4?5vL-#S(z*Uu_f-E;PP*qaZViZrslaD z>HL|uyhh0Dhx_f#13nO3{(3WRuqAFqaf8jc%9fw6K*y_W#uc|5&(mfL98i_a;z_T3 zUcX&Rr^dZX*09w)pVEM4S^!5fYoVv7mX z7CuXrD9+}{n81?ZIJ?R+vOAizQkR2s37JqJ^jJm$h^oN5MZfPHzKuQNj|eR61_$X5}ADeE|3C40JpvsM8AJyJs2Yr=N~sg zJ09q46SVDtxkjvDt9Y%260A=6VX^msz<4l zK4Ga8PdnF9d%e*$%t#xWYg43FQ98e|3!!sMjj5gD+2`F9yuY4n5BR16L+;8mc-3OnDOStz>jZeXdt@(>;zg`Qr0M%t zV5JJ$719S=^tj@2?(wCH-ksERI{eTQCaI*~CJxv{N@AAXnpTt&F68kK_hv%h5H$SB zT%1Z#tRYcD@C>CmZF~kH zPQn>Vm8@Lp1w4}z<{7pFiL6_e>r3P3DW?tu6#K(N^jae+VMT%|k~fTnPJ*vviy8PW z%8+RI)yohVXx8W*IT+S)NgPQ1ul zjvP(xWPdDroMhKtjBf8z zC)-1LJ+Fz|90ARFi(P#V$O%uP`TX3bR`V{cIn(R)ee-wwa#p|-3K=7v(1j={m-0-! zueI4aH}_dF%t-dt;QnyVa!PqS`kTt0*b~oLRz#C)kZAAyrzIU%uaE5WgTijx5j`{*rU@ z-(m6BSpJ~kJpUAv138)@Ep{rG7ipfa%lVWo|stt%Wz1S;18pghe zEP#lyZ$@a|ICsbP8?6hJ3~0g96OM-1CLveSWE!H%mBaO%rxJ2yt%AJSP!;4&tCGA) zD#>%)nJpw#afMuiQ!S4WXD&^{3?>$7wpo#8uI61EzI_u5h+dC5@>1JG);8;%<*F<( zvtmS^YK;X|a~3_b#QC_sDgwD(J=5k^gAND!wYc649(lleMjm7JxTiZf&^C3sCmoyH zjJ?%w2xwNk3H+#oq3_)$@XW`pFs=PUE9vPOn4>9r4BlQiBuKfz7_j=l+%xHU+gsc< z;KKj@T|Q0s#yykoTXLAHzZ$#j8n-U#t<87rIn358Ek8zwvAkz`2gN)~k*alTbNSOP=6lFf=Vq`4wA#1{$*CBSZ;=n z)SD{dV0^{g5wAME#fae4fT($7JbC8>Lm#Ic_Hl}<7I$;`>`6T%Fi7v`P7tQrOy%S= zMZ~=#FzDZyJI2&Z?Q=N+C^P-%N?>(xHUJ7OrLRnc?gl_10DCpIs-K%pLtS9_kBHCd zH@~9%Pqixon$kU1^2hspQMsZ8+G07f(a$MF?`mkOaU-TF8$H9|>_J;YGd`#&JLnan zn;M#tLQ_*4EgETr=QKD|z%f_O2QMPJtf8qC&i%pxClP$9fte)Ey#vl8c&&jcQ&e0& z+2|EgIudgY%{Ty!nsahGh#qR_S9Z9M9dsMf`T=CECY!=RzrwR4{c|@78u~#h@S};~ zCk;GeXR_~{Noas2PG2>2mma?x=lJCie58Tj=+JfNJPLt_@}!}`S*`eF;C#s;qV+?< zO2%6W=c8O9x}u>izu1R6)Xnpn!Ye93D6YrOr#A6&Ingh_2d^*%1^`=OZw>F&;49!2 zo5m?!(^*vry5f&+_%0Dwg|93qSH&-(lV3vTzl2VG>09O)TDUtnr)>d6U+HwLcO{S# zDYns}qFPp0cP^*Z&XA~F?|VpTuo7%(19l`r>a!3mH1NDCW5ZHKCm74?<3#0=$0X?j z^w@u{`Y8N&sFuD<`BZg1oRfy3S7~-zT|2iGkP5}|vvxVx82Z6M0~6L1+P>wA$tC93 z&b`vZsuwZP;4}s-9=h(Wg`{MmuLG2kaO12RvmAm;8hDqnUY!Z``3})F4NZv&;v?Zs zO;v<1G&p4^i21WKIJ$a5pPHW7N4a#+B}D5BFKZy$JaRuu4dF8l{>bL*v~yI7h`!O# zto`^T<9rm9aS(A0{lcccj(dJEA1sbF_%mG$oaucAE3aveH87*Reze`O69{i<@O!p) z9Jp}2vdobNkFg8U@khiYi|~R5kFvG8>Kqn4=yScfy^qW7A6P_U)%LccqYm;>mp)|ZIZm)}!%9lFc!8=`gp<%C`1 z&PRFPMYO(1Qi6jh-njDw-uR0Zhu=|_gIG9A@G~BjMN&gkro(;IIpQelPh1arjp(R`X8!iry&JFuWI55$)Zd;thh&D6+fv&n+);mf?KtN%oPL&d z4NU#*wd0)6aFShWYsnpTx1Sph7^nNCeypjty>?Fw-oZ=#;4x>r>&zwhQ$%ZX=3SGm zY3?m-o+4bEGw-Ooy>{l38D4%Z{qpOwW#`2~E>owH&%Xf@KQM`0-cDy4y+6;Kdq%k|reEEEX=&6RL8kzMg8+?0=V0|8; zTA9!e-U6Q>_)P;-&CF-_7Q^gw~oDGllTa7v3^O@-s-0?!{2lYaTkZ{Uk7)gSG7r4#__6ozh}MrdbHFRd zZUhMzhp9fPFb{lMaStL+Z_SbHN8y7mhb*Q@=r(58ifM!utnA zzi4RYgXi4yKf&9msl{0Cs1Gh`OZS`NY}?dV6y}Auo%{bD<<~}<19``s@TIc@yT>Hf zNOugF4_^6jZ&CD4N1CI27xhU$ianoF-MctLVsQ8-Z)8s`@;-$gY!6NN^}B7jF#>a+ zq<8NQzY?anJNgp(^h@ZIFQJdWf-VUyVDf2rrR3DFVY$hA_=)CBY0R*frO&YQFJOCL zz&04RH2w@b`2u#qv6IiROOBm?hHY_d?=$RB*MX6DldA^vzS4*SrOv1L@>s{WKgZ8? z{OjkRr=a7xHasn`utnq;QMA<5V`_hxHVICMp;ePk@S_d*=A%Ep>%ohj9k*-7b@baO z==xYkb5T@*#9pfkH;NUx1k06CTZmPZ#l=9AEH2eO>Tqs3_21{f@+9DEzv-{(#+GSw zkJ1CHc-N~*(x#^NQyRF;#GN1EA3HX3XUCpLc6JEdiFBuTH9C$D)28H&bgxPqSv;kJ z#^Mp->+8*ES9W0l3XoBCquJ^DZ!~XLO4`Jua1V*SSVY=_8d7>y)jX{wQB=ASzL$)Y$wiG4!l&-=_%!vQV^FvP5F~z%R14}P%ezwtbrnB>x?m| zA+i2X2}|vkOA3|0%P-g@l+#k$C8u^v2Gn^?FQqGzLa+4nE)-&)gZkVU^=AoNp(Sif zzIv@Kiy*ES;*_|SR~=kRB<(254kzrCvKyoZ%y$&7;LV^)yPu<5ET2?bZ_a@|@Elkv zvvsbP&}PTA3pdF3rYAfMPHEwWF`v2b5qXB4atXjpYo2HD4XhmM$fD zm68yOYCXrr?6S`5Z%c<83PI$YHeXmDiNHB&+WZ-n(?|ClWWS+TBJ&(H&a`=FbqMfR z4K1DUsknuxHqNR|pIM%Br#)@j*cx0GmgJ{u;1Wi~Pb!e3v1H1opDbG{6Y0x{0?ww7*x)5hVo;I!(Tc%;}EQVt1 zIb^7=<=j^_|>=?o((em#&&x zM?#U_d7Q2<<&+n$>T+RCs`MCHzMS(BuHKJ@mG&Dpf1xW(*=;eEE;%BWu+pij%c#bU zE!%xJ=R-@g-=W4j!7~ak+3?9$@bcH-dbg2kSO3?7|LmPJqat-frOY%R8cX&K@?01WUI7ayr;TB8tNKFVwaX&aHWR$B2zg6&41wTpn z!J#yxUBX{}ECO{_?^BW)Fcs*-l0avL?tAZ(vX5a4Zp0Qh41%W^wD)C~Dej%I(No3#wF@ zAYb{>Pt^#6AEsf;FjG8j7HT&o#gDRqcU*q)72}+}Zo)r%3-0WSW78IxV>cmh+K{<5 zOsYi}MyY+GuwTCS!#4=N!SR;LhT2^Q3TTwI)>*Ie&vm5t2S35hYv>V!a@;SP-h=Iy z?`?aa!%YP@eZ_;zyuSmqlaL3pd}x?|MgI=Nr;71Ql-E1TZ=;kaj^ZITslhXfKjKlY zeIF4F+TgIvxGIsE^iO7Ij5gh)qn~K&8aC#JtL;B5CRnR#@Pn)2IKBz9Dh#%hXsMdiEM(I^ESuNq6nEGuZ&^2Y7Ccphs z|J4(BV7(4>y|X^4n{18kDvi{pg2=w5@!{L*&1YKbkF>5+^|7Wo%jFUJU0z8q{aRNB zNO+3R`xr)NC7CXq>_*8Jy8ponM`%UAT$U%#`hK#%@UXWx`S>-gi?wA z1Wl9X#EYUAw#8bx@a0>End{;1(%qDIsfZ#38wusse{nxWtVT0Ui**eH=Jl9U172f zKwm4noR9EgxmPY75JdS2xbst#k2lY(t}VDAQ+&x=B^i&0zJEtGcU!838k9E}2(!My zf-zjM^;rB!E|e{G@+kLH)khh@pB0^!5kHuo_ z7`(*rZX33@x)*=q!9QygSFK~kPpp_b?%#0yK6*tR+bimLyrO$8V*UNQf!bQV z5Qc&0aMme4wi(|>e1qeopT`OIVp^o2AKxH2Vhdu1kNG@$5QOJ?XZ?iN+ql-f4d!kf z1{=hv?m_>^^-s_RdOG}6v7vwZMZBeQB2WKi^SgM7h0f2TzkkCdJyH5ukqImO?jQRl zRB8{-r1gzWT4};e|F+F6m!{-&OBpon{>M$bF07XO?`ucC)25 z?dR8BTctI0VMd@(P-_vAMzXqGXhtwe8mi88hp1=;*F0qTzwHzICy9~|TMCysHt%dgFbJfznPjYPl$6zMmw zNhS5U$%oHhx&7RPORJTGzK0 z=x(TRRxD(7jOBB3jt8DDp7Dn9%*0n#TL!$1VPa{j-mYraXsU1m!QYWCrI7;23t60^ zZxG!y+dP$?E;(cl@e>xqUvdTHH!DrMq|4qmnKarrmj8qppDpd=0L(~D$fKYbHOR8fBWkjlrt@dqChGi2 z-I+9}>X?ziD|E(1)$yjQI!?8N({#%q+`3}pDDmA4eLIg{n7>7}%uIF}^DY|JRXUCm zztM=8thKnybHRXX&dC=beV%@k3^jn>7aS_Df;io1q*;6BX49feyMGXbKNy=ReapBA zTGN_vajNfS(vRHWQZs0J3}znZGS|?Y%fm2jjhcSZoQ0?uA(> zGkwD>s#{pxyPwLZQK@~DiE>Fg=34l48TGTkg4V$?!+vwG5K87u$2C%j)>yOY7x_zD z2?I=1z4y7AQLCa7|GWBJp7=D>b*W|==6@UpSsZCcDsig)`+=kEMqq+~Uc$ABeyqSm9;Y9@pJQp#lP0~t*`Xrpix9O` zo!RWGgN#Q^9IC!tK^1Ywja$xQN{W|VCbgD_YwQrNvVFsk5Lp}Yn1OY)AZpP3%Y?85 z{E(-fewU74xD(@shC0IQ782U&M{93xo%F-q+z^9T$7`@ck{ZkBit|8gQ*S59`LPyi zt~K?Af0-nl2#h%kOoQ^^$x(t2~wP0nlk^b-B9c=ps0&DUw!3+mx zq%U<%B_0ySe$1lKzC2oTRgH5;vWjLlY9GpHQz5xZN9CEi>Nhyn;oTP7G1cBRZ=@W< z0~@a84ObA39nrdGAvfUI*%$i(+LUy`V_Y?wgOD!$|AW1Q$Y#U;4>k|hlUMm~KUF_`V?$SHhbdA`o{)J7&)2hnJ zH4Z28RR3v$I3ewBRpXnE=r7SyX*c9bS3EE2xol|q9Xv5v6@{o$0qpCGx zV`VN_DlqnGW69c`&Puze-C6hX84`h;`W;=`H0KF5iG&~R^^;9|WuIy9zKB!aV%Td5 zSn#u`}@3#X`sD5YEkp=b-Jfmzu55< z$e7H1u3h?N=@v^%Db-LC{n0yiwOQK}AQeN&2Btik%3}jET0_-{u)Sr?+Mg7_(Y5q6 z51^@u+P9t_9Lo*zkU1|kYkyLo8&&vA#g;`z>J8P;*NHauuNg)9<51l;FEhED9>7VA z9fquTiILShd~tr)xWf;QKPyX|4dGI?p3=Q(&E_(xJq=b(;T)>kw&Ge4#bZIJuQgWP zYfl{ws49!JBLc~aBDBxa`n5-2dCf>27FIPAK$|Sytg!}q?5v0A-zYYEeBxetHV=3>CjQ3E6@CZ#3;+ zv-U7nZb|b zB}SfJSp=_k=sUrQaZ+A5bBAQgCbuJBJ}M>&7a|nt%kw(Modb0qPc5g;*F$R-T+fc! zocP9&`znUq$GGC>xcU9L_Zx^IzDEeQmnRMmc1|v1T*> zJdTbw6V0aQYts%{K|8c*X*RUlK_y4<0#6*2P*A(eH?(=rPnsVAQ_HvApZi zZPMab02$lbX92x(pt%#5p2nKmPWx%*=}2^`cSA}ZS{L5<_iq9EYY^)T3*4^|v!Tzj zjh~b624i$Tc-istH~l({aL3}Z{jaQEy_@^iPkBy(Qo9!FfU*_;a_SR6SgRz**=lJx z5d><(+9_GpDe|6`v%EBh2_9H&_!}{@IxAhKti(2yN#WL8?(Z*5)znz-p4cDi{tKHo zExu^C65)+ST9lf0`9V0pwE2nNvW42bZ(O!`OBQNV51Qn>w7E;%1vSgORkr)37Ez^5yj%E0 z_xG{_HWkAuS)`R$GFNiK^%2@yF(Rn`8y zjZPf&2xXUN(haJ(HC=KxFvk1y(4XUEviOaW?&o`kr_?>#pWouzQ*I7~RsU zsS|h;du!A0RHIA**m>T7Ruuf>1f5a;l(c8My!@o-ph1gxfQm`%s(yB=B|;+%ZCvG3 zp*zEuSr+hVsoq_?*knKjd#q;kEa-E&>$j6w%;wle7Lr_$T>1}Blw7Xaos}+Gl>%-o z(PFx@3oyf17}}NN_iu-%B3jS-!cLWsppWGRPFUhh%;mbk@)DP1U-a#p`O*CTeRpoi zpL|YaVn;xJ0LscY#aY21IKdL7qi>3VZSkg?XKZ_Q`LeOKT~SW=N1d>AjY3+JyUS-z z#2}8BG%~w$B#hyiBt|!1cabme)h<(g^sJEI*RZ3E$)x7u#cV7*lNXPK4iD632P`NQ zH#*gf%B{gQrqOzu_Jqde1}@{?<{*9N@_`+)do2;G1G|e|3zNPOD)8g*11W*Jvh}) zO@+jz>B+J8JO^JfIrru%W&owvS!?||DZ>TMPsCjpddZ&R)0&JJW5B2e-_miwj{-JDh%4)>NW zhkQkBzwz6tY88syYB|aJ<_5ynUqA zOjJessNG20hpPQo#;(CS6A!0q|HYh=D$NQhhgr^OZ#cUnDMB$L;&g_pdYXDoKr(L} znc6H`Ra6;E9I>mIGtr=?-6?0sFRZ#ZZjI*o@Gokkvb;EJoe@cBIL+0d2M>+1+%{zs1l` z#~*F=gY#XgWzQ~E^lYXO?$jaH7oM}AP_@r<$nr1v6gz}1#y&MnZxn2UZhc21l#@E~ ztg*F?_l0AY2p@ZH3?}~?8KapB8w2g==mC6U%Z#qg)r}t#%~sOvG<@p$kXg=Wl>Wng zR{9UH{T8oL=0DIw!nRFvfwRmYA||>g%#8S7)wOTLwHdOGjZ)VeLOhhwPpTOYD+V_! zKTL@Rw!S6vN_G2tWqq)f+V#++)Qq+-uh|m&?YUU44!TbtB?BDI@|Ja0sVA0 zt236#@uYTRM~TF#Pqk9@#hMX@ke}$vJ7_$TclXX}M;<`;*N+`W;;KIXE2|qVDSBWp zc~}XLLJ9jp~F@0uTV)YwRzK)nL1 zc&;A%6qxXKKaNk{qONsTY%=tAdTld9Q#15a&-67M2O9csAF}gJhHamwwA8S-={vT` z%;Li*&5{<#@2L%nI=+UJz@yssH*`dF1xWLuGZPk#1L&PADwh_OJS@s}t+{1($->Fu z9tkKTODo(vH=(O8XZK}WWK$a^QRwvt1S|f8`h;Ke@89?K<}^>69eN`je+cstWbf2< zi|#p@t+O3Ji+c4Fi?(k$GxF&>n5ynQtA!|oa86(VxDR&1S6GXM;?+43M~8w#Tdf!xrxu&#Fy><8>2TL zI!+tuIBjJ9oA{flexrsTK89U1>{^ChH0=f@+mp{E*ZeVH2uOnZ_17| zo;K#PUi9mx=&V2;^4;+F2(U{!zoL*f%j)5eY|^Ldz+P{7dthzm%5(Wvff3rat%D?= zJvXh&!6wT;XH&MMQ^U?vsGLXG){<l{mQR(jpffG#n8go|Q$K$(Taq4}BDPKcba;W}j@E zHrljZn>N}!S9&e_f$(tc2gjats!lLsvx!}8qW z0Nrpb3ZZtq<(&nL7{2J;E3v0-CkGo7bRF=p9L6;@!K|i~wn!_@lr(HZx^Iex7q@l0 zxJpR&#w|qbokx+6Dc$yO=P)BI@*W0J_Wm<`%8QSAT)Xq!3wnf>c(BFQ${CCq?>8kmGE=4t&JU*48bJKb=VUbAa)6zKn^zz-f9@FGa+>2 zFfVA7BYU__eTGj=G|RQtW;iR%Y{$>+_Q3Ir;ngNj(2N*z(X|B{E*!%VRA$9vpm7R@ zq*5SzvN2MOuI2##Viap=92$gfO99o>~0RL@0Cyy&W*ZL(b%`(26IDYR20r z{zh$0-S%pGTb7lB#qG7Rc!hxJh5OV9oh2uX#7w-rjBK84*0jht@HEgY5)z4vTUAVJCd5`6j2*juP#;6WZ=< zccD}A^x(A>x;FP>%mLV4`X(Ie>NI`rym!&ckjncMt&C(=f2JAT^S$ZET^VnevV-|I1<-L@Zr#cMe77`|?0 zXm&k@Q-g(Cny1uw)S-GoCh>Z9o7~Qw+6+il9fU>oKwW3g1>=DI#Szy@YCh7x!3B** zB;dT;rC%}PhDTwQwwXQ-?U2nKyVf>v^rUHqVrlfJ6)n3Tm<2s?ZCdx1!MpsfK&%5! zT__A`QDTOjD$CGd+MV zA*wC=$({Vm`7vEDXY7v_C=V@ghNG79%;NEpANt2`5lEEh-^A-Hl6G`h;jdN6+AIE`(Oxy{orNAOAX!S{H&0dEw;0z@>R*(#InRa zJD1Npj_L6ML=e;Rzc=lZs6y8bp*nH+JG`qiPvFKtY@0^5chi0f5%Lem%FY~?S{rU_ z5PCsarDdsG%9s}BKri|6F}-wMSrpQ1{befk+Af4nte3{{l8G-7)2hFzRi=wCHQkq( zY1YshAlvc(r5*o2I6lH-w8)0dMU@??T|;XpZXe&Mldd>EMPt*H_qt%lYeR2~Zd>0t z)-h!*Uc#n$X4V-)>ojj0KRU*7l_?Qd()f-UKN(ubZ`=6PHC7jfDbKmtXU4aN*1Xz2 zVhz_=rCJtwdBjr8_|ec>G26y(PP!$2fW}L?tS^Vmn3Suj2FkYaz%^DMdnwP=lAo&= zL+k5o8(%xdF?FJs@6z~#89y6ZpJ&_n!8JZq#?r@FJ}~1OLu=)18?T%Lc4!&Tr11+g zzBjZM$+mIIJ=)5+CBJivf9IH?wQjbJ^KLp#9k5nf8rPU{)X-Zw+txY9`qcW<@^iQN z=Z+g%|7F|w&i&l#aJS;p_<$K77egt>8>`K4ERubEW@kF%7~3g5d8Rx3 zOp^?xn5Kwz{NDZ3swVQF6BY;j3O%CtbeUSmT&cV!MOfx__t?WZ87m5H|J6{h%T@KEtJrNkGqo04j~t-x zLI;+}F66S9mTX|L_+ zv3|{7e4U(m{5a;sSKRIg#RT`t))u97c<8$3DC*R(_#?w3^+xH9$Kzn0_-8%A&T%T# z@o;O1wTa@=%NO^RF=JlC#P-j6foAUtv_=q`eYmff+-xb$MyJ}o16mx2s1b_;yRA5b zq9A+yjuTs_$nFzO?xwGR%zDV$g?^!&WQ}{*ZJi8S@Vh1whKldqRu$=18$o;pa$oj) zG*rJP`ARWP6~4n`xocj7 zH&c~>WAM6dl0mi-mh(SU$)oH6H6HmE@L84GCT^FUVr~9syS~94w@^^EOFFx5c)~mD zH_u#P^kr)0WhlHKk0p*1CkID~6KefV_9EvZ`u-Q={zXH7 zbLE*a)Ta`2u9S$;${o3}jqQZO@)r|-iSJnDscDUbxW4w;2&E2i&c=B`~{30XPT zcy#^Xo7ESnYzs7XmEOsQ!gI=HT@Q3UAr)9o-NUtuUh;V_3_|Jh>gGBI>lLqNL&0BK zGqHFz=EzDezIp=OYe#y0jf?vC@70lEj{1sbVgFhVb1l3zZ)w`o>n&{oRNqOWs7VxY zu8puc=zaxc>!e0l``ngs*4Eb6mW#AH*dVpmwWs=T2CD1X$#RY^iTqVwPgf07-O_iu zeBe5#>q}X^h#_e714bMJ$uClr7Z~hvBJ31jdAs{An%3;}k;ZA=74XrT{jM?l>HKQS zrQv^$zTk8|F()9f1L@Fz{)aaMwJmW?B{5l80*QtgLxMES3XIleEec?6u6BC$+;W`o zD(A+KHPb+^B~#x0W9s0nInDK|`RiBg=-c^$vcZg1su?~wpe8k6lhe;kE`3doxXJM; zHL3cV9CMTS!6CKDZetTWVh4NI*CrPG?CY$3W7>Sa7^)hp)lxq}8Q;JXW5|lW)5~)%SPNL&q?DqwdkLsg?DuZ*|hZp3NHAvuOi+Hg8~0Cl0J1HAz1z zz!Lh&eg`5vmC9VtzLYtN^nOv_OZ?CJ9^KAsZT+g;&IkLIooZ=^ z`<<{qUB|$#l~ySEIUeI^*Q(jC?4*--nj!2>*HLT)(07^!jLP=Ym2^y^bG)u5%twe@ z8;I!V8wel-$OW6-J_lbg9dOgcHd9ZG$&jxPx0y(^S>ee44%ep=szACvWnPm?O8ox) zm+LJ3W&REI@gR}`7mwyCo&+iTsa7MQi@*M6-q!Ip%VS|OHedbM$Bf><%63xiS}Lo? z`%H9t%1Pzsrf*X}WO?se;avIYabM?&u4cwQZ4k61;n+zNvLso)(|&>ThA4xt68C+>*~g1OO*ETB49?==Q=^Z3cT`jRnv4_xQvyuVvVRA`11#QLw}^R4)_5rPr|GZ`k05E!(hX8TLSV z2}PaIuxA;nmxtp0mVMC0Vzqb?5(N-S%r|+&V8@Dk2%zINt5DlBUe7*X>gk z0;au!V3h;zQG5JG&P;X9ZOs?!${o&baZl`t-Q*rO<(t%g*)9>Q4N0#aa8dwqK#sqW z6Tn%$877vwgxD(9qgi_Ba-fq~2(Bh#0zJAiU920FZuqih7+Z*!u}=&gcr(y}*IdNU z`%(OYxACyt31bxhqz9c|FL&YjF;ldI);9lSKG5>uYnJa|`Hq%{U$cZd$xIzr*VprM z?o-PNv%JRkI%wJbn&ksnKA`2>*DOI^CNn_G)z>URXC|{kZ(z-iP#1M^mQk>LsN-{% ztc46SV`D!&N3#XH_< zO{?JDl%`JkJ0ZgA5wS;WD@07w|K7B=aqERDSin{N%XD0MkZY#am%h6` zIM}VE0c>5RXnO@B9P^GHWN0-8!`7wiR!|tBq~1!Bhb*lhK-KIitA3 zIdd=xf81Ct1Zff_V^Mtz;2HO?ji-WQSD;=r)o;}DHmF_3Cu{d(knLM% zqwS26Zk01AsZ+^VF|=md@^Hcew)eC->k06Ie*UBzzzmbt zSxg<>fI}V zJAm~GcBOGvK3Il0L(;UOm7qyOH$|)x^5SGAS8urvov`e7hU9ARZ|DFIE`j1y;pUAGRn}R=r1iagMA--|fBQ^FaPrm%>S{2> zR9e5v2g?9wj>)N@>HdUsJsw0Axx%~(o93N-8VaMUh z8A0i@m@Rn>S~v1>&qip`v2Q&0}2^^ts>vJr;#Gd$1{YVHW?wiwDQYAA2+ zA-|$J^hh!qOy9k#)qOEcN$Z?^-b6Yhuc;hbdic7$?SEZI0EsnAWBBwS2Id`ibw;ML|`8A}7{Sur?h9>+At2 zSX29vpA06X4@0?9XwAJ^;()E358FMT2R@S18Pwzp|*vb@H zAuJyIWDCK@x8k|TLryZhPuE{C9_YrJ)Y195@q%4;-`es#cOXP13S9n#>}j940< zmwiIK+GHQU;AyLve$cxrR#fgr{%VHKm|Oc)^qLR8V4n1vufAYTOKd?r3tCY&?)zvjF%%u{W{gf~9F2dYol z{y;5YR-@(@F~0P6wi0_gJ3q$O4gAym5gMQGM0fVw&;l{9dV9lzUK4VG>^b0KXI$R_ znSwLx2`Qm@%6?&hrr!WsbuScpiP^F-TwK^s;I?DhYQ&ls_(oM#n}|%lf5*(zQIvq z>f2!oVXGWW&h1{r)AIu|z@z^F16SYCXMjU8z|2?MIezFZK=mWqJYgK*6Y?NRrTMf4 ze0t_NJTb2ORn3ONP%~|R0UDBgy3q%?{^9`le1Mn!7wu#E2UvY^0IhELCH+PFxc&hi zzBs^vKEU9M10=L>Q2V0&p&R;V1X54=Gm-tEx6ctvxKV;woBh`DEn0axHCXPTkfMc@ zyHi%DI1ksEg#8oj_?18>)s2X=t_1Nggwe34@ zea~CR&)#$rvqX(g^k6x}QtXlna~h(2j00YBdMZ>i{Bt|TbWc`MJ?@R2tMtQ;qJLDK z*Dm2T8vVPS`|U*JZeXsGhA(oX8NqoS{T$eiWLu10bldy#2nB6~hF7E!$V59kd&#xo zuo0?V?3QANlmHA#W8O}DDG098BXEj`4NK^82x;&hA7J58V~I4ev$>M%Mi~}G#>ZrS zL%G{zfTbO4m+Ms<#A0xbZTy9)|G$5PeptT)U25-dC7{B#gtxpWed7WRY>p9@05njw zy8)aC`OXhoVa*e%zHWW1&GW6dJOlFDZ42uZp-|leZB^u8_*?vikL8+k$ z&Kq;FZrfDirEh#vD<6&>sgl}L&h5W_<(<+C%1>8B7AS{BO`Ha#(&$TcgsCRFfg-)Y z*-E6sB9jTnj!E_)97VDC#BqWS(cC!1on7DO86tK{Iexb^0}mPF@VD6sN~wG^>}QrP z`niuL`fXQtV5|xWy9qNKg|6zin;9BUgWZR`umzT;#6;hXA;?PLBF`ml;Q_Menb zRnN}8=DXce;`k3?S9RY*SRmhrTet9r?NotklScvtqj%lbefr>{%hwK}&(lM(yB?}5 zm5!0rK-s#t*I%`7a{C98CuG|NdH7VGuy&8h;WY3?APGf`2X5W4n`JCPdx9fKGM)=3 z(Mae1)mCD&*g8NSwQAogksu?G8fgQSUof?+L}M;o0U3=ha$6ubJ?gDudj~l+6>?S% z_Dv%h-xlpgvc}HBY_tYDJ^7hKA#?uWl&H5FW($aB4%3-_(&RSjwSl53`PMAoI{jnp zG0dOXW@hXi=h||p_(b7WOG7JN#VUghFgKSA%5EtHvaxMiwQ`$ttW8%)0u~DAmrvAU zZ?8C|8^eW(I7|wo3Vs&VaFhu)+}`~gqtd@ID(hwXKhJT+kl%F)`rM7ZJ^g~{d(zV? zJhLxXFUU2AE~01VnGhpJ*0@c3%&?b+m5Q&0KdMRv64+G`faG^f?NjSCvo<}}ml`ds zbImtOnJKEil6*Dy)!d#lLhDt7-Dbw-yeAfh<1zk4;&Hdx?U%~<@qt<^kF>RNR}-jt zE*Qo(YVmB4^~SZXFW0(T5CQU8>k@3S%jmSxNXIex6}^C-y4cTj96H12O)a!@`{XJ@ zZKgo>i`L6yMkTqmGWDW%h$NG6=}PG~%b!$9Nr{%tfI$;w?R#$@?Ew@MWlmX4B0Q;zHEw3*{yK35qh2xp1<}HyaU{PWdQNe0E#6W;C@p- zuh#-+Ia{LGQOi@)?NK`k;!%oDhI9fD@JTvqJ*uc8wf?2YB!`ti@>%9w}#M+S-V zYD5$ivF<^f{*F#@F*F^Okuwtmwqyv%;E!%R4eB<45_J$;T}lW$6iC z$mwS6=nN%YH2@?D>PiSU7;a;bf;K1>z{0JxVaU3=UQ)_q}ddY&3K1e3j zme~HIubLN&3aAEzlc2$GHb2+}*P$D@%mRs-4eVnsm&VKlWqsP%AHmETV+@4QHT|)z zYZ@jyM!I6Cmf%p$V=7HUY%Fey75Eh~>Q+3y`i)Td$_P`kus4HVskNR)E3 zup1x9aDws`8Kdc^K4_==KI?<`ING!uOB|BznEXZCk3Dwn78KGe?5gr^eJ}CDjnT9q zl+dO%Z;x-DAeIVYwVV)E*bZYg+@|p~iu7nj095K9#eNWjtG7xV@5R2m?Kh$QNw>j# z`^R@Wg!T9KH6v%_CXTERQTIukkxq9%#y`y;W4Rf@ERb|qBXce|_UH)%SVyIIK1b~$ zrF~@OBEi$cI075uf%dhx)=7QIb@D-ddx`Fx_sAFn&luhY1s$TCZ952b3=9uI;!P9{ zql=WAXkA{e`}-pH0%hXZ#WHpy@9g@C^iggkAa--kq)i_ybna%98Hd~$JGDqyOSw49 z6TVo;$AnEU1u{yPDzY3_+!er59J&dc%X|5VL9qcFrAS5@QB|13vNK9TEvUm{*c?{m zqaYtEHcFC=(x$pgM-!J;rbs|g?b)2k$E|!YBG6-=ej}#3R<0p#VHhm78Q#sO9 zjx=TZJdY_#X`<`Mp`!s6k12ZDRDPqW{6^E2d=%IyIr@zX^s~6~S!xL|NAe;9;l`$1 z0-CIq#^V(wiBU1DBbVxSs>pI9dA*IKH$IXV;E0jc9;s?KsuQG7l{5iPV3$+tm+-+s zEEHMFn@^w1O4{Dg{29GaWzAz0{2PaljzW>UzMMWE`dB~l0s4A0miSoSW^2(_TMOt5 z7ZIMF#bbY)G5TbTfp-kQ+5z+2_yFRVDg>B3qhNz5rqouFTGxDwujf!n*~0=lRF=ox zYZpo$!w_Ze@iBag2>z%;oz^$QW<;2yD*WZcL(n1_N8bA^6aQGX)|S{-^r@deo=u|gqr8)^2tTw zOyHB>zpWQe&JKw9(&N3}F3_|nEppP^!Hx4Dg~l|rbLLG*l2Ky1_ZqDDBbOMqSVupf zvv8Vfk}0d@owDLy2TFQOKSFt&fg?Tn=)>f--jyTzgxMbtd@u9eh9U10tnBVvG5T;h z!(O1pPmc+|c?&Beu0O0QC|m~$eVqH{rz#Hk;XI@s6pYjOAzi4#lhIR2V92h7#Y4h? zyf4ULz~$8A>&Ve&;d#SVo)5dC_0;%uo8tPkJfk(ykaNnO$gccq>>p1^-oie$=i`Ww z8|fdAQ8WKOpF>hy3>V^$wipUi{GnbagB&}(X3obK${6%Q-X^{FAJMQi3^@TayCJdo z8PyUTIb-Ke`rT&lP5jZA&l?|qEP87JnzSt1JTpB#25pUDHS3|c687H?g;9`L>ozzW z`%_pOI)ybXL|zTtiZnGI>uhc{eEg=G7NZadi^!eWEg745hFffYnDz92BAf{lXC#%l zPh*jpB|i5FwTdvZY-(4N#r0;SJJu5|t&6EkxizQJxt6aw^=v`Lc>I@REOh~1T?E&D z!xL$w=e5NGj9Y2jI)|AIGxTOtT23}a%dT{t_GRjKvQ3(Gyn5&;F(}^PFUbA&Nr;Ws zh$O-Jyklz9v$nS(sndYeC%2;jk+E2rY#69en8s-wIT@uVrtOSs|8BQEC4*Qh0;!BA z9?cp)!3?OrkSegIpQGtB|E{j(%&V$y%?nGN?ueFa7K#Md&7k!{U1Azoo_|8O}lzPwV-k{utCEO%JXBMlV z@*Wnwv9)`k-`!6P&y?4k{A2f+PL|W ziJbwfVK%_-MQs(t-d4<&4FieD(Vjs0o1lb>e8KrmyL#8k^z4YQ>LHX8+k8M8d5Tz1tcTdHug zQ6QKxOW`Ov>$7a9OwC4tV8$$m2d1P(*-}}XjRL`p*%cm_v>IhgiETE@9gK2^DjN22 z*-r7AjZ%V9N;ryj8*C}M%|?L+WwSDlQdgsFDWJ_pftF>nK8`Z5M%hkDn~ef}%w}mE z<=Gl#J4tOe3N$yH)sT8>9o;Rpwb>}p?re66qdeR9<90gPY?vwxQ^jE}t*^A5RyP|3 zbnItY93^30yxYlcvr$0Mezpsvw5^+ZTm5Y|3`pD0)|iE~u9z)_xY;NmaX-u8xmHc! z9{QjmSGq1MituviyqYgQ!K-vjI%83fY|K!LO?L^Mpg|=y6owa}5i~Tv426}72OZ(| z|2)E@MpZcf7W>hj09|5oWRVqqpO1gMzxIYg?uzVfGZ{f6Y*_o^@EjbHU(p|-`QEur zZrqo33$v?ZUQ4vn4qVwcAK2FheAgg(2?m~5QS!*h5ppYgA;kHh-x_-fh-X+6e zJmh*vt7BAMof8hU%S4Y)tc0(tlz4Fo{bja3u)ZJLF%B*}ScAPjp;5%QEIDSDf#Fq&Q z3&jg|g;C2*cYceqS{xdm0W)cf9aRf>`r<1nR1@)v`jJ#WimYbsW#PkdjU`U)hEy%P zA=PP!vFu-#zB6YOGC0NyWn@z{+)y^URoPvokYj(C>lS2T#WOYuwEmh z@RoDMci*s*)tbwSH8eofE5>w3UwHSqWbI!L(`K`#iIqr}HdYxUbHkB}9RlAR(^N`@ zoy3-2m^Q-!^-~57s>7g=#cRso!)oc9N9 zKsppsqfD(D>W|!!nDU0RbB$RVChb@0fytBC9?Hj5K00iq5gF;4rf3hJ+!U>H2|Lo` z?mWmxMLq`d!P3_+U7C<*`-rhSlBKI6kIh1UriJ`$3%RFQFe=o`8y$)5j-FjL3^kI- z$UW9tK5pgXQ9f8Q{N;m;RHVW^hb|q;+6ivcNPiF59(k;Zbx8_Qkf_)b1b^1JU>b$dY_$F~j> zfNS1ish?G)F-j3zPscp9dclkXxm+c{hjn{OqVovv3pzb=83=KHU}-PZz_~+N3SrlT zafbcN%C{m#{@w2)n++GB%d&KVfBlNb@dfEZLaIHxd&Wkouu;N2bULNu8}6N}4w)9S zX8yDHV{dOBy1a+L)L(OU2n(8epQU4$H!OybD(^$4F>4BjkKZ1?c~vhDsZF(yZTMN*;_cyds~Hfv$Y` z1z0fK42#B-iYSW70cpnFD2FU}htAx0n-po7Kz+Rn4K3gjJrk>eN3G$dq;DqRI+H%v zkKRuaKmF0$+Y9w$SVD$0tlr;%#piUC@@J!*s8Q~5l-}P~XFH!!`ZRaQGA^bngx-)X zVR??1G#lmdUyf3vqr7DQ8aWSoSK^ov1jobdu*qWp|>XZ|9$L~(8c=_hU(gT1eH#1_kb1aGtiUIJ+2Be&GYKJ z+cw0C-9HzQF}Y}ZG)P}=eQt8Awo_a<)ty9y1`Zb1TZ&eNWz=6DeZAk!`*cTPGsZvC zY@-J(2XV{2e`5#cNUvq6BR_3vO`>0Xt6-=YRY*>P^K&ai0{ZvSGfS<7?gpMchp4x> zYuw=qE%s0p>U-`Pcl~l6Yg75mmm5!i+Eu~nEOushohU|CfzWE@qelO7zlG@cg9?-E z^u}$m+VQV&e2H!3uKM?>67N?=&(?Pcg~`78CHfh8Vb3uCJc7zFr$s<-yfnqaze&JL z+`p3t^pd)HHL&jo5W|6NjK4RX-{~j^oMh8R*HH`sNY@Jsk& zB5`f)JvD`Q_jTGp@8!^N^3PPGqVMbjf7@p5E1>Jhls-%zCe8`s1bct<(a^zOYg z@fh>H5%mVrU&h|N?~Bz*VpXCmL}U)pzx|`{W@LthcXfY#(hK{=lEq+=fPXR0vn7wQ z>i-|dG5wEElZfFc=A7vs9}^~hete$Cyd$}-Qr^%s%l+OXqd@rOd5!`8l{%M2V`nn& zMnr4an=a(EGaN*Qjiwkb)Q>`A+~|t=4*e)lRrB0~(8uwU3cHSsorRb-<_%Ni8y{kx znvBN+(Tg4F!>K}*;}?2cK|brB=LUxNE&Y!tW2bzbspgY*fWPXzo+{@mxl}UGWBiaS z{O1|lBrdEma>mX>C7HUtzEWc>s_yI8_topW6uiR*fs&eMY?|1ynkF6_JL%lBJw)fj zc{O!?SGg|N?}}H~+93V`8qv?HFhA{~Go~vRRMfIb>$&CU)WVXkdUABawn#}^u62=J zkR=Jn4h}*g+-;D7hCVyM2H61uzr^AtSy87GT?+8IqX~S#UgH@fLn=NRRGxyy6ykSSF zVzo&W;lyt&15(4~W157;^BboL+ok0|7H&YGA1}RD=ts!Q7N&F62fOsb&K?HSO}(FX zb9CIyVB%@FW0fg16oKeD>eGRE4S#?6!OD^RB&BDAKbaBvteB%;)iK zN+@g~6&_JJZe(?#o$E%Tv~oa1{dxns?Z6n5tZQS8D*WbaaJ*{?N)d;3E7?riuEYdm zGF5{v3%V)nwSdoJN~B+(CE8u@##&_BV=XeRO1Kt+6K8fETt6nW9A2z*=92f`q!Jqw zUlNZw7{ukoV+kD1)a&S7iDM~J{`nLK=L-_%XAW^AnCj6^fb|tz`kdD- z)o+fQ3hpQ5!Ec!${%a!ah!g%N5T`&;?qv3SFY?^(RLkwVEiZbT>J10clpjP>O)=$5 zkf*WfAZ+EjMp&FvS(^R?>ALah5V~?*B~!BE{t5PV!xF+*t`Eu5yR`J{H0*{Ygs@z1 zP&q+D5_?jY{%O{W>wbVF|G;*PDbmI+t(i6D0A5DFn1!6QD)hNK>Dn zYBx+Fs^ywcEkd2DPjI#yrV!e4P0$umPU!3ykY7ROeo5v4O1w^d3}qfx)17I{W|%)Vd@%9U6ZLzb=rTOh2AiQnkCo!6sh#pyZUuH zdczcomt2!%XJ1`cpWvl8OreU&HK};^AJxwM>jd?NDNWBrkTiN+K#i#*miW?acAco% zf}bJ$fNR}^=)7sP{$3}tKiPn)!vVS0`}i)`5mFiT-oS9F=1AJgHj9Q%CN;*0^{(A1GW?X4TW?hbBGkQ!m|5GzfX+|b}_F^*{{OP*% zQ!_1TM&^}HVl!Hm@OmjNX5cCvMID&VbOeMOD?U}}M6+jkarB{O{;n63mZUE9mx^yo zqhKW>D;^d4P)^;mOnvj~g*POB8PVFO9i1o z@@hryPW)FMHlzfaxoC`cL(v>{?(sCWpDjOo-eJD-?BN3jGnBUvO$wuZf1)ApbB1Cn zRThCG3Apr!NLsEa$~KR%eBc;uSNq-=&E2X`Tz4soQm>>abu<&f@7|2jzP9hi$f-m& zdc(?G_-?Z+rlMfVZMPv>rg#LOJ`KeX0tVeqKzOA!YpkwBxmq~NZ@B%5oC3SHCOK!<25bc;U_eINg>=W6l2o4NGx!>us*>8=d4J312wrOXZBTE!rPuwj1>j%%ee&x!IS)9rGWCn<=4thOZ-X<0;y8ZgY@>R7xObdL5AGwLXTM3l z*BokFrU+vSO&GInlT;>2fofKCEYF+ao6e1V2zE!>*AS9}`__Jfp9A>0f}cx$f800l zJci3v9HEtXw{3&d+=i&24W3CGJd<_}eyWBw9n*8x(PNC5bE;5~;TZgD0oDXq6?kI7 zsyH{S>A0STj>(!Ey*C*fL=Z+r;O0b4_5rWx1TxWf7 zs{3%I^dZXXZy45edYCOe+D%w>#x_y^c>iaLe^o@(#{XCRU==Z0)7O?YTP{*5jLXDaQ2mYxwo+ z`T-G7OR-hcW!X&6Qp+|3PtjxS`CKURxErCkU?+e-`^V!w4PhlRyBWmZ34y!7P&hJ_ zGZ>)vPm<~%Z36aGe22hD;4s@fVCY(g5(YG5>=dTltfRTFShFF05C`E2N^~oSqFdm7 zB7=(iMF*GcKN#QM)<6P!fBX>rH$^>zE_(lwfDR_=*W@SL-yU-~x%4SnxAw6L1;3?& z){QJ;A*M^Wa+AoLhYyxLMhPkOYWDW60t=b!bNlP2XMRu|ZwLQ1Y|;M3A6PQ5PW!uw zE7Nhojd^D^F^q@E0f(#FBU(~)#YMkQDzR=wk74$w|0zT7$$Le5dtL>uq@xX4jj`9n z$&yunVvPYm$&9qWlj<*yq3jT2XTa>t#pKG2$GgXtMrMY-5AHCL|4h0{qn9EzrkTS0 z(>~>&T00eS50@4EG8q2A!B1RQCCDENfvBD;N~H)+3)CiXGs zMd73-qIJKIB!&xfc6Pf3gXCj?3qkwW4Mgkr*G{4f1-Yrw6zED z?d3)@Tw`qtoVt5-Ux&ISOg8Q3=prhx|6Z^%hg;R{#_`3`y6Q4)730^i?B6)syG=Ux zg%Mc`>$bP3PzM`2gNb)H7=$H=Z9A2hSF={+rXM$vt^j+ZgasQhUyWaD>p;c*xmaU9 zI}}p+tZ5^GmqoA>z7S5XNC!;`qsjdn9%+{5W3-r(U`ZNH^kGhV%d(t z3bS9*a|J`@Sd-)g-~hn2`tpFZ&E_q1W~T^_?JpVkipXw(*J?9a7QBbq{4%`7-16*f zWQ&M*L}i6|&NNGlI!1u+yQZxvk;Oa?&E*Jt3cuyPW4mLN_O2FEBhV*-yCvAD*T^#% zbiJ0aa)c1E6`&n1AXEz`WLgN#CSc@p|}Rg-6K(2 zgh`sa6P@PHG4pJ7e~fK(p}<7R*hzi6`@Wu%|!U;COl2tz?~q7po=CT z083;aD6{!c(X+gD_XEUNzBD(t^daiYD8<)<2?~7C-v(6SM-KZ2{>x<1C)k6DsKEO4 zzv=@jG;h;-v<27hJ7sr7@gW|W=18h|Gdjk1biFL3QvO$cNOfjTXF$xEse;Q+rV5q}>Bt^1e4i$gvcW7>| ztID3ABce9Uq5N;XP3F|Q`y>stVGjGv>i5L3EkOgH<)${wVS=ho396y0VSke7)G&vc zs(O>aeX2_MNuFuL9Hy-5J*s}G0_`UWR1I^Ov#NI}8yBf}_c`im!yG29>d%yxQy0o7 zsb&pxn6;|Ep}C$ai++;N)G&u>tNIHS))Z6ACkbB-bC|cPH^`j&Dn7~lYM8^sRh^pB zdg`nABn7Nt4l`HvGc?z{Rpvg&k!zU4)K#4rfKGZOKlfC@{^IEQvVsl8(epI}tPd@2 zIexw!J=fhaB(?ch{gogTjLJJ}T4LvvB?W{U$?P4SoYpSEJv=|H?(OWJA8(x{RO{;J zCe0#-zUYCC=rS=7h_a)GhM5Rc2P)z)KHkwkXv-8l#!{9L7}#+=OAJW9F3R5b;8&v| zYcA(+eX-Y`cKA@rlxZfbDQH;ad`8cQ^APG&t22)m?wmWX9S zG;@ZCvWc?9)Z$21xygK_#W**EJd@4j1%aTd&4+ZY%{${+$9N`NEHu{D`i-H+lvLYu zO${Q4bcz%&pqnPoR9{cB{EBRU1_Bq!I;mZHkv%)BzMdBQwE3K!?Q6y^M#eaxB70TO z!aI(L*AZV$2+$>Pu#Y>;U`b3CUUu7P2dfi>^3kQ9`|5x%K3%22U>d#Q@~DD}U(oKR zesIHpq}Qi^na1%~GI#a&lz?VZS`vPHMsm^!jdn(1#2D=;T*gm%IP;^pk#Nb_t0!+0 zBaFBj#cOFrY*^ej5LK)8wY+qIFc&cIe1m`Y-As1X4~+Gh)*YJn4j0iMKlFioa==ii zsmngPy;B4LQ!eJtDHd%bBXbG&HD-0-a=1INE-tj=Oq#!Xs+JUXz4_cvP+FLWn6?J) zF423R-pj@A)t9upTCTc&`%`1E;Ai`f(pdB;jY%0?)7Z5}+QMpZDvS3pKcapW5^lp_ zn+^O@h0UoC%@$&=>idMIo#TLM+R9wtaJ;ls91RgFS}e`SBXEondLiVhUZ)stnh#nh zDIzvi+*M<76n7DiynCi8OoG)Z2^Pts^vlR8IaVWV9M|t?FFq=13bSB!%7P6J`JgIz zGsh&07E$&- zw}Hdx=8N5Te7;w?eMK=P_>GvO+$KIZe1W2tTbm$hB_4!I*0Nx2ykP$LAvV24uS9(= zwG)JP&lh-KUEDn}$s^Zr-bQb*{sF-{c`n8_HJ?(XYr{29<+&Sd{J{F0Jqt_lJ=N*@ z@F&}Rl)a@V9bB*)}MIEcz;Xjx%>9BqXPgqmR*1r2sSo4)N@1L+nDKo|{J+1MdvbBqT4gC@Y z50=R)O4U5AiImrLTb{A8eB2&F9ow&Y!t#}MV4rT#{ihAeG@6)WpG?5QG53rF!hP7V z=6Xm1!r(N-vCZ}1)sAAtI(@_u!`fg{wTH6P+;|^x+dWaLBi4}~k_0z(%In*V5W@*| zvFnzsi_y-*EqcbiBt$E1*+AbcWVtJ*fJP_z%a`cu*C@LIUm>h+`v)vENw4V!yGf2e zF4MqoEUF{%V5A88e!w)_@D{0_ot9IlGH`kbMjp2wf*qA)@_sxB6QVu7*5Zew9&TK$ z@ofE92_=6snVG1Jzh*M!%#86~(!pG^Q;xlWYaxm4BrU<-g{nj|_nmR-`C`?qdT7v;{aif8Q1vv7mOO%hJmY;~Zb)-r5WGa}pjOYH8z z-+TCbrJL&L%3`u`V}$V=ZX`NE_%^+k&y^>=rdxbY-J~ecpbfYgZ@`?iCttM5A-@PQ z95(k*AtcQ;1>4cL-1il={eJ!Wx?p9d{=feT|HscbqTyQ?6qyEJZXo2Qs$qVDobpLQ=!y%Vrh-gx?wOWv4LM3bB{+70C_c?wsTYv3iZ*J$ntIB{2)*tZ>z zZl7Lk?4EC(9#xMUr(1i+JGH~jq`hsjM_rAAbM0qs^y2 zQs<+;t*SYnCmS@4PLomUfxJ7CMt_4d(lq)`MyVUJ9hXl(Pibiy-65mY7kQ^DcfY~^ zXd1mDqgQk{svg(h;6XNx9*|MOs`Xz~r`_jSMopuaWR$ulo1QwSpC=qOjXsf4>Yr?? zzTD4~H=8zZKa3+de_d3RTNL75vp|^3s#fNXI>wg;TXS5S7(oc53;2h{+&uc5i1?@& zfztl(81WKD>M7hM+t~Hz5IrO&~eCzZ}6#7WF76pd^`1#^6coE?S zL~j;`S~wa%*DY%8l$KS%S_)-3GM*2s`JLMmQ<<`rAB}@M+3LE3!Bobcu@0~JEC+_k zCEeEpx0^{`H=X@M3-ddaynbSoblr+N*ut34V?BsEuIxnEyO>VC50_gsn=ePsTWGy` za1Fg#CnfrddY6oUrC$&D>(MYc)@X@{DpXf~#i_*EP<@#e>E}U+!HzVzZB^(}Z#BN4`=0ODh$ss82E^ zL<8?baWfIcO_&=8x^R|=9#bW>TBE=+QjLOl=*H?cy>VGE(!$O@qyG0nORI#&^*dL4 zEGkxSp5iDYi59sN<@vz*-RpKm$L&sSNLm-E&9^MSQO5jx<~kMyu}=+aUJ480vukDU z!l1W@420#WoHG>#@^OaRNP9D;mmUogkWiPi67Ixev5}ms4M#RdeL^xu zf^X`@;zD+dp|d!?Mi|;M;=SFteMmQ%LddStTCy9nDhZ$ngvcCFh(M%1nbhP~)SbXg zNvy|JMe~jXS8EuMDX|TL8YI{9=q{~6CL#BMJiU5*%tFo{fdnG6WGJHc7@9n)B)R~Y z@Analp!Nz%r3JL5xQ|F^W#)~d`$Xf-bHnnnM@Db6!J2&Y@4{?$-bVL@)Hf+`*~eqe z3#Xr&A%-3F)TK`jSH(9{C2_gz{(Uwc^W!noWHYUUJgD4mVuo^OUvI@|f1ABCO&S7s7>Z&PT)mg2CJHjgLetwz?6tnVPS5v7DT;SunZ;l*+P9=K zjE(!aY7$WHQ(iapoXqx&l3Nj0=BSCd!sjq1TjL~^x8hUYOQ6#f8lU(rVbyUH3N$ST z=Wr`wOi{MtF3-$(s78YXWn)@2bjPNP(I85gmewZ9`d~f}y;1tB7E9F&$h{oKnQWNc zbP>5C-2GKSbq16VB+IH&fi_wR*D%^Ltq701qtOSvgAM3n-?@0Tt=K2OceQWAA5poB=DU%^V%G*|EeQRg$SmrT~)o5HRKZ%dq zI^Hx3@5Dv|2G1!5Yp||JpZ+PXC;crolG)v=ZgRoAe-;m(SN9H+29LDn({r7Ur&JxW zkTGDi2hnzK1Ag}4=Ma7%0`Jw}=Lmj`7HSdI^zL1~PkCPJ1!l8th`HMkAGRUZ;Oeo?KC$t=~#|m`^PC8q{&eL`@>&Y1c00FFY5JO1m&(}AeL4Y|pc*q8!ixLA@U~J= zQ{BeHpL7s)JsRtnRE#3p)}tf^pM$*x)+(ReGkCO&(%ImvgsS5aJ-6;2ESAfoG2Q4* z5|NjaXgs;SM6ged^N%x=I2K9rc|P(YmElK_n`V9hyhm)~F@~V{;|gcADm`{62OqjvDs4%bt7WxQs#H z3aeY7Ot0R+Z+z^XF{`Idb)o+FQANS=tT&*)j3maphwH2MY9&91xsghqbX0V+SH{;~ z85b~vH`niX-@pgg1k6Udx$4D4RwOzYYwfK>SOW6Up$4b^TZq2s40a;&uCo6by^OlPyu(hTYr$klkyuQMrLz<`K$sjSAbdLc`XRn;5^MqwWo} zCS(5_cuwBkZ+dlx-8yY-1T0)s%!R+nh+!JelVR?)RShV=Njqa2&XHjP9kvxG-fuF{ zn1%~vxIm>AsRaDHWHhGXA{j0c;!+icev_BRG(1O!=g4qNo#Wr5s4)%Cli_(PWvTw0 z-(;&X4VTDpiO%tYy4-$`xW+WRM245BlT8`^O%5B=@FE#rB#-i08vac>8`JOt8D5~c zLfv`4$!ud7_Jtl_=&gpOxFJpU^7ZrZ@9XeWfFJnueK-?+I1_z1-F-MS{hZ+~`B9Ry zi_rp+W6eRJy4l3!G`N6yeo`T=dbcM#i=G0Bf+Y=6-K?K9+msA2zic*7X3dS>5C7O~ zG0m)(G!;0{c^ThLn(dJA&L_;yk=c%EHb|QFNXF+AX6MPQiT?BlNwW_QwM75A z*%Fz3FwGAC*la${Y%6KDCDXN^Jhv^=Y&U845z8E(FS6cJ4ujoFNjn086LAoLQ-h{k)H068`kKV7&XX|TC1oI!MDdOCcNd)8UGf$Y*ln`jk8H z*D&f*ISLWW3)y8J*HwniD93;KfGAb?sL>EqZc4IOCxGS4TU#vW;L%+rgx>;!lK|FA zSEoxAenW5Yk{OgpNfCvr^5u<7wdFtJX%ha{@7gVVZ1?PU?Up{a`}n(d7e2Q8I@#`n zvMbW;&V6k6JUuJH`3S5#*%NXS$mf9pXKEV3Kl-F1D1zTv5j4IDFu8PV79jl*P_y!P z9GF+aeum8{Bum7?B&Wcw;?#IzN#Qfj#-yy8r9q1OTBVjc-uURan zFx>nd*CMLfU`x|Q^i6!Pe2Wy${NH}I)2l=}Hq$>$XYe9EI2nEl%w~gM7CAYi_~pR@ zhSjAniL#l$k&Zx)Oa?ujJ#S&jc92HJp-R_56VpA|5vW_m1nUcgE@X{lYb)ZycQ|(z zr#AEqn#lHtgL^A}Es@&uH$QzDJ=KY=kFF(xs3s(Lgnz8~keX(hkc%?R(uAb4;f$5& zCc{u1>$^mot zRRsj}E!{35JbglV4!FE?1~wIk2 z%2ZFK)R)+e$BxcqDM(z5#;V5`)nqZqCw!+*_|74>qnshYwt9NQa$!=;%u_Fk9g4i8 zp&O4}iG8?Rq}EgmfjP}Ok!A&$A?AsP}p0=Y90BP_@#HzRm8AAQ_W#C_2Lc`(j@Hyy-I_l(^AQWXMZJ3usU2f(Uba+)yPbp4|1oA3ol9HJmEhjS_g1>Qy;Nd zkaZ3SzF@t!qOSrya#*-mDtQ}DPO2AqJAMYFYNhBQj0I1DyMi3vap6RsjH_4di7PE4 zd+E-dkuLTL<=Hs1>@+%ty9CBcf5xlM`;eb`25igUw_>d>uDa<~K zRjyq}dzYT}_(6NT0C+%$zux>&5!Z%CQP2`rdwO296l?hu<|Poh?nF&Er>HR6gm11{ zgr9l%0iUu7@1l8aIsrw^^oGu+R2XGOS)54}Hylwsho2+(d4(TD5FEl!4Spc9FP@pE zDf#NpQOEklWbL<{vj~B6z5qdaKIfF+7KRXV2}8)DQ$)xmtmpHlWy-$#oP8}-PWLSS z{|B7!i&Qv5EcrsiW$GupwY7C3_wQ5nnz-ul?!6t4?3|jL zY$ztg{Fq##ZYA+eU=3|GXRk5o3WB`wmO?B{GV~9lKglJ@d`DU~DfIs&T`3JOrX(!G z@J}*}((pn`ZZY)!B+G2PV>8bjx_^=omWFdFDd8~qPZ=KkN#ar(&Znd!v>WFvYm3rrG`6NtoFoaFBY<*@C7?B!u{;Y5v_7Xt^ z@i~zL$)p8D3c&-5=q^sw!ZabbVJD?O7~*mI=AKic zCW1z?g_lKSuz5vf^V*KU1TN{npDn>|amQjo^bw{_{Au_$arX&kVB4`*XbTEvB6y79 zzF(XsL_3gd9Qbr>4{M|u9Kdp(NR~K+-dx3Ni$er# zBPolELRohUi2+XWBGhiJBHkfPYauBT3gwu4+@MVOlKZzj)3=Xiwk|vy|2n>Wp-)J1 z){-x3ktH#ZrkN19_^4^vc}(Hh=P6;MT3wxoFsqpV8o@1jb!2U$V1ob6|NhPWj+gy* z$HJO1wul)k{8`l1b;2aA82N5YJBagD~R8 z`_T3LXsRCuEio8)eutUaNKMfZ>oxk5(5V*T=`V=E=yz+ORAMOMmmForvyug;X`~&( zhY3n#c_e4ANY)JgQwb#(4gDdWaH^OA4 zSAI{r-HRB9t!cVbCI`-w$XVO>oDvaIAUJ)&Px=gBT3y8H0a!hH3?BemqBOqp)&AU!KtLuYB(M_wF1=EY%jaDNxw%VH6e z)d6cJB0eTEd1pfEx(_dj5`&WveOOF(dPs(`J$l~3=cl9R&-nag^!&{*N?rHi6QMV+ zxQXQwnHw8>SUWhb9ySioxr87Vcg)w3qfsNyFfx7NE!iar;}$mwpXII0NxnfUCMSp0 zjjf}t<8vu;ayvSr(Ae7C*=n5DF3$IkcamnW$t=kk3uY5J3#`o9dG%D968G`w(cb3f z;g+nTwBzCN2Ay!9tP;!S0)NPjo|O^pj_A5g(QOHAq84o*)^pc)yKe)`PWr9xu+0Z# z9IHnCM!92i7m|JYjnKN-w`9vC`}pv9=ZS{y9vLy7x7kyFJd!X4dQu(V+VU!uEYrn# zD`(IO!+^NFwvB}dhi;8U4u{?^4a2$gih`RJV>N~DzEM>u!CS(1 z$=sOXO!Hda+psBh&%OHts@4wT-u+$)HVN>e^9xkC9VE(a;ZnjX*rb1Zxc)h-MwKC4 z9Cvx@g077dEH$DEtOB^(%G=fZQ$)5wox|Tk)74!_>j721?iX~Q$B+gRW}v7E!&KCg zCyct7>dbM*dXl4=ie#jN)6d)+YnY7i?Q+hED*yYxQQ9`-MQOUaVl8uVzL6zz5 z;92-=6&#w$;AVu6W;0GS!(@m0dGP#6NR1H<-xoAV(x@W<=u%<4oIF$no82 zSdGa7MC2RX*?zp@e2S91ZCLk|`ji3o;&>pPeK&hI@s+WbcTeVTqcyd`uTwT{JeWqrR$tm_vtKf~do~(;{+JeuZ5bDw)Z?es;dWqDOH~3S#cjuCeGm|wFOt9Bq2grs8Iy5KDk6Z_A{wNzqb)9R zn2ANNJ3(<%wS;-3K*=p(q3j3qIP4&{LY8j!(~9%51txZYRr4Ce!m#+>eP6~NB#cl9 z1c4#a*RSh%@12xjj8onpUz;iC7)J(JruSC_0T&<)_%;d!zH5qPNS|?U zHq(2}v1RVHiLGo082H)n_2)2SjLR|o5`~^!=I3axTF2y)c~$rR+@e`3@H&$$ZtE6N z*@b?ILI*AOl*Rn`dwe#KRG7=~vX7ODYL!~tpc)?qul(wm)J2(I&~3gYY_>nN*`8#x zt=oJtB@�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�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

-
WeMix Mainnet (1111)

- -```toml -AutoCreateKey = true -BlockBackfillDepth = 10 -BlockBackfillSkip = false -ChainType = 'wemix' -FinalityDepth = 1 -FinalityTagEnabled = true -LogBackfillBatchSize = 1000 -LogPollInterval = '3s' -LogKeepBlocksDepth = 100000 -MinIncomingConfirmations = 1 -MinContractPayment = '0.00001 link' -NonceAutoSync = true -NoNewHeadsThreshold = '30s' -RPCDefaultBatchSize = 250 -RPCBlockQueryDelay = 1 - -[Transactions] -ForwardersEnabled = false -MaxInFlight = 16 -MaxQueued = 250 -ReaperInterval = '1h0m0s' -ReaperThreshold = '168h0m0s' -ResendAfterThreshold = '1m0s' - -[BalanceMonitor] -Enabled = true - -[GasEstimator] -Mode = 'BlockHistory' -PriceDefault = '20 gwei' -PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' -PriceMin = '1 gwei' -LimitDefault = 500000 -LimitMax = 500000 -LimitMultiplier = '1' -LimitTransfer = 21000 -BumpMin = '5 gwei' -BumpPercent = 20 -BumpThreshold = 3 -EIP1559DynamicFees = true -FeeCapDefault = '100 gwei' -TipCapDefault = '100 gwei' -TipCapMin = '1 wei' - -[GasEstimator.BlockHistory] -BatchSize = 25 -BlockHistorySize = 8 -CheckInclusionBlocks = 12 -CheckInclusionPercentile = 90 -TransactionPercentile = 60 - -[HeadTracker] -HistoryDepth = 100 -MaxBufferSize = 3 -SamplingInterval = '1s' - -[NodePool] -PollFailureThreshold = 5 -PollInterval = '10s' -SelectionMode = 'HighestHead' -SyncThreshold = 5 -LeaseDuration = '0s' - -[OCR] -ContractConfirmations = 1 -ContractTransmitterTransmitTimeout = '10s' -DatabaseTimeout = '10s' -ObservationGracePeriod = '1s' - -[OCR2] -[OCR2.Automation] -GasLimit = 5300000 -``` - -

- -
WeMix Testnet (1112)

- -```toml -AutoCreateKey = true -BlockBackfillDepth = 10 -BlockBackfillSkip = false -ChainType = 'wemix' -FinalityDepth = 1 -FinalityTagEnabled = true -LogBackfillBatchSize = 1000 -LogPollInterval = '3s' -LogKeepBlocksDepth = 100000 -MinIncomingConfirmations = 1 -MinContractPayment = '0.00001 link' -NonceAutoSync = true -NoNewHeadsThreshold = '30s' -RPCDefaultBatchSize = 250 -RPCBlockQueryDelay = 1 - -[Transactions] -ForwardersEnabled = false -MaxInFlight = 16 -MaxQueued = 250 -ReaperInterval = '1h0m0s' -ReaperThreshold = '168h0m0s' -ResendAfterThreshold = '1m0s' - -[BalanceMonitor] -Enabled = true - -[GasEstimator] -Mode = 'BlockHistory' -PriceDefault = '20 gwei' -PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' -PriceMin = '1 gwei' -LimitDefault = 500000 -LimitMax = 500000 -LimitMultiplier = '1' -LimitTransfer = 21000 -BumpMin = '5 gwei' -BumpPercent = 20 -BumpThreshold = 3 -EIP1559DynamicFees = true -FeeCapDefault = '100 gwei' -TipCapDefault = '100 gwei' -TipCapMin = '1 wei' - -[GasEstimator.BlockHistory] -BatchSize = 25 -BlockHistorySize = 8 -CheckInclusionBlocks = 12 -CheckInclusionPercentile = 90 -TransactionPercentile = 60 - -[HeadTracker] -HistoryDepth = 100 -MaxBufferSize = 3 -SamplingInterval = '1s' - -[NodePool] -PollFailureThreshold = 5 -PollInterval = '10s' -SelectionMode = 'HighestHead' -SyncThreshold = 5 -LeaseDuration = '0s' - -[OCR] -ContractConfirmations = 1 -ContractTransmitterTransmitTimeout = '10s' -DatabaseTimeout = '10s' -ObservationGracePeriod = '1s' - -[OCR2] -[OCR2.Automation] -GasLimit = 5300000 -``` - -

-
Simulated (1337)

```toml @@ -3874,7 +3714,7 @@ BlockBackfillDepth = 10 BlockBackfillSkip = false ChainType = 'kroma' FinalityDepth = 400 -FinalityTagEnabled = false +FinalityTagEnabled = true LogBackfillBatchSize = 1000 LogPollInterval = '2s' LogKeepBlocksDepth = 100000 @@ -3947,85 +3787,6 @@ GasLimit = 5300000

-
Kroma Sepolia (2358)

- -```toml -AutoCreateKey = true -BlockBackfillDepth = 10 -BlockBackfillSkip = false -ChainType = 'kroma' -FinalityDepth = 400 -FinalityTagEnabled = true -LogBackfillBatchSize = 1000 -LogPollInterval = '2s' -LogKeepBlocksDepth = 100000 -MinIncomingConfirmations = 1 -MinContractPayment = '0.00001 link' -NonceAutoSync = true -NoNewHeadsThreshold = '40s' -RPCDefaultBatchSize = 250 -RPCBlockQueryDelay = 1 - -[Transactions] -ForwardersEnabled = false -MaxInFlight = 16 -MaxQueued = 250 -ReaperInterval = '1h0m0s' -ReaperThreshold = '168h0m0s' -ResendAfterThreshold = '30s' - -[BalanceMonitor] -Enabled = true - -[GasEstimator] -Mode = 'BlockHistory' -PriceDefault = '20 gwei' -PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' -PriceMin = '1 wei' -LimitDefault = 500000 -LimitMax = 500000 -LimitMultiplier = '1' -LimitTransfer = 21000 -BumpMin = '100 wei' -BumpPercent = 20 -BumpThreshold = 3 -EIP1559DynamicFees = true -FeeCapDefault = '100 gwei' -TipCapDefault = '1 wei' -TipCapMin = '1 wei' - -[GasEstimator.BlockHistory] -BatchSize = 25 -BlockHistorySize = 24 -CheckInclusionBlocks = 12 -CheckInclusionPercentile = 90 -TransactionPercentile = 60 - -[HeadTracker] -HistoryDepth = 400 -MaxBufferSize = 3 -SamplingInterval = '1s' - -[NodePool] -PollFailureThreshold = 5 -PollInterval = '10s' -SelectionMode = 'HighestHead' -SyncThreshold = 10 -LeaseDuration = '0s' - -[OCR] -ContractConfirmations = 1 -ContractTransmitterTransmitTimeout = '10s' -DatabaseTimeout = '10s' -ObservationGracePeriod = '1s' - -[OCR2] -[OCR2.Automation] -GasLimit = 5300000 -``` - -

-
Fantom Testnet (4002)

```toml @@ -4904,6 +4665,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5064,6 +4827,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] @@ -5567,7 +5332,7 @@ GasLimit = 5300000 AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false -FinalityDepth = 5 +FinalityDepth = 50 FinalityTagEnabled = true LinkContractAddress = '0x779877A7B0D9E8603169DdbD7836e478b4624789' LogBackfillBatchSize = 1000 @@ -5713,6 +5478,8 @@ LeaseDuration = '0s' ContractConfirmations = 1 ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' ObservationGracePeriod = '1s' [OCR2] diff --git a/go.md b/go.md index 090221a89f..f3c59260e6 100644 --- a/go.md +++ b/go.md @@ -22,6 +22,8 @@ flowchart LR chainlink/v2 --> caigo click caigo href "https://github.com/smartcontractkit/caigo" + chainlink/v2 --> chain-selectors + click chain-selectors href "https://github.com/smartcontractkit/chain-selectors" chainlink/v2 --> chainlink-automation click chainlink-automation href "https://github.com/smartcontractkit/chainlink-automation" chainlink/v2 --> chainlink-common @@ -32,6 +34,8 @@ flowchart LR click chainlink-data-streams href "https://github.com/smartcontractkit/chainlink-data-streams" chainlink/v2 --> chainlink-feeds click chainlink-feeds href "https://github.com/smartcontractkit/chainlink-feeds" + chainlink/v2 --> chainlink-relay + click chainlink-relay href "https://github.com/smartcontractkit/chainlink-relay" chainlink/v2 --> chainlink-solana click chainlink-solana href "https://github.com/smartcontractkit/chainlink-solana" chainlink/v2 --> chainlink-starknet/relayer @@ -54,6 +58,7 @@ flowchart LR chainlink-data-streams --> libocr chainlink-feeds --> chainlink-common chainlink-feeds --> libocr + chainlink-relay --> libocr chainlink-solana --> chainlink-common chainlink-solana --> libocr chainlink-starknet/relayer --> caigo diff --git a/go.mod b/go.mod index a4b5ed07b8..f7b74fc719 100644 --- a/go.mod +++ b/go.mod @@ -70,15 +70,13 @@ require ( github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 - github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20230828183543-6d0939746966 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 - github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 @@ -108,8 +106,8 @@ require ( google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 gopkg.in/guregu/null.v4 v4.0.0 - k8s.io/utils v0.0.0-20230711102312-30195339c3c7 gopkg.in/natefinch/lumberjack.v2 v2.2.1 + k8s.io/utils v0.0.0-20230711102312-30195339c3c7 ) require ( @@ -123,27 +121,28 @@ require ( filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect github.com/DataDog/zstd v1.5.2 // indirect - github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect + github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/VictoriaMetrics/fastcache v1.10.0 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect - github.com/aws/jsii-runtime-go v1.75.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 // indirect @@ -167,28 +166,26 @@ require ( github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/fvbommel/sortorder v1.0.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gagliardetto/binary v0.7.1 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -202,9 +199,12 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/go-tpm v0.9.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect - github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect @@ -232,84 +232,45 @@ require ( github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect - github.com/libp2p/go-eventbus v0.2.1 // indirect - github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p v0.13.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 // indirect - github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect - github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect - github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect - github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.11.1 // indirect - github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect - github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect - github.com/libp2p/go-libp2p-nat v0.0.6 // indirect - github.com/libp2p/go-libp2p-noise v0.1.2 // indirect - github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect - github.com/libp2p/go-libp2p-record v0.1.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect - github.com/libp2p/go-libp2p-tls v0.1.3 // indirect - github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect - github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect - github.com/libp2p/go-mplex v0.3.0 // indirect - github.com/libp2p/go-msgio v0.0.6 // indirect - github.com/libp2p/go-nat v0.0.5 // indirect - github.com/libp2p/go-netroute v0.1.4 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/libp2p/go-reuseport v0.0.2 // indirect - github.com/libp2p/go-reuseport-transport v0.0.4 // indirect - github.com/libp2p/go-sockaddr v0.1.0 // indirect - github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect - github.com/libp2p/go-tcp-transport v0.2.1 // indirect - github.com/libp2p/go-ws-transport v0.4.0 // indirect - github.com/libp2p/go-yamux/v2 v2.0.0 // indirect - github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/linxGnu/grocksdb v1.7.16 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/russross/blackfriday v1.6.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.16.0 // indirect @@ -329,8 +290,6 @@ require ( github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/xlab/treeprint v1.1.0 // indirect - github.com/yuin/goldmark v1.4.13 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect @@ -345,28 +304,21 @@ require ( go.opentelemetry.io/otel/sdk v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect - go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect - go.uber.org/atomic v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sys v0.15.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.27.3 // indirect - k8s.io/apiextensions-apiserver v0.25.3 // indirect - k8s.io/apimachinery v0.27.3 // indirect - k8s.io/cli-runtime v0.25.11 // indirect - k8s.io/client-go v0.27.3 // indirect - k8s.io/component-base v0.26.2 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 // indirect - k8s.io/kubectl v0.25.11 // indirect + nhooyr.io/websocket v1.8.7 // indirect pgregory.net/rapid v0.5.5 // indirect - sigs.k8s.io/controller-runtime v0.13.0 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.12.1 // indirect - sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) @@ -379,8 +331,4 @@ replace ( // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f - - // K8s imports are weird - k8s.io/api => k8s.io/api v0.25.4 - k8s.io/client-go => k8s.io/client-go v0.25.4 ) diff --git a/go.sum b/go.sum index 46be922267..26d1ab20ec 100644 --- a/go.sum +++ b/go.sum @@ -103,12 +103,6 @@ github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0F github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -<<<<<<< HEAD -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -======= ->>>>>>> develop github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -122,8 +116,8 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= @@ -137,13 +131,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -<<<<<<< HEAD -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -======= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= ->>>>>>> develop github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -160,27 +149,12 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -<<<<<<< HEAD -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= -github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= -github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= -github.com/aws/aws-sdk-go v1.44.302/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g= -github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI= -github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4= -github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I= -======= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= ->>>>>>> develop github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= @@ -207,19 +181,10 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtyd github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= -github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -<<<<<<< HEAD -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 h1:rvc39Ol6z3MvaBzXkxFC6Nfsnixq/dRypushKDd7Nc0= -github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5/go.mod h1:R/pdNYDYFQk+tuuOo7QES1kkv6OLmp5ze2XBZQIVffM= -======= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= ->>>>>>> develop github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -233,10 +198,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 h1:CyuI+igIjadM/GRnE2o0q+WCwipDh0n2cUYFPAvxziM= -github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657/go.mod h1:JRiumF+RFsH1mrrP8FUsi9tExPylKkO/oSRWeQEUdLE= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -254,7 +215,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= @@ -327,8 +287,6 @@ github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJF github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbdT9+Q5kgLpmmsHYl0= github.com/cucumber/common/gherkin/go/v22 v22.0.0/go.mod h1:3mJT10B2GGn3MvVPd3FwR7m2u4tLhSRhWUqJU4KN4Fg= github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= @@ -374,29 +332,22 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -<<<<<<< HEAD -github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -======= github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T/Lao= github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= ->>>>>>> develop github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= @@ -405,16 +356,7 @@ github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGC github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= -github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -425,12 +367,6 @@ github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBd github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -<<<<<<< HEAD -github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= -======= ->>>>>>> develop github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -440,15 +376,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -<<<<<<< HEAD -github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= -github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= -github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= -github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -======= github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= ->>>>>>> develop github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= @@ -481,6 +410,7 @@ github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NB github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= @@ -513,44 +443,29 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= -github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -<<<<<<< HEAD -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= -======= github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= ->>>>>>> develop github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -635,8 +550,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= -github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -680,13 +593,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -<<<<<<< HEAD -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -======= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= ->>>>>>> develop github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -726,8 +634,6 @@ github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EK github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= @@ -899,13 +805,8 @@ github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9 github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -<<<<<<< HEAD -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -======= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= ->>>>>>> develop github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -924,19 +825,17 @@ github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7 github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= -github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -961,6 +860,7 @@ github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awS github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a h1:dHCfT5W7gghzPtfsW488uPmEOm85wewI+ypUwibyTdU= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= @@ -972,211 +872,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -<<<<<<< HEAD -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= -github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= -github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= -github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= -github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= -github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= -github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= -github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= -github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 h1:2H/P+forDWBHije1WULwPfGduByUmC4fthndHVRpYNU= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= -github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= -github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= -github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug= -github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= -github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= -github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= -github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= -github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= -github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= -github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= -github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= -github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= -github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= -github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= -github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= -github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= -github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= -github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= -github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= -github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= -github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= -github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= -github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= -github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= -github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= -github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= -github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= -github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= -github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= -github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= -github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= -github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= -github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk= -github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE= -github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= -github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= -github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= -github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= -github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= -github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= -github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= -github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= -github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= -github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= -github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= -github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= -github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= -github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= -github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= -github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= -github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= -github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= -github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= -github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= -github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= -github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= -github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= -github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= -github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= -github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= -github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.4 h1:47V0+hJfYaqj1WO0A+cDkRc9xr9qKiK7i8zaoGv8Mmo= -github.com/libp2p/go-netroute v0.1.4/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= -github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= -github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= -github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= -github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= -github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= -github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= -github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= -github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= -github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= -github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= -github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= -github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= -github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= -======= ->>>>>>> develop github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= @@ -1184,12 +881,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -<<<<<<< HEAD -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -======= ->>>>>>> develop github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -1234,16 +925,6 @@ github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0Em github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -<<<<<<< HEAD -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -======= ->>>>>>> develop github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -1254,8 +935,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -1267,11 +946,6 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -<<<<<<< HEAD -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -======= ->>>>>>> develop github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1281,8 +955,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= @@ -1290,64 +962,6 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -<<<<<<< HEAD -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= -github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= -github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= -github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= -github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= -github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= -github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -======= ->>>>>>> develop github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= @@ -1404,15 +1018,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -<<<<<<< HEAD -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -======= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= ->>>>>>> develop github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= @@ -1494,8 +1101,6 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1511,13 +1116,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -<<<<<<< HEAD -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -======= github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec= github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= ->>>>>>> develop github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= @@ -1536,24 +1136,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -<<<<<<< HEAD github.com/smartcontractkit/chain-selectors v1.0.6 h1:SWvONQuYnMSMoaOeLBSQY+iQjMVKvzmRGniKO2mYO64= github.com/smartcontractkit/chain-selectors v1.0.6/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-env v0.38.3 h1:ZtOnwkG622R0VCTxL5V09AnT/QXhlFwkGTjd0Lsfpfg= -github.com/smartcontractkit/chainlink-env v0.38.3/go.mod h1:7z4sw/hN8TxioQCLwFqQdhK3vaOV0a22Qe99z4bRUcg= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/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= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.16.0 h1:jLpqwqaTpJXQvTJ1IXTomcCToOdrSCe4+IGcLXGsmD0= -github.com/smartcontractkit/chainlink-testing-framework v1.16.0/go.mod h1:t6FJX3akEfAO31p96ru0ilNPfE9P2UshUlXTIkI58LM= -github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20230828183543-6d0939746966 h1:18MPun8xOGNhP3dGPvr9nYENEKhuhHNPMIQzOsiN6l4= -github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20230828183543-6d0939746966/go.mod h1:RcA3U87XQ2VqXkEG4PuHz2uZiFyXBtUHcFddeHJTWSk= -======= github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 h1:lSYiaiIfAA+5ac45/UD8ciytlNw/S6fnhK7bxFHYI88= @@ -1564,30 +1148,20 @@ github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e h1:/tCHhoAJM+ittEHPZTtJsAgXmYujKiDW0ub9HXW9qtY= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= ->>>>>>> develop github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -<<<<<<< HEAD -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= -github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= -github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -======= github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 h1:AA7vf29c6lFsZm+MtIEtXtg6VUOQV6waJo5MUuHfRjQ= github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7/go.mod h1:WcuWFMskcGK0MYZuH5hEhGJOzdJRUFeNEM4PAKlejI4= ->>>>>>> develop github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= @@ -1620,17 +1194,10 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -<<<<<<< HEAD github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -======= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= ->>>>>>> develop github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -1725,8 +1292,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= -github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= @@ -1743,7 +1308,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -1774,23 +1338,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -<<<<<<< HEAD -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -======= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= @@ -1805,11 +1352,8 @@ go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZ go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= ->>>>>>> develop go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g= -go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1838,13 +1382,8 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -<<<<<<< HEAD -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -======= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= ->>>>>>> develop golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1899,7 +1438,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1965,9 +1503,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -2068,11 +1604,6 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -<<<<<<< HEAD -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -======= ->>>>>>> develop golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2204,19 +1735,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -<<<<<<< HEAD golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= -gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= -======= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= ->>>>>>> develop google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -2294,22 +1816,12 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -<<<<<<< HEAD -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 h1:+VoAg+OKmWaommL56xmZSE2sUK8A7m6SUO7X89F2tbw= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753/go.mod h1:iqkVr8IRpZ53gx1dEnWlCUIEwDWqWARWrbzpasaTNYM= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 h1:lCbbUxUDD+DiXx9Q6F/ttL0aAu7N2pz8XnmMm8ZW4NE= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 h1:XUODHrpzJEUeWmVo/jfNTLj0YyVveOo28oE6vkFbkO4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -======= google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= ->>>>>>> develop google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2330,18 +1842,11 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -<<<<<<< HEAD -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -======= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= ->>>>>>> develop google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2355,7 +1860,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= @@ -2375,8 +1879,6 @@ gopkg.in/guregu/null.v2 v2.1.2/go.mod h1:XORrx8tyS5ZDcyUboCIxQtta/Aujk/6pfWrn9Xe gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -2401,7 +1903,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -2416,31 +1917,10 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -<<<<<<< HEAD -k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs= -k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ= -k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k= -k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo= -k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= -k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/cli-runtime v0.25.11 h1:GE2yNZm1tN+MJtw1SGMOLesLF7Kp7NVAVqRSTbXfu4o= -k8s.io/cli-runtime v0.25.11/go.mod h1:r/nEINuHVEpgGhcd2WamU7hD1t/lMnSz8XM44Autltc= -k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8= -k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw= -k8s.io/component-base v0.26.2 h1:IfWgCGUDzrD6wLLgXEstJKYZKAFS2kO+rBRi0p3LqcI= -k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 h1:OmK1d0WrkD3IPfkskvroRykOulHVHf0s0ZIFRjyt+UI= -k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515/go.mod h1:kzo02I3kQ4BTtEfVLaPbjvCkX97YqGve33wzlb3fofQ= -k8s.io/kubectl v0.25.11 h1:6bsft5Gan6BCvQ7cJbDRFjTm4Zfq8GuUYpsWAdVngYE= -k8s.io/kubectl v0.25.11/go.mod h1:8mIfgkFgT+yJ8/TlmPW1qoRh46H2si9q5nW8id7i9iM= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -======= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= ->>>>>>> develop +k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= +k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= @@ -2461,29 +1941,14 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -<<<<<<< HEAD nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -======= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= -nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= ->>>>>>> develop pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ= -sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= -sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= -sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= -sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index 9502dffd07..38df2e00b5 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -24,9 +24,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index e81949bc47..42337b6e46 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -2,7 +2,6 @@ package actions import ( "context" - _ "embed" "fmt" "math/big" "strings" @@ -19,14 +18,15 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" chainselectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/atomic" "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctfclient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts/laneconfig" @@ -279,19 +279,19 @@ func (ccipModule *CCIPCommon) CleanUp() error { for i, pool := range ccipModule.BridgeTokenPools { bal, err := ccipModule.BridgeTokens[i].BalanceOf(context.Background(), pool.Address()) if err != nil { - return fmt.Errorf("error in getting pool balance %+v", err) + return fmt.Errorf("error in getting pool balance %w", err) } if bal.Cmp(big.NewInt(0)) == 0 { continue } err = pool.RemoveLiquidity(bal) if err != nil { - return fmt.Errorf("error in removing liquidity %+v", err) + return fmt.Errorf("error in removing liquidity %w", err) } } err := ccipModule.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("error in waiting for events %+v", err) + return fmt.Errorf("error in waiting for events %wfmt.Sprintf(\"Setting mockserver response\")", err) } } return nil @@ -391,7 +391,7 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, if ccipModule.ARM != nil { arm, err := cd.NewARMContract(ccipModule.ARM.EthAddress) if err != nil { - return fmt.Errorf("getting new ARM contract shouldn't fail %+v", err) + return fmt.Errorf("getting new ARM contract shouldn't fail %w", err) } ccipModule.ARM = arm } else { @@ -402,11 +402,11 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, } ccipModule.ARMContract, err = cd.DeployMockARMContract() if err != nil { - return fmt.Errorf("deploying mock ARM contract shouldn't fail %+v", err) + return fmt.Errorf("deploying mock ARM contract shouldn't fail %w", err) } err = ccipModule.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("error in waiting for mock ARM deployment %+v", err) + return fmt.Errorf("error in waiting for mock ARM deployment %w", err) } } } @@ -417,18 +417,18 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, // deploy link token token, err := cd.DeployLinkTokenContract() if err != nil { - return fmt.Errorf("deploying fee token contract shouldn't fail %+v", err) + return fmt.Errorf("deploying fee token contract shouldn't fail %w", err) } ccipModule.FeeToken = token err = ccipModule.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("error in waiting for feetoken deployment %+v", err) + return fmt.Errorf("error in waiting for feetoken deployment %w", err) } } else { token, err := cd.NewLinkTokenContract(common.HexToAddress(ccipModule.FeeToken.Address())) if err != nil { - return fmt.Errorf("getting fee token contract shouldn't fail %+v", err) + return fmt.Errorf("getting fee token contract shouldn't fail %w", err) } ccipModule.FeeToken = token } @@ -445,21 +445,24 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, // we deploy link token and cast it to ERC20Token linkToken, err := cd.DeployLinkTokenContract() if err != nil { - return fmt.Errorf("deploying bridge token contract shouldn't fail %+v", err) + return fmt.Errorf("deploying bridge token contract shouldn't fail %w", err) } token, err = cd.NewERC20TokenContract(common.HexToAddress(linkToken.Address())) + if err != nil { + return fmt.Errorf("getting new bridge token contract shouldn't fail %w", err) + } } else { token, err = cd.DeployERC20TokenContract(tokenDeployerFns[i]) - } - if err != nil { - return fmt.Errorf("deploying bridge token contract shouldn't fail %+v", err) + if err != nil { + return fmt.Errorf("deploying bridge token contract shouldn't fail %w", err) + } } ccipModule.BridgeTokens = append(ccipModule.BridgeTokens, token) } } err = ccipModule.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("error in waiting for bridge token deployment %+v", err) + return fmt.Errorf("error in waiting for bridge token deployment %w", err) } } @@ -467,7 +470,7 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, for _, token := range ccipModule.BridgeTokens { newToken, err := cd.NewERC20TokenContract(common.HexToAddress(token.Address())) if err != nil { - return fmt.Errorf("getting new bridge token contract shouldn't fail %+v", err) + return fmt.Errorf("getting new bridge token contract shouldn't fail %w", err) } tokens = append(tokens, newToken) } @@ -481,12 +484,12 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, token := ccipModule.BridgeTokens[i] btp, err := cd.DeployLockReleaseTokenPoolContract(token.Address(), *ccipModule.ARMContract) if err != nil { - return fmt.Errorf("deploying bridge Token pool shouldn't fail %+v", err) + return fmt.Errorf("deploying bridge Token pool shouldn't fail %w", err) } ccipModule.BridgeTokenPools = append(ccipModule.BridgeTokenPools, btp) err = btp.AddLiquidity(token.Approve, token.Address(), ccipModule.poolFunds) if err != nil { - return fmt.Errorf("adding liquidity token to dest pool shouldn't fail %+v", err) + return fmt.Errorf("adding liquidity token to dest pool shouldn't fail %w", err) } } } else { @@ -494,7 +497,7 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, for _, pool := range ccipModule.BridgeTokenPools { newPool, err := cd.NewLockReleaseTokenPoolContract(pool.EthAddress) if err != nil { - return fmt.Errorf("getting new bridge token pool contract shouldn't fail %+v", err) + return fmt.Errorf("getting new bridge token pool contract shouldn't fail %w", err) } pools = append(pools, newPool) } @@ -512,12 +515,12 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, } weth9addr, err := cd.DeployWrappedNative() if err != nil { - return fmt.Errorf("deploying wrapped native shouldn't fail %+v", err) + return fmt.Errorf("deploying wrapped native shouldn't fail %w", err) } err = ccipModule.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for deploying wrapped native shouldn't fail %+v", err) + return fmt.Errorf("waiting for deploying wrapped native shouldn't fail %w", err) } ccipModule.WrappedNative = *weth9addr } @@ -528,16 +531,16 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, } ccipModule.Router, err = cd.DeployRouter(ccipModule.WrappedNative, *ccipModule.ARMContract) if err != nil { - return fmt.Errorf("deploying router shouldn't fail %+v", err) + return fmt.Errorf("deploying router shouldn't fail %w", err) } err = ccipModule.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("error in waiting for router deployment %+v", err) + return fmt.Errorf("error in waiting for router deployment %w", err) } } else { r, err := cd.NewRouter(ccipModule.Router.EthAddress) if err != nil { - return fmt.Errorf("getting new router contract shouldn't fail %+v", err) + return fmt.Errorf("getting new router contract shouldn't fail %w", err) } ccipModule.Router = r } @@ -551,16 +554,16 @@ func (ccipModule *CCIPCommon) DeployContracts(noOfTokens int, common.HexToAddress(ccipModule.WrappedNative.Hex()), }) if err != nil { - return fmt.Errorf("deploying PriceRegistry shouldn't fail %+v", err) + return fmt.Errorf("deploying PriceRegistry shouldn't fail %w", err) } err = ccipModule.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("error in waiting for PriceRegistry deployment %+v", err) + return fmt.Errorf("error in waiting for PriceRegistry deployment %w", err) } } else { ccipModule.PriceRegistry, err = cd.NewPriceRegistry(ccipModule.PriceRegistry.EthAddress) if err != nil { - return fmt.Errorf("getting new PriceRegistry contract shouldn't fail %+v", err) + return fmt.Errorf("getting new PriceRegistry contract shouldn't fail %w", err) } } if ccipModule.MulticallContract == (common.Address{}) && ccipModule.MulticallEnabled { @@ -601,7 +604,7 @@ type SourceCCIPModule struct { DestNetworkName string OnRamp *contracts.OnRamp SrcStartBlock uint64 - CCIPSendRequestedWatcher sync.Map // map[string]*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested + CCIPSendRequestedWatcher *sync.Map // map[string]*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested NewFinalizedBlockNum atomic.Uint64 NewFinalizedBlockTimestamp atomic.Time } @@ -700,7 +703,7 @@ func (sourceCCIP *SourceCCIPModule) DeployContracts(lane *laneconfig.LaneConfig) sourceCCIP.SrcStartBlock, err = sourceCCIP.Common.ChainClient.LatestBlockNumber(context.Background()) if err != nil { - return fmt.Errorf("getting latest block number shouldn't fail %+v", err) + return fmt.Errorf("getting latest block number shouldn't fail %w", err) } sourceCCIP.OnRamp, err = contractDeployer.DeployOnRamp( sourceChainSelector, @@ -731,18 +734,18 @@ func (sourceCCIP *SourceCCIPModule) DeployContracts(lane *laneconfig.LaneConfig) ) if err != nil { - return fmt.Errorf("onRamp deployment shouldn't fail %+v", err) + return fmt.Errorf("onRamp deployment shouldn't fail %w", err) } err = sourceCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for onRamp deployment shouldn't fail %+v", err) + return fmt.Errorf("waiting for onRamp deployment shouldn't fail %w", err) } // update source Router with OnRamp address err = sourceCCIP.Common.Router.SetOnRamp(destChainSelector, sourceCCIP.OnRamp.EthAddress) if err != nil { - return fmt.Errorf("setting onramp on the router shouldn't fail %+v", err) + return fmt.Errorf("setting onramp on the router shouldn't fail %w", err) } // now sync the pools and tokens @@ -753,25 +756,25 @@ func (sourceCCIP *SourceCCIPModule) DeployContracts(lane *laneconfig.LaneConfig) err = sourceCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for events shouldn't fail %+v", err) + return fmt.Errorf("waiting for events shouldn't fail %w", err) } // update native pool with onRamp address for _, pool := range sourceCCIP.Common.BridgeTokenPools { err = pool.SetOnRamp(sourceCCIP.OnRamp.EthAddress) if err != nil { - return fmt.Errorf("setting OnRamp on the bridge token pool shouldn't fail %+v", err) + return fmt.Errorf("setting OnRamp on the bridge token pool shouldn't fail %w", err) } } err = sourceCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for events shouldn't fail %+v", err) + return fmt.Errorf("waiting for events shouldn't fail %w", err) } } else { sourceCCIP.OnRamp, err = contractDeployer.NewOnRamp(sourceCCIP.OnRamp.EthAddress) if err != nil { - return fmt.Errorf("getting new onramp contractshouldn't fail %+v", err) + return fmt.Errorf("getting new onramp contractshouldn't fail %w", err) } } @@ -886,7 +889,7 @@ func (sourceCCIP *SourceCCIPModule) AssertSendRequestedLogFinalized( for _, stat := range reqStats { stat.UpdateState(lggr, stat.SeqNum, testreporters.SourceLogFinalized, time.Since(prevEventAt), testreporters.Failure) } - return time.Time{}, 0, fmt.Errorf("error waiting for CCIPSendRequested event log to be finalized - %+v", err) + return time.Time{}, 0, fmt.Errorf("error waiting for CCIPSendRequested event log to be finalized - %w", err) } for _, stat := range reqStats { stat.UpdateState(lggr, stat.SeqNum, testreporters.SourceLogFinalized, finalizedAt.Sub(prevEventAt), testreporters.Success, @@ -956,12 +959,12 @@ func (sourceCCIP *SourceCCIPModule) CCIPMsg( } receiverAddr, err := utils.ABIEncode(`[{"type":"address"}]`, receiver) if err != nil { - return router.ClientEVM2AnyMessage{}, fmt.Errorf("failed encoding the receiver address: %+v", err) + return router.ClientEVM2AnyMessage{}, fmt.Errorf("failed encoding the receiver address: %w", err) } extraArgsV1, err := testhelpers.GetEVMExtraArgsV1(gasLimit, false) if err != nil { - return router.ClientEVM2AnyMessage{}, fmt.Errorf("failed encoding the options field: %+v", err) + return router.ClientEVM2AnyMessage{}, fmt.Errorf("failed encoding the options field: %w", err) } // form the message for transfer return router.ClientEVM2AnyMessage{ @@ -982,12 +985,12 @@ func (sourceCCIP *SourceCCIPModule) SendRequest( var d time.Duration destChainSelector, err := chainselectors.SelectorFromChainId(sourceCCIP.DestinationChainId) if err != nil { - return common.Hash{}, d, nil, fmt.Errorf("failed getting the chain selector: %+v", err) + return common.Hash{}, d, nil, fmt.Errorf("failed getting the chain selector: %w", err) } // form the message for transfer msg, err := sourceCCIP.CCIPMsg(receiver, msgType, data, gasLimit) if err != nil { - return common.Hash{}, d, nil, fmt.Errorf("failed forming the ccip msg: %+v", err) + return common.Hash{}, d, nil, fmt.Errorf("failed forming the ccip msg: %w", err) } fee, err := sourceCCIP.Common.Router.GetFee(destChainSelector, msg) if err != nil { @@ -995,7 +998,7 @@ func (sourceCCIP *SourceCCIPModule) SendRequest( if reason != "" { return common.Hash{}, d, nil, fmt.Errorf("failed getting the fee: %s", reason) } - return common.Hash{}, d, nil, fmt.Errorf("failed getting the fee: %+v", err) + return common.Hash{}, d, nil, fmt.Errorf("failed getting the fee: %w", err) } log.Info().Str("fee", fee.String()).Msg("calculated fee") @@ -1007,12 +1010,12 @@ func (sourceCCIP *SourceCCIPModule) SendRequest( if feeToken != (common.Address{}) { sendTx, err = sourceCCIP.Common.Router.CCIPSendAndProcessTx(destChainSelector, msg, nil) if err != nil { - return common.Hash{}, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %+v", err) + return common.Hash{}, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err) } } else { sendTx, err = sourceCCIP.Common.Router.CCIPSendAndProcessTx(destChainSelector, msg, fee) if err != nil { - return common.Hash{}, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %+v", err) + return common.Hash{}, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err) } } @@ -1035,11 +1038,12 @@ func DefaultSourceCCIPModule(logger zerolog.Logger, chainClient blockchain.EVMCl transferAmount = transferAmount[:len(cmn.BridgeTokens)] } return &SourceCCIPModule{ - Common: cmn, - TransferAmount: transferAmount, - DestinationChainId: destChainId, - DestNetworkName: destChain, - Sender: common.HexToAddress(chainClient.GetDefaultWallet().Address()), + Common: cmn, + TransferAmount: transferAmount, + DestinationChainId: destChainId, + DestNetworkName: destChain, + Sender: common.HexToAddress(chainClient.GetDefaultWallet().Address()), + CCIPSendRequestedWatcher: &sync.Map{}, }, nil } @@ -1051,9 +1055,9 @@ type DestCCIPModule struct { ReceiverDapp *contracts.ReceiverDapp OffRamp *contracts.OffRamp WrappedNative common.Address - ReportAcceptedWatcher sync.Map - ExecStateChangedWatcher sync.Map - ReportBlessedWatcher sync.Map + ReportAcceptedWatcher *sync.Map + ExecStateChangedWatcher *sync.Map + ReportBlessedWatcher *sync.Map NextSeqNumToCommit *atomic.Uint64 } @@ -1122,26 +1126,26 @@ func (destCCIP *DestCCIPModule) DeployContracts( *destCCIP.Common.ARMContract, ) if err != nil { - return fmt.Errorf("deploying commitstore shouldn't fail %+v", err) + return fmt.Errorf("deploying commitstore shouldn't fail %w", err) } err = destCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for commitstore deployment shouldn't fail %+v", err) + return fmt.Errorf("waiting for commitstore deployment shouldn't fail %w", err) } // CommitStore can update err = destCCIP.Common.PriceRegistry.AddPriceUpdater(destCCIP.CommitStore.EthAddress) if err != nil { - return fmt.Errorf("setting commitstore as fee updater shouldn't fail %+v", err) + return fmt.Errorf("setting commitstore as fee updater shouldn't fail %w", err) } err = destCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for setting commitstore as fee updater shouldn't fail %+v", err) + return fmt.Errorf("waiting for setting commitstore as fee updater shouldn't fail %w", err) } } else { destCCIP.CommitStore, err = contractDeployer.NewCommitStore(destCCIP.CommitStore.EthAddress) if err != nil { - return fmt.Errorf("getting new commitstore shouldn't fail %+v", err) + return fmt.Errorf("getting new commitstore shouldn't fail %w", err) } } @@ -1154,60 +1158,60 @@ func (destCCIP *DestCCIPModule) DeployContracts( destCCIP.CommitStore.EthAddress, sourceCCIP.OnRamp.EthAddress, []common.Address{}, []common.Address{}, destCCIP.Common.RateLimiterConfig, *destCCIP.Common.ARMContract) if err != nil { - return fmt.Errorf("deploying offramp shouldn't fail %+v", err) + return fmt.Errorf("deploying offramp shouldn't fail %w", err) } err = destCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for offramp deployment shouldn't fail %+v", err) + return fmt.Errorf("waiting for offramp deployment shouldn't fail %w", err) } // apply offramp updates _, err = destCCIP.Common.Router.AddOffRamp(destCCIP.OffRamp.EthAddress, sourceChainSelector) if err != nil { - return fmt.Errorf("setting offramp as fee updater shouldn't fail %+v", err) + return fmt.Errorf("setting offramp as fee updater shouldn't fail %w", err) } err = destCCIP.SyncTokensAndPools(sourceCCIP.Common.BridgeTokens) if err != nil { - return fmt.Errorf("syncing tokens and pools shouldn't fail %+v", err) + return fmt.Errorf("syncing tokens and pools shouldn't fail %w", err) } err = destCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for events on destination contract shouldn't fail %+v", err) + return fmt.Errorf("waiting for events on destination contract shouldn't fail %w", err) } // update pools with offRamp id for _, pool := range destCCIP.Common.BridgeTokenPools { err = pool.SetOffRamp(destCCIP.OffRamp.EthAddress) if err != nil { - return fmt.Errorf("setting offramp on the bridge token pool shouldn't fail %+v", err) + return fmt.Errorf("setting offramp on the bridge token pool shouldn't fail %w", err) } } err = destCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for events on destination contract shouldn't fail %+v", err) + return fmt.Errorf("waiting for events on destination contract shouldn't fail %w", err) } } else { destCCIP.OffRamp, err = contractDeployer.NewOffRamp(destCCIP.OffRamp.EthAddress) if err != nil { - return fmt.Errorf("getting new offramp shouldn't fail %+v", err) + return fmt.Errorf("getting new offramp shouldn't fail %w", err) } } if destCCIP.ReceiverDapp == nil { // ReceiverDapp destCCIP.ReceiverDapp, err = contractDeployer.DeployReceiverDapp(false) if err != nil { - return fmt.Errorf("receiverDapp contract should be deployed successfully %+v", err) + return fmt.Errorf("receiverDapp contract should be deployed successfully %w", err) } err = destCCIP.Common.ChainClient.WaitForEvents() if err != nil { - return fmt.Errorf("waiting for events on destination contract deployments %+v", err) + return fmt.Errorf("waiting for events on destination contract deployments %w", err) } } else { destCCIP.ReceiverDapp, err = contractDeployer.NewReceiverDapp(destCCIP.ReceiverDapp.EthAddress) if err != nil { - return fmt.Errorf("getting new receiverDapp shouldn't fail %+v", err) + return fmt.Errorf("getting new receiverDapp shouldn't fail %w", err) } } return nil @@ -1328,16 +1332,15 @@ func (destCCIP *DestCCIPModule) AssertEventExecutionStateChanged( GasUsed: gasUsed, }) return e.State, nil - } else { - reqStat.UpdateState(lggr, seqNum, testreporters.ExecStateChanged, time.Since(timeNow), testreporters.Failure) - return e.State, fmt.Errorf("ExecutionStateChanged event state - expected %d actual - %d with data %x for seq num %v for lane %d-->%d", - execState, testhelpers.MessageExecutionState(e.State), e.ReturnData, seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID()) } + reqStat.UpdateState(lggr, seqNum, testreporters.ExecStateChanged, time.Since(timeNow), testreporters.Failure) + return e.State, fmt.Errorf("ExecutionStateChanged event state - expected %d actual - %d with data %x for seq num %v for lane %d-->%d", + execState, testhelpers.MessageExecutionState(e.State), e.ReturnData, seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID()) } } case <-ctx.Done(): reqStat.UpdateState(lggr, seqNum, testreporters.ExecStateChanged, time.Since(timeNow), testreporters.Failure) - return 0, fmt.Errorf("ExecutionStateChanged event not found for seq num %v for lane %d-->%d", + return 0, fmt.Errorf("ExecutionStateChanged event not found for seq num %d for lane %d-->%d", seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID()) } } @@ -1483,7 +1486,7 @@ func (destCCIP *DestCCIPModule) AssertSeqNumberExecuted( seqNumberAfter, err := destCCIP.CommitStore.Instance.GetExpectedNextSequenceNumber(nil) if err != nil { reqStat.UpdateState(lggr, seqNumberBefore, testreporters.Commit, time.Since(timeNow), testreporters.Failure) - return fmt.Errorf("error %+v in GetNextExpectedSeqNumber by commitStore for seqNum %d lane %d-->%d", + return fmt.Errorf("error %w in GetNextExpectedSeqNumber by commitStore for seqNum %d lane %d-->%d", err, seqNumberBefore+1, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID()) } if seqNumberAfter > seqNumberBefore { @@ -1504,10 +1507,13 @@ func DefaultDestinationCCIPModule(logger zerolog.Logger, chainClient blockchain. return nil, err } return &DestCCIPModule{ - Common: cmn, - SourceChainId: sourceChainId, - SourceNetworkName: sourceChain, - NextSeqNumToCommit: atomic.NewUint64(1), + Common: cmn, + SourceChainId: sourceChainId, + SourceNetworkName: sourceChain, + NextSeqNumToCommit: atomic.NewUint64(1), + ReportBlessedWatcher: &sync.Map{}, + ExecStateChangedWatcher: &sync.Map{}, + ReportAcceptedWatcher: &sync.Map{}, }, nil } @@ -1519,7 +1525,6 @@ type CCIPRequest struct { } func CCIPRequestFromTxHash(txHash common.Hash, chainClient blockchain.EVMClient) (CCIPRequest, *types.Receipt, error) { - txConfirmationTimestamp := time.Now().UTC() rcpt, err := chainClient.GetTxReceipt(txHash) if err != nil { return CCIPRequest{}, nil, err @@ -1529,7 +1534,7 @@ func CCIPRequestFromTxHash(txHash common.Hash, chainClient blockchain.EVMClient) if err != nil { return CCIPRequest{}, nil, err } - txConfirmationTimestamp = hdr.Timestamp + txConfirmationTimestamp := hdr.Timestamp return CCIPRequest{ txHash: txHash.Hex(), @@ -1641,7 +1646,7 @@ func (lane *CCIPLane) AddToSentReqs(txHash common.Hash, reqStats []*testreporter for _, stat := range reqStats { stat.UpdateState(lane.Logger, 0, testreporters.TX, 0, testreporters.Failure) } - return rcpt, fmt.Errorf("could not get request from tx hash %s: %+v", txHash.Hex(), err) + return rcpt, fmt.Errorf("could not get request from tx hash %s: %w", txHash.Hex(), err) } var allRequests []CCIPRequest for _, stat := range reqStats { @@ -1664,11 +1669,11 @@ func (lane *CCIPLane) Multicall(noOfRequests int, msgType string, multiSendAddr feeToken := common.HexToAddress(lane.Source.Common.FeeToken.Address()) genericMsg, err := lane.Source.CCIPMsg(lane.Dest.ReceiverDapp.EthAddress, msgType, "testMsg", big.NewInt(600_000)) if err != nil { - return fmt.Errorf("failed to form the ccip message: %+v", err) + return fmt.Errorf("failed to form the ccip message: %w", err) } destChainSelector, err := chainselectors.SelectorFromChainId(lane.Source.DestinationChainId) if err != nil { - return fmt.Errorf("failed getting the chain selector: %+v", err) + return fmt.Errorf("failed getting the chain selector: %w", err) } var reqStats []*testreporters.RequestStat var txstats []testreporters.TransactionStats @@ -1688,7 +1693,7 @@ func (lane *CCIPLane) Multicall(noOfRequests int, msgType string, multiSendAddr if reason != "" { return fmt.Errorf("failed getting the fee: %s", reason) } - return fmt.Errorf("failed getting the fee: %+v", err) + return fmt.Errorf("failed getting the fee: %w", err) } log.Info().Str("fee", fee.String()).Msg("calculated fee") sendData.Fee = fee @@ -1724,7 +1729,7 @@ func (lane *CCIPLane) Multicall(noOfRequests int, msgType string, multiSendAddr tx, err := contracts.MultiCallCCIP(lane.Source.Common.ChainClient, multiSendAddr.Hex(), ccipMultipleMsg, isNative) if err != nil { - return fmt.Errorf("failed to send the multicall: %+v", err) + return fmt.Errorf("failed to send the multicall: %w", err) } if err != nil { // update the stats as failure for all the requests in the multicall tx @@ -1732,7 +1737,7 @@ func (lane *CCIPLane) Multicall(noOfRequests int, msgType string, multiSendAddr stat.UpdateState(lane.Logger, 0, testreporters.TX, 0, testreporters.Failure) } - return fmt.Errorf("failed to send the multicall: %+v", err) + return fmt.Errorf("failed to send the multicall: %w", err) } rcpt, err := lane.AddToSentReqs(tx.Hash(), reqStats) if err != nil { @@ -1764,13 +1769,13 @@ func (lane *CCIPLane) SendRequests(noOfRequests int, msgType string, gasLimit *b if err != nil { stat.UpdateState(lane.Logger, 0, testreporters.TX, txConfirmationDur, testreporters.Failure) - return fmt.Errorf("could not send request: %+v", err) + return fmt.Errorf("could not send request: %w", err) } err = lane.Source.Common.ChainClient.WaitForEvents() if err != nil { stat.UpdateState(lane.Logger, 0, testreporters.TX, txConfirmationDur, testreporters.Failure) - return fmt.Errorf("could not send request: %+v", err) + return fmt.Errorf("could not send request: %w", err) } noOfTokens := len(lane.Source.TransferAmount) @@ -1868,21 +1873,21 @@ func (lane *CCIPLane) ExecuteManually() error { timeNow := time.Now().UTC() tx, err := args.ExecuteManually() if err != nil { - return fmt.Errorf("could not execute manually: %v seqNum %d", err, seqNum) + return fmt.Errorf("could not execute manually: %w seqNum %d", err, seqNum) } rec, err := bind.WaitMined(context.Background(), lane.DestChain.DeployBackend(), tx) if err != nil { - return fmt.Errorf("could not get receipt: %v seqNum %d", err, seqNum) + return fmt.Errorf("could not get receipt: %w seqNum %d", err, seqNum) } if rec.Status != 1 { - return fmt.Errorf("manual execution failed: %v seqNum %d", err, seqNum) + return fmt.Errorf("manual execution failed: %w seqNum %d", err, seqNum) } lane.Logger.Info().Uint64("seqNum", seqNum).Msg("Manual Execution completed") _, err = lane.Dest.AssertEventExecutionStateChanged(lane.Logger, seqNum, lane.ValidationTimeout, timeNow, ccipReq.RequestStat, testhelpers.ExecutionStateSuccess) if err != nil { - return fmt.Errorf("could not validate ExecutionStateChanged event: %+v", err) + return fmt.Errorf("could not validate ExecutionStateChanged event: %w", err) } } } @@ -1915,19 +1920,23 @@ func (lane *CCIPLane) ValidateRequestByTxHash(txHash common.Hash, execState test ccipRequests := lane.SentReqs[txHash] require.Greater(lane.Test, len(ccipRequests), 0, "no ccip requests found for tx hash") txConfirmation := ccipRequests[0].txConfirmationTimestamp + defer func() { + for _, req := range ccipRequests { + lane.Reports.UpdatePhaseStatsForReq(req.RequestStat) + } + }() for _, req := range ccipRequests { reqStats = append(reqStats, req.RequestStat) - defer lane.Reports.UpdatePhaseStatsForReq(req.RequestStat) } msgLogs, ccipSendReqGenAt, err := lane.Source.AssertEventCCIPSendRequested( lane.Logger, txHash.Hex(), lane.ValidationTimeout, txConfirmation, reqStats) if err != nil || msgLogs == nil { - return fmt.Errorf("could not validate CCIPSendRequested event: %+v", err) + return fmt.Errorf("could not validate CCIPSendRequested event: %w", err) } sourceLogFinalizedAt, _, err := lane.Source.AssertSendRequestedLogFinalized(lane.Logger, txHash, ccipSendReqGenAt, reqStats) if err != nil { - return fmt.Errorf("could not finalize CCIPSendRequested event: %+v", err) + return fmt.Errorf("could not finalize CCIPSendRequested event: %w", err) } for _, msgLog := range msgLogs { seqNumber := msgLog.Message.SequenceNumber @@ -1944,24 +1953,24 @@ func (lane *CCIPLane) ValidateRequestByTxHash(txHash common.Hash, execState test err = lane.Dest.AssertSeqNumberExecuted(lane.Logger, seqNumber, lane.ValidationTimeout, sourceLogFinalizedAt, reqStat) if err != nil { - return fmt.Errorf("could not validate seq number increase at commit store: %+v", err) + return fmt.Errorf("could not validate seq number increase at commit store: %w", err) } // Verify whether commitStore has accepted the report commitReport, reportAcceptedAt, err := lane.Dest.AssertEventReportAccepted( lane.Logger, seqNumber, lane.ValidationTimeout, sourceLogFinalizedAt, reqStat) if err != nil || commitReport == nil { - return fmt.Errorf("could not validate ReportAccepted event: %+v", err) + return fmt.Errorf("could not validate ReportAccepted event: %w", err) } reportBlessedAt, err := lane.Dest.AssertReportBlessed(lane.Logger, seqNumber, lane.ValidationTimeout, *commitReport, reportAcceptedAt, reqStat) if err != nil { - return fmt.Errorf("could not validate ReportBlessed event: %+v", err) + return fmt.Errorf("could not validate ReportBlessed event: %w", err) } // Verify whether the execution state is changed and the transfer is successful _, err = lane.Dest.AssertEventExecutionStateChanged(lane.Logger, seqNumber, lane.ValidationTimeout, reportBlessedAt, reqStat, execState) if err != nil { - return fmt.Errorf("could not validate ExecutionStateChanged event: %+v", err) + return fmt.Errorf("could not validate ExecutionStateChanged event: %w", err) } } return nil @@ -2180,7 +2189,7 @@ func (lane *CCIPLane) DeployNewCCIPLane( // Here for simplicity we are just taking the current block number just before the job is created. currentBlockOnDest, err := destChainClient.LatestBlockNumber(context.Background()) if err != nil { - return lane.SrcNetworkLaneCfg, lane.DstNetworkLaneCfg, fmt.Errorf("getting current block should be successful in destination chain %+v", err) + return lane.SrcNetworkLaneCfg, lane.DstNetworkLaneCfg, fmt.Errorf("getting current block should be successful in destination chain %w", err) } tokenUSDMap := make(map[string]string) @@ -2213,18 +2222,14 @@ func (lane *CCIPLane) DeployNewCCIPLane( } bootstrapCommitP2PId := bootstrapCommit.KeysBundle.P2PKeys.Data[0].Attributes.PeerID - var bootstrapExecP2PId string var p2pBootstrappersExec, p2pBootstrappersCommit *client.P2PData - if bootstrapExec == nil { - bootstrapExec = bootstrapCommit - bootstrapExecP2PId = bootstrapCommitP2PId - } else { - bootstrapExecP2PId = bootstrapExec.KeysBundle.P2PKeys.Data[0].Attributes.PeerID + if bootstrapExec != nil { p2pBootstrappersExec = &client.P2PData{ InternalIP: bootstrapExec.Node.InternalIP(), - PeerID: bootstrapExecP2PId, + PeerID: bootstrapExec.KeysBundle.P2PKeys.Data[0].Attributes.PeerID, } } + p2pBootstrappersCommit = &client.P2PData{ InternalIP: bootstrapCommit.Node.InternalIP(), PeerID: bootstrapCommitP2PId, @@ -2332,12 +2337,12 @@ func CreateBootstrapJob( ) error { _, err := bootstrapCommit.Node.MustCreateJob(jobParams.BootstrapJob(jobParams.CommitStore.Hex())) if err != nil { - return fmt.Errorf("shouldn't fail creating bootstrap job on bootstrap node %+v", err) + return fmt.Errorf("shouldn't fail creating bootstrap job on bootstrap node %w", err) } if bootstrapExec != nil { _, err := bootstrapExec.Node.MustCreateJob(jobParams.BootstrapJob(jobParams.OffRamp.Hex())) if err != nil { - return fmt.Errorf("shouldn't fail creating bootstrap job on bootstrap node %+v", err) + return fmt.Errorf("shouldn't fail creating bootstrap job on bootstrap node %w", err) } } return nil @@ -2362,15 +2367,21 @@ func CreateOCR2CCIPCommitJobs( lggr.Info().Msgf("Creating CCIP-Commit job on OCR node %d job name %s", index+1, ocr2SpecCommit.Name) _, err = node.Node.MustCreateJob(&ocr2SpecCommit) if err != nil { - return fmt.Errorf("shouldn't fail creating CCIP-Commit job on OCR node %d job name %s - %+v", index+1, ocr2SpecCommit.Name, err) + return fmt.Errorf("shouldn't fail creating CCIP-Commit job on OCR node %d job name %s - %w", index+1, ocr2SpecCommit.Name, err) } return nil } + + testSpec := client.OCR2TaskJobSpec{ + Name: ocr2SpecCommit.Name, + JobType: ocr2SpecCommit.JobType, + OCR2OracleSpec: ocr2SpecCommit.OCR2OracleSpec, + } for i, node := range commitNodes { node := node i := i group.Go(func() error { - return createJob(i, node, *ocr2SpecCommit, mutexes[i]) + return createJob(i, node, testSpec, mutexes[i]) }) } return nil @@ -2395,7 +2406,7 @@ func CreateOCR2CCIPExecutionJobs( lggr.Info().Msgf("Creating CCIP-Exec job on OCR node %d job name %s", index+1, ocr2SpecExec.Name) _, err = node.Node.MustCreateJob(&ocr2SpecExec) if err != nil { - return fmt.Errorf("shouldn't fail creating CCIP-Exec job on OCR node %d job name %s - %+v", index+1, + return fmt.Errorf("shouldn't fail creating CCIP-Exec job on OCR node %d job name %s - %w", index+1, ocr2SpecExec.Name, err) } return nil @@ -2405,7 +2416,14 @@ func CreateOCR2CCIPExecutionJobs( node := node i := i group.Go(func() error { - return createJob(i, node, *ocr2SpecExec, mutexes[i]) + return createJob(i, node, client.OCR2TaskJobSpec{ + Name: ocr2SpecExec.Name, + JobType: ocr2SpecExec.JobType, + MaxTaskDuration: ocr2SpecExec.MaxTaskDuration, + ForwardingAllowed: ocr2SpecExec.ForwardingAllowed, + OCR2OracleSpec: ocr2SpecExec.OCR2OracleSpec, + ObservationSource: ocr2SpecExec.ObservationSource, + }, mutexes[i]) }) } } @@ -2413,7 +2431,7 @@ func CreateOCR2CCIPExecutionJobs( } // TODO : keep it if there is a better mockserver implementation is found -func _(tokenAddr []string, mockserver *ctfClient.MockserverClient) string { +func _(tokenAddr []string, mockserver *ctfclient.MockserverClient) string { source := "" right := "" for i, addr := range tokenAddr { @@ -2442,27 +2460,6 @@ func StaticTokenFeeForMultipleTokenAddr(tokenUSD map[string]string) string { return source } -// SetMockServerWithSameTokenFeeConversionValue sets the mock responses in mockserver that are read by chainlink nodes -// to simulate different price feed value. -func SetMockServerWithSameTokenFeeConversionValue( - ctx context.Context, - tokenValueAddress map[string]interface{}, - mockserver *ctfClient.MockserverClient, -) error { - valueAdditions, _ := errgroup.WithContext(ctx) - for tokenAddr, value := range tokenValueAddress { - path := fmt.Sprintf("/%s", tokenAddr) - tokenValue := value - valueAdditions.Go(func() error { - log.Info().Str("path", path). - Str("value", fmt.Sprintf("%v", tokenValue)). - Msg(fmt.Sprintf("Setting mockserver response")) - return mockserver.SetAnyValuePath(path, tokenValue) - }) - } - return valueAdditions.Wait() -} - type CCIPTestEnv struct { LocalCluster *test_env.CLClusterTestEnv CLNodesWithKeys map[string][]*client.CLNodesWithKeys // key - network chain-id @@ -2547,7 +2544,6 @@ func (c *CCIPTestEnv) ChaosLabelForCLNodes(t *testing.T) { } func (c *CCIPTestEnv) SetUpNodesAndKeys( - ctx context.Context, nodeFund *big.Float, chains []blockchain.EVMClient, logger zerolog.Logger, @@ -2604,7 +2600,7 @@ func (c *CCIPTestEnv) SetUpNodesAndKeys( } c1, err := blockchain.ConcurrentEVMClient(*cfg, c.K8Env, ec, logger) if err != nil { - return fmt.Errorf("getting concurrent evmclient chain %s %+v", ec.GetNetworkName(), err) + return fmt.Errorf("getting concurrent evmclient chain %s %w", ec.GetNetworkName(), err) } defer func() { if c1 != nil { @@ -2614,7 +2610,7 @@ func (c *CCIPTestEnv) SetUpNodesAndKeys( log.Info().Str("chain id", c1.GetChainID().String()).Msg("Funding Chainlink nodes for chain") err = actions.FundChainlinkNodesAddresses(chainlinkNodes[1:], c1, nodeFund) if err != nil { - return fmt.Errorf("funding nodes for chain %s %+v", c1.GetNetworkName(), err) + return fmt.Errorf("funding nodes for chain %s %w", c1.GetNetworkName(), err) } return nil } diff --git a/integration-tests/ccip-tests/chaos/ccip_test.go b/integration-tests/ccip-tests/chaos/ccip_test.go index 6db7a45ff5..daf887879c 100644 --- a/integration-tests/ccip-tests/chaos/ccip_test.go +++ b/integration-tests/ccip-tests/chaos/ccip_test.go @@ -5,10 +5,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" diff --git a/integration-tests/ccip-tests/contracts/contract_deployer.go b/integration-tests/ccip-tests/contracts/contract_deployer.go index 2b007b3e55..ea91640a5c 100644 --- a/integration-tests/ccip-tests/contracts/contract_deployer.go +++ b/integration-tests/ccip-tests/contracts/contract_deployer.go @@ -9,14 +9,17 @@ import ( "strings" "time" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ocrConfigHelper2 "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" + + ocrconfighelper2 "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2/types" "golang.org/x/crypto/curve25519" @@ -585,7 +588,7 @@ func OffChainAggregatorV2ConfigWithNodes(numberNodes int, inflightExpiry time.Du RMax: 3, S: s, F: faultyNodes, - Oracles: []ocrConfigHelper2.OracleIdentityExtra{}, + Oracles: []ocrconfighelper2.OracleIdentityExtra{}, MaxDurationQuery: cfg.MaxDurationQuery, MaxDurationObservation: cfg.MaxDurationObservation, MaxDurationReport: cfg.MaxDurationReport, @@ -618,7 +621,7 @@ func NewOffChainAggregatorV2ConfigForCCIPPlugin[T ccipconfig.OffchainConfig]( offchainConfig []byte, err error, ) { - oracleIdentities := make([]ocrConfigHelper2.OracleIdentityExtra, 0) + oracleIdentities := make([]ocrconfighelper2.OracleIdentityExtra, 0) ocrConfig := OffChainAggregatorV2ConfigWithNodes(len(nodes), inflightExpiry, ocr2Params) var onChainKeys []ocrtypes2.OnchainPublicKey for i, nodeWithKeys := range nodes { @@ -639,8 +642,8 @@ func NewOffChainAggregatorV2ConfigForCCIPPlugin[T ccipconfig.OffchainConfig]( ethAddress := nodeWithKeys.KeysBundle.EthAddress p2pKeys := nodeWithKeys.KeysBundle.P2PKeys peerID := p2pKeys.Data[0].Attributes.PeerID - oracleIdentities = append(oracleIdentities, ocrConfigHelper2.OracleIdentityExtra{ - OracleIdentity: ocrConfigHelper2.OracleIdentity{ + oracleIdentities = append(oracleIdentities, ocrconfighelper2.OracleIdentityExtra{ + OracleIdentity: ocrconfighelper2.OracleIdentity{ OffchainPublicKey: offChainPubKey, OnchainPublicKey: common.HexToAddress(formattedOnChainPubKey).Bytes(), PeerID: peerID, @@ -665,7 +668,7 @@ func NewOffChainAggregatorV2ConfigForCCIPPlugin[T ccipconfig.OffchainConfig]( return nil, nil, 0, nil, 0, nil, err } - _, _, f_, onchainConfig_, offchainConfigVersion, offchainConfig, err = ocrConfigHelper2.ContractSetConfigArgsForTests( + _, _, f_, onchainConfig_, offchainConfigVersion, offchainConfig, err = ocrconfighelper2.ContractSetConfigArgsForTests( ocrConfig.DeltaProgress, ocrConfig.DeltaResend, ocrConfig.DeltaRound, diff --git a/integration-tests/ccip-tests/contracts/contract_models.go b/integration-tests/ccip-tests/contracts/contract_models.go index 2f4d426e20..b3dd9d9b80 100644 --- a/integration-tests/ccip-tests/contracts/contract_models.go +++ b/integration-tests/ccip-tests/contracts/contract_models.go @@ -6,10 +6,12 @@ import ( "math/big" "strconv" + "github.com/rs/zerolog/log" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract" @@ -60,43 +62,43 @@ func (token *ERC20Token) BalanceOf(ctx context.Context, addr string) (*big.Int, return balance, nil } -func (l *ERC20Token) Approve(to string, amount *big.Int) error { - opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) +func (token *ERC20Token) Approve(to string, amount *big.Int) error { + opts, err := token.client.TransactionOpts(token.client.GetDefaultWallet()) if err != nil { return err } log.Info(). - Str("From", l.client.GetDefaultWallet().Address()). + Str("From", token.client.GetDefaultWallet().Address()). Str("To", to). - Str("Token", l.Address()). + Str("Token", token.Address()). Str("Amount", amount.String()). Uint64("Nonce", opts.Nonce.Uint64()). - Str("Network Name", l.client.GetNetworkConfig().Name). + Str("Network Name", token.client.GetNetworkConfig().Name). Msg("Approving ERC20 Transfer") - tx, err := l.instance.Approve(opts, common.HexToAddress(to), amount) + tx, err := token.instance.Approve(opts, common.HexToAddress(to), amount) if err != nil { return err } - return l.client.ProcessTransaction(tx) + return token.client.ProcessTransaction(tx) } -func (l *ERC20Token) Transfer(to string, amount *big.Int) error { - opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) +func (token *ERC20Token) Transfer(to string, amount *big.Int) error { + opts, err := token.client.TransactionOpts(token.client.GetDefaultWallet()) if err != nil { return err } log.Info(). - Str("From", l.client.GetDefaultWallet().Address()). + Str("From", token.client.GetDefaultWallet().Address()). Str("To", to). Str("Amount", amount.String()). Uint64("Nonce", opts.Nonce.Uint64()). - Str("Network Name", l.client.GetNetworkConfig().Name). + Str("Network Name", token.client.GetNetworkConfig().Name). Msg("Transferring ERC20") - tx, err := l.instance.Transfer(opts, common.HexToAddress(to), amount) + tx, err := token.instance.Transfer(opts, common.HexToAddress(to), amount) if err != nil { return err } - return l.client.ProcessTransaction(tx) + return token.client.ProcessTransaction(tx) } type LinkToken struct { @@ -105,16 +107,16 @@ type LinkToken struct { EthAddress common.Address } -func (token *LinkToken) Address() string { - return token.EthAddress.Hex() +func (l *LinkToken) Address() string { + return l.EthAddress.Hex() } -func (token *LinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { +func (l *LinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(token.client.GetDefaultWallet().Address()), + From: common.HexToAddress(l.client.GetDefaultWallet().Address()), Context: ctx, } - balance, err := token.instance.BalanceOf(opts, common.HexToAddress(addr)) + balance, err := l.instance.BalanceOf(opts, common.HexToAddress(addr)) if err != nil { return nil, err } @@ -354,8 +356,8 @@ type CommitStore struct { EthAddress common.Address } -func (bv *CommitStore) Address() string { - return bv.EthAddress.Hex() +func (b *CommitStore) Address() string { + return b.EthAddress.Hex() } // SetOCR2Config sets the offchain reporting protocol configuration diff --git a/integration-tests/ccip-tests/contracts/multicall.go b/integration-tests/ccip-tests/contracts/multicall.go index 8d75cbd923..e03c978b92 100644 --- a/integration-tests/ccip-tests/contracts/multicall.go +++ b/integration-tests/ccip-tests/contracts/multicall.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -251,7 +252,7 @@ func TransferTokens( boundContract := bind.NewBoundContract(contractAddress, multiCallABI, evmClient.Backend(), evmClient.Backend(), evmClient.Backend()) for _, token := range tokens { var inputs []byte - balance, err := token.BalanceOf(nil, contractAddress.Hex()) + balance, err := token.BalanceOf(context.Background(), contractAddress.Hex()) if err != nil { return err } diff --git a/integration-tests/ccip-tests/load/ccip_loadgen.go b/integration-tests/ccip-tests/load/ccip_loadgen.go index 0cd73c427e..2c06c9a608 100644 --- a/integration-tests/ccip-tests/load/ccip_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_loadgen.go @@ -137,8 +137,8 @@ func (c *CCIPE2ELoad) CCIPMsg() (router.ClientEVM2AnyMessage, *testreporters.Req return msg, stats } -func (c *CCIPE2ELoad) Call(_ *wasp.Generator) *wasp.CallResult { - res := &wasp.CallResult{} +func (c *CCIPE2ELoad) Call(_ *wasp.Generator) *wasp.Response { + res := &wasp.Response{} sourceCCIP := c.Lane.Source msg, stats := c.CCIPMsg() diff --git a/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go index c46deaad63..4fe7e30865 100644 --- a/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go @@ -12,11 +12,12 @@ import ( "github.com/prometheus/common/model" "github.com/rs/zerolog" chain_selectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/wasp" "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters" @@ -140,8 +141,8 @@ func (m *CCIPMultiCallLoadGenerator) HandleLokiLogs(rValues map[string]MultiCall } } -func (m *CCIPMultiCallLoadGenerator) Call(_ *wasp.Generator) *wasp.CallResult { - res := &wasp.CallResult{} +func (m *CCIPMultiCallLoadGenerator) Call(_ *wasp.Generator) *wasp.Response { + res := &wasp.Response{} msgs, returnValuesByDest, err := m.MergeCalls() if err != nil { res.Error = err.Error() @@ -176,7 +177,7 @@ func (m *CCIPMultiCallLoadGenerator) Call(_ *wasp.Generator) *wasp.CallResult { } for _, rValues := range returnValuesByDest { if len(rValues.Stats) != len(rValues.Msgs) { - res.Error = fmt.Sprintf("number of stats and msgs should be same") + res.Error = fmt.Sprintf("number of stats %d and msgs %d should be same", len(rValues.Stats), len(rValues.Msgs)) res.Failed = true return res } diff --git a/integration-tests/ccip-tests/load/ccip_test.go b/integration-tests/ccip-tests/load/ccip_test.go index 46e1a7052c..3da72bc01a 100644 --- a/integration-tests/ccip-tests/load/ccip_test.go +++ b/integration-tests/ccip-tests/load/ccip_test.go @@ -1,15 +1,15 @@ package load import ( - "context" "testing" "time" "github.com/rs/zerolog/log" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -18,7 +18,7 @@ import ( func TestLoadCCIPStableRPS(t *testing.T) { t.Parallel() lggr := logging.GetTestLogger(t) - testArgs := NewLoadArgs(t, lggr, context.Background()) + testArgs := NewLoadArgs(t, lggr) testArgs.Setup() // if the test runs on remote runner if len(testArgs.TestSetupArgs.Lanes) == 0 { @@ -35,7 +35,7 @@ func TestLoadCCIPStableRPS(t *testing.T) { func TestLoadCCIPStableRPSTriggerBySource(t *testing.T) { t.Parallel() lggr := logging.GetTestLogger(t) - testArgs := NewLoadArgs(t, lggr, context.Background()) + testArgs := NewLoadArgs(t, lggr) testArgs.TestCfg.TestGroupInput.MulticallInOneTx = ptr.Ptr(true) testArgs.Setup() // if the test runs on remote runner @@ -53,7 +53,7 @@ func TestLoadCCIPStableRPSTriggerBySource(t *testing.T) { func TestLoadCCIPStableRequestTriggeringWithNetworkChaos(t *testing.T) { t.Parallel() lggr := logging.GetTestLogger(t) - testArgs := NewLoadArgs(t, lggr, context.Background()) + testArgs := NewLoadArgs(t, lggr) testArgs.Setup() // if the test runs on remote runner if len(testArgs.TestSetupArgs.Lanes) == 0 { @@ -113,7 +113,7 @@ func TestLoadCCIPStableWithMajorityNodeFailure(t *testing.T) { } lggr := logging.GetTestLogger(t) - testArgs := NewLoadArgs(t, lggr, context.Background(), inputs...) + testArgs := NewLoadArgs(t, lggr, inputs...) var allChaosDur time.Duration // to override the default duration of chaos with test input @@ -167,7 +167,7 @@ func TestLoadCCIPStableWithMinorityNodeFailure(t *testing.T) { } lggr := logging.GetTestLogger(t) - testArgs := NewLoadArgs(t, lggr, context.Background(), inputs...) + testArgs := NewLoadArgs(t, lggr, inputs...) var allChaosDur time.Duration // to override the default duration of chaos with test input @@ -246,7 +246,7 @@ func TestLoadCCIPStableWithPodChaosDiffCommitAndExec(t *testing.T) { t.Run(in.ChaosName, func(t *testing.T) { t.Parallel() lggr := logging.GetTestLogger(t) - testArgs := NewLoadArgs(t, lggr, context.Background(), in) + testArgs := NewLoadArgs(t, lggr, in) testArgs.TestCfg.TestGroupInput.TestDuration = models.MustNewDuration(5 * time.Minute) testArgs.TestCfg.TestGroupInput.TimeUnit = models.MustNewDuration(1 * time.Second) testArgs.TestCfg.TestGroupInput.RequestPerUnitTime = []int64{2} diff --git a/integration-tests/ccip-tests/load/helper.go b/integration-tests/ccip-tests/load/helper.go index a049ea6c70..c5a15336e4 100644 --- a/integration-tests/ccip-tests/load/helper.go +++ b/integration-tests/ccip-tests/load/helper.go @@ -1,7 +1,6 @@ package load import ( - "context" "fmt" "math" "math/big" @@ -11,11 +10,13 @@ import ( "github.com/AlekSi/pointer" "github.com/rs/zerolog" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" @@ -29,7 +30,7 @@ type ChaosConfig struct { WaitBetweenChaos time.Duration } -type loadArgs struct { +type LoadArgs struct { t *testing.T lggr zerolog.Logger schedules []*wasp.Segment @@ -41,7 +42,7 @@ type loadArgs struct { LoadgenTearDowns []func() } -func (l *loadArgs) Setup() { +func (l *LoadArgs) Setup() { lggr := l.lggr existing := pointer.GetBool(l.TestCfg.TestGroupInput.ExistingDeployment) envName := "load-ccip" @@ -51,7 +52,7 @@ func (l *loadArgs) Setup() { l.TestSetupArgs = testsetups.CCIPDefaultTestSetUp(l.TestCfg.Test, lggr, envName, nil, l.TestCfg) } -func (l *loadArgs) setSchedule() { +func (l *LoadArgs) setSchedule() { var segments []*wasp.Segment var segmentDuration time.Duration require.Greater(l.t, len(l.TestCfg.TestGroupInput.RequestPerUnitTime), 0, "RequestPerUnitTime must be set") @@ -70,7 +71,7 @@ func (l *loadArgs) setSchedule() { } } -func (l *loadArgs) SanityCheck() { +func (l *LoadArgs) SanityCheck() { for _, lane := range l.TestSetupArgs.Lanes { lane.ForwardLane.RecordStateBeforeTransfer() err := lane.ForwardLane.SendRequests(1, l.TestCfg.TestGroupInput.MsgType, big.NewInt(600_000)) @@ -83,7 +84,7 @@ func (l *loadArgs) SanityCheck() { } } -func (l *loadArgs) TriggerLoadByLane() { +func (l *LoadArgs) TriggerLoadByLane() { l.setSchedule() l.TestSetupArgs.Reporter.SetDuration(l.TestCfg.TestGroupInput.TestDuration.Duration()) namespace := l.TestCfg.TestGroupInput.ExistingEnv @@ -128,6 +129,7 @@ func (l *loadArgs) TriggerLoadByLane() { l.AddToRunnerGroup(loadRunner) } for _, lane := range l.TestSetupArgs.Lanes { + lane := lane l.LoadStarterWg.Add(1) go func() { defer l.LoadStarterWg.Done() @@ -143,7 +145,7 @@ func (l *loadArgs) TriggerLoadByLane() { } } -func (l *loadArgs) AddToRunnerGroup(gen *wasp.Generator) { +func (l *LoadArgs) AddToRunnerGroup(gen *wasp.Generator) { l.RunnerWg.Go(func() error { _, failed := gen.Wait() if failed { @@ -156,7 +158,7 @@ func (l *loadArgs) AddToRunnerGroup(gen *wasp.Generator) { }) } -func (l *loadArgs) Wait() { +func (l *LoadArgs) Wait() { l.lggr.Info().Msg("Waiting for load to start on all lanes") // wait for load runner to start l.LoadStarterWg.Wait() @@ -167,7 +169,7 @@ func (l *loadArgs) Wait() { l.lggr.Info().Msg("Load finished on all lanes") } -func (l *loadArgs) ApplyChaos() { +func (l *LoadArgs) ApplyChaos() { testEnv := l.TestSetupArgs.Env if testEnv == nil || testEnv.K8Env == nil { l.lggr.Warn().Msg("test environment is nil, skipping chaos") @@ -197,7 +199,7 @@ func (l *loadArgs) ApplyChaos() { } } -func (l *loadArgs) TearDown() { +func (l *LoadArgs) TearDown() { for _, tearDn := range l.LoadgenTearDowns { tearDn() } @@ -206,7 +208,7 @@ func (l *loadArgs) TearDown() { } } -func (l *loadArgs) TriggerLoadBySource() { +func (l *LoadArgs) TriggerLoadBySource() { require.NotNil(l.t, l.TestCfg.TestGroupInput.TestDuration, "test duration input is nil") require.GreaterOrEqual(l.t, 1, len(l.TestCfg.TestGroupInput.RequestPerUnitTime), "time unit input must be specified") l.TestSetupArgs.Reporter.SetDuration(l.TestCfg.TestGroupInput.TestDuration.Duration()) @@ -264,9 +266,9 @@ func (l *loadArgs) TriggerLoadBySource() { } } -func NewLoadArgs(t *testing.T, lggr zerolog.Logger, parent context.Context, chaosExps ...ChaosConfig) *loadArgs { - wg, _ := errgroup.WithContext(parent) - return &loadArgs{ +func NewLoadArgs(t *testing.T, lggr zerolog.Logger, chaosExps ...ChaosConfig) *LoadArgs { + wg, _ := errgroup.WithContext(testcontext.Get(t)) + return &LoadArgs{ t: t, lggr: lggr, RunnerWg: wg, diff --git a/integration-tests/ccip-tests/smoke/ccip_test.go b/integration-tests/ccip-tests/smoke/ccip_test.go index f2404ee7b5..bd78ee9821 100644 --- a/integration-tests/ccip-tests/smoke/ccip_test.go +++ b/integration-tests/ccip-tests/smoke/ccip_test.go @@ -7,9 +7,10 @@ import ( "time" "github.com/AlekSi/pointer" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" diff --git a/integration-tests/ccip-tests/testconfig/global.go b/integration-tests/ccip-tests/testconfig/global.go index 210b22fdfc..c923ebc35d 100644 --- a/integration-tests/ccip-tests/testconfig/global.go +++ b/integration-tests/ccip-tests/testconfig/global.go @@ -7,9 +7,13 @@ import ( "fmt" "github.com/AlekSi/pointer" + "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" @@ -29,16 +33,16 @@ const ( var ( //go:embed tomls/default.toml - DefaultConfig []byte - GlobalTestConfig *Config + DefaultConfig []byte ) -func init() { +func GlobalTestConfig() *Config { var err error - GlobalTestConfig, err = NewConfig() + cfg, err := NewConfig() if err != nil { log.Fatal().Err(err).Msg("Failed to load config") } + return cfg } // GenericConfig is an interface for all product based config types to implement @@ -80,6 +84,9 @@ func NewConfig() (*Config, error) { if rawConfig != "" { log.Info().Msg("Found BASE64_TEST_CONFIG_OVERRIDE env var, overriding default config") d, err := base64.StdEncoding.DecodeString(rawConfig) + if err != nil { + return nil, errors.Wrap(err, ErrReadConfig) + } err = toml.Unmarshal(d, &override) if err != nil { return nil, errors.Wrap(err, ErrUnmarshalConfig) @@ -283,7 +290,6 @@ func (n *Node) ApplyOverrides(from *Node) { return } if n == nil { - n = from return } if from.Name != "" { @@ -311,8 +317,8 @@ func (n *Node) ApplyOverrides(from *Node) { if n.ChainConfigTOMLByChain == nil { n.ChainConfigTOMLByChain = from.ChainConfigTOMLByChain } else { - for chainID, toml := range from.ChainConfigTOMLByChain { - n.ChainConfigTOMLByChain[chainID] = toml + for chainID, cfg := range from.ChainConfigTOMLByChain { + n.ChainConfigTOMLByChain[chainID] = cfg } } diff --git a/integration-tests/ccip-tests/testconfig/tomls/default.toml b/integration-tests/ccip-tests/testconfig/tomls/default.toml index b7e316b0fe..3f8e089d7b 100644 --- a/integration-tests/ccip-tests/testconfig/tomls/default.toml +++ b/integration-tests/ccip-tests/testconfig/tomls/default.toml @@ -72,10 +72,6 @@ DefaultTransactionQueueDepth = 0 Enabled = false DefaultTransactionQueueDepth = 0 -[P2P.V1] -Enabled = false -ListenPort = 0 - [P2P] [P2P.V2] Enabled = true diff --git a/integration-tests/ccip-tests/testreporters/ccip.go b/integration-tests/ccip-tests/testreporters/ccip.go index 0e65628173..2590104834 100644 --- a/integration-tests/ccip-tests/testreporters/ccip.go +++ b/integration-tests/ccip-tests/testreporters/ccip.go @@ -13,6 +13,7 @@ import ( "github.com/rs/zerolog" "github.com/slack-go/slack" + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" ) @@ -88,11 +89,11 @@ func (stat *RequestStat) UpdateState(lggr zerolog.Logger, seqNum uint64, step Ph Status: state, } lggr.Info(). - Str(fmt.Sprint(E2E), fmt.Sprintf("%s", Failure)). + Str(fmt.Sprint(E2E), string(Failure)). Msgf("reqNo %d", stat.ReqNo) - event.Str(fmt.Sprint(step), fmt.Sprintf("%s", Failure)).Msgf("reqNo %d", stat.ReqNo) + event.Str(string(step), string(Failure)).Msgf("reqNo %d", stat.ReqNo) } else { - event.Str(fmt.Sprint(step), fmt.Sprintf("%s", Success)).Msgf("reqNo %d", stat.ReqNo) + event.Str(string(step), string(Success)).Msgf("reqNo %d", stat.ReqNo) if step == Commit || step == ReportBlessed || step == ExecStateChanged { stat.StatusByPhase[E2E] = PhaseStat{ SeqNum: seqNum, @@ -101,7 +102,7 @@ func (stat *RequestStat) UpdateState(lggr zerolog.Logger, seqNum uint64, step Ph } if step == ExecStateChanged { lggr.Info(). - Str(fmt.Sprint(E2E), fmt.Sprintf("%s", Success)). + Str(fmt.Sprint(E2E), string(Success)). Msgf("reqNo %d", stat.ReqNo) } } @@ -124,7 +125,7 @@ type CCIPLaneStats struct { SuccessCountsByPhase map[Phase]int64 `json:"success_counts_by_phase,omitempty"` // SuccessCountsByPhase is the number of requests that succeeded in each phase FailedCountsByPhase map[Phase]int64 `json:"failed_counts_by_phase,omitempty"` // FailedCountsByPhase is the number of requests that failed in each phase DurationStatByPhase map[Phase]AggregatorMetrics `json:"duration_stat_by_phase,omitempty"` // DurationStatByPhase is the duration statistics for each phase - statusByPhaseByRequests sync.Map `json:"-"` + statusByPhaseByRequests sync.Map } func (testStats *CCIPLaneStats) UpdatePhaseStatsForReq(stat *RequestStat) { diff --git a/integration-tests/ccip-tests/testsetups/ccip.go b/integration-tests/ccip-tests/testsetups/ccip.go index 5a0246727c..9d925feca6 100644 --- a/integration-tests/ccip-tests/testsetups/ccip.go +++ b/integration-tests/ccip-tests/testsetups/ccip.go @@ -17,16 +17,17 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog" chainselectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/stretchr/testify/require" "go.uber.org/atomic" "go.uber.org/multierr" "go.uber.org/zap/zapcore" "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" integrationactions "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -222,9 +223,9 @@ func NewCCIPTestConfig(t *testing.T, lggr zerolog.Logger, tType string) *CCIPTes if allError != nil { t.Fatal(allError) } - ccipCfg := testconfig.GlobalTestConfig.CCIP.Env - contractCfg := testconfig.GlobalTestConfig.CCIP.Deployments - groupCfg, exists := testconfig.GlobalTestConfig.CCIP.Groups[tType] + ccipCfg := testconfig.GlobalTestConfig().CCIP.Env + contractCfg := testconfig.GlobalTestConfig().CCIP.Deployments + groupCfg, exists := testconfig.GlobalTestConfig().CCIP.Groups[tType] if !exists { t.Fatalf("group config for %s does not exist", tType) } @@ -299,21 +300,21 @@ func (o *CCIPTestSetUpOutputs) DeployChainContracts( chain, err := blockchain.ConcurrentEVMClient(networkCfg, k8Env, chainClient, lggr) if err != nil { - return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %v", networkCfg.Name, err)) + return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkCfg.Name, err)) } chain.ParallelTransactions(true) defer chain.Close() ccipCommon, err := actions.DefaultCCIPModule(lggr, chain, pointer.GetBool(o.Cfg.TestGroupInput.ExistingDeployment), pointer.GetBool(o.Cfg.TestGroupInput.MulticallInOneTx)) if err != nil { - return errors.WithStack(fmt.Errorf("failed to create ccip common module for %s: %v", networkCfg.Name, err)) + return errors.WithStack(fmt.Errorf("failed to create ccip common module for %s: %w", networkCfg.Name, err)) } cfg := o.LaneConfig.ReadLaneConfig(networkCfg.Name) err = ccipCommon.DeployContracts(noOfTokens, tokenDeployerFns, cfg) if err != nil { - return errors.WithStack(fmt.Errorf("failed to deploy common ccip contracts for %s: %v", networkCfg.Name, err)) + return errors.WithStack(fmt.Errorf("failed to deploy common ccip contracts for %s: %w", networkCfg.Name, err)) } o.LaneContractsByNetwork.Store(networkCfg.Name, cfg) o.CommonContractsByNetwork.Store(networkCfg.Name, ccipCommon) @@ -349,14 +350,14 @@ func (o *CCIPTestSetUpOutputs) AddLanesForNetworkPair( // ConcurrentEVMClient is a work-around for that. sourceChainClientA2B, err := blockchain.ConcurrentEVMClient(networkA, k8Env, chainClientA, lggr) if err != nil { - return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %v", networkA.Name, err)) + return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkA.Name, err)) } sourceChainClientA2B.ParallelTransactions(true) destChainClientA2B, err := blockchain.ConcurrentEVMClient(networkB, k8Env, chainClientB, lggr) if err != nil { - return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %v", networkB.Name, err)) + return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkB.Name, err)) } destChainClientA2B.ParallelTransactions(true) @@ -402,13 +403,13 @@ func (o *CCIPTestSetUpOutputs) AddLanesForNetworkPair( if bidirectional { sourceChainClientB2A, err := blockchain.ConcurrentEVMClient(networkB, k8Env, chainClientB, lggr) if err != nil { - return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %v", networkB.Name, err)) + return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkB.Name, err)) } sourceChainClientB2A.ParallelTransactions(true) destChainClientB2A, err := blockchain.ConcurrentEVMClient(networkA, k8Env, chainClientA, lggr) if err != nil { - return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %v", networkA.Name, err)) + return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkA.Name, err)) } destChainClientB2A.ParallelTransactions(true) @@ -457,18 +458,18 @@ func (o *CCIPTestSetUpOutputs) AddLanesForNetworkPair( srcConfig, destConfig, err := ccipLaneA2B.DeployNewCCIPLane(numOfCommitNodes, commitAndExecOnSameDON, networkACmn, networkBCmn, transferAmounts, o.BootstrapAdded, configureCLNode, o.JobAddGrp) if err != nil { - allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("deploying lane %s to %s; err - %+v", networkA.Name, networkB.Name, err))) + allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("deploying lane %s to %s; err - %w", networkA.Name, networkB.Name, err))) return err } err = o.LaneConfig.WriteLaneConfig(networkA.Name, srcConfig) if err != nil { lggr.Error().Err(err).Msgf("error deploying lane %s to %s", networkA.Name, networkB.Name) - allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %+v", networkA.Name, err))) + allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %w", networkA.Name, err))) return err } err = o.LaneConfig.WriteLaneConfig(networkB.Name, destConfig) if err != nil { - allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %+v", networkB.Name, err))) + allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %w", networkB.Name, err))) return err } lggr.Info().Msgf("done setting up lane %s to %s", networkA.Name, networkB.Name) @@ -482,18 +483,18 @@ func (o *CCIPTestSetUpOutputs) AddLanesForNetworkPair( transferAmounts, o.BootstrapAdded, configureCLNode, o.JobAddGrp) if err != nil { lggr.Error().Err(err).Msgf("error deploying lane %s to %s", networkB.Name, networkA.Name) - allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("deploying lane %s to %s; err - %+v", networkB.Name, networkA.Name, err))) + allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("deploying lane %s to %s; err - %w", networkB.Name, networkA.Name, err))) return err } err = o.LaneConfig.WriteLaneConfig(networkB.Name, srcConfig) if err != nil { - allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %+v", networkA.Name, err))) + allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %w", networkA.Name, err))) return err } err = o.LaneConfig.WriteLaneConfig(networkA.Name, destConfig) if err != nil { - allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %+v", networkB.Name, err))) + allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %w", networkB.Name, err))) return err } lggr.Info().Msgf("done setting up lane %s to %s", networkB.Name, networkA.Name) @@ -609,7 +610,6 @@ func CCIPDefaultTestSetUp( var ( ccipEnv *actions.CCIPTestEnv k8Env *environment.Environment - ctx context.Context err error chains []blockchain.EVMClient ) @@ -664,7 +664,7 @@ func CCIPDefaultTestSetUp( ccipEnv = &actions.CCIPTestEnv{K8Env: k8Env} } - ccipEnv.CLNodeWithKeyReady, ctx = errgroup.WithContext(parent) + ccipEnv.CLNodeWithKeyReady, _ = errgroup.WithContext(parent) setUpArgs.Env = ccipEnv if ccipEnv.K8Env != nil && ccipEnv.K8Env.WillUseRemoteRunner() { return setUpArgs @@ -758,7 +758,7 @@ func CCIPDefaultTestSetUp( return err } } - return ccipEnv.SetUpNodesAndKeys(ctx, big.NewFloat(inputs.TestGroupInput.NodeFunding), chains, lggr) + return ccipEnv.SetUpNodesAndKeys(big.NewFloat(inputs.TestGroupInput.NodeFunding), chains, lggr) }) } @@ -811,7 +811,7 @@ func CCIPDefaultTestSetUp( n.NetworkA.URLs = inputs.NetworkPairs[i].ChainClientA.GetNetworkConfig().URLs n.NetworkB.HTTPURLs = inputs.NetworkPairs[i].ChainClientB.GetNetworkConfig().HTTPURLs n.NetworkB.URLs = inputs.NetworkPairs[i].ChainClientB.GetNetworkConfig().URLs - + laneAddGrp.Go(func() error { return setUpArgs.AddLanesForNetworkPair( lggr, n.NetworkA, n.NetworkB, diff --git a/integration-tests/ccip-tests/testsetups/test_env.go b/integration-tests/ccip-tests/testsetups/test_env.go index 224504fba5..cb11989edb 100644 --- a/integration-tests/ccip-tests/testsetups/test_env.go +++ b/integration-tests/ccip-tests/testsetups/test_env.go @@ -7,13 +7,14 @@ import ( "testing" "github.com/AlekSi/pointer" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/client" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/types/config/node" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -47,19 +48,17 @@ func setNodeConfig(nets []blockchain.EVMNetwork, nodeConfig, commonChain string, } } configByChainMap := make(map[int64]evmcfg.Chain) - if configByChain != nil { - for k, v := range configByChain { - var chain evmcfg.Chain - err = config.DecodeTOML(bytes.NewReader([]byte(v)), &chain) - if err != nil { - return nil, "", err - } - chainId, err := strconv.ParseInt(k, 10, 64) - if err != nil { - return nil, "", err - } - configByChainMap[chainId] = chain + for k, v := range configByChain { + var chain evmcfg.Chain + err = config.DecodeTOML(bytes.NewReader([]byte(v)), &chain) + if err != nil { + return nil, "", err + } + chainId, err := strconv.ParseInt(k, 10, 64) + if err != nil { + return nil, "", err } + configByChainMap[chainId] = chain } if nodeConfig == "" { tomlCfg = integrationnodes.NewConfig( @@ -166,7 +165,7 @@ func DeployLocalCluster( ) (*test_env.CLClusterTestEnv, func() error) { selectedNetworks := testInputs.SelectedNetworks env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). WithPrivateGethChains(selectedNetworks). WithoutCleanup(). Build() diff --git a/integration-tests/ccip-tests/types/config/node/core.go b/integration-tests/ccip-tests/types/config/node/core.go index 20d8092ec2..da48a87de7 100644 --- a/integration-tests/ccip-tests/types/config/node/core.go +++ b/integration-tests/ccip-tests/types/config/node/core.go @@ -2,18 +2,18 @@ package node import ( "bytes" - _ "embed" "fmt" "math/big" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" itutils "github.com/smartcontractkit/chainlink/integration-tests/utils" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -41,7 +41,7 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork, commonChainConfig *evmcfg }) } evmConfig := &evmcfg.EVMConfig{ - ChainID: utils.NewBig(big.NewInt(network.ChainID)), + ChainID: ubig.New(big.NewInt(network.ChainID)), Nodes: evmNodes, } if commonChainConfig != nil { diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 56670812fb..b6dce73862 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -92,6 +92,11 @@ func (c *ChainlinkClient) URL() string { return c.Config.URL } +func (c *ChainlinkClient) WithRetryCount(retryCount int) *ChainlinkClient { + c.APIClient.SetRetryCount(retryCount) + return c +} + // CreateJobRaw creates a Chainlink job based on the provided spec string func (c *ChainlinkClient) CreateJobRaw(spec string) (*Job, *http.Response, error) { job := &Job{} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b96d9a3693..58515631f5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -1,6 +1,6 @@ -module github.com/smartcontractkit/chainlink/integration-tests +module github.com/smartcontractkit/ccip/integration-tests -go 1.21.4 +go 1.21.3 // Make sure we're working with the latest chainlink libs replace github.com/smartcontractkit/chainlink/v2 => ../ @@ -8,42 +8,44 @@ replace github.com/smartcontractkit/chainlink/v2 => ../ require ( cosmossdk.io/errors v1.0.0 github.com/AlekSi/pointer v1.1.0 - github.com/K-Phoen/grabana v0.21.17 + github.com/K-Phoen/grabana v0.21.19 github.com/cli/go-gh/v2 v2.0.0 github.com/ethereum/go-ethereum v1.12.0 - github.com/go-resty/resty/v2 v2.7.0 + github.com/go-resty/resty/v2 v2.10.0 github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.5.0 github.com/jmoiron/sqlx v1.3.5 github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.9 github.com/manifoldco/promptui v0.9.0 - github.com/pkg/errors v0.9.1 - github.com/prometheus/common v0.45.0 github.com/onsi/gomega v1.30.0 github.com/pelletier/go-toml/v2 v2.1.1 - github.com/rs/zerolog v1.30.0 + github.com/pkg/errors v0.9.1 + github.com/prometheus/common v0.45.0 + github.com/rs/zerolog v1.31.0 github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 + github.com/smartcontractkit/chain-selectors v1.0.6 github.com/smartcontractkit/chainlink-automation v1.0.1 github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 github.com/smartcontractkit/chainlink-testing-framework v1.22.0 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 + github.com/smartcontractkit/chainlink/integration-tests v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 - github.com/smartcontractkit/wasp v0.3.7 - github.com/spf13/cobra v1.6.1 + github.com/smartcontractkit/wasp v0.4.0 + github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 github.com/testcontainers/testcontainers-go v0.23.0 github.com/umbracle/ethgo v0.1.3 go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/atomic v1.11.0 go.uber.org/multierr v1.11.0 - golang.org/x/crypto v0.14.0 - go.uber.org/ratelimit v0.2.0 + go.uber.org/ratelimit v0.3.0 go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.16.0 golang.org/x/sync v0.5.0 gopkg.in/guregu/null.v4 v4.0.0 ) @@ -52,12 +54,7 @@ require ( exclude github.com/hashicorp/consul v1.2.1 // Pin K8s versions as their updates are highly disruptive and go mod keeps wanting to update them -replace ( - github.com/testcontainers/testcontainers-go => github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 - k8s.io/api => k8s.io/api v0.25.11 - k8s.io/client-go => k8s.io/client-go v0.25.11 - k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d -) +replace github.com/testcontainers/testcontainers-go => github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 require ( contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect @@ -69,38 +66,43 @@ require ( filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect github.com/DataDog/zstd v1.5.2 // indirect - github.com/Depado/ginprom v1.7.11 // indirect - github.com/K-Phoen/sdk v0.12.2 // indirect + github.com/Depado/ginprom v1.8.0 // indirect + github.com/K-Phoen/sdk v0.12.3 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.1 // indirect github.com/VictoriaMetrics/fastcache v1.10.0 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect - github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect + github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect - github.com/aws/aws-sdk-go v1.45.25 // indirect + github.com/aws/aws-sdk-go v1.49.4 // indirect github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/bytedance/sonic v1.10.2 // indirect + github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -110,7 +112,7 @@ require ( github.com/chai2010/gettext-go v1.0.2 // indirect github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect - github.com/chenzhuoyu/iasm v0.9.0 // indirect + github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cli/safeexec v1.0.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect @@ -122,7 +124,7 @@ require ( github.com/confio/ics23/go v0.9.0 // indirect github.com/containerd/containerd v1.7.7 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect @@ -145,31 +147,34 @@ require ( github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect - github.com/emicklei/go-restful/v3 v3.10.2 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/esote/minmaxheap v1.0.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect + github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fvbommel/sortorder v1.0.2 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gagliardetto/binary v0.7.1 // indirect github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/getsentry/sentry-go v0.19.0 // indirect - github.com/gin-contrib/cors v1.4.0 // indirect + github.com/gin-contrib/cors v1.5.0 // indirect github.com/gin-contrib/expvar v0.0.1 // indirect github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 // indirect @@ -190,39 +195,49 @@ require ( github.com/go-openapi/jsonpointer v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/strfmt v0.21.7 // indirect + github.com/go-openapi/spec v0.20.11 // indirect + github.com/go-openapi/strfmt v0.21.9 // indirect github.com/go-openapi/swag v0.22.4 // indirect - github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-openapi/validate v0.22.3 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/go-playground/validator/v10 v10.16.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/go-webauthn/webauthn v0.9.4 // indirect + github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect github.com/gogo/status v1.1.1 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/gnostic v0.6.9 // indirect + github.com/google/gnostic v0.7.0 // indirect + github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/context v1.1.1 // indirect - github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/sessions v1.2.2 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/gosimple/slug v1.13.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect + github.com/grafana/dskit v0.0.0-20231213223053-84f5540a28dd // indirect + github.com/grafana/gomemcache v0.0.0-20231204155601-7de47a8c3cb0 // indirect + github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 // indirect + github.com/grafana/loki/pkg/push v0.0.0-20231215213922-be71a80b15e8 // indirect github.com/grafana/pyroscope-go v1.0.4 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect github.com/graph-gophers/dataloader v5.0.0+incompatible // indirect github.com/graph-gophers/graphql-go v1.3.0 // indirect @@ -235,17 +250,17 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/consul/api v1.25.1 // indirect + github.com/hashicorp/consul/api v1.26.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/golang-lru v0.6.0 // indirect + github.com/hashicorp/go-sockaddr v1.0.6 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/memberlist v0.5.0 // indirect github.com/hashicorp/serf v0.10.1 // indirect @@ -254,6 +269,7 @@ require ( github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect + github.com/huandu/xstrings v1.4.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -272,8 +288,8 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect - github.com/klauspost/compress v1.17.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -291,11 +307,14 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/miekg/dns v1.1.57 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect @@ -315,6 +334,7 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/opencontainers/runc v1.1.10 // indirect github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect @@ -325,12 +345,16 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/pressly/goose/v3 v3.16.0 // indirect + github.com/prometheus/alertmanager v0.26.0 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect - github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 // indirect + github.com/prometheus/exporter-toolkit v0.11.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/prometheus v0.48.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect @@ -339,17 +363,31 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect + github.com/sercand/kuberesolver/v5 v5.1.1 // indirect + github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.3.1 // indirect 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.20231206164210-03f8b219402e // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 // indirect + github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect + github.com/smartcontractkit/wsrpc v0.7.2 // indirect + github.com/soheilhy/cmux v0.1.5 // indirect + github.com/sony/gobreaker v0.5.0 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.16.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.1 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect @@ -366,6 +404,8 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/ulule/limiter/v3 v3.11.2 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/unrolled/secure v1.13.0 // indirect github.com/urfave/cli v1.22.14 // indirect @@ -377,15 +417,15 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect - go.etcd.io/etcd/api/v3 v3.5.9 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect - go.etcd.io/etcd/client/v3 v3.5.9 // indirect - go.mongodb.org/mongo-driver v1.12.0 // indirect + go.etcd.io/etcd/api/v3 v3.5.11 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.11 // indirect + go.etcd.io/etcd/client/v3 v3.5.11 // indirect + go.mongodb.org/mongo-driver v1.13.1 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect - go.opentelemetry.io/collector/semconv v0.87.0 // indirect + go.opentelemetry.io/collector/pdata v1.0.0 // indirect + go.opentelemetry.io/collector/semconv v0.91.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect @@ -394,6 +434,25 @@ require ( go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect + go.uber.org/goleak v1.3.0 // indirect + go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.16.1 // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + gonum.org/v1/gonum v0.14.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect + google.golang.org/grpc v1.60.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -402,24 +461,24 @@ require ( gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.28.2 // indirect + k8s.io/api v0.29.0 // indirect k8s.io/apiextensions-apiserver v0.25.3 // indirect - k8s.io/apimachinery v0.28.2 // indirect + k8s.io/apimachinery v0.29.0 // indirect k8s.io/cli-runtime v0.25.11 // indirect - k8s.io/client-go v0.28.2 // indirect + k8s.io/client-go v1.5.2 // indirect k8s.io/component-base v0.26.2 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231214164306-ab13479f8bf8 // indirect k8s.io/kubectl v0.25.11 // indirect - k8s.io/utils v0.0.0-20230711102312-30195339c3c7 // indirect - nhooyr.io/websocket v1.8.7 // indirect + k8s.io/utils v0.0.0-20231127182322-b307cd553661 // indirect + nhooyr.io/websocket v1.8.10 // indirect pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/controller-runtime v0.13.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) replace ( @@ -434,8 +493,9 @@ replace ( // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f - github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 - github.com/sercand/kuberesolver/v4 => github.com/sercand/kuberesolver/v5 v5.1.1 - github.com/smartcontractkit/chainlink/integration-tests => ../integration-tests + + k8s.io/api => k8s.io/api v0.25.11 + k8s.io/apimachinery => k8s.io/apimachinery v0.25.11 + k8s.io/client-go => k8s.io/client-go v0.25.11 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 476526ef3c..2b601c91dd 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -18,35 +18,590 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= -cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= +cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= -cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= contrib.go.opencensus.io/exporter/stackdriver v0.12.6/go.mod h1:8x999/OcIPy5ivx/wDiV7Gx4D+VUPODf0mWRGRc5kSk= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= contrib.go.opencensus.io/exporter/stackdriver v0.13.5 h1:TNaexHK16gPUoc7uzELKOU7JULqccn1NDuqUxmxSqfo= @@ -71,6 +626,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= @@ -81,12 +638,12 @@ github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= @@ -96,17 +653,17 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -<<<<<<< HEAD -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -======= ->>>>>>> develop github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0= +github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw= +github.com/ClickHouse/clickhouse-go/v2 v2.15.0 h1:G0hTKyO8fXXR1bGnZ0DY3vTG01xYfOGW76zgjg5tmC4= +github.com/ClickHouse/clickhouse-go/v2 v2.15.0/go.mod h1:kXt1SRq0PIRa6aKZD7TnFnY9PQKmc2b13sHtOYcK6cQ= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/CosmWasm/wasmd v0.40.1 h1:LxbO78t/6S8TkeQlUrJ0m5O87HtAwLx4RGHq3rdrOEU= @@ -122,16 +679,22 @@ github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/K-Phoen/grabana v0.21.17 h1:mO/9DvJWC/qpTF/X5jQDm5eKgCBaCGypP/tEfXAvKfg= -github.com/K-Phoen/grabana v0.21.17/go.mod h1:vbASQt9UiQhX4lC3/opLpJMJ8m+hsTUU2FwkQMytHK4= -github.com/K-Phoen/sdk v0.12.2 h1:0QofDlKE+lloyBOzhjEEMW21061zts/WIpfpQ5NLLAs= -github.com/K-Phoen/sdk v0.12.2/go.mod h1:qmM0wO23CtoDux528MXPpYvS4XkRWkWX6rvX9Za8EVU= +github.com/K-Phoen/grabana v0.21.19 h1:tJjRO8nN9JrFjLoQGtOB9P5ILoqENZZGAtt3nK+Ry2Y= +github.com/K-Phoen/grabana v0.21.19/go.mod h1:B7gxVxacQUgHWmgqduf4WPZoKYHO1mvZnRVCoyQiwdw= +github.com/K-Phoen/sdk v0.12.3 h1:ScutEQASc9VEKJCm3OjIMD82BIS9B2XtNg3gEf6Gs+M= +github.com/K-Phoen/sdk v0.12.3/go.mod h1:qmM0wO23CtoDux528MXPpYvS4XkRWkWX6rvX9Za8EVU= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA= @@ -141,8 +704,6 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 h1:HItfr1XKD/4xnsJE56m3uxnkMQ9lbg8xDnkf9qoZCH0= github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56/go.mod h1:ICriE9bLX5CLxL9OFQ2N+2N+f+803LNJ1utJb1+Inx0= @@ -150,7 +711,13 @@ github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40wo github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/Workiva/go-datastructures v1.1.0 h1:hu20UpgZneBhQ3ZvwiOGlqJSKIosin2Rd5wAKUHEO/k= +github.com/Workiva/go-datastructures v1.1.0/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= @@ -159,23 +726,28 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= +github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= +github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= +github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -<<<<<<< HEAD github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= -======= ->>>>>>> develop github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -195,8 +767,8 @@ github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3 github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= -github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.49.4 h1:qiXsqEeLLhdLgUIyfr5ot+N/dGPWALmtM1SetRmbUlY= +github.com/aws/aws-sdk-go v1.49.4/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g= github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI= github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4= @@ -205,6 +777,8 @@ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -217,6 +791,8 @@ github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsy github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= @@ -226,22 +802,16 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOF github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -<<<<<<< HEAD -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I= -github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -======= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= -github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= +github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= ->>>>>>> develop github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 h1:rvc39Ol6z3MvaBzXkxFC6Nfsnixq/dRypushKDd7Nc0= @@ -251,6 +821,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -267,8 +839,9 @@ github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= +github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -290,7 +863,15 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= @@ -320,26 +901,20 @@ github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AK github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -<<<<<<< HEAD -github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o= -github.com/containerd/containerd v1.7.3/go.mod h1:32FOM4/O0RkNg7AjQj3hDzN9cUGtu+HMvaKUNiqCZB8= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -======= github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4= github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= +github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= ->>>>>>> develop github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -416,20 +991,19 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA= github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= +github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -<<<<<<< HEAD -github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= -github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -======= github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= ->>>>>>> develop github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -443,8 +1017,14 @@ github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T/Lao= +github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E= +github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= +github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -452,9 +1032,14 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= @@ -469,6 +1054,8 @@ github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= @@ -478,11 +1065,13 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -490,14 +1079,14 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= github.com/gagliardetto/binary v0.7.1 h1:6ggDQ26vR+4xEvl/S13NcdLK3MUCi4oSy73pS9aI1cI= github.com/gagliardetto/binary v0.7.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= @@ -528,7 +1117,6 @@ github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NB github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= @@ -538,6 +1126,15 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= +github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= +github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI= +github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -549,6 +1146,8 @@ github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -556,7 +1155,6 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -567,11 +1165,8 @@ github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= @@ -580,52 +1175,43 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/spec v0.20.11 h1:J/TzFDLTt4Rcl/l1PmyErvkqlJDncGvPTMnCI39I4gY= +github.com/go-openapi/spec v0.20.11/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= -github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= -github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= +github.com/go-openapi/strfmt v0.21.9 h1:LnEGOO9qyEC1v22Bzr323M98G13paIUGPU7yeJtG9Xs= +github.com/go-openapi/strfmt v0.21.9/go.mod h1:0k3v301mglEaZRJdDDGSlN6Npq4VMVU69DE0LUyf7uA= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= -github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-openapi/validate v0.22.3 h1:KxG9mu5HBRYbecRb37KRCihvGGtND2aXziBAv0NNfyI= +github.com/go-openapi/validate v0.22.3/go.mod h1:kVxh31KbfsxU8ZyoHaDbLBWU5CnMdqBUEtadQ2G4d5M= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -<<<<<<< HEAD github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -======= -github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= -github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= ->>>>>>> develop -github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= +github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo= +github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -637,57 +1223,17 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -<<<<<<< HEAD -github.com/go-webauthn/webauthn v0.8.6 h1:bKMtL1qzd2WTFkf1mFTVbreYrwn7dsYmEPjTq6QN90E= -github.com/go-webauthn/webauthn v0.8.6/go.mod h1:emwVLMCI5yx9evTTvr0r+aOZCdWJqMfbRhF0MufyUog= -github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= -github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= -======= github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= ->>>>>>> develop github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -<<<<<<< HEAD github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -======= -github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= -github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= ->>>>>>> develop github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= @@ -708,15 +1254,11 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -<<<<<<< HEAD -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -======= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= ->>>>>>> develop +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -732,6 +1274,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -764,10 +1307,11 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= -github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic v0.7.0 h1:d7EpuFp8vVdML+y0JJJYiKeOLjKTdH/GvVkLOBWqJpw= +github.com/google/gnostic v0.7.0/go.mod h1:IAcUyMl6vtC95f60EZ8oXyqTsOersP6HbwjeG7EyDPM= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -781,6 +1325,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -796,6 +1341,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -808,7 +1355,12 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -819,15 +1371,31 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= @@ -836,20 +1404,13 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= -<<<<<<< HEAD -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -======= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= ->>>>>>> develop github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= @@ -858,25 +1419,18 @@ github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= -<<<<<<< HEAD -github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 h1:IOks+FXJ6iO/pfbaVEf4efNw+YzYBYNCkCabyrbkFTM= -github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2/go.mod h1:zj+5BNZAVmQafV583uLTAOzRr963KPdEm4d6NPmtbwg= -github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6 h1:V5PspEXlSlNh22sMyGkgfSOVVLTsSmhbmsp1VPt8Fdc= -github.com/grafana/loki v1.6.2-0.20231017135925-990ac685e6a6/go.mod h1:+aWr7OBDuZMT+p0rKmLfW5saO2m3YOGBnt++IlgLhVk= -github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 h1:VXitROTlmZtLzvokNe8ZbUKpmwldM4Hy1zdNRO32jKU= -github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765/go.mod h1:DhJMrd2QInI/1CNtTN43BZuTmkccdizW1jZ+F6aHkhY= -======= -github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f h1:gyojr97YeWZ70pKNakWv5/tKwBHuLy3icnIeCo9gQr4= -github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f/go.mod h1:8dsy5tQOkeNQyjXpm5mQsbCu3H5uzeBD35MzRQFznKU= -github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4 h1:YbfISHhpbiDvoFNxDPCicPOU/+9s4rdv9Fq/V3iRvTo= -github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4/go.mod h1:Tx2uhmS+H0pGmtqX94/KaDkRHWhIowt4iYtJLctAbEY= -github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 h1:wQ0FnSeebhJIBkgYOD06Mxk9HV2KhtEG0hp/7R+5RUQ= -github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0= ->>>>>>> develop +github.com/grafana/dskit v0.0.0-20231213223053-84f5540a28dd h1:znSOnhAwMuyWzb1Vx550Q07o5p9EmqLyiDIYuKipiMc= +github.com/grafana/dskit v0.0.0-20231213223053-84f5540a28dd/go.mod h1:kkWM4WUV230bNG3urVRWPBnSJHs64y/0RmWjftnnn0c= +github.com/grafana/gomemcache v0.0.0-20231204155601-7de47a8c3cb0 h1:aLBiDMjTtXx2800iCIp+8kdjIlvGX0MF/zICQMQO2qU= +github.com/grafana/gomemcache v0.0.0-20231204155601-7de47a8c3cb0/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= +github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 h1:gdrsYbmk8822v6qvPwZO5DC6QjnAW7uKJ9YXnoUmV8c= +github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503/go.mod h1:d8seWXCEXkL42mhuIJYcGi6DxfehzoIpLrMQWJojvOo= +github.com/grafana/loki/pkg/push v0.0.0-20231215213922-be71a80b15e8 h1:Tmh6+YTALf9aVbij73xaY7rz9nlCa5lWoD//9DO33JE= +github.com/grafana/loki/pkg/push v0.0.0-20231215213922-be71a80b15e8/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0= github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= -github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= -github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= +github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo= +github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= @@ -896,6 +1450,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= @@ -907,11 +1463,11 @@ github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/b github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= -github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= +github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM= +github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= -github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= +github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU= +github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -925,8 +1481,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -946,8 +1502,8 @@ github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR3 github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-sockaddr v1.0.6 h1:RSG8rKU28VTUTvEKghe5gIhIQpv8evvNpnDEyqO4u9I= +github.com/hashicorp/go-sockaddr v1.0.6/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -960,8 +1516,8 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= -github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -992,11 +1548,16 @@ github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3 github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= @@ -1057,10 +1618,15 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw= +github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -1075,10 +1641,13 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -1095,35 +1664,34 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= -<<<<<<< HEAD github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -======= ->>>>>>> develop github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= -github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= @@ -1133,7 +1701,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -1149,7 +1716,6 @@ github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awS github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a h1:dHCfT5W7gghzPtfsW488uPmEOm85wewI+ypUwibyTdU= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= @@ -1163,21 +1729,18 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -<<<<<<< HEAD -github.com/linode/linodego v1.14.1 h1:uGxQyy0BidoEpLGdvfi4cPgEW+0YUFsEGrLEhcTfjNc= -github.com/linode/linodego v1.14.1/go.mod h1:NJlzvlNtdMRRkXb0oN6UWzUkj6t+IBsyveHgZ5Ppjyk= -github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= -github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= -======= github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= ->>>>>>> develop +github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= +github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -1191,8 +1754,6 @@ github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYt github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f/go.mod h1:Z60vy0EZVSu0bOugCHdcN5ZxFMKSpjRgsnh0XKPFqqk= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1213,20 +1774,18 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -<<<<<<< HEAD -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -======= ->>>>>>> develop github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= @@ -1234,22 +1793,26 @@ github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/le github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= @@ -1262,6 +1825,9 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= @@ -1334,14 +1900,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -<<<<<<< HEAD -github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= -github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= -github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= -======= -github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= -github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= ->>>>>>> develop +github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= +github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= @@ -1351,6 +1911,8 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= +github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= @@ -1362,25 +1924,27 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s= +github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -<<<<<<< HEAD github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -======= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= ->>>>>>> develop github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= +github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -1390,6 +1954,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -1423,18 +1988,12 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -<<<<<<< HEAD -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -======= ->>>>>>> develop github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= -github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 h1:oHcfzdJnM/SFppy2aUlvomk37GI33x9vgJULihE5Dt8= -github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97/go.mod h1:LoBCZeRh+5hX+fSULNyFnagYlQG/gBsyA/deNzROkq8= +github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= +github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -1458,12 +2017,9 @@ github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGn github.com/regen-network/gocuke v0.6.2/go.mod h1:zYaqIHZobHyd0xOrHGPQjbhGJsuZ1oElx150u2o1xuk= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= -<<<<<<< HEAD github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -======= ->>>>>>> develop github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -1471,8 +2027,6 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= @@ -1486,14 +2040,16 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= -github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= +github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= +github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= @@ -1506,6 +2062,8 @@ github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cj github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= @@ -1529,7 +2087,6 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -1539,22 +2096,8 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -<<<<<<< HEAD github.com/smartcontractkit/chain-selectors v1.0.6 h1:SWvONQuYnMSMoaOeLBSQY+iQjMVKvzmRGniKO2mYO64= github.com/smartcontractkit/chain-selectors v1.0.6/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e h1:Fsx5IJDD14wdCAe2lEI1xgztIvzjiE2iVHvYzg/grew= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231117021201-6814387d8d3e/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/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= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= -github.com/smartcontractkit/chainlink-testing-framework v1.20.2 h1:IF85y6GJRNPrU0GoJgGR7d8A8alPzTwVV1fNpjHXeKk= -github.com/smartcontractkit/chainlink-testing-framework v1.20.2/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= -======= github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213134506-b6c433e6c490 h1:lSYiaiIfAA+5ac45/UD8ciytlNw/S6fnhK7bxFHYI88= @@ -1565,6 +2108,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e h1:/tCHhoAJM+ittEHPZTtJsAgXmYujKiDW0ub9HXW9qtY= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8= @@ -1573,35 +2118,18 @@ github.com/smartcontractkit/chainlink-testing-framework v1.22.0 h1:Lur628wkrceWg github.com/smartcontractkit/chainlink-testing-framework v1.22.0/go.mod h1:yu6qqrppNJfutQV37fiSs4eS0uQP5QT0ebi3tlIgWN0= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= ->>>>>>> develop github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -<<<<<<< HEAD -github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= -github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.28 h1:dufAiYl4+uly9aH0+6GkS2jYzHGujq7tg0LYQE+x6JU= -github.com/smartcontractkit/ocr2keepers v0.7.28/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= -github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= -github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -======= github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 h1:AA7vf29c6lFsZm+MtIEtXtg6VUOQV6waJo5MUuHfRjQ= github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7/go.mod h1:WcuWFMskcGK0MYZuH5hEhGJOzdJRUFeNEM4PAKlejI4= ->>>>>>> develop github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -<<<<<<< HEAD -github.com/smartcontractkit/wasp v0.3.6 h1:1TLWfrTzqZwNvyyoKzPZ8FLQat2lNz640eM+mMh2YxM= -github.com/smartcontractkit/wasp v0.3.6/go.mod h1:L/cyUGfpaWxy/2twOVJLRt2mySJEIqGrFj9nyvRLpSo= -======= -github.com/smartcontractkit/wasp v0.3.7 h1:3toT+iMSHJ1EKQXE+jGnxfmtLlT0gwEl1A7xGyw0NZY= -github.com/smartcontractkit/wasp v0.3.7/go.mod h1:L/cyUGfpaWxy/2twOVJLRt2mySJEIqGrFj9nyvRLpSo= ->>>>>>> develop +github.com/smartcontractkit/wasp v0.4.0 h1:N8yPxlBvoJiyE6HaDkTkwRbuOHkGgQFGEHbw36oh4jA= +github.com/smartcontractkit/wasp v0.4.0/go.mod h1:3qiofyI3pkbrc48a3CVshbMfgl74SiuPL/tm30d9Wb4= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -1609,22 +2137,21 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -<<<<<<< HEAD github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -======= ->>>>>>> develop github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= @@ -1638,14 +2165,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -<<<<<<< HEAD github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -======= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= ->>>>>>> develop github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -1653,8 +2174,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1713,14 +2235,9 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -<<<<<<< HEAD github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -======= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= ->>>>>>> develop github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= @@ -1743,35 +2260,23 @@ github.com/valyala/fastjson v1.4.1/go.mod h1:nV6MsjxL2IMJQUoHDIrjEI7oLyeqK6aBD7E github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= +github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= -<<<<<<< HEAD -github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205 h1:gjb7t9LCnRu14LHubyLIgrE+EYlAaREiPn/VknV7R3s= -github.com/weaveworks/common v0.0.0-20230411130259-f7d83a041205/go.mod h1:O9wmSPNVSuqxzUZPFlHnPQ8xnyvx0qBnKGFfGbj95uY= -github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= -github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= -github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= -github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= -======= ->>>>>>> develop github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= @@ -1780,6 +2285,10 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dzWP1Lu+A40W883dK/Mr3xyDSM/2MggS8GtHT0qgAnE= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= +github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA= +github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= @@ -1789,13 +2298,14 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -<<<<<<< HEAD github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -======= ->>>>>>> develop github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= +github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= @@ -1814,17 +2324,15 @@ go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYr go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= -go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= -go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= -go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= -go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= -go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E= +go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= +go.etcd.io/etcd/client/pkg/v3 v3.5.11 h1:bT2xVspdiCj2910T0V+/KHcVKjkUrCZVtk8J2JF2z1A= +go.etcd.io/etcd/client/pkg/v3 v3.5.11/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= +go.etcd.io/etcd/client/v3 v3.5.11 h1:ajWtgoNSZJ1gmS8k+icvPtqsqEav+iUorF7b0qozgUU= +go.etcd.io/etcd/client/v3 v3.5.11/go.mod h1:a6xQUEqFJ8vztO1agJh/KQKOMfFI8og52ZconzcDJwE= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= -go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= +go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= +go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= @@ -1832,16 +2340,17 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9Atxpk78bmtVdi15KhE= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg= -go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8= -go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= +go.opentelemetry.io/collector/pdata v1.0.0 h1:ECP2jnLztewsHmL1opL8BeMtWVc7/oSlKNhfY9jP8ec= +go.opentelemetry.io/collector/pdata v1.0.0/go.mod h1:TsDFgs4JLNG7t6x9D8kGswXUz4mme+MyNChHx8zSF6k= +go.opentelemetry.io/collector/semconv v0.91.0 h1:TRd+yDDfKQl+aNtS24wmEbJp1/QE/xAFV9SB5zWGxpE= +go.opentelemetry.io/collector/semconv v0.91.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= @@ -1855,6 +2364,7 @@ go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6 go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g= @@ -1875,8 +2385,9 @@ go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKY go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +go.uber.org/ratelimit v0.3.0 h1:IdZd9wqvFXnvLvSEBo0KPcGfkoBGNkpTHlrE3Rcjkjw= +go.uber.org/ratelimit v0.3.0/go.mod h1:So5LG7CV1zWpY1sHe+DXTJqQvOx+FFPFaAs2SnoyBaI= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1886,6 +2397,8 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= @@ -1895,7 +2408,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1904,7 +2416,6 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1915,30 +2426,45 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -<<<<<<< HEAD -golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -======= ->>>>>>> develop +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= -golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1962,7 +2488,10 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -2010,26 +2539,41 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2041,9 +2585,10 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -<<<<<<< HEAD golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -2060,17 +2605,12 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= -======= golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= ->>>>>>> develop golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2078,7 +2618,10 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -2097,11 +2640,9 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2144,55 +2685,77 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2206,7 +2769,10 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -2215,25 +2781,26 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -2241,6 +2808,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2277,6 +2845,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -2284,24 +2853,29 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= -golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -<<<<<<< HEAD gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= @@ -2312,10 +2886,6 @@ gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6d gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= -======= -gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= -gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= ->>>>>>> develop google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -2336,6 +2906,44 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -2390,16 +2998,114 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= +google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= +google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos= +google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o= +google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2423,10 +3129,28 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= +google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2441,6 +3165,10 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -2502,27 +3230,28 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= +howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= k8s.io/api v0.25.11 h1:4mjYDfE3yp22jrytjH0knwgzjXKkxHX4D01ZCAazvZM= k8s.io/api v0.25.11/go.mod h1:bK4UvD4bthtutNlvensrfBX21PRQ/vs2cIYggHkOOAo= k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k= k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/apimachinery v0.25.11 h1:2EhfdrSAMvBxsswvOGCEymKk4ZnHZkranuZqdR0rsO4= +k8s.io/apimachinery v0.25.11/go.mod h1:IFwbcNi3gKkfDhuy0VYu3+BwbxbiIov3p6FR8ge1Epc= k8s.io/cli-runtime v0.25.11 h1:GE2yNZm1tN+MJtw1SGMOLesLF7Kp7NVAVqRSTbXfu4o= k8s.io/cli-runtime v0.25.11/go.mod h1:r/nEINuHVEpgGhcd2WamU7hD1t/lMnSz8XM44Autltc= k8s.io/client-go v0.25.11 h1:DJQ141UsbNRI6wYSlcYLP5J5BW5Wq7Bgm42Ztq2SW70= k8s.io/client-go v0.25.11/go.mod h1:41Xs7p1SfhoReUnmjjYCfCNWFiq4xSkexwJfbxF2F7A= k8s.io/component-base v0.26.2 h1:IfWgCGUDzrD6wLLgXEstJKYZKAFS2kO+rBRi0p3LqcI= k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d h1:VcFq5n7wCJB2FQMCIHfC+f+jNcGgNMar1uKd6rVlifU= -k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231214164306-ab13479f8bf8 h1:yHNkNuLjht7iq95pO9QmbjOWCguvn8mDe3lT78nqPkw= +k8s.io/kube-openapi v0.0.0-20231214164306-ab13479f8bf8/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/kubectl v0.25.11 h1:6bsft5Gan6BCvQ7cJbDRFjTm4Zfq8GuUYpsWAdVngYE= k8s.io/kubectl v0.25.11/go.mod h1:8mIfgkFgT+yJ8/TlmPW1qoRh46H2si9q5nW8id7i9iM= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -<<<<<<< HEAD +k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI= +k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= @@ -2549,8 +3278,8 @@ modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= -modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= +modernc.org/libc v1.32.0 h1:yXatHTrACp3WaKNRCoZwUK7qj5V8ep1XyY0ka4oYcNc= +modernc.org/libc v1.32.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= @@ -2565,8 +3294,8 @@ modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= -modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= +modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= @@ -2576,10 +3305,8 @@ modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -======= ->>>>>>> develop -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= +nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= @@ -2595,7 +3322,7 @@ sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/integration-tests/load/automationv2_1/gun.go b/integration-tests/load/automationv2_1/gun.go index a2863a6064..2bbb654e00 100644 --- a/integration-tests/load/automationv2_1/gun.go +++ b/integration-tests/load/automationv2_1/gun.go @@ -28,7 +28,7 @@ func NewLogTriggerUser( } } -func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.Response { m.logger.Debug().Str("Trigger address", m.triggerContract.Address().String()).Msg("Triggering upkeep") payload := make([]int, 0) for i := 0; i < m.numberOfEvents; i++ { @@ -36,8 +36,8 @@ func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.CallResult { } _, err := m.triggerContract.EmitLogInts(payload) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } diff --git a/integration-tests/load/functions/gateway_gun.go b/integration-tests/load/functions/gateway_gun.go index 3dafb458a5..62fe80ed02 100644 --- a/integration-tests/load/functions/gateway_gun.go +++ b/integration-tests/load/functions/gateway_gun.go @@ -37,7 +37,7 @@ func NewGatewaySecretsSetGun(cfg *PerformanceConfig, method string, pKey *ecdsa. } } -func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { +func callSecretsSet(m *GatewaySecretsSetGun) *wasp.Response { randNum := strconv.Itoa(rand.Intn(100000)) randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) @@ -57,7 +57,7 @@ func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { secret, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } _, _, err = UploadS4Secrets(m.Resty, &S4SecretsCfg{ GatewayURL: m.Cfg.Common.GatewayURL, @@ -71,12 +71,12 @@ func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { S4SetPayload: secrets, }) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } -func callSecretsList(m *GatewaySecretsSetGun) *wasp.CallResult { +func callSecretsList(m *GatewaySecretsSetGun) *wasp.Response { randNum := strconv.Itoa(rand.Intn(100000)) randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) @@ -92,14 +92,14 @@ func callSecretsList(m *GatewaySecretsSetGun) *wasp.CallResult { S4SetVersion: version, S4SetExpirationPeriod: expiration, }); err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } // Call implements example gun call, assertions on response bodies should be done here -func (m *GatewaySecretsSetGun) Call(_ *wasp.Generator) *wasp.CallResult { - var res *wasp.CallResult +func (m *GatewaySecretsSetGun) Call(_ *wasp.Generator) *wasp.Response { + var res *wasp.Response switch m.Method { case "secrets_set": res = callSecretsSet(m) diff --git a/integration-tests/load/functions/request_gun.go b/integration-tests/load/functions/request_gun.go index bd4cf5f35a..6b79a2f19e 100644 --- a/integration-tests/load/functions/request_gun.go +++ b/integration-tests/load/functions/request_gun.go @@ -48,7 +48,7 @@ func NewSingleFunctionCallGun( } } -func (m *SingleFunctionCallGun) callReal() *wasp.CallResult { +func (m *SingleFunctionCallGun) callReal() *wasp.Response { err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( m.times, m.source, @@ -59,12 +59,12 @@ func (m *SingleFunctionCallGun) callReal() *wasp.CallResult { m.jobId, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } -func (m *SingleFunctionCallGun) callWithSecrets() *wasp.CallResult { +func (m *SingleFunctionCallGun) callWithSecrets() *wasp.Response { err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( m.times, m.source, @@ -75,12 +75,12 @@ func (m *SingleFunctionCallGun) callWithSecrets() *wasp.CallResult { m.jobId, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } -func (m *SingleFunctionCallGun) callWithHttp() *wasp.CallResult { +func (m *SingleFunctionCallGun) callWithHttp() *wasp.Response { err := m.ft.LoadTestClient.SendRequest( m.times, m.source, @@ -90,13 +90,13 @@ func (m *SingleFunctionCallGun) callWithHttp() *wasp.CallResult { m.jobId, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleFunctionCallGun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *SingleFunctionCallGun) Call(_ *wasp.Generator) *wasp.Response { switch m.mode { case ModeSecretsOnlyPayload: return m.callWithSecrets() diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md index 3c231b5027..e9e67ce25f 100644 --- a/integration-tests/load/ocr/README.md +++ b/integration-tests/load/ocr/README.md @@ -4,18 +4,10 @@ These tests can connect to any cluster create with [chainlink-cluster](../../../charts/chainlink-cluster/README.md) -<<<<<<< HEAD -Create your cluster - -```sh -kubectl create ns my-cluster -devspace use namespace my-cluster -======= Create your cluster, if you already have one just use `kubefwd` ``` kubectl create ns cl-cluster devspace use namespace cl-cluster ->>>>>>> 06656fac80999d1539e16951a54b87c6df13a9c7 devspace deploy sudo kubefwd svc -n cl-cluster ``` diff --git a/integration-tests/load/ocr/gun.go b/integration-tests/load/ocr/gun.go index a2eb1ff220..cfa8380a70 100644 --- a/integration-tests/load/ocr/gun.go +++ b/integration-tests/load/ocr/gun.go @@ -8,6 +8,7 @@ import ( "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/wasp" @@ -30,7 +31,7 @@ func NewGun(l zerolog.Logger, cc blockchain.EVMClient, ocrInstances []contracts. } } -func (m *Gun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *Gun) Call(_ *wasp.Generator) *wasp.Response { m.roundNum.Add(1) requestedRound := m.roundNum.Load() m.l.Info(). @@ -39,17 +40,17 @@ func (m *Gun) Call(_ *wasp.Generator) *wasp.CallResult { Msg("starting new round") err := m.ocrInstances[0].RequestNewRound() if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } for { time.Sleep(5 * time.Second) lr, err := m.ocrInstances[0].GetLatestRound(context.Background()) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } m.l.Info().Interface("LatestRound", lr).Msg("latest round") if lr.RoundId.Int64() >= requestedRound { - return &wasp.CallResult{} + return &wasp.Response{} } } } diff --git a/integration-tests/load/ocr/vu.go b/integration-tests/load/ocr/vu.go index 96be77c701..d113f7eb3f 100644 --- a/integration-tests/load/ocr/vu.go +++ b/integration-tests/load/ocr/vu.go @@ -105,17 +105,17 @@ func (m *VU) Call(l *wasp.Generator) { Msg("starting new round") err := m.ocrInstances[0].RequestNewRound() if err != nil { - l.ResponsesChan <- &wasp.CallResult{Error: err.Error(), Failed: true} + l.ResponsesChan <- &wasp.Response{Error: err.Error(), Failed: true} } for { time.Sleep(5 * time.Second) lr, err := m.ocrInstances[0].GetLatestRound(context.Background()) if err != nil { - l.ResponsesChan <- &wasp.CallResult{Error: err.Error(), Failed: true} + l.ResponsesChan <- &wasp.Response{Error: err.Error(), Failed: true} } m.l.Info().Interface("LatestRound", lr).Msg("latest round") if lr.RoundId.Int64() >= requestedRound { - l.ResponsesChan <- &wasp.CallResult{} + l.ResponsesChan <- &wasp.Response{} } } } diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index 8a5eb3c66d..fd8cb6195e 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -38,7 +38,7 @@ func NewSingleHashGun( } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets //randomly increase/decrease randomness request count per TX @@ -56,9 +56,9 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { m.logger, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } func deviateValue(requestCountPerTX uint16, deviation uint16) uint16 { diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index 8ab278b73e..77b60e3000 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -38,7 +38,7 @@ func NewSingleHashGun( } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets //randomly increase/decrease randomness request count per TX @@ -58,9 +58,9 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { m.logger, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } func deviateValue(requestCountPerTX uint16, deviation uint16) uint16 { diff --git a/integration-tests/universal/log_poller/gun.go b/integration-tests/universal/log_poller/gun.go index 39286f1b53..a75209aa10 100644 --- a/integration-tests/universal/log_poller/gun.go +++ b/integration-tests/universal/log_poller/gun.go @@ -39,7 +39,7 @@ func NewLogEmitterGun( } } -func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { +func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.Response { localCounter := 0 logEmitter := (*m.contract) address := logEmitter.Address() @@ -58,7 +58,7 @@ func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { } if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } localCounter++ } @@ -69,11 +69,11 @@ func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { defer counter.mu.Unlock() counter.value += localCounter } else { - return &wasp.CallResult{ + return &wasp.Response{ Error: "SharedData did not contain a Counter", Failed: true, } } - return &wasp.CallResult{} + return &wasp.Response{} } diff --git a/operator_ui/TAG b/operator_ui/TAG index c8bf85f33f..584c67d8d2 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1,5 +1 @@ -<<<<<<< HEAD -v0.8.0-e10948a -======= v0.8.0-0953c48 ->>>>>>> develop diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 59f750a8fa..fff027d33c 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -174,22 +174,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -<<<<<<< HEAD -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - -======= ->>>>>>> develop [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index ef26a91888..d56e6859c8 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -218,22 +218,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -<<<<<<< HEAD -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - -======= ->>>>>>> develop [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 4d0f55cd41..7feea4aea3 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -218,22 +218,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -<<<<<<< HEAD -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - -======= ->>>>>>> develop [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 451eaac9db..dbf488763e 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -218,22 +218,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -<<<<<<< HEAD -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - -======= ->>>>>>> develop [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index aae6a3c4f4..8a4529b400 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -208,22 +208,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -<<<<<<< HEAD -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - -======= ->>>>>>> develop [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 60ca8a0eb8..2061d03382 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -215,22 +215,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -<<<<<<< HEAD -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - -======= ->>>>>>> develop [P2P.V2] Enabled = true AnnounceAddresses = [] diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index c32683b3e1..af971ecfab 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -2,27 +2,12 @@ exec chainlink node -c config.toml -s secrets.toml validate cmp stdout out.txt -- config.toml -- -<<<<<<< HEAD -[P2P.V1] -Enabled = true -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' -======= [Tracing] Enabled = true CollectorTarget = 'otel-collector:4317' TLSCertPath = 'something' Mode = 'unencrypted' ->>>>>>> develop -- secrets.toml -- [Database] @@ -41,27 +26,11 @@ AllowSimplePasswords = false Keystore = 'xxxxx' # Input Configuration: -<<<<<<< HEAD -[P2P] -[P2P.V1] -Enabled = true -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' -======= [Tracing] Enabled = true CollectorTarget = 'otel-collector:4317' Mode = 'unencrypted' TLSCertPath = 'something' ->>>>>>> develop # Effective Configuration, with defaults applied: InsecureFastScrypt = false @@ -72,10 +41,7 @@ ShutdownGracePeriod = '5s' FeedsManager = true LogPoller = false UICSAKeys = false -<<<<<<< HEAD CCIP = false -======= ->>>>>>> develop [Database] DefaultIdleInTxSessionTimeout = '1h0m0s' @@ -131,10 +97,7 @@ MaxAgeDays = 0 MaxBackups = 1 [WebServer] -<<<<<<< HEAD -======= AuthenticationMethod = 'local' ->>>>>>> develop AllowOrigins = 'http://localhost:3000,http://localhost:6688' BridgeResponseURL = '' BridgeCacheTTL = '0s' @@ -147,8 +110,6 @@ HTTPMaxSize = '32.77kb' StartTimeout = '15s' ListenIP = '0.0.0.0' -<<<<<<< HEAD -======= [WebServer.LDAP] ServerTLS = true SessionTimeout = '15m0s' @@ -168,7 +129,6 @@ UserAPITokenDuration = '240h0m0s' UpstreamSyncInterval = '0s' UpstreamSyncRateLimit = '2m0s' ->>>>>>> develop [WebServer.MFA] RPID = '' RPOrigin = '' @@ -213,11 +173,7 @@ ContractTransmitterTransmitTimeout = '10s' DatabaseTimeout = '10s' KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' CaptureEATelemetry = false -<<<<<<< HEAD -CaptureAutomationCustomTelemetry = false -======= CaptureAutomationCustomTelemetry = true ->>>>>>> develop DefaultTransactionQueueDepth = 1 SimulateTransactions = false TraceLogging = false @@ -241,22 +197,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -<<<<<<< HEAD -[P2P.V1] -Enabled = true -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - -======= ->>>>>>> develop [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -311,27 +251,6 @@ InfiniteDepthQueries = false DisableRateLimiting = false [Tracing] -<<<<<<< HEAD -Enabled = false -CollectorTarget = '' -NodeID = '' -SamplingRatio = 0.0 - -# Configuration warning: -2 errors: - - P2P.V1: is deprecated and will be removed in a future version - - P2P.V1: 10 errors: - - AnnounceIP: is deprecated and will be removed in a future version - - AnnouncePort: is deprecated and will be removed in a future version - - BootstrapCheckInterval: is deprecated and will be removed in a future version - - DefaultBootstrapPeers: is deprecated and will be removed in a future version - - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version - - DHTLookupInterval: is deprecated and will be removed in a future version - - ListenIP: is deprecated and will be removed in a future version - - ListenPort: is deprecated and will be removed in a future version - - NewStreamTimeout: is deprecated and will be removed in a future version - - PeerstoreWriteInterval: is deprecated and will be removed in a future version -======= Enabled = true CollectorTarget = 'otel-collector:4317' NodeID = '' @@ -347,5 +266,4 @@ LatestReportDeadline = '5s' # Configuration warning: Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' ->>>>>>> develop Valid configuration. From ed12f056fa4199236c034a9a108387b5cae91a1d Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Mon, 18 Dec 2023 16:06:09 +0200 Subject: [PATCH 325/327] fix issues fix integration-tests/go.mod fix imports --- .../internal/ccipdata/onramp_reader_test.go | 6 ++-- .../ccip/testhelpers/integration/chainlink.go | 29 ++----------------- integration-tests/go.mod | 1 + 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go index dd4be8484c..31473ddb0e 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go @@ -5,16 +5,14 @@ import ( "testing" "time" - "github.com/stretchr/testify/mock" - - evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp" diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go index 75c9286db0..eb11edffcc 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go @@ -2,11 +2,9 @@ package integrationtesthelpers import ( "context" - "crypto/rand" "encoding/hex" "fmt" "math/big" - "net" "net/http" "net/http/httptest" "strconv" @@ -19,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common" types3 "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/jmoiron/sqlx" "github.com/onsi/gomega" "github.com/pkg/errors" @@ -838,7 +837,7 @@ func (c *CCIPIntegrationTestHarness) SetupAndStartNodes(ctx context.Context, t * app, peerID, transmitter, kb := setupNodeCCIP( t, c.Dest.User, - bootstrapNodePort+1+i, + int64(freeport.GetOne(t)), fmt.Sprintf("oracle_ccip%d", i), c.Source.Chain, c.Dest.Chain, @@ -885,7 +884,7 @@ func (c *CCIPIntegrationTestHarness) SetUpNodesAndJobs(t *testing.T, pricePipeli // setup Jobs ctx := context.Background() // Starts nodes and configures them in the OCR contracts. - bootstrapNode, _, configBlock := c.SetupAndStartNodes(ctx, t, generateRandomBootstrapPort()) + bootstrapNode, _, configBlock := c.SetupAndStartNodes(ctx, t, int64(freeport.GetOne(t))) jobParams := c.NewCCIPJobSpecParams(pricePipeline, configBlock, usdcAttestationAPI) @@ -966,25 +965,3 @@ func (n NoopFeedsClient) RejectedJob(context.Context, *pb.RejectedJobRequest) (* func (n NoopFeedsClient) CancelledJob(context.Context, *pb.CancelledJobRequest) (*pb.CancelledJobResponse, error) { return &pb.CancelledJobResponse{}, nil } - -func generateRandomBootstrapPort() int64 { - minPort := int64(10000) - maxPort := int64(65500) - for { - i, _ := rand.Int(rand.Reader, big.NewInt(maxPort-minPort)) - port := i.Int64() + minPort - if isPortAvailable(port) { - return port - } - } -} - -func isPortAvailable(port int64) bool { - address := fmt.Sprintf(":%d", port) - listener, err := net.Listen("tcp", address) - if err != nil { - return false - } - listener.Close() - return true -} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 58515631f5..271533805e 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -251,6 +251,7 @@ require ( github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/consul/api v1.26.1 // indirect + github.com/hashicorp/consul/sdk v0.15.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.2 // indirect From 02c32bdab0c76514cec3254fab5379f387aca874 Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Tue, 19 Dec 2023 15:17:13 +0200 Subject: [PATCH 326/327] fix imports --- .../ocr2/plugins/ccip/ccipcommit/ocr2.go | 8 +++----- .../plugins/ccip/ccipexec/initializers.go | 12 +++++------- .../ocr2/plugins/ccip/ccipexec/ocr2.go | 3 +-- .../internal/ccipdata/offramp_reader_test.go | 3 +-- .../ccipdata/price_registry_reader_test.go | 3 +-- .../ocr2/plugins/ccip/observations_test.go | 19 +++++++++---------- .../ccip/testhelpers/integration/chainlink.go | 13 ++++++------- core/services/relay/evm/ccip.go | 4 ++-- .../ccip-tests/actions/ccip_helpers.go | 2 +- .../ccip-tests/chaos/ccip_test.go | 3 +-- .../ccip-tests/contracts/contract_deployer.go | 8 +++----- .../ccip-tests/contracts/contract_models.go | 3 +-- .../ccip-tests/load/ccip_multicall_loadgen.go | 4 ++-- integration-tests/ccip-tests/load/helper.go | 5 ++--- .../ccip-tests/testconfig/global.go | 3 --- .../ccip-tests/testreporters/ccip.go | 2 -- .../ccip-tests/testsetups/ccip.go | 5 ++--- .../ccip-tests/types/config/node/core.go | 3 +-- integration-tests/load/ocr/gun.go | 3 +-- integration-tests/types/config/node/core.go | 7 +++---- 20 files changed, 45 insertions(+), 68 deletions(-) diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go index a289d16c61..881b0bf67d 100644 --- a/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go +++ b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go @@ -13,9 +13,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip" @@ -23,11 +22,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/hashlib" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/merklemulti" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices" ) const ( diff --git a/core/services/ocr2/plugins/ccip/ccipexec/initializers.go b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go index cddeeed842..3b96637bdc 100644 --- a/core/services/ocr2/plugins/ccip/ccipexec/initializers.go +++ b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go @@ -14,22 +14,20 @@ import ( "github.com/pkg/errors" chainselectors "github.com/smartcontractkit/chain-selectors" - libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon" - - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider" + libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip" ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/observability" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/oraclelib" diff --git a/core/services/ocr2/plugins/ccip/ccipexec/ocr2.go b/core/services/ocr2/plugins/ccip/ccipexec/ocr2.go index 9d31c527cb..2e6d66401f 100644 --- a/core/services/ocr2/plugins/ccip/ccipexec/ocr2.go +++ b/core/services/ocr2/plugins/ccip/ccipexec/ocr2.go @@ -11,9 +11,8 @@ import ( mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "golang.org/x/sync/errgroup" - "github.com/pkg/errors" + "golang.org/x/sync/errgroup" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go index 66dea7dfcb..cfd4a6788b 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go @@ -6,11 +6,10 @@ import ( "testing" "time" - "github.com/stretchr/testify/mock" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go index 7397e26580..1095075379 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go @@ -7,13 +7,12 @@ import ( "testing" "time" - "github.com/stretchr/testify/mock" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" diff --git a/core/services/ocr2/plugins/ccip/observations_test.go b/core/services/ocr2/plugins/ccip/observations_test.go index 5f4333f0cf..bd107bf2b7 100644 --- a/core/services/ocr2/plugins/ccip/observations_test.go +++ b/core/services/ocr2/plugins/ccip/observations_test.go @@ -6,16 +6,15 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_0_0" - "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_0_0" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" ) @@ -74,13 +73,13 @@ func TestCommitObservationJsonDeserialization(t *testing.T) { json := `{ "interval": { - "Min":1, - "Max":12 + "Min":1, + "Max":12 }, "tokensPerFeeCoin": { "0x0000000000000000000000000000000000000001": 1 }, - "sourceGasPrice": 3 + "sourceGasPrice": 3 }` observations := GetParsableObservations[CommitObservation](logger.TestLogger(t), []types.AttributedObservation{{Observation: []byte(json)}}) @@ -98,9 +97,9 @@ func TestExecutionObservationJsonDeserialization(t *testing.T) { // ["Yw=="] is "c" json := `{ "messages": { - "2":{"tokenData":["YQ=="]}, - "1":{"tokenData":["Yw=="]}, - "2":{"tokenData":["Yw=="]} + "2":{"tokenData":["YQ=="]}, + "1":{"tokenData":["Yw=="]}, + "2":{"tokenData":["Yw=="]} } }` diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go index eb11edffcc..10a37e05c5 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go @@ -21,23 +21,22 @@ import ( "github.com/jmoiron/sqlx" "github.com/onsi/gomega" "github.com/pkg/errors" - "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" - types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" "k8s.io/utils/pointer" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - - evmUtils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" + types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + evmUtils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store" diff --git a/core/services/relay/evm/ccip.go b/core/services/relay/evm/ccip.go index 900d6e8b32..2af78788a7 100644 --- a/core/services/relay/evm/ccip.go +++ b/core/services/relay/evm/ccip.go @@ -2,6 +2,8 @@ package evm import ( "github.com/ethereum/go-ethereum/common" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -12,8 +14,6 @@ import ( ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" ) // CCIPCommitProvider provides all components needed for a CCIP Relay OCR2 plugin. diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index 42337b6e46..9e112b4762 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -17,12 +17,12 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/atomic" "golang.org/x/sync/errgroup" + chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfclient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" diff --git a/integration-tests/ccip-tests/chaos/ccip_test.go b/integration-tests/ccip-tests/chaos/ccip_test.go index daf887879c..c681b366cb 100644 --- a/integration-tests/ccip-tests/chaos/ccip_test.go +++ b/integration-tests/ccip-tests/chaos/ccip_test.go @@ -11,9 +11,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" - "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" - "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" ) diff --git a/integration-tests/ccip-tests/contracts/contract_deployer.go b/integration-tests/ccip-tests/contracts/contract_deployer.go index ea91640a5c..6d0292b946 100644 --- a/integration-tests/ccip-tests/contracts/contract_deployer.go +++ b/integration-tests/ccip-tests/contracts/contract_deployer.go @@ -9,19 +9,17 @@ import ( "strings" "time" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "golang.org/x/crypto/curve25519" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ocrconfighelper2 "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2/types" - "golang.org/x/crypto/curve25519" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" diff --git a/integration-tests/ccip-tests/contracts/contract_models.go b/integration-tests/ccip-tests/contracts/contract_models.go index b3dd9d9b80..baeea0b358 100644 --- a/integration-tests/ccip-tests/contracts/contract_models.go +++ b/integration-tests/ccip-tests/contracts/contract_models.go @@ -6,11 +6,10 @@ import ( "math/big" "strconv" - "github.com/rs/zerolog/log" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" diff --git a/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go index 4fe7e30865..561f652b28 100644 --- a/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go @@ -11,12 +11,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/prometheus/common/model" "github.com/rs/zerolog" - chain_selectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/wasp" "golang.org/x/sync/errgroup" + chain_selectors "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts" diff --git a/integration-tests/ccip-tests/load/helper.go b/integration-tests/ccip-tests/load/helper.go index c5a15336e4..26a6a2f491 100644 --- a/integration-tests/ccip-tests/load/helper.go +++ b/integration-tests/ccip-tests/load/helper.go @@ -10,16 +10,15 @@ import ( "github.com/AlekSi/pointer" "github.com/rs/zerolog" - "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" + "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" ) diff --git a/integration-tests/ccip-tests/testconfig/global.go b/integration-tests/ccip-tests/testconfig/global.go index c923ebc35d..9e86abda1f 100644 --- a/integration-tests/ccip-tests/testconfig/global.go +++ b/integration-tests/ccip-tests/testconfig/global.go @@ -7,11 +7,8 @@ import ( "fmt" "github.com/AlekSi/pointer" - "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" - "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" diff --git a/integration-tests/ccip-tests/testreporters/ccip.go b/integration-tests/ccip-tests/testreporters/ccip.go index 2590104834..60e6cbc851 100644 --- a/integration-tests/ccip-tests/testreporters/ccip.go +++ b/integration-tests/ccip-tests/testreporters/ccip.go @@ -11,9 +11,7 @@ import ( "time" "github.com/rs/zerolog" - "github.com/slack-go/slack" - "github.com/smartcontractkit/chainlink-testing-framework/testreporters" ) diff --git a/integration-tests/ccip-tests/testsetups/ccip.go b/integration-tests/ccip-tests/testsetups/ccip.go index 9d925feca6..ee3590d09a 100644 --- a/integration-tests/ccip-tests/testsetups/ccip.go +++ b/integration-tests/ccip-tests/testsetups/ccip.go @@ -16,23 +16,22 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/rs/zerolog" - chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/require" "go.uber.org/atomic" "go.uber.org/multierr" "go.uber.org/zap/zapcore" "golang.org/x/sync/errgroup" + chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" - integrationactions "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts/laneconfig" + "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) diff --git a/integration-tests/ccip-tests/types/config/node/core.go b/integration-tests/ccip-tests/types/config/node/core.go index da48a87de7..e462d4b626 100644 --- a/integration-tests/ccip-tests/types/config/node/core.go +++ b/integration-tests/ccip-tests/types/config/node/core.go @@ -8,11 +8,10 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" - ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" itutils "github.com/smartcontractkit/chainlink/integration-tests/utils" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) diff --git a/integration-tests/load/ocr/gun.go b/integration-tests/load/ocr/gun.go index cfa8380a70..306518a598 100644 --- a/integration-tests/load/ocr/gun.go +++ b/integration-tests/load/ocr/gun.go @@ -8,10 +8,9 @@ import ( "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - - "github.com/smartcontractkit/wasp" ) // Gun is a gun for the OCR load test diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 7436c05a10..6ded036bb8 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -7,13 +7,14 @@ import ( "os" "time" - "go.uber.org/zap/zapcore" - "github.com/segmentio/ksuid" + "go.uber.org/zap/zapcore" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" @@ -23,8 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/config" - - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func NewBaseConfig() *chainlink.Config { From 7dd322e2cc8602a89fce39b9ecc07fcf5727c324 Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Tue, 19 Dec 2023 15:42:10 +0200 Subject: [PATCH 327/327] goimports --- core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go | 4 +++- core/services/ocr2/plugins/ccip/ccipexec/initializers.go | 4 ++-- .../ocr2/plugins/ccip/testhelpers/integration/chainlink.go | 5 +++-- core/services/relay/evm/ccip.go | 3 ++- integration-tests/ccip-tests/actions/ccip_helpers.go | 1 + integration-tests/ccip-tests/contracts/contract_deployer.go | 3 ++- integration-tests/ccip-tests/load/ccip_multicall_loadgen.go | 3 ++- integration-tests/ccip-tests/load/helper.go | 3 ++- integration-tests/ccip-tests/testreporters/ccip.go | 1 + integration-tests/ccip-tests/testsetups/ccip.go | 1 + integration-tests/load/ocr/gun.go | 3 ++- 11 files changed, 21 insertions(+), 10 deletions(-) diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go index 881b0bf67d..c7af64e0a9 100644 --- a/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go +++ b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go @@ -13,9 +13,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc" diff --git a/core/services/ocr2/plugins/ccip/ccipexec/initializers.go b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go index 3b96637bdc..2abe288357 100644 --- a/core/services/ocr2/plugins/ccip/ccipexec/initializers.go +++ b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go @@ -12,11 +12,11 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - chainselectors "github.com/smartcontractkit/chain-selectors" - relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" + relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go index 10a37e05c5..3a67facceb 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go @@ -27,12 +27,13 @@ import ( "go.uber.org/zap" "k8s.io/utils/pointer" - "github.com/smartcontractkit/chainlink-common/pkg/loop" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/relay/evm/ccip.go b/core/services/relay/evm/ccip.go index 2af78788a7..b68d67549b 100644 --- a/core/services/relay/evm/ccip.go +++ b/core/services/relay/evm/ccip.go @@ -3,9 +3,10 @@ package evm import ( "github.com/ethereum/go-ethereum/common" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index 9e112b4762..2ad6ba7419 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -23,6 +23,7 @@ import ( "golang.org/x/sync/errgroup" chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfclient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" diff --git a/integration-tests/ccip-tests/contracts/contract_deployer.go b/integration-tests/ccip-tests/contracts/contract_deployer.go index 6d0292b946..4838e6a3d5 100644 --- a/integration-tests/ccip-tests/contracts/contract_deployer.go +++ b/integration-tests/ccip-tests/contracts/contract_deployer.go @@ -17,10 +17,11 @@ import ( "github.com/rs/zerolog/log" "golang.org/x/crypto/curve25519" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ocrconfighelper2 "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract" diff --git a/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go index 561f652b28..24499b44d5 100644 --- a/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go @@ -14,9 +14,10 @@ import ( "golang.org/x/sync/errgroup" chain_selectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts" diff --git a/integration-tests/ccip-tests/load/helper.go b/integration-tests/ccip-tests/load/helper.go index 26a6a2f491..b7ace38781 100644 --- a/integration-tests/ccip-tests/load/helper.go +++ b/integration-tests/ccip-tests/load/helper.go @@ -13,9 +13,10 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig" diff --git a/integration-tests/ccip-tests/testreporters/ccip.go b/integration-tests/ccip-tests/testreporters/ccip.go index 60e6cbc851..68d46e6e65 100644 --- a/integration-tests/ccip-tests/testreporters/ccip.go +++ b/integration-tests/ccip-tests/testreporters/ccip.go @@ -12,6 +12,7 @@ import ( "github.com/rs/zerolog" "github.com/slack-go/slack" + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" ) diff --git a/integration-tests/ccip-tests/testsetups/ccip.go b/integration-tests/ccip-tests/testsetups/ccip.go index ee3590d09a..2ab54372d3 100644 --- a/integration-tests/ccip-tests/testsetups/ccip.go +++ b/integration-tests/ccip-tests/testsetups/ccip.go @@ -23,6 +23,7 @@ import ( "golang.org/x/sync/errgroup" chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" diff --git a/integration-tests/load/ocr/gun.go b/integration-tests/load/ocr/gun.go index 306518a598..14fac84fc1 100644 --- a/integration-tests/load/ocr/gun.go +++ b/integration-tests/load/ocr/gun.go @@ -7,9 +7,10 @@ import ( "github.com/rs/zerolog" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" )